Containers (STL-compatible) StateMachines MessageBus and more for Embedded Systems. See www.etlcpp.com

Revision:
0:b47c2a7920c2
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/pool.h	Fri Mar 16 16:34:18 2018 +0000
@@ -0,0 +1,439 @@
+///\file
+
+/******************************************************************************
+The MIT License(MIT)
+
+Embedded Template Library.
+https://github.com/ETLCPP/etl
+http://www.etlcpp.com
+
+Copyright(c) 2014 jwellbelove
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files(the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions :
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+******************************************************************************/
+
+#ifndef __ETL_POOL__
+#define __ETL_POOL__
+
+#include "platform.h"
+#include "alignment.h"
+#include "array.h"
+#include "container.h"
+#include "integral_limits.h"
+#include "nullptr.h"
+#include "alignment.h"
+#include "error_handler.h"
+#include "static_assert.h"
+
+#include <iterator>
+#include <algorithm>
+
+#undef ETL_FILE
+#define ETL_FILE "11"
+
+//*****************************************************************************
+///\defgroup pool pool
+/// A fixed capacity pool.
+///\ingroup containers
+//*****************************************************************************
+
+namespace etl
+{
+  //***************************************************************************
+  /// The base class for pool exceptions.
+  ///\ingroup pool
+  //***************************************************************************
+  class pool_exception : public exception
+  {
+  public:
+
+    pool_exception(string_type reason_, string_type file_name_, numeric_type line_number_)
+      : exception(reason_, file_name_, line_number_)
+    {}
+  };
+
+  //***************************************************************************
+  /// The exception thrown when the pool has no more free items.
+  ///\ingroup pool
+  //***************************************************************************
+  class pool_no_allocation : public pool_exception
+  {
+  public:
+
+    explicit pool_no_allocation(string_type file_name_, numeric_type line_number_)
+      : pool_exception(ETL_ERROR_TEXT("pool:allocation", ETL_FILE"A"), file_name_, line_number_)
+    {}
+  };
+
+  //***************************************************************************
+  /// The exception thrown when an object is released which does not belong to the pool.
+  ///\ingroup pool
+  //***************************************************************************
+  class pool_object_not_in_pool : public pool_exception
+  {
+  public:
+
+    pool_object_not_in_pool(string_type file_name_, numeric_type line_number_)
+      : pool_exception(ETL_ERROR_TEXT("pool:not in pool", ETL_FILE"B"), file_name_, line_number_)
+    {}
+  };
+
+  //***************************************************************************
+  /// The exception thrown when an the type requested is larger than the element size.
+  ///\ingroup pool
+  //***************************************************************************
+  class pool_element_size : public pool_exception
+  {
+  public:
+
+    pool_element_size(string_type file_name_, numeric_type line_number_)
+      : pool_exception(ETL_ERROR_TEXT("pool:element size", ETL_FILE"C"), file_name_, line_number_)
+    {}
+  };
+
+  //***************************************************************************
+  ///\ingroup pool
+  //***************************************************************************
+  class ipool
+  {
+  public:
+
+    typedef size_t size_type;
+
+    //*************************************************************************
+    /// Allocate an object from the pool.
+    /// Uses the default constructor.
+    /// If asserts or exceptions are enabled and there are no more free items an
+    /// etl::pool_no_allocation if thrown, otherwise a nullptr is returned.
+    //*************************************************************************
+    template <typename T>
+    T* allocate()
+    {
+      if (sizeof(T) > ITEM_SIZE)
+      {
+        ETL_ASSERT(false, ETL_ERROR(etl::pool_element_size));
+      }
+
+      return reinterpret_cast<T*>(allocate_item());
+    }
+
+    //*************************************************************************
+    /// Release an object in the pool.
+    /// If asserts or exceptions are enabled and the object does not belong to this
+    /// pool then an etl::pool_object_not_in_pool is thrown.
+    /// \param p_object A pointer to the object to be released.
+    //*************************************************************************
+    void release(const void* p_object)
+    {
+      release_item((char*)p_object);
+    }
+
+    //*************************************************************************
+    /// Release all objects in the pool.
+    //*************************************************************************
+    void release_all()
+    {
+      items_allocated = 0;
+      items_initialised = 0;
+      p_next = p_buffer;
+    }
+
+    //*************************************************************************
+    /// Check to see if the object belongs to the pool.
+    /// \param p_object A pointer to the object to be checked.
+    /// \return <b>true<\b> if it does, otherwise <b>false</b>
+    //*************************************************************************
+    //template <typename T>
+    bool is_in_pool(const void* p_object) const
+    {
+      return is_item_in_pool((const char*)p_object);
+    }
+
+    //*************************************************************************
+    /// Returns the maximum number of items in the pool.
+    //*************************************************************************
+    size_t max_size() const
+    {
+      return MAX_SIZE;
+    }
+
+    //*************************************************************************
+    /// Returns the number of free items in the pool.
+    //*************************************************************************
+    size_t available() const
+    {
+      return MAX_SIZE - items_allocated;
+    }
+
+    //*************************************************************************
+    /// Returns the number of allocated items in the pool.
+    //*************************************************************************
+    size_t size() const
+    {
+      return items_allocated;
+    }
+
+    //*************************************************************************
+    /// Checks to see if there are no allocated items in the pool.
+    /// \return <b>true</b> if there are none allocated.
+    //*************************************************************************
+    bool empty() const
+    {
+      return items_allocated == 0;
+    }
+
+    //*************************************************************************
+    /// Checks to see if there are no free items in the pool.
+    /// \return <b>true</b> if there are none free.
+    //*************************************************************************
+    bool full() const
+    {
+      return items_allocated == MAX_SIZE;
+    }
+
+  protected:
+
+    //*************************************************************************
+    /// Constructor
+    //*************************************************************************
+    ipool(char* p_buffer_, uint32_t item_size_, uint32_t max_size_)
+      : p_buffer(p_buffer_),
+        p_next(p_buffer_),
+        items_allocated(0),
+        items_initialised(0),
+        ITEM_SIZE(item_size_),
+        MAX_SIZE(max_size_)
+    {
+    }
+
+  private:
+
+    //*************************************************************************
+    /// Allocate an item from the pool.
+    //*************************************************************************
+    char* allocate_item()
+    {
+      char* p_value = std::nullptr;
+
+      // Any free space left?
+      if (items_allocated < MAX_SIZE)
+      {
+        // Initialise another one if necessary.
+        if (items_initialised < MAX_SIZE)
+        {
+          uintptr_t p = reinterpret_cast<uintptr_t>(p_buffer + (items_initialised * ITEM_SIZE));
+          *reinterpret_cast<uintptr_t*>(p) = p + ITEM_SIZE;
+          ++items_initialised;
+        }
+
+        // Get the address of new allocated item.
+        p_value = p_next;
+
+        ++items_allocated;
+        if (items_allocated != MAX_SIZE)
+        {
+          // Set up the pointer to the next free item
+          p_next = *reinterpret_cast<char**>(p_next);
+        }
+        else
+        {
+          // No more left!
+          p_next = std::nullptr;
+        }
+      }
+      else
+      {
+        ETL_ASSERT(false, ETL_ERROR(etl::pool_no_allocation));
+      }
+
+      return p_value;
+    }
+
+    //*************************************************************************
+    /// Release an item back to the pool.
+    //*************************************************************************
+    void release_item(char* p_value)
+    {
+      // Does it belong to us?
+      ETL_ASSERT(is_item_in_pool(p_value), ETL_ERROR(pool_object_not_in_pool));
+
+      if (p_next != std::nullptr)
+      {
+        // Point it to the current free item.
+        *(uintptr_t*)p_value = reinterpret_cast<uintptr_t>(p_next);
+      }
+      else
+      {
+        // This is the only free item.
+        *((uintptr_t*)p_value) = 0;
+      }
+
+      p_next = p_value;
+
+      --items_allocated;
+    }
+
+    //*************************************************************************
+    /// Check if the item belongs to this pool.
+    //*************************************************************************
+    bool is_item_in_pool(const char* p) const
+    {
+      // Within the range of the buffer?
+      intptr_t distance = p - p_buffer;
+      bool is_within_range = (distance >= 0) && (distance <= intptr_t((ITEM_SIZE * MAX_SIZE) - ITEM_SIZE));
+
+      // Modulus and division can be slow on some architectures, so only do this in debug.
+#if defined(ETL_DEBUG)
+      // Is the address on a valid object boundary?
+      bool is_valid_address = ((distance % ITEM_SIZE) == 0);
+#else
+      bool is_valid_address = true;
+#endif
+
+      return is_within_range && is_valid_address;
+    }
+
+    // Disable copy construction and assignment.
+    ipool(const ipool&);
+    ipool& operator =(const ipool&);
+
+    char* p_buffer;
+    char* p_next;
+
+    uint32_t  items_allocated;   ///< The number of items allocated.
+    uint32_t  items_initialised; ///< The number of items initialised.
+
+    const uint32_t ITEM_SIZE;    ///< The size of allocated items.
+    const uint32_t MAX_SIZE;    ///< The maximum number of objects that can be allocated.
+  };
+
+  //*************************************************************************
+  /// A templated pool implementation that uses a fixed size pool.
+  ///\ingroup pool
+  //*************************************************************************
+  template <typename T, const size_t SIZE_>
+  class pool : public etl::ipool
+  {
+  public:
+
+    static const size_t SIZE = SIZE_;
+
+    //*************************************************************************
+    /// Constructor
+    //*************************************************************************
+    pool()
+      : etl::ipool(reinterpret_cast<char*>(&buffer[0]), ELEMENT_SIZE, SIZE)
+    {
+    }
+
+    //*************************************************************************
+    /// Allocate an object from the pool.
+    /// Uses the default constructor.
+    /// If asserts or exceptions are enabled and there are no more free items an
+    /// etl::pool_no_allocation if thrown, otherwise a nullptr is returned.
+    /// Static asserts if the specified type is too large for the pool.
+    //*************************************************************************
+    template <typename U>
+    U* allocate()
+    {
+      STATIC_ASSERT(sizeof(U) <= ELEMENT_SIZE, "Type too large for pool");
+      return ipool::allocate<U>();
+    }
+
+  private:
+
+    // The pool element.
+    union Element
+    {
+      uintptr_t next;             ///< Pointer to the next free element.
+      char      value[sizeof(T)]; ///< Storage for value type.
+      typename  etl::type_with_alignment<etl::alignment_of<T>::value>::type dummy; ///< Dummy item to get correct alignment.
+    };
+
+    ///< The memory for the pool of objects.
+    typename etl::aligned_storage<sizeof(Element), etl::alignment_of<Element>::value>::type buffer[SIZE];
+
+    static const uint32_t ELEMENT_SIZE = sizeof(Element);
+
+    // Should not be copied.
+    pool(const pool&);
+    pool& operator =(const pool&);
+  };
+
+  //*************************************************************************
+  /// A templated abstract pool implementation that uses a fixed size pool.
+  ///\ingroup pool
+  //*************************************************************************
+  template <const size_t TYPE_SIZE_, const size_t ALIGNMENT_, const size_t SIZE_>
+  class generic_pool : public etl::ipool
+  {
+  public:
+
+    static const size_t SIZE      = SIZE_;
+    static const size_t ALIGNMENT = ALIGNMENT_;
+    static const size_t TYPE_SIZE = TYPE_SIZE_;
+
+    //*************************************************************************
+    /// Constructor
+    //*************************************************************************
+    generic_pool()
+      : etl::ipool(reinterpret_cast<char*>(&buffer[0]), ELEMENT_SIZE, SIZE)
+    {
+    }
+
+    //*************************************************************************
+    /// Allocate an object from the pool.
+    /// If asserts or exceptions are enabled and there are no more free items an
+    /// etl::pool_no_allocation if thrown, otherwise a nullptr is returned.
+    /// Static asserts if the specified type is too large for the pool.
+    //*************************************************************************
+    template <typename U>
+    U* allocate()
+    {
+      STATIC_ASSERT(etl::alignment_of<U>::value <= ALIGNMENT_, "Type has incompatible alignment");
+      STATIC_ASSERT(sizeof(U)  <= ELEMENT_SIZE, "Type too large for pool");
+      return ipool::allocate<U>();
+    }
+
+  private:
+
+    // The pool element.
+    union Element
+    {
+      uintptr_t next;              ///< Pointer to the next free element.
+      char      value[TYPE_SIZE_]; ///< Storage for value type.
+      typename  etl::type_with_alignment<ALIGNMENT_>::type dummy; ///< Dummy item to get correct alignment.
+    };
+
+    ///< The memory for the pool of objects.
+    typename etl::aligned_storage<sizeof(Element), etl::alignment_of<Element>::value>::type buffer[SIZE];
+
+    static const uint32_t ELEMENT_SIZE = sizeof(Element);
+
+    // Should not be copied.
+    generic_pool(const generic_pool&);
+    generic_pool& operator =(const generic_pool&);
+  };
+}
+
+#undef ETL_FILE
+
+#endif
+
+