Add more CTL content

This commit is contained in:
Justine Tunney 2024-06-28 19:07:35 -07:00
parent 38921dc46b
commit 021c53ba32
No known key found for this signature in database
GPG key ID: BE714B4575D6E328
56 changed files with 1747 additions and 298 deletions

View file

@ -0,0 +1,55 @@
// -*-mode:c++;indent-tabs-mode:nil;c-basic-offset:4;tab-width:8;coding:utf-8-*-
// vi: set et ft=cpp ts=4 sts=4 sw=4 fenc=utf-8 :vi
#ifndef CTL_ADD_LVALUE_REFERENCE_H_
#define CTL_ADD_LVALUE_REFERENCE_H_
namespace ctl {
template<typename T>
struct add_lvalue_reference
{
typedef T& type;
};
template<typename T>
struct add_lvalue_reference<T&>
{
typedef T& type;
};
template<typename T>
struct add_lvalue_reference<T&&>
{
typedef T& type;
};
template<>
struct add_lvalue_reference<void>
{
typedef void type;
};
template<>
struct add_lvalue_reference<const void>
{
typedef const void type;
};
template<>
struct add_lvalue_reference<volatile void>
{
typedef volatile void type;
};
template<>
struct add_lvalue_reference<const volatile void>
{
typedef const volatile void type;
};
template<typename T>
using add_lvalue_reference_t = typename add_lvalue_reference<T>::type;
} // namespace ctl
#endif // CTL_ADD_LVALUE_REFERENCE_H_

43
ctl/add_pointer.h Normal file
View file

@ -0,0 +1,43 @@
// -*-mode:c++;indent-tabs-mode:nil;c-basic-offset:4;tab-width:8;coding:utf-8-*-
// vi: set et ft=cpp ts=4 sts=4 sw=4 fenc=utf-8 :vi
#ifndef CTL_ADD_POINTER_H_
#define CTL_ADD_POINTER_H_
#include "remove_reference.h"
namespace ctl {
// Primary template
template<typename T>
struct add_pointer
{
typedef typename remove_reference<T>::type* type;
};
// Specialization for functions
template<typename R, typename... Args>
struct add_pointer<R(Args...)>
{
typedef R (*type)(Args...);
};
// Specialization for function references
template<typename R, typename... Args>
struct add_pointer<R (&)(Args...)>
{
typedef R (*type)(Args...);
};
// Specialization for rvalue references to functions
template<typename R, typename... Args>
struct add_pointer<R (&&)(Args...)>
{
typedef R (*type)(Args...);
};
// Helper alias template (C++14 and later)
template<typename T>
using add_pointer_t = typename add_pointer<T>::type;
} // namespace ctl
#endif // CTL_ADD_POINTER_H_

View file

@ -9,11 +9,9 @@ template<class InputIt, class UnaryPredicate>
constexpr bool constexpr bool
all_of(InputIt first, InputIt last, UnaryPredicate p) all_of(InputIt first, InputIt last, UnaryPredicate p)
{ {
for (; first != last; ++first) { for (; first != last; ++first)
if (!p(*first)) { if (!p(*first))
return false; return false;
}
}
return true; return true;
} }

View file

@ -3,8 +3,8 @@
#ifndef CTL_ALLOCATOR_H_ #ifndef CTL_ALLOCATOR_H_
#define CTL_ALLOCATOR_H_ #define CTL_ALLOCATOR_H_
#include "bad_alloc.h" #include "bad_alloc.h"
#include "integral_constant.h"
#include "new.h" #include "new.h"
#include "type_traits.h"
#include "utility.h" #include "utility.h"
namespace ctl { namespace ctl {

View file

@ -1,6 +1,8 @@
// -*-mode:c++;indent-tabs-mode:nil;c-basic-offset:4;tab-width:8;coding:utf-8-*-
// vi: set et ft=cpp ts=4 sts=4 sw=4 fenc=utf-8 :vi
#ifndef CTL_ALLOCATOR_TRAITS_H_ #ifndef CTL_ALLOCATOR_TRAITS_H_
#define CTL_ALLOCATOR_TRAITS_H_ #define CTL_ALLOCATOR_TRAITS_H_
#include "type_traits.h" #include "integral_constant.h"
namespace ctl { namespace ctl {

View file

@ -9,11 +9,9 @@ template<class InputIt, class UnaryPredicate>
constexpr bool constexpr bool
any_of(InputIt first, InputIt last, UnaryPredicate p) any_of(InputIt first, InputIt last, UnaryPredicate p)
{ {
for (; first != last; ++first) { for (; first != last; ++first)
if (p(*first)) { if (p(*first))
return true; return true;
}
}
return false; return false;
} }

View file

@ -3,6 +3,7 @@
#ifndef CTL_ARRAY_H_ #ifndef CTL_ARRAY_H_
#define CTL_ARRAY_H_ #define CTL_ARRAY_H_
#include "initializer_list.h" #include "initializer_list.h"
#include "out_of_range.h"
#include "reverse_iterator.h" #include "reverse_iterator.h"
namespace ctl { namespace ctl {
@ -25,25 +26,25 @@ struct array
T elems[N]; T elems[N];
constexpr array() = default; constexpr array() = default;
constexpr array(std::initializer_list<T> init) constexpr array(std::initializer_list<T> init)
{ {
auto it = init.begin(); auto it = init.begin();
for (size_t i = 0; i < N && it != init.end(); ++i, ++it) { for (size_t i = 0; i < N && it != init.end(); ++i, ++it)
elems[i] = *it; elems[i] = *it;
}
} }
constexpr reference at(size_type pos) constexpr reference at(size_type pos)
{ {
if (pos >= N) if (pos >= N)
__builtin_trap(); throw ctl::out_of_range("out of range");
return elems[pos]; return elems[pos];
} }
constexpr const_reference at(size_type pos) const constexpr const_reference at(size_type pos) const
{ {
if (pos >= N) if (pos >= N)
__builtin_trap(); throw ctl::out_of_range("out of range");
return elems[pos]; return elems[pos];
} }

22
ctl/conditional.h Normal file
View file

@ -0,0 +1,22 @@
// -*-mode:c++;indent-tabs-mode:nil;c-basic-offset:4;tab-width:8;coding:utf-8-*-
// vi: set et ft=cpp ts=4 sts=4 sw=4 fenc=utf-8 :vi
#ifndef CTL_CONDITIONAL_H_
#define CTL_CONDITIONAL_H_
namespace ctl {
template<bool B, class T, class F>
struct conditional
{
typedef T type;
};
template<class T, class F>
struct conditional<false, T, F>
{
typedef F type;
};
} // namespace ctl
#endif // CTL_CONDITIONAL_H_

35
ctl/decay.h Normal file
View file

@ -0,0 +1,35 @@
// -*-mode:c++;indent-tabs-mode:nil;c-basic-offset:4;tab-width:8;coding:utf-8-*-
// vi: set et ft=cpp ts=4 sts=4 sw=4 fenc=utf-8 :vi
#ifndef CTL_DECAY_H_
#define CTL_DECAY_H_
#include "add_pointer.h"
#include "conditional.h"
#include "is_array.h"
#include "is_function.h"
#include "remove_cv.h"
#include "remove_extent.h"
#include "remove_reference.h"
namespace ctl {
template<typename T>
struct decay
{
private:
typedef typename remove_reference<T>::type U;
public:
typedef typename conditional<
is_array<U>::value,
typename remove_extent<U>::type*,
typename conditional<is_function<U>::value,
typename add_pointer<U>::type,
typename remove_cv<U>::type>::type>::type type;
};
template<typename T>
using decay_t = typename decay<T>::type;
} // namespace ctl
#endif // CTL_DECAY_H_

44
ctl/default_delete.h Normal file
View file

@ -0,0 +1,44 @@
// -*-mode:c++;indent-tabs-mode:nil;c-basic-offset:4;tab-width:8;coding:utf-8-*-
// vi: set et ft=cpp ts=4 sts=4 sw=4 fenc=utf-8 :vi
#ifndef CTL_DEFAULT_DELETE_H_
#define CTL_DEFAULT_DELETE_H_
#include "enable_if.h"
#include "is_convertible.h"
namespace ctl {
template<typename T>
struct default_delete
{
constexpr default_delete() noexcept = default;
template<typename U,
typename = typename ctl::enable_if<
ctl::is_convertible<U*, T*>::value>::type>
constexpr default_delete(const default_delete<U>&) noexcept
{
}
constexpr void operator()(T* const p) const noexcept
{
delete p;
}
};
template<typename T>
struct default_delete<T[]>
{
constexpr default_delete() noexcept = default;
template<typename U,
typename = typename ctl::enable_if<
ctl::is_convertible<U (*)[], T (*)[]>::value>::type>
constexpr default_delete(const default_delete<U[]>&) noexcept
{
}
constexpr void operator()(T* const p) const noexcept
{
delete[] p;
}
};
} // namespace ctl
#endif // CTL_DEFAULT_DELETE_H_

View file

@ -1,3 +1,5 @@
// -*-mode:c++;indent-tabs-mode:nil;c-basic-offset:4;tab-width:8;coding:utf-8-*-
// vi: set et ft=cpp ts=4 sts=4 sw=4 fenc=utf-8 :vi
#ifndef CTL_ENABLE_IF_H_ #ifndef CTL_ENABLE_IF_H_
#define CTL_ENABLE_IF_H_ #define CTL_ENABLE_IF_H_

29
ctl/integral_constant.h Normal file
View file

@ -0,0 +1,29 @@
// -*-mode:c++;indent-tabs-mode:nil;c-basic-offset:4;tab-width:8;coding:utf-8-*-
// vi: set et ft=cpp ts=4 sts=4 sw=4 fenc=utf-8 :vi
#ifndef CTL_INTEGRAL_CONSTANT_H_
#define CTL_INTEGRAL_CONSTANT_H_
namespace ctl {
template<class T, T v>
struct integral_constant
{
static constexpr T value = v;
typedef T value_type;
typedef integral_constant type;
constexpr operator value_type() const noexcept
{
return value;
}
constexpr value_type operator()() const noexcept
{
return value;
}
};
typedef integral_constant<bool, true> true_type;
typedef integral_constant<bool, false> false_type;
} // namespace ctl
#endif // CTL_INTEGRAL_CONSTANT_H_

26
ctl/is_array.h Normal file
View file

@ -0,0 +1,26 @@
// -*-mode:c++;indent-tabs-mode:nil;c-basic-offset:4;tab-width:8;coding:utf-8-*-
// vi: set et ft=cpp ts=4 sts=4 sw=4 fenc=utf-8 :vi
#ifndef CTL_IS_ARRAY_H_
#define CTL_IS_ARRAY_H_
#include "integral_constant.h"
namespace ctl {
template<typename T>
struct is_array : false_type
{};
template<typename T, size_t N>
struct is_array<T[N]> : true_type
{};
template<typename T>
struct is_array<T[]> : true_type
{};
template<typename T>
inline constexpr bool is_array_v = is_array<T>::value;
} // namespace ctl
#endif // CTL_IS_ARRAY_H_

54
ctl/is_convertible.h Normal file
View file

@ -0,0 +1,54 @@
// -*-mode:c++;indent-tabs-mode:nil;c-basic-offset:4;tab-width:8;coding:utf-8-*-
// vi: set et ft=cpp ts=4 sts=4 sw=4 fenc=utf-8 :vi
#ifndef CTL_IS_CONVERTIBLE_H_
#define CTL_IS_CONVERTIBLE_H_
#include "ctl/integral_constant.h"
#include "ctl/void_t.h"
namespace ctl {
// Declaration of declval
template<typename T>
T&&
declval() noexcept;
namespace detail {
template<typename From, typename To, typename = void>
struct is_convertible_impl : false_type
{};
template<typename From, typename To>
struct is_convertible_impl<From,
To,
void_t<decltype(static_cast<To>(declval<From>()))>>
: true_type
{};
// Handle void types separately
template<>
struct is_convertible_impl<void, void> : true_type
{};
template<typename To>
struct is_convertible_impl<void, To> : false_type
{};
template<typename From>
struct is_convertible_impl<From, void> : false_type
{};
} // namespace detail
template<typename From, typename To>
struct is_convertible : detail::is_convertible_impl<From, To>
{};
// Helper variable template (C++17 and later)
template<typename From, typename To>
inline constexpr bool is_convertible_v = is_convertible<From, To>::value;
} // namespace ctl
#endif // CTL_IS_CONVERTIBLE_H_

120
ctl/is_function.h Normal file
View file

@ -0,0 +1,120 @@
// -*-mode:c++;indent-tabs-mode:nil;c-basic-offset:4;tab-width:8;coding:utf-8-*-
// vi: set et ft=cpp ts=4 sts=4 sw=4 fenc=utf-8 :vi
#ifndef CTL_IS_FUNCTION_H_
#define CTL_IS_FUNCTION_H_
#include "integral_constant.h"
namespace ctl {
// Primary template
template<class>
struct is_function : false_type
{};
// Specializations for various function types
// Regular functions
template<class Ret, class... Args>
struct is_function<Ret(Args...)> : true_type
{};
// Functions with cv-qualifiers
template<class Ret, class... Args>
struct is_function<Ret(Args...) const> : true_type
{};
template<class Ret, class... Args>
struct is_function<Ret(Args...) volatile> : true_type
{};
template<class Ret, class... Args>
struct is_function<Ret(Args...) const volatile> : true_type
{};
// Functions with ref-qualifiers
template<class Ret, class... Args>
struct is_function<Ret(Args...)&> : true_type
{};
template<class Ret, class... Args>
struct is_function<Ret(Args...) const&> : true_type
{};
template<class Ret, class... Args>
struct is_function<Ret(Args...) volatile&> : true_type
{};
template<class Ret, class... Args>
struct is_function<Ret(Args...) const volatile&> : true_type
{};
template<class Ret, class... Args>
struct is_function<Ret(Args...) &&> : true_type
{};
template<class Ret, class... Args>
struct is_function<Ret(Args...) const&&> : true_type
{};
template<class Ret, class... Args>
struct is_function<Ret(Args...) volatile&&> : true_type
{};
template<class Ret, class... Args>
struct is_function<Ret(Args...) const volatile&&> : true_type
{};
// Variadic functions
template<class Ret, class... Args>
struct is_function<Ret(Args..., ...)> : true_type
{};
// Variadic functions with cv-qualifiers
template<class Ret, class... Args>
struct is_function<Ret(Args..., ...) const> : true_type
{};
template<class Ret, class... Args>
struct is_function<Ret(Args..., ...) volatile> : true_type
{};
template<class Ret, class... Args>
struct is_function<Ret(Args..., ...) const volatile> : true_type
{};
// Variadic functions with ref-qualifiers
template<class Ret, class... Args>
struct is_function<Ret(Args..., ...)&> : true_type
{};
template<class Ret, class... Args>
struct is_function<Ret(Args..., ...) const&> : true_type
{};
template<class Ret, class... Args>
struct is_function<Ret(Args..., ...) volatile&> : true_type
{};
template<class Ret, class... Args>
struct is_function<Ret(Args..., ...) const volatile&> : true_type
{};
template<class Ret, class... Args>
struct is_function<Ret(Args..., ...) &&> : true_type
{};
template<class Ret, class... Args>
struct is_function<Ret(Args..., ...) const&&> : true_type
{};
template<class Ret, class... Args>
struct is_function<Ret(Args..., ...) volatile&&> : true_type
{};
template<class Ret, class... Args>
struct is_function<Ret(Args..., ...) const volatile&&> : true_type
{};
} // namespace ctl
#endif // CTL_IS_FUNCTION_H_

View file

@ -1,29 +1,11 @@
// -*-mode:c++;indent-tabs-mode:nil;c-basic-offset:4;tab-width:8;coding:utf-8-*- // -*-mode:c++;indent-tabs-mode:nil;c-basic-offset:4;tab-width:8;coding:utf-8-*-
// vi: set et ft=cpp ts=4 sts=4 sw=4 fenc=utf-8 :vi // vi: set et ft=cpp ts=4 sts=4 sw=4 fenc=utf-8 :vi
#ifndef CTL_TYPE_TRAITS_H_ #ifndef CTL_IS_INTEGRAL_H_
#define CTL_TYPE_TRAITS_H_ #define CTL_IS_INTEGRAL_H_
#include "integral_constant.h"
namespace ctl { namespace ctl {
template<class T, T v>
struct integral_constant
{
static constexpr T value = v;
using value_type = T;
using type = integral_constant;
constexpr operator value_type() const noexcept
{
return value;
}
constexpr value_type operator()() const noexcept
{
return value;
}
};
using true_type = integral_constant<bool, true>;
using false_type = integral_constant<bool, false>;
template<typename T> template<typename T>
struct is_integral : false_type struct is_integral : false_type
{}; {};
@ -91,33 +73,6 @@ struct is_integral<wchar_t> : true_type
template<typename T> template<typename T>
inline constexpr bool is_integral_v = is_integral<T>::value; inline constexpr bool is_integral_v = is_integral<T>::value;
template<typename T>
struct is_signed
{
static constexpr bool value = T(0) > T(-1);
};
template<typename T>
struct is_unsigned
{
static constexpr bool value = T(0) < T(-1);
};
template<typename T, typename U>
struct is_same
{
static constexpr bool value = false;
};
template<typename T>
struct is_same<T, T>
{
static constexpr bool value = true;
};
template<class T, class U>
inline constexpr bool is_same_v = is_same<T, U>::value;
} // namespace ctl } // namespace ctl
#endif // CTL_TYPE_TRAITS_H_ #endif // CTL_IS_INTEGRAL_H_

35
ctl/is_reference.h Normal file
View file

@ -0,0 +1,35 @@
// -*-mode:c++;indent-tabs-mode:nil;c-basic-offset:4;tab-width:8;coding:utf-8-*-
// vi: set et ft=cpp ts=4 sts=4 sw=4 fenc=utf-8 :vi
#ifndef CTL_IS_REFERENCE_H_
#define CTL_IS_REFERENCE_H_
namespace ctl {
// Primary template
template<class T>
struct is_reference
{
static constexpr bool value = false;
};
// Specialization for lvalue reference
template<class T>
struct is_reference<T&>
{
static constexpr bool value = true;
};
// Specialization for rvalue reference
template<class T>
struct is_reference<T&&>
{
static constexpr bool value = true;
};
// Helper variable template (C++14 and later)
template<class T>
inline constexpr bool is_reference_v = is_reference<T>::value;
} // namespace ctl
#endif // CTL_IS_REFERENCE_H_

25
ctl/is_same.h Normal file
View file

@ -0,0 +1,25 @@
// -*-mode:c++;indent-tabs-mode:nil;c-basic-offset:4;tab-width:8;coding:utf-8-*-
// vi: set et ft=cpp ts=4 sts=4 sw=4 fenc=utf-8 :vi
#ifndef CTL_IS_SAME_H_
#define CTL_IS_SAME_H_
namespace ctl {
template<typename T, typename U>
struct is_same
{
static constexpr bool value = false;
};
template<typename T>
struct is_same<T, T>
{
static constexpr bool value = true;
};
template<class T, class U>
inline constexpr bool is_same_v = is_same<T, U>::value;
} // namespace ctl
#endif // CTL_IS_SAME_H_

16
ctl/is_signed.h Normal file
View file

@ -0,0 +1,16 @@
// -*-mode:c++;indent-tabs-mode:nil;c-basic-offset:4;tab-width:8;coding:utf-8-*-
// vi: set et ft=cpp ts=4 sts=4 sw=4 fenc=utf-8 :vi
#ifndef CTL_IS_SIGNED_H_
#define CTL_IS_SIGNED_H_
namespace ctl {
template<typename T>
struct is_signed
{
static constexpr bool value = T(0) > T(-1);
};
} // namespace ctl
#endif // CTL_IS_SIGNED_H_

25
ctl/is_sorted.h Normal file
View file

@ -0,0 +1,25 @@
// -*-mode:c++;indent-tabs-mode:nil;c-basic-offset:4;tab-width:8;coding:utf-8-*-
// vi: set et ft=cpp ts=4 sts=4 sw=4 fenc=utf-8 :vi
#ifndef CTL_IS_SORTED_H_
#define CTL_IS_SORTED_H_
namespace ctl {
template<typename It, typename Compare>
bool
is_sorted(It first, It last, Compare comp)
{
if (first == last)
return true;
It next = first;
while (++next != last) {
if (comp(*next, *first))
return false;
first = next;
}
return true;
}
} // namespace ctl
#endif // CTL_IS_SORTED_H_

16
ctl/is_unsigned.h Normal file
View file

@ -0,0 +1,16 @@
// -*-mode:c++;indent-tabs-mode:nil;c-basic-offset:4;tab-width:8;coding:utf-8-*-
// vi: set et ft=cpp ts=4 sts=4 sw=4 fenc=utf-8 :vi
#ifndef CTL_IS_UNSIGNED_H_
#define CTL_IS_UNSIGNED_H_
namespace ctl {
template<typename T>
struct is_unsigned
{
static constexpr bool value = T(0) < T(-1);
};
} // namespace ctl
#endif // CTL_IS_UNSIGNED_H_

View file

@ -1,7 +1,6 @@
#ifndef CTL_MOVE_ITERATOR_H_ #ifndef CTL_MOVE_ITERATOR_H_
#define CTL_MOVE_ITERATOR_H_ #define CTL_MOVE_ITERATOR_H_
#include "iterator_traits.h" #include "iterator_traits.h"
#include "type_traits.h"
namespace ctl { namespace ctl {

47
ctl/mutex.h Normal file
View file

@ -0,0 +1,47 @@
// -*-mode:c++;indent-tabs-mode:nil;c-basic-offset:4;tab-width:8;coding:utf-8-*-
// vi: set et ft=cpp ts=4 sts=4 sw=4 fenc=utf-8 :vi
#ifndef CTL_MUTEX_H_
#define CTL_MUTEX_H_
#include "libc/thread/thread.h"
namespace ctl {
class mutex
{
public:
mutex()
{
pthread_mutex_init(&m_, nullptr);
}
~mutex()
{
pthread_mutex_destroy(&m_);
}
void lock()
{
pthread_mutex_lock(&m_);
}
bool try_lock()
{
return pthread_mutex_trylock(&m_) == 0;
}
void unlock()
{
pthread_mutex_unlock(&m_);
}
// Delete copy constructor and assignment operator
mutex(const mutex&) = delete;
mutex& operator=(const mutex&) = delete;
private:
pthread_mutex_t m_;
};
} // namespace ctl
#endif // CTL_MUTEX_H_

View file

@ -2,7 +2,8 @@
// vi: set et ft=cpp ts=4 sts=4 sw=4 fenc=utf-8 :vi // vi: set et ft=cpp ts=4 sts=4 sw=4 fenc=utf-8 :vi
#ifndef CTL_NUMERIC_LIMITS_H_ #ifndef CTL_NUMERIC_LIMITS_H_
#define CTL_NUMERIC_LIMITS_H_ #define CTL_NUMERIC_LIMITS_H_
#include "type_traits.h" #include "is_integral.h"
#include "is_unsigned.h"
namespace ctl { namespace ctl {

29
ctl/partition.h Normal file
View file

@ -0,0 +1,29 @@
// -*-mode:c++;indent-tabs-mode:nil;c-basic-offset:4;tab-width:8;coding:utf-8-*-
// vi: set et ft=cpp ts=4 sts=4 sw=4 fenc=utf-8 :vi
#ifndef CTL_PARTITION_H_
#define CTL_PARTITION_H_
#include "utility.h"
namespace ctl {
template<typename RandomIt, typename Compare>
RandomIt
partition(RandomIt first, RandomIt last, Compare comp)
{
auto pivot = *ctl::move(last - 1);
auto i = first - 1;
for (auto j = first; j < last - 1; ++j) {
if (comp(*j, pivot)) {
++i;
ctl::swap(*i, *j);
}
}
ctl::swap(*(i + 1), *(last - 1));
return i + 1;
}
} // namespace ctl
#endif // CTL_PARTITION_H_

49
ctl/remove_cv.h Normal file
View file

@ -0,0 +1,49 @@
// -*-mode:c++;indent-tabs-mode:nil;c-basic-offset:4;tab-width:8;coding:utf-8-*-
// vi: set et ft=cpp ts=4 sts=4 sw=4 fenc=utf-8 :vi
#ifndef CTL_REMOVE_CV_H_
#define CTL_REMOVE_CV_H_
namespace ctl {
template<class T>
struct remove_const
{
typedef T type;
};
template<class T>
struct remove_const<const T>
{
typedef T type;
};
template<class T>
struct remove_volatile
{
typedef T type;
};
template<class T>
struct remove_volatile<volatile T>
{
typedef T type;
};
template<class T>
struct remove_cv
{
typedef typename remove_volatile<typename remove_const<T>::type>::type type;
};
template<class T>
using remove_const_t = typename remove_const<T>::type;
template<class T>
using remove_volatile_t = typename remove_volatile<T>::type;
template<class T>
using remove_cv_t = typename remove_cv<T>::type;
} // namespace ctl
#endif // CTL_REMOVE_CV_H_

31
ctl/remove_extent.h Normal file
View file

@ -0,0 +1,31 @@
// -*-mode:c++;indent-tabs-mode:nil;c-basic-offset:4;tab-width:8;coding:utf-8-*-
// vi: set et ft=cpp ts=4 sts=4 sw=4 fenc=utf-8 :vi
#ifndef CTL_REMOVE_EXTENT_H_
#define CTL_REMOVE_EXTENT_H_
namespace ctl {
template<typename T>
struct remove_extent
{
typedef T type;
};
template<typename T, size_t N>
struct remove_extent<T[N]>
{
typedef T type;
};
template<typename T>
struct remove_extent<T[]>
{
typedef T type;
};
template<typename T>
using remove_extent_t = typename remove_extent<T>::type;
} // namespace ctl
#endif // CTL_REMOVE_EXTENT_H_

31
ctl/remove_reference.h Normal file
View file

@ -0,0 +1,31 @@
// -*-mode:c++;indent-tabs-mode:nil;c-basic-offset:4;tab-width:8;coding:utf-8-*-
// vi: set et ft=cpp ts=4 sts=4 sw=4 fenc=utf-8 :vi
#ifndef CTL_REMOVE_REFERENCE_H_
#define CTL_REMOVE_REFERENCE_H_
namespace ctl {
template<class T>
struct remove_reference
{
typedef T type;
};
template<class T>
struct remove_reference<T&>
{
typedef T type;
};
template<class T>
struct remove_reference<T&&>
{
typedef T type;
};
template<class T>
using remove_reference_t = typename remove_reference<T>::type;
} // namespace ctl
#endif // CTL_REMOVE_REFERENCE_H_

33
ctl/runtime_error.h Normal file
View file

@ -0,0 +1,33 @@
// -*-mode:c++;indent-tabs-mode:nil;c-basic-offset:4;tab-width:8;coding:utf-8-*-
// vi: set et ft=cpp ts=4 sts=4 sw=4 fenc=utf-8 :vi
#ifndef CTL_RUNTIME_ERROR_H_
#define CTL_RUNTIME_ERROR_H_
#include "ctl/string.h"
namespace ctl {
class runtime_error
{
public:
explicit runtime_error(const string& what_arg) : msg_(what_arg)
{
}
explicit runtime_error(const char* what_arg) : msg_(what_arg)
{
}
virtual ~runtime_error() noexcept = default;
virtual const char* what() const noexcept
{
return msg_.c_str();
}
private:
string msg_;
};
} // namespace ctl
#endif // CTL_RUNTIME_ERROR_H_

44
ctl/sort.h Normal file
View file

@ -0,0 +1,44 @@
// -*-mode:c++;indent-tabs-mode:nil;c-basic-offset:4;tab-width:8;coding:utf-8-*-
// vi: set et ft=cpp ts=4 sts=4 sw=4 fenc=utf-8 :vi
#ifndef CTL_SORT_H_
#define CTL_SORT_H_
#include "iterator_traits.h"
#include "less.h"
#include "partition.h"
namespace ctl {
namespace detail {
template<typename RandomIt, typename Compare>
void
quicksort(RandomIt first, RandomIt last, Compare comp)
{
if (first < last) {
auto pivot = ctl::partition(first, last, comp);
quicksort(first, pivot, comp);
quicksort(pivot + 1, last, comp);
}
}
} // namespace detail
template<typename RandomIt, typename Compare>
void
sort(RandomIt first, RandomIt last, Compare comp)
{
detail::quicksort(first, last, comp);
}
template<typename RandomIt>
void
sort(RandomIt first, RandomIt last)
{
sort(first,
last,
ctl::less<typename ctl::iterator_traits<RandomIt>::value_type>());
}
} // namespace ctl
#endif // CTL_SORT_H_

View file

@ -38,9 +38,9 @@ strcat(const string_view lhs, const string_view rhs) noexcept
if (rhs.n) if (rhs.n)
memcpy(res.data() + lhs.n, rhs.p, rhs.n); memcpy(res.data() + lhs.n, rhs.p, rhs.n);
if (res.isbig()) { if (res.isbig()) {
res.big()->n = lhs.n + rhs.n; res.__b.n = lhs.n + rhs.n;
} else { } else {
res.small()->rem = __::sso_max - lhs.n - rhs.n; res.__s.rem = __::sso_max - lhs.n - rhs.n;
} }
res.data()[res.size()] = 0; res.data()[res.size()] = 0;
return res; return res;

View file

@ -26,7 +26,7 @@ namespace ctl {
void void
string::destroy_big() noexcept string::destroy_big() noexcept
{ {
auto* b = big(); auto* b = &__b;
if (b->n) { if (b->n) {
if (b->n >= b->c) if (b->n >= b->c)
__builtin_trap(); __builtin_trap();
@ -41,7 +41,14 @@ string::destroy_big() noexcept
void void
string::init_big(const string& s) noexcept string::init_big(const string& s) noexcept
{ {
init_big(string_view(s)); char* p2;
size_t size = s.size();
size_t need = size + 1;
size_t capacity = need;
if (!(p2 = (char*)malloc(capacity)))
__builtin_trap();
memcpy(p2, s.data(), need);
set_big_string(p2, size, capacity);
} }
void void
@ -103,7 +110,7 @@ string::reserve(size_t c2) noexcept
__builtin_trap(); __builtin_trap();
memcpy(p2, data(), __::string_size); memcpy(p2, data(), __::string_size);
} else { } else {
if (!(p2 = (char*)realloc(big()->p, c2))) if (!(p2 = (char*)realloc(__b.p, c2)))
__builtin_trap(); __builtin_trap();
} }
std::atomic_signal_fence(std::memory_order_seq_cst); std::atomic_signal_fence(std::memory_order_seq_cst);
@ -120,7 +127,7 @@ string::resize(const size_t n2, const char ch) noexcept
if (n2 > size()) if (n2 > size())
memset(data() + size(), ch, n2 - size()); memset(data() + size(), ch, n2 - size());
if (isbig()) { if (isbig()) {
big()->p[big()->n = n2] = 0; __b.p[__b.n = n2] = 0;
} else { } else {
set_small_size(n2); set_small_size(n2);
data()[size()] = 0; data()[size()] = 0;
@ -141,9 +148,9 @@ string::append(const char ch) noexcept
} }
data()[size()] = ch; data()[size()] = ch;
if (isbig()) { if (isbig()) {
++big()->n; ++__b.n;
} else { } else {
--small()->rem; --__s.rem;
} }
data()[size()] = 0; data()[size()] = 0;
} }
@ -174,9 +181,9 @@ string::append(const char ch, const size_t size) noexcept
if (size) if (size)
memset(data() + this->size(), ch, size); memset(data() + this->size(), ch, size);
if (isbig()) { if (isbig()) {
big()->n += size; __b.n += size;
} else { } else {
small()->rem -= size; __s.rem -= size;
} }
data()[this->size()] = 0; data()[this->size()] = 0;
} }
@ -188,9 +195,9 @@ string::append(const void* data, const size_t size) noexcept
if (size) if (size)
memcpy(this->data() + this->size(), data, size); memcpy(this->data() + this->size(), data, size);
if (isbig()) { if (isbig()) {
big()->n += size; __b.n += size;
} else { } else {
small()->rem -= size; __s.rem -= size;
} }
this->data()[this->size()] = 0; this->data()[this->size()] = 0;
} }
@ -201,9 +208,9 @@ string::pop_back() noexcept
if (!size()) if (!size())
__builtin_trap(); __builtin_trap();
if (isbig()) { if (isbig()) {
--big()->n; --__b.n;
} else { } else {
++small()->rem; ++__s.rem;
} }
data()[size()] = 0; data()[size()] = 0;
} }
@ -322,7 +329,7 @@ string::replace(const size_t pos,
memmove(data() + pos + s.n, data() + last, extra); memmove(data() + pos + s.n, data() + last, extra);
memcpy(data() + pos, s.p, s.n); memcpy(data() + pos, s.p, s.n);
if (isbig()) { if (isbig()) {
big()->p[big()->n = need] = 0; __b.p[__b.n = need] = 0;
} else { } else {
set_small_size(need); set_small_size(need);
data()[size()] = 0; data()[size()] = 0;
@ -346,9 +353,9 @@ string::insert(const size_t i, const string_view s) noexcept
memmove(data() + i + s.n, data() + i, extra); memmove(data() + i + s.n, data() + i, extra);
memcpy(data() + i, s.p, s.n); memcpy(data() + i, s.p, s.n);
if (isbig()) { if (isbig()) {
big()->n += s.n; __b.n += s.n;
} else { } else {
small()->rem -= s.n; __s.rem -= s.n;
} }
data()[size()] = 0; data()[size()] = 0;
return *this; return *this;
@ -365,7 +372,7 @@ string::erase(const size_t pos, size_t count) noexcept
if (extra) if (extra)
memmove(data() + pos, data() + pos + count, extra); memmove(data() + pos, data() + pos + count, extra);
if (isbig()) { if (isbig()) {
big()->n = pos + extra; __b.n = pos + extra;
} else { } else {
set_small_size(pos + extra); set_small_size(pos + extra);
} }

View file

@ -151,7 +151,7 @@ class string
void clear() noexcept void clear() noexcept
{ {
if (isbig()) { if (isbig()) {
big()->n = 0; __b.n = 0;
} else { } else {
set_small_size(0); set_small_size(0);
} }
@ -159,26 +159,26 @@ class string
bool empty() const noexcept bool empty() const noexcept
{ {
return isbig() ? !big()->n : small()->rem >= __::sso_max; return isbig() ? !__b.n : __s.rem >= __::sso_max;
} }
char* data() noexcept __attribute__((__always_inline__)) char* data() noexcept
{ {
return isbig() ? big()->p : small()->buf; return isbig() ? __b.p : __s.buf;
} }
const char* data() const noexcept __attribute__((__always_inline__)) const char* data() const noexcept
{ {
return isbig() ? big()->p : small()->buf; return isbig() ? __b.p : __s.buf;
} }
size_t size() const noexcept __attribute__((__always_inline__)) size_t size() const noexcept
{ {
#if 0 #if 0
if (!isbig() && small()->rem > __::sso_max) if (!isbig() && __s.rem > __::sso_max)
__builtin_trap(); __builtin_trap();
#endif #endif
return isbig() ? big()->n : __::sso_max - small()->rem; return isbig() ? __b.n : __::sso_max - __s.rem;
} }
size_t length() const noexcept size_t length() const noexcept
@ -189,10 +189,10 @@ class string
size_t capacity() const noexcept size_t capacity() const noexcept
{ {
#if 0 #if 0
if (isbig() && big()->c <= __::sso_max) if (isbig() && __b.c <= __::sso_max)
__builtin_trap(); __builtin_trap();
#endif #endif
return isbig() ? __::big_mask & big()->c : __::string_size; return isbig() ? __::big_mask & __b.c : __::string_size;
} }
iterator begin() noexcept iterator begin() noexcept
@ -374,7 +374,7 @@ class string
void init_big(string_view) noexcept; void init_big(string_view) noexcept;
void init_big(size_t, char) noexcept; void init_big(size_t, char) noexcept;
bool isbig() const noexcept __attribute__((__always_inline__)) bool isbig() const noexcept
{ {
return *(blob + __::sso_max) & 0x80; return *(blob + __::sso_max) & 0x80;
} }
@ -395,34 +395,6 @@ class string
__b.c = c2 | ~__::big_mask; __b.c = c2 | ~__::big_mask;
} }
__::small_string* small() noexcept
{
if (isbig())
__builtin_trap();
return &__s;
}
const __::small_string* small() const noexcept
{
if (isbig())
__builtin_trap();
return &__s;
}
__::big_string* big() noexcept
{
if (!isbig())
__builtin_trap();
return &__b;
}
const __::big_string* big() const noexcept
{
if (!isbig())
__builtin_trap();
return &__b;
}
friend string strcat(string_view, string_view) noexcept; friend string strcat(string_view, string_view) noexcept;
union union

138
ctl/tuple.h Normal file
View file

@ -0,0 +1,138 @@
// -*-mode:c++;indent-tabs-mode:nil;c-basic-offset:4;tab-width:8;coding:utf-8-*-
// vi: set et ft=cpp ts=4 sts=4 sw=4 fenc=utf-8 :vi
#ifndef CTL_TUPLE_H_
#define CTL_TUPLE_H_
#include "decay.h"
#include "enable_if.h"
#include "is_same.h"
#include "utility.h"
namespace ctl {
// Forward declaration
template<typename... Types>
class tuple;
// Base case for tuple
template<>
class tuple<>
{};
// Recursive case for tuple
template<typename Head, typename... Tail>
class tuple<Head, Tail...> : public tuple<Tail...>
{
using Base = tuple<Tail...>;
public:
Head head;
constexpr tuple() : Base(), head()
{
}
template<typename H,
typename... T,
typename = typename ctl::enable_if<
!ctl::is_same<typename ctl::decay<H>::type, tuple>::value>::type>
constexpr tuple(H&& h, T&&... t)
: Base(ctl::forward<T>(t)...), head(ctl::forward<H>(h))
{
}
template<typename... UTypes>
constexpr tuple(const tuple<UTypes...>& other)
: Base(static_cast<const tuple<UTypes...>&>(other)), head(other.head)
{
}
template<typename... UTypes>
constexpr tuple(tuple<UTypes...>&& other)
: Base(static_cast<tuple<UTypes...>&&>(other))
, head(ctl::forward<Head>(other.head))
{
}
tuple(const tuple&) = default;
tuple(tuple&&) = default;
tuple& operator=(const tuple&) = default;
tuple& operator=(tuple&&) = default;
};
// Helper struct for getting element type
template<size_t I, typename T>
struct tuple_element;
template<size_t I, typename Head, typename... Tail>
struct tuple_element<I, tuple<Head, Tail...>>
: tuple_element<I - 1, tuple<Tail...>>
{};
template<typename Head, typename... Tail>
struct tuple_element<0, tuple<Head, Tail...>>
{
using type = Head;
};
// Helper function to get element
template<size_t I, typename Head, typename... Tail>
constexpr typename tuple_element<I, tuple<Head, Tail...>>::type&
get(tuple<Head, Tail...>& t)
{
if constexpr (I == 0) {
return t.head;
} else {
return get<I - 1>(static_cast<tuple<Tail...>&>(t));
}
}
template<size_t I, typename Head, typename... Tail>
constexpr const typename tuple_element<I, tuple<Head, Tail...>>::type&
get(const tuple<Head, Tail...>& t)
{
if constexpr (I == 0) {
return t.head;
} else {
return get<I - 1>(static_cast<const tuple<Tail...>&>(t));
}
}
// Helper function to create a tuple
template<typename... Types>
constexpr tuple<typename ctl::decay<Types>::type...>
make_tuple(Types&&... args)
{
return tuple<typename ctl::decay<Types>::type...>(
ctl::forward<Types>(args)...);
}
// Helper function for tuple comparison
template<size_t I = 0, typename... TTypes, typename... UTypes>
constexpr bool
tuple_equals(const tuple<TTypes...>& t, const tuple<UTypes...>& u)
{
if constexpr (I == sizeof...(TTypes)) {
return true;
} else {
return get<I>(t) == get<I>(u) && tuple_equals<I + 1>(t, u);
}
}
// Equality comparison
template<typename... TTypes, typename... UTypes>
constexpr bool
operator==(const tuple<TTypes...>& t, const tuple<UTypes...>& u)
{
return tuple_equals(t, u);
}
template<typename... TTypes, typename... UTypes>
constexpr bool
operator!=(const tuple<TTypes...>& t, const tuple<UTypes...>& u)
{
return !(t == u);
}
} // namespace ctl
#endif // CTL_TUPLE_H_

147
ctl/unique_lock.h Normal file
View file

@ -0,0 +1,147 @@
// -*-mode:c++;indent-tabs-mode:nil;c-basic-offset:4;tab-width:8;coding:utf-8-*-
// vi: set et ft=cpp ts=4 sts=4 sw=4 fenc=utf-8 :vi
#ifndef CTL_UNIQUE_LOCK_H_
#define CTL_UNIQUE_LOCK_H_
#include "mutex.h"
#include "utility.h"
namespace ctl {
struct defer_lock_t
{
explicit defer_lock_t() = default;
};
struct try_to_lock_t
{
explicit try_to_lock_t() = default;
};
struct adopt_lock_t
{
explicit adopt_lock_t() = default;
};
inline constexpr defer_lock_t defer_lock{};
inline constexpr try_to_lock_t try_to_lock{};
inline constexpr adopt_lock_t adopt_lock{};
class unique_lock
{
public:
unique_lock() noexcept : mutex_(nullptr), owns_lock_(false)
{
}
explicit unique_lock(ctl::mutex& m) : mutex_(&m), owns_lock_(false)
{
lock();
}
unique_lock(ctl::mutex& m, defer_lock_t) noexcept
: mutex_(&m), owns_lock_(false)
{
}
unique_lock(ctl::mutex& m, try_to_lock_t)
: mutex_(&m), owns_lock_(mutex_->try_lock())
{
}
unique_lock(ctl::mutex& m, adopt_lock_t) : mutex_(&m), owns_lock_(true)
{
}
~unique_lock()
{
if (owns_lock_)
mutex_->unlock();
}
unique_lock(const unique_lock&) = delete;
unique_lock& operator=(const unique_lock&) = delete;
unique_lock(unique_lock&& other) noexcept
: mutex_(other.mutex_), owns_lock_(other.owns_lock_)
{
other.mutex_ = nullptr;
other.owns_lock_ = false;
}
unique_lock& operator=(unique_lock&& other) noexcept
{
if (owns_lock_)
mutex_->unlock();
mutex_ = other.mutex_;
owns_lock_ = other.owns_lock_;
other.mutex_ = nullptr;
other.owns_lock_ = false;
return *this;
}
void lock()
{
if (!mutex_)
__builtin_trap();
if (owns_lock_)
__builtin_trap();
mutex_->lock();
owns_lock_ = true;
}
bool try_lock()
{
if (!mutex_)
__builtin_trap();
if (owns_lock_)
__builtin_trap();
owns_lock_ = mutex_->try_lock();
return owns_lock_;
}
void unlock()
{
if (!owns_lock_)
__builtin_trap();
mutex_->unlock();
owns_lock_ = false;
}
void swap(unique_lock& other) noexcept
{
using ctl::swap;
swap(mutex_, other.mutex_);
swap(owns_lock_, other.owns_lock_);
}
ctl::mutex* release() noexcept
{
ctl::mutex* result = mutex_;
mutex_ = nullptr;
owns_lock_ = false;
return result;
}
bool owns_lock() const noexcept
{
return owns_lock_;
}
explicit operator bool() const noexcept
{
return owns_lock_;
}
ctl::mutex* mutex() const noexcept
{
return mutex_;
}
private:
ctl::mutex* mutex_;
bool owns_lock_;
};
} // namespace ctl
#endif // CTL_UNIQUE_LOCK_H_

View file

@ -1,19 +0,0 @@
// -*- mode:c++; indent-tabs-mode:nil; c-basic-offset:4; coding:utf-8 -*-
// vi: set et ft=cpp ts=4 sts=4 sw=4 fenc=utf-8 :vi
//
// Copyright 2024 Justine Alexandra Roberts Tunney
//
// Permission to use, copy, modify, and/or distribute this software for
// any purpose with or without fee is hereby granted, provided that the
// above copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
// WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
// WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
// AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
// DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
// PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
// TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
// PERFORMANCE OF THIS SOFTWARE.
#include "unique_ptr.h"

View file

@ -1,41 +1,17 @@
// -*-mode:c++;indent-tabs-mode:nil;c-basic-offset:4;tab-width:8;coding:utf-8-*- // -*-mode:c++;indent-tabs-mode:nil;c-basic-offset:4;tab-width:8;coding:utf-8-*-
// vi: set et ft=cpp ts=4 sts=4 sw=4 fenc=utf-8 :vi // vi: set et ft=cpp ts=4 sts=4 sw=4 fenc=utf-8 :vi
#ifndef COSMOPOLITAN_CTL_UNIQUE_PTR_H_ #ifndef CTL_UNIQUE_PTR_H_
#define COSMOPOLITAN_CTL_UNIQUE_PTR_H_ #define CTL_UNIQUE_PTR_H_
#include "add_lvalue_reference.h"
#include "default_delete.h"
#include "is_convertible.h"
#include "is_reference.h"
#include "is_same.h"
#include "utility.h" #include "utility.h"
#include <__type_traits/is_convertible.h>
namespace ctl { namespace ctl {
template<typename T> template<typename T, typename D = ctl::default_delete<T>>
struct default_delete
{
constexpr default_delete() noexcept = default;
template<typename U>
constexpr default_delete(default_delete<U>&&) noexcept
{
}
constexpr void operator()(T* const p) const noexcept
{
delete p;
}
};
template<typename T>
struct default_delete<T[]>
{
constexpr default_delete() noexcept = default;
template<typename U>
constexpr default_delete(default_delete<U>&&) noexcept
{
}
constexpr void operator()(T* const p) const noexcept
{
delete[] p;
}
};
template<typename T, typename D = default_delete<T>>
struct unique_ptr struct unique_ptr
{ {
using pointer = T*; using pointer = T*;
@ -49,26 +25,34 @@ struct unique_ptr
{ {
} }
constexpr unique_ptr(const pointer p) noexcept : p(p), d() constexpr explicit unique_ptr(pointer p) noexcept : p(p), d()
{ {
} }
constexpr unique_ptr(const pointer p, auto&& d) noexcept constexpr unique_ptr(pointer p, const D& d) noexcept : p(p), d(d)
: p(p), d(ctl::forward<decltype(d)>(d)) {
}
constexpr unique_ptr(pointer p, D&& d) noexcept : p(p), d(ctl::move(d))
{ {
} }
template<typename U, typename E> template<typename U, typename E>
requires std::is_convertible_v<U, T> && std::is_convertible_v<E, D>
constexpr unique_ptr(unique_ptr<U, E>&& u) noexcept constexpr unique_ptr(unique_ptr<U, E>&& u) noexcept
: p(u.p), d(ctl::move(u.d)) : p(u.release()), d(ctl::forward<E>(u.get_deleter()))
{ {
u.p = nullptr; static_assert(ctl::is_convertible<typename unique_ptr<U, E>::pointer,
pointer>::value,
"U* must be implicitly convertible to T*");
static_assert(
(ctl::is_reference<D>::value && ctl::is_same<D, E>::value) ||
(!ctl::is_reference<D>::value && ctl::is_convertible<E, D>::value),
"The deleter must be convertible to the target deleter type");
} }
unique_ptr(const unique_ptr&) = delete; unique_ptr(const unique_ptr&) = delete;
constexpr ~unique_ptr() /* noexcept */ constexpr ~unique_ptr() noexcept
{ {
if (p) if (p)
d(p); d(p);
@ -80,6 +64,20 @@ struct unique_ptr
return *this; return *this;
} }
template<typename U, typename E>
constexpr unique_ptr& operator=(unique_ptr<U, E>&& r) noexcept
{
reset(r.release());
d = ctl::forward<E>(r.get_deleter());
return *this;
}
constexpr unique_ptr& operator=(nullptr_t) noexcept
{
reset();
return *this;
}
constexpr pointer release() noexcept constexpr pointer release() noexcept
{ {
pointer r = p; pointer r = p;
@ -87,12 +85,12 @@ struct unique_ptr
return r; return r;
} }
constexpr void reset(const pointer p2 = pointer()) noexcept constexpr void reset(pointer p2 = pointer()) noexcept
{ {
const pointer r = p; pointer old = p;
p = p2; p = p2;
if (r) if (old)
d(r); d(old);
} }
constexpr void swap(unique_ptr& r) noexcept constexpr void swap(unique_ptr& r) noexcept
@ -119,20 +117,16 @@ struct unique_ptr
constexpr explicit operator bool() const noexcept constexpr explicit operator bool() const noexcept
{ {
return p; return p != nullptr;
} }
element_type& operator*() const noexcept(noexcept(*ctl::declval<pointer>())) constexpr typename ctl::add_lvalue_reference<T>::type operator*() const
{ {
if (!p)
__builtin_trap();
return *p; return *p;
} }
pointer operator->() const noexcept constexpr pointer operator->() const noexcept
{ {
if (!p)
__builtin_trap();
return p; return p;
} }
}; };
@ -148,16 +142,9 @@ template<typename T>
constexpr unique_ptr<T> constexpr unique_ptr<T>
make_unique_for_overwrite() make_unique_for_overwrite()
{ {
#if 0
// You'd think that it'd work like this, but std::unique_ptr does not.
return unique_ptr<T>(
static_cast<T*>(::operator new(sizeof(T), align_val_t(alignof(T)))));
#else
return unique_ptr<T>(new T); return unique_ptr<T>(new T);
#endif
} }
// TODO(mrdomino): specializations for T[]
} // namespace ctl } // namespace ctl
#endif // COSMOPOLITAN_CTL_UNIQUE_PTR_H_
#endif // CTL_UNIQUE_PTR_H_

View file

@ -1,19 +0,0 @@
// -*- mode:c++; indent-tabs-mode:nil; c-basic-offset:4; coding:utf-8 -*-
// vi: set et ft=cpp ts=4 sts=4 sw=4 fenc=utf-8 :vi
//
// Copyright 2024 Justine Alexandra Roberts Tunney
//
// Permission to use, copy, modify, and/or distribute this software for
// any purpose with or without fee is hereby granted, provided that the
// above copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
// WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
// WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
// AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
// DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
// PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
// TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
// PERFORMANCE OF THIS SOFTWARE.
#include "utility.h"

View file

@ -2,6 +2,7 @@
// vi: set et ft=cpp ts=4 sts=4 sw=4 fenc=utf-8 :vi // vi: set et ft=cpp ts=4 sts=4 sw=4 fenc=utf-8 :vi
#ifndef COSMOPOLITAN_CTL_UTILITY_H_ #ifndef COSMOPOLITAN_CTL_UTILITY_H_
#define COSMOPOLITAN_CTL_UTILITY_H_ #define COSMOPOLITAN_CTL_UTILITY_H_
#include "remove_reference.h"
namespace ctl { namespace ctl {
@ -18,6 +19,14 @@ using no_infer = typename no_infer_<T>::type;
} // namespace __ } // namespace __
template<typename T>
constexpr T&&
move(T&& t) noexcept
{
typedef remove_reference_t<T> U;
return static_cast<U&&>(t);
}
template<typename T> template<typename T>
constexpr T&& constexpr T&&
move(T& t) noexcept move(T& t) noexcept
@ -47,9 +56,8 @@ template<typename T, size_t N>
constexpr void constexpr void
swap(T (&a)[N], T (&b)[N]) noexcept swap(T (&a)[N], T (&b)[N]) noexcept
{ {
for (size_t i = 0; i < N; ++i) { for (size_t i = 0; i < N; ++i)
swap(a[i], b[i]); swap(a[i], b[i]);
}
} }
template<typename T> template<typename T>

13
ctl/void_t.h Normal file
View file

@ -0,0 +1,13 @@
// -*-mode:c++;indent-tabs-mode:nil;c-basic-offset:4;tab-width:8;coding:utf-8-*-
// vi: set et ft=cpp ts=4 sts=4 sw=4 fenc=utf-8 :vi
#ifndef CTL_VOID_T_H_
#define CTL_VOID_T_H_
namespace ctl {
template<typename... Ts>
using void_t = void;
} // namespace ctl
#endif // CTL_VOID_T_H_

View file

@ -18,6 +18,7 @@ TEST_CTL_DIRECTDEPS = \
LIBC_INTRIN \ LIBC_INTRIN \
LIBC_MEM \ LIBC_MEM \
LIBC_STDIO \ LIBC_STDIO \
LIBC_THREAD \
THIRD_PARTY_LIBCXX \ THIRD_PARTY_LIBCXX \
THIRD_PARTY_LIBCXXABI \ THIRD_PARTY_LIBCXXABI \
THIRD_PARTY_LIBUNWIND \ THIRD_PARTY_LIBUNWIND \

View file

@ -18,6 +18,7 @@
#include "ctl/accumulate.h" #include "ctl/accumulate.h"
#include "ctl/array.h" #include "ctl/array.h"
#include "libc/mem/leaks.h"
// #include <array> // #include <array>
// #include <numeric> // #include <numeric>
@ -48,4 +49,6 @@ main()
// Test accumulation with single element // Test accumulation with single element
if (ctl::accumulate(arr.begin(), arr.begin() + 1, 0) != 1) if (ctl::accumulate(arr.begin(), arr.begin() + 1, 0) != 1)
return 5; return 5;
CheckForMemoryLeaks();
} }

View file

@ -18,6 +18,7 @@
#include "ctl/advance.h" #include "ctl/advance.h"
#include "ctl/array.h" #include "ctl/array.h"
#include "libc/mem/leaks.h"
// #include <array> // #include <array>
// #include <iterator> // #include <iterator>
@ -53,4 +54,6 @@ main()
ctl::advance(it, -2); ctl::advance(it, -2);
if (it != arr.begin()) if (it != arr.begin())
return 5; return 5;
CheckForMemoryLeaks();
} }

View file

@ -18,6 +18,7 @@
#include "ctl/all_of.h" #include "ctl/all_of.h"
#include "ctl/array.h" #include "ctl/array.h"
#include "libc/mem/leaks.h"
#include <algorithm> #include <algorithm>
#include <array> #include <array>
@ -49,4 +50,6 @@ main()
// Test with no elements satisfying the condition // Test with no elements satisfying the condition
if (ctl::all_of(arr1.begin(), arr1.end(), [](int n) { return n > 10; })) if (ctl::all_of(arr1.begin(), arr1.end(), [](int n) { return n > 10; }))
return 5; return 5;
CheckForMemoryLeaks();
} }

View file

@ -18,6 +18,7 @@
#include "ctl/any_of.h" #include "ctl/any_of.h"
#include "ctl/array.h" #include "ctl/array.h"
#include "libc/mem/leaks.h"
// #include <algorithm> // #include <algorithm>
// #include <array> // #include <array>
@ -48,4 +49,6 @@ main()
// Test with a different condition // Test with a different condition
if (!ctl::any_of(arr1.begin(), arr1.end(), [](int n) { return n > 5; })) if (!ctl::any_of(arr1.begin(), arr1.end(), [](int n) { return n > 5; }))
return 5; return 5;
CheckForMemoryLeaks();
} }

View file

@ -17,8 +17,11 @@
// PERFORMANCE OF THIS SOFTWARE. // PERFORMANCE OF THIS SOFTWARE.
#include "ctl/array.h" #include "ctl/array.h"
#include "ctl/string.h"
#include "libc/mem/leaks.h"
// #include <array> // #include <array>
// #include <string>
// #define ctl std // #define ctl std
int int
@ -264,4 +267,21 @@ main()
if (rit != arr.rend()) if (rit != arr.rend())
return 4; return 4;
} }
{
ctl::array<ctl::string, 2> A = { "hi", "theretheretheretherethere" };
if (A.size() != 2)
return 76;
if (A[0] != "hi")
return 77;
if (A[1] != "theretheretheretherethere")
return 78;
A = { "theretheretheretherethere", "hi" };
if (A[0] != "theretheretheretherethere")
return 79;
if (A[1] != "hi")
return 80;
}
CheckForMemoryLeaks();
} }

View file

@ -20,6 +20,7 @@
#include "ctl/back_inserter.h" #include "ctl/back_inserter.h"
#include "ctl/copy.h" #include "ctl/copy.h"
#include "ctl/vector.h" #include "ctl/vector.h"
#include "libc/mem/leaks.h"
// #include <array> // #include <array>
// #include <iterator> // #include <iterator>
@ -29,33 +30,38 @@
int int
main() main()
{ {
ctl::vector<int> vec = { 1, 2, 3 };
ctl::array<int, 3> arr = { 4, 5, 6 };
// Use back_inserter to append elements from arr to vec {
ctl::copy(arr.begin(), arr.end(), ctl::back_inserter(vec)); ctl::vector<int> vec = { 1, 2, 3 };
ctl::array<int, 3> arr = { 4, 5, 6 };
// Check if vec now contains all elements // Use back_inserter to append elements from arr to vec
if (vec.size() != 6) ctl::copy(arr.begin(), arr.end(), ctl::back_inserter(vec));
return 1;
if (vec[0] != 1 || vec[1] != 2 || vec[2] != 3 || vec[3] != 4 ||
vec[4] != 5 || vec[5] != 6)
return 2;
// Use back_inserter with a single element // Check if vec now contains all elements
ctl::back_inserter(vec) = 7; if (vec.size() != 6)
return 1;
if (vec[0] != 1 || vec[1] != 2 || vec[2] != 3 || vec[3] != 4 ||
vec[4] != 5 || vec[5] != 6)
return 2;
// Check if the new element was added // Use back_inserter with a single element
if (vec.size() != 7) ctl::back_inserter(vec) = 7;
return 3;
if (vec[6] != 7)
return 4;
// Test with an empty source range // Check if the new element was added
ctl::array<int, 0> empty_arr; if (vec.size() != 7)
ctl::copy(empty_arr.begin(), empty_arr.end(), ctl::back_inserter(vec)); return 3;
if (vec[6] != 7)
return 4;
// Check that no elements were added // Test with an empty source range
if (vec.size() != 7) ctl::array<int, 0> empty_arr;
return 5; ctl::copy(empty_arr.begin(), empty_arr.end(), ctl::back_inserter(vec));
// Check that no elements were added
if (vec.size() != 7)
return 5;
}
CheckForMemoryLeaks();
} }

View file

@ -18,49 +18,56 @@
#include "ctl/array.h" #include "ctl/array.h"
#include "ctl/copy.h" #include "ctl/copy.h"
#include "libc/mem/leaks.h"
// #include <iterator> // #include <algorithm>
// #include <array> // #include <array>
// #include <iterator>
// #define ctl std // #define ctl std
int int
main() main()
{ {
ctl::array<int, 5> src = { 1, 2, 3, 4, 5 };
ctl::array<int, 5> dest = { 0, 0, 0, 0, 0 };
// Test basic copy {
ctl::copy(src.begin(), src.end(), dest.begin()); ctl::array<int, 5> src = { 1, 2, 3, 4, 5 };
for (size_t i = 0; i < 5; ++i) { ctl::array<int, 5> dest = { 0, 0, 0, 0, 0 };
if (dest[i] != src[i])
return 1; // Test basic copy
ctl::copy(src.begin(), src.end(), dest.begin());
for (size_t i = 0; i < 5; ++i) {
if (dest[i] != src[i])
return 1;
}
// Test partial copy
ctl::array<int, 5> dest2 = { 0, 0, 0, 0, 0 };
ctl::copy(src.begin(), src.begin() + 3, dest2.begin());
if (dest2[0] != 1 || dest2[1] != 2 || dest2[2] != 3 || dest2[3] != 0 ||
dest2[4] != 0)
return 2;
// Test copy to middle of destination
ctl::array<int, 7> dest3 = { 0, 0, 0, 0, 0, 0, 0 };
ctl::copy(src.begin(), src.end(), dest3.begin() + 1);
if (dest3[0] != 0 || dest3[1] != 1 || dest3[2] != 2 || dest3[3] != 3 ||
dest3[4] != 4 || dest3[5] != 5 || dest3[6] != 0)
return 3;
// Test copy with empty range
ctl::array<int, 5> dest4 = { 0, 0, 0, 0, 0 };
ctl::copy(src.begin(), src.begin(), dest4.begin());
for (size_t i = 0; i < 5; ++i) {
if (dest4[i] != 0)
return 4;
}
// Test copy return value
ctl::array<int, 5> dest5 = { 0, 0, 0, 0, 0 };
auto result = ctl::copy(src.begin(), src.end(), dest5.begin());
if (result != dest5.end())
return 5;
} }
// Test partial copy CheckForMemoryLeaks();
ctl::array<int, 5> dest2 = { 0, 0, 0, 0, 0 };
ctl::copy(src.begin(), src.begin() + 3, dest2.begin());
if (dest2[0] != 1 || dest2[1] != 2 || dest2[2] != 3 || dest2[3] != 0 ||
dest2[4] != 0)
return 2;
// Test copy to middle of destination
ctl::array<int, 7> dest3 = { 0, 0, 0, 0, 0, 0, 0 };
ctl::copy(src.begin(), src.end(), dest3.begin() + 1);
if (dest3[0] != 0 || dest3[1] != 1 || dest3[2] != 2 || dest3[3] != 3 ||
dest3[4] != 4 || dest3[5] != 5 || dest3[6] != 0)
return 3;
// Test copy with empty range
ctl::array<int, 5> dest4 = { 0, 0, 0, 0, 0 };
ctl::copy(src.begin(), src.begin(), dest4.begin());
for (size_t i = 0; i < 5; ++i) {
if (dest4[i] != 0)
return 4;
}
// Test copy return value
ctl::array<int, 5> dest5 = { 0, 0, 0, 0, 0 };
auto result = ctl::copy(src.begin(), src.end(), dest5.begin());
if (result != dest5.end())
return 5;
} }

114
test/ctl/mutex_test.cc Normal file
View file

@ -0,0 +1,114 @@
// -*- mode:c++; indent-tabs-mode:nil; c-basic-offset:4; coding:utf-8 -*-
// vi: set et ft=cpp ts=4 sts=4 sw=4 fenc=utf-8 :vi
//
// Copyright 2024 Justine Alexandra Roberts Tunney
//
// Permission to use, copy, modify, and/or distribute this software for
// any purpose with or without fee is hereby granted, provided that the
// above copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
// WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
// WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
// AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
// DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
// PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
// TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
// PERFORMANCE OF THIS SOFTWARE.
#include "ctl/mutex.h"
#include "libc/mem/leaks.h"
// #include <mutex>
// #define ctl std
ctl::mutex mtx;
int shared_resource = 0;
const int NUM_THREADS = 5;
const int ITERATIONS = 100000;
void*
increment_resource(void* arg)
{
for (int i = 0; i < ITERATIONS; ++i) {
mtx.lock();
++shared_resource;
mtx.unlock();
}
return nullptr;
}
void*
decrement_resource(void* arg)
{
for (int i = 0; i < ITERATIONS; ++i) {
mtx.lock();
--shared_resource;
mtx.unlock();
}
return nullptr;
}
int
test_basic_locking()
{
shared_resource = 0;
pthread_t threads[NUM_THREADS];
for (int i = 0; i < NUM_THREADS; ++i)
if (pthread_create(&threads[i], 0, increment_resource, 0) != 0)
return 1;
for (int i = 0; i < NUM_THREADS; ++i)
if (pthread_join(threads[i], 0) != 0)
return 2;
return (shared_resource == NUM_THREADS * ITERATIONS) ? 0 : 3;
}
int
test_lock_contention()
{
shared_resource = 0;
pthread_t threads[NUM_THREADS * 2];
for (int i = 0; i < NUM_THREADS; ++i)
if (pthread_create(&threads[i], 0, increment_resource, 0) != 0 ||
pthread_create(&threads[i + NUM_THREADS],
nullptr,
decrement_resource,
nullptr) != 0)
return 4;
for (int i = 0; i < NUM_THREADS * 2; ++i)
if (pthread_join(threads[i], 0) != 0)
return 5;
return (shared_resource == 0) ? 0 : 6;
}
int
test_try_lock()
{
ctl::mutex try_mtx;
if (!try_mtx.try_lock())
return 7;
if (try_mtx.try_lock())
return 8;
try_mtx.unlock();
return 0;
}
int
main()
{
int result;
result = test_basic_locking();
if (result != 0)
return result;
result = test_lock_contention();
if (result != 0)
return result;
result = test_try_lock();
if (result != 0)
return result;
CheckForMemoryLeaks();
}

130
test/ctl/sort_test.cc Normal file
View file

@ -0,0 +1,130 @@
// -*- mode:c++; indent-tabs-mode:nil; c-basic-offset:4; coding:utf-8 -*-
// vi: set et ft=cpp ts=4 sts=4 sw=4 fenc=utf-8 :vi
//
// Copyright 2024 Justine Alexandra Roberts Tunney
//
// Permission to use, copy, modify, and/or distribute this software for
// any purpose with or without fee is hereby granted, provided that the
// above copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
// WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
// WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
// AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
// DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
// PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
// TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
// PERFORMANCE OF THIS SOFTWARE.
#include "ctl/is_sorted.h"
#include "ctl/sort.h"
#include "ctl/string.h"
#include "ctl/vector.h"
#include "libc/mem/leaks.h"
#include "libc/stdio/rand.h"
// #include <algorithm>
// #include <string>
// #include <vector>
// #define ctl std
// Test sorting integers
int
test_sort_integers()
{
ctl::vector<int> v = { 5, 2, 8, 1, 9, 3, 7, 6, 4 };
ctl::sort(v.begin(), v.end());
if (!ctl::is_sorted(v.begin(), v.end(), ctl::less<int>()))
return 1;
return 0;
}
// Test sorting with custom comparator
int
test_sort_custom_compare()
{
ctl::vector<int> v = { 5, 2, 8, 1, 9, 3, 7, 6, 4 };
ctl::sort(v.begin(), v.end(), [](int a, int b) { return a > b; });
if (!ctl::is_sorted(v.begin(), v.end(), [](int a, int b) { return a > b; }))
return 2;
return 0;
}
// Test sorting strings
int
test_sort_strings()
{
ctl::vector<ctl::string> v = { "banana", "apple", "cherry", "date" };
ctl::sort(v.begin(), v.end());
if (!ctl::is_sorted(v.begin(), v.end(), ctl::less<ctl::string>()))
return 3;
return 0;
}
// Test sorting with large number of elements
int
test_sort_large()
{
const int SIZE = 10000;
ctl::vector<int> v(SIZE);
for (int i = 0; i < SIZE; ++i)
v[i] = rand() % SIZE;
ctl::sort(v.begin(), v.end());
if (!is_sorted(v.begin(), v.end(), ctl::less<int>()))
return 4;
return 0;
}
// Test sorting already sorted vector
int
test_sort_sorted()
{
ctl::vector<int> v = { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
ctl::sort(v.begin(), v.end());
if (!is_sorted(v.begin(), v.end(), ctl::less<int>()))
return 5;
return 0;
}
// Test sorting reverse sorted vector
int
test_sort_reverse()
{
ctl::vector<int> v = { 9, 8, 7, 6, 5, 4, 3, 2, 1 };
ctl::sort(v.begin(), v.end());
if (!is_sorted(v.begin(), v.end(), ctl::less<int>()))
return 6;
return 0;
}
int
main()
{
int result;
result = test_sort_integers();
if (result != 0)
return result;
result = test_sort_custom_compare();
if (result != 0)
return result;
result = test_sort_strings();
if (result != 0)
return result;
result = test_sort_large();
if (result != 0)
return result;
result = test_sort_sorted();
if (result != 0)
return result;
result = test_sort_reverse();
if (result != 0)
return result;
CheckForMemoryLeaks();
}

View file

@ -17,8 +17,8 @@
// PERFORMANCE OF THIS SOFTWARE. // PERFORMANCE OF THIS SOFTWARE.
#include "ctl/string.h" #include "ctl/string.h"
#include "ctl/utility.h"
#include <__utility/move.h> #include "libc/mem/leaks.h"
#include "libc/calls/struct/timespec.h" #include "libc/calls/struct/timespec.h"
#include "libc/runtime/runtime.h" #include "libc/runtime/runtime.h"
@ -100,7 +100,7 @@ main()
BENCH(1000000, 1, { BENCH(1000000, 1, {
ctl::string s(small); ctl::string s(small);
ctl::string s2(std::move(s)); ctl::string s2(ctl::move(s));
}); });
BENCH(1000000, 1, { BENCH(1000000, 1, {
@ -119,7 +119,7 @@ main()
BENCH(1000000, 1, { BENCH(1000000, 1, {
ctl::string s(big); ctl::string s(big);
ctl::string s2(std::move(s)); ctl::string s2(ctl::move(s));
}); });
BENCH(1000000, 1, { BENCH(1000000, 1, {
@ -142,5 +142,5 @@ main()
BENCH(1000000, 1, { ctl::string s(big_trunc); }); BENCH(1000000, 1, { ctl::string s(big_trunc); });
} }
return 0; CheckForMemoryLeaks();
} }

View file

@ -16,13 +16,14 @@
// TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR // TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
// PERFORMANCE OF THIS SOFTWARE. // PERFORMANCE OF THIS SOFTWARE.
#include "ctl/is_same.h"
#include "ctl/string.h" #include "ctl/string.h"
#include "ctl/type_traits.h"
#include "libc/mem/leaks.h" #include "libc/mem/leaks.h"
#include "libc/str/str.h" #include "libc/str/str.h"
// #include <string> // #include <string>
// #include <utility>
// #define ctl std // #define ctl std
using String = ctl::string; using String = ctl::string;

View file

@ -173,5 +173,4 @@ main(int argc, char* argv[])
} }
CheckForMemoryLeaks(); CheckForMemoryLeaks();
return 0;
} }

161
test/ctl/tuple_test.cc Normal file
View file

@ -0,0 +1,161 @@
// -*- mode:c++; indent-tabs-mode:nil; c-basic-offset:4; coding:utf-8 -*-
// vi: set et ft=cpp ts=4 sts=4 sw=4 fenc=utf-8 :vi
//
// Copyright 2024 Justine Alexandra Roberts Tunney
//
// Permission to use, copy, modify, and/or distribute this software for
// any purpose with or without fee is hereby granted, provided that the
// above copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
// WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
// WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
// AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
// DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
// PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
// TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
// PERFORMANCE OF THIS SOFTWARE.
#include "ctl/string.h"
#include "ctl/tuple.h"
#include "libc/mem/leaks.h"
// #include <string>
// #include <tuple>
// #define ctl std
int
test_tuple_creation()
{
ctl::tuple<int, double, ctl::string> t(1, 2.5, "hello");
if (ctl::get<0>(t) != 1 || ctl::get<1>(t) != 2.5 ||
ctl::get<2>(t) != "hello") {
return 1;
}
return 0;
}
int
test_make_tuple()
{
auto t = ctl::make_tuple(1, 2.5, ctl::string("hello"));
if (ctl::get<0>(t) != 1 || ctl::get<1>(t) != 2.5 ||
ctl::get<2>(t) != "hello") {
return 2;
}
return 0;
}
int
test_tuple_get()
{
ctl::tuple<int, double, ctl::string> t(1, 2.5, "hello");
if (ctl::get<0>(t) != 1)
return 3;
if (ctl::get<1>(t) != 2.5)
return 4;
if (ctl::get<2>(t) != "hello")
return 5;
return 0;
}
int
test_tuple_comparison()
{
auto t1 = ctl::make_tuple(1, 2.5, "hello");
auto t2 = ctl::make_tuple(1, 2.5, "hello");
auto t3 = ctl::make_tuple(2, 3.5, "world");
if (!(t1 == t2))
return 6;
if (t1 != t2)
return 7;
if (t1 == t3)
return 8;
if (!(t1 != t3))
return 9;
return 0;
}
int
test_tuple_assignment()
{
ctl::tuple<int, double, ctl::string> t1(1, 2.5, "hello");
ctl::tuple<int, double, ctl::string> t2;
t2 = t1;
if (!(t1 == t2))
return 10;
return 0;
}
int
test_tuple_move()
{
ctl::tuple<int, double, ctl::string> t1(1, 2.5, "hello");
ctl::tuple<int, double, ctl::string> t2(ctl::move(t1));
if (ctl::get<0>(t2) != 1 || ctl::get<1>(t2) != 2.5 ||
ctl::get<2>(t2) != "hello") {
return 11;
}
return 0;
}
int
test_empty_tuple()
{
ctl::tuple<> t;
ctl::tuple<> t2;
if (!(t == t2))
return 12;
return 0;
}
int
test_single_element_tuple()
{
ctl::tuple<int> t(42);
if (ctl::get<0>(t) != 42)
return 13;
return 0;
}
int
main()
{
int result;
result = test_tuple_creation();
if (result != 0)
return result;
result = test_make_tuple();
if (result != 0)
return result;
result = test_tuple_get();
if (result != 0)
return result;
result = test_tuple_comparison();
if (result != 0)
return result;
result = test_tuple_assignment();
if (result != 0)
return result;
result = test_tuple_move();
if (result != 0)
return result;
result = test_empty_tuple();
if (result != 0)
return result;
result = test_single_element_tuple();
if (result != 0)
return result;
CheckForMemoryLeaks();
}

View file

@ -16,7 +16,7 @@
// TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR // TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
// PERFORMANCE OF THIS SOFTWARE. // PERFORMANCE OF THIS SOFTWARE.
#include "ctl/type_traits.h" #include "ctl/is_same.h"
#include "ctl/unique_ptr.h" #include "ctl/unique_ptr.h"
#include "libc/mem/leaks.h" #include "libc/mem/leaks.h"
@ -41,29 +41,30 @@ MkRaw()
return ctl::make_unique_for_overwrite<T>(); return ctl::make_unique_for_overwrite<T>();
} }
#undef ctl // #undef ctl
static int g = 0; static int g = 0;
struct SetsGDeleter struct SetsGDeleter
{ {
void operator()(auto*) const noexcept void operator()(auto* x) const noexcept
{ {
++g; ++g;
delete x;
} }
}; };
struct StatefulDeleter struct StatefulDeleter
{ {
char state; char state;
void operator()(auto*) const noexcept void operator()(auto* x) const noexcept
{ {
} }
}; };
struct FinalDeleter final struct FinalDeleter final
{ {
void operator()(auto*) const noexcept void operator()(auto* x) const noexcept
{ {
} }
}; };
@ -99,6 +100,7 @@ struct Derived : Base
int int
main() main()
{ {
{ {
Ptr<int> x(new int(5)); Ptr<int> x(new int(5));
} }
@ -186,9 +188,9 @@ main()
g = 0; g = 0;
{ {
auto x = Mk<SetsGDtor>(); auto x = Mk<SetsGDtor>();
x.release(); delete x.release();
} }
if (g) if (g != 1)
return 13; return 13;
} }
@ -224,8 +226,5 @@ main()
Ptr<Base> z(ctl::move(y)); Ptr<Base> z(ctl::move(y));
} }
// next is 18 CheckForMemoryLeaks();
// TODO(mrdomino): Fix memory leaks reported by MODE=dbg
// CheckForMemoryLeaks();
} }