| 
							- //
 - //    ██████ ██   ██  ██████   ██████
 - //   ██      ██   ██ ██    ██ ██            ** Clean Header-Only Classes **
 - //   ██      ███████ ██    ██ ██
 - //   ██      ██   ██ ██    ██ ██           https://github.com/Tracktion/choc
 - //    ██████ ██   ██  ██████   ██████
 - //
 - //   CHOC is (C)2021 Tracktion Corporation, and is offered under the terms of the ISC license:
 - //
 - //   Permission to use, copy, modify, and/or distribute this software for any purpose with or
 - //   without fee is hereby granted, provided that the above copyright notice and this permission
 - //   notice appear in all copies. THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
 - //   WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
 - //   AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR
 - //   CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
 - //   WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
 - //   CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 - 
 - #ifndef CHOC_SMALLVECTOR_HEADER_INCLUDED
 - #define CHOC_SMALLVECTOR_HEADER_INCLUDED
 - 
 - #include <algorithm>
 - #include "choc_Span.h"
 - 
 - namespace choc
 - {
 - 
 - /**
 -     A std::vector-style container class, which uses some pre-allocated storage
 -     to avoid heap allocation when the number of elements is small.
 - 
 -     Inspired by LLVM's SmallVector, I've found this to be handy in many situations
 -     where you know there's only likely to be a small or fixed number of elements,
 -     and where performance is important.
 - 
 -     It retains most of the same basic methods as std::vector, but without some of
 -     the more exotic tricks that the std library uses, just to avoid things getting
 -     too complicated.
 - */
 - template <typename ElementType, size_t numPreallocatedElements>
 - struct SmallVector
 - {
 -     using value_type       = ElementType;
 -     using reference        = ElementType&;
 -     using const_reference  = const ElementType&;
 -     using iterator         = ElementType*;
 -     using const_iterator   = const ElementType*;
 -     using size_type        = size_t;
 - 
 -     SmallVector() noexcept;
 -     ~SmallVector() noexcept;
 - 
 -     SmallVector (SmallVector&&) noexcept;
 -     SmallVector (const SmallVector&);
 -     SmallVector& operator= (SmallVector&&) noexcept;
 -     SmallVector& operator= (const SmallVector&);
 - 
 -     /// Creates a SmallVector as a copy of some kind of iterable container.
 -     template <typename VectorType>
 -     SmallVector (const VectorType& initialContent);
 - 
 -     /// Replaces the contents of this vector with a copy of some kind of iterable container.
 -     template <typename VectorType>
 -     SmallVector& operator= (const VectorType&);
 - 
 -     reference        operator[] (size_type index);
 -     const_reference  operator[] (size_type index) const;
 - 
 -     value_type* data() const noexcept;
 - 
 -     const_iterator  begin() const noexcept;
 -     const_iterator  end() const noexcept;
 -     const_iterator  cbegin() const noexcept;
 -     const_iterator  cend() const noexcept;
 -     iterator        begin() noexcept;
 -     iterator        end() noexcept;
 - 
 -     const_reference front() const;
 -     reference       front();
 -     const_reference back() const;
 -     reference       back();
 - 
 -     bool empty() const noexcept;
 -     size_type size() const noexcept;
 -     size_type length() const noexcept;
 -     size_type capacity() const noexcept;
 - 
 -     bool contains (const ElementType&) const;
 - 
 -     void clear() noexcept;
 -     void resize (size_type newSize);
 -     void reserve (size_type requiredNumElements);
 - 
 -     void push_back (const value_type&);
 -     void push_back (value_type&&);
 - 
 -     /// Handy method to add multiple elements with a single push_back call.
 -     template <typename... Others>
 -     void push_back (const value_type& first, Others&&... others);
 - 
 -     template <typename... ConstructorArgs>
 -     void emplace_back (ConstructorArgs&&... args);
 - 
 -     void pop_back();
 - 
 -     void insert (iterator insertPosition, const value_type& valueToInsert);
 -     void insert (iterator insertPosition, value_type&& valueToInsert);
 - 
 -     void erase (iterator startPosition);
 -     void erase (iterator startPosition, iterator endPosition);
 - 
 -     bool operator== (span<value_type>) const;
 -     bool operator!= (span<value_type>) const;
 - 
 - private:
 -     value_type* elements;
 -     size_type numElements = 0, numAllocated = numPreallocatedElements;
 -     uint64_t internalStorage[(numPreallocatedElements * sizeof (value_type) + sizeof (uint64_t) - 1) / sizeof (uint64_t)];
 - 
 -     void shrink (size_type);
 -     value_type* getInternalStorage() noexcept      { return reinterpret_cast<value_type*> (internalStorage); }
 -     bool isUsingInternalStorage() const noexcept   { return numAllocated <= numPreallocatedElements; }
 -     void resetToInternalStorage() noexcept;
 -     void freeHeapAndResetToInternalStorage() noexcept;
 - 
 -     static inline ElementType& _nullValue() noexcept { static ElementType e = {}; return e; }
 - };
 - 
 - 
 - 
 - //==============================================================================
 - //        _        _           _  _
 - //     __| |  ___ | |_   __ _ (_)| | ___
 - //    / _` | / _ \| __| / _` || || |/ __|
 - //   | (_| ||  __/| |_ | (_| || || |\__ \ _  _  _
 - //    \__,_| \___| \__| \__,_||_||_||___/(_)(_)(_)
 - //
 - //   Code beyond this point is implementation detail...
 - //
 - //==============================================================================
 - 
 - template <typename ElementType, size_t preSize>
 - SmallVector<ElementType, preSize>::SmallVector() noexcept  : elements (getInternalStorage())
 - {
 - }
 - 
 - template <typename ElementType, size_t preSize>
 - SmallVector<ElementType, preSize>::~SmallVector() noexcept
 - {
 -     clear();
 - }
 - 
 - template <typename ElementType, size_t preSize>
 - SmallVector<ElementType, preSize>::SmallVector (const SmallVector& other)  : SmallVector()
 - {
 -     operator= (other);
 - }
 - 
 - template <typename ElementType, size_t preSize>
 - template <typename VectorType>
 - SmallVector<ElementType, preSize>::SmallVector (const VectorType& initialContent)  : SmallVector()
 - {
 -     reserve (initialContent.size());
 - 
 -     for (auto& i : initialContent)
 -         emplace_back (i);
 - }
 - 
 - template <typename ElementType, size_t preSize>
 - SmallVector<ElementType, preSize>::SmallVector (SmallVector&& other) noexcept
 - {
 -     if (other.isUsingInternalStorage())
 -     {
 -         elements = getInternalStorage();
 -         numElements = other.numElements;
 - 
 -         for (size_type i = 0; i < numElements; ++i)
 -             new (elements + i) value_type (std::move (other.elements[i]));
 -     }
 -     else
 -     {
 -         elements = other.elements;
 -         numElements = other.numElements;
 -         numAllocated = other.numAllocated;
 -         other.resetToInternalStorage();
 -         other.numElements = 0;
 -     }
 - }
 - 
 - template <typename ElementType, size_t preSize>
 - SmallVector<ElementType, preSize>& SmallVector<ElementType, preSize>::operator= (SmallVector&& other) noexcept
 - {
 -     clear();
 - 
 -     if (other.isUsingInternalStorage())
 -     {
 -         numElements = other.numElements;
 - 
 -         for (size_type i = 0; i < numElements; ++i)
 -             new (elements + i) value_type (std::move (other.elements[i]));
 -     }
 -     else
 -     {
 -         elements = other.elements;
 -         numElements = other.numElements;
 -         numAllocated = other.numAllocated;
 -         other.resetToInternalStorage();
 -         other.numElements = 0;
 -     }
 - 
 -     return *this;
 - }
 - 
 - template <typename ElementType, size_t preSize>
 - SmallVector<ElementType, preSize>& SmallVector<ElementType, preSize>::operator= (const SmallVector& other)
 - {
 -     if (other.size() > numElements)
 -     {
 -         reserve (other.size());
 - 
 -         for (size_type i = 0; i < numElements; ++i)
 -             elements[i] = other.elements[i];
 - 
 -         for (size_type i = numElements; i < other.size(); ++i)
 -             new (elements + i) value_type (other.elements[i]);
 - 
 -         numElements = other.size();
 -     }
 -     else
 -     {
 -         shrink (other.size());
 - 
 -         for (size_type i = 0; i < numElements; ++i)
 -             elements[i] = other.elements[i];
 -     }
 - 
 -     return *this;
 - }
 - 
 - template <typename ElementType, size_t preSize>
 - template <typename VectorType>
 - SmallVector<ElementType, preSize>& SmallVector<ElementType, preSize>::operator= (const VectorType& other)
 - {
 -     if (other.size() > numElements)
 -     {
 -         reserve (other.size());
 - 
 -         for (size_type i = 0; i < numElements; ++i)
 -             elements[i] = other[i];
 - 
 -         for (size_type i = numElements; i < other.size(); ++i)
 -             new (elements + i) value_type (other[i]);
 - 
 -         numElements = other.size();
 -     }
 -     else
 -     {
 -         shrink (other.size());
 - 
 -         for (size_type i = 0; i < numElements; ++i)
 -             elements[i] = other[i];
 -     }
 - 
 -     return *this;
 - }
 - 
 - template <typename ElementType, size_t preSize>
 - void SmallVector<ElementType, preSize>::resetToInternalStorage() noexcept
 - {
 -     elements = getInternalStorage();
 -     numAllocated = preSize;
 - }
 - 
 - template <typename ElementType, size_t preSize>
 - void SmallVector<ElementType, preSize>::freeHeapAndResetToInternalStorage() noexcept
 - {
 -     if (! isUsingInternalStorage())
 -     {
 -         delete[] reinterpret_cast<char*> (elements);
 -         resetToInternalStorage();
 -     }
 - }
 - 
 - template <typename ElementType, size_t preSize>
 - typename SmallVector<ElementType, preSize>::reference SmallVector<ElementType, preSize>::operator[] (size_type index)
 - {
 -     DISTRHO_SAFE_ASSERT_RETURN (index < numElements, _nullValue());
 -     return elements[index];
 - }
 - 
 - template <typename ElementType, size_t preSize>
 - typename SmallVector<ElementType, preSize>::const_reference SmallVector<ElementType, preSize>::operator[] (size_type index) const
 - {
 -     DISTRHO_SAFE_ASSERT_RETURN (index < numElements, _nullValue());
 -     return elements[index];
 - }
 - 
 - template <typename ElementType, size_t preSize>
 - typename SmallVector<ElementType, preSize>::value_type* SmallVector<ElementType, preSize>::data() const noexcept      { return elements; }
 - template <typename ElementType, size_t preSize>
 - typename SmallVector<ElementType, preSize>::const_iterator SmallVector<ElementType, preSize>::begin() const noexcept  { return elements; }
 - template <typename ElementType, size_t preSize>
 - typename SmallVector<ElementType, preSize>::const_iterator SmallVector<ElementType, preSize>::end() const noexcept    { return elements + numElements; }
 - template <typename ElementType, size_t preSize>
 - typename SmallVector<ElementType, preSize>::const_iterator SmallVector<ElementType, preSize>::cbegin() const noexcept { return elements; }
 - template <typename ElementType, size_t preSize>
 - typename SmallVector<ElementType, preSize>::const_iterator SmallVector<ElementType, preSize>::cend() const noexcept   { return elements + numElements; }
 - template <typename ElementType, size_t preSize>
 - typename SmallVector<ElementType, preSize>::iterator SmallVector<ElementType, preSize>::begin() noexcept              { return elements; }
 - template <typename ElementType, size_t preSize>
 - typename SmallVector<ElementType, preSize>::iterator SmallVector<ElementType, preSize>::end() noexcept                { return elements + numElements; }
 - 
 - template <typename ElementType, size_t preSize>
 - typename SmallVector<ElementType, preSize>::reference SmallVector<ElementType, preSize>::front()
 - {
 -     DISTRHO_SAFE_ASSERT_RETURN (! empty(), _nullValue());
 -     return elements[0];
 - }
 - 
 - template <typename ElementType, size_t preSize>
 - typename SmallVector<ElementType, preSize>::const_reference SmallVector<ElementType, preSize>::front() const
 - {
 -     DISTRHO_SAFE_ASSERT_RETURN (! empty(), _nullValue());
 -     return elements[0];
 - }
 - 
 - template <typename ElementType, size_t preSize>
 - typename SmallVector<ElementType, preSize>::reference SmallVector<ElementType, preSize>::back()
 - {
 -     DISTRHO_SAFE_ASSERT_RETURN (! empty(), _nullValue());
 -     return elements[numElements - 1];
 - }
 - 
 - template <typename ElementType, size_t preSize>
 - typename SmallVector<ElementType, preSize>::const_reference SmallVector<ElementType, preSize>::back() const
 - {
 -     DISTRHO_SAFE_ASSERT_RETURN (! empty(), _nullValue());
 -     return elements[numElements - 1];
 - }
 - 
 - template <typename ElementType, size_t preSize>
 - typename SmallVector<ElementType, preSize>::size_type SmallVector<ElementType, preSize>::size() const noexcept      { return numElements; }
 - 
 - template <typename ElementType, size_t preSize>
 - typename SmallVector<ElementType, preSize>::size_type SmallVector<ElementType, preSize>::length() const noexcept    { return numElements; }
 - 
 - template <typename ElementType, size_t preSize>
 - typename SmallVector<ElementType, preSize>::size_type SmallVector<ElementType, preSize>::capacity() const noexcept  { return numAllocated; }
 - 
 - template <typename ElementType, size_t preSize>
 - bool SmallVector<ElementType, preSize>::empty() const noexcept      { return numElements == 0; }
 - 
 - template <typename ElementType, size_t preSize>
 - bool SmallVector<ElementType, preSize>::contains (const ElementType& target) const
 - {
 -     for (size_t i = 0; i < numElements; ++i)
 -         if (elements[i] == target)
 -             return true;
 - 
 -     return false;
 - }
 - 
 - template <typename ElementType, size_t preSize>
 - bool SmallVector<ElementType, preSize>::operator== (span<value_type> other) const   { return span<value_type> (*this) == other; }
 - 
 - template <typename ElementType, size_t preSize>
 - bool SmallVector<ElementType, preSize>::operator!= (span<value_type> other) const   { return span<value_type> (*this) != other; }
 - 
 - template <typename ElementType, size_t preSize>
 - void SmallVector<ElementType, preSize>::push_back (const value_type& item)
 - {
 -     reserve (numElements + 1);
 -     new (elements + numElements) value_type (item);
 -     ++numElements;
 - }
 - 
 - template <typename ElementType, size_t preSize>
 - void SmallVector<ElementType, preSize>::push_back (value_type&& item)
 - {
 -     reserve (numElements + 1);
 -     new (elements + numElements) value_type (std::move (item));
 -     ++numElements;
 - }
 - 
 - template <typename ElementType, size_t preSize>
 - template <typename... Others>
 - void SmallVector<ElementType, preSize>::push_back (const value_type& first, Others&&... others)
 - {
 -     reserve (numElements + 1 + sizeof... (others));
 -     push_back (first);
 -     push_back (std::forward<Others> (others)...);
 - }
 - 
 - template <typename ElementType, size_t preSize>
 - template <typename... ConstructorArgs>
 - void SmallVector<ElementType, preSize>::emplace_back (ConstructorArgs&&... args)
 - {
 -     reserve (numElements + 1);
 -     new (elements + numElements) value_type (std::forward<ConstructorArgs> (args)...);
 -     ++numElements;
 - }
 - 
 - template <typename ElementType, size_t preSize>
 - void SmallVector<ElementType, preSize>::insert (iterator insertPos, const value_type& item)
 - {
 -     DISTRHO_SAFE_ASSERT_RETURN (insertPos != nullptr && insertPos >= begin() && insertPos <= end(),);
 -     auto index = insertPos - begin();
 -     push_back (item);
 -     std::rotate (begin() + index, end() - 1, end());
 - }
 - 
 - template <typename ElementType, size_t preSize>
 - void SmallVector<ElementType, preSize>::insert (iterator insertPos, value_type&& item)
 - {
 -     DISTRHO_SAFE_ASSERT_RETURN (insertPos != nullptr && insertPos >= begin() && insertPos <= end(),);
 -     auto index = insertPos - begin();
 -     push_back (std::move (item));
 -     std::rotate (begin() + index, end() - 1, end());
 - }
 - 
 - template <typename ElementType, size_t preSize>
 - void SmallVector<ElementType, preSize>::pop_back()
 - {
 -     if (numElements == 1)
 -     {
 -         clear();
 -     }
 -     else
 -     {
 -         DISTRHO_SAFE_ASSERT_RETURN (numElements > 0,);
 -         elements[--numElements].~value_type();
 -     }
 - }
 - 
 - template <typename ElementType, size_t preSize>
 - void SmallVector<ElementType, preSize>::clear() noexcept
 - {
 -     for (size_type i = 0; i < numElements; ++i)
 -         elements[i].~value_type();
 - 
 -     numElements = 0;
 -     freeHeapAndResetToInternalStorage();
 - }
 - 
 - template <typename ElementType, size_t preSize>
 - void SmallVector<ElementType, preSize>::resize (size_type newSize)
 - {
 -     if (newSize > numElements)
 -     {
 -         reserve (newSize);
 - 
 -         while (numElements < newSize)
 -             new (elements + numElements++) value_type (value_type());
 -     }
 -     else
 -     {
 -         shrink (newSize);
 -     }
 - }
 - 
 - template <typename ElementType, size_t preSize>
 - void SmallVector<ElementType, preSize>::shrink (size_type newSize)
 - {
 -     if (newSize == 0)
 -         return clear();
 - 
 -     DISTRHO_SAFE_ASSERT_RETURN (newSize <= numElements,);
 - 
 -     while (newSize < numElements && numElements > 0)
 -         elements[--numElements].~value_type();
 - }
 - 
 - template <typename ElementType, size_t preSize>
 - void SmallVector<ElementType, preSize>::reserve (size_type requiredNumElements)
 - {
 -     if (requiredNumElements > numAllocated)
 -     {
 -         requiredNumElements = static_cast<size_type> ((requiredNumElements + 15u) & ~(size_type) 15u);
 - 
 -         if (requiredNumElements > preSize)
 -         {
 -             auto* newBuffer = reinterpret_cast<value_type*> (new char[requiredNumElements * sizeof (value_type)]);
 - 
 -             for (size_type i = 0; i < numElements; ++i)
 -             {
 -                 new (newBuffer + i) value_type (std::move (elements[i]));
 -                 elements[i].~value_type();
 -             }
 - 
 -             freeHeapAndResetToInternalStorage();
 -             elements = newBuffer;
 -         }
 - 
 -         numAllocated = requiredNumElements;
 -     }
 - }
 - 
 - template <typename ElementType, size_t preSize>
 - void SmallVector<ElementType, preSize>::erase (iterator startElement)
 - {
 -     erase (startElement, startElement + 1);
 - }
 - 
 - template <typename ElementType, size_t preSize>
 - void SmallVector<ElementType, preSize>::erase (iterator startElement, iterator endElement)
 - {
 -     DISTRHO_SAFE_ASSERT_RETURN (startElement != nullptr && startElement >= begin() && startElement <= end(),);
 -     DISTRHO_SAFE_ASSERT_RETURN (endElement != nullptr && endElement >= begin() && endElement <= end(),);
 - 
 -     if (startElement != endElement)
 -     {
 -         DISTRHO_SAFE_ASSERT_RETURN (startElement < endElement,);
 - 
 -         if (endElement == end())
 -             return shrink (static_cast<size_type> (startElement - begin()));
 - 
 -         auto dest = startElement;
 - 
 -         for (auto src = endElement; src < end(); ++dest, ++src)
 -             *dest = std::move (*src);
 - 
 -         shrink (size() - static_cast<size_type> (endElement - startElement));
 -     }
 - }
 - 
 - }
 - 
 - #endif // CHOC_SMALLVECTOR_HEADER_INCLUDED
 
 
  |