1+ #pragma once
2+
3+ #include < cassert>
4+ #include < iterator>
5+ #include < utility>
6+
7+ #include < range/v3/algorithm/copy.hpp>
8+
9+ #include " openvic-simulation/core/Assert.hpp"
10+
11+ namespace OpenVic ::utility {
12+ template <typename Container>
13+ struct bulk_insert_wrapper {
14+ // Member types based on std::vector
15+ #define USING_CONTAINER (member ) using member = typename Container::member
16+ public:
17+ USING_CONTAINER (value_type);
18+ USING_CONTAINER (allocator_type);
19+ USING_CONTAINER (size_type);
20+ USING_CONTAINER (difference_type);
21+ USING_CONTAINER (reference);
22+ USING_CONTAINER (const_reference);
23+ USING_CONTAINER (pointer);
24+ USING_CONTAINER (const_pointer);
25+ USING_CONTAINER (iterator);
26+ USING_CONTAINER (const_iterator);
27+ USING_CONTAINER (reverse_iterator);
28+ USING_CONTAINER (const_reverse_iterator);
29+ #undef USING_CONTAINER
30+
31+ private:
32+ Container container;
33+ size_type valid_size {};
34+ size_type pending_extra_size {};
35+
36+ constexpr void flush_pending_room () {
37+ if (pending_extra_size > size_type{}) {
38+ container.resize (valid_size + pending_extra_size);
39+ pending_extra_size = size_type{};
40+ }
41+ }
42+
43+ constexpr size_type get_invalid_element_count () const {
44+ return container.size () - valid_size;
45+ }
46+
47+ public:
48+ constexpr allocator_type get_allocator () const {
49+ return container.get_allocator ();
50+ }
51+
52+ constexpr bulk_insert_wrapper () noexcept {};
53+
54+ // Forwarding constructor for custom allocators or initial capacities
55+ template <typename ... Args>
56+ explicit bulk_insert_wrapper (Args&&... args)
57+ : container(std::forward<Args>(args)...) {}
58+
59+ constexpr void make_room_for (const size_type count) noexcept {
60+ pending_extra_size += count;
61+ }
62+
63+ // Element access based on std::vector
64+ constexpr reference operator [](const size_type pos) {
65+ OV_HARDEN_ASSERT_ACCESS (pos, " operator[]" );
66+ return container[pos];
67+ }
68+ constexpr const_reference operator [](const size_type pos) const {
69+ OV_HARDEN_ASSERT_ACCESS (pos, " operator[]" );
70+ return container[pos];
71+ }
72+
73+ constexpr reference front () {
74+ OV_HARDEN_ASSERT_NONEMPTY (" front" );
75+ return container.front ();
76+ }
77+ constexpr const_reference front () const {
78+ OV_HARDEN_ASSERT_NONEMPTY (" front" );
79+ return container.front ();
80+ }
81+
82+ constexpr reference back () {
83+ OV_HARDEN_ASSERT_NONEMPTY (" back" );
84+ return container[size ()-1 ];
85+ }
86+ constexpr const_reference back () const {
87+ OV_HARDEN_ASSERT_NONEMPTY (" back" );
88+ return container[size ()-1 ];
89+ }
90+
91+ constexpr value_type* data () noexcept { return container.data (); }
92+ constexpr value_type const * data () const noexcept { return container.data (); }
93+
94+ // Iterators based on std::vector
95+ constexpr iterator begin () noexcept {
96+ return container.begin ();
97+ }
98+ constexpr const_iterator begin () const noexcept {
99+ return container.begin ();
100+ }
101+ constexpr const_iterator cbegin () const noexcept {
102+ return container.cbegin ();
103+ }
104+
105+ constexpr iterator end () noexcept {
106+ return std::next (begin (), valid_size);
107+ }
108+ constexpr const_iterator end () const noexcept {
109+ return std::next (begin (), valid_size);
110+ }
111+ constexpr const_iterator cend () const noexcept {
112+ return std::next (cbegin (), valid_size);
113+ }
114+
115+ constexpr reverse_iterator rbegin () noexcept {
116+ return std::next (container.rbegin (), get_invalid_element_count ());
117+ }
118+ constexpr const_reverse_iterator rbegin () const noexcept {
119+ return std::next (container.rbegin (), get_invalid_element_count ());
120+ }
121+ constexpr const_reverse_iterator crbegin () const noexcept {
122+ return std::next (container.crbegin (), get_invalid_element_count ());
123+ }
124+
125+ constexpr reverse_iterator rend () noexcept {
126+ return container.rend ();
127+ }
128+ constexpr const_reverse_iterator rend () const noexcept {
129+ return container.rend ();
130+ }
131+ constexpr const_reverse_iterator crend () const noexcept {
132+ return container.crend ();
133+ }
134+
135+ // Capacity based on std::vector
136+ constexpr bool empty () const noexcept { return valid_size <= size_type{}; }
137+ constexpr size_type size () const noexcept { return valid_size; }
138+ constexpr size_type max_size () const noexcept { return container.max_size (); }
139+ // reserve() is omitted as we manage that via make_room_for
140+ constexpr size_type capacity () const noexcept { return container.capacity (); }
141+ constexpr void shrink_to_fit () {
142+ pending_extra_size = size_type{};
143+ container.resize (valid_size);
144+ container.shrink_to_fit ();
145+ }
146+
147+ // Modifiers based on std::vector
148+ constexpr void clear () noexcept {
149+ valid_size = size_type{};
150+ pending_extra_size = size_type{};
151+ container.clear ();
152+ }
153+
154+ // the following could be implemented:
155+ // - insert
156+ // - insert_range
157+ // - emplace
158+ // - erase
159+ // - append_range (C++23)
160+ // - pop_back
161+ // - swap
162+
163+ constexpr void push_back (value_type const & value) {
164+ ++valid_size;
165+ return container.push_back (value);
166+
167+ }
168+ constexpr void push_back (value_type&& value) {
169+ ++valid_size;
170+ return container.push_back (std::forward<decltype (value)>(value));
171+ }
172+
173+ template <typename ... Args>
174+ constexpr reference emplace_back (Args&&... args) {
175+ ++valid_size;
176+ return container.emplace_back (std::forward<Args>(args)...);
177+ }
178+
179+ template <typename OtherContainerT>
180+ constexpr void append_range (OtherContainerT const & other) {
181+ append_range (other.begin (), other.end ());
182+ }
183+
184+ template <typename InputIt>
185+ constexpr void append_range (const InputIt first, const InputIt last) {
186+ flush_pending_room ();
187+
188+ const size_type new_valid_size = valid_size + (last - first);
189+ assert (new_valid_size <= container.capacity ());
190+
191+ ranges::copy (
192+ first,
193+ last,
194+ end ()
195+ );
196+ valid_size = new_valid_size;
197+ }
198+
199+ // resize() is omitted as we manage that via make_room_for
200+ };
201+ }
0 commit comments