generated from bemanproject/exemplar
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #6 from bemanproject/add-allocator-tool-tests
Add allocator tool tests
- Loading branch information
Showing
15 changed files
with
388 additions
and
113 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
// include/beman/lazy/detail/allocator_of.hpp -*-C++-*- | ||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||
|
||
#ifndef INCLUDED_INCLUDE_BEMAN_LAZY_DETAIL_ALLOCATOR_OF | ||
#define INCLUDED_INCLUDE_BEMAN_LAZY_DETAIL_ALLOCATOR_OF | ||
|
||
#include <concepts> | ||
#include <memory> | ||
|
||
// ---------------------------------------------------------------------------- | ||
|
||
namespace beman::lazy::detail { | ||
/*! | ||
* \brief Utility to get an allocator type from a context | ||
* \headerfile beman/lazy/lazy.hpp <beman/lazy/lazy.hpp> | ||
* \internal | ||
*/ | ||
template <typename> | ||
struct allocator_of { | ||
using type = std::allocator<std::byte>; | ||
}; | ||
template <typename Context> | ||
requires requires { typename Context::allocator_type; } | ||
struct allocator_of<Context> { | ||
using type = typename Context::allocator_type; | ||
static_assert( | ||
requires(type& a, std::size_t s, std::byte* ptr) { | ||
{ a.allocate(s) } -> std::same_as<std::byte*>; | ||
a.deallocate(ptr, s); | ||
}, "The allocator_type needs to be an allocator of std::byte"); | ||
}; | ||
template <typename Context> | ||
using allocator_of_t = typename allocator_of<Context>::type; | ||
} // namespace beman::lazy::detail | ||
|
||
// ---------------------------------------------------------------------------- | ||
|
||
#endif |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,82 @@ | ||
// include/beman/lazy/detail/allocator_support.hpp -*-C++-*- | ||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||
|
||
#ifndef INCLUDED_BEMAN_LAZY_DETAIL_ALLOCATOR_SUPPORT | ||
#define INCLUDED_BEMAN_LAZY_DETAIL_ALLOCATOR_SUPPORT | ||
|
||
#include <beman/lazy/detail/find_allocator.hpp> | ||
#include <array> | ||
#include <concepts> | ||
#include <cstddef> | ||
#include <memory> | ||
#include <new> | ||
|
||
// ---------------------------------------------------------------------------- | ||
|
||
namespace beman::lazy::detail { | ||
/*! | ||
* \brief Utility adding allocator support to type by embedding the allocator | ||
* \headerfile beman/lazy/lazy.hpp <beman/lazy/lazy.hpp> | ||
* | ||
* To add allocator support using this class just publicly inherit from | ||
* allocator_support<Allocator, YourPromiseType>. This utility is probably | ||
* only useful for coroutine promise types. | ||
* | ||
* This struct is a massive hack, primarily support allocators for coroutines. | ||
* The memory for coroutines is implicitly managed and there isn't a way to | ||
* provide the memory directly. Instead, the promise_type can overload an | ||
* operator new and somehow determine an allocator based on the arguments | ||
* passed to the coroutine. Even worse, the operator delete only gets passed | ||
* a pointer to delete and a size. To determine the correct allocator the | ||
* operator delete needs to located it based on this information. Putting | ||
* the allocator after actually used memory causes the address sanitizer to | ||
* object! So, the current strategy is to embed space for the allocator | ||
* into the object and pull it out from there. | ||
*/ | ||
template <typename Allocator> | ||
struct allocator_support { | ||
using allocator_traits = std::allocator_traits<Allocator>; | ||
|
||
static std::size_t offset(std::size_t size) { | ||
return (size + alignof(Allocator) - 1u) & ~(alignof(Allocator) - 1u); | ||
} | ||
static Allocator* get_allocator(void* ptr, std::size_t size) { | ||
ptr = static_cast<std::byte*>(ptr) + offset(size); | ||
return ::std::launder(reinterpret_cast<Allocator*>(ptr)); | ||
} | ||
|
||
template <typename... A> | ||
static void* operator new(std::size_t size, A&&... a) { | ||
if constexpr (::std::same_as<Allocator, ::std::allocator<::std::byte>>) { | ||
Allocator alloc{}; | ||
return allocator_traits::allocate(alloc, size); | ||
|
||
} else { | ||
Allocator alloc{::beman::lazy::detail::find_allocator<Allocator>(a...)}; | ||
void* ptr{allocator_traits::allocate(alloc, allocator_support::offset(size) + sizeof(Allocator))}; | ||
new (allocator_support::get_allocator(ptr, size)) Allocator(alloc); | ||
return ptr; | ||
} | ||
} | ||
template <typename... A> | ||
static void operator delete(void* ptr, std::size_t size, A&&...) { | ||
allocator_support::operator delete(ptr, size); | ||
} | ||
static void operator delete(void* ptr, std::size_t size) { | ||
if constexpr (::std::same_as<Allocator, ::std::allocator<::std::byte>>) { | ||
Allocator alloc{}; | ||
allocator_traits::deallocate(alloc, static_cast<std::byte*>(ptr), size); | ||
} else { | ||
Allocator* aptr{allocator_support::get_allocator(ptr, size)}; | ||
Allocator alloc{*aptr}; | ||
aptr->~Allocator(); | ||
allocator_traits::deallocate( | ||
alloc, static_cast<std::byte*>(ptr), allocator_support::offset(size) + sizeof(Allocator)); | ||
} | ||
} | ||
}; | ||
} // namespace beman::lazy::detail | ||
|
||
// ---------------------------------------------------------------------------- | ||
|
||
#endif |
Oops, something went wrong.