// // ██████ ██  ██  ██████  ██████ // ██      ██  ██ ██    ██ ██       ** 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_SPAN_HEADER_INCLUDED #define CHOC_SPAN_HEADER_INCLUDED #include #include "DistrhoUtils.hpp" namespace choc { //============================================================================== /** This is a temporary stunt-double for std::span, with the intention of it being deprecated when there's more widespread compiler support for the real std::span. This class has fewer bells-and-whistles than a real std::span, but it does have the advantage of calling CHOC_ASSERT when mistakes are made like out-of-range accesses, which can be useful for getting clean error handling rather than UB. */ template struct span { span() = default; span (const span&) = default; span (span&&) = default; span& operator= (span&&) = default; span& operator= (const span&) = default; /// Construct from some raw start and end pointers. For an empty span, these /// can both be nullptr, but if one is a real pointer then the caller must ensure /// that start <= end. span (Item* start, Item* end) noexcept : s (start), e (end) {} /// Constructs a span from a pointer and length. /// The pointer must not be nullptr unless the length is 0. span (const Item* start, size_t length) noexcept : span (const_cast (start), const_cast (start) + length) {} /// Constructor taking a raw C++ array. template span (Item (&array)[length]) : span (array, length) {} /// Constructor which takes some kind of class like std::vector or std::array. /// Any class that provides data() and size() methods can be passed in. template span (const VectorOrArray& v) : span (v.data(), v.size()) {} /// Returns true if the span is empty. bool empty() const { return s == e; } /// Returns the number of elements. /// The length() and size() methods are equivalent. size_t size() const { return static_cast (e - s); } /// Returns the number of elements. /// The length() and size() methods are equivalent. size_t length() const { return static_cast (e - s); } /// Returns a raw pointer to the start of the data. Item* data() const noexcept { return s; } const Item& front() const { DISTRHO_SAFE_ASSERT_RETURN (! empty(), _nullValue()); return *s; } const Item& back() const { DISTRHO_SAFE_ASSERT_RETURN (! empty(), _nullValue()); return *(e - 1); } Item& front() { DISTRHO_SAFE_ASSERT_RETURN (! empty(), _nullValue()); return *s; } Item& back() { DISTRHO_SAFE_ASSERT_RETURN (! empty(), _nullValue()); return *(e - 1); } const Item& operator[] (size_t index) const { DISTRHO_SAFE_ASSERT_RETURN (index < length(), _nullValue()); return s[index]; } Item& operator[] (size_t index) { DISTRHO_SAFE_ASSERT_RETURN (index < length(), _nullValue()); return s[index]; } /// A handy bonus function for getting a (non-empty) span's tail elements span tail() const { DISTRHO_SAFE_ASSERT_RETURN (! empty(), _nullValue()); return { s + 1, e }; } const Item* begin() const noexcept { return s; } const Item* end() const noexcept { return e; } Item* begin() noexcept { return s; } Item* end() noexcept { return e; } /// Helper function to return a std::vector copy of the span's elements. std::vector::type> createVector() const { return std::vector::type> (s, e); } /// Two spans are considered identical if their elements are all comparable template bool operator== (const OtherSpan& other) const { auto sz = size(); if (sz != other.size()) return false; for (decltype (sz) i = 0; i < sz; ++i) if (s[i] != other.s[i]) return false; return true; } template bool operator!= (const OtherSpan& other) const { return ! operator== (other); } private: Item* s = {}; Item* e = {}; static inline Item& _nullValue() noexcept { static Item e = {}; return e; } }; } // namespace choc #endif // CHOC_SPAN_HEADER_INCLUDED