vn-verdnaturachat/ios/Pods/Flipper-Folly/folly/container/detail/Util.h

232 lines
7.1 KiB
C++

/*
* Copyright (c) Facebook, Inc. and its 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 <memory>
#include <tuple>
#include <type_traits>
#include <utility>
#include <folly/Traits.h>
#include <folly/functional/ApplyTuple.h>
// Utility functions for container implementors
namespace folly {
namespace detail {
template <typename KeyType, typename Alloc>
struct TemporaryEmplaceKey {
TemporaryEmplaceKey(TemporaryEmplaceKey const&) = delete;
TemporaryEmplaceKey(TemporaryEmplaceKey&&) = delete;
template <typename... Args>
TemporaryEmplaceKey(Alloc& a, std::tuple<Args...>&& args) : alloc_(a) {
auto p = &value();
apply(
[&, p](auto&&... inner) {
std::allocator_traits<Alloc>::construct(
alloc_, p, std::forward<decltype(inner)>(inner)...);
},
std::move(args));
}
~TemporaryEmplaceKey() {
std::allocator_traits<Alloc>::destroy(alloc_, &value());
}
KeyType& value() {
return *static_cast<KeyType*>(static_cast<void*>(&raw_));
}
Alloc& alloc_;
std::aligned_storage_t<sizeof(KeyType), alignof(KeyType)> raw_;
};
// A map's emplace(args...) function takes arguments that can be used to
// construct a pair<key_type const, mapped_type>, but that construction
// only needs to take place if the key is not present in the container.
// callWithExtractedKey helps to handle this efficiently by looking for a
// reference to the key within the args list. If the search is successful
// then the search can be performed without constructing any temporaries.
// If the search is not successful then callWithExtractedKey constructs
// a temporary key_type and a new argument list suitable for constructing
// the entire value_type if necessary.
//
// callWithExtractedKey(a, f, args...) will call f(k, args'...), where
// k is the key and args'... is an argument list that can be used to
// construct a pair of key and mapped value. Note that this means f gets
// the key twice.
//
// In some cases a temporary key must be constructed. This is accomplished
// with std::allocator_traits<>::construct, and the temporary will be
// destroyed with std::allocator_traits<>::destroy. Using the allocator's
// construct method reduces unnecessary copies for pmr allocators.
//
// callWithExtractedKey supports heterogeneous lookup with the UsableAsKey
// template parameter. If a single key argument of type K is found in
// args... then it will be passed directly to f if it is either KeyType or
// if UsableAsKey<remove_cvref_t<K>>::value is true. If you don't care
// about heterogeneous lookup you can just pass a single-arg template
// that extends std::false_type.
template <
typename KeyType,
template <typename> class UsableAsKey,
typename Alloc,
typename Func,
typename Arg1,
typename... Args2,
std::enable_if_t<
std::is_same<remove_cvref_t<Arg1>, KeyType>::value ||
UsableAsKey<remove_cvref_t<Arg1>>::value,
int> = 0>
auto callWithExtractedKey(
Alloc&,
Func&& f,
std::piecewise_construct_t,
std::tuple<Arg1>&& first_args,
std::tuple<Args2...>&& second_args) {
// we found a usable key in the args :)
auto const& key = std::get<0>(first_args);
return f(
key,
std::piecewise_construct,
std::tuple<Arg1&&>(std::move(first_args)),
std::tuple<Args2&&...>(std::move(second_args)));
}
template <
typename KeyType,
template <typename> class UsableAsKey,
typename Alloc,
typename Func,
typename... Args1,
typename... Args2>
auto callWithExtractedKey(
Alloc& a,
Func&& f,
std::piecewise_construct_t,
std::tuple<Args1...>&& first_args,
std::tuple<Args2...>&& second_args) {
// we will need to materialize a temporary key :(
TemporaryEmplaceKey<KeyType, Alloc> key(
a, std::tuple<Args1&&...>(std::move(first_args)));
return f(
const_cast<KeyType const&>(key.value()),
std::piecewise_construct,
std::forward_as_tuple(std::move(key.value())),
std::tuple<Args2&&...>(std::move(second_args)));
}
template <
typename KeyType,
template <typename> class UsableAsKey,
typename Alloc,
typename Func>
auto callWithExtractedKey(Alloc& a, Func&& f) {
return callWithExtractedKey<KeyType, UsableAsKey>(
a,
std::forward<Func>(f),
std::piecewise_construct,
std::tuple<>{},
std::tuple<>{});
}
template <
typename KeyType,
template <typename> class UsableAsKey,
typename Alloc,
typename Func,
typename U1,
typename U2>
auto callWithExtractedKey(Alloc& a, Func&& f, U1&& x, U2&& y) {
return callWithExtractedKey<KeyType, UsableAsKey>(
a,
std::forward<Func>(f),
std::piecewise_construct,
std::forward_as_tuple(std::forward<U1>(x)),
std::forward_as_tuple(std::forward<U2>(y)));
}
template <
typename KeyType,
template <typename> class UsableAsKey,
typename Alloc,
typename Func,
typename U1,
typename U2>
auto callWithExtractedKey(Alloc& a, Func&& f, std::pair<U1, U2> const& p) {
return callWithExtractedKey<KeyType, UsableAsKey>(
a,
std::forward<Func>(f),
std::piecewise_construct,
std::forward_as_tuple(p.first),
std::forward_as_tuple(p.second));
}
template <
typename KeyType,
template <typename> class UsableAsKey,
typename Alloc,
typename Func,
typename U1,
typename U2>
auto callWithExtractedKey(Alloc& a, Func&& f, std::pair<U1, U2>&& p) {
return callWithExtractedKey<KeyType, UsableAsKey>(
a,
std::forward<Func>(f),
std::piecewise_construct,
std::forward_as_tuple(std::move(p.first)),
std::forward_as_tuple(std::move(p.second)));
}
// callWithConstructedKey is the set container analogue of
// callWithExtractedKey
template <
typename KeyType,
template <typename> class UsableAsKey,
typename Alloc,
typename Func,
typename Arg,
std::enable_if_t<
std::is_same<remove_cvref_t<Arg>, KeyType>::value ||
UsableAsKey<remove_cvref_t<Arg>>::value,
int> = 0>
auto callWithConstructedKey(Alloc&, Func&& f, Arg&& arg) {
// we found a usable key in the args :)
auto const& key = arg;
return f(key, std::forward<Arg>(arg));
}
template <
typename KeyType,
template <typename> class UsableAsKey,
typename Alloc,
typename Func,
typename... Args>
auto callWithConstructedKey(Alloc& a, Func&& f, Args&&... args) {
// we will need to materialize a temporary key :(
TemporaryEmplaceKey<KeyType, Alloc> key(
a, std::forward_as_tuple(std::forward<Args>(args)...));
return f(const_cast<KeyType const&>(key.value()), std::move(key.value()));
}
} // namespace detail
} // namespace folly