svector.hh 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101
  1. // -*- mode: c++; coding: utf-8 -*-
  2. // ra-ra - Basic dynamic size vector that isn't foreign
  3. // From https://github.com/KonanM/vector. Removed rebinding support...
  4. #pragma once
  5. #include <cstddef>
  6. #include <memory>
  7. #include <type_traits>
  8. #include <vector>
  9. #include "ra/expr.hh"
  10. namespace ra {
  11. template <class T, size_t N>
  12. struct sb_alloc
  13. {
  14. // Cf https://old.reddit.com/r/cpp/comments/hfv24j/small_vector_implementation_using_propagate_on/fw1kw7u/
  15. alignas(alignof(T)) T buffer[N];
  16. std::allocator<T> alloc;
  17. bool used = false;
  18. using value_type = T;
  19. // have to set this three values, as they are responsible for the correct handling of the move assignment operator.
  20. using propagate_on_container_move_assignment = std::false_type;
  21. using propagate_on_container_swap = std::false_type;
  22. using is_always_equal = std::false_type;
  23. template <class U> struct rebind { using other = sb_alloc<U, N>; };
  24. constexpr sb_alloc() noexcept = default;
  25. template <class U> constexpr sb_alloc(sb_alloc<U, N> const &) noexcept {}
  26. // don't copy the small buffer for the copy/move constructors, as that is done through the vector.
  27. constexpr sb_alloc(sb_alloc const & s) noexcept : used(s.used) {}
  28. constexpr sb_alloc & operator=(sb_alloc const & s) noexcept { used = s.used; return *this; }
  29. constexpr sb_alloc(sb_alloc &&) noexcept {}
  30. constexpr sb_alloc & operator=(sb_alloc const &&) noexcept { return *this; }
  31. [[nodiscard]] constexpr T *
  32. allocate(size_t const n)
  33. {
  34. used = (n <= N);
  35. if (used) {
  36. return buffer;
  37. } else {
  38. return alloc.allocate(n);
  39. }
  40. }
  41. constexpr void
  42. deallocate(void * p, const size_t n)
  43. {
  44. used = false;
  45. if (buffer != p) {
  46. alloc.deallocate(static_cast<T *>(p), n);
  47. }
  48. }
  49. // when propagate_on_container_move_assignment is false and this comparison returns false, an elementwise move is done instead of just taking over the memory. So the comparison has to return false when the small buffer is active.
  50. constexpr bool
  51. operator==(sb_alloc const & rhs) const
  52. {
  53. return !this->used && !rhs.used;
  54. }
  55. };
  56. template <class T, size_t N=4>
  57. struct vector: public std::vector<T, sb_alloc<T, N>>
  58. {
  59. using V = std::vector<T, sb_alloc<T, N>>;
  60. // tell V we already have this capacity. Must be done in every constructor.
  61. constexpr vector() noexcept { V::reserve(N); }
  62. constexpr vector(vector const &) = default;
  63. constexpr vector & operator=(vector const &) = default;
  64. constexpr vector(vector && v) noexcept(std::is_nothrow_move_constructible_v<T>): vector()
  65. {
  66. V::operator=(std::move(v));
  67. }
  68. constexpr vector & operator=(vector && v) noexcept(std::is_nothrow_move_constructible_v<T>)
  69. {
  70. V::operator=(std::move(v));
  71. return *this;
  72. }
  73. constexpr explicit vector(size_t count): vector() { V::resize(count); } // hmm
  74. constexpr vector(size_t count, T const & value): vector() { V::assign(count, value); }
  75. template <class It> constexpr vector(It first, It last): vector() { V::insert(V::begin(), first, last); }
  76. constexpr vector(std::initializer_list<T> init): vector() { V::insert(V::begin(), init); }
  77. constexpr friend void swap(vector & a, vector & b) noexcept
  78. {
  79. std::swap(static_cast<V &>(a), static_cast<V &>(b));
  80. }
  81. using V::data, V::size;
  82. template <rank_t c=0> constexpr auto iter()
  83. {
  84. if constexpr (0==c) { return ra::ptr(data(), size()); } else { static_assert(always_false<c>); } // tbd
  85. }
  86. template <rank_t c=0> constexpr auto iter() const
  87. {
  88. if constexpr (0==c) { return ra::ptr(data(), size()); } else { static_assert(always_false<c>); } // tbd
  89. }
  90. };
  91. } // namespace ra