App: fix memory leaks in Enumeration class and simplify code

This commit is contained in:
wmayer
2022-05-10 18:47:23 +02:00
committed by wwmayer
parent d7313598aa
commit 7db925d991
12 changed files with 329 additions and 340 deletions

View File

@@ -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());
}