7#if !defined(ASYNC_MQTT_UTIL_VALUE_ALLOCATOR_HPP)
8#define ASYNC_MQTT_UTIL_VALUE_ALLOCATOR_HPP
13#include <boost/multi_index_container.hpp>
14#include <boost/multi_index/ordered_index.hpp>
15#include <boost/multi_index/identity.hpp>
17#include <async_mqtt/util/optional.hpp>
21namespace mi = boost::multi_index;
24class value_allocator {
27 class value_interval {
29 explicit value_interval(value_type v) : low_{v}, high_{v} {}
30 value_interval(value_type l, value_type h) : low_{l}, high_{h} {}
54 friend bool operator<(value_interval
const& lhs, value_interval
const& rhs) {
56 (lhs.low_ < rhs.low_) &&
57 (lhs.high_ < rhs.low_);
59 value_type low()
const {
62 value_type high()
const {
66 friend std::ostream& operator<<(std::ostream& o, value_interval
const v) {
67 o <<
'[' << v.low() <<
',' << v.high() <<
']';
83 value_allocator(value_type lowest, value_type highest)
84 :lowest_{lowest}, highest_{highest} {
86 BOOST_ASSERT(std::numeric_limits<value_type>::min() <= lowest);
87 BOOST_ASSERT(highest <= std::numeric_limits<value_type>::max());
89 pool_.emplace(lowest_, highest_);
96 optional<value_type> allocate() {
97 if (pool_.empty())
return nullopt;
100 auto it = pool_.begin();
101 value_type value = it->low();
103 if (it->low() + 1 <= it->high()) {
108 BOOST_ASSERT(it->low() < highest_);
109 e = value_interval{value_type(it->low() + 1) , it->high()};
124 optional<value_type> first_vacant()
const {
125 if (pool_.empty())
return nullopt;
128 auto it = pool_.begin();
136 void deallocate(value_type value) {
137 BOOST_ASSERT(lowest_ <= value && value <= highest_);
138 auto itr = pool_.upper_bound(value_interval{value});
139 if (itr == pool_.end()) {
143 if (itr == pool_.begin()) {
145 pool_.emplace(value);
151 if (itl->high() + 1 == value) {
156 e = value_interval{itl->low(), value};
162 pool_.emplace(value);
165 else if (itr == pool_.begin()) {
169 if (value + 1 == itr->low()) {
174 e = value_interval{value, itr->high()};
180 pool_.emplace(value);
189 if (itl->high() + 1 == value) {
190 if (value + 1 == itr->low()) {
192 auto right = itr->high();
197 e = value_interval{itl->low(), right};
207 e = value_interval{itl->low(), value};
213 if (value + 1 == itr->low()) {
218 e = value_interval{value, itr->high()};
224 pool_.emplace(value);
235 bool use(value_type value) {
236 auto it = pool_.find(value_interval{value});
237 if (it == pool_.end())
return false;
239 value_interval iv = *it;
241 if (iv.low() < value) {
242 pool_.emplace(iv.low(), value - 1);
244 if (value + 1 <= iv.high()) {
245 pool_.emplace(value + 1, iv.high());
255 bool is_used(value_type value)
const {
256 auto it = pool_.find(value_interval{value});
257 return it == pool_.end();
265 pool_.emplace(lowest_, highest_);
268 std::size_t interval_count()
const {
272 std::ostream& dump(std::ostream& o) {
273 for (
auto const& e : pool_) {
279 using mi_value_interval = mi::multi_index_container<
283 mi::identity<value_interval>
287 mi_value_interval pool_;