alloc: add aligned::foreign allocator
sometimes we need to ensure memory allocation has a particular alignment in an _offset_ buffer (which we have no control over, eg renderdoc's OpenGL buffers). this applies an offset to various operations that make the aligned::direct allocator correctly align allocations for buffers that aren't themselves aligned.
This commit is contained in:
parent
825ca4a7e7
commit
c2265b9ed2
@ -140,9 +140,12 @@ list (
|
|||||||
alloc/allocator.hpp
|
alloc/allocator.hpp
|
||||||
alloc/arena.cpp
|
alloc/arena.cpp
|
||||||
alloc/arena.hpp
|
alloc/arena.hpp
|
||||||
|
alloc/raw/traits.hpp
|
||||||
alloc/raw/affix.cpp
|
alloc/raw/affix.cpp
|
||||||
alloc/raw/affix.hpp
|
alloc/raw/affix.hpp
|
||||||
alloc/raw/aligned.hpp
|
alloc/raw/aligned/base.hpp
|
||||||
|
alloc/raw/aligned/direct.hpp
|
||||||
|
alloc/raw/aligned/foreign.hpp
|
||||||
alloc/raw/dynamic.hpp
|
alloc/raw/dynamic.hpp
|
||||||
alloc/raw/fallback.cpp
|
alloc/raw/fallback.cpp
|
||||||
alloc/raw/fallback.hpp
|
alloc/raw/fallback.hpp
|
||||||
@ -422,7 +425,8 @@ if (TESTS)
|
|||||||
APPEND TEST_BIN
|
APPEND TEST_BIN
|
||||||
ascii
|
ascii
|
||||||
algo/sort
|
algo/sort
|
||||||
alloc/aligned
|
alloc/aligned/foreign
|
||||||
|
alloc/aligned/direct
|
||||||
alloc/arena
|
alloc/arena
|
||||||
alloc/dynamic
|
alloc/dynamic
|
||||||
alloc/linear
|
alloc/linear
|
||||||
|
@ -29,8 +29,10 @@ namespace util::alloc {
|
|||||||
|
|
||||||
class dynamic;
|
class dynamic;
|
||||||
|
|
||||||
template <typename AllocT>
|
namespace aligned {
|
||||||
class aligned;
|
template <typename AllocT> class foreign;
|
||||||
|
template <typename AllocT> class direct;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -14,23 +14,23 @@
|
|||||||
* Copyright 2016 Danny Robson <danny@nerdcruft.net>
|
* Copyright 2016 Danny Robson <danny@nerdcruft.net>
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef CRUFT_UTIL_ALLOC_RAW_ALIGNED_HPP
|
#ifndef CRUFT_UTIL_ALLOC_RAW_ALIGNED_DIRECT_HPP
|
||||||
#define CRUFT_UTIL_ALLOC_RAW_ALIGNED_HPP
|
#define CRUFT_UTIL_ALLOC_RAW_ALIGNED_DIRECT_HPP
|
||||||
|
|
||||||
|
#include "../../../debug.hpp"
|
||||||
|
|
||||||
#include <cstddef>
|
#include <cstddef>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
|
|
||||||
#include "../../debug.hpp"
|
namespace util::alloc::raw::aligned {
|
||||||
|
|
||||||
namespace util::alloc::raw {
|
|
||||||
/// wraps a child allocator and enforces a fixed alignment
|
/// wraps a child allocator and enforces a fixed alignment
|
||||||
template <typename ChildT>
|
template <typename ChildT>
|
||||||
class aligned {
|
class direct {
|
||||||
public:
|
public:
|
||||||
///////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////
|
||||||
template <typename ...Args>
|
template <typename ...Args>
|
||||||
aligned (std::size_t _alignment, Args &&...args):
|
direct (util::view<std::byte*> _data, std::size_t _alignment, Args &&...args):
|
||||||
m_successor (std::forward<Args> (args)...),
|
m_successor (_data, std::forward<Args> (args)...),
|
||||||
m_alignment (_alignment)
|
m_alignment (_alignment)
|
||||||
{ ; }
|
{ ; }
|
||||||
|
|
||||||
@ -42,16 +42,6 @@ namespace util::alloc::raw {
|
|||||||
return m_successor.allocate (bytes, m_alignment);
|
return m_successor.allocate (bytes, m_alignment);
|
||||||
}
|
}
|
||||||
|
|
||||||
//---------------------------------------------------------------------
|
|
||||||
auto
|
|
||||||
allocate (std::size_t bytes, std::size_t alignment)
|
|
||||||
{
|
|
||||||
(void)alignment;
|
|
||||||
CHECK_EQ (alignment, m_alignment);
|
|
||||||
return m_successor.allocate (bytes, m_alignment);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
//---------------------------------------------------------------------
|
//---------------------------------------------------------------------
|
||||||
auto
|
auto
|
||||||
deallocate (void *ptr, std::size_t bytes)
|
deallocate (void *ptr, std::size_t bytes)
|
||||||
@ -60,16 +50,6 @@ namespace util::alloc::raw {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
//---------------------------------------------------------------------
|
|
||||||
auto
|
|
||||||
deallocate (void *ptr, std::size_t bytes, std::size_t alignment)
|
|
||||||
{
|
|
||||||
(void)alignment;
|
|
||||||
CHECK_EQ (alignment, m_alignment);
|
|
||||||
return m_successor.deallocate (ptr, bytes, m_alignment);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////
|
||||||
constexpr auto alignment (void) const noexcept { return m_alignment; }
|
constexpr auto alignment (void) const noexcept { return m_alignment; }
|
||||||
|
|
99
alloc/raw/aligned/foreign.hpp
Normal file
99
alloc/raw/aligned/foreign.hpp
Normal file
@ -0,0 +1,99 @@
|
|||||||
|
/*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*
|
||||||
|
* Copyright 2016 Danny Robson <danny@nerdcruft.net>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef CRUFT_UTIL_ALLOC_RAW_ALIGNED_OFFSET_HPP
|
||||||
|
#define CRUFT_UTIL_ALLOC_RAW_ALIGNED_OFFSET_HPP
|
||||||
|
|
||||||
|
#include "direct.hpp"
|
||||||
|
|
||||||
|
#include "../../../pointer.hpp"
|
||||||
|
#include "../../../debug.hpp"
|
||||||
|
|
||||||
|
#include <cstddef>
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
|
namespace util::alloc::raw::aligned {
|
||||||
|
/// wraps a child allocator and enforces a fixed alignment that is
|
||||||
|
/// independant of the alignment of the provided source buffer.
|
||||||
|
///
|
||||||
|
/// we use the approach of:
|
||||||
|
/// * shifting the source buffer's alignment to satisfy the requested
|
||||||
|
/// alignment
|
||||||
|
/// * using a direct alignment child to service the requests
|
||||||
|
/// * then applying the reverse offset to values as we return the values
|
||||||
|
template <typename ChildT>
|
||||||
|
class foreign {
|
||||||
|
public:
|
||||||
|
template <typename ...Args>
|
||||||
|
foreign (util::view<std::byte*> _data, std::size_t _alignment, Args &&...args):
|
||||||
|
m_successor (
|
||||||
|
view<std::byte*> {0, _data.size ()},
|
||||||
|
_alignment,
|
||||||
|
std::forward<Args> (args)...
|
||||||
|
),
|
||||||
|
m_offset (m_successor.data () - _data.data ()),
|
||||||
|
m_alignment (_alignment)
|
||||||
|
{ ; }
|
||||||
|
|
||||||
|
|
||||||
|
void*
|
||||||
|
allocate (std::size_t size)
|
||||||
|
{
|
||||||
|
auto ptr= reinterpret_cast<std::byte*> (
|
||||||
|
m_successor.allocate (size)
|
||||||
|
);
|
||||||
|
return ptr - m_offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto
|
||||||
|
deallocate (void *ptr, std::size_t size)
|
||||||
|
{
|
||||||
|
return m_successor.deallocate (
|
||||||
|
reinterpret_cast<std::byte*> (ptr) + m_offset, size
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr auto alignment (void) const noexcept { return m_alignment; }
|
||||||
|
|
||||||
|
auto offset (const void *ptr) const
|
||||||
|
{
|
||||||
|
return m_successor.offset (ptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto data (void) { return m_successor.data () - m_offset; }
|
||||||
|
auto data (void) const { return m_successor.data () - m_offset; }
|
||||||
|
|
||||||
|
auto begin (void) { return m_successor.begin () - m_offset; }
|
||||||
|
auto begin (void) const { return m_successor.begin () - m_offset; }
|
||||||
|
|
||||||
|
auto end (void) { return m_successor.end () - m_offset; }
|
||||||
|
auto end (void) const { return m_successor.end () - m_offset; }
|
||||||
|
|
||||||
|
auto reset (void) { return m_successor.reset (); }
|
||||||
|
|
||||||
|
auto capacity (void) const { return m_successor.capacity (); }
|
||||||
|
auto used (void) const { return m_successor.used (); }
|
||||||
|
auto remain (void) const { return m_successor.remain (); }
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
direct<ChildT> m_successor;
|
||||||
|
std::ptrdiff_t m_offset;
|
||||||
|
std::size_t m_alignment;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
@ -11,12 +11,14 @@
|
|||||||
* See the License for the specific language governing permissions and
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*
|
*
|
||||||
* Copyright 2016 Danny Robson <danny@nerdcruft.net>
|
* Copyright 2016-2018 Danny Robson <danny@nerdcruft.net>
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef CRUFT_UTIL_ALLOC_RAW_DYNAMIC_HPP
|
#ifndef CRUFT_UTIL_ALLOC_RAW_DYNAMIC_HPP
|
||||||
#define CRUFT_UTIL_ALLOC_RAW_DYNAMIC_HPP
|
#define CRUFT_UTIL_ALLOC_RAW_DYNAMIC_HPP
|
||||||
|
|
||||||
|
#include "traits.hpp"
|
||||||
|
|
||||||
#include <cstddef>
|
#include <cstddef>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
@ -26,6 +28,8 @@ namespace util::alloc::raw {
|
|||||||
// allocator interface.
|
// allocator interface.
|
||||||
class dynamic {
|
class dynamic {
|
||||||
public:
|
public:
|
||||||
|
struct alignment_unsupported : public std::exception {};
|
||||||
|
|
||||||
//---------------------------------------------------------------------
|
//---------------------------------------------------------------------
|
||||||
// disable copying, but allow moving (required for calls to 'make')
|
// disable copying, but allow moving (required for calls to 'make')
|
||||||
dynamic (const dynamic&) = delete;
|
dynamic (const dynamic&) = delete;
|
||||||
@ -49,12 +53,19 @@ namespace util::alloc::raw {
|
|||||||
}
|
}
|
||||||
|
|
||||||
//---------------------------------------------------------------------
|
//---------------------------------------------------------------------
|
||||||
// allocation management
|
// if aligned allocation is not exposed by the child then we will
|
||||||
auto allocate (size_t bytes) { return m_child->allocate (bytes); }
|
// unconditionally throw if it is ever called. unfortunately we can't
|
||||||
|
// dynamically eliminate the function altogether given run-time
|
||||||
|
// dynamic dispatch needs the common calls exposed to the clients, and
|
||||||
|
// aligned allocate is stupid useful.
|
||||||
|
auto allocate (size_t bytes) { return m_child->allocate (bytes); }
|
||||||
auto allocate (size_t bytes, size_t alignment) { return m_child->allocate (bytes, alignment); }
|
auto allocate (size_t bytes, size_t alignment) { return m_child->allocate (bytes, alignment); }
|
||||||
|
|
||||||
auto deallocate (void *ptr, size_t bytes) { return m_child->deallocate (ptr, bytes); }
|
auto deallocate (void *ptr, size_t bytes)
|
||||||
auto deallocate (void *ptr, size_t bytes, size_t alignment) { return m_child->deallocate (ptr, bytes, alignment); }
|
{ return m_child->deallocate (ptr, bytes); }
|
||||||
|
|
||||||
|
auto deallocate (void *ptr, size_t bytes, size_t alignment)
|
||||||
|
{ return m_child->deallocate (ptr, bytes, alignment); }
|
||||||
|
|
||||||
//---------------------------------------------------------------------
|
//---------------------------------------------------------------------
|
||||||
auto begin (void) { return m_child->begin (); }
|
auto begin (void) { return m_child->begin (); }
|
||||||
@ -109,9 +120,11 @@ namespace util::alloc::raw {
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
template <typename T>
|
template <typename ChildT>
|
||||||
class child final : public interface {
|
class child final : public interface {
|
||||||
public:
|
public:
|
||||||
|
struct _alignment_unsupported : public alignment_unsupported { };
|
||||||
|
|
||||||
template <typename ...Args>
|
template <typename ...Args>
|
||||||
child (Args &&...args):
|
child (Args &&...args):
|
||||||
interface (),
|
interface (),
|
||||||
@ -123,9 +136,21 @@ namespace util::alloc::raw {
|
|||||||
allocate (size_t bytes) override
|
allocate (size_t bytes) override
|
||||||
{ return m_target.allocate (bytes); }
|
{ return m_target.allocate (bytes); }
|
||||||
|
|
||||||
|
|
||||||
|
// we can't totally eliminate this call given the point is to
|
||||||
|
// expose the common API area, but we will throw if the operation
|
||||||
|
// is unsupported in the child.
|
||||||
void*
|
void*
|
||||||
allocate (size_t bytes, size_t alignment) override
|
allocate (size_t bytes, size_t alignment) override
|
||||||
{ return m_target.allocate (bytes, alignment); }
|
{
|
||||||
|
if constexpr (has_aligned_allocate_v<ChildT>) {
|
||||||
|
return m_target.allocate (bytes, alignment);
|
||||||
|
} else {
|
||||||
|
(void)bytes;
|
||||||
|
(void)alignment;
|
||||||
|
throw _alignment_unsupported ();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
deallocate (void *ptr, size_t bytes) override
|
deallocate (void *ptr, size_t bytes) override
|
||||||
@ -133,7 +158,17 @@ namespace util::alloc::raw {
|
|||||||
|
|
||||||
void
|
void
|
||||||
deallocate (void *ptr, size_t bytes, size_t alignment) override
|
deallocate (void *ptr, size_t bytes, size_t alignment) override
|
||||||
{ m_target.deallocate (ptr, bytes, alignment); }
|
{
|
||||||
|
if constexpr (has_aligned_allocate_v<ChildT>) {
|
||||||
|
m_target.deallocate (ptr, bytes, alignment);
|
||||||
|
} else {
|
||||||
|
(void)ptr;
|
||||||
|
(void)bytes;
|
||||||
|
(void)alignment;
|
||||||
|
|
||||||
|
throw _alignment_unsupported ();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const std::byte*
|
const std::byte*
|
||||||
begin (void) const override
|
begin (void) const override
|
||||||
@ -164,7 +199,7 @@ namespace util::alloc::raw {
|
|||||||
size_t remain (void) const override { return m_target.remain (); }
|
size_t remain (void) const override { return m_target.remain (); }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
T m_target;
|
ChildT m_target;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -23,15 +23,11 @@ using util::alloc::raw::linear;
|
|||||||
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
linear::linear (void *begin, void *end):
|
linear::linear (util::view<std::byte*> _data):
|
||||||
m_begin (reinterpret_cast<std::byte*> (begin)),
|
m_begin (_data.begin ()),
|
||||||
m_end (reinterpret_cast<std::byte*> (end)),
|
m_end (_data.end ()),
|
||||||
m_cursor (reinterpret_cast<std::byte*> (begin))
|
m_cursor (_data.begin ())
|
||||||
{
|
{ ; }
|
||||||
CHECK_NEZ (begin);
|
|
||||||
CHECK_NEZ (end);
|
|
||||||
CHECK_LE (begin, end);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
@ -52,7 +48,6 @@ linear::allocate (size_t bytes, size_t alignment)
|
|||||||
|
|
||||||
m_cursor = ptr + bytes;
|
m_cursor = ptr + bytes;
|
||||||
|
|
||||||
CHECK_NEZ (ptr);
|
|
||||||
return ptr;
|
return ptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -17,6 +17,8 @@
|
|||||||
#ifndef CRUFT_UTIL_ALLOC_RAW_LINEAR_HPP
|
#ifndef CRUFT_UTIL_ALLOC_RAW_LINEAR_HPP
|
||||||
#define CRUFT_UTIL_ALLOC_RAW_LINEAR_HPP
|
#define CRUFT_UTIL_ALLOC_RAW_LINEAR_HPP
|
||||||
|
|
||||||
|
#include "../../view.hpp"
|
||||||
|
|
||||||
#include <cstddef>
|
#include <cstddef>
|
||||||
#include <iterator>
|
#include <iterator>
|
||||||
|
|
||||||
@ -30,12 +32,7 @@ namespace util::alloc::raw {
|
|||||||
linear& operator= (const linear&) = delete;
|
linear& operator= (const linear&) = delete;
|
||||||
linear& operator= (linear&&) = delete;
|
linear& operator= (linear&&) = delete;
|
||||||
|
|
||||||
linear (void *begin, void *end);
|
linear (util::view<std::byte*> _data);
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
linear (T &&view):
|
|
||||||
linear (std::begin (view), std::end (view))
|
|
||||||
{ ; }
|
|
||||||
|
|
||||||
void* allocate (size_t bytes);
|
void* allocate (size_t bytes);
|
||||||
void* allocate (size_t bytes, size_t alignment);
|
void* allocate (size_t bytes, size_t alignment);
|
||||||
|
@ -24,9 +24,9 @@ using util::alloc::raw::stack;
|
|||||||
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
stack::stack (void *begin, void *end):
|
stack::stack (util::view<std::byte*> _data):
|
||||||
m_begin (reinterpret_cast<std::byte*> (begin)),
|
m_begin (_data.begin ()),
|
||||||
m_end (reinterpret_cast<std::byte*> (end)),
|
m_end (_data.end ()),
|
||||||
m_cursor (m_begin)
|
m_cursor (m_begin)
|
||||||
{
|
{
|
||||||
CHECK_LE (m_begin, m_end);
|
CHECK_LE (m_begin, m_end);
|
||||||
|
@ -32,7 +32,7 @@ namespace util::alloc::raw {
|
|||||||
stack& operator= (const stack&) = delete;
|
stack& operator= (const stack&) = delete;
|
||||||
stack& operator= (stack&&) = delete;
|
stack& operator= (stack&&) = delete;
|
||||||
|
|
||||||
stack (void *begin, void *end);
|
stack (util::view<std::byte*> _data);
|
||||||
|
|
||||||
void *allocate (size_t bytes, size_t alignment);
|
void *allocate (size_t bytes, size_t alignment);
|
||||||
void *allocate (size_t bytes);
|
void *allocate (size_t bytes);
|
||||||
|
42
alloc/raw/traits.hpp
Normal file
42
alloc/raw/traits.hpp
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
/*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*
|
||||||
|
* Copyright 2018 Danny Robson <danny@nerdcruft.net>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef CRUFT_UTIL_ALLOC_RAW_TRAITS_HPP
|
||||||
|
#define CRUFT_UTIL_ALLOC_RAW_TRAITS_HPP
|
||||||
|
|
||||||
|
#include <type_traits>
|
||||||
|
|
||||||
|
|
||||||
|
namespace util::alloc::raw {
|
||||||
|
template <typename AllocT, typename = std::void_t<>>
|
||||||
|
struct has_aligned_allocate : std::false_type {};
|
||||||
|
|
||||||
|
template <typename AllocT>
|
||||||
|
struct has_aligned_allocate<
|
||||||
|
AllocT,
|
||||||
|
std::void_t<
|
||||||
|
decltype (
|
||||||
|
std::declval<AllocT> ().allocate(16, 16)
|
||||||
|
)
|
||||||
|
>
|
||||||
|
>: public std::true_type {};
|
||||||
|
|
||||||
|
|
||||||
|
template <typename AllocT>
|
||||||
|
constexpr auto has_aligned_allocate_v = has_aligned_allocate<AllocT>::value;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
@ -1,6 +1,6 @@
|
|||||||
#include "tap.hpp"
|
#include "tap.hpp"
|
||||||
|
|
||||||
#include "alloc/raw/aligned.hpp"
|
#include "alloc/raw/aligned/direct.hpp"
|
||||||
#include "alloc/raw/linear.hpp"
|
#include "alloc/raw/linear.hpp"
|
||||||
|
|
||||||
|
|
||||||
@ -13,15 +13,15 @@ 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 char buffer[1024*1024];
|
static std::byte 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
|
||||||
// we're probably operating correctly.
|
// we're probably operating correctly.
|
||||||
static constexpr std::size_t alignment = 3;
|
static constexpr std::size_t alignment = 3;
|
||||||
|
|
||||||
util::alloc::raw::aligned<util::alloc::raw::linear> alloc (
|
util::alloc::raw::aligned::direct<util::alloc::raw::linear> alloc (
|
||||||
alignment, std::begin (buffer), std::end (buffer)
|
util::make_view (buffer), alignment
|
||||||
);
|
);
|
||||||
|
|
||||||
// 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.
|
54
test/alloc/aligned/foreign.cpp
Normal file
54
test/alloc/aligned/foreign.cpp
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
#include "alloc/raw/aligned/foreign.hpp"
|
||||||
|
#include "alloc/raw/linear.hpp"
|
||||||
|
#include "pointer.hpp"
|
||||||
|
#include "tap.hpp"
|
||||||
|
|
||||||
|
int
|
||||||
|
main ()
|
||||||
|
{
|
||||||
|
static std::byte buffer[1024*1024];
|
||||||
|
static constexpr std::size_t alignment = 3;
|
||||||
|
static constexpr std::size_t increment = 1;
|
||||||
|
|
||||||
|
// ensure we have an base pointer that's off-by-one to a likely natural
|
||||||
|
// system alignment
|
||||||
|
std::byte* base = util::align (
|
||||||
|
std::data (buffer),
|
||||||
|
alignof (std::max_align_t)
|
||||||
|
) + increment;
|
||||||
|
|
||||||
|
util::alloc::raw::aligned::foreign<util::alloc::raw::linear> alloc (
|
||||||
|
util::view(base,std::end(buffer)),
|
||||||
|
alignment
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
util::TAP::logger tap;
|
||||||
|
|
||||||
|
// 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.allocate (8), "first allocation is the supplied base address");
|
||||||
|
|
||||||
|
// 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
|
||||||
|
// alignment to produce a likely system alignment. eg, 3 + 5 == 8 which is
|
||||||
|
// a power-of-2.
|
||||||
|
|
||||||
|
static const struct {
|
||||||
|
size_t size;
|
||||||
|
const char *message;
|
||||||
|
} TESTS[] = {
|
||||||
|
{ 9, "just over a power of two" },
|
||||||
|
{ 1, "a single byte" },
|
||||||
|
{ 64, "a cache line" },
|
||||||
|
{ 250, "multiple cache lines, but not a power of two" },
|
||||||
|
};
|
||||||
|
|
||||||
|
for (const auto &t: TESTS) {
|
||||||
|
auto ptr = (uintptr_t)alloc.allocate (t.size);
|
||||||
|
auto offset = ptr - (uintptr_t)base;
|
||||||
|
tap.expect_mod (offset, alignment, "%s", t.message);
|
||||||
|
}
|
||||||
|
|
||||||
|
return tap.status ();
|
||||||
|
};
|
@ -6,7 +6,7 @@
|
|||||||
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
static char g_backing[1024*1024];
|
static std::byte g_backing[1024*1024];
|
||||||
|
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
@ -28,7 +28,7 @@ struct setter {
|
|||||||
int
|
int
|
||||||
main (void)
|
main (void)
|
||||||
{
|
{
|
||||||
util::alloc::raw::linear alloc (std::begin (g_backing), std::end (g_backing));
|
util::alloc::raw::linear alloc (util::make_view (g_backing));
|
||||||
util::alloc::arena<util::alloc::raw::linear> arena (alloc);
|
util::alloc::arena<util::alloc::raw::linear> arena (alloc);
|
||||||
|
|
||||||
util::TAP::logger tap;
|
util::TAP::logger tap;
|
||||||
|
@ -11,7 +11,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) std::byte memory[BUFFER_SIZE];
|
||||||
util::alloc::raw::linear store (std::begin (memory), std::end (memory));
|
util::alloc::raw::linear store (util::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");
|
||||||
tap.expect_eq (store.offset (std::begin (memory)), 0u, "base offset is 0");
|
tap.expect_eq (store.offset (std::begin (memory)), 0u, "base offset is 0");
|
||||||
|
@ -32,7 +32,7 @@ main (void)
|
|||||||
alignas (std::max_align_t) std::byte memory[BUFFER_SIZE];
|
alignas (std::max_align_t) std::byte memory[BUFFER_SIZE];
|
||||||
std::fill (std::begin (memory), std::end (memory), std::byte{0});
|
std::fill (std::begin (memory), std::end (memory), std::byte{0});
|
||||||
|
|
||||||
util::alloc::raw::stack store (memory, memory + BUFFER_AVAILABLE);
|
util::alloc::raw::stack store (util::make_view(memory, memory + BUFFER_AVAILABLE));
|
||||||
|
|
||||||
tap.expect_eq (store.begin (), std::begin (memory), "base pointers match");
|
tap.expect_eq (store.begin (), std::begin (memory), "base pointers match");
|
||||||
tap.expect_eq (store.offset (std::begin (memory)), 0u, "base offset is 0");
|
tap.expect_eq (store.offset (std::begin (memory)), 0u, "base offset is 0");
|
||||||
|
Loading…
Reference in New Issue
Block a user