/**
 * @file      lib.Buffer.hpp
 * @author    Sergey Baigudin, sergey@baigudin.software
 * @copyright 2014-2022, Sergey Baigudin, Baigudin Software
 */
#ifndef LIB_BUFFER_HPP_
#define LIB_BUFFER_HPP_

#include "lib.AbstractBuffer.hpp"

namespace eoos
{
namespace lib
{
    
/**
 * @class Buffer<T,L,A>
 * @brief Buffer class static.
 *
 * This class is a primary template defines a realization that contains
 * a whole buffer, which is defined by a template argument.
 *
 * @tparam T Data type of buffer element.
 * @tparam L Maximum number of buffer elements, or 0 for dynamic allocation.
 * @tparam A Heap memory allocator class.
 */
template <typename T, int32_t L, class A = Allocator>
class Buffer : public AbstractBuffer<T,A>
{
    typedef AbstractBuffer<T,A> Parent;

public:

    using Parent::isConstructed;

    /**
     * @brief Constructor.
     */
    Buffer() 
        : AbstractBuffer<T,A>(L)
        , buf_(arr_){
    }

    /**
     * @brief Constructor.
     *
     * @note A passed illegal element will be copied to an internal data of the class
     *
     * @param illegal An illegal value.
     */
    Buffer(T const& illegal) 
        : AbstractBuffer<T,A>(L, illegal)
        , buf_ (arr_){
    }

    /**
     * @brief Destructor.
     */
    virtual ~Buffer()
    {
    }
    
    /**
     * @copydoc eoos::api::SequenceContainer::getData()
     */
    virtual T* getData() const
    {
        T* buf( NULLPTR );
        if( isConstructed() )
        {
            buf = buf_;
        }
        return buf;
    }

    /**
     * @brief Assignment operator.
     *
     * If the source buffer is greater than this buffer,
     * only cropped data of that will be copied.
     *
     * @param buf Reference to source buffer.
     * @return Reference to this object.
     */
    Buffer& operator=(api::SequenceContainer<T> const& buf)
    {
        if( isConstructed() && buf.isConstructed() )
        {        
            copy(buf);
        }
        return *this;
    }
    
protected:

    using Parent::setConstructed;
    using Parent::copy;

private:

    /**
     * @brief Current array of T elements.
     */
    T arr_[L];

    /**
     * @brief Pointer to current array.
     *
     * @note The variable has been defined only for giving the getBuffer member function to be constant.
     */
    T* buf_;

};

#ifdef EOOS_ENABLE_DYNAMIC_HEAP_MEMORY

/**
 * @class Buffer<T,0,A>
 * @brief Buffer class dynamic.
 *
 * This is a partial specialization of the template allocates necessary 
 * memory size for containing the buffer in a heap memory.
 *
 * @tparam T Data type of buffer element.
 * @tparam A Heap memory allocator class.
 */
template <typename T, class A>
class Buffer<T,0,A> : public AbstractBuffer<T,A>
{
    typedef AbstractBuffer<T,A> Parent;

public:

    using Parent::isConstructed;

    /**
     * @brief Constructor.
     *
     * @param length Count of buffer elements.
     */
    explicit Buffer(size_t const length) 
        : AbstractBuffer<T,A>(length)
        , buf_(NULLPTR)
        , isDeleted_(true) {
        bool_t const isConstructed( construct(length) );
        setConstructed( isConstructed );
    }

    /**
     * @brief Constructor.
     *
     * @note A passed illegal element will be copied to an internal data of the class
     *
     * @param length  Count of buffer elements.
     * @param illegal Illegal value.
     */
    Buffer(size_t const length, T const& illegal) 
        : AbstractBuffer<T,A>(length, illegal)
        , buf_(NULLPTR)
        , isDeleted_(true) {
        bool_t const isConstructed( construct(length) );
        setConstructed( isConstructed );
    }

    /**
     * @brief Constructor.
     *
     * @note Given external buffer has to exist until this object is alive.
     *
     * @param length Number of elements.
     * @param buf    Pointer to external buffer.
     */
    Buffer(size_t const length, T* const buf) 
        : AbstractBuffer<T,A>(length)
        , buf_(buf)
        , isDeleted_(false) {
        bool_t const isConstructed( construct(length) );
        setConstructed( isConstructed );
    }

    /**
     * @brief Constructor.
     *
     * @note Given external buffer has to exist until this object is alive.
     * @note A passed illegal element will be copied to an internal data of the class.
     *
     * @param length  Number of elements.
     * @param buf     Pointer to external buffer.
     * @param illegal Illegal value.
     */
    Buffer(size_t const length, T* const buf, T const& illegal) 
        : AbstractBuffer<T,A>(length, illegal)
        , buf_(buf)
        , isDeleted_(false) {
        bool_t const isConstructed( construct(length) );
        setConstructed( isConstructed );
    }

    /**
     * @brief Destructor.
     */
    virtual ~Buffer()
    {
        if( isDeleted_ == true )
        {
            A::free(buf_);
        }
    }
    
    /**
     * @copydoc eoos::api::SequenceContainer::getData()
     */
    virtual T* getData() const
    {
        T* buf( NULLPTR );
        if( isConstructed() )
        {
            buf = buf_;
        }
        return buf;
    }    

    /**
     * @brief Assignment operator.
     *
     * If the source buffer is greater than this buffer,
     * only cropped data of that will be copied.
     *
     * @param buf Reference to source buffer.
     * @return Reference to this object.
     */
    Buffer& operator=(api::SequenceContainer<T> const& buf)
    {
        if( isConstructed() && buf.isConstructed() )
        {        
            copy(buf);
        }
        return *this;
    }
    
protected:

    using Parent::setConstructed;    
    using Parent::copy;

private:

    /**
     * @brief Constructor.
     *
     * @param length Count of buffer elements.
     * @return Boolean result.
     */
    bool_t construct(size_t const length)
    {
        bool_t res( false );
        if( isConstructed() && (length > 0U) )
        {
            if(buf_ == NULLPTR)
            {
                void* const addr( A::allocate(length * (sizeof(T))) );
                buf_ = reinterpret_cast<T*>( addr ); ///< SCA MISRA-C++:2008 Justified Rule 5-2-8
            }
            res = buf_ != NULLPTR;
        }
        return res;
    }

    /**
     * @brief Pointer to external given or self created array.
     */
    T* buf_;

    /**
     * @brief Deletet flag.
     *
     * Is set to true for self created array or
     * set to false for external given array.
     */
    bool_t isDeleted_;

};

#endif // EOOS_ENABLE_DYNAMIC_HEAP_MEMORY

} // namespace lib
} // namespace eoos
#endif // LIB_BUFFER_HPP_

Generated by OpenCppCoverage (Version: 0.9.9.0)