summaryrefslogtreecommitdiffhomepage
path: root/misc
diff options
context:
space:
mode:
Diffstat (limited to 'misc')
-rw-r--r--misc/benchmarks/external/ankerl/unordered_dense.h418
-rw-r--r--misc/benchmarks/external/emhash/hash_table7.hpp44
-rw-r--r--misc/benchmarks/plotbench/cdeq_benchmark.cpp15
-rw-r--r--misc/benchmarks/plotbench/clist_benchmark.cpp8
-rw-r--r--misc/benchmarks/plotbench/cmap_benchmark.cpp8
-rw-r--r--misc/benchmarks/plotbench/cpque_benchmark.cpp5
-rw-r--r--misc/benchmarks/plotbench/csmap_benchmark.cpp8
-rw-r--r--misc/benchmarks/plotbench/cvec_benchmark.cpp21
-rw-r--r--misc/benchmarks/plotbench/plot.py11
-rw-r--r--misc/benchmarks/plotbench/run_all.bat6
-rw-r--r--misc/benchmarks/plotbench/run_clang.sh12
-rw-r--r--misc/benchmarks/plotbench/run_gcc.sh12
-rw-r--r--misc/benchmarks/plotbench/run_vc.bat6
-rw-r--r--misc/benchmarks/shootout_hashmaps.cpp4
-rw-r--r--misc/benchmarks/various/csort_bench.c46
-rw-r--r--misc/benchmarks/various/cspan_bench.c97
-rw-r--r--misc/benchmarks/various/prng_bench.cpp33
-rw-r--r--misc/benchmarks/various/rust_cmap.c2
-rw-r--r--misc/benchmarks/various/sso_bench.cpp156
-rw-r--r--misc/benchmarks/various/string_bench_STC.cpp7
-rw-r--r--misc/benchmarks/various/string_bench_STD.cpp3
-rw-r--r--misc/examples/algorithms/forfilter.c (renamed from misc/examples/forfilter.c)17
-rw-r--r--misc/examples/algorithms/forloops.c (renamed from misc/examples/forloops.c)134
-rw-r--r--misc/examples/algorithms/random.c42
-rw-r--r--misc/examples/algorithms/shape.c (renamed from misc/examples/shape.c)16
-rw-r--r--misc/examples/algorithms/shape.cpp (renamed from misc/examples/shape.cpp)0
-rw-r--r--misc/examples/bitsets/bits.c (renamed from misc/examples/bits.c)12
-rw-r--r--misc/examples/bitsets/bits2.c (renamed from misc/examples/bits2.c)6
-rw-r--r--misc/examples/bitsets/prime.c (renamed from misc/examples/prime.c)32
-rw-r--r--misc/examples/coread.c39
-rw-r--r--misc/examples/coroutines.c106
-rw-r--r--misc/examples/coroutines/cointerleave.c62
-rw-r--r--misc/examples/coroutines/coread.c41
-rw-r--r--misc/examples/coroutines/coroutines.c112
-rw-r--r--misc/examples/coroutines/cotasks1.c100
-rw-r--r--misc/examples/coroutines/cotasks2.c98
-rw-r--r--misc/examples/coroutines/dining_philosophers.c105
-rw-r--r--misc/examples/coroutines/filetask.c80
-rw-r--r--misc/examples/coroutines/generator.c66
-rw-r--r--misc/examples/coroutines/scheduler.c67
-rw-r--r--misc/examples/coroutines/triples.c75
-rw-r--r--misc/examples/generator.c53
-rw-r--r--misc/examples/hashmaps/birthday.c (renamed from misc/examples/birthday.c)6
-rw-r--r--misc/examples/hashmaps/books.c (renamed from misc/examples/books.c)3
-rw-r--r--misc/examples/hashmaps/hashmap.c (renamed from misc/examples/hashmap.c)1
-rw-r--r--misc/examples/hashmaps/new_map.c (renamed from misc/examples/new_map.c)15
-rw-r--r--misc/examples/hashmaps/phonebook.c (renamed from misc/examples/phonebook.c)4
-rw-r--r--misc/examples/hashmaps/unordered_set.c (renamed from misc/examples/unordered_set.c)3
-rw-r--r--misc/examples/hashmaps/vikings.c (renamed from misc/examples/vikings.c)15
-rw-r--r--misc/examples/linkedlists/intrusive.c (renamed from misc/examples/intrusive.c)9
-rw-r--r--misc/examples/linkedlists/list.c (renamed from misc/examples/list.c)13
-rw-r--r--misc/examples/linkedlists/list_erase.c (renamed from misc/examples/list_erase.c)6
-rw-r--r--misc/examples/linkedlists/list_splice.c (renamed from misc/examples/list_splice.c)9
-rw-r--r--misc/examples/linkedlists/new_list.c70
-rwxr-xr-xmisc/examples/make.sh37
-rw-r--r--misc/examples/mixed/astar.c (renamed from misc/examples/astar.c)8
-rw-r--r--misc/examples/mixed/complex.c (renamed from misc/examples/complex.c)12
-rw-r--r--misc/examples/mixed/convert.c (renamed from misc/examples/convert.c)10
-rw-r--r--misc/examples/mixed/demos.c (renamed from misc/examples/demos.c)31
-rw-r--r--misc/examples/mixed/inits.c (renamed from misc/examples/inits.c)16
-rw-r--r--misc/examples/mixed/read.c (renamed from misc/examples/read.c)10
-rw-r--r--misc/examples/multidim.c68
-rw-r--r--misc/examples/new_list.c68
-rw-r--r--misc/examples/printspan.c57
-rw-r--r--misc/examples/priorityqueues/functor.c (renamed from misc/examples/functor.c)39
-rw-r--r--misc/examples/priorityqueues/new_pque.c (renamed from misc/examples/new_pque.c)8
-rw-r--r--misc/examples/priorityqueues/priority.c (renamed from misc/examples/priority.c)10
-rw-r--r--misc/examples/queues/new_queue.c (renamed from misc/examples/new_queue.c)14
-rw-r--r--misc/examples/queues/queue.c (renamed from misc/examples/queue.c)14
-rw-r--r--misc/examples/random.c45
-rw-r--r--misc/examples/rawptr_elements.c59
-rw-r--r--misc/examples/regularexpressions/regex1.c (renamed from misc/examples/regex1.c)2
-rw-r--r--misc/examples/regularexpressions/regex2.c (renamed from misc/examples/regex2.c)6
-rw-r--r--misc/examples/regularexpressions/regex_match.c (renamed from misc/examples/regex_match.c)13
-rw-r--r--misc/examples/regularexpressions/regex_replace.c (renamed from misc/examples/regex_replace.c)8
-rw-r--r--misc/examples/sidebyside.cpp57
-rw-r--r--misc/examples/smartpointers/arc_containers.c (renamed from misc/examples/arc_containers.c)16
-rw-r--r--misc/examples/smartpointers/arc_demo.c (renamed from misc/examples/arc_demo.c)23
-rw-r--r--misc/examples/smartpointers/arcvec_erase.c (renamed from misc/examples/arcvec_erase.c)16
-rw-r--r--misc/examples/smartpointers/box.c (renamed from misc/examples/box.c)10
-rw-r--r--misc/examples/smartpointers/box2.c (renamed from misc/examples/box2.c)15
-rw-r--r--misc/examples/smartpointers/map_box.c34
-rw-r--r--misc/examples/smartpointers/map_ptr.c34
-rw-r--r--misc/examples/smartpointers/music_arc.c (renamed from misc/examples/music_arc.c)31
-rw-r--r--misc/examples/smartpointers/new_sptr.c (renamed from misc/examples/new_sptr.c)19
-rw-r--r--misc/examples/smartpointers/person_arc.c (renamed from misc/examples/person_arc.c)13
-rw-r--r--misc/examples/sortedmaps/csmap_erase.c (renamed from misc/examples/csmap_erase.c)5
-rw-r--r--misc/examples/sortedmaps/csmap_find.c (renamed from misc/examples/csmap_find.c)20
-rw-r--r--misc/examples/sortedmaps/csmap_insert.c (renamed from misc/examples/csmap_insert.c)20
-rw-r--r--misc/examples/sortedmaps/csset_erase.c (renamed from misc/examples/csset_erase.c)6
-rw-r--r--misc/examples/sortedmaps/gauss2.c (renamed from misc/examples/gauss2.c)11
-rw-r--r--misc/examples/sortedmaps/listmap.c (renamed from misc/examples/mmap.c)5
-rw-r--r--misc/examples/sortedmaps/mapmap.c (renamed from misc/examples/mapmap.c)2
-rw-r--r--misc/examples/sortedmaps/multimap.c (renamed from misc/examples/multimap.c)6
-rw-r--r--misc/examples/sortedmaps/new_smap.c (renamed from misc/examples/new_smap.c)9
-rw-r--r--misc/examples/sortedmaps/sorted_map.c (renamed from misc/examples/sorted_map.c)4
-rw-r--r--misc/examples/spans/matmult.c90
-rw-r--r--misc/examples/spans/mdspan.c51
-rw-r--r--misc/examples/spans/multidim.c76
-rw-r--r--misc/examples/spans/printspan.c41
-rw-r--r--misc/examples/spans/submdspan.c44
-rw-r--r--misc/examples/strings/cstr_match.c (renamed from misc/examples/cstr_match.c)5
-rw-r--r--misc/examples/strings/replace.c (renamed from misc/examples/replace.c)3
-rw-r--r--misc/examples/strings/splitstr.c (renamed from misc/examples/splitstr.c)5
-rw-r--r--misc/examples/strings/sso_map.c (renamed from misc/examples/sso_map.c)3
-rw-r--r--misc/examples/strings/sso_substr.c (renamed from misc/examples/sso_substr.c)12
-rw-r--r--misc/examples/strings/sview_split.c (renamed from misc/examples/sview_split.c)4
-rw-r--r--misc/examples/strings/utf8replace_c.c (renamed from misc/examples/utf8replace_c.c)5
-rw-r--r--misc/examples/strings/utf8replace_rs.rs (renamed from misc/examples/utf8replace_rs.rs)0
-rw-r--r--misc/examples/triples.c69
-rw-r--r--misc/examples/vectors/lower_bound.c (renamed from misc/examples/lower_bound.c)11
-rw-r--r--misc/examples/vectors/new_vec.c (renamed from misc/examples/new_vec.c)23
-rw-r--r--misc/examples/vectors/stack.c (renamed from misc/examples/stack.c)6
-rw-r--r--misc/tests/cregex_test.c25
-rw-r--r--misc/tests/cspan_test.c38
-rw-r--r--misc/tests/ctest.h3
116 files changed, 2402 insertions, 1342 deletions
diff --git a/misc/benchmarks/external/ankerl/unordered_dense.h b/misc/benchmarks/external/ankerl/unordered_dense.h
index faad051d..b8cacea7 100644
--- a/misc/benchmarks/external/ankerl/unordered_dense.h
+++ b/misc/benchmarks/external/ankerl/unordered_dense.h
@@ -1,7 +1,7 @@
///////////////////////// ankerl::unordered_dense::{map, set} /////////////////////////
// A fast & densely stored hashmap and hashset based on robin-hood backward shift deletion.
-// Version 3.1.0
+// Version 4.0.1
// https://github.com/martinus/unordered_dense
//
// Licensed under the MIT License <http://opensource.org/licenses/MIT>.
@@ -30,12 +30,15 @@
#define ANKERL_UNORDERED_DENSE_H
// see https://semver.org/spec/v2.0.0.html
-#define ANKERL_UNORDERED_DENSE_VERSION_MAJOR 3 // NOLINT(cppcoreguidelines-macro-usage) incompatible API changes
-#define ANKERL_UNORDERED_DENSE_VERSION_MINOR 1 // NOLINT(cppcoreguidelines-macro-usage) backwards compatible functionality
-#define ANKERL_UNORDERED_DENSE_VERSION_PATCH 0 // NOLINT(cppcoreguidelines-macro-usage) backwards compatible bug fixes
+#define ANKERL_UNORDERED_DENSE_VERSION_MAJOR 4 // NOLINT(cppcoreguidelines-macro-usage) incompatible API changes
+#define ANKERL_UNORDERED_DENSE_VERSION_MINOR 0 // NOLINT(cppcoreguidelines-macro-usage) backwards compatible functionality
+#define ANKERL_UNORDERED_DENSE_VERSION_PATCH 1 // NOLINT(cppcoreguidelines-macro-usage) backwards compatible bug fixes
// API versioning with inline namespace, see https://www.foonathan.net/2018/11/inline-namespaces/
+
+// NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
#define ANKERL_UNORDERED_DENSE_VERSION_CONCAT1(major, minor, patch) v##major##_##minor##_##patch
+// NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
#define ANKERL_UNORDERED_DENSE_VERSION_CONCAT(major, minor, patch) ANKERL_UNORDERED_DENSE_VERSION_CONCAT1(major, minor, patch)
#define ANKERL_UNORDERED_DENSE_NAMESPACE \
ANKERL_UNORDERED_DENSE_VERSION_CONCAT( \
@@ -57,9 +60,9 @@
// exceptions
#if defined(__cpp_exceptions) || defined(__EXCEPTIONS) || defined(_CPPUNWIND)
-# define ANKERL_UNORDERED_DENSE_HAS_EXCEPTIONS() 1
+# define ANKERL_UNORDERED_DENSE_HAS_EXCEPTIONS() 1 // NOLINT(cppcoreguidelines-macro-usage)
#else
-# define ANKERL_UNORDERED_DENSE_HAS_EXCEPTIONS() 0
+# define ANKERL_UNORDERED_DENSE_HAS_EXCEPTIONS() 0 // NOLINT(cppcoreguidelines-macro-usage)
#endif
#ifdef _MSC_VER
# define ANKERL_UNORDERED_DENSE_NOINLINE __declspec(noinline)
@@ -89,20 +92,13 @@
# include <cstdlib> // for abort
# endif
-# define ANKERL_UNORDERED_DENSE_PMR 0 // NOLINT(cppcoreguidelines-macro-usage)
# if defined(__has_include)
# if __has_include(<memory_resource>)
-# undef ANKERL_UNORDERED_DENSE_PMR
-# define ANKERL_UNORDERED_DENSE_PMR 1 // NOLINT(cppcoreguidelines-macro-usage)
-# define ANKERL_UNORDERED_DENSE_PMR_ALLOCATOR \
- std::pmr::polymorphic_allocator // NOLINT(cppcoreguidelines-macro-usage)
-# include <memory_resource> // for polymorphic_allocator
+# define ANKERL_UNORDERED_DENSE_PMR std::pmr // NOLINT(cppcoreguidelines-macro-usage)
+# include <memory_resource> // for polymorphic_allocator
# elif __has_include(<experimental/memory_resource>)
-# undef ANKERL_UNORDERED_DENSE_PMR
-# define ANKERL_UNORDERED_DENSE_PMR 1 // NOLINT(cppcoreguidelines-macro-usage)
-# define ANKERL_UNORDERED_DENSE_PMR_ALLOCATOR \
- std::experimental::pmr::polymorphic_allocator // NOLINT(cppcoreguidelines-macro-usage)
-# include <experimental/memory_resource> // for polymorphic_allocator
+# define ANKERL_UNORDERED_DENSE_PMR std::experimental::pmr // NOLINT(cppcoreguidelines-macro-usage)
+# include <experimental/memory_resource> // for polymorphic_allocator
# endif
# endif
@@ -428,7 +424,7 @@ constexpr bool is_map_v = !std::is_void_v<Mapped>;
// clang-format off
template <typename Hash, typename KeyEqual>
-constexpr bool is_transparent_v = is_detected_v<detect_is_transparent, Hash>&& is_detected_v<detect_is_transparent, KeyEqual>;
+constexpr bool is_transparent_v = is_detected_v<detect_is_transparent, Hash> && is_detected_v<detect_is_transparent, KeyEqual>;
// clang-format on
template <typename From, typename To1, typename To2>
@@ -446,19 +442,320 @@ struct base_table_type_map {
// base type for set doesn't have mapped_type
struct base_table_type_set {};
+} // namespace detail
+
+// Very much like std::deque, but faster for indexing (in most cases). As of now this doesn't implement the full std::vector
+// API, but merely what's necessary to work as an underlying container for ankerl::unordered_dense::{map, set}.
+// It allocates blocks of equal size and puts them into the m_blocks vector. That means it can grow simply by adding a new
+// block to the back of m_blocks, and doesn't double its size like an std::vector. The disadvantage is that memory is not
+// linear and thus there is one more indirection necessary for indexing.
+template <typename T, typename Allocator = std::allocator<T>, size_t MaxSegmentSizeBytes = 4096>
+class segmented_vector {
+ template <bool IsConst>
+ class iter_t;
+
+public:
+ using allocator_type = Allocator;
+ using pointer = typename std::allocator_traits<allocator_type>::pointer;
+ using const_pointer = typename std::allocator_traits<allocator_type>::const_pointer;
+ using difference_type = typename std::allocator_traits<allocator_type>::difference_type;
+ using value_type = T;
+ using size_type = std::size_t;
+ using reference = T&;
+ using const_reference = T const&;
+ using iterator = iter_t<false>;
+ using const_iterator = iter_t<true>;
+
+private:
+ using vec_alloc = typename std::allocator_traits<Allocator>::template rebind_alloc<pointer>;
+ std::vector<pointer, vec_alloc> m_blocks{};
+ size_t m_size{};
+
+ // Calculates the maximum number for x in (s << x) <= max_val
+ static constexpr auto num_bits_closest(size_t max_val, size_t s) -> size_t {
+ auto f = size_t{0};
+ while (s << (f + 1) <= max_val) {
+ ++f;
+ }
+ return f;
+ }
+
+ using self_t = segmented_vector<T, Allocator, MaxSegmentSizeBytes>;
+ static constexpr auto num_bits = num_bits_closest(MaxSegmentSizeBytes, sizeof(T));
+ static constexpr auto num_elements_in_block = 1U << num_bits;
+ static constexpr auto mask = num_elements_in_block - 1U;
+
+ /**
+ * Iterator class doubles as const_iterator and iterator
+ */
+ template <bool IsConst>
+ class iter_t {
+ using ptr_t = typename std::conditional_t<IsConst, segmented_vector::const_pointer const*, segmented_vector::pointer*>;
+ ptr_t m_data{};
+ size_t m_idx{};
+
+ template <bool B>
+ friend class iter_t;
+
+ public:
+ using difference_type = segmented_vector::difference_type;
+ using value_type = T;
+ using reference = typename std::conditional_t<IsConst, value_type const&, value_type&>;
+ using pointer = typename std::conditional_t<IsConst, segmented_vector::const_pointer, segmented_vector::pointer>;
+ using iterator_category = std::forward_iterator_tag;
+
+ iter_t() noexcept = default;
+
+ template <bool OtherIsConst, typename = typename std::enable_if<IsConst && !OtherIsConst>::type>
+ // NOLINTNEXTLINE(google-explicit-constructor,hicpp-explicit-conversions)
+ constexpr iter_t(iter_t<OtherIsConst> const& other) noexcept
+ : m_data(other.m_data)
+ , m_idx(other.m_idx) {}
+
+ constexpr iter_t(ptr_t data, size_t idx) noexcept
+ : m_data(data)
+ , m_idx(idx) {}
+
+ template <bool OtherIsConst, typename = typename std::enable_if<IsConst && !OtherIsConst>::type>
+ constexpr auto operator=(iter_t<OtherIsConst> const& other) noexcept -> iter_t& {
+ m_data = other.m_data;
+ m_idx = other.m_idx;
+ return *this;
+ }
+
+ constexpr auto operator++() noexcept -> iter_t& {
+ ++m_idx;
+ return *this;
+ }
+
+ constexpr auto operator+(difference_type diff) noexcept -> iter_t {
+ return {m_data, static_cast<size_t>(static_cast<difference_type>(m_idx) + diff)};
+ }
+
+ template <bool OtherIsConst>
+ constexpr auto operator-(iter_t<OtherIsConst> const& other) noexcept -> difference_type {
+ return static_cast<difference_type>(m_idx) - static_cast<difference_type>(other.m_idx);
+ }
+
+ constexpr auto operator*() const noexcept -> reference {
+ return m_data[m_idx >> num_bits][m_idx & mask];
+ }
+
+ constexpr auto operator->() const noexcept -> pointer {
+ return &m_data[m_idx >> num_bits][m_idx & mask];
+ }
+
+ template <bool O>
+ constexpr auto operator==(iter_t<O> const& o) const noexcept -> bool {
+ return m_idx == o.m_idx;
+ }
+
+ template <bool O>
+ constexpr auto operator!=(iter_t<O> const& o) const noexcept -> bool {
+ return !(*this == o);
+ }
+ };
+
+ // slow path: need to allocate a new segment every once in a while
+ void increase_capacity() {
+ auto ba = Allocator(m_blocks.get_allocator());
+ pointer block = std::allocator_traits<Allocator>::allocate(ba, num_elements_in_block);
+ m_blocks.push_back(block);
+ }
+
+ // Moves everything from other
+ void append_everything_from(segmented_vector&& other) {
+ reserve(size() + other.size());
+ for (auto&& o : other) {
+ emplace_back(std::move(o));
+ }
+ }
+
+ // Copies everything from other
+ void append_everything_from(segmented_vector const& other) {
+ reserve(size() + other.size());
+ for (auto const& o : other) {
+ emplace_back(o);
+ }
+ }
+
+ void dealloc() {
+ auto ba = Allocator(m_blocks.get_allocator());
+ for (auto ptr : m_blocks) {
+ std::allocator_traits<Allocator>::deallocate(ba, ptr, num_elements_in_block);
+ }
+ }
+
+ [[nodiscard]] static constexpr auto calc_num_blocks_for_capacity(size_t capacity) {
+ return (capacity + num_elements_in_block - 1U) / num_elements_in_block;
+ }
+
+public:
+ segmented_vector() = default;
+
+ // NOLINTNEXTLINE(google-explicit-constructor,hicpp-explicit-conversions)
+ segmented_vector(Allocator alloc)
+ : m_blocks(vec_alloc(alloc)) {}
+
+ segmented_vector(segmented_vector&& other, Allocator alloc)
+ : m_blocks(vec_alloc(alloc)) {
+ if (other.get_allocator() == alloc) {
+ *this = std::move(other);
+ } else {
+ // Oh my, allocator is different so we need to copy everything.
+ append_everything_from(std::move(other));
+ }
+ }
+
+ segmented_vector(segmented_vector&& other) noexcept
+ : m_blocks(std::move(other.m_blocks))
+ , m_size(std::exchange(other.m_size, {})) {}
+
+ segmented_vector(segmented_vector const& other, Allocator alloc)
+ : m_blocks(vec_alloc(alloc)) {
+ append_everything_from(other);
+ }
+
+ segmented_vector(segmented_vector const& other) {
+ append_everything_from(other);
+ }
+
+ auto operator=(segmented_vector const& other) -> segmented_vector& {
+ if (this == &other) {
+ return *this;
+ }
+ clear();
+ append_everything_from(other);
+ return *this;
+ }
+
+ auto operator=(segmented_vector&& other) noexcept -> segmented_vector& {
+ clear();
+ dealloc();
+ m_blocks = std::move(other.m_blocks);
+ m_size = std::exchange(other.m_size, {});
+ return *this;
+ }
+
+ ~segmented_vector() {
+ clear();
+ dealloc();
+ }
+
+ [[nodiscard]] constexpr auto size() const -> size_t {
+ return m_size;
+ }
+
+ [[nodiscard]] constexpr auto capacity() const -> size_t {
+ return m_blocks.size() * num_elements_in_block;
+ }
+
+ // Indexing is highly performance critical
+ [[nodiscard]] constexpr auto operator[](size_t i) const noexcept -> T const& {
+ return m_blocks[i >> num_bits][i & mask];
+ }
+
+ [[nodiscard]] constexpr auto operator[](size_t i) noexcept -> T& {
+ return m_blocks[i >> num_bits][i & mask];
+ }
+
+ [[nodiscard]] constexpr auto begin() -> iterator {
+ return {m_blocks.data(), 0U};
+ }
+ [[nodiscard]] constexpr auto begin() const -> const_iterator {
+ return {m_blocks.data(), 0U};
+ }
+ [[nodiscard]] constexpr auto cbegin() const -> const_iterator {
+ return {m_blocks.data(), 0U};
+ }
+
+ [[nodiscard]] constexpr auto end() -> iterator {
+ return {m_blocks.data(), m_size};
+ }
+ [[nodiscard]] constexpr auto end() const -> const_iterator {
+ return {m_blocks.data(), m_size};
+ }
+ [[nodiscard]] constexpr auto cend() const -> const_iterator {
+ return {m_blocks.data(), m_size};
+ }
+
+ [[nodiscard]] constexpr auto back() -> reference {
+ return operator[](m_size - 1);
+ }
+ [[nodiscard]] constexpr auto back() const -> const_reference {
+ return operator[](m_size - 1);
+ }
+
+ void pop_back() {
+ back().~T();
+ --m_size;
+ }
+
+ [[nodiscard]] auto empty() const {
+ return 0 == m_size;
+ }
+
+ void reserve(size_t new_capacity) {
+ m_blocks.reserve(calc_num_blocks_for_capacity(new_capacity));
+ while (new_capacity > capacity()) {
+ increase_capacity();
+ }
+ }
+
+ [[nodiscard]] auto get_allocator() const -> allocator_type {
+ return allocator_type{m_blocks.get_allocator()};
+ }
+
+ template <class... Args>
+ auto emplace_back(Args&&... args) -> reference {
+ if (m_size == capacity()) {
+ increase_capacity();
+ }
+ auto* ptr = static_cast<void*>(&operator[](m_size));
+ auto& ref = *new (ptr) T(std::forward<Args>(args)...);
+ ++m_size;
+ return ref;
+ }
+
+ void clear() {
+ if constexpr (!std::is_trivially_destructible_v<T>) {
+ for (size_t i = 0, s = size(); i < s; ++i) {
+ operator[](i).~T();
+ }
+ }
+ m_size = 0;
+ }
+
+ void shrink_to_fit() {
+ auto ba = Allocator(m_blocks.get_allocator());
+ auto num_blocks_required = calc_num_blocks_for_capacity(m_size);
+ while (m_blocks.size() > num_blocks_required) {
+ std::allocator_traits<Allocator>::deallocate(ba, m_blocks.back(), num_elements_in_block);
+ m_blocks.pop_back();
+ }
+ m_blocks.shrink_to_fit();
+ }
+};
+
+namespace detail {
+
// This is it, the table. Doubles as map and set, and uses `void` for T when its used as a set.
template <class Key,
class T, // when void, treat it as a set.
class Hash,
class KeyEqual,
class AllocatorOrContainer,
- class Bucket>
+ class Bucket,
+ bool IsSegmented>
class table : public std::conditional_t<is_map_v<T>, base_table_type_map<T>, base_table_type_set> {
+ using underlying_value_type = typename std::conditional_t<is_map_v<T>, std::pair<Key, T>, Key>;
+ using underlying_container_type = std::conditional_t<IsSegmented,
+ segmented_vector<underlying_value_type, AllocatorOrContainer>,
+ std::vector<underlying_value_type, AllocatorOrContainer>>;
+
public:
- using value_container_type = std::conditional_t<
- is_detected_v<detect_iterator, AllocatorOrContainer>,
- AllocatorOrContainer,
- typename std::vector<typename std::conditional_t<is_map_v<T>, std::pair<Key, T>, Key>, AllocatorOrContainer>>;
+ using value_container_type = std::
+ conditional_t<is_detected_v<detect_iterator, AllocatorOrContainer>, AllocatorOrContainer, underlying_container_type>;
private:
using bucket_alloc =
@@ -492,7 +789,8 @@ private:
static_assert(std::is_trivially_copyable_v<Bucket>, "assert we can just memset / memcpy");
value_container_type m_values{}; // Contains all the key-value pairs in one densely stored container. No holes.
- typename std::allocator_traits<bucket_alloc>::pointer m_buckets{};
+ using bucket_pointer = typename std::allocator_traits<bucket_alloc>::pointer;
+ bucket_pointer m_buckets{};
size_t m_num_buckets = 0;
size_t m_max_bucket_capacity = 0;
float m_max_load_factor = default_max_load_factor;
@@ -507,8 +805,7 @@ private:
}
// Helper to access bucket through pointer types
- [[nodiscard]] static constexpr auto at(typename std::allocator_traits<bucket_alloc>::pointer bucket_ptr, size_t offset)
- -> Bucket& {
+ [[nodiscard]] static constexpr auto at(bucket_pointer bucket_ptr, size_t offset) -> Bucket& {
return *(bucket_ptr + static_cast<typename std::allocator_traits<bucket_alloc>::difference_type>(offset));
}
@@ -578,7 +875,7 @@ private:
}
[[nodiscard]] static constexpr auto calc_num_buckets(uint8_t shifts) -> size_t {
- return std::min(max_bucket_count(), size_t{1} << (64U - shifts));
+ return (std::min)(max_bucket_count(), size_t{1} << (64U - shifts));
}
[[nodiscard]] constexpr auto calc_shifts_for_size(size_t s) const -> uint8_t {
@@ -983,7 +1280,7 @@ public:
}
[[nodiscard]] static constexpr auto max_size() noexcept -> size_t {
- if constexpr (std::numeric_limits<value_idx_type>::max() == std::numeric_limits<size_t>::max()) {
+ if constexpr ((std::numeric_limits<value_idx_type>::max)() == (std::numeric_limits<size_t>::max)()) {
return size_t{1} << (sizeof(value_idx_type) * 8 - 1);
} else {
return size_t{1} << (sizeof(value_idx_type) * 8);
@@ -1272,7 +1569,7 @@ public:
auto const last_to_end = std::distance(last, cend());
// remove elements from left to right which moves elements from the end back
- auto const mid = idx_first + std::min(first_to_last, last_to_end);
+ auto const mid = idx_first + (std::min)(first_to_last, last_to_end);
auto idx = idx_first;
while (idx != mid) {
erase(begin() + idx);
@@ -1439,8 +1736,8 @@ public:
}
void rehash(size_t count) {
- count = std::min(count, max_size());
- auto shifts = calc_shifts_for_size(std::max(count, size()));
+ count = (std::min)(count, max_size());
+ auto shifts = calc_shifts_for_size((std::max)(count, size()));
if (shifts != m_shifts) {
m_shifts = shifts;
deallocate_buckets();
@@ -1451,12 +1748,12 @@ public:
}
void reserve(size_t capa) {
- capa = std::min(capa, max_size());
+ capa = (std::min)(capa, max_size());
if constexpr (has_reserve<value_container_type>) {
// std::deque doesn't have reserve(). Make sure we only call when available
m_values.reserve(capa);
}
- auto shifts = calc_shifts_for_size(std::max(capa, size()));
+ auto shifts = calc_shifts_for_size((std::max)(capa, size()));
if (0 == m_num_buckets || shifts < m_shifts) {
m_shifts = shifts;
deallocate_buckets();
@@ -1519,16 +1816,31 @@ template <class Key,
class KeyEqual = std::equal_to<Key>,
class AllocatorOrContainer = std::allocator<std::pair<Key, T>>,
class Bucket = bucket_type::standard>
-using map = detail::table<Key, T, Hash, KeyEqual, AllocatorOrContainer, Bucket>;
+using map = detail::table<Key, T, Hash, KeyEqual, AllocatorOrContainer, Bucket, false>;
+
+template <class Key,
+ class T,
+ class Hash = hash<Key>,
+ class KeyEqual = std::equal_to<Key>,
+ class AllocatorOrContainer = std::allocator<std::pair<Key, T>>,
+ class Bucket = bucket_type::standard>
+using segmented_map = detail::table<Key, T, Hash, KeyEqual, AllocatorOrContainer, Bucket, true>;
+
+template <class Key,
+ class Hash = hash<Key>,
+ class KeyEqual = std::equal_to<Key>,
+ class AllocatorOrContainer = std::allocator<Key>,
+ class Bucket = bucket_type::standard>
+using set = detail::table<Key, void, Hash, KeyEqual, AllocatorOrContainer, Bucket, false>;
template <class Key,
class Hash = hash<Key>,
class KeyEqual = std::equal_to<Key>,
class AllocatorOrContainer = std::allocator<Key>,
class Bucket = bucket_type::standard>
-using set = detail::table<Key, void, Hash, KeyEqual, AllocatorOrContainer, Bucket>;
+using segmented_set = detail::table<Key, void, Hash, KeyEqual, AllocatorOrContainer, Bucket, true>;
-# if ANKERL_UNORDERED_DENSE_PMR
+# if defined(ANKERL_UNORDERED_DENSE_PMR)
namespace pmr {
@@ -1537,10 +1849,23 @@ template <class Key,
class Hash = hash<Key>,
class KeyEqual = std::equal_to<Key>,
class Bucket = bucket_type::standard>
-using map = detail::table<Key, T, Hash, KeyEqual, ANKERL_UNORDERED_DENSE_PMR_ALLOCATOR<std::pair<Key, T>>, Bucket>;
+using map =
+ detail::table<Key, T, Hash, KeyEqual, ANKERL_UNORDERED_DENSE_PMR::polymorphic_allocator<std::pair<Key, T>>, Bucket, false>;
+
+template <class Key,
+ class T,
+ class Hash = hash<Key>,
+ class KeyEqual = std::equal_to<Key>,
+ class Bucket = bucket_type::standard>
+using segmented_map =
+ detail::table<Key, T, Hash, KeyEqual, ANKERL_UNORDERED_DENSE_PMR::polymorphic_allocator<std::pair<Key, T>>, Bucket, true>;
+
+template <class Key, class Hash = hash<Key>, class KeyEqual = std::equal_to<Key>, class Bucket = bucket_type::standard>
+using set = detail::table<Key, void, Hash, KeyEqual, ANKERL_UNORDERED_DENSE_PMR::polymorphic_allocator<Key>, Bucket, false>;
template <class Key, class Hash = hash<Key>, class KeyEqual = std::equal_to<Key>, class Bucket = bucket_type::standard>
-using set = detail::table<Key, void, Hash, KeyEqual, ANKERL_UNORDERED_DENSE_PMR_ALLOCATOR<Key>, Bucket>;
+using segmented_set =
+ detail::table<Key, void, Hash, KeyEqual, ANKERL_UNORDERED_DENSE_PMR::polymorphic_allocator<Key>, Bucket, true>;
} // namespace pmr
@@ -1558,11 +1883,18 @@ using set = detail::table<Key, void, Hash, KeyEqual, ANKERL_UNORDERED_DENSE_PMR_
namespace std { // NOLINT(cert-dcl58-cpp)
-template <class Key, class T, class Hash, class KeyEqual, class AllocatorOrContainer, class Bucket, class Pred>
+template <class Key,
+ class T,
+ class Hash,
+ class KeyEqual,
+ class AllocatorOrContainer,
+ class Bucket,
+ class Pred,
+ bool IsSegmented>
// NOLINTNEXTLINE(cert-dcl58-cpp)
-auto erase_if(ankerl::unordered_dense::detail::table<Key, T, Hash, KeyEqual, AllocatorOrContainer, Bucket>& map, Pred pred)
- -> size_t {
- using map_t = ankerl::unordered_dense::detail::table<Key, T, Hash, KeyEqual, AllocatorOrContainer, Bucket>;
+auto erase_if(ankerl::unordered_dense::detail::table<Key, T, Hash, KeyEqual, AllocatorOrContainer, Bucket, IsSegmented>& map,
+ Pred pred) -> size_t {
+ using map_t = ankerl::unordered_dense::detail::table<Key, T, Hash, KeyEqual, AllocatorOrContainer, Bucket, IsSegmented>;
// going back to front because erase() invalidates the end iterator
auto const old_size = map.size();
@@ -1575,7 +1907,7 @@ auto erase_if(ankerl::unordered_dense::detail::table<Key, T, Hash, KeyEqual, All
}
}
- return map.size() - old_size;
+ return old_size - map.size();
}
} // namespace std
diff --git a/misc/benchmarks/external/emhash/hash_table7.hpp b/misc/benchmarks/external/emhash/hash_table7.hpp
index 8f8982f9..41970d8c 100644
--- a/misc/benchmarks/external/emhash/hash_table7.hpp
+++ b/misc/benchmarks/external/emhash/hash_table7.hpp
@@ -92,7 +92,7 @@ of resizing granularity. Ignoring variance, the expected occurrences of list siz
#include "wyhash.h"
#endif
-#ifdef EMH_KEY
+#ifdef EMH_NEW
#undef EMH_KEY
#undef EMH_VAL
#undef EMH_PKV
@@ -547,10 +547,10 @@ public:
static PairT* alloc_bucket(size_type num_buckets)
{
-#if _WIN32
- auto* new_pairs = (PairT*)malloc(AllocSize(num_buckets));
-#else
+#ifdef EMH_ALLOC
auto* new_pairs = (PairT*)aligned_alloc(EMH_MALIGN, AllocSize(num_buckets));
+#else
+ auto* new_pairs = (PairT*)malloc(AllocSize(num_buckets));
#endif
return new_pairs;
}
@@ -1668,16 +1668,10 @@ private:
// key is not in this map. Find a place to put it.
size_type find_empty_bucket(const size_type bucket_from, const size_type main_bucket)
{
-#ifdef EMH_ALIGN64 // only works 64bit
- const auto boset = bucket_from % MASK_BIT;
- auto* const align = _bitmask + bucket_from / MASK_BIT;
- const auto bmask = ((size_t)align[1] << (MASK_BIT - boset)) | (align[0] >> boset);
- if (EMH_LIKELY(bmask != 0))
- return bucket_from + CTZ(bmask);
-#elif EMH_ITER_SAFE
+#if EMH_ITER_SAFE
const auto boset = bucket_from % 8;
- auto* const start = (uint8_t*)_bitmask + bucket_from / 8;
- size_t bmask; memcpy(&bmask, start + 0, sizeof(bmask)); bmask >>= boset;// bmask |= ((size_t)start[8] << (SIZE_BIT - boset));
+ auto* const align = (uint8_t*)_bitmask + bucket_from / 8;(void)main_bucket;
+ size_t bmask; memcpy(&bmask, align + 0, sizeof(bmask)); bmask >>= boset;// bmask |= ((size_t)align[8] << (SIZE_BIT - boset));
if (EMH_LIKELY(bmask != 0))
return bucket_from + CTZ(bmask);
#else
@@ -1715,21 +1709,15 @@ private:
}
// key is not in this map. Find a place to put it.
- size_type find_unique_empty(const size_type bucket_from, const size_t main_bucket)
- {
-#ifdef EMH_ALIGN64
- const auto boset = bucket_from % MASK_BIT;
- auto* const align = _bitmask + bucket_from / MASK_BIT;
- const auto bmask = ((size_t)align[1] << (MASK_BIT - boset)) | (align[0] >> boset);
- static_assert(sizeof(size_t) > 4);
-#elif EMH_ITER_SAFE
+ size_type find_unique_empty(const size_type bucket_from)
+ {
const auto boset = bucket_from % 8;
- auto* const start = (uint8_t*)_bitmask + bucket_from / 8;
- size_t bmask; memcpy(&bmask, start + 0, sizeof(bmask)); bmask >>= boset;
-#else
- const auto boset = bucket_from % 8; (void)main_bucket;
auto* const align = (uint8_t*)_bitmask + bucket_from / 8;
- const auto bmask = (*(size_t*)(align) >> boset); //maybe not aligned and warning
+
+#if EMH_ITER_SAFE
+ size_t bmask; memcpy(&bmask, align + 0, sizeof(bmask)); bmask >>= boset;
+#else
+ const auto bmask = (*(size_t*)(align) >> boset); //maybe not aligned and warning
#endif
if (EMH_LIKELY(bmask != 0))
return bucket_from + CTZ(bmask);
@@ -1789,12 +1777,12 @@ private:
next_bucket = find_last_bucket(next_bucket);
//find a new empty and link it to tail
- return EMH_BUCKET(_pairs, next_bucket) = find_unique_empty(next_bucket, bucket);
+ return EMH_BUCKET(_pairs, next_bucket) = find_empty_bucket(next_bucket, bucket);
}
#if EMH_INT_HASH
static constexpr uint64_t KC = UINT64_C(11400714819323198485);
- inline uint64_t hash64(uint64_t key)
+ inline static uint64_t hash64(uint64_t key)
{
#if __SIZEOF_INT128__ && EMH_INT_HASH == 1
__uint128_t r = key; r *= KC;
diff --git a/misc/benchmarks/plotbench/cdeq_benchmark.cpp b/misc/benchmarks/plotbench/cdeq_benchmark.cpp
index bb0e28c8..d11b4103 100644
--- a/misc/benchmarks/plotbench/cdeq_benchmark.cpp
+++ b/misc/benchmarks/plotbench/cdeq_benchmark.cpp
@@ -9,10 +9,10 @@
#endif
enum {INSERT, ERASE, FIND, ITER, DESTRUCT, N_TESTS};
-const char* operations[] = {"insert", "erase", "find", "iter", "destruct"};
+const char* operations[] = {"insert", "erase", "access", "iter", "destruct"};
typedef struct { time_t t1, t2; uint64_t sum; float fac; } Range;
typedef struct { const char* name; Range test[N_TESTS]; } Sample;
-enum {SAMPLES = 2, N = 50000000, S = 0x3ffc, R = 4};
+enum {SAMPLES = 2, N = 60000000, R = 4};
uint64_t seed = 1, mask1 = 0xfffffff, mask2 = 0xffff;
static float secs(Range s) { return (float)(s.t2 - s.t1) / CLOCKS_PER_SEC; }
@@ -44,14 +44,12 @@ Sample test_std_deque() {
c_forrange (N) con.push_back(crand() & mask2);
s.test[FIND].t1 = clock();
size_t sum = 0;
- // Iteration - not inherent find - skipping
- //container::iterator it;
- //c_forrange (S) if ((it = std::find(con.begin(), con.end(), crand() & mask2)) != con.end()) sum += *it;
+ c_forrange (R) c_forrange (i, N) sum += con[i];
s.test[FIND].t2 = clock();
s.test[FIND].sum = sum;
s.test[ITER].t1 = clock();
sum = 0;
- c_forrange (R) c_forrange (i, N) sum += con[i];
+ c_forrange (R) for (const auto i: con) sum += i;
s.test[ITER].t2 = clock();
s.test[ITER].sum = sum;
s.test[DESTRUCT].t1 = clock();
@@ -89,13 +87,12 @@ Sample test_stc_deque() {
c_forrange (N) cdeq_x_push_back(&con, crand() & mask2);
s.test[FIND].t1 = clock();
size_t sum = 0;
- //cdeq_x_iter it, end = cdeq_x_end(&con);
- //c_forrange (S) if ((it = cdeq_x_find(&con, crand() & mask2)).ref != end.ref) sum += *it.ref;
+ c_forrange (R) c_forrange (i, N) sum += *cdeq_x_at(&con, i);
s.test[FIND].t2 = clock();
s.test[FIND].sum = sum;
s.test[ITER].t1 = clock();
sum = 0;
- c_forrange (R) c_forrange (i, N) sum += con.data[i];
+ c_forrange (R) c_foreach (i, cdeq_x, con) sum += *i.ref;
s.test[ITER].t2 = clock();
s.test[ITER].sum = sum;
s.test[DESTRUCT].t1 = clock();
diff --git a/misc/benchmarks/plotbench/clist_benchmark.cpp b/misc/benchmarks/plotbench/clist_benchmark.cpp
index 01bfbf83..8fdfddba 100644
--- a/misc/benchmarks/plotbench/clist_benchmark.cpp
+++ b/misc/benchmarks/plotbench/clist_benchmark.cpp
@@ -9,10 +9,10 @@
#endif
enum {INSERT, ERASE, FIND, ITER, DESTRUCT, N_TESTS};
-const char* operations[] = {"insert", "erase", "find", "iter", "destruct"};
+const char* operations[] = {"insert", "erase", "access", "iter", "destruct"};
typedef struct { time_t t1, t2; uint64_t sum; float fac; } Range;
typedef struct { const char* name; Range test[N_TESTS]; } Sample;
-enum {SAMPLES = 2, N = 10000000, S = 0x3ffc, R = 4};
+enum {SAMPLES = 2, N = 10000000, R = 4};
uint64_t seed = 1, mask1 = 0xfffffff, mask2 = 0xffff;
static float secs(Range s) { return (float)(s.t2 - s.t1) / CLOCKS_PER_SEC; }
@@ -45,7 +45,6 @@ Sample test_std_forward_list() {
size_t sum = 0;
container::iterator it;
// Iteration - not inherent find - skipping
- //c_forrange (S) if ((it = std::find(con.begin(), con.end(), crand() & mask2)) != con.end()) sum += *it;
s.test[FIND].t2 = clock();
s.test[FIND].sum = sum;
s.test[ITER].t1 = clock();
@@ -86,8 +85,7 @@ Sample test_stc_forward_list() {
c_forrange (N) clist_x_push_front(&con, crand() & mask2);
s.test[FIND].t1 = clock();
size_t sum = 0;
- //clist_x_iter it, end = clist_x_end(&con);
- //c_forrange (S) if ((it = clist_x_find(&con, crand() & mask2)).ref != end.ref) sum += *it.ref;
+ //clist iteration - skipping
s.test[FIND].t2 = clock();
s.test[FIND].sum = sum;
s.test[ITER].t1 = clock();
diff --git a/misc/benchmarks/plotbench/cmap_benchmark.cpp b/misc/benchmarks/plotbench/cmap_benchmark.cpp
index 6b2edbd7..c7957bb7 100644
--- a/misc/benchmarks/plotbench/cmap_benchmark.cpp
+++ b/misc/benchmarks/plotbench/cmap_benchmark.cpp
@@ -8,7 +8,7 @@
#endif
enum {INSERT, ERASE, FIND, ITER, DESTRUCT, N_TESTS};
-const char* operations[] = {"insert", "erase", "find", "iter", "destruct"};
+const char* operations[] = {"insert", "erase", "access", "iter", "destruct"};
typedef struct { time_t t1, t2; uint64_t sum; float fac; } Range;
typedef struct { const char* name; Range test[N_TESTS]; } Sample;
enum {SAMPLES = 2, N = 2000000, R = 4};
@@ -47,12 +47,14 @@ Sample test_std_unordered_map() {
s.test[FIND].t1 = clock();
size_t sum = 0;
container::iterator it;
- c_forrange (N) if ((it = con.find(crand() & mask1)) != con.end()) sum += it->second;
+ c_forrange (N)
+ if ((it = con.find(crand() & mask1)) != con.end())
+ sum += it->second;
s.test[FIND].t2 = clock();
s.test[FIND].sum = sum;
s.test[ITER].t1 = clock();
sum = 0;
- c_forrange (R) for (auto i: con) sum += i.second;
+ c_forrange (R) for (const auto& i: con) sum += i.second;
s.test[ITER].t2 = clock();
s.test[ITER].sum = sum;
s.test[DESTRUCT].t1 = clock();
diff --git a/misc/benchmarks/plotbench/cpque_benchmark.cpp b/misc/benchmarks/plotbench/cpque_benchmark.cpp
index 2d4c7a28..aafc9eb0 100644
--- a/misc/benchmarks/plotbench/cpque_benchmark.cpp
+++ b/misc/benchmarks/plotbench/cpque_benchmark.cpp
@@ -37,7 +37,8 @@ void stc_test()
{
int N = 10000000;
- c_auto (cpque_f, pq)
+ cpque_f pq = {0};
+ c_defer(cpque_f_drop(&pq))
{
csrand(seed);
clock_t start = clock();
@@ -58,7 +59,7 @@ void stc_test()
}
-int main()
+int main(void)
{
puts("STD P.QUEUE:");
std_test();
diff --git a/misc/benchmarks/plotbench/csmap_benchmark.cpp b/misc/benchmarks/plotbench/csmap_benchmark.cpp
index 60f2db49..480163ed 100644
--- a/misc/benchmarks/plotbench/csmap_benchmark.cpp
+++ b/misc/benchmarks/plotbench/csmap_benchmark.cpp
@@ -8,7 +8,7 @@
#endif
enum {INSERT, ERASE, FIND, ITER, DESTRUCT, N_TESTS};
-const char* operations[] = {"insert", "erase", "find", "iter", "destruct"};
+const char* operations[] = {"insert", "erase", "access", "iter", "destruct"};
typedef struct { time_t t1, t2; uint64_t sum; float fac; } Range;
typedef struct { const char* name; Range test[N_TESTS]; } Sample;
enum {SAMPLES = 2, N = 1000000, R = 4};
@@ -47,12 +47,14 @@ Sample test_std_map() {
s.test[FIND].t1 = clock();
size_t sum = 0;
container::iterator it;
- c_forrange (N) if ((it = con.find(crand() & mask1)) != con.end()) sum += it->second;
+ c_forrange (N)
+ if ((it = con.find(crand() & mask1)) != con.end())
+ sum += it->second;
s.test[FIND].t2 = clock();
s.test[FIND].sum = sum;
s.test[ITER].t1 = clock();
sum = 0;
- c_forrange (R) for (auto i: con) sum += i.second;
+ c_forrange (R) for (const auto& i: con) sum += i.second;
s.test[ITER].t2 = clock();
s.test[ITER].sum = sum;
s.test[DESTRUCT].t1 = clock();
diff --git a/misc/benchmarks/plotbench/cvec_benchmark.cpp b/misc/benchmarks/plotbench/cvec_benchmark.cpp
index c488a01c..fb10653a 100644
--- a/misc/benchmarks/plotbench/cvec_benchmark.cpp
+++ b/misc/benchmarks/plotbench/cvec_benchmark.cpp
@@ -9,10 +9,10 @@
#endif
enum {INSERT, ERASE, FIND, ITER, DESTRUCT, N_TESTS};
-const char* operations[] = {"insert", "erase", "find", "iter", "destruct"};
+const char* operations[] = {"insert", "erase", "access", "iter", "destruct"};
typedef struct { time_t t1, t2; uint64_t sum; float fac; } Range;
typedef struct { const char* name; Range test[N_TESTS]; } Sample;
-enum {SAMPLES = 2, N = 80000000, S = 0x3ffc, R = 4};
+enum {SAMPLES = 2, N = 60000000, R = 4};
uint64_t seed = 1, mask1 = 0xfffffff, mask2 = 0xffff;
static float secs(Range s) { return (float)(s.t2 - s.t1) / CLOCKS_PER_SEC; }
@@ -42,14 +42,12 @@ Sample test_std_vector() {
c_forrange (N) con.push_back(crand() & mask2);
s.test[FIND].t1 = clock();
size_t sum = 0;
- //container::iterator it;
- // Iteration - not inherent find - skipping
- //c_forrange (S) if ((it = std::find(con.begin(), con.end(), crand() & mask2)) != con.end()) sum += *it;
+ c_forrange (R) c_forrange (i, N) sum += con[i];
s.test[FIND].t2 = clock();
s.test[FIND].sum = sum;
s.test[ITER].t1 = clock();
sum = 0;
- c_forrange (R) c_forrange (i, N) sum += con[i];
+ c_forrange (R) for (const auto i: con) sum += i;
s.test[ITER].t2 = clock();
s.test[ITER].sum = sum;
s.test[DESTRUCT].t1 = clock();
@@ -71,27 +69,26 @@ Sample test_stc_vector() {
s.test[INSERT].t1 = clock();
container con = cvec_x_init();
csrand(seed);
- c_forrange (N) cvec_x_push_back(&con, crand() & mask1);
+ c_forrange (N) cvec_x_push(&con, crand() & mask1);
s.test[INSERT].t2 = clock();
s.test[INSERT].sum = cvec_x_size(&con);
s.test[ERASE].t1 = clock();
- c_forrange (N) { cvec_x_pop_back(&con); }
+ c_forrange (N) { cvec_x_pop(&con); }
s.test[ERASE].t2 = clock();
s.test[ERASE].sum = cvec_x_size(&con);
cvec_x_drop(&con);
}{
csrand(seed);
container con = cvec_x_init();
- c_forrange (N) cvec_x_push_back(&con, crand() & mask2);
+ c_forrange (N) cvec_x_push(&con, crand() & mask2);
s.test[FIND].t1 = clock();
size_t sum = 0;
- //cvec_x_iter it, end = cvec_x_end(&con);
- //c_forrange (S) if ((it = cvec_x_find(&con, crand() & mask2)).ref != end.ref) sum += *it.ref;
+ c_forrange (R) c_forrange (i, N) sum += con.data[i];
s.test[FIND].t2 = clock();
s.test[FIND].sum = sum;
s.test[ITER].t1 = clock();
sum = 0;
- c_forrange (R) c_forrange (i, N) sum += con.data[i];
+ c_forrange (R) c_foreach (i, cvec_x, con) sum += *i.ref;
s.test[ITER].t2 = clock();
s.test[ITER].sum = sum;
s.test[DESTRUCT].t1 = clock();
diff --git a/misc/benchmarks/plotbench/plot.py b/misc/benchmarks/plotbench/plot.py
index 0ba92264..4a02c6b2 100644
--- a/misc/benchmarks/plotbench/plot.py
+++ b/misc/benchmarks/plotbench/plot.py
@@ -4,7 +4,7 @@ import pandas as pd
import matplotlib.pyplot as plt
#sns.set_theme(style="whitegrid")
-comp = ['All compilers', 'Mingw-g++-11.3.0', 'Win-Clang-14.0.1', 'VC-19.28']
+comp = ['All compilers', 'Mingw-g++-13.1.0', 'Win-Clang-16.0.5', 'VC-19.36']
n = int(sys.argv[1]) if len(sys.argv) > 1 else 0
file = sys.argv[2] if len(sys.argv) > 2 else 'plot_win.csv'
df = pd.read_csv(file)
@@ -12,13 +12,12 @@ df = df[df.Method != 'total']
if n > 0:
df = df[df.Compiler == comp[n]]
-g = sns.catplot(data=df, x='Method', y='Seconds', hue='Library', col='C', kind='bar',
- ci=68, legend=False, col_wrap=2, sharex=False, aspect=1.4, height=3.1)
+g = sns.catplot(data=df, x='Method', y='Seconds', hue='Library', col='C', kind='bar', orient='v',
+ errorbar=('ci', 68), legend=False, col_wrap=2, sharex=False, aspect=1.4, height=3.0)
g.set_xlabels('')
-g.add_legend(bbox_to_anchor=(0.75, 0.2), borderaxespad=0.)
-
-g.fig.subplots_adjust(top=0.90, left=0.06, bottom=0.07)
+g.add_legend(bbox_to_anchor=(0.75, 0.2), borderaxespad=0)
+g.fig.subplots_adjust(top=0.90, left=0.08, right=0.98, bottom=0.04, hspace=0.4)
g.fig.suptitle('Benchmark STC vs c++ std containers: %s' % comp[n], fontsize=15, y=0.98)
plt.show()
diff --git a/misc/benchmarks/plotbench/run_all.bat b/misc/benchmarks/plotbench/run_all.bat
index 98913a50..de380531 100644
--- a/misc/benchmarks/plotbench/run_all.bat
+++ b/misc/benchmarks/plotbench/run_all.bat
@@ -1,7 +1,5 @@
-set out=plot_win.csv
+@set out=plot_win.csv
echo Compiler,Library,C,Method,Seconds,Ratio> %out%
-echo gcc
sh run_gcc.sh >> %out%
-echo clang
sh run_clang.sh >> %out%
-REM call run_vc.bat >> %out%
+call run_vc.bat >> %out%
diff --git a/misc/benchmarks/plotbench/run_clang.sh b/misc/benchmarks/plotbench/run_clang.sh
index 096e71be..4f649cbc 100644
--- a/misc/benchmarks/plotbench/run_clang.sh
+++ b/misc/benchmarks/plotbench/run_clang.sh
@@ -1,12 +1,12 @@
exe=''
if [ "$OS" = "Windows_NT" ] ; then exe=".exe" ; fi
-clang++ -I../include -O3 -o cdeq_benchmark$exe cdeq_benchmark.cpp
-clang++ -I../include -O3 -o clist_benchmark$exe clist_benchmark.cpp
-clang++ -I../include -O3 -o cmap_benchmark$exe cmap_benchmark.cpp
-clang++ -I../include -O3 -o csmap_benchmark$exe csmap_benchmark.cpp
-clang++ -I../include -O3 -o cvec_benchmark$exe cvec_benchmark.cpp
+clang -DNDEBUG -I../../include -O3 -o cdeq_benchmark$exe cdeq_benchmark.cpp -lstdc++
+clang -DNDEBUG -I../../include -O3 -o clist_benchmark$exe clist_benchmark.cpp -lstdc++
+clang -DNDEBUG -I../../include -O3 -o cmap_benchmark$exe cmap_benchmark.cpp -lstdc++
+clang -DNDEBUG -I../../include -O3 -o csmap_benchmark$exe csmap_benchmark.cpp -lstdc++
+clang -DNDEBUG -I../../include -O3 -o cvec_benchmark$exe cvec_benchmark.cpp -lstdc++
-c='Win-Clang-14.0.1'
+c='Win-Clang-16.0.5'
./cdeq_benchmark$exe $c
./clist_benchmark$exe $c
./cmap_benchmark$exe $c
diff --git a/misc/benchmarks/plotbench/run_gcc.sh b/misc/benchmarks/plotbench/run_gcc.sh
index 5249ed1e..0bd2d6ee 100644
--- a/misc/benchmarks/plotbench/run_gcc.sh
+++ b/misc/benchmarks/plotbench/run_gcc.sh
@@ -1,10 +1,10 @@
-g++ -I../include -O3 -o cdeq_benchmark cdeq_benchmark.cpp
-g++ -I../include -O3 -o clist_benchmark clist_benchmark.cpp
-g++ -I../include -O3 -o cmap_benchmark cmap_benchmark.cpp
-g++ -I../include -O3 -o csmap_benchmark csmap_benchmark.cpp
-g++ -I../include -O3 -o cvec_benchmark cvec_benchmark.cpp
+g++ -DNDEBUG -I../../include -O3 -o cdeq_benchmark cdeq_benchmark.cpp
+g++ -DNDEBUG -I../../include -O3 -o clist_benchmark clist_benchmark.cpp
+g++ -DNDEBUG -I../../include -O3 -o cmap_benchmark cmap_benchmark.cpp
+g++ -DNDEBUG -I../../include -O3 -o csmap_benchmark csmap_benchmark.cpp
+g++ -DNDEBUG -I../../include -O3 -o cvec_benchmark cvec_benchmark.cpp
-c='Mingw-g++-11.3.0'
+c='Mingw-g++-13.1.0'
./cdeq_benchmark $c
./clist_benchmark $c
./cmap_benchmark $c
diff --git a/misc/benchmarks/plotbench/run_vc.bat b/misc/benchmarks/plotbench/run_vc.bat
index dc4938f8..c00d059b 100644
--- a/misc/benchmarks/plotbench/run_vc.bat
+++ b/misc/benchmarks/plotbench/run_vc.bat
@@ -1,14 +1,14 @@
@echo off
-if "%VSINSTALLDIR%"=="" call "C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Auxiliary\Build\vcvars64.bat" >nul
+if "%VSINSTALLDIR%"=="" call "C:\Program Files (x86)\Microsoft Visual Studio\2022\Community\VC\Auxiliary\Build\vcvars64.bat" >nul
cl.exe -nologo -EHsc -std:c++latest -I../include -O2 cdeq_benchmark.cpp >nul
cl.exe -nologo -EHsc -std:c++latest -I../include -O2 clist_benchmark.cpp >nul
cl.exe -nologo -EHsc -std:c++latest -I../include -O2 cmap_benchmark.cpp >nul
cl.exe -nologo -EHsc -std:c++latest -I../include -O2 csmap_benchmark.cpp >nul
cl.exe -nologo -EHsc -std:c++latest -I../include -O2 cvec_benchmark.cpp >nul
-del *.obj >nul
+if exist *obj del *.obj
-set c=VC-19.28
+set c=VC-19.36
cdeq_benchmark.exe %c%
clist_benchmark.exe %c%
cmap_benchmark.exe %c%
diff --git a/misc/benchmarks/shootout_hashmaps.cpp b/misc/benchmarks/shootout_hashmaps.cpp
index bae9a42b..c6a81777 100644
--- a/misc/benchmarks/shootout_hashmaps.cpp
+++ b/misc/benchmarks/shootout_hashmaps.cpp
@@ -2,7 +2,7 @@
#include <time.h>
#include <stc/crand.h>
-#define MAX_LOAD_FACTOR 85
+#define MAX_LOAD_FACTOR 80
#ifdef __cplusplus
#include <limits>
@@ -35,8 +35,8 @@ KHASH_MAP_INIT_INT64(ii, IValue)
// cmap template expansion
#define i_key IKey
#define i_val IValue
-#define i_ssize int32_t // enable 2^K buckets like the rest.
#define i_tag ii
+//#define i_expandby 1
#define i_max_load_factor MAX_LOAD_FACTOR / 100.0f
#include <stc/cmap.h>
diff --git a/misc/benchmarks/various/csort_bench.c b/misc/benchmarks/various/csort_bench.c
index d5d7fa7c..793a0503 100644
--- a/misc/benchmarks/various/csort_bench.c
+++ b/misc/benchmarks/various/csort_bench.c
@@ -5,8 +5,12 @@
#ifdef __cplusplus
#include <algorithm>
#endif
-#define i_val int
-#include <stc/algo/csort.h>
+#define NDEBUG
+#define i_type Ints
+#define i_key int
+#define i_more
+#include <stc/cvec.h>
+#include <stc/algo/sort.h>
#define ROTL(d,bits) ((d<<(bits)) | (d>>(8*sizeof(d)-(bits))))
uint64_t romutrio(uint64_t s[3]) {
@@ -21,14 +25,14 @@ static int cmp_int(const void* a, const void* b) {
return c_default_cmp((const int*)a, (const int*)b);
}
-void testsort(int *a, int size, const char *desc) {
+void testsort(Ints *a, int size, const char *desc) {
clock_t t = clock();
#ifdef __cplusplus
- printf("std::sort: "); std::sort(a, a + size);
+ printf("std::sort: "); std::sort(a->data, a->data + size);
#elif defined QSORT
- printf("qsort: "); qsort(a, size, sizeof *a, cmp_int);
+ printf("qsort: "); qsort(a->data, size, sizeof *a->data, cmp_int);
#else
- printf("stc_sort: "); csort_int(a, size);
+ printf("STC sort_n: "); Ints_sort_n(a, size);
#endif
t = clock() - t;
@@ -41,27 +45,27 @@ int main(int argc, char *argv[]) {
size_t i, size = argc > 1 ? strtoull(argv[1], NULL, 0) : 10000000;
uint64_t s[3] = {123456789, 3456789123, 789123456};
- int32_t *a = (int32_t*)malloc(sizeof(*a) * size);
- if (!a) return -1;
+ Ints a = Ints_with_capacity(size);
for (i = 0; i < size; i++)
- a[i] = romutrio(s) & (1U << 30) - 1;
- testsort(a, size, "random");
+ Ints_push(&a, romutrio(s) & (1U << 30) - 1);
+ testsort(&a, size, "random");
for (i = 0; i < 20; i++)
- printf(" %d", (int)a[i]);
+ printf(" %d", (int)*Ints_at(&a, i));
puts("");
for (i = 0; i < size; i++)
- a[i] = i;
- testsort(a, size, "sorted");
+ *Ints_at_mut(&a, i) = i;
+ testsort(&a, size, "sorted");
for (i = 0; i < size; i++)
- a[i] = size - i;
- testsort(a, size, "reverse sorted");
+ *Ints_at_mut(&a, i) = size - i;
+ testsort(&a, size, "reverse sorted");
for (i = 0; i < size; i++)
- a[i] = 126735;
- testsort(a, size, "constant");
+ *Ints_at_mut(&a, i) = 126735;
+ testsort(&a, size, "constant");
for (i = 0; i < size; i++)
- a[i] = i + 1;
- a[size - 1] = 0;
- testsort(a, size, "rotated");
- free(a);
+ *Ints_at_mut(&a, i) = i + 1;
+ *Ints_at_mut(&a, size - 1) = 0;
+ testsort(&a, size, "rotated");
+
+ Ints_drop(&a);
}
diff --git a/misc/benchmarks/various/cspan_bench.c b/misc/benchmarks/various/cspan_bench.c
index 589df13a..bfc0ead3 100644
--- a/misc/benchmarks/various/cspan_bench.c
+++ b/misc/benchmarks/various/cspan_bench.c
@@ -1,4 +1,5 @@
-#define STC_NDEBUG
+// ref: https://stackoverflow.com/questions/74382366/why-is-iterating-over-stdrangesviewsjoin-so-slow
+#define NDEBUG
#include <stc/cspan.h>
#include <stdio.h>
#include <time.h>
@@ -11,9 +12,9 @@ enum {
ny = 64,
nz = 64
};
+// subspan 15x5x10:
int lx = 15, ly = 10, lz = 5;
-int hx = 20, hy = 15, hz = 15;
-intptr_t n = 1000000;
+int hx = 30, hy = 15, hz = 15;
// define the contents of two nx x ny x nz arrays in and out
double Vout[nx * ny * nz];
@@ -21,36 +22,15 @@ double Vin[nx * ny * nz]; //, 1.23;
// define some slice indices for each dimension
-static void MDRanges_setup(intptr_t state)
-{
- double sum = 0;
- clock_t t = clock();
-
- for (intptr_t s = 0; s < state; ++s)
- {
- MD3 r_in = cspan_md(Vin, nx, ny, nz);
- MD3 r_out = cspan_md(Vout, nx, ny, nz);
-
- r_in = cspan_slice(MD3, &r_in, {lx, hx}, {ly, hy}, {lz, hz});
- r_out = cspan_slice(MD3, &r_out, {lx, hx}, {ly, hy}, {lz, hz});
- MD3_iter i = MD3_begin(&r_in); // can be iterated "flat".
- MD3_iter o = MD3_begin(&r_out);
- sum += Vin[s % nx];
- }
- t = clock() - t;
- printf("setup: %.1f ms, %f\n", 1000.0f * t / CLOCKS_PER_SEC, sum);
-}
-
-static void TraditionalForLoop(intptr_t state)
+static void Traditional_for_loop(intptr_t n)
{
clock_t t = clock();
double sum = 0;
- for (int s = 0; s < state; ++s) {
+ for (int s = 0; s < n; ++s) {
for (int x = lx; x < hx; ++x) {
for (int y = ly; y < hy; ++y) {
- for (int z = lz; z < hz; ++z)
- {
+ for (int z = lz; z < hz; ++z) {
double d = Vin[nz*(ny*x + y) + z];
Vout[nz*(ny*x + y) + z] += d;
sum += d;
@@ -59,68 +39,65 @@ static void TraditionalForLoop(intptr_t state)
}
}
t = clock() - t;
- printf("forloop: %.1f ms, %f\n", 1000.0f * t / CLOCKS_PER_SEC, sum);
+ printf("forloop : %.1f ms, %f\n", 1000.0f*t / CLOCKS_PER_SEC, sum);
}
-static void MDRanges_nested_loop(intptr_t state)
+static void MDRanges_loop_over_joined(intptr_t n)
{
+ clock_t t = clock();
MD3 r_in = cspan_md(Vin, nx, ny, nz);
MD3 r_out = cspan_md(Vout, nx, ny, nz);
r_in = cspan_slice(MD3, &r_in, {lx, hx}, {ly, hy}, {lz, hz});
r_out = cspan_slice(MD3, &r_out, {lx, hx}, {ly, hy}, {lz, hz});
-
- // C++23: for (auto [o, i] : std::views::zip(flat(r_out), flat(r_in))) { o = i; }
- clock_t t = clock();
double sum = 0;
- for (intptr_t s = 0; s < state; ++s) {
- for (int x = 0; x < r_in.shape[0]; ++x) {
- for (int y = 0; y < r_in.shape[1]; ++y) {
- for (int z = 0; z < r_in.shape[2]; ++z)
- {
- double d = *cspan_at(&r_in, x, y, z);
- *cspan_at(&r_out, x, y, z) += d;
- sum += d;
- }
- }
+ for (intptr_t s = 0; s < n; ++s) {
+ MD3_iter i = MD3_begin(&r_in);
+ MD3_iter o = MD3_begin(&r_out);
+
+ for (; i.ref; MD3_next(&i), MD3_next(&o))
+ {
+ *o.ref += *i.ref;
+ sum += *i.ref;
}
}
t = clock() - t;
- printf("nested: %.1f ms, %f\n", 1000.0f * t / CLOCKS_PER_SEC, sum);
+ printf("joined : %.1f ms, %f\n", 1000.0f*t / CLOCKS_PER_SEC, sum);
}
-static void MDRanges_loop_over_joined(intptr_t state)
+static void MDRanges_nested_loop(intptr_t n)
{
+ clock_t t = clock();
MD3 r_in = cspan_md(Vin, nx, ny, nz);
MD3 r_out = cspan_md(Vout, nx, ny, nz);
r_in = cspan_slice(MD3, &r_in, {lx, hx}, {ly, hy}, {lz, hz});
r_out = cspan_slice(MD3, &r_out, {lx, hx}, {ly, hy}, {lz, hz});
-
- // C++23: for (auto [o, i] : std::views::zip(flat(r_out), flat(r_in))) { o = i; }
double sum = 0;
- clock_t t = clock();
-
- for (intptr_t s = 0; s < state; ++s) {
- MD3_iter i = MD3_begin(&r_in);
- MD3_iter o = MD3_begin(&r_out);
- for (; i.ref; MD3_next(&i), MD3_next(&o))
- {
- *o.ref += *i.ref;
- sum += *i.ref;
+ for (intptr_t s = 0; s < n; ++s) {
+ for (int x = 0; x < r_in.shape[0]; ++x) {
+ for (int y = 0; y < r_in.shape[1]; ++y) {
+ for (int z = 0; z < r_in.shape[2]; ++z)
+ {
+ double d = *cspan_at(&r_in, x,y,z);
+ *cspan_at(&r_out, x,y,z) += d;
+ sum += d;
+ }
+ }
}
}
t = clock() - t;
- printf("joined: %.1f ms, %f\n", 1000.0f * t / CLOCKS_PER_SEC, sum);
+ printf("nested : %.1f ms, %f\n", 1000.0f*t / CLOCKS_PER_SEC, sum);
}
-int main()
+
+int main(void)
{
+ intptr_t n = 100000;
for (int i = 0; i < nx * ny * nz; ++i)
Vin[i] = i + 1.23;
- MDRanges_setup(n);
- TraditionalForLoop(n);
- MDRanges_nested_loop(n);
+ Traditional_for_loop(n);
MDRanges_loop_over_joined(n);
+ MDRanges_nested_loop(n);
}
diff --git a/misc/benchmarks/various/prng_bench.cpp b/misc/benchmarks/various/prng_bench.cpp
index 234e3805..45c14d18 100644
--- a/misc/benchmarks/various/prng_bench.cpp
+++ b/misc/benchmarks/various/prng_bench.cpp
@@ -66,7 +66,7 @@ uint32_t pcg32(uint32_t s[2]) {
}
-/* xoshiro128+ */
+/* xo(ro)shiro */
uint64_t xoroshiro128plus(uint64_t s[2]) {
const uint64_t s0 = s[0];
@@ -80,9 +80,6 @@ uint64_t xoroshiro128plus(uint64_t s[2]) {
return result;
}
-
-/* xoshiro256** */
-
static inline uint64_t xoshiro256starstar(uint64_t s[4]) {
const uint64_t result = rotl64(s[1] * 5, 7) * 9;
const uint64_t t = s[1] << 17;
@@ -95,7 +92,7 @@ static inline uint64_t xoshiro256starstar(uint64_t s[4]) {
return result;
}
-// wyrand - 2020-12-07
+/* wyrand - 2020-12-07 */
static inline void _wymum(uint64_t *A, uint64_t *B){
#if defined(__SIZEOF_INT128__)
__uint128_t r = *A; r *= *B;
@@ -136,44 +133,44 @@ int main(void)
for (size_t ti = 0; ti < 2; ti++) {
init_state(rng.state, 12345123);
cout << endl << "ROUND " << ti+1 << " ---------" << endl;
-
+/*
beg = clock();
for (size_t i = 0; i < N; i++)
- recipient[i] = romu_trio(rng.state);
+ recipient[i] = sfc32((uint32_t *)rng.state);
end = clock();
- cout << "romu_trio:\t"
+ cout << "sfc32:\t\t"
<< (float(end - beg) / CLOCKS_PER_SEC)
<< "s: " << recipient[312] << endl;
beg = clock();
for (size_t i = 0; i < N; i++)
- recipient[i] = wyrand64(rng.state);
+ recipient[i] = stc32((uint32_t *)rng.state);
end = clock();
- cout << "wyrand64:\t"
+ cout << "stc32:\t\t"
<< (float(end - beg) / CLOCKS_PER_SEC)
<< "s: " << recipient[312] << endl;
beg = clock();
for (size_t i = 0; i < N; i++)
- recipient[i] = sfc32((uint32_t *)rng.state);
+ recipient[i] = pcg32((uint32_t *)rng.state);
end = clock();
- cout << "sfc32:\t\t"
+ cout << "pcg32:\t\t"
<< (float(end - beg) / CLOCKS_PER_SEC)
<< "s: " << recipient[312] << endl;
-
+*/
beg = clock();
for (size_t i = 0; i < N; i++)
- recipient[i] = stc32((uint32_t *)rng.state);
+ recipient[i] = romu_trio(rng.state);
end = clock();
- cout << "stc32:\t\t"
+ cout << "romu_trio:\t"
<< (float(end - beg) / CLOCKS_PER_SEC)
<< "s: " << recipient[312] << endl;
beg = clock();
for (size_t i = 0; i < N; i++)
- recipient[i] = pcg32((uint32_t *)rng.state);
+ recipient[i] = wyrand64(rng.state);
end = clock();
- cout << "pcg32:\t\t"
+ cout << "wyrand64:\t"
<< (float(end - beg) / CLOCKS_PER_SEC)
<< "s: " << recipient[312] << endl;
@@ -189,7 +186,7 @@ int main(void)
for (size_t i = 0; i < N; i++)
recipient[i] = crand_u64(&rng);
end = clock();
- cout << "stc64:\t\t"
+ cout << "crand64:\t"
<< (float(end - beg) / CLOCKS_PER_SEC)
<< "s: " << recipient[312] << endl;
diff --git a/misc/benchmarks/various/rust_cmap.c b/misc/benchmarks/various/rust_cmap.c
index abdb42b0..97047e0b 100644
--- a/misc/benchmarks/various/rust_cmap.c
+++ b/misc/benchmarks/various/rust_cmap.c
@@ -22,7 +22,7 @@ uint64_t romu_trio(uint64_t s[3]) {
return xp;
}
-int main()
+int main(void)
{
cmap_u64 m = {0};
diff --git a/misc/benchmarks/various/sso_bench.cpp b/misc/benchmarks/various/sso_bench.cpp
index 993ff1bb..244c1291 100644
--- a/misc/benchmarks/various/sso_bench.cpp
+++ b/misc/benchmarks/various/sso_bench.cpp
@@ -3,65 +3,82 @@
#include <chrono>
#include <stc/crand.h>
+#define i_static
#include <stc/cstr.h>
#define i_type StcVec
#define i_val_str
#include <stc/cstack.h>
-#define i_type StcSet
-#define i_val_str
-#include <stc/csset.h>
-
#include <vector>
using StdVec = std::vector<std::string>;
-#include <set>
-using StdSet = std::set<std::string>;
-static const int BENCHMARK_SIZE = 2000000;
-static const int MAX_STRING_SIZE = 50;
+#include <unordered_set>
+#include "../external/ankerl/robin_hood.h"
+
+struct string_hash {
+ using is_transparent = void;
+ [[nodiscard]] size_t operator()(const char *txt) const {
+ return std::hash<std::string_view>{}(txt);
+ }
+ [[nodiscard]] size_t operator()(std::string_view txt) const {
+ return std::hash<std::string_view>{}(txt);
+ }
+ [[nodiscard]] size_t operator()(const std::string &txt) const {
+ return std::hash<std::string>{}(txt);
+ }
+};
+using StdSet = robin_hood::unordered_flat_set<std::string, string_hash, std::equal_to<>>;
+//using StdSet = std::unordered_set<std::string>;
+
+#define i_type StcSet
+#define i_val_str
+//#define i_hash(txtp) std::hash<std::string_view>{}(*txtp)
+#include <stc/cset.h>
+
+
+static const int BENCHMARK_SIZE = 250000;
+static const int MAX_STRING_SIZE = 100;
static const char CHARS[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz=+-";
using time_point = std::chrono::high_resolution_clock::time_point;
-static inline std::string randomString_STD(int strsize) {
- std::string s(strsize, 0);
- char* p = &s[0];
+static inline const char* randomString(int strsize) {
+ static char str[256];
union { uint64_t u8; uint8_t b[8]; } r;
for (int i = 0; i < strsize; ++i) {
if ((i & 7) == 0) r.u8 = crand() & 0x3f3f3f3f3f3f3f3f;
- p[i] = CHARS[r.b[i & 7]];
+ str[i] = CHARS[r.b[i & 7]];
}
- return s;
+ str[strsize] = 0;
+ return str;
}
-static inline cstr randomString_STC(int strsize) {
- cstr s = cstr_with_size(strsize, 0);
- char* p = cstr_data(&s);
- union { uint64_t u8; uint8_t b[8]; } r;
- for (int i = 0; i < strsize; ++i) {
- if ((i & 7) == 0) r.u8 = crand() & 0x3f3f3f3f3f3f3f3f;
- p[i] = CHARS[r.b[i & 7]];
- }
- return s;
+
+
+static inline void addRandomString(StdVec& vec, const char* str) {
+ vec.push_back(str);
}
+static inline void addRandomString(StcVec& vec, const char* str) {
+ StcVec_emplace(&vec, str);
+}
-void addRandomString(StdVec& vec, int strsize) {
- vec.push_back(std::move(randomString_STD(strsize)));
+static inline void addRandomString(StdSet& set, const char* str) {
+ set.insert(str);
}
-void addRandomString(StcVec& vec, int strsize) {
- StcVec_push(&vec, randomString_STC(strsize));
+static inline void addRandomString(StcSet& set, const char* str) {
+ StcSet_emplace(&set, str);
}
-void addRandomString(StdSet& set, int strsize) {
- set.insert(std::move(randomString_STD(strsize)));
+static inline bool getRandomString(const StdSet& set, const char* str) {
+ return set.find(str) != set.end();
}
-void addRandomString(StcSet& set, int strsize) {
- StcSet_insert(&set, randomString_STC(strsize));
+static inline bool getRandomString(const StcSet& set, const char* str) {
+ return StcSet_contains(&set, str);
}
@@ -70,7 +87,7 @@ int benchmark(C& container, const int n, const int strsize) {
time_point t1 = std::chrono::high_resolution_clock::now();
for (int i = 0; i < n; i++)
- addRandomString(container, strsize);
+ addRandomString(container, randomString(strsize));
time_point t2 = std::chrono::high_resolution_clock::now();
const auto duration = std::chrono::duration_cast<std::chrono::milliseconds>(t2 - t1).count();
@@ -78,9 +95,25 @@ int benchmark(C& container, const int n, const int strsize) {
return (int)duration;
}
+template <class C>
+int benchmark_lookup(C& container, const int n, const int strsize) {
+ for (int i = 0; i < n; i++)
+ addRandomString(container, randomString(strsize));
+
+ time_point t1 = std::chrono::high_resolution_clock::now();
+ int found = 0;
+ for (int i = 0; i < n; i++)
+ found += (int)getRandomString(container, randomString(strsize));
+
+ time_point t2 = std::chrono::high_resolution_clock::now();
+ const auto duration = std::chrono::duration_cast<std::chrono::milliseconds>(t2 - t1).count();
+ std::cerr << (strsize ? strsize : 32) << "\t" << duration << '\t' << found;
+ return (int)duration;
+}
-int main() {
- uint64_t seed = 4321;
+#include <time.h>
+int main(void) {
+ uint64_t seed = time(NULL); // 4321;
int sum, n;
// VECTOR WITH STRINGS
@@ -88,48 +121,75 @@ int main() {
csrand(seed);
sum = 0, n = 0;
std::cerr << "\nstrsize\tmsecs\tstd::vector<std::string>, size=" << BENCHMARK_SIZE << "\n";
- for (int strsize = 1; strsize <= MAX_STRING_SIZE; strsize += 2) {
+ for (int strsize = 1; strsize <= MAX_STRING_SIZE; strsize += 4) {
StdVec vec; vec.reserve(BENCHMARK_SIZE);
sum += benchmark(vec, BENCHMARK_SIZE, strsize), ++n;
std::cout << '\t' << vec.front() << '\n';
}
- std::cout << "Avg:\t" << sum/n << '\n';
+ std::cout << "Avg:\t" << sum/n << "ms\n";
csrand(seed);
sum = 0, n = 0;
std::cerr << "\nstrsize\tmsecs\tcvec<cstr>, size=" << BENCHMARK_SIZE << "\n";
- for (int strsize = 1; strsize <= MAX_STRING_SIZE; strsize += 2) {
+ for (int strsize = 1; strsize <= MAX_STRING_SIZE; strsize += 4) {
StcVec vec = StcVec_with_capacity(BENCHMARK_SIZE);
sum += benchmark(vec, BENCHMARK_SIZE, strsize), ++n;
std::cout << '\t' << cstr_str(&vec.data[0]) << '\n';
StcVec_drop(&vec);
}
- std::cout << "Avg:\t" << sum/n << '\n';
+ std::cout << "Avg:\t" << sum/n << "ms\n";
+
+ // INSERT: SORTED SET WITH STRINGS
+
+ csrand(seed);
+ sum = 0, n = 0;
+ std::cerr << "\nstrsize\tmsecs\tinsert: robin_hood::unordered_flat_set<std::string>, size=" << BENCHMARK_SIZE/2 << "\n";
+ for (int strsize = 1; strsize <= MAX_STRING_SIZE; strsize += 4) {
+ StdSet set; set.reserve(BENCHMARK_SIZE/2);
+ sum += benchmark(set, BENCHMARK_SIZE/2, strsize), ++n;
+ std::cout << '\t' << *set.begin() << '\n';
+ }
+ std::cout << "Avg:\t" << sum/n << "ms\n";
- // SORTED SET WITH STRINGS
csrand(seed);
sum = 0, n = 0;
- std::cerr << "\nstrsize\tmsecs\tstd::set<std::string>, size=" << BENCHMARK_SIZE/16 << "\n";
+ std::cerr << "\nstrsize\tmsecs\tinsert: cset<cstr>, size=" << BENCHMARK_SIZE/2 << "\n";
+ for (int strsize = 1; strsize <= MAX_STRING_SIZE; strsize += 4) {
+ StcSet set = StcSet_with_capacity(BENCHMARK_SIZE/2);
+ sum += benchmark(set, BENCHMARK_SIZE/2, strsize), ++n;
+ std::cout << '\t' << cstr_str(StcSet_begin(&set).ref) << '\n';
+ StcSet_drop(&set);
+ }
+ std::cout << "Avg:\t" << sum/n << "ms\n";
+
+ // LOOKUP: SORTED SET WITH STRINGS
+
+ csrand(seed);
+ sum = 0, n = 0;
+ std::cerr << "\nstrsize\tmsecs\tfind: robin_hood::unordered_flat_set<std::string>, size=" << BENCHMARK_SIZE/2 << "\n";
for (int strsize = 1; strsize <= MAX_STRING_SIZE; strsize += 2) {
- StdSet set;
- sum += benchmark(set, BENCHMARK_SIZE/16, strsize), ++n;
+ StdSet set; set.reserve(BENCHMARK_SIZE/2);
+ sum += benchmark_lookup(set, BENCHMARK_SIZE/2, strsize), ++n;
std::cout << '\t' << *set.begin() << '\n';
}
- std::cout << "Avg:\t" << sum/n << '\n';
+ std::cout << "Avg:\t" << sum/n << "ms\n";
csrand(seed);
sum = 0, n = 0;
- std::cerr << "\nstrsize\tmsecs\tcsset<cstr>, size=" << BENCHMARK_SIZE/16 << "\n";
+ std::cerr << "\nstrsize\tmsecs\tfind: cset<cstr>, size=" << BENCHMARK_SIZE/2 << "\n";
for (int strsize = 1; strsize <= MAX_STRING_SIZE; strsize += 2) {
- StcSet set = StcSet_with_capacity(BENCHMARK_SIZE/16);
- sum += benchmark(set, BENCHMARK_SIZE/16, strsize), ++n;
- std::cout << '\t' << cstr_str(StcSet_front(&set)) << '\n';
+ StcSet set = StcSet_with_capacity(BENCHMARK_SIZE/2);
+ sum += benchmark_lookup(set, BENCHMARK_SIZE/2, strsize), ++n;
+ std::cout << '\t' << cstr_str(StcSet_begin(&set).ref) << '\n';
StcSet_drop(&set);
}
- std::cout << "Avg:\t" << sum/n << '\n';
+ std::cout << "Avg:\t" << sum/n << "ms\n";
+
std::cerr << "sizeof(std::string) : " << sizeof(std::string) << std::endl
- << "sizeof(cstr) : " << sizeof(cstr) << std::endl;
+ << "sizeof(cstr) : " << sizeof(cstr) << std::endl
+ << "sizeof(StdSet) : " << sizeof(StdSet) << std::endl
+ << "sizeof(StcSet) : " << sizeof(StcSet) << std::endl;
return 0;
}
diff --git a/misc/benchmarks/various/string_bench_STC.cpp b/misc/benchmarks/various/string_bench_STC.cpp
index ae8e4c38..a5dfd901 100644
--- a/misc/benchmarks/various/string_bench_STC.cpp
+++ b/misc/benchmarks/various/string_bench_STC.cpp
@@ -4,10 +4,11 @@
#include <iostream>
#include <iomanip>
#include <chrono>
-#define i_static
+#define i_implement
#include <stc/cstr.h> // string
-#define i_static
+#define i_implement
#include <stc/csview.h> // string_view
+#include <stc/algo/raii.h>
#define i_key_str
#include <stc/cvec.h> // vec of cstr with const char* lookup
@@ -183,7 +184,7 @@ void benchmark(
//const size_t MAX_LOOP = 1000000;
const size_t MAX_LOOP = 2000;
-int main()
+int main(void)
{
c_auto (cvec_str, vec_string)
c_auto (cvec_sv, vec_stringview)
diff --git a/misc/benchmarks/various/string_bench_STD.cpp b/misc/benchmarks/various/string_bench_STD.cpp
index 8bb87937..153ac02f 100644
--- a/misc/benchmarks/various/string_bench_STD.cpp
+++ b/misc/benchmarks/various/string_bench_STD.cpp
@@ -12,6 +12,7 @@
#include <unordered_map>
#define i_static
#include <stc/cstr.h>
+#include <stc/algo/raii.h>
std::vector<std::string> read_file(const char* name)
{
@@ -193,7 +194,7 @@ void benchmark(
//const size_t MAX_LOOP = 1000000;
const size_t MAX_LOOP = 2000;
-int main()
+int main(void)
{
std::vector<std::string> vec_shortstr;
std::vector<std::string_view> vec_shortstrview;
diff --git a/misc/examples/forfilter.c b/misc/examples/algorithms/forfilter.c
index fbb7280f..c1426045 100644
--- a/misc/examples/forfilter.c
+++ b/misc/examples/algorithms/forfilter.c
@@ -1,12 +1,12 @@
#include <stdio.h>
-#define i_extern
+#define i_import
#include <stc/cstr.h>
+#define i_implement
#include <stc/csview.h>
-#include <stc/algo/filter.h>
-#include <stc/algo/crange.h>
+#include <stc/algorithm.h>
#define i_type IVec
-#define i_val int
+#define i_key int
#include <stc/cstack.h>
// filters and transforms:
@@ -17,7 +17,7 @@
void demo1(void)
{
- IVec vec = c_make(IVec, {0, 1, 2, 3, 4, 5, 80, 6, 7, 80, 8, 9, 80,
+ IVec vec = c_init(IVec, {0, 1, 2, 3, 4, 5, 80, 6, 7, 80, 8, 9, 80,
10, 11, 12, 13, 14, 15, 80, 16, 17});
c_forfilter (i, IVec, vec, flt_skipValue(i, 80))
@@ -54,7 +54,8 @@ fn main() {
void demo2(void)
{
IVec vector = {0};
- c_forfilter (x, crange, crange_obj(INT64_MAX),
+ crange r = crange_init(INT64_MAX);
+ c_forfilter (x, crange, r,
c_flt_skipwhile(x, *x.ref != 11) &&
(*x.ref % 2) != 0 &&
c_flt_take(x, 5)
@@ -81,7 +82,7 @@ fn main() {
}
*/
#define i_type SVec
-#define i_valclass csview
+#define i_keyclass csview
#include <stc/cstack.h>
void demo3(void)
@@ -123,7 +124,7 @@ void demo5(void)
{
#define flt_even(i) ((*i.ref & 1) == 0)
#define flt_mid_decade(i) ((*i.ref % 10) != 0)
- crange R = crange_make(1963, INT32_MAX);
+ crange R = crange_init(1963, INT32_MAX);
c_forfilter (i, crange, R,
c_flt_skip(i,15) &&
diff --git a/misc/examples/forloops.c b/misc/examples/algorithms/forloops.c
index 1fc00614..a83d4a53 100644
--- a/misc/examples/forloops.c
+++ b/misc/examples/algorithms/forloops.c
@@ -1,69 +1,65 @@
-#include <stdio.h>
-#include <stc/algo/filter.h>
-
-#define i_type IVec
-#define i_val int
-#include <stc/cstack.h>
-
-#define i_type IMap
-#define i_key int
-#define i_val int
-#include <stc/cmap.h>
-
-
-int main()
-{
- puts("c_forrange:");
- c_forrange (30) printf(" xx");
- puts("");
-
- c_forrange (i, 30) printf(" %lld", i);
- puts("");
-
- c_forrange (i, 30, 60) printf(" %lld", i);
- puts("");
-
- c_forrange (i, 30, 90, 2) printf(" %lld", i);
-
- puts("\n\nc_forlist:");
- c_forlist (i, int, {12, 23, 453, 65, 676})
- printf(" %d", *i.ref);
- puts("");
-
- c_forlist (i, const char*, {"12", "23", "453", "65", "676"})
- printf(" %s", *i.ref);
- puts("");
-
- IVec vec = c_make(IVec, {12, 23, 453, 65, 113, 215, 676, 34, 67, 20, 27, 66, 189, 45, 280, 199});
- IMap map = c_make(IMap, {{12, 23}, {453, 65}, {676, 123}, {34, 67}});
-
- puts("\n\nc_foreach:");
- c_foreach (i, IVec, vec)
- printf(" %d", *i.ref);
-
- puts("\n\nc_foreach_r: reverse");
- c_foreach_rv (i, IVec, vec)
- printf(" %d", *i.ref);
-
- puts("\n\nc_foreach in map:");
- c_foreach (i, IMap, map)
- printf(" (%d %d)", i.ref->first, i.ref->second);
-
- puts("\n\nc_forpair:");
- c_forpair (key, val, IMap, map)
- printf(" (%d %d)", *_.key, *_.val);
-
- #define isOdd(i) (*i.ref & 1)
-
- puts("\n\nc_forfilter:");
- c_forfilter (i, IVec, vec,
- isOdd(i) &&
- c_flt_skip(i, 4) &&
- c_flt_take(i, 4)
- ){
- printf(" %d", *i.ref);
- }
-
- IVec_drop(&vec);
- IMap_drop(&map);
-}
+#include <stdio.h>
+#include <stc/algorithm.h>
+
+#define i_type IVec
+#define i_key int
+#include <stc/cstack.h>
+
+#define i_type IMap
+#define i_key int
+#define i_val int
+#include <stc/cmap.h>
+
+
+int main(void)
+{
+ puts("c_forrange:");
+ c_forrange (30) printf(" xx");
+ puts("");
+
+ c_forrange (i, 30) printf(" %lld", i);
+ puts("");
+
+ c_forrange (i, 30, 60) printf(" %lld", i);
+ puts("");
+
+ c_forrange (i, 30, 90, 2) printf(" %lld", i);
+
+ puts("\n\nc_forlist:");
+ c_forlist (i, int, {12, 23, 453, 65, 676})
+ printf(" %d", *i.ref);
+ puts("");
+
+ c_forlist (i, const char*, {"12", "23", "453", "65", "676"})
+ printf(" %s", *i.ref);
+ puts("");
+
+ IVec vec = c_init(IVec, {12, 23, 453, 65, 113, 215, 676, 34, 67, 20, 27, 66, 189, 45, 280, 199});
+ IMap map = c_init(IMap, {{12, 23}, {453, 65}, {676, 123}, {34, 67}});
+
+ puts("\n\nc_foreach:");
+ c_foreach (i, IVec, vec)
+ printf(" %d", *i.ref);
+
+ puts("\n\nc_foreach in map:");
+ c_foreach (i, IMap, map)
+ printf(" (%d %d)", i.ref->first, i.ref->second);
+
+ puts("\n\nc_forpair:");
+ c_forpair (key, val, IMap, map)
+ printf(" (%d %d)", *_.key, *_.val);
+
+ #define isOdd(i) (*i.ref & 1)
+
+ puts("\n\nc_forfilter:");
+ c_forfilter (i, IVec, vec,
+ isOdd(i) &&
+ c_flt_skip(i, 4) &&
+ c_flt_take(i, 4)
+ ){
+ printf(" %d", *i.ref);
+ }
+
+ IVec_drop(&vec);
+ IMap_drop(&map);
+}
diff --git a/misc/examples/algorithms/random.c b/misc/examples/algorithms/random.c
new file mode 100644
index 00000000..e457d329
--- /dev/null
+++ b/misc/examples/algorithms/random.c
@@ -0,0 +1,42 @@
+#include <stdio.h>
+#include <time.h>
+#include <stc/crand.h>
+
+int main(void)
+{
+ const long long N = 10000000, range = 1000000;
+ const uint64_t seed = (uint64_t)time(NULL);
+ crand_t rng = crand_init(seed);
+ clock_t t;
+
+ printf("Compare speed of full and unbiased ranged random numbers...\n");
+ long long sum = 0;
+ t = clock();
+ c_forrange (N) {
+ sum += (int32_t)crand_u64(&rng);
+ }
+ t = clock() - t;
+ printf("full range\t\t: %f secs, %lld, avg: %f\n",
+ (double)t/CLOCKS_PER_SEC, N, (double)(sum/N));
+
+ crand_uniform_t dist1 = crand_uniform_init(0, range);
+ rng = crand_init(seed);
+ sum = 0;
+ t = clock();
+ c_forrange (N) {
+ sum += crand_uniform(&rng, &dist1); // unbiased
+ }
+ t = clock() - t;
+ printf("unbiased 0-%lld\t: %f secs, %lld, avg: %f\n",
+ range, (double)t/CLOCKS_PER_SEC, N, (double)(sum/N));
+
+ sum = 0;
+ rng = crand_init(seed);
+ t = clock();
+ c_forrange (N) {
+ sum += (int32_t)crand_u64(&rng) % (range + 1); // biased
+ }
+ t = clock() - t;
+ printf("biased 0-%lld \t: %f secs, %lld, avg: %f\n",
+ range, (double)t/CLOCKS_PER_SEC, N, (double)(sum/N));
+}
diff --git a/misc/examples/shape.c b/misc/examples/algorithms/shape.c
index d7116039..bd4bdd5a 100644
--- a/misc/examples/shape.c
+++ b/misc/examples/algorithms/shape.c
@@ -62,9 +62,9 @@ static void Triangle_draw(const Shape* shape)
{
const Triangle* self = DYN_CAST(Triangle, shape);
printf("Triangle : (%g,%g), (%g,%g), (%g,%g)\n",
- self->p[0].x, self->p[0].y,
- self->p[1].x, self->p[1].y,
- self->p[2].x, self->p[2].y);
+ (double)self->p[0].x, (double)self->p[0].y,
+ (double)self->p[1].x, (double)self->p[1].y,
+ (double)self->p[2].x, (double)self->p[2].y);
}
struct ShapeAPI Triangle_api = {
@@ -76,7 +76,7 @@ struct ShapeAPI Triangle_api = {
// ============================================================
#define i_type PointVec
-#define i_val Point
+#define i_key Point
#include <stc/cstack.h>
typedef struct {
@@ -109,7 +109,7 @@ static void Polygon_draw(const Shape* shape)
const Polygon* self = DYN_CAST(Polygon, shape);
printf("Polygon :");
c_foreach (i, PointVec, self->points)
- printf(" (%g,%g)", i.ref->x, i.ref->y);
+ printf(" (%g,%g)", (double)i.ref->x, (double)i.ref->y);
puts("");
}
@@ -122,8 +122,8 @@ struct ShapeAPI Polygon_api = {
// ============================================================
#define i_type Shapes
-#define i_val Shape*
-#define i_valdrop(x) Shape_delete(*x)
+#define i_key Shape*
+#define i_keydrop(x) Shape_delete(*x)
#define i_no_clone
#include <stc/cstack.h>
@@ -137,7 +137,7 @@ int main(void)
{
Shapes shapes = {0};
- Triangle* tri1 = c_new(Triangle, Triangle_from((Point){5, 7}, (Point){12, 7}, (Point){12, 20}));
+ Triangle* tri1 = c_new(Triangle, Triangle_from(c_LITERAL(Point){5, 7}, c_LITERAL(Point){12, 7}, c_LITERAL(Point){12, 20}));
Polygon* pol1 = c_new(Polygon, Polygon_init());
Polygon* pol2 = c_new(Polygon, Polygon_init());
diff --git a/misc/examples/shape.cpp b/misc/examples/algorithms/shape.cpp
index ea1f53d2..ea1f53d2 100644
--- a/misc/examples/shape.cpp
+++ b/misc/examples/algorithms/shape.cpp
diff --git a/misc/examples/bits.c b/misc/examples/bitsets/bits.c
index 1323d4e7..e0a11346 100644
--- a/misc/examples/bits.c
+++ b/misc/examples/bitsets/bits.c
@@ -9,18 +9,18 @@ int main(void)
cbits_drop(&set),
cbits_drop(&s2)
){
- printf("count %" c_ZI ", %" c_ZI "\n", cbits_count(&set), cbits_size(&set));
+ printf("count %lld, %lld\n", cbits_count(&set), cbits_size(&set));
cbits s1 = cbits_from("1110100110111");
char buf[256];
cbits_to_str(&s1, buf, 0, 255);
- printf("buf: %s: %" c_ZI "\n", buf, cbits_count(&s1));
+ printf("buf: %s: %lld\n", buf, cbits_count(&s1));
cbits_drop(&s1);
cbits_reset(&set, 9);
cbits_resize(&set, 43, false);
printf(" str: %s\n", cbits_to_str(&set, buf, 0, 255));
- printf("%4" c_ZI ": ", cbits_size(&set));
+ printf("%4lld: ", cbits_size(&set));
c_forrange (i, cbits_size(&set))
printf("%d", cbits_test(&set, i));
puts("");
@@ -30,12 +30,12 @@ int main(void)
cbits_resize(&set, 93, false);
cbits_resize(&set, 102, true);
cbits_set_value(&set, 99, false);
- printf("%4" c_ZI ": ", cbits_size(&set));
+ printf("%4lld: ", cbits_size(&set));
c_forrange (i, cbits_size(&set))
printf("%d", cbits_test(&set, i));
puts("\nIterate:");
- printf("%4" c_ZI ": ", cbits_size(&set));
+ printf("%4lld: ", cbits_size(&set));
c_forrange (i, cbits_size(&set))
printf("%d", cbits_test(&set, i));
puts("");
@@ -58,7 +58,7 @@ int main(void)
puts("");
cbits_set_all(&set, false);
- printf("%4" c_ZI ": ", cbits_size(&set));
+ printf("%4lld: ", cbits_size(&set));
c_forrange (i, cbits_size(&set))
printf("%d", cbits_test(&set, i));
puts("");
diff --git a/misc/examples/bits2.c b/misc/examples/bitsets/bits2.c
index b002af3c..de2f16f4 100644
--- a/misc/examples/bits2.c
+++ b/misc/examples/bitsets/bits2.c
@@ -5,14 +5,14 @@
#define i_capacity 80 // enable fixed bitset on the stack
#include <stc/cbits.h>
-int main()
+int main(void)
{
Bits s1 = Bits_from("1110100110111");
- printf("size %" c_ZI "\n", Bits_size(&s1));
+ printf("size %lld\n", Bits_size(&s1));
char buf[256];
Bits_to_str(&s1, buf, 0, 256);
- printf("buf: %s: count=%" c_ZI "\n", buf, Bits_count(&s1));
+ printf("buf: %s: count=%lld\n", buf, Bits_count(&s1));
Bits_reset(&s1, 8);
printf(" s1: %s\n", Bits_to_str(&s1, buf, 0, 256));
diff --git a/misc/examples/prime.c b/misc/examples/bitsets/prime.c
index d0887353..7e5a2b3f 100644
--- a/misc/examples/prime.c
+++ b/misc/examples/bitsets/prime.c
@@ -2,23 +2,23 @@
#include <math.h>
#include <time.h>
#include <stc/cbits.h>
-#include <stc/algo/filter.h>
-#include <stc/algo/crange.h>
+#include <stc/algorithm.h>
+typedef long long llong;
-cbits sieveOfEratosthenes(int64_t n)
+cbits sieveOfEratosthenes(llong n)
{
cbits bits = cbits_with_size(n/2 + 1, true);
- int64_t q = (int64_t)sqrt((double) n) + 1;
- for (int64_t i = 3; i < q; i += 2) {
- int64_t j = i;
+ llong q = (llong)sqrt((double) n) + 1;
+ for (llong i = 3; i < q; i += 2) {
+ llong j = i;
for (; j < n; j += 2) {
if (cbits_test(&bits, j>>1)) {
i = j;
break;
}
}
- for (int64_t j = i*i; j < n; j += i*2)
+ for (llong j = i*i; j < n; j += i*2)
cbits_reset(&bits, j>>1);
}
return bits;
@@ -26,15 +26,17 @@ cbits sieveOfEratosthenes(int64_t n)
int main(void)
{
- int64_t n = 1000000000;
- printf("Computing prime numbers up to %" c_ZI "\n", n);
+ llong n = 100000000;
+ printf("Computing prime numbers up to %lld\n", n);
- clock_t t1 = clock();
+ clock_t t = clock();
cbits primes = sieveOfEratosthenes(n + 1);
- int64_t np = cbits_count(&primes);
- clock_t t2 = clock();
- printf("Number of primes: %" c_ZI ", time: %f\n\n", np, (float)(t2 - t1) / (float)CLOCKS_PER_SEC);
+ llong np = cbits_count(&primes);
+ t = clock() - t;
+
+ printf("Number of primes: %lld, time: %f\n\n", np, (double)t/CLOCKS_PER_SEC);
+
puts("Show all the primes in the range [2, 1000):");
printf("2");
c_forrange (i, 3, 1000, 2)
@@ -42,7 +44,9 @@ int main(void)
puts("\n");
puts("Show the last 50 primes using a temporary crange generator:");
- c_forfilter (i, crange, crange_obj(n - 1, 0, -2),
+ crange range = crange_init(n - 1, 0, -2);
+
+ c_forfilter (i, crange, range,
cbits_test(&primes, *i.ref/2) &&
c_flt_take(i, 50)
){
diff --git a/misc/examples/coread.c b/misc/examples/coread.c
deleted file mode 100644
index 0a7f4816..00000000
--- a/misc/examples/coread.c
+++ /dev/null
@@ -1,39 +0,0 @@
-#include <stc/cstr.h>
-#include <stc/algo/coroutine.h>
-#include <errno.h>
-
-// Read file line by line using coroutines:
-
-struct file_nextline {
- const char* filename;
- int cco_state;
- FILE* fp;
- cstr line;
-};
-
-bool file_nextline(struct file_nextline* U)
-{
- cco_begin(U)
- U->fp = fopen(U->filename, "r");
- U->line = cstr_init();
-
- while (cstr_getline(&U->line, U->fp))
- cco_yield(true);
-
- cco_final: // this label is required.
- printf("finish\n");
- cstr_drop(&U->line);
- fclose(U->fp);
- cco_end(false);
-}
-
-int main(void)
-{
- struct file_nextline it = {__FILE__};
- int n = 0;
- while (file_nextline(&it))
- {
- printf("%3d %s\n", ++n, cstr_str(&it.line));
- //if (n == 10) cco_stop(&it);
- }
-}
diff --git a/misc/examples/coroutines.c b/misc/examples/coroutines.c
deleted file mode 100644
index b11b8532..00000000
--- a/misc/examples/coroutines.c
+++ /dev/null
@@ -1,106 +0,0 @@
-#include <stc/algo/coroutine.h>
-#include <stdio.h>
-#include <stdint.h>
-
-// Demonstrate to call another coroutine from a coroutine:
-// First create prime generator, then call fibonacci sequence:
-
-bool is_prime(int64_t i) {
- for (int64_t j=2; j*j <= i; ++j)
- if (i % j == 0) return false;
- return true;
-}
-
-struct prime {
- int count, idx;
- int64_t result, pos;
- int cco_state;
-};
-
-bool prime(struct prime* U) {
- cco_begin(U);
- if (U->result < 2) U->result = 2;
- if (U->result == 2) {
- if (U->count-- == 0) cco_return;
- ++U->idx;
- cco_yield(true);
- }
- U->result += !(U->result & 1);
- for (U->pos = U->result; U->count > 0; U->pos += 2) {
- if (is_prime(U->pos)) {
- --U->count;
- ++U->idx;
- U->result = U->pos;
- cco_yield(true);
- }
- }
- cco_final:
- printf("final prm\n");
- cco_end(false);
-}
-
-
-// Use coroutine to create a fibonacci sequence generator:
-
-struct fibonacci {
- int count, idx;
- int64_t result, b;
- int cco_state;
-};
-
-bool fibonacci(struct fibonacci* F) {
- assert(F->count < 94);
-
- cco_begin(F);
- F->idx = 0;
- F->result = 0;
- F->b = 1;
- for (;;) {
- if (F->count-- == 0)
- cco_return;
- if (++F->idx > 1) {
- int64_t sum = F->result + F->b; // NB! locals only lasts until next cco_yield!
- F->result = F->b;
- F->b = sum;
- }
- cco_yield(true);
- }
- cco_final:
- printf("final fib\n");
- cco_end(false);
-}
-
-// Combine
-
-struct combined {
- struct prime prm;
- struct fibonacci fib;
- int cco_state;
-};
-
-bool combined(struct combined* C) {
- cco_begin(C);
- cco_yield(prime(&C->prm), &C->prm, true);
- cco_yield(fibonacci(&C->fib), &C->fib, true);
-
- // Reuse the C->prm context and extend the count:
- C->prm.count = 8; C->prm.result += 2;
- cco_reset(&C->prm);
- cco_yield(prime(&C->prm), &C->prm, true);
-
- cco_final: puts("final comb");
- cco_end(false);
-}
-
-int main(void) {
- struct combined comb = {.prm={.count=8}, .fib={14}};
- if (true)
- while (combined(&comb))
- printf("Prime(%d)=%lld, Fib(%d)=%lld\n",
- comb.prm.idx, (long long)comb.prm.result,
- comb.fib.idx, (long long)comb.fib.result);
- else
- while (prime(&comb.prm))
- printf("Prime(%d)=%lld\n",
- comb.prm.idx, (long long)comb.prm.result);
-}
diff --git a/misc/examples/coroutines/cointerleave.c b/misc/examples/coroutines/cointerleave.c
new file mode 100644
index 00000000..80494176
--- /dev/null
+++ b/misc/examples/coroutines/cointerleave.c
@@ -0,0 +1,62 @@
+// https://www.youtube.com/watch?v=8sEe-4tig_A
+#include <stdio.h>
+#include <stc/coroutine.h>
+#define i_type IVec
+#define i_key int
+#include <stc/cvec.h>
+
+struct GenValue {
+ IVec *v;
+ IVec_iter it;
+ int cco_state;
+};
+
+static int get_value(struct GenValue* g)
+{
+ cco_routine(g) {
+ for (g->it = IVec_begin(g->v); g->it.ref; IVec_next(&g->it))
+ cco_yield_v(*g->it.ref);
+ }
+ return -1;
+}
+
+struct Generator {
+ struct GenValue x, y;
+ int cco_state;
+ int value;
+};
+
+cco_result interleaved(struct Generator* g)
+{
+ cco_routine(g) {
+ while (!(cco_done(&g->x) & cco_done(&g->y))) {
+ g->value = get_value(&g->x);
+ if (!cco_done(&g->x))
+ cco_yield();
+
+ g->value = get_value(&g->y);
+ if (!cco_done(&g->y))
+ cco_yield();
+ }
+ }
+ return CCO_DONE;
+}
+
+void Use(void)
+{
+ IVec a = c_init(IVec, {2, 4, 6, 8, 10, 11});
+ IVec b = c_init(IVec, {3, 5, 7, 9});
+
+ struct Generator g = {{&a}, {&b}};
+
+ cco_blocking_call(interleaved(&g)) {
+ printf("%d ", g.value);
+ }
+ puts("");
+ c_drop(IVec, &a, &b);
+}
+
+int main(void)
+{
+ Use();
+}
diff --git a/misc/examples/coroutines/coread.c b/misc/examples/coroutines/coread.c
new file mode 100644
index 00000000..6d3acdd7
--- /dev/null
+++ b/misc/examples/coroutines/coread.c
@@ -0,0 +1,41 @@
+#define i_implement
+#include <stc/cstr.h>
+#include <stc/coroutine.h>
+#include <errno.h>
+
+// Read file line by line using coroutines:
+
+struct file_read {
+ const char* filename;
+ int cco_state;
+ FILE* fp;
+ cstr line;
+};
+
+int file_read(struct file_read* g)
+{
+ cco_routine(g) {
+ g->fp = fopen(g->filename, "r");
+ if (!g->fp) cco_return;
+ g->line = cstr_init();
+
+ cco_await(!cstr_getline(&g->line, g->fp));
+
+ cco_final:
+ printf("finish\n");
+ cstr_drop(&g->line);
+ if (g->fp) fclose(g->fp);
+ }
+ return 0;
+}
+
+int main(void)
+{
+ struct file_read g = {__FILE__};
+ int n = 0;
+ cco_blocking_call(file_read(&g))
+ {
+ printf("%3d %s\n", ++n, cstr_str(&g.line));
+ //if (n == 10) cco_stop(&g);
+ }
+}
diff --git a/misc/examples/coroutines/coroutines.c b/misc/examples/coroutines/coroutines.c
new file mode 100644
index 00000000..802a976a
--- /dev/null
+++ b/misc/examples/coroutines/coroutines.c
@@ -0,0 +1,112 @@
+#include <stc/coroutine.h>
+#include <stdio.h>
+#include <stdint.h>
+
+// Demonstrate to call another coroutine from a coroutine:
+// First create prime generator, then call fibonacci sequence:
+
+bool is_prime(long long i) {
+ for (long long j=2; j*j <= i; ++j)
+ if (i % j == 0) return false;
+ return true;
+}
+
+struct prime {
+ int count, idx;
+ long long result, pos;
+ int cco_state;
+};
+
+int prime(struct prime* g) {
+ cco_routine(g) {
+ if (g->result < 2) g->result = 2;
+ if (g->result == 2) {
+ if (g->count-- == 0) cco_return;
+ ++g->idx;
+ cco_yield();
+ }
+ g->result += !(g->result & 1);
+ for (g->pos = g->result; g->count > 0; g->pos += 2) {
+ if (is_prime(g->pos)) {
+ --g->count;
+ ++g->idx;
+ g->result = g->pos;
+ cco_yield();
+ }
+ }
+ cco_final:
+ printf("final prm\n");
+ }
+ return 0;
+}
+
+
+// Use coroutine to create a fibonacci sequence generator:
+
+struct fibonacci {
+ int count, idx;
+ long long result, b;
+ int cco_state;
+};
+
+int fibonacci(struct fibonacci* g) {
+ assert(g->count < 94);
+
+ long long sum;
+ cco_routine(g) {
+ g->idx = 0;
+ g->result = 0;
+ g->b = 1;
+ for (;;) {
+ if (g->count-- == 0)
+ cco_return;
+ if (++g->idx > 1) {
+ // NB! locals lasts only until next yield/await!
+ sum = g->result + g->b;
+ g->result = g->b;
+ g->b = sum;
+ }
+ cco_yield();
+ }
+ cco_final:
+ printf("final fib\n");
+ }
+ return 0;
+}
+
+// Combine
+
+struct combined {
+ struct prime prm;
+ struct fibonacci fib;
+ int cco_state;
+};
+
+int combined(struct combined* g) {
+ cco_routine(g) {
+ cco_await_call(prime(&g->prm));
+ cco_await_call(fibonacci(&g->fib));
+
+ // Reuse the g->prm context and extend the count:
+ g->prm.count = 8, g->prm.result += 2;
+ cco_reset(&g->prm);
+ cco_await_call(prime(&g->prm));
+
+ cco_final:
+ puts("final combined");
+ }
+ return 0;
+}
+
+int main(void)
+{
+ struct combined c = {.prm={.count=8}, .fib={14}};
+ int res;
+
+ cco_blocking_call(res = combined(&c)) {
+ if (res == CCO_YIELD)
+ printf("Prime(%d)=%lld, Fib(%d)=%lld\n",
+ c.prm.idx, c.prm.result,
+ c.fib.idx, c.fib.result);
+ }
+}
diff --git a/misc/examples/coroutines/cotasks1.c b/misc/examples/coroutines/cotasks1.c
new file mode 100644
index 00000000..cffd6620
--- /dev/null
+++ b/misc/examples/coroutines/cotasks1.c
@@ -0,0 +1,100 @@
+// https://mariusbancila.ro/blog/2020/06/22/a-cpp20-coroutine-example/
+
+#include <time.h>
+#include <stdio.h>
+#define i_static
+#include <stc/cstr.h>
+#include <stc/coroutine.h>
+
+struct next_value {
+ int val;
+ int cco_state;
+ cco_timer tm;
+};
+
+int next_value(struct next_value* co)
+{
+ cco_routine (co) {
+ while (true) {
+ cco_await_timer(&co->tm, 1 + rand() % 2);
+ co->val = rand();
+ cco_yield();
+ }
+ }
+ return 0;
+}
+
+void print_time()
+{
+ time_t now = time(NULL);
+ char mbstr[64];
+ strftime(mbstr, sizeof(mbstr), "[%H:%M:%S]", localtime(&now));
+ printf("%s ", mbstr);
+}
+
+// PRODUCER
+
+struct produce_items {
+ struct next_value next;
+ cstr text;
+ int cco_state;
+};
+
+int produce_items(struct produce_items* p)
+{
+ cco_routine (p) {
+ p->text = cstr_init();
+ while (true)
+ {
+ cco_await(next_value(&p->next) != CCO_AWAIT);
+ cstr_printf(&p->text, "item %d", p->next.val);
+ print_time();
+ printf("produced %s\n", cstr_str(&p->text));
+ cco_yield();
+ }
+ cco_final:
+ cstr_drop(&p->text);
+ puts("done produce");
+ }
+ return 0;
+}
+
+// CONSUMER
+
+struct consume_items {
+ int n, i;
+ int cco_state;
+};
+
+int consume_items(struct consume_items* c, struct produce_items* p)
+{
+ cco_routine (c) {
+ for (c->i = 1; c->i <= c->n; ++c->i)
+ {
+ printf("consume #%d\n", c->i);
+ cco_await(produce_items(p) != CCO_AWAIT);
+ print_time();
+ printf("consumed %s\n", cstr_str(&p->text));
+ }
+ cco_final:
+ puts("done consume");
+ }
+ return 0;
+}
+
+int main(void)
+{
+ struct produce_items produce = {0};
+ struct consume_items consume = {.n=5};
+ int count = 0;
+
+ cco_blocking_call(consume_items(&consume, &produce))
+ {
+ ++count;
+ //cco_sleep(0.001);
+ //if (consume.i == 3) cco_stop(&consume);
+ }
+ cco_stop(&produce);
+ produce_items(&produce);
+ printf("count: %d\n", count);
+} \ No newline at end of file
diff --git a/misc/examples/coroutines/cotasks2.c b/misc/examples/coroutines/cotasks2.c
new file mode 100644
index 00000000..558df118
--- /dev/null
+++ b/misc/examples/coroutines/cotasks2.c
@@ -0,0 +1,98 @@
+// https://mariusbancila.ro/blog/2020/06/22/a-cpp20-coroutine-example/
+
+#include <time.h>
+#include <stdio.h>
+#define i_static
+#include <stc/cstr.h>
+#include <stc/coroutine.h>
+
+cco_task_struct (next_value,
+ int val;
+ cco_timer tm;
+);
+
+int next_value(struct next_value* co, cco_runtime* rt)
+{
+ cco_routine (co) {
+ while (true) {
+ cco_await_timer(&co->tm, 1 + rand() % 2);
+ co->val = rand();
+ cco_yield();
+ }
+ }
+ return 0;
+}
+
+void print_time()
+{
+ time_t now = time(NULL);
+ char mbstr[64];
+ strftime(mbstr, sizeof(mbstr), "[%H:%M:%S]", localtime(&now));
+ printf("%s ", mbstr);
+}
+
+// PRODUCER
+
+cco_task_struct (produce_items,
+ struct next_value next;
+ cstr text;
+);
+
+int produce_items(struct produce_items* p, cco_runtime* rt)
+{
+ cco_routine (p) {
+ p->text = cstr_init();
+ p->next.cco_func = next_value;
+ while (true)
+ {
+ // await for next CCO_YIELD (or CCO_DONE) in next_value
+ cco_await_task(&p->next, rt, CCO_YIELD);
+ cstr_printf(&p->text, "item %d", p->next.val);
+ print_time();
+ printf("produced %s\n", cstr_str(&p->text));
+ cco_yield();
+ }
+
+ cco_final:
+ cstr_drop(&p->text);
+ puts("done produce");
+ }
+ return 0;
+}
+
+// CONSUMER
+
+cco_task_struct (consume_items,
+ int n, i;
+ struct produce_items produce;
+);
+
+int consume_items(struct consume_items* c, cco_runtime* rt)
+{
+ cco_routine (c) {
+ c->produce.cco_func = produce_items;
+
+ for (c->i = 1; c->i <= c->n; ++c->i)
+ {
+ printf("consume #%d\n", c->i);
+ cco_await_task(&c->produce, rt, CCO_YIELD);
+ print_time();
+ printf("consumed %s\n", cstr_str(&c->produce.text));
+ }
+
+ cco_final:
+ cco_stop(&c->produce);
+ cco_resume_task(&c->produce, rt);
+ puts("done consume");
+ }
+ return 0;
+}
+
+int main(void)
+{
+ struct consume_items consume = {
+ .cco_func = consume_items,
+ .n = 5,
+ };
+ cco_blocking_task(&consume);
+}
diff --git a/misc/examples/coroutines/dining_philosophers.c b/misc/examples/coroutines/dining_philosophers.c
new file mode 100644
index 00000000..d353b3b9
--- /dev/null
+++ b/misc/examples/coroutines/dining_philosophers.c
@@ -0,0 +1,105 @@
+// https://en.wikipedia.org/wiki/Dining_philosophers_problem
+#include <stdio.h>
+#include <time.h>
+#include <stc/crand.h>
+#include <stc/coroutine.h>
+
+// Define the number of philosophers and forks
+enum {
+ num_philosophers = 5,
+ num_forks = num_philosophers,
+};
+
+struct Philosopher {
+ int id;
+ cco_timer tm;
+ cco_sem* left_fork;
+ cco_sem* right_fork;
+ int cco_state; // required
+};
+
+struct Dining {
+ // Define semaphores for the forks
+ cco_sem forks[num_forks];
+ struct Philosopher ph[num_philosophers];
+ int cco_state; // required
+};
+
+
+// Philosopher coroutine
+int philosopher(struct Philosopher* p)
+{
+ double duration;
+ cco_routine(p) {
+ while (1) {
+ duration = 1.0 + crandf()*2.0;
+ printf("Philosopher %d is thinking for %.0f minutes...\n", p->id, duration*10);
+ cco_await_timer(&p->tm, duration);
+
+ printf("Philosopher %d is hungry...\n", p->id);
+ cco_await_sem(p->left_fork);
+ cco_await_sem(p->right_fork);
+
+ duration = 0.5 + crandf();
+ printf("Philosopher %d is eating for %.0f minutes...\n", p->id, duration*10);
+ cco_await_timer(&p->tm, duration);
+
+ cco_sem_release(p->left_fork);
+ cco_sem_release(p->right_fork);
+ }
+
+ cco_final:
+ printf("Philosopher %d finished\n", p->id);
+ }
+ return 0;
+}
+
+
+// Dining coroutine
+int dining(struct Dining* d)
+{
+ cco_routine(d) {
+ for (int i = 0; i < num_forks; ++i)
+ cco_sem_set(&d->forks[i], 1); // all forks available
+ for (int i = 0; i < num_philosophers; ++i) {
+ cco_reset(&d->ph[i]);
+ d->ph[i].id = i + 1;
+ d->ph[i].left_fork = &d->forks[i];
+ d->ph[i].right_fork = &d->forks[(i + 1) % num_forks];
+ }
+
+ while (1) {
+ // per-"frame" logic resume each philosopher
+ for (int i = 0; i < num_philosophers; ++i) {
+ philosopher(&d->ph[i]);
+ }
+ cco_yield(); // suspend, return control back to main
+ }
+
+ cco_final:
+ for (int i = 0; i < num_philosophers; ++i) {
+ cco_stop(&d->ph[i]);
+ philosopher(&d->ph[i]);
+ }
+ puts("Dining finished");
+ }
+ return 0;
+}
+
+int main(void)
+{
+ struct Dining dine;
+ cco_reset(&dine);
+ int n=0;
+ cco_timer tm = cco_timer_from(15.0); // seconds
+ csrand((uint64_t)time(NULL));
+
+ cco_blocking_call(dining(&dine))
+ {
+ if (cco_timer_expired(&tm))
+ cco_stop(&dine);
+ cco_sleep(0.001);
+ ++n;
+ }
+ printf("n=%d\n", n);
+}
diff --git a/misc/examples/coroutines/filetask.c b/misc/examples/coroutines/filetask.c
new file mode 100644
index 00000000..9650cb60
--- /dev/null
+++ b/misc/examples/coroutines/filetask.c
@@ -0,0 +1,80 @@
+// https://github.com/lewissbaker/cppcoro#taskt
+
+#include <time.h>
+#include <stdio.h>
+#define i_static
+#include <stc/cstr.h>
+#include <stc/coroutine.h>
+
+cco_task_struct(file_read,
+ const char* path;
+ cstr line;
+ FILE* fp;
+ cco_timer tm;
+);
+
+int file_read(struct file_read* co, cco_runtime* rt)
+{
+ cco_routine (co) {
+ co->fp = fopen(co->path, "r");
+ co->line = cstr_init();
+
+ while (true) {
+ // emulate async io: await 10ms per line
+ cco_await_timer(&co->tm, 0.010);
+
+ if (!cstr_getline(&co->line, co->fp))
+ break;
+ cco_yield();
+ }
+
+ cco_final:
+ fclose(co->fp);
+ cstr_drop(&co->line);
+ puts("done file_read");
+ }
+ return 0;
+}
+
+cco_task_struct(count_line,
+ cstr path;
+ struct file_read reader;
+ int lineCount;
+);
+
+int count_line(struct count_line* co, cco_runtime* rt)
+{
+ cco_routine (co) {
+ co->reader.cco_func = file_read;
+ co->reader.path = cstr_str(&co->path);
+ while (true)
+ {
+ // await for next CCO_YIELD (or CCO_DONE) in file_read()
+ cco_await_task(&co->reader, rt, CCO_YIELD);
+ if (rt->result == CCO_DONE) break;
+ co->lineCount += 1;
+ cco_yield();
+ }
+
+ cco_final:
+ cstr_drop(&co->path);
+ puts("done count_line");
+ }
+ return 0;
+}
+
+int main(void)
+{
+ // Creates a new task
+ struct count_line countTask = {
+ .cco_func = count_line,
+ .path = cstr_from(__FILE__),
+ };
+
+ // Execute coroutine as top-level blocking
+ int loop = 0;
+ cco_blocking_task(&countTask) { ++loop; }
+
+ printf("line count = %d\n", countTask.lineCount);
+ printf("exec count = %d\n", loop);
+}
diff --git a/misc/examples/coroutines/generator.c b/misc/examples/coroutines/generator.c
new file mode 100644
index 00000000..96498498
--- /dev/null
+++ b/misc/examples/coroutines/generator.c
@@ -0,0 +1,66 @@
+// https://quuxplusone.github.io/blog/2019/03/06/pythagorean-triples/
+
+#include <stdio.h>
+#include <stc/coroutine.h>
+#include <stc/algorithm.h>
+
+typedef struct {
+ int max_triples;
+ int a, b, c;
+} Triple;
+
+// Create an iterable generator over Triple with count items.
+// Requires coroutine Triple_next() and function Triple_begin() to be defined.
+cco_iter_struct(Triple,
+ int count;
+);
+
+int Triple_next(Triple_iter* it) {
+ Triple* g = it->ref; // note: before cco_routine
+ cco_routine(it)
+ {
+ for (g->c = 5;; ++g->c) {
+ for (g->a = 1; g->a < g->c; ++g->a) {
+ for (g->b = g->a; g->b < g->c; ++g->b) {
+ if (g->a*g->a + g->b*g->b == g->c*g->c) {
+ if (it->count++ == g->max_triples)
+ cco_return;
+ cco_yield();
+ }
+ }
+ }
+ }
+ cco_final:
+ it->ref = NULL; // stop the iterator
+ }
+ return 0;
+}
+
+Triple_iter Triple_begin(Triple* g) {
+ Triple_iter it = {.ref=g};
+ Triple_next(&it);
+ return it;
+}
+
+
+int main(void)
+{
+ puts("Pythagorean triples.\nGet max 200 triples with c < 50:");
+ Triple triple = {.max_triples=200};
+
+ c_foreach (i, Triple, triple) {
+ if (i.ref->c < 50)
+ printf("%u: (%d, %d, %d)\n", i.count, i.ref->a, i.ref->b, i.ref->c);
+ else
+ cco_stop(&i);
+ }
+
+ puts("\nGet the 10 first triples with odd a's and a <= 20:");
+ c_forfilter (i, Triple, triple,
+ i.ref->a <= 20 &&
+ (i.ref->a & 1) &&
+ c_flt_take(i, 10)
+ ){
+ printf("%d: (%d, %d, %d)\n", c_flt_getcount(i), i.ref->a, i.ref->b, i.ref->c);
+ }
+}
diff --git a/misc/examples/coroutines/scheduler.c b/misc/examples/coroutines/scheduler.c
new file mode 100644
index 00000000..be1810d2
--- /dev/null
+++ b/misc/examples/coroutines/scheduler.c
@@ -0,0 +1,67 @@
+// https://www.youtube.com/watch?v=8sEe-4tig_A
+#include <stdio.h>
+#include <stc/coroutine.h>
+
+#define i_type cco_tasks
+#define i_key cco_task*
+#define i_keydrop(x) { puts("free task"); free(*x); }
+#define i_no_clone
+#include <stc/cqueue.h>
+
+typedef struct {
+ cco_tasks tasks;
+} cco_scheduler;
+
+void cco_scheduler_drop(cco_scheduler* sched) {
+ cco_tasks_drop(&sched->tasks);
+}
+
+int cco_scheduler_run(cco_scheduler* sched) {
+ while (!cco_tasks_empty(&sched->tasks)) {
+ cco_task* task = cco_tasks_pull(&sched->tasks);
+ if (cco_resume_task(task, NULL))
+ cco_tasks_push(&sched->tasks, task);
+ else
+ cco_tasks_value_drop(&task);
+ }
+ return 0;
+}
+
+static int taskA(cco_task* task, cco_runtime* rt) {
+ cco_routine(task) {
+ puts("Hello, from task A");
+ cco_yield();
+ puts("A is back doing work");
+ cco_yield();
+ puts("A is back doing more work");
+ cco_yield();
+ puts("A is back doing even more work");
+ }
+ return 0;
+}
+
+static int taskB(cco_task* task, cco_runtime* rt) {
+ cco_routine(task) {
+ puts("Hello, from task B");
+ cco_yield();
+ puts("B is back doing work");
+ cco_yield();
+ puts("B is back doing more work");
+ }
+ return 0;
+}
+
+void Use(void) {
+ cco_scheduler sched = {.tasks = c_init(cco_tasks, {
+ c_new(cco_task, {.cco_func=taskA}),
+ c_new(cco_task, {.cco_func=taskB}),
+ })};
+
+ cco_scheduler_run(&sched);
+ cco_scheduler_drop(&sched);
+}
+
+int main(void)
+{
+ Use();
+}
diff --git a/misc/examples/coroutines/triples.c b/misc/examples/coroutines/triples.c
new file mode 100644
index 00000000..d6ce2791
--- /dev/null
+++ b/misc/examples/coroutines/triples.c
@@ -0,0 +1,75 @@
+// https://quuxplusone.github.io/blog/2019/03/06/pythagorean-triples/
+
+#include <stdio.h>
+#include <stc/coroutine.h>
+
+void triples_vanilla(int max_c) {
+ for (int c = 5, i = 0;; ++c) {
+ for (int a = 1; a < c; ++a) {
+ for (int b = a + 1; b < c; ++b) {
+ if ((int64_t)a*a + (int64_t)b*b == (int64_t)c*c) {
+ if (c > max_c)
+ goto done;
+ printf("%d: {%d, %d, %d}\n", ++i, a, b, c);
+ }
+ }
+ }
+ }
+ done:;
+}
+
+struct triples {
+ int max_c;
+ int a, b, c;
+ int cco_state;
+};
+
+int triples_coro(struct triples* t) {
+ cco_routine(t) {
+ for (t->c = 5;; ++t->c) {
+ for (t->a = 1; t->a < t->c; ++t->a) {
+ for (t->b = t->a + 1; t->b < t->c; ++t->b) {
+ if ((int64_t)t->a * t->a +
+ (int64_t)t->b * t->b ==
+ (int64_t)t->c * t->c)
+ {
+ if (t->c > t->max_c)
+ cco_return;
+ cco_yield();
+ }
+ }
+ }
+ }
+ cco_final:
+ puts("done");
+ }
+ return 0;
+}
+
+int gcd(int a, int b) {
+ while (b) {
+ int t = a % b;
+ a = b;
+ b = t;
+ }
+ return a;
+}
+
+int main(void)
+{
+ puts("Vanilla triples:");
+ triples_vanilla(20);
+
+ puts("\nCoroutine triples with GCD = 1:");
+ struct triples t = {.max_c = 100};
+ int n = 0;
+
+ cco_blocking_call(triples_coro(&t)) {
+ if (gcd(t.a, t.b) > 1)
+ continue;
+ if (++n <= 20)
+ printf("%d: {%d, %d, %d}\n", n, t.a, t.b, t.c);
+ else
+ cco_stop(&t);
+ }
+}
diff --git a/misc/examples/generator.c b/misc/examples/generator.c
deleted file mode 100644
index 2bccc489..00000000
--- a/misc/examples/generator.c
+++ /dev/null
@@ -1,53 +0,0 @@
-// https://quuxplusone.github.io/blog/2019/03/06/pythagorean-triples/
-
-#include <stc/algo/coroutine.h>
-#include <stdio.h>
-
-typedef struct {
- int n;
- int a, b, c;
-} Triple_value, Triple;
-
-typedef struct {
- Triple_value* ref;
- int cco_state;
-} Triple_iter;
-
-bool Triple_next(Triple_iter* it) {
- Triple_value* t = it->ref;
- cco_begin(it);
- for (t->c = 1;; ++t->c) {
- for (t->a = 1; t->a < t->c; ++t->a) {
- for (t->b = t->a; t->b < t->c; ++t->b) {
- if (t->a*t->a + t->b*t->b == t->c*t->c) {
- if (t->n-- == 0) cco_return;
- cco_yield(true);
- }
- }
- }
- }
- cco_final:
- it->ref = NULL;
- cco_end(false);
-}
-
-Triple_iter Triple_begin(Triple* t) {
- Triple_iter it = {t};
- if (t->n > 0) Triple_next(&it);
- else it.ref = NULL;
- return it;
-}
-
-
-int main()
-{
- puts("Pythagorean triples with c < 100:");
- Triple t = {INT32_MAX};
- c_foreach (i, Triple, t)
- {
- if (i.ref->c < 100)
- printf("%u: (%d, %d, %d)\n", INT32_MAX - i.ref->n + 1, i.ref->a, i.ref->b, i.ref->c);
- else
- cco_stop(&i);
- }
-}
diff --git a/misc/examples/birthday.c b/misc/examples/hashmaps/birthday.c
index c301128a..4742cb45 100644
--- a/misc/examples/birthday.c
+++ b/misc/examples/hashmaps/birthday.c
@@ -13,8 +13,8 @@ static uint64_t seed = 12345;
static void test_repeats(void)
{
enum {BITS = 46, BITS_TEST = BITS/2 + 2};
- const static uint64_t N = 1ull << BITS_TEST;
- const static uint64_t mask = (1ull << BITS) - 1;
+ static const uint64_t N = 1ull << BITS_TEST;
+ static const uint64_t mask = (1ull << BITS) - 1;
printf("birthday paradox: value range: 2^%d, testing repeats of 2^%d values\n", BITS, BITS_TEST);
crand_t rng = crand_init(seed);
@@ -60,7 +60,7 @@ void test_distribution(void)
cmap_x_drop(&map);
}
-int main()
+int main(void)
{
seed = (uint64_t)time(NULL);
test_distribution();
diff --git a/misc/examples/books.c b/misc/examples/hashmaps/books.c
index a62769b0..1fd57f27 100644
--- a/misc/examples/books.c
+++ b/misc/examples/hashmaps/books.c
@@ -1,4 +1,5 @@
// https://doc.rust-lang.org/std/collections/struct.HashMap.html
+#define i_implement
#include <stc/cstr.h>
#define i_key_str
#define i_val_str
@@ -6,7 +7,7 @@
// Type inference lets us omit an explicit type signature (which
// would be `HashMap<String, String>` in this example).
-int main()
+int main(void)
{
cmap_str book_reviews = {0};
diff --git a/misc/examples/hashmap.c b/misc/examples/hashmaps/hashmap.c
index 47a3bcff..cf11b7f7 100644
--- a/misc/examples/hashmap.c
+++ b/misc/examples/hashmaps/hashmap.c
@@ -1,4 +1,5 @@
// https://doc.rust-lang.org/rust-by-example/std/hash.html
+#define i_implement
#include <stc/cstr.h>
#define i_key_str
#define i_val_str
diff --git a/misc/examples/new_map.c b/misc/examples/hashmaps/new_map.c
index 3a4f934d..de990040 100644
--- a/misc/examples/new_map.c
+++ b/misc/examples/hashmaps/new_map.c
@@ -1,12 +1,13 @@
+#define i_implement
#include <stc/cstr.h>
#include <stc/forward.h>
forward_cmap(cmap_pnt, struct Point, int);
-struct MyStruct {
+typedef struct MyStruct {
cmap_pnt pntmap;
cstr name;
-} typedef MyStruct;
+} MyStruct;
// int => int map
#define i_key int
@@ -14,7 +15,7 @@ struct MyStruct {
#include <stc/cmap.h>
// Point => int map
-struct Point { int x, y; } typedef Point;
+typedef struct Point { int x, y; } Point;
int point_cmp(const Point* a, const Point* b) {
int c = a->x - b->x;
@@ -40,20 +41,20 @@ int point_cmp(const Point* a, const Point* b) {
#include <stc/cset.h>
-int main()
+int main(void)
{
- cmap_pnt pmap = c_make(cmap_pnt, {{{42, 14}, 1}, {{32, 94}, 2}, {{62, 81}, 3}});
+ cmap_pnt pmap = c_init(cmap_pnt, {{{42, 14}, 1}, {{32, 94}, 2}, {{62, 81}, 3}});
c_foreach (i, cmap_pnt, pmap)
printf(" (%d, %d: %d)", i.ref->first.x, i.ref->first.y, i.ref->second);
puts("");
- cmap_str smap = c_make(cmap_str, {
+ cmap_str smap = c_init(cmap_str, {
{"Hello, friend", "long time no see"},
{"So long", "see you around"},
});
- cset_str sset = c_make(cset_str, {
+ cset_str sset = c_init(cset_str, {
"Hello, friend",
"Nice to see you again",
"So long",
diff --git a/misc/examples/phonebook.c b/misc/examples/hashmaps/phonebook.c
index c0007cb7..faf7566e 100644
--- a/misc/examples/phonebook.c
+++ b/misc/examples/hashmaps/phonebook.c
@@ -20,7 +20,7 @@
// IN THE SOFTWARE.
// Program to emulates the phone book.
-
+#define i_implement
#include <stc/cstr.h>
#define i_key_str
@@ -38,7 +38,7 @@ void print_phone_book(cmap_str phone_book)
int main(int argc, char **argv)
{
- cmap_str phone_book = c_make(cmap_str, {
+ cmap_str phone_book = c_init(cmap_str, {
{"Lilia Friedman", "(892) 670-4739"},
{"Tariq Beltran", "(489) 600-7575"},
{"Laiba Juarez", "(303) 885-5692"},
diff --git a/misc/examples/unordered_set.c b/misc/examples/hashmaps/unordered_set.c
index 61f9cc1f..dd899d78 100644
--- a/misc/examples/unordered_set.c
+++ b/misc/examples/hashmaps/unordered_set.c
@@ -1,10 +1,11 @@
// https://iq.opengenus.org/containers-cpp-stl/
// C program to demonstrate various function of stc cset
+#define i_implement
#include <stc/cstr.h>
#define i_key_str
#include <stc/cset.h>
-int main()
+int main(void)
{
// declaring set for storing string data-type
cset_str stringSet = {0};
diff --git a/misc/examples/vikings.c b/misc/examples/hashmaps/vikings.c
index abb909c3..cef17a04 100644
--- a/misc/examples/vikings.c
+++ b/misc/examples/hashmaps/vikings.c
@@ -1,3 +1,4 @@
+#define i_implement
#include <stc/cstr.h>
typedef struct Viking {
@@ -36,19 +37,19 @@ static inline RViking Viking_toraw(const Viking* vp) {
#define i_rawclass RViking // lookup type
#define i_keyfrom Viking_from
#define i_opt c_no_clone
-#define i_hash(rp) cstrhash(rp->name) ^ cstrhash(rp->country)
+#define i_hash(rp) stc_strhash(rp->name) ^ stc_strhash(rp->country)
#define i_val int // mapped type
#include <stc/cmap.h>
-int main()
+int main(void)
{
Vikings vikings = {0};
- Vikings_emplace(&vikings, (RViking){"Einar", "Norway"}, 20);
- Vikings_emplace(&vikings, (RViking){"Olaf", "Denmark"}, 24);
- Vikings_emplace(&vikings, (RViking){"Harald", "Iceland"}, 12);
- Vikings_emplace(&vikings, (RViking){"Björn", "Sweden"}, 10);
+ Vikings_emplace(&vikings, c_LITERAL(RViking){"Einar", "Norway"}, 20);
+ Vikings_emplace(&vikings, c_LITERAL(RViking){"Olaf", "Denmark"}, 24);
+ Vikings_emplace(&vikings, c_LITERAL(RViking){"Harald", "Iceland"}, 12);
+ Vikings_emplace(&vikings, c_LITERAL(RViking){"Björn", "Sweden"}, 10);
- Vikings_value* v = Vikings_get_mut(&vikings, (RViking){"Einar", "Norway"});
+ Vikings_value* v = Vikings_get_mut(&vikings, c_LITERAL(RViking){"Einar", "Norway"});
v->second += 3; // add 3 hp points to Einar
c_forpair (vk, hp, Vikings, vikings) {
diff --git a/misc/examples/intrusive.c b/misc/examples/linkedlists/intrusive.c
index 0d503575..edb072c7 100644
--- a/misc/examples/intrusive.c
+++ b/misc/examples/linkedlists/intrusive.c
@@ -3,8 +3,9 @@
#include <stdio.h>
#define i_type List
-#define i_val int
-#include <stc/clist.h>
+#define i_key int
+#define i_use_cmp
+#include <stc/clist.h>
void printList(List list) {
printf("list:");
@@ -13,10 +14,10 @@ void printList(List list) {
puts("");
}
-int main() {
+int main(void) {
List list = {0};
c_forlist (i, int, {6, 9, 3, 1, 7, 4, 5, 2, 8})
- List_push_back_node(&list, c_new(List_node, {0, *i.ref}));
+ List_push_back_node(&list, c_new(List_node, {.value=*i.ref}));
printList(list);
diff --git a/misc/examples/list.c b/misc/examples/linkedlists/list.c
index 363d7fec..e83dc6b2 100644
--- a/misc/examples/list.c
+++ b/misc/examples/linkedlists/list.c
@@ -1,20 +1,21 @@
#include <stdio.h>
#include <time.h>
-#include <stc/algo/filter.h>
+#include <stc/algorithm.h>
#include <stc/crand.h>
#define i_type DList
-#define i_val double
+#define i_key double
+#define i_use_cmp
#include <stc/clist.h>
-int main() {
+int main(void) {
const int n = 3000000;
DList list = {0};
- crand_t rng = crand_init(1234567);
+ csrand(1234567);
int m = 0;
c_forrange (n)
- DList_push_back(&list, crand_f64(&rng)*n + 100), ++m;
+ DList_push_back(&list, crandf()*n + 100), ++m;
double sum = 0.0;
printf("sumarize %d:\n", m);
@@ -34,7 +35,7 @@ int main() {
puts("");
DList_drop(&list);
- list = c_make(DList, {10, 20, 30, 40, 30, 50});
+ list = c_init(DList, {10, 20, 30, 40, 30, 50});
const double* v = DList_get(&list, 30);
printf("found: %f\n", *v);
diff --git a/misc/examples/list_erase.c b/misc/examples/linkedlists/list_erase.c
index 0201c2d9..211c5a5d 100644
--- a/misc/examples/list_erase.c
+++ b/misc/examples/linkedlists/list_erase.c
@@ -2,12 +2,12 @@
#include <stdio.h>
#define i_type IList
-#define i_val int
+#define i_key int
#include <stc/clist.h>
-int main ()
+int main(void)
{
- IList L = c_make(IList, {10, 20, 30, 40, 50});
+ IList L = c_init(IList, {10, 20, 30, 40, 50});
c_foreach (x, IList, L)
printf("%d ", *x.ref);
diff --git a/misc/examples/list_splice.c b/misc/examples/linkedlists/list_splice.c
index baebca29..f1fd6e1f 100644
--- a/misc/examples/list_splice.c
+++ b/misc/examples/linkedlists/list_splice.c
@@ -1,8 +1,7 @@
#include <stdio.h>
-#define i_val int
+#define i_key int
#define i_tag i
-#define i_extern // define _clist_mergesort() once
#include <stc/clist.h>
void print_ilist(const char* s, clist_i list)
@@ -14,10 +13,10 @@ void print_ilist(const char* s, clist_i list)
puts("");
}
-int main ()
+int main(void)
{
- clist_i list1 = c_make(clist_i, {1, 2, 3, 4, 5});
- clist_i list2 = c_make(clist_i, {10, 20, 30, 40, 50});
+ clist_i list1 = c_init(clist_i, {1, 2, 3, 4, 5});
+ clist_i list2 = c_init(clist_i, {10, 20, 30, 40, 50});
print_ilist("list1:", list1);
print_ilist("list2:", list2);
diff --git a/misc/examples/linkedlists/new_list.c b/misc/examples/linkedlists/new_list.c
new file mode 100644
index 00000000..7518929a
--- /dev/null
+++ b/misc/examples/linkedlists/new_list.c
@@ -0,0 +1,70 @@
+#include <stdio.h>
+#include <stc/forward.h>
+
+forward_clist(clist_i32, int);
+forward_clist(clist_pnt, struct Point);
+
+typedef struct {
+ clist_i32 intlist;
+ clist_pnt pntlist;
+} MyStruct;
+
+#define i_key int
+#define i_tag i32
+#define i_is_forward
+#include <stc/clist.h>
+
+typedef struct Point { int x, y; } Point;
+int point_cmp(const Point* a, const Point* b) {
+ int c = a->x - b->x;
+ return c ? c : a->y - b->y;
+}
+
+#define i_key Point
+#define i_cmp point_cmp
+#define i_is_forward
+#define i_tag pnt
+#include <stc/clist.h>
+
+#define i_key float
+#define i_use_cmp // use < and == operators for comparison
+#include <stc/clist.h>
+
+void MyStruct_drop(MyStruct* s);
+#define i_type MyList
+#define i_key MyStruct
+#define i_keydrop MyStruct_drop // define drop function
+#define i_no_clone // must explicitely exclude or define cloning support because of drop.
+#include <stc/clist.h>
+
+void MyStruct_drop(MyStruct* s) {
+ clist_i32_drop(&s->intlist);
+ clist_pnt_drop(&s->pntlist);
+}
+
+
+int main(void)
+{
+ MyStruct my = {0};
+ clist_i32_push_back(&my.intlist, 123);
+ clist_pnt_push_back(&my.pntlist, c_LITERAL(Point){123, 456});
+ MyStruct_drop(&my);
+
+ clist_pnt plist = c_init(clist_pnt, {{42, 14}, {32, 94}, {62, 81}});
+ clist_pnt_sort(&plist);
+
+ c_foreach (i, clist_pnt, plist)
+ printf(" (%d %d)", i.ref->x, i.ref->y);
+ puts("");
+ clist_pnt_drop(&plist);
+
+
+ clist_float flist = c_init(clist_float, {123.3f, 321.2f, -32.2f, 78.2f});
+ clist_float_sort(&flist);
+
+ c_foreach (i, clist_float, flist)
+ printf(" %g", (double)*i.ref);
+
+ puts("");
+ clist_float_drop(&flist);
+}
diff --git a/misc/examples/make.sh b/misc/examples/make.sh
index 0297e5a1..b362f275 100755
--- a/misc/examples/make.sh
+++ b/misc/examples/make.sh
@@ -1,20 +1,19 @@
#!/bin/sh
if [ "$(uname)" = 'Linux' ]; then
- sanitize='-fsanitize=address'
+ sanitize='-fsanitize=address -fsanitize=undefined -fsanitize-trap'
clibs='-lm' # -pthread
oflag='-o '
fi
-cc=gcc; cflags="-s -O3 -std=c99 -Wconversion -Wpedantic -Wall -Wsign-compare -Wwrite-strings"
-#cc=gcc; cflags="-g -std=c99 -Werror -Wfatal-errors -Wpedantic -Wall $sanitize"
-#cc=tcc; cflags="-Wall -std=c99"
-#cc=clang; cflags="-s -O2 -std=c99 -Werror -Wfatal-errors -Wpedantic -Wall -Wno-unused-function -Wsign-compare -Wwrite-strings"
-#cc=gcc; cflags="-x c++ -s -O2 -Wall -std=c++20"
-#cc=g++; cflags="-x c++ -s -O2 -Wall"
-#cc=cl; cflags="-O2 -nologo -W3 -MD"
-#cc=cl; cflags="-nologo -TP"
-#cc=cl; cflags="-nologo -std:c11"
+cc=gcc; cflags="-std=c99 -s -O3 -Wall -Wextra -Wpedantic -Wconversion -Wwrite-strings -Wdouble-promotion -Wno-unused-parameter -Wno-maybe-uninitialized -Wno-implicit-fallthrough -Wno-missing-field-initializers"
+#cc=gcc; cflags="-std=c99 -g -Werror -Wfatal-errors -Wpedantic -Wall $sanitize"
+#cc=tcc; cflags="-std=c99 -Wall"
+#cc=clang; cflags="-std=c99 -s -O3 -Wall -Wextra -Wpedantic -Wconversion -Wwrite-strings -Wdouble-promotion -Wno-unused-parameter -Wno-unused-function -Wno-implicit-fallthrough -Wno-missing-field-initializers"
+#cc=gcc; cflags="-x c++ -std=c++20 -O2 -s -Wall"
+#cc=cl; cflags="-nologo -O2 -MD -W3 -wd4003"
+#cc=cl; cflags="-nologo -TP -std:c++20 -wd4003"
+#cc=cl; cflags="-nologo -std:c11 -wd4003"
if [ "$cc" = "cl" ]; then
oflag='/Fe:'
@@ -38,18 +37,20 @@ else
fi
if [ $run = 0 ] ; then
- for i in *.c ; do
- echo $comp -I../../include $i $clibs $oflag$(basename $i .c).exe
- $comp -I../../include $i $clibs $oflag$(basename $i .c).exe
+ for i in */*.c ; do
+ out=$(basename $i .c).exe
+ #out=$(dirname $i)/$(basename $i .c).exe
+ echo $comp -I../../include $i $clibs $oflag$out
+ $comp -I../../include $i $clibs $oflag$out
done
else
- for i in *.c ; do
+ for i in */*.c ; do
echo $comp -I../../include $i $clibs
$comp -I../../include $i $clibs
- if [ -f $(basename -s .c $i).exe ]; then ./$(basename -s .c $i).exe; fi
- if [ -f ./a.exe ]; then ./a.exe; fi
- if [ -f ./a.out ]; then ./a.out; fi
+ out=$(basename $i .c).exe
+ #out=$(dirname $i)/$(basename $i .c).exe
+ if [ -f $out ]; then ./$out; fi
done
fi
-rm -f a.out *.o *.obj # *.exe
+#rm -f a.out *.o *.obj # *.exe
diff --git a/misc/examples/astar.c b/misc/examples/mixed/astar.c
index 7dd12d50..d15a9ed7 100644
--- a/misc/examples/astar.c
+++ b/misc/examples/mixed/astar.c
@@ -4,6 +4,7 @@
// This is a reimplementation of the CTL example to STC:
// https://github.com/glouw/ctl/blob/master/examples/astar.c
// https://www.redblobgames.com/pathfinding/a-star/introduction.html
+#define i_implement
#include <stc/cstr.h>
#include <stdio.h>
@@ -19,7 +20,7 @@ point;
point
point_init(int x, int y, int width)
{
- return (point) { x, y, 0, width };
+ return c_LITERAL(point){ x, y, 0, width };
}
int
@@ -55,12 +56,11 @@ point_key_cmp(const point* a, const point* b)
return (i == j) ? 0 : (i < j) ? -1 : 1;
}
-#define i_val point
+#define i_key point
#define i_cmp point_cmp_priority
#include <stc/cpque.h>
-#define i_val point
-#define i_opt c_no_cmp
+#define i_key point
#include <stc/cdeq.h>
#define i_key point
diff --git a/misc/examples/complex.c b/misc/examples/mixed/complex.c
index 7dde981d..9fcbc417 100644
--- a/misc/examples/complex.c
+++ b/misc/examples/mixed/complex.c
@@ -5,17 +5,15 @@
// using StackList = std::stack<FloatStack>;
// using ListMap = std::unordered_map<int, std::forward_list<StackList>>;
// using MapMap = std::unordered_map<std::string, ListMap>;
-
+#define i_implement
#include <stc/cstr.h>
-
#define i_type FloatStack
-#define i_val float
+#define i_key float
#include <stc/cstack.h>
#define i_type StackList
-#define i_valclass FloatStack // "class" picks up _clone, _drop
-#define i_opt c_no_cmp // no FloatStack_cmp()
+#define i_keyclass FloatStack // "class" picks up _clone, _drop, _cmp
#include <stc/clist.h>
#define i_type ListMap
@@ -29,7 +27,7 @@
#include <stc/cmap.h>
-int main()
+int main(void)
{
MapMap mmap = {0};
@@ -44,7 +42,7 @@ int main()
const ListMap* lmap_p = MapMap_at(&mmap, "first");
const StackList* list_p = ListMap_at(lmap_p, 42);
const FloatStack* stack_p = StackList_back(list_p);
- printf("value is: %f\n", *FloatStack_at(stack_p, 3)); // pi
+ printf("value is: %f\n", (double)*FloatStack_at(stack_p, 3)); // pi
MapMap_drop(&mmap);
}
diff --git a/misc/examples/convert.c b/misc/examples/mixed/convert.c
index 0f09e830..fa64560e 100644
--- a/misc/examples/convert.c
+++ b/misc/examples/mixed/convert.c
@@ -1,17 +1,17 @@
+#define i_implement
#include <stc/cstr.h>
#define i_key_str
#define i_val_str
#include <stc/cmap.h>
-#define i_val_str
+#define i_key_str
#include <stc/cvec.h>
-#define i_val_str
-#define i_extern // define _clist_mergesort() once
+#define i_key_str
#include <stc/clist.h>
-int main()
+int main(void)
{
cmap_str map, mclone;
cvec_str keys = {0}, values = {0};
@@ -24,7 +24,7 @@ int main()
cvec_str_drop(&values),
clist_str_drop(&list)
){
- map = c_make(cmap_str, {
+ map = c_init(cmap_str, {
{"green", "#00ff00"},
{"blue", "#0000ff"},
{"yellow", "#ffff00"},
diff --git a/misc/examples/demos.c b/misc/examples/mixed/demos.c
index de92e378..43c9a7ae 100644
--- a/misc/examples/demos.c
+++ b/misc/examples/mixed/demos.c
@@ -1,6 +1,7 @@
+#define i_implement
#include <stc/cstr.h>
-void stringdemo1()
+void stringdemo1(void)
{
cstr cs = cstr_lit("one-nine-three-seven-five");
printf("%s.\n", cstr_str(&cs));
@@ -27,34 +28,35 @@ void stringdemo1()
cstr_drop(&cs);
}
-#define i_val int64_t
+#define i_key long long
#define i_tag ix
#include <stc/cvec.h>
-void vectordemo1()
+void vectordemo1(void)
{
cvec_ix bignums = cvec_ix_with_capacity(100);
cvec_ix_reserve(&bignums, 100);
for (int i = 10; i <= 100; i += 10)
cvec_ix_push(&bignums, i * i);
- printf("erase - %d: %" PRIu64 "\n", 3, bignums.data[3]);
+ printf("erase - %d: %lld\n", 3, bignums.data[3]);
cvec_ix_erase_n(&bignums, 3, 1); // erase index 3
cvec_ix_pop(&bignums); // erase the last
cvec_ix_erase_n(&bignums, 0, 1); // erase the first
for (int i = 0; i < cvec_ix_size(&bignums); ++i) {
- printf("%d: %" PRIu64 "\n", i, bignums.data[i]);
+ printf("%d: %lld\n", i, bignums.data[i]);
}
cvec_ix_drop(&bignums);
}
-#define i_val_str
+#define i_key_str
+#define i_use_cmp
#include <stc/cvec.h>
-void vectordemo2()
+void vectordemo2(void)
{
cvec_str names = {0};
cvec_str_emplace_back(&names, "Mary");
@@ -71,11 +73,12 @@ void vectordemo2()
cvec_str_drop(&names);
}
-#define i_val int
+#define i_key int
#define i_tag ix
+#define i_use_cmp
#include <stc/clist.h>
-void listdemo1()
+void listdemo1(void)
{
clist_ix nums = {0}, nums2 = {0};
for (int i = 0; i < 10; ++i)
@@ -107,7 +110,7 @@ void listdemo1()
#define i_tag i
#include <stc/cset.h>
-void setdemo1()
+void setdemo1(void)
{
cset_i nums = {0};
cset_i_insert(&nums, 8);
@@ -123,7 +126,7 @@ void setdemo1()
#define i_tag ii
#include <stc/cmap.h>
-void mapdemo1()
+void mapdemo1(void)
{
cmap_ii nums = {0};
cmap_ii_insert(&nums, 8, 64);
@@ -137,7 +140,7 @@ void mapdemo1()
#define i_tag si
#include <stc/cmap.h>
-void mapdemo2()
+void mapdemo2(void)
{
cmap_si nums = {0};
cmap_si_emplace_or_assign(&nums, "Hello", 64);
@@ -159,7 +162,7 @@ void mapdemo2()
#define i_val_str
#include <stc/cmap.h>
-void mapdemo3()
+void mapdemo3(void)
{
cmap_str table = {0};
cmap_str_emplace(&table, "Map", "test");
@@ -179,7 +182,7 @@ void mapdemo3()
cmap_str_drop(&table); // frees key and value cstrs, and hash table.
}
-int main()
+int main(void)
{
printf("\nSTRINGDEMO1\n"); stringdemo1();
printf("\nVECTORDEMO1\n"); vectordemo1();
diff --git a/misc/examples/inits.c b/misc/examples/mixed/inits.c
index 81bcdd3e..53a49f1f 100644
--- a/misc/examples/inits.c
+++ b/misc/examples/mixed/inits.c
@@ -1,3 +1,4 @@
+#define i_implement
#include <stc/cstr.h>
#define i_key int
@@ -17,18 +18,17 @@ inline static int ipair_cmp(const ipair_t* a, const ipair_t* b) {
}
-#define i_val ipair_t
+#define i_key ipair_t
#define i_cmp ipair_cmp
#define i_tag ip
#include <stc/cvec.h>
-#define i_val ipair_t
+#define i_key ipair_t
#define i_cmp ipair_cmp
#define i_tag ip
-#define i_extern // define _clist_mergesort() once
#include <stc/clist.h>
-#define i_val float
+#define i_key float
#define i_tag f
#include <stc/cpque.h>
@@ -45,7 +45,7 @@ int main(void)
puts("\npop and show high priorites first:");
while (! cpque_f_empty(&floats)) {
- printf("%.1f ", *cpque_f_top(&floats));
+ printf("%.1f ", (double)*cpque_f_top(&floats));
cpque_f_pop(&floats);
}
puts("\n");
@@ -66,7 +66,7 @@ int main(void)
// CMAP CNT
- cmap_cnt countries = c_make(cmap_cnt, {
+ cmap_cnt countries = c_init(cmap_cnt, {
{"Norway", 100},
{"Denmark", 50},
{"Iceland", 10},
@@ -88,7 +88,7 @@ int main(void)
// CVEC PAIR
- cvec_ip pairs1 = c_make(cvec_ip, {{5, 6}, {3, 4}, {1, 2}, {7, 8}});
+ cvec_ip pairs1 = c_init(cvec_ip, {{5, 6}, {3, 4}, {1, 2}, {7, 8}});
cvec_ip_sort(&pairs1);
c_foreach (i, cvec_ip, pairs1)
@@ -98,7 +98,7 @@ int main(void)
// CLIST PAIR
- clist_ip pairs2 = c_make(clist_ip, {{5, 6}, {3, 4}, {1, 2}, {7, 8}});
+ clist_ip pairs2 = c_init(clist_ip, {{5, 6}, {3, 4}, {1, 2}, {7, 8}});
clist_ip_sort(&pairs2);
c_foreach (i, clist_ip, pairs2)
diff --git a/misc/examples/read.c b/misc/examples/mixed/read.c
index 4efdcfeb..de04fd31 100644
--- a/misc/examples/read.c
+++ b/misc/examples/mixed/read.c
@@ -1,19 +1,21 @@
+#define i_implement
#include <stc/cstr.h>
-#define i_val_str
+#include <stc/algo/raii.h>
+#define i_key_str
#include <stc/cvec.h>
#include <errno.h>
cvec_str read_file(const char* name)
{
- cvec_str vec = cvec_str_init();
+ cvec_str vec = {0};
c_with (FILE* f = fopen(name, "r"), fclose(f))
- c_with (cstr line = cstr_NULL, cstr_drop(&line))
+ c_with (cstr line = {0}, cstr_drop(&line))
while (cstr_getline(&line, f))
cvec_str_push(&vec, cstr_clone(line));
return vec;
}
-int main()
+int main(void)
{
int n = 0;
c_with (cvec_str vec = read_file(__FILE__), cvec_str_drop(&vec))
diff --git a/misc/examples/multidim.c b/misc/examples/multidim.c
deleted file mode 100644
index 3980e6d8..00000000
--- a/misc/examples/multidim.c
+++ /dev/null
@@ -1,68 +0,0 @@
-// Example based on https://en.cppreference.com/w/cpp/container/mdspan
-#define i_val int
-#include <stc/cstack.h>
-#include <stc/cspan.h>
-#include <stdio.h>
-
-using_cspan3(ispan, int);
-
-int main()
-{
- cstack_int v = c_make(cstack_int, {1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24});
-
- // View data as contiguous memory representing 24 ints
- ispan ms1 = cspan_from(&v);
-
- // View the same data as a 3D array 2 x 3 x 4
- ispan3 ms3 = cspan_md(v.data, 2, 3, 4);
-
- puts("ms3:");
- for (int i=0; i != ms3.shape[0]; i++) {
- for (int j=0; j != ms3.shape[1]; j++) {
- for (int k=0; k != ms3.shape[2]; k++) {
- printf(" %2d", *cspan_at(&ms3, i, j, k));
- }
- puts("");
- }
- puts("");
- }
- puts("ss3 = ms3[:, 1:3, 1:3]");
- ispan3 ss3 = ms3;
- //cspan_slice(&ss3, {c_ALL}, {1,3}, {1,3});
- ss3 = cspan_slice(ispan3, &ms3, {c_ALL}, {1,3}, {1,3});
-
- for (int i=0; i != ss3.shape[0]; i++) {
- for (int j=0; j != ss3.shape[1]; j++) {
- for (int k=0; k != ss3.shape[2]; k++) {
- printf(" %2d", *cspan_at(&ss3, i, j, k));
- }
- puts("");
- }
- puts("");
- }
-
- puts("Iterate ss3 flat:");
- c_foreach (i, ispan3, ss3)
- printf(" %d", *i.ref);
- puts("");
-
- ispan2 ms2 = cspan_submd3(&ms3, 0);
-
- // write data using 2D view
- for (int i=0; i != ms2.shape[0]; i++)
- for (int j=0; j != ms2.shape[1]; j++)
- *cspan_at(&ms2, i, j) = i*1000 + j;
-
- puts("\nview data as 1D view:");
- for (int i=0; i != cspan_size(&ms1); i++)
- printf(" %d", *cspan_at(&ms1, i));
- puts("");
-
- puts("iterate subspan ms3[1]:");
- ispan2 sub = cspan_submd3(&ms3, 1);
- c_foreach (i, ispan2, sub)
- printf(" %d", *i.ref);
- puts("");
-
- cstack_int_drop(&v);
-}
diff --git a/misc/examples/new_list.c b/misc/examples/new_list.c
deleted file mode 100644
index 8b291d34..00000000
--- a/misc/examples/new_list.c
+++ /dev/null
@@ -1,68 +0,0 @@
-#include <stdio.h>
-#include <stc/forward.h>
-
-forward_clist(clist_i32, int);
-forward_clist(clist_pnt, struct Point);
-
-typedef struct {
- clist_i32 intlst;
- clist_pnt pntlst;
-} MyStruct;
-
-#define i_val int
-#define i_tag i32
-#define i_is_forward
-#include <stc/clist.h>
-
-typedef struct Point { int x, y; } Point;
-int point_cmp(const Point* a, const Point* b) {
- int c = a->x - b->x;
- return c ? c : a->y - b->y;
-}
-
-#define i_val Point
-#define i_cmp point_cmp
-#define i_is_forward
-#define i_tag pnt
-#include <stc/clist.h>
-
-#define i_val float
-#include <stc/clist.h>
-
-void MyStruct_drop(MyStruct* s);
-#define i_type MyList
-#define i_valclass MyStruct // i_valclass uses MyStruct_drop
-#define i_opt c_no_clone|c_no_cmp
-#include <stc/clist.h>
-
-void MyStruct_drop(MyStruct* s) {
- clist_i32_drop(&s->intlst);
- clist_pnt_drop(&s->pntlst);
-}
-
-
-int main()
-{
- MyStruct my = {0};
- clist_i32_push_back(&my.intlst, 123);
- clist_pnt_push_back(&my.pntlst, (Point){123, 456});
- MyStruct_drop(&my);
-
- clist_pnt plst = c_make(clist_pnt, {{42, 14}, {32, 94}, {62, 81}});
- clist_pnt_sort(&plst);
-
- c_foreach (i, clist_pnt, plst)
- printf(" (%d %d)", i.ref->x, i.ref->y);
- puts("");
- clist_pnt_drop(&plst);
-
-
- clist_float flst = c_make(clist_float, {123.3f, 321.2f, -32.2f, 78.2f});
- clist_float_sort(&flst);
-
- c_foreach (i, clist_float, flst)
- printf(" %g", *i.ref);
-
- puts("");
- clist_float_drop(&flst);
-}
diff --git a/misc/examples/printspan.c b/misc/examples/printspan.c
deleted file mode 100644
index 7459ac77..00000000
--- a/misc/examples/printspan.c
+++ /dev/null
@@ -1,57 +0,0 @@
-// printspan.c
-
-#include <stdio.h>
-#include <stc/cstr.h>
-#define i_val int
-#include <stc/cvec.h>
-#define i_val int
-#include <stc/cstack.h>
-#define i_val int
-#include <stc/cdeq.h>
-#define i_val_str
-#include <stc/csset.h>
-#include <stc/cspan.h>
-
-using_cspan(intspan, int, 1);
-
-void printMe(intspan container) {
- printf("%d:", (int)cspan_size(&container));
- c_foreach (e, intspan, container)
- printf(" %d", *e.ref);
- puts("");
-}
-
-int main()
-{
- intspan sp1 = cspan_make(intspan, {1, 2});
- printMe( sp1 );
-
- printMe( c_make(intspan, {1, 2, 3}) );
-
- int arr[] = {1, 2, 3, 4, 5, 6};
- intspan sp2 = cspan_from_array(arr);
- printMe( (intspan)cspan_subspan(&sp2, 1, 4) );
-
- cvec_int vec = c_make(cvec_int, {1, 2, 3, 4, 5});
- printMe( (intspan)cspan_from(&vec) );
-
- printMe( sp2 );
-
- cstack_int stk = c_make(cstack_int, {1, 2, 3, 4, 5, 6, 7});
- printMe( (intspan)cspan_from(&stk) );
-
- cdeq_int deq = c_make(cdeq_int, {1, 2, 3, 4, 5, 6, 7, 8});
- printMe( (intspan)cspan_from(&deq) );
-
- csset_str set = c_make(csset_str, {"5", "7", "4", "3", "8", "2", "1", "9", "6"});
- printf("%d:", (int)csset_str_size(&set));
- c_foreach (e, csset_str, set)
- printf(" %s", cstr_str(e.ref));
- puts("");
-
- // cleanup
- cvec_int_drop(&vec);
- cstack_int_drop(&stk);
- cdeq_int_drop(&deq);
- csset_str_drop(&set);
-}
diff --git a/misc/examples/functor.c b/misc/examples/priorityqueues/functor.c
index c0a4f8e8..e3bde1dd 100644
--- a/misc/examples/functor.c
+++ b/misc/examples/priorityqueues/functor.c
@@ -1,22 +1,22 @@
// Implements c++ example: https://en.cppreference.com/w/cpp/container/priority_queue
// Example of per-instance less-function on a single priority queue type
//
-// Note: i_less: has self for cpque types only
-// i_cmp: has self for csmap and csset types only
-// i_hash/i_eq: has self for cmap and cset types only
#include <stdio.h>
#define i_type IPQue
-#define i_val int
-#define i_extend bool (*less)(const int*, const int*);
-#define i_less(x, y) c_getcon(self)->less(x, y)
-#define i_con cpque
+#define i_base cpque
+#define i_key int
+#define i_extend bool(*less)(const int*, const int*);
+#define i_less(x, y) c_extend()->less(x, y)
+// Note: i_less: c_extend() accessible for cpque types
+// i_cmp: c_extend() accessible for csmap and csset types
+// i_hash/i_eq: c_extend() accessible for cmap and cset types
#include <stc/extend.h>
void print_queue(const char* name, IPQue_ext q) {
// NB: make a clone because there is no way to traverse
- // priority_queue's content without erasing the queue.
+ // priority queue's content without erasing the queue.
IPQue_ext copy = {q.less, IPQue_clone(q.get)};
for (printf("%s: \t", name); !IPQue_empty(&copy.get); IPQue_pop(&copy.get))
@@ -30,28 +30,27 @@ static bool int_less(const int* x, const int* y) { return *x < *y; }
static bool int_greater(const int* x, const int* y) { return *x > *y; }
static bool int_lambda(const int* x, const int* y) { return (*x ^ 1) < (*y ^ 1); }
-int main()
+int main(void)
{
const int data[] = {1,8,5,6,3,4,0,9,7,2}, n = c_arraylen(data);
printf("data: \t");
- c_forrange (i, n)
- printf("%d ", data[i]);
+ c_forrange (i, n) printf("%d ", data[i]);
puts("");
- IPQue_ext q1 = {int_less}; // Max priority queue
- IPQue_ext minq1 = {int_greater}; // Min priority queue
- IPQue_ext q5 = {int_lambda}; // Using lambda to compare elements.
- c_forrange (i, n)
- IPQue_push(&q1.get, data[i]);
+ // Max priority queue
+ IPQue_ext q1 = {.less=int_less};
+ IPQue_put_n(&q1.get, data, n);
print_queue("q1", q1);
- c_forrange (i, n)
- IPQue_push(&minq1.get, data[i]);
+ // Min priority queue
+ IPQue_ext minq1 = {.less=int_greater};
+ IPQue_put_n(&minq1.get, data, n);
print_queue("minq1", minq1);
- c_forrange (i, n)
- IPQue_push(&q5.get, data[i]);
+ // Using lambda to compare elements.
+ IPQue_ext q5 = {.less=int_lambda};
+ IPQue_put_n(&q5.get, data, n);
print_queue("q5", q5);
c_drop(IPQue, &q1.get, &minq1.get, &q5.get);
diff --git a/misc/examples/new_pque.c b/misc/examples/priorityqueues/new_pque.c
index 9147e3f2..16823bb6 100644
--- a/misc/examples/new_pque.c
+++ b/misc/examples/priorityqueues/new_pque.c
@@ -1,16 +1,16 @@
#include <stdio.h>
-struct Point { int x, y; } typedef Point;
+typedef struct Point { int x, y; } Point;
#define i_type PointQ
-#define i_val Point
+#define i_key Point
#define i_less(a, b) a->x < b->x || (a->x == b->x && a->y < b->y)
#include <stc/cpque.h>
-int main()
+int main(void)
{
- PointQ pque = c_make(PointQ, {{23, 80}, {12, 32}, {54, 74}, {12, 62}});
+ PointQ pque = c_init(PointQ, {{23, 80}, {12, 32}, {54, 74}, {12, 62}});
// print
for (; !PointQ_empty(&pque); PointQ_pop(&pque))
{
diff --git a/misc/examples/priority.c b/misc/examples/priorityqueues/priority.c
index 95dd3183..18684e73 100644
--- a/misc/examples/priority.c
+++ b/misc/examples/priorityqueues/priority.c
@@ -3,29 +3,29 @@
#include <time.h>
#include <stc/crand.h>
-#define i_val int64_t
+#define i_key int64_t
#define i_cmp -c_default_cmp // min-heap (increasing values)
#define i_tag i
#include <stc/cpque.h>
-int main() {
+int main(void) {
intptr_t N = 10000000;
crand_t rng = crand_init((uint64_t)time(NULL));
- crand_unif_t dist = crand_unif_init(0, N * 10);
+ crand_uniform_t dist = crand_uniform_init(0, N * 10);
cpque_i heap = {0};
// Push ten million random numbers to priority queue
printf("Push %" c_ZI " numbers\n", N);
c_forrange (N)
- cpque_i_push(&heap, crand_unif(&rng, &dist));
+ cpque_i_push(&heap, crand_uniform(&rng, &dist));
// push some negative numbers too.
c_forlist (i, int, {-231, -32, -873, -4, -343})
cpque_i_push(&heap, *i.ref);
c_forrange (N)
- cpque_i_push(&heap, crand_unif(&rng, &dist));
+ cpque_i_push(&heap, crand_uniform(&rng, &dist));
puts("Extract the hundred smallest.");
c_forrange (100) {
diff --git a/misc/examples/new_queue.c b/misc/examples/queues/new_queue.c
index 916f4dbc..3904c50c 100644
--- a/misc/examples/new_queue.c
+++ b/misc/examples/queues/new_queue.c
@@ -5,37 +5,37 @@
forward_cqueue(cqueue_pnt, struct Point);
-struct Point { int x, y; } typedef Point;
+typedef struct Point { int x, y; } Point;
int point_cmp(const Point* a, const Point* b) {
int c = c_default_cmp(&a->x, &b->x);
return c ? c : c_default_cmp(&a->y, &b->y);
}
-#define i_val Point
+#define i_key Point
#define i_cmp point_cmp
#define i_is_forward
#define i_tag pnt
#include <stc/cqueue.h>
#define i_type IQ
-#define i_val int
+#define i_key int
#include <stc/cqueue.h>
-int main() {
+int main(void) {
int n = 50000000;
crand_t rng = crand_init((uint64_t)time(NULL));
- crand_unif_t dist = crand_unif_init(0, n);
+ crand_uniform_t dist = crand_uniform_init(0, n);
IQ Q = {0};
// Push 50'000'000 random numbers onto the queue.
c_forrange (n)
- IQ_push(&Q, (int)crand_unif(&rng, &dist));
+ IQ_push(&Q, (int)crand_uniform(&rng, &dist));
// Push or pop on the queue 50 million times
printf("befor: size %" c_ZI ", capacity %" c_ZI "\n", IQ_size(&Q), IQ_capacity(&Q));
c_forrange (n) {
- int r = (int)crand_unif(&rng, &dist);
+ int r = (int)crand_uniform(&rng, &dist);
if (r & 3)
IQ_push(&Q, r);
else
diff --git a/misc/examples/queue.c b/misc/examples/queues/queue.c
index 83c18d09..5b1f7606 100644
--- a/misc/examples/queue.c
+++ b/misc/examples/queues/queue.c
@@ -1,26 +1,26 @@
#include <stc/crand.h>
#include <stdio.h>
-#define i_val int
+#define i_key int
#define i_tag i
#include <stc/cqueue.h>
-int main() {
- int n = 100000000;
- crand_unif_t dist;
+int main(void) {
+ int n = 1000000;
+ crand_uniform_t dist;
crand_t rng = crand_init(1234);
- dist = crand_unif_init(0, n);
+ dist = crand_uniform_init(0, n);
cqueue_i queue = {0};
// Push ten million random numbers onto the queue.
c_forrange (n)
- cqueue_i_push(&queue, (int)crand_unif(&rng, &dist));
+ cqueue_i_push(&queue, (int)crand_uniform(&rng, &dist));
// Push or pop on the queue ten million times
printf("%d\n", n);
c_forrange (n) { // forrange uses initial n only.
- int r = (int)crand_unif(&rng, &dist);
+ int r = (int)crand_uniform(&rng, &dist);
if (r & 1)
++n, cqueue_i_push(&queue, r);
else
diff --git a/misc/examples/random.c b/misc/examples/random.c
deleted file mode 100644
index ea9c483e..00000000
--- a/misc/examples/random.c
+++ /dev/null
@@ -1,45 +0,0 @@
-#include <stdio.h>
-#include <time.h>
-#include <stc/crand.h>
-
-int main()
-{
- const size_t N = 1000000000;
- const uint64_t seed = (uint64_t)time(NULL), range = 1000000;
- crand_t rng = crand_init(seed);
-
- int64_t sum;
- clock_t diff, before;
-
- printf("Compare speed of full and unbiased ranged random numbers...\n");
- sum = 0;
- before = clock();
- c_forrange (N) {
- sum += (uint32_t)crand_u64(&rng);
- }
- diff = clock() - before;
- printf("full range\t\t: %f secs, %" c_ZI ", avg: %f\n",
- (float)diff / CLOCKS_PER_SEC, N, (float)sum / (float)N);
-
- crand_unif_t dist1 = crand_unif_init(0, range);
- rng = crand_init(seed);
- sum = 0;
- before = clock();
- c_forrange (N) {
- sum += crand_unif(&rng, &dist1); // unbiased
- }
- diff = clock() - before;
- printf("unbiased 0-%" PRIu64 "\t: %f secs, %" c_ZI ", avg: %f\n",
- range, (float)diff/CLOCKS_PER_SEC, N, (float)sum / (float)N);
-
- sum = 0;
- rng = crand_init(seed);
- before = clock();
- c_forrange (N) {
- sum += (int64_t)(crand_u64(&rng) % (range + 1)); // biased
- }
- diff = clock() - before;
- printf("biased 0-%" PRIu64 " \t: %f secs, %" c_ZI ", avg: %f\n",
- range, (float)diff / CLOCKS_PER_SEC, N, (float)sum / (float)N);
-
-}
diff --git a/misc/examples/rawptr_elements.c b/misc/examples/rawptr_elements.c
deleted file mode 100644
index 01bcdc44..00000000
--- a/misc/examples/rawptr_elements.c
+++ /dev/null
@@ -1,59 +0,0 @@
-#include <stc/ccommon.h>
-#include <stdio.h>
-
-#include <stc/cstr.h>
-
-// Create cmap of cstr => long*
-#define i_type SIPtrMap
-#define i_key_str
-#define i_val long*
-#define i_valraw long
-#define i_valfrom(raw) c_new(long, raw)
-#define i_valto(x) **x
-#define i_valclone(x) c_new(long, *x)
-#define i_valdrop(x) c_free(*x)
-#include <stc/cmap.h>
-
-// Alternatively, using cbox:
-#define i_type IBox
-#define i_val long
-#include <stc/cbox.h> // unique_ptr<long> alike.
-
-// cmap of cstr => IBox
-#define i_type SIBoxMap
-#define i_key_str
-#define i_valboxed IBox // i_valboxed: use properties from IBox automatically
-#include <stc/cmap.h>
-
-int main()
-{
- // These have the same behaviour, except IBox has a get member:
- SIPtrMap map1 = {0};
- SIBoxMap map2 = {0};
-
- printf("\nMap cstr => long*:\n");
- SIPtrMap_insert(&map1, cstr_from("Test1"), c_new(long, 1));
- SIPtrMap_insert(&map1, cstr_from("Test2"), c_new(long, 2));
-
- // Emplace implicitly creates cstr from const char* and an owned long* from long!
- SIPtrMap_emplace(&map1, "Test3", 3);
- SIPtrMap_emplace(&map1, "Test4", 4);
-
- c_forpair (name, number, SIPtrMap, map1)
- printf("%s: %ld\n", cstr_str(_.name), **_.number);
-
- puts("\nMap cstr => IBox:");
- SIBoxMap_insert(&map2, cstr_from("Test1"), IBox_make(1));
- SIBoxMap_insert(&map2, cstr_from("Test2"), IBox_make(2));
-
- // Emplace implicitly creates cstr from const char* and IBox from long!
- SIBoxMap_emplace(&map2, "Test3", 3);
- SIBoxMap_emplace(&map2, "Test4", 4);
-
- c_forpair (name, number, SIBoxMap, map2)
- printf("%s: %ld\n", cstr_str(_.name), *_.number->get);
- puts("");
-
- SIPtrMap_drop(&map1);
- SIBoxMap_drop(&map2);
-}
diff --git a/misc/examples/regex1.c b/misc/examples/regularexpressions/regex1.c
index 4a56b8ac..d8032358 100644
--- a/misc/examples/regex1.c
+++ b/misc/examples/regularexpressions/regex1.c
@@ -1,4 +1,4 @@
-#define i_extern
+#define i_import
#include <stc/cregex.h>
int main(int argc, char* argv[])
diff --git a/misc/examples/regex2.c b/misc/examples/regularexpressions/regex2.c
index 3133f7c2..a798b1a1 100644
--- a/misc/examples/regex2.c
+++ b/misc/examples/regularexpressions/regex2.c
@@ -1,7 +1,7 @@
-#define i_extern
+#define i_import
#include <stc/cregex.h>
-int main()
+int main(void)
{
struct { const char *pattern, *input; } s[] = {
{"(\\d\\d\\d\\d)[-_](1[0-2]|0[1-9])[-_](3[01]|[12][0-9]|0[1-9])",
@@ -26,7 +26,7 @@ int main()
printf("\ninput: %s\n", s[i].input);
c_formatch (j, &re, s[i].input) {
- c_forrange (k, cregex_captures(&re))
+ c_forrange (k, cregex_captures(&re) + 1)
printf(" submatch %lld: %.*s\n", k, c_SV(j.match[k]));
}
}
diff --git a/misc/examples/regex_match.c b/misc/examples/regularexpressions/regex_match.c
index def0ae7a..9106ffbd 100644
--- a/misc/examples/regex_match.c
+++ b/misc/examples/regularexpressions/regex_match.c
@@ -1,11 +1,12 @@
-#define i_extern
+#define i_import
#include <stc/cregex.h>
+#define i_implement
#include <stc/csview.h>
-#define i_val float
+#define i_key float
#include <stc/cstack.h>
-int main()
+int main(void)
{
// Lets find the first sequence of digits in a string
const char *str = "Hello numeric world, there are 24 hours in a day, 3600 seconds in an hour."
@@ -21,13 +22,13 @@ int main()
// extract and convert all numbers in str to floats
c_formatch (i, &re, str)
- cstack_float_push(&vec, (float)atof(i.match[0].str));
+ cstack_float_push(&vec, (float)atof(i.match[0].buf));
c_foreach (i, cstack_float, vec)
- printf(" %g\n", *i.ref);
+ printf(" %g\n", (double)*i.ref);
// extracts the numbers only to a comma separated string.
- cstr nums = cregex_replace_sv(&re, csview_from(str), " $0,", 0, NULL, CREG_R_STRIP);
+ cstr nums = cregex_replace_sv(&re, csview_from(str), " $0,", 0, NULL, CREG_STRIP);
printf("\n%s\n", cstr_str(&nums));
cstr_drop(&nums);
diff --git a/misc/examples/regex_replace.c b/misc/examples/regularexpressions/regex_replace.c
index d3952f50..087387d7 100644
--- a/misc/examples/regex_replace.c
+++ b/misc/examples/regularexpressions/regex_replace.c
@@ -1,18 +1,18 @@
-#define i_extern
+#define i_import
#include <stc/cregex.h>
#include <stc/csview.h>
bool add_10_years(int i, csview match, cstr* out) {
if (i == 1) { // group 1 matches year
int year;
- sscanf(match.str, "%4d", &year); // scan 4 chars only
+ sscanf(match.buf, "%4d", &year); // scan 4 chars only
cstr_printf(out, "%04d", year + 10);
return true;
}
return false;
}
-int main()
+int main(void)
{
const char* pattern = "\\b(\\d\\d\\d\\d)-(1[0-2]|0[1-9])-(3[01]|[12][0-9]|0[1-9])\\b";
const char* input = "start date: 2015-12-31, end date: 2022-02-28";
@@ -47,7 +47,7 @@ int main()
printf("euros: %s\n", cstr_str(&str));
/* Strip out everything but the matches */
- cstr_take(&str, cregex_replace_sv(&re, csview_from(input), "$3.$2.$1;", 0, NULL, CREG_R_STRIP));
+ cstr_take(&str, cregex_replace_sv(&re, csview_from(input), "$3.$2.$1;", 0, NULL, CREG_STRIP));
printf("strip: %s\n", cstr_str(&str));
/* Wrap all words in ${} */
diff --git a/misc/examples/sidebyside.cpp b/misc/examples/sidebyside.cpp
deleted file mode 100644
index a7c1008c..00000000
--- a/misc/examples/sidebyside.cpp
+++ /dev/null
@@ -1,57 +0,0 @@
-#include <iostream>
-#include <map>
-#include <string>
-#include <stc/cstr.h>
-
-#define i_type IIMap
-#define i_key int
-#define i_val int
-#include <stc/csmap.h>
-
-#define i_type SIMap
-#define i_key_str
-#define i_val int
-#include <stc/cmap.h>
-
-int main() {
- {
- std::map<int, int> hist;
- hist.emplace(12, 100).first->second += 1;
- hist.emplace(13, 100).first->second += 1;
- hist.emplace(12, 100).first->second += 1;
-
- for (auto i: hist)
- std::cout << i.first << ", " << i.second << std::endl;
- std::cout << std::endl;
- }
- {
- IIMap hist = {0};
- IIMap_insert(&hist, 12, 100).ref->second += 1;
- IIMap_insert(&hist, 13, 100).ref->second += 1;
- IIMap_insert(&hist, 12, 100).ref->second += 1;
-
- c_foreach (i, IIMap, hist)
- printf("%d, %d\n", i.ref->first, i.ref->second);
- puts("");
- IIMap_drop(&hist);
- }
- // ===================================================
- {
- std::map<std::string, int> food =
- {{"burger", 5}, {"pizza", 12}, {"steak", 15}};
-
- for (auto i: food)
- std::cout << i.first << ", " << i.second << std::endl;
- std::cout << std::endl;
- }
- {
- SIMap food = {0};
- c_forlist (i, SIMap_raw, {{"burger", 5}, {"pizza", 12}, {"steak", 15}})
- SIMap_emplace(&food, i.ref->first, i.ref->second);
-
- c_foreach (i, SIMap, food)
- printf("%s, %d\n", cstr_str(&i.ref->first), i.ref->second);
- puts("");
- SIMap_drop(&food);
- }
-}
diff --git a/misc/examples/arc_containers.c b/misc/examples/smartpointers/arc_containers.c
index 84ba8dda..79211d2b 100644
--- a/misc/examples/arc_containers.c
+++ b/misc/examples/smartpointers/arc_containers.c
@@ -1,6 +1,6 @@
// Create a stack and a list of shared pointers to maps,
// and demonstrate sharing and cloning of maps.
-#define i_static
+#define i_implement
#include <stc/cstr.h>
#define i_type Map
#define i_key_str // strings
@@ -9,23 +9,21 @@
#include <stc/csmap.h>
#define i_type Arc // (atomic) ref. counted type
-#define i_val Map
-#define i_valdrop(p) (printf("drop Arc:\n"), Map_drop(p))
+#define i_key Map
+#define i_keydrop(p) (printf("drop Arc:\n"), Map_drop(p))
// no need for atomic ref. count in single thread:
-#define i_opt c_no_atomic|c_no_cmp|c_no_clone
+#define i_opt c_no_atomic
#include <stc/carc.h>
#define i_type Stack
-#define i_valboxed Arc // define i_valboxed for carc/cbox value (not i_val)
-#define i_opt c_no_cmp
+#define i_keyboxed Arc // use i_keyboxed for carc/cbox key
#include <stc/cvec.h>
#define i_type List
-#define i_valboxed Arc // as above
-#define i_opt c_no_cmp
+#define i_keyboxed Arc // as above
#include <stc/clist.h>
-int main()
+int main(void)
{
Stack stack = {0};
List list = {0};
diff --git a/misc/examples/arc_demo.c b/misc/examples/smartpointers/arc_demo.c
index 2339adbb..a66d84b0 100644
--- a/misc/examples/arc_demo.c
+++ b/misc/examples/smartpointers/arc_demo.c
@@ -6,27 +6,32 @@ void int_drop(int* x) {
}
// carc implements its own clone method using reference counting,
-// so 'i_valclone' is not required to be defined (ignored).
+// so 'i_keyclone' is not required to be defined (ignored).
#define i_type Arc // set type name to be defined (instead of 'carc_int')
-#define i_val int
-#define i_valdrop int_drop // optional, just to display the elements destroyed
-#define i_no_clone // required because of valdrop
+#define i_key int
+#define i_keydrop int_drop // optional, just to display the elements destroyed
+#define i_use_cmp // use int comparison (x < y, x == y).
#include <stc/carc.h> // Arc
-#define i_keyboxed Arc // note: use i_keyboxed instead of i_key for carc/cbox elements
+#define i_keyboxed Arc // note: use i_keyboxed instead of i_key for carc/cbox elements
#include <stc/csset.h> // csset_Arc (like: std::set<std::shared_ptr<int>>)
-#define i_valboxed Arc // note: as above.
+#define i_keyboxed Arc // note: as above.
+#define i_use_cmp
#include <stc/cvec.h> // cvec_Arc (like: std::vector<std::shared_ptr<int>>)
-int main()
+int main(void)
{
const int years[] = {2021, 2012, 2022, 2015};
cvec_Arc vec = {0};
- c_forrange (i, c_arraylen(years))
- cvec_Arc_push(&vec, Arc_from(years[i]));
+ c_forrange (i, c_arraylen(years)) {
+ cvec_Arc_emplace(&vec, years[i]);
+ // cvec_Arc_push(&vec, Arc_from(years[i])); // alt.
+ }
+
+ cvec_Arc_sort(&vec);
printf("vec:");
c_foreach (i, cvec_Arc, vec)
diff --git a/misc/examples/arcvec_erase.c b/misc/examples/smartpointers/arcvec_erase.c
index 3bf41559..0526b6a0 100644
--- a/misc/examples/arcvec_erase.c
+++ b/misc/examples/smartpointers/arcvec_erase.c
@@ -3,23 +3,25 @@
void show_drop(int* x) { printf("drop: %d\n", *x); }
#define i_type Arc
-#define i_val int
-#define i_valdrop show_drop
-#define i_no_clone // required because of valdrop
+#define i_key int
+#define i_keydrop show_drop
+#define i_use_cmp // enable sort/search for int type
#include <stc/carc.h> // Shared pointer to int
#define i_type Vec
-#define i_valboxed Arc
+#define i_keyboxed Arc
+#define i_use_cmp
#include <stc/cvec.h> // Vec: cvec<Arc>
-int main()
+int main(void)
{
- Vec vec = c_make(Vec, {2012, 1990, 2012, 2019, 2015});
+ Vec vec = c_init(Vec, {2012, 1990, 2012, 2019, 2015});
// clone the second 2012 and push it back.
// note: cloning make sure that vec.data[2] has ref count 2.
- Vec_push(&vec, Arc_clone(vec.data[2]));
+ Vec_push(&vec, Arc_clone(vec.data[2])); // => share vec.data[2]
+ Vec_emplace(&vec, *vec.data[2].get); // => deep-copy vec.data[2]
printf("vec before erase :");
c_foreach (i, Vec, vec)
diff --git a/misc/examples/box.c b/misc/examples/smartpointers/box.c
index 9954883c..5c8018d4 100644
--- a/misc/examples/box.c
+++ b/misc/examples/smartpointers/box.c
@@ -1,10 +1,11 @@
/* cbox: heap allocated boxed type */
+#define i_implement
#include <stc/cstr.h>
typedef struct { cstr name, last; } Person;
Person Person_make(const char* name, const char* last) {
- return (Person){.name = cstr_from(name), .last = cstr_from(last)};
+ return c_LITERAL(Person){.name = cstr_from(name), .last = cstr_from(last)};
}
uint64_t Person_hash(const Person* a) {
@@ -28,14 +29,15 @@ void Person_drop(Person* p) {
}
#define i_type PBox
-#define i_valclass Person // "class" binds _cmp, _clone, _drop functions.
+#define i_keyclass Person // "class" binds _cmp, _clone, _drop functions.
+#define i_use_cmp
#include <stc/cbox.h>
#define i_type Persons
-#define i_valboxed PBox // "arcbox" informs that PBox is a smart pointer.
+#define i_keyboxed PBox // "arcbox" informs that PBox is a smart pointer.
#include <stc/csset.h>
-int main()
+int main(void)
{
Persons vec = {0};
PBox p = PBox_from(Person_make("Laura", "Palmer"));
diff --git a/misc/examples/box2.c b/misc/examples/smartpointers/box2.c
index cba255d2..9b782c74 100644
--- a/misc/examples/box2.c
+++ b/misc/examples/smartpointers/box2.c
@@ -13,27 +13,24 @@ typedef struct {
Point bottom_right;
} Rectangle;
-#define i_val Point
-#define i_no_cmp
+#define i_key Point
#include <stc/cbox.h> // cbox_Point
-#define i_val Rectangle
-#define i_no_cmp
+#define i_key Rectangle
#include <stc/cbox.h> // cbox_Rectangle
// Box in box:
-#define i_valboxed cbox_Point // NB: use i_valboxed when value is a cbox or carc!
#define i_type BoxBoxPoint
-#define i_no_cmp
+#define i_keyboxed cbox_Point // NB: use i_keyboxed when value is a cbox or carc!
#include <stc/cbox.h> // BoxBoxPoint
Point origin(void) {
- return (Point){ .x=1.0, .y=2.0 };
+ return c_LITERAL(Point){ .x=1.0, .y=2.0 };
}
cbox_Point boxed_origin(void) {
// Allocate this point on the heap, and return a pointer to it
- return cbox_Point_make((Point){ .x=1.0, .y=2.0 });
+ return cbox_Point_make(c_LITERAL(Point){ .x=1.0, .y=2.0 });
}
@@ -46,7 +43,7 @@ int main(void) {
};
// Heap allocated rectangle
- cbox_Rectangle boxed_rectangle = cbox_Rectangle_make((Rectangle){
+ cbox_Rectangle boxed_rectangle = cbox_Rectangle_make(c_LITERAL(Rectangle){
.top_left = origin(),
.bottom_right = { .x=3.0, .y=-4.0 }
});
diff --git a/misc/examples/smartpointers/map_box.c b/misc/examples/smartpointers/map_box.c
new file mode 100644
index 00000000..f651b302
--- /dev/null
+++ b/misc/examples/smartpointers/map_box.c
@@ -0,0 +1,34 @@
+#include <stc/ccommon.h>
+#include <stdio.h>
+#define i_implement
+#include <stc/cstr.h>
+
+#define i_type IBox
+#define i_key long
+#include <stc/cbox.h> // unique_ptr<long> alike.
+
+// cmap of cstr => IBox
+#define i_type Boxmap
+#define i_key_str
+#define i_valboxed IBox // i_valboxed: use properties from IBox automatically
+#include <stc/cmap.h>
+
+
+int main(void)
+{
+ Boxmap map = {0};
+
+ puts("Map cstr => IBox:");
+ Boxmap_insert(&map, cstr_from("Test1"), IBox_make(1));
+ Boxmap_insert(&map, cstr_from("Test2"), IBox_make(2));
+
+ // Simpler: emplace() implicitly creates cstr from const char* and IBox from long!
+ Boxmap_emplace(&map, "Test3", 3);
+ Boxmap_emplace(&map, "Test4", 4);
+
+ c_forpair (name, number, Boxmap, map)
+ printf("%s: %ld\n", cstr_str(_.name), *_.number->get);
+ puts("");
+
+ Boxmap_drop(&map);
+}
diff --git a/misc/examples/smartpointers/map_ptr.c b/misc/examples/smartpointers/map_ptr.c
new file mode 100644
index 00000000..453322c5
--- /dev/null
+++ b/misc/examples/smartpointers/map_ptr.c
@@ -0,0 +1,34 @@
+#include <stc/ccommon.h>
+#include <stdio.h>
+#define i_implement
+#include <stc/cstr.h>
+
+// cmap of cstr => long*
+#define i_type Ptrmap
+#define i_key_str
+#define i_val long*
+#define i_valraw long
+#define i_valfrom(raw) c_new(long, raw)
+#define i_valto(x) **x
+#define i_valclone(x) c_new(long, *x)
+#define i_valdrop(x) c_free(*x)
+#include <stc/cmap.h>
+
+int main(void)
+{
+ Ptrmap map = {0};
+
+ puts("Map cstr => long*:");
+ Ptrmap_insert(&map, cstr_from("Test1"), c_new(long, 1));
+ Ptrmap_insert(&map, cstr_from("Test2"), c_new(long, 2));
+
+ // Simple: emplace() implicitly creates cstr from const char* and an owned long* from long!
+ Ptrmap_emplace(&map, "Test3", 3);
+ Ptrmap_emplace(&map, "Test4", 4);
+
+ c_forpair (name, number, Ptrmap, map)
+ printf("%s: %ld\n", cstr_str(_.name), **_.number);
+ puts("");
+
+ Ptrmap_drop(&map);
+}
diff --git a/misc/examples/music_arc.c b/misc/examples/smartpointers/music_arc.c
index 3714e1d5..e9ebbbfe 100644
--- a/misc/examples/music_arc.c
+++ b/misc/examples/smartpointers/music_arc.c
@@ -1,5 +1,6 @@
// shared_ptr-examples.cpp
// based on https://docs.microsoft.com/en-us/cpp/cpp/how-to-create-and-use-shared-ptr-instances?view=msvc-160
+#define i_implement
#include <stc/cstr.h>
typedef struct
@@ -11,8 +12,8 @@ typedef struct
int Song_cmp(const Song* x, const Song* y)
{ return cstr_cmp(&x->title, &y->title); }
-Song Song_make(const char* artist, const char* title)
- { return (Song){cstr_from(artist), cstr_from(title)}; }
+Song Song_init(const char* artist, const char* title)
+ { return c_LITERAL(Song){cstr_from(artist), cstr_from(title)}; }
void Song_drop(Song* s) {
printf("drop: %s\n", cstr_str(&s->title));
@@ -21,21 +22,21 @@ void Song_drop(Song* s) {
// Define the shared pointer:
#define i_type SongArc
-#define i_valclass Song
-#define i_opt c_no_hash // arc require hash fn, disable as we don't need it.
+#define i_keyclass Song
+#define i_opt c_use_cmp|c_no_hash
#include <stc/carc.h>
// ... and a vector of them
#define i_type SongVec
-#define i_valboxed SongArc // use i_valboxed on carc / cbox instead of i_val
-#include <stc/cstack.h>
+#define i_keyboxed SongArc // use i_keyboxed on carc / cbox (instead of i_key)
+#include <stc/cvec.h>
-void example3()
+void example3(void)
{
- SongVec vec1 = c_make(SongVec, {
- Song_make("Bob Dylan", "The Times They Are A Changing"),
- Song_make("Aretha Franklin", "Bridge Over Troubled Water"),
- Song_make("Thalia", "Entre El Mar y Una Estrella")
+ SongVec vec1 = c_init(SongVec, {
+ Song_init("Bob Dylan", "The Times They Are A Changing"),
+ Song_init("Aretha Franklin", "Bridge Over Troubled Water"),
+ Song_init("Thalia", "Entre El Mar y Una Estrella")
});
SongVec vec2 = {0};
@@ -46,8 +47,8 @@ void example3()
// Add a few more to vec2. We can use emplace when creating new entries
// Emplace calls SongArc_from() on the argument to create the Arc:
- SongVec_emplace(&vec2, Song_make("Michael Jackson", "Billie Jean"));
- SongVec_emplace(&vec2, Song_make("Rihanna", "Stay"));
+ SongVec_emplace(&vec2, Song_init("Michael Jackson", "Billie Jean"));
+ SongVec_emplace(&vec2, Song_init("Rihanna", "Stay"));
// We now have two vectors with some shared, some unique entries.
c_forlist (i, SongVec, {vec1, vec2}) {
@@ -60,7 +61,7 @@ void example3()
c_drop(SongVec, &vec1, &vec2);
}
-int main()
+int main(void)
{
example3();
-}
+} \ No newline at end of file
diff --git a/misc/examples/new_sptr.c b/misc/examples/smartpointers/new_sptr.c
index 1b72e4f5..50e28ae2 100644
--- a/misc/examples/new_sptr.c
+++ b/misc/examples/smartpointers/new_sptr.c
@@ -1,3 +1,4 @@
+#define i_implement
#include <stc/cstr.h>
typedef struct { cstr name, last; } Person;
@@ -8,28 +9,28 @@ int Person_cmp(const Person* a, const Person* b);
uint64_t Person_hash(const Person* p);
#define i_type PersonArc
-#define i_valclass Person // "class" ensure Person_drop will be called
-#define i_cmp Person_cmp // enable carc object comparisons (not ptr to obj)
-#define i_hash Person_hash // enable carc object hash (not ptr to obj)
+#define i_keyclass Person // "class" assume _clone, _drop, _cmp, _hash is defined.
+#define i_use_cmp
#include <stc/carc.h>
#define i_type IPtr
-#define i_val int
-#define i_valdrop(x) printf("drop: %d\n", *x)
-#define i_no_clone
+#define i_key int
+#define i_keydrop(x) printf("drop: %d\n", *x)
+#define i_use_cmp
#include <stc/carc.h>
#define i_type IPStack
-#define i_valboxed IPtr
+#define i_keyboxed IPtr
#include <stc/cstack.h>
#define i_type PASet
-#define i_valboxed PersonArc
+#define i_keyboxed PersonArc
#include <stc/cset.h>
Person Person_make(const char* name, const char* last) {
- return (Person){.name = cstr_from(name), .last = cstr_from(last)};
+ Person p = {.name = cstr_from(name), .last = cstr_from(last)};
+ return p;
}
int Person_cmp(const Person* a, const Person* b) {
diff --git a/misc/examples/person_arc.c b/misc/examples/smartpointers/person_arc.c
index 620d311f..11040cd2 100644
--- a/misc/examples/person_arc.c
+++ b/misc/examples/smartpointers/person_arc.c
@@ -1,10 +1,12 @@
/* cbox: heap allocated boxed type */
+#define i_implement
#include <stc/cstr.h>
typedef struct { cstr name, last; } Person;
Person Person_make(const char* name, const char* last) {
- return (Person){.name = cstr_from(name), .last = cstr_from(last)};
+ Person p = {.name = cstr_from(name), .last = cstr_from(last)};
+ return p;
}
int Person_cmp(const Person* a, const Person* b) {
@@ -28,16 +30,17 @@ void Person_drop(Person* p) {
}
#define i_type PSPtr
-#define i_valclass Person // ensure Person_drop
-#define i_cmp Person_cmp // specify object cmp, instead of ptr cmp for arc.
+#define i_keyclass Person // ensure Person_drop
+#define i_use_cmp
#include <stc/carc.h>
#define i_type Persons
-#define i_valboxed PSPtr // binds PSPtr_cmp, PSPtr_drop...
+#define i_keyboxed PSPtr // binds PSPtr_cmp, PSPtr_drop...
+#define i_use_cmp
#include <stc/cvec.h>
-int main()
+int main(void)
{
PSPtr p = PSPtr_from(Person_make("Laura", "Palmer"));
PSPtr q = PSPtr_from(Person_clone(*p.get)); // deep copy
diff --git a/misc/examples/csmap_erase.c b/misc/examples/sortedmaps/csmap_erase.c
index 697e6c09..8d4eeae3 100644
--- a/misc/examples/csmap_erase.c
+++ b/misc/examples/sortedmaps/csmap_erase.c
@@ -1,5 +1,6 @@
// map_erase.c
// From C++ example: https://docs.microsoft.com/en-us/cpp/standard-library/map-class?view=msvc-160#example-16
+#define i_implement
#include <stc/cstr.h>
#include <stdio.h>
@@ -15,7 +16,7 @@ void printmap(mymap m)
printf("\nsize() == %" c_ZI "\n\n", mymap_size(&m));
}
-int main()
+int main(void)
{
mymap m1 = {0};
@@ -34,7 +35,7 @@ int main()
printmap(m1);
// Fill in some data to test with
- mymap m2 = c_make(mymap, {
+ mymap m2 = c_init(mymap, {
{10, "Bob"},
{11, "Rob"},
{12, "Robert"},
diff --git a/misc/examples/csmap_find.c b/misc/examples/sortedmaps/csmap_find.c
index c417567a..c392338d 100644
--- a/misc/examples/csmap_find.c
+++ b/misc/examples/sortedmaps/csmap_find.c
@@ -1,5 +1,6 @@
// This implements the c++ std::map::find example at:
// https://docs.microsoft.com/en-us/cpp/standard-library/map-class?view=msvc-160#example-17
+#define i_implement
#include <stc/cstr.h>
#define i_key int
@@ -7,8 +8,7 @@
#define i_tag istr
#include <stc/csmap.h>
-#define i_val csmap_istr_raw
-#define i_opt c_no_cmp
+#define i_key csmap_istr_raw
#define i_tag istr
#include <stc/cvec.h>
@@ -40,21 +40,21 @@ void findit(csmap_istr c, csmap_istr_key val)
}
}
-int main()
+int main(void)
{
- csmap_istr m1 = c_make(csmap_istr, {{40, "Zr"}, {45, "Rh"}});
+ csmap_istr m1 = c_init(csmap_istr, {{40, "Zr"}, {45, "Rh"}});
cvec_istr v = {0};
puts("The starting map m1 is (key, value):");
print_collection_csmap_istr(&m1);
typedef cvec_istr_value pair;
- cvec_istr_push(&v, (pair){43, "Tc"});
- cvec_istr_push(&v, (pair){41, "Nb"});
- cvec_istr_push(&v, (pair){46, "Pd"});
- cvec_istr_push(&v, (pair){42, "Mo"});
- cvec_istr_push(&v, (pair){44, "Ru"});
- cvec_istr_push(&v, (pair){44, "Ru"}); // attempt a duplicate
+ cvec_istr_push(&v, c_LITERAL(pair){43, "Tc"});
+ cvec_istr_push(&v, c_LITERAL(pair){41, "Nb"});
+ cvec_istr_push(&v, c_LITERAL(pair){46, "Pd"});
+ cvec_istr_push(&v, c_LITERAL(pair){42, "Mo"});
+ cvec_istr_push(&v, c_LITERAL(pair){44, "Ru"});
+ cvec_istr_push(&v, c_LITERAL(pair){44, "Ru"}); // attempt a duplicate
puts("Inserting the following vector data into m1:");
print_collection_cvec_istr(&v);
diff --git a/misc/examples/csmap_insert.c b/misc/examples/sortedmaps/csmap_insert.c
index 3da245c7..04b8ddc6 100644
--- a/misc/examples/csmap_insert.c
+++ b/misc/examples/sortedmaps/csmap_insert.c
@@ -5,14 +5,14 @@
#define i_tag ii // Map of int => int
#include <stc/csmap.h>
+#define i_implement
#include <stc/cstr.h>
#define i_key int
#define i_val_str
#define i_tag istr // Map of int => cstr
#include <stc/csmap.h>
-#define i_val csmap_ii_raw
-#define i_opt c_no_cmp
+#define i_key csmap_ii_raw
#define i_tag ii
#include <stc/cvec.h>
@@ -28,12 +28,12 @@ void print_istr(csmap_istr map) {
puts("");
}
-int main()
+int main(void)
{
// insert single values
csmap_ii m1 = {0};
csmap_ii_insert(&m1, 1, 10);
- csmap_ii_push(&m1, (csmap_ii_value){2, 20});
+ csmap_ii_push(&m1, c_LITERAL(csmap_ii_value){2, 20});
puts("The original key and mapped values of m1 are:");
print_ii(m1);
@@ -60,11 +60,11 @@ int main()
csmap_ii m2 = {0};
cvec_ii v = {0};
typedef cvec_ii_value ipair;
- cvec_ii_push(&v, (ipair){43, 294});
- cvec_ii_push(&v, (ipair){41, 262});
- cvec_ii_push(&v, (ipair){45, 330});
- cvec_ii_push(&v, (ipair){42, 277});
- cvec_ii_push(&v, (ipair){44, 311});
+ cvec_ii_push(&v, c_LITERAL(ipair){43, 294});
+ cvec_ii_push(&v, c_LITERAL(ipair){41, 262});
+ cvec_ii_push(&v, c_LITERAL(ipair){45, 330});
+ cvec_ii_push(&v, c_LITERAL(ipair){42, 277});
+ cvec_ii_push(&v, c_LITERAL(ipair){44, 311});
puts("Inserting the following vector data into m2:");
c_foreach (e, cvec_ii, v)
@@ -96,7 +96,7 @@ int main()
csmap_ii m4 = {0};
// Insert the elements from an initializer_list
- m4 = c_make(csmap_ii, {{4, 44}, {2, 22}, {3, 33}, {1, 11}, {5, 55}});
+ m4 = c_init(csmap_ii, {{4, 44}, {2, 22}, {3, 33}, {1, 11}, {5, 55}});
puts("After initializer_list insertion, m4 contains:");
print_ii(m4);
puts("");
diff --git a/misc/examples/csset_erase.c b/misc/examples/sortedmaps/csset_erase.c
index 9fa40682..9c7f5e1a 100644
--- a/misc/examples/csset_erase.c
+++ b/misc/examples/sortedmaps/csset_erase.c
@@ -3,9 +3,9 @@
#define i_key int
#include <stc/csset.h>
-int main()
+int main(void)
{
- csset_int set = c_make(csset_int, {30, 20, 80, 40, 60, 90, 10, 70, 50});
+ csset_int set = c_init(csset_int, {30, 20, 80, 40, 60, 90, 10, 70, 50});
c_foreach (k, csset_int, set)
printf(" %d", *k.ref);
@@ -38,4 +38,4 @@ int main()
puts("");
csset_int_drop(&set);
-} \ No newline at end of file
+}
diff --git a/misc/examples/gauss2.c b/misc/examples/sortedmaps/gauss2.c
index df709d03..02ce4bc5 100644
--- a/misc/examples/gauss2.c
+++ b/misc/examples/sortedmaps/gauss2.c
@@ -1,33 +1,34 @@
#include <stdio.h>
#include <time.h>
-#include <stc/crand.h>
+#define i_implement
#include <stc/cstr.h>
+#include <stc/crand.h>
// Declare int -> int sorted map.
#define i_key int
#define i_val int
#include <stc/csmap.h>
-int main()
+int main(void)
{
enum {N = 5000000};
uint64_t seed = (uint64_t)time(NULL);
crand_t rng = crand_init(seed);
- const double Mean = round(crand_f64(&rng)*98.f - 49.f), StdDev = crand_f64(&rng)*10.f + 1.f, Scale = 74.f;
+ const double Mean = round(crand_f64(&rng)*98.0 - 49.0), StdDev = crand_f64(&rng)*10.0 + 1.0, Scale = 74.0;
printf("Demo of gaussian / normal distribution of %d random samples\n", N);
printf("Mean %f, StdDev %f\n", Mean, StdDev);
// Setup random engine with normal distribution.
- crand_norm_t dist = crand_norm_init(Mean, StdDev);
+ crand_normal_t dist = crand_normal_init(Mean, StdDev);
// Create and init histogram map with defered destruct
csmap_int hist = {0};
cstr bar = {0};
c_forrange (N) {
- int index = (int)round(crand_norm(&rng, &dist));
+ int index = (int)round(crand_normal(&rng, &dist));
csmap_int_insert(&hist, index, 0).ref->second += 1;
}
diff --git a/misc/examples/mmap.c b/misc/examples/sortedmaps/listmap.c
index 0394a2df..04a605a7 100644
--- a/misc/examples/mmap.c
+++ b/misc/examples/sortedmaps/listmap.c
@@ -2,8 +2,9 @@
// https://en.cppreference.com/w/cpp/container/multimap/insert
// Multimap entries
+#define i_implement
#include <stc/cstr.h>
-#define i_val_str
+#define i_key_str
#include <stc/clist.h>
// Map of int => clist_str.
@@ -29,7 +30,7 @@ void insert(Multimap* mmap, int key, const char* str)
clist_str_emplace_back(list, str);
}
-int main()
+int main(void)
{
Multimap mmap = {0};
diff --git a/misc/examples/mapmap.c b/misc/examples/sortedmaps/mapmap.c
index 668da5de..d3065659 100644
--- a/misc/examples/mapmap.c
+++ b/misc/examples/sortedmaps/mapmap.c
@@ -1,5 +1,5 @@
// create a structure like: std::map<std::string, std::map<std::string, std::string>>:
-
+#define i_implement
#include <stc/cstr.h>
// People: std::map<std::string, std::string>
diff --git a/misc/examples/multimap.c b/misc/examples/sortedmaps/multimap.c
index d8981a81..a4490f91 100644
--- a/misc/examples/multimap.c
+++ b/misc/examples/sortedmaps/multimap.c
@@ -1,3 +1,4 @@
+#define i_implement
#include <stc/cstr.h>
// Olympics multimap example
@@ -39,7 +40,8 @@ OlympicLoc OlympicLoc_clone(OlympicLoc loc);
void OlympicLoc_drop(OlympicLoc* self);
// Create a clist<OlympicLoc>, can be sorted by year.
-#define i_valclass OlympicLoc // binds _cmp, _clone and _drop.
+#define i_keyclass OlympicLoc // binds _cmp, _clone and _drop.
+#define i_use_cmp
#define i_tag OL
#include <stc/clist.h>
@@ -65,7 +67,7 @@ void OlympicLoc_drop(OlympicLoc* self) {
}
-int main()
+int main(void)
{
// Define the multimap with destructor defered to when block is completed.
csmap_OL multimap = {0};
diff --git a/misc/examples/new_smap.c b/misc/examples/sortedmaps/new_smap.c
index d8245b8b..ee946c9a 100644
--- a/misc/examples/new_smap.c
+++ b/misc/examples/sortedmaps/new_smap.c
@@ -1,3 +1,4 @@
+#define i_implement
#include <stc/cstr.h>
#include <stc/forward.h>
@@ -10,7 +11,7 @@ typedef struct {
} MyStruct;
// Point => int map
-struct Point { int x, y; } typedef Point;
+typedef struct Point { int x, y; } Point;
int point_cmp(const Point* a, const Point* b) {
int c = a->x - b->x;
return c ? c : a->y - b->y;
@@ -35,14 +36,14 @@ int point_cmp(const Point* a, const Point* b) {
#include <stc/csset.h>
-int main()
+int main(void)
{
- PMap pmap = c_make(PMap, {
+ PMap pmap = c_init(PMap, {
{{42, 14}, 1},
{{32, 94}, 2},
{{62, 81}, 3},
});
- SMap smap = c_make(SMap, {
+ SMap smap = c_init(SMap, {
{"Hello, friend", "this is the mapped value"},
{"The brown fox", "jumped"},
{"This is the time", "for all good things"},
diff --git a/misc/examples/sorted_map.c b/misc/examples/sortedmaps/sorted_map.c
index ae9b45a4..89381554 100644
--- a/misc/examples/sorted_map.c
+++ b/misc/examples/sortedmaps/sorted_map.c
@@ -1,11 +1,11 @@
// https://iq.opengenus.org/containers-cpp-stl/
+#include <stdio.h>
#define i_key int
#define i_val int
#include <stc/csmap.h>
-#include <stdio.h>
-int main()
+int main(void)
{
// empty map containers
diff --git a/misc/examples/spans/matmult.c b/misc/examples/spans/matmult.c
new file mode 100644
index 00000000..ec992ff9
--- /dev/null
+++ b/misc/examples/spans/matmult.c
@@ -0,0 +1,90 @@
+// https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2023/p2642r2.html
+// C99:
+#include <stdio.h>
+#include <time.h>
+#include <stc/cspan.h>
+
+using_cspan3(Mat, double);
+typedef Mat2 OutMat;
+typedef struct { Mat2 m00, m01, m10, m11; } Partition;
+
+Partition partition(Mat2 A)
+{
+ int32_t M = A.shape[0];
+ int32_t N = A.shape[1];
+ return (Partition){
+ .m00 = cspan_slice(Mat2, &A, {0, M/2}, {0, N/2}),
+ .m01 = cspan_slice(Mat2, &A, {0, M/2}, {N/2, N}),
+ .m10 = cspan_slice(Mat2, &A, {M/2, M}, {0, N/2}),
+ .m11 = cspan_slice(Mat2, &A, {M/2, M}, {N/2, N}),
+ };
+}
+
+// Slow generic implementation
+void base_case_matrix_product(Mat2 A, Mat2 B, OutMat C)
+{
+ for (int j = 0; j < C.shape[1]; ++j) {
+ for (int i = 0; i < C.shape[0]; ++i) {
+ Mat2_value C_ij = 0;
+ for (int k = 0; k < A.shape[1]; ++k) {
+ C_ij += *cspan_at(&A, i,k) * *cspan_at(&B, k,j);
+ }
+ *cspan_at(&C, i,j) += C_ij;
+ }
+ }
+}
+
+void recursive_matrix_product(Mat2 A, Mat2 B, OutMat C)
+{
+ // Some hardware-dependent constant
+ enum {recursion_threshold = 32};
+ if (C.shape[0] <= recursion_threshold || C.shape[1] <= recursion_threshold) {
+ base_case_matrix_product(A, B, C);
+ } else {
+ Partition c = partition(C),
+ a = partition(A),
+ b = partition(B);
+ recursive_matrix_product(a.m00, b.m00, c.m00);
+ recursive_matrix_product(a.m01, b.m10, c.m00);
+ recursive_matrix_product(a.m10, b.m00, c.m10);
+ recursive_matrix_product(a.m11, b.m10, c.m10);
+ recursive_matrix_product(a.m00, b.m01, c.m01);
+ recursive_matrix_product(a.m01, b.m11, c.m01);
+ recursive_matrix_product(a.m10, b.m01, c.m11);
+ recursive_matrix_product(a.m11, b.m11, c.m11);
+ }
+}
+
+
+#define i_type Values
+#define i_val double
+#include <stc/cstack.h>
+#include <stc/crand.h>
+
+int main(void)
+{
+ enum {N = 10, D = 256};
+
+ Values values = {0};
+ for (int i=0; i < N*D*D; ++i)
+ Values_push(&values, (crandf() - 0.5)*4.0);
+
+ double out[D*D];
+ Mat3 data = cspan_md_layout(c_ROWMAJOR, values.data, N, D, D);
+ OutMat c = cspan_md_layout(c_COLMAJOR, out, D, D);
+ Mat2 a = cspan_submd3(&data, 0);
+
+ clock_t t = clock();
+ for (int i=1; i<N; ++i) {
+ Mat2 b = cspan_submd3(&data, i);
+ memset(out, 0, sizeof out);
+ recursive_matrix_product(a, b, c);
+ //base_case_matrix_product(a, b, c);
+ }
+ t = clock() - t;
+
+ double sum = 0.0;
+ c_foreach (i, Mat2, c) sum += *i.ref;
+ printf("sum=%.16g, %f ms\n", sum, (double)t*1000.0/CLOCKS_PER_SEC);
+ Values_drop(&values);
+}
diff --git a/misc/examples/spans/mdspan.c b/misc/examples/spans/mdspan.c
new file mode 100644
index 00000000..630ffddb
--- /dev/null
+++ b/misc/examples/spans/mdspan.c
@@ -0,0 +1,51 @@
+#include <stdio.h>
+#include <stc/cspan.h>
+#include <stdlib.h>
+
+using_cspan3(DSpan, double);
+
+int main(void) {
+ const int nx=5, ny=4, nz=3;
+ double* data = c_new_n(double, nx*ny*nz);
+
+ printf("\nMultidim span ms[5, 4, 3], fortran ordered");
+ DSpan3 ms = cspan_md_layout(c_COLMAJOR, data, nx, ny, nz);
+
+ int idx = 0;
+ for (int i = 0; i < ms.shape[0]; ++i)
+ for (int j = 0; j < ms.shape[1]; ++j)
+ for (int k = 0; k < ms.shape[2]; ++k)
+ *cspan_at(&ms, i, j, k) = ++idx;
+
+ cspan_transpose(&ms);
+
+ printf(", transposed:\n\n");
+ for (int i = 0; i < ms.shape[0]; ++i) {
+ for (int j = 0; j < ms.shape[1]; ++j) {
+ for (int k = 0; k < ms.shape[2]; ++k)
+ printf(" %3g", *cspan_at(&ms, i, j, k));
+ puts("");
+ }
+ puts("");
+ }
+
+ DSpan2 sub;
+
+ puts("Slicing:");
+ printf("\nms[0, :, :] ");
+ sub = cspan_slice(DSpan2, &ms, {0}, {c_ALL}, {c_ALL});
+ c_foreach (i, DSpan2, sub) printf(" %g", *i.ref);
+ puts("");
+
+ printf("\nms[:, 0, :] ");
+ sub = cspan_slice(DSpan2, &ms, {c_ALL}, {0}, {c_ALL});
+ c_foreach (i, DSpan2, sub) printf(" %g", *i.ref);
+ puts("");
+
+ sub = cspan_slice(DSpan2, &ms, {c_ALL}, {c_ALL}, {0});
+ printf("\nms[:, :, 0] ");
+ c_foreach (i, DSpan2, sub) printf(" %g", *i.ref);
+ puts("");
+
+ free(data);
+}
diff --git a/misc/examples/spans/multidim.c b/misc/examples/spans/multidim.c
new file mode 100644
index 00000000..70fda7e2
--- /dev/null
+++ b/misc/examples/spans/multidim.c
@@ -0,0 +1,76 @@
+// Example based on https://en.cppreference.com/w/cpp/container/mdspan
+#define i_val int
+#include <stc/cstack.h>
+#define i_implement
+#include <stc/cspan.h>
+#include <stdio.h>
+
+using_cspan3(ispan, int);
+
+void print2d(ispan2 ms2) {
+ for (int i=0; i < ms2.shape[0]; i++) {
+ for (int j=0; j < ms2.shape[1]; j++)
+ printf(" %3d", *cspan_at(&ms2, i, j));
+ puts("");
+ }
+}
+
+void print3d(ispan3 ms3) {
+ for (int i=0; i < ms3.shape[0]; i++) {
+ for (int j=0; j < ms3.shape[1]; j++) {
+ for (int k=0; k < ms3.shape[2]; k++)
+ printf(" %3d", *cspan_at(&ms3, i, j, k));
+ puts("");
+ }
+ puts("");
+ }
+}
+
+int main(void)
+{
+ cstack_int v = c_init(cstack_int, {1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24});
+
+ // Create 1d span from a compatibel container
+ ispan ms1 = cspan_from(&v);
+
+ // Create a 3D mdspan 2 x 3 x 4
+ ispan3 ms3 = cspan_md(v.data, 2, 3, 4);
+
+ puts("ms3:");
+ print3d(ms3);
+
+ // Take a slice of md3
+ ispan3 ss3 = cspan_slice(ispan3, &ms3, {c_ALL}, {1,3}, {1,3});
+ puts("ss3 = ms3[:, 1:3, 1:3]");
+ print3d(ss3);
+
+ puts("Iterate ss3 flat:");
+ c_foreach (i, ispan3, ss3) printf(" %d", *i.ref);
+ puts("");
+
+ // submd3 span reduces rank depending on number of arguments
+ ispan2 ms2 = cspan_submd3(&ms3, 1);
+
+ // Change data on the 2d subspan
+ for (int i=0; i != ms2.shape[0]; i++)
+ for (int j=0; j != ms2.shape[1]; j++)
+ *cspan_at(&ms2, i, j) = (i + 1)*100 + j;
+
+ puts("\nms2 = ms3[1] with updated data:");
+ print2d(ms2);
+ puts("");
+
+ puts("\nOriginal s1 span with updated data:");
+ c_foreach (i, ispan, ms1) printf(" %d", *i.ref);
+ puts("");
+
+ puts("\nOriginal ms3 span with updated data:");
+ print3d(ms3);
+
+ puts("col = ms3[1, :, 2]");
+ ispan col = cspan_slice(ispan, &ms3, {1}, {c_ALL}, {2});
+ c_foreach (i, ispan, col) printf(" %d", *i.ref);
+ puts("");
+
+ cstack_int_drop(&v);
+}
diff --git a/misc/examples/spans/printspan.c b/misc/examples/spans/printspan.c
new file mode 100644
index 00000000..b6999b61
--- /dev/null
+++ b/misc/examples/spans/printspan.c
@@ -0,0 +1,41 @@
+// https://www.modernescpp.com/index.php/c-20-std-span/
+
+#include <stdio.h>
+#define i_key int
+#include <stc/cvec.h>
+
+#define i_key int
+#include <stc/cstack.h>
+
+#include <stc/cspan.h>
+using_cspan(intspan, int);
+
+
+void printMe(intspan container) {
+ printf("%d:", (int)cspan_size(&container));
+ c_foreach (e, intspan, container)
+ printf(" %d", *e.ref);
+ puts("");
+}
+
+
+int main(void)
+{
+ printMe( c_init(intspan, {1, 2, 3, 4}) );
+
+ int arr[] = {1, 2, 3, 4, 5};
+ printMe( (intspan)cspan_from_array(arr) );
+
+ cvec_int vec = c_init(cvec_int, {1, 2, 3, 4, 5, 6});
+ printMe( (intspan)cspan_from(&vec) );
+
+ cstack_int stk = c_init(cstack_int, {1, 2, 3, 4, 5, 6, 7});
+ printMe( (intspan)cspan_from(&stk) );
+
+ intspan spn = c_init(intspan, {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12});
+ printMe( (intspan)cspan_subspan(&spn, 2, 8) );
+
+ // cleanup
+ cvec_int_drop(&vec);
+ cstack_int_drop(&stk);
+}
diff --git a/misc/examples/spans/submdspan.c b/misc/examples/spans/submdspan.c
new file mode 100644
index 00000000..0752dfa1
--- /dev/null
+++ b/misc/examples/spans/submdspan.c
@@ -0,0 +1,44 @@
+// https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2022/p2630r0.html
+// C99:
+#include <stdio.h>
+#include <stc/cspan.h>
+
+using_cspan3(span, double); // shorthand for defining span, span2, span3
+
+// Set all elements of a rank-2 mdspan to zero.
+void zero_2d(span2 grid2d) {
+ (void)c_static_assert(cspan_rank(&grid2d) == 2);
+ for (int i = 0; i < grid2d.shape[0]; ++i) {
+ for (int j = 0; j < grid2d.shape[1]; ++j) {
+ *cspan_at(&grid2d, i,j) = 0;
+ }
+ }
+}
+
+void zero_surface(span3 grid3d) {
+ (void)c_static_assert(cspan_rank(&grid3d) == 3);
+ zero_2d(cspan_slice(span2, &grid3d, {0}, {c_ALL}, {c_ALL}));
+ zero_2d(cspan_slice(span2, &grid3d, {c_ALL}, {0}, {c_ALL}));
+ zero_2d(cspan_slice(span2, &grid3d, {c_ALL}, {c_ALL}, {0}));
+ zero_2d(cspan_slice(span2, &grid3d, {grid3d.shape[0]-1}, {c_ALL}, {c_ALL}));
+ zero_2d(cspan_slice(span2, &grid3d, {c_ALL}, {grid3d.shape[1]-1}, {c_ALL}));
+ zero_2d(cspan_slice(span2, &grid3d, {c_ALL}, {c_ALL}, {grid3d.shape[2]-1}));
+}
+
+int main() {
+ double arr[3*4*5];
+ for (int i=0; i<c_arraylen(arr); ++i) arr[i] = i + 1.0;
+
+ span3 md = cspan_md(arr, 3, 4, 5);
+
+ zero_surface(md);
+
+ for (int i = 0; i < md.shape[0]; i++) {
+ for (int j = 0; j < md.shape[1]; j++) {
+ for (int k = 0; k < md.shape[2]; k++)
+ printf(" %2g", *cspan_at(&md, i,j,k));
+ puts("");
+ }
+ puts("");
+ }
+}
diff --git a/misc/examples/cstr_match.c b/misc/examples/strings/cstr_match.c
index 58cf8884..80013019 100644
--- a/misc/examples/cstr_match.c
+++ b/misc/examples/strings/cstr_match.c
@@ -1,10 +1,11 @@
+#define i_implement
#include <stc/cstr.h>
#include <stc/csview.h>
#include <stdio.h>
-int main()
+int main(void)
{
- cstr ss = cstr_lit("The quick brown fox jumps over the lazy dog.JPG");
+ cstr ss = cstr_from("The quick brown fox jumps over the lazy dog.JPG");
intptr_t pos = cstr_find_at(&ss, 0, "brown");
printf("%" c_ZI " [%s]\n", pos, pos == c_NPOS ? "<NULL>" : cstr_str(&ss) + pos);
diff --git a/misc/examples/replace.c b/misc/examples/strings/replace.c
index cf5b45cb..59a56bf7 100644
--- a/misc/examples/replace.c
+++ b/misc/examples/strings/replace.c
@@ -1,6 +1,7 @@
+#define i_implement
#include <stc/cstr.h>
-int main ()
+int main(void)
{
const char *base = "this is a test string.";
const char *s2 = "n example";
diff --git a/misc/examples/splitstr.c b/misc/examples/strings/splitstr.c
index 2bc6fc07..ef7ed174 100644
--- a/misc/examples/splitstr.c
+++ b/misc/examples/strings/splitstr.c
@@ -1,9 +1,10 @@
#include <stdio.h>
-#define i_extern // cstr + utf8 functions
+#define i_import // cstr + utf8 functions
#include <stc/cregex.h>
+#define i_implement
#include <stc/csview.h>
-int main()
+int main(void)
{
puts("Split with c_fortoken (csview):");
diff --git a/misc/examples/sso_map.c b/misc/examples/strings/sso_map.c
index 70450e21..4f84b651 100644
--- a/misc/examples/sso_map.c
+++ b/misc/examples/strings/sso_map.c
@@ -1,9 +1,10 @@
+#define i_implement
#include <stc/cstr.h>
#define i_key_str
#define i_val_str
#include <stc/cmap.h>
-int main()
+int main(void)
{
cmap_str m = {0};
cmap_str_emplace(&m, "Test short", "This is a short string");
diff --git a/misc/examples/sso_substr.c b/misc/examples/strings/sso_substr.c
index 4b2dbcc8..70d34440 100644
--- a/misc/examples/sso_substr.c
+++ b/misc/examples/strings/sso_substr.c
@@ -1,18 +1,20 @@
+#define i_implement
#include <stc/cstr.h>
+#define i_implement
#include <stc/csview.h>
-int main ()
+int main(void)
{
- cstr str = cstr_lit("We think in generalities, but we live in details.");
+ cstr str = cstr_from("We think in generalities, but we live in details.");
csview sv1 = cstr_substr_ex(&str, 3, 5); // "think"
- intptr_t pos = cstr_find(&str, "live"); // position of "live"
+ intptr_t pos = cstr_find(&str, "live"); // position of "live"
csview sv2 = cstr_substr_ex(&str, pos, 4); // "live"
csview sv3 = cstr_slice_ex(&str, -8, -1); // "details"
printf("%.*s, %.*s, %.*s\n", c_SV(sv1), c_SV(sv2), c_SV(sv3));
cstr_assign(&str, "apples are green or red");
- cstr s2 = cstr_from_sv(cstr_substr_ex(&str, -3, 3)); // "red"
- cstr s3 = cstr_from_sv(cstr_substr_ex(&str, 0, 6)); // "apples"
+ cstr s2 = cstr_from_sv(cstr_substr_ex(&str, -3, 3)); // "red"
+ cstr s3 = cstr_from_sv(cstr_substr_ex(&str, 0, 6)); // "apples"
printf("%s %s: %d, %d\n", cstr_str(&s2), cstr_str(&s3),
cstr_is_long(&str), cstr_is_long(&s2));
c_drop (cstr, &str, &s2, &s3);
diff --git a/misc/examples/sview_split.c b/misc/examples/strings/sview_split.c
index 31a28e51..ac275da0 100644
--- a/misc/examples/sview_split.c
+++ b/misc/examples/strings/sview_split.c
@@ -1,7 +1,9 @@
+#define i_implement
#include <stc/cstr.h>
+#define i_implement
#include <stc/csview.h>
-int main()
+int main(void)
{
// No memory allocations or string length calculations!
const csview date = c_sv("2021/03/12");
diff --git a/misc/examples/utf8replace_c.c b/misc/examples/strings/utf8replace_c.c
index 3cde8701..317313b0 100644
--- a/misc/examples/utf8replace_c.c
+++ b/misc/examples/strings/utf8replace_c.c
@@ -1,6 +1,7 @@
+#define i_implement
#include <stc/cstr.h>
-int main()
+int main(void)
{
cstr hello = cstr_lit("hell😀 w😀rld");
printf("%s\n", cstr_str(&hello));
@@ -14,7 +15,7 @@ int main()
printf("%s\n", cstr_str(&hello));
c_foreach (c, cstr, hello)
- printf("%.*s,", c_SV(c.u8.chr));
+ printf("%.*s,", c_SV(c.chr));
cstr str = cstr_lit("scooby, dooby doo");
cstr_replace(&str, "oo", "00");
diff --git a/misc/examples/utf8replace_rs.rs b/misc/examples/strings/utf8replace_rs.rs
index 8b163b4e..8b163b4e 100644
--- a/misc/examples/utf8replace_rs.rs
+++ b/misc/examples/strings/utf8replace_rs.rs
diff --git a/misc/examples/triples.c b/misc/examples/triples.c
deleted file mode 100644
index 520bf012..00000000
--- a/misc/examples/triples.c
+++ /dev/null
@@ -1,69 +0,0 @@
-// https://quuxplusone.github.io/blog/2019/03/06/pythagorean-triples/
-
-#include <stc/algo/coroutine.h>
-#include <stdio.h>
-
-void triples_vanilla(int n) {
- for (int c = 5; n; ++c) {
- for (int a = 1; a < c; ++a) {
- for (int b = a + 1; b < c; ++b) {
- if ((int64_t)a*a + (int64_t)b*b == (int64_t)c*c) {
- printf("{%d, %d, %d}\n", a, b, c);
- if (--n == 0) goto done;
- }
- }
- }
- }
- done:;
-}
-
-struct triples {
- int n;
- int a, b, c;
- int cco_state;
-};
-
-bool triples_next(struct triples* I) {
- cco_begin(I);
- for (I->c = 5; I->n; ++I->c) {
- for (I->a = 1; I->a < I->c; ++I->a) {
- for (I->b = I->a + 1; I->b < I->c; ++I->b) {
- if ((int64_t)I->a*I->a + (int64_t)I->b*I->b == (int64_t)I->c*I->c) {
- cco_yield(true);
- if (--I->n == 0) cco_return;
- }
- }
- }
- }
- cco_final:
- puts("done");
- cco_end(false);
-}
-
-int gcd(int a, int b) {
- while (b) {
- int t = a % b;
- a = b;
- b = t;
- }
- return a;
-}
-
-int main()
-{
- puts("Vanilla triples:");
- triples_vanilla(6);
-
- puts("\nCoroutine triples:");
- struct triples t = {INT32_MAX};
- int n = 0;
-
- while (triples_next(&t)) {
- if (gcd(t.a, t.b) > 1)
- continue;
- if (t.c < 100)
- printf("%d: {%d, %d, %d}\n", ++n, t.a, t.b, t.c);
- else
- cco_stop(&t);
- }
-}
diff --git a/misc/examples/lower_bound.c b/misc/examples/vectors/lower_bound.c
index 6ec7544c..09cf2008 100644
--- a/misc/examples/lower_bound.c
+++ b/misc/examples/vectors/lower_bound.c
@@ -1,17 +1,18 @@
#include <stdio.h>
-#define i_val int
+#define i_key int
+#define i_use_cmp
#include <stc/cvec.h>
-#define i_val int
+#define i_key int
#include <stc/csset.h>
-int main()
+int main(void)
{
// TEST SORTED VECTOR
{
int key, *res;
- cvec_int vec = c_make(cvec_int, {40, 600, 1, 7000, 2, 500, 30});
+ cvec_int vec = c_init(cvec_int, {40, 600, 1, 7000, 2, 500, 30});
cvec_int_sort(&vec);
@@ -40,7 +41,7 @@ int main()
// TEST SORTED SET
{
int key, *res;
- csset_int set = c_make(csset_int, {40, 600, 1, 7000, 2, 500, 30});
+ csset_int set = c_init(csset_int, {40, 600, 1, 7000, 2, 500, 30});
key = 100;
res = csset_int_lower_bound(&set, key).ref;
diff --git a/misc/examples/new_vec.c b/misc/examples/vectors/new_vec.c
index df443b7f..88efd55a 100644
--- a/misc/examples/new_vec.c
+++ b/misc/examples/vectors/new_vec.c
@@ -4,32 +4,33 @@
forward_cvec(cvec_i32, int);
forward_cvec(cvec_pnt, struct Point);
-struct MyStruct {
+typedef struct MyStruct {
cvec_i32 intvec;
cvec_pnt pntvec;
-} typedef MyStruct;
+} MyStruct;
-#define i_val int
-#define i_is_forward
+#define i_key int
#define i_tag i32
+#define i_is_forward
#include <stc/cvec.h>
typedef struct Point { int x, y; } Point;
-#define i_val Point
+#define i_key Point
+#define i_tag pnt
#define i_less(a, b) a->x < b->x || (a->x == b->x && a->y < b->y)
+#define i_eq(a, b) a->x == b->x && a->y == b->y
#define i_is_forward
-#define i_tag pnt
#include <stc/cvec.h>
-int main()
+int main(void)
{
MyStruct my = {0};
- cvec_pnt_push(&my.pntvec, (Point){42, 14});
- cvec_pnt_push(&my.pntvec, (Point){32, 94});
- cvec_pnt_push(&my.pntvec, (Point){62, 81});
- cvec_pnt_push(&my.pntvec, (Point){32, 91});
+ cvec_pnt_push(&my.pntvec, c_LITERAL(Point){42, 14});
+ cvec_pnt_push(&my.pntvec, c_LITERAL(Point){32, 94});
+ cvec_pnt_push(&my.pntvec, c_LITERAL(Point){62, 81});
+ cvec_pnt_push(&my.pntvec, c_LITERAL(Point){32, 91});
cvec_pnt_sort(&my.pntvec);
diff --git a/misc/examples/stack.c b/misc/examples/vectors/stack.c
index c817e1ae..6297fb6f 100644
--- a/misc/examples/stack.c
+++ b/misc/examples/vectors/stack.c
@@ -3,14 +3,14 @@
#define i_tag i
#define i_capacity 100
-#define i_val int
+#define i_key int
#include <stc/cstack.h>
#define i_tag c
-#define i_val char
+#define i_key char
#include <stc/cstack.h>
-int main() {
+int main(void) {
cstack_i stack = {0};
cstack_c chars = {0};
diff --git a/misc/tests/cregex_test.c b/misc/tests/cregex_test.c
index aa4b2a65..a83b7593 100644
--- a/misc/tests/cregex_test.c
+++ b/misc/tests/cregex_test.c
@@ -1,9 +1,10 @@
-#define i_extern
+#define i_import
#include <stc/cregex.h>
#include <stc/csview.h>
+#include <stc/algo/raii.h>
#include "ctest.h"
-#define M_START(m) ((m).str - inp)
+#define M_START(m) ((m).buf - inp)
#define M_END(m) (M_START(m) + (m).size)
@@ -14,7 +15,7 @@ CTEST(cregex, compile_match_char)
ASSERT_EQ(re.error, 0);
csview match;
- ASSERT_EQ(cregex_find(&re, inp="äsdf", &match, CREG_M_FULLMATCH), CREG_OK);
+ ASSERT_EQ(cregex_find(&re, inp="äsdf", &match, CREG_FULLMATCH), CREG_OK);
ASSERT_EQ(M_START(match), 0);
ASSERT_EQ(M_END(match), 5); // ä is two bytes wide
@@ -192,14 +193,14 @@ CTEST(cregex, search_all)
int res;
ASSERT_EQ(re.error, CREG_OK);
inp="ab,ab,ab";
- res = cregex_find(&re, inp, &m, CREG_M_NEXT);
+ res = cregex_find(&re, inp, &m, CREG_NEXT);
ASSERT_EQ(M_START(m), 0);
- res = cregex_find(&re, inp, &m, CREG_M_NEXT);
+ res = cregex_find(&re, inp, &m, CREG_NEXT);
ASSERT_EQ(res, CREG_OK);
ASSERT_EQ(M_START(m), 3);
- res = cregex_find(&re, inp, &m, CREG_M_NEXT);
+ res = cregex_find(&re, inp, &m, CREG_NEXT);
ASSERT_EQ(M_START(m), 6);
- res = cregex_find(&re, inp, &m, CREG_M_NEXT);
+ res = cregex_find(&re, inp, &m, CREG_NEXT);
ASSERT_NE(res, CREG_OK);
}
}
@@ -208,7 +209,7 @@ CTEST(cregex, captures_len)
{
c_auto (cregex, re) {
re = cregex_from("(ab(cd))(ef)");
- ASSERT_EQ(cregex_captures(&re), 4);
+ ASSERT_EQ(cregex_captures(&re), 3);
}
}
@@ -217,7 +218,7 @@ CTEST(cregex, captures_cap)
const char* inp;
c_auto (cregex, re) {
re = cregex_from("(ab)((cd)+)");
- ASSERT_EQ(cregex_captures(&re), 4);
+ ASSERT_EQ(cregex_captures(&re), 3);
csview cap[5];
ASSERT_EQ(cregex_find(&re, inp="xxabcdcde", cap), CREG_OK);
@@ -237,7 +238,7 @@ CTEST(cregex, captures_cap)
static bool add_10_years(int i, csview match, cstr* out) {
if (i == 1) { // group 1 matches year
int year;
- sscanf(match.str, "%4d", &year); // scan 4 chars only
+ sscanf(match.buf, "%4d", &year); // scan 4 chars only
cstr_printf(out, "%04d", year + 10);
return true;
}
@@ -272,14 +273,14 @@ CTEST(cregex, replace)
// Compile RE separately
re = cregex_from(pattern);
- ASSERT_EQ(cregex_captures(&re), 4);
+ ASSERT_EQ(cregex_captures(&re), 3);
// European date format.
cstr_take(&str, cregex_replace(&re, input, "$3.$2.$1"));
ASSERT_STREQ(cstr_str(&str), "start date: 31.12.2015, end date: 28.02.2022");
// Strip out everything but the matches
- cstr_take(&str, cregex_replace_sv(&re, csview_from(input), "$3.$2.$1;", 0, NULL, CREG_R_STRIP));
+ cstr_take(&str, cregex_replace_sv(&re, csview_from(input), "$3.$2.$1;", 0, NULL, CREG_STRIP));
ASSERT_STREQ(cstr_str(&str), "31.12.2015;28.02.2022;");
}
}
diff --git a/misc/tests/cspan_test.c b/misc/tests/cspan_test.c
index 5d46f579..ce267b14 100644
--- a/misc/tests/cspan_test.c
+++ b/misc/tests/cspan_test.c
@@ -9,11 +9,11 @@ CTEST(cspan, subdim) {
int array[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12};
intspan3 m = cspan_md(array, 2, 2, 3);
- for (size_t i = 0; i < m.shape[0]; ++i) {
+ for (int i = 0; i < m.shape[0]; ++i) {
intspan2 sub_i = cspan_submd3(&m, i);
- for (size_t j = 0; j < m.shape[1]; ++j) {
+ for (int j = 0; j < m.shape[1]; ++j) {
intspan sub_i_j = cspan_submd2(&sub_i, j);
- for (size_t k = 0; k < m.shape[2]; ++k) {
+ for (int k = 0; k < m.shape[2]; ++k) {
ASSERT_EQ(*cspan_at(&sub_i_j, k), *cspan_at(&m, i, j, k));
}
}
@@ -24,18 +24,18 @@ CTEST(cspan, slice) {
int array[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12};
intspan2 m1 = cspan_md(array, 3, 4);
- size_t sum1 = 0;
- for (size_t i = 0; i < m1.shape[0]; ++i) {
- for (size_t j = 0; j < m1.shape[1]; ++j) {
+ int sum1 = 0;
+ for (int i = 0; i < m1.shape[0]; ++i) {
+ for (int j = 0; j < m1.shape[1]; ++j) {
sum1 += *cspan_at(&m1, i, j);
}
}
intspan2 m2 = cspan_slice(intspan2, &m1, {c_ALL}, {2,4});
- size_t sum2 = 0;
- for (size_t i = 0; i < m2.shape[0]; ++i) {
- for (size_t j = 0; j < m2.shape[1]; ++j) {
+ int sum2 = 0;
+ for (int i = 0; i < m2.shape[0]; ++i) {
+ for (int j = 0; j < m2.shape[1]; ++j) {
sum2 += *cspan_at(&m2, i, j);
}
}
@@ -43,11 +43,12 @@ CTEST(cspan, slice) {
ASSERT_EQ(45, sum2);
}
-#define i_val int
+#define i_key int
#include <stc/cstack.h>
CTEST(cspan, slice2) {
- c_auto (cstack_int, stack)
+ cstack_int stack = {0};
+ c_defer (cstack_int_drop(&stack))
{
c_forrange (i, 10*20*30)
cstack_int_push(&stack, i);
@@ -55,10 +56,10 @@ CTEST(cspan, slice2) {
intspan3 ms3 = cspan_md(stack.data, 10, 20, 30);
ms3 = cspan_slice(intspan3, &ms3, {1,4}, {3,7}, {20,24});
- size_t sum = 0;
- for (size_t i = 0; i < ms3.shape[0]; ++i) {
- for (size_t j = 0; j < ms3.shape[1]; ++j) {
- for (size_t k = 0; k < ms3.shape[2]; ++k) {
+ int sum = 0;
+ for (int i = 0; i < ms3.shape[0]; ++i) {
+ for (int j = 0; j < ms3.shape[1]; ++j) {
+ for (int k = 0; k < ms3.shape[2]; ++k) {
sum += *cspan_at(&ms3, i, j, k);
}
}
@@ -74,7 +75,7 @@ CTEST(cspan, slice2) {
#define i_type Tiles
-#define i_val intspan3
+#define i_key intspan3
#include <stc/cstack.h>
CTEST_FIXTURE(cspan_cube) {
@@ -112,10 +113,9 @@ CTEST_TEARDOWN(cspan_cube) {
CTEST_F(cspan_cube, slice3) {
- intptr_t n = cstack_int_size(&_self->stack);
- //printf("\ntiles: %zi, cells: %zi\n", Tiles_size(&_self->tiles), n);
+ long long n = cstack_int_size(&_self->stack);
+ long long sum = 0;
- int64_t sum = 0;
// iterate each 3d tile in sequence
c_foreach (i, Tiles, _self->tiles)
c_foreach (t, intspan3, *i.ref)
diff --git a/misc/tests/ctest.h b/misc/tests/ctest.h
index 373cda0e..6b1b1084 100644
--- a/misc/tests/ctest.h
+++ b/misc/tests/ctest.h
@@ -408,7 +408,8 @@ void assert_dbl_compare(const char* cmp, double exp, double real, double tol, co
void assert_pointers(const char* cmp, const void* exp, const void* real, const char* caller, int line) {
if ((exp == real) != (cmp[0] == '=')) {
- CTEST_ERR("%s:%d assertion failed (0x%02llx) %s (0x%02llx)", caller, line, (unsigned long long)exp , cmp, (unsigned long long)real);
+ CTEST_ERR("%s:%d assertion failed (0x%02llx) %s (0x%02llx)", caller, line,
+ (unsigned long long)(uintptr_t)exp , cmp, (unsigned long long)(uintptr_t)real);
}
}