This commit is contained in:
greg
2019-03-16 20:48:50 -04:00
parent b32594fa0a
commit 5170154e8d
8 changed files with 5582 additions and 4 deletions
Vendored
+202
View File
@@ -0,0 +1,202 @@
Apache License
Version 2.0, January 2004
https://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
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.
+4 -1
View File
@@ -4,7 +4,7 @@ CXX=CL -EHsc -DNDEBUG -Fo$@ -O2
ABSEIL_LIBS=absl_bad_optional_access.lib absl_bad_variant_access.lib absl_base.lib absl_demangle_internal.lib absl_hash.lib absl_int128.lib absl_internal_bad_any_cast_impl.lib absl_internal_city.lib absl_internal_civil_time.lib absl_internal_debugging_internal.lib absl_internal_graphcycles_internal.lib absl_internal_hashtablez_sampler.lib absl_internal_malloc_internal.lib absl_internal_spinlock_wait.lib absl_internal_strings_internal.lib absl_internal_throw_delegate.lib absl_internal_time_zone.lib absl_optional.lib absl_raw_hash_set.lib absl_stacktrace.lib absl_strings.lib absl_symbolize.lib absl_synchronization.lib absl_time.lib
PROGS = stl_unordered_map sparsepp abseil_flat abseil_parallel_flat
PROGS = stl_unordered_map sparsepp phmap abseil_flat abseil_parallel_flat
BUILD_PROGS = $(addprefix build/,$(PROGS))
SIZE = 100000000
ABSEIL = ../../abseil-cpp
@@ -20,6 +20,9 @@ build/stl_unordered_map: bench.cc Makefile
build/sparsepp: bench.cc Makefile
$(CXX) -DSPARSEPP -I../../sparsepp bench.cc -o $@
build/phmap: bench.cc Makefile
$(CXX) -DPHMAP -I.. bench.cc /MD -o $@
build/abseil_flat: bench.cc Makefile
$(CXX) -DABSEIL_FLAT -I$(ABSEIL) bench.cc /MD -o $@ /link /LIBPATH:$(ABSEIL)/build/lib ${ABSEIL_LIBS}
+8 -3
View File
@@ -13,9 +13,14 @@
#include "absl/container/flat_hash_map.h"
#define MAPNAME absl::flat_hash_map
#define EXTRAARGS
#elif defined(ABSEIL_PARALLEL_FLAT)
#include "absl/container/parallel_flat_hash_map.h"
#define MAPNAME absl::parallel_flat_hash_map
#elif defined(ABSEIL_PARALLEL_FLAT) || defined(PHMAP)
#if defined(ABSEIL_PARALLEL_FLAT)
#include "absl/container/parallel_flat_hash_map.h"
#define MAPNAME absl::parallel_flat_hash_map
#else
#include "parallel_hashmap/phmap.h"
#define MAPNAME phmap::parallel_flat_hash_map
#endif
//#define MT_SUPPORT 2
#if MT_SUPPORT == 1
+3828
View File
File diff suppressed because it is too large Load Diff
+511
View File
@@ -0,0 +1,511 @@
#if !defined(phmap_base_h_guard_)
#define phmap_base_h_guard_
// ---------------------------------------------------------------------------
// Copyright (c) 2019, Gregory Popovitch - greg7mdp@gmail.com
//
// 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.
//
// Includes work from abseil-cpp (https://github.com/abseil/abseil-cpp)
// with modifications.
//
// 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.
// ---------------------------------------------------------------------------
#include <stddef.h>
#include <functional>
#include <type_traits>
#include "phmap_config.h"
namespace phmap {
namespace type_traits_internal {
template <typename... Ts>
struct VoidTImpl {
using type = void;
};
// This trick to retrieve a default alignment is necessary for our
// implementation of aligned_storage_t to be consistent with any implementation
// of std::aligned_storage.
// ---------------------------------------------------------------------------
template <size_t Len, typename T = std::aligned_storage<Len>>
struct default_alignment_of_aligned_storage;
template <size_t Len, size_t Align>
struct default_alignment_of_aligned_storage<Len,
std::aligned_storage<Len, Align>> {
static constexpr size_t value = Align;
};
// NOTE: The `is_detected` family of templates here differ from the library
// fundamentals specification in that for library fundamentals, `Op<Args...>` is
// evaluated as soon as the type `is_detected<Op, Args...>` undergoes
// substitution, regardless of whether or not the `::value` is accessed. That
// is inconsistent with all other standard traits and prevents lazy evaluation
// in larger contexts (such as if the `is_detected` check is a trailing argument
// of a `conjunction`. This implementation opts to instead be lazy in the same
// way that the standard traits are (this "defect" of the detection idiom
// specifications has been reported).
// ---------------------------------------------------------------------------
template <class Enabler, template <class...> class Op, class... Args>
struct is_detected_impl {
using type = std::false_type;
};
template <template <class...> class Op, class... Args>
struct is_detected_impl<typename VoidTImpl<Op<Args...>>::type, Op, Args...> {
using type = std::true_type;
};
template <template <class...> class Op, class... Args>
struct is_detected : is_detected_impl<void, Op, Args...>::type {};
template <class Enabler, class To, template <class...> class Op, class... Args>
struct is_detected_convertible_impl {
using type = std::false_type;
};
template <class To, template <class...> class Op, class... Args>
struct is_detected_convertible_impl<
typename std::enable_if<std::is_convertible<Op<Args...>, To>::value>::type,
To, Op, Args...> {
using type = std::true_type;
};
template <class To, template <class...> class Op, class... Args>
struct is_detected_convertible
: is_detected_convertible_impl<void, To, Op, Args...>::type {};
template <typename T>
using IsCopyAssignableImpl =
decltype(std::declval<T&>() = std::declval<const T&>());
template <typename T>
using IsMoveAssignableImpl = decltype(std::declval<T&>() = std::declval<T&&>());
} // namespace type_traits_internal
template <typename T>
struct is_copy_assignable : type_traits_internal::is_detected<
type_traits_internal::IsCopyAssignableImpl, T> {
};
template <typename T>
struct is_move_assignable : type_traits_internal::is_detected<
type_traits_internal::IsMoveAssignableImpl, T> {
};
// ---------------------------------------------------------------------------
// void_t()
//
// Ignores the type of any its arguments and returns `void`. In general, this
// metafunction allows you to create a general case that maps to `void` while
// allowing specializations that map to specific types.
//
// This metafunction is designed to be a drop-in replacement for the C++17
// `std::void_t` metafunction.
//
// NOTE: `phmap::void_t` does not use the standard-specified implementation so
// that it can remain compatible with gcc < 5.1. This can introduce slightly
// different behavior, such as when ordering partial specializations.
// ---------------------------------------------------------------------------
template <typename... Ts>
using void_t = typename type_traits_internal::VoidTImpl<Ts...>::type;
// ---------------------------------------------------------------------------
// conjunction
//
// Performs a compile-time logical AND operation on the passed types (which
// must have `::value` members convertible to `bool`. Short-circuits if it
// encounters any `false` members (and does not compare the `::value` members
// of any remaining arguments).
//
// This metafunction is designed to be a drop-in replacement for the C++17
// `std::conjunction` metafunction.
// ---------------------------------------------------------------------------
template <typename... Ts>
struct conjunction;
template <typename T, typename... Ts>
struct conjunction<T, Ts...>
: std::conditional<T::value, conjunction<Ts...>, T>::type {};
template <typename T>
struct conjunction<T> : T {};
template <>
struct conjunction<> : std::true_type {};
// ---------------------------------------------------------------------------
// disjunction
//
// Performs a compile-time logical OR operation on the passed types (which
// must have `::value` members convertible to `bool`. Short-circuits if it
// encounters any `true` members (and does not compare the `::value` members
// of any remaining arguments).
//
// This metafunction is designed to be a drop-in replacement for the C++17
// `std::disjunction` metafunction.
// ---------------------------------------------------------------------------
template <typename... Ts>
struct disjunction;
template <typename T, typename... Ts>
struct disjunction<T, Ts...> :
std::conditional<T::value, T, disjunction<Ts...>>::type {};
template <typename T>
struct disjunction<T> : T {};
template <>
struct disjunction<> : std::false_type {};
// ---------------------------------------------------------------------------
// negation
//
// Performs a compile-time logical NOT operation on the passed type (which
// must have `::value` members convertible to `bool`.
//
// This metafunction is designed to be a drop-in replacement for the C++17
// `std::negation` metafunction.
// ---------------------------------------------------------------------------
template <typename T>
struct negation : std::integral_constant<bool, !T::value> {};
// ---------------------------------------------------------------------------
// is_trivially_destructible()
//
// Determines whether the passed type `T` is trivially destructable.
//
// This metafunction is designed to be a drop-in replacement for the C++11
// `std::is_trivially_destructible()` metafunction for platforms that have
// incomplete C++11 support (such as libstdc++ 4.x). On any platforms that do
// fully support C++11, we check whether this yields the same result as the std
// implementation.
//
// NOTE: the extensions (__has_trivial_xxx) are implemented in gcc (version >=
// 4.3) and clang. Since we are supporting libstdc++ > 4.7, they should always
// be present. These extensions are documented at
// https://gcc.gnu.org/onlinedocs/gcc/Type-Traits.html#Type-Traits.
// ---------------------------------------------------------------------------
template <typename T>
struct is_trivially_destructible
: std::integral_constant<bool, __has_trivial_destructor(T) &&
std::is_destructible<T>::value>
{
#ifdef PHMAP_HAVE_STD_IS_TRIVIALLY_DESTRUCTIBLE
private:
static constexpr bool compliant = std::is_trivially_destructible<T>::value ==
is_trivially_destructible::value;
static_assert(compliant || std::is_trivially_destructible<T>::value,
"Not compliant with std::is_trivially_destructible; "
"Standard: false, Implementation: true");
static_assert(compliant || !std::is_trivially_destructible<T>::value,
"Not compliant with std::is_trivially_destructible; "
"Standard: true, Implementation: false");
#endif
};
// ---------------------------------------------------------------------------
// is_trivially_default_constructible()
//
// Determines whether the passed type `T` is trivially default constructible.
//
// This metafunction is designed to be a drop-in replacement for the C++11
// `std::is_trivially_default_constructible()` metafunction for platforms that
// have incomplete C++11 support (such as libstdc++ 4.x). On any platforms that
// do fully support C++11, we check whether this yields the same result as the
// std implementation.
//
// NOTE: according to the C++ standard, Section: 20.15.4.3 [meta.unary.prop]
// "The predicate condition for a template specialization is_constructible<T,
// Args...> shall be satisfied if and only if the following variable
// definition would be well-formed for some invented variable t:
//
// T t(declval<Args>()...);
//
// is_trivially_constructible<T, Args...> additionally requires that the
// variable definition does not call any operation that is not trivial.
// For the purposes of this check, the call to std::declval is considered
// trivial."
//
// Notes from https://en.cppreference.com/w/cpp/types/is_constructible:
// In many implementations, is_nothrow_constructible also checks if the
// destructor throws because it is effectively noexcept(T(arg)). Same
// applies to is_trivially_constructible, which, in these implementations, also
// requires that the destructor is trivial.
// GCC bug 51452: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=51452
// LWG issue 2116: http://cplusplus.github.io/LWG/lwg-active.html#2116.
//
// "T obj();" need to be well-formed and not call any nontrivial operation.
// Nontrivially destructible types will cause the expression to be nontrivial.
// ---------------------------------------------------------------------------
template <typename T>
struct is_trivially_default_constructible
: std::integral_constant<bool, __has_trivial_constructor(T) &&
std::is_default_constructible<T>::value &&
is_trivially_destructible<T>::value>
{
#ifdef PHMAP_HAVE_STD_IS_TRIVIALLY_CONSTRUCTIBLE
private:
static constexpr bool compliant =
std::is_trivially_default_constructible<T>::value ==
is_trivially_default_constructible::value;
static_assert(compliant || std::is_trivially_default_constructible<T>::value,
"Not compliant with std::is_trivially_default_constructible; "
"Standard: false, Implementation: true");
static_assert(compliant || !std::is_trivially_default_constructible<T>::value,
"Not compliant with std::is_trivially_default_constructible; "
"Standard: true, Implementation: false");
#endif
};
// ---------------------------------------------------------------------------
// is_trivially_copy_constructible()
//
// Determines whether the passed type `T` is trivially copy constructible.
//
// This metafunction is designed to be a drop-in replacement for the C++11
// `std::is_trivially_copy_constructible()` metafunction for platforms that have
// incomplete C++11 support (such as libstdc++ 4.x). On any platforms that do
// fully support C++11, we check whether this yields the same result as the std
// implementation.
//
// NOTE: `T obj(declval<const T&>());` needs to be well-formed and not call any
// nontrivial operation. Nontrivially destructible types will cause the
// expression to be nontrivial.
// ---------------------------------------------------------------------------
template <typename T>
struct is_trivially_copy_constructible
: std::integral_constant<bool, __has_trivial_copy(T) &&
std::is_copy_constructible<T>::value &&
is_trivially_destructible<T>::value>
{
#ifdef PHMAP_HAVE_STD_IS_TRIVIALLY_CONSTRUCTIBLE
private:
static constexpr bool compliant =
std::is_trivially_copy_constructible<T>::value ==
is_trivially_copy_constructible::value;
static_assert(compliant || std::is_trivially_copy_constructible<T>::value,
"Not compliant with std::is_trivially_copy_constructible; "
"Standard: false, Implementation: true");
static_assert(compliant || !std::is_trivially_copy_constructible<T>::value,
"Not compliant with std::is_trivially_copy_constructible; "
"Standard: true, Implementation: false");
#endif
};
// ---------------------------------------------------------------------------
// is_trivially_copy_assignable()
//
// Determines whether the passed type `T` is trivially copy assignable.
//
// This metafunction is designed to be a drop-in replacement for the C++11
// `std::is_trivially_copy_assignable()` metafunction for platforms that have
// incomplete C++11 support (such as libstdc++ 4.x). On any platforms that do
// fully support C++11, we check whether this yields the same result as the std
// implementation.
//
// NOTE: `is_assignable<T, U>::value` is `true` if the expression
// `declval<T>() = declval<U>()` is well-formed when treated as an unevaluated
// operand. `is_trivially_assignable<T, U>` requires the assignment to call no
// operation that is not trivial. `is_trivially_copy_assignable<T>` is simply
// `is_trivially_assignable<T&, const T&>`.
// ---------------------------------------------------------------------------
template <typename T>
struct is_trivially_copy_assignable
: std::integral_constant<
bool, __has_trivial_assign(typename std::remove_reference<T>::type) &&
phmap::is_copy_assignable<T>::value>
{
#ifdef PHMAP_HAVE_STD_IS_TRIVIALLY_ASSIGNABLE
private:
static constexpr bool compliant =
std::is_trivially_copy_assignable<T>::value ==
is_trivially_copy_assignable::value;
static_assert(compliant || std::is_trivially_copy_assignable<T>::value,
"Not compliant with std::is_trivially_copy_assignable; "
"Standard: false, Implementation: true");
static_assert(compliant || !std::is_trivially_copy_assignable<T>::value,
"Not compliant with std::is_trivially_copy_assignable; "
"Standard: true, Implementation: false");
#endif
};
// -----------------------------------------------------------------------------
// C++14 "_t" trait aliases
// -----------------------------------------------------------------------------
template <typename T>
using remove_cv_t = typename std::remove_cv<T>::type;
template <typename T>
using remove_const_t = typename std::remove_const<T>::type;
template <typename T>
using remove_volatile_t = typename std::remove_volatile<T>::type;
template <typename T>
using add_cv_t = typename std::add_cv<T>::type;
template <typename T>
using add_const_t = typename std::add_const<T>::type;
template <typename T>
using add_volatile_t = typename std::add_volatile<T>::type;
template <typename T>
using remove_reference_t = typename std::remove_reference<T>::type;
template <typename T>
using add_lvalue_reference_t = typename std::add_lvalue_reference<T>::type;
template <typename T>
using add_rvalue_reference_t = typename std::add_rvalue_reference<T>::type;
template <typename T>
using remove_pointer_t = typename std::remove_pointer<T>::type;
template <typename T>
using add_pointer_t = typename std::add_pointer<T>::type;
template <typename T>
using make_signed_t = typename std::make_signed<T>::type;
template <typename T>
using make_unsigned_t = typename std::make_unsigned<T>::type;
template <typename T>
using remove_extent_t = typename std::remove_extent<T>::type;
template <typename T>
using remove_all_extents_t = typename std::remove_all_extents<T>::type;
template <size_t Len, size_t Align = type_traits_internal::
default_alignment_of_aligned_storage<Len>::value>
using aligned_storage_t = typename std::aligned_storage<Len, Align>::type;
template <typename T>
using decay_t = typename std::decay<T>::type;
template <bool B, typename T = void>
using enable_if_t = typename std::enable_if<B, T>::type;
template <bool B, typename T, typename F>
using conditional_t = typename std::conditional<B, T, F>::type;
template <typename... T>
using common_type_t = typename std::common_type<T...>::type;
template <typename T>
using underlying_type_t = typename std::underlying_type<T>::type;
template <typename T>
using result_of_t = typename std::result_of<T>::type;
namespace type_traits_internal {
// ----------------------------------------------------------------------
// In MSVC we can't probe std::hash or stdext::hash because it triggers a
// static_assert instead of failing substitution. Libc++ prior to 4.0
// also used a static_assert.
// ----------------------------------------------------------------------
#if defined(_MSC_VER) || (defined(_LIBCPP_VERSION) && \
_LIBCPP_VERSION < 4000 && _LIBCPP_STD_VER > 11)
#define PHMAP_META_INTERNAL_STD_HASH_SFINAE_FRIENDLY_ 0
#else
#define PHMAP_META_INTERNAL_STD_HASH_SFINAE_FRIENDLY_ 1
#endif
#if !PHMAP_META_INTERNAL_STD_HASH_SFINAE_FRIENDLY_
template <typename Key, typename = size_t>
struct IsHashable : std::true_type {};
#else // PHMAP_META_INTERNAL_STD_HASH_SFINAE_FRIENDLY_
template <typename Key, typename = void>
struct IsHashable : std::false_type {};
template <typename Key>
struct IsHashable<
Key,
phmap::enable_if_t<std::is_convertible<
decltype(std::declval<std::hash<Key>&>()(std::declval<Key const&>())),
std::size_t>::value>> : std::true_type {};
#endif
struct AssertHashEnabledHelper
{
private:
static void Sink(...) {}
struct NAT {};
template <class Key>
static auto GetReturnType(int)
-> decltype(std::declval<std::hash<Key>>()(std::declval<Key const&>()));
template <class Key>
static NAT GetReturnType(...);
template <class Key>
static std::nullptr_t DoIt() {
static_assert(IsHashable<Key>::value,
"std::hash<Key> does not provide a call operator");
static_assert(
std::is_default_constructible<std::hash<Key>>::value,
"std::hash<Key> must be default constructible when it is enabled");
static_assert(
std::is_copy_constructible<std::hash<Key>>::value,
"std::hash<Key> must be copy constructible when it is enabled");
static_assert(phmap::is_copy_assignable<std::hash<Key>>::value,
"std::hash<Key> must be copy assignable when it is enabled");
// is_destructible is unchecked as it's implied by each of the
// is_constructible checks.
using ReturnType = decltype(GetReturnType<Key>(0));
static_assert(std::is_same<ReturnType, NAT>::value ||
std::is_same<ReturnType, size_t>::value,
"std::hash<Key> must return size_t");
return nullptr;
}
template <class... Ts>
friend void AssertHashEnabled();
};
template <class... Ts>
inline void AssertHashEnabled()
{
using Helper = AssertHashEnabledHelper;
Helper::Sink(Helper::DoIt<Ts>()...);
}
} // namespace type_traits_internal
} // namespace phmap
#endif // phmap_base_h_guard_
+358
View File
@@ -0,0 +1,358 @@
#if !defined(phmap_bits_h_guard_)
#define phmap_bits_h_guard_
// ---------------------------------------------------------------------------
// Copyright (c) 2019, Gregory Popovitch - greg7mdp@gmail.com
//
// 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.
//
// Includes work from abseil-cpp (https://github.com/abseil/abseil-cpp)
// with modifications.
//
// 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.
// ---------------------------------------------------------------------------
// The following guarantees declaration of the byte swap functions
#ifdef _MSC_VER
#include <stdlib.h> // NOLINT(build/include)
#elif defined(__APPLE__)
// Mac OS X / Darwin features
#include <libkern/OSByteOrder.h>
#elif defined(__FreeBSD__)
#include <sys/endian.h>
#elif defined(__GLIBC__)
#include <byteswap.h> // IWYU pragma: export
#endif
#include <string.h>
#include <cstdint>
#include "phmap_config.h"
// -----------------------------------------------------------------------------
// unaligned APIs
// -----------------------------------------------------------------------------
// Portable handling of unaligned loads, stores, and copies.
// On some platforms, like ARM, the copy functions can be more efficient
// then a load and a store.
// -----------------------------------------------------------------------------
#if defined(ADDRESS_SANITIZER) || defined(THREAD_SANITIZER) ||\
defined(MEMORY_SANITIZER)
#include <stdint.h>
extern "C" {
uint16_t __sanitizer_unaligned_load16(const void *p);
uint32_t __sanitizer_unaligned_load32(const void *p);
uint64_t __sanitizer_unaligned_load64(const void *p);
void __sanitizer_unaligned_store16(void *p, uint16_t v);
void __sanitizer_unaligned_store32(void *p, uint32_t v);
void __sanitizer_unaligned_store64(void *p, uint64_t v);
} // extern "C"
namespace phmap {
namespace bits {
inline uint16_t UnalignedLoad16(const void *p) {
return __sanitizer_unaligned_load16(p);
}
inline uint32_t UnalignedLoad32(const void *p) {
return __sanitizer_unaligned_load32(p);
}
inline uint64_t UnalignedLoad64(const void *p) {
return __sanitizer_unaligned_load64(p);
}
inline void UnalignedStore16(void *p, uint16_t v) {
__sanitizer_unaligned_store16(p, v);
}
inline void UnalignedStore32(void *p, uint32_t v) {
__sanitizer_unaligned_store32(p, v);
}
inline void UnalignedStore64(void *p, uint64_t v) {
__sanitizer_unaligned_store64(p, v);
}
} // namespace bits
} // namespace phmap
#define PHMAP_INTERNAL_UNALIGNED_LOAD16(_p) (phmap::bits::UnalignedLoad16(_p))
#define PHMAP_INTERNAL_UNALIGNED_LOAD32(_p) (phmap::bits::UnalignedLoad32(_p))
#define PHMAP_INTERNAL_UNALIGNED_LOAD64(_p) (phmap::bits::UnalignedLoad64(_p))
#define PHMAP_INTERNAL_UNALIGNED_STORE16(_p, _val) (phmap::bits::UnalignedStore16(_p, _val))
#define PHMAP_INTERNAL_UNALIGNED_STORE32(_p, _val) (phmap::bits::UnalignedStore32(_p, _val))
#define PHMAP_INTERNAL_UNALIGNED_STORE64(_p, _val) (phmap::bits::UnalignedStore64(_p, _val))
#elif defined(UNDEFINED_BEHAVIOR_SANITIZER)
namespace phmap {
namespace bits {
inline uint16_t UnalignedLoad16(const void *p) {
uint16_t t;
memcpy(&t, p, sizeof t);
return t;
}
inline uint32_t UnalignedLoad32(const void *p) {
uint32_t t;
memcpy(&t, p, sizeof t);
return t;
}
inline uint64_t UnalignedLoad64(const void *p) {
uint64_t t;
memcpy(&t, p, sizeof t);
return t;
}
inline void UnalignedStore16(void *p, uint16_t v) { memcpy(p, &v, sizeof v); }
inline void UnalignedStore32(void *p, uint32_t v) { memcpy(p, &v, sizeof v); }
inline void UnalignedStore64(void *p, uint64_t v) { memcpy(p, &v, sizeof v); }
} // namespace bits
} // namespace phmap
#define PHMAP_INTERNAL_UNALIGNED_LOAD16(_p) \
(phmap::bits::UnalignedLoad16(_p))
#define PHMAP_INTERNAL_UNALIGNED_LOAD32(_p) \
(phmap::bits::UnalignedLoad32(_p))
#define PHMAP_INTERNAL_UNALIGNED_LOAD64(_p) \
(phmap::bits::UnalignedLoad64(_p))
#define PHMAP_INTERNAL_UNALIGNED_STORE16(_p, _val) \
(phmap::bits::UnalignedStore16(_p, _val))
#define PHMAP_INTERNAL_UNALIGNED_STORE32(_p, _val) \
(phmap::bits::UnalignedStore32(_p, _val))
#define PHMAP_INTERNAL_UNALIGNED_STORE64(_p, _val) \
(phmap::bits::UnalignedStore64(_p, _val))
#elif defined(__x86_64__) || defined(_M_X64) || defined(__i386) || \
defined(_M_IX86) || defined(__ppc__) || defined(__PPC__) || \
defined(__ppc64__) || defined(__PPC64__)
// x86 and x86-64 can perform unaligned loads/stores directly;
// modern PowerPC hardware can also do unaligned integer loads and stores;
// but note: the FPU still sends unaligned loads and stores to a trap handler!
#define PHMAP_INTERNAL_UNALIGNED_LOAD16(_p) \
(*reinterpret_cast<const uint16_t *>(_p))
#define PHMAP_INTERNAL_UNALIGNED_LOAD32(_p) \
(*reinterpret_cast<const uint32_t *>(_p))
#define PHMAP_INTERNAL_UNALIGNED_LOAD64(_p) \
(*reinterpret_cast<const uint64_t *>(_p))
#define PHMAP_INTERNAL_UNALIGNED_STORE16(_p, _val) \
(*reinterpret_cast<uint16_t *>(_p) = (_val))
#define PHMAP_INTERNAL_UNALIGNED_STORE32(_p, _val) \
(*reinterpret_cast<uint32_t *>(_p) = (_val))
#define PHMAP_INTERNAL_UNALIGNED_STORE64(_p, _val) \
(*reinterpret_cast<uint64_t *>(_p) = (_val))
#elif defined(__arm__) && \
!defined(__ARM_ARCH_5__) && \
!defined(__ARM_ARCH_5T__) && \
!defined(__ARM_ARCH_5TE__) && \
!defined(__ARM_ARCH_5TEJ__) && \
!defined(__ARM_ARCH_6__) && \
!defined(__ARM_ARCH_6J__) && \
!defined(__ARM_ARCH_6K__) && \
!defined(__ARM_ARCH_6Z__) && \
!defined(__ARM_ARCH_6ZK__) && \
!defined(__ARM_ARCH_6T2__)
namespace phmap {
namespace bits {
struct Unaligned16Struct
{
uint16_t value;
uint8_t dummy; // To make the size non-power-of-two.
} PHMAP_ATTRIBUTE_PACKED;
struct Unaligned32Struct
{
uint32_t value;
uint8_t dummy; // To make the size non-power-of-two.
} PHMAP_ATTRIBUTE_PACKED;
} // namespace bits
} // namespace phmap
#define PHMAP_INTERNAL_UNALIGNED_LOAD16(_p) \
((reinterpret_cast<const ::phmap::bits::Unaligned16Struct *>(_p))->value)
#define PHMAP_INTERNAL_UNALIGNED_LOAD32(_p) \
((reinterpret_cast<const ::phmap::bits::Unaligned32Struct *>(_p))->value)
#define PHMAP_INTERNAL_UNALIGNED_STORE16(_p, _val) \
((reinterpret_cast< ::phmap::bits::Unaligned16Struct *>(_p))->value = (_val))
#define PHMAP_INTERNAL_UNALIGNED_STORE32(_p, _val) \
((reinterpret_cast< ::phmap::bits::Unaligned32Struct *>(_p))->value = (_val))
namespace phmap {
namespace bits {
inline uint64_t UnalignedLoad64(const void *p)
{
uint64_t t;
memcpy(&t, p, sizeof t);
return t;
}
inline void UnalignedStore64(void *p, uint64_t v) { memcpy(p, &v, sizeof v); }
} // namespace bits
} // namespace phmap
#define PHMAP_INTERNAL_UNALIGNED_LOAD64(_p) \
(phmap::bits::UnalignedLoad64(_p))
#define PHMAP_INTERNAL_UNALIGNED_STORE64(_p, _val) \
(phmap::bits::UnalignedStore64(_p, _val))
#else
// PHMAP_INTERNAL_NEED_ALIGNED_LOADS is defined when the underlying platform
// doesn't support unaligned access.
#define PHMAP_INTERNAL_NEED_ALIGNED_LOADS
// These functions are provided for architectures that don't support
// unaligned loads and stores.
namespace phmap {
namespace bits {
inline uint16_t UnalignedLoad16(const void *p) {
uint16_t t;
memcpy(&t, p, sizeof t);
return t;
}
inline uint32_t UnalignedLoad32(const void *p) {
uint32_t t;
memcpy(&t, p, sizeof t);
return t;
}
inline uint64_t UnalignedLoad64(const void *p) {
uint64_t t;
memcpy(&t, p, sizeof t);
return t;
}
inline void UnalignedStore16(void *p, uint16_t v) { memcpy(p, &v, sizeof v); }
inline void UnalignedStore32(void *p, uint32_t v) { memcpy(p, &v, sizeof v); }
inline void UnalignedStore64(void *p, uint64_t v) { memcpy(p, &v, sizeof v); }
} // namespace bits
} // namespace phmap
#define PHMAP_INTERNAL_UNALIGNED_LOAD16(_p) (phmap::bits::UnalignedLoad16(_p))
#define PHMAP_INTERNAL_UNALIGNED_LOAD32(_p) (phmap::bits::UnalignedLoad32(_p))
#define PHMAP_INTERNAL_UNALIGNED_LOAD64(_p) (phmap::bits::UnalignedLoad64(_p))
#define PHMAP_INTERNAL_UNALIGNED_STORE16(_p, _val) (phmap::bits::UnalignedStore16(_p, _val))
#define PHMAP_INTERNAL_UNALIGNED_STORE32(_p, _val) (phmap::bits::UnalignedStore32(_p, _val))
#define PHMAP_INTERNAL_UNALIGNED_STORE64(_p, _val) (phmap::bits::UnalignedStore64(_p, _val))
#endif
// -----------------------------------------------------------------------------
// File: optimization.h
// -----------------------------------------------------------------------------
#if defined(__pnacl__)
#define PHMAP_BLOCK_TAIL_CALL_OPTIMIZATION() if (volatile int x = 0) { (void)x; }
#elif defined(__clang__)
// Clang will not tail call given inline volatile assembly.
#define PHMAP_BLOCK_TAIL_CALL_OPTIMIZATION() __asm__ __volatile__("")
#elif defined(__GNUC__)
// GCC will not tail call given inline volatile assembly.
#define PHMAP_BLOCK_TAIL_CALL_OPTIMIZATION() __asm__ __volatile__("")
#elif defined(_MSC_VER)
#include <intrin.h>
// The __nop() intrinsic blocks the optimisation.
#define PHMAP_BLOCK_TAIL_CALL_OPTIMIZATION() __nop()
#else
#define PHMAP_BLOCK_TAIL_CALL_OPTIMIZATION() if (volatile int x = 0) { (void)x; }
#endif
#if defined(__GNUC__)
// Cache line alignment
#if defined(__i386__) || defined(__x86_64__)
#define PHMAP_CACHELINE_SIZE 64
#elif defined(__powerpc64__)
#define PHMAP_CACHELINE_SIZE 128
#elif defined(__aarch64__)
// We would need to read special register ctr_el0 to find out L1 dcache size.
// This value is a good estimate based on a real aarch64 machine.
#define PHMAP_CACHELINE_SIZE 64
#elif defined(__arm__)
// Cache line sizes for ARM: These values are not strictly correct since
// cache line sizes depend on implementations, not architectures. There
// are even implementations with cache line sizes configurable at boot
// time.
#if defined(__ARM_ARCH_5T__)
#define PHMAP_CACHELINE_SIZE 32
#elif defined(__ARM_ARCH_7A__)
#define PHMAP_CACHELINE_SIZE 64
#endif
#endif
#ifndef PHMAP_CACHELINE_SIZE
// A reasonable default guess. Note that overestimates tend to waste more
// space, while underestimates tend to waste more time.
#define PHMAP_CACHELINE_SIZE 64
#endif
#define PHMAP_CACHELINE_ALIGNED __attribute__((aligned(PHMAP_CACHELINE_SIZE)))
#elif defined(_MSC_VER)
#define PHMAP_CACHELINE_SIZE 64
#define PHMAP_CACHELINE_ALIGNED __declspec(align(PHMAP_CACHELINE_SIZE))
#else
#define PHMAP_CACHELINE_SIZE 64
#define PHMAP_CACHELINE_ALIGNED
#endif
#if PHMAP_HAVE_BUILTIN(__builtin_expect) || \
(defined(__GNUC__) && !defined(__clang__))
#define PHMAP_PREDICT_FALSE(x) (__builtin_expect(x, 0))
#define PHMAP_PREDICT_TRUE(x) (__builtin_expect(!!(x), 1))
#else
#define PHMAP_PREDICT_FALSE(x) (x)
#define PHMAP_PREDICT_TRUE(x) (x)
#endif
#endif // phmap_bits_h_guard_
+631
View File
@@ -0,0 +1,631 @@
#if !defined(phmap_config_h_guard_)
#define phmap_config_h_guard_
// ---------------------------------------------------------------------------
// Copyright (c) 2019, Gregory Popovitch - greg7mdp@gmail.com
//
// 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.
//
// Includes work from abseil-cpp (https://github.com/abseil/abseil-cpp)
// with modifications.
//
// 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.
// ---------------------------------------------------------------------------
// Included for the __GLIBC__ macro (or similar macros on other systems).
#include <limits.h>
#ifdef __cplusplus
// Included for __GLIBCXX__, _LIBCPP_VERSION
#include <cstddef>
#endif // __cplusplus
#if defined(__APPLE__)
// Included for TARGET_OS_IPHONE, __IPHONE_OS_VERSION_MIN_REQUIRED,
// __IPHONE_8_0.
#include <Availability.h>
#include <TargetConditionals.h>
#endif
// -----------------------------------------------------------------------------
// Some sanity checks
// -----------------------------------------------------------------------------
#if defined(__CYGWIN__)
#error "Cygwin is not supported."
#endif
#if defined(_MSC_FULL_VER) && _MSC_FULL_VER < 190023918 && !defined(__clang__)
#error "phmap requires Visual Studio 2015 Update 2 or higher."
#endif
// We support gcc 4.7 and later.
#if defined(__GNUC__) && !defined(__clang__)
#if __GNUC__ < 4 || (__GNUC__ == 4 && __GNUC_MINOR__ < 7)
#error "phmap requires gcc 4.7 or higher."
#endif
#endif
// We support Apple Xcode clang 4.2.1 (version 421.11.65) and later.
// This corresponds to Apple Xcode version 4.5.
#if defined(__apple_build_version__) && __apple_build_version__ < 4211165
#error "phmap requires __apple_build_version__ of 4211165 or higher."
#endif
// Enforce C++11 as the minimum.
#if defined(__cplusplus) && !defined(_MSC_VER)
#if __cplusplus < 201103L
#error "C++ versions less than C++11 are not supported."
#endif
#endif
// We have chosen glibc 2.12 as the minimum
#if defined(__GLIBC__) && defined(__GLIBC_PREREQ)
#if !__GLIBC_PREREQ(2, 12)
#error "Minimum required version of glibc is 2.12."
#endif
#endif
#if defined(_STLPORT_VERSION)
#error "STLPort is not supported."
#endif
#if CHAR_BIT != 8
#error "phmap assumes CHAR_BIT == 8."
#endif
// phmap currently assumes that an int is 4 bytes.
#if INT_MAX < 2147483647
#error "phmap assumes that int is at least 4 bytes. "
#endif
// -----------------------------------------------------------------------------
// Compiler Feature Checks
// -----------------------------------------------------------------------------
#ifdef __has_builtin
#define PHMAP_HAVE_BUILTIN(x) __has_builtin(x)
#else
#define PHMAP_HAVE_BUILTIN(x) 0
#endif
// ----------------------------------------------------------------
// Checks whether `std::is_trivially_destructible<T>` is supported.
// ----------------------------------------------------------------
#ifdef PHMAP_HAVE_STD_IS_TRIVIALLY_DESTRUCTIBLE
#error PHMAP_HAVE_STD_IS_TRIVIALLY_DESTRUCTIBLE cannot be directly set
#elif defined(_LIBCPP_VERSION) || \
(!defined(__clang__) && defined(__GNUC__) && defined(__GLIBCXX__) && \
(__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 8))) || \
defined(_MSC_VER)
#define PHMAP_HAVE_STD_IS_TRIVIALLY_DESTRUCTIBLE 1
#endif
// --------------------------------------------------------------
// Checks whether `std::is_trivially_default_constructible<T>` is
// supported.
// --------------------------------------------------------------
#if defined(PHMAP_HAVE_STD_IS_TRIVIALLY_CONSTRUCTIBLE)
#error PHMAP_HAVE_STD_IS_TRIVIALLY_CONSTRUCTIBLE cannot be directly set
#elif defined(PHMAP_HAVE_STD_IS_TRIVIALLY_ASSIGNABLE)
#error PHMAP_HAVE_STD_IS_TRIVIALLY_ASSIGNABLE cannot directly set
#elif (defined(__clang__) && defined(_LIBCPP_VERSION)) || \
(!defined(__clang__) && defined(__GNUC__) && \
(__GNUC__ > 5 || (__GNUC__ == 5 && __GNUC_MINOR__ >= 1)) && \
(defined(_LIBCPP_VERSION) || defined(__GLIBCXX__))) || \
(defined(_MSC_VER) && !defined(__NVCC__))
#define PHMAP_HAVE_STD_IS_TRIVIALLY_CONSTRUCTIBLE 1
#define PHMAP_HAVE_STD_IS_TRIVIALLY_ASSIGNABLE 1
#endif
// -------------------------------------------------------------------
// Checks whether C++11's `thread_local` storage duration specifier is
// supported.
// -------------------------------------------------------------------
#ifdef PHMAP_HAVE_THREAD_LOCAL
#error PHMAP_HAVE_THREAD_LOCAL cannot be directly set
#elif defined(__APPLE__)
#if __has_feature(cxx_thread_local) && \
!(TARGET_OS_IPHONE && __IPHONE_OS_VERSION_MIN_REQUIRED < __IPHONE_9_0)
#define PHMAP_HAVE_THREAD_LOCAL 1
#endif
#else // !defined(__APPLE__)
#define PHMAP_HAVE_THREAD_LOCAL 1
#endif
#if defined(__ANDROID__) && defined(__clang__)
#if __has_include(<android/ndk-version.h>)
#include <android/ndk-version.h>
#endif // __has_include(<android/ndk-version.h>)
#if defined(__ANDROID__) && defined(__clang__) && defined(__NDK_MAJOR__) && \
defined(__NDK_MINOR__) && \
((__NDK_MAJOR__ < 12) || ((__NDK_MAJOR__ == 12) && (__NDK_MINOR__ < 1)))
#undef PHMAP_HAVE_TLS
#undef PHMAP_HAVE_THREAD_LOCAL
#endif
#endif
// ------------------------------------------------------------
// Checks whether the __int128 compiler extension for a 128-bit
// integral type is supported.
// ------------------------------------------------------------
#ifdef PHMAP_HAVE_INTRINSIC_INT128
#error PHMAP_HAVE_INTRINSIC_INT128 cannot be directly set
#elif defined(__SIZEOF_INT128__)
#if (defined(__clang__) && !defined(_WIN32) && !defined(__aarch64__)) || \
(defined(__CUDACC__) && __CUDACC_VER_MAJOR__ >= 9) || \
(defined(__GNUC__) && !defined(__clang__) && !defined(__CUDACC__))
#define PHMAP_HAVE_INTRINSIC_INT128 1
#elif defined(__CUDACC__)
#if __CUDACC_VER__ >= 70000
#define PHMAP_HAVE_INTRINSIC_INT128 1
#endif // __CUDACC_VER__ >= 70000
#endif // defined(__CUDACC__)
#endif
// ------------------------------------------------------------------
// Checks whether the compiler both supports and enables exceptions.
// ------------------------------------------------------------------
#ifdef PHMAP_HAVE_EXCEPTIONS
#error PHMAP_HAVE_EXCEPTIONS cannot be directly set.
#elif defined(__clang__)
#if defined(__EXCEPTIONS) && __has_feature(cxx_exceptions)
#define PHMAP_HAVE_EXCEPTIONS 1
#endif // defined(__EXCEPTIONS) && __has_feature(cxx_exceptions)
#elif !(defined(__GNUC__) && (__GNUC__ < 5) && !defined(__EXCEPTIONS)) && \
!(defined(__GNUC__) && (__GNUC__ >= 5) && !defined(__cpp_exceptions)) && \
!(defined(_MSC_VER) && !defined(_CPPUNWIND))
#define PHMAP_HAVE_EXCEPTIONS 1
#endif
// -----------------------------------------------------------------------
// Checks whether the platform has an mmap(2) implementation as defined in
// POSIX.1-2001.
// -----------------------------------------------------------------------
#ifdef PHMAP_HAVE_MMAP
#error PHMAP_HAVE_MMAP cannot be directly set
#elif defined(__linux__) || defined(__APPLE__) || defined(__FreeBSD__) || \
defined(__ros__) || defined(__native_client__) || defined(__asmjs__) || \
defined(__wasm__) || defined(__Fuchsia__) || defined(__sun) || \
defined(__ASYLO__)
#define PHMAP_HAVE_MMAP 1
#endif
// -----------------------------------------------------------------------
// Checks the endianness of the platform.
// -----------------------------------------------------------------------
#if defined(PHMAP_IS_BIG_ENDIAN)
#error "PHMAP_IS_BIG_ENDIAN cannot be directly set."
#endif
#if defined(PHMAP_IS_LITTLE_ENDIAN)
#error "PHMAP_IS_LITTLE_ENDIAN cannot be directly set."
#endif
#if (defined(__BYTE_ORDER__) && defined(__ORDER_LITTLE_ENDIAN__) && \
__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__)
#define PHMAP_IS_LITTLE_ENDIAN 1
#elif defined(__BYTE_ORDER__) && defined(__ORDER_BIG_ENDIAN__) && \
__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
#define PHMAP_IS_BIG_ENDIAN 1
#elif defined(_WIN32)
#define PHMAP_IS_LITTLE_ENDIAN 1
#else
#error "phmap endian detection needs to be set up for your compiler"
#endif
#if defined(__APPLE__) && defined(_LIBCPP_VERSION) && \
defined(__MAC_OS_X_VERSION_MIN_REQUIRED__) && \
__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ < 101400
#define PHMAP_INTERNAL_MACOS_CXX17_TYPES_UNAVAILABLE 1
#else
#define PHMAP_INTERNAL_MACOS_CXX17_TYPES_UNAVAILABLE 0
#endif
// ---------------------------------------------------------------------------
// Checks whether C++17 std::any is available by checking whether <any> exists.
// ---------------------------------------------------------------------------
#ifdef PHMAP_HAVE_STD_ANY
#error "PHMAP_HAVE_STD_ANY cannot be directly set."
#endif
#ifdef __has_include
#if __has_include(<any>) && __cplusplus >= 201703L && \
!PHMAP_INTERNAL_MACOS_CXX17_TYPES_UNAVAILABLE
#define PHMAP_HAVE_STD_ANY 1
#endif
#endif
#ifdef PHMAP_HAVE_STD_OPTIONAL
#error "PHMAP_HAVE_STD_OPTIONAL cannot be directly set."
#endif
#ifdef __has_include
#if __has_include(<optional>) && __cplusplus >= 201703L && \
!PHMAP_INTERNAL_MACOS_CXX17_TYPES_UNAVAILABLE
#define PHMAP_HAVE_STD_OPTIONAL 1
#endif
#endif
#ifdef PHMAP_HAVE_STD_VARIANT
#error "PHMAP_HAVE_STD_VARIANT cannot be directly set."
#endif
#ifdef __has_include
#if __has_include(<variant>) && __cplusplus >= 201703L && \
!PHMAP_INTERNAL_MACOS_CXX17_TYPES_UNAVAILABLE
#define PHMAP_HAVE_STD_VARIANT 1
#endif
#endif
#ifdef PHMAP_HAVE_STD_STRING_VIEW
#error "PHMAP_HAVE_STD_STRING_VIEW cannot be directly set."
#endif
#ifdef __has_include
#if __has_include(<string_view>) && __cplusplus >= 201703L
#define PHMAP_HAVE_STD_STRING_VIEW 1
#endif
#endif
#if defined(_MSC_VER) && _MSC_VER >= 1910 && \
((defined(_MSVC_LANG) && _MSVC_LANG > 201402) || __cplusplus > 201402)
// #define PHMAP_HAVE_STD_ANY 1
#define PHMAP_HAVE_STD_OPTIONAL 1
#define PHMAP_HAVE_STD_VARIANT 1
#define PHMAP_HAVE_STD_STRING_VIEW 1
#endif
// In debug mode, MSVC 2017's std::variant throws a EXCEPTION_ACCESS_VIOLATION
// SEH exception from emplace for variant<SomeStruct> when constructing the
// struct can throw. This defeats some of variant_test and
// variant_exception_safety_test.
#if defined(_MSC_VER) && _MSC_VER >= 1700 && defined(_DEBUG)
#define PHMAP_INTERNAL_MSVC_2017_DBG_MODE
#endif
// -----------------------------------------------------------------------------
// Sanitizer Attributes
// -----------------------------------------------------------------------------
//
// Sanitizer-related attributes are not "defined" in this file (and indeed
// are not defined as such in any file). To utilize the following
// sanitizer-related attributes within your builds, define the following macros
// within your build using a `-D` flag, along with the given value for
// `-fsanitize`:
//
// * `ADDRESS_SANITIZER` + `-fsanitize=address` (Clang, GCC 4.8)
// * `MEMORY_SANITIZER` + `-fsanitize=memory` (Clang-only)
// * `THREAD_SANITIZER + `-fsanitize=thread` (Clang, GCC 4.8+)
// * `UNDEFINED_BEHAVIOR_SANITIZER` + `-fsanitize=undefined` (Clang, GCC 4.9+)
// * `CONTROL_FLOW_INTEGRITY` + -fsanitize=cfi (Clang-only)
// -----------------------------------------------------------------------------
// -----------------------------------------------------------------------------
// A function-like feature checking macro that is a wrapper around
// `__has_attribute`, which is defined by GCC 5+ and Clang and evaluates to a
// nonzero constant integer if the attribute is supported or 0 if not.
//
// It evaluates to zero if `__has_attribute` is not defined by the compiler.
// -----------------------------------------------------------------------------
#ifdef __has_attribute
#define PHMAP_HAVE_ATTRIBUTE(x) __has_attribute(x)
#else
#define PHMAP_HAVE_ATTRIBUTE(x) 0
#endif
// -----------------------------------------------------------------------------
// A function-like feature checking macro that accepts C++11 style attributes.
// It's a wrapper around `__has_cpp_attribute`, defined by ISO C++ SD-6
// (https://en.cppreference.com/w/cpp/experimental/feature_test). If we don't
// find `__has_cpp_attribute`, will evaluate to 0.
// -----------------------------------------------------------------------------
#if defined(__cplusplus) && defined(__has_cpp_attribute)
#define PHMAP_HAVE_CPP_ATTRIBUTE(x) __has_cpp_attribute(x)
#else
#define PHMAP_HAVE_CPP_ATTRIBUTE(x) 0
#endif
// -----------------------------------------------------------------------------
// Function Attributes
// -----------------------------------------------------------------------------
#if PHMAP_HAVE_ATTRIBUTE(format) || (defined(__GNUC__) && !defined(__clang__))
#define PHMAP_PRINTF_ATTRIBUTE(string_index, first_to_check) \
__attribute__((__format__(__printf__, string_index, first_to_check)))
#define PHMAP_SCANF_ATTRIBUTE(string_index, first_to_check) \
__attribute__((__format__(__scanf__, string_index, first_to_check)))
#else
#define PHMAP_PRINTF_ATTRIBUTE(string_index, first_to_check)
#define PHMAP_SCANF_ATTRIBUTE(string_index, first_to_check)
#endif
#if PHMAP_HAVE_ATTRIBUTE(always_inline) || \
(defined(__GNUC__) && !defined(__clang__))
#define PHMAP_ATTRIBUTE_ALWAYS_INLINE __attribute__((always_inline))
#define PHMAP_HAVE_ATTRIBUTE_ALWAYS_INLINE 1
#else
#define PHMAP_ATTRIBUTE_ALWAYS_INLINE
#endif
#if PHMAP_HAVE_ATTRIBUTE(noinline) || (defined(__GNUC__) && !defined(__clang__))
#define PHMAP_ATTRIBUTE_NOINLINE __attribute__((noinline))
#define PHMAP_HAVE_ATTRIBUTE_NOINLINE 1
#else
#define PHMAP_ATTRIBUTE_NOINLINE
#endif
#if PHMAP_HAVE_ATTRIBUTE(disable_tail_calls)
#define PHMAP_HAVE_ATTRIBUTE_NO_TAIL_CALL 1
#define PHMAP_ATTRIBUTE_NO_TAIL_CALL __attribute__((disable_tail_calls))
#elif defined(__GNUC__) && !defined(__clang__)
#define PHMAP_HAVE_ATTRIBUTE_NO_TAIL_CALL 1
#define PHMAP_ATTRIBUTE_NO_TAIL_CALL \
__attribute__((optimize("no-optimize-sibling-calls")))
#else
#define PHMAP_ATTRIBUTE_NO_TAIL_CALL
#define PHMAP_HAVE_ATTRIBUTE_NO_TAIL_CALL 0
#endif
#if (PHMAP_HAVE_ATTRIBUTE(weak) || \
(defined(__GNUC__) && !defined(__clang__))) && \
!(defined(__llvm__) && defined(_WIN32))
#undef PHMAP_ATTRIBUTE_WEAK
#define PHMAP_ATTRIBUTE_WEAK __attribute__((weak))
#define PHMAP_HAVE_ATTRIBUTE_WEAK 1
#else
#define PHMAP_ATTRIBUTE_WEAK
#define PHMAP_HAVE_ATTRIBUTE_WEAK 0
#endif
#if PHMAP_HAVE_ATTRIBUTE(nonnull) || (defined(__GNUC__) && !defined(__clang__))
#define PHMAP_ATTRIBUTE_NONNULL(arg_index) __attribute__((nonnull(arg_index)))
#else
#define PHMAP_ATTRIBUTE_NONNULL(...)
#endif
#if PHMAP_HAVE_ATTRIBUTE(noreturn) || (defined(__GNUC__) && !defined(__clang__))
#define PHMAP_ATTRIBUTE_NORETURN __attribute__((noreturn))
#elif defined(_MSC_VER)
#define PHMAP_ATTRIBUTE_NORETURN __declspec(noreturn)
#else
#define PHMAP_ATTRIBUTE_NORETURN
#endif
#if defined(__GNUC__) && defined(ADDRESS_SANITIZER)
#define PHMAP_ATTRIBUTE_NO_SANITIZE_ADDRESS __attribute__((no_sanitize_address))
#else
#define PHMAP_ATTRIBUTE_NO_SANITIZE_ADDRESS
#endif
#if defined(__GNUC__) && defined(MEMORY_SANITIZER)
#define PHMAP_ATTRIBUTE_NO_SANITIZE_MEMORY __attribute__((no_sanitize_memory))
#else
#define PHMAP_ATTRIBUTE_NO_SANITIZE_MEMORY
#endif
#if defined(__GNUC__) && defined(THREAD_SANITIZER)
#define PHMAP_ATTRIBUTE_NO_SANITIZE_THREAD __attribute__((no_sanitize_thread))
#else
#define PHMAP_ATTRIBUTE_NO_SANITIZE_THREAD
#endif
#if defined(__GNUC__) && \
(defined(UNDEFINED_BEHAVIOR_SANITIZER) || defined(ADDRESS_SANITIZER))
#define PHMAP_ATTRIBUTE_NO_SANITIZE_UNDEFINED \
__attribute__((no_sanitize("undefined")))
#else
#define PHMAP_ATTRIBUTE_NO_SANITIZE_UNDEFINED
#endif
#if defined(__GNUC__) && defined(CONTROL_FLOW_INTEGRITY)
#define PHMAP_ATTRIBUTE_NO_SANITIZE_CFI __attribute__((no_sanitize("cfi")))
#else
#define PHMAP_ATTRIBUTE_NO_SANITIZE_CFI
#endif
#if defined(__GNUC__) && defined(SAFESTACK_SANITIZER)
#define PHMAP_ATTRIBUTE_NO_SANITIZE_SAFESTACK \
__attribute__((no_sanitize("safe-stack")))
#else
#define PHMAP_ATTRIBUTE_NO_SANITIZE_SAFESTACK
#endif
#if PHMAP_HAVE_ATTRIBUTE(returns_nonnull) || \
(defined(__GNUC__) && \
(__GNUC__ > 5 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 9)) && \
!defined(__clang__))
#define PHMAP_ATTRIBUTE_RETURNS_NONNULL __attribute__((returns_nonnull))
#else
#define PHMAP_ATTRIBUTE_RETURNS_NONNULL
#endif
#ifdef PHMAP_HAVE_ATTRIBUTE_SECTION
#error PHMAP_HAVE_ATTRIBUTE_SECTION cannot be directly set
#elif (PHMAP_HAVE_ATTRIBUTE(section) || \
(defined(__GNUC__) && !defined(__clang__))) && \
!defined(__APPLE__) && PHMAP_HAVE_ATTRIBUTE_WEAK
#define PHMAP_HAVE_ATTRIBUTE_SECTION 1
#ifndef PHMAP_ATTRIBUTE_SECTION
#define PHMAP_ATTRIBUTE_SECTION(name) \
__attribute__((section(#name))) __attribute__((noinline))
#endif
#ifndef PHMAP_ATTRIBUTE_SECTION_VARIABLE
#define PHMAP_ATTRIBUTE_SECTION_VARIABLE(name) __attribute__((section(#name)))
#endif
#ifndef PHMAP_DECLARE_ATTRIBUTE_SECTION_VARS
#define PHMAP_DECLARE_ATTRIBUTE_SECTION_VARS(name) \
extern char __start_##name[] PHMAP_ATTRIBUTE_WEAK; \
extern char __stop_##name[] PHMAP_ATTRIBUTE_WEAK
#endif
#ifndef PHMAP_DEFINE_ATTRIBUTE_SECTION_VARS
#define PHMAP_INIT_ATTRIBUTE_SECTION_VARS(name)
#define PHMAP_DEFINE_ATTRIBUTE_SECTION_VARS(name)
#endif
#define PHMAP_ATTRIBUTE_SECTION_START(name) \
(reinterpret_cast<void *>(__start_##name))
#define PHMAP_ATTRIBUTE_SECTION_STOP(name) \
(reinterpret_cast<void *>(__stop_##name))
#else // !PHMAP_HAVE_ATTRIBUTE_SECTION
#define PHMAP_HAVE_ATTRIBUTE_SECTION 0
#define PHMAP_ATTRIBUTE_SECTION(name)
#define PHMAP_ATTRIBUTE_SECTION_VARIABLE(name)
#define PHMAP_INIT_ATTRIBUTE_SECTION_VARS(name)
#define PHMAP_DEFINE_ATTRIBUTE_SECTION_VARS(name)
#define PHMAP_DECLARE_ATTRIBUTE_SECTION_VARS(name)
#define PHMAP_ATTRIBUTE_SECTION_START(name) (reinterpret_cast<void *>(0))
#define PHMAP_ATTRIBUTE_SECTION_STOP(name) (reinterpret_cast<void *>(0))
#endif // PHMAP_ATTRIBUTE_SECTION
#if PHMAP_HAVE_ATTRIBUTE(force_align_arg_pointer) || \
(defined(__GNUC__) && !defined(__clang__))
#if defined(__i386__)
#define PHMAP_ATTRIBUTE_STACK_ALIGN_FOR_OLD_LIBC \
__attribute__((force_align_arg_pointer))
#define PHMAP_REQUIRE_STACK_ALIGN_TRAMPOLINE (0)
#elif defined(__x86_64__)
#define PHMAP_REQUIRE_STACK_ALIGN_TRAMPOLINE (1)
#define PHMAP_ATTRIBUTE_STACK_ALIGN_FOR_OLD_LIBC
#else // !__i386__ && !__x86_64
#define PHMAP_REQUIRE_STACK_ALIGN_TRAMPOLINE (0)
#define PHMAP_ATTRIBUTE_STACK_ALIGN_FOR_OLD_LIBC
#endif // __i386__
#else
#define PHMAP_ATTRIBUTE_STACK_ALIGN_FOR_OLD_LIBC
#define PHMAP_REQUIRE_STACK_ALIGN_TRAMPOLINE (0)
#endif
#if PHMAP_HAVE_ATTRIBUTE(nodiscard)
#define PHMAP_MUST_USE_RESULT [[nodiscard]]
#elif defined(__clang__) && PHMAP_HAVE_ATTRIBUTE(warn_unused_result)
#define PHMAP_MUST_USE_RESULT __attribute__((warn_unused_result))
#else
#define PHMAP_MUST_USE_RESULT
#endif
#if PHMAP_HAVE_ATTRIBUTE(hot) || (defined(__GNUC__) && !defined(__clang__))
#define PHMAP_ATTRIBUTE_HOT __attribute__((hot))
#else
#define PHMAP_ATTRIBUTE_HOT
#endif
#if PHMAP_HAVE_ATTRIBUTE(cold) || (defined(__GNUC__) && !defined(__clang__))
#define PHMAP_ATTRIBUTE_COLD __attribute__((cold))
#else
#define PHMAP_ATTRIBUTE_COLD
#endif
#if PHMAP_HAVE_CPP_ATTRIBUTE(clang::xray_always_instrument) && \
!defined(PHMAP_NO_XRAY_ATTRIBUTES)
#define PHMAP_XRAY_ALWAYS_INSTRUMENT [[clang::xray_always_instrument]]
#define PHMAP_XRAY_NEVER_INSTRUMENT [[clang::xray_never_instrument]]
#if PHMAP_HAVE_CPP_ATTRIBUTE(clang::xray_log_args)
#define PHMAP_XRAY_LOG_ARGS(N) \
[[clang::xray_always_instrument, clang::xray_log_args(N)]]
#else
#define PHMAP_XRAY_LOG_ARGS(N) [[clang::xray_always_instrument]]
#endif
#else
#define PHMAP_XRAY_ALWAYS_INSTRUMENT
#define PHMAP_XRAY_NEVER_INSTRUMENT
#define PHMAP_XRAY_LOG_ARGS(N)
#endif
#if PHMAP_HAVE_CPP_ATTRIBUTE(clang::reinitializes)
#define PHMAP_ATTRIBUTE_REINITIALIZES [[clang::reinitializes]]
#else
#define PHMAP_ATTRIBUTE_REINITIALIZES
#endif
#if PHMAP_HAVE_ATTRIBUTE(unused) || (defined(__GNUC__) && !defined(__clang__))
#undef PHMAP_ATTRIBUTE_UNUSED
#define PHMAP_ATTRIBUTE_UNUSED __attribute__((__unused__))
#else
#define PHMAP_ATTRIBUTE_UNUSED
#endif
#if PHMAP_HAVE_ATTRIBUTE(tls_model) || (defined(__GNUC__) && !defined(__clang__))
#define PHMAP_ATTRIBUTE_INITIAL_EXEC __attribute__((tls_model("initial-exec")))
#else
#define PHMAP_ATTRIBUTE_INITIAL_EXEC
#endif
#if PHMAP_HAVE_ATTRIBUTE(packed) || (defined(__GNUC__) && !defined(__clang__))
#define PHMAP_ATTRIBUTE_PACKED __attribute__((__packed__))
#else
#define PHMAP_ATTRIBUTE_PACKED
#endif
#if PHMAP_HAVE_ATTRIBUTE(aligned) || (defined(__GNUC__) && !defined(__clang__))
#define PHMAP_ATTRIBUTE_FUNC_ALIGN(bytes) __attribute__((aligned(bytes)))
#else
#define PHMAP_ATTRIBUTE_FUNC_ALIGN(bytes)
#endif
#if PHMAP_HAVE_CPP_ATTRIBUTE(clang::require_constant_initialization)
#define PHMAP_CONST_INIT [[clang::require_constant_initialization]]
#else
#define PHMAP_CONST_INIT
#endif // PHMAP_HAVE_CPP_ATTRIBUTE(clang::require_constant_initialization)
// ----------------------------------------------------------------------
// Figure out SSE support
// ----------------------------------------------------------------------
#ifndef PHMAP_HAVE_SSE2
#if defined(__SSE2__) || \
(defined(_MSC_VER) && \
(defined(_M_X64) || (defined(_M_IX86) && _M_IX86_FP >= 2)))
#define PHMAP_HAVE_SSE2 1
#else
#define PHMAP_HAVE_SSE2 0
#endif
#endif
#ifndef PHMAP_HAVE_SSSE3
#ifdef __SSSE3__
#define PHMAP_HAVE_SSSE3 1
#else
#define PHMAP_HAVE_SSSE3 0
#endif
#endif
#if PHMAP_HAVE_SSSE3 && !PHMAP_HAVE_SSE2
#error "Bad configuration!"
#endif
#if PHMAP_HAVE_SSE2
#include <emmintrin.h>
#endif
#if PHMAP_HAVE_SSSE3
#include <tmmintrin.h>
#endif
#endif // phmap_config_h_guard_
+40
View File
@@ -0,0 +1,40 @@
#if !defined(phmap_utils_h_guard_)
#define phmap_utils_h_guard_
// ---------------------------------------------------------------------------
// Copyright (c) 2019, Gregory Popovitch - greg7mdp@gmail.com
//
// 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.
//
// Includes work from abseil-cpp (https://github.com/abseil/abseil-cpp)
// with modifications.
//
// 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.
// ---------------------------------------------------------------------------
#endif // phmap_utils_h_guard_