Add files using upload-large-folder tool
Browse filesThis view is limited to 50 files because it contains too many changes. See raw diff
- weight/_dep/abseil-cpp/absl/cleanup/BUILD.bazel +73 -0
- weight/_dep/abseil-cpp/absl/cleanup/cleanup.h +140 -0
- weight/_dep/abseil-cpp/absl/cleanup/cleanup_test.cc +311 -0
- weight/_dep/abseil-cpp/absl/cleanup/internal/cleanup.h +100 -0
- weight/_dep/abseil-cpp/absl/copts/GENERATED_copts.bzl +230 -0
- weight/_dep/abseil-cpp/absl/copts/configure_copts.bzl +82 -0
- weight/_dep/abseil-cpp/absl/copts/copts.py +191 -0
- weight/_dep/abseil-cpp/absl/copts/generate_copts.py +109 -0
- weight/_dep/abseil-cpp/absl/flags/BUILD.bazel +601 -0
- weight/_dep/abseil-cpp/absl/flags/CMakeLists.txt +471 -0
- weight/_dep/abseil-cpp/absl/flags/commandlineflag.cc +34 -0
- weight/_dep/abseil-cpp/absl/flags/commandlineflag.h +200 -0
- weight/_dep/abseil-cpp/absl/flags/commandlineflag_test.cc +231 -0
- weight/_dep/abseil-cpp/absl/flags/config.h +68 -0
- weight/_dep/abseil-cpp/absl/flags/config_test.cc +61 -0
- weight/_dep/abseil-cpp/absl/flags/declare.h +68 -0
- weight/_dep/abseil-cpp/absl/flags/flag.h +301 -0
- weight/_dep/abseil-cpp/absl/flags/flag_benchmark.cc +251 -0
- weight/_dep/abseil-cpp/absl/flags/flag_benchmark.lds +13 -0
- weight/_dep/abseil-cpp/absl/flags/flag_test.cc +1217 -0
- weight/_dep/abseil-cpp/absl/flags/flag_test_defs.cc +24 -0
- weight/_dep/abseil-cpp/absl/flags/internal/commandlineflag.h +68 -0
- weight/_dep/abseil-cpp/absl/flags/internal/flag.h +796 -0
- weight/_dep/abseil-cpp/absl/flags/marshalling.cc +291 -0
- weight/_dep/abseil-cpp/absl/flags/parse.cc +943 -0
- weight/_dep/abseil-cpp/absl/flags/parse.h +130 -0
- weight/_dep/abseil-cpp/absl/flags/parse_test.cc +1087 -0
- weight/_dep/abseil-cpp/absl/flags/reflection.h +90 -0
- weight/_dep/abseil-cpp/absl/flags/reflection_test.cc +265 -0
- weight/_dep/abseil-cpp/absl/flags/usage.cc +66 -0
- weight/_dep/abseil-cpp/absl/flags/usage_config.cc +165 -0
- weight/_dep/abseil-cpp/absl/flags/usage_config.h +135 -0
- weight/_dep/abseil-cpp/absl/flags/usage_config_test.cc +205 -0
- weight/_dep/abseil-cpp/absl/strings/cord_test.cc +0 -0
- weight/_dep/abseil-cpp/absl/strings/escaping.cc +957 -0
- weight/_dep/abseil-cpp/absl/strings/escaping_test.cc +714 -0
- weight/_dep/abseil-cpp/absl/strings/has_ostream_operator_test.cc +41 -0
- weight/_dep/abseil-cpp/absl/strings/internal/charconv_bigint.h +423 -0
- weight/_dep/abseil-cpp/absl/strings/internal/charconv_bigint_test.cc +260 -0
- weight/_dep/abseil-cpp/absl/strings/internal/charconv_parse_test.cc +357 -0
- weight/_dep/abseil-cpp/absl/strings/internal/cord_data_edge_test.cc +130 -0
- weight/_dep/abseil-cpp/absl/strings/internal/cord_rep_btree.cc +1241 -0
- weight/_dep/abseil-cpp/absl/strings/internal/cord_rep_btree_navigator.cc +187 -0
- weight/_dep/abseil-cpp/absl/strings/internal/cord_rep_btree_navigator.h +267 -0
- weight/_dep/abseil-cpp/absl/strings/internal/cord_rep_btree_reader.cc +69 -0
- weight/_dep/abseil-cpp/absl/strings/internal/cord_rep_btree_reader.h +212 -0
- weight/_dep/abseil-cpp/absl/strings/internal/cord_rep_btree_reader_test.cc +293 -0
- weight/_dep/abseil-cpp/absl/strings/internal/cord_rep_btree_test.cc +1568 -0
- weight/_dep/abseil-cpp/absl/strings/internal/cord_rep_consume.h +47 -0
- weight/_dep/abseil-cpp/absl/strings/internal/cord_rep_crc.cc +56 -0
weight/_dep/abseil-cpp/absl/cleanup/BUILD.bazel
ADDED
|
@@ -0,0 +1,73 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Copyright 2021 The Abseil Authors.
|
| 2 |
+
#
|
| 3 |
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
| 4 |
+
# you may not use this file except in compliance with the License.
|
| 5 |
+
# You may obtain a copy of the License at
|
| 6 |
+
#
|
| 7 |
+
# https://www.apache.org/licenses/LICENSE-2.0
|
| 8 |
+
#
|
| 9 |
+
# Unless required by applicable law or agreed to in writing, software
|
| 10 |
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
| 11 |
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
| 12 |
+
# See the License for the specific language governing permissions and
|
| 13 |
+
# limitations under the License.
|
| 14 |
+
|
| 15 |
+
load(
|
| 16 |
+
"//absl:copts/configure_copts.bzl",
|
| 17 |
+
"ABSL_DEFAULT_COPTS",
|
| 18 |
+
"ABSL_DEFAULT_LINKOPTS",
|
| 19 |
+
"ABSL_TEST_COPTS",
|
| 20 |
+
)
|
| 21 |
+
|
| 22 |
+
package(
|
| 23 |
+
default_visibility = ["//visibility:public"],
|
| 24 |
+
features = [
|
| 25 |
+
"header_modules",
|
| 26 |
+
"layering_check",
|
| 27 |
+
"parse_headers",
|
| 28 |
+
],
|
| 29 |
+
)
|
| 30 |
+
|
| 31 |
+
licenses(["notice"])
|
| 32 |
+
|
| 33 |
+
cc_library(
|
| 34 |
+
name = "cleanup_internal",
|
| 35 |
+
hdrs = ["internal/cleanup.h"],
|
| 36 |
+
copts = ABSL_DEFAULT_COPTS,
|
| 37 |
+
linkopts = ABSL_DEFAULT_LINKOPTS,
|
| 38 |
+
deps = [
|
| 39 |
+
"//absl/base:base_internal",
|
| 40 |
+
"//absl/base:core_headers",
|
| 41 |
+
"//absl/utility",
|
| 42 |
+
],
|
| 43 |
+
)
|
| 44 |
+
|
| 45 |
+
cc_library(
|
| 46 |
+
name = "cleanup",
|
| 47 |
+
hdrs = [
|
| 48 |
+
"cleanup.h",
|
| 49 |
+
],
|
| 50 |
+
copts = ABSL_DEFAULT_COPTS,
|
| 51 |
+
linkopts = ABSL_DEFAULT_LINKOPTS,
|
| 52 |
+
deps = [
|
| 53 |
+
":cleanup_internal",
|
| 54 |
+
"//absl/base:config",
|
| 55 |
+
"//absl/base:core_headers",
|
| 56 |
+
],
|
| 57 |
+
)
|
| 58 |
+
|
| 59 |
+
cc_test(
|
| 60 |
+
name = "cleanup_test",
|
| 61 |
+
size = "small",
|
| 62 |
+
srcs = [
|
| 63 |
+
"cleanup_test.cc",
|
| 64 |
+
],
|
| 65 |
+
copts = ABSL_TEST_COPTS,
|
| 66 |
+
deps = [
|
| 67 |
+
":cleanup",
|
| 68 |
+
"//absl/base:config",
|
| 69 |
+
"//absl/utility",
|
| 70 |
+
"@com_google_googletest//:gtest",
|
| 71 |
+
"@com_google_googletest//:gtest_main",
|
| 72 |
+
],
|
| 73 |
+
)
|
weight/_dep/abseil-cpp/absl/cleanup/cleanup.h
ADDED
|
@@ -0,0 +1,140 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
// Copyright 2021 The Abseil Authors.
|
| 2 |
+
//
|
| 3 |
+
// Licensed under the Apache License, Version 2.0 (the "License");
|
| 4 |
+
// you may not use this file except in compliance with the License.
|
| 5 |
+
// You may obtain a copy of the License at
|
| 6 |
+
//
|
| 7 |
+
// https://www.apache.org/licenses/LICENSE-2.0
|
| 8 |
+
//
|
| 9 |
+
// Unless required by applicable law or agreed to in writing, software
|
| 10 |
+
// distributed under the License is distributed on an "AS IS" BASIS,
|
| 11 |
+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
| 12 |
+
// See the License for the specific language governing permissions and
|
| 13 |
+
// limitations under the License.
|
| 14 |
+
//
|
| 15 |
+
// -----------------------------------------------------------------------------
|
| 16 |
+
// File: cleanup.h
|
| 17 |
+
// -----------------------------------------------------------------------------
|
| 18 |
+
//
|
| 19 |
+
// `absl::Cleanup` implements the scope guard idiom, invoking the contained
|
| 20 |
+
// callback's `operator()() &&` on scope exit.
|
| 21 |
+
//
|
| 22 |
+
// Example:
|
| 23 |
+
//
|
| 24 |
+
// ```
|
| 25 |
+
// absl::Status CopyGoodData(const char* source_path, const char* sink_path) {
|
| 26 |
+
// FILE* source_file = fopen(source_path, "r");
|
| 27 |
+
// if (source_file == nullptr) {
|
| 28 |
+
// return absl::NotFoundError("No source file"); // No cleanups execute
|
| 29 |
+
// }
|
| 30 |
+
//
|
| 31 |
+
// // C++17 style cleanup using class template argument deduction
|
| 32 |
+
// absl::Cleanup source_closer = [source_file] { fclose(source_file); };
|
| 33 |
+
//
|
| 34 |
+
// FILE* sink_file = fopen(sink_path, "w");
|
| 35 |
+
// if (sink_file == nullptr) {
|
| 36 |
+
// return absl::NotFoundError("No sink file"); // First cleanup executes
|
| 37 |
+
// }
|
| 38 |
+
//
|
| 39 |
+
// // C++11 style cleanup using the factory function
|
| 40 |
+
// auto sink_closer = absl::MakeCleanup([sink_file] { fclose(sink_file); });
|
| 41 |
+
//
|
| 42 |
+
// Data data;
|
| 43 |
+
// while (ReadData(source_file, &data)) {
|
| 44 |
+
// if (!data.IsGood()) {
|
| 45 |
+
// absl::Status result = absl::FailedPreconditionError("Read bad data");
|
| 46 |
+
// return result; // Both cleanups execute
|
| 47 |
+
// }
|
| 48 |
+
// SaveData(sink_file, &data);
|
| 49 |
+
// }
|
| 50 |
+
//
|
| 51 |
+
// return absl::OkStatus(); // Both cleanups execute
|
| 52 |
+
// }
|
| 53 |
+
// ```
|
| 54 |
+
//
|
| 55 |
+
// Methods:
|
| 56 |
+
//
|
| 57 |
+
// `std::move(cleanup).Cancel()` will prevent the callback from executing.
|
| 58 |
+
//
|
| 59 |
+
// `std::move(cleanup).Invoke()` will execute the callback early, before
|
| 60 |
+
// destruction, and prevent the callback from executing in the destructor.
|
| 61 |
+
//
|
| 62 |
+
// Usage:
|
| 63 |
+
//
|
| 64 |
+
// `absl::Cleanup` is not an interface type. It is only intended to be used
|
| 65 |
+
// within the body of a function. It is not a value type and instead models a
|
| 66 |
+
// control flow construct. Check out `defer` in Golang for something similar.
|
| 67 |
+
|
| 68 |
+
#ifndef ABSL_CLEANUP_CLEANUP_H_
|
| 69 |
+
#define ABSL_CLEANUP_CLEANUP_H_
|
| 70 |
+
|
| 71 |
+
#include <utility>
|
| 72 |
+
|
| 73 |
+
#include "absl/base/config.h"
|
| 74 |
+
#include "absl/base/macros.h"
|
| 75 |
+
#include "absl/cleanup/internal/cleanup.h"
|
| 76 |
+
|
| 77 |
+
namespace absl {
|
| 78 |
+
ABSL_NAMESPACE_BEGIN
|
| 79 |
+
|
| 80 |
+
template <typename Arg, typename Callback = void()>
|
| 81 |
+
class ABSL_MUST_USE_RESULT Cleanup final {
|
| 82 |
+
static_assert(cleanup_internal::WasDeduced<Arg>(),
|
| 83 |
+
"Explicit template parameters are not supported.");
|
| 84 |
+
|
| 85 |
+
static_assert(cleanup_internal::ReturnsVoid<Callback>(),
|
| 86 |
+
"Callbacks that return values are not supported.");
|
| 87 |
+
|
| 88 |
+
public:
|
| 89 |
+
Cleanup(Callback callback) : storage_(std::move(callback)) {} // NOLINT
|
| 90 |
+
|
| 91 |
+
Cleanup(Cleanup&& other) = default;
|
| 92 |
+
|
| 93 |
+
void Cancel() && {
|
| 94 |
+
ABSL_HARDENING_ASSERT(storage_.IsCallbackEngaged());
|
| 95 |
+
storage_.DestroyCallback();
|
| 96 |
+
}
|
| 97 |
+
|
| 98 |
+
void Invoke() && {
|
| 99 |
+
ABSL_HARDENING_ASSERT(storage_.IsCallbackEngaged());
|
| 100 |
+
storage_.InvokeCallback();
|
| 101 |
+
storage_.DestroyCallback();
|
| 102 |
+
}
|
| 103 |
+
|
| 104 |
+
~Cleanup() {
|
| 105 |
+
if (storage_.IsCallbackEngaged()) {
|
| 106 |
+
storage_.InvokeCallback();
|
| 107 |
+
storage_.DestroyCallback();
|
| 108 |
+
}
|
| 109 |
+
}
|
| 110 |
+
|
| 111 |
+
private:
|
| 112 |
+
cleanup_internal::Storage<Callback> storage_;
|
| 113 |
+
};
|
| 114 |
+
|
| 115 |
+
// `absl::Cleanup c = /* callback */;`
|
| 116 |
+
//
|
| 117 |
+
// C++17 type deduction API for creating an instance of `absl::Cleanup`
|
| 118 |
+
#if defined(ABSL_HAVE_CLASS_TEMPLATE_ARGUMENT_DEDUCTION)
|
| 119 |
+
template <typename Callback>
|
| 120 |
+
Cleanup(Callback callback) -> Cleanup<cleanup_internal::Tag, Callback>;
|
| 121 |
+
#endif // defined(ABSL_HAVE_CLASS_TEMPLATE_ARGUMENT_DEDUCTION)
|
| 122 |
+
|
| 123 |
+
// `auto c = absl::MakeCleanup(/* callback */);`
|
| 124 |
+
//
|
| 125 |
+
// C++11 type deduction API for creating an instance of `absl::Cleanup`
|
| 126 |
+
template <typename... Args, typename Callback>
|
| 127 |
+
absl::Cleanup<cleanup_internal::Tag, Callback> MakeCleanup(Callback callback) {
|
| 128 |
+
static_assert(cleanup_internal::WasDeduced<cleanup_internal::Tag, Args...>(),
|
| 129 |
+
"Explicit template parameters are not supported.");
|
| 130 |
+
|
| 131 |
+
static_assert(cleanup_internal::ReturnsVoid<Callback>(),
|
| 132 |
+
"Callbacks that return values are not supported.");
|
| 133 |
+
|
| 134 |
+
return {std::move(callback)};
|
| 135 |
+
}
|
| 136 |
+
|
| 137 |
+
ABSL_NAMESPACE_END
|
| 138 |
+
} // namespace absl
|
| 139 |
+
|
| 140 |
+
#endif // ABSL_CLEANUP_CLEANUP_H_
|
weight/_dep/abseil-cpp/absl/cleanup/cleanup_test.cc
ADDED
|
@@ -0,0 +1,311 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
// Copyright 2021 The Abseil Authors.
|
| 2 |
+
//
|
| 3 |
+
// Licensed under the Apache License, Version 2.0 (the "License");
|
| 4 |
+
// you may not use this file except in compliance with the License.
|
| 5 |
+
// You may obtain a copy of the License at
|
| 6 |
+
//
|
| 7 |
+
// https://www.apache.org/licenses/LICENSE-2.0
|
| 8 |
+
//
|
| 9 |
+
// Unless required by applicable law or agreed to in writing, software
|
| 10 |
+
// distributed under the License is distributed on an "AS IS" BASIS,
|
| 11 |
+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
| 12 |
+
// See the License for the specific language governing permissions and
|
| 13 |
+
// limitations under the License.
|
| 14 |
+
|
| 15 |
+
#include "absl/cleanup/cleanup.h"
|
| 16 |
+
|
| 17 |
+
#include <functional>
|
| 18 |
+
#include <type_traits>
|
| 19 |
+
#include <utility>
|
| 20 |
+
|
| 21 |
+
#include "gtest/gtest.h"
|
| 22 |
+
#include "absl/base/config.h"
|
| 23 |
+
#include "absl/utility/utility.h"
|
| 24 |
+
|
| 25 |
+
namespace {
|
| 26 |
+
|
| 27 |
+
using Tag = absl::cleanup_internal::Tag;
|
| 28 |
+
|
| 29 |
+
template <typename Type1, typename Type2>
|
| 30 |
+
constexpr bool IsSame() {
|
| 31 |
+
return (std::is_same<Type1, Type2>::value);
|
| 32 |
+
}
|
| 33 |
+
|
| 34 |
+
struct IdentityFactory {
|
| 35 |
+
template <typename Callback>
|
| 36 |
+
static Callback AsCallback(Callback callback) {
|
| 37 |
+
return Callback(std::move(callback));
|
| 38 |
+
}
|
| 39 |
+
};
|
| 40 |
+
|
| 41 |
+
// `FunctorClass` is a type used for testing `absl::Cleanup`. It is intended to
|
| 42 |
+
// represent users that make their own move-only callback types outside of
|
| 43 |
+
// `std::function` and lambda literals.
|
| 44 |
+
class FunctorClass {
|
| 45 |
+
using Callback = std::function<void()>;
|
| 46 |
+
|
| 47 |
+
public:
|
| 48 |
+
explicit FunctorClass(Callback callback) : callback_(std::move(callback)) {}
|
| 49 |
+
|
| 50 |
+
FunctorClass(FunctorClass&& other)
|
| 51 |
+
: callback_(absl::exchange(other.callback_, Callback())) {}
|
| 52 |
+
|
| 53 |
+
FunctorClass(const FunctorClass&) = delete;
|
| 54 |
+
|
| 55 |
+
FunctorClass& operator=(const FunctorClass&) = delete;
|
| 56 |
+
|
| 57 |
+
FunctorClass& operator=(FunctorClass&&) = delete;
|
| 58 |
+
|
| 59 |
+
void operator()() const& = delete;
|
| 60 |
+
|
| 61 |
+
void operator()() && {
|
| 62 |
+
ASSERT_TRUE(callback_);
|
| 63 |
+
callback_();
|
| 64 |
+
callback_ = nullptr;
|
| 65 |
+
}
|
| 66 |
+
|
| 67 |
+
private:
|
| 68 |
+
Callback callback_;
|
| 69 |
+
};
|
| 70 |
+
|
| 71 |
+
struct FunctorClassFactory {
|
| 72 |
+
template <typename Callback>
|
| 73 |
+
static FunctorClass AsCallback(Callback callback) {
|
| 74 |
+
return FunctorClass(std::move(callback));
|
| 75 |
+
}
|
| 76 |
+
};
|
| 77 |
+
|
| 78 |
+
struct StdFunctionFactory {
|
| 79 |
+
template <typename Callback>
|
| 80 |
+
static std::function<void()> AsCallback(Callback callback) {
|
| 81 |
+
return std::function<void()>(std::move(callback));
|
| 82 |
+
}
|
| 83 |
+
};
|
| 84 |
+
|
| 85 |
+
using CleanupTestParams =
|
| 86 |
+
::testing::Types<IdentityFactory, FunctorClassFactory, StdFunctionFactory>;
|
| 87 |
+
template <typename>
|
| 88 |
+
struct CleanupTest : public ::testing::Test {};
|
| 89 |
+
TYPED_TEST_SUITE(CleanupTest, CleanupTestParams);
|
| 90 |
+
|
| 91 |
+
bool fn_ptr_called = false;
|
| 92 |
+
void FnPtrFunction() { fn_ptr_called = true; }
|
| 93 |
+
|
| 94 |
+
TYPED_TEST(CleanupTest, FactoryProducesCorrectType) {
|
| 95 |
+
{
|
| 96 |
+
auto callback = TypeParam::AsCallback([] {});
|
| 97 |
+
auto cleanup = absl::MakeCleanup(std::move(callback));
|
| 98 |
+
|
| 99 |
+
static_assert(
|
| 100 |
+
IsSame<absl::Cleanup<Tag, decltype(callback)>, decltype(cleanup)>(),
|
| 101 |
+
"");
|
| 102 |
+
}
|
| 103 |
+
|
| 104 |
+
{
|
| 105 |
+
auto cleanup = absl::MakeCleanup(&FnPtrFunction);
|
| 106 |
+
|
| 107 |
+
static_assert(IsSame<absl::Cleanup<Tag, void (*)()>, decltype(cleanup)>(),
|
| 108 |
+
"");
|
| 109 |
+
}
|
| 110 |
+
|
| 111 |
+
{
|
| 112 |
+
auto cleanup = absl::MakeCleanup(FnPtrFunction);
|
| 113 |
+
|
| 114 |
+
static_assert(IsSame<absl::Cleanup<Tag, void (*)()>, decltype(cleanup)>(),
|
| 115 |
+
"");
|
| 116 |
+
}
|
| 117 |
+
}
|
| 118 |
+
|
| 119 |
+
#if defined(ABSL_HAVE_CLASS_TEMPLATE_ARGUMENT_DEDUCTION)
|
| 120 |
+
TYPED_TEST(CleanupTest, CTADProducesCorrectType) {
|
| 121 |
+
{
|
| 122 |
+
auto callback = TypeParam::AsCallback([] {});
|
| 123 |
+
absl::Cleanup cleanup = std::move(callback);
|
| 124 |
+
|
| 125 |
+
static_assert(
|
| 126 |
+
IsSame<absl::Cleanup<Tag, decltype(callback)>, decltype(cleanup)>(),
|
| 127 |
+
"");
|
| 128 |
+
}
|
| 129 |
+
|
| 130 |
+
{
|
| 131 |
+
absl::Cleanup cleanup = &FnPtrFunction;
|
| 132 |
+
|
| 133 |
+
static_assert(IsSame<absl::Cleanup<Tag, void (*)()>, decltype(cleanup)>(),
|
| 134 |
+
"");
|
| 135 |
+
}
|
| 136 |
+
|
| 137 |
+
{
|
| 138 |
+
absl::Cleanup cleanup = FnPtrFunction;
|
| 139 |
+
|
| 140 |
+
static_assert(IsSame<absl::Cleanup<Tag, void (*)()>, decltype(cleanup)>(),
|
| 141 |
+
"");
|
| 142 |
+
}
|
| 143 |
+
}
|
| 144 |
+
|
| 145 |
+
TYPED_TEST(CleanupTest, FactoryAndCTADProduceSameType) {
|
| 146 |
+
{
|
| 147 |
+
auto callback = IdentityFactory::AsCallback([] {});
|
| 148 |
+
auto factory_cleanup = absl::MakeCleanup(callback);
|
| 149 |
+
absl::Cleanup deduction_cleanup = callback;
|
| 150 |
+
|
| 151 |
+
static_assert(
|
| 152 |
+
IsSame<decltype(factory_cleanup), decltype(deduction_cleanup)>(), "");
|
| 153 |
+
}
|
| 154 |
+
|
| 155 |
+
{
|
| 156 |
+
auto factory_cleanup =
|
| 157 |
+
absl::MakeCleanup(FunctorClassFactory::AsCallback([] {}));
|
| 158 |
+
absl::Cleanup deduction_cleanup = FunctorClassFactory::AsCallback([] {});
|
| 159 |
+
|
| 160 |
+
static_assert(
|
| 161 |
+
IsSame<decltype(factory_cleanup), decltype(deduction_cleanup)>(), "");
|
| 162 |
+
}
|
| 163 |
+
|
| 164 |
+
{
|
| 165 |
+
auto factory_cleanup =
|
| 166 |
+
absl::MakeCleanup(StdFunctionFactory::AsCallback([] {}));
|
| 167 |
+
absl::Cleanup deduction_cleanup = StdFunctionFactory::AsCallback([] {});
|
| 168 |
+
|
| 169 |
+
static_assert(
|
| 170 |
+
IsSame<decltype(factory_cleanup), decltype(deduction_cleanup)>(), "");
|
| 171 |
+
}
|
| 172 |
+
|
| 173 |
+
{
|
| 174 |
+
auto factory_cleanup = absl::MakeCleanup(&FnPtrFunction);
|
| 175 |
+
absl::Cleanup deduction_cleanup = &FnPtrFunction;
|
| 176 |
+
|
| 177 |
+
static_assert(
|
| 178 |
+
IsSame<decltype(factory_cleanup), decltype(deduction_cleanup)>(), "");
|
| 179 |
+
}
|
| 180 |
+
|
| 181 |
+
{
|
| 182 |
+
auto factory_cleanup = absl::MakeCleanup(FnPtrFunction);
|
| 183 |
+
absl::Cleanup deduction_cleanup = FnPtrFunction;
|
| 184 |
+
|
| 185 |
+
static_assert(
|
| 186 |
+
IsSame<decltype(factory_cleanup), decltype(deduction_cleanup)>(), "");
|
| 187 |
+
}
|
| 188 |
+
}
|
| 189 |
+
#endif // defined(ABSL_HAVE_CLASS_TEMPLATE_ARGUMENT_DEDUCTION)
|
| 190 |
+
|
| 191 |
+
TYPED_TEST(CleanupTest, BasicUsage) {
|
| 192 |
+
bool called = false;
|
| 193 |
+
|
| 194 |
+
{
|
| 195 |
+
auto cleanup =
|
| 196 |
+
absl::MakeCleanup(TypeParam::AsCallback([&called] { called = true; }));
|
| 197 |
+
EXPECT_FALSE(called); // Constructor shouldn't invoke the callback
|
| 198 |
+
}
|
| 199 |
+
|
| 200 |
+
EXPECT_TRUE(called); // Destructor should invoke the callback
|
| 201 |
+
}
|
| 202 |
+
|
| 203 |
+
TYPED_TEST(CleanupTest, BasicUsageWithFunctionPointer) {
|
| 204 |
+
fn_ptr_called = false;
|
| 205 |
+
|
| 206 |
+
{
|
| 207 |
+
auto cleanup = absl::MakeCleanup(TypeParam::AsCallback(&FnPtrFunction));
|
| 208 |
+
EXPECT_FALSE(fn_ptr_called); // Constructor shouldn't invoke the callback
|
| 209 |
+
}
|
| 210 |
+
|
| 211 |
+
EXPECT_TRUE(fn_ptr_called); // Destructor should invoke the callback
|
| 212 |
+
}
|
| 213 |
+
|
| 214 |
+
TYPED_TEST(CleanupTest, Cancel) {
|
| 215 |
+
bool called = false;
|
| 216 |
+
|
| 217 |
+
{
|
| 218 |
+
auto cleanup =
|
| 219 |
+
absl::MakeCleanup(TypeParam::AsCallback([&called] { called = true; }));
|
| 220 |
+
EXPECT_FALSE(called); // Constructor shouldn't invoke the callback
|
| 221 |
+
|
| 222 |
+
std::move(cleanup).Cancel();
|
| 223 |
+
EXPECT_FALSE(called); // Cancel shouldn't invoke the callback
|
| 224 |
+
}
|
| 225 |
+
|
| 226 |
+
EXPECT_FALSE(called); // Destructor shouldn't invoke the callback
|
| 227 |
+
}
|
| 228 |
+
|
| 229 |
+
TYPED_TEST(CleanupTest, Invoke) {
|
| 230 |
+
bool called = false;
|
| 231 |
+
|
| 232 |
+
{
|
| 233 |
+
auto cleanup =
|
| 234 |
+
absl::MakeCleanup(TypeParam::AsCallback([&called] { called = true; }));
|
| 235 |
+
EXPECT_FALSE(called); // Constructor shouldn't invoke the callback
|
| 236 |
+
|
| 237 |
+
std::move(cleanup).Invoke();
|
| 238 |
+
EXPECT_TRUE(called); // Invoke should invoke the callback
|
| 239 |
+
|
| 240 |
+
called = false; // Reset tracker before destructor runs
|
| 241 |
+
}
|
| 242 |
+
|
| 243 |
+
EXPECT_FALSE(called); // Destructor shouldn't invoke the callback
|
| 244 |
+
}
|
| 245 |
+
|
| 246 |
+
TYPED_TEST(CleanupTest, Move) {
|
| 247 |
+
bool called = false;
|
| 248 |
+
|
| 249 |
+
{
|
| 250 |
+
auto moved_from_cleanup =
|
| 251 |
+
absl::MakeCleanup(TypeParam::AsCallback([&called] { called = true; }));
|
| 252 |
+
EXPECT_FALSE(called); // Constructor shouldn't invoke the callback
|
| 253 |
+
|
| 254 |
+
{
|
| 255 |
+
auto moved_to_cleanup = std::move(moved_from_cleanup);
|
| 256 |
+
EXPECT_FALSE(called); // Move shouldn't invoke the callback
|
| 257 |
+
}
|
| 258 |
+
|
| 259 |
+
EXPECT_TRUE(called); // Destructor should invoke the callback
|
| 260 |
+
|
| 261 |
+
called = false; // Reset tracker before destructor runs
|
| 262 |
+
}
|
| 263 |
+
|
| 264 |
+
EXPECT_FALSE(called); // Destructor shouldn't invoke the callback
|
| 265 |
+
}
|
| 266 |
+
|
| 267 |
+
int DestructionCount = 0;
|
| 268 |
+
|
| 269 |
+
struct DestructionCounter {
|
| 270 |
+
void operator()() {}
|
| 271 |
+
|
| 272 |
+
~DestructionCounter() { ++DestructionCount; }
|
| 273 |
+
};
|
| 274 |
+
|
| 275 |
+
TYPED_TEST(CleanupTest, DestructorDestroys) {
|
| 276 |
+
{
|
| 277 |
+
auto cleanup =
|
| 278 |
+
absl::MakeCleanup(TypeParam::AsCallback(DestructionCounter()));
|
| 279 |
+
DestructionCount = 0;
|
| 280 |
+
}
|
| 281 |
+
|
| 282 |
+
EXPECT_EQ(DestructionCount, 1); // Engaged cleanup destroys
|
| 283 |
+
}
|
| 284 |
+
|
| 285 |
+
TYPED_TEST(CleanupTest, CancelDestroys) {
|
| 286 |
+
{
|
| 287 |
+
auto cleanup =
|
| 288 |
+
absl::MakeCleanup(TypeParam::AsCallback(DestructionCounter()));
|
| 289 |
+
DestructionCount = 0;
|
| 290 |
+
|
| 291 |
+
std::move(cleanup).Cancel();
|
| 292 |
+
EXPECT_EQ(DestructionCount, 1); // Cancel destroys
|
| 293 |
+
}
|
| 294 |
+
|
| 295 |
+
EXPECT_EQ(DestructionCount, 1); // Canceled cleanup does not double destroy
|
| 296 |
+
}
|
| 297 |
+
|
| 298 |
+
TYPED_TEST(CleanupTest, InvokeDestroys) {
|
| 299 |
+
{
|
| 300 |
+
auto cleanup =
|
| 301 |
+
absl::MakeCleanup(TypeParam::AsCallback(DestructionCounter()));
|
| 302 |
+
DestructionCount = 0;
|
| 303 |
+
|
| 304 |
+
std::move(cleanup).Invoke();
|
| 305 |
+
EXPECT_EQ(DestructionCount, 1); // Invoke destroys
|
| 306 |
+
}
|
| 307 |
+
|
| 308 |
+
EXPECT_EQ(DestructionCount, 1); // Invoked cleanup does not double destroy
|
| 309 |
+
}
|
| 310 |
+
|
| 311 |
+
} // namespace
|
weight/_dep/abseil-cpp/absl/cleanup/internal/cleanup.h
ADDED
|
@@ -0,0 +1,100 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
// Copyright 2021 The Abseil Authors.
|
| 2 |
+
//
|
| 3 |
+
// Licensed under the Apache License, Version 2.0 (the "License");
|
| 4 |
+
// you may not use this file except in compliance with the License.
|
| 5 |
+
// You may obtain a copy of the License at
|
| 6 |
+
//
|
| 7 |
+
// https://www.apache.org/licenses/LICENSE-2.0
|
| 8 |
+
//
|
| 9 |
+
// Unless required by applicable law or agreed to in writing, software
|
| 10 |
+
// distributed under the License is distributed on an "AS IS" BASIS,
|
| 11 |
+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
| 12 |
+
// See the License for the specific language governing permissions and
|
| 13 |
+
// limitations under the License.
|
| 14 |
+
|
| 15 |
+
#ifndef ABSL_CLEANUP_INTERNAL_CLEANUP_H_
|
| 16 |
+
#define ABSL_CLEANUP_INTERNAL_CLEANUP_H_
|
| 17 |
+
|
| 18 |
+
#include <new>
|
| 19 |
+
#include <type_traits>
|
| 20 |
+
#include <utility>
|
| 21 |
+
|
| 22 |
+
#include "absl/base/internal/invoke.h"
|
| 23 |
+
#include "absl/base/macros.h"
|
| 24 |
+
#include "absl/base/thread_annotations.h"
|
| 25 |
+
#include "absl/utility/utility.h"
|
| 26 |
+
|
| 27 |
+
namespace absl {
|
| 28 |
+
ABSL_NAMESPACE_BEGIN
|
| 29 |
+
|
| 30 |
+
namespace cleanup_internal {
|
| 31 |
+
|
| 32 |
+
struct Tag {};
|
| 33 |
+
|
| 34 |
+
template <typename Arg, typename... Args>
|
| 35 |
+
constexpr bool WasDeduced() {
|
| 36 |
+
return (std::is_same<cleanup_internal::Tag, Arg>::value) &&
|
| 37 |
+
(sizeof...(Args) == 0);
|
| 38 |
+
}
|
| 39 |
+
|
| 40 |
+
template <typename Callback>
|
| 41 |
+
constexpr bool ReturnsVoid() {
|
| 42 |
+
return (std::is_same<base_internal::invoke_result_t<Callback>, void>::value);
|
| 43 |
+
}
|
| 44 |
+
|
| 45 |
+
template <typename Callback>
|
| 46 |
+
class Storage {
|
| 47 |
+
public:
|
| 48 |
+
Storage() = delete;
|
| 49 |
+
|
| 50 |
+
explicit Storage(Callback callback) {
|
| 51 |
+
// Placement-new into a character buffer is used for eager destruction when
|
| 52 |
+
// the cleanup is invoked or cancelled. To ensure this optimizes well, the
|
| 53 |
+
// behavior is implemented locally instead of using an absl::optional.
|
| 54 |
+
::new (GetCallbackBuffer()) Callback(std::move(callback));
|
| 55 |
+
is_callback_engaged_ = true;
|
| 56 |
+
}
|
| 57 |
+
|
| 58 |
+
Storage(Storage&& other) {
|
| 59 |
+
ABSL_HARDENING_ASSERT(other.IsCallbackEngaged());
|
| 60 |
+
|
| 61 |
+
::new (GetCallbackBuffer()) Callback(std::move(other.GetCallback()));
|
| 62 |
+
is_callback_engaged_ = true;
|
| 63 |
+
|
| 64 |
+
other.DestroyCallback();
|
| 65 |
+
}
|
| 66 |
+
|
| 67 |
+
Storage(const Storage& other) = delete;
|
| 68 |
+
|
| 69 |
+
Storage& operator=(Storage&& other) = delete;
|
| 70 |
+
|
| 71 |
+
Storage& operator=(const Storage& other) = delete;
|
| 72 |
+
|
| 73 |
+
void* GetCallbackBuffer() { return static_cast<void*>(+callback_buffer_); }
|
| 74 |
+
|
| 75 |
+
Callback& GetCallback() {
|
| 76 |
+
return *reinterpret_cast<Callback*>(GetCallbackBuffer());
|
| 77 |
+
}
|
| 78 |
+
|
| 79 |
+
bool IsCallbackEngaged() const { return is_callback_engaged_; }
|
| 80 |
+
|
| 81 |
+
void DestroyCallback() {
|
| 82 |
+
is_callback_engaged_ = false;
|
| 83 |
+
GetCallback().~Callback();
|
| 84 |
+
}
|
| 85 |
+
|
| 86 |
+
void InvokeCallback() ABSL_NO_THREAD_SAFETY_ANALYSIS {
|
| 87 |
+
std::move(GetCallback())();
|
| 88 |
+
}
|
| 89 |
+
|
| 90 |
+
private:
|
| 91 |
+
bool is_callback_engaged_;
|
| 92 |
+
alignas(Callback) char callback_buffer_[sizeof(Callback)];
|
| 93 |
+
};
|
| 94 |
+
|
| 95 |
+
} // namespace cleanup_internal
|
| 96 |
+
|
| 97 |
+
ABSL_NAMESPACE_END
|
| 98 |
+
} // namespace absl
|
| 99 |
+
|
| 100 |
+
#endif // ABSL_CLEANUP_INTERNAL_CLEANUP_H_
|
weight/_dep/abseil-cpp/absl/copts/GENERATED_copts.bzl
ADDED
|
@@ -0,0 +1,230 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""GENERATED! DO NOT MANUALLY EDIT THIS FILE.
|
| 2 |
+
|
| 3 |
+
(1) Edit absl/copts/copts.py.
|
| 4 |
+
(2) Run `python <path_to_absl>/copts/generate_copts.py`.
|
| 5 |
+
"""
|
| 6 |
+
|
| 7 |
+
ABSL_CLANG_CL_FLAGS = [
|
| 8 |
+
"/W3",
|
| 9 |
+
"/DNOMINMAX",
|
| 10 |
+
"/DWIN32_LEAN_AND_MEAN",
|
| 11 |
+
"/D_CRT_SECURE_NO_WARNINGS",
|
| 12 |
+
"/D_SCL_SECURE_NO_WARNINGS",
|
| 13 |
+
"/D_ENABLE_EXTENDED_ALIGNED_STORAGE",
|
| 14 |
+
]
|
| 15 |
+
|
| 16 |
+
ABSL_CLANG_CL_TEST_FLAGS = [
|
| 17 |
+
"/W3",
|
| 18 |
+
"/DNOMINMAX",
|
| 19 |
+
"/DWIN32_LEAN_AND_MEAN",
|
| 20 |
+
"/D_CRT_SECURE_NO_WARNINGS",
|
| 21 |
+
"/D_SCL_SECURE_NO_WARNINGS",
|
| 22 |
+
"/D_ENABLE_EXTENDED_ALIGNED_STORAGE",
|
| 23 |
+
"-Wno-deprecated-declarations",
|
| 24 |
+
"-Wno-implicit-int-conversion",
|
| 25 |
+
"-Wno-missing-prototypes",
|
| 26 |
+
"-Wno-missing-variable-declarations",
|
| 27 |
+
"-Wno-shadow",
|
| 28 |
+
"-Wno-shorten-64-to-32",
|
| 29 |
+
"-Wno-sign-compare",
|
| 30 |
+
"-Wno-sign-conversion",
|
| 31 |
+
"-Wno-unreachable-code-loop-increment",
|
| 32 |
+
"-Wno-unused-function",
|
| 33 |
+
"-Wno-unused-member-function",
|
| 34 |
+
"-Wno-unused-parameter",
|
| 35 |
+
"-Wno-unused-private-field",
|
| 36 |
+
"-Wno-unused-template",
|
| 37 |
+
"-Wno-used-but-marked-unused",
|
| 38 |
+
"-Wno-gnu-zero-variadic-macro-arguments",
|
| 39 |
+
]
|
| 40 |
+
|
| 41 |
+
ABSL_GCC_FLAGS = [
|
| 42 |
+
"-Wall",
|
| 43 |
+
"-Wextra",
|
| 44 |
+
"-Wcast-qual",
|
| 45 |
+
"-Wconversion-null",
|
| 46 |
+
"-Wformat-security",
|
| 47 |
+
"-Wmissing-declarations",
|
| 48 |
+
"-Woverlength-strings",
|
| 49 |
+
"-Wpointer-arith",
|
| 50 |
+
"-Wundef",
|
| 51 |
+
"-Wunused-local-typedefs",
|
| 52 |
+
"-Wunused-result",
|
| 53 |
+
"-Wvarargs",
|
| 54 |
+
"-Wvla",
|
| 55 |
+
"-Wwrite-strings",
|
| 56 |
+
"-DNOMINMAX",
|
| 57 |
+
]
|
| 58 |
+
|
| 59 |
+
ABSL_GCC_TEST_FLAGS = [
|
| 60 |
+
"-Wall",
|
| 61 |
+
"-Wextra",
|
| 62 |
+
"-Wcast-qual",
|
| 63 |
+
"-Wconversion-null",
|
| 64 |
+
"-Wformat-security",
|
| 65 |
+
"-Woverlength-strings",
|
| 66 |
+
"-Wpointer-arith",
|
| 67 |
+
"-Wundef",
|
| 68 |
+
"-Wunused-local-typedefs",
|
| 69 |
+
"-Wunused-result",
|
| 70 |
+
"-Wvarargs",
|
| 71 |
+
"-Wvla",
|
| 72 |
+
"-Wwrite-strings",
|
| 73 |
+
"-DNOMINMAX",
|
| 74 |
+
"-Wno-deprecated-declarations",
|
| 75 |
+
"-Wno-missing-declarations",
|
| 76 |
+
"-Wno-self-move",
|
| 77 |
+
"-Wno-sign-compare",
|
| 78 |
+
"-Wno-unused-function",
|
| 79 |
+
"-Wno-unused-parameter",
|
| 80 |
+
"-Wno-unused-private-field",
|
| 81 |
+
]
|
| 82 |
+
|
| 83 |
+
ABSL_LLVM_FLAGS = [
|
| 84 |
+
"-Wall",
|
| 85 |
+
"-Wextra",
|
| 86 |
+
"-Wcast-qual",
|
| 87 |
+
"-Wconversion",
|
| 88 |
+
"-Wfloat-overflow-conversion",
|
| 89 |
+
"-Wfloat-zero-conversion",
|
| 90 |
+
"-Wfor-loop-analysis",
|
| 91 |
+
"-Wformat-security",
|
| 92 |
+
"-Wgnu-redeclared-enum",
|
| 93 |
+
"-Winfinite-recursion",
|
| 94 |
+
"-Winvalid-constexpr",
|
| 95 |
+
"-Wliteral-conversion",
|
| 96 |
+
"-Wmissing-declarations",
|
| 97 |
+
"-Woverlength-strings",
|
| 98 |
+
"-Wpointer-arith",
|
| 99 |
+
"-Wself-assign",
|
| 100 |
+
"-Wshadow-all",
|
| 101 |
+
"-Wshorten-64-to-32",
|
| 102 |
+
"-Wsign-conversion",
|
| 103 |
+
"-Wstring-conversion",
|
| 104 |
+
"-Wtautological-overlap-compare",
|
| 105 |
+
"-Wtautological-unsigned-zero-compare",
|
| 106 |
+
"-Wundef",
|
| 107 |
+
"-Wuninitialized",
|
| 108 |
+
"-Wunreachable-code",
|
| 109 |
+
"-Wunused-comparison",
|
| 110 |
+
"-Wunused-local-typedefs",
|
| 111 |
+
"-Wunused-result",
|
| 112 |
+
"-Wvla",
|
| 113 |
+
"-Wwrite-strings",
|
| 114 |
+
"-Wno-float-conversion",
|
| 115 |
+
"-Wno-implicit-float-conversion",
|
| 116 |
+
"-Wno-implicit-int-float-conversion",
|
| 117 |
+
"-Wno-unknown-warning-option",
|
| 118 |
+
"-DNOMINMAX",
|
| 119 |
+
]
|
| 120 |
+
|
| 121 |
+
ABSL_LLVM_TEST_FLAGS = [
|
| 122 |
+
"-Wall",
|
| 123 |
+
"-Wextra",
|
| 124 |
+
"-Wcast-qual",
|
| 125 |
+
"-Wconversion",
|
| 126 |
+
"-Wfloat-overflow-conversion",
|
| 127 |
+
"-Wfloat-zero-conversion",
|
| 128 |
+
"-Wfor-loop-analysis",
|
| 129 |
+
"-Wformat-security",
|
| 130 |
+
"-Wgnu-redeclared-enum",
|
| 131 |
+
"-Winfinite-recursion",
|
| 132 |
+
"-Winvalid-constexpr",
|
| 133 |
+
"-Wliteral-conversion",
|
| 134 |
+
"-Wmissing-declarations",
|
| 135 |
+
"-Woverlength-strings",
|
| 136 |
+
"-Wpointer-arith",
|
| 137 |
+
"-Wself-assign",
|
| 138 |
+
"-Wshadow-all",
|
| 139 |
+
"-Wstring-conversion",
|
| 140 |
+
"-Wtautological-overlap-compare",
|
| 141 |
+
"-Wtautological-unsigned-zero-compare",
|
| 142 |
+
"-Wundef",
|
| 143 |
+
"-Wuninitialized",
|
| 144 |
+
"-Wunreachable-code",
|
| 145 |
+
"-Wunused-comparison",
|
| 146 |
+
"-Wunused-local-typedefs",
|
| 147 |
+
"-Wunused-result",
|
| 148 |
+
"-Wvla",
|
| 149 |
+
"-Wwrite-strings",
|
| 150 |
+
"-Wno-float-conversion",
|
| 151 |
+
"-Wno-implicit-float-conversion",
|
| 152 |
+
"-Wno-implicit-int-float-conversion",
|
| 153 |
+
"-Wno-unknown-warning-option",
|
| 154 |
+
"-DNOMINMAX",
|
| 155 |
+
"-Wno-deprecated-declarations",
|
| 156 |
+
"-Wno-implicit-int-conversion",
|
| 157 |
+
"-Wno-missing-prototypes",
|
| 158 |
+
"-Wno-missing-variable-declarations",
|
| 159 |
+
"-Wno-shadow",
|
| 160 |
+
"-Wno-shorten-64-to-32",
|
| 161 |
+
"-Wno-sign-compare",
|
| 162 |
+
"-Wno-sign-conversion",
|
| 163 |
+
"-Wno-unreachable-code-loop-increment",
|
| 164 |
+
"-Wno-unused-function",
|
| 165 |
+
"-Wno-unused-member-function",
|
| 166 |
+
"-Wno-unused-parameter",
|
| 167 |
+
"-Wno-unused-private-field",
|
| 168 |
+
"-Wno-unused-template",
|
| 169 |
+
"-Wno-used-but-marked-unused",
|
| 170 |
+
"-Wno-gnu-zero-variadic-macro-arguments",
|
| 171 |
+
]
|
| 172 |
+
|
| 173 |
+
ABSL_MSVC_FLAGS = [
|
| 174 |
+
"/W3",
|
| 175 |
+
"/bigobj",
|
| 176 |
+
"/wd4005",
|
| 177 |
+
"/wd4068",
|
| 178 |
+
"/wd4180",
|
| 179 |
+
"/wd4244",
|
| 180 |
+
"/wd4267",
|
| 181 |
+
"/wd4503",
|
| 182 |
+
"/wd4800",
|
| 183 |
+
"/DNOMINMAX",
|
| 184 |
+
"/DWIN32_LEAN_AND_MEAN",
|
| 185 |
+
"/D_CRT_SECURE_NO_WARNINGS",
|
| 186 |
+
"/D_SCL_SECURE_NO_WARNINGS",
|
| 187 |
+
"/D_ENABLE_EXTENDED_ALIGNED_STORAGE",
|
| 188 |
+
]
|
| 189 |
+
|
| 190 |
+
ABSL_MSVC_LINKOPTS = [
|
| 191 |
+
"-ignore:4221",
|
| 192 |
+
]
|
| 193 |
+
|
| 194 |
+
ABSL_MSVC_TEST_FLAGS = [
|
| 195 |
+
"/W3",
|
| 196 |
+
"/bigobj",
|
| 197 |
+
"/wd4005",
|
| 198 |
+
"/wd4068",
|
| 199 |
+
"/wd4180",
|
| 200 |
+
"/wd4244",
|
| 201 |
+
"/wd4267",
|
| 202 |
+
"/wd4503",
|
| 203 |
+
"/wd4800",
|
| 204 |
+
"/DNOMINMAX",
|
| 205 |
+
"/DWIN32_LEAN_AND_MEAN",
|
| 206 |
+
"/D_CRT_SECURE_NO_WARNINGS",
|
| 207 |
+
"/D_SCL_SECURE_NO_WARNINGS",
|
| 208 |
+
"/D_ENABLE_EXTENDED_ALIGNED_STORAGE",
|
| 209 |
+
"/wd4018",
|
| 210 |
+
"/wd4101",
|
| 211 |
+
"/wd4503",
|
| 212 |
+
"/wd4996",
|
| 213 |
+
"/DNOMINMAX",
|
| 214 |
+
]
|
| 215 |
+
|
| 216 |
+
ABSL_RANDOM_HWAES_ARM32_FLAGS = [
|
| 217 |
+
"-mfpu=neon",
|
| 218 |
+
]
|
| 219 |
+
|
| 220 |
+
ABSL_RANDOM_HWAES_ARM64_FLAGS = [
|
| 221 |
+
"-march=armv8-a+crypto",
|
| 222 |
+
]
|
| 223 |
+
|
| 224 |
+
ABSL_RANDOM_HWAES_MSVC_X64_FLAGS = [
|
| 225 |
+
]
|
| 226 |
+
|
| 227 |
+
ABSL_RANDOM_HWAES_X64_FLAGS = [
|
| 228 |
+
"-maes",
|
| 229 |
+
"-msse4.1",
|
| 230 |
+
]
|
weight/_dep/abseil-cpp/absl/copts/configure_copts.bzl
ADDED
|
@@ -0,0 +1,82 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""absl specific copts.
|
| 2 |
+
|
| 3 |
+
This file simply selects the correct options from the generated files. To
|
| 4 |
+
change Abseil copts, edit absl/copts/copts.py
|
| 5 |
+
"""
|
| 6 |
+
|
| 7 |
+
load(
|
| 8 |
+
"//absl:copts/GENERATED_copts.bzl",
|
| 9 |
+
"ABSL_CLANG_CL_FLAGS",
|
| 10 |
+
"ABSL_CLANG_CL_TEST_FLAGS",
|
| 11 |
+
"ABSL_GCC_FLAGS",
|
| 12 |
+
"ABSL_GCC_TEST_FLAGS",
|
| 13 |
+
"ABSL_LLVM_FLAGS",
|
| 14 |
+
"ABSL_LLVM_TEST_FLAGS",
|
| 15 |
+
"ABSL_MSVC_FLAGS",
|
| 16 |
+
"ABSL_MSVC_LINKOPTS",
|
| 17 |
+
"ABSL_MSVC_TEST_FLAGS",
|
| 18 |
+
"ABSL_RANDOM_HWAES_ARM32_FLAGS",
|
| 19 |
+
"ABSL_RANDOM_HWAES_ARM64_FLAGS",
|
| 20 |
+
"ABSL_RANDOM_HWAES_MSVC_X64_FLAGS",
|
| 21 |
+
"ABSL_RANDOM_HWAES_X64_FLAGS",
|
| 22 |
+
)
|
| 23 |
+
|
| 24 |
+
ABSL_DEFAULT_COPTS = select({
|
| 25 |
+
"//absl:msvc_compiler": ABSL_MSVC_FLAGS,
|
| 26 |
+
"//absl:clang-cl_compiler": ABSL_CLANG_CL_FLAGS,
|
| 27 |
+
"//absl:clang_compiler": ABSL_LLVM_FLAGS,
|
| 28 |
+
"//absl:gcc_compiler": ABSL_GCC_FLAGS,
|
| 29 |
+
"//conditions:default": ABSL_GCC_FLAGS,
|
| 30 |
+
})
|
| 31 |
+
|
| 32 |
+
ABSL_TEST_COPTS = select({
|
| 33 |
+
"//absl:msvc_compiler": ABSL_MSVC_TEST_FLAGS,
|
| 34 |
+
"//absl:clang-cl_compiler": ABSL_CLANG_CL_TEST_FLAGS,
|
| 35 |
+
"//absl:clang_compiler": ABSL_LLVM_TEST_FLAGS,
|
| 36 |
+
"//absl:gcc_compiler": ABSL_GCC_TEST_FLAGS,
|
| 37 |
+
"//conditions:default": ABSL_GCC_TEST_FLAGS,
|
| 38 |
+
})
|
| 39 |
+
|
| 40 |
+
ABSL_DEFAULT_LINKOPTS = select({
|
| 41 |
+
"//absl:msvc_compiler": ABSL_MSVC_LINKOPTS,
|
| 42 |
+
"//conditions:default": [],
|
| 43 |
+
})
|
| 44 |
+
|
| 45 |
+
# ABSL_RANDOM_RANDEN_COPTS blaze copts flags which are required by each
|
| 46 |
+
# environment to build an accelerated RandenHwAes library.
|
| 47 |
+
ABSL_RANDOM_RANDEN_COPTS = select({
|
| 48 |
+
# APPLE
|
| 49 |
+
":cpu_darwin_x86_64": ABSL_RANDOM_HWAES_X64_FLAGS,
|
| 50 |
+
":cpu_darwin": ABSL_RANDOM_HWAES_X64_FLAGS,
|
| 51 |
+
":cpu_x64_windows_msvc": ABSL_RANDOM_HWAES_MSVC_X64_FLAGS,
|
| 52 |
+
":cpu_x64_windows": ABSL_RANDOM_HWAES_MSVC_X64_FLAGS,
|
| 53 |
+
":cpu_k8": ABSL_RANDOM_HWAES_X64_FLAGS,
|
| 54 |
+
":cpu_ppc": ["-mcrypto"],
|
| 55 |
+
":cpu_aarch64": ABSL_RANDOM_HWAES_ARM64_FLAGS,
|
| 56 |
+
|
| 57 |
+
# Supported by default or unsupported.
|
| 58 |
+
"//conditions:default": [],
|
| 59 |
+
})
|
| 60 |
+
|
| 61 |
+
# absl_random_randen_copts_init:
|
| 62 |
+
# Initialize the config targets based on cpu, os, etc. used to select
|
| 63 |
+
# the required values for ABSL_RANDOM_RANDEN_COPTS
|
| 64 |
+
def absl_random_randen_copts_init():
|
| 65 |
+
"""Initialize the config_settings used by ABSL_RANDOM_RANDEN_COPTS."""
|
| 66 |
+
|
| 67 |
+
# CPU configs.
|
| 68 |
+
# These configs have consistent flags to enable HWAES intsructions.
|
| 69 |
+
cpu_configs = [
|
| 70 |
+
"ppc",
|
| 71 |
+
"k8",
|
| 72 |
+
"darwin_x86_64",
|
| 73 |
+
"darwin",
|
| 74 |
+
"x64_windows_msvc",
|
| 75 |
+
"x64_windows",
|
| 76 |
+
"aarch64",
|
| 77 |
+
]
|
| 78 |
+
for cpu in cpu_configs:
|
| 79 |
+
native.config_setting(
|
| 80 |
+
name = "cpu_%s" % cpu,
|
| 81 |
+
values = {"cpu": cpu},
|
| 82 |
+
)
|
weight/_dep/abseil-cpp/absl/copts/copts.py
ADDED
|
@@ -0,0 +1,191 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""Abseil compiler options.
|
| 2 |
+
|
| 3 |
+
This is the source of truth for Abseil compiler options. To modify Abseil
|
| 4 |
+
compilation options:
|
| 5 |
+
|
| 6 |
+
(1) Edit the appropriate list in this file based on the platform the flag is
|
| 7 |
+
needed on.
|
| 8 |
+
(2) Run `<path_to_absl>/copts/generate_copts.py`.
|
| 9 |
+
|
| 10 |
+
The generated copts are consumed by configure_copts.bzl and
|
| 11 |
+
AbseilConfigureCopts.cmake.
|
| 12 |
+
"""
|
| 13 |
+
|
| 14 |
+
ABSL_GCC_FLAGS = [
|
| 15 |
+
"-Wall",
|
| 16 |
+
"-Wextra",
|
| 17 |
+
"-Wcast-qual",
|
| 18 |
+
"-Wconversion-null",
|
| 19 |
+
"-Wformat-security",
|
| 20 |
+
"-Wmissing-declarations",
|
| 21 |
+
"-Woverlength-strings",
|
| 22 |
+
"-Wpointer-arith",
|
| 23 |
+
"-Wundef",
|
| 24 |
+
"-Wunused-local-typedefs",
|
| 25 |
+
"-Wunused-result",
|
| 26 |
+
"-Wvarargs",
|
| 27 |
+
"-Wvla", # variable-length array
|
| 28 |
+
"-Wwrite-strings",
|
| 29 |
+
# Don't define min and max macros (Build on Windows using gcc)
|
| 30 |
+
"-DNOMINMAX",
|
| 31 |
+
]
|
| 32 |
+
|
| 33 |
+
ABSL_GCC_TEST_ADDITIONAL_FLAGS = [
|
| 34 |
+
"-Wno-deprecated-declarations",
|
| 35 |
+
"-Wno-missing-declarations",
|
| 36 |
+
"-Wno-self-move",
|
| 37 |
+
"-Wno-sign-compare",
|
| 38 |
+
"-Wno-unused-function",
|
| 39 |
+
"-Wno-unused-parameter",
|
| 40 |
+
"-Wno-unused-private-field",
|
| 41 |
+
]
|
| 42 |
+
|
| 43 |
+
ABSL_LLVM_FLAGS = [
|
| 44 |
+
"-Wall",
|
| 45 |
+
"-Wextra",
|
| 46 |
+
"-Wcast-qual",
|
| 47 |
+
"-Wconversion",
|
| 48 |
+
"-Wfloat-overflow-conversion",
|
| 49 |
+
"-Wfloat-zero-conversion",
|
| 50 |
+
"-Wfor-loop-analysis",
|
| 51 |
+
"-Wformat-security",
|
| 52 |
+
"-Wgnu-redeclared-enum",
|
| 53 |
+
"-Winfinite-recursion",
|
| 54 |
+
"-Winvalid-constexpr",
|
| 55 |
+
"-Wliteral-conversion",
|
| 56 |
+
"-Wmissing-declarations",
|
| 57 |
+
"-Woverlength-strings",
|
| 58 |
+
"-Wpointer-arith",
|
| 59 |
+
"-Wself-assign",
|
| 60 |
+
"-Wshadow-all",
|
| 61 |
+
"-Wshorten-64-to-32",
|
| 62 |
+
"-Wsign-conversion",
|
| 63 |
+
"-Wstring-conversion",
|
| 64 |
+
"-Wtautological-overlap-compare",
|
| 65 |
+
"-Wtautological-unsigned-zero-compare",
|
| 66 |
+
"-Wundef",
|
| 67 |
+
"-Wuninitialized",
|
| 68 |
+
"-Wunreachable-code",
|
| 69 |
+
"-Wunused-comparison",
|
| 70 |
+
"-Wunused-local-typedefs",
|
| 71 |
+
"-Wunused-result",
|
| 72 |
+
"-Wvla",
|
| 73 |
+
"-Wwrite-strings",
|
| 74 |
+
# Warnings that are enabled by group warning flags like -Wall that we
|
| 75 |
+
# explicitly disable.
|
| 76 |
+
"-Wno-float-conversion",
|
| 77 |
+
"-Wno-implicit-float-conversion",
|
| 78 |
+
"-Wno-implicit-int-float-conversion",
|
| 79 |
+
# Disable warnings on unknown warning flags (when warning flags are
|
| 80 |
+
# unknown on older compiler versions)
|
| 81 |
+
"-Wno-unknown-warning-option",
|
| 82 |
+
# Don't define min and max macros (Build on Windows using clang)
|
| 83 |
+
"-DNOMINMAX",
|
| 84 |
+
]
|
| 85 |
+
|
| 86 |
+
ABSL_LLVM_TEST_ADDITIONAL_FLAGS = [
|
| 87 |
+
"-Wno-deprecated-declarations",
|
| 88 |
+
"-Wno-implicit-int-conversion",
|
| 89 |
+
"-Wno-missing-prototypes",
|
| 90 |
+
"-Wno-missing-variable-declarations",
|
| 91 |
+
"-Wno-shadow",
|
| 92 |
+
"-Wno-shorten-64-to-32",
|
| 93 |
+
"-Wno-sign-compare",
|
| 94 |
+
"-Wno-sign-conversion",
|
| 95 |
+
"-Wno-unreachable-code-loop-increment",
|
| 96 |
+
"-Wno-unused-function",
|
| 97 |
+
"-Wno-unused-member-function",
|
| 98 |
+
"-Wno-unused-parameter",
|
| 99 |
+
"-Wno-unused-private-field",
|
| 100 |
+
"-Wno-unused-template",
|
| 101 |
+
"-Wno-used-but-marked-unused",
|
| 102 |
+
# gtest depends on this GNU extension being offered.
|
| 103 |
+
"-Wno-gnu-zero-variadic-macro-arguments",
|
| 104 |
+
]
|
| 105 |
+
|
| 106 |
+
# /Wall with msvc includes unhelpful warnings such as C4711, C4710, ...
|
| 107 |
+
MSVC_BIG_WARNING_FLAGS = [
|
| 108 |
+
"/W3",
|
| 109 |
+
]
|
| 110 |
+
|
| 111 |
+
MSVC_WARNING_FLAGS = [
|
| 112 |
+
# Increase the number of sections available in object files
|
| 113 |
+
"/bigobj",
|
| 114 |
+
"/wd4005", # macro-redefinition
|
| 115 |
+
"/wd4068", # unknown pragma
|
| 116 |
+
# qualifier applied to function type has no meaning; ignored
|
| 117 |
+
"/wd4180",
|
| 118 |
+
# conversion from 'type1' to 'type2', possible loss of data
|
| 119 |
+
"/wd4244",
|
| 120 |
+
# conversion from 'size_t' to 'type', possible loss of data
|
| 121 |
+
"/wd4267",
|
| 122 |
+
# The decorated name was longer than the compiler limit
|
| 123 |
+
"/wd4503",
|
| 124 |
+
# forcing value to bool 'true' or 'false' (performance warning)
|
| 125 |
+
"/wd4800",
|
| 126 |
+
]
|
| 127 |
+
|
| 128 |
+
MSVC_DEFINES = [
|
| 129 |
+
"/DNOMINMAX", # Don't define min and max macros (windows.h)
|
| 130 |
+
# Don't bloat namespace with incompatible winsock versions.
|
| 131 |
+
"/DWIN32_LEAN_AND_MEAN",
|
| 132 |
+
# Don't warn about usage of insecure C functions.
|
| 133 |
+
"/D_CRT_SECURE_NO_WARNINGS",
|
| 134 |
+
"/D_SCL_SECURE_NO_WARNINGS",
|
| 135 |
+
# Introduced in VS 2017 15.8, allow overaligned types in aligned_storage
|
| 136 |
+
"/D_ENABLE_EXTENDED_ALIGNED_STORAGE",
|
| 137 |
+
]
|
| 138 |
+
|
| 139 |
+
|
| 140 |
+
def GccStyleFilterAndCombine(default_flags, test_flags):
|
| 141 |
+
"""Merges default_flags and test_flags for GCC and LLVM.
|
| 142 |
+
|
| 143 |
+
Args:
|
| 144 |
+
default_flags: A list of default compiler flags
|
| 145 |
+
test_flags: A list of flags that are only used in tests
|
| 146 |
+
|
| 147 |
+
Returns:
|
| 148 |
+
A combined list of default_flags and test_flags, but with all flags of the
|
| 149 |
+
form '-Wwarning' removed if test_flags contains a flag of the form
|
| 150 |
+
'-Wno-warning'
|
| 151 |
+
"""
|
| 152 |
+
remove = set(["-W" + f[5:] for f in test_flags if f[:5] == "-Wno-"])
|
| 153 |
+
return [f for f in default_flags if f not in remove] + test_flags
|
| 154 |
+
|
| 155 |
+
COPT_VARS = {
|
| 156 |
+
"ABSL_GCC_FLAGS": ABSL_GCC_FLAGS,
|
| 157 |
+
"ABSL_GCC_TEST_FLAGS": GccStyleFilterAndCombine(
|
| 158 |
+
ABSL_GCC_FLAGS, ABSL_GCC_TEST_ADDITIONAL_FLAGS),
|
| 159 |
+
"ABSL_LLVM_FLAGS": ABSL_LLVM_FLAGS,
|
| 160 |
+
"ABSL_LLVM_TEST_FLAGS": GccStyleFilterAndCombine(
|
| 161 |
+
ABSL_LLVM_FLAGS, ABSL_LLVM_TEST_ADDITIONAL_FLAGS),
|
| 162 |
+
"ABSL_CLANG_CL_FLAGS":
|
| 163 |
+
MSVC_BIG_WARNING_FLAGS + MSVC_DEFINES,
|
| 164 |
+
"ABSL_CLANG_CL_TEST_FLAGS":
|
| 165 |
+
MSVC_BIG_WARNING_FLAGS + MSVC_DEFINES + ABSL_LLVM_TEST_ADDITIONAL_FLAGS,
|
| 166 |
+
"ABSL_MSVC_FLAGS":
|
| 167 |
+
MSVC_BIG_WARNING_FLAGS + MSVC_WARNING_FLAGS + MSVC_DEFINES,
|
| 168 |
+
"ABSL_MSVC_TEST_FLAGS":
|
| 169 |
+
MSVC_BIG_WARNING_FLAGS + MSVC_WARNING_FLAGS + MSVC_DEFINES + [
|
| 170 |
+
"/wd4018", # signed/unsigned mismatch
|
| 171 |
+
"/wd4101", # unreferenced local variable
|
| 172 |
+
"/wd4503", # decorated name length exceeded, name was truncated
|
| 173 |
+
"/wd4996", # use of deprecated symbol
|
| 174 |
+
"/DNOMINMAX", # disable the min() and max() macros from <windows.h>
|
| 175 |
+
],
|
| 176 |
+
"ABSL_MSVC_LINKOPTS": [
|
| 177 |
+
# Object file doesn't export any previously undefined symbols
|
| 178 |
+
"-ignore:4221",
|
| 179 |
+
],
|
| 180 |
+
# "HWAES" is an abbreviation for "hardware AES" (AES - Advanced Encryption
|
| 181 |
+
# Standard). These flags are used for detecting whether or not the target
|
| 182 |
+
# architecture has hardware support for AES instructions which can be used
|
| 183 |
+
# to improve performance of some random bit generators.
|
| 184 |
+
"ABSL_RANDOM_HWAES_ARM64_FLAGS": ["-march=armv8-a+crypto"],
|
| 185 |
+
"ABSL_RANDOM_HWAES_ARM32_FLAGS": ["-mfpu=neon"],
|
| 186 |
+
"ABSL_RANDOM_HWAES_X64_FLAGS": [
|
| 187 |
+
"-maes",
|
| 188 |
+
"-msse4.1",
|
| 189 |
+
],
|
| 190 |
+
"ABSL_RANDOM_HWAES_MSVC_X64_FLAGS": [],
|
| 191 |
+
}
|
weight/_dep/abseil-cpp/absl/copts/generate_copts.py
ADDED
|
@@ -0,0 +1,109 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#!/usr/bin/env python3
|
| 2 |
+
"""Generate Abseil compile compile option configs.
|
| 3 |
+
|
| 4 |
+
Usage: <path_to_absl>/copts/generate_copts.py
|
| 5 |
+
|
| 6 |
+
The configs are generated from copts.py.
|
| 7 |
+
"""
|
| 8 |
+
|
| 9 |
+
from os import path
|
| 10 |
+
import sys
|
| 11 |
+
from copts import COPT_VARS
|
| 12 |
+
|
| 13 |
+
|
| 14 |
+
# Helper functions
|
| 15 |
+
def file_header_lines():
|
| 16 |
+
return [
|
| 17 |
+
"GENERATED! DO NOT MANUALLY EDIT THIS FILE.", "",
|
| 18 |
+
"(1) Edit absl/copts/copts.py.",
|
| 19 |
+
"(2) Run `python <path_to_absl>/copts/generate_copts.py`."
|
| 20 |
+
]
|
| 21 |
+
|
| 22 |
+
|
| 23 |
+
def flatten(*lists):
|
| 24 |
+
return [item for sublist in lists for item in sublist]
|
| 25 |
+
|
| 26 |
+
|
| 27 |
+
def relative_filename(filename):
|
| 28 |
+
return path.join(path.dirname(__file__), filename)
|
| 29 |
+
|
| 30 |
+
|
| 31 |
+
# Style classes. These contain all the syntactic styling needed to generate a
|
| 32 |
+
# copt file for different build tools.
|
| 33 |
+
class CMakeStyle(object):
|
| 34 |
+
"""Style object for CMake copts file."""
|
| 35 |
+
|
| 36 |
+
def separator(self):
|
| 37 |
+
return ""
|
| 38 |
+
|
| 39 |
+
def list_introducer(self, name):
|
| 40 |
+
return "list(APPEND " + name
|
| 41 |
+
|
| 42 |
+
def list_closer(self):
|
| 43 |
+
return ")\n"
|
| 44 |
+
|
| 45 |
+
def docstring(self):
|
| 46 |
+
return "\n".join((("# " + line).strip() for line in file_header_lines()))
|
| 47 |
+
|
| 48 |
+
def filename(self):
|
| 49 |
+
return "GENERATED_AbseilCopts.cmake"
|
| 50 |
+
|
| 51 |
+
|
| 52 |
+
class StarlarkStyle(object):
|
| 53 |
+
"""Style object for Starlark copts file."""
|
| 54 |
+
|
| 55 |
+
def separator(self):
|
| 56 |
+
return ","
|
| 57 |
+
|
| 58 |
+
def list_introducer(self, name):
|
| 59 |
+
return name + " = ["
|
| 60 |
+
|
| 61 |
+
def list_closer(self):
|
| 62 |
+
return "]\n"
|
| 63 |
+
|
| 64 |
+
def docstring(self):
|
| 65 |
+
docstring_quotes = "\"\"\""
|
| 66 |
+
return docstring_quotes + "\n".join(
|
| 67 |
+
flatten(file_header_lines(), [docstring_quotes]))
|
| 68 |
+
|
| 69 |
+
def filename(self):
|
| 70 |
+
return "GENERATED_copts.bzl"
|
| 71 |
+
|
| 72 |
+
|
| 73 |
+
def copt_list(name, arg_list, style):
|
| 74 |
+
"""Copt file generation."""
|
| 75 |
+
|
| 76 |
+
make_line = lambda s: " \"" + s + "\"" + style.separator()
|
| 77 |
+
external_str_list = [make_line(s) for s in arg_list]
|
| 78 |
+
|
| 79 |
+
return "\n".join(
|
| 80 |
+
flatten(
|
| 81 |
+
[style.list_introducer(name)],
|
| 82 |
+
external_str_list,
|
| 83 |
+
[style.list_closer()]))
|
| 84 |
+
|
| 85 |
+
|
| 86 |
+
def generate_copt_file(style):
|
| 87 |
+
"""Creates a generated copt file using the given style object.
|
| 88 |
+
|
| 89 |
+
Args:
|
| 90 |
+
style: either StarlarkStyle() or CMakeStyle()
|
| 91 |
+
"""
|
| 92 |
+
with open(relative_filename(style.filename()), "w") as f:
|
| 93 |
+
f.write(style.docstring())
|
| 94 |
+
f.write("\n")
|
| 95 |
+
for var_name, arg_list in sorted(COPT_VARS.items()):
|
| 96 |
+
f.write("\n")
|
| 97 |
+
f.write(copt_list(var_name, arg_list, style))
|
| 98 |
+
|
| 99 |
+
|
| 100 |
+
def main(argv):
|
| 101 |
+
if len(argv) > 1:
|
| 102 |
+
raise RuntimeError("generate_copts needs no command line args")
|
| 103 |
+
|
| 104 |
+
generate_copt_file(StarlarkStyle())
|
| 105 |
+
generate_copt_file(CMakeStyle())
|
| 106 |
+
|
| 107 |
+
|
| 108 |
+
if __name__ == "__main__":
|
| 109 |
+
main(sys.argv)
|
weight/_dep/abseil-cpp/absl/flags/BUILD.bazel
ADDED
|
@@ -0,0 +1,601 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#
|
| 2 |
+
# Copyright 2019 The Abseil Authors.
|
| 3 |
+
#
|
| 4 |
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
| 5 |
+
# you may not use this file except in compliance with the License.
|
| 6 |
+
# You may obtain a copy of the License at
|
| 7 |
+
#
|
| 8 |
+
# https://www.apache.org/licenses/LICENSE-2.0
|
| 9 |
+
#
|
| 10 |
+
# Unless required by applicable law or agreed to in writing, software
|
| 11 |
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
| 12 |
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
| 13 |
+
# See the License for the specific language governing permissions and
|
| 14 |
+
# limitations under the License.
|
| 15 |
+
#
|
| 16 |
+
|
| 17 |
+
load(
|
| 18 |
+
"//absl:copts/configure_copts.bzl",
|
| 19 |
+
"ABSL_DEFAULT_COPTS",
|
| 20 |
+
"ABSL_DEFAULT_LINKOPTS",
|
| 21 |
+
"ABSL_TEST_COPTS",
|
| 22 |
+
)
|
| 23 |
+
|
| 24 |
+
package(
|
| 25 |
+
default_visibility = ["//visibility:public"],
|
| 26 |
+
features = [
|
| 27 |
+
"header_modules",
|
| 28 |
+
"layering_check",
|
| 29 |
+
"parse_headers",
|
| 30 |
+
],
|
| 31 |
+
)
|
| 32 |
+
|
| 33 |
+
licenses(["notice"])
|
| 34 |
+
|
| 35 |
+
cc_library(
|
| 36 |
+
name = "path_util",
|
| 37 |
+
hdrs = [
|
| 38 |
+
"internal/path_util.h",
|
| 39 |
+
],
|
| 40 |
+
copts = ABSL_DEFAULT_COPTS,
|
| 41 |
+
linkopts = ABSL_DEFAULT_LINKOPTS,
|
| 42 |
+
visibility = [
|
| 43 |
+
"//absl/flags:__pkg__",
|
| 44 |
+
],
|
| 45 |
+
deps = [
|
| 46 |
+
"//absl/base:config",
|
| 47 |
+
"//absl/strings",
|
| 48 |
+
],
|
| 49 |
+
)
|
| 50 |
+
|
| 51 |
+
cc_library(
|
| 52 |
+
name = "program_name",
|
| 53 |
+
srcs = [
|
| 54 |
+
"internal/program_name.cc",
|
| 55 |
+
],
|
| 56 |
+
hdrs = [
|
| 57 |
+
"internal/program_name.h",
|
| 58 |
+
],
|
| 59 |
+
copts = ABSL_DEFAULT_COPTS,
|
| 60 |
+
linkopts = ABSL_DEFAULT_LINKOPTS,
|
| 61 |
+
visibility = [
|
| 62 |
+
"//absl/flags:__pkg__",
|
| 63 |
+
"//absl/log:__pkg__",
|
| 64 |
+
],
|
| 65 |
+
deps = [
|
| 66 |
+
":path_util",
|
| 67 |
+
"//absl/base:config",
|
| 68 |
+
"//absl/base:core_headers",
|
| 69 |
+
"//absl/strings",
|
| 70 |
+
"//absl/synchronization",
|
| 71 |
+
],
|
| 72 |
+
)
|
| 73 |
+
|
| 74 |
+
cc_library(
|
| 75 |
+
name = "config",
|
| 76 |
+
srcs = [
|
| 77 |
+
"usage_config.cc",
|
| 78 |
+
],
|
| 79 |
+
hdrs = [
|
| 80 |
+
"config.h",
|
| 81 |
+
"usage_config.h",
|
| 82 |
+
],
|
| 83 |
+
copts = ABSL_DEFAULT_COPTS,
|
| 84 |
+
linkopts = ABSL_DEFAULT_LINKOPTS,
|
| 85 |
+
deps = [
|
| 86 |
+
":path_util",
|
| 87 |
+
":program_name",
|
| 88 |
+
"//absl/base:config",
|
| 89 |
+
"//absl/base:core_headers",
|
| 90 |
+
"//absl/strings",
|
| 91 |
+
"//absl/synchronization",
|
| 92 |
+
],
|
| 93 |
+
)
|
| 94 |
+
|
| 95 |
+
cc_library(
|
| 96 |
+
name = "marshalling",
|
| 97 |
+
srcs = [
|
| 98 |
+
"marshalling.cc",
|
| 99 |
+
],
|
| 100 |
+
hdrs = [
|
| 101 |
+
"marshalling.h",
|
| 102 |
+
],
|
| 103 |
+
copts = ABSL_DEFAULT_COPTS,
|
| 104 |
+
linkopts = ABSL_DEFAULT_LINKOPTS,
|
| 105 |
+
deps = [
|
| 106 |
+
"//absl/base:config",
|
| 107 |
+
"//absl/base:core_headers",
|
| 108 |
+
"//absl/base:log_severity",
|
| 109 |
+
"//absl/numeric:int128",
|
| 110 |
+
"//absl/strings",
|
| 111 |
+
"//absl/strings:str_format",
|
| 112 |
+
"//absl/types:optional",
|
| 113 |
+
],
|
| 114 |
+
)
|
| 115 |
+
|
| 116 |
+
cc_library(
|
| 117 |
+
name = "commandlineflag_internal",
|
| 118 |
+
srcs = [
|
| 119 |
+
"internal/commandlineflag.cc",
|
| 120 |
+
],
|
| 121 |
+
hdrs = [
|
| 122 |
+
"internal/commandlineflag.h",
|
| 123 |
+
],
|
| 124 |
+
copts = ABSL_DEFAULT_COPTS,
|
| 125 |
+
linkopts = ABSL_DEFAULT_LINKOPTS,
|
| 126 |
+
visibility = [
|
| 127 |
+
"//visibility:private",
|
| 128 |
+
],
|
| 129 |
+
deps = [
|
| 130 |
+
"//absl/base:config",
|
| 131 |
+
"//absl/base:fast_type_id",
|
| 132 |
+
],
|
| 133 |
+
)
|
| 134 |
+
|
| 135 |
+
cc_library(
|
| 136 |
+
name = "commandlineflag",
|
| 137 |
+
srcs = [
|
| 138 |
+
"commandlineflag.cc",
|
| 139 |
+
],
|
| 140 |
+
hdrs = [
|
| 141 |
+
"commandlineflag.h",
|
| 142 |
+
],
|
| 143 |
+
copts = ABSL_DEFAULT_COPTS,
|
| 144 |
+
linkopts = ABSL_DEFAULT_LINKOPTS,
|
| 145 |
+
deps = [
|
| 146 |
+
":commandlineflag_internal",
|
| 147 |
+
"//absl/base:config",
|
| 148 |
+
"//absl/base:fast_type_id",
|
| 149 |
+
"//absl/strings",
|
| 150 |
+
"//absl/types:optional",
|
| 151 |
+
],
|
| 152 |
+
)
|
| 153 |
+
|
| 154 |
+
cc_library(
|
| 155 |
+
name = "private_handle_accessor",
|
| 156 |
+
srcs = [
|
| 157 |
+
"internal/private_handle_accessor.cc",
|
| 158 |
+
],
|
| 159 |
+
hdrs = [
|
| 160 |
+
"internal/private_handle_accessor.h",
|
| 161 |
+
],
|
| 162 |
+
copts = ABSL_DEFAULT_COPTS,
|
| 163 |
+
linkopts = ABSL_DEFAULT_LINKOPTS,
|
| 164 |
+
visibility = [
|
| 165 |
+
"//absl/flags:__pkg__",
|
| 166 |
+
],
|
| 167 |
+
deps = [
|
| 168 |
+
":commandlineflag",
|
| 169 |
+
":commandlineflag_internal",
|
| 170 |
+
"//absl/base:config",
|
| 171 |
+
"//absl/strings",
|
| 172 |
+
],
|
| 173 |
+
)
|
| 174 |
+
|
| 175 |
+
cc_library(
|
| 176 |
+
name = "reflection",
|
| 177 |
+
srcs = [
|
| 178 |
+
"reflection.cc",
|
| 179 |
+
],
|
| 180 |
+
hdrs = [
|
| 181 |
+
"internal/registry.h",
|
| 182 |
+
"reflection.h",
|
| 183 |
+
],
|
| 184 |
+
copts = ABSL_DEFAULT_COPTS,
|
| 185 |
+
linkopts = ABSL_DEFAULT_LINKOPTS,
|
| 186 |
+
deps = [
|
| 187 |
+
":commandlineflag",
|
| 188 |
+
":commandlineflag_internal",
|
| 189 |
+
":config",
|
| 190 |
+
":private_handle_accessor",
|
| 191 |
+
"//absl/base:config",
|
| 192 |
+
"//absl/base:core_headers",
|
| 193 |
+
"//absl/base:no_destructor",
|
| 194 |
+
"//absl/container:flat_hash_map",
|
| 195 |
+
"//absl/strings",
|
| 196 |
+
"//absl/synchronization",
|
| 197 |
+
],
|
| 198 |
+
)
|
| 199 |
+
|
| 200 |
+
cc_library(
|
| 201 |
+
name = "flag_internal",
|
| 202 |
+
srcs = [
|
| 203 |
+
"internal/flag.cc",
|
| 204 |
+
],
|
| 205 |
+
hdrs = [
|
| 206 |
+
"internal/flag.h",
|
| 207 |
+
"internal/sequence_lock.h",
|
| 208 |
+
],
|
| 209 |
+
copts = ABSL_DEFAULT_COPTS,
|
| 210 |
+
linkopts = ABSL_DEFAULT_LINKOPTS,
|
| 211 |
+
visibility = ["//absl/base:__subpackages__"],
|
| 212 |
+
deps = [
|
| 213 |
+
":commandlineflag",
|
| 214 |
+
":commandlineflag_internal",
|
| 215 |
+
":config",
|
| 216 |
+
":marshalling",
|
| 217 |
+
":reflection",
|
| 218 |
+
"//absl/base",
|
| 219 |
+
"//absl/base:config",
|
| 220 |
+
"//absl/base:core_headers",
|
| 221 |
+
"//absl/base:dynamic_annotations",
|
| 222 |
+
"//absl/memory",
|
| 223 |
+
"//absl/meta:type_traits",
|
| 224 |
+
"//absl/strings",
|
| 225 |
+
"//absl/synchronization",
|
| 226 |
+
"//absl/utility",
|
| 227 |
+
],
|
| 228 |
+
)
|
| 229 |
+
|
| 230 |
+
cc_library(
|
| 231 |
+
name = "flag",
|
| 232 |
+
hdrs = [
|
| 233 |
+
"declare.h",
|
| 234 |
+
"flag.h",
|
| 235 |
+
],
|
| 236 |
+
copts = ABSL_DEFAULT_COPTS,
|
| 237 |
+
linkopts = ABSL_DEFAULT_LINKOPTS,
|
| 238 |
+
deps = [
|
| 239 |
+
":config",
|
| 240 |
+
":flag_internal",
|
| 241 |
+
":reflection",
|
| 242 |
+
"//absl/base",
|
| 243 |
+
"//absl/base:config",
|
| 244 |
+
"//absl/base:core_headers",
|
| 245 |
+
"//absl/strings",
|
| 246 |
+
],
|
| 247 |
+
)
|
| 248 |
+
|
| 249 |
+
cc_library(
|
| 250 |
+
name = "usage_internal",
|
| 251 |
+
srcs = [
|
| 252 |
+
"internal/usage.cc",
|
| 253 |
+
],
|
| 254 |
+
hdrs = [
|
| 255 |
+
"internal/usage.h",
|
| 256 |
+
],
|
| 257 |
+
copts = ABSL_DEFAULT_COPTS,
|
| 258 |
+
linkopts = ABSL_DEFAULT_LINKOPTS,
|
| 259 |
+
visibility = [
|
| 260 |
+
"//absl/flags:__pkg__",
|
| 261 |
+
],
|
| 262 |
+
deps = [
|
| 263 |
+
":commandlineflag",
|
| 264 |
+
":config",
|
| 265 |
+
":flag",
|
| 266 |
+
":flag_internal",
|
| 267 |
+
":path_util",
|
| 268 |
+
":private_handle_accessor",
|
| 269 |
+
":program_name",
|
| 270 |
+
":reflection",
|
| 271 |
+
"//absl/base:config",
|
| 272 |
+
"//absl/base:core_headers",
|
| 273 |
+
"//absl/strings",
|
| 274 |
+
"//absl/synchronization",
|
| 275 |
+
],
|
| 276 |
+
)
|
| 277 |
+
|
| 278 |
+
cc_library(
|
| 279 |
+
name = "usage",
|
| 280 |
+
srcs = [
|
| 281 |
+
"usage.cc",
|
| 282 |
+
],
|
| 283 |
+
hdrs = [
|
| 284 |
+
"usage.h",
|
| 285 |
+
],
|
| 286 |
+
copts = ABSL_DEFAULT_COPTS,
|
| 287 |
+
linkopts = ABSL_DEFAULT_LINKOPTS,
|
| 288 |
+
deps = [
|
| 289 |
+
":usage_internal",
|
| 290 |
+
"//absl/base:config",
|
| 291 |
+
"//absl/base:core_headers",
|
| 292 |
+
"//absl/base:raw_logging_internal",
|
| 293 |
+
"//absl/strings",
|
| 294 |
+
"//absl/synchronization",
|
| 295 |
+
],
|
| 296 |
+
)
|
| 297 |
+
|
| 298 |
+
cc_library(
|
| 299 |
+
name = "parse",
|
| 300 |
+
srcs = ["parse.cc"],
|
| 301 |
+
hdrs = [
|
| 302 |
+
"internal/parse.h",
|
| 303 |
+
"parse.h",
|
| 304 |
+
],
|
| 305 |
+
copts = ABSL_DEFAULT_COPTS,
|
| 306 |
+
linkopts = ABSL_DEFAULT_LINKOPTS,
|
| 307 |
+
deps = [
|
| 308 |
+
":commandlineflag",
|
| 309 |
+
":commandlineflag_internal",
|
| 310 |
+
":config",
|
| 311 |
+
":flag",
|
| 312 |
+
":flag_internal",
|
| 313 |
+
":private_handle_accessor",
|
| 314 |
+
":program_name",
|
| 315 |
+
":reflection",
|
| 316 |
+
":usage",
|
| 317 |
+
":usage_internal",
|
| 318 |
+
"//absl/algorithm:container",
|
| 319 |
+
"//absl/base:config",
|
| 320 |
+
"//absl/base:core_headers",
|
| 321 |
+
"//absl/strings",
|
| 322 |
+
"//absl/synchronization",
|
| 323 |
+
],
|
| 324 |
+
)
|
| 325 |
+
|
| 326 |
+
############################################################################
|
| 327 |
+
# Unit tests in alphabetical order.
|
| 328 |
+
|
| 329 |
+
cc_test(
|
| 330 |
+
name = "commandlineflag_test",
|
| 331 |
+
size = "small",
|
| 332 |
+
srcs = [
|
| 333 |
+
"commandlineflag_test.cc",
|
| 334 |
+
],
|
| 335 |
+
copts = ABSL_TEST_COPTS,
|
| 336 |
+
linkopts = ABSL_DEFAULT_LINKOPTS,
|
| 337 |
+
tags = [
|
| 338 |
+
"no_test:os:android",
|
| 339 |
+
"no_test:os:ios",
|
| 340 |
+
"no_test_android",
|
| 341 |
+
"no_test_ios",
|
| 342 |
+
"no_test_wasm",
|
| 343 |
+
],
|
| 344 |
+
deps = [
|
| 345 |
+
":commandlineflag",
|
| 346 |
+
":commandlineflag_internal",
|
| 347 |
+
":config",
|
| 348 |
+
":flag",
|
| 349 |
+
":private_handle_accessor",
|
| 350 |
+
":reflection",
|
| 351 |
+
"//absl/memory",
|
| 352 |
+
"//absl/strings",
|
| 353 |
+
"@com_google_googletest//:gtest",
|
| 354 |
+
"@com_google_googletest//:gtest_main",
|
| 355 |
+
],
|
| 356 |
+
)
|
| 357 |
+
|
| 358 |
+
cc_test(
|
| 359 |
+
name = "config_test",
|
| 360 |
+
size = "small",
|
| 361 |
+
srcs = [
|
| 362 |
+
"config_test.cc",
|
| 363 |
+
],
|
| 364 |
+
copts = ABSL_TEST_COPTS,
|
| 365 |
+
linkopts = ABSL_DEFAULT_LINKOPTS,
|
| 366 |
+
deps = [
|
| 367 |
+
":config",
|
| 368 |
+
"@com_google_googletest//:gtest",
|
| 369 |
+
"@com_google_googletest//:gtest_main",
|
| 370 |
+
],
|
| 371 |
+
)
|
| 372 |
+
|
| 373 |
+
cc_test(
|
| 374 |
+
name = "flag_test",
|
| 375 |
+
size = "small",
|
| 376 |
+
srcs = [
|
| 377 |
+
"flag_test.cc",
|
| 378 |
+
"flag_test_defs.cc",
|
| 379 |
+
],
|
| 380 |
+
copts = ABSL_TEST_COPTS,
|
| 381 |
+
linkopts = ABSL_DEFAULT_LINKOPTS,
|
| 382 |
+
tags = [
|
| 383 |
+
"no_test:os:android",
|
| 384 |
+
"no_test:os:ios",
|
| 385 |
+
"no_test_android",
|
| 386 |
+
"no_test_ios",
|
| 387 |
+
"no_test_wasm",
|
| 388 |
+
],
|
| 389 |
+
deps = [
|
| 390 |
+
":config",
|
| 391 |
+
":flag",
|
| 392 |
+
":flag_internal",
|
| 393 |
+
":marshalling",
|
| 394 |
+
":reflection",
|
| 395 |
+
"//absl/base:core_headers",
|
| 396 |
+
"//absl/base:malloc_internal",
|
| 397 |
+
"//absl/numeric:int128",
|
| 398 |
+
"//absl/strings",
|
| 399 |
+
"//absl/time",
|
| 400 |
+
"@com_google_googletest//:gtest",
|
| 401 |
+
"@com_google_googletest//:gtest_main",
|
| 402 |
+
],
|
| 403 |
+
)
|
| 404 |
+
|
| 405 |
+
cc_binary(
|
| 406 |
+
name = "flag_benchmark",
|
| 407 |
+
testonly = 1,
|
| 408 |
+
srcs = [
|
| 409 |
+
"flag_benchmark.cc",
|
| 410 |
+
],
|
| 411 |
+
copts = ABSL_TEST_COPTS,
|
| 412 |
+
linkopts = select({
|
| 413 |
+
"//conditions:default": [],
|
| 414 |
+
}) + ABSL_DEFAULT_LINKOPTS,
|
| 415 |
+
tags = ["benchmark"],
|
| 416 |
+
visibility = ["//visibility:private"],
|
| 417 |
+
deps = [
|
| 418 |
+
"flag_benchmark.lds",
|
| 419 |
+
":flag",
|
| 420 |
+
":marshalling",
|
| 421 |
+
":parse",
|
| 422 |
+
":reflection",
|
| 423 |
+
"//absl/strings",
|
| 424 |
+
"//absl/time",
|
| 425 |
+
"//absl/types:optional",
|
| 426 |
+
"@com_github_google_benchmark//:benchmark_main",
|
| 427 |
+
],
|
| 428 |
+
)
|
| 429 |
+
|
| 430 |
+
cc_test(
|
| 431 |
+
name = "marshalling_test",
|
| 432 |
+
size = "small",
|
| 433 |
+
srcs = [
|
| 434 |
+
"marshalling_test.cc",
|
| 435 |
+
],
|
| 436 |
+
copts = ABSL_TEST_COPTS,
|
| 437 |
+
linkopts = ABSL_DEFAULT_LINKOPTS,
|
| 438 |
+
deps = [
|
| 439 |
+
":marshalling",
|
| 440 |
+
"@com_google_googletest//:gtest",
|
| 441 |
+
"@com_google_googletest//:gtest_main",
|
| 442 |
+
],
|
| 443 |
+
)
|
| 444 |
+
|
| 445 |
+
cc_test(
|
| 446 |
+
name = "parse_test",
|
| 447 |
+
size = "small",
|
| 448 |
+
timeout = "moderate",
|
| 449 |
+
srcs = [
|
| 450 |
+
"parse_test.cc",
|
| 451 |
+
],
|
| 452 |
+
copts = ABSL_TEST_COPTS,
|
| 453 |
+
linkopts = ABSL_DEFAULT_LINKOPTS,
|
| 454 |
+
tags = [
|
| 455 |
+
"no_test:os:android",
|
| 456 |
+
"no_test:os:ios",
|
| 457 |
+
"no_test_android",
|
| 458 |
+
"no_test_ios",
|
| 459 |
+
"no_test_wasm",
|
| 460 |
+
],
|
| 461 |
+
deps = [
|
| 462 |
+
":flag",
|
| 463 |
+
":parse",
|
| 464 |
+
":reflection",
|
| 465 |
+
":usage_internal",
|
| 466 |
+
"//absl/base:scoped_set_env",
|
| 467 |
+
"//absl/log",
|
| 468 |
+
"//absl/strings",
|
| 469 |
+
"//absl/types:span",
|
| 470 |
+
"@com_google_googletest//:gtest",
|
| 471 |
+
"@com_google_googletest//:gtest_main",
|
| 472 |
+
],
|
| 473 |
+
)
|
| 474 |
+
|
| 475 |
+
cc_test(
|
| 476 |
+
name = "path_util_test",
|
| 477 |
+
size = "small",
|
| 478 |
+
srcs = [
|
| 479 |
+
"internal/path_util_test.cc",
|
| 480 |
+
],
|
| 481 |
+
copts = ABSL_TEST_COPTS,
|
| 482 |
+
linkopts = ABSL_DEFAULT_LINKOPTS,
|
| 483 |
+
deps = [
|
| 484 |
+
":path_util",
|
| 485 |
+
"@com_google_googletest//:gtest",
|
| 486 |
+
"@com_google_googletest//:gtest_main",
|
| 487 |
+
],
|
| 488 |
+
)
|
| 489 |
+
|
| 490 |
+
cc_test(
|
| 491 |
+
name = "program_name_test",
|
| 492 |
+
size = "small",
|
| 493 |
+
srcs = [
|
| 494 |
+
"internal/program_name_test.cc",
|
| 495 |
+
],
|
| 496 |
+
copts = ABSL_TEST_COPTS,
|
| 497 |
+
linkopts = ABSL_DEFAULT_LINKOPTS,
|
| 498 |
+
tags = ["no_test_wasm"],
|
| 499 |
+
deps = [
|
| 500 |
+
":program_name",
|
| 501 |
+
"//absl/strings",
|
| 502 |
+
"@com_google_googletest//:gtest",
|
| 503 |
+
"@com_google_googletest//:gtest_main",
|
| 504 |
+
],
|
| 505 |
+
)
|
| 506 |
+
|
| 507 |
+
cc_test(
|
| 508 |
+
name = "reflection_test",
|
| 509 |
+
size = "small",
|
| 510 |
+
srcs = [
|
| 511 |
+
"reflection_test.cc",
|
| 512 |
+
],
|
| 513 |
+
copts = ABSL_TEST_COPTS,
|
| 514 |
+
linkopts = ABSL_DEFAULT_LINKOPTS,
|
| 515 |
+
tags = [
|
| 516 |
+
"no_test:os:android",
|
| 517 |
+
"no_test:os:ios",
|
| 518 |
+
"no_test_android",
|
| 519 |
+
"no_test_ios",
|
| 520 |
+
"no_test_wasm",
|
| 521 |
+
],
|
| 522 |
+
deps = [
|
| 523 |
+
":commandlineflag_internal",
|
| 524 |
+
":flag",
|
| 525 |
+
":marshalling",
|
| 526 |
+
":reflection",
|
| 527 |
+
":usage_internal",
|
| 528 |
+
"//absl/memory",
|
| 529 |
+
"//absl/strings",
|
| 530 |
+
"@com_google_googletest//:gtest",
|
| 531 |
+
"@com_google_googletest//:gtest_main",
|
| 532 |
+
],
|
| 533 |
+
)
|
| 534 |
+
|
| 535 |
+
cc_test(
|
| 536 |
+
name = "sequence_lock_test",
|
| 537 |
+
size = "small",
|
| 538 |
+
timeout = "moderate",
|
| 539 |
+
srcs = [
|
| 540 |
+
"internal/sequence_lock_test.cc",
|
| 541 |
+
],
|
| 542 |
+
copts = ABSL_TEST_COPTS,
|
| 543 |
+
linkopts = ABSL_DEFAULT_LINKOPTS,
|
| 544 |
+
shard_count = 31,
|
| 545 |
+
tags = ["no_test_wasm"],
|
| 546 |
+
deps = [
|
| 547 |
+
":flag_internal",
|
| 548 |
+
"//absl/base",
|
| 549 |
+
"//absl/container:fixed_array",
|
| 550 |
+
"//absl/time",
|
| 551 |
+
"@com_google_googletest//:gtest",
|
| 552 |
+
"@com_google_googletest//:gtest_main",
|
| 553 |
+
],
|
| 554 |
+
)
|
| 555 |
+
|
| 556 |
+
cc_test(
|
| 557 |
+
name = "usage_config_test",
|
| 558 |
+
size = "small",
|
| 559 |
+
srcs = [
|
| 560 |
+
"usage_config_test.cc",
|
| 561 |
+
],
|
| 562 |
+
copts = ABSL_TEST_COPTS,
|
| 563 |
+
linkopts = ABSL_DEFAULT_LINKOPTS,
|
| 564 |
+
deps = [
|
| 565 |
+
":config",
|
| 566 |
+
":path_util",
|
| 567 |
+
":program_name",
|
| 568 |
+
"//absl/strings",
|
| 569 |
+
"@com_google_googletest//:gtest",
|
| 570 |
+
"@com_google_googletest//:gtest_main",
|
| 571 |
+
],
|
| 572 |
+
)
|
| 573 |
+
|
| 574 |
+
cc_test(
|
| 575 |
+
name = "usage_test",
|
| 576 |
+
size = "small",
|
| 577 |
+
srcs = [
|
| 578 |
+
"internal/usage_test.cc",
|
| 579 |
+
],
|
| 580 |
+
copts = ABSL_TEST_COPTS,
|
| 581 |
+
linkopts = ABSL_DEFAULT_LINKOPTS,
|
| 582 |
+
tags = [
|
| 583 |
+
"no_test:os:android",
|
| 584 |
+
"no_test:os:ios",
|
| 585 |
+
"no_test_android",
|
| 586 |
+
"no_test_ios",
|
| 587 |
+
"no_test_wasm",
|
| 588 |
+
],
|
| 589 |
+
deps = [
|
| 590 |
+
":config",
|
| 591 |
+
":flag",
|
| 592 |
+
":parse",
|
| 593 |
+
":path_util",
|
| 594 |
+
":program_name",
|
| 595 |
+
":reflection",
|
| 596 |
+
":usage",
|
| 597 |
+
":usage_internal",
|
| 598 |
+
"//absl/strings",
|
| 599 |
+
"@com_google_googletest//:gtest",
|
| 600 |
+
],
|
| 601 |
+
)
|
weight/_dep/abseil-cpp/absl/flags/CMakeLists.txt
ADDED
|
@@ -0,0 +1,471 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#
|
| 2 |
+
# Copyright 2019 The Abseil Authors.
|
| 3 |
+
#
|
| 4 |
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
| 5 |
+
# you may not use this file except in compliance with the License.
|
| 6 |
+
# You may obtain a copy of the License at
|
| 7 |
+
#
|
| 8 |
+
# https://www.apache.org/licenses/LICENSE-2.0
|
| 9 |
+
#
|
| 10 |
+
# Unless required by applicable law or agreed to in writing, software
|
| 11 |
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
| 12 |
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
| 13 |
+
# See the License for the specific language governing permissions and
|
| 14 |
+
# limitations under the License.
|
| 15 |
+
#
|
| 16 |
+
|
| 17 |
+
# Internal-only target, do not depend on directly.
|
| 18 |
+
absl_cc_library(
|
| 19 |
+
NAME
|
| 20 |
+
flags_path_util
|
| 21 |
+
HDRS
|
| 22 |
+
"internal/path_util.h"
|
| 23 |
+
COPTS
|
| 24 |
+
${ABSL_DEFAULT_COPTS}
|
| 25 |
+
LINKOPTS
|
| 26 |
+
${ABSL_DEFAULT_LINKOPTS}
|
| 27 |
+
DEPS
|
| 28 |
+
absl::config
|
| 29 |
+
absl::strings
|
| 30 |
+
PUBLIC
|
| 31 |
+
)
|
| 32 |
+
|
| 33 |
+
# Internal-only target, do not depend on directly.
|
| 34 |
+
absl_cc_library(
|
| 35 |
+
NAME
|
| 36 |
+
flags_program_name
|
| 37 |
+
SRCS
|
| 38 |
+
"internal/program_name.cc"
|
| 39 |
+
HDRS
|
| 40 |
+
"internal/program_name.h"
|
| 41 |
+
COPTS
|
| 42 |
+
${ABSL_DEFAULT_COPTS}
|
| 43 |
+
LINKOPTS
|
| 44 |
+
${ABSL_DEFAULT_LINKOPTS}
|
| 45 |
+
DEPS
|
| 46 |
+
absl::config
|
| 47 |
+
absl::core_headers
|
| 48 |
+
absl::flags_path_util
|
| 49 |
+
absl::strings
|
| 50 |
+
absl::synchronization
|
| 51 |
+
PUBLIC
|
| 52 |
+
)
|
| 53 |
+
|
| 54 |
+
absl_cc_library(
|
| 55 |
+
NAME
|
| 56 |
+
flags_config
|
| 57 |
+
SRCS
|
| 58 |
+
"usage_config.cc"
|
| 59 |
+
HDRS
|
| 60 |
+
"config.h"
|
| 61 |
+
"usage_config.h"
|
| 62 |
+
COPTS
|
| 63 |
+
${ABSL_DEFAULT_COPTS}
|
| 64 |
+
LINKOPTS
|
| 65 |
+
${ABSL_DEFAULT_LINKOPTS}
|
| 66 |
+
DEPS
|
| 67 |
+
absl::config
|
| 68 |
+
absl::flags_path_util
|
| 69 |
+
absl::flags_program_name
|
| 70 |
+
absl::core_headers
|
| 71 |
+
absl::strings
|
| 72 |
+
absl::synchronization
|
| 73 |
+
)
|
| 74 |
+
|
| 75 |
+
absl_cc_library(
|
| 76 |
+
NAME
|
| 77 |
+
flags_marshalling
|
| 78 |
+
SRCS
|
| 79 |
+
"marshalling.cc"
|
| 80 |
+
HDRS
|
| 81 |
+
"marshalling.h"
|
| 82 |
+
COPTS
|
| 83 |
+
${ABSL_DEFAULT_COPTS}
|
| 84 |
+
LINKOPTS
|
| 85 |
+
${ABSL_DEFAULT_LINKOPTS}
|
| 86 |
+
DEPS
|
| 87 |
+
absl::config
|
| 88 |
+
absl::core_headers
|
| 89 |
+
absl::log_severity
|
| 90 |
+
absl::int128
|
| 91 |
+
absl::optional
|
| 92 |
+
absl::strings
|
| 93 |
+
absl::str_format
|
| 94 |
+
)
|
| 95 |
+
|
| 96 |
+
# Internal-only target, do not depend on directly.
|
| 97 |
+
absl_cc_library(
|
| 98 |
+
NAME
|
| 99 |
+
flags_commandlineflag_internal
|
| 100 |
+
SRCS
|
| 101 |
+
"internal/commandlineflag.cc"
|
| 102 |
+
HDRS
|
| 103 |
+
"internal/commandlineflag.h"
|
| 104 |
+
COPTS
|
| 105 |
+
${ABSL_DEFAULT_COPTS}
|
| 106 |
+
LINKOPTS
|
| 107 |
+
${ABSL_DEFAULT_LINKOPTS}
|
| 108 |
+
DEPS
|
| 109 |
+
absl::config
|
| 110 |
+
absl::dynamic_annotations
|
| 111 |
+
absl::fast_type_id
|
| 112 |
+
)
|
| 113 |
+
|
| 114 |
+
absl_cc_library(
|
| 115 |
+
NAME
|
| 116 |
+
flags_commandlineflag
|
| 117 |
+
SRCS
|
| 118 |
+
"commandlineflag.cc"
|
| 119 |
+
HDRS
|
| 120 |
+
"commandlineflag.h"
|
| 121 |
+
COPTS
|
| 122 |
+
${ABSL_DEFAULT_COPTS}
|
| 123 |
+
LINKOPTS
|
| 124 |
+
${ABSL_DEFAULT_LINKOPTS}
|
| 125 |
+
DEPS
|
| 126 |
+
absl::config
|
| 127 |
+
absl::fast_type_id
|
| 128 |
+
absl::flags_commandlineflag_internal
|
| 129 |
+
absl::optional
|
| 130 |
+
absl::strings
|
| 131 |
+
)
|
| 132 |
+
|
| 133 |
+
# Internal-only target, do not depend on directly.
|
| 134 |
+
absl_cc_library(
|
| 135 |
+
NAME
|
| 136 |
+
flags_private_handle_accessor
|
| 137 |
+
SRCS
|
| 138 |
+
"internal/private_handle_accessor.cc"
|
| 139 |
+
HDRS
|
| 140 |
+
"internal/private_handle_accessor.h"
|
| 141 |
+
COPTS
|
| 142 |
+
${ABSL_DEFAULT_COPTS}
|
| 143 |
+
LINKOPTS
|
| 144 |
+
${ABSL_DEFAULT_LINKOPTS}
|
| 145 |
+
DEPS
|
| 146 |
+
absl::config
|
| 147 |
+
absl::flags_commandlineflag
|
| 148 |
+
absl::flags_commandlineflag_internal
|
| 149 |
+
absl::strings
|
| 150 |
+
)
|
| 151 |
+
|
| 152 |
+
absl_cc_library(
|
| 153 |
+
NAME
|
| 154 |
+
flags_reflection
|
| 155 |
+
SRCS
|
| 156 |
+
"reflection.cc"
|
| 157 |
+
HDRS
|
| 158 |
+
"reflection.h"
|
| 159 |
+
"internal/registry.h"
|
| 160 |
+
COPTS
|
| 161 |
+
${ABSL_DEFAULT_COPTS}
|
| 162 |
+
LINKOPTS
|
| 163 |
+
${ABSL_DEFAULT_LINKOPTS}
|
| 164 |
+
DEPS
|
| 165 |
+
absl::config
|
| 166 |
+
absl::flags_commandlineflag
|
| 167 |
+
absl::flags_private_handle_accessor
|
| 168 |
+
absl::flags_config
|
| 169 |
+
absl::strings
|
| 170 |
+
absl::synchronization
|
| 171 |
+
absl::flat_hash_map
|
| 172 |
+
absl::no_destructor
|
| 173 |
+
)
|
| 174 |
+
|
| 175 |
+
# Internal-only target, do not depend on directly.
|
| 176 |
+
absl_cc_library(
|
| 177 |
+
NAME
|
| 178 |
+
flags_internal
|
| 179 |
+
SRCS
|
| 180 |
+
"internal/flag.cc"
|
| 181 |
+
HDRS
|
| 182 |
+
"internal/flag.h"
|
| 183 |
+
"internal/sequence_lock.h"
|
| 184 |
+
COPTS
|
| 185 |
+
${ABSL_DEFAULT_COPTS}
|
| 186 |
+
LINKOPTS
|
| 187 |
+
${ABSL_DEFAULT_LINKOPTS}
|
| 188 |
+
DEPS
|
| 189 |
+
absl::base
|
| 190 |
+
absl::config
|
| 191 |
+
absl::flags_commandlineflag
|
| 192 |
+
absl::flags_commandlineflag_internal
|
| 193 |
+
absl::flags_config
|
| 194 |
+
absl::flags_marshalling
|
| 195 |
+
absl::synchronization
|
| 196 |
+
absl::meta
|
| 197 |
+
absl::utility
|
| 198 |
+
PUBLIC
|
| 199 |
+
)
|
| 200 |
+
|
| 201 |
+
absl_cc_library(
|
| 202 |
+
NAME
|
| 203 |
+
flags
|
| 204 |
+
HDRS
|
| 205 |
+
"declare.h"
|
| 206 |
+
"flag.h"
|
| 207 |
+
COPTS
|
| 208 |
+
${ABSL_DEFAULT_COPTS}
|
| 209 |
+
LINKOPTS
|
| 210 |
+
${ABSL_DEFAULT_LINKOPTS}
|
| 211 |
+
DEPS
|
| 212 |
+
absl::config
|
| 213 |
+
absl::flags_commandlineflag
|
| 214 |
+
absl::flags_config
|
| 215 |
+
absl::flags_internal
|
| 216 |
+
absl::flags_reflection
|
| 217 |
+
absl::base
|
| 218 |
+
absl::core_headers
|
| 219 |
+
absl::strings
|
| 220 |
+
)
|
| 221 |
+
|
| 222 |
+
# Internal-only target, do not depend on directly.
|
| 223 |
+
absl_cc_library(
|
| 224 |
+
NAME
|
| 225 |
+
flags_usage_internal
|
| 226 |
+
SRCS
|
| 227 |
+
"internal/usage.cc"
|
| 228 |
+
HDRS
|
| 229 |
+
"internal/usage.h"
|
| 230 |
+
COPTS
|
| 231 |
+
${ABSL_DEFAULT_COPTS}
|
| 232 |
+
LINKOPTS
|
| 233 |
+
${ABSL_DEFAULT_LINKOPTS}
|
| 234 |
+
DEPS
|
| 235 |
+
absl::config
|
| 236 |
+
absl::flags_config
|
| 237 |
+
absl::flags
|
| 238 |
+
absl::flags_commandlineflag
|
| 239 |
+
absl::flags_internal
|
| 240 |
+
absl::flags_path_util
|
| 241 |
+
absl::flags_private_handle_accessor
|
| 242 |
+
absl::flags_program_name
|
| 243 |
+
absl::flags_reflection
|
| 244 |
+
absl::strings
|
| 245 |
+
absl::synchronization
|
| 246 |
+
)
|
| 247 |
+
|
| 248 |
+
absl_cc_library(
|
| 249 |
+
NAME
|
| 250 |
+
flags_usage
|
| 251 |
+
SRCS
|
| 252 |
+
"usage.cc"
|
| 253 |
+
HDRS
|
| 254 |
+
"usage.h"
|
| 255 |
+
COPTS
|
| 256 |
+
${ABSL_DEFAULT_COPTS}
|
| 257 |
+
LINKOPTS
|
| 258 |
+
${ABSL_DEFAULT_LINKOPTS}
|
| 259 |
+
DEPS
|
| 260 |
+
absl::config
|
| 261 |
+
absl::core_headers
|
| 262 |
+
absl::flags_usage_internal
|
| 263 |
+
absl::raw_logging_internal
|
| 264 |
+
absl::strings
|
| 265 |
+
absl::synchronization
|
| 266 |
+
)
|
| 267 |
+
|
| 268 |
+
absl_cc_library(
|
| 269 |
+
NAME
|
| 270 |
+
flags_parse
|
| 271 |
+
SRCS
|
| 272 |
+
"parse.cc"
|
| 273 |
+
HDRS
|
| 274 |
+
"internal/parse.h"
|
| 275 |
+
"parse.h"
|
| 276 |
+
COPTS
|
| 277 |
+
${ABSL_DEFAULT_COPTS}
|
| 278 |
+
LINKOPTS
|
| 279 |
+
${ABSL_DEFAULT_LINKOPTS}
|
| 280 |
+
DEPS
|
| 281 |
+
absl::algorithm_container
|
| 282 |
+
absl::config
|
| 283 |
+
absl::core_headers
|
| 284 |
+
absl::flags_config
|
| 285 |
+
absl::flags
|
| 286 |
+
absl::flags_commandlineflag
|
| 287 |
+
absl::flags_commandlineflag_internal
|
| 288 |
+
absl::flags_internal
|
| 289 |
+
absl::flags_private_handle_accessor
|
| 290 |
+
absl::flags_program_name
|
| 291 |
+
absl::flags_reflection
|
| 292 |
+
absl::flags_usage
|
| 293 |
+
absl::strings
|
| 294 |
+
absl::synchronization
|
| 295 |
+
)
|
| 296 |
+
|
| 297 |
+
############################################################################
|
| 298 |
+
# Unit tests in alphabetical order.
|
| 299 |
+
|
| 300 |
+
absl_cc_test(
|
| 301 |
+
NAME
|
| 302 |
+
flags_commandlineflag_test
|
| 303 |
+
SRCS
|
| 304 |
+
"commandlineflag_test.cc"
|
| 305 |
+
COPTS
|
| 306 |
+
${ABSL_TEST_COPTS}
|
| 307 |
+
DEPS
|
| 308 |
+
absl::flags
|
| 309 |
+
absl::flags_commandlineflag
|
| 310 |
+
absl::flags_commandlineflag_internal
|
| 311 |
+
absl::flags_config
|
| 312 |
+
absl::flags_private_handle_accessor
|
| 313 |
+
absl::flags_reflection
|
| 314 |
+
absl::memory
|
| 315 |
+
absl::strings
|
| 316 |
+
GTest::gtest_main
|
| 317 |
+
)
|
| 318 |
+
|
| 319 |
+
absl_cc_test(
|
| 320 |
+
NAME
|
| 321 |
+
flags_config_test
|
| 322 |
+
SRCS
|
| 323 |
+
"config_test.cc"
|
| 324 |
+
COPTS
|
| 325 |
+
${ABSL_TEST_COPTS}
|
| 326 |
+
DEPS
|
| 327 |
+
absl::flags_config
|
| 328 |
+
GTest::gtest_main
|
| 329 |
+
)
|
| 330 |
+
|
| 331 |
+
absl_cc_test(
|
| 332 |
+
NAME
|
| 333 |
+
flags_flag_test
|
| 334 |
+
SRCS
|
| 335 |
+
"flag_test.cc"
|
| 336 |
+
"flag_test_defs.cc"
|
| 337 |
+
COPTS
|
| 338 |
+
${ABSL_TEST_COPTS}
|
| 339 |
+
DEPS
|
| 340 |
+
absl::core_headers
|
| 341 |
+
absl::flags
|
| 342 |
+
absl::flags_config
|
| 343 |
+
absl::flags_internal
|
| 344 |
+
absl::flags_marshalling
|
| 345 |
+
absl::flags_reflection
|
| 346 |
+
absl::int128
|
| 347 |
+
absl::strings
|
| 348 |
+
absl::time
|
| 349 |
+
GTest::gtest_main
|
| 350 |
+
)
|
| 351 |
+
|
| 352 |
+
absl_cc_test(
|
| 353 |
+
NAME
|
| 354 |
+
flags_marshalling_test
|
| 355 |
+
SRCS
|
| 356 |
+
"marshalling_test.cc"
|
| 357 |
+
COPTS
|
| 358 |
+
${ABSL_TEST_COPTS}
|
| 359 |
+
DEPS
|
| 360 |
+
absl::flags_marshalling
|
| 361 |
+
GTest::gtest_main
|
| 362 |
+
)
|
| 363 |
+
|
| 364 |
+
absl_cc_test(
|
| 365 |
+
NAME
|
| 366 |
+
flags_parse_test
|
| 367 |
+
SRCS
|
| 368 |
+
"parse_test.cc"
|
| 369 |
+
COPTS
|
| 370 |
+
${ABSL_TEST_COPTS}
|
| 371 |
+
DEPS
|
| 372 |
+
absl::flags
|
| 373 |
+
absl::flags_parse
|
| 374 |
+
absl::flags_reflection
|
| 375 |
+
absl::flags_usage_internal
|
| 376 |
+
absl::log
|
| 377 |
+
absl::scoped_set_env
|
| 378 |
+
absl::span
|
| 379 |
+
absl::strings
|
| 380 |
+
GTest::gmock_main
|
| 381 |
+
)
|
| 382 |
+
|
| 383 |
+
absl_cc_test(
|
| 384 |
+
NAME
|
| 385 |
+
flags_path_util_test
|
| 386 |
+
SRCS
|
| 387 |
+
"internal/path_util_test.cc"
|
| 388 |
+
COPTS
|
| 389 |
+
${ABSL_TEST_COPTS}
|
| 390 |
+
DEPS
|
| 391 |
+
absl::flags_path_util
|
| 392 |
+
GTest::gtest_main
|
| 393 |
+
)
|
| 394 |
+
|
| 395 |
+
absl_cc_test(
|
| 396 |
+
NAME
|
| 397 |
+
flags_program_name_test
|
| 398 |
+
SRCS
|
| 399 |
+
"internal/program_name_test.cc"
|
| 400 |
+
COPTS
|
| 401 |
+
${ABSL_TEST_COPTS}
|
| 402 |
+
DEPS
|
| 403 |
+
absl::flags_program_name
|
| 404 |
+
absl::strings
|
| 405 |
+
GTest::gtest_main
|
| 406 |
+
)
|
| 407 |
+
|
| 408 |
+
absl_cc_test(
|
| 409 |
+
NAME
|
| 410 |
+
flags_reflection_test
|
| 411 |
+
SRCS
|
| 412 |
+
"reflection_test.cc"
|
| 413 |
+
COPTS
|
| 414 |
+
${ABSL_TEST_COPTS}
|
| 415 |
+
DEPS
|
| 416 |
+
absl::flags_commandlineflag_internal
|
| 417 |
+
absl::flags
|
| 418 |
+
absl::flags_reflection
|
| 419 |
+
absl::flags_usage
|
| 420 |
+
absl::memory
|
| 421 |
+
absl::strings
|
| 422 |
+
GTest::gmock_main
|
| 423 |
+
)
|
| 424 |
+
|
| 425 |
+
absl_cc_test(
|
| 426 |
+
NAME
|
| 427 |
+
flags_sequence_lock_test
|
| 428 |
+
SRCS
|
| 429 |
+
"internal/sequence_lock_test.cc"
|
| 430 |
+
COPTS
|
| 431 |
+
${ABSL_TEST_COPTS}
|
| 432 |
+
DEPS
|
| 433 |
+
absl::base
|
| 434 |
+
absl::flags_internal
|
| 435 |
+
absl::time
|
| 436 |
+
GTest::gmock_main
|
| 437 |
+
)
|
| 438 |
+
|
| 439 |
+
absl_cc_test(
|
| 440 |
+
NAME
|
| 441 |
+
flags_usage_config_test
|
| 442 |
+
SRCS
|
| 443 |
+
"usage_config_test.cc"
|
| 444 |
+
COPTS
|
| 445 |
+
${ABSL_TEST_COPTS}
|
| 446 |
+
DEPS
|
| 447 |
+
absl::flags_config
|
| 448 |
+
absl::flags_path_util
|
| 449 |
+
absl::flags_program_name
|
| 450 |
+
absl::strings
|
| 451 |
+
GTest::gtest_main
|
| 452 |
+
)
|
| 453 |
+
|
| 454 |
+
absl_cc_test(
|
| 455 |
+
NAME
|
| 456 |
+
flags_usage_test
|
| 457 |
+
SRCS
|
| 458 |
+
"internal/usage_test.cc"
|
| 459 |
+
COPTS
|
| 460 |
+
${ABSL_TEST_COPTS}
|
| 461 |
+
DEPS
|
| 462 |
+
absl::flags_config
|
| 463 |
+
absl::flags
|
| 464 |
+
absl::flags_path_util
|
| 465 |
+
absl::flags_program_name
|
| 466 |
+
absl::flags_parse
|
| 467 |
+
absl::flags_reflection
|
| 468 |
+
absl::flags_usage
|
| 469 |
+
absl::strings
|
| 470 |
+
GTest::gmock
|
| 471 |
+
)
|
weight/_dep/abseil-cpp/absl/flags/commandlineflag.cc
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
//
|
| 2 |
+
// Copyright 2020 The Abseil Authors.
|
| 3 |
+
//
|
| 4 |
+
// Licensed under the Apache License, Version 2.0 (the "License");
|
| 5 |
+
// you may not use this file except in compliance with the License.
|
| 6 |
+
// You may obtain a copy of the License at
|
| 7 |
+
//
|
| 8 |
+
// https://www.apache.org/licenses/LICENSE-2.0
|
| 9 |
+
//
|
| 10 |
+
// Unless required by applicable law or agreed to in writing, software
|
| 11 |
+
// distributed under the License is distributed on an "AS IS" BASIS,
|
| 12 |
+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
| 13 |
+
// See the License for the specific language governing permissions and
|
| 14 |
+
// limitations under the License.
|
| 15 |
+
|
| 16 |
+
#include "absl/flags/commandlineflag.h"
|
| 17 |
+
|
| 18 |
+
#include <string>
|
| 19 |
+
|
| 20 |
+
#include "absl/base/config.h"
|
| 21 |
+
#include "absl/flags/internal/commandlineflag.h"
|
| 22 |
+
#include "absl/strings/string_view.h"
|
| 23 |
+
|
| 24 |
+
namespace absl {
|
| 25 |
+
ABSL_NAMESPACE_BEGIN
|
| 26 |
+
|
| 27 |
+
bool CommandLineFlag::IsRetired() const { return false; }
|
| 28 |
+
bool CommandLineFlag::ParseFrom(absl::string_view value, std::string* error) {
|
| 29 |
+
return ParseFrom(value, flags_internal::SET_FLAGS_VALUE,
|
| 30 |
+
flags_internal::kProgrammaticChange, *error);
|
| 31 |
+
}
|
| 32 |
+
|
| 33 |
+
ABSL_NAMESPACE_END
|
| 34 |
+
} // namespace absl
|
weight/_dep/abseil-cpp/absl/flags/commandlineflag.h
ADDED
|
@@ -0,0 +1,200 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
//
|
| 2 |
+
// Copyright 2020 The Abseil Authors.
|
| 3 |
+
//
|
| 4 |
+
// Licensed under the Apache License, Version 2.0 (the "License");
|
| 5 |
+
// you may not use this file except in compliance with the License.
|
| 6 |
+
// You may obtain a copy of the License at
|
| 7 |
+
//
|
| 8 |
+
// https://www.apache.org/licenses/LICENSE-2.0
|
| 9 |
+
//
|
| 10 |
+
// Unless required by applicable law or agreed to in writing, software
|
| 11 |
+
// distributed under the License is distributed on an "AS IS" BASIS,
|
| 12 |
+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
| 13 |
+
// See the License for the specific language governing permissions and
|
| 14 |
+
// limitations under the License.
|
| 15 |
+
//
|
| 16 |
+
// -----------------------------------------------------------------------------
|
| 17 |
+
// File: commandlineflag.h
|
| 18 |
+
// -----------------------------------------------------------------------------
|
| 19 |
+
//
|
| 20 |
+
// This header file defines the `CommandLineFlag`, which acts as a type-erased
|
| 21 |
+
// handle for accessing metadata about the Abseil Flag in question.
|
| 22 |
+
//
|
| 23 |
+
// Because an actual Abseil flag is of an unspecified type, you should not
|
| 24 |
+
// manipulate or interact directly with objects of that type. Instead, use the
|
| 25 |
+
// CommandLineFlag type as an intermediary.
|
| 26 |
+
#ifndef ABSL_FLAGS_COMMANDLINEFLAG_H_
|
| 27 |
+
#define ABSL_FLAGS_COMMANDLINEFLAG_H_
|
| 28 |
+
|
| 29 |
+
#include <memory>
|
| 30 |
+
#include <string>
|
| 31 |
+
|
| 32 |
+
#include "absl/base/config.h"
|
| 33 |
+
#include "absl/base/internal/fast_type_id.h"
|
| 34 |
+
#include "absl/flags/internal/commandlineflag.h"
|
| 35 |
+
#include "absl/strings/string_view.h"
|
| 36 |
+
#include "absl/types/optional.h"
|
| 37 |
+
|
| 38 |
+
namespace absl {
|
| 39 |
+
ABSL_NAMESPACE_BEGIN
|
| 40 |
+
namespace flags_internal {
|
| 41 |
+
class PrivateHandleAccessor;
|
| 42 |
+
} // namespace flags_internal
|
| 43 |
+
|
| 44 |
+
// CommandLineFlag
|
| 45 |
+
//
|
| 46 |
+
// This type acts as a type-erased handle for an instance of an Abseil Flag and
|
| 47 |
+
// holds reflection information pertaining to that flag. Use CommandLineFlag to
|
| 48 |
+
// access a flag's name, location, help string etc.
|
| 49 |
+
//
|
| 50 |
+
// To obtain an absl::CommandLineFlag, invoke `absl::FindCommandLineFlag()`
|
| 51 |
+
// passing it the flag name string.
|
| 52 |
+
//
|
| 53 |
+
// Example:
|
| 54 |
+
//
|
| 55 |
+
// // Obtain reflection handle for a flag named "flagname".
|
| 56 |
+
// const absl::CommandLineFlag* my_flag_data =
|
| 57 |
+
// absl::FindCommandLineFlag("flagname");
|
| 58 |
+
//
|
| 59 |
+
// // Now you can get flag info from that reflection handle.
|
| 60 |
+
// std::string flag_location = my_flag_data->Filename();
|
| 61 |
+
// ...
|
| 62 |
+
class CommandLineFlag {
|
| 63 |
+
public:
|
| 64 |
+
constexpr CommandLineFlag() = default;
|
| 65 |
+
|
| 66 |
+
// Not copyable/assignable.
|
| 67 |
+
CommandLineFlag(const CommandLineFlag&) = delete;
|
| 68 |
+
CommandLineFlag& operator=(const CommandLineFlag&) = delete;
|
| 69 |
+
|
| 70 |
+
// absl::CommandLineFlag::IsOfType()
|
| 71 |
+
//
|
| 72 |
+
// Return true iff flag has type T.
|
| 73 |
+
template <typename T>
|
| 74 |
+
inline bool IsOfType() const {
|
| 75 |
+
return TypeId() == base_internal::FastTypeId<T>();
|
| 76 |
+
}
|
| 77 |
+
|
| 78 |
+
// absl::CommandLineFlag::TryGet()
|
| 79 |
+
//
|
| 80 |
+
// Attempts to retrieve the flag value. Returns value on success,
|
| 81 |
+
// absl::nullopt otherwise.
|
| 82 |
+
template <typename T>
|
| 83 |
+
absl::optional<T> TryGet() const {
|
| 84 |
+
if (IsRetired() || !IsOfType<T>()) {
|
| 85 |
+
return absl::nullopt;
|
| 86 |
+
}
|
| 87 |
+
|
| 88 |
+
// Implementation notes:
|
| 89 |
+
//
|
| 90 |
+
// We are wrapping a union around the value of `T` to serve three purposes:
|
| 91 |
+
//
|
| 92 |
+
// 1. `U.value` has correct size and alignment for a value of type `T`
|
| 93 |
+
// 2. The `U.value` constructor is not invoked since U's constructor does
|
| 94 |
+
// not do it explicitly.
|
| 95 |
+
// 3. The `U.value` destructor is invoked since U's destructor does it
|
| 96 |
+
// explicitly. This makes `U` a kind of RAII wrapper around non default
|
| 97 |
+
// constructible value of T, which is destructed when we leave the
|
| 98 |
+
// scope. We do need to destroy U.value, which is constructed by
|
| 99 |
+
// CommandLineFlag::Read even though we left it in a moved-from state
|
| 100 |
+
// after std::move.
|
| 101 |
+
//
|
| 102 |
+
// All of this serves to avoid requiring `T` being default constructible.
|
| 103 |
+
union U {
|
| 104 |
+
T value;
|
| 105 |
+
U() {}
|
| 106 |
+
~U() { value.~T(); }
|
| 107 |
+
};
|
| 108 |
+
U u;
|
| 109 |
+
|
| 110 |
+
Read(&u.value);
|
| 111 |
+
// allow retired flags to be "read", so we can report invalid access.
|
| 112 |
+
if (IsRetired()) {
|
| 113 |
+
return absl::nullopt;
|
| 114 |
+
}
|
| 115 |
+
return std::move(u.value);
|
| 116 |
+
}
|
| 117 |
+
|
| 118 |
+
// absl::CommandLineFlag::Name()
|
| 119 |
+
//
|
| 120 |
+
// Returns name of this flag.
|
| 121 |
+
virtual absl::string_view Name() const = 0;
|
| 122 |
+
|
| 123 |
+
// absl::CommandLineFlag::Filename()
|
| 124 |
+
//
|
| 125 |
+
// Returns name of the file where this flag is defined.
|
| 126 |
+
virtual std::string Filename() const = 0;
|
| 127 |
+
|
| 128 |
+
// absl::CommandLineFlag::Help()
|
| 129 |
+
//
|
| 130 |
+
// Returns help message associated with this flag.
|
| 131 |
+
virtual std::string Help() const = 0;
|
| 132 |
+
|
| 133 |
+
// absl::CommandLineFlag::IsRetired()
|
| 134 |
+
//
|
| 135 |
+
// Returns true iff this object corresponds to retired flag.
|
| 136 |
+
virtual bool IsRetired() const;
|
| 137 |
+
|
| 138 |
+
// absl::CommandLineFlag::DefaultValue()
|
| 139 |
+
//
|
| 140 |
+
// Returns the default value for this flag.
|
| 141 |
+
virtual std::string DefaultValue() const = 0;
|
| 142 |
+
|
| 143 |
+
// absl::CommandLineFlag::CurrentValue()
|
| 144 |
+
//
|
| 145 |
+
// Returns the current value for this flag.
|
| 146 |
+
virtual std::string CurrentValue() const = 0;
|
| 147 |
+
|
| 148 |
+
// absl::CommandLineFlag::ParseFrom()
|
| 149 |
+
//
|
| 150 |
+
// Sets the value of the flag based on specified string `value`. If the flag
|
| 151 |
+
// was successfully set to new value, it returns true. Otherwise, sets `error`
|
| 152 |
+
// to indicate the error, leaves the flag unchanged, and returns false.
|
| 153 |
+
bool ParseFrom(absl::string_view value, std::string* error);
|
| 154 |
+
|
| 155 |
+
protected:
|
| 156 |
+
~CommandLineFlag() = default;
|
| 157 |
+
|
| 158 |
+
private:
|
| 159 |
+
friend class flags_internal::PrivateHandleAccessor;
|
| 160 |
+
|
| 161 |
+
// Sets the value of the flag based on specified string `value`. If the flag
|
| 162 |
+
// was successfully set to new value, it returns true. Otherwise, sets `error`
|
| 163 |
+
// to indicate the error, leaves the flag unchanged, and returns false. There
|
| 164 |
+
// are three ways to set the flag's value:
|
| 165 |
+
// * Update the current flag value
|
| 166 |
+
// * Update the flag's default value
|
| 167 |
+
// * Update the current flag value if it was never set before
|
| 168 |
+
// The mode is selected based on `set_mode` parameter.
|
| 169 |
+
virtual bool ParseFrom(absl::string_view value,
|
| 170 |
+
flags_internal::FlagSettingMode set_mode,
|
| 171 |
+
flags_internal::ValueSource source,
|
| 172 |
+
std::string& error) = 0;
|
| 173 |
+
|
| 174 |
+
// Returns id of the flag's value type.
|
| 175 |
+
virtual flags_internal::FlagFastTypeId TypeId() const = 0;
|
| 176 |
+
|
| 177 |
+
// Interface to save flag to some persistent state. Returns current flag state
|
| 178 |
+
// or nullptr if flag does not support saving and restoring a state.
|
| 179 |
+
virtual std::unique_ptr<flags_internal::FlagStateInterface> SaveState() = 0;
|
| 180 |
+
|
| 181 |
+
// Copy-construct a new value of the flag's type in a memory referenced by
|
| 182 |
+
// the dst based on the current flag's value.
|
| 183 |
+
virtual void Read(void* dst) const = 0;
|
| 184 |
+
|
| 185 |
+
// To be deleted. Used to return true if flag's current value originated from
|
| 186 |
+
// command line.
|
| 187 |
+
virtual bool IsSpecifiedOnCommandLine() const = 0;
|
| 188 |
+
|
| 189 |
+
// Validates supplied value using validator or parseflag routine
|
| 190 |
+
virtual bool ValidateInputValue(absl::string_view value) const = 0;
|
| 191 |
+
|
| 192 |
+
// Checks that flags default value can be converted to string and back to the
|
| 193 |
+
// flag's value type.
|
| 194 |
+
virtual void CheckDefaultValueParsingRoundtrip() const = 0;
|
| 195 |
+
};
|
| 196 |
+
|
| 197 |
+
ABSL_NAMESPACE_END
|
| 198 |
+
} // namespace absl
|
| 199 |
+
|
| 200 |
+
#endif // ABSL_FLAGS_COMMANDLINEFLAG_H_
|
weight/_dep/abseil-cpp/absl/flags/commandlineflag_test.cc
ADDED
|
@@ -0,0 +1,231 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
//
|
| 2 |
+
// Copyright 2019 The Abseil Authors.
|
| 3 |
+
//
|
| 4 |
+
// Licensed under the Apache License, Version 2.0 (the "License");
|
| 5 |
+
// you may not use this file except in compliance with the License.
|
| 6 |
+
// You may obtain a copy of the License at
|
| 7 |
+
//
|
| 8 |
+
// https://www.apache.org/licenses/LICENSE-2.0
|
| 9 |
+
//
|
| 10 |
+
// Unless required by applicable law or agreed to in writing, software
|
| 11 |
+
// distributed under the License is distributed on an "AS IS" BASIS,
|
| 12 |
+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
| 13 |
+
// See the License for the specific language governing permissions and
|
| 14 |
+
// limitations under the License.
|
| 15 |
+
|
| 16 |
+
#include "absl/flags/commandlineflag.h"
|
| 17 |
+
|
| 18 |
+
#include <memory>
|
| 19 |
+
#include <string>
|
| 20 |
+
|
| 21 |
+
#include "gtest/gtest.h"
|
| 22 |
+
#include "absl/flags/flag.h"
|
| 23 |
+
#include "absl/flags/internal/commandlineflag.h"
|
| 24 |
+
#include "absl/flags/internal/private_handle_accessor.h"
|
| 25 |
+
#include "absl/flags/reflection.h"
|
| 26 |
+
#include "absl/flags/usage_config.h"
|
| 27 |
+
#include "absl/memory/memory.h"
|
| 28 |
+
#include "absl/strings/match.h"
|
| 29 |
+
#include "absl/strings/str_cat.h"
|
| 30 |
+
#include "absl/strings/string_view.h"
|
| 31 |
+
|
| 32 |
+
ABSL_FLAG(int, int_flag, 201, "int_flag help");
|
| 33 |
+
ABSL_FLAG(std::string, string_flag, "dflt",
|
| 34 |
+
absl::StrCat("string_flag", " help"));
|
| 35 |
+
ABSL_RETIRED_FLAG(bool, bool_retired_flag, false, "bool_retired_flag help");
|
| 36 |
+
|
| 37 |
+
// These are only used to test default values.
|
| 38 |
+
ABSL_FLAG(int, int_flag2, 201, "");
|
| 39 |
+
ABSL_FLAG(std::string, string_flag2, "dflt", "");
|
| 40 |
+
|
| 41 |
+
namespace {
|
| 42 |
+
|
| 43 |
+
namespace flags = absl::flags_internal;
|
| 44 |
+
|
| 45 |
+
class CommandLineFlagTest : public testing::Test {
|
| 46 |
+
protected:
|
| 47 |
+
static void SetUpTestSuite() {
|
| 48 |
+
// Install a function to normalize filenames before this test is run.
|
| 49 |
+
absl::FlagsUsageConfig default_config;
|
| 50 |
+
default_config.normalize_filename = &CommandLineFlagTest::NormalizeFileName;
|
| 51 |
+
absl::SetFlagsUsageConfig(default_config);
|
| 52 |
+
}
|
| 53 |
+
|
| 54 |
+
void SetUp() override { flag_saver_ = absl::make_unique<absl::FlagSaver>(); }
|
| 55 |
+
void TearDown() override { flag_saver_.reset(); }
|
| 56 |
+
|
| 57 |
+
private:
|
| 58 |
+
static std::string NormalizeFileName(absl::string_view fname) {
|
| 59 |
+
#ifdef _WIN32
|
| 60 |
+
std::string normalized(fname);
|
| 61 |
+
std::replace(normalized.begin(), normalized.end(), '\\', '/');
|
| 62 |
+
fname = normalized;
|
| 63 |
+
#endif
|
| 64 |
+
return std::string(fname);
|
| 65 |
+
}
|
| 66 |
+
|
| 67 |
+
std::unique_ptr<absl::FlagSaver> flag_saver_;
|
| 68 |
+
};
|
| 69 |
+
|
| 70 |
+
TEST_F(CommandLineFlagTest, TestAttributesAccessMethods) {
|
| 71 |
+
auto* flag_01 = absl::FindCommandLineFlag("int_flag");
|
| 72 |
+
|
| 73 |
+
ASSERT_TRUE(flag_01);
|
| 74 |
+
EXPECT_EQ(flag_01->Name(), "int_flag");
|
| 75 |
+
EXPECT_EQ(flag_01->Help(), "int_flag help");
|
| 76 |
+
EXPECT_TRUE(!flag_01->IsRetired());
|
| 77 |
+
EXPECT_TRUE(flag_01->IsOfType<int>());
|
| 78 |
+
EXPECT_TRUE(!flag_01->IsOfType<bool>());
|
| 79 |
+
EXPECT_TRUE(!flag_01->IsOfType<std::string>());
|
| 80 |
+
EXPECT_TRUE(absl::EndsWith(flag_01->Filename(),
|
| 81 |
+
"absl/flags/commandlineflag_test.cc"))
|
| 82 |
+
<< flag_01->Filename();
|
| 83 |
+
|
| 84 |
+
auto* flag_02 = absl::FindCommandLineFlag("string_flag");
|
| 85 |
+
|
| 86 |
+
ASSERT_TRUE(flag_02);
|
| 87 |
+
EXPECT_EQ(flag_02->Name(), "string_flag");
|
| 88 |
+
EXPECT_EQ(flag_02->Help(), "string_flag help");
|
| 89 |
+
EXPECT_TRUE(!flag_02->IsRetired());
|
| 90 |
+
EXPECT_TRUE(flag_02->IsOfType<std::string>());
|
| 91 |
+
EXPECT_TRUE(!flag_02->IsOfType<bool>());
|
| 92 |
+
EXPECT_TRUE(!flag_02->IsOfType<int>());
|
| 93 |
+
EXPECT_TRUE(absl::EndsWith(flag_02->Filename(),
|
| 94 |
+
"absl/flags/commandlineflag_test.cc"))
|
| 95 |
+
<< flag_02->Filename();
|
| 96 |
+
}
|
| 97 |
+
|
| 98 |
+
// --------------------------------------------------------------------
|
| 99 |
+
|
| 100 |
+
TEST_F(CommandLineFlagTest, TestValueAccessMethods) {
|
| 101 |
+
absl::SetFlag(&FLAGS_int_flag2, 301);
|
| 102 |
+
auto* flag_01 = absl::FindCommandLineFlag("int_flag2");
|
| 103 |
+
|
| 104 |
+
ASSERT_TRUE(flag_01);
|
| 105 |
+
EXPECT_EQ(flag_01->CurrentValue(), "301");
|
| 106 |
+
EXPECT_EQ(flag_01->DefaultValue(), "201");
|
| 107 |
+
|
| 108 |
+
absl::SetFlag(&FLAGS_string_flag2, "new_str_value");
|
| 109 |
+
auto* flag_02 = absl::FindCommandLineFlag("string_flag2");
|
| 110 |
+
|
| 111 |
+
ASSERT_TRUE(flag_02);
|
| 112 |
+
EXPECT_EQ(flag_02->CurrentValue(), "new_str_value");
|
| 113 |
+
EXPECT_EQ(flag_02->DefaultValue(), "dflt");
|
| 114 |
+
}
|
| 115 |
+
|
| 116 |
+
// --------------------------------------------------------------------
|
| 117 |
+
|
| 118 |
+
TEST_F(CommandLineFlagTest, TestParseFromCurrentValue) {
|
| 119 |
+
std::string err;
|
| 120 |
+
|
| 121 |
+
auto* flag_01 = absl::FindCommandLineFlag("int_flag");
|
| 122 |
+
EXPECT_FALSE(
|
| 123 |
+
flags::PrivateHandleAccessor::IsSpecifiedOnCommandLine(*flag_01));
|
| 124 |
+
|
| 125 |
+
EXPECT_TRUE(flags::PrivateHandleAccessor::ParseFrom(
|
| 126 |
+
*flag_01, "11", flags::SET_FLAGS_VALUE, flags::kProgrammaticChange, err));
|
| 127 |
+
EXPECT_EQ(absl::GetFlag(FLAGS_int_flag), 11);
|
| 128 |
+
EXPECT_FALSE(
|
| 129 |
+
flags::PrivateHandleAccessor::IsSpecifiedOnCommandLine(*flag_01));
|
| 130 |
+
|
| 131 |
+
EXPECT_TRUE(flags::PrivateHandleAccessor::ParseFrom(
|
| 132 |
+
*flag_01, "-123", flags::SET_FLAGS_VALUE, flags::kProgrammaticChange,
|
| 133 |
+
err));
|
| 134 |
+
EXPECT_EQ(absl::GetFlag(FLAGS_int_flag), -123);
|
| 135 |
+
EXPECT_FALSE(
|
| 136 |
+
flags::PrivateHandleAccessor::IsSpecifiedOnCommandLine(*flag_01));
|
| 137 |
+
|
| 138 |
+
EXPECT_TRUE(!flags::PrivateHandleAccessor::ParseFrom(
|
| 139 |
+
*flag_01, "xyz", flags::SET_FLAGS_VALUE, flags::kProgrammaticChange,
|
| 140 |
+
err));
|
| 141 |
+
EXPECT_EQ(absl::GetFlag(FLAGS_int_flag), -123);
|
| 142 |
+
EXPECT_EQ(err, "Illegal value 'xyz' specified for flag 'int_flag'");
|
| 143 |
+
EXPECT_FALSE(
|
| 144 |
+
flags::PrivateHandleAccessor::IsSpecifiedOnCommandLine(*flag_01));
|
| 145 |
+
|
| 146 |
+
EXPECT_TRUE(!flags::PrivateHandleAccessor::ParseFrom(
|
| 147 |
+
*flag_01, "A1", flags::SET_FLAGS_VALUE, flags::kProgrammaticChange, err));
|
| 148 |
+
EXPECT_EQ(absl::GetFlag(FLAGS_int_flag), -123);
|
| 149 |
+
EXPECT_EQ(err, "Illegal value 'A1' specified for flag 'int_flag'");
|
| 150 |
+
EXPECT_FALSE(
|
| 151 |
+
flags::PrivateHandleAccessor::IsSpecifiedOnCommandLine(*flag_01));
|
| 152 |
+
|
| 153 |
+
EXPECT_TRUE(flags::PrivateHandleAccessor::ParseFrom(
|
| 154 |
+
*flag_01, "0x10", flags::SET_FLAGS_VALUE, flags::kProgrammaticChange,
|
| 155 |
+
err));
|
| 156 |
+
EXPECT_EQ(absl::GetFlag(FLAGS_int_flag), 16);
|
| 157 |
+
EXPECT_FALSE(
|
| 158 |
+
flags::PrivateHandleAccessor::IsSpecifiedOnCommandLine(*flag_01));
|
| 159 |
+
|
| 160 |
+
EXPECT_TRUE(flags::PrivateHandleAccessor::ParseFrom(
|
| 161 |
+
*flag_01, "011", flags::SET_FLAGS_VALUE, flags::kCommandLine, err));
|
| 162 |
+
EXPECT_EQ(absl::GetFlag(FLAGS_int_flag), 11);
|
| 163 |
+
EXPECT_TRUE(flags::PrivateHandleAccessor::IsSpecifiedOnCommandLine(*flag_01));
|
| 164 |
+
|
| 165 |
+
EXPECT_TRUE(!flags::PrivateHandleAccessor::ParseFrom(
|
| 166 |
+
*flag_01, "", flags::SET_FLAGS_VALUE, flags::kProgrammaticChange, err));
|
| 167 |
+
EXPECT_EQ(err, "Illegal value '' specified for flag 'int_flag'");
|
| 168 |
+
|
| 169 |
+
auto* flag_02 = absl::FindCommandLineFlag("string_flag");
|
| 170 |
+
EXPECT_TRUE(flags::PrivateHandleAccessor::ParseFrom(
|
| 171 |
+
*flag_02, "xyz", flags::SET_FLAGS_VALUE, flags::kProgrammaticChange,
|
| 172 |
+
err));
|
| 173 |
+
EXPECT_EQ(absl::GetFlag(FLAGS_string_flag), "xyz");
|
| 174 |
+
|
| 175 |
+
EXPECT_TRUE(flags::PrivateHandleAccessor::ParseFrom(
|
| 176 |
+
*flag_02, "", flags::SET_FLAGS_VALUE, flags::kProgrammaticChange, err));
|
| 177 |
+
EXPECT_EQ(absl::GetFlag(FLAGS_string_flag), "");
|
| 178 |
+
}
|
| 179 |
+
|
| 180 |
+
// --------------------------------------------------------------------
|
| 181 |
+
|
| 182 |
+
TEST_F(CommandLineFlagTest, TestParseFromDefaultValue) {
|
| 183 |
+
std::string err;
|
| 184 |
+
|
| 185 |
+
auto* flag_01 = absl::FindCommandLineFlag("int_flag");
|
| 186 |
+
|
| 187 |
+
EXPECT_TRUE(flags::PrivateHandleAccessor::ParseFrom(
|
| 188 |
+
*flag_01, "111", flags::SET_FLAGS_DEFAULT, flags::kProgrammaticChange,
|
| 189 |
+
err));
|
| 190 |
+
EXPECT_EQ(flag_01->DefaultValue(), "111");
|
| 191 |
+
|
| 192 |
+
auto* flag_02 = absl::FindCommandLineFlag("string_flag");
|
| 193 |
+
|
| 194 |
+
EXPECT_TRUE(flags::PrivateHandleAccessor::ParseFrom(
|
| 195 |
+
*flag_02, "abc", flags::SET_FLAGS_DEFAULT, flags::kProgrammaticChange,
|
| 196 |
+
err));
|
| 197 |
+
EXPECT_EQ(flag_02->DefaultValue(), "abc");
|
| 198 |
+
}
|
| 199 |
+
|
| 200 |
+
// --------------------------------------------------------------------
|
| 201 |
+
|
| 202 |
+
TEST_F(CommandLineFlagTest, TestParseFromIfDefault) {
|
| 203 |
+
std::string err;
|
| 204 |
+
|
| 205 |
+
auto* flag_01 = absl::FindCommandLineFlag("int_flag");
|
| 206 |
+
|
| 207 |
+
EXPECT_TRUE(flags::PrivateHandleAccessor::ParseFrom(
|
| 208 |
+
*flag_01, "22", flags::SET_FLAG_IF_DEFAULT, flags::kProgrammaticChange,
|
| 209 |
+
err))
|
| 210 |
+
<< err;
|
| 211 |
+
EXPECT_EQ(absl::GetFlag(FLAGS_int_flag), 22);
|
| 212 |
+
|
| 213 |
+
EXPECT_TRUE(flags::PrivateHandleAccessor::ParseFrom(
|
| 214 |
+
*flag_01, "33", flags::SET_FLAG_IF_DEFAULT, flags::kProgrammaticChange,
|
| 215 |
+
err));
|
| 216 |
+
EXPECT_EQ(absl::GetFlag(FLAGS_int_flag), 22);
|
| 217 |
+
// EXPECT_EQ(err, "ERROR: int_flag is already set to 22");
|
| 218 |
+
|
| 219 |
+
// Reset back to default value
|
| 220 |
+
EXPECT_TRUE(flags::PrivateHandleAccessor::ParseFrom(
|
| 221 |
+
*flag_01, "201", flags::SET_FLAGS_VALUE, flags::kProgrammaticChange,
|
| 222 |
+
err));
|
| 223 |
+
|
| 224 |
+
EXPECT_TRUE(flags::PrivateHandleAccessor::ParseFrom(
|
| 225 |
+
*flag_01, "33", flags::SET_FLAG_IF_DEFAULT, flags::kProgrammaticChange,
|
| 226 |
+
err));
|
| 227 |
+
EXPECT_EQ(absl::GetFlag(FLAGS_int_flag), 201);
|
| 228 |
+
// EXPECT_EQ(err, "ERROR: int_flag is already set to 201");
|
| 229 |
+
}
|
| 230 |
+
|
| 231 |
+
} // namespace
|
weight/_dep/abseil-cpp/absl/flags/config.h
ADDED
|
@@ -0,0 +1,68 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
//
|
| 2 |
+
// Copyright 2019 The Abseil Authors.
|
| 3 |
+
//
|
| 4 |
+
// Licensed under the Apache License, Version 2.0 (the "License");
|
| 5 |
+
// you may not use this file except in compliance with the License.
|
| 6 |
+
// You may obtain a copy of the License at
|
| 7 |
+
//
|
| 8 |
+
// https://www.apache.org/licenses/LICENSE-2.0
|
| 9 |
+
//
|
| 10 |
+
// Unless required by applicable law or agreed to in writing, software
|
| 11 |
+
// distributed under the License is distributed on an "AS IS" BASIS,
|
| 12 |
+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
| 13 |
+
// See the License for the specific language governing permissions and
|
| 14 |
+
// limitations under the License.
|
| 15 |
+
|
| 16 |
+
#ifndef ABSL_FLAGS_CONFIG_H_
|
| 17 |
+
#define ABSL_FLAGS_CONFIG_H_
|
| 18 |
+
|
| 19 |
+
// Determine if we should strip string literals from the Flag objects.
|
| 20 |
+
// By default we strip string literals on mobile platforms.
|
| 21 |
+
#if !defined(ABSL_FLAGS_STRIP_NAMES)
|
| 22 |
+
|
| 23 |
+
#if defined(__ANDROID__)
|
| 24 |
+
#define ABSL_FLAGS_STRIP_NAMES 1
|
| 25 |
+
|
| 26 |
+
#elif defined(__APPLE__)
|
| 27 |
+
#include <TargetConditionals.h>
|
| 28 |
+
#if defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE
|
| 29 |
+
#define ABSL_FLAGS_STRIP_NAMES 1
|
| 30 |
+
#elif defined(TARGET_OS_EMBEDDED) && TARGET_OS_EMBEDDED
|
| 31 |
+
#define ABSL_FLAGS_STRIP_NAMES 1
|
| 32 |
+
#endif // TARGET_OS_*
|
| 33 |
+
#endif
|
| 34 |
+
|
| 35 |
+
#endif // !defined(ABSL_FLAGS_STRIP_NAMES)
|
| 36 |
+
|
| 37 |
+
#if !defined(ABSL_FLAGS_STRIP_NAMES)
|
| 38 |
+
// If ABSL_FLAGS_STRIP_NAMES wasn't set on the command line or above,
|
| 39 |
+
// the default is not to strip.
|
| 40 |
+
#define ABSL_FLAGS_STRIP_NAMES 0
|
| 41 |
+
#endif
|
| 42 |
+
|
| 43 |
+
#if !defined(ABSL_FLAGS_STRIP_HELP)
|
| 44 |
+
// By default, if we strip names, we also strip help.
|
| 45 |
+
#define ABSL_FLAGS_STRIP_HELP ABSL_FLAGS_STRIP_NAMES
|
| 46 |
+
#endif
|
| 47 |
+
|
| 48 |
+
// These macros represent the "source of truth" for the list of supported
|
| 49 |
+
// built-in types.
|
| 50 |
+
#define ABSL_FLAGS_INTERNAL_BUILTIN_TYPES(A) \
|
| 51 |
+
A(bool, bool) \
|
| 52 |
+
A(short, short) \
|
| 53 |
+
A(unsigned short, unsigned_short) \
|
| 54 |
+
A(int, int) \
|
| 55 |
+
A(unsigned int, unsigned_int) \
|
| 56 |
+
A(long, long) \
|
| 57 |
+
A(unsigned long, unsigned_long) \
|
| 58 |
+
A(long long, long_long) \
|
| 59 |
+
A(unsigned long long, unsigned_long_long) \
|
| 60 |
+
A(double, double) \
|
| 61 |
+
A(float, float)
|
| 62 |
+
|
| 63 |
+
#define ABSL_FLAGS_INTERNAL_SUPPORTED_TYPES(A) \
|
| 64 |
+
ABSL_FLAGS_INTERNAL_BUILTIN_TYPES(A) \
|
| 65 |
+
A(std::string, std_string) \
|
| 66 |
+
A(std::vector<std::string>, std_vector_of_string)
|
| 67 |
+
|
| 68 |
+
#endif // ABSL_FLAGS_CONFIG_H_
|
weight/_dep/abseil-cpp/absl/flags/config_test.cc
ADDED
|
@@ -0,0 +1,61 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
// Copyright 2019 The Abseil Authors.
|
| 2 |
+
//
|
| 3 |
+
// Licensed under the Apache License, Version 2.0 (the "License");
|
| 4 |
+
// you may not use this file except in compliance with the License.
|
| 5 |
+
// You may obtain a copy of the License at
|
| 6 |
+
//
|
| 7 |
+
// https://www.apache.org/licenses/LICENSE-2.0
|
| 8 |
+
//
|
| 9 |
+
// Unless required by applicable law or agreed to in writing, software
|
| 10 |
+
// distributed under the License is distributed on an "AS IS" BASIS,
|
| 11 |
+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
| 12 |
+
// See the License for the specific language governing permissions and
|
| 13 |
+
// limitations under the License.
|
| 14 |
+
|
| 15 |
+
#include "absl/flags/config.h"
|
| 16 |
+
|
| 17 |
+
#ifdef __APPLE__
|
| 18 |
+
#include <TargetConditionals.h>
|
| 19 |
+
#endif
|
| 20 |
+
|
| 21 |
+
#include "gtest/gtest.h"
|
| 22 |
+
|
| 23 |
+
#ifndef ABSL_FLAGS_STRIP_NAMES
|
| 24 |
+
#error ABSL_FLAGS_STRIP_NAMES is not defined
|
| 25 |
+
#endif
|
| 26 |
+
|
| 27 |
+
#ifndef ABSL_FLAGS_STRIP_HELP
|
| 28 |
+
#error ABSL_FLAGS_STRIP_HELP is not defined
|
| 29 |
+
#endif
|
| 30 |
+
|
| 31 |
+
namespace {
|
| 32 |
+
|
| 33 |
+
// Test that ABSL_FLAGS_STRIP_NAMES and ABSL_FLAGS_STRIP_HELP are configured how
|
| 34 |
+
// we expect them to be configured by default. If you override this
|
| 35 |
+
// configuration, this test will fail, but the code should still be safe to use.
|
| 36 |
+
TEST(FlagsConfigTest, Test) {
|
| 37 |
+
#if defined(__ANDROID__)
|
| 38 |
+
EXPECT_EQ(ABSL_FLAGS_STRIP_NAMES, 1);
|
| 39 |
+
EXPECT_EQ(ABSL_FLAGS_STRIP_HELP, 1);
|
| 40 |
+
#elif defined(__myriad2__)
|
| 41 |
+
EXPECT_EQ(ABSL_FLAGS_STRIP_NAMES, 0);
|
| 42 |
+
EXPECT_EQ(ABSL_FLAGS_STRIP_HELP, 0);
|
| 43 |
+
#elif defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE
|
| 44 |
+
EXPECT_EQ(ABSL_FLAGS_STRIP_NAMES, 1);
|
| 45 |
+
EXPECT_EQ(ABSL_FLAGS_STRIP_HELP, 1);
|
| 46 |
+
#elif defined(TARGET_OS_EMBEDDED) && TARGET_OS_EMBEDDED
|
| 47 |
+
EXPECT_EQ(ABSL_FLAGS_STRIP_NAMES, 1);
|
| 48 |
+
EXPECT_EQ(ABSL_FLAGS_STRIP_HELP, 1);
|
| 49 |
+
#elif defined(__APPLE__)
|
| 50 |
+
EXPECT_EQ(ABSL_FLAGS_STRIP_NAMES, 0);
|
| 51 |
+
EXPECT_EQ(ABSL_FLAGS_STRIP_HELP, 0);
|
| 52 |
+
#elif defined(_WIN32)
|
| 53 |
+
EXPECT_EQ(ABSL_FLAGS_STRIP_NAMES, 0);
|
| 54 |
+
EXPECT_EQ(ABSL_FLAGS_STRIP_HELP, 0);
|
| 55 |
+
#elif defined(__linux__)
|
| 56 |
+
EXPECT_EQ(ABSL_FLAGS_STRIP_NAMES, 0);
|
| 57 |
+
EXPECT_EQ(ABSL_FLAGS_STRIP_HELP, 0);
|
| 58 |
+
#endif
|
| 59 |
+
}
|
| 60 |
+
|
| 61 |
+
} // namespace
|
weight/_dep/abseil-cpp/absl/flags/declare.h
ADDED
|
@@ -0,0 +1,68 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
//
|
| 2 |
+
// Copyright 2019 The Abseil Authors.
|
| 3 |
+
//
|
| 4 |
+
// Licensed under the Apache License, Version 2.0 (the "License");
|
| 5 |
+
// you may not use this file except in compliance with the License.
|
| 6 |
+
// You may obtain a copy of the License at
|
| 7 |
+
//
|
| 8 |
+
// https://www.apache.org/licenses/LICENSE-2.0
|
| 9 |
+
//
|
| 10 |
+
// Unless required by applicable law or agreed to in writing, software
|
| 11 |
+
// distributed under the License is distributed on an "AS IS" BASIS,
|
| 12 |
+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
| 13 |
+
// See the License for the specific language governing permissions and
|
| 14 |
+
// limitations under the License.
|
| 15 |
+
//
|
| 16 |
+
// -----------------------------------------------------------------------------
|
| 17 |
+
// File: declare.h
|
| 18 |
+
// -----------------------------------------------------------------------------
|
| 19 |
+
//
|
| 20 |
+
// This file defines the ABSL_DECLARE_FLAG macro, allowing you to declare an
|
| 21 |
+
// `absl::Flag` for use within a translation unit. You should place this
|
| 22 |
+
// declaration within the header file associated with the .cc file that defines
|
| 23 |
+
// and owns the `Flag`.
|
| 24 |
+
|
| 25 |
+
#ifndef ABSL_FLAGS_DECLARE_H_
|
| 26 |
+
#define ABSL_FLAGS_DECLARE_H_
|
| 27 |
+
|
| 28 |
+
#include "absl/base/config.h"
|
| 29 |
+
|
| 30 |
+
namespace absl {
|
| 31 |
+
ABSL_NAMESPACE_BEGIN
|
| 32 |
+
namespace flags_internal {
|
| 33 |
+
|
| 34 |
+
// absl::Flag<T> represents a flag of type 'T' created by ABSL_FLAG.
|
| 35 |
+
template <typename T>
|
| 36 |
+
class Flag;
|
| 37 |
+
|
| 38 |
+
} // namespace flags_internal
|
| 39 |
+
|
| 40 |
+
// Flag
|
| 41 |
+
//
|
| 42 |
+
// Forward declaration of the `absl::Flag` type for use in defining the macro.
|
| 43 |
+
template <typename T>
|
| 44 |
+
using Flag = flags_internal::Flag<T>;
|
| 45 |
+
|
| 46 |
+
ABSL_NAMESPACE_END
|
| 47 |
+
} // namespace absl
|
| 48 |
+
|
| 49 |
+
// ABSL_DECLARE_FLAG()
|
| 50 |
+
//
|
| 51 |
+
// This macro is a convenience for declaring use of an `absl::Flag` within a
|
| 52 |
+
// translation unit. This macro should be used within a header file to
|
| 53 |
+
// declare usage of the flag within any .cc file including that header file.
|
| 54 |
+
//
|
| 55 |
+
// The ABSL_DECLARE_FLAG(type, name) macro expands to:
|
| 56 |
+
//
|
| 57 |
+
// extern absl::Flag<type> FLAGS_name;
|
| 58 |
+
#define ABSL_DECLARE_FLAG(type, name) ABSL_DECLARE_FLAG_INTERNAL(type, name)
|
| 59 |
+
|
| 60 |
+
// Internal implementation of ABSL_DECLARE_FLAG to allow macro expansion of its
|
| 61 |
+
// arguments. Clients must use ABSL_DECLARE_FLAG instead.
|
| 62 |
+
#define ABSL_DECLARE_FLAG_INTERNAL(type, name) \
|
| 63 |
+
extern absl::Flag<type> FLAGS_##name; \
|
| 64 |
+
namespace absl /* block flags in namespaces */ {} \
|
| 65 |
+
/* second redeclaration is to allow applying attributes */ \
|
| 66 |
+
extern absl::Flag<type> FLAGS_##name
|
| 67 |
+
|
| 68 |
+
#endif // ABSL_FLAGS_DECLARE_H_
|
weight/_dep/abseil-cpp/absl/flags/flag.h
ADDED
|
@@ -0,0 +1,301 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
//
|
| 2 |
+
// Copyright 2019 The Abseil Authors.
|
| 3 |
+
//
|
| 4 |
+
// Licensed under the Apache License, Version 2.0 (the "License");
|
| 5 |
+
// you may not use this file except in compliance with the License.
|
| 6 |
+
// You may obtain a copy of the License at
|
| 7 |
+
//
|
| 8 |
+
// https://www.apache.org/licenses/LICENSE-2.0
|
| 9 |
+
//
|
| 10 |
+
// Unless required by applicable law or agreed to in writing, software
|
| 11 |
+
// distributed under the License is distributed on an "AS IS" BASIS,
|
| 12 |
+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
| 13 |
+
// See the License for the specific language governing permissions and
|
| 14 |
+
// limitations under the License.
|
| 15 |
+
//
|
| 16 |
+
// -----------------------------------------------------------------------------
|
| 17 |
+
// File: flag.h
|
| 18 |
+
// -----------------------------------------------------------------------------
|
| 19 |
+
//
|
| 20 |
+
// This header file defines the `absl::Flag<T>` type for holding command-line
|
| 21 |
+
// flag data, and abstractions to create, get and set such flag data.
|
| 22 |
+
//
|
| 23 |
+
// It is important to note that this type is **unspecified** (an implementation
|
| 24 |
+
// detail) and you do not construct or manipulate actual `absl::Flag<T>`
|
| 25 |
+
// instances. Instead, you define and declare flags using the
|
| 26 |
+
// `ABSL_FLAG()` and `ABSL_DECLARE_FLAG()` macros, and get and set flag values
|
| 27 |
+
// using the `absl::GetFlag()` and `absl::SetFlag()` functions.
|
| 28 |
+
|
| 29 |
+
#ifndef ABSL_FLAGS_FLAG_H_
|
| 30 |
+
#define ABSL_FLAGS_FLAG_H_
|
| 31 |
+
|
| 32 |
+
#include <string>
|
| 33 |
+
#include <type_traits>
|
| 34 |
+
|
| 35 |
+
#include "absl/base/attributes.h"
|
| 36 |
+
#include "absl/base/config.h"
|
| 37 |
+
#include "absl/base/optimization.h"
|
| 38 |
+
#include "absl/flags/config.h"
|
| 39 |
+
#include "absl/flags/internal/flag.h"
|
| 40 |
+
#include "absl/flags/internal/registry.h"
|
| 41 |
+
#include "absl/strings/string_view.h"
|
| 42 |
+
|
| 43 |
+
namespace absl {
|
| 44 |
+
ABSL_NAMESPACE_BEGIN
|
| 45 |
+
|
| 46 |
+
// Flag
|
| 47 |
+
//
|
| 48 |
+
// An `absl::Flag` holds a command-line flag value, providing a runtime
|
| 49 |
+
// parameter to a binary. Such flags should be defined in the global namespace
|
| 50 |
+
// and (preferably) in the module containing the binary's `main()` function.
|
| 51 |
+
//
|
| 52 |
+
// You should not construct and cannot use the `absl::Flag` type directly;
|
| 53 |
+
// instead, you should declare flags using the `ABSL_DECLARE_FLAG()` macro
|
| 54 |
+
// within a header file, and define your flag using `ABSL_FLAG()` within your
|
| 55 |
+
// header's associated `.cc` file. Such flags will be named `FLAGS_name`.
|
| 56 |
+
//
|
| 57 |
+
// Example:
|
| 58 |
+
//
|
| 59 |
+
// .h file
|
| 60 |
+
//
|
| 61 |
+
// // Declares usage of a flag named "FLAGS_count"
|
| 62 |
+
// ABSL_DECLARE_FLAG(int, count);
|
| 63 |
+
//
|
| 64 |
+
// .cc file
|
| 65 |
+
//
|
| 66 |
+
// // Defines a flag named "FLAGS_count" with a default `int` value of 0.
|
| 67 |
+
// ABSL_FLAG(int, count, 0, "Count of items to process");
|
| 68 |
+
//
|
| 69 |
+
// No public methods of `absl::Flag<T>` are part of the Abseil Flags API.
|
| 70 |
+
//
|
| 71 |
+
// For type support of Abseil Flags, see the marshalling.h header file, which
|
| 72 |
+
// discusses supported standard types, optional flags, and additional Abseil
|
| 73 |
+
// type support.
|
| 74 |
+
|
| 75 |
+
template <typename T>
|
| 76 |
+
using Flag = flags_internal::Flag<T>;
|
| 77 |
+
|
| 78 |
+
// GetFlag()
|
| 79 |
+
//
|
| 80 |
+
// Returns the value (of type `T`) of an `absl::Flag<T>` instance, by value. Do
|
| 81 |
+
// not construct an `absl::Flag<T>` directly and call `absl::GetFlag()`;
|
| 82 |
+
// instead, refer to flag's constructed variable name (e.g. `FLAGS_name`).
|
| 83 |
+
// Because this function returns by value and not by reference, it is
|
| 84 |
+
// thread-safe, but note that the operation may be expensive; as a result, avoid
|
| 85 |
+
// `absl::GetFlag()` within any tight loops.
|
| 86 |
+
//
|
| 87 |
+
// Example:
|
| 88 |
+
//
|
| 89 |
+
// // FLAGS_count is a Flag of type `int`
|
| 90 |
+
// int my_count = absl::GetFlag(FLAGS_count);
|
| 91 |
+
//
|
| 92 |
+
// // FLAGS_firstname is a Flag of type `std::string`
|
| 93 |
+
// std::string first_name = absl::GetFlag(FLAGS_firstname);
|
| 94 |
+
template <typename T>
|
| 95 |
+
ABSL_MUST_USE_RESULT T GetFlag(const absl::Flag<T>& flag) {
|
| 96 |
+
return flags_internal::FlagImplPeer::InvokeGet<T>(flag);
|
| 97 |
+
}
|
| 98 |
+
|
| 99 |
+
// SetFlag()
|
| 100 |
+
//
|
| 101 |
+
// Sets the value of an `absl::Flag` to the value `v`. Do not construct an
|
| 102 |
+
// `absl::Flag<T>` directly and call `absl::SetFlag()`; instead, use the
|
| 103 |
+
// flag's variable name (e.g. `FLAGS_name`). This function is
|
| 104 |
+
// thread-safe, but is potentially expensive. Avoid setting flags in general,
|
| 105 |
+
// but especially within performance-critical code.
|
| 106 |
+
template <typename T>
|
| 107 |
+
void SetFlag(absl::Flag<T>* flag, const T& v) {
|
| 108 |
+
flags_internal::FlagImplPeer::InvokeSet(*flag, v);
|
| 109 |
+
}
|
| 110 |
+
|
| 111 |
+
// Overload of `SetFlag()` to allow callers to pass in a value that is
|
| 112 |
+
// convertible to `T`. E.g., use this overload to pass a "const char*" when `T`
|
| 113 |
+
// is `std::string`.
|
| 114 |
+
template <typename T, typename V>
|
| 115 |
+
void SetFlag(absl::Flag<T>* flag, const V& v) {
|
| 116 |
+
T value(v);
|
| 117 |
+
flags_internal::FlagImplPeer::InvokeSet(*flag, value);
|
| 118 |
+
}
|
| 119 |
+
|
| 120 |
+
// GetFlagReflectionHandle()
|
| 121 |
+
//
|
| 122 |
+
// Returns the reflection handle corresponding to specified Abseil Flag
|
| 123 |
+
// instance. Use this handle to access flag's reflection information, like name,
|
| 124 |
+
// location, default value etc.
|
| 125 |
+
//
|
| 126 |
+
// Example:
|
| 127 |
+
//
|
| 128 |
+
// std::string = absl::GetFlagReflectionHandle(FLAGS_count).DefaultValue();
|
| 129 |
+
|
| 130 |
+
template <typename T>
|
| 131 |
+
const CommandLineFlag& GetFlagReflectionHandle(const absl::Flag<T>& f) {
|
| 132 |
+
return flags_internal::FlagImplPeer::InvokeReflect(f);
|
| 133 |
+
}
|
| 134 |
+
|
| 135 |
+
ABSL_NAMESPACE_END
|
| 136 |
+
} // namespace absl
|
| 137 |
+
|
| 138 |
+
|
| 139 |
+
// ABSL_FLAG()
|
| 140 |
+
//
|
| 141 |
+
// This macro defines an `absl::Flag<T>` instance of a specified type `T`:
|
| 142 |
+
//
|
| 143 |
+
// ABSL_FLAG(T, name, default_value, help);
|
| 144 |
+
//
|
| 145 |
+
// where:
|
| 146 |
+
//
|
| 147 |
+
// * `T` is a supported flag type (see the list of types in `marshalling.h`),
|
| 148 |
+
// * `name` designates the name of the flag (as a global variable
|
| 149 |
+
// `FLAGS_name`),
|
| 150 |
+
// * `default_value` is an expression holding the default value for this flag
|
| 151 |
+
// (which must be implicitly convertible to `T`),
|
| 152 |
+
// * `help` is the help text, which can also be an expression.
|
| 153 |
+
//
|
| 154 |
+
// This macro expands to a flag named 'FLAGS_name' of type 'T':
|
| 155 |
+
//
|
| 156 |
+
// absl::Flag<T> FLAGS_name = ...;
|
| 157 |
+
//
|
| 158 |
+
// Note that all such instances are created as global variables.
|
| 159 |
+
//
|
| 160 |
+
// For `ABSL_FLAG()` values that you wish to expose to other translation units,
|
| 161 |
+
// it is recommended to define those flags within the `.cc` file associated with
|
| 162 |
+
// the header where the flag is declared.
|
| 163 |
+
//
|
| 164 |
+
// Note: do not construct objects of type `absl::Flag<T>` directly. Only use the
|
| 165 |
+
// `ABSL_FLAG()` macro for such construction.
|
| 166 |
+
#define ABSL_FLAG(Type, name, default_value, help) \
|
| 167 |
+
ABSL_FLAG_IMPL(Type, name, default_value, help)
|
| 168 |
+
|
| 169 |
+
// ABSL_FLAG().OnUpdate()
|
| 170 |
+
//
|
| 171 |
+
// Defines a flag of type `T` with a callback attached:
|
| 172 |
+
//
|
| 173 |
+
// ABSL_FLAG(T, name, default_value, help).OnUpdate(callback);
|
| 174 |
+
//
|
| 175 |
+
// `callback` should be convertible to `void (*)()`.
|
| 176 |
+
//
|
| 177 |
+
// After any setting of the flag value, the callback will be called at least
|
| 178 |
+
// once. A rapid sequence of changes may be merged together into the same
|
| 179 |
+
// callback. No concurrent calls to the callback will be made for the same
|
| 180 |
+
// flag. Callbacks are allowed to read the current value of the flag but must
|
| 181 |
+
// not mutate that flag.
|
| 182 |
+
//
|
| 183 |
+
// The update mechanism guarantees "eventual consistency"; if the callback
|
| 184 |
+
// derives an auxiliary data structure from the flag value, it is guaranteed
|
| 185 |
+
// that eventually the flag value and the derived data structure will be
|
| 186 |
+
// consistent.
|
| 187 |
+
//
|
| 188 |
+
// Note: ABSL_FLAG.OnUpdate() does not have a public definition. Hence, this
|
| 189 |
+
// comment serves as its API documentation.
|
| 190 |
+
|
| 191 |
+
// -----------------------------------------------------------------------------
|
| 192 |
+
// Implementation details below this section
|
| 193 |
+
// -----------------------------------------------------------------------------
|
| 194 |
+
|
| 195 |
+
// ABSL_FLAG_IMPL macro definition conditional on ABSL_FLAGS_STRIP_NAMES
|
| 196 |
+
#define ABSL_FLAG_IMPL_FLAG_PTR(flag) flag
|
| 197 |
+
#define ABSL_FLAG_IMPL_HELP_ARG(name) \
|
| 198 |
+
absl::flags_internal::HelpArg<AbslFlagHelpGenFor##name>( \
|
| 199 |
+
FLAGS_help_storage_##name)
|
| 200 |
+
#define ABSL_FLAG_IMPL_DEFAULT_ARG(Type, name) \
|
| 201 |
+
absl::flags_internal::DefaultArg<Type, AbslFlagDefaultGenFor##name>(0)
|
| 202 |
+
|
| 203 |
+
#if ABSL_FLAGS_STRIP_NAMES
|
| 204 |
+
#define ABSL_FLAG_IMPL_FLAGNAME(txt) ""
|
| 205 |
+
#define ABSL_FLAG_IMPL_FILENAME() ""
|
| 206 |
+
#define ABSL_FLAG_IMPL_REGISTRAR(T, flag) \
|
| 207 |
+
absl::flags_internal::FlagRegistrar<T, false>(ABSL_FLAG_IMPL_FLAG_PTR(flag), \
|
| 208 |
+
nullptr)
|
| 209 |
+
#else
|
| 210 |
+
#define ABSL_FLAG_IMPL_FLAGNAME(txt) txt
|
| 211 |
+
#define ABSL_FLAG_IMPL_FILENAME() __FILE__
|
| 212 |
+
#define ABSL_FLAG_IMPL_REGISTRAR(T, flag) \
|
| 213 |
+
absl::flags_internal::FlagRegistrar<T, true>(ABSL_FLAG_IMPL_FLAG_PTR(flag), \
|
| 214 |
+
__FILE__)
|
| 215 |
+
#endif
|
| 216 |
+
|
| 217 |
+
// ABSL_FLAG_IMPL macro definition conditional on ABSL_FLAGS_STRIP_HELP
|
| 218 |
+
|
| 219 |
+
#if ABSL_FLAGS_STRIP_HELP
|
| 220 |
+
#define ABSL_FLAG_IMPL_FLAGHELP(txt) absl::flags_internal::kStrippedFlagHelp
|
| 221 |
+
#else
|
| 222 |
+
#define ABSL_FLAG_IMPL_FLAGHELP(txt) txt
|
| 223 |
+
#endif
|
| 224 |
+
|
| 225 |
+
// AbslFlagHelpGenFor##name is used to encapsulate both immediate (method Const)
|
| 226 |
+
// and lazy (method NonConst) evaluation of help message expression. We choose
|
| 227 |
+
// between the two via the call to HelpArg in absl::Flag instantiation below.
|
| 228 |
+
// If help message expression is constexpr evaluable compiler will optimize
|
| 229 |
+
// away this whole struct.
|
| 230 |
+
// TODO(rogeeff): place these generated structs into local namespace and apply
|
| 231 |
+
// ABSL_INTERNAL_UNIQUE_SHORT_NAME.
|
| 232 |
+
// TODO(rogeeff): Apply __attribute__((nodebug)) to FLAGS_help_storage_##name
|
| 233 |
+
#define ABSL_FLAG_IMPL_DECLARE_HELP_WRAPPER(name, txt) \
|
| 234 |
+
struct AbslFlagHelpGenFor##name { \
|
| 235 |
+
/* The expression is run in the caller as part of the */ \
|
| 236 |
+
/* default value argument. That keeps temporaries alive */ \
|
| 237 |
+
/* long enough for NonConst to work correctly. */ \
|
| 238 |
+
static constexpr absl::string_view Value( \
|
| 239 |
+
absl::string_view absl_flag_help = ABSL_FLAG_IMPL_FLAGHELP(txt)) { \
|
| 240 |
+
return absl_flag_help; \
|
| 241 |
+
} \
|
| 242 |
+
static std::string NonConst() { return std::string(Value()); } \
|
| 243 |
+
}; \
|
| 244 |
+
constexpr auto FLAGS_help_storage_##name ABSL_INTERNAL_UNIQUE_SMALL_NAME() \
|
| 245 |
+
ABSL_ATTRIBUTE_SECTION_VARIABLE(flags_help_cold) = \
|
| 246 |
+
absl::flags_internal::HelpStringAsArray<AbslFlagHelpGenFor##name>( \
|
| 247 |
+
0);
|
| 248 |
+
|
| 249 |
+
#define ABSL_FLAG_IMPL_DECLARE_DEF_VAL_WRAPPER(name, Type, default_value) \
|
| 250 |
+
struct AbslFlagDefaultGenFor##name { \
|
| 251 |
+
Type value = absl::flags_internal::InitDefaultValue<Type>(default_value); \
|
| 252 |
+
static void Gen(void* absl_flag_default_loc) { \
|
| 253 |
+
new (absl_flag_default_loc) Type(AbslFlagDefaultGenFor##name{}.value); \
|
| 254 |
+
} \
|
| 255 |
+
};
|
| 256 |
+
|
| 257 |
+
// ABSL_FLAG_IMPL
|
| 258 |
+
//
|
| 259 |
+
// Note: Name of registrar object is not arbitrary. It is used to "grab"
|
| 260 |
+
// global name for FLAGS_no<flag_name> symbol, thus preventing the possibility
|
| 261 |
+
// of defining two flags with names foo and nofoo.
|
| 262 |
+
#define ABSL_FLAG_IMPL(Type, name, default_value, help) \
|
| 263 |
+
extern ::absl::Flag<Type> FLAGS_##name; \
|
| 264 |
+
namespace absl /* block flags in namespaces */ {} \
|
| 265 |
+
ABSL_FLAG_IMPL_DECLARE_DEF_VAL_WRAPPER(name, Type, default_value) \
|
| 266 |
+
ABSL_FLAG_IMPL_DECLARE_HELP_WRAPPER(name, help) \
|
| 267 |
+
ABSL_CONST_INIT absl::Flag<Type> FLAGS_##name{ \
|
| 268 |
+
ABSL_FLAG_IMPL_FLAGNAME(#name), ABSL_FLAG_IMPL_FILENAME(), \
|
| 269 |
+
ABSL_FLAG_IMPL_HELP_ARG(name), ABSL_FLAG_IMPL_DEFAULT_ARG(Type, name)}; \
|
| 270 |
+
extern absl::flags_internal::FlagRegistrarEmpty FLAGS_no##name; \
|
| 271 |
+
absl::flags_internal::FlagRegistrarEmpty FLAGS_no##name = \
|
| 272 |
+
ABSL_FLAG_IMPL_REGISTRAR(Type, FLAGS_##name)
|
| 273 |
+
|
| 274 |
+
// ABSL_RETIRED_FLAG
|
| 275 |
+
//
|
| 276 |
+
// Designates the flag (which is usually pre-existing) as "retired." A retired
|
| 277 |
+
// flag is a flag that is now unused by the program, but may still be passed on
|
| 278 |
+
// the command line, usually by production scripts. A retired flag is ignored
|
| 279 |
+
// and code can't access it at runtime.
|
| 280 |
+
//
|
| 281 |
+
// This macro registers a retired flag with given name and type, with a name
|
| 282 |
+
// identical to the name of the original flag you are retiring. The retired
|
| 283 |
+
// flag's type can change over time, so that you can retire code to support a
|
| 284 |
+
// custom flag type.
|
| 285 |
+
//
|
| 286 |
+
// This macro has the same signature as `ABSL_FLAG`. To retire a flag, simply
|
| 287 |
+
// replace an `ABSL_FLAG` definition with `ABSL_RETIRED_FLAG`, leaving the
|
| 288 |
+
// arguments unchanged (unless of course you actually want to retire the flag
|
| 289 |
+
// type at this time as well).
|
| 290 |
+
//
|
| 291 |
+
// `default_value` is only used as a double check on the type. `explanation` is
|
| 292 |
+
// unused.
|
| 293 |
+
// TODO(rogeeff): replace RETIRED_FLAGS with FLAGS once forward declarations of
|
| 294 |
+
// retired flags are cleaned up.
|
| 295 |
+
#define ABSL_RETIRED_FLAG(type, name, default_value, explanation) \
|
| 296 |
+
static absl::flags_internal::RetiredFlag<type> RETIRED_FLAGS_##name; \
|
| 297 |
+
ABSL_ATTRIBUTE_UNUSED static const auto RETIRED_FLAGS_REG_##name = \
|
| 298 |
+
(RETIRED_FLAGS_##name.Retire(#name), \
|
| 299 |
+
::absl::flags_internal::FlagRegistrarEmpty{})
|
| 300 |
+
|
| 301 |
+
#endif // ABSL_FLAGS_FLAG_H_
|
weight/_dep/abseil-cpp/absl/flags/flag_benchmark.cc
ADDED
|
@@ -0,0 +1,251 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
//
|
| 2 |
+
// Copyright 2020 The Abseil Authors.
|
| 3 |
+
//
|
| 4 |
+
// Licensed under the Apache License, Version 2.0 (the "License");
|
| 5 |
+
// you may not use this file except in compliance with the License.
|
| 6 |
+
// You may obtain a copy of the License at
|
| 7 |
+
//
|
| 8 |
+
// https://www.apache.org/licenses/LICENSE-2.0
|
| 9 |
+
//
|
| 10 |
+
// Unless required by applicable law or agreed to in writing, software
|
| 11 |
+
// distributed under the License is distributed on an "AS IS" BASIS,
|
| 12 |
+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
| 13 |
+
// See the License for the specific language governing permissions and
|
| 14 |
+
// limitations under the License.
|
| 15 |
+
|
| 16 |
+
#include <stdint.h>
|
| 17 |
+
|
| 18 |
+
#include <string>
|
| 19 |
+
#include <vector>
|
| 20 |
+
|
| 21 |
+
#include "absl/flags/flag.h"
|
| 22 |
+
#include "absl/flags/marshalling.h"
|
| 23 |
+
#include "absl/flags/parse.h"
|
| 24 |
+
#include "absl/flags/reflection.h"
|
| 25 |
+
#include "absl/strings/string_view.h"
|
| 26 |
+
#include "absl/time/time.h"
|
| 27 |
+
#include "absl/types/optional.h"
|
| 28 |
+
#include "benchmark/benchmark.h"
|
| 29 |
+
|
| 30 |
+
namespace {
|
| 31 |
+
using String = std::string;
|
| 32 |
+
using VectorOfStrings = std::vector<std::string>;
|
| 33 |
+
using AbslDuration = absl::Duration;
|
| 34 |
+
|
| 35 |
+
// We do not want to take over marshalling for the types absl::optional<int>,
|
| 36 |
+
// absl::optional<std::string> which we do not own. Instead we introduce unique
|
| 37 |
+
// "aliases" to these types, which we do.
|
| 38 |
+
using AbslOptionalInt = absl::optional<int>;
|
| 39 |
+
struct OptionalInt : AbslOptionalInt {
|
| 40 |
+
using AbslOptionalInt::AbslOptionalInt;
|
| 41 |
+
};
|
| 42 |
+
// Next two functions represent Abseil Flags marshalling for OptionalInt.
|
| 43 |
+
bool AbslParseFlag(absl::string_view src, OptionalInt* flag,
|
| 44 |
+
std::string* error) {
|
| 45 |
+
int val;
|
| 46 |
+
if (src.empty())
|
| 47 |
+
flag->reset();
|
| 48 |
+
else if (!absl::ParseFlag(src, &val, error))
|
| 49 |
+
return false;
|
| 50 |
+
*flag = val;
|
| 51 |
+
return true;
|
| 52 |
+
}
|
| 53 |
+
std::string AbslUnparseFlag(const OptionalInt& flag) {
|
| 54 |
+
return !flag ? "" : absl::UnparseFlag(*flag);
|
| 55 |
+
}
|
| 56 |
+
|
| 57 |
+
using AbslOptionalString = absl::optional<std::string>;
|
| 58 |
+
struct OptionalString : AbslOptionalString {
|
| 59 |
+
using AbslOptionalString::AbslOptionalString;
|
| 60 |
+
};
|
| 61 |
+
// Next two functions represent Abseil Flags marshalling for OptionalString.
|
| 62 |
+
bool AbslParseFlag(absl::string_view src, OptionalString* flag,
|
| 63 |
+
std::string* error) {
|
| 64 |
+
std::string val;
|
| 65 |
+
if (src.empty())
|
| 66 |
+
flag->reset();
|
| 67 |
+
else if (!absl::ParseFlag(src, &val, error))
|
| 68 |
+
return false;
|
| 69 |
+
*flag = val;
|
| 70 |
+
return true;
|
| 71 |
+
}
|
| 72 |
+
std::string AbslUnparseFlag(const OptionalString& flag) {
|
| 73 |
+
return !flag ? "" : absl::UnparseFlag(*flag);
|
| 74 |
+
}
|
| 75 |
+
|
| 76 |
+
struct UDT {
|
| 77 |
+
UDT() = default;
|
| 78 |
+
UDT(const UDT&) {}
|
| 79 |
+
UDT& operator=(const UDT&) { return *this; }
|
| 80 |
+
};
|
| 81 |
+
// Next two functions represent Abseil Flags marshalling for UDT.
|
| 82 |
+
bool AbslParseFlag(absl::string_view, UDT*, std::string*) { return true; }
|
| 83 |
+
std::string AbslUnparseFlag(const UDT&) { return ""; }
|
| 84 |
+
|
| 85 |
+
} // namespace
|
| 86 |
+
|
| 87 |
+
#define BENCHMARKED_TYPES(A) \
|
| 88 |
+
A(bool) \
|
| 89 |
+
A(int16_t) \
|
| 90 |
+
A(uint16_t) \
|
| 91 |
+
A(int32_t) \
|
| 92 |
+
A(uint32_t) \
|
| 93 |
+
A(int64_t) \
|
| 94 |
+
A(uint64_t) \
|
| 95 |
+
A(double) \
|
| 96 |
+
A(float) \
|
| 97 |
+
A(String) \
|
| 98 |
+
A(VectorOfStrings) \
|
| 99 |
+
A(OptionalInt) \
|
| 100 |
+
A(OptionalString) \
|
| 101 |
+
A(AbslDuration) \
|
| 102 |
+
A(UDT)
|
| 103 |
+
|
| 104 |
+
#define REPLICATE_0(A, T, name, index) A(T, name, index)
|
| 105 |
+
#define REPLICATE_1(A, T, name, index) \
|
| 106 |
+
REPLICATE_0(A, T, name, index##0) REPLICATE_0(A, T, name, index##1)
|
| 107 |
+
#define REPLICATE_2(A, T, name, index) \
|
| 108 |
+
REPLICATE_1(A, T, name, index##0) REPLICATE_1(A, T, name, index##1)
|
| 109 |
+
#define REPLICATE_3(A, T, name, index) \
|
| 110 |
+
REPLICATE_2(A, T, name, index##0) REPLICATE_2(A, T, name, index##1)
|
| 111 |
+
#define REPLICATE_4(A, T, name, index) \
|
| 112 |
+
REPLICATE_3(A, T, name, index##0) REPLICATE_3(A, T, name, index##1)
|
| 113 |
+
#define REPLICATE_5(A, T, name, index) \
|
| 114 |
+
REPLICATE_4(A, T, name, index##0) REPLICATE_4(A, T, name, index##1)
|
| 115 |
+
#define REPLICATE_6(A, T, name, index) \
|
| 116 |
+
REPLICATE_5(A, T, name, index##0) REPLICATE_5(A, T, name, index##1)
|
| 117 |
+
#define REPLICATE_7(A, T, name, index) \
|
| 118 |
+
REPLICATE_6(A, T, name, index##0) REPLICATE_6(A, T, name, index##1)
|
| 119 |
+
#define REPLICATE_8(A, T, name, index) \
|
| 120 |
+
REPLICATE_7(A, T, name, index##0) REPLICATE_7(A, T, name, index##1)
|
| 121 |
+
#define REPLICATE_9(A, T, name, index) \
|
| 122 |
+
REPLICATE_8(A, T, name, index##0) REPLICATE_8(A, T, name, index##1)
|
| 123 |
+
#if defined(_MSC_VER)
|
| 124 |
+
#define REPLICATE(A, T, name) \
|
| 125 |
+
REPLICATE_7(A, T, name, 0) REPLICATE_7(A, T, name, 1)
|
| 126 |
+
#define SINGLE_FLAG(T) FLAGS_##T##_flag_00000000
|
| 127 |
+
#else
|
| 128 |
+
#define REPLICATE(A, T, name) \
|
| 129 |
+
REPLICATE_9(A, T, name, 0) REPLICATE_9(A, T, name, 1)
|
| 130 |
+
#define SINGLE_FLAG(T) FLAGS_##T##_flag_0000000000
|
| 131 |
+
#endif
|
| 132 |
+
#define REPLICATE_ALL(A, T, name) \
|
| 133 |
+
REPLICATE_9(A, T, name, 0) REPLICATE_9(A, T, name, 1)
|
| 134 |
+
|
| 135 |
+
#define COUNT(T, name, index) +1
|
| 136 |
+
constexpr size_t kNumFlags = 0 REPLICATE(COUNT, _, _);
|
| 137 |
+
|
| 138 |
+
#if defined(__clang__) && defined(__linux__)
|
| 139 |
+
// Force the flags used for benchmarks into a separate ELF section.
|
| 140 |
+
// This ensures that, even when other parts of the code might change size,
|
| 141 |
+
// the layout of the flags across cachelines is kept constant. This makes
|
| 142 |
+
// benchmark results more reproducible across unrelated code changes.
|
| 143 |
+
#pragma clang section data = ".benchmark_flags"
|
| 144 |
+
#endif
|
| 145 |
+
#define DEFINE_FLAG(T, name, index) ABSL_FLAG(T, name##_##index, {}, "");
|
| 146 |
+
#define FLAG_DEF(T) REPLICATE(DEFINE_FLAG, T, T##_flag);
|
| 147 |
+
BENCHMARKED_TYPES(FLAG_DEF)
|
| 148 |
+
#if defined(__clang__) && defined(__linux__)
|
| 149 |
+
#pragma clang section data = ""
|
| 150 |
+
#endif
|
| 151 |
+
// Register thousands of flags to bloat up the size of the registry.
|
| 152 |
+
// This mimics real life production binaries.
|
| 153 |
+
#define BLOAT_FLAG(_unused1, _unused2, index) \
|
| 154 |
+
ABSL_FLAG(int, bloat_flag_##index, 0, "");
|
| 155 |
+
REPLICATE_ALL(BLOAT_FLAG, _, _)
|
| 156 |
+
|
| 157 |
+
namespace {
|
| 158 |
+
|
| 159 |
+
#define FLAG_PTR(T, name, index) &FLAGS_##name##_##index,
|
| 160 |
+
#define FLAG_PTR_ARR(T) \
|
| 161 |
+
static constexpr absl::Flag<T>* FlagPtrs_##T[] = { \
|
| 162 |
+
REPLICATE(FLAG_PTR, T, T##_flag)};
|
| 163 |
+
BENCHMARKED_TYPES(FLAG_PTR_ARR)
|
| 164 |
+
|
| 165 |
+
#define BM_SingleGetFlag(T) \
|
| 166 |
+
void BM_SingleGetFlag_##T(benchmark::State& state) { \
|
| 167 |
+
for (auto _ : state) { \
|
| 168 |
+
benchmark::DoNotOptimize(absl::GetFlag(SINGLE_FLAG(T))); \
|
| 169 |
+
} \
|
| 170 |
+
} \
|
| 171 |
+
BENCHMARK(BM_SingleGetFlag_##T)->ThreadRange(1, 16);
|
| 172 |
+
|
| 173 |
+
BENCHMARKED_TYPES(BM_SingleGetFlag)
|
| 174 |
+
|
| 175 |
+
template <typename T>
|
| 176 |
+
struct Accumulator {
|
| 177 |
+
using type = T;
|
| 178 |
+
};
|
| 179 |
+
template <>
|
| 180 |
+
struct Accumulator<String> {
|
| 181 |
+
using type = size_t;
|
| 182 |
+
};
|
| 183 |
+
template <>
|
| 184 |
+
struct Accumulator<VectorOfStrings> {
|
| 185 |
+
using type = size_t;
|
| 186 |
+
};
|
| 187 |
+
template <>
|
| 188 |
+
struct Accumulator<OptionalInt> {
|
| 189 |
+
using type = bool;
|
| 190 |
+
};
|
| 191 |
+
template <>
|
| 192 |
+
struct Accumulator<OptionalString> {
|
| 193 |
+
using type = bool;
|
| 194 |
+
};
|
| 195 |
+
template <>
|
| 196 |
+
struct Accumulator<UDT> {
|
| 197 |
+
using type = bool;
|
| 198 |
+
};
|
| 199 |
+
|
| 200 |
+
template <typename T>
|
| 201 |
+
void Accumulate(typename Accumulator<T>::type& a, const T& f) {
|
| 202 |
+
a += f;
|
| 203 |
+
}
|
| 204 |
+
void Accumulate(bool& a, bool f) { a = a || f; }
|
| 205 |
+
void Accumulate(size_t& a, const std::string& f) { a += f.size(); }
|
| 206 |
+
void Accumulate(size_t& a, const std::vector<std::string>& f) { a += f.size(); }
|
| 207 |
+
void Accumulate(bool& a, const OptionalInt& f) { a |= f.has_value(); }
|
| 208 |
+
void Accumulate(bool& a, const OptionalString& f) { a |= f.has_value(); }
|
| 209 |
+
void Accumulate(bool& a, const UDT& f) {
|
| 210 |
+
a |= reinterpret_cast<int64_t>(&f) & 0x1;
|
| 211 |
+
}
|
| 212 |
+
|
| 213 |
+
#define BM_ManyGetFlag(T) \
|
| 214 |
+
void BM_ManyGetFlag_##T(benchmark::State& state) { \
|
| 215 |
+
Accumulator<T>::type res = {}; \
|
| 216 |
+
while (state.KeepRunningBatch(kNumFlags)) { \
|
| 217 |
+
for (auto* flag_ptr : FlagPtrs_##T) { \
|
| 218 |
+
Accumulate(res, absl::GetFlag(*flag_ptr)); \
|
| 219 |
+
} \
|
| 220 |
+
} \
|
| 221 |
+
benchmark::DoNotOptimize(res); \
|
| 222 |
+
} \
|
| 223 |
+
BENCHMARK(BM_ManyGetFlag_##T)->ThreadRange(1, 8);
|
| 224 |
+
|
| 225 |
+
BENCHMARKED_TYPES(BM_ManyGetFlag)
|
| 226 |
+
|
| 227 |
+
void BM_ThreadedFindCommandLineFlag(benchmark::State& state) {
|
| 228 |
+
char dummy[] = "dummy";
|
| 229 |
+
char* argv[] = {dummy};
|
| 230 |
+
// We need to ensure that flags have been parsed. That is where the registry
|
| 231 |
+
// is finalized.
|
| 232 |
+
absl::ParseCommandLine(1, argv);
|
| 233 |
+
|
| 234 |
+
while (state.KeepRunningBatch(kNumFlags)) {
|
| 235 |
+
for (auto* flag_ptr : FlagPtrs_bool) {
|
| 236 |
+
benchmark::DoNotOptimize(absl::FindCommandLineFlag(flag_ptr->Name()));
|
| 237 |
+
}
|
| 238 |
+
}
|
| 239 |
+
}
|
| 240 |
+
BENCHMARK(BM_ThreadedFindCommandLineFlag)->ThreadRange(1, 16);
|
| 241 |
+
|
| 242 |
+
} // namespace
|
| 243 |
+
|
| 244 |
+
#ifdef __llvm__
|
| 245 |
+
// To view disassembly use: gdb ${BINARY} -batch -ex "disassemble /s $FUNC"
|
| 246 |
+
#define InvokeGetFlag(T) \
|
| 247 |
+
T AbslInvokeGetFlag##T() { return absl::GetFlag(SINGLE_FLAG(T)); } \
|
| 248 |
+
int odr##T = (benchmark::DoNotOptimize(AbslInvokeGetFlag##T), 1);
|
| 249 |
+
|
| 250 |
+
BENCHMARKED_TYPES(InvokeGetFlag)
|
| 251 |
+
#endif // __llvm__
|
weight/_dep/abseil-cpp/absl/flags/flag_benchmark.lds
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
/* This linker script forces the flags used by flags_benchmark
|
| 2 |
+
* into a separate page-aligned section. This isn't necessary for
|
| 3 |
+
* correctness but ensures that the benchmark results are more
|
| 4 |
+
* reproducible across unrelated code changes.
|
| 5 |
+
*/
|
| 6 |
+
SECTIONS {
|
| 7 |
+
.benchmark_flags : {
|
| 8 |
+
. = ALIGN(0x1000);
|
| 9 |
+
* (.benchmark_flags);
|
| 10 |
+
}
|
| 11 |
+
}
|
| 12 |
+
|
| 13 |
+
INSERT AFTER .data
|
weight/_dep/abseil-cpp/absl/flags/flag_test.cc
ADDED
|
@@ -0,0 +1,1217 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
//
|
| 2 |
+
// Copyright 2019 The Abseil Authors.
|
| 3 |
+
//
|
| 4 |
+
// Licensed under the Apache License, Version 2.0 (the "License");
|
| 5 |
+
// you may not use this file except in compliance with the License.
|
| 6 |
+
// You may obtain a copy of the License at
|
| 7 |
+
//
|
| 8 |
+
// https://www.apache.org/licenses/LICENSE-2.0
|
| 9 |
+
//
|
| 10 |
+
// Unless required by applicable law or agreed to in writing, software
|
| 11 |
+
// distributed under the License is distributed on an "AS IS" BASIS,
|
| 12 |
+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
| 13 |
+
// See the License for the specific language governing permissions and
|
| 14 |
+
// limitations under the License.
|
| 15 |
+
|
| 16 |
+
#include "absl/flags/flag.h"
|
| 17 |
+
|
| 18 |
+
#include <stddef.h>
|
| 19 |
+
#include <stdint.h>
|
| 20 |
+
|
| 21 |
+
#include <atomic>
|
| 22 |
+
#include <cmath>
|
| 23 |
+
#include <new>
|
| 24 |
+
#include <string>
|
| 25 |
+
#include <thread> // NOLINT
|
| 26 |
+
#include <vector>
|
| 27 |
+
|
| 28 |
+
#include "gtest/gtest.h"
|
| 29 |
+
#include "absl/base/attributes.h"
|
| 30 |
+
#include "absl/base/macros.h"
|
| 31 |
+
#include "absl/flags/config.h"
|
| 32 |
+
#include "absl/flags/declare.h"
|
| 33 |
+
#include "absl/flags/internal/flag.h"
|
| 34 |
+
#include "absl/flags/marshalling.h"
|
| 35 |
+
#include "absl/flags/reflection.h"
|
| 36 |
+
#include "absl/flags/usage_config.h"
|
| 37 |
+
#include "absl/numeric/int128.h"
|
| 38 |
+
#include "absl/strings/match.h"
|
| 39 |
+
#include "absl/strings/numbers.h"
|
| 40 |
+
#include "absl/strings/str_cat.h"
|
| 41 |
+
#include "absl/strings/str_split.h"
|
| 42 |
+
#include "absl/strings/string_view.h"
|
| 43 |
+
#include "absl/time/time.h"
|
| 44 |
+
|
| 45 |
+
ABSL_DECLARE_FLAG(int64_t, mistyped_int_flag);
|
| 46 |
+
ABSL_DECLARE_FLAG(std::vector<std::string>, mistyped_string_flag);
|
| 47 |
+
|
| 48 |
+
namespace {
|
| 49 |
+
|
| 50 |
+
namespace flags = absl::flags_internal;
|
| 51 |
+
|
| 52 |
+
std::string TestHelpMsg() { return "dynamic help"; }
|
| 53 |
+
#if defined(_MSC_VER) && !defined(__clang__)
|
| 54 |
+
std::string TestLiteralHelpMsg() { return "literal help"; }
|
| 55 |
+
#endif
|
| 56 |
+
template <typename T>
|
| 57 |
+
void TestMakeDflt(void* dst) {
|
| 58 |
+
new (dst) T{};
|
| 59 |
+
}
|
| 60 |
+
void TestCallback() {}
|
| 61 |
+
|
| 62 |
+
struct UDT {
|
| 63 |
+
UDT() = default;
|
| 64 |
+
UDT(const UDT&) = default;
|
| 65 |
+
UDT& operator=(const UDT&) = default;
|
| 66 |
+
};
|
| 67 |
+
bool AbslParseFlag(absl::string_view, UDT*, std::string*) { return true; }
|
| 68 |
+
std::string AbslUnparseFlag(const UDT&) { return ""; }
|
| 69 |
+
|
| 70 |
+
class FlagTest : public testing::Test {
|
| 71 |
+
protected:
|
| 72 |
+
static void SetUpTestSuite() {
|
| 73 |
+
// Install a function to normalize filenames before this test is run.
|
| 74 |
+
absl::FlagsUsageConfig default_config;
|
| 75 |
+
default_config.normalize_filename = &FlagTest::NormalizeFileName;
|
| 76 |
+
absl::SetFlagsUsageConfig(default_config);
|
| 77 |
+
}
|
| 78 |
+
|
| 79 |
+
private:
|
| 80 |
+
static std::string NormalizeFileName(absl::string_view fname) {
|
| 81 |
+
#ifdef _WIN32
|
| 82 |
+
std::string normalized(fname);
|
| 83 |
+
std::replace(normalized.begin(), normalized.end(), '\\', '/');
|
| 84 |
+
fname = normalized;
|
| 85 |
+
#endif
|
| 86 |
+
return std::string(fname);
|
| 87 |
+
}
|
| 88 |
+
absl::FlagSaver flag_saver_;
|
| 89 |
+
};
|
| 90 |
+
|
| 91 |
+
struct S1 {
|
| 92 |
+
S1() = default;
|
| 93 |
+
S1(const S1&) = default;
|
| 94 |
+
int32_t f1;
|
| 95 |
+
int64_t f2;
|
| 96 |
+
};
|
| 97 |
+
|
| 98 |
+
struct S2 {
|
| 99 |
+
S2() = default;
|
| 100 |
+
S2(const S2&) = default;
|
| 101 |
+
int64_t f1;
|
| 102 |
+
double f2;
|
| 103 |
+
};
|
| 104 |
+
|
| 105 |
+
TEST_F(FlagTest, Traits) {
|
| 106 |
+
EXPECT_EQ(flags::StorageKind<int>(),
|
| 107 |
+
flags::FlagValueStorageKind::kValueAndInitBit);
|
| 108 |
+
EXPECT_EQ(flags::StorageKind<bool>(),
|
| 109 |
+
flags::FlagValueStorageKind::kValueAndInitBit);
|
| 110 |
+
EXPECT_EQ(flags::StorageKind<double>(),
|
| 111 |
+
flags::FlagValueStorageKind::kOneWordAtomic);
|
| 112 |
+
EXPECT_EQ(flags::StorageKind<int64_t>(),
|
| 113 |
+
flags::FlagValueStorageKind::kOneWordAtomic);
|
| 114 |
+
|
| 115 |
+
EXPECT_EQ(flags::StorageKind<S1>(),
|
| 116 |
+
flags::FlagValueStorageKind::kSequenceLocked);
|
| 117 |
+
EXPECT_EQ(flags::StorageKind<S2>(),
|
| 118 |
+
flags::FlagValueStorageKind::kSequenceLocked);
|
| 119 |
+
// Make sure absl::Duration uses the sequence-locked code path. MSVC 2015
|
| 120 |
+
// doesn't consider absl::Duration to be trivially-copyable so we just
|
| 121 |
+
// restrict this to clang as it seems to be a well-behaved compiler.
|
| 122 |
+
#ifdef __clang__
|
| 123 |
+
EXPECT_EQ(flags::StorageKind<absl::Duration>(),
|
| 124 |
+
flags::FlagValueStorageKind::kSequenceLocked);
|
| 125 |
+
#endif
|
| 126 |
+
|
| 127 |
+
EXPECT_EQ(flags::StorageKind<std::string>(),
|
| 128 |
+
flags::FlagValueStorageKind::kAlignedBuffer);
|
| 129 |
+
EXPECT_EQ(flags::StorageKind<std::vector<std::string>>(),
|
| 130 |
+
flags::FlagValueStorageKind::kAlignedBuffer);
|
| 131 |
+
|
| 132 |
+
EXPECT_EQ(flags::StorageKind<absl::int128>(),
|
| 133 |
+
flags::FlagValueStorageKind::kSequenceLocked);
|
| 134 |
+
EXPECT_EQ(flags::StorageKind<absl::uint128>(),
|
| 135 |
+
flags::FlagValueStorageKind::kSequenceLocked);
|
| 136 |
+
}
|
| 137 |
+
|
| 138 |
+
// --------------------------------------------------------------------
|
| 139 |
+
|
| 140 |
+
constexpr flags::FlagHelpArg help_arg{flags::FlagHelpMsg("literal help"),
|
| 141 |
+
flags::FlagHelpKind::kLiteral};
|
| 142 |
+
|
| 143 |
+
using String = std::string;
|
| 144 |
+
using int128 = absl::int128;
|
| 145 |
+
using uint128 = absl::uint128;
|
| 146 |
+
|
| 147 |
+
#define DEFINE_CONSTRUCTED_FLAG(T, dflt, dflt_kind) \
|
| 148 |
+
constexpr flags::FlagDefaultArg f1default##T{ \
|
| 149 |
+
flags::FlagDefaultSrc{dflt}, flags::FlagDefaultKind::dflt_kind}; \
|
| 150 |
+
constexpr absl::Flag<T> f1##T{"f1", "file", help_arg, f1default##T}; \
|
| 151 |
+
ABSL_CONST_INIT absl::Flag<T> f2##T { \
|
| 152 |
+
"f2", "file", \
|
| 153 |
+
{flags::FlagHelpMsg(&TestHelpMsg), flags::FlagHelpKind::kGenFunc}, \
|
| 154 |
+
flags::FlagDefaultArg { \
|
| 155 |
+
flags::FlagDefaultSrc(&TestMakeDflt<T>), \
|
| 156 |
+
flags::FlagDefaultKind::kGenFunc \
|
| 157 |
+
} \
|
| 158 |
+
}
|
| 159 |
+
|
| 160 |
+
DEFINE_CONSTRUCTED_FLAG(bool, true, kOneWord);
|
| 161 |
+
DEFINE_CONSTRUCTED_FLAG(int16_t, 1, kOneWord);
|
| 162 |
+
DEFINE_CONSTRUCTED_FLAG(uint16_t, 2, kOneWord);
|
| 163 |
+
DEFINE_CONSTRUCTED_FLAG(int32_t, 3, kOneWord);
|
| 164 |
+
DEFINE_CONSTRUCTED_FLAG(uint32_t, 4, kOneWord);
|
| 165 |
+
DEFINE_CONSTRUCTED_FLAG(int64_t, 5, kOneWord);
|
| 166 |
+
DEFINE_CONSTRUCTED_FLAG(uint64_t, 6, kOneWord);
|
| 167 |
+
DEFINE_CONSTRUCTED_FLAG(float, 7.8, kOneWord);
|
| 168 |
+
DEFINE_CONSTRUCTED_FLAG(double, 9.10, kOneWord);
|
| 169 |
+
DEFINE_CONSTRUCTED_FLAG(String, &TestMakeDflt<String>, kGenFunc);
|
| 170 |
+
DEFINE_CONSTRUCTED_FLAG(UDT, &TestMakeDflt<UDT>, kGenFunc);
|
| 171 |
+
DEFINE_CONSTRUCTED_FLAG(int128, 13, kGenFunc);
|
| 172 |
+
DEFINE_CONSTRUCTED_FLAG(uint128, 14, kGenFunc);
|
| 173 |
+
|
| 174 |
+
template <typename T>
|
| 175 |
+
bool TestConstructionFor(const absl::Flag<T>& f1, absl::Flag<T>& f2) {
|
| 176 |
+
EXPECT_EQ(absl::GetFlagReflectionHandle(f1).Name(), "f1");
|
| 177 |
+
EXPECT_EQ(absl::GetFlagReflectionHandle(f1).Help(), "literal help");
|
| 178 |
+
EXPECT_EQ(absl::GetFlagReflectionHandle(f1).Filename(), "file");
|
| 179 |
+
|
| 180 |
+
flags::FlagRegistrar<T, false>(ABSL_FLAG_IMPL_FLAG_PTR(f2), nullptr)
|
| 181 |
+
.OnUpdate(TestCallback);
|
| 182 |
+
|
| 183 |
+
EXPECT_EQ(absl::GetFlagReflectionHandle(f2).Name(), "f2");
|
| 184 |
+
EXPECT_EQ(absl::GetFlagReflectionHandle(f2).Help(), "dynamic help");
|
| 185 |
+
EXPECT_EQ(absl::GetFlagReflectionHandle(f2).Filename(), "file");
|
| 186 |
+
|
| 187 |
+
return true;
|
| 188 |
+
}
|
| 189 |
+
|
| 190 |
+
#define TEST_CONSTRUCTED_FLAG(T) TestConstructionFor(f1##T, f2##T);
|
| 191 |
+
|
| 192 |
+
TEST_F(FlagTest, TestConstruction) {
|
| 193 |
+
TEST_CONSTRUCTED_FLAG(bool);
|
| 194 |
+
TEST_CONSTRUCTED_FLAG(int16_t);
|
| 195 |
+
TEST_CONSTRUCTED_FLAG(uint16_t);
|
| 196 |
+
TEST_CONSTRUCTED_FLAG(int32_t);
|
| 197 |
+
TEST_CONSTRUCTED_FLAG(uint32_t);
|
| 198 |
+
TEST_CONSTRUCTED_FLAG(int64_t);
|
| 199 |
+
TEST_CONSTRUCTED_FLAG(uint64_t);
|
| 200 |
+
TEST_CONSTRUCTED_FLAG(float);
|
| 201 |
+
TEST_CONSTRUCTED_FLAG(double);
|
| 202 |
+
TEST_CONSTRUCTED_FLAG(String);
|
| 203 |
+
TEST_CONSTRUCTED_FLAG(UDT);
|
| 204 |
+
TEST_CONSTRUCTED_FLAG(int128);
|
| 205 |
+
TEST_CONSTRUCTED_FLAG(uint128);
|
| 206 |
+
}
|
| 207 |
+
|
| 208 |
+
// --------------------------------------------------------------------
|
| 209 |
+
|
| 210 |
+
} // namespace
|
| 211 |
+
|
| 212 |
+
ABSL_DECLARE_FLAG(bool, test_flag_01);
|
| 213 |
+
ABSL_DECLARE_FLAG(int, test_flag_02);
|
| 214 |
+
ABSL_DECLARE_FLAG(int16_t, test_flag_03);
|
| 215 |
+
ABSL_DECLARE_FLAG(uint16_t, test_flag_04);
|
| 216 |
+
ABSL_DECLARE_FLAG(int32_t, test_flag_05);
|
| 217 |
+
ABSL_DECLARE_FLAG(uint32_t, test_flag_06);
|
| 218 |
+
ABSL_DECLARE_FLAG(int64_t, test_flag_07);
|
| 219 |
+
ABSL_DECLARE_FLAG(uint64_t, test_flag_08);
|
| 220 |
+
ABSL_DECLARE_FLAG(double, test_flag_09);
|
| 221 |
+
ABSL_DECLARE_FLAG(float, test_flag_10);
|
| 222 |
+
ABSL_DECLARE_FLAG(std::string, test_flag_11);
|
| 223 |
+
ABSL_DECLARE_FLAG(absl::Duration, test_flag_12);
|
| 224 |
+
ABSL_DECLARE_FLAG(absl::int128, test_flag_13);
|
| 225 |
+
ABSL_DECLARE_FLAG(absl::uint128, test_flag_14);
|
| 226 |
+
|
| 227 |
+
namespace {
|
| 228 |
+
|
| 229 |
+
#if !ABSL_FLAGS_STRIP_NAMES
|
| 230 |
+
|
| 231 |
+
TEST_F(FlagTest, TestFlagDeclaration) {
|
| 232 |
+
// test that we can access flag objects.
|
| 233 |
+
EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_01).Name(),
|
| 234 |
+
"test_flag_01");
|
| 235 |
+
EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_02).Name(),
|
| 236 |
+
"test_flag_02");
|
| 237 |
+
EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_03).Name(),
|
| 238 |
+
"test_flag_03");
|
| 239 |
+
EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_04).Name(),
|
| 240 |
+
"test_flag_04");
|
| 241 |
+
EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_05).Name(),
|
| 242 |
+
"test_flag_05");
|
| 243 |
+
EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_06).Name(),
|
| 244 |
+
"test_flag_06");
|
| 245 |
+
EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_07).Name(),
|
| 246 |
+
"test_flag_07");
|
| 247 |
+
EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_08).Name(),
|
| 248 |
+
"test_flag_08");
|
| 249 |
+
EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_09).Name(),
|
| 250 |
+
"test_flag_09");
|
| 251 |
+
EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_10).Name(),
|
| 252 |
+
"test_flag_10");
|
| 253 |
+
EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_11).Name(),
|
| 254 |
+
"test_flag_11");
|
| 255 |
+
EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_12).Name(),
|
| 256 |
+
"test_flag_12");
|
| 257 |
+
EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_13).Name(),
|
| 258 |
+
"test_flag_13");
|
| 259 |
+
EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_14).Name(),
|
| 260 |
+
"test_flag_14");
|
| 261 |
+
}
|
| 262 |
+
#endif // !ABSL_FLAGS_STRIP_NAMES
|
| 263 |
+
|
| 264 |
+
// --------------------------------------------------------------------
|
| 265 |
+
|
| 266 |
+
} // namespace
|
| 267 |
+
|
| 268 |
+
ABSL_FLAG(bool, test_flag_01, true, "test flag 01");
|
| 269 |
+
ABSL_FLAG(int, test_flag_02, 1234, "test flag 02");
|
| 270 |
+
ABSL_FLAG(int16_t, test_flag_03, -34, "test flag 03");
|
| 271 |
+
ABSL_FLAG(uint16_t, test_flag_04, 189, "test flag 04");
|
| 272 |
+
ABSL_FLAG(int32_t, test_flag_05, 10765, "test flag 05");
|
| 273 |
+
ABSL_FLAG(uint32_t, test_flag_06, 40000, "test flag 06");
|
| 274 |
+
ABSL_FLAG(int64_t, test_flag_07, -1234567, "test flag 07");
|
| 275 |
+
ABSL_FLAG(uint64_t, test_flag_08, 9876543, "test flag 08");
|
| 276 |
+
ABSL_FLAG(double, test_flag_09, -9.876e-50, "test flag 09");
|
| 277 |
+
ABSL_FLAG(float, test_flag_10, 1.234e12f, "test flag 10");
|
| 278 |
+
ABSL_FLAG(std::string, test_flag_11, "", "test flag 11");
|
| 279 |
+
ABSL_FLAG(absl::Duration, test_flag_12, absl::Minutes(10), "test flag 12");
|
| 280 |
+
ABSL_FLAG(absl::int128, test_flag_13, absl::MakeInt128(-1, 0), "test flag 13");
|
| 281 |
+
ABSL_FLAG(absl::uint128, test_flag_14, absl::MakeUint128(0, 0xFFFAAABBBCCCDDD),
|
| 282 |
+
"test flag 14");
|
| 283 |
+
|
| 284 |
+
namespace {
|
| 285 |
+
|
| 286 |
+
#if !ABSL_FLAGS_STRIP_NAMES
|
| 287 |
+
TEST_F(FlagTest, TestFlagDefinition) {
|
| 288 |
+
absl::string_view expected_file_name = "absl/flags/flag_test.cc";
|
| 289 |
+
|
| 290 |
+
EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_01).Name(),
|
| 291 |
+
"test_flag_01");
|
| 292 |
+
EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_01).Help(),
|
| 293 |
+
"test flag 01");
|
| 294 |
+
EXPECT_TRUE(absl::EndsWith(
|
| 295 |
+
absl::GetFlagReflectionHandle(FLAGS_test_flag_01).Filename(),
|
| 296 |
+
expected_file_name))
|
| 297 |
+
<< absl::GetFlagReflectionHandle(FLAGS_test_flag_01).Filename();
|
| 298 |
+
|
| 299 |
+
EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_02).Name(),
|
| 300 |
+
"test_flag_02");
|
| 301 |
+
EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_02).Help(),
|
| 302 |
+
"test flag 02");
|
| 303 |
+
EXPECT_TRUE(absl::EndsWith(
|
| 304 |
+
absl::GetFlagReflectionHandle(FLAGS_test_flag_02).Filename(),
|
| 305 |
+
expected_file_name))
|
| 306 |
+
<< absl::GetFlagReflectionHandle(FLAGS_test_flag_02).Filename();
|
| 307 |
+
|
| 308 |
+
EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_03).Name(),
|
| 309 |
+
"test_flag_03");
|
| 310 |
+
EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_03).Help(),
|
| 311 |
+
"test flag 03");
|
| 312 |
+
EXPECT_TRUE(absl::EndsWith(
|
| 313 |
+
absl::GetFlagReflectionHandle(FLAGS_test_flag_03).Filename(),
|
| 314 |
+
expected_file_name))
|
| 315 |
+
<< absl::GetFlagReflectionHandle(FLAGS_test_flag_03).Filename();
|
| 316 |
+
|
| 317 |
+
EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_04).Name(),
|
| 318 |
+
"test_flag_04");
|
| 319 |
+
EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_04).Help(),
|
| 320 |
+
"test flag 04");
|
| 321 |
+
EXPECT_TRUE(absl::EndsWith(
|
| 322 |
+
absl::GetFlagReflectionHandle(FLAGS_test_flag_04).Filename(),
|
| 323 |
+
expected_file_name))
|
| 324 |
+
<< absl::GetFlagReflectionHandle(FLAGS_test_flag_04).Filename();
|
| 325 |
+
|
| 326 |
+
EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_05).Name(),
|
| 327 |
+
"test_flag_05");
|
| 328 |
+
EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_05).Help(),
|
| 329 |
+
"test flag 05");
|
| 330 |
+
EXPECT_TRUE(absl::EndsWith(
|
| 331 |
+
absl::GetFlagReflectionHandle(FLAGS_test_flag_05).Filename(),
|
| 332 |
+
expected_file_name))
|
| 333 |
+
<< absl::GetFlagReflectionHandle(FLAGS_test_flag_05).Filename();
|
| 334 |
+
|
| 335 |
+
EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_06).Name(),
|
| 336 |
+
"test_flag_06");
|
| 337 |
+
EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_06).Help(),
|
| 338 |
+
"test flag 06");
|
| 339 |
+
EXPECT_TRUE(absl::EndsWith(
|
| 340 |
+
absl::GetFlagReflectionHandle(FLAGS_test_flag_06).Filename(),
|
| 341 |
+
expected_file_name))
|
| 342 |
+
<< absl::GetFlagReflectionHandle(FLAGS_test_flag_06).Filename();
|
| 343 |
+
|
| 344 |
+
EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_07).Name(),
|
| 345 |
+
"test_flag_07");
|
| 346 |
+
EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_07).Help(),
|
| 347 |
+
"test flag 07");
|
| 348 |
+
EXPECT_TRUE(absl::EndsWith(
|
| 349 |
+
absl::GetFlagReflectionHandle(FLAGS_test_flag_07).Filename(),
|
| 350 |
+
expected_file_name))
|
| 351 |
+
<< absl::GetFlagReflectionHandle(FLAGS_test_flag_07).Filename();
|
| 352 |
+
|
| 353 |
+
EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_08).Name(),
|
| 354 |
+
"test_flag_08");
|
| 355 |
+
EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_08).Help(),
|
| 356 |
+
"test flag 08");
|
| 357 |
+
EXPECT_TRUE(absl::EndsWith(
|
| 358 |
+
absl::GetFlagReflectionHandle(FLAGS_test_flag_08).Filename(),
|
| 359 |
+
expected_file_name))
|
| 360 |
+
<< absl::GetFlagReflectionHandle(FLAGS_test_flag_08).Filename();
|
| 361 |
+
|
| 362 |
+
EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_09).Name(),
|
| 363 |
+
"test_flag_09");
|
| 364 |
+
EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_09).Help(),
|
| 365 |
+
"test flag 09");
|
| 366 |
+
EXPECT_TRUE(absl::EndsWith(
|
| 367 |
+
absl::GetFlagReflectionHandle(FLAGS_test_flag_09).Filename(),
|
| 368 |
+
expected_file_name))
|
| 369 |
+
<< absl::GetFlagReflectionHandle(FLAGS_test_flag_09).Filename();
|
| 370 |
+
|
| 371 |
+
EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_10).Name(),
|
| 372 |
+
"test_flag_10");
|
| 373 |
+
EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_10).Help(),
|
| 374 |
+
"test flag 10");
|
| 375 |
+
EXPECT_TRUE(absl::EndsWith(
|
| 376 |
+
absl::GetFlagReflectionHandle(FLAGS_test_flag_10).Filename(),
|
| 377 |
+
expected_file_name))
|
| 378 |
+
<< absl::GetFlagReflectionHandle(FLAGS_test_flag_10).Filename();
|
| 379 |
+
|
| 380 |
+
EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_11).Name(),
|
| 381 |
+
"test_flag_11");
|
| 382 |
+
EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_11).Help(),
|
| 383 |
+
"test flag 11");
|
| 384 |
+
EXPECT_TRUE(absl::EndsWith(
|
| 385 |
+
absl::GetFlagReflectionHandle(FLAGS_test_flag_11).Filename(),
|
| 386 |
+
expected_file_name))
|
| 387 |
+
<< absl::GetFlagReflectionHandle(FLAGS_test_flag_11).Filename();
|
| 388 |
+
|
| 389 |
+
EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_12).Name(),
|
| 390 |
+
"test_flag_12");
|
| 391 |
+
EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_12).Help(),
|
| 392 |
+
"test flag 12");
|
| 393 |
+
EXPECT_TRUE(absl::EndsWith(
|
| 394 |
+
absl::GetFlagReflectionHandle(FLAGS_test_flag_12).Filename(),
|
| 395 |
+
expected_file_name))
|
| 396 |
+
<< absl::GetFlagReflectionHandle(FLAGS_test_flag_12).Filename();
|
| 397 |
+
|
| 398 |
+
EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_13).Name(),
|
| 399 |
+
"test_flag_13");
|
| 400 |
+
EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_13).Help(),
|
| 401 |
+
"test flag 13");
|
| 402 |
+
EXPECT_TRUE(absl::EndsWith(
|
| 403 |
+
absl::GetFlagReflectionHandle(FLAGS_test_flag_13).Filename(),
|
| 404 |
+
expected_file_name))
|
| 405 |
+
<< absl::GetFlagReflectionHandle(FLAGS_test_flag_13).Filename();
|
| 406 |
+
|
| 407 |
+
EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_14).Name(),
|
| 408 |
+
"test_flag_14");
|
| 409 |
+
EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_14).Help(),
|
| 410 |
+
"test flag 14");
|
| 411 |
+
EXPECT_TRUE(absl::EndsWith(
|
| 412 |
+
absl::GetFlagReflectionHandle(FLAGS_test_flag_14).Filename(),
|
| 413 |
+
expected_file_name))
|
| 414 |
+
<< absl::GetFlagReflectionHandle(FLAGS_test_flag_14).Filename();
|
| 415 |
+
}
|
| 416 |
+
#endif // !ABSL_FLAGS_STRIP_NAMES
|
| 417 |
+
|
| 418 |
+
// --------------------------------------------------------------------
|
| 419 |
+
|
| 420 |
+
TEST_F(FlagTest, TestDefault) {
|
| 421 |
+
EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_01).DefaultValue(),
|
| 422 |
+
"true");
|
| 423 |
+
EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_02).DefaultValue(),
|
| 424 |
+
"1234");
|
| 425 |
+
EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_03).DefaultValue(),
|
| 426 |
+
"-34");
|
| 427 |
+
EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_04).DefaultValue(),
|
| 428 |
+
"189");
|
| 429 |
+
EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_05).DefaultValue(),
|
| 430 |
+
"10765");
|
| 431 |
+
EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_06).DefaultValue(),
|
| 432 |
+
"40000");
|
| 433 |
+
EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_07).DefaultValue(),
|
| 434 |
+
"-1234567");
|
| 435 |
+
EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_08).DefaultValue(),
|
| 436 |
+
"9876543");
|
| 437 |
+
EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_09).DefaultValue(),
|
| 438 |
+
"-9.876e-50");
|
| 439 |
+
EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_10).DefaultValue(),
|
| 440 |
+
"1.234e+12");
|
| 441 |
+
EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_11).DefaultValue(),
|
| 442 |
+
"");
|
| 443 |
+
EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_12).DefaultValue(),
|
| 444 |
+
"10m");
|
| 445 |
+
EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_13).DefaultValue(),
|
| 446 |
+
"-18446744073709551616");
|
| 447 |
+
EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_14).DefaultValue(),
|
| 448 |
+
"1152827684197027293");
|
| 449 |
+
|
| 450 |
+
EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_01).CurrentValue(),
|
| 451 |
+
"true");
|
| 452 |
+
EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_02).CurrentValue(),
|
| 453 |
+
"1234");
|
| 454 |
+
EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_03).CurrentValue(),
|
| 455 |
+
"-34");
|
| 456 |
+
EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_04).CurrentValue(),
|
| 457 |
+
"189");
|
| 458 |
+
EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_05).CurrentValue(),
|
| 459 |
+
"10765");
|
| 460 |
+
EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_06).CurrentValue(),
|
| 461 |
+
"40000");
|
| 462 |
+
EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_07).CurrentValue(),
|
| 463 |
+
"-1234567");
|
| 464 |
+
EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_08).CurrentValue(),
|
| 465 |
+
"9876543");
|
| 466 |
+
EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_09).CurrentValue(),
|
| 467 |
+
"-9.876e-50");
|
| 468 |
+
EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_10).CurrentValue(),
|
| 469 |
+
"1.234e+12");
|
| 470 |
+
EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_11).CurrentValue(),
|
| 471 |
+
"");
|
| 472 |
+
EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_12).CurrentValue(),
|
| 473 |
+
"10m");
|
| 474 |
+
EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_13).CurrentValue(),
|
| 475 |
+
"-18446744073709551616");
|
| 476 |
+
EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_14).CurrentValue(),
|
| 477 |
+
"1152827684197027293");
|
| 478 |
+
|
| 479 |
+
EXPECT_EQ(absl::GetFlag(FLAGS_test_flag_01), true);
|
| 480 |
+
EXPECT_EQ(absl::GetFlag(FLAGS_test_flag_02), 1234);
|
| 481 |
+
EXPECT_EQ(absl::GetFlag(FLAGS_test_flag_03), -34);
|
| 482 |
+
EXPECT_EQ(absl::GetFlag(FLAGS_test_flag_04), 189);
|
| 483 |
+
EXPECT_EQ(absl::GetFlag(FLAGS_test_flag_05), 10765);
|
| 484 |
+
EXPECT_EQ(absl::GetFlag(FLAGS_test_flag_06), 40000);
|
| 485 |
+
EXPECT_EQ(absl::GetFlag(FLAGS_test_flag_07), -1234567);
|
| 486 |
+
EXPECT_EQ(absl::GetFlag(FLAGS_test_flag_08), 9876543);
|
| 487 |
+
EXPECT_NEAR(absl::GetFlag(FLAGS_test_flag_09), -9.876e-50, 1e-55);
|
| 488 |
+
EXPECT_NEAR(absl::GetFlag(FLAGS_test_flag_10), 1.234e12f, 1e5f);
|
| 489 |
+
EXPECT_EQ(absl::GetFlag(FLAGS_test_flag_11), "");
|
| 490 |
+
EXPECT_EQ(absl::GetFlag(FLAGS_test_flag_12), absl::Minutes(10));
|
| 491 |
+
EXPECT_EQ(absl::GetFlag(FLAGS_test_flag_13), absl::MakeInt128(-1, 0));
|
| 492 |
+
EXPECT_EQ(absl::GetFlag(FLAGS_test_flag_14),
|
| 493 |
+
absl::MakeUint128(0, 0xFFFAAABBBCCCDDD));
|
| 494 |
+
}
|
| 495 |
+
|
| 496 |
+
// --------------------------------------------------------------------
|
| 497 |
+
|
| 498 |
+
struct NonTriviallyCopyableAggregate {
|
| 499 |
+
NonTriviallyCopyableAggregate() = default;
|
| 500 |
+
NonTriviallyCopyableAggregate(const NonTriviallyCopyableAggregate& rhs)
|
| 501 |
+
: value(rhs.value) {}
|
| 502 |
+
NonTriviallyCopyableAggregate& operator=(
|
| 503 |
+
const NonTriviallyCopyableAggregate& rhs) {
|
| 504 |
+
value = rhs.value;
|
| 505 |
+
return *this;
|
| 506 |
+
}
|
| 507 |
+
|
| 508 |
+
int value;
|
| 509 |
+
};
|
| 510 |
+
bool AbslParseFlag(absl::string_view src, NonTriviallyCopyableAggregate* f,
|
| 511 |
+
std::string* e) {
|
| 512 |
+
return absl::ParseFlag(src, &f->value, e);
|
| 513 |
+
}
|
| 514 |
+
std::string AbslUnparseFlag(const NonTriviallyCopyableAggregate& ntc) {
|
| 515 |
+
return absl::StrCat(ntc.value);
|
| 516 |
+
}
|
| 517 |
+
|
| 518 |
+
bool operator==(const NonTriviallyCopyableAggregate& ntc1,
|
| 519 |
+
const NonTriviallyCopyableAggregate& ntc2) {
|
| 520 |
+
return ntc1.value == ntc2.value;
|
| 521 |
+
}
|
| 522 |
+
|
| 523 |
+
} // namespace
|
| 524 |
+
|
| 525 |
+
ABSL_FLAG(bool, test_flag_eb_01, {}, "");
|
| 526 |
+
ABSL_FLAG(int32_t, test_flag_eb_02, {}, "");
|
| 527 |
+
ABSL_FLAG(int64_t, test_flag_eb_03, {}, "");
|
| 528 |
+
ABSL_FLAG(double, test_flag_eb_04, {}, "");
|
| 529 |
+
ABSL_FLAG(std::string, test_flag_eb_05, {}, "");
|
| 530 |
+
ABSL_FLAG(NonTriviallyCopyableAggregate, test_flag_eb_06, {}, "");
|
| 531 |
+
|
| 532 |
+
namespace {
|
| 533 |
+
|
| 534 |
+
TEST_F(FlagTest, TestEmptyBracesDefault) {
|
| 535 |
+
EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_eb_01).DefaultValue(),
|
| 536 |
+
"false");
|
| 537 |
+
EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_eb_02).DefaultValue(),
|
| 538 |
+
"0");
|
| 539 |
+
EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_eb_03).DefaultValue(),
|
| 540 |
+
"0");
|
| 541 |
+
EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_eb_04).DefaultValue(),
|
| 542 |
+
"0");
|
| 543 |
+
EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_eb_05).DefaultValue(),
|
| 544 |
+
"");
|
| 545 |
+
EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_eb_06).DefaultValue(),
|
| 546 |
+
"0");
|
| 547 |
+
|
| 548 |
+
EXPECT_EQ(absl::GetFlag(FLAGS_test_flag_eb_01), false);
|
| 549 |
+
EXPECT_EQ(absl::GetFlag(FLAGS_test_flag_eb_02), 0);
|
| 550 |
+
EXPECT_EQ(absl::GetFlag(FLAGS_test_flag_eb_03), 0);
|
| 551 |
+
EXPECT_EQ(absl::GetFlag(FLAGS_test_flag_eb_04), 0.0);
|
| 552 |
+
EXPECT_EQ(absl::GetFlag(FLAGS_test_flag_eb_05), "");
|
| 553 |
+
EXPECT_EQ(absl::GetFlag(FLAGS_test_flag_eb_06),
|
| 554 |
+
NonTriviallyCopyableAggregate{});
|
| 555 |
+
}
|
| 556 |
+
|
| 557 |
+
// --------------------------------------------------------------------
|
| 558 |
+
|
| 559 |
+
TEST_F(FlagTest, TestGetSet) {
|
| 560 |
+
absl::SetFlag(&FLAGS_test_flag_01, false);
|
| 561 |
+
EXPECT_EQ(absl::GetFlag(FLAGS_test_flag_01), false);
|
| 562 |
+
|
| 563 |
+
absl::SetFlag(&FLAGS_test_flag_02, 321);
|
| 564 |
+
EXPECT_EQ(absl::GetFlag(FLAGS_test_flag_02), 321);
|
| 565 |
+
|
| 566 |
+
absl::SetFlag(&FLAGS_test_flag_03, 67);
|
| 567 |
+
EXPECT_EQ(absl::GetFlag(FLAGS_test_flag_03), 67);
|
| 568 |
+
|
| 569 |
+
absl::SetFlag(&FLAGS_test_flag_04, 1);
|
| 570 |
+
EXPECT_EQ(absl::GetFlag(FLAGS_test_flag_04), 1);
|
| 571 |
+
|
| 572 |
+
absl::SetFlag(&FLAGS_test_flag_05, -908);
|
| 573 |
+
EXPECT_EQ(absl::GetFlag(FLAGS_test_flag_05), -908);
|
| 574 |
+
|
| 575 |
+
absl::SetFlag(&FLAGS_test_flag_06, 4001);
|
| 576 |
+
EXPECT_EQ(absl::GetFlag(FLAGS_test_flag_06), 4001);
|
| 577 |
+
|
| 578 |
+
absl::SetFlag(&FLAGS_test_flag_07, -23456);
|
| 579 |
+
EXPECT_EQ(absl::GetFlag(FLAGS_test_flag_07), -23456);
|
| 580 |
+
|
| 581 |
+
absl::SetFlag(&FLAGS_test_flag_08, 975310);
|
| 582 |
+
EXPECT_EQ(absl::GetFlag(FLAGS_test_flag_08), 975310);
|
| 583 |
+
|
| 584 |
+
absl::SetFlag(&FLAGS_test_flag_09, 1.00001);
|
| 585 |
+
EXPECT_NEAR(absl::GetFlag(FLAGS_test_flag_09), 1.00001, 1e-10);
|
| 586 |
+
|
| 587 |
+
absl::SetFlag(&FLAGS_test_flag_10, -3.54f);
|
| 588 |
+
EXPECT_NEAR(absl::GetFlag(FLAGS_test_flag_10), -3.54f, 1e-6f);
|
| 589 |
+
|
| 590 |
+
absl::SetFlag(&FLAGS_test_flag_11, "asdf");
|
| 591 |
+
EXPECT_EQ(absl::GetFlag(FLAGS_test_flag_11), "asdf");
|
| 592 |
+
|
| 593 |
+
absl::SetFlag(&FLAGS_test_flag_12, absl::Seconds(110));
|
| 594 |
+
EXPECT_EQ(absl::GetFlag(FLAGS_test_flag_12), absl::Seconds(110));
|
| 595 |
+
|
| 596 |
+
absl::SetFlag(&FLAGS_test_flag_13, absl::MakeInt128(-1, 0));
|
| 597 |
+
EXPECT_EQ(absl::GetFlag(FLAGS_test_flag_13), absl::MakeInt128(-1, 0));
|
| 598 |
+
|
| 599 |
+
absl::SetFlag(&FLAGS_test_flag_14, absl::MakeUint128(0, 0xFFFAAABBBCCCDDD));
|
| 600 |
+
EXPECT_EQ(absl::GetFlag(FLAGS_test_flag_14),
|
| 601 |
+
absl::MakeUint128(0, 0xFFFAAABBBCCCDDD));
|
| 602 |
+
}
|
| 603 |
+
|
| 604 |
+
// --------------------------------------------------------------------
|
| 605 |
+
|
| 606 |
+
TEST_F(FlagTest, TestGetViaReflection) {
|
| 607 |
+
auto* handle = absl::FindCommandLineFlag("test_flag_01");
|
| 608 |
+
EXPECT_EQ(*handle->TryGet<bool>(), true);
|
| 609 |
+
handle = absl::FindCommandLineFlag("test_flag_02");
|
| 610 |
+
EXPECT_EQ(*handle->TryGet<int>(), 1234);
|
| 611 |
+
handle = absl::FindCommandLineFlag("test_flag_03");
|
| 612 |
+
EXPECT_EQ(*handle->TryGet<int16_t>(), -34);
|
| 613 |
+
handle = absl::FindCommandLineFlag("test_flag_04");
|
| 614 |
+
EXPECT_EQ(*handle->TryGet<uint16_t>(), 189);
|
| 615 |
+
handle = absl::FindCommandLineFlag("test_flag_05");
|
| 616 |
+
EXPECT_EQ(*handle->TryGet<int32_t>(), 10765);
|
| 617 |
+
handle = absl::FindCommandLineFlag("test_flag_06");
|
| 618 |
+
EXPECT_EQ(*handle->TryGet<uint32_t>(), 40000);
|
| 619 |
+
handle = absl::FindCommandLineFlag("test_flag_07");
|
| 620 |
+
EXPECT_EQ(*handle->TryGet<int64_t>(), -1234567);
|
| 621 |
+
handle = absl::FindCommandLineFlag("test_flag_08");
|
| 622 |
+
EXPECT_EQ(*handle->TryGet<uint64_t>(), 9876543);
|
| 623 |
+
handle = absl::FindCommandLineFlag("test_flag_09");
|
| 624 |
+
EXPECT_NEAR(*handle->TryGet<double>(), -9.876e-50, 1e-55);
|
| 625 |
+
handle = absl::FindCommandLineFlag("test_flag_10");
|
| 626 |
+
EXPECT_NEAR(*handle->TryGet<float>(), 1.234e12f, 1e5f);
|
| 627 |
+
handle = absl::FindCommandLineFlag("test_flag_11");
|
| 628 |
+
EXPECT_EQ(*handle->TryGet<std::string>(), "");
|
| 629 |
+
handle = absl::FindCommandLineFlag("test_flag_12");
|
| 630 |
+
EXPECT_EQ(*handle->TryGet<absl::Duration>(), absl::Minutes(10));
|
| 631 |
+
handle = absl::FindCommandLineFlag("test_flag_13");
|
| 632 |
+
EXPECT_EQ(*handle->TryGet<absl::int128>(), absl::MakeInt128(-1, 0));
|
| 633 |
+
handle = absl::FindCommandLineFlag("test_flag_14");
|
| 634 |
+
EXPECT_EQ(*handle->TryGet<absl::uint128>(),
|
| 635 |
+
absl::MakeUint128(0, 0xFFFAAABBBCCCDDD));
|
| 636 |
+
}
|
| 637 |
+
|
| 638 |
+
// --------------------------------------------------------------------
|
| 639 |
+
|
| 640 |
+
TEST_F(FlagTest, ConcurrentSetAndGet) {
|
| 641 |
+
static constexpr int kNumThreads = 8;
|
| 642 |
+
// Two arbitrary durations. One thread will concurrently flip the flag
|
| 643 |
+
// between these two values, while the other threads read it and verify
|
| 644 |
+
// that no other value is seen.
|
| 645 |
+
static const absl::Duration kValidDurations[] = {
|
| 646 |
+
absl::Seconds(int64_t{0x6cebf47a9b68c802}) + absl::Nanoseconds(229702057),
|
| 647 |
+
absl::Seconds(int64_t{0x23fec0307e4e9d3}) + absl::Nanoseconds(44555374)};
|
| 648 |
+
absl::SetFlag(&FLAGS_test_flag_12, kValidDurations[0]);
|
| 649 |
+
|
| 650 |
+
std::atomic<bool> stop{false};
|
| 651 |
+
std::vector<std::thread> threads;
|
| 652 |
+
auto* handle = absl::FindCommandLineFlag("test_flag_12");
|
| 653 |
+
for (int i = 0; i < kNumThreads; i++) {
|
| 654 |
+
threads.emplace_back([&]() {
|
| 655 |
+
while (!stop.load(std::memory_order_relaxed)) {
|
| 656 |
+
// Try loading the flag both directly and via a reflection
|
| 657 |
+
// handle.
|
| 658 |
+
absl::Duration v = absl::GetFlag(FLAGS_test_flag_12);
|
| 659 |
+
EXPECT_TRUE(v == kValidDurations[0] || v == kValidDurations[1]);
|
| 660 |
+
v = *handle->TryGet<absl::Duration>();
|
| 661 |
+
EXPECT_TRUE(v == kValidDurations[0] || v == kValidDurations[1]);
|
| 662 |
+
}
|
| 663 |
+
});
|
| 664 |
+
}
|
| 665 |
+
absl::Time end_time = absl::Now() + absl::Seconds(1);
|
| 666 |
+
int i = 0;
|
| 667 |
+
while (absl::Now() < end_time) {
|
| 668 |
+
absl::SetFlag(&FLAGS_test_flag_12,
|
| 669 |
+
kValidDurations[i++ % ABSL_ARRAYSIZE(kValidDurations)]);
|
| 670 |
+
}
|
| 671 |
+
stop.store(true, std::memory_order_relaxed);
|
| 672 |
+
for (auto& t : threads) t.join();
|
| 673 |
+
}
|
| 674 |
+
|
| 675 |
+
// --------------------------------------------------------------------
|
| 676 |
+
|
| 677 |
+
int GetDflt1() { return 1; }
|
| 678 |
+
|
| 679 |
+
} // namespace
|
| 680 |
+
|
| 681 |
+
ABSL_FLAG(int, test_int_flag_with_non_const_default, GetDflt1(),
|
| 682 |
+
"test int flag non const default");
|
| 683 |
+
ABSL_FLAG(std::string, test_string_flag_with_non_const_default,
|
| 684 |
+
absl::StrCat("AAA", "BBB"), "test string flag non const default");
|
| 685 |
+
|
| 686 |
+
namespace {
|
| 687 |
+
|
| 688 |
+
TEST_F(FlagTest, TestNonConstexprDefault) {
|
| 689 |
+
EXPECT_EQ(absl::GetFlag(FLAGS_test_int_flag_with_non_const_default), 1);
|
| 690 |
+
EXPECT_EQ(absl::GetFlag(FLAGS_test_string_flag_with_non_const_default),
|
| 691 |
+
"AAABBB");
|
| 692 |
+
}
|
| 693 |
+
|
| 694 |
+
// --------------------------------------------------------------------
|
| 695 |
+
|
| 696 |
+
} // namespace
|
| 697 |
+
|
| 698 |
+
ABSL_FLAG(bool, test_flag_with_non_const_help, true,
|
| 699 |
+
absl::StrCat("test ", "flag ", "non const help"));
|
| 700 |
+
|
| 701 |
+
namespace {
|
| 702 |
+
|
| 703 |
+
#if !ABSL_FLAGS_STRIP_HELP
|
| 704 |
+
TEST_F(FlagTest, TestNonConstexprHelp) {
|
| 705 |
+
EXPECT_EQ(
|
| 706 |
+
absl::GetFlagReflectionHandle(FLAGS_test_flag_with_non_const_help).Help(),
|
| 707 |
+
"test flag non const help");
|
| 708 |
+
}
|
| 709 |
+
#endif //! ABSL_FLAGS_STRIP_HELP
|
| 710 |
+
|
| 711 |
+
// --------------------------------------------------------------------
|
| 712 |
+
|
| 713 |
+
int cb_test_value = -1;
|
| 714 |
+
void TestFlagCB();
|
| 715 |
+
|
| 716 |
+
} // namespace
|
| 717 |
+
|
| 718 |
+
ABSL_FLAG(int, test_flag_with_cb, 100, "").OnUpdate(TestFlagCB);
|
| 719 |
+
|
| 720 |
+
ABSL_FLAG(int, test_flag_with_lambda_cb, 200, "").OnUpdate([]() {
|
| 721 |
+
cb_test_value = absl::GetFlag(FLAGS_test_flag_with_lambda_cb) +
|
| 722 |
+
absl::GetFlag(FLAGS_test_flag_with_cb);
|
| 723 |
+
});
|
| 724 |
+
|
| 725 |
+
namespace {
|
| 726 |
+
|
| 727 |
+
void TestFlagCB() { cb_test_value = absl::GetFlag(FLAGS_test_flag_with_cb); }
|
| 728 |
+
|
| 729 |
+
// Tests side-effects of callback invocation.
|
| 730 |
+
TEST_F(FlagTest, CallbackInvocation) {
|
| 731 |
+
EXPECT_EQ(absl::GetFlag(FLAGS_test_flag_with_cb), 100);
|
| 732 |
+
EXPECT_EQ(absl::GetFlag(FLAGS_test_flag_with_lambda_cb), 200);
|
| 733 |
+
EXPECT_EQ(cb_test_value, 300);
|
| 734 |
+
|
| 735 |
+
absl::SetFlag(&FLAGS_test_flag_with_cb, 1);
|
| 736 |
+
EXPECT_EQ(cb_test_value, 1);
|
| 737 |
+
|
| 738 |
+
absl::SetFlag(&FLAGS_test_flag_with_lambda_cb, 3);
|
| 739 |
+
EXPECT_EQ(cb_test_value, 4);
|
| 740 |
+
}
|
| 741 |
+
|
| 742 |
+
// --------------------------------------------------------------------
|
| 743 |
+
|
| 744 |
+
struct CustomUDT {
|
| 745 |
+
CustomUDT() : a(1), b(1) {}
|
| 746 |
+
CustomUDT(int a_, int b_) : a(a_), b(b_) {}
|
| 747 |
+
|
| 748 |
+
friend bool operator==(const CustomUDT& f1, const CustomUDT& f2) {
|
| 749 |
+
return f1.a == f2.a && f1.b == f2.b;
|
| 750 |
+
}
|
| 751 |
+
|
| 752 |
+
int a;
|
| 753 |
+
int b;
|
| 754 |
+
};
|
| 755 |
+
bool AbslParseFlag(absl::string_view in, CustomUDT* f, std::string*) {
|
| 756 |
+
std::vector<absl::string_view> parts =
|
| 757 |
+
absl::StrSplit(in, ':', absl::SkipWhitespace());
|
| 758 |
+
|
| 759 |
+
if (parts.size() != 2) return false;
|
| 760 |
+
|
| 761 |
+
if (!absl::SimpleAtoi(parts[0], &f->a)) return false;
|
| 762 |
+
|
| 763 |
+
if (!absl::SimpleAtoi(parts[1], &f->b)) return false;
|
| 764 |
+
|
| 765 |
+
return true;
|
| 766 |
+
}
|
| 767 |
+
std::string AbslUnparseFlag(const CustomUDT& f) {
|
| 768 |
+
return absl::StrCat(f.a, ":", f.b);
|
| 769 |
+
}
|
| 770 |
+
|
| 771 |
+
} // namespace
|
| 772 |
+
|
| 773 |
+
ABSL_FLAG(CustomUDT, test_flag_custom_udt, CustomUDT(), "test flag custom UDT");
|
| 774 |
+
|
| 775 |
+
namespace {
|
| 776 |
+
|
| 777 |
+
TEST_F(FlagTest, TestCustomUDT) {
|
| 778 |
+
EXPECT_EQ(flags::StorageKind<CustomUDT>(),
|
| 779 |
+
flags::FlagValueStorageKind::kOneWordAtomic);
|
| 780 |
+
EXPECT_EQ(absl::GetFlag(FLAGS_test_flag_custom_udt), CustomUDT(1, 1));
|
| 781 |
+
absl::SetFlag(&FLAGS_test_flag_custom_udt, CustomUDT(2, 3));
|
| 782 |
+
EXPECT_EQ(absl::GetFlag(FLAGS_test_flag_custom_udt), CustomUDT(2, 3));
|
| 783 |
+
}
|
| 784 |
+
|
| 785 |
+
// MSVC produces link error on the type mismatch.
|
| 786 |
+
// Linux does not have build errors and validations work as expected.
|
| 787 |
+
#if !defined(_WIN32) && GTEST_HAS_DEATH_TEST
|
| 788 |
+
|
| 789 |
+
using FlagDeathTest = FlagTest;
|
| 790 |
+
|
| 791 |
+
TEST_F(FlagDeathTest, TestTypeMismatchValidations) {
|
| 792 |
+
#if !defined(NDEBUG)
|
| 793 |
+
EXPECT_DEATH_IF_SUPPORTED(
|
| 794 |
+
static_cast<void>(absl::GetFlag(FLAGS_mistyped_int_flag)),
|
| 795 |
+
"Flag 'mistyped_int_flag' is defined as one type and declared "
|
| 796 |
+
"as another");
|
| 797 |
+
EXPECT_DEATH_IF_SUPPORTED(
|
| 798 |
+
static_cast<void>(absl::GetFlag(FLAGS_mistyped_string_flag)),
|
| 799 |
+
"Flag 'mistyped_string_flag' is defined as one type and "
|
| 800 |
+
"declared as another");
|
| 801 |
+
#endif
|
| 802 |
+
|
| 803 |
+
EXPECT_DEATH_IF_SUPPORTED(
|
| 804 |
+
absl::SetFlag(&FLAGS_mistyped_int_flag, 1),
|
| 805 |
+
"Flag 'mistyped_int_flag' is defined as one type and declared "
|
| 806 |
+
"as another");
|
| 807 |
+
EXPECT_DEATH_IF_SUPPORTED(
|
| 808 |
+
absl::SetFlag(&FLAGS_mistyped_string_flag, std::vector<std::string>{}),
|
| 809 |
+
"Flag 'mistyped_string_flag' is defined as one type and declared as "
|
| 810 |
+
"another");
|
| 811 |
+
}
|
| 812 |
+
|
| 813 |
+
#endif
|
| 814 |
+
|
| 815 |
+
// --------------------------------------------------------------------
|
| 816 |
+
|
| 817 |
+
// A contrived type that offers implicit and explicit conversion from specific
|
| 818 |
+
// source types.
|
| 819 |
+
struct ConversionTestVal {
|
| 820 |
+
ConversionTestVal() = default;
|
| 821 |
+
explicit ConversionTestVal(int a_in) : a(a_in) {}
|
| 822 |
+
|
| 823 |
+
enum class ViaImplicitConv { kTen = 10, kEleven };
|
| 824 |
+
// NOLINTNEXTLINE
|
| 825 |
+
ConversionTestVal(ViaImplicitConv from) : a(static_cast<int>(from)) {}
|
| 826 |
+
|
| 827 |
+
int a;
|
| 828 |
+
};
|
| 829 |
+
|
| 830 |
+
bool AbslParseFlag(absl::string_view in, ConversionTestVal* val_out,
|
| 831 |
+
std::string*) {
|
| 832 |
+
if (!absl::SimpleAtoi(in, &val_out->a)) {
|
| 833 |
+
return false;
|
| 834 |
+
}
|
| 835 |
+
return true;
|
| 836 |
+
}
|
| 837 |
+
std::string AbslUnparseFlag(const ConversionTestVal& val) {
|
| 838 |
+
return absl::StrCat(val.a);
|
| 839 |
+
}
|
| 840 |
+
|
| 841 |
+
} // namespace
|
| 842 |
+
|
| 843 |
+
// Flag default values can be specified with a value that converts to the flag
|
| 844 |
+
// value type implicitly.
|
| 845 |
+
ABSL_FLAG(ConversionTestVal, test_flag_implicit_conv,
|
| 846 |
+
ConversionTestVal::ViaImplicitConv::kTen,
|
| 847 |
+
"test flag init via implicit conversion");
|
| 848 |
+
|
| 849 |
+
namespace {
|
| 850 |
+
|
| 851 |
+
TEST_F(FlagTest, CanSetViaImplicitConversion) {
|
| 852 |
+
EXPECT_EQ(absl::GetFlag(FLAGS_test_flag_implicit_conv).a, 10);
|
| 853 |
+
absl::SetFlag(&FLAGS_test_flag_implicit_conv,
|
| 854 |
+
ConversionTestVal::ViaImplicitConv::kEleven);
|
| 855 |
+
EXPECT_EQ(absl::GetFlag(FLAGS_test_flag_implicit_conv).a, 11);
|
| 856 |
+
}
|
| 857 |
+
|
| 858 |
+
// --------------------------------------------------------------------
|
| 859 |
+
|
| 860 |
+
struct NonDfltConstructible {
|
| 861 |
+
public:
|
| 862 |
+
// This constructor tests that we can initialize the flag with int value
|
| 863 |
+
NonDfltConstructible(int i) : value(i) {} // NOLINT
|
| 864 |
+
|
| 865 |
+
// This constructor tests that we can't initialize the flag with char value
|
| 866 |
+
// but can with explicitly constructed NonDfltConstructible.
|
| 867 |
+
explicit NonDfltConstructible(char c) : value(100 + static_cast<int>(c)) {}
|
| 868 |
+
|
| 869 |
+
int value;
|
| 870 |
+
};
|
| 871 |
+
|
| 872 |
+
bool AbslParseFlag(absl::string_view in, NonDfltConstructible* ndc_out,
|
| 873 |
+
std::string*) {
|
| 874 |
+
return absl::SimpleAtoi(in, &ndc_out->value);
|
| 875 |
+
}
|
| 876 |
+
std::string AbslUnparseFlag(const NonDfltConstructible& ndc) {
|
| 877 |
+
return absl::StrCat(ndc.value);
|
| 878 |
+
}
|
| 879 |
+
|
| 880 |
+
} // namespace
|
| 881 |
+
|
| 882 |
+
ABSL_FLAG(NonDfltConstructible, ndc_flag1, NonDfltConstructible('1'),
|
| 883 |
+
"Flag with non default constructible type");
|
| 884 |
+
ABSL_FLAG(NonDfltConstructible, ndc_flag2, 0,
|
| 885 |
+
"Flag with non default constructible type");
|
| 886 |
+
|
| 887 |
+
namespace {
|
| 888 |
+
|
| 889 |
+
TEST_F(FlagTest, TestNonDefaultConstructibleType) {
|
| 890 |
+
EXPECT_EQ(absl::GetFlag(FLAGS_ndc_flag1).value, '1' + 100);
|
| 891 |
+
EXPECT_EQ(absl::GetFlag(FLAGS_ndc_flag2).value, 0);
|
| 892 |
+
|
| 893 |
+
absl::SetFlag(&FLAGS_ndc_flag1, NonDfltConstructible('A'));
|
| 894 |
+
absl::SetFlag(&FLAGS_ndc_flag2, 25);
|
| 895 |
+
|
| 896 |
+
EXPECT_EQ(absl::GetFlag(FLAGS_ndc_flag1).value, 'A' + 100);
|
| 897 |
+
EXPECT_EQ(absl::GetFlag(FLAGS_ndc_flag2).value, 25);
|
| 898 |
+
}
|
| 899 |
+
|
| 900 |
+
} // namespace
|
| 901 |
+
|
| 902 |
+
// --------------------------------------------------------------------
|
| 903 |
+
|
| 904 |
+
ABSL_RETIRED_FLAG(bool, old_bool_flag, true, "old descr");
|
| 905 |
+
ABSL_RETIRED_FLAG(int, old_int_flag, (int)std::sqrt(10), "old descr");
|
| 906 |
+
ABSL_RETIRED_FLAG(std::string, old_str_flag, "", absl::StrCat("old ", "descr"));
|
| 907 |
+
|
| 908 |
+
namespace {
|
| 909 |
+
|
| 910 |
+
bool initialization_order_fiasco_test ABSL_ATTRIBUTE_UNUSED = [] {
|
| 911 |
+
// Iterate over all the flags during static initialization.
|
| 912 |
+
// This should not trigger ASan's initialization-order-fiasco.
|
| 913 |
+
auto* handle1 = absl::FindCommandLineFlag("flag_on_separate_file");
|
| 914 |
+
auto* handle2 = absl::FindCommandLineFlag("retired_flag_on_separate_file");
|
| 915 |
+
if (handle1 != nullptr && handle2 != nullptr) {
|
| 916 |
+
return handle1->Name() == handle2->Name();
|
| 917 |
+
}
|
| 918 |
+
return true;
|
| 919 |
+
}();
|
| 920 |
+
|
| 921 |
+
TEST_F(FlagTest, TestRetiredFlagRegistration) {
|
| 922 |
+
auto* handle = absl::FindCommandLineFlag("old_bool_flag");
|
| 923 |
+
EXPECT_TRUE(handle->IsOfType<bool>());
|
| 924 |
+
EXPECT_TRUE(handle->IsRetired());
|
| 925 |
+
handle = absl::FindCommandLineFlag("old_int_flag");
|
| 926 |
+
EXPECT_TRUE(handle->IsOfType<int>());
|
| 927 |
+
EXPECT_TRUE(handle->IsRetired());
|
| 928 |
+
handle = absl::FindCommandLineFlag("old_str_flag");
|
| 929 |
+
EXPECT_TRUE(handle->IsOfType<std::string>());
|
| 930 |
+
EXPECT_TRUE(handle->IsRetired());
|
| 931 |
+
}
|
| 932 |
+
|
| 933 |
+
} // namespace
|
| 934 |
+
|
| 935 |
+
// --------------------------------------------------------------------
|
| 936 |
+
|
| 937 |
+
namespace {
|
| 938 |
+
|
| 939 |
+
// User-defined type with small alignment, but size exceeding 16.
|
| 940 |
+
struct SmallAlignUDT {
|
| 941 |
+
SmallAlignUDT() : c('A'), s(12) {}
|
| 942 |
+
char c;
|
| 943 |
+
int16_t s;
|
| 944 |
+
char bytes[14];
|
| 945 |
+
};
|
| 946 |
+
|
| 947 |
+
bool AbslParseFlag(absl::string_view, SmallAlignUDT*, std::string*) {
|
| 948 |
+
return true;
|
| 949 |
+
}
|
| 950 |
+
std::string AbslUnparseFlag(const SmallAlignUDT&) { return ""; }
|
| 951 |
+
|
| 952 |
+
// User-defined type with small size, but not trivially copyable.
|
| 953 |
+
struct NonTriviallyCopyableUDT {
|
| 954 |
+
NonTriviallyCopyableUDT() : c('A') {}
|
| 955 |
+
NonTriviallyCopyableUDT(const NonTriviallyCopyableUDT& rhs) : c(rhs.c) {}
|
| 956 |
+
NonTriviallyCopyableUDT& operator=(const NonTriviallyCopyableUDT& rhs) {
|
| 957 |
+
c = rhs.c;
|
| 958 |
+
return *this;
|
| 959 |
+
}
|
| 960 |
+
|
| 961 |
+
char c;
|
| 962 |
+
};
|
| 963 |
+
|
| 964 |
+
bool AbslParseFlag(absl::string_view, NonTriviallyCopyableUDT*, std::string*) {
|
| 965 |
+
return true;
|
| 966 |
+
}
|
| 967 |
+
std::string AbslUnparseFlag(const NonTriviallyCopyableUDT&) { return ""; }
|
| 968 |
+
|
| 969 |
+
} // namespace
|
| 970 |
+
|
| 971 |
+
ABSL_FLAG(SmallAlignUDT, test_flag_sa_udt, {}, "help");
|
| 972 |
+
ABSL_FLAG(NonTriviallyCopyableUDT, test_flag_ntc_udt, {}, "help");
|
| 973 |
+
|
| 974 |
+
namespace {
|
| 975 |
+
|
| 976 |
+
TEST_F(FlagTest, TestSmallAlignUDT) {
|
| 977 |
+
SmallAlignUDT value = absl::GetFlag(FLAGS_test_flag_sa_udt);
|
| 978 |
+
EXPECT_EQ(value.c, 'A');
|
| 979 |
+
EXPECT_EQ(value.s, 12);
|
| 980 |
+
|
| 981 |
+
value.c = 'B';
|
| 982 |
+
value.s = 45;
|
| 983 |
+
absl::SetFlag(&FLAGS_test_flag_sa_udt, value);
|
| 984 |
+
value = absl::GetFlag(FLAGS_test_flag_sa_udt);
|
| 985 |
+
EXPECT_EQ(value.c, 'B');
|
| 986 |
+
EXPECT_EQ(value.s, 45);
|
| 987 |
+
}
|
| 988 |
+
|
| 989 |
+
TEST_F(FlagTest, TestNonTriviallyCopyableUDT) {
|
| 990 |
+
NonTriviallyCopyableUDT value = absl::GetFlag(FLAGS_test_flag_ntc_udt);
|
| 991 |
+
EXPECT_EQ(value.c, 'A');
|
| 992 |
+
|
| 993 |
+
value.c = 'B';
|
| 994 |
+
absl::SetFlag(&FLAGS_test_flag_ntc_udt, value);
|
| 995 |
+
value = absl::GetFlag(FLAGS_test_flag_ntc_udt);
|
| 996 |
+
EXPECT_EQ(value.c, 'B');
|
| 997 |
+
}
|
| 998 |
+
|
| 999 |
+
} // namespace
|
| 1000 |
+
|
| 1001 |
+
// --------------------------------------------------------------------
|
| 1002 |
+
|
| 1003 |
+
namespace {
|
| 1004 |
+
|
| 1005 |
+
enum TestE { A = 1, B = 2, C = 3 };
|
| 1006 |
+
|
| 1007 |
+
struct EnumWrapper {
|
| 1008 |
+
EnumWrapper() : e(A) {}
|
| 1009 |
+
|
| 1010 |
+
TestE e;
|
| 1011 |
+
};
|
| 1012 |
+
|
| 1013 |
+
bool AbslParseFlag(absl::string_view, EnumWrapper*, std::string*) {
|
| 1014 |
+
return true;
|
| 1015 |
+
}
|
| 1016 |
+
std::string AbslUnparseFlag(const EnumWrapper&) { return ""; }
|
| 1017 |
+
|
| 1018 |
+
} // namespace
|
| 1019 |
+
|
| 1020 |
+
ABSL_FLAG(EnumWrapper, test_enum_wrapper_flag, {}, "help");
|
| 1021 |
+
|
| 1022 |
+
TEST_F(FlagTest, TesTypeWrappingEnum) {
|
| 1023 |
+
EnumWrapper value = absl::GetFlag(FLAGS_test_enum_wrapper_flag);
|
| 1024 |
+
EXPECT_EQ(value.e, A);
|
| 1025 |
+
|
| 1026 |
+
value.e = B;
|
| 1027 |
+
absl::SetFlag(&FLAGS_test_enum_wrapper_flag, value);
|
| 1028 |
+
value = absl::GetFlag(FLAGS_test_enum_wrapper_flag);
|
| 1029 |
+
EXPECT_EQ(value.e, B);
|
| 1030 |
+
}
|
| 1031 |
+
|
| 1032 |
+
// This is a compile test to ensure macros are expanded within ABSL_FLAG and
|
| 1033 |
+
// ABSL_DECLARE_FLAG.
|
| 1034 |
+
#define FLAG_NAME_MACRO(name) prefix_##name
|
| 1035 |
+
ABSL_DECLARE_FLAG(int, FLAG_NAME_MACRO(test_macro_named_flag));
|
| 1036 |
+
ABSL_FLAG(int, FLAG_NAME_MACRO(test_macro_named_flag), 0,
|
| 1037 |
+
"Testing macro expansion within ABSL_FLAG");
|
| 1038 |
+
|
| 1039 |
+
TEST_F(FlagTest, MacroWithinAbslFlag) {
|
| 1040 |
+
EXPECT_EQ(absl::GetFlag(FLAGS_prefix_test_macro_named_flag), 0);
|
| 1041 |
+
absl::SetFlag(&FLAGS_prefix_test_macro_named_flag, 1);
|
| 1042 |
+
EXPECT_EQ(absl::GetFlag(FLAGS_prefix_test_macro_named_flag), 1);
|
| 1043 |
+
}
|
| 1044 |
+
|
| 1045 |
+
// --------------------------------------------------------------------
|
| 1046 |
+
|
| 1047 |
+
#if defined(__GNUC__) && !defined(__clang__) && __GNUC__ <= 5
|
| 1048 |
+
#define ABSL_SKIP_OPTIONAL_BOOL_TEST_DUE_TO_GCC_BUG
|
| 1049 |
+
#endif
|
| 1050 |
+
|
| 1051 |
+
#ifndef ABSL_SKIP_OPTIONAL_BOOL_TEST_DUE_TO_GCC_BUG
|
| 1052 |
+
ABSL_FLAG(absl::optional<bool>, optional_bool, absl::nullopt, "help");
|
| 1053 |
+
#endif
|
| 1054 |
+
ABSL_FLAG(absl::optional<int>, optional_int, {}, "help");
|
| 1055 |
+
ABSL_FLAG(absl::optional<double>, optional_double, 9.3, "help");
|
| 1056 |
+
ABSL_FLAG(absl::optional<std::string>, optional_string, absl::nullopt, "help");
|
| 1057 |
+
ABSL_FLAG(absl::optional<absl::Duration>, optional_duration, absl::nullopt,
|
| 1058 |
+
"help");
|
| 1059 |
+
ABSL_FLAG(absl::optional<absl::optional<int>>, optional_optional_int,
|
| 1060 |
+
absl::nullopt, "help");
|
| 1061 |
+
#if defined(ABSL_HAVE_STD_OPTIONAL) && !defined(ABSL_USES_STD_OPTIONAL)
|
| 1062 |
+
ABSL_FLAG(std::optional<int64_t>, std_optional_int64, std::nullopt, "help");
|
| 1063 |
+
#endif
|
| 1064 |
+
|
| 1065 |
+
namespace {
|
| 1066 |
+
|
| 1067 |
+
#ifndef ABSL_SKIP_OPTIONAL_BOOL_TEST_DUE_TO_GCC_BUG
|
| 1068 |
+
TEST_F(FlagTest, TestOptionalBool) {
|
| 1069 |
+
EXPECT_FALSE(absl::GetFlag(FLAGS_optional_bool).has_value());
|
| 1070 |
+
EXPECT_EQ(absl::GetFlag(FLAGS_optional_bool), absl::nullopt);
|
| 1071 |
+
|
| 1072 |
+
absl::SetFlag(&FLAGS_optional_bool, false);
|
| 1073 |
+
EXPECT_TRUE(absl::GetFlag(FLAGS_optional_bool).has_value());
|
| 1074 |
+
EXPECT_EQ(absl::GetFlag(FLAGS_optional_bool), false);
|
| 1075 |
+
|
| 1076 |
+
absl::SetFlag(&FLAGS_optional_bool, true);
|
| 1077 |
+
EXPECT_TRUE(absl::GetFlag(FLAGS_optional_bool).has_value());
|
| 1078 |
+
EXPECT_EQ(absl::GetFlag(FLAGS_optional_bool), true);
|
| 1079 |
+
|
| 1080 |
+
absl::SetFlag(&FLAGS_optional_bool, absl::nullopt);
|
| 1081 |
+
EXPECT_FALSE(absl::GetFlag(FLAGS_optional_bool).has_value());
|
| 1082 |
+
EXPECT_EQ(absl::GetFlag(FLAGS_optional_bool), absl::nullopt);
|
| 1083 |
+
}
|
| 1084 |
+
|
| 1085 |
+
// --------------------------------------------------------------------
|
| 1086 |
+
#endif
|
| 1087 |
+
|
| 1088 |
+
TEST_F(FlagTest, TestOptionalInt) {
|
| 1089 |
+
EXPECT_FALSE(absl::GetFlag(FLAGS_optional_int).has_value());
|
| 1090 |
+
EXPECT_EQ(absl::GetFlag(FLAGS_optional_int), absl::nullopt);
|
| 1091 |
+
|
| 1092 |
+
absl::SetFlag(&FLAGS_optional_int, 0);
|
| 1093 |
+
EXPECT_TRUE(absl::GetFlag(FLAGS_optional_int).has_value());
|
| 1094 |
+
EXPECT_EQ(absl::GetFlag(FLAGS_optional_int), 0);
|
| 1095 |
+
|
| 1096 |
+
absl::SetFlag(&FLAGS_optional_int, 10);
|
| 1097 |
+
EXPECT_TRUE(absl::GetFlag(FLAGS_optional_int).has_value());
|
| 1098 |
+
EXPECT_EQ(absl::GetFlag(FLAGS_optional_int), 10);
|
| 1099 |
+
|
| 1100 |
+
absl::SetFlag(&FLAGS_optional_int, absl::nullopt);
|
| 1101 |
+
EXPECT_FALSE(absl::GetFlag(FLAGS_optional_int).has_value());
|
| 1102 |
+
EXPECT_EQ(absl::GetFlag(FLAGS_optional_int), absl::nullopt);
|
| 1103 |
+
}
|
| 1104 |
+
|
| 1105 |
+
// --------------------------------------------------------------------
|
| 1106 |
+
|
| 1107 |
+
TEST_F(FlagTest, TestOptionalDouble) {
|
| 1108 |
+
EXPECT_TRUE(absl::GetFlag(FLAGS_optional_double).has_value());
|
| 1109 |
+
EXPECT_DOUBLE_EQ(*absl::GetFlag(FLAGS_optional_double), 9.3);
|
| 1110 |
+
|
| 1111 |
+
absl::SetFlag(&FLAGS_optional_double, 0.0);
|
| 1112 |
+
EXPECT_TRUE(absl::GetFlag(FLAGS_optional_double).has_value());
|
| 1113 |
+
EXPECT_EQ(absl::GetFlag(FLAGS_optional_double), 0.0);
|
| 1114 |
+
|
| 1115 |
+
absl::SetFlag(&FLAGS_optional_double, 1.234);
|
| 1116 |
+
EXPECT_TRUE(absl::GetFlag(FLAGS_optional_double).has_value());
|
| 1117 |
+
EXPECT_DOUBLE_EQ(*absl::GetFlag(FLAGS_optional_double), 1.234);
|
| 1118 |
+
|
| 1119 |
+
absl::SetFlag(&FLAGS_optional_double, absl::nullopt);
|
| 1120 |
+
EXPECT_FALSE(absl::GetFlag(FLAGS_optional_double).has_value());
|
| 1121 |
+
EXPECT_EQ(absl::GetFlag(FLAGS_optional_double), absl::nullopt);
|
| 1122 |
+
}
|
| 1123 |
+
|
| 1124 |
+
// --------------------------------------------------------------------
|
| 1125 |
+
|
| 1126 |
+
TEST_F(FlagTest, TestOptionalString) {
|
| 1127 |
+
EXPECT_FALSE(absl::GetFlag(FLAGS_optional_string).has_value());
|
| 1128 |
+
EXPECT_EQ(absl::GetFlag(FLAGS_optional_string), absl::nullopt);
|
| 1129 |
+
|
| 1130 |
+
// Setting optional string to "" leads to undefined behavior.
|
| 1131 |
+
|
| 1132 |
+
absl::SetFlag(&FLAGS_optional_string, " ");
|
| 1133 |
+
EXPECT_TRUE(absl::GetFlag(FLAGS_optional_string).has_value());
|
| 1134 |
+
EXPECT_EQ(absl::GetFlag(FLAGS_optional_string), " ");
|
| 1135 |
+
|
| 1136 |
+
absl::SetFlag(&FLAGS_optional_string, "QWERTY");
|
| 1137 |
+
EXPECT_TRUE(absl::GetFlag(FLAGS_optional_string).has_value());
|
| 1138 |
+
EXPECT_EQ(absl::GetFlag(FLAGS_optional_string), "QWERTY");
|
| 1139 |
+
|
| 1140 |
+
absl::SetFlag(&FLAGS_optional_string, absl::nullopt);
|
| 1141 |
+
EXPECT_FALSE(absl::GetFlag(FLAGS_optional_string).has_value());
|
| 1142 |
+
EXPECT_EQ(absl::GetFlag(FLAGS_optional_string), absl::nullopt);
|
| 1143 |
+
}
|
| 1144 |
+
|
| 1145 |
+
// --------------------------------------------------------------------
|
| 1146 |
+
|
| 1147 |
+
TEST_F(FlagTest, TestOptionalDuration) {
|
| 1148 |
+
EXPECT_FALSE(absl::GetFlag(FLAGS_optional_duration).has_value());
|
| 1149 |
+
EXPECT_EQ(absl::GetFlag(FLAGS_optional_duration), absl::nullopt);
|
| 1150 |
+
|
| 1151 |
+
absl::SetFlag(&FLAGS_optional_duration, absl::ZeroDuration());
|
| 1152 |
+
EXPECT_TRUE(absl::GetFlag(FLAGS_optional_duration).has_value());
|
| 1153 |
+
EXPECT_EQ(absl::GetFlag(FLAGS_optional_duration), absl::Seconds(0));
|
| 1154 |
+
|
| 1155 |
+
absl::SetFlag(&FLAGS_optional_duration, absl::Hours(3));
|
| 1156 |
+
EXPECT_TRUE(absl::GetFlag(FLAGS_optional_duration).has_value());
|
| 1157 |
+
EXPECT_EQ(absl::GetFlag(FLAGS_optional_duration), absl::Hours(3));
|
| 1158 |
+
|
| 1159 |
+
absl::SetFlag(&FLAGS_optional_duration, absl::nullopt);
|
| 1160 |
+
EXPECT_FALSE(absl::GetFlag(FLAGS_optional_duration).has_value());
|
| 1161 |
+
EXPECT_EQ(absl::GetFlag(FLAGS_optional_duration), absl::nullopt);
|
| 1162 |
+
}
|
| 1163 |
+
|
| 1164 |
+
// --------------------------------------------------------------------
|
| 1165 |
+
|
| 1166 |
+
TEST_F(FlagTest, TestOptionalOptional) {
|
| 1167 |
+
EXPECT_FALSE(absl::GetFlag(FLAGS_optional_optional_int).has_value());
|
| 1168 |
+
EXPECT_EQ(absl::GetFlag(FLAGS_optional_optional_int), absl::nullopt);
|
| 1169 |
+
|
| 1170 |
+
absl::optional<int> nullint{absl::nullopt};
|
| 1171 |
+
|
| 1172 |
+
absl::SetFlag(&FLAGS_optional_optional_int, nullint);
|
| 1173 |
+
EXPECT_TRUE(absl::GetFlag(FLAGS_optional_optional_int).has_value());
|
| 1174 |
+
EXPECT_NE(absl::GetFlag(FLAGS_optional_optional_int), nullint);
|
| 1175 |
+
EXPECT_EQ(absl::GetFlag(FLAGS_optional_optional_int),
|
| 1176 |
+
absl::optional<absl::optional<int>>{nullint});
|
| 1177 |
+
|
| 1178 |
+
absl::SetFlag(&FLAGS_optional_optional_int, 0);
|
| 1179 |
+
EXPECT_TRUE(absl::GetFlag(FLAGS_optional_optional_int).has_value());
|
| 1180 |
+
EXPECT_EQ(absl::GetFlag(FLAGS_optional_optional_int), 0);
|
| 1181 |
+
|
| 1182 |
+
absl::SetFlag(&FLAGS_optional_optional_int, absl::optional<int>{0});
|
| 1183 |
+
EXPECT_TRUE(absl::GetFlag(FLAGS_optional_optional_int).has_value());
|
| 1184 |
+
EXPECT_EQ(absl::GetFlag(FLAGS_optional_optional_int), 0);
|
| 1185 |
+
EXPECT_EQ(absl::GetFlag(FLAGS_optional_optional_int), absl::optional<int>{0});
|
| 1186 |
+
|
| 1187 |
+
absl::SetFlag(&FLAGS_optional_optional_int, absl::nullopt);
|
| 1188 |
+
EXPECT_FALSE(absl::GetFlag(FLAGS_optional_optional_int).has_value());
|
| 1189 |
+
EXPECT_EQ(absl::GetFlag(FLAGS_optional_optional_int), absl::nullopt);
|
| 1190 |
+
}
|
| 1191 |
+
|
| 1192 |
+
// --------------------------------------------------------------------
|
| 1193 |
+
|
| 1194 |
+
#if defined(ABSL_HAVE_STD_OPTIONAL) && !defined(ABSL_USES_STD_OPTIONAL)
|
| 1195 |
+
|
| 1196 |
+
TEST_F(FlagTest, TestStdOptional) {
|
| 1197 |
+
EXPECT_FALSE(absl::GetFlag(FLAGS_std_optional_int64).has_value());
|
| 1198 |
+
EXPECT_EQ(absl::GetFlag(FLAGS_std_optional_int64), std::nullopt);
|
| 1199 |
+
|
| 1200 |
+
absl::SetFlag(&FLAGS_std_optional_int64, 0);
|
| 1201 |
+
EXPECT_TRUE(absl::GetFlag(FLAGS_std_optional_int64).has_value());
|
| 1202 |
+
EXPECT_EQ(absl::GetFlag(FLAGS_std_optional_int64), 0);
|
| 1203 |
+
|
| 1204 |
+
absl::SetFlag(&FLAGS_std_optional_int64, 0xFFFFFFFFFF16);
|
| 1205 |
+
EXPECT_TRUE(absl::GetFlag(FLAGS_std_optional_int64).has_value());
|
| 1206 |
+
EXPECT_EQ(absl::GetFlag(FLAGS_std_optional_int64), 0xFFFFFFFFFF16);
|
| 1207 |
+
|
| 1208 |
+
absl::SetFlag(&FLAGS_std_optional_int64, std::nullopt);
|
| 1209 |
+
EXPECT_FALSE(absl::GetFlag(FLAGS_std_optional_int64).has_value());
|
| 1210 |
+
EXPECT_EQ(absl::GetFlag(FLAGS_std_optional_int64), std::nullopt);
|
| 1211 |
+
}
|
| 1212 |
+
|
| 1213 |
+
// --------------------------------------------------------------------
|
| 1214 |
+
|
| 1215 |
+
#endif
|
| 1216 |
+
|
| 1217 |
+
} // namespace
|
weight/_dep/abseil-cpp/absl/flags/flag_test_defs.cc
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
//
|
| 2 |
+
// Copyright 2019 The Abseil Authors.
|
| 3 |
+
//
|
| 4 |
+
// Licensed under the Apache License, Version 2.0 (the "License");
|
| 5 |
+
// you may not use this file except in compliance with the License.
|
| 6 |
+
// You may obtain a copy of the License at
|
| 7 |
+
//
|
| 8 |
+
// https://www.apache.org/licenses/LICENSE-2.0
|
| 9 |
+
//
|
| 10 |
+
// Unless required by applicable law or agreed to in writing, software
|
| 11 |
+
// distributed under the License is distributed on an "AS IS" BASIS,
|
| 12 |
+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
| 13 |
+
// See the License for the specific language governing permissions and
|
| 14 |
+
// limitations under the License.
|
| 15 |
+
|
| 16 |
+
// This file is used to test the mismatch of the flag type between definition
|
| 17 |
+
// and declaration. These are definitions. flag_test.cc contains declarations.
|
| 18 |
+
#include <string>
|
| 19 |
+
#include "absl/flags/flag.h"
|
| 20 |
+
|
| 21 |
+
ABSL_FLAG(int, mistyped_int_flag, 0, "");
|
| 22 |
+
ABSL_FLAG(std::string, mistyped_string_flag, "", "");
|
| 23 |
+
ABSL_FLAG(bool, flag_on_separate_file, false, "");
|
| 24 |
+
ABSL_RETIRED_FLAG(bool, retired_flag_on_separate_file, false, "");
|
weight/_dep/abseil-cpp/absl/flags/internal/commandlineflag.h
ADDED
|
@@ -0,0 +1,68 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
//
|
| 2 |
+
// Copyright 2019 The Abseil Authors.
|
| 3 |
+
//
|
| 4 |
+
// Licensed under the Apache License, Version 2.0 (the "License");
|
| 5 |
+
// you may not use this file except in compliance with the License.
|
| 6 |
+
// You may obtain a copy of the License at
|
| 7 |
+
//
|
| 8 |
+
// https://www.apache.org/licenses/LICENSE-2.0
|
| 9 |
+
//
|
| 10 |
+
// Unless required by applicable law or agreed to in writing, software
|
| 11 |
+
// distributed under the License is distributed on an "AS IS" BASIS,
|
| 12 |
+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
| 13 |
+
// See the License for the specific language governing permissions and
|
| 14 |
+
// limitations under the License.
|
| 15 |
+
|
| 16 |
+
#ifndef ABSL_FLAGS_INTERNAL_COMMANDLINEFLAG_H_
|
| 17 |
+
#define ABSL_FLAGS_INTERNAL_COMMANDLINEFLAG_H_
|
| 18 |
+
|
| 19 |
+
#include "absl/base/config.h"
|
| 20 |
+
#include "absl/base/internal/fast_type_id.h"
|
| 21 |
+
|
| 22 |
+
namespace absl {
|
| 23 |
+
ABSL_NAMESPACE_BEGIN
|
| 24 |
+
namespace flags_internal {
|
| 25 |
+
|
| 26 |
+
// An alias for flag fast type id. This value identifies the flag value type
|
| 27 |
+
// similarly to typeid(T), without relying on RTTI being available. In most
|
| 28 |
+
// cases this id is enough to uniquely identify the flag's value type. In a few
|
| 29 |
+
// cases we'll have to resort to using actual RTTI implementation if it is
|
| 30 |
+
// available.
|
| 31 |
+
using FlagFastTypeId = absl::base_internal::FastTypeIdType;
|
| 32 |
+
|
| 33 |
+
// Options that control SetCommandLineOptionWithMode.
|
| 34 |
+
enum FlagSettingMode {
|
| 35 |
+
// update the flag's value unconditionally (can call this multiple times).
|
| 36 |
+
SET_FLAGS_VALUE,
|
| 37 |
+
// update the flag's value, but *only if* it has not yet been updated
|
| 38 |
+
// with SET_FLAGS_VALUE, SET_FLAG_IF_DEFAULT, or "FLAGS_xxx = nondef".
|
| 39 |
+
SET_FLAG_IF_DEFAULT,
|
| 40 |
+
// set the flag's default value to this. If the flag has not been updated
|
| 41 |
+
// yet (via SET_FLAGS_VALUE, SET_FLAG_IF_DEFAULT, or "FLAGS_xxx = nondef")
|
| 42 |
+
// change the flag's current value to the new default value as well.
|
| 43 |
+
SET_FLAGS_DEFAULT
|
| 44 |
+
};
|
| 45 |
+
|
| 46 |
+
// Options that control ParseFrom: Source of a value.
|
| 47 |
+
enum ValueSource {
|
| 48 |
+
// Flag is being set by value specified on a command line.
|
| 49 |
+
kCommandLine,
|
| 50 |
+
// Flag is being set by value specified in the code.
|
| 51 |
+
kProgrammaticChange,
|
| 52 |
+
};
|
| 53 |
+
|
| 54 |
+
// Handle to FlagState objects. Specific flag state objects will restore state
|
| 55 |
+
// of a flag produced this flag state from method CommandLineFlag::SaveState().
|
| 56 |
+
class FlagStateInterface {
|
| 57 |
+
public:
|
| 58 |
+
virtual ~FlagStateInterface();
|
| 59 |
+
|
| 60 |
+
// Restores the flag originated this object to the saved state.
|
| 61 |
+
virtual void Restore() const = 0;
|
| 62 |
+
};
|
| 63 |
+
|
| 64 |
+
} // namespace flags_internal
|
| 65 |
+
ABSL_NAMESPACE_END
|
| 66 |
+
} // namespace absl
|
| 67 |
+
|
| 68 |
+
#endif // ABSL_FLAGS_INTERNAL_COMMANDLINEFLAG_H_
|
weight/_dep/abseil-cpp/absl/flags/internal/flag.h
ADDED
|
@@ -0,0 +1,796 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
//
|
| 2 |
+
// Copyright 2019 The Abseil Authors.
|
| 3 |
+
//
|
| 4 |
+
// Licensed under the Apache License, Version 2.0 (the "License");
|
| 5 |
+
// you may not use this file except in compliance with the License.
|
| 6 |
+
// You may obtain a copy of the License at
|
| 7 |
+
//
|
| 8 |
+
// https://www.apache.org/licenses/LICENSE-2.0
|
| 9 |
+
//
|
| 10 |
+
// Unless required by applicable law or agreed to in writing, software
|
| 11 |
+
// distributed under the License is distributed on an "AS IS" BASIS,
|
| 12 |
+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
| 13 |
+
// See the License for the specific language governing permissions and
|
| 14 |
+
// limitations under the License.
|
| 15 |
+
|
| 16 |
+
#ifndef ABSL_FLAGS_INTERNAL_FLAG_H_
|
| 17 |
+
#define ABSL_FLAGS_INTERNAL_FLAG_H_
|
| 18 |
+
|
| 19 |
+
#include <stddef.h>
|
| 20 |
+
#include <stdint.h>
|
| 21 |
+
|
| 22 |
+
#include <atomic>
|
| 23 |
+
#include <cstring>
|
| 24 |
+
#include <memory>
|
| 25 |
+
#include <new>
|
| 26 |
+
#include <string>
|
| 27 |
+
#include <type_traits>
|
| 28 |
+
#include <typeinfo>
|
| 29 |
+
|
| 30 |
+
#include "absl/base/attributes.h"
|
| 31 |
+
#include "absl/base/call_once.h"
|
| 32 |
+
#include "absl/base/casts.h"
|
| 33 |
+
#include "absl/base/config.h"
|
| 34 |
+
#include "absl/base/optimization.h"
|
| 35 |
+
#include "absl/base/thread_annotations.h"
|
| 36 |
+
#include "absl/flags/commandlineflag.h"
|
| 37 |
+
#include "absl/flags/config.h"
|
| 38 |
+
#include "absl/flags/internal/commandlineflag.h"
|
| 39 |
+
#include "absl/flags/internal/registry.h"
|
| 40 |
+
#include "absl/flags/internal/sequence_lock.h"
|
| 41 |
+
#include "absl/flags/marshalling.h"
|
| 42 |
+
#include "absl/meta/type_traits.h"
|
| 43 |
+
#include "absl/strings/string_view.h"
|
| 44 |
+
#include "absl/synchronization/mutex.h"
|
| 45 |
+
#include "absl/utility/utility.h"
|
| 46 |
+
|
| 47 |
+
namespace absl {
|
| 48 |
+
ABSL_NAMESPACE_BEGIN
|
| 49 |
+
|
| 50 |
+
///////////////////////////////////////////////////////////////////////////////
|
| 51 |
+
// Forward declaration of absl::Flag<T> public API.
|
| 52 |
+
namespace flags_internal {
|
| 53 |
+
template <typename T>
|
| 54 |
+
class Flag;
|
| 55 |
+
} // namespace flags_internal
|
| 56 |
+
|
| 57 |
+
template <typename T>
|
| 58 |
+
using Flag = flags_internal::Flag<T>;
|
| 59 |
+
|
| 60 |
+
template <typename T>
|
| 61 |
+
ABSL_MUST_USE_RESULT T GetFlag(const absl::Flag<T>& flag);
|
| 62 |
+
|
| 63 |
+
template <typename T>
|
| 64 |
+
void SetFlag(absl::Flag<T>* flag, const T& v);
|
| 65 |
+
|
| 66 |
+
template <typename T, typename V>
|
| 67 |
+
void SetFlag(absl::Flag<T>* flag, const V& v);
|
| 68 |
+
|
| 69 |
+
template <typename U>
|
| 70 |
+
const CommandLineFlag& GetFlagReflectionHandle(const absl::Flag<U>& f);
|
| 71 |
+
|
| 72 |
+
///////////////////////////////////////////////////////////////////////////////
|
| 73 |
+
// Flag value type operations, eg., parsing, copying, etc. are provided
|
| 74 |
+
// by function specific to that type with a signature matching FlagOpFn.
|
| 75 |
+
|
| 76 |
+
namespace flags_internal {
|
| 77 |
+
|
| 78 |
+
enum class FlagOp {
|
| 79 |
+
kAlloc,
|
| 80 |
+
kDelete,
|
| 81 |
+
kCopy,
|
| 82 |
+
kCopyConstruct,
|
| 83 |
+
kSizeof,
|
| 84 |
+
kFastTypeId,
|
| 85 |
+
kRuntimeTypeId,
|
| 86 |
+
kParse,
|
| 87 |
+
kUnparse,
|
| 88 |
+
kValueOffset,
|
| 89 |
+
};
|
| 90 |
+
using FlagOpFn = void* (*)(FlagOp, const void*, void*, void*);
|
| 91 |
+
|
| 92 |
+
// Forward declaration for Flag value specific operations.
|
| 93 |
+
template <typename T>
|
| 94 |
+
void* FlagOps(FlagOp op, const void* v1, void* v2, void* v3);
|
| 95 |
+
|
| 96 |
+
// Allocate aligned memory for a flag value.
|
| 97 |
+
inline void* Alloc(FlagOpFn op) {
|
| 98 |
+
return op(FlagOp::kAlloc, nullptr, nullptr, nullptr);
|
| 99 |
+
}
|
| 100 |
+
// Deletes memory interpreting obj as flag value type pointer.
|
| 101 |
+
inline void Delete(FlagOpFn op, void* obj) {
|
| 102 |
+
op(FlagOp::kDelete, nullptr, obj, nullptr);
|
| 103 |
+
}
|
| 104 |
+
// Copies src to dst interpreting as flag value type pointers.
|
| 105 |
+
inline void Copy(FlagOpFn op, const void* src, void* dst) {
|
| 106 |
+
op(FlagOp::kCopy, src, dst, nullptr);
|
| 107 |
+
}
|
| 108 |
+
// Construct a copy of flag value in a location pointed by dst
|
| 109 |
+
// based on src - pointer to the flag's value.
|
| 110 |
+
inline void CopyConstruct(FlagOpFn op, const void* src, void* dst) {
|
| 111 |
+
op(FlagOp::kCopyConstruct, src, dst, nullptr);
|
| 112 |
+
}
|
| 113 |
+
// Makes a copy of flag value pointed by obj.
|
| 114 |
+
inline void* Clone(FlagOpFn op, const void* obj) {
|
| 115 |
+
void* res = flags_internal::Alloc(op);
|
| 116 |
+
flags_internal::CopyConstruct(op, obj, res);
|
| 117 |
+
return res;
|
| 118 |
+
}
|
| 119 |
+
// Returns true if parsing of input text is successful.
|
| 120 |
+
inline bool Parse(FlagOpFn op, absl::string_view text, void* dst,
|
| 121 |
+
std::string* error) {
|
| 122 |
+
return op(FlagOp::kParse, &text, dst, error) != nullptr;
|
| 123 |
+
}
|
| 124 |
+
// Returns string representing supplied value.
|
| 125 |
+
inline std::string Unparse(FlagOpFn op, const void* val) {
|
| 126 |
+
std::string result;
|
| 127 |
+
op(FlagOp::kUnparse, val, &result, nullptr);
|
| 128 |
+
return result;
|
| 129 |
+
}
|
| 130 |
+
// Returns size of flag value type.
|
| 131 |
+
inline size_t Sizeof(FlagOpFn op) {
|
| 132 |
+
// This sequence of casts reverses the sequence from
|
| 133 |
+
// `flags_internal::FlagOps()`
|
| 134 |
+
return static_cast<size_t>(reinterpret_cast<intptr_t>(
|
| 135 |
+
op(FlagOp::kSizeof, nullptr, nullptr, nullptr)));
|
| 136 |
+
}
|
| 137 |
+
// Returns fast type id corresponding to the value type.
|
| 138 |
+
inline FlagFastTypeId FastTypeId(FlagOpFn op) {
|
| 139 |
+
return reinterpret_cast<FlagFastTypeId>(
|
| 140 |
+
op(FlagOp::kFastTypeId, nullptr, nullptr, nullptr));
|
| 141 |
+
}
|
| 142 |
+
// Returns fast type id corresponding to the value type.
|
| 143 |
+
inline const std::type_info* RuntimeTypeId(FlagOpFn op) {
|
| 144 |
+
return reinterpret_cast<const std::type_info*>(
|
| 145 |
+
op(FlagOp::kRuntimeTypeId, nullptr, nullptr, nullptr));
|
| 146 |
+
}
|
| 147 |
+
// Returns offset of the field value_ from the field impl_ inside of
|
| 148 |
+
// absl::Flag<T> data. Given FlagImpl pointer p you can get the
|
| 149 |
+
// location of the corresponding value as:
|
| 150 |
+
// reinterpret_cast<char*>(p) + ValueOffset().
|
| 151 |
+
inline ptrdiff_t ValueOffset(FlagOpFn op) {
|
| 152 |
+
// This sequence of casts reverses the sequence from
|
| 153 |
+
// `flags_internal::FlagOps()`
|
| 154 |
+
return static_cast<ptrdiff_t>(reinterpret_cast<intptr_t>(
|
| 155 |
+
op(FlagOp::kValueOffset, nullptr, nullptr, nullptr)));
|
| 156 |
+
}
|
| 157 |
+
|
| 158 |
+
// Returns an address of RTTI's typeid(T).
|
| 159 |
+
template <typename T>
|
| 160 |
+
inline const std::type_info* GenRuntimeTypeId() {
|
| 161 |
+
#ifdef ABSL_INTERNAL_HAS_RTTI
|
| 162 |
+
return &typeid(T);
|
| 163 |
+
#else
|
| 164 |
+
return nullptr;
|
| 165 |
+
#endif
|
| 166 |
+
}
|
| 167 |
+
|
| 168 |
+
///////////////////////////////////////////////////////////////////////////////
|
| 169 |
+
// Flag help auxiliary structs.
|
| 170 |
+
|
| 171 |
+
// This is help argument for absl::Flag encapsulating the string literal pointer
|
| 172 |
+
// or pointer to function generating it as well as enum descriminating two
|
| 173 |
+
// cases.
|
| 174 |
+
using HelpGenFunc = std::string (*)();
|
| 175 |
+
|
| 176 |
+
template <size_t N>
|
| 177 |
+
struct FixedCharArray {
|
| 178 |
+
char value[N];
|
| 179 |
+
|
| 180 |
+
template <size_t... I>
|
| 181 |
+
static constexpr FixedCharArray<N> FromLiteralString(
|
| 182 |
+
absl::string_view str, absl::index_sequence<I...>) {
|
| 183 |
+
return (void)str, FixedCharArray<N>({{str[I]..., '\0'}});
|
| 184 |
+
}
|
| 185 |
+
};
|
| 186 |
+
|
| 187 |
+
template <typename Gen, size_t N = Gen::Value().size()>
|
| 188 |
+
constexpr FixedCharArray<N + 1> HelpStringAsArray(int) {
|
| 189 |
+
return FixedCharArray<N + 1>::FromLiteralString(
|
| 190 |
+
Gen::Value(), absl::make_index_sequence<N>{});
|
| 191 |
+
}
|
| 192 |
+
|
| 193 |
+
template <typename Gen>
|
| 194 |
+
constexpr std::false_type HelpStringAsArray(char) {
|
| 195 |
+
return std::false_type{};
|
| 196 |
+
}
|
| 197 |
+
|
| 198 |
+
union FlagHelpMsg {
|
| 199 |
+
constexpr explicit FlagHelpMsg(const char* help_msg) : literal(help_msg) {}
|
| 200 |
+
constexpr explicit FlagHelpMsg(HelpGenFunc help_gen) : gen_func(help_gen) {}
|
| 201 |
+
|
| 202 |
+
const char* literal;
|
| 203 |
+
HelpGenFunc gen_func;
|
| 204 |
+
};
|
| 205 |
+
|
| 206 |
+
enum class FlagHelpKind : uint8_t { kLiteral = 0, kGenFunc = 1 };
|
| 207 |
+
|
| 208 |
+
struct FlagHelpArg {
|
| 209 |
+
FlagHelpMsg source;
|
| 210 |
+
FlagHelpKind kind;
|
| 211 |
+
};
|
| 212 |
+
|
| 213 |
+
extern const char kStrippedFlagHelp[];
|
| 214 |
+
|
| 215 |
+
// These two HelpArg overloads allows us to select at compile time one of two
|
| 216 |
+
// way to pass Help argument to absl::Flag. We'll be passing
|
| 217 |
+
// AbslFlagHelpGenFor##name as Gen and integer 0 as a single argument to prefer
|
| 218 |
+
// first overload if possible. If help message is evaluatable on constexpr
|
| 219 |
+
// context We'll be able to make FixedCharArray out of it and we'll choose first
|
| 220 |
+
// overload. In this case the help message expression is immediately evaluated
|
| 221 |
+
// and is used to construct the absl::Flag. No additional code is generated by
|
| 222 |
+
// ABSL_FLAG Otherwise SFINAE kicks in and first overload is dropped from the
|
| 223 |
+
// consideration, in which case the second overload will be used. The second
|
| 224 |
+
// overload does not attempt to evaluate the help message expression
|
| 225 |
+
// immediately and instead delays the evaluation by returning the function
|
| 226 |
+
// pointer (&T::NonConst) generating the help message when necessary. This is
|
| 227 |
+
// evaluatable in constexpr context, but the cost is an extra function being
|
| 228 |
+
// generated in the ABSL_FLAG code.
|
| 229 |
+
template <typename Gen, size_t N>
|
| 230 |
+
constexpr FlagHelpArg HelpArg(const FixedCharArray<N>& value) {
|
| 231 |
+
return {FlagHelpMsg(value.value), FlagHelpKind::kLiteral};
|
| 232 |
+
}
|
| 233 |
+
|
| 234 |
+
template <typename Gen>
|
| 235 |
+
constexpr FlagHelpArg HelpArg(std::false_type) {
|
| 236 |
+
return {FlagHelpMsg(&Gen::NonConst), FlagHelpKind::kGenFunc};
|
| 237 |
+
}
|
| 238 |
+
|
| 239 |
+
///////////////////////////////////////////////////////////////////////////////
|
| 240 |
+
// Flag default value auxiliary structs.
|
| 241 |
+
|
| 242 |
+
// Signature for the function generating the initial flag value (usually
|
| 243 |
+
// based on default value supplied in flag's definition)
|
| 244 |
+
using FlagDfltGenFunc = void (*)(void*);
|
| 245 |
+
|
| 246 |
+
union FlagDefaultSrc {
|
| 247 |
+
constexpr explicit FlagDefaultSrc(FlagDfltGenFunc gen_func_arg)
|
| 248 |
+
: gen_func(gen_func_arg) {}
|
| 249 |
+
|
| 250 |
+
#define ABSL_FLAGS_INTERNAL_DFLT_FOR_TYPE(T, name) \
|
| 251 |
+
T name##_value; \
|
| 252 |
+
constexpr explicit FlagDefaultSrc(T value) : name##_value(value) {} // NOLINT
|
| 253 |
+
ABSL_FLAGS_INTERNAL_BUILTIN_TYPES(ABSL_FLAGS_INTERNAL_DFLT_FOR_TYPE)
|
| 254 |
+
#undef ABSL_FLAGS_INTERNAL_DFLT_FOR_TYPE
|
| 255 |
+
|
| 256 |
+
void* dynamic_value;
|
| 257 |
+
FlagDfltGenFunc gen_func;
|
| 258 |
+
};
|
| 259 |
+
|
| 260 |
+
enum class FlagDefaultKind : uint8_t {
|
| 261 |
+
kDynamicValue = 0,
|
| 262 |
+
kGenFunc = 1,
|
| 263 |
+
kOneWord = 2 // for default values UP to one word in size
|
| 264 |
+
};
|
| 265 |
+
|
| 266 |
+
struct FlagDefaultArg {
|
| 267 |
+
FlagDefaultSrc source;
|
| 268 |
+
FlagDefaultKind kind;
|
| 269 |
+
};
|
| 270 |
+
|
| 271 |
+
// This struct and corresponding overload to InitDefaultValue are used to
|
| 272 |
+
// facilitate usage of {} as default value in ABSL_FLAG macro.
|
| 273 |
+
// TODO(rogeeff): Fix handling types with explicit constructors.
|
| 274 |
+
struct EmptyBraces {};
|
| 275 |
+
|
| 276 |
+
template <typename T>
|
| 277 |
+
constexpr T InitDefaultValue(T t) {
|
| 278 |
+
return t;
|
| 279 |
+
}
|
| 280 |
+
|
| 281 |
+
template <typename T>
|
| 282 |
+
constexpr T InitDefaultValue(EmptyBraces) {
|
| 283 |
+
return T{};
|
| 284 |
+
}
|
| 285 |
+
|
| 286 |
+
template <typename ValueT, typename GenT,
|
| 287 |
+
typename std::enable_if<std::is_integral<ValueT>::value, int>::type =
|
| 288 |
+
((void)GenT{}, 0)>
|
| 289 |
+
constexpr FlagDefaultArg DefaultArg(int) {
|
| 290 |
+
return {FlagDefaultSrc(GenT{}.value), FlagDefaultKind::kOneWord};
|
| 291 |
+
}
|
| 292 |
+
|
| 293 |
+
template <typename ValueT, typename GenT>
|
| 294 |
+
constexpr FlagDefaultArg DefaultArg(char) {
|
| 295 |
+
return {FlagDefaultSrc(&GenT::Gen), FlagDefaultKind::kGenFunc};
|
| 296 |
+
}
|
| 297 |
+
|
| 298 |
+
///////////////////////////////////////////////////////////////////////////////
|
| 299 |
+
// Flag current value auxiliary structs.
|
| 300 |
+
|
| 301 |
+
constexpr int64_t UninitializedFlagValue() {
|
| 302 |
+
return static_cast<int64_t>(0xababababababababll);
|
| 303 |
+
}
|
| 304 |
+
|
| 305 |
+
template <typename T>
|
| 306 |
+
using FlagUseValueAndInitBitStorage =
|
| 307 |
+
std::integral_constant<bool, std::is_trivially_copyable<T>::value &&
|
| 308 |
+
std::is_default_constructible<T>::value &&
|
| 309 |
+
(sizeof(T) < 8)>;
|
| 310 |
+
|
| 311 |
+
template <typename T>
|
| 312 |
+
using FlagUseOneWordStorage =
|
| 313 |
+
std::integral_constant<bool, std::is_trivially_copyable<T>::value &&
|
| 314 |
+
(sizeof(T) <= 8)>;
|
| 315 |
+
|
| 316 |
+
template <class T>
|
| 317 |
+
using FlagUseSequenceLockStorage =
|
| 318 |
+
std::integral_constant<bool, std::is_trivially_copyable<T>::value &&
|
| 319 |
+
(sizeof(T) > 8)>;
|
| 320 |
+
|
| 321 |
+
enum class FlagValueStorageKind : uint8_t {
|
| 322 |
+
kValueAndInitBit = 0,
|
| 323 |
+
kOneWordAtomic = 1,
|
| 324 |
+
kSequenceLocked = 2,
|
| 325 |
+
kAlignedBuffer = 3,
|
| 326 |
+
};
|
| 327 |
+
|
| 328 |
+
template <typename T>
|
| 329 |
+
static constexpr FlagValueStorageKind StorageKind() {
|
| 330 |
+
return FlagUseValueAndInitBitStorage<T>::value
|
| 331 |
+
? FlagValueStorageKind::kValueAndInitBit
|
| 332 |
+
: FlagUseOneWordStorage<T>::value
|
| 333 |
+
? FlagValueStorageKind::kOneWordAtomic
|
| 334 |
+
: FlagUseSequenceLockStorage<T>::value
|
| 335 |
+
? FlagValueStorageKind::kSequenceLocked
|
| 336 |
+
: FlagValueStorageKind::kAlignedBuffer;
|
| 337 |
+
}
|
| 338 |
+
|
| 339 |
+
struct FlagOneWordValue {
|
| 340 |
+
constexpr explicit FlagOneWordValue(int64_t v) : value(v) {}
|
| 341 |
+
std::atomic<int64_t> value;
|
| 342 |
+
};
|
| 343 |
+
|
| 344 |
+
template <typename T>
|
| 345 |
+
struct alignas(8) FlagValueAndInitBit {
|
| 346 |
+
T value;
|
| 347 |
+
// Use an int instead of a bool to guarantee that a non-zero value has
|
| 348 |
+
// a bit set.
|
| 349 |
+
uint8_t init;
|
| 350 |
+
};
|
| 351 |
+
|
| 352 |
+
template <typename T,
|
| 353 |
+
FlagValueStorageKind Kind = flags_internal::StorageKind<T>()>
|
| 354 |
+
struct FlagValue;
|
| 355 |
+
|
| 356 |
+
template <typename T>
|
| 357 |
+
struct FlagValue<T, FlagValueStorageKind::kValueAndInitBit> : FlagOneWordValue {
|
| 358 |
+
constexpr FlagValue() : FlagOneWordValue(0) {}
|
| 359 |
+
bool Get(const SequenceLock&, T& dst) const {
|
| 360 |
+
int64_t storage = value.load(std::memory_order_acquire);
|
| 361 |
+
if (ABSL_PREDICT_FALSE(storage == 0)) {
|
| 362 |
+
return false;
|
| 363 |
+
}
|
| 364 |
+
dst = absl::bit_cast<FlagValueAndInitBit<T>>(storage).value;
|
| 365 |
+
return true;
|
| 366 |
+
}
|
| 367 |
+
};
|
| 368 |
+
|
| 369 |
+
template <typename T>
|
| 370 |
+
struct FlagValue<T, FlagValueStorageKind::kOneWordAtomic> : FlagOneWordValue {
|
| 371 |
+
constexpr FlagValue() : FlagOneWordValue(UninitializedFlagValue()) {}
|
| 372 |
+
bool Get(const SequenceLock&, T& dst) const {
|
| 373 |
+
int64_t one_word_val = value.load(std::memory_order_acquire);
|
| 374 |
+
if (ABSL_PREDICT_FALSE(one_word_val == UninitializedFlagValue())) {
|
| 375 |
+
return false;
|
| 376 |
+
}
|
| 377 |
+
std::memcpy(&dst, static_cast<const void*>(&one_word_val), sizeof(T));
|
| 378 |
+
return true;
|
| 379 |
+
}
|
| 380 |
+
};
|
| 381 |
+
|
| 382 |
+
template <typename T>
|
| 383 |
+
struct FlagValue<T, FlagValueStorageKind::kSequenceLocked> {
|
| 384 |
+
bool Get(const SequenceLock& lock, T& dst) const {
|
| 385 |
+
return lock.TryRead(&dst, value_words, sizeof(T));
|
| 386 |
+
}
|
| 387 |
+
|
| 388 |
+
static constexpr int kNumWords =
|
| 389 |
+
flags_internal::AlignUp(sizeof(T), sizeof(uint64_t)) / sizeof(uint64_t);
|
| 390 |
+
|
| 391 |
+
alignas(T) alignas(
|
| 392 |
+
std::atomic<uint64_t>) std::atomic<uint64_t> value_words[kNumWords];
|
| 393 |
+
};
|
| 394 |
+
|
| 395 |
+
template <typename T>
|
| 396 |
+
struct FlagValue<T, FlagValueStorageKind::kAlignedBuffer> {
|
| 397 |
+
bool Get(const SequenceLock&, T&) const { return false; }
|
| 398 |
+
|
| 399 |
+
alignas(T) char value[sizeof(T)];
|
| 400 |
+
};
|
| 401 |
+
|
| 402 |
+
///////////////////////////////////////////////////////////////////////////////
|
| 403 |
+
// Flag callback auxiliary structs.
|
| 404 |
+
|
| 405 |
+
// Signature for the mutation callback used by watched Flags
|
| 406 |
+
// The callback is noexcept.
|
| 407 |
+
// TODO(rogeeff): add noexcept after C++17 support is added.
|
| 408 |
+
using FlagCallbackFunc = void (*)();
|
| 409 |
+
|
| 410 |
+
struct FlagCallback {
|
| 411 |
+
FlagCallbackFunc func;
|
| 412 |
+
absl::Mutex guard; // Guard for concurrent callback invocations.
|
| 413 |
+
};
|
| 414 |
+
|
| 415 |
+
///////////////////////////////////////////////////////////////////////////////
|
| 416 |
+
// Flag implementation, which does not depend on flag value type.
|
| 417 |
+
// The class encapsulates the Flag's data and access to it.
|
| 418 |
+
|
| 419 |
+
struct DynValueDeleter {
|
| 420 |
+
explicit DynValueDeleter(FlagOpFn op_arg = nullptr);
|
| 421 |
+
void operator()(void* ptr) const;
|
| 422 |
+
|
| 423 |
+
FlagOpFn op;
|
| 424 |
+
};
|
| 425 |
+
|
| 426 |
+
class FlagState;
|
| 427 |
+
|
| 428 |
+
class FlagImpl final : public CommandLineFlag {
|
| 429 |
+
public:
|
| 430 |
+
constexpr FlagImpl(const char* name, const char* filename, FlagOpFn op,
|
| 431 |
+
FlagHelpArg help, FlagValueStorageKind value_kind,
|
| 432 |
+
FlagDefaultArg default_arg)
|
| 433 |
+
: name_(name),
|
| 434 |
+
filename_(filename),
|
| 435 |
+
op_(op),
|
| 436 |
+
help_(help.source),
|
| 437 |
+
help_source_kind_(static_cast<uint8_t>(help.kind)),
|
| 438 |
+
value_storage_kind_(static_cast<uint8_t>(value_kind)),
|
| 439 |
+
def_kind_(static_cast<uint8_t>(default_arg.kind)),
|
| 440 |
+
modified_(false),
|
| 441 |
+
on_command_line_(false),
|
| 442 |
+
callback_(nullptr),
|
| 443 |
+
default_value_(default_arg.source),
|
| 444 |
+
data_guard_{} {}
|
| 445 |
+
|
| 446 |
+
// Constant access methods
|
| 447 |
+
int64_t ReadOneWord() const ABSL_LOCKS_EXCLUDED(*DataGuard());
|
| 448 |
+
bool ReadOneBool() const ABSL_LOCKS_EXCLUDED(*DataGuard());
|
| 449 |
+
void Read(void* dst) const override ABSL_LOCKS_EXCLUDED(*DataGuard());
|
| 450 |
+
void Read(bool* value) const ABSL_LOCKS_EXCLUDED(*DataGuard()) {
|
| 451 |
+
*value = ReadOneBool();
|
| 452 |
+
}
|
| 453 |
+
template <typename T,
|
| 454 |
+
absl::enable_if_t<flags_internal::StorageKind<T>() ==
|
| 455 |
+
FlagValueStorageKind::kOneWordAtomic,
|
| 456 |
+
int> = 0>
|
| 457 |
+
void Read(T* value) const ABSL_LOCKS_EXCLUDED(*DataGuard()) {
|
| 458 |
+
int64_t v = ReadOneWord();
|
| 459 |
+
std::memcpy(value, static_cast<const void*>(&v), sizeof(T));
|
| 460 |
+
}
|
| 461 |
+
template <typename T,
|
| 462 |
+
typename std::enable_if<flags_internal::StorageKind<T>() ==
|
| 463 |
+
FlagValueStorageKind::kValueAndInitBit,
|
| 464 |
+
int>::type = 0>
|
| 465 |
+
void Read(T* value) const ABSL_LOCKS_EXCLUDED(*DataGuard()) {
|
| 466 |
+
*value = absl::bit_cast<FlagValueAndInitBit<T>>(ReadOneWord()).value;
|
| 467 |
+
}
|
| 468 |
+
|
| 469 |
+
// Mutating access methods
|
| 470 |
+
void Write(const void* src) ABSL_LOCKS_EXCLUDED(*DataGuard());
|
| 471 |
+
|
| 472 |
+
// Interfaces to operate on callbacks.
|
| 473 |
+
void SetCallback(const FlagCallbackFunc mutation_callback)
|
| 474 |
+
ABSL_LOCKS_EXCLUDED(*DataGuard());
|
| 475 |
+
void InvokeCallback() const ABSL_EXCLUSIVE_LOCKS_REQUIRED(*DataGuard());
|
| 476 |
+
|
| 477 |
+
// Used in read/write operations to validate source/target has correct type.
|
| 478 |
+
// For example if flag is declared as absl::Flag<int> FLAGS_foo, a call to
|
| 479 |
+
// absl::GetFlag(FLAGS_foo) validates that the type of FLAGS_foo is indeed
|
| 480 |
+
// int. To do that we pass the "assumed" type id (which is deduced from type
|
| 481 |
+
// int) as an argument `type_id`, which is in turn is validated against the
|
| 482 |
+
// type id stored in flag object by flag definition statement.
|
| 483 |
+
void AssertValidType(FlagFastTypeId type_id,
|
| 484 |
+
const std::type_info* (*gen_rtti)()) const;
|
| 485 |
+
|
| 486 |
+
private:
|
| 487 |
+
template <typename T>
|
| 488 |
+
friend class Flag;
|
| 489 |
+
friend class FlagState;
|
| 490 |
+
|
| 491 |
+
// Ensures that `data_guard_` is initialized and returns it.
|
| 492 |
+
absl::Mutex* DataGuard() const
|
| 493 |
+
ABSL_LOCK_RETURNED(reinterpret_cast<absl::Mutex*>(data_guard_));
|
| 494 |
+
// Returns heap allocated value of type T initialized with default value.
|
| 495 |
+
std::unique_ptr<void, DynValueDeleter> MakeInitValue() const
|
| 496 |
+
ABSL_EXCLUSIVE_LOCKS_REQUIRED(*DataGuard());
|
| 497 |
+
// Flag initialization called via absl::call_once.
|
| 498 |
+
void Init();
|
| 499 |
+
|
| 500 |
+
// Offset value access methods. One per storage kind. These methods to not
|
| 501 |
+
// respect const correctness, so be very carefull using them.
|
| 502 |
+
|
| 503 |
+
// This is a shared helper routine which encapsulates most of the magic. Since
|
| 504 |
+
// it is only used inside the three routines below, which are defined in
|
| 505 |
+
// flag.cc, we can define it in that file as well.
|
| 506 |
+
template <typename StorageT>
|
| 507 |
+
StorageT* OffsetValue() const;
|
| 508 |
+
// This is an accessor for a value stored in an aligned buffer storage
|
| 509 |
+
// used for non-trivially-copyable data types.
|
| 510 |
+
// Returns a mutable pointer to the start of a buffer.
|
| 511 |
+
void* AlignedBufferValue() const;
|
| 512 |
+
|
| 513 |
+
// The same as above, but used for sequencelock-protected storage.
|
| 514 |
+
std::atomic<uint64_t>* AtomicBufferValue() const;
|
| 515 |
+
|
| 516 |
+
// This is an accessor for a value stored as one word atomic. Returns a
|
| 517 |
+
// mutable reference to an atomic value.
|
| 518 |
+
std::atomic<int64_t>& OneWordValue() const;
|
| 519 |
+
|
| 520 |
+
// Attempts to parse supplied `value` string. If parsing is successful,
|
| 521 |
+
// returns new value. Otherwise returns nullptr.
|
| 522 |
+
std::unique_ptr<void, DynValueDeleter> TryParse(absl::string_view value,
|
| 523 |
+
std::string& err) const
|
| 524 |
+
ABSL_EXCLUSIVE_LOCKS_REQUIRED(*DataGuard());
|
| 525 |
+
// Stores the flag value based on the pointer to the source.
|
| 526 |
+
void StoreValue(const void* src) ABSL_EXCLUSIVE_LOCKS_REQUIRED(*DataGuard());
|
| 527 |
+
|
| 528 |
+
// Copy the flag data, protected by `seq_lock_` into `dst`.
|
| 529 |
+
//
|
| 530 |
+
// REQUIRES: ValueStorageKind() == kSequenceLocked.
|
| 531 |
+
void ReadSequenceLockedData(void* dst) const
|
| 532 |
+
ABSL_LOCKS_EXCLUDED(*DataGuard());
|
| 533 |
+
|
| 534 |
+
FlagHelpKind HelpSourceKind() const {
|
| 535 |
+
return static_cast<FlagHelpKind>(help_source_kind_);
|
| 536 |
+
}
|
| 537 |
+
FlagValueStorageKind ValueStorageKind() const {
|
| 538 |
+
return static_cast<FlagValueStorageKind>(value_storage_kind_);
|
| 539 |
+
}
|
| 540 |
+
FlagDefaultKind DefaultKind() const
|
| 541 |
+
ABSL_EXCLUSIVE_LOCKS_REQUIRED(*DataGuard()) {
|
| 542 |
+
return static_cast<FlagDefaultKind>(def_kind_);
|
| 543 |
+
}
|
| 544 |
+
|
| 545 |
+
// CommandLineFlag interface implementation
|
| 546 |
+
absl::string_view Name() const override;
|
| 547 |
+
std::string Filename() const override;
|
| 548 |
+
std::string Help() const override;
|
| 549 |
+
FlagFastTypeId TypeId() const override;
|
| 550 |
+
bool IsSpecifiedOnCommandLine() const override
|
| 551 |
+
ABSL_LOCKS_EXCLUDED(*DataGuard());
|
| 552 |
+
std::string DefaultValue() const override ABSL_LOCKS_EXCLUDED(*DataGuard());
|
| 553 |
+
std::string CurrentValue() const override ABSL_LOCKS_EXCLUDED(*DataGuard());
|
| 554 |
+
bool ValidateInputValue(absl::string_view value) const override
|
| 555 |
+
ABSL_LOCKS_EXCLUDED(*DataGuard());
|
| 556 |
+
void CheckDefaultValueParsingRoundtrip() const override
|
| 557 |
+
ABSL_LOCKS_EXCLUDED(*DataGuard());
|
| 558 |
+
|
| 559 |
+
int64_t ModificationCount() const ABSL_EXCLUSIVE_LOCKS_REQUIRED(*DataGuard());
|
| 560 |
+
|
| 561 |
+
// Interfaces to save and restore flags to/from persistent state.
|
| 562 |
+
// Returns current flag state or nullptr if flag does not support
|
| 563 |
+
// saving and restoring a state.
|
| 564 |
+
std::unique_ptr<FlagStateInterface> SaveState() override
|
| 565 |
+
ABSL_LOCKS_EXCLUDED(*DataGuard());
|
| 566 |
+
|
| 567 |
+
// Restores the flag state to the supplied state object. If there is
|
| 568 |
+
// nothing to restore returns false. Otherwise returns true.
|
| 569 |
+
bool RestoreState(const FlagState& flag_state)
|
| 570 |
+
ABSL_LOCKS_EXCLUDED(*DataGuard());
|
| 571 |
+
|
| 572 |
+
bool ParseFrom(absl::string_view value, FlagSettingMode set_mode,
|
| 573 |
+
ValueSource source, std::string& error) override
|
| 574 |
+
ABSL_LOCKS_EXCLUDED(*DataGuard());
|
| 575 |
+
|
| 576 |
+
// Immutable flag's state.
|
| 577 |
+
|
| 578 |
+
// Flags name passed to ABSL_FLAG as second arg.
|
| 579 |
+
const char* const name_;
|
| 580 |
+
// The file name where ABSL_FLAG resides.
|
| 581 |
+
const char* const filename_;
|
| 582 |
+
// Type-specific operations "vtable".
|
| 583 |
+
const FlagOpFn op_;
|
| 584 |
+
// Help message literal or function to generate it.
|
| 585 |
+
const FlagHelpMsg help_;
|
| 586 |
+
// Indicates if help message was supplied as literal or generator func.
|
| 587 |
+
const uint8_t help_source_kind_ : 1;
|
| 588 |
+
// Kind of storage this flag is using for the flag's value.
|
| 589 |
+
const uint8_t value_storage_kind_ : 2;
|
| 590 |
+
|
| 591 |
+
uint8_t : 0; // The bytes containing the const bitfields must not be
|
| 592 |
+
// shared with bytes containing the mutable bitfields.
|
| 593 |
+
|
| 594 |
+
// Mutable flag's state (guarded by `data_guard_`).
|
| 595 |
+
|
| 596 |
+
// def_kind_ is not guard by DataGuard() since it is accessed in Init without
|
| 597 |
+
// locks.
|
| 598 |
+
uint8_t def_kind_ : 2;
|
| 599 |
+
// Has this flag's value been modified?
|
| 600 |
+
bool modified_ : 1 ABSL_GUARDED_BY(*DataGuard());
|
| 601 |
+
// Has this flag been specified on command line.
|
| 602 |
+
bool on_command_line_ : 1 ABSL_GUARDED_BY(*DataGuard());
|
| 603 |
+
|
| 604 |
+
// Unique tag for absl::call_once call to initialize this flag.
|
| 605 |
+
absl::once_flag init_control_;
|
| 606 |
+
|
| 607 |
+
// Sequence lock / mutation counter.
|
| 608 |
+
flags_internal::SequenceLock seq_lock_;
|
| 609 |
+
|
| 610 |
+
// Optional flag's callback and absl::Mutex to guard the invocations.
|
| 611 |
+
FlagCallback* callback_ ABSL_GUARDED_BY(*DataGuard());
|
| 612 |
+
// Either a pointer to the function generating the default value based on the
|
| 613 |
+
// value specified in ABSL_FLAG or pointer to the dynamically set default
|
| 614 |
+
// value via SetCommandLineOptionWithMode. def_kind_ is used to distinguish
|
| 615 |
+
// these two cases.
|
| 616 |
+
FlagDefaultSrc default_value_;
|
| 617 |
+
|
| 618 |
+
// This is reserved space for an absl::Mutex to guard flag data. It will be
|
| 619 |
+
// initialized in FlagImpl::Init via placement new.
|
| 620 |
+
// We can't use "absl::Mutex data_guard_", since this class is not literal.
|
| 621 |
+
// We do not want to use "absl::Mutex* data_guard_", since this would require
|
| 622 |
+
// heap allocation during initialization, which is both slows program startup
|
| 623 |
+
// and can fail. Using reserved space + placement new allows us to avoid both
|
| 624 |
+
// problems.
|
| 625 |
+
alignas(absl::Mutex) mutable char data_guard_[sizeof(absl::Mutex)];
|
| 626 |
+
};
|
| 627 |
+
|
| 628 |
+
///////////////////////////////////////////////////////////////////////////////
|
| 629 |
+
// The Flag object parameterized by the flag's value type. This class implements
|
| 630 |
+
// flag reflection handle interface.
|
| 631 |
+
|
| 632 |
+
template <typename T>
|
| 633 |
+
class Flag {
|
| 634 |
+
public:
|
| 635 |
+
constexpr Flag(const char* name, const char* filename, FlagHelpArg help,
|
| 636 |
+
const FlagDefaultArg default_arg)
|
| 637 |
+
: impl_(name, filename, &FlagOps<T>, help,
|
| 638 |
+
flags_internal::StorageKind<T>(), default_arg),
|
| 639 |
+
value_() {}
|
| 640 |
+
|
| 641 |
+
// CommandLineFlag interface
|
| 642 |
+
absl::string_view Name() const { return impl_.Name(); }
|
| 643 |
+
std::string Filename() const { return impl_.Filename(); }
|
| 644 |
+
std::string Help() const { return impl_.Help(); }
|
| 645 |
+
// Do not use. To be removed.
|
| 646 |
+
bool IsSpecifiedOnCommandLine() const {
|
| 647 |
+
return impl_.IsSpecifiedOnCommandLine();
|
| 648 |
+
}
|
| 649 |
+
std::string DefaultValue() const { return impl_.DefaultValue(); }
|
| 650 |
+
std::string CurrentValue() const { return impl_.CurrentValue(); }
|
| 651 |
+
|
| 652 |
+
private:
|
| 653 |
+
template <typename, bool>
|
| 654 |
+
friend class FlagRegistrar;
|
| 655 |
+
friend class FlagImplPeer;
|
| 656 |
+
|
| 657 |
+
T Get() const {
|
| 658 |
+
// See implementation notes in CommandLineFlag::Get().
|
| 659 |
+
union U {
|
| 660 |
+
T value;
|
| 661 |
+
U() {}
|
| 662 |
+
~U() { value.~T(); }
|
| 663 |
+
};
|
| 664 |
+
U u;
|
| 665 |
+
|
| 666 |
+
#if !defined(NDEBUG)
|
| 667 |
+
impl_.AssertValidType(base_internal::FastTypeId<T>(), &GenRuntimeTypeId<T>);
|
| 668 |
+
#endif
|
| 669 |
+
|
| 670 |
+
if (ABSL_PREDICT_FALSE(!value_.Get(impl_.seq_lock_, u.value))) {
|
| 671 |
+
impl_.Read(&u.value);
|
| 672 |
+
}
|
| 673 |
+
return std::move(u.value);
|
| 674 |
+
}
|
| 675 |
+
void Set(const T& v) {
|
| 676 |
+
impl_.AssertValidType(base_internal::FastTypeId<T>(), &GenRuntimeTypeId<T>);
|
| 677 |
+
impl_.Write(&v);
|
| 678 |
+
}
|
| 679 |
+
|
| 680 |
+
// Access to the reflection.
|
| 681 |
+
const CommandLineFlag& Reflect() const { return impl_; }
|
| 682 |
+
|
| 683 |
+
// Flag's data
|
| 684 |
+
// The implementation depends on value_ field to be placed exactly after the
|
| 685 |
+
// impl_ field, so that impl_ can figure out the offset to the value and
|
| 686 |
+
// access it.
|
| 687 |
+
FlagImpl impl_;
|
| 688 |
+
FlagValue<T> value_;
|
| 689 |
+
};
|
| 690 |
+
|
| 691 |
+
///////////////////////////////////////////////////////////////////////////////
|
| 692 |
+
// Trampoline for friend access
|
| 693 |
+
|
| 694 |
+
class FlagImplPeer {
|
| 695 |
+
public:
|
| 696 |
+
template <typename T, typename FlagType>
|
| 697 |
+
static T InvokeGet(const FlagType& flag) {
|
| 698 |
+
return flag.Get();
|
| 699 |
+
}
|
| 700 |
+
template <typename FlagType, typename T>
|
| 701 |
+
static void InvokeSet(FlagType& flag, const T& v) {
|
| 702 |
+
flag.Set(v);
|
| 703 |
+
}
|
| 704 |
+
template <typename FlagType>
|
| 705 |
+
static const CommandLineFlag& InvokeReflect(const FlagType& f) {
|
| 706 |
+
return f.Reflect();
|
| 707 |
+
}
|
| 708 |
+
};
|
| 709 |
+
|
| 710 |
+
///////////////////////////////////////////////////////////////////////////////
|
| 711 |
+
// Implementation of Flag value specific operations routine.
|
| 712 |
+
template <typename T>
|
| 713 |
+
void* FlagOps(FlagOp op, const void* v1, void* v2, void* v3) {
|
| 714 |
+
switch (op) {
|
| 715 |
+
case FlagOp::kAlloc: {
|
| 716 |
+
std::allocator<T> alloc;
|
| 717 |
+
return std::allocator_traits<std::allocator<T>>::allocate(alloc, 1);
|
| 718 |
+
}
|
| 719 |
+
case FlagOp::kDelete: {
|
| 720 |
+
T* p = static_cast<T*>(v2);
|
| 721 |
+
p->~T();
|
| 722 |
+
std::allocator<T> alloc;
|
| 723 |
+
std::allocator_traits<std::allocator<T>>::deallocate(alloc, p, 1);
|
| 724 |
+
return nullptr;
|
| 725 |
+
}
|
| 726 |
+
case FlagOp::kCopy:
|
| 727 |
+
*static_cast<T*>(v2) = *static_cast<const T*>(v1);
|
| 728 |
+
return nullptr;
|
| 729 |
+
case FlagOp::kCopyConstruct:
|
| 730 |
+
new (v2) T(*static_cast<const T*>(v1));
|
| 731 |
+
return nullptr;
|
| 732 |
+
case FlagOp::kSizeof:
|
| 733 |
+
return reinterpret_cast<void*>(static_cast<uintptr_t>(sizeof(T)));
|
| 734 |
+
case FlagOp::kFastTypeId:
|
| 735 |
+
return const_cast<void*>(base_internal::FastTypeId<T>());
|
| 736 |
+
case FlagOp::kRuntimeTypeId:
|
| 737 |
+
return const_cast<std::type_info*>(GenRuntimeTypeId<T>());
|
| 738 |
+
case FlagOp::kParse: {
|
| 739 |
+
// Initialize the temporary instance of type T based on current value in
|
| 740 |
+
// destination (which is going to be flag's default value).
|
| 741 |
+
T temp(*static_cast<T*>(v2));
|
| 742 |
+
if (!absl::ParseFlag<T>(*static_cast<const absl::string_view*>(v1), &temp,
|
| 743 |
+
static_cast<std::string*>(v3))) {
|
| 744 |
+
return nullptr;
|
| 745 |
+
}
|
| 746 |
+
*static_cast<T*>(v2) = std::move(temp);
|
| 747 |
+
return v2;
|
| 748 |
+
}
|
| 749 |
+
case FlagOp::kUnparse:
|
| 750 |
+
*static_cast<std::string*>(v2) =
|
| 751 |
+
absl::UnparseFlag<T>(*static_cast<const T*>(v1));
|
| 752 |
+
return nullptr;
|
| 753 |
+
case FlagOp::kValueOffset: {
|
| 754 |
+
// Round sizeof(FlagImp) to a multiple of alignof(FlagValue<T>) to get the
|
| 755 |
+
// offset of the data.
|
| 756 |
+
size_t round_to = alignof(FlagValue<T>);
|
| 757 |
+
size_t offset =
|
| 758 |
+
(sizeof(FlagImpl) + round_to - 1) / round_to * round_to;
|
| 759 |
+
return reinterpret_cast<void*>(offset);
|
| 760 |
+
}
|
| 761 |
+
}
|
| 762 |
+
return nullptr;
|
| 763 |
+
}
|
| 764 |
+
|
| 765 |
+
///////////////////////////////////////////////////////////////////////////////
|
| 766 |
+
// This class facilitates Flag object registration and tail expression-based
|
| 767 |
+
// flag definition, for example:
|
| 768 |
+
// ABSL_FLAG(int, foo, 42, "Foo help").OnUpdate(NotifyFooWatcher);
|
| 769 |
+
struct FlagRegistrarEmpty {};
|
| 770 |
+
template <typename T, bool do_register>
|
| 771 |
+
class FlagRegistrar {
|
| 772 |
+
public:
|
| 773 |
+
explicit FlagRegistrar(Flag<T>& flag, const char* filename) : flag_(flag) {
|
| 774 |
+
if (do_register)
|
| 775 |
+
flags_internal::RegisterCommandLineFlag(flag_.impl_, filename);
|
| 776 |
+
}
|
| 777 |
+
|
| 778 |
+
FlagRegistrar OnUpdate(FlagCallbackFunc cb) && {
|
| 779 |
+
flag_.impl_.SetCallback(cb);
|
| 780 |
+
return *this;
|
| 781 |
+
}
|
| 782 |
+
|
| 783 |
+
// Make the registrar "die" gracefully as an empty struct on a line where
|
| 784 |
+
// registration happens. Registrar objects are intended to live only as
|
| 785 |
+
// temporary.
|
| 786 |
+
operator FlagRegistrarEmpty() const { return {}; } // NOLINT
|
| 787 |
+
|
| 788 |
+
private:
|
| 789 |
+
Flag<T>& flag_; // Flag being registered (not owned).
|
| 790 |
+
};
|
| 791 |
+
|
| 792 |
+
} // namespace flags_internal
|
| 793 |
+
ABSL_NAMESPACE_END
|
| 794 |
+
} // namespace absl
|
| 795 |
+
|
| 796 |
+
#endif // ABSL_FLAGS_INTERNAL_FLAG_H_
|
weight/_dep/abseil-cpp/absl/flags/marshalling.cc
ADDED
|
@@ -0,0 +1,291 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
//
|
| 2 |
+
// Copyright 2019 The Abseil Authors.
|
| 3 |
+
//
|
| 4 |
+
// Licensed under the Apache License, Version 2.0 (the "License");
|
| 5 |
+
// you may not use this file except in compliance with the License.
|
| 6 |
+
// You may obtain a copy of the License at
|
| 7 |
+
//
|
| 8 |
+
// https://www.apache.org/licenses/LICENSE-2.0
|
| 9 |
+
//
|
| 10 |
+
// Unless required by applicable law or agreed to in writing, software
|
| 11 |
+
// distributed under the License is distributed on an "AS IS" BASIS,
|
| 12 |
+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
| 13 |
+
// See the License for the specific language governing permissions and
|
| 14 |
+
// limitations under the License.
|
| 15 |
+
|
| 16 |
+
#include "absl/flags/marshalling.h"
|
| 17 |
+
|
| 18 |
+
#include <stddef.h>
|
| 19 |
+
|
| 20 |
+
#include <cmath>
|
| 21 |
+
#include <limits>
|
| 22 |
+
#include <sstream>
|
| 23 |
+
#include <string>
|
| 24 |
+
#include <type_traits>
|
| 25 |
+
#include <vector>
|
| 26 |
+
|
| 27 |
+
#include "absl/base/config.h"
|
| 28 |
+
#include "absl/base/log_severity.h"
|
| 29 |
+
#include "absl/base/macros.h"
|
| 30 |
+
#include "absl/numeric/int128.h"
|
| 31 |
+
#include "absl/strings/ascii.h"
|
| 32 |
+
#include "absl/strings/match.h"
|
| 33 |
+
#include "absl/strings/numbers.h"
|
| 34 |
+
#include "absl/strings/str_cat.h"
|
| 35 |
+
#include "absl/strings/str_format.h"
|
| 36 |
+
#include "absl/strings/str_join.h"
|
| 37 |
+
#include "absl/strings/str_split.h"
|
| 38 |
+
#include "absl/strings/string_view.h"
|
| 39 |
+
|
| 40 |
+
namespace absl {
|
| 41 |
+
ABSL_NAMESPACE_BEGIN
|
| 42 |
+
namespace flags_internal {
|
| 43 |
+
|
| 44 |
+
// --------------------------------------------------------------------
|
| 45 |
+
// AbslParseFlag specializations for boolean type.
|
| 46 |
+
|
| 47 |
+
bool AbslParseFlag(absl::string_view text, bool* dst, std::string*) {
|
| 48 |
+
const char* kTrue[] = {"1", "t", "true", "y", "yes"};
|
| 49 |
+
const char* kFalse[] = {"0", "f", "false", "n", "no"};
|
| 50 |
+
static_assert(sizeof(kTrue) == sizeof(kFalse), "true_false_equal");
|
| 51 |
+
|
| 52 |
+
text = absl::StripAsciiWhitespace(text);
|
| 53 |
+
|
| 54 |
+
for (size_t i = 0; i < ABSL_ARRAYSIZE(kTrue); ++i) {
|
| 55 |
+
if (absl::EqualsIgnoreCase(text, kTrue[i])) {
|
| 56 |
+
*dst = true;
|
| 57 |
+
return true;
|
| 58 |
+
} else if (absl::EqualsIgnoreCase(text, kFalse[i])) {
|
| 59 |
+
*dst = false;
|
| 60 |
+
return true;
|
| 61 |
+
}
|
| 62 |
+
}
|
| 63 |
+
return false; // didn't match a legal input
|
| 64 |
+
}
|
| 65 |
+
|
| 66 |
+
// --------------------------------------------------------------------
|
| 67 |
+
// AbslParseFlag for integral types.
|
| 68 |
+
|
| 69 |
+
// Return the base to use for parsing text as an integer. Leading 0x
|
| 70 |
+
// puts us in base 16. But leading 0 does not put us in base 8. It
|
| 71 |
+
// caused too many bugs when we had that behavior.
|
| 72 |
+
static int NumericBase(absl::string_view text) {
|
| 73 |
+
if (text.empty()) return 0;
|
| 74 |
+
size_t num_start = (text[0] == '-' || text[0] == '+') ? 1 : 0;
|
| 75 |
+
const bool hex = (text.size() >= num_start + 2 && text[num_start] == '0' &&
|
| 76 |
+
(text[num_start + 1] == 'x' || text[num_start + 1] == 'X'));
|
| 77 |
+
return hex ? 16 : 10;
|
| 78 |
+
}
|
| 79 |
+
|
| 80 |
+
template <typename IntType>
|
| 81 |
+
inline bool ParseFlagImpl(absl::string_view text, IntType& dst) {
|
| 82 |
+
text = absl::StripAsciiWhitespace(text);
|
| 83 |
+
|
| 84 |
+
return absl::numbers_internal::safe_strtoi_base(text, &dst,
|
| 85 |
+
NumericBase(text));
|
| 86 |
+
}
|
| 87 |
+
|
| 88 |
+
bool AbslParseFlag(absl::string_view text, short* dst, std::string*) {
|
| 89 |
+
int val;
|
| 90 |
+
if (!ParseFlagImpl(text, val)) return false;
|
| 91 |
+
if (static_cast<short>(val) != val) // worked, but number out of range
|
| 92 |
+
return false;
|
| 93 |
+
*dst = static_cast<short>(val);
|
| 94 |
+
return true;
|
| 95 |
+
}
|
| 96 |
+
|
| 97 |
+
bool AbslParseFlag(absl::string_view text, unsigned short* dst, std::string*) {
|
| 98 |
+
unsigned int val;
|
| 99 |
+
if (!ParseFlagImpl(text, val)) return false;
|
| 100 |
+
if (static_cast<unsigned short>(val) !=
|
| 101 |
+
val) // worked, but number out of range
|
| 102 |
+
return false;
|
| 103 |
+
*dst = static_cast<unsigned short>(val);
|
| 104 |
+
return true;
|
| 105 |
+
}
|
| 106 |
+
|
| 107 |
+
bool AbslParseFlag(absl::string_view text, int* dst, std::string*) {
|
| 108 |
+
return ParseFlagImpl(text, *dst);
|
| 109 |
+
}
|
| 110 |
+
|
| 111 |
+
bool AbslParseFlag(absl::string_view text, unsigned int* dst, std::string*) {
|
| 112 |
+
return ParseFlagImpl(text, *dst);
|
| 113 |
+
}
|
| 114 |
+
|
| 115 |
+
bool AbslParseFlag(absl::string_view text, long* dst, std::string*) {
|
| 116 |
+
return ParseFlagImpl(text, *dst);
|
| 117 |
+
}
|
| 118 |
+
|
| 119 |
+
bool AbslParseFlag(absl::string_view text, unsigned long* dst, std::string*) {
|
| 120 |
+
return ParseFlagImpl(text, *dst);
|
| 121 |
+
}
|
| 122 |
+
|
| 123 |
+
bool AbslParseFlag(absl::string_view text, long long* dst, std::string*) {
|
| 124 |
+
return ParseFlagImpl(text, *dst);
|
| 125 |
+
}
|
| 126 |
+
|
| 127 |
+
bool AbslParseFlag(absl::string_view text, unsigned long long* dst,
|
| 128 |
+
std::string*) {
|
| 129 |
+
return ParseFlagImpl(text, *dst);
|
| 130 |
+
}
|
| 131 |
+
|
| 132 |
+
bool AbslParseFlag(absl::string_view text, absl::int128* dst, std::string*) {
|
| 133 |
+
text = absl::StripAsciiWhitespace(text);
|
| 134 |
+
|
| 135 |
+
// check hex
|
| 136 |
+
int base = NumericBase(text);
|
| 137 |
+
if (!absl::numbers_internal::safe_strto128_base(text, dst, base)) {
|
| 138 |
+
return false;
|
| 139 |
+
}
|
| 140 |
+
|
| 141 |
+
return base == 16 ? absl::SimpleHexAtoi(text, dst)
|
| 142 |
+
: absl::SimpleAtoi(text, dst);
|
| 143 |
+
}
|
| 144 |
+
|
| 145 |
+
bool AbslParseFlag(absl::string_view text, absl::uint128* dst, std::string*) {
|
| 146 |
+
text = absl::StripAsciiWhitespace(text);
|
| 147 |
+
|
| 148 |
+
// check hex
|
| 149 |
+
int base = NumericBase(text);
|
| 150 |
+
if (!absl::numbers_internal::safe_strtou128_base(text, dst, base)) {
|
| 151 |
+
return false;
|
| 152 |
+
}
|
| 153 |
+
|
| 154 |
+
return base == 16 ? absl::SimpleHexAtoi(text, dst)
|
| 155 |
+
: absl::SimpleAtoi(text, dst);
|
| 156 |
+
}
|
| 157 |
+
|
| 158 |
+
// --------------------------------------------------------------------
|
| 159 |
+
// AbslParseFlag for floating point types.
|
| 160 |
+
|
| 161 |
+
bool AbslParseFlag(absl::string_view text, float* dst, std::string*) {
|
| 162 |
+
return absl::SimpleAtof(text, dst);
|
| 163 |
+
}
|
| 164 |
+
|
| 165 |
+
bool AbslParseFlag(absl::string_view text, double* dst, std::string*) {
|
| 166 |
+
return absl::SimpleAtod(text, dst);
|
| 167 |
+
}
|
| 168 |
+
|
| 169 |
+
// --------------------------------------------------------------------
|
| 170 |
+
// AbslParseFlag for strings.
|
| 171 |
+
|
| 172 |
+
bool AbslParseFlag(absl::string_view text, std::string* dst, std::string*) {
|
| 173 |
+
dst->assign(text.data(), text.size());
|
| 174 |
+
return true;
|
| 175 |
+
}
|
| 176 |
+
|
| 177 |
+
// --------------------------------------------------------------------
|
| 178 |
+
// AbslParseFlag for vector of strings.
|
| 179 |
+
|
| 180 |
+
bool AbslParseFlag(absl::string_view text, std::vector<std::string>* dst,
|
| 181 |
+
std::string*) {
|
| 182 |
+
// An empty flag value corresponds to an empty vector, not a vector
|
| 183 |
+
// with a single, empty std::string.
|
| 184 |
+
if (text.empty()) {
|
| 185 |
+
dst->clear();
|
| 186 |
+
return true;
|
| 187 |
+
}
|
| 188 |
+
*dst = absl::StrSplit(text, ',', absl::AllowEmpty());
|
| 189 |
+
return true;
|
| 190 |
+
}
|
| 191 |
+
|
| 192 |
+
// --------------------------------------------------------------------
|
| 193 |
+
// AbslUnparseFlag specializations for various builtin flag types.
|
| 194 |
+
|
| 195 |
+
std::string Unparse(bool v) { return v ? "true" : "false"; }
|
| 196 |
+
std::string Unparse(short v) { return absl::StrCat(v); }
|
| 197 |
+
std::string Unparse(unsigned short v) { return absl::StrCat(v); }
|
| 198 |
+
std::string Unparse(int v) { return absl::StrCat(v); }
|
| 199 |
+
std::string Unparse(unsigned int v) { return absl::StrCat(v); }
|
| 200 |
+
std::string Unparse(long v) { return absl::StrCat(v); }
|
| 201 |
+
std::string Unparse(unsigned long v) { return absl::StrCat(v); }
|
| 202 |
+
std::string Unparse(long long v) { return absl::StrCat(v); }
|
| 203 |
+
std::string Unparse(unsigned long long v) { return absl::StrCat(v); }
|
| 204 |
+
std::string Unparse(absl::int128 v) {
|
| 205 |
+
std::stringstream ss;
|
| 206 |
+
ss << v;
|
| 207 |
+
return ss.str();
|
| 208 |
+
}
|
| 209 |
+
std::string Unparse(absl::uint128 v) {
|
| 210 |
+
std::stringstream ss;
|
| 211 |
+
ss << v;
|
| 212 |
+
return ss.str();
|
| 213 |
+
}
|
| 214 |
+
|
| 215 |
+
template <typename T>
|
| 216 |
+
std::string UnparseFloatingPointVal(T v) {
|
| 217 |
+
// digits10 is guaranteed to roundtrip correctly in string -> value -> string
|
| 218 |
+
// conversions, but may not be enough to represent all the values correctly.
|
| 219 |
+
std::string digit10_str =
|
| 220 |
+
absl::StrFormat("%.*g", std::numeric_limits<T>::digits10, v);
|
| 221 |
+
if (std::isnan(v) || std::isinf(v)) return digit10_str;
|
| 222 |
+
|
| 223 |
+
T roundtrip_val = 0;
|
| 224 |
+
std::string err;
|
| 225 |
+
if (absl::ParseFlag(digit10_str, &roundtrip_val, &err) &&
|
| 226 |
+
roundtrip_val == v) {
|
| 227 |
+
return digit10_str;
|
| 228 |
+
}
|
| 229 |
+
|
| 230 |
+
// max_digits10 is the number of base-10 digits that are necessary to uniquely
|
| 231 |
+
// represent all distinct values.
|
| 232 |
+
return absl::StrFormat("%.*g", std::numeric_limits<T>::max_digits10, v);
|
| 233 |
+
}
|
| 234 |
+
std::string Unparse(float v) { return UnparseFloatingPointVal(v); }
|
| 235 |
+
std::string Unparse(double v) { return UnparseFloatingPointVal(v); }
|
| 236 |
+
std::string AbslUnparseFlag(absl::string_view v) { return std::string(v); }
|
| 237 |
+
std::string AbslUnparseFlag(const std::vector<std::string>& v) {
|
| 238 |
+
return absl::StrJoin(v, ",");
|
| 239 |
+
}
|
| 240 |
+
|
| 241 |
+
} // namespace flags_internal
|
| 242 |
+
|
| 243 |
+
bool AbslParseFlag(absl::string_view text, absl::LogSeverity* dst,
|
| 244 |
+
std::string* err) {
|
| 245 |
+
text = absl::StripAsciiWhitespace(text);
|
| 246 |
+
if (text.empty()) {
|
| 247 |
+
*err = "no value provided";
|
| 248 |
+
return false;
|
| 249 |
+
}
|
| 250 |
+
if (absl::EqualsIgnoreCase(text, "dfatal")) {
|
| 251 |
+
*dst = absl::kLogDebugFatal;
|
| 252 |
+
return true;
|
| 253 |
+
}
|
| 254 |
+
if (absl::EqualsIgnoreCase(text, "klogdebugfatal")) {
|
| 255 |
+
*dst = absl::kLogDebugFatal;
|
| 256 |
+
return true;
|
| 257 |
+
}
|
| 258 |
+
if (text.front() == 'k' || text.front() == 'K') text.remove_prefix(1);
|
| 259 |
+
if (absl::EqualsIgnoreCase(text, "info")) {
|
| 260 |
+
*dst = absl::LogSeverity::kInfo;
|
| 261 |
+
return true;
|
| 262 |
+
}
|
| 263 |
+
if (absl::EqualsIgnoreCase(text, "warning")) {
|
| 264 |
+
*dst = absl::LogSeverity::kWarning;
|
| 265 |
+
return true;
|
| 266 |
+
}
|
| 267 |
+
if (absl::EqualsIgnoreCase(text, "error")) {
|
| 268 |
+
*dst = absl::LogSeverity::kError;
|
| 269 |
+
return true;
|
| 270 |
+
}
|
| 271 |
+
if (absl::EqualsIgnoreCase(text, "fatal")) {
|
| 272 |
+
*dst = absl::LogSeverity::kFatal;
|
| 273 |
+
return true;
|
| 274 |
+
}
|
| 275 |
+
std::underlying_type<absl::LogSeverity>::type numeric_value;
|
| 276 |
+
if (absl::ParseFlag(text, &numeric_value, err)) {
|
| 277 |
+
*dst = static_cast<absl::LogSeverity>(numeric_value);
|
| 278 |
+
return true;
|
| 279 |
+
}
|
| 280 |
+
*err =
|
| 281 |
+
"only integers, absl::LogSeverity enumerators, and DFATAL are accepted";
|
| 282 |
+
return false;
|
| 283 |
+
}
|
| 284 |
+
|
| 285 |
+
std::string AbslUnparseFlag(absl::LogSeverity v) {
|
| 286 |
+
if (v == absl::NormalizeLogSeverity(v)) return absl::LogSeverityName(v);
|
| 287 |
+
return absl::UnparseFlag(static_cast<int>(v));
|
| 288 |
+
}
|
| 289 |
+
|
| 290 |
+
ABSL_NAMESPACE_END
|
| 291 |
+
} // namespace absl
|
weight/_dep/abseil-cpp/absl/flags/parse.cc
ADDED
|
@@ -0,0 +1,943 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
//
|
| 2 |
+
// Copyright 2019 The Abseil Authors.
|
| 3 |
+
//
|
| 4 |
+
// Licensed under the Apache License, Version 2.0 (the "License");
|
| 5 |
+
// you may not use this file except in compliance with the License.
|
| 6 |
+
// You may obtain a copy of the License at
|
| 7 |
+
//
|
| 8 |
+
// https://www.apache.org/licenses/LICENSE-2.0
|
| 9 |
+
//
|
| 10 |
+
// Unless required by applicable law or agreed to in writing, software
|
| 11 |
+
// distributed under the License is distributed on an "AS IS" BASIS,
|
| 12 |
+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
| 13 |
+
// See the License for the specific language governing permissions and
|
| 14 |
+
// limitations under the License.
|
| 15 |
+
|
| 16 |
+
#include "absl/flags/parse.h"
|
| 17 |
+
|
| 18 |
+
#include <stdlib.h>
|
| 19 |
+
|
| 20 |
+
#include <algorithm>
|
| 21 |
+
#include <cstdint>
|
| 22 |
+
#include <cstdlib>
|
| 23 |
+
#include <fstream>
|
| 24 |
+
#include <iostream>
|
| 25 |
+
#include <ostream>
|
| 26 |
+
#include <string>
|
| 27 |
+
#include <tuple>
|
| 28 |
+
#include <utility>
|
| 29 |
+
#include <vector>
|
| 30 |
+
|
| 31 |
+
#ifdef _WIN32
|
| 32 |
+
#include <windows.h>
|
| 33 |
+
#endif
|
| 34 |
+
|
| 35 |
+
#include "absl/algorithm/container.h"
|
| 36 |
+
#include "absl/base/attributes.h"
|
| 37 |
+
#include "absl/base/config.h"
|
| 38 |
+
#include "absl/base/const_init.h"
|
| 39 |
+
#include "absl/base/thread_annotations.h"
|
| 40 |
+
#include "absl/flags/commandlineflag.h"
|
| 41 |
+
#include "absl/flags/config.h"
|
| 42 |
+
#include "absl/flags/flag.h"
|
| 43 |
+
#include "absl/flags/internal/commandlineflag.h"
|
| 44 |
+
#include "absl/flags/internal/flag.h"
|
| 45 |
+
#include "absl/flags/internal/parse.h"
|
| 46 |
+
#include "absl/flags/internal/private_handle_accessor.h"
|
| 47 |
+
#include "absl/flags/internal/program_name.h"
|
| 48 |
+
#include "absl/flags/internal/usage.h"
|
| 49 |
+
#include "absl/flags/reflection.h"
|
| 50 |
+
#include "absl/flags/usage.h"
|
| 51 |
+
#include "absl/flags/usage_config.h"
|
| 52 |
+
#include "absl/strings/ascii.h"
|
| 53 |
+
#include "absl/strings/internal/damerau_levenshtein_distance.h"
|
| 54 |
+
#include "absl/strings/str_cat.h"
|
| 55 |
+
#include "absl/strings/str_join.h"
|
| 56 |
+
#include "absl/strings/string_view.h"
|
| 57 |
+
#include "absl/strings/strip.h"
|
| 58 |
+
#include "absl/synchronization/mutex.h"
|
| 59 |
+
|
| 60 |
+
// --------------------------------------------------------------------
|
| 61 |
+
|
| 62 |
+
namespace absl {
|
| 63 |
+
ABSL_NAMESPACE_BEGIN
|
| 64 |
+
namespace flags_internal {
|
| 65 |
+
namespace {
|
| 66 |
+
|
| 67 |
+
ABSL_CONST_INIT absl::Mutex processing_checks_guard(absl::kConstInit);
|
| 68 |
+
|
| 69 |
+
ABSL_CONST_INIT bool flagfile_needs_processing
|
| 70 |
+
ABSL_GUARDED_BY(processing_checks_guard) = false;
|
| 71 |
+
ABSL_CONST_INIT bool fromenv_needs_processing
|
| 72 |
+
ABSL_GUARDED_BY(processing_checks_guard) = false;
|
| 73 |
+
ABSL_CONST_INIT bool tryfromenv_needs_processing
|
| 74 |
+
ABSL_GUARDED_BY(processing_checks_guard) = false;
|
| 75 |
+
|
| 76 |
+
ABSL_CONST_INIT absl::Mutex specified_flags_guard(absl::kConstInit);
|
| 77 |
+
ABSL_CONST_INIT std::vector<const CommandLineFlag*>* specified_flags
|
| 78 |
+
ABSL_GUARDED_BY(specified_flags_guard) = nullptr;
|
| 79 |
+
|
| 80 |
+
// Suggesting at most kMaxHints flags in case of misspellings.
|
| 81 |
+
ABSL_CONST_INIT const size_t kMaxHints = 100;
|
| 82 |
+
// Suggesting only flags which have a smaller distance than kMaxDistance.
|
| 83 |
+
ABSL_CONST_INIT const size_t kMaxDistance = 3;
|
| 84 |
+
|
| 85 |
+
struct SpecifiedFlagsCompare {
|
| 86 |
+
bool operator()(const CommandLineFlag* a, const CommandLineFlag* b) const {
|
| 87 |
+
return a->Name() < b->Name();
|
| 88 |
+
}
|
| 89 |
+
bool operator()(const CommandLineFlag* a, absl::string_view b) const {
|
| 90 |
+
return a->Name() < b;
|
| 91 |
+
}
|
| 92 |
+
bool operator()(absl::string_view a, const CommandLineFlag* b) const {
|
| 93 |
+
return a < b->Name();
|
| 94 |
+
}
|
| 95 |
+
};
|
| 96 |
+
|
| 97 |
+
} // namespace
|
| 98 |
+
} // namespace flags_internal
|
| 99 |
+
ABSL_NAMESPACE_END
|
| 100 |
+
} // namespace absl
|
| 101 |
+
|
| 102 |
+
// These flags influence how command line flags are parsed and are only intended
|
| 103 |
+
// to be set on the command line. Avoid reading or setting them from C++ code.
|
| 104 |
+
ABSL_FLAG(std::vector<std::string>, flagfile, {},
|
| 105 |
+
"comma-separated list of files to load flags from")
|
| 106 |
+
.OnUpdate([]() {
|
| 107 |
+
if (absl::GetFlag(FLAGS_flagfile).empty()) return;
|
| 108 |
+
|
| 109 |
+
absl::MutexLock l(&absl::flags_internal::processing_checks_guard);
|
| 110 |
+
|
| 111 |
+
// Setting this flag twice before it is handled most likely an internal
|
| 112 |
+
// error and should be reviewed by developers.
|
| 113 |
+
if (absl::flags_internal::flagfile_needs_processing) {
|
| 114 |
+
ABSL_INTERNAL_LOG(WARNING, "flagfile set twice before it is handled");
|
| 115 |
+
}
|
| 116 |
+
|
| 117 |
+
absl::flags_internal::flagfile_needs_processing = true;
|
| 118 |
+
});
|
| 119 |
+
ABSL_FLAG(std::vector<std::string>, fromenv, {},
|
| 120 |
+
"comma-separated list of flags to set from the environment"
|
| 121 |
+
" [use 'export FLAGS_flag1=value']")
|
| 122 |
+
.OnUpdate([]() {
|
| 123 |
+
if (absl::GetFlag(FLAGS_fromenv).empty()) return;
|
| 124 |
+
|
| 125 |
+
absl::MutexLock l(&absl::flags_internal::processing_checks_guard);
|
| 126 |
+
|
| 127 |
+
// Setting this flag twice before it is handled most likely an internal
|
| 128 |
+
// error and should be reviewed by developers.
|
| 129 |
+
if (absl::flags_internal::fromenv_needs_processing) {
|
| 130 |
+
ABSL_INTERNAL_LOG(WARNING, "fromenv set twice before it is handled.");
|
| 131 |
+
}
|
| 132 |
+
|
| 133 |
+
absl::flags_internal::fromenv_needs_processing = true;
|
| 134 |
+
});
|
| 135 |
+
ABSL_FLAG(std::vector<std::string>, tryfromenv, {},
|
| 136 |
+
"comma-separated list of flags to try to set from the environment if "
|
| 137 |
+
"present")
|
| 138 |
+
.OnUpdate([]() {
|
| 139 |
+
if (absl::GetFlag(FLAGS_tryfromenv).empty()) return;
|
| 140 |
+
|
| 141 |
+
absl::MutexLock l(&absl::flags_internal::processing_checks_guard);
|
| 142 |
+
|
| 143 |
+
// Setting this flag twice before it is handled most likely an internal
|
| 144 |
+
// error and should be reviewed by developers.
|
| 145 |
+
if (absl::flags_internal::tryfromenv_needs_processing) {
|
| 146 |
+
ABSL_INTERNAL_LOG(WARNING,
|
| 147 |
+
"tryfromenv set twice before it is handled.");
|
| 148 |
+
}
|
| 149 |
+
|
| 150 |
+
absl::flags_internal::tryfromenv_needs_processing = true;
|
| 151 |
+
});
|
| 152 |
+
|
| 153 |
+
// Rather than reading or setting --undefok from C++ code, please consider using
|
| 154 |
+
// ABSL_RETIRED_FLAG instead.
|
| 155 |
+
ABSL_FLAG(std::vector<std::string>, undefok, {},
|
| 156 |
+
"comma-separated list of flag names that it is okay to specify "
|
| 157 |
+
"on the command line even if the program does not define a flag "
|
| 158 |
+
"with that name");
|
| 159 |
+
|
| 160 |
+
namespace absl {
|
| 161 |
+
ABSL_NAMESPACE_BEGIN
|
| 162 |
+
namespace flags_internal {
|
| 163 |
+
|
| 164 |
+
namespace {
|
| 165 |
+
|
| 166 |
+
class ArgsList {
|
| 167 |
+
public:
|
| 168 |
+
ArgsList() : next_arg_(0) {}
|
| 169 |
+
ArgsList(int argc, char* argv[]) : args_(argv, argv + argc), next_arg_(0) {}
|
| 170 |
+
explicit ArgsList(const std::vector<std::string>& args)
|
| 171 |
+
: args_(args), next_arg_(0) {}
|
| 172 |
+
|
| 173 |
+
// Returns success status: true if parsing successful, false otherwise.
|
| 174 |
+
bool ReadFromFlagfile(const std::string& flag_file_name);
|
| 175 |
+
|
| 176 |
+
size_t Size() const { return args_.size() - next_arg_; }
|
| 177 |
+
size_t FrontIndex() const { return next_arg_; }
|
| 178 |
+
absl::string_view Front() const { return args_[next_arg_]; }
|
| 179 |
+
void PopFront() { next_arg_++; }
|
| 180 |
+
|
| 181 |
+
private:
|
| 182 |
+
std::vector<std::string> args_;
|
| 183 |
+
size_t next_arg_;
|
| 184 |
+
};
|
| 185 |
+
|
| 186 |
+
bool ArgsList::ReadFromFlagfile(const std::string& flag_file_name) {
|
| 187 |
+
std::ifstream flag_file(flag_file_name);
|
| 188 |
+
|
| 189 |
+
if (!flag_file) {
|
| 190 |
+
flags_internal::ReportUsageError(
|
| 191 |
+
absl::StrCat("Can't open flagfile ", flag_file_name), true);
|
| 192 |
+
|
| 193 |
+
return false;
|
| 194 |
+
}
|
| 195 |
+
|
| 196 |
+
// This argument represents fake argv[0], which should be present in all arg
|
| 197 |
+
// lists.
|
| 198 |
+
args_.emplace_back("");
|
| 199 |
+
|
| 200 |
+
std::string line;
|
| 201 |
+
bool success = true;
|
| 202 |
+
|
| 203 |
+
while (std::getline(flag_file, line)) {
|
| 204 |
+
absl::string_view stripped = absl::StripLeadingAsciiWhitespace(line);
|
| 205 |
+
|
| 206 |
+
if (stripped.empty() || stripped[0] == '#') {
|
| 207 |
+
// Comment or empty line; just ignore.
|
| 208 |
+
continue;
|
| 209 |
+
}
|
| 210 |
+
|
| 211 |
+
if (stripped[0] == '-') {
|
| 212 |
+
if (stripped == "--") {
|
| 213 |
+
flags_internal::ReportUsageError(
|
| 214 |
+
"Flagfile can't contain position arguments or --", true);
|
| 215 |
+
|
| 216 |
+
success = false;
|
| 217 |
+
break;
|
| 218 |
+
}
|
| 219 |
+
|
| 220 |
+
args_.emplace_back(stripped);
|
| 221 |
+
continue;
|
| 222 |
+
}
|
| 223 |
+
|
| 224 |
+
flags_internal::ReportUsageError(
|
| 225 |
+
absl::StrCat("Unexpected line in the flagfile ", flag_file_name, ": ",
|
| 226 |
+
line),
|
| 227 |
+
true);
|
| 228 |
+
|
| 229 |
+
success = false;
|
| 230 |
+
}
|
| 231 |
+
|
| 232 |
+
return success;
|
| 233 |
+
}
|
| 234 |
+
|
| 235 |
+
// --------------------------------------------------------------------
|
| 236 |
+
|
| 237 |
+
// Reads the environment variable with name `name` and stores results in
|
| 238 |
+
// `value`. If variable is not present in environment returns false, otherwise
|
| 239 |
+
// returns true.
|
| 240 |
+
bool GetEnvVar(const char* var_name, std::string& var_value) {
|
| 241 |
+
#ifdef _WIN32
|
| 242 |
+
char buf[1024];
|
| 243 |
+
auto get_res = GetEnvironmentVariableA(var_name, buf, sizeof(buf));
|
| 244 |
+
if (get_res >= sizeof(buf)) {
|
| 245 |
+
return false;
|
| 246 |
+
}
|
| 247 |
+
|
| 248 |
+
if (get_res == 0) {
|
| 249 |
+
return false;
|
| 250 |
+
}
|
| 251 |
+
|
| 252 |
+
var_value = std::string(buf, get_res);
|
| 253 |
+
#else
|
| 254 |
+
const char* val = ::getenv(var_name);
|
| 255 |
+
if (val == nullptr) {
|
| 256 |
+
return false;
|
| 257 |
+
}
|
| 258 |
+
|
| 259 |
+
var_value = val;
|
| 260 |
+
#endif
|
| 261 |
+
|
| 262 |
+
return true;
|
| 263 |
+
}
|
| 264 |
+
|
| 265 |
+
// --------------------------------------------------------------------
|
| 266 |
+
|
| 267 |
+
// Returns:
|
| 268 |
+
// Flag name or empty if arg= --
|
| 269 |
+
// Flag value after = in --flag=value (empty if --foo)
|
| 270 |
+
// "Is empty value" status. True if arg= --foo=, false otherwise. This is
|
| 271 |
+
// required to separate --foo from --foo=.
|
| 272 |
+
// For example:
|
| 273 |
+
// arg return values
|
| 274 |
+
// "--foo=bar" -> {"foo", "bar", false}.
|
| 275 |
+
// "--foo" -> {"foo", "", false}.
|
| 276 |
+
// "--foo=" -> {"foo", "", true}.
|
| 277 |
+
std::tuple<absl::string_view, absl::string_view, bool> SplitNameAndValue(
|
| 278 |
+
absl::string_view arg) {
|
| 279 |
+
// Allow -foo and --foo
|
| 280 |
+
absl::ConsumePrefix(&arg, "-");
|
| 281 |
+
|
| 282 |
+
if (arg.empty()) {
|
| 283 |
+
return std::make_tuple("", "", false);
|
| 284 |
+
}
|
| 285 |
+
|
| 286 |
+
auto equal_sign_pos = arg.find('=');
|
| 287 |
+
|
| 288 |
+
absl::string_view flag_name = arg.substr(0, equal_sign_pos);
|
| 289 |
+
|
| 290 |
+
absl::string_view value;
|
| 291 |
+
bool is_empty_value = false;
|
| 292 |
+
|
| 293 |
+
if (equal_sign_pos != absl::string_view::npos) {
|
| 294 |
+
value = arg.substr(equal_sign_pos + 1);
|
| 295 |
+
is_empty_value = value.empty();
|
| 296 |
+
}
|
| 297 |
+
|
| 298 |
+
return std::make_tuple(flag_name, value, is_empty_value);
|
| 299 |
+
}
|
| 300 |
+
|
| 301 |
+
// --------------------------------------------------------------------
|
| 302 |
+
|
| 303 |
+
// Returns:
|
| 304 |
+
// found flag or nullptr
|
| 305 |
+
// is negative in case of --nofoo
|
| 306 |
+
std::tuple<CommandLineFlag*, bool> LocateFlag(absl::string_view flag_name) {
|
| 307 |
+
CommandLineFlag* flag = absl::FindCommandLineFlag(flag_name);
|
| 308 |
+
bool is_negative = false;
|
| 309 |
+
|
| 310 |
+
if (!flag && absl::ConsumePrefix(&flag_name, "no")) {
|
| 311 |
+
flag = absl::FindCommandLineFlag(flag_name);
|
| 312 |
+
is_negative = true;
|
| 313 |
+
}
|
| 314 |
+
|
| 315 |
+
return std::make_tuple(flag, is_negative);
|
| 316 |
+
}
|
| 317 |
+
|
| 318 |
+
// --------------------------------------------------------------------
|
| 319 |
+
|
| 320 |
+
// Verify that default values of typed flags must be convertible to string and
|
| 321 |
+
// back.
|
| 322 |
+
void CheckDefaultValuesParsingRoundtrip() {
|
| 323 |
+
#ifndef NDEBUG
|
| 324 |
+
flags_internal::ForEachFlag([&](CommandLineFlag& flag) {
|
| 325 |
+
if (flag.IsRetired()) return;
|
| 326 |
+
|
| 327 |
+
#define ABSL_FLAGS_INTERNAL_IGNORE_TYPE(T, _) \
|
| 328 |
+
if (flag.IsOfType<T>()) return;
|
| 329 |
+
|
| 330 |
+
ABSL_FLAGS_INTERNAL_SUPPORTED_TYPES(ABSL_FLAGS_INTERNAL_IGNORE_TYPE)
|
| 331 |
+
#undef ABSL_FLAGS_INTERNAL_IGNORE_TYPE
|
| 332 |
+
|
| 333 |
+
flags_internal::PrivateHandleAccessor::CheckDefaultValueParsingRoundtrip(
|
| 334 |
+
flag);
|
| 335 |
+
});
|
| 336 |
+
#endif
|
| 337 |
+
}
|
| 338 |
+
|
| 339 |
+
// --------------------------------------------------------------------
|
| 340 |
+
|
| 341 |
+
// Returns success status, which is true if we successfully read all flag files,
|
| 342 |
+
// in which case new ArgLists are appended to the input_args in a reverse order
|
| 343 |
+
// of file names in the input flagfiles list. This order ensures that flags from
|
| 344 |
+
// the first flagfile in the input list are processed before the second flagfile
|
| 345 |
+
// etc.
|
| 346 |
+
bool ReadFlagfiles(const std::vector<std::string>& flagfiles,
|
| 347 |
+
std::vector<ArgsList>& input_args) {
|
| 348 |
+
bool success = true;
|
| 349 |
+
for (auto it = flagfiles.rbegin(); it != flagfiles.rend(); ++it) {
|
| 350 |
+
ArgsList al;
|
| 351 |
+
|
| 352 |
+
if (al.ReadFromFlagfile(*it)) {
|
| 353 |
+
input_args.push_back(al);
|
| 354 |
+
} else {
|
| 355 |
+
success = false;
|
| 356 |
+
}
|
| 357 |
+
}
|
| 358 |
+
|
| 359 |
+
return success;
|
| 360 |
+
}
|
| 361 |
+
|
| 362 |
+
// Returns success status, which is true if were able to locate all environment
|
| 363 |
+
// variables correctly or if fail_on_absent_in_env is false. The environment
|
| 364 |
+
// variable names are expected to be of the form `FLAGS_<flag_name>`, where
|
| 365 |
+
// `flag_name` is a string from the input flag_names list. If successful we
|
| 366 |
+
// append a single ArgList at the end of the input_args.
|
| 367 |
+
bool ReadFlagsFromEnv(const std::vector<std::string>& flag_names,
|
| 368 |
+
std::vector<ArgsList>& input_args,
|
| 369 |
+
bool fail_on_absent_in_env) {
|
| 370 |
+
bool success = true;
|
| 371 |
+
std::vector<std::string> args;
|
| 372 |
+
|
| 373 |
+
// This argument represents fake argv[0], which should be present in all arg
|
| 374 |
+
// lists.
|
| 375 |
+
args.emplace_back("");
|
| 376 |
+
|
| 377 |
+
for (const auto& flag_name : flag_names) {
|
| 378 |
+
// Avoid infinite recursion.
|
| 379 |
+
if (flag_name == "fromenv" || flag_name == "tryfromenv") {
|
| 380 |
+
flags_internal::ReportUsageError(
|
| 381 |
+
absl::StrCat("Infinite recursion on flag ", flag_name), true);
|
| 382 |
+
|
| 383 |
+
success = false;
|
| 384 |
+
continue;
|
| 385 |
+
}
|
| 386 |
+
|
| 387 |
+
const std::string envname = absl::StrCat("FLAGS_", flag_name);
|
| 388 |
+
std::string envval;
|
| 389 |
+
if (!GetEnvVar(envname.c_str(), envval)) {
|
| 390 |
+
if (fail_on_absent_in_env) {
|
| 391 |
+
flags_internal::ReportUsageError(
|
| 392 |
+
absl::StrCat(envname, " not found in environment"), true);
|
| 393 |
+
|
| 394 |
+
success = false;
|
| 395 |
+
}
|
| 396 |
+
|
| 397 |
+
continue;
|
| 398 |
+
}
|
| 399 |
+
|
| 400 |
+
args.push_back(absl::StrCat("--", flag_name, "=", envval));
|
| 401 |
+
}
|
| 402 |
+
|
| 403 |
+
if (success) {
|
| 404 |
+
input_args.emplace_back(args);
|
| 405 |
+
}
|
| 406 |
+
|
| 407 |
+
return success;
|
| 408 |
+
}
|
| 409 |
+
|
| 410 |
+
// --------------------------------------------------------------------
|
| 411 |
+
|
| 412 |
+
// Returns success status, which is true if were able to handle all generator
|
| 413 |
+
// flags (flagfile, fromenv, tryfromemv) successfully.
|
| 414 |
+
bool HandleGeneratorFlags(std::vector<ArgsList>& input_args,
|
| 415 |
+
std::vector<std::string>& flagfile_value) {
|
| 416 |
+
bool success = true;
|
| 417 |
+
|
| 418 |
+
absl::MutexLock l(&flags_internal::processing_checks_guard);
|
| 419 |
+
|
| 420 |
+
// flagfile could have been set either on a command line or
|
| 421 |
+
// programmatically before invoking ParseCommandLine. Note that we do not
|
| 422 |
+
// actually process arguments specified in the flagfile, but instead
|
| 423 |
+
// create a secondary arguments list to be processed along with the rest
|
| 424 |
+
// of the command line arguments. Since we always the process most recently
|
| 425 |
+
// created list of arguments first, this will result in flagfile argument
|
| 426 |
+
// being processed before any other argument in the command line. If
|
| 427 |
+
// FLAGS_flagfile contains more than one file name we create multiple new
|
| 428 |
+
// levels of arguments in a reverse order of file names. Thus we always
|
| 429 |
+
// process arguments from first file before arguments containing in a
|
| 430 |
+
// second file, etc. If flagfile contains another
|
| 431 |
+
// --flagfile inside of it, it will produce new level of arguments and
|
| 432 |
+
// processed before the rest of the flagfile. We are also collecting all
|
| 433 |
+
// flagfiles set on original command line. Unlike the rest of the flags,
|
| 434 |
+
// this flag can be set multiple times and is expected to be handled
|
| 435 |
+
// multiple times. We are collecting them all into a single list and set
|
| 436 |
+
// the value of FLAGS_flagfile to that value at the end of the parsing.
|
| 437 |
+
if (flags_internal::flagfile_needs_processing) {
|
| 438 |
+
auto flagfiles = absl::GetFlag(FLAGS_flagfile);
|
| 439 |
+
|
| 440 |
+
if (input_args.size() == 1) {
|
| 441 |
+
flagfile_value.insert(flagfile_value.end(), flagfiles.begin(),
|
| 442 |
+
flagfiles.end());
|
| 443 |
+
}
|
| 444 |
+
|
| 445 |
+
success &= ReadFlagfiles(flagfiles, input_args);
|
| 446 |
+
|
| 447 |
+
flags_internal::flagfile_needs_processing = false;
|
| 448 |
+
}
|
| 449 |
+
|
| 450 |
+
// Similar to flagfile fromenv/tryfromemv can be set both
|
| 451 |
+
// programmatically and at runtime on a command line. Unlike flagfile these
|
| 452 |
+
// can't be recursive.
|
| 453 |
+
if (flags_internal::fromenv_needs_processing) {
|
| 454 |
+
auto flags_list = absl::GetFlag(FLAGS_fromenv);
|
| 455 |
+
|
| 456 |
+
success &= ReadFlagsFromEnv(flags_list, input_args, true);
|
| 457 |
+
|
| 458 |
+
flags_internal::fromenv_needs_processing = false;
|
| 459 |
+
}
|
| 460 |
+
|
| 461 |
+
if (flags_internal::tryfromenv_needs_processing) {
|
| 462 |
+
auto flags_list = absl::GetFlag(FLAGS_tryfromenv);
|
| 463 |
+
|
| 464 |
+
success &= ReadFlagsFromEnv(flags_list, input_args, false);
|
| 465 |
+
|
| 466 |
+
flags_internal::tryfromenv_needs_processing = false;
|
| 467 |
+
}
|
| 468 |
+
|
| 469 |
+
return success;
|
| 470 |
+
}
|
| 471 |
+
|
| 472 |
+
// --------------------------------------------------------------------
|
| 473 |
+
|
| 474 |
+
void ResetGeneratorFlags(const std::vector<std::string>& flagfile_value) {
|
| 475 |
+
// Setting flagfile to the value which collates all the values set on a
|
| 476 |
+
// command line and programmatically. So if command line looked like
|
| 477 |
+
// --flagfile=f1 --flagfile=f2 the final value of the FLAGS_flagfile flag is
|
| 478 |
+
// going to be {"f1", "f2"}
|
| 479 |
+
if (!flagfile_value.empty()) {
|
| 480 |
+
absl::SetFlag(&FLAGS_flagfile, flagfile_value);
|
| 481 |
+
absl::MutexLock l(&flags_internal::processing_checks_guard);
|
| 482 |
+
flags_internal::flagfile_needs_processing = false;
|
| 483 |
+
}
|
| 484 |
+
|
| 485 |
+
// fromenv/tryfromenv are set to <undefined> value.
|
| 486 |
+
if (!absl::GetFlag(FLAGS_fromenv).empty()) {
|
| 487 |
+
absl::SetFlag(&FLAGS_fromenv, {});
|
| 488 |
+
}
|
| 489 |
+
if (!absl::GetFlag(FLAGS_tryfromenv).empty()) {
|
| 490 |
+
absl::SetFlag(&FLAGS_tryfromenv, {});
|
| 491 |
+
}
|
| 492 |
+
|
| 493 |
+
absl::MutexLock l(&flags_internal::processing_checks_guard);
|
| 494 |
+
flags_internal::fromenv_needs_processing = false;
|
| 495 |
+
flags_internal::tryfromenv_needs_processing = false;
|
| 496 |
+
}
|
| 497 |
+
|
| 498 |
+
// --------------------------------------------------------------------
|
| 499 |
+
|
| 500 |
+
// Returns:
|
| 501 |
+
// success status
|
| 502 |
+
// deduced value
|
| 503 |
+
// We are also mutating curr_list in case if we need to get a hold of next
|
| 504 |
+
// argument in the input.
|
| 505 |
+
std::tuple<bool, absl::string_view> DeduceFlagValue(const CommandLineFlag& flag,
|
| 506 |
+
absl::string_view value,
|
| 507 |
+
bool is_negative,
|
| 508 |
+
bool is_empty_value,
|
| 509 |
+
ArgsList* curr_list) {
|
| 510 |
+
// Value is either an argument suffix after `=` in "--foo=<value>"
|
| 511 |
+
// or separate argument in case of "--foo" "<value>".
|
| 512 |
+
|
| 513 |
+
// boolean flags have these forms:
|
| 514 |
+
// --foo
|
| 515 |
+
// --nofoo
|
| 516 |
+
// --foo=true
|
| 517 |
+
// --foo=false
|
| 518 |
+
// --nofoo=<value> is not supported
|
| 519 |
+
// --foo <value> is not supported
|
| 520 |
+
|
| 521 |
+
// non boolean flags have these forms:
|
| 522 |
+
// --foo=<value>
|
| 523 |
+
// --foo <value>
|
| 524 |
+
// --nofoo is not supported
|
| 525 |
+
|
| 526 |
+
if (flag.IsOfType<bool>()) {
|
| 527 |
+
if (value.empty()) {
|
| 528 |
+
if (is_empty_value) {
|
| 529 |
+
// "--bool_flag=" case
|
| 530 |
+
flags_internal::ReportUsageError(
|
| 531 |
+
absl::StrCat(
|
| 532 |
+
"Missing the value after assignment for the boolean flag '",
|
| 533 |
+
flag.Name(), "'"),
|
| 534 |
+
true);
|
| 535 |
+
return std::make_tuple(false, "");
|
| 536 |
+
}
|
| 537 |
+
|
| 538 |
+
// "--bool_flag" case
|
| 539 |
+
value = is_negative ? "0" : "1";
|
| 540 |
+
} else if (is_negative) {
|
| 541 |
+
// "--nobool_flag=Y" case
|
| 542 |
+
flags_internal::ReportUsageError(
|
| 543 |
+
absl::StrCat("Negative form with assignment is not valid for the "
|
| 544 |
+
"boolean flag '",
|
| 545 |
+
flag.Name(), "'"),
|
| 546 |
+
true);
|
| 547 |
+
return std::make_tuple(false, "");
|
| 548 |
+
}
|
| 549 |
+
} else if (is_negative) {
|
| 550 |
+
// "--noint_flag=1" case
|
| 551 |
+
flags_internal::ReportUsageError(
|
| 552 |
+
absl::StrCat("Negative form is not valid for the flag '", flag.Name(),
|
| 553 |
+
"'"),
|
| 554 |
+
true);
|
| 555 |
+
return std::make_tuple(false, "");
|
| 556 |
+
} else if (value.empty() && (!is_empty_value)) {
|
| 557 |
+
if (curr_list->Size() == 1) {
|
| 558 |
+
// "--int_flag" case
|
| 559 |
+
flags_internal::ReportUsageError(
|
| 560 |
+
absl::StrCat("Missing the value for the flag '", flag.Name(), "'"),
|
| 561 |
+
true);
|
| 562 |
+
return std::make_tuple(false, "");
|
| 563 |
+
}
|
| 564 |
+
|
| 565 |
+
// "--int_flag" "10" case
|
| 566 |
+
curr_list->PopFront();
|
| 567 |
+
value = curr_list->Front();
|
| 568 |
+
|
| 569 |
+
// Heuristic to detect the case where someone treats a string arg
|
| 570 |
+
// like a bool or just forgets to pass a value:
|
| 571 |
+
// --my_string_var --foo=bar
|
| 572 |
+
// We look for a flag of string type, whose value begins with a
|
| 573 |
+
// dash and corresponds to known flag or standalone --.
|
| 574 |
+
if (!value.empty() && value[0] == '-' && flag.IsOfType<std::string>()) {
|
| 575 |
+
auto maybe_flag_name = std::get<0>(SplitNameAndValue(value.substr(1)));
|
| 576 |
+
|
| 577 |
+
if (maybe_flag_name.empty() ||
|
| 578 |
+
std::get<0>(LocateFlag(maybe_flag_name)) != nullptr) {
|
| 579 |
+
// "--string_flag" "--known_flag" case
|
| 580 |
+
ABSL_INTERNAL_LOG(
|
| 581 |
+
WARNING,
|
| 582 |
+
absl::StrCat("Did you really mean to set flag '", flag.Name(),
|
| 583 |
+
"' to the value '", value, "'?"));
|
| 584 |
+
}
|
| 585 |
+
}
|
| 586 |
+
}
|
| 587 |
+
|
| 588 |
+
return std::make_tuple(true, value);
|
| 589 |
+
}
|
| 590 |
+
|
| 591 |
+
// --------------------------------------------------------------------
|
| 592 |
+
|
| 593 |
+
bool CanIgnoreUndefinedFlag(absl::string_view flag_name) {
|
| 594 |
+
auto undefok = absl::GetFlag(FLAGS_undefok);
|
| 595 |
+
if (std::find(undefok.begin(), undefok.end(), flag_name) != undefok.end()) {
|
| 596 |
+
return true;
|
| 597 |
+
}
|
| 598 |
+
|
| 599 |
+
if (absl::ConsumePrefix(&flag_name, "no") &&
|
| 600 |
+
std::find(undefok.begin(), undefok.end(), flag_name) != undefok.end()) {
|
| 601 |
+
return true;
|
| 602 |
+
}
|
| 603 |
+
|
| 604 |
+
return false;
|
| 605 |
+
}
|
| 606 |
+
|
| 607 |
+
// --------------------------------------------------------------------
|
| 608 |
+
|
| 609 |
+
void ReportUnrecognizedFlags(
|
| 610 |
+
const std::vector<UnrecognizedFlag>& unrecognized_flags,
|
| 611 |
+
bool report_as_fatal_error) {
|
| 612 |
+
for (const auto& unrecognized : unrecognized_flags) {
|
| 613 |
+
// Verify if flag_name has the "no" already removed
|
| 614 |
+
std::vector<std::string> misspelling_hints;
|
| 615 |
+
if (unrecognized.source == UnrecognizedFlag::kFromArgv) {
|
| 616 |
+
misspelling_hints =
|
| 617 |
+
flags_internal::GetMisspellingHints(unrecognized.flag_name);
|
| 618 |
+
}
|
| 619 |
+
|
| 620 |
+
if (misspelling_hints.empty()) {
|
| 621 |
+
flags_internal::ReportUsageError(
|
| 622 |
+
absl::StrCat("Unknown command line flag '", unrecognized.flag_name,
|
| 623 |
+
"'"),
|
| 624 |
+
report_as_fatal_error);
|
| 625 |
+
} else {
|
| 626 |
+
flags_internal::ReportUsageError(
|
| 627 |
+
absl::StrCat("Unknown command line flag '", unrecognized.flag_name,
|
| 628 |
+
"'. Did you mean: ",
|
| 629 |
+
absl::StrJoin(misspelling_hints, ", "), " ?"),
|
| 630 |
+
report_as_fatal_error);
|
| 631 |
+
}
|
| 632 |
+
}
|
| 633 |
+
}
|
| 634 |
+
|
| 635 |
+
} // namespace
|
| 636 |
+
|
| 637 |
+
// --------------------------------------------------------------------
|
| 638 |
+
|
| 639 |
+
bool WasPresentOnCommandLine(absl::string_view flag_name) {
|
| 640 |
+
absl::ReaderMutexLock l(&specified_flags_guard);
|
| 641 |
+
ABSL_INTERNAL_CHECK(specified_flags != nullptr,
|
| 642 |
+
"ParseCommandLine is not invoked yet");
|
| 643 |
+
|
| 644 |
+
return std::binary_search(specified_flags->begin(), specified_flags->end(),
|
| 645 |
+
flag_name, SpecifiedFlagsCompare{});
|
| 646 |
+
}
|
| 647 |
+
|
| 648 |
+
// --------------------------------------------------------------------
|
| 649 |
+
|
| 650 |
+
struct BestHints {
|
| 651 |
+
explicit BestHints(uint8_t _max) : best_distance(_max + 1) {}
|
| 652 |
+
bool AddHint(absl::string_view hint, uint8_t distance) {
|
| 653 |
+
if (hints.size() >= kMaxHints) return false;
|
| 654 |
+
if (distance == best_distance) {
|
| 655 |
+
hints.emplace_back(hint);
|
| 656 |
+
}
|
| 657 |
+
if (distance < best_distance) {
|
| 658 |
+
best_distance = distance;
|
| 659 |
+
hints = std::vector<std::string>{std::string(hint)};
|
| 660 |
+
}
|
| 661 |
+
return true;
|
| 662 |
+
}
|
| 663 |
+
|
| 664 |
+
uint8_t best_distance;
|
| 665 |
+
std::vector<std::string> hints;
|
| 666 |
+
};
|
| 667 |
+
|
| 668 |
+
// Return the list of flags with the smallest Damerau-Levenshtein distance to
|
| 669 |
+
// the given flag.
|
| 670 |
+
std::vector<std::string> GetMisspellingHints(const absl::string_view flag) {
|
| 671 |
+
const size_t maxCutoff = std::min(flag.size() / 2 + 1, kMaxDistance);
|
| 672 |
+
auto undefok = absl::GetFlag(FLAGS_undefok);
|
| 673 |
+
BestHints best_hints(static_cast<uint8_t>(maxCutoff));
|
| 674 |
+
flags_internal::ForEachFlag([&](const CommandLineFlag& f) {
|
| 675 |
+
if (best_hints.hints.size() >= kMaxHints) return;
|
| 676 |
+
uint8_t distance = strings_internal::CappedDamerauLevenshteinDistance(
|
| 677 |
+
flag, f.Name(), best_hints.best_distance);
|
| 678 |
+
best_hints.AddHint(f.Name(), distance);
|
| 679 |
+
// For boolean flags, also calculate distance to the negated form.
|
| 680 |
+
if (f.IsOfType<bool>()) {
|
| 681 |
+
const std::string negated_flag = absl::StrCat("no", f.Name());
|
| 682 |
+
distance = strings_internal::CappedDamerauLevenshteinDistance(
|
| 683 |
+
flag, negated_flag, best_hints.best_distance);
|
| 684 |
+
best_hints.AddHint(negated_flag, distance);
|
| 685 |
+
}
|
| 686 |
+
});
|
| 687 |
+
// Finally calculate distance to flags in "undefok".
|
| 688 |
+
absl::c_for_each(undefok, [&](const absl::string_view f) {
|
| 689 |
+
if (best_hints.hints.size() >= kMaxHints) return;
|
| 690 |
+
uint8_t distance = strings_internal::CappedDamerauLevenshteinDistance(
|
| 691 |
+
flag, f, best_hints.best_distance);
|
| 692 |
+
best_hints.AddHint(absl::StrCat(f, " (undefok)"), distance);
|
| 693 |
+
});
|
| 694 |
+
return best_hints.hints;
|
| 695 |
+
}
|
| 696 |
+
|
| 697 |
+
// --------------------------------------------------------------------
|
| 698 |
+
|
| 699 |
+
std::vector<char*> ParseCommandLineImpl(int argc, char* argv[],
|
| 700 |
+
UsageFlagsAction usage_flag_action,
|
| 701 |
+
OnUndefinedFlag undef_flag_action,
|
| 702 |
+
std::ostream& error_help_output) {
|
| 703 |
+
std::vector<char*> positional_args;
|
| 704 |
+
std::vector<UnrecognizedFlag> unrecognized_flags;
|
| 705 |
+
|
| 706 |
+
auto help_mode = flags_internal::ParseAbseilFlagsOnlyImpl(
|
| 707 |
+
argc, argv, positional_args, unrecognized_flags, usage_flag_action);
|
| 708 |
+
|
| 709 |
+
if (undef_flag_action != OnUndefinedFlag::kIgnoreUndefined) {
|
| 710 |
+
flags_internal::ReportUnrecognizedFlags(
|
| 711 |
+
unrecognized_flags,
|
| 712 |
+
(undef_flag_action == OnUndefinedFlag::kAbortIfUndefined));
|
| 713 |
+
|
| 714 |
+
if (undef_flag_action == OnUndefinedFlag::kAbortIfUndefined) {
|
| 715 |
+
if (!unrecognized_flags.empty()) {
|
| 716 |
+
flags_internal::HandleUsageFlags(error_help_output,
|
| 717 |
+
ProgramUsageMessage()); std::exit(1);
|
| 718 |
+
}
|
| 719 |
+
}
|
| 720 |
+
}
|
| 721 |
+
|
| 722 |
+
flags_internal::MaybeExit(help_mode);
|
| 723 |
+
|
| 724 |
+
return positional_args;
|
| 725 |
+
}
|
| 726 |
+
|
| 727 |
+
// --------------------------------------------------------------------
|
| 728 |
+
|
| 729 |
+
// This function handles all Abseil Flags and built-in usage flags and, if any
|
| 730 |
+
// help mode was handled, it returns that help mode. The caller of this function
|
| 731 |
+
// can decide to exit based on the returned help mode.
|
| 732 |
+
// The caller may decide to handle unrecognized positional arguments and
|
| 733 |
+
// unrecognized flags first before exiting.
|
| 734 |
+
//
|
| 735 |
+
// Returns:
|
| 736 |
+
// * HelpMode::kFull if parsing errors were detected in recognized arguments
|
| 737 |
+
// * The HelpMode that was handled in case when `usage_flag_action` is
|
| 738 |
+
// UsageFlagsAction::kHandleUsage and a usage flag was specified on the
|
| 739 |
+
// commandline
|
| 740 |
+
// * Otherwise it returns HelpMode::kNone
|
| 741 |
+
HelpMode ParseAbseilFlagsOnlyImpl(
|
| 742 |
+
int argc, char* argv[], std::vector<char*>& positional_args,
|
| 743 |
+
std::vector<UnrecognizedFlag>& unrecognized_flags,
|
| 744 |
+
UsageFlagsAction usage_flag_action) {
|
| 745 |
+
ABSL_INTERNAL_CHECK(argc > 0, "Missing argv[0]");
|
| 746 |
+
|
| 747 |
+
using flags_internal::ArgsList;
|
| 748 |
+
using flags_internal::specified_flags;
|
| 749 |
+
|
| 750 |
+
std::vector<std::string> flagfile_value;
|
| 751 |
+
std::vector<ArgsList> input_args;
|
| 752 |
+
|
| 753 |
+
// Once parsing has started we will not allow more flag registrations.
|
| 754 |
+
flags_internal::FinalizeRegistry();
|
| 755 |
+
|
| 756 |
+
// This routine does not return anything since we abort on failure.
|
| 757 |
+
flags_internal::CheckDefaultValuesParsingRoundtrip();
|
| 758 |
+
|
| 759 |
+
input_args.push_back(ArgsList(argc, argv));
|
| 760 |
+
|
| 761 |
+
// Set program invocation name if it is not set before.
|
| 762 |
+
if (flags_internal::ProgramInvocationName() == "UNKNOWN") {
|
| 763 |
+
flags_internal::SetProgramInvocationName(argv[0]);
|
| 764 |
+
}
|
| 765 |
+
positional_args.push_back(argv[0]);
|
| 766 |
+
|
| 767 |
+
absl::MutexLock l(&flags_internal::specified_flags_guard);
|
| 768 |
+
if (specified_flags == nullptr) {
|
| 769 |
+
specified_flags = new std::vector<const CommandLineFlag*>;
|
| 770 |
+
} else {
|
| 771 |
+
specified_flags->clear();
|
| 772 |
+
}
|
| 773 |
+
|
| 774 |
+
// Iterate through the list of the input arguments. First level are
|
| 775 |
+
// arguments originated from argc/argv. Following levels are arguments
|
| 776 |
+
// originated from recursive parsing of flagfile(s).
|
| 777 |
+
bool success = true;
|
| 778 |
+
while (!input_args.empty()) {
|
| 779 |
+
// First we process the built-in generator flags.
|
| 780 |
+
success &= flags_internal::HandleGeneratorFlags(input_args, flagfile_value);
|
| 781 |
+
|
| 782 |
+
// Select top-most (most recent) arguments list. If it is empty drop it
|
| 783 |
+
// and re-try.
|
| 784 |
+
ArgsList& curr_list = input_args.back();
|
| 785 |
+
|
| 786 |
+
// Every ArgsList starts with real or fake program name, so we can always
|
| 787 |
+
// start by skipping it.
|
| 788 |
+
curr_list.PopFront();
|
| 789 |
+
|
| 790 |
+
if (curr_list.Size() == 0) {
|
| 791 |
+
input_args.pop_back();
|
| 792 |
+
continue;
|
| 793 |
+
}
|
| 794 |
+
|
| 795 |
+
// Handle the next argument in the current list. If the stack of argument
|
| 796 |
+
// lists contains only one element - we are processing an argument from
|
| 797 |
+
// the original argv.
|
| 798 |
+
absl::string_view arg(curr_list.Front());
|
| 799 |
+
bool arg_from_argv = input_args.size() == 1;
|
| 800 |
+
|
| 801 |
+
// If argument does not start with '-' or is just "-" - this is
|
| 802 |
+
// positional argument.
|
| 803 |
+
if (!absl::ConsumePrefix(&arg, "-") || arg.empty()) {
|
| 804 |
+
ABSL_INTERNAL_CHECK(arg_from_argv,
|
| 805 |
+
"Flagfile cannot contain positional argument");
|
| 806 |
+
|
| 807 |
+
positional_args.push_back(argv[curr_list.FrontIndex()]);
|
| 808 |
+
continue;
|
| 809 |
+
}
|
| 810 |
+
|
| 811 |
+
// Split the current argument on '=' to deduce the argument flag name and
|
| 812 |
+
// value. If flag name is empty it means we've got an "--" argument. Value
|
| 813 |
+
// can be empty either if there were no '=' in argument string at all or
|
| 814 |
+
// an argument looked like "--foo=". In a latter case is_empty_value is
|
| 815 |
+
// true.
|
| 816 |
+
absl::string_view flag_name;
|
| 817 |
+
absl::string_view value;
|
| 818 |
+
bool is_empty_value = false;
|
| 819 |
+
|
| 820 |
+
std::tie(flag_name, value, is_empty_value) =
|
| 821 |
+
flags_internal::SplitNameAndValue(arg);
|
| 822 |
+
|
| 823 |
+
// Standalone "--" argument indicates that the rest of the arguments are
|
| 824 |
+
// positional. We do not support positional arguments in flagfiles.
|
| 825 |
+
if (flag_name.empty()) {
|
| 826 |
+
ABSL_INTERNAL_CHECK(arg_from_argv,
|
| 827 |
+
"Flagfile cannot contain positional argument");
|
| 828 |
+
|
| 829 |
+
curr_list.PopFront();
|
| 830 |
+
break;
|
| 831 |
+
}
|
| 832 |
+
|
| 833 |
+
// Locate the flag based on flag name. Handle both --foo and --nofoo.
|
| 834 |
+
CommandLineFlag* flag = nullptr;
|
| 835 |
+
bool is_negative = false;
|
| 836 |
+
std::tie(flag, is_negative) = flags_internal::LocateFlag(flag_name);
|
| 837 |
+
|
| 838 |
+
if (flag == nullptr) {
|
| 839 |
+
// Usage flags are not modeled as Abseil flags. Locate them separately.
|
| 840 |
+
if (flags_internal::DeduceUsageFlags(flag_name, value)) {
|
| 841 |
+
continue;
|
| 842 |
+
}
|
| 843 |
+
unrecognized_flags.emplace_back(arg_from_argv
|
| 844 |
+
? UnrecognizedFlag::kFromArgv
|
| 845 |
+
: UnrecognizedFlag::kFromFlagfile,
|
| 846 |
+
flag_name);
|
| 847 |
+
continue;
|
| 848 |
+
}
|
| 849 |
+
|
| 850 |
+
// Deduce flag's value (from this or next argument).
|
| 851 |
+
bool value_success = true;
|
| 852 |
+
std::tie(value_success, value) = flags_internal::DeduceFlagValue(
|
| 853 |
+
*flag, value, is_negative, is_empty_value, &curr_list);
|
| 854 |
+
success &= value_success;
|
| 855 |
+
|
| 856 |
+
// Set the located flag to a new value, unless it is retired. Setting
|
| 857 |
+
// retired flag fails, but we ignoring it here while also reporting access
|
| 858 |
+
// to retired flag.
|
| 859 |
+
std::string error;
|
| 860 |
+
if (!flags_internal::PrivateHandleAccessor::ParseFrom(
|
| 861 |
+
*flag, value, flags_internal::SET_FLAGS_VALUE,
|
| 862 |
+
flags_internal::kCommandLine, error)) {
|
| 863 |
+
if (flag->IsRetired()) continue;
|
| 864 |
+
|
| 865 |
+
flags_internal::ReportUsageError(error, true);
|
| 866 |
+
success = false;
|
| 867 |
+
} else {
|
| 868 |
+
specified_flags->push_back(flag);
|
| 869 |
+
}
|
| 870 |
+
}
|
| 871 |
+
|
| 872 |
+
flags_internal::ResetGeneratorFlags(flagfile_value);
|
| 873 |
+
|
| 874 |
+
// All the remaining arguments are positional.
|
| 875 |
+
if (!input_args.empty()) {
|
| 876 |
+
for (size_t arg_index = input_args.back().FrontIndex();
|
| 877 |
+
arg_index < static_cast<size_t>(argc); ++arg_index) {
|
| 878 |
+
positional_args.push_back(argv[arg_index]);
|
| 879 |
+
}
|
| 880 |
+
}
|
| 881 |
+
|
| 882 |
+
// Trim and sort the vector.
|
| 883 |
+
specified_flags->shrink_to_fit();
|
| 884 |
+
std::sort(specified_flags->begin(), specified_flags->end(),
|
| 885 |
+
flags_internal::SpecifiedFlagsCompare{});
|
| 886 |
+
|
| 887 |
+
// Filter out unrecognized flags, which are ok to ignore.
|
| 888 |
+
std::vector<UnrecognizedFlag> filtered;
|
| 889 |
+
filtered.reserve(unrecognized_flags.size());
|
| 890 |
+
for (const auto& unrecognized : unrecognized_flags) {
|
| 891 |
+
if (flags_internal::CanIgnoreUndefinedFlag(unrecognized.flag_name))
|
| 892 |
+
continue;
|
| 893 |
+
filtered.push_back(unrecognized);
|
| 894 |
+
}
|
| 895 |
+
|
| 896 |
+
std::swap(unrecognized_flags, filtered);
|
| 897 |
+
|
| 898 |
+
if (!success) {
|
| 899 |
+
#if ABSL_FLAGS_STRIP_NAMES
|
| 900 |
+
flags_internal::ReportUsageError(
|
| 901 |
+
"NOTE: command line flags are disabled in this build", true);
|
| 902 |
+
#else
|
| 903 |
+
flags_internal::HandleUsageFlags(std::cerr, ProgramUsageMessage());
|
| 904 |
+
#endif
|
| 905 |
+
return HelpMode::kFull; // We just need to make sure the exit with
|
| 906 |
+
// code 1.
|
| 907 |
+
}
|
| 908 |
+
|
| 909 |
+
return usage_flag_action == UsageFlagsAction::kHandleUsage
|
| 910 |
+
? flags_internal::HandleUsageFlags(std::cout,
|
| 911 |
+
ProgramUsageMessage())
|
| 912 |
+
: HelpMode::kNone;
|
| 913 |
+
}
|
| 914 |
+
|
| 915 |
+
} // namespace flags_internal
|
| 916 |
+
|
| 917 |
+
void ParseAbseilFlagsOnly(int argc, char* argv[],
|
| 918 |
+
std::vector<char*>& positional_args,
|
| 919 |
+
std::vector<UnrecognizedFlag>& unrecognized_flags) {
|
| 920 |
+
auto help_mode = flags_internal::ParseAbseilFlagsOnlyImpl(
|
| 921 |
+
argc, argv, positional_args, unrecognized_flags,
|
| 922 |
+
flags_internal::UsageFlagsAction::kHandleUsage);
|
| 923 |
+
|
| 924 |
+
flags_internal::MaybeExit(help_mode);
|
| 925 |
+
}
|
| 926 |
+
|
| 927 |
+
// --------------------------------------------------------------------
|
| 928 |
+
|
| 929 |
+
void ReportUnrecognizedFlags(
|
| 930 |
+
const std::vector<UnrecognizedFlag>& unrecognized_flags) {
|
| 931 |
+
flags_internal::ReportUnrecognizedFlags(unrecognized_flags, true);
|
| 932 |
+
}
|
| 933 |
+
|
| 934 |
+
// --------------------------------------------------------------------
|
| 935 |
+
|
| 936 |
+
std::vector<char*> ParseCommandLine(int argc, char* argv[]) {
|
| 937 |
+
return flags_internal::ParseCommandLineImpl(
|
| 938 |
+
argc, argv, flags_internal::UsageFlagsAction::kHandleUsage,
|
| 939 |
+
flags_internal::OnUndefinedFlag::kAbortIfUndefined);
|
| 940 |
+
}
|
| 941 |
+
|
| 942 |
+
ABSL_NAMESPACE_END
|
| 943 |
+
} // namespace absl
|
weight/_dep/abseil-cpp/absl/flags/parse.h
ADDED
|
@@ -0,0 +1,130 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
//
|
| 2 |
+
// Copyright 2019 The Abseil Authors.
|
| 3 |
+
//
|
| 4 |
+
// Licensed under the Apache License, Version 2.0 (the "License");
|
| 5 |
+
// you may not use this file except in compliance with the License.
|
| 6 |
+
// You may obtain a copy of the License at
|
| 7 |
+
//
|
| 8 |
+
// https://www.apache.org/licenses/LICENSE-2.0
|
| 9 |
+
//
|
| 10 |
+
// Unless required by applicable law or agreed to in writing, software
|
| 11 |
+
// distributed under the License is distributed on an "AS IS" BASIS,
|
| 12 |
+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
| 13 |
+
// See the License for the specific language governing permissions and
|
| 14 |
+
// limitations under the License.
|
| 15 |
+
//
|
| 16 |
+
// -----------------------------------------------------------------------------
|
| 17 |
+
// File: parse.h
|
| 18 |
+
// -----------------------------------------------------------------------------
|
| 19 |
+
//
|
| 20 |
+
// This file defines the main parsing function for Abseil flags:
|
| 21 |
+
// `absl::ParseCommandLine()`.
|
| 22 |
+
|
| 23 |
+
#ifndef ABSL_FLAGS_PARSE_H_
|
| 24 |
+
#define ABSL_FLAGS_PARSE_H_
|
| 25 |
+
|
| 26 |
+
#include <string>
|
| 27 |
+
#include <vector>
|
| 28 |
+
|
| 29 |
+
#include "absl/base/config.h"
|
| 30 |
+
#include "absl/flags/internal/parse.h"
|
| 31 |
+
|
| 32 |
+
namespace absl {
|
| 33 |
+
ABSL_NAMESPACE_BEGIN
|
| 34 |
+
|
| 35 |
+
// This type represent information about an unrecognized flag in the command
|
| 36 |
+
// line.
|
| 37 |
+
struct UnrecognizedFlag {
|
| 38 |
+
enum Source { kFromArgv, kFromFlagfile };
|
| 39 |
+
|
| 40 |
+
explicit UnrecognizedFlag(Source s, absl::string_view f)
|
| 41 |
+
: source(s), flag_name(f) {}
|
| 42 |
+
// This field indicates where we found this flag: on the original command line
|
| 43 |
+
// or read in some flag file.
|
| 44 |
+
Source source;
|
| 45 |
+
// Name of the flag we did not recognize in --flag_name=value or --flag_name.
|
| 46 |
+
std::string flag_name;
|
| 47 |
+
};
|
| 48 |
+
|
| 49 |
+
inline bool operator==(const UnrecognizedFlag& lhs,
|
| 50 |
+
const UnrecognizedFlag& rhs) {
|
| 51 |
+
return lhs.source == rhs.source && lhs.flag_name == rhs.flag_name;
|
| 52 |
+
}
|
| 53 |
+
|
| 54 |
+
namespace flags_internal {
|
| 55 |
+
|
| 56 |
+
HelpMode ParseAbseilFlagsOnlyImpl(
|
| 57 |
+
int argc, char* argv[], std::vector<char*>& positional_args,
|
| 58 |
+
std::vector<UnrecognizedFlag>& unrecognized_flags,
|
| 59 |
+
UsageFlagsAction usage_flag_action);
|
| 60 |
+
|
| 61 |
+
} // namespace flags_internal
|
| 62 |
+
|
| 63 |
+
// ParseAbseilFlagsOnly()
|
| 64 |
+
//
|
| 65 |
+
// Parses a list of command-line arguments, passed in the `argc` and `argv[]`
|
| 66 |
+
// parameters, into a set of Abseil Flag values, returning any unparsed
|
| 67 |
+
// arguments in `positional_args` and `unrecognized_flags` output parameters.
|
| 68 |
+
//
|
| 69 |
+
// This function classifies all the arguments (including content of the
|
| 70 |
+
// flagfiles, if any) into one of the following groups:
|
| 71 |
+
//
|
| 72 |
+
// * arguments specified as "--flag=value" or "--flag value" that match
|
| 73 |
+
// registered or built-in Abseil Flags. These are "Abseil Flag arguments."
|
| 74 |
+
// * arguments specified as "--flag" that are unrecognized as Abseil Flags
|
| 75 |
+
// * arguments that are not specified as "--flag" are positional arguments
|
| 76 |
+
// * arguments that follow the flag-terminating delimiter (`--`) are also
|
| 77 |
+
// treated as positional arguments regardless of their syntax.
|
| 78 |
+
//
|
| 79 |
+
// All of the deduced Abseil Flag arguments are then parsed into their
|
| 80 |
+
// corresponding flag values. If any syntax errors are found in these arguments,
|
| 81 |
+
// the binary exits with code 1.
|
| 82 |
+
//
|
| 83 |
+
// This function also handles Abseil Flags built-in usage flags (e.g. --help)
|
| 84 |
+
// if any were present on the command line.
|
| 85 |
+
//
|
| 86 |
+
// All the remaining positional arguments including original program name
|
| 87 |
+
// (argv[0]) are are returned in the `positional_args` output parameter.
|
| 88 |
+
//
|
| 89 |
+
// All unrecognized flags that are not otherwise ignored are returned in the
|
| 90 |
+
// `unrecognized_flags` output parameter. Note that the special `undefok`
|
| 91 |
+
// flag allows you to specify flags which can be safely ignored; `undefok`
|
| 92 |
+
// specifies these flags as a comma-separated list. Any unrecognized flags
|
| 93 |
+
// that appear within `undefok` will therefore be ignored and not included in
|
| 94 |
+
// the `unrecognized_flag` output parameter.
|
| 95 |
+
//
|
| 96 |
+
void ParseAbseilFlagsOnly(int argc, char* argv[],
|
| 97 |
+
std::vector<char*>& positional_args,
|
| 98 |
+
std::vector<UnrecognizedFlag>& unrecognized_flags);
|
| 99 |
+
|
| 100 |
+
// ReportUnrecognizedFlags()
|
| 101 |
+
//
|
| 102 |
+
// Reports an error to `stderr` for all non-ignored unrecognized flags in
|
| 103 |
+
// the provided `unrecognized_flags` list.
|
| 104 |
+
void ReportUnrecognizedFlags(
|
| 105 |
+
const std::vector<UnrecognizedFlag>& unrecognized_flags);
|
| 106 |
+
|
| 107 |
+
// ParseCommandLine()
|
| 108 |
+
//
|
| 109 |
+
// First parses Abseil Flags only from the command line according to the
|
| 110 |
+
// description in `ParseAbseilFlagsOnly`. In addition this function handles
|
| 111 |
+
// unrecognized and usage flags.
|
| 112 |
+
//
|
| 113 |
+
// If any unrecognized flags are located they are reported using
|
| 114 |
+
// `ReportUnrecognizedFlags`.
|
| 115 |
+
//
|
| 116 |
+
// If any errors detected during command line parsing, this routine reports a
|
| 117 |
+
// usage message and aborts the program.
|
| 118 |
+
//
|
| 119 |
+
// If any built-in usage flags were specified on the command line (e.g.
|
| 120 |
+
// `--help`), this function reports help messages and then gracefully exits the
|
| 121 |
+
// program.
|
| 122 |
+
//
|
| 123 |
+
// This function returns all the remaining positional arguments collected by
|
| 124 |
+
// `ParseAbseilFlagsOnly`.
|
| 125 |
+
std::vector<char*> ParseCommandLine(int argc, char* argv[]);
|
| 126 |
+
|
| 127 |
+
ABSL_NAMESPACE_END
|
| 128 |
+
} // namespace absl
|
| 129 |
+
|
| 130 |
+
#endif // ABSL_FLAGS_PARSE_H_
|
weight/_dep/abseil-cpp/absl/flags/parse_test.cc
ADDED
|
@@ -0,0 +1,1087 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
//
|
| 2 |
+
// Copyright 2019 The Abseil Authors.
|
| 3 |
+
//
|
| 4 |
+
// Licensed under the Apache License, Version 2.0 (the "License");
|
| 5 |
+
// you may not use this file except in compliance with the License.
|
| 6 |
+
// You may obtain a copy of the License at
|
| 7 |
+
//
|
| 8 |
+
// https://www.apache.org/licenses/LICENSE-2.0
|
| 9 |
+
//
|
| 10 |
+
// Unless required by applicable law or agreed to in writing, software
|
| 11 |
+
// distributed under the License is distributed on an "AS IS" BASIS,
|
| 12 |
+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
| 13 |
+
// See the License for the specific language governing permissions and
|
| 14 |
+
// limitations under the License.
|
| 15 |
+
|
| 16 |
+
#include "absl/flags/parse.h"
|
| 17 |
+
|
| 18 |
+
#include <stdlib.h>
|
| 19 |
+
|
| 20 |
+
#include <fstream>
|
| 21 |
+
#include <iostream>
|
| 22 |
+
#include <string>
|
| 23 |
+
#include <vector>
|
| 24 |
+
|
| 25 |
+
#include "gmock/gmock.h"
|
| 26 |
+
#include "gtest/gtest.h"
|
| 27 |
+
#include "absl/base/internal/scoped_set_env.h"
|
| 28 |
+
#include "absl/flags/flag.h"
|
| 29 |
+
#include "absl/flags/internal/parse.h"
|
| 30 |
+
#include "absl/flags/internal/usage.h"
|
| 31 |
+
#include "absl/flags/reflection.h"
|
| 32 |
+
#include "absl/log/log.h"
|
| 33 |
+
#include "absl/strings/str_cat.h"
|
| 34 |
+
#include "absl/strings/string_view.h"
|
| 35 |
+
#include "absl/strings/substitute.h"
|
| 36 |
+
#include "absl/types/span.h"
|
| 37 |
+
|
| 38 |
+
#ifdef _WIN32
|
| 39 |
+
#include <windows.h>
|
| 40 |
+
#endif
|
| 41 |
+
|
| 42 |
+
// Define 125 similar flags to test kMaxHints for flag suggestions.
|
| 43 |
+
#define FLAG_MULT(x) F3(x)
|
| 44 |
+
#define TEST_FLAG_HEADER FLAG_HEADER_
|
| 45 |
+
|
| 46 |
+
#define F(name) ABSL_FLAG(int, name, 0, "");
|
| 47 |
+
|
| 48 |
+
#define F1(name) \
|
| 49 |
+
F(name##1); \
|
| 50 |
+
F(name##2); \
|
| 51 |
+
F(name##3); \
|
| 52 |
+
F(name##4); \
|
| 53 |
+
F(name##5);
|
| 54 |
+
/**/
|
| 55 |
+
#define F2(name) \
|
| 56 |
+
F1(name##1); \
|
| 57 |
+
F1(name##2); \
|
| 58 |
+
F1(name##3); \
|
| 59 |
+
F1(name##4); \
|
| 60 |
+
F1(name##5);
|
| 61 |
+
/**/
|
| 62 |
+
#define F3(name) \
|
| 63 |
+
F2(name##1); \
|
| 64 |
+
F2(name##2); \
|
| 65 |
+
F2(name##3); \
|
| 66 |
+
F2(name##4); \
|
| 67 |
+
F2(name##5);
|
| 68 |
+
/**/
|
| 69 |
+
|
| 70 |
+
FLAG_MULT(TEST_FLAG_HEADER)
|
| 71 |
+
|
| 72 |
+
namespace {
|
| 73 |
+
|
| 74 |
+
using absl::base_internal::ScopedSetEnv;
|
| 75 |
+
|
| 76 |
+
struct UDT {
|
| 77 |
+
UDT() = default;
|
| 78 |
+
UDT(const UDT&) = default;
|
| 79 |
+
UDT& operator=(const UDT&) = default;
|
| 80 |
+
UDT(int v) : value(v) {} // NOLINT
|
| 81 |
+
|
| 82 |
+
int value;
|
| 83 |
+
};
|
| 84 |
+
|
| 85 |
+
bool AbslParseFlag(absl::string_view in, UDT* udt, std::string* err) {
|
| 86 |
+
if (in == "A") {
|
| 87 |
+
udt->value = 1;
|
| 88 |
+
return true;
|
| 89 |
+
}
|
| 90 |
+
if (in == "AAA") {
|
| 91 |
+
udt->value = 10;
|
| 92 |
+
return true;
|
| 93 |
+
}
|
| 94 |
+
|
| 95 |
+
*err = "Use values A, AAA instead";
|
| 96 |
+
return false;
|
| 97 |
+
}
|
| 98 |
+
std::string AbslUnparseFlag(const UDT& udt) {
|
| 99 |
+
return udt.value == 1 ? "A" : "AAA";
|
| 100 |
+
}
|
| 101 |
+
|
| 102 |
+
std::string GetTestTmpDirEnvVar(const char* const env_var_name) {
|
| 103 |
+
#ifdef _WIN32
|
| 104 |
+
char buf[MAX_PATH];
|
| 105 |
+
auto get_res = GetEnvironmentVariableA(env_var_name, buf, sizeof(buf));
|
| 106 |
+
if (get_res >= sizeof(buf) || get_res == 0) {
|
| 107 |
+
return "";
|
| 108 |
+
}
|
| 109 |
+
|
| 110 |
+
return std::string(buf, get_res);
|
| 111 |
+
#else
|
| 112 |
+
const char* val = ::getenv(env_var_name);
|
| 113 |
+
if (val == nullptr) {
|
| 114 |
+
return "";
|
| 115 |
+
}
|
| 116 |
+
|
| 117 |
+
return val;
|
| 118 |
+
#endif
|
| 119 |
+
}
|
| 120 |
+
|
| 121 |
+
const std::string& GetTestTempDir() {
|
| 122 |
+
static std::string* temp_dir_name = []() -> std::string* {
|
| 123 |
+
std::string* res = new std::string(GetTestTmpDirEnvVar("TEST_TMPDIR"));
|
| 124 |
+
|
| 125 |
+
if (res->empty()) {
|
| 126 |
+
*res = GetTestTmpDirEnvVar("TMPDIR");
|
| 127 |
+
}
|
| 128 |
+
|
| 129 |
+
if (res->empty()) {
|
| 130 |
+
#ifdef _WIN32
|
| 131 |
+
char temp_path_buffer[MAX_PATH];
|
| 132 |
+
|
| 133 |
+
auto len = GetTempPathA(MAX_PATH, temp_path_buffer);
|
| 134 |
+
if (len < MAX_PATH && len != 0) {
|
| 135 |
+
std::string temp_dir_name = temp_path_buffer;
|
| 136 |
+
if (!absl::EndsWith(temp_dir_name, "\\")) {
|
| 137 |
+
temp_dir_name.push_back('\\');
|
| 138 |
+
}
|
| 139 |
+
absl::StrAppend(&temp_dir_name, "parse_test.", GetCurrentProcessId());
|
| 140 |
+
if (CreateDirectoryA(temp_dir_name.c_str(), nullptr)) {
|
| 141 |
+
*res = temp_dir_name;
|
| 142 |
+
}
|
| 143 |
+
}
|
| 144 |
+
#else
|
| 145 |
+
char temp_dir_template[] = "/tmp/parse_test.XXXXXX";
|
| 146 |
+
if (auto* unique_name = ::mkdtemp(temp_dir_template)) {
|
| 147 |
+
*res = unique_name;
|
| 148 |
+
}
|
| 149 |
+
#endif
|
| 150 |
+
}
|
| 151 |
+
|
| 152 |
+
if (res->empty()) {
|
| 153 |
+
LOG(FATAL) << "Failed to make temporary directory for data files";
|
| 154 |
+
}
|
| 155 |
+
|
| 156 |
+
#ifdef _WIN32
|
| 157 |
+
*res += "\\";
|
| 158 |
+
#else
|
| 159 |
+
*res += "/";
|
| 160 |
+
#endif
|
| 161 |
+
|
| 162 |
+
return res;
|
| 163 |
+
}();
|
| 164 |
+
|
| 165 |
+
return *temp_dir_name;
|
| 166 |
+
}
|
| 167 |
+
|
| 168 |
+
struct FlagfileData {
|
| 169 |
+
const absl::string_view file_name;
|
| 170 |
+
const absl::Span<const char* const> file_lines;
|
| 171 |
+
};
|
| 172 |
+
|
| 173 |
+
// clang-format off
|
| 174 |
+
constexpr const char* const ff1_data[] = {
|
| 175 |
+
"# comment ",
|
| 176 |
+
" # comment ",
|
| 177 |
+
"",
|
| 178 |
+
" ",
|
| 179 |
+
"--int_flag=-1",
|
| 180 |
+
" --string_flag=q2w2 ",
|
| 181 |
+
" ## ",
|
| 182 |
+
" --double_flag=0.1",
|
| 183 |
+
"--bool_flag=Y "
|
| 184 |
+
};
|
| 185 |
+
|
| 186 |
+
constexpr const char* const ff2_data[] = {
|
| 187 |
+
"# Setting legacy flag",
|
| 188 |
+
"--legacy_int=1111",
|
| 189 |
+
"--legacy_bool",
|
| 190 |
+
"--nobool_flag",
|
| 191 |
+
"--legacy_str=aqsw",
|
| 192 |
+
"--int_flag=100",
|
| 193 |
+
" ## ============="
|
| 194 |
+
};
|
| 195 |
+
// clang-format on
|
| 196 |
+
|
| 197 |
+
// Builds flagfile flag in the flagfile_flag buffer and returns it. This
|
| 198 |
+
// function also creates a temporary flagfile based on FlagfileData input.
|
| 199 |
+
// We create a flagfile in a temporary directory with the name specified in
|
| 200 |
+
// FlagfileData and populate it with lines specified in FlagfileData. If $0 is
|
| 201 |
+
// referenced in any of the lines in FlagfileData they are replaced with
|
| 202 |
+
// temporary directory location. This way we can test inclusion of one flagfile
|
| 203 |
+
// from another flagfile.
|
| 204 |
+
const char* GetFlagfileFlag(const std::vector<FlagfileData>& ffd,
|
| 205 |
+
std::string& flagfile_flag) {
|
| 206 |
+
flagfile_flag = "--flagfile=";
|
| 207 |
+
absl::string_view separator;
|
| 208 |
+
for (const auto& flagfile_data : ffd) {
|
| 209 |
+
std::string flagfile_name =
|
| 210 |
+
absl::StrCat(GetTestTempDir(), flagfile_data.file_name);
|
| 211 |
+
|
| 212 |
+
std::ofstream flagfile_out(flagfile_name);
|
| 213 |
+
for (auto line : flagfile_data.file_lines) {
|
| 214 |
+
flagfile_out << absl::Substitute(line, GetTestTempDir()) << "\n";
|
| 215 |
+
}
|
| 216 |
+
|
| 217 |
+
absl::StrAppend(&flagfile_flag, separator, flagfile_name);
|
| 218 |
+
separator = ",";
|
| 219 |
+
}
|
| 220 |
+
|
| 221 |
+
return flagfile_flag.c_str();
|
| 222 |
+
}
|
| 223 |
+
|
| 224 |
+
} // namespace
|
| 225 |
+
|
| 226 |
+
ABSL_FLAG(int, int_flag, 1, "");
|
| 227 |
+
ABSL_FLAG(double, double_flag, 1.1, "");
|
| 228 |
+
ABSL_FLAG(std::string, string_flag, "a", "");
|
| 229 |
+
ABSL_FLAG(bool, bool_flag, false, "");
|
| 230 |
+
ABSL_FLAG(UDT, udt_flag, -1, "");
|
| 231 |
+
ABSL_RETIRED_FLAG(int, legacy_int, 1, "");
|
| 232 |
+
ABSL_RETIRED_FLAG(bool, legacy_bool, false, "");
|
| 233 |
+
ABSL_RETIRED_FLAG(std::string, legacy_str, "l", "");
|
| 234 |
+
|
| 235 |
+
namespace {
|
| 236 |
+
|
| 237 |
+
namespace flags = absl::flags_internal;
|
| 238 |
+
using testing::AllOf;
|
| 239 |
+
using testing::ElementsAreArray;
|
| 240 |
+
using testing::HasSubstr;
|
| 241 |
+
|
| 242 |
+
class ParseTest : public testing::Test {
|
| 243 |
+
public:
|
| 244 |
+
~ParseTest() override { flags::SetFlagsHelpMode(flags::HelpMode::kNone); }
|
| 245 |
+
|
| 246 |
+
private:
|
| 247 |
+
absl::FlagSaver flag_saver_;
|
| 248 |
+
};
|
| 249 |
+
|
| 250 |
+
// --------------------------------------------------------------------
|
| 251 |
+
|
| 252 |
+
template <int N>
|
| 253 |
+
flags::HelpMode InvokeParseAbslOnlyImpl(const char* (&in_argv)[N]) {
|
| 254 |
+
std::vector<char*> positional_args;
|
| 255 |
+
std::vector<absl::UnrecognizedFlag> unrecognized_flags;
|
| 256 |
+
|
| 257 |
+
return flags::ParseAbseilFlagsOnlyImpl(N, const_cast<char**>(in_argv),
|
| 258 |
+
positional_args, unrecognized_flags,
|
| 259 |
+
flags::UsageFlagsAction::kHandleUsage);
|
| 260 |
+
}
|
| 261 |
+
|
| 262 |
+
// --------------------------------------------------------------------
|
| 263 |
+
|
| 264 |
+
template <int N>
|
| 265 |
+
void InvokeParseAbslOnly(const char* (&in_argv)[N]) {
|
| 266 |
+
std::vector<char*> positional_args;
|
| 267 |
+
std::vector<absl::UnrecognizedFlag> unrecognized_flags;
|
| 268 |
+
|
| 269 |
+
absl::ParseAbseilFlagsOnly(2, const_cast<char**>(in_argv), positional_args,
|
| 270 |
+
unrecognized_flags);
|
| 271 |
+
}
|
| 272 |
+
|
| 273 |
+
// --------------------------------------------------------------------
|
| 274 |
+
|
| 275 |
+
template <int N>
|
| 276 |
+
std::vector<char*> InvokeParseCommandLineImpl(const char* (&in_argv)[N]) {
|
| 277 |
+
return flags::ParseCommandLineImpl(
|
| 278 |
+
N, const_cast<char**>(in_argv), flags::UsageFlagsAction::kHandleUsage,
|
| 279 |
+
flags::OnUndefinedFlag::kAbortIfUndefined, std::cerr);
|
| 280 |
+
}
|
| 281 |
+
|
| 282 |
+
// --------------------------------------------------------------------
|
| 283 |
+
|
| 284 |
+
template <int N>
|
| 285 |
+
std::vector<char*> InvokeParse(const char* (&in_argv)[N]) {
|
| 286 |
+
return absl::ParseCommandLine(N, const_cast<char**>(in_argv));
|
| 287 |
+
}
|
| 288 |
+
|
| 289 |
+
// --------------------------------------------------------------------
|
| 290 |
+
|
| 291 |
+
template <int N>
|
| 292 |
+
void TestParse(const char* (&in_argv)[N], int int_flag_value,
|
| 293 |
+
double double_flag_val, absl::string_view string_flag_val,
|
| 294 |
+
bool bool_flag_val, int exp_position_args = 0) {
|
| 295 |
+
auto out_args = InvokeParse(in_argv);
|
| 296 |
+
|
| 297 |
+
EXPECT_EQ(out_args.size(), 1 + exp_position_args);
|
| 298 |
+
EXPECT_STREQ(out_args[0], "testbin");
|
| 299 |
+
|
| 300 |
+
EXPECT_EQ(absl::GetFlag(FLAGS_int_flag), int_flag_value);
|
| 301 |
+
EXPECT_NEAR(absl::GetFlag(FLAGS_double_flag), double_flag_val, 0.0001);
|
| 302 |
+
EXPECT_EQ(absl::GetFlag(FLAGS_string_flag), string_flag_val);
|
| 303 |
+
EXPECT_EQ(absl::GetFlag(FLAGS_bool_flag), bool_flag_val);
|
| 304 |
+
}
|
| 305 |
+
|
| 306 |
+
// --------------------------------------------------------------------
|
| 307 |
+
|
| 308 |
+
TEST_F(ParseTest, TestEmptyArgv) {
|
| 309 |
+
const char* in_argv[] = {"testbin"};
|
| 310 |
+
|
| 311 |
+
auto out_args = InvokeParse(in_argv);
|
| 312 |
+
|
| 313 |
+
EXPECT_EQ(out_args.size(), 1);
|
| 314 |
+
EXPECT_STREQ(out_args[0], "testbin");
|
| 315 |
+
}
|
| 316 |
+
|
| 317 |
+
// --------------------------------------------------------------------
|
| 318 |
+
|
| 319 |
+
TEST_F(ParseTest, TestValidIntArg) {
|
| 320 |
+
const char* in_args1[] = {
|
| 321 |
+
"testbin",
|
| 322 |
+
"--int_flag=10",
|
| 323 |
+
};
|
| 324 |
+
TestParse(in_args1, 10, 1.1, "a", false);
|
| 325 |
+
|
| 326 |
+
const char* in_args2[] = {
|
| 327 |
+
"testbin",
|
| 328 |
+
"-int_flag=020",
|
| 329 |
+
};
|
| 330 |
+
TestParse(in_args2, 20, 1.1, "a", false);
|
| 331 |
+
|
| 332 |
+
const char* in_args3[] = {
|
| 333 |
+
"testbin",
|
| 334 |
+
"--int_flag",
|
| 335 |
+
"-30",
|
| 336 |
+
};
|
| 337 |
+
TestParse(in_args3, -30, 1.1, "a", false);
|
| 338 |
+
|
| 339 |
+
const char* in_args4[] = {
|
| 340 |
+
"testbin",
|
| 341 |
+
"-int_flag",
|
| 342 |
+
"0x21",
|
| 343 |
+
};
|
| 344 |
+
TestParse(in_args4, 33, 1.1, "a", false);
|
| 345 |
+
}
|
| 346 |
+
|
| 347 |
+
// --------------------------------------------------------------------
|
| 348 |
+
|
| 349 |
+
TEST_F(ParseTest, TestValidDoubleArg) {
|
| 350 |
+
const char* in_args1[] = {
|
| 351 |
+
"testbin",
|
| 352 |
+
"--double_flag=2.3",
|
| 353 |
+
};
|
| 354 |
+
TestParse(in_args1, 1, 2.3, "a", false);
|
| 355 |
+
|
| 356 |
+
const char* in_args2[] = {
|
| 357 |
+
"testbin",
|
| 358 |
+
"--double_flag=0x1.2",
|
| 359 |
+
};
|
| 360 |
+
TestParse(in_args2, 1, 1.125, "a", false);
|
| 361 |
+
|
| 362 |
+
const char* in_args3[] = {
|
| 363 |
+
"testbin",
|
| 364 |
+
"--double_flag",
|
| 365 |
+
"99.7",
|
| 366 |
+
};
|
| 367 |
+
TestParse(in_args3, 1, 99.7, "a", false);
|
| 368 |
+
|
| 369 |
+
const char* in_args4[] = {
|
| 370 |
+
"testbin",
|
| 371 |
+
"--double_flag",
|
| 372 |
+
"0x20.1",
|
| 373 |
+
};
|
| 374 |
+
TestParse(in_args4, 1, 32.0625, "a", false);
|
| 375 |
+
}
|
| 376 |
+
|
| 377 |
+
// --------------------------------------------------------------------
|
| 378 |
+
|
| 379 |
+
TEST_F(ParseTest, TestValidStringArg) {
|
| 380 |
+
const char* in_args1[] = {
|
| 381 |
+
"testbin",
|
| 382 |
+
"--string_flag=aqswde",
|
| 383 |
+
};
|
| 384 |
+
TestParse(in_args1, 1, 1.1, "aqswde", false);
|
| 385 |
+
|
| 386 |
+
const char* in_args2[] = {
|
| 387 |
+
"testbin",
|
| 388 |
+
"-string_flag=a=b=c",
|
| 389 |
+
};
|
| 390 |
+
TestParse(in_args2, 1, 1.1, "a=b=c", false);
|
| 391 |
+
|
| 392 |
+
const char* in_args3[] = {
|
| 393 |
+
"testbin",
|
| 394 |
+
"--string_flag",
|
| 395 |
+
"zaxscd",
|
| 396 |
+
};
|
| 397 |
+
TestParse(in_args3, 1, 1.1, "zaxscd", false);
|
| 398 |
+
|
| 399 |
+
const char* in_args4[] = {
|
| 400 |
+
"testbin",
|
| 401 |
+
"-string_flag",
|
| 402 |
+
"--int_flag",
|
| 403 |
+
};
|
| 404 |
+
TestParse(in_args4, 1, 1.1, "--int_flag", false);
|
| 405 |
+
|
| 406 |
+
const char* in_args5[] = {
|
| 407 |
+
"testbin",
|
| 408 |
+
"--string_flag",
|
| 409 |
+
"--no_a_flag=11",
|
| 410 |
+
};
|
| 411 |
+
TestParse(in_args5, 1, 1.1, "--no_a_flag=11", false);
|
| 412 |
+
}
|
| 413 |
+
|
| 414 |
+
// --------------------------------------------------------------------
|
| 415 |
+
|
| 416 |
+
TEST_F(ParseTest, TestValidBoolArg) {
|
| 417 |
+
const char* in_args1[] = {
|
| 418 |
+
"testbin",
|
| 419 |
+
"--bool_flag",
|
| 420 |
+
};
|
| 421 |
+
TestParse(in_args1, 1, 1.1, "a", true);
|
| 422 |
+
|
| 423 |
+
const char* in_args2[] = {
|
| 424 |
+
"testbin",
|
| 425 |
+
"--nobool_flag",
|
| 426 |
+
};
|
| 427 |
+
TestParse(in_args2, 1, 1.1, "a", false);
|
| 428 |
+
|
| 429 |
+
const char* in_args3[] = {
|
| 430 |
+
"testbin",
|
| 431 |
+
"--bool_flag=true",
|
| 432 |
+
};
|
| 433 |
+
TestParse(in_args3, 1, 1.1, "a", true);
|
| 434 |
+
|
| 435 |
+
const char* in_args4[] = {
|
| 436 |
+
"testbin",
|
| 437 |
+
"-bool_flag=false",
|
| 438 |
+
};
|
| 439 |
+
TestParse(in_args4, 1, 1.1, "a", false);
|
| 440 |
+
}
|
| 441 |
+
|
| 442 |
+
// --------------------------------------------------------------------
|
| 443 |
+
|
| 444 |
+
TEST_F(ParseTest, TestValidUDTArg) {
|
| 445 |
+
const char* in_args1[] = {
|
| 446 |
+
"testbin",
|
| 447 |
+
"--udt_flag=A",
|
| 448 |
+
};
|
| 449 |
+
InvokeParse(in_args1);
|
| 450 |
+
|
| 451 |
+
EXPECT_EQ(absl::GetFlag(FLAGS_udt_flag).value, 1);
|
| 452 |
+
|
| 453 |
+
const char* in_args2[] = {"testbin", "--udt_flag", "AAA"};
|
| 454 |
+
InvokeParse(in_args2);
|
| 455 |
+
|
| 456 |
+
EXPECT_EQ(absl::GetFlag(FLAGS_udt_flag).value, 10);
|
| 457 |
+
}
|
| 458 |
+
|
| 459 |
+
// --------------------------------------------------------------------
|
| 460 |
+
|
| 461 |
+
TEST_F(ParseTest, TestValidMultipleArg) {
|
| 462 |
+
const char* in_args1[] = {
|
| 463 |
+
"testbin", "--bool_flag", "--int_flag=2",
|
| 464 |
+
"--double_flag=0.1", "--string_flag=asd",
|
| 465 |
+
};
|
| 466 |
+
TestParse(in_args1, 2, 0.1, "asd", true);
|
| 467 |
+
|
| 468 |
+
const char* in_args2[] = {
|
| 469 |
+
"testbin", "--string_flag=", "--nobool_flag", "--int_flag",
|
| 470 |
+
"-011", "--double_flag", "-1e-2",
|
| 471 |
+
};
|
| 472 |
+
TestParse(in_args2, -11, -0.01, "", false);
|
| 473 |
+
|
| 474 |
+
const char* in_args3[] = {
|
| 475 |
+
"testbin", "--int_flag", "-0", "--string_flag", "\"\"",
|
| 476 |
+
"--bool_flag=true", "--double_flag=1e18",
|
| 477 |
+
};
|
| 478 |
+
TestParse(in_args3, 0, 1e18, "\"\"", true);
|
| 479 |
+
}
|
| 480 |
+
|
| 481 |
+
// --------------------------------------------------------------------
|
| 482 |
+
|
| 483 |
+
TEST_F(ParseTest, TestPositionalArgs) {
|
| 484 |
+
const char* in_args1[] = {
|
| 485 |
+
"testbin",
|
| 486 |
+
"p1",
|
| 487 |
+
"p2",
|
| 488 |
+
};
|
| 489 |
+
TestParse(in_args1, 1, 1.1, "a", false, 2);
|
| 490 |
+
|
| 491 |
+
auto out_args1 = InvokeParse(in_args1);
|
| 492 |
+
|
| 493 |
+
EXPECT_STREQ(out_args1[1], "p1");
|
| 494 |
+
EXPECT_STREQ(out_args1[2], "p2");
|
| 495 |
+
|
| 496 |
+
const char* in_args2[] = {
|
| 497 |
+
"testbin",
|
| 498 |
+
"--int_flag=2",
|
| 499 |
+
"p1",
|
| 500 |
+
};
|
| 501 |
+
TestParse(in_args2, 2, 1.1, "a", false, 1);
|
| 502 |
+
|
| 503 |
+
auto out_args2 = InvokeParse(in_args2);
|
| 504 |
+
|
| 505 |
+
EXPECT_STREQ(out_args2[1], "p1");
|
| 506 |
+
|
| 507 |
+
const char* in_args3[] = {"testbin", "p1", "--int_flag=3",
|
| 508 |
+
"p2", "--bool_flag", "true"};
|
| 509 |
+
TestParse(in_args3, 3, 1.1, "a", true, 3);
|
| 510 |
+
|
| 511 |
+
auto out_args3 = InvokeParse(in_args3);
|
| 512 |
+
|
| 513 |
+
EXPECT_STREQ(out_args3[1], "p1");
|
| 514 |
+
EXPECT_STREQ(out_args3[2], "p2");
|
| 515 |
+
EXPECT_STREQ(out_args3[3], "true");
|
| 516 |
+
|
| 517 |
+
const char* in_args4[] = {
|
| 518 |
+
"testbin",
|
| 519 |
+
"--",
|
| 520 |
+
"p1",
|
| 521 |
+
"p2",
|
| 522 |
+
};
|
| 523 |
+
TestParse(in_args4, 3, 1.1, "a", true, 2);
|
| 524 |
+
|
| 525 |
+
auto out_args4 = InvokeParse(in_args4);
|
| 526 |
+
|
| 527 |
+
EXPECT_STREQ(out_args4[1], "p1");
|
| 528 |
+
EXPECT_STREQ(out_args4[2], "p2");
|
| 529 |
+
|
| 530 |
+
const char* in_args5[] = {
|
| 531 |
+
"testbin", "p1", "--int_flag=4", "--", "--bool_flag", "false", "p2",
|
| 532 |
+
};
|
| 533 |
+
TestParse(in_args5, 4, 1.1, "a", true, 4);
|
| 534 |
+
|
| 535 |
+
auto out_args5 = InvokeParse(in_args5);
|
| 536 |
+
|
| 537 |
+
EXPECT_STREQ(out_args5[1], "p1");
|
| 538 |
+
EXPECT_STREQ(out_args5[2], "--bool_flag");
|
| 539 |
+
EXPECT_STREQ(out_args5[3], "false");
|
| 540 |
+
EXPECT_STREQ(out_args5[4], "p2");
|
| 541 |
+
}
|
| 542 |
+
|
| 543 |
+
// --------------------------------------------------------------------
|
| 544 |
+
|
| 545 |
+
using ParseDeathTest = ParseTest;
|
| 546 |
+
|
| 547 |
+
TEST_F(ParseDeathTest, TestUndefinedArg) {
|
| 548 |
+
const char* in_args1[] = {
|
| 549 |
+
"testbin",
|
| 550 |
+
"--undefined_flag",
|
| 551 |
+
};
|
| 552 |
+
EXPECT_DEATH_IF_SUPPORTED(InvokeParse(in_args1),
|
| 553 |
+
"Unknown command line flag 'undefined_flag'");
|
| 554 |
+
|
| 555 |
+
const char* in_args2[] = {
|
| 556 |
+
"testbin",
|
| 557 |
+
"--noprefixed_flag",
|
| 558 |
+
};
|
| 559 |
+
EXPECT_DEATH_IF_SUPPORTED(InvokeParse(in_args2),
|
| 560 |
+
"Unknown command line flag 'noprefixed_flag'");
|
| 561 |
+
|
| 562 |
+
const char* in_args3[] = {
|
| 563 |
+
"testbin",
|
| 564 |
+
"--Int_flag=1",
|
| 565 |
+
};
|
| 566 |
+
EXPECT_DEATH_IF_SUPPORTED(InvokeParse(in_args3),
|
| 567 |
+
"Unknown command line flag 'Int_flag'");
|
| 568 |
+
}
|
| 569 |
+
|
| 570 |
+
// --------------------------------------------------------------------
|
| 571 |
+
|
| 572 |
+
TEST_F(ParseDeathTest, TestInvalidBoolFlagFormat) {
|
| 573 |
+
const char* in_args1[] = {
|
| 574 |
+
"testbin",
|
| 575 |
+
"--bool_flag=",
|
| 576 |
+
};
|
| 577 |
+
EXPECT_DEATH_IF_SUPPORTED(
|
| 578 |
+
InvokeParse(in_args1),
|
| 579 |
+
"Missing the value after assignment for the boolean flag 'bool_flag'");
|
| 580 |
+
|
| 581 |
+
const char* in_args2[] = {
|
| 582 |
+
"testbin",
|
| 583 |
+
"--nobool_flag=true",
|
| 584 |
+
};
|
| 585 |
+
EXPECT_DEATH_IF_SUPPORTED(InvokeParse(in_args2),
|
| 586 |
+
"Negative form with assignment is not valid for the boolean "
|
| 587 |
+
"flag 'bool_flag'");
|
| 588 |
+
}
|
| 589 |
+
|
| 590 |
+
// --------------------------------------------------------------------
|
| 591 |
+
|
| 592 |
+
TEST_F(ParseDeathTest, TestInvalidNonBoolFlagFormat) {
|
| 593 |
+
const char* in_args1[] = {
|
| 594 |
+
"testbin",
|
| 595 |
+
"--nostring_flag",
|
| 596 |
+
};
|
| 597 |
+
EXPECT_DEATH_IF_SUPPORTED(InvokeParse(in_args1),
|
| 598 |
+
"Negative form is not valid for the flag 'string_flag'");
|
| 599 |
+
|
| 600 |
+
const char* in_args2[] = {
|
| 601 |
+
"testbin",
|
| 602 |
+
"--int_flag",
|
| 603 |
+
};
|
| 604 |
+
EXPECT_DEATH_IF_SUPPORTED(InvokeParse(in_args2),
|
| 605 |
+
"Missing the value for the flag 'int_flag'");
|
| 606 |
+
}
|
| 607 |
+
|
| 608 |
+
// --------------------------------------------------------------------
|
| 609 |
+
|
| 610 |
+
TEST_F(ParseDeathTest, TestInvalidUDTFlagFormat) {
|
| 611 |
+
const char* in_args1[] = {
|
| 612 |
+
"testbin",
|
| 613 |
+
"--udt_flag=1",
|
| 614 |
+
};
|
| 615 |
+
EXPECT_DEATH_IF_SUPPORTED(InvokeParse(in_args1),
|
| 616 |
+
"Illegal value '1' specified for flag 'udt_flag'; Use values A, "
|
| 617 |
+
"AAA instead");
|
| 618 |
+
|
| 619 |
+
const char* in_args2[] = {
|
| 620 |
+
"testbin",
|
| 621 |
+
"--udt_flag",
|
| 622 |
+
"AA",
|
| 623 |
+
};
|
| 624 |
+
EXPECT_DEATH_IF_SUPPORTED(InvokeParse(in_args2),
|
| 625 |
+
"Illegal value 'AA' specified for flag 'udt_flag'; Use values "
|
| 626 |
+
"A, AAA instead");
|
| 627 |
+
}
|
| 628 |
+
|
| 629 |
+
// --------------------------------------------------------------------
|
| 630 |
+
|
| 631 |
+
TEST_F(ParseDeathTest, TestFlagSuggestions) {
|
| 632 |
+
const char* in_args1[] = {
|
| 633 |
+
"testbin",
|
| 634 |
+
"--legacy_boo",
|
| 635 |
+
};
|
| 636 |
+
EXPECT_DEATH_IF_SUPPORTED(
|
| 637 |
+
InvokeParse(in_args1),
|
| 638 |
+
"Unknown command line flag 'legacy_boo'. Did you mean: legacy_bool ?");
|
| 639 |
+
|
| 640 |
+
const char* in_args2[] = {"testbin", "--foo", "--undefok=foo1"};
|
| 641 |
+
EXPECT_DEATH_IF_SUPPORTED(
|
| 642 |
+
InvokeParse(in_args2),
|
| 643 |
+
"Unknown command line flag 'foo'. Did you mean: foo1 \\(undefok\\)?");
|
| 644 |
+
|
| 645 |
+
const char* in_args3[] = {
|
| 646 |
+
"testbin",
|
| 647 |
+
"--nolegacy_ino",
|
| 648 |
+
};
|
| 649 |
+
EXPECT_DEATH_IF_SUPPORTED(InvokeParse(in_args3),
|
| 650 |
+
"Unknown command line flag 'nolegacy_ino'. Did "
|
| 651 |
+
"you mean: nolegacy_bool, legacy_int ?");
|
| 652 |
+
}
|
| 653 |
+
|
| 654 |
+
// --------------------------------------------------------------------
|
| 655 |
+
|
| 656 |
+
TEST_F(ParseTest, GetHints) {
|
| 657 |
+
EXPECT_THAT(absl::flags_internal::GetMisspellingHints("legacy_boo"),
|
| 658 |
+
testing::ContainerEq(std::vector<std::string>{"legacy_bool"}));
|
| 659 |
+
EXPECT_THAT(absl::flags_internal::GetMisspellingHints("nolegacy_itn"),
|
| 660 |
+
testing::ContainerEq(std::vector<std::string>{"legacy_int"}));
|
| 661 |
+
EXPECT_THAT(absl::flags_internal::GetMisspellingHints("nolegacy_int1"),
|
| 662 |
+
testing::ContainerEq(std::vector<std::string>{"legacy_int"}));
|
| 663 |
+
EXPECT_THAT(absl::flags_internal::GetMisspellingHints("nolegacy_int"),
|
| 664 |
+
testing::ContainerEq(std::vector<std::string>{"legacy_int"}));
|
| 665 |
+
EXPECT_THAT(absl::flags_internal::GetMisspellingHints("nolegacy_ino"),
|
| 666 |
+
testing::ContainerEq(
|
| 667 |
+
std::vector<std::string>{"nolegacy_bool", "legacy_int"}));
|
| 668 |
+
EXPECT_THAT(
|
| 669 |
+
absl::flags_internal::GetMisspellingHints("FLAG_HEADER_000").size(), 100);
|
| 670 |
+
}
|
| 671 |
+
|
| 672 |
+
// --------------------------------------------------------------------
|
| 673 |
+
|
| 674 |
+
TEST_F(ParseTest, TestLegacyFlags) {
|
| 675 |
+
const char* in_args1[] = {
|
| 676 |
+
"testbin",
|
| 677 |
+
"--legacy_int=11",
|
| 678 |
+
};
|
| 679 |
+
TestParse(in_args1, 1, 1.1, "a", false);
|
| 680 |
+
|
| 681 |
+
const char* in_args2[] = {
|
| 682 |
+
"testbin",
|
| 683 |
+
"--legacy_bool",
|
| 684 |
+
};
|
| 685 |
+
TestParse(in_args2, 1, 1.1, "a", false);
|
| 686 |
+
|
| 687 |
+
const char* in_args3[] = {
|
| 688 |
+
"testbin", "--legacy_int", "22", "--int_flag=2",
|
| 689 |
+
"--legacy_bool", "true", "--legacy_str", "--string_flag=qwe",
|
| 690 |
+
};
|
| 691 |
+
TestParse(in_args3, 2, 1.1, "a", false, 1);
|
| 692 |
+
}
|
| 693 |
+
|
| 694 |
+
// --------------------------------------------------------------------
|
| 695 |
+
|
| 696 |
+
TEST_F(ParseTest, TestSimpleValidFlagfile) {
|
| 697 |
+
std::string flagfile_flag;
|
| 698 |
+
|
| 699 |
+
const char* in_args1[] = {
|
| 700 |
+
"testbin",
|
| 701 |
+
GetFlagfileFlag({{"parse_test.ff1", absl::MakeConstSpan(ff1_data)}},
|
| 702 |
+
flagfile_flag),
|
| 703 |
+
};
|
| 704 |
+
TestParse(in_args1, -1, 0.1, "q2w2 ", true);
|
| 705 |
+
|
| 706 |
+
const char* in_args2[] = {
|
| 707 |
+
"testbin",
|
| 708 |
+
GetFlagfileFlag({{"parse_test.ff2", absl::MakeConstSpan(ff2_data)}},
|
| 709 |
+
flagfile_flag),
|
| 710 |
+
};
|
| 711 |
+
TestParse(in_args2, 100, 0.1, "q2w2 ", false);
|
| 712 |
+
}
|
| 713 |
+
|
| 714 |
+
// --------------------------------------------------------------------
|
| 715 |
+
|
| 716 |
+
TEST_F(ParseTest, TestValidMultiFlagfile) {
|
| 717 |
+
std::string flagfile_flag;
|
| 718 |
+
|
| 719 |
+
const char* in_args1[] = {
|
| 720 |
+
"testbin",
|
| 721 |
+
GetFlagfileFlag({{"parse_test.ff2", absl::MakeConstSpan(ff2_data)},
|
| 722 |
+
{"parse_test.ff1", absl::MakeConstSpan(ff1_data)}},
|
| 723 |
+
flagfile_flag),
|
| 724 |
+
};
|
| 725 |
+
TestParse(in_args1, -1, 0.1, "q2w2 ", true);
|
| 726 |
+
}
|
| 727 |
+
|
| 728 |
+
// --------------------------------------------------------------------
|
| 729 |
+
|
| 730 |
+
TEST_F(ParseTest, TestFlagfileMixedWithRegularFlags) {
|
| 731 |
+
std::string flagfile_flag;
|
| 732 |
+
|
| 733 |
+
const char* in_args1[] = {
|
| 734 |
+
"testbin", "--int_flag=3",
|
| 735 |
+
GetFlagfileFlag({{"parse_test.ff1", absl::MakeConstSpan(ff1_data)}},
|
| 736 |
+
flagfile_flag),
|
| 737 |
+
"-double_flag=0.2"};
|
| 738 |
+
TestParse(in_args1, -1, 0.2, "q2w2 ", true);
|
| 739 |
+
}
|
| 740 |
+
|
| 741 |
+
// --------------------------------------------------------------------
|
| 742 |
+
|
| 743 |
+
TEST_F(ParseTest, TestFlagfileInFlagfile) {
|
| 744 |
+
std::string flagfile_flag;
|
| 745 |
+
|
| 746 |
+
constexpr const char* const ff3_data[] = {
|
| 747 |
+
"--flagfile=$0/parse_test.ff1",
|
| 748 |
+
"--flagfile=$0/parse_test.ff2",
|
| 749 |
+
};
|
| 750 |
+
|
| 751 |
+
GetFlagfileFlag({{"parse_test.ff2", absl::MakeConstSpan(ff2_data)},
|
| 752 |
+
{"parse_test.ff1", absl::MakeConstSpan(ff1_data)}},
|
| 753 |
+
flagfile_flag);
|
| 754 |
+
|
| 755 |
+
const char* in_args1[] = {
|
| 756 |
+
"testbin",
|
| 757 |
+
GetFlagfileFlag({{"parse_test.ff3", absl::MakeConstSpan(ff3_data)}},
|
| 758 |
+
flagfile_flag),
|
| 759 |
+
};
|
| 760 |
+
TestParse(in_args1, 100, 0.1, "q2w2 ", false);
|
| 761 |
+
}
|
| 762 |
+
|
| 763 |
+
// --------------------------------------------------------------------
|
| 764 |
+
|
| 765 |
+
TEST_F(ParseDeathTest, TestInvalidFlagfiles) {
|
| 766 |
+
std::string flagfile_flag;
|
| 767 |
+
|
| 768 |
+
constexpr const char* const ff4_data[] = {
|
| 769 |
+
"--unknown_flag=10"
|
| 770 |
+
};
|
| 771 |
+
|
| 772 |
+
const char* in_args1[] = {
|
| 773 |
+
"testbin",
|
| 774 |
+
GetFlagfileFlag({{"parse_test.ff4",
|
| 775 |
+
absl::MakeConstSpan(ff4_data)}}, flagfile_flag),
|
| 776 |
+
};
|
| 777 |
+
EXPECT_DEATH_IF_SUPPORTED(InvokeParse(in_args1),
|
| 778 |
+
"Unknown command line flag 'unknown_flag'");
|
| 779 |
+
|
| 780 |
+
constexpr const char* const ff5_data[] = {
|
| 781 |
+
"--int_flag 10",
|
| 782 |
+
};
|
| 783 |
+
|
| 784 |
+
const char* in_args2[] = {
|
| 785 |
+
"testbin",
|
| 786 |
+
GetFlagfileFlag({{"parse_test.ff5",
|
| 787 |
+
absl::MakeConstSpan(ff5_data)}}, flagfile_flag),
|
| 788 |
+
};
|
| 789 |
+
EXPECT_DEATH_IF_SUPPORTED(InvokeParse(in_args2),
|
| 790 |
+
"Unknown command line flag 'int_flag 10'");
|
| 791 |
+
|
| 792 |
+
constexpr const char* const ff6_data[] = {
|
| 793 |
+
"--int_flag=10", "--", "arg1", "arg2", "arg3",
|
| 794 |
+
};
|
| 795 |
+
|
| 796 |
+
const char* in_args3[] = {
|
| 797 |
+
"testbin",
|
| 798 |
+
GetFlagfileFlag({{"parse_test.ff6", absl::MakeConstSpan(ff6_data)}},
|
| 799 |
+
flagfile_flag),
|
| 800 |
+
};
|
| 801 |
+
EXPECT_DEATH_IF_SUPPORTED(InvokeParse(in_args3),
|
| 802 |
+
"Flagfile can't contain position arguments or --");
|
| 803 |
+
|
| 804 |
+
const char* in_args4[] = {
|
| 805 |
+
"testbin",
|
| 806 |
+
"--flagfile=invalid_flag_file",
|
| 807 |
+
};
|
| 808 |
+
EXPECT_DEATH_IF_SUPPORTED(InvokeParse(in_args4),
|
| 809 |
+
"Can't open flagfile invalid_flag_file");
|
| 810 |
+
|
| 811 |
+
constexpr const char* const ff7_data[] = {
|
| 812 |
+
"--int_flag=10",
|
| 813 |
+
"*bin*",
|
| 814 |
+
"--str_flag=aqsw",
|
| 815 |
+
};
|
| 816 |
+
|
| 817 |
+
const char* in_args5[] = {
|
| 818 |
+
"testbin",
|
| 819 |
+
GetFlagfileFlag({{"parse_test.ff7", absl::MakeConstSpan(ff7_data)}},
|
| 820 |
+
flagfile_flag),
|
| 821 |
+
};
|
| 822 |
+
EXPECT_DEATH_IF_SUPPORTED(InvokeParse(in_args5),
|
| 823 |
+
"Unexpected line in the flagfile .*: \\*bin\\*");
|
| 824 |
+
}
|
| 825 |
+
|
| 826 |
+
// --------------------------------------------------------------------
|
| 827 |
+
|
| 828 |
+
TEST_F(ParseTest, TestReadingRequiredFlagsFromEnv) {
|
| 829 |
+
const char* in_args1[] = {"testbin",
|
| 830 |
+
"--fromenv=int_flag,bool_flag,string_flag"};
|
| 831 |
+
|
| 832 |
+
ScopedSetEnv set_int_flag("FLAGS_int_flag", "33");
|
| 833 |
+
ScopedSetEnv set_bool_flag("FLAGS_bool_flag", "True");
|
| 834 |
+
ScopedSetEnv set_string_flag("FLAGS_string_flag", "AQ12");
|
| 835 |
+
|
| 836 |
+
TestParse(in_args1, 33, 1.1, "AQ12", true);
|
| 837 |
+
}
|
| 838 |
+
|
| 839 |
+
// --------------------------------------------------------------------
|
| 840 |
+
|
| 841 |
+
TEST_F(ParseDeathTest, TestReadingUnsetRequiredFlagsFromEnv) {
|
| 842 |
+
const char* in_args1[] = {"testbin", "--fromenv=int_flag"};
|
| 843 |
+
|
| 844 |
+
EXPECT_DEATH_IF_SUPPORTED(InvokeParse(in_args1),
|
| 845 |
+
"FLAGS_int_flag not found in environment");
|
| 846 |
+
}
|
| 847 |
+
|
| 848 |
+
// --------------------------------------------------------------------
|
| 849 |
+
|
| 850 |
+
TEST_F(ParseDeathTest, TestRecursiveFlagsFromEnv) {
|
| 851 |
+
const char* in_args1[] = {"testbin", "--fromenv=tryfromenv"};
|
| 852 |
+
|
| 853 |
+
ScopedSetEnv set_tryfromenv("FLAGS_tryfromenv", "int_flag");
|
| 854 |
+
|
| 855 |
+
EXPECT_DEATH_IF_SUPPORTED(InvokeParse(in_args1),
|
| 856 |
+
"Infinite recursion on flag tryfromenv");
|
| 857 |
+
}
|
| 858 |
+
|
| 859 |
+
// --------------------------------------------------------------------
|
| 860 |
+
|
| 861 |
+
TEST_F(ParseTest, TestReadingOptionalFlagsFromEnv) {
|
| 862 |
+
const char* in_args1[] = {
|
| 863 |
+
"testbin", "--tryfromenv=int_flag,bool_flag,string_flag,other_flag"};
|
| 864 |
+
|
| 865 |
+
ScopedSetEnv set_int_flag("FLAGS_int_flag", "17");
|
| 866 |
+
ScopedSetEnv set_bool_flag("FLAGS_bool_flag", "Y");
|
| 867 |
+
|
| 868 |
+
TestParse(in_args1, 17, 1.1, "a", true);
|
| 869 |
+
}
|
| 870 |
+
|
| 871 |
+
// --------------------------------------------------------------------
|
| 872 |
+
|
| 873 |
+
TEST_F(ParseTest, TestReadingFlagsFromEnvMoxedWithRegularFlags) {
|
| 874 |
+
const char* in_args1[] = {
|
| 875 |
+
"testbin",
|
| 876 |
+
"--bool_flag=T",
|
| 877 |
+
"--tryfromenv=int_flag,bool_flag",
|
| 878 |
+
"--int_flag=-21",
|
| 879 |
+
};
|
| 880 |
+
|
| 881 |
+
ScopedSetEnv set_int_flag("FLAGS_int_flag", "-15");
|
| 882 |
+
ScopedSetEnv set_bool_flag("FLAGS_bool_flag", "F");
|
| 883 |
+
|
| 884 |
+
TestParse(in_args1, -21, 1.1, "a", false);
|
| 885 |
+
}
|
| 886 |
+
|
| 887 |
+
// --------------------------------------------------------------------
|
| 888 |
+
|
| 889 |
+
TEST_F(ParseDeathTest, TestSimpleHelpFlagHandling) {
|
| 890 |
+
const char* in_args1[] = {
|
| 891 |
+
"testbin",
|
| 892 |
+
"--help",
|
| 893 |
+
};
|
| 894 |
+
|
| 895 |
+
EXPECT_EQ(InvokeParseAbslOnlyImpl(in_args1), flags::HelpMode::kImportant);
|
| 896 |
+
EXPECT_EXIT(InvokeParse(in_args1), testing::ExitedWithCode(1), "");
|
| 897 |
+
|
| 898 |
+
const char* in_args2[] = {
|
| 899 |
+
"testbin",
|
| 900 |
+
"--help",
|
| 901 |
+
"--int_flag=3",
|
| 902 |
+
};
|
| 903 |
+
|
| 904 |
+
EXPECT_EQ(InvokeParseAbslOnlyImpl(in_args2), flags::HelpMode::kImportant);
|
| 905 |
+
EXPECT_EQ(absl::GetFlag(FLAGS_int_flag), 3);
|
| 906 |
+
|
| 907 |
+
const char* in_args3[] = {"testbin", "--help", "some_positional_arg"};
|
| 908 |
+
|
| 909 |
+
EXPECT_EQ(InvokeParseAbslOnlyImpl(in_args3), flags::HelpMode::kImportant);
|
| 910 |
+
}
|
| 911 |
+
|
| 912 |
+
// --------------------------------------------------------------------
|
| 913 |
+
|
| 914 |
+
TEST_F(ParseTest, TestSubstringHelpFlagHandling) {
|
| 915 |
+
const char* in_args1[] = {
|
| 916 |
+
"testbin",
|
| 917 |
+
"--help=abcd",
|
| 918 |
+
};
|
| 919 |
+
|
| 920 |
+
EXPECT_EQ(InvokeParseAbslOnlyImpl(in_args1), flags::HelpMode::kMatch);
|
| 921 |
+
EXPECT_EQ(flags::GetFlagsHelpMatchSubstr(), "abcd");
|
| 922 |
+
}
|
| 923 |
+
|
| 924 |
+
// --------------------------------------------------------------------
|
| 925 |
+
|
| 926 |
+
TEST_F(ParseDeathTest, TestVersionHandling) {
|
| 927 |
+
const char* in_args1[] = {
|
| 928 |
+
"testbin",
|
| 929 |
+
"--version",
|
| 930 |
+
};
|
| 931 |
+
|
| 932 |
+
EXPECT_EQ(InvokeParseAbslOnlyImpl(in_args1), flags::HelpMode::kVersion);
|
| 933 |
+
}
|
| 934 |
+
|
| 935 |
+
// --------------------------------------------------------------------
|
| 936 |
+
|
| 937 |
+
TEST_F(ParseTest, TestCheckArgsHandling) {
|
| 938 |
+
const char* in_args1[] = {"testbin", "--only_check_args", "--int_flag=211"};
|
| 939 |
+
|
| 940 |
+
EXPECT_EQ(InvokeParseAbslOnlyImpl(in_args1), flags::HelpMode::kOnlyCheckArgs);
|
| 941 |
+
EXPECT_EXIT(InvokeParseAbslOnly(in_args1), testing::ExitedWithCode(0), "");
|
| 942 |
+
EXPECT_EXIT(InvokeParse(in_args1), testing::ExitedWithCode(0), "");
|
| 943 |
+
|
| 944 |
+
const char* in_args2[] = {"testbin", "--only_check_args", "--unknown_flag=a"};
|
| 945 |
+
|
| 946 |
+
EXPECT_EQ(InvokeParseAbslOnlyImpl(in_args2), flags::HelpMode::kOnlyCheckArgs);
|
| 947 |
+
EXPECT_EXIT(InvokeParseAbslOnly(in_args2), testing::ExitedWithCode(0), "");
|
| 948 |
+
EXPECT_EXIT(InvokeParse(in_args2), testing::ExitedWithCode(1), "");
|
| 949 |
+
}
|
| 950 |
+
|
| 951 |
+
// --------------------------------------------------------------------
|
| 952 |
+
|
| 953 |
+
TEST_F(ParseTest, WasPresentOnCommandLine) {
|
| 954 |
+
const char* in_args1[] = {
|
| 955 |
+
"testbin", "arg1", "--bool_flag",
|
| 956 |
+
"--int_flag=211", "arg2", "--double_flag=1.1",
|
| 957 |
+
"--string_flag", "asd", "--",
|
| 958 |
+
"--some_flag", "arg4",
|
| 959 |
+
};
|
| 960 |
+
|
| 961 |
+
InvokeParse(in_args1);
|
| 962 |
+
|
| 963 |
+
EXPECT_TRUE(flags::WasPresentOnCommandLine("bool_flag"));
|
| 964 |
+
EXPECT_TRUE(flags::WasPresentOnCommandLine("int_flag"));
|
| 965 |
+
EXPECT_TRUE(flags::WasPresentOnCommandLine("double_flag"));
|
| 966 |
+
EXPECT_TRUE(flags::WasPresentOnCommandLine("string_flag"));
|
| 967 |
+
EXPECT_FALSE(flags::WasPresentOnCommandLine("some_flag"));
|
| 968 |
+
EXPECT_FALSE(flags::WasPresentOnCommandLine("another_flag"));
|
| 969 |
+
}
|
| 970 |
+
|
| 971 |
+
// --------------------------------------------------------------------
|
| 972 |
+
|
| 973 |
+
TEST_F(ParseTest, ParseAbseilFlagsOnlySuccess) {
|
| 974 |
+
const char* in_args[] = {
|
| 975 |
+
"testbin",
|
| 976 |
+
"arg1",
|
| 977 |
+
"--bool_flag",
|
| 978 |
+
"--int_flag=211",
|
| 979 |
+
"arg2",
|
| 980 |
+
"--double_flag=1.1",
|
| 981 |
+
"--undef_flag1",
|
| 982 |
+
"--undef_flag2=123",
|
| 983 |
+
"--string_flag",
|
| 984 |
+
"asd",
|
| 985 |
+
"--",
|
| 986 |
+
"--some_flag",
|
| 987 |
+
"arg4",
|
| 988 |
+
};
|
| 989 |
+
|
| 990 |
+
std::vector<char*> positional_args;
|
| 991 |
+
std::vector<absl::UnrecognizedFlag> unrecognized_flags;
|
| 992 |
+
|
| 993 |
+
absl::ParseAbseilFlagsOnly(13, const_cast<char**>(in_args), positional_args,
|
| 994 |
+
unrecognized_flags);
|
| 995 |
+
EXPECT_THAT(positional_args,
|
| 996 |
+
ElementsAreArray(
|
| 997 |
+
{absl::string_view("testbin"), absl::string_view("arg1"),
|
| 998 |
+
absl::string_view("arg2"), absl::string_view("--some_flag"),
|
| 999 |
+
absl::string_view("arg4")}));
|
| 1000 |
+
EXPECT_THAT(unrecognized_flags,
|
| 1001 |
+
ElementsAreArray(
|
| 1002 |
+
{absl::UnrecognizedFlag(absl::UnrecognizedFlag::kFromArgv,
|
| 1003 |
+
"undef_flag1"),
|
| 1004 |
+
absl::UnrecognizedFlag(absl::UnrecognizedFlag::kFromArgv,
|
| 1005 |
+
"undef_flag2")}));
|
| 1006 |
+
}
|
| 1007 |
+
|
| 1008 |
+
// --------------------------------------------------------------------
|
| 1009 |
+
|
| 1010 |
+
TEST_F(ParseDeathTest, ParseAbseilFlagsOnlyFailure) {
|
| 1011 |
+
const char* in_args[] = {
|
| 1012 |
+
"testbin",
|
| 1013 |
+
"--int_flag=21.1",
|
| 1014 |
+
};
|
| 1015 |
+
|
| 1016 |
+
EXPECT_DEATH_IF_SUPPORTED(
|
| 1017 |
+
InvokeParseAbslOnly(in_args),
|
| 1018 |
+
"Illegal value '21.1' specified for flag 'int_flag'");
|
| 1019 |
+
}
|
| 1020 |
+
|
| 1021 |
+
// --------------------------------------------------------------------
|
| 1022 |
+
|
| 1023 |
+
TEST_F(ParseTest, UndefOkFlagsAreIgnored) {
|
| 1024 |
+
const char* in_args[] = {
|
| 1025 |
+
"testbin", "--undef_flag1",
|
| 1026 |
+
"--undef_flag2=123", "--undefok=undef_flag2",
|
| 1027 |
+
"--undef_flag3", "value",
|
| 1028 |
+
};
|
| 1029 |
+
|
| 1030 |
+
std::vector<char*> positional_args;
|
| 1031 |
+
std::vector<absl::UnrecognizedFlag> unrecognized_flags;
|
| 1032 |
+
|
| 1033 |
+
absl::ParseAbseilFlagsOnly(6, const_cast<char**>(in_args), positional_args,
|
| 1034 |
+
unrecognized_flags);
|
| 1035 |
+
EXPECT_THAT(positional_args, ElementsAreArray({absl::string_view("testbin"),
|
| 1036 |
+
absl::string_view("value")}));
|
| 1037 |
+
EXPECT_THAT(unrecognized_flags,
|
| 1038 |
+
ElementsAreArray(
|
| 1039 |
+
{absl::UnrecognizedFlag(absl::UnrecognizedFlag::kFromArgv,
|
| 1040 |
+
"undef_flag1"),
|
| 1041 |
+
absl::UnrecognizedFlag(absl::UnrecognizedFlag::kFromArgv,
|
| 1042 |
+
"undef_flag3")}));
|
| 1043 |
+
}
|
| 1044 |
+
|
| 1045 |
+
// --------------------------------------------------------------------
|
| 1046 |
+
|
| 1047 |
+
TEST_F(ParseTest, AllUndefOkFlagsAreIgnored) {
|
| 1048 |
+
const char* in_args[] = {
|
| 1049 |
+
"testbin",
|
| 1050 |
+
"--undef_flag1",
|
| 1051 |
+
"--undef_flag2=123",
|
| 1052 |
+
"--undefok=undef_flag2,undef_flag1,undef_flag3",
|
| 1053 |
+
"--undef_flag3",
|
| 1054 |
+
"value",
|
| 1055 |
+
"--",
|
| 1056 |
+
"--undef_flag4",
|
| 1057 |
+
};
|
| 1058 |
+
|
| 1059 |
+
std::vector<char*> positional_args;
|
| 1060 |
+
std::vector<absl::UnrecognizedFlag> unrecognized_flags;
|
| 1061 |
+
|
| 1062 |
+
absl::ParseAbseilFlagsOnly(8, const_cast<char**>(in_args), positional_args,
|
| 1063 |
+
unrecognized_flags);
|
| 1064 |
+
EXPECT_THAT(positional_args,
|
| 1065 |
+
ElementsAreArray({absl::string_view("testbin"),
|
| 1066 |
+
absl::string_view("value"),
|
| 1067 |
+
absl::string_view("--undef_flag4")}));
|
| 1068 |
+
EXPECT_THAT(unrecognized_flags, testing::IsEmpty());
|
| 1069 |
+
}
|
| 1070 |
+
|
| 1071 |
+
// --------------------------------------------------------------------
|
| 1072 |
+
|
| 1073 |
+
TEST_F(ParseDeathTest, ExitOnUnrecognizedFlagPrintsHelp) {
|
| 1074 |
+
const char* in_args[] = {
|
| 1075 |
+
"testbin",
|
| 1076 |
+
"--undef_flag1",
|
| 1077 |
+
"--help=int_flag",
|
| 1078 |
+
};
|
| 1079 |
+
|
| 1080 |
+
EXPECT_EXIT(InvokeParseCommandLineImpl(in_args), testing::ExitedWithCode(1),
|
| 1081 |
+
AllOf(HasSubstr("Unknown command line flag 'undef_flag1'"),
|
| 1082 |
+
HasSubstr("Try --helpfull to get a list of all flags")));
|
| 1083 |
+
}
|
| 1084 |
+
|
| 1085 |
+
// --------------------------------------------------------------------
|
| 1086 |
+
|
| 1087 |
+
} // namespace
|
weight/_dep/abseil-cpp/absl/flags/reflection.h
ADDED
|
@@ -0,0 +1,90 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
//
|
| 2 |
+
// Copyright 2020 The Abseil Authors.
|
| 3 |
+
//
|
| 4 |
+
// Licensed under the Apache License, Version 2.0 (the "License");
|
| 5 |
+
// you may not use this file except in compliance with the License.
|
| 6 |
+
// You may obtain a copy of the License at
|
| 7 |
+
//
|
| 8 |
+
// https://www.apache.org/licenses/LICENSE-2.0
|
| 9 |
+
//
|
| 10 |
+
// Unless required by applicable law or agreed to in writing, software
|
| 11 |
+
// distributed under the License is distributed on an "AS IS" BASIS,
|
| 12 |
+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
| 13 |
+
// See the License for the specific language governing permissions and
|
| 14 |
+
// limitations under the License.
|
| 15 |
+
//
|
| 16 |
+
// -----------------------------------------------------------------------------
|
| 17 |
+
// File: reflection.h
|
| 18 |
+
// -----------------------------------------------------------------------------
|
| 19 |
+
//
|
| 20 |
+
// This file defines the routines to access and operate on an Abseil Flag's
|
| 21 |
+
// reflection handle.
|
| 22 |
+
|
| 23 |
+
#ifndef ABSL_FLAGS_REFLECTION_H_
|
| 24 |
+
#define ABSL_FLAGS_REFLECTION_H_
|
| 25 |
+
|
| 26 |
+
#include <string>
|
| 27 |
+
|
| 28 |
+
#include "absl/base/config.h"
|
| 29 |
+
#include "absl/container/flat_hash_map.h"
|
| 30 |
+
#include "absl/flags/commandlineflag.h"
|
| 31 |
+
#include "absl/flags/internal/commandlineflag.h"
|
| 32 |
+
|
| 33 |
+
namespace absl {
|
| 34 |
+
ABSL_NAMESPACE_BEGIN
|
| 35 |
+
namespace flags_internal {
|
| 36 |
+
class FlagSaverImpl;
|
| 37 |
+
} // namespace flags_internal
|
| 38 |
+
|
| 39 |
+
// FindCommandLineFlag()
|
| 40 |
+
//
|
| 41 |
+
// Returns the reflection handle of an Abseil flag of the specified name, or
|
| 42 |
+
// `nullptr` if not found. This function will emit a warning if the name of a
|
| 43 |
+
// 'retired' flag is specified.
|
| 44 |
+
absl::CommandLineFlag* FindCommandLineFlag(absl::string_view name);
|
| 45 |
+
|
| 46 |
+
// Returns current state of the Flags registry in a form of mapping from flag
|
| 47 |
+
// name to a flag reflection handle.
|
| 48 |
+
absl::flat_hash_map<absl::string_view, absl::CommandLineFlag*> GetAllFlags();
|
| 49 |
+
|
| 50 |
+
//------------------------------------------------------------------------------
|
| 51 |
+
// FlagSaver
|
| 52 |
+
//------------------------------------------------------------------------------
|
| 53 |
+
//
|
| 54 |
+
// A FlagSaver object stores the state of flags in the scope where the FlagSaver
|
| 55 |
+
// is defined, allowing modification of those flags within that scope and
|
| 56 |
+
// automatic restoration of the flags to their previous state upon leaving the
|
| 57 |
+
// scope.
|
| 58 |
+
//
|
| 59 |
+
// A FlagSaver can be used within tests to temporarily change the test
|
| 60 |
+
// environment and restore the test case to its previous state.
|
| 61 |
+
//
|
| 62 |
+
// Example:
|
| 63 |
+
//
|
| 64 |
+
// void MyFunc() {
|
| 65 |
+
// absl::FlagSaver fs;
|
| 66 |
+
// ...
|
| 67 |
+
// absl::SetFlag(&FLAGS_myFlag, otherValue);
|
| 68 |
+
// ...
|
| 69 |
+
// } // scope of FlagSaver left, flags return to previous state
|
| 70 |
+
//
|
| 71 |
+
// This class is thread-safe.
|
| 72 |
+
|
| 73 |
+
class FlagSaver {
|
| 74 |
+
public:
|
| 75 |
+
FlagSaver();
|
| 76 |
+
~FlagSaver();
|
| 77 |
+
|
| 78 |
+
FlagSaver(const FlagSaver&) = delete;
|
| 79 |
+
void operator=(const FlagSaver&) = delete;
|
| 80 |
+
|
| 81 |
+
private:
|
| 82 |
+
flags_internal::FlagSaverImpl* impl_;
|
| 83 |
+
};
|
| 84 |
+
|
| 85 |
+
//-----------------------------------------------------------------------------
|
| 86 |
+
|
| 87 |
+
ABSL_NAMESPACE_END
|
| 88 |
+
} // namespace absl
|
| 89 |
+
|
| 90 |
+
#endif // ABSL_FLAGS_REFLECTION_H_
|
weight/_dep/abseil-cpp/absl/flags/reflection_test.cc
ADDED
|
@@ -0,0 +1,265 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
//
|
| 2 |
+
// Copyright 2019 The Abseil Authors.
|
| 3 |
+
//
|
| 4 |
+
// Licensed under the Apache License, Version 2.0 (the "License");
|
| 5 |
+
// you may not use this file except in compliance with the License.
|
| 6 |
+
// You may obtain a copy of the License at
|
| 7 |
+
//
|
| 8 |
+
// https://www.apache.org/licenses/LICENSE-2.0
|
| 9 |
+
//
|
| 10 |
+
// Unless required by applicable law or agreed to in writing, software
|
| 11 |
+
// distributed under the License is distributed on an "AS IS" BASIS,
|
| 12 |
+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
| 13 |
+
// See the License for the specific language governing permissions and
|
| 14 |
+
// limitations under the License.
|
| 15 |
+
|
| 16 |
+
#include "absl/flags/reflection.h"
|
| 17 |
+
|
| 18 |
+
#include <memory>
|
| 19 |
+
#include <string>
|
| 20 |
+
|
| 21 |
+
#include "gmock/gmock.h"
|
| 22 |
+
#include "gtest/gtest.h"
|
| 23 |
+
#include "absl/flags/declare.h"
|
| 24 |
+
#include "absl/flags/flag.h"
|
| 25 |
+
#include "absl/flags/internal/commandlineflag.h"
|
| 26 |
+
#include "absl/flags/marshalling.h"
|
| 27 |
+
#include "absl/memory/memory.h"
|
| 28 |
+
#include "absl/strings/str_cat.h"
|
| 29 |
+
#include "absl/strings/str_split.h"
|
| 30 |
+
|
| 31 |
+
ABSL_FLAG(int, int_flag, 1, "int_flag help");
|
| 32 |
+
ABSL_FLAG(std::string, string_flag, "dflt", "string_flag help");
|
| 33 |
+
ABSL_RETIRED_FLAG(bool, bool_retired_flag, false, "bool_retired_flag help");
|
| 34 |
+
|
| 35 |
+
namespace {
|
| 36 |
+
|
| 37 |
+
class ReflectionTest : public testing::Test {
|
| 38 |
+
protected:
|
| 39 |
+
void SetUp() override { flag_saver_ = absl::make_unique<absl::FlagSaver>(); }
|
| 40 |
+
void TearDown() override { flag_saver_.reset(); }
|
| 41 |
+
|
| 42 |
+
private:
|
| 43 |
+
std::unique_ptr<absl::FlagSaver> flag_saver_;
|
| 44 |
+
};
|
| 45 |
+
|
| 46 |
+
// --------------------------------------------------------------------
|
| 47 |
+
|
| 48 |
+
TEST_F(ReflectionTest, TestFindCommandLineFlag) {
|
| 49 |
+
auto* handle = absl::FindCommandLineFlag("some_flag");
|
| 50 |
+
EXPECT_EQ(handle, nullptr);
|
| 51 |
+
|
| 52 |
+
handle = absl::FindCommandLineFlag("int_flag");
|
| 53 |
+
EXPECT_NE(handle, nullptr);
|
| 54 |
+
|
| 55 |
+
handle = absl::FindCommandLineFlag("string_flag");
|
| 56 |
+
EXPECT_NE(handle, nullptr);
|
| 57 |
+
|
| 58 |
+
handle = absl::FindCommandLineFlag("bool_retired_flag");
|
| 59 |
+
EXPECT_NE(handle, nullptr);
|
| 60 |
+
}
|
| 61 |
+
|
| 62 |
+
// --------------------------------------------------------------------
|
| 63 |
+
|
| 64 |
+
TEST_F(ReflectionTest, TestGetAllFlags) {
|
| 65 |
+
auto all_flags = absl::GetAllFlags();
|
| 66 |
+
EXPECT_NE(all_flags.find("int_flag"), all_flags.end());
|
| 67 |
+
EXPECT_EQ(all_flags.find("bool_retired_flag"), all_flags.end());
|
| 68 |
+
EXPECT_EQ(all_flags.find("some_undefined_flag"), all_flags.end());
|
| 69 |
+
|
| 70 |
+
std::vector<absl::string_view> flag_names_first_attempt;
|
| 71 |
+
auto all_flags_1 = absl::GetAllFlags();
|
| 72 |
+
for (auto f : all_flags_1) {
|
| 73 |
+
flag_names_first_attempt.push_back(f.first);
|
| 74 |
+
}
|
| 75 |
+
|
| 76 |
+
std::vector<absl::string_view> flag_names_second_attempt;
|
| 77 |
+
auto all_flags_2 = absl::GetAllFlags();
|
| 78 |
+
for (auto f : all_flags_2) {
|
| 79 |
+
flag_names_second_attempt.push_back(f.first);
|
| 80 |
+
}
|
| 81 |
+
|
| 82 |
+
EXPECT_THAT(flag_names_first_attempt,
|
| 83 |
+
::testing::UnorderedElementsAreArray(flag_names_second_attempt));
|
| 84 |
+
}
|
| 85 |
+
|
| 86 |
+
// --------------------------------------------------------------------
|
| 87 |
+
|
| 88 |
+
struct CustomUDT {
|
| 89 |
+
CustomUDT() : a(1), b(1) {}
|
| 90 |
+
CustomUDT(int a_, int b_) : a(a_), b(b_) {}
|
| 91 |
+
|
| 92 |
+
friend bool operator==(const CustomUDT& f1, const CustomUDT& f2) {
|
| 93 |
+
return f1.a == f2.a && f1.b == f2.b;
|
| 94 |
+
}
|
| 95 |
+
|
| 96 |
+
int a;
|
| 97 |
+
int b;
|
| 98 |
+
};
|
| 99 |
+
bool AbslParseFlag(absl::string_view in, CustomUDT* f, std::string*) {
|
| 100 |
+
std::vector<absl::string_view> parts =
|
| 101 |
+
absl::StrSplit(in, ':', absl::SkipWhitespace());
|
| 102 |
+
|
| 103 |
+
if (parts.size() != 2) return false;
|
| 104 |
+
|
| 105 |
+
if (!absl::SimpleAtoi(parts[0], &f->a)) return false;
|
| 106 |
+
|
| 107 |
+
if (!absl::SimpleAtoi(parts[1], &f->b)) return false;
|
| 108 |
+
|
| 109 |
+
return true;
|
| 110 |
+
}
|
| 111 |
+
std::string AbslUnparseFlag(const CustomUDT& f) {
|
| 112 |
+
return absl::StrCat(f.a, ":", f.b);
|
| 113 |
+
}
|
| 114 |
+
|
| 115 |
+
} // namespace
|
| 116 |
+
|
| 117 |
+
// --------------------------------------------------------------------
|
| 118 |
+
|
| 119 |
+
ABSL_FLAG(bool, test_flag_01, true, "");
|
| 120 |
+
ABSL_FLAG(int, test_flag_02, 1234, "");
|
| 121 |
+
ABSL_FLAG(int16_t, test_flag_03, -34, "");
|
| 122 |
+
ABSL_FLAG(uint16_t, test_flag_04, 189, "");
|
| 123 |
+
ABSL_FLAG(int32_t, test_flag_05, 10765, "");
|
| 124 |
+
ABSL_FLAG(uint32_t, test_flag_06, 40000, "");
|
| 125 |
+
ABSL_FLAG(int64_t, test_flag_07, -1234567, "");
|
| 126 |
+
ABSL_FLAG(uint64_t, test_flag_08, 9876543, "");
|
| 127 |
+
ABSL_FLAG(double, test_flag_09, -9.876e-50, "");
|
| 128 |
+
ABSL_FLAG(float, test_flag_10, 1.234e12f, "");
|
| 129 |
+
ABSL_FLAG(std::string, test_flag_11, "", "");
|
| 130 |
+
ABSL_FLAG(absl::Duration, test_flag_12, absl::Minutes(10), "");
|
| 131 |
+
static int counter = 0;
|
| 132 |
+
ABSL_FLAG(int, test_flag_13, 200, "").OnUpdate([]() { counter++; });
|
| 133 |
+
ABSL_FLAG(CustomUDT, test_flag_14, {}, "");
|
| 134 |
+
|
| 135 |
+
namespace {
|
| 136 |
+
|
| 137 |
+
TEST_F(ReflectionTest, TestFlagSaverInScope) {
|
| 138 |
+
{
|
| 139 |
+
absl::FlagSaver s;
|
| 140 |
+
counter = 0;
|
| 141 |
+
absl::SetFlag(&FLAGS_test_flag_01, false);
|
| 142 |
+
absl::SetFlag(&FLAGS_test_flag_02, -1021);
|
| 143 |
+
absl::SetFlag(&FLAGS_test_flag_03, 6009);
|
| 144 |
+
absl::SetFlag(&FLAGS_test_flag_04, 44);
|
| 145 |
+
absl::SetFlag(&FLAGS_test_flag_05, +800);
|
| 146 |
+
absl::SetFlag(&FLAGS_test_flag_06, -40978756);
|
| 147 |
+
absl::SetFlag(&FLAGS_test_flag_07, 23405);
|
| 148 |
+
absl::SetFlag(&FLAGS_test_flag_08, 975310);
|
| 149 |
+
absl::SetFlag(&FLAGS_test_flag_09, 1.00001);
|
| 150 |
+
absl::SetFlag(&FLAGS_test_flag_10, -3.54f);
|
| 151 |
+
absl::SetFlag(&FLAGS_test_flag_11, "asdf");
|
| 152 |
+
absl::SetFlag(&FLAGS_test_flag_12, absl::Hours(20));
|
| 153 |
+
absl::SetFlag(&FLAGS_test_flag_13, 4);
|
| 154 |
+
absl::SetFlag(&FLAGS_test_flag_14, CustomUDT{-1, -2});
|
| 155 |
+
}
|
| 156 |
+
|
| 157 |
+
EXPECT_EQ(absl::GetFlag(FLAGS_test_flag_01), true);
|
| 158 |
+
EXPECT_EQ(absl::GetFlag(FLAGS_test_flag_02), 1234);
|
| 159 |
+
EXPECT_EQ(absl::GetFlag(FLAGS_test_flag_03), -34);
|
| 160 |
+
EXPECT_EQ(absl::GetFlag(FLAGS_test_flag_04), 189);
|
| 161 |
+
EXPECT_EQ(absl::GetFlag(FLAGS_test_flag_05), 10765);
|
| 162 |
+
EXPECT_EQ(absl::GetFlag(FLAGS_test_flag_06), 40000);
|
| 163 |
+
EXPECT_EQ(absl::GetFlag(FLAGS_test_flag_07), -1234567);
|
| 164 |
+
EXPECT_EQ(absl::GetFlag(FLAGS_test_flag_08), 9876543);
|
| 165 |
+
EXPECT_NEAR(absl::GetFlag(FLAGS_test_flag_09), -9.876e-50, 1e-55);
|
| 166 |
+
EXPECT_NEAR(absl::GetFlag(FLAGS_test_flag_10), 1.234e12f, 1e5f);
|
| 167 |
+
EXPECT_EQ(absl::GetFlag(FLAGS_test_flag_11), "");
|
| 168 |
+
EXPECT_EQ(absl::GetFlag(FLAGS_test_flag_12), absl::Minutes(10));
|
| 169 |
+
EXPECT_EQ(absl::GetFlag(FLAGS_test_flag_13), 200);
|
| 170 |
+
EXPECT_EQ(absl::GetFlag(FLAGS_test_flag_14), CustomUDT{});
|
| 171 |
+
EXPECT_EQ(counter, 2);
|
| 172 |
+
}
|
| 173 |
+
|
| 174 |
+
// --------------------------------------------------------------------
|
| 175 |
+
|
| 176 |
+
TEST_F(ReflectionTest, TestFlagSaverVsUpdateViaReflection) {
|
| 177 |
+
{
|
| 178 |
+
absl::FlagSaver s;
|
| 179 |
+
counter = 0;
|
| 180 |
+
std::string error;
|
| 181 |
+
EXPECT_TRUE(
|
| 182 |
+
absl::FindCommandLineFlag("test_flag_01")->ParseFrom("false", &error))
|
| 183 |
+
<< error;
|
| 184 |
+
EXPECT_TRUE(
|
| 185 |
+
absl::FindCommandLineFlag("test_flag_02")->ParseFrom("-4536", &error))
|
| 186 |
+
<< error;
|
| 187 |
+
EXPECT_TRUE(
|
| 188 |
+
absl::FindCommandLineFlag("test_flag_03")->ParseFrom("111", &error))
|
| 189 |
+
<< error;
|
| 190 |
+
EXPECT_TRUE(
|
| 191 |
+
absl::FindCommandLineFlag("test_flag_04")->ParseFrom("909", &error))
|
| 192 |
+
<< error;
|
| 193 |
+
EXPECT_TRUE(
|
| 194 |
+
absl::FindCommandLineFlag("test_flag_05")->ParseFrom("-2004", &error))
|
| 195 |
+
<< error;
|
| 196 |
+
EXPECT_TRUE(
|
| 197 |
+
absl::FindCommandLineFlag("test_flag_06")->ParseFrom("1000023", &error))
|
| 198 |
+
<< error;
|
| 199 |
+
EXPECT_TRUE(
|
| 200 |
+
absl::FindCommandLineFlag("test_flag_07")->ParseFrom("69305", &error))
|
| 201 |
+
<< error;
|
| 202 |
+
EXPECT_TRUE(absl::FindCommandLineFlag("test_flag_08")
|
| 203 |
+
->ParseFrom("1000000001", &error))
|
| 204 |
+
<< error;
|
| 205 |
+
EXPECT_TRUE(
|
| 206 |
+
absl::FindCommandLineFlag("test_flag_09")->ParseFrom("2.09021", &error))
|
| 207 |
+
<< error;
|
| 208 |
+
EXPECT_TRUE(
|
| 209 |
+
absl::FindCommandLineFlag("test_flag_10")->ParseFrom("-33.1", &error))
|
| 210 |
+
<< error;
|
| 211 |
+
EXPECT_TRUE(
|
| 212 |
+
absl::FindCommandLineFlag("test_flag_11")->ParseFrom("ADD_FOO", &error))
|
| 213 |
+
<< error;
|
| 214 |
+
EXPECT_TRUE(absl::FindCommandLineFlag("test_flag_12")
|
| 215 |
+
->ParseFrom("3h11m16s", &error))
|
| 216 |
+
<< error;
|
| 217 |
+
EXPECT_TRUE(
|
| 218 |
+
absl::FindCommandLineFlag("test_flag_13")->ParseFrom("0", &error))
|
| 219 |
+
<< error;
|
| 220 |
+
EXPECT_TRUE(
|
| 221 |
+
absl::FindCommandLineFlag("test_flag_14")->ParseFrom("10:1", &error))
|
| 222 |
+
<< error;
|
| 223 |
+
}
|
| 224 |
+
|
| 225 |
+
EXPECT_EQ(absl::GetFlag(FLAGS_test_flag_01), true);
|
| 226 |
+
EXPECT_EQ(absl::GetFlag(FLAGS_test_flag_02), 1234);
|
| 227 |
+
EXPECT_EQ(absl::GetFlag(FLAGS_test_flag_03), -34);
|
| 228 |
+
EXPECT_EQ(absl::GetFlag(FLAGS_test_flag_04), 189);
|
| 229 |
+
EXPECT_EQ(absl::GetFlag(FLAGS_test_flag_05), 10765);
|
| 230 |
+
EXPECT_EQ(absl::GetFlag(FLAGS_test_flag_06), 40000);
|
| 231 |
+
EXPECT_EQ(absl::GetFlag(FLAGS_test_flag_07), -1234567);
|
| 232 |
+
EXPECT_EQ(absl::GetFlag(FLAGS_test_flag_08), 9876543);
|
| 233 |
+
EXPECT_NEAR(absl::GetFlag(FLAGS_test_flag_09), -9.876e-50, 1e-55);
|
| 234 |
+
EXPECT_NEAR(absl::GetFlag(FLAGS_test_flag_10), 1.234e12f, 1e5f);
|
| 235 |
+
EXPECT_EQ(absl::GetFlag(FLAGS_test_flag_11), "");
|
| 236 |
+
EXPECT_EQ(absl::GetFlag(FLAGS_test_flag_12), absl::Minutes(10));
|
| 237 |
+
EXPECT_EQ(absl::GetFlag(FLAGS_test_flag_13), 200);
|
| 238 |
+
EXPECT_EQ(absl::GetFlag(FLAGS_test_flag_14), CustomUDT{});
|
| 239 |
+
EXPECT_EQ(counter, 2);
|
| 240 |
+
}
|
| 241 |
+
|
| 242 |
+
// --------------------------------------------------------------------
|
| 243 |
+
|
| 244 |
+
TEST_F(ReflectionTest, TestMultipleFlagSaversInEnclosedScopes) {
|
| 245 |
+
{
|
| 246 |
+
absl::FlagSaver s;
|
| 247 |
+
absl::SetFlag(&FLAGS_test_flag_08, 10);
|
| 248 |
+
EXPECT_EQ(absl::GetFlag(FLAGS_test_flag_08), 10);
|
| 249 |
+
{
|
| 250 |
+
absl::FlagSaver s;
|
| 251 |
+
absl::SetFlag(&FLAGS_test_flag_08, 20);
|
| 252 |
+
EXPECT_EQ(absl::GetFlag(FLAGS_test_flag_08), 20);
|
| 253 |
+
{
|
| 254 |
+
absl::FlagSaver s;
|
| 255 |
+
absl::SetFlag(&FLAGS_test_flag_08, -200);
|
| 256 |
+
EXPECT_EQ(absl::GetFlag(FLAGS_test_flag_08), -200);
|
| 257 |
+
}
|
| 258 |
+
EXPECT_EQ(absl::GetFlag(FLAGS_test_flag_08), 20);
|
| 259 |
+
}
|
| 260 |
+
EXPECT_EQ(absl::GetFlag(FLAGS_test_flag_08), 10);
|
| 261 |
+
}
|
| 262 |
+
EXPECT_EQ(absl::GetFlag(FLAGS_test_flag_08), 9876543);
|
| 263 |
+
}
|
| 264 |
+
|
| 265 |
+
} // namespace
|
weight/_dep/abseil-cpp/absl/flags/usage.cc
ADDED
|
@@ -0,0 +1,66 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
//
|
| 2 |
+
// Copyright 2019 The Abseil Authors.
|
| 3 |
+
//
|
| 4 |
+
// Licensed under the Apache License, Version 2.0 (the "License");
|
| 5 |
+
// you may not use this file except in compliance with the License.
|
| 6 |
+
// You may obtain a copy of the License at
|
| 7 |
+
//
|
| 8 |
+
// https://www.apache.org/licenses/LICENSE-2.0
|
| 9 |
+
//
|
| 10 |
+
// Unless required by applicable law or agreed to in writing, software
|
| 11 |
+
// distributed under the License is distributed on an "AS IS" BASIS,
|
| 12 |
+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
| 13 |
+
// See the License for the specific language governing permissions and
|
| 14 |
+
// limitations under the License.
|
| 15 |
+
#include "absl/flags/usage.h"
|
| 16 |
+
|
| 17 |
+
#include <stdlib.h>
|
| 18 |
+
|
| 19 |
+
#include <string>
|
| 20 |
+
|
| 21 |
+
#include "absl/base/attributes.h"
|
| 22 |
+
#include "absl/base/config.h"
|
| 23 |
+
#include "absl/base/const_init.h"
|
| 24 |
+
#include "absl/base/internal/raw_logging.h"
|
| 25 |
+
#include "absl/base/thread_annotations.h"
|
| 26 |
+
#include "absl/flags/internal/usage.h"
|
| 27 |
+
#include "absl/strings/string_view.h"
|
| 28 |
+
#include "absl/synchronization/mutex.h"
|
| 29 |
+
|
| 30 |
+
namespace absl {
|
| 31 |
+
ABSL_NAMESPACE_BEGIN
|
| 32 |
+
namespace flags_internal {
|
| 33 |
+
namespace {
|
| 34 |
+
ABSL_CONST_INIT absl::Mutex usage_message_guard(absl::kConstInit);
|
| 35 |
+
ABSL_CONST_INIT std::string* program_usage_message
|
| 36 |
+
ABSL_GUARDED_BY(usage_message_guard) = nullptr;
|
| 37 |
+
} // namespace
|
| 38 |
+
} // namespace flags_internal
|
| 39 |
+
|
| 40 |
+
// --------------------------------------------------------------------
|
| 41 |
+
// Sets the "usage" message to be used by help reporting routines.
|
| 42 |
+
void SetProgramUsageMessage(absl::string_view new_usage_message) {
|
| 43 |
+
absl::MutexLock l(&flags_internal::usage_message_guard);
|
| 44 |
+
|
| 45 |
+
if (flags_internal::program_usage_message != nullptr) {
|
| 46 |
+
ABSL_INTERNAL_LOG(FATAL, "SetProgramUsageMessage() called twice.");
|
| 47 |
+
std::exit(1);
|
| 48 |
+
}
|
| 49 |
+
|
| 50 |
+
flags_internal::program_usage_message = new std::string(new_usage_message);
|
| 51 |
+
}
|
| 52 |
+
|
| 53 |
+
// --------------------------------------------------------------------
|
| 54 |
+
// Returns the usage message set by SetProgramUsageMessage().
|
| 55 |
+
// Note: We able to return string_view here only because calling
|
| 56 |
+
// SetProgramUsageMessage twice is prohibited.
|
| 57 |
+
absl::string_view ProgramUsageMessage() {
|
| 58 |
+
absl::MutexLock l(&flags_internal::usage_message_guard);
|
| 59 |
+
|
| 60 |
+
return flags_internal::program_usage_message != nullptr
|
| 61 |
+
? absl::string_view(*flags_internal::program_usage_message)
|
| 62 |
+
: "Warning: SetProgramUsageMessage() never called";
|
| 63 |
+
}
|
| 64 |
+
|
| 65 |
+
ABSL_NAMESPACE_END
|
| 66 |
+
} // namespace absl
|
weight/_dep/abseil-cpp/absl/flags/usage_config.cc
ADDED
|
@@ -0,0 +1,165 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
//
|
| 2 |
+
// Copyright 2019 The Abseil Authors.
|
| 3 |
+
//
|
| 4 |
+
// Licensed under the Apache License, Version 2.0 (the "License");
|
| 5 |
+
// you may not use this file except in compliance with the License.
|
| 6 |
+
// You may obtain a copy of the License at
|
| 7 |
+
//
|
| 8 |
+
// https://www.apache.org/licenses/LICENSE-2.0
|
| 9 |
+
//
|
| 10 |
+
// Unless required by applicable law or agreed to in writing, software
|
| 11 |
+
// distributed under the License is distributed on an "AS IS" BASIS,
|
| 12 |
+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
| 13 |
+
// See the License for the specific language governing permissions and
|
| 14 |
+
// limitations under the License.
|
| 15 |
+
|
| 16 |
+
#include "absl/flags/usage_config.h"
|
| 17 |
+
|
| 18 |
+
#include <functional>
|
| 19 |
+
#include <iostream>
|
| 20 |
+
#include <string>
|
| 21 |
+
|
| 22 |
+
#include "absl/base/attributes.h"
|
| 23 |
+
#include "absl/base/config.h"
|
| 24 |
+
#include "absl/base/const_init.h"
|
| 25 |
+
#include "absl/base/thread_annotations.h"
|
| 26 |
+
#include "absl/flags/internal/path_util.h"
|
| 27 |
+
#include "absl/flags/internal/program_name.h"
|
| 28 |
+
#include "absl/strings/match.h"
|
| 29 |
+
#include "absl/strings/string_view.h"
|
| 30 |
+
#include "absl/strings/strip.h"
|
| 31 |
+
#include "absl/synchronization/mutex.h"
|
| 32 |
+
|
| 33 |
+
extern "C" {
|
| 34 |
+
|
| 35 |
+
// Additional report of fatal usage error message before we std::exit. Error is
|
| 36 |
+
// fatal if is_fatal argument to ReportUsageError is true.
|
| 37 |
+
ABSL_ATTRIBUTE_WEAK void ABSL_INTERNAL_C_SYMBOL(
|
| 38 |
+
AbslInternalReportFatalUsageError)(absl::string_view) {}
|
| 39 |
+
|
| 40 |
+
} // extern "C"
|
| 41 |
+
|
| 42 |
+
namespace absl {
|
| 43 |
+
ABSL_NAMESPACE_BEGIN
|
| 44 |
+
namespace flags_internal {
|
| 45 |
+
|
| 46 |
+
namespace {
|
| 47 |
+
|
| 48 |
+
// --------------------------------------------------------------------
|
| 49 |
+
// Returns true if flags defined in the filename should be reported with
|
| 50 |
+
// -helpshort flag.
|
| 51 |
+
|
| 52 |
+
bool ContainsHelpshortFlags(absl::string_view filename) {
|
| 53 |
+
// By default we only want flags in binary's main. We expect the main
|
| 54 |
+
// routine to reside in <program>.cc or <program>-main.cc or
|
| 55 |
+
// <program>_main.cc, where the <program> is the name of the binary
|
| 56 |
+
// (without .exe on Windows).
|
| 57 |
+
auto suffix = flags_internal::Basename(filename);
|
| 58 |
+
auto program_name = flags_internal::ShortProgramInvocationName();
|
| 59 |
+
absl::string_view program_name_ref = program_name;
|
| 60 |
+
#if defined(_WIN32)
|
| 61 |
+
absl::ConsumeSuffix(&program_name_ref, ".exe");
|
| 62 |
+
#endif
|
| 63 |
+
if (!absl::ConsumePrefix(&suffix, program_name_ref))
|
| 64 |
+
return false;
|
| 65 |
+
return absl::StartsWith(suffix, ".") || absl::StartsWith(suffix, "-main.") ||
|
| 66 |
+
absl::StartsWith(suffix, "_main.");
|
| 67 |
+
}
|
| 68 |
+
|
| 69 |
+
// --------------------------------------------------------------------
|
| 70 |
+
// Returns true if flags defined in the filename should be reported with
|
| 71 |
+
// -helppackage flag.
|
| 72 |
+
|
| 73 |
+
bool ContainsHelppackageFlags(absl::string_view filename) {
|
| 74 |
+
// TODO(rogeeff): implement properly when registry is available.
|
| 75 |
+
return ContainsHelpshortFlags(filename);
|
| 76 |
+
}
|
| 77 |
+
|
| 78 |
+
// --------------------------------------------------------------------
|
| 79 |
+
// Generates program version information into supplied output.
|
| 80 |
+
|
| 81 |
+
std::string VersionString() {
|
| 82 |
+
std::string version_str(flags_internal::ShortProgramInvocationName());
|
| 83 |
+
|
| 84 |
+
version_str += "\n";
|
| 85 |
+
|
| 86 |
+
#if !defined(NDEBUG)
|
| 87 |
+
version_str += "Debug build (NDEBUG not #defined)\n";
|
| 88 |
+
#endif
|
| 89 |
+
|
| 90 |
+
return version_str;
|
| 91 |
+
}
|
| 92 |
+
|
| 93 |
+
// --------------------------------------------------------------------
|
| 94 |
+
// Normalizes the filename specific to the build system/filesystem used.
|
| 95 |
+
|
| 96 |
+
std::string NormalizeFilename(absl::string_view filename) {
|
| 97 |
+
// Skip any leading slashes
|
| 98 |
+
auto pos = filename.find_first_not_of("\\/");
|
| 99 |
+
if (pos == absl::string_view::npos) return "";
|
| 100 |
+
|
| 101 |
+
filename.remove_prefix(pos);
|
| 102 |
+
return std::string(filename);
|
| 103 |
+
}
|
| 104 |
+
|
| 105 |
+
// --------------------------------------------------------------------
|
| 106 |
+
|
| 107 |
+
ABSL_CONST_INIT absl::Mutex custom_usage_config_guard(absl::kConstInit);
|
| 108 |
+
ABSL_CONST_INIT FlagsUsageConfig* custom_usage_config
|
| 109 |
+
ABSL_GUARDED_BY(custom_usage_config_guard) = nullptr;
|
| 110 |
+
|
| 111 |
+
} // namespace
|
| 112 |
+
|
| 113 |
+
FlagsUsageConfig GetUsageConfig() {
|
| 114 |
+
absl::MutexLock l(&custom_usage_config_guard);
|
| 115 |
+
|
| 116 |
+
if (custom_usage_config) return *custom_usage_config;
|
| 117 |
+
|
| 118 |
+
FlagsUsageConfig default_config;
|
| 119 |
+
default_config.contains_helpshort_flags = &ContainsHelpshortFlags;
|
| 120 |
+
default_config.contains_help_flags = &ContainsHelppackageFlags;
|
| 121 |
+
default_config.contains_helppackage_flags = &ContainsHelppackageFlags;
|
| 122 |
+
default_config.version_string = &VersionString;
|
| 123 |
+
default_config.normalize_filename = &NormalizeFilename;
|
| 124 |
+
|
| 125 |
+
return default_config;
|
| 126 |
+
}
|
| 127 |
+
|
| 128 |
+
void ReportUsageError(absl::string_view msg, bool is_fatal) {
|
| 129 |
+
std::cerr << "ERROR: " << msg << std::endl;
|
| 130 |
+
|
| 131 |
+
if (is_fatal) {
|
| 132 |
+
ABSL_INTERNAL_C_SYMBOL(AbslInternalReportFatalUsageError)(msg);
|
| 133 |
+
}
|
| 134 |
+
}
|
| 135 |
+
|
| 136 |
+
} // namespace flags_internal
|
| 137 |
+
|
| 138 |
+
void SetFlagsUsageConfig(FlagsUsageConfig usage_config) {
|
| 139 |
+
absl::MutexLock l(&flags_internal::custom_usage_config_guard);
|
| 140 |
+
|
| 141 |
+
if (!usage_config.contains_helpshort_flags)
|
| 142 |
+
usage_config.contains_helpshort_flags =
|
| 143 |
+
flags_internal::ContainsHelpshortFlags;
|
| 144 |
+
|
| 145 |
+
if (!usage_config.contains_help_flags)
|
| 146 |
+
usage_config.contains_help_flags = flags_internal::ContainsHelppackageFlags;
|
| 147 |
+
|
| 148 |
+
if (!usage_config.contains_helppackage_flags)
|
| 149 |
+
usage_config.contains_helppackage_flags =
|
| 150 |
+
flags_internal::ContainsHelppackageFlags;
|
| 151 |
+
|
| 152 |
+
if (!usage_config.version_string)
|
| 153 |
+
usage_config.version_string = flags_internal::VersionString;
|
| 154 |
+
|
| 155 |
+
if (!usage_config.normalize_filename)
|
| 156 |
+
usage_config.normalize_filename = flags_internal::NormalizeFilename;
|
| 157 |
+
|
| 158 |
+
if (flags_internal::custom_usage_config)
|
| 159 |
+
*flags_internal::custom_usage_config = usage_config;
|
| 160 |
+
else
|
| 161 |
+
flags_internal::custom_usage_config = new FlagsUsageConfig(usage_config);
|
| 162 |
+
}
|
| 163 |
+
|
| 164 |
+
ABSL_NAMESPACE_END
|
| 165 |
+
} // namespace absl
|
weight/_dep/abseil-cpp/absl/flags/usage_config.h
ADDED
|
@@ -0,0 +1,135 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
//
|
| 2 |
+
// Copyright 2019 The Abseil Authors.
|
| 3 |
+
//
|
| 4 |
+
// Licensed under the Apache License, Version 2.0 (the "License");
|
| 5 |
+
// you may not use this file except in compliance with the License.
|
| 6 |
+
// You may obtain a copy of the License at
|
| 7 |
+
//
|
| 8 |
+
// https://www.apache.org/licenses/LICENSE-2.0
|
| 9 |
+
//
|
| 10 |
+
// Unless required by applicable law or agreed to in writing, software
|
| 11 |
+
// distributed under the License is distributed on an "AS IS" BASIS,
|
| 12 |
+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
| 13 |
+
// See the License for the specific language governing permissions and
|
| 14 |
+
// limitations under the License.
|
| 15 |
+
//
|
| 16 |
+
// -----------------------------------------------------------------------------
|
| 17 |
+
// File: usage_config.h
|
| 18 |
+
// -----------------------------------------------------------------------------
|
| 19 |
+
//
|
| 20 |
+
// This file defines the main usage reporting configuration interfaces and
|
| 21 |
+
// documents Abseil's supported built-in usage flags. If these flags are found
|
| 22 |
+
// when parsing a command-line, Abseil will exit the program and display
|
| 23 |
+
// appropriate help messages.
|
| 24 |
+
#ifndef ABSL_FLAGS_USAGE_CONFIG_H_
|
| 25 |
+
#define ABSL_FLAGS_USAGE_CONFIG_H_
|
| 26 |
+
|
| 27 |
+
#include <functional>
|
| 28 |
+
#include <string>
|
| 29 |
+
|
| 30 |
+
#include "absl/base/config.h"
|
| 31 |
+
#include "absl/strings/string_view.h"
|
| 32 |
+
|
| 33 |
+
// -----------------------------------------------------------------------------
|
| 34 |
+
// Built-in Usage Flags
|
| 35 |
+
// -----------------------------------------------------------------------------
|
| 36 |
+
//
|
| 37 |
+
// Abseil supports the following built-in usage flags. When passed, these flags
|
| 38 |
+
// exit the program and :
|
| 39 |
+
//
|
| 40 |
+
// * --help
|
| 41 |
+
// Shows help on important flags for this binary
|
| 42 |
+
// * --helpfull
|
| 43 |
+
// Shows help on all flags
|
| 44 |
+
// * --helpshort
|
| 45 |
+
// Shows help on only the main module for this program
|
| 46 |
+
// * --helppackage
|
| 47 |
+
// Shows help on all modules in the main package
|
| 48 |
+
// * --version
|
| 49 |
+
// Shows the version and build info for this binary and exits
|
| 50 |
+
// * --only_check_args
|
| 51 |
+
// Exits after checking all flags
|
| 52 |
+
// * --helpon
|
| 53 |
+
// Shows help on the modules named by this flag value
|
| 54 |
+
// * --helpmatch
|
| 55 |
+
// Shows help on modules whose name contains the specified substring
|
| 56 |
+
|
| 57 |
+
namespace absl {
|
| 58 |
+
ABSL_NAMESPACE_BEGIN
|
| 59 |
+
|
| 60 |
+
namespace flags_internal {
|
| 61 |
+
using FlagKindFilter = std::function<bool (absl::string_view)>;
|
| 62 |
+
} // namespace flags_internal
|
| 63 |
+
|
| 64 |
+
// FlagsUsageConfig
|
| 65 |
+
//
|
| 66 |
+
// This structure contains the collection of callbacks for changing the behavior
|
| 67 |
+
// of the usage reporting routines in Abseil Flags.
|
| 68 |
+
struct FlagsUsageConfig {
|
| 69 |
+
// Returns true if flags defined in the given source code file should be
|
| 70 |
+
// reported with --helpshort flag. For example, if the file
|
| 71 |
+
// "path/to/my/code.cc" defines the flag "--my_flag", and
|
| 72 |
+
// contains_helpshort_flags("path/to/my/code.cc") returns true, invoking the
|
| 73 |
+
// program with --helpshort will include information about --my_flag in the
|
| 74 |
+
// program output.
|
| 75 |
+
flags_internal::FlagKindFilter contains_helpshort_flags;
|
| 76 |
+
|
| 77 |
+
// Returns true if flags defined in the filename should be reported with
|
| 78 |
+
// --help flag. For example, if the file
|
| 79 |
+
// "path/to/my/code.cc" defines the flag "--my_flag", and
|
| 80 |
+
// contains_help_flags("path/to/my/code.cc") returns true, invoking the
|
| 81 |
+
// program with --help will include information about --my_flag in the
|
| 82 |
+
// program output.
|
| 83 |
+
flags_internal::FlagKindFilter contains_help_flags;
|
| 84 |
+
|
| 85 |
+
// Returns true if flags defined in the filename should be reported with
|
| 86 |
+
// --helppackage flag. For example, if the file
|
| 87 |
+
// "path/to/my/code.cc" defines the flag "--my_flag", and
|
| 88 |
+
// contains_helppackage_flags("path/to/my/code.cc") returns true, invoking the
|
| 89 |
+
// program with --helppackage will include information about --my_flag in the
|
| 90 |
+
// program output.
|
| 91 |
+
flags_internal::FlagKindFilter contains_helppackage_flags;
|
| 92 |
+
|
| 93 |
+
// Generates string containing program version. This is the string reported
|
| 94 |
+
// when user specifies --version in a command line.
|
| 95 |
+
std::function<std::string()> version_string;
|
| 96 |
+
|
| 97 |
+
// Normalizes the filename specific to the build system/filesystem used. This
|
| 98 |
+
// routine is used when we report the information about the flag definition
|
| 99 |
+
// location. For instance, if your build resides at some location you do not
|
| 100 |
+
// want to expose in the usage output, you can trim it to show only relevant
|
| 101 |
+
// part.
|
| 102 |
+
// For example:
|
| 103 |
+
// normalize_filename("/my_company/some_long_path/src/project/file.cc")
|
| 104 |
+
// might produce
|
| 105 |
+
// "project/file.cc".
|
| 106 |
+
std::function<std::string(absl::string_view)> normalize_filename;
|
| 107 |
+
};
|
| 108 |
+
|
| 109 |
+
// SetFlagsUsageConfig()
|
| 110 |
+
//
|
| 111 |
+
// Sets the usage reporting configuration callbacks. If any of the callbacks are
|
| 112 |
+
// not set in usage_config instance, then the default value of the callback is
|
| 113 |
+
// used.
|
| 114 |
+
void SetFlagsUsageConfig(FlagsUsageConfig usage_config);
|
| 115 |
+
|
| 116 |
+
namespace flags_internal {
|
| 117 |
+
|
| 118 |
+
FlagsUsageConfig GetUsageConfig();
|
| 119 |
+
|
| 120 |
+
void ReportUsageError(absl::string_view msg, bool is_fatal);
|
| 121 |
+
|
| 122 |
+
} // namespace flags_internal
|
| 123 |
+
ABSL_NAMESPACE_END
|
| 124 |
+
} // namespace absl
|
| 125 |
+
|
| 126 |
+
extern "C" {
|
| 127 |
+
|
| 128 |
+
// Additional report of fatal usage error message before we std::exit. Error is
|
| 129 |
+
// fatal if is_fatal argument to ReportUsageError is true.
|
| 130 |
+
void ABSL_INTERNAL_C_SYMBOL(AbslInternalReportFatalUsageError)(
|
| 131 |
+
absl::string_view);
|
| 132 |
+
|
| 133 |
+
} // extern "C"
|
| 134 |
+
|
| 135 |
+
#endif // ABSL_FLAGS_USAGE_CONFIG_H_
|
weight/_dep/abseil-cpp/absl/flags/usage_config_test.cc
ADDED
|
@@ -0,0 +1,205 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
//
|
| 2 |
+
// Copyright 2019 The Abseil Authors.
|
| 3 |
+
//
|
| 4 |
+
// Licensed under the Apache License, Version 2.0 (the "License");
|
| 5 |
+
// you may not use this file except in compliance with the License.
|
| 6 |
+
// You may obtain a copy of the License at
|
| 7 |
+
//
|
| 8 |
+
// https://www.apache.org/licenses/LICENSE-2.0
|
| 9 |
+
//
|
| 10 |
+
// Unless required by applicable law or agreed to in writing, software
|
| 11 |
+
// distributed under the License is distributed on an "AS IS" BASIS,
|
| 12 |
+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
| 13 |
+
// See the License for the specific language governing permissions and
|
| 14 |
+
// limitations under the License.
|
| 15 |
+
|
| 16 |
+
#include "absl/flags/usage_config.h"
|
| 17 |
+
|
| 18 |
+
#include <string>
|
| 19 |
+
|
| 20 |
+
#include "gtest/gtest.h"
|
| 21 |
+
#include "absl/flags/internal/path_util.h"
|
| 22 |
+
#include "absl/flags/internal/program_name.h"
|
| 23 |
+
#include "absl/strings/match.h"
|
| 24 |
+
#include "absl/strings/string_view.h"
|
| 25 |
+
|
| 26 |
+
namespace {
|
| 27 |
+
|
| 28 |
+
class FlagsUsageConfigTest : public testing::Test {
|
| 29 |
+
protected:
|
| 30 |
+
void SetUp() override {
|
| 31 |
+
// Install Default config for the use on this unit test.
|
| 32 |
+
// Binary may install a custom config before tests are run.
|
| 33 |
+
absl::FlagsUsageConfig default_config;
|
| 34 |
+
absl::SetFlagsUsageConfig(default_config);
|
| 35 |
+
}
|
| 36 |
+
};
|
| 37 |
+
|
| 38 |
+
namespace flags = absl::flags_internal;
|
| 39 |
+
|
| 40 |
+
bool TstContainsHelpshortFlags(absl::string_view f) {
|
| 41 |
+
return absl::StartsWith(flags::Basename(f), "progname.");
|
| 42 |
+
}
|
| 43 |
+
|
| 44 |
+
bool TstContainsHelppackageFlags(absl::string_view f) {
|
| 45 |
+
return absl::EndsWith(flags::Package(f), "aaa/");
|
| 46 |
+
}
|
| 47 |
+
|
| 48 |
+
bool TstContainsHelpFlags(absl::string_view f) {
|
| 49 |
+
return absl::EndsWith(flags::Package(f), "zzz/");
|
| 50 |
+
}
|
| 51 |
+
|
| 52 |
+
std::string TstVersionString() { return "program 1.0.0"; }
|
| 53 |
+
|
| 54 |
+
std::string TstNormalizeFilename(absl::string_view filename) {
|
| 55 |
+
return std::string(filename.substr(2));
|
| 56 |
+
}
|
| 57 |
+
|
| 58 |
+
void TstReportUsageMessage(absl::string_view msg) {}
|
| 59 |
+
|
| 60 |
+
// --------------------------------------------------------------------
|
| 61 |
+
|
| 62 |
+
TEST_F(FlagsUsageConfigTest, TestGetSetFlagsUsageConfig) {
|
| 63 |
+
EXPECT_TRUE(flags::GetUsageConfig().contains_helpshort_flags);
|
| 64 |
+
EXPECT_TRUE(flags::GetUsageConfig().contains_help_flags);
|
| 65 |
+
EXPECT_TRUE(flags::GetUsageConfig().contains_helppackage_flags);
|
| 66 |
+
EXPECT_TRUE(flags::GetUsageConfig().version_string);
|
| 67 |
+
EXPECT_TRUE(flags::GetUsageConfig().normalize_filename);
|
| 68 |
+
|
| 69 |
+
absl::FlagsUsageConfig empty_config;
|
| 70 |
+
empty_config.contains_helpshort_flags = &TstContainsHelpshortFlags;
|
| 71 |
+
empty_config.contains_help_flags = &TstContainsHelpFlags;
|
| 72 |
+
empty_config.contains_helppackage_flags = &TstContainsHelppackageFlags;
|
| 73 |
+
empty_config.version_string = &TstVersionString;
|
| 74 |
+
empty_config.normalize_filename = &TstNormalizeFilename;
|
| 75 |
+
absl::SetFlagsUsageConfig(empty_config);
|
| 76 |
+
|
| 77 |
+
EXPECT_TRUE(flags::GetUsageConfig().contains_helpshort_flags);
|
| 78 |
+
EXPECT_TRUE(flags::GetUsageConfig().contains_help_flags);
|
| 79 |
+
EXPECT_TRUE(flags::GetUsageConfig().contains_helppackage_flags);
|
| 80 |
+
EXPECT_TRUE(flags::GetUsageConfig().version_string);
|
| 81 |
+
EXPECT_TRUE(flags::GetUsageConfig().normalize_filename);
|
| 82 |
+
}
|
| 83 |
+
|
| 84 |
+
// --------------------------------------------------------------------
|
| 85 |
+
|
| 86 |
+
TEST_F(FlagsUsageConfigTest, TestContainsHelpshortFlags) {
|
| 87 |
+
#if defined(_WIN32)
|
| 88 |
+
flags::SetProgramInvocationName("usage_config_test.exe");
|
| 89 |
+
#else
|
| 90 |
+
flags::SetProgramInvocationName("usage_config_test");
|
| 91 |
+
#endif
|
| 92 |
+
|
| 93 |
+
auto config = flags::GetUsageConfig();
|
| 94 |
+
EXPECT_TRUE(config.contains_helpshort_flags("adir/cd/usage_config_test.cc"));
|
| 95 |
+
EXPECT_TRUE(
|
| 96 |
+
config.contains_helpshort_flags("aaaa/usage_config_test-main.cc"));
|
| 97 |
+
EXPECT_TRUE(config.contains_helpshort_flags("abc/usage_config_test_main.cc"));
|
| 98 |
+
EXPECT_FALSE(config.contains_helpshort_flags("usage_config_main.cc"));
|
| 99 |
+
|
| 100 |
+
absl::FlagsUsageConfig empty_config;
|
| 101 |
+
empty_config.contains_helpshort_flags = &TstContainsHelpshortFlags;
|
| 102 |
+
absl::SetFlagsUsageConfig(empty_config);
|
| 103 |
+
|
| 104 |
+
EXPECT_TRUE(
|
| 105 |
+
flags::GetUsageConfig().contains_helpshort_flags("aaa/progname.cpp"));
|
| 106 |
+
EXPECT_FALSE(
|
| 107 |
+
flags::GetUsageConfig().contains_helpshort_flags("aaa/progmane.cpp"));
|
| 108 |
+
}
|
| 109 |
+
|
| 110 |
+
// --------------------------------------------------------------------
|
| 111 |
+
|
| 112 |
+
TEST_F(FlagsUsageConfigTest, TestContainsHelpFlags) {
|
| 113 |
+
flags::SetProgramInvocationName("usage_config_test");
|
| 114 |
+
|
| 115 |
+
auto config = flags::GetUsageConfig();
|
| 116 |
+
EXPECT_TRUE(config.contains_help_flags("zzz/usage_config_test.cc"));
|
| 117 |
+
EXPECT_TRUE(
|
| 118 |
+
config.contains_help_flags("bdir/a/zzz/usage_config_test-main.cc"));
|
| 119 |
+
EXPECT_TRUE(
|
| 120 |
+
config.contains_help_flags("//aqse/zzz/usage_config_test_main.cc"));
|
| 121 |
+
EXPECT_FALSE(config.contains_help_flags("zzz/aa/usage_config_main.cc"));
|
| 122 |
+
|
| 123 |
+
absl::FlagsUsageConfig empty_config;
|
| 124 |
+
empty_config.contains_help_flags = &TstContainsHelpFlags;
|
| 125 |
+
absl::SetFlagsUsageConfig(empty_config);
|
| 126 |
+
|
| 127 |
+
EXPECT_TRUE(flags::GetUsageConfig().contains_help_flags("zzz/main-body.c"));
|
| 128 |
+
EXPECT_FALSE(
|
| 129 |
+
flags::GetUsageConfig().contains_help_flags("zzz/dir/main-body.c"));
|
| 130 |
+
}
|
| 131 |
+
|
| 132 |
+
// --------------------------------------------------------------------
|
| 133 |
+
|
| 134 |
+
TEST_F(FlagsUsageConfigTest, TestContainsHelppackageFlags) {
|
| 135 |
+
flags::SetProgramInvocationName("usage_config_test");
|
| 136 |
+
|
| 137 |
+
auto config = flags::GetUsageConfig();
|
| 138 |
+
EXPECT_TRUE(config.contains_helppackage_flags("aaa/usage_config_test.cc"));
|
| 139 |
+
EXPECT_TRUE(
|
| 140 |
+
config.contains_helppackage_flags("bbdir/aaa/usage_config_test-main.cc"));
|
| 141 |
+
EXPECT_TRUE(config.contains_helppackage_flags(
|
| 142 |
+
"//aqswde/aaa/usage_config_test_main.cc"));
|
| 143 |
+
EXPECT_FALSE(config.contains_helppackage_flags("aadir/usage_config_main.cc"));
|
| 144 |
+
|
| 145 |
+
absl::FlagsUsageConfig empty_config;
|
| 146 |
+
empty_config.contains_helppackage_flags = &TstContainsHelppackageFlags;
|
| 147 |
+
absl::SetFlagsUsageConfig(empty_config);
|
| 148 |
+
|
| 149 |
+
EXPECT_TRUE(
|
| 150 |
+
flags::GetUsageConfig().contains_helppackage_flags("aaa/main-body.c"));
|
| 151 |
+
EXPECT_FALSE(
|
| 152 |
+
flags::GetUsageConfig().contains_helppackage_flags("aadir/main-body.c"));
|
| 153 |
+
}
|
| 154 |
+
|
| 155 |
+
// --------------------------------------------------------------------
|
| 156 |
+
|
| 157 |
+
TEST_F(FlagsUsageConfigTest, TestVersionString) {
|
| 158 |
+
flags::SetProgramInvocationName("usage_config_test");
|
| 159 |
+
|
| 160 |
+
#ifdef NDEBUG
|
| 161 |
+
std::string expected_output = "usage_config_test\n";
|
| 162 |
+
#else
|
| 163 |
+
std::string expected_output =
|
| 164 |
+
"usage_config_test\nDebug build (NDEBUG not #defined)\n";
|
| 165 |
+
#endif
|
| 166 |
+
|
| 167 |
+
EXPECT_EQ(flags::GetUsageConfig().version_string(), expected_output);
|
| 168 |
+
|
| 169 |
+
absl::FlagsUsageConfig empty_config;
|
| 170 |
+
empty_config.version_string = &TstVersionString;
|
| 171 |
+
absl::SetFlagsUsageConfig(empty_config);
|
| 172 |
+
|
| 173 |
+
EXPECT_EQ(flags::GetUsageConfig().version_string(), "program 1.0.0");
|
| 174 |
+
}
|
| 175 |
+
|
| 176 |
+
// --------------------------------------------------------------------
|
| 177 |
+
|
| 178 |
+
TEST_F(FlagsUsageConfigTest, TestNormalizeFilename) {
|
| 179 |
+
// This tests the default implementation.
|
| 180 |
+
EXPECT_EQ(flags::GetUsageConfig().normalize_filename("a/a.cc"), "a/a.cc");
|
| 181 |
+
EXPECT_EQ(flags::GetUsageConfig().normalize_filename("/a/a.cc"), "a/a.cc");
|
| 182 |
+
EXPECT_EQ(flags::GetUsageConfig().normalize_filename("///a/a.cc"), "a/a.cc");
|
| 183 |
+
EXPECT_EQ(flags::GetUsageConfig().normalize_filename("/"), "");
|
| 184 |
+
|
| 185 |
+
// This tests that the custom implementation is called.
|
| 186 |
+
absl::FlagsUsageConfig empty_config;
|
| 187 |
+
empty_config.normalize_filename = &TstNormalizeFilename;
|
| 188 |
+
absl::SetFlagsUsageConfig(empty_config);
|
| 189 |
+
|
| 190 |
+
EXPECT_EQ(flags::GetUsageConfig().normalize_filename("a/a.cc"), "a.cc");
|
| 191 |
+
EXPECT_EQ(flags::GetUsageConfig().normalize_filename("aaa/a.cc"), "a/a.cc");
|
| 192 |
+
|
| 193 |
+
// This tests that the default implementation is called.
|
| 194 |
+
empty_config.normalize_filename = nullptr;
|
| 195 |
+
absl::SetFlagsUsageConfig(empty_config);
|
| 196 |
+
|
| 197 |
+
EXPECT_EQ(flags::GetUsageConfig().normalize_filename("a/a.cc"), "a/a.cc");
|
| 198 |
+
EXPECT_EQ(flags::GetUsageConfig().normalize_filename("/a/a.cc"), "a/a.cc");
|
| 199 |
+
EXPECT_EQ(flags::GetUsageConfig().normalize_filename("///a/a.cc"), "a/a.cc");
|
| 200 |
+
EXPECT_EQ(flags::GetUsageConfig().normalize_filename("\\a\\a.cc"), "a\\a.cc");
|
| 201 |
+
EXPECT_EQ(flags::GetUsageConfig().normalize_filename("//"), "");
|
| 202 |
+
EXPECT_EQ(flags::GetUsageConfig().normalize_filename("\\\\"), "");
|
| 203 |
+
}
|
| 204 |
+
|
| 205 |
+
} // namespace
|
weight/_dep/abseil-cpp/absl/strings/cord_test.cc
ADDED
|
The diff for this file is too large to render.
See raw diff
|
|
|
weight/_dep/abseil-cpp/absl/strings/escaping.cc
ADDED
|
@@ -0,0 +1,957 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
// Copyright 2017 The Abseil Authors.
|
| 2 |
+
//
|
| 3 |
+
// Licensed under the Apache License, Version 2.0 (the "License");
|
| 4 |
+
// you may not use this file except in compliance with the License.
|
| 5 |
+
// You may obtain a copy of the License at
|
| 6 |
+
//
|
| 7 |
+
// https://www.apache.org/licenses/LICENSE-2.0
|
| 8 |
+
//
|
| 9 |
+
// Unless required by applicable law or agreed to in writing, software
|
| 10 |
+
// distributed under the License is distributed on an "AS IS" BASIS,
|
| 11 |
+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
| 12 |
+
// See the License for the specific language governing permissions and
|
| 13 |
+
// limitations under the License.
|
| 14 |
+
|
| 15 |
+
#include "absl/strings/escaping.h"
|
| 16 |
+
|
| 17 |
+
#include <algorithm>
|
| 18 |
+
#include <cassert>
|
| 19 |
+
#include <cstddef>
|
| 20 |
+
#include <cstdint>
|
| 21 |
+
#include <cstring>
|
| 22 |
+
#include <limits>
|
| 23 |
+
#include <string>
|
| 24 |
+
|
| 25 |
+
#include "absl/base/config.h"
|
| 26 |
+
#include "absl/base/internal/raw_logging.h"
|
| 27 |
+
#include "absl/base/internal/unaligned_access.h"
|
| 28 |
+
#include "absl/strings/ascii.h"
|
| 29 |
+
#include "absl/strings/charset.h"
|
| 30 |
+
#include "absl/strings/internal/escaping.h"
|
| 31 |
+
#include "absl/strings/internal/resize_uninitialized.h"
|
| 32 |
+
#include "absl/strings/internal/utf8.h"
|
| 33 |
+
#include "absl/strings/numbers.h"
|
| 34 |
+
#include "absl/strings/str_cat.h"
|
| 35 |
+
#include "absl/strings/string_view.h"
|
| 36 |
+
|
| 37 |
+
namespace absl {
|
| 38 |
+
ABSL_NAMESPACE_BEGIN
|
| 39 |
+
namespace {
|
| 40 |
+
|
| 41 |
+
// These are used for the leave_nulls_escaped argument to CUnescapeInternal().
|
| 42 |
+
constexpr bool kUnescapeNulls = false;
|
| 43 |
+
|
| 44 |
+
inline bool is_octal_digit(char c) { return ('0' <= c) && (c <= '7'); }
|
| 45 |
+
|
| 46 |
+
inline unsigned int hex_digit_to_int(char c) {
|
| 47 |
+
static_assert('0' == 0x30 && 'A' == 0x41 && 'a' == 0x61,
|
| 48 |
+
"Character set must be ASCII.");
|
| 49 |
+
assert(absl::ascii_isxdigit(static_cast<unsigned char>(c)));
|
| 50 |
+
unsigned int x = static_cast<unsigned char>(c);
|
| 51 |
+
if (x > '9') {
|
| 52 |
+
x += 9;
|
| 53 |
+
}
|
| 54 |
+
return x & 0xf;
|
| 55 |
+
}
|
| 56 |
+
|
| 57 |
+
inline bool IsSurrogate(char32_t c, absl::string_view src, std::string* error) {
|
| 58 |
+
if (c >= 0xD800 && c <= 0xDFFF) {
|
| 59 |
+
if (error) {
|
| 60 |
+
*error = absl::StrCat("invalid surrogate character (0xD800-DFFF): \\",
|
| 61 |
+
src);
|
| 62 |
+
}
|
| 63 |
+
return true;
|
| 64 |
+
}
|
| 65 |
+
return false;
|
| 66 |
+
}
|
| 67 |
+
|
| 68 |
+
// ----------------------------------------------------------------------
|
| 69 |
+
// CUnescapeInternal()
|
| 70 |
+
// Implements both CUnescape() and CUnescapeForNullTerminatedString().
|
| 71 |
+
//
|
| 72 |
+
// Unescapes C escape sequences and is the reverse of CEscape().
|
| 73 |
+
//
|
| 74 |
+
// If 'source' is valid, stores the unescaped string and its size in
|
| 75 |
+
// 'dest' and 'dest_len' respectively, and returns true. Otherwise
|
| 76 |
+
// returns false and optionally stores the error description in
|
| 77 |
+
// 'error'. Set 'error' to nullptr to disable error reporting.
|
| 78 |
+
//
|
| 79 |
+
// 'dest' should point to a buffer that is at least as big as 'source'.
|
| 80 |
+
// 'source' and 'dest' may be the same.
|
| 81 |
+
//
|
| 82 |
+
// NOTE: any changes to this function must also be reflected in the older
|
| 83 |
+
// UnescapeCEscapeSequences().
|
| 84 |
+
// ----------------------------------------------------------------------
|
| 85 |
+
bool CUnescapeInternal(absl::string_view source, bool leave_nulls_escaped,
|
| 86 |
+
char* dest, ptrdiff_t* dest_len, std::string* error) {
|
| 87 |
+
char* d = dest;
|
| 88 |
+
const char* p = source.data();
|
| 89 |
+
const char* end = p + source.size();
|
| 90 |
+
const char* last_byte = end - 1;
|
| 91 |
+
|
| 92 |
+
// Small optimization for case where source = dest and there's no escaping
|
| 93 |
+
while (p == d && p < end && *p != '\\') p++, d++;
|
| 94 |
+
|
| 95 |
+
while (p < end) {
|
| 96 |
+
if (*p != '\\') {
|
| 97 |
+
*d++ = *p++;
|
| 98 |
+
} else {
|
| 99 |
+
if (++p > last_byte) { // skip past the '\\'
|
| 100 |
+
if (error) *error = "String cannot end with \\";
|
| 101 |
+
return false;
|
| 102 |
+
}
|
| 103 |
+
switch (*p) {
|
| 104 |
+
case 'a': *d++ = '\a'; break;
|
| 105 |
+
case 'b': *d++ = '\b'; break;
|
| 106 |
+
case 'f': *d++ = '\f'; break;
|
| 107 |
+
case 'n': *d++ = '\n'; break;
|
| 108 |
+
case 'r': *d++ = '\r'; break;
|
| 109 |
+
case 't': *d++ = '\t'; break;
|
| 110 |
+
case 'v': *d++ = '\v'; break;
|
| 111 |
+
case '\\': *d++ = '\\'; break;
|
| 112 |
+
case '?': *d++ = '\?'; break; // \? Who knew?
|
| 113 |
+
case '\'': *d++ = '\''; break;
|
| 114 |
+
case '"': *d++ = '\"'; break;
|
| 115 |
+
case '0':
|
| 116 |
+
case '1':
|
| 117 |
+
case '2':
|
| 118 |
+
case '3':
|
| 119 |
+
case '4':
|
| 120 |
+
case '5':
|
| 121 |
+
case '6':
|
| 122 |
+
case '7': {
|
| 123 |
+
// octal digit: 1 to 3 digits
|
| 124 |
+
const char* octal_start = p;
|
| 125 |
+
unsigned int ch = static_cast<unsigned int>(*p - '0'); // digit 1
|
| 126 |
+
if (p < last_byte && is_octal_digit(p[1]))
|
| 127 |
+
ch = ch * 8 + static_cast<unsigned int>(*++p - '0'); // digit 2
|
| 128 |
+
if (p < last_byte && is_octal_digit(p[1]))
|
| 129 |
+
ch = ch * 8 + static_cast<unsigned int>(*++p - '0'); // digit 3
|
| 130 |
+
if (ch > 0xff) {
|
| 131 |
+
if (error) {
|
| 132 |
+
*error = "Value of \\" +
|
| 133 |
+
std::string(octal_start,
|
| 134 |
+
static_cast<size_t>(p + 1 - octal_start)) +
|
| 135 |
+
" exceeds 0xff";
|
| 136 |
+
}
|
| 137 |
+
return false;
|
| 138 |
+
}
|
| 139 |
+
if ((ch == 0) && leave_nulls_escaped) {
|
| 140 |
+
// Copy the escape sequence for the null character
|
| 141 |
+
const size_t octal_size = static_cast<size_t>(p + 1 - octal_start);
|
| 142 |
+
*d++ = '\\';
|
| 143 |
+
memmove(d, octal_start, octal_size);
|
| 144 |
+
d += octal_size;
|
| 145 |
+
break;
|
| 146 |
+
}
|
| 147 |
+
*d++ = static_cast<char>(ch);
|
| 148 |
+
break;
|
| 149 |
+
}
|
| 150 |
+
case 'x':
|
| 151 |
+
case 'X': {
|
| 152 |
+
if (p >= last_byte) {
|
| 153 |
+
if (error) *error = "String cannot end with \\x";
|
| 154 |
+
return false;
|
| 155 |
+
} else if (!absl::ascii_isxdigit(static_cast<unsigned char>(p[1]))) {
|
| 156 |
+
if (error) *error = "\\x cannot be followed by a non-hex digit";
|
| 157 |
+
return false;
|
| 158 |
+
}
|
| 159 |
+
unsigned int ch = 0;
|
| 160 |
+
const char* hex_start = p;
|
| 161 |
+
while (p < last_byte &&
|
| 162 |
+
absl::ascii_isxdigit(static_cast<unsigned char>(p[1])))
|
| 163 |
+
// Arbitrarily many hex digits
|
| 164 |
+
ch = (ch << 4) + hex_digit_to_int(*++p);
|
| 165 |
+
if (ch > 0xFF) {
|
| 166 |
+
if (error) {
|
| 167 |
+
*error = "Value of \\" +
|
| 168 |
+
std::string(hex_start,
|
| 169 |
+
static_cast<size_t>(p + 1 - hex_start)) +
|
| 170 |
+
" exceeds 0xff";
|
| 171 |
+
}
|
| 172 |
+
return false;
|
| 173 |
+
}
|
| 174 |
+
if ((ch == 0) && leave_nulls_escaped) {
|
| 175 |
+
// Copy the escape sequence for the null character
|
| 176 |
+
const size_t hex_size = static_cast<size_t>(p + 1 - hex_start);
|
| 177 |
+
*d++ = '\\';
|
| 178 |
+
memmove(d, hex_start, hex_size);
|
| 179 |
+
d += hex_size;
|
| 180 |
+
break;
|
| 181 |
+
}
|
| 182 |
+
*d++ = static_cast<char>(ch);
|
| 183 |
+
break;
|
| 184 |
+
}
|
| 185 |
+
case 'u': {
|
| 186 |
+
// \uhhhh => convert 4 hex digits to UTF-8
|
| 187 |
+
char32_t rune = 0;
|
| 188 |
+
const char* hex_start = p;
|
| 189 |
+
if (p + 4 >= end) {
|
| 190 |
+
if (error) {
|
| 191 |
+
*error = "\\u must be followed by 4 hex digits: \\" +
|
| 192 |
+
std::string(hex_start,
|
| 193 |
+
static_cast<size_t>(p + 1 - hex_start));
|
| 194 |
+
}
|
| 195 |
+
return false;
|
| 196 |
+
}
|
| 197 |
+
for (int i = 0; i < 4; ++i) {
|
| 198 |
+
// Look one char ahead.
|
| 199 |
+
if (absl::ascii_isxdigit(static_cast<unsigned char>(p[1]))) {
|
| 200 |
+
rune = (rune << 4) + hex_digit_to_int(*++p); // Advance p.
|
| 201 |
+
} else {
|
| 202 |
+
if (error) {
|
| 203 |
+
*error = "\\u must be followed by 4 hex digits: \\" +
|
| 204 |
+
std::string(hex_start,
|
| 205 |
+
static_cast<size_t>(p + 1 - hex_start));
|
| 206 |
+
}
|
| 207 |
+
return false;
|
| 208 |
+
}
|
| 209 |
+
}
|
| 210 |
+
if ((rune == 0) && leave_nulls_escaped) {
|
| 211 |
+
// Copy the escape sequence for the null character
|
| 212 |
+
*d++ = '\\';
|
| 213 |
+
memmove(d, hex_start, 5); // u0000
|
| 214 |
+
d += 5;
|
| 215 |
+
break;
|
| 216 |
+
}
|
| 217 |
+
if (IsSurrogate(rune, absl::string_view(hex_start, 5), error)) {
|
| 218 |
+
return false;
|
| 219 |
+
}
|
| 220 |
+
d += strings_internal::EncodeUTF8Char(d, rune);
|
| 221 |
+
break;
|
| 222 |
+
}
|
| 223 |
+
case 'U': {
|
| 224 |
+
// \Uhhhhhhhh => convert 8 hex digits to UTF-8
|
| 225 |
+
char32_t rune = 0;
|
| 226 |
+
const char* hex_start = p;
|
| 227 |
+
if (p + 8 >= end) {
|
| 228 |
+
if (error) {
|
| 229 |
+
*error = "\\U must be followed by 8 hex digits: \\" +
|
| 230 |
+
std::string(hex_start,
|
| 231 |
+
static_cast<size_t>(p + 1 - hex_start));
|
| 232 |
+
}
|
| 233 |
+
return false;
|
| 234 |
+
}
|
| 235 |
+
for (int i = 0; i < 8; ++i) {
|
| 236 |
+
// Look one char ahead.
|
| 237 |
+
if (absl::ascii_isxdigit(static_cast<unsigned char>(p[1]))) {
|
| 238 |
+
// Don't change rune until we're sure this
|
| 239 |
+
// is within the Unicode limit, but do advance p.
|
| 240 |
+
uint32_t newrune = (rune << 4) + hex_digit_to_int(*++p);
|
| 241 |
+
if (newrune > 0x10FFFF) {
|
| 242 |
+
if (error) {
|
| 243 |
+
*error = "Value of \\" +
|
| 244 |
+
std::string(hex_start,
|
| 245 |
+
static_cast<size_t>(p + 1 - hex_start)) +
|
| 246 |
+
" exceeds Unicode limit (0x10FFFF)";
|
| 247 |
+
}
|
| 248 |
+
return false;
|
| 249 |
+
} else {
|
| 250 |
+
rune = newrune;
|
| 251 |
+
}
|
| 252 |
+
} else {
|
| 253 |
+
if (error) {
|
| 254 |
+
*error = "\\U must be followed by 8 hex digits: \\" +
|
| 255 |
+
std::string(hex_start,
|
| 256 |
+
static_cast<size_t>(p + 1 - hex_start));
|
| 257 |
+
}
|
| 258 |
+
return false;
|
| 259 |
+
}
|
| 260 |
+
}
|
| 261 |
+
if ((rune == 0) && leave_nulls_escaped) {
|
| 262 |
+
// Copy the escape sequence for the null character
|
| 263 |
+
*d++ = '\\';
|
| 264 |
+
memmove(d, hex_start, 9); // U00000000
|
| 265 |
+
d += 9;
|
| 266 |
+
break;
|
| 267 |
+
}
|
| 268 |
+
if (IsSurrogate(rune, absl::string_view(hex_start, 9), error)) {
|
| 269 |
+
return false;
|
| 270 |
+
}
|
| 271 |
+
d += strings_internal::EncodeUTF8Char(d, rune);
|
| 272 |
+
break;
|
| 273 |
+
}
|
| 274 |
+
default: {
|
| 275 |
+
if (error) *error = std::string("Unknown escape sequence: \\") + *p;
|
| 276 |
+
return false;
|
| 277 |
+
}
|
| 278 |
+
}
|
| 279 |
+
p++; // read past letter we escaped
|
| 280 |
+
}
|
| 281 |
+
}
|
| 282 |
+
*dest_len = d - dest;
|
| 283 |
+
return true;
|
| 284 |
+
}
|
| 285 |
+
|
| 286 |
+
// ----------------------------------------------------------------------
|
| 287 |
+
// CUnescapeInternal()
|
| 288 |
+
//
|
| 289 |
+
// Same as above but uses a std::string for output. 'source' and 'dest'
|
| 290 |
+
// may be the same.
|
| 291 |
+
// ----------------------------------------------------------------------
|
| 292 |
+
bool CUnescapeInternal(absl::string_view source, bool leave_nulls_escaped,
|
| 293 |
+
std::string* dest, std::string* error) {
|
| 294 |
+
strings_internal::STLStringResizeUninitialized(dest, source.size());
|
| 295 |
+
|
| 296 |
+
ptrdiff_t dest_size;
|
| 297 |
+
if (!CUnescapeInternal(source,
|
| 298 |
+
leave_nulls_escaped,
|
| 299 |
+
&(*dest)[0],
|
| 300 |
+
&dest_size,
|
| 301 |
+
error)) {
|
| 302 |
+
return false;
|
| 303 |
+
}
|
| 304 |
+
dest->erase(static_cast<size_t>(dest_size));
|
| 305 |
+
return true;
|
| 306 |
+
}
|
| 307 |
+
|
| 308 |
+
// ----------------------------------------------------------------------
|
| 309 |
+
// CEscape()
|
| 310 |
+
// CHexEscape()
|
| 311 |
+
// Utf8SafeCEscape()
|
| 312 |
+
// Utf8SafeCHexEscape()
|
| 313 |
+
// Escapes 'src' using C-style escape sequences. This is useful for
|
| 314 |
+
// preparing query flags. The 'Hex' version uses hexadecimal rather than
|
| 315 |
+
// octal sequences. The 'Utf8Safe' version does not touch UTF-8 bytes.
|
| 316 |
+
//
|
| 317 |
+
// Escaped chars: \n, \r, \t, ", ', \, and !absl::ascii_isprint().
|
| 318 |
+
// ----------------------------------------------------------------------
|
| 319 |
+
std::string CEscapeInternal(absl::string_view src, bool use_hex,
|
| 320 |
+
bool utf8_safe) {
|
| 321 |
+
std::string dest;
|
| 322 |
+
bool last_hex_escape = false; // true if last output char was \xNN.
|
| 323 |
+
|
| 324 |
+
for (char c : src) {
|
| 325 |
+
bool is_hex_escape = false;
|
| 326 |
+
switch (c) {
|
| 327 |
+
case '\n': dest.append("\\" "n"); break;
|
| 328 |
+
case '\r': dest.append("\\" "r"); break;
|
| 329 |
+
case '\t': dest.append("\\" "t"); break;
|
| 330 |
+
case '\"': dest.append("\\" "\""); break;
|
| 331 |
+
case '\'': dest.append("\\" "'"); break;
|
| 332 |
+
case '\\': dest.append("\\" "\\"); break;
|
| 333 |
+
default: {
|
| 334 |
+
// Note that if we emit \xNN and the src character after that is a hex
|
| 335 |
+
// digit then that digit must be escaped too to prevent it being
|
| 336 |
+
// interpreted as part of the character code by C.
|
| 337 |
+
const unsigned char uc = static_cast<unsigned char>(c);
|
| 338 |
+
if ((!utf8_safe || uc < 0x80) &&
|
| 339 |
+
(!absl::ascii_isprint(uc) ||
|
| 340 |
+
(last_hex_escape && absl::ascii_isxdigit(uc)))) {
|
| 341 |
+
if (use_hex) {
|
| 342 |
+
dest.append("\\" "x");
|
| 343 |
+
dest.push_back(numbers_internal::kHexChar[uc / 16]);
|
| 344 |
+
dest.push_back(numbers_internal::kHexChar[uc % 16]);
|
| 345 |
+
is_hex_escape = true;
|
| 346 |
+
} else {
|
| 347 |
+
dest.append("\\");
|
| 348 |
+
dest.push_back(numbers_internal::kHexChar[uc / 64]);
|
| 349 |
+
dest.push_back(numbers_internal::kHexChar[(uc % 64) / 8]);
|
| 350 |
+
dest.push_back(numbers_internal::kHexChar[uc % 8]);
|
| 351 |
+
}
|
| 352 |
+
} else {
|
| 353 |
+
dest.push_back(c);
|
| 354 |
+
break;
|
| 355 |
+
}
|
| 356 |
+
}
|
| 357 |
+
}
|
| 358 |
+
last_hex_escape = is_hex_escape;
|
| 359 |
+
}
|
| 360 |
+
|
| 361 |
+
return dest;
|
| 362 |
+
}
|
| 363 |
+
|
| 364 |
+
/* clang-format off */
|
| 365 |
+
constexpr unsigned char kCEscapedLen[256] = {
|
| 366 |
+
4, 4, 4, 4, 4, 4, 4, 4, 4, 2, 2, 4, 4, 2, 4, 4, // \t, \n, \r
|
| 367 |
+
4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
|
| 368 |
+
1, 1, 2, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, // ", '
|
| 369 |
+
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // '0'..'9'
|
| 370 |
+
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 'A'..'O'
|
| 371 |
+
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, // 'P'..'Z', '\'
|
| 372 |
+
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 'a'..'o'
|
| 373 |
+
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 4, // 'p'..'z', DEL
|
| 374 |
+
4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
|
| 375 |
+
4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
|
| 376 |
+
4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
|
| 377 |
+
4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
|
| 378 |
+
4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
|
| 379 |
+
4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
|
| 380 |
+
4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
|
| 381 |
+
4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
|
| 382 |
+
};
|
| 383 |
+
/* clang-format on */
|
| 384 |
+
|
| 385 |
+
// Calculates the length of the C-style escaped version of 'src'.
|
| 386 |
+
// Assumes that non-printable characters are escaped using octal sequences, and
|
| 387 |
+
// that UTF-8 bytes are not handled specially.
|
| 388 |
+
inline size_t CEscapedLength(absl::string_view src) {
|
| 389 |
+
size_t escaped_len = 0;
|
| 390 |
+
// The maximum value of kCEscapedLen[x] is 4, so we can escape any string of
|
| 391 |
+
// length size_t_max/4 without checking for overflow.
|
| 392 |
+
size_t unchecked_limit =
|
| 393 |
+
std::min<size_t>(src.size(), std::numeric_limits<size_t>::max() / 4);
|
| 394 |
+
size_t i = 0;
|
| 395 |
+
while (i < unchecked_limit) {
|
| 396 |
+
// Common case: No need to check for overflow.
|
| 397 |
+
escaped_len += kCEscapedLen[static_cast<unsigned char>(src[i++])];
|
| 398 |
+
}
|
| 399 |
+
while (i < src.size()) {
|
| 400 |
+
// Beyond unchecked_limit we need to check for overflow before adding.
|
| 401 |
+
size_t char_len = kCEscapedLen[static_cast<unsigned char>(src[i++])];
|
| 402 |
+
ABSL_INTERNAL_CHECK(
|
| 403 |
+
escaped_len <= std::numeric_limits<size_t>::max() - char_len,
|
| 404 |
+
"escaped_len overflow");
|
| 405 |
+
escaped_len += char_len;
|
| 406 |
+
}
|
| 407 |
+
return escaped_len;
|
| 408 |
+
}
|
| 409 |
+
|
| 410 |
+
void CEscapeAndAppendInternal(absl::string_view src, std::string* dest) {
|
| 411 |
+
size_t escaped_len = CEscapedLength(src);
|
| 412 |
+
if (escaped_len == src.size()) {
|
| 413 |
+
dest->append(src.data(), src.size());
|
| 414 |
+
return;
|
| 415 |
+
}
|
| 416 |
+
|
| 417 |
+
size_t cur_dest_len = dest->size();
|
| 418 |
+
ABSL_INTERNAL_CHECK(
|
| 419 |
+
cur_dest_len <= std::numeric_limits<size_t>::max() - escaped_len,
|
| 420 |
+
"std::string size overflow");
|
| 421 |
+
strings_internal::STLStringResizeUninitialized(dest,
|
| 422 |
+
cur_dest_len + escaped_len);
|
| 423 |
+
char* append_ptr = &(*dest)[cur_dest_len];
|
| 424 |
+
|
| 425 |
+
for (char c : src) {
|
| 426 |
+
size_t char_len = kCEscapedLen[static_cast<unsigned char>(c)];
|
| 427 |
+
if (char_len == 1) {
|
| 428 |
+
*append_ptr++ = c;
|
| 429 |
+
} else if (char_len == 2) {
|
| 430 |
+
switch (c) {
|
| 431 |
+
case '\n':
|
| 432 |
+
*append_ptr++ = '\\';
|
| 433 |
+
*append_ptr++ = 'n';
|
| 434 |
+
break;
|
| 435 |
+
case '\r':
|
| 436 |
+
*append_ptr++ = '\\';
|
| 437 |
+
*append_ptr++ = 'r';
|
| 438 |
+
break;
|
| 439 |
+
case '\t':
|
| 440 |
+
*append_ptr++ = '\\';
|
| 441 |
+
*append_ptr++ = 't';
|
| 442 |
+
break;
|
| 443 |
+
case '\"':
|
| 444 |
+
*append_ptr++ = '\\';
|
| 445 |
+
*append_ptr++ = '\"';
|
| 446 |
+
break;
|
| 447 |
+
case '\'':
|
| 448 |
+
*append_ptr++ = '\\';
|
| 449 |
+
*append_ptr++ = '\'';
|
| 450 |
+
break;
|
| 451 |
+
case '\\':
|
| 452 |
+
*append_ptr++ = '\\';
|
| 453 |
+
*append_ptr++ = '\\';
|
| 454 |
+
break;
|
| 455 |
+
}
|
| 456 |
+
} else {
|
| 457 |
+
*append_ptr++ = '\\';
|
| 458 |
+
*append_ptr++ = '0' + static_cast<unsigned char>(c) / 64;
|
| 459 |
+
*append_ptr++ = '0' + (static_cast<unsigned char>(c) % 64) / 8;
|
| 460 |
+
*append_ptr++ = '0' + static_cast<unsigned char>(c) % 8;
|
| 461 |
+
}
|
| 462 |
+
}
|
| 463 |
+
}
|
| 464 |
+
|
| 465 |
+
// Reverses the mapping in Base64EscapeInternal; see that method's
|
| 466 |
+
// documentation for details of the mapping.
|
| 467 |
+
bool Base64UnescapeInternal(const char* src_param, size_t szsrc, char* dest,
|
| 468 |
+
size_t szdest, const signed char* unbase64,
|
| 469 |
+
size_t* len) {
|
| 470 |
+
static const char kPad64Equals = '=';
|
| 471 |
+
static const char kPad64Dot = '.';
|
| 472 |
+
|
| 473 |
+
size_t destidx = 0;
|
| 474 |
+
int decode = 0;
|
| 475 |
+
int state = 0;
|
| 476 |
+
unsigned char ch = 0;
|
| 477 |
+
unsigned int temp = 0;
|
| 478 |
+
|
| 479 |
+
// If "char" is signed by default, using *src as an array index results in
|
| 480 |
+
// accessing negative array elements. Treat the input as a pointer to
|
| 481 |
+
// unsigned char to avoid this.
|
| 482 |
+
const unsigned char* src = reinterpret_cast<const unsigned char*>(src_param);
|
| 483 |
+
|
| 484 |
+
// The GET_INPUT macro gets the next input character, skipping
|
| 485 |
+
// over any whitespace, and stopping when we reach the end of the
|
| 486 |
+
// string or when we read any non-data character. The arguments are
|
| 487 |
+
// an arbitrary identifier (used as a label for goto) and the number
|
| 488 |
+
// of data bytes that must remain in the input to avoid aborting the
|
| 489 |
+
// loop.
|
| 490 |
+
#define GET_INPUT(label, remain) \
|
| 491 |
+
label: \
|
| 492 |
+
--szsrc; \
|
| 493 |
+
ch = *src++; \
|
| 494 |
+
decode = unbase64[ch]; \
|
| 495 |
+
if (decode < 0) { \
|
| 496 |
+
if (absl::ascii_isspace(ch) && szsrc >= remain) goto label; \
|
| 497 |
+
state = 4 - remain; \
|
| 498 |
+
break; \
|
| 499 |
+
}
|
| 500 |
+
|
| 501 |
+
// if dest is null, we're just checking to see if it's legal input
|
| 502 |
+
// rather than producing output. (I suspect this could just be done
|
| 503 |
+
// with a regexp...). We duplicate the loop so this test can be
|
| 504 |
+
// outside it instead of in every iteration.
|
| 505 |
+
|
| 506 |
+
if (dest) {
|
| 507 |
+
// This loop consumes 4 input bytes and produces 3 output bytes
|
| 508 |
+
// per iteration. We can't know at the start that there is enough
|
| 509 |
+
// data left in the string for a full iteration, so the loop may
|
| 510 |
+
// break out in the middle; if so 'state' will be set to the
|
| 511 |
+
// number of input bytes read.
|
| 512 |
+
|
| 513 |
+
while (szsrc >= 4) {
|
| 514 |
+
// We'll start by optimistically assuming that the next four
|
| 515 |
+
// bytes of the string (src[0..3]) are four good data bytes
|
| 516 |
+
// (that is, no nulls, whitespace, padding chars, or illegal
|
| 517 |
+
// chars). We need to test src[0..2] for nulls individually
|
| 518 |
+
// before constructing temp to preserve the property that we
|
| 519 |
+
// never read past a null in the string (no matter how long
|
| 520 |
+
// szsrc claims the string is).
|
| 521 |
+
|
| 522 |
+
if (!src[0] || !src[1] || !src[2] ||
|
| 523 |
+
((temp = ((unsigned(unbase64[src[0]]) << 18) |
|
| 524 |
+
(unsigned(unbase64[src[1]]) << 12) |
|
| 525 |
+
(unsigned(unbase64[src[2]]) << 6) |
|
| 526 |
+
(unsigned(unbase64[src[3]])))) &
|
| 527 |
+
0x80000000)) {
|
| 528 |
+
// Iff any of those four characters was bad (null, illegal,
|
| 529 |
+
// whitespace, padding), then temp's high bit will be set
|
| 530 |
+
// (because unbase64[] is -1 for all bad characters).
|
| 531 |
+
//
|
| 532 |
+
// We'll back up and resort to the slower decoder, which knows
|
| 533 |
+
// how to handle those cases.
|
| 534 |
+
|
| 535 |
+
GET_INPUT(first, 4);
|
| 536 |
+
temp = static_cast<unsigned char>(decode);
|
| 537 |
+
GET_INPUT(second, 3);
|
| 538 |
+
temp = (temp << 6) | static_cast<unsigned char>(decode);
|
| 539 |
+
GET_INPUT(third, 2);
|
| 540 |
+
temp = (temp << 6) | static_cast<unsigned char>(decode);
|
| 541 |
+
GET_INPUT(fourth, 1);
|
| 542 |
+
temp = (temp << 6) | static_cast<unsigned char>(decode);
|
| 543 |
+
} else {
|
| 544 |
+
// We really did have four good data bytes, so advance four
|
| 545 |
+
// characters in the string.
|
| 546 |
+
|
| 547 |
+
szsrc -= 4;
|
| 548 |
+
src += 4;
|
| 549 |
+
}
|
| 550 |
+
|
| 551 |
+
// temp has 24 bits of input, so write that out as three bytes.
|
| 552 |
+
|
| 553 |
+
if (destidx + 3 > szdest) return false;
|
| 554 |
+
dest[destidx + 2] = static_cast<char>(temp);
|
| 555 |
+
temp >>= 8;
|
| 556 |
+
dest[destidx + 1] = static_cast<char>(temp);
|
| 557 |
+
temp >>= 8;
|
| 558 |
+
dest[destidx] = static_cast<char>(temp);
|
| 559 |
+
destidx += 3;
|
| 560 |
+
}
|
| 561 |
+
} else {
|
| 562 |
+
while (szsrc >= 4) {
|
| 563 |
+
if (!src[0] || !src[1] || !src[2] ||
|
| 564 |
+
((temp = ((unsigned(unbase64[src[0]]) << 18) |
|
| 565 |
+
(unsigned(unbase64[src[1]]) << 12) |
|
| 566 |
+
(unsigned(unbase64[src[2]]) << 6) |
|
| 567 |
+
(unsigned(unbase64[src[3]])))) &
|
| 568 |
+
0x80000000)) {
|
| 569 |
+
GET_INPUT(first_no_dest, 4);
|
| 570 |
+
GET_INPUT(second_no_dest, 3);
|
| 571 |
+
GET_INPUT(third_no_dest, 2);
|
| 572 |
+
GET_INPUT(fourth_no_dest, 1);
|
| 573 |
+
} else {
|
| 574 |
+
szsrc -= 4;
|
| 575 |
+
src += 4;
|
| 576 |
+
}
|
| 577 |
+
destidx += 3;
|
| 578 |
+
}
|
| 579 |
+
}
|
| 580 |
+
|
| 581 |
+
#undef GET_INPUT
|
| 582 |
+
|
| 583 |
+
// if the loop terminated because we read a bad character, return
|
| 584 |
+
// now.
|
| 585 |
+
if (decode < 0 && ch != kPad64Equals && ch != kPad64Dot &&
|
| 586 |
+
!absl::ascii_isspace(ch))
|
| 587 |
+
return false;
|
| 588 |
+
|
| 589 |
+
if (ch == kPad64Equals || ch == kPad64Dot) {
|
| 590 |
+
// if we stopped by hitting an '=' or '.', un-read that character -- we'll
|
| 591 |
+
// look at it again when we count to check for the proper number of
|
| 592 |
+
// equals signs at the end.
|
| 593 |
+
++szsrc;
|
| 594 |
+
--src;
|
| 595 |
+
} else {
|
| 596 |
+
// This loop consumes 1 input byte per iteration. It's used to
|
| 597 |
+
// clean up the 0-3 input bytes remaining when the first, faster
|
| 598 |
+
// loop finishes. 'temp' contains the data from 'state' input
|
| 599 |
+
// characters read by the first loop.
|
| 600 |
+
while (szsrc > 0) {
|
| 601 |
+
--szsrc;
|
| 602 |
+
ch = *src++;
|
| 603 |
+
decode = unbase64[ch];
|
| 604 |
+
if (decode < 0) {
|
| 605 |
+
if (absl::ascii_isspace(ch)) {
|
| 606 |
+
continue;
|
| 607 |
+
} else if (ch == kPad64Equals || ch == kPad64Dot) {
|
| 608 |
+
// back up one character; we'll read it again when we check
|
| 609 |
+
// for the correct number of pad characters at the end.
|
| 610 |
+
++szsrc;
|
| 611 |
+
--src;
|
| 612 |
+
break;
|
| 613 |
+
} else {
|
| 614 |
+
return false;
|
| 615 |
+
}
|
| 616 |
+
}
|
| 617 |
+
|
| 618 |
+
// Each input character gives us six bits of output.
|
| 619 |
+
temp = (temp << 6) | static_cast<unsigned char>(decode);
|
| 620 |
+
++state;
|
| 621 |
+
if (state == 4) {
|
| 622 |
+
// If we've accumulated 24 bits of output, write that out as
|
| 623 |
+
// three bytes.
|
| 624 |
+
if (dest) {
|
| 625 |
+
if (destidx + 3 > szdest) return false;
|
| 626 |
+
dest[destidx + 2] = static_cast<char>(temp);
|
| 627 |
+
temp >>= 8;
|
| 628 |
+
dest[destidx + 1] = static_cast<char>(temp);
|
| 629 |
+
temp >>= 8;
|
| 630 |
+
dest[destidx] = static_cast<char>(temp);
|
| 631 |
+
}
|
| 632 |
+
destidx += 3;
|
| 633 |
+
state = 0;
|
| 634 |
+
temp = 0;
|
| 635 |
+
}
|
| 636 |
+
}
|
| 637 |
+
}
|
| 638 |
+
|
| 639 |
+
// Process the leftover data contained in 'temp' at the end of the input.
|
| 640 |
+
int expected_equals = 0;
|
| 641 |
+
switch (state) {
|
| 642 |
+
case 0:
|
| 643 |
+
// Nothing left over; output is a multiple of 3 bytes.
|
| 644 |
+
break;
|
| 645 |
+
|
| 646 |
+
case 1:
|
| 647 |
+
// Bad input; we have 6 bits left over.
|
| 648 |
+
return false;
|
| 649 |
+
|
| 650 |
+
case 2:
|
| 651 |
+
// Produce one more output byte from the 12 input bits we have left.
|
| 652 |
+
if (dest) {
|
| 653 |
+
if (destidx + 1 > szdest) return false;
|
| 654 |
+
temp >>= 4;
|
| 655 |
+
dest[destidx] = static_cast<char>(temp);
|
| 656 |
+
}
|
| 657 |
+
++destidx;
|
| 658 |
+
expected_equals = 2;
|
| 659 |
+
break;
|
| 660 |
+
|
| 661 |
+
case 3:
|
| 662 |
+
// Produce two more output bytes from the 18 input bits we have left.
|
| 663 |
+
if (dest) {
|
| 664 |
+
if (destidx + 2 > szdest) return false;
|
| 665 |
+
temp >>= 2;
|
| 666 |
+
dest[destidx + 1] = static_cast<char>(temp);
|
| 667 |
+
temp >>= 8;
|
| 668 |
+
dest[destidx] = static_cast<char>(temp);
|
| 669 |
+
}
|
| 670 |
+
destidx += 2;
|
| 671 |
+
expected_equals = 1;
|
| 672 |
+
break;
|
| 673 |
+
|
| 674 |
+
default:
|
| 675 |
+
// state should have no other values at this point.
|
| 676 |
+
ABSL_RAW_LOG(FATAL, "This can't happen; base64 decoder state = %d",
|
| 677 |
+
state);
|
| 678 |
+
}
|
| 679 |
+
|
| 680 |
+
// The remainder of the string should be all whitespace, mixed with
|
| 681 |
+
// exactly 0 equals signs, or exactly 'expected_equals' equals
|
| 682 |
+
// signs. (Always accepting 0 equals signs is an Abseil extension
|
| 683 |
+
// not covered in the RFC, as is accepting dot as the pad character.)
|
| 684 |
+
|
| 685 |
+
int equals = 0;
|
| 686 |
+
while (szsrc > 0) {
|
| 687 |
+
if (*src == kPad64Equals || *src == kPad64Dot)
|
| 688 |
+
++equals;
|
| 689 |
+
else if (!absl::ascii_isspace(*src))
|
| 690 |
+
return false;
|
| 691 |
+
--szsrc;
|
| 692 |
+
++src;
|
| 693 |
+
}
|
| 694 |
+
|
| 695 |
+
const bool ok = (equals == 0 || equals == expected_equals);
|
| 696 |
+
if (ok) *len = destidx;
|
| 697 |
+
return ok;
|
| 698 |
+
}
|
| 699 |
+
|
| 700 |
+
// The arrays below map base64-escaped characters back to their original values.
|
| 701 |
+
// For the inverse case, see k(WebSafe)Base64Chars in the internal
|
| 702 |
+
// escaping.cc.
|
| 703 |
+
// These arrays were generated by the following inversion code:
|
| 704 |
+
// #include <sys/time.h>
|
| 705 |
+
// #include <stdlib.h>
|
| 706 |
+
// #include <string.h>
|
| 707 |
+
// main()
|
| 708 |
+
// {
|
| 709 |
+
// static const char Base64[] =
|
| 710 |
+
// "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
|
| 711 |
+
// char* pos;
|
| 712 |
+
// int idx, i, j;
|
| 713 |
+
// printf(" ");
|
| 714 |
+
// for (i = 0; i < 255; i += 8) {
|
| 715 |
+
// for (j = i; j < i + 8; j++) {
|
| 716 |
+
// pos = strchr(Base64, j);
|
| 717 |
+
// if ((pos == nullptr) || (j == 0))
|
| 718 |
+
// idx = -1;
|
| 719 |
+
// else
|
| 720 |
+
// idx = pos - Base64;
|
| 721 |
+
// if (idx == -1)
|
| 722 |
+
// printf(" %2d, ", idx);
|
| 723 |
+
// else
|
| 724 |
+
// printf(" %2d/*%c*/,", idx, j);
|
| 725 |
+
// }
|
| 726 |
+
// printf("\n ");
|
| 727 |
+
// }
|
| 728 |
+
// }
|
| 729 |
+
//
|
| 730 |
+
// where the value of "Base64[]" was replaced by one of k(WebSafe)Base64Chars
|
| 731 |
+
// in the internal escaping.cc.
|
| 732 |
+
/* clang-format off */
|
| 733 |
+
constexpr signed char kUnBase64[] = {
|
| 734 |
+
-1, -1, -1, -1, -1, -1, -1, -1,
|
| 735 |
+
-1, -1, -1, -1, -1, -1, -1, -1,
|
| 736 |
+
-1, -1, -1, -1, -1, -1, -1, -1,
|
| 737 |
+
-1, -1, -1, -1, -1, -1, -1, -1,
|
| 738 |
+
-1, -1, -1, -1, -1, -1, -1, -1,
|
| 739 |
+
-1, -1, -1, 62/*+*/, -1, -1, -1, 63/*/ */,
|
| 740 |
+
52/*0*/, 53/*1*/, 54/*2*/, 55/*3*/, 56/*4*/, 57/*5*/, 58/*6*/, 59/*7*/,
|
| 741 |
+
60/*8*/, 61/*9*/, -1, -1, -1, -1, -1, -1,
|
| 742 |
+
-1, 0/*A*/, 1/*B*/, 2/*C*/, 3/*D*/, 4/*E*/, 5/*F*/, 6/*G*/,
|
| 743 |
+
07/*H*/, 8/*I*/, 9/*J*/, 10/*K*/, 11/*L*/, 12/*M*/, 13/*N*/, 14/*O*/,
|
| 744 |
+
15/*P*/, 16/*Q*/, 17/*R*/, 18/*S*/, 19/*T*/, 20/*U*/, 21/*V*/, 22/*W*/,
|
| 745 |
+
23/*X*/, 24/*Y*/, 25/*Z*/, -1, -1, -1, -1, -1,
|
| 746 |
+
-1, 26/*a*/, 27/*b*/, 28/*c*/, 29/*d*/, 30/*e*/, 31/*f*/, 32/*g*/,
|
| 747 |
+
33/*h*/, 34/*i*/, 35/*j*/, 36/*k*/, 37/*l*/, 38/*m*/, 39/*n*/, 40/*o*/,
|
| 748 |
+
41/*p*/, 42/*q*/, 43/*r*/, 44/*s*/, 45/*t*/, 46/*u*/, 47/*v*/, 48/*w*/,
|
| 749 |
+
49/*x*/, 50/*y*/, 51/*z*/, -1, -1, -1, -1, -1,
|
| 750 |
+
-1, -1, -1, -1, -1, -1, -1, -1,
|
| 751 |
+
-1, -1, -1, -1, -1, -1, -1, -1,
|
| 752 |
+
-1, -1, -1, -1, -1, -1, -1, -1,
|
| 753 |
+
-1, -1, -1, -1, -1, -1, -1, -1,
|
| 754 |
+
-1, -1, -1, -1, -1, -1, -1, -1,
|
| 755 |
+
-1, -1, -1, -1, -1, -1, -1, -1,
|
| 756 |
+
-1, -1, -1, -1, -1, -1, -1, -1,
|
| 757 |
+
-1, -1, -1, -1, -1, -1, -1, -1,
|
| 758 |
+
-1, -1, -1, -1, -1, -1, -1, -1,
|
| 759 |
+
-1, -1, -1, -1, -1, -1, -1, -1,
|
| 760 |
+
-1, -1, -1, -1, -1, -1, -1, -1,
|
| 761 |
+
-1, -1, -1, -1, -1, -1, -1, -1,
|
| 762 |
+
-1, -1, -1, -1, -1, -1, -1, -1,
|
| 763 |
+
-1, -1, -1, -1, -1, -1, -1, -1,
|
| 764 |
+
-1, -1, -1, -1, -1, -1, -1, -1,
|
| 765 |
+
-1, -1, -1, -1, -1, -1, -1, -1
|
| 766 |
+
};
|
| 767 |
+
|
| 768 |
+
constexpr signed char kUnWebSafeBase64[] = {
|
| 769 |
+
-1, -1, -1, -1, -1, -1, -1, -1,
|
| 770 |
+
-1, -1, -1, -1, -1, -1, -1, -1,
|
| 771 |
+
-1, -1, -1, -1, -1, -1, -1, -1,
|
| 772 |
+
-1, -1, -1, -1, -1, -1, -1, -1,
|
| 773 |
+
-1, -1, -1, -1, -1, -1, -1, -1,
|
| 774 |
+
-1, -1, -1, -1, -1, 62/*-*/, -1, -1,
|
| 775 |
+
52/*0*/, 53/*1*/, 54/*2*/, 55/*3*/, 56/*4*/, 57/*5*/, 58/*6*/, 59/*7*/,
|
| 776 |
+
60/*8*/, 61/*9*/, -1, -1, -1, -1, -1, -1,
|
| 777 |
+
-1, 0/*A*/, 1/*B*/, 2/*C*/, 3/*D*/, 4/*E*/, 5/*F*/, 6/*G*/,
|
| 778 |
+
07/*H*/, 8/*I*/, 9/*J*/, 10/*K*/, 11/*L*/, 12/*M*/, 13/*N*/, 14/*O*/,
|
| 779 |
+
15/*P*/, 16/*Q*/, 17/*R*/, 18/*S*/, 19/*T*/, 20/*U*/, 21/*V*/, 22/*W*/,
|
| 780 |
+
23/*X*/, 24/*Y*/, 25/*Z*/, -1, -1, -1, -1, 63/*_*/,
|
| 781 |
+
-1, 26/*a*/, 27/*b*/, 28/*c*/, 29/*d*/, 30/*e*/, 31/*f*/, 32/*g*/,
|
| 782 |
+
33/*h*/, 34/*i*/, 35/*j*/, 36/*k*/, 37/*l*/, 38/*m*/, 39/*n*/, 40/*o*/,
|
| 783 |
+
41/*p*/, 42/*q*/, 43/*r*/, 44/*s*/, 45/*t*/, 46/*u*/, 47/*v*/, 48/*w*/,
|
| 784 |
+
49/*x*/, 50/*y*/, 51/*z*/, -1, -1, -1, -1, -1,
|
| 785 |
+
-1, -1, -1, -1, -1, -1, -1, -1,
|
| 786 |
+
-1, -1, -1, -1, -1, -1, -1, -1,
|
| 787 |
+
-1, -1, -1, -1, -1, -1, -1, -1,
|
| 788 |
+
-1, -1, -1, -1, -1, -1, -1, -1,
|
| 789 |
+
-1, -1, -1, -1, -1, -1, -1, -1,
|
| 790 |
+
-1, -1, -1, -1, -1, -1, -1, -1,
|
| 791 |
+
-1, -1, -1, -1, -1, -1, -1, -1,
|
| 792 |
+
-1, -1, -1, -1, -1, -1, -1, -1,
|
| 793 |
+
-1, -1, -1, -1, -1, -1, -1, -1,
|
| 794 |
+
-1, -1, -1, -1, -1, -1, -1, -1,
|
| 795 |
+
-1, -1, -1, -1, -1, -1, -1, -1,
|
| 796 |
+
-1, -1, -1, -1, -1, -1, -1, -1,
|
| 797 |
+
-1, -1, -1, -1, -1, -1, -1, -1,
|
| 798 |
+
-1, -1, -1, -1, -1, -1, -1, -1,
|
| 799 |
+
-1, -1, -1, -1, -1, -1, -1, -1,
|
| 800 |
+
-1, -1, -1, -1, -1, -1, -1, -1
|
| 801 |
+
};
|
| 802 |
+
/* clang-format on */
|
| 803 |
+
|
| 804 |
+
template <typename String>
|
| 805 |
+
bool Base64UnescapeInternal(const char* src, size_t slen, String* dest,
|
| 806 |
+
const signed char* unbase64) {
|
| 807 |
+
// Determine the size of the output string. Base64 encodes every 3 bytes into
|
| 808 |
+
// 4 characters. Any leftover chars are added directly for good measure.
|
| 809 |
+
const size_t dest_len = 3 * (slen / 4) + (slen % 4);
|
| 810 |
+
|
| 811 |
+
strings_internal::STLStringResizeUninitialized(dest, dest_len);
|
| 812 |
+
|
| 813 |
+
// We are getting the destination buffer by getting the beginning of the
|
| 814 |
+
// string and converting it into a char *.
|
| 815 |
+
size_t len;
|
| 816 |
+
const bool ok =
|
| 817 |
+
Base64UnescapeInternal(src, slen, &(*dest)[0], dest_len, unbase64, &len);
|
| 818 |
+
if (!ok) {
|
| 819 |
+
dest->clear();
|
| 820 |
+
return false;
|
| 821 |
+
}
|
| 822 |
+
|
| 823 |
+
// could be shorter if there was padding
|
| 824 |
+
assert(len <= dest_len);
|
| 825 |
+
dest->erase(len);
|
| 826 |
+
|
| 827 |
+
return true;
|
| 828 |
+
}
|
| 829 |
+
|
| 830 |
+
/* clang-format off */
|
| 831 |
+
constexpr char kHexValueLenient[256] = {
|
| 832 |
+
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
| 833 |
+
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
| 834 |
+
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
| 835 |
+
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 0, 0, 0, 0, 0, // '0'..'9'
|
| 836 |
+
0, 10, 11, 12, 13, 14, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 'A'..'F'
|
| 837 |
+
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
| 838 |
+
0, 10, 11, 12, 13, 14, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 'a'..'f'
|
| 839 |
+
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
| 840 |
+
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
| 841 |
+
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
| 842 |
+
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
| 843 |
+
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
| 844 |
+
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
| 845 |
+
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
| 846 |
+
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
| 847 |
+
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
| 848 |
+
};
|
| 849 |
+
|
| 850 |
+
/* clang-format on */
|
| 851 |
+
|
| 852 |
+
// This is a templated function so that T can be either a char*
|
| 853 |
+
// or a string. This works because we use the [] operator to access
|
| 854 |
+
// individual characters at a time.
|
| 855 |
+
template <typename T>
|
| 856 |
+
void HexStringToBytesInternal(const char* from, T to, size_t num) {
|
| 857 |
+
for (size_t i = 0; i < num; i++) {
|
| 858 |
+
to[i] = static_cast<char>(kHexValueLenient[from[i * 2] & 0xFF] << 4) +
|
| 859 |
+
(kHexValueLenient[from[i * 2 + 1] & 0xFF]);
|
| 860 |
+
}
|
| 861 |
+
}
|
| 862 |
+
|
| 863 |
+
// This is a templated function so that T can be either a char* or a
|
| 864 |
+
// std::string.
|
| 865 |
+
template <typename T>
|
| 866 |
+
void BytesToHexStringInternal(const unsigned char* src, T dest, size_t num) {
|
| 867 |
+
auto dest_ptr = &dest[0];
|
| 868 |
+
for (auto src_ptr = src; src_ptr != (src + num); ++src_ptr, dest_ptr += 2) {
|
| 869 |
+
const char* hex_p = &numbers_internal::kHexTable[*src_ptr * 2];
|
| 870 |
+
std::copy(hex_p, hex_p + 2, dest_ptr);
|
| 871 |
+
}
|
| 872 |
+
}
|
| 873 |
+
|
| 874 |
+
} // namespace
|
| 875 |
+
|
| 876 |
+
// ----------------------------------------------------------------------
|
| 877 |
+
// CUnescape()
|
| 878 |
+
//
|
| 879 |
+
// See CUnescapeInternal() for implementation details.
|
| 880 |
+
// ----------------------------------------------------------------------
|
| 881 |
+
bool CUnescape(absl::string_view source, std::string* dest,
|
| 882 |
+
std::string* error) {
|
| 883 |
+
return CUnescapeInternal(source, kUnescapeNulls, dest, error);
|
| 884 |
+
}
|
| 885 |
+
|
| 886 |
+
std::string CEscape(absl::string_view src) {
|
| 887 |
+
std::string dest;
|
| 888 |
+
CEscapeAndAppendInternal(src, &dest);
|
| 889 |
+
return dest;
|
| 890 |
+
}
|
| 891 |
+
|
| 892 |
+
std::string CHexEscape(absl::string_view src) {
|
| 893 |
+
return CEscapeInternal(src, true, false);
|
| 894 |
+
}
|
| 895 |
+
|
| 896 |
+
std::string Utf8SafeCEscape(absl::string_view src) {
|
| 897 |
+
return CEscapeInternal(src, false, true);
|
| 898 |
+
}
|
| 899 |
+
|
| 900 |
+
std::string Utf8SafeCHexEscape(absl::string_view src) {
|
| 901 |
+
return CEscapeInternal(src, true, true);
|
| 902 |
+
}
|
| 903 |
+
|
| 904 |
+
bool Base64Unescape(absl::string_view src, std::string* dest) {
|
| 905 |
+
return Base64UnescapeInternal(src.data(), src.size(), dest, kUnBase64);
|
| 906 |
+
}
|
| 907 |
+
|
| 908 |
+
bool WebSafeBase64Unescape(absl::string_view src, std::string* dest) {
|
| 909 |
+
return Base64UnescapeInternal(src.data(), src.size(), dest, kUnWebSafeBase64);
|
| 910 |
+
}
|
| 911 |
+
|
| 912 |
+
void Base64Escape(absl::string_view src, std::string* dest) {
|
| 913 |
+
strings_internal::Base64EscapeInternal(
|
| 914 |
+
reinterpret_cast<const unsigned char*>(src.data()), src.size(), dest,
|
| 915 |
+
true, strings_internal::kBase64Chars);
|
| 916 |
+
}
|
| 917 |
+
|
| 918 |
+
void WebSafeBase64Escape(absl::string_view src, std::string* dest) {
|
| 919 |
+
strings_internal::Base64EscapeInternal(
|
| 920 |
+
reinterpret_cast<const unsigned char*>(src.data()), src.size(), dest,
|
| 921 |
+
false, strings_internal::kWebSafeBase64Chars);
|
| 922 |
+
}
|
| 923 |
+
|
| 924 |
+
std::string Base64Escape(absl::string_view src) {
|
| 925 |
+
std::string dest;
|
| 926 |
+
strings_internal::Base64EscapeInternal(
|
| 927 |
+
reinterpret_cast<const unsigned char*>(src.data()), src.size(), &dest,
|
| 928 |
+
true, strings_internal::kBase64Chars);
|
| 929 |
+
return dest;
|
| 930 |
+
}
|
| 931 |
+
|
| 932 |
+
std::string WebSafeBase64Escape(absl::string_view src) {
|
| 933 |
+
std::string dest;
|
| 934 |
+
strings_internal::Base64EscapeInternal(
|
| 935 |
+
reinterpret_cast<const unsigned char*>(src.data()), src.size(), &dest,
|
| 936 |
+
false, strings_internal::kWebSafeBase64Chars);
|
| 937 |
+
return dest;
|
| 938 |
+
}
|
| 939 |
+
|
| 940 |
+
std::string HexStringToBytes(absl::string_view from) {
|
| 941 |
+
std::string result;
|
| 942 |
+
const auto num = from.size() / 2;
|
| 943 |
+
strings_internal::STLStringResizeUninitialized(&result, num);
|
| 944 |
+
absl::HexStringToBytesInternal<std::string&>(from.data(), result, num);
|
| 945 |
+
return result;
|
| 946 |
+
}
|
| 947 |
+
|
| 948 |
+
std::string BytesToHexString(absl::string_view from) {
|
| 949 |
+
std::string result;
|
| 950 |
+
strings_internal::STLStringResizeUninitialized(&result, 2 * from.size());
|
| 951 |
+
absl::BytesToHexStringInternal<std::string&>(
|
| 952 |
+
reinterpret_cast<const unsigned char*>(from.data()), result, from.size());
|
| 953 |
+
return result;
|
| 954 |
+
}
|
| 955 |
+
|
| 956 |
+
ABSL_NAMESPACE_END
|
| 957 |
+
} // namespace absl
|
weight/_dep/abseil-cpp/absl/strings/escaping_test.cc
ADDED
|
@@ -0,0 +1,714 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
// Copyright 2017 The Abseil Authors.
|
| 2 |
+
//
|
| 3 |
+
// Licensed under the Apache License, Version 2.0 (the "License");
|
| 4 |
+
// you may not use this file except in compliance with the License.
|
| 5 |
+
// You may obtain a copy of the License at
|
| 6 |
+
//
|
| 7 |
+
// https://www.apache.org/licenses/LICENSE-2.0
|
| 8 |
+
//
|
| 9 |
+
// Unless required by applicable law or agreed to in writing, software
|
| 10 |
+
// distributed under the License is distributed on an "AS IS" BASIS,
|
| 11 |
+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
| 12 |
+
// See the License for the specific language governing permissions and
|
| 13 |
+
// limitations under the License.
|
| 14 |
+
|
| 15 |
+
#include "absl/strings/escaping.h"
|
| 16 |
+
|
| 17 |
+
#include <array>
|
| 18 |
+
#include <cstddef>
|
| 19 |
+
#include <cstdio>
|
| 20 |
+
#include <cstring>
|
| 21 |
+
#include <initializer_list>
|
| 22 |
+
#include <memory>
|
| 23 |
+
#include <string>
|
| 24 |
+
#include <vector>
|
| 25 |
+
|
| 26 |
+
#include "gtest/gtest.h"
|
| 27 |
+
#include "absl/log/check.h"
|
| 28 |
+
#include "absl/strings/str_cat.h"
|
| 29 |
+
|
| 30 |
+
#include "absl/strings/internal/escaping_test_common.h"
|
| 31 |
+
#include "absl/strings/string_view.h"
|
| 32 |
+
|
| 33 |
+
namespace {
|
| 34 |
+
|
| 35 |
+
struct epair {
|
| 36 |
+
std::string escaped;
|
| 37 |
+
std::string unescaped;
|
| 38 |
+
};
|
| 39 |
+
|
| 40 |
+
TEST(CEscape, EscapeAndUnescape) {
|
| 41 |
+
const std::string inputs[] = {
|
| 42 |
+
std::string("foo\nxx\r\b\0023"),
|
| 43 |
+
std::string(""),
|
| 44 |
+
std::string("abc"),
|
| 45 |
+
std::string("\1chad_rules"),
|
| 46 |
+
std::string("\1arnar_drools"),
|
| 47 |
+
std::string("xxxx\r\t'\"\\"),
|
| 48 |
+
std::string("\0xx\0", 4),
|
| 49 |
+
std::string("\x01\x31"),
|
| 50 |
+
std::string("abc\xb\x42\141bc"),
|
| 51 |
+
std::string("123\1\x31\x32\x33"),
|
| 52 |
+
std::string("\xc1\xca\x1b\x62\x19o\xcc\x04"),
|
| 53 |
+
std::string(
|
| 54 |
+
"\\\"\xe8\xb0\xb7\xe6\xad\x8c\\\" is Google\\\'s Chinese name"),
|
| 55 |
+
};
|
| 56 |
+
// Do this twice, once for octal escapes and once for hex escapes.
|
| 57 |
+
for (int kind = 0; kind < 4; kind++) {
|
| 58 |
+
for (const std::string& original : inputs) {
|
| 59 |
+
std::string escaped;
|
| 60 |
+
switch (kind) {
|
| 61 |
+
case 0:
|
| 62 |
+
escaped = absl::CEscape(original);
|
| 63 |
+
break;
|
| 64 |
+
case 1:
|
| 65 |
+
escaped = absl::CHexEscape(original);
|
| 66 |
+
break;
|
| 67 |
+
case 2:
|
| 68 |
+
escaped = absl::Utf8SafeCEscape(original);
|
| 69 |
+
break;
|
| 70 |
+
case 3:
|
| 71 |
+
escaped = absl::Utf8SafeCHexEscape(original);
|
| 72 |
+
break;
|
| 73 |
+
}
|
| 74 |
+
std::string unescaped_str;
|
| 75 |
+
EXPECT_TRUE(absl::CUnescape(escaped, &unescaped_str));
|
| 76 |
+
EXPECT_EQ(unescaped_str, original);
|
| 77 |
+
|
| 78 |
+
unescaped_str.erase();
|
| 79 |
+
std::string error;
|
| 80 |
+
EXPECT_TRUE(absl::CUnescape(escaped, &unescaped_str, &error));
|
| 81 |
+
EXPECT_EQ(error, "");
|
| 82 |
+
|
| 83 |
+
// Check in-place unescaping
|
| 84 |
+
std::string s = escaped;
|
| 85 |
+
EXPECT_TRUE(absl::CUnescape(s, &s));
|
| 86 |
+
ASSERT_EQ(s, original);
|
| 87 |
+
}
|
| 88 |
+
}
|
| 89 |
+
// Check that all possible two character strings can be escaped then
|
| 90 |
+
// unescaped successfully.
|
| 91 |
+
for (int char0 = 0; char0 < 256; char0++) {
|
| 92 |
+
for (int char1 = 0; char1 < 256; char1++) {
|
| 93 |
+
char chars[2];
|
| 94 |
+
chars[0] = char0;
|
| 95 |
+
chars[1] = char1;
|
| 96 |
+
std::string s(chars, 2);
|
| 97 |
+
std::string escaped = absl::CHexEscape(s);
|
| 98 |
+
std::string unescaped;
|
| 99 |
+
EXPECT_TRUE(absl::CUnescape(escaped, &unescaped));
|
| 100 |
+
EXPECT_EQ(s, unescaped);
|
| 101 |
+
}
|
| 102 |
+
}
|
| 103 |
+
}
|
| 104 |
+
|
| 105 |
+
TEST(CEscape, BasicEscaping) {
|
| 106 |
+
epair oct_values[] = {
|
| 107 |
+
{"foo\\rbar\\nbaz\\t", "foo\rbar\nbaz\t"},
|
| 108 |
+
{"\\'full of \\\"sound\\\" and \\\"fury\\\"\\'",
|
| 109 |
+
"'full of \"sound\" and \"fury\"'"},
|
| 110 |
+
{"signi\\\\fying\\\\ nothing\\\\", "signi\\fying\\ nothing\\"},
|
| 111 |
+
{"\\010\\t\\n\\013\\014\\r", "\010\011\012\013\014\015"}
|
| 112 |
+
};
|
| 113 |
+
epair hex_values[] = {
|
| 114 |
+
{"ubik\\rubik\\nubik\\t", "ubik\rubik\nubik\t"},
|
| 115 |
+
{"I\\\'ve just seen a \\\"face\\\"",
|
| 116 |
+
"I've just seen a \"face\""},
|
| 117 |
+
{"hel\\\\ter\\\\skel\\\\ter\\\\", "hel\\ter\\skel\\ter\\"},
|
| 118 |
+
{"\\x08\\t\\n\\x0b\\x0c\\r", "\010\011\012\013\014\015"}
|
| 119 |
+
};
|
| 120 |
+
epair utf8_oct_values[] = {
|
| 121 |
+
{"\xe8\xb0\xb7\xe6\xad\x8c\\r\xe8\xb0\xb7\xe6\xad\x8c\\nbaz\\t",
|
| 122 |
+
"\xe8\xb0\xb7\xe6\xad\x8c\r\xe8\xb0\xb7\xe6\xad\x8c\nbaz\t"},
|
| 123 |
+
{"\\\"\xe8\xb0\xb7\xe6\xad\x8c\\\" is Google\\\'s Chinese name",
|
| 124 |
+
"\"\xe8\xb0\xb7\xe6\xad\x8c\" is Google\'s Chinese name"},
|
| 125 |
+
{"\xe3\x83\xa1\xe3\x83\xbc\xe3\x83\xab\\\\are\\\\Japanese\\\\chars\\\\",
|
| 126 |
+
"\xe3\x83\xa1\xe3\x83\xbc\xe3\x83\xab\\are\\Japanese\\chars\\"},
|
| 127 |
+
{"\xed\x81\xac\xeb\xa1\xac\\010\\t\\n\\013\\014\\r",
|
| 128 |
+
"\xed\x81\xac\xeb\xa1\xac\010\011\012\013\014\015"}
|
| 129 |
+
};
|
| 130 |
+
epair utf8_hex_values[] = {
|
| 131 |
+
{"\x20\xe4\xbd\xa0\\t\xe5\xa5\xbd,\\r!\\n",
|
| 132 |
+
"\x20\xe4\xbd\xa0\t\xe5\xa5\xbd,\r!\n"},
|
| 133 |
+
{"\xe8\xa9\xa6\xe9\xa8\x93\\\' means \\\"test\\\"",
|
| 134 |
+
"\xe8\xa9\xa6\xe9\xa8\x93\' means \"test\""},
|
| 135 |
+
{"\\\\\xe6\x88\x91\\\\:\\\\\xe6\x9d\xa8\xe6\xac\xa2\\\\",
|
| 136 |
+
"\\\xe6\x88\x91\\:\\\xe6\x9d\xa8\xe6\xac\xa2\\"},
|
| 137 |
+
{"\xed\x81\xac\xeb\xa1\xac\\x08\\t\\n\\x0b\\x0c\\r",
|
| 138 |
+
"\xed\x81\xac\xeb\xa1\xac\010\011\012\013\014\015"}
|
| 139 |
+
};
|
| 140 |
+
|
| 141 |
+
for (const epair& val : oct_values) {
|
| 142 |
+
std::string escaped = absl::CEscape(val.unescaped);
|
| 143 |
+
EXPECT_EQ(escaped, val.escaped);
|
| 144 |
+
}
|
| 145 |
+
for (const epair& val : hex_values) {
|
| 146 |
+
std::string escaped = absl::CHexEscape(val.unescaped);
|
| 147 |
+
EXPECT_EQ(escaped, val.escaped);
|
| 148 |
+
}
|
| 149 |
+
for (const epair& val : utf8_oct_values) {
|
| 150 |
+
std::string escaped = absl::Utf8SafeCEscape(val.unescaped);
|
| 151 |
+
EXPECT_EQ(escaped, val.escaped);
|
| 152 |
+
}
|
| 153 |
+
for (const epair& val : utf8_hex_values) {
|
| 154 |
+
std::string escaped = absl::Utf8SafeCHexEscape(val.unescaped);
|
| 155 |
+
EXPECT_EQ(escaped, val.escaped);
|
| 156 |
+
}
|
| 157 |
+
}
|
| 158 |
+
|
| 159 |
+
TEST(Unescape, BasicFunction) {
|
| 160 |
+
epair tests[] =
|
| 161 |
+
{{"", ""},
|
| 162 |
+
{"\\u0030", "0"},
|
| 163 |
+
{"\\u00A3", "\xC2\xA3"},
|
| 164 |
+
{"\\u22FD", "\xE2\x8B\xBD"},
|
| 165 |
+
{"\\U00010000", "\xF0\x90\x80\x80"},
|
| 166 |
+
{"\\U0010FFFD", "\xF4\x8F\xBF\xBD"}};
|
| 167 |
+
for (const epair& val : tests) {
|
| 168 |
+
std::string out;
|
| 169 |
+
EXPECT_TRUE(absl::CUnescape(val.escaped, &out));
|
| 170 |
+
EXPECT_EQ(out, val.unescaped);
|
| 171 |
+
}
|
| 172 |
+
std::string bad[] = {"\\u1", // too short
|
| 173 |
+
"\\U1", // too short
|
| 174 |
+
"\\Uffffff", // exceeds 0x10ffff (largest Unicode)
|
| 175 |
+
"\\U00110000", // exceeds 0x10ffff (largest Unicode)
|
| 176 |
+
"\\uD835", // surrogate character (D800-DFFF)
|
| 177 |
+
"\\U0000DD04", // surrogate character (D800-DFFF)
|
| 178 |
+
"\\777", // exceeds 0xff
|
| 179 |
+
"\\xABCD"}; // exceeds 0xff
|
| 180 |
+
for (const std::string& e : bad) {
|
| 181 |
+
std::string error;
|
| 182 |
+
std::string out;
|
| 183 |
+
EXPECT_FALSE(absl::CUnescape(e, &out, &error));
|
| 184 |
+
EXPECT_FALSE(error.empty());
|
| 185 |
+
|
| 186 |
+
out.erase();
|
| 187 |
+
EXPECT_FALSE(absl::CUnescape(e, &out));
|
| 188 |
+
}
|
| 189 |
+
}
|
| 190 |
+
|
| 191 |
+
class CUnescapeTest : public testing::Test {
|
| 192 |
+
protected:
|
| 193 |
+
static const char kStringWithMultipleOctalNulls[];
|
| 194 |
+
static const char kStringWithMultipleHexNulls[];
|
| 195 |
+
static const char kStringWithMultipleUnicodeNulls[];
|
| 196 |
+
|
| 197 |
+
std::string result_string_;
|
| 198 |
+
};
|
| 199 |
+
|
| 200 |
+
const char CUnescapeTest::kStringWithMultipleOctalNulls[] =
|
| 201 |
+
"\\0\\n" // null escape \0 plus newline
|
| 202 |
+
"0\\n" // just a number 0 (not a null escape) plus newline
|
| 203 |
+
"\\00\\12" // null escape \00 plus octal newline code
|
| 204 |
+
"\\000"; // null escape \000
|
| 205 |
+
|
| 206 |
+
// This has the same ingredients as kStringWithMultipleOctalNulls
|
| 207 |
+
// but with \x hex escapes instead of octal escapes.
|
| 208 |
+
const char CUnescapeTest::kStringWithMultipleHexNulls[] =
|
| 209 |
+
"\\x0\\n"
|
| 210 |
+
"0\\n"
|
| 211 |
+
"\\x00\\xa"
|
| 212 |
+
"\\x000";
|
| 213 |
+
|
| 214 |
+
const char CUnescapeTest::kStringWithMultipleUnicodeNulls[] =
|
| 215 |
+
"\\u0000\\n" // short-form (4-digit) null escape plus newline
|
| 216 |
+
"0\\n" // just a number 0 (not a null escape) plus newline
|
| 217 |
+
"\\U00000000"; // long-form (8-digit) null escape
|
| 218 |
+
|
| 219 |
+
TEST_F(CUnescapeTest, Unescapes1CharOctalNull) {
|
| 220 |
+
std::string original_string = "\\0";
|
| 221 |
+
EXPECT_TRUE(absl::CUnescape(original_string, &result_string_));
|
| 222 |
+
EXPECT_EQ(std::string("\0", 1), result_string_);
|
| 223 |
+
}
|
| 224 |
+
|
| 225 |
+
TEST_F(CUnescapeTest, Unescapes2CharOctalNull) {
|
| 226 |
+
std::string original_string = "\\00";
|
| 227 |
+
EXPECT_TRUE(absl::CUnescape(original_string, &result_string_));
|
| 228 |
+
EXPECT_EQ(std::string("\0", 1), result_string_);
|
| 229 |
+
}
|
| 230 |
+
|
| 231 |
+
TEST_F(CUnescapeTest, Unescapes3CharOctalNull) {
|
| 232 |
+
std::string original_string = "\\000";
|
| 233 |
+
EXPECT_TRUE(absl::CUnescape(original_string, &result_string_));
|
| 234 |
+
EXPECT_EQ(std::string("\0", 1), result_string_);
|
| 235 |
+
}
|
| 236 |
+
|
| 237 |
+
TEST_F(CUnescapeTest, Unescapes1CharHexNull) {
|
| 238 |
+
std::string original_string = "\\x0";
|
| 239 |
+
EXPECT_TRUE(absl::CUnescape(original_string, &result_string_));
|
| 240 |
+
EXPECT_EQ(std::string("\0", 1), result_string_);
|
| 241 |
+
}
|
| 242 |
+
|
| 243 |
+
TEST_F(CUnescapeTest, Unescapes2CharHexNull) {
|
| 244 |
+
std::string original_string = "\\x00";
|
| 245 |
+
EXPECT_TRUE(absl::CUnescape(original_string, &result_string_));
|
| 246 |
+
EXPECT_EQ(std::string("\0", 1), result_string_);
|
| 247 |
+
}
|
| 248 |
+
|
| 249 |
+
TEST_F(CUnescapeTest, Unescapes3CharHexNull) {
|
| 250 |
+
std::string original_string = "\\x000";
|
| 251 |
+
EXPECT_TRUE(absl::CUnescape(original_string, &result_string_));
|
| 252 |
+
EXPECT_EQ(std::string("\0", 1), result_string_);
|
| 253 |
+
}
|
| 254 |
+
|
| 255 |
+
TEST_F(CUnescapeTest, Unescapes4CharUnicodeNull) {
|
| 256 |
+
std::string original_string = "\\u0000";
|
| 257 |
+
EXPECT_TRUE(absl::CUnescape(original_string, &result_string_));
|
| 258 |
+
EXPECT_EQ(std::string("\0", 1), result_string_);
|
| 259 |
+
}
|
| 260 |
+
|
| 261 |
+
TEST_F(CUnescapeTest, Unescapes8CharUnicodeNull) {
|
| 262 |
+
std::string original_string = "\\U00000000";
|
| 263 |
+
EXPECT_TRUE(absl::CUnescape(original_string, &result_string_));
|
| 264 |
+
EXPECT_EQ(std::string("\0", 1), result_string_);
|
| 265 |
+
}
|
| 266 |
+
|
| 267 |
+
TEST_F(CUnescapeTest, UnescapesMultipleOctalNulls) {
|
| 268 |
+
std::string original_string(kStringWithMultipleOctalNulls);
|
| 269 |
+
EXPECT_TRUE(absl::CUnescape(original_string, &result_string_));
|
| 270 |
+
// All escapes, including newlines and null escapes, should have been
|
| 271 |
+
// converted to the equivalent characters.
|
| 272 |
+
EXPECT_EQ(std::string("\0\n"
|
| 273 |
+
"0\n"
|
| 274 |
+
"\0\n"
|
| 275 |
+
"\0",
|
| 276 |
+
7),
|
| 277 |
+
result_string_);
|
| 278 |
+
}
|
| 279 |
+
|
| 280 |
+
|
| 281 |
+
TEST_F(CUnescapeTest, UnescapesMultipleHexNulls) {
|
| 282 |
+
std::string original_string(kStringWithMultipleHexNulls);
|
| 283 |
+
EXPECT_TRUE(absl::CUnescape(original_string, &result_string_));
|
| 284 |
+
EXPECT_EQ(std::string("\0\n"
|
| 285 |
+
"0\n"
|
| 286 |
+
"\0\n"
|
| 287 |
+
"\0",
|
| 288 |
+
7),
|
| 289 |
+
result_string_);
|
| 290 |
+
}
|
| 291 |
+
|
| 292 |
+
TEST_F(CUnescapeTest, UnescapesMultipleUnicodeNulls) {
|
| 293 |
+
std::string original_string(kStringWithMultipleUnicodeNulls);
|
| 294 |
+
EXPECT_TRUE(absl::CUnescape(original_string, &result_string_));
|
| 295 |
+
EXPECT_EQ(std::string("\0\n"
|
| 296 |
+
"0\n"
|
| 297 |
+
"\0",
|
| 298 |
+
5),
|
| 299 |
+
result_string_);
|
| 300 |
+
}
|
| 301 |
+
|
| 302 |
+
static struct {
|
| 303 |
+
absl::string_view plaintext;
|
| 304 |
+
absl::string_view cyphertext;
|
| 305 |
+
} const base64_tests[] = {
|
| 306 |
+
// Empty string.
|
| 307 |
+
{{"", 0}, {"", 0}},
|
| 308 |
+
{{nullptr, 0},
|
| 309 |
+
{"", 0}}, // if length is zero, plaintext ptr must be ignored!
|
| 310 |
+
|
| 311 |
+
// Basic bit patterns;
|
| 312 |
+
// values obtained with "echo -n '...' | uuencode -m test"
|
| 313 |
+
|
| 314 |
+
{{"\000", 1}, "AA=="},
|
| 315 |
+
{{"\001", 1}, "AQ=="},
|
| 316 |
+
{{"\002", 1}, "Ag=="},
|
| 317 |
+
{{"\004", 1}, "BA=="},
|
| 318 |
+
{{"\010", 1}, "CA=="},
|
| 319 |
+
{{"\020", 1}, "EA=="},
|
| 320 |
+
{{"\040", 1}, "IA=="},
|
| 321 |
+
{{"\100", 1}, "QA=="},
|
| 322 |
+
{{"\200", 1}, "gA=="},
|
| 323 |
+
|
| 324 |
+
{{"\377", 1}, "/w=="},
|
| 325 |
+
{{"\376", 1}, "/g=="},
|
| 326 |
+
{{"\375", 1}, "/Q=="},
|
| 327 |
+
{{"\373", 1}, "+w=="},
|
| 328 |
+
{{"\367", 1}, "9w=="},
|
| 329 |
+
{{"\357", 1}, "7w=="},
|
| 330 |
+
{{"\337", 1}, "3w=="},
|
| 331 |
+
{{"\277", 1}, "vw=="},
|
| 332 |
+
{{"\177", 1}, "fw=="},
|
| 333 |
+
{{"\000\000", 2}, "AAA="},
|
| 334 |
+
{{"\000\001", 2}, "AAE="},
|
| 335 |
+
{{"\000\002", 2}, "AAI="},
|
| 336 |
+
{{"\000\004", 2}, "AAQ="},
|
| 337 |
+
{{"\000\010", 2}, "AAg="},
|
| 338 |
+
{{"\000\020", 2}, "ABA="},
|
| 339 |
+
{{"\000\040", 2}, "ACA="},
|
| 340 |
+
{{"\000\100", 2}, "AEA="},
|
| 341 |
+
{{"\000\200", 2}, "AIA="},
|
| 342 |
+
{{"\001\000", 2}, "AQA="},
|
| 343 |
+
{{"\002\000", 2}, "AgA="},
|
| 344 |
+
{{"\004\000", 2}, "BAA="},
|
| 345 |
+
{{"\010\000", 2}, "CAA="},
|
| 346 |
+
{{"\020\000", 2}, "EAA="},
|
| 347 |
+
{{"\040\000", 2}, "IAA="},
|
| 348 |
+
{{"\100\000", 2}, "QAA="},
|
| 349 |
+
{{"\200\000", 2}, "gAA="},
|
| 350 |
+
|
| 351 |
+
{{"\377\377", 2}, "//8="},
|
| 352 |
+
{{"\377\376", 2}, "//4="},
|
| 353 |
+
{{"\377\375", 2}, "//0="},
|
| 354 |
+
{{"\377\373", 2}, "//s="},
|
| 355 |
+
{{"\377\367", 2}, "//c="},
|
| 356 |
+
{{"\377\357", 2}, "/+8="},
|
| 357 |
+
{{"\377\337", 2}, "/98="},
|
| 358 |
+
{{"\377\277", 2}, "/78="},
|
| 359 |
+
{{"\377\177", 2}, "/38="},
|
| 360 |
+
{{"\376\377", 2}, "/v8="},
|
| 361 |
+
{{"\375\377", 2}, "/f8="},
|
| 362 |
+
{{"\373\377", 2}, "+/8="},
|
| 363 |
+
{{"\367\377", 2}, "9/8="},
|
| 364 |
+
{{"\357\377", 2}, "7/8="},
|
| 365 |
+
{{"\337\377", 2}, "3/8="},
|
| 366 |
+
{{"\277\377", 2}, "v/8="},
|
| 367 |
+
{{"\177\377", 2}, "f/8="},
|
| 368 |
+
|
| 369 |
+
{{"\000\000\000", 3}, "AAAA"},
|
| 370 |
+
{{"\000\000\001", 3}, "AAAB"},
|
| 371 |
+
{{"\000\000\002", 3}, "AAAC"},
|
| 372 |
+
{{"\000\000\004", 3}, "AAAE"},
|
| 373 |
+
{{"\000\000\010", 3}, "AAAI"},
|
| 374 |
+
{{"\000\000\020", 3}, "AAAQ"},
|
| 375 |
+
{{"\000\000\040", 3}, "AAAg"},
|
| 376 |
+
{{"\000\000\100", 3}, "AABA"},
|
| 377 |
+
{{"\000\000\200", 3}, "AACA"},
|
| 378 |
+
{{"\000\001\000", 3}, "AAEA"},
|
| 379 |
+
{{"\000\002\000", 3}, "AAIA"},
|
| 380 |
+
{{"\000\004\000", 3}, "AAQA"},
|
| 381 |
+
{{"\000\010\000", 3}, "AAgA"},
|
| 382 |
+
{{"\000\020\000", 3}, "ABAA"},
|
| 383 |
+
{{"\000\040\000", 3}, "ACAA"},
|
| 384 |
+
{{"\000\100\000", 3}, "AEAA"},
|
| 385 |
+
{{"\000\200\000", 3}, "AIAA"},
|
| 386 |
+
{{"\001\000\000", 3}, "AQAA"},
|
| 387 |
+
{{"\002\000\000", 3}, "AgAA"},
|
| 388 |
+
{{"\004\000\000", 3}, "BAAA"},
|
| 389 |
+
{{"\010\000\000", 3}, "CAAA"},
|
| 390 |
+
{{"\020\000\000", 3}, "EAAA"},
|
| 391 |
+
{{"\040\000\000", 3}, "IAAA"},
|
| 392 |
+
{{"\100\000\000", 3}, "QAAA"},
|
| 393 |
+
{{"\200\000\000", 3}, "gAAA"},
|
| 394 |
+
|
| 395 |
+
{{"\377\377\377", 3}, "////"},
|
| 396 |
+
{{"\377\377\376", 3}, "///+"},
|
| 397 |
+
{{"\377\377\375", 3}, "///9"},
|
| 398 |
+
{{"\377\377\373", 3}, "///7"},
|
| 399 |
+
{{"\377\377\367", 3}, "///3"},
|
| 400 |
+
{{"\377\377\357", 3}, "///v"},
|
| 401 |
+
{{"\377\377\337", 3}, "///f"},
|
| 402 |
+
{{"\377\377\277", 3}, "//+/"},
|
| 403 |
+
{{"\377\377\177", 3}, "//9/"},
|
| 404 |
+
{{"\377\376\377", 3}, "//7/"},
|
| 405 |
+
{{"\377\375\377", 3}, "//3/"},
|
| 406 |
+
{{"\377\373\377", 3}, "//v/"},
|
| 407 |
+
{{"\377\367\377", 3}, "//f/"},
|
| 408 |
+
{{"\377\357\377", 3}, "/+//"},
|
| 409 |
+
{{"\377\337\377", 3}, "/9//"},
|
| 410 |
+
{{"\377\277\377", 3}, "/7//"},
|
| 411 |
+
{{"\377\177\377", 3}, "/3//"},
|
| 412 |
+
{{"\376\377\377", 3}, "/v//"},
|
| 413 |
+
{{"\375\377\377", 3}, "/f//"},
|
| 414 |
+
{{"\373\377\377", 3}, "+///"},
|
| 415 |
+
{{"\367\377\377", 3}, "9///"},
|
| 416 |
+
{{"\357\377\377", 3}, "7///"},
|
| 417 |
+
{{"\337\377\377", 3}, "3///"},
|
| 418 |
+
{{"\277\377\377", 3}, "v///"},
|
| 419 |
+
{{"\177\377\377", 3}, "f///"},
|
| 420 |
+
|
| 421 |
+
// Random numbers: values obtained with
|
| 422 |
+
//
|
| 423 |
+
// #! /bin/bash
|
| 424 |
+
// dd bs=$1 count=1 if=/dev/random of=/tmp/bar.random
|
| 425 |
+
// od -N $1 -t o1 /tmp/bar.random
|
| 426 |
+
// uuencode -m test < /tmp/bar.random
|
| 427 |
+
//
|
| 428 |
+
// where $1 is the number of bytes (2, 3)
|
| 429 |
+
|
| 430 |
+
{{"\243\361", 2}, "o/E="},
|
| 431 |
+
{{"\024\167", 2}, "FHc="},
|
| 432 |
+
{{"\313\252", 2}, "y6o="},
|
| 433 |
+
{{"\046\041", 2}, "JiE="},
|
| 434 |
+
{{"\145\236", 2}, "ZZ4="},
|
| 435 |
+
{{"\254\325", 2}, "rNU="},
|
| 436 |
+
{{"\061\330", 2}, "Mdg="},
|
| 437 |
+
{{"\245\032", 2}, "pRo="},
|
| 438 |
+
{{"\006\000", 2}, "BgA="},
|
| 439 |
+
{{"\375\131", 2}, "/Vk="},
|
| 440 |
+
{{"\303\210", 2}, "w4g="},
|
| 441 |
+
{{"\040\037", 2}, "IB8="},
|
| 442 |
+
{{"\261\372", 2}, "sfo="},
|
| 443 |
+
{{"\335\014", 2}, "3Qw="},
|
| 444 |
+
{{"\233\217", 2}, "m48="},
|
| 445 |
+
{{"\373\056", 2}, "+y4="},
|
| 446 |
+
{{"\247\232", 2}, "p5o="},
|
| 447 |
+
{{"\107\053", 2}, "Rys="},
|
| 448 |
+
{{"\204\077", 2}, "hD8="},
|
| 449 |
+
{{"\276\211", 2}, "vok="},
|
| 450 |
+
{{"\313\110", 2}, "y0g="},
|
| 451 |
+
{{"\363\376", 2}, "8/4="},
|
| 452 |
+
{{"\251\234", 2}, "qZw="},
|
| 453 |
+
{{"\103\262", 2}, "Q7I="},
|
| 454 |
+
{{"\142\312", 2}, "Yso="},
|
| 455 |
+
{{"\067\211", 2}, "N4k="},
|
| 456 |
+
{{"\220\001", 2}, "kAE="},
|
| 457 |
+
{{"\152\240", 2}, "aqA="},
|
| 458 |
+
{{"\367\061", 2}, "9zE="},
|
| 459 |
+
{{"\133\255", 2}, "W60="},
|
| 460 |
+
{{"\176\035", 2}, "fh0="},
|
| 461 |
+
{{"\032\231", 2}, "Gpk="},
|
| 462 |
+
|
| 463 |
+
{{"\013\007\144", 3}, "Cwdk"},
|
| 464 |
+
{{"\030\112\106", 3}, "GEpG"},
|
| 465 |
+
{{"\047\325\046", 3}, "J9Um"},
|
| 466 |
+
{{"\310\160\022", 3}, "yHAS"},
|
| 467 |
+
{{"\131\100\237", 3}, "WUCf"},
|
| 468 |
+
{{"\064\342\134", 3}, "NOJc"},
|
| 469 |
+
{{"\010\177\004", 3}, "CH8E"},
|
| 470 |
+
{{"\345\147\205", 3}, "5WeF"},
|
| 471 |
+
{{"\300\343\360", 3}, "wOPw"},
|
| 472 |
+
{{"\061\240\201", 3}, "MaCB"},
|
| 473 |
+
{{"\225\333\044", 3}, "ldsk"},
|
| 474 |
+
{{"\215\137\352", 3}, "jV/q"},
|
| 475 |
+
{{"\371\147\160", 3}, "+Wdw"},
|
| 476 |
+
{{"\030\320\051", 3}, "GNAp"},
|
| 477 |
+
{{"\044\174\241", 3}, "JHyh"},
|
| 478 |
+
{{"\260\127\037", 3}, "sFcf"},
|
| 479 |
+
{{"\111\045\033", 3}, "SSUb"},
|
| 480 |
+
{{"\202\114\107", 3}, "gkxH"},
|
| 481 |
+
{{"\057\371\042", 3}, "L/ki"},
|
| 482 |
+
{{"\223\247\244", 3}, "k6ek"},
|
| 483 |
+
{{"\047\216\144", 3}, "J45k"},
|
| 484 |
+
{{"\203\070\327", 3}, "gzjX"},
|
| 485 |
+
{{"\247\140\072", 3}, "p2A6"},
|
| 486 |
+
{{"\124\115\116", 3}, "VE1O"},
|
| 487 |
+
{{"\157\162\050", 3}, "b3Io"},
|
| 488 |
+
{{"\357\223\004", 3}, "75ME"},
|
| 489 |
+
{{"\052\117\156", 3}, "Kk9u"},
|
| 490 |
+
{{"\347\154\000", 3}, "52wA"},
|
| 491 |
+
{{"\303\012\142", 3}, "wwpi"},
|
| 492 |
+
{{"\060\035\362", 3}, "MB3y"},
|
| 493 |
+
{{"\130\226\361", 3}, "WJbx"},
|
| 494 |
+
{{"\173\013\071", 3}, "ews5"},
|
| 495 |
+
{{"\336\004\027", 3}, "3gQX"},
|
| 496 |
+
{{"\357\366\234", 3}, "7/ac"},
|
| 497 |
+
{{"\353\304\111", 3}, "68RJ"},
|
| 498 |
+
{{"\024\264\131", 3}, "FLRZ"},
|
| 499 |
+
{{"\075\114\251", 3}, "PUyp"},
|
| 500 |
+
{{"\315\031\225", 3}, "zRmV"},
|
| 501 |
+
{{"\154\201\276", 3}, "bIG+"},
|
| 502 |
+
{{"\200\066\072", 3}, "gDY6"},
|
| 503 |
+
{{"\142\350\267", 3}, "Yui3"},
|
| 504 |
+
{{"\033\000\166", 3}, "GwB2"},
|
| 505 |
+
{{"\210\055\077", 3}, "iC0/"},
|
| 506 |
+
{{"\341\037\124", 3}, "4R9U"},
|
| 507 |
+
{{"\161\103\152", 3}, "cUNq"},
|
| 508 |
+
{{"\270\142\131", 3}, "uGJZ"},
|
| 509 |
+
{{"\337\076\074", 3}, "3z48"},
|
| 510 |
+
{{"\375\106\362", 3}, "/Uby"},
|
| 511 |
+
{{"\227\301\127", 3}, "l8FX"},
|
| 512 |
+
{{"\340\002\234", 3}, "4AKc"},
|
| 513 |
+
{{"\121\064\033", 3}, "UTQb"},
|
| 514 |
+
{{"\157\134\143", 3}, "b1xj"},
|
| 515 |
+
{{"\247\055\327", 3}, "py3X"},
|
| 516 |
+
{{"\340\142\005", 3}, "4GIF"},
|
| 517 |
+
{{"\060\260\143", 3}, "MLBj"},
|
| 518 |
+
{{"\075\203\170", 3}, "PYN4"},
|
| 519 |
+
{{"\143\160\016", 3}, "Y3AO"},
|
| 520 |
+
{{"\313\013\063", 3}, "ywsz"},
|
| 521 |
+
{{"\174\236\135", 3}, "fJ5d"},
|
| 522 |
+
{{"\103\047\026", 3}, "QycW"},
|
| 523 |
+
{{"\365\005\343", 3}, "9QXj"},
|
| 524 |
+
{{"\271\160\223", 3}, "uXCT"},
|
| 525 |
+
{{"\362\255\172", 3}, "8q16"},
|
| 526 |
+
{{"\113\012\015", 3}, "SwoN"},
|
| 527 |
+
|
| 528 |
+
// various lengths, generated by this python script:
|
| 529 |
+
//
|
| 530 |
+
// from std::string import lowercase as lc
|
| 531 |
+
// for i in range(27):
|
| 532 |
+
// print '{ %2d, "%s",%s "%s" },' % (i, lc[:i], ' ' * (26-i),
|
| 533 |
+
// lc[:i].encode('base64').strip())
|
| 534 |
+
|
| 535 |
+
{{"", 0}, {"", 0}},
|
| 536 |
+
{"a", "YQ=="},
|
| 537 |
+
{"ab", "YWI="},
|
| 538 |
+
{"abc", "YWJj"},
|
| 539 |
+
{"abcd", "YWJjZA=="},
|
| 540 |
+
{"abcde", "YWJjZGU="},
|
| 541 |
+
{"abcdef", "YWJjZGVm"},
|
| 542 |
+
{"abcdefg", "YWJjZGVmZw=="},
|
| 543 |
+
{"abcdefgh", "YWJjZGVmZ2g="},
|
| 544 |
+
{"abcdefghi", "YWJjZGVmZ2hp"},
|
| 545 |
+
{"abcdefghij", "YWJjZGVmZ2hpag=="},
|
| 546 |
+
{"abcdefghijk", "YWJjZGVmZ2hpams="},
|
| 547 |
+
{"abcdefghijkl", "YWJjZGVmZ2hpamts"},
|
| 548 |
+
{"abcdefghijklm", "YWJjZGVmZ2hpamtsbQ=="},
|
| 549 |
+
{"abcdefghijklmn", "YWJjZGVmZ2hpamtsbW4="},
|
| 550 |
+
{"abcdefghijklmno", "YWJjZGVmZ2hpamtsbW5v"},
|
| 551 |
+
{"abcdefghijklmnop", "YWJjZGVmZ2hpamtsbW5vcA=="},
|
| 552 |
+
{"abcdefghijklmnopq", "YWJjZGVmZ2hpamtsbW5vcHE="},
|
| 553 |
+
{"abcdefghijklmnopqr", "YWJjZGVmZ2hpamtsbW5vcHFy"},
|
| 554 |
+
{"abcdefghijklmnopqrs", "YWJjZGVmZ2hpamtsbW5vcHFycw=="},
|
| 555 |
+
{"abcdefghijklmnopqrst", "YWJjZGVmZ2hpamtsbW5vcHFyc3Q="},
|
| 556 |
+
{"abcdefghijklmnopqrstu", "YWJjZGVmZ2hpamtsbW5vcHFyc3R1"},
|
| 557 |
+
{"abcdefghijklmnopqrstuv", "YWJjZGVmZ2hpamtsbW5vcHFyc3R1dg=="},
|
| 558 |
+
{"abcdefghijklmnopqrstuvw", "YWJjZGVmZ2hpamtsbW5vcHFyc3R1dnc="},
|
| 559 |
+
{"abcdefghijklmnopqrstuvwx", "YWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4"},
|
| 560 |
+
{"abcdefghijklmnopqrstuvwxy", "YWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eQ=="},
|
| 561 |
+
{"abcdefghijklmnopqrstuvwxyz", "YWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXo="},
|
| 562 |
+
};
|
| 563 |
+
|
| 564 |
+
template <typename StringType>
|
| 565 |
+
void TestEscapeAndUnescape() {
|
| 566 |
+
// Check the short strings; this tests the math (and boundaries)
|
| 567 |
+
for (const auto& tc : base64_tests) {
|
| 568 |
+
// Test plain base64.
|
| 569 |
+
StringType encoded("this junk should be ignored");
|
| 570 |
+
absl::Base64Escape(tc.plaintext, &encoded);
|
| 571 |
+
EXPECT_EQ(encoded, tc.cyphertext);
|
| 572 |
+
EXPECT_EQ(absl::Base64Escape(tc.plaintext), tc.cyphertext);
|
| 573 |
+
|
| 574 |
+
StringType decoded("this junk should be ignored");
|
| 575 |
+
EXPECT_TRUE(absl::Base64Unescape(encoded, &decoded));
|
| 576 |
+
EXPECT_EQ(decoded, tc.plaintext);
|
| 577 |
+
|
| 578 |
+
StringType websafe_with_padding(tc.cyphertext);
|
| 579 |
+
for (unsigned int c = 0; c < websafe_with_padding.size(); ++c) {
|
| 580 |
+
if ('+' == websafe_with_padding[c]) websafe_with_padding[c] = '-';
|
| 581 |
+
if ('/' == websafe_with_padding[c]) websafe_with_padding[c] = '_';
|
| 582 |
+
// Intentionally keeping padding aka '='.
|
| 583 |
+
}
|
| 584 |
+
|
| 585 |
+
// Test plain websafe (aka without padding).
|
| 586 |
+
StringType websafe(websafe_with_padding);
|
| 587 |
+
for (unsigned int c = 0; c < websafe.size(); ++c) {
|
| 588 |
+
if ('=' == websafe[c]) {
|
| 589 |
+
websafe.resize(c);
|
| 590 |
+
break;
|
| 591 |
+
}
|
| 592 |
+
}
|
| 593 |
+
encoded = "this junk should be ignored";
|
| 594 |
+
absl::WebSafeBase64Escape(tc.plaintext, &encoded);
|
| 595 |
+
EXPECT_EQ(encoded, websafe);
|
| 596 |
+
EXPECT_EQ(absl::WebSafeBase64Escape(tc.plaintext), websafe);
|
| 597 |
+
|
| 598 |
+
decoded = "this junk should be ignored";
|
| 599 |
+
EXPECT_TRUE(absl::WebSafeBase64Unescape(websafe, &decoded));
|
| 600 |
+
EXPECT_EQ(decoded, tc.plaintext);
|
| 601 |
+
}
|
| 602 |
+
|
| 603 |
+
// Now try the long strings, this tests the streaming
|
| 604 |
+
for (const auto& tc : absl::strings_internal::base64_strings()) {
|
| 605 |
+
StringType buffer;
|
| 606 |
+
absl::WebSafeBase64Escape(tc.plaintext, &buffer);
|
| 607 |
+
EXPECT_EQ(tc.cyphertext, buffer);
|
| 608 |
+
EXPECT_EQ(absl::WebSafeBase64Escape(tc.plaintext), tc.cyphertext);
|
| 609 |
+
}
|
| 610 |
+
|
| 611 |
+
// Verify the behavior when decoding bad data
|
| 612 |
+
{
|
| 613 |
+
absl::string_view data_set[] = {"ab-/", absl::string_view("\0bcd", 4),
|
| 614 |
+
absl::string_view("abc.\0", 5)};
|
| 615 |
+
for (absl::string_view bad_data : data_set) {
|
| 616 |
+
StringType buf;
|
| 617 |
+
EXPECT_FALSE(absl::Base64Unescape(bad_data, &buf));
|
| 618 |
+
EXPECT_FALSE(absl::WebSafeBase64Unescape(bad_data, &buf));
|
| 619 |
+
EXPECT_TRUE(buf.empty());
|
| 620 |
+
}
|
| 621 |
+
}
|
| 622 |
+
}
|
| 623 |
+
|
| 624 |
+
TEST(Base64, EscapeAndUnescape) {
|
| 625 |
+
TestEscapeAndUnescape<std::string>();
|
| 626 |
+
}
|
| 627 |
+
|
| 628 |
+
TEST(Base64, Padding) {
|
| 629 |
+
// Padding is optional.
|
| 630 |
+
// '.' is an acceptable padding character, just like '='.
|
| 631 |
+
std::initializer_list<absl::string_view> good_padding = {
|
| 632 |
+
"YQ",
|
| 633 |
+
"YQ==",
|
| 634 |
+
"YQ=.",
|
| 635 |
+
"YQ.=",
|
| 636 |
+
"YQ..",
|
| 637 |
+
};
|
| 638 |
+
for (absl::string_view b64 : good_padding) {
|
| 639 |
+
std::string decoded;
|
| 640 |
+
EXPECT_TRUE(absl::Base64Unescape(b64, &decoded));
|
| 641 |
+
EXPECT_EQ(decoded, "a");
|
| 642 |
+
std::string websafe_decoded;
|
| 643 |
+
EXPECT_TRUE(absl::WebSafeBase64Unescape(b64, &websafe_decoded));
|
| 644 |
+
EXPECT_EQ(websafe_decoded, "a");
|
| 645 |
+
}
|
| 646 |
+
std::initializer_list<absl::string_view> bad_padding = {
|
| 647 |
+
"YQ=",
|
| 648 |
+
"YQ.",
|
| 649 |
+
"YQ===",
|
| 650 |
+
"YQ==.",
|
| 651 |
+
"YQ=.=",
|
| 652 |
+
"YQ=..",
|
| 653 |
+
"YQ.==",
|
| 654 |
+
"YQ.=.",
|
| 655 |
+
"YQ..=",
|
| 656 |
+
"YQ...",
|
| 657 |
+
"YQ====",
|
| 658 |
+
"YQ....",
|
| 659 |
+
"YQ=====",
|
| 660 |
+
"YQ.....",
|
| 661 |
+
};
|
| 662 |
+
for (absl::string_view b64 : bad_padding) {
|
| 663 |
+
std::string decoded;
|
| 664 |
+
EXPECT_FALSE(absl::Base64Unescape(b64, &decoded));
|
| 665 |
+
std::string websafe_decoded;
|
| 666 |
+
EXPECT_FALSE(absl::WebSafeBase64Unescape(b64, &websafe_decoded));
|
| 667 |
+
}
|
| 668 |
+
}
|
| 669 |
+
|
| 670 |
+
TEST(Base64, DISABLED_HugeData) {
|
| 671 |
+
const size_t kSize = size_t(3) * 1000 * 1000 * 1000;
|
| 672 |
+
static_assert(kSize % 3 == 0, "kSize must be divisible by 3");
|
| 673 |
+
const std::string huge(kSize, 'x');
|
| 674 |
+
|
| 675 |
+
std::string escaped;
|
| 676 |
+
absl::Base64Escape(huge, &escaped);
|
| 677 |
+
|
| 678 |
+
// Generates the string that should match a base64 encoded "xxx..." string.
|
| 679 |
+
// "xxx" in base64 is "eHh4".
|
| 680 |
+
std::string expected_encoding;
|
| 681 |
+
expected_encoding.reserve(kSize / 3 * 4);
|
| 682 |
+
for (size_t i = 0; i < kSize / 3; ++i) {
|
| 683 |
+
expected_encoding.append("eHh4");
|
| 684 |
+
}
|
| 685 |
+
EXPECT_EQ(expected_encoding, escaped);
|
| 686 |
+
|
| 687 |
+
std::string unescaped;
|
| 688 |
+
EXPECT_TRUE(absl::Base64Unescape(escaped, &unescaped));
|
| 689 |
+
EXPECT_EQ(huge, unescaped);
|
| 690 |
+
}
|
| 691 |
+
|
| 692 |
+
TEST(HexAndBack, HexStringToBytes_and_BytesToHexString) {
|
| 693 |
+
std::string hex_mixed = "0123456789abcdefABCDEF";
|
| 694 |
+
std::string bytes_expected = "\x01\x23\x45\x67\x89\xab\xcd\xef\xAB\xCD\xEF";
|
| 695 |
+
std::string hex_only_lower = "0123456789abcdefabcdef";
|
| 696 |
+
|
| 697 |
+
std::string bytes_result = absl::HexStringToBytes(hex_mixed);
|
| 698 |
+
EXPECT_EQ(bytes_expected, bytes_result);
|
| 699 |
+
|
| 700 |
+
std::string prefix_valid = hex_mixed + "?";
|
| 701 |
+
std::string prefix_valid_result = absl::HexStringToBytes(
|
| 702 |
+
absl::string_view(prefix_valid.data(), prefix_valid.size() - 1));
|
| 703 |
+
EXPECT_EQ(bytes_expected, prefix_valid_result);
|
| 704 |
+
|
| 705 |
+
std::string infix_valid = "?" + hex_mixed + "???";
|
| 706 |
+
std::string infix_valid_result = absl::HexStringToBytes(
|
| 707 |
+
absl::string_view(infix_valid.data() + 1, hex_mixed.size()));
|
| 708 |
+
EXPECT_EQ(bytes_expected, infix_valid_result);
|
| 709 |
+
|
| 710 |
+
std::string hex_result = absl::BytesToHexString(bytes_expected);
|
| 711 |
+
EXPECT_EQ(hex_only_lower, hex_result);
|
| 712 |
+
}
|
| 713 |
+
|
| 714 |
+
} // namespace
|
weight/_dep/abseil-cpp/absl/strings/has_ostream_operator_test.cc
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
// Copyright 2023 The Abseil Authors
|
| 2 |
+
//
|
| 3 |
+
// Licensed under the Apache License, Version 2.0 (the "License");
|
| 4 |
+
// you may not use this file except in compliance with the License.
|
| 5 |
+
// You may obtain a copy of the License at
|
| 6 |
+
//
|
| 7 |
+
// https://www.apache.org/licenses/LICENSE-2.0
|
| 8 |
+
//
|
| 9 |
+
// Unless required by applicable law or agreed to in writing, software
|
| 10 |
+
// distributed under the License is distributed on an "AS IS" BASIS,
|
| 11 |
+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
| 12 |
+
// See the License for the specific language governing permissions and
|
| 13 |
+
// limitations under the License.
|
| 14 |
+
|
| 15 |
+
#include "absl/strings/has_ostream_operator.h"
|
| 16 |
+
|
| 17 |
+
#include <ostream>
|
| 18 |
+
#include <string>
|
| 19 |
+
|
| 20 |
+
#include "gtest/gtest.h"
|
| 21 |
+
#include "absl/types/optional.h"
|
| 22 |
+
|
| 23 |
+
namespace {
|
| 24 |
+
|
| 25 |
+
struct TypeWithoutOstreamOp {};
|
| 26 |
+
|
| 27 |
+
struct TypeWithOstreamOp {
|
| 28 |
+
friend std::ostream& operator<<(std::ostream& os, const TypeWithOstreamOp&) {
|
| 29 |
+
return os;
|
| 30 |
+
}
|
| 31 |
+
};
|
| 32 |
+
|
| 33 |
+
TEST(HasOstreamOperatorTest, Works) {
|
| 34 |
+
EXPECT_TRUE(absl::HasOstreamOperator<int>::value);
|
| 35 |
+
EXPECT_TRUE(absl::HasOstreamOperator<std::string>::value);
|
| 36 |
+
EXPECT_FALSE(absl::HasOstreamOperator<absl::optional<int>>::value);
|
| 37 |
+
EXPECT_FALSE(absl::HasOstreamOperator<TypeWithoutOstreamOp>::value);
|
| 38 |
+
EXPECT_TRUE(absl::HasOstreamOperator<TypeWithOstreamOp>::value);
|
| 39 |
+
}
|
| 40 |
+
|
| 41 |
+
} // namespace
|
weight/_dep/abseil-cpp/absl/strings/internal/charconv_bigint.h
ADDED
|
@@ -0,0 +1,423 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
// Copyright 2018 The Abseil Authors.
|
| 2 |
+
//
|
| 3 |
+
// Licensed under the Apache License, Version 2.0 (the "License");
|
| 4 |
+
// you may not use this file except in compliance with the License.
|
| 5 |
+
// You may obtain a copy of the License at
|
| 6 |
+
//
|
| 7 |
+
// https://www.apache.org/licenses/LICENSE-2.0
|
| 8 |
+
//
|
| 9 |
+
// Unless required by applicable law or agreed to in writing, software
|
| 10 |
+
// distributed under the License is distributed on an "AS IS" BASIS,
|
| 11 |
+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
| 12 |
+
// See the License for the specific language governing permissions and
|
| 13 |
+
// limitations under the License.
|
| 14 |
+
|
| 15 |
+
#ifndef ABSL_STRINGS_INTERNAL_CHARCONV_BIGINT_H_
|
| 16 |
+
#define ABSL_STRINGS_INTERNAL_CHARCONV_BIGINT_H_
|
| 17 |
+
|
| 18 |
+
#include <algorithm>
|
| 19 |
+
#include <cstdint>
|
| 20 |
+
#include <iostream>
|
| 21 |
+
#include <string>
|
| 22 |
+
|
| 23 |
+
#include "absl/base/config.h"
|
| 24 |
+
#include "absl/strings/ascii.h"
|
| 25 |
+
#include "absl/strings/internal/charconv_parse.h"
|
| 26 |
+
#include "absl/strings/string_view.h"
|
| 27 |
+
|
| 28 |
+
namespace absl {
|
| 29 |
+
ABSL_NAMESPACE_BEGIN
|
| 30 |
+
namespace strings_internal {
|
| 31 |
+
|
| 32 |
+
// The largest power that 5 that can be raised to, and still fit in a uint32_t.
|
| 33 |
+
constexpr int kMaxSmallPowerOfFive = 13;
|
| 34 |
+
// The largest power that 10 that can be raised to, and still fit in a uint32_t.
|
| 35 |
+
constexpr int kMaxSmallPowerOfTen = 9;
|
| 36 |
+
|
| 37 |
+
ABSL_DLL extern const uint32_t
|
| 38 |
+
kFiveToNth[kMaxSmallPowerOfFive + 1];
|
| 39 |
+
ABSL_DLL extern const uint32_t kTenToNth[kMaxSmallPowerOfTen + 1];
|
| 40 |
+
|
| 41 |
+
// Large, fixed-width unsigned integer.
|
| 42 |
+
//
|
| 43 |
+
// Exact rounding for decimal-to-binary floating point conversion requires very
|
| 44 |
+
// large integer math, but a design goal of absl::from_chars is to avoid
|
| 45 |
+
// allocating memory. The integer precision needed for decimal-to-binary
|
| 46 |
+
// conversions is large but bounded, so a huge fixed-width integer class
|
| 47 |
+
// suffices.
|
| 48 |
+
//
|
| 49 |
+
// This is an intentionally limited big integer class. Only needed operations
|
| 50 |
+
// are implemented. All storage lives in an array data member, and all
|
| 51 |
+
// arithmetic is done in-place, to avoid requiring separate storage for operand
|
| 52 |
+
// and result.
|
| 53 |
+
//
|
| 54 |
+
// This is an internal class. Some methods live in the .cc file, and are
|
| 55 |
+
// instantiated only for the values of max_words we need.
|
| 56 |
+
template <int max_words>
|
| 57 |
+
class BigUnsigned {
|
| 58 |
+
public:
|
| 59 |
+
static_assert(max_words == 4 || max_words == 84,
|
| 60 |
+
"unsupported max_words value");
|
| 61 |
+
|
| 62 |
+
BigUnsigned() : size_(0), words_{} {}
|
| 63 |
+
explicit constexpr BigUnsigned(uint64_t v)
|
| 64 |
+
: size_((v >> 32) ? 2 : v ? 1 : 0),
|
| 65 |
+
words_{static_cast<uint32_t>(v & 0xffffffffu),
|
| 66 |
+
static_cast<uint32_t>(v >> 32)} {}
|
| 67 |
+
|
| 68 |
+
// Constructs a BigUnsigned from the given string_view containing a decimal
|
| 69 |
+
// value. If the input string is not a decimal integer, constructs a 0
|
| 70 |
+
// instead.
|
| 71 |
+
explicit BigUnsigned(absl::string_view sv) : size_(0), words_{} {
|
| 72 |
+
// Check for valid input, returning a 0 otherwise. This is reasonable
|
| 73 |
+
// behavior only because this constructor is for unit tests.
|
| 74 |
+
if (std::find_if_not(sv.begin(), sv.end(), ascii_isdigit) != sv.end() ||
|
| 75 |
+
sv.empty()) {
|
| 76 |
+
return;
|
| 77 |
+
}
|
| 78 |
+
int exponent_adjust =
|
| 79 |
+
ReadDigits(sv.data(), sv.data() + sv.size(), Digits10() + 1);
|
| 80 |
+
if (exponent_adjust > 0) {
|
| 81 |
+
MultiplyByTenToTheNth(exponent_adjust);
|
| 82 |
+
}
|
| 83 |
+
}
|
| 84 |
+
|
| 85 |
+
// Loads the mantissa value of a previously-parsed float.
|
| 86 |
+
//
|
| 87 |
+
// Returns the associated decimal exponent. The value of the parsed float is
|
| 88 |
+
// exactly *this * 10**exponent.
|
| 89 |
+
int ReadFloatMantissa(const ParsedFloat& fp, int significant_digits);
|
| 90 |
+
|
| 91 |
+
// Returns the number of decimal digits of precision this type provides. All
|
| 92 |
+
// numbers with this many decimal digits or fewer are representable by this
|
| 93 |
+
// type.
|
| 94 |
+
//
|
| 95 |
+
// Analogous to std::numeric_limits<BigUnsigned>::digits10.
|
| 96 |
+
static constexpr int Digits10() {
|
| 97 |
+
// 9975007/1035508 is very slightly less than log10(2**32).
|
| 98 |
+
return static_cast<uint64_t>(max_words) * 9975007 / 1035508;
|
| 99 |
+
}
|
| 100 |
+
|
| 101 |
+
// Shifts left by the given number of bits.
|
| 102 |
+
void ShiftLeft(int count) {
|
| 103 |
+
if (count > 0) {
|
| 104 |
+
const int word_shift = count / 32;
|
| 105 |
+
if (word_shift >= max_words) {
|
| 106 |
+
SetToZero();
|
| 107 |
+
return;
|
| 108 |
+
}
|
| 109 |
+
size_ = (std::min)(size_ + word_shift, max_words);
|
| 110 |
+
count %= 32;
|
| 111 |
+
if (count == 0) {
|
| 112 |
+
std::copy_backward(words_, words_ + size_ - word_shift, words_ + size_);
|
| 113 |
+
} else {
|
| 114 |
+
for (int i = (std::min)(size_, max_words - 1); i > word_shift; --i) {
|
| 115 |
+
words_[i] = (words_[i - word_shift] << count) |
|
| 116 |
+
(words_[i - word_shift - 1] >> (32 - count));
|
| 117 |
+
}
|
| 118 |
+
words_[word_shift] = words_[0] << count;
|
| 119 |
+
// Grow size_ if necessary.
|
| 120 |
+
if (size_ < max_words && words_[size_]) {
|
| 121 |
+
++size_;
|
| 122 |
+
}
|
| 123 |
+
}
|
| 124 |
+
std::fill_n(words_, word_shift, 0u);
|
| 125 |
+
}
|
| 126 |
+
}
|
| 127 |
+
|
| 128 |
+
|
| 129 |
+
// Multiplies by v in-place.
|
| 130 |
+
void MultiplyBy(uint32_t v) {
|
| 131 |
+
if (size_ == 0 || v == 1) {
|
| 132 |
+
return;
|
| 133 |
+
}
|
| 134 |
+
if (v == 0) {
|
| 135 |
+
SetToZero();
|
| 136 |
+
return;
|
| 137 |
+
}
|
| 138 |
+
const uint64_t factor = v;
|
| 139 |
+
uint64_t window = 0;
|
| 140 |
+
for (int i = 0; i < size_; ++i) {
|
| 141 |
+
window += factor * words_[i];
|
| 142 |
+
words_[i] = window & 0xffffffff;
|
| 143 |
+
window >>= 32;
|
| 144 |
+
}
|
| 145 |
+
// If carry bits remain and there's space for them, grow size_.
|
| 146 |
+
if (window && size_ < max_words) {
|
| 147 |
+
words_[size_] = window & 0xffffffff;
|
| 148 |
+
++size_;
|
| 149 |
+
}
|
| 150 |
+
}
|
| 151 |
+
|
| 152 |
+
void MultiplyBy(uint64_t v) {
|
| 153 |
+
uint32_t words[2];
|
| 154 |
+
words[0] = static_cast<uint32_t>(v);
|
| 155 |
+
words[1] = static_cast<uint32_t>(v >> 32);
|
| 156 |
+
if (words[1] == 0) {
|
| 157 |
+
MultiplyBy(words[0]);
|
| 158 |
+
} else {
|
| 159 |
+
MultiplyBy(2, words);
|
| 160 |
+
}
|
| 161 |
+
}
|
| 162 |
+
|
| 163 |
+
// Multiplies in place by 5 to the power of n. n must be non-negative.
|
| 164 |
+
void MultiplyByFiveToTheNth(int n) {
|
| 165 |
+
while (n >= kMaxSmallPowerOfFive) {
|
| 166 |
+
MultiplyBy(kFiveToNth[kMaxSmallPowerOfFive]);
|
| 167 |
+
n -= kMaxSmallPowerOfFive;
|
| 168 |
+
}
|
| 169 |
+
if (n > 0) {
|
| 170 |
+
MultiplyBy(kFiveToNth[n]);
|
| 171 |
+
}
|
| 172 |
+
}
|
| 173 |
+
|
| 174 |
+
// Multiplies in place by 10 to the power of n. n must be non-negative.
|
| 175 |
+
void MultiplyByTenToTheNth(int n) {
|
| 176 |
+
if (n > kMaxSmallPowerOfTen) {
|
| 177 |
+
// For large n, raise to a power of 5, then shift left by the same amount.
|
| 178 |
+
// (10**n == 5**n * 2**n.) This requires fewer multiplications overall.
|
| 179 |
+
MultiplyByFiveToTheNth(n);
|
| 180 |
+
ShiftLeft(n);
|
| 181 |
+
} else if (n > 0) {
|
| 182 |
+
// We can do this more quickly for very small N by using a single
|
| 183 |
+
// multiplication.
|
| 184 |
+
MultiplyBy(kTenToNth[n]);
|
| 185 |
+
}
|
| 186 |
+
}
|
| 187 |
+
|
| 188 |
+
// Returns the value of 5**n, for non-negative n. This implementation uses
|
| 189 |
+
// a lookup table, and is faster then seeding a BigUnsigned with 1 and calling
|
| 190 |
+
// MultiplyByFiveToTheNth().
|
| 191 |
+
static BigUnsigned FiveToTheNth(int n);
|
| 192 |
+
|
| 193 |
+
// Multiplies by another BigUnsigned, in-place.
|
| 194 |
+
template <int M>
|
| 195 |
+
void MultiplyBy(const BigUnsigned<M>& other) {
|
| 196 |
+
MultiplyBy(other.size(), other.words());
|
| 197 |
+
}
|
| 198 |
+
|
| 199 |
+
void SetToZero() {
|
| 200 |
+
std::fill_n(words_, size_, 0u);
|
| 201 |
+
size_ = 0;
|
| 202 |
+
}
|
| 203 |
+
|
| 204 |
+
// Returns the value of the nth word of this BigUnsigned. This is
|
| 205 |
+
// range-checked, and returns 0 on out-of-bounds accesses.
|
| 206 |
+
uint32_t GetWord(int index) const {
|
| 207 |
+
if (index < 0 || index >= size_) {
|
| 208 |
+
return 0;
|
| 209 |
+
}
|
| 210 |
+
return words_[index];
|
| 211 |
+
}
|
| 212 |
+
|
| 213 |
+
// Returns this integer as a decimal string. This is not used in the decimal-
|
| 214 |
+
// to-binary conversion; it is intended to aid in testing.
|
| 215 |
+
std::string ToString() const;
|
| 216 |
+
|
| 217 |
+
int size() const { return size_; }
|
| 218 |
+
const uint32_t* words() const { return words_; }
|
| 219 |
+
|
| 220 |
+
private:
|
| 221 |
+
// Reads the number between [begin, end), possibly containing a decimal point,
|
| 222 |
+
// into this BigUnsigned.
|
| 223 |
+
//
|
| 224 |
+
// Callers are required to ensure [begin, end) contains a valid number, with
|
| 225 |
+
// one or more decimal digits and at most one decimal point. This routine
|
| 226 |
+
// will behave unpredictably if these preconditions are not met.
|
| 227 |
+
//
|
| 228 |
+
// Only the first `significant_digits` digits are read. Digits beyond this
|
| 229 |
+
// limit are "sticky": If the final significant digit is 0 or 5, and if any
|
| 230 |
+
// dropped digit is nonzero, then that final significant digit is adjusted up
|
| 231 |
+
// to 1 or 6. This adjustment allows for precise rounding.
|
| 232 |
+
//
|
| 233 |
+
// Returns `exponent_adjustment`, a power-of-ten exponent adjustment to
|
| 234 |
+
// account for the decimal point and for dropped significant digits. After
|
| 235 |
+
// this function returns,
|
| 236 |
+
// actual_value_of_parsed_string ~= *this * 10**exponent_adjustment.
|
| 237 |
+
int ReadDigits(const char* begin, const char* end, int significant_digits);
|
| 238 |
+
|
| 239 |
+
// Performs a step of big integer multiplication. This computes the full
|
| 240 |
+
// (64-bit-wide) values that should be added at the given index (step), and
|
| 241 |
+
// adds to that location in-place.
|
| 242 |
+
//
|
| 243 |
+
// Because our math all occurs in place, we must multiply starting from the
|
| 244 |
+
// highest word working downward. (This is a bit more expensive due to the
|
| 245 |
+
// extra carries involved.)
|
| 246 |
+
//
|
| 247 |
+
// This must be called in steps, for each word to be calculated, starting from
|
| 248 |
+
// the high end and working down to 0. The first value of `step` should be
|
| 249 |
+
// `std::min(original_size + other.size_ - 2, max_words - 1)`.
|
| 250 |
+
// The reason for this expression is that multiplying the i'th word from one
|
| 251 |
+
// multiplicand and the j'th word of another multiplicand creates a
|
| 252 |
+
// two-word-wide value to be stored at the (i+j)'th element. The highest
|
| 253 |
+
// word indices we will access are `original_size - 1` from this object, and
|
| 254 |
+
// `other.size_ - 1` from our operand. Therefore,
|
| 255 |
+
// `original_size + other.size_ - 2` is the first step we should calculate,
|
| 256 |
+
// but limited on an upper bound by max_words.
|
| 257 |
+
|
| 258 |
+
// Working from high-to-low ensures that we do not overwrite the portions of
|
| 259 |
+
// the initial value of *this which are still needed for later steps.
|
| 260 |
+
//
|
| 261 |
+
// Once called with step == 0, *this contains the result of the
|
| 262 |
+
// multiplication.
|
| 263 |
+
//
|
| 264 |
+
// `original_size` is the size_ of *this before the first call to
|
| 265 |
+
// MultiplyStep(). `other_words` and `other_size` are the contents of our
|
| 266 |
+
// operand. `step` is the step to perform, as described above.
|
| 267 |
+
void MultiplyStep(int original_size, const uint32_t* other_words,
|
| 268 |
+
int other_size, int step);
|
| 269 |
+
|
| 270 |
+
void MultiplyBy(int other_size, const uint32_t* other_words) {
|
| 271 |
+
const int original_size = size_;
|
| 272 |
+
const int first_step =
|
| 273 |
+
(std::min)(original_size + other_size - 2, max_words - 1);
|
| 274 |
+
for (int step = first_step; step >= 0; --step) {
|
| 275 |
+
MultiplyStep(original_size, other_words, other_size, step);
|
| 276 |
+
}
|
| 277 |
+
}
|
| 278 |
+
|
| 279 |
+
// Adds a 32-bit value to the index'th word, with carry.
|
| 280 |
+
void AddWithCarry(int index, uint32_t value) {
|
| 281 |
+
if (value) {
|
| 282 |
+
while (index < max_words && value > 0) {
|
| 283 |
+
words_[index] += value;
|
| 284 |
+
// carry if we overflowed in this word:
|
| 285 |
+
if (value > words_[index]) {
|
| 286 |
+
value = 1;
|
| 287 |
+
++index;
|
| 288 |
+
} else {
|
| 289 |
+
value = 0;
|
| 290 |
+
}
|
| 291 |
+
}
|
| 292 |
+
size_ = (std::min)(max_words, (std::max)(index + 1, size_));
|
| 293 |
+
}
|
| 294 |
+
}
|
| 295 |
+
|
| 296 |
+
void AddWithCarry(int index, uint64_t value) {
|
| 297 |
+
if (value && index < max_words) {
|
| 298 |
+
uint32_t high = value >> 32;
|
| 299 |
+
uint32_t low = value & 0xffffffff;
|
| 300 |
+
words_[index] += low;
|
| 301 |
+
if (words_[index] < low) {
|
| 302 |
+
++high;
|
| 303 |
+
if (high == 0) {
|
| 304 |
+
// Carry from the low word caused our high word to overflow.
|
| 305 |
+
// Short circuit here to do the right thing.
|
| 306 |
+
AddWithCarry(index + 2, static_cast<uint32_t>(1));
|
| 307 |
+
return;
|
| 308 |
+
}
|
| 309 |
+
}
|
| 310 |
+
if (high > 0) {
|
| 311 |
+
AddWithCarry(index + 1, high);
|
| 312 |
+
} else {
|
| 313 |
+
// Normally 32-bit AddWithCarry() sets size_, but since we don't call
|
| 314 |
+
// it when `high` is 0, do it ourselves here.
|
| 315 |
+
size_ = (std::min)(max_words, (std::max)(index + 1, size_));
|
| 316 |
+
}
|
| 317 |
+
}
|
| 318 |
+
}
|
| 319 |
+
|
| 320 |
+
// Divide this in place by a constant divisor. Returns the remainder of the
|
| 321 |
+
// division.
|
| 322 |
+
template <uint32_t divisor>
|
| 323 |
+
uint32_t DivMod() {
|
| 324 |
+
uint64_t accumulator = 0;
|
| 325 |
+
for (int i = size_ - 1; i >= 0; --i) {
|
| 326 |
+
accumulator <<= 32;
|
| 327 |
+
accumulator += words_[i];
|
| 328 |
+
// accumulator / divisor will never overflow an int32_t in this loop
|
| 329 |
+
words_[i] = static_cast<uint32_t>(accumulator / divisor);
|
| 330 |
+
accumulator = accumulator % divisor;
|
| 331 |
+
}
|
| 332 |
+
while (size_ > 0 && words_[size_ - 1] == 0) {
|
| 333 |
+
--size_;
|
| 334 |
+
}
|
| 335 |
+
return static_cast<uint32_t>(accumulator);
|
| 336 |
+
}
|
| 337 |
+
|
| 338 |
+
// The number of elements in words_ that may carry significant values.
|
| 339 |
+
// All elements beyond this point are 0.
|
| 340 |
+
//
|
| 341 |
+
// When size_ is 0, this BigUnsigned stores the value 0.
|
| 342 |
+
// When size_ is nonzero, is *not* guaranteed that words_[size_ - 1] is
|
| 343 |
+
// nonzero. This can occur due to overflow truncation.
|
| 344 |
+
// In particular, x.size_ != y.size_ does *not* imply x != y.
|
| 345 |
+
int size_;
|
| 346 |
+
uint32_t words_[max_words];
|
| 347 |
+
};
|
| 348 |
+
|
| 349 |
+
// Compares two big integer instances.
|
| 350 |
+
//
|
| 351 |
+
// Returns -1 if lhs < rhs, 0 if lhs == rhs, and 1 if lhs > rhs.
|
| 352 |
+
template <int N, int M>
|
| 353 |
+
int Compare(const BigUnsigned<N>& lhs, const BigUnsigned<M>& rhs) {
|
| 354 |
+
int limit = (std::max)(lhs.size(), rhs.size());
|
| 355 |
+
for (int i = limit - 1; i >= 0; --i) {
|
| 356 |
+
const uint32_t lhs_word = lhs.GetWord(i);
|
| 357 |
+
const uint32_t rhs_word = rhs.GetWord(i);
|
| 358 |
+
if (lhs_word < rhs_word) {
|
| 359 |
+
return -1;
|
| 360 |
+
} else if (lhs_word > rhs_word) {
|
| 361 |
+
return 1;
|
| 362 |
+
}
|
| 363 |
+
}
|
| 364 |
+
return 0;
|
| 365 |
+
}
|
| 366 |
+
|
| 367 |
+
template <int N, int M>
|
| 368 |
+
bool operator==(const BigUnsigned<N>& lhs, const BigUnsigned<M>& rhs) {
|
| 369 |
+
int limit = (std::max)(lhs.size(), rhs.size());
|
| 370 |
+
for (int i = 0; i < limit; ++i) {
|
| 371 |
+
if (lhs.GetWord(i) != rhs.GetWord(i)) {
|
| 372 |
+
return false;
|
| 373 |
+
}
|
| 374 |
+
}
|
| 375 |
+
return true;
|
| 376 |
+
}
|
| 377 |
+
|
| 378 |
+
template <int N, int M>
|
| 379 |
+
bool operator!=(const BigUnsigned<N>& lhs, const BigUnsigned<M>& rhs) {
|
| 380 |
+
return !(lhs == rhs);
|
| 381 |
+
}
|
| 382 |
+
|
| 383 |
+
template <int N, int M>
|
| 384 |
+
bool operator<(const BigUnsigned<N>& lhs, const BigUnsigned<M>& rhs) {
|
| 385 |
+
return Compare(lhs, rhs) == -1;
|
| 386 |
+
}
|
| 387 |
+
|
| 388 |
+
template <int N, int M>
|
| 389 |
+
bool operator>(const BigUnsigned<N>& lhs, const BigUnsigned<M>& rhs) {
|
| 390 |
+
return rhs < lhs;
|
| 391 |
+
}
|
| 392 |
+
template <int N, int M>
|
| 393 |
+
bool operator<=(const BigUnsigned<N>& lhs, const BigUnsigned<M>& rhs) {
|
| 394 |
+
return !(rhs < lhs);
|
| 395 |
+
}
|
| 396 |
+
template <int N, int M>
|
| 397 |
+
bool operator>=(const BigUnsigned<N>& lhs, const BigUnsigned<M>& rhs) {
|
| 398 |
+
return !(lhs < rhs);
|
| 399 |
+
}
|
| 400 |
+
|
| 401 |
+
// Output operator for BigUnsigned, for testing purposes only.
|
| 402 |
+
template <int N>
|
| 403 |
+
std::ostream& operator<<(std::ostream& os, const BigUnsigned<N>& num) {
|
| 404 |
+
return os << num.ToString();
|
| 405 |
+
}
|
| 406 |
+
|
| 407 |
+
// Explicit instantiation declarations for the sizes of BigUnsigned that we
|
| 408 |
+
// are using.
|
| 409 |
+
//
|
| 410 |
+
// For now, the choices of 4 and 84 are arbitrary; 4 is a small value that is
|
| 411 |
+
// still bigger than an int128, and 84 is a large value we will want to use
|
| 412 |
+
// in the from_chars implementation.
|
| 413 |
+
//
|
| 414 |
+
// Comments justifying the use of 84 belong in the from_chars implementation,
|
| 415 |
+
// and will be added in a follow-up CL.
|
| 416 |
+
extern template class BigUnsigned<4>;
|
| 417 |
+
extern template class BigUnsigned<84>;
|
| 418 |
+
|
| 419 |
+
} // namespace strings_internal
|
| 420 |
+
ABSL_NAMESPACE_END
|
| 421 |
+
} // namespace absl
|
| 422 |
+
|
| 423 |
+
#endif // ABSL_STRINGS_INTERNAL_CHARCONV_BIGINT_H_
|
weight/_dep/abseil-cpp/absl/strings/internal/charconv_bigint_test.cc
ADDED
|
@@ -0,0 +1,260 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
// Copyright 2018 The Abseil Authors.
|
| 2 |
+
//
|
| 3 |
+
// Licensed under the Apache License, Version 2.0 (the "License");
|
| 4 |
+
// you may not use this file except in compliance with the License.
|
| 5 |
+
// You may obtain a copy of the License at
|
| 6 |
+
//
|
| 7 |
+
// https://www.apache.org/licenses/LICENSE-2.0
|
| 8 |
+
//
|
| 9 |
+
// Unless required by applicable law or agreed to in writing, software
|
| 10 |
+
// distributed under the License is distributed on an "AS IS" BASIS,
|
| 11 |
+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
| 12 |
+
// See the License for the specific language governing permissions and
|
| 13 |
+
// limitations under the License.
|
| 14 |
+
|
| 15 |
+
#include "absl/strings/internal/charconv_bigint.h"
|
| 16 |
+
|
| 17 |
+
#include <string>
|
| 18 |
+
|
| 19 |
+
#include "gtest/gtest.h"
|
| 20 |
+
|
| 21 |
+
namespace absl {
|
| 22 |
+
ABSL_NAMESPACE_BEGIN
|
| 23 |
+
namespace strings_internal {
|
| 24 |
+
|
| 25 |
+
TEST(BigUnsigned, ShiftLeft) {
|
| 26 |
+
{
|
| 27 |
+
// Check that 3 * 2**100 is calculated correctly
|
| 28 |
+
BigUnsigned<4> num(3u);
|
| 29 |
+
num.ShiftLeft(100);
|
| 30 |
+
EXPECT_EQ(num, BigUnsigned<4>("3802951800684688204490109616128"));
|
| 31 |
+
}
|
| 32 |
+
{
|
| 33 |
+
// Test that overflow is truncated properly.
|
| 34 |
+
// 15 is 4 bits long, and BigUnsigned<4> is a 128-bit bigint.
|
| 35 |
+
// Shifting left by 125 bits should truncate off the high bit, so that
|
| 36 |
+
// 15 << 125 == 7 << 125
|
| 37 |
+
// after truncation.
|
| 38 |
+
BigUnsigned<4> a(15u);
|
| 39 |
+
BigUnsigned<4> b(7u);
|
| 40 |
+
BigUnsigned<4> c(3u);
|
| 41 |
+
a.ShiftLeft(125);
|
| 42 |
+
b.ShiftLeft(125);
|
| 43 |
+
c.ShiftLeft(125);
|
| 44 |
+
EXPECT_EQ(a, b);
|
| 45 |
+
EXPECT_NE(a, c);
|
| 46 |
+
}
|
| 47 |
+
{
|
| 48 |
+
// Same test, larger bigint:
|
| 49 |
+
BigUnsigned<84> a(15u);
|
| 50 |
+
BigUnsigned<84> b(7u);
|
| 51 |
+
BigUnsigned<84> c(3u);
|
| 52 |
+
a.ShiftLeft(84 * 32 - 3);
|
| 53 |
+
b.ShiftLeft(84 * 32 - 3);
|
| 54 |
+
c.ShiftLeft(84 * 32 - 3);
|
| 55 |
+
EXPECT_EQ(a, b);
|
| 56 |
+
EXPECT_NE(a, c);
|
| 57 |
+
}
|
| 58 |
+
{
|
| 59 |
+
// Check that incrementally shifting has the same result as doing it all at
|
| 60 |
+
// once (attempting to capture corner cases.)
|
| 61 |
+
const std::string seed = "1234567890123456789012345678901234567890";
|
| 62 |
+
BigUnsigned<84> a(seed);
|
| 63 |
+
for (int i = 1; i <= 84 * 32; ++i) {
|
| 64 |
+
a.ShiftLeft(1);
|
| 65 |
+
BigUnsigned<84> b(seed);
|
| 66 |
+
b.ShiftLeft(i);
|
| 67 |
+
EXPECT_EQ(a, b);
|
| 68 |
+
}
|
| 69 |
+
// And we should have fully rotated all bits off by now:
|
| 70 |
+
EXPECT_EQ(a, BigUnsigned<84>(0u));
|
| 71 |
+
}
|
| 72 |
+
{
|
| 73 |
+
// Bit shifting large and small numbers by large and small offsets.
|
| 74 |
+
// Intended to exercise bounds-checking corner on ShiftLeft() (directly
|
| 75 |
+
// and under asan).
|
| 76 |
+
|
| 77 |
+
// 2**(32*84)-1
|
| 78 |
+
const BigUnsigned<84> all_bits_one(
|
| 79 |
+
"1474444211396924248063325089479706787923460402125687709454567433186613"
|
| 80 |
+
"6228083464060749874845919674257665016359189106695900028098437021384227"
|
| 81 |
+
"3285029708032466536084583113729486015826557532750465299832071590813090"
|
| 82 |
+
"2011853039837649252477307070509704043541368002938784757296893793903797"
|
| 83 |
+
"8180292336310543540677175225040919704702800559606097685920595947397024"
|
| 84 |
+
"8303316808753252115729411497720357971050627997031988036134171378490368"
|
| 85 |
+
"6008000778741115399296162550786288457245180872759047016734959330367829"
|
| 86 |
+
"5235612397427686310674725251378116268607113017720538636924549612987647"
|
| 87 |
+
"5767411074510311386444547332882472126067840027882117834454260409440463"
|
| 88 |
+
"9345147252664893456053258463203120637089916304618696601333953616715125"
|
| 89 |
+
"2115882482473279040772264257431663818610405673876655957323083702713344"
|
| 90 |
+
"4201105427930770976052393421467136557055");
|
| 91 |
+
const BigUnsigned<84> zero(0u);
|
| 92 |
+
const BigUnsigned<84> one(1u);
|
| 93 |
+
// in bounds shifts
|
| 94 |
+
for (int i = 1; i < 84*32; ++i) {
|
| 95 |
+
// shifting all_bits_one to the left should result in a smaller number,
|
| 96 |
+
// since the high bits rotate off and the low bits are replaced with
|
| 97 |
+
// zeroes.
|
| 98 |
+
BigUnsigned<84> big_shifted = all_bits_one;
|
| 99 |
+
big_shifted.ShiftLeft(i);
|
| 100 |
+
EXPECT_GT(all_bits_one, big_shifted);
|
| 101 |
+
// Shifting 1 to the left should instead result in a larger number.
|
| 102 |
+
BigUnsigned<84> small_shifted = one;
|
| 103 |
+
small_shifted.ShiftLeft(i);
|
| 104 |
+
EXPECT_LT(one, small_shifted);
|
| 105 |
+
}
|
| 106 |
+
// Shifting by zero or a negative number has no effect
|
| 107 |
+
for (int no_op_shift : {0, -1, -84 * 32, std::numeric_limits<int>::min()}) {
|
| 108 |
+
BigUnsigned<84> big_shifted = all_bits_one;
|
| 109 |
+
big_shifted.ShiftLeft(no_op_shift);
|
| 110 |
+
EXPECT_EQ(all_bits_one, big_shifted);
|
| 111 |
+
BigUnsigned<84> small_shifted = one;
|
| 112 |
+
big_shifted.ShiftLeft(no_op_shift);
|
| 113 |
+
EXPECT_EQ(one, small_shifted);
|
| 114 |
+
}
|
| 115 |
+
// Shifting by an amount greater than the number of bits should result in
|
| 116 |
+
// zero.
|
| 117 |
+
for (int out_of_bounds_shift :
|
| 118 |
+
{84 * 32, 84 * 32 + 1, std::numeric_limits<int>::max()}) {
|
| 119 |
+
BigUnsigned<84> big_shifted = all_bits_one;
|
| 120 |
+
big_shifted.ShiftLeft(out_of_bounds_shift);
|
| 121 |
+
EXPECT_EQ(zero, big_shifted);
|
| 122 |
+
BigUnsigned<84> small_shifted = one;
|
| 123 |
+
small_shifted.ShiftLeft(out_of_bounds_shift);
|
| 124 |
+
EXPECT_EQ(zero, small_shifted);
|
| 125 |
+
}
|
| 126 |
+
}
|
| 127 |
+
}
|
| 128 |
+
|
| 129 |
+
TEST(BigUnsigned, MultiplyByUint32) {
|
| 130 |
+
const BigUnsigned<84> factorial_100(
|
| 131 |
+
"933262154439441526816992388562667004907159682643816214685929638952175999"
|
| 132 |
+
"932299156089414639761565182862536979208272237582511852109168640000000000"
|
| 133 |
+
"00000000000000");
|
| 134 |
+
BigUnsigned<84> a(1u);
|
| 135 |
+
for (uint32_t i = 1; i <= 100; ++i) {
|
| 136 |
+
a.MultiplyBy(i);
|
| 137 |
+
}
|
| 138 |
+
EXPECT_EQ(a, BigUnsigned<84>(factorial_100));
|
| 139 |
+
}
|
| 140 |
+
|
| 141 |
+
TEST(BigUnsigned, MultiplyByBigUnsigned) {
|
| 142 |
+
{
|
| 143 |
+
// Put the terms of factorial_200 into two bigints, and multiply them
|
| 144 |
+
// together.
|
| 145 |
+
const BigUnsigned<84> factorial_200(
|
| 146 |
+
"7886578673647905035523632139321850622951359776871732632947425332443594"
|
| 147 |
+
"4996340334292030428401198462390417721213891963883025764279024263710506"
|
| 148 |
+
"1926624952829931113462857270763317237396988943922445621451664240254033"
|
| 149 |
+
"2918641312274282948532775242424075739032403212574055795686602260319041"
|
| 150 |
+
"7032406235170085879617892222278962370389737472000000000000000000000000"
|
| 151 |
+
"0000000000000000000000000");
|
| 152 |
+
BigUnsigned<84> evens(1u);
|
| 153 |
+
BigUnsigned<84> odds(1u);
|
| 154 |
+
for (uint32_t i = 1; i < 200; i += 2) {
|
| 155 |
+
odds.MultiplyBy(i);
|
| 156 |
+
evens.MultiplyBy(i + 1);
|
| 157 |
+
}
|
| 158 |
+
evens.MultiplyBy(odds);
|
| 159 |
+
EXPECT_EQ(evens, factorial_200);
|
| 160 |
+
}
|
| 161 |
+
{
|
| 162 |
+
// Multiply various powers of 10 together.
|
| 163 |
+
for (int a = 0 ; a < 700; a += 25) {
|
| 164 |
+
SCOPED_TRACE(a);
|
| 165 |
+
BigUnsigned<84> a_value("3" + std::string(a, '0'));
|
| 166 |
+
for (int b = 0; b < (700 - a); b += 25) {
|
| 167 |
+
SCOPED_TRACE(b);
|
| 168 |
+
BigUnsigned<84> b_value("2" + std::string(b, '0'));
|
| 169 |
+
BigUnsigned<84> expected_product("6" + std::string(a + b, '0'));
|
| 170 |
+
b_value.MultiplyBy(a_value);
|
| 171 |
+
EXPECT_EQ(b_value, expected_product);
|
| 172 |
+
}
|
| 173 |
+
}
|
| 174 |
+
}
|
| 175 |
+
}
|
| 176 |
+
|
| 177 |
+
TEST(BigUnsigned, MultiplyByOverflow) {
|
| 178 |
+
{
|
| 179 |
+
// Check that multiplcation overflow predictably truncates.
|
| 180 |
+
|
| 181 |
+
// A big int with all bits on.
|
| 182 |
+
BigUnsigned<4> all_bits_on("340282366920938463463374607431768211455");
|
| 183 |
+
// Modulo 2**128, this is equal to -1. Therefore the square of this,
|
| 184 |
+
// modulo 2**128, should be 1.
|
| 185 |
+
all_bits_on.MultiplyBy(all_bits_on);
|
| 186 |
+
EXPECT_EQ(all_bits_on, BigUnsigned<4>(1u));
|
| 187 |
+
}
|
| 188 |
+
{
|
| 189 |
+
// Try multiplying a large bigint by 2**50, and compare the result to
|
| 190 |
+
// shifting.
|
| 191 |
+
BigUnsigned<4> value_1("12345678901234567890123456789012345678");
|
| 192 |
+
BigUnsigned<4> value_2("12345678901234567890123456789012345678");
|
| 193 |
+
BigUnsigned<4> two_to_fiftieth(1u);
|
| 194 |
+
two_to_fiftieth.ShiftLeft(50);
|
| 195 |
+
|
| 196 |
+
value_1.ShiftLeft(50);
|
| 197 |
+
value_2.MultiplyBy(two_to_fiftieth);
|
| 198 |
+
EXPECT_EQ(value_1, value_2);
|
| 199 |
+
}
|
| 200 |
+
}
|
| 201 |
+
|
| 202 |
+
TEST(BigUnsigned, FiveToTheNth) {
|
| 203 |
+
{
|
| 204 |
+
// Sanity check that MultiplyByFiveToTheNth gives consistent answers, up to
|
| 205 |
+
// and including overflow.
|
| 206 |
+
for (int i = 0; i < 1160; ++i) {
|
| 207 |
+
SCOPED_TRACE(i);
|
| 208 |
+
BigUnsigned<84> value_1(123u);
|
| 209 |
+
BigUnsigned<84> value_2(123u);
|
| 210 |
+
value_1.MultiplyByFiveToTheNth(i);
|
| 211 |
+
for (int j = 0; j < i; j++) {
|
| 212 |
+
value_2.MultiplyBy(5u);
|
| 213 |
+
}
|
| 214 |
+
EXPECT_EQ(value_1, value_2);
|
| 215 |
+
}
|
| 216 |
+
}
|
| 217 |
+
{
|
| 218 |
+
// Check that the faster, table-lookup-based static method returns the same
|
| 219 |
+
// result that multiplying in-place would return, up to and including
|
| 220 |
+
// overflow.
|
| 221 |
+
for (int i = 0; i < 1160; ++i) {
|
| 222 |
+
SCOPED_TRACE(i);
|
| 223 |
+
BigUnsigned<84> value_1(1u);
|
| 224 |
+
value_1.MultiplyByFiveToTheNth(i);
|
| 225 |
+
BigUnsigned<84> value_2 = BigUnsigned<84>::FiveToTheNth(i);
|
| 226 |
+
EXPECT_EQ(value_1, value_2);
|
| 227 |
+
}
|
| 228 |
+
}
|
| 229 |
+
}
|
| 230 |
+
|
| 231 |
+
TEST(BigUnsigned, TenToTheNth) {
|
| 232 |
+
{
|
| 233 |
+
// Sanity check MultiplyByTenToTheNth.
|
| 234 |
+
for (int i = 0; i < 800; ++i) {
|
| 235 |
+
SCOPED_TRACE(i);
|
| 236 |
+
BigUnsigned<84> value_1(123u);
|
| 237 |
+
BigUnsigned<84> value_2(123u);
|
| 238 |
+
value_1.MultiplyByTenToTheNth(i);
|
| 239 |
+
for (int j = 0; j < i; j++) {
|
| 240 |
+
value_2.MultiplyBy(10u);
|
| 241 |
+
}
|
| 242 |
+
EXPECT_EQ(value_1, value_2);
|
| 243 |
+
}
|
| 244 |
+
}
|
| 245 |
+
{
|
| 246 |
+
// Alternate testing approach, taking advantage of the decimal parser.
|
| 247 |
+
for (int i = 0; i < 200; ++i) {
|
| 248 |
+
SCOPED_TRACE(i);
|
| 249 |
+
BigUnsigned<84> value_1(135u);
|
| 250 |
+
value_1.MultiplyByTenToTheNth(i);
|
| 251 |
+
BigUnsigned<84> value_2("135" + std::string(i, '0'));
|
| 252 |
+
EXPECT_EQ(value_1, value_2);
|
| 253 |
+
}
|
| 254 |
+
}
|
| 255 |
+
}
|
| 256 |
+
|
| 257 |
+
|
| 258 |
+
} // namespace strings_internal
|
| 259 |
+
ABSL_NAMESPACE_END
|
| 260 |
+
} // namespace absl
|
weight/_dep/abseil-cpp/absl/strings/internal/charconv_parse_test.cc
ADDED
|
@@ -0,0 +1,357 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
// Copyright 2018 The Abseil Authors.
|
| 2 |
+
//
|
| 3 |
+
// Licensed under the Apache License, Version 2.0 (the "License");
|
| 4 |
+
// you may not use this file except in compliance with the License.
|
| 5 |
+
// You may obtain a copy of the License at
|
| 6 |
+
//
|
| 7 |
+
// https://www.apache.org/licenses/LICENSE-2.0
|
| 8 |
+
//
|
| 9 |
+
// Unless required by applicable law or agreed to in writing, software
|
| 10 |
+
// distributed under the License is distributed on an "AS IS" BASIS,
|
| 11 |
+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
| 12 |
+
// See the License for the specific language governing permissions and
|
| 13 |
+
// limitations under the License.
|
| 14 |
+
|
| 15 |
+
#include "absl/strings/internal/charconv_parse.h"
|
| 16 |
+
|
| 17 |
+
#include <string>
|
| 18 |
+
#include <utility>
|
| 19 |
+
|
| 20 |
+
#include "gmock/gmock.h"
|
| 21 |
+
#include "gtest/gtest.h"
|
| 22 |
+
#include "absl/log/check.h"
|
| 23 |
+
#include "absl/strings/str_cat.h"
|
| 24 |
+
|
| 25 |
+
using absl::chars_format;
|
| 26 |
+
using absl::strings_internal::FloatType;
|
| 27 |
+
using absl::strings_internal::ParsedFloat;
|
| 28 |
+
using absl::strings_internal::ParseFloat;
|
| 29 |
+
|
| 30 |
+
namespace {
|
| 31 |
+
|
| 32 |
+
// Check that a given string input is parsed to the expected mantissa and
|
| 33 |
+
// exponent.
|
| 34 |
+
//
|
| 35 |
+
// Input string `s` must contain a '$' character. It marks the end of the
|
| 36 |
+
// characters that should be consumed by the match. It is stripped from the
|
| 37 |
+
// input to ParseFloat.
|
| 38 |
+
//
|
| 39 |
+
// If input string `s` contains '[' and ']' characters, these mark the region
|
| 40 |
+
// of characters that should be marked as the "subrange". For NaNs, this is
|
| 41 |
+
// the location of the extended NaN string. For numbers, this is the location
|
| 42 |
+
// of the full, over-large mantissa.
|
| 43 |
+
template <int base>
|
| 44 |
+
void ExpectParsedFloat(std::string s, absl::chars_format format_flags,
|
| 45 |
+
FloatType expected_type, uint64_t expected_mantissa,
|
| 46 |
+
int expected_exponent,
|
| 47 |
+
int expected_literal_exponent = -999) {
|
| 48 |
+
SCOPED_TRACE(s);
|
| 49 |
+
|
| 50 |
+
int begin_subrange = -1;
|
| 51 |
+
int end_subrange = -1;
|
| 52 |
+
// If s contains '[' and ']', then strip these characters and set the subrange
|
| 53 |
+
// indices appropriately.
|
| 54 |
+
std::string::size_type open_bracket_pos = s.find('[');
|
| 55 |
+
if (open_bracket_pos != std::string::npos) {
|
| 56 |
+
begin_subrange = static_cast<int>(open_bracket_pos);
|
| 57 |
+
s.replace(open_bracket_pos, 1, "");
|
| 58 |
+
std::string::size_type close_bracket_pos = s.find(']');
|
| 59 |
+
CHECK_NE(close_bracket_pos, absl::string_view::npos)
|
| 60 |
+
<< "Test input contains [ without matching ]";
|
| 61 |
+
end_subrange = static_cast<int>(close_bracket_pos);
|
| 62 |
+
s.replace(close_bracket_pos, 1, "");
|
| 63 |
+
}
|
| 64 |
+
const std::string::size_type expected_characters_matched = s.find('$');
|
| 65 |
+
CHECK_NE(expected_characters_matched, std::string::npos)
|
| 66 |
+
<< "Input string must contain $";
|
| 67 |
+
s.replace(expected_characters_matched, 1, "");
|
| 68 |
+
|
| 69 |
+
ParsedFloat parsed =
|
| 70 |
+
ParseFloat<base>(s.data(), s.data() + s.size(), format_flags);
|
| 71 |
+
|
| 72 |
+
EXPECT_NE(parsed.end, nullptr);
|
| 73 |
+
if (parsed.end == nullptr) {
|
| 74 |
+
return; // The following tests are not useful if we fully failed to parse
|
| 75 |
+
}
|
| 76 |
+
EXPECT_EQ(parsed.type, expected_type);
|
| 77 |
+
if (begin_subrange == -1) {
|
| 78 |
+
EXPECT_EQ(parsed.subrange_begin, nullptr);
|
| 79 |
+
EXPECT_EQ(parsed.subrange_end, nullptr);
|
| 80 |
+
} else {
|
| 81 |
+
EXPECT_EQ(parsed.subrange_begin, s.data() + begin_subrange);
|
| 82 |
+
EXPECT_EQ(parsed.subrange_end, s.data() + end_subrange);
|
| 83 |
+
}
|
| 84 |
+
if (parsed.type == FloatType::kNumber) {
|
| 85 |
+
EXPECT_EQ(parsed.mantissa, expected_mantissa);
|
| 86 |
+
EXPECT_EQ(parsed.exponent, expected_exponent);
|
| 87 |
+
if (expected_literal_exponent != -999) {
|
| 88 |
+
EXPECT_EQ(parsed.literal_exponent, expected_literal_exponent);
|
| 89 |
+
}
|
| 90 |
+
}
|
| 91 |
+
auto characters_matched = static_cast<int>(parsed.end - s.data());
|
| 92 |
+
EXPECT_EQ(characters_matched, expected_characters_matched);
|
| 93 |
+
}
|
| 94 |
+
|
| 95 |
+
// Check that a given string input is parsed to the expected mantissa and
|
| 96 |
+
// exponent.
|
| 97 |
+
//
|
| 98 |
+
// Input string `s` must contain a '$' character. It marks the end of the
|
| 99 |
+
// characters that were consumed by the match.
|
| 100 |
+
template <int base>
|
| 101 |
+
void ExpectNumber(std::string s, absl::chars_format format_flags,
|
| 102 |
+
uint64_t expected_mantissa, int expected_exponent,
|
| 103 |
+
int expected_literal_exponent = -999) {
|
| 104 |
+
ExpectParsedFloat<base>(std::move(s), format_flags, FloatType::kNumber,
|
| 105 |
+
expected_mantissa, expected_exponent,
|
| 106 |
+
expected_literal_exponent);
|
| 107 |
+
}
|
| 108 |
+
|
| 109 |
+
// Check that a given string input is parsed to the given special value.
|
| 110 |
+
//
|
| 111 |
+
// This tests against both number bases, since infinities and NaNs have
|
| 112 |
+
// identical representations in both modes.
|
| 113 |
+
void ExpectSpecial(const std::string& s, absl::chars_format format_flags,
|
| 114 |
+
FloatType type) {
|
| 115 |
+
ExpectParsedFloat<10>(s, format_flags, type, 0, 0);
|
| 116 |
+
ExpectParsedFloat<16>(s, format_flags, type, 0, 0);
|
| 117 |
+
}
|
| 118 |
+
|
| 119 |
+
// Check that a given input string is not matched by Float.
|
| 120 |
+
template <int base>
|
| 121 |
+
void ExpectFailedParse(absl::string_view s, absl::chars_format format_flags) {
|
| 122 |
+
ParsedFloat parsed =
|
| 123 |
+
ParseFloat<base>(s.data(), s.data() + s.size(), format_flags);
|
| 124 |
+
EXPECT_EQ(parsed.end, nullptr);
|
| 125 |
+
}
|
| 126 |
+
|
| 127 |
+
TEST(ParseFloat, SimpleValue) {
|
| 128 |
+
// Test that various forms of floating point numbers all parse correctly.
|
| 129 |
+
ExpectNumber<10>("1.23456789e5$", chars_format::general, 123456789, -3);
|
| 130 |
+
ExpectNumber<10>("1.23456789e+5$", chars_format::general, 123456789, -3);
|
| 131 |
+
ExpectNumber<10>("1.23456789E5$", chars_format::general, 123456789, -3);
|
| 132 |
+
ExpectNumber<10>("1.23456789e05$", chars_format::general, 123456789, -3);
|
| 133 |
+
ExpectNumber<10>("123.456789e3$", chars_format::general, 123456789, -3);
|
| 134 |
+
ExpectNumber<10>("0.000123456789e9$", chars_format::general, 123456789, -3);
|
| 135 |
+
ExpectNumber<10>("123456.789$", chars_format::general, 123456789, -3);
|
| 136 |
+
ExpectNumber<10>("123456789e-3$", chars_format::general, 123456789, -3);
|
| 137 |
+
|
| 138 |
+
ExpectNumber<16>("1.234abcdefp28$", chars_format::general, 0x1234abcdef, -8);
|
| 139 |
+
ExpectNumber<16>("1.234abcdefp+28$", chars_format::general, 0x1234abcdef, -8);
|
| 140 |
+
ExpectNumber<16>("1.234ABCDEFp28$", chars_format::general, 0x1234abcdef, -8);
|
| 141 |
+
ExpectNumber<16>("1.234AbCdEfP0028$", chars_format::general, 0x1234abcdef,
|
| 142 |
+
-8);
|
| 143 |
+
ExpectNumber<16>("123.4abcdefp20$", chars_format::general, 0x1234abcdef, -8);
|
| 144 |
+
ExpectNumber<16>("0.0001234abcdefp44$", chars_format::general, 0x1234abcdef,
|
| 145 |
+
-8);
|
| 146 |
+
ExpectNumber<16>("1234abcd.ef$", chars_format::general, 0x1234abcdef, -8);
|
| 147 |
+
ExpectNumber<16>("1234abcdefp-8$", chars_format::general, 0x1234abcdef, -8);
|
| 148 |
+
|
| 149 |
+
// ExpectNumber does not attempt to drop trailing zeroes.
|
| 150 |
+
ExpectNumber<10>("0001.2345678900e005$", chars_format::general, 12345678900,
|
| 151 |
+
-5);
|
| 152 |
+
ExpectNumber<16>("0001.234abcdef000p28$", chars_format::general,
|
| 153 |
+
0x1234abcdef000, -20);
|
| 154 |
+
|
| 155 |
+
// Ensure non-matching characters after a number are ignored, even when they
|
| 156 |
+
// look like potentially matching characters.
|
| 157 |
+
ExpectNumber<10>("1.23456789e5$ ", chars_format::general, 123456789, -3);
|
| 158 |
+
ExpectNumber<10>("1.23456789e5$e5e5", chars_format::general, 123456789, -3);
|
| 159 |
+
ExpectNumber<10>("1.23456789e5$.25", chars_format::general, 123456789, -3);
|
| 160 |
+
ExpectNumber<10>("1.23456789e5$-", chars_format::general, 123456789, -3);
|
| 161 |
+
ExpectNumber<10>("1.23456789e5$PUPPERS!!!", chars_format::general, 123456789,
|
| 162 |
+
-3);
|
| 163 |
+
ExpectNumber<10>("123456.789$efghij", chars_format::general, 123456789, -3);
|
| 164 |
+
ExpectNumber<10>("123456.789$e", chars_format::general, 123456789, -3);
|
| 165 |
+
ExpectNumber<10>("123456.789$p5", chars_format::general, 123456789, -3);
|
| 166 |
+
ExpectNumber<10>("123456.789$.10", chars_format::general, 123456789, -3);
|
| 167 |
+
|
| 168 |
+
ExpectNumber<16>("1.234abcdefp28$ ", chars_format::general, 0x1234abcdef,
|
| 169 |
+
-8);
|
| 170 |
+
ExpectNumber<16>("1.234abcdefp28$p28", chars_format::general, 0x1234abcdef,
|
| 171 |
+
-8);
|
| 172 |
+
ExpectNumber<16>("1.234abcdefp28$.125", chars_format::general, 0x1234abcdef,
|
| 173 |
+
-8);
|
| 174 |
+
ExpectNumber<16>("1.234abcdefp28$-", chars_format::general, 0x1234abcdef, -8);
|
| 175 |
+
ExpectNumber<16>("1.234abcdefp28$KITTEHS!!!", chars_format::general,
|
| 176 |
+
0x1234abcdef, -8);
|
| 177 |
+
ExpectNumber<16>("1234abcd.ef$ghijk", chars_format::general, 0x1234abcdef,
|
| 178 |
+
-8);
|
| 179 |
+
ExpectNumber<16>("1234abcd.ef$p", chars_format::general, 0x1234abcdef, -8);
|
| 180 |
+
ExpectNumber<16>("1234abcd.ef$.10", chars_format::general, 0x1234abcdef, -8);
|
| 181 |
+
|
| 182 |
+
// Ensure we can read a full resolution mantissa without overflow.
|
| 183 |
+
ExpectNumber<10>("9999999999999999999$", chars_format::general,
|
| 184 |
+
9999999999999999999u, 0);
|
| 185 |
+
ExpectNumber<16>("fffffffffffffff$", chars_format::general,
|
| 186 |
+
0xfffffffffffffffu, 0);
|
| 187 |
+
|
| 188 |
+
// Check that zero is consistently read.
|
| 189 |
+
ExpectNumber<10>("0$", chars_format::general, 0, 0);
|
| 190 |
+
ExpectNumber<16>("0$", chars_format::general, 0, 0);
|
| 191 |
+
ExpectNumber<10>("000000000000000000000000000000000000000$",
|
| 192 |
+
chars_format::general, 0, 0);
|
| 193 |
+
ExpectNumber<16>("000000000000000000000000000000000000000$",
|
| 194 |
+
chars_format::general, 0, 0);
|
| 195 |
+
ExpectNumber<10>("0000000000000000000000.000000000000000000$",
|
| 196 |
+
chars_format::general, 0, 0);
|
| 197 |
+
ExpectNumber<16>("0000000000000000000000.000000000000000000$",
|
| 198 |
+
chars_format::general, 0, 0);
|
| 199 |
+
ExpectNumber<10>("0.00000000000000000000000000000000e123456$",
|
| 200 |
+
chars_format::general, 0, 0);
|
| 201 |
+
ExpectNumber<16>("0.00000000000000000000000000000000p123456$",
|
| 202 |
+
chars_format::general, 0, 0);
|
| 203 |
+
}
|
| 204 |
+
|
| 205 |
+
TEST(ParseFloat, LargeDecimalMantissa) {
|
| 206 |
+
// After 19 significant decimal digits in the mantissa, ParsedFloat will
|
| 207 |
+
// truncate additional digits. We need to test that:
|
| 208 |
+
// 1) the truncation to 19 digits happens
|
| 209 |
+
// 2) the returned exponent reflects the dropped significant digits
|
| 210 |
+
// 3) a correct literal_exponent is set
|
| 211 |
+
//
|
| 212 |
+
// If and only if a significant digit is found after 19 digits, then the
|
| 213 |
+
// entirety of the mantissa in case the exact value is needed to make a
|
| 214 |
+
// rounding decision. The [ and ] characters below denote where such a
|
| 215 |
+
// subregion was marked by by ParseFloat. They are not part of the input.
|
| 216 |
+
|
| 217 |
+
// Mark a capture group only if a dropped digit is significant (nonzero).
|
| 218 |
+
ExpectNumber<10>("100000000000000000000000000$", chars_format::general,
|
| 219 |
+
1000000000000000000,
|
| 220 |
+
/* adjusted exponent */ 8);
|
| 221 |
+
|
| 222 |
+
ExpectNumber<10>("123456789123456789100000000$", chars_format::general,
|
| 223 |
+
1234567891234567891,
|
| 224 |
+
/* adjusted exponent */ 8);
|
| 225 |
+
|
| 226 |
+
ExpectNumber<10>("[123456789123456789123456789]$", chars_format::general,
|
| 227 |
+
1234567891234567891,
|
| 228 |
+
/* adjusted exponent */ 8,
|
| 229 |
+
/* literal exponent */ 0);
|
| 230 |
+
|
| 231 |
+
ExpectNumber<10>("[123456789123456789100000009]$", chars_format::general,
|
| 232 |
+
1234567891234567891,
|
| 233 |
+
/* adjusted exponent */ 8,
|
| 234 |
+
/* literal exponent */ 0);
|
| 235 |
+
|
| 236 |
+
ExpectNumber<10>("[123456789123456789120000000]$", chars_format::general,
|
| 237 |
+
1234567891234567891,
|
| 238 |
+
/* adjusted exponent */ 8,
|
| 239 |
+
/* literal exponent */ 0);
|
| 240 |
+
|
| 241 |
+
// Leading zeroes should not count towards the 19 significant digit limit
|
| 242 |
+
ExpectNumber<10>("[00000000123456789123456789123456789]$",
|
| 243 |
+
chars_format::general, 1234567891234567891,
|
| 244 |
+
/* adjusted exponent */ 8,
|
| 245 |
+
/* literal exponent */ 0);
|
| 246 |
+
|
| 247 |
+
ExpectNumber<10>("00000000123456789123456789100000000$",
|
| 248 |
+
chars_format::general, 1234567891234567891,
|
| 249 |
+
/* adjusted exponent */ 8);
|
| 250 |
+
|
| 251 |
+
// Truncated digits after the decimal point should not cause a further
|
| 252 |
+
// exponent adjustment.
|
| 253 |
+
ExpectNumber<10>("1.234567891234567891e123$", chars_format::general,
|
| 254 |
+
1234567891234567891, 105);
|
| 255 |
+
ExpectNumber<10>("[1.23456789123456789123456789]e123$", chars_format::general,
|
| 256 |
+
1234567891234567891,
|
| 257 |
+
/* adjusted exponent */ 105,
|
| 258 |
+
/* literal exponent */ 123);
|
| 259 |
+
|
| 260 |
+
// Ensure we truncate, and not round. (The from_chars algorithm we use
|
| 261 |
+
// depends on our guess missing low, if it misses, so we need the rounding
|
| 262 |
+
// error to be downward.)
|
| 263 |
+
ExpectNumber<10>("[1999999999999999999999]$", chars_format::general,
|
| 264 |
+
1999999999999999999,
|
| 265 |
+
/* adjusted exponent */ 3,
|
| 266 |
+
/* literal exponent */ 0);
|
| 267 |
+
}
|
| 268 |
+
|
| 269 |
+
TEST(ParseFloat, LargeHexadecimalMantissa) {
|
| 270 |
+
// After 15 significant hex digits in the mantissa, ParsedFloat will treat
|
| 271 |
+
// additional digits as sticky, We need to test that:
|
| 272 |
+
// 1) The truncation to 15 digits happens
|
| 273 |
+
// 2) The returned exponent reflects the dropped significant digits
|
| 274 |
+
// 3) If a nonzero digit is dropped, the low bit of mantissa is set.
|
| 275 |
+
|
| 276 |
+
ExpectNumber<16>("123456789abcdef123456789abcdef$", chars_format::general,
|
| 277 |
+
0x123456789abcdef, 60);
|
| 278 |
+
|
| 279 |
+
// Leading zeroes should not count towards the 15 significant digit limit
|
| 280 |
+
ExpectNumber<16>("000000123456789abcdef123456789abcdef$",
|
| 281 |
+
chars_format::general, 0x123456789abcdef, 60);
|
| 282 |
+
|
| 283 |
+
// Truncated digits after the radix point should not cause a further
|
| 284 |
+
// exponent adjustment.
|
| 285 |
+
ExpectNumber<16>("1.23456789abcdefp100$", chars_format::general,
|
| 286 |
+
0x123456789abcdef, 44);
|
| 287 |
+
ExpectNumber<16>("1.23456789abcdef123456789abcdefp100$",
|
| 288 |
+
chars_format::general, 0x123456789abcdef, 44);
|
| 289 |
+
|
| 290 |
+
// test sticky digit behavior. The low bit should be set iff any dropped
|
| 291 |
+
// digit is nonzero.
|
| 292 |
+
ExpectNumber<16>("123456789abcdee123456789abcdee$", chars_format::general,
|
| 293 |
+
0x123456789abcdef, 60);
|
| 294 |
+
ExpectNumber<16>("123456789abcdee000000000000001$", chars_format::general,
|
| 295 |
+
0x123456789abcdef, 60);
|
| 296 |
+
ExpectNumber<16>("123456789abcdee000000000000000$", chars_format::general,
|
| 297 |
+
0x123456789abcdee, 60);
|
| 298 |
+
}
|
| 299 |
+
|
| 300 |
+
TEST(ParseFloat, ScientificVsFixed) {
|
| 301 |
+
// In fixed mode, an exponent is never matched (but the remainder of the
|
| 302 |
+
// number will be matched.)
|
| 303 |
+
ExpectNumber<10>("1.23456789$e5", chars_format::fixed, 123456789, -8);
|
| 304 |
+
ExpectNumber<10>("123456.789$", chars_format::fixed, 123456789, -3);
|
| 305 |
+
ExpectNumber<16>("1.234abcdef$p28", chars_format::fixed, 0x1234abcdef, -36);
|
| 306 |
+
ExpectNumber<16>("1234abcd.ef$", chars_format::fixed, 0x1234abcdef, -8);
|
| 307 |
+
|
| 308 |
+
// In scientific mode, numbers don't match *unless* they have an exponent.
|
| 309 |
+
ExpectNumber<10>("1.23456789e5$", chars_format::scientific, 123456789, -3);
|
| 310 |
+
ExpectFailedParse<10>("-123456.789$", chars_format::scientific);
|
| 311 |
+
ExpectNumber<16>("1.234abcdefp28$", chars_format::scientific, 0x1234abcdef,
|
| 312 |
+
-8);
|
| 313 |
+
ExpectFailedParse<16>("1234abcd.ef$", chars_format::scientific);
|
| 314 |
+
}
|
| 315 |
+
|
| 316 |
+
TEST(ParseFloat, Infinity) {
|
| 317 |
+
ExpectFailedParse<10>("in", chars_format::general);
|
| 318 |
+
ExpectFailedParse<16>("in", chars_format::general);
|
| 319 |
+
ExpectFailedParse<10>("inx", chars_format::general);
|
| 320 |
+
ExpectFailedParse<16>("inx", chars_format::general);
|
| 321 |
+
ExpectSpecial("inf$", chars_format::general, FloatType::kInfinity);
|
| 322 |
+
ExpectSpecial("Inf$", chars_format::general, FloatType::kInfinity);
|
| 323 |
+
ExpectSpecial("INF$", chars_format::general, FloatType::kInfinity);
|
| 324 |
+
ExpectSpecial("inf$inite", chars_format::general, FloatType::kInfinity);
|
| 325 |
+
ExpectSpecial("iNfInItY$", chars_format::general, FloatType::kInfinity);
|
| 326 |
+
ExpectSpecial("infinity$!!!", chars_format::general, FloatType::kInfinity);
|
| 327 |
+
}
|
| 328 |
+
|
| 329 |
+
TEST(ParseFloat, NaN) {
|
| 330 |
+
ExpectFailedParse<10>("na", chars_format::general);
|
| 331 |
+
ExpectFailedParse<16>("na", chars_format::general);
|
| 332 |
+
ExpectFailedParse<10>("nah", chars_format::general);
|
| 333 |
+
ExpectFailedParse<16>("nah", chars_format::general);
|
| 334 |
+
ExpectSpecial("nan$", chars_format::general, FloatType::kNan);
|
| 335 |
+
ExpectSpecial("NaN$", chars_format::general, FloatType::kNan);
|
| 336 |
+
ExpectSpecial("nAn$", chars_format::general, FloatType::kNan);
|
| 337 |
+
ExpectSpecial("NAN$", chars_format::general, FloatType::kNan);
|
| 338 |
+
ExpectSpecial("NaN$aNaNaNaNaBatman!", chars_format::general, FloatType::kNan);
|
| 339 |
+
|
| 340 |
+
// A parenthesized sequence of the characters [a-zA-Z0-9_] is allowed to
|
| 341 |
+
// appear after an NaN. Check that this is allowed, and that the correct
|
| 342 |
+
// characters are grouped.
|
| 343 |
+
//
|
| 344 |
+
// (The characters [ and ] in the pattern below delimit the expected matched
|
| 345 |
+
// subgroup; they are not part of the input passed to ParseFloat.)
|
| 346 |
+
ExpectSpecial("nan([0xabcdef])$", chars_format::general, FloatType::kNan);
|
| 347 |
+
ExpectSpecial("nan([0xabcdef])$...", chars_format::general, FloatType::kNan);
|
| 348 |
+
ExpectSpecial("nan([0xabcdef])$)...", chars_format::general, FloatType::kNan);
|
| 349 |
+
ExpectSpecial("nan([])$", chars_format::general, FloatType::kNan);
|
| 350 |
+
ExpectSpecial("nan([aAzZ09_])$", chars_format::general, FloatType::kNan);
|
| 351 |
+
// If the subgroup contains illegal characters, don't match it at all.
|
| 352 |
+
ExpectSpecial("nan$(bad-char)", chars_format::general, FloatType::kNan);
|
| 353 |
+
// Also cope with a missing close paren.
|
| 354 |
+
ExpectSpecial("nan$(0xabcdef", chars_format::general, FloatType::kNan);
|
| 355 |
+
}
|
| 356 |
+
|
| 357 |
+
} // namespace
|
weight/_dep/abseil-cpp/absl/strings/internal/cord_data_edge_test.cc
ADDED
|
@@ -0,0 +1,130 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
// Copyright 2022 The Abseil Authors
|
| 2 |
+
//
|
| 3 |
+
// Licensed under the Apache License, Version 2.0 (the "License");
|
| 4 |
+
// you may not use this file except in compliance with the License.
|
| 5 |
+
// You may obtain a copy of the License at
|
| 6 |
+
//
|
| 7 |
+
// https://www.apache.org/licenses/LICENSE-2.0
|
| 8 |
+
//
|
| 9 |
+
// Unless required by applicable law or agreed to in writing, software
|
| 10 |
+
// distributed under the License is distributed on an "AS IS" BASIS,
|
| 11 |
+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
| 12 |
+
// See the License for the specific language governing permissions and
|
| 13 |
+
// limitations under the License.
|
| 14 |
+
|
| 15 |
+
#include "absl/strings/internal/cord_data_edge.h"
|
| 16 |
+
|
| 17 |
+
#include "gmock/gmock.h"
|
| 18 |
+
#include "gtest/gtest.h"
|
| 19 |
+
#include "absl/strings/internal/cord_internal.h"
|
| 20 |
+
#include "absl/strings/internal/cord_rep_test_util.h"
|
| 21 |
+
|
| 22 |
+
namespace absl {
|
| 23 |
+
ABSL_NAMESPACE_BEGIN
|
| 24 |
+
namespace cord_internal {
|
| 25 |
+
namespace {
|
| 26 |
+
|
| 27 |
+
using ::absl::cordrep_testing::MakeExternal;
|
| 28 |
+
using ::absl::cordrep_testing::MakeFlat;
|
| 29 |
+
using ::absl::cordrep_testing::MakeSubstring;
|
| 30 |
+
|
| 31 |
+
TEST(CordDataEdgeTest, IsDataEdgeOnFlat) {
|
| 32 |
+
CordRep* rep = MakeFlat("Lorem ipsum dolor sit amet, consectetur ...");
|
| 33 |
+
EXPECT_TRUE(IsDataEdge(rep));
|
| 34 |
+
CordRep::Unref(rep);
|
| 35 |
+
}
|
| 36 |
+
|
| 37 |
+
TEST(CordDataEdgeTest, IsDataEdgeOnExternal) {
|
| 38 |
+
CordRep* rep = MakeExternal("Lorem ipsum dolor sit amet, consectetur ...");
|
| 39 |
+
EXPECT_TRUE(IsDataEdge(rep));
|
| 40 |
+
CordRep::Unref(rep);
|
| 41 |
+
}
|
| 42 |
+
|
| 43 |
+
TEST(CordDataEdgeTest, IsDataEdgeOnSubstringOfFlat) {
|
| 44 |
+
CordRep* rep = MakeFlat("Lorem ipsum dolor sit amet, consectetur ...");
|
| 45 |
+
CordRep* substr = MakeSubstring(1, 20, rep);
|
| 46 |
+
EXPECT_TRUE(IsDataEdge(substr));
|
| 47 |
+
CordRep::Unref(substr);
|
| 48 |
+
}
|
| 49 |
+
|
| 50 |
+
TEST(CordDataEdgeTest, IsDataEdgeOnSubstringOfExternal) {
|
| 51 |
+
CordRep* rep = MakeExternal("Lorem ipsum dolor sit amet, consectetur ...");
|
| 52 |
+
CordRep* substr = MakeSubstring(1, 20, rep);
|
| 53 |
+
EXPECT_TRUE(IsDataEdge(substr));
|
| 54 |
+
CordRep::Unref(substr);
|
| 55 |
+
}
|
| 56 |
+
|
| 57 |
+
TEST(CordDataEdgeTest, IsDataEdgeOnBtree) {
|
| 58 |
+
CordRep* rep = MakeFlat("Lorem ipsum dolor sit amet, consectetur ...");
|
| 59 |
+
CordRepBtree* tree = CordRepBtree::New(rep);
|
| 60 |
+
EXPECT_FALSE(IsDataEdge(tree));
|
| 61 |
+
CordRep::Unref(tree);
|
| 62 |
+
}
|
| 63 |
+
|
| 64 |
+
TEST(CordDataEdgeTest, IsDataEdgeOnBadSubstr) {
|
| 65 |
+
CordRep* rep = MakeFlat("Lorem ipsum dolor sit amet, consectetur ...");
|
| 66 |
+
CordRep* substr = MakeSubstring(1, 18, MakeSubstring(1, 20, rep));
|
| 67 |
+
EXPECT_FALSE(IsDataEdge(substr));
|
| 68 |
+
CordRep::Unref(substr);
|
| 69 |
+
}
|
| 70 |
+
|
| 71 |
+
TEST(CordDataEdgeTest, EdgeDataOnFlat) {
|
| 72 |
+
absl::string_view value = "Lorem ipsum dolor sit amet, consectetur ...";
|
| 73 |
+
CordRep* rep = MakeFlat(value);
|
| 74 |
+
EXPECT_EQ(EdgeData(rep), value);
|
| 75 |
+
CordRep::Unref(rep);
|
| 76 |
+
}
|
| 77 |
+
|
| 78 |
+
TEST(CordDataEdgeTest, EdgeDataOnExternal) {
|
| 79 |
+
absl::string_view value = "Lorem ipsum dolor sit amet, consectetur ...";
|
| 80 |
+
CordRep* rep = MakeExternal(value);
|
| 81 |
+
EXPECT_EQ(EdgeData(rep), value);
|
| 82 |
+
CordRep::Unref(rep);
|
| 83 |
+
}
|
| 84 |
+
|
| 85 |
+
TEST(CordDataEdgeTest, EdgeDataOnSubstringOfFlat) {
|
| 86 |
+
absl::string_view value = "Lorem ipsum dolor sit amet, consectetur ...";
|
| 87 |
+
CordRep* rep = MakeFlat(value);
|
| 88 |
+
CordRep* substr = MakeSubstring(1, 20, rep);
|
| 89 |
+
EXPECT_EQ(EdgeData(substr), value.substr(1, 20));
|
| 90 |
+
CordRep::Unref(substr);
|
| 91 |
+
}
|
| 92 |
+
|
| 93 |
+
TEST(CordDataEdgeTest, EdgeDataOnSubstringOfExternal) {
|
| 94 |
+
absl::string_view value = "Lorem ipsum dolor sit amet, consectetur ...";
|
| 95 |
+
CordRep* rep = MakeExternal(value);
|
| 96 |
+
CordRep* substr = MakeSubstring(1, 20, rep);
|
| 97 |
+
EXPECT_EQ(EdgeData(substr), value.substr(1, 20));
|
| 98 |
+
CordRep::Unref(substr);
|
| 99 |
+
}
|
| 100 |
+
|
| 101 |
+
#if defined(GTEST_HAS_DEATH_TEST) && !defined(NDEBUG)
|
| 102 |
+
|
| 103 |
+
TEST(CordDataEdgeTest, IsDataEdgeOnNullPtr) {
|
| 104 |
+
EXPECT_DEATH(IsDataEdge(nullptr), ".*");
|
| 105 |
+
}
|
| 106 |
+
|
| 107 |
+
TEST(CordDataEdgeTest, EdgeDataOnNullPtr) {
|
| 108 |
+
EXPECT_DEATH(EdgeData(nullptr), ".*");
|
| 109 |
+
}
|
| 110 |
+
|
| 111 |
+
TEST(CordDataEdgeTest, EdgeDataOnBtree) {
|
| 112 |
+
CordRep* rep = MakeFlat("Lorem ipsum dolor sit amet, consectetur ...");
|
| 113 |
+
CordRepBtree* tree = CordRepBtree::New(rep);
|
| 114 |
+
EXPECT_DEATH(EdgeData(tree), ".*");
|
| 115 |
+
CordRep::Unref(tree);
|
| 116 |
+
}
|
| 117 |
+
|
| 118 |
+
TEST(CordDataEdgeTest, EdgeDataOnBadSubstr) {
|
| 119 |
+
CordRep* rep = MakeFlat("Lorem ipsum dolor sit amet, consectetur ...");
|
| 120 |
+
CordRep* substr = MakeSubstring(1, 18, MakeSubstring(1, 20, rep));
|
| 121 |
+
EXPECT_DEATH(EdgeData(substr), ".*");
|
| 122 |
+
CordRep::Unref(substr);
|
| 123 |
+
}
|
| 124 |
+
|
| 125 |
+
#endif // GTEST_HAS_DEATH_TEST && !NDEBUG
|
| 126 |
+
|
| 127 |
+
} // namespace
|
| 128 |
+
} // namespace cord_internal
|
| 129 |
+
ABSL_NAMESPACE_END
|
| 130 |
+
} // namespace absl
|
weight/_dep/abseil-cpp/absl/strings/internal/cord_rep_btree.cc
ADDED
|
@@ -0,0 +1,1241 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
// Copyright 2021 The Abseil Authors
|
| 2 |
+
//
|
| 3 |
+
// Licensed under the Apache License, Version 2.0 (the "License");
|
| 4 |
+
// you may not use this file except in compliance with the License.
|
| 5 |
+
// You may obtain a copy of the License at
|
| 6 |
+
//
|
| 7 |
+
// https://www.apache.org/licenses/LICENSE-2.0
|
| 8 |
+
//
|
| 9 |
+
// Unless required by applicable law or agreed to in writing, software
|
| 10 |
+
// distributed under the License is distributed on an "AS IS" BASIS,
|
| 11 |
+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
| 12 |
+
// See the License for the specific language governing permissions and
|
| 13 |
+
// limitations under the License.
|
| 14 |
+
|
| 15 |
+
#include "absl/strings/internal/cord_rep_btree.h"
|
| 16 |
+
|
| 17 |
+
#include <atomic>
|
| 18 |
+
#include <cassert>
|
| 19 |
+
#include <cstdint>
|
| 20 |
+
#include <iostream>
|
| 21 |
+
#include <ostream>
|
| 22 |
+
#include <string>
|
| 23 |
+
|
| 24 |
+
#include "absl/base/attributes.h"
|
| 25 |
+
#include "absl/base/config.h"
|
| 26 |
+
#include "absl/base/internal/raw_logging.h"
|
| 27 |
+
#include "absl/base/optimization.h"
|
| 28 |
+
#include "absl/strings/internal/cord_data_edge.h"
|
| 29 |
+
#include "absl/strings/internal/cord_internal.h"
|
| 30 |
+
#include "absl/strings/internal/cord_rep_consume.h"
|
| 31 |
+
#include "absl/strings/internal/cord_rep_flat.h"
|
| 32 |
+
#include "absl/strings/str_cat.h"
|
| 33 |
+
#include "absl/strings/string_view.h"
|
| 34 |
+
|
| 35 |
+
namespace absl {
|
| 36 |
+
ABSL_NAMESPACE_BEGIN
|
| 37 |
+
namespace cord_internal {
|
| 38 |
+
|
| 39 |
+
#ifdef ABSL_INTERNAL_NEED_REDUNDANT_CONSTEXPR_DECL
|
| 40 |
+
constexpr size_t CordRepBtree::kMaxCapacity;
|
| 41 |
+
#endif
|
| 42 |
+
|
| 43 |
+
namespace {
|
| 44 |
+
|
| 45 |
+
using NodeStack = CordRepBtree * [CordRepBtree::kMaxDepth];
|
| 46 |
+
using EdgeType = CordRepBtree::EdgeType;
|
| 47 |
+
using OpResult = CordRepBtree::OpResult;
|
| 48 |
+
using CopyResult = CordRepBtree::CopyResult;
|
| 49 |
+
|
| 50 |
+
constexpr auto kFront = CordRepBtree::kFront;
|
| 51 |
+
constexpr auto kBack = CordRepBtree::kBack;
|
| 52 |
+
|
| 53 |
+
ABSL_CONST_INIT std::atomic<bool> cord_btree_exhaustive_validation(false);
|
| 54 |
+
|
| 55 |
+
// Implementation of the various 'Dump' functions.
|
| 56 |
+
// Prints the entire tree structure or 'rep'. External callers should
|
| 57 |
+
// not specify 'depth' and leave it to its default (0) value.
|
| 58 |
+
// Rep may be a CordRepBtree tree, or a SUBSTRING / EXTERNAL / FLAT node.
|
| 59 |
+
void DumpAll(const CordRep* rep,
|
| 60 |
+
bool include_contents,
|
| 61 |
+
std::ostream& stream,
|
| 62 |
+
size_t depth = 0) {
|
| 63 |
+
// Allow for full height trees + substring -> flat / external nodes.
|
| 64 |
+
assert(depth <= CordRepBtree::kMaxDepth + 2);
|
| 65 |
+
std::string sharing = const_cast<CordRep*>(rep)->refcount.IsOne()
|
| 66 |
+
? std::string("Private")
|
| 67 |
+
: absl::StrCat("Shared(", rep->refcount.Get(), ")");
|
| 68 |
+
std::string sptr = absl::StrCat("0x", absl::Hex(rep));
|
| 69 |
+
|
| 70 |
+
// Dumps the data contents of `rep` if `include_contents` is true.
|
| 71 |
+
// Always emits a new line character.
|
| 72 |
+
auto maybe_dump_data = [&stream, include_contents](const CordRep* r) {
|
| 73 |
+
if (include_contents) {
|
| 74 |
+
// Allow for up to 60 wide display of content data, which with some
|
| 75 |
+
// indentation and prefix / labels keeps us within roughly 80-100 wide.
|
| 76 |
+
constexpr size_t kMaxDataLength = 60;
|
| 77 |
+
stream << ", data = \""
|
| 78 |
+
<< EdgeData(r).substr(0, kMaxDataLength)
|
| 79 |
+
<< (r->length > kMaxDataLength ? "\"..." : "\"");
|
| 80 |
+
}
|
| 81 |
+
stream << '\n';
|
| 82 |
+
};
|
| 83 |
+
|
| 84 |
+
// For each level, we print the 'shared/private' state and the rep pointer,
|
| 85 |
+
// indented by two spaces per recursive depth.
|
| 86 |
+
stream << std::string(depth * 2, ' ') << sharing << " (" << sptr << ") ";
|
| 87 |
+
|
| 88 |
+
if (rep->IsBtree()) {
|
| 89 |
+
const CordRepBtree* node = rep->btree();
|
| 90 |
+
std::string label =
|
| 91 |
+
node->height() ? absl::StrCat("Node(", node->height(), ")") : "Leaf";
|
| 92 |
+
stream << label << ", len = " << node->length
|
| 93 |
+
<< ", begin = " << node->begin() << ", end = " << node->end()
|
| 94 |
+
<< "\n";
|
| 95 |
+
for (CordRep* edge : node->Edges()) {
|
| 96 |
+
DumpAll(edge, include_contents, stream, depth + 1);
|
| 97 |
+
}
|
| 98 |
+
} else if (rep->tag == SUBSTRING) {
|
| 99 |
+
const CordRepSubstring* substring = rep->substring();
|
| 100 |
+
stream << "Substring, len = " << rep->length
|
| 101 |
+
<< ", start = " << substring->start;
|
| 102 |
+
maybe_dump_data(rep);
|
| 103 |
+
DumpAll(substring->child, include_contents, stream, depth + 1);
|
| 104 |
+
} else if (rep->tag >= FLAT) {
|
| 105 |
+
stream << "Flat, len = " << rep->length
|
| 106 |
+
<< ", cap = " << rep->flat()->Capacity();
|
| 107 |
+
maybe_dump_data(rep);
|
| 108 |
+
} else if (rep->tag == EXTERNAL) {
|
| 109 |
+
stream << "Extn, len = " << rep->length;
|
| 110 |
+
maybe_dump_data(rep);
|
| 111 |
+
}
|
| 112 |
+
}
|
| 113 |
+
|
| 114 |
+
// TODO(b/192061034): add 'bytes to copy' logic to avoid large slop on substring
|
| 115 |
+
// small data out of large reps, and general efficiency of 'always copy small
|
| 116 |
+
// data'. Consider making this a cord rep internal library function.
|
| 117 |
+
CordRepSubstring* CreateSubstring(CordRep* rep, size_t offset, size_t n) {
|
| 118 |
+
assert(n != 0);
|
| 119 |
+
assert(offset + n <= rep->length);
|
| 120 |
+
assert(offset != 0 || n != rep->length);
|
| 121 |
+
|
| 122 |
+
if (rep->tag == SUBSTRING) {
|
| 123 |
+
CordRepSubstring* substring = rep->substring();
|
| 124 |
+
offset += substring->start;
|
| 125 |
+
rep = CordRep::Ref(substring->child);
|
| 126 |
+
CordRep::Unref(substring);
|
| 127 |
+
}
|
| 128 |
+
assert(rep->IsExternal() || rep->IsFlat());
|
| 129 |
+
CordRepSubstring* substring = new CordRepSubstring();
|
| 130 |
+
substring->length = n;
|
| 131 |
+
substring->tag = SUBSTRING;
|
| 132 |
+
substring->start = offset;
|
| 133 |
+
substring->child = rep;
|
| 134 |
+
return substring;
|
| 135 |
+
}
|
| 136 |
+
|
| 137 |
+
// TODO(b/192061034): consider making this a cord rep library function.
|
| 138 |
+
inline CordRep* MakeSubstring(CordRep* rep, size_t offset, size_t n) {
|
| 139 |
+
if (n == rep->length) return rep;
|
| 140 |
+
if (n == 0) return CordRep::Unref(rep), nullptr;
|
| 141 |
+
return CreateSubstring(rep, offset, n);
|
| 142 |
+
}
|
| 143 |
+
|
| 144 |
+
// TODO(b/192061034): consider making this a cord rep library function.
|
| 145 |
+
inline CordRep* MakeSubstring(CordRep* rep, size_t offset) {
|
| 146 |
+
if (offset == 0) return rep;
|
| 147 |
+
return CreateSubstring(rep, offset, rep->length - offset);
|
| 148 |
+
}
|
| 149 |
+
|
| 150 |
+
// Resizes `edge` to the provided `length`. Adopts a reference on `edge`.
|
| 151 |
+
// This method directly returns `edge` if `length` equals `edge->length`.
|
| 152 |
+
// If `is_mutable` is set to true, this function may return `edge` with
|
| 153 |
+
// `edge->length` set to the new length depending on the type and size of
|
| 154 |
+
// `edge`. Otherwise, this function returns a new CordRepSubstring value.
|
| 155 |
+
// Requires `length > 0 && length <= edge->length`.
|
| 156 |
+
CordRep* ResizeEdge(CordRep* edge, size_t length, bool is_mutable) {
|
| 157 |
+
assert(length > 0);
|
| 158 |
+
assert(length <= edge->length);
|
| 159 |
+
assert(IsDataEdge(edge));
|
| 160 |
+
if (length >= edge->length) return edge;
|
| 161 |
+
|
| 162 |
+
if (is_mutable && (edge->tag >= FLAT || edge->tag == SUBSTRING)) {
|
| 163 |
+
edge->length = length;
|
| 164 |
+
return edge;
|
| 165 |
+
}
|
| 166 |
+
|
| 167 |
+
return CreateSubstring(edge, 0, length);
|
| 168 |
+
}
|
| 169 |
+
|
| 170 |
+
template <EdgeType edge_type>
|
| 171 |
+
inline absl::string_view Consume(absl::string_view s, size_t n) {
|
| 172 |
+
return edge_type == kBack ? s.substr(n) : s.substr(0, s.size() - n);
|
| 173 |
+
}
|
| 174 |
+
|
| 175 |
+
template <EdgeType edge_type>
|
| 176 |
+
inline absl::string_view Consume(char* dst, absl::string_view s, size_t n) {
|
| 177 |
+
if (edge_type == kBack) {
|
| 178 |
+
memcpy(dst, s.data(), n);
|
| 179 |
+
return s.substr(n);
|
| 180 |
+
} else {
|
| 181 |
+
const size_t offset = s.size() - n;
|
| 182 |
+
memcpy(dst, s.data() + offset, n);
|
| 183 |
+
return s.substr(0, offset);
|
| 184 |
+
}
|
| 185 |
+
}
|
| 186 |
+
|
| 187 |
+
// Known issue / optimization weirdness: the store associated with the
|
| 188 |
+
// decrement introduces traffic between cpus (even if the result of that
|
| 189 |
+
// traffic does nothing), making this faster than a single call to
|
| 190 |
+
// refcount.Decrement() checking the zero refcount condition.
|
| 191 |
+
template <typename R, typename Fn>
|
| 192 |
+
inline void FastUnref(R* r, Fn&& fn) {
|
| 193 |
+
if (r->refcount.IsOne()) {
|
| 194 |
+
fn(r);
|
| 195 |
+
} else if (!r->refcount.DecrementExpectHighRefcount()) {
|
| 196 |
+
fn(r);
|
| 197 |
+
}
|
| 198 |
+
}
|
| 199 |
+
|
| 200 |
+
|
| 201 |
+
void DeleteSubstring(CordRepSubstring* substring) {
|
| 202 |
+
CordRep* rep = substring->child;
|
| 203 |
+
if (!rep->refcount.Decrement()) {
|
| 204 |
+
if (rep->tag >= FLAT) {
|
| 205 |
+
CordRepFlat::Delete(rep->flat());
|
| 206 |
+
} else {
|
| 207 |
+
assert(rep->tag == EXTERNAL);
|
| 208 |
+
CordRepExternal::Delete(rep->external());
|
| 209 |
+
}
|
| 210 |
+
}
|
| 211 |
+
delete substring;
|
| 212 |
+
}
|
| 213 |
+
|
| 214 |
+
// Deletes a leaf node data edge. Requires `IsDataEdge(rep)`.
|
| 215 |
+
void DeleteLeafEdge(CordRep* rep) {
|
| 216 |
+
assert(IsDataEdge(rep));
|
| 217 |
+
if (rep->tag >= FLAT) {
|
| 218 |
+
CordRepFlat::Delete(rep->flat());
|
| 219 |
+
} else if (rep->tag == EXTERNAL) {
|
| 220 |
+
CordRepExternal::Delete(rep->external());
|
| 221 |
+
} else {
|
| 222 |
+
DeleteSubstring(rep->substring());
|
| 223 |
+
}
|
| 224 |
+
}
|
| 225 |
+
|
| 226 |
+
// StackOperations contains the logic to build a left-most or right-most stack
|
| 227 |
+
// (leg) down to the leaf level of a btree, and 'unwind' / 'Finalize' methods to
|
| 228 |
+
// propagate node changes up the stack.
|
| 229 |
+
template <EdgeType edge_type>
|
| 230 |
+
struct StackOperations {
|
| 231 |
+
// Returns true if the node at 'depth' is not shared, i.e. has a refcount
|
| 232 |
+
// of one and all of its parent nodes have a refcount of one.
|
| 233 |
+
inline bool owned(int depth) const { return depth < share_depth; }
|
| 234 |
+
|
| 235 |
+
// Returns the node at 'depth'.
|
| 236 |
+
inline CordRepBtree* node(int depth) const { return stack[depth]; }
|
| 237 |
+
|
| 238 |
+
// Builds a `depth` levels deep stack starting at `tree` recording which nodes
|
| 239 |
+
// are private in the form of the 'share depth' where nodes are shared.
|
| 240 |
+
inline CordRepBtree* BuildStack(CordRepBtree* tree, int depth) {
|
| 241 |
+
assert(depth <= tree->height());
|
| 242 |
+
int current_depth = 0;
|
| 243 |
+
while (current_depth < depth && tree->refcount.IsOne()) {
|
| 244 |
+
stack[current_depth++] = tree;
|
| 245 |
+
tree = tree->Edge(edge_type)->btree();
|
| 246 |
+
}
|
| 247 |
+
share_depth = current_depth + (tree->refcount.IsOne() ? 1 : 0);
|
| 248 |
+
while (current_depth < depth) {
|
| 249 |
+
stack[current_depth++] = tree;
|
| 250 |
+
tree = tree->Edge(edge_type)->btree();
|
| 251 |
+
}
|
| 252 |
+
return tree;
|
| 253 |
+
}
|
| 254 |
+
|
| 255 |
+
// Builds a stack with the invariant that all nodes are private owned / not
|
| 256 |
+
// shared. This is used in iterative updates where a previous propagation
|
| 257 |
+
// guaranteed all nodes are owned / private.
|
| 258 |
+
inline void BuildOwnedStack(CordRepBtree* tree, int height) {
|
| 259 |
+
assert(height <= CordRepBtree::kMaxHeight);
|
| 260 |
+
int depth = 0;
|
| 261 |
+
while (depth < height) {
|
| 262 |
+
assert(tree->refcount.IsOne());
|
| 263 |
+
stack[depth++] = tree;
|
| 264 |
+
tree = tree->Edge(edge_type)->btree();
|
| 265 |
+
}
|
| 266 |
+
assert(tree->refcount.IsOne());
|
| 267 |
+
share_depth = depth + 1;
|
| 268 |
+
}
|
| 269 |
+
|
| 270 |
+
// Processes the final 'top level' result action for the tree.
|
| 271 |
+
// See the 'Action' enum for the various action implications.
|
| 272 |
+
static inline CordRepBtree* Finalize(CordRepBtree* tree, OpResult result) {
|
| 273 |
+
switch (result.action) {
|
| 274 |
+
case CordRepBtree::kPopped:
|
| 275 |
+
tree = edge_type == kBack ? CordRepBtree::New(tree, result.tree)
|
| 276 |
+
: CordRepBtree::New(result.tree, tree);
|
| 277 |
+
if (ABSL_PREDICT_FALSE(tree->height() > CordRepBtree::kMaxHeight)) {
|
| 278 |
+
tree = CordRepBtree::Rebuild(tree);
|
| 279 |
+
ABSL_RAW_CHECK(tree->height() <= CordRepBtree::kMaxHeight,
|
| 280 |
+
"Max height exceeded");
|
| 281 |
+
}
|
| 282 |
+
return tree;
|
| 283 |
+
case CordRepBtree::kCopied:
|
| 284 |
+
CordRep::Unref(tree);
|
| 285 |
+
ABSL_FALLTHROUGH_INTENDED;
|
| 286 |
+
case CordRepBtree::kSelf:
|
| 287 |
+
return result.tree;
|
| 288 |
+
}
|
| 289 |
+
ABSL_UNREACHABLE();
|
| 290 |
+
return result.tree;
|
| 291 |
+
}
|
| 292 |
+
|
| 293 |
+
// Propagate the action result in 'result' up into all nodes of the stack
|
| 294 |
+
// starting at depth 'depth'. 'length' contains the extra length of data that
|
| 295 |
+
// was added at the lowest level, and is updated into all nodes of the stack.
|
| 296 |
+
// See the 'Action' enum for the various action implications.
|
| 297 |
+
// If 'propagate' is true, then any copied node values are updated into the
|
| 298 |
+
// stack, which is used for iterative processing on the same stack.
|
| 299 |
+
template <bool propagate = false>
|
| 300 |
+
inline CordRepBtree* Unwind(CordRepBtree* tree, int depth, size_t length,
|
| 301 |
+
OpResult result) {
|
| 302 |
+
// TODO(mvels): revisit the below code to check if 3 loops with 3
|
| 303 |
+
// (incremental) conditions is faster than 1 loop with a switch.
|
| 304 |
+
// Benchmarking and perf recordings indicate the loop with switch is
|
| 305 |
+
// fastest, likely because of indirect jumps on the tight case values and
|
| 306 |
+
// dense branches. But it's worth considering 3 loops, as the `action`
|
| 307 |
+
// transitions are mono directional. E.g.:
|
| 308 |
+
// while (action == kPopped) {
|
| 309 |
+
// ...
|
| 310 |
+
// }
|
| 311 |
+
// while (action == kCopied) {
|
| 312 |
+
// ...
|
| 313 |
+
// }
|
| 314 |
+
// ...
|
| 315 |
+
// We also found that an "if () do {}" loop here seems faster, possibly
|
| 316 |
+
// because it allows the branch predictor more granular heuristics on
|
| 317 |
+
// 'single leaf' (`depth` == 0) and 'single depth' (`depth` == 1) cases
|
| 318 |
+
// which appear to be the most common use cases.
|
| 319 |
+
if (depth != 0) {
|
| 320 |
+
do {
|
| 321 |
+
CordRepBtree* node = stack[--depth];
|
| 322 |
+
const bool owned = depth < share_depth;
|
| 323 |
+
switch (result.action) {
|
| 324 |
+
case CordRepBtree::kPopped:
|
| 325 |
+
assert(!propagate);
|
| 326 |
+
result = node->AddEdge<edge_type>(owned, result.tree, length);
|
| 327 |
+
break;
|
| 328 |
+
case CordRepBtree::kCopied:
|
| 329 |
+
result = node->SetEdge<edge_type>(owned, result.tree, length);
|
| 330 |
+
if (propagate) stack[depth] = result.tree;
|
| 331 |
+
break;
|
| 332 |
+
case CordRepBtree::kSelf:
|
| 333 |
+
node->length += length;
|
| 334 |
+
while (depth > 0) {
|
| 335 |
+
node = stack[--depth];
|
| 336 |
+
node->length += length;
|
| 337 |
+
}
|
| 338 |
+
return node;
|
| 339 |
+
}
|
| 340 |
+
} while (depth > 0);
|
| 341 |
+
}
|
| 342 |
+
return Finalize(tree, result);
|
| 343 |
+
}
|
| 344 |
+
|
| 345 |
+
// Invokes `Unwind` with `propagate=true` to update the stack node values.
|
| 346 |
+
inline CordRepBtree* Propagate(CordRepBtree* tree, int depth, size_t length,
|
| 347 |
+
OpResult result) {
|
| 348 |
+
return Unwind</*propagate=*/true>(tree, depth, length, result);
|
| 349 |
+
}
|
| 350 |
+
|
| 351 |
+
// `share_depth` contains the depth at which the nodes in the stack become
|
| 352 |
+
// shared. I.e., if the top most level is shared (i.e.: `!refcount.IsOne()`),
|
| 353 |
+
// then `share_depth` is 0. If the 2nd node is shared (and implicitly all
|
| 354 |
+
// nodes below that) then `share_depth` is 1, etc. A `share_depth` greater
|
| 355 |
+
// than the depth of the stack indicates that none of the nodes in the stack
|
| 356 |
+
// are shared.
|
| 357 |
+
int share_depth;
|
| 358 |
+
|
| 359 |
+
NodeStack stack;
|
| 360 |
+
};
|
| 361 |
+
|
| 362 |
+
} // namespace
|
| 363 |
+
|
| 364 |
+
void SetCordBtreeExhaustiveValidation(bool do_exaustive_validation) {
|
| 365 |
+
cord_btree_exhaustive_validation.store(do_exaustive_validation,
|
| 366 |
+
std::memory_order_relaxed);
|
| 367 |
+
}
|
| 368 |
+
|
| 369 |
+
bool IsCordBtreeExhaustiveValidationEnabled() {
|
| 370 |
+
return cord_btree_exhaustive_validation.load(std::memory_order_relaxed);
|
| 371 |
+
}
|
| 372 |
+
|
| 373 |
+
void CordRepBtree::Dump(const CordRep* rep, absl::string_view label,
|
| 374 |
+
bool include_contents, std::ostream& stream) {
|
| 375 |
+
stream << "===================================\n";
|
| 376 |
+
if (!label.empty()) {
|
| 377 |
+
stream << label << '\n';
|
| 378 |
+
stream << "-----------------------------------\n";
|
| 379 |
+
}
|
| 380 |
+
if (rep) {
|
| 381 |
+
DumpAll(rep, include_contents, stream);
|
| 382 |
+
} else {
|
| 383 |
+
stream << "NULL\n";
|
| 384 |
+
}
|
| 385 |
+
}
|
| 386 |
+
|
| 387 |
+
void CordRepBtree::Dump(const CordRep* rep, absl::string_view label,
|
| 388 |
+
std::ostream& stream) {
|
| 389 |
+
Dump(rep, label, false, stream);
|
| 390 |
+
}
|
| 391 |
+
|
| 392 |
+
void CordRepBtree::Dump(const CordRep* rep, std::ostream& stream) {
|
| 393 |
+
Dump(rep, absl::string_view(), false, stream);
|
| 394 |
+
}
|
| 395 |
+
|
| 396 |
+
template <size_t size>
|
| 397 |
+
static void DestroyTree(CordRepBtree* tree) {
|
| 398 |
+
for (CordRep* node : tree->Edges()) {
|
| 399 |
+
if (node->refcount.Decrement()) continue;
|
| 400 |
+
for (CordRep* edge : node->btree()->Edges()) {
|
| 401 |
+
if (edge->refcount.Decrement()) continue;
|
| 402 |
+
if (size == 1) {
|
| 403 |
+
DeleteLeafEdge(edge);
|
| 404 |
+
} else {
|
| 405 |
+
CordRepBtree::Destroy(edge->btree());
|
| 406 |
+
}
|
| 407 |
+
}
|
| 408 |
+
CordRepBtree::Delete(node->btree());
|
| 409 |
+
}
|
| 410 |
+
CordRepBtree::Delete(tree);
|
| 411 |
+
}
|
| 412 |
+
|
| 413 |
+
void CordRepBtree::Destroy(CordRepBtree* tree) {
|
| 414 |
+
switch (tree->height()) {
|
| 415 |
+
case 0:
|
| 416 |
+
for (CordRep* edge : tree->Edges()) {
|
| 417 |
+
if (!edge->refcount.Decrement()) {
|
| 418 |
+
DeleteLeafEdge(edge);
|
| 419 |
+
}
|
| 420 |
+
}
|
| 421 |
+
return CordRepBtree::Delete(tree);
|
| 422 |
+
case 1:
|
| 423 |
+
return DestroyTree<1>(tree);
|
| 424 |
+
default:
|
| 425 |
+
return DestroyTree<2>(tree);
|
| 426 |
+
}
|
| 427 |
+
}
|
| 428 |
+
|
| 429 |
+
bool CordRepBtree::IsValid(const CordRepBtree* tree, bool shallow) {
|
| 430 |
+
#define NODE_CHECK_VALID(x) \
|
| 431 |
+
if (!(x)) { \
|
| 432 |
+
ABSL_RAW_LOG(ERROR, "CordRepBtree::CheckValid() FAILED: %s", #x); \
|
| 433 |
+
return false; \
|
| 434 |
+
}
|
| 435 |
+
#define NODE_CHECK_EQ(x, y) \
|
| 436 |
+
if ((x) != (y)) { \
|
| 437 |
+
ABSL_RAW_LOG(ERROR, \
|
| 438 |
+
"CordRepBtree::CheckValid() FAILED: %s != %s (%s vs %s)", #x, \
|
| 439 |
+
#y, absl::StrCat(x).c_str(), absl::StrCat(y).c_str()); \
|
| 440 |
+
return false; \
|
| 441 |
+
}
|
| 442 |
+
|
| 443 |
+
NODE_CHECK_VALID(tree != nullptr);
|
| 444 |
+
NODE_CHECK_VALID(tree->IsBtree());
|
| 445 |
+
NODE_CHECK_VALID(tree->height() <= kMaxHeight);
|
| 446 |
+
NODE_CHECK_VALID(tree->begin() < tree->capacity());
|
| 447 |
+
NODE_CHECK_VALID(tree->end() <= tree->capacity());
|
| 448 |
+
NODE_CHECK_VALID(tree->begin() <= tree->end());
|
| 449 |
+
size_t child_length = 0;
|
| 450 |
+
for (CordRep* edge : tree->Edges()) {
|
| 451 |
+
NODE_CHECK_VALID(edge != nullptr);
|
| 452 |
+
if (tree->height() > 0) {
|
| 453 |
+
NODE_CHECK_VALID(edge->IsBtree());
|
| 454 |
+
NODE_CHECK_VALID(edge->btree()->height() == tree->height() - 1);
|
| 455 |
+
} else {
|
| 456 |
+
NODE_CHECK_VALID(IsDataEdge(edge));
|
| 457 |
+
}
|
| 458 |
+
child_length += edge->length;
|
| 459 |
+
}
|
| 460 |
+
NODE_CHECK_EQ(child_length, tree->length);
|
| 461 |
+
if ((!shallow || IsCordBtreeExhaustiveValidationEnabled()) &&
|
| 462 |
+
tree->height() > 0) {
|
| 463 |
+
for (CordRep* edge : tree->Edges()) {
|
| 464 |
+
if (!IsValid(edge->btree(), shallow)) return false;
|
| 465 |
+
}
|
| 466 |
+
}
|
| 467 |
+
return true;
|
| 468 |
+
|
| 469 |
+
#undef NODE_CHECK_VALID
|
| 470 |
+
#undef NODE_CHECK_EQ
|
| 471 |
+
}
|
| 472 |
+
|
| 473 |
+
#ifndef NDEBUG
|
| 474 |
+
|
| 475 |
+
CordRepBtree* CordRepBtree::AssertValid(CordRepBtree* tree, bool shallow) {
|
| 476 |
+
if (!IsValid(tree, shallow)) {
|
| 477 |
+
Dump(tree, "CordRepBtree validation failed:", false, std::cout);
|
| 478 |
+
ABSL_RAW_LOG(FATAL, "CordRepBtree::CheckValid() FAILED");
|
| 479 |
+
}
|
| 480 |
+
return tree;
|
| 481 |
+
}
|
| 482 |
+
|
| 483 |
+
const CordRepBtree* CordRepBtree::AssertValid(const CordRepBtree* tree,
|
| 484 |
+
bool shallow) {
|
| 485 |
+
if (!IsValid(tree, shallow)) {
|
| 486 |
+
Dump(tree, "CordRepBtree validation failed:", false, std::cout);
|
| 487 |
+
ABSL_RAW_LOG(FATAL, "CordRepBtree::CheckValid() FAILED");
|
| 488 |
+
}
|
| 489 |
+
return tree;
|
| 490 |
+
}
|
| 491 |
+
|
| 492 |
+
#endif // NDEBUG
|
| 493 |
+
|
| 494 |
+
template <EdgeType edge_type>
|
| 495 |
+
inline OpResult CordRepBtree::AddEdge(bool owned, CordRep* edge, size_t delta) {
|
| 496 |
+
if (size() >= kMaxCapacity) return {New(edge), kPopped};
|
| 497 |
+
OpResult result = ToOpResult(owned);
|
| 498 |
+
result.tree->Add<edge_type>(edge);
|
| 499 |
+
result.tree->length += delta;
|
| 500 |
+
return result;
|
| 501 |
+
}
|
| 502 |
+
|
| 503 |
+
template <EdgeType edge_type>
|
| 504 |
+
OpResult CordRepBtree::SetEdge(bool owned, CordRep* edge, size_t delta) {
|
| 505 |
+
OpResult result;
|
| 506 |
+
const size_t idx = index(edge_type);
|
| 507 |
+
if (owned) {
|
| 508 |
+
result = {this, kSelf};
|
| 509 |
+
CordRep::Unref(edges_[idx]);
|
| 510 |
+
} else {
|
| 511 |
+
// Create a copy containing all unchanged edges. Unchanged edges are the
|
| 512 |
+
// open interval [begin, back) or [begin + 1, end) depending on `edge_type`.
|
| 513 |
+
// We conveniently cover both case using a constexpr `shift` being 0 or 1
|
| 514 |
+
// as `end :== back + 1`.
|
| 515 |
+
result = {CopyRaw(length), kCopied};
|
| 516 |
+
constexpr int shift = edge_type == kFront ? 1 : 0;
|
| 517 |
+
for (CordRep* r : Edges(begin() + shift, back() + shift)) {
|
| 518 |
+
CordRep::Ref(r);
|
| 519 |
+
}
|
| 520 |
+
}
|
| 521 |
+
result.tree->edges_[idx] = edge;
|
| 522 |
+
result.tree->length += delta;
|
| 523 |
+
return result;
|
| 524 |
+
}
|
| 525 |
+
|
| 526 |
+
template <EdgeType edge_type>
|
| 527 |
+
CordRepBtree* CordRepBtree::AddCordRep(CordRepBtree* tree, CordRep* rep) {
|
| 528 |
+
const int depth = tree->height();
|
| 529 |
+
const size_t length = rep->length;
|
| 530 |
+
StackOperations<edge_type> ops;
|
| 531 |
+
CordRepBtree* leaf = ops.BuildStack(tree, depth);
|
| 532 |
+
const OpResult result =
|
| 533 |
+
leaf->AddEdge<edge_type>(ops.owned(depth), rep, length);
|
| 534 |
+
return ops.Unwind(tree, depth, length, result);
|
| 535 |
+
}
|
| 536 |
+
|
| 537 |
+
template <>
|
| 538 |
+
CordRepBtree* CordRepBtree::NewLeaf<kBack>(absl::string_view data,
|
| 539 |
+
size_t extra) {
|
| 540 |
+
CordRepBtree* leaf = CordRepBtree::New(0);
|
| 541 |
+
size_t length = 0;
|
| 542 |
+
size_t end = 0;
|
| 543 |
+
const size_t cap = leaf->capacity();
|
| 544 |
+
while (!data.empty() && end != cap) {
|
| 545 |
+
auto* flat = CordRepFlat::New(data.length() + extra);
|
| 546 |
+
flat->length = (std::min)(data.length(), flat->Capacity());
|
| 547 |
+
length += flat->length;
|
| 548 |
+
leaf->edges_[end++] = flat;
|
| 549 |
+
data = Consume<kBack>(flat->Data(), data, flat->length);
|
| 550 |
+
}
|
| 551 |
+
leaf->length = length;
|
| 552 |
+
leaf->set_end(end);
|
| 553 |
+
return leaf;
|
| 554 |
+
}
|
| 555 |
+
|
| 556 |
+
template <>
|
| 557 |
+
CordRepBtree* CordRepBtree::NewLeaf<kFront>(absl::string_view data,
|
| 558 |
+
size_t extra) {
|
| 559 |
+
CordRepBtree* leaf = CordRepBtree::New(0);
|
| 560 |
+
size_t length = 0;
|
| 561 |
+
size_t begin = leaf->capacity();
|
| 562 |
+
leaf->set_end(leaf->capacity());
|
| 563 |
+
while (!data.empty() && begin != 0) {
|
| 564 |
+
auto* flat = CordRepFlat::New(data.length() + extra);
|
| 565 |
+
flat->length = (std::min)(data.length(), flat->Capacity());
|
| 566 |
+
length += flat->length;
|
| 567 |
+
leaf->edges_[--begin] = flat;
|
| 568 |
+
data = Consume<kFront>(flat->Data(), data, flat->length);
|
| 569 |
+
}
|
| 570 |
+
leaf->length = length;
|
| 571 |
+
leaf->set_begin(begin);
|
| 572 |
+
return leaf;
|
| 573 |
+
}
|
| 574 |
+
|
| 575 |
+
template <>
|
| 576 |
+
absl::string_view CordRepBtree::AddData<kBack>(absl::string_view data,
|
| 577 |
+
size_t extra) {
|
| 578 |
+
assert(!data.empty());
|
| 579 |
+
assert(size() < capacity());
|
| 580 |
+
AlignBegin();
|
| 581 |
+
const size_t cap = capacity();
|
| 582 |
+
do {
|
| 583 |
+
CordRepFlat* flat = CordRepFlat::New(data.length() + extra);
|
| 584 |
+
const size_t n = (std::min)(data.length(), flat->Capacity());
|
| 585 |
+
flat->length = n;
|
| 586 |
+
edges_[fetch_add_end(1)] = flat;
|
| 587 |
+
data = Consume<kBack>(flat->Data(), data, n);
|
| 588 |
+
} while (!data.empty() && end() != cap);
|
| 589 |
+
return data;
|
| 590 |
+
}
|
| 591 |
+
|
| 592 |
+
template <>
|
| 593 |
+
absl::string_view CordRepBtree::AddData<kFront>(absl::string_view data,
|
| 594 |
+
size_t extra) {
|
| 595 |
+
assert(!data.empty());
|
| 596 |
+
assert(size() < capacity());
|
| 597 |
+
AlignEnd();
|
| 598 |
+
do {
|
| 599 |
+
CordRepFlat* flat = CordRepFlat::New(data.length() + extra);
|
| 600 |
+
const size_t n = (std::min)(data.length(), flat->Capacity());
|
| 601 |
+
flat->length = n;
|
| 602 |
+
edges_[sub_fetch_begin(1)] = flat;
|
| 603 |
+
data = Consume<kFront>(flat->Data(), data, n);
|
| 604 |
+
} while (!data.empty() && begin() != 0);
|
| 605 |
+
return data;
|
| 606 |
+
}
|
| 607 |
+
|
| 608 |
+
template <EdgeType edge_type>
|
| 609 |
+
CordRepBtree* CordRepBtree::AddData(CordRepBtree* tree, absl::string_view data,
|
| 610 |
+
size_t extra) {
|
| 611 |
+
if (ABSL_PREDICT_FALSE(data.empty())) return tree;
|
| 612 |
+
|
| 613 |
+
const size_t original_data_size = data.size();
|
| 614 |
+
int depth = tree->height();
|
| 615 |
+
StackOperations<edge_type> ops;
|
| 616 |
+
CordRepBtree* leaf = ops.BuildStack(tree, depth);
|
| 617 |
+
|
| 618 |
+
// If there is capacity in the last edge, append as much data
|
| 619 |
+
// as possible into this last edge.
|
| 620 |
+
if (leaf->size() < leaf->capacity()) {
|
| 621 |
+
OpResult result = leaf->ToOpResult(ops.owned(depth));
|
| 622 |
+
data = result.tree->AddData<edge_type>(data, extra);
|
| 623 |
+
if (data.empty()) {
|
| 624 |
+
result.tree->length += original_data_size;
|
| 625 |
+
return ops.Unwind(tree, depth, original_data_size, result);
|
| 626 |
+
}
|
| 627 |
+
|
| 628 |
+
// We added some data into this leaf, but not all. Propagate the added
|
| 629 |
+
// length to the top most node, and rebuild the stack with any newly copied
|
| 630 |
+
// or updated nodes. From this point on, the path (leg) from the top most
|
| 631 |
+
// node to the right-most node towards the leaf node is privately owned.
|
| 632 |
+
size_t delta = original_data_size - data.size();
|
| 633 |
+
assert(delta > 0);
|
| 634 |
+
result.tree->length += delta;
|
| 635 |
+
tree = ops.Propagate(tree, depth, delta, result);
|
| 636 |
+
ops.share_depth = depth + 1;
|
| 637 |
+
}
|
| 638 |
+
|
| 639 |
+
// We were unable to append all data into the existing right-most leaf node.
|
| 640 |
+
// This means all remaining data must be put into (a) new leaf node(s) which
|
| 641 |
+
// we append to the tree. To make this efficient, we iteratively build full
|
| 642 |
+
// leaf nodes from `data` until the created leaf contains all remaining data.
|
| 643 |
+
// We utilize the `Unwind` method to merge the created leaf into the first
|
| 644 |
+
// level towards root that has capacity. On each iteration with remaining
|
| 645 |
+
// data, we rebuild the stack in the knowledge that right-most nodes are
|
| 646 |
+
// privately owned after the first `Unwind` completes.
|
| 647 |
+
for (;;) {
|
| 648 |
+
OpResult result = {CordRepBtree::NewLeaf<edge_type>(data, extra), kPopped};
|
| 649 |
+
if (result.tree->length == data.size()) {
|
| 650 |
+
return ops.Unwind(tree, depth, result.tree->length, result);
|
| 651 |
+
}
|
| 652 |
+
data = Consume<edge_type>(data, result.tree->length);
|
| 653 |
+
tree = ops.Unwind(tree, depth, result.tree->length, result);
|
| 654 |
+
depth = tree->height();
|
| 655 |
+
ops.BuildOwnedStack(tree, depth);
|
| 656 |
+
}
|
| 657 |
+
}
|
| 658 |
+
|
| 659 |
+
template <EdgeType edge_type>
|
| 660 |
+
CordRepBtree* CordRepBtree::Merge(CordRepBtree* dst, CordRepBtree* src) {
|
| 661 |
+
assert(dst->height() >= src->height());
|
| 662 |
+
|
| 663 |
+
// Capture source length as we may consume / destroy `src`.
|
| 664 |
+
const size_t length = src->length;
|
| 665 |
+
|
| 666 |
+
// We attempt to merge `src` at its corresponding height in `dst`.
|
| 667 |
+
const int depth = dst->height() - src->height();
|
| 668 |
+
StackOperations<edge_type> ops;
|
| 669 |
+
CordRepBtree* merge_node = ops.BuildStack(dst, depth);
|
| 670 |
+
|
| 671 |
+
// If there is enough space in `merge_node` for all edges from `src`, add all
|
| 672 |
+
// edges to this node, making a fresh copy as needed if not privately owned.
|
| 673 |
+
// If `merge_node` does not have capacity for `src`, we rely on `Unwind` and
|
| 674 |
+
// `Finalize` to merge `src` into the first level towards `root` where there
|
| 675 |
+
// is capacity for another edge, or create a new top level node.
|
| 676 |
+
OpResult result;
|
| 677 |
+
if (merge_node->size() + src->size() <= kMaxCapacity) {
|
| 678 |
+
result = merge_node->ToOpResult(ops.owned(depth));
|
| 679 |
+
result.tree->Add<edge_type>(src->Edges());
|
| 680 |
+
result.tree->length += src->length;
|
| 681 |
+
if (src->refcount.IsOne()) {
|
| 682 |
+
Delete(src);
|
| 683 |
+
} else {
|
| 684 |
+
for (CordRep* edge : src->Edges()) CordRep::Ref(edge);
|
| 685 |
+
CordRepBtree::Unref(src);
|
| 686 |
+
}
|
| 687 |
+
} else {
|
| 688 |
+
result = {src, kPopped};
|
| 689 |
+
}
|
| 690 |
+
|
| 691 |
+
// Unless we merged at the top level (i.e.: src and dst are equal height),
|
| 692 |
+
// unwind the result towards the top level, and finalize the result.
|
| 693 |
+
if (depth) {
|
| 694 |
+
return ops.Unwind(dst, depth, length, result);
|
| 695 |
+
}
|
| 696 |
+
return ops.Finalize(dst, result);
|
| 697 |
+
}
|
| 698 |
+
|
| 699 |
+
CopyResult CordRepBtree::CopySuffix(size_t offset) {
|
| 700 |
+
assert(offset < this->length);
|
| 701 |
+
|
| 702 |
+
// As long as `offset` starts inside the last edge, we can 'drop' the current
|
| 703 |
+
// depth. For the most extreme example: if offset references the last data
|
| 704 |
+
// edge in the tree, there is only a single edge / path from the top of the
|
| 705 |
+
// tree to that last edge, so we can drop all the nodes except that edge.
|
| 706 |
+
// The fast path check for this is `back->length >= length - offset`.
|
| 707 |
+
int height = this->height();
|
| 708 |
+
CordRepBtree* node = this;
|
| 709 |
+
size_t len = node->length - offset;
|
| 710 |
+
CordRep* back = node->Edge(kBack);
|
| 711 |
+
while (back->length >= len) {
|
| 712 |
+
offset = back->length - len;
|
| 713 |
+
if (--height < 0) {
|
| 714 |
+
return {MakeSubstring(CordRep::Ref(back), offset), height};
|
| 715 |
+
}
|
| 716 |
+
node = back->btree();
|
| 717 |
+
back = node->Edge(kBack);
|
| 718 |
+
}
|
| 719 |
+
if (offset == 0) return {CordRep::Ref(node), height};
|
| 720 |
+
|
| 721 |
+
// Offset does not point into the last edge, so we span at least two edges.
|
| 722 |
+
// Find the index of offset with `IndexBeyond` which provides us the edge
|
| 723 |
+
// 'beyond' the offset if offset is not a clean starting point of an edge.
|
| 724 |
+
Position pos = node->IndexBeyond(offset);
|
| 725 |
+
CordRepBtree* sub = node->CopyToEndFrom(pos.index, len);
|
| 726 |
+
const CopyResult result = {sub, height};
|
| 727 |
+
|
| 728 |
+
// `pos.n` contains a non zero value if the offset is not an exact starting
|
| 729 |
+
// point of an edge. In this case, `pos.n` contains the 'trailing' amount of
|
| 730 |
+
// bytes of the edge preceding that in `pos.index`. We need to iteratively
|
| 731 |
+
// adjust the preceding edge with the 'broken' offset until we have a perfect
|
| 732 |
+
// start of the edge.
|
| 733 |
+
while (pos.n != 0) {
|
| 734 |
+
assert(pos.index >= 1);
|
| 735 |
+
const size_t begin = pos.index - 1;
|
| 736 |
+
sub->set_begin(begin);
|
| 737 |
+
CordRep* const edge = node->Edge(begin);
|
| 738 |
+
|
| 739 |
+
len = pos.n;
|
| 740 |
+
offset = edge->length - len;
|
| 741 |
+
|
| 742 |
+
if (--height < 0) {
|
| 743 |
+
sub->edges_[begin] = MakeSubstring(CordRep::Ref(edge), offset, len);
|
| 744 |
+
return result;
|
| 745 |
+
}
|
| 746 |
+
|
| 747 |
+
node = edge->btree();
|
| 748 |
+
pos = node->IndexBeyond(offset);
|
| 749 |
+
|
| 750 |
+
CordRepBtree* nsub = node->CopyToEndFrom(pos.index, len);
|
| 751 |
+
sub->edges_[begin] = nsub;
|
| 752 |
+
sub = nsub;
|
| 753 |
+
}
|
| 754 |
+
sub->set_begin(pos.index);
|
| 755 |
+
return result;
|
| 756 |
+
}
|
| 757 |
+
|
| 758 |
+
CopyResult CordRepBtree::CopyPrefix(size_t n, bool allow_folding) {
|
| 759 |
+
assert(n > 0);
|
| 760 |
+
assert(n <= this->length);
|
| 761 |
+
|
| 762 |
+
// As long as `n` does not exceed the length of the first edge, we can 'drop'
|
| 763 |
+
// the current depth. For the most extreme example: if we'd copy a 1 byte
|
| 764 |
+
// prefix from a tree, there is only a single edge / path from the top of the
|
| 765 |
+
// tree to the single data edge containing this byte, so we can drop all the
|
| 766 |
+
// nodes except the data node.
|
| 767 |
+
int height = this->height();
|
| 768 |
+
CordRepBtree* node = this;
|
| 769 |
+
CordRep* front = node->Edge(kFront);
|
| 770 |
+
if (allow_folding) {
|
| 771 |
+
while (front->length >= n) {
|
| 772 |
+
if (--height < 0) return {MakeSubstring(CordRep::Ref(front), 0, n), -1};
|
| 773 |
+
node = front->btree();
|
| 774 |
+
front = node->Edge(kFront);
|
| 775 |
+
}
|
| 776 |
+
}
|
| 777 |
+
if (node->length == n) return {CordRep::Ref(node), height};
|
| 778 |
+
|
| 779 |
+
// `n` spans at least two nodes, find the end point of the span.
|
| 780 |
+
Position pos = node->IndexOf(n);
|
| 781 |
+
|
| 782 |
+
// Create a partial copy of the node up to `pos.index`, with a defined length
|
| 783 |
+
// of `n`. Any 'partial last edge' is added further below as needed.
|
| 784 |
+
CordRepBtree* sub = node->CopyBeginTo(pos.index, n);
|
| 785 |
+
const CopyResult result = {sub, height};
|
| 786 |
+
|
| 787 |
+
// `pos.n` contains the 'offset inside the edge for IndexOf(n)'. As long as
|
| 788 |
+
// this is not zero, we don't have a 'clean cut', so we need to make a
|
| 789 |
+
// (partial) copy of that last edge, and repeat this until pos.n is zero.
|
| 790 |
+
while (pos.n != 0) {
|
| 791 |
+
size_t end = pos.index;
|
| 792 |
+
n = pos.n;
|
| 793 |
+
|
| 794 |
+
CordRep* edge = node->Edge(pos.index);
|
| 795 |
+
if (--height < 0) {
|
| 796 |
+
sub->edges_[end++] = MakeSubstring(CordRep::Ref(edge), 0, n);
|
| 797 |
+
sub->set_end(end);
|
| 798 |
+
AssertValid(result.edge->btree());
|
| 799 |
+
return result;
|
| 800 |
+
}
|
| 801 |
+
|
| 802 |
+
node = edge->btree();
|
| 803 |
+
pos = node->IndexOf(n);
|
| 804 |
+
CordRepBtree* nsub = node->CopyBeginTo(pos.index, n);
|
| 805 |
+
sub->edges_[end++] = nsub;
|
| 806 |
+
sub->set_end(end);
|
| 807 |
+
sub = nsub;
|
| 808 |
+
}
|
| 809 |
+
sub->set_end(pos.index);
|
| 810 |
+
AssertValid(result.edge->btree());
|
| 811 |
+
return result;
|
| 812 |
+
}
|
| 813 |
+
|
| 814 |
+
CordRep* CordRepBtree::ExtractFront(CordRepBtree* tree) {
|
| 815 |
+
CordRep* front = tree->Edge(tree->begin());
|
| 816 |
+
if (tree->refcount.IsOne()) {
|
| 817 |
+
Unref(tree->Edges(tree->begin() + 1, tree->end()));
|
| 818 |
+
CordRepBtree::Delete(tree);
|
| 819 |
+
} else {
|
| 820 |
+
CordRep::Ref(front);
|
| 821 |
+
CordRep::Unref(tree);
|
| 822 |
+
}
|
| 823 |
+
return front;
|
| 824 |
+
}
|
| 825 |
+
|
| 826 |
+
CordRepBtree* CordRepBtree::ConsumeBeginTo(CordRepBtree* tree, size_t end,
|
| 827 |
+
size_t new_length) {
|
| 828 |
+
assert(end <= tree->end());
|
| 829 |
+
if (tree->refcount.IsOne()) {
|
| 830 |
+
Unref(tree->Edges(end, tree->end()));
|
| 831 |
+
tree->set_end(end);
|
| 832 |
+
tree->length = new_length;
|
| 833 |
+
} else {
|
| 834 |
+
CordRepBtree* old = tree;
|
| 835 |
+
tree = tree->CopyBeginTo(end, new_length);
|
| 836 |
+
CordRep::Unref(old);
|
| 837 |
+
}
|
| 838 |
+
return tree;
|
| 839 |
+
}
|
| 840 |
+
|
| 841 |
+
CordRep* CordRepBtree::RemoveSuffix(CordRepBtree* tree, size_t n) {
|
| 842 |
+
// Check input and deal with trivial cases 'Remove all/none'
|
| 843 |
+
assert(tree != nullptr);
|
| 844 |
+
assert(n <= tree->length);
|
| 845 |
+
const size_t len = tree->length;
|
| 846 |
+
if (ABSL_PREDICT_FALSE(n == 0)) {
|
| 847 |
+
return tree;
|
| 848 |
+
}
|
| 849 |
+
if (ABSL_PREDICT_FALSE(n >= len)) {
|
| 850 |
+
CordRepBtree::Unref(tree);
|
| 851 |
+
return nullptr;
|
| 852 |
+
}
|
| 853 |
+
|
| 854 |
+
size_t length = len - n;
|
| 855 |
+
int height = tree->height();
|
| 856 |
+
bool is_mutable = tree->refcount.IsOne();
|
| 857 |
+
|
| 858 |
+
// Extract all top nodes which are reduced to size = 1
|
| 859 |
+
Position pos = tree->IndexOfLength(length);
|
| 860 |
+
while (pos.index == tree->begin()) {
|
| 861 |
+
CordRep* edge = ExtractFront(tree);
|
| 862 |
+
is_mutable &= edge->refcount.IsOne();
|
| 863 |
+
if (height-- == 0) return ResizeEdge(edge, length, is_mutable);
|
| 864 |
+
tree = edge->btree();
|
| 865 |
+
pos = tree->IndexOfLength(length);
|
| 866 |
+
}
|
| 867 |
+
|
| 868 |
+
// Repeat the following sequence traversing down the tree:
|
| 869 |
+
// - Crop the top node to the 'last remaining edge' adjusting length.
|
| 870 |
+
// - Set the length for down edges to the partial length in that last edge.
|
| 871 |
+
// - Repeat this until the last edge is 'included in full'
|
| 872 |
+
// - If we hit the data edge level, resize and return the last data edge
|
| 873 |
+
CordRepBtree* top = tree = ConsumeBeginTo(tree, pos.index + 1, length);
|
| 874 |
+
CordRep* edge = tree->Edge(pos.index);
|
| 875 |
+
length = pos.n;
|
| 876 |
+
while (length != edge->length) {
|
| 877 |
+
// ConsumeBeginTo guarantees `tree` is a clean, privately owned copy.
|
| 878 |
+
assert(tree->refcount.IsOne());
|
| 879 |
+
const bool edge_is_mutable = edge->refcount.IsOne();
|
| 880 |
+
|
| 881 |
+
if (height-- == 0) {
|
| 882 |
+
tree->edges_[pos.index] = ResizeEdge(edge, length, edge_is_mutable);
|
| 883 |
+
return AssertValid(top);
|
| 884 |
+
}
|
| 885 |
+
|
| 886 |
+
if (!edge_is_mutable) {
|
| 887 |
+
// We can't 'in place' remove any suffixes down this edge.
|
| 888 |
+
// Replace this edge with a prefix copy instead.
|
| 889 |
+
tree->edges_[pos.index] = edge->btree()->CopyPrefix(length, false).edge;
|
| 890 |
+
CordRep::Unref(edge);
|
| 891 |
+
return AssertValid(top);
|
| 892 |
+
}
|
| 893 |
+
|
| 894 |
+
// Move down one level, rinse repeat.
|
| 895 |
+
tree = edge->btree();
|
| 896 |
+
pos = tree->IndexOfLength(length);
|
| 897 |
+
tree = ConsumeBeginTo(edge->btree(), pos.index + 1, length);
|
| 898 |
+
edge = tree->Edge(pos.index);
|
| 899 |
+
length = pos.n;
|
| 900 |
+
}
|
| 901 |
+
|
| 902 |
+
return AssertValid(top);
|
| 903 |
+
}
|
| 904 |
+
|
| 905 |
+
CordRep* CordRepBtree::SubTree(size_t offset, size_t n) {
|
| 906 |
+
assert(n <= this->length);
|
| 907 |
+
assert(offset <= this->length - n);
|
| 908 |
+
if (ABSL_PREDICT_FALSE(n == 0)) return nullptr;
|
| 909 |
+
|
| 910 |
+
CordRepBtree* node = this;
|
| 911 |
+
int height = node->height();
|
| 912 |
+
Position front = node->IndexOf(offset);
|
| 913 |
+
CordRep* left = node->edges_[front.index];
|
| 914 |
+
while (front.n + n <= left->length) {
|
| 915 |
+
if (--height < 0) return MakeSubstring(CordRep::Ref(left), front.n, n);
|
| 916 |
+
node = left->btree();
|
| 917 |
+
front = node->IndexOf(front.n);
|
| 918 |
+
left = node->edges_[front.index];
|
| 919 |
+
}
|
| 920 |
+
|
| 921 |
+
const Position back = node->IndexBefore(front, n);
|
| 922 |
+
CordRep* const right = node->edges_[back.index];
|
| 923 |
+
assert(back.index > front.index);
|
| 924 |
+
|
| 925 |
+
// Get partial suffix and prefix entries.
|
| 926 |
+
CopyResult prefix;
|
| 927 |
+
CopyResult suffix;
|
| 928 |
+
if (height > 0) {
|
| 929 |
+
// Copy prefix and suffix of the boundary nodes.
|
| 930 |
+
prefix = left->btree()->CopySuffix(front.n);
|
| 931 |
+
suffix = right->btree()->CopyPrefix(back.n);
|
| 932 |
+
|
| 933 |
+
// If there is an edge between the prefix and suffix edges, then the tree
|
| 934 |
+
// must remain at its previous (full) height. If we have no edges between
|
| 935 |
+
// prefix and suffix edges, then the tree must be as high as either the
|
| 936 |
+
// suffix or prefix edges (which are collapsed to their minimum heights).
|
| 937 |
+
if (front.index + 1 == back.index) {
|
| 938 |
+
height = (std::max)(prefix.height, suffix.height) + 1;
|
| 939 |
+
}
|
| 940 |
+
|
| 941 |
+
// Raise prefix and suffixes to the new tree height.
|
| 942 |
+
for (int h = prefix.height + 1; h < height; ++h) {
|
| 943 |
+
prefix.edge = CordRepBtree::New(prefix.edge);
|
| 944 |
+
}
|
| 945 |
+
for (int h = suffix.height + 1; h < height; ++h) {
|
| 946 |
+
suffix.edge = CordRepBtree::New(suffix.edge);
|
| 947 |
+
}
|
| 948 |
+
} else {
|
| 949 |
+
// Leaf node, simply take substrings for prefix and suffix.
|
| 950 |
+
prefix = CopyResult{MakeSubstring(CordRep::Ref(left), front.n), -1};
|
| 951 |
+
suffix = CopyResult{MakeSubstring(CordRep::Ref(right), 0, back.n), -1};
|
| 952 |
+
}
|
| 953 |
+
|
| 954 |
+
// Compose resulting tree.
|
| 955 |
+
CordRepBtree* sub = CordRepBtree::New(height);
|
| 956 |
+
size_t end = 0;
|
| 957 |
+
sub->edges_[end++] = prefix.edge;
|
| 958 |
+
for (CordRep* r : node->Edges(front.index + 1, back.index)) {
|
| 959 |
+
sub->edges_[end++] = CordRep::Ref(r);
|
| 960 |
+
}
|
| 961 |
+
sub->edges_[end++] = suffix.edge;
|
| 962 |
+
sub->set_end(end);
|
| 963 |
+
sub->length = n;
|
| 964 |
+
return AssertValid(sub);
|
| 965 |
+
}
|
| 966 |
+
|
| 967 |
+
CordRepBtree* CordRepBtree::MergeTrees(CordRepBtree* left,
|
| 968 |
+
CordRepBtree* right) {
|
| 969 |
+
return left->height() >= right->height() ? Merge<kBack>(left, right)
|
| 970 |
+
: Merge<kFront>(right, left);
|
| 971 |
+
}
|
| 972 |
+
|
| 973 |
+
bool CordRepBtree::IsFlat(absl::string_view* fragment) const {
|
| 974 |
+
if (height() == 0 && size() == 1) {
|
| 975 |
+
if (fragment) *fragment = Data(begin());
|
| 976 |
+
return true;
|
| 977 |
+
}
|
| 978 |
+
return false;
|
| 979 |
+
}
|
| 980 |
+
|
| 981 |
+
bool CordRepBtree::IsFlat(size_t offset, const size_t n,
|
| 982 |
+
absl::string_view* fragment) const {
|
| 983 |
+
assert(n <= this->length);
|
| 984 |
+
assert(offset <= this->length - n);
|
| 985 |
+
if (ABSL_PREDICT_FALSE(n == 0)) return false;
|
| 986 |
+
int height = this->height();
|
| 987 |
+
const CordRepBtree* node = this;
|
| 988 |
+
for (;;) {
|
| 989 |
+
const Position front = node->IndexOf(offset);
|
| 990 |
+
const CordRep* edge = node->Edge(front.index);
|
| 991 |
+
if (edge->length < front.n + n) return false;
|
| 992 |
+
if (--height < 0) {
|
| 993 |
+
if (fragment) *fragment = EdgeData(edge).substr(front.n, n);
|
| 994 |
+
return true;
|
| 995 |
+
}
|
| 996 |
+
offset = front.n;
|
| 997 |
+
node = node->Edge(front.index)->btree();
|
| 998 |
+
}
|
| 999 |
+
}
|
| 1000 |
+
|
| 1001 |
+
char CordRepBtree::GetCharacter(size_t offset) const {
|
| 1002 |
+
assert(offset < length);
|
| 1003 |
+
const CordRepBtree* node = this;
|
| 1004 |
+
int height = node->height();
|
| 1005 |
+
for (;;) {
|
| 1006 |
+
Position front = node->IndexOf(offset);
|
| 1007 |
+
if (--height < 0) return node->Data(front.index)[front.n];
|
| 1008 |
+
offset = front.n;
|
| 1009 |
+
node = node->Edge(front.index)->btree();
|
| 1010 |
+
}
|
| 1011 |
+
}
|
| 1012 |
+
|
| 1013 |
+
Span<char> CordRepBtree::GetAppendBufferSlow(size_t size) {
|
| 1014 |
+
// The inlined version in `GetAppendBuffer()` deals with all heights <= 3.
|
| 1015 |
+
assert(height() >= 4);
|
| 1016 |
+
assert(refcount.IsOne());
|
| 1017 |
+
|
| 1018 |
+
// Build a stack of nodes we may potentially need to update if we find a
|
| 1019 |
+
// non-shared FLAT with capacity at the leaf level.
|
| 1020 |
+
const int depth = height();
|
| 1021 |
+
CordRepBtree* node = this;
|
| 1022 |
+
CordRepBtree* stack[kMaxDepth];
|
| 1023 |
+
for (int i = 0; i < depth; ++i) {
|
| 1024 |
+
node = node->Edge(kBack)->btree();
|
| 1025 |
+
if (!node->refcount.IsOne()) return {};
|
| 1026 |
+
stack[i] = node;
|
| 1027 |
+
}
|
| 1028 |
+
|
| 1029 |
+
// Must be a privately owned, mutable flat.
|
| 1030 |
+
CordRep* const edge = node->Edge(kBack);
|
| 1031 |
+
if (!edge->refcount.IsOne() || edge->tag < FLAT) return {};
|
| 1032 |
+
|
| 1033 |
+
// Must have capacity.
|
| 1034 |
+
const size_t avail = edge->flat()->Capacity() - edge->length;
|
| 1035 |
+
if (avail == 0) return {};
|
| 1036 |
+
|
| 1037 |
+
// Build span on remaining capacity.
|
| 1038 |
+
size_t delta = (std::min)(size, avail);
|
| 1039 |
+
Span<char> span = {edge->flat()->Data() + edge->length, delta};
|
| 1040 |
+
edge->length += delta;
|
| 1041 |
+
this->length += delta;
|
| 1042 |
+
for (int i = 0; i < depth; ++i) {
|
| 1043 |
+
stack[i]->length += delta;
|
| 1044 |
+
}
|
| 1045 |
+
return span;
|
| 1046 |
+
}
|
| 1047 |
+
|
| 1048 |
+
CordRepBtree* CordRepBtree::CreateSlow(CordRep* rep) {
|
| 1049 |
+
if (rep->IsBtree()) return rep->btree();
|
| 1050 |
+
|
| 1051 |
+
CordRepBtree* node = nullptr;
|
| 1052 |
+
auto consume = [&node](CordRep* r, size_t offset, size_t length) {
|
| 1053 |
+
r = MakeSubstring(r, offset, length);
|
| 1054 |
+
if (node == nullptr) {
|
| 1055 |
+
node = New(r);
|
| 1056 |
+
} else {
|
| 1057 |
+
node = CordRepBtree::AddCordRep<kBack>(node, r);
|
| 1058 |
+
}
|
| 1059 |
+
};
|
| 1060 |
+
Consume(rep, consume);
|
| 1061 |
+
return node;
|
| 1062 |
+
}
|
| 1063 |
+
|
| 1064 |
+
CordRepBtree* CordRepBtree::AppendSlow(CordRepBtree* tree, CordRep* rep) {
|
| 1065 |
+
if (ABSL_PREDICT_TRUE(rep->IsBtree())) {
|
| 1066 |
+
return MergeTrees(tree, rep->btree());
|
| 1067 |
+
}
|
| 1068 |
+
auto consume = [&tree](CordRep* r, size_t offset, size_t length) {
|
| 1069 |
+
r = MakeSubstring(r, offset, length);
|
| 1070 |
+
tree = CordRepBtree::AddCordRep<kBack>(tree, r);
|
| 1071 |
+
};
|
| 1072 |
+
Consume(rep, consume);
|
| 1073 |
+
return tree;
|
| 1074 |
+
}
|
| 1075 |
+
|
| 1076 |
+
CordRepBtree* CordRepBtree::PrependSlow(CordRepBtree* tree, CordRep* rep) {
|
| 1077 |
+
if (ABSL_PREDICT_TRUE(rep->IsBtree())) {
|
| 1078 |
+
return MergeTrees(rep->btree(), tree);
|
| 1079 |
+
}
|
| 1080 |
+
auto consume = [&tree](CordRep* r, size_t offset, size_t length) {
|
| 1081 |
+
r = MakeSubstring(r, offset, length);
|
| 1082 |
+
tree = CordRepBtree::AddCordRep<kFront>(tree, r);
|
| 1083 |
+
};
|
| 1084 |
+
ReverseConsume(rep, consume);
|
| 1085 |
+
return tree;
|
| 1086 |
+
}
|
| 1087 |
+
|
| 1088 |
+
CordRepBtree* CordRepBtree::Append(CordRepBtree* tree, absl::string_view data,
|
| 1089 |
+
size_t extra) {
|
| 1090 |
+
return CordRepBtree::AddData<kBack>(tree, data, extra);
|
| 1091 |
+
}
|
| 1092 |
+
|
| 1093 |
+
CordRepBtree* CordRepBtree::Prepend(CordRepBtree* tree, absl::string_view data,
|
| 1094 |
+
size_t extra) {
|
| 1095 |
+
return CordRepBtree::AddData<kFront>(tree, data, extra);
|
| 1096 |
+
}
|
| 1097 |
+
|
| 1098 |
+
template CordRepBtree* CordRepBtree::AddCordRep<kFront>(CordRepBtree* tree,
|
| 1099 |
+
CordRep* rep);
|
| 1100 |
+
template CordRepBtree* CordRepBtree::AddCordRep<kBack>(CordRepBtree* tree,
|
| 1101 |
+
CordRep* rep);
|
| 1102 |
+
template CordRepBtree* CordRepBtree::AddData<kFront>(CordRepBtree* tree,
|
| 1103 |
+
absl::string_view data,
|
| 1104 |
+
size_t extra);
|
| 1105 |
+
template CordRepBtree* CordRepBtree::AddData<kBack>(CordRepBtree* tree,
|
| 1106 |
+
absl::string_view data,
|
| 1107 |
+
size_t extra);
|
| 1108 |
+
|
| 1109 |
+
void CordRepBtree::Rebuild(CordRepBtree** stack, CordRepBtree* tree,
|
| 1110 |
+
bool consume) {
|
| 1111 |
+
bool owned = consume && tree->refcount.IsOne();
|
| 1112 |
+
if (tree->height() == 0) {
|
| 1113 |
+
for (CordRep* edge : tree->Edges()) {
|
| 1114 |
+
if (!owned) edge = CordRep::Ref(edge);
|
| 1115 |
+
size_t height = 0;
|
| 1116 |
+
size_t length = edge->length;
|
| 1117 |
+
CordRepBtree* node = stack[0];
|
| 1118 |
+
OpResult result = node->AddEdge<kBack>(true, edge, length);
|
| 1119 |
+
while (result.action == CordRepBtree::kPopped) {
|
| 1120 |
+
stack[height] = result.tree;
|
| 1121 |
+
if (stack[++height] == nullptr) {
|
| 1122 |
+
result.action = CordRepBtree::kSelf;
|
| 1123 |
+
stack[height] = CordRepBtree::New(node, result.tree);
|
| 1124 |
+
} else {
|
| 1125 |
+
node = stack[height];
|
| 1126 |
+
result = node->AddEdge<kBack>(true, result.tree, length);
|
| 1127 |
+
}
|
| 1128 |
+
}
|
| 1129 |
+
while (stack[++height] != nullptr) {
|
| 1130 |
+
stack[height]->length += length;
|
| 1131 |
+
}
|
| 1132 |
+
}
|
| 1133 |
+
} else {
|
| 1134 |
+
for (CordRep* rep : tree->Edges()) {
|
| 1135 |
+
Rebuild(stack, rep->btree(), owned);
|
| 1136 |
+
}
|
| 1137 |
+
}
|
| 1138 |
+
if (consume) {
|
| 1139 |
+
if (owned) {
|
| 1140 |
+
CordRepBtree::Delete(tree);
|
| 1141 |
+
} else {
|
| 1142 |
+
CordRepBtree::Unref(tree);
|
| 1143 |
+
}
|
| 1144 |
+
}
|
| 1145 |
+
}
|
| 1146 |
+
|
| 1147 |
+
CordRepBtree* CordRepBtree::Rebuild(CordRepBtree* tree) {
|
| 1148 |
+
// Set up initial stack with empty leaf node.
|
| 1149 |
+
CordRepBtree* node = CordRepBtree::New();
|
| 1150 |
+
CordRepBtree* stack[CordRepBtree::kMaxDepth + 1] = {node};
|
| 1151 |
+
|
| 1152 |
+
// Recursively build the tree, consuming the input tree.
|
| 1153 |
+
Rebuild(stack, tree, /* consume reference */ true);
|
| 1154 |
+
|
| 1155 |
+
// Return top most node
|
| 1156 |
+
for (CordRepBtree* parent : stack) {
|
| 1157 |
+
if (parent == nullptr) return node;
|
| 1158 |
+
node = parent;
|
| 1159 |
+
}
|
| 1160 |
+
|
| 1161 |
+
// Unreachable
|
| 1162 |
+
assert(false);
|
| 1163 |
+
return nullptr;
|
| 1164 |
+
}
|
| 1165 |
+
|
| 1166 |
+
CordRepBtree::ExtractResult CordRepBtree::ExtractAppendBuffer(
|
| 1167 |
+
CordRepBtree* tree, size_t extra_capacity) {
|
| 1168 |
+
int depth = 0;
|
| 1169 |
+
NodeStack stack;
|
| 1170 |
+
|
| 1171 |
+
// Set up default 'no success' result which is {tree, nullptr}.
|
| 1172 |
+
ExtractResult result;
|
| 1173 |
+
result.tree = tree;
|
| 1174 |
+
result.extracted = nullptr;
|
| 1175 |
+
|
| 1176 |
+
// Dive down the right side of the tree, making sure no edges are shared.
|
| 1177 |
+
while (tree->height() > 0) {
|
| 1178 |
+
if (!tree->refcount.IsOne()) return result;
|
| 1179 |
+
stack[depth++] = tree;
|
| 1180 |
+
tree = tree->Edge(kBack)->btree();
|
| 1181 |
+
}
|
| 1182 |
+
if (!tree->refcount.IsOne()) return result;
|
| 1183 |
+
|
| 1184 |
+
// Validate we ended on a non shared flat.
|
| 1185 |
+
CordRep* rep = tree->Edge(kBack);
|
| 1186 |
+
if (!(rep->IsFlat() && rep->refcount.IsOne())) return result;
|
| 1187 |
+
|
| 1188 |
+
// Verify it has at least the requested extra capacity.
|
| 1189 |
+
CordRepFlat* flat = rep->flat();
|
| 1190 |
+
const size_t length = flat->length;
|
| 1191 |
+
const size_t avail = flat->Capacity() - flat->length;
|
| 1192 |
+
if (extra_capacity > avail) return result;
|
| 1193 |
+
|
| 1194 |
+
// Set the extracted flat in the result.
|
| 1195 |
+
result.extracted = flat;
|
| 1196 |
+
|
| 1197 |
+
// Cascading delete all nodes that become empty.
|
| 1198 |
+
while (tree->size() == 1) {
|
| 1199 |
+
CordRepBtree::Delete(tree);
|
| 1200 |
+
if (--depth < 0) {
|
| 1201 |
+
// We consumed the entire tree: return nullptr for new tree.
|
| 1202 |
+
result.tree = nullptr;
|
| 1203 |
+
return result;
|
| 1204 |
+
}
|
| 1205 |
+
rep = tree;
|
| 1206 |
+
tree = stack[depth];
|
| 1207 |
+
}
|
| 1208 |
+
|
| 1209 |
+
// Remove the edge or cascaded up parent node.
|
| 1210 |
+
tree->set_end(tree->end() - 1);
|
| 1211 |
+
tree->length -= length;
|
| 1212 |
+
|
| 1213 |
+
// Adjust lengths up the tree.
|
| 1214 |
+
while (depth > 0) {
|
| 1215 |
+
tree = stack[--depth];
|
| 1216 |
+
tree->length -= length;
|
| 1217 |
+
}
|
| 1218 |
+
|
| 1219 |
+
// Remove unnecessary top nodes with size = 1. This may iterate all the way
|
| 1220 |
+
// down to the leaf node in which case we simply return the remaining last
|
| 1221 |
+
// edge in that node and the extracted flat.
|
| 1222 |
+
while (tree->size() == 1) {
|
| 1223 |
+
int height = tree->height();
|
| 1224 |
+
rep = tree->Edge(kBack);
|
| 1225 |
+
Delete(tree);
|
| 1226 |
+
if (height == 0) {
|
| 1227 |
+
// We consumed the leaf: return the sole data edge as the new tree.
|
| 1228 |
+
result.tree = rep;
|
| 1229 |
+
return result;
|
| 1230 |
+
}
|
| 1231 |
+
tree = rep->btree();
|
| 1232 |
+
}
|
| 1233 |
+
|
| 1234 |
+
// Done: return the (new) top level node and extracted flat.
|
| 1235 |
+
result.tree = tree;
|
| 1236 |
+
return result;
|
| 1237 |
+
}
|
| 1238 |
+
|
| 1239 |
+
} // namespace cord_internal
|
| 1240 |
+
ABSL_NAMESPACE_END
|
| 1241 |
+
} // namespace absl
|
weight/_dep/abseil-cpp/absl/strings/internal/cord_rep_btree_navigator.cc
ADDED
|
@@ -0,0 +1,187 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
// Copyright 2021 The Abseil Authors
|
| 2 |
+
//
|
| 3 |
+
// Licensed under the Apache License, Version 2.0 (the "License");
|
| 4 |
+
// you may not use this file except in compliance with the License.
|
| 5 |
+
// You may obtain a copy of the License at
|
| 6 |
+
//
|
| 7 |
+
// https://www.apache.org/licenses/LICENSE-2.0
|
| 8 |
+
//
|
| 9 |
+
// Unless required by applicable law or agreed to in writing, software
|
| 10 |
+
// distributed under the License is distributed on an "AS IS" BASIS,
|
| 11 |
+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
| 12 |
+
// See the License for the specific language governing permissions and
|
| 13 |
+
// limitations under the License.
|
| 14 |
+
|
| 15 |
+
#include "absl/strings/internal/cord_rep_btree_navigator.h"
|
| 16 |
+
|
| 17 |
+
#include <cassert>
|
| 18 |
+
|
| 19 |
+
#include "absl/strings/internal/cord_data_edge.h"
|
| 20 |
+
#include "absl/strings/internal/cord_internal.h"
|
| 21 |
+
#include "absl/strings/internal/cord_rep_btree.h"
|
| 22 |
+
|
| 23 |
+
namespace absl {
|
| 24 |
+
ABSL_NAMESPACE_BEGIN
|
| 25 |
+
namespace cord_internal {
|
| 26 |
+
|
| 27 |
+
using ReadResult = CordRepBtreeNavigator::ReadResult;
|
| 28 |
+
|
| 29 |
+
namespace {
|
| 30 |
+
|
| 31 |
+
// Returns a `CordRepSubstring` from `rep` starting at `offset` of size `n`.
|
| 32 |
+
// If `rep` is already a `CordRepSubstring` instance, an adjusted instance is
|
| 33 |
+
// created based on the old offset and new offset.
|
| 34 |
+
// Adopts a reference on `rep`. Rep must be a valid data edge. Returns
|
| 35 |
+
// nullptr if `n == 0`, `rep` if `n == rep->length`.
|
| 36 |
+
// Requires `offset < rep->length` and `offset + n <= rep->length`.
|
| 37 |
+
// TODO(192061034): move to utility library in internal and optimize for small
|
| 38 |
+
// substrings of larger reps.
|
| 39 |
+
inline CordRep* Substring(CordRep* rep, size_t offset, size_t n) {
|
| 40 |
+
assert(n <= rep->length);
|
| 41 |
+
assert(offset < rep->length);
|
| 42 |
+
assert(offset <= rep->length - n);
|
| 43 |
+
assert(IsDataEdge(rep));
|
| 44 |
+
|
| 45 |
+
if (n == 0) return nullptr;
|
| 46 |
+
if (n == rep->length) return CordRep::Ref(rep);
|
| 47 |
+
|
| 48 |
+
if (rep->tag == SUBSTRING) {
|
| 49 |
+
offset += rep->substring()->start;
|
| 50 |
+
rep = rep->substring()->child;
|
| 51 |
+
}
|
| 52 |
+
|
| 53 |
+
assert(rep->IsExternal() || rep->IsFlat());
|
| 54 |
+
CordRepSubstring* substring = new CordRepSubstring();
|
| 55 |
+
substring->length = n;
|
| 56 |
+
substring->tag = SUBSTRING;
|
| 57 |
+
substring->start = offset;
|
| 58 |
+
substring->child = CordRep::Ref(rep);
|
| 59 |
+
return substring;
|
| 60 |
+
}
|
| 61 |
+
|
| 62 |
+
inline CordRep* Substring(CordRep* rep, size_t offset) {
|
| 63 |
+
return Substring(rep, offset, rep->length - offset);
|
| 64 |
+
}
|
| 65 |
+
|
| 66 |
+
} // namespace
|
| 67 |
+
|
| 68 |
+
CordRepBtreeNavigator::Position CordRepBtreeNavigator::Skip(size_t n) {
|
| 69 |
+
int height = 0;
|
| 70 |
+
size_t index = index_[0];
|
| 71 |
+
CordRepBtree* node = node_[0];
|
| 72 |
+
CordRep* edge = node->Edge(index);
|
| 73 |
+
|
| 74 |
+
// Overall logic: Find an edge of at least the length we need to skip.
|
| 75 |
+
// We consume all edges which are smaller (i.e., must be 100% skipped).
|
| 76 |
+
// If we exhausted all edges on the current level, we move one level
|
| 77 |
+
// up the tree, and repeat until we either find the edge, or until we hit
|
| 78 |
+
// the top of the tree meaning the skip exceeds tree->length.
|
| 79 |
+
while (n >= edge->length) {
|
| 80 |
+
n -= edge->length;
|
| 81 |
+
while (++index == node->end()) {
|
| 82 |
+
if (++height > height_) return {nullptr, n};
|
| 83 |
+
node = node_[height];
|
| 84 |
+
index = index_[height];
|
| 85 |
+
}
|
| 86 |
+
edge = node->Edge(index);
|
| 87 |
+
}
|
| 88 |
+
|
| 89 |
+
// If we moved up the tree, descend down to the leaf level, consuming all
|
| 90 |
+
// edges that must be skipped.
|
| 91 |
+
while (height > 0) {
|
| 92 |
+
node = edge->btree();
|
| 93 |
+
index_[height] = static_cast<uint8_t>(index);
|
| 94 |
+
node_[--height] = node;
|
| 95 |
+
index = node->begin();
|
| 96 |
+
edge = node->Edge(index);
|
| 97 |
+
while (n >= edge->length) {
|
| 98 |
+
n -= edge->length;
|
| 99 |
+
++index;
|
| 100 |
+
assert(index != node->end());
|
| 101 |
+
edge = node->Edge(index);
|
| 102 |
+
}
|
| 103 |
+
}
|
| 104 |
+
index_[0] = static_cast<uint8_t>(index);
|
| 105 |
+
return {edge, n};
|
| 106 |
+
}
|
| 107 |
+
|
| 108 |
+
ReadResult CordRepBtreeNavigator::Read(size_t edge_offset, size_t n) {
|
| 109 |
+
int height = 0;
|
| 110 |
+
size_t length = edge_offset + n;
|
| 111 |
+
size_t index = index_[0];
|
| 112 |
+
CordRepBtree* node = node_[0];
|
| 113 |
+
CordRep* edge = node->Edge(index);
|
| 114 |
+
assert(edge_offset < edge->length);
|
| 115 |
+
|
| 116 |
+
if (length < edge->length) {
|
| 117 |
+
return {Substring(edge, edge_offset, n), length};
|
| 118 |
+
}
|
| 119 |
+
|
| 120 |
+
// Similar to 'Skip', we consume all edges that are inside the 'length' of
|
| 121 |
+
// data that needs to be read. If we exhaust the current level, we move one
|
| 122 |
+
// level up the tree and repeat until we hit the final edge that must be
|
| 123 |
+
// (partially) read. We consume all edges into `subtree`.
|
| 124 |
+
CordRepBtree* subtree = CordRepBtree::New(Substring(edge, edge_offset));
|
| 125 |
+
size_t subtree_end = 1;
|
| 126 |
+
do {
|
| 127 |
+
length -= edge->length;
|
| 128 |
+
while (++index == node->end()) {
|
| 129 |
+
index_[height] = static_cast<uint8_t>(index);
|
| 130 |
+
if (++height > height_) {
|
| 131 |
+
subtree->set_end(subtree_end);
|
| 132 |
+
if (length == 0) return {subtree, 0};
|
| 133 |
+
CordRep::Unref(subtree);
|
| 134 |
+
return {nullptr, length};
|
| 135 |
+
}
|
| 136 |
+
if (length != 0) {
|
| 137 |
+
subtree->set_end(subtree_end);
|
| 138 |
+
subtree = CordRepBtree::New(subtree);
|
| 139 |
+
subtree_end = 1;
|
| 140 |
+
}
|
| 141 |
+
node = node_[height];
|
| 142 |
+
index = index_[height];
|
| 143 |
+
}
|
| 144 |
+
edge = node->Edge(index);
|
| 145 |
+
if (length >= edge->length) {
|
| 146 |
+
subtree->length += edge->length;
|
| 147 |
+
subtree->edges_[subtree_end++] = CordRep::Ref(edge);
|
| 148 |
+
}
|
| 149 |
+
} while (length >= edge->length);
|
| 150 |
+
CordRepBtree* tree = subtree;
|
| 151 |
+
subtree->length += length;
|
| 152 |
+
|
| 153 |
+
// If we moved up the tree, descend down to the leaf level, consuming all
|
| 154 |
+
// edges that must be read, adding 'down' nodes to `subtree`.
|
| 155 |
+
while (height > 0) {
|
| 156 |
+
node = edge->btree();
|
| 157 |
+
index_[height] = static_cast<uint8_t>(index);
|
| 158 |
+
node_[--height] = node;
|
| 159 |
+
index = node->begin();
|
| 160 |
+
edge = node->Edge(index);
|
| 161 |
+
|
| 162 |
+
if (length != 0) {
|
| 163 |
+
CordRepBtree* right = CordRepBtree::New(height);
|
| 164 |
+
right->length = length;
|
| 165 |
+
subtree->edges_[subtree_end++] = right;
|
| 166 |
+
subtree->set_end(subtree_end);
|
| 167 |
+
subtree = right;
|
| 168 |
+
subtree_end = 0;
|
| 169 |
+
while (length >= edge->length) {
|
| 170 |
+
subtree->edges_[subtree_end++] = CordRep::Ref(edge);
|
| 171 |
+
length -= edge->length;
|
| 172 |
+
edge = node->Edge(++index);
|
| 173 |
+
}
|
| 174 |
+
}
|
| 175 |
+
}
|
| 176 |
+
// Add any (partial) edge still remaining at the leaf level.
|
| 177 |
+
if (length != 0) {
|
| 178 |
+
subtree->edges_[subtree_end++] = Substring(edge, 0, length);
|
| 179 |
+
}
|
| 180 |
+
subtree->set_end(subtree_end);
|
| 181 |
+
index_[0] = static_cast<uint8_t>(index);
|
| 182 |
+
return {tree, length};
|
| 183 |
+
}
|
| 184 |
+
|
| 185 |
+
} // namespace cord_internal
|
| 186 |
+
ABSL_NAMESPACE_END
|
| 187 |
+
} // namespace absl
|
weight/_dep/abseil-cpp/absl/strings/internal/cord_rep_btree_navigator.h
ADDED
|
@@ -0,0 +1,267 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
// Copyright 2021 The Abseil Authors
|
| 2 |
+
//
|
| 3 |
+
// Licensed under the Apache License, Version 2.0 (the "License");
|
| 4 |
+
// you may not use this file except in compliance with the License.
|
| 5 |
+
// You may obtain a copy of the License at
|
| 6 |
+
//
|
| 7 |
+
// https://www.apache.org/licenses/LICENSE-2.0
|
| 8 |
+
//
|
| 9 |
+
// Unless required by applicable law or agreed to in writing, software
|
| 10 |
+
// distributed under the License is distributed on an "AS IS" BASIS,
|
| 11 |
+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
| 12 |
+
// See the License for the specific language governing permissions and
|
| 13 |
+
// limitations under the License.
|
| 14 |
+
|
| 15 |
+
#ifndef ABSL_STRINGS_INTERNAL_CORD_REP_BTREE_NAVIGATOR_H_
|
| 16 |
+
#define ABSL_STRINGS_INTERNAL_CORD_REP_BTREE_NAVIGATOR_H_
|
| 17 |
+
|
| 18 |
+
#include <cassert>
|
| 19 |
+
#include <iostream>
|
| 20 |
+
|
| 21 |
+
#include "absl/strings/internal/cord_internal.h"
|
| 22 |
+
#include "absl/strings/internal/cord_rep_btree.h"
|
| 23 |
+
|
| 24 |
+
namespace absl {
|
| 25 |
+
ABSL_NAMESPACE_BEGIN
|
| 26 |
+
namespace cord_internal {
|
| 27 |
+
|
| 28 |
+
// CordRepBtreeNavigator is a bi-directional navigator allowing callers to
|
| 29 |
+
// navigate all the (leaf) data edges in a CordRepBtree instance.
|
| 30 |
+
//
|
| 31 |
+
// A CordRepBtreeNavigator instance is by default empty. Callers initialize a
|
| 32 |
+
// navigator instance by calling one of `InitFirst()`, `InitLast()` or
|
| 33 |
+
// `InitOffset()`, which establishes a current position. Callers can then
|
| 34 |
+
// navigate using the `Next`, `Previous`, `Skip` and `Seek` methods.
|
| 35 |
+
//
|
| 36 |
+
// The navigator instance does not take or adopt a reference on the provided
|
| 37 |
+
// `tree` on any of the initialization calls. Callers are responsible for
|
| 38 |
+
// guaranteeing the lifecycle of the provided tree. A navigator instance can
|
| 39 |
+
// be reset to the empty state by calling `Reset`.
|
| 40 |
+
//
|
| 41 |
+
// A navigator only keeps positional state on the 'current data edge', it does
|
| 42 |
+
// explicitly not keep any 'offset' state. The class does accept and return
|
| 43 |
+
// offsets in the `Read()`, `Skip()` and 'Seek()` methods as these would
|
| 44 |
+
// otherwise put a big burden on callers. Callers are expected to maintain
|
| 45 |
+
// (returned) offset info if they require such granular state.
|
| 46 |
+
class CordRepBtreeNavigator {
|
| 47 |
+
public:
|
| 48 |
+
// The logical position as returned by the Seek() and Skip() functions.
|
| 49 |
+
// Returns the current leaf edge for the desired seek or skip position and
|
| 50 |
+
// the offset of that position inside that edge.
|
| 51 |
+
struct Position {
|
| 52 |
+
CordRep* edge;
|
| 53 |
+
size_t offset;
|
| 54 |
+
};
|
| 55 |
+
|
| 56 |
+
// The read result as returned by the Read() function.
|
| 57 |
+
// `tree` contains the resulting tree which is identical to the result
|
| 58 |
+
// of calling CordRepBtree::SubTree(...) on the tree being navigated.
|
| 59 |
+
// `n` contains the number of bytes used from the last navigated to
|
| 60 |
+
// edge of the tree.
|
| 61 |
+
struct ReadResult {
|
| 62 |
+
CordRep* tree;
|
| 63 |
+
size_t n;
|
| 64 |
+
};
|
| 65 |
+
|
| 66 |
+
// Returns true if this instance is not empty.
|
| 67 |
+
explicit operator bool() const;
|
| 68 |
+
|
| 69 |
+
// Returns the tree for this instance or nullptr if empty.
|
| 70 |
+
CordRepBtree* btree() const;
|
| 71 |
+
|
| 72 |
+
// Returns the data edge of the current position.
|
| 73 |
+
// Requires this instance to not be empty.
|
| 74 |
+
CordRep* Current() const;
|
| 75 |
+
|
| 76 |
+
// Resets this navigator to `tree`, returning the first data edge in the tree.
|
| 77 |
+
CordRep* InitFirst(CordRepBtree* tree);
|
| 78 |
+
|
| 79 |
+
// Resets this navigator to `tree`, returning the last data edge in the tree.
|
| 80 |
+
CordRep* InitLast(CordRepBtree* tree);
|
| 81 |
+
|
| 82 |
+
// Resets this navigator to `tree` returning the data edge at position
|
| 83 |
+
// `offset` and the relative offset of `offset` into that data edge.
|
| 84 |
+
// Returns `Position.edge = nullptr` if the provided offset is greater
|
| 85 |
+
// than or equal to the length of the tree, in which case the state of
|
| 86 |
+
// the navigator instance remains unchanged.
|
| 87 |
+
Position InitOffset(CordRepBtree* tree, size_t offset);
|
| 88 |
+
|
| 89 |
+
// Navigates to the next data edge.
|
| 90 |
+
// Returns the next data edge or nullptr if there is no next data edge, in
|
| 91 |
+
// which case the current position remains unchanged.
|
| 92 |
+
CordRep* Next();
|
| 93 |
+
|
| 94 |
+
// Navigates to the previous data edge.
|
| 95 |
+
// Returns the previous data edge or nullptr if there is no previous data
|
| 96 |
+
// edge, in which case the current position remains unchanged.
|
| 97 |
+
CordRep* Previous();
|
| 98 |
+
|
| 99 |
+
// Navigates to the data edge at position `offset`. Returns the navigated to
|
| 100 |
+
// data edge in `Position.edge` and the relative offset of `offset` into that
|
| 101 |
+
// data edge in `Position.offset`. Returns `Position.edge = nullptr` if the
|
| 102 |
+
// provide offset is greater than or equal to the tree's length.
|
| 103 |
+
Position Seek(size_t offset);
|
| 104 |
+
|
| 105 |
+
// Reads `n` bytes of data starting at offset `edge_offset` of the current
|
| 106 |
+
// data edge, and returns the result in `ReadResult.tree`. `ReadResult.n`
|
| 107 |
+
// contains the 'bytes used` from the last / current data edge in the tree.
|
| 108 |
+
// This allows users that mix regular navigation (using string views) and
|
| 109 |
+
// 'read into cord' navigation to keep track of the current state, and which
|
| 110 |
+
// bytes have been consumed from a navigator.
|
| 111 |
+
// This function returns `ReadResult.tree = nullptr` if the requested length
|
| 112 |
+
// exceeds the length of the tree starting at the current data edge.
|
| 113 |
+
ReadResult Read(size_t edge_offset, size_t n);
|
| 114 |
+
|
| 115 |
+
// Skips `n` bytes forward from the current data edge, returning the navigated
|
| 116 |
+
// to data edge in `Position.edge` and `Position.offset` containing the offset
|
| 117 |
+
// inside that data edge. Note that the state of the navigator is left
|
| 118 |
+
// unchanged if `n` is smaller than the length of the current data edge.
|
| 119 |
+
Position Skip(size_t n);
|
| 120 |
+
|
| 121 |
+
// Resets this instance to the default / empty state.
|
| 122 |
+
void Reset();
|
| 123 |
+
|
| 124 |
+
private:
|
| 125 |
+
// Slow path for Next() if Next() reached the end of a leaf node. Backtracks
|
| 126 |
+
// up the stack until it finds a node that has a 'next' position available,
|
| 127 |
+
// and then does a 'front dive' towards the next leaf node.
|
| 128 |
+
CordRep* NextUp();
|
| 129 |
+
|
| 130 |
+
// Slow path for Previous() if Previous() reached the beginning of a leaf
|
| 131 |
+
// node. Backtracks up the stack until it finds a node that has a 'previous'
|
| 132 |
+
// position available, and then does a 'back dive' towards the previous leaf
|
| 133 |
+
// node.
|
| 134 |
+
CordRep* PreviousUp();
|
| 135 |
+
|
| 136 |
+
// Generic implementation of InitFirst() and InitLast().
|
| 137 |
+
template <CordRepBtree::EdgeType edge_type>
|
| 138 |
+
CordRep* Init(CordRepBtree* tree);
|
| 139 |
+
|
| 140 |
+
// `height_` contains the height of the current tree, or -1 if empty.
|
| 141 |
+
int height_ = -1;
|
| 142 |
+
|
| 143 |
+
// `index_` and `node_` contain the navigation state as the 'path' to the
|
| 144 |
+
// current data edge which is at `node_[0]->Edge(index_[0])`. The contents
|
| 145 |
+
// of these are undefined until the instance is initialized (`height_ >= 0`).
|
| 146 |
+
uint8_t index_[CordRepBtree::kMaxDepth];
|
| 147 |
+
CordRepBtree* node_[CordRepBtree::kMaxDepth];
|
| 148 |
+
};
|
| 149 |
+
|
| 150 |
+
// Returns true if this instance is not empty.
|
| 151 |
+
inline CordRepBtreeNavigator::operator bool() const { return height_ >= 0; }
|
| 152 |
+
|
| 153 |
+
inline CordRepBtree* CordRepBtreeNavigator::btree() const {
|
| 154 |
+
return height_ >= 0 ? node_[height_] : nullptr;
|
| 155 |
+
}
|
| 156 |
+
|
| 157 |
+
inline CordRep* CordRepBtreeNavigator::Current() const {
|
| 158 |
+
assert(height_ >= 0);
|
| 159 |
+
return node_[0]->Edge(index_[0]);
|
| 160 |
+
}
|
| 161 |
+
|
| 162 |
+
inline void CordRepBtreeNavigator::Reset() { height_ = -1; }
|
| 163 |
+
|
| 164 |
+
inline CordRep* CordRepBtreeNavigator::InitFirst(CordRepBtree* tree) {
|
| 165 |
+
return Init<CordRepBtree::kFront>(tree);
|
| 166 |
+
}
|
| 167 |
+
|
| 168 |
+
inline CordRep* CordRepBtreeNavigator::InitLast(CordRepBtree* tree) {
|
| 169 |
+
return Init<CordRepBtree::kBack>(tree);
|
| 170 |
+
}
|
| 171 |
+
|
| 172 |
+
template <CordRepBtree::EdgeType edge_type>
|
| 173 |
+
inline CordRep* CordRepBtreeNavigator::Init(CordRepBtree* tree) {
|
| 174 |
+
assert(tree != nullptr);
|
| 175 |
+
assert(tree->size() > 0);
|
| 176 |
+
assert(tree->height() <= CordRepBtree::kMaxHeight);
|
| 177 |
+
int height = height_ = tree->height();
|
| 178 |
+
size_t index = tree->index(edge_type);
|
| 179 |
+
node_[height] = tree;
|
| 180 |
+
index_[height] = static_cast<uint8_t>(index);
|
| 181 |
+
while (--height >= 0) {
|
| 182 |
+
tree = tree->Edge(index)->btree();
|
| 183 |
+
node_[height] = tree;
|
| 184 |
+
index = tree->index(edge_type);
|
| 185 |
+
index_[height] = static_cast<uint8_t>(index);
|
| 186 |
+
}
|
| 187 |
+
return node_[0]->Edge(index);
|
| 188 |
+
}
|
| 189 |
+
|
| 190 |
+
inline CordRepBtreeNavigator::Position CordRepBtreeNavigator::Seek(
|
| 191 |
+
size_t offset) {
|
| 192 |
+
assert(btree() != nullptr);
|
| 193 |
+
int height = height_;
|
| 194 |
+
CordRepBtree* edge = node_[height];
|
| 195 |
+
if (ABSL_PREDICT_FALSE(offset >= edge->length)) return {nullptr, 0};
|
| 196 |
+
CordRepBtree::Position index = edge->IndexOf(offset);
|
| 197 |
+
index_[height] = static_cast<uint8_t>(index.index);
|
| 198 |
+
while (--height >= 0) {
|
| 199 |
+
edge = edge->Edge(index.index)->btree();
|
| 200 |
+
node_[height] = edge;
|
| 201 |
+
index = edge->IndexOf(index.n);
|
| 202 |
+
index_[height] = static_cast<uint8_t>(index.index);
|
| 203 |
+
}
|
| 204 |
+
return {edge->Edge(index.index), index.n};
|
| 205 |
+
}
|
| 206 |
+
|
| 207 |
+
inline CordRepBtreeNavigator::Position CordRepBtreeNavigator::InitOffset(
|
| 208 |
+
CordRepBtree* tree, size_t offset) {
|
| 209 |
+
assert(tree != nullptr);
|
| 210 |
+
assert(tree->height() <= CordRepBtree::kMaxHeight);
|
| 211 |
+
if (ABSL_PREDICT_FALSE(offset >= tree->length)) return {nullptr, 0};
|
| 212 |
+
height_ = tree->height();
|
| 213 |
+
node_[height_] = tree;
|
| 214 |
+
return Seek(offset);
|
| 215 |
+
}
|
| 216 |
+
|
| 217 |
+
inline CordRep* CordRepBtreeNavigator::Next() {
|
| 218 |
+
CordRepBtree* edge = node_[0];
|
| 219 |
+
return index_[0] == edge->back() ? NextUp() : edge->Edge(++index_[0]);
|
| 220 |
+
}
|
| 221 |
+
|
| 222 |
+
inline CordRep* CordRepBtreeNavigator::Previous() {
|
| 223 |
+
CordRepBtree* edge = node_[0];
|
| 224 |
+
return index_[0] == edge->begin() ? PreviousUp() : edge->Edge(--index_[0]);
|
| 225 |
+
}
|
| 226 |
+
|
| 227 |
+
inline CordRep* CordRepBtreeNavigator::NextUp() {
|
| 228 |
+
assert(index_[0] == node_[0]->back());
|
| 229 |
+
CordRepBtree* edge;
|
| 230 |
+
size_t index;
|
| 231 |
+
int height = 0;
|
| 232 |
+
do {
|
| 233 |
+
if (++height > height_) return nullptr;
|
| 234 |
+
edge = node_[height];
|
| 235 |
+
index = index_[height] + 1;
|
| 236 |
+
} while (index == edge->end());
|
| 237 |
+
index_[height] = static_cast<uint8_t>(index);
|
| 238 |
+
do {
|
| 239 |
+
node_[--height] = edge = edge->Edge(index)->btree();
|
| 240 |
+
index_[height] = static_cast<uint8_t>(index = edge->begin());
|
| 241 |
+
} while (height > 0);
|
| 242 |
+
return edge->Edge(index);
|
| 243 |
+
}
|
| 244 |
+
|
| 245 |
+
inline CordRep* CordRepBtreeNavigator::PreviousUp() {
|
| 246 |
+
assert(index_[0] == node_[0]->begin());
|
| 247 |
+
CordRepBtree* edge;
|
| 248 |
+
size_t index;
|
| 249 |
+
int height = 0;
|
| 250 |
+
do {
|
| 251 |
+
if (++height > height_) return nullptr;
|
| 252 |
+
edge = node_[height];
|
| 253 |
+
index = index_[height];
|
| 254 |
+
} while (index == edge->begin());
|
| 255 |
+
index_[height] = static_cast<uint8_t>(--index);
|
| 256 |
+
do {
|
| 257 |
+
node_[--height] = edge = edge->Edge(index)->btree();
|
| 258 |
+
index_[height] = static_cast<uint8_t>(index = edge->back());
|
| 259 |
+
} while (height > 0);
|
| 260 |
+
return edge->Edge(index);
|
| 261 |
+
}
|
| 262 |
+
|
| 263 |
+
} // namespace cord_internal
|
| 264 |
+
ABSL_NAMESPACE_END
|
| 265 |
+
} // namespace absl
|
| 266 |
+
|
| 267 |
+
#endif // ABSL_STRINGS_INTERNAL_CORD_REP_BTREE_NAVIGATOR_H_
|
weight/_dep/abseil-cpp/absl/strings/internal/cord_rep_btree_reader.cc
ADDED
|
@@ -0,0 +1,69 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
// Copyright 2021 The Abseil Authors
|
| 2 |
+
//
|
| 3 |
+
// Licensed under the Apache License, Version 2.0 (the "License");
|
| 4 |
+
// you may not use this file except in compliance with the License.
|
| 5 |
+
// You may obtain a copy of the License at
|
| 6 |
+
//
|
| 7 |
+
// https://www.apache.org/licenses/LICENSE-2.0
|
| 8 |
+
//
|
| 9 |
+
// Unless required by applicable law or agreed to in writing, software
|
| 10 |
+
// distributed under the License is distributed on an "AS IS" BASIS,
|
| 11 |
+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
| 12 |
+
// See the License for the specific language governing permissions and
|
| 13 |
+
// limitations under the License.
|
| 14 |
+
|
| 15 |
+
#include "absl/strings/internal/cord_rep_btree_reader.h"
|
| 16 |
+
|
| 17 |
+
#include <cassert>
|
| 18 |
+
|
| 19 |
+
#include "absl/base/config.h"
|
| 20 |
+
#include "absl/strings/internal/cord_data_edge.h"
|
| 21 |
+
#include "absl/strings/internal/cord_internal.h"
|
| 22 |
+
#include "absl/strings/internal/cord_rep_btree.h"
|
| 23 |
+
#include "absl/strings/internal/cord_rep_btree_navigator.h"
|
| 24 |
+
#include "absl/strings/internal/cord_rep_flat.h"
|
| 25 |
+
|
| 26 |
+
namespace absl {
|
| 27 |
+
ABSL_NAMESPACE_BEGIN
|
| 28 |
+
namespace cord_internal {
|
| 29 |
+
|
| 30 |
+
absl::string_view CordRepBtreeReader::Read(size_t n, size_t chunk_size,
|
| 31 |
+
CordRep*& tree) {
|
| 32 |
+
assert(chunk_size <= navigator_.Current()->length);
|
| 33 |
+
|
| 34 |
+
// If chunk_size is non-zero, we need to start inside last returned edge.
|
| 35 |
+
// Else we start reading at the next data edge of the tree.
|
| 36 |
+
CordRep* edge = chunk_size ? navigator_.Current() : navigator_.Next();
|
| 37 |
+
const size_t offset = chunk_size ? edge->length - chunk_size : 0;
|
| 38 |
+
|
| 39 |
+
// Read the sub tree and verify we got what we wanted.
|
| 40 |
+
ReadResult result = navigator_.Read(offset, n);
|
| 41 |
+
tree = result.tree;
|
| 42 |
+
|
| 43 |
+
// If the data returned in `tree` was covered entirely by `chunk_size`, i.e.,
|
| 44 |
+
// read from the 'previous' edge, we did not consume any additional data, and
|
| 45 |
+
// can directly return the substring into the current data edge as the next
|
| 46 |
+
// chunk. We can easily establish from the above code that `navigator_.Next()`
|
| 47 |
+
// has not been called as that requires `chunk_size` to be zero.
|
| 48 |
+
if (n < chunk_size) return EdgeData(edge).substr(result.n);
|
| 49 |
+
|
| 50 |
+
// The amount of data taken from the last edge is `chunk_size` and `result.n`
|
| 51 |
+
// contains the offset into the current edge trailing the read data (which can
|
| 52 |
+
// be 0). As the call to `navigator_.Read()` could have consumed all remaining
|
| 53 |
+
// data, calling `navigator_.Current()` is not safe before checking if we
|
| 54 |
+
// already consumed all remaining data.
|
| 55 |
+
const size_t consumed_by_read = n - chunk_size - result.n;
|
| 56 |
+
if (consumed_by_read >= remaining_) {
|
| 57 |
+
remaining_ = 0;
|
| 58 |
+
return {};
|
| 59 |
+
}
|
| 60 |
+
|
| 61 |
+
// We did not read all data, return remaining data from current edge.
|
| 62 |
+
edge = navigator_.Current();
|
| 63 |
+
remaining_ -= consumed_by_read + edge->length;
|
| 64 |
+
return EdgeData(edge).substr(result.n);
|
| 65 |
+
}
|
| 66 |
+
|
| 67 |
+
} // namespace cord_internal
|
| 68 |
+
ABSL_NAMESPACE_END
|
| 69 |
+
} // namespace absl
|
weight/_dep/abseil-cpp/absl/strings/internal/cord_rep_btree_reader.h
ADDED
|
@@ -0,0 +1,212 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
// Copyright 2021 The Abseil Authors
|
| 2 |
+
//
|
| 3 |
+
// Licensed under the Apache License, Version 2.0 (the "License");
|
| 4 |
+
// you may not use this file except in compliance with the License.
|
| 5 |
+
// You may obtain a copy of the License at
|
| 6 |
+
//
|
| 7 |
+
// https://www.apache.org/licenses/LICENSE-2.0
|
| 8 |
+
//
|
| 9 |
+
// Unless required by applicable law or agreed to in writing, software
|
| 10 |
+
// distributed under the License is distributed on an "AS IS" BASIS,
|
| 11 |
+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
| 12 |
+
// See the License for the specific language governing permissions and
|
| 13 |
+
// limitations under the License.
|
| 14 |
+
|
| 15 |
+
#ifndef ABSL_STRINGS_INTERNAL_CORD_REP_BTREE_READER_H_
|
| 16 |
+
#define ABSL_STRINGS_INTERNAL_CORD_REP_BTREE_READER_H_
|
| 17 |
+
|
| 18 |
+
#include <cassert>
|
| 19 |
+
|
| 20 |
+
#include "absl/base/config.h"
|
| 21 |
+
#include "absl/strings/internal/cord_data_edge.h"
|
| 22 |
+
#include "absl/strings/internal/cord_internal.h"
|
| 23 |
+
#include "absl/strings/internal/cord_rep_btree.h"
|
| 24 |
+
#include "absl/strings/internal/cord_rep_btree_navigator.h"
|
| 25 |
+
#include "absl/strings/internal/cord_rep_flat.h"
|
| 26 |
+
|
| 27 |
+
namespace absl {
|
| 28 |
+
ABSL_NAMESPACE_BEGIN
|
| 29 |
+
namespace cord_internal {
|
| 30 |
+
|
| 31 |
+
// CordRepBtreeReader implements logic to iterate over cord btrees.
|
| 32 |
+
// References to the underlying data are returned as absl::string_view values.
|
| 33 |
+
// The most typical use case is a forward only iteration over tree data.
|
| 34 |
+
// The class also provides `Skip()`, `Seek()` and `Read()` methods similar to
|
| 35 |
+
// CordRepBtreeNavigator that allow more advanced navigation.
|
| 36 |
+
//
|
| 37 |
+
// Example: iterate over all data inside a cord btree:
|
| 38 |
+
//
|
| 39 |
+
// CordRepBtreeReader reader;
|
| 40 |
+
// for (string_view sv = reader.Init(tree); !sv.Empty(); sv = sv.Next()) {
|
| 41 |
+
// DoSomethingWithDataIn(sv);
|
| 42 |
+
// }
|
| 43 |
+
//
|
| 44 |
+
// All navigation methods always return the next 'chunk' of data. The class
|
| 45 |
+
// assumes that all data is directly 'consumed' by the caller. For example:
|
| 46 |
+
// invoking `Skip()` will skip the desired number of bytes, and directly
|
| 47 |
+
// read and return the next chunk of data directly after the skipped bytes.
|
| 48 |
+
//
|
| 49 |
+
// Example: iterate over all data inside a btree skipping the first 100 bytes:
|
| 50 |
+
//
|
| 51 |
+
// CordRepBtreeReader reader;
|
| 52 |
+
// absl::string_view sv = reader.Init(tree);
|
| 53 |
+
// if (sv.length() > 100) {
|
| 54 |
+
// sv.RemovePrefix(100);
|
| 55 |
+
// } else {
|
| 56 |
+
// sv = reader.Skip(100 - sv.length());
|
| 57 |
+
// }
|
| 58 |
+
// while (!sv.empty()) {
|
| 59 |
+
// DoSomethingWithDataIn(sv);
|
| 60 |
+
// absl::string_view sv = reader.Next();
|
| 61 |
+
// }
|
| 62 |
+
//
|
| 63 |
+
// It is important to notice that `remaining` is based on the end position of
|
| 64 |
+
// the last data edge returned to the caller, not the cumulative data returned
|
| 65 |
+
// to the caller which can be less in cases of skipping or seeking over data.
|
| 66 |
+
//
|
| 67 |
+
// For example, consider a cord btree with five data edges: "abc", "def", "ghi",
|
| 68 |
+
// "jkl" and "mno":
|
| 69 |
+
//
|
| 70 |
+
// absl::string_view sv;
|
| 71 |
+
// CordRepBtreeReader reader;
|
| 72 |
+
//
|
| 73 |
+
// sv = reader.Init(tree); // sv = "abc", remaining = 12
|
| 74 |
+
// sv = reader.Skip(4); // sv = "hi", remaining = 6
|
| 75 |
+
// sv = reader.Skip(2); // sv = "l", remaining = 3
|
| 76 |
+
// sv = reader.Next(); // sv = "mno", remaining = 0
|
| 77 |
+
// sv = reader.Seek(1); // sv = "bc", remaining = 12
|
| 78 |
+
//
|
| 79 |
+
class CordRepBtreeReader {
|
| 80 |
+
public:
|
| 81 |
+
using ReadResult = CordRepBtreeNavigator::ReadResult;
|
| 82 |
+
using Position = CordRepBtreeNavigator::Position;
|
| 83 |
+
|
| 84 |
+
// Returns true if this instance is not empty.
|
| 85 |
+
explicit operator bool() const { return navigator_.btree() != nullptr; }
|
| 86 |
+
|
| 87 |
+
// Returns the tree referenced by this instance or nullptr if empty.
|
| 88 |
+
CordRepBtree* btree() const { return navigator_.btree(); }
|
| 89 |
+
|
| 90 |
+
// Returns the current data edge inside the referenced btree.
|
| 91 |
+
// Requires that the current instance is not empty.
|
| 92 |
+
CordRep* node() const { return navigator_.Current(); }
|
| 93 |
+
|
| 94 |
+
// Returns the length of the referenced tree.
|
| 95 |
+
// Requires that the current instance is not empty.
|
| 96 |
+
size_t length() const;
|
| 97 |
+
|
| 98 |
+
// Returns the number of remaining bytes available for iteration, which is the
|
| 99 |
+
// number of bytes directly following the end of the last chunk returned.
|
| 100 |
+
// This value will be zero if we iterated over the last edge in the bound
|
| 101 |
+
// tree, in which case any call to Next() or Skip() will return an empty
|
| 102 |
+
// string_view reflecting the EOF state.
|
| 103 |
+
// Note that a call to `Seek()` resets `remaining` to a value based on the
|
| 104 |
+
// end position of the chunk returned by that call.
|
| 105 |
+
size_t remaining() const { return remaining_; }
|
| 106 |
+
|
| 107 |
+
// Resets this instance to an empty value.
|
| 108 |
+
void Reset() { navigator_.Reset(); }
|
| 109 |
+
|
| 110 |
+
// Initializes this instance with `tree`. `tree` must not be null.
|
| 111 |
+
// Returns a reference to the first data edge of the provided tree.
|
| 112 |
+
absl::string_view Init(CordRepBtree* tree);
|
| 113 |
+
|
| 114 |
+
// Navigates to and returns the next data edge of the referenced tree.
|
| 115 |
+
// Returns an empty string_view if an attempt is made to read beyond the end
|
| 116 |
+
// of the tree, i.e.: if `remaining()` is zero indicating an EOF condition.
|
| 117 |
+
// Requires that the current instance is not empty.
|
| 118 |
+
absl::string_view Next();
|
| 119 |
+
|
| 120 |
+
// Skips the provided amount of bytes and returns a reference to the data
|
| 121 |
+
// directly following the skipped bytes.
|
| 122 |
+
absl::string_view Skip(size_t skip);
|
| 123 |
+
|
| 124 |
+
// Reads `n` bytes into `tree`.
|
| 125 |
+
// If `chunk_size` is zero, starts reading at the next data edge. If
|
| 126 |
+
// `chunk_size` is non zero, the read starts at the last `chunk_size` bytes of
|
| 127 |
+
// the last returned data edge. Effectively, this means that the read starts
|
| 128 |
+
// at offset `consumed() - chunk_size`.
|
| 129 |
+
// Requires that `chunk_size` is less than or equal to the length of the
|
| 130 |
+
// last returned data edge. The purpose of `chunk_size` is to simplify code
|
| 131 |
+
// partially consuming a returned chunk and wanting to include the remaining
|
| 132 |
+
// bytes in the Read call. For example, the below code will read 1000 bytes of
|
| 133 |
+
// data into a cord tree if the first chunk starts with "big:":
|
| 134 |
+
//
|
| 135 |
+
// CordRepBtreeReader reader;
|
| 136 |
+
// absl::string_view sv = reader.Init(tree);
|
| 137 |
+
// if (absl::StartsWith(sv, "big:")) {
|
| 138 |
+
// CordRepBtree tree;
|
| 139 |
+
// sv = reader.Read(1000, sv.size() - 4 /* "big:" */, &tree);
|
| 140 |
+
// }
|
| 141 |
+
//
|
| 142 |
+
// This method will return an empty string view if all remaining data was
|
| 143 |
+
// read. If `n` exceeded the amount of remaining data this function will
|
| 144 |
+
// return an empty string view and `tree` will be set to nullptr.
|
| 145 |
+
// In both cases, `consumed` will be set to `length`.
|
| 146 |
+
absl::string_view Read(size_t n, size_t chunk_size, CordRep*& tree);
|
| 147 |
+
|
| 148 |
+
// Navigates to the chunk at offset `offset`.
|
| 149 |
+
// Returns a reference into the navigated to chunk, adjusted for the relative
|
| 150 |
+
// position of `offset` into that chunk. For example, calling `Seek(13)` on a
|
| 151 |
+
// cord tree containing 2 chunks of 10 and 20 bytes respectively will return
|
| 152 |
+
// a string view into the second chunk starting at offset 3 with a size of 17.
|
| 153 |
+
// Returns an empty string view if `offset` is equal to or greater than the
|
| 154 |
+
// length of the referenced tree.
|
| 155 |
+
absl::string_view Seek(size_t offset);
|
| 156 |
+
|
| 157 |
+
private:
|
| 158 |
+
size_t remaining_ = 0;
|
| 159 |
+
CordRepBtreeNavigator navigator_;
|
| 160 |
+
};
|
| 161 |
+
|
| 162 |
+
inline size_t CordRepBtreeReader::length() const {
|
| 163 |
+
assert(btree() != nullptr);
|
| 164 |
+
return btree()->length;
|
| 165 |
+
}
|
| 166 |
+
|
| 167 |
+
inline absl::string_view CordRepBtreeReader::Init(CordRepBtree* tree) {
|
| 168 |
+
assert(tree != nullptr);
|
| 169 |
+
const CordRep* edge = navigator_.InitFirst(tree);
|
| 170 |
+
remaining_ = tree->length - edge->length;
|
| 171 |
+
return EdgeData(edge);
|
| 172 |
+
}
|
| 173 |
+
|
| 174 |
+
inline absl::string_view CordRepBtreeReader::Next() {
|
| 175 |
+
if (remaining_ == 0) return {};
|
| 176 |
+
const CordRep* edge = navigator_.Next();
|
| 177 |
+
assert(edge != nullptr);
|
| 178 |
+
remaining_ -= edge->length;
|
| 179 |
+
return EdgeData(edge);
|
| 180 |
+
}
|
| 181 |
+
|
| 182 |
+
inline absl::string_view CordRepBtreeReader::Skip(size_t skip) {
|
| 183 |
+
// As we are always positioned on the last 'consumed' edge, we
|
| 184 |
+
// need to skip the current edge as well as `skip`.
|
| 185 |
+
const size_t edge_length = navigator_.Current()->length;
|
| 186 |
+
CordRepBtreeNavigator::Position pos = navigator_.Skip(skip + edge_length);
|
| 187 |
+
if (ABSL_PREDICT_FALSE(pos.edge == nullptr)) {
|
| 188 |
+
remaining_ = 0;
|
| 189 |
+
return {};
|
| 190 |
+
}
|
| 191 |
+
// The combined length of all edges skipped before `pos.edge` is `skip -
|
| 192 |
+
// pos.offset`, all of which are 'consumed', as well as the current edge.
|
| 193 |
+
remaining_ -= skip - pos.offset + pos.edge->length;
|
| 194 |
+
return EdgeData(pos.edge).substr(pos.offset);
|
| 195 |
+
}
|
| 196 |
+
|
| 197 |
+
inline absl::string_view CordRepBtreeReader::Seek(size_t offset) {
|
| 198 |
+
const CordRepBtreeNavigator::Position pos = navigator_.Seek(offset);
|
| 199 |
+
if (ABSL_PREDICT_FALSE(pos.edge == nullptr)) {
|
| 200 |
+
remaining_ = 0;
|
| 201 |
+
return {};
|
| 202 |
+
}
|
| 203 |
+
absl::string_view chunk = EdgeData(pos.edge).substr(pos.offset);
|
| 204 |
+
remaining_ = length() - offset - chunk.length();
|
| 205 |
+
return chunk;
|
| 206 |
+
}
|
| 207 |
+
|
| 208 |
+
} // namespace cord_internal
|
| 209 |
+
ABSL_NAMESPACE_END
|
| 210 |
+
} // namespace absl
|
| 211 |
+
|
| 212 |
+
#endif // ABSL_STRINGS_INTERNAL_CORD_REP_BTREE_READER_H_
|
weight/_dep/abseil-cpp/absl/strings/internal/cord_rep_btree_reader_test.cc
ADDED
|
@@ -0,0 +1,293 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
// Copyright 2021 The Abseil Authors
|
| 2 |
+
//
|
| 3 |
+
// Licensed under the Apache License, Version 2.0 (the "License");
|
| 4 |
+
// you may not use this file except in compliance with the License.
|
| 5 |
+
// You may obtain a copy of the License at
|
| 6 |
+
//
|
| 7 |
+
// https://www.apache.org/licenses/LICENSE-2.0
|
| 8 |
+
//
|
| 9 |
+
// Unless required by applicable law or agreed to in writing, software
|
| 10 |
+
// distributed under the License is distributed on an "AS IS" BASIS,
|
| 11 |
+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
| 12 |
+
// See the License for the specific language governing permissions and
|
| 13 |
+
// limitations under the License.
|
| 14 |
+
|
| 15 |
+
#include "absl/strings/internal/cord_rep_btree_reader.h"
|
| 16 |
+
|
| 17 |
+
#include <iostream>
|
| 18 |
+
#include <random>
|
| 19 |
+
#include <string>
|
| 20 |
+
#include <vector>
|
| 21 |
+
|
| 22 |
+
#include "gmock/gmock.h"
|
| 23 |
+
#include "gtest/gtest.h"
|
| 24 |
+
#include "absl/base/config.h"
|
| 25 |
+
#include "absl/base/internal/raw_logging.h"
|
| 26 |
+
#include "absl/strings/cord.h"
|
| 27 |
+
#include "absl/strings/internal/cord_internal.h"
|
| 28 |
+
#include "absl/strings/internal/cord_rep_btree.h"
|
| 29 |
+
#include "absl/strings/internal/cord_rep_test_util.h"
|
| 30 |
+
#include "absl/strings/string_view.h"
|
| 31 |
+
|
| 32 |
+
namespace absl {
|
| 33 |
+
ABSL_NAMESPACE_BEGIN
|
| 34 |
+
namespace cord_internal {
|
| 35 |
+
namespace {
|
| 36 |
+
|
| 37 |
+
using ::testing::Eq;
|
| 38 |
+
using ::testing::IsEmpty;
|
| 39 |
+
using ::testing::Ne;
|
| 40 |
+
using ::testing::Not;
|
| 41 |
+
|
| 42 |
+
using ::absl::cordrep_testing::CordRepBtreeFromFlats;
|
| 43 |
+
using ::absl::cordrep_testing::MakeFlat;
|
| 44 |
+
using ::absl::cordrep_testing::CordToString;
|
| 45 |
+
using ::absl::cordrep_testing::CreateFlatsFromString;
|
| 46 |
+
using ::absl::cordrep_testing::CreateRandomString;
|
| 47 |
+
|
| 48 |
+
using ReadResult = CordRepBtreeReader::ReadResult;
|
| 49 |
+
|
| 50 |
+
TEST(CordRepBtreeReaderTest, Next) {
|
| 51 |
+
constexpr size_t kChars = 3;
|
| 52 |
+
const size_t cap = CordRepBtree::kMaxCapacity;
|
| 53 |
+
size_t counts[] = {1, 2, cap, cap * cap, cap * cap + 1, cap * cap * 2 + 17};
|
| 54 |
+
|
| 55 |
+
for (size_t count : counts) {
|
| 56 |
+
std::string data = CreateRandomString(count * kChars);
|
| 57 |
+
std::vector<CordRep*> flats = CreateFlatsFromString(data, kChars);
|
| 58 |
+
CordRepBtree* node = CordRepBtreeFromFlats(flats);
|
| 59 |
+
|
| 60 |
+
CordRepBtreeReader reader;
|
| 61 |
+
size_t remaining = data.length();
|
| 62 |
+
absl::string_view chunk = reader.Init(node);
|
| 63 |
+
EXPECT_THAT(chunk, Eq(data.substr(0, chunk.length())));
|
| 64 |
+
|
| 65 |
+
remaining -= chunk.length();
|
| 66 |
+
EXPECT_THAT(reader.remaining(), Eq(remaining));
|
| 67 |
+
|
| 68 |
+
while (remaining > 0) {
|
| 69 |
+
const size_t offset = data.length() - remaining;
|
| 70 |
+
chunk = reader.Next();
|
| 71 |
+
EXPECT_THAT(chunk, Eq(data.substr(offset, chunk.length())));
|
| 72 |
+
|
| 73 |
+
remaining -= chunk.length();
|
| 74 |
+
EXPECT_THAT(reader.remaining(), Eq(remaining));
|
| 75 |
+
}
|
| 76 |
+
|
| 77 |
+
EXPECT_THAT(reader.remaining(), Eq(0u));
|
| 78 |
+
|
| 79 |
+
// Verify trying to read beyond EOF returns empty string_view
|
| 80 |
+
EXPECT_THAT(reader.Next(), testing::IsEmpty());
|
| 81 |
+
|
| 82 |
+
CordRep::Unref(node);
|
| 83 |
+
}
|
| 84 |
+
}
|
| 85 |
+
|
| 86 |
+
TEST(CordRepBtreeReaderTest, Skip) {
|
| 87 |
+
constexpr size_t kChars = 3;
|
| 88 |
+
const size_t cap = CordRepBtree::kMaxCapacity;
|
| 89 |
+
size_t counts[] = {1, 2, cap, cap * cap, cap * cap + 1, cap * cap * 2 + 17};
|
| 90 |
+
|
| 91 |
+
for (size_t count : counts) {
|
| 92 |
+
std::string data = CreateRandomString(count * kChars);
|
| 93 |
+
std::vector<CordRep*> flats = CreateFlatsFromString(data, kChars);
|
| 94 |
+
CordRepBtree* node = CordRepBtreeFromFlats(flats);
|
| 95 |
+
|
| 96 |
+
for (size_t skip1 = 0; skip1 < data.length() - kChars; ++skip1) {
|
| 97 |
+
for (size_t skip2 = 0; skip2 < data.length() - kChars; ++skip2) {
|
| 98 |
+
CordRepBtreeReader reader;
|
| 99 |
+
size_t remaining = data.length();
|
| 100 |
+
absl::string_view chunk = reader.Init(node);
|
| 101 |
+
remaining -= chunk.length();
|
| 102 |
+
|
| 103 |
+
chunk = reader.Skip(skip1);
|
| 104 |
+
size_t offset = data.length() - remaining;
|
| 105 |
+
ASSERT_THAT(chunk, Eq(data.substr(offset + skip1, chunk.length())));
|
| 106 |
+
remaining -= chunk.length() + skip1;
|
| 107 |
+
ASSERT_THAT(reader.remaining(), Eq(remaining));
|
| 108 |
+
|
| 109 |
+
if (remaining == 0) continue;
|
| 110 |
+
|
| 111 |
+
size_t skip = std::min(remaining - 1, skip2);
|
| 112 |
+
chunk = reader.Skip(skip);
|
| 113 |
+
offset = data.length() - remaining;
|
| 114 |
+
ASSERT_THAT(chunk, Eq(data.substr(offset + skip, chunk.length())));
|
| 115 |
+
}
|
| 116 |
+
}
|
| 117 |
+
|
| 118 |
+
CordRep::Unref(node);
|
| 119 |
+
}
|
| 120 |
+
}
|
| 121 |
+
|
| 122 |
+
TEST(CordRepBtreeReaderTest, SkipBeyondLength) {
|
| 123 |
+
CordRepBtree* tree = CordRepBtree::Create(MakeFlat("abc"));
|
| 124 |
+
tree = CordRepBtree::Append(tree, MakeFlat("def"));
|
| 125 |
+
CordRepBtreeReader reader;
|
| 126 |
+
reader.Init(tree);
|
| 127 |
+
EXPECT_THAT(reader.Skip(100), IsEmpty());
|
| 128 |
+
EXPECT_THAT(reader.remaining(), Eq(0u));
|
| 129 |
+
CordRep::Unref(tree);
|
| 130 |
+
}
|
| 131 |
+
|
| 132 |
+
TEST(CordRepBtreeReaderTest, Seek) {
|
| 133 |
+
constexpr size_t kChars = 3;
|
| 134 |
+
const size_t cap = CordRepBtree::kMaxCapacity;
|
| 135 |
+
size_t counts[] = {1, 2, cap, cap * cap, cap * cap + 1, cap * cap * 2 + 17};
|
| 136 |
+
|
| 137 |
+
for (size_t count : counts) {
|
| 138 |
+
std::string data = CreateRandomString(count * kChars);
|
| 139 |
+
std::vector<CordRep*> flats = CreateFlatsFromString(data, kChars);
|
| 140 |
+
CordRepBtree* node = CordRepBtreeFromFlats(flats);
|
| 141 |
+
|
| 142 |
+
for (size_t seek = 0; seek < data.length() - 1; ++seek) {
|
| 143 |
+
CordRepBtreeReader reader;
|
| 144 |
+
reader.Init(node);
|
| 145 |
+
absl::string_view chunk = reader.Seek(seek);
|
| 146 |
+
ASSERT_THAT(chunk, Not(IsEmpty()));
|
| 147 |
+
ASSERT_THAT(chunk, Eq(data.substr(seek, chunk.length())));
|
| 148 |
+
ASSERT_THAT(reader.remaining(),
|
| 149 |
+
Eq(data.length() - seek - chunk.length()));
|
| 150 |
+
}
|
| 151 |
+
|
| 152 |
+
CordRep::Unref(node);
|
| 153 |
+
}
|
| 154 |
+
}
|
| 155 |
+
|
| 156 |
+
TEST(CordRepBtreeReaderTest, SeekBeyondLength) {
|
| 157 |
+
CordRepBtree* tree = CordRepBtree::Create(MakeFlat("abc"));
|
| 158 |
+
tree = CordRepBtree::Append(tree, MakeFlat("def"));
|
| 159 |
+
CordRepBtreeReader reader;
|
| 160 |
+
reader.Init(tree);
|
| 161 |
+
EXPECT_THAT(reader.Seek(6), IsEmpty());
|
| 162 |
+
EXPECT_THAT(reader.remaining(), Eq(0u));
|
| 163 |
+
EXPECT_THAT(reader.Seek(100), IsEmpty());
|
| 164 |
+
EXPECT_THAT(reader.remaining(), Eq(0u));
|
| 165 |
+
CordRep::Unref(tree);
|
| 166 |
+
}
|
| 167 |
+
|
| 168 |
+
TEST(CordRepBtreeReaderTest, Read) {
|
| 169 |
+
std::string data = "abcdefghijklmno";
|
| 170 |
+
std::vector<CordRep*> flats = CreateFlatsFromString(data, 5);
|
| 171 |
+
CordRepBtree* node = CordRepBtreeFromFlats(flats);
|
| 172 |
+
|
| 173 |
+
CordRep* tree;
|
| 174 |
+
CordRepBtreeReader reader;
|
| 175 |
+
absl::string_view chunk;
|
| 176 |
+
|
| 177 |
+
// Read zero bytes
|
| 178 |
+
chunk = reader.Init(node);
|
| 179 |
+
chunk = reader.Read(0, chunk.length(), tree);
|
| 180 |
+
EXPECT_THAT(tree, Eq(nullptr));
|
| 181 |
+
EXPECT_THAT(chunk, Eq("abcde"));
|
| 182 |
+
EXPECT_THAT(reader.remaining(), Eq(10u));
|
| 183 |
+
EXPECT_THAT(reader.Next(), Eq("fghij"));
|
| 184 |
+
|
| 185 |
+
// Read in full
|
| 186 |
+
chunk = reader.Init(node);
|
| 187 |
+
chunk = reader.Read(15, chunk.length(), tree);
|
| 188 |
+
EXPECT_THAT(tree, Ne(nullptr));
|
| 189 |
+
EXPECT_THAT(CordToString(tree), Eq("abcdefghijklmno"));
|
| 190 |
+
EXPECT_THAT(chunk, Eq(""));
|
| 191 |
+
EXPECT_THAT(reader.remaining(), Eq(0u));
|
| 192 |
+
CordRep::Unref(tree);
|
| 193 |
+
|
| 194 |
+
// Read < chunk bytes
|
| 195 |
+
chunk = reader.Init(node);
|
| 196 |
+
chunk = reader.Read(3, chunk.length(), tree);
|
| 197 |
+
ASSERT_THAT(tree, Ne(nullptr));
|
| 198 |
+
EXPECT_THAT(CordToString(tree), Eq("abc"));
|
| 199 |
+
EXPECT_THAT(chunk, Eq("de"));
|
| 200 |
+
EXPECT_THAT(reader.remaining(), Eq(10u));
|
| 201 |
+
EXPECT_THAT(reader.Next(), Eq("fghij"));
|
| 202 |
+
CordRep::Unref(tree);
|
| 203 |
+
|
| 204 |
+
// Read < chunk bytes at offset
|
| 205 |
+
chunk = reader.Init(node);
|
| 206 |
+
chunk = reader.Read(2, chunk.length() - 2, tree);
|
| 207 |
+
ASSERT_THAT(tree, Ne(nullptr));
|
| 208 |
+
EXPECT_THAT(CordToString(tree), Eq("cd"));
|
| 209 |
+
EXPECT_THAT(chunk, Eq("e"));
|
| 210 |
+
EXPECT_THAT(reader.remaining(), Eq(10u));
|
| 211 |
+
EXPECT_THAT(reader.Next(), Eq("fghij"));
|
| 212 |
+
CordRep::Unref(tree);
|
| 213 |
+
|
| 214 |
+
// Read from consumed chunk
|
| 215 |
+
chunk = reader.Init(node);
|
| 216 |
+
chunk = reader.Read(3, 0, tree);
|
| 217 |
+
ASSERT_THAT(tree, Ne(nullptr));
|
| 218 |
+
EXPECT_THAT(CordToString(tree), Eq("fgh"));
|
| 219 |
+
EXPECT_THAT(chunk, Eq("ij"));
|
| 220 |
+
EXPECT_THAT(reader.remaining(), Eq(5u));
|
| 221 |
+
EXPECT_THAT(reader.Next(), Eq("klmno"));
|
| 222 |
+
CordRep::Unref(tree);
|
| 223 |
+
|
| 224 |
+
// Read across chunks
|
| 225 |
+
chunk = reader.Init(node);
|
| 226 |
+
chunk = reader.Read(12, chunk.length() - 2, tree);
|
| 227 |
+
ASSERT_THAT(tree, Ne(nullptr));
|
| 228 |
+
EXPECT_THAT(CordToString(tree), Eq("cdefghijklmn"));
|
| 229 |
+
EXPECT_THAT(chunk, Eq("o"));
|
| 230 |
+
EXPECT_THAT(reader.remaining(), Eq(0u));
|
| 231 |
+
CordRep::Unref(tree);
|
| 232 |
+
|
| 233 |
+
// Read across chunks landing on exact edge boundary
|
| 234 |
+
chunk = reader.Init(node);
|
| 235 |
+
chunk = reader.Read(10 - 2, chunk.length() - 2, tree);
|
| 236 |
+
ASSERT_THAT(tree, Ne(nullptr));
|
| 237 |
+
EXPECT_THAT(CordToString(tree), Eq("cdefghij"));
|
| 238 |
+
EXPECT_THAT(chunk, Eq("klmno"));
|
| 239 |
+
EXPECT_THAT(reader.remaining(), Eq(0u));
|
| 240 |
+
CordRep::Unref(tree);
|
| 241 |
+
|
| 242 |
+
CordRep::Unref(node);
|
| 243 |
+
}
|
| 244 |
+
|
| 245 |
+
TEST(CordRepBtreeReaderTest, ReadExhaustive) {
|
| 246 |
+
constexpr size_t kChars = 3;
|
| 247 |
+
const size_t cap = CordRepBtree::kMaxCapacity;
|
| 248 |
+
size_t counts[] = {1, 2, cap, cap * cap + 1, cap * cap * cap * 2 + 17};
|
| 249 |
+
|
| 250 |
+
for (size_t count : counts) {
|
| 251 |
+
std::string data = CreateRandomString(count * kChars);
|
| 252 |
+
std::vector<CordRep*> flats = CreateFlatsFromString(data, kChars);
|
| 253 |
+
CordRepBtree* node = CordRepBtreeFromFlats(flats);
|
| 254 |
+
|
| 255 |
+
for (size_t read_size : {kChars - 1, kChars, kChars + 7, cap * cap}) {
|
| 256 |
+
CordRepBtreeReader reader;
|
| 257 |
+
absl::string_view chunk = reader.Init(node);
|
| 258 |
+
|
| 259 |
+
// `consumed` tracks the end of last consumed chunk which is the start of
|
| 260 |
+
// the next chunk: we always read with `chunk_size = chunk.length()`.
|
| 261 |
+
size_t consumed = 0;
|
| 262 |
+
size_t remaining = data.length();
|
| 263 |
+
while (remaining > 0) {
|
| 264 |
+
CordRep* tree;
|
| 265 |
+
size_t n = (std::min)(remaining, read_size);
|
| 266 |
+
chunk = reader.Read(n, chunk.length(), tree);
|
| 267 |
+
EXPECT_THAT(tree, Ne(nullptr));
|
| 268 |
+
if (tree) {
|
| 269 |
+
EXPECT_THAT(CordToString(tree), Eq(data.substr(consumed, n)));
|
| 270 |
+
CordRep::Unref(tree);
|
| 271 |
+
}
|
| 272 |
+
|
| 273 |
+
consumed += n;
|
| 274 |
+
remaining -= n;
|
| 275 |
+
EXPECT_THAT(reader.remaining(), Eq(remaining - chunk.length()));
|
| 276 |
+
|
| 277 |
+
if (remaining > 0) {
|
| 278 |
+
ASSERT_FALSE(chunk.empty());
|
| 279 |
+
ASSERT_THAT(chunk, Eq(data.substr(consumed, chunk.length())));
|
| 280 |
+
} else {
|
| 281 |
+
ASSERT_TRUE(chunk.empty()) << chunk;
|
| 282 |
+
}
|
| 283 |
+
}
|
| 284 |
+
}
|
| 285 |
+
|
| 286 |
+
CordRep::Unref(node);
|
| 287 |
+
}
|
| 288 |
+
}
|
| 289 |
+
|
| 290 |
+
} // namespace
|
| 291 |
+
} // namespace cord_internal
|
| 292 |
+
ABSL_NAMESPACE_END
|
| 293 |
+
} // namespace absl
|
weight/_dep/abseil-cpp/absl/strings/internal/cord_rep_btree_test.cc
ADDED
|
@@ -0,0 +1,1568 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
// Copyright 2021 The Abseil Authors
|
| 2 |
+
//
|
| 3 |
+
// Licensed under the Apache License, Version 2.0 (the "License");
|
| 4 |
+
// you may not use this file except in compliance with the License.
|
| 5 |
+
// You may obtain a copy of the License at
|
| 6 |
+
//
|
| 7 |
+
// https://www.apache.org/licenses/LICENSE-2.0
|
| 8 |
+
//
|
| 9 |
+
// Unless required by applicable law or agreed to in writing, software
|
| 10 |
+
// distributed under the License is distributed on an "AS IS" BASIS,
|
| 11 |
+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
| 12 |
+
// See the License for the specific language governing permissions and
|
| 13 |
+
// limitations under the License.
|
| 14 |
+
|
| 15 |
+
#include "absl/strings/internal/cord_rep_btree.h"
|
| 16 |
+
|
| 17 |
+
#include <cmath>
|
| 18 |
+
#include <deque>
|
| 19 |
+
#include <iostream>
|
| 20 |
+
#include <string>
|
| 21 |
+
#include <vector>
|
| 22 |
+
|
| 23 |
+
#include "gmock/gmock.h"
|
| 24 |
+
#include "gtest/gtest.h"
|
| 25 |
+
#include "absl/base/config.h"
|
| 26 |
+
#include "absl/base/internal/raw_logging.h"
|
| 27 |
+
#include "absl/cleanup/cleanup.h"
|
| 28 |
+
#include "absl/strings/internal/cord_data_edge.h"
|
| 29 |
+
#include "absl/strings/internal/cord_internal.h"
|
| 30 |
+
#include "absl/strings/internal/cord_rep_test_util.h"
|
| 31 |
+
#include "absl/strings/str_cat.h"
|
| 32 |
+
#include "absl/strings/string_view.h"
|
| 33 |
+
|
| 34 |
+
namespace absl {
|
| 35 |
+
ABSL_NAMESPACE_BEGIN
|
| 36 |
+
namespace cord_internal {
|
| 37 |
+
|
| 38 |
+
class CordRepBtreeTestPeer {
|
| 39 |
+
public:
|
| 40 |
+
static void SetEdge(CordRepBtree* node, size_t idx, CordRep* edge) {
|
| 41 |
+
node->edges_[idx] = edge;
|
| 42 |
+
}
|
| 43 |
+
static void AddEdge(CordRepBtree* node, CordRep* edge) {
|
| 44 |
+
node->edges_[node->fetch_add_end(1)] = edge;
|
| 45 |
+
}
|
| 46 |
+
};
|
| 47 |
+
|
| 48 |
+
namespace {
|
| 49 |
+
|
| 50 |
+
using ::absl::cordrep_testing::AutoUnref;
|
| 51 |
+
using ::absl::cordrep_testing::CordCollectRepsIf;
|
| 52 |
+
using ::absl::cordrep_testing::CordToString;
|
| 53 |
+
using ::absl::cordrep_testing::CordVisitReps;
|
| 54 |
+
using ::absl::cordrep_testing::CreateFlatsFromString;
|
| 55 |
+
using ::absl::cordrep_testing::CreateRandomString;
|
| 56 |
+
using ::absl::cordrep_testing::MakeExternal;
|
| 57 |
+
using ::absl::cordrep_testing::MakeFlat;
|
| 58 |
+
using ::absl::cordrep_testing::MakeSubstring;
|
| 59 |
+
using ::testing::_;
|
| 60 |
+
using ::testing::AllOf;
|
| 61 |
+
using ::testing::AnyOf;
|
| 62 |
+
using ::testing::Conditional;
|
| 63 |
+
using ::testing::ElementsAre;
|
| 64 |
+
using ::testing::ElementsAreArray;
|
| 65 |
+
using ::testing::Eq;
|
| 66 |
+
using ::testing::HasSubstr;
|
| 67 |
+
using ::testing::Le;
|
| 68 |
+
using ::testing::Ne;
|
| 69 |
+
using ::testing::Not;
|
| 70 |
+
using ::testing::SizeIs;
|
| 71 |
+
using ::testing::TypedEq;
|
| 72 |
+
|
| 73 |
+
MATCHER_P(EqFlatHolding, data, "Equals flat holding data") {
|
| 74 |
+
if (arg->tag < FLAT) {
|
| 75 |
+
*result_listener << "Expected FLAT, got tag " << static_cast<int>(arg->tag);
|
| 76 |
+
return false;
|
| 77 |
+
}
|
| 78 |
+
std::string actual = CordToString(arg);
|
| 79 |
+
if (actual != data) {
|
| 80 |
+
*result_listener << "Expected flat holding \"" << data
|
| 81 |
+
<< "\", got flat holding \"" << actual << "\"";
|
| 82 |
+
return false;
|
| 83 |
+
}
|
| 84 |
+
return true;
|
| 85 |
+
}
|
| 86 |
+
|
| 87 |
+
MATCHER_P(IsNode, height, absl::StrCat("Is a valid node of height ", height)) {
|
| 88 |
+
if (arg == nullptr) {
|
| 89 |
+
*result_listener << "Expected NODE, got nullptr";
|
| 90 |
+
return false;
|
| 91 |
+
}
|
| 92 |
+
if (arg->tag != BTREE) {
|
| 93 |
+
*result_listener << "Expected NODE, got " << static_cast<int>(arg->tag);
|
| 94 |
+
return false;
|
| 95 |
+
}
|
| 96 |
+
if (!CordRepBtree::IsValid(arg->btree())) {
|
| 97 |
+
CordRepBtree::Dump(arg->btree(), "Expected valid NODE, got:", false,
|
| 98 |
+
*result_listener->stream());
|
| 99 |
+
return false;
|
| 100 |
+
}
|
| 101 |
+
if (arg->btree()->height() != height) {
|
| 102 |
+
*result_listener << "Expected NODE of height " << height << ", got "
|
| 103 |
+
<< arg->btree()->height();
|
| 104 |
+
return false;
|
| 105 |
+
}
|
| 106 |
+
return true;
|
| 107 |
+
}
|
| 108 |
+
|
| 109 |
+
MATCHER_P2(IsSubstring, start, length,
|
| 110 |
+
absl::StrCat("Is a substring(start = ", start, ", length = ", length,
|
| 111 |
+
")")) {
|
| 112 |
+
if (arg == nullptr) {
|
| 113 |
+
*result_listener << "Expected substring, got nullptr";
|
| 114 |
+
return false;
|
| 115 |
+
}
|
| 116 |
+
if (arg->tag != SUBSTRING) {
|
| 117 |
+
*result_listener << "Expected SUBSTRING, got "
|
| 118 |
+
<< static_cast<int>(arg->tag);
|
| 119 |
+
return false;
|
| 120 |
+
}
|
| 121 |
+
const CordRepSubstring* const substr = arg->substring();
|
| 122 |
+
if (substr->start != start || substr->length != length) {
|
| 123 |
+
*result_listener << "Expected substring(" << start << ", " << length
|
| 124 |
+
<< "), got substring(" << substr->start << ", "
|
| 125 |
+
<< substr->length << ")";
|
| 126 |
+
return false;
|
| 127 |
+
}
|
| 128 |
+
return true;
|
| 129 |
+
}
|
| 130 |
+
|
| 131 |
+
MATCHER_P2(EqExtractResult, tree, rep, "Equals ExtractResult") {
|
| 132 |
+
if (arg.tree != tree || arg.extracted != rep) {
|
| 133 |
+
*result_listener << "Expected {" << static_cast<const void*>(tree) << ", "
|
| 134 |
+
<< static_cast<const void*>(rep) << "}, got {" << arg.tree
|
| 135 |
+
<< ", " << arg.extracted << "}";
|
| 136 |
+
return false;
|
| 137 |
+
}
|
| 138 |
+
return true;
|
| 139 |
+
}
|
| 140 |
+
|
| 141 |
+
// DataConsumer is a simple helper class used by tests to 'consume' string
|
| 142 |
+
// fragments from the provided input in forward or backward direction.
|
| 143 |
+
class DataConsumer {
|
| 144 |
+
public:
|
| 145 |
+
// Starts consumption of `data`. Caller must make sure `data` outlives this
|
| 146 |
+
// instance. Consumes data starting at the front if `forward` is true, else
|
| 147 |
+
// consumes data from the back.
|
| 148 |
+
DataConsumer(absl::string_view data, bool forward)
|
| 149 |
+
: data_(data), forward_(forward) {}
|
| 150 |
+
|
| 151 |
+
// Return the next `n` bytes from referenced data.
|
| 152 |
+
absl::string_view Next(size_t n) {
|
| 153 |
+
assert(n <= data_.size() - consumed_);
|
| 154 |
+
consumed_ += n;
|
| 155 |
+
return data_.substr(forward_ ? consumed_ - n : data_.size() - consumed_, n);
|
| 156 |
+
}
|
| 157 |
+
|
| 158 |
+
// Returns all data consumed so far.
|
| 159 |
+
absl::string_view Consumed() const {
|
| 160 |
+
return forward_ ? data_.substr(0, consumed_)
|
| 161 |
+
: data_.substr(data_.size() - consumed_);
|
| 162 |
+
}
|
| 163 |
+
|
| 164 |
+
private:
|
| 165 |
+
absl::string_view data_;
|
| 166 |
+
size_t consumed_ = 0;
|
| 167 |
+
bool forward_;
|
| 168 |
+
};
|
| 169 |
+
|
| 170 |
+
// BtreeAdd returns either CordRepBtree::Append or CordRepBtree::Prepend.
|
| 171 |
+
CordRepBtree* BtreeAdd(CordRepBtree* node, bool append,
|
| 172 |
+
absl::string_view data) {
|
| 173 |
+
return append ? CordRepBtree::Append(node, data)
|
| 174 |
+
: CordRepBtree::Prepend(node, data);
|
| 175 |
+
}
|
| 176 |
+
|
| 177 |
+
// Recursively collects all leaf edges from `tree` and appends them to `edges`.
|
| 178 |
+
void GetLeafEdges(const CordRepBtree* tree, std::vector<CordRep*>& edges) {
|
| 179 |
+
if (tree->height() == 0) {
|
| 180 |
+
for (CordRep* edge : tree->Edges()) {
|
| 181 |
+
edges.push_back(edge);
|
| 182 |
+
}
|
| 183 |
+
} else {
|
| 184 |
+
for (CordRep* edge : tree->Edges()) {
|
| 185 |
+
GetLeafEdges(edge->btree(), edges);
|
| 186 |
+
}
|
| 187 |
+
}
|
| 188 |
+
}
|
| 189 |
+
|
| 190 |
+
// Recursively collects and returns all leaf edges from `tree`.
|
| 191 |
+
std::vector<CordRep*> GetLeafEdges(const CordRepBtree* tree) {
|
| 192 |
+
std::vector<CordRep*> edges;
|
| 193 |
+
GetLeafEdges(tree, edges);
|
| 194 |
+
return edges;
|
| 195 |
+
}
|
| 196 |
+
|
| 197 |
+
// Creates a flat containing the hexadecimal value of `i` zero padded
|
| 198 |
+
// to at least 4 digits prefixed with "0x", e.g.: "0x04AC".
|
| 199 |
+
CordRepFlat* MakeHexFlat(size_t i) {
|
| 200 |
+
return MakeFlat(absl::StrCat("0x", absl::Hex(i, absl::kZeroPad4)));
|
| 201 |
+
}
|
| 202 |
+
|
| 203 |
+
CordRepBtree* MakeLeaf(size_t size = CordRepBtree::kMaxCapacity) {
|
| 204 |
+
assert(size <= CordRepBtree::kMaxCapacity);
|
| 205 |
+
CordRepBtree* leaf = CordRepBtree::Create(MakeHexFlat(0));
|
| 206 |
+
for (size_t i = 1; i < size; ++i) {
|
| 207 |
+
leaf = CordRepBtree::Append(leaf, MakeHexFlat(i));
|
| 208 |
+
}
|
| 209 |
+
return leaf;
|
| 210 |
+
}
|
| 211 |
+
|
| 212 |
+
CordRepBtree* MakeTree(size_t size, bool append = true) {
|
| 213 |
+
CordRepBtree* tree = CordRepBtree::Create(MakeHexFlat(0));
|
| 214 |
+
for (size_t i = 1; i < size; ++i) {
|
| 215 |
+
tree = append ? CordRepBtree::Append(tree, MakeHexFlat(i))
|
| 216 |
+
: CordRepBtree::Prepend(tree, MakeHexFlat(i));
|
| 217 |
+
}
|
| 218 |
+
return tree;
|
| 219 |
+
}
|
| 220 |
+
|
| 221 |
+
CordRepBtree* CreateTree(absl::Span<CordRep* const> reps) {
|
| 222 |
+
auto it = reps.begin();
|
| 223 |
+
CordRepBtree* tree = CordRepBtree::Create(*it);
|
| 224 |
+
while (++it != reps.end()) tree = CordRepBtree::Append(tree, *it);
|
| 225 |
+
return tree;
|
| 226 |
+
}
|
| 227 |
+
|
| 228 |
+
CordRepBtree* CreateTree(absl::string_view data, size_t chunk_size) {
|
| 229 |
+
return CreateTree(CreateFlatsFromString(data, chunk_size));
|
| 230 |
+
}
|
| 231 |
+
|
| 232 |
+
CordRepBtree* CreateTreeReverse(absl::string_view data, size_t chunk_size) {
|
| 233 |
+
std::vector<CordRep*> flats = CreateFlatsFromString(data, chunk_size);
|
| 234 |
+
auto rit = flats.rbegin();
|
| 235 |
+
CordRepBtree* tree = CordRepBtree::Create(*rit);
|
| 236 |
+
while (++rit != flats.rend()) tree = CordRepBtree::Prepend(tree, *rit);
|
| 237 |
+
return tree;
|
| 238 |
+
}
|
| 239 |
+
|
| 240 |
+
class CordRepBtreeTest : public testing::TestWithParam<bool> {
|
| 241 |
+
public:
|
| 242 |
+
bool shared() const { return GetParam(); }
|
| 243 |
+
|
| 244 |
+
static std::string ToString(testing::TestParamInfo<bool> param) {
|
| 245 |
+
return param.param ? "Shared" : "Private";
|
| 246 |
+
}
|
| 247 |
+
};
|
| 248 |
+
|
| 249 |
+
INSTANTIATE_TEST_SUITE_P(WithParam, CordRepBtreeTest, testing::Bool(),
|
| 250 |
+
CordRepBtreeTest::ToString);
|
| 251 |
+
|
| 252 |
+
class CordRepBtreeHeightTest : public testing::TestWithParam<int> {
|
| 253 |
+
public:
|
| 254 |
+
int height() const { return GetParam(); }
|
| 255 |
+
|
| 256 |
+
static std::string ToString(testing::TestParamInfo<int> param) {
|
| 257 |
+
return absl::StrCat(param.param);
|
| 258 |
+
}
|
| 259 |
+
};
|
| 260 |
+
|
| 261 |
+
INSTANTIATE_TEST_SUITE_P(WithHeights, CordRepBtreeHeightTest,
|
| 262 |
+
testing::Range(0, CordRepBtree::kMaxHeight),
|
| 263 |
+
CordRepBtreeHeightTest::ToString);
|
| 264 |
+
|
| 265 |
+
using TwoBools = testing::tuple<bool, bool>;
|
| 266 |
+
|
| 267 |
+
class CordRepBtreeDualTest : public testing::TestWithParam<TwoBools> {
|
| 268 |
+
public:
|
| 269 |
+
bool first_shared() const { return std::get<0>(GetParam()); }
|
| 270 |
+
bool second_shared() const { return std::get<1>(GetParam()); }
|
| 271 |
+
|
| 272 |
+
static std::string ToString(testing::TestParamInfo<TwoBools> param) {
|
| 273 |
+
if (std::get<0>(param.param)) {
|
| 274 |
+
return std::get<1>(param.param) ? "BothShared" : "FirstShared";
|
| 275 |
+
}
|
| 276 |
+
return std::get<1>(param.param) ? "SecondShared" : "Private";
|
| 277 |
+
}
|
| 278 |
+
};
|
| 279 |
+
|
| 280 |
+
INSTANTIATE_TEST_SUITE_P(WithParam, CordRepBtreeDualTest,
|
| 281 |
+
testing::Combine(testing::Bool(), testing::Bool()),
|
| 282 |
+
CordRepBtreeDualTest::ToString);
|
| 283 |
+
|
| 284 |
+
TEST(CordRepBtreeTest, SizeIsMultipleOf64) {
|
| 285 |
+
// Only enforce for fully 64-bit platforms.
|
| 286 |
+
if (sizeof(size_t) == 8 && sizeof(void*) == 8) {
|
| 287 |
+
EXPECT_THAT(sizeof(CordRepBtree) % 64, Eq(0u))
|
| 288 |
+
<< "Should be multiple of 64";
|
| 289 |
+
}
|
| 290 |
+
}
|
| 291 |
+
|
| 292 |
+
TEST(CordRepBtreeTest, NewDestroyEmptyTree) {
|
| 293 |
+
auto* tree = CordRepBtree::New();
|
| 294 |
+
EXPECT_THAT(tree->size(), Eq(0u));
|
| 295 |
+
EXPECT_THAT(tree->height(), Eq(0));
|
| 296 |
+
EXPECT_THAT(tree->Edges(), ElementsAre());
|
| 297 |
+
CordRepBtree::Destroy(tree);
|
| 298 |
+
}
|
| 299 |
+
|
| 300 |
+
TEST(CordRepBtreeTest, NewDestroyEmptyTreeAtHeight) {
|
| 301 |
+
auto* tree = CordRepBtree::New(3);
|
| 302 |
+
EXPECT_THAT(tree->size(), Eq(0u));
|
| 303 |
+
EXPECT_THAT(tree->height(), Eq(3));
|
| 304 |
+
EXPECT_THAT(tree->Edges(), ElementsAre());
|
| 305 |
+
CordRepBtree::Destroy(tree);
|
| 306 |
+
}
|
| 307 |
+
|
| 308 |
+
TEST(CordRepBtreeTest, Btree) {
|
| 309 |
+
CordRep* rep = CordRepBtree::New();
|
| 310 |
+
EXPECT_THAT(rep->btree(), Eq(rep));
|
| 311 |
+
EXPECT_THAT(static_cast<const CordRep*>(rep)->btree(), Eq(rep));
|
| 312 |
+
CordRep::Unref(rep);
|
| 313 |
+
#if defined(GTEST_HAS_DEATH_TEST) && !defined(NDEBUG)
|
| 314 |
+
rep = MakeFlat("Hello world");
|
| 315 |
+
EXPECT_DEATH(rep->btree(), ".*");
|
| 316 |
+
EXPECT_DEATH(static_cast<const CordRep*>(rep)->btree(), ".*");
|
| 317 |
+
CordRep::Unref(rep);
|
| 318 |
+
#endif
|
| 319 |
+
}
|
| 320 |
+
|
| 321 |
+
TEST(CordRepBtreeTest, EdgeData) {
|
| 322 |
+
CordRepFlat* flat = MakeFlat("Hello world");
|
| 323 |
+
CordRepExternal* external = MakeExternal("Hello external");
|
| 324 |
+
CordRep* substr1 = MakeSubstring(1, 6, CordRep::Ref(flat));
|
| 325 |
+
CordRep* substr2 = MakeSubstring(1, 6, CordRep::Ref(external));
|
| 326 |
+
CordRep* bad_substr = MakeSubstring(1, 2, CordRep::Ref(substr1));
|
| 327 |
+
|
| 328 |
+
EXPECT_TRUE(IsDataEdge(flat));
|
| 329 |
+
EXPECT_THAT(EdgeData(flat).data(), TypedEq<const void*>(flat->Data()));
|
| 330 |
+
EXPECT_THAT(EdgeData(flat), Eq("Hello world"));
|
| 331 |
+
|
| 332 |
+
EXPECT_TRUE(IsDataEdge(external));
|
| 333 |
+
EXPECT_THAT(EdgeData(external).data(), TypedEq<const void*>(external->base));
|
| 334 |
+
EXPECT_THAT(EdgeData(external), Eq("Hello external"));
|
| 335 |
+
|
| 336 |
+
EXPECT_TRUE(IsDataEdge(substr1));
|
| 337 |
+
EXPECT_THAT(EdgeData(substr1).data(), TypedEq<const void*>(flat->Data() + 1));
|
| 338 |
+
EXPECT_THAT(EdgeData(substr1), Eq("ello w"));
|
| 339 |
+
|
| 340 |
+
EXPECT_TRUE(IsDataEdge(substr2));
|
| 341 |
+
EXPECT_THAT(EdgeData(substr2).data(),
|
| 342 |
+
TypedEq<const void*>(external->base + 1));
|
| 343 |
+
EXPECT_THAT(EdgeData(substr2), Eq("ello e"));
|
| 344 |
+
|
| 345 |
+
EXPECT_FALSE(IsDataEdge(bad_substr));
|
| 346 |
+
#if defined(GTEST_HAS_DEATH_TEST) && !defined(NDEBUG)
|
| 347 |
+
EXPECT_DEATH(EdgeData(bad_substr), ".*");
|
| 348 |
+
#endif
|
| 349 |
+
|
| 350 |
+
CordRep::Unref(bad_substr);
|
| 351 |
+
CordRep::Unref(substr2);
|
| 352 |
+
CordRep::Unref(substr1);
|
| 353 |
+
CordRep::Unref(external);
|
| 354 |
+
CordRep::Unref(flat);
|
| 355 |
+
}
|
| 356 |
+
|
| 357 |
+
TEST(CordRepBtreeTest, CreateUnrefLeaf) {
|
| 358 |
+
auto* flat = MakeFlat("a");
|
| 359 |
+
auto* leaf = CordRepBtree::Create(flat);
|
| 360 |
+
EXPECT_THAT(leaf->size(), Eq(1u));
|
| 361 |
+
EXPECT_THAT(leaf->height(), Eq(0));
|
| 362 |
+
EXPECT_THAT(leaf->Edges(), ElementsAre(flat));
|
| 363 |
+
CordRepBtree::Unref(leaf);
|
| 364 |
+
}
|
| 365 |
+
|
| 366 |
+
TEST(CordRepBtreeTest, NewUnrefNode) {
|
| 367 |
+
auto* leaf = CordRepBtree::Create(MakeFlat("a"));
|
| 368 |
+
CordRepBtree* tree = CordRepBtree::New(leaf);
|
| 369 |
+
EXPECT_THAT(tree->size(), Eq(1u));
|
| 370 |
+
EXPECT_THAT(tree->height(), Eq(1));
|
| 371 |
+
EXPECT_THAT(tree->Edges(), ElementsAre(leaf));
|
| 372 |
+
CordRepBtree::Unref(tree);
|
| 373 |
+
}
|
| 374 |
+
|
| 375 |
+
TEST_P(CordRepBtreeTest, AppendToLeafToCapacity) {
|
| 376 |
+
AutoUnref refs;
|
| 377 |
+
std::vector<CordRep*> flats;
|
| 378 |
+
flats.push_back(MakeHexFlat(0));
|
| 379 |
+
auto* leaf = CordRepBtree::Create(flats.back());
|
| 380 |
+
|
| 381 |
+
for (size_t i = 1; i < CordRepBtree::kMaxCapacity; ++i) {
|
| 382 |
+
refs.RefIf(shared(), leaf);
|
| 383 |
+
flats.push_back(MakeHexFlat(i));
|
| 384 |
+
auto* result = CordRepBtree::Append(leaf, flats.back());
|
| 385 |
+
EXPECT_THAT(result->height(), Eq(0));
|
| 386 |
+
EXPECT_THAT(result, Conditional(shared(), Ne(leaf), Eq(leaf)));
|
| 387 |
+
EXPECT_THAT(result->Edges(), ElementsAreArray(flats));
|
| 388 |
+
leaf = result;
|
| 389 |
+
}
|
| 390 |
+
CordRep::Unref(leaf);
|
| 391 |
+
}
|
| 392 |
+
|
| 393 |
+
TEST_P(CordRepBtreeTest, PrependToLeafToCapacity) {
|
| 394 |
+
AutoUnref refs;
|
| 395 |
+
std::deque<CordRep*> flats;
|
| 396 |
+
flats.push_front(MakeHexFlat(0));
|
| 397 |
+
auto* leaf = CordRepBtree::Create(flats.front());
|
| 398 |
+
|
| 399 |
+
for (size_t i = 1; i < CordRepBtree::kMaxCapacity; ++i) {
|
| 400 |
+
refs.RefIf(shared(), leaf);
|
| 401 |
+
flats.push_front(MakeHexFlat(i));
|
| 402 |
+
auto* result = CordRepBtree::Prepend(leaf, flats.front());
|
| 403 |
+
EXPECT_THAT(result->height(), Eq(0));
|
| 404 |
+
EXPECT_THAT(result, Conditional(shared(), Ne(leaf), Eq(leaf)));
|
| 405 |
+
EXPECT_THAT(result->Edges(), ElementsAreArray(flats));
|
| 406 |
+
leaf = result;
|
| 407 |
+
}
|
| 408 |
+
CordRep::Unref(leaf);
|
| 409 |
+
}
|
| 410 |
+
|
| 411 |
+
// This test specifically aims at code aligning data at either the front or the
|
| 412 |
+
// back of the contained `edges[]` array, alternating Append and Prepend will
|
| 413 |
+
// move `begin()` and `end()` values as needed for each added value.
|
| 414 |
+
TEST_P(CordRepBtreeTest, AppendPrependToLeafToCapacity) {
|
| 415 |
+
AutoUnref refs;
|
| 416 |
+
std::deque<CordRep*> flats;
|
| 417 |
+
flats.push_front(MakeHexFlat(0));
|
| 418 |
+
auto* leaf = CordRepBtree::Create(flats.front());
|
| 419 |
+
|
| 420 |
+
for (size_t i = 1; i < CordRepBtree::kMaxCapacity; ++i) {
|
| 421 |
+
refs.RefIf(shared(), leaf);
|
| 422 |
+
CordRepBtree* result;
|
| 423 |
+
if (i % 2 != 0) {
|
| 424 |
+
flats.push_front(MakeHexFlat(i));
|
| 425 |
+
result = CordRepBtree::Prepend(leaf, flats.front());
|
| 426 |
+
} else {
|
| 427 |
+
flats.push_back(MakeHexFlat(i));
|
| 428 |
+
result = CordRepBtree::Append(leaf, flats.back());
|
| 429 |
+
}
|
| 430 |
+
EXPECT_THAT(result->height(), Eq(0));
|
| 431 |
+
EXPECT_THAT(result, Conditional(shared(), Ne(leaf), Eq(leaf)));
|
| 432 |
+
EXPECT_THAT(result->Edges(), ElementsAreArray(flats));
|
| 433 |
+
leaf = result;
|
| 434 |
+
}
|
| 435 |
+
CordRep::Unref(leaf);
|
| 436 |
+
}
|
| 437 |
+
|
| 438 |
+
TEST_P(CordRepBtreeTest, AppendToLeafBeyondCapacity) {
|
| 439 |
+
AutoUnref refs;
|
| 440 |
+
auto* leaf = MakeLeaf();
|
| 441 |
+
refs.RefIf(shared(), leaf);
|
| 442 |
+
CordRep* flat = MakeFlat("abc");
|
| 443 |
+
auto* result = CordRepBtree::Append(leaf, flat);
|
| 444 |
+
ASSERT_THAT(result, IsNode(1));
|
| 445 |
+
EXPECT_THAT(result, Ne(leaf));
|
| 446 |
+
absl::Span<CordRep* const> edges = result->Edges();
|
| 447 |
+
ASSERT_THAT(edges, ElementsAre(leaf, IsNode(0)));
|
| 448 |
+
EXPECT_THAT(edges[1]->btree()->Edges(), ElementsAre(flat));
|
| 449 |
+
CordRep::Unref(result);
|
| 450 |
+
}
|
| 451 |
+
|
| 452 |
+
TEST_P(CordRepBtreeTest, PrependToLeafBeyondCapacity) {
|
| 453 |
+
AutoUnref refs;
|
| 454 |
+
auto* leaf = MakeLeaf();
|
| 455 |
+
refs.RefIf(shared(), leaf);
|
| 456 |
+
CordRep* flat = MakeFlat("abc");
|
| 457 |
+
auto* result = CordRepBtree::Prepend(leaf, flat);
|
| 458 |
+
ASSERT_THAT(result, IsNode(1));
|
| 459 |
+
EXPECT_THAT(result, Ne(leaf));
|
| 460 |
+
absl::Span<CordRep* const> edges = result->Edges();
|
| 461 |
+
ASSERT_THAT(edges, ElementsAre(IsNode(0), leaf));
|
| 462 |
+
EXPECT_THAT(edges[0]->btree()->Edges(), ElementsAre(flat));
|
| 463 |
+
CordRep::Unref(result);
|
| 464 |
+
}
|
| 465 |
+
|
| 466 |
+
TEST_P(CordRepBtreeTest, AppendToTreeOneDeep) {
|
| 467 |
+
constexpr size_t max_cap = CordRepBtree::kMaxCapacity;
|
| 468 |
+
AutoUnref refs;
|
| 469 |
+
std::vector<CordRep*> flats;
|
| 470 |
+
flats.push_back(MakeHexFlat(0));
|
| 471 |
+
CordRepBtree* tree = CordRepBtree::Create(flats.back());
|
| 472 |
+
for (size_t i = 1; i <= max_cap; ++i) {
|
| 473 |
+
flats.push_back(MakeHexFlat(i));
|
| 474 |
+
tree = CordRepBtree::Append(tree, flats.back());
|
| 475 |
+
}
|
| 476 |
+
ASSERT_THAT(tree, IsNode(1));
|
| 477 |
+
|
| 478 |
+
for (size_t i = max_cap + 1; i < max_cap * max_cap; ++i) {
|
| 479 |
+
// Ref top level tree based on param.
|
| 480 |
+
// Ref leaf node once every 4 iterations, which should not have an
|
| 481 |
+
// observable effect other than that the leaf itself is copied.
|
| 482 |
+
refs.RefIf(shared(), tree);
|
| 483 |
+
refs.RefIf(i % 4 == 0, tree->Edges().back());
|
| 484 |
+
|
| 485 |
+
flats.push_back(MakeHexFlat(i));
|
| 486 |
+
CordRepBtree* result = CordRepBtree::Append(tree, flats.back());
|
| 487 |
+
ASSERT_THAT(result, IsNode(1));
|
| 488 |
+
ASSERT_THAT(result, Conditional(shared(), Ne(tree), Eq(tree)));
|
| 489 |
+
std::vector<CordRep*> edges = GetLeafEdges(result);
|
| 490 |
+
ASSERT_THAT(edges, ElementsAreArray(flats));
|
| 491 |
+
tree = result;
|
| 492 |
+
}
|
| 493 |
+
CordRep::Unref(tree);
|
| 494 |
+
}
|
| 495 |
+
|
| 496 |
+
TEST_P(CordRepBtreeTest, AppendToTreeTwoDeep) {
|
| 497 |
+
constexpr size_t max_cap = CordRepBtree::kMaxCapacity;
|
| 498 |
+
AutoUnref refs;
|
| 499 |
+
std::vector<CordRep*> flats;
|
| 500 |
+
flats.push_back(MakeHexFlat(0));
|
| 501 |
+
CordRepBtree* tree = CordRepBtree::Create(flats.back());
|
| 502 |
+
for (size_t i = 1; i <= max_cap * max_cap; ++i) {
|
| 503 |
+
flats.push_back(MakeHexFlat(i));
|
| 504 |
+
tree = CordRepBtree::Append(tree, flats.back());
|
| 505 |
+
}
|
| 506 |
+
ASSERT_THAT(tree, IsNode(2));
|
| 507 |
+
for (size_t i = max_cap * max_cap + 1; i < max_cap * max_cap * max_cap; ++i) {
|
| 508 |
+
// Ref top level tree based on param.
|
| 509 |
+
// Ref child node once every 16 iterations, and leaf node every 4
|
| 510 |
+
// iterations which which should not have an observable effect other than
|
| 511 |
+
// the node and/or the leaf below it being copied.
|
| 512 |
+
refs.RefIf(shared(), tree);
|
| 513 |
+
refs.RefIf(i % 16 == 0, tree->Edges().back());
|
| 514 |
+
refs.RefIf(i % 4 == 0, tree->Edges().back()->btree()->Edges().back());
|
| 515 |
+
|
| 516 |
+
flats.push_back(MakeHexFlat(i));
|
| 517 |
+
CordRepBtree* result = CordRepBtree::Append(tree, flats.back());
|
| 518 |
+
ASSERT_THAT(result, IsNode(2));
|
| 519 |
+
ASSERT_THAT(result, Conditional(shared(), Ne(tree), Eq(tree)));
|
| 520 |
+
std::vector<CordRep*> edges = GetLeafEdges(result);
|
| 521 |
+
ASSERT_THAT(edges, ElementsAreArray(flats));
|
| 522 |
+
tree = result;
|
| 523 |
+
}
|
| 524 |
+
CordRep::Unref(tree);
|
| 525 |
+
}
|
| 526 |
+
|
| 527 |
+
TEST_P(CordRepBtreeTest, PrependToTreeOneDeep) {
|
| 528 |
+
constexpr size_t max_cap = CordRepBtree::kMaxCapacity;
|
| 529 |
+
AutoUnref refs;
|
| 530 |
+
std::deque<CordRep*> flats;
|
| 531 |
+
flats.push_back(MakeHexFlat(0));
|
| 532 |
+
CordRepBtree* tree = CordRepBtree::Create(flats.back());
|
| 533 |
+
for (size_t i = 1; i <= max_cap; ++i) {
|
| 534 |
+
flats.push_front(MakeHexFlat(i));
|
| 535 |
+
tree = CordRepBtree::Prepend(tree, flats.front());
|
| 536 |
+
}
|
| 537 |
+
ASSERT_THAT(tree, IsNode(1));
|
| 538 |
+
|
| 539 |
+
for (size_t i = max_cap + 1; i < max_cap * max_cap; ++i) {
|
| 540 |
+
// Ref top level tree based on param.
|
| 541 |
+
// Ref leaf node once every 4 iterations which should not have an observable
|
| 542 |
+
// effect other than than the leaf itself is copied.
|
| 543 |
+
refs.RefIf(shared(), tree);
|
| 544 |
+
refs.RefIf(i % 4 == 0, tree->Edges().back());
|
| 545 |
+
|
| 546 |
+
flats.push_front(MakeHexFlat(i));
|
| 547 |
+
CordRepBtree* result = CordRepBtree::Prepend(tree, flats.front());
|
| 548 |
+
ASSERT_THAT(result, IsNode(1));
|
| 549 |
+
ASSERT_THAT(result, Conditional(shared(), Ne(tree), Eq(tree)));
|
| 550 |
+
std::vector<CordRep*> edges = GetLeafEdges(result);
|
| 551 |
+
ASSERT_THAT(edges, ElementsAreArray(flats));
|
| 552 |
+
tree = result;
|
| 553 |
+
}
|
| 554 |
+
CordRep::Unref(tree);
|
| 555 |
+
}
|
| 556 |
+
|
| 557 |
+
TEST_P(CordRepBtreeTest, PrependToTreeTwoDeep) {
|
| 558 |
+
constexpr size_t max_cap = CordRepBtree::kMaxCapacity;
|
| 559 |
+
AutoUnref refs;
|
| 560 |
+
std::deque<CordRep*> flats;
|
| 561 |
+
flats.push_back(MakeHexFlat(0));
|
| 562 |
+
CordRepBtree* tree = CordRepBtree::Create(flats.back());
|
| 563 |
+
for (size_t i = 1; i <= max_cap * max_cap; ++i) {
|
| 564 |
+
flats.push_front(MakeHexFlat(i));
|
| 565 |
+
tree = CordRepBtree::Prepend(tree, flats.front());
|
| 566 |
+
}
|
| 567 |
+
ASSERT_THAT(tree, IsNode(2));
|
| 568 |
+
for (size_t i = max_cap * max_cap + 1; i < max_cap * max_cap * max_cap; ++i) {
|
| 569 |
+
// Ref top level tree based on param.
|
| 570 |
+
// Ref child node once every 16 iterations, and leaf node every 4
|
| 571 |
+
// iterations which which should not have an observable effect other than
|
| 572 |
+
// the node and/or the leaf below it being copied.
|
| 573 |
+
refs.RefIf(shared(), tree);
|
| 574 |
+
refs.RefIf(i % 16 == 0, tree->Edges().back());
|
| 575 |
+
refs.RefIf(i % 4 == 0, tree->Edges().back()->btree()->Edges().back());
|
| 576 |
+
|
| 577 |
+
flats.push_front(MakeHexFlat(i));
|
| 578 |
+
CordRepBtree* result = CordRepBtree::Prepend(tree, flats.front());
|
| 579 |
+
ASSERT_THAT(result, IsNode(2));
|
| 580 |
+
ASSERT_THAT(result, Conditional(shared(), Ne(tree), Eq(tree)));
|
| 581 |
+
std::vector<CordRep*> edges = GetLeafEdges(result);
|
| 582 |
+
ASSERT_THAT(edges, ElementsAreArray(flats));
|
| 583 |
+
tree = result;
|
| 584 |
+
}
|
| 585 |
+
CordRep::Unref(tree);
|
| 586 |
+
}
|
| 587 |
+
|
| 588 |
+
TEST_P(CordRepBtreeDualTest, MergeLeafsNotExceedingCapacity) {
|
| 589 |
+
for (bool use_append : {false, true}) {
|
| 590 |
+
SCOPED_TRACE(use_append ? "Using Append" : "Using Prepend");
|
| 591 |
+
|
| 592 |
+
AutoUnref refs;
|
| 593 |
+
std::vector<CordRep*> flats;
|
| 594 |
+
|
| 595 |
+
// Build `left` side leaf appending all contained flats to `flats`
|
| 596 |
+
CordRepBtree* left = MakeLeaf(3);
|
| 597 |
+
GetLeafEdges(left, flats);
|
| 598 |
+
refs.RefIf(first_shared(), left);
|
| 599 |
+
|
| 600 |
+
// Build `right` side leaf appending all contained flats to `flats`
|
| 601 |
+
CordRepBtree* right = MakeLeaf(2);
|
| 602 |
+
GetLeafEdges(right, flats);
|
| 603 |
+
refs.RefIf(second_shared(), right);
|
| 604 |
+
|
| 605 |
+
CordRepBtree* tree = use_append ? CordRepBtree::Append(left, right)
|
| 606 |
+
: CordRepBtree::Prepend(right, left);
|
| 607 |
+
EXPECT_THAT(tree, IsNode(0));
|
| 608 |
+
|
| 609 |
+
// `tree` contains all flats originally belonging to `left` and `right`.
|
| 610 |
+
EXPECT_THAT(tree->Edges(), ElementsAreArray(flats));
|
| 611 |
+
CordRepBtree::Unref(tree);
|
| 612 |
+
}
|
| 613 |
+
}
|
| 614 |
+
|
| 615 |
+
TEST_P(CordRepBtreeDualTest, MergeLeafsExceedingCapacity) {
|
| 616 |
+
for (bool use_append : {false, true}) {
|
| 617 |
+
SCOPED_TRACE(use_append ? "Using Append" : "Using Prepend");
|
| 618 |
+
|
| 619 |
+
AutoUnref refs;
|
| 620 |
+
|
| 621 |
+
// Build `left` side tree appending all contained flats to `flats`
|
| 622 |
+
CordRepBtree* left = MakeLeaf(CordRepBtree::kMaxCapacity - 2);
|
| 623 |
+
refs.RefIf(first_shared(), left);
|
| 624 |
+
|
| 625 |
+
// Build `right` side tree appending all contained flats to `flats`
|
| 626 |
+
CordRepBtree* right = MakeLeaf(CordRepBtree::kMaxCapacity - 1);
|
| 627 |
+
refs.RefIf(second_shared(), right);
|
| 628 |
+
|
| 629 |
+
CordRepBtree* tree = use_append ? CordRepBtree::Append(left, right)
|
| 630 |
+
: CordRepBtree::Prepend(right, left);
|
| 631 |
+
EXPECT_THAT(tree, IsNode(1));
|
| 632 |
+
EXPECT_THAT(tree->Edges(), ElementsAre(left, right));
|
| 633 |
+
CordRepBtree::Unref(tree);
|
| 634 |
+
}
|
| 635 |
+
}
|
| 636 |
+
|
| 637 |
+
TEST_P(CordRepBtreeDualTest, MergeEqualHeightTrees) {
|
| 638 |
+
for (bool use_append : {false, true}) {
|
| 639 |
+
SCOPED_TRACE(use_append ? "Using Append" : "Using Prepend");
|
| 640 |
+
|
| 641 |
+
AutoUnref refs;
|
| 642 |
+
std::vector<CordRep*> flats;
|
| 643 |
+
|
| 644 |
+
// Build `left` side tree appending all contained flats to `flats`
|
| 645 |
+
CordRepBtree* left = MakeTree(CordRepBtree::kMaxCapacity * 3);
|
| 646 |
+
GetLeafEdges(left, flats);
|
| 647 |
+
refs.RefIf(first_shared(), left);
|
| 648 |
+
|
| 649 |
+
// Build `right` side tree appending all contained flats to `flats`
|
| 650 |
+
CordRepBtree* right = MakeTree(CordRepBtree::kMaxCapacity * 2);
|
| 651 |
+
GetLeafEdges(right, flats);
|
| 652 |
+
refs.RefIf(second_shared(), right);
|
| 653 |
+
|
| 654 |
+
CordRepBtree* tree = use_append ? CordRepBtree::Append(left, right)
|
| 655 |
+
: CordRepBtree::Prepend(right, left);
|
| 656 |
+
EXPECT_THAT(tree, IsNode(1));
|
| 657 |
+
EXPECT_THAT(tree->Edges(), SizeIs(5u));
|
| 658 |
+
|
| 659 |
+
// `tree` contains all flats originally belonging to `left` and `right`.
|
| 660 |
+
EXPECT_THAT(GetLeafEdges(tree), ElementsAreArray(flats));
|
| 661 |
+
CordRepBtree::Unref(tree);
|
| 662 |
+
}
|
| 663 |
+
}
|
| 664 |
+
|
| 665 |
+
TEST_P(CordRepBtreeDualTest, MergeLeafWithTreeNotExceedingLeafCapacity) {
|
| 666 |
+
for (bool use_append : {false, true}) {
|
| 667 |
+
SCOPED_TRACE(use_append ? "Using Append" : "Using Prepend");
|
| 668 |
+
|
| 669 |
+
AutoUnref refs;
|
| 670 |
+
std::vector<CordRep*> flats;
|
| 671 |
+
|
| 672 |
+
// Build `left` side tree appending all added flats to `flats`
|
| 673 |
+
CordRepBtree* left = MakeTree(CordRepBtree::kMaxCapacity * 2 + 2);
|
| 674 |
+
GetLeafEdges(left, flats);
|
| 675 |
+
refs.RefIf(first_shared(), left);
|
| 676 |
+
|
| 677 |
+
// Build `right` side tree appending all added flats to `flats`
|
| 678 |
+
CordRepBtree* right = MakeTree(3);
|
| 679 |
+
GetLeafEdges(right, flats);
|
| 680 |
+
refs.RefIf(second_shared(), right);
|
| 681 |
+
|
| 682 |
+
CordRepBtree* tree = use_append ? CordRepBtree::Append(left, right)
|
| 683 |
+
: CordRepBtree::Prepend(right, left);
|
| 684 |
+
EXPECT_THAT(tree, IsNode(1));
|
| 685 |
+
EXPECT_THAT(tree->Edges(), SizeIs(3u));
|
| 686 |
+
|
| 687 |
+
// `tree` contains all flats originally belonging to `left` and `right`.
|
| 688 |
+
EXPECT_THAT(GetLeafEdges(tree), ElementsAreArray(flats));
|
| 689 |
+
CordRepBtree::Unref(tree);
|
| 690 |
+
}
|
| 691 |
+
}
|
| 692 |
+
|
| 693 |
+
TEST_P(CordRepBtreeDualTest, MergeLeafWithTreeExceedingLeafCapacity) {
|
| 694 |
+
for (bool use_append : {false, true}) {
|
| 695 |
+
SCOPED_TRACE(use_append ? "Using Append" : "Using Prepend");
|
| 696 |
+
|
| 697 |
+
AutoUnref refs;
|
| 698 |
+
std::vector<CordRep*> flats;
|
| 699 |
+
|
| 700 |
+
// Build `left` side tree appending all added flats to `flats`
|
| 701 |
+
CordRepBtree* left = MakeTree(CordRepBtree::kMaxCapacity * 3 - 2);
|
| 702 |
+
GetLeafEdges(left, flats);
|
| 703 |
+
refs.RefIf(first_shared(), left);
|
| 704 |
+
|
| 705 |
+
// Build `right` side tree appending all added flats to `flats`
|
| 706 |
+
CordRepBtree* right = MakeTree(3);
|
| 707 |
+
GetLeafEdges(right, flats);
|
| 708 |
+
refs.RefIf(second_shared(), right);
|
| 709 |
+
|
| 710 |
+
CordRepBtree* tree = use_append ? CordRepBtree::Append(left, right)
|
| 711 |
+
: CordRepBtree::Prepend(right, left);
|
| 712 |
+
EXPECT_THAT(tree, IsNode(1));
|
| 713 |
+
EXPECT_THAT(tree->Edges(), SizeIs(4u));
|
| 714 |
+
|
| 715 |
+
// `tree` contains all flats originally belonging to `left` and `right`.
|
| 716 |
+
EXPECT_THAT(GetLeafEdges(tree), ElementsAreArray(flats));
|
| 717 |
+
CordRepBtree::Unref(tree);
|
| 718 |
+
}
|
| 719 |
+
}
|
| 720 |
+
|
| 721 |
+
void RefEdgesAt(size_t depth, AutoUnref& refs, CordRepBtree* tree) {
|
| 722 |
+
absl::Span<CordRep* const> edges = tree->Edges();
|
| 723 |
+
if (depth == 0) {
|
| 724 |
+
refs.Ref(edges.front());
|
| 725 |
+
refs.Ref(edges.back());
|
| 726 |
+
} else {
|
| 727 |
+
assert(tree->height() > 0);
|
| 728 |
+
RefEdgesAt(depth - 1, refs, edges.front()->btree());
|
| 729 |
+
RefEdgesAt(depth - 1, refs, edges.back()->btree());
|
| 730 |
+
}
|
| 731 |
+
}
|
| 732 |
+
|
| 733 |
+
TEST(CordRepBtreeTest, MergeFuzzTest) {
|
| 734 |
+
constexpr size_t max_cap = CordRepBtree::kMaxCapacity;
|
| 735 |
+
std::minstd_rand rnd;
|
| 736 |
+
std::uniform_int_distribution<int> coin_flip(0, 1);
|
| 737 |
+
std::uniform_int_distribution<int> dice_throw(1, 6);
|
| 738 |
+
|
| 739 |
+
auto random_leaf_count = [&]() {
|
| 740 |
+
std::uniform_int_distribution<int> dist_height(0, 3);
|
| 741 |
+
std::uniform_int_distribution<int> dist_leaf(0, max_cap - 1);
|
| 742 |
+
const int height = dist_height(rnd);
|
| 743 |
+
return (height ? pow(max_cap, height) : 0) + dist_leaf(rnd);
|
| 744 |
+
};
|
| 745 |
+
|
| 746 |
+
for (int i = 0; i < 10000; ++i) {
|
| 747 |
+
AutoUnref refs;
|
| 748 |
+
std::vector<CordRep*> flats;
|
| 749 |
+
|
| 750 |
+
CordRepBtree* left = MakeTree(random_leaf_count(), coin_flip(rnd));
|
| 751 |
+
GetLeafEdges(left, flats);
|
| 752 |
+
if (dice_throw(rnd) == 1) {
|
| 753 |
+
std::uniform_int_distribution<size_t> dist(
|
| 754 |
+
0, static_cast<size_t>(left->height()));
|
| 755 |
+
RefEdgesAt(dist(rnd), refs, left);
|
| 756 |
+
}
|
| 757 |
+
|
| 758 |
+
CordRepBtree* right = MakeTree(random_leaf_count(), coin_flip(rnd));
|
| 759 |
+
GetLeafEdges(right, flats);
|
| 760 |
+
if (dice_throw(rnd) == 1) {
|
| 761 |
+
std::uniform_int_distribution<size_t> dist(
|
| 762 |
+
0, static_cast<size_t>(right->height()));
|
| 763 |
+
RefEdgesAt(dist(rnd), refs, right);
|
| 764 |
+
}
|
| 765 |
+
|
| 766 |
+
CordRepBtree* tree = CordRepBtree::Append(left, right);
|
| 767 |
+
EXPECT_THAT(GetLeafEdges(tree), ElementsAreArray(flats));
|
| 768 |
+
CordRepBtree::Unref(tree);
|
| 769 |
+
}
|
| 770 |
+
}
|
| 771 |
+
|
| 772 |
+
TEST_P(CordRepBtreeTest, RemoveSuffix) {
|
| 773 |
+
// Create tree of 1, 2 and 3 levels high
|
| 774 |
+
constexpr size_t max_cap = CordRepBtree::kMaxCapacity;
|
| 775 |
+
for (size_t cap : {max_cap - 1, max_cap * 2, max_cap * max_cap * 2}) {
|
| 776 |
+
const std::string data = CreateRandomString(cap * 512);
|
| 777 |
+
|
| 778 |
+
{
|
| 779 |
+
// Verify RemoveSuffix(<all>)
|
| 780 |
+
AutoUnref refs;
|
| 781 |
+
CordRepBtree* node = refs.RefIf(shared(), CreateTree(data, 512));
|
| 782 |
+
EXPECT_THAT(CordRepBtree::RemoveSuffix(node, data.length()), Eq(nullptr));
|
| 783 |
+
|
| 784 |
+
// Verify RemoveSuffix(<none>)
|
| 785 |
+
node = refs.RefIf(shared(), CreateTree(data, 512));
|
| 786 |
+
EXPECT_THAT(CordRepBtree::RemoveSuffix(node, 0), Eq(node));
|
| 787 |
+
CordRep::Unref(node);
|
| 788 |
+
}
|
| 789 |
+
|
| 790 |
+
for (size_t n = 1; n < data.length(); ++n) {
|
| 791 |
+
AutoUnref refs;
|
| 792 |
+
auto flats = CreateFlatsFromString(data, 512);
|
| 793 |
+
CordRepBtree* node = refs.RefIf(shared(), CreateTree(flats));
|
| 794 |
+
CordRep* rep = refs.Add(CordRepBtree::RemoveSuffix(node, n));
|
| 795 |
+
EXPECT_THAT(CordToString(rep), Eq(data.substr(0, data.length() - n)));
|
| 796 |
+
|
| 797 |
+
// Collect all flats
|
| 798 |
+
auto is_flat = [](CordRep* rep) { return rep->tag >= FLAT; };
|
| 799 |
+
std::vector<CordRep*> edges = CordCollectRepsIf(is_flat, rep);
|
| 800 |
+
ASSERT_THAT(edges.size(), Le(flats.size()));
|
| 801 |
+
|
| 802 |
+
// Isolate last edge
|
| 803 |
+
CordRep* last_edge = edges.back();
|
| 804 |
+
edges.pop_back();
|
| 805 |
+
const size_t last_length = rep->length - edges.size() * 512;
|
| 806 |
+
|
| 807 |
+
// All flats except the last edge must be kept or copied 'as is'
|
| 808 |
+
size_t index = 0;
|
| 809 |
+
for (CordRep* edge : edges) {
|
| 810 |
+
ASSERT_THAT(edge, Eq(flats[index++]));
|
| 811 |
+
ASSERT_THAT(edge->length, Eq(512u));
|
| 812 |
+
}
|
| 813 |
+
|
| 814 |
+
// CordRepBtree may optimize small substrings to avoid waste, so only
|
| 815 |
+
// check for flat sharing / updates where the code should always do this.
|
| 816 |
+
if (last_length >= 500) {
|
| 817 |
+
EXPECT_THAT(last_edge, Eq(flats[index++]));
|
| 818 |
+
if (shared()) {
|
| 819 |
+
EXPECT_THAT(last_edge->length, Eq(512u));
|
| 820 |
+
} else {
|
| 821 |
+
EXPECT_TRUE(last_edge->refcount.IsOne());
|
| 822 |
+
EXPECT_THAT(last_edge->length, Eq(last_length));
|
| 823 |
+
}
|
| 824 |
+
}
|
| 825 |
+
}
|
| 826 |
+
}
|
| 827 |
+
}
|
| 828 |
+
|
| 829 |
+
TEST(CordRepBtreeTest, SubTree) {
|
| 830 |
+
// Create tree of at least 2 levels high
|
| 831 |
+
constexpr size_t max_cap = CordRepBtree::kMaxCapacity;
|
| 832 |
+
const size_t n = max_cap * max_cap * 2;
|
| 833 |
+
const std::string data = CreateRandomString(n * 3);
|
| 834 |
+
std::vector<CordRep*> flats;
|
| 835 |
+
for (absl::string_view s = data; !s.empty(); s.remove_prefix(3)) {
|
| 836 |
+
flats.push_back(MakeFlat(s.substr(0, 3)));
|
| 837 |
+
}
|
| 838 |
+
CordRepBtree* node = CordRepBtree::Create(CordRep::Ref(flats[0]));
|
| 839 |
+
for (size_t i = 1; i < flats.size(); ++i) {
|
| 840 |
+
node = CordRepBtree::Append(node, CordRep::Ref(flats[i]));
|
| 841 |
+
}
|
| 842 |
+
|
| 843 |
+
for (size_t offset = 0; offset < data.length(); ++offset) {
|
| 844 |
+
for (size_t length = 1; length <= data.length() - offset; ++length) {
|
| 845 |
+
CordRep* rep = node->SubTree(offset, length);
|
| 846 |
+
EXPECT_THAT(CordToString(rep), Eq(data.substr(offset, length)));
|
| 847 |
+
CordRep::Unref(rep);
|
| 848 |
+
}
|
| 849 |
+
}
|
| 850 |
+
CordRepBtree::Unref(node);
|
| 851 |
+
for (CordRep* rep : flats) {
|
| 852 |
+
CordRep::Unref(rep);
|
| 853 |
+
}
|
| 854 |
+
}
|
| 855 |
+
|
| 856 |
+
TEST(CordRepBtreeTest, SubTreeOnExistingSubstring) {
|
| 857 |
+
// This test verifies that a SubTree call on a pre-existing (large) substring
|
| 858 |
+
// adjusts the existing substring if not shared, and else rewrites the
|
| 859 |
+
// existing substring.
|
| 860 |
+
AutoUnref refs;
|
| 861 |
+
std::string data = CreateRandomString(1000);
|
| 862 |
+
CordRepBtree* leaf = CordRepBtree::Create(MakeFlat("abc"));
|
| 863 |
+
CordRep* flat = MakeFlat(data);
|
| 864 |
+
leaf = CordRepBtree::Append(leaf, flat);
|
| 865 |
+
|
| 866 |
+
// Setup tree containing substring.
|
| 867 |
+
CordRep* result = leaf->SubTree(0, 3 + 990);
|
| 868 |
+
ASSERT_THAT(result->tag, Eq(BTREE));
|
| 869 |
+
CordRep::Unref(leaf);
|
| 870 |
+
leaf = result->btree();
|
| 871 |
+
ASSERT_THAT(leaf->Edges(), ElementsAre(_, IsSubstring(0u, 990u)));
|
| 872 |
+
EXPECT_THAT(leaf->Edges()[1]->substring()->child, Eq(flat));
|
| 873 |
+
|
| 874 |
+
// Verify substring of substring.
|
| 875 |
+
result = leaf->SubTree(3 + 5, 970);
|
| 876 |
+
ASSERT_THAT(result, IsSubstring(5u, 970u));
|
| 877 |
+
EXPECT_THAT(result->substring()->child, Eq(flat));
|
| 878 |
+
CordRep::Unref(result);
|
| 879 |
+
|
| 880 |
+
CordRep::Unref(leaf);
|
| 881 |
+
}
|
| 882 |
+
|
| 883 |
+
TEST_P(CordRepBtreeTest, AddDataToLeaf) {
|
| 884 |
+
const size_t n = CordRepBtree::kMaxCapacity;
|
| 885 |
+
const std::string data = CreateRandomString(n * 3);
|
| 886 |
+
|
| 887 |
+
for (bool append : {true, false}) {
|
| 888 |
+
AutoUnref refs;
|
| 889 |
+
DataConsumer consumer(data, append);
|
| 890 |
+
SCOPED_TRACE(append ? "Append" : "Prepend");
|
| 891 |
+
|
| 892 |
+
CordRepBtree* leaf = CordRepBtree::Create(MakeFlat(consumer.Next(3)));
|
| 893 |
+
for (size_t i = 1; i < n; ++i) {
|
| 894 |
+
refs.RefIf(shared(), leaf);
|
| 895 |
+
CordRepBtree* result = BtreeAdd(leaf, append, consumer.Next(3));
|
| 896 |
+
EXPECT_THAT(result, Conditional(shared(), Ne(leaf), Eq(leaf)));
|
| 897 |
+
EXPECT_THAT(CordToString(result), Eq(consumer.Consumed()));
|
| 898 |
+
leaf = result;
|
| 899 |
+
}
|
| 900 |
+
CordRep::Unref(leaf);
|
| 901 |
+
}
|
| 902 |
+
}
|
| 903 |
+
|
| 904 |
+
TEST_P(CordRepBtreeTest, AppendDataToTree) {
|
| 905 |
+
AutoUnref refs;
|
| 906 |
+
size_t n = CordRepBtree::kMaxCapacity + CordRepBtree::kMaxCapacity / 2;
|
| 907 |
+
std::string data = CreateRandomString(n * 3);
|
| 908 |
+
CordRepBtree* tree = refs.RefIf(shared(), CreateTree(data, 3));
|
| 909 |
+
CordRepBtree* leaf0 = tree->Edges()[0]->btree();
|
| 910 |
+
CordRepBtree* leaf1 = tree->Edges()[1]->btree();
|
| 911 |
+
CordRepBtree* result = CordRepBtree::Append(tree, "123456789");
|
| 912 |
+
EXPECT_THAT(result, Conditional(shared(), Ne(tree), Eq(tree)));
|
| 913 |
+
EXPECT_THAT(result->Edges(),
|
| 914 |
+
ElementsAre(leaf0, Conditional(shared(), Ne(leaf1), Eq(leaf1))));
|
| 915 |
+
EXPECT_THAT(CordToString(result), Eq(data + "123456789"));
|
| 916 |
+
CordRep::Unref(result);
|
| 917 |
+
}
|
| 918 |
+
|
| 919 |
+
TEST_P(CordRepBtreeTest, PrependDataToTree) {
|
| 920 |
+
AutoUnref refs;
|
| 921 |
+
size_t n = CordRepBtree::kMaxCapacity + CordRepBtree::kMaxCapacity / 2;
|
| 922 |
+
std::string data = CreateRandomString(n * 3);
|
| 923 |
+
CordRepBtree* tree = refs.RefIf(shared(), CreateTreeReverse(data, 3));
|
| 924 |
+
CordRepBtree* leaf0 = tree->Edges()[0]->btree();
|
| 925 |
+
CordRepBtree* leaf1 = tree->Edges()[1]->btree();
|
| 926 |
+
CordRepBtree* result = CordRepBtree::Prepend(tree, "123456789");
|
| 927 |
+
EXPECT_THAT(result, Conditional(shared(), Ne(tree), Eq(tree)));
|
| 928 |
+
EXPECT_THAT(result->Edges(),
|
| 929 |
+
ElementsAre(Conditional(shared(), Ne(leaf0), Eq(leaf0)), leaf1));
|
| 930 |
+
EXPECT_THAT(CordToString(result), Eq("123456789" + data));
|
| 931 |
+
CordRep::Unref(result);
|
| 932 |
+
}
|
| 933 |
+
|
| 934 |
+
TEST_P(CordRepBtreeTest, AddDataToTreeThreeLevelsDeep) {
|
| 935 |
+
constexpr size_t max_cap = CordRepBtree::kMaxCapacity;
|
| 936 |
+
const size_t n = max_cap * max_cap * max_cap;
|
| 937 |
+
const std::string data = CreateRandomString(n * 3);
|
| 938 |
+
|
| 939 |
+
for (bool append : {true, false}) {
|
| 940 |
+
AutoUnref refs;
|
| 941 |
+
DataConsumer consumer(data, append);
|
| 942 |
+
SCOPED_TRACE(append ? "Append" : "Prepend");
|
| 943 |
+
|
| 944 |
+
// Fill leaf
|
| 945 |
+
CordRepBtree* tree = CordRepBtree::Create(MakeFlat(consumer.Next(3)));
|
| 946 |
+
for (size_t i = 1; i < max_cap; ++i) {
|
| 947 |
+
tree = BtreeAdd(tree, append, consumer.Next(3));
|
| 948 |
+
}
|
| 949 |
+
ASSERT_THAT(CordToString(tree), Eq(consumer.Consumed()));
|
| 950 |
+
|
| 951 |
+
// Fill to maximum at one deep
|
| 952 |
+
refs.RefIf(shared(), tree);
|
| 953 |
+
CordRepBtree* result = BtreeAdd(tree, append, consumer.Next(3));
|
| 954 |
+
ASSERT_THAT(result, IsNode(1));
|
| 955 |
+
ASSERT_THAT(result, Ne(tree));
|
| 956 |
+
ASSERT_THAT(CordToString(result), Eq(consumer.Consumed()));
|
| 957 |
+
tree = result;
|
| 958 |
+
for (size_t i = max_cap + 1; i < max_cap * max_cap; ++i) {
|
| 959 |
+
refs.RefIf(shared(), tree);
|
| 960 |
+
result = BtreeAdd(tree, append, consumer.Next(3));
|
| 961 |
+
ASSERT_THAT(result, Conditional(shared(), Ne(tree), Eq(tree)));
|
| 962 |
+
ASSERT_THAT(CordToString(result), Eq(consumer.Consumed()));
|
| 963 |
+
tree = result;
|
| 964 |
+
}
|
| 965 |
+
|
| 966 |
+
// Fill to maximum at two deep
|
| 967 |
+
refs.RefIf(shared(), tree);
|
| 968 |
+
result = BtreeAdd(tree, append, consumer.Next(3));
|
| 969 |
+
ASSERT_THAT(result, IsNode(2));
|
| 970 |
+
ASSERT_THAT(result, Ne(tree));
|
| 971 |
+
ASSERT_THAT(CordToString(result), Eq(consumer.Consumed()));
|
| 972 |
+
tree = result;
|
| 973 |
+
for (size_t i = max_cap * max_cap + 1; i < max_cap * max_cap * max_cap;
|
| 974 |
+
++i) {
|
| 975 |
+
refs.RefIf(shared(), tree);
|
| 976 |
+
result = BtreeAdd(tree, append, consumer.Next(3));
|
| 977 |
+
ASSERT_THAT(result, Conditional(shared(), Ne(tree), Eq(tree)));
|
| 978 |
+
ASSERT_THAT(CordToString(result), Eq(consumer.Consumed()));
|
| 979 |
+
tree = result;
|
| 980 |
+
}
|
| 981 |
+
|
| 982 |
+
CordRep::Unref(tree);
|
| 983 |
+
}
|
| 984 |
+
}
|
| 985 |
+
|
| 986 |
+
TEST_P(CordRepBtreeTest, AddLargeDataToLeaf) {
|
| 987 |
+
const size_t max_cap = CordRepBtree::kMaxCapacity;
|
| 988 |
+
const size_t n = max_cap * max_cap * max_cap * 3 + 2;
|
| 989 |
+
const std::string data = CreateRandomString(n * kMaxFlatLength);
|
| 990 |
+
|
| 991 |
+
for (bool append : {true, false}) {
|
| 992 |
+
AutoUnref refs;
|
| 993 |
+
SCOPED_TRACE(append ? "Append" : "Prepend");
|
| 994 |
+
|
| 995 |
+
CordRepBtree* leaf = CordRepBtree::Create(MakeFlat("abc"));
|
| 996 |
+
refs.RefIf(shared(), leaf);
|
| 997 |
+
CordRepBtree* result = BtreeAdd(leaf, append, data);
|
| 998 |
+
EXPECT_THAT(CordToString(result), Eq(append ? "abc" + data : data + "abc"));
|
| 999 |
+
CordRep::Unref(result);
|
| 1000 |
+
}
|
| 1001 |
+
}
|
| 1002 |
+
|
| 1003 |
+
TEST_P(CordRepBtreeTest, CreateFromTreeReturnsTree) {
|
| 1004 |
+
AutoUnref refs;
|
| 1005 |
+
CordRepBtree* leaf = CordRepBtree::Create(MakeFlat("Hello world"));
|
| 1006 |
+
refs.RefIf(shared(), leaf);
|
| 1007 |
+
CordRepBtree* result = CordRepBtree::Create(leaf);
|
| 1008 |
+
EXPECT_THAT(result, Eq(leaf));
|
| 1009 |
+
CordRep::Unref(result);
|
| 1010 |
+
}
|
| 1011 |
+
|
| 1012 |
+
TEST(CordRepBtreeTest, GetCharacter) {
|
| 1013 |
+
size_t n = CordRepBtree::kMaxCapacity * CordRepBtree::kMaxCapacity + 2;
|
| 1014 |
+
std::string data = CreateRandomString(n * 3);
|
| 1015 |
+
CordRepBtree* tree = CreateTree(data, 3);
|
| 1016 |
+
// Add a substring node for good measure.
|
| 1017 |
+
tree = tree->Append(tree, MakeSubstring(4, 5, MakeFlat("abcdefghijklm")));
|
| 1018 |
+
data += "efghi";
|
| 1019 |
+
for (size_t i = 0; i < data.length(); ++i) {
|
| 1020 |
+
ASSERT_THAT(tree->GetCharacter(i), Eq(data[i]));
|
| 1021 |
+
}
|
| 1022 |
+
CordRep::Unref(tree);
|
| 1023 |
+
}
|
| 1024 |
+
|
| 1025 |
+
TEST_P(CordRepBtreeTest, IsFlatSingleFlat) {
|
| 1026 |
+
CordRepBtree* leaf = CordRepBtree::Create(MakeFlat("Hello world"));
|
| 1027 |
+
|
| 1028 |
+
absl::string_view fragment;
|
| 1029 |
+
EXPECT_TRUE(leaf->IsFlat(nullptr));
|
| 1030 |
+
EXPECT_TRUE(leaf->IsFlat(&fragment));
|
| 1031 |
+
EXPECT_THAT(fragment, Eq("Hello world"));
|
| 1032 |
+
fragment = "";
|
| 1033 |
+
EXPECT_TRUE(leaf->IsFlat(0, 11, nullptr));
|
| 1034 |
+
EXPECT_TRUE(leaf->IsFlat(0, 11, &fragment));
|
| 1035 |
+
EXPECT_THAT(fragment, Eq("Hello world"));
|
| 1036 |
+
|
| 1037 |
+
// Arbitrary ranges must check true as well.
|
| 1038 |
+
EXPECT_TRUE(leaf->IsFlat(1, 4, &fragment));
|
| 1039 |
+
EXPECT_THAT(fragment, Eq("ello"));
|
| 1040 |
+
EXPECT_TRUE(leaf->IsFlat(6, 5, &fragment));
|
| 1041 |
+
EXPECT_THAT(fragment, Eq("world"));
|
| 1042 |
+
|
| 1043 |
+
CordRep::Unref(leaf);
|
| 1044 |
+
}
|
| 1045 |
+
|
| 1046 |
+
TEST(CordRepBtreeTest, IsFlatMultiFlat) {
|
| 1047 |
+
size_t n = CordRepBtree::kMaxCapacity * CordRepBtree::kMaxCapacity + 2;
|
| 1048 |
+
std::string data = CreateRandomString(n * 3);
|
| 1049 |
+
CordRepBtree* tree = CreateTree(data, 3);
|
| 1050 |
+
// Add substring nodes for good measure.
|
| 1051 |
+
tree = tree->Append(tree, MakeSubstring(4, 3, MakeFlat("abcdefghijklm")));
|
| 1052 |
+
tree = tree->Append(tree, MakeSubstring(8, 3, MakeFlat("abcdefghijklm")));
|
| 1053 |
+
data += "efgijk";
|
| 1054 |
+
|
| 1055 |
+
EXPECT_FALSE(tree->IsFlat(nullptr));
|
| 1056 |
+
absl::string_view fragment = "Can't touch this";
|
| 1057 |
+
EXPECT_FALSE(tree->IsFlat(&fragment));
|
| 1058 |
+
EXPECT_THAT(fragment, Eq("Can't touch this"));
|
| 1059 |
+
|
| 1060 |
+
for (size_t offset = 0; offset < data.size(); offset += 3) {
|
| 1061 |
+
EXPECT_TRUE(tree->IsFlat(offset, 3, nullptr));
|
| 1062 |
+
EXPECT_TRUE(tree->IsFlat(offset, 3, &fragment));
|
| 1063 |
+
EXPECT_THAT(fragment, Eq(data.substr(offset, 3)));
|
| 1064 |
+
|
| 1065 |
+
fragment = "Can't touch this";
|
| 1066 |
+
if (offset > 0) {
|
| 1067 |
+
EXPECT_FALSE(tree->IsFlat(offset - 1, 4, nullptr));
|
| 1068 |
+
EXPECT_FALSE(tree->IsFlat(offset - 1, 4, &fragment));
|
| 1069 |
+
EXPECT_THAT(fragment, Eq("Can't touch this"));
|
| 1070 |
+
}
|
| 1071 |
+
if (offset < data.size() - 4) {
|
| 1072 |
+
EXPECT_FALSE(tree->IsFlat(offset, 4, nullptr));
|
| 1073 |
+
EXPECT_FALSE(tree->IsFlat(offset, 4, &fragment));
|
| 1074 |
+
EXPECT_THAT(fragment, Eq("Can't touch this"));
|
| 1075 |
+
}
|
| 1076 |
+
}
|
| 1077 |
+
|
| 1078 |
+
CordRep::Unref(tree);
|
| 1079 |
+
}
|
| 1080 |
+
|
| 1081 |
+
#if defined(GTEST_HAS_DEATH_TEST) && !defined(NDEBUG)
|
| 1082 |
+
|
| 1083 |
+
TEST_P(CordRepBtreeHeightTest, GetAppendBufferNotPrivate) {
|
| 1084 |
+
CordRepBtree* tree = CordRepBtree::Create(MakeExternal("Foo"));
|
| 1085 |
+
CordRepBtree::Ref(tree);
|
| 1086 |
+
EXPECT_DEATH(tree->GetAppendBuffer(1), ".*");
|
| 1087 |
+
CordRepBtree::Unref(tree);
|
| 1088 |
+
CordRepBtree::Unref(tree);
|
| 1089 |
+
}
|
| 1090 |
+
|
| 1091 |
+
#endif // defined(GTEST_HAS_DEATH_TEST) && !defined(NDEBUG)
|
| 1092 |
+
|
| 1093 |
+
TEST_P(CordRepBtreeHeightTest, GetAppendBufferNotFlat) {
|
| 1094 |
+
CordRepBtree* tree = CordRepBtree::Create(MakeExternal("Foo"));
|
| 1095 |
+
for (int i = 1; i <= height(); ++i) {
|
| 1096 |
+
tree = CordRepBtree::New(tree);
|
| 1097 |
+
}
|
| 1098 |
+
EXPECT_THAT(tree->GetAppendBuffer(1), SizeIs(0u));
|
| 1099 |
+
CordRepBtree::Unref(tree);
|
| 1100 |
+
}
|
| 1101 |
+
|
| 1102 |
+
TEST_P(CordRepBtreeHeightTest, GetAppendBufferFlatNotPrivate) {
|
| 1103 |
+
CordRepFlat* flat = MakeFlat("abc");
|
| 1104 |
+
CordRepBtree* tree = CordRepBtree::Create(CordRep::Ref(flat));
|
| 1105 |
+
for (int i = 1; i <= height(); ++i) {
|
| 1106 |
+
tree = CordRepBtree::New(tree);
|
| 1107 |
+
}
|
| 1108 |
+
EXPECT_THAT(tree->GetAppendBuffer(1), SizeIs(0u));
|
| 1109 |
+
CordRepBtree::Unref(tree);
|
| 1110 |
+
CordRep::Unref(flat);
|
| 1111 |
+
}
|
| 1112 |
+
|
| 1113 |
+
TEST_P(CordRepBtreeHeightTest, GetAppendBufferTreeNotPrivate) {
|
| 1114 |
+
if (height() == 0) return;
|
| 1115 |
+
AutoUnref refs;
|
| 1116 |
+
CordRepFlat* flat = MakeFlat("abc");
|
| 1117 |
+
CordRepBtree* tree = CordRepBtree::Create(CordRep::Ref(flat));
|
| 1118 |
+
for (int i = 1; i <= height(); ++i) {
|
| 1119 |
+
if (i == (height() + 1) / 2) refs.Ref(tree);
|
| 1120 |
+
tree = CordRepBtree::New(tree);
|
| 1121 |
+
}
|
| 1122 |
+
EXPECT_THAT(tree->GetAppendBuffer(1), SizeIs(0u));
|
| 1123 |
+
CordRepBtree::Unref(tree);
|
| 1124 |
+
CordRep::Unref(flat);
|
| 1125 |
+
}
|
| 1126 |
+
|
| 1127 |
+
TEST_P(CordRepBtreeHeightTest, GetAppendBufferFlatNoCapacity) {
|
| 1128 |
+
CordRepFlat* flat = MakeFlat("abc");
|
| 1129 |
+
flat->length = flat->Capacity();
|
| 1130 |
+
CordRepBtree* tree = CordRepBtree::Create(flat);
|
| 1131 |
+
for (int i = 1; i <= height(); ++i) {
|
| 1132 |
+
tree = CordRepBtree::New(tree);
|
| 1133 |
+
}
|
| 1134 |
+
EXPECT_THAT(tree->GetAppendBuffer(1), SizeIs(0u));
|
| 1135 |
+
CordRepBtree::Unref(tree);
|
| 1136 |
+
}
|
| 1137 |
+
|
| 1138 |
+
TEST_P(CordRepBtreeHeightTest, GetAppendBufferFlatWithCapacity) {
|
| 1139 |
+
CordRepFlat* flat = MakeFlat("abc");
|
| 1140 |
+
CordRepBtree* tree = CordRepBtree::Create(flat);
|
| 1141 |
+
for (int i = 1; i <= height(); ++i) {
|
| 1142 |
+
tree = CordRepBtree::New(tree);
|
| 1143 |
+
}
|
| 1144 |
+
absl::Span<char> span = tree->GetAppendBuffer(2);
|
| 1145 |
+
EXPECT_THAT(span, SizeIs(2u));
|
| 1146 |
+
EXPECT_THAT(span.data(), TypedEq<void*>(flat->Data() + 3));
|
| 1147 |
+
EXPECT_THAT(tree->length, Eq(5u));
|
| 1148 |
+
|
| 1149 |
+
size_t avail = flat->Capacity() - 5;
|
| 1150 |
+
span = tree->GetAppendBuffer(avail + 100);
|
| 1151 |
+
EXPECT_THAT(span, SizeIs(avail));
|
| 1152 |
+
EXPECT_THAT(span.data(), TypedEq<void*>(flat->Data() + 5));
|
| 1153 |
+
EXPECT_THAT(tree->length, Eq(5 + avail));
|
| 1154 |
+
|
| 1155 |
+
CordRepBtree::Unref(tree);
|
| 1156 |
+
}
|
| 1157 |
+
|
| 1158 |
+
TEST(CordRepBtreeTest, Dump) {
|
| 1159 |
+
// Handles nullptr
|
| 1160 |
+
std::stringstream ss;
|
| 1161 |
+
CordRepBtree::Dump(nullptr, ss);
|
| 1162 |
+
CordRepBtree::Dump(nullptr, "Once upon a label", ss);
|
| 1163 |
+
CordRepBtree::Dump(nullptr, "Once upon a label", false, ss);
|
| 1164 |
+
CordRepBtree::Dump(nullptr, "Once upon a label", true, ss);
|
| 1165 |
+
|
| 1166 |
+
// Cover legal edges
|
| 1167 |
+
CordRepFlat* flat = MakeFlat("Hello world");
|
| 1168 |
+
CordRepExternal* external = MakeExternal("Hello external");
|
| 1169 |
+
CordRep* substr_flat = MakeSubstring(1, 6, CordRep::Ref(flat));
|
| 1170 |
+
CordRep* substr_external = MakeSubstring(2, 7, CordRep::Ref(external));
|
| 1171 |
+
|
| 1172 |
+
// Build tree
|
| 1173 |
+
CordRepBtree* tree = CordRepBtree::Create(flat);
|
| 1174 |
+
tree = CordRepBtree::Append(tree, external);
|
| 1175 |
+
tree = CordRepBtree::Append(tree, substr_flat);
|
| 1176 |
+
tree = CordRepBtree::Append(tree, substr_external);
|
| 1177 |
+
|
| 1178 |
+
// Repeat until we have a tree
|
| 1179 |
+
while (tree->height() == 0) {
|
| 1180 |
+
tree = CordRepBtree::Append(tree, CordRep::Ref(flat));
|
| 1181 |
+
tree = CordRepBtree::Append(tree, CordRep::Ref(external));
|
| 1182 |
+
tree = CordRepBtree::Append(tree, CordRep::Ref(substr_flat));
|
| 1183 |
+
tree = CordRepBtree::Append(tree, CordRep::Ref(substr_external));
|
| 1184 |
+
}
|
| 1185 |
+
|
| 1186 |
+
for (int api = 0; api <= 3; ++api) {
|
| 1187 |
+
absl::string_view api_scope;
|
| 1188 |
+
std::stringstream ss;
|
| 1189 |
+
switch (api) {
|
| 1190 |
+
case 0:
|
| 1191 |
+
api_scope = "Bare";
|
| 1192 |
+
CordRepBtree::Dump(tree, ss);
|
| 1193 |
+
break;
|
| 1194 |
+
case 1:
|
| 1195 |
+
api_scope = "Label only";
|
| 1196 |
+
CordRepBtree::Dump(tree, "Once upon a label", ss);
|
| 1197 |
+
break;
|
| 1198 |
+
case 2:
|
| 1199 |
+
api_scope = "Label no content";
|
| 1200 |
+
CordRepBtree::Dump(tree, "Once upon a label", false, ss);
|
| 1201 |
+
break;
|
| 1202 |
+
default:
|
| 1203 |
+
api_scope = "Label and content";
|
| 1204 |
+
CordRepBtree::Dump(tree, "Once upon a label", true, ss);
|
| 1205 |
+
break;
|
| 1206 |
+
}
|
| 1207 |
+
SCOPED_TRACE(api_scope);
|
| 1208 |
+
std::string str = ss.str();
|
| 1209 |
+
|
| 1210 |
+
// Contains Node(depth) / Leaf and private / shared indicators
|
| 1211 |
+
EXPECT_THAT(str, AllOf(HasSubstr("Node(1)"), HasSubstr("Leaf"),
|
| 1212 |
+
HasSubstr("Private"), HasSubstr("Shared")));
|
| 1213 |
+
|
| 1214 |
+
// Contains length and start offset of all data edges
|
| 1215 |
+
EXPECT_THAT(str, AllOf(HasSubstr("len = 11"), HasSubstr("len = 14"),
|
| 1216 |
+
HasSubstr("len = 6"), HasSubstr("len = 7"),
|
| 1217 |
+
HasSubstr("start = 1"), HasSubstr("start = 2")));
|
| 1218 |
+
|
| 1219 |
+
// Contains address of all data edges
|
| 1220 |
+
EXPECT_THAT(
|
| 1221 |
+
str, AllOf(HasSubstr(absl::StrCat("0x", absl::Hex(flat))),
|
| 1222 |
+
HasSubstr(absl::StrCat("0x", absl::Hex(external))),
|
| 1223 |
+
HasSubstr(absl::StrCat("0x", absl::Hex(substr_flat))),
|
| 1224 |
+
HasSubstr(absl::StrCat("0x", absl::Hex(substr_external)))));
|
| 1225 |
+
|
| 1226 |
+
if (api != 0) {
|
| 1227 |
+
// Contains label
|
| 1228 |
+
EXPECT_THAT(str, HasSubstr("Once upon a label"));
|
| 1229 |
+
}
|
| 1230 |
+
|
| 1231 |
+
if (api != 3) {
|
| 1232 |
+
// Does not contain contents
|
| 1233 |
+
EXPECT_THAT(str, Not(AnyOf((HasSubstr("data = \"Hello world\""),
|
| 1234 |
+
HasSubstr("data = \"Hello external\""),
|
| 1235 |
+
HasSubstr("data = \"ello w\""),
|
| 1236 |
+
HasSubstr("data = \"llo ext\"")))));
|
| 1237 |
+
} else {
|
| 1238 |
+
// Contains contents
|
| 1239 |
+
EXPECT_THAT(str, AllOf((HasSubstr("data = \"Hello world\""),
|
| 1240 |
+
HasSubstr("data = \"Hello external\""),
|
| 1241 |
+
HasSubstr("data = \"ello w\""),
|
| 1242 |
+
HasSubstr("data = \"llo ext\""))));
|
| 1243 |
+
}
|
| 1244 |
+
}
|
| 1245 |
+
|
| 1246 |
+
CordRep::Unref(tree);
|
| 1247 |
+
}
|
| 1248 |
+
|
| 1249 |
+
TEST(CordRepBtreeTest, IsValid) {
|
| 1250 |
+
EXPECT_FALSE(CordRepBtree::IsValid(nullptr));
|
| 1251 |
+
|
| 1252 |
+
CordRepBtree* empty = CordRepBtree::New(0);
|
| 1253 |
+
EXPECT_TRUE(CordRepBtree::IsValid(empty));
|
| 1254 |
+
CordRep::Unref(empty);
|
| 1255 |
+
|
| 1256 |
+
for (bool as_tree : {false, true}) {
|
| 1257 |
+
CordRepBtree* leaf = CordRepBtree::Create(MakeFlat("abc"));
|
| 1258 |
+
CordRepBtree* tree = as_tree ? CordRepBtree::New(leaf) : nullptr;
|
| 1259 |
+
CordRepBtree* check = as_tree ? tree : leaf;
|
| 1260 |
+
|
| 1261 |
+
ASSERT_TRUE(CordRepBtree::IsValid(check));
|
| 1262 |
+
leaf->length--;
|
| 1263 |
+
EXPECT_FALSE(CordRepBtree::IsValid(check));
|
| 1264 |
+
leaf->length++;
|
| 1265 |
+
|
| 1266 |
+
ASSERT_TRUE(CordRepBtree::IsValid(check));
|
| 1267 |
+
leaf->tag--;
|
| 1268 |
+
EXPECT_FALSE(CordRepBtree::IsValid(check));
|
| 1269 |
+
leaf->tag++;
|
| 1270 |
+
|
| 1271 |
+
// Height
|
| 1272 |
+
ASSERT_TRUE(CordRepBtree::IsValid(check));
|
| 1273 |
+
leaf->storage[0] = static_cast<uint8_t>(CordRepBtree::kMaxHeight + 1);
|
| 1274 |
+
EXPECT_FALSE(CordRepBtree::IsValid(check));
|
| 1275 |
+
leaf->storage[0] = 1;
|
| 1276 |
+
EXPECT_FALSE(CordRepBtree::IsValid(check));
|
| 1277 |
+
leaf->storage[0] = 0;
|
| 1278 |
+
|
| 1279 |
+
// Begin
|
| 1280 |
+
ASSERT_TRUE(CordRepBtree::IsValid(check));
|
| 1281 |
+
const uint8_t begin = leaf->storage[1];
|
| 1282 |
+
leaf->storage[1] = static_cast<uint8_t>(CordRepBtree::kMaxCapacity);
|
| 1283 |
+
EXPECT_FALSE(CordRepBtree::IsValid(check));
|
| 1284 |
+
leaf->storage[1] = 2;
|
| 1285 |
+
EXPECT_FALSE(CordRepBtree::IsValid(check));
|
| 1286 |
+
leaf->storage[1] = begin;
|
| 1287 |
+
|
| 1288 |
+
// End
|
| 1289 |
+
ASSERT_TRUE(CordRepBtree::IsValid(check));
|
| 1290 |
+
const uint8_t end = leaf->storage[2];
|
| 1291 |
+
leaf->storage[2] = static_cast<uint8_t>(CordRepBtree::kMaxCapacity + 1);
|
| 1292 |
+
EXPECT_FALSE(CordRepBtree::IsValid(check));
|
| 1293 |
+
leaf->storage[2] = end;
|
| 1294 |
+
|
| 1295 |
+
// DataEdge tag and value
|
| 1296 |
+
ASSERT_TRUE(CordRepBtree::IsValid(check));
|
| 1297 |
+
CordRep* const edge = leaf->Edges()[0];
|
| 1298 |
+
const uint8_t tag = edge->tag;
|
| 1299 |
+
CordRepBtreeTestPeer::SetEdge(leaf, begin, nullptr);
|
| 1300 |
+
EXPECT_FALSE(CordRepBtree::IsValid(check));
|
| 1301 |
+
CordRepBtreeTestPeer::SetEdge(leaf, begin, edge);
|
| 1302 |
+
edge->tag = BTREE;
|
| 1303 |
+
EXPECT_FALSE(CordRepBtree::IsValid(check));
|
| 1304 |
+
edge->tag = tag;
|
| 1305 |
+
|
| 1306 |
+
if (as_tree) {
|
| 1307 |
+
ASSERT_TRUE(CordRepBtree::IsValid(check));
|
| 1308 |
+
leaf->length--;
|
| 1309 |
+
EXPECT_FALSE(CordRepBtree::IsValid(check));
|
| 1310 |
+
leaf->length++;
|
| 1311 |
+
|
| 1312 |
+
// Height
|
| 1313 |
+
ASSERT_TRUE(CordRepBtree::IsValid(check));
|
| 1314 |
+
tree->storage[0] = static_cast<uint8_t>(2);
|
| 1315 |
+
EXPECT_FALSE(CordRepBtree::IsValid(check));
|
| 1316 |
+
tree->storage[0] = 1;
|
| 1317 |
+
|
| 1318 |
+
// Btree edge
|
| 1319 |
+
ASSERT_TRUE(CordRepBtree::IsValid(check));
|
| 1320 |
+
CordRep* const edge = tree->Edges()[0];
|
| 1321 |
+
const uint8_t tag = edge->tag;
|
| 1322 |
+
edge->tag = FLAT;
|
| 1323 |
+
EXPECT_FALSE(CordRepBtree::IsValid(check));
|
| 1324 |
+
edge->tag = tag;
|
| 1325 |
+
}
|
| 1326 |
+
|
| 1327 |
+
ASSERT_TRUE(CordRepBtree::IsValid(check));
|
| 1328 |
+
CordRep::Unref(check);
|
| 1329 |
+
}
|
| 1330 |
+
}
|
| 1331 |
+
|
| 1332 |
+
TEST(CordRepBtreeTest, AssertValid) {
|
| 1333 |
+
CordRepBtree* tree = CordRepBtree::Create(MakeFlat("abc"));
|
| 1334 |
+
const CordRepBtree* ctree = tree;
|
| 1335 |
+
EXPECT_THAT(CordRepBtree::AssertValid(tree), Eq(tree));
|
| 1336 |
+
EXPECT_THAT(CordRepBtree::AssertValid(ctree), Eq(ctree));
|
| 1337 |
+
|
| 1338 |
+
#if defined(GTEST_HAS_DEATH_TEST)
|
| 1339 |
+
CordRepBtree* nulltree = nullptr;
|
| 1340 |
+
const CordRepBtree* cnulltree = nullptr;
|
| 1341 |
+
EXPECT_DEBUG_DEATH(
|
| 1342 |
+
EXPECT_THAT(CordRepBtree::AssertValid(nulltree), Eq(nulltree)), ".*");
|
| 1343 |
+
EXPECT_DEBUG_DEATH(
|
| 1344 |
+
EXPECT_THAT(CordRepBtree::AssertValid(cnulltree), Eq(cnulltree)), ".*");
|
| 1345 |
+
|
| 1346 |
+
tree->length--;
|
| 1347 |
+
EXPECT_DEBUG_DEATH(EXPECT_THAT(CordRepBtree::AssertValid(tree), Eq(tree)),
|
| 1348 |
+
".*");
|
| 1349 |
+
EXPECT_DEBUG_DEATH(EXPECT_THAT(CordRepBtree::AssertValid(ctree), Eq(ctree)),
|
| 1350 |
+
".*");
|
| 1351 |
+
tree->length++;
|
| 1352 |
+
#endif
|
| 1353 |
+
CordRep::Unref(tree);
|
| 1354 |
+
}
|
| 1355 |
+
|
| 1356 |
+
TEST(CordRepBtreeTest, CheckAssertValidShallowVsDeep) {
|
| 1357 |
+
// Restore exhaustive validation on any exit.
|
| 1358 |
+
const bool exhaustive_validation = IsCordBtreeExhaustiveValidationEnabled();
|
| 1359 |
+
auto cleanup = absl::MakeCleanup([exhaustive_validation] {
|
| 1360 |
+
SetCordBtreeExhaustiveValidation(exhaustive_validation);
|
| 1361 |
+
});
|
| 1362 |
+
|
| 1363 |
+
// Create a tree of at least 2 levels, and mess with the original flat, which
|
| 1364 |
+
// should go undetected in shallow mode as the flat is too far away, but
|
| 1365 |
+
// should be detected in forced non-shallow mode.
|
| 1366 |
+
CordRep* flat = MakeFlat("abc");
|
| 1367 |
+
CordRepBtree* tree = CordRepBtree::Create(flat);
|
| 1368 |
+
constexpr size_t max_cap = CordRepBtree::kMaxCapacity;
|
| 1369 |
+
const size_t n = max_cap * max_cap * 2;
|
| 1370 |
+
for (size_t i = 0; i < n; ++i) {
|
| 1371 |
+
tree = CordRepBtree::Append(tree, MakeFlat("Hello world"));
|
| 1372 |
+
}
|
| 1373 |
+
flat->length = 100;
|
| 1374 |
+
|
| 1375 |
+
SetCordBtreeExhaustiveValidation(false);
|
| 1376 |
+
EXPECT_FALSE(CordRepBtree::IsValid(tree));
|
| 1377 |
+
EXPECT_TRUE(CordRepBtree::IsValid(tree, true));
|
| 1378 |
+
EXPECT_FALSE(CordRepBtree::IsValid(tree, false));
|
| 1379 |
+
CordRepBtree::AssertValid(tree);
|
| 1380 |
+
CordRepBtree::AssertValid(tree, true);
|
| 1381 |
+
#if defined(GTEST_HAS_DEATH_TEST)
|
| 1382 |
+
EXPECT_DEBUG_DEATH(CordRepBtree::AssertValid(tree, false), ".*");
|
| 1383 |
+
#endif
|
| 1384 |
+
|
| 1385 |
+
SetCordBtreeExhaustiveValidation(true);
|
| 1386 |
+
EXPECT_FALSE(CordRepBtree::IsValid(tree));
|
| 1387 |
+
EXPECT_FALSE(CordRepBtree::IsValid(tree, true));
|
| 1388 |
+
EXPECT_FALSE(CordRepBtree::IsValid(tree, false));
|
| 1389 |
+
#if defined(GTEST_HAS_DEATH_TEST)
|
| 1390 |
+
EXPECT_DEBUG_DEATH(CordRepBtree::AssertValid(tree), ".*");
|
| 1391 |
+
EXPECT_DEBUG_DEATH(CordRepBtree::AssertValid(tree, true), ".*");
|
| 1392 |
+
#endif
|
| 1393 |
+
|
| 1394 |
+
flat->length = 3;
|
| 1395 |
+
CordRep::Unref(tree);
|
| 1396 |
+
}
|
| 1397 |
+
|
| 1398 |
+
TEST_P(CordRepBtreeTest, Rebuild) {
|
| 1399 |
+
for (size_t size : {3u, 8u, 100u, 10000u, 1000000u}) {
|
| 1400 |
+
SCOPED_TRACE(absl::StrCat("Rebuild @", size));
|
| 1401 |
+
|
| 1402 |
+
std::vector<CordRepFlat*> flats;
|
| 1403 |
+
for (size_t i = 0; i < size; ++i) {
|
| 1404 |
+
flats.push_back(CordRepFlat::New(2));
|
| 1405 |
+
flats.back()->Data()[0] = 'x';
|
| 1406 |
+
flats.back()->length = 1;
|
| 1407 |
+
}
|
| 1408 |
+
|
| 1409 |
+
// Build the tree into 'right', and each so many 'split_limit' edges,
|
| 1410 |
+
// combine 'left' + 'right' into a new 'left', and start a new 'right'.
|
| 1411 |
+
// This guarantees we get a reasonable amount of chaos in the tree.
|
| 1412 |
+
size_t split_count = 0;
|
| 1413 |
+
size_t split_limit = 3;
|
| 1414 |
+
auto it = flats.begin();
|
| 1415 |
+
CordRepBtree* left = nullptr;
|
| 1416 |
+
CordRepBtree* right = CordRepBtree::New(*it);
|
| 1417 |
+
while (++it != flats.end()) {
|
| 1418 |
+
if (++split_count >= split_limit) {
|
| 1419 |
+
split_limit += split_limit / 16;
|
| 1420 |
+
left = left ? CordRepBtree::Append(left, right) : right;
|
| 1421 |
+
right = CordRepBtree::New(*it);
|
| 1422 |
+
} else {
|
| 1423 |
+
right = CordRepBtree::Append(right, *it);
|
| 1424 |
+
}
|
| 1425 |
+
}
|
| 1426 |
+
|
| 1427 |
+
// Finalize tree
|
| 1428 |
+
left = left ? CordRepBtree::Append(left, right) : right;
|
| 1429 |
+
|
| 1430 |
+
// Rebuild
|
| 1431 |
+
AutoUnref ref;
|
| 1432 |
+
left = ref.Add(CordRepBtree::Rebuild(ref.RefIf(shared(), left)));
|
| 1433 |
+
ASSERT_TRUE(CordRepBtree::IsValid(left));
|
| 1434 |
+
|
| 1435 |
+
// Verify we have the exact same edges in the exact same order.
|
| 1436 |
+
bool ok = true;
|
| 1437 |
+
it = flats.begin();
|
| 1438 |
+
CordVisitReps(left, [&](CordRep* edge) {
|
| 1439 |
+
if (edge->tag < FLAT) return;
|
| 1440 |
+
ok = ok && (it != flats.end() && *it++ == edge);
|
| 1441 |
+
});
|
| 1442 |
+
EXPECT_TRUE(ok && it == flats.end()) << "Rebuild edges mismatch";
|
| 1443 |
+
}
|
| 1444 |
+
}
|
| 1445 |
+
|
| 1446 |
+
// Convenience helper for CordRepBtree::ExtractAppendBuffer
|
| 1447 |
+
CordRepBtree::ExtractResult ExtractLast(CordRepBtree* input, size_t cap = 1) {
|
| 1448 |
+
return CordRepBtree::ExtractAppendBuffer(input, cap);
|
| 1449 |
+
}
|
| 1450 |
+
|
| 1451 |
+
TEST(CordRepBtreeTest, ExtractAppendBufferLeafSingleFlat) {
|
| 1452 |
+
CordRep* flat = MakeFlat("Abc");
|
| 1453 |
+
CordRepBtree* leaf = CordRepBtree::Create(flat);
|
| 1454 |
+
EXPECT_THAT(ExtractLast(leaf), EqExtractResult(nullptr, flat));
|
| 1455 |
+
CordRep::Unref(flat);
|
| 1456 |
+
}
|
| 1457 |
+
|
| 1458 |
+
TEST(CordRepBtreeTest, ExtractAppendBufferNodeSingleFlat) {
|
| 1459 |
+
CordRep* flat = MakeFlat("Abc");
|
| 1460 |
+
CordRepBtree* leaf = CordRepBtree::Create(flat);
|
| 1461 |
+
CordRepBtree* node = CordRepBtree::New(leaf);
|
| 1462 |
+
EXPECT_THAT(ExtractLast(node), EqExtractResult(nullptr, flat));
|
| 1463 |
+
CordRep::Unref(flat);
|
| 1464 |
+
}
|
| 1465 |
+
|
| 1466 |
+
TEST(CordRepBtreeTest, ExtractAppendBufferLeafTwoFlats) {
|
| 1467 |
+
std::vector<CordRep*> flats = CreateFlatsFromString("abcdef", 3);
|
| 1468 |
+
CordRepBtree* leaf = CreateTree(flats);
|
| 1469 |
+
EXPECT_THAT(ExtractLast(leaf), EqExtractResult(flats[0], flats[1]));
|
| 1470 |
+
CordRep::Unref(flats[0]);
|
| 1471 |
+
CordRep::Unref(flats[1]);
|
| 1472 |
+
}
|
| 1473 |
+
|
| 1474 |
+
TEST(CordRepBtreeTest, ExtractAppendBufferNodeTwoFlats) {
|
| 1475 |
+
std::vector<CordRep*> flats = CreateFlatsFromString("abcdef", 3);
|
| 1476 |
+
CordRepBtree* leaf = CreateTree(flats);
|
| 1477 |
+
CordRepBtree* node = CordRepBtree::New(leaf);
|
| 1478 |
+
EXPECT_THAT(ExtractLast(node), EqExtractResult(flats[0], flats[1]));
|
| 1479 |
+
CordRep::Unref(flats[0]);
|
| 1480 |
+
CordRep::Unref(flats[1]);
|
| 1481 |
+
}
|
| 1482 |
+
|
| 1483 |
+
TEST(CordRepBtreeTest, ExtractAppendBufferNodeTwoFlatsInTwoLeafs) {
|
| 1484 |
+
std::vector<CordRep*> flats = CreateFlatsFromString("abcdef", 3);
|
| 1485 |
+
CordRepBtree* leaf1 = CordRepBtree::Create(flats[0]);
|
| 1486 |
+
CordRepBtree* leaf2 = CordRepBtree::Create(flats[1]);
|
| 1487 |
+
CordRepBtree* node = CordRepBtree::New(leaf1, leaf2);
|
| 1488 |
+
EXPECT_THAT(ExtractLast(node), EqExtractResult(flats[0], flats[1]));
|
| 1489 |
+
CordRep::Unref(flats[0]);
|
| 1490 |
+
CordRep::Unref(flats[1]);
|
| 1491 |
+
}
|
| 1492 |
+
|
| 1493 |
+
TEST(CordRepBtreeTest, ExtractAppendBufferLeafThreeFlats) {
|
| 1494 |
+
std::vector<CordRep*> flats = CreateFlatsFromString("abcdefghi", 3);
|
| 1495 |
+
CordRepBtree* leaf = CreateTree(flats);
|
| 1496 |
+
EXPECT_THAT(ExtractLast(leaf), EqExtractResult(leaf, flats[2]));
|
| 1497 |
+
CordRep::Unref(flats[2]);
|
| 1498 |
+
CordRep::Unref(leaf);
|
| 1499 |
+
}
|
| 1500 |
+
|
| 1501 |
+
TEST(CordRepBtreeTest, ExtractAppendBufferNodeThreeFlatsRightNoFolding) {
|
| 1502 |
+
CordRep* flat = MakeFlat("Abc");
|
| 1503 |
+
std::vector<CordRep*> flats = CreateFlatsFromString("defghi", 3);
|
| 1504 |
+
CordRepBtree* leaf1 = CordRepBtree::Create(flat);
|
| 1505 |
+
CordRepBtree* leaf2 = CreateTree(flats);
|
| 1506 |
+
CordRepBtree* node = CordRepBtree::New(leaf1, leaf2);
|
| 1507 |
+
EXPECT_THAT(ExtractLast(node), EqExtractResult(node, flats[1]));
|
| 1508 |
+
EXPECT_THAT(node->Edges(), ElementsAre(leaf1, leaf2));
|
| 1509 |
+
EXPECT_THAT(leaf1->Edges(), ElementsAre(flat));
|
| 1510 |
+
EXPECT_THAT(leaf2->Edges(), ElementsAre(flats[0]));
|
| 1511 |
+
CordRep::Unref(node);
|
| 1512 |
+
CordRep::Unref(flats[1]);
|
| 1513 |
+
}
|
| 1514 |
+
|
| 1515 |
+
TEST(CordRepBtreeTest, ExtractAppendBufferNodeThreeFlatsRightLeafFolding) {
|
| 1516 |
+
CordRep* flat = MakeFlat("Abc");
|
| 1517 |
+
std::vector<CordRep*> flats = CreateFlatsFromString("defghi", 3);
|
| 1518 |
+
CordRepBtree* leaf1 = CreateTree(flats);
|
| 1519 |
+
CordRepBtree* leaf2 = CordRepBtree::Create(flat);
|
| 1520 |
+
CordRepBtree* node = CordRepBtree::New(leaf1, leaf2);
|
| 1521 |
+
EXPECT_THAT(ExtractLast(node), EqExtractResult(leaf1, flat));
|
| 1522 |
+
EXPECT_THAT(leaf1->Edges(), ElementsAreArray(flats));
|
| 1523 |
+
CordRep::Unref(leaf1);
|
| 1524 |
+
CordRep::Unref(flat);
|
| 1525 |
+
}
|
| 1526 |
+
|
| 1527 |
+
TEST(CordRepBtreeTest, ExtractAppendBufferNoCapacity) {
|
| 1528 |
+
std::vector<CordRep*> flats = CreateFlatsFromString("abcdef", 3);
|
| 1529 |
+
CordRepBtree* leaf = CreateTree(flats);
|
| 1530 |
+
size_t avail = flats[1]->flat()->Capacity() - flats[1]->length;
|
| 1531 |
+
EXPECT_THAT(ExtractLast(leaf, avail + 1), EqExtractResult(leaf, nullptr));
|
| 1532 |
+
EXPECT_THAT(ExtractLast(leaf, avail), EqExtractResult(flats[0], flats[1]));
|
| 1533 |
+
CordRep::Unref(flats[0]);
|
| 1534 |
+
CordRep::Unref(flats[1]);
|
| 1535 |
+
}
|
| 1536 |
+
|
| 1537 |
+
TEST(CordRepBtreeTest, ExtractAppendBufferNotFlat) {
|
| 1538 |
+
std::vector<CordRep*> flats = CreateFlatsFromString("abcdef", 3);
|
| 1539 |
+
auto substr = MakeSubstring(1, 2, flats[1]);
|
| 1540 |
+
CordRepBtree* leaf = CreateTree({flats[0], substr});
|
| 1541 |
+
EXPECT_THAT(ExtractLast(leaf), EqExtractResult(leaf, nullptr));
|
| 1542 |
+
CordRep::Unref(leaf);
|
| 1543 |
+
}
|
| 1544 |
+
|
| 1545 |
+
TEST(CordRepBtreeTest, ExtractAppendBufferShared) {
|
| 1546 |
+
std::vector<CordRep*> flats = CreateFlatsFromString("abcdef", 3);
|
| 1547 |
+
CordRepBtree* leaf = CreateTree(flats);
|
| 1548 |
+
|
| 1549 |
+
CordRep::Ref(flats[1]);
|
| 1550 |
+
EXPECT_THAT(ExtractLast(leaf), EqExtractResult(leaf, nullptr));
|
| 1551 |
+
CordRep::Unref(flats[1]);
|
| 1552 |
+
|
| 1553 |
+
CordRep::Ref(leaf);
|
| 1554 |
+
EXPECT_THAT(ExtractLast(leaf), EqExtractResult(leaf, nullptr));
|
| 1555 |
+
CordRep::Unref(leaf);
|
| 1556 |
+
|
| 1557 |
+
CordRepBtree* node = CordRepBtree::New(leaf);
|
| 1558 |
+
CordRep::Ref(node);
|
| 1559 |
+
EXPECT_THAT(ExtractLast(node), EqExtractResult(node, nullptr));
|
| 1560 |
+
CordRep::Unref(node);
|
| 1561 |
+
|
| 1562 |
+
CordRep::Unref(node);
|
| 1563 |
+
}
|
| 1564 |
+
|
| 1565 |
+
} // namespace
|
| 1566 |
+
} // namespace cord_internal
|
| 1567 |
+
ABSL_NAMESPACE_END
|
| 1568 |
+
} // namespace absl
|
weight/_dep/abseil-cpp/absl/strings/internal/cord_rep_consume.h
ADDED
|
@@ -0,0 +1,47 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
// Copyright 2021 The Abseil Authors
|
| 2 |
+
//
|
| 3 |
+
// Licensed under the Apache License, Version 2.0 (the "License");
|
| 4 |
+
// you may not use this file except in compliance with the License.
|
| 5 |
+
// You may obtain a copy of the License at
|
| 6 |
+
//
|
| 7 |
+
// https://www.apache.org/licenses/LICENSE-2.0
|
| 8 |
+
//
|
| 9 |
+
// Unless required by applicable law or agreed to in writing, software
|
| 10 |
+
// distributed under the License is distributed on an "AS IS" BASIS,
|
| 11 |
+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
| 12 |
+
// See the License for the specific language governing permissions and
|
| 13 |
+
// limitations under the License.
|
| 14 |
+
|
| 15 |
+
#ifndef ABSL_STRINGS_INTERNAL_CORD_REP_CONSUME_H_
|
| 16 |
+
#define ABSL_STRINGS_INTERNAL_CORD_REP_CONSUME_H_
|
| 17 |
+
|
| 18 |
+
#include <functional>
|
| 19 |
+
|
| 20 |
+
#include "absl/functional/function_ref.h"
|
| 21 |
+
#include "absl/strings/internal/cord_internal.h"
|
| 22 |
+
|
| 23 |
+
namespace absl {
|
| 24 |
+
ABSL_NAMESPACE_BEGIN
|
| 25 |
+
namespace cord_internal {
|
| 26 |
+
|
| 27 |
+
// Consume() and ReverseConsume() consume CONCAT based trees and invoke the
|
| 28 |
+
// provided functor with the contained nodes in the proper forward or reverse
|
| 29 |
+
// order, which is used to convert CONCAT trees into other tree or cord data.
|
| 30 |
+
// All CONCAT and SUBSTRING nodes are processed internally. The 'offset`
|
| 31 |
+
// parameter of the functor is non-zero for any nodes below SUBSTRING nodes.
|
| 32 |
+
// It's up to the caller to form these back into SUBSTRING nodes or otherwise
|
| 33 |
+
// store offset / prefix information. These functions are intended to be used
|
| 34 |
+
// only for migration / transitional code where due to factors such as ODR
|
| 35 |
+
// violations, we can not 100% guarantee that all code respects 'new format'
|
| 36 |
+
// settings and flags, so we need to be able to parse old data on the fly until
|
| 37 |
+
// all old code is deprecated / no longer the default format.
|
| 38 |
+
void Consume(CordRep* rep,
|
| 39 |
+
FunctionRef<void(CordRep*, size_t, size_t)> consume_fn);
|
| 40 |
+
void ReverseConsume(CordRep* rep,
|
| 41 |
+
FunctionRef<void(CordRep*, size_t, size_t)> consume_fn);
|
| 42 |
+
|
| 43 |
+
} // namespace cord_internal
|
| 44 |
+
ABSL_NAMESPACE_END
|
| 45 |
+
} // namespace absl
|
| 46 |
+
|
| 47 |
+
#endif // ABSL_STRINGS_INTERNAL_CORD_REP_CONSUME_H_
|
weight/_dep/abseil-cpp/absl/strings/internal/cord_rep_crc.cc
ADDED
|
@@ -0,0 +1,56 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
// Copyright 2021 The Abseil Authors
|
| 2 |
+
//
|
| 3 |
+
// Licensed under the Apache License, Version 2.0 (the "License");
|
| 4 |
+
// you may not use this file except in compliance with the License.
|
| 5 |
+
// You may obtain a copy of the License at
|
| 6 |
+
//
|
| 7 |
+
// https://www.apache.org/licenses/LICENSE-2.0
|
| 8 |
+
//
|
| 9 |
+
// Unless required by applicable law or agreed to in writing, software
|
| 10 |
+
// distributed under the License is distributed on an "AS IS" BASIS,
|
| 11 |
+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
| 12 |
+
// See the License for the specific language governing permissions and
|
| 13 |
+
// limitations under the License.
|
| 14 |
+
|
| 15 |
+
#include "absl/strings/internal/cord_rep_crc.h"
|
| 16 |
+
|
| 17 |
+
#include <cassert>
|
| 18 |
+
#include <cstdint>
|
| 19 |
+
#include <utility>
|
| 20 |
+
|
| 21 |
+
#include "absl/base/config.h"
|
| 22 |
+
#include "absl/strings/internal/cord_internal.h"
|
| 23 |
+
|
| 24 |
+
namespace absl {
|
| 25 |
+
ABSL_NAMESPACE_BEGIN
|
| 26 |
+
namespace cord_internal {
|
| 27 |
+
|
| 28 |
+
CordRepCrc* CordRepCrc::New(CordRep* child, crc_internal::CrcCordState state) {
|
| 29 |
+
if (child != nullptr && child->IsCrc()) {
|
| 30 |
+
if (child->refcount.IsOne()) {
|
| 31 |
+
child->crc()->crc_cord_state = std::move(state);
|
| 32 |
+
return child->crc();
|
| 33 |
+
}
|
| 34 |
+
CordRep* old = child;
|
| 35 |
+
child = old->crc()->child;
|
| 36 |
+
CordRep::Ref(child);
|
| 37 |
+
CordRep::Unref(old);
|
| 38 |
+
}
|
| 39 |
+
auto* new_cordrep = new CordRepCrc;
|
| 40 |
+
new_cordrep->length = child != nullptr ? child->length : 0;
|
| 41 |
+
new_cordrep->tag = cord_internal::CRC;
|
| 42 |
+
new_cordrep->child = child;
|
| 43 |
+
new_cordrep->crc_cord_state = std::move(state);
|
| 44 |
+
return new_cordrep;
|
| 45 |
+
}
|
| 46 |
+
|
| 47 |
+
void CordRepCrc::Destroy(CordRepCrc* node) {
|
| 48 |
+
if (node->child != nullptr) {
|
| 49 |
+
CordRep::Unref(node->child);
|
| 50 |
+
}
|
| 51 |
+
delete node;
|
| 52 |
+
}
|
| 53 |
+
|
| 54 |
+
} // namespace cord_internal
|
| 55 |
+
ABSL_NAMESPACE_END
|
| 56 |
+
} // namespace absl
|