App: fix memory leaks in Enumeration class and simplify code
This commit is contained in:
@@ -28,76 +28,81 @@
|
||||
|
||||
#include <Base/Exception.h>
|
||||
#include "Enumeration.h"
|
||||
#include <string_view>
|
||||
|
||||
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<std::string> &values)
|
||||
oldValue = str;
|
||||
}
|
||||
|
||||
if (isValid() && _ownEnumArray) {
|
||||
tearDown();
|
||||
}
|
||||
|
||||
_EnumArray = new const char*[values.size() + 1];
|
||||
int i = 0;
|
||||
enumArray.clear();
|
||||
for (std::vector<std::string>::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<int>(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<std::string> &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<int>(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<std::string> Enumeration::getEnumVector(void) const
|
||||
std::vector<std::string> Enumeration::getEnumVector() const
|
||||
{
|
||||
// using string methods without set, use setEnums(const char** plEnums) first!
|
||||
if (!_EnumArray)
|
||||
return std::vector<std::string>();
|
||||
std::vector<std::string> list;
|
||||
for (const auto& it : enumArray)
|
||||
list.emplace_back(it.data());
|
||||
return list;
|
||||
}
|
||||
|
||||
std::vector<std::string> 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<int>(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<int>(enumArray.size());
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user