summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CMake/AbseilDll.cmake2
-rw-r--r--absl/container/internal/btree.h151
-rw-r--r--absl/debugging/BUILD.bazel2
-rw-r--r--absl/debugging/CMakeLists.txt2
-rw-r--r--absl/debugging/internal/examine_stack.cc30
-rw-r--r--absl/debugging/internal/stacktrace_config.h21
-rw-r--r--absl/debugging/internal/symbolize.h6
-rw-r--r--absl/debugging/symbolize.cc2
-rw-r--r--absl/debugging/symbolize_darwin.inc101
-rw-r--r--absl/debugging/symbolize_test.cc8
-rw-r--r--absl/flags/BUILD.bazel31
-rw-r--r--absl/flags/CMakeLists.txt33
-rw-r--r--absl/flags/commandlineflag_test.cc31
-rw-r--r--absl/flags/flag_test.cc43
-rw-r--r--absl/flags/internal/registry.h13
-rw-r--r--absl/flags/internal/type_erased.cc86
-rw-r--r--absl/flags/internal/type_erased.h80
-rw-r--r--absl/flags/internal/type_erased_test.cc156
-rw-r--r--absl/flags/internal/usage_test.cc12
-rw-r--r--absl/flags/parse.cc6
-rw-r--r--absl/flags/parse_test.cc2
-rw-r--r--absl/flags/reflection.cc (renamed from absl/flags/internal/registry.cc)218
-rw-r--r--absl/flags/reflection.h47
-rw-r--r--absl/flags/reflection_test.cc60
-rw-r--r--absl/random/BUILD.bazel7
-rw-r--r--absl/random/CMakeLists.txt22
-rw-r--r--absl/random/bit_gen_ref.h105
-rw-r--r--absl/random/bit_gen_ref_test.cc25
-rw-r--r--absl/random/internal/BUILD.bazel17
-rw-r--r--absl/random/internal/distribution_caller.h51
-rw-r--r--absl/random/internal/mock_overload_set.h33
-rw-r--r--absl/random/internal/mocking_bit_gen_base.h85
-rw-r--r--absl/random/mock_distributions.h5
-rw-r--r--absl/random/mocking_bit_gen.h175
34 files changed, 783 insertions, 885 deletions
diff --git a/CMake/AbseilDll.cmake b/CMake/AbseilDll.cmake
index 8e93e794..07ae20fe 100644
--- a/CMake/AbseilDll.cmake
+++ b/CMake/AbseilDll.cmake
@@ -147,7 +147,6 @@ set(ABSL_INTERNAL_DLL_FILES
"random/internal/platform.h"
"random/internal/pool_urbg.cc"
"random/internal/pool_urbg.h"
- "random/internal/randen_round_keys.cc"
"random/internal/randen.cc"
"random/internal/randen.h"
"random/internal/randen_detect.cc"
@@ -155,6 +154,7 @@ set(ABSL_INTERNAL_DLL_FILES
"random/internal/randen_engine.h"
"random/internal/randen_hwaes.cc"
"random/internal/randen_hwaes.h"
+ "random/internal/randen_round_keys.cc"
"random/internal/randen_slow.cc"
"random/internal/randen_slow.h"
"random/internal/randen_traits.h"
diff --git a/absl/container/internal/btree.h b/absl/container/internal/btree.h
index b23138f0..f52fe235 100644
--- a/absl/container/internal/btree.h
+++ b/absl/container/internal/btree.h
@@ -817,33 +817,52 @@ class btree_node {
absl::container_internal::SanitizerPoisonObject(slot(i));
}
- // Transfers value from slot `src_i` in `src` to slot `dest_i` in `this`.
- void transfer(const size_type dest_i, const size_type src_i, btree_node *src,
- allocator_type *alloc) {
+ // Transfers value from slot `src_i` in `src_node` to slot `dest_i` in `this`.
+ void transfer(const size_type dest_i, const size_type src_i,
+ btree_node *src_node, allocator_type *alloc) {
absl::container_internal::SanitizerUnpoisonObject(slot(dest_i));
- params_type::transfer(alloc, slot(dest_i), src->slot(src_i));
- absl::container_internal::SanitizerPoisonObject(src->slot(src_i));
+ params_type::transfer(alloc, slot(dest_i), src_node->slot(src_i));
+ absl::container_internal::SanitizerPoisonObject(src_node->slot(src_i));
}
- // Move n values starting at value i in this node into the values starting at
- // value j in dest_node.
- void uninitialized_move_n(const size_type n, const size_type i,
- const size_type j, btree_node *dest_node,
- allocator_type *alloc) {
+ // Transfers `n` values starting at value `src_i` in `src_node` into the
+ // values starting at value `dest_i` in `this`.
+ void transfer_n(const size_type n, const size_type dest_i,
+ const size_type src_i, btree_node *src_node,
+ allocator_type *alloc) {
absl::container_internal::SanitizerUnpoisonMemoryRegion(
- dest_node->slot(j), n * sizeof(slot_type));
- for (slot_type *src = slot(i), *end = src + n, *dest = dest_node->slot(j);
+ slot(dest_i), n * sizeof(slot_type));
+ for (slot_type *src = src_node->slot(src_i), *end = src + n,
+ *dest = slot(dest_i);
src != end; ++src, ++dest) {
- params_type::construct(alloc, dest, src);
+ params_type::transfer(alloc, dest, src);
}
+ // We take care to avoid poisoning transferred-to nodes in case of overlap.
+ const size_type overlap =
+ this == src_node ? (std::max)(src_i, dest_i + n) - src_i : 0;
+ assert(n >= overlap);
+ absl::container_internal::SanitizerPoisonMemoryRegion(
+ src_node->slot(src_i + overlap), (n - overlap) * sizeof(slot_type));
}
- // Destroys a range of n values, starting at index i.
- void value_destroy_n(const size_type i, const size_type n,
- allocator_type *alloc) {
- for (int j = 0; j < n; ++j) {
- value_destroy(i + j, alloc);
+ // Same as above, except that we start at the end and work our way to the
+ // beginning.
+ void transfer_n_backward(const size_type n, const size_type dest_i,
+ const size_type src_i, btree_node *src_node,
+ allocator_type *alloc) {
+ absl::container_internal::SanitizerUnpoisonMemoryRegion(
+ slot(dest_i), n * sizeof(slot_type));
+ for (slot_type *src = src_node->slot(src_i + n - 1), *end = src - n,
+ *dest = slot(dest_i + n - 1);
+ src != end; --src, --dest) {
+ params_type::transfer(alloc, dest, src);
}
+ // We take care to avoid poisoning transferred-to nodes in case of overlap.
+ assert(this != src_node || dest_i >= src_i);
+ const size_type num_to_poison =
+ this == src_node ? (std::min)(n, dest_i - src_i) : n;
+ absl::container_internal::SanitizerPoisonMemoryRegion(
+ src_node->slot(src_i), num_to_poison * sizeof(slot_type));
}
template <typename P>
@@ -1531,10 +1550,8 @@ inline void btree_node<P>::emplace_value(const size_type i,
// Shift old values to create space for new value and then construct it in
// place.
if (i < finish()) {
- value_init(finish(), alloc, slot(finish() - 1));
- for (size_type j = finish() - 1; j > i; --j)
- params_type::move(alloc, slot(j - 1), slot(j));
- value_destroy(i, alloc);
+ transfer_n_backward(finish() - i, /*dest_i=*/i + 1, /*src_i=*/i, this,
+ alloc);
}
value_init(i, alloc, std::forward<Args>(args)...);
set_finish(finish() + 1);
@@ -1564,7 +1581,9 @@ template <typename P>
inline void btree_node<P>::remove_values_ignore_children(
const int i, const int to_erase, allocator_type *alloc) {
params_type::move(alloc, slot(i + to_erase), finish_slot(), slot(i));
- value_destroy_n(finish() - to_erase, to_erase, alloc);
+ for (int j = finish() - to_erase; j < finish(); ++j) {
+ value_destroy(j, alloc);
+ }
set_finish(finish() - to_erase);
}
@@ -1579,22 +1598,17 @@ void btree_node<P>::rebalance_right_to_left(const int to_move,
assert(to_move <= right->count());
// 1) Move the delimiting value in the parent to the left node.
- value_init(finish(), alloc, parent()->slot(position()));
+ transfer(finish(), position(), parent(), alloc);
// 2) Move the (to_move - 1) values from the right node to the left node.
- right->uninitialized_move_n(to_move - 1, right->start(), finish() + 1, this,
- alloc);
+ transfer_n(to_move - 1, finish() + 1, right->start(), right, alloc);
// 3) Move the new delimiting value to the parent from the right node.
- params_type::move(alloc, right->slot(to_move - 1),
- parent()->slot(position()));
-
- // 4) Shift the values in the right node to their correct position.
- params_type::move(alloc, right->slot(to_move), right->finish_slot(),
- right->start_slot());
+ parent()->transfer(position(), right->start() + to_move - 1, right, alloc);
- // 5) Destroy the now-empty to_move entries in the right node.
- right->value_destroy_n(right->finish() - to_move, to_move, alloc);
+ // 4) Shift the values in the right node to their correct positions.
+ right->transfer_n(right->count() - to_move, right->start(),
+ right->start() + to_move, right, alloc);
if (!leaf()) {
// Move the child pointers from the right to the left node.
@@ -1629,54 +1643,19 @@ void btree_node<P>::rebalance_left_to_right(const int to_move,
// Lastly, a new delimiting value is moved from the left node into the
// parent, and the remaining empty left node entries are destroyed.
- if (right->count() >= to_move) {
- // The original location of the right->count() values are sufficient to hold
- // the new to_move entries from the parent and left node.
-
- // 1) Shift existing values in the right node to their correct positions.
- right->uninitialized_move_n(to_move, right->finish() - to_move,
- right->finish(), right, alloc);
- for (slot_type *src = right->slot(right->finish() - to_move - 1),
- *dest = right->slot(right->finish() - 1),
- *end = right->start_slot();
- src >= end; --src, --dest) {
- params_type::move(alloc, src, dest);
- }
-
- // 2) Move the delimiting value in the parent to the right node.
- params_type::move(alloc, parent()->slot(position()),
- right->slot(to_move - 1));
+ // 1) Shift existing values in the right node to their correct positions.
+ right->transfer_n_backward(right->count(), right->start() + to_move,
+ right->start(), right, alloc);
- // 3) Move the (to_move - 1) values from the left node to the right node.
- params_type::move(alloc, slot(finish() - (to_move - 1)), finish_slot(),
- right->start_slot());
- } else {
- // The right node does not have enough initialized space to hold the new
- // to_move entries, so part of them will move to uninitialized space.
-
- // 1) Shift existing values in the right node to their correct positions.
- right->uninitialized_move_n(right->count(), right->start(),
- right->start() + to_move, right, alloc);
+ // 2) Move the delimiting value in the parent to the right node.
+ right->transfer(right->start() + to_move - 1, position(), parent(), alloc);
- // 2) Move the delimiting value in the parent to the right node.
- right->value_init(to_move - 1, alloc, parent()->slot(position()));
-
- // 3) Move the (to_move - 1) values from the left node to the right node.
- const size_type uninitialized_remaining = to_move - right->count() - 1;
- uninitialized_move_n(uninitialized_remaining,
- finish() - uninitialized_remaining, right->finish(),
- right, alloc);
- params_type::move(alloc, slot(finish() - (to_move - 1)),
- slot(finish() - uninitialized_remaining),
- right->start_slot());
- }
+ // 3) Move the (to_move - 1) values from the left node to the right node.
+ right->transfer_n(to_move - 1, right->start(), finish() - (to_move - 1), this,
+ alloc);
// 4) Move the new delimiting value to the parent from the left node.
- params_type::move(alloc, slot(finish() - to_move),
- parent()->slot(position()));
-
- // 5) Destroy the now-empty to_move entries in the left node.
- value_destroy_n(finish() - to_move, to_move, alloc);
+ parent()->transfer(position(), finish() - to_move, this, alloc);
if (!leaf()) {
// Move the child pointers from the left to the right node.
@@ -1716,10 +1695,7 @@ void btree_node<P>::split(const int insert_position, btree_node *dest,
assert(count() >= 1);
// Move values from the left sibling to the right sibling.
- uninitialized_move_n(dest->count(), finish(), dest->start(), dest, alloc);
-
- // Destroy the now-empty entries in the left node.
- value_destroy_n(finish(), dest->count(), alloc);
+ dest->transfer_n(dest->count(), dest->start(), finish(), this, alloc);
// The split key is the largest value in the left sibling.
--mutable_finish();
@@ -1746,11 +1722,7 @@ void btree_node<P>::merge(btree_node *src, allocator_type *alloc) {
value_init(finish(), alloc, parent()->slot(position()));
// Move the values from the right to the left node.
- src->uninitialized_move_n(src->count(), src->start(), finish() + 1, this,
- alloc);
-
- // Destroy the now-empty entries in the right node.
- src->value_destroy_n(src->start(), src->count(), alloc);
+ transfer_n(src->count(), finish() + 1, src->start(), src, alloc);
if (!leaf()) {
// Move the child pointers from the right to the left node.
@@ -2474,9 +2446,8 @@ inline auto btree<P>::internal_emplace(iterator iter, Args &&... args)
// Transfer the values from the old root to the new root.
node_type *old_root = root();
node_type *new_root = iter.node;
- for (int i = old_root->start(), f = old_root->finish(); i < f; ++i) {
- new_root->transfer(i, i, old_root, alloc);
- }
+ new_root->transfer_n(old_root->count(), new_root->start(),
+ old_root->start(), old_root, alloc);
new_root->set_finish(old_root->finish());
old_root->set_finish(old_root->start());
delete_leaf_node(old_root);
diff --git a/absl/debugging/BUILD.bazel b/absl/debugging/BUILD.bazel
index 8f521bec..ff627924 100644
--- a/absl/debugging/BUILD.bazel
+++ b/absl/debugging/BUILD.bazel
@@ -55,6 +55,7 @@ cc_library(
name = "symbolize",
srcs = [
"symbolize.cc",
+ "symbolize_darwin.inc",
"symbolize_elf.inc",
"symbolize_unimplemented.inc",
"symbolize_win32.inc",
@@ -77,6 +78,7 @@ cc_library(
"//absl/base:dynamic_annotations",
"//absl/base:malloc_internal",
"//absl/base:raw_logging_internal",
+ "//absl/strings",
],
)
diff --git a/absl/debugging/CMakeLists.txt b/absl/debugging/CMakeLists.txt
index 77336159..995e8887 100644
--- a/absl/debugging/CMakeLists.txt
+++ b/absl/debugging/CMakeLists.txt
@@ -46,6 +46,7 @@ absl_cc_library(
"internal/symbolize.h"
SRCS
"symbolize.cc"
+ "symbolize_darwin.inc"
"symbolize_elf.inc"
"symbolize_unimplemented.inc"
"symbolize_win32.inc"
@@ -63,6 +64,7 @@ absl_cc_library(
absl::dynamic_annotations
absl::malloc_internal
absl::raw_logging_internal
+ absl::strings
PUBLIC
)
diff --git a/absl/debugging/internal/examine_stack.cc b/absl/debugging/internal/examine_stack.cc
index a3dd893a..6e5ff1fb 100644
--- a/absl/debugging/internal/examine_stack.cc
+++ b/absl/debugging/internal/examine_stack.cc
@@ -20,6 +20,10 @@
#include <unistd.h>
#endif
+#ifdef __APPLE__
+#include <sys/ucontext.h>
+#endif
+
#include <csignal>
#include <cstdio>
@@ -66,6 +70,32 @@ void* GetProgramCounter(void* vuc) {
#error "Undefined Architecture."
#endif
}
+#elif defined(__APPLE__)
+ if (vuc != nullptr) {
+ ucontext_t* signal_ucontext = reinterpret_cast<ucontext_t*>(vuc);
+#if defined(__aarch64__)
+ return reinterpret_cast<void*>(
+ __darwin_arm_thread_state64_get_pc(signal_ucontext->uc_mcontext->__ss));
+#elif defined(__arm__)
+#if __DARWIN_UNIX03
+ return reinterpret_cast<void*>(signal_ucontext->uc_mcontext->__ss.__pc);
+#else
+ return reinterpret_cast<void*>(signal_ucontext->uc_mcontext->ss.pc);
+#endif
+#elif defined(__i386__)
+#if __DARWIN_UNIX03
+ return reinterpret_cast<void*>(signal_ucontext->uc_mcontext->__ss.__eip);
+#else
+ return reinterpret_cast<void*>(signal_ucontext->uc_mcontext->ss.eip);
+#endif
+#elif defined(__x86_64__)
+#if __DARWIN_UNIX03
+ return reinterpret_cast<void*>(signal_ucontext->uc_mcontext->__ss.__rip);
+#else
+ return reinterpret_cast<void*>(signal_ucontext->uc_mcontext->ss.rip);
+#endif
+#endif
+ }
#elif defined(__akaros__)
auto* ctx = reinterpret_cast<struct user_context*>(vuc);
return reinterpret_cast<void*>(get_user_ctx_pc(ctx));
diff --git a/absl/debugging/internal/stacktrace_config.h b/absl/debugging/internal/stacktrace_config.h
index d4e8480a..8caa97c0 100644
--- a/absl/debugging/internal/stacktrace_config.h
+++ b/absl/debugging/internal/stacktrace_config.h
@@ -28,6 +28,27 @@
#define ABSL_STACKTRACE_INL_HEADER \
"absl/debugging/internal/stacktrace_win32-inl.inc"
+#elif defined(__APPLE__)
+// Thread local support required for UnwindImpl.
+// Notes:
+// * Xcode's clang did not support `thread_local` until version 8, and
+// even then not for all iOS < 9.0.
+// * Xcode 9.3 started disallowing `thread_local` for 32-bit iOS simulator
+// targeting iOS 9.x.
+// * Xcode 10 moves the deployment target check for iOS < 9.0 to link time
+// making __has_feature unreliable there.
+//
+// Otherwise, `__has_feature` is only supported by Clang so it has be inside
+// `defined(__APPLE__)` check.
+#if __has_feature(cxx_thread_local) && \
+ !(TARGET_OS_IPHONE && __IPHONE_OS_VERSION_MIN_REQUIRED < __IPHONE_9_0)
+#define ABSL_STACKTRACE_INL_HEADER \
+ "absl/debugging/internal/stacktrace_generic-inl.inc"
+#else
+#define ABSL_STACKTRACE_INL_HEADER \
+ "absl/debugging/internal/stacktrace_unimplemented-inl.inc"
+#endif
+
#elif defined(__linux__) && !defined(__ANDROID__)
#if !defined(NO_FRAME_POINTER)
diff --git a/absl/debugging/internal/symbolize.h b/absl/debugging/internal/symbolize.h
index 5d0858b5..8789e69a 100644
--- a/absl/debugging/internal/symbolize.h
+++ b/absl/debugging/internal/symbolize.h
@@ -59,6 +59,12 @@ ABSL_NAMESPACE_END
#endif // ABSL_INTERNAL_HAVE_ELF_SYMBOLIZE
+#ifdef ABSL_INTERNAL_HAVE_DARWIN_SYMBOLIZE
+#error ABSL_INTERNAL_HAVE_DARWIN_SYMBOLIZE cannot be directly set
+#elif defined(__APPLE__)
+#define ABSL_INTERNAL_HAVE_DARWIN_SYMBOLIZE 1
+#endif
+
namespace absl {
ABSL_NAMESPACE_BEGIN
namespace debugging_internal {
diff --git a/absl/debugging/symbolize.cc b/absl/debugging/symbolize.cc
index 54ed9700..eec7a6e8 100644
--- a/absl/debugging/symbolize.cc
+++ b/absl/debugging/symbolize.cc
@@ -20,6 +20,8 @@
// The Windows Symbolizer only works if PDB files containing the debug info
// are available to the program at runtime.
#include "absl/debugging/symbolize_win32.inc"
+#elif defined(__APPLE__)
+#include "absl/debugging/symbolize_darwin.inc"
#else
#include "absl/debugging/symbolize_unimplemented.inc"
#endif
diff --git a/absl/debugging/symbolize_darwin.inc b/absl/debugging/symbolize_darwin.inc
new file mode 100644
index 00000000..cdadd40e
--- /dev/null
+++ b/absl/debugging/symbolize_darwin.inc
@@ -0,0 +1,101 @@
+// Copyright 2020 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 <cxxabi.h>
+#include <execinfo.h>
+
+#include <algorithm>
+#include <cstring>
+
+#include "absl/base/internal/raw_logging.h"
+#include "absl/debugging/internal/demangle.h"
+#include "absl/strings/numbers.h"
+#include "absl/strings/str_cat.h"
+#include "absl/strings/string_view.h"
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+
+void InitializeSymbolizer(const char*) {}
+
+namespace debugging_internal {
+namespace {
+
+static std::string GetSymbolString(absl::string_view backtrace_line) {
+ // Example Backtrace lines:
+ // 0 libimaging_shared.dylib 0x018c152a
+ // _ZNSt11_Deque_baseIN3nik7mediadb4PageESaIS2_EE17_M_initialize_mapEm + 3478
+ //
+ // or
+ // 0 libimaging_shared.dylib 0x0000000001895c39
+ // _ZN3nik4util19register_shared_ptrINS_3gpu7TextureEEEvPKvS5_ + 39
+ //
+ // or
+ // 0 mysterious_app 0x0124000120120009 main + 17
+ auto address_pos = backtrace_line.find(" 0x");
+ if (address_pos == absl::string_view::npos) return std::string();
+ absl::string_view symbol_view = backtrace_line.substr(address_pos + 1);
+
+ auto space_pos = symbol_view.find(" ");
+ if (space_pos == absl::string_view::npos) return std::string();
+ symbol_view = symbol_view.substr(space_pos + 1); // to mangled symbol
+
+ auto plus_pos = symbol_view.find(" + ");
+ if (plus_pos == absl::string_view::npos) return std::string();
+ symbol_view = symbol_view.substr(0, plus_pos); // strip remainng
+
+ return std::string(symbol_view);
+}
+
+} // namespace
+} // namespace debugging_internal
+
+bool Symbolize(const void* pc, char* out, int out_size) {
+ if (out_size <= 0 || pc == nullptr) {
+ out = nullptr;
+ return false;
+ }
+
+ // This allocates a char* array.
+ char** frame_strings = backtrace_symbols(const_cast<void**>(&pc), 1);
+
+ if (frame_strings == nullptr) return false;
+
+ std::string symbol = debugging_internal::GetSymbolString(frame_strings[0]);
+ free(frame_strings);
+
+ char tmp_buf[1024];
+ if (debugging_internal::Demangle(symbol.c_str(), tmp_buf, sizeof(tmp_buf))) {
+ int len = strlen(tmp_buf);
+ if (len + 1 <= out_size) { // +1 for '\0'
+ assert(len < sizeof(tmp_buf));
+ memmove(out, tmp_buf, len + 1);
+ }
+ } else {
+ strncpy(out, symbol.c_str(), out_size);
+ }
+
+ if (out[out_size - 1] != '\0') {
+ // strncpy() does not '\0' terminate when it truncates.
+ static constexpr char kEllipsis[] = "...";
+ int ellipsis_size = std::min<int>(sizeof(kEllipsis) - 1, out_size - 1);
+ memcpy(out + out_size - ellipsis_size - 1, kEllipsis, ellipsis_size);
+ out[out_size - 1] = '\0';
+ }
+
+ return true;
+}
+
+ABSL_NAMESPACE_END
+} // namespace absl
diff --git a/absl/debugging/symbolize_test.cc b/absl/debugging/symbolize_test.cc
index a1d03aab..e476d82a 100644
--- a/absl/debugging/symbolize_test.cc
+++ b/absl/debugging/symbolize_test.cc
@@ -144,7 +144,8 @@ static const char *TrySymbolize(void *pc) {
return TrySymbolizeWithLimit(pc, sizeof(try_symbolize_buffer));
}
-#ifdef ABSL_INTERNAL_HAVE_ELF_SYMBOLIZE
+#if defined(ABSL_INTERNAL_HAVE_ELF_SYMBOLIZE) || \
+ defined(ABSL_INTERNAL_HAVE_DARWIN_SYMBOLIZE)
TEST(Symbolize, Cached) {
// Compilers should give us pointers to them.
@@ -258,6 +259,7 @@ TEST(Symbolize, SymbolizeWithDemanglingStackConsumption) {
#endif // ABSL_INTERNAL_HAVE_DEBUGGING_STACK_CONSUMPTION
+#ifndef ABSL_INTERNAL_HAVE_DARWIN_SYMBOLIZE
// Use a 64K page size for PPC.
const size_t kPageSize = 64 << 10;
// We place a read-only symbols into the .text section and verify that we can
@@ -413,6 +415,7 @@ TEST(Symbolize, ForEachSection) {
close(fd);
}
+#endif // !ABSL_INTERNAL_HAVE_DARWIN_SYMBOLIZE
// x86 specific tests. Uses some inline assembler.
extern "C" {
@@ -541,7 +544,8 @@ int main(int argc, char **argv) {
absl::InitializeSymbolizer(argv[0]);
testing::InitGoogleTest(&argc, argv);
-#ifdef ABSL_INTERNAL_HAVE_ELF_SYMBOLIZE
+#if defined(ABSL_INTERNAL_HAVE_ELF_SYMBOLIZE) || \
+ defined(ABSL_INTERNAL_HAVE_DARWIN_SYMBOLIZE)
TestWithPCInsideInlineFunction();
TestWithPCInsideNonInlineFunction();
TestWithReturnAddress();
diff --git a/absl/flags/BUILD.bazel b/absl/flags/BUILD.bazel
index 6ffd07ce..37c9a105 100644
--- a/absl/flags/BUILD.bazel
+++ b/absl/flags/BUILD.bazel
@@ -159,14 +159,13 @@ cc_library(
)
cc_library(
- name = "registry",
+ name = "reflection",
srcs = [
- "internal/registry.cc",
- "internal/type_erased.cc",
+ "reflection.cc",
],
hdrs = [
"internal/registry.h",
- "internal/type_erased.h",
+ "reflection.h",
],
copts = ABSL_DEFAULT_COPTS,
linkopts = ABSL_DEFAULT_LINKOPTS,
@@ -180,7 +179,6 @@ cc_library(
":private_handle_accessor",
"//absl/base:config",
"//absl/base:core_headers",
- "//absl/base:raw_logging_internal",
"//absl/strings",
"//absl/synchronization",
],
@@ -202,7 +200,7 @@ cc_library(
":commandlineflag_internal",
":config",
":marshalling",
- ":registry",
+ ":reflection",
"//absl/base",
"//absl/base:config",
"//absl/base:core_headers",
@@ -228,7 +226,7 @@ cc_library(
deps = [
":config",
":flag_internal",
- ":registry",
+ ":reflection",
"//absl/base",
"//absl/base:config",
"//absl/base:core_headers",
@@ -257,7 +255,7 @@ cc_library(
":path_util",
":private_handle_accessor",
":program_name",
- ":registry",
+ ":reflection",
"//absl/base:config",
"//absl/base:core_headers",
"//absl/strings",
@@ -300,7 +298,7 @@ cc_library(
":flag_internal",
":private_handle_accessor",
":program_name",
- ":registry",
+ ":reflection",
":usage",
":usage_internal",
"//absl/base:config",
@@ -327,7 +325,7 @@ cc_test(
":config",
":flag",
":private_handle_accessor",
- ":registry",
+ ":reflection",
"//absl/memory",
"//absl/strings",
"@com_google_googletest//:gtest_main",
@@ -362,7 +360,7 @@ cc_test(
":flag",
":flag_internal",
":marshalling",
- ":registry",
+ ":reflection",
"//absl/base:core_headers",
"//absl/base:malloc_internal",
"//absl/strings",
@@ -415,7 +413,7 @@ cc_test(
deps = [
":flag",
":parse",
- ":registry",
+ ":reflection",
"//absl/base:raw_logging_internal",
"//absl/base:scoped_set_env",
"//absl/strings",
@@ -454,17 +452,18 @@ cc_test(
)
cc_test(
- name = "type_erased_test",
+ name = "reflection_test",
size = "small",
srcs = [
- "internal/type_erased_test.cc",
+ "reflection_test.cc",
],
copts = ABSL_TEST_COPTS,
linkopts = ABSL_DEFAULT_LINKOPTS,
deps = [
":commandlineflag_internal",
":flag",
- ":registry",
+ ":marshalling",
+ ":reflection",
"//absl/memory",
"@com_google_googletest//:gtest_main",
],
@@ -501,7 +500,7 @@ cc_test(
":parse",
":path_util",
":program_name",
- ":registry",
+ ":reflection",
":usage",
":usage_internal",
"//absl/strings",
diff --git a/absl/flags/CMakeLists.txt b/absl/flags/CMakeLists.txt
index 2dc7cf45..ef75db8e 100644
--- a/absl/flags/CMakeLists.txt
+++ b/absl/flags/CMakeLists.txt
@@ -144,16 +144,14 @@ absl_cc_library(
absl::strings
)
-# Internal-only target, do not depend on directly.
absl_cc_library(
NAME
- flags_registry
+ flags_reflection
SRCS
- "internal/registry.cc"
- "internal/type_erased.cc"
+ "reflection.cc"
HDRS
+ "reflection.h"
"internal/registry.h"
- "internal/type_erased.h"
COPTS
${ABSL_DEFAULT_COPTS}
LINKOPTS
@@ -161,10 +159,8 @@ absl_cc_library(
DEPS
absl::config
absl::flags_commandlineflag
- absl::flags_config
absl::flags_private_handle_accessor
- absl::core_headers
- absl::raw_logging_internal
+ absl::flags_config
absl::strings
absl::synchronization
)
@@ -187,7 +183,6 @@ absl_cc_library(
absl::flags_commandlineflag_internal
absl::flags_config
absl::flags_marshalling
- absl::flags_registry
absl::synchronization
absl::meta
absl::utility
@@ -211,7 +206,7 @@ absl_cc_library(
absl::flags_commandlineflag
absl::flags_config
absl::flags_internal
- absl::flags_registry
+ absl::flags_reflection
absl::base
absl::core_headers
absl::strings
@@ -238,7 +233,7 @@ absl_cc_library(
absl::flags_path_util
absl::flags_private_handle_accessor
absl::flags_program_name
- absl::flags_registry
+ absl::flags_reflection
absl::strings
absl::synchronization
)
@@ -284,7 +279,7 @@ absl_cc_library(
absl::flags_internal
absl::flags_private_handle_accessor
absl::flags_program_name
- absl::flags_registry
+ absl::flags_reflection
absl::flags_usage
absl::strings
absl::synchronization
@@ -306,7 +301,7 @@ absl_cc_test(
absl::flags_commandlineflag_internal
absl::flags_config
absl::flags_private_handle_accessor
- absl::flags_registry
+ absl::flags_reflection
absl::memory
absl::strings
gtest_main
@@ -338,7 +333,7 @@ absl_cc_test(
absl::flags_config
absl::flags_internal
absl::flags_marshalling
- absl::flags_registry
+ absl::flags_reflection
absl::strings
absl::time
gtest_main
@@ -366,7 +361,7 @@ absl_cc_test(
DEPS
absl::flags
absl::flags_parse
- absl::flags_registry
+ absl::flags_reflection
absl::raw_logging_internal
absl::scoped_set_env
absl::span
@@ -401,15 +396,15 @@ absl_cc_test(
absl_cc_test(
NAME
- flags_type_erased_test
+ flags_reflection_test
SRCS
- "internal/type_erased_test.cc"
+ "reflection_test.cc"
COPTS
${ABSL_TEST_COPTS}
DEPS
absl::flags_commandlineflag_internal
absl::flags
- absl::flags_registry
+ absl::flags_reflection
absl::memory
absl::strings
gtest_main
@@ -443,7 +438,7 @@ absl_cc_test(
absl::flags_path_util
absl::flags_program_name
absl::flags_parse
- absl::flags_registry
+ absl::flags_reflection
absl::flags_usage
absl::strings
gtest
diff --git a/absl/flags/commandlineflag_test.cc b/absl/flags/commandlineflag_test.cc
index 570bbe2f..cc8eae91 100644
--- a/absl/flags/commandlineflag_test.cc
+++ b/absl/flags/commandlineflag_test.cc
@@ -22,7 +22,7 @@
#include "absl/flags/flag.h"
#include "absl/flags/internal/commandlineflag.h"
#include "absl/flags/internal/private_handle_accessor.h"
-#include "absl/flags/internal/registry.h"
+#include "absl/flags/reflection.h"
#include "absl/flags/usage_config.h"
#include "absl/memory/memory.h"
#include "absl/strings/match.h"
@@ -64,7 +64,7 @@ class CommandLineFlagTest : public testing::Test {
};
TEST_F(CommandLineFlagTest, TestAttributesAccessMethods) {
- auto* flag_01 = flags::FindCommandLineFlag("int_flag");
+ auto* flag_01 = absl::FindCommandLineFlag("int_flag");
ASSERT_TRUE(flag_01);
EXPECT_EQ(flag_01->Name(), "int_flag");
@@ -77,7 +77,7 @@ TEST_F(CommandLineFlagTest, TestAttributesAccessMethods) {
"absl/flags/commandlineflag_test.cc"))
<< flag_01->Filename();
- auto* flag_02 = flags::FindCommandLineFlag("string_flag");
+ auto* flag_02 = absl::FindCommandLineFlag("string_flag");
ASSERT_TRUE(flag_02);
EXPECT_EQ(flag_02->Name(), "string_flag");
@@ -89,31 +89,20 @@ TEST_F(CommandLineFlagTest, TestAttributesAccessMethods) {
EXPECT_TRUE(absl::EndsWith(flag_02->Filename(),
"absl/flags/commandlineflag_test.cc"))
<< flag_02->Filename();
-
- auto* flag_03 = flags::FindRetiredFlag("bool_retired_flag");
-
- ASSERT_TRUE(flag_03);
- EXPECT_EQ(flag_03->Name(), "bool_retired_flag");
- EXPECT_EQ(flag_03->Help(), "");
- EXPECT_TRUE(flag_03->IsRetired());
- EXPECT_TRUE(flag_03->IsOfType<bool>());
- EXPECT_TRUE(!flag_03->IsOfType<int>());
- EXPECT_TRUE(!flag_03->IsOfType<std::string>());
- EXPECT_EQ(flag_03->Filename(), "RETIRED");
}
// --------------------------------------------------------------------
TEST_F(CommandLineFlagTest, TestValueAccessMethods) {
absl::SetFlag(&FLAGS_int_flag, 301);
- auto* flag_01 = flags::FindCommandLineFlag("int_flag");
+ auto* flag_01 = absl::FindCommandLineFlag("int_flag");
ASSERT_TRUE(flag_01);
EXPECT_EQ(flag_01->CurrentValue(), "301");
EXPECT_EQ(flag_01->DefaultValue(), "201");
absl::SetFlag(&FLAGS_string_flag, "new_str_value");
- auto* flag_02 = flags::FindCommandLineFlag("string_flag");
+ auto* flag_02 = absl::FindCommandLineFlag("string_flag");
ASSERT_TRUE(flag_02);
EXPECT_EQ(flag_02->CurrentValue(), "new_str_value");
@@ -125,7 +114,7 @@ TEST_F(CommandLineFlagTest, TestValueAccessMethods) {
TEST_F(CommandLineFlagTest, TestParseFromCurrentValue) {
std::string err;
- auto* flag_01 = flags::FindCommandLineFlag("int_flag");
+ auto* flag_01 = absl::FindCommandLineFlag("int_flag");
EXPECT_FALSE(
flags::PrivateHandleAccessor::IsSpecifiedOnCommandLine(*flag_01));
@@ -173,7 +162,7 @@ TEST_F(CommandLineFlagTest, TestParseFromCurrentValue) {
*flag_01, "", flags::SET_FLAGS_VALUE, flags::kProgrammaticChange, err));
EXPECT_EQ(err, "Illegal value '' specified for flag 'int_flag'");
- auto* flag_02 = flags::FindCommandLineFlag("string_flag");
+ auto* flag_02 = absl::FindCommandLineFlag("string_flag");
EXPECT_TRUE(flags::PrivateHandleAccessor::ParseFrom(
*flag_02, "xyz", flags::SET_FLAGS_VALUE, flags::kProgrammaticChange,
err));
@@ -189,14 +178,14 @@ TEST_F(CommandLineFlagTest, TestParseFromCurrentValue) {
TEST_F(CommandLineFlagTest, TestParseFromDefaultValue) {
std::string err;
- auto* flag_01 = flags::FindCommandLineFlag("int_flag");
+ auto* flag_01 = absl::FindCommandLineFlag("int_flag");
EXPECT_TRUE(flags::PrivateHandleAccessor::ParseFrom(
*flag_01, "111", flags::SET_FLAGS_DEFAULT, flags::kProgrammaticChange,
err));
EXPECT_EQ(flag_01->DefaultValue(), "111");
- auto* flag_02 = flags::FindCommandLineFlag("string_flag");
+ auto* flag_02 = absl::FindCommandLineFlag("string_flag");
EXPECT_TRUE(flags::PrivateHandleAccessor::ParseFrom(
*flag_02, "abc", flags::SET_FLAGS_DEFAULT, flags::kProgrammaticChange,
@@ -209,7 +198,7 @@ TEST_F(CommandLineFlagTest, TestParseFromDefaultValue) {
TEST_F(CommandLineFlagTest, TestParseFromIfDefault) {
std::string err;
- auto* flag_01 = flags::FindCommandLineFlag("int_flag");
+ auto* flag_01 = absl::FindCommandLineFlag("int_flag");
EXPECT_TRUE(flags::PrivateHandleAccessor::ParseFrom(
*flag_01, "22", flags::SET_FLAG_IF_DEFAULT, flags::kProgrammaticChange,
diff --git a/absl/flags/flag_test.cc b/absl/flags/flag_test.cc
index 71661d39..0c88e24a 100644
--- a/absl/flags/flag_test.cc
+++ b/absl/flags/flag_test.cc
@@ -29,8 +29,8 @@
#include "absl/flags/config.h"
#include "absl/flags/declare.h"
#include "absl/flags/internal/flag.h"
-#include "absl/flags/internal/registry.h"
#include "absl/flags/marshalling.h"
+#include "absl/flags/reflection.h"
#include "absl/flags/usage_config.h"
#include "absl/strings/match.h"
#include "absl/strings/numbers.h"
@@ -555,29 +555,29 @@ TEST_F(FlagTest, TestGetSet) {
// --------------------------------------------------------------------
TEST_F(FlagTest, TestGetViaReflection) {
- auto* handle = flags::FindCommandLineFlag("test_flag_01");
+ auto* handle = absl::FindCommandLineFlag("test_flag_01");
EXPECT_EQ(*handle->TryGet<bool>(), true);
- handle = flags::FindCommandLineFlag("test_flag_02");
+ handle = absl::FindCommandLineFlag("test_flag_02");
EXPECT_EQ(*handle->TryGet<int>(), 1234);
- handle = flags::FindCommandLineFlag("test_flag_03");
+ handle = absl::FindCommandLineFlag("test_flag_03");
EXPECT_EQ(*handle->TryGet<int16_t>(), -34);
- handle = flags::FindCommandLineFlag("test_flag_04");
+ handle = absl::FindCommandLineFlag("test_flag_04");
EXPECT_EQ(*handle->TryGet<uint16_t>(), 189);
- handle = flags::FindCommandLineFlag("test_flag_05");
+ handle = absl::FindCommandLineFlag("test_flag_05");
EXPECT_EQ(*handle->TryGet<int32_t>(), 10765);
- handle = flags::FindCommandLineFlag("test_flag_06");
+ handle = absl::FindCommandLineFlag("test_flag_06");
EXPECT_EQ(*handle->TryGet<uint32_t>(), 40000);
- handle = flags::FindCommandLineFlag("test_flag_07");
+ handle = absl::FindCommandLineFlag("test_flag_07");
EXPECT_EQ(*handle->TryGet<int64_t>(), -1234567);
- handle = flags::FindCommandLineFlag("test_flag_08");
+ handle = absl::FindCommandLineFlag("test_flag_08");
EXPECT_EQ(*handle->TryGet<uint64_t>(), 9876543);
- handle = flags::FindCommandLineFlag("test_flag_09");
+ handle = absl::FindCommandLineFlag("test_flag_09");
EXPECT_NEAR(*handle->TryGet<double>(), -9.876e-50, 1e-55);
- handle = flags::FindCommandLineFlag("test_flag_10");
+ handle = absl::FindCommandLineFlag("test_flag_10");
EXPECT_NEAR(*handle->TryGet<float>(), 1.234e12f, 1e5f);
- handle = flags::FindCommandLineFlag("test_flag_11");
+ handle = absl::FindCommandLineFlag("test_flag_11");
EXPECT_EQ(*handle->TryGet<std::string>(), "");
- handle = flags::FindCommandLineFlag("test_flag_12");
+ handle = absl::FindCommandLineFlag("test_flag_12");
EXPECT_EQ(*handle->TryGet<absl::Duration>(), absl::Minutes(10));
}
@@ -815,14 +815,15 @@ ABSL_RETIRED_FLAG(std::string, old_str_flag, "", absl::StrCat("old ", "descr"));
namespace {
TEST_F(FlagTest, TestRetiredFlagRegistration) {
- bool is_bool = false;
- EXPECT_TRUE(flags::IsRetiredFlag("old_bool_flag", &is_bool));
- EXPECT_TRUE(is_bool);
- EXPECT_TRUE(flags::IsRetiredFlag("old_int_flag", &is_bool));
- EXPECT_FALSE(is_bool);
- EXPECT_TRUE(flags::IsRetiredFlag("old_str_flag", &is_bool));
- EXPECT_FALSE(is_bool);
- EXPECT_FALSE(flags::IsRetiredFlag("some_other_flag", &is_bool));
+ auto* handle = absl::FindCommandLineFlag("old_bool_flag");
+ EXPECT_TRUE(handle->IsOfType<bool>());
+ EXPECT_TRUE(handle->IsRetired());
+ handle = absl::FindCommandLineFlag("old_int_flag");
+ EXPECT_TRUE(handle->IsOfType<int>());
+ EXPECT_TRUE(handle->IsRetired());
+ handle = absl::FindCommandLineFlag("old_str_flag");
+ EXPECT_TRUE(handle->IsOfType<std::string>());
+ EXPECT_TRUE(handle->IsRetired());
}
} // namespace
diff --git a/absl/flags/internal/registry.h b/absl/flags/internal/registry.h
index d207c225..1e655a3e 100644
--- a/absl/flags/internal/registry.h
+++ b/absl/flags/internal/registry.h
@@ -28,10 +28,14 @@
namespace absl {
ABSL_NAMESPACE_BEGIN
-namespace flags_internal {
+// TODO(rogeeff): remove this declaration
CommandLineFlag* FindCommandLineFlag(absl::string_view name);
-CommandLineFlag* FindRetiredFlag(absl::string_view name);
+
+namespace flags_internal {
+
+// TODO(rogeeff): remove this alias
+using absl::FindCommandLineFlag;
// Executes specified visitor for each non-retired flag in the registry.
// Requires the caller hold the registry lock.
@@ -85,11 +89,6 @@ inline bool RetiredFlag(const char* flag_name) {
return flags_internal::Retire(flag_name, base_internal::FastTypeId<T>());
}
-// If the flag is retired, returns true and indicates in |*type_is_bool|
-// whether the type of the retired flag is a bool.
-// Only to be called by code that needs to explicitly ignore retired flags.
-bool IsRetiredFlag(absl::string_view name, bool* type_is_bool);
-
//-----------------------------------------------------------------------------
// Saves the states (value, default value, whether the user has set
// the flag, registered validators, etc) of all flags, and restores
diff --git a/absl/flags/internal/type_erased.cc b/absl/flags/internal/type_erased.cc
deleted file mode 100644
index b2523b24..00000000
--- a/absl/flags/internal/type_erased.cc
+++ /dev/null
@@ -1,86 +0,0 @@
-//
-// Copyright 2019 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 "absl/flags/internal/type_erased.h"
-
-#include <assert.h>
-
-#include <string>
-
-#include "absl/base/config.h"
-#include "absl/base/internal/raw_logging.h"
-#include "absl/flags/commandlineflag.h"
-#include "absl/flags/internal/private_handle_accessor.h"
-#include "absl/flags/internal/registry.h"
-#include "absl/flags/usage_config.h"
-#include "absl/strings/string_view.h"
-
-namespace absl {
-ABSL_NAMESPACE_BEGIN
-namespace flags_internal {
-
-bool GetCommandLineOption(absl::string_view name, std::string* value) {
- if (name.empty()) return false;
- assert(value);
-
- CommandLineFlag* flag = flags_internal::FindCommandLineFlag(name);
- if (flag == nullptr || flag->IsRetired()) {
- return false;
- }
-
- *value = flag->CurrentValue();
- return true;
-}
-
-bool SetCommandLineOption(absl::string_view name, absl::string_view value) {
- return SetCommandLineOptionWithMode(name, value,
- flags_internal::SET_FLAGS_VALUE);
-}
-
-bool SetCommandLineOptionWithMode(absl::string_view name,
- absl::string_view value,
- FlagSettingMode set_mode) {
- CommandLineFlag* flag = flags_internal::FindCommandLineFlag(name);
-
- if (!flag || flag->IsRetired()) return false;
-
- std::string error;
- if (!flags_internal::PrivateHandleAccessor::ParseFrom(
- *flag, value, set_mode, kProgrammaticChange, error)) {
- // Errors here are all of the form: the provided name was a recognized
- // flag, but the value was invalid (bad type, or validation failed).
- flags_internal::ReportUsageError(error, false);
- return false;
- }
-
- return true;
-}
-
-// --------------------------------------------------------------------
-
-bool IsValidFlagValue(absl::string_view name, absl::string_view value) {
- CommandLineFlag* flag = flags_internal::FindCommandLineFlag(name);
-
- return flag != nullptr &&
- (flag->IsRetired() ||
- flags_internal::PrivateHandleAccessor::ValidateInputValue(*flag,
- value));
-}
-
-// --------------------------------------------------------------------
-
-} // namespace flags_internal
-ABSL_NAMESPACE_END
-} // namespace absl
diff --git a/absl/flags/internal/type_erased.h b/absl/flags/internal/type_erased.h
deleted file mode 100644
index 437a8c28..00000000
--- a/absl/flags/internal/type_erased.h
+++ /dev/null
@@ -1,80 +0,0 @@
-//
-// Copyright 2019 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.
-
-#ifndef ABSL_FLAGS_INTERNAL_TYPE_ERASED_H_
-#define ABSL_FLAGS_INTERNAL_TYPE_ERASED_H_
-
-#include <string>
-
-#include "absl/base/config.h"
-#include "absl/flags/commandlineflag.h"
-#include "absl/flags/internal/commandlineflag.h"
-#include "absl/flags/internal/registry.h"
-#include "absl/strings/string_view.h"
-
-// --------------------------------------------------------------------
-// Registry interfaces operating on type erased handles.
-
-namespace absl {
-ABSL_NAMESPACE_BEGIN
-namespace flags_internal {
-
-// If a flag named "name" exists, store its current value in *OUTPUT
-// and return true. Else return false without changing *OUTPUT.
-// Thread-safe.
-bool GetCommandLineOption(absl::string_view name, std::string* value);
-
-// Set the value of the flag named "name" to value. If successful,
-// returns true. If not successful (e.g., the flag was not found or
-// the value is not a valid value), returns false.
-// Thread-safe.
-bool SetCommandLineOption(absl::string_view name, absl::string_view value);
-
-bool SetCommandLineOptionWithMode(absl::string_view name,
- absl::string_view value,
- FlagSettingMode set_mode);
-
-//-----------------------------------------------------------------------------
-
-// Returns true iff all of the following conditions are true:
-// (a) "name" names a registered flag
-// (b) "value" can be parsed succesfully according to the type of the flag
-// (c) parsed value passes any validator associated with the flag
-bool IsValidFlagValue(absl::string_view name, absl::string_view value);
-
-//-----------------------------------------------------------------------------
-
-// If a flag with specified "name" exists and has type T, store
-// its current value in *dst and return true. Else return false
-// without touching *dst. T must obey all of the requirements for
-// types passed to DEFINE_FLAG.
-template <typename T>
-inline bool GetByName(absl::string_view name, T* dst) {
- CommandLineFlag* flag = flags_internal::FindCommandLineFlag(name);
- if (!flag) return false;
-
- if (auto val = flag->TryGet<T>()) {
- *dst = *val;
- return true;
- }
-
- return false;
-}
-
-} // namespace flags_internal
-ABSL_NAMESPACE_END
-} // namespace absl
-
-#endif // ABSL_FLAGS_INTERNAL_TYPE_ERASED_H_
diff --git a/absl/flags/internal/type_erased_test.cc b/absl/flags/internal/type_erased_test.cc
deleted file mode 100644
index 42f374dc..00000000
--- a/absl/flags/internal/type_erased_test.cc
+++ /dev/null
@@ -1,156 +0,0 @@
-//
-// Copyright 2019 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 "absl/flags/internal/type_erased.h"
-
-#include <memory>
-#include <string>
-
-#include "gtest/gtest.h"
-#include "absl/flags/flag.h"
-#include "absl/flags/internal/commandlineflag.h"
-#include "absl/flags/internal/registry.h"
-#include "absl/memory/memory.h"
-
-ABSL_FLAG(int, int_flag, 1, "int_flag help");
-ABSL_FLAG(std::string, string_flag, "dflt", "string_flag help");
-ABSL_RETIRED_FLAG(bool, bool_retired_flag, false, "bool_retired_flag help");
-
-namespace {
-
-namespace flags = absl::flags_internal;
-
-class TypeErasedTest : public testing::Test {
- protected:
- void SetUp() override { flag_saver_ = absl::make_unique<flags::FlagSaver>(); }
- void TearDown() override { flag_saver_.reset(); }
-
- private:
- std::unique_ptr<flags::FlagSaver> flag_saver_;
-};
-
-// --------------------------------------------------------------------
-
-TEST_F(TypeErasedTest, TestGetCommandLineOption) {
- std::string value;
- EXPECT_TRUE(flags::GetCommandLineOption("int_flag", &value));
- EXPECT_EQ(value, "1");
-
- EXPECT_TRUE(flags::GetCommandLineOption("string_flag", &value));
- EXPECT_EQ(value, "dflt");
-
- EXPECT_FALSE(flags::GetCommandLineOption("bool_retired_flag", &value));
-
- EXPECT_FALSE(flags::GetCommandLineOption("unknown_flag", &value));
-}
-
-// --------------------------------------------------------------------
-
-TEST_F(TypeErasedTest, TestSetCommandLineOption) {
- EXPECT_TRUE(flags::SetCommandLineOption("int_flag", "101"));
- EXPECT_EQ(absl::GetFlag(FLAGS_int_flag), 101);
-
- EXPECT_TRUE(flags::SetCommandLineOption("string_flag", "asdfgh"));
- EXPECT_EQ(absl::GetFlag(FLAGS_string_flag), "asdfgh");
-
- EXPECT_FALSE(flags::SetCommandLineOption("bool_retired_flag", "true"));
-
- EXPECT_FALSE(flags::SetCommandLineOption("unknown_flag", "true"));
-}
-
-// --------------------------------------------------------------------
-
-TEST_F(TypeErasedTest, TestSetCommandLineOptionWithMode_SET_FLAGS_VALUE) {
- EXPECT_TRUE(flags::SetCommandLineOptionWithMode("int_flag", "101",
- flags::SET_FLAGS_VALUE));
- EXPECT_EQ(absl::GetFlag(FLAGS_int_flag), 101);
-
- EXPECT_TRUE(flags::SetCommandLineOptionWithMode("string_flag", "asdfgh",
- flags::SET_FLAGS_VALUE));
- EXPECT_EQ(absl::GetFlag(FLAGS_string_flag), "asdfgh");
-
- EXPECT_FALSE(flags::SetCommandLineOptionWithMode("bool_retired_flag", "true",
- flags::SET_FLAGS_VALUE));
-
- EXPECT_FALSE(flags::SetCommandLineOptionWithMode("unknown_flag", "true",
- flags::SET_FLAGS_VALUE));
-}
-
-// --------------------------------------------------------------------
-
-TEST_F(TypeErasedTest, TestSetCommandLineOptionWithMode_SET_FLAG_IF_DEFAULT) {
- EXPECT_TRUE(flags::SetCommandLineOptionWithMode("int_flag", "101",
- flags::SET_FLAG_IF_DEFAULT));
- EXPECT_EQ(absl::GetFlag(FLAGS_int_flag), 101);
-
- // This semantic is broken. We return true instead of false. Value is not
- // updated.
- EXPECT_TRUE(flags::SetCommandLineOptionWithMode("int_flag", "202",
- flags::SET_FLAG_IF_DEFAULT));
- EXPECT_EQ(absl::GetFlag(FLAGS_int_flag), 101);
-
- EXPECT_TRUE(flags::SetCommandLineOptionWithMode("string_flag", "asdfgh",
- flags::SET_FLAG_IF_DEFAULT));
- EXPECT_EQ(absl::GetFlag(FLAGS_string_flag), "asdfgh");
-
- EXPECT_FALSE(flags::SetCommandLineOptionWithMode("bool_retired_flag", "true",
- flags::SET_FLAG_IF_DEFAULT));
-
- EXPECT_FALSE(flags::SetCommandLineOptionWithMode("unknown_flag", "true",
- flags::SET_FLAG_IF_DEFAULT));
-}
-
-// --------------------------------------------------------------------
-
-TEST_F(TypeErasedTest, TestSetCommandLineOptionWithMode_SET_FLAGS_DEFAULT) {
- EXPECT_TRUE(flags::SetCommandLineOptionWithMode("int_flag", "101",
- flags::SET_FLAGS_DEFAULT));
-
- // Set it again to ensure that resetting logic is covered.
- EXPECT_TRUE(flags::SetCommandLineOptionWithMode("int_flag", "102",
- flags::SET_FLAGS_DEFAULT));
-
- EXPECT_TRUE(flags::SetCommandLineOptionWithMode("int_flag", "103",
- flags::SET_FLAGS_DEFAULT));
-
- EXPECT_TRUE(flags::SetCommandLineOptionWithMode("string_flag", "asdfgh",
- flags::SET_FLAGS_DEFAULT));
- EXPECT_EQ(absl::GetFlag(FLAGS_string_flag), "asdfgh");
-
- EXPECT_FALSE(flags::SetCommandLineOptionWithMode("bool_retired_flag", "true",
- flags::SET_FLAGS_DEFAULT));
-
- EXPECT_FALSE(flags::SetCommandLineOptionWithMode("unknown_flag", "true",
- flags::SET_FLAGS_DEFAULT));
-
- // This should be successfull, since flag is still is not set
- EXPECT_TRUE(flags::SetCommandLineOptionWithMode("int_flag", "202",
- flags::SET_FLAG_IF_DEFAULT));
- EXPECT_EQ(absl::GetFlag(FLAGS_int_flag), 202);
-}
-
-// --------------------------------------------------------------------
-
-TEST_F(TypeErasedTest, TestIsValidFlagValue) {
- EXPECT_TRUE(flags::IsValidFlagValue("int_flag", "57"));
- EXPECT_TRUE(flags::IsValidFlagValue("int_flag", "-101"));
- EXPECT_FALSE(flags::IsValidFlagValue("int_flag", "1.1"));
-
- EXPECT_TRUE(flags::IsValidFlagValue("string_flag", "#%^#%^$%DGHDG$W%adsf"));
-
- EXPECT_TRUE(flags::IsValidFlagValue("bool_retired_flag", "true"));
-}
-
-} // namespace
diff --git a/absl/flags/internal/usage_test.cc b/absl/flags/internal/usage_test.cc
index 53b4d983..46f85b55 100644
--- a/absl/flags/internal/usage_test.cc
+++ b/absl/flags/internal/usage_test.cc
@@ -25,7 +25,7 @@
#include "absl/flags/internal/parse.h"
#include "absl/flags/internal/path_util.h"
#include "absl/flags/internal/program_name.h"
-#include "absl/flags/internal/registry.h"
+#include "absl/flags/reflection.h"
#include "absl/flags/usage.h"
#include "absl/flags/usage_config.h"
#include "absl/strings/match.h"
@@ -110,7 +110,7 @@ TEST_F(UsageReportingDeathTest, TestSetProgramUsageMessage) {
// --------------------------------------------------------------------
TEST_F(UsageReportingTest, TestFlagHelpHRF_on_flag_01) {
- const auto* flag = flags::FindCommandLineFlag("usage_reporting_test_flag_01");
+ const auto* flag = absl::FindCommandLineFlag("usage_reporting_test_flag_01");
std::stringstream test_buf;
flags::FlagHelp(test_buf, *flag, flags::HelpFormat::kHumanReadable);
@@ -122,7 +122,7 @@ TEST_F(UsageReportingTest, TestFlagHelpHRF_on_flag_01) {
}
TEST_F(UsageReportingTest, TestFlagHelpHRF_on_flag_02) {
- const auto* flag = flags::FindCommandLineFlag("usage_reporting_test_flag_02");
+ const auto* flag = absl::FindCommandLineFlag("usage_reporting_test_flag_02");
std::stringstream test_buf;
flags::FlagHelp(test_buf, *flag, flags::HelpFormat::kHumanReadable);
@@ -134,7 +134,7 @@ TEST_F(UsageReportingTest, TestFlagHelpHRF_on_flag_02) {
}
TEST_F(UsageReportingTest, TestFlagHelpHRF_on_flag_03) {
- const auto* flag = flags::FindCommandLineFlag("usage_reporting_test_flag_03");
+ const auto* flag = absl::FindCommandLineFlag("usage_reporting_test_flag_03");
std::stringstream test_buf;
flags::FlagHelp(test_buf, *flag, flags::HelpFormat::kHumanReadable);
@@ -146,7 +146,7 @@ TEST_F(UsageReportingTest, TestFlagHelpHRF_on_flag_03) {
}
TEST_F(UsageReportingTest, TestFlagHelpHRF_on_flag_04) {
- const auto* flag = flags::FindCommandLineFlag("usage_reporting_test_flag_04");
+ const auto* flag = absl::FindCommandLineFlag("usage_reporting_test_flag_04");
std::stringstream test_buf;
flags::FlagHelp(test_buf, *flag, flags::HelpFormat::kHumanReadable);
@@ -158,7 +158,7 @@ TEST_F(UsageReportingTest, TestFlagHelpHRF_on_flag_04) {
}
TEST_F(UsageReportingTest, TestFlagHelpHRF_on_flag_05) {
- const auto* flag = flags::FindCommandLineFlag("usage_reporting_test_flag_05");
+ const auto* flag = absl::FindCommandLineFlag("usage_reporting_test_flag_05");
std::stringstream test_buf;
flags::FlagHelp(test_buf, *flag, flags::HelpFormat::kHumanReadable);
diff --git a/absl/flags/parse.cc b/absl/flags/parse.cc
index f0a131f2..e2c88ff8 100644
--- a/absl/flags/parse.cc
+++ b/absl/flags/parse.cc
@@ -42,8 +42,8 @@
#include "absl/flags/internal/parse.h"
#include "absl/flags/internal/private_handle_accessor.h"
#include "absl/flags/internal/program_name.h"
-#include "absl/flags/internal/registry.h"
#include "absl/flags/internal/usage.h"
+#include "absl/flags/reflection.h"
#include "absl/flags/usage.h"
#include "absl/flags/usage_config.h"
#include "absl/strings/ascii.h"
@@ -290,11 +290,11 @@ std::tuple<absl::string_view, absl::string_view, bool> SplitNameAndValue(
// found flag or nullptr
// is negative in case of --nofoo
std::tuple<CommandLineFlag*, bool> LocateFlag(absl::string_view flag_name) {
- CommandLineFlag* flag = flags_internal::FindCommandLineFlag(flag_name);
+ CommandLineFlag* flag = absl::FindCommandLineFlag(flag_name);
bool is_negative = false;
if (!flag && absl::ConsumePrefix(&flag_name, "no")) {
- flag = flags_internal::FindCommandLineFlag(flag_name);
+ flag = absl::FindCommandLineFlag(flag_name);
is_negative = true;
}
diff --git a/absl/flags/parse_test.cc b/absl/flags/parse_test.cc
index aea068ee..1ab87690 100644
--- a/absl/flags/parse_test.cc
+++ b/absl/flags/parse_test.cc
@@ -28,7 +28,7 @@
#include "absl/flags/declare.h"
#include "absl/flags/flag.h"
#include "absl/flags/internal/parse.h"
-#include "absl/flags/internal/registry.h"
+#include "absl/flags/reflection.h"
#include "absl/strings/str_cat.h"
#include "absl/strings/string_view.h"
#include "absl/strings/substitute.h"
diff --git a/absl/flags/internal/registry.cc b/absl/flags/reflection.cc
index e582d79d..02bb6c2e 100644
--- a/absl/flags/internal/registry.cc
+++ b/absl/flags/reflection.cc
@@ -1,5 +1,5 @@
//
-// Copyright 2019 The Abseil Authors.
+// Copyright 2020 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.
@@ -13,47 +13,34 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-#include "absl/flags/internal/registry.h"
+#include "absl/flags/reflection.h"
#include <assert.h>
-#include <stdlib.h>
-#include <functional>
#include <map>
-#include <memory>
#include <string>
-#include <utility>
-#include <vector>
#include "absl/base/config.h"
-#include "absl/base/internal/raw_logging.h"
#include "absl/base/thread_annotations.h"
#include "absl/flags/commandlineflag.h"
-#include "absl/flags/internal/commandlineflag.h"
#include "absl/flags/internal/private_handle_accessor.h"
+#include "absl/flags/internal/registry.h"
#include "absl/flags/usage_config.h"
#include "absl/strings/str_cat.h"
#include "absl/strings/string_view.h"
#include "absl/synchronization/mutex.h"
-// --------------------------------------------------------------------
-// FlagRegistry implementation
-// A FlagRegistry holds all flag objects indexed
-// by their names so that if you know a flag's name you can access or
-// set it.
-
namespace absl {
ABSL_NAMESPACE_BEGIN
namespace flags_internal {
// --------------------------------------------------------------------
// FlagRegistry
-// A FlagRegistry singleton object holds all flag objects indexed
-// by their names so that if you know a flag's name (as a C
-// string), you can access or set it. If the function is named
-// FooLocked(), you must own the registry lock before calling
-// the function; otherwise, you should *not* hold the lock, and
-// the function will acquire it itself if needed.
+// A FlagRegistry singleton object holds all flag objects indexed by their
+// names so that if you know a flag's name, you can access or set it. If the
+// function is named FooLocked(), you must own the registry lock before
+// calling the function; otherwise, you should *not* hold the lock, and the
+// function will acquire it itself if needed.
// --------------------------------------------------------------------
class FlagRegistry {
@@ -95,9 +82,27 @@ class FlagRegistry {
FlagRegistry& operator=(const FlagRegistry&);
};
-FlagRegistry& FlagRegistry::GlobalRegistry() {
- static FlagRegistry* global_registry = new FlagRegistry;
- return *global_registry;
+CommandLineFlag* FlagRegistry::FindFlagLocked(absl::string_view name) {
+ FlagConstIterator i = flags_.find(name);
+ if (i == flags_.end()) {
+ return nullptr;
+ }
+
+ if (i->second->IsRetired()) {
+ flags_internal::ReportUsageError(
+ absl::StrCat("Accessing retired flag '", name, "'"), false);
+ }
+
+ return i->second;
+}
+
+CommandLineFlag* FlagRegistry::FindRetiredFlagLocked(absl::string_view name) {
+ FlagConstIterator i = flags_.find(name);
+ if (i == flags_.end() || !i->second->IsRetired()) {
+ return nullptr;
+ }
+
+ return i->second;
}
namespace {
@@ -161,98 +166,9 @@ void FlagRegistry::RegisterFlag(CommandLineFlag& flag) {
}
}
-CommandLineFlag* FlagRegistry::FindFlagLocked(absl::string_view name) {
- FlagConstIterator i = flags_.find(name);
- if (i == flags_.end()) {
- return nullptr;
- }
-
- if (i->second->IsRetired()) {
- flags_internal::ReportUsageError(
- absl::StrCat("Accessing retired flag '", name, "'"), false);
- }
-
- return i->second;
-}
-
-CommandLineFlag* FlagRegistry::FindRetiredFlagLocked(absl::string_view name) {
- FlagConstIterator i = flags_.find(name);
- if (i == flags_.end() || !i->second->IsRetired()) {
- return nullptr;
- }
-
- return i->second;
-}
-
-// --------------------------------------------------------------------
-// FlagSaver
-// FlagSaverImpl
-// This class stores the states of all flags at construct time,
-// and restores all flags to that state at destruct time.
-// Its major implementation challenge is that it never modifies
-// pointers in the 'main' registry, so global FLAG_* vars always
-// point to the right place.
-// --------------------------------------------------------------------
-
-class FlagSaverImpl {
- public:
- FlagSaverImpl() = default;
- FlagSaverImpl(const FlagSaverImpl&) = delete;
- void operator=(const FlagSaverImpl&) = delete;
-
- // Saves the flag states from the flag registry into this object.
- // It's an error to call this more than once.
- void SaveFromRegistry() {
- assert(backup_registry_.empty()); // call only once!
- flags_internal::ForEachFlag([&](CommandLineFlag& flag) {
- if (auto flag_state =
- flags_internal::PrivateHandleAccessor::SaveState(flag)) {
- backup_registry_.emplace_back(std::move(flag_state));
- }
- });
- }
-
- // Restores the saved flag states into the flag registry.
- void RestoreToRegistry() {
- for (const auto& flag_state : backup_registry_) {
- flag_state->Restore();
- }
- }
-
- private:
- std::vector<std::unique_ptr<flags_internal::FlagStateInterface>>
- backup_registry_;
-};
-
-FlagSaver::FlagSaver() : impl_(new FlagSaverImpl) { impl_->SaveFromRegistry(); }
-
-void FlagSaver::Ignore() {
- delete impl_;
- impl_ = nullptr;
-}
-
-FlagSaver::~FlagSaver() {
- if (!impl_) return;
-
- impl_->RestoreToRegistry();
- delete impl_;
-}
-
-// --------------------------------------------------------------------
-
-CommandLineFlag* FindCommandLineFlag(absl::string_view name) {
- if (name.empty()) return nullptr;
- FlagRegistry& registry = FlagRegistry::GlobalRegistry();
- FlagRegistryLock frl(registry);
-
- return registry.FindFlagLocked(name);
-}
-
-CommandLineFlag* FindRetiredFlag(absl::string_view name) {
- FlagRegistry& registry = FlagRegistry::GlobalRegistry();
- FlagRegistryLock frl(registry);
-
- return registry.FindRetiredFlagLocked(name);
+FlagRegistry& FlagRegistry::GlobalRegistry() {
+ static FlagRegistry* global_registry = new FlagRegistry;
+ return *global_registry;
}
// --------------------------------------------------------------------
@@ -333,17 +249,71 @@ bool Retire(const char* name, FlagFastTypeId type_id) {
// --------------------------------------------------------------------
-bool IsRetiredFlag(absl::string_view name, bool* type_is_bool) {
- assert(!name.empty());
- CommandLineFlag* flag = flags_internal::FindRetiredFlag(name);
- if (flag == nullptr) {
- return false;
+// FlagSaver
+// FlagSaverImpl
+// This class stores the states of all flags at construct time,
+// and restores all flags to that state at destruct time.
+// Its major implementation challenge is that it never modifies
+// pointers in the 'main' registry, so global FLAG_* vars always
+// point to the right place.
+// --------------------------------------------------------------------
+
+class FlagSaverImpl {
+ public:
+ FlagSaverImpl() = default;
+ FlagSaverImpl(const FlagSaverImpl&) = delete;
+ void operator=(const FlagSaverImpl&) = delete;
+
+ // Saves the flag states from the flag registry into this object.
+ // It's an error to call this more than once.
+ void SaveFromRegistry() {
+ assert(backup_registry_.empty()); // call only once!
+ flags_internal::ForEachFlag([&](CommandLineFlag& flag) {
+ if (auto flag_state =
+ flags_internal::PrivateHandleAccessor::SaveState(flag)) {
+ backup_registry_.emplace_back(std::move(flag_state));
+ }
+ });
}
- assert(type_is_bool);
- *type_is_bool = flag->IsOfType<bool>();
- return true;
+
+ // Restores the saved flag states into the flag registry.
+ void RestoreToRegistry() {
+ for (const auto& flag_state : backup_registry_) {
+ flag_state->Restore();
+ }
+ }
+
+ private:
+ std::vector<std::unique_ptr<flags_internal::FlagStateInterface>>
+ backup_registry_;
+};
+
+FlagSaver::FlagSaver() : impl_(new FlagSaverImpl) { impl_->SaveFromRegistry(); }
+
+void FlagSaver::Ignore() {
+ delete impl_;
+ impl_ = nullptr;
+}
+
+FlagSaver::~FlagSaver() {
+ if (!impl_) return;
+
+ impl_->RestoreToRegistry();
+ delete impl_;
}
+// --------------------------------------------------------------------
+
} // namespace flags_internal
+
+CommandLineFlag* FindCommandLineFlag(absl::string_view name) {
+ if (name.empty()) return nullptr;
+ flags_internal::FlagRegistry& registry =
+ flags_internal::FlagRegistry::GlobalRegistry();
+ flags_internal::FlagRegistryLock frl(registry);
+
+ return registry.FindFlagLocked(name);
+}
+
ABSL_NAMESPACE_END
} // namespace absl
diff --git a/absl/flags/reflection.h b/absl/flags/reflection.h
new file mode 100644
index 00000000..e8e24f68
--- /dev/null
+++ b/absl/flags/reflection.h
@@ -0,0 +1,47 @@
+//
+// Copyright 2020 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.
+//
+// -----------------------------------------------------------------------------
+// File: reflection.h
+// -----------------------------------------------------------------------------
+//
+// This file defines the routines to access and operate on an Abseil Flag's
+// reflection handle.
+
+#ifndef ABSL_FLAGS_REFLECTION_H_
+#define ABSL_FLAGS_REFLECTION_H_
+
+#include <string>
+
+#include "absl/base/config.h"
+#include "absl/flags/commandlineflag.h"
+#include "absl/flags/internal/commandlineflag.h"
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+
+// FindCommandLineFlag()
+//
+// Returns the reflection handle of an Abseil flag of the specified name, or
+// `nullptr` if not found. This function will emit a warning if the name of a
+// 'retired' flag is specified.
+CommandLineFlag* FindCommandLineFlag(absl::string_view name);
+
+//-----------------------------------------------------------------------------
+
+ABSL_NAMESPACE_END
+} // namespace absl
+
+#endif // ABSL_FLAGS_REFLECTION_H_
diff --git a/absl/flags/reflection_test.cc b/absl/flags/reflection_test.cc
new file mode 100644
index 00000000..2a137bf7
--- /dev/null
+++ b/absl/flags/reflection_test.cc
@@ -0,0 +1,60 @@
+//
+// Copyright 2019 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 "absl/flags/reflection.h"
+
+#include <memory>
+#include <string>
+
+#include "gtest/gtest.h"
+#include "absl/flags/flag.h"
+#include "absl/flags/internal/commandlineflag.h"
+#include "absl/flags/marshalling.h"
+#include "absl/memory/memory.h"
+
+ABSL_FLAG(int, int_flag, 1, "int_flag help");
+ABSL_FLAG(std::string, string_flag, "dflt", "string_flag help");
+ABSL_RETIRED_FLAG(bool, bool_retired_flag, false, "bool_retired_flag help");
+
+namespace {
+
+namespace flags = absl::flags_internal;
+
+class ReflectionTest : public testing::Test {
+ protected:
+ void SetUp() override { flag_saver_ = absl::make_unique<flags::FlagSaver>(); }
+ void TearDown() override { flag_saver_.reset(); }
+
+ private:
+ std::unique_ptr<flags::FlagSaver> flag_saver_;
+};
+
+// --------------------------------------------------------------------
+
+TEST_F(ReflectionTest, TestFindCommandLineFlag) {
+ auto* handle = absl::FindCommandLineFlag("some_flag");
+ EXPECT_EQ(handle, nullptr);
+
+ handle = absl::FindCommandLineFlag("int_flag");
+ EXPECT_NE(handle, nullptr);
+
+ handle = absl::FindCommandLineFlag("string_flag");
+ EXPECT_NE(handle, nullptr);
+
+ handle = absl::FindCommandLineFlag("bool_retired_flag");
+ EXPECT_NE(handle, nullptr);
+}
+
+} // namespace
diff --git a/absl/random/BUILD.bazel b/absl/random/BUILD.bazel
index 4b804c86..694331c2 100644
--- a/absl/random/BUILD.bazel
+++ b/absl/random/BUILD.bazel
@@ -115,11 +115,12 @@ cc_library(
copts = ABSL_DEFAULT_COPTS,
linkopts = ABSL_DEFAULT_LINKOPTS,
deps = [
+ ":random",
"//absl/base:core_headers",
+ "//absl/base:fast_type_id",
"//absl/meta:type_traits",
"//absl/random/internal:distribution_caller",
"//absl/random/internal:fast_uniform_bits",
- "//absl/random/internal:mocking_bit_gen_base",
],
)
@@ -145,10 +146,11 @@ cc_library(
linkopts = ABSL_DEFAULT_LINKOPTS,
deps = [
":distributions",
+ ":random",
+ "//absl/base:fast_type_id",
"//absl/container:flat_hash_map",
"//absl/meta:type_traits",
"//absl/random/internal:distribution_caller",
- "//absl/random/internal:mocking_bit_gen_base",
"//absl/strings",
"//absl/types:span",
"//absl/types:variant",
@@ -410,6 +412,7 @@ cc_test(
deps = [
":bit_gen_ref",
":random",
+ "//absl/base:fast_type_id",
"//absl/random/internal:sequence_urbg",
"@com_google_googletest//:gtest_main",
],
diff --git a/absl/random/CMakeLists.txt b/absl/random/CMakeLists.txt
index 85a2ea37..8875b309 100644
--- a/absl/random/CMakeLists.txt
+++ b/absl/random/CMakeLists.txt
@@ -45,7 +45,6 @@ absl_cc_library(
absl::core_headers
absl::random_internal_distribution_caller
absl::random_internal_fast_uniform_bits
- absl::random_internal_mocking_bit_gen_base
absl::type_traits
)
@@ -62,6 +61,7 @@ absl_cc_test(
absl::random_bit_gen_ref
absl::random_random
absl::random_internal_sequence_urbg
+ absl::fast_type_id
gmock
gtest_main
)
@@ -69,21 +69,6 @@ absl_cc_test(
# Internal-only target, do not depend on directly.
absl_cc_library(
NAME
- random_internal_mocking_bit_gen_base
- HDRS
- "internal/mocking_bit_gen_base.h"
- COPTS
- ${ABSL_DEFAULT_COPTS}
- LINKOPTS
- ${ABSL_DEFAULT_LINKOPTS}
- DEPS
- absl::random_random
- absl::strings
-)
-
-# Internal-only target, do not depend on directly.
-absl_cc_library(
- NAME
random_internal_mock_overload_set
HDRS
"internal/mock_overload_set.h"
@@ -93,6 +78,7 @@ absl_cc_library(
${ABSL_DEFAULT_LINKOPTS}
DEPS
absl::random_mocking_bit_gen
+ absl::fast_type_id
TESTONLY
)
@@ -111,8 +97,8 @@ absl_cc_library(
absl::raw_logging_internal
absl::random_distributions
absl::random_internal_distribution_caller
- absl::random_internal_mocking_bit_gen_base
absl::random_internal_mock_overload_set
+ absl::random_random
absl::strings
absl::span
absl::type_traits
@@ -533,6 +519,8 @@ absl_cc_library(
${ABSL_DEFAULT_LINKOPTS}
DEPS
absl::config
+ absl::utility
+ absl::fast_type_id
)
# Internal-only target, do not depend on directly.
diff --git a/absl/random/bit_gen_ref.h b/absl/random/bit_gen_ref.h
index 59591a47..00e36248 100644
--- a/absl/random/bit_gen_ref.h
+++ b/absl/random/bit_gen_ref.h
@@ -24,11 +24,11 @@
#ifndef ABSL_RANDOM_BIT_GEN_REF_H_
#define ABSL_RANDOM_BIT_GEN_REF_H_
+#include "absl/base/internal/fast_type_id.h"
#include "absl/base/macros.h"
#include "absl/meta/type_traits.h"
#include "absl/random/internal/distribution_caller.h"
#include "absl/random/internal/fast_uniform_bits.h"
-#include "absl/random/internal/mocking_bit_gen_base.h"
namespace absl {
ABSL_NAMESPACE_BEGIN
@@ -51,6 +51,9 @@ struct is_urbg<
typename std::decay<decltype(std::declval<URBG>()())>::type>::value>>
: std::true_type {};
+template <typename>
+struct DistributionCaller;
+
} // namespace random_internal
// -----------------------------------------------------------------------------
@@ -77,23 +80,50 @@ struct is_urbg<
// }
//
class BitGenRef {
- public:
- using result_type = uint64_t;
+ // SFINAE to detect whether the URBG type includes a member matching
+ // bool InvokeMock(base_internal::FastTypeIdType, void*, void*).
+ //
+ // These live inside BitGenRef so that they have friend access
+ // to MockingBitGen. (see similar methods in DistributionCaller).
+ template <template <class...> class Trait, class AlwaysVoid, class... Args>
+ struct detector : std::false_type {};
+ template <template <class...> class Trait, class... Args>
+ struct detector<Trait, absl::void_t<Trait<Args...>>, Args...>
+ : std::true_type {};
+
+ template <class T>
+ using invoke_mock_t = decltype(std::declval<T*>()->InvokeMock(
+ std::declval<base_internal::FastTypeIdType>(), std::declval<void*>(),
+ std::declval<void*>()));
+
+ template <typename T>
+ using HasInvokeMock = typename detector<invoke_mock_t, void, T>::type;
- BitGenRef(const absl::BitGenRef&) = default;
- BitGenRef(absl::BitGenRef&&) = default;
- BitGenRef& operator=(const absl::BitGenRef&) = default;
- BitGenRef& operator=(absl::BitGenRef&&) = default;
+ public:
+ BitGenRef(const BitGenRef&) = default;
+ BitGenRef(BitGenRef&&) = default;
+ BitGenRef& operator=(const BitGenRef&) = default;
+ BitGenRef& operator=(BitGenRef&&) = default;
+
+ template <typename URBG, typename absl::enable_if_t<
+ (!std::is_same<URBG, BitGenRef>::value &&
+ random_internal::is_urbg<URBG>::value &&
+ !HasInvokeMock<URBG>::value)>* = nullptr>
+ BitGenRef(URBG& gen) // NOLINT
+ : t_erased_gen_ptr_(reinterpret_cast<uintptr_t>(&gen)),
+ mock_call_(NotAMock),
+ generate_impl_fn_(ImplFn<URBG>) {}
template <typename URBG,
- typename absl::enable_if_t<
- (!std::is_same<URBG, BitGenRef>::value &&
- random_internal::is_urbg<URBG>::value)>* = nullptr>
+ typename absl::enable_if_t<(!std::is_same<URBG, BitGenRef>::value &&
+ random_internal::is_urbg<URBG>::value &&
+ HasInvokeMock<URBG>::value)>* = nullptr>
BitGenRef(URBG& gen) // NOLINT
- : mocked_gen_ptr_(MakeMockPointer(&gen)),
- t_erased_gen_ptr_(reinterpret_cast<uintptr_t>(&gen)),
- generate_impl_fn_(ImplFn<URBG>) {
- }
+ : t_erased_gen_ptr_(reinterpret_cast<uintptr_t>(&gen)),
+ mock_call_(&MockCall<URBG>),
+ generate_impl_fn_(ImplFn<URBG>) {}
+
+ using result_type = uint64_t;
static constexpr result_type(min)() {
return (std::numeric_limits<result_type>::min)();
@@ -106,14 +136,9 @@ class BitGenRef {
result_type operator()() { return generate_impl_fn_(t_erased_gen_ptr_); }
private:
- friend struct absl::random_internal::DistributionCaller<absl::BitGenRef>;
using impl_fn = result_type (*)(uintptr_t);
- using mocker_base_t = absl::random_internal::MockingBitGenBase;
-
- // Convert an arbitrary URBG pointer into either a valid mocker_base_t
- // pointer or a nullptr.
- static inline mocker_base_t* MakeMockPointer(mocker_base_t* t) { return t; }
- static inline mocker_base_t* MakeMockPointer(void*) { return nullptr; }
+ using mock_call_fn = bool (*)(uintptr_t, base_internal::FastTypeIdType, void*,
+ void*);
template <typename URBG>
static result_type ImplFn(uintptr_t ptr) {
@@ -123,29 +148,31 @@ class BitGenRef {
return fast_uniform_bits(*reinterpret_cast<URBG*>(ptr));
}
- mocker_base_t* mocked_gen_ptr_;
+ // Get a type-erased InvokeMock pointer.
+ template <typename URBG>
+ static bool MockCall(uintptr_t gen_ptr, base_internal::FastTypeIdType type,
+ void* result, void* arg_tuple) {
+ return reinterpret_cast<URBG*>(gen_ptr)->InvokeMock(type, result,
+ arg_tuple);
+ }
+ static bool NotAMock(uintptr_t, base_internal::FastTypeIdType, void*, void*) {
+ return false;
+ }
+
+ inline bool InvokeMock(base_internal::FastTypeIdType type, void* args_tuple,
+ void* result) {
+ if (mock_call_ == NotAMock) return false; // avoids an indirect call.
+ return mock_call_(t_erased_gen_ptr_, type, args_tuple, result);
+ }
+
uintptr_t t_erased_gen_ptr_;
+ mock_call_fn mock_call_;
impl_fn generate_impl_fn_;
-};
-
-namespace random_internal {
-template <>
-struct DistributionCaller<absl::BitGenRef> {
- template <typename DistrT, typename... Args>
- static typename DistrT::result_type Call(absl::BitGenRef* gen_ref,
- Args&&... args) {
- auto* mock_ptr = gen_ref->mocked_gen_ptr_;
- if (mock_ptr == nullptr) {
- DistrT dist(std::forward<Args>(args)...);
- return dist(*gen_ref);
- } else {
- return mock_ptr->template Call<DistrT>(std::forward<Args>(args)...);
- }
- }
+ template <typename>
+ friend struct ::absl::random_internal::DistributionCaller; // for InvokeMock
};
-} // namespace random_internal
ABSL_NAMESPACE_END
} // namespace absl
diff --git a/absl/random/bit_gen_ref_test.cc b/absl/random/bit_gen_ref_test.cc
index ca0e4d70..1135cf2d 100644
--- a/absl/random/bit_gen_ref_test.cc
+++ b/absl/random/bit_gen_ref_test.cc
@@ -17,30 +17,31 @@
#include "gmock/gmock.h"
#include "gtest/gtest.h"
+#include "absl/base/internal/fast_type_id.h"
#include "absl/random/internal/sequence_urbg.h"
#include "absl/random/random.h"
namespace absl {
ABSL_NAMESPACE_BEGIN
-class ConstBitGen : public absl::random_internal::MockingBitGenBase {
- bool CallImpl(const std::type_info&, void*, void* result) override {
+class ConstBitGen {
+ public:
+ // URBG interface
+ using result_type = absl::BitGen::result_type;
+
+ static constexpr result_type(min)() { return (absl::BitGen::min)(); }
+ static constexpr result_type(max)() { return (absl::BitGen::max)(); }
+ result_type operator()() { return 1; }
+
+ // InvokeMock method
+ bool InvokeMock(base_internal::FastTypeIdType index, void*, void* result) {
*static_cast<int*>(result) = 42;
return true;
}
};
-namespace random_internal {
-template <>
-struct DistributionCaller<ConstBitGen> {
- template <typename DistrT, typename FormatT, typename... Args>
- static typename DistrT::result_type Call(ConstBitGen* gen, Args&&... args) {
- return gen->template Call<DistrT, FormatT>(std::forward<Args>(args)...);
- }
-};
-} // namespace random_internal
-
namespace {
+
int FnTest(absl::BitGenRef gen_ref) { return absl::Uniform(gen_ref, 1, 7); }
template <typename T>
diff --git a/absl/random/internal/BUILD.bazel b/absl/random/internal/BUILD.bazel
index 813d926e..3ab1177d 100644
--- a/absl/random/internal/BUILD.bazel
+++ b/absl/random/internal/BUILD.bazel
@@ -45,7 +45,11 @@ cc_library(
hdrs = ["distribution_caller.h"],
copts = ABSL_DEFAULT_COPTS,
linkopts = ABSL_DEFAULT_LINKOPTS,
- deps = ["//absl/base:config"],
+ deps = [
+ "//absl/base:config",
+ "//absl/base:fast_type_id",
+ "//absl/utility",
+ ],
)
cc_library(
@@ -481,20 +485,11 @@ cc_test(
)
cc_library(
- name = "mocking_bit_gen_base",
- hdrs = ["mocking_bit_gen_base.h"],
- linkopts = ABSL_DEFAULT_LINKOPTS,
- deps = [
- "//absl/random",
- "//absl/strings",
- ],
-)
-
-cc_library(
name = "mock_overload_set",
testonly = 1,
hdrs = ["mock_overload_set.h"],
deps = [
+ "//absl/base:fast_type_id",
"//absl/random:mocking_bit_gen",
"@com_google_googletest//:gtest",
],
diff --git a/absl/random/internal/distribution_caller.h b/absl/random/internal/distribution_caller.h
index 4e072444..87a76845 100644
--- a/absl/random/internal/distribution_caller.h
+++ b/absl/random/internal/distribution_caller.h
@@ -20,6 +20,8 @@
#include <utility>
#include "absl/base/config.h"
+#include "absl/base/internal/fast_type_id.h"
+#include "absl/utility/utility.h"
namespace absl {
ABSL_NAMESPACE_BEGIN
@@ -30,14 +32,55 @@ namespace random_internal {
// to intercept such calls.
template <typename URBG>
struct DistributionCaller {
- // Call the provided distribution type. The parameters are expected
- // to be explicitly specified.
- // DistrT is the distribution type.
+ // SFINAE to detect whether the URBG type includes a member matching
+ // bool InvokeMock(base_internal::FastTypeIdType, void*, void*).
+ //
+ // These live inside BitGenRef so that they have friend access
+ // to MockingBitGen. (see similar methods in DistributionCaller).
+ template <template <class...> class Trait, class AlwaysVoid, class... Args>
+ struct detector : std::false_type {};
+ template <template <class...> class Trait, class... Args>
+ struct detector<Trait, absl::void_t<Trait<Args...>>, Args...>
+ : std::true_type {};
+
+ template <class T>
+ using invoke_mock_t = decltype(std::declval<T*>()->InvokeMock(
+ std::declval<::absl::base_internal::FastTypeIdType>(),
+ std::declval<void*>(), std::declval<void*>()));
+
+ using HasInvokeMock = typename detector<invoke_mock_t, void, URBG>::type;
+
+ // Default implementation of distribution caller.
template <typename DistrT, typename... Args>
- static typename DistrT::result_type Call(URBG* urbg, Args&&... args) {
+ static inline typename DistrT::result_type Impl(std::false_type, URBG* urbg,
+ Args&&... args) {
DistrT dist(std::forward<Args>(args)...);
return dist(*urbg);
}
+
+ // Mock implementation of distribution caller.
+ template <typename DistrT, typename... Args>
+ static inline typename DistrT::result_type Impl(std::true_type, URBG* urbg,
+ Args&&... args) {
+ using ResultT = typename DistrT::result_type;
+ using ArgTupleT = std::tuple<absl::decay_t<Args>...>;
+ ArgTupleT arg_tuple(std::forward<Args>(args)...);
+ ResultT result;
+ if (!urbg->InvokeMock(
+ ::absl::base_internal::FastTypeId<ResultT(DistrT, ArgTupleT)>(),
+ &arg_tuple, &result)) {
+ auto dist = absl::make_from_tuple<DistrT>(arg_tuple);
+ result = dist(*urbg);
+ }
+ return result;
+ }
+
+ // Default implementation of distribution caller.
+ template <typename DistrT, typename... Args>
+ static inline typename DistrT::result_type Call(URBG* urbg, Args&&... args) {
+ return Impl<DistrT, Args...>(HasInvokeMock{}, urbg,
+ std::forward<Args>(args)...);
+ }
};
} // namespace random_internal
diff --git a/absl/random/internal/mock_overload_set.h b/absl/random/internal/mock_overload_set.h
index c2a30d89..60561b51 100644
--- a/absl/random/internal/mock_overload_set.h
+++ b/absl/random/internal/mock_overload_set.h
@@ -20,6 +20,7 @@
#include "gmock/gmock.h"
#include "gtest/gtest.h"
+#include "absl/base/internal/fast_type_id.h"
#include "absl/random/mocking_bit_gen.h"
namespace absl {
@@ -35,17 +36,23 @@ struct MockSingleOverload;
// EXPECT_CALL(mock_single_overload, Call(...))` will expand to a call to
// `mock_single_overload.gmock_Call(...)`. Because expectations are stored on
// the MockingBitGen (an argument passed inside `Call(...)`), this forwards to
-// arguments to Mocking::Register.
+// arguments to MockingBitGen::Register.
template <typename DistrT, typename Ret, typename... Args>
struct MockSingleOverload<DistrT, Ret(MockingBitGen&, Args...)> {
static_assert(std::is_same<typename DistrT::result_type, Ret>::value,
"Overload signature must have return type matching the "
- "distributions result type.");
+ "distribution result_type.");
+ using ArgTupleT = std::tuple<Args...>;
auto gmock_Call(
absl::MockingBitGen& gen, // NOLINT(google-runtime-references)
- const ::testing::Matcher<Args>&... args)
- -> decltype(gen.Register<DistrT, Args...>(args...)) {
- return gen.Register<DistrT, Args...>(args...);
+ const ::testing::Matcher<Args>&... matchers)
+ -> decltype(gen.RegisterMock<Ret, ArgTupleT>(
+ std::declval<::absl::base_internal::FastTypeIdType>())
+ .gmock_Call(matchers...)) {
+ return gen
+ .RegisterMock<Ret, ArgTupleT>(
+ ::absl::base_internal::FastTypeId<Ret(DistrT, ArgTupleT)>())
+ .gmock_Call(matchers...);
}
};
@@ -53,13 +60,19 @@ template <typename DistrT, typename Ret, typename Arg, typename... Args>
struct MockSingleOverload<DistrT, Ret(Arg, MockingBitGen&, Args...)> {
static_assert(std::is_same<typename DistrT::result_type, Ret>::value,
"Overload signature must have return type matching the "
- "distributions result type.");
+ "distribution result_type.");
+ using ArgTupleT = std::tuple<Arg, Args...>;
auto gmock_Call(
- const ::testing::Matcher<Arg>& arg,
+ const ::testing::Matcher<Arg>& matcher,
absl::MockingBitGen& gen, // NOLINT(google-runtime-references)
- const ::testing::Matcher<Args>&... args)
- -> decltype(gen.Register<DistrT, Arg, Args...>(arg, args...)) {
- return gen.Register<DistrT, Arg, Args...>(arg, args...);
+ const ::testing::Matcher<Args>&... matchers)
+ -> decltype(gen.RegisterMock<Ret, ArgTupleT>(
+ std::declval<::absl::base_internal::FastTypeIdType>())
+ .gmock_Call(matcher, matchers...)) {
+ return gen
+ .RegisterMock<Ret, ArgTupleT>(
+ ::absl::base_internal::FastTypeId<Ret(DistrT, ArgTupleT)>())
+ .gmock_Call(matcher, matchers...);
}
};
diff --git a/absl/random/internal/mocking_bit_gen_base.h b/absl/random/internal/mocking_bit_gen_base.h
deleted file mode 100644
index 23ecaf6c..00000000
--- a/absl/random/internal/mocking_bit_gen_base.h
+++ /dev/null
@@ -1,85 +0,0 @@
-//
-// 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.
-//
-#ifndef ABSL_RANDOM_INTERNAL_MOCKING_BIT_GEN_BASE_H_
-#define ABSL_RANDOM_INTERNAL_MOCKING_BIT_GEN_BASE_H_
-
-#include <string>
-#include <typeinfo>
-
-#include "absl/random/random.h"
-#include "absl/strings/str_cat.h"
-
-namespace absl {
-ABSL_NAMESPACE_BEGIN
-namespace random_internal {
-
-class MockingBitGenBase {
- template <typename>
- friend struct DistributionCaller;
- using generator_type = absl::BitGen;
-
- public:
- // URBG interface
- using result_type = generator_type::result_type;
- static constexpr result_type(min)() { return (generator_type::min)(); }
- static constexpr result_type(max)() { return (generator_type::max)(); }
- result_type operator()() { return gen_(); }
-
- virtual ~MockingBitGenBase() = default;
-
- protected:
- // CallImpl is the type-erased virtual dispatch.
- // The type of dist is always distribution<T>,
- // The type of result is always distribution<T>::result_type.
- virtual bool CallImpl(const std::type_info& distr_type, void* dist_args,
- void* result) = 0;
-
- template <typename DistrT, typename ArgTupleT>
- static const std::type_info& GetTypeId() {
- return typeid(std::pair<absl::decay_t<DistrT>, absl::decay_t<ArgTupleT>>);
- }
-
- // Call the generating distribution function.
- // Invoked by DistributionCaller<>::Call<DistT>.
- // DistT is the distribution type.
- template <typename DistrT, typename... Args>
- typename DistrT::result_type Call(Args&&... args) {
- using distr_result_type = typename DistrT::result_type;
- using ArgTupleT = std::tuple<absl::decay_t<Args>...>;
-
- ArgTupleT arg_tuple(std::forward<Args>(args)...);
- auto dist = absl::make_from_tuple<DistrT>(arg_tuple);
-
- distr_result_type result{};
- bool found_match =
- CallImpl(GetTypeId<DistrT, ArgTupleT>(), &arg_tuple, &result);
-
- if (!found_match) {
- result = dist(gen_);
- }
-
- return result;
- }
-
- private:
- generator_type gen_;
-}; // namespace random_internal
-
-} // namespace random_internal
-ABSL_NAMESPACE_END
-} // namespace absl
-
-#endif // ABSL_RANDOM_INTERNAL_MOCKING_BIT_GEN_BASE_H_
diff --git a/absl/random/mock_distributions.h b/absl/random/mock_distributions.h
index d36d5ba0..764ab370 100644
--- a/absl/random/mock_distributions.h
+++ b/absl/random/mock_distributions.h
@@ -27,6 +27,11 @@
// More information about the Googletest testing framework is available at
// https://github.com/google/googletest
//
+// EXPECT_CALL and ON_CALL need to be made within the same DLL component as
+// the call to absl::Uniform and related methods, otherwise mocking will fail
+// since the underlying implementation creates a type-specific pointer which
+// will be distinct across different DLL boundaries.
+//
// Example:
//
// absl::MockingBitGen mock;
diff --git a/absl/random/mocking_bit_gen.h b/absl/random/mocking_bit_gen.h
index 3d8a979e..c3c7d44d 100644
--- a/absl/random/mocking_bit_gen.h
+++ b/absl/random/mocking_bit_gen.h
@@ -33,17 +33,16 @@
#include <memory>
#include <tuple>
#include <type_traits>
-#include <typeindex>
-#include <typeinfo>
#include <utility>
#include "gmock/gmock.h"
#include "gtest/gtest.h"
+#include "absl/base/internal/fast_type_id.h"
#include "absl/container/flat_hash_map.h"
#include "absl/meta/type_traits.h"
#include "absl/random/distributions.h"
#include "absl/random/internal/distribution_caller.h"
-#include "absl/random/internal/mocking_bit_gen_base.h"
+#include "absl/random/random.h"
#include "absl/strings/str_cat.h"
#include "absl/strings/str_join.h"
#include "absl/types/span.h"
@@ -54,11 +53,13 @@ namespace absl {
ABSL_NAMESPACE_BEGIN
namespace random_internal {
-
template <typename, typename>
struct MockSingleOverload;
+template <typename>
+struct DistributionCaller;
} // namespace random_internal
+class BitGenRef;
// MockingBitGen
//
@@ -96,102 +97,132 @@ struct MockSingleOverload;
// At this time, only mock distributions supplied within the Abseil random
// library are officially supported.
//
-class MockingBitGen : public absl::random_internal::MockingBitGenBase {
+// EXPECT_CALL and ON_CALL need to be made within the same DLL component as
+// the call to absl::Uniform and related methods, otherwise mocking will fail
+// since the underlying implementation creates a type-specific pointer which
+// will be distinct across different DLL boundaries.
+//
+class MockingBitGen {
public:
- MockingBitGen() {}
+ MockingBitGen() = default;
- ~MockingBitGen() override {
+ ~MockingBitGen() {
for (const auto& del : deleters_) del();
}
+ // URBG interface
+ using result_type = absl::BitGen::result_type;
+
+ static constexpr result_type(min)() { return (absl::BitGen::min)(); }
+ static constexpr result_type(max)() { return (absl::BitGen::max)(); }
+ result_type operator()() { return gen_(); }
+
private:
- template <typename DistrT, typename... Args>
- using MockFnType =
- ::testing::MockFunction<typename DistrT::result_type(Args...)>;
+ using match_impl_fn = void (*)(void* mock_fn, void* t_erased_arg_tuple,
+ void* t_erased_result);
- // MockingBitGen::Register
+ struct MockData {
+ void* mock_fn = nullptr;
+ match_impl_fn match_impl = nullptr;
+ };
+
+ // GetMockFnType returns the testing::MockFunction for a result and tuple.
+ // This method only exists for type deduction and is otherwise unimplemented.
+ template <typename ResultT, typename... Args>
+ static auto GetMockFnType(ResultT, std::tuple<Args...>)
+ -> ::testing::MockFunction<ResultT(Args...)>;
+
+ // MockFnCaller is a helper method for use with absl::apply to
+ // apply an ArgTupleT to a compatible MockFunction.
+ // NOTE: MockFnCaller is essentially equivalent to the lambda:
+ // [fn](auto... args) { return fn->Call(std::move(args)...)}
+ // however that fails to build on some supported platforms.
+ template <typename ResultT, typename MockFnType, typename Tuple>
+ struct MockFnCaller;
+ // specialization for std::tuple.
+ template <typename ResultT, typename MockFnType, typename... Args>
+ struct MockFnCaller<ResultT, MockFnType, std::tuple<Args...>> {
+ MockFnType* fn;
+ inline ResultT operator()(Args... args) {
+ return fn->Call(std::move(args)...);
+ }
+ };
+
+ // MockingBitGen::RegisterMock
//
- // Register<DistrT, FormatT, ArgTupleT> is the main extension point for
- // extending the MockingBitGen framework. It provides a mechanism to install a
- // mock expectation for the distribution `distr_t` onto the MockingBitGen
- // context.
+ // RegisterMock<ResultT, ArgTupleT>(FastTypeIdType) is the main extension
+ // point for extending the MockingBitGen framework. It provides a mechanism to
+ // install a mock expectation for a function like ResultT(Args...) keyed by
+ // type_idex onto the MockingBitGen context. The key is that the type_index
+ // used to register must match the type index used to call the mock.
//
// The returned MockFunction<...> type can be used to setup additional
// distribution parameters of the expectation.
- template <typename DistrT, typename... Args, typename... Ms>
- decltype(std::declval<MockFnType<DistrT, Args...>>().gmock_Call(
- std::declval<Ms>()...))
- Register(Ms&&... matchers) {
- auto& mock =
- mocks_[std::type_index(GetTypeId<DistrT, std::tuple<Args...>>())];
-
+ template <typename ResultT, typename ArgTupleT>
+ auto RegisterMock(base_internal::FastTypeIdType type)
+ -> decltype(GetMockFnType(std::declval<ResultT>(),
+ std::declval<ArgTupleT>()))& {
+ using MockFnType = decltype(
+ GetMockFnType(std::declval<ResultT>(), std::declval<ArgTupleT>()));
+ auto& mock = mocks_[type];
if (!mock.mock_fn) {
- auto* mock_fn = new MockFnType<DistrT, Args...>;
+ auto* mock_fn = new MockFnType;
mock.mock_fn = mock_fn;
- mock.match_impl = &MatchImpl<DistrT, Args...>;
+ mock.match_impl = &MatchImpl<ResultT, ArgTupleT>;
deleters_.emplace_back([mock_fn] { delete mock_fn; });
}
-
- return static_cast<MockFnType<DistrT, Args...>*>(mock.mock_fn)
- ->gmock_Call(std::forward<Ms>(matchers)...);
+ return *static_cast<MockFnType*>(mock.mock_fn);
}
- mutable std::vector<std::function<void()>> deleters_;
-
- using match_impl_fn = void (*)(void* mock_fn, void* t_erased_dist_args,
- void* t_erased_result);
- struct MockData {
- void* mock_fn = nullptr;
- match_impl_fn match_impl = nullptr;
- };
-
- mutable absl::flat_hash_map<std::type_index, MockData> mocks_;
-
- template <typename DistrT, typename... Args>
- static void MatchImpl(void* mock_fn, void* dist_args, void* result) {
- using result_type = typename DistrT::result_type;
- *static_cast<result_type*>(result) = absl::apply(
- [mock_fn](Args... args) -> result_type {
- return (*static_cast<MockFnType<DistrT, Args...>*>(mock_fn))
- .Call(std::move(args)...);
- },
- *static_cast<std::tuple<Args...>*>(dist_args));
+ // MockingBitGen::MatchImpl<> is a dispatch function which converts the
+ // generic type-erased parameters into a specific mock invocation call.
+ // Requires tuple_args to point to a ArgTupleT, which is a std::tuple<Args...>
+ // used to invoke the mock function.
+ // Requires result to point to a ResultT, which is the result of the call.
+ template <typename ResultT, typename ArgTupleT>
+ static void MatchImpl(/*MockFnType<ResultT, Args...>*/ void* mock_fn,
+ /*ArgTupleT*/ void* args_tuple,
+ /*ResultT*/ void* result) {
+ using MockFnType = decltype(
+ GetMockFnType(std::declval<ResultT>(), std::declval<ArgTupleT>()));
+ *static_cast<ResultT*>(result) = absl::apply(
+ MockFnCaller<ResultT, MockFnType, ArgTupleT>{
+ static_cast<MockFnType*>(mock_fn)},
+ *static_cast<ArgTupleT*>(args_tuple));
}
- // Looks for an appropriate mock - Returns the mocked result if one is found.
- // Otherwise, returns a random value generated by the underlying URBG.
- bool CallImpl(const std::type_info& key_type, void* dist_args,
- void* result) override {
+ // MockingBitGen::InvokeMock
+ //
+ // InvokeMock(FastTypeIdType, args, result) is the entrypoint for invoking
+ // mocks registered on MockingBitGen.
+ //
+ // When no mocks are registered on the provided FastTypeIdType, returns false.
+ // Otherwise attempts to invoke the mock function ResultT(Args...) that
+ // was previously registered via the type_index.
+ // Requires tuple_args to point to a ArgTupleT, which is a std::tuple<Args...>
+ // used to invoke the mock function.
+ // Requires result to point to a ResultT, which is the result of the call.
+ inline bool InvokeMock(base_internal::FastTypeIdType type, void* args_tuple,
+ void* result) {
// Trigger a mock, if there exists one that matches `param`.
- auto it = mocks_.find(std::type_index(key_type));
+ auto it = mocks_.find(type);
if (it == mocks_.end()) return false;
auto* mock_data = static_cast<MockData*>(&it->second);
- mock_data->match_impl(mock_data->mock_fn, dist_args, result);
+ mock_data->match_impl(mock_data->mock_fn, args_tuple, result);
return true;
}
- template <typename, typename>
- friend struct ::absl::random_internal::MockSingleOverload;
- friend struct ::absl::random_internal::DistributionCaller<
- absl::MockingBitGen>;
-};
+ absl::flat_hash_map<base_internal::FastTypeIdType, MockData> mocks_;
+ std::vector<std::function<void()>> deleters_;
+ absl::BitGen gen_;
-// -----------------------------------------------------------------------------
-// Implementation Details Only Below
-// -----------------------------------------------------------------------------
-
-namespace random_internal {
-
-template <>
-struct DistributionCaller<absl::MockingBitGen> {
- template <typename DistrT, typename... Args>
- static typename DistrT::result_type Call(absl::MockingBitGen* gen,
- Args&&... args) {
- return gen->template Call<DistrT>(std::forward<Args>(args)...);
- }
+ template <typename, typename>
+ friend struct ::absl::random_internal::MockSingleOverload; // for Register
+ template <typename>
+ friend struct ::absl::random_internal::DistributionCaller; // for InvokeMock
+ friend class ::absl::BitGenRef; // for InvokeMock
};
-} // namespace random_internal
ABSL_NAMESPACE_END
} // namespace absl