/* * charybdis: 21st Century IRC++d * util.h: Miscellaneous utilities * * Copyright (C) 2016 Charybdis Development Team * Copyright (C) 2016 Jason Volk * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice is present in all copies. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. * */ #pragma once #define HAVE_IRCD_ALLOCATOR_H namespace ircd { struct allocator { template struct fixed; }; template struct allocator::fixed { struct allocator; using word_t = unsigned long long; size_t last { 0 }; std::array avail {{ 0 }}; std::array buf alignas(16); static constexpr uint word_bytes { sizeof(word_t) }; static constexpr uint word_bits { word_bytes * 8 }; static uint byte(const uint &i) { return i / word_bits; } static uint bit(const uint &i) { return i % word_bits; } static word_t mask(const uint &pos) { return word_t(1) << bit(pos); } bool test(const uint &pos) const { return avail[byte(pos)] & mask(pos); } void bts(const uint &pos) { avail[byte(pos)] |= mask(pos); } void btc(const uint &pos) { avail[byte(pos)] &= ~mask(pos); } uint next(const size_t &n) const; allocator operator()(); operator allocator(); }; template struct allocator::fixed::allocator { using value_type = T; using pointer = T *; using const_pointer = const T *; using reference = T &; using const_reference = const T &; using size_type = std::size_t; using difference_type = std::ptrdiff_t; template struct rebind { using other = typename fixed::allocator; }; size_type max_size() const { return size; } auto address(reference x) const { return &x; } auto address(const_reference x) const { return &x; } fixed *s; pointer allocate(const size_type &n, const const_pointer &hint = nullptr); void deallocate(const pointer &p, const size_type &n); allocator(fixed &) noexcept; allocator(allocator &&) = default; allocator(const allocator &) = default; template allocator(const typename fixed::allocator &) noexcept; }; template bool operator==(const typename allocator::fixed::allocator &, const typename allocator::fixed::allocator &); template bool operator!=(const typename allocator::fixed::allocator &, const typename allocator::fixed::allocator &); } // namespace ircd template ircd::allocator::fixed::allocator::allocator(fixed &s) noexcept :s{&s} {} template template ircd::allocator::fixed::allocator::allocator(const typename fixed::allocator &s) noexcept :s { reinterpret_cast::state *>(s.s) } {} template void ircd::allocator::fixed::allocator::deallocate(const pointer &p, const size_type &n) { const uint pos(p - s->buf.data()); for(size_t i(0); i < n; ++i) s->btc(pos + i); } template typename ircd::allocator::fixed::allocator::pointer ircd::allocator::fixed::allocator::allocate(const size_type &n, const const_pointer &hint) { const auto next(s->next(n)); if(unlikely(next >= size)) // No block of n was found anywhere (next is past-the-end) throw std::bad_alloc(); for(size_t i(0); i < n; ++i) s->bts(next + i); s->last = next + n; return s->buf.data() + next; } template typename ircd::allocator::fixed::allocator ircd::allocator::fixed::operator()() { return { *this }; } template ircd::allocator::fixed::operator allocator() { return { *this }; } template uint ircd::allocator::fixed::next(const size_t &n) const { uint ret(last), rem(n); for(; ret < size && rem; ++ret) if(test(ret)) rem = n; else --rem; if(likely(!rem)) return ret - n; for(ret = 0, rem = n; ret < last && rem; ++ret) if(test(ret)) rem = n; else --rem; if(unlikely(rem)) // The allocator should throw std::bad_alloc if !rem return size; return ret - n; } template bool ircd::operator==(const typename allocator::fixed::allocator &a, const typename allocator::fixed::allocator &b) { return &a == &b; } template bool ircd::operator!=(const typename allocator::fixed::allocator &a, const typename allocator::fixed::allocator &b) { return &a != &b; }