ETLCPP / etl

Embedded Template Library
https://www.etlcpp.com
MIT License
2.17k stars 386 forks source link

etl::variant_pool should support C++17 variadic parameters #806

Closed pwsoftwaredesigns closed 5 months ago

pwsoftwaredesigns commented 9 months ago

In the same way etl::variant supports variadic parameters past C++17, the code for etl::variant_pool should be modified to support unlimited types (rather than only 16) if the C++ version supports it.

pwsoftwaredesigns commented 6 months ago

I implemented and tested a C++17 version of variant_pool that accepts "unlimited" types using parameter packs and fold expressions. I wasn't able to push a pull request, but here is my implementation:

#ifndef ETL_C17_VARIANT_POOL_INCLUDED
#define ETL_C17_VARIANT_POOL_INCLUDED

#include "platform.h"
#include "pool.h"
#include "type_traits.h"
#include "static_assert.h"
#include "largest.h"

#include <stdint.h>

#if ETL_USING_CPP17

namespace etl
{
  //***************************************************************************
  template <size_t MAX_SIZE_, typename ... Ts>
  class variant_pool
    : public etl::generic_pool<etl::largest<Ts...>::size,
                               etl::largest<Ts...>::alignment,
                               MAX_SIZE_>
  {
  public:

    typedef etl::generic_pool<etl::largest<Ts...>::size,
                              etl::largest<Ts...>::alignment,
                              MAX_SIZE_> base_t;

    static const size_t MAX_SIZE = MAX_SIZE_;

    //*************************************************************************
    /// Default constructor.
    //*************************************************************************
    variant_pool()
    {
    }

    //*************************************************************************
    /// Creates the object from a type. Variadic parameter constructor.
    //*************************************************************************
    template <typename T, typename... Args>
    T* create(Args&&... args)
    {
      ETL_STATIC_ASSERT((etl::is_one_of<T, Ts...>::value), "Unsupported type");

      return base_t::template create<T>(etl::forward<Args>(args)...);
    }

    //*************************************************************************
    /// Destroys the object.
    //*************************************************************************
    template <typename T>
    void destroy(const T* const p)
    {
      ETL_STATIC_ASSERT((etl::is_one_of<T, Ts...>::value ||
                         ((etl::is_base_of<T, Ts>::value) || ... )
                         ), "Invalid type");

      base_t::destroy(p);
    }

    //*************************************************************************
    /// Returns the maximum number of items in the variant_pool.
    //*************************************************************************
    size_t max_size() const
    {
      return MAX_SIZE;
    }

  private:

    variant_pool(const variant_pool&) ETL_DELETE;
    variant_pool& operator =(const variant_pool&) ETL_DELETE;
  };

  //***************************************************************************
  template <typename ... Ts>
  class variant_pool_ext
    : public etl::generic_pool_ext<etl::largest<Ts...>::size,
                                   etl::largest<Ts...>::alignment>
  {
  public:

    typedef etl::generic_pool_ext<etl::largest<Ts...>::size,
                                  etl::largest<Ts...>::alignment> base_t;

    //*************************************************************************
    /// Default constructor.
    //*************************************************************************
    variant_pool_ext(typename base_t::element* buffer, size_t size)
      : base_t(buffer, size) 
    {
    }

    //*************************************************************************
    /// Creates the object from a type. Variadic parameter constructor.
    //*************************************************************************
    template <typename T, typename... Args>
    T* create(Args&&... args)
    {
      ETL_STATIC_ASSERT((etl::is_one_of<T, Ts...>::value), "Unsupported type");

      return base_t::template create<T>(etl::forward<Args>(args)...);
    }

    //*************************************************************************
    /// Destroys the object.
    //*************************************************************************
    template <typename T>
    void destroy(const T* const p)
    {
      ETL_STATIC_ASSERT((etl::is_one_of<T, Ts...>::value ||
                         ((etl::is_base_of<T, Ts>::value) || ... )
                         ), "Invalid type");

      base_t::destroy(p);
    }

    //*************************************************************************
    /// Returns the maximum number of items in the variant_pool.
    //*************************************************************************
    size_t max_size() const 
    { 
      return base_t::max_size(); 
    }

  private:

    variant_pool_ext(const variant_pool_ext&) ETL_DELETE;
    variant_pool_ext& operator =(const variant_pool_ext&) ETL_DELETE;
  };
}

#endif //ETL_USING_CPP17

#endif
jwellbelove commented 5 months ago

I've managed to make the variadic etl::variant_pool compile for C++11 by introducing a new type variadic trait etl::is_base_of_any (along with its counterpart etl::is_base_of_all). This allowed me to replace the C++17 fold expression.

jwellbelove commented 5 months ago

Fixed 20.38.11