diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 0bdcba2..55e634f 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -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 diff --git a/src/snmalloc/aal/aal.h b/src/snmalloc/aal/aal.h index dae6231..7648444 100644 --- a/src/snmalloc/aal/aal.h +++ b/src/snmalloc/aal/aal.h @@ -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; diff --git a/src/snmalloc/aal/aal_concept.h b/src/snmalloc/aal/aal_concept.h index eac6ebc..1ea35da 100644 --- a/src/snmalloc/aal/aal_concept.h +++ b/src/snmalloc/aal/aal_concept.h @@ -4,8 +4,7 @@ # include "../ds_core/ds_core.h" # include "aal_consts.h" -# include -# include +# include namespace snmalloc { @@ -16,10 +15,10 @@ namespace snmalloc template concept IsAAL_static_members = requires() { - typename std::integral_constant; - typename std::integral_constant; - typename std::integral_constant; - typename std::integral_constant; + typename stl::integral_constant; + typename stl::integral_constant; + typename stl::integral_constant; + typename stl::integral_constant; }; /** diff --git a/src/snmalloc/backend/fixedglobalconfig.h b/src/snmalloc/backend/fixedglobalconfig.h index 83e1117..97318c5 100644 --- a/src/snmalloc/backend/fixedglobalconfig.h +++ b/src/snmalloc/backend/fixedglobalconfig.h @@ -118,7 +118,8 @@ namespace snmalloc static_assert(B::wildness == capptr::dimension::Wildness::Wild); static const size_t sz = sizeof( - std::conditional, void>, void*, T>); + stl:: + conditional_t, void>, void*, T>); UNUSED(ls); auto address = address_cast(p); diff --git a/src/snmalloc/backend/globalconfig.h b/src/snmalloc/backend/globalconfig.h index c3e3f7b..97ca9ec 100644 --- a/src/snmalloc/backend/globalconfig.h +++ b/src/snmalloc/backend/globalconfig.h @@ -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, StandardLocalState>; diff --git a/src/snmalloc/backend/meta_protected_range.h b/src/snmalloc/backend/meta_protected_range.h index b94968c..857e853 100644 --- a/src/snmalloc/backend/meta_protected_range.h +++ b/src/snmalloc/backend/meta_protected_range.h @@ -75,7 +75,7 @@ namespace snmalloc CommitRange, // 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, diff --git a/src/snmalloc/backend_helpers/authmap.h b/src/snmalloc/backend_helpers/authmap.h index 9ad4f06..f79ec8e 100644 --- a/src/snmalloc/backend_helpers/authmap.h +++ b/src/snmalloc/backend_helpers/authmap.h @@ -31,7 +31,7 @@ namespace snmalloc struct BasicAuthmap { static_assert( - std::is_same_v, typename ConcreteMap::EntryType>, + stl::is_same_v, typename ConcreteMap::EntryType>, "BasicAuthmap's ConcreteMap must have capptr::Arena element type!"); private: @@ -70,7 +70,7 @@ namespace snmalloc * Pick between the two above implementations based on StrictProvenance */ template - using DefaultAuthmap = std::conditional_t< + using DefaultAuthmap = stl::conditional_t< aal_supports, BasicAuthmap, DummyAuthmap>; diff --git a/src/snmalloc/backend_helpers/largebuddyrange.h b/src/snmalloc/backend_helpers/largebuddyrange.h index 803eb48..1532475 100644 --- a/src/snmalloc/backend_helpers/largebuddyrange.h +++ b/src/snmalloc/backend_helpers/largebuddyrange.h @@ -228,7 +228,7 @@ namespace snmalloc * covers the whole range. Uses template insanity to make this work. */ template - std::enable_if_t + stl::enable_if_t parent_dealloc_range(capptr::Arena 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); + stl::is_same_v); constexpr Type() = default; diff --git a/src/snmalloc/backend_helpers/pagemap.h b/src/snmalloc/backend_helpers/pagemap.h index 1eaf95d..6a0cc59 100644 --- a/src/snmalloc/backend_helpers/pagemap.h +++ b/src/snmalloc/backend_helpers/pagemap.h @@ -29,11 +29,11 @@ namespace snmalloc using Entry = PagemapEntry; static_assert( - std::is_same_v, + stl::is_same_v, "BasicPagemap's PagemapEntry and ConcreteMap disagree!"); static_assert( - std::is_base_of_v, + stl::is_base_of_v, "BasicPagemap's PagemapEntry type is not a MetaEntryBase"); /** @@ -115,7 +115,7 @@ namespace snmalloc */ template static SNMALLOC_FAST_PATH - std::enable_if_t> + stl::enable_if_t> get_bounds() { static_assert(fixed_range_ == fixed_range, "Don't set SFINAE parameter!"); diff --git a/src/snmalloc/backend_helpers/range_helpers.h b/src/snmalloc/backend_helpers/range_helpers.h index f1a82ba..77455ff 100644 --- a/src/snmalloc/backend_helpers/range_helpers.h +++ b/src/snmalloc/backend_helpers/range_helpers.h @@ -89,7 +89,7 @@ namespace snmalloc template Anc* ancestor() { - if constexpr (std::is_same_v) + if constexpr (stl::is_same_v) { return &parent; } @@ -119,7 +119,7 @@ namespace snmalloc template Anc* ancestor() { - if constexpr (std::is_same_v) + if constexpr (stl::is_same_v) { return &parent; } @@ -150,7 +150,7 @@ namespace snmalloc template Anc* ancestor() { - if constexpr (std::is_same_v) + if constexpr (stl::is_same_v) { return parent; } diff --git a/src/snmalloc/backend_helpers/staticconditionalrange.h b/src/snmalloc/backend_helpers/staticconditionalrange.h index 4663713..682c2f1 100644 --- a/src/snmalloc/backend_helpers/staticconditionalrange.h +++ b/src/snmalloc/backend_helpers/staticconditionalrange.h @@ -42,7 +42,7 @@ namespace snmalloc using ChunkBounds = typename ActualParentRange::ChunkBounds; static_assert( - std::is_same_v, + stl::is_same_v, "Grandparent and optional parent range chunk bounds must be equal"); constexpr Type() = default; diff --git a/src/snmalloc/ds/entropy.h b/src/snmalloc/ds/entropy.h index 431495e..1282c29 100644 --- a/src/snmalloc/ds/entropy.h +++ b/src/snmalloc/ds/entropy.h @@ -7,13 +7,13 @@ namespace snmalloc { template - std::enable_if_t, uint64_t> get_entropy64() + stl::enable_if_t, uint64_t> get_entropy64() { return PAL::get_entropy64(); } template - std::enable_if_t, uint64_t> get_entropy64() + stl::enable_if_t, uint64_t> get_entropy64() { #ifdef SNMALLOC_PLATFORM_HAS_GETENTROPY return DefaultPal::get_entropy64(); diff --git a/src/snmalloc/ds/mpmcstack.h b/src/snmalloc/ds/mpmcstack.h index 5024b19..f1e965e 100644 --- a/src/snmalloc/ds/mpmcstack.h +++ b/src/snmalloc/ds/mpmcstack.h @@ -36,7 +36,7 @@ namespace snmalloc void push(T* item) { static_assert( - std::is_same>::value, + stl::is_same_v>, "T->next must be an stl::Atomic"); return push(item, item); diff --git a/src/snmalloc/ds/pagemap.h b/src/snmalloc/ds/pagemap.h index d8636f6..1d28546 100644 --- a/src/snmalloc/ds/pagemap.h +++ b/src/snmalloc/ds/pagemap.h @@ -83,7 +83,7 @@ namespace snmalloc * fixed-range pagemaps, whose size depends on dynamic configuration. */ template - static constexpr std::enable_if_t required_size() + static constexpr stl::enable_if_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 - std::enable_if_t init(T* address) + stl::enable_if_t init(T* address) { SNMALLOC_ASSERT(!is_initialised()); @@ -115,7 +115,7 @@ namespace snmalloc * Returns usable range after pagemap has been allocated */ template - std::enable_if_t> + stl::enable_if_t> init(void* b, size_t s) { SNMALLOC_ASSERT(!is_initialised()); @@ -174,7 +174,7 @@ namespace snmalloc * Initialise the pagemap without bounds. */ template - std::enable_if_t init() + stl::enable_if_t init() { SNMALLOC_ASSERT(!is_initialised()); @@ -250,7 +250,7 @@ namespace snmalloc } template - std::enable_if_t> get_bounds() + stl::enable_if_t> get_bounds() { SNMALLOC_ASSERT(is_initialised()); diff --git a/src/snmalloc/ds/singleton.h b/src/snmalloc/ds/singleton.h index c8edae2..6375c13 100644 --- a/src/snmalloc/ds/singleton.h +++ b/src/snmalloc/ds/singleton.h @@ -3,8 +3,7 @@ #include "../ds_core/ds_core.h" #include "flaglock.h" #include "snmalloc/stl/atomic.h" - -#include +#include "snmalloc/stl/type_traits.h" namespace snmalloc { diff --git a/src/snmalloc/ds_core/bits.h b/src/snmalloc/ds_core/bits.h index 8ead754..ff481f9 100644 --- a/src/snmalloc/ds_core/bits.h +++ b/src/snmalloc/ds_core/bits.h @@ -7,10 +7,10 @@ #include "defines.h" #include "snmalloc/stl/atomic.h" +#include "snmalloc/stl/type_traits.h" #include #include -#include #if defined(_MSC_VER) # include #endif @@ -55,7 +55,7 @@ namespace snmalloc template constexpr T one_at_bit(S shift) { - static_assert(std::is_integral_v, "Type must be integral"); + static_assert(stl::is_integral_v, "Type must be integral"); SNMALLOC_ASSERT(sizeof(T) * 8 > static_cast(shift)); return (static_cast(1)) << shift; } @@ -95,15 +95,15 @@ namespace snmalloc return BITS - index - 1; # endif #else - if constexpr (std::is_same_v) + if constexpr (stl::is_same_v) { return static_cast(__builtin_clzl(x)); } - else if constexpr (std::is_same_v) + else if constexpr (stl::is_same_v) { return static_cast(__builtin_clzll(x)); } - else if constexpr (std::is_same_v) + else if constexpr (stl::is_same_v) { return static_cast(__builtin_clz(x)); } @@ -182,15 +182,15 @@ namespace snmalloc return _tzcnt_u32(static_cast(x)); # endif #else - if constexpr (std::is_same_v) + if constexpr (stl::is_same_v) { return static_cast(__builtin_ctzl(x)); } - else if constexpr (std::is_same_v) + else if constexpr (stl::is_same_v) { return static_cast(__builtin_ctzll(x)); } - else if constexpr (std::is_same_v) + else if constexpr (stl::is_same_v) { return static_cast(__builtin_ctz(x)); } diff --git a/src/snmalloc/ds_core/concept.h b/src/snmalloc/ds_core/concept.h index 996af5f..001642c 100644 --- a/src/snmalloc/ds_core/concept.h +++ b/src/snmalloc/ds_core/concept.h @@ -1,6 +1,6 @@ #pragma once -#include +#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 is true if T and U are the same type and false otherwise. - * When specifying a concept, use ConceptSame to indicate that an - * expression must evaluate precisely to the type U. - */ template - concept ConceptSame = std::same_as; -# else - template - concept ConceptSame = std::is_same::value; -# endif + concept ConceptSame = stl::is_same_v; /** - * Equivalence mod std::remove_reference + * Equivalence mod stl::remove_reference */ template concept ConceptSameModRef = - ConceptSame, std::remove_reference_t>; + ConceptSame, stl::remove_reference_t>; /** * 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 - constexpr bool is_type_complete_v> = true; + constexpr bool is_type_complete_v> = true; } // namespace snmalloc #endif diff --git a/src/snmalloc/ds_core/helpers.h b/src/snmalloc/ds_core/helpers.h index 8b71569..0041857 100644 --- a/src/snmalloc/ds_core/helpers.h +++ b/src/snmalloc/ds_core/helpers.h @@ -2,10 +2,10 @@ #include "bits.h" #include "snmalloc/ds_core/defines.h" +#include "snmalloc/stl/type_traits.h" #include #include -#include namespace snmalloc { @@ -104,7 +104,7 @@ namespace snmalloc template< typename Fn, typename = - std::enable_if_t, function_ref>>> + stl::enable_if_t, function_ref>>> function_ref(Fn&& fn) { data_ = static_cast(&fn); @@ -123,7 +123,7 @@ namespace snmalloc template static R execute(void* p, Args... args) { - return (*static_cast>(p))(args...); + return (*static_cast>(p))(args...); }; }; diff --git a/src/snmalloc/ds_core/ptrwrap.h b/src/snmalloc/ds_core/ptrwrap.h index 01ad463..8681e3d 100644 --- a/src/snmalloc/ds_core/ptrwrap.h +++ b/src/snmalloc/ds_core/ptrwrap.h @@ -18,7 +18,7 @@ namespace snmalloc */ template SNMALLOC_FAST_PATH_INLINE uintptr_t - unsafe_to_uintptr(std::enable_if_t* p) + unsafe_to_uintptr(stl::enable_if_t* p) { return reinterpret_cast(p); } diff --git a/src/snmalloc/ds_core/redblacktree.h b/src/snmalloc/ds_core/redblacktree.h index 77ca6e5..377e896 100644 --- a/src/snmalloc/ds_core/redblacktree.h +++ b/src/snmalloc/ds_core/redblacktree.h @@ -60,7 +60,7 @@ namespace snmalloc } -> ConceptSameModRef; { typename Rep::Handle{const_cast< - std::remove_const_t>*>( + stl::remove_const_t>*>( &Rep::root)} } -> ConceptSame; }; @@ -70,7 +70,7 @@ namespace snmalloc RBRepTypes // && RBRepMethods // && - ConceptSame>; + ConceptSame>; #endif /** @@ -156,7 +156,7 @@ namespace snmalloc }; // Root field of the tree - typename std::remove_const_t> + typename stl::remove_const_t> root{Rep::root}; static ChildRef get_dir(bool direction, K k) diff --git a/src/snmalloc/ds_core/seqset.h b/src/snmalloc/ds_core/seqset.h index e493fbb..2816825 100644 --- a/src/snmalloc/ds_core/seqset.h +++ b/src/snmalloc/ds_core/seqset.h @@ -2,9 +2,9 @@ #include "../aal/aal.h" #include "../ds_core/ds_core.h" +#include "snmalloc/stl/type_traits.h" #include -#include namespace snmalloc { @@ -98,7 +98,7 @@ namespace snmalloc SNMALLOC_FAST_PATH bool is_empty() { static_assert( - std::is_same_v().node)>, + stl::is_same_v().node)>, "T->node must be Node for T"); head.invariant(); return head.next == &head; diff --git a/src/snmalloc/global/libc.h b/src/snmalloc/global/libc.h index 2a6db38..2ce178a 100644 --- a/src/snmalloc/global/libc.h +++ b/src/snmalloc/global/libc.h @@ -182,7 +182,7 @@ namespace snmalloc::libc return ThreadAlloc::get().get_client_meta_data(p); } - inline std::add_const_t + inline stl::add_const_t get_client_meta_data_const(void* p) { return ThreadAlloc::get().get_client_meta_data_const(p); diff --git a/src/snmalloc/global/memcpy.h b/src/snmalloc/global/memcpy.h index 51a8727..f52cea4 100644 --- a/src/snmalloc/global/memcpy.h +++ b/src/snmalloc/global/memcpy.h @@ -418,7 +418,7 @@ namespace snmalloc #elif defined(__powerpc64__) PPC64Arch #else - std::conditional_t< + stl::conditional_t< aal_supports, GenericStrictProvenance, GenericArch> diff --git a/src/snmalloc/mem/backend_concept.h b/src/snmalloc/mem/backend_concept.h index c7e76a1..ee288d3 100644 --- a/src/snmalloc/mem/backend_concept.h +++ b/src/snmalloc/mem/backend_concept.h @@ -148,7 +148,7 @@ namespace snmalloc * */ template - concept IsConfig = std::is_base_of::value && + concept IsConfig = stl::is_base_of_v && IsPAL && IsBackend - 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(), std::declval>())), diff --git a/src/snmalloc/mem/corealloc.h b/src/snmalloc/mem/corealloc.h index 5b03818..ec46acd 100644 --- a/src/snmalloc/mem/corealloc.h +++ b/src/snmalloc/mem/corealloc.h @@ -33,7 +33,7 @@ namespace snmalloc * `init_message_queue`. */ template - class CoreAllocator : public std::conditional_t< + class CoreAllocator : public stl::conditional_t< Config::Options.CoreAllocIsPoolAllocated, Pooled>, 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> + typename = stl::enable_if_t> CoreAllocator(Range& spare) { init(spare); @@ -676,7 +676,7 @@ namespace snmalloc */ template< typename Config_ = Config, - typename = std::enable_if_t> + typename = stl::enable_if_t> CoreAllocator( Range& spare, LocalCache* cache, @@ -691,7 +691,7 @@ namespace snmalloc * configure the message queue for use. */ template - std::enable_if_t init_message_queue(RemoteAllocator* q) + stl::enable_if_t init_message_queue(RemoteAllocator* q) { remote_alloc = q; init_message_queue(); diff --git a/src/snmalloc/mem/entropy.h b/src/snmalloc/mem/entropy.h index c6f2c85..3692907 100644 --- a/src/snmalloc/mem/entropy.h +++ b/src/snmalloc/mem/entropy.h @@ -2,9 +2,9 @@ #include "../ds/ds.h" #include "../pal/pal.h" +#include "snmalloc/stl/type_traits.h" #include -#include namespace snmalloc { diff --git a/src/snmalloc/mem/freelist.h b/src/snmalloc/mem/freelist.h index 37cdfa3..b184c8c 100644 --- a/src/snmalloc/mem/freelist.h +++ b/src/snmalloc/mem/freelist.h @@ -182,7 +182,7 @@ namespace snmalloc }; SNMALLOC_NO_UNIQUE_ADDRESS - std::conditional_t + stl::conditional_t 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; + stl::conditional_t; /** * 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 - std::enable_if_t add( + stl::enable_if_t add( Object::BHeadPtr n, const FreeListKey& key, address_t key_tweak) @@ -896,14 +896,14 @@ namespace snmalloc } template - std::enable_if_t extract_segment_length() + stl::enable_if_t extract_segment_length() { static_assert(RANDOM_ == RANDOM, "Don't set SFINAE parameter!"); return length[0]; } template - std::enable_if_t< + stl::enable_if_t< !RANDOM_, std::pair< Object::BHeadPtr, diff --git a/src/snmalloc/mem/localalloc.h b/src/snmalloc/mem/localalloc.h index abf4e2e..946d853 100644 --- a/src/snmalloc/mem/localalloc.h +++ b/src/snmalloc/mem/localalloc.h @@ -853,7 +853,7 @@ namespace snmalloc * @brief Get the client meta data for the snmalloc allocation covering this * pointer. */ - std::add_const_t + stl::add_const_t get_client_meta_data_const(void* p) { const PagemapEntry& entry = diff --git a/src/snmalloc/mem/metadata.h b/src/snmalloc/mem/metadata.h index 968902d..b363d6e 100644 --- a/src/snmalloc/mem/metadata.h +++ b/src/snmalloc/mem/metadata.h @@ -454,7 +454,7 @@ namespace snmalloc smallsizeclass_t sizeclass, address_t slab, const FreeListKey& key) { static_assert( - std::is_base_of::value, + stl::is_base_of_v, "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 tmp_fl; + stl::remove_reference_t 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, + stl::is_convertible_v, "The front end requires that the back end provides slab metadata that is " "compatible with the front-end's structure"); diff --git a/src/snmalloc/mem/remoteallocator.h b/src/snmalloc/mem/remoteallocator.h index a207d12..58c62e4 100644 --- a/src/snmalloc/mem/remoteallocator.h +++ b/src/snmalloc/mem/remoteallocator.h @@ -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>; diff --git a/src/snmalloc/mem/remotecache.h b/src/snmalloc/mem/remotecache.h index 2780da7..8a87ea1 100644 --- a/src/snmalloc/mem/remotecache.h +++ b/src/snmalloc/mem/remotecache.h @@ -180,7 +180,7 @@ namespace snmalloc }; template - using RemoteDeallocCacheBatchingImpl = std::conditional_t< + using RemoteDeallocCacheBatchingImpl = stl::conditional_t< (DEALLOC_BATCH_RINGS > 0), RemoteDeallocCacheBatching, RemoteDeallocCacheNoBatching>; diff --git a/src/snmalloc/pal/pal.h b/src/snmalloc/pal/pal.h index cc7ca1b..a8d45e2 100644 --- a/src/snmalloc/pal/pal.h +++ b/src/snmalloc/pal/pal.h @@ -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, CapPtr>> capptr_to_user_address_control(CapPtr 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, CapPtr>> capptr_to_user_address_control(CapPtr p) diff --git a/src/snmalloc/pal/pal_concept.h b/src/snmalloc/pal/pal_concept.h index 7efbd08..b7ae57a 100644 --- a/src/snmalloc/pal/pal_concept.h +++ b/src/snmalloc/pal/pal_concept.h @@ -21,7 +21,7 @@ namespace snmalloc template concept IsPAL_static_features = requires() { - typename std::integral_constant; + typename stl::integral_constant; }; /** @@ -30,8 +30,8 @@ namespace snmalloc template concept IsPAL_static_sizes = requires() { - typename std::integral_constant; - typename std::integral_constant; + typename stl::integral_constant; + typename stl::integral_constant; }; /** diff --git a/src/snmalloc/pal/pal_ds.h b/src/snmalloc/pal/pal_ds.h index f9f92de..ff17412 100644 --- a/src/snmalloc/pal/pal_ds.h +++ b/src/snmalloc/pal/pal_ds.h @@ -14,7 +14,7 @@ namespace snmalloc stl::Atomic elements{nullptr}; static_assert( - std::is_same>::value, + stl::is_same_v>, "Required pal_next type."); public: diff --git a/src/snmalloc/stl/cxx/type_traits.h b/src/snmalloc/stl/cxx/type_traits.h new file mode 100644 index 0000000..a6b2582 --- /dev/null +++ b/src/snmalloc/stl/cxx/type_traits.h @@ -0,0 +1,46 @@ +#pragma once + +#include + +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 diff --git a/src/snmalloc/stl/gnu/atomic.h b/src/snmalloc/stl/gnu/atomic.h index a8d9f42..28a2170 100644 --- a/src/snmalloc/stl/gnu/atomic.h +++ b/src/snmalloc/stl/gnu/atomic.h @@ -1,7 +1,8 @@ #pragma once +#include "snmalloc/stl/type_traits.h" + #include -#include // 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 && std::is_copy_constructible_v && - std::is_move_constructible_v && std::is_copy_assignable_v && - std::is_move_assignable_v, + stl::is_trivially_copyable_v && stl::is_copy_constructible_v && + stl::is_move_constructible_v && stl::is_copy_assignable_v && + stl::is_move_assignable_v, "Atomic requires T to be trivially copyable, copy " "constructible, move constructible, copy assignable, " "and move assignable."); static_assert( - std::has_unique_object_representations_v, + stl::has_unique_object_representations_v, "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 must be an integral type."); + static_assert(stl::is_integral_v, "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 must be an integral type."); + static_assert(stl::is_integral_v, "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 must be an integral type."); + static_assert(stl::is_integral_v, "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 must be an integral type."); + static_assert(stl::is_integral_v, "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 must be an integral type."); + static_assert(stl::is_integral_v, "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 must be an integral type."); + static_assert(stl::is_integral_v, "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 must be an integral type."); + static_assert(stl::is_integral_v, "T must be an integral type."); return __atomic_sub_fetch( addressof(val), decrement, order(MemoryOrder::SEQ_CST)); } diff --git a/src/snmalloc/stl/gnu/type_traits.h b/src/snmalloc/stl/gnu/type_traits.h new file mode 100644 index 0000000..7b2d769 --- /dev/null +++ b/src/snmalloc/stl/gnu/type_traits.h @@ -0,0 +1,394 @@ +#pragma once + +#include + +namespace snmalloc +{ + namespace stl + { + /** + * Type identity metafunction. + */ + template + struct type_identity + { + using type = T; + }; + + template + using type_identity_t = typename type_identity::type; + + /** + * Integral constant. + */ + template + struct integral_constant + { + using value_type = T; + static constexpr T value = v; + }; + + template + using bool_constant = integral_constant; + + using true_type = bool_constant; + using false_type = bool_constant; + + /** + * Remove CV qualifiers. + */ + template + struct remove_cv : type_identity + {}; + + template + struct remove_cv : type_identity + {}; + + template + struct remove_cv : type_identity + {}; + + template + struct remove_cv : type_identity + {}; + + template + using remove_cv_t = typename remove_cv::type; + + /** + * Type equality. + */ + template + struct is_same : false_type + {}; + + template + struct is_same : true_type + {}; + + template + inline constexpr bool is_same_v = is_same::value; + + /** + * Is integral type. + */ + template + struct is_integral + { + private: + template + static constexpr bool is_unqualified_any_of() + { + return (... || is_same_v, 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 + inline constexpr bool is_integral_v = is_integral::value; + + /** + * Remove all array extents. + */ +#if __has_builtin(__remove_all_extents) + template + using remove_all_extents_t = __remove_all_extents(T); +#else + template + struct remove_all_extents + { + using type = T; + }; + + template + struct remove_all_extents + { + using type = typename remove_all_extents::type; + }; + + template + struct remove_all_extents + { + using type = typename remove_all_extents::type; + }; + + template + using remove_all_extents_t = typename remove_all_extents::type; +#endif + + /** + * void_t + */ + template + using void_t = typename type_identity::type; + + /** + * Has unique object representations. + */ + /* remove_all_extents_t is needed due to clang's behavior */ + template + inline constexpr bool has_unique_object_representations_v = + __has_unique_object_representations(remove_all_extents_t); + + /** + * enable_if + */ + template + struct enable_if; + + template + struct enable_if : type_identity + {}; + + template + using enable_if_t = typename enable_if::type; + + /** + * conditional + */ + + template + struct conditional : type_identity + {}; + + template + struct conditional : type_identity + {}; + + template + using conditional_t = typename conditional::type; + + /** + * add_lvalue_reference/add_rvalue_reference + */ +#if __has_builtin(__add_lvalue_reference) + template + using add_lvalue_reference_t = __add_lvalue_reference(T); +#else + template // Note that `cv void&` is a substitution failure + auto __add_lvalue_reference_impl(int) -> type_identity; + template // Handle T = cv void case + auto __add_lvalue_reference_impl(...) -> type_identity; + + template + struct add_lvalue_reference : decltype(__add_lvalue_reference_impl(0)) + {}; + template + using add_lvalue_reference_t = typename add_lvalue_reference::type; +#endif + +#if __has_builtin(__add_rvalue_reference) + template + using add_rvalue_reference_t = __add_rvalue_reference(T); +#else + template + auto __add_rvalue_reference_impl(int) -> type_identity; + template + auto __add_rvalue_referenc_impl(...) -> type_identity; + + template + struct add_rvalue_reference : decltype(__add_rvalue_reference_impl(0)) + {}; + + template + using add_rvalue_reference_t = typename add_rvalue_reference::type; +#endif + + /** + * remove_reference + */ + template + struct remove_reference : type_identity + {}; + + template + struct remove_reference : type_identity + {}; + + template + struct remove_reference : type_identity + {}; + template + using remove_reference_t = typename remove_reference::type; + + /** + * add_pointer + */ +#if __has_builtin(__add_pointer) + template + using add_pointer_t = __add_pointer(T); +#else + template + auto __add_pointer_impl(int) -> type_identity*>; + template + auto __add_pointer_impl(...) -> type_identity; + + template + struct add_pointer : decltype(__add_pointer_impl(0)) + {}; + + template + using add_pointer_t = typename add_pointer::type; +#endif + /** + * is_array + */ + template + inline constexpr bool is_array_v = __is_array(T); + + /** + * is_function + */ + template + inline constexpr bool is_function_v = __is_function(T); + + /** + * remove_extent + */ + +#if __has_builtin(__remove_extent) + template + using remove_extent_t = __remove_extent(T); +#else + template + struct remove_extent + { + using type = T; + }; + + template + struct remove_extent + { + using type = T; + }; + + template + struct remove_extent + { + using type = T; + }; + + template + using remove_extent_t = typename remove_extent::type; +#endif + + /** + * decay + */ +#if __has_builtin(__decay) + template + using decay_t = __decay(T); +#else + template + class decay + { + using U = remove_reference_t; + + public: + using type = conditional_t< + is_array_v, + add_pointer_t>, + conditional_t, add_pointer_t, remove_cv_t>>; + }; + + template + using decay_t = typename decay::type; +#endif + + /** + * is_copy_assignable + */ + template + constexpr bool is_copy_assignable_v = __is_assignable( + add_lvalue_reference_t, add_lvalue_reference_t); + + /** + * is_copy_constructible + */ + template + inline constexpr bool is_copy_constructible_v = + __is_constructible(T, add_lvalue_reference_t); + + /** + * is_move_assignable + */ + template + constexpr bool is_move_assignable_v = + __is_assignable(add_lvalue_reference_t, add_lvalue_reference_t); + + /** + * is_move_constructible + */ + template + inline constexpr bool is_move_constructible_v = + __is_constructible(T, add_rvalue_reference_t); + + /** + * is_convertible + */ + template + inline constexpr bool is_convertible_v = __is_convertible(From, To); + + /** + * is_base_of + */ + template + inline constexpr bool is_base_of_v = __is_base_of(Base, Derived); + + /** + * is_trivially_copyable + */ + template + inline constexpr bool is_trivially_copyable_v = __is_trivially_copyable(T); + + /** + * remove_const + */ +#if __has_builtin(__remove_const) + template + using remove_const_t = __remove_const(T); +#else + template + struct remove_const + { + using type = T; + }; + + template + struct remove_const + { + using type = T; + }; + + template + using remove_const_t = typename remove_const::type; +#endif + + /** + * add_const + */ + template + using add_const_t = const T; + + } // namespace stl +} // namespace snmalloc diff --git a/src/snmalloc/stl/type_traits.h b/src/snmalloc/stl/type_traits.h new file mode 100644 index 0000000..7171221 --- /dev/null +++ b/src/snmalloc/stl/type_traits.h @@ -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