diff options
| author | _Tradam <[email protected]> | 2023-09-08 01:29:47 +0000 |
|---|---|---|
| committer | GitHub <[email protected]> | 2023-09-08 01:29:47 +0000 |
| commit | 3c76c7f3d5db3f9586a90d03f8fbb02d79de9acd (patch) | |
| tree | afbe4b540967223911f7c5de36559b82154f02f3 /misc | |
| parent | 0841165881871ee01b782129be681209aeed2423 (diff) | |
| parent | 1a72205fe05c2375cfd380dd8381a8460d9ed8d1 (diff) | |
| download | STC-modified-modified.tar.gz STC-modified-modified.zip | |
Diffstat (limited to 'misc')
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(©.get); IPQue_pop(©.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); } } |
