diff --git a/ctl/add_lvalue_reference.h b/ctl/add_lvalue_reference.h new file mode 100644 index 000000000..9d0c48b1d --- /dev/null +++ b/ctl/add_lvalue_reference.h @@ -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 +struct add_lvalue_reference +{ + typedef T& type; +}; + +template +struct add_lvalue_reference +{ + typedef T& type; +}; + +template +struct add_lvalue_reference +{ + typedef T& type; +}; + +template<> +struct add_lvalue_reference +{ + typedef void type; +}; + +template<> +struct add_lvalue_reference +{ + typedef const void type; +}; + +template<> +struct add_lvalue_reference +{ + typedef volatile void type; +}; + +template<> +struct add_lvalue_reference +{ + typedef const volatile void type; +}; + +template +using add_lvalue_reference_t = typename add_lvalue_reference::type; + +} // namespace ctl + +#endif // CTL_ADD_LVALUE_REFERENCE_H_ diff --git a/ctl/add_pointer.h b/ctl/add_pointer.h new file mode 100644 index 000000000..005a4a09a --- /dev/null +++ b/ctl/add_pointer.h @@ -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 +struct add_pointer +{ + typedef typename remove_reference::type* type; +}; + +// Specialization for functions +template +struct add_pointer +{ + typedef R (*type)(Args...); +}; + +// Specialization for function references +template +struct add_pointer +{ + typedef R (*type)(Args...); +}; + +// Specialization for rvalue references to functions +template +struct add_pointer +{ + typedef R (*type)(Args...); +}; + +// Helper alias template (C++14 and later) +template +using add_pointer_t = typename add_pointer::type; + +} // namespace ctl + +#endif // CTL_ADD_POINTER_H_ diff --git a/ctl/all_of.h b/ctl/all_of.h index 8934668a2..0c258bc4a 100644 --- a/ctl/all_of.h +++ b/ctl/all_of.h @@ -9,11 +9,9 @@ template constexpr bool all_of(InputIt first, InputIt last, UnaryPredicate p) { - for (; first != last; ++first) { - if (!p(*first)) { + for (; first != last; ++first) + if (!p(*first)) return false; - } - } return true; } diff --git a/ctl/allocator.h b/ctl/allocator.h index b084f10e9..3a593d363 100644 --- a/ctl/allocator.h +++ b/ctl/allocator.h @@ -3,8 +3,8 @@ #ifndef CTL_ALLOCATOR_H_ #define CTL_ALLOCATOR_H_ #include "bad_alloc.h" +#include "integral_constant.h" #include "new.h" -#include "type_traits.h" #include "utility.h" namespace ctl { diff --git a/ctl/allocator_traits.h b/ctl/allocator_traits.h index 42d43d84d..ebdf03424 100644 --- a/ctl/allocator_traits.h +++ b/ctl/allocator_traits.h @@ -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_ #define CTL_ALLOCATOR_TRAITS_H_ -#include "type_traits.h" +#include "integral_constant.h" namespace ctl { diff --git a/ctl/any_of.h b/ctl/any_of.h index 7eec80605..09c9bcfbd 100644 --- a/ctl/any_of.h +++ b/ctl/any_of.h @@ -9,11 +9,9 @@ template constexpr bool any_of(InputIt first, InputIt last, UnaryPredicate p) { - for (; first != last; ++first) { - if (p(*first)) { + for (; first != last; ++first) + if (p(*first)) return true; - } - } return false; } diff --git a/ctl/array.h b/ctl/array.h index fda2ddd04..a2b5925b5 100644 --- a/ctl/array.h +++ b/ctl/array.h @@ -3,6 +3,7 @@ #ifndef CTL_ARRAY_H_ #define CTL_ARRAY_H_ #include "initializer_list.h" +#include "out_of_range.h" #include "reverse_iterator.h" namespace ctl { @@ -25,25 +26,25 @@ struct array T elems[N]; constexpr array() = default; + constexpr array(std::initializer_list init) { 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; - } } constexpr reference at(size_type pos) { if (pos >= N) - __builtin_trap(); + throw ctl::out_of_range("out of range"); return elems[pos]; } constexpr const_reference at(size_type pos) const { if (pos >= N) - __builtin_trap(); + throw ctl::out_of_range("out of range"); return elems[pos]; } diff --git a/ctl/conditional.h b/ctl/conditional.h new file mode 100644 index 000000000..976143a1d --- /dev/null +++ b/ctl/conditional.h @@ -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 +struct conditional +{ + typedef T type; +}; + +template +struct conditional +{ + typedef F type; +}; + +} // namespace ctl + +#endif // CTL_CONDITIONAL_H_ diff --git a/ctl/decay.h b/ctl/decay.h new file mode 100644 index 000000000..6c4fe6f2a --- /dev/null +++ b/ctl/decay.h @@ -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 +struct decay +{ + private: + typedef typename remove_reference::type U; + + public: + typedef typename conditional< + is_array::value, + typename remove_extent::type*, + typename conditional::value, + typename add_pointer::type, + typename remove_cv::type>::type>::type type; +}; + +template +using decay_t = typename decay::type; + +} // namespace ctl + +#endif // CTL_DECAY_H_ diff --git a/ctl/default_delete.h b/ctl/default_delete.h new file mode 100644 index 000000000..4a3458369 --- /dev/null +++ b/ctl/default_delete.h @@ -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 +struct default_delete +{ + constexpr default_delete() noexcept = default; + template::value>::type> + constexpr default_delete(const default_delete&) noexcept + { + } + constexpr void operator()(T* const p) const noexcept + { + delete p; + } +}; + +template +struct default_delete +{ + constexpr default_delete() noexcept = default; + template::value>::type> + constexpr default_delete(const default_delete&) noexcept + { + } + constexpr void operator()(T* const p) const noexcept + { + delete[] p; + } +}; + +} // namespace ctl + +#endif // CTL_DEFAULT_DELETE_H_ diff --git a/ctl/enable_if.h b/ctl/enable_if.h index 70cb862a3..9c61957a4 100644 --- a/ctl/enable_if.h +++ b/ctl/enable_if.h @@ -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_ #define CTL_ENABLE_IF_H_ diff --git a/ctl/integral_constant.h b/ctl/integral_constant.h new file mode 100644 index 000000000..df5a0a688 --- /dev/null +++ b/ctl/integral_constant.h @@ -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 +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 true_type; +typedef integral_constant false_type; + +} // namespace ctl + +#endif // CTL_INTEGRAL_CONSTANT_H_ diff --git a/ctl/is_array.h b/ctl/is_array.h new file mode 100644 index 000000000..946d152ea --- /dev/null +++ b/ctl/is_array.h @@ -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 +struct is_array : false_type +{}; + +template +struct is_array : true_type +{}; + +template +struct is_array : true_type +{}; + +template +inline constexpr bool is_array_v = is_array::value; + +} // namespace ctl + +#endif // CTL_IS_ARRAY_H_ diff --git a/ctl/is_convertible.h b/ctl/is_convertible.h new file mode 100644 index 000000000..9b81747e8 --- /dev/null +++ b/ctl/is_convertible.h @@ -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 +T&& +declval() noexcept; + +namespace detail { + +template +struct is_convertible_impl : false_type +{}; + +template +struct is_convertible_impl(declval()))>> + : true_type +{}; + +// Handle void types separately +template<> +struct is_convertible_impl : true_type +{}; + +template +struct is_convertible_impl : false_type +{}; + +template +struct is_convertible_impl : false_type +{}; + +} // namespace detail + +template +struct is_convertible : detail::is_convertible_impl +{}; + +// Helper variable template (C++17 and later) +template +inline constexpr bool is_convertible_v = is_convertible::value; + +} // namespace ctl + +#endif // CTL_IS_CONVERTIBLE_H_ diff --git a/ctl/is_function.h b/ctl/is_function.h new file mode 100644 index 000000000..667a1e8eb --- /dev/null +++ b/ctl/is_function.h @@ -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 +struct is_function : false_type +{}; + +// Specializations for various function types + +// Regular functions +template +struct is_function : true_type +{}; + +// Functions with cv-qualifiers +template +struct is_function : true_type +{}; + +template +struct is_function : true_type +{}; + +template +struct is_function : true_type +{}; + +// Functions with ref-qualifiers +template +struct is_function : true_type +{}; + +template +struct is_function : true_type +{}; + +template +struct is_function : true_type +{}; + +template +struct is_function : true_type +{}; + +template +struct is_function : true_type +{}; + +template +struct is_function : true_type +{}; + +template +struct is_function : true_type +{}; + +template +struct is_function : true_type +{}; + +// Variadic functions +template +struct is_function : true_type +{}; + +// Variadic functions with cv-qualifiers +template +struct is_function : true_type +{}; + +template +struct is_function : true_type +{}; + +template +struct is_function : true_type +{}; + +// Variadic functions with ref-qualifiers +template +struct is_function : true_type +{}; + +template +struct is_function : true_type +{}; + +template +struct is_function : true_type +{}; + +template +struct is_function : true_type +{}; + +template +struct is_function : true_type +{}; + +template +struct is_function : true_type +{}; + +template +struct is_function : true_type +{}; + +template +struct is_function : true_type +{}; + +} // namespace ctl + +#endif // CTL_IS_FUNCTION_H_ diff --git a/ctl/type_traits.h b/ctl/is_integral.h similarity index 55% rename from ctl/type_traits.h rename to ctl/is_integral.h index c9dea8584..384985a38 100644 --- a/ctl/type_traits.h +++ b/ctl/is_integral.h @@ -1,29 +1,11 @@ // -*-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_TYPE_TRAITS_H_ -#define CTL_TYPE_TRAITS_H_ +#ifndef CTL_IS_INTEGRAL_H_ +#define CTL_IS_INTEGRAL_H_ +#include "integral_constant.h" namespace ctl { -template -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; -using false_type = integral_constant; - template struct is_integral : false_type {}; @@ -91,33 +73,6 @@ struct is_integral : true_type template inline constexpr bool is_integral_v = is_integral::value; -template -struct is_signed -{ - static constexpr bool value = T(0) > T(-1); -}; - -template -struct is_unsigned -{ - static constexpr bool value = T(0) < T(-1); -}; - -template -struct is_same -{ - static constexpr bool value = false; -}; - -template -struct is_same -{ - static constexpr bool value = true; -}; - -template -inline constexpr bool is_same_v = is_same::value; - } // namespace ctl -#endif // CTL_TYPE_TRAITS_H_ +#endif // CTL_IS_INTEGRAL_H_ diff --git a/ctl/is_reference.h b/ctl/is_reference.h new file mode 100644 index 000000000..66ae107b6 --- /dev/null +++ b/ctl/is_reference.h @@ -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 +struct is_reference +{ + static constexpr bool value = false; +}; + +// Specialization for lvalue reference +template +struct is_reference +{ + static constexpr bool value = true; +}; + +// Specialization for rvalue reference +template +struct is_reference +{ + static constexpr bool value = true; +}; + +// Helper variable template (C++14 and later) +template +inline constexpr bool is_reference_v = is_reference::value; + +} // namespace ctl + +#endif // CTL_IS_REFERENCE_H_ diff --git a/ctl/is_same.h b/ctl/is_same.h new file mode 100644 index 000000000..44c09761b --- /dev/null +++ b/ctl/is_same.h @@ -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 +struct is_same +{ + static constexpr bool value = false; +}; + +template +struct is_same +{ + static constexpr bool value = true; +}; + +template +inline constexpr bool is_same_v = is_same::value; + +} // namespace ctl + +#endif // CTL_IS_SAME_H_ diff --git a/ctl/is_signed.h b/ctl/is_signed.h new file mode 100644 index 000000000..2c911ee4c --- /dev/null +++ b/ctl/is_signed.h @@ -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 +struct is_signed +{ + static constexpr bool value = T(0) > T(-1); +}; + +} // namespace ctl + +#endif // CTL_IS_SIGNED_H_ diff --git a/ctl/is_sorted.h b/ctl/is_sorted.h new file mode 100644 index 000000000..551cce9da --- /dev/null +++ b/ctl/is_sorted.h @@ -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 +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_ diff --git a/ctl/is_unsigned.h b/ctl/is_unsigned.h new file mode 100644 index 000000000..02f276a7c --- /dev/null +++ b/ctl/is_unsigned.h @@ -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 +struct is_unsigned +{ + static constexpr bool value = T(0) < T(-1); +}; + +} // namespace ctl + +#endif // CTL_IS_UNSIGNED_H_ diff --git a/ctl/move_iterator.h b/ctl/move_iterator.h index 8ce1ed05b..2527eca3b 100644 --- a/ctl/move_iterator.h +++ b/ctl/move_iterator.h @@ -1,7 +1,6 @@ #ifndef CTL_MOVE_ITERATOR_H_ #define CTL_MOVE_ITERATOR_H_ #include "iterator_traits.h" -#include "type_traits.h" namespace ctl { diff --git a/ctl/mutex.h b/ctl/mutex.h new file mode 100644 index 000000000..28a21e2e7 --- /dev/null +++ b/ctl/mutex.h @@ -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_ diff --git a/ctl/numeric_limits.h b/ctl/numeric_limits.h index 5693a62e2..41aea3ae2 100644 --- a/ctl/numeric_limits.h +++ b/ctl/numeric_limits.h @@ -2,7 +2,8 @@ // vi: set et ft=cpp ts=4 sts=4 sw=4 fenc=utf-8 :vi #ifndef CTL_NUMERIC_LIMITS_H_ #define CTL_NUMERIC_LIMITS_H_ -#include "type_traits.h" +#include "is_integral.h" +#include "is_unsigned.h" namespace ctl { diff --git a/ctl/partition.h b/ctl/partition.h new file mode 100644 index 000000000..a1db21fb2 --- /dev/null +++ b/ctl/partition.h @@ -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 +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_ diff --git a/ctl/remove_cv.h b/ctl/remove_cv.h new file mode 100644 index 000000000..2801f7d80 --- /dev/null +++ b/ctl/remove_cv.h @@ -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 +struct remove_const +{ + typedef T type; +}; + +template +struct remove_const +{ + typedef T type; +}; + +template +struct remove_volatile +{ + typedef T type; +}; + +template +struct remove_volatile +{ + typedef T type; +}; + +template +struct remove_cv +{ + typedef typename remove_volatile::type>::type type; +}; + +template +using remove_const_t = typename remove_const::type; + +template +using remove_volatile_t = typename remove_volatile::type; + +template +using remove_cv_t = typename remove_cv::type; + +} // namespace ctl + +#endif // CTL_REMOVE_CV_H_ diff --git a/ctl/remove_extent.h b/ctl/remove_extent.h new file mode 100644 index 000000000..7aef1d20a --- /dev/null +++ b/ctl/remove_extent.h @@ -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 +struct remove_extent +{ + typedef T type; +}; + +template +struct remove_extent +{ + typedef T type; +}; + +template +struct remove_extent +{ + typedef T type; +}; + +template +using remove_extent_t = typename remove_extent::type; + +} // namespace ctl + +#endif // CTL_REMOVE_EXTENT_H_ diff --git a/ctl/remove_reference.h b/ctl/remove_reference.h new file mode 100644 index 000000000..3e773e0ce --- /dev/null +++ b/ctl/remove_reference.h @@ -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 +struct remove_reference +{ + typedef T type; +}; + +template +struct remove_reference +{ + typedef T type; +}; + +template +struct remove_reference +{ + typedef T type; +}; + +template +using remove_reference_t = typename remove_reference::type; + +} // namespace ctl + +#endif // CTL_REMOVE_REFERENCE_H_ diff --git a/ctl/runtime_error.h b/ctl/runtime_error.h new file mode 100644 index 000000000..29cc5f301 --- /dev/null +++ b/ctl/runtime_error.h @@ -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_ diff --git a/ctl/sort.h b/ctl/sort.h new file mode 100644 index 000000000..fb5a3d6c2 --- /dev/null +++ b/ctl/sort.h @@ -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 +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 +void +sort(RandomIt first, RandomIt last, Compare comp) +{ + detail::quicksort(first, last, comp); +} + +template +void +sort(RandomIt first, RandomIt last) +{ + sort(first, + last, + ctl::less::value_type>()); +} + +} // namespace ctl + +#endif // CTL_SORT_H_ diff --git a/ctl/strcat.cc b/ctl/strcat.cc index 0e7c49070..a00cf0e59 100644 --- a/ctl/strcat.cc +++ b/ctl/strcat.cc @@ -38,9 +38,9 @@ strcat(const string_view lhs, const string_view rhs) noexcept if (rhs.n) memcpy(res.data() + lhs.n, rhs.p, rhs.n); if (res.isbig()) { - res.big()->n = lhs.n + rhs.n; + res.__b.n = lhs.n + rhs.n; } else { - res.small()->rem = __::sso_max - lhs.n - rhs.n; + res.__s.rem = __::sso_max - lhs.n - rhs.n; } res.data()[res.size()] = 0; return res; diff --git a/ctl/string.cc b/ctl/string.cc index 08ee1e65d..064882178 100644 --- a/ctl/string.cc +++ b/ctl/string.cc @@ -26,7 +26,7 @@ namespace ctl { void string::destroy_big() noexcept { - auto* b = big(); + auto* b = &__b; if (b->n) { if (b->n >= b->c) __builtin_trap(); @@ -41,7 +41,14 @@ string::destroy_big() noexcept void 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 @@ -103,7 +110,7 @@ string::reserve(size_t c2) noexcept __builtin_trap(); memcpy(p2, data(), __::string_size); } else { - if (!(p2 = (char*)realloc(big()->p, c2))) + if (!(p2 = (char*)realloc(__b.p, c2))) __builtin_trap(); } 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()) memset(data() + size(), ch, n2 - size()); if (isbig()) { - big()->p[big()->n = n2] = 0; + __b.p[__b.n = n2] = 0; } else { set_small_size(n2); data()[size()] = 0; @@ -141,9 +148,9 @@ string::append(const char ch) noexcept } data()[size()] = ch; if (isbig()) { - ++big()->n; + ++__b.n; } else { - --small()->rem; + --__s.rem; } data()[size()] = 0; } @@ -174,9 +181,9 @@ string::append(const char ch, const size_t size) noexcept if (size) memset(data() + this->size(), ch, size); if (isbig()) { - big()->n += size; + __b.n += size; } else { - small()->rem -= size; + __s.rem -= size; } data()[this->size()] = 0; } @@ -188,9 +195,9 @@ string::append(const void* data, const size_t size) noexcept if (size) memcpy(this->data() + this->size(), data, size); if (isbig()) { - big()->n += size; + __b.n += size; } else { - small()->rem -= size; + __s.rem -= size; } this->data()[this->size()] = 0; } @@ -201,9 +208,9 @@ string::pop_back() noexcept if (!size()) __builtin_trap(); if (isbig()) { - --big()->n; + --__b.n; } else { - ++small()->rem; + ++__s.rem; } data()[size()] = 0; } @@ -322,7 +329,7 @@ string::replace(const size_t pos, memmove(data() + pos + s.n, data() + last, extra); memcpy(data() + pos, s.p, s.n); if (isbig()) { - big()->p[big()->n = need] = 0; + __b.p[__b.n = need] = 0; } else { set_small_size(need); 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); memcpy(data() + i, s.p, s.n); if (isbig()) { - big()->n += s.n; + __b.n += s.n; } else { - small()->rem -= s.n; + __s.rem -= s.n; } data()[size()] = 0; return *this; @@ -365,7 +372,7 @@ string::erase(const size_t pos, size_t count) noexcept if (extra) memmove(data() + pos, data() + pos + count, extra); if (isbig()) { - big()->n = pos + extra; + __b.n = pos + extra; } else { set_small_size(pos + extra); } diff --git a/ctl/string.h b/ctl/string.h index 69a9cf1b7..ba0ee6223 100644 --- a/ctl/string.h +++ b/ctl/string.h @@ -151,7 +151,7 @@ class string void clear() noexcept { if (isbig()) { - big()->n = 0; + __b.n = 0; } else { set_small_size(0); } @@ -159,26 +159,26 @@ class string 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 (!isbig() && small()->rem > __::sso_max) + if (!isbig() && __s.rem > __::sso_max) __builtin_trap(); #endif - return isbig() ? big()->n : __::sso_max - small()->rem; + return isbig() ? __b.n : __::sso_max - __s.rem; } size_t length() const noexcept @@ -189,10 +189,10 @@ class string size_t capacity() const noexcept { #if 0 - if (isbig() && big()->c <= __::sso_max) + if (isbig() && __b.c <= __::sso_max) __builtin_trap(); #endif - return isbig() ? __::big_mask & big()->c : __::string_size; + return isbig() ? __::big_mask & __b.c : __::string_size; } iterator begin() noexcept @@ -374,7 +374,7 @@ class string void init_big(string_view) noexcept; void init_big(size_t, char) noexcept; - bool isbig() const noexcept + __attribute__((__always_inline__)) bool isbig() const noexcept { return *(blob + __::sso_max) & 0x80; } @@ -395,34 +395,6 @@ class string __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; union diff --git a/ctl/tuple.h b/ctl/tuple.h new file mode 100644 index 000000000..dcea0f15f --- /dev/null +++ b/ctl/tuple.h @@ -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 +class tuple; + +// Base case for tuple +template<> +class tuple<> +{}; + +// Recursive case for tuple +template +class tuple : public tuple +{ + using Base = tuple; + + public: + Head head; + + constexpr tuple() : Base(), head() + { + } + + template::type, tuple>::value>::type> + constexpr tuple(H&& h, T&&... t) + : Base(ctl::forward(t)...), head(ctl::forward(h)) + { + } + + template + constexpr tuple(const tuple& other) + : Base(static_cast&>(other)), head(other.head) + { + } + + template + constexpr tuple(tuple&& other) + : Base(static_cast&&>(other)) + , head(ctl::forward(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 +struct tuple_element; + +template +struct tuple_element> + : tuple_element> +{}; + +template +struct tuple_element<0, tuple> +{ + using type = Head; +}; + +// Helper function to get element +template +constexpr typename tuple_element>::type& +get(tuple& t) +{ + if constexpr (I == 0) { + return t.head; + } else { + return get(static_cast&>(t)); + } +} + +template +constexpr const typename tuple_element>::type& +get(const tuple& t) +{ + if constexpr (I == 0) { + return t.head; + } else { + return get(static_cast&>(t)); + } +} + +// Helper function to create a tuple +template +constexpr tuple::type...> +make_tuple(Types&&... args) +{ + return tuple::type...>( + ctl::forward(args)...); +} + +// Helper function for tuple comparison +template +constexpr bool +tuple_equals(const tuple& t, const tuple& u) +{ + if constexpr (I == sizeof...(TTypes)) { + return true; + } else { + return get(t) == get(u) && tuple_equals(t, u); + } +} + +// Equality comparison +template +constexpr bool +operator==(const tuple& t, const tuple& u) +{ + return tuple_equals(t, u); +} + +template +constexpr bool +operator!=(const tuple& t, const tuple& u) +{ + return !(t == u); +} + +} // namespace ctl + +#endif // CTL_TUPLE_H_ diff --git a/ctl/unique_lock.h b/ctl/unique_lock.h new file mode 100644 index 000000000..6568a408e --- /dev/null +++ b/ctl/unique_lock.h @@ -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_ diff --git a/ctl/unique_ptr.cc b/ctl/unique_ptr.cc deleted file mode 100644 index daeda3b1b..000000000 --- a/ctl/unique_ptr.cc +++ /dev/null @@ -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" diff --git a/ctl/unique_ptr.h b/ctl/unique_ptr.h index c2ebae7ba..5027d5ec1 100644 --- a/ctl/unique_ptr.h +++ b/ctl/unique_ptr.h @@ -1,41 +1,17 @@ // -*-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 COSMOPOLITAN_CTL_UNIQUE_PTR_H_ -#define COSMOPOLITAN_CTL_UNIQUE_PTR_H_ +#ifndef 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 <__type_traits/is_convertible.h> namespace ctl { -template -struct default_delete -{ - constexpr default_delete() noexcept = default; - template - constexpr default_delete(default_delete&&) noexcept - { - } - constexpr void operator()(T* const p) const noexcept - { - delete p; - } -}; - -template -struct default_delete -{ - constexpr default_delete() noexcept = default; - template - constexpr default_delete(default_delete&&) noexcept - { - } - constexpr void operator()(T* const p) const noexcept - { - delete[] p; - } -}; - -template> +template> struct unique_ptr { 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 - : p(p), d(ctl::forward(d)) + constexpr unique_ptr(pointer p, const D& d) noexcept : p(p), d(d) + { + } + + constexpr unique_ptr(pointer p, D&& d) noexcept : p(p), d(ctl::move(d)) { } template - requires std::is_convertible_v && std::is_convertible_v constexpr unique_ptr(unique_ptr&& u) noexcept - : p(u.p), d(ctl::move(u.d)) + : p(u.release()), d(ctl::forward(u.get_deleter())) { - u.p = nullptr; + static_assert(ctl::is_convertible::pointer, + pointer>::value, + "U* must be implicitly convertible to T*"); + static_assert( + (ctl::is_reference::value && ctl::is_same::value) || + (!ctl::is_reference::value && ctl::is_convertible::value), + "The deleter must be convertible to the target deleter type"); } unique_ptr(const unique_ptr&) = delete; - constexpr ~unique_ptr() /* noexcept */ + constexpr ~unique_ptr() noexcept { if (p) d(p); @@ -80,6 +64,20 @@ struct unique_ptr return *this; } + template + constexpr unique_ptr& operator=(unique_ptr&& r) noexcept + { + reset(r.release()); + d = ctl::forward(r.get_deleter()); + return *this; + } + + constexpr unique_ptr& operator=(nullptr_t) noexcept + { + reset(); + return *this; + } + constexpr pointer release() noexcept { pointer r = p; @@ -87,12 +85,12 @@ struct unique_ptr 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; - if (r) - d(r); + if (old) + d(old); } constexpr void swap(unique_ptr& r) noexcept @@ -119,20 +117,16 @@ struct unique_ptr constexpr explicit operator bool() const noexcept { - return p; + return p != nullptr; } - element_type& operator*() const noexcept(noexcept(*ctl::declval())) + constexpr typename ctl::add_lvalue_reference::type operator*() const { - if (!p) - __builtin_trap(); return *p; } - pointer operator->() const noexcept + constexpr pointer operator->() const noexcept { - if (!p) - __builtin_trap(); return p; } }; @@ -148,16 +142,9 @@ template constexpr unique_ptr make_unique_for_overwrite() { -#if 0 - // You'd think that it'd work like this, but std::unique_ptr does not. - return unique_ptr( - static_cast(::operator new(sizeof(T), align_val_t(alignof(T))))); -#else return unique_ptr(new T); -#endif } -// TODO(mrdomino): specializations for T[] - } // namespace ctl -#endif // COSMOPOLITAN_CTL_UNIQUE_PTR_H_ + +#endif // CTL_UNIQUE_PTR_H_ diff --git a/ctl/utility.cc b/ctl/utility.cc deleted file mode 100644 index a4c2a2008..000000000 --- a/ctl/utility.cc +++ /dev/null @@ -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" diff --git a/ctl/utility.h b/ctl/utility.h index 62036ca04..464e04f64 100644 --- a/ctl/utility.h +++ b/ctl/utility.h @@ -2,6 +2,7 @@ // vi: set et ft=cpp ts=4 sts=4 sw=4 fenc=utf-8 :vi #ifndef COSMOPOLITAN_CTL_UTILITY_H_ #define COSMOPOLITAN_CTL_UTILITY_H_ +#include "remove_reference.h" namespace ctl { @@ -18,6 +19,14 @@ using no_infer = typename no_infer_::type; } // namespace __ +template +constexpr T&& +move(T&& t) noexcept +{ + typedef remove_reference_t U; + return static_cast(t); +} + template constexpr T&& move(T& t) noexcept @@ -47,9 +56,8 @@ template constexpr void 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]); - } } template diff --git a/ctl/void_t.h b/ctl/void_t.h new file mode 100644 index 000000000..c4573260e --- /dev/null +++ b/ctl/void_t.h @@ -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 +using void_t = void; + +} // namespace ctl + +#endif // CTL_VOID_T_H_ diff --git a/libc/runtime/dsohandle.S b/libc/intrin/dsohandle.S similarity index 100% rename from libc/runtime/dsohandle.S rename to libc/intrin/dsohandle.S diff --git a/test/ctl/BUILD.mk b/test/ctl/BUILD.mk index 439d7e786..2bdcf5381 100644 --- a/test/ctl/BUILD.mk +++ b/test/ctl/BUILD.mk @@ -18,6 +18,7 @@ TEST_CTL_DIRECTDEPS = \ LIBC_INTRIN \ LIBC_MEM \ LIBC_STDIO \ + LIBC_THREAD \ THIRD_PARTY_LIBCXX \ THIRD_PARTY_LIBCXXABI \ THIRD_PARTY_LIBUNWIND \ diff --git a/test/ctl/accumulate_test.cc b/test/ctl/accumulate_test.cc index ff29e278e..3145e18e2 100644 --- a/test/ctl/accumulate_test.cc +++ b/test/ctl/accumulate_test.cc @@ -18,6 +18,7 @@ #include "ctl/accumulate.h" #include "ctl/array.h" +#include "libc/mem/leaks.h" // #include // #include @@ -48,4 +49,6 @@ main() // Test accumulation with single element if (ctl::accumulate(arr.begin(), arr.begin() + 1, 0) != 1) return 5; + + CheckForMemoryLeaks(); } diff --git a/test/ctl/advance_test.cc b/test/ctl/advance_test.cc index 90b381bd5..e0782ba35 100644 --- a/test/ctl/advance_test.cc +++ b/test/ctl/advance_test.cc @@ -18,6 +18,7 @@ #include "ctl/advance.h" #include "ctl/array.h" +#include "libc/mem/leaks.h" // #include // #include @@ -53,4 +54,6 @@ main() ctl::advance(it, -2); if (it != arr.begin()) return 5; + + CheckForMemoryLeaks(); } diff --git a/test/ctl/all_of_test.cc b/test/ctl/all_of_test.cc index 5f38e441b..4bc090b67 100644 --- a/test/ctl/all_of_test.cc +++ b/test/ctl/all_of_test.cc @@ -18,6 +18,7 @@ #include "ctl/all_of.h" #include "ctl/array.h" +#include "libc/mem/leaks.h" #include #include @@ -49,4 +50,6 @@ main() // Test with no elements satisfying the condition if (ctl::all_of(arr1.begin(), arr1.end(), [](int n) { return n > 10; })) return 5; + + CheckForMemoryLeaks(); } diff --git a/test/ctl/any_of_test.cc b/test/ctl/any_of_test.cc index 02ba6928d..ee08afd3e 100644 --- a/test/ctl/any_of_test.cc +++ b/test/ctl/any_of_test.cc @@ -18,6 +18,7 @@ #include "ctl/any_of.h" #include "ctl/array.h" +#include "libc/mem/leaks.h" // #include // #include @@ -48,4 +49,6 @@ main() // Test with a different condition if (!ctl::any_of(arr1.begin(), arr1.end(), [](int n) { return n > 5; })) return 5; + + CheckForMemoryLeaks(); } diff --git a/test/ctl/array_test.cc b/test/ctl/array_test.cc index 5fd8dbe54..40f774173 100644 --- a/test/ctl/array_test.cc +++ b/test/ctl/array_test.cc @@ -17,8 +17,11 @@ // PERFORMANCE OF THIS SOFTWARE. #include "ctl/array.h" +#include "ctl/string.h" +#include "libc/mem/leaks.h" // #include +// #include // #define ctl std int @@ -264,4 +267,21 @@ main() if (rit != arr.rend()) return 4; } + + { + ctl::array 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(); } diff --git a/test/ctl/back_inserter_test.cc b/test/ctl/back_inserter_test.cc index 38659b10e..122493952 100644 --- a/test/ctl/back_inserter_test.cc +++ b/test/ctl/back_inserter_test.cc @@ -20,6 +20,7 @@ #include "ctl/back_inserter.h" #include "ctl/copy.h" #include "ctl/vector.h" +#include "libc/mem/leaks.h" // #include // #include @@ -29,33 +30,38 @@ int main() { - ctl::vector vec = { 1, 2, 3 }; - ctl::array 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 vec = { 1, 2, 3 }; + ctl::array arr = { 4, 5, 6 }; - // Check if vec now contains all elements - 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; + // Use back_inserter to append elements from arr to vec + ctl::copy(arr.begin(), arr.end(), ctl::back_inserter(vec)); - // Use back_inserter with a single element - ctl::back_inserter(vec) = 7; + // Check if vec now contains all elements + 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 - if (vec.size() != 7) - return 3; - if (vec[6] != 7) - return 4; + // Use back_inserter with a single element + ctl::back_inserter(vec) = 7; - // Test with an empty source range - ctl::array empty_arr; - ctl::copy(empty_arr.begin(), empty_arr.end(), ctl::back_inserter(vec)); + // Check if the new element was added + if (vec.size() != 7) + return 3; + if (vec[6] != 7) + return 4; - // Check that no elements were added - if (vec.size() != 7) - return 5; + // Test with an empty source range + ctl::array empty_arr; + 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(); } diff --git a/test/ctl/copy_test.cc b/test/ctl/copy_test.cc index 868bbee97..2c417186a 100644 --- a/test/ctl/copy_test.cc +++ b/test/ctl/copy_test.cc @@ -18,49 +18,56 @@ #include "ctl/array.h" #include "ctl/copy.h" +#include "libc/mem/leaks.h" -// #include +// #include // #include +// #include // #define ctl std int main() { - ctl::array src = { 1, 2, 3, 4, 5 }; - ctl::array dest = { 0, 0, 0, 0, 0 }; - // 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; + { + ctl::array src = { 1, 2, 3, 4, 5 }; + ctl::array dest = { 0, 0, 0, 0, 0 }; + + // 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 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 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 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 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 - ctl::array 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 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 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 dest5 = { 0, 0, 0, 0, 0 }; - auto result = ctl::copy(src.begin(), src.end(), dest5.begin()); - if (result != dest5.end()) - return 5; + CheckForMemoryLeaks(); } diff --git a/test/ctl/mutex_test.cc b/test/ctl/mutex_test.cc new file mode 100644 index 000000000..9c03d08c8 --- /dev/null +++ b/test/ctl/mutex_test.cc @@ -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 +// #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(); +} diff --git a/test/ctl/sort_test.cc b/test/ctl/sort_test.cc new file mode 100644 index 000000000..2acc59917 --- /dev/null +++ b/test/ctl/sort_test.cc @@ -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 +// #include +// #include +// #define ctl std + +// Test sorting integers +int +test_sort_integers() +{ + ctl::vector 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())) + return 1; + return 0; +} + +// Test sorting with custom comparator +int +test_sort_custom_compare() +{ + ctl::vector 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 v = { "banana", "apple", "cherry", "date" }; + ctl::sort(v.begin(), v.end()); + if (!ctl::is_sorted(v.begin(), v.end(), ctl::less())) + return 3; + return 0; +} + +// Test sorting with large number of elements +int +test_sort_large() +{ + const int SIZE = 10000; + ctl::vector 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())) + return 4; + return 0; +} + +// Test sorting already sorted vector +int +test_sort_sorted() +{ + ctl::vector 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())) + return 5; + return 0; +} + +// Test sorting reverse sorted vector +int +test_sort_reverse() +{ + ctl::vector 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())) + 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(); +} diff --git a/test/ctl/string_bench.cc b/test/ctl/string_bench.cc index c59695dd1..b7b30c935 100644 --- a/test/ctl/string_bench.cc +++ b/test/ctl/string_bench.cc @@ -17,8 +17,8 @@ // PERFORMANCE OF THIS SOFTWARE. #include "ctl/string.h" - -#include <__utility/move.h> +#include "ctl/utility.h" +#include "libc/mem/leaks.h" #include "libc/calls/struct/timespec.h" #include "libc/runtime/runtime.h" @@ -100,7 +100,7 @@ main() BENCH(1000000, 1, { ctl::string s(small); - ctl::string s2(std::move(s)); + ctl::string s2(ctl::move(s)); }); BENCH(1000000, 1, { @@ -119,7 +119,7 @@ main() BENCH(1000000, 1, { ctl::string s(big); - ctl::string s2(std::move(s)); + ctl::string s2(ctl::move(s)); }); BENCH(1000000, 1, { @@ -142,5 +142,5 @@ main() BENCH(1000000, 1, { ctl::string s(big_trunc); }); } - return 0; + CheckForMemoryLeaks(); } diff --git a/test/ctl/string_test.cc b/test/ctl/string_test.cc index a3fd1f461..90b19e9c8 100644 --- a/test/ctl/string_test.cc +++ b/test/ctl/string_test.cc @@ -16,13 +16,14 @@ // TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR // PERFORMANCE OF THIS SOFTWARE. +#include "ctl/is_same.h" #include "ctl/string.h" -#include "ctl/type_traits.h" #include "libc/mem/leaks.h" #include "libc/str/str.h" // #include +// #include // #define ctl std using String = ctl::string; diff --git a/test/ctl/string_view_test.cc b/test/ctl/string_view_test.cc index 8ca1f8bee..a82743e15 100644 --- a/test/ctl/string_view_test.cc +++ b/test/ctl/string_view_test.cc @@ -173,5 +173,4 @@ main(int argc, char* argv[]) } CheckForMemoryLeaks(); - return 0; } diff --git a/test/ctl/tuple_test.cc b/test/ctl/tuple_test.cc new file mode 100644 index 000000000..0a3da6c6f --- /dev/null +++ b/test/ctl/tuple_test.cc @@ -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 +// #include +// #define ctl std + +int +test_tuple_creation() +{ + ctl::tuple 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 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 t1(1, 2.5, "hello"); + ctl::tuple t2; + t2 = t1; + if (!(t1 == t2)) + return 10; + return 0; +} + +int +test_tuple_move() +{ + ctl::tuple t1(1, 2.5, "hello"); + ctl::tuple 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 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(); +} diff --git a/test/ctl/unique_ptr_test.cc b/test/ctl/unique_ptr_test.cc index 87e4f30f2..75ed674ba 100644 --- a/test/ctl/unique_ptr_test.cc +++ b/test/ctl/unique_ptr_test.cc @@ -16,7 +16,7 @@ // TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR // PERFORMANCE OF THIS SOFTWARE. -#include "ctl/type_traits.h" +#include "ctl/is_same.h" #include "ctl/unique_ptr.h" #include "libc/mem/leaks.h" @@ -41,29 +41,30 @@ MkRaw() return ctl::make_unique_for_overwrite(); } -#undef ctl +// #undef ctl static int g = 0; struct SetsGDeleter { - void operator()(auto*) const noexcept + void operator()(auto* x) const noexcept { ++g; + delete x; } }; struct StatefulDeleter { char state; - void operator()(auto*) const noexcept + void operator()(auto* x) const noexcept { } }; struct FinalDeleter final { - void operator()(auto*) const noexcept + void operator()(auto* x) const noexcept { } }; @@ -99,6 +100,7 @@ struct Derived : Base int main() { + { Ptr x(new int(5)); } @@ -186,9 +188,9 @@ main() g = 0; { auto x = Mk(); - x.release(); + delete x.release(); } - if (g) + if (g != 1) return 13; } @@ -224,8 +226,5 @@ main() Ptr z(ctl::move(y)); } - // next is 18 - - // TODO(mrdomino): Fix memory leaks reported by MODE=dbg - // CheckForMemoryLeaks(); + CheckForMemoryLeaks(); }