Skip to content

Commit b1f0902

Browse files
fix(ofParameter): better default init() handling of non-comparable/non-copyable objects and containers (#8325)
* fix(ofParameter): correct init() handling of non-comparable objects * refactor(ofParameter): default isInit switched from false to true * feat(ofParameter): prioritize assignment by value * fix(ofParameter): correct return type for = const ParameterType & v * feat(ofParameter): expand the is_comparable trait to include actual comparability --------- Co-authored-by: alexandre burton <[email protected]>
1 parent 7d0067f commit b1f0902

File tree

1 file changed

+59
-43
lines changed

1 file changed

+59
-43
lines changed

libs/openFrameworks/types/ofParameter.h

Lines changed: 59 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -38,8 +38,8 @@ class ofAbstractParameter {
3838
virtual std::string getEscapedName() const;
3939
virtual std::string valueType() const = 0;
4040

41-
virtual bool isInit() const = 0;
42-
virtual void reInit() = 0;
41+
virtual bool isInit() const { return true; }
42+
virtual void reInit() {};
4343

4444
virtual void setParent(ofParameterGroup & _parent) = 0;
4545
std::vector<std::string> getGroupHierarchyNames() const;
@@ -351,6 +351,23 @@ ofReadOnlyParameter<ParameterType, Friend> & ofParameterGroup::getReadOnly(std::
351351
/*! \cond PRIVATE */
352352
namespace of {
353353
namespace priv {
354+
355+
template<typename T, typename U = T>
356+
constexpr auto test_comparable(int) -> decltype(std::declval<T>() == std::declval<U>(), std::true_type{});
357+
358+
template<typename T, typename U = T>
359+
constexpr std::false_type test_comparable(...);
360+
361+
template<typename T>
362+
struct is_comparable : decltype(test_comparable<T>(0)) {};
363+
364+
template<typename T>
365+
struct is_comparable<std::vector<T>> : is_comparable<T> {};
366+
367+
template<typename T>
368+
constexpr bool is_comparable_v = is_comparable<T>::value;
369+
370+
354371
//----------------------------------------------------------------------
355372
// Mechanism to provide min and max default values for types where it makes sense
356373
template <typename T, bool B>
@@ -510,6 +527,9 @@ template <typename ParameterType>
510527
class ofParameter : public ofAbstractParameter {
511528
public:
512529

530+
/// \brief flag to opt-out of the isInit mechanism (in-complement to auto-detection of incomparability)
531+
static inline bool init_opt_out { false };
532+
513533
/// \brief constructs a default ofParameter of type ParameterType
514534
/// \tparam ParameterType the type of the Value held by the ofParameter
515535
ofParameter();
@@ -601,6 +621,8 @@ class ofParameter : public ofAbstractParameter {
601621
void makeReferenceTo(ofParameter<ParameterType> & mom);
602622

603623
ofParameter<ParameterType> & operator=(const ofParameter<ParameterType> & v);
624+
625+
template<typename U = ParameterType, std::enable_if_t<!std::is_same_v<U, ofParameter<U>>, int> = 0>
604626
const ParameterType & operator=(const ParameterType & v);
605627

606628
template <typename U = ParameterType>
@@ -671,39 +693,38 @@ class ofParameter : public ofAbstractParameter {
671693
protected:
672694
private:
673695
class Value {
696+
auto init_init(ParameterType &v) {
697+
if constexpr (of::priv::is_comparable_v<ParameterType>) {
698+
if (!init_opt_out) init = v;
699+
}
700+
}
701+
674702
public:
675703
Value()
676-
: init(of::priv::TypeInfo<ParameterType>::min())
677-
, min(of::priv::TypeInfo<ParameterType>::min())
704+
: min(of::priv::TypeInfo<ParameterType>::min())
678705
, max(of::priv::TypeInfo<ParameterType>::max())
679706
, bInNotify(false)
680-
, serializable(true) { }
681-
707+
, serializable(true) { init_init(min); }
682708
Value(ParameterType v)
683-
: init(v)
684-
, value(v)
709+
: value(v)
685710
, min(of::priv::TypeInfo<ParameterType>::min())
686711
, max(of::priv::TypeInfo<ParameterType>::max())
687712
, bInNotify(false)
688-
, serializable(true) { }
689-
713+
, serializable(true) { init_init(v); }
690714
Value(std::string name, ParameterType v)
691715
: name(name)
692-
, init(v)
693716
, value(v)
694717
, min(of::priv::TypeInfo<ParameterType>::min())
695718
, max(of::priv::TypeInfo<ParameterType>::max())
696719
, bInNotify(false)
697-
, serializable(true) { }
698-
720+
, serializable(true) { init_init(v); }
699721
Value(std::string name, ParameterType v, ParameterType min, ParameterType max)
700722
: name(name)
701-
, init(v)
702723
, value(v)
703724
, min(min)
704725
, max(max)
705726
, bInNotify(false)
706-
, serializable(true) { }
727+
, serializable(true) { init_init(v); }
707728

708729
std::string name;
709730
ParameterType init, value, min, max;
@@ -762,9 +783,10 @@ inline ofParameter<ParameterType> & ofParameter<ParameterType>::operator=(const
762783
}
763784

764785
template <typename ParameterType>
786+
template<typename U, std::enable_if_t<!std::is_same_v<U, ofParameter<U>>, int>>
765787
inline const ParameterType & ofParameter<ParameterType>::operator=(const ParameterType & v) {
766788
set(v);
767-
return obj->value;
789+
return *this;
768790
}
769791

770792
template <typename ParameterType>
@@ -891,7 +913,13 @@ ParameterType ofParameter<ParameterType>::getMax() const {
891913

892914
template <typename ParameterType>
893915
void ofParameter<ParameterType>::setInit(const ParameterType & init) {
894-
obj->init = init;
916+
if constexpr (of::priv::is_comparable_v<ParameterType>) {
917+
if (!init_opt_out) {
918+
obj->init = init;
919+
return;
920+
}
921+
}
922+
ofLogWarning("ofParameter::setInit") << "called on a non-comparable (or opted-out) type";
895923
}
896924

897925
template <typename ParameterType>
@@ -901,12 +929,24 @@ ParameterType ofParameter<ParameterType>::getInit() const {
901929

902930
template <typename ParameterType>
903931
bool ofParameter<ParameterType>::isInit() const {
904-
return obj->value == obj->init;
932+
if constexpr (of::priv::is_comparable_v<ParameterType>) {
933+
if (!init_opt_out) {
934+
return obj->value == obj->init;
935+
}
936+
}
937+
ofLogWarning("ofParameter::isInit") << "called on a non-comparable (or opted-out) type => always true";
938+
return true;
905939
}
906940

907941
template <typename ParameterType>
908942
void ofParameter<ParameterType>::reInit() {
909-
setMethod(obj->init);
943+
if constexpr (of::priv::is_comparable_v<ParameterType>) {
944+
if (!init_opt_out) {
945+
setMethod(obj->init);
946+
return;
947+
}
948+
}
949+
ofLogWarning("ofParameter::reInit") << "called on a non-comparable (or opted-out) type => no-op";
910950
}
911951

912952
template <typename ParameterType>
@@ -1276,9 +1316,6 @@ class ofReadOnlyParameter : public ofAbstractParameter {
12761316

12771317
void setMin(const ParameterType & min);
12781318
void setMax(const ParameterType & max);
1279-
void setInit(const ParameterType & init);
1280-
bool isInit() const;
1281-
void reInit();
12821319

12831320
void fromString(const std::string & str);
12841321

@@ -1560,27 +1597,6 @@ inline void ofReadOnlyParameter<ParameterType, Friend>::setMax(const ParameterTy
15601597
parameter.setMax(max);
15611598
}
15621599

1563-
template <typename ParameterType, typename Friend>
1564-
inline void ofReadOnlyParameter<ParameterType, Friend>::setInit(const ParameterType & init) {
1565-
parameter.setInit(init);
1566-
}
1567-
1568-
template <typename ParameterType, typename Friend>
1569-
inline bool ofReadOnlyParameter<ParameterType, Friend>::isInit() const {
1570-
// not sure what the expected behaviour for isInit() would be for ReadOnlyParameter
1571-
// as-is, it fails with : No member named 'value' in 'ofParameter<std::string>'
1572-
// returning true while informing with a log msg seems sane
1573-
ofLogVerbose("ofReadOnlyParameter::isInit()") << "isInit() called on ofReadOnlyParameter, where it always returns true";
1574-
return true;
1575-
}
1576-
1577-
template <typename ParameterType, typename Friend>
1578-
inline void ofReadOnlyParameter<ParameterType, Friend>::reInit() {
1579-
// not sure what the expected behaviour for reInit() would be for ReadOnlyParameter
1580-
// informing with a log msg seems sane
1581-
ofLogVerbose("ofReadOnlyParameter::reInit()") << "reInit() called on ofReadOnlyParameter, where it is a no-op";
1582-
}
1583-
15841600
template <typename ParameterType, typename Friend>
15851601
inline void ofReadOnlyParameter<ParameterType, Friend>::fromString(const std::string & str) {
15861602
parameter.fromString(str);

0 commit comments

Comments
 (0)