Skip to content

Commit

Permalink
Updated readme and added example
Browse files Browse the repository at this point in the history
  • Loading branch information
FireFlyForLife committed Oct 2, 2019
1 parent 70ed03e commit 6af93a2
Show file tree
Hide file tree
Showing 4 changed files with 141 additions and 9 deletions.
82 changes: 76 additions & 6 deletions README.md
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.
1 change: 1 addition & 0 deletions SparseToDenseVector.vcxproj
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,7 @@
<ClInclude Include="include\utils\tmp_compatibility.h" />
</ItemGroup>
<ItemGroup>
<ClCompile Include="examples\basic_example.cpp" />
<ClCompile Include="tests\different_allocator_test.cpp" />
<ClCompile Include="tests\light_flat_value_map_find_tests.cpp" />
<ClCompile Include="tests\move_only_types_tests.cpp" />
Expand Down
9 changes: 6 additions & 3 deletions SparseToDenseVector.vcxproj.filters
Original file line number Diff line number Diff line change
Expand Up @@ -38,9 +38,6 @@
<ClCompile Include="tests\tests.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="tests\test_main.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="tests\light_flat_value_map_find_tests.cpp">
<Filter>Source Files</Filter>
</ClCompile>
Expand All @@ -50,5 +47,11 @@
<ClCompile Include="tests\move_only_types_tests.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="examples\basic_example.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="tests\test_main.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
</Project>
58 changes: 58 additions & 0 deletions examples/basic_example.cpp
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;
}

0 comments on commit 6af93a2

Please sign in to comment.