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))))))