Skip to content

Commit 8215f0e

Browse files
committed
BulkInsertWrapper
1 parent 79f0994 commit 8215f0e

3 files changed

Lines changed: 209 additions & 42 deletions

File tree

src/openvic-simulation/modifier/ModifierSum.cpp

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -31,8 +31,6 @@ memory::string modifier_entry_t::to_string() const {
3131
}
3232

3333
void ModifierSum::clear() {
34-
extra_size = 0;
35-
valid_size = 0;
3634
modifiers.clear();
3735
value_sum.clear();
3836
}
@@ -63,6 +61,5 @@ void ModifierSum::add_modifier(
6361
new_entry.multiplier,
6462
new_entry.excluded_targets
6563
);
66-
++valid_size;
6764
}
6865
}

src/openvic-simulation/modifier/ModifierSum.hpp

Lines changed: 8 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,12 @@
33
#include <cstddef>
44
#include <variant>
55

6-
#include <range/v3/algorithm/copy.hpp>
7-
86
#include "openvic-simulation/core/portable/ForwardableSpan.hpp"
97
#include "openvic-simulation/dataloader/NodeTools.hpp"
108
#include "openvic-simulation/modifier/ModifierValue.hpp"
119
#include "openvic-simulation/modifier/Modifier.hpp"
1210
#include "openvic-simulation/types/fixed_point/FixedPoint.hpp"
11+
#include "openvic-simulation/utility/BulkInsertWrapper.hpp"
1312
#include "openvic-simulation/utility/Containers.hpp"
1413

1514
namespace OpenVic {
@@ -113,42 +112,29 @@ namespace OpenVic {
113112

114113
struct ModifierSum {
115114
private:
116-
// to optimise adding other modifier sums
117-
std::size_t extra_size { 0 };
118-
std::size_t valid_size { 0 }; //everything beyond this is empty
119-
120115
// Default source used for any modifier added to the sum without an explicit non-null source,
121116
// representing the object the sum is attached to.
122117
modifier_entry_t::modifier_source_t PROPERTY_RW(this_source);
123118
// Targets to be excluded from all modifiers added to the sum, combined with any explicit exclusions.
124119
ModifierEffect::target_t PROPERTY_RW(this_excluded_targets, ModifierEffect::target_t::NO_TARGETS);
125120

126-
memory::vector<modifier_entry_t> modifiers;
121+
utility::bulk_insert_wrapper<
122+
memory::vector<modifier_entry_t>
123+
> SPAN_PROPERTY(modifiers);
127124
ModifierValue PROPERTY(value_sum);
128125

129-
constexpr void reserve(const std::size_t new_capacity) {
130-
modifiers.reserve(new_capacity);
131-
}
132-
constexpr void resize(const std::size_t new_size) {
133-
modifiers.resize(new_size);
134-
}
135-
136126
public:
137127
ModifierSum() {};
138128
ModifierSum(ModifierSum const&) = default;
139129
ModifierSum(ModifierSum&&) = default;
140130
ModifierSum& operator=(ModifierSum const&) = default;
141131
ModifierSum& operator=(ModifierSum&&) = default;
142132

143-
constexpr forwardable_span<const modifier_entry_t> get_modifiers() const {
144-
return { modifiers.data(), size() };
145-
}
146-
147133
constexpr std::size_t size() const {
148-
return valid_size;
134+
return modifiers.size();
149135
}
150136
constexpr bool empty() const {
151-
return valid_size == 0;
137+
return modifiers.empty();
152138
}
153139
void clear();
154140

@@ -163,34 +149,17 @@ namespace OpenVic {
163149
);
164150

165151
constexpr void make_room_for(ModifierSum const& modifier_sum) {
166-
extra_size += modifier_sum.valid_size;
152+
modifiers.make_room_for(modifier_sum.size());
167153
}
168154

169155
// Inserts modifiers directly via std::ranges::copy. Requires resizing beforehand!
170156
// with the modifier entries' attributes as arguments. This means non-null sources are preserved (null ones are
171157
// replaced with this_source, but in practice the other sum should've set them itself already) and exclusion targets
172158
// are combined with this_excluded_targets.
173159
constexpr void add_modifier_sum(ModifierSum const& modifier_sum) {
174-
if (extra_size > 0) {
175-
resize(
176-
valid_size
177-
+ extra_size
178-
);
179-
extra_size = 0;
180-
}
181-
182-
const std::size_t new_valid_size = valid_size + modifier_sum.valid_size;
183-
assert(new_valid_size <= modifiers.capacity());
184-
185160
// We could test that excluded_targets != ALL_TARGETS, but in practice it's always
186161
// called with an explcit/hardcoded value and so won't ever exclude everything.
187-
ranges::copy(
188-
modifier_sum.modifiers.begin(),
189-
modifier_sum.modifiers.begin() + modifier_sum.valid_size,
190-
modifiers.begin() + valid_size
191-
);
192-
193-
valid_size = new_valid_size;
162+
modifiers.append_range(modifier_sum.modifiers);
194163

195164
for (modifier_entry_t const& m : modifier_sum.get_modifiers()) {
196165
value_sum.multiply_add_exclude_targets(
Lines changed: 201 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,201 @@
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

Comments
 (0)