19#include "sequoia/PlatformSpecific/Preprocessor.hpp"
27 namespace data_structures
31 template<
class Container, std::
integral IndexType>
32 using partition_iterator
33 = utilities::iterator<
34 typename Container::iterator,
35 utilities::identity_dereference_policy<typename Container::iterator, partition_impl::partition_index_policy<false, IndexType>>>;
37 template<
class Container, std::
integral IndexType>
38 using const_partition_iterator
39 = utilities::iterator<
40 typename Container::const_iterator,
41 utilities::identity_dereference_policy<typename Container::const_iterator, partition_impl::partition_index_policy<false, IndexType>>>;
43 template<
class Container, std::
integral IndexType>
44 using reverse_partition_iterator
45 = utilities::iterator<
46 typename Container::reverse_iterator,
47 utilities::identity_dereference_policy<typename Container::reverse_iterator, partition_impl::partition_index_policy<true, IndexType>>>;
49 template<
class Container, std::
integral IndexType>
50 using const_reverse_partition_iterator
51 = utilities::iterator<
52 typename Container::const_reverse_iterator,
53 utilities::identity_dereference_policy<typename Container::const_reverse_iterator, partition_impl::partition_index_policy<true, IndexType>>>;
61 template<
class T,
class Container=std::vector<std::vector<T>>>
66 using container_type = Container;
67 using bucket_type =
typename container_type::value_type;
68 using size_type =
typename container_type::size_type;
69 using index_type = size_type;
70 using allocator_type =
typename container_type::allocator_type;
77 using partition_range = std::ranges::subrange<partition_iterator>;
78 using const_partition_range = std::ranges::subrange<const_partition_iterator>;
80 constexpr static auto npos{partition_iterator::npos};
85 : m_Buckets(allocator)
89 const allocator_type& allocator = allocator_type{})
90 : m_Buckets(allocator)
92 m_Buckets.reserve(list.size());
93 for(
auto iter{list.begin()}; iter != list.end(); ++iter)
96 const auto dist{std::ranges::distance(list.begin(), iter)};
97 m_Buckets[dist].reserve(iter->size());
98 for(
const auto& element : (*iter))
100 push_back_to_partition(dist, element);
108 : m_Buckets(std::allocator_traits<allocator_type>::select_on_container_copy_construction(allocator))
110 m_Buckets.reserve(other.m_Buckets.size());
112 for(
auto i{other.m_Buckets.cbegin()}; i != other.m_Buckets.cend(); ++i)
114 const auto& bucket{*i};
115 const auto dist{std::ranges::distance(other.m_Buckets.cbegin(), i)};
117 m_Buckets.back().reserve(other.m_Buckets[dist].size());
118 for(
const auto& elt : bucket)
120 m_Buckets.back().push_back(elt);
128 : m_Buckets(std::move(other).m_Buckets, allocator)
136 noexcept(
noexcept(std::ranges::swap(this->m_Buckets, other.m_Buckets)))
138 std::ranges::swap(m_Buckets, other.m_Buckets);
142 noexcept(
noexcept(lhs.swap(rhs)))
148 bool empty()
const noexcept
150 return m_Buckets.empty();
154 size_type size()
const
156 return std::accumulate(std::cbegin(m_Buckets), std::cend(m_Buckets), size_type{},
157 [](
const size_type& current,
const auto& bucket){
158 return current + bucket.size();
163 size_type size_of_partition(size_type i)
const
165 return static_cast<size_type
>(std::ranges::distance(partition(i)));
169 size_type num_partitions()
const noexcept {
return m_Buckets.size(); }
171 void swap_partitions(
const size_type i,
const size_type j)
173 if((i < num_partitions()) && (j < num_partitions()))
175 if(i != j) std::ranges::swap(m_Buckets[i], m_Buckets[j]);
180 allocator_type get_allocator()
const
182 return m_Buckets.get_allocator();
187 m_Buckets.emplace_back();
190 void insert_slot(
const size_type pos)
192 if(pos < num_partitions())
194 auto iter{m_Buckets.begin() + pos};
195 m_Buckets.emplace(iter);
203 void erase_slot(
const size_type n)
205 if(n < m_Buckets.size())
207 m_Buckets.erase(m_Buckets.begin() + n);
211 void reserve_partition(
const size_type partition,
const size_type size)
213 if(partition < num_partitions())
214 m_Buckets[partition].reserve(size);
218 size_type partition_capacity(
const size_type partition)
const
220 return partition < num_partitions() ? m_Buckets[partition].capacity() : 0;
223 void reserve_partitions(
const size_type numPartitions)
225 m_Buckets.reserve(numPartitions);
229 size_type num_partitions_capacity()
const noexcept
232 return m_Buckets.capacity();
235 void shrink_num_partitions_to_fit()
237 m_Buckets.shrink_to_fit();
240 void shrink_to_fit(
const size_type partition)
242 if(partition < num_partitions()) m_Buckets[partition].shrink_to_fit();
247 shrink_num_partitions_to_fit();
248 for(
auto& b : m_Buckets) b.shrink_to_fit();
251 void clear()
noexcept
256 template<
class... Args>
257 void push_back_to_partition(
const size_type index, Args&&... args)
259 check_range(
"push_back_to_partition", index);
261 m_Buckets[index].emplace_back(std::forward<Args>(args)...);
264 template<
class... Args>
267 const auto source{pos.partition_index()};
268 check_range(
"insert_to_partition", source);
270 auto iter{m_Buckets[source].emplace(pos.base_iterator(), std::forward<Args>(args)...)};
275 template<
class... Args>
276 partition_iterator insert_to_partition(
const size_type index,
const size_type pos, Args&&... args)
278 check_range(
"insert_to_partition", index, pos);
279 return insert_to_partition(std::ranges::next(begin_partition_raw(index), pos, end_partition_raw(index)), std::forward<Args>(args)...);
284 const auto partition{iter.partition_index()};
285 if(
const auto n{num_partitions()}; partition >= n)
287 return end_partition(n);
289 else if(iter == cend_partition(partition))
291 return end_partition(partition);
294 const auto next{m_Buckets[partition].erase(iter.base_iterator())};
295 return {next, partition};
300 const auto firstPartition{first.partition_index()}, lastPartition{last.partition_index()};
301 if(
const auto n{num_partitions()}; (firstPartition >= n) && (lastPartition >= n))
303 return end_partition(n);
305 else if(lastPartition == firstPartition)
307 if(std::ranges::distance(first, last) > 0)
309 const auto next{m_Buckets[firstPartition].erase(first.base_iterator(), last.base_iterator())};
310 return {next, firstPartition};
313 return std::ranges::next(begin_partition(firstPartition), std::ranges::distance(cbegin_partition(firstPartition), first));
316 throw std::domain_error{std::string{
"bucketed_sequence::erase - Invalid range specified by iterators belonging to partitions ["}
317 .append(std::to_string(firstPartition)).append(
", ").append(std::to_string(lastPartition)).append(
"]")};
322 check_for_empty(
"erase_from_partition");
323 return erase_from_partition(std::ranges::next(begin_partition_raw(index), pos, end_partition_raw(index)));
329 check_for_empty(
"begin_partition");
336 check_for_empty(
"end_partition");
343 check_for_empty(
"begin_partition");
344 return begin_partition_raw(i);
350 check_for_empty(
"end_partition");
351 return end_partition_raw(i);
357 check_for_empty(
"rbegin_partition");
364 check_for_empty(
"rend_partition");
371 check_for_empty(
"rbegin_partition");
379 check_for_empty(
"rend_partition");
386 return begin_partition(i);
392 return end_partition(i);
398 return rbegin_partition(i);
404 return rend_partition(i);
408 partition_range partition(
const size_type i)
410 check_for_empty(
"partition");
417 const_partition_range partition(
const size_type i)
const
419 check_for_empty(
"partition");
426 const_partition_range cpartition(
const size_type i)
const {
return partition(i); }
434 void reset(
const allocator_type& allocator)
noexcept
435 requires (std::allocator_traits<allocator_type>::propagate_on_container_copy_assignment::value)
437 const container_type buckets(allocator);
444 container_type m_Buckets;
446 void check_range(std::string_view method,
const size_type index)
const
448 if(index >= m_Buckets.size())
450 throw std::out_of_range{std::string{
"bucketed_sequence::"}.append(method).append(
"index ").append(std::to_string(index)).append(
" out of range")};
454 void check_range(std::string_view method,
const size_type index,
const size_type pos)
const
456 check_range(method, index);
457 const auto bucketSize{m_Buckets[index].size()};
460 throw std::out_of_range{std::string{
"bucketed_sequence::"}.append(method).append(
"pos ").append(std::to_string(pos)).append(
" out of range")};
464 void check_for_empty(std::string_view method)
const
466 if(m_Buckets.empty())
throw std::out_of_range{std::string{
"bucketed_sequence::"}.append(method).append(
": no buckets\n")};
487 template<
class T,
class Container,
class Partitions>
491 using value_type = T;
492 using container_type = Container;
493 using partitions_type = Partitions;
494 using index_type =
typename partitions_type::value_type;
495 using size_type = std::common_type_t<index_type, typename container_type::size_type>;
501 using partition_range = std::ranges::subrange<partition_iterator>;
502 using const_partition_range = std::ranges::subrange<const_partition_iterator>;
509 constexpr bool empty()
const noexcept {
return m_Data.empty(); }
512 constexpr auto size()
const noexcept {
return m_Data.size(); }
515 constexpr size_type size_of_partition(index_type i)
const
517 return static_cast<size_type
>(std::ranges::distance(partition(i)));
521 constexpr auto num_partitions()
const noexcept {
return m_Partitions.size(); }
526 return get_begin_iterator<partition_iterator>(i, m_Data.begin());
532 return get_end_iterator<partition_iterator>(i, m_Data.begin());
538 return get_begin_iterator<const_partition_iterator>(i, m_Data.cbegin());
544 return get_end_iterator<const_partition_iterator>(i, m_Data.cbegin());
550 return begin_partition(i);
556 return end_partition(i);
562 return get_end_iterator<reverse_partition_iterator>(i, m_Data.rend());
568 return get_begin_iterator<reverse_partition_iterator>(i, m_Data.rend());
574 return get_end_iterator<const_reverse_partition_iterator>(i, m_Data.crend());
580 return get_begin_iterator<const_reverse_partition_iterator>(i, m_Data.crend());
586 return rbegin_partition(i);
592 return rend_partition(i);
596 constexpr partition_range partition(
const index_type i)
noexcept {
return {begin_partition(i), end_partition(i)}; }
599 constexpr const_partition_range partition(
const index_type i)
const noexcept {
return {begin_partition(i), end_partition(i)}; }
602 constexpr const_partition_range cpartition(
const index_type i)
const noexcept {
return partition(i); }
608 constexpr partition_iterator operator[](
const index_type i)
noexcept {
return begin_partition(i); }
610 constexpr void swap_partitions(index_type i, index_type j)
612 if((i < num_partitions()) && (j < num_partitions()))
616 if(i > j) std::ranges::swap(i, j);
618 const auto len_i{std::ranges::distance(partition(i))};
619 const auto len_j{std::ranges::distance(partition(j))};
621 auto begin_i{begin_partition(i).base_iterator()}, begin_j{begin_partition(j).base_iterator()};
622 auto end_i{end_partition(i).base_iterator()}, end_j{end_partition(j).base_iterator()};
623 for(
auto iter_i{begin_i}, iter_j{begin_j}; (iter_i != end_i) && (iter_j != end_j); ++iter_i, ++iter_j)
625 std::ranges::iter_swap(iter_i, iter_j);
630 std::ranges::rotate(begin_i + len_j, begin_i + len_i, end_j);
632 else if(len_j > len_i)
634 std::ranges::rotate(begin_i + len_i, begin_j + len_i, end_j);
640 m_Partitions.begin() + i,
641 m_Partitions.begin() + j,
642 [len_i, len_j](
const index_type index) -> index_type { return static_cast<index_type>(index + len_j - len_i);});
648 template<alloc Allocator, alloc PartitionsAllocator>
649 requires (std::allocator_traits<Allocator>::propagate_on_container_copy_assignment::value
650 && std::allocator_traits<PartitionsAllocator>::propagate_on_container_copy_assignment::value)
651 void reset(
const Allocator& allocator,
const PartitionsAllocator& partitionsAllocator)
noexcept
653 const partitions_type partitions(partitionsAllocator);
654 m_Partitions = partitions;
656 const container_type container{allocator};
664 : m_Partitions{data.first}
665 , m_Data{data.second}
677 noexcept(
noexcept(std::ranges::swap(this->m_Partitions, other.m_Partitions)) &&
noexcept(std::ranges::swap(this->m_Data, other.m_Data)))
679 std::ranges::swap(m_Partitions, other.m_Partitions);
680 std::ranges::swap(m_Data, other.m_Data);
684 auto get_allocator()
const
686 return m_Data.get_allocator();
690 auto get_partitions_allocator()
const
692 return m_Partitions.get_allocator();
695 template<alloc Allocator>
700 template<alloc Allocator, alloc PartitionsAllocator>
702 : m_Partitions(partitionsAllocator)
706 template<alloc Allocator, alloc PartitionsAllocator>
707 constexpr partitioned_sequence_base(std::initializer_list<std::initializer_list<T>> list,
const Allocator& allocator,
const PartitionsAllocator& partitionsAllocator)
708 : m_Partitions(partitionsAllocator)
714 template<alloc Allocator, alloc PartitionsAllocator>
716 : m_Partitions{other.m_Partitions, partitionsAllocator}
717 , m_Data(copy(other.m_Data, allocator))
720 template<alloc Allocator, alloc PartitionsAllocator>
722 : m_Partitions{std::move(in.m_Partitions), partitionsAllocator}
723 , m_Data{std::move(in.m_Data), allocator}
728 m_Partitions.push_back(m_Data.size());
731 void insert_slot(
const size_t pos)
733 if(pos < num_partitions())
735 auto iter{m_Partitions.begin() + pos};
736 const index_type newPartitionBound{(pos == 0) ? 0 : *(iter - 1)};
737 m_Partitions.insert(iter, newPartitionBound);
745 void erase_slot(
const index_type n)
747 if(n < m_Partitions.size())
750 const index_type offset{(n > 0) ? m_Partitions[n - 1] : index_type{}};
751 if(m_Partitions[n] > 0)
753 erased = m_Partitions[n] - offset;
754 m_Data.erase(m_Data.begin() + offset, m_Data.begin() + m_Partitions[n]);
756 m_Partitions.erase(m_Partitions.begin() + n);
757 m_Partitions.mutate(
maths::unsafe_t{}, m_Partitions.begin() + n, m_Partitions.end(), [erased](
const auto index){
return index - erased; });
761 void reserve(
const size_type size)
763 m_Data.reserve(size);
767 index_type capacity()
const noexcept
769 return m_Data.capacity();
772 void reserve_partitions(
const size_type numPartitions)
774 m_Partitions.reserve(numPartitions);
778 index_type num_partitions_capacity()
const noexcept
780 return m_Partitions.capacity();
785 m_Partitions.shrink_to_fit();
786 m_Data.shrink_to_fit();
789 void clear()
noexcept
791 m_Partitions.clear();
795 template<
class... Args>
796 void push_back_to_partition(
const index_type index, Args&&... args)
798 check_range(
"push_back_to_partition", index);
800 auto iter{m_Data.end()};
801 if(index == m_Partitions.size() - 1)
803 m_Data.emplace_back(std::forward<Args>(args)...);
804 iter = --m_Data.end();
808 iter = m_Data.emplace(m_Data.begin() + m_Partitions[index], std::forward<Args>(args)...);
811 increment_partition_indices(index);
814 template<
class... Args>
817 const auto source{pos.partition_index()};
818 check_range(
"insert_to_partition", source);
820 auto iter{m_Data.emplace(pos.base_iterator(), std::forward<Args>(args)...)};
821 increment_partition_indices(source);
826 template<
class... Args>
827 partition_iterator insert_to_partition(
const size_type index,
const size_type pos, Args&&... args)
829 return insert_to_partition(std::ranges::next(cbegin_partition(index), pos, cend_partition(index)), std::forward<Args>(args)...);
834 const auto partition{iter.partition_index()};
835 if(
const auto n{num_partitions()}; partition >= n)
837 return end_partition(n);
839 else if(iter == cend_partition(partition))
841 return end_partition(partition);
844 const auto next{m_Data.erase(iter.base_iterator())};
845 decrement_partition_indices(partition, num_partitions(), 1);
847 return {next, iter.partition_index()};
852 const auto firstPartition{first.partition_index()}, lastPartition{last.partition_index()};
853 if(
const auto n{num_partitions()}; (firstPartition >= n) && (lastPartition >= n))
855 return end_partition(n);
857 else if(lastPartition == firstPartition)
859 if(
const auto numErased{std::ranges::distance(first, last)}; numErased > 0)
861 const auto next{m_Data.erase(first.base_iterator(), last.base_iterator())};
862 decrement_partition_indices(firstPartition, num_partitions(), numErased);
864 return {next, firstPartition};
867 return std::ranges::next(begin_partition(firstPartition), std::ranges::distance(cbegin_partition(firstPartition), first));
870 throw std::domain_error{std::string{
"partitioned_sequence::erase - Invalid range specified by iterators belonging to partitions ["}
871 .append(std::to_string(firstPartition)).append(
", ").append(std::to_string(lastPartition)).append(
"]")};
876 return erase_from_partition(std::ranges::next(cbegin_partition(index), pos, cend_partition(index)));
879 constexpr static index_type npos{partition_iterator::npos};
881 SEQUOIA_NO_UNIQUE_ADDRESS partitions_type m_Partitions;
882 container_type m_Data;
889 void init(std::initializer_list<std::initializer_list<T>> list)
891 m_Partitions.reserve(list.size());
892 m_Data.reserve(std::accumulate(list.begin(), list.end(), std::size_t{}, [](std::size_t n,
auto l) { return n += l.size(); }));
893 for(
auto iter{list.begin()}; iter != list.end(); ++iter)
896 const auto dist{std::ranges::distance(list.begin(), iter)};
897 for(
const auto& element : (*iter))
899 push_back_to_partition(dist, element);
904 template<alloc Allocator>
906 static container_type copy(
const container_type& other,
const Allocator& a)
908 container_type container(std::allocator_traits<Allocator>::select_on_container_copy_construction(a));
910 container.reserve(other.size());
911 for(
const auto& elt : other)
913 container.push_back(elt);
919 void increment_partition_indices(
const size_type first)
noexcept
922 std::ranges::next(m_Partitions.begin(), first, m_Partitions.end()),
924 [](index_type index){
return ++index; });
927 void decrement_partition_indices(
const size_type first,
const size_type last,
const index_type num)
noexcept
930 std::ranges::next(m_Partitions.begin(), first, m_Partitions.end()),
931 std::ranges::next(m_Partitions.begin(), last, m_Partitions.end()),
932 [num](index_type index){
return index -= num; });
935 void check_range(std::string_view method,
const size_type index)
const
937 if(index >= m_Partitions.size())
939 throw std::out_of_range{std::string{
"partition_sequence::"}.append(method).append(
"index ").append(std::to_string(index)).append(
" out of range")};
943 void check_range(std::string_view method,
const size_type index,
const index_type pos)
const
945 check_range(method, index);
946 const index_type maxPos{index ? m_Partitions[index] - m_Partitions[index - 1] : m_Partitions[index]};
949 throw std::out_of_range{std::string{
"partition_sequence::"}.append(method).append(
"pos ").append(std::to_string(pos)).append(
" out of range")};
953 template<
class PartitionIterator, std::input_or_output_iterator Iterator>
955 constexpr PartitionIterator get_begin_iterator(
const index_type i, Iterator iter)
const noexcept
957 const index_type index{i >= m_Partitions.size() ? npos : i};
958 const auto offset{(i > 0 && i < m_Partitions.size()) ? m_Partitions[i-1] : index_type{}};
959 return PartitionIterator::reversed() ? PartitionIterator{iter, index} - offset : PartitionIterator{iter, index} + offset;
962 template<
class PartitionIterator, std::input_or_output_iterator Iterator>
964 constexpr PartitionIterator get_end_iterator(
const index_type i, Iterator iter)
const
966 index_type index{PartitionIterator::reversed() ? index_type{} : npos};
968 [sz{m_Data.size()}] () {
969 if (sz > std::numeric_limits<index_type>::max())
970 throw std::out_of_range{
"Partition offset out of range"};
971 return static_cast<index_type
>(sz);
975 if(i < m_Partitions.size())
978 offset = m_Partitions[i];
981 return PartitionIterator::reversed() ? PartitionIterator{iter, index} - offset : PartitionIterator{iter, index} + offset;
989 template<
class T,
class Container=std::vector<T>,
class Partitions=maths::monotonic_sequence<std::
size_t, std::ranges::greater>>
995 using container_type =
typename partitioned_sequence_base<T, Container, Partitions>::container_type;
996 using partitions_type =
typename partitioned_sequence_base<T, Container, Partitions>::partitions_type;
997 using allocator_type =
typename container_type::allocator_type;
998 using partitions_allocator_type =
typename partitions_type::allocator_type;
1002 partitioned_sequence(
const allocator_type& allocator,
const partitions_allocator_type& partitionAllocator) noexcept
1006 partitioned_sequence(std::initializer_list<std::initializer_list<T>> list,
const allocator_type& allocator=allocator_type{},
const partitions_allocator_type& partitionAllocator=partitions_allocator_type{})
1030 noexcept(
noexcept(lhs.swap(rhs)))
1035 using base_t::add_slot;
1036 using base_t::insert_slot;
1037 using base_t::erase_slot;
1039 using base_t::reserve;
1040 using base_t::capacity;
1041 using base_t::reserve_partitions;
1042 using base_t::num_partitions_capacity;
1043 using base_t::shrink_to_fit;
1044 using base_t::get_allocator;
1045 using base_t::get_partitions_allocator;
1047 using base_t::clear;
1048 using base_t::push_back_to_partition;
1049 using base_t::insert_to_partition;
1050 using base_t::erase_from_partition;
1056 template<std::
integral IndexType, std::
size_t Npartitions>
1061 constexpr static std::size_t num_partitions_v{Npartitions};
1065 constexpr static partitions_type make_partitions(std::initializer_list<std::initializer_list<T>> list)
1067 constexpr auto upper{std::numeric_limits<IndexType>::max()};
1069 [](std::initializer_list<T> l) -> IndexType {
1070 if(l.size() > upper)
1071 throw std::out_of_range{
"Partition size out of bounds"};
1073 return static_cast<IndexType
>(l.size());
1077 auto sizes{utilities::to_array<IndexType, num_partitions_v>(list, fn)};
1080 for(
auto iter{sizes.begin() + 1}; iter != sizes.end(); ++iter)
1082 const auto prev{*(iter - 1)};
1084 if(upper - prev < curr)
1085 throw std::out_of_range{
"Partition index out of bounds"};
1096 template<
class T, std::
size_t Npartitions, std::
size_t Nelements,
class Partitions=maths::static_monotonic_sequence<std::
size_t, Npartitions, std::ranges::greater>>
1102 using container_type =
typename base_t::container_type;
1103 using partitions_type =
typename base_t::partitions_type;
1104 using size_type =
typename base_t::size_type;
1105 using index_type =
typename base_t::index_type;
1107 constexpr static std::size_t num_partitions_v{Npartitions};
1108 constexpr static std::size_t num_elements_v{Nelements};
1113 :
base_t{fill(std::make_index_sequence<num_elements_v>(), list)}
1125 noexcept(
noexcept(lhs.swap(rhs)))
1130 template<size_type... Inds>
1132 constexpr static std::pair<partitions_type, container_type> fill(std::index_sequence<Inds...>, std::initializer_list<std::initializer_list<T>> list)
1134 if(list.size() != num_partitions_v)
1135 throw std::logic_error{std::string{
"Inconsistent number of elements supplied by initializer lists: expected "}
1136 .append(std::to_string(num_partitions_v)).append(
" but got ").append(std::to_string(list.size()))};
1140 const size_type total{std::accumulate(list.begin(), list.end(), size_type{}, [](size_type val, std::initializer_list<T> l){ return val + l.size(); })};
1142 if(total != num_elements_v)
1143 throw std::logic_error{std::string{
"Inconsistent number of elements supplied by initializer lists: expected "}
1144 .append(std::to_string(num_elements_v)).append(
" but got ").append(std::to_string(total))};
1146 if constexpr(
sizeof...(Inds) > 0)
1148 index_type partitionIndex{};
1149 return {partitions, container_type{make_element(Inds, list, partitions, partitionIndex)...}};
1153 return {partitions, container_type{}};
1159 constexpr static T make_element(size_type i, std::initializer_list<std::initializer_list<T>> list,
const partitions_type& partitions, index_type& partitionIndex)
1161 auto boundary{partitions[partitionIndex]};
1162 while(i == boundary)
1164 boundary = partitions[++partitionIndex];
1167 auto index{partitionIndex ? i - partitions[partitionIndex - 1] : i};
1169 return T{*((list.begin() + partitionIndex)->begin() + index)};
A collection of constexpr algorithms.
Utility to convert an initializer_list into an array, potentially transforming the initializer_list i...
Implementation for an iterator with policies controlling dereferencing and auxiliary data.
Classes implementing the concept of a monotonic sequence.
Metaprogramming components for partitioned data.
Storage for partitioned data such that data within each partition is contiguous.
Definition: PartitionedData.hpp:63
Base class for partitioned sequences where data is contiguous across all partitions.
Definition: PartitionedData.hpp:489
Definition: PartitionedData.hpp:991
Definition: PartitionedData.hpp:1099
Definition: MonotonicSequence.hpp:303
An iterator with policies controlling dereferencing and auxiliary data.
Definition: Iterator.hpp:234
Definition: PartitionedData.hpp:1054
Definition: MonotonicSequence.hpp:22