subrepo: subdir: "external/repo/neo-buffer" merged: "9461ede" upstream: origin: "git@github.com:vector-of-bool/neo-buffer.git" branch: "develop" commit: "9461ede" git-subrepo: version: "0.4.0" origin: "https://github.com/ingydotnet/git-subrepo.git" commit: "5d6aba9"default_compile_flags
_build/ | |||||
.vscode/ |
; DO NOT EDIT (unless you know what you are doing) | |||||
; | |||||
; This subdirectory is a git "subrepo", and this file is maintained by the | |||||
; git-subrepo command. See https://github.com/git-commands/git-subrepo#readme | |||||
; | |||||
[subrepo] | |||||
remote = git@github.com:vector-of-bool/neo-buffer.git | |||||
branch = develop | |||||
commit = 9461eded7f661b31bcdf4f8760ebe4ebc83e9630 | |||||
parent = 4bc28954ef34869a5b5ad65094c6f56a23937f8b | |||||
method = merge | |||||
cmdver = 0.4.0 |
Name: buffer |
Name: neo-buffer | |||||
Namespace: neo | |||||
Version: 0.1.0 |
#pragma once | |||||
#include <cstddef> | |||||
#include <iterator> | |||||
namespace neo { | |||||
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 | |||||
template <typename T> | |||||
constexpr std::byte* byte_pointer(T* ptr) noexcept requires std::is_trivial_v<T> { | |||||
auto void_ = static_cast<void*>(ptr); | |||||
return static_cast<std::byte*>(void_); | |||||
} | |||||
template <typename T> | |||||
constexpr const std::byte* byte_pointer(const T* ptr) noexcept requires std::is_trivial_v<T> { | |||||
auto void_ = static_cast<const void*>(ptr); | |||||
return static_cast<const std::byte*>(void_); | |||||
} | |||||
} // namespace neo |
#include "./buffer.hpp" |
#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 |
#include <neo/buffer.hpp> | |||||
#include <neo/buffer.test.hpp> | |||||
#include <neo/buffer_algorithm.hpp> | |||||
#include <array> | |||||
#include <string> | |||||
struct my_simple_struct { | |||||
int a; | |||||
int b; | |||||
}; | |||||
int main() { | |||||
// std::string s = "I am a string!"; | |||||
// auto s_buf = neo::buffer(s); | |||||
// CHECK(s_buf.data() == s.data()); | |||||
my_simple_struct foo; | |||||
foo.a = 12; | |||||
foo.b = 3; | |||||
neo::mutable_buffer pod_buf = neo::buffer(foo); | |||||
CHECK(pod_buf.size() == sizeof(foo)); | |||||
my_simple_struct bar; | |||||
neo::buffer_copy(neo::buffer(bar), pod_buf); | |||||
CHECK(bar.a == foo.a); | |||||
CHECK(bar.b == foo.b); | |||||
bar.b = 55; | |||||
std::array<char, sizeof bar> buf; | |||||
neo::buffer_copy(neo::buffer(buf), neo::buffer(bar)); | |||||
neo::buffer_copy(neo::buffer(foo), neo::buffer(buf)); | |||||
CHECK(foo.b == 55); | |||||
} |
#pragma once | |||||
#include <iostream> | |||||
#define CHECK(...) \ | |||||
do { \ | |||||
if (!(__VA_ARGS__)) { \ | |||||
std::cerr << "Check failed: " << (#__VA_ARGS__) << '\n'; \ | |||||
return 1; \ | |||||
} \ | |||||
} while (0) |
#pragma once | |||||
#include <neo/buffer_concepts.hpp> | |||||
#include <neo/const_buffer.hpp> | |||||
#include <neo/mutable_buffer.hpp> | |||||
#include <algorithm> | |||||
#include <cstddef> | |||||
#include <cstring> | |||||
namespace neo { | |||||
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 <mutable_buffer_sequence MutableSeq, const_buffer_sequence 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 |
#include <neo/buffer_algorithm.hpp> | |||||
#include <neo/buffer.test.hpp> | |||||
#include <neo/const_buffer.hpp> | |||||
#include <string_view> | |||||
int main() { | |||||
auto buf = neo::const_buffer("A string"); | |||||
auto buf_iter = neo::buffer_sequence_begin(buf); | |||||
CHECK(buf_iter->data() == buf.data()); | |||||
CHECK(buf_iter != neo::buffer_sequence_end(buf)); | |||||
CHECK(neo::buffer_size(buf) == buf.size()); | |||||
// neo::buffer_size(12); | |||||
} |
#pragma once | |||||
#ifndef NEO_CONCEPT | |||||
#if defined(__GNUC__) && __GNUC__ < 9 | |||||
#define NEO_CONCEPT concept bool | |||||
#else | |||||
#define NEO_CONCEPT concept | |||||
#endif | |||||
#endif | |||||
#include <neo/buffer_seq_iter.hpp> | |||||
#include <neo/const_buffer.hpp> | |||||
#include <neo/mutable_buffer.hpp> | |||||
#include <iterator> | |||||
namespace neo { | |||||
template <typename T> | |||||
NEO_CONCEPT const_buffer_sequence_iterator = requires(T iter) { | |||||
typename std::iterator_traits<T>::value_type; | |||||
std::is_convertible_v<typename std::iterator_traits<T>::value_type, const_buffer>; | |||||
}; | |||||
template <typename T> | |||||
NEO_CONCEPT mutable_buffer_sequence_iterator | |||||
= const_buffer_sequence_iterator<T>&& requires(T iter) { | |||||
std::is_convertible_v<typename std::iterator_traits<T>::value_type, mutable_buffer>; | |||||
}; | |||||
template <typename T> | |||||
NEO_CONCEPT const_buffer_sequence = requires(T seq) { | |||||
{ buffer_sequence_begin(seq) } | |||||
->const_buffer_sequence_iterator; | |||||
buffer_sequence_end(seq); | |||||
{ buffer_sequence_begin(seq) != buffer_sequence_end(seq) } | |||||
->bool; | |||||
}; | |||||
template <typename T> | |||||
NEO_CONCEPT mutable_buffer_sequence = const_buffer_sequence<T>&& requires(T seq) { | |||||
{ buffer_sequence_begin(seq) } | |||||
->mutable_buffer_sequence_iterator; | |||||
}; | |||||
} // namespace neo |
#pragma once | |||||
#include <utility> | |||||
namespace neo { | |||||
constexpr inline struct buffer_sequence_begin_fn { | |||||
template <typename T> | |||||
decltype(auto) operator()(T&& t) const requires requires { | |||||
buffer_sequence_begin(t); | |||||
} | |||||
{ return buffer_sequence_begin(t); } | |||||
template <typename T> | |||||
decltype(auto) operator()(T&& t) const requires requires { | |||||
t.buffer_sequence_begin(); | |||||
} | |||||
{ return t.buffer_sequence_begin(); } | |||||
template <typename T> | |||||
decltype(auto) operator()(T&& t) const requires requires { | |||||
_impl_buffer_sequence_begin(t); | |||||
} | |||||
{ return _impl_buffer_sequence_begin(t); } | |||||
} buffer_sequence_begin; | |||||
inline struct buffer_sequence_end_fn { | |||||
template <typename T> | |||||
decltype(auto) operator()(T&& t) const requires requires { | |||||
buffer_sequence_end(t); | |||||
} | |||||
{ return buffer_sequence_end(t); } | |||||
template <typename T> | |||||
decltype(auto) operator()(T&& t) const requires requires { | |||||
t.buffer_sequence_end(); | |||||
} | |||||
{ return t.buffer_sequence_end(); } | |||||
template <typename T> | |||||
decltype(auto) operator()(T&& t) const requires requires { | |||||
_impl_buffer_sequence_end(t); | |||||
} | |||||
{ return _impl_buffer_sequence_end(t); } | |||||
} buffer_sequence_end; | |||||
} // namespace neo |
#pragma once | |||||
#include <neo/base_buffer.hpp> | |||||
#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 pointer data_end() const noexcept { return _data + size(); } | |||||
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 _impl_buffer_sequence_begin(const_buffer buf) noexcept { | |||||
return detail::single_buffer_iter(buf); | |||||
} | |||||
inline constexpr auto _impl_buffer_sequence_end(const_buffer) noexcept { | |||||
return detail::single_buffer_iter_sentinel(); | |||||
} | |||||
} // namespace neo |
#include <neo/buffer.test.hpp> | |||||
#include <neo/const_buffer.hpp> | |||||
#include <iostream> | |||||
int main() { | |||||
neo::const_buffer buf; | |||||
CHECK(buf.size() == 0); | |||||
buf = neo::const_buffer("meow"); | |||||
CHECK(buf.size() == 4); | |||||
auto buf2 = buf + 3; | |||||
CHECK(buf2.size() == 1); | |||||
CHECK(buf2.data()[0] == std::byte('w')); | |||||
buf2 += 1; | |||||
CHECK(buf2.size() == 0); | |||||
} |
#pragma once | |||||
#include <neo/base_buffer.hpp> | |||||
#include <cstddef> | |||||
#include <iterator> | |||||
#include <type_traits> | |||||
namespace neo { | |||||
class mutable_buffer { | |||||
public: | |||||
using pointer = std::byte*; | |||||
using size_type = std::size_t; | |||||
private: | |||||
pointer _data = nullptr; | |||||
size_type _size = 0; | |||||
public: | |||||
constexpr mutable_buffer() noexcept = default; | |||||
constexpr mutable_buffer(pointer p, size_type size) noexcept | |||||
: _data(p) | |||||
, _size(size) {} | |||||
constexpr mutable_buffer& operator+=(size_type s) noexcept { | |||||
_data += s; | |||||
_size -= s; | |||||
return *this; | |||||
} | |||||
constexpr pointer data() const noexcept { return _data; } | |||||
constexpr pointer data_end() const noexcept { return _data + size(); } | |||||
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; | |||||
} | |||||
inline constexpr auto _impl_buffer_sequence_begin(mutable_buffer buf) noexcept { | |||||
return detail::single_buffer_iter(buf); | |||||
} | |||||
inline constexpr auto _impl_buffer_sequence_end(mutable_buffer) noexcept { | |||||
return detail::single_buffer_iter_sentinel(); | |||||
} | |||||
} // namespace neo |
#include <neo/mutable_buffer.hpp> | |||||
int main() {} |
Compiler-ID: GNU | |||||
C++-Compiler: g++-8 | |||||
C++-Version: C++17 | |||||
Flags: -fconcepts |