/*
* Copyright (C) 2018 ScyllaDB
*/
/*
* This file is part of Scylla.
*
* Scylla is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Scylla is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Scylla. If not, see .
*/
#pragma once
#include
#include
#include
#include "bytes.hh"
enum class mutable_view { no, yes, };
GCC6_CONCEPT(
/// Fragmented buffer
///
/// Concept `FragmentedBuffer` is satisfied by any class that is a range of
/// fragments and provides a method `size_bytes()` which returns the total
/// size of the buffer. The interfaces accepting `FragmentedBuffer` will attempt
/// to avoid unnecessary linearisation.
template
concept bool FragmentRange = requires (T range) {
typename T::fragment_type;
requires std::is_same_v
|| std::is_same_v;
{ *range.begin() } -> typename T::fragment_type;
{ *range.end() } -> typename T::fragment_type;
{ range.size_bytes() } -> size_t;
{ range.empty() } -> bool; // returns true iff size_bytes() == 0.
};
)
template
struct is_fragment_range : std::false_type { };
template
struct is_fragment_range> : std::true_type { };
template
static constexpr bool is_fragment_range_v = is_fragment_range::value;
/// Single-element fragment range
///
/// This is a helper that allows converting a bytes_view into a FragmentRange.
template
class single_fragment_range {
public:
using fragment_type = std::conditional_t;
private:
fragment_type _view;
public:
using iterator = const fragment_type*;
using const_iterator = const fragment_type*;
explicit single_fragment_range(fragment_type f) : _view { f } { }
const_iterator begin() const { return &_view; }
const_iterator end() const { return &_view + 1; }
size_t size_bytes() const { return _view.size(); }
bool empty() const { return _view.empty(); }
};
single_fragment_range(bytes_view) -> single_fragment_range;
single_fragment_range(bytes_mutable_view) -> single_fragment_range;
/// Empty fragment range.
struct empty_fragment_range {
using fragment_type = bytes_view;
using iterator = bytes_view*;
using const_iterator = bytes_view*;
iterator begin() const { return nullptr; }
iterator end() const { return nullptr; }
size_t size_bytes() const { return 0; }
bool empty() const { return true; }
};
GCC6_CONCEPT(
static_assert(FragmentRange);
static_assert(FragmentRange>);
static_assert(FragmentRange>);
)
template
GCC6_CONCEPT(requires FragmentRange)
bytes linearized(const FragmentedBuffer& buffer)
{
bytes b(bytes::initialized_later(), buffer.size_bytes());
auto dst = b.begin();
using boost::range::for_each;
for_each(buffer, [&] (bytes_view fragment) {
dst = boost::copy(fragment, dst);
});
return b;
}
template
GCC6_CONCEPT(requires FragmentRange && requires (Function fn, bytes_view bv) {
fn(bv);
})
decltype(auto) with_linearized(const FragmentedBuffer& buffer, Function&& fn)
{
bytes b;
bytes_view bv;
if (__builtin_expect(!buffer.empty() && std::next(buffer.begin()) == buffer.end(), true)) {
bv = *buffer.begin();
} else if (!buffer.empty()) {
b = linearized(buffer);
bv = b;
}
return fn(bv);
}