mirror of
https://github.com/matrix-construct/construct
synced 2024-11-25 16:22:35 +01:00
ircd::buffer: Split into directory.
This commit is contained in:
parent
4aaeaff8fb
commit
3eadd31c7f
8 changed files with 496 additions and 341 deletions
|
@ -45,6 +45,10 @@ namespace ircd::buffer
|
|||
template<template<class> class I> using const_buffers = I<const_buffer>;
|
||||
template<template<class> class I> using mutable_buffers = I<mutable_buffer>;
|
||||
|
||||
// Preconstructed null buffers
|
||||
extern const mutable_buffer null_buffer;
|
||||
extern const ilist<mutable_buffer> null_buffers;
|
||||
|
||||
// Single buffer iteration of contents
|
||||
template<class it> const it &begin(const buffer<it> &buffer);
|
||||
template<class it> const it &end(const buffer<it> &buffer);
|
||||
|
@ -77,12 +81,15 @@ namespace ircd::buffer
|
|||
// Convenience copy to std stream
|
||||
template<class it> std::ostream &operator<<(std::ostream &s, const buffer<it> &buffer);
|
||||
template<template<class> class I, class T> std::ostream &operator<<(std::ostream &s, const I<T> &buffers);
|
||||
|
||||
// Preconstructed null buffers
|
||||
extern const mutable_buffer null_buffer;
|
||||
extern const ilist<mutable_buffer> null_buffers;
|
||||
}
|
||||
|
||||
#include "buffer_base.h"
|
||||
#include "mutable_buffer.h"
|
||||
#include "const_buffer.h"
|
||||
#include "fixed_buffer.h"
|
||||
#include "window_buffer.h"
|
||||
#include "unique_buffer.h"
|
||||
|
||||
// Export these important aliases down to main ircd namespace
|
||||
namespace ircd
|
||||
{
|
||||
|
@ -104,342 +111,6 @@ namespace ircd
|
|||
using buffer::consume;
|
||||
}
|
||||
|
||||
/// Base for all buffer types
|
||||
///
|
||||
template<class it>
|
||||
struct ircd::buffer::buffer
|
||||
:std::tuple<it, it>
|
||||
{
|
||||
using iterator = it;
|
||||
using value_type = typename std::remove_pointer<iterator>::type;
|
||||
|
||||
operator string_view() const;
|
||||
explicit operator std::string_view() const;
|
||||
explicit operator std::string() const;
|
||||
|
||||
auto &begin() const { return std::get<0>(*this); }
|
||||
auto &begin() { return std::get<0>(*this); }
|
||||
auto &end() const { return std::get<1>(*this); }
|
||||
auto &end() { return std::get<1>(*this); }
|
||||
|
||||
auto &operator[](const size_t &i) const
|
||||
{
|
||||
return *(begin() + i);
|
||||
}
|
||||
|
||||
auto &operator[](const size_t &i)
|
||||
{
|
||||
return *(begin() + i);
|
||||
}
|
||||
|
||||
buffer(const it &start, const it &stop)
|
||||
:std::tuple<it, it>{start, stop}
|
||||
{}
|
||||
|
||||
buffer(const it &start, const size_t &size)
|
||||
:buffer{start, start + size}
|
||||
{}
|
||||
|
||||
buffer()
|
||||
:buffer{nullptr, nullptr}
|
||||
{}
|
||||
};
|
||||
|
||||
/// Base for mutable buffers, or buffers which can be written to because they
|
||||
/// are not const.
|
||||
///
|
||||
struct ircd::buffer::mutable_buffer
|
||||
:buffer<char *>
|
||||
{
|
||||
// Conversion offered for the analogous asio buffer
|
||||
operator boost::asio::mutable_buffer() const;
|
||||
|
||||
// Allows boost::spirit to append to the buffer; this means the size() of
|
||||
// this buffer becomes a consumption counter and the real size of the buffer
|
||||
// must be kept separately. This is the lowlevel basis for a stream buffer.
|
||||
void insert(char *const &it, const value_type &v)
|
||||
{
|
||||
assert(it >= this->begin() && it <= this->end());
|
||||
memmove(it + 1, it, std::distance(it, this->end()));
|
||||
*it = v;
|
||||
++std::get<1>(*this);
|
||||
}
|
||||
|
||||
using buffer<char *>::buffer;
|
||||
|
||||
mutable_buffer()
|
||||
:buffer<char *>{}
|
||||
{}
|
||||
|
||||
mutable_buffer(const buffer<char *> &b)
|
||||
:buffer<char *>{b}
|
||||
{}
|
||||
|
||||
template<size_t SIZE>
|
||||
mutable_buffer(char (&buf)[SIZE])
|
||||
:buffer<char *>{buf, SIZE}
|
||||
{}
|
||||
|
||||
template<size_t SIZE>
|
||||
mutable_buffer(std::array<char, SIZE> &buf)
|
||||
:buffer<char *>{buf.data(), SIZE}
|
||||
{}
|
||||
|
||||
// lvalue string reference offered to write through to a std::string as
|
||||
// the buffer. not explicit; should be hard to bind by accident...
|
||||
mutable_buffer(std::string &buf)
|
||||
:mutable_buffer{const_cast<char *>(buf.data()), buf.size()}
|
||||
{}
|
||||
|
||||
mutable_buffer(const std::function<void (const mutable_buffer &)> &closure)
|
||||
{
|
||||
closure(*this);
|
||||
}
|
||||
};
|
||||
|
||||
struct ircd::buffer::const_buffer
|
||||
:buffer<const char *>
|
||||
{
|
||||
operator boost::asio::const_buffer() const;
|
||||
|
||||
using buffer<const char *>::buffer;
|
||||
|
||||
const_buffer()
|
||||
:buffer<const char *>{}
|
||||
{}
|
||||
|
||||
const_buffer(const buffer<const char *> &b)
|
||||
:buffer<const char *>{b}
|
||||
{}
|
||||
|
||||
const_buffer(const buffer<char *> &b)
|
||||
:buffer<const char *>{data(b), size(b)}
|
||||
{}
|
||||
|
||||
template<size_t SIZE>
|
||||
const_buffer(const char (&buf)[SIZE])
|
||||
:buffer<const char *>{buf, SIZE}
|
||||
{}
|
||||
|
||||
template<size_t SIZE>
|
||||
const_buffer(const std::array<char, SIZE> &buf)
|
||||
:buffer<const char *>{reinterpret_cast<const char *>(buf.data()), SIZE}
|
||||
{}
|
||||
|
||||
const_buffer(const mutable_buffer &b)
|
||||
:buffer<const char *>{data(b), size(b)}
|
||||
{}
|
||||
|
||||
const_buffer(const string_view &s)
|
||||
:buffer<const char *>{data(s), size(s)}
|
||||
{}
|
||||
};
|
||||
|
||||
/// fixed_buffer wraps an std::array with construction and conversions apropos
|
||||
/// the ircd::buffer suite. fixed_buffer should be punnable. Its only memory
|
||||
/// footprint is the array itself and
|
||||
///
|
||||
template<class buffer,
|
||||
size_t SIZE>
|
||||
struct ircd::buffer::fixed_buffer
|
||||
:std::array<typename std::remove_const<typename buffer::value_type>::type, SIZE>
|
||||
{
|
||||
using mutable_type = typename std::remove_const<typename buffer::value_type>::type;
|
||||
using const_type = typename std::add_const<mutable_type>::type;
|
||||
using array_type = std::array<mutable_type, SIZE>;
|
||||
|
||||
operator buffer() const
|
||||
{
|
||||
return { std::begin(*this), std::end(*this) };
|
||||
}
|
||||
|
||||
operator buffer()
|
||||
{
|
||||
return { std::begin(*this), std::end(*this) };
|
||||
}
|
||||
|
||||
using array_type::array_type;
|
||||
fixed_buffer(const nullptr_t &)
|
||||
:array_type{{0}}
|
||||
{}
|
||||
|
||||
fixed_buffer(const std::function<void (const mutable_buffer &)> &closure)
|
||||
{
|
||||
closure(mutable_buffer{reinterpret_cast<mutable_buffer::iterator>(this->data()), this->size()});
|
||||
}
|
||||
|
||||
fixed_buffer(buffer b)
|
||||
:array_type{std::begin(b), std::end(b)}
|
||||
{}
|
||||
|
||||
fixed_buffer() = default;
|
||||
};
|
||||
|
||||
static_assert
|
||||
(
|
||||
// Assertion over an arbitrary but common template configuration.
|
||||
std::is_standard_layout<ircd::buffer::fixed_buffer<ircd::buffer::const_buffer, 32>>::value,
|
||||
"ircd::buffer::fixed_buffer must be standard layout"
|
||||
);
|
||||
|
||||
/// The window_buffer is just two mutable_buffers. One of the two buffers
|
||||
/// just spans an underlying space and the other buffer is a window of the
|
||||
/// remaining space which shrinks toward the end as the space is consumed.
|
||||
/// The window_buffer object inherits from the latter, so it always has the
|
||||
/// appearance of a mutable_buffer windowing on the the next place to write.
|
||||
///
|
||||
/// The recommended usage of this device is actually through the operator()
|
||||
/// closure, which will automatically resize the window based on the return
|
||||
/// value in the closure.
|
||||
///
|
||||
struct ircd::buffer::window_buffer
|
||||
:mutable_buffer
|
||||
{
|
||||
mutable_buffer base;
|
||||
|
||||
/// Bytes remaining for writes to the stream buffer (same as size(*this))
|
||||
size_t remaining() const
|
||||
{
|
||||
assert(begin() <= base.end());
|
||||
const size_t ret(std::distance(begin(), base.end()));
|
||||
assert(ret == size(*this));
|
||||
return ret;
|
||||
}
|
||||
|
||||
/// Bytes used by writes to the stream buffer
|
||||
size_t consumed() const
|
||||
{
|
||||
assert(begin() >= base.begin());
|
||||
assert(begin() <= base.end());
|
||||
return std::distance(base.begin(), begin());
|
||||
}
|
||||
|
||||
/// View the completed portion of the stream
|
||||
const_buffer completed() const
|
||||
{
|
||||
assert(base.begin() <= begin());
|
||||
assert(base.begin() + consumed() <= base.end());
|
||||
return { base.begin(), base.begin() + consumed() };
|
||||
}
|
||||
|
||||
/// View the completed portion of the stream
|
||||
mutable_buffer completed()
|
||||
{
|
||||
assert(base.begin() <= begin());
|
||||
assert(base.begin() + consumed() <= base.end());
|
||||
return { base.begin(), base.begin() + consumed() };
|
||||
}
|
||||
|
||||
/// Convenience conversion to get the completed portion
|
||||
explicit operator const_buffer() const
|
||||
{
|
||||
return completed();
|
||||
}
|
||||
|
||||
/// Convenience closure presenting the writable window and advancing the
|
||||
/// window with a consume() for the bytes written in the closure.
|
||||
using closure = std::function<size_t (const mutable_buffer &)>;
|
||||
void operator()(const closure &closure)
|
||||
{
|
||||
consume(*this, closure(*this));
|
||||
}
|
||||
|
||||
window_buffer(const mutable_buffer &base)
|
||||
:mutable_buffer{base}
|
||||
,base{base}
|
||||
{}
|
||||
};
|
||||
|
||||
/// Like unique_ptr, this template holds ownership of an allocated buffer
|
||||
///
|
||||
template<class buffer,
|
||||
uint alignment>
|
||||
struct ircd::buffer::unique_buffer
|
||||
:buffer
|
||||
{
|
||||
unique_buffer(std::unique_ptr<uint8_t[]> &&, const size_t &size);
|
||||
unique_buffer(const size_t &size);
|
||||
unique_buffer();
|
||||
unique_buffer(unique_buffer &&) noexcept;
|
||||
unique_buffer(const unique_buffer &) = delete;
|
||||
unique_buffer &operator=(unique_buffer &&) noexcept;
|
||||
unique_buffer &operator=(const unique_buffer &) = delete;
|
||||
~unique_buffer() noexcept;
|
||||
};
|
||||
|
||||
template<class buffer,
|
||||
uint alignment>
|
||||
ircd::buffer::unique_buffer<buffer, alignment>::unique_buffer()
|
||||
:buffer
|
||||
{
|
||||
nullptr, nullptr
|
||||
}
|
||||
{}
|
||||
|
||||
template<class buffer,
|
||||
uint alignment>
|
||||
ircd::buffer::unique_buffer<buffer, alignment>::unique_buffer(std::unique_ptr<uint8_t[]> &&b,
|
||||
const size_t &size)
|
||||
:buffer
|
||||
{
|
||||
typename buffer::iterator(b.release()), size
|
||||
}
|
||||
{}
|
||||
|
||||
template<class buffer,
|
||||
uint alignment>
|
||||
ircd::buffer::unique_buffer<buffer, alignment>::unique_buffer(const size_t &size)
|
||||
:unique_buffer<buffer, alignment>
|
||||
{
|
||||
std::unique_ptr<uint8_t[]>
|
||||
{
|
||||
//TODO: Can't use a template parameter to the attribute even though
|
||||
// it's known at compile time. Hardcoding this until fixed with better
|
||||
// aligned dynamic memory.
|
||||
//new __attribute__((aligned(alignment))) uint8_t[size]
|
||||
new __attribute__((aligned(16))) uint8_t[size]
|
||||
},
|
||||
size
|
||||
}
|
||||
{
|
||||
// Alignment can only be 16 bytes for now
|
||||
assert(alignment == 16);
|
||||
}
|
||||
|
||||
template<class buffer,
|
||||
uint alignment>
|
||||
ircd::buffer::unique_buffer<buffer, alignment>::unique_buffer(unique_buffer &&other)
|
||||
noexcept
|
||||
:buffer
|
||||
{
|
||||
std::move(static_cast<buffer &>(other))
|
||||
}
|
||||
{
|
||||
get<0>(other) = nullptr;
|
||||
}
|
||||
|
||||
template<class buffer,
|
||||
uint alignment>
|
||||
ircd::buffer::unique_buffer<buffer, alignment> &
|
||||
ircd::buffer::unique_buffer<buffer, alignment>::operator=(unique_buffer &&other)
|
||||
noexcept
|
||||
{
|
||||
this->~unique_buffer();
|
||||
|
||||
static_cast<buffer &>(*this) = std::move(static_cast<buffer &>(other));
|
||||
get<0>(other) = nullptr;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
template<class buffer,
|
||||
uint alignment>
|
||||
ircd::buffer::unique_buffer<buffer, alignment>::~unique_buffer()
|
||||
noexcept
|
||||
{
|
||||
delete[] data(*this);
|
||||
}
|
||||
|
||||
template<template<class>
|
||||
class buffers,
|
||||
class T>
|
70
include/ircd/buffer/buffer_base.h
Normal file
70
include/ircd/buffer/buffer_base.h
Normal file
|
@ -0,0 +1,70 @@
|
|||
// Matrix Construct
|
||||
//
|
||||
// Copyright (C) Matrix Construct Developers, Authors & Contributors
|
||||
// Copyright (C) 2016-2018 Jason Volk <jason@zemos.net>
|
||||
//
|
||||
// Permission to use, copy, modify, and/or distribute this software for any
|
||||
// purpose with or without fee is hereby granted, provided that the above
|
||||
// copyright notice and this permission notice is present in all copies. The
|
||||
// full license for this software is available in the LICENSE file.
|
||||
|
||||
#pragma once
|
||||
#define HAVE_IRCD_BUFFER_BASE_H
|
||||
|
||||
/// Base for all buffer types
|
||||
///
|
||||
template<class it>
|
||||
struct ircd::buffer::buffer
|
||||
:std::tuple<it, it>
|
||||
{
|
||||
using iterator = it;
|
||||
using value_type = typename std::remove_pointer<iterator>::type;
|
||||
|
||||
operator string_view() const;
|
||||
explicit operator std::string_view() const;
|
||||
explicit operator std::string() const;
|
||||
|
||||
auto &begin() const { return std::get<0>(*this); }
|
||||
auto &begin() { return std::get<0>(*this); }
|
||||
auto &end() const { return std::get<1>(*this); }
|
||||
auto &end() { return std::get<1>(*this); }
|
||||
|
||||
auto &operator[](const size_t &i) const;
|
||||
auto &operator[](const size_t &i);
|
||||
|
||||
buffer(const it &start, const it &stop);
|
||||
buffer(const it &start, const size_t &size);
|
||||
buffer();
|
||||
};
|
||||
|
||||
template<class it>
|
||||
ircd::buffer::buffer<it>::buffer()
|
||||
:buffer{nullptr, nullptr}
|
||||
{}
|
||||
|
||||
template<class it>
|
||||
ircd::buffer::buffer<it>::buffer(const it &start,
|
||||
const size_t &size)
|
||||
:buffer{start, start + size}
|
||||
{}
|
||||
|
||||
template<class it>
|
||||
ircd::buffer::buffer<it>::buffer(const it &start,
|
||||
const it &stop)
|
||||
:std::tuple<it, it>{start, stop}
|
||||
{}
|
||||
|
||||
template<class it>
|
||||
auto &
|
||||
ircd::buffer::buffer<it>::operator[](const size_t &i)
|
||||
const
|
||||
{
|
||||
return *(begin() + i);
|
||||
}
|
||||
|
||||
template<class it>
|
||||
auto &
|
||||
ircd::buffer::buffer<it>::operator[](const size_t &i)
|
||||
{
|
||||
return *(begin() + i);
|
||||
}
|
58
include/ircd/buffer/const_buffer.h
Normal file
58
include/ircd/buffer/const_buffer.h
Normal file
|
@ -0,0 +1,58 @@
|
|||
// Matrix Construct
|
||||
//
|
||||
// Copyright (C) Matrix Construct Developers, Authors & Contributors
|
||||
// Copyright (C) 2016-2018 Jason Volk <jason@zemos.net>
|
||||
//
|
||||
// Permission to use, copy, modify, and/or distribute this software for any
|
||||
// purpose with or without fee is hereby granted, provided that the above
|
||||
// copyright notice and this permission notice is present in all copies. The
|
||||
// full license for this software is available in the LICENSE file.
|
||||
|
||||
#pragma once
|
||||
#define HAVE_IRCD_BUFFER_CONST_BUFFER_H
|
||||
|
||||
struct ircd::buffer::const_buffer
|
||||
:buffer<const char *>
|
||||
{
|
||||
// Definition for this is somewhere in the .cc files where boost is incl.
|
||||
operator boost::asio::const_buffer() const;
|
||||
|
||||
using buffer<const char *>::buffer;
|
||||
template<size_t SIZE> const_buffer(const char (&buf)[SIZE]);
|
||||
template<size_t SIZE> const_buffer(const std::array<char, SIZE> &buf);
|
||||
const_buffer(const buffer<const char *> &b);
|
||||
const_buffer(const buffer<char *> &b);
|
||||
const_buffer(const mutable_buffer &b);
|
||||
const_buffer(const string_view &s);
|
||||
const_buffer() = default;
|
||||
};
|
||||
|
||||
inline
|
||||
ircd::buffer::const_buffer::const_buffer(const buffer<const char *> &b)
|
||||
:buffer<const char *>{b}
|
||||
{}
|
||||
|
||||
inline
|
||||
ircd::buffer::const_buffer::const_buffer(const buffer<char *> &b)
|
||||
:buffer<const char *>{data(b), size(b)}
|
||||
{}
|
||||
|
||||
inline
|
||||
ircd::buffer::const_buffer::const_buffer(const mutable_buffer &b)
|
||||
:buffer<const char *>{data(b), size(b)}
|
||||
{}
|
||||
|
||||
inline
|
||||
ircd::buffer::const_buffer::const_buffer(const string_view &s)
|
||||
:buffer<const char *>{data(s), size(s)}
|
||||
{}
|
||||
|
||||
template<size_t SIZE>
|
||||
ircd::buffer::const_buffer::const_buffer(const char (&buf)[SIZE])
|
||||
:buffer<const char *>{buf, SIZE}
|
||||
{}
|
||||
|
||||
template<size_t SIZE>
|
||||
ircd::buffer::const_buffer::const_buffer(const std::array<char, SIZE> &buf)
|
||||
:buffer<const char *>{reinterpret_cast<const char *>(buf.data()), SIZE}
|
||||
{}
|
78
include/ircd/buffer/fixed_buffer.h
Normal file
78
include/ircd/buffer/fixed_buffer.h
Normal file
|
@ -0,0 +1,78 @@
|
|||
// Matrix Construct
|
||||
//
|
||||
// Copyright (C) Matrix Construct Developers, Authors & Contributors
|
||||
// Copyright (C) 2016-2018 Jason Volk <jason@zemos.net>
|
||||
//
|
||||
// Permission to use, copy, modify, and/or distribute this software for any
|
||||
// purpose with or without fee is hereby granted, provided that the above
|
||||
// copyright notice and this permission notice is present in all copies. The
|
||||
// full license for this software is available in the LICENSE file.
|
||||
|
||||
#pragma once
|
||||
#define HAVE_IRCD_BUFFER_FIXED_BUFFER_H
|
||||
|
||||
/// fixed_buffer wraps an std::array with construction and conversions apropos
|
||||
/// the ircd::buffer suite. fixed_buffer should be punnable. Its only memory
|
||||
/// footprint is the array itself and
|
||||
///
|
||||
template<class buffer,
|
||||
size_t SIZE>
|
||||
struct ircd::buffer::fixed_buffer
|
||||
:std::array<typename std::remove_const<typename buffer::value_type>::type, SIZE>
|
||||
{
|
||||
using mutable_type = typename std::remove_const<typename buffer::value_type>::type;
|
||||
using const_type = typename std::add_const<mutable_type>::type;
|
||||
using array_type = std::array<mutable_type, SIZE>;
|
||||
|
||||
operator buffer() const;
|
||||
operator buffer();
|
||||
|
||||
using array_type::array_type;
|
||||
fixed_buffer(const nullptr_t &);
|
||||
fixed_buffer(const std::function<void (const mutable_buffer &)> &closure);
|
||||
fixed_buffer(buffer b);
|
||||
fixed_buffer() = default;
|
||||
};
|
||||
|
||||
static_assert
|
||||
(
|
||||
// Assertion over an arbitrary but common template configuration.
|
||||
std::is_standard_layout<ircd::buffer::fixed_buffer<ircd::buffer::const_buffer, 32>>::value,
|
||||
"ircd::buffer::fixed_buffer must be standard layout"
|
||||
);
|
||||
|
||||
template<class buffer,
|
||||
size_t SIZE>
|
||||
ircd::buffer::fixed_buffer<buffer, SIZE>::fixed_buffer(const nullptr_t &)
|
||||
:array_type{{0}}
|
||||
{}
|
||||
|
||||
template<class buffer,
|
||||
size_t SIZE>
|
||||
ircd::buffer::fixed_buffer<buffer, SIZE>::fixed_buffer(const std::function<void (const mutable_buffer &)> &closure)
|
||||
{
|
||||
closure(mutable_buffer{reinterpret_cast<mutable_buffer::iterator>(this->data()), this->size()});
|
||||
}
|
||||
|
||||
template<class buffer,
|
||||
size_t SIZE>
|
||||
ircd::buffer::fixed_buffer<buffer, SIZE>::fixed_buffer(buffer b)
|
||||
:array_type{std::begin(b), std::end(b)}
|
||||
{}
|
||||
|
||||
template<class buffer,
|
||||
size_t SIZE>
|
||||
ircd::buffer::fixed_buffer<buffer, SIZE>::operator
|
||||
buffer()
|
||||
{
|
||||
return { std::begin(*this), std::end(*this) };
|
||||
}
|
||||
|
||||
template<class buffer,
|
||||
size_t SIZE>
|
||||
ircd::buffer::fixed_buffer<buffer, SIZE>::operator
|
||||
buffer()
|
||||
const
|
||||
{
|
||||
return { std::begin(*this), std::end(*this) };
|
||||
}
|
75
include/ircd/buffer/mutable_buffer.h
Normal file
75
include/ircd/buffer/mutable_buffer.h
Normal file
|
@ -0,0 +1,75 @@
|
|||
// Matrix Construct
|
||||
//
|
||||
// Copyright (C) Matrix Construct Developers, Authors & Contributors
|
||||
// Copyright (C) 2016-2018 Jason Volk <jason@zemos.net>
|
||||
//
|
||||
// Permission to use, copy, modify, and/or distribute this software for any
|
||||
// purpose with or without fee is hereby granted, provided that the above
|
||||
// copyright notice and this permission notice is present in all copies. The
|
||||
// full license for this software is available in the LICENSE file.
|
||||
|
||||
#pragma once
|
||||
#define HAVE_IRCD_BUFFER_MUTABLE_BUFFER_H
|
||||
|
||||
/// Base for mutable buffers, or buffers which can be written to because they
|
||||
/// are not const.
|
||||
///
|
||||
struct ircd::buffer::mutable_buffer
|
||||
:buffer<char *>
|
||||
{
|
||||
// The definition for this is somewhere in one of the .cc files.
|
||||
/// Conversion offered for the analogous asio buffer.
|
||||
operator boost::asio::mutable_buffer() const;
|
||||
|
||||
/// Allows boost::spirit to append to the buffer; this means the size() of
|
||||
/// this buffer becomes a consumption counter and the real size of the buffer
|
||||
/// must be kept separately. This is the lowlevel basis for a stream buffer.
|
||||
void insert(char *const &it, const value_type &v);
|
||||
|
||||
using buffer<char *>::buffer;
|
||||
template<size_t SIZE> mutable_buffer(char (&buf)[SIZE]);
|
||||
template<size_t SIZE> mutable_buffer(std::array<char, SIZE> &buf);
|
||||
mutable_buffer(const std::function<void (const mutable_buffer &)> &);
|
||||
explicit mutable_buffer(std::string &buf);
|
||||
mutable_buffer(const buffer<char *> &b);
|
||||
mutable_buffer() = default;
|
||||
};
|
||||
|
||||
inline
|
||||
ircd::buffer::mutable_buffer::mutable_buffer(const buffer<char *> &b)
|
||||
:buffer<char *>{b}
|
||||
{}
|
||||
|
||||
/// lvalue string reference offered to write through to a std::string as
|
||||
/// the buffer. should be hard to bind by accident...
|
||||
inline
|
||||
ircd::buffer::mutable_buffer::mutable_buffer(std::string &buf)
|
||||
:mutable_buffer{const_cast<char *>(buf.data()), buf.size()}
|
||||
{}
|
||||
|
||||
inline
|
||||
ircd::buffer::mutable_buffer::mutable_buffer(const std::function<void (const mutable_buffer &)> &closure)
|
||||
{
|
||||
closure(*this);
|
||||
}
|
||||
|
||||
template<size_t SIZE>
|
||||
ircd::buffer::mutable_buffer::mutable_buffer(char (&buf)[SIZE])
|
||||
:buffer<char *>{buf, SIZE}
|
||||
{}
|
||||
|
||||
template<size_t SIZE>
|
||||
ircd::buffer::mutable_buffer::mutable_buffer(std::array<char, SIZE> &buf)
|
||||
:buffer<char *>{buf.data(), SIZE}
|
||||
{}
|
||||
|
||||
inline void
|
||||
ircd::buffer::mutable_buffer::insert(char *const &it,
|
||||
const value_type &v)
|
||||
{
|
||||
assert(it >= this->begin() && it <= this->end());
|
||||
memmove(it + 1, it, std::distance(it, this->end()));
|
||||
*it = v;
|
||||
++std::get<1>(*this);
|
||||
}
|
||||
|
102
include/ircd/buffer/unique_buffer.h
Normal file
102
include/ircd/buffer/unique_buffer.h
Normal file
|
@ -0,0 +1,102 @@
|
|||
// Matrix Construct
|
||||
//
|
||||
// Copyright (C) Matrix Construct Developers, Authors & Contributors
|
||||
// Copyright (C) 2016-2018 Jason Volk <jason@zemos.net>
|
||||
//
|
||||
// Permission to use, copy, modify, and/or distribute this software for any
|
||||
// purpose with or without fee is hereby granted, provided that the above
|
||||
// copyright notice and this permission notice is present in all copies. The
|
||||
// full license for this software is available in the LICENSE file.
|
||||
|
||||
#pragma once
|
||||
#define HAVE_IRCD_BUFFER_UNIQUE_BUFFER_H
|
||||
|
||||
/// Like unique_ptr, this template holds ownership of an allocated buffer
|
||||
///
|
||||
template<class buffer,
|
||||
uint alignment>
|
||||
struct ircd::buffer::unique_buffer
|
||||
:buffer
|
||||
{
|
||||
unique_buffer(std::unique_ptr<uint8_t[]> &&, const size_t &size);
|
||||
unique_buffer(const size_t &size);
|
||||
unique_buffer();
|
||||
unique_buffer(unique_buffer &&) noexcept;
|
||||
unique_buffer(const unique_buffer &) = delete;
|
||||
unique_buffer &operator=(unique_buffer &&) noexcept;
|
||||
unique_buffer &operator=(const unique_buffer &) = delete;
|
||||
~unique_buffer() noexcept;
|
||||
};
|
||||
|
||||
template<class buffer,
|
||||
uint alignment>
|
||||
ircd::buffer::unique_buffer<buffer, alignment>::unique_buffer()
|
||||
:buffer
|
||||
{
|
||||
nullptr, nullptr
|
||||
}
|
||||
{}
|
||||
|
||||
template<class buffer,
|
||||
uint alignment>
|
||||
ircd::buffer::unique_buffer<buffer, alignment>::unique_buffer(std::unique_ptr<uint8_t[]> &&b,
|
||||
const size_t &size)
|
||||
:buffer
|
||||
{
|
||||
typename buffer::iterator(b.release()), size
|
||||
}
|
||||
{}
|
||||
|
||||
template<class buffer,
|
||||
uint alignment>
|
||||
ircd::buffer::unique_buffer<buffer, alignment>::unique_buffer(const size_t &size)
|
||||
:unique_buffer<buffer, alignment>
|
||||
{
|
||||
std::unique_ptr<uint8_t[]>
|
||||
{
|
||||
//TODO: Can't use a template parameter to the attribute even though
|
||||
// it's known at compile time. Hardcoding this until fixed with better
|
||||
// aligned dynamic memory.
|
||||
//new __attribute__((aligned(alignment))) uint8_t[size]
|
||||
new __attribute__((aligned(16))) uint8_t[size]
|
||||
},
|
||||
size
|
||||
}
|
||||
{
|
||||
// Alignment can only be 16 bytes for now
|
||||
assert(alignment == 16);
|
||||
}
|
||||
|
||||
template<class buffer,
|
||||
uint alignment>
|
||||
ircd::buffer::unique_buffer<buffer, alignment>::unique_buffer(unique_buffer &&other)
|
||||
noexcept
|
||||
:buffer
|
||||
{
|
||||
std::move(static_cast<buffer &>(other))
|
||||
}
|
||||
{
|
||||
get<0>(other) = nullptr;
|
||||
}
|
||||
|
||||
template<class buffer,
|
||||
uint alignment>
|
||||
ircd::buffer::unique_buffer<buffer, alignment> &
|
||||
ircd::buffer::unique_buffer<buffer, alignment>::operator=(unique_buffer &&other)
|
||||
noexcept
|
||||
{
|
||||
this->~unique_buffer();
|
||||
|
||||
static_cast<buffer &>(*this) = std::move(static_cast<buffer &>(other));
|
||||
get<0>(other) = nullptr;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
template<class buffer,
|
||||
uint alignment>
|
||||
ircd::buffer::unique_buffer<buffer, alignment>::~unique_buffer()
|
||||
noexcept
|
||||
{
|
||||
delete[] data(*this);
|
||||
}
|
101
include/ircd/buffer/window_buffer.h
Normal file
101
include/ircd/buffer/window_buffer.h
Normal file
|
@ -0,0 +1,101 @@
|
|||
// Matrix Construct
|
||||
//
|
||||
// Copyright (C) Matrix Construct Developers, Authors & Contributors
|
||||
// Copyright (C) 2016-2018 Jason Volk <jason@zemos.net>
|
||||
//
|
||||
// Permission to use, copy, modify, and/or distribute this software for any
|
||||
// purpose with or without fee is hereby granted, provided that the above
|
||||
// copyright notice and this permission notice is present in all copies. The
|
||||
// full license for this software is available in the LICENSE file.
|
||||
|
||||
#pragma once
|
||||
#define HAVE_IRCD_BUFFER_WINDOW_BUFFER_H
|
||||
|
||||
/// The window_buffer is just two mutable_buffers. One of the two buffers
|
||||
/// just spans an underlying space and the other buffer is a window of the
|
||||
/// remaining space which shrinks toward the end as the space is consumed.
|
||||
/// The window_buffer object inherits from the latter, so it always has the
|
||||
/// appearance of a mutable_buffer windowing on the the next place to write.
|
||||
///
|
||||
/// The recommended usage of this device is actually through the operator()
|
||||
/// closure, which will automatically resize the window based on the return
|
||||
/// value in the closure.
|
||||
///
|
||||
struct ircd::buffer::window_buffer
|
||||
:mutable_buffer
|
||||
{
|
||||
using closure = std::function<size_t (const mutable_buffer &)>;
|
||||
|
||||
mutable_buffer base;
|
||||
|
||||
size_t remaining() const;
|
||||
size_t consumed() const;
|
||||
|
||||
const_buffer completed() const;
|
||||
explicit operator const_buffer() const;
|
||||
mutable_buffer completed();
|
||||
|
||||
void operator()(const closure &closure);
|
||||
|
||||
window_buffer(const mutable_buffer &base);
|
||||
};
|
||||
|
||||
inline
|
||||
ircd::buffer::window_buffer::window_buffer(const mutable_buffer &base)
|
||||
:mutable_buffer{base}
|
||||
,base{base}
|
||||
{}
|
||||
|
||||
inline void
|
||||
ircd::buffer::window_buffer::operator()(const closure &closure)
|
||||
{
|
||||
consume(*this, closure(*this));
|
||||
}
|
||||
|
||||
/// View the completed portion of the stream
|
||||
inline ircd::buffer::mutable_buffer
|
||||
ircd::buffer::window_buffer::completed()
|
||||
{
|
||||
assert(base.begin() <= begin());
|
||||
assert(base.begin() + consumed() <= base.end());
|
||||
return { base.begin(), base.begin() + consumed() };
|
||||
}
|
||||
|
||||
/// Convenience conversion to get the completed portion
|
||||
inline ircd::buffer::window_buffer::operator
|
||||
const_buffer()
|
||||
const
|
||||
{
|
||||
return completed();
|
||||
}
|
||||
|
||||
/// View the completed portion of the stream
|
||||
inline ircd::buffer::const_buffer
|
||||
ircd::buffer::window_buffer::completed()
|
||||
const
|
||||
{
|
||||
assert(base.begin() <= begin());
|
||||
assert(base.begin() + consumed() <= base.end());
|
||||
return { base.begin(), base.begin() + consumed() };
|
||||
}
|
||||
|
||||
/// Bytes used by writes to the stream buffer
|
||||
inline size_t
|
||||
ircd::buffer::window_buffer::consumed()
|
||||
const
|
||||
{
|
||||
assert(begin() >= base.begin());
|
||||
assert(begin() <= base.end());
|
||||
return std::distance(base.begin(), begin());
|
||||
}
|
||||
|
||||
/// Bytes remaining for writes to the stream buffer (same as size(*this))
|
||||
inline size_t
|
||||
ircd::buffer::window_buffer::remaining()
|
||||
const
|
||||
{
|
||||
assert(begin() <= base.end());
|
||||
const size_t ret(std::distance(begin(), base.end()));
|
||||
assert(ret == size(*this));
|
||||
return ret;
|
||||
}
|
|
@ -193,7 +193,7 @@ namespace ircd
|
|||
#include "string_view.h"
|
||||
#include "vector_view.h"
|
||||
#include "byte_view.h"
|
||||
#include "buffer.h"
|
||||
#include "buffer/buffer.h"
|
||||
#include "allocator.h"
|
||||
#include "util/util.h"
|
||||
#include "exception.h"
|
||||
|
|
Loading…
Reference in a new issue