/* * charybdis5 * Copyright (C) 2016 Jason Volk * * 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. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #pragma once #define HAVE_IRCD_BUFFER_H namespace ircd::buffer { template struct buffer; struct const_buffer; struct mutable_buffer; template struct unique_buffer; template using buffers = std::initializer_list; using const_buffers = buffers; using mutable_buffers = buffers; extern const mutable_buffer null_buffer; extern const mutable_buffers null_buffers; template const it &begin(const buffer &buffer); template const it &end(const buffer &buffer); template it &begin(buffer &buffer); template it &end(buffer &buffer); template it rbegin(const buffer &buffer); template it rend(const buffer &buffer); template size_t size(const buffer &buffer); template size_t size(const buffers &buffers); template const it &data(const buffer &buffer); template size_t consume(buffer &buffer, const size_t &bytes); template size_t consume(buffers &buffers, const size_t &bytes); template char *copy(char *&dest, char *const &stop, const buffer &buffer); template size_t copy(char *const &dest, const size_t &max, const buffer &buffer); template char *copy(char *&dest, char *const &stop, const buffers &buffer); template size_t copy(char *const &dest, const size_t &max, const buffers &buffer); template std::ostream &operator<<(std::ostream &s, const buffer &buffer); template std::ostream &operator<<(std::ostream &s, const buffers &buffers); } // Export these important aliases down to main ircd namespace namespace ircd { using buffer::const_buffer; using buffer::mutable_buffer; using buffer::unique_buffer; using buffer::const_buffers; using buffer::mutable_buffers; using buffer::null_buffer; using buffer::null_buffers; } template struct ircd::buffer::buffer :std::tuple { using value_type = it; operator string_view() const; operator std::string_view() const; explicit operator std::string() const; buffer(const it &start, const it &stop) :std::tuple{start, stop} {} buffer(const it &start, const size_t &size) :buffer{start, start + size} {} template buffer(typename std::remove_pointer::type (&buf)[SIZE]) :buffer{buf, SIZE} {} buffer() :buffer{nullptr, nullptr} {} }; struct ircd::buffer::const_buffer :buffer { operator boost::asio::const_buffer() const; using buffer::buffer; const_buffer(const string_view &s) :buffer{begin(s), end(s)} {} }; struct ircd::buffer::mutable_buffer :buffer { operator boost::asio::mutable_buffer() const; using buffer::buffer; }; template std::ostream & ircd::buffer::operator<<(std::ostream &s, const buffers &buffers) { std::for_each(begin(buffers), end(buffers), [&s] (const auto &buffer) { s << buffer; }); return s; } template std::ostream & ircd::buffer::operator<<(std::ostream &s, const buffer &buffer) { s.write(data(buffer), size(buffer)); return s; } template size_t ircd::buffer::copy(char *const &dest, const size_t &max, const buffers &buffers) { size_t ret(0); for(const auto &buffer : buffers) ret += copy(dest + ret, max - ret, buffer); return ret; } template size_t ircd::buffer::copy(char *const &dest, const size_t &max, const buffer &buffer) { if(!max) return 0; char *out(dest); char *const stop(dest + max - 1); copy(out, stop, buffer); *out = '\0'; return std::distance(dest, out); } template char * ircd::buffer::copy(char *&dest, char *const &stop, const buffers &buffers) { char *const ret(dest); for(const auto &buffer : buffers) copy(dest, stop, buffer); return ret; } template char * ircd::buffer::copy(char *&dest, char *const &stop, const buffer &buffer) { char *const ret(dest); const size_t remain(stop - dest); dest += std::min(size(buffer), remain); memcpy(ret, data(buffer), dest - ret); return ret; } template size_t ircd::buffer::consume(buffers &buffers, const size_t &bytes) { size_t remain(bytes); for(auto it(begin(buffers)); it != end(buffers) && remain > 0; ++it) { using buffer = typename buffers::value_type; using iterator = typename buffer::value_type; buffer &b(const_cast(*it)); remain -= consume(b, remain); } return bytes - remain; } template size_t ircd::buffer::consume(buffer &buffer, const size_t &bytes) { get<0>(buffer) += std::min(size(buffer), bytes); return bytes - size(buffer); } template const it & ircd::buffer::data(const buffer &buffer) { return get<0>(buffer); } template size_t ircd::buffer::size(const buffers &buffers) { return std::accumulate(std::begin(buffers), std::end(buffers), size_t(0), [] (auto ret, const auto &buffer) { return ret += size(buffer); }); } template size_t ircd::buffer::size(const buffer &buffer) { assert(get<0>(buffer) <= get<1>(buffer)); return std::distance(get<0>(buffer), get<1>(buffer)); } template it ircd::buffer::rend(const buffer &buffer) { return std::reverse_iterator(get<0>(buffer)); } template it ircd::buffer::rbegin(const buffer &buffer) { return std::reverse_iterator(get<0>(buffer) + size(buffer)); } template it & ircd::buffer::end(buffer &buffer) { return get<1>(buffer); } template it & ircd::buffer::begin(buffer &buffer) { return get<0>(buffer); } template const it & ircd::buffer::end(const buffer &buffer) { return get<1>(buffer); } template const it & ircd::buffer::begin(const buffer &buffer) { return get<0>(buffer); } template ircd::buffer::buffer::operator std::string() const { return { get<0>(*this), size(*this) }; } template ircd::buffer::buffer::operator std::string_view() const { return { get<0>(*this), size(*this) }; } template ircd::buffer::buffer::operator string_view() const { return { get<0>(*this), get<1>(*this) }; } template struct ircd::buffer::unique_buffer :buffer { unique_buffer(std::unique_ptr &&, const size_t &size); unique_buffer(const size_t &size); unique_buffer() = default; unique_buffer(unique_buffer &&) noexcept; unique_buffer(const unique_buffer &) = delete; ~unique_buffer() noexcept; }; template ircd::buffer::unique_buffer::unique_buffer(std::unique_ptr &&b, const size_t &size) :buffer { typename buffer::value_type(b.release()), size } { } template ircd::buffer::unique_buffer::unique_buffer(const size_t &size) :unique_buffer { std::unique_ptr { new __attribute__((aligned(alignment))) uint8_t[size] }, size } { } template ircd::buffer::unique_buffer::unique_buffer(unique_buffer &&other) noexcept :buffer { std::move(other) } { get<0>(other) = nullptr; } template ircd::buffer::unique_buffer::~unique_buffer() noexcept { delete[] data(*this); }