1 /*
2 * Copyright 2019 Google LLC
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * https://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #pragma once
18
19 #include <algorithm>
20 #include <cassert>
21 #include <cstddef>
22 #include <cstdint>
23 #include <cstring>
24 #include <functional>
25 #include <iterator>
26 #include <memory>
27 #include <numeric>
28 #include <string>
29 #include <string_view>
30 #include <vector>
31
32 #if ABSL_INTERNAL_CPLUSPLUS_LANG >= 202002L || __cplusplus >= 202002L
33 #include <span>
34 #else // not ABSL_INTERNAL_CPLUSPLUS_LANG >= 202002L || __cplusplus >= 202002L
35 #include "span.h"
36 #endif // not ABSL_INTERNAL_CPLUSPLUS_LANG >= 202002L || __cplusplus >= 202002L
37
38 #ifdef OS_WINDOWS
39 #include <basetsd.h>
40
41 #define ssize_t SSIZE_T
42 #endif // OS_WINDOWS
43
44 #ifdef TRUE
45 #undef TRUE
46 #endif // TRUE
47 #ifdef FALSE
48 #undef FALSE
49 #endif // FALSE
50
51 namespace cppbor {
52
53 #if ABSL_INTERNAL_CPLUSPLUS_LANG >= 202002L || __cplusplus >= 202002L
54 using std::span;
55 #endif // ABSL_INTERNAL_CPLUSPLUS_LANG >= 202002L || __cplusplus >= 202002L
56
57 enum MajorType : uint8_t {
58 UINT = 0 << 5,
59 NINT = 1 << 5,
60 BSTR = 2 << 5,
61 TSTR = 3 << 5,
62 ARRAY = 4 << 5,
63 MAP = 5 << 5,
64 SEMANTIC = 6 << 5,
65 SIMPLE = 7 << 5,
66 };
67
68 enum SimpleType {
69 BOOLEAN,
70 NULL_T,
71 FLOAT,
72 DOUBLE, // Only four supported, as yet.
73 };
74
75 enum SpecialAddlInfoValues : uint8_t {
76 FALSE = 20,
77 TRUE = 21,
78 NULL_V = 22,
79 ONE_BYTE_LENGTH = 24,
80 TWO_BYTE_LENGTH = 25,
81 FOUR_BYTE_LENGTH = 26,
82 FLOAT_V = 26,
83 EIGHT_BYTE_LENGTH = 27,
84 DOUBLE_V = 27,
85 INDEFINITE_LENGTH = 31,
86 };
87
88 class Item;
89 class Uint;
90 class Nint;
91 class Int;
92 class Tstr;
93 class Bstr;
94 class Simple;
95 class Bool;
96 class Array;
97 class Map;
98 class Null;
99 class SemanticTag;
100 class EncodedItem;
101 class ViewTstr;
102 class ViewBstr;
103 class Float;
104 class Double;
105
106 /**
107 * Returns the size of a CBOR header that contains the additional info value addlInfo.
108 */
109 size_t headerSize(uint64_t addlInfo);
110
111 /**
112 * Encodes a CBOR header with the specified type and additional info into the range [pos, end).
113 * Returns a pointer to one past the last byte written, or nullptr if there isn't sufficient space
114 * to write the header.
115 */
116 uint8_t* encodeHeader(MajorType type, uint64_t addlInfo, uint8_t* pos, const uint8_t* end);
117
118 using EncodeCallback = std::function<void(uint8_t)>;
119
120 /**
121 * Encodes a CBOR header with the specified type and additional info, passing each byte in turn to
122 * encodeCallback.
123 */
124 void encodeHeader(MajorType type, uint64_t addlInfo, EncodeCallback encodeCallback);
125
126 /**
127 * Encodes a CBOR header witht he specified type and additional info, writing each byte to the
128 * provided OutputIterator.
129 */
130 template <typename OutputIterator,
131 typename = std::enable_if_t<std::is_base_of_v<
132 std::output_iterator_tag,
133 typename std::iterator_traits<OutputIterator>::iterator_category>>>
encodeHeader(MajorType type,uint64_t addlInfo,OutputIterator iter)134 void encodeHeader(MajorType type, uint64_t addlInfo, OutputIterator iter) {
135 return encodeHeader(type, addlInfo, [&](uint8_t v) { *iter++ = v; });
136 }
137
138 /**
139 * Item represents a CBOR-encodeable data item. Item is an abstract interface with a set of virtual
140 * methods that allow encoding of the item or conversion to the appropriate derived type.
141 */
142 class Item {
143 public:
~Item()144 virtual ~Item() {}
145
146 /**
147 * Returns the CBOR type of the item.
148 */
149 virtual MajorType type() const = 0;
150
151 // These methods safely downcast an Item to the appropriate subclass.
asInt()152 virtual Int* asInt() { return nullptr; }
asInt()153 const Int* asInt() const { return const_cast<Item*>(this)->asInt(); }
asUint()154 virtual Uint* asUint() { return nullptr; }
asUint()155 const Uint* asUint() const { return const_cast<Item*>(this)->asUint(); }
asNint()156 virtual Nint* asNint() { return nullptr; }
asNint()157 const Nint* asNint() const { return const_cast<Item*>(this)->asNint(); }
asTstr()158 virtual Tstr* asTstr() { return nullptr; }
asTstr()159 const Tstr* asTstr() const { return const_cast<Item*>(this)->asTstr(); }
asBstr()160 virtual Bstr* asBstr() { return nullptr; }
asBstr()161 const Bstr* asBstr() const { return const_cast<Item*>(this)->asBstr(); }
asSimple()162 virtual Simple* asSimple() { return nullptr; }
asSimple()163 const Simple* asSimple() const { return const_cast<Item*>(this)->asSimple(); }
asBool()164 virtual Bool* asBool() { return nullptr; }
asBool()165 const Bool* asBool() const { return const_cast<Item*>(this)->asBool(); }
asNull()166 virtual Null* asNull() { return nullptr; }
asNull()167 const Null* asNull() const { return const_cast<Item*>(this)->asNull(); }
asFloat()168 virtual Float* asFloat() { return nullptr; }
asFloat()169 const Float* asFloat() const { return const_cast<Item*>(this)->asFloat(); }
asDouble()170 virtual Double* asDouble() { return nullptr; }
asDouble()171 const Double* asDouble() const { return const_cast<Item*>(this)->asDouble(); }
172
asMap()173 virtual Map* asMap() { return nullptr; }
asMap()174 const Map* asMap() const { return const_cast<Item*>(this)->asMap(); }
asArray()175 virtual Array* asArray() { return nullptr; }
asArray()176 const Array* asArray() const { return const_cast<Item*>(this)->asArray(); }
177
asViewTstr()178 virtual ViewTstr* asViewTstr() { return nullptr; }
asViewTstr()179 const ViewTstr* asViewTstr() const { return const_cast<Item*>(this)->asViewTstr(); }
asViewBstr()180 virtual ViewBstr* asViewBstr() { return nullptr; }
asViewBstr()181 const ViewBstr* asViewBstr() const { return const_cast<Item*>(this)->asViewBstr(); }
182
183 // Like those above, these methods safely downcast an Item when it's actually a SemanticTag.
184 // However, if you think you want to use these methods, you probably don't. Typically, the way
185 // you should handle tagged Items is by calling the appropriate method above (e.g. asInt())
186 // which will return a pointer to the tagged Item, rather than the tag itself. If you want to
187 // find out if the Item* you're holding is to something with one or more tags applied, see
188 // semanticTagCount() and semanticTag() below.
asSemanticTag()189 virtual SemanticTag* asSemanticTag() { return nullptr; }
asSemanticTag()190 const SemanticTag* asSemanticTag() const { return const_cast<Item*>(this)->asSemanticTag(); }
191
192 /**
193 * Returns the number of semantic tags prefixed to this Item.
194 */
semanticTagCount()195 virtual size_t semanticTagCount() const { return 0; }
196
197 /**
198 * Returns the semantic tag at the specified nesting level `nesting`, iff `nesting` is less than
199 * the value returned by semanticTagCount().
200 *
201 * CBOR tags are "nested" by applying them in sequence. The "rightmost" tag is the "inner" tag.
202 * That is, given:
203 *
204 * 4(5(6("AES"))) which encodes as C1 C2 C3 63 414553
205 *
206 * The tstr "AES" is tagged with 6. The combined entity ("AES" tagged with 6) is tagged with 5,
207 * etc. So in this example, semanticTagCount() would return 3, and semanticTag(0) would return
208 * 6, semanticTag(1) would return 5, and semanticTag(2) would return 4. For values of n > 2,
209 * semanticTag(n) would return 0, but this is a meaningless value.
210 *
211 * If this layering is confusing, you probably don't have to worry about it. Nested tagging does
212 * not appear to be common, so semanticTag(0) is the only one you'll use.
213 */
214 virtual uint64_t semanticTag(size_t /* nesting */ = 0) const { return 0; }
215
216 /**
217 * Returns true if this is a "compound" item, i.e. one that contains one or more other items.
218 */
isCompound()219 virtual bool isCompound() const { return false; }
220
221 bool operator==(const Item& other) const&;
222 bool operator!=(const Item& other) const& { return !(*this == other); }
223
224 /**
225 * Returns the number of bytes required to encode this Item into CBOR. Note that if this is a
226 * complex Item, calling this method will require walking the whole tree.
227 */
228 virtual size_t encodedSize() const = 0;
229
230 /**
231 * Encodes the Item into buffer referenced by range [*pos, end). Returns a pointer to one past
232 * the last position written. Returns nullptr if there isn't enough space to encode.
233 */
234 virtual uint8_t* encode(uint8_t* pos, const uint8_t* end) const = 0;
235
236 /**
237 * Encodes the Item by passing each encoded byte to encodeCallback.
238 */
239 virtual void encode(EncodeCallback encodeCallback) const = 0;
240
241 /**
242 * Clones the Item
243 */
244 virtual std::unique_ptr<Item> clone() const = 0;
245
246 /**
247 * Encodes the Item into the provided OutputIterator.
248 */
249 template <typename OutputIterator,
250 typename = typename std::iterator_traits<OutputIterator>::iterator_category>
encode(OutputIterator i)251 void encode(OutputIterator i) const {
252 return encode([&](uint8_t v) { *i++ = v; });
253 }
254
255 /**
256 * Encodes the Item into a new std::vector<uint8_t>.
257 */
encode()258 std::vector<uint8_t> encode() const {
259 std::vector<uint8_t> retval;
260 retval.reserve(encodedSize());
261 encode(std::back_inserter(retval));
262 return retval;
263 }
264
265 /**
266 * Encodes the Item into a new std::string.
267 */
toString()268 std::string toString() const {
269 std::string retval;
270 retval.reserve(encodedSize());
271 encode([&](uint8_t v) { retval.push_back(v); });
272 return retval;
273 }
274
275 /**
276 * Encodes only the header of the Item.
277 */
encodeHeader(uint64_t addlInfo,uint8_t * pos,const uint8_t * end)278 inline uint8_t* encodeHeader(uint64_t addlInfo, uint8_t* pos, const uint8_t* end) const {
279 return ::cppbor::encodeHeader(type(), addlInfo, pos, end);
280 }
281
282 /**
283 * Encodes only the header of the Item.
284 */
encodeHeader(uint64_t addlInfo,EncodeCallback encodeCallback)285 inline void encodeHeader(uint64_t addlInfo, EncodeCallback encodeCallback) const {
286 ::cppbor::encodeHeader(type(), addlInfo, encodeCallback);
287 }
288 };
289
290 /**
291 * EncodedItem represents a bit of already-encoded CBOR. Caveat emptor: It does no checking to
292 * ensure that the provided data is a valid encoding, cannot be meaninfully-compared with other
293 * kinds of items and you cannot use the as*() methods to find out what's inside it.
294 */
295 class EncodedItem : public Item {
296 public:
EncodedItem(std::vector<uint8_t> value)297 explicit EncodedItem(std::vector<uint8_t> value) : mValue(std::move(value)) {}
298
299 bool operator==(const EncodedItem& other) const& { return mValue == other.mValue; }
300
301 // Type can't be meaningfully-obtained. We could extract the type from the first byte and return
302 // it, but you can't do any of the normal things with an EncodedItem so there's no point.
type()303 MajorType type() const override {
304 assert(false);
305 return static_cast<MajorType>(-1);
306 }
encodedSize()307 size_t encodedSize() const override { return mValue.size(); }
encode(uint8_t * pos,const uint8_t * end)308 uint8_t* encode(uint8_t* pos, const uint8_t* end) const override {
309 if (end - pos < static_cast<ssize_t>(mValue.size())) return nullptr;
310 return std::copy(mValue.begin(), mValue.end(), pos);
311 }
encode(EncodeCallback encodeCallback)312 void encode(EncodeCallback encodeCallback) const override {
313 std::for_each(mValue.begin(), mValue.end(), encodeCallback);
314 }
clone()315 std::unique_ptr<Item> clone() const override { return std::make_unique<EncodedItem>(mValue); }
316
317 private:
318 std::vector<uint8_t> mValue;
319 };
320
321 /**
322 * Int is an abstraction that allows Uint and Nint objects to be manipulated without caring about
323 * the sign.
324 */
325 class Int : public Item {
326 public:
327 bool operator==(const Int& other) const& { return value() == other.value(); }
328
329 virtual int64_t value() const = 0;
330 using Item::asInt;
asInt()331 Int* asInt() override { return this; }
332 };
333
334 /**
335 * Uint is a concrete Item that implements CBOR major type 0.
336 */
337 class Uint : public Int {
338 public:
339 static constexpr MajorType kMajorType = UINT;
340
Uint(uint64_t v)341 explicit Uint(uint64_t v) : mValue(v) {}
342
343 bool operator==(const Uint& other) const& { return mValue == other.mValue; }
344
type()345 MajorType type() const override { return kMajorType; }
346 using Item::asUint;
asUint()347 Uint* asUint() override { return this; }
348
encodedSize()349 size_t encodedSize() const override { return headerSize(mValue); }
350
value()351 int64_t value() const override { return mValue; }
unsignedValue()352 uint64_t unsignedValue() const { return mValue; }
353
354 using Item::encode;
encode(uint8_t * pos,const uint8_t * end)355 uint8_t* encode(uint8_t* pos, const uint8_t* end) const override {
356 return encodeHeader(mValue, pos, end);
357 }
encode(EncodeCallback encodeCallback)358 void encode(EncodeCallback encodeCallback) const override {
359 encodeHeader(mValue, encodeCallback);
360 }
361
clone()362 std::unique_ptr<Item> clone() const override { return std::make_unique<Uint>(mValue); }
363
364 private:
365 uint64_t mValue;
366 };
367
368 /**
369 * Nint is a concrete Item that implements CBOR major type 1.
370
371 * Note that it is incapable of expressing the full range of major type 1 values, becaue it can only
372 * express values that fall into the range [std::numeric_limits<int64_t>::min(), -1]. It cannot
373 * express values in the range [std::numeric_limits<int64_t>::min() - 1,
374 * -std::numeric_limits<uint64_t>::max()].
375 */
376 class Nint : public Int {
377 public:
378 static constexpr MajorType kMajorType = NINT;
379
380 explicit Nint(int64_t v);
381
382 bool operator==(const Nint& other) const& { return mValue == other.mValue; }
383
type()384 MajorType type() const override { return kMajorType; }
385 using Item::asNint;
asNint()386 Nint* asNint() override { return this; }
encodedSize()387 size_t encodedSize() const override { return headerSize(addlInfo()); }
388
value()389 int64_t value() const override { return mValue; }
390
391 using Item::encode;
encode(uint8_t * pos,const uint8_t * end)392 uint8_t* encode(uint8_t* pos, const uint8_t* end) const override {
393 return encodeHeader(addlInfo(), pos, end);
394 }
encode(EncodeCallback encodeCallback)395 void encode(EncodeCallback encodeCallback) const override {
396 encodeHeader(addlInfo(), encodeCallback);
397 }
398
clone()399 std::unique_ptr<Item> clone() const override { return std::make_unique<Nint>(mValue); }
400
401 private:
addlInfo()402 uint64_t addlInfo() const { return -1ll - mValue; }
403
404 int64_t mValue;
405 };
406
407 /**
408 * Bstr is a concrete Item that implements major type 2.
409 */
410 class Bstr : public Item {
411 public:
412 static constexpr MajorType kMajorType = BSTR;
413
414 // Construct an empty Bstr
Bstr()415 explicit Bstr() {}
416
417 // Construct from a vector
Bstr(std::vector<uint8_t> v)418 explicit Bstr(std::vector<uint8_t> v) : mValue(std::move(v)) {}
419
420 // Construct from a string
Bstr(const std::string & v)421 explicit Bstr(const std::string& v)
422 : mValue(reinterpret_cast<const uint8_t*>(v.data()),
423 reinterpret_cast<const uint8_t*>(v.data()) + v.size()) {}
424
425 // Construct from a pointer/size pair
Bstr(const std::pair<const uint8_t *,size_t> & buf)426 explicit Bstr(const std::pair<const uint8_t*, size_t>& buf)
427 : mValue(buf.first, buf.first + buf.second) {}
428
429 // Construct from a pair of iterators
430 template <typename I1, typename I2,
431 typename = typename std::iterator_traits<I1>::iterator_category,
432 typename = typename std::iterator_traits<I2>::iterator_category>
Bstr(const std::pair<I1,I2> & pair)433 explicit Bstr(const std::pair<I1, I2>& pair) : mValue(pair.first, pair.second) {}
434
435 // Construct from an iterator range.
436 template <typename I1, typename I2,
437 typename = typename std::iterator_traits<I1>::iterator_category,
438 typename = typename std::iterator_traits<I2>::iterator_category>
Bstr(I1 begin,I2 end)439 Bstr(I1 begin, I2 end) : mValue(begin, end) {}
440
441 bool operator==(const Bstr& other) const& { return mValue == other.mValue; }
442
type()443 MajorType type() const override { return kMajorType; }
444 using Item::asBstr;
asBstr()445 Bstr* asBstr() override { return this; }
encodedSize()446 size_t encodedSize() const override { return headerSize(mValue.size()) + mValue.size(); }
447 using Item::encode;
448 uint8_t* encode(uint8_t* pos, const uint8_t* end) const override;
encode(EncodeCallback encodeCallback)449 void encode(EncodeCallback encodeCallback) const override {
450 encodeHeader(mValue.size(), encodeCallback);
451 encodeValue(encodeCallback);
452 }
453
value()454 const std::vector<uint8_t>& value() const { return mValue; }
moveValue()455 std::vector<uint8_t>&& moveValue() { return std::move(mValue); }
456
clone()457 std::unique_ptr<Item> clone() const override { return std::make_unique<Bstr>(mValue); }
458
459 protected:
460 std::vector<uint8_t> mValue;
461
462 private:
463 void encodeValue(EncodeCallback encodeCallback) const;
464 };
465
466 /**
467 * ViewBstr is a read-only version of Bstr backed by span
468 */
469 class ViewBstr : public Item {
470 public:
471 static constexpr MajorType kMajorType = BSTR;
472
473 // Construct an empty ViewBstr
ViewBstr()474 explicit ViewBstr() {}
475
476 // Construct from a span of uint8_t values
ViewBstr(span<const uint8_t> v)477 explicit ViewBstr(span<const uint8_t> v) : mView(std::move(v)) {}
478
479 // Construct from a string_view
ViewBstr(std::string_view v)480 explicit ViewBstr(std::string_view v)
481 : mView(reinterpret_cast<const uint8_t*>(v.data()), v.size()) {}
482
483 // Construct from an iterator range
484 template <typename I1, typename I2,
485 typename = typename std::iterator_traits<I1>::iterator_category,
486 typename = typename std::iterator_traits<I2>::iterator_category>
ViewBstr(I1 begin,I2 end)487 ViewBstr(I1 begin, I2 end) : mView(begin, end) {}
488
489 // Construct from a uint8_t pointer pair
ViewBstr(const uint8_t * begin,const uint8_t * end)490 ViewBstr(const uint8_t* begin, const uint8_t* end) : mView(begin, std::distance(begin, end)) {}
491
492 bool operator==(const ViewBstr& other) const& {
493 return std::equal(mView.begin(), mView.end(), other.mView.begin(), other.mView.end());
494 }
495
type()496 MajorType type() const override { return kMajorType; }
497 using Item::asViewBstr;
asViewBstr()498 ViewBstr* asViewBstr() override { return this; }
encodedSize()499 size_t encodedSize() const override { return headerSize(mView.size()) + mView.size(); }
500 using Item::encode;
501 uint8_t* encode(uint8_t* pos, const uint8_t* end) const override;
encode(EncodeCallback encodeCallback)502 void encode(EncodeCallback encodeCallback) const override {
503 encodeHeader(mView.size(), encodeCallback);
504 encodeValue(encodeCallback);
505 }
506
view()507 const span<const uint8_t>& view() const { return mView; }
508
clone()509 std::unique_ptr<Item> clone() const override { return std::make_unique<ViewBstr>(mView); }
510
511 private:
512 void encodeValue(EncodeCallback encodeCallback) const;
513
514 span<const uint8_t> mView;
515 };
516
517 /**
518 * Tstr is a concrete Item that implements major type 3.
519 */
520 class Tstr : public Item {
521 public:
522 static constexpr MajorType kMajorType = TSTR;
523
524 // Construct an empty Tstr
Tstr()525 explicit Tstr() {}
526
527 // Construct from a string
Tstr(std::string v)528 explicit Tstr(std::string v) : mValue(std::move(v)) {}
529
530 // Construct from a string_view
Tstr(const std::string_view & v)531 explicit Tstr(const std::string_view& v) : mValue(v) {}
532
533 // Construct from a C string
Tstr(const char * v)534 explicit Tstr(const char* v) : mValue(std::string(v)) {}
535
536 // Construct from a pair of iterators
537 template <typename I1, typename I2,
538 typename = typename std::iterator_traits<I1>::iterator_category,
539 typename = typename std::iterator_traits<I2>::iterator_category>
Tstr(const std::pair<I1,I2> & pair)540 explicit Tstr(const std::pair<I1, I2>& pair) : mValue(pair.first, pair.second) {}
541
542 // Construct from an iterator range
543 template <typename I1, typename I2,
544 typename = typename std::iterator_traits<I1>::iterator_category,
545 typename = typename std::iterator_traits<I2>::iterator_category>
Tstr(I1 begin,I2 end)546 Tstr(I1 begin, I2 end) : mValue(begin, end) {}
547
548 bool operator==(const Tstr& other) const& { return mValue == other.mValue; }
549
type()550 MajorType type() const override { return kMajorType; }
551 using Item::asTstr;
asTstr()552 Tstr* asTstr() override { return this; }
encodedSize()553 size_t encodedSize() const override { return headerSize(mValue.size()) + mValue.size(); }
554 using Item::encode;
555 uint8_t* encode(uint8_t* pos, const uint8_t* end) const override;
encode(EncodeCallback encodeCallback)556 void encode(EncodeCallback encodeCallback) const override {
557 encodeHeader(mValue.size(), encodeCallback);
558 encodeValue(encodeCallback);
559 }
560
value()561 const std::string& value() const { return mValue; }
moveValue()562 std::string&& moveValue() { return std::move(mValue); }
563
clone()564 std::unique_ptr<Item> clone() const override { return std::make_unique<Tstr>(mValue); }
565
566 protected:
567 std::string mValue;
568
569 private:
570 void encodeValue(EncodeCallback encodeCallback) const;
571 };
572
573 /**
574 * ViewTstr is a read-only version of Tstr backed by std::string_view
575 */
576 class ViewTstr : public Item {
577 public:
578 static constexpr MajorType kMajorType = TSTR;
579
580 // Construct an empty ViewTstr
ViewTstr()581 explicit ViewTstr() {}
582
583 // Construct from a string_view
ViewTstr(std::string_view v)584 explicit ViewTstr(std::string_view v) : mView(std::move(v)) {}
585
586 // Construct from an iterator range
587 template <typename I1, typename I2,
588 typename = typename std::iterator_traits<I1>::iterator_category,
589 typename = typename std::iterator_traits<I2>::iterator_category>
ViewTstr(I1 begin,I2 end)590 ViewTstr(I1 begin, I2 end) : mView(begin, end) {}
591
592 // Construct from a uint8_t pointer pair
ViewTstr(const uint8_t * begin,const uint8_t * end)593 ViewTstr(const uint8_t* begin, const uint8_t* end)
594 : mView(reinterpret_cast<const char*>(begin), std::distance(begin, end)) {}
595
596 bool operator==(const ViewTstr& other) const& { return mView == other.mView; }
597
type()598 MajorType type() const override { return kMajorType; }
599 using Item::asViewTstr;
asViewTstr()600 ViewTstr* asViewTstr() override { return this; }
encodedSize()601 size_t encodedSize() const override { return headerSize(mView.size()) + mView.size(); }
602 using Item::encode;
603 uint8_t* encode(uint8_t* pos, const uint8_t* end) const override;
encode(EncodeCallback encodeCallback)604 void encode(EncodeCallback encodeCallback) const override {
605 encodeHeader(mView.size(), encodeCallback);
606 encodeValue(encodeCallback);
607 }
608
view()609 const std::string_view& view() const { return mView; }
610
clone()611 std::unique_ptr<Item> clone() const override { return std::make_unique<ViewTstr>(mView); }
612
613 private:
614 void encodeValue(EncodeCallback encodeCallback) const;
615
616 std::string_view mView;
617 };
618
619 /*
620 * Array is a concrete Item that implements CBOR major type 4.
621 *
622 * Note that Arrays are not copyable. This is because copying them is expensive and making them
623 * move-only ensures that they're never copied accidentally. If you actually want to copy an Array,
624 * use the clone() method.
625 */
626 class Array : public Item {
627 public:
628 static constexpr MajorType kMajorType = ARRAY;
629
630 Array() = default;
631 Array(const Array& other) = delete;
632 Array(Array&&) = default;
633 Array& operator=(const Array&) = delete;
634 Array& operator=(Array&&) = default;
635
636 bool operator==(const Array& other) const&;
637
638 /**
639 * Construct an Array from a variable number of arguments of different types. See
640 * details::makeItem below for details on what types may be provided. In general, this accepts
641 * all of the types you'd expect and doest the things you'd expect (integral values are addes as
642 * Uint or Nint, std::string and char* are added as Tstr, bools are added as Bool, etc.).
643 */
644 template <typename... Args, typename Enable>
645 Array(Args&&... args);
646
647 /**
648 * The above variadic constructor is disabled if sizeof(Args) != 1, so special
649 * case an explicit Array constructor for creating an Array with one Item.
650 */
651 template <typename T, typename Enable>
652 explicit Array(T&& v);
653
654 /**
655 * Append a single element to the Array, of any compatible type.
656 */
657 template <typename T>
658 Array& add(T&& v) &;
659 template <typename T>
660 Array&& add(T&& v) &&;
661
isCompound()662 bool isCompound() const override { return true; }
663
size()664 virtual size_t size() const { return mEntries.size(); }
665
encodedSize()666 size_t encodedSize() const override {
667 return std::accumulate(mEntries.begin(), mEntries.end(), headerSize(size()),
668 [](size_t sum, auto& entry) { return sum + entry->encodedSize(); });
669 }
670
671 using Item::encode; // Make base versions visible.
672 uint8_t* encode(uint8_t* pos, const uint8_t* end) const override;
673 void encode(EncodeCallback encodeCallback) const override;
674
675 const std::unique_ptr<Item>& operator[](size_t index) const { return get(index); }
676 std::unique_ptr<Item>& operator[](size_t index) { return get(index); }
677
get(size_t index)678 const std::unique_ptr<Item>& get(size_t index) const { return mEntries[index]; }
get(size_t index)679 std::unique_ptr<Item>& get(size_t index) { return mEntries[index]; }
680
type()681 MajorType type() const override { return kMajorType; }
682 using Item::asArray;
asArray()683 Array* asArray() override { return this; }
684
685 std::unique_ptr<Item> clone() const override;
686
begin()687 auto begin() { return mEntries.begin(); }
begin()688 auto begin() const { return mEntries.begin(); }
end()689 auto end() { return mEntries.end(); }
end()690 auto end() const { return mEntries.end(); }
691
692 protected:
693 std::vector<std::unique_ptr<Item>> mEntries;
694 };
695
696 /*
697 * Map is a concrete Item that implements CBOR major type 5.
698 *
699 * Note that Maps are not copyable. This is because copying them is expensive and making them
700 * move-only ensures that they're never copied accidentally. If you actually want to copy a
701 * Map, use the clone() method.
702 */
703 class Map : public Item {
704 public:
705 static constexpr MajorType kMajorType = MAP;
706
707 using entry_type = std::pair<std::unique_ptr<Item>, std::unique_ptr<Item>>;
708
709 Map() = default;
710 Map(const Map& other) = delete;
711 Map(Map&&) = default;
712 Map& operator=(const Map& other) = delete;
713 Map& operator=(Map&&) = default;
714
715 bool operator==(const Map& other) const&;
716
717 /**
718 * Construct a Map from a variable number of arguments of different types. An even number of
719 * arguments must be provided (this is verified statically). See details::makeItem below for
720 * details on what types may be provided. In general, this accepts all of the types you'd
721 * expect and doest the things you'd expect (integral values are addes as Uint or Nint,
722 * std::string and char* are added as Tstr, bools are added as Bool, etc.).
723 */
724 template <typename... Args, typename Enable>
725 Map(Args&&... args);
726
727 /**
728 * Append a key/value pair to the Map, of any compatible types.
729 */
730 template <typename Key, typename Value>
731 Map& add(Key&& key, Value&& value) &;
732 template <typename Key, typename Value>
733 Map&& add(Key&& key, Value&& value) &&;
734
isCompound()735 bool isCompound() const override { return true; }
736
size()737 virtual size_t size() const { return mEntries.size(); }
738
encodedSize()739 size_t encodedSize() const override {
740 return std::accumulate(
741 mEntries.begin(), mEntries.end(), headerSize(size()), [](size_t sum, auto& entry) {
742 return sum + entry.first->encodedSize() + entry.second->encodedSize();
743 });
744 }
745
746 using Item::encode; // Make base versions visible.
747 uint8_t* encode(uint8_t* pos, const uint8_t* end) const override;
748 void encode(EncodeCallback encodeCallback) const override;
749
750 /**
751 * Find and return the value associated with `key`, if any.
752 *
753 * If the searched-for `key` is not present, returns `nullptr`.
754 *
755 * Note that if the map is canonicalized (sorted), Map::get() performs a binary search. If your
756 * map is large and you're searching in it many times, it may be worthwhile to canonicalize it
757 * to make Map::get() faster. Any use of a method that might modify the map disables the
758 * speedup.
759 */
760 template <typename Key, typename Enable>
761 const std::unique_ptr<Item>& get(Key key) const;
762
763 // Note that use of non-const operator[] marks the map as not canonicalized.
764 auto& operator[](size_t index) {
765 mCanonicalized = false;
766 return mEntries[index];
767 }
768 const auto& operator[](size_t index) const { return mEntries[index]; }
769
type()770 MajorType type() const override { return kMajorType; }
771 using Item::asMap;
asMap()772 Map* asMap() override { return this; }
773
774 /**
775 * Sorts the map in canonical order, as defined in RFC 7049. Use this before encoding if you
776 * want canonicalization; cppbor does not canonicalize by default, though the integer encodings
777 * are always canonical and cppbor does not support indefinite-length encodings, so map order
778 * canonicalization is the only thing that needs to be done.
779 *
780 * @param recurse If set to true, canonicalize() will also walk the contents of the map and
781 * canonicalize any contained maps as well.
782 */
783 Map& canonicalize(bool recurse = false) &;
784 Map&& canonicalize(bool recurse = false) && {
785 canonicalize(recurse);
786 return std::move(*this);
787 }
788
isCanonical()789 bool isCanonical() { return mCanonicalized; }
790
791 std::unique_ptr<Item> clone() const override;
792
begin()793 auto begin() {
794 mCanonicalized = false;
795 return mEntries.begin();
796 }
begin()797 auto begin() const { return mEntries.begin(); }
end()798 auto end() {
799 mCanonicalized = false;
800 return mEntries.end();
801 }
end()802 auto end() const { return mEntries.end(); }
803
804 // Returns true if a < b, per CBOR map key canonicalization rules.
805 static bool keyLess(const Item* a, const Item* b);
806
807 protected:
808 std::vector<entry_type> mEntries;
809
810 private:
811 bool mCanonicalized = false;
812 };
813
814 class SemanticTag : public Item {
815 public:
816 static constexpr MajorType kMajorType = SEMANTIC;
817
818 template <typename T>
819 SemanticTag(uint64_t tagValue, T&& taggedItem);
820 SemanticTag(const SemanticTag& other) = delete;
821 SemanticTag(SemanticTag&&) = default;
822 SemanticTag& operator=(const SemanticTag& other) = delete;
823 SemanticTag& operator=(SemanticTag&&) = default;
824
825 bool operator==(const SemanticTag& other) const& {
826 return mValue == other.mValue && *mTaggedItem == *other.mTaggedItem;
827 }
828
isCompound()829 bool isCompound() const override { return true; }
830
size()831 virtual size_t size() const { return 1; }
832
833 // Encoding returns the tag + enclosed Item.
encodedSize()834 size_t encodedSize() const override { return headerSize(mValue) + mTaggedItem->encodedSize(); }
835
836 using Item::encode; // Make base versions visible.
837 uint8_t* encode(uint8_t* pos, const uint8_t* end) const override;
838 void encode(EncodeCallback encodeCallback) const override;
839
840 // type() is a bit special. In normal usage it should return the wrapped type, but during
841 // parsing when we haven't yet parsed the tagged item, it needs to return SEMANTIC.
type()842 MajorType type() const override { return mTaggedItem ? mTaggedItem->type() : SEMANTIC; }
843 using Item::asSemanticTag;
asSemanticTag()844 SemanticTag* asSemanticTag() override { return this; }
845
846 // Type information reflects the enclosed Item. Note that if the immediately-enclosed Item is
847 // another tag, these methods will recurse down to the non-tag Item.
848 using Item::asInt;
asInt()849 Int* asInt() override { return mTaggedItem->asInt(); }
850 using Item::asUint;
asUint()851 Uint* asUint() override { return mTaggedItem->asUint(); }
852 using Item::asNint;
asNint()853 Nint* asNint() override { return mTaggedItem->asNint(); }
854 using Item::asTstr;
asTstr()855 Tstr* asTstr() override { return mTaggedItem->asTstr(); }
856 using Item::asBstr;
asBstr()857 Bstr* asBstr() override { return mTaggedItem->asBstr(); }
858 using Item::asSimple;
asSimple()859 Simple* asSimple() override { return mTaggedItem->asSimple(); }
860 using Item::asMap;
asMap()861 Map* asMap() override { return mTaggedItem->asMap(); }
862 using Item::asArray;
asArray()863 Array* asArray() override { return mTaggedItem->asArray(); }
864 using Item::asViewTstr;
asViewTstr()865 ViewTstr* asViewTstr() override { return mTaggedItem->asViewTstr(); }
866 using Item::asViewBstr;
asViewBstr()867 ViewBstr* asViewBstr() override { return mTaggedItem->asViewBstr(); }
868
869 std::unique_ptr<Item> clone() const override;
870
871 size_t semanticTagCount() const override;
872 uint64_t semanticTag(size_t nesting = 0) const override;
873
874 protected:
875 SemanticTag() = default;
SemanticTag(uint64_t value)876 SemanticTag(uint64_t value) : mValue(value) {}
877 uint64_t mValue;
878 std::unique_ptr<Item> mTaggedItem;
879 };
880
881 /**
882 * Simple is abstract Item that implements CBOR major type 7. It is intended to be subclassed to
883 * create concrete Simple types. At present only Bool is provided.
884 */
885 class Simple : public Item {
886 public:
887 static constexpr MajorType kMajorType = SIMPLE;
888
889 bool operator==(const Simple& other) const&;
890
891 virtual SimpleType simpleType() const = 0;
type()892 MajorType type() const override { return kMajorType; }
893
asSimple()894 Simple* asSimple() override { return this; }
895 };
896
897 /**
898 * Bool is a concrete type that implements CBOR major type 7, with additional item values for TRUE
899 * and FALSE.
900 */
901 class Bool : public Simple {
902 public:
903 static constexpr SimpleType kSimpleType = BOOLEAN;
904
Bool(bool v)905 explicit Bool(bool v) : mValue(v) {}
906
907 bool operator==(const Bool& other) const& { return mValue == other.mValue; }
908
simpleType()909 SimpleType simpleType() const override { return kSimpleType; }
asBool()910 Bool* asBool() override { return this; }
911
encodedSize()912 size_t encodedSize() const override { return 1; }
913
914 using Item::encode;
encode(uint8_t * pos,const uint8_t * end)915 uint8_t* encode(uint8_t* pos, const uint8_t* end) const override {
916 return encodeHeader(mValue ? TRUE : FALSE, pos, end);
917 }
encode(EncodeCallback encodeCallback)918 void encode(EncodeCallback encodeCallback) const override {
919 encodeHeader(mValue ? TRUE : FALSE, encodeCallback);
920 }
921
value()922 bool value() const { return mValue; }
923
clone()924 std::unique_ptr<Item> clone() const override { return std::make_unique<Bool>(mValue); }
925
926 private:
927 bool mValue;
928 };
929
930 /**
931 * Null is a concrete type that implements CBOR major type 7, with additional item value for NULL
932 */
933 class Null : public Simple {
934 public:
935 static constexpr SimpleType kSimpleType = NULL_T;
936
Null()937 explicit Null() {}
938
simpleType()939 SimpleType simpleType() const override { return kSimpleType; }
asNull()940 Null* asNull() override { return this; }
941
encodedSize()942 size_t encodedSize() const override { return 1; }
943
944 using Item::encode;
encode(uint8_t * pos,const uint8_t * end)945 uint8_t* encode(uint8_t* pos, const uint8_t* end) const override {
946 return encodeHeader(NULL_V, pos, end);
947 }
encode(EncodeCallback encodeCallback)948 void encode(EncodeCallback encodeCallback) const override {
949 encodeHeader(NULL_V, encodeCallback);
950 }
951
clone()952 std::unique_ptr<Item> clone() const override { return std::make_unique<Null>(); }
953 };
954
955 #if defined(__STDC_IEC_559__) || FLT_MANT_DIG == 24 || __FLT_MANT_DIG__ == 24
956 /**
957 * Float is a concrete type that implements CBOR major type 7, with additional item value for
958 * FLOAT.
959 */
960 class Float : public Simple {
961 public:
962 static constexpr SimpleType kSimpleType = FLOAT;
963
Float(float v)964 explicit Float(float v) : mValue(v) {}
965
simpleType()966 SimpleType simpleType() const override { return kSimpleType; }
asFloat()967 Float* asFloat() override { return this; }
968
value()969 float value() const { return mValue; }
encodedSize()970 size_t encodedSize() const override { return 5; }
971
972 using Item::encode;
encode(uint8_t * pos,const uint8_t * end)973 uint8_t* encode(uint8_t* pos, const uint8_t* end) const override {
974 uint32_t bits;
975 std::memcpy(&bits, &mValue, sizeof(float));
976 return encodeHeader(bits, pos, end);
977 }
encode(EncodeCallback encodeCallback)978 void encode(EncodeCallback encodeCallback) const override {
979 uint32_t bits;
980 std::memcpy(&bits, &mValue, sizeof(float));
981 encodeHeader(bits, encodeCallback);
982 }
983
clone()984 std::unique_ptr<Item> clone() const override { return std::make_unique<Float>(mValue); }
985
986 private:
987 float mValue;
988 };
989 #endif // __STDC_IEC_559__ || FLT_MANT_DIG == 24 || __FLT_MANT_DIG__ == 24
990
991 #if defined(__STDC_IEC_559__) || DBL_MANT_DIG == 53 || __DBL_MANT_DIG__ == 53
992 /**
993 * Double is a concrete type that implements CBOR major type 7, with additional item value for
994 * DOUBLE.
995 */
996 class Double : public Simple {
997 public:
998 static constexpr SimpleType kSimpleType = DOUBLE;
999
Double(double v)1000 explicit Double(double v) : mValue(v) {}
1001
simpleType()1002 SimpleType simpleType() const override { return kSimpleType; }
asDouble()1003 Double* asDouble() override { return this; }
1004
value()1005 double value() const { return mValue; }
encodedSize()1006 size_t encodedSize() const override { return 9; }
1007
1008 using Item::encode;
encode(uint8_t * pos,const uint8_t * end)1009 uint8_t* encode(uint8_t* pos, const uint8_t* end) const override {
1010 uint64_t bits;
1011 std::memcpy(&bits, &mValue, sizeof(double));
1012 return encodeHeader(bits, pos, end);
1013 }
encode(EncodeCallback encodeCallback)1014 void encode(EncodeCallback encodeCallback) const override {
1015 uint64_t bits;
1016 std::memcpy(&bits, &mValue, sizeof(double));
1017 encodeHeader(bits, encodeCallback);
1018 }
1019
clone()1020 std::unique_ptr<Item> clone() const override { return std::make_unique<Double>(mValue); }
1021
1022 private:
1023 double mValue;
1024 };
1025 #endif // __STDC_IEC_559__ || DBL_MANT_DIG == 53 || __DBL_MANT_DIG__ == 53
1026
1027 /**
1028 * Returns pretty-printed CBOR for |item|
1029 *
1030 * If a byte-string is larger than |maxBStrSize| its contents will not be printed, instead the value
1031 * of the form "<bstr size=1099016 sha1=ef549cca331f73dfae2090e6a37c04c23f84b07b>" will be
1032 * printed. Pass zero for |maxBStrSize| to disable this.
1033 *
1034 * The |mapKeysToNotPrint| parameter specifies the name of map values to not print. This is useful
1035 * for unit tests.
1036 */
1037 std::string prettyPrint(const Item* item, size_t maxBStrSize = 32,
1038 const std::vector<std::string>& mapKeysToNotPrint = {});
1039
1040 /**
1041 * Returns pretty-printed CBOR for |value|.
1042 *
1043 * Only valid CBOR should be passed to this function.
1044 *
1045 * If a byte-string is larger than |maxBStrSize| its contents will not be printed, instead the value
1046 * of the form "<bstr size=1099016 sha1=ef549cca331f73dfae2090e6a37c04c23f84b07b>" will be
1047 * printed. Pass zero for |maxBStrSize| to disable this.
1048 *
1049 * The |mapKeysToNotPrint| parameter specifies the name of map values to not print. This is useful
1050 * for unit tests.
1051 */
1052 std::string prettyPrint(const std::vector<uint8_t>& encodedCbor, size_t maxBStrSize = 32,
1053 const std::vector<std::string>& mapKeysToNotPrint = {});
1054
1055 /**
1056 * Details. Mostly you shouldn't have to look below, except perhaps at the docstring for makeItem.
1057 */
1058 namespace details {
1059
1060 template <typename T, typename V, typename Enable = void>
1061 struct is_iterator_pair_over : public std::false_type {};
1062
1063 template <typename I1, typename I2, typename V>
1064 struct is_iterator_pair_over<
1065 std::pair<I1, I2>, V,
1066 typename std::enable_if_t<std::is_same_v<V, typename std::iterator_traits<I1>::value_type>>>
1067 : public std::true_type {};
1068
1069 template <typename T, typename V, typename Enable = void>
1070 struct is_unique_ptr_of_subclass_of_v : public std::false_type {};
1071
1072 template <typename T, typename P>
1073 struct is_unique_ptr_of_subclass_of_v<T, std::unique_ptr<P>,
1074 typename std::enable_if_t<std::is_base_of_v<T, P>>>
1075 : public std::true_type {};
1076
1077 /* check if type is one of std::string (1), std::string_view (2), null-terminated char* (3) or pair
1078 * of iterators (4)*/
1079 template <typename T, typename Enable = void>
1080 struct is_text_type_v : public std::false_type {};
1081
1082 template <typename T>
1083 struct is_text_type_v<
1084 T, typename std::enable_if_t<
1085 /* case 1 */ //
1086 std::is_same_v<std::remove_cv_t<std::remove_reference_t<T>>, std::string>
1087 /* case 2 */ //
1088 || std::is_same_v<std::remove_cv_t<std::remove_reference_t<T>>, std::string_view>
1089 /* case 3 */ //
1090 || std::is_same_v<std::remove_cv_t<std::decay_t<T>>, char*> //
1091 || std::is_same_v<std::remove_cv_t<std::decay_t<T>>, const char*>
1092 /* case 4 */
1093 || details::is_iterator_pair_over<T, char>::value>> : public std::true_type {};
1094
1095 /**
1096 * Construct a unique_ptr<Item> from many argument types. Accepts:
1097 *
1098 * (a) booleans;
1099 * (b) integers, all sizes and signs;
1100 * (c) text strings, as defined by is_text_type_v above;
1101 * (d) byte strings, as std::vector<uint8_t>(d1), pair of iterators (d2) or pair<uint8_t*, size_T>
1102 * (d3); and
1103 * (e) Item subclass instances, including Array and Map. Items may be provided by naked pointer
1104 * (e1), unique_ptr (e2), reference (e3) or value (e3). If provided by reference or value, will
1105 * be moved if possible. If provided by pointer, ownership is taken.
1106 * (f) null pointer;
1107 * (g) enums, using the underlying integer value.
1108 */
1109 template <typename T>
1110 std::unique_ptr<Item> makeItem(T v) {
1111 Item* p = nullptr;
1112 if constexpr (/* case a */ std::is_same_v<T, bool>) {
1113 p = new Bool(v);
1114 } else if constexpr (/* case b */ std::is_integral_v<T>) { // b
1115 if (v < 0) {
1116 p = new Nint(v);
1117 } else {
1118 p = new Uint(static_cast<uint64_t>(v));
1119 }
1120 } else if constexpr (/* case c */ //
1121 details::is_text_type_v<T>::value) {
1122 p = new Tstr(v);
1123 } else if constexpr (/* case d1 */ //
1124 std::is_same_v<std::remove_cv_t<std::remove_reference_t<T>>,
1125 std::vector<uint8_t>>
1126 /* case d2 */ //
1127 || details::is_iterator_pair_over<T, uint8_t>::value
1128 /* case d3 */ //
1129 || std::is_same_v<std::remove_cv_t<std::remove_reference_t<T>>,
1130 std::pair<uint8_t*, size_t>>) {
1131 p = new Bstr(v);
1132 } else if constexpr (/* case e1 */ //
1133 std::is_pointer_v<T> &&
1134 std::is_base_of_v<Item, std::remove_pointer_t<T>>) {
1135 p = v;
1136 } else if constexpr (/* case e2 */ //
1137 details::is_unique_ptr_of_subclass_of_v<Item, T>::value) {
1138 p = v.release();
1139 } else if constexpr (/* case e3 */ //
1140 std::is_base_of_v<Item, T>) {
1141 p = new T(std::move(v));
1142 } else if constexpr (/* case f */ std::is_null_pointer_v<T>) {
1143 p = new Null();
1144 } else if constexpr (/* case g */ std::is_enum_v<T>) {
1145 return makeItem(static_cast<std::underlying_type_t<T>>(v));
1146 } else {
1147 // It's odd that this can't be static_assert(false), since it shouldn't be evaluated if one
1148 // of the above ifs matches. But static_assert(false) always triggers.
1149 static_assert(std::is_same_v<T, bool>, "makeItem called with unsupported type");
1150 }
1151 return std::unique_ptr<Item>(p);
1152 }
1153
1154 inline void map_helper(Map& /* map */) {}
1155
1156 template <typename Key, typename Value, typename... Rest>
1157 inline void map_helper(Map& map, Key&& key, Value&& value, Rest&&... rest) {
1158 map.add(std::forward<Key>(key), std::forward<Value>(value));
1159 map_helper(map, std::forward<Rest>(rest)...);
1160 }
1161
1162 } // namespace details
1163
1164 template <typename... Args,
1165 /* Prevent implicit construction with a single argument. */
1166 typename = std::enable_if_t<(sizeof...(Args)) != 1>>
1167 Array::Array(Args&&... args) {
1168 mEntries.reserve(sizeof...(args));
1169 (mEntries.push_back(details::makeItem(std::forward<Args>(args))), ...);
1170 }
1171
1172 template <typename T,
1173 /* Prevent use as copy constructor. */
1174 typename = std::enable_if_t<
1175 !std::is_same_v<Array, std::remove_cv_t<std::remove_reference_t<T>>>>>
1176 Array::Array(T&& v) {
1177 mEntries.push_back(details::makeItem(std::forward<T>(v)));
1178 }
1179
1180 template <typename T>
1181 Array& Array::add(T&& v) & {
1182 mEntries.push_back(details::makeItem(std::forward<T>(v)));
1183 return *this;
1184 }
1185
1186 template <typename T>
1187 Array&& Array::add(T&& v) && {
1188 mEntries.push_back(details::makeItem(std::forward<T>(v)));
1189 return std::move(*this);
1190 }
1191
1192 template <typename... Args,
1193 /* Prevent use as copy ctor */ typename = std::enable_if_t<(sizeof...(Args)) != 1>>
1194 Map::Map(Args&&... args) {
1195 static_assert((sizeof...(Args)) % 2 == 0, "Map must have an even number of entries");
1196 mEntries.reserve(sizeof...(args) / 2);
1197 details::map_helper(*this, std::forward<Args>(args)...);
1198 }
1199
1200 template <typename Key, typename Value>
1201 Map& Map::add(Key&& key, Value&& value) & {
1202 mEntries.push_back({details::makeItem(std::forward<Key>(key)),
1203 details::makeItem(std::forward<Value>(value))});
1204 mCanonicalized = false;
1205 return *this;
1206 }
1207
1208 template <typename Key, typename Value>
1209 Map&& Map::add(Key&& key, Value&& value) && {
1210 this->add(std::forward<Key>(key), std::forward<Value>(value));
1211 return std::move(*this);
1212 }
1213
1214 static const std::unique_ptr<Item> kEmptyItemPtr;
1215
1216 template <typename Key,
1217 typename = std::enable_if_t<std::is_integral_v<Key> || std::is_enum_v<Key> ||
1218 details::is_text_type_v<Key>::value>>
1219 const std::unique_ptr<Item>& Map::get(Key key) const {
1220 auto keyItem = details::makeItem(key);
1221
1222 if (mCanonicalized) {
1223 // It's sorted, so binary-search it.
1224 auto found = std::lower_bound(begin(), end(), keyItem.get(),
1225 [](const entry_type& entry, const Item* key) {
1226 return keyLess(entry.first.get(), key);
1227 });
1228 return (found == end() || *found->first != *keyItem) ? kEmptyItemPtr : found->second;
1229 } else {
1230 // Unsorted, do a linear search.
1231 auto found = std::find_if(
1232 begin(), end(), [&](const entry_type& entry) { return *entry.first == *keyItem; });
1233 return found == end() ? kEmptyItemPtr : found->second;
1234 }
1235 }
1236
1237 template <typename T>
1238 SemanticTag::SemanticTag(uint64_t value, T&& taggedItem)
1239 : mValue(value), mTaggedItem(details::makeItem(std::forward<T>(taggedItem))) {}
1240
1241 } // namespace cppbor
1242