/*
 * Copyright (C) 2020-2021 Aloysius Indrayanto
 *
 * This file is part of the eCxx library, see LICENSE file for the license details.
 */


#ifndef ECXX_CTL_ALIGNED_STORAGE_H
#define ECXX_CTL_ALIGNED_STORAGE_H


#include <eCxx/CTL/Types.h>


namespace eCxx {


//
// alignedStorage<>
//
template <size_t Len, size_t Align>
struct alignedStorage {
    struct Type {
        alignas(Align) unsigned char data[Len];
    };
};


//
// AlignedStorage<>
//
template <typename ValueT, size_t Len>
class AlignedStorage {
    public:
        typedef ValueT  ValueType;
        typedef size_t  SizeType;

        static constexpr SizeType Capacity   = Len;
        static constexpr SizeType ValueSize  = sizeof(ValueT);
        static constexpr SizeType BufferSize = sizeof(ValueT) * Len;

    public:
        inline AlignedStorage() noexcept = default;
        inline ~AlignedStorage() noexcept = default;

        inline constexpr SizeType capacity() const noexcept
        { return Capacity; }

        inline ValueT* operator()(size_t index) noexcept
        { return eCxx::launder( reinterpret_cast<ValueT*>(_data + ValueSize * index) ); }

        inline const ValueT* operator()(size_t index) const noexcept
        { return eCxx::launder( reinterpret_cast<const ValueT*>(_data + ValueSize * index) ); }

    public:
        AlignedStorage(const AlignedStorage& ) = delete;
        AlignedStorage(      AlignedStorage&&) = delete;

        AlignedStorage& operator=(const AlignedStorage& ) = delete;
        AlignedStorage& operator=(      AlignedStorage&&) = delete;

    private:
        alignas(alignof(ValueT)) unsigned char _data[BufferSize];
};


} // namespace eCxx


//
// Aligned memory allocation and deallocation
//

// AVR
#if defined(__AVR_ARCH__)

    extern "C" void* malloc(size_t size);
    extern "C" void  free  (void*  ptr );

    #define aligned_malloc(ALIGNMENT, SIZE) malloc(SIZE)
    #define aligned_free(PTR)               free(PTR)

// NodeMCU-ESP8266
#elif defined(__XTENSA__)

    extern "C" void* ICACHE_RAM_ATTR aligned_malloc(size_t alignment, size_t size);
    extern "C" void  ICACHE_RAM_ATTR aligned_free  (void* ptr                    );

// Dummy (for testing the eCxx library in the host PC)
#else

    extern "C" void* aligned_alloc(size_t alignment, size_t size);
    extern "C" void* malloc       (                  size_t size);
    extern "C" void  free         (void*  ptr                   );

    #define aligned_malloc(ALIGNMENT, SIZE) aligned_alloc(ALIGNMENT, SIZE)
    #define aligned_free(PTR)               free(PTR)

#endif


#endif
