dfx 0.1.0
Linux-based dynamic dataflow executor
Loading...
Searching...
No Matches
RecyclableIdAllocator.hpp
1// SPDX-FileCopyrightText: 2025 Vincent Leroy
2// SPDX-License-Identifier: MIT
3//
4// This file is part of dfx.
5//
6// Licensed under the MIT License. See the LICENSE file in the project root
7// for full license information.
8
9#pragma once
10
11// Standard includes
12#include <concepts>
13#include <cstdint>
14#include <queue>
15#include <unordered_set>
16
17// Project includes
18#include "Exception.hpp"
19
20namespace dfx::Utils
21{
76template<std::integral T>
78{
79public:
81 using value_type = T;
82
83private:
88 using FreeIdList = std::priority_queue<value_type, std::vector<value_type>, std::greater<value_type>>;
89
90public:
99 value_type next() noexcept
100 {
101 value_type id;
102
103 if (_freeIds.empty())
104 id = _nextId++;
105 else
106 {
107 id = _freeIds.top();
108 _freeIds.pop();
109 _freedIds.erase(id);
110 }
111
112 ++_activeCount;
113 return id;
114 }
115
135 {
136 // Ignore invalid frees (id was never allocated)
137 if (id >= _nextId)
138 return ;
139
140 // Prevent double-free
141 if (_freedIds.contains(id))
142 return ;
143
144 --_activeCount;
145
146 if (_activeCount == 0) // Everything has been released — full reset
147 return reset();
148
149 if (_nextId == id + 1)
150 --_nextId; // Reclaim end-of-sequence ID without heap use
151 else
152 {
153 _freeIds.push(id);
154 _freedIds.insert(id);
155 }
156 }
157
180 {
181 if (id >= _nextId)
182 {
183 // Fill the gap from _nextId to id
184 for (auto i = _nextId; i < id; ++i)
185 {
186 _freeIds.push(i);
187 _freedIds.insert(i);
188 }
189 _nextId = id + 1;
190 }
191 else
192 {
193 B_ASSERT(_freedIds.contains(id), "ID {} is already in use", id);
194
195 // Remove from free lists
196 _freedIds.erase(id);
197
198 // _freeIds has no direct erase, so we rebuild the heap
199 FreeIdList tmp;
200 while (!_freeIds.empty())
201 {
202 auto const v = _freeIds.top();
203 _freeIds.pop();
204 if (v != id)
205 tmp.push(v);
206 }
207
208 _freeIds.swap(tmp);
209 }
210
211 ++_activeCount;
212 }
213
225 void reset() noexcept
226 {
227 _nextId = value_type{};
228 _activeCount = 0;
229 _freeIds = {};
230 _freedIds.clear();
231 }
232
233private:
234 value_type _nextId = value_type{};
235 uint64_t _activeCount = 0;
236 FreeIdList _freeIds;
237 std::unordered_set<value_type> _freedIds;
238};
239} // !namespace dfx::Utils
Exception utilities for dfx (source-location aware exceptions, nested stacks, and safe invocation hel...
#define B_ASSERT(expr, msg,...)
Assert-like check that throws an dfx::Utils::Exception on failure.
Definition Exception.hpp:251
ID allocator that can recycle released identifiers.
Definition RecyclableIdAllocator.hpp:78
void reset() noexcept
Reset the allocator to its initial state.
Definition RecyclableIdAllocator.hpp:225
void release(value_type id)
Release an identifier back to the allocator.
Definition RecyclableIdAllocator.hpp:134
void reserve(value_type id)
Mark an identifier as in-use without returning it from next().
Definition RecyclableIdAllocator.hpp:179
T value_type
Type used for allocated identifiers.
Definition RecyclableIdAllocator.hpp:81
value_type next() noexcept
Allocate and return an identifier.
Definition RecyclableIdAllocator.hpp:99
Definition SystemConfigCommandHandler.hpp:15