// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab // Derived from: /* uses_allocator.h -*-C++-*- * * Copyright (C) 2016 Pablo Halpern * Distributed under the Boost Software License - Version 1.0 */ // Downloaded from https://github.com/phalpern/uses-allocator.git #pragma once #include #include #include #include namespace ceph { namespace internal { template T make_from_tuple_imp(Tuple&& t, std::index_sequence) { return T(std::get(std::forward(t))...); } } // namespace internal template T make_from_tuple(Tuple&& args_tuple) { using namespace internal; using Indices = std::make_index_sequence>>; return make_from_tuple_imp(std::forward(args_tuple), Indices{}); } //////////////////////////////////////////////////////////////////////// // Forward declaration template auto uses_allocator_construction_args(const Alloc& a, Args&&... args); namespace internal { template struct has_allocator : std::uses_allocator { }; // Specialization of `has_allocator` for `std::pair` template struct has_allocator, A> : std::integral_constant::value || has_allocator::value> { }; template using boolean_constant = std::integral_constant; template struct is_pair : std::false_type { }; template struct is_pair> : std::true_type { }; // Return a tuple of arguments appropriate for uses-allocator construction // with allocator `Alloc` and ctor arguments `Args`. // This overload is handles types for which `has_allocator` is false. template auto uses_allocator_args_imp(Unused1 /* is_pair */, std::false_type /* has_allocator */, Unused2 /* uses prefix allocator arg */, const Alloc& /* ignored */, Args&&... args) { // Allocator is ignored return std::forward_as_tuple(std::forward(args)...); } // Return a tuple of arguments appropriate for uses-allocator construction // with allocator `Alloc` and ctor arguments `Args`. // This overload handles non-pair `T` for which `has_allocator` is // true and constructor `T(allocator_arg_t, a, args...)` is valid. template auto uses_allocator_args_imp(std::false_type /* is_pair */, std::true_type /* has_allocator */, std::true_type /* uses prefix allocator arg */, const Alloc& a, Args&&... args) { // Allocator added to front of argument list, after `allocator_arg`. return std::tuple(std::allocator_arg, a, std::forward(args)...); } // Return a tuple of arguments appropriate for uses-allocator construction // with allocator `Alloc` and ctor arguments `Args`. // This overload handles non-pair `T` for which `has_allocator` is // true and constructor `T(allocator_arg_t, a, args...)` NOT valid. // This function will produce invalid results unless `T(args..., a)` is valid. template auto uses_allocator_args_imp(std::false_type /* is_pair */, std::true_type /* has_allocator */, std::false_type /* prefix allocator arg */, const Alloc& a, Args&&... args) { // Allocator added to end of argument list return std::forward_as_tuple(std::forward(args)..., a); } // Return a tuple of arguments appropriate for uses-allocator construction // with allocator `Alloc` and ctor arguments `Args`. // This overload handles specializations of `T` = `std::pair` for which // `has_allocator` is true for either or both of the elements and // piecewise_construct arguments are passed in. template auto uses_allocator_args_imp(std::true_type /* is_pair */, std::true_type /* has_allocator */, std::false_type /* prefix allocator arg */, const Alloc& a, std::piecewise_construct_t, Tuple1&& x, Tuple2&& y) { using T1 = typename T::first_type; using T2 = typename T::second_type; return std::make_tuple( std::piecewise_construct, std::apply([&a](auto&&... args1) -> auto { return uses_allocator_construction_args( a, std::forward(args1)...); }, std::forward(x)), std::apply([&a](auto&&... args2) -> auto { return uses_allocator_construction_args( a, std::forward(args2)...); }, std::forward(y)) ); } // Return a tuple of arguments appropriate for uses-allocator construction // with allocator `Alloc` and ctor arguments `Args`. // This overload handles specializations of `T` = `std::pair` for which // `has_allocator` is true for either or both of the elements and // no other constructor arguments are passed in. template auto uses_allocator_args_imp(std::true_type /* is_pair */, std::true_type /* has_allocator */, std::false_type /* prefix allocator arg */, const Alloc& a) { // using T1 = typename T::first_type; // using T2 = typename T::second_type; // return std::make_tuple( // piecewise_construct, // uses_allocator_construction_args(a), // uses_allocator_construction_args(a)); return uses_allocator_construction_args(a, std::piecewise_construct, std::tuple<>{}, std::tuple<>{}); } // Return a tuple of arguments appropriate for uses-allocator construction // with allocator `Alloc` and ctor arguments `Args`. // This overload handles specializations of `T` = `std::pair` for which // `has_allocator` is true for either or both of the elements and // a single argument of type const-lvalue-of-pair is passed in. template auto uses_allocator_args_imp(std::true_type /* is_pair */, std::true_type /* has_allocator */, std::false_type /* prefix allocator arg */, const Alloc& a, const std::pair& arg) { // using T1 = typename T::first_type; // using T2 = typename T::second_type; // return std::make_tuple( // piecewise_construct, // uses_allocator_construction_args(a, arg.first), // uses_allocator_construction_args(a, arg.second)); return uses_allocator_construction_args(a, std::piecewise_construct, std::forward_as_tuple(arg.first), std::forward_as_tuple(arg.second)); } // Return a tuple of arguments appropriate for uses-allocator construction // with allocator `Alloc` and ctor arguments `Args`. // This overload handles specializations of `T` = `std::pair` for which // `has_allocator` is true for either or both of the elements and // a single argument of type rvalue-of-pair is passed in. template auto uses_allocator_args_imp(std::true_type /* is_pair */, std::true_type /* has_allocator */, std::false_type /* prefix allocator arg */, const Alloc& a, std::pair&& arg) { // using T1 = typename T::first_type; // using T2 = typename T::second_type; // return std::make_tuple( // piecewise_construct, // uses_allocator_construction_args(a, forward(arg.first)), // uses_allocator_construction_args(a, forward(arg.second))); return uses_allocator_construction_args(a, std::piecewise_construct, std::forward_as_tuple(std::forward(arg.first)), std::forward_as_tuple(std::forward(arg.second))); } // Return a tuple of arguments appropriate for uses-allocator construction // with allocator `Alloc` and ctor arguments `Args`. // This overload handles specializations of `T` = `std::pair` for which // `has_allocator` is true for either or both of the elements and // two additional constructor arguments are passed in. template auto uses_allocator_args_imp(std::true_type /* is_pair */, std::true_type /* has_allocator */, std::false_type /* prefix allocator arg */, const Alloc& a, U1&& arg1, U2&& arg2) { // using T1 = typename T::first_type; // using T2 = typename T::second_type; // return std::make_tuple( // piecewise_construct, // uses_allocator_construction_args(a, forward(arg1)), // uses_allocator_construction_args(a, forward(arg2))); return uses_allocator_construction_args( a, std::piecewise_construct, std::forward_as_tuple(std::forward(arg1)), std::forward_as_tuple(std::forward(arg2))); } } // close namespace internal template auto uses_allocator_construction_args(const Alloc& a, Args&&... args) { using namespace internal; return uses_allocator_args_imp(is_pair(), has_allocator(), std::is_constructible(), a, std::forward(args)...); } template T make_obj_using_allocator(const Alloc& a, Args&&... args) { return make_from_tuple( uses_allocator_construction_args(a, std::forward(args)...)); } template T* uninitialized_construct_using_allocator(T* p, const Alloc& a, Args&&... args) { return std::apply([p](auto&&... args2){ return ::new(static_cast(p)) T(std::forward(args2)...); }, uses_allocator_construction_args( a, std::forward(args)...)); } } // namespace ceph