Squashed 'externals/mcl/' content from commit a86a53843

git-subtree-dir: externals/mcl
git-subtree-split: a86a53843f82e4d6ca2f2e1437824495acad2712
This commit is contained in:
Merry 2022-04-19 16:27:52 +01:00
commit 7eb1d05f63
70 changed files with 2902 additions and 0 deletions

61
include/mcl/assert.hpp Normal file
View file

@ -0,0 +1,61 @@
// This file is part of the mcl project.
// Copyright (c) 2022 merryhime
// SPDX-License-Identifier: MIT
#pragma once
#include <stdexcept>
#include <type_traits>
#include <fmt/format.h>
#include "mcl/hint/assume.hpp"
namespace mcl::detail {
[[noreturn]] void assert_terminate_impl(fmt::string_view msg, fmt::format_args args);
template<typename... Ts>
[[noreturn]] void assert_terminate(fmt::string_view msg, Ts... args) {
assert_terminate_impl(msg, fmt::make_format_args(args...));
}
} // namespace mcl::detail
#define UNREACHABLE() ASSERT_FALSE("Unreachable code!")
#define ASSERT(expr) \
[&] { \
if (std::is_constant_evaluated()) { \
if (!(expr)) { \
throw std::logic_error{"ASSERT failed at compile time"}; \
} \
} else { \
if (!(expr)) [[unlikely]] { \
::mcl::detail::assert_terminate(#expr); \
} \
} \
}()
#define ASSERT_MSG(expr, ...) \
[&] { \
if (std::is_constant_evaluated()) { \
if (!(expr)) { \
throw std::logic_error{"ASSERT_MSG failed at compile time"}; \
} \
} else { \
if (!(expr)) [[unlikely]] { \
::mcl::detail::assert_terminate(#expr "\nMessage: " __VA_ARGS__); \
} \
} \
}()
#define ASSERT_FALSE(...) ::mcl::detail::assert_terminate("false\nMessage: " __VA_ARGS__)
#if defined(NDEBUG) || defined(MCL_IGNORE_ASSERTS)
# define DEBUG_ASSERT(expr) ASSUME(expr)
# define DEBUG_ASSERT_MSG(expr, ...) ASSUME(expr)
#else
# define DEBUG_ASSERT(expr) ASSERT(expr)
# define DEBUG_ASSERT_MSG(expr, ...) ASSERT_MSG(expr, __VA_ARGS__)
#endif

View file

@ -0,0 +1,54 @@
// This file is part of the mcl project.
// Copyright (c) 2022 merryhime
// SPDX-License-Identifier: MIT
#pragma once
#include <bitset>
#include "mcl/bitsizeof.hpp"
#include "mcl/concepts/bit_integral.hpp"
#include "mcl/stdint.hpp"
namespace mcl::bit {
template<BitIntegral T>
inline size_t count_ones(T x) {
return std::bitset<bitsizeof<T>>(x).count();
}
template<BitIntegral T>
constexpr size_t count_leading_zeros(T x) {
size_t result = bitsizeof<T>;
while (x != 0) {
x >>= 1;
result--;
}
return result;
}
template<BitIntegral T>
constexpr int highest_set_bit(T x) {
int result = -1;
while (x != 0) {
x >>= 1;
result++;
}
return result;
}
template<BitIntegral T>
constexpr size_t lowest_set_bit(T x) {
if (x == 0) {
return bitsizeof<T>;
}
size_t result = 0;
while ((x & 1) == 0) {
x >>= 1;
result++;
}
return result;
}
} // namespace mcl::bit

View file

@ -0,0 +1,203 @@
// This file is part of the mcl project.
// Copyright (c) 2022 merryhime
// SPDX-License-Identifier: MIT
#pragma once
#include "mcl/assert.hpp"
#include "mcl/bitsizeof.hpp"
#include "mcl/concepts/bit_integral.hpp"
#include "mcl/stdint.hpp"
namespace mcl::bit {
/// Create a mask with `count` number of one bits.
template<size_t count, BitIntegral T>
constexpr T ones() {
static_assert(count <= bitsizeof<T>, "count larger than bitsize of T");
if constexpr (count == 0) {
return 0;
} else {
return static_cast<T>(~static_cast<T>(0)) >> (bitsizeof<T> - count);
}
}
/// Create a mask with `count` number of one bits.
template<BitIntegral T>
constexpr T ones(size_t count) {
ASSERT_MSG(count <= bitsizeof<T>, "count larger than bitsize of T");
if (count == 0) {
return 0;
}
return ~static_cast<T>(0) >> (bitsizeof<T> - count);
}
/// Create a mask of type T for bits [begin_bit, end_bit] inclusive.
template<size_t begin_bit, size_t end_bit, BitIntegral T>
constexpr T mask() {
static_assert(begin_bit <= end_bit, "invalid bit range (position of beginning bit cannot be greater than that of end bit)");
static_assert(begin_bit < bitsizeof<T>, "begin_bit must be smaller than size of T");
static_assert(end_bit < bitsizeof<T>, "end_bit must be smaller than size of T");
return ones<end_bit - begin_bit + 1, T>() << begin_bit;
}
/// Create a mask of type T for bits [begin_bit, end_bit] inclusive.
template<BitIntegral T>
constexpr T mask(size_t begin_bit, size_t end_bit) {
ASSERT_MSG(begin_bit <= end_bit, "invalid bit range (position of beginning bit cannot be greater than that of end bit)");
ASSERT_MSG(begin_bit < bitsizeof<T>, "begin_bit must be smaller than size of T");
ASSERT_MSG(end_bit < bitsizeof<T>, "end_bit must be smaller than size of T");
return ones<T>(end_bit - begin_bit + 1) << begin_bit;
}
/// Extract bits [begin_bit, end_bit] inclusive from value of type T.
template<size_t begin_bit, size_t end_bit, BitIntegral T>
constexpr T get_bits(T value) {
constexpr T m = mask<begin_bit, end_bit, T>();
return (value & m) >> begin_bit;
}
/// Extract bits [begin_bit, end_bit] inclusive from value of type T.
template<BitIntegral T>
constexpr T get_bits(size_t begin_bit, size_t end_bit, T value) {
const T m = mask<T>(begin_bit, end_bit);
return (value & m) >> begin_bit;
}
/// Clears bits [begin_bit, end_bit] inclusive of value of type T.
template<size_t begin_bit, size_t end_bit, BitIntegral T>
constexpr T clear_bits(T value) {
constexpr T m = mask<begin_bit, end_bit, T>();
return value & ~m;
}
/// Clears bits [begin_bit, end_bit] inclusive of value of type T.
template<BitIntegral T>
constexpr T clear_bits(size_t begin_bit, size_t end_bit, T value) {
const T m = mask<T>(begin_bit, end_bit);
return value & ~m;
}
/// Modifies bits [begin_bit, end_bit] inclusive of value of type T.
template<size_t begin_bit, size_t end_bit, BitIntegral T>
constexpr T set_bits(T value, T new_bits) {
constexpr T m = mask<begin_bit, end_bit, T>();
return (value & ~m) | ((new_bits << begin_bit) & m);
}
/// Modifies bits [begin_bit, end_bit] inclusive of value of type T.
template<BitIntegral T>
constexpr T set_bits(size_t begin_bit, size_t end_bit, T value, T new_bits) {
const T m = mask<T>(begin_bit, end_bit);
return (value & ~m) | ((new_bits << begin_bit) & m);
}
/// Extract bit at bit_position from value of type T.
template<size_t bit_position, BitIntegral T>
constexpr bool get_bit(T value) {
constexpr T m = mask<bit_position, bit_position, T>();
return (value & m) != 0;
}
/// Extract bit at bit_position from value of type T.
template<BitIntegral T>
constexpr bool get_bit(size_t bit_position, T value) {
const T m = mask<T>(bit_position, bit_position);
return (value & m) != 0;
}
/// Clears bit at bit_position of value of type T.
template<size_t bit_position, BitIntegral T>
constexpr T clear_bit(T value) {
constexpr T m = mask<bit_position, bit_position, T>();
return value & ~m;
}
/// Clears bit at bit_position of value of type T.
template<BitIntegral T>
constexpr T clear_bit(size_t bit_position, T value) {
const T m = mask<T>(bit_position, bit_position);
return value & ~m;
}
/// Modifies bit at bit_position of value of type T.
template<size_t bit_position, BitIntegral T>
constexpr T set_bit(T value, bool new_bit) {
constexpr T m = mask<bit_position, bit_position, T>();
return (value & ~m) | (new_bit ? m : static_cast<T>(0));
}
/// Modifies bit at bit_position of value of type T.
template<BitIntegral T>
constexpr T set_bit(size_t bit_position, T value, bool new_bit) {
const T m = mask<T>(bit_position, bit_position);
return (value & ~m) | (new_bit ? m : static_cast<T>(0));
}
/// Sign-extends a value that has bit_count bits to the full bitwidth of type T.
template<size_t bit_count, BitIntegral T>
constexpr T sign_extend(T value) {
static_assert(bit_count != 0, "cannot sign-extend zero-sized value");
constexpr T m = ones<bit_count, T>();
if (get_bit<bit_count - 1, T>(value)) {
return value | ~m;
}
return value;
}
/// Sign-extends a value that has bit_count bits to the full bitwidth of type T.
template<BitIntegral T>
constexpr T sign_extend(size_t bit_count, T value) {
ASSERT_MSG(bit_count != 0, "cannot sign-extend zero-sized value");
const T m = ones<T>(bit_count);
if (get_bit<T>(bit_count - 1, value)) {
return value | ~m;
}
return value;
}
/// Replicate an element across a value of type T.
template<size_t element_size, BitIntegral T>
constexpr T replicate_element(T value) {
static_assert(element_size <= bitsizeof<T>, "element_size is too large");
static_assert(bitsizeof<T> % element_size == 0, "bitsize of T not divisible by element_size");
if constexpr (element_size == bitsizeof<T>) {
return value;
} else {
return replicate_element<element_size * 2, T>(static_cast<T>(value | (value << element_size)));
}
}
/// Replicate an element of type U across a value of type T.
template<BitIntegral U, BitIntegral T>
constexpr T replicate_element(T value) {
static_assert(bitsizeof<U> <= bitsizeof<T>, "element_size is too large");
return replicate_element<bitsizeof<U>, T>(value);
}
/// Replicate an element across a value of type T.
template<BitIntegral T>
constexpr T replicate_element(size_t element_size, T value) {
ASSERT_MSG(element_size <= bitsizeof<T>, "element_size is too large");
ASSERT_MSG(bitsizeof<T> % element_size == 0, "bitsize of T not divisible by element_size");
if (element_size == bitsizeof<T>) {
return value;
}
return replicate_element<T>(static_cast<T>(value | (value << element_size)), element_size * 2);
}
template<BitIntegral T>
constexpr bool most_significant_bit(T value) {
return get_bit<bitsizeof<T> - 1, T>(value);
}
} // namespace mcl::bit

View file

@ -0,0 +1,31 @@
// This file is part of the mcl project.
// Copyright (c) 2022 merryhime
// SPDX-License-Identifier: MIT
#pragma once
#include "mcl/bitsizeof.hpp"
#include "mcl/concepts/bit_integral.hpp"
#include "mcl/stdint.hpp"
namespace mcl::bit {
template<BitIntegral T>
constexpr T rotate_right(T x, size_t amount) {
amount %= bitsizeof<T>;
if (amount == 0) {
return x;
}
return static_cast<T>((x >> amount) | (x << (bitsizeof<T> - amount)));
}
template<BitIntegral T>
constexpr T rotate_left(T x, size_t amount) {
amount %= bitsizeof<T>;
if (amount == 0) {
return x;
}
return static_cast<T>((x << amount) | (x >> (bitsizeof<T> - amount)));
}
} // namespace mcl::bit

50
include/mcl/bit/swap.hpp Normal file
View file

@ -0,0 +1,50 @@
// This file is part of the mcl project.
// Copyright (c) 2022 merryhime
// SPDX-License-Identifier: MIT
#pragma once
#include "mcl/concepts/bit_integral.hpp"
namespace mcl::bit {
constexpr u16 swap_bytes_16(u16 value) {
return static_cast<u16>(u32{value} >> 8 | u32{value} << 8);
}
constexpr u32 swap_bytes_32(u32 value) {
return ((value & 0xff000000u) >> 24)
| ((value & 0x00ff0000u) >> 8)
| ((value & 0x0000ff00u) << 8)
| ((value & 0x000000ffu) << 24);
}
constexpr u64 swap_bytes_64(u64 value) {
return ((value & 0xff00000000000000ull) >> 56)
| ((value & 0x00ff000000000000ull) >> 40)
| ((value & 0x0000ff0000000000ull) >> 24)
| ((value & 0x000000ff00000000ull) >> 8)
| ((value & 0x00000000ff000000ull) << 8)
| ((value & 0x0000000000ff0000ull) << 24)
| ((value & 0x000000000000ff00ull) << 40)
| ((value & 0x00000000000000ffull) << 56);
}
constexpr u32 swap_halves_32(u32 value) {
return ((value & 0xffff0000u) >> 16)
| ((value & 0x0000ffffu) << 16);
}
constexpr u64 swap_halves_64(u64 value) {
return ((value & 0xffff000000000000ull) >> 48)
| ((value & 0x0000ffff00000000ull) >> 16)
| ((value & 0x00000000ffff0000ull) << 16)
| ((value & 0x000000000000ffffull) << 48);
}
constexpr u64 swap_words_64(u64 value) {
return ((value & 0xffffffff00000000ull) >> 32)
| ((value & 0x00000000ffffffffull) << 32);
}
} // namespace mcl::bit

36
include/mcl/bit_cast.hpp Normal file
View file

@ -0,0 +1,36 @@
// This file is part of the mcl project.
// Copyright (c) 2022 merryhime
// SPDX-License-Identifier: MIT
#pragma once
#include <cstring>
#include <type_traits>
namespace mcl {
/// Reinterpret objects of one type as another by bit-casting between object representations.
template<class Dest, class Source>
inline Dest bit_cast(const Source& source) noexcept {
static_assert(sizeof(Dest) == sizeof(Source), "size of destination and source objects must be equal");
static_assert(std::is_trivially_copyable_v<Dest>, "destination type must be trivially copyable.");
static_assert(std::is_trivially_copyable_v<Source>, "source type must be trivially copyable");
std::aligned_storage_t<sizeof(Dest), alignof(Dest)> dest;
std::memcpy(&dest, &source, sizeof(dest));
return reinterpret_cast<Dest&>(dest);
}
/// Reinterpret objects of any arbitrary type as another type by bit-casting between object representations.
/// Note that here we do not verify if source pointed to by source_ptr has enough bytes to read from.
template<class Dest, class SourcePtr>
inline Dest bit_cast_pointee(const SourcePtr source_ptr) noexcept {
static_assert(sizeof(SourcePtr) == sizeof(void*), "source pointer must have size of a pointer");
static_assert(std::is_trivially_copyable_v<Dest>, "destination type must be trivially copyable.");
std::aligned_storage_t<sizeof(Dest), alignof(Dest)> dest;
std::memcpy(&dest, bit_cast<void*>(source_ptr), sizeof(dest));
return reinterpret_cast<Dest&>(dest);
}
} // namespace mcl

15
include/mcl/bitsizeof.hpp Normal file
View file

@ -0,0 +1,15 @@
// This file is part of the mcl project.
// Copyright (c) 2022 merryhime
// SPDX-License-Identifier: MIT
#pragma once
#include <climits>
#include <cstddef>
namespace mcl {
template<typename T>
constexpr std::size_t bitsizeof = CHAR_BIT * sizeof(T);
} // namespace mcl

View file

@ -0,0 +1,16 @@
// This file is part of the mcl project.
// Copyright (c) 2022 merryhime
// SPDX-License-Identifier: MIT
#pragma once
#include "mcl/concepts/is_any_of.hpp"
#include "mcl/stdint.hpp"
namespace mcl {
/// Integral upon which bit operations can be safely performed.
template<typename T>
concept BitIntegral = IsAnyOf<T, u8, u16, u32, u64, uptr, size_t>;
} // namespace mcl

View file

@ -0,0 +1,14 @@
// This file is part of the mcl project.
// Copyright (c) 2022 merryhime
// SPDX-License-Identifier: MIT
#pragma once
#include "mcl/concepts/same_as.hpp"
namespace mcl {
template<typename T, typename... U>
concept IsAnyOf = (SameAs<T, U> || ...);
} // namespace mcl

View file

@ -0,0 +1,19 @@
// This file is part of the mcl project.
// Copyright (c) 2022 merryhime
// SPDX-License-Identifier: MIT
#pragma once
namespace mcl {
namespace detail {
template<typename T, typename U>
concept SameHelper = std::is_same_v<T, U>;
} // namespace detail
template<typename T, typename U>
concept SameAs = detail::SameHelper<T, U> && detail::SameHelper<U, T>;
} // namespace mcl

View file

@ -0,0 +1,378 @@
// This file is part of the mcl project.
// Copyright (c) 2022 merryhime
// SPDX-License-Identifier: MIT
#pragma once
#include <cstddef>
#include <iterator>
#include <memory>
#include <type_traits>
#include "mcl/assert.hpp"
namespace mcl {
template<typename T>
class intrusive_list;
template<typename T>
class intrusive_list_iterator;
template<typename T>
class intrusive_list_node {
public:
bool is_sentinel() const {
return is_sentinel_;
}
protected:
intrusive_list_node* next = nullptr;
intrusive_list_node* prev = nullptr;
bool is_sentinel_ = false;
friend class intrusive_list<T>;
friend class intrusive_list_iterator<T>;
friend class intrusive_list_iterator<const T>;
};
template<typename T>
class intrusive_list_sentinel final : public intrusive_list_node<T> {
using intrusive_list_node<T>::next;
using intrusive_list_node<T>::prev;
using intrusive_list_node<T>::is_sentinel_;
public:
intrusive_list_sentinel() {
next = this;
prev = this;
is_sentinel_ = true;
}
};
template<typename T>
class intrusive_list_iterator {
public:
using iterator_category = std::bidirectional_iterator_tag;
using difference_type = std::ptrdiff_t;
using value_type = T;
using pointer = value_type*;
using const_pointer = const value_type*;
using reference = value_type&;
using const_reference = const value_type&;
// If value_type is const, we want "const intrusive_list_node<value_type>", not "intrusive_list_node<const value_type>"
using node_type = std::conditional_t<std::is_const<value_type>::value,
const intrusive_list_node<std::remove_const_t<value_type>>,
intrusive_list_node<value_type>>;
using node_pointer = node_type*;
using node_reference = node_type&;
intrusive_list_iterator() = default;
intrusive_list_iterator(const intrusive_list_iterator& other) = default;
intrusive_list_iterator& operator=(const intrusive_list_iterator& other) = default;
explicit intrusive_list_iterator(node_pointer list_node)
: node(list_node) {
}
explicit intrusive_list_iterator(pointer data)
: node(data) {
}
explicit intrusive_list_iterator(reference data)
: node(&data) {
}
intrusive_list_iterator& operator++() {
node = node->next;
return *this;
}
intrusive_list_iterator& operator--() {
node = node->prev;
return *this;
}
intrusive_list_iterator operator++(int) {
intrusive_list_iterator it(*this);
++*this;
return it;
}
intrusive_list_iterator operator--(int) {
intrusive_list_iterator it(*this);
--*this;
return it;
}
bool operator==(const intrusive_list_iterator& other) const {
return node == other.node;
}
bool operator!=(const intrusive_list_iterator& other) const {
return !operator==(other);
}
reference operator*() const {
DEBUG_ASSERT(!node->is_sentinel());
return static_cast<reference>(*node);
}
pointer operator->() const {
return std::addressof(operator*());
}
node_pointer AsNodePointer() const {
return node;
}
private:
friend class intrusive_list<T>;
node_pointer node = nullptr;
};
template<typename T>
class intrusive_list {
public:
using difference_type = std::ptrdiff_t;
using size_type = std::size_t;
using value_type = T;
using pointer = value_type*;
using const_pointer = const value_type*;
using reference = value_type&;
using const_reference = const value_type&;
using iterator = intrusive_list_iterator<value_type>;
using const_iterator = intrusive_list_iterator<const value_type>;
using reverse_iterator = std::reverse_iterator<iterator>;
using const_reverse_iterator = std::reverse_iterator<const_iterator>;
/**
* Inserts a node at the given location indicated by an iterator.
*
* @param location The location to insert the node.
* @param new_node The node to add.
*/
iterator insert(iterator location, pointer new_node) {
return insert_before(location, new_node);
}
/**
* Inserts a node at the given location, moving the previous
* node occupant ahead of the one inserted.
*
* @param location The location to insert the new node.
* @param new_node The node to insert into the list.
*/
iterator insert_before(iterator location, pointer new_node) {
auto existing_node = location.AsNodePointer();
new_node->next = existing_node;
new_node->prev = existing_node->prev;
existing_node->prev->next = new_node;
existing_node->prev = new_node;
return iterator(new_node);
}
/**
* Inserts a new node into the list ahead of the position indicated.
*
* @param position Location to insert the node in front of.
* @param new_node The node to be inserted into the list.
*/
iterator insert_after(iterator position, pointer new_node) {
if (empty())
return insert(begin(), new_node);
return insert(++position, new_node);
}
/**
* Add an entry to the start of the list.
* @param node Node to add to the list.
*/
void push_front(pointer node) {
insert(begin(), node);
}
/**
* Add an entry to the end of the list
* @param node Node to add to the list.
*/
void push_back(pointer node) {
insert(end(), node);
}
/**
* Erases the node at the front of the list.
* @note Must not be called on an empty list.
*/
void pop_front() {
DEBUG_ASSERT(!empty());
erase(begin());
}
/**
* Erases the node at the back of the list.
* @note Must not be called on an empty list.
*/
void pop_back() {
DEBUG_ASSERT(!empty());
erase(--end());
}
/**
* Removes a node from this list
* @param it An iterator that points to the node to remove from list.
*/
pointer remove(iterator& it) {
DEBUG_ASSERT(it != end());
pointer node = &*it++;
node->prev->next = node->next;
node->next->prev = node->prev;
#if !defined(NDEBUG)
node->next = nullptr;
node->prev = nullptr;
#endif
return node;
}
/**
* Removes a node from this list
* @param it A constant iterator that points to the node to remove from list.
*/
pointer remove(const iterator& it) {
iterator copy = it;
return remove(copy);
}
/**
* Removes a node from this list.
* @param node A pointer to the node to remove.
*/
pointer remove(pointer node) {
return remove(iterator(node));
}
/**
* Removes a node from this list.
* @param node A reference to the node to remove.
*/
pointer remove(reference node) {
return remove(iterator(node));
}
/**
* Is this list empty?
* @returns true if there are no nodes in this list.
*/
bool empty() const {
return root->next == root.get();
}
/**
* Gets the total number of elements within this list.
* @return the number of elements in this list.
*/
size_type size() const {
return static_cast<size_type>(std::distance(begin(), end()));
}
/**
* Retrieves a reference to the node at the front of the list.
* @note Must not be called on an empty list.
*/
reference front() {
DEBUG_ASSERT(!empty());
return *begin();
}
/**
* Retrieves a constant reference to the node at the front of the list.
* @note Must not be called on an empty list.
*/
const_reference front() const {
DEBUG_ASSERT(!empty());
return *begin();
}
/**
* Retrieves a reference to the node at the back of the list.
* @note Must not be called on an empty list.
*/
reference back() {
DEBUG_ASSERT(!empty());
return *--end();
}
/**
* Retrieves a constant reference to the node at the back of the list.
* @note Must not be called on an empty list.
*/
const_reference back() const {
DEBUG_ASSERT(!empty());
return *--end();
}
// Iterator interface
iterator begin() { return iterator(root->next); }
const_iterator begin() const { return const_iterator(root->next); }
const_iterator cbegin() const { return begin(); }
iterator end() { return iterator(root.get()); }
const_iterator end() const { return const_iterator(root.get()); }
const_iterator cend() const { return end(); }
reverse_iterator rbegin() { return reverse_iterator(end()); }
const_reverse_iterator rbegin() const { return const_reverse_iterator(end()); }
const_reverse_iterator crbegin() const { return rbegin(); }
reverse_iterator rend() { return reverse_iterator(begin()); }
const_reverse_iterator rend() const { return const_reverse_iterator(begin()); }
const_reverse_iterator crend() const { return rend(); }
/**
* Erases a node from the list, indicated by an iterator.
* @param it The iterator that points to the node to erase.
*/
iterator erase(iterator it) {
remove(it);
return it;
}
/**
* Erases a node from this list.
* @param node A pointer to the node to erase from this list.
*/
iterator erase(pointer node) {
return erase(iterator(node));
}
/**
* Erases a node from this list.
* @param node A reference to the node to erase from this list.
*/
iterator erase(reference node) {
return erase(iterator(node));
}
/**
* Exchanges contents of this list with another list instance.
* @param other The other list to swap with.
*/
void swap(intrusive_list& other) noexcept {
root.swap(other.root);
}
private:
std::shared_ptr<intrusive_list_node<T>> root = std::make_shared<intrusive_list_sentinel<T>>();
};
/**
* Exchanges contents of an intrusive list with another intrusive list.
* @tparam T The type of data being kept track of by the lists.
* @param lhs The first list.
* @param rhs The second list.
*/
template<typename T>
void swap(intrusive_list<T>& lhs, intrusive_list<T>& rhs) noexcept {
lhs.swap(rhs);
}
} // namespace mcl

View file

@ -0,0 +1,13 @@
// This file is part of the mcl project.
// Copyright (c) 2022 merryhime
// SPDX-License-Identifier: MIT
#pragma once
#if defined(__clang) || defined(__GNUC__)
# define ASSUME(expr) [&] { if (!(expr)) __builtin_unreachable(); }()
#elif defined(_MSC_VER)
# define ASSUME(expr) __assume(expr)
#else
# define ASSUME(expr)
#endif

View file

@ -0,0 +1,34 @@
// This file is part of the mcl project.
// Copyright (c) 2022 merryhime
// SPDX-License-Identifier: MIT
#pragma once
#include <iterator>
namespace mcl::iterator {
namespace detail {
template<typename T>
struct reverse_adapter {
T& iterable;
constexpr auto begin() {
using namespace std;
return rbegin(iterable);
}
constexpr auto end() {
using namespace std;
return rend(iterable);
}
};
} // namespace detail
template<typename T>
constexpr detail::reverse_adapter<T> reverse(T&& iterable) {
return detail::reverse_adapter<T>{iterable};
}
} // namespace mcl::iterator

View file

@ -0,0 +1,13 @@
// This file is part of the mcl project.
// Copyright (c) 2022 merryhime
// SPDX-License-Identifier: MIT
#pragma once
#include <mcl/macro/concatenate_tokens.hpp>
#ifdef __COUNTER__
# define ANONYMOUS_VARIABLE(str) CONCATENATE_TOKENS(str, __COUNTER__)
#else
# define ANONYMOUS_VARIABLE(str) CONCATENATE_TOKENS(str, __LINE__)
#endif

View file

@ -0,0 +1,40 @@
// This file is part of the mcl project.
// Copyright (c) 2022 merryhime
// SPDX-License-Identifier: MIT
#pragma once
#if defined(__ARM64__) || defined(__aarch64__) || defined(_M_ARM64)
# define MCL_ARCHITECTURE arm64
# define MCL_ARCHITECTURE_ARM64 1
#elif defined(__arm__) || defined(__TARGET_ARCH_ARM) || defined(_M_ARM)
# define MCL_ARCHITECTURE arm32
# define MCL_ARCHITECTURE_ARM32 1
#elif defined(__x86_64) || defined(__x86_64__) || defined(__amd64) || defined(_M_X64)
# define MCL_ARCHITECTURE x86_64
# define MCL_ARCHITECTURE_X86_64 1
#elif defined(__i386) || defined(__i386__) || defined(_M_IX86)
# define MCL_ARCHITECTURE x86_32
# define MCL_ARCHITECTURE_X86_32 1
#elif defined(__ia64) || defined(__ia64__) || defined(_M_IA64)
# define MCL_ARCHITECTURE ia64
# define MCL_ARCHITECTURE_IA64 1
#elif defined(__mips) || defined(__mips__) || defined(_M_MRX000)
# define MCL_ARCHITECTURE mips
# define MCL_ARCHITECTURE_MIPS 1
#elif defined(__ppc64__) || defined(__powerpc64__)
# define MCL_ARCHITECTURE ppc64
# define MCL_ARCHITECTURE_PPC64 1
#elif defined(__ppc__) || defined(__ppc) || defined(__powerpc__) || defined(_ARCH_COM) || defined(_ARCH_PWR) || defined(_ARCH_PPC) || defined(_M_MPPC) || defined(_M_PPC)
# define MCL_ARCHITECTURE ppc32
# define MCL_ARCHITECTURE_PPC32 1
#elif defined(__riscv)
# define MCL_ARCHITECTURE riscv
# define MCL_ARCHITECTURE_RISCV 1
#elif defined(__EMSCRIPTEN__)
# define MCL_ARCHITECTURE wasm
# define MCL_ARCHITECTURE_WASM 1
#else
# define MCL_ARCHITECTURE generic
# define MCL_ARCHITECTURE_GENERIC 1
#endif

View file

@ -0,0 +1,8 @@
// This file is part of the mcl project.
// Copyright (c) 2022 merryhime
// SPDX-License-Identifier: MIT
#pragma once
#define CONCATENATE_TOKENS(x, y) CONCATENATE_TOKENS_IMPL(x, y)
#define CONCATENATE_TOKENS_IMPL(x, y) x##y

View file

@ -0,0 +1,25 @@
// This file is part of the mcl project.
// Copyright (c) 2022 merryhime
// SPDX-License-Identifier: MIT
#pragma once
namespace mcl::mp {
namespace detail {
template<template<class...> class F, class L>
struct apply_impl;
template<template<class...> class F, template<class...> class LT, class... Es>
struct apply_impl<F, LT<Es...>> {
using type = F<Es...>;
};
} // namespace detail
/// Invokes metafunction F where the arguments are all the members of list L
template<template<class...> class F, class L>
using apply = typename detail::apply_impl<F, L>::type;
} // namespace mcl::mp

View file

@ -0,0 +1,18 @@
// This file is part of the mcl project.
// Copyright (c) 2022 merryhime
// SPDX-License-Identifier: MIT
#pragma once
namespace mcl::mp {
/// Binds the first sizeof...(A) arguments of metafunction F with arguments A
template<template<class...> class F, class... As>
struct bind {
template<class... Rs>
using type = F<As..., Rs...>;
};
} // namespace mcl::mp
#define MCL_MP_BIND(...) ::mcl::mp::bind<__VA_ARGS__>::template type

View file

@ -0,0 +1,22 @@
// This file is part of the mcl project.
// Copyright (c) 2022 merryhime
// SPDX-License-Identifier: MIT
#pragma once
namespace mcl::mp {
namespace detail {
template<class T>
struct identity_impl {
using type = T;
};
} // namespace detail
/// Identity metafunction
template<class T>
using identity = typename identity_impl<T>::type;
} // namespace mcl::mp

View file

@ -0,0 +1,25 @@
// This file is part of the mcl project.
// Copyright (c) 2022 merryhime
// SPDX-License-Identifier: MIT
#pragma once
namespace mcl::mp {
namespace detail {
template<template<class...> class F, class L>
struct map_impl;
template<template<class...> class F, template<class...> class LT, class... Es>
struct map_impl<F, LT<Es...>> {
using type = LT<F<Es>...>;
};
} // namespace detail
/// Applies each element of list L to metafunction F
template<template<class...> class F, class L>
using map = typename detail::map_impl<F, L>::type;
} // namespace mcl::mp

View file

@ -0,0 +1,19 @@
// This file is part of the mcl project.
// Copyright (c) 2022 merryhime
// SPDX-License-Identifier: MIT
#pragma once
#include "mcl/mp/metavalue/lift_value.hpp"
namespace mcl::mp {
/// Bitwise and of metavalues Vs
template<class... Vs>
using bit_and = lift_value<(Vs::value & ...)>;
/// Bitwise and of metavalues Vs
template<class... Vs>
constexpr auto bit_and_v = (Vs::value & ...);
} // namespace mcl::mp

View file

@ -0,0 +1,19 @@
// This file is part of the mcl project.
// Copyright (c) 2022 merryhime
// SPDX-License-Identifier: MIT
#pragma once
#include "mcl/mp/metavalue/lift_value.hpp"
namespace mcl::mp {
/// Bitwise not of metavalue V
template<class V>
using bit_not = lift_value<~V::value>;
/// Bitwise not of metavalue V
template<class V>
constexpr auto bit_not_v = ~V::value;
} // namespace mcl::mp

View file

@ -0,0 +1,19 @@
// This file is part of the mcl project.
// Copyright (c) 2022 merryhime
// SPDX-License-Identifier: MIT
#pragma once
#include "mcl/mp/metavalue/lift_value.hpp"
namespace mcl::mp {
/// Bitwise or of metavalues Vs
template<class... Vs>
using bit_or = lift_value<(Vs::value | ...)>;
/// Bitwise or of metavalues Vs
template<class... Vs>
constexpr auto bit_or_v = (Vs::value | ...);
} // namespace mcl::mp

View file

@ -0,0 +1,19 @@
// This file is part of the mcl project.
// Copyright (c) 2022 merryhime
// SPDX-License-Identifier: MIT
#pragma once
#include "mcl/mp/metavalue/lift_value.hpp"
namespace mcl::mp {
/// Bitwise xor of metavalues Vs
template<class... Vs>
using bit_xor = lift_value<(Vs::value ^ ...)>;
/// Bitwise xor of metavalues Vs
template<class... Vs>
constexpr auto bit_xor_v = (Vs::value ^ ...);
} // namespace mcl::mp

View file

@ -0,0 +1,42 @@
// This file is part of the mcl project.
// Copyright (c) 2022 merryhime
// SPDX-License-Identifier: MIT
#pragma once
#include "mcl/mp/metavalue/logic_if.hpp"
#include "mcl/mp/metavalue/value.hpp"
namespace mcl::mp {
namespace detail {
template<class...>
struct conjunction_impl;
template<>
struct conjunction_impl<> {
using type = false_type;
};
template<class V>
struct conjunction_impl<V> {
using type = V;
};
template<class V1, class... Vs>
struct conjunction_impl<V1, Vs...> {
using type = logic_if<V1, typename conjunction_impl<Vs...>::type, V1>;
};
} // namespace detail
/// Conjunction of metavalues Vs with short-circuiting and type preservation.
template<class... Vs>
using conjunction = typename detail::conjunction_impl<Vs...>::type;
/// Conjunction of metavalues Vs with short-circuiting and type preservation.
template<class... Vs>
constexpr auto conjunction_v = conjunction<Vs...>::value;
} // namespace mcl::mp

View file

@ -0,0 +1,42 @@
// This file is part of the mcl project.
// Copyright (c) 2022 merryhime
// SPDX-License-Identifier: MIT
#pragma once
#include "mcl/mp/metavalue/logic_if.hpp"
#include "mcl/mp/metavalue/value.hpp"
namespace mcl::mp {
namespace detail {
template<class...>
struct disjunction_impl;
template<>
struct disjunction_impl<> {
using type = false_type;
};
template<class V>
struct disjunction_impl<V> {
using type = V;
};
template<class V1, class... Vs>
struct disjunction_impl<V1, Vs...> {
using type = logic_if<V1, V1, typename disjunction_impl<Vs...>::type>;
};
} // namespace detail
/// Disjunction of metavalues Vs with short-circuiting and type preservation.
template<class... Vs>
using disjunction = typename detail::disjunction_impl<Vs...>::type;
/// Disjunction of metavalues Vs with short-circuiting and type preservation.
template<class... Vs>
constexpr auto disjunction_v = disjunction<Vs...>::value;
} // namespace mcl::mp

View file

@ -0,0 +1,15 @@
// This file is part of the mcl project.
// Copyright (c) 2022 merryhime
// SPDX-License-Identifier: MIT
#pragma once
#include <type_traits>
namespace mcl::mp {
/// Lifts a value into a type (a metavalue)
template<auto V>
using lift_value = std::integral_constant<decltype(V), V>;
} // namespace mcl::mp

View file

@ -0,0 +1,19 @@
// This file is part of the mcl project.
// Copyright (c) 2022 merryhime
// SPDX-License-Identifier: MIT
#pragma once
#include "mcl/mp/metavalue/value.hpp"
namespace mcl::mp {
/// Logical conjunction of metavalues Vs without short-circuiting or type presevation.
template<class... Vs>
using logic_and = bool_value<(true && ... && Vs::value)>;
/// Logical conjunction of metavalues Vs without short-circuiting or type presevation.
template<class... Vs>
constexpr bool logic_and_v = (true && ... && Vs::value);
} // namespace mcl::mp

View file

@ -0,0 +1,21 @@
// This file is part of the mcl project.
// Copyright (c) 2022 merryhime
// SPDX-License-Identifier: MIT
#pragma once
#include <type_traits>
#include "mcl/mp/metavalue/value.hpp"
namespace mcl::mp {
/// Conditionally select between types T and F based on boolean metavalue V
template<class V, class T, class F>
using logic_if = std::conditional_t<bool(V::value), T, F>;
/// Conditionally select between metavalues T and F based on boolean metavalue V
template<class V, class TV, class FV>
constexpr auto logic_if_v = logic_if<V, TV, FV>::value;
} // namespace mcl::mp

View file

@ -0,0 +1,19 @@
// This file is part of the mcl project.
// Copyright (c) 2022 merryhime
// SPDX-License-Identifier: MIT
#pragma once
#include "mcl/mp/metavalue/value.hpp"
namespace mcl::mp {
/// Logical negation of metavalue V.
template<class V>
using logic_not = bool_value<!bool(V::value)>;
/// Logical negation of metavalue V.
template<class V>
constexpr bool logic_not_v = !bool(V::value);
} // namespace mcl::mp

View file

@ -0,0 +1,19 @@
// This file is part of the mcl project.
// Copyright (c) 2022 merryhime
// SPDX-License-Identifier: MIT
#pragma once
#include "mcl/mp/metavalue/value.hpp"
namespace mcl::mp {
/// Logical disjunction of metavalues Vs without short-circuiting or type presevation.
template<class... Vs>
using logic_or = bool_value<(false || ... || Vs::value)>;
/// Logical disjunction of metavalues Vs without short-circuiting or type presevation.
template<class... Vs>
constexpr bool logic_or_v = (false || ... || Vs::value);
} // namespace mcl::mp

View file

@ -0,0 +1,19 @@
// This file is part of the mcl project.
// Copyright (c) 2022 merryhime
// SPDX-License-Identifier: MIT
#pragma once
#include "mcl/mp/metavalue/lift_value.hpp"
namespace mcl::mp {
/// Product of metavalues Vs
template<class... Vs>
using product = lift_value<(Vs::value * ...)>;
/// Product of metavalues Vs
template<class... Vs>
constexpr auto product_v = (Vs::value * ...);
} // namespace mcl::mp

View file

@ -0,0 +1,19 @@
// This file is part of the mcl project.
// Copyright (c) 2022 merryhime
// SPDX-License-Identifier: MIT
#pragma once
#include "mcl/mp/metavalue/lift_value.hpp"
namespace mcl::mp {
/// Sum of metavalues Vs
template<class... Vs>
using sum = lift_value<(Vs::value + ...)>;
/// Sum of metavalues Vs
template<class... Vs>
constexpr auto sum_v = (Vs::value + ...);
} // namespace mcl::mp

View file

@ -0,0 +1,30 @@
// This file is part of the mcl project.
// Copyright (c) 2022 merryhime
// SPDX-License-Identifier: MIT
#pragma once
#include <cstddef>
#include <type_traits>
namespace mcl::mp {
/// A metavalue (of type VT and value v).
template<class VT, VT v>
using value = std::integral_constant<VT, v>;
/// A metavalue of type size_t (and value v).
template<size_t v>
using size_value = value<size_t, v>;
/// A metavalue of type bool (and value v). (Aliases to std::bool_constant.)
template<bool v>
using bool_value = value<bool, v>;
/// true metavalue (Aliases to std::true_type).
using true_type = bool_value<true>;
/// false metavalue (Aliases to std::false_type).
using false_type = bool_value<false>;
} // namespace mcl::mp

View file

@ -0,0 +1,15 @@
// This file is part of the mcl project.
// Copyright (c) 2022 merryhime
// SPDX-License-Identifier: MIT
#pragma once
#include <type_traits>
namespace mcl::mp {
/// Casts a metavalue from one type to another
template<class T, class V>
using value_cast = std::integral_constant<T, static_cast<T>(V::value)>;
} // namespace mcl::mp

View file

@ -0,0 +1,15 @@
// This file is part of the mcl project.
// Copyright (c) 2022 merryhime
// SPDX-License-Identifier: MIT
#pragma once
#include <type_traits>
namespace mcl::mp {
/// Do two metavalues contain the same value?
template<class V1, class V2>
using value_equal = std::bool_constant<V1::value == V2::value>;
} // namespace mcl::mp

View file

@ -0,0 +1,19 @@
// This file is part of the mcl project.
// Copyright (c) 2022 merryhime
// SPDX-License-Identifier: MIT
#pragma once
#include "mcl/mp/metavalue/lift_value.hpp"
namespace mcl::mp {
/// Metafunction that returns the number of arguments it has
template<typename... Ts>
using argument_count = lift_value<sizeof...(Ts)>;
/// Metafunction that returns the number of arguments it has
template<typename... Ts>
constexpr auto argument_count_v = sizeof...(Ts);
} // namespace mcl::mp

View file

@ -0,0 +1,25 @@
// This file is part of the mcl project.
// Copyright (c) 2022 merryhime
// SPDX-License-Identifier: MIT
#pragma once
namespace mcl::mp {
namespace detail {
template<class... L>
struct append_impl;
template<template<class...> class LT, class... E1s, class... E2s>
struct append_impl<LT<E1s...>, E2s...> {
using type = LT<E1s..., E2s...>;
};
} // namespace detail
/// Append items E to list L
template<class L, class... Es>
using append = typename detail::append_impl<L, Es...>::type;
} // namespace mcl::mp

View file

@ -0,0 +1,47 @@
// This file is part of the mcl project.
// Copyright (c) 2022 merryhime
// SPDX-License-Identifier: MIT
#pragma once
#include "mcl/mp/metafunction/bind.hpp"
#include "mcl/mp/metafunction/map.hpp"
#include "mcl/mp/typelist/append.hpp"
#include "mcl/mp/typelist/concat.hpp"
#include "mcl/mp/typelist/list.hpp"
namespace mcl::mp {
namespace detail {
template<class... Ls>
struct cartesian_product_impl;
template<class RL>
struct cartesian_product_impl<RL> {
using type = RL;
};
template<template<class...> class LT, class... REs, class... E2s>
struct cartesian_product_impl<LT<REs...>, LT<E2s...>> {
using type = concat<
map<MCL_MP_BIND(append, REs), list<E2s...>>...>;
};
template<class RL, class L2, class L3, class... Ls>
struct cartesian_product_impl<RL, L2, L3, Ls...> {
using type = typename cartesian_product_impl<
typename cartesian_product_impl<RL, L2>::type,
L3,
Ls...>::type;
};
} // namespace detail
/// Produces the cartesian product of a set of lists
/// For example:
/// cartesian_product<list<A, B>, list<D, E>> == list<list<A, D>, list<A, E>, list<B, D>, list<B, E>
template<typename L1, typename... Ls>
using cartesian_product = typename detail::cartesian_product_impl<map<list, L1>, Ls...>::type;
} // namespace mcl::mp

View file

@ -0,0 +1,94 @@
// This file is part of the mcl project.
// Copyright (c) 2022 merryhime
// SPDX-License-Identifier: MIT
#pragma once
#include "mcl/mp/typelist/list.hpp"
namespace mcl::mp {
namespace detail {
template<class... Ls>
struct concat_impl;
template<>
struct concat_impl<> {
using type = list<>;
};
template<class L>
struct concat_impl<L> {
using type = L;
};
template<template<class...> class LT, class... E1s, class... E2s, class... Ls>
struct concat_impl<LT<E1s...>, LT<E2s...>, Ls...> {
using type = typename concat_impl<LT<E1s..., E2s...>, Ls...>::type;
};
template<template<class...> class LT,
class... E1s,
class... E2s,
class... E3s,
class... E4s,
class... E5s,
class... E6s,
class... E7s,
class... E8s,
class... E9s,
class... E10s,
class... E11s,
class... E12s,
class... E13s,
class... E14s,
class... E15s,
class... E16s,
class... Ls>
struct concat_impl<
LT<E1s...>,
LT<E2s...>,
LT<E3s...>,
LT<E4s...>,
LT<E5s...>,
LT<E6s...>,
LT<E7s...>,
LT<E8s...>,
LT<E9s...>,
LT<E10s...>,
LT<E11s...>,
LT<E12s...>,
LT<E13s...>,
LT<E14s...>,
LT<E15s...>,
LT<E16s...>,
Ls...> {
using type = typename concat_impl<
LT<
E1s...,
E2s...,
E3s...,
E4s...,
E5s...,
E6s...,
E7s...,
E8s...,
E9s...,
E10s...,
E11s...,
E12s...,
E13s...,
E14s...,
E15s...,
E16s...>,
Ls...>::type;
};
} // namespace detail
/// Concatenate lists together
template<class... Ls>
using concat = typename detail::concat_impl<Ls...>::type;
} // namespace mcl::mp

View file

@ -0,0 +1,23 @@
// This file is part of the mcl project.
// Copyright (c) 2022 merryhime
// SPDX-License-Identifier: MIT
#pragma once
#include "mcl/mp/metavalue/value.hpp"
namespace mcl::mp {
/// Does list L contain an element which is same as type T?
template<class L, class T>
struct contains;
template<template<class...> class LT, class... Ts, class T>
struct contains<LT<Ts...>, T>
: bool_value<(false || ... || std::is_same_v<Ts, T>)> {};
/// Does list L contain an element which is same as type T?
template<class L, class T>
constexpr bool contains_v = contains<L, T>::value;
} // namespace mcl::mp

View file

@ -0,0 +1,33 @@
// This file is part of the mcl project.
// Copyright (c) 2022 merryhime
// SPDX-License-Identifier: MIT
#pragma once
#include <cstddef>
#include <type_traits>
namespace mcl::mp {
namespace detail {
template<size_t N, class L>
struct drop_impl;
template<size_t N, template<class...> class LT>
struct drop_impl<N, LT<>> {
using type = LT<>;
};
template<size_t N, template<class...> class LT, class E1, class... Es>
struct drop_impl<N, LT<E1, Es...>> {
using type = std::conditional_t<N == 0, LT<E1, Es...>, typename drop_impl<N - 1, LT<Es...>>::type>;
};
} // namespace detail
/// Drops the first N elements of list L
template<std::size_t N, class L>
using drop = typename detail::drop_impl<N, L>::type;
} // namespace mcl::mp

View file

@ -0,0 +1,18 @@
// This file is part of the mcl project.
// Copyright (c) 2022 merryhime
// SPDX-License-Identifier: MIT
#pragma once
#include <cstddef>
#include <tuple>
#include "mcl/mp/metafunction/apply.hpp"
namespace mcl::mp {
/// Get element I from list L
template<std::size_t I, class L>
using get = std::tuple_element_t<I, apply<std::tuple, L>>;
} // namespace mcl::mp

View file

@ -0,0 +1,25 @@
// This file is part of the mcl project.
// Copyright (c) 2022 merryhime
// SPDX-License-Identifier: MIT
#pragma once
namespace mcl::mp {
namespace detail {
template<class L>
struct head_impl;
template<template<class...> class LT, class E1, class... Es>
struct head_impl<LT<E1, Es...>> {
using type = E1;
};
} // namespace detail
/// Gets the tail/cdr/all-but-the-first-element of list L
template<class L>
using head = typename detail::head_impl<L>::type;
} // namespace mcl::mp

View file

@ -0,0 +1,20 @@
// This file is part of the mcl project.
// Copyright (c) 2022 merryhime
// SPDX-License-Identifier: MIT
#pragma once
#include "mcl/mp/metafunction/apply.hpp"
#include "mcl/mp/misc/argument_count.hpp"
namespace mcl::mp {
/// Length of list L
template<class L>
using length = apply<argument_count, L>;
/// Length of list L
template<class L>
constexpr auto length_v = length<L>::value;
} // namespace mcl::mp

View file

@ -0,0 +1,29 @@
// This file is part of the mcl project.
// Copyright (c) 2022 merryhime
// SPDX-License-Identifier: MIT
#pragma once
#include <type_traits>
#include "mcl/mp/typelist/list.hpp"
namespace mcl::mp {
namespace detail {
template<class VL>
struct lift_sequence_impl;
template<class T, template<class, T...> class VLT, T... values>
struct lift_sequence_impl<VLT<T, values...>> {
using type = list<std::integral_constant<T, values>...>;
};
} // namespace detail
/// Lifts values in value list VL to create a type list.
template<class VL>
using lift_sequence = typename detail::lift_sequence_impl<VL>::type;
} // namespace mcl::mp

View file

@ -0,0 +1,13 @@
// This file is part of the mcl project.
// Copyright (c) 2022 merryhime
// SPDX-License-Identifier: MIT
#pragma once
namespace mcl::mp {
/// Contains a list of types
template<class... E>
struct list {};
} // namespace mcl::mp

View file

@ -0,0 +1,24 @@
// This file is part of the mcl project.
// Copyright (c) 2022 merryhime
// SPDX-License-Identifier: MIT
#pragma once
#include <tuple>
namespace mcl::mp {
/// Converts a list of metavalues to a tuple.
template<class L>
struct lower_to_tuple;
template<template<class...> class LT, class... Es>
struct lower_to_tuple<LT<Es...>> {
static constexpr auto value = std::make_tuple(static_cast<typename Es::value_type>(Es::value)...);
};
/// Converts a list of metavalues to a tuple.
template<class L>
constexpr auto lower_to_tuple_v = lower_to_tuple<L>::value;
} // namespace mcl::mp

View file

@ -0,0 +1,25 @@
// This file is part of the mcl project.
// Copyright (c) 2022 merryhime
// SPDX-License-Identifier: MIT
#pragma once
namespace mcl::mp {
namespace detail {
template<class... L>
struct prepend_impl;
template<template<class...> class LT, class... E1s, class... E2s>
struct prepend_impl<LT<E1s...>, E2s...> {
using type = LT<E2s..., E1s...>;
};
} // namespace detail
/// Prepend items E to list L
template<class L, class... Es>
using prepend = typename detail::prepend_impl<L, Es...>::type;
} // namespace mcl::mp

View file

@ -0,0 +1,25 @@
// This file is part of the mcl project.
// Copyright (c) 2022 merryhime
// SPDX-License-Identifier: MIT
#pragma once
namespace mcl::mp {
namespace detail {
template<class L>
struct tail_impl;
template<template<class...> class LT, class E1, class... Es>
struct tail_impl<LT<E1, Es...>> {
using type = LT<Es...>;
};
} // namespace detail
/// Gets the first type of list L
template<class L>
using tail = typename detail::tail_impl<L>::type;
} // namespace mcl::mp

View file

@ -0,0 +1,85 @@
// This file is part of the mcl project.
// Copyright (c) 2022 merryhime
// SPDX-License-Identifier: MIT
#pragma once
#include <exception>
#include <type_traits>
#include <utility>
#include <mcl/macro/anonymous_variable.hpp>
namespace mcl::detail {
struct scope_exit_tag {};
struct scope_fail_tag {};
struct scope_success_tag {};
template<typename Function>
class scope_exit final {
public:
explicit scope_exit(Function&& fn)
: function(std::move(fn)) {}
~scope_exit() noexcept {
function();
}
private:
Function function;
};
template<typename Function>
class scope_fail final {
public:
explicit scope_fail(Function&& fn)
: function(std::move(fn)), exception_count(std::uncaught_exceptions()) {}
~scope_fail() noexcept {
if (std::uncaught_exceptions() > exception_count) {
function();
}
}
private:
Function function;
int exception_count;
};
template<typename Function>
class scope_success final {
public:
explicit scope_success(Function&& fn)
: function(std::move(fn)), exception_count(std::uncaught_exceptions()) {}
~scope_success() {
if (std::uncaught_exceptions() <= exception_count) {
function();
}
}
private:
Function function;
int exception_count;
};
// We use ->* here as it has the highest precedence of the operators we can use.
template<typename Function>
auto operator->*(scope_exit_tag, Function&& function) {
return scope_exit<std::decay_t<Function>>{std::forward<Function>(function)};
}
template<typename Function>
auto operator->*(scope_fail_tag, Function&& function) {
return scope_fail<std::decay_t<Function>>{std::forward<Function>(function)};
}
template<typename Function>
auto operator->*(scope_success_tag, Function&& function) {
return scope_success<std::decay_t<Function>>{std::forward<Function>(function)};
}
} // namespace mcl::detail
#define SCOPE_EXIT auto ANONYMOUS_VARIABLE(MCL_SCOPE_EXIT_VAR_) = ::mcl::detail::scope_exit_tag{}->*[&]() noexcept
#define SCOPE_FAIL auto ANONYMOUS_VARIABLE(MCL_SCOPE_FAIL_VAR_) = ::mcl::detail::scope_fail_tag{}->*[&]() noexcept
#define SCOPE_SUCCESS auto ANONYMOUS_VARIABLE(MCL_SCOPE_FAIL_VAR_) = ::mcl::detail::scope_success_tag{}->*[&]()

27
include/mcl/stdint.hpp Normal file
View file

@ -0,0 +1,27 @@
// This file is part of the mcl project.
// Copyright (c) 2022 merryhime
// SPDX-License-Identifier: MIT
#pragma once
#include <cstddef>
#include <cstdint>
using u8 = std::uint8_t;
using u16 = std::uint16_t;
using u32 = std::uint32_t;
using u64 = std::uint64_t;
using uptr = std::uintptr_t;
using s8 = std::int8_t;
using s16 = std::int16_t;
using s32 = std::int32_t;
using s64 = std::int64_t;
using sptr = std::intptr_t;
using size_t = std::size_t;
using f32 = float;
using f64 = double;
static_assert(sizeof(f32) == sizeof(u32), "f32 must be 32 bits wide");
static_assert(sizeof(f64) == sizeof(u64), "f64 must be 64 bits wide");

View file

@ -0,0 +1,70 @@
// This file is part of the mcl project.
// Copyright (c) 2022 merryhime
// SPDX-License-Identifier: MIT
#pragma once
#include <cstddef>
#include <tuple>
#include "mcl/mp/typelist/list.hpp"
namespace mcl {
template<class F>
struct function_info : function_info<decltype(&F::operator())> {};
template<class R, class... As>
struct function_info<R(As...)> {
using return_type = R;
using parameter_list = mp::list<As...>;
static constexpr std::size_t parameter_count = sizeof...(As);
using equivalent_function_type = R(As...);
template<std::size_t I>
struct parameter {
static_assert(I < parameter_count, "Non-existent parameter");
using type = std::tuple_element_t<I, std::tuple<As...>>;
};
};
template<class R, class... As>
struct function_info<R (*)(As...)> : function_info<R(As...)> {};
template<class C, class R, class... As>
struct function_info<R (C::*)(As...)> : function_info<R(As...)> {
using class_type = C;
using equivalent_function_type_with_class = R(C*, As...);
};
template<class C, class R, class... As>
struct function_info<R (C::*)(As...) const> : function_info<R(As...)> {
using class_type = C;
using equivalent_function_type_with_class = R(C*, As...);
};
template<class F>
constexpr size_t parameter_count_v = function_info<F>::parameter_count;
template<class F>
using parameter_list = typename function_info<F>::parameter_list;
template<class F, std::size_t I>
using get_parameter = typename function_info<F>::template parameter<I>::type;
template<class F>
using equivalent_function_type = typename function_info<F>::equivalent_function_type;
template<class F>
using equivalent_function_type_with_class = typename function_info<F>::equivalent_function_type_with_class;
template<class F>
using return_type = typename function_info<F>::return_type;
template<class F>
using class_type = typename function_info<F>::class_type;
} // namespace mcl

View file

@ -0,0 +1,48 @@
// This file is part of the mcl project.
// Copyright (c) 2022 merryhime
// SPDX-License-Identifier: MIT
#pragma once
#include "mcl/stdint.hpp"
namespace mcl {
namespace detail {
template<size_t size>
struct integer_of_size_impl {};
template<>
struct integer_of_size_impl<8> {
using unsigned_type = u8;
using signed_type = s8;
};
template<>
struct integer_of_size_impl<16> {
using unsigned_type = u16;
using signed_type = s16;
};
template<>
struct integer_of_size_impl<32> {
using unsigned_type = u32;
using signed_type = s32;
};
template<>
struct integer_of_size_impl<64> {
using unsigned_type = u64;
using signed_type = s64;
};
} // namespace detail
template<size_t size>
using unsigned_integer_of_size = typename detail::integer_of_size_impl<size>::unsigned_type;
template<size_t size>
using signed_integer_of_size = typename detail::integer_of_size_impl<size>::signed_type;
} // namespace mcl

View file

@ -0,0 +1,22 @@
// This file is part of the mcl project.
// Copyright (c) 2022 merryhime
// SPDX-License-Identifier: MIT
#pragma once
#include "mcl/mp/metavalue/value.hpp"
namespace mcl {
/// Is type T an instance of template class C?
template<template<class...> class, class>
struct is_instance_of_template : mp::false_type {};
template<template<class...> class C, class... As>
struct is_instance_of_template<C, C<As...>> : mp::true_type {};
/// Is type T an instance of template class C?
template<template<class...> class C, class T>
constexpr bool is_instance_of_template_v = is_instance_of_template<C, T>::value;
} // namespace mcl