From 38921dc46b6b54cb0b57453db68f9307e2fc97c5 Mon Sep 17 00:00:00 2001 From: Justine Tunney Date: Thu, 27 Jun 2024 22:18:55 -0700 Subject: [PATCH] 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. --- ctl/BUILD.mk | 1 + ctl/accumulate.h | 28 ++ ctl/addressof.h | 29 ++ ctl/advance.h | 24 ++ ctl/all_of.h | 22 ++ ctl/allocator.h | 94 +++++ ctl/allocator_traits.h | 72 ++++ ctl/any_of.h | 22 ++ ctl/array.h | 243 +++++++++++++ ctl/back_inserter.h | 64 ++++ ctl/bad_alloc.h | 23 ++ ctl/copy.h | 22 ++ ctl/distance.h | 37 ++ ctl/enable_if.h | 21 ++ ctl/exception.h | 22 ++ ctl/fill.h | 18 + ctl/fill_n.h | 19 + ctl/iterator.h | 28 ++ ctl/iterator_traits.h | 31 ++ ctl/lexicographical_compare.h | 43 +++ ctl/map.h | 5 +- ctl/max.h | 17 + ctl/min.h | 17 + ctl/move_backward.h | 20 ++ ctl/move_iterator.h | 173 +++++++++ ctl/new.cc | 52 ++- ctl/new.h | 26 +- ctl/numeric_limits.h | 122 +++++++ ctl/out_of_range.h | 23 ++ ctl/reverse_iterator.h | 183 ++++++++++ ctl/string.cc | 15 +- ctl/string.h | 59 ++- ctl/type_traits.h | 123 +++++++ ctl/uninitialized_fill.h | 29 ++ ctl/uninitialized_fill_n.h | 52 +++ ctl/uninitialized_move_n.h | 52 +++ ctl/vector.h | 635 +++++++++++++++++++++++++-------- test/ctl/BUILD.mk | 8 + test/ctl/accumulate_test.cc | 51 +++ test/ctl/advance_test.cc | 56 +++ test/ctl/all_of_test.cc | 52 +++ test/ctl/any_of_test.cc | 51 +++ test/ctl/array_test.cc | 267 ++++++++++++++ test/ctl/back_inserter_test.cc | 61 ++++ test/ctl/copy_test.cc | 66 ++++ test/ctl/string_test.cc | 8 +- test/ctl/unique_ptr_test.cc | 9 +- test/ctl/vector_test.cc | 46 ++- test/libc/runtime/zipos_test.c | 1 - test/libc/stdio/lemur64_test.c | 25 ++ tool/emacs/cosmo-c-builtins.el | 2 + tool/emacs/cosmo-stuff.el | 4 +- 52 files changed, 2980 insertions(+), 193 deletions(-) create mode 100644 ctl/accumulate.h create mode 100644 ctl/addressof.h create mode 100644 ctl/advance.h create mode 100644 ctl/all_of.h create mode 100644 ctl/allocator.h create mode 100644 ctl/allocator_traits.h create mode 100644 ctl/any_of.h create mode 100644 ctl/array.h create mode 100644 ctl/back_inserter.h create mode 100644 ctl/bad_alloc.h create mode 100644 ctl/copy.h create mode 100644 ctl/distance.h create mode 100644 ctl/enable_if.h create mode 100644 ctl/exception.h create mode 100644 ctl/fill.h create mode 100644 ctl/fill_n.h create mode 100644 ctl/iterator.h create mode 100644 ctl/iterator_traits.h create mode 100644 ctl/lexicographical_compare.h create mode 100644 ctl/max.h create mode 100644 ctl/min.h create mode 100644 ctl/move_backward.h create mode 100644 ctl/move_iterator.h create mode 100644 ctl/numeric_limits.h create mode 100644 ctl/out_of_range.h create mode 100644 ctl/reverse_iterator.h create mode 100644 ctl/type_traits.h create mode 100644 ctl/uninitialized_fill.h create mode 100644 ctl/uninitialized_fill_n.h create mode 100644 ctl/uninitialized_move_n.h create mode 100644 test/ctl/accumulate_test.cc create mode 100644 test/ctl/advance_test.cc create mode 100644 test/ctl/all_of_test.cc create mode 100644 test/ctl/any_of_test.cc create mode 100644 test/ctl/array_test.cc create mode 100644 test/ctl/back_inserter_test.cc create mode 100644 test/ctl/copy_test.cc create mode 100644 test/libc/stdio/lemur64_test.c diff --git a/ctl/BUILD.mk b/ctl/BUILD.mk index ac613db1e..66527b46b 100644 --- a/ctl/BUILD.mk +++ b/ctl/BUILD.mk @@ -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)) diff --git a/ctl/accumulate.h b/ctl/accumulate.h new file mode 100644 index 000000000..786e10321 --- /dev/null +++ b/ctl/accumulate.h @@ -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 +constexpr T +accumulate(InputIt first, InputIt last, T init) +{ + for (; first != last; ++first) + init = init + *first; + return init; +} + +template +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_ diff --git a/ctl/addressof.h b/ctl/addressof.h new file mode 100644 index 000000000..713598bf8 --- /dev/null +++ b/ctl/addressof.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_ADDRESSOF_H_ +#define CTL_ADDRESSOF_H_ + +namespace ctl { + +template +T* +addressof(T& arg) noexcept +{ + return reinterpret_cast( + &const_cast(reinterpret_cast(arg))); +} + +template +R (*addressof(R (*&arg)(Args...)) noexcept) +(Args...) +{ + return arg; +} + +template +T* +addressof(T&&) = delete; + +} // namespace ctl + +#endif // CTL_ADDRESSOF_H_ diff --git a/ctl/advance.h b/ctl/advance.h new file mode 100644 index 000000000..e0408c680 --- /dev/null +++ b/ctl/advance.h @@ -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 +constexpr void +advance(InputIt& it, Distance n) +{ + while (n > 0) { + --n; + ++it; + } + while (n < 0) { + ++n; + --it; + } +} + +} // namespace ctl + +#endif // CTL_ADVANCE_H_ diff --git a/ctl/all_of.h b/ctl/all_of.h new file mode 100644 index 000000000..8934668a2 --- /dev/null +++ b/ctl/all_of.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_ALL_OF_H_ +#define CTL_ALL_OF_H_ + +namespace ctl { + +template +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_ diff --git a/ctl/allocator.h b/ctl/allocator.h new file mode 100644 index 000000000..b084f10e9 --- /dev/null +++ b/ctl/allocator.h @@ -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 +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 + constexpr allocator(const allocator&) 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(::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 + void construct(U* p, Args&&... args) + { + ::new (static_cast(p)) U(ctl::forward(args)...); + } + + template + void destroy(U* p) + { + p->~U(); + } + + size_type max_size() const noexcept + { + return __SIZE_MAX__ / sizeof(T); + } + + allocator& operator=(const allocator&) = default; + + template + struct rebind + { + using other = allocator; + }; +}; + +template +bool +operator==(const allocator&, const allocator&) noexcept +{ + return true; +} + +template +bool +operator!=(const allocator&, const allocator&) noexcept +{ + return false; +} + +} // namespace ctl + +#endif // CTL_ALLOCATOR_H_ diff --git a/ctl/allocator_traits.h b/ctl/allocator_traits.h new file mode 100644 index 000000000..42d43d84d --- /dev/null +++ b/ctl/allocator_traits.h @@ -0,0 +1,72 @@ +#ifndef CTL_ALLOCATOR_TRAITS_H_ +#define CTL_ALLOCATOR_TRAITS_H_ +#include "type_traits.h" + +namespace ctl { + +template +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 + using rebind_alloc = typename Alloc::template rebind::other; + + template + using rebind_traits = allocator_traits>; + + __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 + __attribute__((__always_inline__)) static void construct(Alloc& a, + T* p, + Args&&... args) + { + ::new ((void*)p) T(static_cast(args)...); + } + + template + __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_ diff --git a/ctl/any_of.h b/ctl/any_of.h new file mode 100644 index 000000000..7eec80605 --- /dev/null +++ b/ctl/any_of.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_ANY_OF_H_ +#define CTL_ANY_OF_H_ + +namespace ctl { + +template +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_ diff --git a/ctl/array.h b/ctl/array.h new file mode 100644 index 000000000..fda2ddd04 --- /dev/null +++ b/ctl/array.h @@ -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 +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; + using const_reverse_iterator = ctl::reverse_iterator; + + 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) { + 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 +bool +operator==(const array& lhs, const array& rhs) +{ + for (size_t i = 0; i < N; ++i) { + if (!(lhs[i] == rhs[i])) + return false; + } + return true; +} + +template +bool +operator!=(const array& lhs, const array& rhs) +{ + return !(lhs == rhs); +} + +template +bool +operator<(const array& lhs, const array& 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 +bool +operator<=(const array& lhs, const array& rhs) +{ + return !(rhs < lhs); +} + +template +bool +operator>(const array& lhs, const array& rhs) +{ + return rhs < lhs; +} + +template +bool +operator>=(const array& lhs, const array& rhs) +{ + return !(lhs < rhs); +} + +template +void +swap(array& lhs, array& rhs) noexcept +{ + lhs.swap(rhs); +} + +} // namespace ctl + +#endif // CTL_ARRAY_H_ diff --git a/ctl/back_inserter.h b/ctl/back_inserter.h new file mode 100644 index 000000000..667f95924 --- /dev/null +++ b/ctl/back_inserter.h @@ -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 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 +back_insert_iterator +back_inserter(Container& c) +{ + return back_insert_iterator(c); +} + +} // namespace ctl + +#endif // CTL_BACK_INSERTER_H_ diff --git a/ctl/bad_alloc.h b/ctl/bad_alloc.h new file mode 100644 index 000000000..2f92578fe --- /dev/null +++ b/ctl/bad_alloc.h @@ -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_ diff --git a/ctl/copy.h b/ctl/copy.h new file mode 100644 index 000000000..dd546bce8 --- /dev/null +++ b/ctl/copy.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_COPY_H_ +#define CTL_COPY_H_ + +namespace ctl { + +template +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_ diff --git a/ctl/distance.h b/ctl/distance.h new file mode 100644 index 000000000..83bac2a77 --- /dev/null +++ b/ctl/distance.h @@ -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 +constexpr typename iterator_traits::difference_type +distance_impl(InputIter first, InputIter last, input_iterator_tag) +{ + typename iterator_traits::difference_type res(0); + for (; first != last; ++first) + ++res; + return res; +} + +template +constexpr typename iterator_traits::difference_type +distance_impl(RandIter first, RandIter last, random_access_iterator_tag) +{ + return last - first; +} + +template +constexpr typename iterator_traits::difference_type +distance(InputIter first, InputIter last) +{ + return distance_impl( + first, last, typename iterator_traits::iterator_category()); +} + +} // namespace ctl + +#endif // CTL_DISTANCE_H_ diff --git a/ctl/enable_if.h b/ctl/enable_if.h new file mode 100644 index 000000000..70cb862a3 --- /dev/null +++ b/ctl/enable_if.h @@ -0,0 +1,21 @@ +#ifndef CTL_ENABLE_IF_H_ +#define CTL_ENABLE_IF_H_ + +namespace ctl { + +template +struct enable_if +{}; + +template +struct enable_if +{ + typedef T type; +}; + +template +using enable_if_t = typename enable_if::type; + +} // namespace ctl + +#endif // CTL_ENABLE_IF_H_ diff --git a/ctl/exception.h b/ctl/exception.h new file mode 100644 index 000000000..9c36374e5 --- /dev/null +++ b/ctl/exception.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_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_ diff --git a/ctl/fill.h b/ctl/fill.h new file mode 100644 index 000000000..9d87de776 --- /dev/null +++ b/ctl/fill.h @@ -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 +void +fill(ForwardIt first, ForwardIt last, const T& value) +{ + for (; first != last; ++first) + *first = value; +} + +} // namespace ctl + +#endif // CTL_FILL_H_ diff --git a/ctl/fill_n.h b/ctl/fill_n.h new file mode 100644 index 000000000..b2dd61b24 --- /dev/null +++ b/ctl/fill_n.h @@ -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 +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_ diff --git a/ctl/iterator.h b/ctl/iterator.h new file mode 100644 index 000000000..7b9398b22 --- /dev/null +++ b/ctl/iterator.h @@ -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_ diff --git a/ctl/iterator_traits.h b/ctl/iterator_traits.h new file mode 100644 index 000000000..c08217c76 --- /dev/null +++ b/ctl/iterator_traits.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_ITERATOR_TRAITS_H_ +#define CTL_ITERATOR_TRAITS_H_ +#include "utility.h" + +namespace ctl { + +template +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 +struct iterator_traits +{ + 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_ diff --git a/ctl/lexicographical_compare.h b/ctl/lexicographical_compare.h new file mode 100644 index 000000000..e1644ecc4 --- /dev/null +++ b/ctl/lexicographical_compare.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_LEXICOGRAPHICAL_COMPARE_H_ +#define CTL_LEXICOGRAPHICAL_COMPARE_H_ + +namespace ctl { + +template +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 +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_ */ diff --git a/ctl/map.h b/ctl/map.h index ce564793c..a9a6510bb 100644 --- a/ctl/map.h +++ b/ctl/map.h @@ -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; } diff --git a/ctl/max.h b/ctl/max.h new file mode 100644 index 000000000..63a0cb5bd --- /dev/null +++ b/ctl/max.h @@ -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 +inline constexpr const T& +max(const T& a, const T& b) +{ + return a < b ? b : a; +} + +} // namespace ctl + +#endif /* CTL_MAX_H_ */ diff --git a/ctl/min.h b/ctl/min.h new file mode 100644 index 000000000..7adfe137f --- /dev/null +++ b/ctl/min.h @@ -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 +inline constexpr const T& +min(const T& a, const T& b) +{ + return b < a ? b : a; +} + +} // namespace ctl + +#endif /* CTL_MIN_H_ */ diff --git a/ctl/move_backward.h b/ctl/move_backward.h new file mode 100644 index 000000000..b4d3f2124 --- /dev/null +++ b/ctl/move_backward.h @@ -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 +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_ diff --git a/ctl/move_iterator.h b/ctl/move_iterator.h new file mode 100644 index 000000000..8ce1ed05b --- /dev/null +++ b/ctl/move_iterator.h @@ -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 +class move_iterator +{ + public: + using iterator_type = Iterator; + using iterator_category = + typename ctl::iterator_traits::iterator_category; + using value_type = typename ctl::iterator_traits::value_type; + using difference_type = + typename ctl::iterator_traits::difference_type; + using pointer = Iterator; + using reference = value_type&&; + + constexpr move_iterator() : current() + { + } + + explicit constexpr move_iterator(Iterator i) : current(i) + { + } + + template + constexpr move_iterator(const move_iterator& u) : current(u.base()) + { + } + + constexpr Iterator base() const + { + return current; + } + + constexpr reference operator*() const + { + return static_cast(*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 +__attribute__((__always_inline__)) constexpr move_iterator +make_move_iterator(Iterator i) +{ + return move_iterator(i); +} + +template +constexpr bool +operator==(const move_iterator& x, const move_iterator& y) +{ + return x.base() == y.base(); +} + +template +constexpr bool +operator!=(const move_iterator& x, const move_iterator& y) +{ + return !(x == y); +} + +template +constexpr bool +operator<(const move_iterator& x, const move_iterator& y) +{ + return x.base() < y.base(); +} + +template +constexpr bool +operator<=(const move_iterator& x, const move_iterator& y) +{ + return !(y < x); +} + +template +constexpr bool +operator>(const move_iterator& x, const move_iterator& y) +{ + return y < x; +} + +template +constexpr bool +operator>=(const move_iterator& x, const move_iterator& y) +{ + return !(x < y); +} + +template +constexpr move_iterator +operator+(typename move_iterator::difference_type n, + const move_iterator& x) +{ + return x + n; +} + +template +constexpr auto +operator-(const move_iterator& x, + const move_iterator& y) -> decltype(x.base() - y.base()) +{ + return x.base() - y.base(); +} + +} // namespace ctl + +#endif // CTL_MOVE_ITERATOR_H_ diff --git a/ctl/new.cc b/ctl/new.cc index 638f820a7..044fe4050 100644 --- a/ctl/new.cc +++ b/ctl/new.cc @@ -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); diff --git a/ctl/new.h b/ctl/new.h index 9993a02f8..d9dd36e95 100644 --- a/ctl/new.h +++ b/ctl/new.h @@ -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; diff --git a/ctl/numeric_limits.h b/ctl/numeric_limits.h new file mode 100644 index 000000000..5693a62e2 --- /dev/null +++ b/ctl/numeric_limits.h @@ -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 +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::value; + static constexpr bool is_signed = !ctl::is_unsigned::value; + static constexpr bool is_integer = ctl::is_integral::value; + static constexpr bool is_exact = ctl::is_integral::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 +{ + 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 +{ + 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 +{ + 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_ diff --git a/ctl/out_of_range.h b/ctl/out_of_range.h new file mode 100644 index 000000000..08c65fc18 --- /dev/null +++ b/ctl/out_of_range.h @@ -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_ diff --git a/ctl/reverse_iterator.h b/ctl/reverse_iterator.h new file mode 100644 index 000000000..b7d0245cd --- /dev/null +++ b/ctl/reverse_iterator.h @@ -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 reverse_iterator +{ + public: + using iterator_type = Iterator; + using iterator_category = + typename iterator_traits::iterator_category; + using value_type = typename iterator_traits::value_type; + using difference_type = typename iterator_traits::difference_type; + using pointer = typename iterator_traits::pointer; + using reference = typename iterator_traits::reference; + + constexpr reverse_iterator() : current() + { + } + + constexpr explicit reverse_iterator(Iterator x) : current(x) + { + } + + template + constexpr reverse_iterator(const reverse_iterator& other) + : current(other.base()) + { + } + + template + constexpr reverse_iterator& operator=(const reverse_iterator& 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 +constexpr bool +operator==(const reverse_iterator& lhs, + const reverse_iterator& rhs) +{ + return lhs.base() == rhs.base(); +} + +template +constexpr bool +operator!=(const reverse_iterator& lhs, + const reverse_iterator& rhs) +{ + return lhs.base() != rhs.base(); +} + +template +constexpr bool +operator<(const reverse_iterator& lhs, + const reverse_iterator& rhs) +{ + return rhs.base() < lhs.base(); +} + +template +constexpr bool +operator<=(const reverse_iterator& lhs, + const reverse_iterator& rhs) +{ + return !(rhs < lhs); +} + +template +constexpr bool +operator>(const reverse_iterator& lhs, + const reverse_iterator& rhs) +{ + return rhs < lhs; +} + +template +constexpr bool +operator>=(const reverse_iterator& lhs, + const reverse_iterator& rhs) +{ + return !(lhs < rhs); +} + +template +constexpr reverse_iterator +operator+(typename reverse_iterator::difference_type n, + const reverse_iterator& it) +{ + return reverse_iterator(it.base() - n); +} + +template +constexpr auto +operator-(const reverse_iterator& lhs, + const reverse_iterator& rhs) -> decltype(rhs.base() - + lhs.base()) +{ + return rhs.base() - lhs.base(); +} + +} // namespace ctl + +#endif // CTL_REVERSE_ITERATOR_H_ diff --git a/ctl/string.cc b/ctl/string.cc index 4e292a188..08ee1e65d 100644 --- a/ctl/string.cc +++ b/ctl/string.cc @@ -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)); - } + 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; diff --git a/ctl/string.h b/ctl/string.h index 6b6935424..69a9cf1b7 100644 --- a/ctl/string.h +++ b/ctl/string.h @@ -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; + using const_reverse_iterator = ctl::reverse_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()) diff --git a/ctl/type_traits.h b/ctl/type_traits.h new file mode 100644 index 000000000..c9dea8584 --- /dev/null +++ b/ctl/type_traits.h @@ -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 +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 +{}; + +template<> +struct is_integral : true_type +{}; + +template<> +struct is_integral : true_type +{}; + +template<> +struct is_integral : true_type +{}; + +template<> +struct is_integral : true_type +{}; + +template<> +struct is_integral : true_type +{}; + +template<> +struct is_integral : true_type +{}; + +template<> +struct is_integral : true_type +{}; + +template<> +struct is_integral : true_type +{}; + +template<> +struct is_integral : true_type +{}; + +template<> +struct is_integral : true_type +{}; + +template<> +struct is_integral : true_type +{}; + +template<> +struct is_integral : true_type +{}; + +template<> +struct is_integral : true_type +{}; + +template<> +struct is_integral : true_type +{}; + +template<> +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_ diff --git a/ctl/uninitialized_fill.h b/ctl/uninitialized_fill.h new file mode 100644 index 000000000..966d948cc --- /dev/null +++ b/ctl/uninitialized_fill.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_UNINITIALIZED_FILL_H_ +#define CTL_UNINITIALIZED_FILL_H_ +#include "addressof.h" +#include "iterator_traits.h" + +namespace ctl { + +template +void +uninitialized_fill(ForwardIt first, ForwardIt last, const T& value) +{ + using ValueType = typename ctl::iterator_traits::value_type; + ForwardIt current = first; + try { + for (; current != last; ++current) + ::new (static_cast(ctl::addressof(*current))) + ValueType(value); + } catch (...) { + for (; first != current; ++first) + first->~ValueType(); + throw; + } +} + +} // namespace ctl + +#endif // CTL_UNINITIALIZED_FILL_H_ diff --git a/ctl/uninitialized_fill_n.h b/ctl/uninitialized_fill_n.h new file mode 100644 index 000000000..c0b6102a8 --- /dev/null +++ b/ctl/uninitialized_fill_n.h @@ -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 +ForwardIt +uninitialized_fill_n(ForwardIt first, Size n, const T& value) +{ + using ValueType = typename ctl::iterator_traits::value_type; + ForwardIt current = first; + try { + for (; n > 0; ++current, --n) { + ::new (static_cast(ctl::addressof(*current))) + ValueType(value); + } + return current; + } catch (...) { + for (; first != current; ++first) { + first->~ValueType(); + } + throw; + } +} + +template +ForwardIt +uninitialized_fill_n(ForwardIt first, Size n, const T& value, Alloc& alloc) +{ + using AllocTraits = ctl::allocator_traits; + 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_ diff --git a/ctl/uninitialized_move_n.h b/ctl/uninitialized_move_n.h new file mode 100644 index 000000000..108cc0e11 --- /dev/null +++ b/ctl/uninitialized_move_n.h @@ -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 +ForwardIt +uninitialized_move_n(InputIt first, Size n, ForwardIt d_first) +{ + using T = typename ctl::iterator_traits::value_type; + ForwardIt current = d_first; + try { + for (; n > 0; ++first, (void)++current, --n) { + ::new (static_cast(ctl::addressof(*current))) + T(ctl::move(*first)); + } + } catch (...) { + for (; d_first != current; ++d_first) { + d_first->~T(); + } + throw; + } + return current; +} + +template +ForwardIt +uninitialized_move_n(InputIt first, Size n, ForwardIt d_first, Alloc& alloc) +{ + using AllocTraits = ctl::allocator_traits; + 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_ diff --git a/ctl/vector.h b/ctl/vector.h index e86e0d503..b5837614c 100644 --- a/ctl/vector.h +++ b/ctl/vector.h @@ -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 -struct vector +template> +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::pointer; + using const_pointer = + typename ctl::allocator_traits::const_pointer; + using iterator = pointer; + using const_iterator = const_pointer; + using reverse_iterator = ctl::reverse_iterator; + using const_reverse_iterator = ctl::reverse_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 + 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 init, const Allocator& alloc = Allocator()) + : alloc_(alloc), data_(nullptr), size_(0), capacity_(0) + { + assign(init.begin(), init.end()); + } + + ~vector() + { + clear(); + ctl::allocator_traits::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::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::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 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 + 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 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(e)); - ++n; + return data_; } - template - void emplace_back(Args&&... args) + iterator end() noexcept { - if (n == c) { - size_t c2 = c + 1; - c2 += c2 >> 1; - reserve(c2); - } - new (&p[n]) T(ctl::forward(args)...); - ++n; + return data_ + size_; + } + + 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::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 + 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 ilist) + { + return insert(pos, ilist.begin(), ilist.end()); + } + + template + 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::construct( + alloc_, it, ctl::forward(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::destroy(alloc_, end() - i - 1); + size_ -= count; + return it; + } + + void push_back(const T& value) + { + if (size_ == capacity_) + grow(); + ctl::allocator_traits::construct( + alloc_, data_ + size_, value); + ++size_; + } + + void push_back(T&& value) + { + if (size_ == capacity_) + grow(); + ctl::allocator_traits::construct( + alloc_, data_ + size_, ctl::move(value)); + ++size_; + } + + template + reference emplace_back(Args&&... args) + { + if (size_ == capacity_) + grow(); + ctl::allocator_traits::construct( + alloc_, data_ + size_, ctl::forward(args)...); + return data_[size_++]; } void pop_back() { - if (n > 0) { - --n; - p[n].~T(); + if (!empty()) { + ctl::allocator_traits::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::destroy(alloc_, data_ + i); + } + size_ = count; } + + void swap(vector& other) noexcept( + ctl::allocator_traits::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::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::deallocate( + alloc_, new_data, new_capacity); + throw; + } + for (size_type i = 0; i < size_; ++i) + ctl::allocator_traits::destroy(alloc_, data_ + i); + ctl::allocator_traits::deallocate(alloc_, data_, capacity_); + data_ = new_data; + size_ = new_size; + capacity_ = new_capacity; + } + + Allocator alloc_; + pointer data_; + size_type size_; + size_type capacity_; }; +template +bool +operator==(const vector& lhs, const vector& rhs) +{ + return lhs.size() == rhs.size() && + ctl::equal(lhs.begin(), lhs.end(), rhs.begin()); +} + +template +bool +operator!=(const vector& lhs, const vector& rhs) +{ + return !(lhs == rhs); +} + +template +bool +operator<(const vector& lhs, const vector& rhs) +{ + return ctl::lexicographical_compare( + lhs.begin(), lhs.end(), rhs.begin(), rhs.end()); +} + +template +bool +operator<=(const vector& lhs, const vector& rhs) +{ + return !(rhs < lhs); +} + +template +bool +operator>(const vector& lhs, const vector& rhs) +{ + return rhs < lhs; +} + +template +bool +operator>=(const vector& lhs, const vector& rhs) +{ + return !(lhs < rhs); +} + +template +void +swap(vector& lhs, + vector& rhs) noexcept(noexcept(lhs.swap(rhs))) +{ + lhs.swap(rhs); +} + +template::value_type>> +vector(InputIt, InputIt, Alloc = Alloc()) + -> vector::value_type, Alloc>; + +template +vector(size_t, + const typename ctl::allocator_traits::value_type&, + Alloc = Alloc()) + -> vector::value_type, Alloc>; + } // namespace ctl -#endif // COSMOPOLITAN_CTL_OPTIONAL_H_ +#endif // CTL_VECTOR_H_ diff --git a/test/ctl/BUILD.mk b/test/ctl/BUILD.mk index 250e941d5..439d7e786 100644 --- a/test/ctl/BUILD.mk +++ b/test/ctl/BUILD.mk @@ -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) \ diff --git a/test/ctl/accumulate_test.cc b/test/ctl/accumulate_test.cc new file mode 100644 index 000000000..ff29e278e --- /dev/null +++ b/test/ctl/accumulate_test.cc @@ -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 +// #include +// #define ctl std + +int +main() +{ + ctl::array 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; +} diff --git a/test/ctl/advance_test.cc b/test/ctl/advance_test.cc new file mode 100644 index 000000000..90b381bd5 --- /dev/null +++ b/test/ctl/advance_test.cc @@ -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 +// #include +// #define ctl std + +int +main() +{ + ctl::array 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; +} diff --git a/test/ctl/all_of_test.cc b/test/ctl/all_of_test.cc new file mode 100644 index 000000000..5f38e441b --- /dev/null +++ b/test/ctl/all_of_test.cc @@ -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 +#include +#define ctl std + +int +main() +{ + ctl::array arr1 = { 2, 4, 6, 8, 10 }; + ctl::array 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; +} diff --git a/test/ctl/any_of_test.cc b/test/ctl/any_of_test.cc new file mode 100644 index 000000000..02ba6928d --- /dev/null +++ b/test/ctl/any_of_test.cc @@ -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 +// #include +// #define ctl std + +int +main() +{ + ctl::array arr1 = { 1, 3, 5, 7, 9 }; + ctl::array 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; +} diff --git a/test/ctl/array_test.cc b/test/ctl/array_test.cc new file mode 100644 index 000000000..5fd8dbe54 --- /dev/null +++ b/test/ctl/array_test.cc @@ -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 +// #define ctl std + +int +main() +{ + + // Test construction and basic properties + { + ctl::array 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 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 arr = { 1, 2, 3 }; + int* data = arr.data(); + if (data[0] != 1 || data[1] != 2 || data[2] != 3) + return 9; + } + + // Test iterators + { + ctl::array 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 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 arr; + arr.fill(42); + for (int i = 0; i < 5; ++i) { + if (arr[i] != 42) + return 14; + } + } + + // Test swap method + { + ctl::array arr1 = { 1, 2, 3 }; + ctl::array 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 arr1 = { 1, 2, 3 }; + ctl::array arr2 = { 1, 2, 3 }; + ctl::array 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 arr1 = { 1, 2, 3 }; + ctl::array 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 arr = { 1, 2, 3 }; + if (arr[0].value != 1 || arr[1].value != 2 || arr[2].value != 3) + return 25; + } + + // Test empty array + { + ctl::array 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 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 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 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 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 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 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 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; + } +} diff --git a/test/ctl/back_inserter_test.cc b/test/ctl/back_inserter_test.cc new file mode 100644 index 000000000..38659b10e --- /dev/null +++ b/test/ctl/back_inserter_test.cc @@ -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 +// #include +// #include +// #define ctl std + +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)); + + // 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 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; +} diff --git a/test/ctl/copy_test.cc b/test/ctl/copy_test.cc new file mode 100644 index 000000000..868bbee97 --- /dev/null +++ b/test/ctl/copy_test.cc @@ -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 +// #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; + } + + // 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; +} diff --git a/test/ctl/string_test.cc b/test/ctl/string_test.cc index 7e7cb3f32..a3fd1f461 100644 --- a/test/ctl/string_test.cc +++ b/test/ctl/string_test.cc @@ -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 @@ -366,7 +365,7 @@ main() { String s; - if constexpr (std::is_same_v) { + if constexpr (ctl::is_same_v) { // 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) { + if constexpr (ctl::is_same_v) { String r(s); if (issmall(s) || !issmall(r)) return 106; @@ -405,5 +404,4 @@ main() } CheckForMemoryLeaks(); - return 0; } diff --git a/test/ctl/unique_ptr_test.cc b/test/ctl/unique_ptr_test.cc index 4f83de945..87e4f30f2 100644 --- a/test/ctl/unique_ptr_test.cc +++ b/test/ctl/unique_ptr_test.cc @@ -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 +// #include // #define ctl std template> @@ -70,7 +71,7 @@ struct FinalDeleter final static_assert(sizeof(Ptr) == sizeof(int*)); // not everyone uses [[no_unique_address]]... -static_assert(!std::is_same_v, ctl::unique_ptr> || +static_assert(!ctl::is_same_v, ctl::unique_ptr> || sizeof(Ptr) == sizeof(int*)); struct SetsGCtor @@ -227,6 +228,4 @@ main() // TODO(mrdomino): Fix memory leaks reported by MODE=dbg // CheckForMemoryLeaks(); - - return 0; } diff --git a/test/ctl/vector_test.cc b/test/ctl/vector_test.cc index aa70cb21d..9e65333c3 100644 --- a/test/ctl/vector_test.cc +++ b/test/ctl/vector_test.cc @@ -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 - -#include "ctl/string.h" - // #include // #include // #define ctl std @@ -315,6 +312,45 @@ main() return 69; } + { + ctl::vector A = { 1, 2, 3 }; + if (A[1] != 2) + return 70; + A = { 4, 5, 6 }; + if (A[1] != 5) + return 71; + } + + { + ctl::vector 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 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; } diff --git a/test/libc/runtime/zipos_test.c b/test/libc/runtime/zipos_test.c index c77614a85..147920b45 100644 --- a/test/libc/runtime/zipos_test.c +++ b/test/libc/runtime/zipos_test.c @@ -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) { diff --git a/test/libc/stdio/lemur64_test.c b/test/libc/stdio/lemur64_test.c new file mode 100644 index 000000000..fb6af0b2e --- /dev/null +++ b/test/libc/stdio/lemur64_test.c @@ -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()); +} diff --git a/tool/emacs/cosmo-c-builtins.el b/tool/emacs/cosmo-c-builtins.el index ef7bfb4a4..bdb777018 100644 --- a/tool/emacs/cosmo-c-builtins.el +++ b/tool/emacs/cosmo-c-builtins.el @@ -46,6 +46,8 @@ (gcc-builtin-functions '("__builtin_strlen" + "__builtin_memcpy" + "__builtin_memmove" "__builtin_setjmp" "__builtin_longjmp" "__builtin_va_start" diff --git a/tool/emacs/cosmo-stuff.el b/tool/emacs/cosmo-stuff.el index 1ca81f45a..f7c712b2d 100644 --- a/tool/emacs/cosmo-stuff.el +++ b/tool/emacs/cosmo-stuff.el @@ -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))))))