/**
 * @file      lib.Align.hpp
 * @author    Sergey Baigudin, sergey@baigudin.software
 * @copyright 2016-2022, Sergey Baigudin, Baigudin Software
 */
#ifndef LIB_ALIGN_HPP_
#define LIB_ALIGN_HPP_

#include "lib.ObjectAllocator.hpp"

namespace eoos
{
namespace lib
{
    
/**
 * @class Align<T,S,A>
 * @brief Alignment of fundamental types to byte boundary of memory.
 * 
 * MISRA C++ NOTE: Any signed underlying types shall not be used
 * for not violating the 5-0-21 MISRA C++:2008 Rule.
 *
 * @tparam T Type of aligning data.
 * @tparam S Size of aligning data type.
 * @tparam A Heap memory allocator class.
 */
template <typename T, size_t S = sizeof(T), class A = Allocator>
class Align : public ObjectAllocator<A>
{

public:

    /**
     * @brief Constructor.
     */
    Align() 
        : ObjectAllocator<A>() {
    }

    /**
     * @brief Constructor.
     *
     * @note A passed value is copied to an internal data structure
     * so that the value might be invalidated after the function called.
     *
     * @param value A data value.
     */
    Align(T const& value) 
        : ObjectAllocator<A>() {
        assignment(value);
    }

    /**
     * @brief Copy constructor.
     *
     * @param obj A source object.
     */
    Align(Align const& obj) ///< SCA MISRA-C++:2008 Justified Rule 12-8-1
        : ObjectAllocator<A>(obj) {
        copy(obj);
    }
    
    /**
     * @brief Destructor.
     */
    ~Align() {}    

    /**
     * @brief Assignment operator.
     *
     * @note A passed value is copied to an internal data structure
     * so that the value might be invalidated after the function called.
     *
     * @param value A source data value.
     * @return Reference to this object.
     */
    Align& operator=(T const& value)
    {
        assignment(value);
        return *this;
    }

    /**
     * @brief Assignment operator.
     *
     * @param obj A source object.
     * @return Reference to this object.
     */
    Align& operator=(Align const& obj)
    {
        copy(obj);
        return *this;
    }

    /**
     * @brief Pre-increment operator.
     *
     * @param obj A source object.
     * @return Reference to this object.
     */
    Align& operator++()
    {
        T val( typecast() );
        val += 1;
        assignment(val);
        return *this;
    }

    /**
     * @brief Pre-decrement operator.
     *
     * @param obj A source object.
     * @return Reference to this object.
     */
    Align& operator--()
    {
        T val( typecast() );
        val -= 1;
        assignment(val);
        return *this;
    }

    /**
     * @brief Post-increment operator.
     *
     * @return This object.
     */
    Align operator++(int) ///< SCA MISRA-C++:2008 Justified Rule 3-9-2
    {
        T val( typecast() );
        val += 1;
        assignment(val);
        return *this;
    }

    /**
     * @brief Post-decrement operator.
     *
     * @return This object.
     */
    Align operator--(int) ///< SCA MISRA-C++:2008 Justified Rule 3-9-2
    {
        T val( typecast() );
        val -= 1;
        assignment(val);
        return *this;
    }

    /**
     * @brief Casts to the template data type.
     *
     * @return A data value.
     */
    operator T() const
    {
        return typecast();
    }

private:

    /**
     * @brief Compares a type based value with this class.
     *
     * @param val A source value.
     * @return True if this object value equals to a passed value.
     */
    bool_t equal(T const& value) const
    {
        Align<T,S,A> obj(value);
        return equal(obj);
    }

    /**
     * @brief Compares an object of this class type with this class.
     *
     * @param obj A source object.
     * @return True if this object value equals to a passed object value.
     */
    bool_t equal(Align const& obj) const
    {
        bool_t res( true );
        for(size_t i(0U); i<S; i++)
        {
            if( val_[i] != obj.val_[i] )
            {
                res = false;
                break;
            }
        }
        return res;
    }

    /**
     * @brief Assigns given value to self data.
     *
     * @param value Source data value.
     */
    void assignment(T const& value) ///< SCA MISRA-C++:2008 Defected Rule 9-3-3
    {
        for(size_t i(0U); i<S; i++)
        {
            T const v( value >> (8U * i) ); ///< SCA MISRA-C++:2008 Justified Rule 5-0-21
            val_[i] = static_cast<ucell_t>(v);
        }
    }

    /**
     * @brief Copies given object to self data.
     *
     * @param obj Reference to source object.
     */
    void copy(Align const& obj) ///< SCA MISRA-C++:2008 Defected Rule 9-3-3
    {
        for(size_t i(0U); i<S; i++)
        {
            val_[i] = obj.val_[i];
        }
    }

    /**
     * @brief Returns conversed data to type of aligning data.
     *
     * @return Conversed data.
     */
    T typecast() const
    {
        int32_t const max( static_cast<int32_t>(S) - 1 );
        T r( static_cast<T>(0) );
        for(int32_t i(max); i>=0; i--)
        {
            r = r << 8U;                     ///< SCA MISRA-C++:2008 Justified Rule 5-0-21
            r = r | static_cast<T>(val_[i]); ///< SCA MISRA-C++:2008 Justified Rule 5-0-21
        }
        return r;
    }

    /**
     * @brief Array of data bytes.
     */
    ucell_t val_[S];

    template <typename T0, size_t S0, class A0> friend bool_t operator==(Align<T0,S0,A0> const&, Align<T0,S0,A0> const&);
    template <typename T0, size_t S0, class A0> friend bool_t operator!=(Align<T0,S0,A0> const&, Align<T0,S0,A0> const&);
};

/**
 * @brief Comparison operator to equal.
 *
 * @param obj1 Reference to object.
 * @param obj2 Reference to object.
 * @return True if objects are equal.
 */
template <typename T, size_t S, class A>
inline bool_t operator==(Align<T,S,A> const& obj1, Align<T,S,A> const& obj2)
{
    bool_t const res( obj1.equal(obj2) );
    return res;
}

/**
 * @brief Comparison operator to unequal.
 *
 * @param obj1 Reference to object.
 * @param obj2 Reference to object.
 * @return True if objects are not equal.
 */
template <typename T, size_t S, class A>
inline bool_t operator!=(Align<T,S,A> const& obj1, Align<T,S,A> const& obj2)
{
    bool_t const res( obj1.equal(obj2) );
    return !res;
}

} // namespace lib
} // namespace eoos
#endif // LIB_ALIGN_HPP_

Generated by OpenCppCoverage (Version: 0.9.9.0)