mirror of
				https://github.com/Zelda64Recomp/Zelda64Recomp.git
				synced 2025-10-30 08:03:03 +00:00 
			
		
		
		
	Remove slotmap submodule and integrate header directly after submodule URL changed (#645)
	
		
			
	
		
	
	
		
	
		
			Some checks failed
		
		
	
	
		
			
				
	
				validate-internal / build (push) Has been cancelled
				
			
		
		
	
	
				
					
				
			
		
			Some checks failed
		
		
	
	validate-internal / build (push) Has been cancelled
				
			This commit is contained in:
		
							parent
							
								
									bb7030bcd1
								
							
						
					
					
						commit
						a215103002
					
				
					 5 changed files with 1625 additions and 5 deletions
				
			
		
							
								
								
									
										4
									
								
								.gitmodules
									
										
									
									
										vendored
									
									
								
							
							
						
						
									
										4
									
								
								.gitmodules
									
										
									
									
										vendored
									
									
								
							|  | @ -19,6 +19,4 @@ | |||
| [submodule "Zelda64RecompSyms"] | ||||
| 	path = Zelda64RecompSyms | ||||
| 	url = https://github.com/Zelda64Recomp/Zelda64RecompSyms | ||||
| [submodule "lib/slot_map"] | ||||
| 	path = lib/slot_map | ||||
| 	url = https://github.com/SergeyMakeev/slot_map | ||||
| 
 | ||||
|  |  | |||
|  | @ -222,7 +222,7 @@ target_include_directories(Zelda64Recompiled PRIVATE | |||
|     ${CMAKE_SOURCE_DIR}/lib/rt64/src/render | ||||
|     ${CMAKE_SOURCE_DIR}/lib/freetype-windows-binaries/include | ||||
|     ${CMAKE_SOURCE_DIR}/lib/rt64/src/contrib/nativefiledialog-extended/src/include | ||||
|     ${CMAKE_SOURCE_DIR}/lib/slot_map/slot_map | ||||
|     ${CMAKE_SOURCE_DIR}/lib/SlotMap | ||||
|     ${CMAKE_BINARY_DIR}/shaders | ||||
|     ${CMAKE_CURRENT_BINARY_DIR} | ||||
| ) | ||||
|  |  | |||
							
								
								
									
										257
									
								
								lib/SlotMap/README.md
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										257
									
								
								lib/SlotMap/README.md
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,257 @@ | |||
| This file is originally from the repo: https://github.com/SergeyMakeev/SlotMap | ||||
| 
 | ||||
| The original license and README are as follows: | ||||
| ``` | ||||
| MIT License | ||||
| 
 | ||||
| Copyright (c) 2022 Sergey Makeev | ||||
| 
 | ||||
| Permission is hereby granted, free of charge, to any person obtaining a copy | ||||
| of this software and associated documentation files (the "Software"), to deal | ||||
| in the Software without restriction, including without limitation the rights | ||||
| to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||||
| copies of the Software, and to permit persons to whom the Software is | ||||
| furnished to do so, subject to the following conditions: | ||||
| 
 | ||||
| The above copyright notice and this permission notice shall be included in all | ||||
| copies or substantial portions of the Software. | ||||
| 
 | ||||
| THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||||
| IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||||
| FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||||
| AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||||
| LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||||
| OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||||
| SOFTWARE. | ||||
| ``` | ||||
| # Slot Map | ||||
| 
 | ||||
| [](https://github.com/SergeyMakeev/slot_map/actions) | ||||
| [](https://ci.appveyor.com/project/SergeyMakeev/slot-map) | ||||
| [](https://codecov.io/gh/SergeyMakeev/slot_map) | ||||
|  | ||||
| 
 | ||||
| A Slot Map is a high-performance associative container with persistent unique keys to access stored values. Upon insertion, a key is returned that can be used to later access or remove the values. Insertion, removal, and access are all guaranteed to take `O(1)` time (best, worst, and average case)   | ||||
| Great for storing collections of objects that need stable, safe references but have no clear ownership. | ||||
| 
 | ||||
| The difference between a `std::unordered_map` and a `dod::slot_map` is that the slot map generates and returns the key when inserting a value. A key is always unique and will only refer to the value that was inserted. | ||||
| 
 | ||||
|   Usage example: | ||||
|   ```cpp | ||||
|   slot_map<std::string> strings; | ||||
|   auto red = strings.emplace("Red"); | ||||
|   auto green = strings.emplace("Green"); | ||||
|   auto blue = strings.emplace("Blue"); | ||||
| 
 | ||||
|   const std::string* val1 = strings.get(red); | ||||
|   if (val1) | ||||
|   { | ||||
|     printf("red = '%s'\n", val1->c_str()); | ||||
|   } | ||||
| 
 | ||||
|   strings.erase(green); | ||||
|   printf("%d\n", strings.has(green)); | ||||
|   printf("%d\n", strings.has(blue)); | ||||
|   ``` | ||||
| 
 | ||||
|   Output: | ||||
|   ``` | ||||
|   red = 'Red' | ||||
|   0 | ||||
|   1 | ||||
|   ``` | ||||
|    | ||||
| # Implementation details | ||||
| 
 | ||||
| The slot map container will allocate memory in pages (default page size = 4096 elements) to avoid memory spikes during growth and be able to deallocate pages that are no longer needed. | ||||
| Also, the page-based memory allocator is very important since it guarantees "pointers stability"; hence, we never move values in memory. | ||||
| 
 | ||||
| 
 | ||||
| Keys are always uses `uint64_t/uint32_t` (configurable) and technically typless, but we "artificially" make them typed to get a few extra compile-time checks.   | ||||
| i.e., the following code will produce a compiler error | ||||
| ```cpp | ||||
| slot_map<std::string> strings; | ||||
| slot_map<int> numbers; | ||||
| slot_map<int>::key numKey = numbers.emplace(3); | ||||
| const std::string* value = strings.get(numKey);   //  <---- can not use slot_map<int>::key to index slot_map<std::string> ! | ||||
| ``` | ||||
| 
 | ||||
| The keys can be converted to/from their numeric types if you do not need additional type checks. | ||||
| ```cpp | ||||
| slot_map<int> numbers; | ||||
| slot_map<int>::key numKey = numbers.emplace(3); | ||||
| uint64_t rawKey = numKey;  // convert to numeric type (like cast pointer to void*) | ||||
| ... | ||||
| slot_map<int>::key numKey2{rawKey}; // create key from numeric type | ||||
| ``` | ||||
| 
 | ||||
| When a slot is reused, its version is automatically incremented (to invalidate all existing keys that refers to the same slot). | ||||
| But since we only use 20-bits *(10-bits for 32 bit keys)* for version counter, there is a possibility that the version counter will wrap around, | ||||
| and a new item will get the same key as a removed item. | ||||
| 
 | ||||
| To mitigate this potential issue, once the version counter overflows, we disable that slot so that no new keys are returned for this slot | ||||
| (this gives us a guarantee that there are no key collisions) | ||||
| 
 | ||||
| To prevent version overflow from happening too often, we need to ensure that we don't reuse the same slot too often. | ||||
| So we do not reuse recently freed slot-indices as long as their number is below a certain threshold (`kMinFreeIndices = 64`). | ||||
| 
 | ||||
| Keys also can carry a few extra bits of information provided by a user that we called `tag`.   | ||||
| That might be handy to add application-specific data to keys. | ||||
| 
 | ||||
| For example: | ||||
| ```cpp | ||||
|   slot_map<std::string> strings; | ||||
|   auto red = strings.emplace("Red"); | ||||
|   red.set_tag(13); | ||||
|    | ||||
|   auto tag = red.get_tag(); | ||||
|   assert(tag == 13); | ||||
| ``` | ||||
| 
 | ||||
| Here is how a key structure looks like internally | ||||
| 
 | ||||
| 64-bit key type | ||||
| 
 | ||||
| | Component      |  Number of bits        | | ||||
| | ---------------|------------------------| | ||||
| | tag            |  12                    | | ||||
| | version        |  20 (0..1,048,575      | | ||||
| | index          |  32 (0..4,294,967,295) | | ||||
| 
 | ||||
| 32-bit key type | ||||
| 
 | ||||
| | Component      |  Number of bits     | | ||||
| | ---------------|---------------------| | ||||
| | tag            |  2                  | | ||||
| | version        |  10 (0..1023)       | | ||||
| | index          |  20 (0..1,048,575)  | | ||||
| 
 | ||||
| Note: To use your custom memory allocator define `SLOT_MAP_ALLOC`/`SLOT_MAP_FREE` before including `"slot_map.h"` | ||||
| 
 | ||||
| ```cpp | ||||
| #define SLOT_MAP_ALLOC(sizeInBytes, alignment) aligned_alloc(alignment, sizeInBytes) | ||||
| #define SLOT_MAP_FREE(ptr) free(ptr) | ||||
| #include "slot_map.h" | ||||
| ``` | ||||
| 
 | ||||
| 
 | ||||
| # API | ||||
|    | ||||
| `bool has_key(key k) const noexcept`   | ||||
| Returns true if the slot map contains a specific key   | ||||
|      | ||||
| `void reset()`   | ||||
| Clears the slot map and releases any allocated memory.   | ||||
| Note: By calling this function, you must guarantee that no handles are in use!   | ||||
| Otherwise calling this function might be dangerous and lead to key "collisions".   | ||||
| You might consider using "clear()" instead.   | ||||
|    | ||||
| `void clear()`   | ||||
| Clears the slot map but keeps the allocated memory for reuse.   | ||||
| Automatically increases version for all the removed elements (the same as calling "erase()" for all existing elements)   | ||||
|        | ||||
| `const T* get(key k) const noexcept`   | ||||
| If key exists returns a const pointer to the value corresponding to the given key or returns null elsewere.   | ||||
|        | ||||
| `T* get(key k)`   | ||||
| If key exists returns a pointer to the value corresponding to the given key or returns null elsewere.   | ||||
|        | ||||
| `key emplace(Args&&... args)`   | ||||
| Constructs element in-place and returns a unique key that can be used to access this value.   | ||||
|        | ||||
| `void erase(key k)`   | ||||
| Removes element (if such key exists) from the slot map.   | ||||
|        | ||||
| `std::optional<T> pop(key k)`   | ||||
| Removes element (if such key exists) from the slot map, returning the value at the key if the key was not previously removed.   | ||||
|        | ||||
| `bool empty() const noexcept`   | ||||
| Returns true if the slot map is empty.   | ||||
|     | ||||
| `size_type size() const noexcept`   | ||||
| Returns the number of elements in the slot map.   | ||||
| 
 | ||||
| `void swap(slot_map& other) noexcept`   | ||||
| Exchanges the content of the slot map by the content of another slot map object of the same type.   | ||||
|    | ||||
| `slot_map(const slot_map& other)`   | ||||
| Copy constructor   | ||||
| 
 | ||||
| `slot_map& operator=(const slot_map& other)`   | ||||
| Copy assignment   | ||||
| 
 | ||||
| `slot_map(slot_map&& other) noexcept`   | ||||
| Move constructor | ||||
| 
 | ||||
| `slot_map& operator=(slot_map&& other) noexcept`   | ||||
| Move asignment | ||||
| 
 | ||||
| 
 | ||||
| `const_values_iterator begin() const noexcept`   | ||||
| `const_values_iterator end() const noexcept`   | ||||
| Const values iterator | ||||
| 
 | ||||
| ```cpp | ||||
| for (const auto& value : slotMap) | ||||
| { | ||||
|  ... | ||||
| } | ||||
| ``` | ||||
| 
 | ||||
| `Items items() const noexcept`   | ||||
| Const key/value iterator | ||||
| 
 | ||||
| ```cpp | ||||
| for (const auto& [key, value] : slotMap.items()) | ||||
| { | ||||
| ... | ||||
| } | ||||
| ``` | ||||
|    | ||||
| # References | ||||
| 
 | ||||
|   Sean Middleditch   | ||||
|   Data Structures for Game Developers: The Slot Map, 2013   | ||||
|   https://web.archive.org/web/20180121142549/http://seanmiddleditch.com/data-structures-for-game-developers-the-slot-map/  | ||||
|    | ||||
|   Niklas Gray   | ||||
|   Building a Data-Oriented Entity System (part 1), 2014   | ||||
|   http://bitsquid.blogspot.com/2014/08/building-data-oriented-entity-system.html   | ||||
| 
 | ||||
|   Noel Llopis   | ||||
|   Managing Data Relationships, 2010   | ||||
|   https://gamesfromwithin.com/managing-data-relationships   | ||||
| 
 | ||||
|   Stefan Reinalter   | ||||
|   Adventures in data-oriented design - Part 3c: External References, 2013   | ||||
|   https://blog.molecular-matters.com/2013/07/24/adventures-in-data-oriented-design-part-3c-external-references/   | ||||
| 
 | ||||
|   Niklas Gray   | ||||
|   Managing Decoupling Part 4 - The ID Lookup Table, 2011   | ||||
|   https://bitsquid.blogspot.com/2011/09/managing-decoupling-part-4-id-lookup.html   | ||||
| 
 | ||||
|   Sander Mertens   | ||||
|   Making the most of ECS identifiers, 2020   | ||||
|   https://ajmmertens.medium.com/doing-a-lot-with-a-little-ecs-identifiers-25a72bd2647   | ||||
| 
 | ||||
|   Michele Caini   | ||||
|   ECS back and forth. Part 9 - Sparse sets and EnTT, 2020   | ||||
|   https://skypjack.github.io/2020-08-02-ecs-baf-part-9/   | ||||
| 
 | ||||
|   Andre Weissflog   | ||||
|   Handles are the better pointers, 2018   | ||||
|   https://floooh.github.io/2018/06/17/handles-vs-pointers.html   | ||||
| 
 | ||||
|   Allan Deutsch   | ||||
|   C++Now 2017: "The Slot Map Data Structure", 2017   | ||||
|   https://www.youtube.com/watch?v=SHaAR7XPtNU   | ||||
| 
 | ||||
|   Jeff Gates   | ||||
|   Init, Update, Draw - Data Arrays, 2012   | ||||
|   https://greysphere.tumblr.com/post/31601463396/data-arrays   | ||||
|    | ||||
|   Niklas Gray   | ||||
|   Data Structures Part 1: Bulk Data, 2019   | ||||
|   https://ourmachinery.com/post/data-structures-part-1-bulk-data/   | ||||
|    | ||||
|    | ||||
							
								
								
									
										1366
									
								
								lib/SlotMap/slot_map.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										1366
									
								
								lib/SlotMap/slot_map.h
									
										
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load diff
											
										
									
								
							|  | @ -1 +0,0 @@ | |||
| Subproject commit b8ac8ebd89aa1cd18f20ce6e4ad1cac716f1933f | ||||
		Loading…
	
	Add table
		
		Reference in a new issue
	
	 Wiseguy
						Wiseguy