index_set.hpp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325
  1. ////////////////////////////////////////////////////////////////////////////
  2. //
  3. // Copyright 2015 Realm Inc.
  4. //
  5. // Licensed under the Apache License, Version 2.0 (the "License");
  6. // you may not use this file except in compliance with the License.
  7. // You may obtain a copy of the License at
  8. //
  9. // http://www.apache.org/licenses/LICENSE-2.0
  10. //
  11. // Unless required by applicable law or agreed to in writing, software
  12. // distributed under the License is distributed on an "AS IS" BASIS,
  13. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14. // See the License for the specific language governing permissions and
  15. // limitations under the License.
  16. //
  17. ////////////////////////////////////////////////////////////////////////////
  18. #ifndef REALM_INDEX_SET_HPP
  19. #define REALM_INDEX_SET_HPP
  20. #include <cstddef>
  21. #include <initializer_list>
  22. #include <iterator>
  23. #include <type_traits>
  24. #include <utility>
  25. #include <vector>
  26. namespace realm {
  27. namespace _impl {
  28. template<typename OuterIterator>
  29. class MutableChunkedRangeVectorIterator;
  30. // An iterator for ChunkedRangeVector, templated on the vector iterator/const_iterator
  31. template<typename OuterIterator>
  32. class ChunkedRangeVectorIterator {
  33. public:
  34. using iterator_category = std::bidirectional_iterator_tag;
  35. using value_type = typename std::remove_reference<decltype(*OuterIterator()->data.begin())>::type;
  36. using difference_type = ptrdiff_t;
  37. using pointer = const value_type*;
  38. using reference = const value_type&;
  39. ChunkedRangeVectorIterator(OuterIterator outer, OuterIterator end, value_type* inner)
  40. : m_outer(outer), m_end(end), m_inner(inner) { }
  41. reference operator*() const noexcept { return *m_inner; }
  42. pointer operator->() const noexcept { return m_inner; }
  43. template<typename Other> bool operator==(Other const& it) const noexcept;
  44. template<typename Other> bool operator!=(Other const& it) const noexcept;
  45. ChunkedRangeVectorIterator& operator++() noexcept;
  46. ChunkedRangeVectorIterator operator++(int) noexcept;
  47. ChunkedRangeVectorIterator& operator--() noexcept;
  48. ChunkedRangeVectorIterator operator--(int) noexcept;
  49. // Advance directly to the next outer block
  50. void next_chunk() noexcept;
  51. OuterIterator outer() const noexcept { return m_outer; }
  52. size_t offset() const noexcept { return m_inner - &m_outer->data[0]; }
  53. private:
  54. OuterIterator m_outer;
  55. OuterIterator m_end;
  56. value_type* m_inner;
  57. friend struct ChunkedRangeVector;
  58. friend class MutableChunkedRangeVectorIterator<OuterIterator>;
  59. };
  60. // A mutable iterator that adds some invariant-preserving mutation methods
  61. template<typename OuterIterator>
  62. class MutableChunkedRangeVectorIterator : public ChunkedRangeVectorIterator<OuterIterator> {
  63. public:
  64. using ChunkedRangeVectorIterator<OuterIterator>::ChunkedRangeVectorIterator;
  65. // Set this iterator to the given range and update the parent if needed
  66. void set(size_t begin, size_t end);
  67. // Adjust the begin and end of this iterator by the given amounts and
  68. // update the parent if needed
  69. void adjust(ptrdiff_t front, ptrdiff_t back);
  70. // Shift this iterator by the given amount and update the parent if needed
  71. void shift(ptrdiff_t distance);
  72. };
  73. // A vector which stores ranges in chunks with a maximum size
  74. struct ChunkedRangeVector {
  75. struct Chunk {
  76. std::vector<std::pair<size_t, size_t>> data;
  77. size_t begin;
  78. size_t end;
  79. size_t count;
  80. };
  81. std::vector<Chunk> m_data;
  82. using value_type = std::pair<size_t, size_t>;
  83. using iterator = MutableChunkedRangeVectorIterator<typename decltype(m_data)::iterator>;
  84. using const_iterator = ChunkedRangeVectorIterator<typename decltype(m_data)::const_iterator>;
  85. #ifdef REALM_DEBUG
  86. static const size_t max_size = 4;
  87. #else
  88. static const size_t max_size = 4096 / sizeof(std::pair<size_t, size_t>);
  89. #endif
  90. iterator begin() noexcept { return empty() ? end() : iterator(m_data.begin(), m_data.end(), &m_data[0].data[0]); }
  91. iterator end() noexcept { return iterator(m_data.end(), m_data.end(), nullptr); }
  92. const_iterator begin() const noexcept { return cbegin(); }
  93. const_iterator end() const noexcept { return cend(); }
  94. const_iterator cbegin() const noexcept { return empty() ? cend() : const_iterator(m_data.cbegin(), m_data.end(), &m_data[0].data[0]); }
  95. const_iterator cend() const noexcept { return const_iterator(m_data.end(), m_data.end(), nullptr); }
  96. bool empty() const noexcept { return m_data.empty(); }
  97. iterator insert(iterator pos, value_type value);
  98. iterator erase(iterator pos) noexcept;
  99. void push_back(value_type value);
  100. iterator ensure_space(iterator pos);
  101. void verify() const noexcept;
  102. };
  103. } // namespace _impl
  104. class IndexSet : private _impl::ChunkedRangeVector {
  105. public:
  106. static const size_t npos = -1;
  107. using ChunkedRangeVector::value_type;
  108. using ChunkedRangeVector::iterator;
  109. using ChunkedRangeVector::const_iterator;
  110. using ChunkedRangeVector::begin;
  111. using ChunkedRangeVector::end;
  112. using ChunkedRangeVector::empty;
  113. using ChunkedRangeVector::verify;
  114. IndexSet() = default;
  115. IndexSet(std::initializer_list<size_t>);
  116. // Check if the index set contains the given index
  117. bool contains(size_t index) const noexcept;
  118. // Counts the number of indices in the set in the given range
  119. size_t count(size_t start_index=0, size_t end_index=-1) const noexcept;
  120. // Add an index to the set, doing nothing if it's already present
  121. void add(size_t index);
  122. void add(IndexSet const& is);
  123. // Add an index which has had all of the ranges in the set before it removed
  124. // Returns the unshifted index
  125. size_t add_shifted(size_t index);
  126. // Add indexes which have had the ranges in `shifted_by` added and the ranges
  127. // in the current set removed
  128. void add_shifted_by(IndexSet const& shifted_by, IndexSet const& values);
  129. // Remove all indexes from the set and then add a single range starting from
  130. // zero with the given length
  131. void set(size_t len);
  132. // Insert an index at the given position, shifting existing indexes at or
  133. // after that point back by one
  134. void insert_at(size_t index, size_t count=1);
  135. void insert_at(IndexSet const&);
  136. // Shift indexes at or after the given point back by one
  137. void shift_for_insert_at(size_t index, size_t count=1);
  138. void shift_for_insert_at(IndexSet const&);
  139. // Delete an index at the given position, shifting indexes after that point
  140. // forward by one
  141. void erase_at(size_t index);
  142. void erase_at(IndexSet const&);
  143. // If the given index is in the set remove it and return npos; otherwise unshift() it
  144. size_t erase_or_unshift(size_t index);
  145. // Remove the indexes at the given index from the set, without shifting
  146. void remove(size_t index, size_t count=1);
  147. void remove(IndexSet const&);
  148. // Shift an index by inserting each of the indexes in this set
  149. size_t shift(size_t index) const noexcept;
  150. // Shift an index by deleting each of the indexes in this set
  151. size_t unshift(size_t index) const noexcept;
  152. // Remove all indexes from the set
  153. void clear() noexcept;
  154. // An iterator over the individual indices in the set rather than the ranges
  155. class IndexIterator : public std::iterator<std::forward_iterator_tag, size_t> {
  156. public:
  157. IndexIterator(IndexSet::const_iterator it) : m_iterator(it) { }
  158. size_t operator*() const noexcept { return m_iterator->first + m_offset; }
  159. bool operator==(IndexIterator const& it) const noexcept { return m_iterator == it.m_iterator; }
  160. bool operator!=(IndexIterator const& it) const noexcept { return m_iterator != it.m_iterator; }
  161. IndexIterator& operator++() noexcept
  162. {
  163. ++m_offset;
  164. if (m_iterator->first + m_offset == m_iterator->second) {
  165. ++m_iterator;
  166. m_offset = 0;
  167. }
  168. return *this;
  169. }
  170. IndexIterator operator++(int) noexcept
  171. {
  172. auto value = *this;
  173. ++*this;
  174. return value;
  175. }
  176. private:
  177. IndexSet::const_iterator m_iterator;
  178. size_t m_offset = 0;
  179. };
  180. class IndexIteratableAdaptor {
  181. public:
  182. using value_type = size_t;
  183. using iterator = IndexIterator;
  184. using const_iterator = iterator;
  185. const_iterator begin() const noexcept { return m_index_set.begin(); }
  186. const_iterator end() const noexcept { return m_index_set.end(); }
  187. IndexIteratableAdaptor(IndexSet const& is) : m_index_set(is) { }
  188. private:
  189. IndexSet const& m_index_set;
  190. };
  191. IndexIteratableAdaptor as_indexes() const noexcept { return *this; }
  192. private:
  193. // Find the range which contains the index, or the first one after it if
  194. // none do
  195. iterator find(size_t index) noexcept;
  196. iterator find(size_t index, iterator it) noexcept;
  197. // Insert the index before the given position, combining existing ranges as
  198. // applicable
  199. // returns inserted position
  200. iterator do_add(iterator pos, size_t index);
  201. void do_erase(iterator it, size_t index);
  202. iterator do_remove(iterator it, size_t index, size_t count);
  203. void shift_until_end_by(iterator begin, ptrdiff_t shift);
  204. };
  205. namespace util {
  206. // This was added in C++14 but is missing from libstdc++ 4.9
  207. template<typename Iterator>
  208. std::reverse_iterator<Iterator> make_reverse_iterator(Iterator it) noexcept
  209. {
  210. return std::reverse_iterator<Iterator>(it);
  211. }
  212. } // namespace util
  213. namespace _impl {
  214. template<typename T>
  215. template<typename OtherIterator>
  216. inline bool ChunkedRangeVectorIterator<T>::operator==(OtherIterator const& it) const noexcept
  217. {
  218. return m_outer == it.outer() && m_inner == it.operator->();
  219. }
  220. template<typename T>
  221. template<typename OtherIterator>
  222. inline bool ChunkedRangeVectorIterator<T>::operator!=(OtherIterator const& it) const noexcept
  223. {
  224. return !(*this == it);
  225. }
  226. template<typename T>
  227. inline ChunkedRangeVectorIterator<T>& ChunkedRangeVectorIterator<T>::operator++() noexcept
  228. {
  229. ++m_inner;
  230. if (offset() == m_outer->data.size())
  231. next_chunk();
  232. return *this;
  233. }
  234. template<typename T>
  235. inline ChunkedRangeVectorIterator<T> ChunkedRangeVectorIterator<T>::operator++(int) noexcept
  236. {
  237. auto value = *this;
  238. ++*this;
  239. return value;
  240. }
  241. template<typename T>
  242. inline ChunkedRangeVectorIterator<T>& ChunkedRangeVectorIterator<T>::operator--() noexcept
  243. {
  244. if (!m_inner || m_inner == &m_outer->data.front()) {
  245. --m_outer;
  246. m_inner = &m_outer->data.back();
  247. }
  248. else {
  249. --m_inner;
  250. }
  251. return *this;
  252. }
  253. template<typename T>
  254. inline ChunkedRangeVectorIterator<T> ChunkedRangeVectorIterator<T>::operator--(int) noexcept
  255. {
  256. auto value = *this;
  257. --*this;
  258. return value;
  259. }
  260. template<typename T>
  261. inline void ChunkedRangeVectorIterator<T>::next_chunk() noexcept
  262. {
  263. ++m_outer;
  264. m_inner = m_outer != m_end ? &m_outer->data[0] : nullptr;
  265. }
  266. } // namespace _impl
  267. } // namespace realm
  268. #endif // REALM_INDEX_SET_HPP