/* * Copyright (c) Meta Platforms, Inc. and affiliates. * * 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 <functional> #include <iterator> #include <memory> #include <tuple> #include <type_traits> #include <utility> #include <folly/Traits.h> #include <folly/Utility.h> #include <folly/container/Access.h> #include <folly/functional/Invoke.h> #include <folly/lang/RValueReferenceWrapper.h> namespace folly { // iterator_has_known_distance_v // // Whether std::distance over a pair of iterators is reasonably known to give // the distance without advancing the iterators or copies of them. iterator_has_known_distance_v; iterator_has_known_distance_v; // range_has_known_distance_v // // Whether std::distance over the begin and end iterators is reasonably known // to give the distance without advancing the iterators or copies of them. // // Useful for conditionally reserving memory in advance of iterating the range. // // Note: Many use-cases are better served by range-v3 or std::ranges. // // Example: // // std::vector<result_type> results; // auto elems = /* some range */; // auto const elemsb = folly::access::begin(elems); // auto const elemse = folly::access::end(elems); // // if constexpr (range_has_known_distance_v<decltype(elems)>) { // auto const dist = std::distance(elemsb, elemse); // results.reserve(static_cast<std::size_t>(dist)); // } // // for (auto elemsi = elemsb; elemsi != elemsi; ++i) { // results.push_back(do_work(*elemsi)); // } // return results; range_has_known_distance_v; // iterator_category_t // // Extracts iterator_category from an iterator. iterator_category_t; namespace detail { iterator_category_matches_v_; iterator_category_matches_v_; } // namespace detail // iterator_category_matches_v // // Whether an iterator's category matches Category (std::input_iterator_tag, // std::output_iterator_tag, etc). Defined for non-iterator types as well. // // Useful for containers deduction guides implementation. iterator_category_matches_v; // iterator_value_type_t // // Extracts a value type from an iterator. iterator_value_type_t; // iterator_key_type_t // // Extracts a key type from an iterator, leverages the knowledge that // key/value containers usually use std::pair<const K, V> as a value_type. iterator_key_type_t; // iterator_mapped_type_t // // Extracts a mapped type from an iterator. iterator_mapped_type_t; /** * Argument tuple for variadic emplace/constructor calls. Stores arguments by * (decayed) value. Restores original argument types with reference qualifiers * and adornments at unpack time to emulate perfect forwarding. * * Uses inheritance instead of a type alias to std::tuple so that emplace * iterators with implicit unpacking disabled can distinguish between * emplace_args and std::tuple parameters. * * @seealso folly::make_emplace_args * @seealso folly::get_emplace_arg */ template <typename... Args> struct emplace_args : public std::tuple<std::decay_t<Args>...> { … }; /** * Pack arguments in a tuple for assignment to a folly::emplace_iterator, * folly::front_emplace_iterator, or folly::back_emplace_iterator. The * iterator's operator= will unpack the tuple and pass the unpacked arguments * to the container's emplace function, which in turn forwards the arguments to * the (multi-argument) constructor of the target class. * * Argument tuples generated with folly::make_emplace_args will be unpacked * before being passed to the container's emplace function, even for iterators * where implicit_unpack is set to false (so they will not implicitly unpack * std::pair or std::tuple arguments to operator=). * * 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(). * * Note that an argument pack created with folly::make_emplace_args is different * from an argument pack created with std::make_pair or std::make_tuple. * Specifically, passing a std::pair&& or std::tuple&& to an emplace iterator's * operator= will pass rvalue references to all fields of that tuple to the * container's emplace function, while passing an emplace_args&& to operator= * will cast those field references to the exact argument types as passed to * folly::make_emplace_args previously. If all arguments have been wrapped by * std::reference_wrappers or folly::rvalue_reference_wrappers, the result will * be the same as if the container's emplace function had been called directly * (perfect forwarding), with no temporary copies of the arguments. * * @seealso folly::rref * * @example * class Widget { Widget(int, int); }; * std::vector<Widget> makeWidgets(const std::vector<int>& in) { * std::vector<Widget> out; * std::transform( * in.begin(), * in.end(), * folly::back_emplacer(out), * [](int i) { return folly::make_emplace_args(i, i); }); * return out; * } */ template <typename... Args> emplace_args<Args...> make_emplace_args(Args&&... args) noexcept( noexcept(emplace_args<Args...>(std::forward<Args>(args)...))) { … } namespace detail { template <typename Arg> decltype(auto) unwrap_emplace_arg(Arg&& arg) noexcept { … } template <typename Arg> decltype(auto) unwrap_emplace_arg(std::reference_wrapper<Arg> arg) noexcept { … } template <typename Arg> decltype(auto) unwrap_emplace_arg( folly::rvalue_reference_wrapper<Arg> arg) noexcept { … } } // namespace detail /** * Getter function for unpacking a single emplace argument. * * Calling get_emplace_arg on an emplace_args rvalue reference results in * perfect forwarding of the original input types. A special case are * std::reference_wrapper and folly::rvalue_reference_wrapper objects within * folly::emplace_args. These are also unwrapped so that the bare reference is * returned. * * std::get is not a customization point in the standard library, so the * cleanest solution was to define our own getter function. */ template <size_t I, typename... Args> decltype(auto) get_emplace_arg(emplace_args<Args...>&& args) noexcept { … } template <size_t I, typename... Args> decltype(auto) get_emplace_arg(emplace_args<Args...>& args) noexcept { … } template <size_t I, typename... Args> decltype(auto) get_emplace_arg(const emplace_args<Args...>& args) noexcept { … } template <size_t I, typename Args> decltype(auto) get_emplace_arg(Args&& args) noexcept { … } template <size_t I, typename Args> decltype(auto) get_emplace_arg(Args& args) noexcept { … } template <size_t I, typename Args> decltype(auto) get_emplace_arg(const Args& args) noexcept { … } namespace detail { /** * Emplace implementation class for folly::emplace_iterator. */ template <typename Container> struct Emplace { … }; /** * Emplace implementation class for folly::hint_emplace_iterator. */ template <typename Container> struct EmplaceHint { … }; /** * Emplace implementation class for folly::front_emplace_iterator. */ template <typename Container> struct EmplaceFront { … }; /** * Emplace implementation class for folly::back_emplace_iterator. */ template <typename Container> struct EmplaceBack { … }; /** * Generic base class and implementation of all emplace iterator classes. * * Uses the curiously recurring template pattern (CRTP) to cast `this*` to * `Derived*`; i.e., to implement covariant return types in a generic manner. */ template <typename Derived, typename EmplaceImpl, bool implicit_unpack> class emplace_iterator_base; /** * Partial specialization of emplace_iterator_base with implicit unpacking * disabled. */ emplace_iterator_base<Derived, EmplaceImpl, false>; /** * Partial specialization of emplace_iterator_base with implicit unpacking * enabled. * * Uses inheritance rather than SFINAE. operator= requires a single argument, * which makes it very tricky to use std::enable_if or similar. */ emplace_iterator_base<Derived, EmplaceImpl, true>; /** * Concrete instantiation of emplace_iterator_base. All emplace iterator * classes; folly::emplace_iterator, folly::hint_emplace_iterator, * folly::front_emplace_iterator, and folly::back_emplace_iterator; are just * type aliases of this class. * * It is not possible to alias emplace_iterator_base directly, because type * aliases cannot be used for CRTP. */ 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> { … }; } // namespace detail /** * Behaves just like std::insert_iterator except that it calls emplace() * instead of insert(). Uses perfect forwarding. */ emplace_iterator; /** * Behaves just like std::insert_iterator except that it calls emplace_hint() * instead of insert(). Uses perfect forwarding. */ hint_emplace_iterator; /** * Behaves just like std::front_insert_iterator except that it calls * emplace_front() instead of insert(). Uses perfect forwarding. */ front_emplace_iterator; /** * Behaves just like std::back_insert_iterator except that it calls * emplace_back() instead of insert(). Uses perfect forwarding. */ back_emplace_iterator; /** * Convenience function to construct a folly::emplace_iterator, analogous to * std::inserter(). * * Setting implicit_unpack to false will disable implicit unpacking of * single std::pair and std::tuple arguments to the iterator's operator=. That * may be desirable in case of constructors that expect a std::pair or * std::tuple argument. */ template <bool implicit_unpack = true, typename Container> emplace_iterator<Container, implicit_unpack> emplacer( Container& c, typename Container::iterator i) { … } /** * Convenience function to construct a folly::hint_emplace_iterator, analogous * to std::inserter(). * * Setting implicit_unpack to false will disable implicit unpacking of * single std::pair and std::tuple arguments to the iterator's operator=. That * may be desirable in case of constructors that expect a std::pair or * std::tuple argument. */ template <bool implicit_unpack = true, typename Container> hint_emplace_iterator<Container, implicit_unpack> hint_emplacer( Container& c, typename Container::iterator i) { … } /** * Convenience function to construct a folly::front_emplace_iterator, analogous * to std::front_inserter(). * * Setting implicit_unpack to false will disable implicit unpacking of * single std::pair and std::tuple arguments to the iterator's operator=. That * may be desirable in case of constructors that expect a std::pair or * std::tuple argument. */ template <bool implicit_unpack = true, typename Container> front_emplace_iterator<Container, implicit_unpack> front_emplacer( Container& c) { … } /** * Convenience function to construct a folly::back_emplace_iterator, analogous * to std::back_inserter(). * * Setting implicit_unpack to false will disable implicit unpacking of * single std::pair and std::tuple arguments to the iterator's operator=. That * may be desirable in case of constructors that expect a std::pair or * std::tuple argument. */ template <bool implicit_unpack = true, typename Container> back_emplace_iterator<Container, implicit_unpack> back_emplacer(Container& c) { … } namespace detail { // An accepted way to make operator-> work // https://quuxplusone.github.io/blog/2019/02/06/arrow-proxy/ template <typename Ref> struct arrow_proxy { … }; struct index_iterator_access_at { … }; } // namespace detail FOLLY_DEFINE_CPO(detail::index_iterator_access_at, index_iterator_access_at) /** * index_iterator * * An iterator class for random access data structures that provide an * access by index via `operator[](size_type)`. * * Requires a `value_type` defined in a container (we cannot * get the value type from reference). * * Example: * class Container { * public: * using value_type = <*>; // we need value_type to be defined. * using iterator = folly::index_iterator<Container>; * using const_iterator = folly::index_iterator<const Container>; * using reverse_iterator = std::reverse_iterator<iterator>; * using const_reverse_iterator = std::reverse_iterator<const_iterator>; * * some_ref_type operator[](std::size_t index); * some_cref_type operator[](std::size_t index) const; * ... * }; * * Note that `some_ref_type` can be any proxy reference, as long as the * algorithms support that (for example from range-v3). * * NOTE: if `operator[]` doesn't work for you for some reason * you can specify: * * ``` * friend some_ref_type tag_invoke( * folly::cpo_t<index_iterator_access_at>, * Container& c, * std::size_t index); * * friend some_cref_type tag_invoke( * folly::cpo_t<index_iterator_access_at>, * const Container& c, * std::size_t index); * ``` **/ template <typename Container> class index_iterator { … }; } // namespace folly