App: Add IndexedName class

Ported from development/toponaming.
This commit is contained in:
Chris Hennes
2023-03-07 23:21:05 -06:00
committed by Chris Hennes
parent bcc80ba9aa
commit f0fe65e769
3 changed files with 310 additions and 0 deletions

View File

@@ -261,6 +261,7 @@ SET(FreeCADApp_CPP_SRCS
ComplexGeoData.cpp
ComplexGeoDataPyImp.cpp
Enumeration.cpp
IndexedName.cpp
Material.cpp
MaterialPyImp.cpp
Metadata.cpp
@@ -277,6 +278,7 @@ SET(FreeCADApp_HPP_SRCS
ColorModel.h
ComplexGeoData.h
Enumeration.h
IndexedName.h
Material.h
Metadata.h
)

127
src/App/IndexedName.cpp Normal file
View File

@@ -0,0 +1,127 @@
// SPDX-License-Identifier: LGPL-2.1-or-later
/****************************************************************************
* Copyright (c) 2022 Zheng, Lei (realthunder) <realthunder.dev@gmail.com>*
* *
* This file is part of FreeCAD. *
* *
* FreeCAD is free software: you can redistribute it and/or modify it *
* under the terms of the GNU Lesser General Public License as *
* published by the Free Software Foundation, either version 2.1 of the *
* License, or (at your option) any later version. *
* *
* FreeCAD is distributed in the hope that it will be useful, but *
* WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
* Lesser General Public License for more details. *
* *
* You should have received a copy of the GNU Lesser General Public *
* License along with FreeCAD. If not, see *
* <https://www.gnu.org/licenses/>. *
* *
***************************************************************************/
#include "PreCompiled.h"
#ifndef _PreComp_
# include <cstdlib>
# include <unordered_set>
#endif
#include <QHash>
#include "IndexedName.h"
using namespace Data;
struct ByteArray
{
ByteArray(const QByteArray& b)
:bytes(b)
{}
ByteArray(const ByteArray& other)
:bytes(other.bytes)
{}
ByteArray(ByteArray&& other)
:bytes(std::move(other.bytes))
{}
void mutate() const
{
QByteArray copy;
copy.append(bytes.constData(), bytes.size());
bytes = copy;
}
bool operator==(const ByteArray& other) const {
return bytes == other.bytes;
}
mutable QByteArray bytes;
};
struct ByteArrayHasher
{
std::size_t operator()(const ByteArray& bytes) const
{
return qHash(bytes.bytes);
}
std::size_t operator()(const QByteArray& bytes) const
{
return qHash(bytes);
}
};
void IndexedName::set(
const char* name,
int len,
const std::vector<const char*>& types,
bool allowOthers)
{
static std::unordered_set<ByteArray, ByteArrayHasher> NameSet;
if (len < 0)
len = static_cast<int>(std::strlen(name));
int i;
for (i = len - 1; i >= 0; --i) {
if (name[i] < '0' || name[i]>'9')
break;
}
++i;
this->index = std::atoi(name + i);
for (int j = 0; j < i; ++j) {
if (name[j] == '_'
|| (name[j] >= 'a' && name[j] <= 'z')
|| (name[j] >= 'A' && name[j] <= 'Z'))
continue;
this->type = "";
return;
}
for (const char* type : types) {
int j = 0;
for (const char* n = name, *t = type; *n; ++n) {
if (*n != *t || j >= i)
break;
++j;
++t;
if (!*t) {
this->type = type;
return;
}
}
}
if (allowOthers) {
auto res = NameSet.insert(QByteArray::fromRawData(name, i));
if (res.second)
res.first->mutate();
this->type = res.first->bytes.constData();
}
else
this->type = "";
}

181
src/App/IndexedName.h Normal file
View File

@@ -0,0 +1,181 @@
// SPDX-License-Identifier: LGPL-2.1-or-later
/****************************************************************************
* Copyright (c) 2022 Zheng, Lei (realthunder) <realthunder.dev@gmail.com>*
* *
* This file is part of FreeCAD. *
* *
* FreeCAD is free software: you can redistribute it and/or modify it *
* under the terms of the GNU Lesser General Public License as *
* published by the Free Software Foundation, either version 2.1 of the *
* License, or (at your option) any later version. *
* *
* FreeCAD is distributed in the hope that it will be useful, but *
* WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
* Lesser General Public License for more details. *
* *
* You should have received a copy of the GNU Lesser General Public *
* License along with FreeCAD. If not, see *
* <https://www.gnu.org/licenses/>. *
* *
***************************************************************************/
#ifndef _IndexedName_h_
#define _IndexedName_h_
#include <cassert>
#include <cstring>
#include <ostream>
#include <string>
#include <vector>
#include <QByteArray>
#include "FCGlobal.h"
namespace Data
{
class AppExport IndexedName {
public:
explicit IndexedName(const char *name = nullptr, int _index = 0)
: index(0)
{
if (!name)
this->type = "";
else {
set(name);
if (_index)
this->index = _index;
}
}
IndexedName(const char *name,
const std::vector<const char*> & types,
bool allowOthers=true)
{
set(name, -1, types, allowOthers);
}
explicit IndexedName(const QByteArray & data)
{
set(data.constData(), data.size());
}
IndexedName(const IndexedName &other)
: type(other.type), index(other.index)
{}
static IndexedName fromConst(const char *name, int index) {
IndexedName res;
res.type = name;
res.index = index;
return res;
}
IndexedName & operator=(const IndexedName & other)
{
this->index = other.index;
this->type = other.type;
return *this;
}
friend std::ostream & operator<<(std::ostream & s, const IndexedName & e)
{
s << e.type;
if (e.index > 0)
s << e.index;
return s;
}
bool operator==(const IndexedName & other) const
{
return this->index == other.index
&& (this->type == other.type
|| std::strcmp(this->type, other.type)==0);
}
IndexedName & operator+=(int offset)
{
this->index += offset;
assert(this->index >= 0);
return *this;
}
IndexedName & operator++()
{
++this->index;
return *this;
}
IndexedName & operator--()
{
--this->index;
assert(this->index >= 0);
return *this;
}
bool operator!=(const IndexedName & other) const
{
return !(this->operator==(other));
}
const char * toString(std::string & s) const
{
// Note! s is not cleared on purpose.
std::size_t offset = s.size();
s += this->type;
if (this->index > 0)
s += std::to_string(this->index);
return s.c_str() + offset;
}
int compare(const IndexedName & other) const
{
int res = std::strcmp(this->type, other.type);
if (res)
return res;
if (this->index < other.index)
return -1;
if (this->index > other.index)
return 1;
return 0;
}
bool operator<(const IndexedName & other) const
{
return compare(other) < 0;
}
char operator[](int index) const
{
return this->type[index];
}
const char * getType() const { return this->type; }
int getIndex() const { return this->index; }
void setIndex(int index) { assert(index>=0); this->index = index; }
bool isNull() const { return !this->type[0]; }
explicit operator bool() const { return !isNull(); }
protected:
void set(const char *,
int len = -1,
const std::vector<const char *> &types = {},
bool allowOthers = true);
private:
const char * type;
int index;
};
}
#endif _IndexedName_h_