aboutsummaryrefslogtreecommitdiff
path: root/libsupport
diff options
context:
space:
mode:
authorRichard Qin <richard.qin.x@gmail.com>2026-11-02 02:07:38 +0800
committerRichard Qin <richard.qin.x@gmail.com>2026-11-02 02:07:38 +0800
commite3c4c7709f65404bcf8ce195a518e7d445e768d2 (patch)
tree48ac475db03a63827f8910acce982fead7612d26 /libsupport
parent02b615c8704aeda9a94cf5457c9c78de847c911a (diff)
downloadrcc-project-e3c4c7709f65404bcf8ce195a518e7d445e768d2.tar.gz
rcc-project-e3c4c7709f65404bcf8ce195a518e7d445e768d2.tar.xz
Restructure libbase and RCCCore build
Diffstat (limited to 'libsupport')
-rw-r--r--libsupport/CMakeLists.txt15
-rw-r--r--libsupport/include/CoreLib/ADT/STLFunctionalExtras.h112
-rw-r--r--libsupport/include/CoreLib/ADT/SmallVector.h1926
-rw-r--r--libsupport/include/CoreLib/Compiler/Compiler.h853
-rw-r--r--libsupport/include/CoreLib/Error/ErrorHandling.h217
-rw-r--r--libsupport/include/CoreLib/Error/ErrorOr.h378
-rw-r--r--libsupport/include/CoreLib/Math/MathExtras.h1050
-rw-r--r--libsupport/include/CoreLib/Memory/MemAlloc.h124
-rw-r--r--libsupport/include/CoreLib/System/Errno.h64
-rw-r--r--libsupport/src/corelib/math/MathExtras.cc97
-rw-r--r--libsupport/src/corelib/memory/MemAlloc.cpp63
-rw-r--r--libsupport/src/corelib/system/Errno.cc79
12 files changed, 0 insertions, 4978 deletions
diff --git a/libsupport/CMakeLists.txt b/libsupport/CMakeLists.txt
deleted file mode 100644
index 0784f3b..0000000
--- a/libsupport/CMakeLists.txt
+++ /dev/null
@@ -1,15 +0,0 @@
-# SPDX-License-Identifier: GPL-3.0-or-later
-
-add_rcc_library(RCCSupport
- STATIC
- src/corelib/math/MathExtras.cc
- src/corelib/memory/MemAlloc.cpp
- src/corelib/system/Errno.cc
-)
-
-target_include_directories(RCCSupport
- PUBLIC
- "$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>"
- "$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>")
-
-install(DIRECTORY include/CoreLib DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}")
diff --git a/libsupport/include/CoreLib/ADT/STLFunctionalExtras.h b/libsupport/include/CoreLib/ADT/STLFunctionalExtras.h
deleted file mode 100644
index 993acc0..0000000
--- a/libsupport/include/CoreLib/ADT/STLFunctionalExtras.h
+++ /dev/null
@@ -1,112 +0,0 @@
-/*
- R *CC-Project
-
- Copyright (C) 2026 Richard Qin
-
- This file is part of RCC-Project.
-
- RCC-Project is free software; you can redistribute it and/or modify it under
- the terms of the GNU General Public License as published by the Free
- Software Foundation; either version 3 of the License, or (at your option) any
- later version.
-
- RCC-Project is distributed in the hope that it will be useful, but WITHOUT ANY
- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
- A PARTICULAR PURPOSE. See the GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License along with
- RCC-Project; see the file COPYING. If not see
- <http://www.gnu.org/licenses/>.
- */
-
-//===- llvm/ADT/STLFunctionalExtras.h - Extras for <functional> -*- C++ -*-===//
-//
-// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
-// See https://llvm.org/LICENSE.txt for license information.
-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-//
-//===----------------------------------------------------------------------===//
-//
-// This file contains some extension to <functional>.
-//
-// No library is required when using these functions.
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef RCC_ADT_STLFUNCTIONALEXTRAS_H
-#define RCC_ADT_STLFUNCTIONALEXTRAS_H
-
-#include "CoreLib/Compiler/Compiler.h"
-
-#include <cstddef
-#include <cstdint>
-#include <type_traits>
-#include <utility>
-
-namespace rcc
-{
-
-//===----------------------------------------------------------------------===//
-// Extra additions to <functional>
-//===----------------------------------------------------------------------===//
-
-/// An efficient, type-erasing, non-owning reference to a callable. This is
-/// intended for use as the type of a function parameter that is not used
-/// after the function in question returns.
-///
-/// This class does not own the callable, so it is not in general safe to store
-/// a function_ref.
-template <typename Fn> class function_ref;
-
-template <typename Ret, typename... Params>
-class RCC_GSL_POINTER function_ref<Ret (Params...)>
-{
- Ret (*callback) (intptr_t callable, Params... params) = nullptr;
- intptr_t callable = 0;
-
- template <typename Callable>
- static Ret
- callback_fn (intptr_t callable, Params... params)
- {
- return (*reinterpret_cast<Callable *> (callable)) (
- std::forward<Params> (params)...);
- }
-
-public:
- function_ref () = default;
- function_ref (std::nullptr_t)
- {
- }
-
- template <typename Callable>
- function_ref (
- Callable &&callable RCC_LIFETIME_BOUND,
- // This is not the copy-constructor.
- std::enable_if_t<!std::is_same<std::remove_cvref_t<Callable>,
- function_ref>::value> * = nullptr,
- // Functor must be callable and return a suitable type.
- std::enable_if_t<std::is_void<Ret>::value ||
- std::is_convertible<decltype (std::declval<Callable> () (
- std::declval<Params> ()...)),
- Ret>::value> * = nullptr)
- : callback (callback_fn<std::remove_reference_t<Callable>>),
- callable (reinterpret_cast<intptr_t> (&callable))
- {
- }
-
- Ret
- operator() (Params... params) const
- {
- return callback (callable, std::forward<Params> (params)...);
- }
-
- explicit
- operator bool () const
- {
- return callback;
- }
-};
-
-} // end namespace rcc
-
-#endif // RCC_ADT_STLFUNCTIONALEXTRAS_H
diff --git a/libsupport/include/CoreLib/ADT/SmallVector.h b/libsupport/include/CoreLib/ADT/SmallVector.h
deleted file mode 100644
index 8b9826a..0000000
--- a/libsupport/include/CoreLib/ADT/SmallVector.h
+++ /dev/null
@@ -1,1926 +0,0 @@
-/*
- R *CC-Project
-
- Copyright (C) 2026 Richard Qin
-
- This file is part of RCC-Project.
-
- RCC-Project is free software; you can redistribute it and/or modify it under
- the terms of the GNU General Public License as published by the Free
- Software Foundation; either version 3 of the License, or (at your option) any
- later version.
-
- RCC-Project is distributed in the hope that it will be useful, but WITHOUT ANY
- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
- PARTICULAR PURPOSE. See the GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License along with
- RCC-Project; see the file COPYING. If not see
- <http://www.gnu.org/licenses/>.
- */
-
-//===- rcc/ADT/SmallVector.h - 'Normally small' vectors --------*- C++ -*-===//
-//
-// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
-// See https://llvm.org/LICENSE.txt for license information.
-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-//
-//===----------------------------------------------------------------------===//
-///
-/// \file
-/// This file defines the SmallVector class.
-///
-//===----------------------------------------------------------------------===//
-
-#ifndef RCC_ADT_SMALLVECTOR_H
-#define RCC_ADT_SMALLVECTOR_H
-
-#include "CoreLib/Compiler/Compiler.h"
-#include <algorithm>
-#include <cassert>
-#include <cstddef>
-#include <cstdint>
-#include <cstdlib>
-#include <cstring>
-#include <functional>
-#include <initializer_list>
-#include <iterator>
-#include <limits>
-#include <memory>
-#include <new>
-#include <ranges>
-#include <type_traits>
-#include <utility>
-
-namespace rcc
-{
-
-template <typename T> class ArrayRef;
-
-template <typename IteratorT> class iterator_range;
-
-template <class Iterator, class Tag>
-using HasIteratorTag = std::is_convertible<
- typename std::iterator_traits<Iterator>::iterator_category, Tag>;
-
-template <class Iterator>
-using EnableIfConvertibleToInputIterator =
- std::enable_if_t<HasIteratorTag<Iterator, std::input_iterator_tag>::value>;
-
-/// This is all the stuff common to all SmallVectors.
-///
-/// The template parameter specifies the type which should be used to hold the
-/// Size and Capacity of the SmallVector, so it can be adjusted.
-/// Using 32 bit size is desirable to shrink the size of the SmallVector.
-/// Using 64 bit size is desirable for cases like SmallVector<char>, where a
-/// 32 bit size would limit the vector to ~4GB. SmallVectors are used for
-/// buffering bitcode output - which can exceed 4GB.
-template <class Size_T> class SmallVectorBase
-{
-protected:
- void *BeginX;
- Size_T Size = 0, Capacity;
-
- /// The maximum value of the Size_T used.
- static constexpr size_t
- SizeTypeMax ()
- {
- return std::numeric_limits<Size_T>::max ();
- }
-
- SmallVectorBase () = delete;
- SmallVectorBase (void *FirstEl, size_t TotalCapacity)
- : BeginX (FirstEl), Capacity (static_cast<Size_T> (TotalCapacity))
- {
- }
-
- /// This is a helper for \a grow() that's out of line to reduce code
- /// duplication. This function will report a fatal error if it can't grow at
- /// least to \p MinSize.
- RCC_ABI void *
- mallocForGrow (void *FirstEl, size_t MinSize, size_t TSize,
- size_t &NewCapacity);
-
- /// This is an implementation of the grow() method which only works
- /// on POD-like data types and is out of line to reduce code duplication.
- /// This function will report a fatal error if it cannot increase capacity.
- RCC_ABI void
- grow_pod (void *FirstEl, size_t MinSize, size_t TSize);
-
-public:
- size_t
- size () const
- {
- return Size;
- }
- size_t
- capacity () const
- {
- return Capacity;
- }
-
- [[nodiscard]] bool
- empty () const
- {
- return !Size;
- }
-
-protected:
- /// Set the array size to \p N, which the current array must have enough
- /// capacity for.
- ///
- /// This does not construct or destroy any elements in the vector.
- void
- set_size (size_t N)
- {
- assert (N <= capacity ()); // implies no overflow in assignment
- Size = static_cast<Size_T> (N);
- }
-
- /// Set the array data pointer to \p Begin and capacity to \p N.
- ///
- /// This does not construct or destroy any elements in the vector.
- // This does not clean up any existing allocation.
- void
- set_allocation_range (void *Begin, size_t N)
- {
- assert (N <= SizeTypeMax ());
- BeginX = Begin;
- Capacity = static_cast<Size_T> (N);
- }
-};
-
-template <class T>
-using SmallVectorSizeType =
- std::conditional_t<sizeof (T) < 4 && sizeof (void *) >= 8, uint64_t,
- uint32_t>;
-
-/// Figure out the offset of the first element.
-template <class T, typename = void> struct SmallVectorAlignmentAndSize
-{
- alignas (SmallVectorBase<SmallVectorSizeType<T>>) char Base[sizeof (
- SmallVectorBase<SmallVectorSizeType<T>>)];
- alignas (T) char FirstEl[sizeof (T)];
-};
-
-/// This is the part of SmallVectorTemplateBase which does not depend on whether
-/// the type T is a POD. The extra dummy template argument is used by ArrayRef
-/// to avoid unnecessarily requiring T to be complete.
-template <typename T, typename = void>
-class SmallVectorTemplateCommon : public SmallVectorBase<SmallVectorSizeType<T>>
-{
- using Base = SmallVectorBase<SmallVectorSizeType<T>>;
-
-protected:
- /// Find the address of the first element. For this pointer math to be valid
- /// with small-size of 0 for T with lots of alignment, it's important that
- /// SmallVectorStorage is properly-aligned even for small-size of 0.
- void *
- getFirstEl () const
- {
- return const_cast<void *> (reinterpret_cast<const void *> (
- reinterpret_cast<const char *> (this) +
- offsetof (SmallVectorAlignmentAndSize<T>, FirstEl)));
- }
- // Space after 'FirstEl' is clobbered, do not add any instance vars after it.
-
- SmallVectorTemplateCommon (size_t SizeArg) : Base (getFirstEl (), SizeArg)
- {
- }
-
- void
- grow_pod (size_t MinSize, size_t TSize)
- {
- Base::grow_pod (getFirstEl (), MinSize, TSize);
- }
-
- /// Return true if this is a smallvector which has not had dynamic
- /// memory allocated for it.
- bool
- isSmall () const
- {
- return this->BeginX == getFirstEl ();
- }
-
- /// Put this vector in a state of being small.
- void
- resetToSmall ()
- {
- this->BeginX = getFirstEl ();
- // The inline capacity is unknown here. SmallVector restores it when moving
- // from the same concrete type; moves through SmallVectorImpl leave it at 0.
- this->Size = this->Capacity = 0;
- }
-
- /// Return true if V is an internal reference to the given range.
- bool
- isReferenceToRange (const void *V, const void *First, const void *Last) const
- {
- // Use std::less to avoid UB.
- std::less<> LessThan;
- return !LessThan (V, First) && LessThan (V, Last);
- }
-
- /// Return true if V is an internal reference to this vector.
- bool
- isReferenceToStorage (const void *V) const
- {
- return isReferenceToRange (V, this->begin (), this->end ());
- }
-
- /// Return true if First and Last form a valid (possibly empty) range in this
- /// vector's storage.
- bool
- isRangeInStorage (const void *First, const void *Last) const
- {
- // Use std::less to avoid UB.
- std::less<> LessThan;
- return !LessThan (First, this->begin ()) && !LessThan (Last, First) &&
- !LessThan (this->end (), Last);
- }
-
- /// Return true unless Elt will be invalidated by resizing the vector to
- /// NewSize.
- bool
- isSafeToReferenceAfterResize (const void *Elt, size_t NewSize)
- {
- // Past the end.
- if (RCC_LIKELY (!isReferenceToStorage (Elt)))
- {
- return true;
- }
-
- // Return false if Elt will be destroyed by shrinking.
- if (NewSize <= this->size ())
- {
- return Elt < this->begin () + NewSize;
- }
-
- // Return false if we need to grow.
- return NewSize <= this->capacity ();
- }
-
- /// Check whether Elt will be invalidated by resizing the vector to NewSize.
- void
- assertSafeToReferenceAfterResize (const void *Elt, size_t NewSize)
- {
- assert (isSafeToReferenceAfterResize (Elt, NewSize) &&
- "Attempting to reference an element of the vector in an operation "
- "that invalidates it");
- }
-
- /// Check whether Elt will be invalidated by increasing the size of the
- /// vector by N.
- void
- assertSafeToAdd (const void *Elt, size_t N = 1)
- {
- this->assertSafeToReferenceAfterResize (Elt, this->size () + N);
- }
-
- /// Check whether any part of the range will be invalidated by clearing.
- template <class ItTy>
- void
- assertSafeToReferenceAfterClear (ItTy From, ItTy To)
- {
- if constexpr (std::is_pointer_v<ItTy> &&
- std::is_same_v<
- std::remove_const_t<std::remove_pointer_t<ItTy>>,
- std::remove_const_t<T>>)
- {
- if (From == To)
- {
- return;
- }
- this->assertSafeToReferenceAfterResize (From, 0);
- this->assertSafeToReferenceAfterResize (To - 1, 0);
- }
- (void)From;
- (void)To;
- }
-
- /// Check whether any part of the range will be invalidated by growing.
- template <class ItTy>
- void
- assertSafeToAddRange (ItTy From, ItTy To)
- {
- if constexpr (std::is_pointer_v<ItTy> &&
- std::is_same_v<std::remove_cv_t<std::remove_pointer_t<ItTy>>,
- T>)
- {
- if (From == To)
- {
- return;
- }
- this->assertSafeToAdd (From, To - From);
- this->assertSafeToAdd (To - 1, To - From);
- }
- (void)From;
- (void)To;
- }
-
- /// Reserve enough space to add one element, and return the updated element
- /// pointer in case it was a reference to the storage.
- template <class U>
- static const T *
- reserveForParamAndGetAddressImpl (U *This, const T &Elt, size_t N)
- {
- size_t NewSize = This->size () + N;
- if (RCC_LIKELY (NewSize <= This->capacity ()))
- {
- return &Elt;
- }
-
- bool ReferencesStorage = false;
- int64_t Index = -1;
- if (!U::TakesParamByValue)
- {
- if (RCC_UNLIKELY (This->isReferenceToStorage (&Elt)))
- {
- ReferencesStorage = true;
- Index = &Elt - This->begin ();
- }
- }
- This->grow (NewSize);
- return ReferencesStorage ? This->begin () + Index : &Elt;
- }
-
-public:
- using size_type = size_t;
- using difference_type = ptrdiff_t;
- using value_type = T;
- using iterator = T *;
- using const_iterator = const T *;
-
- using const_reverse_iterator = std::reverse_iterator<const_iterator>;
- using reverse_iterator = std::reverse_iterator<iterator>;
-
- using reference = T &;
- using const_reference = const T &;
- using pointer = T *;
- using const_pointer = const T *;
-
- using Base::capacity;
- using Base::empty;
- using Base::size;
-
- // forward iterator creation methods.
- iterator
- begin ()
- {
- return (iterator)this->BeginX;
- }
- const_iterator
- begin () const
- {
- return (const_iterator)this->BeginX;
- }
- iterator
- end ()
- {
- return begin () + size ();
- }
- const_iterator
- end () const
- {
- return begin () + size ();
- }
-
- // reverse iterator creation methods.
- reverse_iterator
- rbegin ()
- {
- return reverse_iterator (end ());
- }
- const_reverse_iterator
- rbegin () const
- {
- return const_reverse_iterator (end ());
- }
- reverse_iterator
- rend ()
- {
- return reverse_iterator (begin ());
- }
- const_reverse_iterator
- rend () const
- {
- return const_reverse_iterator (begin ());
- }
-
- size_type
- size_in_bytes () const
- {
- return size () * sizeof (T);
- }
- size_type
- max_size () const
- {
- return std::min (this->SizeTypeMax (), size_type (-1) / sizeof (T));
- }
-
- size_t
- capacity_in_bytes () const
- {
- return capacity () * sizeof (T);
- }
-
- /// Return a pointer to the vector's buffer, even if empty().
- pointer
- data ()
- {
- return pointer (begin ());
- }
- /// Return a pointer to the vector's buffer, even if empty().
- const_pointer
- data () const
- {
- return const_pointer (begin ());
- }
-
- reference
- operator[] (size_type idx)
- {
- assert (idx < size ());
- return begin ()[idx];
- }
- const_reference
- operator[] (size_type idx) const
- {
- assert (idx < size ());
- return begin ()[idx];
- }
-
- reference
- front ()
- {
- assert (!empty ());
- return begin ()[0];
- }
- const_reference
- front () const
- {
- assert (!empty ());
- return begin ()[0];
- }
-
- reference
- back ()
- {
- assert (!empty ());
- return end ()[-1];
- }
- const_reference
- back () const
- {
- assert (!empty ());
- return end ()[-1];
- }
-};
-
-/// SmallVectorTemplateBase<TriviallyCopyable = false> - This is where we put
-/// method implementations that are designed to work with non-trivial T's.
-///
-/// We approximate is_trivially_copyable with trivial move/copy construction and
-/// trivial destruction. While the standard doesn't specify that you're allowed
-/// copy these types with memcpy, there is no way for the type to observe this.
-/// This catches the important case of std::pair<POD, POD>, which is not
-/// trivially assignable.
-template <typename T, bool = (std::is_trivially_copy_constructible<T>::value) &&
- (std::is_trivially_move_constructible<T>::value) &&
- std::is_trivially_destructible<T>::value>
-class SmallVectorTemplateBase : public SmallVectorTemplateCommon<T>
-{
- friend class SmallVectorTemplateCommon<T>;
-
-protected:
- static constexpr bool TakesParamByValue = false;
- using ValueParamT = const T &;
-
- SmallVectorTemplateBase (size_t SizeArg)
- : SmallVectorTemplateCommon<T> (SizeArg)
- {
- }
-
- static void
- destroy_range (T *S, T *E)
- {
- while (S != E)
- {
- --E;
- E->~T ();
- }
- }
-
- /// Move the range [I, E) into the uninitialized memory starting with "Dest",
- /// constructing elements as needed.
- template <typename It1, typename It2>
- static void
- uninitialized_move (It1 I, It1 E, It2 Dest)
- {
- std::uninitialized_move (I, E, Dest);
- }
-
- /// Copy the range [I, E) onto the uninitialized memory starting with "Dest",
- /// constructing elements as needed.
- template <typename It1, typename It2>
- static void
- uninitialized_copy (It1 I, It1 E, It2 Dest)
- {
- std::uninitialized_copy (I, E, Dest);
- }
-
- /// Grow the allocated memory (without initializing new elements), doubling
- /// the size of the allocated memory. Guarantees space for at least one more
- /// element, or MinSize more elements if specified.
- void
- grow (size_t MinSize = 0);
-
- /// Create a new allocation big enough for \p MinSize and pass back its size
- /// in \p NewCapacity. This is the first section of \a grow().
- T *
- mallocForGrow (size_t MinSize, size_t &NewCapacity);
-
- /// Move existing elements over to the new allocation \p NewElts, the middle
- /// section of \a grow().
- void
- moveElementsForGrow (T *NewElts);
-
- /// Transfer ownership of the allocation, finishing up \a grow().
- void
- takeAllocationForGrow (T *NewElts, size_t NewCapacity);
-
- /// Reserve enough space to add one element, and return the updated element
- /// pointer in case it was a reference to the storage.
- const T *
- reserveForParamAndGetAddress (const T &Elt, size_t N = 1)
- {
- return this->reserveForParamAndGetAddressImpl (this, Elt, N);
- }
-
- /// Reserve enough space to add one element, and return the updated element
- /// pointer in case it was a reference to the storage.
- T *
- reserveForParamAndGetAddress (T &Elt, size_t N = 1)
- {
- return const_cast<T *> (
- this->reserveForParamAndGetAddressImpl (this, Elt, N));
- }
-
- static T &&
- forward_value_param (T &&V)
- {
- return std::move (V);
- }
- static const T &
- forward_value_param (const T &V)
- {
- return V;
- }
-
- void
- growAndAssign (size_t NumElts, const T &Elt)
- {
- // Grow manually in case Elt is an internal reference.
- size_t NewCapacity;
- T *NewElts = mallocForGrow (NumElts, NewCapacity);
- std::uninitialized_fill_n (NewElts, NumElts, Elt);
- this->destroy_range (this->begin (), this->end ());
- takeAllocationForGrow (NewElts, NewCapacity);
- this->set_size (NumElts);
- }
-
- template <typename... ArgTypes>
- T &
- growAndEmplaceBack (ArgTypes &&...Args)
- {
- // Grow manually in case one of Args is an internal reference.
- size_t NewCapacity;
- T *NewElts = mallocForGrow (0, NewCapacity);
- ::new ((void *)(NewElts + this->size ()))
- T (std::forward<ArgTypes> (Args)...);
- moveElementsForGrow (NewElts);
- takeAllocationForGrow (NewElts, NewCapacity);
- this->set_size (this->size () + 1);
- return this->back ();
- }
-
-public:
- void
- push_back (const T &Elt)
- {
- const T *EltPtr = reserveForParamAndGetAddress (Elt);
- ::new ((void *)this->end ()) T (*EltPtr);
- this->set_size (this->size () + 1);
- }
-
- void
- push_back (T &&Elt)
- {
- T *EltPtr = reserveForParamAndGetAddress (Elt);
- ::new ((void *)this->end ()) T (::std::move (*EltPtr));
- this->set_size (this->size () + 1);
- }
-
- void
- pop_back ()
- {
- this->set_size (this->size () - 1);
- this->end ()->~T ();
- }
-};
-
-// Define this out-of-line to dissuade the C++ compiler from inlining it.
-template <typename T, bool TriviallyCopyable>
-void
-SmallVectorTemplateBase<T, TriviallyCopyable>::grow (size_t MinSize)
-{
- size_t NewCapacity;
- T *NewElts = mallocForGrow (MinSize, NewCapacity);
- moveElementsForGrow (NewElts);
- takeAllocationForGrow (NewElts, NewCapacity);
-}
-
-template <typename T, bool TriviallyCopyable>
-T *
-SmallVectorTemplateBase<T, TriviallyCopyable>::mallocForGrow (
- size_t MinSize, size_t &NewCapacity)
-{
- return static_cast<T *> (
- SmallVectorBase<SmallVectorSizeType<T>>::mallocForGrow (
- this->getFirstEl (), MinSize, sizeof (T), NewCapacity));
-}
-
-// Define this out-of-line to dissuade the C++ compiler from inlining it.
-template <typename T, bool TriviallyCopyable>
-void
-SmallVectorTemplateBase<T, TriviallyCopyable>::moveElementsForGrow (T *NewElts)
-{
- // Move the elements over.
- this->uninitialized_move (this->begin (), this->end (), NewElts);
-
- // Destroy the original elements.
- destroy_range (this->begin (), this->end ());
-}
-
-// Define this out-of-line to dissuade the C++ compiler from inlining it.
-template <typename T, bool TriviallyCopyable>
-void
-SmallVectorTemplateBase<T, TriviallyCopyable>::takeAllocationForGrow (
- T *NewElts, size_t NewCapacity)
-{
- // If this wasn't grown from the inline copy, deallocate the old space.
- if (!this->isSmall ())
- {
- free (this->begin ());
- }
-
- this->set_allocation_range (NewElts, NewCapacity);
-}
-
-/// SmallVectorTemplateBase<TriviallyCopyable = true> - This is where we put
-/// method implementations that are designed to work with trivially copyable
-/// T's. This allows using memcpy in place of copy/move construction and
-/// skipping destruction.
-template <typename T>
-class SmallVectorTemplateBase<T, true> : public SmallVectorTemplateCommon<T>
-{
- friend class SmallVectorTemplateCommon<T>;
-
-protected:
- /// True if it's cheap enough to take parameters by value. Doing so avoids
- /// overhead related to mitigations for reference invalidation.
- static constexpr bool TakesParamByValue = sizeof (T) <= 2 * sizeof (void *);
-
- /// Either const T& or T, depending on whether it's cheap enough to take
- /// parameters by value.
- using ValueParamT = std::conditional_t<TakesParamByValue, T, const T &>;
-
- SmallVectorTemplateBase (size_t SizeArg)
- : SmallVectorTemplateCommon<T> (SizeArg)
- {
- }
-
- // No need to do a destroy loop for POD's.
- static void
- destroy_range (T *, T *)
- {
- }
-
- /// Move the range [I, E) onto the uninitialized memory
- /// starting with "Dest", constructing elements into it as needed.
- template <typename It1, typename It2>
- static void
- uninitialized_move (It1 I, It1 E, It2 Dest)
- {
- // Just do a copy.
- uninitialized_copy (I, E, Dest);
- }
-
- /// Copy the range [I, E) onto the uninitialized memory
- /// starting with "Dest", constructing elements into it as needed.
- template <typename It1, typename It2>
- static void
- uninitialized_copy (It1 I, It1 E, It2 Dest)
- {
- if constexpr (std::is_pointer_v<It1> && std::is_pointer_v<It2> &&
- std::is_same_v<
- std::remove_const_t<std::remove_pointer_t<It1>>,
- std::remove_pointer_t<It2>>)
- {
- // Use memcpy for PODs iterated by pointers (which includes SmallVector
- // iterators): std::uninitialized_copy optimizes to memmove, but we can
- // use memcpy here. Note that I and E are iterators and thus might be
- // invalid for memcpy if they are equal.
- if (I != E)
- {
- std::memcpy (reinterpret_cast<void *> (Dest), I, (E - I) * sizeof (T));
- }
- }
- else
- {
- // Arbitrary iterator types; just use the basic implementation.
- std::uninitialized_copy (I, E, Dest);
- }
- }
-
- /// Double the size of the allocated memory, guaranteeing space for at
- /// least one more element or MinSize if specified.
- void
- grow (size_t MinSize = 0)
- {
- this->grow_pod (MinSize, sizeof (T));
- }
-
- /// Reserve enough space to add one element, and return the updated element
- /// pointer in case it was a reference to the storage.
- const T *
- reserveForParamAndGetAddress (const T &Elt, size_t N = 1)
- {
- return this->reserveForParamAndGetAddressImpl (this, Elt, N);
- }
-
- /// Reserve enough space to add one element, and return the updated element
- /// pointer in case it was a reference to the storage.
- T *
- reserveForParamAndGetAddress (T &Elt, size_t N = 1)
- {
- return const_cast<T *> (
- this->reserveForParamAndGetAddressImpl (this, Elt, N));
- }
-
- /// Copy \p V or return a reference, depending on \a ValueParamT.
- static ValueParamT
- forward_value_param (ValueParamT V)
- {
- return V;
- }
-
- void
- growAndAssign (size_t NumElts, T Elt)
- {
- // Elt has been copied in case it's an internal reference, side-stepping
- // reference invalidation problems without losing the realloc optimization.
- this->set_size (0);
- this->grow (NumElts);
- std::uninitialized_fill_n (this->begin (), NumElts, Elt);
- this->set_size (NumElts);
- }
-
- template <typename... ArgTypes>
- T &
- growAndEmplaceBack (ArgTypes &&...Args)
- {
- // Use push_back with a copy in case Args has an internal reference,
- // side-stepping reference invalidation problems without losing the realloc
- // optimization.
- push_back (T (std::forward<ArgTypes> (Args)...));
- return this->back ();
- }
-
- // Out-of-line slow path so the inline push_back needs no callee-saved
- // registers or stack frame on its hot path.
- RCC_ATTRIBUTE_NOINLINE void
- growAndPushBack (ValueParamT Elt)
- {
- // Copy in case Elt is an internal reference invalidated by grow.
- T Tmp = Elt;
- this->grow (this->size () + 1);
- std::memcpy (reinterpret_cast<void *> (this->end ()), &Tmp, sizeof (T));
- this->set_size (this->size () + 1);
- }
-
-public:
- void
- push_back (ValueParamT Elt)
- {
- if (RCC_UNLIKELY (this->size () >= this->capacity ()))
- {
- return growAndPushBack (Elt);
- }
- std::memcpy (reinterpret_cast<void *> (this->end ()), &Elt, sizeof (T));
- this->set_size (this->size () + 1);
- }
-
- void
- pop_back ()
- {
- this->set_size (this->size () - 1);
- }
-};
-
-/// This class consists of common code factored out of the SmallVector class to
-/// reduce code duplication based on the SmallVector 'N' template parameter.
-template <typename T> class SmallVectorImpl : public SmallVectorTemplateBase<T>
-{
- using SuperClass = SmallVectorTemplateBase<T>;
-
-public:
- using iterator = typename SuperClass::iterator;
- using const_iterator = typename SuperClass::const_iterator;
- using reference = typename SuperClass::reference;
- using size_type = typename SuperClass::size_type;
-
-protected:
- using SmallVectorTemplateBase<T>::TakesParamByValue;
- using ValueParamT = typename SuperClass::ValueParamT;
-
- // Default ctor - Initialize to empty.
- explicit SmallVectorImpl (unsigned N) : SmallVectorTemplateBase<T> (N)
- {
- }
-
- void
- assignRemote (SmallVectorImpl &&RHS)
- {
- this->destroy_range (this->begin (), this->end ());
- if (!this->isSmall ())
- {
- free (this->begin ());
- }
- this->BeginX = RHS.BeginX;
- this->Size = RHS.Size;
- this->Capacity = RHS.Capacity;
- RHS.resetToSmall ();
- }
-
- void
- moveConstructFrom (SmallVectorImpl &&RHS)
- {
- assert (this->empty () && "move construction requires an empty vector");
- if (!RHS.isSmall ())
- {
- assignRemote (std::move (RHS));
- return;
- }
-
- // Construct inline elements directly instead of requiring T to be move
- // assignable through the general move-assignment implementation.
- size_type RHSSize = RHS.size ();
- reserve (RHSSize);
- this->uninitialized_move (RHS.begin (), RHS.end (), this->begin ());
- this->set_size (RHSSize);
- RHS.clear ();
- }
-
- ~SmallVectorImpl ()
- {
- // Subclass has already destructed this vector's elements.
- // If this wasn't grown from the inline copy, deallocate the old space.
- if (!this->isSmall ())
- {
- free (this->begin ());
- }
- }
-
-public:
- SmallVectorImpl (const SmallVectorImpl &) = delete;
-
- void
- clear ()
- {
- this->destroy_range (this->begin (), this->end ());
- this->Size = 0;
- }
-
-private:
- // Make set_size() private to avoid misuse in subclasses.
- using SuperClass::set_size;
-
- template <bool ForOverwrite>
- void
- resizeImpl (size_type N)
- {
- if (N == this->size ())
- {
- return;
- }
-
- if (N < this->size ())
- {
- this->truncate (N);
- return;
- }
-
- this->reserve (N);
- for (auto I = this->end (), E = this->begin () + N; I != E; ++I)
- {
- if (ForOverwrite)
- {
- new (&*I) T;
- }
- else
- {
- new (&*I) T ();
- }
- }
- this->set_size (N);
- }
-
-public:
- void
- resize (size_type N)
- {
- resizeImpl<false> (N);
- }
-
- /// Like resize, but \ref T is POD, the new values won't be initialized.
- void
- resize_for_overwrite (size_type N)
- {
- resizeImpl<true> (N);
- }
-
- /// Like resize, but requires that \p N is less than \a size().
- void
- truncate (size_type N)
- {
- assert (this->size () >= N && "Cannot increase size with truncate");
- this->destroy_range (this->begin () + N, this->end ());
- this->set_size (N);
- }
-
- void
- resize (size_type N, ValueParamT NV)
- {
- if (N == this->size ())
- {
- return;
- }
-
- if (N < this->size ())
- {
- this->truncate (N);
- return;
- }
-
- // N > this->size(). Defer to append.
- this->append (N - this->size (), NV);
- }
-
- void
- reserve (size_type N)
- {
- if (this->capacity () < N)
- {
- this->grow (N);
- }
- }
-
- void
- pop_back_n (size_type NumItems)
- {
- assert (this->size () >= NumItems);
- truncate (this->size () - NumItems);
- }
-
- [[nodiscard]] T
- pop_back_val ()
- {
- T Result = ::std::move (this->back ());
- this->pop_back ();
- return Result;
- }
-
- void
- swap (SmallVectorImpl &RHS);
-
- /// Add the specified range to the end of the SmallVector.
- template <typename ItTy, typename = EnableIfConvertibleToInputIterator<ItTy>>
- void
- append (ItTy in_start, ItTy in_end)
- {
- if constexpr (HasIteratorTag<ItTy, std::forward_iterator_tag>::value)
- {
- this->assertSafeToAddRange (in_start, in_end);
- size_type NumInputs = std::distance (in_start, in_end);
- this->reserve (this->size () + NumInputs);
- this->uninitialized_copy (in_start, in_end, this->end ());
- this->set_size (this->size () + NumInputs);
- }
- else
- {
- // Input iterator, we can't know ahead how many elements we'll add.
- for (; in_start != in_end; ++in_start)
- {
- this->emplace_back (*in_start);
- }
- }
- }
-
- /// Append \p NumInputs copies of \p Elt to the end.
- void
- append (size_type NumInputs, ValueParamT Elt)
- {
- const T *EltPtr = this->reserveForParamAndGetAddress (Elt, NumInputs);
- std::uninitialized_fill_n (this->end (), NumInputs, *EltPtr);
- this->set_size (this->size () + NumInputs);
- }
-
- void
- append (std::initializer_list<T> IL)
- {
- append (IL.begin (), IL.end ());
- }
-
- void
- append (const SmallVectorImpl &RHS)
- {
- append (RHS.begin (), RHS.end ());
- }
-
- void
- assign (size_type NumElts, ValueParamT Elt)
- {
- // Note that Elt could be an internal reference.
- if (NumElts > this->capacity ())
- {
- this->growAndAssign (NumElts, Elt);
- return;
- }
-
- // Assign over existing elements.
- std::fill_n (this->begin (), std::min (NumElts, this->size ()), Elt);
- if (NumElts > this->size ())
- {
- std::uninitialized_fill_n (this->end (), NumElts - this->size (), Elt);
- }
- else if (NumElts < this->size ())
- {
- this->destroy_range (this->begin () + NumElts, this->end ());
- }
- this->set_size (NumElts);
- }
-
- // FIXME: Consider assigning over existing elements, rather than clearing &
- // re-initializing them - for all assign(...) variants.
-
- template <typename ItTy, typename = EnableIfConvertibleToInputIterator<ItTy>>
- void
- assign (ItTy in_start, ItTy in_end)
- {
- this->assertSafeToReferenceAfterClear (in_start, in_end);
- clear ();
- append (in_start, in_end);
- }
-
- void
- assign (std::initializer_list<T> IL)
- {
- clear ();
- append (IL);
- }
-
- void
- assign (const SmallVectorImpl &RHS)
- {
- assign (RHS.begin (), RHS.end ());
- }
-
- template <typename U,
- typename = std::enable_if_t<std::is_convertible_v<U, T>>>
- void
- assign (ArrayRef<U> AR)
- {
- assign (AR.begin (), AR.end ());
- }
-
- iterator
- erase (const_iterator CI)
- {
- // Just cast away constness because this is a non-const member function.
- iterator I = const_cast<iterator> (CI);
-
- assert (this->isReferenceToStorage (CI) &&
- "Iterator to erase is out of bounds.");
-
- iterator N = I;
- // Shift all elts down one.
- std::move (I + 1, this->end (), I);
- // Drop the last elt.
- this->pop_back ();
- return (N);
- }
-
- iterator
- erase (const_iterator CS, const_iterator CE)
- {
- // Just cast away constness because this is a non-const member function.
- iterator S = const_cast<iterator> (CS);
- iterator E = const_cast<iterator> (CE);
-
- assert (this->isRangeInStorage (S, E) &&
- "Range to erase is out of bounds.");
-
- iterator N = S;
- // Shift all elts down.
- iterator I = std::move (E, this->end (), S);
- // Drop the last elts.
- this->destroy_range (I, this->end ());
- this->set_size (I - this->begin ());
- return (N);
- }
-
-private:
- template <class ArgType>
- iterator
- insert_one_impl (iterator I, ArgType &&Elt)
- {
- // Callers ensure that ArgType is derived from T.
- static_assert (
- std::is_same<std::remove_const_t<std::remove_reference_t<ArgType>>,
- T>::value,
- "ArgType must be derived from T!");
-
- if (I == this->end ())
- { // Important special case for empty vector.
- this->push_back (::std::forward<ArgType> (Elt));
- return this->end () - 1;
- }
-
- assert (this->isReferenceToStorage (I) &&
- "Insertion iterator is out of bounds.");
-
- // Grow if necessary.
- size_t Index = I - this->begin ();
- std::remove_reference_t<ArgType> *EltPtr =
- this->reserveForParamAndGetAddress (Elt);
- I = this->begin () + Index;
-
- ::new ((void *)this->end ()) T (::std::move (this->back ()));
- // Push everything else over.
- std::move_backward (I, this->end () - 1, this->end ());
- this->set_size (this->size () + 1);
-
- // If we just moved the element we're inserting, be sure to update
- // the reference (never happens if TakesParamByValue).
- static_assert (!TakesParamByValue || std::is_same<ArgType, T>::value,
- "ArgType must be 'T' when taking by value!");
- if (!TakesParamByValue &&
- this->isReferenceToRange (EltPtr, I, this->end ()))
- {
- ++EltPtr;
- }
-
- *I = ::std::forward<ArgType> (*EltPtr);
- return I;
- }
-
-public:
- iterator
- insert (iterator I, T &&Elt)
- {
- return insert_one_impl (I, this->forward_value_param (std::move (Elt)));
- }
-
- iterator
- insert (iterator I, const T &Elt)
- {
- return insert_one_impl (I, this->forward_value_param (Elt));
- }
-
- iterator
- insert (iterator I, size_type NumToInsert, ValueParamT Elt)
- {
- // Convert iterator to elt# to avoid invalidating iterator when we reserve()
- size_t InsertElt = I - this->begin ();
-
- if (I == this->end ())
- { // Important special case for empty vector.
- append (NumToInsert, Elt);
- return this->begin () + InsertElt;
- }
-
- assert (this->isReferenceToStorage (I) &&
- "Insertion iterator is out of bounds.");
-
- // Ensure there is enough space, and get the (maybe updated) address of
- // Elt.
- const T *EltPtr = this->reserveForParamAndGetAddress (Elt, NumToInsert);
-
- // Uninvalidate the iterator.
- I = this->begin () + InsertElt;
-
- // If there are more elements between the insertion point and the end of the
- // range than there are being inserted, we can use a simple approach to
- // insertion. Since we already reserved space, we know that this won't
- // reallocate the vector.
- if (size_t (this->end () - I) >= NumToInsert)
- {
- T *OldEnd = this->end ();
- append (std::move_iterator<iterator> (this->end () - NumToInsert),
- std::move_iterator<iterator> (this->end ()));
-
- // Copy the existing elements that get replaced.
- std::move_backward (I, OldEnd - NumToInsert, OldEnd);
-
- // If we just moved the element we're inserting, be sure to update
- // the reference (never happens if TakesParamByValue).
- if (!TakesParamByValue && I <= EltPtr && EltPtr < this->end ())
- {
- EltPtr += NumToInsert;
- }
-
- std::fill_n (I, NumToInsert, *EltPtr);
- return I;
- }
-
- // Otherwise, we're inserting more elements than exist already, and we're
- // not inserting at the end.
-
- // Move over the elements that we're about to overwrite.
- T *OldEnd = this->end ();
- this->set_size (this->size () + NumToInsert);
- size_t NumOverwritten = OldEnd - I;
- this->uninitialized_move (I, OldEnd, this->end () - NumOverwritten);
-
- // If we just moved the element we're inserting, be sure to update
- // the reference (never happens if TakesParamByValue).
- if (!TakesParamByValue && I <= EltPtr && EltPtr < this->end ())
- {
- EltPtr += NumToInsert;
- }
-
- // Replace the overwritten part.
- std::fill_n (I, NumOverwritten, *EltPtr);
-
- // Insert the non-overwritten middle part.
- std::uninitialized_fill_n (OldEnd, NumToInsert - NumOverwritten, *EltPtr);
- return I;
- }
-
- template <typename ItTy, typename = EnableIfConvertibleToInputIterator<ItTy>>
- iterator
- insert (iterator I, ItTy From, ItTy To)
- {
- // Convert iterator to elt# to avoid invalidating iterator when we reserve()
- size_t InsertElt = I - this->begin ();
-
- if (I == this->end ())
- { // Important special case for empty vector.
- append (From, To);
- return this->begin () + InsertElt;
- }
-
- if constexpr (!HasIteratorTag<ItTy, std::forward_iterator_tag>::value)
- {
- // For input iterators, we don't know the number of elements to insert.
- size_t OldSize = this->size ();
- append (From, To);
- I = this->begin () + InsertElt; // Uninvalidate the iterator.
- std::rotate (I, this->begin () + OldSize, this->end ());
- return I;
- }
-
- assert (this->isReferenceToStorage (I) &&
- "Insertion iterator is out of bounds.");
-
- // Check that the reserve that follows doesn't invalidate the iterators.
- this->assertSafeToAddRange (From, To);
-
- size_t NumToInsert = std::distance (From, To);
-
- // Ensure there is enough space.
- reserve (this->size () + NumToInsert);
-
- // Uninvalidate the iterator.
- I = this->begin () + InsertElt;
-
- // If there are more elements between the insertion point and the end of the
- // range than there are being inserted, we can use a simple approach to
- // insertion. Since we already reserved space, we know that this won't
- // reallocate the vector.
- if (size_t (this->end () - I) >= NumToInsert)
- {
- T *OldEnd = this->end ();
- append (std::move_iterator<iterator> (this->end () - NumToInsert),
- std::move_iterator<iterator> (this->end ()));
-
- // Copy the existing elements that get replaced.
- std::move_backward (I, OldEnd - NumToInsert, OldEnd);
-
- std::copy (From, To, I);
- return I;
- }
-
- // Otherwise, we're inserting more elements than exist already, and we're
- // not inserting at the end.
-
- // Move over the elements that we're about to overwrite.
- T *OldEnd = this->end ();
- this->set_size (this->size () + NumToInsert);
- size_t NumOverwritten = OldEnd - I;
- this->uninitialized_move (I, OldEnd, this->end () - NumOverwritten);
-
- // Replace the overwritten part.
- for (T *J = I; NumOverwritten > 0; --NumOverwritten)
- {
- *J = *From;
- ++J;
- ++From;
- }
-
- // Insert the non-overwritten middle part.
- this->uninitialized_copy (From, To, OldEnd);
- return I;
- }
-
- void
- insert (iterator I, std::initializer_list<T> IL)
- {
- insert (I, IL.begin (), IL.end ());
- }
-
- template <typename... ArgTypes>
- reference
- emplace_back (ArgTypes &&...Args)
- {
- if (RCC_UNLIKELY (this->size () >= this->capacity ()))
- {
- return this->growAndEmplaceBack (std::forward<ArgTypes> (Args)...);
- }
-
- ::new ((void *)this->end ()) T (std::forward<ArgTypes> (Args)...);
- this->set_size (this->size () + 1);
- return this->back ();
- }
-
- SmallVectorImpl &
- operator= (const SmallVectorImpl &RHS);
-
- SmallVectorImpl &
- operator= (SmallVectorImpl &&RHS);
-
- bool
- operator== (const SmallVectorImpl &RHS) const
- {
- if (this->size () != RHS.size ())
- {
- return false;
- }
- return std::equal (this->begin (), this->end (), RHS.begin ());
- }
- bool
- operator!= (const SmallVectorImpl &RHS) const
- {
- return !(*this == RHS);
- }
-
- bool
- operator< (const SmallVectorImpl &RHS) const
- {
- return std::lexicographical_compare (this->begin (), this->end (),
- RHS.begin (), RHS.end ());
- }
- bool
- operator> (const SmallVectorImpl &RHS) const
- {
- return RHS < *this;
- }
- bool
- operator<= (const SmallVectorImpl &RHS) const
- {
- return !(*this > RHS);
- }
- bool
- operator>= (const SmallVectorImpl &RHS) const
- {
- return !(*this < RHS);
- }
-};
-
-template <typename T>
-void
-SmallVectorImpl<T>::swap (SmallVectorImpl<T> &RHS)
-{
- if (this == &RHS)
- {
- return;
- }
-
- // We can only avoid copying elements if neither vector is small.
- if (!this->isSmall () && !RHS.isSmall ())
- {
- std::swap (this->BeginX, RHS.BeginX);
- std::swap (this->Size, RHS.Size);
- std::swap (this->Capacity, RHS.Capacity);
- return;
- }
- this->reserve (RHS.size ());
- RHS.reserve (this->size ());
-
- // Swap the shared elements.
- size_t NumShared = this->size ();
- if (NumShared > RHS.size ())
- {
- NumShared = RHS.size ();
- }
- for (size_type i = 0; i != NumShared; ++i)
- {
- std::swap ((*this)[i], RHS[i]);
- }
-
- // Copy over the extra elts.
- if (this->size () > RHS.size ())
- {
- size_t EltDiff = this->size () - RHS.size ();
- this->uninitialized_copy (this->begin () + NumShared, this->end (),
- RHS.end ());
- RHS.set_size (RHS.size () + EltDiff);
- this->destroy_range (this->begin () + NumShared, this->end ());
- this->set_size (NumShared);
- }
- else if (RHS.size () > this->size ())
- {
- size_t EltDiff = RHS.size () - this->size ();
- this->uninitialized_copy (RHS.begin () + NumShared, RHS.end (),
- this->end ());
- this->set_size (this->size () + EltDiff);
- this->destroy_range (RHS.begin () + NumShared, RHS.end ());
- RHS.set_size (NumShared);
- }
-}
-
-template <typename T>
-SmallVectorImpl<T> &
-SmallVectorImpl<T>::operator= (const SmallVectorImpl<T> &RHS)
-{
- // Avoid self-assignment.
- if (this == &RHS)
- {
- return *this;
- }
-
- // If we already have sufficient space, assign the common elements, then
- // destroy any excess.
- size_t RHSSize = RHS.size ();
- size_t CurSize = this->size ();
- if (CurSize >= RHSSize)
- {
- // Assign common elements.
- iterator NewEnd;
- if (RHSSize)
- {
- NewEnd = std::copy (RHS.begin (), RHS.begin () + RHSSize, this->begin ());
- }
- else
- {
- NewEnd = this->begin ();
- }
-
- // Destroy excess elements.
- this->destroy_range (NewEnd, this->end ());
-
- // Trim.
- this->set_size (RHSSize);
- return *this;
- }
-
- // If we have to grow to have enough elements, destroy the current elements.
- // This allows us to avoid copying them during the grow.
- // FIXME: don't do this if they're efficiently moveable.
- if (this->capacity () < RHSSize)
- {
- // Destroy current elements.
- this->clear ();
- CurSize = 0;
- this->grow (RHSSize);
- }
- else if (CurSize)
- {
- // Otherwise, use assignment for the already-constructed elements.
- std::copy (RHS.begin (), RHS.begin () + CurSize, this->begin ());
- }
-
- // Copy construct the new elements in place.
- this->uninitialized_copy (RHS.begin () + CurSize, RHS.end (),
- this->begin () + CurSize);
-
- // Set end.
- this->set_size (RHSSize);
- return *this;
-}
-
-template <typename T>
-SmallVectorImpl<T> &
-SmallVectorImpl<T>::operator= (SmallVectorImpl<T> &&RHS)
-{
- // Avoid self-assignment.
- if (this == &RHS)
- {
- return *this;
- }
-
- // If the RHS isn't small, clear this vector and then steal its buffer.
- if (!RHS.isSmall ())
- {
- this->assignRemote (std::move (RHS));
- return *this;
- }
-
- // If we already have sufficient space, assign the common elements, then
- // destroy any excess.
- size_t RHSSize = RHS.size ();
- size_t CurSize = this->size ();
- if (CurSize >= RHSSize)
- {
- // Assign common elements.
- iterator NewEnd = this->begin ();
- if (RHSSize)
- {
- NewEnd = std::move (RHS.begin (), RHS.end (), NewEnd);
- }
-
- // Destroy excess elements and trim the bounds.
- this->destroy_range (NewEnd, this->end ());
- this->set_size (RHSSize);
-
- // Clear the RHS.
- RHS.clear ();
-
- return *this;
- }
-
- // If we have to grow to have enough elements, destroy the current elements.
- // This allows us to avoid copying them during the grow.
- // FIXME: this may not actually make any sense if we can efficiently move
- // elements.
- if (this->capacity () < RHSSize)
- {
- // Destroy current elements.
- this->clear ();
- CurSize = 0;
- this->grow (RHSSize);
- }
- else if (CurSize)
- {
- // Otherwise, use assignment for the already-constructed elements.
- std::move (RHS.begin (), RHS.begin () + CurSize, this->begin ());
- }
-
- // Move-construct the new elements in place.
- this->uninitialized_move (RHS.begin () + CurSize, RHS.end (),
- this->begin () + CurSize);
-
- // Set end.
- this->set_size (RHSSize);
-
- RHS.clear ();
- return *this;
-}
-
-/// Storage for the SmallVector elements. This is specialized for the N=0 case
-/// to avoid allocating unnecessary storage.
-template <typename T, unsigned N> struct SmallVectorStorage
-{
- alignas (T) char InlineElts[N * sizeof (T)];
-};
-
-/// We need the storage to be properly aligned even for small-size of 0 so that
-/// the pointer math in \a SmallVectorTemplateCommon::getFirstEl() is
-/// well-defined.
-template <typename T> struct alignas (T) SmallVectorStorage<T, 0>
-{
-};
-
-/// Forward declaration of SmallVector so that
-/// calculateSmallVectorDefaultInlinedElements can reference
-/// `sizeof(SmallVector<T, 0>)`.
-template <typename T, unsigned N> class RCC_GSL_OWNER SmallVector;
-
-/// Helper class for calculating the default number of inline elements for
-/// `SmallVector<T>`.
-///
-/// This should be migrated to a constexpr function when our minimum
-/// compiler support is enough for multi-statement constexpr functions.
-template <typename T> struct CalculateSmallVectorDefaultInlinedElements
-{
- // Parameter controlling the default number of inlined elements
- // for `SmallVector<T>`.
- //
- // The default number of inlined elements ensures that
- // 1. There is at least one inlined element.
- // 2. `sizeof(SmallVector<T>) <= kPreferredSmallVectorSizeof` unless
- // it contradicts 1.
- static constexpr size_t kPreferredSmallVectorSizeof = 64;
-
- // static_assert that sizeof(T) is not "too big".
- //
- // Because our policy guarantees at least one inlined element, it is possible
- // for an arbitrarily large inlined element to allocate an arbitrarily large
- // amount of inline storage. We generally consider it an antipattern for a
- // SmallVector to allocate an excessive amount of inline storage, so we want
- // to call attention to these cases and make sure that users are making an
- // intentional decision if they request a lot of inline storage.
- //
- // We want this assertion to trigger in pathological cases, but otherwise
- // not be too easy to hit. To accomplish that, the cutoff is actually somewhat
- // larger than kPreferredSmallVectorSizeof (otherwise,
- // `SmallVector<SmallVector<T>>` would be one easy way to trip it, and that
- // pattern seems useful in practice).
- //
- // One wrinkle is that this assertion is in theory non-portable, since
- // sizeof(T) is in general platform-dependent. However, we don't expect this
- // to be much of an issue, because most LLVM development happens on 64-bit
- // hosts, and therefore sizeof(T) is expected to *decrease* when compiled for
- // 32-bit hosts, dodging the issue. The reverse situation, where development
- // happens on a 32-bit host and then fails due to sizeof(T) *increasing* on a
- // 64-bit host, is expected to be very rare.
- static_assert (
- sizeof (T) <= 256,
- "You are trying to use a default number of inlined elements for "
- "`SmallVector<T>` but `sizeof(T)` is really big! Please use an "
- "explicit number of inlined elements with `SmallVector<T, N>` to make "
- "sure you really want that much inline storage.");
-
- // Discount the size of the header itself when calculating the maximum inline
- // bytes.
- static constexpr size_t PreferredInlineBytes =
- kPreferredSmallVectorSizeof - sizeof (SmallVector<T, 0>);
- static constexpr size_t NumElementsThatFit =
- PreferredInlineBytes / sizeof (T);
- static constexpr size_t value =
- NumElementsThatFit == 0 ? 1 : NumElementsThatFit;
-};
-
-/// This is a 'vector' (really, a variable-sized array), optimized
-/// for the case when the array is small. It contains some number of elements
-/// in-place, which allows it to avoid heap allocation when the actual number of
-/// elements is below that threshold. This allows normal "small" cases to be
-/// fast without losing generality for large inputs.
-///
-/// \note
-/// In the absence of a well-motivated choice for the number of inlined
-/// elements \p N, it is recommended to use \c SmallVector<T> (that is,
-/// omitting the \p N). This will choose a default number of inlined elements
-/// reasonable for allocation on the stack (for example, trying to keep \c
-/// sizeof(SmallVector<T>) around 64 bytes).
-///
-/// \warning This does not attempt to be exception safe.
-///
-/// \see https://llvm.org/docs/ProgrammersManual.html#llvm-adt-smallvector-h
-template <typename T,
- unsigned N = CalculateSmallVectorDefaultInlinedElements<T>::value>
-class RCC_GSL_OWNER SmallVector : public SmallVectorImpl<T>,
- SmallVectorStorage<T, N>
-{
-public:
- SmallVector () : SmallVectorImpl<T> (N)
- {
- }
-
- ~SmallVector ()
- {
- // Destroy the constructed elements in the vector.
- this->destroy_range (this->begin (), this->end ());
- }
-
- explicit SmallVector (size_t SizeArg) : SmallVectorImpl<T> (N)
- {
- this->resize (SizeArg);
- }
-
- SmallVector (size_t SizeArg, const T &Value) : SmallVectorImpl<T> (N)
- {
- this->assign (SizeArg, Value);
- }
-
- template <typename ItTy, typename = EnableIfConvertibleToInputIterator<ItTy>>
- SmallVector (ItTy S, ItTy E) : SmallVectorImpl<T> (N)
- {
- this->append (S, E);
- }
-
- template <typename RangeTy>
- explicit SmallVector (const iterator_range<RangeTy> &R)
- : SmallVectorImpl<T> (N)
- {
- this->append (R.begin (), R.end ());
- }
-
- SmallVector (std::initializer_list<T> IL) : SmallVectorImpl<T> (N)
- {
- this->append (IL);
- }
-
- template <typename U,
- typename = std::enable_if_t<std::is_convertible_v<U, T>>>
- explicit SmallVector (ArrayRef<U> A) : SmallVectorImpl<T> (N)
- {
- this->append (A.begin (), A.end ());
- }
-
- SmallVector (const SmallVector &RHS) : SmallVectorImpl<T> (N)
- {
- if (!RHS.empty ())
- {
- SmallVectorImpl<T>::operator= (RHS);
- }
- }
-
- SmallVector &
- operator= (const SmallVector &RHS)
- {
- SmallVectorImpl<T>::operator= (RHS);
- return *this;
- }
-
- // Reuse the move-assignment instantiation for trivially move-assignable
- // elements. Calling moveConstructFrom unconditionally would emit an
- // additional per-T wrapper at -O0, increasing object size.
- // std::is_move_assignable_v<T> is too broad: it can be a false positive for
- // types with an unconstrained assignment operator whose body is ill-formed.
- SmallVector (SmallVector &&RHS) : SmallVectorImpl<T> (N)
- {
- if (!RHS.empty ())
- {
- bool StoleAllocation = N > 0 && !RHS.isSmall ();
- if constexpr (std::is_trivially_move_assignable_v<T>)
- {
- SmallVectorImpl<T>::operator= (::std::move (RHS));
- }
- else
- {
- this->moveConstructFrom (::std::move (RHS));
- }
- if constexpr (N > 0)
- {
- if (StoleAllocation)
- {
- RHS.set_allocation_range (RHS.begin (), N);
- }
- }
- }
- }
-
- SmallVector (SmallVectorImpl<T> &&RHS) : SmallVectorImpl<T> (N)
- {
- if (!RHS.empty ())
- {
- if constexpr (std::is_trivially_move_assignable_v<T>)
- {
- SmallVectorImpl<T>::operator= (::std::move (RHS));
- }
- else
- {
- this->moveConstructFrom (::std::move (RHS));
- }
- }
- }
-
- SmallVector &
- operator= (SmallVector &&RHS)
- {
- if (N)
- {
- bool StoleAllocation = this != &RHS && !RHS.isSmall ();
- SmallVectorImpl<T>::operator= (::std::move (RHS));
- // Restore the inline capacity after stealing RHS's allocation.
- if (StoleAllocation)
- {
- RHS.set_allocation_range (RHS.begin (), N);
- }
- return *this;
- }
- // SmallVectorImpl<T>::operator= does not leverage N==0. Optimize the
- // case.
- if (this == &RHS)
- {
- return *this;
- }
- if (RHS.empty ())
- {
- this->destroy_range (this->begin (), this->end ());
- this->Size = 0;
- }
- else
- {
- this->assignRemote (std::move (RHS));
- }
- return *this;
- }
-
- SmallVector &
- operator= (SmallVectorImpl<T> &&RHS)
- {
- SmallVectorImpl<T>::operator= (::std::move (RHS));
- return *this;
- }
-
- SmallVector &
- operator= (std::initializer_list<T> IL)
- {
- this->assign (IL);
- return *this;
- }
-};
-
-template <typename T, unsigned N>
-inline size_t
-capacity_in_bytes (const SmallVector<T, N> &X)
-{
- return X.capacity_in_bytes ();
-}
-
-template <typename RangeType>
-using ValueTypeFromRangeType = std::ranges::range_value_t<RangeType>;
-
-/// Given a range of type R, iterate the entire range and return a
-/// SmallVector with elements of the vector. This is useful, for example,
-/// when you want to iterate a range and then sort the results.
-template <unsigned Size, typename R>
-SmallVector<ValueTypeFromRangeType<R>, Size>
-to_vector (R &&Range)
-{
- return SmallVector<ValueTypeFromRangeType<R>, Size> (
- std::ranges::begin (Range), std::ranges::end (Range));
-}
-template <typename R>
-SmallVector<ValueTypeFromRangeType<R>>
-to_vector (R &&Range)
-{
- return SmallVector<ValueTypeFromRangeType<R>> (std::ranges::begin (Range),
- std::ranges::end (Range));
-}
-
-template <typename Out, unsigned Size, typename R>
-SmallVector<Out, Size>
-to_vector_of (R &&Range)
-{
- return SmallVector<Out, Size> (std::ranges::begin (Range),
- std::ranges::end (Range));
-}
-
-template <typename Out, typename R>
-SmallVector<Out>
-to_vector_of (R &&Range)
-{
- return SmallVector<Out> (std::ranges::begin (Range),
- std::ranges::end (Range));
-}
-
-// Explicit instantiations
-extern template class rcc::SmallVectorBase<uint32_t>;
-#if SIZE_MAX > UINT32_MAX
-extern template class rcc::SmallVectorBase<uint64_t>;
-#endif
-
-} // end namespace rcc
-
-namespace std
-{
-
-template <typename T, unsigned N> struct hash<rcc::SmallVector<T, N>>
-{
- size_t
- operator() (const rcc::SmallVector<T, N> &Value) const
- {
- size_t Seed = 0;
- for (const T &Element : Value)
- {
- size_t ElementHash = std::hash<T>{}(Element);
- Seed ^= ElementHash + static_cast<size_t> (0x9e3779b9U) + (Seed << 6) +
- (Seed >> 2);
- }
- return Seed;
- }
-};
-
-/// Implement std::swap in terms of SmallVector swap.
-template <typename T>
-inline void
-swap (rcc::SmallVectorImpl<T> &LHS, rcc::SmallVectorImpl<T> &RHS)
-{
- LHS.swap (RHS);
-}
-
-/// Implement std::swap in terms of SmallVector swap.
-template <typename T, unsigned N>
-inline void
-swap (rcc::SmallVector<T, N> &LHS, rcc::SmallVector<T, N> &RHS)
-{
- LHS.swap (RHS);
-}
-
-} // end namespace std
-
-#endif // RCC_ADT_SMALLVECTOR_H
diff --git a/libsupport/include/CoreLib/Compiler/Compiler.h b/libsupport/include/CoreLib/Compiler/Compiler.h
deleted file mode 100644
index 511c4cd..0000000
--- a/libsupport/include/CoreLib/Compiler/Compiler.h
+++ /dev/null
@@ -1,853 +0,0 @@
-/*
- RCC-Project
-
- Copyright (C) 2026 Richard Qin
-
- This file is part of RCC-Project.
-
- RCC-Project is free software; you can redistribute it and/or modify it under
- the terms of the GNU General Public License as published by the Free
- Software Foundation; either version 3 of the License, or (at your option) any
- later version.
-
- RCC-Project is distributed in the hope that it will be useful, but WITHOUT ANY
- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
- A PARTICULAR PURPOSE. See the GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License along with
- RCC-Project; see the file COPYING. If not see
- <http://www.gnu.org/licenses/>.
-*/
-
-//===-- llvm/Support/Compiler.h - Compiler abstraction support --*- C++ -*-===//
-//
-// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
-// See https://llvm.org/LICENSE.txt for license information.
-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-//
-//===----------------------------------------------------------------------===//
-//
-// This file defines several macros, based on the current compiler. This allows
-// use of compiler-specific features in a way that remains portable. This header
-// can be included from either C or C++.
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef RCC_SUPPORT_COMPILER_H
-#define RCC_SUPPORT_COMPILER_H
-
-#include "rcc/Config/rcc-config.h"
-
-#include <stddef.h>
-
-#if defined(_MSC_VER)
-#include <sal.h>
-#endif
-
-#ifndef __has_feature
-#define __has_feature(x) 0
-#endif
-
-#ifndef __has_extension
-#define __has_extension(x) 0
-#endif
-
-#ifndef __has_attribute
-#define __has_attribute(x) 0
-#endif
-
-#ifndef __has_builtin
-#define __has_builtin(x) 0
-#endif
-
-#ifndef __has_warning
-#define __has_warning(x) 0
-#endif
-
-// Only use __has_cpp_attribute in C++ mode. GCC defines __has_cpp_attribute in
-// C mode, but the :: in __has_cpp_attribute(scoped::attribute) is invalid.
-#ifndef RCC_HAS_CPP_ATTRIBUTE
-#if defined(__cplusplus) && defined(__has_cpp_attribute)
-#define RCC_HAS_CPP_ATTRIBUTE(x) __has_cpp_attribute (x)
-#else
-#define RCC_HAS_CPP_ATTRIBUTE(x) 0
-#endif
-#endif
-
-/// \macro RCC_GNUC_PREREQ
-/// Extend the default __GNUC_PREREQ even if glibc's features.h isn't
-/// available.
-#ifndef RCC_GNUC_PREREQ
-#if defined(__GNUC__) && defined(__GNUC_MINOR__) && defined(__GNUC_PATCHLEVEL__)
-#define RCC_GNUC_PREREQ(maj, min, patch) \
- ((__GNUC__ << 20) + (__GNUC_MINOR__ << 10) + __GNUC_PATCHLEVEL__ >= \
- ((maj) << 20) + ((min) << 10) + (patch))
-#elif defined(__GNUC__) && defined(__GNUC_MINOR__)
-#define RCC_GNUC_PREREQ(maj, min, patch) \
- ((__GNUC__ << 20) + (__GNUC_MINOR__ << 10) >= ((maj) << 20) + ((min) << 10))
-#else
-#define RCC_GNUC_PREREQ(maj, min, patch) 0
-#endif
-#endif
-
-/// \macro RCC_MSC_PREREQ
-/// Is the compiler MSVC of at least the specified version?
-/// The common \param version values to check for are:
-/// * 1910: VS2017, version 15.1 & 15.2
-/// * 1911: VS2017, version 15.3 & 15.4
-/// * 1912: VS2017, version 15.5
-/// * 1913: VS2017, version 15.6
-/// * 1914: VS2017, version 15.7
-/// * 1915: VS2017, version 15.8
-/// * 1916: VS2017, version 15.9
-/// * 1920: VS2019, version 16.0
-/// * 1921: VS2019, version 16.1
-/// * 1922: VS2019, version 16.2
-/// * 1923: VS2019, version 16.3
-/// * 1924: VS2019, version 16.4
-/// * 1925: VS2019, version 16.5
-/// * 1926: VS2019, version 16.6
-/// * 1927: VS2019, version 16.7
-/// * 1928: VS2019, version 16.8 + 16.9
-/// * 1929: VS2019, version 16.10 + 16.11
-/// * 1930: VS2022, version 17.0
-#ifdef _MSC_VER
-#define RCC_MSC_PREREQ(version) (_MSC_VER >= (version))
-
-// We require at least VS 2019.
-#if !defined(RCC_FORCE_USE_OLD_TOOLCHAIN)
-#if !RCC_MSC_PREREQ(1920)
-#error RCC requires at least VS 2019.
-#endif
-#endif
-
-#else
-#define RCC_MSC_PREREQ(version) 0
-#endif
-
-/// RCC_LIBRARY_VISIBILITY - If a class marked with this attribute is linked
-/// into a shared library, then the class should be private to the library and
-/// not accessible from outside it. Can also be used to mark variables and
-/// functions, making them private to any shared library they are linked into.
-/// On PE/COFF targets, library visibility is the default, so this isn't needed.
-///
-/// RCC_EXTERNAL_VISIBILITY - classes, functions, and variables marked with
-/// this attribute will be made public and visible outside of any shared library
-/// they are linked in to.
-
-#if RCC_HAS_CPP_ATTRIBUTE(gnu::visibility) && defined(__GNUC__) && \
- !defined(__clang__)
-#define RCC_ATTRIBUTE_VISIBILITY_HIDDEN [[gnu::visibility ("hidden")]]
-#define RCC_ATTRIBUTE_VISIBILITY_DEFAULT [[gnu::visibility ("default")]]
-#elif __has_attribute(visibility)
-#define RCC_ATTRIBUTE_VISIBILITY_HIDDEN __attribute__ ((visibility ("hidden")))
-#define RCC_ATTRIBUTE_VISIBILITY_DEFAULT \
- __attribute__ ((visibility ("default")))
-#else
-#define RCC_ATTRIBUTE_VISIBILITY_HIDDEN
-#define RCC_ATTRIBUTE_VISIBILITY_DEFAULT
-#endif
-
-#if defined(RCC_BUILD_RCC_DYLIB) || defined(RCC_BUILD_SHARED_LIBS)
-#define RCC_EXTERNAL_VISIBILITY RCC_ATTRIBUTE_VISIBILITY_DEFAULT
-#else
-#define RCC_EXTERNAL_VISIBILITY
-#endif
-
-#if (!(defined(_WIN32) || defined(__CYGWIN__)) || \
- ((defined(__MINGW32__) || defined(__CYGWIN__)) && defined(__clang__)))
-#define RCC_LIBRARY_VISIBILITY RCC_ATTRIBUTE_VISIBILITY_HIDDEN
-// Clang compilers older then 15 do not support gnu style attributes on
-// namespaces.
-#if defined(__clang__) && __clang_major__ < 15
-#define RCC_LIBRARY_VISIBILITY_NAMESPACE [[gnu::visibility ("hidden")]]
-#else
-#define RCC_LIBRARY_VISIBILITY_NAMESPACE RCC_ATTRIBUTE_VISIBILITY_HIDDEN
-#endif
-#define RCC_ALWAYS_EXPORT RCC_ATTRIBUTE_VISIBILITY_DEFAULT
-#elif defined(_WIN32)
-#define RCC_ALWAYS_EXPORT __declspec (dllexport)
-#define RCC_LIBRARY_VISIBILITY
-#define RCC_LIBRARY_VISIBILITY_NAMESPACE
-#else
-#define RCC_LIBRARY_VISIBILITY
-#define RCC_ALWAYS_EXPORT
-#define RCC_LIBRARY_VISIBILITY_NAMESPACE
-#endif
-
-/// RCC_ABI is the main export/visibility macro to mark something as explicitly
-/// exported when rcc is built as a shared library with everything else that is
-/// unannotated will have internal visibility.
-///
-/// RCC_ABI_EXPORT is for the special case for things like plugin symbol
-/// declarations or definitions where we don't want the macro to be switching
-/// between dllexport and dllimport on windows based on what codebase is being
-/// built, it will only be dllexport. For non windows platforms this macro
-/// behaves the same as RCC_ABI.
-///
-/// RCC_EXPORT_TEMPLATE is used on explicit template instantiations in source
-/// files that were declared extern in a header. This macro is only set as a
-/// compiler export attribute on windows, on other platforms it does nothing.
-///
-/// RCC_TEMPLATE_ABI is for annotating extern template declarations in headers
-/// for both functions and classes. On windows its turned in to dllimport for
-/// library consumers, for other platforms its a default visibility attribute.
-///
-/// RCC_ABI_FOR_TEST is for annotating symbols that are exported from a
-/// library-internal header solely so that unit tests can link against them.
-/// Symbols in RCC's public headers are part of the RCC public interface and
-/// should use RCC_ABI. RCC_ABI_FOR_TEST is reserved for internal headers,
-/// whose symbols could be conditionally excluded when not building tests in the
-/// future.
-///
-#ifndef RCC_ABI_GENERATING_ANNOTATIONS
-// Marker to add to classes or functions in public headers that should not have
-// export macros added to them by the clang tool
-#define RCC_ABI_NOT_EXPORTED
-// TODO(https://github.com/rcc/rcc-project/issues/145406): eliminate need for
-// two preprocessor definitions to gate RCC_ABI macro definitions.
-#if defined(RCC_ENABLE_RCC_EXPORT_ANNOTATIONS) && !defined(RCC_BUILD_STATIC)
-#if defined(_WIN32) && !defined(__MINGW32__)
-#if defined(RCC_EXPORTS)
-#define RCC_ABI __declspec (dllexport)
-#define RCC_TEMPLATE_ABI
-#define RCC_EXPORT_TEMPLATE __declspec (dllexport)
-#else
-#define RCC_ABI __declspec (dllimport)
-#define RCC_TEMPLATE_ABI __declspec (dllimport)
-#define RCC_EXPORT_TEMPLATE
-#endif
-#define RCC_ABI_EXPORT __declspec (dllexport)
-#elif __has_attribute(visibility)
-#if defined(__ELF__) || defined(__MINGW32__) || defined(_AIX) || \
- defined(__MVS__) || defined(__CYGWIN__)
-#define RCC_ABI __attribute__ ((visibility ("default")))
-#define RCC_TEMPLATE_ABI RCC_ABI
-#define RCC_EXPORT_TEMPLATE
-#define RCC_ABI_EXPORT RCC_ABI
-#elif defined(__MACH__) || defined(__wasm__) || defined(__EMSCRIPTEN__)
-#define RCC_ABI __attribute__ ((visibility ("default")))
-#define RCC_TEMPLATE_ABI
-#define RCC_EXPORT_TEMPLATE
-#define RCC_ABI_EXPORT RCC_ABI
-#endif
-#endif
-#endif
-#if !defined(RCC_ABI)
-#define RCC_ABI
-#define RCC_TEMPLATE_ABI
-#define RCC_EXPORT_TEMPLATE
-#define RCC_ABI_EXPORT
-#endif
-#define RCC_ABI_FOR_TEST RCC_ABI
-#endif
-
-#if defined(__GNUC__)
-#define RCC_PREFETCH(addr, rw, locality) __builtin_prefetch (addr, rw, locality)
-#else
-#define RCC_PREFETCH(addr, rw, locality)
-#endif
-
-#if __has_attribute(uninitialized)
-#define RCC_ATTRIBUTE_UNINITIALIZED __attribute__ ((uninitialized))
-#else
-#define RCC_ATTRIBUTE_UNINITIALIZED
-#endif
-
-#if __has_attribute(used)
-#define RCC_ATTRIBUTE_USED __attribute__ ((__used__))
-#else
-#define RCC_ATTRIBUTE_USED
-#endif
-
-#if __has_attribute(warn_unused)
-#define RCC_ATTRIBUTE_WARN_UNUSED __attribute__ ((warn_unused))
-#else
-#define RCC_ATTRIBUTE_WARN_UNUSED
-#endif
-
-// Only enabled for clang:
-// See https://gcc.gnu.org/bugzilla/show_bug.cgi?id=99587
-// GCC may produce "warning: 'retain' attribute ignored" (despite
-// __has_attribute(retain) being 1).
-#if defined(__clang__) && __has_attribute(retain)
-#define RCC_ATTRIBUTE_RETAIN __attribute__ ((__retain__))
-#else
-#define RCC_ATTRIBUTE_RETAIN
-#endif
-
-// For deprecations that are not a simple rename, use [[deprecated(MSG)]]
-// instead.
-#if defined(__clang__)
-#define RCC_DEPRECATED_WITH_FIXIT(MSG, FIX) \
- __attribute__ ((deprecated (MSG, FIX)))
-#else
-#define RCC_DEPRECATED_WITH_FIXIT(MSG, FIX) [[deprecated (MSG)]]
-#endif
-
-// clang-format off
-#if defined(__clang__) || defined(__GNUC__)
-#define RCC_SUPPRESS_DEPRECATED_DECLARATIONS_PUSH \
- _Pragma("GCC diagnostic push") \
- _Pragma("GCC diagnostic ignored \"-Wdeprecated-declarations\"")
-#define RCC_SUPPRESS_DEPRECATED_DECLARATIONS_POP \
- _Pragma("GCC diagnostic pop")
-#elif defined(_MSC_VER)
-#define RCC_SUPPRESS_DEPRECATED_DECLARATIONS_PUSH \
- __pragma(warning(push)) \
- __pragma(warning(disable : 4996))
-#define RCC_SUPPRESS_DEPRECATED_DECLARATIONS_POP \
- __pragma(warning(pop))
-#else
-#define RCC_SUPPRESS_DEPRECATED_DECLARATIONS_PUSH
-#define RCC_SUPPRESS_DEPRECATED_DECLARATIONS_POP
-#endif
-// clang-format on
-
-// Indicate that a non-static, non-const C++ member function reinitializes
-// the entire object to a known state, independent of the previous state of
-// the object.
-//
-// The clang-tidy check bugprone-use-after-move recognizes this attribute as a
-// marker that a moved-from object has left the indeterminate state and can be
-// reused.
-#if RCC_HAS_CPP_ATTRIBUTE(clang::reinitializes)
-#define RCC_ATTRIBUTE_REINITIALIZES [[clang::reinitializes]]
-#else
-#define RCC_ATTRIBUTE_REINITIALIZES
-#endif
-
-// Some compilers warn about unused functions. When a function is sometimes
-// used or not depending on build settings (e.g. a function only called from
-// within "assert"), this attribute can be used to suppress such warnings.
-//
-// However, it shouldn't be used for unused *variables*, as those have a much
-// more portable solution:
-// (void)unused_var_name;
-// Prefer cast-to-void wherever it is sufficient.
-#if __has_attribute(unused)
-#define RCC_ATTRIBUTE_UNUSED __attribute__ ((__unused__))
-#else
-#define RCC_ATTRIBUTE_UNUSED
-#endif
-
-// FIXME: Provide this for PE/COFF targets.
-#if __has_attribute(weak) && !defined(__MINGW32__) && !defined(__CYGWIN__) && \
- !defined(_WIN32)
-#define RCC_HAS_ATTRIBUTE_WEAK 1
-#else
-#define RCC_HAS_ATTRIBUTE_WEAK 0
-#endif
-#if RCC_HAS_ATTRIBUTE_WEAK
-#define RCC_ATTRIBUTE_WEAK __attribute__ ((__weak__))
-#else
-#define RCC_ATTRIBUTE_WEAK
-#endif
-
-// Prior to clang 3.2, clang did not accept any spelling of
-// __has_attribute(const), so assume it is supported.
-#if defined(__clang__) || defined(__GNUC__)
-// aka 'CONST' but following RCC Conventions.
-#define RCC_READNONE __attribute__ ((__const__))
-#else
-#define RCC_READNONE
-#endif
-
-#if __has_attribute(pure) || defined(__GNUC__)
-// aka 'PURE' but following RCC Conventions.
-#define RCC_READONLY __attribute__ ((__pure__))
-#else
-#define RCC_READONLY
-#endif
-
-#if __has_attribute(minsize)
-#define RCC_ATTRIBUTE_MINSIZE __attribute__ ((minsize))
-#else
-#define RCC_ATTRIBUTE_MINSIZE
-#endif
-
-#if __has_builtin(__builtin_expect) || defined(__GNUC__)
-#define RCC_LIKELY(EXPR) __builtin_expect ((bool)(EXPR), true)
-#define RCC_UNLIKELY(EXPR) __builtin_expect ((bool)(EXPR), false)
-#else
-#define RCC_LIKELY(EXPR) (EXPR)
-#define RCC_UNLIKELY(EXPR) (EXPR)
-#endif
-
-/// RCC_ATTRIBUTE_NOINLINE - On compilers where we have a directive to do so,
-/// mark a method "not for inlining".
-#if __has_attribute(noinline)
-#define RCC_ATTRIBUTE_NOINLINE __attribute__ ((noinline))
-#elif defined(_MSC_VER)
-#define RCC_ATTRIBUTE_NOINLINE __declspec (noinline)
-#else
-#define RCC_ATTRIBUTE_NOINLINE
-#endif
-
-/// RCC_ATTRIBUTE_ALWAYS_INLINE - On compilers where we have a directive to do
-/// so, mark a method "always inline" because it is performance sensitive.
-#if __has_attribute(always_inline)
-#define RCC_ATTRIBUTE_ALWAYS_INLINE inline __attribute__ ((always_inline))
-#elif defined(_MSC_VER)
-#define RCC_ATTRIBUTE_ALWAYS_INLINE __forceinline
-#else
-#define RCC_ATTRIBUTE_ALWAYS_INLINE inline
-#endif
-
-/// RCC_ATTRIBUTE_ALWAYS_INLINE_UNLESS_DEBUG - Like
-/// RCC_ATTRIBUTE_ALWAYS_INLINE but disabled in debug builds to avoid stack
-/// overflow with deep recursion.
-#if defined(NDEBUG)
-#define RCC_ATTRIBUTE_ALWAYS_INLINE_UNLESS_DEBUG RCC_ATTRIBUTE_ALWAYS_INLINE
-#else
-#define RCC_ATTRIBUTE_ALWAYS_INLINE_UNLESS_DEBUG inline
-#endif
-
-/// RCC_ATTRIBUTE_NO_DEBUG - On compilers where we have a directive to do
-/// so, mark a method "no debug" because debug info makes the debugger
-/// experience worse.
-#if __has_attribute(nodebug)
-#define RCC_ATTRIBUTE_NODEBUG __attribute__ ((nodebug))
-#else
-#define RCC_ATTRIBUTE_NODEBUG
-#endif
-
-#if __has_attribute(returns_nonnull)
-#define RCC_ATTRIBUTE_RETURNS_NONNULL __attribute__ ((returns_nonnull))
-#elif defined(_MSC_VER)
-#define RCC_ATTRIBUTE_RETURNS_NONNULL _Ret_notnull_
-#else
-#define RCC_ATTRIBUTE_RETURNS_NONNULL
-#endif
-
-/// RCC_ATTRIBUTE_RESTRICT - Annotates a pointer to tell the compiler that
-/// it is not aliased in the current scope.
-#if defined(__clang__) || defined(__GNUC__) || defined(_MSC_VER)
-#define RCC_ATTRIBUTE_RESTRICT __restrict
-#else
-#define RCC_ATTRIBUTE_RESTRICT
-#endif
-
-/// \macro RCC_ATTRIBUTE_RETURNS_NOALIAS Used to mark a function as returning a
-/// pointer that does not alias any other valid pointer.
-#ifdef __GNUC__
-#define RCC_ATTRIBUTE_RETURNS_NOALIAS __attribute__ ((__malloc__))
-#elif defined(_MSC_VER)
-#define RCC_ATTRIBUTE_RETURNS_NOALIAS __declspec (restrict)
-#else
-#define RCC_ATTRIBUTE_RETURNS_NOALIAS
-#endif
-
-/// RCC_FALLTHROUGH - Mark fallthrough cases in switch statements.
-#if defined(__cplusplus) && __cplusplus > 201402L && \
- RCC_HAS_CPP_ATTRIBUTE(fallthrough)
-#define RCC_FALLTHROUGH [[fallthrough]]
-#elif RCC_HAS_CPP_ATTRIBUTE(gnu::fallthrough)
-#define RCC_FALLTHROUGH [[gnu::fallthrough]]
-#elif __has_attribute(fallthrough)
-#define RCC_FALLTHROUGH __attribute__ ((fallthrough))
-#elif RCC_HAS_CPP_ATTRIBUTE(clang::fallthrough)
-#define RCC_FALLTHROUGH [[clang::fallthrough]]
-#else
-#define RCC_FALLTHROUGH
-#endif
-
-/// RCC_REQUIRE_CONSTANT_INITIALIZATION - Apply this to globals to ensure that
-/// they are constant initialized.
-#if RCC_HAS_CPP_ATTRIBUTE(clang::require_constant_initialization)
-#define RCC_REQUIRE_CONSTANT_INITIALIZATION \
- [[clang::require_constant_initialization]]
-#else
-#define RCC_REQUIRE_CONSTANT_INITIALIZATION
-#endif
-
-/// RCC_GSL_OWNER - Apply this to owning classes like SmallVector to enable
-/// lifetime warnings.
-#if RCC_HAS_CPP_ATTRIBUTE(gsl::Owner)
-#define RCC_GSL_OWNER [[gsl::Owner]]
-#else
-#define RCC_GSL_OWNER
-#endif
-
-/// RCC_GSL_POINTER - Apply this to non-owning classes like
-/// StringRef to enable lifetime warnings.
-#if RCC_HAS_CPP_ATTRIBUTE(gsl::Pointer)
-#define RCC_GSL_POINTER [[gsl::Pointer]]
-#else
-#define RCC_GSL_POINTER
-#endif
-
-#if RCC_HAS_CPP_ATTRIBUTE(clang::lifetimebound)
-#define RCC_LIFETIME_BOUND [[clang::lifetimebound]]
-#else
-#define RCC_LIFETIME_BOUND
-#endif
-
-#if RCC_HAS_CPP_ATTRIBUTE(nodiscard) >= 201907L
-#define RCC_CTOR_NODISCARD [[nodiscard]]
-#else
-#define RCC_CTOR_NODISCARD
-#endif
-
-// Macro to suppress the MSVC warning C4848:
-// "support for attribute [[msvc::no_unique_address]] in C++17 and earlier
-// is a vendor extension".
-// This warning is removed in versions >= 19.43.
-#if !defined(_MSC_VER) || _MSC_VER >= 1943 || defined(__clang__)
-#define RCC_SUPPRESS_MSVC_ATTR_IS_VENDOR_EXT_PUSH
-#define RCC_SUPPRESS_MSVC_ATTR_IS_VENDOR_EXT_POP
-#else // MSVC < 19.43
-#define RCC_SUPPRESS_MSVC_ATTR_IS_VENDOR_EXT_PUSH \
- __pragma (warning (push)) __pragma (warning (disable : 4848))
-#define RCC_SUPPRESS_MSVC_ATTR_IS_VENDOR_EXT_POP __pragma (warning (pop))
-#endif
-
-#if RCC_HAS_CPP_ATTRIBUTE(no_unique_address)
-#define RCC_NO_UNIQUE_ADDRESS [[no_unique_address]]
-#elif RCC_HAS_CPP_ATTRIBUTE(msvc::no_unique_address)
-#define RCC_NO_UNIQUE_ADDRESS \
- RCC_SUPPRESS_MSVC_ATTR_IS_VENDOR_EXT_PUSH \
- [[msvc::no_unique_address]] RCC_SUPPRESS_MSVC_ATTR_IS_VENDOR_EXT_POP
-#else
-#define RCC_NO_UNIQUE_ADDRESS
-#endif
-
-/// RCC_EXTENSION - Support compilers where we have a keyword to suppress
-/// pedantic diagnostics.
-#ifdef __GNUC__
-#define RCC_EXTENSION __extension__
-#else
-#define RCC_EXTENSION
-#endif
-
-/// RCC_BUILTIN_UNREACHABLE - On compilers which support it, expands
-/// to an expression which states that it is undefined behavior for the
-/// compiler to reach this point. Otherwise is not defined.
-///
-/// '#else' is intentionally left out so that other macro logic (e.g.,
-/// RCC_ASSUME_ALIGNED and rcc_unreachable()) can detect whether
-/// RCC_BUILTIN_UNREACHABLE has a definition.
-#if __has_builtin(__builtin_unreachable) || defined(__GNUC__)
-#define RCC_BUILTIN_UNREACHABLE __builtin_unreachable ()
-#elif defined(_MSC_VER)
-#define RCC_BUILTIN_UNREACHABLE __assume (false)
-#endif
-
-/// RCC_BUILTIN_TRAP - On compilers which support it, expands to an expression
-/// which causes the program to exit abnormally.
-#if __has_builtin(__builtin_trap) || defined(__GNUC__)
-#define RCC_BUILTIN_TRAP __builtin_trap ()
-#elif defined(_MSC_VER)
-// The __debugbreak intrinsic is supported by MSVC, does not require forward
-// declarations involving platform-specific typedefs (unlike RaiseException),
-// results in a call to vectored exception handlers, and encodes to a short
-// instruction that still causes the trapping behavior we want.
-#define RCC_BUILTIN_TRAP __debugbreak ()
-#else
-#define RCC_BUILTIN_TRAP *(volatile int *)0x11 = 0
-#endif
-
-/// RCC_BUILTIN_DEBUGTRAP - On compilers which support it, expands to
-/// an expression which causes the program to break while running
-/// under a debugger.
-#if __has_builtin(__builtin_debugtrap)
-#define RCC_BUILTIN_DEBUGTRAP __builtin_debugtrap ()
-#elif defined(_MSC_VER)
-// The __debugbreak intrinsic is supported by MSVC and breaks while
-// running under the debugger, and also supports invoking a debugger
-// when the OS is configured appropriately.
-#define RCC_BUILTIN_DEBUGTRAP __debugbreak ()
-#else
-// Just continue execution when built with compilers that have no
-// support. This is a debugging aid and not intended to force the
-// program to abort if encountered.
-#define RCC_BUILTIN_DEBUGTRAP
-#endif
-
-/// \macro RCC_ASSUME_ALIGNED
-/// Returns a pointer with an assumed alignment.
-#if __has_builtin(__builtin_assume_aligned) || defined(__GNUC__)
-#define RCC_ASSUME_ALIGNED(p, a) __builtin_assume_aligned (p, a)
-#elif defined(RCC_BUILTIN_UNREACHABLE)
-#define RCC_ASSUME_ALIGNED(p, a) \
- (((uintptr_t (p) % (a)) == 0) ? (p) : (RCC_BUILTIN_UNREACHABLE, (p)))
-#else
-#define RCC_ASSUME_ALIGNED(p, a) (p)
-#endif
-
-/// \macro RCC_PACKED
-/// Used to specify a packed structure.
-/// RCC_PACKED(
-/// struct A {
-/// int i;
-/// int j;
-/// int k;
-/// long long l;
-/// });
-///
-/// RCC_PACKED_START
-/// struct B {
-/// int i;
-/// int j;
-/// int k;
-/// long long l;
-/// };
-/// RCC_PACKED_END
-#ifdef _MSC_VER
-#define RCC_PACKED(d) __pragma (pack (push, 1)) d __pragma (pack (pop))
-#define RCC_PACKED_START __pragma (pack (push, 1))
-#define RCC_PACKED_END __pragma (pack (pop))
-#else
-#define RCC_PACKED(d) d __attribute__ ((packed))
-#define RCC_PACKED_START _Pragma ("pack(push, 1)")
-#define RCC_PACKED_END _Pragma ("pack(pop)")
-#endif
-
-/// \macro RCC_MEMORY_SANITIZER_BUILD
-/// Whether RCC itself is built with MemorySanitizer instrumentation.
-#if __has_feature(memory_sanitizer)
-#define RCC_MEMORY_SANITIZER_BUILD 1
-#include <sanitizer/msan_interface.h>
-#define RCC_NO_SANITIZE_MEMORY_ATTRIBUTE __attribute__ ((no_sanitize_memory))
-#else
-#define RCC_MEMORY_SANITIZER_BUILD 0
-#define __msan_allocated_memory(p, size)
-#define __msan_unpoison(p, size)
-#define RCC_NO_SANITIZE_MEMORY_ATTRIBUTE
-#endif
-
-/// \macro RCC_ADDRESS_SANITIZER_BUILD
-/// Whether RCC itself is built with AddressSanitizer instrumentation.
-#if __has_feature(address_sanitizer) || defined(__SANITIZE_ADDRESS__)
-#define RCC_ADDRESS_SANITIZER_BUILD 1
-#if __has_include(<sanitizer/asan_interface.h>)
-#include <sanitizer/asan_interface.h>
-#else
-// These declarations exist to support ASan with MSVC. If MSVC eventually ships
-// asan_interface.h in their headers, then we can remove this.
-#ifdef __cplusplus
-extern "C"
-{
-#endif
- void
- __asan_poison_memory_region (void const volatile *addr, size_t size);
- void
- __asan_unpoison_memory_region (void const volatile *addr, size_t size);
-#ifdef __cplusplus
-} // extern "C"
-#endif
-#endif
-#else
-#define RCC_ADDRESS_SANITIZER_BUILD 0
-#define __asan_poison_memory_region(p, size)
-#define __asan_unpoison_memory_region(p, size)
-#endif
-
-/// \macro RCC_HWADDRESS_SANITIZER_BUILD
-/// Whether RCC itself is built with HWAddressSanitizer instrumentation.
-#if __has_feature(hwaddress_sanitizer)
-#define RCC_HWADDRESS_SANITIZER_BUILD 1
-#else
-#define RCC_HWADDRESS_SANITIZER_BUILD 0
-#endif
-
-/// \macro RCC_THREAD_SANITIZER_BUILD
-/// Whether RCC itself is built with ThreadSanitizer instrumentation.
-#if __has_feature(thread_sanitizer) || defined(__SANITIZE_THREAD__)
-#define RCC_THREAD_SANITIZER_BUILD 1
-#else
-#define RCC_THREAD_SANITIZER_BUILD 0
-#endif
-
-#if RCC_THREAD_SANITIZER_BUILD
-// Thread Sanitizer is a tool that finds races in code.
-// See http://code.google.com/p/data-race-test/wiki/DynamicAnnotations .
-// tsan detects these exact functions by name.
-#ifdef __cplusplus
-extern "C"
-{
-#endif
- void
- AnnotateHappensAfter (const char *file, int line, const volatile void *cv);
- void
- AnnotateHappensBefore (const char *file, int line, const volatile void *cv);
- void
- AnnotateIgnoreWritesBegin (const char *file, int line);
- void
- AnnotateIgnoreWritesEnd (const char *file, int line);
-#ifdef __cplusplus
-}
-#endif
-
-// This marker is used to define a happens-before arc. The race detector will
-// infer an arc from the begin to the end when they share the same pointer
-// argument.
-#define TsanHappensBefore(cv) AnnotateHappensBefore (__FILE__, __LINE__, cv)
-
-// This marker defines the destination of a happens-before arc.
-#define TsanHappensAfter(cv) AnnotateHappensAfter (__FILE__, __LINE__, cv)
-
-// Ignore any races on writes between here and the next TsanIgnoreWritesEnd.
-#define TsanIgnoreWritesBegin() AnnotateIgnoreWritesBegin (__FILE__, __LINE__)
-
-// Resume checking for racy writes.
-#define TsanIgnoreWritesEnd() AnnotateIgnoreWritesEnd (__FILE__, __LINE__)
-#else
-#define TsanHappensBefore(cv)
-#define TsanHappensAfter(cv)
-#define TsanIgnoreWritesBegin()
-#define TsanIgnoreWritesEnd()
-#endif
-
-/// \macro RCC_NO_SANITIZE
-/// Disable a particular sanitizer for a function.
-#if __has_attribute(no_sanitize)
-#define RCC_NO_SANITIZE(KIND) __attribute__ ((no_sanitize (KIND)))
-#else
-#define RCC_NO_SANITIZE(KIND)
-#endif
-
-/// Mark debug helper function definitions like dump() that should not be
-/// stripped from debug builds.
-/// Note that you should also surround dump() functions with
-/// `#if !defined(NDEBUG) || defined(RCC_ENABLE_DUMP)` so they do always
-/// get stripped in release builds.
-// FIXME: Move this to a private config.h as it's not usable in public headers.
-#if !defined(NDEBUG) || defined(RCC_ENABLE_DUMP)
-#define RCC_DUMP_METHOD \
- RCC_ATTRIBUTE_NOINLINE RCC_ATTRIBUTE_USED RCC_ATTRIBUTE_RETAIN
-#else
-#define RCC_DUMP_METHOD RCC_ATTRIBUTE_NOINLINE
-#endif
-
-/// \macro RCC_PRETTY_FUNCTION
-/// Gets a user-friendly looking function signature for the current scope
-/// using the best available method on each platform. The exact format of the
-/// resulting string is implementation specific and non-portable, so this should
-/// only be used, for example, for logging or diagnostics.
-#if defined(_MSC_VER)
-#define RCC_PRETTY_FUNCTION __FUNCSIG__
-#elif defined(__GNUC__) || defined(__clang__)
-#define RCC_PRETTY_FUNCTION __PRETTY_FUNCTION__
-#else
-#define RCC_PRETTY_FUNCTION __func__
-#endif
-
-/// \macro RCC_THREAD_LOCAL
-/// A thread-local storage specifier which can be used with globals,
-/// extern globals, and static globals.
-///
-/// This is essentially an extremely restricted analog to C++11's thread_local
-/// support. It uses thread_local if available, falling back on gcc __thread
-/// if not. __thread doesn't support many of the C++11 thread_local's
-/// features. You should only use this for PODs that you can statically
-/// initialize to some constant value. In almost all circumstances this is most
-/// appropriate for use with a pointer, integer, or small aggregation of
-/// pointers and integers.
-#if RCC_ENABLE_THREADS
-#if __has_feature(cxx_thread_local) || defined(_MSC_VER)
-#define RCC_THREAD_LOCAL thread_local
-#else
-// Clang, GCC, and other compatible compilers used __thread prior to C++11 and
-// we only need the restricted functionality that provides.
-#define RCC_THREAD_LOCAL __thread
-#endif
-#else // !RCC_ENABLE_THREADS
-// If threading is disabled entirely, this compiles to nothing and you get
-// a normal global variable.
-#define RCC_THREAD_LOCAL
-#endif
-
-/// \macro RCC_ENABLE_EXCEPTIONS
-/// Whether RCC is built with exception support.
-#if __has_feature(cxx_exceptions)
-#define RCC_ENABLE_EXCEPTIONS 1
-#elif defined(__GNUC__) && defined(__EXCEPTIONS)
-#define RCC_ENABLE_EXCEPTIONS 1
-#elif defined(_MSC_VER) && defined(_CPPUNWIND)
-#define RCC_ENABLE_EXCEPTIONS 1
-#endif
-
-/// \macro RCC_NO_PROFILE_INSTRUMENT_FUNCTION
-/// Disable the profile instrument for a function.
-#if __has_attribute(no_profile_instrument_function)
-#define RCC_NO_PROFILE_INSTRUMENT_FUNCTION \
- __attribute__ ((no_profile_instrument_function))
-#else
-#define RCC_NO_PROFILE_INSTRUMENT_FUNCTION
-#endif
-
-/// \macro RCC_PREFERRED_TYPE
-/// Adjust type of bit-field in debug info.
-#if __has_attribute(preferred_type)
-#define RCC_PREFERRED_TYPE(T) __attribute__ ((preferred_type (T)))
-#else
-#define RCC_PREFERRED_TYPE(T)
-#endif
-
-#if RCC_HAS_CPP_ATTRIBUTE(clang::ptrauth_vtable_pointer) && \
- (defined(__PTRAUTH__) || __has_feature(ptrauth_calls))
-#define RCC_MOVABLE_POLYMORPHIC_TYPE \
- [[clang::ptrauth_vtable_pointer (default_key, no_address_discrimination, \
- default_extra_discrimination)]]
-#else
-#define RCC_MOVABLE_POLYMORPHIC_TYPE
-#endif
-
-/// \macro RCC_VIRTUAL_ANCHOR_FUNCTION
-/// This macro is used to adhere to RCC's policy that each class with a vtable
-/// must have at least one out-of-line virtual function. This macro allows us
-/// to declare such a function in `final` classes without triggering a warning.
-// clang-format off
-// Autoformatting makes this look awful.
-#if defined(__clang__)
- // Make sure this is only parsed if __clang__ is defined
- #if __has_warning("-Wunnecessary-virtual-specifier")
- #define RCC_DECLARE_VIRTUAL_ANCHOR_FUNCTION() \
- _Pragma("clang diagnostic push") \
- _Pragma("clang diagnostic ignored \"-Wunnecessary-virtual-specifier\"") \
- virtual void anchor() \
- _Pragma("clang diagnostic pop")
- #else // __has_warning
- #define RCC_DECLARE_VIRTUAL_ANCHOR_FUNCTION() \
- virtual void anchor()
- #endif
-#else // defined(__clang__)
- #define RCC_DECLARE_VIRTUAL_ANCHOR_FUNCTION() \
- virtual void anchor()
-#endif
-// clang-format on
-
-/// \macro RCC_IS_X86
-/// Whether the target architecture is x86 / x86-64.
-#if defined(__x86_64__) || defined(__i386__)
-#define RCC_IS_X86 1
-#else
-#define RCC_IS_X86 0
-#endif
-
-/// \macro RCC_TARGET_SSE42
-/// Function attribute to compile a function with SSE4.2 enabled.
-#if defined(__has_attribute) && __has_attribute(target)
-#define RCC_TARGET_SSE42 __attribute__ ((target ("sse4.2")))
-#else
-#define RCC_TARGET_SSE42
-#endif
-
-#if __has_builtin(__builtin_cpu_supports) && \
- (defined(__linux__) || defined(__APPLE__))
-#define RCC_CPU_SUPPORTS(feature) __builtin_cpu_supports (feature)
-#else
-#define RCC_CPU_SUPPORTS(feature) 0
-#endif
-
-/// \macro RCC_CPU_SUPPORTS_SSE42
-/// Expands to true if the runtime cpu supports SSE4.2, or if compiled with
-/// SSE4.2 enabled.
-#if defined(__SSE4_2__)
-#define RCC_CPU_SUPPORTS_SSE42 1
-#else
-#define RCC_CPU_SUPPORTS_SSE42 RCC_CPU_SUPPORTS ("sse4.2")
-#endif
-
-#endif
diff --git a/libsupport/include/CoreLib/Error/ErrorHandling.h b/libsupport/include/CoreLib/Error/ErrorHandling.h
deleted file mode 100644
index 5ab5a9e..0000000
--- a/libsupport/include/CoreLib/Error/ErrorHandling.h
+++ /dev/null
@@ -1,217 +0,0 @@
-/*
- RCC-Project
-
- Copyright (C) 2026 Richard Qin
-
- This file is part of RCC-Project.
-
- RCC-Project is free software; you can redistribute it and/or modify it under
- the terms of the GNU General Public License as published by the Free
- Software Foundation; either version 3 of the License, or (at your option) any
- later version.
-
- RCC-Project is distributed in the hope that it will be useful, but WITHOUT ANY
- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
- A PARTICULAR PURPOSE. See the GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License along with
- RCC-Project; see the file COPYING. If not see
- <http://www.gnu.org/licenses/>.
- */
-
-//===- llvm/Support/ErrorHandling.h - Fatal error handling ------*- C++ -*-===//
-//
-// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
-// See https://llvm.org/LICENSE.txt for license information.
-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-//
-//===----------------------------------------------------------------------===//
-//
-// This file defines an API used to indicate fatal error conditions. Non-fatal
-// errors (most of them) should be handled through LLVMContext.
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef RCC_SUPPORT_ERRORHANDLING_H
-#define RCC_SUPPORT_ERRORHANDLING_H
-
-#include "CoreLib/Compiler/Compiler.h"
-
-namespace rcc
-{
-class StringRef;
-class Twine;
-
-/// An error handler callback.
-using fatal_error_handler_t = void (*) (void *user_data, const char *reason,
- bool gen_crash_diag);
-
-/// install_fatal_error_handler - Installs a new error handler to be used
-/// whenever a serious (non-recoverable) error is encountered by LLVM.
-///
-/// If no error handler is installed the default is to print the error message
-/// to stderr, and call exit(1). If an error handler is installed then it is
-/// the handler's responsibility to log the message, it will no longer be
-/// printed to stderr. If the error handler returns, then exit(1) will be
-/// called.
-///
-/// It is dangerous to naively use an error handler which throws an exception.
-/// Even though some applications desire to gracefully recover from arbitrary
-/// faults, blindly throwing exceptions through unfamiliar code isn't a way to
-/// achieve this.
-///
-/// \param user_data - An argument which will be passed to the install error
-/// handler.
-RCC_ABI void
-install_fatal_error_handler (fatal_error_handler_t handler,
- void *user_data = nullptr);
-
-/// Restores default error handling behaviour.
-RCC_ABI void
-remove_fatal_error_handler ();
-
-/// ScopedFatalErrorHandler - This is a simple helper class which just
-/// calls install_fatal_error_handler in its constructor and
-/// remove_fatal_error_handler in its destructor.
-struct ScopedFatalErrorHandler
-{
- explicit ScopedFatalErrorHandler (fatal_error_handler_t handler,
- void *user_data = nullptr)
- {
- install_fatal_error_handler (handler, user_data);
- }
-
- ~ScopedFatalErrorHandler ()
- {
- remove_fatal_error_handler ();
- }
-};
-
-/// @deprecated Use reportFatalInternalError() or reportFatalUsageError()
-/// instead.
-[[noreturn]] RCC_ABI void
-report_fatal_error (const char *reason, bool gen_crash_diag = true);
-[[noreturn]] RCC_ABI void
-report_fatal_error (StringRef reason, bool gen_crash_diag = true);
-[[noreturn]] RCC_ABI void
-report_fatal_error (const Twine &reason, bool gen_crash_diag = true);
-
-/// Report a fatal error that likely indicates a bug in LLVM. It serves a
-/// similar purpose as an assertion, but is always enabled, regardless of the
-/// value of NDEBUG.
-///
-/// This will call installed error handlers (or print the message by default)
-/// and then abort. This will produce a crash trace and *will* ask users to
-/// report an LLVM bug.
-[[noreturn]] RCC_ABI void
-reportFatalInternalError (const char *reason);
-[[noreturn]] RCC_ABI void
-reportFatalInternalError (StringRef reason);
-[[noreturn]] RCC_ABI void
-reportFatalInternalError (const Twine &reason);
-
-/// Report a fatal error that does not indicate a bug in LLVM.
-///
-/// This can be used in contexts where a proper error reporting mechanism
-/// (such as Error/Expected or DiagnosticInfo) is currently not supported, and
-/// would be too involved to introduce at the moment.
-///
-/// Examples where this function should be used instead of
-/// reportFatalInternalError() include invalid inputs or options, but also
-/// environment error conditions outside LLVM's control. It should also be used
-/// for known unsupported/unimplemented functionality.
-///
-/// This will call installed error handlers (or print the message by default)
-/// and then exit with code 1. It will not produce a crash trace and will
-/// *not* ask users to report an LLVM bug.
-[[noreturn]] RCC_ABI void
-reportFatalUsageError (const char *reason);
-[[noreturn]] RCC_ABI void
-reportFatalUsageError (StringRef reason);
-[[noreturn]] RCC_ABI void
-reportFatalUsageError (const Twine &reason);
-
-/// Installs a new bad alloc error handler that should be used whenever a
-/// bad alloc error, e.g. failing malloc/calloc, is encountered by LLVM.
-///
-/// The user can install a bad alloc handler, in order to define the behavior
-/// in case of failing allocations, e.g. throwing an exception. Note that this
-/// handler must not trigger any additional allocations itself.
-///
-/// If no error handler is installed the default is to print the error message
-/// to stderr, and call exit(1). If an error handler is installed then it is
-/// the handler's responsibility to log the message, it will no longer be
-/// printed to stderr. If the error handler returns, then exit(1) will be
-/// called.
-///
-///
-/// \param user_data - An argument which will be passed to the installed error
-/// handler.
-RCC_ABI void
-install_bad_alloc_error_handler (fatal_error_handler_t handler,
- void *user_data = nullptr);
-
-/// Restores default bad alloc error handling behavior.
-RCC_ABI void
-remove_bad_alloc_error_handler ();
-
-RCC_ABI void
-install_out_of_memory_new_handler ();
-
-/// Reports a bad alloc error, calling any user defined bad alloc
-/// error handler. In contrast to the generic 'report_fatal_error'
-/// functions, this function might not terminate, e.g. the user
-/// defined error handler throws an exception, but it won't return.
-///
-/// Note: When throwing an exception in the bad alloc handler, make sure that
-/// the following unwind succeeds, e.g. do not trigger additional allocations
-/// in the unwind chain.
-///
-/// If no error handler is installed (default), throws a bad_alloc exception
-/// if LLVM is compiled with exception support. Otherwise prints the error
-/// to standard error and calls abort().
-[[noreturn]] RCC_ABI void
-report_bad_alloc_error (const char *Reason, bool GenCrashDiag = true);
-
-/// This function calls abort(), and prints the optional message to stderr.
-/// Use the llvm_unreachable macro (that adds location info), instead of
-/// calling this function directly.
-[[noreturn]] RCC_ABI void
-rcc_unreachable_internal (const char *msg = nullptr, const char *file = nullptr,
- unsigned line = 0);
-} // namespace rcc
-
-/// Marks that the current location is not supposed to be reachable.
-/// In !NDEBUG builds, prints the message and location info to stderr.
-/// In NDEBUG builds, if the platform does not support a builtin unreachable
-/// then we call an internal LLVM runtime function. Otherwise the behavior is
-/// controlled by the CMake flag
-/// -DLLVM_UNREACHABLE_OPTIMIZE
-/// * When "ON" (default) llvm_unreachable() becomes an optimizer hint
-/// that the current location is not supposed to be reachable: the hint
-/// turns such code path into undefined behavior. On compilers that don't
-/// support such hints, prints a reduced message instead and aborts the
-/// program.
-/// * When "OFF", a builtin_trap is emitted instead of an
-// optimizer hint or printing a reduced message.
-///
-/// Use this instead of assert(0). It conveys intent more clearly, suppresses
-/// diagnostics for unreachable code paths, and allows compilers to omit
-/// unnecessary code.
-#ifndef NDEBUG
-#define rcc_unreachable(msg) \
- ::rcc::rcc_unreachable_internal (msg, __FILE__, __LINE__)
-#elif !defined(RCC_BUILTIN_UNREACHABLE)
-#define rcc_unreachable(msg) ::rcc::rcc_unreachable_internal ()
-#elif RCC_UNREACHABLE_OPTIMIZE
-#define rcc_unreachable(msg) RCC_BUILTIN_UNREACHABLE
-#else
-#define rcc_unreachable(msg) \
- do \
- { \
- RCC_BUILTIN_TRAP; \
- RCC_BUILTIN_UNREACHABLE; \
- } while (false)
-#endif
-
-#endif
diff --git a/libsupport/include/CoreLib/Error/ErrorOr.h b/libsupport/include/CoreLib/Error/ErrorOr.h
deleted file mode 100644
index 0e17822..0000000
--- a/libsupport/include/CoreLib/Error/ErrorOr.h
+++ /dev/null
@@ -1,378 +0,0 @@
-/*
- RCC-Project
-
- Copyright (C) 2026 Richard Qin
-
- This file is part of RCC-Project.
-
- RCC-Project is free software; you can redistribute it and/or modify it under
- the terms of the GNU General Public License as published by the Free
- Software Foundation; either version 3 of the License, or (at your option) any
- later version.
-
- RCC-Project is distributed in the hope that it will be useful, but WITHOUT ANY
- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
- A PARTICULAR PURPOSE. See the GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License along with
- RCC-Project; see the file COPYING. If not see
- <http://www.gnu.org/licenses/>.
-*/
-
-//===- llvm/Support/ErrorOr.h - Error Smart Pointer -------------*- C++ -*-===//
-//
-// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
-// See https://llvm.org/LICENSE.txt for license information.
-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-//
-//===----------------------------------------------------------------------===//
-///
-/// \file
-///
-/// Provides ErrorOr<T> smart pointer.
-///
-//===----------------------------------------------------------------------===//
-
-#ifndef RCC_SUPPORT_ERROROR_H
-#define RCC_SUPPORT_ERROROR_H
-
-#include <cassert>
-#include <functional> // for std::reference_wrapper
-#include <system_error>
-#include <type_traits>
-#include <utility>
-
-namespace rcc
-{
-
-/// Represents either an error or a value T.
-///
-/// ErrorOr<T> is a pointer-like class that represents the result of an
-/// operation. The result is either an error, or a value of type T. This is
-/// designed to emulate the usage of returning a pointer where nullptr indicates
-/// failure. However instead of just knowing that the operation failed, we also
-/// have an error_code that describes why it failed.
-///
-/// It is used like the following.
-/// \code
-/// ErrorOr<Buffer> getBuffer();
-///
-/// auto buffer = getBuffer();
-/// if (error_code ec = buffer.getError())
-/// return ec;
-/// buffer->write("adena");
-/// \endcode
-///
-///
-/// Implicit conversion to bool returns true if there is a usable value. The
-/// unary * and -> operators provide pointer like access to the value. Accessing
-/// the value when there is an error has undefined behavior.
-///
-/// When T is a reference type the behavior is slightly different. The reference
-/// is held in a std::reference_wrapper<std::remove_reference<T>::type>, and
-/// there is special handling to make operator -> work as if T was not a
-/// reference.
-///
-/// T cannot be a rvalue reference.
-template <class T> class ErrorOr
-{
- template <class OtherT> friend class ErrorOr;
-
- static constexpr bool isRef = std::is_reference_v<T>;
-
- using wrap = std::reference_wrapper<std::remove_reference_t<T>>;
-
-public:
- using storage_type = std::conditional_t<isRef, wrap, T>;
-
-private:
- using reference = std::remove_reference_t<T> &;
- using const_reference = const std::remove_reference_t<T> &;
- using pointer = std::remove_reference_t<T> *;
- using const_pointer = const std::remove_reference_t<T> *;
-
-public:
- template <class E>
- ErrorOr (E ErrorCode,
- std::enable_if_t<std::is_error_code_enum<E>::value ||
- std::is_error_condition_enum<E>::value,
- void *> = nullptr)
- : HasError (true)
- {
- new (getErrorStorage ()) std::error_code (make_error_code (ErrorCode));
- }
-
- ErrorOr (std::error_code EC) : HasError (true)
- {
- new (getErrorStorage ()) std::error_code (EC);
- }
-
- template <class OtherT>
- ErrorOr (OtherT &&Val,
- std::enable_if_t<std::is_convertible_v<OtherT, T>> * = nullptr)
- : HasError (false)
- {
- new (getStorage ()) storage_type (std::forward<OtherT> (Val));
- }
-
- ErrorOr (const ErrorOr &Other)
- {
- copyConstruct (Other);
- }
-
- template <class OtherT>
- ErrorOr (const ErrorOr<OtherT> &Other,
- std::enable_if_t<std::is_convertible_v<OtherT, T>> * = nullptr)
- {
- copyConstruct (Other);
- }
-
- template <class OtherT>
- explicit ErrorOr (
- const ErrorOr<OtherT> &Other,
- std::enable_if_t<!std::is_convertible_v<OtherT, const T &>> * = nullptr)
- {
- copyConstruct (Other);
- }
-
- ErrorOr (ErrorOr &&Other)
- {
- moveConstruct (std::move (Other));
- }
-
- template <class OtherT>
- ErrorOr (ErrorOr<OtherT> &&Other,
- std::enable_if_t<std::is_convertible_v<OtherT, T>> * = nullptr)
- {
- moveConstruct (std::move (Other));
- }
-
- // This might eventually need SFINAE but it's more complex than is_convertible
- // & I'm too lazy to write it right now.
- template <class OtherT>
- explicit ErrorOr (
- ErrorOr<OtherT> &&Other,
- std::enable_if_t<!std::is_convertible_v<OtherT, T>> * = nullptr)
- {
- moveConstruct (std::move (Other));
- }
-
- ErrorOr &
- operator= (const ErrorOr &Other)
- {
- copyAssign (Other);
- return *this;
- }
-
- ErrorOr &
- operator= (ErrorOr &&Other)
- {
- moveAssign (std::move (Other));
- return *this;
- }
-
- ~ErrorOr ()
- {
- if (!HasError)
- {
- getStorage ()->~storage_type ();
- }
- }
-
- /// Return false if there is an error.
- explicit
- operator bool () const
- {
- return !HasError;
- }
-
- reference
- get ()
- {
- return *getStorage ();
- }
- const_reference
- get () const
- {
- return const_cast<ErrorOr<T> *> (this)->get ();
- }
-
- std::error_code
- getError () const
- {
- return HasError ? *getErrorStorage () : std::error_code ();
- }
-
- pointer
- operator->()
- {
- return toPointer (getStorage ());
- }
-
- const_pointer
- operator->() const
- {
- return toPointer (getStorage ());
- }
-
- reference
- operator* ()
- {
- return *getStorage ();
- }
-
- const_reference
- operator* () const
- {
- return *getStorage ();
- }
-
-private:
- template <class OtherT>
- void
- copyConstruct (const ErrorOr<OtherT> &Other)
- {
- if (!Other.HasError)
- {
- // Get the other value.
- HasError = false;
- new (getStorage ()) storage_type (*Other.getStorage ());
- }
- else
- {
- // Get other's error.
- HasError = true;
- new (getErrorStorage ()) std::error_code (Other.getError ());
- }
- }
-
- template <class T1>
- static bool
- compareThisIfSameType (const T1 &a, const T1 &b)
- {
- return &a == &b;
- }
-
- template <class T1, class T2>
- static bool
- compareThisIfSameType (const T1 &, const T2 &)
- {
- return false;
- }
-
- template <class OtherT>
- void
- copyAssign (const ErrorOr<OtherT> &Other)
- {
- if (compareThisIfSameType (*this, Other))
- {
- return;
- }
-
- this->~ErrorOr ();
- new (this) ErrorOr (Other);
- }
-
- template <class OtherT>
- void
- moveConstruct (ErrorOr<OtherT> &&Other)
- {
- if (!Other.HasError)
- {
- // Get the other value.
- HasError = false;
- new (getStorage ()) storage_type (std::move (*Other.getStorage ()));
- }
- else
- {
- // Get other's error.
- HasError = true;
- new (getErrorStorage ()) std::error_code (Other.getError ());
- }
- }
-
- template <class OtherT>
- void
- moveAssign (ErrorOr<OtherT> &&Other)
- {
- if (compareThisIfSameType (*this, Other))
- {
- return;
- }
-
- this->~ErrorOr ();
- new (this) ErrorOr (std::move (Other));
- }
-
- pointer
- toPointer (pointer Val)
- {
- return Val;
- }
-
- const_pointer
- toPointer (const_pointer Val) const
- {
- return Val;
- }
-
- pointer
- toPointer (wrap *Val)
- {
- return &Val->get ();
- }
-
- const_pointer
- toPointer (const wrap *Val) const
- {
- return &Val->get ();
- }
-
- storage_type *
- getStorage ()
- {
- assert (!HasError && "Cannot get value when an error exists!");
- return &TStorage;
- }
-
- const storage_type *
- getStorage () const
- {
- assert (!HasError && "Cannot get value when an error exists!");
- return &TStorage;
- }
-
- std::error_code *
- getErrorStorage ()
- {
- assert (HasError && "Cannot get error when a value exists!");
- return &ErrorStorage;
- }
-
- const std::error_code *
- getErrorStorage () const
- {
- assert (HasError && "Cannot get error when a value exists!");
- return &ErrorStorage;
- }
-
- union
- {
- storage_type TStorage;
- std::error_code ErrorStorage;
- };
- bool HasError : 1;
-};
-
-template <class T, class E>
-std::enable_if_t<std::is_error_code_enum<E>::value ||
- std::is_error_condition_enum<E>::value,
- bool>
-operator== (const ErrorOr<T> &Err, E Code)
-{
- return Err.getError () == Code;
-}
-
-} // end namespace rcc
-
-#endif // RCC_SUPPORT_ERROROR_H
diff --git a/libsupport/include/CoreLib/Math/MathExtras.h b/libsupport/include/CoreLib/Math/MathExtras.h
deleted file mode 100644
index a9c954d..0000000
--- a/libsupport/include/CoreLib/Math/MathExtras.h
+++ /dev/null
@@ -1,1050 +0,0 @@
-/*
- RCC-Project
-
- Copyright (C) 2026 Richard Qin
-
- This file is part of RCC-Project.
-
- RCC-Project is free software; you can redistribute it and/or modify it under
- the terms of the GNU General Public License as published by the Free
- Software Foundation; either version 3 of the License, or (at your option) any
- later version.
-
- RCC-Project is distributed in the hope that it will be useful, but WITHOUT ANY
- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
- A PARTICULAR PURPOSE. See the GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License along with
- RCC-Project; see the file COPYING. If not see
- <http://www.gnu.org/licenses/>.
-*/
-
-//===-- llvm/Support/MathExtras.h - Useful math functions -------*- C++ -*-===//
-//
-// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
-// See https://llvm.org/LICENSE.txt for license information.
-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-//
-//===----------------------------------------------------------------------===//
-//
-// This file contains some functions that are useful for math stuff.
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef RCC_SUPPORT_MATHEXTRAS_H
-#define RCC_SUPPORT_MATHEXTRAS_H
-
-#include "CoreLib/Compiler/Compiler.h"
-#include <bit>
-#include <cassert>
-#include <climits>
-#include <cstdint>
-#include <cstring>
-#include <limits>
-#include <numbers>
-#include <type_traits>
-#include <utility>
-
-namespace rcc
-{
-/// Some template parameter helpers to optimize for bitwidth, for functions that
-/// take multiple arguments.
-
-// We can't verify signedness, since callers rely on implicit coercions to
-// signed/unsigned.
-template <typename T, typename U>
-using enableif_int =
- std::enable_if_t<std::is_integral_v<T> && std::is_integral_v<U>>;
-
-// Use std::common_type_t to widen only up to the widest argument.
-template <typename T, typename U, typename = enableif_int<T, U>>
-using common_uint =
- std::common_type_t<std::make_unsigned_t<T>, std::make_unsigned_t<U>>;
-template <typename T, typename U, typename = enableif_int<T, U>>
-using common_sint =
- std::common_type_t<std::make_signed_t<T>, std::make_signed_t<U>>;
-
-/// Mathematical constants.
-namespace numbers
-{
-// clang-format off
-inline constexpr float ef = std::numbers::e_v<float>;
-inline constexpr float egammaf = std::numbers::egamma_v<float>;
-inline constexpr float ln2f = std::numbers::ln2_v<float>;
-inline constexpr float ln10f = std::numbers::ln10_v<float>;
-inline constexpr float log2ef = std::numbers::log2e_v<float>;
-inline constexpr float log10ef = std::numbers::log10e_v<float>;
-inline constexpr float pif = std::numbers::pi_v<float>;
-inline constexpr float inv_pif = std::numbers::inv_pi_v<float>;
-inline constexpr float inv_sqrtpif = std::numbers::inv_sqrtpi_v<float>;
-inline constexpr float sqrt2f = std::numbers::sqrt2_v<float>;
-inline constexpr float inv_sqrt2f = 1.0f / std::numbers::sqrt2_v<float>;
-inline constexpr float sqrt3f = std::numbers::sqrt3_v<float>;
-inline constexpr float inv_sqrt3f = std::numbers::inv_sqrt3_v<float>;
-inline constexpr float phif = std::numbers::phi_v<float>;
-
-// sqrtpi is not in C++20 std::numbers.
-template <typename T, typename = std::enable_if_t<std::is_floating_point_v<T>>>
-inline constexpr T sqrtpi_v = T(0x1.c5bf891b4ef6bP+0); // (1.7724538509055160273) https://oeis.org/A002161
-inline constexpr double sqrtpi = sqrtpi_v<double>;
-inline constexpr float sqrtpif = sqrtpi_v<float>;
-
-// These string literals are taken from below:
-// https://github.com/bminor/glibc/blob/8543577b04ded6d979ffcc5a818930e4d74d0645/math/math.h#L1215-L1229
-constexpr const char *pis = "3.141592653589793238462643383279502884",
- *inv_pis = "0.318309886183790671537767526745028724";
-// clang-format on
-} // namespace numbers
-
-/// Create a bitmask with the N right-most bits set to 1, and all other
-/// bits set to 0. Only unsigned types are allowed.
-template <typename T>
-constexpr T
-maskTrailingOnes (unsigned N)
-{
- static_assert (std::is_unsigned_v<T>, "Invalid type!");
- const unsigned Bits = CHAR_BIT * sizeof (T);
- assert (N <= Bits && "Invalid bit index");
- if (N == 0)
- {
- return 0;
- }
- return T (-1) >> (Bits - N);
-}
-
-/// Create a bitmask with the N left-most bits set to 1, and all other
-/// bits set to 0. Only unsigned types are allowed.
-template <typename T>
-constexpr T
-maskLeadingOnes (unsigned N)
-{
- return ~maskTrailingOnes<T> (CHAR_BIT * sizeof (T) - N);
-}
-
-/// Create a bitmask with the N right-most bits set to 0, and all other
-/// bits set to 1. Only unsigned types are allowed.
-template <typename T>
-constexpr T
-maskTrailingZeros (unsigned N)
-{
- return maskLeadingOnes<T> (CHAR_BIT * sizeof (T) - N);
-}
-
-/// Create a bitmask with the N left-most bits set to 0, and all other
-/// bits set to 1. Only unsigned types are allowed.
-template <typename T>
-constexpr T
-maskLeadingZeros (unsigned N)
-{
- return maskTrailingOnes<T> (CHAR_BIT * sizeof (T) - N);
-}
-
-/// Macro compressed bit reversal table for 256 bits.
-///
-/// http://graphics.stanford.edu/~seander/bithacks.html#BitReverseTable
-static const unsigned char BitReverseTable256[256] = {
-#define R2(n) n, n + 2 * 64, n + 1 * 64, n + 3 * 64
-#define R4(n) R2 (n), R2 (n + 2 * 16), R2 (n + 1 * 16), R2 (n + 3 * 16)
-#define R6(n) R4 (n), R4 (n + 2 * 4), R4 (n + 1 * 4), R4 (n + 3 * 4)
- R6 (0), R6 (2), R6 (1), R6 (3)
-#undef R2
-#undef R4
-#undef R6
-};
-
-/// Reverse the bits in \p Val.
-template <typename T>
-constexpr T
-reverseBits (T Val)
-{
-#if __has_builtin(__builtin_bitreverse8)
- if constexpr (std::is_same_v<T, uint8_t>)
- {
- return __builtin_bitreverse8 (Val);
- }
-#endif
-#if __has_builtin(__builtin_bitreverse16)
- if constexpr (std::is_same_v<T, uint16_t>)
- {
- return __builtin_bitreverse16 (Val);
- }
-#endif
-#if __has_builtin(__builtin_bitreverse32)
- if constexpr (std::is_same_v<T, uint32_t>)
- {
- return __builtin_bitreverse32 (Val);
- }
-#endif
-#if __has_builtin(__builtin_bitreverse64)
- if constexpr (std::is_same_v<T, uint64_t>)
- {
- return __builtin_bitreverse64 (Val);
- }
-#endif
-
- unsigned char in[sizeof (Val)];
- unsigned char out[sizeof (Val)];
- std::memcpy (in, &Val, sizeof (Val));
- for (unsigned i = 0; i < sizeof (Val); ++i)
- {
- out[(sizeof (Val) - i) - 1] = BitReverseTable256[in[i]];
- }
- std::memcpy (&Val, out, sizeof (Val));
- return Val;
-}
-
-// NOTE: The following support functions use the _32/_64 extensions instead of
-// type overloading so that signed and unsigned integers can be used without
-// ambiguity.
-
-/// Return the high 32 bits of a 64 bit value.
-constexpr uint32_t
-Hi_32 (uint64_t Value)
-{
- return static_cast<uint32_t> (Value >> 32);
-}
-
-/// Return the low 32 bits of a 64 bit value.
-constexpr uint32_t
-Lo_32 (uint64_t Value)
-{
- return static_cast<uint32_t> (Value);
-}
-
-/// Make a 64-bit integer from a high / low pair of 32-bit integers.
-constexpr uint64_t
-Make_64 (uint32_t High, uint32_t Low)
-{
- return ((uint64_t)High << 32) | (uint64_t)Low;
-}
-
-/// Checks if an integer fits into the given bit width.
-template <unsigned N>
-constexpr bool
-isInt (int64_t x)
-{
- if constexpr (N == 0)
- {
- return 0 == x;
- }
- if constexpr (N == 8)
- {
- return static_cast<int8_t> (x) == x;
- }
- if constexpr (N == 16)
- {
- return static_cast<int16_t> (x) == x;
- }
- if constexpr (N == 32)
- {
- return static_cast<int32_t> (x) == x;
- }
- if constexpr (N < 64)
- {
- return -(INT64_C (1) << (N - 1)) <= x && x < (INT64_C (1) << (N - 1));
- }
- (void)x; // MSVC v19.25 warns that x is unused.
- return true;
-}
-
-/// Checks if a signed integer is an N bit number shifted left by S.
-template <unsigned N, unsigned S>
-constexpr bool
-isShiftedInt (int64_t x)
-{
- static_assert (S < 64, "isShiftedInt<N, S> with S >= 64 is too much.");
- static_assert (N + S <= 64,
- "isShiftedInt<N, S> with N + S > 64 is too wide.");
- return isInt<N + S> (x) && (x % (UINT64_C (1) << S) == 0);
-}
-
-/// Checks if an unsigned integer fits into the given bit width.
-template <unsigned N>
-constexpr bool
-isUInt (uint64_t x)
-{
- if constexpr (N < 64)
- {
- return (x >> N) == 0;
- }
- (void)x; // MSVC v19.25 warns that x is unused.
- return true;
-}
-
-/// Checks if a unsigned integer is an N bit number shifted left by S.
-template <unsigned N, unsigned S>
-constexpr bool
-isShiftedUInt (uint64_t x)
-{
- static_assert (S < 64, "isShiftedUInt<N, S> with S >= 64 is too much.");
- static_assert (N + S <= 64,
- "isShiftedUInt<N, S> with N + S > 64 is too wide.");
- // S must be strictly less than 64. So 1 << S is not undefined behavior.
- return isUInt<N + S> (x) && (x % (UINT64_C (1) << S) == 0);
-}
-
-/// Gets the maximum value for a N-bit unsigned integer.
-inline constexpr uint64_t
-maxUIntN (uint64_t N)
-{
- assert (N <= 64 && "integer width out of range");
-
- // uint64_t(1) << 64 is undefined behavior, so we can't do
- // (uint64_t(1) << N) - 1
- // without checking first that N != 64. But this works and doesn't have a
- // branch for N != 0.
- // Unfortunately, shifting a uint64_t right by 64 bit is undefined
- // behavior, so the condition on N == 0 is necessary. Fortunately, most
- // optimizers do not emit branches for this check.
- if (N == 0)
- {
- return 0;
- }
- return UINT64_MAX >> (64 - N);
-}
-
-/// Gets the minimum value for a N-bit signed integer.
-inline constexpr int64_t
-minIntN (int64_t N)
-{
- assert (N <= 64 && "integer width out of range");
-
- if (N == 0)
- {
- return 0;
- }
- return UINT64_MAX << (N - 1);
-}
-
-/// Gets the maximum value for a N-bit signed integer.
-inline constexpr int64_t
-maxIntN (int64_t N)
-{
- assert (N <= 64 && "integer width out of range");
-
- // This relies on two's complement wraparound when N == 64, so we convert to
- // int64_t only at the very end to avoid UB.
- if (N == 0)
- {
- return 0;
- }
- return (UINT64_C (1) << (N - 1)) - 1;
-}
-
-/// Checks if an unsigned integer fits into the given (dynamic) bit width.
-inline constexpr bool
-isUIntN (unsigned N, uint64_t x)
-{
- return N >= 64 || (x >> N) == 0;
-}
-
-/// Checks if an signed integer fits into the given (dynamic) bit width.
-inline constexpr bool
-isIntN (unsigned N, int64_t x)
-{
- return N >= 64 || (minIntN (N) <= x && x <= maxIntN (N));
-}
-
-/// Return true if the argument is a non-empty sequence of ones starting at the
-/// least significant bit with the remainder zero (32 bit version).
-/// Ex. isMask_32(0x0000FFFFU) == true.
-constexpr bool
-isMask_32 (uint32_t Value)
-{
- return Value && ((Value + 1) & Value) == 0;
-}
-
-/// Return true if the argument is a non-empty sequence of ones starting at the
-/// least significant bit with the remainder zero (64 bit version).
-constexpr bool
-isMask_64 (uint64_t Value)
-{
- return Value && ((Value + 1) & Value) == 0;
-}
-
-/// Return true if the argument contains a non-empty sequence of ones with the
-/// remainder zero (32 bit version.) Ex. isShiftedMask_32(0x0000FF00U) == true.
-constexpr bool
-isShiftedMask_32 (uint32_t Value)
-{
- return Value && isMask_32 ((Value - 1) | Value);
-}
-
-/// Return true if the argument contains a non-empty sequence of ones with the
-/// remainder zero (64 bit version.)
-constexpr bool
-isShiftedMask_64 (uint64_t Value)
-{
- return Value && isMask_64 ((Value - 1) | Value);
-}
-
-/// Return true if the argument is a power of two > 0.
-/// Ex. isPowerOf2_32(0x00100000U) == true (32 bit edition.)
-constexpr bool
-isPowerOf2_32 (uint32_t Value)
-{
- return std::has_single_bit (Value);
-}
-
-/// Return true if the argument is a power of two > 0 (64 bit edition.)
-constexpr bool
-isPowerOf2_64 (uint64_t Value)
-{
- return std::has_single_bit (Value);
-}
-
-/// Return true if the argument contains a non-empty sequence of ones with the
-/// remainder zero (32 bit version.) Ex. isShiftedMask_32(0x0000FF00U) == true.
-/// If true, \p MaskIdx will specify the index of the lowest set bit and \p
-/// MaskLen is updated to specify the length of the mask, else neither are
-/// updated.
-inline bool
-isShiftedMask_32 (uint32_t Value, unsigned &MaskIdx, unsigned &MaskLen)
-{
- if (!isShiftedMask_32 (Value))
- {
- return false;
- }
- MaskIdx = std::countr_zero (Value);
- MaskLen = std::popcount (Value);
- return true;
-}
-
-/// Return true if the argument contains a non-empty sequence of ones with the
-/// remainder zero (64 bit version.) If true, \p MaskIdx will specify the index
-/// of the lowest set bit and \p MaskLen is updated to specify the length of the
-/// mask, else neither are updated.
-inline bool
-isShiftedMask_64 (uint64_t Value, unsigned &MaskIdx, unsigned &MaskLen)
-{
- if (!isShiftedMask_64 (Value))
- {
- return false;
- }
- MaskIdx = std::countr_zero (Value);
- MaskLen = std::popcount (Value);
- return true;
-}
-
-/// Compile time Log2.
-/// Valid only for positive powers of two.
-template <size_t kValue>
-constexpr size_t
-ConstantLog2 ()
-{
- static_assert (rcc::isPowerOf2_64 (kValue),
- "Value is not a valid power of 2");
- return std::countr_zero (kValue);
-}
-
-/// Return the floor log base 2 of the specified value, -1 if the value is zero.
-/// (32 bit edition.)
-/// Ex. Log2_32(32) == 5, Log2_32(1) == 0, Log2_32(0) == -1, Log2_32(6) == 2
-inline unsigned
-Log2_32 (uint32_t Value)
-{
- return 31 - std::countl_zero (Value);
-}
-
-/// Return the floor log base 2 of the specified value, -1 if the value is zero.
-/// (64 bit edition.)
-inline unsigned
-Log2_64 (uint64_t Value)
-{
- return 63 - std::countl_zero (Value);
-}
-
-/// Return the ceil log base 2 of the specified value, 32 if the value is zero.
-/// (32 bit edition).
-/// Ex. Log2_32_Ceil(32) == 5, Log2_32_Ceil(1) == 0, Log2_32_Ceil(6) == 3
-inline unsigned
-Log2_32_Ceil (uint32_t Value)
-{
- return 32 - std::countl_zero (Value - 1);
-}
-
-/// Return the ceil log base 2 of the specified value, 64 if the value is zero.
-/// (64 bit edition.)
-inline unsigned
-Log2_64_Ceil (uint64_t Value)
-{
- return 64 - std::countl_zero (Value - 1);
-}
-
-/// A and B are either alignments or offsets. Return the minimum alignment that
-/// may be assumed after adding the two together.
-template <typename U, typename V, typename T = common_uint<U, V>>
-constexpr T
-MinAlign (U A, V B)
-{
- // The largest power of 2 that divides both A and B.
- //
- // Replace "-Value" by "1+~Value" in the following commented code to avoid
- // MSVC warning C4146
- // return (A | B) & -(A | B);
- return (A | B) & (1 + ~(A | B));
-}
-
-/// Fallback when arguments aren't integral.
-constexpr uint64_t
-MinAlign (uint64_t A, uint64_t B)
-{
- return (A | B) & (1 + ~(A | B));
-}
-
-/// Returns the next power of two (in 64-bits) that is strictly greater than A.
-/// Returns zero on overflow.
-constexpr uint64_t
-NextPowerOf2 (uint64_t A)
-{
- A |= (A >> 1);
- A |= (A >> 2);
- A |= (A >> 4);
- A |= (A >> 8);
- A |= (A >> 16);
- A |= (A >> 32);
- return A + 1;
-}
-
-/// Returns the power of two which is greater than or equal to the given value.
-/// Essentially, it is a ceil operation across the domain of powers of two.
-inline uint64_t
-PowerOf2Ceil (uint64_t A)
-{
- if (!A || A > UINT64_MAX / 2)
- {
- return 0;
- }
- return UINT64_C (1) << Log2_64_Ceil (A);
-}
-
-/// Returns the integer ceil(Numerator / Denominator). Unsigned version.
-/// Guaranteed to never overflow.
-template <typename U, typename V, typename T = common_uint<U, V>>
-constexpr T
-divideCeil (U Numerator, V Denominator)
-{
- assert (Denominator && "Division by zero");
- T Bias = (Numerator != 0);
- return (Numerator - Bias) / Denominator + Bias;
-}
-
-/// Fallback when arguments aren't integral.
-constexpr uint64_t
-divideCeil (uint64_t Numerator, uint64_t Denominator)
-{
- assert (Denominator && "Division by zero");
- uint64_t Bias = (Numerator != 0);
- return (Numerator - Bias) / Denominator + Bias;
-}
-
-// Check whether divideCeilSigned or divideFloorSigned would overflow. This
-// happens only when Numerator = INT_MIN and Denominator = -1.
-template <typename U, typename V>
-constexpr bool
-divideSignedWouldOverflow (U Numerator, V Denominator)
-{
- return Numerator == std::numeric_limits<U>::min () && Denominator == -1;
-}
-
-/// Returns the integer ceil(Numerator / Denominator). Signed version.
-/// Overflow is explicitly forbidden with an assert.
-template <typename U, typename V, typename T = common_sint<U, V>>
-constexpr T
-divideCeilSigned (U Numerator, V Denominator)
-{
- assert (Denominator && "Division by zero");
- assert (!divideSignedWouldOverflow (Numerator, Denominator) &&
- "Divide would overflow");
- if (!Numerator)
- {
- return 0;
- }
- // C's integer division rounds towards 0.
- T Bias = Denominator >= 0 ? 1 : -1;
- bool SameSign = (Numerator >= 0) == (Denominator >= 0);
- return SameSign ? (Numerator - Bias) / Denominator + 1
- : Numerator / Denominator;
-}
-
-/// Returns the integer floor(Numerator / Denominator). Signed version.
-/// Overflow is explicitly forbidden with an assert.
-template <typename U, typename V, typename T = common_sint<U, V>>
-constexpr T
-divideFloorSigned (U Numerator, V Denominator)
-{
- assert (Denominator && "Division by zero");
- assert (!divideSignedWouldOverflow (Numerator, Denominator) &&
- "Divide would overflow");
- if (!Numerator)
- {
- return 0;
- }
- // C's integer division rounds towards 0.
- T Bias = Denominator >= 0 ? -1 : 1;
- bool SameSign = (Numerator >= 0) == (Denominator >= 0);
- return SameSign ? Numerator / Denominator
- : (Numerator - Bias) / Denominator - 1;
-}
-
-/// Returns the remainder of the Euclidean division of LHS by RHS. Result is
-/// always non-negative.
-template <typename U, typename V, typename T = common_sint<U, V>>
-constexpr T
-mod (U Numerator, V Denominator)
-{
- assert (Denominator >= 1 && "Mod by non-positive number");
- T Mod = Numerator % Denominator;
- return Mod < 0 ? Mod + Denominator : Mod;
-}
-
-/// Returns (Numerator / Denominator) rounded by round-half-up. Guaranteed to
-/// never overflow.
-template <typename U, typename V, typename T = common_uint<U, V>>
-constexpr T
-divideNearest (U Numerator, V Denominator)
-{
- assert (Denominator && "Division by zero");
- T Mod = Numerator % Denominator;
- return (Numerator / Denominator) +
- (Mod > (static_cast<T> (Denominator) - 1) / 2);
-}
-
-/// Returns the next integer (mod 2**nbits) that is greater than or equal to
-/// \p Value and is a multiple of \p Align. \p Align must be non-zero.
-///
-/// Examples:
-/// \code
-/// alignTo(5, 8) = 8
-/// alignTo(17, 8) = 24
-/// alignTo(~0LL, 8) = 0
-/// alignTo(321, 255) = 510
-/// \endcode
-///
-/// Will overflow only if result is not representable in T.
-template <typename U, typename V, typename T = common_uint<U, V>>
-constexpr T
-alignTo (U Value, V Align)
-{
- assert (Align != 0u && "Align can't be 0.");
- T CeilDiv = divideCeil (Value, Align);
- return CeilDiv * Align;
-}
-
-/// Fallback when arguments aren't integral.
-constexpr uint64_t
-alignTo (uint64_t Value, uint64_t Align)
-{
- assert (Align != 0u && "Align can't be 0.");
- uint64_t CeilDiv = divideCeil (Value, Align);
- return CeilDiv * Align;
-}
-
-/// Will overflow only if result is not representable in T.
-template <typename U, typename V, typename T = common_uint<U, V>>
-constexpr T
-alignToPowerOf2 (U Value, V Align)
-{
- assert (Align != 0 && (Align & (Align - 1)) == 0 &&
- "Align must be a power of 2");
- T NegAlign = static_cast<T> (0) - Align;
- return (Value + (Align - 1)) & NegAlign;
-}
-
-/// Fallback when arguments aren't integral.
-constexpr uint64_t
-alignToPowerOf2 (uint64_t Value, uint64_t Align)
-{
- assert (Align != 0 && (Align & (Align - 1)) == 0 &&
- "Align must be a power of 2");
- uint64_t NegAlign = 0 - Align;
- return (Value + (Align - 1)) & NegAlign;
-}
-
-/// If non-zero \p Skew is specified, the return value will be a minimal integer
-/// that is greater than or equal to \p Size and equal to \p A * N + \p Skew for
-/// some integer N. If \p Skew is larger than \p A, its value is adjusted to '\p
-/// Skew mod \p A'. \p Align must be non-zero.
-///
-/// Examples:
-/// \code
-/// alignTo(5, 8, 7) = 7
-/// alignTo(17, 8, 1) = 17
-/// alignTo(~0LL, 8, 3) = 3
-/// alignTo(321, 255, 42) = 552
-/// \endcode
-///
-/// May overflow.
-template <typename U, typename V, typename W,
- typename T = common_uint<common_uint<U, V>, W>>
-constexpr T
-alignTo (U Value, V Align, W Skew)
-{
- assert (Align != 0u && "Align can't be 0.");
- Skew %= Align;
- return alignTo (Value - Skew, Align) + Skew;
-}
-
-/// Returns the next integer (mod 2**nbits) that is greater than or equal to
-/// \p Value and is a multiple of \c Align. \c Align must be non-zero.
-///
-/// Will overflow only if result is not representable in T.
-template <auto Align, typename V, typename T = common_uint<decltype (Align), V>>
-constexpr T
-alignTo (V Value)
-{
- static_assert (Align != 0u, "Align must be non-zero");
- T CeilDiv = divideCeil (Value, Align);
- return CeilDiv * Align;
-}
-
-/// Returns the largest unsigned integer less than or equal to \p Value and is
-/// \p Skew mod \p Align. \p Align must be non-zero. Guaranteed to never
-/// overflow.
-template <typename U, typename V, typename W = uint8_t,
- typename T = common_uint<common_uint<U, V>, W>>
-constexpr T
-alignDown (U Value, V Align, W Skew = 0)
-{
- assert (Align != 0u && "Align can't be 0.");
- Skew %= Align;
- return (Value - Skew) / Align * Align + Skew;
-}
-
-/// Sign-extend the number in the bottom B bits of X to a 32-bit integer.
-/// Requires B <= 32.
-template <unsigned B>
-constexpr int32_t
-SignExtend32 (uint32_t X)
-{
- static_assert (B <= 32, "Bit width out of range.");
- if constexpr (B == 0)
- {
- return 0;
- }
- return int32_t (X << (32 - B)) >> (32 - B);
-}
-
-/// Sign-extend the number in the bottom B bits of X to a 32-bit integer.
-/// Requires B <= 32.
-inline int32_t
-SignExtend32 (uint32_t X, unsigned B)
-{
- assert (B <= 32 && "Bit width out of range.");
- if (B == 0)
- {
- return 0;
- }
- return int32_t (X << (32 - B)) >> (32 - B);
-}
-
-/// Sign-extend the number in the bottom B bits of X to a 64-bit integer.
-/// Requires B <= 64.
-template <unsigned B>
-constexpr int64_t
-SignExtend64 (uint64_t x)
-{
- static_assert (B <= 64, "Bit width out of range.");
- if constexpr (B == 0)
- {
- return 0;
- }
- return int64_t (x << (64 - B)) >> (64 - B);
-}
-
-/// Sign-extend the number in the bottom B bits of X to a 64-bit integer.
-/// Requires B <= 64.
-inline int64_t
-SignExtend64 (uint64_t X, unsigned B)
-{
- assert (B <= 64 && "Bit width out of range.");
- if (B == 0)
- {
- return 0;
- }
- return int64_t (X << (64 - B)) >> (64 - B);
-}
-
-/// Return the absolute value of a signed integer, converted to the
-/// corresponding unsigned integer type. Avoids undefined behavior in std::abs
-/// when you pass it INT_MIN or similar.
-template <typename T, typename U = std::make_unsigned_t<T>>
-constexpr U
-AbsoluteValue (T X)
-{
- // If X is negative, cast it to the unsigned type _before_ negating it.
- return X < 0 ? -static_cast<U> (X) : X;
-}
-
-/// Subtract two unsigned integers, X and Y, of type T and return the absolute
-/// value of the result.
-template <typename U, typename V, typename T = common_uint<U, V>>
-constexpr T
-AbsoluteDifference (U X, V Y)
-{
- return X > Y ? (X - Y) : (Y - X);
-}
-
-/// Add two unsigned integers, X and Y, of type T. Clamp the result to the
-/// maximum representable value of T on overflow. ResultOverflowed indicates if
-/// the result is larger than the maximum representable value of type T.
-template <typename T>
-std::enable_if_t<std::is_unsigned_v<T>, T>
-SaturatingAdd (T X, T Y, bool *ResultOverflowed = nullptr)
-{
- bool Dummy;
- bool &Overflowed = ResultOverflowed ? *ResultOverflowed : Dummy;
- // Hacker's Delight, p. 29
- T Z = X + Y;
- Overflowed = (Z < X || Z < Y);
- if (Overflowed)
- {
- return std::numeric_limits<T>::max ();
- }
- else
- {
- return Z;
- }
-}
-
-/// Add multiple unsigned integers of type T. Clamp the result to the
-/// maximum representable value of T on overflow.
-template <class T, class... Ts>
-std::enable_if_t<std::is_unsigned_v<T>, T>
-SaturatingAdd (T X, T Y, T Z, Ts... Args)
-{
- bool Overflowed = false;
- T XY = SaturatingAdd (X, Y, &Overflowed);
- if (Overflowed)
- {
- return SaturatingAdd (std::numeric_limits<T>::max (), T (1), Args...);
- }
- return SaturatingAdd (XY, Z, Args...);
-}
-
-/// Multiply two unsigned integers, X and Y, of type T. Clamp the result to the
-/// maximum representable value of T on overflow. ResultOverflowed indicates if
-/// the result is larger than the maximum representable value of type T.
-template <typename T>
-std::enable_if_t<std::is_unsigned_v<T>, T>
-SaturatingMultiply (T X, T Y, bool *ResultOverflowed = nullptr)
-{
- bool Dummy;
- bool &Overflowed = ResultOverflowed ? *ResultOverflowed : Dummy;
-
- // Hacker's Delight, p. 30 has a different algorithm, but we don't use that
- // because it fails for uint16_t (where multiplication can have undefined
- // behavior due to promotion to int), and requires a division in addition
- // to the multiplication.
-
- Overflowed = false;
-
- // Log2(Z) would be either Log2Z or Log2Z + 1.
- // Special case: if X or Y is 0, Log2_64 gives -1, and Log2Z
- // will necessarily be less than Log2Max as desired.
- int Log2Z = Log2_64 (X) + Log2_64 (Y);
- const T Max = std::numeric_limits<T>::max ();
- int Log2Max = Log2_64 (Max);
- if (Log2Z < Log2Max)
- {
- return X * Y;
- }
- if (Log2Z > Log2Max)
- {
- Overflowed = true;
- return Max;
- }
-
- // We're going to use the top bit, and maybe overflow one
- // bit past it. Multiply all but the bottom bit then add
- // that on at the end.
- T Z = (X >> 1) * Y;
- if (Z & ~(Max >> 1))
- {
- Overflowed = true;
- return Max;
- }
- Z <<= 1;
- if (X & 1)
- {
- return SaturatingAdd (Z, Y, ResultOverflowed);
- }
-
- return Z;
-}
-
-/// Multiply two unsigned integers, X and Y, and add the unsigned integer, A to
-/// the product. Clamp the result to the maximum representable value of T on
-/// overflow. ResultOverflowed indicates if the result is larger than the
-/// maximum representable value of type T.
-template <typename T>
-std::enable_if_t<std::is_unsigned_v<T>, T>
-SaturatingMultiplyAdd (T X, T Y, T A, bool *ResultOverflowed = nullptr)
-{
- bool Dummy;
- bool &Overflowed = ResultOverflowed ? *ResultOverflowed : Dummy;
-
- T Product = SaturatingMultiply (X, Y, &Overflowed);
- if (Overflowed)
- {
- return Product;
- }
-
- return SaturatingAdd (A, Product, &Overflowed);
-}
-
-/// Use this rather than HUGE_VALF; the latter causes warnings on MSVC.
-RCC_ABI extern const float huge_valf;
-
-/// Add two signed integers, computing the two's complement truncated result,
-/// returning a pair {result, overflow}, where "overflow" is a boolean value
-/// indicating whether an overflow occurred.
-template <typename T>
-constexpr std::enable_if_t<std::is_signed_v<T>, std::pair<T, bool>>
-AddOverflow (T X, T Y)
-{
- // Perform the unsigned addition.
- using U = std::make_unsigned_t<T>;
- const U UX = static_cast<U> (X);
- const U UY = static_cast<U> (Y);
- const U UResult = UX + UY;
-
- // Convert to signed.
- auto Result = static_cast<T> (UResult);
-
- // Adding two positive numbers should result in a positive number.
- if (X > 0 && Y > 0)
- {
- return {Result, Result <= 0};
- }
- // Adding two negatives should result in a negative number.
- if (X < 0 && Y < 0)
- {
- return {Result, Result >= 0};
- }
- return {Result, false};
-}
-
-/// Add two signed integers, computing the two's complement truncated result,
-/// returning true if overflow occurred.
-template <typename T>
-std::enable_if_t<std::is_signed_v<T>, bool>
-AddOverflow (T X, T Y, T &Result)
-{
-#if __has_builtin(__builtin_add_overflow)
- return __builtin_add_overflow (X, Y, &Result);
-#else
- auto [Res, Ovf] = AddOverflow (X, Y);
- Result = Res;
- return Ovf;
-#endif
-}
-
-/// Subtract two signed integers, computing the two's complement truncated
-/// result, returning a pair {result, overflow}, where "overflow" is a
-/// boolean value indicating whether an overflow occurred.
-template <typename T>
-constexpr std::enable_if_t<std::is_signed_v<T>, std::pair<T, bool>>
-SubOverflow (T X, T Y)
-{
- // Perform the unsigned addition.
- using U = std::make_unsigned_t<T>;
- const U UX = static_cast<U> (X);
- const U UY = static_cast<U> (Y);
- const U UResult = UX - UY;
-
- // Convert to signed.
- auto Result = static_cast<T> (UResult);
-
- // Subtracting a positive number from a negative results in a negative number.
- if (X <= 0 && Y > 0)
- {
- return {Result, Result >= 0};
- }
- // Subtracting a negative number from a positive results in a positive number.
- if (X >= 0 && Y < 0)
- {
- return {Result, Result <= 0};
- }
- return {Result, false};
-}
-
-/// Subtract two signed integers, computing the two's complement truncated
-/// result, returning true if an overflow occurred.
-template <typename T>
-std::enable_if_t<std::is_signed_v<T>, bool>
-SubOverflow (T X, T Y, T &Result)
-{
-#if __has_builtin(__builtin_sub_overflow)
- return __builtin_sub_overflow (X, Y, &Result);
-#else
- auto [Res, Ovf] = SubOverflow (X, Y);
- Result = Res;
- return Ovf;
-#endif
-}
-
-/// Multiply two signed integers, computing the two's complement truncated
-/// result, returning a pair {result, overflow}, where "overflow" is a
-/// boolean value indicating whether an overflow occurred.
-template <typename T>
-constexpr std::enable_if_t<std::is_signed_v<T>, std::pair<T, bool>>
-MulOverflow (T X, T Y)
-{
- // Perform the unsigned multiplication on absolute values.
- using U = std::make_unsigned_t<T>;
- const U UX = X < 0 ? (0 - static_cast<U> (X)) : static_cast<U> (X);
- const U UY = Y < 0 ? (0 - static_cast<U> (Y)) : static_cast<U> (Y);
- const U UResult = UX * UY;
-
- // Convert to signed.
- const bool IsNegative = (X < 0) ^ (Y < 0);
- auto Result = IsNegative ? (0 - UResult) : UResult;
-
- // If any of the args was 0, result is 0 and no overflow occurs.
- if (UX == 0 || UY == 0)
- {
- return {Result, false};
- }
-
- // UX and UY are in [1, 2^n], where n is the number of digits.
- // Check how the max allowed absolute value (2^n for negative, 2^(n-1) for
- // positive) divided by an argument compares to the other.
- bool Overflow =
- IsNegative
- ? UX > (static_cast<U> (std::numeric_limits<T>::max ()) + U (1)) / UY
- : UX > (static_cast<U> (std::numeric_limits<T>::max ())) / UY;
-
- return {Result, Overflow};
-}
-
-/// Multiply two signed integers, computing the two's complement truncated
-/// result, returning true if an overflow occurred.
-template <typename T>
-std::enable_if_t<std::is_signed_v<T>, bool>
-MulOverflow (T X, T Y, T &Result)
-{
-#if __has_builtin(__builtin_mul_overflow)
- return __builtin_mul_overflow (X, Y, &Result);
-#else
- auto [Res, Ovf] = MulOverflow (X, Y);
- Result = Res;
- return Ovf;
-#endif
-}
-
-/// Type to force float point values onto the stack, so that x86 doesn't add
-/// hidden precision, avoiding rounding differences on various platforms.
-#if defined(__i386__) || defined(_M_IX86)
-using stack_float_t = volatile float;
-#else
-using stack_float_t = float;
-#endif
-
-/// Returns the number of digits in the given integer.
-RCC_ABI int
-NumDigitsBase10 (uint64_t X);
-
-} // namespace rcc
-
-#endif
diff --git a/libsupport/include/CoreLib/Memory/MemAlloc.h b/libsupport/include/CoreLib/Memory/MemAlloc.h
deleted file mode 100644
index b7183c0..0000000
--- a/libsupport/include/CoreLib/Memory/MemAlloc.h
+++ /dev/null
@@ -1,124 +0,0 @@
-/*
- RCC-Project
-
- Copyright (C) 2026 Richard Qin
-
- This file is part of RCC-Project.
-
- RCC-Project is free software; you can redistribute it and/or modify it under
- the terms of the GNU General Public License as published by the Free
- Software Foundation; either version 3 of the License, or (at your option) any
- later version.
-
- RCC-Project is distributed in the hope that it will be useful, but WITHOUT ANY
- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
- A PARTICULAR PURPOSE. See the GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License along with
- RCC-Project; see the file COPYING. If not see
- <http://www.gnu.org/licenses/>.
- */
-
-//===- MemAlloc.h - Memory allocation functions -----------------*- C++ -*-===//
-//
-// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
-// See https://llvm.org/LICENSE.txt for license information.
-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-//
-//===----------------------------------------------------------------------===//
-/// \file
-///
-/// This file defines counterparts of C library allocation functions defined in
-/// the namespace 'std'. The new allocation functions crash on allocation
-/// failure instead of returning null pointer.
-///
-//===----------------------------------------------------------------------===//
-
-#ifndef RCC_SUPPORT_MEMALLOC_H
-#define RCC_SUPPORT_MEMALLOC_H
-
-#include "CoreLib/Compiler/Compiler.h"
-#include "CoreLib/Error/ErrorHandling.h"
-#include <cstdlib>
-
-namespace rcc
-{
-
-RCC_ATTRIBUTE_RETURNS_NONNULL inline void *
-safe_malloc (size_t Sz)
-{
- void *Result = std::malloc (Sz);
- if (Result == nullptr)
- {
- // It is implementation-defined whether allocation occurs if the space
- // requested is zero (ISO/IEC 9899:2018 7.22.3). Retry, requesting
- // non-zero, if the space requested was zero.
- if (Sz == 0)
- {
- return safe_malloc (1);
- }
- report_bad_alloc_error ("Allocation failed");
- }
- return Result;
-}
-
-RCC_ATTRIBUTE_RETURNS_NONNULL inline void *
-safe_calloc (size_t Count, size_t Sz)
-{
- void *Result = std::calloc (Count, Sz);
- if (Result == nullptr)
- {
- // It is implementation-defined whether allocation occurs if the space
- // requested is zero (ISO/IEC 9899:2018 7.22.3). Retry, requesting
- // non-zero, if the space requested was zero.
- if (Count == 0 || Sz == 0)
- {
- return safe_malloc (1);
- }
- report_bad_alloc_error ("Allocation failed");
- }
- return Result;
-}
-
-RCC_ATTRIBUTE_RETURNS_NONNULL inline void *
-safe_realloc (void *Ptr, size_t Sz)
-{
- void *Result = std::realloc (Ptr, Sz);
- if (Result == nullptr)
- {
- // It is implementation-defined whether allocation occurs if the space
- // requested is zero (ISO/IEC 9899:2018 7.22.3). Retry, requesting
- // non-zero, if the space requested was zero.
- if (Sz == 0)
- {
- return safe_malloc (1);
- }
- report_bad_alloc_error ("Allocation failed");
- }
- return Result;
-}
-
-/// Allocate a buffer of memory with the given size and alignment.
-///
-/// When the compiler supports aligned operator new, this will use it to
-/// handle even over-aligned allocations.
-///
-/// However, this doesn't make any attempt to leverage the fancier techniques
-/// like posix_memalign due to portability. It is mostly intended to allow
-/// compatibility with platforms that, after aligned allocation was added, use
-/// reduced default alignment.
-RCC_ABI RCC_ATTRIBUTE_RETURNS_NONNULL RCC_ATTRIBUTE_RETURNS_NOALIAS void *
-allocate_buffer (size_t Size, size_t Alignment);
-
-/// Deallocate a buffer of memory with the given size and alignment.
-///
-/// If supported, this will used the sized delete operator. Also if supported,
-/// this will pass the alignment to the delete operator.
-///
-/// The pointer must have been allocated with the corresponding new operator,
-/// most likely using the above helper.
-RCC_ABI void
-deallocate_buffer (void *Ptr, size_t Size, size_t Alignment);
-
-} // namespace rcc
-#endif
diff --git a/libsupport/include/CoreLib/System/Errno.h b/libsupport/include/CoreLib/System/Errno.h
deleted file mode 100644
index 2626ad9..0000000
--- a/libsupport/include/CoreLib/System/Errno.h
+++ /dev/null
@@ -1,64 +0,0 @@
-/*
- RCC-Project
-
- Copyright (C) 2026 Richard Qin
-
- This file is part of RCC-Project.
-
- RCC-Project is free software; you can redistribute it and/or modify it under
- the terms of the GNU General Public License as published by the Free
- Software Foundation; either version 3 of the License, or (at your option) any
- later version.
-
- RCC-Project is distributed in the hope that it will be useful, but WITHOUT ANY
- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
- A PARTICULAR PURPOSE. See the GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License along with
- RCC-Project; see the file COPYING. If not see
- <http://www.gnu.org/licenses/>.
-*/
-
-// This implementation is based on llvm/include/llvm/Support/Errno.h.
-
-#ifndef RCC_SUPPORT_ERRNO_H
-#define RCC_SUPPORT_ERRNO_H
-
-#include "CoreLib/Compiler/Compiler.h"
-
-#include <cerrno>
-#include <string>
-
-namespace rcc
-{
-namespace sys
-{
-
-/// Returns a string representation of the errno value, using whatever
-/// thread-safe variant of strerror() is available. Be sure to call this
-/// immediately after the function that set errno, or errno may have been
-/// overwritten by an intervening call.
-RCC_ABI std::string
-StrError ();
-
-/// Like the no-argument version above, but uses \p errnum instead of errno.
-RCC_ABI std::string
-StrError (int errnum);
-
-template <typename FailT, typename Fun, typename... Args>
-inline decltype (auto)
-RetryAfterSignal (const FailT &Fail, const Fun &F, const Args &...As)
-{
- decltype (F (As...)) Res;
- do
- {
- errno = 0;
- Res = F (As...);
- } while (Res == Fail && errno == EINTR);
- return Res;
-}
-
-} // namespace sys
-} // namespace rcc
-
-#endif // RCC_SUPPORT_ERRNO_H
diff --git a/libsupport/src/corelib/math/MathExtras.cc b/libsupport/src/corelib/math/MathExtras.cc
deleted file mode 100644
index 99d7ba7..0000000
--- a/libsupport/src/corelib/math/MathExtras.cc
+++ /dev/null
@@ -1,97 +0,0 @@
-/*
- RCC-Project
-
- Copyright (C) 2026 Richard Qin
-
- This file is part of RCC-Project.
-
- RCC-Project is free software; you can redistribute it and/or modify it under
- the terms of the GNU General Public License as published by the Free
- Software Foundation; either version 3 of the License, or (at your option) any
- later version.
-
- RCC-Project is distributed in the hope that it will be useful, but WITHOUT ANY
- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
- A PARTICULAR PURPOSE. See the GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License along with
- RCC-Project; see the file COPYING. If not see
- <http://www.gnu.org/licenses/>.
-*/
-
-//===-- MathExtras.cpp - Implement the MathExtras header --------------===//
-//
-// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
-// See https://llvm.org/LICENSE.txt for license information.
-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-//
-//===----------------------------------------------------------------------===//
-//
-// This file implements the MathExtras.h header
-//
-//===----------------------------------------------------------------------===//
-
-#include "CoreLib/Math/MathExtras.h"
-
-#ifdef _MSC_VER
-#include <limits>
-#else
-#include <cmath>
-#endif
-
-namespace rcc
-{
-
-#if defined(_MSC_VER)
-// Visual Studio defines the HUGE_VAL class of macros using purposeful
-// constant arithmetic overflow, which it then warns on when encountered.
-const float huge_valf = std::numeric_limits<float>::infinity ();
-#else
-const float huge_valf = HUGE_VALF;
-#endif
-
-/// Returns the number of digits in the given integer.
-int
-NumDigitsBase10 (uint64_t X)
-{
- static constexpr struct ConstexprData
- {
- uint8_t AtLeast[65] = {};
- uint64_t Boundaries[20] = {};
- static constexpr int
- NumDigitsConstexpr (uint64_t N)
- {
- int res = 1;
- while (N >= 10)
- {
- res++;
- N /= 10;
- }
- return res;
- }
- constexpr ConstexprData ()
- {
- uint64_t Val = ~0ull;
- for (uint64_t i = 0; i <= 64; i++)
- {
- uint64_t Digits = NumDigitsConstexpr (Val) - 1;
- AtLeast[i] = Digits;
- Val >>= 1;
- }
- // Special case because X=0 should return 1 and not 0
- Boundaries[0] = 0;
- Val = 10;
- for (uint64_t i = 1; i < 20; i++)
- {
- Boundaries[i] = Val;
- Val *= 10;
- }
- }
- } Data;
-
- uint64_t Base2 = X ? std::countl_zero (X) : 64;
- uint64_t Digits = Data.AtLeast[Base2];
- return Digits + (X >= Data.Boundaries[Digits]);
-}
-
-} // namespace rcc
diff --git a/libsupport/src/corelib/memory/MemAlloc.cpp b/libsupport/src/corelib/memory/MemAlloc.cpp
deleted file mode 100644
index 9413922..0000000
--- a/libsupport/src/corelib/memory/MemAlloc.cpp
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- RCC-Project
-
- Copyright (C) 2026 Richard Qin
-
- This file is part of RCC-Project.
-
- RCC-Project is free software; you can redistribute it and/or modify it under
- the terms of the GNU General Public License as published by the Free
- Software Foundation; either version 3 of the License, or (at your option) any
- later version.
-
- RCC-Project is distributed in the hope that it will be useful, but WITHOUT ANY
- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
- A PARTICULAR PURPOSE. See the GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License along with
- RCC-Project; see the file COPYING. If not see
- <http://www.gnu.org/licenses/>.
- */
-
-//===- MemAlloc.cpp - Memory allocation functions -------------------------===//
-//
-// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
-// See https://llvm.org/LICENSE.txt for license information.
-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-//
-//===----------------------------------------------------------------------===//
-
-#include "CoreLib/Memory/MemAlloc.h"
-#include <new>
-
-// These are out of line to have __cpp_aligned_new not affect ABI.
-
-RCC_ATTRIBUTE_RETURNS_NONNULL RCC_ATTRIBUTE_RETURNS_NOALIAS void *
-rcc::allocate_buffer (size_t Size, size_t Alignment)
-{
- void *Result = ::operator new (Size,
-#ifdef __cpp_aligned_new
- std::align_val_t (Alignment),
-#endif
- std::nothrow);
- if (Result == nullptr)
- {
- report_bad_alloc_error ("Buffer allocation failed");
- }
- return Result;
-}
-
-void
-rcc::deallocate_buffer (void *Ptr, size_t Size, size_t Alignment)
-{
- ::operator delete (Ptr
-#ifdef __cpp_sized_deallocation
- ,
- Size
-#endif
-#ifdef __cpp_aligned_new
- ,
- std::align_val_t (Alignment)
-#endif
- );
-}
diff --git a/libsupport/src/corelib/system/Errno.cc b/libsupport/src/corelib/system/Errno.cc
deleted file mode 100644
index 66ced94..0000000
--- a/libsupport/src/corelib/system/Errno.cc
+++ /dev/null
@@ -1,79 +0,0 @@
-/*
- RCC-Project
-
- Copyright (C) 2026 Richard Qin
-
- This file is part of RCC-Project.
-
- RCC-Project is free software; you can redistribute it and/or modify it under
- the terms of the GNU General Public License as published by the Free
- Software Foundation; either version 3 of the License, or (at your option) any
- later version.
-
- RCC-Project is distributed in the hope that it will be useful, but WITHOUT ANY
- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
- A PARTICULAR PURPOSE. See the GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License along with
- RCC-Project; see the file COPYING. If not see
- <http://www.gnu.org/licenses/>.
-*/
-
-// This implementation is based on llvm/lib/Support/Errno.cpp.
-
-#include "CoreLib/System/Errno.h"
-#include "rcc/Config/config.h"
-
-#include <cstring>
-#include <errno.h>
-
-namespace rcc
-{
-namespace sys
-{
-
-std::string
-StrError ()
-{
- return StrError (errno);
-}
-
-std::string
-StrError (int errnum)
-{
- std::string str;
- if (errnum == 0)
- {
- return str;
- }
-
-#if defined(HAVE_STRERROR_R) || HAVE_DECL_STRERROR_S
- const int maxErrStrLen = 2000;
- char buffer[maxErrStrLen];
- buffer[0] = '\0';
-#endif
-
-#ifdef HAVE_STRERROR_R
- // strerror_r is thread-safe.
-#if defined(__GLIBC__) && defined(_GNU_SOURCE)
- // glibc defines its own incompatible version of strerror_r which may not
- // use the buffer supplied.
- str = strerror_r (errnum, buffer, maxErrStrLen - 1);
-#else
- strerror_r (errnum, buffer, maxErrStrLen - 1);
- str = buffer;
-#endif
-#elif HAVE_DECL_STRERROR_S
- // Windows Secure API.
- strerror_s (buffer, maxErrStrLen - 1, errnum);
- str = buffer;
-#else
- // Copy the thread-unsafe result of strerror into the buffer as fast as
- // possible to minimize the impact of collisions in multiple threads.
- str = strerror (errnum);
-#endif
- return str;
-}
-
-} // namespace sys
-} // namespace rcc