Bladeren bron

neo-buffer library

default_compile_flags
vector-of-bool 5 jaren geleden
bovenliggende
commit
3e75838e46
9 gewijzigde bestanden met toevoegingen van 447 en 0 verwijderingen
  1. +109
    -0
      src/neo/buffer.hpp
  2. +38
    -0
      src/neo/buffer.test.cpp
  3. +11
    -0
      src/neo/buffer.test.hpp
  4. +87
    -0
      src/neo/buffer_algorithm.hpp
  5. +18
    -0
      src/neo/buffer_algorithm.test.cpp
  6. +62
    -0
      src/neo/const_buffer.hpp
  7. +17
    -0
      src/neo/const_buffer.test.cpp
  8. +102
    -0
      src/neo/mutable_buffer.hpp
  9. +3
    -0
      src/neo/mutable_buffer.test.cpp

+ 109
- 0
src/neo/buffer.hpp Bestand weergeven

@@ -0,0 +1,109 @@
#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

+ 38
- 0
src/neo/buffer.test.cpp Bestand weergeven

@@ -0,0 +1,38 @@
#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);
}

+ 11
- 0
src/neo/buffer.test.hpp Bestand weergeven

@@ -0,0 +1,11 @@
#pragma once

#include <iostream>

#define CHECK(...) \
do { \
if (!(__VA_ARGS__)) { \
std::cerr << "Check failed: " << (#__VA_ARGS__) << '\n'; \
return 1; \
} \
} while (0)

+ 87
- 0
src/neo/buffer_algorithm.hpp Bestand weergeven

@@ -0,0 +1,87 @@
#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

+ 18
- 0
src/neo/buffer_algorithm.test.cpp Bestand weergeven

@@ -0,0 +1,18 @@
#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);
}

+ 62
- 0
src/neo/const_buffer.hpp Bestand weergeven

@@ -0,0 +1,62 @@
#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

+ 17
- 0
src/neo/const_buffer.test.cpp Bestand weergeven

@@ -0,0 +1,17 @@
#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);
}

+ 102
- 0
src/neo/mutable_buffer.hpp Bestand weergeven

@@ -0,0 +1,102 @@
#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

+ 3
- 0
src/neo/mutable_buffer.test.cpp Bestand weergeven

@@ -0,0 +1,3 @@
#include <neo/mutable_buffer.hpp>

int main() {}

Laden…
Annuleren
Opslaan