bounded_array.h

Back to Bounded array

pastel/sys/

// Description: Bounded array

#ifndef PASTELSYS_BOUNDED_ARRAY_H
#define PASTELSYS_BOUNDED_ARRAY_H

#include "pastel/sys/bounded_array_concepts.h"
#include "pastel/sys/bounded_array_fwd.h"
#include "pastel/sys/bounded_array_iterator.h"
#include "pastel/sys/destruct.h"
#include "pastel/sys/ensure.h"

#include <type_traits>

namespace Pastel
{

    template <typename Settings>
    using Empty_BoundedArray_Customization = 
        BoundedArray_Concepts::Customization<Settings>;

    template <
        typename Settings, 
        template <typename> class Customization = Empty_BoundedArray_Customization>
    class BoundedArray
    : public Customization<Settings>
    {
    public:
        using Fwd = BoundedArray_Fwd<Settings>;
        PASTEL_FWD(Element);
        PASTEL_FWD(Iterator);
        PASTEL_FWD(ConstIterator);
        PASTEL_FWD(Range);
        PASTEL_FWD(ConstRange);
        PASTEL_FWD(iterator);
        PASTEL_FWD(const_iterator);
        static constexpr integer N = Fwd::N;

        #ifdef _MSC_VER
        // The std::is_trivially_copyable is not implemented in gcc 4.

        // We must require the Element to be trivially copyable,
        // or else the swap() cannot be implemented with the nothrow
        // guarantee.
        PASTEL_STATIC_ASSERT(std::is_trivially_copyable<Element>::value);
        #endif

        using Base = Customization<Settings>;

        //! Constructs an empty array.
        /*!
       Time complexity: O(1)
       Exception safety: nothrow
       */
        BoundedArray()
        {
            this->onConstruct();
        }

        //! Copy-constructs from another array.
        /*!
       Time complexity: O(min(that.size(), maxSize()))
       Exception safety: strong

       Exactly min(that.size(), maxSize()) elements
       will be copied.
       */
        BoundedArray(const BoundedArray& that)
        {
            integer n = std::min(maxSize(), that.size());
            for (integer i = 0;i < n;++i)
            {
                emplaceBack(that[i]);
            }

            this->onConstruct();
        }

        //! Constructs from another array.
        /*!
       Time complexity: O(min(that.size(), maxSize()))
       Exception safety: strong

       Exactly min(that.size(), maxSize()) elements
       will be copied.
       */
        template <
            typename That_Settings, 
            template <typename> class That_Customization>
        BoundedArray(const BoundedArray<That_Settings, That_Customization>& that)
        {
            integer n = std::min(maxSize(), that.size());
            for (integer i = 0;i < n;++i)
            {
                emplaceBack(that[i]);
            }

            this->onConstruct();
        }

        //! Move-constructs from another array.
        /*!
       Time complexity: O(1)
       Exception safety: nothrow
       */
        BoundedArray(BoundedArray&& that)
        {
            swap(that);

            this->onConstruct();
        }

        //! Constructs from an initializer list.
        /*!
       Time complexity: O(min(that.size(), maxSize()))
       Exception safety: strong

       Exactly min(that.size(), maxSize()) elements
       will be copied.
       */
        template <typename That_Element>
        BoundedArray(const std::initializer_list<That_Element>& thatSet)
        {
            RANGES_FOR(auto&& value, thatSet)
            {
                emplaceBack(value);
            }
        }

        //! Assigns from another array.
        /*!
       Time complexity: 
       O(1), if moved,
       O(size()), if copied.

       Exception safety: nothrow
       */
        BoundedArray& operator=(BoundedArray that)
        {
            swap(that);
            return *this;
        }

        //! Swaps two arrays.
        /*!
       Time complexity: O(1)
       Exception safety: nothrow
       */
        void swap(BoundedArray& that)
        {
            using std::swap;

            Base::swap(that);

            // Assumes std::is_trivially_copyable<Element>.
            swap(elementSet_, that.elementSet_);
            swap(size_, that.size_);
        }

        //! Removes all elements.
        /*!
       Time complexity: 
       O(size()), if non-trivial destruction,
       O(1), otherwise.

       Exception safety: nothrow
       */
        void clear()
        {
            this->onClear();

            destruct(address(0), address(size()));
            size_ = 0;
        }

        //! Inserts an element at the back of the array.
        /*!
       Preconditions:
       !full()

       Time complexity: O(1)
       Exception safety: nothrow
       */
        template <typename... Type>
        void emplaceBack(Type&&... that)
        {
            PENSURE(!full());

            new (address(size())) Element(std::forward<Type>(that)...);
            ++size_;

            this->onEmplaceBack();
        }

        //! Removes the last element from the array.
        /*!
       Preconditions:
       !empty()

       Time complexity: O(1)
       Exception safety: nothrow
       */
        void popBack()
        {
            PENSURE(!empty());

            this->onPopBack();

            destruct(address(size() - 1));
            --size_;
        }

        PASTEL_ITERATOR_FUNCTIONS(begin, address(0));
        PASTEL_ITERATOR_FUNCTIONS(end, address(size()));
        PASTEL_RANGE_FUNCTIONS(range, begin, end);

        //! Returns the first element.
        /*!
       Preconditions:
       !empty()

       Time complexity: O(1)
       Exception safety: nothrow
       */
        Element& front()
        {
            return removeConst(addConst(*this).front());
        }

        //! Returns the first element.
        /*!
       Preconditions:
       !empty()

       Time complexity: O(1)
       Exception safety: nothrow
       */
        const Element& front() const
        {
            PENSURE(!empty());
            return (*this)[0];
        }

        //! Returns the last element.
        /*!
       Preconditions:
       !empty()

       Time complexity: O(1)
       Exception safety: nothrow
       */
        Element& back()
        {
            return removeConst(addConst(*this).back());
        }

        //! Returns the last element.
        /*!
       Preconditions:
       !empty()

       Time complexity: O(1)
       Exception safety: nothrow
       */
        const Element& back() const
        {
            PENSURE(!empty());
            return (*this)[size() - 1];
        }

        //! Returns the i:th element.
        /*!
       Preconditions:
       0 <= i < size()

       Time complexity: O(1)
       Exception safety: nothrow
       */
        Element& operator[](integer i)
        {
            return removeConst(addConst(*this)[i]);
        }

        //! Returns the i:th element.
        /*!
       Preconditions:
       0 <= i < size()

       Time complexity: O(1)
       Exception safety: nothrow
       */
        const Element& operator[](integer i) const
        {
            PENSURE_OP(i, >=, 0);
            PENSURE_OP(i, <, size());

            return *address(i);
        }

        //! Returns the number of elements in the array.
        /*!
       Time complexity: O(1)
       Exception safety: nothrow
       */
        integer size() const
        {
            return size_;
        }

        //! Returns the maximum number of possible elements.
        /*!
       Time complexity: O(1)
       Exception safety: nothrow
       */
        integer maxSize() const
        {
            return N;
        }

        //! Returns whether the array is full.
        /*!
       Time complexity: O(1)
       Exception safety: nothrow
       */
        bool full() const
        {
            return size() == N;
        }

        //! Returns whether the array is empty.
        /*!
       Time complexity: O(1)
       Exception safety: nothrow
       */
        bool empty() const
        {
            return size() == 0;
        }

    private:
        Element* address(integer i)
        {
            return ((Element*)elementSet_) + i;
        }

        const Element* address(integer i) const
        {
            return ((const Element*)elementSet_) + i;
        }

        char elementSet_[sizeof(Element) * N];
        integer size_ = 0;
    };

}

namespace Pastel
{

    template <
        typename Element_,
        integer N_>
    class BoundedArray_Settings
    {
    public:
        using Element = Element_;
        static constexpr integer N = N_;
    };

}

#endif