HikoGUI
A low latency retained GUI
Loading...
Searching...
No Matches
id_factory.hpp
1// Copyright Take Vos 2021-2023.
2// Distributed under the Boost Software License, Version 1.0.
3// (See accompanying file LICENSE_1_0.txt or copy at https://www.boost.org/LICENSE_1_0.txt)
4
5#pragma once
6
7#include "unfair_mutex.hpp"
8#include "../utility/utility.hpp"
9#include "../macros.hpp"
10#include <mutex>
11#include <vector>
12
13hi_export_module(hikogui.concurrency.id_factory);
14
15hi_export namespace hi { inline namespace v1 {
16
24template<std::unsigned_integral T>
26public:
27 using value_type = T;
28
29 id_factory() = default;
30 id_factory(id_factory const &) = delete;
31 id_factory(id_factory &&) = delete;
32 id_factory &operator=(id_factory const &) = delete;
33 id_factory &operator=(id_factory &&) = delete;
34
40 [[nodiscard]] value_type acquire() noexcept
41 {
42 auto expected = _released_count.load(std::memory_order::relaxed);
43 if (expected != 0) {
44 // There MAY be released IDs.
45
46 if (_released_count.compare_exchange_weak(expected, expected - 1, std::memory_order::acquire, std::memory_order::relaxed)) {
47 // There ARE released IDs.
48
49 // unfair_mutex::try_lock() is wait-free.
50 if (_mutex.try_lock()) {
51 // We got a lock, pop the last ID.
52 hi_axiom(not _released.empty());
53
54 // std::vector::pop_back() should be wait-free since there are no reallocations.
55 auto const tmp = _released.back();
56 _released.pop_back();
57
58 _mutex.unlock();
59 return tmp;
60
61 } else {
62 // We couldn't get a lock; access to release-stack may be slow due to reallocation.
63 // Since we didn't pop, increment the release-count again.
64 _released_count.fetch_add(1, std::memory_order::relaxed);
65 }
66 }
67 }
68
69 auto const tmp = _v.fetch_add(1, std::memory_order::relaxed) + 1;
70 hi_assert(tmp != 0, "id_factory overflow.");
71 return tmp;
72 }
73
82 void release(value_type v) noexcept
83 {
84 auto const lock = std::scoped_lock(_mutex);
85 _released.push_back(v);
86 _released_count.fetch_add(1, std::memory_order::release);
87 }
88
91 [[nodiscard]] value_type operator++() noexcept
92 {
93 return acquire();
94 }
95
96private:
97 mutable unfair_mutex _mutex = {};
99
100 std::atomic<size_t> _released_count = 0;
101 std::vector<value_type> _released = {};
102};
103
104}}
105
Definition of the unfair_mutex.
The HikoGUI namespace.
Definition array_generic.hpp:20
DOXYGEN BUG.
Definition algorithm_misc.hpp:20
A factory for unique IDs.
Definition id_factory.hpp:25
value_type operator++() noexcept
Definition id_factory.hpp:91
void release(value_type v) noexcept
Release an ID for reuse.
Definition id_factory.hpp:82
value_type acquire() noexcept
Get the next ID.
Definition id_factory.hpp:40
bool try_lock() noexcept
When try_lock() is called from a thread that already owns the lock it will return false.
Definition unfair_mutex_impl.hpp:216
T back(T... args)
T compare_exchange_weak(T... args)
T empty(T... args)
T fetch_add(T... args)
T load(T... args)
T pop_back(T... args)
T push_back(T... args)