You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

128 lines
5.8KB

  1. //
  2. // ██████ ██  ██  ██████  ██████
  3. // ██      ██  ██ ██    ██ ██       ** Clean Header-Only Classes **
  4. // ██  ███████ ██  ██ ██
  5. // ██  ██   ██ ██  ██ ██ https://github.com/Tracktion/choc
  6. //  ██████ ██  ██  ██████   ██████
  7. //
  8. // CHOC is (C)2021 Tracktion Corporation, and is offered under the terms of the ISC license:
  9. //
  10. // Permission to use, copy, modify, and/or distribute this software for any purpose with or
  11. // without fee is hereby granted, provided that the above copyright notice and this permission
  12. // notice appear in all copies. THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
  13. // WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
  14. // AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR
  15. // CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
  16. // WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
  17. // CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  18. #ifndef CHOC_SPAN_HEADER_INCLUDED
  19. #define CHOC_SPAN_HEADER_INCLUDED
  20. #include <vector>
  21. #include "DistrhoUtils.hpp"
  22. namespace choc
  23. {
  24. //==============================================================================
  25. /** This is a temporary stunt-double for std::span, with the intention of it being
  26. deprecated when there's more widespread compiler support for the real std::span.
  27. This class has fewer bells-and-whistles than a real std::span, but it does have
  28. the advantage of calling CHOC_ASSERT when mistakes are made like out-of-range
  29. accesses, which can be useful for getting clean error handling rather than UB.
  30. */
  31. template <typename Item>
  32. struct span
  33. {
  34. span() = default;
  35. span (const span&) = default;
  36. span (span&&) = default;
  37. span& operator= (span&&) = default;
  38. span& operator= (const span&) = default;
  39. /// Construct from some raw start and end pointers. For an empty span, these
  40. /// can both be nullptr, but if one is a real pointer then the caller must ensure
  41. /// that start <= end.
  42. span (Item* start, Item* end) noexcept : s (start), e (end) {}
  43. /// Constructs a span from a pointer and length.
  44. /// The pointer must not be nullptr unless the length is 0.
  45. span (const Item* start, size_t length) noexcept : span (const_cast<Item*> (start), const_cast<Item*> (start) + length) {}
  46. /// Constructor taking a raw C++ array.
  47. template <size_t length>
  48. span (Item (&array)[length]) : span (array, length) {}
  49. /// Constructor which takes some kind of class like std::vector or std::array.
  50. /// Any class that provides data() and size() methods can be passed in.
  51. template <typename VectorOrArray>
  52. span (const VectorOrArray& v) : span (v.data(), v.size()) {}
  53. /// Returns true if the span is empty.
  54. bool empty() const { return s == e; }
  55. /// Returns the number of elements.
  56. /// The length() and size() methods are equivalent.
  57. size_t size() const { return static_cast<size_t> (e - s); }
  58. /// Returns the number of elements.
  59. /// The length() and size() methods are equivalent.
  60. size_t length() const { return static_cast<size_t> (e - s); }
  61. /// Returns a raw pointer to the start of the data.
  62. Item* data() const noexcept { return s; }
  63. const Item& front() const { DISTRHO_SAFE_ASSERT_RETURN (! empty(), _nullValue()); return *s; }
  64. const Item& back() const { DISTRHO_SAFE_ASSERT_RETURN (! empty(), _nullValue()); return *(e - 1); }
  65. Item& front() { DISTRHO_SAFE_ASSERT_RETURN (! empty(), _nullValue()); return *s; }
  66. Item& back() { DISTRHO_SAFE_ASSERT_RETURN (! empty(), _nullValue()); return *(e - 1); }
  67. const Item& operator[] (size_t index) const { DISTRHO_SAFE_ASSERT_RETURN (index < length(), _nullValue()); return s[index]; }
  68. Item& operator[] (size_t index) { DISTRHO_SAFE_ASSERT_RETURN (index < length(), _nullValue()); return s[index]; }
  69. /// A handy bonus function for getting a (non-empty) span's tail elements
  70. span tail() const { DISTRHO_SAFE_ASSERT_RETURN (! empty(), _nullValue()); return { s + 1, e }; }
  71. const Item* begin() const noexcept { return s; }
  72. const Item* end() const noexcept { return e; }
  73. Item* begin() noexcept { return s; }
  74. Item* end() noexcept { return e; }
  75. /// Helper function to return a std::vector copy of the span's elements.
  76. std::vector<typename std::remove_const<Item>::type> createVector() const
  77. {
  78. return std::vector<typename std::remove_const<Item>::type> (s, e);
  79. }
  80. /// Two spans are considered identical if their elements are all comparable
  81. template <typename OtherSpan>
  82. bool operator== (const OtherSpan& other) const
  83. {
  84. auto sz = size();
  85. if (sz != other.size())
  86. return false;
  87. for (decltype (sz) i = 0; i < sz; ++i)
  88. if (s[i] != other.s[i])
  89. return false;
  90. return true;
  91. }
  92. template <typename OtherSpan>
  93. bool operator!= (const OtherSpan& other) const { return ! operator== (other); }
  94. private:
  95. Item* s = {};
  96. Item* e = {};
  97. static inline Item& _nullValue() noexcept { static Item e = {}; return e; }
  98. };
  99. } // namespace choc
  100. #endif // CHOC_SPAN_HEADER_INCLUDED