-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
70ed03e
commit 6af93a2
Showing
4 changed files
with
141 additions
and
9 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,12 +1,82 @@ | ||
# SparseToDenseVector | ||
# FlatValueMap | ||
|
||
A sparse to dense vector. Useful for having a handle instead of a index for. | ||
A sparse to dense container. | ||
This container has a constant lookup time (on average) thanks to the internal map which stores sparse handles to the dense indices. | ||
It has O(1) iteration speed because all the values are stored in a vector. | ||
|
||
The API is almost identical to std::map. With some extra additions to get more control over the internals. | ||
|
||
## Code Example | ||
```cpp | ||
#include <flat_value_map_handle.h> | ||
#include <flat_value_map.h> | ||
#include <cassert> | ||
#include <iostream> | ||
|
||
|
||
using namespace cof; | ||
|
||
|
||
class Entity | ||
{ | ||
public: | ||
Entity() : name(), tags{} | ||
{} | ||
Entity(std::string name, std::vector<std::string> tags) : name(std::move(name)), tags{ std::move(tags) } | ||
{} | ||
virtual ~Entity() = default; | ||
|
||
std::string name; | ||
std::vector<std::string> tags{}; | ||
|
||
|
||
friend bool operator==(const Entity& lhs, const Entity& rhs) | ||
{ | ||
return lhs.name == rhs.name | ||
&& lhs.tags == rhs.tags; | ||
} | ||
friend bool operator!=(const Entity& lhs, const Entity& rhs) { return !(lhs == rhs); } | ||
}; | ||
|
||
using EntityHandle = FvmHandle<Entity>; | ||
|
||
|
||
int example_main(int argc, char* argv[]) | ||
{ | ||
FlatValueMap<EntityHandle, Entity> entities{}; | ||
|
||
auto dogHandle = entities.push_back(Entity{ "Dog", {"Animal", "Good boi"} }); | ||
auto catHandle = entities.push_back(Entity{ "Cat", {"Animal", "Lazy"} }); | ||
|
||
// O(1) iteration speed because the entities are stored in a vector. | ||
for (Entity& entity : entities) { | ||
if (entity == Entity{ "Cat", {"Animal", "Lazy"} }) { | ||
std::cout << "I know this one!\n"; | ||
} else { | ||
std::cout << "Unknown entity detected! named: " << entity.name << '\n'; | ||
} | ||
} | ||
|
||
// Lookup times are constant (on average) because the handles are stored next to the indices in an unordered_map | ||
Entity& dog = entities[dogHandle]; | ||
std::cout << "I'm going to play fetch with: " << dog.name << '\n'; | ||
|
||
entities.erase(dogHandle); | ||
assert(entities.size() == 1); | ||
entities.erase(catHandle); | ||
assert(entities.empty()); | ||
|
||
return 0; | ||
} | ||
``` | ||
## Classes | ||
### flat_value_map | ||
A generic vector indexed by handle(aka id) instead of index directly. | ||
There are two versions of the FlatValueMap, they both have an (almost) identical API but they have slightly different internals. | ||
### cof::FlatValueMap | ||
This implementation uses a `unordered_map<handle, index>` as sparse to dense map for quick lookup times and uses `unordered_map<index, SparseToDense::iterator>` as a DenseToSparse map for quick deletion times. | ||
This causes it to use more memory but will perform more consistent. | ||
### light_flat_value_map | ||
A generic vector indexed by handle(aka id) instead of index directly. | ||
### cof::LightFlatValueMap | ||
This implementation only uses a `unordered_map<handle, index>` as sparse to dense map for quick lookup times and does not use any other map for the reverse lookup. This means that deletion complexity is linear because we loop over all elements in the sparse_to_dense map to find a matching key-value pair. | ||
But the memory usage is smaller. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,58 @@ | ||
#include <flat_value_map_handle.h> | ||
#include <flat_value_map.h> | ||
#include <cassert> | ||
#include <iostream> | ||
|
||
|
||
using namespace cof; | ||
|
||
|
||
class Entity | ||
{ | ||
public: | ||
Entity() : name(), tags{} | ||
{} | ||
Entity(std::string name, std::vector<std::string> tags) : name(std::move(name)), tags{ std::move(tags) } | ||
{} | ||
virtual ~Entity() = default; | ||
|
||
std::string name; | ||
std::vector<std::string> tags{}; | ||
|
||
|
||
friend bool operator==(const Entity& lhs, const Entity& rhs) | ||
{ | ||
return lhs.name == rhs.name | ||
&& lhs.tags == rhs.tags; | ||
} | ||
friend bool operator!=(const Entity& lhs, const Entity& rhs) { return !(lhs == rhs); } | ||
}; | ||
|
||
using EntityHandle = FvmHandle<Entity>; | ||
|
||
|
||
int example_main(int argc, char* argv[]) | ||
{ | ||
FlatValueMap<EntityHandle, Entity> entities{}; | ||
|
||
auto dogHandle = entities.push_back(Entity{ "Dog", {"Animal", "Good boi"} }); | ||
auto catHandle = entities.push_back(Entity{ "Cat", {"Animal", "Lazy"} }); | ||
|
||
for (Entity& entity : entities) { | ||
if (entity == Entity{ "Cat", {"Animal", "Lazy"} }) { | ||
std::cout << "I know this one!\n"; | ||
} else { | ||
std::cout << "Unknown entity detected! named: " << entity.name << '\n'; | ||
} | ||
} | ||
|
||
Entity& dog = entities[dogHandle]; | ||
std::cout << "I'm going to play fetch with: " << dog.name << '\n'; | ||
|
||
entities.erase(dogHandle); | ||
assert(entities.size() == 1); | ||
entities.erase(catHandle); | ||
assert(entities.empty()); | ||
|
||
return 0; | ||
} |