#pragma once #include // std::aligned_storage_t #include // std::memcmp #include #include "libipc/def.h" #include "libipc/platform/detail.h" namespace ipc { using storage_id_t = std::int32_t; template struct id_type; template struct id_type<0, AlignSize> { uint_t<8> id_; id_type& operator=(storage_id_t val) { id_ = static_cast>(val); return (*this); } operator uint_t<8>() const { return id_; } }; template struct id_type : id_type<0, AlignSize> { std::aligned_storage_t data_; }; template class id_pool { static constexpr std::size_t limited_max_count() { return ipc::detail::min(large_msg_cache, (std::numeric_limits>::max)()); } public: enum : std::size_t { /* eliminate error: taking address of temporary */ max_count = limited_max_count() }; private: id_type next_[max_count]; uint_t<8> cursor_ = 0; bool prepared_ = false; public: void prepare() { if (!prepared_ && this->invalid()) this->init(); prepared_ = true; } void init() { for (storage_id_t i = 0; i < max_count;) { i = next_[i] = (i + 1); } } bool invalid() const { static id_pool inv; return std::memcmp(this, &inv, sizeof(id_pool)) == 0; } bool empty() const { return cursor_ == max_count; } storage_id_t acquire() { if (empty()) return -1; storage_id_t id = cursor_; cursor_ = next_[id]; // point to next return id; } bool release(storage_id_t id) { if (id < 0) return false; next_[id] = cursor_; cursor_ = static_cast>(id); // put it back return true; } void * at(storage_id_t id) { return &(next_[id].data_); } void const * at(storage_id_t id) const { return &(next_[id].data_); } }; template class obj_pool : public id_pool { using base_t = id_pool; public: T * at(storage_id_t id) { return reinterpret_cast(base_t::at(id)); } T const * at(storage_id_t id) const { return reinterpret_cast(base_t::at(id)); } }; } // namespace ipc