Skip to content

Commit

Permalink
Updates for StringLiteral and StateValue (#468)
Browse files Browse the repository at this point in the history
* Updates for StringLiteral and StateValue

* Apply clang-format

---------

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
  • Loading branch information
jatinchowdhury18 and github-actions[bot] authored Nov 11, 2023
1 parent ced67ec commit f930081
Show file tree
Hide file tree
Showing 7 changed files with 73 additions and 26 deletions.
18 changes: 18 additions & 0 deletions modules/common/chowdsp_core/Types/chowdsp_TypeTraits.h
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,24 @@ namespace TypeTraits

} // namespace TypeTraits

/** Return true if the complete type is a specialization of the outer type */
template <typename CompleteType, template <typename...> class OuterType>
struct is_specialization_of;

template <typename CompleteType, template <typename...> class OuterType>
struct is_specialization_of final : std::false_type
{
};

template <template <typename...> class OuterType, typename... TypeArgs>
struct is_specialization_of<OuterType<TypeArgs...>, OuterType> final : std::true_type
{
};

/** Return true if the complete type is a specialization of the outer type */
template <typename CompleteType, template <typename...> class OuterType>
static constexpr bool is_specialization_of_v = is_specialization_of<CompleteType, OuterType>::value;

/**
* An empty struct intended to be used with std::conditional_t
* to effectively "disable" some member of a struct/class.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -189,5 +189,5 @@ struct IsOptionalPointerType<OptionalPointer<T>> : std::true_type

/** True if the type is a chowdsp::OptionalPointer<T> */
template <typename T>
static constexpr bool IsOptionalPointer = IsOptionalPointerType<T>::value;
static constexpr bool IsOptionalPointer = is_specialization_of_v<T, OptionalPointer>;
} // namespace chowdsp
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,19 @@ namespace sl_detail
return d_first;
}
#endif

/** Counts the string length needed to contain a number. */
template <typename Int>
size_t num_str_len (Int number)
{
size_t digits = (number > 0) ? 0 : 1;
while (number)
{
number /= 10;
digits++;
}
return digits;
}
} // namespace sl_detail
#endif

Expand Down Expand Up @@ -57,6 +70,23 @@ struct StringLiteral
}

[[nodiscard]] constexpr std::string_view toStringView() const { return { data(), size() }; }

template <typename IntType, typename = typename std::enable_if_t<std::is_integral_v<IntType>>>
constexpr explicit StringLiteral (IntType int_value)
: actual_size (sl_detail::num_str_len (int_value))
{
// N is not large enough to hold this number!
jassert (N >= actual_size);

// temporary copy so we don't have to leave room for the null terminator added by snprintf
std::array<char, N + 1> temp_str;
if constexpr (std::is_signed_v<IntType>)
std::snprintf (temp_str.data(), temp_str.size(), "%lld", static_cast<int64_t> (int_value));
else
std::snprintf (temp_str.data(), temp_str.size(), "%llu", static_cast<uint64_t> (int_value));

sl_detail::copy (temp_str.begin(), temp_str.begin() + actual_size, chars.begin());
}
constexpr operator std::string_view() const { return toStringView(); } // NOSONAR NOLINT(google-explicit-constructor)
[[nodiscard]] std::string toString() const { return { data(), size() }; }
operator std::string() const { return toString(); } // NOSONAR NOLINT(google-explicit-constructor)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,18 +61,8 @@ class BaseSerializer
static constexpr auto IsString = std::is_same_v<T, std::string> || std::is_same_v<T, juce::String>;

#if JUCE_MODULE_AVAILABLE_juce_graphics
template <class T>
struct IsJucePointType : std::false_type
{
};

template <class T>
struct IsJucePointType<juce::Point<T>> : std::true_type
{
};

template <typename T>
static constexpr auto IsPoint = IsJucePointType<T>::value;
static constexpr auto IsPoint = is_specialization_of_v<T, juce::Point>;
#endif

template <typename T>
Expand Down
25 changes: 13 additions & 12 deletions modules/plugin/chowdsp_plugin_state/Backend/chowdsp_StateValue.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,34 +6,35 @@ namespace chowdsp
struct StateValueBase
{
explicit StateValueBase (std::string_view valueName) : name (valueName) {}
StateValueBase (const StateValueBase&) = default;
virtual ~StateValueBase() = default;

virtual void reset() {}

virtual void serialize (JSONSerializer::SerializedType&) const {}
virtual void deserialize (JSONSerializer::DeserializedType) {}

const std::string_view name;
Broadcaster<void()> changeBroadcaster;
const std::string_view name {};
Broadcaster<void()> changeBroadcaster {};
};
#endif

/** A stateful value that can be used to hold some non-parameter state */
template <typename T>
template <typename T, typename element_type_ = T>
struct StateValue : StateValueBase
{
using element_type = T;
using element_type = element_type_;

/** Default constructor */
StateValue()
: StateValueBase ({}),
defaultValue (T {}),
defaultValue (element_type {}),
currentValue (defaultValue)
{
}

/** Constructs the value with a name and default value */
StateValue (std::string_view valueName, T defaultVal)
StateValue (std::string_view valueName, element_type defaultVal)
: StateValueBase (valueName),
defaultValue (defaultVal),
currentValue (defaultValue)
Expand All @@ -44,11 +45,11 @@ struct StateValue : StateValueBase
StateValue& operator= (StateValue&&) noexcept = default;

/** Returns the value */
T get() const noexcept { return currentValue; }
operator T() const noexcept { return get(); } // NOSONAR NOLINT(google-explicit-constructor): we want to be able to do implicit conversion
element_type get() const noexcept { return currentValue; }
operator element_type() const noexcept { return get(); } // NOSONAR NOLINT(google-explicit-constructor): we want to be able to do implicit conversion

/** Sets a new value */
void set (T v)
void set (element_type v)
{
JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE ("-Wfloat-equal")
if (v == currentValue)
Expand All @@ -59,7 +60,7 @@ struct StateValue : StateValueBase
changeBroadcaster();
}

StateValue& operator= (T v)
StateValue& operator= (element_type v)
{
set (v);
return *this;
Expand All @@ -80,7 +81,7 @@ struct StateValue : StateValueBase
deserialize<JSONSerializer> (deserial, *this);
}

const T defaultValue;
const element_type defaultValue;

private:
template <typename Serializer>
Expand All @@ -93,7 +94,7 @@ struct StateValue : StateValueBase
template <typename Serializer>
static void deserialize (typename Serializer::DeserializedType deserial, StateValue& value)
{
T val {};
element_type val {};
Serialization::deserialize<Serializer> (deserial, val);
value.set (val);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -83,5 +83,9 @@ TEST_CASE ("String Literal Test", "[common][data-structures]")
{
static constexpr auto fifteen = 15_sl;
REQUIRE (fifteen == chowdsp::StringLiteral { "15" });

REQUIRE (chowdsp::StringLiteral<2> { (int) 15 } == chowdsp::StringLiteral { "15" });
REQUIRE (chowdsp::StringLiteral<2> { (size_t) 15 } == chowdsp::StringLiteral { "15" });
REQUIRE (chowdsp::StringLiteral<3> { (int) -15 } == chowdsp::StringLiteral { "-15" });
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -39,18 +39,19 @@ struct PluginNonParameterState : chowdsp::NonParamState

PluginNonParameterState()
{
addStateValues ({ &editorWidth, &editorHeight });
addStateValues ({ &editorWidth, &editorHeight, &atomicThing });

for (size_t i = 0; i < 4; ++i)
{
yesNoNames[i] = chowdsp::StringLiteral { "yes_no" } + chowdsp::StringLiteral<1> { char ('0' + i) };
yesNoNames[i] = chowdsp::StringLiteral { "yes_no" } + chowdsp::StringLiteral<1> { i };
yesNoVals.emplace_back (yesNoNames[i], YesNo::No);
}
addStateValues<YesNo> ({ yesNoVals.begin(), yesNoVals.end() });
}

chowdsp::StateValue<int> editorWidth { "editor_width", 300 };
chowdsp::StateValue<int> editorHeight { "editor_height", 500 };
chowdsp::StateValue<std::atomic_int, int> atomicThing { "something_atomic", 12 };

std::array<chowdsp::StringLiteral<8>, 8> yesNoNames {};
chowdsp::SmallVector<chowdsp::StateValue<YesNo>, 8> yesNoVals;
Expand Down Expand Up @@ -185,19 +186,22 @@ TEST_CASE ("State Serialization Test", "[plugin][state]")
{
static constexpr int width = 200;
static constexpr int height = 150;
static constexpr int atomic = 24;

juce::MemoryBlock block;
{
State state;
state.nonParams.editorWidth = width;
state.nonParams.editorHeight = height;
state.nonParams.atomicThing = atomic;
state.serialize (block);
}

State state;
state.deserialize (block);
REQUIRE_MESSAGE (state.nonParams.editorWidth.get() == width, "Editor width is incorrect");
REQUIRE_MESSAGE (state.nonParams.editorHeight.get() == height, "Editor height is incorrect");
REQUIRE_MESSAGE (state.nonParams.atomicThing.get() == atomic, "Atomic thing is incorrect");
}

SECTION ("Added Parameter Test")
Expand Down

0 comments on commit f930081

Please sign in to comment.