blob: a9934e8d499a53f872f491821fcf1174d1822753 [file] [log] [blame]
/*
* Copyright 2017 Facebook, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#pragma once
#include <cstdint>
#include <type_traits>
#include <utility>
namespace folly {
/**
* copy
*
* Usable when you have a function with two overloads:
*
* class MyData;
* void something(MyData&&);
* void something(const MyData&);
*
* Where the purpose is to make copies and moves explicit without having to
* spell out the full type names - in this case, for copies, to invoke copy
* constructors.
*
* When the caller wants to pass a copy of an lvalue, the caller may:
*
* void foo() {
* MyData data;
* something(folly::copy(data)); // explicit copy
* something(std::move(data)); // explicit move
* something(data); // const& - neither move nor copy
* }
*
* Note: If passed an rvalue, invokes the move-ctor, not the copy-ctor. This
* can be used to to force a move, where just using std::move would not:
*
* std::copy(std::move(data)); // force-move, not just a cast to &&
*
* Note: The following text appears in the standard:
*
* > In several places in this Clause the operation //DECAY_COPY(x)// is used.
* > All such uses mean call the function `decay_copy(x)` and use the result,
* > where `decay_copy` is defined as follows:
* >
* > template <class T> decay_t<T> decay_copy(T&& v)
* > { return std::forward<T>(v); }
* >
* > http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n4296.pdf
* > 30.2.6 `decay_copy` [thread.decaycopy].
*
* We mimic it, with a `noexcept` specifier for good measure.
*/
template <typename T>
constexpr typename std::decay<T>::type copy(T&& value) noexcept(
noexcept(typename std::decay<T>::type(std::forward<T>(value)))) {
return std::forward<T>(value);
}
/**
* A simple helper for getting a constant reference to an object.
*
* Example:
*
* std::vector<int> v{1,2,3};
* // The following two lines are equivalent:
* auto a = const_cast<const std::vector<int>&>(v).begin();
* auto b = folly::as_const(v).begin();
*
* Like C++17's std::as_const. See http://wg21.link/p0007
*/
#if __cpp_lib_as_const || _MSC_VER
/* using override */ using std::as_const;
#else
template <class T>
constexpr T const& as_const(T& t) noexcept {
return t;
}
template <class T>
void as_const(T const&&) = delete;
#endif
#if __cpp_lib_integer_sequence || _MSC_VER
/* using override */ using std::integer_sequence;
/* using override */ using std::index_sequence;
/* using override */ using std::make_index_sequence;
#else
template <class T, T... Ints>
struct integer_sequence {
using value_type = T;
static constexpr std::size_t size() noexcept {
return sizeof...(Ints);
}
};
template <std::size_t... Ints>
using index_sequence = folly::integer_sequence<std::size_t, Ints...>;
namespace detail {
template <std::size_t N, std::size_t... Ints>
struct make_index_sequence
: detail::make_index_sequence<N - 1, N - 1, Ints...> {};
template <std::size_t... Ints>
struct make_index_sequence<0, Ints...> : folly::index_sequence<Ints...> {};
}
template <std::size_t N>
using make_index_sequence = detail::make_index_sequence<N>;
#endif
/**
* Backports from C++17 of:
* std::in_place_t
* std::in_place_type_t
* std::in_place_index_t
* std::in_place
* std::in_place_type
* std::in_place_index
*/
struct in_place_tag {};
template <class>
struct in_place_type_tag {};
template <std::size_t>
struct in_place_index_tag {};
using in_place_t = in_place_tag (&)(in_place_tag);
template <class T>
using in_place_type_t = in_place_type_tag<T> (&)(in_place_type_tag<T>);
template <std::size_t I>
using in_place_index_t = in_place_index_tag<I> (&)(in_place_index_tag<I>);
inline in_place_tag in_place(in_place_tag = {}) {
return {};
}
template <class T>
inline in_place_type_tag<T> in_place_type(in_place_type_tag<T> = {}) {
return {};
}
template <std::size_t I>
inline in_place_index_tag<I> in_place_index(in_place_index_tag<I> = {}) {
return {};
}
/**
* Initializer lists are a powerful compile time syntax introduced in C++11
* but due to their often conflicting syntax they are not used by APIs for
* construction.
*
* Further standard conforming compilers *strongly* favor an
* std::initalizer_list overload for construction if one exists. The
* following is a simple tag used to disambiguate construction with
* initializer lists and regular uniform initialization.
*
* For example consider the following case
*
* class Something {
* public:
* explicit Something(int);
* Something(std::intiializer_list<int>);
*
* operator int();
* };
*
* ...
* Something something{1}; // SURPRISE!!
*
* The last call to instantiate the Something object will go to the
* initializer_list overload. Which may be surprising to users.
*
* If however this tag was used to disambiguate such construction it would be
* easy for users to see which construction overload their code was referring
* to. For example
*
* class Something {
* public:
* explicit Something(int);
* Something(folly::initlist_construct_t, std::initializer_list<int>);
*
* operator int();
* };
*
* ...
* Something something_one{1}; // not the initializer_list overload
* Something something_two{folly::initlist_construct, {1}}; // correct
*/
struct initlist_construct_t {};
constexpr initlist_construct_t initlist_construct{};
/**
* A simple function object that passes its argument through unchanged.
*
* Example:
*
* int i = 42;
* int &j = Identity()(i);
* assert(&i == &j);
*
* Warning: passing a prvalue through Identity turns it into an xvalue,
* which can effect whether lifetime extension occurs or not. For instance:
*
* auto&& x = std::make_unique<int>(42);
* cout << *x ; // OK, x refers to a valid unique_ptr.
*
* auto&& y = Identity()(std::make_unique<int>(42));
* cout << *y ; // ERROR: y did not lifetime-extend the unique_ptr. It
* // is no longer valid
*/
struct Identity {
using is_transparent = void;
template <class T>
constexpr T&& operator()(T&& x) const noexcept {
return static_cast<T&&>(x);
}
};
namespace moveonly_ { // Protection from unintended ADL.
/**
* Disallow copy but not move in derived types. This is essentially
* boost::noncopyable (the implementation is almost identical) but it
* doesn't delete move constructor and move assignment.
*/
class MoveOnly {
protected:
constexpr MoveOnly() = default;
~MoveOnly() = default;
MoveOnly(MoveOnly&&) = default;
MoveOnly& operator=(MoveOnly&&) = default;
MoveOnly(const MoveOnly&) = delete;
MoveOnly& operator=(const MoveOnly&) = delete;
};
} // namespace moveonly_
using MoveOnly = moveonly_::MoveOnly;
} // namespace folly