diff --git a/src/private/mx/core/OneOrMore.h b/src/private/mx/core/OneOrMore.h index fc131b804..08fa545ce 100644 --- a/src/private/mx/core/OneOrMore.h +++ b/src/private/mx/core/OneOrMore.h @@ -20,11 +20,11 @@ namespace mx::core template class OneOrMore { public: - OneOrMore() : m_items(1) + OneOrMore() : m_items(1), m_hasPlaceholder(true) { } - explicit OneOrMore(T first) + explicit OneOrMore(T first) : m_hasPlaceholder(false) { m_items.push_back(std::move(first)); } @@ -41,12 +41,21 @@ template class OneOrMore void add(T item) { - m_items.push_back(std::move(item)); + if (m_hasPlaceholder) + { + m_items.front() = std::move(item); + m_hasPlaceholder = false; + } + else + { + m_items.push_back(std::move(item)); + } } /// Deterministic repair: an empty replacement becomes one default item. void setItems(std::vector items) { + m_hasPlaceholder = items.empty(); if (items.empty()) { items.emplace_back(); @@ -66,6 +75,7 @@ template class OneOrMore private: std::vector m_items; + bool m_hasPlaceholder = false; }; } // namespace mx::core diff --git a/src/private/mxtest/core/ShapeTest.cpp b/src/private/mxtest/core/ShapeTest.cpp index 94c911881..bdfd72543 100644 --- a/src/private/mxtest/core/ShapeTest.cpp +++ b/src/private/mxtest/core/ShapeTest.cpp @@ -11,6 +11,7 @@ #include "cpul/cpulTestHarness.h" #include "mx/core/Error.h" +#include "mx/core/OneOrMore.h" #include "mx/core/Xml.h" #include "mx/core/generated/Beam.h" #include "mx/core/generated/BeamValue.h" @@ -88,6 +89,36 @@ TEST(DefaultConstructionIsValid, Shapes) CHECK_EQUAL(std::string{"A0"}, toXml(Pitch{})); } +TEST(OneOrMoreAddConsumesDefaultPlaceholder, Shapes) +{ + OneOrMore items; + items.add(7); + CHECK_EQUAL(std::size_t{1}, items.items().size()); + CHECK_EQUAL(7, items.front()); + + items.add(8); + CHECK_EQUAL(std::size_t{2}, items.items().size()); + CHECK_EQUAL(8, items.items().back()); +} + +TEST(OneOrMoreAddPreservesExplicitFirstItem, Shapes) +{ + OneOrMore items{0}; + items.add(7); + CHECK_EQUAL(std::size_t{2}, items.items().size()); + CHECK_EQUAL(0, items.items().front()); + CHECK_EQUAL(7, items.items().back()); +} + +TEST(OneOrMoreEmptySetItemsCreatesPlaceholder, Shapes) +{ + OneOrMore items{1}; + items.setItems({}); + items.add(7); + CHECK_EQUAL(std::size_t{1}, items.items().size()); + CHECK_EQUAL(7, items.front()); +} + TEST(VariantExclusivity, Shapes) { // Exactly one alternative by construction; duplicate alternative TYPES