Skip to content

Commit 54d3952

Browse files
committed
Implement a counting_inserter std::output_iterator to get rid of an unnecessary std::copy
1 parent 4d7a5dc commit 54d3952

File tree

1 file changed

+52
-16
lines changed

1 file changed

+52
-16
lines changed

include/msgpack23/msgpack23.h

+52-16
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,38 @@ namespace msgpack23 {
127127
return to_big_endian(value);
128128
}
129129

130+
template<typename T>
131+
class counting_inserter final {
132+
public:
133+
using difference_type = std::ptrdiff_t;
134+
135+
constexpr explicit counting_inserter(std::size_t &size) : size_(std::addressof(size)) {}
136+
137+
constexpr counting_inserter &operator=(const T &value) {
138+
++*size_;
139+
return *this;
140+
}
141+
142+
constexpr counting_inserter &operator=(T &&value) {
143+
++*size_;
144+
return *this;
145+
}
146+
147+
[[nodiscard]] constexpr counting_inserter &operator*() {
148+
return *this;
149+
}
150+
151+
constexpr counting_inserter &operator++() {
152+
return *this;
153+
}
154+
155+
constexpr counting_inserter operator++(int) {
156+
return *this;
157+
}
158+
private:
159+
std::size_t *size_{};
160+
};
161+
130162
template<std::output_iterator<std::byte> Iter>
131163
class Packer final {
132164
public:
@@ -217,38 +249,42 @@ namespace msgpack23 {
217249
template<typename T>
218250
requires VariantLike<T>
219251
void pack_type(T const &value) {
220-
std::vector<std::byte> data{};
221-
std::visit([this, &data](auto const &arg) {
222-
auto const inserter = std::back_insert_iterator(data);
223-
Packer packer{inserter};
252+
std::size_t size = 0;
253+
std::visit([this, &size](auto const &arg) {
254+
const auto inserter = counting_inserter<std::byte>{size};
255+
Packer<counting_inserter<std::byte> > packer{inserter};
224256
packer(arg);
225257
}, value);
258+
226259
auto const index = static_cast<std::int8_t>(value.index());
227260
if (index > 127) {
228261
throw std::overflow_error("Variant index is to large to be serialized.");
229262
}
230263

231-
if (data.size() == 1) {
264+
if (size == 1) {
232265
emplace_constant(FormatConstants::fixext1);
233-
} else if (data.size() == 2) {
266+
} else if (size == 2) {
234267
emplace_constant(FormatConstants::fixext2);
235-
} else if (data.size() == 4) {
268+
} else if (size == 4) {
236269
emplace_constant(FormatConstants::fixext4);
237-
} else if (data.size() == 8) {
270+
} else if (size == 8) {
238271
emplace_constant(FormatConstants::fixext8);
239-
} else if (data.size() == 16) {
272+
} else if (size == 16) {
240273
emplace_constant(FormatConstants::fixext16);
241-
} else if (data.size() < std::numeric_limits<std::uint8_t>::max()) {
242-
emplace_combined(FormatConstants::ext8, static_cast<std::uint8_t>(data.size()));
243-
} else if (data.size() < std::numeric_limits<std::uint16_t>::max()) {
244-
emplace_combined(FormatConstants::ext16, static_cast<std::uint16_t>(data.size()));
245-
} else if (data.size() < std::numeric_limits<std::uint32_t>::max()) {
246-
emplace_combined(FormatConstants::ext32, static_cast<std::uint32_t>(data.size()));
274+
} else if (size < std::numeric_limits<std::uint8_t>::max()) {
275+
emplace_combined(FormatConstants::ext8, static_cast<std::uint8_t>(size));
276+
} else if (size < std::numeric_limits<std::uint16_t>::max()) {
277+
emplace_combined(FormatConstants::ext16, static_cast<std::uint16_t>(size));
278+
} else if (size < std::numeric_limits<std::uint32_t>::max()) {
279+
emplace_combined(FormatConstants::ext32, static_cast<std::uint32_t>(size));
247280
} else {
248281
throw std::length_error("Variant is too long to be serialized.");
249282
}
250283
emplace_integral(index);
251-
std::copy(data.begin(), data.end(), store_);
284+
std::visit([this](auto const &arg) {
285+
Packer packer{store_};
286+
packer(arg);
287+
}, value);
252288
}
253289

254290
template<typename T>

0 commit comments

Comments
 (0)