Introduce more CTL content

This change introduces accumulate, addressof, advance, all_of, distance,
array, enable_if, allocator_traits, back_inserter, bad_alloc, is_signed,
any_of, copy, exception, fill, fill_n, is_same, is_same_v, out_of_range,
lexicographical_compare, is_integral, uninitialized_fill_n, is_unsigned,
numeric_limits, uninitialized_fill, iterator_traits, move_backward, min,
max, iterator_tag, move_iterator, reverse_iterator, uninitialized_move_n

This change experiments with rewriting the ctl::vector class to make the
CTL design more similar to the STL. So far it has not slowed things down
to have 42 #include lines rather than 2, since it's still almost nothing
compared to LLVM's code. In fact the closer we can flirt with being just
like libcxx, the better chance we might have of discovering exactly what
makes it so slow to compile. It would be an enormous discovery if we can
find one simple trick to solving the issue there instead.

This also fixes a bug in `ctl::string(const string &s)` when `s` is big.
This commit is contained in:
Justine Tunney 2024-06-27 22:18:55 -07:00
parent 054da021d0
commit 38921dc46b
No known key found for this signature in database
GPG key ID: BE714B4575D6E328
52 changed files with 2980 additions and 193 deletions

View file

@ -36,6 +36,7 @@ $(CTL_A_OBJS): private \
-Walloca-larger-than=4096 \
-ffunction-sections \
-fdata-sections \
-fexceptions \
CTL_LIBS = $(foreach x,$(CTL_ARTIFACTS),$($(x)))
CTL_SRCS = $(foreach x,$(CTL_ARTIFACTS),$($(x)_SRCS))

28
ctl/accumulate.h Normal file
View file

@ -0,0 +1,28 @@
// -*-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_ACCUMULATE_H_
#define CTL_ACCUMULATE_H_
namespace ctl {
template<class InputIt, class T>
constexpr T
accumulate(InputIt first, InputIt last, T init)
{
for (; first != last; ++first)
init = init + *first;
return init;
}
template<class InputIt, class T, class BinaryOperation>
constexpr T
accumulate(InputIt first, InputIt last, T init, BinaryOperation op)
{
for (; first != last; ++first)
init = op(init, *first);
return init;
}
} // namespace ctl
#endif // CTL_ACCUMULATE_H_

29
ctl/addressof.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_ADDRESSOF_H_
#define CTL_ADDRESSOF_H_
namespace ctl {
template<typename T>
T*
addressof(T& arg) noexcept
{
return reinterpret_cast<T*>(
&const_cast<char&>(reinterpret_cast<const volatile char&>(arg)));
}
template<typename R, typename... Args>
R (*addressof(R (*&arg)(Args...)) noexcept)
(Args...)
{
return arg;
}
template<typename T>
T*
addressof(T&&) = delete;
} // namespace ctl
#endif // CTL_ADDRESSOF_H_

24
ctl/advance.h Normal file
View file

@ -0,0 +1,24 @@
// -*-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_ADVANCE_H_
#define CTL_ADVANCE_H_
namespace ctl {
template<class InputIt, class Distance>
constexpr void
advance(InputIt& it, Distance n)
{
while (n > 0) {
--n;
++it;
}
while (n < 0) {
++n;
--it;
}
}
} // namespace ctl
#endif // CTL_ADVANCE_H_

22
ctl/all_of.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_ALL_OF_H_
#define CTL_ALL_OF_H_
namespace ctl {
template<class InputIt, class UnaryPredicate>
constexpr bool
all_of(InputIt first, InputIt last, UnaryPredicate p)
{
for (; first != last; ++first) {
if (!p(*first)) {
return false;
}
}
return true;
}
} // namespace ctl
#endif // CTL_ALL_OF_H_

94
ctl/allocator.h Normal file
View file

@ -0,0 +1,94 @@
// -*-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_H_
#define CTL_ALLOCATOR_H_
#include "bad_alloc.h"
#include "new.h"
#include "type_traits.h"
#include "utility.h"
namespace ctl {
template<typename T>
class allocator
{
public:
using value_type = T;
using size_type = size_t;
using difference_type = ptrdiff_t;
using propagate_on_container_move_assignment = ctl::true_type;
using is_always_equal = ctl::true_type;
using pointer = T*;
using const_pointer = const T*;
using reference = T&;
using const_reference = const T&;
constexpr allocator() noexcept = default;
constexpr allocator(const allocator&) noexcept = default;
template<class U>
constexpr allocator(const allocator<U>&) noexcept
{
}
constexpr ~allocator() = default;
[[nodiscard]] T* allocate(size_type n)
{
if (n > __SIZE_MAX__ / sizeof(T))
throw ctl::bad_alloc();
if (auto p = static_cast<T*>(::operator new(
n * sizeof(T), ctl::align_val_t(alignof(T)), ctl::nothrow)))
return p;
throw ctl::bad_alloc();
}
void deallocate(T* p, size_type n) noexcept
{
::operator delete(p, n * sizeof(T), ctl::align_val_t(alignof(T)));
}
template<typename U, typename... Args>
void construct(U* p, Args&&... args)
{
::new (static_cast<void*>(p)) U(ctl::forward<Args>(args)...);
}
template<typename U>
void destroy(U* p)
{
p->~U();
}
size_type max_size() const noexcept
{
return __SIZE_MAX__ / sizeof(T);
}
allocator& operator=(const allocator&) = default;
template<typename U>
struct rebind
{
using other = allocator<U>;
};
};
template<class T, class U>
bool
operator==(const allocator<T>&, const allocator<U>&) noexcept
{
return true;
}
template<class T, class U>
bool
operator!=(const allocator<T>&, const allocator<U>&) noexcept
{
return false;
}
} // namespace ctl
#endif // CTL_ALLOCATOR_H_

72
ctl/allocator_traits.h Normal file
View file

@ -0,0 +1,72 @@
#ifndef CTL_ALLOCATOR_TRAITS_H_
#define CTL_ALLOCATOR_TRAITS_H_
#include "type_traits.h"
namespace ctl {
template<typename Alloc>
struct allocator_traits
{
using allocator_type = Alloc;
using value_type = typename Alloc::value_type;
using pointer = typename Alloc::pointer;
using const_pointer = typename Alloc::const_pointer;
using void_pointer = void*;
using const_void_pointer = const void*;
using difference_type = typename Alloc::difference_type;
using size_type = typename Alloc::size_type;
using propagate_on_container_copy_assignment = false_type;
using propagate_on_container_move_assignment = true_type;
using propagate_on_container_swap = false_type;
using is_always_equal = true_type;
template<typename T>
using rebind_alloc = typename Alloc::template rebind<T>::other;
template<typename T>
using rebind_traits = allocator_traits<rebind_alloc<T>>;
__attribute__((__always_inline__)) static pointer allocate(Alloc& a,
size_type n)
{
return a.allocate(n);
}
__attribute__((__always_inline__)) static void deallocate(Alloc& a,
pointer p,
size_type n)
{
a.deallocate(p, n);
}
template<typename T, typename... Args>
__attribute__((__always_inline__)) static void construct(Alloc& a,
T* p,
Args&&... args)
{
::new ((void*)p) T(static_cast<Args&&>(args)...);
}
template<typename T>
__attribute__((__always_inline__)) static void destroy(Alloc& a, T* p)
{
p->~T();
}
__attribute__((__always_inline__)) static size_type max_size(
const Alloc& a) noexcept
{
return __PTRDIFF_MAX__ / sizeof(value_type);
}
__attribute__((__always_inline__)) static Alloc
select_on_container_copy_construction(const Alloc& a)
{
return a;
}
};
} // namespace ctl
#endif // CTL_ALLOCATOR_TRAITS_H_

22
ctl/any_of.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_ANY_OF_H_
#define CTL_ANY_OF_H_
namespace ctl {
template<class InputIt, class UnaryPredicate>
constexpr bool
any_of(InputIt first, InputIt last, UnaryPredicate p)
{
for (; first != last; ++first) {
if (p(*first)) {
return true;
}
}
return false;
}
} // namespace ctl
#endif // CTL_ANY_OF_H_

243
ctl/array.h Normal file
View file

@ -0,0 +1,243 @@
// -*-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_ARRAY_H_
#define CTL_ARRAY_H_
#include "initializer_list.h"
#include "reverse_iterator.h"
namespace ctl {
template<typename T, size_t N>
struct array
{
using value_type = T;
using size_type = size_t;
using difference_type = ptrdiff_t;
using reference = value_type&;
using const_reference = const value_type&;
using pointer = value_type*;
using const_pointer = const value_type*;
using iterator = value_type*;
using const_iterator = const value_type*;
using reverse_iterator = ctl::reverse_iterator<iterator>;
using const_reverse_iterator = ctl::reverse_iterator<const_iterator>;
T elems[N];
constexpr array() = default;
constexpr array(std::initializer_list<T> init)
{
auto it = init.begin();
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();
return elems[pos];
}
constexpr const_reference at(size_type pos) const
{
if (pos >= N)
__builtin_trap();
return elems[pos];
}
constexpr reference operator[](size_type pos)
{
return elems[pos];
}
constexpr const_reference operator[](size_type pos) const
{
return elems[pos];
}
constexpr reference front()
{
return elems[0];
}
constexpr const_reference front() const
{
return elems[0];
}
constexpr reference back()
{
return elems[N - 1];
}
constexpr const_reference back() const
{
return elems[N - 1];
}
constexpr T* data() noexcept
{
return elems;
}
constexpr const T* data() const noexcept
{
return elems;
}
constexpr iterator begin() noexcept
{
return elems;
}
constexpr const_iterator begin() const noexcept
{
return elems;
}
constexpr iterator end() noexcept
{
return elems + N;
}
constexpr const_iterator end() const noexcept
{
return elems + N;
}
constexpr reverse_iterator rbegin() noexcept
{
return reverse_iterator(end());
}
constexpr const_reverse_iterator rbegin() const noexcept
{
return const_reverse_iterator(end());
}
constexpr reverse_iterator rend() noexcept
{
return reverse_iterator(begin());
}
constexpr const_reverse_iterator rend() const noexcept
{
return const_reverse_iterator(begin());
}
constexpr const_iterator cbegin() const noexcept
{
return begin();
}
constexpr const_iterator cend() const noexcept
{
return end();
}
constexpr const_reverse_iterator crbegin() const noexcept
{
return rbegin();
}
constexpr const_reverse_iterator crend() const noexcept
{
return rend();
}
constexpr bool empty() const noexcept
{
return N == 0;
}
constexpr size_type size() const noexcept
{
return N;
}
constexpr size_type max_size() const noexcept
{
return N;
}
void fill(const T& value)
{
for (size_type i = 0; i < N; ++i) {
elems[i] = value;
}
}
void swap(array& other) noexcept
{
for (size_type i = 0; i < N; ++i) {
T temp = elems[i];
elems[i] = other.elems[i];
other.elems[i] = temp;
}
}
};
template<typename T, size_t N>
bool
operator==(const array<T, N>& lhs, const array<T, N>& rhs)
{
for (size_t i = 0; i < N; ++i) {
if (!(lhs[i] == rhs[i]))
return false;
}
return true;
}
template<typename T, size_t N>
bool
operator!=(const array<T, N>& lhs, const array<T, N>& rhs)
{
return !(lhs == rhs);
}
template<typename T, size_t N>
bool
operator<(const array<T, N>& lhs, const array<T, N>& rhs)
{
for (size_t i = 0; i < N; ++i) {
if (lhs[i] < rhs[i])
return true;
if (rhs[i] < lhs[i])
return false;
}
return false;
}
template<typename T, size_t N>
bool
operator<=(const array<T, N>& lhs, const array<T, N>& rhs)
{
return !(rhs < lhs);
}
template<typename T, size_t N>
bool
operator>(const array<T, N>& lhs, const array<T, N>& rhs)
{
return rhs < lhs;
}
template<typename T, size_t N>
bool
operator>=(const array<T, N>& lhs, const array<T, N>& rhs)
{
return !(lhs < rhs);
}
template<typename T, size_t N>
void
swap(array<T, N>& lhs, array<T, N>& rhs) noexcept
{
lhs.swap(rhs);
}
} // namespace ctl
#endif // CTL_ARRAY_H_

64
ctl/back_inserter.h Normal file
View file

@ -0,0 +1,64 @@
// -*-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_BACK_INSERTER_H_
#define CTL_BACK_INSERTER_H_
#include "iterator.h"
#include "utility.h"
namespace ctl {
template<class Container>
class back_insert_iterator
{
protected:
Container* container;
public:
using iterator_category = ctl::output_iterator_tag;
using value_type = void;
using difference_type = void;
using pointer = void;
using reference = void;
explicit back_insert_iterator(Container& c) : container(&c)
{
}
back_insert_iterator& operator=(const typename Container::value_type& value)
{
container->push_back(value);
return *this;
}
back_insert_iterator& operator=(typename Container::value_type&& value)
{
container->push_back(ctl::move(value));
return *this;
}
back_insert_iterator& operator*()
{
return *this;
}
back_insert_iterator& operator++()
{
return *this;
}
back_insert_iterator operator++(int)
{
return *this;
}
};
template<class Container>
back_insert_iterator<Container>
back_inserter(Container& c)
{
return back_insert_iterator<Container>(c);
}
} // namespace ctl
#endif // CTL_BACK_INSERTER_H_

23
ctl/bad_alloc.h Normal file
View file

@ -0,0 +1,23 @@
// -*-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_BAD_ALLOC_H_
#define CTL_BAD_ALLOC_H_
#include "exception.h"
namespace ctl {
class bad_alloc : public exception
{
public:
bad_alloc() noexcept = default;
~bad_alloc() override = default;
const char* what() const noexcept override
{
return "ctl::bad_alloc";
}
};
} // namespace ctl
#endif // CTL_BAD_ALLOC_H_

22
ctl/copy.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_COPY_H_
#define CTL_COPY_H_
namespace ctl {
template<class InputIt, class OutputIt>
OutputIt
copy(InputIt first, InputIt last, OutputIt d_first)
{
while (first != last) {
*d_first = *first;
++d_first;
++first;
}
return d_first;
}
} // namespace ctl
#endif // CTL_COPY_H_

37
ctl/distance.h Normal file
View file

@ -0,0 +1,37 @@
// -*-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_DISTANCE_H_
#define CTL_DISTANCE_H_
#include "iterator.h"
#include "iterator_traits.h"
namespace ctl {
template<class InputIter>
constexpr typename iterator_traits<InputIter>::difference_type
distance_impl(InputIter first, InputIter last, input_iterator_tag)
{
typename iterator_traits<InputIter>::difference_type res(0);
for (; first != last; ++first)
++res;
return res;
}
template<class RandIter>
constexpr typename iterator_traits<RandIter>::difference_type
distance_impl(RandIter first, RandIter last, random_access_iterator_tag)
{
return last - first;
}
template<class InputIter>
constexpr typename iterator_traits<InputIter>::difference_type
distance(InputIter first, InputIter last)
{
return distance_impl(
first, last, typename iterator_traits<InputIter>::iterator_category());
}
} // namespace ctl
#endif // CTL_DISTANCE_H_

21
ctl/enable_if.h Normal file
View file

@ -0,0 +1,21 @@
#ifndef CTL_ENABLE_IF_H_
#define CTL_ENABLE_IF_H_
namespace ctl {
template<bool B, class T = void>
struct enable_if
{};
template<class T>
struct enable_if<true, T>
{
typedef T type;
};
template<bool B, class T = void>
using enable_if_t = typename enable_if<B, T>::type;
} // namespace ctl
#endif // CTL_ENABLE_IF_H_

22
ctl/exception.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_EXCEPTION_H_
#define CTL_EXCEPTION_H_
namespace ctl {
class exception
{
public:
exception() noexcept = default;
virtual ~exception() = default;
virtual const char* what() const noexcept
{
return "ctl::exception";
}
};
} // namespace ctl
#endif // CTL_EXCEPTION_H_

18
ctl/fill.h Normal file
View file

@ -0,0 +1,18 @@
// -*-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_FILL_H_
#define CTL_FILL_H_
namespace ctl {
template<typename ForwardIt, typename T>
void
fill(ForwardIt first, ForwardIt last, const T& value)
{
for (; first != last; ++first)
*first = value;
}
} // namespace ctl
#endif // CTL_FILL_H_

19
ctl/fill_n.h Normal file
View file

@ -0,0 +1,19 @@
// -*-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_FILL_N_H_
#define CTL_FILL_N_H_
namespace ctl {
template<typename OutputIt, typename Size, typename T>
OutputIt
fill_n(OutputIt first, Size count, const T& value)
{
for (; count > 0; --count, ++first)
*first = value;
return first;
}
} // namespace ctl
#endif // CTL_FILL_N_H_

28
ctl/iterator.h Normal file
View file

@ -0,0 +1,28 @@
// -*-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_OUTPUT_ITERATOR_TAG_H_
#define CTL_OUTPUT_ITERATOR_TAG_H_
namespace ctl {
struct input_iterator_tag
{};
struct output_iterator_tag
{};
struct forward_iterator_tag : public input_iterator_tag
{};
struct bidirectional_iterator_tag : public forward_iterator_tag
{};
struct random_access_iterator_tag : public bidirectional_iterator_tag
{};
struct contiguous_iterator_tag : public random_access_iterator_tag
{};
} // namespace ctl
#endif // CTL_OUTPUT_ITERATOR_TAG_H_

31
ctl/iterator_traits.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_ITERATOR_TRAITS_H_
#define CTL_ITERATOR_TRAITS_H_
#include "utility.h"
namespace ctl {
template<class Iterator>
struct iterator_traits
{
using iterator_category = typename Iterator::iterator_category;
using value_type = typename Iterator::value_type;
using difference_type = typename Iterator::difference_type;
using pointer = typename Iterator::pointer;
using reference = typename Iterator::reference;
};
template<class T>
struct iterator_traits<T*>
{
using iterator_category = void*; // We don't actually use this
using value_type = T;
using difference_type = ptrdiff_t;
using pointer = T*;
using reference = T&;
};
} // namespace ctl
#endif // CTL_ITERATOR_TRAITS_H_

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_LEXICOGRAPHICAL_COMPARE_H_
#define CTL_LEXICOGRAPHICAL_COMPARE_H_
namespace ctl {
template<class InputIt1, class InputIt2>
bool
lexicographical_compare(InputIt1 first1,
InputIt1 last1,
InputIt2 first2,
InputIt2 last2)
{
for (; (first1 != last1) && (first2 != last2); ++first1, ++first2) {
if (*first1 < *first2)
return true;
if (*first2 < *first1)
return false;
}
return (first1 == last1) && (first2 != last2);
}
template<class InputIt1, class InputIt2, class Compare>
bool
lexicographical_compare(InputIt1 first1,
InputIt1 last1,
InputIt2 first2,
InputIt2 last2,
Compare comp)
{
for (; (first1 != last1) && (first2 != last2); ++first1, ++first2) {
if (comp(*first1, *first2))
return true;
if (comp(*first2, *first1))
return false;
}
return (first1 == last1) && (first2 != last2);
}
} // namespace ctl
#endif /* CTL_LEXICOGRAPHICAL_COMPARE_H_ */

View file

@ -2,6 +2,7 @@
// vi: set et ft=cpp ts=4 sts=4 sw=4 fenc=utf-8 :vi
#ifndef CTL_MAP_H_
#define CTL_MAP_H_
#include "out_of_range.h"
#include "set.h"
namespace ctl {
@ -164,7 +165,7 @@ class map
{
auto it = find(key);
if (it == end())
__builtin_trap();
throw ctl::out_of_range("out of range");
return it->second;
}
@ -172,7 +173,7 @@ class map
{
auto it = find(key);
if (it == end())
__builtin_trap();
throw ctl::out_of_range("out of range");
return it->second;
}

17
ctl/max.h Normal file
View file

@ -0,0 +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 CTL_MAX_H_
#define CTL_MAX_H_
namespace ctl {
template<class T>
inline constexpr const T&
max(const T& a, const T& b)
{
return a < b ? b : a;
}
} // namespace ctl
#endif /* CTL_MAX_H_ */

17
ctl/min.h Normal file
View file

@ -0,0 +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 CTL_MIN_H_
#define CTL_MIN_H_
namespace ctl {
template<class T>
inline constexpr const T&
min(const T& a, const T& b)
{
return b < a ? b : a;
}
} // namespace ctl
#endif /* CTL_MIN_H_ */

20
ctl/move_backward.h Normal file
View file

@ -0,0 +1,20 @@
// -*-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_MOVE_BACKWARD_H_
#define CTL_MOVE_BACKWARD_H_
#include "utility.h"
namespace ctl {
template<typename BidirIt1, typename BidirIt2>
BidirIt2
move_backward(BidirIt1 first, BidirIt1 last, BidirIt2 d_last)
{
while (first != last)
*(--d_last) = ctl::move(*(--last));
return d_last;
}
} // namespace ctl
#endif // CTL_MOVE_BACKWARD_H_

173
ctl/move_iterator.h Normal file
View file

@ -0,0 +1,173 @@
#ifndef CTL_MOVE_ITERATOR_H_
#define CTL_MOVE_ITERATOR_H_
#include "iterator_traits.h"
#include "type_traits.h"
namespace ctl {
template<typename Iterator>
class move_iterator
{
public:
using iterator_type = Iterator;
using iterator_category =
typename ctl::iterator_traits<Iterator>::iterator_category;
using value_type = typename ctl::iterator_traits<Iterator>::value_type;
using difference_type =
typename ctl::iterator_traits<Iterator>::difference_type;
using pointer = Iterator;
using reference = value_type&&;
constexpr move_iterator() : current()
{
}
explicit constexpr move_iterator(Iterator i) : current(i)
{
}
template<class U>
constexpr move_iterator(const move_iterator<U>& u) : current(u.base())
{
}
constexpr Iterator base() const
{
return current;
}
constexpr reference operator*() const
{
return static_cast<reference>(*current);
}
constexpr pointer operator->() const
{
return current;
}
constexpr move_iterator& operator++()
{
++current;
return *this;
}
constexpr move_iterator operator++(int)
{
move_iterator tmp = *this;
++current;
return tmp;
}
constexpr move_iterator& operator--()
{
--current;
return *this;
}
constexpr move_iterator operator--(int)
{
move_iterator tmp = *this;
--current;
return tmp;
}
constexpr move_iterator operator+(difference_type n) const
{
return move_iterator(current + n);
}
constexpr move_iterator& operator+=(difference_type n)
{
current += n;
return *this;
}
constexpr move_iterator operator-(difference_type n) const
{
return move_iterator(current - n);
}
constexpr move_iterator& operator-=(difference_type n)
{
current -= n;
return *this;
}
constexpr reference operator[](difference_type n) const
{
return ctl::move(current[n]);
}
private:
Iterator current;
};
template<typename Iterator>
__attribute__((__always_inline__)) constexpr move_iterator<Iterator>
make_move_iterator(Iterator i)
{
return move_iterator<Iterator>(i);
}
template<typename Iterator1, typename Iterator2>
constexpr bool
operator==(const move_iterator<Iterator1>& x, const move_iterator<Iterator2>& y)
{
return x.base() == y.base();
}
template<typename Iterator1, typename Iterator2>
constexpr bool
operator!=(const move_iterator<Iterator1>& x, const move_iterator<Iterator2>& y)
{
return !(x == y);
}
template<typename Iterator1, typename Iterator2>
constexpr bool
operator<(const move_iterator<Iterator1>& x, const move_iterator<Iterator2>& y)
{
return x.base() < y.base();
}
template<typename Iterator1, typename Iterator2>
constexpr bool
operator<=(const move_iterator<Iterator1>& x, const move_iterator<Iterator2>& y)
{
return !(y < x);
}
template<typename Iterator1, typename Iterator2>
constexpr bool
operator>(const move_iterator<Iterator1>& x, const move_iterator<Iterator2>& y)
{
return y < x;
}
template<typename Iterator1, typename Iterator2>
constexpr bool
operator>=(const move_iterator<Iterator1>& x, const move_iterator<Iterator2>& y)
{
return !(x < y);
}
template<typename Iterator>
constexpr move_iterator<Iterator>
operator+(typename move_iterator<Iterator>::difference_type n,
const move_iterator<Iterator>& x)
{
return x + n;
}
template<typename Iterator1, typename Iterator2>
constexpr auto
operator-(const move_iterator<Iterator1>& x,
const move_iterator<Iterator2>& y) -> decltype(x.base() - y.base())
{
return x.base() - y.base();
}
} // namespace ctl
#endif // CTL_MOVE_ITERATOR_H_

View file

@ -23,7 +23,7 @@
COSMOPOLITAN_C_START_
static void*
_ctl_alloc(size_t n, size_t a)
_ctl_alloc(size_t n, size_t a) noexcept
{
void* p;
if (!(p = memalign(a, n)))
@ -32,7 +32,16 @@ _ctl_alloc(size_t n, size_t a)
}
static void*
_ctl_alloc1(size_t n)
_ctl_alloc_nothrow(size_t n, size_t a, const ctl::nothrow_t&)
{
void* p;
if (!(p = memalign(a, n)))
__builtin_trap();
return p;
}
static void*
_ctl_alloc1(size_t n) noexcept
{
void* p;
if (!(p = malloc(n)))
@ -41,19 +50,28 @@ _ctl_alloc1(size_t n)
}
static void*
_ctl_ret(size_t, void* p)
_ctl_alloc1_nothrow(size_t n, const ctl::nothrow_t&) noexcept
{
void* p;
if (!(p = malloc(n)))
__builtin_trap();
return p;
}
static void*
_ctl_ret(size_t, void* p) noexcept
{
return p;
}
static void
_ctl_free(void* p)
_ctl_free(void* p) noexcept
{
free(p);
}
static void
_ctl_nop(void*, void*)
_ctl_nop(void*, void*) noexcept
{
}
@ -75,23 +93,43 @@ __weak_reference(void*
operator new(size_t, ctl::align_val_t),
_ctl_alloc);
__weak_reference(void*
operator new(size_t,
ctl::align_val_t,
const ctl::nothrow_t&) noexcept,
_ctl_alloc_nothrow);
__weak_reference(void*
operator new[](size_t, ctl::align_val_t),
_ctl_alloc);
__weak_reference(void*
operator new[](size_t,
ctl::align_val_t,
const ctl::nothrow_t&) noexcept,
_ctl_alloc_nothrow);
__weak_reference(void*
operator new(size_t),
_ctl_alloc1);
__weak_reference(void*
operator new(size_t, const ctl::nothrow_t&) noexcept,
_ctl_alloc1_nothrow);
__weak_reference(void*
operator new[](size_t),
_ctl_alloc1);
__weak_reference(void*
operator new[](size_t, const ctl::nothrow_t&) noexcept,
_ctl_alloc1_nothrow);
// XXX clang-format currently mutilates these for some reason.
// clang-format off
__weak_reference(void* operator new(size_t, void*), _ctl_ret);
__weak_reference(void* operator new[](size_t, void*), _ctl_ret);
__weak_reference(void* operator new(size_t, void*) noexcept, _ctl_ret);
__weak_reference(void* operator new[](size_t, void*) noexcept, _ctl_ret);
__weak_reference(void operator delete(void*) noexcept, _ctl_free);
__weak_reference(void operator delete[](void*) noexcept, _ctl_free);

View file

@ -13,18 +13,30 @@ enum class align_val_t : size_t
{
};
} // namespace ctl
struct nothrow_t
{
explicit nothrow_t() = default;
};
void* operator new(size_t);
void* operator new[](size_t);
void* operator new(size_t, ctl::align_val_t);
void* operator new[](size_t, ctl::align_val_t);
inline constexpr nothrow_t nothrow{};
} // namespace ctl
// XXX clang-format currently mutilates these for some reason.
// clang-format off
void* operator new(size_t, void*);
void* operator new[](size_t, void*);
void* operator new(size_t);
void* operator new(size_t, const ctl::nothrow_t&) noexcept;
void* operator new(size_t, ctl::align_val_t);
void* operator new(size_t, ctl::align_val_t, const ctl::nothrow_t&) noexcept;
void* operator new[](size_t);
void* operator new[](size_t, const ctl::nothrow_t&) noexcept;
void* operator new[](size_t, ctl::align_val_t);
void* operator new[](size_t, ctl::align_val_t, const ctl::nothrow_t&) noexcept;
void* operator new(size_t, void*) noexcept;
void* operator new[](size_t, void*) noexcept;
void operator delete(void*) noexcept;
void operator delete[](void*) noexcept;

122
ctl/numeric_limits.h Normal file
View file

@ -0,0 +1,122 @@
// -*-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_NUMERIC_LIMITS_H_
#define CTL_NUMERIC_LIMITS_H_
#include "type_traits.h"
namespace ctl {
template<typename T>
class numeric_limits
{
static constexpr T max_signed()
{
return T(((uintmax_t)1 << (sizeof(T) * 8 - 1)) - 1);
}
static constexpr T max_unsigned()
{
return T(~T(0));
}
public:
static constexpr bool is_specialized = ctl::is_integral<T>::value;
static constexpr bool is_signed = !ctl::is_unsigned<T>::value;
static constexpr bool is_integer = ctl::is_integral<T>::value;
static constexpr bool is_exact = ctl::is_integral<T>::value;
static constexpr int digits = sizeof(T) * 8 - (is_signed ? 1 : 0);
static constexpr T min() noexcept
{
return is_signed ? T(-max_signed() - 1) : T(0);
}
static constexpr T max() noexcept
{
return is_signed ? max_signed() : max_unsigned();
}
static constexpr T lowest() noexcept
{
return min();
}
};
template<>
struct numeric_limits<bool>
{
static constexpr bool is_specialized = true;
static constexpr bool is_signed = false;
static constexpr bool is_integer = true;
static constexpr bool is_exact = true;
static constexpr int digits = 1;
static constexpr bool min() noexcept
{
return false;
}
static constexpr bool max() noexcept
{
return true;
}
static constexpr bool lowest() noexcept
{
return false;
}
};
template<>
struct numeric_limits<float>
{
static constexpr bool is_specialized = true;
static constexpr bool is_signed = true;
static constexpr bool is_integer = false;
static constexpr bool is_exact = false;
static constexpr int digits = 24;
static constexpr float min() noexcept
{
return __FLT_MIN__;
}
static constexpr float max() noexcept
{
return __FLT_MAX__;
}
static constexpr float lowest() noexcept
{
return -max();
}
};
template<>
struct numeric_limits<double>
{
static constexpr bool is_specialized = true;
static constexpr bool is_signed = true;
static constexpr bool is_integer = false;
static constexpr bool is_exact = false;
static constexpr int digits = 53;
static constexpr double min() noexcept
{
return __DBL_MIN__;
}
static constexpr double max() noexcept
{
return __DBL_MAX__;
}
static constexpr double lowest() noexcept
{
return -max();
}
};
} // namespace ctl
#endif // CTL_NUMERIC_LIMITS_H_

23
ctl/out_of_range.h Normal file
View file

@ -0,0 +1,23 @@
// -*-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_OUT_OF_RANGE_H_
#define CTL_OUT_OF_RANGE_H_
#include "exception.h"
namespace ctl {
class out_of_range : public exception
{
public:
out_of_range() noexcept = default;
~out_of_range() override = default;
const char* what() const noexcept override
{
return "ctl::out_of_range";
}
};
} // namespace ctl
#endif // CTL_OUT_OF_RANGE_H_

183
ctl/reverse_iterator.h Normal file
View file

@ -0,0 +1,183 @@
// -*-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_REVERSE_ITERATOR_H_
#define CTL_REVERSE_ITERATOR_H_
#include "iterator_traits.h"
#include "utility.h"
namespace ctl {
template<class Iterator>
class reverse_iterator
{
public:
using iterator_type = Iterator;
using iterator_category =
typename iterator_traits<Iterator>::iterator_category;
using value_type = typename iterator_traits<Iterator>::value_type;
using difference_type = typename iterator_traits<Iterator>::difference_type;
using pointer = typename iterator_traits<Iterator>::pointer;
using reference = typename iterator_traits<Iterator>::reference;
constexpr reverse_iterator() : current()
{
}
constexpr explicit reverse_iterator(Iterator x) : current(x)
{
}
template<class U>
constexpr reverse_iterator(const reverse_iterator<U>& other)
: current(other.base())
{
}
template<class U>
constexpr reverse_iterator& operator=(const reverse_iterator<U>& other)
{
current = other.base();
return *this;
}
constexpr Iterator base() const
{
return current;
}
constexpr reference operator*() const
{
Iterator tmp = current;
return *--tmp;
}
constexpr pointer operator->() const
{
return &(operator*());
}
constexpr reverse_iterator& operator++()
{
--current;
return *this;
}
constexpr reverse_iterator operator++(int)
{
reverse_iterator tmp = *this;
--current;
return tmp;
}
constexpr reverse_iterator& operator--()
{
++current;
return *this;
}
constexpr reverse_iterator operator--(int)
{
reverse_iterator tmp = *this;
++current;
return tmp;
}
constexpr reverse_iterator operator+(difference_type n) const
{
return reverse_iterator(current - n);
}
constexpr reverse_iterator& operator+=(difference_type n)
{
current -= n;
return *this;
}
constexpr reverse_iterator operator-(difference_type n) const
{
return reverse_iterator(current + n);
}
constexpr reverse_iterator& operator-=(difference_type n)
{
current += n;
return *this;
}
constexpr reference operator[](difference_type n) const
{
return *(*this + n);
}
protected:
Iterator current;
};
template<class Iterator1, class Iterator2>
constexpr bool
operator==(const reverse_iterator<Iterator1>& lhs,
const reverse_iterator<Iterator2>& rhs)
{
return lhs.base() == rhs.base();
}
template<class Iterator1, class Iterator2>
constexpr bool
operator!=(const reverse_iterator<Iterator1>& lhs,
const reverse_iterator<Iterator2>& rhs)
{
return lhs.base() != rhs.base();
}
template<class Iterator1, class Iterator2>
constexpr bool
operator<(const reverse_iterator<Iterator1>& lhs,
const reverse_iterator<Iterator2>& rhs)
{
return rhs.base() < lhs.base();
}
template<class Iterator1, class Iterator2>
constexpr bool
operator<=(const reverse_iterator<Iterator1>& lhs,
const reverse_iterator<Iterator2>& rhs)
{
return !(rhs < lhs);
}
template<class Iterator1, class Iterator2>
constexpr bool
operator>(const reverse_iterator<Iterator1>& lhs,
const reverse_iterator<Iterator2>& rhs)
{
return rhs < lhs;
}
template<class Iterator1, class Iterator2>
constexpr bool
operator>=(const reverse_iterator<Iterator1>& lhs,
const reverse_iterator<Iterator2>& rhs)
{
return !(lhs < rhs);
}
template<class Iterator>
constexpr reverse_iterator<Iterator>
operator+(typename reverse_iterator<Iterator>::difference_type n,
const reverse_iterator<Iterator>& it)
{
return reverse_iterator<Iterator>(it.base() - n);
}
template<class Iterator1, class Iterator2>
constexpr auto
operator-(const reverse_iterator<Iterator1>& lhs,
const reverse_iterator<Iterator2>& rhs) -> decltype(rhs.base() -
lhs.base())
{
return rhs.base() - lhs.base();
}
} // namespace ctl
#endif // CTL_REVERSE_ITERATOR_H_

View file

@ -41,25 +41,14 @@ string::destroy_big() noexcept
void
string::init_big(const string& s) noexcept
{
char* p2;
#ifndef NDEBUG
if (!s.isbig())
__builtin_trap();
#endif
if (s.size() >= s.capacity() >> 1) {
if (!(p2 = (char*)malloc(s.capacity())))
__builtin_trap();
set_big_string(p2, s.size(), s.capacity());
} else {
init_big(string_view(s));
}
}
void
string::init_big(const string_view s) noexcept
{
size_t need;
char* p2;
size_t need;
if (ckd_add(&need, s.n, 1 /* nul */ + 15))
__builtin_trap();
need &= -16;

View file

@ -2,6 +2,7 @@
// vi: set et ft=cpp ts=4 sts=4 sw=4 fenc=utf-8 :vi
#ifndef CTL_STRING_H_
#define CTL_STRING_H_
#include "reverse_iterator.h"
#include "string_view.h"
namespace ctl {
@ -44,8 +45,18 @@ struct big_string
class string
{
public:
using iterator = char*;
using const_iterator = const char*;
using value_type = char;
using size_type = size_t;
using difference_type = ptrdiff_t;
using pointer = value_type*;
using const_pointer = const value_type*;
using reference = value_type&;
using const_reference = const value_type&;
using iterator = pointer;
using const_iterator = const_pointer;
using reverse_iterator = ctl::reverse_iterator<iterator>;
using const_reverse_iterator = ctl::reverse_iterator<const_iterator>;
static constexpr size_t npos = -1;
string() noexcept
@ -189,9 +200,9 @@ class string
return data();
}
iterator end() noexcept
const_iterator begin() const noexcept
{
return data() + size();
return data();
}
const_iterator cbegin() const noexcept
@ -199,11 +210,51 @@ class string
return data();
}
reverse_iterator rbegin() noexcept
{
return reverse_iterator(end());
}
const_reverse_iterator rbegin() const noexcept
{
return const_reverse_iterator(end());
}
const_reverse_iterator crbegin() const noexcept
{
return const_reverse_iterator(end());
}
iterator end() noexcept
{
return data() + size();
}
const_iterator end() const noexcept
{
return data() + size();
}
const_iterator cend() const noexcept
{
return data() + size();
}
reverse_iterator rend() noexcept
{
return reverse_iterator(begin());
}
const_reverse_iterator rend() const noexcept
{
return const_reverse_iterator(cbegin());
}
const_reverse_iterator crend() const noexcept
{
return const_reverse_iterator(cbegin());
}
char& front()
{
if (!size())

123
ctl/type_traits.h Normal file
View file

@ -0,0 +1,123 @@
// -*-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_
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>
struct is_integral : false_type
{};
template<>
struct is_integral<bool> : true_type
{};
template<>
struct is_integral<char> : true_type
{};
template<>
struct is_integral<signed char> : true_type
{};
template<>
struct is_integral<unsigned char> : true_type
{};
template<>
struct is_integral<short> : true_type
{};
template<>
struct is_integral<unsigned short> : true_type
{};
template<>
struct is_integral<int> : true_type
{};
template<>
struct is_integral<unsigned int> : true_type
{};
template<>
struct is_integral<long> : true_type
{};
template<>
struct is_integral<unsigned long> : true_type
{};
template<>
struct is_integral<long long> : true_type
{};
template<>
struct is_integral<unsigned long long> : true_type
{};
template<>
struct is_integral<char16_t> : true_type
{};
template<>
struct is_integral<char32_t> : true_type
{};
template<>
struct is_integral<wchar_t> : true_type
{};
template<typename T>
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
#endif // CTL_TYPE_TRAITS_H_

29
ctl/uninitialized_fill.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_UNINITIALIZED_FILL_H_
#define CTL_UNINITIALIZED_FILL_H_
#include "addressof.h"
#include "iterator_traits.h"
namespace ctl {
template<typename ForwardIt, typename T>
void
uninitialized_fill(ForwardIt first, ForwardIt last, const T& value)
{
using ValueType = typename ctl::iterator_traits<ForwardIt>::value_type;
ForwardIt current = first;
try {
for (; current != last; ++current)
::new (static_cast<void*>(ctl::addressof(*current)))
ValueType(value);
} catch (...) {
for (; first != current; ++first)
first->~ValueType();
throw;
}
}
} // namespace ctl
#endif // CTL_UNINITIALIZED_FILL_H_

View file

@ -0,0 +1,52 @@
// -*-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_UNINITIALIZED_FILL_N_H_
#define CTL_UNINITIALIZED_FILL_N_H_
#include "addressof.h"
#include "allocator_traits.h"
#include "iterator_traits.h"
namespace ctl {
template<typename ForwardIt, typename Size, typename T>
ForwardIt
uninitialized_fill_n(ForwardIt first, Size n, const T& value)
{
using ValueType = typename ctl::iterator_traits<ForwardIt>::value_type;
ForwardIt current = first;
try {
for (; n > 0; ++current, --n) {
::new (static_cast<void*>(ctl::addressof(*current)))
ValueType(value);
}
return current;
} catch (...) {
for (; first != current; ++first) {
first->~ValueType();
}
throw;
}
}
template<typename ForwardIt, typename Size, typename T, typename Alloc>
ForwardIt
uninitialized_fill_n(ForwardIt first, Size n, const T& value, Alloc& alloc)
{
using AllocTraits = ctl::allocator_traits<Alloc>;
ForwardIt current = first;
try {
for (; n > 0; ++current, --n) {
AllocTraits::construct(alloc, ctl::addressof(*current), value);
}
return current;
} catch (...) {
for (; first != current; ++first) {
AllocTraits::destroy(alloc, ctl::addressof(*first));
}
throw;
}
}
} // namespace ctl
#endif // CTL_UNINITIALIZED_FILL_N_H_

View file

@ -0,0 +1,52 @@
// -*-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_UNINITIALIZED_MOVE_N_H_
#define CTL_UNINITIALIZED_MOVE_N_H_
#include "addressof.h"
#include "allocator_traits.h"
#include "iterator_traits.h"
#include "utility.h"
namespace ctl {
template<typename InputIt, typename Size, typename ForwardIt>
ForwardIt
uninitialized_move_n(InputIt first, Size n, ForwardIt d_first)
{
using T = typename ctl::iterator_traits<ForwardIt>::value_type;
ForwardIt current = d_first;
try {
for (; n > 0; ++first, (void)++current, --n) {
::new (static_cast<void*>(ctl::addressof(*current)))
T(ctl::move(*first));
}
} catch (...) {
for (; d_first != current; ++d_first) {
d_first->~T();
}
throw;
}
return current;
}
template<typename InputIt, typename Size, typename ForwardIt, typename Alloc>
ForwardIt
uninitialized_move_n(InputIt first, Size n, ForwardIt d_first, Alloc& alloc)
{
using AllocTraits = ctl::allocator_traits<Alloc>;
ForwardIt current = d_first;
try {
for (; n > 0; ++first, (void)++current, --n)
AllocTraits::construct(
alloc, ctl::addressof(*current), ctl::move(*first));
} catch (...) {
for (; d_first != current; ++d_first)
AllocTraits::destroy(alloc, ctl::addressof(*d_first));
throw;
}
return current;
}
} // namespace ctl
#endif // CTL_UNINITIALIZED_MOVE_N_H_

View file

@ -1,245 +1,594 @@
// -*-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_OPTIONAL_H_
#define COSMOPOLITAN_CTL_OPTIONAL_H_
#include "new.h"
#include "utility.h"
#ifndef CTL_VECTOR_H_
#define CTL_VECTOR_H_
#include "allocator.h"
#include "allocator_traits.h"
#include "copy.h"
#include "distance.h"
#include "equal.h"
#include "fill_n.h"
#include "initializer_list.h"
#include "iterator_traits.h"
#include "lexicographical_compare.h"
#include "max.h"
#include "move_backward.h"
#include "move_iterator.h"
#include "out_of_range.h"
#include "reverse_iterator.h"
#include "uninitialized_fill.h"
#include "uninitialized_fill_n.h"
#include "uninitialized_move_n.h"
namespace ctl {
template<typename T>
struct vector
template<typename T, typename Allocator = ctl::allocator<T>>
class vector
{
size_t n = 0;
size_t c = 0;
T* p = nullptr;
public:
using value_type = T;
using allocator_type = Allocator;
using size_type = size_t;
using difference_type = ptrdiff_t;
using reference = value_type&;
using const_reference = const value_type&;
using pointer = typename ctl::allocator_traits<Allocator>::pointer;
using const_pointer =
typename ctl::allocator_traits<Allocator>::const_pointer;
using iterator = pointer;
using const_iterator = const_pointer;
using reverse_iterator = ctl::reverse_iterator<iterator>;
using const_reverse_iterator = ctl::reverse_iterator<const_iterator>;
using iterator = T*;
using const_iterator = const T*;
vector() = default;
~vector()
public:
vector() noexcept(noexcept(Allocator()))
: alloc_(), data_(nullptr), size_(0), capacity_(0)
{
delete[] p;
}
explicit vector(const Allocator& alloc) noexcept
: alloc_(alloc), data_(nullptr), size_(0), capacity_(0)
{
}
vector(size_type count,
const T& value,
const Allocator& alloc = Allocator())
: alloc_(alloc), data_(nullptr), size_(0), capacity_(0)
{
assign(count, value);
}
explicit vector(size_type count, const Allocator& alloc = Allocator())
: alloc_(alloc), data_(nullptr), size_(0), capacity_(0)
{
resize(count);
}
template<class InputIt>
vector(InputIt first, InputIt last, const Allocator& alloc = Allocator())
: alloc_(alloc), data_(nullptr), size_(0), capacity_(0)
{
assign(first, last);
}
vector(const vector& other)
: alloc_(ctl::allocator_traits<
Allocator>::select_on_container_copy_construction(other.alloc_))
, data_(nullptr)
, size_(0)
, capacity_(0)
{
n = other.n;
c = other.c;
p = new T[c];
for (size_t i = 0; i < n; ++i)
new (&p[i]) T(other.p[i]);
assign(other.begin(), other.end());
}
vector(const vector& other, const Allocator& alloc)
: alloc_(alloc), data_(nullptr), size_(0), capacity_(0)
{
assign(other.begin(), other.end());
}
vector(vector&& other) noexcept
: alloc_(ctl::move(other.alloc_))
, data_(other.data_)
, size_(other.size_)
, capacity_(other.capacity_)
{
n = other.n;
c = other.c;
p = other.p;
other.n = 0;
other.c = 0;
other.p = nullptr;
other.data_ = nullptr;
other.size_ = 0;
other.capacity_ = 0;
}
explicit vector(size_t count, const T& value = T())
vector(vector&& other, const Allocator& alloc)
: alloc_(alloc), data_(nullptr), size_(0), capacity_(0)
{
n = count;
c = count;
p = new T[c];
for (size_t i = 0; i < n; ++i)
new (&p[i]) T(value);
if (alloc_ == other.alloc_) {
data_ = other.data_;
size_ = other.size_;
capacity_ = other.capacity_;
other.data_ = nullptr;
other.size_ = 0;
other.capacity_ = 0;
} else {
assign(ctl::make_move_iterator(other.begin()),
ctl::make_move_iterator(other.end()));
}
}
vector(std::initializer_list<T> init, const Allocator& alloc = Allocator())
: alloc_(alloc), data_(nullptr), size_(0), capacity_(0)
{
assign(init.begin(), init.end());
}
~vector()
{
clear();
ctl::allocator_traits<Allocator>::deallocate(alloc_, data_, capacity_);
}
vector& operator=(const vector& other)
{
if (this != &other) {
T* newData = new T[other.c];
for (size_t i = 0; i < other.n; ++i) {
newData[i] = other.p[i];
}
delete[] p;
p = newData;
n = other.n;
c = other.c;
if (ctl::allocator_traits<
Allocator>::propagate_on_container_copy_assignment::value)
alloc_ = other.alloc_;
assign(other.begin(), other.end());
}
return *this;
}
vector& operator=(vector&& other) noexcept
vector& operator=(vector&& other) noexcept(
ctl::allocator_traits<Allocator>::is_always_equal::value)
{
if (this != &other) {
delete[] p;
p = other.p;
n = other.n;
c = other.c;
other.p = nullptr;
other.n = 0;
other.c = 0;
clear();
ctl::allocator_traits<Allocator>::deallocate(
alloc_, data_, capacity_);
if (ctl::allocator_traits<
Allocator>::propagate_on_container_move_assignment::value)
alloc_ = ctl::move(other.alloc_);
data_ = other.data_;
size_ = other.size_;
capacity_ = other.capacity_;
other.data_ = nullptr;
other.size_ = 0;
other.capacity_ = 0;
}
return *this;
}
bool empty() const
vector& operator=(std::initializer_list<T> ilist)
{
return !n;
assign(ilist.begin(), ilist.end());
return *this;
}
size_t size() const
void assign(size_type count, const T& value)
{
return n;
clear();
if (count > capacity_)
reallocate(count);
ctl::uninitialized_fill_n(data_, count, value);
size_ = count;
}
size_t capacity() const
template<class InputIt>
void assign(InputIt first, InputIt last)
{
return c;
clear();
for (; first != last; ++first)
push_back(*first);
}
T& operator[](size_t i)
void assign(std::initializer_list<T> ilist)
{
if (i >= n)
__builtin_trap();
return p[i];
assign(ilist.begin(), ilist.end());
}
const T& operator[](size_t i) const
reference at(size_type pos)
{
if (i >= n)
__builtin_trap();
return p[i];
if (pos >= size_)
throw ctl::out_of_range("out of range");
return data_[pos];
}
iterator begin()
const_reference at(size_type pos) const
{
return p;
if (pos >= size_)
throw ctl::out_of_range("out of range");
return data_[pos];
}
iterator end()
reference operator[](size_type pos)
{
return p + n;
return data_[pos];
}
const_iterator cbegin() const
const_reference operator[](size_type pos) const
{
return p;
return data_[pos];
}
const_iterator cend() const
reference front()
{
return p + n;
return data_[0];
}
T& front()
const_reference front() const
{
if (!n)
__builtin_trap();
return p[0];
return data_[0];
}
const T& front() const
reference back()
{
if (!n)
__builtin_trap();
return p[0];
return data_[size_ - 1];
}
T& back()
const_reference back() const
{
if (!n)
__builtin_trap();
return p[n - 1];
return data_[size_ - 1];
}
const T& back() const
T* data() noexcept
{
if (!n)
__builtin_trap();
return p[n - 1];
return data_;
}
void clear()
const T* data() const noexcept
{
for (size_t i = 0; i < n; ++i)
p[i].~T();
n = 0;
return data_;
}
void reserve(size_t c2)
iterator begin() noexcept
{
if (c2 <= c)
return;
T* newP = new T[c2];
for (size_t i = 0; i < n; ++i)
newP[i] = ctl::move(p[i]);
delete[] p;
p = newP;
c = c2;
return data_;
}
void push_back(const T& e)
const_iterator begin() const noexcept
{
if (n == c) {
size_t c2 = c + 1;
c2 += c2 >> 1;
reserve(c2);
}
new (&p[n]) T(e);
++n;
return data_;
}
void push_back(T&& e)
const_iterator cbegin() const noexcept
{
if (n == c) {
size_t c2 = c + 1;
c2 += c2 >> 1;
reserve(c2);
}
new (&p[n]) T(ctl::forward<T>(e));
++n;
return data_;
}
template<typename... Args>
void emplace_back(Args&&... args)
iterator end() noexcept
{
if (n == c) {
size_t c2 = c + 1;
c2 += c2 >> 1;
reserve(c2);
return data_ + size_;
}
new (&p[n]) T(ctl::forward<Args>(args)...);
++n;
const_iterator end() const noexcept
{
return data_ + size_;
}
const_iterator cend() const noexcept
{
return data_ + size_;
}
reverse_iterator rbegin() noexcept
{
return reverse_iterator(end());
}
const_reverse_iterator rbegin() const noexcept
{
return const_reverse_iterator(end());
}
const_reverse_iterator crbegin() const noexcept
{
return const_reverse_iterator(end());
}
reverse_iterator rend() noexcept
{
return reverse_iterator(begin());
}
const_reverse_iterator rend() const noexcept
{
return const_reverse_iterator(begin());
}
const_reverse_iterator crend() const noexcept
{
return const_reverse_iterator(begin());
}
bool empty() const noexcept
{
return size_ == 0;
}
size_type size() const noexcept
{
return size_;
}
size_type max_size() const noexcept
{
return __PTRDIFF_MAX__;
}
size_type capacity() const noexcept
{
return capacity_;
}
void reserve(size_type new_cap)
{
if (new_cap > capacity_)
reallocate(new_cap);
}
void shrink_to_fit()
{
if (size_ < capacity_)
reallocate(size_);
}
void clear() noexcept
{
for (size_type i = 0; i < size_; ++i)
ctl::allocator_traits<Allocator>::destroy(alloc_, data_ + i);
size_ = 0;
}
iterator insert(const_iterator pos, const T& value)
{
return insert(pos, 1, value);
}
iterator insert(const_iterator pos, T&& value)
{
difference_type index = pos - begin();
if (size_ == capacity_)
grow();
iterator it = begin() + index;
ctl::move_backward(it, end(), end() + 1);
*it = ctl::move(value);
++size_;
return it;
}
iterator insert(const_iterator pos, size_type count, const T& value)
{
difference_type index = pos - begin();
if (size_ + count > capacity_)
reallocate(ctl::max(size_ + count, capacity_ * 2));
iterator it = begin() + index;
ctl::move_backward(it, end(), end() + count);
ctl::fill_n(it, count, value);
size_ += count;
return it;
}
template<class InputIt>
iterator insert(const_iterator pos, InputIt first, InputIt last)
{
difference_type count = ctl::distance(first, last);
difference_type index = pos - begin();
if (size_ + count > capacity_)
reallocate(ctl::max(size_ + count, capacity_ * 2));
iterator it = begin() + index;
ctl::move_backward(it, end(), end() + count);
ctl::copy(first, last, it);
size_ += count;
return it;
}
iterator insert(const_iterator pos, std::initializer_list<T> ilist)
{
return insert(pos, ilist.begin(), ilist.end());
}
template<class... Args>
iterator emplace(const_iterator pos, Args&&... args)
{
difference_type index = pos - begin();
if (size_ == capacity_)
grow();
iterator it = begin() + index;
ctl::move_backward(it, end(), end() + 1);
ctl::allocator_traits<Allocator>::construct(
alloc_, it, ctl::forward<Args>(args)...);
++size_;
return it;
}
iterator erase(const_iterator pos)
{
return erase(pos, pos + 1);
}
iterator erase(const_iterator first, const_iterator last)
{
difference_type index = first - begin();
difference_type count = last - first;
iterator it = begin() + index;
ctl::move(it + count, end(), it);
for (difference_type i = 0; i < count; ++i)
ctl::allocator_traits<Allocator>::destroy(alloc_, end() - i - 1);
size_ -= count;
return it;
}
void push_back(const T& value)
{
if (size_ == capacity_)
grow();
ctl::allocator_traits<Allocator>::construct(
alloc_, data_ + size_, value);
++size_;
}
void push_back(T&& value)
{
if (size_ == capacity_)
grow();
ctl::allocator_traits<Allocator>::construct(
alloc_, data_ + size_, ctl::move(value));
++size_;
}
template<class... Args>
reference emplace_back(Args&&... args)
{
if (size_ == capacity_)
grow();
ctl::allocator_traits<Allocator>::construct(
alloc_, data_ + size_, ctl::forward<Args>(args)...);
return data_[size_++];
}
void pop_back()
{
if (n > 0) {
--n;
p[n].~T();
if (!empty()) {
ctl::allocator_traits<Allocator>::destroy(alloc_,
data_ + size_ - 1);
--size_;
}
}
void resize(size_t n2)
void resize(size_type count)
{
if (n2 > n) {
reserve(n2);
for (size_t i = n; i < n2; ++i)
new (&p[i]) T();
} else if (n2 < n) {
for (size_t i = n2; i < n; ++i)
p[i].~T();
}
n = n2;
resize(count, T());
}
void swap(vector& other) noexcept
void resize(size_type count, const value_type& value)
{
ctl::swap(n, other.n);
ctl::swap(c, other.c);
ctl::swap(p, other.p);
if (count > size_) {
if (count > capacity_)
reallocate(count);
ctl::uninitialized_fill(data_ + size_, data_ + count, value);
} else if (count < size_) {
for (size_type i = count; i < size_; ++i)
ctl::allocator_traits<Allocator>::destroy(alloc_, data_ + i);
}
size_ = count;
}
void swap(vector& other) noexcept(
ctl::allocator_traits<Allocator>::is_always_equal::value)
{
using ctl::swap;
swap(alloc_, other.alloc_);
swap(data_, other.data_);
swap(size_, other.size_);
swap(capacity_, other.capacity_);
}
allocator_type get_allocator() const noexcept
{
return alloc_;
}
private:
void grow()
{
size_type c2;
c2 = capacity_;
if (c2 < 4)
c2 = 4;
c2 += c2 >> 1;
reallocate(c2);
}
void reallocate(size_type new_capacity)
{
pointer new_data =
ctl::allocator_traits<Allocator>::allocate(alloc_, new_capacity);
size_type new_size = size_ < new_capacity ? size_ : new_capacity;
try {
ctl::uninitialized_move_n(data_, new_size, new_data);
} catch (...) {
ctl::allocator_traits<Allocator>::deallocate(
alloc_, new_data, new_capacity);
throw;
}
for (size_type i = 0; i < size_; ++i)
ctl::allocator_traits<Allocator>::destroy(alloc_, data_ + i);
ctl::allocator_traits<Allocator>::deallocate(alloc_, data_, capacity_);
data_ = new_data;
size_ = new_size;
capacity_ = new_capacity;
}
Allocator alloc_;
pointer data_;
size_type size_;
size_type capacity_;
};
template<class T, class Alloc>
bool
operator==(const vector<T, Alloc>& lhs, const vector<T, Alloc>& rhs)
{
return lhs.size() == rhs.size() &&
ctl::equal(lhs.begin(), lhs.end(), rhs.begin());
}
template<class T, class Alloc>
bool
operator!=(const vector<T, Alloc>& lhs, const vector<T, Alloc>& rhs)
{
return !(lhs == rhs);
}
template<class T, class Alloc>
bool
operator<(const vector<T, Alloc>& lhs, const vector<T, Alloc>& rhs)
{
return ctl::lexicographical_compare(
lhs.begin(), lhs.end(), rhs.begin(), rhs.end());
}
template<class T, class Alloc>
bool
operator<=(const vector<T, Alloc>& lhs, const vector<T, Alloc>& rhs)
{
return !(rhs < lhs);
}
template<class T, class Alloc>
bool
operator>(const vector<T, Alloc>& lhs, const vector<T, Alloc>& rhs)
{
return rhs < lhs;
}
template<class T, class Alloc>
bool
operator>=(const vector<T, Alloc>& lhs, const vector<T, Alloc>& rhs)
{
return !(lhs < rhs);
}
template<class T, class Alloc>
void
swap(vector<T, Alloc>& lhs,
vector<T, Alloc>& rhs) noexcept(noexcept(lhs.swap(rhs)))
{
lhs.swap(rhs);
}
template<class InputIt,
class Alloc =
ctl::allocator<typename ctl::iterator_traits<InputIt>::value_type>>
vector(InputIt, InputIt, Alloc = Alloc())
-> vector<typename ctl::iterator_traits<InputIt>::value_type, Alloc>;
template<class Alloc>
vector(size_t,
const typename ctl::allocator_traits<Alloc>::value_type&,
Alloc = Alloc())
-> vector<typename ctl::allocator_traits<Alloc>::value_type, Alloc>;
} // namespace ctl
#endif // COSMOPOLITAN_CTL_OPTIONAL_H_
#endif // CTL_VECTOR_H_

View file

@ -17,6 +17,10 @@ TEST_CTL_DIRECTDEPS = \
LIBC_STDIO \
LIBC_INTRIN \
LIBC_MEM \
LIBC_STDIO \
THIRD_PARTY_LIBCXX \
THIRD_PARTY_LIBCXXABI \
THIRD_PARTY_LIBUNWIND \
TEST_CTL_DEPS := \
$(call uniq,$(foreach x,$(TEST_CTL_DIRECTDEPS),$($(x))))
@ -33,6 +37,10 @@ o/$(MODE)/test/ctl/%.dbg: \
$(APE_NO_MODIFY_SELF)
@$(APELINK)
$(TEST_CTL_OBJS): private \
OVERRIDE_CXXFLAGS += \
-fexceptions \
.PHONY: o/$(MODE)/test/ctl
o/$(MODE)/test/ctl: \
$(TEST_CTL_BINS) \

View file

@ -0,0 +1,51 @@
// -*- 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/accumulate.h"
#include "ctl/array.h"
// #include <array>
// #include <numeric>
// #define ctl std
int
main()
{
ctl::array<int, 5> arr = { 1, 2, 3, 4, 5 };
// Test basic accumulation with addition
if (ctl::accumulate(arr.begin(), arr.end(), 0) != 15)
return 1;
// Test accumulation with initial value
if (ctl::accumulate(arr.begin(), arr.end(), 10) != 25)
return 2;
// Test accumulation with custom operation (multiplication)
if (ctl::accumulate(
arr.begin(), arr.end(), 1, [](int a, int b) { return a * b; }) != 120)
return 3;
// Test accumulation with empty range
if (ctl::accumulate(arr.end(), arr.end(), 0) != 0)
return 4;
// Test accumulation with single element
if (ctl::accumulate(arr.begin(), arr.begin() + 1, 0) != 1)
return 5;
}

56
test/ctl/advance_test.cc Normal file
View file

@ -0,0 +1,56 @@
// -*- 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/advance.h"
#include "ctl/array.h"
// #include <array>
// #include <iterator>
// #define ctl std
int
main()
{
ctl::array<int, 5> arr = { 1, 2, 3, 4, 5 };
// Test advancing forward
auto it = arr.begin();
ctl::advance(it, 2);
if (*it != 3)
return 1;
// Test advancing to the end
ctl::advance(it, 2);
if (it != arr.end() - 1)
return 2;
// Test advancing backward
ctl::advance(it, -2);
if (*it != 3)
return 3;
// Test advancing by zero
ctl::advance(it, 0);
if (*it != 3)
return 4;
// Test advancing to the beginning
ctl::advance(it, -2);
if (it != arr.begin())
return 5;
}

52
test/ctl/all_of_test.cc Normal file
View file

@ -0,0 +1,52 @@
// -*- 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/all_of.h"
#include "ctl/array.h"
#include <algorithm>
#include <array>
#define ctl std
int
main()
{
ctl::array<int, 5> arr1 = { 2, 4, 6, 8, 10 };
ctl::array<int, 5> arr2 = { 2, 4, 5, 8, 10 };
// Test when all elements satisfy the condition
if (!ctl::all_of(
arr1.begin(), arr1.end(), [](int n) { return n % 2 == 0; }))
return 1;
// Test when not all elements satisfy the condition
if (ctl::all_of(arr2.begin(), arr2.end(), [](int n) { return n % 2 == 0; }))
return 2;
// Test with empty range
if (!ctl::all_of(arr1.end(), arr1.end(), [](int n) { return false; }))
return 3;
// Test with all elements satisfying a different condition
if (!ctl::all_of(arr1.begin(), arr1.end(), [](int n) { return n > 0; }))
return 4;
// Test with no elements satisfying the condition
if (ctl::all_of(arr1.begin(), arr1.end(), [](int n) { return n > 10; }))
return 5;
}

51
test/ctl/any_of_test.cc Normal file
View file

@ -0,0 +1,51 @@
// -*- 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/any_of.h"
#include "ctl/array.h"
// #include <algorithm>
// #include <array>
// #define ctl std
int
main()
{
ctl::array<int, 5> arr1 = { 1, 3, 5, 7, 9 };
ctl::array<int, 5> arr2 = { 2, 4, 6, 8, 10 };
// Test when at least one element satisfies the condition
if (!ctl::any_of(arr1.begin(), arr1.end(), [](int n) { return n == 7; }))
return 1;
// Test when no elements satisfy the condition
if (ctl::any_of(arr1.begin(), arr1.end(), [](int n) { return n == 11; }))
return 2;
// Test with empty range
if (ctl::any_of(arr1.end(), arr1.end(), [](int n) { return true; }))
return 3;
// Test when all elements satisfy the condition
if (!ctl::any_of(arr2.begin(), arr2.end(), [](int n) { return true; }))
return 4;
// Test with a different condition
if (!ctl::any_of(arr1.begin(), arr1.end(), [](int n) { return n > 5; }))
return 5;
}

267
test/ctl/array_test.cc Normal file
View file

@ -0,0 +1,267 @@
// -*- 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/array.h"
// #include <array>
// #define ctl std
int
main()
{
// Test construction and basic properties
{
ctl::array<int, 5> arr = { 1, 2, 3, 4, 5 };
if (arr.size() != 5)
return 2;
if (arr.max_size() != 5)
return 3;
if (arr.empty())
return 4;
}
// Test element access
{
ctl::array<int, 3> arr = { 10, 20, 30 };
if (arr[0] != 10 || arr[1] != 20 || arr[2] != 30)
return 5;
if (arr.front() != 10)
return 6;
if (arr.back() != 30)
return 7;
}
// Test data() method
{
ctl::array<int, 3> arr = { 1, 2, 3 };
int* data = arr.data();
if (data[0] != 1 || data[1] != 2 || data[2] != 3)
return 9;
}
// Test iterators
{
ctl::array<int, 3> arr = { 1, 2, 3 };
int sum = 0;
for (auto it = arr.begin(); it != arr.end(); ++it) {
sum += *it;
}
if (sum != 6)
return 10;
sum = 0;
for (auto it = arr.rbegin(); it != arr.rend(); ++it) {
sum += *it;
}
if (sum != 6)
return 11;
}
// Test const iterators
{
const ctl::array<int, 3> arr = { 1, 2, 3 };
int sum = 0;
for (auto it = arr.cbegin(); it != arr.cend(); ++it) {
sum += *it;
}
if (sum != 6)
return 12;
sum = 0;
for (auto it = arr.crbegin(); it != arr.crend(); ++it) {
sum += *it;
}
if (sum != 6)
return 13;
}
// Test fill method
{
ctl::array<int, 5> arr;
arr.fill(42);
for (int i = 0; i < 5; ++i) {
if (arr[i] != 42)
return 14;
}
}
// Test swap method
{
ctl::array<int, 3> arr1 = { 1, 2, 3 };
ctl::array<int, 3> arr2 = { 4, 5, 6 };
arr1.swap(arr2);
if (arr1[0] != 4 || arr1[1] != 5 || arr1[2] != 6)
return 15;
if (arr2[0] != 1 || arr2[1] != 2 || arr2[2] != 3)
return 16;
}
// Test comparison operators
{
ctl::array<int, 3> arr1 = { 1, 2, 3 };
ctl::array<int, 3> arr2 = { 1, 2, 3 };
ctl::array<int, 3> arr3 = { 1, 2, 4 };
if (!(arr1 == arr2))
return 17;
if (arr1 != arr2)
return 18;
if (!(arr1 < arr3))
return 19;
if (arr3 <= arr1)
return 20;
if (!(arr3 > arr1))
return 21;
if (arr1 >= arr3)
return 22;
}
// Test non-member swap function
{
ctl::array<int, 3> arr1 = { 1, 2, 3 };
ctl::array<int, 3> arr2 = { 4, 5, 6 };
swap(arr1, arr2);
if (arr1[0] != 4 || arr1[1] != 5 || arr1[2] != 6)
return 23;
if (arr2[0] != 1 || arr2[1] != 2 || arr2[2] != 3)
return 24;
}
// Test with non-trivial type
{
struct NonTrivial
{
int value;
NonTrivial(int v = 0) : value(v)
{
}
bool operator==(const NonTrivial& other) const
{
return value == other.value;
}
};
ctl::array<NonTrivial, 3> arr = { 1, 2, 3 };
if (arr[0].value != 1 || arr[1].value != 2 || arr[2].value != 3)
return 25;
}
// Test empty array
{
ctl::array<int, 0> arr;
if (!arr.empty())
return 26;
if (arr.size() != 0)
return 27;
if (arr.begin() != arr.end())
return 28;
}
// Test basic array functionality
{
ctl::array<int, 5> arr = { 1, 2, 3, 4, 5 };
if (arr.size() != 5)
return 2;
if (arr[0] != 1 || arr[4] != 5)
return 3;
}
// Test reverse iterator basics
{
ctl::array<int, 5> arr = { 1, 2, 3, 4, 5 };
auto rit = arr.rbegin();
if (*rit != 5)
return 4;
++rit;
if (*rit != 4)
return 5;
if (*(arr.rbegin() + 2) != 3)
return 6;
}
// Test reverse iterator traversal
{
ctl::array<int, 5> arr = { 1, 2, 3, 4, 5 };
int expected = 5;
for (auto rit = arr.rbegin(); rit != arr.rend(); ++rit) {
if (*rit != expected)
return 7;
--expected;
}
}
// Test const reverse iterator
{
const ctl::array<int, 5> arr = { 1, 2, 3, 4, 5 };
auto crit = arr.crbegin();
if (*crit != 5)
return 8;
++crit;
if (*crit != 4)
return 9;
}
// Test reverse iterator arithmetic
{
ctl::array<int, 5> arr = { 1, 2, 3, 4, 5 };
auto rit = arr.rbegin();
rit += 2;
if (*rit != 3)
return 10;
rit -= 1;
if (*rit != 4)
return 11;
if (*(rit + 2) != 2)
return 12;
if (*(rit - 1) != 5)
return 13;
}
// Test reverse iterator comparison
{
ctl::array<int, 5> arr = { 1, 2, 3, 4, 5 };
auto rit1 = arr.rbegin();
auto rit2 = arr.rbegin() + 2;
if (rit1 >= rit2)
return 14;
if (!(rit1 < rit2))
return 15;
if (rit1 == rit2)
return 16;
}
// Test it seems legit
{
ctl::array<int, 3> arr = { 1, 2, 3 };
auto rit = arr.rbegin();
if (*rit != 3)
return 1;
++rit;
if (*rit != 2)
return 2;
++rit;
if (*rit != 1)
return 3;
++rit;
if (rit != arr.rend())
return 4;
}
}

View file

@ -0,0 +1,61 @@
// -*- 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/array.h"
#include "ctl/back_inserter.h"
#include "ctl/copy.h"
#include "ctl/vector.h"
// #include <array>
// #include <iterator>
// #include <vector>
// #define ctl std
int
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));
// 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 with a single element
ctl::back_inserter(vec) = 7;
// Check if the new element was added
if (vec.size() != 7)
return 3;
if (vec[6] != 7)
return 4;
// Test with an empty source range
ctl::array<int, 0> 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;
}

66
test/ctl/copy_test.cc Normal file
View file

@ -0,0 +1,66 @@
// -*- 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/array.h"
#include "ctl/copy.h"
// #include <iterator>
// #include <array>
// #define ctl std
int
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());
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;
}

View file

@ -17,10 +17,9 @@
// PERFORMANCE OF THIS SOFTWARE.
#include "ctl/string.h"
#include "ctl/type_traits.h"
#include "libc/mem/leaks.h"
#include <__type_traits/is_same.h>
#include "libc/str/str.h"
// #include <string>
@ -366,7 +365,7 @@ main()
{
String s;
if constexpr (std::is_same_v<ctl::string, decltype(s)>) {
if constexpr (ctl::is_same_v<ctl::string, decltype(s)>) {
// tests the small-string optimization on ctl::string
for (int i = 0; i < 23; ++i) {
s.append("a");
@ -397,7 +396,7 @@ main()
s.resize(4);
if (s != "arst")
return 105;
if constexpr (std::is_same_v<ctl::string, decltype(s)>) {
if constexpr (ctl::is_same_v<ctl::string, decltype(s)>) {
String r(s);
if (issmall(s) || !issmall(r))
return 106;
@ -405,5 +404,4 @@ main()
}
CheckForMemoryLeaks();
return 0;
}

View file

@ -16,11 +16,12 @@
// TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
// PERFORMANCE OF THIS SOFTWARE.
#include "ctl/type_traits.h"
#include "ctl/unique_ptr.h"
#include <__type_traits/is_same.h>
#include "libc/mem/leaks.h"
// #include <memory>
// #include <type_traits>
// #define ctl std
template<typename T, typename D = ctl::default_delete<T>>
@ -70,7 +71,7 @@ struct FinalDeleter final
static_assert(sizeof(Ptr<int, SetsGDeleter>) == sizeof(int*));
// not everyone uses [[no_unique_address]]...
static_assert(!std::is_same_v<Ptr<int>, ctl::unique_ptr<int>> ||
static_assert(!ctl::is_same_v<Ptr<int>, ctl::unique_ptr<int>> ||
sizeof(Ptr<int, FinalDeleter>) == sizeof(int*));
struct SetsGCtor
@ -227,6 +228,4 @@ main()
// TODO(mrdomino): Fix memory leaks reported by MODE=dbg
// CheckForMemoryLeaks();
return 0;
}

View file

@ -16,13 +16,10 @@
// TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
// PERFORMANCE OF THIS SOFTWARE.
#include "ctl/string.h"
#include "ctl/vector.h"
#include "libc/mem/leaks.h"
#include <cosmo.h>
#include "ctl/string.h"
// #include <string>
// #include <vector>
// #define ctl std
@ -315,6 +312,45 @@ main()
return 69;
}
{
ctl::vector<int> A = { 1, 2, 3 };
if (A[1] != 2)
return 70;
A = { 4, 5, 6 };
if (A[1] != 5)
return 71;
}
{
ctl::vector<int> arr = { 1, 2, 3 };
auto rit = arr.rbegin();
if (*rit != 3)
return 72;
++rit;
if (*rit != 2)
return 73;
++rit;
if (*rit != 1)
return 74;
++rit;
if (rit != arr.rend())
return 75;
}
{
ctl::vector<ctl::string> 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();
return 0;
}

View file

@ -144,7 +144,6 @@ static void *pthread_main(void *ptr) {
struct State *s = ptr;
struct State children[2];
int fd, rc;
fd = s->fd;
if (s->id < 8) {
for (int i = 0; i < 2; ++i) {

View file

@ -0,0 +1,25 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set et ft=c ts=2 sts=2 sw=2 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 "libc/stdio/rand.h"
#include "libc/testlib/testlib.h"
TEST(lemur64, test) {
EXPECT_EQ(1819718037028923529, lemur64());
EXPECT_EQ(-3120132252617434764, lemur64());
}

View file

@ -46,6 +46,8 @@
(gcc-builtin-functions
'("__builtin_strlen"
"__builtin_memcpy"
"__builtin_memmove"
"__builtin_setjmp"
"__builtin_longjmp"
"__builtin_va_start"

View file

@ -771,7 +771,9 @@
dots (cosmo-file-name-sans-extensions name))))
(if (file-exists-p cc-version)
cc-version
c-version))
(if (eq major-mode 'c++-mode)
cc-version
c-version)))
))))
(when buddy
(find-file buddy))))))