/*
* Copyright (C) 2017 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
/**
* Adopted from
* http://cpptruths.blogspot.se/2013/09/21-ways-of-passing-parameters-plus-one.html#inTidiom
*
* Helper type to somewhat help bridge std::initializer_list and move semantics
*
*/
namespace utils {
template class in;
template struct is_in {
static const bool value = false;
};
template struct is_in> {
static const bool value = true;
};
template struct is_in> {
static const bool value = true;
};
//
// Allows initializer lists of mixed rvalue/lvalues, where receive can
// use move semantics on provided value(s).
// Allows in-place conversion, _BUT_ (warning), a converted value
// is only valid until end-of-statement (;). So a call like:
//
// void apa(initializer_list>);
// apa({ "ola", "kong" });
//
// is ok, but
//
// initializer_list> apa = { "ola", "kong" };
// for (auto&x : apa) ...
//
// is not.
// So again. Only for calls.
template
class in {
public:
in(const T& l)
: _value(l)
, _is_rvalue(false)
{}
in(T&& r)
: _value(r)
, _is_rvalue(true)
{}
// Support for implicit conversion via perfect forwarding.
//
struct storage {
storage(): created (false) {}
~storage() {
if (created) {
reinterpret_cast (&data)->~T ();
}
}
bool created;
typename std::aligned_storage::type data;
};
// conversion constuctor. See warning above.
template::value
&& !is_in::type>::value,int>::type = 0>
in(T1&& x, storage&& s = storage())
: _value(*new (&s.data) T (std::forward(x)))
, _is_rvalue(true)
{
s.created = true;
}
in(T& l)
: _value(l)
, _is_rvalue(false)
{} // For T1&& becoming T1&.
// Accessors.
//
bool lvalue() const { return !_is_rvalue; }
bool rvalue() const { return _is_rvalue; }
operator const T&() const { return get(); }
const T& get() const { return _value; }
T&& rget() const { return std::move (const_cast (_value)); }
// Return a copy if lvalue.
//
T move() const {
if (_is_rvalue) {
return rget();
}
return _value;
}
private:
const T& _value;
bool _is_rvalue;
};
template
Container make_from_in_list(std::initializer_list> args) {
return boost::copy_range(args | boost::adaptors::transformed([](const in& v) {
return v.move();
}));
}
template
std::vector make_vector_from_in_list(std::initializer_list> args) {
return make_from_in_list>(args);
}
}