diff --git a/src/App/Enumeration.cpp b/src/App/Enumeration.cpp
index 265a457789..4661145ed5 100644
--- a/src/App/Enumeration.cpp
+++ b/src/App/Enumeration.cpp
@@ -28,76 +28,81 @@
#include
#include "Enumeration.h"
+#include
using namespace App;
+namespace {
+struct StringCopy {
+ StringCopy(const char* str) : d(str) {
+ }
+ const char* data() const {
+ return d.data();
+ }
+ bool isEqual(const char* str) const {
+ return d == str;
+ }
+ bool isCustom() const {
+ return true;
+ }
+
+private:
+ std::string d;
+};
+
+struct StringView {
+ StringView(const char* str) : d(str) {
+ }
+ const char* data() const {
+ return d.data();
+ }
+ bool isEqual(const char* str) const {
+ return d == str;
+ }
+ bool isCustom() const {
+ return false;
+ }
+
+private:
+ std::string_view d;
+};
+}
+
Enumeration::Enumeration()
- : _EnumArray(nullptr), _ownEnumArray(false), _index(0), _maxVal(-1)
+ : _index(0)
{
}
Enumeration::Enumeration(const Enumeration &other)
- : _EnumArray(nullptr), _ownEnumArray(false), _index(0), _maxVal(-1)
{
- if (other._ownEnumArray) {
- setEnums(other.getEnumVector());
- } else {
- _EnumArray = other._EnumArray;
- }
-
- _ownEnumArray = other._ownEnumArray;
+ enumArray = other.enumArray;
_index = other._index;
- _maxVal = other._maxVal;
}
Enumeration::Enumeration(const char *valStr)
- : _ownEnumArray(true), _index(0), _maxVal(0)
+ : _index(0)
{
- _EnumArray = new const char*[2];
-#if defined (_MSC_VER)
- _EnumArray[0] = _strdup(valStr);
-#else
- _EnumArray[0] = strdup(valStr);
-#endif
- _EnumArray[1] = nullptr;
+ enumArray.push_back(StringCopy(valStr));
+ setValue(valStr);
}
Enumeration::Enumeration(const char **list, const char *valStr)
- : _EnumArray(list), _ownEnumArray(false)
+ : _index(0)
{
- findMaxVal();
+ while (list && *list) {
+ enumArray.push_back(StringView(*list));
+ list++;
+ }
setValue(valStr);
}
Enumeration::~Enumeration()
{
- if (_ownEnumArray) {
- if (_EnumArray != nullptr) {
- tearDown();
- }
- }
-}
-
-void Enumeration::tearDown(void)
-{
- // Ugly...
- for(char **plEnums = (char **)_EnumArray; *plEnums != nullptr; ++plEnums) {
- // Delete C Strings first
- free(*plEnums);
- }
-
- delete [] _EnumArray;
-
- _EnumArray = nullptr;
- _ownEnumArray = false;
- _maxVal = -1;
+ enumArray.clear();
}
void Enumeration::setEnums(const char **plEnums)
{
- if(plEnums == _EnumArray)
- return;
-
std::string oldValue;
bool preserve = (isValid() && plEnums != nullptr);
if (preserve) {
@@ -106,23 +111,15 @@ void Enumeration::setEnums(const char **plEnums)
oldValue = str;
}
- // set _ownEnumArray
- if (isValid() && _ownEnumArray) {
- tearDown();
+ enumArray.clear();
+ while (plEnums && *plEnums) {
+ enumArray.push_back(StringView(*plEnums));
+ plEnums++;
}
- // set...
- _EnumArray = plEnums;
-
- // set _maxVal
- findMaxVal();
-
// set _index
if (_index < 0)
_index = 0;
- else if (_index > _maxVal)
- _index = _maxVal;
-
if (preserve) {
setValue(oldValue);
}
@@ -143,30 +140,14 @@ void Enumeration::setEnums(const std::vector &values)
oldValue = str;
}
- if (isValid() && _ownEnumArray) {
- tearDown();
- }
-
- _EnumArray = new const char*[values.size() + 1];
- int i = 0;
+ enumArray.clear();
for (std::vector::const_iterator it = values.begin(); it != values.end(); ++it) {
-#if defined (_MSC_VER)
- _EnumArray[i++] = _strdup(it->c_str());
-#else
- _EnumArray[i++] = strdup(it->c_str());
-#endif
+ enumArray.push_back(StringCopy(it->c_str()));
}
- _EnumArray[i] = nullptr; // null termination
-
- // Other state variables
- _maxVal = static_cast(values.size() - 1);
- _ownEnumArray = true;
+ // set _index
if (_index < 0)
_index = 0;
- else if (_index > _maxVal)
- _index = _maxVal;
-
if (preserve) {
setValue(oldValue);
}
@@ -174,36 +155,18 @@ void Enumeration::setEnums(const std::vector &values)
void Enumeration::setValue(const char *value)
{
- // using string methods without set, use setEnums(const char** plEnums) first!
- //assert(_EnumArray);
-
- if (!_EnumArray) {
- _index = 0;
- return;
- }
-
- int i = 0;
- const char **plEnums = _EnumArray;
-
- // search for the right entry
- while (1) {
- // end of list? set zero
- if (*plEnums == nullptr) {
- _index = 0;
+ _index = 0;
+ for (std::size_t i = 0; i < enumArray.size(); i++) {
+ if (enumArray[i].isEqual(value)) {
+ _index = static_cast(i);
break;
}
- if (strcmp(*plEnums, value) == 0) {
- _index = i;
- break;
- }
- ++plEnums;
- ++i;
}
}
void Enumeration::setValue(long value, bool checkRange)
{
- if (value >= 0 && value <= _maxVal) {
+ if (value >= 0 && value < countItems()) {
_index = value;
} else {
if (checkRange) {
@@ -216,116 +179,104 @@ void Enumeration::setValue(long value, bool checkRange)
bool Enumeration::isValue(const char *value) const
{
- // using string methods without set, use setEnums(const char** plEnums) first!
- //assert(_EnumArray);
-
int i = getInt();
if (i == -1) {
return false;
} else {
- return strcmp(_EnumArray[i], value) == 0;
+ return enumArray[i].isEqual(value);
}
}
bool Enumeration::contains(const char *value) const
{
- // using string methods without set, use setEnums(const char** plEnums) first!
- //assert(_EnumArray);
-
- if (!getEnums()) {
+ if (!isValid()) {
return false;
}
- const char **plEnums = _EnumArray;
-
- // search for the right entry
- while (1) {
- // end of list?
- if (*plEnums == nullptr)
- return false;
- if (strcmp(*plEnums, value) == 0)
+ for (const auto& it : enumArray) {
+ if (it.isEqual(value))
return true;
- ++plEnums;
}
+
+ return false;
}
-const char * Enumeration::getCStr(void) const
+const char * Enumeration::getCStr() const
{
- // using string methods without set, use setEnums(const char** plEnums) first!
- //assert(_EnumArray);
-
- if (!isValid() || _index < 0 || _index > _maxVal) {
+ if (!isValid() || _index < 0 || _index >= countItems()) {
return nullptr;
}
- return _EnumArray[_index];
+ return enumArray[_index].data();
}
-int Enumeration::getInt(void) const
+int Enumeration::getInt() const
{
- if (!isValid() || _index < 0 || _index > _maxVal) {
+ if (!isValid() || _index < 0 || _index >= countItems()) {
return -1;
}
return _index;
}
-std::vector Enumeration::getEnumVector(void) const
+std::vector Enumeration::getEnumVector() const
{
- // using string methods without set, use setEnums(const char** plEnums) first!
- if (!_EnumArray)
- return std::vector();
+ std::vector list;
+ for (const auto& it : enumArray)
+ list.emplace_back(it.data());
+ return list;
+}
- std::vector result;
- const char **plEnums = _EnumArray;
+bool Enumeration::hasEnums() const
+{
+ return (!enumArray.empty());
+}
- // end of list?
- while (*plEnums != nullptr) {
- result.push_back(*plEnums);
- ++plEnums;
+bool Enumeration::isValid() const
+{
+ return (!enumArray.empty() && _index >= 0 && _index < countItems());
+}
+
+int Enumeration::maxValue() const
+{
+ int num = -1;
+ if (!enumArray.empty())
+ num = static_cast(enumArray.size()) - 1;
+ return num;
+}
+
+bool Enumeration::isCustom() const
+{
+ for (const auto& it : enumArray) {
+ if (it.isCustom())
+ return true;
}
-
- return result;
-}
-
-const char ** Enumeration::getEnums(void) const
-{
- return _EnumArray;
-}
-
-bool Enumeration::isValid(void) const
-{
- return (_EnumArray != nullptr && _index >= 0 && _index <= _maxVal);
+ return false;
}
Enumeration & Enumeration::operator=(const Enumeration &other)
{
- if (other._ownEnumArray) {
- setEnums(other.getEnumVector());
- } else {
- _EnumArray = other._EnumArray;
- }
+ if (this == &other)
+ return *this;
- _ownEnumArray = other._ownEnumArray;
+ enumArray = other.enumArray;
_index = other._index;
- _maxVal = other._maxVal;
return *this;
}
bool Enumeration::operator==(const Enumeration &other) const
{
- if(_index != other._index || _maxVal != other._maxVal)
+ if (_index != other._index || enumArray.size() != other.enumArray.size()) {
return false;
- if (_EnumArray == other._EnumArray)
- return true;
- for (int i=0; i<=_maxVal; ++i) {
- if (_EnumArray[i] == other._EnumArray[i])
+ }
+ for (size_t i = 0; i < enumArray.size(); ++i) {
+ if (enumArray[i].data() == other.enumArray[i].data())
continue;
- if (_EnumArray[i] == nullptr || other._EnumArray[i] == nullptr)
+ if (enumArray[i].data() == nullptr || other.enumArray[i].data() == nullptr)
return false;
- if (strcmp(_EnumArray[i], other._EnumArray[i]) != 0)
+ if (!enumArray[i].isEqual(other.enumArray[i].data()))
return false;
}
return true;
@@ -340,24 +291,7 @@ bool Enumeration::operator==(const char *other) const
return (strcmp(getCStr(), other) == 0);
}
-void Enumeration::findMaxVal(void)
+int Enumeration::countItems() const
{
- if (_EnumArray == nullptr) {
- _maxVal = -1;
- return;
- }
-
- const char **plEnums = _EnumArray;
-
- // the NULL terminator doesn't belong to the range of
- // valid values
- int i = -1;
- while (*(plEnums++) != nullptr) {
- ++i;
- // very unlikely to have enums with more then 5000 entries!
- assert(i < 5000);
- }
-
- _maxVal = i;
+ return static_cast(enumArray.size());
}
-
diff --git a/src/App/Enumeration.h b/src/App/Enumeration.h
index 99747c8ea6..e9ddf4acab 100644
--- a/src/App/Enumeration.h
+++ b/src/App/Enumeration.h
@@ -24,14 +24,13 @@
#ifndef BASE_ENUMERATION_H
#define BASE_ENUMERATION_H
+#include
#include
#include
-
+#include
namespace App
{
- class PropertyEnumeration;
-
/// A bidirectional string-integer mapping
/*!
* This is mainly intended for two purposes: working around the difficulty
@@ -52,144 +51,172 @@ namespace App
*/
class AppExport Enumeration
{
- friend class App::PropertyEnumeration;
+ protected:
+ class Object {
public:
- /// Constructs an empty Enumeration object
- Enumeration();
+ template
+ Object(T&& obj): object(std::make_shared>(std::forward(obj))){}
+ const char* data() const {
+ return object->data();
+ }
+ bool isEqual(const char* str) const {
+ return object->isEqual(str);
+ }
+ bool isCustom() const {
+ return object->isCustom();
+ }
- /// Standard copy constructor
- Enumeration(const Enumeration& other);
+ struct Concept {
+ virtual ~Concept() {}
+ virtual const char* data() const = 0;
+ virtual bool isEqual(const char*) const = 0;
+ virtual bool isCustom() const = 0;
+ };
- /// Constructs an Enumeration with a single element
- Enumeration(const char *valStr);
+ template< typename T >
+ struct Model : Concept {
+ Model(const T& t) : object(t) {}
+ const char* data() const override {
+ return object.data();
+ }
+ bool isEqual(const char* str) const override {
+ return object.isEqual(str);
+ }
+ bool isCustom() const override {
+ return object.isCustom();
+ }
+ private:
+ T object;
+ };
- /// Constructs an Enumeration using val within list
- Enumeration(const char **list, const char *valStr);
+ std::shared_ptr object;
+ };
- /// Standard destructor
- ~Enumeration();
+ public:
+ /// Constructs an empty Enumeration object
+ Enumeration();
- /** Sets the enumeration string list
- * The list is a NULL terminated array of pointers to const
- * char* strings.
- * \code
- * const char enums[] = {"Black","White","Other",NULL}
- * \endcode
- *
- * If Enumeration was already valid, will attempt to preserve
- * the string-representation value of the Enumeration
- *
- * Enumeration does not take ownership of the passed object
- */
- void setEnums(const char **plEnums);
+ /// Standard copy constructor
+ Enumeration(const Enumeration& other);
- /// Set all enum values as vector of strings
- /*!
- * This method causes the Enumeration to dynamically allocate
- * it's own array of C Strings, which will be deleted by the
- * destructor or subsequent calls to setEnums(). So, it is
- * important to make sure the Enumeration stays in scope as
- * long as values returned by getCStr are in use.
- *
- * If Enumeration was already valid, will attempt to preserve
- * the string-representation value of the Enumeration
- */
- void setEnums(const std::vector &values);
+ /// Constructs an Enumeration with a single element
+ Enumeration(const char *valStr);
- /// Set the enum using a C string
- void setValue(const char *value);
+ /// Constructs an Enumeration using val within list
+ Enumeration(const char **list, const char *valStr);
- /// Overload of setValue(const char *value)
- void setValue(const std::string &value) {setValue(value.c_str());}
+ /// Standard destructor
+ ~Enumeration();
- /// Set the enum using a long
- /*!
- * if checkRange is set to true, throws Base::ValueError when
- * values are set out of range
- *
- * Checks for boundaries via assert()
- */
- void setValue(long value, bool checkRange = false);
+ /** Sets the enumeration string list
+ * The list is a NULL terminated array of pointers to const
+ * char* strings.
+ * \code
+ * const char enums[] = {"Black","White","Other",NULL}
+ * \endcode
+ *
+ * If Enumeration was already valid, will attempt to preserve
+ * the string-representation value of the Enumeration
+ *
+ * Enumeration does not take ownership of the passed object
+ */
+ void setEnums(const char **plEnums);
- /// Checks if the property is set to a certain string value
- bool isValue(const char *value) const;
+ /// Set all enum values as vector of strings
+ /*!
+ * This method causes the Enumeration to dynamically allocate
+ * it's own array of C Strings, which will be deleted by the
+ * destructor or subsequent calls to setEnums(). So, it is
+ * important to make sure the Enumeration stays in scope as
+ * long as values returned by getCStr are in use.
+ *
+ * If Enumeration was already valid, will attempt to preserve
+ * the string-representation value of the Enumeration
+ */
+ void setEnums(const std::vector &values);
- /// Checks if a string is included in the enumeration
- bool contains(const char *value) const;
+ /// Set the enum using a C string
+ void setValue(const char *value);
- /// Return the value as C string
- /*!
- * Returns NULL if the enumeration is invalid.
- */
- const char * getCStr(void) const;
+ /// Overload of setValue(const char *value)
+ void setValue(const std::string &value) {setValue(value.c_str());}
- /// Return value as integer
- /*!
- * Returns -1 if the Enumeration isn't valid
- */
- int getInt(void) const;
+ /// Set the enum using a long
+ /*!
+ * if checkRange is set to true, throws Base::ValueError when
+ * values are set out of range
+ *
+ * Checks for boundaries via assert()
+ */
+ void setValue(long value, bool checkRange = false);
- /// get all possible enum values as vector of strings
- std::vector getEnumVector(void) const;
+ /// Checks if the property is set to a certain string value
+ bool isValue(const char *value) const;
- /// get pointer to the enum list
- const char ** getEnums(void) const;
+ /// Checks if a string is included in the enumeration
+ bool contains(const char *value) const;
- /// Returns true if the instance is in a usable state
- bool isValid(void) const;
+ /// Return the value as C string
+ /*!
+ * Returns NULL if the enumeration is invalid.
+ */
+ const char * getCStr() const;
- /// Returns the highest usable integer value for this enum
- /*!
- * Returns -1 if the enumeration is not valid according to isValid()
- */
- int maxValue(void) const {return _maxVal;}
+ /// Return value as integer
+ /*!
+ * Returns -1 if the Enumeration isn't valid
+ */
+ int getInt() const;
- /// Assignment operator
- Enumeration & operator=(const Enumeration &other);
+ /// get all possible enum values as vector of strings
+ std::vector getEnumVector() const;
- /// true iff our string representation matches other's
- /*!
- * Returns false if either Enumeration is not valid.
- */
- bool operator==(const Enumeration &other) const;
+ /// returns true if the enum list is non-empty, false otherwise
+ bool hasEnums() const;
- /// true iff our string representation matches other
- /*!
- * Returns false if Enumeration is not valid.
- */
- bool operator==(const char *other) const;
- protected:
- /// Returns true if instance was not initialized via static string list
- bool isCustom(void) const {return _ownEnumArray;}
+ /// Returns true if the instance is in a usable state
+ bool isValid() const;
- /// Updates _maxVal
- void findMaxVal(void);
+ /// Returns the highest usable integer value for this enum
+ /*!
+ * Returns -1 if the enumeration is not valid according to isValid()
+ */
+ int maxValue() const;
- /// De-allocates memory used in _EnumArray
- /*!
- * Important to not call this unless this Enumeration owns array.
- */
- void tearDown(void);
+ /// Returns true if any of the items is a user-defined string
+ bool isCustom() const;
- private:
- /// Handle to C Strings of possible enumeration values
- const char **_EnumArray;
+ /// Assignment operator
+ Enumeration & operator=(const Enumeration &other);
- /// Whether instance owns _EnumArray
- bool _ownEnumArray;
+ /// true iff our string representation matches other's
+ /*!
+ * Returns false if either Enumeration is not valid.
+ */
+ bool operator==(const Enumeration &other) const;
- /// Integer value of the enumeration
- /*!
- * This serves as an index into _EnumArray to get the string
- * representation.
- */
- int _index;
+ /// true iff our string representation matches other
+ /*!
+ * Returns false if Enumeration is not valid.
+ */
+ bool operator==(const char *other) const;
+ protected:
- /*! Cached result from findMaxVal()
- * Value should either be the maximum allowable integer value for
- * the Enumeration, or -1 if not initialized
- */
- int _maxVal;
+ /// Number of items
+ int countItems() const;
+
+ private:
+ /// Handle to C Strings of possible enumeration values
+ std::vector