diff --git a/bench/AbstractTreeBench.cpp b/bench/AbstractTreeBench.cpp index ff628109e..97bf9f905 100644 --- a/bench/AbstractTreeBench.cpp +++ b/bench/AbstractTreeBench.cpp @@ -13,8 +13,7 @@ struct DataTree : chowdsp::AbstractTree static Node& insertOneElement (FakeData&& element, Node& parent, AbstractTree& tree) { - auto* new_node = tree.createEmptyNode(); - new_node->leaf = std::move (element); + auto* new_node = tree.createLeafNode (std::move (element)); new_node->prev_sibling = parent.last_child; if (parent.last_child != nullptr) parent.last_child->next_sibling = new_node; @@ -27,8 +26,7 @@ struct DataTree : chowdsp::AbstractTree AbstractTree& tree, std::string_view tag) { - auto* new_sub_tree_node = tree.createEmptyNode(); - new_sub_tree_node->tag = tag; + auto* new_sub_tree_node = tree.createTagNode (tag); new_sub_tree_node->prev_sibling = parent.last_child; if (parent.last_child != nullptr) parent.last_child->next_sibling = new_sub_tree_node; @@ -38,25 +36,26 @@ struct DataTree : chowdsp::AbstractTree static FakeData& insertElementInternal (AbstractTree& self, FakeData&& element, Node& root) { + // since we know all the tags ahead of time, we only compare the first letter. for (auto* iter = root.first_child; iter != nullptr; iter = iter->next_sibling) { - if (iter->tag == positiveTag && element[0] > 0) - return *insertOneElement (std::move (element), *iter, self).leaf; + if (iter->value.tag()[0] == positiveTag[0] && element[0] > 0) + return insertOneElement (std::move (element), *iter, self).value.leaf(); - if (iter->tag == negativeTag && element[0] < 0) - return *insertOneElement (std::move (element), *iter, self).leaf; + if (iter->value.tag()[0] == negativeTag[0] && element[0] < 0) + return insertOneElement (std::move (element), *iter, self).value.leaf(); - if (iter->tag == zeroTag && element[0] == 0) - return *insertOneElement (std::move (element), *iter, self).leaf; + if (iter->value.tag()[0] == zeroTag[0] && element[0] == 0) + return insertOneElement (std::move (element), *iter, self).value.leaf(); } if (element[0] > 0) - return *insertElementIntoNewSubtree (std::move (element), root, self, positiveTag).leaf; + return insertElementIntoNewSubtree (std::move (element), root, self, positiveTag).value.leaf(); if (element[0] < 0) - return *insertElementIntoNewSubtree (std::move (element), root, self, negativeTag).leaf; + return insertElementIntoNewSubtree (std::move (element), root, self, negativeTag).value.leaf(); - return *insertElementIntoNewSubtree (std::move (element), root, self, zeroTag).leaf; + return insertElementIntoNewSubtree (std::move (element), root, self, zeroTag).value.leaf(); } }; @@ -223,8 +222,8 @@ static void accessTree (benchmark::State& state) { if (iter_count == 25) { - (*iter->leaf)[0]++; - benchmark::DoNotOptimize ((*iter->leaf)[0]); + iter->value.leaf()[0]++; + benchmark::DoNotOptimize (iter->value.leaf()[0]); break; } iter_count++; diff --git a/modules/common/chowdsp_data_structures/Structures/chowdsp_AbstractTree.cpp b/modules/common/chowdsp_data_structures/Structures/chowdsp_AbstractTree.cpp index ed1041365..be0829ab4 100644 --- a/modules/common/chowdsp_data_structures/Structures/chowdsp_AbstractTree.cpp +++ b/modules/common/chowdsp_data_structures/Structures/chowdsp_AbstractTree.cpp @@ -1,8 +1,9 @@ namespace chowdsp { template -AbstractTree::AbstractTree() +AbstractTree::AbstractTree (size_t num_nodes_reserved) { + reserve (num_nodes_reserved); clear(); } @@ -10,7 +11,7 @@ template AbstractTree::~AbstractTree() { doForAllNodes ([] (Node& node) - { node.leaf.reset(); }); + { node.value.destroy(); }); } template @@ -79,20 +80,24 @@ void AbstractTree::removeNode (Node& node) onDelete (node); - if (node.leaf.has_value()) + if (node.value.has_value()) count--; + for (auto* iter = &root_node; iter != nullptr; iter = iter->next_linear) + { + if (iter->next_linear == &node) + { + iter->next_linear = node.next_linear; + if (last_node == &node) + last_node = iter; + break; + } + } + if (node.prev_sibling != nullptr) node.prev_sibling->next_sibling = node.next_sibling; if (node.next_sibling != nullptr) node.next_sibling->prev_sibling = node.prev_sibling; - if (node.next_linear != nullptr) - node.next_linear->prev_linear = node.prev_linear; - // we don't need to check if node.prev_linear is nullptr, because the root node is never deleted! - node.prev_linear->next_linear = node.next_linear; - - if (last_node == &node) - last_node = node.prev_linear; if (node.parent->first_child == node.parent->last_child) { @@ -108,7 +113,7 @@ void AbstractTree::removeNode (Node& node) node.parent->last_child = node.prev_sibling; } - node.leaf.reset(); + node.value.destroy(); } template @@ -116,7 +121,7 @@ void AbstractTree::removeElement (const ElementType& e { for (auto* node = &root_node; node != nullptr; node = node->next_linear) { - if (node->leaf.has_value() && node->leaf == element) + if (node->value.has_value() && node->value.leaf() == element) { removeNode (*node); break; @@ -133,7 +138,7 @@ void AbstractTree::removeElements (const Callable& ele // need to change. for (auto* node = &root_node; node != nullptr;) { - if (node->leaf.has_value() && elementsToRemove (*node->leaf)) + if (node->value.has_value() && elementsToRemove (node->value.leaf())) { auto* next_node = node->next_linear; removeNode (*node); @@ -150,8 +155,8 @@ template void AbstractTree::clear() { doForAllNodes ([] (Node& node) - { node.leaf.reset(); }); - allocator.reset (64 * sizeof (Node)); + { node.value.destroy(); }); + allocator.clear(); count = 0; root_node = {}; } @@ -205,8 +210,8 @@ void AbstractTree::doForAllElements (Callable&& callab doForAllNodes ( [c = std::forward (callable)] (Node& node) { - if (node.leaf.has_value()) - c (*node.leaf); + if (node.value.has_value()) + c (node.value.leaf()); }); } @@ -217,28 +222,50 @@ void AbstractTree::doForAllElements (Callable&& callab doForAllNodes ( [c = std::forward (callable)] (const Node& node) { - if (node.leaf.has_value()) - c (*node.leaf); + if (node.value.has_value()) + c (node.value.leaf()); }); } template -typename AbstractTree::Node* AbstractTree::createEmptyNode() +typename AbstractTree::Node* AbstractTree::createTagNode (std::string_view str) { - auto* new_node = new (allocator.allocate (1)) Node {}; + auto* bytes = (std::byte*) allocator.allocate_bytes (sizeof (Node) + sizeof (std::string_view) + alignof (std::string_view) + str.size(), alignof (Node)); + auto* new_node = new (bytes) Node {}; last_node->next_linear = new_node; - new_node->prev_linear = last_node; last_node = new_node; + bytes = juce::snapPointerToAlignment (bytes + sizeof (Node), alignof (std::string_view)); + + auto* str_data = (char*) (bytes + sizeof (std::string_view)); + std::copy (str.begin(), str.end(), str_data); + + auto tag_str_view = new (bytes) std::string_view { str_data, str.size() }; + new_node->value.set_tag (tag_str_view); + return new_node; } template -std::string_view AbstractTree::allocateTag (std::string_view str) +void AbstractTree::reserve (size_t num_nodes) { - auto* str_data = allocator.allocate (str.size()); - std::copy (str.begin(), str.end(), str_data); - return { str_data, str.size() }; // NOLINT NOSONAR + if (count > 0) + { + jassertfalse; + return; + } + allocator.reset (num_nodes * (sizeof (Node) + sizeof (ElementType) + alignof (ElementType))); +} + +template +void AbstractTree::shrinkArena() +{ + if (count > 0) + { + jassertfalse; + return; + } + allocator.reset (allocator.get_current_arena().get_total_num_bytes()); } } // namespace chowdsp diff --git a/modules/common/chowdsp_data_structures/Structures/chowdsp_AbstractTree.h b/modules/common/chowdsp_data_structures/Structures/chowdsp_AbstractTree.h index 7ef847dcf..9c57bcbf1 100644 --- a/modules/common/chowdsp_data_structures/Structures/chowdsp_AbstractTree.h +++ b/modules/common/chowdsp_data_structures/Structures/chowdsp_AbstractTree.h @@ -9,10 +9,75 @@ template class AbstractTree { public: + struct ValuePtr + { + JUCE_BEGIN_IGNORE_WARNINGS_MSVC (4324) // structure was padded due to alignment specifier + struct alignas (8) Void + { + }; + PackedPointer ptr { nullptr, Empty }; + JUCE_END_IGNORE_WARNINGS_MSVC + + ValuePtr() = default; + + enum : uint8_t + { + Empty = 0, + Leaf = 1, + Tag = 2, + }; + + void set (ElementType* new_leaf) + { + jassert (! has_value()); + ptr.set (reinterpret_cast (new_leaf), Leaf); // NOSONAR + } + + void set_tag (std::string_view* new_tag) + { + jassert (! has_value()); + ptr.set (reinterpret_cast (new_tag), Tag); // NOSONAR + } + + [[nodiscard]] ElementType& leaf() + { + jassert (has_value()); + return *(reinterpret_cast (ptr.get_ptr())); // NOSONAR + } + + [[nodiscard]] const ElementType& leaf() const + { + jassert (has_value()); + return *(reinterpret_cast (ptr.get_ptr())); // NOSONAR + } + + [[nodiscard]] std::string_view tag() const + { + jassert (is_tag()); + return *(reinterpret_cast (ptr.get_ptr())); // NOSONAR + } + + void destroy() + { + if (has_value()) + leaf().~ElementType(); // NOSONAR + ptr.set (nullptr, Empty); + } + + [[nodiscard]] bool has_value() const noexcept + { + return ptr.get_flags() == Leaf; + } + + [[nodiscard]] bool is_tag() const noexcept + { + return ptr.get_flags() == Tag; + } + }; + struct Node { - std::optional leaf { std::nullopt }; - std::string_view tag {}; + ValuePtr value {}; Node* parent {}; // slot for parent in hierarchy Node* first_child {}; // slot for first child in hierarchy @@ -20,10 +85,9 @@ class AbstractTree Node* next_sibling {}; // slot for next sibling in hierarchy Node* prev_sibling {}; // slot for previous sibling in hierarchy Node* next_linear {}; // slot for linked list through all nodes - Node* prev_linear {}; // slot for linked list through all nodes }; - AbstractTree(); + explicit AbstractTree (size_t num_nodes_reserved = 64); virtual ~AbstractTree(); AbstractTree (const AbstractTree&) = delete; @@ -77,19 +141,43 @@ class AbstractTree template void doForAllElements (Callable&& callable) const; - /** Creates a new empty node in the tree's memory arena. */ - Node* createEmptyNode(); + /** Creates a new tag node in the tree's memory arena. */ + Node* createTagNode (std::string_view str); + + /** Creates a new leaf node in the tree's memory arena. */ + template + Node* createLeafNode (Args&&... args) + { + auto* bytes = (std::byte*) allocator.allocate_bytes (sizeof (Node) + sizeof (C) + alignof (C), alignof (Node)); + + auto* new_node = new (bytes) Node {}; + last_node->next_linear = new_node; + last_node = new_node; - /** Allocates a new tag in the tree's memory arena. */ - std::string_view allocateTag (std::string_view str); + auto* new_obj = new (juce::snapPointerToAlignment (bytes + sizeof (Node), alignof (C))) C (std::forward (args)...); + new_node->value.set (new_obj); + return new_node; + } [[nodiscard]] Node& getRootNode() noexcept { return root_node; } [[nodiscard]] const Node& getRootNode() const noexcept { return root_node; } + /** + * Reserves memory for some number of nodes. + * NOTE: this must be called while the tree is empty. + */ + void reserve (size_t num_nodes); + + /** + * Shrinks the tree's memory arena down to the reserved size. + * NOTE: this must be called while the tree is empty. + */ + void shrinkArena(); + protected: virtual void onDelete (const Node& /*nodeBeingDeleted*/) {} - ChainedArenaAllocator allocator { 64 * sizeof (Node) }; + ChainedArenaAllocator allocator {}; private: Node root_node {}; diff --git a/modules/common/chowdsp_data_structures/Structures/chowdsp_OptionalPointer.h b/modules/common/chowdsp_data_structures/Structures/chowdsp_OptionalPointer.h index ebbc4d506..fd4234245 100644 --- a/modules/common/chowdsp_data_structures/Structures/chowdsp_OptionalPointer.h +++ b/modules/common/chowdsp_data_structures/Structures/chowdsp_OptionalPointer.h @@ -23,16 +23,14 @@ struct OptionalPointer /** Creates an optional pointer from a raw pointer, and optionally taking ownership */ explicit OptionalPointer (T* ptr, bool shouldOwn = true) - : owningPtr (shouldOwn ? ptr : nullptr), - nonOwningPtr (shouldOwn ? owningPtr.get() : ptr) + : pointer (ptr, shouldOwn ? Owning : NonOwning) { } /** Creates an owning optional pointer */ template && std::is_base_of_v>)>> explicit OptionalPointer (Arg1&& arg1, Args&&... args) - : owningPtr (std::make_unique (std::forward (arg1), std::forward (args)...)), - nonOwningPtr (owningPtr.get()) + : pointer (new T { std::forward (arg1), std::forward (args)... }, Owning) // NOSONAR { } @@ -42,18 +40,18 @@ struct OptionalPointer */ void setOwning (T* ptr) { - owningPtr.reset (ptr); - nonOwningPtr = ptr; + invalidate(); + pointer.set (ptr, Owning); } /** * Sets OptionalPointer to point to a new pointer, and take ownership of it. * If the OptionalPointer previously owned some data, that data will be deleted. */ - void setOwning (std::unique_ptr&& ptr) + void setOwning (std::unique_ptr&& ptr) // NOSONAR { - owningPtr = std::move (ptr); - nonOwningPtr = owningPtr.get(); + invalidate(); + pointer.set (ptr.release(), Owning); } /** @@ -62,8 +60,7 @@ struct OptionalPointer */ void setNonOwning (T* ptr) { - owningPtr.reset(); - nonOwningPtr = ptr; + pointer.set (ptr, NonOwning); } /** Move constructor */ @@ -76,7 +73,7 @@ struct OptionalPointer OptionalPointer& operator= (const OptionalPointer&) = delete; /** Returns true if this pointer owns the data it's pointing to */ - [[nodiscard]] bool isOwner() const noexcept { return owningPtr != nullptr; } + [[nodiscard]] bool isOwner() const noexcept { return pointer.get_flags() == Owning; } /** * Releases ownership of the underlying data. @@ -87,7 +84,8 @@ struct OptionalPointer [[nodiscard]] T* release() { jassert (isOwner()); // Pointer has already been released! - return owningPtr.release(); + pointer.set_flags (NonOwning); + return pointer.get_ptr(); } /** @@ -97,22 +95,27 @@ struct OptionalPointer void invalidate() { if (isOwner()) - owningPtr.reset(); - nonOwningPtr = nullptr; + delete pointer.get_ptr(); // NOSONAR + pointer.set (nullptr); } - [[nodiscard]] T* get() { return nonOwningPtr; } - [[nodiscard]] const T* get() const { return nonOwningPtr; } + [[nodiscard]] T* get() { return pointer.get_ptr(); } + [[nodiscard]] const T* get() const { return pointer.get_ptr(); } - [[nodiscard]] operator T&() { return *nonOwningPtr; } // NOSONAR, NOLINT(google-explicit-constructor): we want to be able to do implicit conversion here - [[nodiscard]] T* operator->() { return nonOwningPtr; } - [[nodiscard]] const T* operator->() const { return nonOwningPtr; } - [[nodiscard]] T& operator*() { return *nonOwningPtr; } - [[nodiscard]] const T& operator*() const { return *nonOwningPtr; } + [[nodiscard]] operator T&() { return *pointer; } // NOSONAR, NOLINT(google-explicit-constructor): we want to be able to do implicit conversion here + [[nodiscard]] T* operator->() { return pointer.get_ptr(); } + [[nodiscard]] const T* operator->() const { return pointer.get_ptr(); } + [[nodiscard]] T& operator*() { return *pointer; } + [[nodiscard]] const T& operator*() const { return *pointer; } private: - std::unique_ptr owningPtr {}; - T* nonOwningPtr = nullptr; + enum : uint8_t + { + NonOwning = 0, + Owning = 1, + }; + + PackedPointer pointer {}; }; template diff --git a/modules/common/chowdsp_data_structures/Structures/chowdsp_PackedPointer.h b/modules/common/chowdsp_data_structures/Structures/chowdsp_PackedPointer.h new file mode 100644 index 000000000..7fcd2284f --- /dev/null +++ b/modules/common/chowdsp_data_structures/Structures/chowdsp_PackedPointer.h @@ -0,0 +1,119 @@ +#pragma once + +namespace chowdsp +{ +/** A pointer that can be "packed" together with some flags. */ +template +struct PackedPointer +{ + static_assert (alignof (T) >= 8, "PackedPointer implementation requires pointers that are aligned to 8 bytes or greater!"); + + static constexpr auto max_flag_value = alignof (T) - 1; + static constexpr auto address_mask = ~static_cast (max_flag_value); + static constexpr auto flags_mask = static_cast (max_flag_value); + + PackedPointer() = default; + + /** Initializes the pointer, optionally with some flags. */ + explicit PackedPointer (T* ptr, uint8_t flags = 0) + { + set (ptr, flags); + } + + /** Modifies both the pointer and the flags. */ + void set (T* ptr, uint8_t flags = 0) + { + jassert (flags <= max_flag_value); +#if JUCE_DEBUG + actual_ptr = ptr; +#endif + ptr_with_flags = reinterpret_cast ((reinterpret_cast (ptr) & address_mask) // NOSONAR + | (static_cast (flags) & flags_mask)); + } + + /** Modifies the flags without modifying the pointer. */ + void set_flags (uint8_t flags) + { + jassert (flags <= max_flag_value); + ptr_with_flags = reinterpret_cast ((reinterpret_cast (ptr_with_flags) & address_mask) // NOSONAR + | (static_cast (flags) & flags_mask)); + } + + /** Returns the pointer */ + [[nodiscard]] T* get_ptr() + { + return reinterpret_cast (reinterpret_cast (ptr_with_flags) & address_mask); // NOSONAR + } + + /** Returns the pointer */ + [[nodiscard]] const T* get_ptr() const + { + return reinterpret_cast (reinterpret_cast (ptr_with_flags) & address_mask); // NOSONAR + } + + /** Returns the flags */ + [[nodiscard]] uint8_t get_flags() const noexcept + { + return static_cast (reinterpret_cast (ptr_with_flags) & flags_mask); // NOSONAR + } + + [[nodiscard]] T* operator->() { return get_ptr(); } + [[nodiscard]] const T* operator->() const { return get_ptr(); } + [[nodiscard]] T& operator*() { return *get_ptr(); } + [[nodiscard]] const T& operator*() const { return *get_ptr(); } + +private: + T* ptr_with_flags = nullptr; +#if JUCE_DEBUG + [[maybe_unused]] T* actual_ptr = nullptr; +#endif +}; + +template +bool operator== (const PackedPointer& p1, T* other) +{ + return p1.get_ptr() == other; +} + +template +bool operator!= (const PackedPointer& p1, T* other) +{ + return p1.get_ptr() != other; +} + +template +bool operator== (T* other, const PackedPointer& p1) +{ + return p1.get_ptr() == other; +} + +template +bool operator!= (T* other, const PackedPointer& p1) +{ + return p1.get_ptr() != other; +} + +template +bool operator== (const PackedPointer& p1, std::nullptr_t) +{ + return p1.get_ptr() == nullptr; +} + +template +bool operator!= (const PackedPointer& p1, std::nullptr_t) +{ + return p1.get_ptr() != nullptr; +} + +template +bool operator== (std::nullptr_t, const PackedPointer& p2) +{ + return nullptr == p2.get_ptr(); +} + +template +bool operator!= (std::nullptr_t, const PackedPointer& p2) +{ + return nullptr != p2.get_ptr(); +} +} // namespace chowdsp diff --git a/modules/common/chowdsp_data_structures/chowdsp_data_structures.h b/modules/common/chowdsp_data_structures/chowdsp_data_structures.h index 02e9cccab..5690b77de 100644 --- a/modules/common/chowdsp_data_structures/chowdsp_data_structures.h +++ b/modules/common/chowdsp_data_structures/chowdsp_data_structures.h @@ -33,6 +33,7 @@ BEGIN_JUCE_MODULE_DECLARATION #include "Helpers/chowdsp_Iterators.h" #include "Structures/chowdsp_DoubleBuffer.h" +#include "Structures/chowdsp_PackedPointer.h" #include "Structures/chowdsp_DestructiblePointer.h" #include "Structures/chowdsp_RawObject.h" #include "Structures/chowdsp_LocalPointer.h" diff --git a/modules/plugin/chowdsp_presets_v2/Backend/chowdsp_PresetTree.cpp b/modules/plugin/chowdsp_presets_v2/Backend/chowdsp_PresetTree.cpp index 352736f45..3ec0590b1 100644 --- a/modules/plugin/chowdsp_presets_v2/Backend/chowdsp_PresetTree.cpp +++ b/modules/plugin/chowdsp_presets_v2/Backend/chowdsp_PresetTree.cpp @@ -19,11 +19,9 @@ namespace PresetTreeInserters PresetTree::Node& root, const PresetTree::InsertionHelper& insertionHelper) { - auto* item = tree.createEmptyNode(); - item->leaf = std::move (preset); - + auto* item = tree.createLeafNode (std::move (preset)); insertionHelper.insertNodeIntoTree (root, item); - return *item->leaf; + return item->value.leaf(); } template @@ -44,13 +42,12 @@ namespace PresetTreeInserters for (auto* iter = root.first_child; iter != nullptr; iter = iter->next_sibling) { - if (iter->tag == tag) + if (iter->value.tag() == tag) return fallbackInserter (std::move (preset), tree, *iter, insertionHelper); } // preset vendor is not currently in the tree, so let's add a new sub-tree - auto* subTree = tree.createEmptyNode(); - subTree->tag = tree.allocateTag (tag); + auto* subTree = tree.createTagNode (tag); insertionHelper.insertNodeIntoTree (root, subTree); return fallbackInserter (std::move (preset), tree, *subTree, insertionHelper); } @@ -115,16 +112,16 @@ PresetTree::PresetTree (PresetState* currentPresetState, InsertionHelper&& inser const auto comparator = [&tagComp = std::as_const (insertHelper.tagSortMethod), &presetComp = std::as_const (insertHelper.presetSortMethod)] (const Node& item1, const Node& item2) { - if (item1.leaf.has_value() && ! item2.leaf.has_value()) + if (item1.value.has_value() && ! item2.value.has_value()) return false; - if (! item1.leaf.has_value() && item2.leaf.has_value()) + if (! item1.value.has_value() && item2.value.has_value()) return true; - if (item1.leaf.has_value()) - return presetComp (*item1.leaf, *item2.leaf); + if (item1.value.has_value()) + return presetComp (item1.value.leaf(), item2.value.leaf()); - return tagComp (item1.tag, item2.tag); + return tagComp (item1.value.tag(), item2.value.tag()); }; insertNodeSorted (parent, newNode, comparator); }; @@ -140,8 +137,8 @@ void PresetTree::onDelete (const Node& nodeBeingDeleted) { if (presetState != nullptr && presetState->get() != nullptr - && nodeBeingDeleted.leaf.has_value() - && *presetState->get() == *nodeBeingDeleted.leaf) + && nodeBeingDeleted.value.has_value() + && *presetState->get() == nodeBeingDeleted.value.leaf()) presetState->assumeOwnership(); } } // namespace chowdsp::presets diff --git a/modules/plugin/chowdsp_presets_v2/Frontend/chowdsp_PresetsMenuInterface.cpp b/modules/plugin/chowdsp_presets_v2/Frontend/chowdsp_PresetsMenuInterface.cpp index ed292b17c..2348c0755 100644 --- a/modules/plugin/chowdsp_presets_v2/Frontend/chowdsp_PresetsMenuInterface.cpp +++ b/modules/plugin/chowdsp_presets_v2/Frontend/chowdsp_PresetsMenuInterface.cpp @@ -107,12 +107,12 @@ static void loadPresetsIntoMenu (juce::PopupMenu& menu, const PresetTree::Node& { for (auto* node = root.first_child; node != nullptr; node = node->next_sibling) { - if (node->leaf.has_value()) + if (node->value.has_value()) { juce::PopupMenu::Item menuItem; menuItem.itemID = -1; - menuItem.text = node->leaf->getName(); - menuItem.action = [&presetMgr, &preset = std::as_const (*node->leaf)] + menuItem.text = node->value.leaf().getName(); + menuItem.action = [&presetMgr, &preset = std::as_const (node->value.leaf())] { presetMgr.loadPreset (preset); }; @@ -123,7 +123,7 @@ static void loadPresetsIntoMenu (juce::PopupMenu& menu, const PresetTree::Node& juce::PopupMenu subMenu {}; loadPresetsIntoMenu (subMenu, *node, presetMgr); if (subMenu.containsAnyActiveItems()) - menu.addSubMenu (toString (node->tag), subMenu); + menu.addSubMenu (toString (node->value.tag()), subMenu); } } } diff --git a/modules/plugin/chowdsp_presets_v2/Frontend/chowdsp_PresetsNextPreviousInterface.cpp b/modules/plugin/chowdsp_presets_v2/Frontend/chowdsp_PresetsNextPreviousInterface.cpp index 4f539e96c..0f90749bc 100644 --- a/modules/plugin/chowdsp_presets_v2/Frontend/chowdsp_PresetsNextPreviousInterface.cpp +++ b/modules/plugin/chowdsp_presets_v2/Frontend/chowdsp_PresetsNextPreviousInterface.cpp @@ -10,7 +10,7 @@ static const PresetTree::Node* findNodeForPreset (const PresetTree::Node& root, { for (auto* node = &root; node != nullptr; node = node->next_linear) { - if (node->leaf.has_value() && *node->leaf == current) + if (node->value.has_value() && node->value.leaf() == current) return node; } return nullptr; @@ -28,7 +28,7 @@ static const PresetTree::Node* getNextOrPreviousPresetNode (const PresetTree::No auto* nextParent = getNextOrPreviousPresetNode (node->parent, forward); if (nextParent == nullptr) return nullptr; - if (nextParent->leaf.has_value()) + if (nextParent->value.has_value()) return nextParent; return forward ? nextParent->first_child : nextParent->last_child; @@ -54,10 +54,10 @@ bool NextPrevious::navigateThroughPresets (bool forward) nextPresetNode = &presetTree.getRootNode(); } - while (! nextPresetNode->leaf.has_value()) + while (! nextPresetNode->value.has_value()) nextPresetNode = forward ? nextPresetNode->first_child : nextPresetNode->last_child; - presetManager.loadPreset (*nextPresetNode->leaf); + presetManager.loadPreset (nextPresetNode->value.leaf()); return true; } diff --git a/tests/common_tests/chowdsp_data_structures_test/AbstractTreeTest.cpp b/tests/common_tests/chowdsp_data_structures_test/AbstractTreeTest.cpp index 0a723f040..35fb4b3e8 100644 --- a/tests/common_tests/chowdsp_data_structures_test/AbstractTreeTest.cpp +++ b/tests/common_tests/chowdsp_data_structures_test/AbstractTreeTest.cpp @@ -3,13 +3,14 @@ struct StringTree : chowdsp::AbstractTree { + using AbstractTree::AbstractTree; + static Node& insert_string (std::string&& element, Node& parent_node, AbstractTree& tree) { - auto* new_node = tree.createEmptyNode(); - new_node->leaf = std::move (element); + auto* new_node = tree.createLeafNode (std::move (element)); insertNodeSorted (parent_node, new_node, [] (const Node& el1, const Node& el2) - { return *el1.leaf < *el2.leaf; }); + { return el1.value.leaf() < el2.value.leaf(); }); return *new_node; } @@ -17,15 +18,19 @@ struct StringTree : chowdsp::AbstractTree { for (auto* iter = root.first_child; iter != nullptr; iter = iter->next_sibling) { - if (iter->tag == std::string_view { element.data(), 1 }) - return *insert_string (std::move (element), *iter, self).leaf; + if (iter->value.tag() == std::string_view { element.data(), 1 }) + return insert_string (std::move (element), *iter, self).value.leaf(); } - auto* new_sub_tree = self.createEmptyNode(); - new_sub_tree->tag = self.allocateTag ({ element.data(), 1 }); + auto* new_sub_tree = self.createTagNode ({ element.data(), 1 }); insertNodeSorted (root, new_sub_tree, [] (const Node& el1, const Node& el2) - { return el1.tag < el2.tag; }); - return *insert_string (std::move (element), *new_sub_tree, self).leaf; + { return el1.value.tag() < el2.value.tag(); }); + return insert_string (std::move (element), *new_sub_tree, self).value.leaf(); + } + + auto& get_allocator() + { + return allocator; } }; @@ -33,7 +38,7 @@ TEST_CASE ("Abstract Tree Test", "[common][data-structures]") { const std::vector foods { "alfalfa", "apples", "beets", "donuts" }; - StringTree tree; + StringTree tree { 7 }; tree.insertElements (std::vector { foods }); REQUIRE (tree.size() == 4); @@ -45,15 +50,19 @@ TEST_CASE ("Abstract Tree Test", "[common][data-structures]") SECTION ("Insertion") { + REQUIRE (tree.get_allocator().get_arena_count() == 1); + tree.reserve (6); // should jassert! + REQUIRE (tree.get_allocator().get_arena_count() == 1); + tree.insertElement ("almonds"); REQUIRE (tree.size() == 5); { const auto* a_node = tree.getRootNode().first_child; - REQUIRE (a_node->tag == "a"); - REQUIRE (a_node->first_child->leaf == "alfalfa"); - REQUIRE (a_node->first_child->next_sibling->leaf == "almonds"); - REQUIRE (a_node->first_child->next_sibling->next_sibling->leaf == "apples"); + REQUIRE (a_node->value.tag() == "a"); + REQUIRE (a_node->first_child->value.leaf() == "alfalfa"); + REQUIRE (a_node->first_child->next_sibling->value.leaf() == "almonds"); + REQUIRE (a_node->first_child->next_sibling->next_sibling->value.leaf() == "apples"); } tree.insertElement ("acai"); @@ -61,12 +70,20 @@ TEST_CASE ("Abstract Tree Test", "[common][data-structures]") { const auto* a_node = tree.getRootNode().first_child; - REQUIRE (a_node->tag == "a"); - REQUIRE (a_node->first_child->leaf == "acai"); - REQUIRE (a_node->first_child->next_sibling->leaf == "alfalfa"); - REQUIRE (a_node->first_child->next_sibling->next_sibling->leaf == "almonds"); - REQUIRE (a_node->first_child->next_sibling->next_sibling->next_sibling->leaf == "apples"); + REQUIRE (a_node->value.tag() == "a"); + REQUIRE (a_node->first_child->value.leaf() == "acai"); + REQUIRE (a_node->first_child->next_sibling->value.leaf() == "alfalfa"); + REQUIRE (a_node->first_child->next_sibling->next_sibling->value.leaf() == "almonds"); + REQUIRE (a_node->first_child->next_sibling->next_sibling->next_sibling->value.leaf() == "apples"); } + + REQUIRE (tree.get_allocator().get_arena_count() == 2); + tree.shrinkArena(); // should jassert! + REQUIRE (tree.get_allocator().get_arena_count() == 2); + tree.clear(); + REQUIRE (tree.get_allocator().get_arena_count() == 2); + tree.shrinkArena(); + REQUIRE (tree.get_allocator().get_arena_count() == 1); } SECTION ("Remove One") @@ -75,7 +92,7 @@ TEST_CASE ("Abstract Tree Test", "[common][data-structures]") REQUIRE (tree.size() == 3); const auto* d_node = tree.getRootNode().first_child->next_sibling; - REQUIRE (d_node->tag == "d"); + REQUIRE (d_node->value.tag() == "d"); } SECTION ("Remove From Start of Sub-Tree") @@ -84,7 +101,7 @@ TEST_CASE ("Abstract Tree Test", "[common][data-structures]") REQUIRE (tree.size() == 3); const auto* a_node = tree.getRootNode().first_child; - REQUIRE (a_node->first_child->leaf == "apples"); + REQUIRE (a_node->first_child->value.leaf() == "apples"); } SECTION ("Remove From End of Sub-Tree") @@ -93,7 +110,7 @@ TEST_CASE ("Abstract Tree Test", "[common][data-structures]") REQUIRE (tree.size() == 3); const auto* a_node = tree.getRootNode().first_child; - REQUIRE (a_node->last_child->leaf == "alfalfa"); + REQUIRE (a_node->first_child->value.leaf() == "alfalfa"); } SECTION ("Remove Last Node in Sub-Tree") @@ -102,7 +119,7 @@ TEST_CASE ("Abstract Tree Test", "[common][data-structures]") REQUIRE (tree.size() == 3); const auto* b_node = tree.getRootNode().last_child; - REQUIRE (b_node->tag == "b"); + REQUIRE (b_node->value.tag() == "b"); } SECTION ("Remove Multiple") @@ -112,7 +129,7 @@ TEST_CASE ("Abstract Tree Test", "[common][data-structures]") REQUIRE (tree.size() == 2); REQUIRE (tree.getRootNode().first_child == tree.getRootNode().last_child); - REQUIRE (tree.getRootNode().first_child->tag == "a"); + REQUIRE (tree.getRootNode().first_child->value.tag() == "a"); } SECTION ("Remove All") @@ -123,8 +140,8 @@ TEST_CASE ("Abstract Tree Test", "[common][data-structures]") tree.insertElement ("mussels"); REQUIRE (tree.size() == 1); - REQUIRE (tree.getRootNode().first_child->tag == "m"); - REQUIRE (tree.getRootNode().first_child->first_child->leaf == "mussels"); + REQUIRE (tree.getRootNode().first_child->value.tag() == "m"); + REQUIRE (tree.getRootNode().first_child->first_child->value.leaf() == "mussels"); auto found = tree.findElement ("mussels"); REQUIRE (found); diff --git a/tests/common_tests/chowdsp_data_structures_test/CMakeLists.txt b/tests/common_tests/chowdsp_data_structures_test/CMakeLists.txt index b007a8f0c..7abee29f2 100644 --- a/tests/common_tests/chowdsp_data_structures_test/CMakeLists.txt +++ b/tests/common_tests/chowdsp_data_structures_test/CMakeLists.txt @@ -22,6 +22,7 @@ target_sources(chowdsp_data_structures_test OptionalRefTest.cpp OptionalArrayTest.cpp PoolAllocatorTest.cpp + PackedPointerTest.cpp ) target_compile_features(chowdsp_data_structures_test PRIVATE cxx_std_20) diff --git a/tests/common_tests/chowdsp_data_structures_test/OptionalPointerTest.cpp b/tests/common_tests/chowdsp_data_structures_test/OptionalPointerTest.cpp index 61355dfc2..72e2741fd 100644 --- a/tests/common_tests/chowdsp_data_structures_test/OptionalPointerTest.cpp +++ b/tests/common_tests/chowdsp_data_structures_test/OptionalPointerTest.cpp @@ -3,7 +3,7 @@ TEST_CASE ("Optional Pointer Test", "[common][data-structures]") { - struct TestType + struct alignas (8) TestType { TestType (int _x, int _y) : x (_x), y (_y) {} int x; diff --git a/tests/common_tests/chowdsp_data_structures_test/PackedPointerTest.cpp b/tests/common_tests/chowdsp_data_structures_test/PackedPointerTest.cpp new file mode 100644 index 000000000..1972a2ddd --- /dev/null +++ b/tests/common_tests/chowdsp_data_structures_test/PackedPointerTest.cpp @@ -0,0 +1,53 @@ +#include +#include + +TEST_CASE ("Packed Pointer Test", "[common][data-structures]") +{ + struct alignas (8) TestType + { + TestType (int _x, int _y) : x (_x), y (_y) {} + int x; + int y; + }; + + TestType t1 { 4, 5 }; + TestType t2 { 6, 7 }; + + SECTION ("Null Init") + { + chowdsp::PackedPointer ptr {}; + REQUIRE (ptr == nullptr); + REQUIRE (nullptr == ptr); + REQUIRE (ptr != &t2); + REQUIRE (&t2 != ptr); + } + + SECTION ("Init No Flags") + { + chowdsp::PackedPointer ptr { &t1 }; + REQUIRE (ptr == &t1); + REQUIRE (ptr != nullptr); + REQUIRE (ptr.get_flags() == 0); + } + + SECTION ("Flags") + { + chowdsp::PackedPointer ptr { &t1, 5 }; + REQUIRE (ptr == &t1); + REQUIRE (nullptr != ptr); + REQUIRE (ptr.get_flags() == 5); + REQUIRE ((*ptr).x == t1.x); + + ptr.set_flags (7); + REQUIRE (&t1 == ptr); + REQUIRE (ptr.get_flags() == 7); + REQUIRE ((*std::as_const (ptr)).y == t1.y); + } + + SECTION ("Modify") + { + chowdsp::PackedPointer ptr { &t1, 5 }; + ptr->x = 100; + REQUIRE (std::as_const (ptr)->x == t1.x); + } +} diff --git a/tests/plugin_tests/chowdsp_presets_v2_test/ClipboardInterfaceTest.cpp b/tests/plugin_tests/chowdsp_presets_v2_test/ClipboardInterfaceTest.cpp index 516fc9db9..10236078e 100644 --- a/tests/plugin_tests/chowdsp_presets_v2_test/ClipboardInterfaceTest.cpp +++ b/tests/plugin_tests/chowdsp_presets_v2_test/ClipboardInterfaceTest.cpp @@ -24,13 +24,13 @@ TEST_CASE ("Clipboard Interface Test", "[plugin][presets]") SECTION ("Copy/Paste") { - presetMgr.loadPreset (*presetMgr.getPresetTree().getRootNode().first_child->leaf); + presetMgr.loadPreset (presetMgr.getPresetTree().getRootNode().first_child->value.leaf()); REQUIRE (juce::approximatelyEqual (state.params.floatParam->get(), val1)); chowdsp::presets::frontend::ClipboardInterface clipInterface { presetMgr }; clipInterface.copyCurrentPreset(); - presetMgr.loadPreset (*presetMgr.getPresetTree().getRootNode().first_child->next_sibling->leaf); + presetMgr.loadPreset (presetMgr.getPresetTree().getRootNode().first_child->next_sibling->value.leaf()); REQUIRE (juce::approximatelyEqual (state.params.floatParam->get(), val2)); REQUIRE (clipInterface.tryToPastePreset()); @@ -40,7 +40,7 @@ TEST_CASE ("Clipboard Interface Test", "[plugin][presets]") SECTION ("Empty Paste") { chowdsp::presets::frontend::ClipboardInterface clipInterface { presetMgr }; - presetMgr.loadPreset (*presetMgr.getPresetTree().getRootNode().first_child->leaf); + presetMgr.loadPreset (presetMgr.getPresetTree().getRootNode().first_child->value.leaf()); juce::SystemClipboard::copyTextToClipboard ({}); @@ -52,7 +52,7 @@ TEST_CASE ("Clipboard Interface Test", "[plugin][presets]") SECTION ("Invalid Preset Paste") { chowdsp::presets::frontend::ClipboardInterface clipInterface { presetMgr }; - presetMgr.loadPreset (*presetMgr.getPresetTree().getRootNode().first_child->leaf); + presetMgr.loadPreset (presetMgr.getPresetTree().getRootNode().first_child->value.leaf()); chowdsp::presets::Preset invalid { "Preset1", "", { { "float", val2 } } }; juce::SystemClipboard::copyTextToClipboard (invalid.toJson().dump()); diff --git a/tests/plugin_tests/chowdsp_presets_v2_test/NextPreviousTest.cpp b/tests/plugin_tests/chowdsp_presets_v2_test/NextPreviousTest.cpp index 18782dba6..41b588439 100644 --- a/tests/plugin_tests/chowdsp_presets_v2_test/NextPreviousTest.cpp +++ b/tests/plugin_tests/chowdsp_presets_v2_test/NextPreviousTest.cpp @@ -59,7 +59,7 @@ TEST_CASE ("Next/Previous Test", "[plugin][presets]") nextPrev.setShouldWrapAtEndOfList (false); REQUIRE (nextPrev.willWrapAtEndOFList() == false); - presetMgr.loadPreset (*presetMgr.getPresetTree().getRootNode().first_child->leaf); + presetMgr.loadPreset (presetMgr.getPresetTree().getRootNode().first_child->value.leaf()); checkPresetIndex (presetMgr, 0); REQUIRE (nextPrev.goToPreviousPreset() == false); @@ -100,7 +100,7 @@ TEST_CASE ("Next/Previous Test", "[plugin][presets]") nextPrev.setShouldWrapAtEndOfList (true); REQUIRE (nextPrev.willWrapAtEndOFList() == true); - presetMgr.loadPreset (*presetMgr.getPresetTree().getRootNode().first_child->first_child->leaf); + presetMgr.loadPreset (presetMgr.getPresetTree().getRootNode().first_child->first_child->value.leaf()); checkPresetIndex (presetMgr, 0); REQUIRE (nextPrev.goToNextPreset() == true); diff --git a/tests/plugin_tests/chowdsp_presets_v2_test/PresetManagerTest.cpp b/tests/plugin_tests/chowdsp_presets_v2_test/PresetManagerTest.cpp index 8dcc02a34..21db6f62c 100644 --- a/tests/plugin_tests/chowdsp_presets_v2_test/PresetManagerTest.cpp +++ b/tests/plugin_tests/chowdsp_presets_v2_test/PresetManagerTest.cpp @@ -92,7 +92,7 @@ TEST_CASE ("Preset Manager Test", "[plugin][presets][state]") presetMgr.setFloatParam (dummyValue); REQUIRE_MESSAGE (juce::approximatelyEqual (presetMgr.getFloatParam(), dummyValue), "Changed value is incorrect!"); - presetMgr->loadPreset (*presetMgr->getPresetTree().getRootNode().first_child->leaf); + presetMgr->loadPreset (presetMgr->getPresetTree().getRootNode().first_child->value.leaf()); REQUIRE_MESSAGE (juce::approximatelyEqual (presetMgr.getFloatParam(), testValue), "Preset value is incorrect!"); } @@ -103,7 +103,7 @@ TEST_CASE ("Preset Manager Test", "[plugin][presets][state]") ScopedPresetManager presetMgr {}; presetMgr->addPresets ({ preset }); - presetMgr->loadPreset (*presetMgr->getPresetTree().getRootNode().first_child->leaf); + presetMgr->loadPreset (presetMgr->getPresetTree().getRootNode().first_child->value.leaf()); REQUIRE_MESSAGE (juce::approximatelyEqual (presetMgr.getFloatParam(), testValue), "Preset value is incorrect!"); } @@ -119,7 +119,7 @@ TEST_CASE ("Preset Manager Test", "[plugin][presets][state]") presetMgr.toggleBoolParam(); REQUIRE_MESSAGE (! presetMgr.state.params.boolParam->get(), "Value after toggle incorrect!"); - presetMgr->loadPreset (*presetMgr->getPresetTree().getRootNode().first_child->leaf); + presetMgr->loadPreset (presetMgr->getPresetTree().getRootNode().first_child->value.leaf()); REQUIRE_MESSAGE (! presetMgr.state.params.boolParam->get(), "Value after preset load incorrect!"); } @@ -140,7 +140,7 @@ TEST_CASE ("Preset Manager Test", "[plugin][presets][state]") REQUIRE_MESSAGE (presetMgr->getIsPresetDirty(), "Preset dirty after set value is incorrect!"); presetMgr->addPresets ({ preset }); - presetMgr->loadPreset (*presetMgr->getPresetTree().getRootNode().first_child->leaf); + presetMgr->loadPreset (presetMgr->getPresetTree().getRootNode().first_child->value.leaf()); REQUIRE_MESSAGE (juce::approximatelyEqual (presetMgr.state.params.extraParam->get(), defaultValue), "Reset value is incorrect!"); } @@ -251,7 +251,7 @@ TEST_CASE ("Preset Manager Test", "[plugin][presets][state]") { ScopedPresetManager presetMgr {}; presetMgr->addPresets ({ chowdsp::presets::Preset { preset } }); - presetMgr->loadPreset (*presetMgr->getPresetTree().getRootNode().first_child->leaf); + presetMgr->loadPreset (presetMgr->getPresetTree().getRootNode().first_child->value.leaf()); REQUIRE (juce::approximatelyEqual (presetMgr.getFloatParam(), testValue)); presetMgr.setFloatParam (otherValue); @@ -280,14 +280,14 @@ TEST_CASE ("Preset Manager Test", "[plugin][presets][state]") presetMgr.state.undoManager = &um; presetMgr->addPresets ({ chowdsp::presets::Preset { preset }, chowdsp::presets::Preset { preset2 } }); - presetMgr->loadPreset (*presetMgr->getPresetTree().getRootNode().first_child->leaf); + presetMgr->loadPreset (presetMgr->getPresetTree().getRootNode().first_child->value.leaf()); REQUIRE (juce::approximatelyEqual (presetMgr.getFloatParam(), testValue)); presetMgr.setFloatParam (dirtyVal); REQUIRE (juce::approximatelyEqual (presetMgr.getFloatParam(), dirtyVal)); REQUIRE (presetMgr->getIsPresetDirty()); - presetMgr->loadPreset (*presetMgr->getPresetTree().getRootNode().first_child->next_sibling->leaf); + presetMgr->loadPreset (presetMgr->getPresetTree().getRootNode().first_child->next_sibling->value.leaf()); REQUIRE (juce::approximatelyEqual (presetMgr.getFloatParam(), testValue2)); REQUIRE (! presetMgr->getIsPresetDirty()); diff --git a/tests/plugin_tests/chowdsp_presets_v2_test/PresetTreeTest.cpp b/tests/plugin_tests/chowdsp_presets_v2_test/PresetTreeTest.cpp index 2c8327cdc..299e44c63 100644 --- a/tests/plugin_tests/chowdsp_presets_v2_test/PresetTreeTest.cpp +++ b/tests/plugin_tests/chowdsp_presets_v2_test/PresetTreeTest.cpp @@ -28,7 +28,7 @@ TEST_CASE ("Preset Tree Test", "[plugin][presets]") const auto* iter = root.first_child; for (const auto& name : preset_names_sorted) { - REQUIRE (iter->leaf->getName() == name); + REQUIRE (iter->value.leaf().getName() == name); iter = iter->next_sibling; } REQUIRE (iter == nullptr); @@ -48,19 +48,19 @@ TEST_CASE ("Preset Tree Test", "[plugin][presets]") const auto& root = preset_tree.getRootNode(); const auto* bob_node = root.first_child; - REQUIRE (bob_node->tag == "Bob"); - REQUIRE (bob_node->first_child->leaf->getName() == "Preset2"); + REQUIRE (bob_node->value.tag() == "Bob"); + REQUIRE (bob_node->first_child->value.leaf().getName() == "Preset2"); REQUIRE (bob_node->first_child->next_sibling == nullptr); const auto* jatin_node = bob_node->next_sibling; - REQUIRE (jatin_node->tag == "Jatin"); - REQUIRE (jatin_node->first_child->leaf->getName() == "Preset1"); - REQUIRE (jatin_node->first_child->next_sibling->leaf->getName() == "ZZZZ"); + REQUIRE (jatin_node->value.tag() == "Jatin"); + REQUIRE (jatin_node->first_child->value.leaf().getName() == "Preset1"); + REQUIRE (jatin_node->first_child->next_sibling->value.leaf().getName() == "ZZZZ"); REQUIRE (jatin_node->first_child->next_sibling->next_sibling == nullptr); const auto* livey_node = jatin_node->next_sibling; - REQUIRE (livey_node->tag == "Livey"); - REQUIRE (livey_node->first_child->leaf->getName() == "ABCD"); + REQUIRE (livey_node->value.tag() == "Livey"); + REQUIRE (livey_node->first_child->value.leaf().getName() == "ABCD"); REQUIRE (livey_node->first_child->next_sibling == nullptr); } @@ -78,19 +78,19 @@ TEST_CASE ("Preset Tree Test", "[plugin][presets]") const auto& root = preset_tree.getRootNode(); const auto* bass_node = root.first_child; - REQUIRE (bass_node->tag == "Bass"); - REQUIRE (bass_node->first_child->leaf->getName() == "ZZZZ"); + REQUIRE (bass_node->value.tag() == "Bass"); + REQUIRE (bass_node->first_child->value.leaf().getName() == "ZZZZ"); REQUIRE (bass_node->first_child->next_sibling == nullptr); const auto* drums_node = bass_node->next_sibling; - REQUIRE (drums_node->tag == "Drums"); - REQUIRE (drums_node->first_child->leaf->getName() == "ABCD"); - REQUIRE (drums_node->first_child->next_sibling->leaf->getName() == "Preset2"); + REQUIRE (drums_node->value.tag() == "Drums"); + REQUIRE (drums_node->first_child->value.leaf().getName() == "ABCD"); + REQUIRE (drums_node->first_child->next_sibling->value.leaf().getName() == "Preset2"); REQUIRE (drums_node->first_child->next_sibling->next_sibling == nullptr); const auto* loose_preset = drums_node->next_sibling; REQUIRE (loose_preset == root.last_child); - REQUIRE (loose_preset->leaf->getName() == "Preset1"); + REQUIRE (loose_preset->value.leaf().getName() == "Preset1"); } SECTION ("Vendor/Category Insertion Test") @@ -112,30 +112,30 @@ TEST_CASE ("Preset Tree Test", "[plugin][presets]") const auto& root = preset_tree.getRootNode(); const auto* jatin_node = root.first_child; - REQUIRE (jatin_node->tag == "Jatin"); + REQUIRE (jatin_node->value.tag() == "Jatin"); const auto* jatin_bass_node = jatin_node->first_child; - REQUIRE (jatin_bass_node->tag == "Bass"); - REQUIRE (jatin_bass_node->first_child->leaf->getName() == "Bass1"); - REQUIRE (jatin_bass_node->first_child->next_sibling->leaf->getName() == "Bass2"); + REQUIRE (jatin_bass_node->value.tag() == "Bass"); + REQUIRE (jatin_bass_node->first_child->value.leaf().getName() == "Bass1"); + REQUIRE (jatin_bass_node->first_child->next_sibling->value.leaf().getName() == "Bass2"); REQUIRE (jatin_bass_node->first_child->next_sibling->next_sibling == nullptr); const auto* jatin_drums_node = jatin_bass_node->next_sibling; - REQUIRE (jatin_drums_node->tag == "Drums"); - REQUIRE (jatin_drums_node->first_child->leaf->getName() == "Drums1"); + REQUIRE (jatin_drums_node->value.tag() == "Drums"); + REQUIRE (jatin_drums_node->first_child->value.leaf().getName() == "Drums1"); REQUIRE (jatin_drums_node->first_child->next_sibling == nullptr); const auto* jatin_loose_preset = jatin_drums_node->next_sibling; REQUIRE (jatin_loose_preset == jatin_node->last_child); - REQUIRE (jatin_loose_preset->leaf->getName() == "Blah"); + REQUIRE (jatin_loose_preset->value.leaf().getName() == "Blah"); const auto* steve_node = jatin_node->next_sibling; - REQUIRE (steve_node->tag == "Steve"); + REQUIRE (steve_node->value.tag() == "Steve"); const auto* steve_gtr_node = steve_node->first_child; - REQUIRE (steve_gtr_node->tag == "Gtr"); - REQUIRE (steve_gtr_node->first_child->leaf->getName() == "Gtr1"); - REQUIRE (steve_gtr_node->first_child->next_sibling->leaf->getName() == "Gtr2"); + REQUIRE (steve_gtr_node->value.tag() == "Gtr"); + REQUIRE (steve_gtr_node->first_child->value.leaf().getName() == "Gtr1"); + REQUIRE (steve_gtr_node->first_child->next_sibling->value.leaf().getName() == "Gtr2"); REQUIRE (steve_gtr_node->first_child->next_sibling->next_sibling == nullptr); } @@ -187,14 +187,14 @@ TEST_CASE ("Preset Tree Test", "[plugin][presets]") REQUIRE (preset_tree.size() == 2); const auto* bass_node = preset_tree.getRootNode().first_child->first_child; - REQUIRE (bass_node->tag == "Bass"); + REQUIRE (bass_node->value.tag() == "Bass"); - REQUIRE (bass_node->first_child->leaf->getName() == "Bass1"); - REQUIRE (bass_node->first_child->next_sibling->leaf->getName() == "Bass2"); + REQUIRE (bass_node->first_child->value.leaf().getName() == "Bass1"); + REQUIRE (bass_node->first_child->next_sibling->value.leaf().getName() == "Bass2"); preset_tree.removeElement (preset2); REQUIRE (preset_tree.size() == 1); - REQUIRE (bass_node->first_child->leaf->getName() == "Bass1"); + REQUIRE (bass_node->first_child->value.leaf().getName() == "Bass1"); REQUIRE (bass_node->first_child->next_sibling == nullptr); } @@ -243,7 +243,7 @@ TEST_CASE ("Preset Tree Test", "[plugin][presets]") chowdsp::presets::PresetTree preset_tree { &state }; preset_tree.insertElement (chowdsp::presets::Preset { preset }); - state = *preset_tree.getRootNode().first_child->leaf; + state = preset_tree.getRootNode().first_child->value.leaf(); REQUIRE (*state.get() == preset); preset_tree.removeElement (preset); diff --git a/tests/plugin_tests/chowdsp_presets_v2_test/ProgramAdapterTest.cpp b/tests/plugin_tests/chowdsp_presets_v2_test/ProgramAdapterTest.cpp index 8938cf444..044d02099 100644 --- a/tests/plugin_tests/chowdsp_presets_v2_test/ProgramAdapterTest.cpp +++ b/tests/plugin_tests/chowdsp_presets_v2_test/ProgramAdapterTest.cpp @@ -63,13 +63,13 @@ TEST_CASE ("Program Adapter Test", "[plugin][presets]") chowdsp::presets::Preset { "B", "Vendor", { { "value", 1 } } }, chowdsp::presets::Preset { "C", "Vendor", { { "value", 2 } } } }); - presetMgr->loadPreset (*presetMgr->getPresetTree().getRootNode().first_child->leaf); + presetMgr->loadPreset (presetMgr->getPresetTree().getRootNode().first_child->value.leaf()); REQUIRE (adapter.getCurrentProgram() == 0); - presetMgr->loadPreset (*presetMgr->getPresetTree().getRootNode().first_child->next_sibling->leaf); + presetMgr->loadPreset (presetMgr->getPresetTree().getRootNode().first_child->next_sibling->value.leaf()); REQUIRE (adapter.getCurrentProgram() == 1); - presetMgr->loadPreset (*presetMgr->getPresetTree().getRootNode().first_child->next_sibling->next_sibling->leaf); + presetMgr->loadPreset (presetMgr->getPresetTree().getRootNode().first_child->next_sibling->next_sibling->value.leaf()); REQUIRE (adapter.getCurrentProgram() == 2); } diff --git a/tests/plugin_tests/chowdsp_presets_v2_test/TextInterfaceTest.cpp b/tests/plugin_tests/chowdsp_presets_v2_test/TextInterfaceTest.cpp index cd7de53f6..4b2c8f032 100644 --- a/tests/plugin_tests/chowdsp_presets_v2_test/TextInterfaceTest.cpp +++ b/tests/plugin_tests/chowdsp_presets_v2_test/TextInterfaceTest.cpp @@ -19,17 +19,17 @@ TEST_CASE ("Text Interface Test", "[plugin][presets]") SECTION ("Preset Change") { - presetMgr.loadPreset (*presetMgr.getPresetTree().getRootNode().first_child->leaf); + presetMgr.loadPreset (presetMgr.getPresetTree().getRootNode().first_child->value.leaf()); chowdsp::presets::frontend::TextInterface textInterface { presetMgr }; REQUIRE (textInterface.getPresetText() == "Preset0"); - presetMgr.loadPreset (*presetMgr.getPresetTree().getRootNode().first_child->next_sibling->leaf); + presetMgr.loadPreset (presetMgr.getPresetTree().getRootNode().first_child->next_sibling->value.leaf()); REQUIRE (textInterface.getPresetText() == "Preset1"); } SECTION ("Preset Dirty Change") { - presetMgr.loadPreset (*presetMgr.getPresetTree().getRootNode().first_child->leaf); + presetMgr.loadPreset (presetMgr.getPresetTree().getRootNode().first_child->value.leaf()); chowdsp::presets::frontend::TextInterface textInterface { presetMgr }; REQUIRE (textInterface.getPresetText() == "Preset0"); @@ -37,7 +37,7 @@ TEST_CASE ("Text Interface Test", "[plugin][presets]") state.getParameterListeners().updateBroadcastersFromMessageThread(); REQUIRE (textInterface.getPresetText() == "Preset0*"); - presetMgr.loadPreset (*presetMgr.getPresetTree().getRootNode().first_child->next_sibling->leaf); + presetMgr.loadPreset (presetMgr.getPresetTree().getRootNode().first_child->next_sibling->value.leaf()); REQUIRE (textInterface.getPresetText() == "Preset1"); } }