Abseil Common Libraries (C++) (grcp 依赖)
https://abseil.io/
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
182 lines
4.9 KiB
182 lines
4.9 KiB
// Copyright 2018 The Abseil Authors. |
|
// |
|
// 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 |
|
// |
|
// https://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. |
|
// |
|
// Generates random values for testing. Specialized only for the few types we |
|
// care about. |
|
|
|
#ifndef ABSL_CONTAINER_INTERNAL_HASH_GENERATOR_TESTING_H_ |
|
#define ABSL_CONTAINER_INTERNAL_HASH_GENERATOR_TESTING_H_ |
|
|
|
#include <stdint.h> |
|
|
|
#include <algorithm> |
|
#include <cassert> |
|
#include <iosfwd> |
|
#include <random> |
|
#include <tuple> |
|
#include <type_traits> |
|
#include <utility> |
|
#include <vector> |
|
|
|
#include "absl/container/internal/hash_policy_testing.h" |
|
#include "absl/memory/memory.h" |
|
#include "absl/meta/type_traits.h" |
|
#include "absl/strings/string_view.h" |
|
|
|
namespace absl { |
|
ABSL_NAMESPACE_BEGIN |
|
namespace container_internal { |
|
namespace hash_internal { |
|
namespace generator_internal { |
|
|
|
template <class Container, class = void> |
|
struct IsMap : std::false_type {}; |
|
|
|
template <class Map> |
|
struct IsMap<Map, absl::void_t<typename Map::mapped_type>> : std::true_type {}; |
|
|
|
} // namespace generator_internal |
|
|
|
std::mt19937_64* GetSharedRng(); |
|
|
|
enum Enum { |
|
kEnumEmpty, |
|
kEnumDeleted, |
|
}; |
|
|
|
enum class EnumClass : uint64_t { |
|
kEmpty, |
|
kDeleted, |
|
}; |
|
|
|
inline std::ostream& operator<<(std::ostream& o, const EnumClass& ec) { |
|
return o << static_cast<uint64_t>(ec); |
|
} |
|
|
|
template <class T, class E = void> |
|
struct Generator; |
|
|
|
template <class T> |
|
struct Generator<T, typename std::enable_if<std::is_integral<T>::value>::type> { |
|
T operator()() const { |
|
std::uniform_int_distribution<T> dist; |
|
return dist(*GetSharedRng()); |
|
} |
|
}; |
|
|
|
template <> |
|
struct Generator<Enum> { |
|
Enum operator()() const { |
|
std::uniform_int_distribution<typename std::underlying_type<Enum>::type> |
|
dist; |
|
while (true) { |
|
auto variate = dist(*GetSharedRng()); |
|
if (variate != kEnumEmpty && variate != kEnumDeleted) |
|
return static_cast<Enum>(variate); |
|
} |
|
} |
|
}; |
|
|
|
template <> |
|
struct Generator<EnumClass> { |
|
EnumClass operator()() const { |
|
std::uniform_int_distribution< |
|
typename std::underlying_type<EnumClass>::type> |
|
dist; |
|
while (true) { |
|
EnumClass variate = static_cast<EnumClass>(dist(*GetSharedRng())); |
|
if (variate != EnumClass::kEmpty && variate != EnumClass::kDeleted) |
|
return static_cast<EnumClass>(variate); |
|
} |
|
} |
|
}; |
|
|
|
template <> |
|
struct Generator<std::string> { |
|
std::string operator()() const; |
|
}; |
|
|
|
template <> |
|
struct Generator<absl::string_view> { |
|
absl::string_view operator()() const; |
|
}; |
|
|
|
template <> |
|
struct Generator<NonStandardLayout> { |
|
NonStandardLayout operator()() const { |
|
return NonStandardLayout(Generator<std::string>()()); |
|
} |
|
}; |
|
|
|
template <class K, class V> |
|
struct Generator<std::pair<K, V>> { |
|
std::pair<K, V> operator()() const { |
|
return std::pair<K, V>(Generator<typename std::decay<K>::type>()(), |
|
Generator<typename std::decay<V>::type>()()); |
|
} |
|
}; |
|
|
|
template <class... Ts> |
|
struct Generator<std::tuple<Ts...>> { |
|
std::tuple<Ts...> operator()() const { |
|
return std::tuple<Ts...>(Generator<typename std::decay<Ts>::type>()()...); |
|
} |
|
}; |
|
|
|
template <class T> |
|
struct Generator<std::unique_ptr<T>> { |
|
std::unique_ptr<T> operator()() const { |
|
return absl::make_unique<T>(Generator<T>()()); |
|
} |
|
}; |
|
|
|
template <class U> |
|
struct Generator<U, absl::void_t<decltype(std::declval<U&>().key()), |
|
decltype(std::declval<U&>().value())>> |
|
: Generator<std::pair< |
|
typename std::decay<decltype(std::declval<U&>().key())>::type, |
|
typename std::decay<decltype(std::declval<U&>().value())>::type>> {}; |
|
|
|
template <class Container> |
|
using GeneratedType = decltype( |
|
std::declval<const Generator< |
|
typename std::conditional<generator_internal::IsMap<Container>::value, |
|
typename Container::value_type, |
|
typename Container::key_type>::type>&>()()); |
|
|
|
// Naive wrapper that performs a linear search of previous values. |
|
// Beware this is O(SQR), which is reasonable for smaller kMaxValues. |
|
template <class T, size_t kMaxValues = 64, class E = void> |
|
struct UniqueGenerator { |
|
Generator<T, E> gen; |
|
std::vector<T> values; |
|
|
|
T operator()() { |
|
assert(values.size() < kMaxValues); |
|
for (;;) { |
|
T value = gen(); |
|
if (std::find(values.begin(), values.end(), value) == values.end()) { |
|
values.push_back(value); |
|
return value; |
|
} |
|
} |
|
} |
|
}; |
|
|
|
} // namespace hash_internal |
|
} // namespace container_internal |
|
ABSL_NAMESPACE_END |
|
} // namespace absl |
|
|
|
#endif // ABSL_CONTAINER_INTERNAL_HASH_GENERATOR_TESTING_H_
|
|
|