alloc: rationalise the 'arena' allocator
This commit is contained in:
parent
4e055f5f0b
commit
10d5c141f2
@ -195,10 +195,11 @@ list (
|
|||||||
alloc/fwd.hpp
|
alloc/fwd.hpp
|
||||||
alloc/allocator.cpp
|
alloc/allocator.cpp
|
||||||
alloc/allocator.hpp
|
alloc/allocator.hpp
|
||||||
alloc/arena.cpp
|
#alloc/arena.cpp
|
||||||
alloc/arena.hpp
|
#alloc/arena.hpp
|
||||||
alloc/forwarding.cpp
|
alloc/easy.hpp
|
||||||
alloc/forwarding.hpp
|
#alloc/forwarding.cpp
|
||||||
|
#alloc/forwarding.hpp
|
||||||
alloc/raw/traits.hpp
|
alloc/raw/traits.hpp
|
||||||
alloc/raw/affix.cpp
|
alloc/raw/affix.cpp
|
||||||
alloc/raw/affix.hpp
|
alloc/raw/affix.hpp
|
||||||
@ -215,6 +216,8 @@ list (
|
|||||||
alloc/raw/null.hpp
|
alloc/raw/null.hpp
|
||||||
alloc/raw/stack.cpp
|
alloc/raw/stack.cpp
|
||||||
alloc/raw/stack.hpp
|
alloc/raw/stack.hpp
|
||||||
|
alloc/std.hpp
|
||||||
|
alloc/traits.hpp
|
||||||
annotation.hpp
|
annotation.hpp
|
||||||
array/darray.hpp
|
array/darray.hpp
|
||||||
array/sarray.cpp
|
array/sarray.cpp
|
||||||
@ -521,11 +524,12 @@ if (TESTS)
|
|||||||
algo/sort
|
algo/sort
|
||||||
alloc/aligned/foreign
|
alloc/aligned/foreign
|
||||||
alloc/aligned/direct
|
alloc/aligned/direct
|
||||||
alloc/arena
|
#alloc/arena
|
||||||
#alloc/dynamic
|
#alloc/dynamic
|
||||||
|
alloc/easy
|
||||||
alloc/linear
|
alloc/linear
|
||||||
alloc/stack
|
alloc/stack
|
||||||
alloc/forwarding
|
#alloc/forwarding
|
||||||
affine
|
affine
|
||||||
array/darray
|
array/darray
|
||||||
array/sarray
|
array/sarray
|
||||||
|
279
alloc/easy.hpp
Normal file
279
alloc/easy.hpp
Normal file
@ -0,0 +1,279 @@
|
|||||||
|
/*
|
||||||
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||||
|
*
|
||||||
|
* Copyright 2018 Danny Robson <danny@nerdcruft.net>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
|
||||||
|
#include "traits.hpp"
|
||||||
|
|
||||||
|
#include "../std.hpp"
|
||||||
|
#include "../view.hpp"
|
||||||
|
#include "../memory/buffer/traits.hpp"
|
||||||
|
|
||||||
|
#include <utility>
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
|
||||||
|
namespace cruft::alloc::easy {
|
||||||
|
/// Provides an interface suitable for allocating and constructing typed
|
||||||
|
/// objects using a reference to an existing allocator.
|
||||||
|
template <typename AllocatorT>
|
||||||
|
class passthrough {
|
||||||
|
public:
|
||||||
|
explicit passthrough (AllocatorT &_allocator)
|
||||||
|
: m_allocator (_allocator)
|
||||||
|
{ ; }
|
||||||
|
|
||||||
|
|
||||||
|
/// Allocate, construct, and return a type `U` using memory from the
|
||||||
|
/// underlying allocator with the default alignment.
|
||||||
|
template <typename U, typename ...Args>
|
||||||
|
U*
|
||||||
|
acquire (Args&&...args)&
|
||||||
|
{
|
||||||
|
auto memory = m_allocator.allocate (sizeof (U), alignof (U));
|
||||||
|
try {
|
||||||
|
return new (memory.data ()) U (std::forward<Args> (args)...);
|
||||||
|
} catch (...) {
|
||||||
|
m_allocator.deallocate (memory.data (), sizeof (U), alignof (U));
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// Destruct and deallocate an object which has previously been
|
||||||
|
/// allocated through this interface.
|
||||||
|
template <typename U>
|
||||||
|
void release (U *ptr)
|
||||||
|
{
|
||||||
|
ptr->~U ();
|
||||||
|
m_allocator.deallocate (ptr, sizeof (U), alignof (U));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// Create an object of type `U` using `acquire` and wrap the result
|
||||||
|
/// in a std::unique_ptr that will call release on this interface at d
|
||||||
|
/// struction time.
|
||||||
|
template <typename U, typename ...Args>
|
||||||
|
auto unique (Args &&...args)&
|
||||||
|
{
|
||||||
|
struct deleter {
|
||||||
|
passthrough &m_owner;
|
||||||
|
|
||||||
|
void operator() (U *ptr)
|
||||||
|
{ return m_owner.release (ptr); }
|
||||||
|
};
|
||||||
|
|
||||||
|
return std::unique_ptr (
|
||||||
|
acquire (std::forward<Args> (args)...),
|
||||||
|
deleter {*this}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
decltype (auto)
|
||||||
|
offset (T const *ptr)
|
||||||
|
{
|
||||||
|
return m_allocator.offset (ptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
decltype(auto) data (void) { return m_allocator.data (); }
|
||||||
|
decltype(auto) begin (void) { return m_allocator.begin (); }
|
||||||
|
decltype(auto) end (void) { return m_allocator.end (); }
|
||||||
|
|
||||||
|
decltype(auto) remain (void) { return m_allocator.remain (); }
|
||||||
|
|
||||||
|
decltype(auto) offset (void const *ptr) { return m_allocator.offset (ptr); }
|
||||||
|
|
||||||
|
|
||||||
|
private:
|
||||||
|
AllocatorT &m_allocator;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/// An interfaces that manages an allocator and a backing store, and
|
||||||
|
/// provides a simple interface for constructing arbitrary objects using
|
||||||
|
/// the child objects.
|
||||||
|
template <
|
||||||
|
typename AllocatorT,
|
||||||
|
typename = std::enable_if_t<is_allocator_v<AllocatorT>>
|
||||||
|
>
|
||||||
|
class backed {
|
||||||
|
public:
|
||||||
|
template <typename BufferT, typename ...Args>
|
||||||
|
explicit backed (BufferT &_buffer, Args&&...args)
|
||||||
|
: m_allocator (_buffer, std::forward<Args> (args)...)
|
||||||
|
{ ; }
|
||||||
|
|
||||||
|
|
||||||
|
/// Allocate, construct, and return a type `U` using memory from the
|
||||||
|
/// underlying allocator with the default alignment.
|
||||||
|
template <typename U, typename ...Args>
|
||||||
|
U*
|
||||||
|
acquire (Args&&...args)&
|
||||||
|
{
|
||||||
|
auto memory = m_allocator.allocate (sizeof (U), alignof (U));
|
||||||
|
try {
|
||||||
|
return new (memory.data ()) U (std::forward<Args> (args)...);
|
||||||
|
} catch (...) {
|
||||||
|
m_allocator.deallocate (memory.data (), memory.size (), alignof (U));
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// Destruct and deallocate an object which has previously been
|
||||||
|
/// allocated through this interface.
|
||||||
|
template <typename U>
|
||||||
|
void release (U *ptr)
|
||||||
|
{
|
||||||
|
ptr->~U ();
|
||||||
|
m_allocator.deallocate (
|
||||||
|
reinterpret_cast<u08*> (ptr),
|
||||||
|
sizeof (U),
|
||||||
|
alignof (U)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
cruft::view<T*>
|
||||||
|
array (std::size_t count)
|
||||||
|
{
|
||||||
|
auto mem = m_allocator.allocate (count * sizeof (T), alignof (T)).template cast<T*> ();
|
||||||
|
try {
|
||||||
|
new (mem.data ()) T[count];
|
||||||
|
return mem;
|
||||||
|
} catch (...) {
|
||||||
|
m_allocator.deallocate (mem.data (), count * sizeof (T), alignof (T));
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/// Create an object of type `U` using `acquire` and wrap the result
|
||||||
|
/// in a std::unique_ptr that will call release on this interface at d
|
||||||
|
/// struction time.
|
||||||
|
template <typename U, typename ...Args>
|
||||||
|
auto unique (Args &&...args)&
|
||||||
|
{
|
||||||
|
struct deleter {
|
||||||
|
backed &m_owner;
|
||||||
|
|
||||||
|
void operator() (U *ptr)
|
||||||
|
{ return m_owner.release (ptr); }
|
||||||
|
};
|
||||||
|
|
||||||
|
return std::unique_ptr<U,deleter> (
|
||||||
|
acquire<U> (std::forward<Args> (args)...),
|
||||||
|
deleter {*this}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
decltype(auto) data (void) { return m_allocator.data (); }
|
||||||
|
decltype(auto) begin (void) { return m_allocator.begin (); }
|
||||||
|
decltype(auto) end (void) { return m_allocator.end (); }
|
||||||
|
|
||||||
|
decltype(auto) used (void) { return m_allocator.used (); }
|
||||||
|
decltype(auto) remain (void) { return m_allocator.remain (); }
|
||||||
|
|
||||||
|
decltype(auto) offset (void const *ptr) { return m_allocator.offset (ptr); }
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
decltype(auto)
|
||||||
|
offset (cruft::view<T*> ptr)
|
||||||
|
{
|
||||||
|
return offset (ptr.data ());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private:
|
||||||
|
AllocatorT m_allocator;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/// An interfaces that manages an allocator and a backing store, and
|
||||||
|
/// provides a simple interface for constructing arbitrary objects using
|
||||||
|
/// the child objects.
|
||||||
|
template <
|
||||||
|
typename AllocatorT,
|
||||||
|
typename BufferT,
|
||||||
|
typename = std::enable_if_t<true
|
||||||
|
//&& memory::buffer::is_buffer_v<BufferT>
|
||||||
|
&& is_allocator_v<AllocatorT>
|
||||||
|
>
|
||||||
|
>
|
||||||
|
class owned {
|
||||||
|
public:
|
||||||
|
explicit owned (BufferT &&_buffer)
|
||||||
|
: m_buffer (std::move (_buffer))
|
||||||
|
, m_allocator (m_buffer)
|
||||||
|
{ ; }
|
||||||
|
|
||||||
|
|
||||||
|
/// Allocate, construct, and return a type `U` using memory from the
|
||||||
|
/// underlying allocator with the default alignment.
|
||||||
|
template <typename U, typename ...Args>
|
||||||
|
U*
|
||||||
|
acquire (Args&&...args)&
|
||||||
|
{
|
||||||
|
auto memory = m_allocator.allocate (sizeof (U), alignof (U));
|
||||||
|
try {
|
||||||
|
return new (memory.data ()) U (std::forward<Args> (args)...);
|
||||||
|
} catch (...) {
|
||||||
|
m_allocator.deallocate (memory.data (), memory.size (), alignof (U));
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// Destruct and deallocate an object which has previously been
|
||||||
|
/// allocated through this interface.
|
||||||
|
template <typename U>
|
||||||
|
void release (U *ptr)
|
||||||
|
{
|
||||||
|
ptr->~U ();
|
||||||
|
m_allocator.deallocate (
|
||||||
|
reinterpret_cast<u08*> (ptr),
|
||||||
|
sizeof (U),
|
||||||
|
alignof (U)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// Create an object of type `U` using `acquire` and wrap the result
|
||||||
|
/// in a std::unique_ptr that will call release on this interface at d
|
||||||
|
/// struction time.
|
||||||
|
template <typename U, typename ...Args>
|
||||||
|
auto unique (Args &&...args)&
|
||||||
|
{
|
||||||
|
struct deleter {
|
||||||
|
owned &m_owner;
|
||||||
|
|
||||||
|
void operator() (U *ptr)
|
||||||
|
{ return m_owner.release (ptr); }
|
||||||
|
};
|
||||||
|
|
||||||
|
return std::unique_ptr<U,deleter> (
|
||||||
|
acquire<U> (std::forward<Args> (args)...),
|
||||||
|
deleter {*this}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private:
|
||||||
|
BufferT m_buffer;
|
||||||
|
AllocatorT m_allocator;
|
||||||
|
};
|
||||||
|
};
|
@ -3,18 +3,18 @@
|
|||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||||
*
|
*
|
||||||
* Copyright 2016 Danny Robson <danny@nerdcruft.net>
|
* Copyright 2016-2018 Danny Robson <danny@nerdcruft.net>
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef CRUFT_UTIL_ALLOC_RAW_ALIGNED_DIRECT_HPP
|
#pragma once
|
||||||
#define CRUFT_UTIL_ALLOC_RAW_ALIGNED_DIRECT_HPP
|
|
||||||
|
|
||||||
|
#include "../../../std.hpp"
|
||||||
#include "../../../debug.hpp"
|
#include "../../../debug.hpp"
|
||||||
#include "../../../view.hpp"
|
#include "../../../view.hpp"
|
||||||
|
|
||||||
#include <cstddef>
|
|
||||||
#include <utility>
|
#include <utility>
|
||||||
|
|
||||||
|
|
||||||
namespace cruft::alloc::raw::aligned {
|
namespace cruft::alloc::raw::aligned {
|
||||||
/// wraps a child allocator and enforces a fixed alignment
|
/// wraps a child allocator and enforces a fixed alignment
|
||||||
template <typename ChildT>
|
template <typename ChildT>
|
||||||
@ -22,26 +22,43 @@ namespace cruft::alloc::raw::aligned {
|
|||||||
public:
|
public:
|
||||||
///////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////
|
||||||
template <typename ...Args>
|
template <typename ...Args>
|
||||||
direct (cruft::view<std::byte*> _data, std::size_t _alignment, Args &&...args):
|
direct (
|
||||||
m_successor (_data, std::forward<Args> (args)...),
|
cruft::view<u08*> _data,
|
||||||
m_alignment (_alignment)
|
std::size_t _alignment,
|
||||||
|
Args &&...args
|
||||||
|
)
|
||||||
|
: m_successor (_data, std::forward<Args> (args)...)
|
||||||
|
, m_alignment (_alignment)
|
||||||
{ ; }
|
{ ; }
|
||||||
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////
|
||||||
template <typename T>
|
auto allocate (std::size_t bytes)
|
||||||
auto
|
|
||||||
allocate (std::size_t count)
|
|
||||||
{
|
{
|
||||||
return m_successor.template allocate<T> (count, m_alignment);
|
return m_successor.allocate (bytes, m_alignment);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
//---------------------------------------------------------------------
|
//---------------------------------------------------------------------
|
||||||
template <typename T>
|
auto allocate (std::size_t bytes, std::size_t alignment)
|
||||||
auto
|
|
||||||
deallocate (cruft::view<T*> ptr)
|
|
||||||
{
|
{
|
||||||
return m_successor.template deallocate<T> (ptr);
|
(void)alignment;
|
||||||
|
return m_successor.allocate (bytes, m_alignment);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------
|
||||||
|
auto deallocate (u08 *ptr, std::size_t bytes, std::size_t alignment)
|
||||||
|
{
|
||||||
|
(void)alignment;
|
||||||
|
return m_successor.deallocate (ptr, bytes, m_alignment);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------
|
||||||
|
auto deallocate (u08 *ptr, std::size_t bytes)
|
||||||
|
{
|
||||||
|
return m_successor.deallocate (ptr, bytes, m_alignment);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -82,5 +99,3 @@ namespace cruft::alloc::raw::aligned {
|
|||||||
std::size_t m_alignment;
|
std::size_t m_alignment;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
|
||||||
|
@ -3,11 +3,10 @@
|
|||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||||
*
|
*
|
||||||
* Copyright 2016 Danny Robson <danny@nerdcruft.net>
|
* Copyright 2016-2018 Danny Robson <danny@nerdcruft.net>
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef CRUFT_UTIL_ALLOC_RAW_ALIGNED_OFFSET_HPP
|
#pragma once
|
||||||
#define CRUFT_UTIL_ALLOC_RAW_ALIGNED_OFFSET_HPP
|
|
||||||
|
|
||||||
#include "direct.hpp"
|
#include "direct.hpp"
|
||||||
|
|
||||||
@ -15,9 +14,9 @@
|
|||||||
#include "../../../pointer.hpp"
|
#include "../../../pointer.hpp"
|
||||||
#include "../../../debug.hpp"
|
#include "../../../debug.hpp"
|
||||||
|
|
||||||
#include <cstddef>
|
|
||||||
#include <utility>
|
#include <utility>
|
||||||
|
|
||||||
|
|
||||||
namespace cruft::alloc::raw::aligned {
|
namespace cruft::alloc::raw::aligned {
|
||||||
/// wraps a child allocator and enforces a fixed alignment that is
|
/// wraps a child allocator and enforces a fixed alignment that is
|
||||||
/// independant of the alignment of the provided source buffer.
|
/// independant of the alignment of the provided source buffer.
|
||||||
@ -45,11 +44,11 @@ namespace cruft::alloc::raw::aligned {
|
|||||||
class foreign {
|
class foreign {
|
||||||
public:
|
public:
|
||||||
template <typename ...Args>
|
template <typename ...Args>
|
||||||
foreign (cruft::view<std::byte*> _data, std::size_t _alignment, Args &&...args):
|
foreign (cruft::view<u08*> _data, std::size_t _alignment, Args &&...args):
|
||||||
m_successor (
|
m_successor (
|
||||||
view<std::byte*> {
|
view<u08*> {
|
||||||
reinterpret_cast<std::byte*> (_alignment),
|
reinterpret_cast<u08*> (_alignment),
|
||||||
reinterpret_cast<std::byte*> (_alignment + _data.size ()),
|
reinterpret_cast<u08*> (_alignment + _data.size ()),
|
||||||
},
|
},
|
||||||
_alignment,
|
_alignment,
|
||||||
std::forward<Args> (args)...
|
std::forward<Args> (args)...
|
||||||
@ -59,38 +58,43 @@ namespace cruft::alloc::raw::aligned {
|
|||||||
{ ; }
|
{ ; }
|
||||||
|
|
||||||
|
|
||||||
template <typename T>
|
cruft::view<u08*>
|
||||||
cruft::view<T*>
|
allocate (std::size_t bytes, std::size_t alignment)
|
||||||
allocate (std::size_t count)
|
|
||||||
{
|
{
|
||||||
auto root = m_successor.template allocate<T> (count);
|
(void)alignment;
|
||||||
auto base = root.template cast<char*> ().data ();
|
auto inner = m_successor.allocate (bytes, m_alignment);
|
||||||
|
return cruft::view { inner.begin () + m_offset, bytes };
|
||||||
// we can't use alignment cast here because it will almost
|
|
||||||
// certainly fail the tests it performs.
|
|
||||||
return { cruft::cast::ffs<T*> (base + m_offset), count };
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
auto
|
|
||||||
deallocate (cruft::view<T*> ptr)
|
|
||||||
{
|
|
||||||
auto base = ptr.template cast<char*> ();
|
|
||||||
auto next = base - m_offset;
|
|
||||||
|
|
||||||
// we can't use alignment cast here because it will almost
|
cruft::view<u08*>
|
||||||
// certainly fail the tests it performs.
|
allocate (std::size_t bytes)
|
||||||
return m_successor.template deallocate<T> (
|
{
|
||||||
cruft::view<T*> { cruft::cast::ffs<T*> (next), ptr.size () }
|
return m_successor.allocate (bytes);
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
decltype(auto)
|
||||||
|
deallocate (u08 *ptr, std::size_t bytes, std::size_t alignment)
|
||||||
|
{
|
||||||
|
CHECK_MOD (m_alignment, alignment);
|
||||||
|
return m_successor.deallocate (ptr - m_offset, bytes, alignment);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
decltype(auto)
|
||||||
|
deallocate (u08 *ptr, std::size_t bytes)
|
||||||
|
{
|
||||||
|
return m_successor.deallocate (ptr - m_offset, bytes, m_alignment);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
constexpr auto alignment (void) const noexcept { return m_alignment; }
|
constexpr auto alignment (void) const noexcept { return m_alignment; }
|
||||||
|
|
||||||
auto offset (const void *ptr) const
|
auto offset (const void *ptr) const
|
||||||
{
|
{
|
||||||
return m_successor.offset (
|
return m_successor.offset (
|
||||||
reinterpret_cast<const std::byte*> (ptr) - m_offset
|
reinterpret_cast<u08 const*> (ptr) - m_offset
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -115,5 +119,3 @@ namespace cruft::alloc::raw::aligned {
|
|||||||
std::size_t m_alignment;
|
std::size_t m_alignment;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
|
||||||
|
@ -8,6 +8,8 @@
|
|||||||
|
|
||||||
#include "linear.hpp"
|
#include "linear.hpp"
|
||||||
|
|
||||||
|
#include "../traits.hpp"
|
||||||
|
|
||||||
#include "../../pointer.hpp"
|
#include "../../pointer.hpp"
|
||||||
#include "../../debug.hpp"
|
#include "../../debug.hpp"
|
||||||
|
|
||||||
@ -15,7 +17,7 @@ using cruft::alloc::raw::linear;
|
|||||||
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
linear::linear (cruft::view<std::byte*> _data):
|
linear::linear (cruft::view<u08*> _data):
|
||||||
m_begin (_data.begin ()),
|
m_begin (_data.begin ()),
|
||||||
m_end (_data.end ()),
|
m_end (_data.end ()),
|
||||||
m_cursor (_data.begin ())
|
m_cursor (_data.begin ())
|
||||||
@ -43,7 +45,7 @@ linear::operator= (cruft::alloc::raw::linear &&rhs)
|
|||||||
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
std::byte*
|
u08*
|
||||||
linear::data (void)
|
linear::data (void)
|
||||||
{
|
{
|
||||||
return m_begin;
|
return m_begin;
|
||||||
@ -51,7 +53,7 @@ linear::data (void)
|
|||||||
|
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
const std::byte*
|
const u08*
|
||||||
linear::data (void) const
|
linear::data (void) const
|
||||||
{
|
{
|
||||||
return m_begin;
|
return m_begin;
|
||||||
@ -59,7 +61,7 @@ linear::data (void) const
|
|||||||
|
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
std::byte*
|
u08*
|
||||||
linear::begin (void)
|
linear::begin (void)
|
||||||
{
|
{
|
||||||
return m_begin;
|
return m_begin;
|
||||||
@ -67,7 +69,7 @@ linear::begin (void)
|
|||||||
|
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
const std::byte*
|
const u08*
|
||||||
linear::begin (void) const
|
linear::begin (void) const
|
||||||
{
|
{
|
||||||
return m_begin;
|
return m_begin;
|
||||||
@ -75,7 +77,7 @@ linear::begin (void) const
|
|||||||
|
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
std::byte*
|
u08*
|
||||||
linear::end (void)
|
linear::end (void)
|
||||||
{
|
{
|
||||||
return m_end;
|
return m_end;
|
||||||
@ -83,7 +85,7 @@ linear::end (void)
|
|||||||
|
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
const std::byte*
|
const u08*
|
||||||
linear::end (void) const
|
linear::end (void) const
|
||||||
{
|
{
|
||||||
return m_end;
|
return m_end;
|
||||||
@ -94,7 +96,7 @@ linear::end (void) const
|
|||||||
size_t
|
size_t
|
||||||
linear::offset (const void *_ptr) const
|
linear::offset (const void *_ptr) const
|
||||||
{
|
{
|
||||||
auto ptr = reinterpret_cast<const std::byte*> (_ptr);
|
auto ptr = reinterpret_cast<const u08*> (_ptr);
|
||||||
|
|
||||||
CHECK_GE (ptr, m_begin);
|
CHECK_GE (ptr, m_begin);
|
||||||
return ptr - m_begin;
|
return ptr - m_begin;
|
||||||
@ -131,3 +133,7 @@ linear::remain (void) const
|
|||||||
{
|
{
|
||||||
return capacity () - used ();
|
return capacity () - used ();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
static_assert (cruft::alloc::is_allocator_v<linear>);
|
||||||
|
@ -3,18 +3,20 @@
|
|||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||||
*
|
*
|
||||||
* Copyright 2015 Danny Robson <danny@nerdcruft.net>
|
* Copyright 2015-2018 Danny Robson <danny@nerdcruft.net>
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef CRUFT_UTIL_ALLOC_RAW_LINEAR_HPP
|
#pragma once
|
||||||
#define CRUFT_UTIL_ALLOC_RAW_LINEAR_HPP
|
|
||||||
|
|
||||||
|
#include "../../std.hpp"
|
||||||
#include "../../view.hpp"
|
#include "../../view.hpp"
|
||||||
#include "../../pointer.hpp"
|
#include "../../pointer.hpp"
|
||||||
|
#include "../../memory/buffer/traits.hpp"
|
||||||
|
|
||||||
#include <cstddef>
|
#include <cstddef>
|
||||||
#include <iterator>
|
#include <iterator>
|
||||||
|
|
||||||
|
|
||||||
namespace cruft::alloc::raw {
|
namespace cruft::alloc::raw {
|
||||||
// allocate progressively across a buffer without concern for deallocation.
|
// allocate progressively across a buffer without concern for deallocation.
|
||||||
// deallocation is a noop; the only way to free allocations is via reset.
|
// deallocation is a noop; the only way to free allocations is via reset.
|
||||||
@ -26,52 +28,67 @@ namespace cruft::alloc::raw {
|
|||||||
linear (linear&&);
|
linear (linear&&);
|
||||||
linear& operator= (linear&&);
|
linear& operator= (linear&&);
|
||||||
|
|
||||||
linear (cruft::view<std::byte*> _data);
|
linear (cruft::view<u08*> _data);
|
||||||
|
|
||||||
template <typename T>
|
template <
|
||||||
cruft::view<T*>
|
typename BufferT,
|
||||||
allocate (size_t count)
|
typename = std::enable_if_t<
|
||||||
|
memory::buffer::is_buffer_v<BufferT>
|
||||||
|
>
|
||||||
|
>
|
||||||
|
linear (BufferT &_buffer)
|
||||||
|
: linear (cruft::view (_buffer))
|
||||||
|
{ ; }
|
||||||
|
|
||||||
|
|
||||||
|
cruft::view<u08*>
|
||||||
|
allocate (size_t bytes)
|
||||||
{
|
{
|
||||||
auto const bytes = count * sizeof (T);
|
|
||||||
if (m_cursor + bytes > m_end)
|
if (m_cursor + bytes > m_end)
|
||||||
throw std::bad_alloc ();
|
throw std::bad_alloc ();
|
||||||
|
|
||||||
auto ptr = m_cursor;
|
auto ptr = m_cursor;
|
||||||
m_cursor += bytes;
|
m_cursor += bytes;
|
||||||
return { cruft::cast::alignment<T*> (ptr), count };
|
return { ptr, bytes };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
template <typename T>
|
cruft::view<u08*>
|
||||||
cruft::view<T*>
|
allocate (size_t bytes, std::size_t alignment)
|
||||||
allocate (size_t count, size_t alignment)
|
|
||||||
{
|
{
|
||||||
auto const bytes = count * sizeof (T);
|
auto ptr = cruft::align::up (m_cursor, alignment);
|
||||||
|
|
||||||
auto ptr = cruft::align_up (m_cursor, alignment);
|
|
||||||
if (ptr + bytes > m_end)
|
if (ptr + bytes > m_end)
|
||||||
throw std::bad_alloc ();
|
throw std::bad_alloc ();
|
||||||
|
|
||||||
m_cursor = ptr + bytes;
|
m_cursor = ptr + bytes;
|
||||||
|
|
||||||
return { cruft::cast::alignment<T*> (ptr), count };
|
return { ptr, bytes };
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
void deallocate (cruft::view<T*> ptr)
|
void deallocate (void *ptr, std::size_t bytes, std::size_t alignment)
|
||||||
{
|
{
|
||||||
(void)ptr;
|
(void)ptr;
|
||||||
|
(void)bytes;
|
||||||
|
(void)alignment;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::byte* data (void);
|
|
||||||
std::byte* begin (void);
|
|
||||||
std::byte* end (void);
|
|
||||||
std::byte* cursor (void);
|
|
||||||
|
|
||||||
const std::byte* data (void) const;
|
void deallocate (void *ptr, std::size_t bytes)
|
||||||
const std::byte* begin (void) const;
|
{
|
||||||
const std::byte* end (void) const;
|
return deallocate (ptr, bytes, alignof (std::max_align_t));
|
||||||
const std::byte* cursor (void) const;
|
}
|
||||||
|
|
||||||
|
|
||||||
|
u08* data (void);
|
||||||
|
u08* begin (void);
|
||||||
|
u08* end (void);
|
||||||
|
u08* cursor (void);
|
||||||
|
|
||||||
|
u08 const* data (void) const;
|
||||||
|
u08 const* begin (void) const;
|
||||||
|
u08 const* end (void) const;
|
||||||
|
u08 const* cursor (void) const;
|
||||||
|
|
||||||
size_t offset (const void*) const;
|
size_t offset (const void*) const;
|
||||||
|
|
||||||
@ -101,11 +118,9 @@ namespace cruft::alloc::raw {
|
|||||||
protected:
|
protected:
|
||||||
// The begin and end iterators should be constant but that interferes
|
// The begin and end iterators should be constant but that interferes
|
||||||
// with move operators so we need to leave them mutable.
|
// with move operators so we need to leave them mutable.
|
||||||
std::byte *m_begin;
|
u08 *m_begin;
|
||||||
std::byte *m_end;
|
u08 *m_end;
|
||||||
|
|
||||||
std::byte *m_cursor;
|
u08 *m_cursor;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
|
||||||
|
@ -40,7 +40,7 @@ namespace cruft::alloc::raw {
|
|||||||
|
|
||||||
// align the outgoing pointer if required
|
// align the outgoing pointer if required
|
||||||
alignment = cruft::max (MIN_ALIGNMENT, alignment);
|
alignment = cruft::max (MIN_ALIGNMENT, alignment);
|
||||||
ptr = cruft::align_up (ptr, alignment);
|
ptr = cruft::align::up (ptr, alignment);
|
||||||
|
|
||||||
// ensure we haven't overrun our allocated segment
|
// ensure we haven't overrun our allocated segment
|
||||||
if (ptr + bytes > m_end)
|
if (ptr + bytes > m_end)
|
||||||
|
34
alloc/std.hpp
Normal file
34
alloc/std.hpp
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
/*
|
||||||
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||||
|
*
|
||||||
|
* Copyright 2018 Danny Robson <danny@nerdcruft.net>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <cstddef>
|
||||||
|
|
||||||
|
namespace cruft::alloc {
|
||||||
|
template <typename ValueT, typename AllocatorT>
|
||||||
|
struct std {
|
||||||
|
using value_type = ValueT;
|
||||||
|
using size_type = std::size_t;
|
||||||
|
using difference_type = std::ptrdiff_t;
|
||||||
|
|
||||||
|
[[nodiscard]] ValueT* allocate (std::size_t n)
|
||||||
|
{
|
||||||
|
return m_allocator.allocate (n * sizeof (ValueT), alignof (ValueT));
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
deallocate (ValueT *ptr, std::size_t n)
|
||||||
|
{
|
||||||
|
m_allocator.deallocate (ptr, n * sizeof (ValueT), alignof (ValueT));
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
AllocatorT m_allocator;
|
||||||
|
};
|
||||||
|
}
|
55
alloc/traits.hpp
Normal file
55
alloc/traits.hpp
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
/*
|
||||||
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||||
|
*
|
||||||
|
* Copyright 2018 Danny Robson <danny@nerdcruft.net>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <type_traits>
|
||||||
|
|
||||||
|
|
||||||
|
namespace cruft::alloc {
|
||||||
|
///////////////////////////////////////////////////////////////////////////
|
||||||
|
/// A trait that evaluates to true if the queried type models cruft::allocator
|
||||||
|
template <
|
||||||
|
typename AllocatorT,
|
||||||
|
typename = std::void_t<>
|
||||||
|
>
|
||||||
|
struct is_allocator
|
||||||
|
: public std::false_type
|
||||||
|
{ };
|
||||||
|
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------
|
||||||
|
template <typename AllocatorT>
|
||||||
|
struct is_allocator<AllocatorT,
|
||||||
|
std::void_t<
|
||||||
|
// Provides aligned and unaligned allocation
|
||||||
|
decltype(std::declval<AllocatorT> ().allocate (0 )),
|
||||||
|
decltype(std::declval<AllocatorT> ().allocate (0, 0)),
|
||||||
|
|
||||||
|
//// Provides aligned an unaligned deallocation
|
||||||
|
decltype(std::declval<AllocatorT> ().deallocate (nullptr, 0)),
|
||||||
|
decltype(std::declval<AllocatorT> ().deallocate (nullptr, 0, 0)),
|
||||||
|
|
||||||
|
//// Provides capacity/used/remain
|
||||||
|
decltype(std::declval<AllocatorT> ().capacity ()),
|
||||||
|
decltype(std::declval<AllocatorT> ().used ()),
|
||||||
|
decltype(std::declval<AllocatorT> ().remain ()),
|
||||||
|
|
||||||
|
decltype(std::declval<AllocatorT> ().begin ()),
|
||||||
|
decltype(std::declval<AllocatorT> ().end ()),
|
||||||
|
|
||||||
|
void
|
||||||
|
>
|
||||||
|
> : public std::true_type
|
||||||
|
{ };
|
||||||
|
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------
|
||||||
|
template <typename AllocatorT>
|
||||||
|
constexpr auto is_allocator_v = is_allocator<AllocatorT>::value;
|
||||||
|
}
|
@ -89,8 +89,8 @@ paged::apply_prot (cruft::view<value_type*> region, int prot)
|
|||||||
// bump the request up to page aligned
|
// bump the request up to page aligned
|
||||||
static_assert (sizeof (value_type) == 1);
|
static_assert (sizeof (value_type) == 1);
|
||||||
auto const alignment = pagesize ();
|
auto const alignment = pagesize ();
|
||||||
auto const first = align_down (region.begin (), alignment);
|
auto const first = align::down (region.begin (), alignment);
|
||||||
auto const last = align_up (region.end (), alignment);
|
auto const last = align::up (region.end (), alignment);
|
||||||
|
|
||||||
if (MAP_FAILED == mmap (first, last - first, prot,
|
if (MAP_FAILED == mmap (first, last - first, prot,
|
||||||
MAP_FIXED | MAP_PRIVATE | MAP_ANONYMOUS,
|
MAP_FIXED | MAP_PRIVATE | MAP_ANONYMOUS,
|
||||||
|
@ -8,6 +8,8 @@
|
|||||||
|
|
||||||
#include "simple.hpp"
|
#include "simple.hpp"
|
||||||
|
|
||||||
|
#include "traits.hpp"
|
||||||
|
|
||||||
using cruft::memory::buffer::simple;
|
using cruft::memory::buffer::simple;
|
||||||
|
|
||||||
|
|
||||||
@ -26,3 +28,7 @@ simple::value_type* simple::end (void)& { return begin () + m_size; }
|
|||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
simple::value_type const* simple::begin (void) const& { return m_base.get (); }
|
simple::value_type const* simple::begin (void) const& { return m_base.get (); }
|
||||||
simple::value_type const* simple::end (void) const& { return begin () + m_size; }
|
simple::value_type const* simple::end (void) const& { return begin () + m_size; }
|
||||||
|
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
static_assert (cruft::memory::buffer::is_buffer_v<cruft::memory::buffer::simple>);
|
||||||
|
@ -48,7 +48,7 @@ namespace cruft::memory::buffer {
|
|||||||
std::size_t capacity (void) const;
|
std::size_t capacity (void) const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::unique_ptr<u08> m_base;
|
std::unique_ptr<u08[]> m_base;
|
||||||
std::size_t m_size;
|
std::size_t m_size;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
38
pointer.hpp
38
pointer.hpp
@ -12,11 +12,11 @@
|
|||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
|
|
||||||
|
|
||||||
namespace cruft {
|
namespace cruft::align {
|
||||||
///////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////
|
||||||
/// round the pointer upwards to satisfy the provided alignment
|
/// round the pointer upwards to satisfy the provided alignment
|
||||||
constexpr inline uintptr_t
|
constexpr inline uintptr_t
|
||||||
align_up (uintptr_t ptr, size_t alignment)
|
up (uintptr_t ptr, size_t alignment)
|
||||||
{
|
{
|
||||||
// we perform this as two steps to avoid unnecessarily incrementing when
|
// we perform this as two steps to avoid unnecessarily incrementing when
|
||||||
// remainder is zero.
|
// remainder is zero.
|
||||||
@ -30,23 +30,23 @@ namespace cruft {
|
|||||||
/// round the pointer upwards to satisfy the provided alignment
|
/// round the pointer upwards to satisfy the provided alignment
|
||||||
template <typename T>
|
template <typename T>
|
||||||
constexpr T*
|
constexpr T*
|
||||||
align_up (T *_ptr, size_t alignment)
|
up (T *ptr, size_t alignment)
|
||||||
{
|
{
|
||||||
// we perform this as two steps to avoid unnecessarily incrementing when
|
// we perform this as two steps to avoid unnecessarily incrementing when
|
||||||
// remainder is zero.
|
// remainder is zero.
|
||||||
return reinterpret_cast<T*>(
|
return reinterpret_cast<T*>(
|
||||||
align_up (reinterpret_cast<uintptr_t> (_ptr), alignment)
|
up (reinterpret_cast<uintptr_t> (ptr), alignment)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
///------------------------------------------------------------------------
|
//-------------------------------------------------------------------------
|
||||||
/// round the pointer upwards to the nearest valid alignment for T
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
constexpr auto
|
constexpr T*
|
||||||
align_up (T *t)
|
up (T *ptr, std::align_val_t _alignment)
|
||||||
{
|
{
|
||||||
return align_up (t, alignof (T));
|
auto alignment = std::underlying_type_t<decltype(_alignment)> (_alignment);
|
||||||
|
return up (ptr, alignment);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -54,15 +54,25 @@ namespace cruft {
|
|||||||
/// round the pointer upwards to the nearest valid alignment for T
|
/// round the pointer upwards to the nearest valid alignment for T
|
||||||
template <typename T>
|
template <typename T>
|
||||||
constexpr auto
|
constexpr auto
|
||||||
align_up (uintptr_t ptr)
|
up (T *t)
|
||||||
{
|
{
|
||||||
return align_up (ptr, alignof (T));
|
return up (t, alignof (T));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
///------------------------------------------------------------------------
|
||||||
|
/// round the pointer upwards to the nearest valid alignment for T
|
||||||
|
template <typename T>
|
||||||
|
constexpr auto
|
||||||
|
up (uintptr_t ptr)
|
||||||
|
{
|
||||||
|
return up (ptr, alignof (T));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////
|
||||||
constexpr inline uintptr_t
|
constexpr inline uintptr_t
|
||||||
align_down (uintptr_t ptr, size_t alignment)
|
down (uintptr_t ptr, size_t alignment)
|
||||||
{
|
{
|
||||||
return ptr - ptr % alignment;
|
return ptr - ptr % alignment;
|
||||||
}
|
}
|
||||||
@ -71,10 +81,10 @@ namespace cruft {
|
|||||||
//-------------------------------------------------------------------------
|
//-------------------------------------------------------------------------
|
||||||
template <typename T>
|
template <typename T>
|
||||||
constexpr T*
|
constexpr T*
|
||||||
align_down (T *ptr, size_t alignment)
|
down (T *ptr, size_t alignment)
|
||||||
{
|
{
|
||||||
return reinterpret_cast<T*> (
|
return reinterpret_cast<T*> (
|
||||||
align_down (reinterpret_cast<uintptr_t> (ptr), alignment)
|
down (reinterpret_cast<uintptr_t> (ptr), alignment)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -13,7 +13,7 @@ main (int, char**)
|
|||||||
// satisfy a sane allocation request during testing, just in case the
|
// satisfy a sane allocation request during testing, just in case the
|
||||||
// underlying code actually decides to do something; we don't be touching
|
// underlying code actually decides to do something; we don't be touching
|
||||||
// it ourselves.
|
// it ourselves.
|
||||||
static std::byte buffer[1024*1024];
|
static u08 buffer[1024*1024];
|
||||||
|
|
||||||
// pick an alignment that isn't likely to be satisfied by any likely
|
// pick an alignment that isn't likely to be satisfied by any likely
|
||||||
// underlying allocator. if the allocation fulfills this alignment then
|
// underlying allocator. if the allocation fulfills this alignment then
|
||||||
@ -29,10 +29,10 @@ main (int, char**)
|
|||||||
// alignment to produce a likely system alignment. eg, 3 + 5 == 8 which is
|
// alignment to produce a likely system alignment. eg, 3 + 5 == 8 which is
|
||||||
// a power-of-2.
|
// a power-of-2.
|
||||||
uintptr_t result[4] = {
|
uintptr_t result[4] = {
|
||||||
reinterpret_cast<uintptr_t>(alloc.allocate<char> (9).data ()), // just over a power of two
|
reinterpret_cast<uintptr_t>(alloc.allocate ( 9).data ()), // just over a power of two
|
||||||
reinterpret_cast<uintptr_t>(alloc.allocate<char> (1).data ()), // a single byte
|
reinterpret_cast<uintptr_t>(alloc.allocate ( 1).data ()), // a single byte
|
||||||
reinterpret_cast<uintptr_t>(alloc.allocate<char> (64).data ()), // a cache line
|
reinterpret_cast<uintptr_t>(alloc.allocate ( 64).data ()), // a cache line
|
||||||
reinterpret_cast<uintptr_t>(alloc.allocate<char> (250).data ()) // multiple lines, but not a power of two
|
reinterpret_cast<uintptr_t>(alloc.allocate (250).data ()) // multiple lines, but not a power of two
|
||||||
};
|
};
|
||||||
|
|
||||||
tap.expect (
|
tap.expect (
|
||||||
|
@ -6,13 +6,13 @@
|
|||||||
int
|
int
|
||||||
main ()
|
main ()
|
||||||
{
|
{
|
||||||
static std::byte buffer[1024*1024];
|
static u08 buffer[1024*1024];
|
||||||
static constexpr std::size_t alignment = 3;
|
static constexpr std::size_t alignment = 3;
|
||||||
static constexpr std::size_t increment = 1;
|
static constexpr std::size_t increment = 1;
|
||||||
|
|
||||||
// ensure we have an base pointer that's off-by-one to a likely natural
|
// ensure we have an base pointer that's off-by-one to a likely natural
|
||||||
// system alignment
|
// system alignment
|
||||||
std::byte* base = cruft::align_up (
|
u08* base = cruft::align::up (
|
||||||
std::data (buffer),
|
std::data (buffer),
|
||||||
alignof (std::max_align_t)
|
alignof (std::max_align_t)
|
||||||
) + increment;
|
) + increment;
|
||||||
@ -27,7 +27,7 @@ main ()
|
|||||||
|
|
||||||
// ensure the first element allocated falls at the base address
|
// ensure the first element allocated falls at the base address
|
||||||
tap.expect_eq (base, alloc.data (), "allocator base address is the supplied base address");
|
tap.expect_eq (base, alloc.data (), "allocator base address is the supplied base address");
|
||||||
tap.expect_eq (base, alloc.allocate<std::byte> (8).data (), "first allocation is the supplied base address");
|
tap.expect_eq (base, alloc.allocate (8).data (), "first allocation is the supplied base address");
|
||||||
|
|
||||||
// allocate a range of values and make sure they all satisfy our alignment.
|
// allocate a range of values and make sure they all satisfy our alignment.
|
||||||
// don't choose values which are likely to combine with the testing
|
// don't choose values which are likely to combine with the testing
|
||||||
@ -45,7 +45,7 @@ main ()
|
|||||||
};
|
};
|
||||||
|
|
||||||
for (const auto &t: TESTS) {
|
for (const auto &t: TESTS) {
|
||||||
auto ptr = reinterpret_cast<uintptr_t> (alloc.allocate<char> (t.size).data ());
|
auto ptr = reinterpret_cast<uintptr_t> (alloc.allocate (t.size).data ());
|
||||||
auto offset = ptr - reinterpret_cast<uintptr_t> (base);
|
auto offset = ptr - reinterpret_cast<uintptr_t> (base);
|
||||||
tap.expect_mod (offset, alignment, "%s", t.message);
|
tap.expect_mod (offset, alignment, "%s", t.message);
|
||||||
}
|
}
|
||||||
|
66
test/alloc/easy.cpp
Normal file
66
test/alloc/easy.cpp
Normal file
@ -0,0 +1,66 @@
|
|||||||
|
#include "alloc/easy.hpp"
|
||||||
|
#include "alloc/raw/linear.hpp"
|
||||||
|
#include "memory/buffer/simple.hpp"
|
||||||
|
#include "tap.hpp"
|
||||||
|
|
||||||
|
#include <cstdlib>
|
||||||
|
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
struct setter {
|
||||||
|
setter (const setter&) = delete;
|
||||||
|
|
||||||
|
setter (bool &_target):
|
||||||
|
target (_target)
|
||||||
|
{ target = false; }
|
||||||
|
|
||||||
|
~setter ()
|
||||||
|
{ target = true; }
|
||||||
|
|
||||||
|
bool ⌖
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
int main ()
|
||||||
|
{
|
||||||
|
static constexpr std::size_t elements = 4096;
|
||||||
|
cruft::memory::buffer::simple buf (elements);
|
||||||
|
|
||||||
|
cruft::alloc::easy::owned <
|
||||||
|
cruft::alloc::raw::linear,
|
||||||
|
cruft::memory::buffer::simple
|
||||||
|
> alloc (
|
||||||
|
std::move (buf)
|
||||||
|
);
|
||||||
|
|
||||||
|
cruft::TAP::logger tap;
|
||||||
|
|
||||||
|
bool flag = true;
|
||||||
|
|
||||||
|
// double check our testing object is working, because I'm tired and stupid
|
||||||
|
{
|
||||||
|
setter val (flag);
|
||||||
|
CHECK (!flag);
|
||||||
|
}
|
||||||
|
CHECK (flag);
|
||||||
|
|
||||||
|
// ensure manual acquire and release calls constructors and destructors
|
||||||
|
{
|
||||||
|
auto obj = alloc.acquire<setter> (flag);
|
||||||
|
tap.expect_eq (flag, false, "backed::acquire calls constructor");
|
||||||
|
|
||||||
|
alloc.release (obj);
|
||||||
|
tap.expect_eq (flag, true, "backed::release calls destructor");
|
||||||
|
}
|
||||||
|
|
||||||
|
// ensure unique_ptr like objects call constructors and destructors
|
||||||
|
{
|
||||||
|
auto obj = alloc.unique<setter> (flag);
|
||||||
|
tap.expect_eq (flag, false, "backed::unique acquire calls constructor");
|
||||||
|
}
|
||||||
|
|
||||||
|
tap.expect_eq (flag, true, "backed::unique release calls destructor");
|
||||||
|
|
||||||
|
return tap.status ();
|
||||||
|
}
|
@ -10,7 +10,7 @@ main (void)
|
|||||||
|
|
||||||
constexpr size_t BUFFER_SIZE = 1024;
|
constexpr size_t BUFFER_SIZE = 1024;
|
||||||
|
|
||||||
alignas (std::max_align_t) std::byte memory[BUFFER_SIZE];
|
alignas (std::max_align_t) u08 memory[BUFFER_SIZE];
|
||||||
cruft::alloc::raw::linear store (cruft::make_view (memory));
|
cruft::alloc::raw::linear store (cruft::make_view (memory));
|
||||||
|
|
||||||
tap.expect_eq (store.begin (), std::begin (memory), "base pointers match");
|
tap.expect_eq (store.begin (), std::begin (memory), "base pointers match");
|
||||||
@ -18,12 +18,12 @@ main (void)
|
|||||||
tap.expect_eq (store.capacity (), BUFFER_SIZE, "bytes capacity matches");
|
tap.expect_eq (store.capacity (), BUFFER_SIZE, "bytes capacity matches");
|
||||||
|
|
||||||
tap.expect_throw<std::bad_alloc> (
|
tap.expect_throw<std::bad_alloc> (
|
||||||
[&] (void) { store.allocate<char> (BUFFER_SIZE + 1, 1); },
|
[&] (void) { store.allocate (BUFFER_SIZE + 1, 1); },
|
||||||
"excessive allocation throws bad_alloc"
|
"excessive allocation throws bad_alloc"
|
||||||
);
|
);
|
||||||
|
|
||||||
tap.expect_nothrow (
|
tap.expect_nothrow (
|
||||||
[&] (void) { store.allocate<char> (BUFFER_SIZE); },
|
[&] (void) { store.allocate (BUFFER_SIZE); },
|
||||||
"maximum allocation succeeds"
|
"maximum allocation succeeds"
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -31,14 +31,14 @@ main (void)
|
|||||||
tap.expect_eq (store.remain (), 0u, "bytes remain matches");
|
tap.expect_eq (store.remain (), 0u, "bytes remain matches");
|
||||||
|
|
||||||
tap.expect_throw<std::bad_alloc> (
|
tap.expect_throw<std::bad_alloc> (
|
||||||
[&] (void) { store.allocate<char> (1, 1); },
|
[&] (void) { store.allocate (1, 1); },
|
||||||
"minimum allocation fails after exhaustion"
|
"minimum allocation fails after exhaustion"
|
||||||
);
|
);
|
||||||
|
|
||||||
store.reset ();
|
store.reset ();
|
||||||
|
|
||||||
tap.expect_nothrow (
|
tap.expect_nothrow (
|
||||||
[&] (void) { store.allocate<char> (1, 1); },
|
[&] (void) { store.allocate (1, 1); },
|
||||||
"minimum allocation succeeds after reset"
|
"minimum allocation succeeds after reset"
|
||||||
);
|
);
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user