[proxy](2/n) provide proxy layers for type traits (#717)

* [proxy](2/n) provide proxy layers for type traits

* fix after rebasing
This commit is contained in:
Schrodinger ZHU Yifan
2025-01-07 01:07:49 +08:00
committed by GitHub
parent 7db1f243cc
commit 2cc74eac10
39 changed files with 557 additions and 122 deletions

View File

@@ -495,21 +495,23 @@ jobs:
run: ${{github.workspace}}/build/fuzzing/snmalloc-fuzzer
self-vendored:
name: Self Vendored STL Functionality
strategy:
fail-fast: false
matrix:
include:
- os: windows-2022
cxx: clang-cl
cc: clang-cl
- os: ubuntu-latest
cxx: clang++
cc: clang
- os: ubuntu-latest
cxx: g++
cc: gcc
- os: ubuntu-24.04
cxx: clang++-18
cc: clang-18
- os: ubuntu-24.04
cxx: g++-14
cc: gcc-14
- os: macos-latest
cxx: clang++
cc: clang
cc: clang
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v4
@@ -524,7 +526,7 @@ jobs:
- name: Prepare Ubuntu
if: runner.os == 'Linux'
run: |
sudo apt install ninja-build
sudo apt-get install -y ninja-build
- name: Configure CMake
run: >
cmake

View File

@@ -69,10 +69,10 @@ namespace snmalloc
* must explicitly give their address_t.
*
* This somewhat obtuse way of spelling the defaulting is necessary so
* that all arguments to std::conditional_t are valid, even if they
* that all arguments to stl::conditional_t are valid, even if they
* wouldn't be valid in context. One might rather wish to say
*
* std::conditional_t<..., uintptr_t, Arch::address_t>
* stl::conditional_t<..., uintptr_t, Arch::address_t>
*
* but that requires that Arch::address_t always be given, precisely
* the thing we're trying to avoid with the conditional.
@@ -83,7 +83,7 @@ namespace snmalloc
using address_t = uintptr_t;
};
using address_t = typename std::conditional_t<
using address_t = typename stl::conditional_t<
(Arch::aal_features & IntegerPointers) != 0,
default_address_t,
Arch>::address_t;

View File

@@ -4,8 +4,7 @@
# include "../ds_core/ds_core.h"
# include "aal_consts.h"
# include <cstdint>
# include <utility>
# include <stdint.h>
namespace snmalloc
{
@@ -16,10 +15,10 @@ namespace snmalloc
template<typename AAL>
concept IsAAL_static_members =
requires() {
typename std::integral_constant<uint64_t, AAL::aal_features>;
typename std::integral_constant<int, AAL::aal_name>;
typename std::integral_constant<std::size_t, AAL::bits>;
typename std::integral_constant<std::size_t, AAL::address_bits>;
typename stl::integral_constant<uint64_t, AAL::aal_features>;
typename stl::integral_constant<int, AAL::aal_name>;
typename stl::integral_constant<size_t, AAL::bits>;
typename stl::integral_constant<size_t, AAL::address_bits>;
};
/**

View File

@@ -118,7 +118,8 @@ namespace snmalloc
static_assert(B::wildness == capptr::dimension::Wildness::Wild);
static const size_t sz = sizeof(
std::conditional<std::is_same_v<std::remove_cv<T>, void>, void*, T>);
stl::
conditional_t<stl::is_same_v<stl::remove_cv_t<T>, void>, void*, T>);
UNUSED(ls);
auto address = address_cast(p);

View File

@@ -65,7 +65,7 @@ namespace snmalloc
/**
* Use one of the default range configurations
*/
using LocalState = std::conditional_t<
using LocalState = stl::conditional_t<
mitigations(metadata_protection),
MetaProtectedRangeLocalState<Pal, Pagemap, Base>,
StandardLocalState<Pal, Pagemap, Base>>;

View File

@@ -75,7 +75,7 @@ namespace snmalloc
CommitRange<PAL>,
// In case of huge pages, we don't want to give each thread its own huge
// page, so commit in the global range.
std::conditional_t<
stl::conditional_t<
(max_page_chunk_size_bits > MIN_CHUNK_BITS),
LargeBuddyRange<
max_page_chunk_size_bits,

View File

@@ -31,7 +31,7 @@ namespace snmalloc
struct BasicAuthmap
{
static_assert(
std::is_same_v<capptr::Arena<void>, typename ConcreteMap::EntryType>,
stl::is_same_v<capptr::Arena<void>, typename ConcreteMap::EntryType>,
"BasicAuthmap's ConcreteMap must have capptr::Arena<void> element type!");
private:
@@ -70,7 +70,7 @@ namespace snmalloc
* Pick between the two above implementations based on StrictProvenance
*/
template<typename CA>
using DefaultAuthmap = std::conditional_t<
using DefaultAuthmap = stl::conditional_t<
aal_supports<StrictProvenance>,
BasicAuthmap<CA>,
DummyAuthmap>;

View File

@@ -228,7 +228,7 @@ namespace snmalloc
* covers the whole range. Uses template insanity to make this work.
*/
template<bool exists = MAX_SIZE_BITS != (bits::BITS - 1)>
std::enable_if_t<exists>
stl::enable_if_t<exists>
parent_dealloc_range(capptr::Arena<void> base, size_t size)
{
static_assert(
@@ -343,7 +343,7 @@ namespace snmalloc
/* The large buddy allocator always deals in Arena-bounded pointers. */
using ChunkBounds = capptr::bounds::Arena;
static_assert(
std::is_same_v<typename ParentRange::ChunkBounds, ChunkBounds>);
stl::is_same_v<typename ParentRange::ChunkBounds, ChunkBounds>);
constexpr Type() = default;

View File

@@ -29,11 +29,11 @@ namespace snmalloc
using Entry = PagemapEntry;
static_assert(
std::is_same_v<PagemapEntry, typename ConcreteMap::EntryType>,
stl::is_same_v<PagemapEntry, typename ConcreteMap::EntryType>,
"BasicPagemap's PagemapEntry and ConcreteMap disagree!");
static_assert(
std::is_base_of_v<MetaEntryBase, PagemapEntry>,
stl::is_base_of_v<MetaEntryBase, PagemapEntry>,
"BasicPagemap's PagemapEntry type is not a MetaEntryBase");
/**
@@ -115,7 +115,7 @@ namespace snmalloc
*/
template<bool fixed_range_ = fixed_range>
static SNMALLOC_FAST_PATH
std::enable_if_t<fixed_range_, std::pair<address_t, address_t>>
stl::enable_if_t<fixed_range_, std::pair<address_t, address_t>>
get_bounds()
{
static_assert(fixed_range_ == fixed_range, "Don't set SFINAE parameter!");

View File

@@ -89,7 +89,7 @@ namespace snmalloc
template<typename Anc>
Anc* ancestor()
{
if constexpr (std::is_same_v<Anc, Parent>)
if constexpr (stl::is_same_v<Anc, Parent>)
{
return &parent;
}
@@ -119,7 +119,7 @@ namespace snmalloc
template<typename Anc>
Anc* ancestor()
{
if constexpr (std::is_same_v<Anc, Parent>)
if constexpr (stl::is_same_v<Anc, Parent>)
{
return &parent;
}
@@ -150,7 +150,7 @@ namespace snmalloc
template<typename Anc>
Anc* ancestor()
{
if constexpr (std::is_same_v<Anc, Parent>)
if constexpr (stl::is_same_v<Anc, Parent>)
{
return parent;
}

View File

@@ -42,7 +42,7 @@ namespace snmalloc
using ChunkBounds = typename ActualParentRange::ChunkBounds;
static_assert(
std::is_same_v<ChunkBounds, typename ParentRange::ChunkBounds>,
stl::is_same_v<ChunkBounds, typename ParentRange::ChunkBounds>,
"Grandparent and optional parent range chunk bounds must be equal");
constexpr Type() = default;

View File

@@ -7,13 +7,13 @@
namespace snmalloc
{
template<typename PAL>
std::enable_if_t<pal_supports<Entropy, PAL>, uint64_t> get_entropy64()
stl::enable_if_t<pal_supports<Entropy, PAL>, uint64_t> get_entropy64()
{
return PAL::get_entropy64();
}
template<typename PAL>
std::enable_if_t<!pal_supports<Entropy, PAL>, uint64_t> get_entropy64()
stl::enable_if_t<!pal_supports<Entropy, PAL>, uint64_t> get_entropy64()
{
#ifdef SNMALLOC_PLATFORM_HAS_GETENTROPY
return DefaultPal::get_entropy64();

View File

@@ -36,7 +36,7 @@ namespace snmalloc
void push(T* item)
{
static_assert(
std::is_same<decltype(T::next), stl::Atomic<T*>>::value,
stl::is_same_v<decltype(T::next), stl::Atomic<T*>>,
"T->next must be an stl::Atomic<T*>");
return push(item, item);

View File

@@ -83,7 +83,7 @@ namespace snmalloc
* fixed-range pagemaps, whose size depends on dynamic configuration.
*/
template<bool has_bounds_ = has_bounds>
static constexpr std::enable_if_t<!has_bounds_, size_t> required_size()
static constexpr stl::enable_if_t<!has_bounds_, size_t> required_size()
{
static_assert(
has_bounds_ == has_bounds, "Don't set SFINAE template parameter!");
@@ -99,7 +99,7 @@ namespace snmalloc
* `required_size` is enabled for the has-bounds case.
*/
template<bool has_bounds_ = has_bounds>
std::enable_if_t<!has_bounds_> init(T* address)
stl::enable_if_t<!has_bounds_> init(T* address)
{
SNMALLOC_ASSERT(!is_initialised());
@@ -115,7 +115,7 @@ namespace snmalloc
* Returns usable range after pagemap has been allocated
*/
template<bool has_bounds_ = has_bounds>
std::enable_if_t<has_bounds_, std::pair<void*, size_t>>
stl::enable_if_t<has_bounds_, std::pair<void*, size_t>>
init(void* b, size_t s)
{
SNMALLOC_ASSERT(!is_initialised());
@@ -174,7 +174,7 @@ namespace snmalloc
* Initialise the pagemap without bounds.
*/
template<bool randomize_position, bool has_bounds_ = has_bounds>
std::enable_if_t<!has_bounds_> init()
stl::enable_if_t<!has_bounds_> init()
{
SNMALLOC_ASSERT(!is_initialised());
@@ -250,7 +250,7 @@ namespace snmalloc
}
template<bool has_bounds_ = has_bounds>
std::enable_if_t<has_bounds_, std::pair<address_t, size_t>> get_bounds()
stl::enable_if_t<has_bounds_, std::pair<address_t, size_t>> get_bounds()
{
SNMALLOC_ASSERT(is_initialised());

View File

@@ -3,8 +3,7 @@
#include "../ds_core/ds_core.h"
#include "flaglock.h"
#include "snmalloc/stl/atomic.h"
#include <type_traits>
#include "snmalloc/stl/type_traits.h"
namespace snmalloc
{

View File

@@ -7,10 +7,10 @@
#include "defines.h"
#include "snmalloc/stl/atomic.h"
#include "snmalloc/stl/type_traits.h"
#include <climits>
#include <cstdint>
#include <type_traits>
#if defined(_MSC_VER)
# include <intsafe.h>
#endif
@@ -55,7 +55,7 @@ namespace snmalloc
template<typename T = size_t, typename S>
constexpr T one_at_bit(S shift)
{
static_assert(std::is_integral_v<T>, "Type must be integral");
static_assert(stl::is_integral_v<T>, "Type must be integral");
SNMALLOC_ASSERT(sizeof(T) * 8 > static_cast<size_t>(shift));
return (static_cast<T>(1)) << shift;
}
@@ -95,15 +95,15 @@ namespace snmalloc
return BITS - index - 1;
# endif
#else
if constexpr (std::is_same_v<unsigned long, std::size_t>)
if constexpr (stl::is_same_v<unsigned long, std::size_t>)
{
return static_cast<size_t>(__builtin_clzl(x));
}
else if constexpr (std::is_same_v<unsigned long long, std::size_t>)
else if constexpr (stl::is_same_v<unsigned long long, std::size_t>)
{
return static_cast<size_t>(__builtin_clzll(x));
}
else if constexpr (std::is_same_v<unsigned int, std::size_t>)
else if constexpr (stl::is_same_v<unsigned int, std::size_t>)
{
return static_cast<size_t>(__builtin_clz(x));
}
@@ -182,15 +182,15 @@ namespace snmalloc
return _tzcnt_u32(static_cast<unsigned int>(x));
# endif
#else
if constexpr (std::is_same_v<unsigned long, std::size_t>)
if constexpr (stl::is_same_v<unsigned long, std::size_t>)
{
return static_cast<size_t>(__builtin_ctzl(x));
}
else if constexpr (std::is_same_v<unsigned long long, std::size_t>)
else if constexpr (stl::is_same_v<unsigned long long, std::size_t>)
{
return static_cast<size_t>(__builtin_ctzll(x));
}
else if constexpr (std::is_same_v<unsigned int, std::size_t>)
else if constexpr (stl::is_same_v<unsigned int, std::size_t>)
{
return static_cast<size_t>(__builtin_ctz(x));
}

View File

@@ -1,6 +1,6 @@
#pragma once
#include <type_traits>
#include "snmalloc/stl/type_traits.h"
/**
* C++20 concepts are referenced as if they were types in declarations within
@@ -20,31 +20,15 @@
#ifdef __cpp_concepts
namespace snmalloc
{
/**
* C++20 concepts are more than just new syntax; there's a new support
* library specified as well. As C++20 is quite new, however, there are some
* environments, notably Clang, that understand the syntax but do not yet
* offer the library. Fortunately, alternate pronouciations are possible.
*/
# ifdef _cpp_lib_concepts
/**
* ConceptSame<T,U> is true if T and U are the same type and false otherwise.
* When specifying a concept, use ConceptSame<U> to indicate that an
* expression must evaluate precisely to the type U.
*/
template<typename T, typename U>
concept ConceptSame = std::same_as<T, U>;
# else
template<typename T, typename U>
concept ConceptSame = std::is_same<T, U>::value;
# endif
concept ConceptSame = stl::is_same_v<T, U>;
/**
* Equivalence mod std::remove_reference
* Equivalence mod stl::remove_reference
*/
template<typename T, typename U>
concept ConceptSameModRef =
ConceptSame<std::remove_reference_t<T>, std::remove_reference_t<U>>;
ConceptSame<stl::remove_reference_t<T>, stl::remove_reference_t<U>>;
/**
* Some of the types in snmalloc are circular in their definition and use
@@ -73,7 +57,7 @@ namespace snmalloc
constexpr bool is_type_complete_v = false;
template<typename T>
constexpr bool is_type_complete_v<T, std::void_t<decltype(sizeof(T))>> = true;
constexpr bool is_type_complete_v<T, stl::void_t<decltype(sizeof(T))>> = true;
} // namespace snmalloc
#endif

View File

@@ -2,10 +2,10 @@
#include "bits.h"
#include "snmalloc/ds_core/defines.h"
#include "snmalloc/stl/type_traits.h"
#include <array>
#include <cstddef>
#include <type_traits>
namespace snmalloc
{
@@ -104,7 +104,7 @@ namespace snmalloc
template<
typename Fn,
typename =
std::enable_if_t<!std::is_same_v<std::decay_t<Fn>, function_ref>>>
stl::enable_if_t<!stl::is_same_v<std::decay_t<Fn>, function_ref>>>
function_ref(Fn&& fn)
{
data_ = static_cast<void*>(&fn);
@@ -123,7 +123,7 @@ namespace snmalloc
template<typename Fn>
static R execute(void* p, Args... args)
{
return (*static_cast<std::add_pointer_t<Fn>>(p))(args...);
return (*static_cast<stl::add_pointer_t<Fn>>(p))(args...);
};
};

View File

@@ -18,7 +18,7 @@ namespace snmalloc
*/
template<typename T>
SNMALLOC_FAST_PATH_INLINE uintptr_t
unsafe_to_uintptr(std::enable_if_t<true, T>* p)
unsafe_to_uintptr(stl::enable_if_t<true, T>* p)
{
return reinterpret_cast<uintptr_t>(p);
}

View File

@@ -60,7 +60,7 @@ namespace snmalloc
} -> ConceptSameModRef<const typename Rep::Contents>;
{
typename Rep::Handle{const_cast<
std::remove_const_t<std::remove_reference_t<decltype(Rep::root)>>*>(
stl::remove_const_t<stl::remove_reference_t<decltype(Rep::root)>>*>(
&Rep::root)}
} -> ConceptSame<typename Rep::Handle>;
};
@@ -70,7 +70,7 @@ namespace snmalloc
RBRepTypes<Rep> //
&& RBRepMethods<Rep> //
&&
ConceptSame<decltype(Rep::null), std::add_const_t<typename Rep::Contents>>;
ConceptSame<decltype(Rep::null), stl::add_const_t<typename Rep::Contents>>;
#endif
/**
@@ -156,7 +156,7 @@ namespace snmalloc
};
// Root field of the tree
typename std::remove_const_t<std::remove_reference_t<decltype(Rep::root)>>
typename stl::remove_const_t<stl::remove_reference_t<decltype(Rep::root)>>
root{Rep::root};
static ChildRef get_dir(bool direction, K k)

View File

@@ -2,9 +2,9 @@
#include "../aal/aal.h"
#include "../ds_core/ds_core.h"
#include "snmalloc/stl/type_traits.h"
#include <cstdint>
#include <type_traits>
namespace snmalloc
{
@@ -98,7 +98,7 @@ namespace snmalloc
SNMALLOC_FAST_PATH bool is_empty()
{
static_assert(
std::is_same_v<Node, decltype(std::declval<T>().node)>,
stl::is_same_v<Node, decltype(std::declval<T>().node)>,
"T->node must be Node for T");
head.invariant();
return head.next == &head;

View File

@@ -182,7 +182,7 @@ namespace snmalloc::libc
return ThreadAlloc::get().get_client_meta_data(p);
}
inline std::add_const_t<typename snmalloc::Alloc::Config::ClientMeta::DataRef>
inline stl::add_const_t<typename snmalloc::Alloc::Config::ClientMeta::DataRef>
get_client_meta_data_const(void* p)
{
return ThreadAlloc::get().get_client_meta_data_const(p);

View File

@@ -418,7 +418,7 @@ namespace snmalloc
#elif defined(__powerpc64__)
PPC64Arch
#else
std::conditional_t<
stl::conditional_t<
aal_supports<StrictProvenance>,
GenericStrictProvenance,
GenericArch>

View File

@@ -148,7 +148,7 @@ namespace snmalloc
*
*/
template<typename Config>
concept IsConfig = std::is_base_of<CommonConfig, Config>::value &&
concept IsConfig = stl::is_base_of_v<CommonConfig, Config> &&
IsPAL<typename Config::Pal> &&
IsBackend<typename Config::LocalState,
typename Config::PagemapEntry,

View File

@@ -43,8 +43,8 @@ namespace snmalloc
SNMALLOC_CONCEPT(IsConfigDomestication) Config,
typename T,
SNMALLOC_CONCEPT(capptr::IsBound) B>
constexpr SNMALLOC_FAST_PATH auto has_domesticate(int) -> std::enable_if_t<
std::is_same_v<
constexpr SNMALLOC_FAST_PATH auto has_domesticate(int) -> stl::enable_if_t<
stl::is_same_v<
decltype(Config::capptr_domesticate(
std::declval<typename Config::LocalState*>(),
std::declval<CapPtr<T, B>>())),

View File

@@ -33,7 +33,7 @@ namespace snmalloc
* `init_message_queue`.
*/
template<SNMALLOC_CONCEPT(IsConfigLazy) Config>
class CoreAllocator : public std::conditional_t<
class CoreAllocator : public stl::conditional_t<
Config::Options.CoreAllocIsPoolAllocated,
Pooled<CoreAllocator<Config>>,
Empty>
@@ -78,7 +78,7 @@ namespace snmalloc
* Message queue for allocations being returned to this
* allocator
*/
std::conditional_t<
stl::conditional_t<
Config::Options.IsQueueInline,
RemoteAllocator,
RemoteAllocator*>
@@ -95,7 +95,7 @@ namespace snmalloc
* core allocator owns the local state or indirect if it is owned
* externally.
*/
std::conditional_t<
stl::conditional_t<
Config::Options.CoreAllocOwnsLocalState,
LocalState,
LocalState*>
@@ -661,7 +661,7 @@ namespace snmalloc
*/
template<
typename Config_ = Config,
typename = std::enable_if_t<Config_::Options.CoreAllocOwnsLocalState>>
typename = stl::enable_if_t<Config_::Options.CoreAllocOwnsLocalState>>
CoreAllocator(Range<capptr::bounds::Alloc>& spare)
{
init(spare);
@@ -676,7 +676,7 @@ namespace snmalloc
*/
template<
typename Config_ = Config,
typename = std::enable_if_t<!Config_::Options.CoreAllocOwnsLocalState>>
typename = stl::enable_if_t<!Config_::Options.CoreAllocOwnsLocalState>>
CoreAllocator(
Range<capptr::bounds::Alloc>& spare,
LocalCache<Config_>* cache,
@@ -691,7 +691,7 @@ namespace snmalloc
* configure the message queue for use.
*/
template<bool InlineQueue = Config::Options.IsQueueInline>
std::enable_if_t<!InlineQueue> init_message_queue(RemoteAllocator* q)
stl::enable_if_t<!InlineQueue> init_message_queue(RemoteAllocator* q)
{
remote_alloc = q;
init_message_queue();

View File

@@ -2,9 +2,9 @@
#include "../ds/ds.h"
#include "../pal/pal.h"
#include "snmalloc/stl/type_traits.h"
#include <cstdint>
#include <type_traits>
namespace snmalloc
{

View File

@@ -182,7 +182,7 @@ namespace snmalloc
};
SNMALLOC_NO_UNIQUE_ADDRESS
std::conditional_t<mitigations(freelist_backward_edge), Prev, Empty>
stl::conditional_t<mitigations(freelist_backward_edge), Prev, Empty>
prev{};
public:
@@ -377,7 +377,7 @@ namespace snmalloc
"Free Object View must be domesticated, justifying raw pointers");
static_assert(
std::is_same_v<
stl::is_same_v<
typename BQueue::template with_wildness<
capptr::dimension::Wildness::Tame>,
BView>,
@@ -554,7 +554,7 @@ namespace snmalloc
};
using IterBase =
std::conditional_t<mitigations(freelist_backward_edge), Prev, NoPrev>;
stl::conditional_t<mitigations(freelist_backward_edge), Prev, NoPrev>;
/**
* Used to iterate a free list in object space.
@@ -596,7 +596,7 @@ namespace snmalloc
};
SNMALLOC_NO_UNIQUE_ADDRESS
std::conditional_t<
stl::conditional_t<
mitigations(freelist_forward_edge) ||
mitigations(freelist_backward_edge),
KeyTweak,
@@ -774,7 +774,7 @@ namespace snmalloc
* lists, which will be randomised at the other end.
*/
template<bool RANDOM_ = RANDOM>
std::enable_if_t<!RANDOM_> add(
stl::enable_if_t<!RANDOM_> add(
Object::BHeadPtr<BView, BQueue> n,
const FreeListKey& key,
address_t key_tweak)
@@ -896,14 +896,14 @@ namespace snmalloc
}
template<bool RANDOM_ = RANDOM>
std::enable_if_t<!RANDOM_, size_t> extract_segment_length()
stl::enable_if_t<!RANDOM_, size_t> extract_segment_length()
{
static_assert(RANDOM_ == RANDOM, "Don't set SFINAE parameter!");
return length[0];
}
template<bool RANDOM_ = RANDOM>
std::enable_if_t<
stl::enable_if_t<
!RANDOM_,
std::pair<
Object::BHeadPtr<BView, BQueue>,

View File

@@ -853,7 +853,7 @@ namespace snmalloc
* @brief Get the client meta data for the snmalloc allocation covering this
* pointer.
*/
std::add_const_t<typename Config::ClientMeta::DataRef>
stl::add_const_t<typename Config::ClientMeta::DataRef>
get_client_meta_data_const(void* p)
{
const PagemapEntry& entry =

View File

@@ -454,7 +454,7 @@ namespace snmalloc
smallsizeclass_t sizeclass, address_t slab, const FreeListKey& key)
{
static_assert(
std::is_base_of<FrontendSlabMetadata_Trait, BackendType>::value,
stl::is_base_of_v<FrontendSlabMetadata_Trait, BackendType>,
"Template should be a subclass of FrontendSlabMetadata");
free_queue.init(slab, key, this->as_key_tweak());
// Set up meta data as if the entire slab has been turned into a free
@@ -629,7 +629,7 @@ namespace snmalloc
{
auto& key = freelist::Object::key_root;
std::remove_reference_t<decltype(fast_free_list)> tmp_fl;
stl::remove_reference_t<decltype(fast_free_list)> tmp_fl;
auto remaining =
meta->free_queue.close(tmp_fl, key, meta->as_key_tweak());
@@ -707,7 +707,7 @@ namespace snmalloc
* Ensure that the template parameter is valid.
*/
static_assert(
std::is_convertible_v<SlabMetadataType, FrontendSlabMetadata_Trait>,
stl::is_convertible_v<SlabMetadataType, FrontendSlabMetadata_Trait>,
"The front end requires that the back end provides slab metadata that is "
"compatible with the front-end's structure");

View File

@@ -274,7 +274,7 @@ namespace snmalloc
static_assert(offsetof(SingletonRemoteMessage, message_link) == 0);
};
using RemoteMessage = std::conditional_t<
using RemoteMessage = stl::conditional_t<
(DEALLOC_BATCH_RINGS > 0),
BatchedRemoteMessage,
SingletonRemoteMessage>;

View File

@@ -180,7 +180,7 @@ namespace snmalloc
};
template<typename Config>
using RemoteDeallocCacheBatchingImpl = std::conditional_t<
using RemoteDeallocCacheBatchingImpl = stl::conditional_t<
(DEALLOC_BATCH_RINGS > 0),
RemoteDeallocCacheBatching<Config, DEALLOC_BATCH_RINGS>,
RemoteDeallocCacheNoBatching<Config>>;

View File

@@ -85,7 +85,7 @@ namespace snmalloc
typename AAL = Aal,
typename T,
SNMALLOC_CONCEPT(capptr::IsBound) B>
static inline typename std::enable_if_t<
static inline typename stl::enable_if_t<
!aal_supports<StrictProvenance, AAL>,
CapPtr<T, capptr::user_address_control_type<B>>>
capptr_to_user_address_control(CapPtr<T, B> p)
@@ -99,7 +99,7 @@ namespace snmalloc
typename AAL = Aal,
typename T,
SNMALLOC_CONCEPT(capptr::IsBound) B>
static SNMALLOC_FAST_PATH typename std::enable_if_t<
static SNMALLOC_FAST_PATH typename stl::enable_if_t<
aal_supports<StrictProvenance, AAL>,
CapPtr<T, capptr::user_address_control_type<B>>>
capptr_to_user_address_control(CapPtr<T, B> p)

View File

@@ -21,7 +21,7 @@ namespace snmalloc
template<typename PAL>
concept IsPAL_static_features =
requires() {
typename std::integral_constant<uint64_t, PAL::pal_features>;
typename stl::integral_constant<uint64_t, PAL::pal_features>;
};
/**
@@ -30,8 +30,8 @@ namespace snmalloc
template<typename PAL>
concept IsPAL_static_sizes =
requires() {
typename std::integral_constant<std::size_t, PAL::address_bits>;
typename std::integral_constant<std::size_t, PAL::page_size>;
typename stl::integral_constant<std::size_t, PAL::address_bits>;
typename stl::integral_constant<std::size_t, PAL::page_size>;
};
/**

View File

@@ -14,7 +14,7 @@ namespace snmalloc
stl::Atomic<T*> elements{nullptr};
static_assert(
std::is_same<decltype(T::pal_next), stl::Atomic<T*>>::value,
stl::is_same_v<decltype(T::pal_next), stl::Atomic<T*>>,
"Required pal_next type.");
public:

View File

@@ -0,0 +1,46 @@
#pragma once
#include <type_traits>
namespace snmalloc
{
namespace stl
{
using std::add_const_t;
using std::add_lvalue_reference_t;
using std::add_pointer_t;
using std::add_rvalue_reference_t;
using std::bool_constant;
using std::conditional;
using std::conditional_t;
using std::decay;
using std::decay_t;
using std::enable_if;
using std::enable_if_t;
using std::false_type;
using std::has_unique_object_representations_v;
using std::integral_constant;
using std::is_array_v;
using std::is_base_of_v;
using std::is_convertible_v;
using std::is_copy_assignable_v;
using std::is_copy_constructible_v;
using std::is_function_v;
using std::is_integral;
using std::is_integral_v;
using std::is_move_assignable_v;
using std::is_move_constructible_v;
using std::is_same;
using std::is_same_v;
using std::is_trivially_copyable_v;
using std::remove_all_extents_t;
using std::remove_const_t;
using std::remove_cv;
using std::remove_cv_t;
using std::remove_extent_t;
using std::remove_reference;
using std::remove_reference_t;
using std::true_type;
using std::void_t;
} // namespace stl
} // namespace snmalloc

View File

@@ -1,7 +1,8 @@
#pragma once
#include "snmalloc/stl/type_traits.h"
#include <stddef.h>
#include <type_traits> // TODO: switch the vendored headers when we have them.
namespace snmalloc
{
@@ -29,15 +30,15 @@ namespace snmalloc
class Atomic
{
static_assert(
std::is_trivially_copyable_v<T> && std::is_copy_constructible_v<T> &&
std::is_move_constructible_v<T> && std::is_copy_assignable_v<T> &&
std::is_move_assignable_v<T>,
stl::is_trivially_copyable_v<T> && stl::is_copy_constructible_v<T> &&
stl::is_move_constructible_v<T> && stl::is_copy_assignable_v<T> &&
stl::is_move_assignable_v<T>,
"Atomic<T> requires T to be trivially copyable, copy "
"constructible, move constructible, copy assignable, "
"and move assignable.");
static_assert(
std::has_unique_object_representations_v<T>,
stl::has_unique_object_representations_v<T>,
"vendored Atomic only supports types with unique object "
"representations");
@@ -180,48 +181,48 @@ namespace snmalloc
SNMALLOC_FAST_PATH T
fetch_add(T increment, MemoryOrder mem_ord = MemoryOrder::SEQ_CST)
{
static_assert(std::is_integral_v<T>, "T must be an integral type.");
static_assert(stl::is_integral_v<T>, "T must be an integral type.");
return __atomic_fetch_add(addressof(val), increment, order(mem_ord));
}
SNMALLOC_FAST_PATH T
fetch_or(T mask, MemoryOrder mem_ord = MemoryOrder::SEQ_CST)
{
static_assert(std::is_integral_v<T>, "T must be an integral type.");
static_assert(stl::is_integral_v<T>, "T must be an integral type.");
return __atomic_fetch_or(addressof(val), mask, order(mem_ord));
}
SNMALLOC_FAST_PATH T
fetch_and(T mask, MemoryOrder mem_ord = MemoryOrder::SEQ_CST)
{
static_assert(std::is_integral_v<T>, "T must be an integral type.");
static_assert(stl::is_integral_v<T>, "T must be an integral type.");
return __atomic_fetch_and(addressof(val), mask, order(mem_ord));
}
SNMALLOC_FAST_PATH T
fetch_sub(T decrement, MemoryOrder mem_ord = MemoryOrder::SEQ_CST)
{
static_assert(std::is_integral_v<T>, "T must be an integral type.");
static_assert(stl::is_integral_v<T>, "T must be an integral type.");
return __atomic_fetch_sub(addressof(val), decrement, order(mem_ord));
}
SNMALLOC_FAST_PATH T operator++()
{
static_assert(std::is_integral_v<T>, "T must be an integral type.");
static_assert(stl::is_integral_v<T>, "T must be an integral type.");
return __atomic_add_fetch(
addressof(val), 1, order(MemoryOrder::SEQ_CST));
}
SNMALLOC_FAST_PATH const T operator++(int)
{
static_assert(std::is_integral_v<T>, "T must be an integral type.");
static_assert(stl::is_integral_v<T>, "T must be an integral type.");
return __atomic_fetch_add(
addressof(val), 1, order(MemoryOrder::SEQ_CST));
}
SNMALLOC_FAST_PATH T operator-=(T decrement)
{
static_assert(std::is_integral_v<T>, "T must be an integral type.");
static_assert(stl::is_integral_v<T>, "T must be an integral type.");
return __atomic_sub_fetch(
addressof(val), decrement, order(MemoryOrder::SEQ_CST));
}

View File

@@ -0,0 +1,394 @@
#pragma once
#include <stddef.h>
namespace snmalloc
{
namespace stl
{
/**
* Type identity metafunction.
*/
template<typename T>
struct type_identity
{
using type = T;
};
template<typename T>
using type_identity_t = typename type_identity<T>::type;
/**
* Integral constant.
*/
template<typename T, T v>
struct integral_constant
{
using value_type = T;
static constexpr T value = v;
};
template<bool B>
using bool_constant = integral_constant<bool, B>;
using true_type = bool_constant<true>;
using false_type = bool_constant<false>;
/**
* Remove CV qualifiers.
*/
template<class T>
struct remove_cv : type_identity<T>
{};
template<class T>
struct remove_cv<const T> : type_identity<T>
{};
template<class T>
struct remove_cv<volatile T> : type_identity<T>
{};
template<class T>
struct remove_cv<const volatile T> : type_identity<T>
{};
template<class T>
using remove_cv_t = typename remove_cv<T>::type;
/**
* Type equality.
*/
template<typename T, typename U>
struct is_same : false_type
{};
template<typename T>
struct is_same<T, T> : true_type
{};
template<typename T, typename U>
inline constexpr bool is_same_v = is_same<T, U>::value;
/**
* Is integral type.
*/
template<typename T>
struct is_integral
{
private:
template<typename Head, typename... Args>
static constexpr bool is_unqualified_any_of()
{
return (... || is_same_v<remove_cv_t<Head>, Args>);
}
public:
static constexpr bool value = is_unqualified_any_of<
T,
#ifdef __SIZEOF_INT128__
__int128_t,
__uint128_t,
#endif
char,
signed char,
unsigned char,
short,
unsigned short,
int,
unsigned int,
long,
unsigned long,
long long,
unsigned long long,
bool>();
};
template<typename T>
inline constexpr bool is_integral_v = is_integral<T>::value;
/**
* Remove all array extents.
*/
#if __has_builtin(__remove_all_extents)
template<typename T>
using remove_all_extents_t = __remove_all_extents(T);
#else
template<class T>
struct remove_all_extents
{
using type = T;
};
template<class T>
struct remove_all_extents<T[]>
{
using type = typename remove_all_extents<T>::type;
};
template<class T, size_t N>
struct remove_all_extents<T[N]>
{
using type = typename remove_all_extents<T>::type;
};
template<class T>
using remove_all_extents_t = typename remove_all_extents<T>::type;
#endif
/**
* void_t
*/
template<typename... Ts>
using void_t = typename type_identity<void>::type;
/**
* Has unique object representations.
*/
/* remove_all_extents_t is needed due to clang's behavior */
template<class T>
inline constexpr bool has_unique_object_representations_v =
__has_unique_object_representations(remove_all_extents_t<T>);
/**
* enable_if
*/
template<bool B, typename T = void>
struct enable_if;
template<typename T>
struct enable_if<true, T> : type_identity<T>
{};
template<bool B, typename T = void>
using enable_if_t = typename enable_if<B, T>::type;
/**
* conditional
*/
template<bool B, typename T, typename F>
struct conditional : type_identity<T>
{};
template<typename T, typename F>
struct conditional<false, T, F> : type_identity<F>
{};
template<bool B, typename T, typename F>
using conditional_t = typename conditional<B, T, F>::type;
/**
* add_lvalue_reference/add_rvalue_reference
*/
#if __has_builtin(__add_lvalue_reference)
template<class T>
using add_lvalue_reference_t = __add_lvalue_reference(T);
#else
template<class T> // Note that `cv void&` is a substitution failure
auto __add_lvalue_reference_impl(int) -> type_identity<T&>;
template<class T> // Handle T = cv void case
auto __add_lvalue_reference_impl(...) -> type_identity<T>;
template<class T>
struct add_lvalue_reference : decltype(__add_lvalue_reference_impl<T>(0))
{};
template<class T>
using add_lvalue_reference_t = typename add_lvalue_reference<T>::type;
#endif
#if __has_builtin(__add_rvalue_reference)
template<class T>
using add_rvalue_reference_t = __add_rvalue_reference(T);
#else
template<class T>
auto __add_rvalue_reference_impl(int) -> type_identity<T&&>;
template<class T>
auto __add_rvalue_referenc_impl(...) -> type_identity<T>;
template<class T>
struct add_rvalue_reference : decltype(__add_rvalue_reference_impl<T>(0))
{};
template<class T>
using add_rvalue_reference_t = typename add_rvalue_reference<T>::type;
#endif
/**
* remove_reference
*/
template<class T>
struct remove_reference : type_identity<T>
{};
template<class T>
struct remove_reference<T&> : type_identity<T>
{};
template<class T>
struct remove_reference<T&&> : type_identity<T>
{};
template<class T>
using remove_reference_t = typename remove_reference<T>::type;
/**
* add_pointer
*/
#if __has_builtin(__add_pointer)
template<class T>
using add_pointer_t = __add_pointer(T);
#else
template<class T>
auto __add_pointer_impl(int) -> type_identity<remove_reference_t<T>*>;
template<class T>
auto __add_pointer_impl(...) -> type_identity<T>;
template<class T>
struct add_pointer : decltype(__add_pointer_impl<T>(0))
{};
template<class T>
using add_pointer_t = typename add_pointer<T>::type;
#endif
/**
* is_array
*/
template<class T>
inline constexpr bool is_array_v = __is_array(T);
/**
* is_function
*/
template<typename T>
inline constexpr bool is_function_v = __is_function(T);
/**
* remove_extent
*/
#if __has_builtin(__remove_extent)
template<class T>
using remove_extent_t = __remove_extent(T);
#else
template<class T>
struct remove_extent
{
using type = T;
};
template<class T>
struct remove_extent<T[]>
{
using type = T;
};
template<class T, size_t N>
struct remove_extent<T[N]>
{
using type = T;
};
template<class T>
using remove_extent_t = typename remove_extent<T>::type;
#endif
/**
* decay
*/
#if __has_builtin(__decay)
template<class T>
using decay_t = __decay(T);
#else
template<class T>
class decay
{
using U = remove_reference_t<T>;
public:
using type = conditional_t<
is_array_v<U>,
add_pointer_t<remove_extent_t<U>>,
conditional_t<is_function_v<U>, add_pointer_t<U>, remove_cv_t<U>>>;
};
template<class T>
using decay_t = typename decay<T>::type;
#endif
/**
* is_copy_assignable
*/
template<class T>
constexpr bool is_copy_assignable_v = __is_assignable(
add_lvalue_reference_t<T>, add_lvalue_reference_t<const T>);
/**
* is_copy_constructible
*/
template<class T>
inline constexpr bool is_copy_constructible_v =
__is_constructible(T, add_lvalue_reference_t<const T>);
/**
* is_move_assignable
*/
template<class T>
constexpr bool is_move_assignable_v =
__is_assignable(add_lvalue_reference_t<T>, add_lvalue_reference_t<T>);
/**
* is_move_constructible
*/
template<class T>
inline constexpr bool is_move_constructible_v =
__is_constructible(T, add_rvalue_reference_t<T>);
/**
* is_convertible
*/
template<class From, class To>
inline constexpr bool is_convertible_v = __is_convertible(From, To);
/**
* is_base_of
*/
template<class Base, class Derived>
inline constexpr bool is_base_of_v = __is_base_of(Base, Derived);
/**
* is_trivially_copyable
*/
template<class T>
inline constexpr bool is_trivially_copyable_v = __is_trivially_copyable(T);
/**
* remove_const
*/
#if __has_builtin(__remove_const)
template<class T>
using remove_const_t = __remove_const(T);
#else
template<class T>
struct remove_const
{
using type = T;
};
template<class T>
struct remove_const<const T>
{
using type = T;
};
template<class T>
using remove_const_t = typename remove_const<T>::type;
#endif
/**
* add_const
*/
template<class T>
using add_const_t = const T;
} // namespace stl
} // namespace snmalloc

View File

@@ -0,0 +1,9 @@
#pragma once
#include "snmalloc/stl/common.h"
#if SNMALLOC_USE_SELF_VENDORED_STL
# include "snmalloc/stl/gnu/type_traits.h"
#else
# include "snmalloc/stl/cxx/type_traits.h"
#endif