1 /*
2  * Copyright (c) 2019, The Android Open Source Project
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  *     http://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 <cstdint>
20 #include <functional>
21 #include <iterator>
22 #include <memory>
23 #include <numeric>
24 #include <string>
25 #include <vector>
26 
27 namespace cppbor {
28 
29 enum MajorType : uint8_t {
30     UINT = 0 << 5,
31     NINT = 1 << 5,
32     BSTR = 2 << 5,
33     TSTR = 3 << 5,
34     ARRAY = 4 << 5,
35     MAP = 5 << 5,
36     SEMANTIC = 6 << 5,
37     SIMPLE = 7 << 5,
38 };
39 
40 enum SimpleType {
41     BOOLEAN,
42     NULL_T,  // Only two supported, as yet.
43 };
44 
45 enum SpecialAddlInfoValues : uint8_t {
46     FALSE = 20,
47     TRUE = 21,
48     NULL_V = 22,
49     ONE_BYTE_LENGTH = 24,
50     TWO_BYTE_LENGTH = 25,
51     FOUR_BYTE_LENGTH = 26,
52     EIGHT_BYTE_LENGTH = 27,
53 };
54 
55 class Item;
56 class Uint;
57 class Nint;
58 class Int;
59 class Tstr;
60 class Bstr;
61 class Simple;
62 class Bool;
63 class Array;
64 class Map;
65 class Null;
66 class Semantic;
67 
68 /**
69  * Returns the size of a CBOR header that contains the additional info value addlInfo.
70  */
71 size_t headerSize(uint64_t addlInfo);
72 
73 /**
74  * Encodes a CBOR header with the specified type and additional info into the range [pos, end).
75  * Returns a pointer to one past the last byte written, or nullptr if there isn't sufficient space
76  * to write the header.
77  */
78 uint8_t* encodeHeader(MajorType type, uint64_t addlInfo, uint8_t* pos, const uint8_t* end);
79 
80 using EncodeCallback = std::function<void(uint8_t)>;
81 
82 /**
83  * Encodes a CBOR header with the specified type and additional info, passing each byte in turn to
84  * encodeCallback.
85  */
86 void encodeHeader(MajorType type, uint64_t addlInfo, EncodeCallback encodeCallback);
87 
88 /**
89  * Encodes a CBOR header with the specified type and additional info, writing each byte to the
90  * provided OutputIterator.
91  */
92 template <typename OutputIterator,
93           typename = std::enable_if_t<std::is_base_of_v<
94                   std::output_iterator_tag,
95                   typename std::iterator_traits<OutputIterator>::iterator_category>>>
encodeHeader(MajorType type,uint64_t addlInfo,OutputIterator iter)96 void encodeHeader(MajorType type, uint64_t addlInfo, OutputIterator iter) {
97     return encodeHeader(type, addlInfo, [&](uint8_t v) { *iter++ = v; });
98 }
99 
100 /**
101  * Item represents a CBOR-encodeable data item.  Item is an abstract interface with a set of virtual
102  * methods that allow encoding of the item or conversion to the appropriate derived type.
103  */
104 class Item {
105   public:
~Item()106     virtual ~Item() {}
107 
108     /**
109      * Returns the CBOR type of the item.
110      */
111     virtual MajorType type() const = 0;
112 
113     // These methods safely downcast an Item to the appropriate subclass.
asInt()114     virtual const Int* asInt() const { return nullptr; }
asUint()115     virtual const Uint* asUint() const { return nullptr; }
asNint()116     virtual const Nint* asNint() const { return nullptr; }
asTstr()117     virtual const Tstr* asTstr() const { return nullptr; }
asBstr()118     virtual const Bstr* asBstr() const { return nullptr; }
asSimple()119     virtual const Simple* asSimple() const { return nullptr; }
asMap()120     virtual const Map* asMap() const { return nullptr; }
asArray()121     virtual const Array* asArray() const { return nullptr; }
asSemantic()122     virtual const Semantic* asSemantic() const { return nullptr; }
123 
124     /**
125      * Returns true if this is a "compound" item, i.e. one that contains one or more other items.
126      */
isCompound()127     virtual bool isCompound() const { return false; }
128 
129     bool operator==(const Item& other) const&;
130     bool operator!=(const Item& other) const& { return !(*this == other); }
131 
132     /**
133      * Returns the number of bytes required to encode this Item into CBOR.  Note that if this is a
134      * complex Item, calling this method will require walking the whole tree.
135      */
136     virtual size_t encodedSize() const = 0;
137 
138     /**
139      * Encodes the Item into buffer referenced by range [*pos, end).  Returns a pointer to one past
140      * the last position written.  Returns nullptr if there isn't enough space to encode.
141      */
142     virtual uint8_t* encode(uint8_t* pos, const uint8_t* end) const = 0;
143 
144     /**
145      * Encodes the Item by passing each encoded byte to encodeCallback.
146      */
147     virtual void encode(EncodeCallback encodeCallback) const = 0;
148 
149     /**
150      * Clones the Item
151      */
152     virtual std::unique_ptr<Item> clone() const = 0;
153 
154     /**
155      * Encodes the Item into the provided OutputIterator.
156      */
157     template <typename OutputIterator,
158               typename = typename std::iterator_traits<OutputIterator>::iterator_category>
encode(OutputIterator i)159     void encode(OutputIterator i) const {
160         return encode([&](uint8_t v) { *i++ = v; });
161     }
162 
163     /**
164      * Encodes the Item into a new std::vector<uint8_t>.
165      */
encode()166     std::vector<uint8_t> encode() const {
167         std::vector<uint8_t> retval;
168         retval.reserve(encodedSize());
169         encode(std::back_inserter(retval));
170         return retval;
171     }
172 
173     /**
174      * Encodes the Item into a new std::string.
175      */
toString()176     std::string toString() const {
177         std::string retval;
178         retval.reserve(encodedSize());
179         encode([&](uint8_t v) { retval.push_back(v); });
180         return retval;
181     }
182 
183     /**
184      * Encodes only the header of the Item.
185      */
encodeHeader(uint64_t addlInfo,uint8_t * pos,const uint8_t * end)186     inline uint8_t* encodeHeader(uint64_t addlInfo, uint8_t* pos, const uint8_t* end) const {
187         return ::cppbor::encodeHeader(type(), addlInfo, pos, end);
188     }
189 
190     /**
191      * Encodes only the header of the Item.
192      */
encodeHeader(uint64_t addlInfo,EncodeCallback encodeCallback)193     inline void encodeHeader(uint64_t addlInfo, EncodeCallback encodeCallback) const {
194         ::cppbor::encodeHeader(type(), addlInfo, encodeCallback);
195     }
196 };
197 
198 /**
199  * Int is an abstraction that allows Uint and Nint objects to be manipulated without caring about
200  * the sign.
201  */
202 class Int : public Item {
203   public:
204     bool operator==(const Int& other) const& { return value() == other.value(); }
205 
206     virtual int64_t value() const = 0;
207 
asInt()208     const Int* asInt() const override { return this; }
209 };
210 
211 /**
212  * Uint is a concrete Item that implements CBOR major type 0.
213  */
214 class Uint : public Int {
215   public:
216     static constexpr MajorType kMajorType = UINT;
217 
Uint(uint64_t v)218     explicit Uint(uint64_t v) : mValue(v) {}
219 
220     bool operator==(const Uint& other) const& { return mValue == other.mValue; }
221 
type()222     MajorType type() const override { return kMajorType; }
asUint()223     const Uint* asUint() const override { return this; }
224 
encodedSize()225     size_t encodedSize() const override { return headerSize(mValue); }
226 
value()227     int64_t value() const override { return mValue; }
unsignedValue()228     uint64_t unsignedValue() const { return mValue; }
229 
230     using Item::encode;
encode(uint8_t * pos,const uint8_t * end)231     uint8_t* encode(uint8_t* pos, const uint8_t* end) const override {
232         return encodeHeader(mValue, pos, end);
233     }
encode(EncodeCallback encodeCallback)234     void encode(EncodeCallback encodeCallback) const override {
235         encodeHeader(mValue, encodeCallback);
236     }
237 
clone()238     virtual std::unique_ptr<Item> clone() const override { return std::make_unique<Uint>(mValue); }
239 
240   private:
241     uint64_t mValue;
242 };
243 
244 /**
245  * Nint is a concrete Item that implements CBOR major type 1.
246 
247  * Note that it is incapable of expressing the full range of major type 1 values, becaue it can only
248  * express values that fall into the range [std::numeric_limits<int64_t>::min(), -1].  It cannot
249  * express values in the range [std::numeric_limits<int64_t>::min() - 1,
250  * -std::numeric_limits<uint64_t>::max()].
251  */
252 class Nint : public Int {
253   public:
254     static constexpr MajorType kMajorType = NINT;
255 
256     explicit Nint(int64_t v);
257 
258     bool operator==(const Nint& other) const& { return mValue == other.mValue; }
259 
type()260     MajorType type() const override { return kMajorType; }
asNint()261     const Nint* asNint() const override { return this; }
encodedSize()262     size_t encodedSize() const override { return headerSize(addlInfo()); }
263 
value()264     int64_t value() const override { return mValue; }
265 
266     using Item::encode;
encode(uint8_t * pos,const uint8_t * end)267     uint8_t* encode(uint8_t* pos, const uint8_t* end) const override {
268         return encodeHeader(addlInfo(), pos, end);
269     }
encode(EncodeCallback encodeCallback)270     void encode(EncodeCallback encodeCallback) const override {
271         encodeHeader(addlInfo(), encodeCallback);
272     }
273 
clone()274     virtual std::unique_ptr<Item> clone() const override { return std::make_unique<Nint>(mValue); }
275 
276   private:
addlInfo()277     uint64_t addlInfo() const { return -1ll - mValue; }
278 
279     int64_t mValue;
280 };
281 
282 /**
283  * Bstr is a concrete Item that implements major type 2.
284  */
285 class Bstr : public Item {
286   public:
287     static constexpr MajorType kMajorType = BSTR;
288 
289     // Construct from a vector
Bstr(std::vector<uint8_t> v)290     explicit Bstr(std::vector<uint8_t> v) : mValue(std::move(v)) {}
291 
292     // Construct from a string
Bstr(const std::string & v)293     explicit Bstr(const std::string& v)
294         : mValue(reinterpret_cast<const uint8_t*>(v.data()),
295                  reinterpret_cast<const uint8_t*>(v.data()) + v.size()) {}
296 
297     // Construct from a pointer/size pair
Bstr(const std::pair<const uint8_t *,size_t> & buf)298     explicit Bstr(const std::pair<const uint8_t*, size_t>& buf)
299         : mValue(buf.first, buf.first + buf.second) {}
300 
301     // Construct from a pair of iterators
302     template <typename I1, typename I2,
303               typename = typename std::iterator_traits<I1>::iterator_category,
304               typename = typename std::iterator_traits<I2>::iterator_category>
Bstr(const std::pair<I1,I2> & pair)305     explicit Bstr(const std::pair<I1, I2>& pair) : mValue(pair.first, pair.second) {}
306 
307     // Construct from an iterator range.
308     template <typename I1, typename I2,
309               typename = typename std::iterator_traits<I1>::iterator_category,
310               typename = typename std::iterator_traits<I2>::iterator_category>
Bstr(I1 begin,I2 end)311     Bstr(I1 begin, I2 end) : mValue(begin, end) {}
312 
313     bool operator==(const Bstr& other) const& { return mValue == other.mValue; }
314 
type()315     MajorType type() const override { return kMajorType; }
asBstr()316     const Bstr* asBstr() const override { return this; }
encodedSize()317     size_t encodedSize() const override { return headerSize(mValue.size()) + mValue.size(); }
318     using Item::encode;
319     uint8_t* encode(uint8_t* pos, const uint8_t* end) const override;
encode(EncodeCallback encodeCallback)320     void encode(EncodeCallback encodeCallback) const override {
321         encodeHeader(mValue.size(), encodeCallback);
322         encodeValue(encodeCallback);
323     }
324 
value()325     const std::vector<uint8_t>& value() const { return mValue; }
326 
clone()327     virtual std::unique_ptr<Item> clone() const override { return std::make_unique<Bstr>(mValue); }
328 
329   private:
330     void encodeValue(EncodeCallback encodeCallback) const;
331 
332     std::vector<uint8_t> mValue;
333 };
334 
335 /**
336  * Bstr is a concrete Item that implements major type 3.
337  */
338 class Tstr : public Item {
339   public:
340     static constexpr MajorType kMajorType = TSTR;
341 
342     // Construct from a string
Tstr(std::string v)343     explicit Tstr(std::string v) : mValue(std::move(v)) {}
344 
345     // Construct from a string_view
Tstr(const std::string_view & v)346     explicit Tstr(const std::string_view& v) : mValue(v) {}
347 
348     // Construct from a C string
Tstr(const char * v)349     explicit Tstr(const char* v) : mValue(std::string(v)) {}
350 
351     // Construct from a pair of iterators
352     template <typename I1, typename I2,
353               typename = typename std::iterator_traits<I1>::iterator_category,
354               typename = typename std::iterator_traits<I2>::iterator_category>
Tstr(const std::pair<I1,I2> & pair)355     explicit Tstr(const std::pair<I1, I2>& pair) : mValue(pair.first, pair.second) {}
356 
357     // Construct from an iterator range
358     template <typename I1, typename I2,
359               typename = typename std::iterator_traits<I1>::iterator_category,
360               typename = typename std::iterator_traits<I2>::iterator_category>
Tstr(I1 begin,I2 end)361     Tstr(I1 begin, I2 end) : mValue(begin, end) {}
362 
363     bool operator==(const Tstr& other) const& { return mValue == other.mValue; }
364 
type()365     MajorType type() const override { return kMajorType; }
asTstr()366     const Tstr* asTstr() const override { return this; }
encodedSize()367     size_t encodedSize() const override { return headerSize(mValue.size()) + mValue.size(); }
368     using Item::encode;
369     uint8_t* encode(uint8_t* pos, const uint8_t* end) const override;
encode(EncodeCallback encodeCallback)370     void encode(EncodeCallback encodeCallback) const override {
371         encodeHeader(mValue.size(), encodeCallback);
372         encodeValue(encodeCallback);
373     }
374 
value()375     const std::string& value() const { return mValue; }
376 
clone()377     virtual std::unique_ptr<Item> clone() const override { return std::make_unique<Tstr>(mValue); }
378 
379   private:
380     void encodeValue(EncodeCallback encodeCallback) const;
381 
382     std::string mValue;
383 };
384 
385 /**
386  * CompoundItem is an abstract Item that provides common functionality for Items that contain other
387  * items, i.e. Arrays (CBOR type 4) and Maps (CBOR type 5).
388  */
389 class CompoundItem : public Item {
390   public:
391     bool operator==(const CompoundItem& other) const&;
392 
size()393     virtual size_t size() const { return mEntries.size(); }
394 
isCompound()395     bool isCompound() const override { return true; }
396 
encodedSize()397     size_t encodedSize() const override {
398         return std::accumulate(mEntries.begin(), mEntries.end(), headerSize(size()),
399                                [](size_t sum, auto& entry) { return sum + entry->encodedSize(); });
400     }
401 
402     using Item::encode;  // Make base versions visible.
403     uint8_t* encode(uint8_t* pos, const uint8_t* end) const override;
404     void encode(EncodeCallback encodeCallback) const override;
405 
406     virtual uint64_t addlInfo() const = 0;
407 
408   protected:
409     std::vector<std::unique_ptr<Item>> mEntries;
410 };
411 
412 /*
413  * Array is a concrete Item that implements CBOR major type 4.
414  *
415  * Note that Arrays are not copyable.  This is because copying them is expensive and making them
416  * move-only ensures that they're never copied accidentally.  If you actually want to copy an Array,
417  * use the clone() method.
418  */
419 class Array : public CompoundItem {
420   public:
421     static constexpr MajorType kMajorType = ARRAY;
422 
423     Array() = default;
424     Array(const Array& other) = delete;
425     Array(Array&&) = default;
426     Array& operator=(const Array&) = delete;
427     Array& operator=(Array&&) = default;
428 
429     /**
430      * Construct an Array from a variable number of arguments of different types.  See
431      * details::makeItem below for details on what types may be provided.  In general, this accepts
432      * all of the types you'd expect and doest the things you'd expect (integral values are addes as
433      * Uint or Nint, std::string and char* are added as Tstr, bools are added as Bool, etc.).
434      */
435     template <typename... Args, typename Enable>
436     Array(Args&&... args);
437 
438     /**
439      * Append a single element to the Array, of any compatible type.
440      */
441     template <typename T>
442     Array& add(T&& v) &;
443     template <typename T>
444     Array&& add(T&& v) &&;
445 
446     const std::unique_ptr<Item>& operator[](size_t index) const { return mEntries[index]; }
447     std::unique_ptr<Item>& operator[](size_t index) { return mEntries[index]; }
448 
type()449     MajorType type() const override { return kMajorType; }
asArray()450     const Array* asArray() const override { return this; }
451 
452     virtual std::unique_ptr<Item> clone() const override;
453 
addlInfo()454     uint64_t addlInfo() const override { return size(); }
455 };
456 
457 /*
458  * Map is a concrete Item that implements CBOR major type 5.
459  *
460  * Note that Maps are not copyable.  This is because copying them is expensive and making them
461  * move-only ensures that they're never copied accidentally.  If you actually want to copy a
462  * Map, use the clone() method.
463  */
464 class Map : public CompoundItem {
465   public:
466     static constexpr MajorType kMajorType = MAP;
467 
468     Map() = default;
469     Map(const Map& other) = delete;
470     Map(Map&&) = default;
471     Map& operator=(const Map& other) = delete;
472     Map& operator=(Map&&) = default;
473 
474     /**
475      * Construct a Map from a variable number of arguments of different types.  An even number of
476      * arguments must be provided (this is verified statically). See details::makeItem below for
477      * details on what types may be provided.  In general, this accepts all of the types you'd
478      * expect and doest the things you'd expect (integral values are addes as Uint or Nint,
479      * std::string and char* are added as Tstr, bools are added as Bool, etc.).
480      */
481     template <typename... Args, typename Enable>
482     Map(Args&&... args);
483 
484     /**
485      * Append a key/value pair to the Map, of any compatible types.
486      */
487     template <typename Key, typename Value>
488     Map& add(Key&& key, Value&& value) &;
489     template <typename Key, typename Value>
490     Map&& add(Key&& key, Value&& value) &&;
491 
size()492     size_t size() const override {
493         assertInvariant();
494         return mEntries.size() / 2;
495     }
496 
497     template <typename Key, typename Enable>
498     std::pair<std::unique_ptr<Item>&, bool> get(Key key);
499 
500     std::pair<const std::unique_ptr<Item>&, const std::unique_ptr<Item>&> operator[](
501             size_t index) const {
502         assertInvariant();
503         return {mEntries[index * 2], mEntries[index * 2 + 1]};
504     }
505 
506     std::pair<std::unique_ptr<Item>&, std::unique_ptr<Item>&> operator[](size_t index) {
507         assertInvariant();
508         return {mEntries[index * 2], mEntries[index * 2 + 1]};
509     }
510 
type()511     MajorType type() const override { return kMajorType; }
asMap()512     const Map* asMap() const override { return this; }
513 
514     virtual std::unique_ptr<Item> clone() const override;
515 
addlInfo()516     uint64_t addlInfo() const override { return size(); }
517 
518   private:
519     void assertInvariant() const;
520 };
521 
522 class Semantic : public CompoundItem {
523   public:
524     static constexpr MajorType kMajorType = SEMANTIC;
525 
526     template <typename T>
527     explicit Semantic(uint64_t value, T&& child);
528 
529     Semantic(const Semantic& other) = delete;
530     Semantic(Semantic&&) = default;
531     Semantic& operator=(const Semantic& other) = delete;
532     Semantic& operator=(Semantic&&) = default;
533 
size()534     size_t size() const override {
535         assertInvariant();
536         return 1;
537     }
538 
encodedSize()539     size_t encodedSize() const override {
540         return std::accumulate(mEntries.begin(), mEntries.end(), headerSize(mValue),
541                                [](size_t sum, auto& entry) { return sum + entry->encodedSize(); });
542     }
543 
type()544     MajorType type() const override { return kMajorType; }
asSemantic()545     const Semantic* asSemantic() const override { return this; }
546 
child()547     const std::unique_ptr<Item>& child() const {
548         assertInvariant();
549         return mEntries[0];
550     }
551 
child()552     std::unique_ptr<Item>& child() {
553         assertInvariant();
554         return mEntries[0];
555     }
556 
value()557     uint64_t value() const { return mValue; }
558 
addlInfo()559     uint64_t addlInfo() const override { return value(); }
560 
clone()561     virtual std::unique_ptr<Item> clone() const override {
562         assertInvariant();
563         return std::make_unique<Semantic>(mValue, mEntries[0]->clone());
564     }
565 
566   protected:
567     Semantic() = default;
Semantic(uint64_t value)568     Semantic(uint64_t value) : mValue(value) {}
569     uint64_t mValue;
570 
571   private:
572     void assertInvariant() const;
573 };
574 
575 /**
576  * Simple is abstract Item that implements CBOR major type 7.  It is intended to be subclassed to
577  * create concrete Simple types.  At present only Bool is provided.
578  */
579 class Simple : public Item {
580   public:
581     static constexpr MajorType kMajorType = SIMPLE;
582 
583     bool operator==(const Simple& other) const&;
584 
585     virtual SimpleType simpleType() const = 0;
type()586     MajorType type() const override { return kMajorType; }
587 
asSimple()588     const Simple* asSimple() const override { return this; }
589 
asBool()590     virtual const Bool* asBool() const { return nullptr; };
asNull()591     virtual const Null* asNull() const { return nullptr; };
592 };
593 
594 /**
595  * Bool is a concrete type that implements CBOR major type 7, with additional item values for TRUE
596  * and FALSE.
597  */
598 class Bool : public Simple {
599   public:
600     static constexpr SimpleType kSimpleType = BOOLEAN;
601 
Bool(bool v)602     explicit Bool(bool v) : mValue(v) {}
603 
604     bool operator==(const Bool& other) const& { return mValue == other.mValue; }
605 
simpleType()606     SimpleType simpleType() const override { return kSimpleType; }
asBool()607     const Bool* asBool() const override { return this; }
608 
encodedSize()609     size_t encodedSize() const override { return 1; }
610 
611     using Item::encode;
encode(uint8_t * pos,const uint8_t * end)612     uint8_t* encode(uint8_t* pos, const uint8_t* end) const override {
613         return encodeHeader(mValue ? TRUE : FALSE, pos, end);
614     }
encode(EncodeCallback encodeCallback)615     void encode(EncodeCallback encodeCallback) const override {
616         encodeHeader(mValue ? TRUE : FALSE, encodeCallback);
617     }
618 
value()619     bool value() const { return mValue; }
620 
clone()621     virtual std::unique_ptr<Item> clone() const override { return std::make_unique<Bool>(mValue); }
622 
623   private:
624     bool mValue;
625 };
626 
627 /**
628  * Null is a concrete type that implements CBOR major type 7, with additional item value for NULL
629  */
630 class Null : public Simple {
631   public:
632     static constexpr SimpleType kSimpleType = NULL_T;
633 
Null()634     explicit Null() {}
635 
simpleType()636     SimpleType simpleType() const override { return kSimpleType; }
asNull()637     const Null* asNull() const override { return this; }
638 
encodedSize()639     size_t encodedSize() const override { return 1; }
640 
641     using Item::encode;
encode(uint8_t * pos,const uint8_t * end)642     uint8_t* encode(uint8_t* pos, const uint8_t* end) const override {
643         return encodeHeader(NULL_V, pos, end);
644     }
encode(EncodeCallback encodeCallback)645     void encode(EncodeCallback encodeCallback) const override {
646         encodeHeader(NULL_V, encodeCallback);
647     }
648 
clone()649     virtual std::unique_ptr<Item> clone() const override { return std::make_unique<Null>(); }
650 };
651 
652 template <typename T>
downcastItem(std::unique_ptr<Item> && v)653 std::unique_ptr<T> downcastItem(std::unique_ptr<Item>&& v) {
654     static_assert(std::is_base_of_v<Item, T> && !std::is_abstract_v<T>,
655                   "returned type is not an Item or is an abstract class");
656     if (v && T::kMajorType == v->type()) {
657         if constexpr (std::is_base_of_v<Simple, T>) {
658             if (T::kSimpleType != v->asSimple()->simpleType()) {
659                 return nullptr;
660             }
661         }
662         return std::unique_ptr<T>(static_cast<T*>(v.release()));
663     } else {
664         return nullptr;
665     }
666 }
667 
668 /**
669  * Details. Mostly you shouldn't have to look below, except perhaps at the docstring for makeItem.
670  */
671 namespace details {
672 
673 template <typename T, typename V, typename Enable = void>
674 struct is_iterator_pair_over : public std::false_type {};
675 
676 template <typename I1, typename I2, typename V>
677 struct is_iterator_pair_over<
678         std::pair<I1, I2>, V,
679         typename std::enable_if_t<std::is_same_v<V, typename std::iterator_traits<I1>::value_type>>>
680     : public std::true_type {};
681 
682 template <typename T, typename V, typename Enable = void>
683 struct is_unique_ptr_of_subclass_of_v : public std::false_type {};
684 
685 template <typename T, typename P>
686 struct is_unique_ptr_of_subclass_of_v<T, std::unique_ptr<P>,
687                                       typename std::enable_if_t<std::is_base_of_v<T, P>>>
688     : public std::true_type {};
689 
690 /* check if type is one of std::string (1), std::string_view (2), null-terminated char* (3) or pair
691  *     of iterators (4)*/
692 template <typename T, typename Enable = void>
693 struct is_text_type_v : public std::false_type {};
694 
695 template <typename T>
696 struct is_text_type_v<
697         T, typename std::enable_if_t<
698                    /* case 1 */  //
699                    std::is_same_v<std::remove_cv_t<std::remove_reference_t<T>>, std::string>
700                    /* case 2 */  //
701                    || std::is_same_v<std::remove_cv_t<std::remove_reference_t<T>>, std::string_view>
702                    /* case 3 */                                                 //
703                    || std::is_same_v<std::remove_cv_t<std::decay_t<T>>, char*>  //
704                    || std::is_same_v<std::remove_cv_t<std::decay_t<T>>, const char*>
705                    /* case 4 */
706                    || details::is_iterator_pair_over<T, char>::value>> : public std::true_type {};
707 
708 /**
709  * Construct a unique_ptr<Item> from many argument types. Accepts:
710  *
711  * (a) booleans;
712  * (b) integers, all sizes and signs;
713  * (c) text strings, as defined by is_text_type_v above;
714  * (d) byte strings, as std::vector<uint8_t>(d1), pair of iterators (d2) or pair<uint8_t*, size_T>
715  *     (d3); and
716  * (e) Item subclass instances, including Array and Map.  Items may be provided by naked pointer
717  *     (e1), unique_ptr (e2), reference (e3) or value (e3).  If provided by reference or value, will
718  *     be moved if possible.  If provided by pointer, ownership is taken.
719  * (f) null pointer;
720  */
721 template <typename T>
722 std::unique_ptr<Item> makeItem(T v) {
723     Item* p = nullptr;
724     if constexpr (/* case a */ std::is_same_v<T, bool>) {
725         p = new Bool(v);
726     } else if constexpr (/* case b */ std::is_integral_v<T>) {  // b
727         if (v < 0) {
728             p = new Nint(v);
729         } else {
730             p = new Uint(static_cast<uint64_t>(v));
731         }
732     } else if constexpr (/* case c */  //
733                          details::is_text_type_v<T>::value) {
734         p = new Tstr(v);
735     } else if constexpr (/* case d1 */  //
736                          std::is_same_v<std::remove_cv_t<std::remove_reference_t<T>>,
737                                         std::vector<uint8_t>>
738                          /* case d2 */  //
739                          || details::is_iterator_pair_over<T, uint8_t>::value
740                          /* case d3 */  //
741                          || std::is_same_v<std::remove_cv_t<std::remove_reference_t<T>>,
742                                            std::pair<uint8_t*, size_t>>) {
743         p = new Bstr(v);
744     } else if constexpr (/* case e1 */  //
745                          std::is_pointer_v<T> &&
746                          std::is_base_of_v<Item, std::remove_pointer_t<T>>) {
747         p = v;
748     } else if constexpr (/* case e2 */  //
749                          details::is_unique_ptr_of_subclass_of_v<Item, T>::value) {
750         p = v.release();
751     } else if constexpr (/* case e3 */  //
752                          std::is_base_of_v<Item, T>) {
753         p = new T(std::move(v));
754     } else if constexpr (/* case f */ std::is_null_pointer_v<T>) {
755         p = new Null();
756     } else {
757         // It's odd that this can't be static_assert(false), since it shouldn't be evaluated if one
758         // of the above ifs matches.  But static_assert(false) always triggers.
759         static_assert(std::is_same_v<T, bool>, "makeItem called with unsupported type");
760     }
761     return std::unique_ptr<Item>(p);
762 }
763 
764 }  // namespace details
765 
766 template <typename... Args,
767           /* Prevent use as copy ctor */ typename = std::enable_if_t<
768                   (sizeof...(Args)) != 1 ||
769                   !(std::is_same_v<Array, std::remove_cv_t<std::remove_reference_t<Args>>> || ...)>>
770 Array::Array(Args&&... args) {
771     mEntries.reserve(sizeof...(args));
772     (mEntries.push_back(details::makeItem(std::forward<Args>(args))), ...);
773 }
774 
775 template <typename T>
776 Array& Array::add(T&& v) & {
777     mEntries.push_back(details::makeItem(std::forward<T>(v)));
778     return *this;
779 }
780 
781 template <typename T>
782 Array&& Array::add(T&& v) && {
783     mEntries.push_back(details::makeItem(std::forward<T>(v)));
784     return std::move(*this);
785 }
786 
787 template <typename... Args,
788           /* Prevent use as copy ctor */ typename = std::enable_if_t<(sizeof...(Args)) != 1>>
789 Map::Map(Args&&... args) {
790     static_assert((sizeof...(Args)) % 2 == 0, "Map must have an even number of entries");
791     mEntries.reserve(sizeof...(args));
792     (mEntries.push_back(details::makeItem(std::forward<Args>(args))), ...);
793 }
794 
795 template <typename Key, typename Value>
796 Map& Map::add(Key&& key, Value&& value) & {
797     mEntries.push_back(details::makeItem(std::forward<Key>(key)));
798     mEntries.push_back(details::makeItem(std::forward<Value>(value)));
799     return *this;
800 }
801 
802 template <typename Key, typename Value>
803 Map&& Map::add(Key&& key, Value&& value) && {
804     this->add(std::forward<Key>(key), std::forward<Value>(value));
805     return std::move(*this);
806 }
807 
808 template <typename Key, typename = std::enable_if_t<std::is_integral_v<Key> ||
809                                                     details::is_text_type_v<Key>::value>>
810 std::pair<std::unique_ptr<Item>&, bool> Map::get(Key key) {
811     assertInvariant();
812     auto keyItem = details::makeItem(key);
813     for (size_t i = 0; i < mEntries.size(); i += 2) {
814         if (*keyItem == *mEntries[i]) {
815             return {mEntries[i + 1], true};
816         }
817     }
818     return {keyItem, false};
819 }
820 
821 template <typename T>
822 Semantic::Semantic(uint64_t value, T&& child) : mValue(value) {
823     mEntries.reserve(1);
824     mEntries.push_back(details::makeItem(std::forward<T>(child)));
825 }
826 
827 }  // namespace cppbor
828