[ad_1]
I’m writing one thing just like the Unity’s shader graph and I’m kinda caught on a property panel.
I add a float property, which title is Float
, after which I add a second float property, which additionally is called Float
(till I rename it). I’d just like the second property title to be rearranged to Float(1)
What I attempted firstly was a easy vector
of properties
struct Property
{
Property(std::string_view title, std::any worth)
: title(title), worth(std::transfer(worth)) {}
std::string title;
std::any worth;
};
template<typename PropertyT>
void Add(std::string_view title, PropertyT&& worth)
{
static uint32_t counter = 0;
auto finalName = counter == 0 ? title : fmt::format("{}({})", title, counter);
properties.emplace_back(finalName, std::transfer(worth));
++counter;
}
void Remove(std::string_view title)
{
std::erase_if(properties, [name](const auto& prop){ return prop.title == title; });
}
std::vector<Property> properties;
however the static uint32_t counter
isn’t a legitimate resolution, as a result of
- static variable
- the counter isn’t decremented, so if
Float(1)
will probably be named to one thing else, the following float property needs to beFloat(1)
, notFloat(2)
.
so I assumed I’d do a map of the property pool by title.
struct Property
{
Property(std::string_view title, std::any&& worth, size_t index)
: title(title), worth(std::transfer(worth))
{
if (index != 0) {
this->title += "(" + std::to_string(index) + ")";
}
}
const bool isValid() const
{
return worth.has_value() && !title.empty();
}
std::any worth;
std::string title;
non-public:
pal struct PropertyPool;
int64_t subsequent = 0;
};
struct PropertyPool
{
[[nodiscard]] inline size_t Add(std::string_view title, std::any&& worth)
{
if(nextFree == -1) {
const size_t index = (size_t)nextFree;
nextFree = pool[index].subsequent;
auto& prop = pool[index];
prop = Property(title, std::transfer(worth), index);
nameToId[prop.name] = index;
return index;
} else {
const size_t index = pool.measurement();
auto& prop = pool.emplace_back(title, std::transfer(worth), index);
nameToId[prop.name] = index;
return index;
}
}
void erase(size_t index)
{
auto& prop = pool[index];
prop.title.clear();
prop.worth.reset();
prop.subsequent = nextFree;
nextFree = (int64_t)index;
}
Property* tryGetByName(const std::string& title)
{
if(!nameToId.accommodates(title)) {
return nullptr;
}
const size_t index = nameToId.at(title);
if(pool.measurement() <= index) {
return nullptr;
}
if(!pool[index].isValid()) {
return nullptr;
}
return &pool[index];
}
std::unordered_map<std::string, int64_t> nameToId;
std::vector<Property> pool;
int64_t nextFree = -1;
};
struct PropertySet
{
template<typename T>
void Add(std::string_view title, T&& worth)
{
const uint32_t hash = getHash(title);
auto& pool = swimming pools[hash];
size_t index = pool.insert(title, std::transfer(worth));
return pool.pool[index];
}
void Remove(std::string_view title)
{
const uint32_t hash = getHash(title);
auto& pool = swimming pools[hash];
pool.erase(pool.nameToId[std::string(name)]);
}
const uint32_t getHash(std::string_view title) const
{
auto it = title.find_last_of("(");
if (it != std::string_view::npos) {
title.remove_suffix(title.measurement() - it);
}
return std::hash<std::string_view>{}(title);
}
std::unordered_map<uint32_t, PropertyPool> swimming pools;
};
The code seems terrible, but it surely roughly works as I want.
The foremost drawback is that this complete code is written solely to help properties with the identical names, that can likely be renamed. Thus this resolution is kinda ineffective as a result of for instance there’re 4 properties named: Float
, x
, y
, z
. The std::unordered_map<uint32_t, PropertyPool> swimming pools
will allocate reminiscence, and the PropertyPool
may also allocate reminiscence, so it is kinda waste.
What do you consider it?
How would you implement one thing like this?
What would you alter in my code? (I wager all the pieces :D, however maintain it for actual, although)
[ad_2]