Arguments are copied (lvalues) or moved (rvalues). To avoid copies and moves, wrap references using std::ref(), std::cref(), and folly::rref(). Beware of dangling references, especially references to temporary objects created with folly::rref().
#pragma once
#include <functional>
#include <iterator>
#include <memory>
#include <tuple>
#include <type_traits>
#include <utility>
template <
typename...
Args>
struct emplace_args : public std::tuple<std::decay_t<Args>...> {
using storage_type::storage_type;
};
template <
typename...
Args>
noexcept(emplace_args<Args...>(std::forward<Args>(args)...))) {
return emplace_args<
Args...>(std::forward<Args>(args)...);
}
template <typename Arg>
return std::forward<Arg>(arg);
}
template <typename Arg>
return arg.get();
}
template <typename Arg>
}
}
template <
size_t I,
typename...
Args>
using Out = std::tuple<
Args...>;
std::forward<std::tuple_element_t<I, Out>>(std::get<I>(args)));
}
template <
size_t I,
typename...
Args>
}
template <
size_t I,
typename...
Args>
}
template <size_t I, typename Args>
}
template <size_t I, typename Args>
return std::get<I>(args);
}
template <size_t I, typename Args>
return std::get<I>(args);
}
template <typename Container>
struct Emplace {
Emplace(Container&
c,
typename Container::iterator
i)
: container(std::addressof(c)), iter(
std::move(i)) {}
template <
typename...
Args>
void emplace(
Args&&... args) {
iter = container->emplace(iter, std::forward<Args>(args)...);
++iter;
}
Container* container;
typename Container::iterator iter;
};
template <typename Container>
struct EmplaceHint {
EmplaceHint(Container&
c,
typename Container::iterator
i)
: container(std::addressof(c)), iter(
std::move(i)) {}
template <
typename...
Args>
void emplace(
Args&&... args) {
iter = container->emplace_hint(iter, std::forward<Args>(args)...);
++iter;
}
Container* container;
typename Container::iterator iter;
};
template <typename Container>
struct EmplaceFront {
explicit EmplaceFront(Container&
c) : container(std::addressof(c)) {}
template <
typename...
Args>
void emplace(
Args&&... args) {
container->emplace_front(std::forward<Args>(args)...);
}
Container* container;
};
template <typename Container>
struct EmplaceBack {
explicit EmplaceBack(Container&
c) : container(std::addressof(c)) {}
template <
typename...
Args>
void emplace(
Args&&... args) {
container->emplace_back(std::forward<Args>(args)...);
}
Container* container;
};
template <typename Derived, typename EmplaceImpl, bool implicit_unpack>
class emplace_iterator_base;
template <typename Derived, typename EmplaceImpl>
class emplace_iterator_base<Derived, EmplaceImpl, false>
: protected EmplaceImpl {
public:
using iterator_category = std::output_iterator_tag;
using value_type = void;
using difference_type = void;
using pointer = void;
using reference = void;
using container_type =
std::remove_reference_t<decltype(*EmplaceImpl::container)>;
using EmplaceImpl::EmplaceImpl;
template <typename T>
Derived& operator=(
T&& arg) {
this->emplace(std::forward<T>(arg));
return static_cast<Derived&>(*this);
}
template <
typename...
Args>
Derived& operator=(emplace_args<Args...>& args) {
return unpackAndEmplace(args, index_sequence_for<Args...>{});
}
template <
typename...
Args>
Derived& operator=(const emplace_args<Args...>& args) {
return unpackAndEmplace(args, index_sequence_for<Args...>{});
}
template <
typename...
Args>
Derived& operator=(emplace_args<Args...>&& args) {
return unpackAndEmplace(
std::move(args), index_sequence_for<Args...>{});
}
Derived& operator*() {
return static_cast<Derived&>(*this);
}
Derived& operator++() {
return static_cast<Derived&>(*this);
}
Derived& operator++(int) {
return static_cast<Derived&>(*this);
}
emplace_iterator_base(const emplace_iterator_base&) = default;
emplace_iterator_base(emplace_iterator_base&&)
noexcept =
default;
emplace_iterator_base& operator=(emplace_iterator_base&) = default;
emplace_iterator_base& operator=(const emplace_iterator_base&) = default;
emplace_iterator_base& operator=(emplace_iterator_base&&)
noexcept =
default;
protected:
template <
typename Args, std::size_t... I>
Derived& unpackAndEmplace(
Args& args, index_sequence<I...>) {
this->emplace(get_emplace_arg<I>(args)...);
return static_cast<Derived&>(*this);
}
template <
typename Args, std::size_t... I>
Derived& unpackAndEmplace(
const Args& args, index_sequence<I...>) {
this->emplace(get_emplace_arg<I>(args)...);
return static_cast<Derived&>(*this);
}
template <
typename Args, std::size_t... I>
Derived& unpackAndEmplace(
Args&& args, index_sequence<I...>) {
this->emplace(get_emplace_arg<I>(
std::move(args))...);
return static_cast<Derived&>(*this);
}
};
template <typename Derived, typename EmplaceImpl>
class emplace_iterator_base<Derived, EmplaceImpl, true>
: public emplace_iterator_base<Derived, EmplaceImpl, false> {
private:
using Base = emplace_iterator_base<Derived, EmplaceImpl, false>;
public:
using Base::operator=;
template <
typename...
Args>
Derived& operator=(std::pair<Args...>& args) {
return this->unpackAndEmplace(args, index_sequence_for<Args...>{});
}
template <
typename...
Args>
Derived& operator=(const std::pair<Args...>& args) {
return this->unpackAndEmplace(args, index_sequence_for<Args...>{});
}
template <
typename...
Args>
Derived& operator=(std::pair<Args...>&& args) {
return this->unpackAndEmplace(
std::move(args), index_sequence_for<Args...>{});
}
template <
typename...
Args>
Derived& operator=(std::tuple<Args...>& args) {
return this->unpackAndEmplace(args, index_sequence_for<Args...>{});
}
template <
typename...
Args>
Derived& operator=(const std::tuple<Args...>& args) {
return this->unpackAndEmplace(args, index_sequence_for<Args...>{});
}
template <
typename...
Args>
Derived& operator=(std::tuple<Args...>&& args) {
return this->unpackAndEmplace(
std::move(args), index_sequence_for<Args...>{});
}
emplace_iterator_base(const emplace_iterator_base&) = default;
emplace_iterator_base(emplace_iterator_base&&)
noexcept =
default;
emplace_iterator_base& operator=(emplace_iterator_base&) = default;
emplace_iterator_base& operator=(const emplace_iterator_base&) = default;
emplace_iterator_base& operator=(emplace_iterator_base&&)
noexcept =
default;
};
template <
template <typename> class EmplaceImplT,
typename Container,
bool implicit_unpack>
class emplace_iterator_impl
: public emplace_iterator_base<
emplace_iterator_impl<EmplaceImplT, Container, implicit_unpack>,
EmplaceImplT<Container>,
implicit_unpack> {
private:
using Base = emplace_iterator_base<
emplace_iterator_impl,
EmplaceImplT<Container>,
implicit_unpack>;
public:
using Base::operator=;
emplace_iterator_impl(const emplace_iterator_impl&) = default;
emplace_iterator_impl(emplace_iterator_impl&&)
noexcept =
default;
emplace_iterator_impl& operator=(emplace_iterator_impl&) = default;
emplace_iterator_impl& operator=(const emplace_iterator_impl&) = default;
emplace_iterator_impl& operator=(emplace_iterator_impl&&)
noexcept =
default;
};
}
template <typename Container, bool implicit_unpack = true>
detail::emplace_iterator_impl<detail::Emplace, Container, implicit_unpack>;
template <typename Container, bool implicit_unpack = true>
emplace_iterator_impl<detail::EmplaceHint, Container, implicit_unpack>;
template <typename Container, bool implicit_unpack = true>
emplace_iterator_impl<detail::EmplaceFront, Container, implicit_unpack>;
template <typename Container, bool implicit_unpack = true>
emplace_iterator_impl<detail::EmplaceBack, Container, implicit_unpack>;
template <bool implicit_unpack = true, typename Container>
emplace_iterator<Container, implicit_unpack>
emplacer(
typename Container::iterator
i) {
return emplace_iterator<Container, implicit_unpack>(
c,
std::move(i));
}
template <bool implicit_unpack = true, typename Container>
Container& c,
typename Container::iterator i) {
return hint_emplace_iterator<Container, implicit_unpack>(
c,
std::move(i));
}
template <bool implicit_unpack = true, typename Container>
Container& c) {
return front_emplace_iterator<Container, implicit_unpack>(
c);
}
template <bool implicit_unpack = true, typename Container>
back_emplace_iterator<Container, implicit_unpack>
back_emplacer(Container& c) {
return back_emplace_iterator<Container, implicit_unpack>(
c);
}
}