Remove CompoundItem.

Refactor to remove CompoundItem. It was a way to share some common
code between Array and Map, and later Semantic, but the
representations of those classes need to diverge so it adds no value.

Test: cppbor_test_external
Change-Id: I986e90c1d212f6d81debe4b2f650ba68f065a6ed
diff --git a/src/cppbor.cpp b/src/cppbor.cpp
index 50e98ca..632dd0b 100644
--- a/src/cppbor.cpp
+++ b/src/cppbor.cpp
@@ -52,7 +52,7 @@
     }
 }
 
-bool cborAreAllElementsNonCompound(const CompoundItem* compoundItem) {
+bool cborAreAllElementsNonCompound(const Item* compoundItem) {
     if (compoundItem->type() == ARRAY) {
         const Array* array = compoundItem->asArray();
         for (size_t n = 0; n < array->size(); n++) {
@@ -365,17 +365,16 @@
     }
 }
 
-bool CompoundItem::operator==(const CompoundItem& other) const& {
-    return type() == other.type()             //
-           && addlInfo() == other.addlInfo()  //
+bool Array::operator==(const Array& other) const& {
+    return size() == other.size()
            // Can't use vector::operator== because the contents are pointers.  std::equal lets us
            // provide a predicate that does the dereferencing.
            && std::equal(mEntries.begin(), mEntries.end(), other.mEntries.begin(),
                          [](auto& a, auto& b) -> bool { return *a == *b; });
 }
 
-uint8_t* CompoundItem::encode(uint8_t* pos, const uint8_t* end) const {
-    pos = encodeHeader(addlInfo(), pos, end);
+uint8_t* Array::encode(uint8_t* pos, const uint8_t* end) const {
+    pos = encodeHeader(size(), pos, end);
     if (!pos) return nullptr;
     for (auto& entry : mEntries) {
         pos = entry->encode(pos, end);
@@ -384,8 +383,41 @@
     return pos;
 }
 
-void CompoundItem::encode(EncodeCallback encodeCallback) const {
-    encodeHeader(addlInfo(), encodeCallback);
+void Array::encode(EncodeCallback encodeCallback) const {
+    encodeHeader(size(), encodeCallback);
+    for (auto& entry : mEntries) {
+        entry->encode(encodeCallback);
+    }
+}
+
+std::unique_ptr<Item> Array::clone() const {
+    auto res = std::make_unique<Array>();
+    for (size_t i = 0; i < mEntries.size(); i++) {
+        res->add(mEntries[i]->clone());
+    }
+    return res;
+}
+
+bool Map::operator==(const Map& other) const& {
+    return size() == other.size()
+           // Can't use vector::operator== because the contents are pointers.  std::equal lets us
+           // provide a predicate that does the dereferencing.
+           && std::equal(mEntries.begin(), mEntries.end(), other.mEntries.begin(),
+                         [](auto& a, auto& b) -> bool { return *a == *b; });
+}
+
+uint8_t* Map::encode(uint8_t* pos, const uint8_t* end) const {
+    pos = encodeHeader(size(), pos, end);
+    if (!pos) return nullptr;
+    for (auto& entry : mEntries) {
+        pos = entry->encode(pos, end);
+        if (!pos) return nullptr;
+    }
+    return pos;
+}
+
+void Map::encode(EncodeCallback encodeCallback) const {
+    encodeHeader(size(), encodeCallback);
     for (auto& entry : mEntries) {
         entry->encode(encodeCallback);
     }
@@ -455,12 +487,20 @@
     return res;
 }
 
-std::unique_ptr<Item> Array::clone() const {
-    auto res = std::make_unique<Array>();
-    for (size_t i = 0; i < mEntries.size(); i++) {
-        res->add(mEntries[i]->clone());
-    }
-    return res;
+bool Semantic::operator==(const Semantic& other) const& {
+    assertInvariant();
+    return *mEntries.front() == *other.mEntries.front();
+}
+
+uint8_t* Semantic::encode(uint8_t* pos, const uint8_t* end) const {
+    pos = encodeHeader(value(), pos, end);
+    if (!pos) return nullptr;
+    return mEntries.front()->encode(pos, end);
+}
+
+void Semantic::encode(EncodeCallback encodeCallback) const {
+    encodeHeader(value(), encodeCallback);
+    mEntries.front()->encode(encodeCallback);
 }
 
 void Semantic::assertInvariant() const {
diff --git a/src/cppbor_parse.cpp b/src/cppbor_parse.cpp
index 357b9ee..488f8c7 100644
--- a/src/cppbor_parse.cpp
+++ b/src/cppbor_parse.cpp
@@ -280,10 +280,7 @@
             // Starting a new compound data item, i.e. a new parent.  Save it on the parent stack.
             // It's safe to save a raw pointer because the unique_ptr is guaranteed to stay in
             // existence until the corresponding itemEnd() call.
-#if __has_feature(cxx_rtti)
-            assert(dynamic_cast<CompoundItem*>(item.get()));
-#endif
-            mParentStack.push(static_cast<CompoundItem*>(item.get()));
+            mParentStack.push(item.get());
             return this;
         } else {
             appendToLastParent(std::move(item));
@@ -336,7 +333,7 @@
     }
 
     std::unique_ptr<Item> mTheItem;
-    std::stack<CompoundItem*> mParentStack;
+    std::stack<Item*> mParentStack;
     const uint8_t* mPosition = nullptr;
     std::string mErrorMessage;
 };