Download unify/engine/core/handle.h from Snapkitty/repoverse: direct link, hf CLI and curl.
- Browser
- Download file 4.05 kB
-
https://huggingface.co/Snapkitty/repoverse/resolve/main/unify/engine/core/handle.h
- Command line
-
hf download hf://Snapkitty/repoverse/unify/engine/core/handle.h
-
curl -L -o handle.h https://huggingface.co/Snapkitty/repoverse/resolve/main/unify/engine/core/handle.h
4.05 kB
| namespace unify { | |
| /// Generational handle: 24-bit slot index + 8-bit generation, packed in 32 bits. | |
| /// Handles are what cross subsystem and script boundaries; raw pointers never do. | |
| /// A handle whose generation no longer matches its slot is stale and fails validation. | |
| template <typename Tag> | |
| struct Handle { | |
| uint32_t bits = 0; // 0 == null (generation 0 is never issued) | |
| static constexpr uint32_t kIndexBits = 24; | |
| static constexpr uint32_t kIndexMask = (1u << kIndexBits) - 1; | |
| static Handle make(uint32_t index, uint8_t gen) { return Handle{(uint32_t(gen) << kIndexBits) | (index & kIndexMask)}; } | |
| uint32_t index() const { return bits & kIndexMask; } | |
| uint8_t generation() const { return uint8_t(bits >> kIndexBits); } | |
| bool is_null() const { return bits == 0; } | |
| explicit operator bool() const { return bits != 0; } | |
| bool operator==(const Handle& o) const { return bits == o.bits; } | |
| bool operator!=(const Handle& o) const { return bits != o.bits; } | |
| bool operator<(const Handle& o) const { return bits < o.bits; } | |
| }; | |
| struct EntityTag {}; | |
| struct TextureTag {}; | |
| struct AudioTag {}; | |
| struct PhysicsBodyTag {}; | |
| struct BufferTag {}; | |
| struct KernelTag {}; | |
| struct AssetTag {}; | |
| struct ClipTag {}; | |
| using EntityHandle = Handle<EntityTag>; | |
| using TextureHandle = Handle<TextureTag>; | |
| using AudioHandle = Handle<AudioTag>; // a playing voice | |
| using PhysicsBodyHandle = Handle<PhysicsBodyTag>; | |
| using BufferHandle = Handle<BufferTag>; | |
| using KernelHandle = Handle<KernelTag>; | |
| using AssetHandle = Handle<AssetTag>; | |
| /// Issues and validates generational handles over a dense slot range with a free list. | |
| /// Free order is LIFO and fully deterministic, so the same sequence of alloc/free calls | |
| /// always yields the same handles (required for deterministic replay and save states). | |
| template <typename H> | |
| class HandlePool { | |
| public: | |
| H allocate() { | |
| uint32_t index; | |
| if (!free_.empty()) { | |
| index = free_.back(); | |
| free_.pop_back(); | |
| } else { | |
| index = uint32_t(gens_.size()); | |
| assert(index <= H::kIndexMask); | |
| gens_.push_back(1); | |
| live_.push_back(0); | |
| } | |
| live_[index] = 1; | |
| alive_++; | |
| return H::make(index, gens_[index]); | |
| } | |
| bool valid(H h) const { | |
| uint32_t i = h.index(); | |
| return !h.is_null() && i < gens_.size() && live_[i] && gens_[i] == h.generation(); | |
| } | |
| bool release(H h) { | |
| if (!valid(h)) return false; | |
| uint8_t& g = gens_[h.index()]; | |
| g = uint8_t(g + 1); | |
| if (g == 0) g = 1; // skip 0 so a recycled slot never re-issues null | |
| live_[h.index()] = 0; | |
| free_.push_back(h.index()); | |
| alive_--; | |
| return true; | |
| } | |
| /// Handle currently occupying a slot (for iteration); null if the slot is free. | |
| H at(uint32_t index) const { return index < gens_.size() && live_[index] ? H::make(index, gens_[index]) : H{}; } | |
| uint32_t alive() const { return alive_; } | |
| uint32_t capacity() const { return uint32_t(gens_.size()); } | |
| void reserve(size_t n) { gens_.reserve(n); free_.reserve(n); live_.reserve(n); } | |
| /// Raw state for save/restore: generations, liveness and free-list order. | |
| struct State { std::vector<uint8_t> gens; std::vector<uint8_t> live; std::vector<uint32_t> free; uint32_t alive = 0; }; | |
| State save() const { return {gens_, live_, free_, alive_}; } | |
| void load(const State& s) { gens_ = s.gens; live_ = s.live; free_ = s.free; alive_ = s.alive; } | |
| void clear() { gens_.clear(); live_.clear(); free_.clear(); alive_ = 0; } | |
| private: | |
| std::vector<uint8_t> gens_; | |
| std::vector<uint8_t> live_; | |
| std::vector<uint32_t> free_; | |
| uint32_t alive_ = 0; | |
| }; | |
| } // namespace unify | |
| namespace std { | |
| template <typename T> | |
| struct hash<unify::Handle<T>> { | |
| size_t operator()(const unify::Handle<T>& h) const noexcept { return std::hash<uint32_t>()(h.bits); } | |
| }; | |
| } // namespace std | |