| #include <browns/md5.hpp> | #include <browns/md5.hpp> | ||||
| #include <browns/output.hpp> | #include <browns/output.hpp> | ||||
| #include <neo/buffer.hpp> | |||||
| #include <neo/as_buffer.hpp> | |||||
| #include <catch2/catch.hpp> | #include <catch2/catch.hpp> | ||||
| auto md5_hash_str(std::string_view s) { | auto md5_hash_str(std::string_view s) { | ||||
| browns::md5 hash; | browns::md5 hash; | ||||
| hash.feed(neo::buffer(s)); | |||||
| hash.feed(neo::as_buffer(s)); | |||||
| hash.pad(); | hash.pad(); | ||||
| return browns::format_digest(hash.digest()); | return browns::format_digest(hash.digest()); | ||||
| } | } |
| #pragma once | |||||
| #include <neo/const_buffer.hpp> | |||||
| #include <neo/mutable_buffer.hpp> | |||||
| #include <string> | |||||
| #include <string_view> | |||||
| #include <type_traits> | |||||
| namespace neo { | |||||
| constexpr mutable_buffer buffer(const mutable_buffer& b) noexcept { return b; } | |||||
| constexpr mutable_buffer buffer(const mutable_buffer& b, mutable_buffer::size_type s) noexcept { | |||||
| auto min_size = s > b.size() ? b.size() : s; | |||||
| return mutable_buffer(b.data(), min_size); | |||||
| } | |||||
| constexpr const_buffer buffer(const const_buffer& b) noexcept { return b; } | |||||
| constexpr const_buffer buffer(const const_buffer& b, const_buffer::size_type s) noexcept { | |||||
| auto min_size = s > b.size() ? b.size() : s; | |||||
| return const_buffer(b.data(), min_size); | |||||
| } | |||||
| // ############################################################################# | |||||
| /** | |||||
| * Create a mutable buffer from an opaque pointer to void | |||||
| */ | |||||
| constexpr mutable_buffer buffer(void* ptr, mutable_buffer::size_type s) noexcept { | |||||
| return mutable_buffer(static_cast<std::byte*>(ptr), s); | |||||
| } | |||||
| /** | |||||
| * Create an immutable buffer from an opaque pointer to void | |||||
| */ | |||||
| constexpr const_buffer buffer(const void* ptr, const_buffer::size_type s) noexcept { | |||||
| return const_buffer(static_cast<const std::byte*>(ptr), s); | |||||
| } | |||||
| // ############################################################################# | |||||
| /** | |||||
| * Create a mutable buffer that refers to the bytes of a trivial object. | |||||
| */ | |||||
| template <typename Trivial, | |||||
| typename | |||||
| = std::enable_if_t<!std::is_const_v<Trivial> && !std::is_same_v<Trivial, mutable_buffer>>> | |||||
| constexpr mutable_buffer buffer(Trivial& item, std::size_t max_size = sizeof(Trivial)) { | |||||
| auto min_size = max_size > sizeof(item) ? sizeof(item) : max_size; | |||||
| return mutable_buffer(byte_pointer(std::addressof(item)), min_size); | |||||
| } | |||||
| /** | |||||
| * Create an immutable buffer that refers to the bytes of a trivial object. | |||||
| */ | |||||
| template < | |||||
| typename Trivial, | |||||
| typename = std::enable_if_t< | |||||
| std::is_const_v< | |||||
| Trivial> && !std::is_same_v<Trivial, mutable_buffer> && !std::is_same_v<Trivial, const_buffer>>> | |||||
| constexpr const_buffer buffer(Trivial& item, std::size_t max_size = sizeof(Trivial)) { | |||||
| auto min_size = std::min(sizeof(item), max_size); | |||||
| return const_buffer(byte_pointer(std::addressof(item)), min_size); | |||||
| } | |||||
| // ############################################################################# | |||||
| /** | |||||
| * Create a mutable buffer referring to the characters of a basic_string object | |||||
| */ | |||||
| template <typename Char, typename Traits, typename Alloc> | |||||
| constexpr mutable_buffer buffer(std::basic_string<Char, Traits, Alloc>& str, std::size_t max_size) { | |||||
| auto use_size = max_size > str.size() ? str.size() : max_size; | |||||
| return buffer(str.data(), use_size); | |||||
| } | |||||
| template <typename Char, typename Traits, typename Alloc> | |||||
| constexpr mutable_buffer buffer(std::basic_string<Char, Traits, Alloc>& str) { | |||||
| return buffer(str, str.size()); | |||||
| } | |||||
| /** | |||||
| * Create an immutable buffer refering to the characters of a basic_string object | |||||
| */ | |||||
| template <typename Char, typename Traits, typename Alloc> | |||||
| constexpr const_buffer buffer(const std::basic_string<Char, Traits, Alloc>& str, | |||||
| std::size_t max_size) { | |||||
| auto use_size = max_size > str.size() ? str.size() : max_size; | |||||
| return buffer(str.data(), use_size); | |||||
| } | |||||
| template <typename Char, typename Traits, typename Alloc> | |||||
| constexpr const_buffer buffer(const std::basic_string<Char, Traits, Alloc>& str) { | |||||
| return buffer(str, str.size()); | |||||
| } | |||||
| // ############################################################################# | |||||
| /** | |||||
| * Create an immutable buffer referring to the characters of a basic_string_view | |||||
| */ | |||||
| template <typename Char, typename Traits> | |||||
| constexpr const_buffer buffer(std::basic_string_view<Char, Traits> sv, std::size_t max_size) { | |||||
| auto use_size = max_size > sv.size() ? sv.size() : max_size; | |||||
| return buffer(sv.data(), use_size); | |||||
| } | |||||
| template <typename Char, typename Traits> | |||||
| constexpr const_buffer buffer(std::basic_string_view<Char, Traits> sv) { | |||||
| return buffer(sv, sv.size()); | |||||
| } | |||||
| } // namespace neo |
| #pragma once | |||||
| #include <algorithm> | |||||
| #include <cstddef> | |||||
| #include <cstring> | |||||
| #include <neo/const_buffer.hpp> | |||||
| #include <neo/mutable_buffer.hpp> | |||||
| namespace neo { | |||||
| namespace detail { | |||||
| void get_buffer_sequence_begin(void*, class buf_seq_begin_opaq); | |||||
| void get_buffer_sequence_end(void*, class buf_seq_end_opaq); | |||||
| } // namespace detail | |||||
| constexpr auto buffer_sequence_begin = [](auto&& what) { | |||||
| using detail::get_buffer_sequence_begin; | |||||
| return get_buffer_sequence_begin((decltype(what)&&)(what)); | |||||
| }; | |||||
| constexpr auto buffer_sequence_end = [](auto&& what) { | |||||
| using detail::get_buffer_sequence_end; | |||||
| return get_buffer_sequence_end((decltype(what)&&)(what)); | |||||
| }; | |||||
| template <typename Seq> | |||||
| constexpr std::size_t buffer_size(const Seq& seq) { | |||||
| auto iter = buffer_sequence_begin(seq); | |||||
| const auto stop = buffer_sequence_end(seq); | |||||
| std::size_t size = 0; | |||||
| while (iter != stop) { | |||||
| size += static_cast<std::size_t>(iter->size()); | |||||
| ++iter; | |||||
| } | |||||
| return size; | |||||
| } | |||||
| template <typename MutableSeq, typename ConstSeq> | |||||
| constexpr std::size_t | |||||
| buffer_copy(const MutableSeq& dest, const ConstSeq& src, std::size_t max_copy) { | |||||
| auto remaining_to_copy = max_copy; | |||||
| std::size_t n_copied = 0; | |||||
| auto dest_iter = buffer_sequence_begin(dest); | |||||
| const auto dest_stop = buffer_sequence_end(dest); | |||||
| auto src_iter = buffer_sequence_begin(src); | |||||
| const auto src_stop = buffer_sequence_end(dest); | |||||
| std::size_t src_offset = 0; | |||||
| std::size_t dest_offset = 0; | |||||
| while (dest_iter != dest_stop && src_iter != src_stop && remaining_to_copy) { | |||||
| const_buffer src_buf = *src_iter + src_offset; | |||||
| mutable_buffer dest_buf = *dest_iter + dest_offset; | |||||
| const auto copy_now | |||||
| = std::min(src_buf.size(), std::min(dest_buf.size(), remaining_to_copy)); | |||||
| std::memcpy(dest_buf.data(), src_buf.data(), copy_now); | |||||
| n_copied += copy_now; | |||||
| src_buf += n_copied; | |||||
| dest_buf += n_copied; | |||||
| src_offset += n_copied; | |||||
| dest_offset += n_copied; | |||||
| if (src_buf.size() == 0) { | |||||
| ++src_iter; | |||||
| src_offset = 0; | |||||
| } | |||||
| if (dest_buf.size() == 0) { | |||||
| ++dest_iter; | |||||
| dest_offset = 0; | |||||
| } | |||||
| } | |||||
| return 0; | |||||
| } | |||||
| template <typename MutableSeq, typename ConstSeq> | |||||
| constexpr std::size_t buffer_copy(const MutableSeq& dest, const ConstSeq& src) { | |||||
| auto src_size = buffer_size(src); | |||||
| auto dest_size = buffer_size(dest); | |||||
| auto min_size = (src_size > dest_size) ? dest_size : src_size; | |||||
| return buffer_copy(dest, src, min_size); | |||||
| } | |||||
| } // namespace neo |
| #pragma once | |||||
| #include <neo/mutable_buffer.hpp> | |||||
| #include <cassert> | |||||
| #include <cstddef> | |||||
| #include <string_view> | |||||
| namespace neo { | |||||
| /** | |||||
| * A type that represents a view to a readonly segment of contiguous memory. | |||||
| */ | |||||
| class const_buffer { | |||||
| public: | |||||
| using pointer = const std::byte*; | |||||
| using size_type = std::size_t; | |||||
| private: | |||||
| pointer _data = nullptr; | |||||
| size_type _size = 0; | |||||
| public: | |||||
| constexpr const_buffer() noexcept = default; | |||||
| constexpr const_buffer(pointer ptr, size_type size) noexcept | |||||
| : _data(ptr) | |||||
| , _size(size) {} | |||||
| constexpr const_buffer(mutable_buffer buf) | |||||
| : _data(buf.data()) | |||||
| , _size(buf.size()) {} | |||||
| explicit constexpr const_buffer(std::string_view sv) | |||||
| : _data(byte_pointer(sv.data())) | |||||
| , _size(sv.size()) {} | |||||
| constexpr pointer data() const noexcept { return _data; } | |||||
| constexpr size_type size() const noexcept { return _size; } | |||||
| constexpr const_buffer& operator+=(size_type s) noexcept { | |||||
| assert(s <= size() && "Advanced neo::const_buffer past-the-end"); | |||||
| _data += s; | |||||
| _size -= s; | |||||
| return *this; | |||||
| } | |||||
| }; | |||||
| inline constexpr const_buffer operator+(const_buffer buf, const_buffer::size_type s) noexcept { | |||||
| auto copy = buf; | |||||
| copy += s; | |||||
| return copy; | |||||
| } | |||||
| inline constexpr auto get_buffer_sequence_begin(const_buffer buf) noexcept { | |||||
| return detail::single_buffer_iter{buf}; | |||||
| } | |||||
| inline constexpr auto get_buffer_sequence_end(const_buffer) noexcept { | |||||
| return detail::single_buffer_iter_sentinel(); | |||||
| } | |||||
| } // namespace neo |
| #pragma once | |||||
| #include <cstddef> | |||||
| #include <iterator> | |||||
| #include <type_traits> | |||||
| namespace neo { | |||||
| template <typename T, typename = std::enable_if_t<std::is_trivial_v<T>>> | |||||
| constexpr std::byte* byte_pointer(T* ptr) { | |||||
| auto void_ = static_cast<void*>(ptr); | |||||
| return static_cast<std::byte*>(void_); | |||||
| } | |||||
| template <typename T, typename = std::enable_if_t<std::is_trivial_v<T>>> | |||||
| constexpr const std::byte* byte_pointer(const T* ptr) noexcept { | |||||
| auto void_ = static_cast<const void*>(ptr); | |||||
| return static_cast<const std::byte*>(void_); | |||||
| } | |||||
| class mutable_buffer { | |||||
| public: | |||||
| using pointer = std::byte*; | |||||
| using size_type = std::size_t; | |||||
| private: | |||||
| pointer _ptr = nullptr; | |||||
| size_type _size = 0; | |||||
| public: | |||||
| constexpr mutable_buffer() noexcept = default; | |||||
| constexpr mutable_buffer(pointer p, size_type size) noexcept | |||||
| : _ptr(p) | |||||
| , _size(size) {} | |||||
| constexpr mutable_buffer& operator+=(size_type s) noexcept { | |||||
| _ptr += s; | |||||
| _size -= s; | |||||
| return *this; | |||||
| } | |||||
| constexpr pointer data() const noexcept { return _ptr; } | |||||
| constexpr size_type size() const noexcept { return _size; } | |||||
| }; | |||||
| inline constexpr mutable_buffer operator+(mutable_buffer buf, | |||||
| mutable_buffer::size_type s) noexcept { | |||||
| auto copy = buf; | |||||
| copy += s; | |||||
| return copy; | |||||
| } | |||||
| namespace detail { | |||||
| class single_buffer_iter_sentinel {}; | |||||
| template <typename Buffer> | |||||
| class single_buffer_iter { | |||||
| Buffer _buf; | |||||
| bool _dead = false; | |||||
| public: | |||||
| using difference_type = std::ptrdiff_t; | |||||
| using value_type = Buffer; | |||||
| using pointer = const value_type*; | |||||
| using reference = const value_type&; | |||||
| using iterator_category = std::forward_iterator_tag; | |||||
| constexpr single_buffer_iter(Buffer b) noexcept | |||||
| : _buf(b) {} | |||||
| constexpr reference operator*() const noexcept { return _buf; } | |||||
| constexpr pointer operator->() const noexcept { return &_buf; } | |||||
| constexpr bool operator==(single_buffer_iter_sentinel) const noexcept { return _dead; } | |||||
| constexpr bool operator!=(single_buffer_iter_sentinel) const noexcept { return !_dead; } | |||||
| constexpr bool operator==(single_buffer_iter o) const noexcept { return _dead == o._dead; } | |||||
| constexpr bool operator!=(single_buffer_iter o) const noexcept { return !(*this == o); } | |||||
| constexpr single_buffer_iter operator++(int) noexcept { | |||||
| auto me = *this; | |||||
| _dead = true; | |||||
| return me; | |||||
| } | |||||
| constexpr single_buffer_iter& operator++() noexcept { | |||||
| _dead = true; | |||||
| return *this; | |||||
| } | |||||
| }; | |||||
| } // namespace detail | |||||
| inline auto get_buffer_sequence_begin(mutable_buffer b) noexcept { | |||||
| return detail::single_buffer_iter(b); | |||||
| } | |||||
| inline constexpr auto get_buffer_sequence_end(mutable_buffer) noexcept { | |||||
| return detail::single_buffer_iter_sentinel(); | |||||
| } | |||||
| } // namespace neo |