Update Тint (#3553)

* Trimmed Tint.

* Updated Tint.
This commit is contained in:
Branimir Karadžić
2026-01-15 20:44:27 -08:00
committed by GitHub
parent 0d7526dfb9
commit cc923c5165
390 changed files with 120 additions and 168171 deletions

View File

@@ -611,6 +611,7 @@ typedef enum WGPUFeatureName {
WGPUFeatureName_SharedBufferMemoryD3D12SharedMemoryFileMappingHandle = 0x00050038,
WGPUFeatureName_SharedTextureMemoryD3D12Resource = 0x00050039,
WGPUFeatureName_ChromiumExperimentalSamplingResourceTable = 0x0005003A,
WGPUFeatureName_ChromiumExperimentalSubgroupSizeControl = 0x0005003B,
WGPUFeatureName_Force32 = 0x7FFFFFFF
} WGPUFeatureName WGPU_ENUM_ATTRIBUTE;

File diff suppressed because it is too large Load Diff

View File

@@ -1,53 +0,0 @@
// Copyright 2023 The Dawn & Tint Authors
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this
// list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#ifndef SRC_TINT_LANG_CORE_IR_BINARY_DECODE_H_
#define SRC_TINT_LANG_CORE_IR_BINARY_DECODE_H_
#include <span>
#include "src/tint/utils/result.h"
// Forward declarations
namespace tint::core::ir {
class Module;
} // namespace tint::core::ir
namespace tint::core::ir::binary::pb {
class Module;
} // namespace tint::core::ir::binary::pb
namespace tint::core::ir::binary {
/// @returns the decoded Module from the serialized protobuf.
Result<Module> Decode(std::span<const std::byte> encoded);
/// @returns the decoded Module from the protobuf.
Result<Module> Decode(const pb::Module& module);
} // namespace tint::core::ir::binary
#endif // SRC_TINT_LANG_CORE_IR_BINARY_DECODE_H_

File diff suppressed because it is too large Load Diff

View File

@@ -1,55 +0,0 @@
// Copyright 2023 The Dawn & Tint Authors
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this
// list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#ifndef SRC_TINT_LANG_CORE_IR_BINARY_ENCODE_H_
#define SRC_TINT_LANG_CORE_IR_BINARY_ENCODE_H_
#include <memory>
#include "src/tint/utils/containers/vector.h"
#include "src/tint/utils/result.h"
// Forward declarations
namespace tint::core::ir {
class Module;
} // namespace tint::core::ir
namespace tint::core::ir::binary::pb {
class Module;
}
namespace tint::core::ir::binary {
// Encode the module into a proto representation.
Result<std::unique_ptr<pb::Module>> EncodeToProto(const Module& module);
// Encode the module into a binary representation.
Result<Vector<std::byte, 0>> EncodeToBinary(const Module& module);
} // namespace tint::core::ir::binary
#endif // SRC_TINT_LANG_CORE_IR_BINARY_ENCODE_H_

View File

@@ -37,11 +37,13 @@ namespace tint::core::ir {
Result<WorkgroupInfo> GetWorkgroupInfo(core::ir::Module& ir) {
std::optional<std::array<uint32_t, 3>> const_wg_size;
std::optional<uint32_t> const_sg_size;
for (auto func : ir.functions) {
if (!func->IsEntryPoint()) {
continue;
}
const_wg_size = func->WorkgroupSizeAsConst();
const_sg_size = func->SubgroupSizeAsConst();
}
if (!const_wg_size) {
@@ -65,7 +67,7 @@ Result<WorkgroupInfo> GetWorkgroupInfo(core::ir::Module& ir) {
}
}
return WorkgroupInfo{(*const_wg_size)[0], (*const_wg_size)[1], (*const_wg_size)[2],
wg_storage_size};
wg_storage_size, const_sg_size};
}
} // namespace tint::core::ir

View File

@@ -28,6 +28,8 @@
#ifndef SRC_TINT_LANG_CORE_IR_REFLECTION_H_
#define SRC_TINT_LANG_CORE_IR_REFLECTION_H_
#include <optional>
#include "src/tint/lang/core/ir/module.h"
#include "src/tint/utils/result.h"
@@ -43,6 +45,9 @@ struct WorkgroupInfo {
/// The needed workgroup storage size
size_t storage_size = 0;
/// The `@subgroup_size` attribute
std::optional<uint32_t> subgroup_size;
};
/// Generate WorkgroupInfo for an IR module input.

View File

@@ -142,11 +142,14 @@ struct State {
}
}
break;
case core::BuiltinFn::kSaturate:
if (config.saturate) {
case core::BuiltinFn::kSaturate: {
const bool is_vec_f16 =
builtin->Args()[0]->Type()->DeepestElement()->Is<core::type::F16>() &&
builtin->Args()[0]->Type()->IsFloatVector();
if ((is_vec_f16 && config.saturate_as_min_max) || config.saturate) {
worklist.Push(builtin);
}
break;
} break;
case core::BuiltinFn::kTextureSampleBias:
worklist.Push(builtin);
break;
@@ -907,6 +910,8 @@ struct State {
void Saturate(ir::CoreBuiltinCall* call) {
// Replace `saturate(x)` with `clamp(x, 0., 1.)`.
auto* type = call->Result()->Type();
const bool is_vec_f16 =
type->DeepestElement()->Is<core::type::F16>() && type->IsFloatVector();
ir::Constant* zero = nullptr;
ir::Constant* one = nullptr;
if (type->DeepestElement()->Is<core::type::F32>()) {
@@ -916,9 +921,22 @@ struct State {
zero = b.MatchWidth(0_h, type);
one = b.MatchWidth(1_h, type);
}
// Intel mesa incorrectly performs saturate on vec f16 loads from uniforms.
// Note: to avoid compiler pattern matching, we do the min then the max which is
// functionally different than doing the max then the min for high/low swapped (this doesnt
// matter in the case with saturate). See crbug.com/448873316
if (config.saturate_as_min_max && is_vec_f16) {
b.InsertBefore(call, [&] {
auto* clamped_via_min_max = b.Max(b.Min(call->Args()[0], one), zero);
clamped_via_min_max->SetResult(call->DetachResult());
});
} else {
auto* clamp = b.Clamp(call->Args()[0], zero, one);
clamp->SetResult(call->DetachResult());
clamp->InsertBefore(call);
}
call->Destroy();
}

View File

@@ -100,6 +100,8 @@ struct BuiltinPolyfillConfig {
bool pack_unpack_4x8_norm = false;
/// Should `subgroupBroadcast(f16)` be polyfilled?
bool subgroup_broadcast_f16 = false;
// Should 'saturate(f16)' be polyfilled with min and max.
bool saturate_as_min_max = false;
/// Reflection for this class
TINT_REFLECT(BuiltinPolyfillConfig,
@@ -120,7 +122,8 @@ struct BuiltinPolyfillConfig {
pack_unpack_4x8,
pack_4xu8_clamp,
pack_unpack_4x8_norm,
subgroup_broadcast_f16);
subgroup_broadcast_f16,
saturate_as_min_max);
};
/// BuiltinPolyfill is a transform that replaces calls to builtin functions and uses of other core

View File

@@ -1315,9 +1315,13 @@ class Validator {
/// @param anchor where to attach error messages to.
/// @param ty the type of the IO object
/// @param attr the IO attributes of the object.
/// @param stage the shader stage
/// @param dir the direction of the IO usage
void CheckInterpolation(const CastableBase* anchor,
const core::type::Type* ty,
const IOAttributes& attr);
const IOAttributes& attr,
const Function::PipelineStage stage,
const IODirection dir);
/// Validates binding_point attributes on entry point IO.
/// @param anchor where to attach error messages to.
@@ -2482,17 +2486,45 @@ void Validator::CheckRootBlock(const Block* blk) {
block_stack_.Push(blk);
TINT_DEFER(block_stack_.Pop());
Hashset<const core::ir::Value*, 8> pipeline_evaluatable{};
auto add_evaluatable = [&](const Instruction* inst, const bool is_creatable) {
if (auto* res = inst->Result(0); res != nullptr && is_creatable) {
pipeline_evaluatable.Add(res);
}
};
for (auto* inst : *blk) {
if (inst->Block() != blk) {
AddError(inst) << "instruction in root block does not have root block as parent";
continue;
}
auto is_pipeline_creatable = true;
for (auto* op : inst->Operands()) {
if (!op) {
continue;
}
if (op->Is<core::ir::Constant>()) {
continue;
}
if (pipeline_evaluatable.Contains(op)) {
continue;
}
is_pipeline_creatable = false;
break;
}
if (!is_pipeline_creatable) {
AddError(inst) << "instruction is not evaluatable at pipeline creation time";
}
tint::Switch(
inst, //
[&](const core::ir::Override* o) {
if (capabilities_.Contains(Capability::kAllowOverrides)) {
CheckInstruction(o);
add_evaluatable(o, is_pipeline_creatable);
} else {
AddError(inst) << "root block: invalid instruction: " << inst->TypeInfo().name;
}
@@ -2501,6 +2533,7 @@ void Validator::CheckRootBlock(const Block* blk) {
[&](const core::ir::Let* let) {
if (capabilities_.Contains(Capability::kAllowModuleScopeLets)) {
CheckInstruction(let);
add_evaluatable(let, is_pipeline_creatable);
} else {
AddError(inst) << "root block: invalid instruction: " << inst->TypeInfo().name;
}
@@ -2510,16 +2543,15 @@ void Validator::CheckRootBlock(const Block* blk) {
capabilities_.Contains(Capability::kAllowOverrides)) {
CheckInstruction(c);
CheckOnlyUsedInRootBlock(inst);
add_evaluatable(c, is_pipeline_creatable);
} else {
AddError(inst) << "root block: invalid instruction: " << inst->TypeInfo().name;
}
},
[&](Default) {
// Note, this validation around kAllowOverrides is looser than it could be. There
// are only certain expressions and builtins which can be used in an override, but
// the current checks are only doing type level checking. To tighten this up will
// require walking up the tree to make sure that operands are const/override and
// builtins are allowed.
// are only certain expressions and builtins which can be used in an override, which
// currently isn't checked.
if (capabilities_.Contains(Capability::kAllowOverrides) &&
inst->IsAnyOf<core::ir::Unary, core::ir::Binary, core::ir::BuiltinCall,
core::ir::Convert, core::ir::Swizzle, core::ir::Access,
@@ -2529,6 +2561,7 @@ void Validator::CheckRootBlock(const Block* blk) {
// block, with the caveat that those instructions can _only_ be used in the root
// block.
CheckOnlyUsedInRootBlock(inst);
add_evaluatable(inst, is_pipeline_creatable);
} else {
AddError(inst) << "root block: invalid instruction: " << inst->TypeInfo().name;
}
@@ -2885,7 +2918,7 @@ void Validator::ValidateIOAttributes(const Function* func) {
// Validate all the interpolation usages.
for (const auto& task : tasks) {
CheckInterpolation(task.anchor, task.type, task.attr);
CheckInterpolation(task.anchor, task.type, task.attr, stage, task.dir);
}
if (stage != Function::PipelineStage::kUndefined) {
@@ -3116,18 +3149,10 @@ void Validator::CheckWorkgroupSize(const Function* func) {
return;
}
if (r->Instruction()->Is<core::ir::Override>()) {
continue;
}
// TODO(376624999): Finish implementing checking that this is a override/constant
// expression, i.e. calculated from only appropriate values/operations, once override
// implementation is complete
// for each value/operation used to calculate param:
// if not constant expression && not override expression:
// fail
// pass
// Since above, it is already checked if the value is in the root block, it is assumed
// to be pipeline creatable here, i.e. const/override or derived from consts and
// overrides.
// If that is not true, that indicates an issue in CheckRootBlock().
continue;
}
@@ -3640,20 +3665,15 @@ void Validator::CheckLocation(Hashmap<uint32_t, const CastableBase*, 4>& locatio
void Validator::CheckInterpolation(const CastableBase* anchor,
const core::type::Type* ty,
const IOAttributes& attr) {
const IOAttributes& attr,
const Function::PipelineStage stage,
const IODirection dir) {
bool ctx = false;
WalkTypeAndMembers(
ctx, ty, attr,
[this, anchor](bool& in_location_composite, const core::type::Type* t,
[this, anchor, stage, dir](bool& in_location_composite, const core::type::Type* t,
const IOAttributes& a) {
if (a.interpolation.has_value()) {
if (!capabilities_.Contains(Capability::kAllowLocationForNumericElements) &&
t->As<core::type::Struct>()) {
AddError(anchor) << "interpolation cannot be applied to a struct without "
"'kAllowLocationForNumericElements' capability";
}
bool has_location = a.location.has_value() || in_location_composite;
if (!has_location) {
if (auto* str = t->As<core::type::Struct>()) {
@@ -3661,9 +3681,24 @@ void Validator::CheckInterpolation(const CastableBase* anchor,
[](const auto* mem) { return mem->Attributes().location.has_value(); });
}
}
if (a.interpolation.has_value()) {
has_location |= (capabilities_.Contains(Capability::kLoosenValidationForShaderIO) &&
a.builtin.has_value());
if (!capabilities_.Contains(Capability::kAllowLocationForNumericElements) &&
t->As<core::type::Struct>()) {
AddError(anchor) << "interpolation cannot be applied to a struct without "
"'kAllowLocationForNumericElements' capability";
}
if (t->IsIntegerScalar()) {
if (a.interpolation.value().type != InterpolationType::kFlat) {
AddError(anchor)
<< "interpolation attribute type must be flat for integral types";
}
}
if (!has_location) {
if (!capabilities_.Contains(Capability::kLoosenValidationForShaderIO)) {
AddError(anchor) << "interpolation attribute requires a location attribute";
@@ -3672,9 +3707,20 @@ void Validator::CheckInterpolation(const CastableBase* anchor,
"(or location-like shader I/O annotation)";
}
}
} else if (has_location && t->IsIntegerScalarOrVector()) {
// Integral vertex outputs and fragment inputs require flat interpolation.
const bool needs_flat =
(stage == Function::PipelineStage::kVertex && dir == IODirection::kOutput) ||
(stage == Function::PipelineStage::kFragment && dir == IODirection::kInput);
if (needs_flat) {
AddError(anchor) << "integral user-defined inputs and outputs must have an "
"@interpolate(flat) attribute";
}
}
if (t->IsAnyOf<core::type::Array, core::type::Struct>()) {
in_location_composite |= a.location.has_value();
}
});
}

View File

@@ -1,40 +0,0 @@
// Copyright 2025 The Dawn & Tint Authors
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this
// list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "src/tint/lang/null/writer/common/options.h"
namespace tint::null::writer {
Options::Options() = default;
Options::~Options() = default;
Options::Options(const Options&) = default;
Options& Options::operator=(const Options&) = default;
} // namespace tint::null::writer

View File

@@ -1,64 +0,0 @@
// Copyright 2025 The Dawn & Tint Authors
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this
// list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#ifndef SRC_TINT_LANG_NULL_WRITER_COMMON_OPTIONS_H_
#define SRC_TINT_LANG_NULL_WRITER_COMMON_OPTIONS_H_
#include <string>
#include "src/tint/api/common/substitute_overrides_config.h"
#include "src/tint/utils/reflection.h"
namespace tint::null::writer {
/// Configuration options used for Null generator.
struct Options {
/// Constructor
Options();
/// Destructor
~Options();
/// Copy constructor
Options(const Options&);
/// Copy assignment
/// @returns this Options
Options& operator=(const Options&);
/// The entry point name to emit
std::string entry_point_name = {};
// Substitute Overrides
SubstituteOverridesConfig substitute_overrides_config = {};
/// Reflect the fields of this class so that it can be used by tint::ForeachField()
TINT_REFLECT(Options, entry_point_name, substitute_overrides_config);
TINT_REFLECT_EQUALS(Options);
TINT_REFLECT_HASH_CODE(Options);
};
} // namespace tint::null::writer
#endif // SRC_TINT_LANG_NULL_WRITER_COMMON_OPTIONS_H_

View File

@@ -1,40 +0,0 @@
// Copyright 2025 The Dawn & Tint Authors
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this
// list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "src/tint/lang/null/writer/common/output.h"
namespace tint::null::writer {
Output::Output() = default;
Output::~Output() = default;
Output::Output(const Output&) = default;
Output& Output::operator=(const Output&) = default;
} // namespace tint::null::writer

View File

@@ -1,70 +0,0 @@
// Copyright 2025 The Dawn & Tint Authors
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this
// list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#ifndef SRC_TINT_LANG_NULL_WRITER_COMMON_OUTPUT_H_
#define SRC_TINT_LANG_NULL_WRITER_COMMON_OUTPUT_H_
#include <cstddef>
#include <cstdint>
namespace tint::null::writer {
/// The output produced by Null writer
struct Output {
/// Constructor
Output();
/// Destructor
~Output();
/// Copy constructor
Output(const Output&);
/// Copy assignment
/// @returns this
Output& operator=(const Output&);
/// Workgroup size information
struct WorkgroupInfo {
/// The x-component
uint32_t x = 0;
/// The y-component
uint32_t y = 0;
/// The z-component
uint32_t z = 0;
/// The needed workgroup storage size
size_t storage_size = 0;
};
/// The workgroup size information, if the entry point was a compute shader
WorkgroupInfo workgroup_info{};
};
} // namespace tint::null::writer
#endif // SRC_TINT_LANG_NULL_WRITER_COMMON_OUTPUT_H_

View File

@@ -1,43 +0,0 @@
// Copyright 2025 The Dawn & Tint Authors
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this
// list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "src/tint/lang/null/writer/raise/raise.h"
#include "src/tint/lang/core/ir/module.h"
#include "src/tint/lang/core/ir/transform/single_entry_point.h"
#include "src/tint/lang/core/ir/transform/substitute_overrides.h"
namespace tint::null::writer {
Result<SuccessType> Raise(core::ir::Module& module, const Options& options) {
TINT_CHECK_RESULT(core::ir::transform::SingleEntryPoint(module, options.entry_point_name));
TINT_CHECK_RESULT(
core::ir::transform::SubstituteOverrides(module, options.substitute_overrides_config));
return Success;
}
} // namespace tint::null::writer

View File

@@ -1,49 +0,0 @@
// Copyright 2025 The Dawn & Tint Authors
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this
// list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#ifndef SRC_TINT_LANG_NULL_WRITER_RAISE_RAISE_H_
#define SRC_TINT_LANG_NULL_WRITER_RAISE_RAISE_H_
#include "src/tint/lang/null/writer/common/options.h"
#include "src/tint/utils/result.h"
// Forward declarations
namespace tint::core::ir {
class Module;
} // namespace tint::core::ir
namespace tint::null::writer {
/// Run the `Raise` transform of an IR module for the Null backend.
/// @param module the core IR module to raise to Null dialect
/// @param options the printer options
/// @returns success or failure
Result<SuccessType> Raise(core::ir::Module& module, const Options& options);
} // namespace tint::null::writer
#endif // SRC_TINT_LANG_NULL_WRITER_RAISE_RAISE_H_

View File

@@ -1,54 +0,0 @@
// Copyright 2025 The Dawn & Tint Authors
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this
// list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "src/tint/lang/null/writer/writer.h"
#include "src/tint/lang/core/ir/module.h"
#include "src/tint/lang/core/ir/reflection.h"
#include "src/tint/lang/core/ir/validator.h"
#include "src/tint/lang/null/writer/raise/raise.h"
namespace tint::null::writer {
Result<Output> Generate(core::ir::Module& ir, const Options& options) {
Output output;
// Raise from core-dialect
TINT_CHECK_RESULT(Raise(ir, options));
TINT_CHECK_RESULT_UNWRAP(wg_info, GetWorkgroupInfo(ir));
output.workgroup_info = {
.x = wg_info.x,
.y = wg_info.y,
.z = wg_info.z,
.storage_size = wg_info.storage_size,
};
return output;
}
} // namespace tint::null::writer

View File

@@ -1,51 +0,0 @@
// Copyright 2025 The Dawn & Tint Authors
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this
// list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#ifndef SRC_TINT_LANG_NULL_WRITER_WRITER_H_
#define SRC_TINT_LANG_NULL_WRITER_WRITER_H_
#include "src/tint/lang/null/writer/common/options.h"
#include "src/tint/lang/null/writer/common/output.h"
#include "src/tint/utils/result.h"
// Forward declarations
namespace tint::core::ir {
class Module;
} // namespace tint::core::ir
namespace tint::null::writer {
/// Run generator for the Null backend, according to a set of configuration options.
/// The result will contain the supplementary information, or failure.
/// @param ir the IR module
/// @param options the configuration options to use
/// @returns the supplementary information, or failure
Result<Output> Generate(core::ir::Module& ir, const Options& options);
} // namespace tint::null::writer
#endif // SRC_TINT_LANG_NULL_WRITER_WRITER_H_

View File

@@ -106,6 +106,9 @@ struct Options {
/// Set to `true` to generate polyfill for f32 abs.
bool polyfill_f32_abs = false;
/// Set to `true` to generate polyfill for f16 saturate.
bool polyfill_saturate_as_min_max_f16 = false;
TINT_REFLECT(Workarounds,
polyfill_case_switch,
scalarize_max_min_clamp,
@@ -116,7 +119,8 @@ struct Options {
polyfill_subgroup_broadcast_f16,
pass_matrix_by_pointer,
polyfill_unary_f32_negation,
polyfill_f32_abs);
polyfill_f32_abs,
polyfill_saturate_as_min_max_f16);
};
/// Any options which are controlled by the presence/absence of a vulkan extension.

View File

@@ -134,6 +134,7 @@ Result<SuccessType> Raise(core::ir::Module& module, const Options& options) {
core_polyfills.pack_unpack_4x8_norm = options.workarounds.polyfill_pack_unpack_4x8_norm;
core_polyfills.abs_signed_int = true;
core_polyfills.subgroup_broadcast_f16 = options.workarounds.polyfill_subgroup_broadcast_f16;
core_polyfills.saturate_as_min_max = options.workarounds.polyfill_saturate_as_min_max_f16;
TINT_CHECK_RESULT(core::ir::transform::BuiltinPolyfill(module, core_polyfills));
core::ir::transform::ConversionPolyfillConfig conversion_polyfills;

View File

@@ -69,9 +69,6 @@ Extension ParseExtension(std::string_view str) {
if (str == "chromium_experimental_subgroup_size_control") {
return Extension::kChromiumExperimentalSubgroupSizeControl;
}
if (str == "chromium_internal_graphite") {
return Extension::kChromiumInternalGraphite;
}
if (str == "chromium_internal_input_attachments") {
return Extension::kChromiumInternalInputAttachments;
}
@@ -110,8 +107,6 @@ std::string_view ToString(Extension value) {
return "chromium_experimental_subgroup_matrix";
case Extension::kChromiumExperimentalSubgroupSizeControl:
return "chromium_experimental_subgroup_size_control";
case Extension::kChromiumInternalGraphite:
return "chromium_internal_graphite";
case Extension::kChromiumInternalInputAttachments:
return "chromium_internal_input_attachments";
case Extension::kClipDistances:

View File

@@ -121,7 +121,6 @@ enum class Extension : uint8_t {
kChromiumExperimentalResourceTable,
kChromiumExperimentalSubgroupMatrix,
kChromiumExperimentalSubgroupSizeControl,
kChromiumInternalGraphite,
kChromiumInternalInputAttachments,
kClipDistances,
kDualSourceBlending,
@@ -156,7 +155,6 @@ constexpr std::string_view kExtensionStrings[] = {
"chromium_experimental_resource_table",
"chromium_experimental_subgroup_matrix",
"chromium_experimental_subgroup_size_control",
"chromium_internal_graphite",
"chromium_internal_input_attachments",
"clip_distances",
"dual_source_blending",
@@ -174,7 +172,6 @@ static constexpr Extension kAllExtensions[] = {
Extension::kChromiumExperimentalResourceTable,
Extension::kChromiumExperimentalSubgroupMatrix,
Extension::kChromiumExperimentalSubgroupSizeControl,
Extension::kChromiumInternalGraphite,
Extension::kChromiumInternalInputAttachments,
Extension::kClipDistances,
Extension::kDualSourceBlending,

View File

@@ -1,270 +0,0 @@
// Copyright 2023 The Dawn & Tint Authors
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this
// list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "src/tint/lang/wgsl/reader/lower/lower.h"
#include <utility>
#include "src/tint/lang/core/enums.h"
#include "src/tint/lang/core/ir/builder.h"
#include "src/tint/lang/core/ir/core_builtin_call.h"
#include "src/tint/lang/core/ir/validator.h"
#include "src/tint/lang/wgsl/enums.h"
#include "src/tint/lang/wgsl/ir/builtin_call.h"
#include "src/tint/utils/ice/ice.h"
namespace tint::wgsl::reader {
namespace {
core::BuiltinFn Convert(wgsl::BuiltinFn fn) {
#define CASE(NAME) \
case wgsl::BuiltinFn::NAME: \
return core::BuiltinFn::NAME;
switch (fn) {
CASE(kAbs)
CASE(kAcos)
CASE(kAcosh)
CASE(kAll)
CASE(kAny)
CASE(kArrayLength)
CASE(kAsin)
CASE(kAsinh)
CASE(kAtan)
CASE(kAtan2)
CASE(kAtanh)
CASE(kCeil)
CASE(kClamp)
CASE(kCos)
CASE(kCosh)
CASE(kCountLeadingZeros)
CASE(kCountOneBits)
CASE(kCountTrailingZeros)
CASE(kCross)
CASE(kDegrees)
CASE(kDeterminant)
CASE(kDistance)
CASE(kDot)
CASE(kDot4I8Packed)
CASE(kDot4U8Packed)
CASE(kDpdx)
CASE(kDpdxCoarse)
CASE(kDpdxFine)
CASE(kDpdy)
CASE(kDpdyCoarse)
CASE(kDpdyFine)
CASE(kExp)
CASE(kExp2)
CASE(kExtractBits)
CASE(kFaceForward)
CASE(kFirstLeadingBit)
CASE(kFirstTrailingBit)
CASE(kFloor)
CASE(kFma)
CASE(kFract)
CASE(kFrexp)
CASE(kFwidth)
CASE(kFwidthCoarse)
CASE(kFwidthFine)
CASE(kInsertBits)
CASE(kInverseSqrt)
CASE(kLdexp)
CASE(kLength)
CASE(kLog)
CASE(kLog2)
CASE(kMax)
CASE(kMin)
CASE(kMix)
CASE(kModf)
CASE(kNormalize)
CASE(kPack2X16Float)
CASE(kPack2X16Snorm)
CASE(kPack2X16Unorm)
CASE(kPack4X8Snorm)
CASE(kPack4X8Unorm)
CASE(kPack4XI8)
CASE(kPack4XU8)
CASE(kPack4XI8Clamp)
CASE(kPack4XU8Clamp)
CASE(kPow)
CASE(kQuantizeToF16)
CASE(kRadians)
CASE(kReflect)
CASE(kRefract)
CASE(kReverseBits)
CASE(kRound)
CASE(kSaturate)
CASE(kSelect)
CASE(kSign)
CASE(kSin)
CASE(kSinh)
CASE(kSmoothstep)
CASE(kSqrt)
CASE(kStep)
CASE(kStorageBarrier)
CASE(kTan)
CASE(kTanh)
CASE(kTranspose)
CASE(kTrunc)
CASE(kUnpack2X16Float)
CASE(kUnpack2X16Snorm)
CASE(kUnpack2X16Unorm)
CASE(kUnpack4X8Snorm)
CASE(kUnpack4X8Unorm)
CASE(kUnpack4XI8)
CASE(kUnpack4XU8)
CASE(kWorkgroupBarrier)
CASE(kTextureBarrier)
CASE(kTextureDimensions)
CASE(kTextureGather)
CASE(kTextureGatherCompare)
CASE(kTextureNumLayers)
CASE(kTextureNumLevels)
CASE(kTextureNumSamples)
CASE(kTextureSample)
CASE(kTextureSampleBias)
CASE(kTextureSampleCompare)
CASE(kTextureSampleCompareLevel)
CASE(kTextureSampleGrad)
CASE(kTextureSampleLevel)
CASE(kTextureSampleBaseClampToEdge)
CASE(kTextureStore)
CASE(kTextureLoad)
CASE(kAtomicLoad)
CASE(kAtomicStore)
CASE(kAtomicAdd)
CASE(kAtomicSub)
CASE(kAtomicMax)
CASE(kAtomicMin)
CASE(kAtomicAnd)
CASE(kAtomicOr)
CASE(kAtomicXor)
CASE(kAtomicExchange)
CASE(kAtomicCompareExchangeWeak)
CASE(kSubgroupBallot)
CASE(kSubgroupElect)
CASE(kSubgroupBroadcast)
CASE(kSubgroupBroadcastFirst)
CASE(kSubgroupShuffle)
CASE(kSubgroupShuffleXor)
CASE(kSubgroupShuffleUp)
CASE(kSubgroupShuffleDown)
CASE(kInputAttachmentLoad)
CASE(kSubgroupAdd)
CASE(kSubgroupInclusiveAdd)
CASE(kSubgroupExclusiveAdd)
CASE(kSubgroupMul)
CASE(kSubgroupInclusiveMul)
CASE(kSubgroupExclusiveMul)
CASE(kSubgroupAnd)
CASE(kSubgroupOr)
CASE(kSubgroupXor)
CASE(kSubgroupMin)
CASE(kSubgroupMax)
CASE(kSubgroupAll)
CASE(kSubgroupAny)
CASE(kQuadBroadcast)
CASE(kQuadSwapX)
CASE(kQuadSwapY)
CASE(kQuadSwapDiagonal)
CASE(kSubgroupMatrixLoad)
CASE(kSubgroupMatrixStore)
CASE(kSubgroupMatrixMultiply)
CASE(kSubgroupMatrixMultiplyAccumulate)
CASE(kSubgroupMatrixScalarAdd)
CASE(kSubgroupMatrixScalarSubtract)
CASE(kSubgroupMatrixScalarMultiply)
CASE(kPrint)
CASE(kHasResource)
CASE(kGetResource)
CASE(kBufferView)
CASE(kBufferLength)
case tint::wgsl::BuiltinFn::kBitcast: // should lower to ir::Bitcast
case tint::wgsl::BuiltinFn::kWorkgroupUniformLoad: // should be handled in Lower()
case tint::wgsl::BuiltinFn::kTintMaterialize:
case tint::wgsl::BuiltinFn::kNone:
break;
}
TINT_ICE() << "unhandled builtin function: " << fn;
}
} // namespace
Result<SuccessType> Lower(core::ir::Module& mod) {
TINT_CHECK_RESULT(
core::ir::ValidateAndDumpIfNeeded(mod, "wgsl.Lower",
core::ir::Capabilities{
core::ir::Capability::kAllowMultipleEntryPoints,
core::ir::Capability::kAllowOverrides,
core::ir::Capability::kAllow8BitIntegers,
}));
core::ir::Builder b{mod};
core::type::Manager& ty{mod.Types()};
for (auto* inst : mod.Instructions()) {
if (auto* call = inst->As<wgsl::ir::BuiltinCall>()) {
switch (call->Func()) {
case BuiltinFn::kWorkgroupUniformLoad: {
auto* param0 = call->Args()[0];
TINT_ASSERT(param0->Type()->Is<core::type::Pointer>());
auto* storeType = param0->Type()->As<core::type::Pointer>()->StoreType();
// Replace:
// %value = call workgroupUniformLoad %ptr
// With:
// call workgroupBarrier
// %value = {load || atomicLoad} &ptr
// call workgroupBarrier
b.InsertBefore(call, [&] {
b.Call(ty.void_(), core::BuiltinFn::kWorkgroupBarrier);
if (storeType->Is<core::type::Atomic>()) {
b.CallWithResult(call->DetachResult(), core::BuiltinFn::kAtomicLoad,
param0);
} else {
b.LoadWithResult(call->DetachResult(), param0);
}
b.Call(ty.void_(), core::BuiltinFn::kWorkgroupBarrier);
});
break;
}
default: {
Vector<core::ir::Value*, 8> args(call->Args());
auto* replacement = b.CallWithResult(call->DetachResult(),
Convert(call->Func()), std::move(args));
if (!call->ExplicitTemplateParams().IsEmpty()) {
replacement->SetExplicitTemplateParams(call->ExplicitTemplateParams());
}
call->ReplaceWith(replacement);
break;
}
}
call->Destroy();
}
}
return Success;
}
} // namespace tint::wgsl::reader

View File

@@ -1,43 +0,0 @@
// Copyright 2023 The Dawn & Tint Authors
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this
// list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#ifndef SRC_TINT_LANG_WGSL_READER_LOWER_LOWER_H_
#define SRC_TINT_LANG_WGSL_READER_LOWER_LOWER_H_
#include "src/tint/lang/core/ir/module.h"
#include "src/tint/utils/result.h"
namespace tint::wgsl::reader {
/// Lower converts a WGSL-dialect IR module to a core-dialect IR module
/// @param mod the IR module
/// @return the result of the operation
Result<SuccessType> Lower(core::ir::Module& mod);
} // namespace tint::wgsl::reader
#endif // SRC_TINT_LANG_WGSL_READER_LOWER_LOWER_H_

View File

@@ -1,47 +0,0 @@
// Copyright 2023 The Dawn & Tint Authors
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this
// list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#ifndef SRC_TINT_LANG_WGSL_READER_OPTIONS_H_
#define SRC_TINT_LANG_WGSL_READER_OPTIONS_H_
#include "src/tint/lang/wgsl/allowed_features.h"
#include "src/tint/utils/reflection.h"
namespace tint::wgsl::reader {
/// Configuration options used for reading WGSL.
struct Options {
/// The extensions and language features that are allowed to be used.
AllowedFeatures allowed_features{};
/// Reflect the fields of this class so that it can be used by tint::ForeachField().
TINT_REFLECT(Options, allowed_features);
};
} // namespace tint::wgsl::reader
#endif // SRC_TINT_LANG_WGSL_READER_OPTIONS_H_

View File

@@ -1,157 +0,0 @@
// Copyright 2023 The Dawn & Tint Authors
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this
// list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "src/tint/lang/wgsl/reader/parser/classify_template_args.h"
#include <vector>
#include "src/tint/utils/containers/vector.h"
#include "src/tint/utils/ice/ice.h"
namespace tint::wgsl::reader {
namespace {
/// If the token at index @p idx is a '>>', '>=' or '>>=', then the token is split into two, with
/// the first being '>', otherwise MaybeSplit() will be a no-op.
/// @param tokens the vector of tokens
/// @param idx the index of the token to (maybe) split
void MaybeSplit(std::vector<Token>& tokens, size_t idx) {
auto* cur = &tokens[idx];
auto* next = &tokens[idx + 1];
TINT_ASSERT(cur);
TINT_ASSERT(next);
switch (cur->type()) {
case Token::Type::kShiftRight: // '>>'
TINT_ASSERT(next->type() == Token::Type::kPlaceholder);
cur->SetType(Token::Type::kGreaterThan);
next->SetType(Token::Type::kGreaterThan);
break;
case Token::Type::kGreaterThanEqual: // '>='
TINT_ASSERT(next->type() == Token::Type::kPlaceholder);
cur->SetType(Token::Type::kGreaterThan);
next->SetType(Token::Type::kEqual);
break;
case Token::Type::kShiftRightEqual: // '>>='
TINT_ASSERT(next->type() == Token::Type::kPlaceholder);
cur->SetType(Token::Type::kGreaterThan);
next->SetType(Token::Type::kGreaterThanEqual);
break;
default:
break;
}
}
} // namespace
void ClassifyTemplateArguments(std::vector<Token>& tokens) {
const size_t count = tokens.size();
// The current expression nesting depth.
// Each '(', '[' increments the depth.
// Each ')', ']' decrements the depth.
uint64_t expr_depth = 0;
// A stack of '<' tokens.
// Used to pair '<' and '>' tokens at the same expression depth.
struct StackEntry {
Token* token; // A pointer to the opening '<' token
uint64_t expr_depth; // The value of 'expr_depth' for the opening '<'
};
Vector<StackEntry, 16> stack;
for (size_t i = 0; i < count - 1; i++) {
switch (tokens[i].type()) {
case Token::Type::kIdentifier:
case Token::Type::kVar: {
auto& next = tokens[i + 1];
if (next.type() == Token::Type::kLessThan) {
// ident '<'
// Push this '<' to the stack, along with the current nesting expr_depth.
stack.Push(StackEntry{&tokens[i + 1], expr_depth});
i++; // Skip the '<'
}
break;
}
case Token::Type::kGreaterThan: // '>'
case Token::Type::kShiftRight: // '>>'
case Token::Type::kGreaterThanEqual: // '>='
case Token::Type::kShiftRightEqual: // '>>='
if (!stack.IsEmpty() && stack.Back().expr_depth == expr_depth) {
// '<' and '>' at same expr_depth, and no terminating tokens in-between.
// Consider both as a template argument list.
MaybeSplit(tokens, i);
stack.Pop().token->SetType(Token::Type::kTemplateArgsLeft);
tokens[i].SetType(Token::Type::kTemplateArgsRight);
}
break;
case Token::Type::kParenLeft: // '('
case Token::Type::kBracketLeft: // '['
// Entering a nested expression
expr_depth++;
break;
case Token::Type::kParenRight: // ')'
case Token::Type::kBracketRight: // ']'
// Exiting a nested expression
// Pop the stack until we return to the current expression expr_depth
while (!stack.IsEmpty() && stack.Back().expr_depth == expr_depth) {
stack.Pop();
}
if (expr_depth > 0) {
expr_depth--;
}
break;
case Token::Type::kSemicolon: // ';'
case Token::Type::kBraceLeft: // '{'
case Token::Type::kEqual: // '='
case Token::Type::kColon: // ':'
// Expression terminating tokens. No opening template list can hold these tokens, so
// clear the stack and expression depth.
expr_depth = 0;
stack.Clear();
break;
case Token::Type::kOrOr: // '||'
case Token::Type::kAndAnd: // '&&'
// Treat 'a < b || c > d' as a logical binary operator of two comparison operators
// instead of a single template argument 'b||c'.
// Use parentheses around 'b||c' to parse as a template argument list.
while (!stack.IsEmpty() && stack.Back().expr_depth == expr_depth) {
stack.Pop();
}
break;
default:
break;
}
}
}
} // namespace tint::wgsl::reader

View File

@@ -1,41 +0,0 @@
// Copyright 2023 The Dawn & Tint Authors
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this
// list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#ifndef SRC_TINT_LANG_WGSL_READER_PARSER_CLASSIFY_TEMPLATE_ARGS_H_
#define SRC_TINT_LANG_WGSL_READER_PARSER_CLASSIFY_TEMPLATE_ARGS_H_
#include <vector>
#include "src/tint/lang/wgsl/reader/parser/token.h"
namespace tint::wgsl::reader {
void ClassifyTemplateArguments(std::vector<Token>& tokens);
} // namespace tint::wgsl::reader
#endif // SRC_TINT_LANG_WGSL_READER_PARSER_CLASSIFY_TEMPLATE_ARGS_H_

View File

@@ -1,77 +0,0 @@
// Copyright 2020 The Dawn & Tint Authors
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this
// list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#ifndef SRC_TINT_LANG_WGSL_READER_PARSER_DETAIL_H_
#define SRC_TINT_LANG_WGSL_READER_PARSER_DETAIL_H_
#include <memory>
namespace tint::wgsl::reader::detail {
/// OperatorArrow is a traits helper for ParserImpl::Expect<T>::operator->() and
/// ParserImpl::Maybe<T>::operator->() so that pointer types are automatically
/// dereferenced. This simplifies usage by allowing
/// `result.value->field`
/// to be written as:
/// `result->field`
/// As well as reducing the amount of code, using the operator->() asserts that
/// the Expect<T> or Maybe<T> is not in an error state before dereferencing.
template <typename T>
struct OperatorArrow {
/// type resolves to the return type for the operator->()
using type = T*;
/// @param val the value held by `ParserImpl::Expect<T>` or
/// `ParserImpl::Maybe<T>`.
/// @return a pointer to `val`
static inline T* ptr(T& val) { return &val; }
};
/// OperatorArrow template specialization for std::unique_ptr<>.
template <typename T>
struct OperatorArrow<std::unique_ptr<T>> {
/// type resolves to the return type for the operator->()
using type = T*;
/// @param val the value held by `ParserImpl::Expect<T>` or
/// `ParserImpl::Maybe<T>`.
/// @return the raw pointer held by `val`.
static inline T* ptr(std::unique_ptr<T>& val) { return val.get(); }
};
/// OperatorArrow template specialization for T*.
template <typename T>
struct OperatorArrow<T*> {
/// type resolves to the return type for the operator->()
using type = T*;
/// @param val the value held by `ParserImpl::Expect<T>` or
/// `ParserImpl::Maybe<T>`.
/// @return `val`.
static inline T* ptr(T* val) { return val; }
};
} // namespace tint::wgsl::reader::detail
#endif // SRC_TINT_LANG_WGSL_READER_PARSER_DETAIL_H_

File diff suppressed because it is too large Load Diff

View File

@@ -1,134 +0,0 @@
// Copyright 2020 The Dawn & Tint Authors
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this
// list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#ifndef SRC_TINT_LANG_WGSL_READER_PARSER_LEXER_H_
#define SRC_TINT_LANG_WGSL_READER_PARSER_LEXER_H_
#include <optional>
#include <vector>
#include "src/tint/lang/wgsl/reader/parser/token.h"
namespace tint::wgsl::reader {
/// Converts the input stream into a series of Tokens
class Lexer {
public:
/// Creates a new Lexer
/// @param file the source file
explicit Lexer(const Source::File* file);
~Lexer();
/// @return the token list.
std::vector<Token> Lex();
private:
/// Returns the next token in the input stream.
/// @return Token
Token next();
/// Advances past blankspace and comments, if present at the current position.
/// @returns error token, EOF, or uninitialized
std::optional<Token> skip_blankspace_and_comments();
/// Advances past a comment at the current position, if one exists.
/// Returns an error if there was an unterminated block comment,
/// or a null character was present.
/// @returns uninitialized token on success, or error
std::optional<Token> skip_comment();
Token build_token_from_int_if_possible(Source source,
uint32_t start,
uint32_t prefix_count,
int32_t base);
std::optional<Token::Type> parse_keyword(std::string_view);
/// The try_* methods have the following in common:
/// - They assume there is at least one character to be consumed,
/// i.e. the input has not yet reached end of file.
/// - They return an initialized token when they match and consume
/// a token of the specified kind.
/// - Some can return an error token.
/// - Otherwise they return an uninitialized token when they did not
/// match a token of the specfied kind.
std::optional<Token> try_float();
std::optional<Token> try_hex_float();
std::optional<Token> try_hex_integer();
std::optional<Token> try_ident();
std::optional<Token> try_integer();
std::optional<Token> try_punctuation();
Source begin_source() const;
void end_source(Source&) const;
/// @returns view of current line
std::string_view line() const;
/// @returns position in current line
uint32_t pos() const;
/// @returns length of current line
uint32_t length() const;
/// @returns reference to character at `pos` within current line
const char& at(uint32_t pos) const;
/// @returns a point to the character just beyond the end of the current line, similar to how
/// std::end works
const char* line_end() const;
/// @returns substring view at `offset` within current line of length `count`
std::string_view substr(uint32_t offset, uint32_t count);
/// advances current position by `offset` within current line
void advance(uint32_t offset = 1);
/// sets current position to `pos` within current line
void set_pos(uint32_t pos);
/// advances current position to next line
void advance_line();
/// @returns true if the current position contains a BOM
bool is_bom() const;
/// @returns true if the end of the input has been reached.
bool is_eof() const;
/// @returns true if the end of the current line has been reached.
bool is_eol() const;
/// @returns true if there is another character on the input and
/// it is not null.
bool is_null() const;
/// @param ch a character
/// @returns true if 'ch' is a decimal digit
bool is_digit(char ch) const;
/// @param ch a character
/// @returns true if 'ch' is a hexadecimal digit
bool is_hex(char ch) const;
/// @returns true if string at `pos` matches `substr`
bool matches(uint32_t pos, std::string_view substr);
/// @returns true if char at `pos` matches `ch`
bool matches(uint32_t pos, char ch);
/// The source file content
Source::File const* const file_;
/// The current location within the input
Source::Location location_;
};
} // namespace tint::wgsl::reader
#endif // SRC_TINT_LANG_WGSL_READER_PARSER_LEXER_H_

File diff suppressed because it is too large Load Diff

View File

@@ -1,927 +0,0 @@
// Copyright 2020 The Dawn & Tint Authors
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this
// list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#ifndef SRC_TINT_LANG_WGSL_READER_PARSER_PARSER_H_
#define SRC_TINT_LANG_WGSL_READER_PARSER_PARSER_H_
#include <memory>
#include <string>
#include <string_view>
#include <unordered_map>
#include <utility>
#include <vector>
#include "src/tint/lang/core/enums.h"
#include "src/tint/lang/wgsl/program/program_builder.h"
#include "src/tint/lang/wgsl/reader/parser/detail.h"
#include "src/tint/lang/wgsl/reader/parser/token.h"
#include "src/tint/lang/wgsl/resolver/resolve.h"
#include "src/tint/utils/diagnostic/formatter.h"
#include "src/tint/utils/text/styled_text.h"
namespace tint::ast {
class BreakStatement;
class CallStatement;
class ContinueStatement;
class IfStatement;
class LoopStatement;
class ReturnStatement;
class SwitchStatement;
class VariableDeclStatement;
} // namespace tint::ast
namespace tint::wgsl::reader {
class Lexer;
/// Struct holding information for a for loop
struct ForHeader {
/// Constructor
/// @param init the initializer statement
/// @param cond the condition statement
/// @param cont the continuing statement
ForHeader(const ast::Statement* init, const ast::Expression* cond, const ast::Statement* cont);
~ForHeader();
/// The for loop initializer
const ast::Statement* initializer = nullptr;
/// The for loop condition
const ast::Expression* condition = nullptr;
/// The for loop continuing statement
const ast::Statement* continuing = nullptr;
};
/// Parser for WGSL source data
class Parser {
/// Failure holds enumerator values used for the constructing an Expect and
/// Match in an errored state.
struct Failure {
enum Errored { kErrored };
enum NoMatch { kNoMatch };
};
public:
/// Pre-determined small vector sizes for AST pointers
//! @cond Doxygen_Suppress
using AttributeList = Vector<const ast::Attribute*, 4>;
using CaseSelectorList = Vector<const ast::CaseSelector*, 4>;
using CaseStatementList = Vector<const ast::CaseStatement*, 4>;
using ExpressionList = Vector<const ast::Expression*, 8>;
using ParameterList = Vector<const ast::Parameter*, 8>;
using StatementList = Vector<const ast::Statement*, 8>;
using StructMemberList = Vector<const ast::StructMember*, 8>;
//! @endcond
/// Empty structure used by functions that do not return a value, but need to signal success /
/// error with Expect<Void> or Maybe<NoError>.
struct Void {};
/// Expect is the return type of the parser methods that are expected to
/// return a parsed value of type T, unless there was an parse error.
/// In the case of a parse error the called method will have called
/// AddError() and #errored will be set to true.
template <typename T>
struct Expect {
/// An alias to the templated type T.
using type = T;
/// Don't allow an Expect to take a nullptr.
inline Expect(std::nullptr_t) = delete; // NOLINT
/// Constructor for a successful parse.
/// @param val the result value of the parse
template <typename U>
inline Expect(U&& val) // NOLINT
: value(std::forward<U>(val)) {}
/// Constructor for parse error.
inline Expect(Failure::Errored) : errored(true) {} // NOLINT
/// Copy constructor
inline Expect(const Expect&) = default;
/// Move constructor
inline Expect(Expect&&) = default;
/// Assignment operator
/// @return this Expect
inline Expect& operator=(const Expect&) = default;
/// Assignment move operator
/// @return this Expect
inline Expect& operator=(Expect&&) = default;
/// @return a pointer to the returned value. If T is a pointer or
/// std::unique_ptr, operator->() automatically dereferences so that the
/// return type will always be a pointer to a non-pointer type. #errored
/// must be false to call.
inline typename detail::OperatorArrow<T>::type operator->() {
TINT_ASSERT(!errored);
return detail::OperatorArrow<T>::ptr(value);
}
/// The expected value of a successful parse.
/// Zero-initialized when there was a parse error.
T value{};
/// True if there was a error parsing.
bool errored = false;
};
/// Maybe is the return type of the parser methods that attempts to match a
/// grammar and return a parsed value of type T, or may parse part of the
/// grammar and then hit a parse error.
/// In the case of a successful grammar match, the Maybe will have #matched
/// set to true.
/// In the case of a parse error the called method will have called
/// AddError() and the Maybe will have #errored set to true.
template <typename T>
struct Maybe {
inline Maybe(std::nullptr_t) = delete; // NOLINT
/// Constructor for a successful parse.
/// @param val the result value of the parse
template <typename U>
inline Maybe(U&& val) // NOLINT
: value(std::forward<U>(val)), matched(true) {}
/// Constructor for parse error state.
inline Maybe(Failure::Errored) : errored(true) {} // NOLINT
/// Constructor for the no-match state.
inline Maybe(Failure::NoMatch) {} // NOLINT
/// Constructor from an Expect.
/// @param e the Expect to copy this Maybe from
template <typename U>
inline Maybe(const Expect<U>& e) // NOLINT
: value(e.value), errored(e.errored), matched(!e.errored) {}
/// Move from an Expect.
/// @param e the Expect to move this Maybe from
template <typename U>
inline Maybe(Expect<U>&& e) // NOLINT
: value(std::move(e.value)), errored(e.errored), matched(!e.errored) {}
/// Copy constructor
inline Maybe(const Maybe&) = default;
/// Move constructor
inline Maybe(Maybe&&) = default;
/// Assignment operator
/// @return this Maybe
inline Maybe& operator=(const Maybe&) = default;
/// Assignment move operator
/// @return this Maybe
inline Maybe& operator=(Maybe&&) = default;
/// @return a pointer to the returned value. If T is a pointer or
/// std::unique_ptr, operator->() automatically dereferences so that the
/// return type will always be a pointer to a non-pointer type. #errored
/// must be false to call.
inline typename detail::OperatorArrow<T>::type operator->() {
TINT_ASSERT(!errored);
return detail::OperatorArrow<T>::ptr(value);
}
/// The value of a successful parse.
/// Zero-initialized when there was a parse error.
T value{};
/// True if there was a error parsing.
bool errored = false;
/// True if there was a error parsing.
bool matched = false;
};
/// TypedIdentifier holds a parsed identifier and type. Returned by
/// variable_ident_decl().
struct TypedIdentifier {
/// Constructor
TypedIdentifier();
/// Copy constructor
/// @param other the FunctionHeader to copy
TypedIdentifier(const TypedIdentifier& other);
/// Constructor
/// @param type_in parsed type
/// @param name_in parsed identifier
TypedIdentifier(ast::Type type_in, const ast::Identifier* name_in);
/// Destructor
~TypedIdentifier();
/// Parsed type. type.expr be nullptr for inferred types.
ast::Type type;
/// Parsed identifier.
const ast::Identifier* name = nullptr;
};
/// FunctionHeader contains the parsed information for a function header.
struct FunctionHeader {
/// Constructor
FunctionHeader();
/// Copy constructor
/// @param other the FunctionHeader to copy
FunctionHeader(const FunctionHeader& other);
/// Constructor
/// @param src parsed header source
/// @param n function name
/// @param p function parameters
/// @param ret_ty function return type
/// @param ret_attrs return type attributes
FunctionHeader(Source src,
const ast::Identifier* n,
VectorRef<const ast::Parameter*> p,
ast::Type ret_ty,
VectorRef<const ast::Attribute*> ret_attrs);
/// Destructor
~FunctionHeader();
/// Assignment operator
/// @param other the FunctionHeader to copy
/// @returns this FunctionHeader
FunctionHeader& operator=(const FunctionHeader& other);
/// Parsed header source
Source source;
/// Function name
const ast::Identifier* name;
/// Function parameters
Vector<const ast::Parameter*, 8> params;
/// Function return type
ast::Type return_type;
/// Function return type attributes
AttributeList return_type_attributes;
};
/// VarDeclInfo contains the parsed information for variable declaration.
struct VarDeclInfo {
/// Variable declaration source
Source source;
/// Variable name
const ast::Identifier* name = nullptr;
/// Variable address space
const ast::Expression* address_space = nullptr;
/// Variable access control
const ast::Expression* access = nullptr;
/// Variable type
ast::Type type;
};
/// VariableQualifier contains the parsed information for a variable qualifier
struct VariableQualifier {
/// The variable's address space
const ast::Expression* address_space = nullptr;
/// The variable's access control
const ast::Expression* access = nullptr;
};
/// MatrixDimensions contains the column and row information for a matrix
struct MatrixDimensions {
/// The number of columns
uint32_t columns = 0;
/// The number of rows
uint32_t rows = 0;
};
/// Creates a new parser using the given file
/// @param file the input source file to parse
explicit Parser(Source::File const* file);
~Parser();
/// Reads tokens from the source file. This will be called automatically
/// by |parse|.
void InitializeLex();
/// Run the parser
/// @returns true if the parse was successful, false otherwise.
bool Parse();
/// set_max_diagnostics sets the maximum number of reported errors before
/// aborting parsing.
/// @param limit the new maximum number of errors
void set_max_errors(size_t limit) { max_errors_ = limit; }
/// @return the number of maximum number of reported errors before aborting
/// parsing.
size_t get_max_errors() const { return max_errors_; }
/// @returns true if an error was encountered.
bool has_error() const { return builder_.Diagnostics().ContainsErrors(); }
/// @returns the parser error string
std::string error() const {
diag::Formatter formatter{{false, false, false, false}};
return formatter.Format(builder_.Diagnostics()).Plain();
}
/// @returns the Program. The program builder in the parser will be reset
/// after this.
Program program() { return resolver::Resolve(builder_); }
/// @returns the program builder.
ProgramBuilder& builder() { return builder_; }
/// @returns the next token
const Token& next();
/// Peeks ahead and returns the token at `idx` ahead of the current position
/// @param idx the index of the token to return
/// @returns the token `idx` positions ahead without advancing
const Token& peek(size_t idx = 0);
/// Peeks ahead and returns true if the token at `idx` ahead of the current
/// position is |tok|
/// @param idx the index of the token to return
/// @param tok the token to look for
/// @returns true if the token `idx` positions ahead is |tok|
bool peek_is(Token::Type tok, size_t idx = 0);
/// @returns the last source location that was returned by `next()`
Source last_source() const;
/// Appends an error at `t` with the message `msg`
/// @param t the token to associate the error with
/// @param msg the error message
/// @return `Failure::Errored::kError` so that you can combine an AddError()
/// call and return on the same line.
Failure::Errored AddError(const Token& t, std::string_view msg);
/// Appends an error raised when parsing `use` at `t` with the message
/// `msg`
/// @param source the source to associate the error with
/// @param msg the error message
/// @param use a description of what was being parsed when the error was
/// raised.
/// @return `Failure::Errored::kError` so that you can combine an AddError()
/// call and return on the same line.
Failure::Errored AddError(const Source& source, std::string_view msg, std::string_view use);
/// Appends an error at `source` with the message `msg`
/// @param source the source to associate the error with
/// @param msg the error message
/// @return `Failure::Errored::kError` so that you can combine an AddError()
/// call and return on the same line.
Failure::Errored AddError(const Source& source, std::string_view msg);
/// Appends an error at `source` with the message `msg`
/// @param source the source to associate the error with
/// @param msg the error message
/// @return `Failure::Errored::kError` so that you can combine an AddError()
/// call and return on the same line.
Failure::Errored AddError(const Source& source, StyledText&& msg);
/// Appends a note at `source` with the message `msg`
/// @param source the source to associate the error with
/// @param msg the note message
void AddNote(const Source& source, std::string_view msg);
/// Appends a deprecated-language-feature warning at `source` with the message
/// `msg`
/// @param source the source to associate the error with
/// @param msg the warning message
void deprecated(const Source& source, std::string_view msg);
/// Parses the `translation_unit` grammar element
void translation_unit();
/// Parses the `global_directive` grammar element, erroring on parse failure.
/// @param has_parsed_decl flag indicating if the parser has consumed a global declaration.
/// @return true on parse success, otherwise an error or no-match.
Maybe<Void> global_directive(bool has_parsed_decl);
/// Parses the `diagnostic_directive` grammar element, erroring on parse failure.
/// @return true on parse success, otherwise an error or no-match.
Maybe<Void> diagnostic_directive();
/// Parses the `enable_directive` grammar element, erroring on parse failure.
/// @return true on parse success, otherwise an error or no-match.
Maybe<Void> enable_directive();
/// Parses the `requires_directive` grammar element, erroring on parse failure.
/// @return true on parse success, otherwise an error or no-match.
Maybe<Void> requires_directive();
/// Parses the `global_decl` grammar element, erroring on parse failure.
/// @return true on parse success, otherwise an error or no-match.
Maybe<Void> global_decl();
/// Parses a `global_variable_decl` grammar element with the initial
/// `variable_attribute_list*` provided as `attrs`
/// @returns the variable parsed or nullptr
/// @param attrs the list of attributes for the variable declaration. If attributes are consumed
/// by the declaration, then this vector is cleared before returning.
Maybe<const ast::Variable*> global_variable_decl(AttributeList& attrs);
/// Parses a `global_constant_decl` grammar element with the initial
/// `variable_attribute_list*` provided as `attrs`
/// @returns the const object or nullptr
/// @param attrs the list of attributes for the constant declaration. If attributes are consumed
/// by the declaration, then this vector is cleared before returning.
Maybe<const ast::Variable*> global_constant_decl(AttributeList& attrs);
/// Parses a `variable_decl` grammar element
/// @returns the parsed variable declaration info
Maybe<VarDeclInfo> variable_decl();
/// Helper for parsing ident with an optional type declaration. Should not be called directly,
/// use the specific version below.
/// @param use a description of what was being parsed if an error was raised.
/// @param allow_inferred allow the identifier to be parsed without a type
/// @returns the parsed identifier, and possibly type, or empty otherwise
Expect<TypedIdentifier> expect_ident_with_optional_type_specifier(std::string_view use,
bool allow_inferred);
/// Parses a `ident` or a `variable_ident_decl` grammar element, erroring on parse failure.
/// @param use a description of what was being parsed if an error was raised.
/// @returns the identifier or empty otherwise.
Expect<TypedIdentifier> expect_optionally_typed_ident(std::string_view use);
/// Parses a `variable_ident_decl` grammar element, erroring on parse failure.
/// @param use a description of what was being parsed if an error was raised.
/// @returns the identifier and type parsed or empty otherwise
Expect<TypedIdentifier> expect_ident_with_type_specifier(std::string_view use);
/// Parses a `variable_qualifier` grammar element
/// @returns the variable qualifier information
Maybe<VariableQualifier> variable_qualifier();
/// Parses a `type_alias_decl` grammar element
/// @returns the type alias or nullptr on error
Maybe<const ast::Alias*> type_alias_decl();
/// Parses a `type_specifier` grammar element
/// @returns the parsed Type or nullptr if none matched.
Maybe<ast::Type> type_specifier();
/// Parses a `struct_decl` grammar element.
/// @returns the struct type or nullptr on error
Maybe<const ast::Struct*> struct_decl();
/// Parses a `struct_body_decl` grammar element, erroring on parse failure.
/// @returns the struct members
Expect<StructMemberList> expect_struct_body_decl();
/// Parses a `struct_member` grammar element, erroring on parse failure.
/// @returns the struct member or nullptr
Expect<const ast::StructMember*> expect_struct_member();
/// Parses a `function_decl` grammar element with the initial
/// `function_attribute_decl*` provided as `attrs`.
/// @param attrs the list of attributes for the function declaration. If attributes are consumed
/// by the declaration, then this vector is cleared before returning.
/// @returns the parsed function, nullptr otherwise
Maybe<const ast::Function*> function_decl(AttributeList& attrs);
/// Parses a `const_assert_statement` grammar element
/// @returns returns the const assert, if it matched.
Maybe<const ast::ConstAssert*> const_assert_statement();
/// Parses a `function_header` grammar element
/// @returns the parsed function header
Maybe<FunctionHeader> function_header();
/// Parses a `param_list` grammar element, erroring on parse failure.
/// @returns the parsed variables
Expect<ParameterList> expect_param_list();
/// Parses a `param` grammar element, erroring on parse failure.
/// @returns the parsed variable
Expect<const ast::Parameter*> expect_param();
/// Parses a `pipeline_stage` grammar element, erroring if the next token does
/// not match a stage name.
/// @returns the pipeline stage.
Expect<ast::PipelineStage> expect_pipeline_stage();
/// Parses a `compound_statement` grammar element, erroring on parse failure.
/// @param use a description of what was being parsed if an error was raised
/// @returns the parsed statements
Expect<ast::BlockStatement*> expect_compound_statement(std::string_view use);
/// Parses a `compound_statement` grammar element, with the attribute list provided as `attrs`.
/// @param attrs the list of attributes for the statement
/// @param use a description of what was being parsed if an error was raised
/// @returns the parsed statements
Expect<ast::BlockStatement*> expect_compound_statement(AttributeList& attrs,
std::string_view use);
/// Parses a `paren_expression` grammar element, erroring on parse failure.
/// @returns the parsed element or nullptr
Expect<const ast::Expression*> expect_paren_expression();
/// Parses a `statements` grammar element
/// @returns the statements parsed
Expect<StatementList> expect_statements();
/// Parses a `statement` grammar element
/// @returns the parsed statement or nullptr
Maybe<const ast::Statement*> statement();
/// Parses a `break_statement` grammar element
/// @returns the parsed statement or nullptr
Maybe<const ast::BreakStatement*> break_statement();
/// Parses a `return_statement` grammar element
/// @returns the parsed statement or nullptr
Maybe<const ast::ReturnStatement*> return_statement();
/// Parses a `continue_statement` grammar element
/// @returns the parsed statement or nullptr
Maybe<const ast::ContinueStatement*> continue_statement();
/// Parses a `variable_statement` grammar element
/// @returns the parsed variable or nullptr
Maybe<const ast::VariableDeclStatement*> variable_statement();
/// Parses a `if_statement` grammar element, with the attribute list provided as `attrs`.
/// @param attrs the list of attributes for the statement
/// @returns the parsed statement or nullptr
Maybe<const ast::IfStatement*> if_statement(AttributeList& attrs);
/// Parses a `switch_statement` grammar element
/// @param attrs the list of attributes for the statement
/// @returns the parsed statement or nullptr
Maybe<const ast::SwitchStatement*> switch_statement(AttributeList& attrs);
/// Parses a `switch_body` grammar element
/// @returns the parsed statement or nullptr
Maybe<const ast::CaseStatement*> switch_body();
/// Parses a `case_selectors` grammar element
/// @returns the list of literals
Expect<CaseSelectorList> expect_case_selectors();
/// Parses a `case_selector` grammar element
/// @returns the selector
Maybe<const ast::CaseSelector*> case_selector();
/// Parses a `func_call_statement` grammar element
/// @returns the parsed function call or nullptr
Maybe<const ast::CallStatement*> func_call_statement();
/// Parses a `loop_statement` grammar element, with the attribute list provided as `attrs`.
/// @param attrs the list of attributes for the statement
/// @returns the parsed loop or nullptr
Maybe<const ast::LoopStatement*> loop_statement(AttributeList& attrs);
/// Parses a `for_header` grammar element, erroring on parse failure.
/// @returns the parsed for header or nullptr
Expect<std::unique_ptr<ForHeader>> expect_for_header();
/// Parses a `for_statement` grammar element, with the attribute list provided as `attrs`.
/// @param attrs the list of attributes for the statement
/// @returns the parsed for loop or nullptr
Maybe<const ast::ForLoopStatement*> for_statement(AttributeList& attrs);
/// Parses a `while_statement` grammar element, with the attribute list provided as `attrs`.
/// @param attrs the list of attributes for the statement
/// @returns the parsed while loop or nullptr
Maybe<const ast::WhileStatement*> while_statement(AttributeList& attrs);
/// Parses a `break_if_statement` grammar element
/// @returns the parsed statement or nullptr
Maybe<const ast::Statement*> break_if_statement();
/// Parses a `continuing_compound_statement` grammar element
/// @returns the parsed statements
Maybe<const ast::BlockStatement*> continuing_compound_statement();
/// Parses a `continuing_statement` grammar element
/// @returns the parsed statements
Maybe<const ast::BlockStatement*> continuing_statement();
/// Parses a `const_literal` grammar element
/// @returns the const literal parsed or nullptr if none found
Maybe<const ast::LiteralExpression*> const_literal();
/// Parses a `primary_expression` grammar element
/// @returns the parsed expression or nullptr
Maybe<const ast::Expression*> primary_expression();
/// Parses a `argument_expression_list` grammar element, erroring on parse
/// failure.
/// @param use a description of what was being parsed if an error was raised
/// @returns the list of arguments
Expect<ExpressionList> expect_argument_expression_list(std::string_view use);
/// Parses the recursive portion of the component_or_swizzle_specifier
/// @param prefix the left side of the expression
/// @returns the parsed expression or nullptr
Maybe<const ast::Expression*> component_or_swizzle_specifier(const ast::Expression* prefix);
/// Parses a `singular_expression` grammar elment
/// @returns the parsed expression or nullptr
Maybe<const ast::Expression*> singular_expression();
/// Parses a `unary_expression` grammar element
/// @returns the parsed expression or nullptr
Maybe<const ast::Expression*> unary_expression();
/// Parses the `expression` grammar rule
/// @returns the parsed expression or nullptr
Maybe<const ast::Expression*> expression();
/// Parses the `expression` grammar rule
/// @param use the use of the expression
/// @returns the parsed expression or error
Expect<const ast::Expression*> expect_expression(std::string_view use);
/// Parses a comma separated expression list
/// @param use the use of the expression list
/// @param terminator the terminating token for the list
/// @returns the parsed expression list or error
Maybe<Parser::ExpressionList> expression_list(std::string_view use, Token::Type terminator);
/// Parses a comma separated expression list, with at least one expression
/// @param use the use of the expression list
/// @param terminator the terminating token for the list
/// @returns the parsed expression list or error
Expect<Parser::ExpressionList> expect_expression_list(std::string_view use,
Token::Type terminator);
/// Parses the `bitwise_expression.post.unary_expression` grammar element
/// @param lhs the left side of the expression
/// @param lhs_source the source span for the left side of the expression
/// @returns the parsed expression or nullptr
Maybe<const ast::Expression*> bitwise_expression_post_unary_expression(
const ast::Expression* lhs,
const Source& lhs_source);
/// Parse the `multiplicative_operator` grammar element
/// @returns the parsed operator if successful
Maybe<core::BinaryOp> multiplicative_operator();
/// Parses multiplicative elements
/// @param lhs the left side of the expression
/// @param lhs_source the source span for the left side of the expression
/// @returns the parsed expression or `lhs` if no match
Expect<const ast::Expression*> expect_multiplicative_expression_post_unary_expression(
const ast::Expression* lhs,
const Source& lhs_source);
/// Parses additive elements
/// @param lhs the left side of the expression
/// @param lhs_source the source span for the left side of the expression
/// @returns the parsed expression or `lhs` if no match
Expect<const ast::Expression*> expect_additive_expression_post_unary_expression(
const ast::Expression* lhs,
const Source& lhs_source);
/// Parses math elements
/// @param lhs the left side of the expression
/// @param lhs_source the source span for the left side of the expression
/// @returns the parsed expression or `lhs` if no match
Expect<const ast::Expression*> expect_math_expression_post_unary_expression(
const ast::Expression* lhs,
const Source& lhs_source);
/// Parses a `unary_expression shift.post.unary_expression`
/// @returns the parsed expression or nullptr
Maybe<const ast::Expression*> shift_expression();
/// Parses a `shift_expression.post.unary_expression` grammar element
/// @param lhs the left side of the expression
/// @param lhs_source the source span for the left side of the expression
/// @returns the parsed expression or `lhs` if no match
Expect<const ast::Expression*> expect_shift_expression_post_unary_expression(
const ast::Expression* lhs,
const Source& lhs_source);
/// Parses a `unary_expression relational_expression.post.unary_expression`
/// @returns the parsed expression or nullptr
Maybe<const ast::Expression*> relational_expression();
/// Parses a `relational_expression.post.unary_expression` grammar element
/// @param lhs the left side of the expression
/// @param lhs_source the source span for the left side of the expression
/// @returns the parsed expression or `lhs` if no match
Expect<const ast::Expression*> expect_relational_expression_post_unary_expression(
const ast::Expression* lhs,
const Source& lhs_source);
/// Parse the `additive_operator` grammar element
/// @returns the parsed operator if successful
Maybe<core::BinaryOp> additive_operator();
/// Parses a `compound_assignment_operator` grammar element
/// @returns the parsed compound assignment operator
Maybe<core::BinaryOp> compound_assignment_operator();
/// Parses a `core_lhs_expression` grammar element
/// @returns the parsed expression or a non-kMatched failure
Maybe<const ast::Expression*> core_lhs_expression();
/// Parses a `lhs_expression` grammar element
/// @returns the parsed expression or a non-kMatched failure
Maybe<const ast::Expression*> lhs_expression();
/// Parses a `variable_updating_statement` grammar element
/// @returns the parsed assignment or nullptr
Maybe<const ast::Statement*> variable_updating_statement();
/// Parses one or more attribute lists.
/// @return the parsed attribute list, or an empty list on error.
Maybe<AttributeList> attribute_list();
/// Parses a single attribute of the following types:
/// * `struct_attribute`
/// * `struct_member_attribute`
/// * `array_attribute`
/// * `variable_attribute`
/// * `global_const_attribute`
/// * `function_attribute`
/// @return the parsed attribute, or nullptr.
Maybe<const ast::Attribute*> attribute();
/// Parses a single attribute, reporting an error if the next token does not
/// represent a attribute.
/// @see #attribute for the full list of attributes this method parses.
/// @return the parsed attribute.
Expect<const ast::Attribute*> expect_attribute();
/// Parses a severity_control_name grammar element.
/// @return the parsed severity control name.
Expect<wgsl::DiagnosticSeverity> expect_severity_control_name();
/// Parses a diagnostic_control grammar element.
/// @return the parsed diagnostic control.
Expect<ast::DiagnosticControl> expect_diagnostic_control();
/// Parses a diagnostic_rule_name grammar element.
/// @return the parsed diagnostic rule name.
Expect<const ast::DiagnosticRuleName*> expect_diagnostic_rule_name();
/// Splits a peekable token into to parts filling in the peekable fields.
/// @param lhs the token to set in the current position
/// @param rhs the token to set in the placeholder
void split_token(Token::Type lhs, Token::Type rhs);
private:
/// ReturnType resolves to the return type for the function or lambda F.
template <typename F>
using ReturnType = typename std::invoke_result<F>::type;
/// ResultType resolves to `T` for a `RESULT` of type Expect<T>.
template <typename RESULT>
using ResultType = typename RESULT::type;
/// @returns true and consumes the next token if it equals `tok`
/// @param source if not nullptr, the next token's source is written to this
/// pointer, regardless of success or error
bool match(Token::Type tok, Source* source = nullptr);
/// Errors if the next token is not equal to `tok`
/// Consumes the next token on match.
/// expect() also updates #synchronized_, setting it to `true` if the next
/// token is equal to `tok`, otherwise `false`.
/// @param use a description of what was being parsed if an error was raised.
/// @param tok the token to test against
/// @returns true if the next token equals `tok`
bool expect(std::string_view use, Token::Type tok);
/// Parses a signed integer from the next token in the stream, erroring if the
/// next token is not a signed integer.
/// Consumes the next token on match.
/// @param use a description of what was being parsed if an error was raised
/// @returns the parsed integer.
/// @param source if not nullptr, the next token's source is written to this
/// pointer, regardless of success or error
Expect<int32_t> expect_sint(std::string_view use, Source* source = nullptr);
/// Parses a signed integer from the next token in the stream, erroring if
/// the next token is not a signed integer or is negative.
/// Consumes the next token if it is a signed integer (not necessarily
/// negative).
/// @param use a description of what was being parsed if an error was raised
/// @returns the parsed integer.
Expect<uint32_t> expect_positive_sint(std::string_view use);
/// Parses a non-zero signed integer from the next token in the stream,
/// erroring if the next token is not a signed integer or is less than 1.
/// Consumes the next token if it is a signed integer (not necessarily
/// >= 1).
/// @param use a description of what was being parsed if an error was raised
/// @returns the parsed integer.
Expect<uint32_t> expect_nonzero_positive_sint(std::string_view use);
/// Errors if the next token is not an identifier.
/// Consumes the next token on match.
/// @param use a description of what was being parsed if an error was raised
/// @param kind a string describing the kind of identifier.
/// Examples: "identifier", "diagnostic name"
/// @returns the parsed identifier.
Expect<const ast::Identifier*> expect_ident(std::string_view use,
std::string_view kind = "identifier");
/// Parses a lexical block starting with the token `start` and ending with
/// the token `end`. `body` is called to parse the lexical block body
/// between the `start` and `end` tokens. If the `start` or `end` tokens
/// are not matched then an error is generated and a zero-initialized `T` is
/// returned. If `body` raises an error while parsing then a zero-initialized
/// `T` is returned.
/// @param start the token that begins the lexical block
/// @param end the token that ends the lexical block
/// @param use a description of what was being parsed if an error was raised
/// @param body a function or lambda that is called to parse the lexical block
/// body, with the signature: `Expect<Result>()` or `Maybe<Result>()`.
/// @return the value returned by `body` if no errors are raised, otherwise
/// an Expect with error state.
template <typename F, typename T = ReturnType<F>>
T expect_block(Token::Type start, Token::Type end, std::string_view use, F&& body);
/// A convenience function that calls expect_block() passing
/// `Token::Type::kParenLeft` and `Token::Type::kParenRight` for the `start`
/// and `end` arguments, respectively.
/// @param use a description of what was being parsed if an error was raised
/// @param body a function or lambda that is called to parse the lexical block
/// body, with the signature: `Expect<Result>()` or `Maybe<Result>()`.
/// @return the value returned by `body` if no errors are raised, otherwise
/// an Expect with error state.
template <typename F, typename T = ReturnType<F>>
T expect_paren_block(std::string_view use, F&& body);
/// A convenience function that calls `expect_block` passing
/// `Token::Type::kBraceLeft` and `Token::Type::kBraceRight` for the `start`
/// and `end` arguments, respectively.
/// @param use a description of what was being parsed if an error was raised
/// @param body a function or lambda that is called to parse the lexical block
/// body, with the signature: `Expect<Result>()` or `Maybe<Result>()`.
/// @return the value returned by `body` if no errors are raised, otherwise
/// an Expect with error state.
template <typename F, typename T = ReturnType<F>>
T expect_brace_block(std::string_view use, F&& body);
/// A convenience function that calls `expect_block` passing
/// `Token::Type::kLessThan` and `Token::Type::kGreaterThan` for the `start`
/// and `end` arguments, respectively.
/// @param use a description of what was being parsed if an error was raised
/// @param body a function or lambda that is called to parse the lexical block
/// body, with the signature: `Expect<Result>()` or `Maybe<Result>()`.
/// @return the value returned by `body` if no errors are raised, otherwise
/// an Expect with error state.
template <typename F, typename T = ReturnType<F>>
T expect_lt_gt_block(std::string_view use, F&& body);
/// A convenience function that calls `expect_block` passing
/// `Token::Type::kTemplateArgsLeft` and `Token::Type::kTemplateArgsRight` for the `start` and
/// `end` arguments, respectively.
/// @param use a description of what was being parsed if an error was raised
/// @param body a function or lambda that is called to parse the lexical block body, with the
/// signature: `Expect<Result>()` or `Maybe<Result>()`.
/// @return the value returned by `body` if no errors are raised, otherwise an Expect with error
/// state.
template <typename F, typename T = ReturnType<F>>
T expect_template_arg_block(std::string_view use, F&& body);
/// sync() calls the function `func`, and attempts to resynchronize the
/// parser to the next found resynchronization token if `func` fails. If the
/// next found resynchronization token is `tok`, then sync will also consume
/// `tok`.
///
/// sync() will transiently add `tok` to the parser's stack of
/// synchronization tokens for the duration of the call to `func`. Once @p
/// func returns,
/// `tok` is removed from the stack of resynchronization tokens. sync calls
/// may be nested, and so the number of resynchronization tokens is equal to
/// the number of sync() calls in the current stack frame.
///
/// sync() updates #synchronized_, setting it to `true` if the next
/// resynchronization token found was `tok`, otherwise `false`.
///
/// @param tok the token to attempt to synchronize the parser to if `func`
/// fails.
/// @param func a function or lambda with the signature: `Expect<Result>()` or
/// `Maybe<Result>()`.
/// @return the value returned by `func`
template <typename F, typename T = ReturnType<F>>
T sync(Token::Type tok, F&& func);
/// sync_to() attempts to resynchronize the parser to the next found
/// resynchronization token or `tok` (whichever comes first).
///
/// Synchronization tokens are transiently defined by calls to sync().
///
/// sync_to() updates #synchronized_, setting it to `true` if a
/// resynchronization token was found and it was `tok`, otherwise `false`.
///
/// @param tok the token to attempt to synchronize the parser to.
/// @param consume if true and the next found resynchronization token is
/// `tok` then sync_to() will also consume `tok`.
/// @return the state of #synchronized_.
/// @see sync().
bool sync_to(Token::Type tok, bool consume);
/// @return true if `t` is in the stack of resynchronization tokens.
/// @see sync().
bool is_sync_token(const Token& t) const;
/// If `t` is an error token, then `synchronized_` is set to false and the
/// token's error is appended to the builder's diagnostics. If `t` is not an
/// error token, then this function does nothing and false is returned.
/// @returns true if `t` is an error, otherwise false.
bool handle_error(const Token& t);
/// @returns true if #synchronized_ is true and the number of reported errors
/// is less than #max_errors_.
bool continue_parsing() {
return synchronized_ && builder_.Diagnostics().NumErrors() < max_errors_;
}
/// without_diag() calls the function `func` muting any diagnostics found while executing the
/// function. This can be used to silence spew when attempting to resynchronize the parser.
/// @param func a function or lambda with the signature: `Expect<Result>()` or
/// `Maybe<Result>()`.
/// @return the value returned by `func`
template <typename F, typename T = ReturnType<F>>
T without_diag(F&& func);
/// Reports an error if the attribute list `list` is not empty.
/// Used to ensure that all attributes are consumed.
Expect<Void> expect_attributes_consumed(VectorRef<const ast::Attribute*> list);
/// Raises an error if the next token is the start of a template list.
/// Used to hint to the user that the parser interpreted the following as a templated identifier
/// expression:
///
/// ```
/// a < b, c >
/// ^~~~~~~~
/// ```
Expect<Void> expect_next_not_template_list(const Source& lhs_source);
/// Raises an error if the parsed expression is a templated identifier expression
/// Used to hint to the user that the parser intepreted the following as a templated identifier
/// expression:
///
/// ```
/// a < b, c > d
/// ^^^^^^^^^^
/// expr
/// ```
Expect<Void> expect_not_templated_ident_expr(const ast::Expression* expr);
/// Parses the given enum, providing sensible error messages if the next token does not match
/// any of the enum values.
/// @param name the name of the enumerator
/// @param parse the optimized function used to parse the enum
/// @param strings the list of possible strings in the enum
/// @param use an optional description of what was being parsed if an error was raised.
template <typename ENUM>
Expect<ENUM> expect_enum(std::string_view name,
ENUM (*parse)(std::string_view str),
Slice<const std::string_view> strings,
std::string_view use = "");
Expect<ast::Type> expect_type(std::string_view use);
Maybe<const ast::Statement*> non_block_statement();
Maybe<const ast::Statement*> for_header_initializer();
Maybe<const ast::Statement*> for_header_continuing();
class MultiTokenSource;
/// Creates a new `ast::Node` owned by the Module. When the Module is
/// destructed, the `ast::Node` will also be destructed.
/// @param args the arguments to pass to the constructor
/// @returns the node pointer
template <typename T, typename... ARGS>
T* create(ARGS&&... args) {
return builder_.create<T>(std::forward<ARGS>(args)...);
}
Source::File const* const file_;
std::vector<Token> tokens_;
size_t next_token_idx_ = 0;
size_t last_source_idx_ = 0;
bool synchronized_ = true;
uint32_t parse_depth_ = 0;
std::vector<Token::Type> sync_tokens_;
int silence_diags_ = 0;
ProgramBuilder builder_;
size_t max_errors_ = 25;
};
} // namespace tint::wgsl::reader
#endif // SRC_TINT_LANG_WGSL_READER_PARSER_PARSER_H_

View File

@@ -1,290 +0,0 @@
// Copyright 2020 The Dawn & Tint Authors
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this
// list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "src/tint/lang/wgsl/reader/parser/token.h"
namespace tint::wgsl::reader {
// static
std::string_view Token::TypeToName(Type type) {
switch (type) {
case Token::Type::kError:
return "error";
case Token::Type::kEOF:
return "end of file";
case Token::Type::kIdentifier:
return "identifier";
case Token::Type::kFloatLiteral:
return "abstract float literal";
case Token::Type::kFloatLiteral_F:
return "'f'-suffixed float literal";
case Token::Type::kFloatLiteral_H:
return "'h'-suffixed float literal";
case Token::Type::kIntLiteral:
return "abstract integer literal";
case Token::Type::kIntLiteral_I:
return "'i'-suffixed integer literal";
case Token::Type::kIntLiteral_U:
return "'u'-suffixed integer literal";
case Token::Type::kPlaceholder:
return "placeholder";
case Token::Type::kUninitialized:
return "uninitialized";
case Token::Type::kAnd:
return "&";
case Token::Type::kAndAnd:
return "&&";
case Token::Type::kArrow:
return "->";
case Token::Type::kAttr:
return "@";
case Token::Type::kForwardSlash:
return "/";
case Token::Type::kBang:
return "!";
case Token::Type::kBracketLeft:
return "[";
case Token::Type::kBracketRight:
return "]";
case Token::Type::kBraceLeft:
return "{";
case Token::Type::kBraceRight:
return "}";
case Token::Type::kColon:
return ":";
case Token::Type::kComma:
return ",";
case Token::Type::kEqual:
return "=";
case Token::Type::kEqualEqual:
return "==";
case Token::Type::kTemplateArgsRight:
case Token::Type::kGreaterThan:
return ">";
case Token::Type::kGreaterThanEqual:
return ">=";
case Token::Type::kShiftRight:
return ">>";
case Token::Type::kTemplateArgsLeft:
case Token::Type::kLessThan:
return "<";
case Token::Type::kLessThanEqual:
return "<=";
case Token::Type::kShiftLeft:
return "<<";
case Token::Type::kMod:
return "%";
case Token::Type::kNotEqual:
return "!=";
case Token::Type::kMinus:
return "-";
case Token::Type::kMinusMinus:
return "--";
case Token::Type::kPeriod:
return ".";
case Token::Type::kPlus:
return "+";
case Token::Type::kPlusPlus:
return "++";
case Token::Type::kOr:
return "|";
case Token::Type::kOrOr:
return "||";
case Token::Type::kParenLeft:
return "(";
case Token::Type::kParenRight:
return ")";
case Token::Type::kSemicolon:
return ";";
case Token::Type::kStar:
return "*";
case Token::Type::kTilde:
return "~";
case Token::Type::kUnderscore:
return "_";
case Token::Type::kXor:
return "^";
case Token::Type::kPlusEqual:
return "+=";
case Token::Type::kMinusEqual:
return "-=";
case Token::Type::kTimesEqual:
return "*=";
case Token::Type::kDivisionEqual:
return "/=";
case Token::Type::kModuloEqual:
return "%=";
case Token::Type::kAndEqual:
return "&=";
case Token::Type::kOrEqual:
return "|=";
case Token::Type::kXorEqual:
return "^=";
case Token::Type::kShiftLeftEqual:
return "<<=";
case Token::Type::kShiftRightEqual:
return ">>=";
case Token::Type::kAlias:
return "alias";
case Token::Type::kBreak:
return "break";
case Token::Type::kCase:
return "case";
case Token::Type::kConst:
return "const";
case Token::Type::kConstAssert:
return "const_assert";
case Token::Type::kContinue:
return "continue";
case Token::Type::kContinuing:
return "continuing";
case Token::Type::kDiagnostic:
return "diagnostic";
case Token::Type::kDiscard:
return "discard";
case Token::Type::kDefault:
return "default";
case Token::Type::kElse:
return "else";
case Token::Type::kEnable:
return "enable";
case Token::Type::kFallthrough:
return "fallthrough";
case Token::Type::kFalse:
return "false";
case Token::Type::kFn:
return "fn";
case Token::Type::kFor:
return "for";
case Token::Type::kIf:
return "if";
case Token::Type::kLet:
return "let";
case Token::Type::kLoop:
return "loop";
case Token::Type::kOverride:
return "override";
case Token::Type::kReturn:
return "return";
case Token::Type::kRequires:
return "requires";
case Token::Type::kStruct:
return "struct";
case Token::Type::kSwitch:
return "switch";
case Token::Type::kTrue:
return "true";
case Token::Type::kVar:
return "var";
case Token::Type::kWhile:
return "while";
}
return "<unknown>";
}
Token::Token() : type_(Type::kUninitialized) {}
Token::Token(Type type, const Source& source, std::string_view view)
: type_(type), source_(source), value_(view) {}
Token::Token(Type type, const Source& source, const std::string& str)
: type_(type), source_(source), value_(str) {}
Token::Token(Type type, const Source& source, const char* str)
: type_(type), source_(source), value_(std::string_view(str)) {}
Token::Token(Type type, const Source& source, int64_t val)
: type_(type), source_(source), value_(val) {}
Token::Token(Type type, const Source& source, double val)
: type_(type), source_(source), value_(val) {}
Token::Token(Type type, const Source& source) : type_(type), source_(source) {}
Token::Token(Token&&) = default;
Token::~Token() = default;
bool Token::operator==(std::string_view ident) const {
if (type_ != Type::kIdentifier) {
return false;
}
if (auto* view = std::get_if<std::string_view>(&value_)) {
return *view == ident;
}
return std::get<std::string>(value_) == ident;
}
std::string Token::to_str() const {
switch (type_) {
case Type::kFloatLiteral:
return std::to_string(std::get<double>(value_));
case Type::kFloatLiteral_F:
return std::to_string(std::get<double>(value_)) + "f";
case Type::kFloatLiteral_H:
return std::to_string(std::get<double>(value_)) + "h";
case Type::kIntLiteral:
return std::to_string(std::get<int64_t>(value_));
case Type::kIntLiteral_I:
return std::to_string(std::get<int64_t>(value_)) + "i";
case Type::kIntLiteral_U:
return std::to_string(std::get<int64_t>(value_)) + "u";
case Type::kIdentifier:
case Type::kError:
if (auto* view = std::get_if<std::string_view>(&value_)) {
return std::string(*view);
}
return std::get<std::string>(value_);
default:
return "";
}
}
std::string_view Token::to_str_view() const {
if (type_ != Type::kIdentifier) {
return {};
}
if (auto* view = std::get_if<std::string_view>(&value_)) {
return *view;
}
auto& s = std::get<std::string>(value_);
return {s.data(), s.length()};
}
double Token::to_f64() const {
return std::get<double>(value_);
}
int64_t Token::to_i64() const {
return std::get<int64_t>(value_);
}
} // namespace tint::wgsl::reader

View File

@@ -1,382 +0,0 @@
// Copyright 2020 The Dawn & Tint Authors
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this
// list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#ifndef SRC_TINT_LANG_WGSL_READER_PARSER_TOKEN_H_
#define SRC_TINT_LANG_WGSL_READER_PARSER_TOKEN_H_
#include <string>
#include <string_view>
#include <variant>
#include "src/tint/utils/diagnostic/source.h"
namespace tint::wgsl::reader {
/// Stores tokens generated by the Lexer
class Token {
public:
/// The type of the parsed token
enum class Type {
/// Error result
kError = -2,
/// Uninitialized token
kUninitialized = 0,
/// Placeholder token which maybe filled in later
kPlaceholder = 1,
/// End of input string reached
kEOF,
/// An identifier
kIdentifier,
/// A float literal with no suffix
kFloatLiteral,
/// A float literal with an 'f' suffix
kFloatLiteral_F,
/// A float literal with an 'h' suffix
kFloatLiteral_H,
/// An integer literal with no suffix
kIntLiteral,
/// An integer literal with an 'i' suffix
kIntLiteral_I,
/// An integer literal with a 'u' suffix
kIntLiteral_U,
/// A '&'
kAnd,
/// A '&&'
kAndAnd,
/// A '->'
kArrow,
/// A '@'
kAttr,
/// A '/'
kForwardSlash,
/// A '!'
kBang,
/// A '['
kBracketLeft,
/// A ']'
kBracketRight,
/// A '{'
kBraceLeft,
/// A '}'
kBraceRight,
/// A ':'
kColon,
/// A ','
kComma,
/// A '='
kEqual,
/// A '=='
kEqualEqual,
/// A '>' (post template-args classification)
kTemplateArgsRight,
/// A '>'
kGreaterThan,
/// A '>='
kGreaterThanEqual,
/// A '>>'
kShiftRight,
/// A '<' (post template-args classification)
kTemplateArgsLeft,
/// A '<'
kLessThan,
/// A '<='
kLessThanEqual,
/// A '<<'
kShiftLeft,
/// A '%'
kMod,
/// A '-'
kMinus,
/// A '--'
kMinusMinus,
/// A '!='
kNotEqual,
/// A '.'
kPeriod,
/// A '+'
kPlus,
/// A '++'
kPlusPlus,
/// A '|'
kOr,
/// A '||'
kOrOr,
/// A '('
kParenLeft,
/// A ')'
kParenRight,
/// A ';'
kSemicolon,
/// A '*'
kStar,
/// A '~'
kTilde,
/// A '_'
kUnderscore,
/// A '^'
kXor,
/// A '+='
kPlusEqual,
/// A '-='
kMinusEqual,
/// A '*='
kTimesEqual,
/// A '/='
kDivisionEqual,
/// A '%='
kModuloEqual,
/// A '&='
kAndEqual,
/// A '|='
kOrEqual,
/// A '^='
kXorEqual,
/// A '>>='
kShiftRightEqual,
/// A '<<='
kShiftLeftEqual,
/// A 'alias'
kAlias,
/// A 'break'
kBreak,
/// A 'case'
kCase,
/// A 'const'
kConst,
/// A 'const_assert'
kConstAssert,
/// A 'continue'
kContinue,
/// A 'continuing'
kContinuing,
/// A 'default'
kDefault,
/// A 'diagnostic'
kDiagnostic,
/// A 'discard'
kDiscard,
/// A 'else'
kElse,
/// A 'enable'
kEnable,
/// A 'fallthrough'
// Note, this isn't a keyword, but a reserved word. We match it as a keyword in order to
// provide better diagnostics in case a `fallthrough` is added to a case body.
kFallthrough,
/// A 'false'
kFalse,
/// A 'fn'
kFn,
// A 'for'
kFor,
/// A 'if'
kIf,
/// A 'let'
kLet,
/// A 'loop'
kLoop,
/// A 'override'
kOverride,
/// A 'requires'
kRequires,
/// A 'return'
kReturn,
/// A 'struct'
kStruct,
/// A 'switch'
kSwitch,
/// A 'true'
kTrue,
/// A 'var'
kVar,
/// A 'while'
kWhile,
};
/// Converts a token type to a name
/// @param type the type to convert
/// @returns the token type as as string
static std::string_view TypeToName(Type type);
/// Creates an uninitialized token
Token();
/// Create a Token
/// @param type the Token::Type of the token
/// @param source the source of the token
Token(Type type, const Source& source);
/// Create a string Token
/// @param type the Token::Type of the token
/// @param source the source of the token
/// @param view the source string view for the token
Token(Type type, const Source& source, std::string_view view);
/// Create a string Token
/// @param type the Token::Type of the token
/// @param source the source of the token
/// @param str the source string for the token
Token(Type type, const Source& source, const std::string& str);
/// Create a string Token
/// @param type the Token::Type of the token
/// @param source the source of the token
/// @param str the source string for the token
Token(Type type, const Source& source, const char* str);
/// Create a integer Token of the given type
/// @param type the Token::Type of the token
/// @param source the source of the token
/// @param val the source unsigned for the token
Token(Type type, const Source& source, int64_t val);
/// Create a double Token
/// @param type the Token::Type of the token
/// @param source the source of the token
/// @param val the source double for the token
Token(Type type, const Source& source, double val);
/// Move constructor
Token(Token&&);
~Token();
/// Equality operator with an identifier
/// @param ident the identifier string
/// @return true if this token is an identifier and is equal to ident.
bool operator==(std::string_view ident) const;
/// Sets the token to the given type
/// @param type the type to set
void SetType(Token::Type type) { type_ = type; }
/// Returns true if the token is of the given type
/// @param t the type to check against.
/// @returns true if the token is of type `t`
bool Is(Type t) const { return type_ == t; }
/// @returns true if the token is uninitialized
bool IsUninitialized() const { return type_ == Type::kUninitialized; }
/// @returns true if the token is a placeholder
bool IsPlaceholder() const { return type_ == Type::kPlaceholder; }
/// @returns true if the token is EOF
bool IsEof() const { return type_ == Type::kEOF; }
/// @returns true if the token is Error
bool IsError() const { return type_ == Type::kError; }
/// @returns true if the token is an identifier
bool IsIdentifier() const { return type_ == Type::kIdentifier; }
/// @returns true if the token is a literal
bool IsLiteral() const {
return type_ == Type::kIntLiteral || type_ == Type::kIntLiteral_I ||
type_ == Type::kIntLiteral_U || type_ == Type::kFalse || type_ == Type::kTrue ||
type_ == Type::kFloatLiteral || type_ == Type::kFloatLiteral_F ||
type_ == Type::kFloatLiteral_H;
}
/// @returns the number of placeholder tokens required to follow the token, in order to provide
/// space for token splitting.
size_t NumPlaceholders() const {
switch (type_) {
case Type::kShiftRightEqual:
return 2;
case Type::kShiftRight:
case Type::kGreaterThanEqual:
case Type::kAndAnd:
case Type::kMinusMinus:
return 1;
default:
return 0;
}
}
/// @returns true if the token is a binary operator
bool IsBinaryOperator() const {
switch (type_) {
case Type::kAnd:
case Type::kAndAnd:
case Type::kEqualEqual:
case Type::kForwardSlash:
case Type::kGreaterThan:
case Type::kGreaterThanEqual:
case Type::kLessThan:
case Type::kLessThanEqual:
case Type::kMinus:
case Type::kMod:
case Type::kNotEqual:
case Type::kOr:
case Type::kOrOr:
case Type::kPlus:
case Type::kShiftLeft:
case Type::kShiftRight:
case Type::kStar:
case Type::kXor:
return true;
default:
return false;
}
}
/// @returns the source information for this token
Source source() const { return source_; }
/// @returns the type of the token
Type type() const { return type_; }
/// Returns the string value of the token
/// @return std::string
std::string to_str() const;
/// Returns the string view of the token
/// @return std::string_view
/// @note if the token is not an identifier, an empty string_view will be returned.
std::string_view to_str_view() const;
/// Returns the float value of the token. 0 is returned if the token does not
/// contain a float value.
/// @return double
double to_f64() const;
/// Returns the int64_t value of the token. 0 is returned if the token does
/// not contain an integer value.
/// @return int64_t
int64_t to_i64() const;
/// @returns the token type as string
std::string_view to_name() const { return Token::TypeToName(type_); }
private:
/// The Token::Type of the token
Type type_ = Type::kError;
/// The source where the token appeared
Source source_;
/// The value represented by the token
std::variant<int64_t, double, std::string, std::string_view> value_;
};
template <typename STREAM>
requires(traits::IsOStream<STREAM>)
auto& operator<<(STREAM& out, Token::Type type) {
out << Token::TypeToName(type);
return out;
}
} // namespace tint::wgsl::reader
#endif // SRC_TINT_LANG_WGSL_READER_PARSER_TOKEN_H_

File diff suppressed because it is too large Load Diff

View File

@@ -1,52 +0,0 @@
// Copyright 2023 The Dawn & Tint Authors
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this
// list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#ifndef SRC_TINT_LANG_WGSL_READER_PROGRAM_TO_IR_PROGRAM_TO_IR_H_
#define SRC_TINT_LANG_WGSL_READER_PROGRAM_TO_IR_PROGRAM_TO_IR_H_
#include "src/tint/lang/core/ir/module.h"
#include "src/tint/utils/result.h"
// Forward Declarations
namespace tint {
class Program;
} // namespace tint
namespace tint::wgsl::reader {
/// Builds a WGSL-dialect core::ir::Module from the given Program
/// @param program the Program to use.
/// @returns the WGSL-dialect IR module.
///
/// @note this assumes the `program.IsValid()`, and has had const-eval done so
/// any abstract values have been calculated and converted into the relevant
/// concrete types.
Result<core::ir::Module> ProgramToIR(const Program& program);
} // namespace tint::wgsl::reader
#endif // SRC_TINT_LANG_WGSL_READER_PROGRAM_TO_IR_PROGRAM_TO_IR_H_

View File

@@ -1,80 +0,0 @@
// Copyright 2020 The Dawn & Tint Authors
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this
// list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "src/tint/lang/wgsl/reader/reader.h"
#include <limits>
#include <utility>
#include "src/tint/lang/wgsl/reader/lower/lower.h"
#include "src/tint/lang/wgsl/reader/parser/parser.h"
#include "src/tint/lang/wgsl/reader/program_to_ir/program_to_ir.h"
#include "src/tint/lang/wgsl/resolver/resolve.h"
namespace tint::wgsl::reader {
Program Parse(const Source::File* file, const Options& options) {
if (DAWN_UNLIKELY(file->content.data.size() >
static_cast<size_t>(std::numeric_limits<uint32_t>::max()))) {
ProgramBuilder b;
b.Diagnostics().AddError(tint::Source{}) << "WGSL source must be 0xffffffff bytes or fewer";
return Program(std::move(b));
}
Parser parser(file);
parser.Parse();
return resolver::Resolve(parser.builder(), options.allowed_features);
}
Result<core::ir::Module> WgslToIR(const Source::File* file, const Options& options) {
Program program = Parse(file, options);
return ProgramToLoweredIR(program);
}
Result<core::ir::Module> ProgramToLoweredIR(const Program& program,
InternalCompilerErrorCallback ice_callback) {
TINT_CHECK_RESULT_UNWRAP(ir, ProgramToIR(program));
ir.ice_callback = ice_callback;
// Lower from WGSL-dialect to core-dialect
TINT_CHECK_RESULT(Lower(ir));
return ir;
}
bool IsUnsupportedByIR(const ast::Enable* enable) {
for (auto ext : enable->extensions) {
switch (ext->name) {
case tint::wgsl::Extension::kChromiumExperimentalFramebufferFetch:
return true;
default:
break;
}
}
return false;
}
} // namespace tint::wgsl::reader

View File

@@ -1,75 +0,0 @@
// Copyright 2020 The Dawn & Tint Authors
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this
// list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#ifndef SRC_TINT_LANG_WGSL_READER_READER_H_
#define SRC_TINT_LANG_WGSL_READER_READER_H_
#include "src/tint/lang/core/ir/module.h"
#include "src/tint/lang/wgsl/program/program.h"
#include "src/tint/lang/wgsl/reader/options.h"
#include "src/tint/utils/result.h"
namespace tint::ast {
class Enable;
} // namespace tint::ast
namespace tint::wgsl::reader {
/// Parses the WGSL source, returning the parsed program.
/// If the source fails to parse then the returned
/// `program.Diagnostics.ContainsErrors()` will be true, and the
/// `program.Diagnostics()` will describe the error.
/// @param file the source file
/// @param options the configuration options to use when parsing WGSL
/// @returns the parsed program
Program Parse(const Source::File* file, const Options& options = {});
/// Parse a WGSL program from source, and return an IR module.
/// @param file the input WGSL file
/// @param options the configuration options to use when parsing WGSL
/// @returns the resulting IR module, or failure
Result<core::ir::Module> WgslToIR(const Source::File* file, const Options& options = {});
/// Builds a core-dialect core::ir::Module from the given Program
/// @param program the Program to use.
/// @param ice_callback the callback to use for any ICE produced while processing the IR module
/// @returns the core-dialect IR module.
///
/// @note this assumes the `program.IsValid()`, and has had const-eval done so
/// any abstract values have been calculated and converted into the relevant
/// concrete types.
Result<core::ir::Module> ProgramToLoweredIR(
const Program& program,
InternalCompilerErrorCallback ice_callback = std::nullopt);
/// Allows for checking if an extension is currently supported/unsupported by IR
/// before trying to convert to it.
bool IsUnsupportedByIR(const ast::Enable* enable);
} // namespace tint::wgsl::reader
#endif // SRC_TINT_LANG_WGSL_READER_READER_H_

View File

@@ -1059,10 +1059,6 @@ class State {
return b.ty.sampled_texture(t->Dim(), el);
},
[&](const core::type::StorageTexture* t) {
if (RequiresChromiumInternalGraphite(t)) {
Enable(wgsl::Extension::kChromiumInternalGraphite);
}
return b.ty.storage_texture(t->Dim(), t->TexelFormat(), t->Access());
},
[&](const core::type::Sampler* s) { return b.ty.sampler(s->Kind()); },
@@ -1411,12 +1407,6 @@ class State {
return false;
}
}
/// @returns true if the storage texture type requires the kChromiumInternalGraphite extension
/// to be enabled.
bool RequiresChromiumInternalGraphite(const core::type::StorageTexture* tex) {
return tex->TexelFormat() == core::TexelFormat::kR8Unorm;
}
};
} // namespace

View File

@@ -57,7 +57,7 @@ inline constexpr bool IsPowerOfTwo(T value) {
inline constexpr uint32_t Log2(uint64_t value) {
#if defined(__clang__) || defined(__GNUC__)
return 63 - static_cast<uint32_t>(__builtin_clzll(value));
#elif defined(_MSC_VER) && !defined(__clang__) && __cplusplus >= 202002L && defined(__x86_64__) // MSVC and C++20+
#elif 0 //defined(_MSC_VER) && !defined(__clang__) && __cplusplus >= 202002L // MSVC and C++20+
// note: std::is_constant_evaluated() added in C++20
// required here as _BitScanReverse64 is not constexpr
if (!std::is_constant_evaluated()) {
@@ -65,7 +65,7 @@ inline constexpr uint32_t Log2(uint64_t value) {
if constexpr (sizeof(unsigned long) == 8) { // 64-bit
// NOLINTNEXTLINE(runtime/int)
unsigned long first_bit_index = 0;
_tzcnt_u64(&first_bit_index, value);
_BitScanReverse64(&first_bit_index, value);
return first_bit_index;
} else { // 32-bit
// NOLINTNEXTLINE(runtime/int)

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -1,115 +0,0 @@
// Copyright 2023 The Dawn & Tint Authors
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this
// list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "src/tint/utils/strconv/parse_num.h"
#include <charconv>
#include "absl/strings/charconv.h"
namespace tint::strconv {
namespace {
// The unsafe buffer warnings here are intrinsic to how the underlying API being called operates, so
// cannot be easily avoided.
TINT_BEGIN_DISABLE_WARNING(UNSAFE_BUFFER_USAGE);
template <typename T>
Result<T, ParseNumberError> Parse(std::string_view number) {
T val = 0;
if constexpr (std::is_floating_point_v<T>) {
auto result = absl::from_chars(number.data(), number.data() + number.size(), val);
if (result.ec == std::errc::result_out_of_range) {
return ParseNumberError::kResultOutOfRange;
}
if (result.ec != std::errc() || result.ptr != number.data() + number.size()) {
return ParseNumberError::kUnparsable;
}
} else {
auto result = std::from_chars(number.data(), number.data() + number.size(), val);
if (result.ec == std::errc::result_out_of_range) {
return ParseNumberError::kResultOutOfRange;
}
if (result.ec != std::errc() || result.ptr != number.data() + number.size()) {
return ParseNumberError::kUnparsable;
}
}
return val;
}
TINT_END_DISABLE_WARNING(UNSAFE_BUFFER_USAGE);
} // namespace
Result<float, ParseNumberError> ParseFloat(std::string_view str) {
return Parse<float>(str);
}
Result<double, ParseNumberError> ParseDouble(std::string_view str) {
return Parse<double>(str);
}
Result<int, ParseNumberError> ParseInt(std::string_view str) {
return Parse<int>(str);
}
Result<unsigned int, ParseNumberError> ParseUint(std::string_view str) {
return Parse<unsigned int>(str);
}
Result<int64_t, ParseNumberError> ParseInt64(std::string_view str) {
return Parse<int64_t>(str);
}
Result<uint64_t, ParseNumberError> ParseUint64(std::string_view str) {
return Parse<uint64_t>(str);
}
Result<int32_t, ParseNumberError> ParseInt32(std::string_view str) {
return Parse<int32_t>(str);
}
Result<uint32_t, ParseNumberError> ParseUint32(std::string_view str) {
return Parse<uint32_t>(str);
}
Result<int16_t, ParseNumberError> ParseInt16(std::string_view str) {
return Parse<int16_t>(str);
}
Result<uint16_t, ParseNumberError> ParseUint16(std::string_view str) {
return Parse<uint16_t>(str);
}
Result<int8_t, ParseNumberError> ParseInt8(std::string_view str) {
return Parse<int8_t>(str);
}
Result<uint8_t, ParseNumberError> ParseUint8(std::string_view str) {
return Parse<uint8_t>(str);
}
} // namespace tint::strconv

View File

@@ -1,145 +0,0 @@
// Copyright 2023 The Dawn & Tint Authors
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this
// list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#ifndef SRC_TINT_UTILS_STRCONV_PARSE_NUM_H_
#define SRC_TINT_UTILS_STRCONV_PARSE_NUM_H_
#include <cstdint>
#include "src/tint/utils/macros/compiler.h"
#include "src/tint/utils/result.h"
namespace tint::strconv {
/// Error returned by the number parsing functions
enum class ParseNumberError : uint8_t {
/// The number was unparsable
kUnparsable,
/// The parsed number is not representable by the target datatype
kResultOutOfRange,
};
/// @param str the string
/// @returns the string @p str parsed as a float
Result<float, ParseNumberError> ParseFloat(std::string_view str);
/// @param str the string
/// @returns the string @p str parsed as a double
Result<double, ParseNumberError> ParseDouble(std::string_view str);
/// @param str the string
/// @returns the string @p str parsed as a int
Result<int, ParseNumberError> ParseInt(std::string_view str);
/// @param str the string
/// @returns the string @p str parsed as a unsigned int
Result<unsigned int, ParseNumberError> ParseUint(std::string_view str);
/// @param str the string
/// @returns the string @p str parsed as a int64_t
Result<int64_t, ParseNumberError> ParseInt64(std::string_view str);
/// @param str the string
/// @returns the string @p str parsed as a uint64_t
Result<uint64_t, ParseNumberError> ParseUint64(std::string_view str);
/// @param str the string
/// @returns the string @p str parsed as a int32_t
Result<int32_t, ParseNumberError> ParseInt32(std::string_view str);
/// @param str the string
/// @returns the string @p str parsed as a uint32_t
Result<uint32_t, ParseNumberError> ParseUint32(std::string_view str);
/// @param str the string
/// @returns the string @p str parsed as a int16_t
Result<int16_t, ParseNumberError> ParseInt16(std::string_view str);
/// @param str the string
/// @returns the string @p str parsed as a uint16_t
Result<uint16_t, ParseNumberError> ParseUint16(std::string_view str);
/// @param str the string
/// @returns the string @p str parsed as a int8_t
Result<int8_t, ParseNumberError> ParseInt8(std::string_view str);
/// @param str the string
/// @returns the string @p str parsed as a uint8_t
Result<uint8_t, ParseNumberError> ParseUint8(std::string_view str);
/// Disables the false-positive unreachable-code compiler warnings
TINT_BEGIN_DISABLE_WARNING(UNREACHABLE_CODE);
/// @param str the string
/// @returns the string @p str parsed as a the number @p T
template <typename T>
inline Result<T, ParseNumberError> ParseNumber(std::string_view str) {
if constexpr (std::is_same_v<T, float>) {
return ParseFloat(str);
}
if constexpr (std::is_same_v<T, double>) {
return ParseDouble(str);
}
if constexpr (std::is_same_v<T, int>) {
return ParseInt(str);
}
if constexpr (std::is_same_v<T, unsigned int>) {
return ParseUint(str);
}
if constexpr (std::is_same_v<T, int64_t>) {
return ParseInt64(str);
}
if constexpr (std::is_same_v<T, uint64_t>) {
return ParseUint64(str);
}
if constexpr (std::is_same_v<T, int32_t>) {
return ParseInt32(str);
}
if constexpr (std::is_same_v<T, uint32_t>) {
return ParseUint32(str);
}
if constexpr (std::is_same_v<T, int16_t>) {
return ParseInt16(str);
}
if constexpr (std::is_same_v<T, uint16_t>) {
return ParseUint16(str);
}
if constexpr (std::is_same_v<T, int8_t>) {
return ParseInt8(str);
}
if constexpr (std::is_same_v<T, uint8_t>) {
return ParseUint8(str);
}
return ParseNumberError::kUnparsable;
}
/// Re-enables the unreachable-code compiler warnings
TINT_END_DISABLE_WARNING(UNREACHABLE_CODE);
} // namespace tint::strconv
#endif // SRC_TINT_UTILS_STRCONV_PARSE_NUM_H_

View File

@@ -1,203 +0,0 @@
Apache License
Version 2.0, January 2004
https://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
https://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

View File

@@ -1,64 +0,0 @@
// Copyright 2017 The Abseil Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// -----------------------------------------------------------------------------
// File: algorithm.h
// -----------------------------------------------------------------------------
//
// This header file contains Google extensions to the standard <algorithm> C++
// header.
#ifndef ABSL_ALGORITHM_ALGORITHM_H_
#define ABSL_ALGORITHM_ALGORITHM_H_
#include <algorithm>
#include <iterator>
#include <type_traits>
#include "absl/base/config.h"
namespace absl {
ABSL_NAMESPACE_BEGIN
// equal()
// rotate()
//
// Historical note: Abseil once provided implementations of these algorithms
// prior to their adoption in C++14. New code should prefer to use the std
// variants.
//
// See the documentation for the STL <algorithm> header for more information:
// https://en.cppreference.com/w/cpp/header/algorithm
using std::equal;
using std::rotate;
// linear_search()
//
// Performs a linear search for `value` using the iterator `first` up to
// but not including `last`, returning true if [`first`, `last`) contains an
// element equal to `value`.
//
// A linear search is of O(n) complexity which is guaranteed to make at most
// n = (`last` - `first`) comparisons. A linear search over short containers
// may be faster than a binary search, even when the container is sorted.
template <typename InputIterator, typename EqualityComparable>
ABSL_INTERNAL_CONSTEXPR_SINCE_CXX20 bool linear_search(
InputIterator first, InputIterator last, const EqualityComparable& value) {
return std::find(first, last, value) != last;
}
ABSL_NAMESPACE_END
} // namespace absl
#endif // ABSL_ALGORITHM_ALGORITHM_H_

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -1,30 +0,0 @@
// Copyright 2024 The Abseil Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifdef __cplusplus
#error This is a C compile test
#endif
// This test ensures that headers that are included in legacy C code are
// compatible with C. Abseil is a C++ library. We do not desire to expand C
// compatibility or keep C compatibility forever. This test only exists to
// ensure C compatibility until it is no longer required. Do not add new code
// that requires C compatibility.
#include "absl/base/attributes.h" // IWYU pragma: keep
#include "absl/base/config.h" // IWYU pragma: keep
#include "absl/base/optimization.h" // IWYU pragma: keep
#include "absl/base/policy_checks.h" // IWYU pragma: keep
#include "absl/base/port.h" // IWYU pragma: keep
int main() { return 0; }

View File

@@ -1,227 +0,0 @@
// Copyright 2017 The Abseil Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// -----------------------------------------------------------------------------
// File: call_once.h
// -----------------------------------------------------------------------------
//
// This header file provides an Abseil version of `std::call_once` for invoking
// a given function at most once, across all threads. This Abseil version is
// faster than the C++11 version and incorporates the C++17 argument-passing
// fix, so that (for example) non-const references may be passed to the invoked
// function.
#ifndef ABSL_BASE_CALL_ONCE_H_
#define ABSL_BASE_CALL_ONCE_H_
#include <algorithm>
#include <atomic>
#include <cstdint>
#include <functional>
#include <type_traits>
#include <utility>
#include "absl/base/attributes.h"
#include "absl/base/config.h"
#include "absl/base/internal/low_level_scheduling.h"
#include "absl/base/internal/raw_logging.h"
#include "absl/base/internal/scheduling_mode.h"
#include "absl/base/internal/spinlock_wait.h"
#include "absl/base/macros.h"
#include "absl/base/nullability.h"
#include "absl/base/optimization.h"
#include "absl/base/port.h"
namespace absl {
ABSL_NAMESPACE_BEGIN
class once_flag;
namespace base_internal {
std::atomic<uint32_t>* absl_nonnull ControlWord(
absl::once_flag* absl_nonnull flag);
} // namespace base_internal
// call_once()
//
// For all invocations using a given `once_flag`, invokes a given `fn` exactly
// once across all threads. The first call to `call_once()` with a particular
// `once_flag` argument (that does not throw an exception) will run the
// specified function with the provided `args`; other calls with the same
// `once_flag` argument will not run the function, but will wait
// for the provided function to finish running (if it is still running).
//
// This mechanism provides a safe, simple, and fast mechanism for one-time
// initialization in a multi-threaded process.
//
// Example:
//
// class MyInitClass {
// public:
// ...
// mutable absl::once_flag once_;
//
// MyInitClass* init() const {
// absl::call_once(once_, &MyInitClass::Init, this);
// return ptr_;
// }
//
template <typename Callable, typename... Args>
void call_once(absl::once_flag& flag, Callable&& fn, Args&&... args);
// once_flag
//
// Objects of this type are used to distinguish calls to `call_once()` and
// ensure the provided function is only invoked once across all threads. This
// type is not copyable or movable. However, it has a `constexpr`
// constructor, and is safe to use as a namespace-scoped global variable.
class once_flag {
public:
constexpr once_flag() : control_(0) {}
once_flag(const once_flag&) = delete;
once_flag& operator=(const once_flag&) = delete;
private:
friend std::atomic<uint32_t>* absl_nonnull base_internal::ControlWord(
once_flag* absl_nonnull flag);
std::atomic<uint32_t> control_;
};
//------------------------------------------------------------------------------
// End of public interfaces.
// Implementation details follow.
//------------------------------------------------------------------------------
namespace base_internal {
// Like call_once, but uses KERNEL_ONLY scheduling. Intended to be used to
// initialize entities used by the scheduler implementation.
template <typename Callable, typename... Args>
void LowLevelCallOnce(absl::once_flag* absl_nonnull flag, Callable&& fn,
Args&&... args);
// Disables scheduling while on stack when scheduling mode is non-cooperative.
// No effect for cooperative scheduling modes.
class SchedulingHelper {
public:
explicit SchedulingHelper(base_internal::SchedulingMode mode) : mode_(mode) {
if (mode_ == base_internal::SCHEDULE_KERNEL_ONLY) {
guard_result_ = base_internal::SchedulingGuard::DisableRescheduling();
}
}
~SchedulingHelper() {
if (mode_ == base_internal::SCHEDULE_KERNEL_ONLY) {
base_internal::SchedulingGuard::EnableRescheduling(guard_result_);
}
}
private:
base_internal::SchedulingMode mode_;
bool guard_result_ = false;
};
// Bit patterns for call_once state machine values. Internal implementation
// detail, not for use by clients.
//
// The bit patterns are arbitrarily chosen from unlikely values, to aid in
// debugging. However, kOnceInit must be 0, so that a zero-initialized
// once_flag will be valid for immediate use.
enum {
kOnceInit = 0,
kOnceRunning = 0x65C2937B,
kOnceWaiter = 0x05A308D2,
// A very small constant is chosen for kOnceDone so that it fit in a single
// compare with immediate instruction for most common ISAs. This is verified
// for x86, POWER and ARM.
kOnceDone = 221, // Random Number
};
template <typename Callable, typename... Args>
void
CallOnceImpl(std::atomic<uint32_t>* absl_nonnull control,
base_internal::SchedulingMode scheduling_mode, Callable&& fn,
Args&&... args) {
#ifndef NDEBUG
{
uint32_t old_control = control->load(std::memory_order_relaxed);
if (old_control != kOnceInit &&
old_control != kOnceRunning &&
old_control != kOnceWaiter &&
old_control != kOnceDone) {
ABSL_RAW_LOG(FATAL, "Unexpected value for control word: 0x%lx",
static_cast<unsigned long>(old_control)); // NOLINT
}
}
#endif // NDEBUG
static const base_internal::SpinLockWaitTransition trans[] = {
{kOnceInit, kOnceRunning, true},
{kOnceRunning, kOnceWaiter, false},
{kOnceDone, kOnceDone, true}};
// Must do this before potentially modifying control word's state.
base_internal::SchedulingHelper maybe_disable_scheduling(scheduling_mode);
// Short circuit the simplest case to avoid procedure call overhead.
// The base_internal::SpinLockWait() call returns either kOnceInit or
// kOnceDone. If it returns kOnceDone, it must have loaded the control word
// with std::memory_order_acquire and seen a value of kOnceDone.
uint32_t old_control = kOnceInit;
if (control->compare_exchange_strong(old_control, kOnceRunning,
std::memory_order_relaxed) ||
base_internal::SpinLockWait(control, ABSL_ARRAYSIZE(trans), trans,
scheduling_mode) == kOnceInit) {
std::invoke(std::forward<Callable>(fn), std::forward<Args>(args)...);
old_control =
control->exchange(base_internal::kOnceDone, std::memory_order_release);
if (old_control == base_internal::kOnceWaiter) {
base_internal::SpinLockWake(control, true);
}
} // else *control is already kOnceDone
}
inline std::atomic<uint32_t>* absl_nonnull ControlWord(
once_flag* absl_nonnull flag) {
return &flag->control_;
}
template <typename Callable, typename... Args>
void LowLevelCallOnce(absl::once_flag* absl_nonnull flag, Callable&& fn,
Args&&... args) {
std::atomic<uint32_t>* once = base_internal::ControlWord(flag);
uint32_t s = once->load(std::memory_order_acquire);
if (ABSL_PREDICT_FALSE(s != base_internal::kOnceDone)) {
base_internal::CallOnceImpl(once, base_internal::SCHEDULE_KERNEL_ONLY,
std::forward<Callable>(fn),
std::forward<Args>(args)...);
}
}
} // namespace base_internal
template <typename Callable, typename... Args>
void
call_once(absl::once_flag& flag, Callable&& fn, Args&&... args) {
std::atomic<uint32_t>* once = base_internal::ControlWord(&flag);
uint32_t s = once->load(std::memory_order_acquire);
if (ABSL_PREDICT_FALSE(s != base_internal::kOnceDone)) {
base_internal::CallOnceImpl(
once, base_internal::SCHEDULE_COOPERATIVE_AND_KERNEL,
std::forward<Callable>(fn), std::forward<Args>(args)...);
}
}
ABSL_NAMESPACE_END
} // namespace absl
#endif // ABSL_BASE_CALL_ONCE_H_

View File

@@ -1,180 +0,0 @@
//
// Copyright 2017 The Abseil Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// -----------------------------------------------------------------------------
// File: casts.h
// -----------------------------------------------------------------------------
//
// This header file defines casting templates to fit use cases not covered by
// the standard casts provided in the C++ standard. As with all cast operations,
// use these with caution and only if alternatives do not exist.
#ifndef ABSL_BASE_CASTS_H_
#define ABSL_BASE_CASTS_H_
#include <cstring>
#include <memory>
#include <type_traits>
#include <utility>
#if defined(__cpp_lib_bit_cast) && __cpp_lib_bit_cast >= 201806L
#include <bit> // For std::bit_cast.
#endif // defined(__cpp_lib_bit_cast) && __cpp_lib_bit_cast >= 201806L
#include "absl/base/internal/identity.h"
#include "absl/base/macros.h"
#include "absl/meta/type_traits.h"
namespace absl {
ABSL_NAMESPACE_BEGIN
// implicit_cast()
//
// Performs an implicit conversion between types following the language
// rules for implicit conversion; if an implicit conversion is otherwise
// allowed by the language in the given context, this function performs such an
// implicit conversion.
//
// Example:
//
// // If the context allows implicit conversion:
// From from;
// To to = from;
//
// // Such code can be replaced by:
// implicit_cast<To>(from);
//
// An `implicit_cast()` may also be used to annotate numeric type conversions
// that, although safe, may produce compiler warnings (such as `long` to `int`).
// Additionally, an `implicit_cast()` is also useful within return statements to
// indicate a specific implicit conversion is being undertaken.
//
// Example:
//
// return implicit_cast<double>(size_in_bytes) / capacity_;
//
// Annotating code with `implicit_cast()` allows you to explicitly select
// particular overloads and template instantiations, while providing a safer
// cast than `reinterpret_cast()` or `static_cast()`.
//
// Additionally, an `implicit_cast()` can be used to allow upcasting within a
// type hierarchy where incorrect use of `static_cast()` could accidentally
// allow downcasting.
//
// Finally, an `implicit_cast()` can be used to perform implicit conversions
// from unrelated types that otherwise couldn't be implicitly cast directly;
// C++ will normally only implicitly cast "one step" in such conversions.
//
// That is, if C is a type which can be implicitly converted to B, with B being
// a type that can be implicitly converted to A, an `implicit_cast()` can be
// used to convert C to B (which the compiler can then implicitly convert to A
// using language rules).
//
// Example:
//
// // Assume an object C is convertible to B, which is implicitly convertible
// // to A
// A a = implicit_cast<B>(C);
//
// Such implicit cast chaining may be useful within template logic.
template <typename To>
constexpr To implicit_cast(typename absl::internal::type_identity_t<To> to) {
return to;
}
// bit_cast()
//
// Creates a value of the new type `Dest` whose representation is the same as
// that of the argument, which is of (deduced) type `Source` (a "bitwise cast";
// every bit in the value representation of the result is equal to the
// corresponding bit in the object representation of the source). Source and
// destination types must be of the same size, and both types must be trivially
// copyable.
//
// As with most casts, use with caution. A `bit_cast()` might be needed when you
// need to treat a value as the value of some other type, for example, to access
// the individual bits of an object which are not normally accessible through
// the object's type, such as for working with the binary representation of a
// floating point value:
//
// float f = 3.14159265358979;
// int i = bit_cast<int>(f);
// // i = 0x40490fdb
//
// Reinterpreting and accessing a value directly as a different type (as shown
// below) usually results in undefined behavior.
//
// Example:
//
// // WRONG
// float f = 3.14159265358979;
// int i = reinterpret_cast<int&>(f); // Wrong
// int j = *reinterpret_cast<int*>(&f); // Equally wrong
// int k = *bit_cast<int*>(&f); // Equally wrong
//
// Reinterpret-casting results in undefined behavior according to the ISO C++
// specification, section [basic.lval]. Roughly, this section says: if an object
// in memory has one type, and a program accesses it with a different type, the
// result is undefined behavior for most "different type".
//
// Using bit_cast on a pointer and then dereferencing it is no better than using
// reinterpret_cast. You should only use bit_cast on the value itself.
//
// Such casting results in type punning: holding an object in memory of one type
// and reading its bits back using a different type. A `bit_cast()` avoids this
// issue by copying the object representation to a new value, which avoids
// introducing this undefined behavior (since the original value is never
// accessed in the wrong way).
//
// The requirements of `absl::bit_cast` are more strict than that of
// `std::bit_cast` unless compiler support is available. Specifically, without
// compiler support, this implementation also requires `Dest` to be
// default-constructible. In C++20, `absl::bit_cast` is replaced by
// `std::bit_cast`.
#if defined(__cpp_lib_bit_cast) && __cpp_lib_bit_cast >= 201806L
using std::bit_cast;
#else // defined(__cpp_lib_bit_cast) && __cpp_lib_bit_cast >= 201806L
template <
typename Dest, typename Source,
typename std::enable_if<sizeof(Dest) == sizeof(Source) &&
std::is_trivially_copyable<Source>::value &&
std::is_trivially_copyable<Dest>::value
#if !ABSL_HAVE_BUILTIN(__builtin_bit_cast)
&& std::is_default_constructible<Dest>::value
#endif // !ABSL_HAVE_BUILTIN(__builtin_bit_cast)
,
int>::type = 0>
#if ABSL_HAVE_BUILTIN(__builtin_bit_cast)
inline constexpr Dest bit_cast(const Source& source) {
return __builtin_bit_cast(Dest, source);
}
#else // ABSL_HAVE_BUILTIN(__builtin_bit_cast)
inline Dest bit_cast(const Source& source) {
Dest dest;
memcpy(static_cast<void*>(std::addressof(dest)),
static_cast<const void*>(std::addressof(source)), sizeof(dest));
return dest;
}
#endif // ABSL_HAVE_BUILTIN(__builtin_bit_cast)
#endif // defined(__cpp_lib_bit_cast) && __cpp_lib_bit_cast >= 201806L
ABSL_NAMESPACE_END
} // namespace absl
#endif // ABSL_BASE_CASTS_H_

View File

@@ -1,877 +0,0 @@
//
// Copyright 2017 The Abseil Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// -----------------------------------------------------------------------------
// File: config.h
// -----------------------------------------------------------------------------
//
// This header file defines a set of macros for checking the presence of
// important compiler and platform features. Such macros can be used to
// produce portable code by parameterizing compilation based on the presence or
// lack of a given feature.
//
// We define a "feature" as some interface we wish to program to: for example,
// a library function or system call. A value of `1` indicates support for
// that feature; any other value indicates the feature support is undefined.
//
// Example:
//
// Suppose a programmer wants to write a program that uses the 'mmap()' system
// call. The Abseil macro for that feature (`ABSL_HAVE_MMAP`) allows you to
// selectively include the `mmap.h` header and bracket code using that feature
// in the macro:
//
// #include "absl/base/config.h"
//
// #ifdef ABSL_HAVE_MMAP
// #include "sys/mman.h"
// #endif //ABSL_HAVE_MMAP
//
// ...
// #ifdef ABSL_HAVE_MMAP
// void *ptr = mmap(...);
// ...
// #endif // ABSL_HAVE_MMAP
#ifndef ABSL_BASE_CONFIG_H_
#define ABSL_BASE_CONFIG_H_
// Included for the __GLIBC__ macro (or similar macros on other systems).
#include <limits.h>
#ifdef __cplusplus
// Included for __GLIBCXX__, _LIBCPP_VERSION
#include <cstddef>
#endif // __cplusplus
// ABSL_INTERNAL_CPLUSPLUS_LANG
//
// MSVC does not set the value of __cplusplus correctly, but instead uses
// _MSVC_LANG as a stand-in.
// https://docs.microsoft.com/en-us/cpp/preprocessor/predefined-macros
//
// However, there are reports that MSVC even sets _MSVC_LANG incorrectly at
// times, for example:
// https://github.com/microsoft/vscode-cpptools/issues/1770
// https://reviews.llvm.org/D70996
//
// For this reason, this symbol is considered INTERNAL and code outside of
// Abseil must not use it.
#if defined(_MSVC_LANG)
#define ABSL_INTERNAL_CPLUSPLUS_LANG _MSVC_LANG
#elif defined(__cplusplus)
#define ABSL_INTERNAL_CPLUSPLUS_LANG __cplusplus
#endif
#if defined(ABSL_INTERNAL_CPLUSPLUS_LANG) && \
ABSL_INTERNAL_CPLUSPLUS_LANG >= 202002L
// Include library feature test macros.
#include <version>
#endif
#if defined(__APPLE__)
// Included for TARGET_OS_IPHONE, __IPHONE_OS_VERSION_MIN_REQUIRED,
// __IPHONE_8_0.
#include <Availability.h>
#include <TargetConditionals.h>
#endif
#include "absl/base/options.h"
#include "absl/base/policy_checks.h"
// Abseil long-term support (LTS) releases will define
// `ABSL_LTS_RELEASE_VERSION` to the integer representing the date string of the
// LTS release version, and will define `ABSL_LTS_RELEASE_PATCH_LEVEL` to the
// integer representing the patch-level for that release.
//
// For example, for LTS release version "20300401.2", this would give us
// ABSL_LTS_RELEASE_VERSION == 20300401 && ABSL_LTS_RELEASE_PATCH_LEVEL == 2
//
// These symbols will not be defined in non-LTS code.
//
// Abseil recommends that clients live-at-head. Therefore, if you are using
// these symbols to assert a minimum version requirement, we recommend you do it
// as
//
// #if defined(ABSL_LTS_RELEASE_VERSION) && ABSL_LTS_RELEASE_VERSION < 20300401
// #error Project foo requires Abseil LTS version >= 20300401
// #endif
//
// The `defined(ABSL_LTS_RELEASE_VERSION)` part of the check excludes
// live-at-head clients from the minimum version assertion.
//
// See https://abseil.io/about/releases for more information on Abseil release
// management.
//
// LTS releases can be obtained from
// https://github.com/abseil/abseil-cpp/releases.
#undef ABSL_LTS_RELEASE_VERSION
#undef ABSL_LTS_RELEASE_PATCH_LEVEL
// Helper macro to convert a CPP variable to a string literal.
#define ABSL_INTERNAL_DO_TOKEN_STR(x) #x
#define ABSL_INTERNAL_TOKEN_STR(x) ABSL_INTERNAL_DO_TOKEN_STR(x)
// -----------------------------------------------------------------------------
// Abseil namespace annotations
// -----------------------------------------------------------------------------
// ABSL_NAMESPACE_BEGIN/ABSL_NAMESPACE_END
//
// An annotation placed at the beginning/end of each `namespace absl` scope.
// This is used to inject an inline namespace.
//
// The proper way to write Abseil code in the `absl` namespace is:
//
// namespace absl {
// ABSL_NAMESPACE_BEGIN
//
// void Foo(); // absl::Foo().
//
// ABSL_NAMESPACE_END
// } // namespace absl
//
// Users of Abseil should not use these macros, because users of Abseil should
// not write `namespace absl {` in their own code for any reason. (Abseil does
// not support forward declarations of its own types, nor does it support
// user-provided specialization of Abseil templates. Code that violates these
// rules may be broken without warning.)
#if !defined(ABSL_OPTION_USE_INLINE_NAMESPACE) || \
!defined(ABSL_OPTION_INLINE_NAMESPACE_NAME)
#error options.h is misconfigured.
#endif
// Check that ABSL_OPTION_INLINE_NAMESPACE_NAME is neither "head" nor ""
#if defined(__cplusplus) && ABSL_OPTION_USE_INLINE_NAMESPACE == 1
#define ABSL_INTERNAL_INLINE_NAMESPACE_STR \
ABSL_INTERNAL_TOKEN_STR(ABSL_OPTION_INLINE_NAMESPACE_NAME)
static_assert(ABSL_INTERNAL_INLINE_NAMESPACE_STR[0] != '\0',
"options.h misconfigured: ABSL_OPTION_INLINE_NAMESPACE_NAME must "
"not be empty.");
static_assert(ABSL_INTERNAL_INLINE_NAMESPACE_STR[0] != 'h' ||
ABSL_INTERNAL_INLINE_NAMESPACE_STR[1] != 'e' ||
ABSL_INTERNAL_INLINE_NAMESPACE_STR[2] != 'a' ||
ABSL_INTERNAL_INLINE_NAMESPACE_STR[3] != 'd' ||
ABSL_INTERNAL_INLINE_NAMESPACE_STR[4] != '\0',
"options.h misconfigured: ABSL_OPTION_INLINE_NAMESPACE_NAME must "
"be changed to a new, unique identifier name.");
#endif
#if ABSL_OPTION_USE_INLINE_NAMESPACE == 0
#define ABSL_NAMESPACE_BEGIN
#define ABSL_NAMESPACE_END
#define ABSL_INTERNAL_C_SYMBOL(x) x
#elif ABSL_OPTION_USE_INLINE_NAMESPACE == 1
#define ABSL_NAMESPACE_BEGIN \
inline namespace ABSL_OPTION_INLINE_NAMESPACE_NAME {
#define ABSL_NAMESPACE_END }
#define ABSL_INTERNAL_C_SYMBOL_HELPER_2(x, v) x##_##v
#define ABSL_INTERNAL_C_SYMBOL_HELPER_1(x, v) \
ABSL_INTERNAL_C_SYMBOL_HELPER_2(x, v)
#define ABSL_INTERNAL_C_SYMBOL(x) \
ABSL_INTERNAL_C_SYMBOL_HELPER_1(x, ABSL_OPTION_INLINE_NAMESPACE_NAME)
#else
#error options.h is misconfigured.
#endif
// -----------------------------------------------------------------------------
// Compiler Feature Checks
// -----------------------------------------------------------------------------
// ABSL_HAVE_BUILTIN()
//
// Checks whether the compiler supports a Clang Feature Checking Macro, and if
// so, checks whether it supports the provided builtin function "x" where x
// is one of the functions noted in
// https://clang.llvm.org/docs/LanguageExtensions.html
//
// Note: Use this macro to avoid an extra level of #ifdef __has_builtin check.
// http://releases.llvm.org/3.3/tools/clang/docs/LanguageExtensions.html
#ifdef __has_builtin
#define ABSL_HAVE_BUILTIN(x) __has_builtin(x)
#else
#define ABSL_HAVE_BUILTIN(x) 0
#endif
#ifdef __has_feature
#define ABSL_HAVE_FEATURE(f) __has_feature(f)
#else
#define ABSL_HAVE_FEATURE(f) 0
#endif
// Portable check for GCC minimum version:
// https://gcc.gnu.org/onlinedocs/cpp/Common-Predefined-Macros.html
#if defined(__GNUC__) && defined(__GNUC_MINOR__)
#define ABSL_INTERNAL_HAVE_MIN_GNUC_VERSION(x, y) \
(__GNUC__ > (x) || __GNUC__ == (x) && __GNUC_MINOR__ >= (y))
#else
#define ABSL_INTERNAL_HAVE_MIN_GNUC_VERSION(x, y) 0
#endif
#if defined(__clang__) && defined(__clang_major__) && defined(__clang_minor__)
#define ABSL_INTERNAL_HAVE_MIN_CLANG_VERSION(x, y) \
(__clang_major__ > (x) || __clang_major__ == (x) && __clang_minor__ >= (y))
#else
#define ABSL_INTERNAL_HAVE_MIN_CLANG_VERSION(x, y) 0
#endif
// ABSL_HAVE_TLS is defined to 1 when __thread should be supported.
// We assume __thread is supported on Linux when compiled with Clang or
// compiled against libstdc++ with _GLIBCXX_HAVE_TLS defined.
#ifdef ABSL_HAVE_TLS
#error ABSL_HAVE_TLS cannot be directly set
#elif (defined(__linux__)) && (defined(__clang__) || defined(_GLIBCXX_HAVE_TLS))
#define ABSL_HAVE_TLS 1
#elif defined(__INTEL_LLVM_COMPILER)
#define ABSL_HAVE_TLS 1
#endif
// ABSL_HAVE_STD_IS_TRIVIALLY_DESTRUCTIBLE
//
// Checks whether `std::is_trivially_destructible<T>` is supported.
#ifdef ABSL_HAVE_STD_IS_TRIVIALLY_DESTRUCTIBLE
#error ABSL_HAVE_STD_IS_TRIVIALLY_DESTRUCTIBLE cannot be directly set
#define ABSL_HAVE_STD_IS_TRIVIALLY_DESTRUCTIBLE 1
#endif
// ABSL_HAVE_STD_IS_TRIVIALLY_CONSTRUCTIBLE
//
// Checks whether `std::is_trivially_default_constructible<T>` and
// `std::is_trivially_copy_constructible<T>` are supported.
#ifdef ABSL_HAVE_STD_IS_TRIVIALLY_CONSTRUCTIBLE
#error ABSL_HAVE_STD_IS_TRIVIALLY_CONSTRUCTIBLE cannot be directly set
#else
#define ABSL_HAVE_STD_IS_TRIVIALLY_CONSTRUCTIBLE 1
#endif
// ABSL_HAVE_STD_IS_TRIVIALLY_ASSIGNABLE
//
// Checks whether `std::is_trivially_copy_assignable<T>` is supported.
#ifdef ABSL_HAVE_STD_IS_TRIVIALLY_ASSIGNABLE
#error ABSL_HAVE_STD_IS_TRIVIALLY_ASSIGNABLE cannot be directly set
#else
#define ABSL_HAVE_STD_IS_TRIVIALLY_ASSIGNABLE 1
#endif
// ABSL_HAVE_STD_IS_TRIVIALLY_COPYABLE
//
// Checks whether `std::is_trivially_copyable<T>` is supported.
#ifdef ABSL_HAVE_STD_IS_TRIVIALLY_COPYABLE
#error ABSL_HAVE_STD_IS_TRIVIALLY_COPYABLE cannot be directly set
#define ABSL_HAVE_STD_IS_TRIVIALLY_COPYABLE 1
#endif
// ABSL_HAVE_THREAD_LOCAL
//
// Checks whether the `thread_local` storage duration specifier is supported.
#ifdef ABSL_HAVE_THREAD_LOCAL
#error ABSL_HAVE_THREAD_LOCAL cannot be directly set
#elif !defined(__XTENSA__)
#define ABSL_HAVE_THREAD_LOCAL 1
#endif
// ABSL_HAVE_INTRINSIC_INT128
//
// Checks whether the __int128 compiler extension for a 128-bit integral type is
// supported.
//
// Note: __SIZEOF_INT128__ is defined by Clang and GCC when __int128 is
// supported, but we avoid using it in certain cases:
// * On Clang:
// * Building using Clang for Windows, where the Clang runtime library has
// 128-bit support only on LP64 architectures, but Windows is LLP64.
// * On Nvidia's nvcc:
// * nvcc also defines __GNUC__ and __SIZEOF_INT128__, but not all versions
// actually support __int128.
#ifdef ABSL_HAVE_INTRINSIC_INT128
#error ABSL_HAVE_INTRINSIC_INT128 cannot be directly set
#elif defined(__SIZEOF_INT128__)
#if (defined(__clang__) && !defined(_WIN32)) || \
(defined(__CUDACC__) && __CUDACC_VER_MAJOR__ >= 9) || \
(defined(__GNUC__) && !defined(__clang__) && !defined(__CUDACC__))
#define ABSL_HAVE_INTRINSIC_INT128 1
#elif defined(__CUDACC__)
// __CUDACC_VER__ is a full version number before CUDA 9, and is defined to a
// string explaining that it has been removed starting with CUDA 9. We use
// nested #ifs because there is no short-circuiting in the preprocessor.
// NOTE: `__CUDACC__` could be undefined while `__CUDACC_VER__` is defined.
#if __CUDACC_VER__ >= 70000
#define ABSL_HAVE_INTRINSIC_INT128 1
#endif // __CUDACC_VER__ >= 70000
#endif // defined(__CUDACC__)
#endif // ABSL_HAVE_INTRINSIC_INT128
// ABSL_HAVE_EXCEPTIONS
//
// Checks whether the compiler both supports and enables exceptions. Many
// compilers support a "no exceptions" mode that disables exceptions.
//
// Generally, when ABSL_HAVE_EXCEPTIONS is not defined:
//
// * Code using `throw` and `try` may not compile.
// * The `noexcept` specifier will still compile and behave as normal.
// * The `noexcept` operator may still return `false`.
//
// For further details, consult the compiler's documentation.
#ifdef ABSL_HAVE_EXCEPTIONS
#error ABSL_HAVE_EXCEPTIONS cannot be directly set.
#elif ABSL_INTERNAL_HAVE_MIN_CLANG_VERSION(3, 6)
// Clang >= 3.6
#if ABSL_HAVE_FEATURE(cxx_exceptions)
#define ABSL_HAVE_EXCEPTIONS 1
#endif // ABSL_HAVE_FEATURE(cxx_exceptions)
#elif defined(__clang__)
// Clang < 3.6
// http://releases.llvm.org/3.6.0/tools/clang/docs/ReleaseNotes.html#the-exceptions-macro
#if defined(__EXCEPTIONS) && ABSL_HAVE_FEATURE(cxx_exceptions)
#define ABSL_HAVE_EXCEPTIONS 1
#endif // defined(__EXCEPTIONS) && ABSL_HAVE_FEATURE(cxx_exceptions)
// Handle remaining special cases and default to exceptions being supported.
#elif !(defined(__GNUC__) && !defined(__cpp_exceptions)) && \
!(defined(_MSC_VER) && !defined(_CPPUNWIND))
#define ABSL_HAVE_EXCEPTIONS 1
#endif
// -----------------------------------------------------------------------------
// Platform Feature Checks
// -----------------------------------------------------------------------------
// Currently supported operating systems and associated preprocessor
// symbols:
//
// Linux and Linux-derived __linux__
// Android __ANDROID__ (implies __linux__)
// Linux (non-Android) __linux__ && !__ANDROID__
// Darwin (macOS and iOS) __APPLE__
// Akaros (http://akaros.org) __ros__
// Windows _WIN32
// AsmJS __asmjs__
// WebAssembly (Emscripten) __EMSCRIPTEN__
// Fuchsia __Fuchsia__
// WebAssembly (WASI) _WASI_EMULATED_MMAN (implies __wasi__)
//
// Note that since Android defines both __ANDROID__ and __linux__, one
// may probe for either Linux or Android by simply testing for __linux__.
// ABSL_HAVE_MMAP
//
// Checks whether the platform has an mmap(2) implementation as defined in
// POSIX.1-2001.
#ifdef ABSL_HAVE_MMAP
#error ABSL_HAVE_MMAP cannot be directly set
#elif defined(__linux__) || defined(__APPLE__) || defined(__FreeBSD__) || \
defined(_AIX) || defined(__ros__) || defined(__asmjs__) || \
defined(__EMSCRIPTEN__) || defined(__Fuchsia__) || defined(__sun) || \
defined(__myriad2__) || defined(__HAIKU__) || defined(__OpenBSD__) || \
defined(__NetBSD__) || defined(__QNX__) || defined(__VXWORKS__) || \
defined(__hexagon__) || defined(__XTENSA__) || \
defined(_WASI_EMULATED_MMAN)
#define ABSL_HAVE_MMAP 1
#endif
// ABSL_HAVE_PTHREAD_GETSCHEDPARAM
//
// Checks whether the platform implements the pthread_(get|set)schedparam(3)
// functions as defined in POSIX.1-2001.
#ifdef ABSL_HAVE_PTHREAD_GETSCHEDPARAM
#error ABSL_HAVE_PTHREAD_GETSCHEDPARAM cannot be directly set
#elif defined(__linux__) || defined(__APPLE__) || defined(__FreeBSD__) || \
defined(_AIX) || defined(__ros__) || defined(__OpenBSD__) || \
defined(__NetBSD__) || defined(__VXWORKS__)
#define ABSL_HAVE_PTHREAD_GETSCHEDPARAM 1
#endif
// ABSL_HAVE_SCHED_GETCPU
//
// Checks whether sched_getcpu is available.
#ifdef ABSL_HAVE_SCHED_GETCPU
#error ABSL_HAVE_SCHED_GETCPU cannot be directly set
#elif defined(__linux__)
#define ABSL_HAVE_SCHED_GETCPU 1
#endif
// ABSL_HAVE_SCHED_YIELD
//
// Checks whether the platform implements sched_yield(2) as defined in
// POSIX.1-2001.
#ifdef ABSL_HAVE_SCHED_YIELD
#error ABSL_HAVE_SCHED_YIELD cannot be directly set
#elif defined(__linux__) || defined(__ros__) || defined(__native_client__) || \
defined(__VXWORKS__)
#define ABSL_HAVE_SCHED_YIELD 1
#endif
// ABSL_HAVE_SEMAPHORE_H
//
// Checks whether the platform supports the <semaphore.h> header and sem_init(3)
// family of functions as standardized in POSIX.1-2001.
//
// Note: While Apple provides <semaphore.h> for both iOS and macOS, it is
// explicitly deprecated and will cause build failures if enabled for those
// platforms. We side-step the issue by not defining it here for Apple
// platforms.
#ifdef ABSL_HAVE_SEMAPHORE_H
#error ABSL_HAVE_SEMAPHORE_H cannot be directly set
#elif defined(__linux__) || defined(__ros__) || defined(__VXWORKS__)
#define ABSL_HAVE_SEMAPHORE_H 1
#endif
// ABSL_HAVE_ALARM
//
// Checks whether the platform supports the <signal.h> header and alarm(2)
// function as standardized in POSIX.1-2001.
#ifdef ABSL_HAVE_ALARM
#error ABSL_HAVE_ALARM cannot be directly set
#elif defined(__GOOGLE_GRTE_VERSION__)
// feature tests for Google's GRTE
#define ABSL_HAVE_ALARM 1
#elif defined(__GLIBC__)
// feature test for glibc
#define ABSL_HAVE_ALARM 1
#elif defined(_MSC_VER)
// feature tests for Microsoft's library
#elif defined(__MINGW32__)
// mingw32 doesn't provide alarm(2):
// https://osdn.net/projects/mingw/scm/git/mingw-org-wsl/blobs/5.2-trunk/mingwrt/include/unistd.h
// mingw-w64 provides a no-op implementation:
// https://sourceforge.net/p/mingw-w64/mingw-w64/ci/master/tree/mingw-w64-crt/misc/alarm.c
#elif defined(__EMSCRIPTEN__)
// emscripten doesn't support signals
#elif defined(__wasi__)
// WASI doesn't support signals
#elif defined(__Fuchsia__)
// Signals don't exist on fuchsia.
#elif defined(__hexagon__)
#else
// other standard libraries
#define ABSL_HAVE_ALARM 1
#endif
// ABSL_IS_LITTLE_ENDIAN
// ABSL_IS_BIG_ENDIAN
//
// Checks the endianness of the platform.
//
// Prefer using `std::endian` in C++20, or `absl::endian` from
// absl/numeric/bits.h prior to C++20.
//
// Notes: uses the built in endian macros provided by GCC (since 4.6) and
// Clang (since 3.2); see
// https://gcc.gnu.org/onlinedocs/cpp/Common-Predefined-Macros.html.
// Otherwise, if _WIN32, assume little endian. Otherwise, bail with an error.
#if defined(ABSL_IS_BIG_ENDIAN)
#error "ABSL_IS_BIG_ENDIAN cannot be directly set."
#endif
#if defined(ABSL_IS_LITTLE_ENDIAN)
#error "ABSL_IS_LITTLE_ENDIAN cannot be directly set."
#endif
#if (defined(__BYTE_ORDER__) && defined(__ORDER_LITTLE_ENDIAN__) && \
__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__)
#define ABSL_IS_LITTLE_ENDIAN 1
#elif defined(__BYTE_ORDER__) && defined(__ORDER_BIG_ENDIAN__) && \
__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
#define ABSL_IS_BIG_ENDIAN 1
#elif defined(_WIN32)
#define ABSL_IS_LITTLE_ENDIAN 1
#else
#error "absl endian detection needs to be set up for your compiler"
#endif
// macOS < 10.13 and iOS < 12 don't support <any>, <optional>, or <variant>
// because the libc++ shared library shipped on the system doesn't have the
// requisite exported symbols. See
// https://github.com/abseil/abseil-cpp/issues/207 and
// https://developer.apple.com/documentation/xcode_release_notes/xcode_10_release_notes
//
// libc++ spells out the availability requirements in the file
// llvm-project/libcxx/include/__config via the #define
// _LIBCPP_AVAILABILITY_BAD_OPTIONAL_ACCESS. The set of versions has been
// modified a few times, via
// https://github.com/llvm/llvm-project/commit/7fb40e1569dd66292b647f4501b85517e9247953
// and
// https://github.com/llvm/llvm-project/commit/0bc451e7e137c4ccadcd3377250874f641ca514a
// The second has the actually correct versions, thus, is what we copy here.
#if defined(__APPLE__) && \
((defined(__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__) && \
__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ < 101300) || \
(defined(__ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__) && \
__ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__ < 120000) || \
(defined(__ENVIRONMENT_WATCH_OS_VERSION_MIN_REQUIRED__) && \
__ENVIRONMENT_WATCH_OS_VERSION_MIN_REQUIRED__ < 50000) || \
(defined(__ENVIRONMENT_TV_OS_VERSION_MIN_REQUIRED__) && \
__ENVIRONMENT_TV_OS_VERSION_MIN_REQUIRED__ < 120000))
#define ABSL_INTERNAL_APPLE_CXX17_TYPES_UNAVAILABLE 1
#else
#define ABSL_INTERNAL_APPLE_CXX17_TYPES_UNAVAILABLE 0
#endif
// Deprecated macros for polyfill detection.
#define ABSL_HAVE_STD_ANY 1
#define ABSL_USES_STD_ANY 1
#define ABSL_HAVE_STD_OPTIONAL 1
#define ABSL_USES_STD_OPTIONAL 1
#define ABSL_HAVE_STD_VARIANT 1
#define ABSL_USES_STD_VARIANT 1
// ABSL_HAVE_STD_STRING_VIEW
//
// Deprecated: always defined to 1.
// std::string_view was added in C++17, which means all versions of C++
// supported by Abseil have it.
#ifdef ABSL_HAVE_STD_STRING_VIEW
#error "ABSL_HAVE_STD_STRING_VIEW cannot be directly set."
#else
#define ABSL_HAVE_STD_STRING_VIEW 1
#endif
// ABSL_HAVE_STD_ORDERING
//
// Checks whether C++20 std::{partial,weak,strong}_ordering are available.
//
// __cpp_lib_three_way_comparison is missing on libc++
// (https://github.com/llvm/llvm-project/issues/73953) so treat it as defined
// when building in C++20 mode.
#ifdef ABSL_HAVE_STD_ORDERING
#error "ABSL_HAVE_STD_ORDERING cannot be directly set."
#elif (defined(__cpp_lib_three_way_comparison) && \
__cpp_lib_three_way_comparison >= 201907L) || \
(defined(ABSL_INTERNAL_CPLUSPLUS_LANG) && \
ABSL_INTERNAL_CPLUSPLUS_LANG >= 202002L)
#define ABSL_HAVE_STD_ORDERING 1
#endif
// ABSL_USES_STD_STRING_VIEW
//
// Indicates whether absl::string_view is an alias for std::string_view.
#if !defined(ABSL_OPTION_USE_STD_STRING_VIEW)
#error options.h is misconfigured.
#elif ABSL_OPTION_USE_STD_STRING_VIEW == 0
#undef ABSL_USES_STD_STRING_VIEW
#elif ABSL_OPTION_USE_STD_STRING_VIEW == 1 || \
ABSL_OPTION_USE_STD_STRING_VIEW == 2
#define ABSL_USES_STD_STRING_VIEW 1
#else
#error options.h is misconfigured.
#endif
// ABSL_USES_STD_ORDERING
//
// Indicates whether absl::{partial,weak,strong}_ordering are aliases for the
// std:: ordering types.
#if !defined(ABSL_OPTION_USE_STD_ORDERING)
#error options.h is misconfigured.
#elif ABSL_OPTION_USE_STD_ORDERING == 0 || \
(ABSL_OPTION_USE_STD_ORDERING == 2 && !defined(ABSL_HAVE_STD_ORDERING))
#undef ABSL_USES_STD_ORDERING
#elif ABSL_OPTION_USE_STD_ORDERING == 1 || \
(ABSL_OPTION_USE_STD_ORDERING == 2 && defined(ABSL_HAVE_STD_ORDERING))
#define ABSL_USES_STD_ORDERING 1
#else
#error options.h is misconfigured.
#endif
// ABSL_INTERNAL_MANGLED_NS
// ABSL_INTERNAL_MANGLED_BACKREFERENCE
//
// Internal macros for building up mangled names in our internal fork of CCTZ.
// This implementation detail is only needed and provided for the MSVC build.
//
// These macros both expand to string literals. ABSL_INTERNAL_MANGLED_NS is
// the mangled spelling of the `absl` namespace, and
// ABSL_INTERNAL_MANGLED_BACKREFERENCE is a back-reference integer representing
// the proper count to skip past the CCTZ fork namespace names. (This number
// is one larger when there is an inline namespace name to skip.)
#if defined(_MSC_VER)
#if ABSL_OPTION_USE_INLINE_NAMESPACE == 0
#define ABSL_INTERNAL_MANGLED_NS "absl"
#define ABSL_INTERNAL_MANGLED_BACKREFERENCE "5"
#else
#define ABSL_INTERNAL_MANGLED_NS \
ABSL_INTERNAL_TOKEN_STR(ABSL_OPTION_INLINE_NAMESPACE_NAME) "@absl"
#define ABSL_INTERNAL_MANGLED_BACKREFERENCE "6"
#endif
#endif
// ABSL_DLL
//
// When building Abseil as a DLL, this macro expands to `__declspec(dllexport)`
// so we can annotate symbols appropriately as being exported. When used in
// headers consuming a DLL, this macro expands to `__declspec(dllimport)` so
// that consumers know the symbol is defined inside the DLL. In all other cases,
// the macro expands to nothing.
#if defined(_MSC_VER)
#if defined(ABSL_BUILD_DLL)
#define ABSL_DLL __declspec(dllexport)
#elif defined(ABSL_CONSUME_DLL)
#define ABSL_DLL __declspec(dllimport)
#else
#define ABSL_DLL
#endif
#else
#define ABSL_DLL
#endif // defined(_MSC_VER)
#if defined(_MSC_VER)
#if defined(ABSL_BUILD_TEST_DLL)
#define ABSL_TEST_DLL __declspec(dllexport)
#elif defined(ABSL_CONSUME_TEST_DLL)
#define ABSL_TEST_DLL __declspec(dllimport)
#else
#define ABSL_TEST_DLL
#endif
#else
#define ABSL_TEST_DLL
#endif // defined(_MSC_VER)
// ABSL_HAVE_MEMORY_SANITIZER
//
// MemorySanitizer (MSan) is a detector of uninitialized reads. It consists of
// a compiler instrumentation module and a run-time library.
#ifdef ABSL_HAVE_MEMORY_SANITIZER
#error "ABSL_HAVE_MEMORY_SANITIZER cannot be directly set."
#elif !defined(__native_client__) && ABSL_HAVE_FEATURE(memory_sanitizer)
#define ABSL_HAVE_MEMORY_SANITIZER 1
#endif
// ABSL_HAVE_THREAD_SANITIZER
//
// ThreadSanitizer (TSan) is a fast data race detector.
#ifdef ABSL_HAVE_THREAD_SANITIZER
#error "ABSL_HAVE_THREAD_SANITIZER cannot be directly set."
#elif defined(__SANITIZE_THREAD__)
#define ABSL_HAVE_THREAD_SANITIZER 1
#elif ABSL_HAVE_FEATURE(thread_sanitizer)
#define ABSL_HAVE_THREAD_SANITIZER 1
#endif
// ABSL_HAVE_ADDRESS_SANITIZER
//
// AddressSanitizer (ASan) is a fast memory error detector.
#ifdef ABSL_HAVE_ADDRESS_SANITIZER
#error "ABSL_HAVE_ADDRESS_SANITIZER cannot be directly set."
#elif defined(__SANITIZE_ADDRESS__)
#define ABSL_HAVE_ADDRESS_SANITIZER 1
#elif ABSL_HAVE_FEATURE(address_sanitizer)
#define ABSL_HAVE_ADDRESS_SANITIZER 1
#endif
// ABSL_HAVE_HWADDRESS_SANITIZER
//
// Hardware-Assisted AddressSanitizer (or HWASAN) is even faster than asan
// memory error detector which can use CPU features like ARM TBI, Intel LAM or
// AMD UAI.
#ifdef ABSL_HAVE_HWADDRESS_SANITIZER
#error "ABSL_HAVE_HWADDRESS_SANITIZER cannot be directly set."
#elif defined(__SANITIZE_HWADDRESS__)
#define ABSL_HAVE_HWADDRESS_SANITIZER 1
#elif ABSL_HAVE_FEATURE(hwaddress_sanitizer)
#define ABSL_HAVE_HWADDRESS_SANITIZER 1
#endif
// ABSL_HAVE_DATAFLOW_SANITIZER
//
// Dataflow Sanitizer (or DFSAN) is a generalised dynamic data flow analysis.
#ifdef ABSL_HAVE_DATAFLOW_SANITIZER
#error "ABSL_HAVE_DATAFLOW_SANITIZER cannot be directly set."
#elif defined(DATAFLOW_SANITIZER)
// GCC provides no method for detecting the presence of the standalone
// DataFlowSanitizer (-fsanitize=dataflow), so GCC users of -fsanitize=dataflow
// should also use -DDATAFLOW_SANITIZER.
#define ABSL_HAVE_DATAFLOW_SANITIZER 1
#elif ABSL_HAVE_FEATURE(dataflow_sanitizer)
#define ABSL_HAVE_DATAFLOW_SANITIZER 1
#endif
// ABSL_HAVE_LEAK_SANITIZER
//
// LeakSanitizer (or lsan) is a detector of memory leaks.
// https://clang.llvm.org/docs/LeakSanitizer.html
// https://github.com/google/sanitizers/wiki/AddressSanitizerLeakSanitizer
//
// The macro ABSL_HAVE_LEAK_SANITIZER can be used to detect at compile-time
// whether the LeakSanitizer is potentially available. However, just because the
// LeakSanitizer is available does not mean it is active. Use the
// always-available run-time interface in //absl/debugging/leak_check.h for
// interacting with LeakSanitizer.
#ifdef ABSL_HAVE_LEAK_SANITIZER
#error "ABSL_HAVE_LEAK_SANITIZER cannot be directly set."
#elif defined(LEAK_SANITIZER)
// GCC provides no method for detecting the presence of the standalone
// LeakSanitizer (-fsanitize=leak), so GCC users of -fsanitize=leak should also
// use -DLEAK_SANITIZER.
#define ABSL_HAVE_LEAK_SANITIZER 1
// Clang standalone LeakSanitizer (-fsanitize=leak)
#elif ABSL_HAVE_FEATURE(leak_sanitizer)
#define ABSL_HAVE_LEAK_SANITIZER 1
#elif defined(ABSL_HAVE_ADDRESS_SANITIZER)
// GCC or Clang using the LeakSanitizer integrated into AddressSanitizer.
#define ABSL_HAVE_LEAK_SANITIZER 1
#endif
// ABSL_HAVE_CLASS_TEMPLATE_ARGUMENT_DEDUCTION
//
// Deprecated: always defined to 1.
// Class template argument deduction is a language feature added in C++17,
// which means all versions of C++ supported by Abseil have it.
#ifdef ABSL_HAVE_CLASS_TEMPLATE_ARGUMENT_DEDUCTION
#error "ABSL_HAVE_CLASS_TEMPLATE_ARGUMENT_DEDUCTION cannot be directly set."
#else
#define ABSL_HAVE_CLASS_TEMPLATE_ARGUMENT_DEDUCTION 1
#endif
// `ABSL_INTERNAL_HAS_RTTI` determines whether abseil is being compiled with
// RTTI support.
#ifdef ABSL_INTERNAL_HAS_RTTI
#error ABSL_INTERNAL_HAS_RTTI cannot be directly set
#elif ABSL_HAVE_FEATURE(cxx_rtti)
#define ABSL_INTERNAL_HAS_RTTI 1
#elif defined(__GNUC__) && defined(__GXX_RTTI)
#define ABSL_INTERNAL_HAS_RTTI 1
#elif defined(_MSC_VER) && defined(_CPPRTTI)
#define ABSL_INTERNAL_HAS_RTTI 1
#elif !defined(__GNUC__) && !defined(_MSC_VER)
// Unknown compiler, default to RTTI
#define ABSL_INTERNAL_HAS_RTTI 1
#endif
// `ABSL_INTERNAL_HAS_CXA_DEMANGLE` determines whether `abi::__cxa_demangle` is
// available.
#ifdef ABSL_INTERNAL_HAS_CXA_DEMANGLE
#error ABSL_INTERNAL_HAS_CXA_DEMANGLE cannot be directly set
#elif defined(OS_ANDROID) && (defined(__i386__) || defined(__x86_64__))
#define ABSL_INTERNAL_HAS_CXA_DEMANGLE 0
#elif defined(__GNUC__)
#define ABSL_INTERNAL_HAS_CXA_DEMANGLE 1
#elif defined(__clang__) && !defined(_MSC_VER)
#define ABSL_INTERNAL_HAS_CXA_DEMANGLE 1
#endif
// ABSL_INTERNAL_HAVE_SSE is used for compile-time detection of SSE support.
// See https://gcc.gnu.org/onlinedocs/gcc/x86-Options.html for an overview of
// which architectures support the various x86 instruction sets.
#ifdef ABSL_INTERNAL_HAVE_SSE
#error ABSL_INTERNAL_HAVE_SSE cannot be directly set
#elif defined(__SSE__)
#define ABSL_INTERNAL_HAVE_SSE 1
#elif (defined(_M_X64) || (defined(_M_IX86_FP) && _M_IX86_FP >= 1)) && \
!defined(_M_ARM64EC)
// MSVC only defines _M_IX86_FP for x86 32-bit code, and _M_IX86_FP >= 1
// indicates that at least SSE was targeted with the /arch:SSE option.
// All x86-64 processors support SSE, so support can be assumed.
// https://docs.microsoft.com/en-us/cpp/preprocessor/predefined-macros
#define ABSL_INTERNAL_HAVE_SSE 1
#endif
// ABSL_INTERNAL_HAVE_SSE2 is used for compile-time detection of SSE2 support.
// See https://gcc.gnu.org/onlinedocs/gcc/x86-Options.html for an overview of
// which architectures support the various x86 instruction sets.
#ifdef ABSL_INTERNAL_HAVE_SSE2
#error ABSL_INTERNAL_HAVE_SSE2 cannot be directly set
#elif defined(__SSE2__)
#define ABSL_INTERNAL_HAVE_SSE2 1
#elif (defined(_M_X64) || (defined(_M_IX86_FP) && _M_IX86_FP >= 2)) && \
!defined(_M_ARM64EC)
// MSVC only defines _M_IX86_FP for x86 32-bit code, and _M_IX86_FP >= 2
// indicates that at least SSE2 was targeted with the /arch:SSE2 option.
// All x86-64 processors support SSE2, so support can be assumed.
// https://docs.microsoft.com/en-us/cpp/preprocessor/predefined-macros
#define ABSL_INTERNAL_HAVE_SSE2 1
#endif
// ABSL_INTERNAL_HAVE_SSSE3 is used for compile-time detection of SSSE3 support.
// See https://gcc.gnu.org/onlinedocs/gcc/x86-Options.html for an overview of
// which architectures support the various x86 instruction sets.
//
// MSVC does not have a mode that targets SSSE3 at compile-time. To use SSSE3
// with MSVC requires either assuming that the code will only every run on CPUs
// that support SSSE3, otherwise __cpuid() can be used to detect support at
// runtime and fallback to a non-SSSE3 implementation when SSSE3 is unsupported
// by the CPU.
#ifdef ABSL_INTERNAL_HAVE_SSSE3
#error ABSL_INTERNAL_HAVE_SSSE3 cannot be directly set
#elif defined(__SSSE3__)
#define ABSL_INTERNAL_HAVE_SSSE3 1
#endif
// ABSL_INTERNAL_HAVE_ARM_NEON is used for compile-time detection of NEON (ARM
// SIMD).
//
// If __CUDA_ARCH__ is defined, then we are compiling CUDA code in device mode.
// In device mode, NEON intrinsics are not available, regardless of host
// platform.
// https://llvm.org/docs/CompileCudaWithLLVM.html#detecting-clang-vs-nvcc-from-code
#ifdef ABSL_INTERNAL_HAVE_ARM_NEON
#error ABSL_INTERNAL_HAVE_ARM_NEON cannot be directly set
#elif defined(__ARM_NEON) && !(defined(__NVCC__) && defined(__CUDACC__))
#define ABSL_INTERNAL_HAVE_ARM_NEON 1
#endif
// ABSL_HAVE_CONSTANT_EVALUATED is used for compile-time detection of
// constant evaluation support through `absl::is_constant_evaluated`.
#ifdef ABSL_HAVE_CONSTANT_EVALUATED
#error ABSL_HAVE_CONSTANT_EVALUATED cannot be directly set
#endif
#ifdef __cpp_lib_is_constant_evaluated
#define ABSL_HAVE_CONSTANT_EVALUATED 1
#elif ABSL_HAVE_BUILTIN(__builtin_is_constant_evaluated)
#define ABSL_HAVE_CONSTANT_EVALUATED 1
#endif
// ABSL_INTERNAL_CONSTEXPR_SINCE_CXXYY is used to conditionally define constexpr
// for different C++ versions.
//
// These macros are an implementation detail and will be unconditionally removed
// once the minimum supported C++ version catches up to a given version.
//
// For this reason, this symbol is considered INTERNAL and code outside of
// Abseil must not use it.
#if defined(ABSL_INTERNAL_CPLUSPLUS_LANG) && \
ABSL_INTERNAL_CPLUSPLUS_LANG >= 201703L
#define ABSL_INTERNAL_CONSTEXPR_SINCE_CXX17 constexpr
#else
#define ABSL_INTERNAL_CONSTEXPR_SINCE_CXX17
#endif
#if defined(ABSL_INTERNAL_CPLUSPLUS_LANG) && \
ABSL_INTERNAL_CPLUSPLUS_LANG >= 202002L
#define ABSL_INTERNAL_CONSTEXPR_SINCE_CXX20 constexpr
#else
#define ABSL_INTERNAL_CONSTEXPR_SINCE_CXX20
#endif
// ABSL_INTERNAL_EMSCRIPTEN_VERSION combines Emscripten's three version macros
// into an integer that can be compared against.
#ifdef ABSL_INTERNAL_EMSCRIPTEN_VERSION
#error ABSL_INTERNAL_EMSCRIPTEN_VERSION cannot be directly set
#endif
#ifdef __EMSCRIPTEN__
#include <emscripten/version.h>
#ifdef __EMSCRIPTEN_major__
#if __EMSCRIPTEN_minor__ >= 1000
#error __EMSCRIPTEN_minor__ is too big to fit in ABSL_INTERNAL_EMSCRIPTEN_VERSION
#endif
#if __EMSCRIPTEN_tiny__ >= 1000
#error __EMSCRIPTEN_tiny__ is too big to fit in ABSL_INTERNAL_EMSCRIPTEN_VERSION
#endif
#define ABSL_INTERNAL_EMSCRIPTEN_VERSION \
((__EMSCRIPTEN_major__) * 1000000 + (__EMSCRIPTEN_minor__) * 1000 + \
(__EMSCRIPTEN_tiny__))
#endif
#endif
#endif // ABSL_BASE_CONFIG_H_

View File

@@ -1,76 +0,0 @@
// Copyright 2017 The Abseil Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// -----------------------------------------------------------------------------
// kConstInit
// -----------------------------------------------------------------------------
//
// A constructor tag used to mark an object as safe for use as a global
// variable, avoiding the usual lifetime issues that can affect globals.
#ifndef ABSL_BASE_CONST_INIT_H_
#define ABSL_BASE_CONST_INIT_H_
#include "absl/base/config.h"
// In general, objects with static storage duration (such as global variables)
// can trigger tricky object lifetime situations. Attempting to access them
// from the constructors or destructors of other global objects can result in
// undefined behavior, unless their constructors and destructors are designed
// with this issue in mind.
//
// The normal way to deal with this issue in C++11 is to use constant
// initialization and trivial destructors.
//
// Constant initialization is guaranteed to occur before any other code
// executes. Constructors that are declared 'constexpr' are eligible for
// constant initialization. You can annotate a variable declaration with the
// ABSL_CONST_INIT macro to express this intent. For compilers that support
// it, this annotation will cause a compilation error for declarations that
// aren't subject to constant initialization (perhaps because a runtime value
// was passed as a constructor argument).
//
// On program shutdown, lifetime issues can be avoided on global objects by
// ensuring that they contain trivial destructors. A class has a trivial
// destructor unless it has a user-defined destructor, a virtual method or base
// class, or a data member or base class with a non-trivial destructor of its
// own. Objects with static storage duration and a trivial destructor are not
// cleaned up on program shutdown, and are thus safe to access from other code
// running during shutdown.
//
// For a few core Abseil classes, we make a best effort to allow for safe global
// instances, even though these classes have non-trivial destructors. These
// objects can be created with the absl::kConstInit tag. For example:
// ABSL_CONST_INIT absl::Mutex global_mutex(absl::kConstInit);
//
// The line above declares a global variable of type absl::Mutex which can be
// accessed at any point during startup or shutdown. global_mutex's destructor
// will still run, but will not invalidate the object. Note that C++ specifies
// that accessing an object after its destructor has run results in undefined
// behavior, but this pattern works on the toolchains we support.
//
// The absl::kConstInit tag should only be used to define objects with static
// or thread_local storage duration.
namespace absl {
ABSL_NAMESPACE_BEGIN
enum ConstInitType {
kConstInit,
};
ABSL_NAMESPACE_END
} // namespace absl
#endif // ABSL_BASE_CONST_INIT_H_

View File

@@ -1,477 +0,0 @@
// Copyright 2017 The Abseil Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// This file defines dynamic annotations for use with dynamic analysis tool
// such as valgrind, PIN, etc.
//
// Dynamic annotation is a source code annotation that affects the generated
// code (that is, the annotation is not a comment). Each such annotation is
// attached to a particular instruction and/or to a particular object (address)
// in the program.
//
// The annotations that should be used by users are macros in all upper-case
// (e.g., ABSL_ANNOTATE_THREAD_NAME).
//
// Actual implementation of these macros may differ depending on the dynamic
// analysis tool being used.
//
// This file supports the following configurations:
// - Dynamic Annotations enabled (with static thread-safety warnings disabled).
// In this case, macros expand to functions implemented by Thread Sanitizer,
// when building with TSan. When not provided an external implementation,
// dynamic_annotations.cc provides no-op implementations.
//
// - Static Clang thread-safety warnings enabled.
// When building with a Clang compiler that supports thread-safety warnings,
// a subset of annotations can be statically-checked at compile-time. We
// expand these macros to static-inline functions that can be analyzed for
// thread-safety, but afterwards elided when building the final binary.
//
// - All annotations are disabled.
// If neither Dynamic Annotations nor Clang thread-safety warnings are
// enabled, then all annotation-macros expand to empty.
#ifndef ABSL_BASE_DYNAMIC_ANNOTATIONS_H_
#define ABSL_BASE_DYNAMIC_ANNOTATIONS_H_
#include <stddef.h>
#include <stdint.h>
#include "absl/base/attributes.h"
#include "absl/base/config.h"
#ifdef __cplusplus
#include "absl/base/macros.h"
#endif
#ifdef ABSL_HAVE_HWADDRESS_SANITIZER
#include <sanitizer/hwasan_interface.h>
#endif
// -------------------------------------------------------------------------
// Decide which features are enabled.
#ifdef ABSL_HAVE_THREAD_SANITIZER
#define ABSL_INTERNAL_RACE_ANNOTATIONS_ENABLED 1
#define ABSL_INTERNAL_READS_ANNOTATIONS_ENABLED 1
#define ABSL_INTERNAL_WRITES_ANNOTATIONS_ENABLED 1
#define ABSL_INTERNAL_ANNOTALYSIS_ENABLED 0
#define ABSL_INTERNAL_READS_WRITES_ANNOTATIONS_ENABLED 1
#else
#define ABSL_INTERNAL_RACE_ANNOTATIONS_ENABLED 0
#define ABSL_INTERNAL_READS_ANNOTATIONS_ENABLED 0
#define ABSL_INTERNAL_WRITES_ANNOTATIONS_ENABLED 0
// Clang provides limited support for static thread-safety analysis through a
// feature called Annotalysis. We configure macro-definitions according to
// whether Annotalysis support is available. When running in opt-mode, GCC
// will issue a warning, if these attributes are compiled. Only include them
// when compiling using Clang.
#if defined(__clang__)
#define ABSL_INTERNAL_ANNOTALYSIS_ENABLED 1
#if !defined(SWIG)
#define ABSL_INTERNAL_IGNORE_READS_ATTRIBUTE_ENABLED 1
#endif
#else
#define ABSL_INTERNAL_ANNOTALYSIS_ENABLED 0
#endif
// Read/write annotations are enabled in Annotalysis mode; disabled otherwise.
#define ABSL_INTERNAL_READS_WRITES_ANNOTATIONS_ENABLED \
ABSL_INTERNAL_ANNOTALYSIS_ENABLED
#endif // ABSL_HAVE_THREAD_SANITIZER
#ifdef __cplusplus
#define ABSL_INTERNAL_BEGIN_EXTERN_C extern "C" {
#define ABSL_INTERNAL_END_EXTERN_C } // extern "C"
#define ABSL_INTERNAL_GLOBAL_SCOPED(F) ::F
#define ABSL_INTERNAL_STATIC_INLINE inline
#else
#define ABSL_INTERNAL_BEGIN_EXTERN_C // empty
#define ABSL_INTERNAL_END_EXTERN_C // empty
#define ABSL_INTERNAL_GLOBAL_SCOPED(F) F
#define ABSL_INTERNAL_STATIC_INLINE static inline
#endif
// -------------------------------------------------------------------------
// Define race annotations.
#if ABSL_INTERNAL_RACE_ANNOTATIONS_ENABLED == 1
// Some of the symbols used in this section (e.g. AnnotateBenignRaceSized) are
// defined by the compiler-based sanitizer implementation, not by the Abseil
// library. Therefore they do not use ABSL_INTERNAL_C_SYMBOL.
// -------------------------------------------------------------
// Annotations that suppress errors. It is usually better to express the
// program's synchronization using the other annotations, but these can be used
// when all else fails.
// Report that we may have a benign race at `pointer`, with size
// "sizeof(*(pointer))". `pointer` must be a non-void* pointer. Insert at the
// point where `pointer` has been allocated, preferably close to the point
// where the race happens. See also ABSL_ANNOTATE_BENIGN_RACE_STATIC.
#define ABSL_ANNOTATE_BENIGN_RACE(pointer, description) \
ABSL_INTERNAL_GLOBAL_SCOPED(AnnotateBenignRaceSized) \
(__FILE__, __LINE__, pointer, sizeof(*(pointer)), description)
// Same as ABSL_ANNOTATE_BENIGN_RACE(`address`, `description`), but applies to
// the memory range [`address`, `address`+`size`).
#define ABSL_ANNOTATE_BENIGN_RACE_SIZED(address, size, description) \
ABSL_INTERNAL_GLOBAL_SCOPED(AnnotateBenignRaceSized) \
(__FILE__, __LINE__, address, size, description)
// Enable (`enable`!=0) or disable (`enable`==0) race detection for all threads.
// This annotation could be useful if you want to skip expensive race analysis
// during some period of program execution, e.g. during initialization.
#define ABSL_ANNOTATE_ENABLE_RACE_DETECTION(enable) \
ABSL_INTERNAL_GLOBAL_SCOPED(AnnotateEnableRaceDetection) \
(__FILE__, __LINE__, enable)
// -------------------------------------------------------------
// Annotations useful for debugging.
// Report the current thread `name` to a race detector.
#define ABSL_ANNOTATE_THREAD_NAME(name) \
ABSL_INTERNAL_GLOBAL_SCOPED(AnnotateThreadName)(__FILE__, __LINE__, name)
// -------------------------------------------------------------
// Annotations useful when implementing locks. They are not normally needed by
// modules that merely use locks. The `lock` argument is a pointer to the lock
// object.
// Report that a lock has been created at address `lock`.
#define ABSL_ANNOTATE_RWLOCK_CREATE(lock) \
ABSL_INTERNAL_GLOBAL_SCOPED(AnnotateRWLockCreate)(__FILE__, __LINE__, lock)
// Report that a linker initialized lock has been created at address `lock`.
#ifdef ABSL_HAVE_THREAD_SANITIZER
#define ABSL_ANNOTATE_RWLOCK_CREATE_STATIC(lock) \
ABSL_INTERNAL_GLOBAL_SCOPED(AnnotateRWLockCreateStatic) \
(__FILE__, __LINE__, lock)
#else
#define ABSL_ANNOTATE_RWLOCK_CREATE_STATIC(lock) \
ABSL_ANNOTATE_RWLOCK_CREATE(lock)
#endif
// Report that the lock at address `lock` is about to be destroyed.
#define ABSL_ANNOTATE_RWLOCK_DESTROY(lock) \
ABSL_INTERNAL_GLOBAL_SCOPED(AnnotateRWLockDestroy)(__FILE__, __LINE__, lock)
// Report that the lock at address `lock` has been acquired.
// `is_w`=1 for writer lock, `is_w`=0 for reader lock.
#define ABSL_ANNOTATE_RWLOCK_ACQUIRED(lock, is_w) \
ABSL_INTERNAL_GLOBAL_SCOPED(AnnotateRWLockAcquired) \
(__FILE__, __LINE__, lock, is_w)
// Report that the lock at address `lock` is about to be released.
// `is_w`=1 for writer lock, `is_w`=0 for reader lock.
#define ABSL_ANNOTATE_RWLOCK_RELEASED(lock, is_w) \
ABSL_INTERNAL_GLOBAL_SCOPED(AnnotateRWLockReleased) \
(__FILE__, __LINE__, lock, is_w)
// Apply ABSL_ANNOTATE_BENIGN_RACE_SIZED to a static variable `static_var`.
#define ABSL_ANNOTATE_BENIGN_RACE_STATIC(static_var, description) \
namespace { \
class static_var##_annotator { \
public: \
static_var##_annotator() { \
ABSL_ANNOTATE_BENIGN_RACE_SIZED(&static_var, sizeof(static_var), \
#static_var ": " description); \
} \
}; \
static static_var##_annotator the##static_var##_annotator; \
} // namespace
// Function prototypes of annotations provided by the compiler-based sanitizer
// implementation.
ABSL_INTERNAL_BEGIN_EXTERN_C
void AnnotateRWLockCreate(const char* file, int line,
const volatile void* lock);
void AnnotateRWLockCreateStatic(const char* file, int line,
const volatile void* lock);
void AnnotateRWLockDestroy(const char* file, int line,
const volatile void* lock);
void AnnotateRWLockAcquired(const char* file, int line,
const volatile void* lock, long is_w); // NOLINT
void AnnotateRWLockReleased(const char* file, int line,
const volatile void* lock, long is_w); // NOLINT
void AnnotateBenignRace(const char* file, int line,
const volatile void* address, const char* description);
void AnnotateBenignRaceSized(const char* file, int line,
const volatile void* address, size_t size,
const char* description);
void AnnotateThreadName(const char* file, int line, const char* name);
void AnnotateEnableRaceDetection(const char* file, int line, int enable);
ABSL_INTERNAL_END_EXTERN_C
#else // ABSL_INTERNAL_RACE_ANNOTATIONS_ENABLED == 0
#define ABSL_ANNOTATE_RWLOCK_CREATE(lock) // empty
#define ABSL_ANNOTATE_RWLOCK_CREATE_STATIC(lock) // empty
#define ABSL_ANNOTATE_RWLOCK_DESTROY(lock) // empty
#define ABSL_ANNOTATE_RWLOCK_ACQUIRED(lock, is_w) // empty
#define ABSL_ANNOTATE_RWLOCK_RELEASED(lock, is_w) // empty
#define ABSL_ANNOTATE_BENIGN_RACE(address, description) // empty
#define ABSL_ANNOTATE_BENIGN_RACE_SIZED(address, size, description) // empty
#define ABSL_ANNOTATE_THREAD_NAME(name) // empty
#define ABSL_ANNOTATE_ENABLE_RACE_DETECTION(enable) // empty
#define ABSL_ANNOTATE_BENIGN_RACE_STATIC(static_var, description) // empty
#endif // ABSL_INTERNAL_RACE_ANNOTATIONS_ENABLED
// -------------------------------------------------------------------------
// Define memory annotations.
#ifdef ABSL_HAVE_MEMORY_SANITIZER
#include <sanitizer/msan_interface.h>
#define ABSL_ANNOTATE_MEMORY_IS_INITIALIZED(address, size) \
__msan_unpoison(address, size)
#define ABSL_ANNOTATE_MEMORY_IS_UNINITIALIZED(address, size) \
__msan_allocated_memory(address, size)
#else // !defined(ABSL_HAVE_MEMORY_SANITIZER)
#define ABSL_ANNOTATE_MEMORY_IS_INITIALIZED(address, size) // empty
#define ABSL_ANNOTATE_MEMORY_IS_UNINITIALIZED(address, size) // empty
#endif // ABSL_HAVE_MEMORY_SANITIZER
// -------------------------------------------------------------------------
// Define IGNORE_READS_BEGIN/_END attributes.
#if defined(ABSL_INTERNAL_IGNORE_READS_ATTRIBUTE_ENABLED)
#define ABSL_INTERNAL_IGNORE_READS_BEGIN_ATTRIBUTE \
__attribute((exclusive_lock_function("*")))
#define ABSL_INTERNAL_IGNORE_READS_END_ATTRIBUTE \
__attribute((unlock_function("*")))
#else // !defined(ABSL_INTERNAL_IGNORE_READS_ATTRIBUTE_ENABLED)
#define ABSL_INTERNAL_IGNORE_READS_BEGIN_ATTRIBUTE // empty
#define ABSL_INTERNAL_IGNORE_READS_END_ATTRIBUTE // empty
#endif // defined(ABSL_INTERNAL_IGNORE_READS_ATTRIBUTE_ENABLED)
// -------------------------------------------------------------------------
// Define IGNORE_READS_BEGIN/_END annotations.
#if ABSL_INTERNAL_READS_ANNOTATIONS_ENABLED == 1
// Some of the symbols used in this section (e.g. AnnotateIgnoreReadsBegin) are
// defined by the compiler-based implementation, not by the Abseil
// library. Therefore they do not use ABSL_INTERNAL_C_SYMBOL.
// Request the analysis tool to ignore all reads in the current thread until
// ABSL_ANNOTATE_IGNORE_READS_END is called. Useful to ignore intentional racey
// reads, while still checking other reads and all writes.
// See also ABSL_ANNOTATE_UNPROTECTED_READ.
#define ABSL_ANNOTATE_IGNORE_READS_BEGIN() \
ABSL_INTERNAL_GLOBAL_SCOPED(AnnotateIgnoreReadsBegin) \
(__FILE__, __LINE__)
// Stop ignoring reads.
#define ABSL_ANNOTATE_IGNORE_READS_END() \
ABSL_INTERNAL_GLOBAL_SCOPED(AnnotateIgnoreReadsEnd) \
(__FILE__, __LINE__)
// Function prototypes of annotations provided by the compiler-based sanitizer
// implementation.
ABSL_INTERNAL_BEGIN_EXTERN_C
void AnnotateIgnoreReadsBegin(const char* file, int line)
ABSL_INTERNAL_IGNORE_READS_BEGIN_ATTRIBUTE;
void AnnotateIgnoreReadsEnd(const char* file,
int line) ABSL_INTERNAL_IGNORE_READS_END_ATTRIBUTE;
ABSL_INTERNAL_END_EXTERN_C
#elif defined(ABSL_INTERNAL_ANNOTALYSIS_ENABLED)
// When Annotalysis is enabled without Dynamic Annotations, the use of
// static-inline functions allows the annotations to be read at compile-time,
// while still letting the compiler elide the functions from the final build.
//
// TODO(delesley) -- The exclusive lock here ignores writes as well, but
// allows IGNORE_READS_AND_WRITES to work properly.
#define ABSL_ANNOTATE_IGNORE_READS_BEGIN() \
ABSL_INTERNAL_GLOBAL_SCOPED( \
ABSL_INTERNAL_C_SYMBOL(AbslInternalAnnotateIgnoreReadsBegin)) \
()
#define ABSL_ANNOTATE_IGNORE_READS_END() \
ABSL_INTERNAL_GLOBAL_SCOPED( \
ABSL_INTERNAL_C_SYMBOL(AbslInternalAnnotateIgnoreReadsEnd)) \
()
ABSL_INTERNAL_STATIC_INLINE void ABSL_INTERNAL_C_SYMBOL(
AbslInternalAnnotateIgnoreReadsBegin)()
ABSL_INTERNAL_IGNORE_READS_BEGIN_ATTRIBUTE {}
ABSL_INTERNAL_STATIC_INLINE void ABSL_INTERNAL_C_SYMBOL(
AbslInternalAnnotateIgnoreReadsEnd)()
ABSL_INTERNAL_IGNORE_READS_END_ATTRIBUTE {}
#else
#define ABSL_ANNOTATE_IGNORE_READS_BEGIN() // empty
#define ABSL_ANNOTATE_IGNORE_READS_END() // empty
#endif
// -------------------------------------------------------------------------
// Define IGNORE_WRITES_BEGIN/_END annotations.
#if ABSL_INTERNAL_WRITES_ANNOTATIONS_ENABLED == 1
// Similar to ABSL_ANNOTATE_IGNORE_READS_BEGIN, but ignore writes instead.
#define ABSL_ANNOTATE_IGNORE_WRITES_BEGIN() \
ABSL_INTERNAL_GLOBAL_SCOPED(AnnotateIgnoreWritesBegin)(__FILE__, __LINE__)
// Stop ignoring writes.
#define ABSL_ANNOTATE_IGNORE_WRITES_END() \
ABSL_INTERNAL_GLOBAL_SCOPED(AnnotateIgnoreWritesEnd)(__FILE__, __LINE__)
// Function prototypes of annotations provided by the compiler-based sanitizer
// implementation.
ABSL_INTERNAL_BEGIN_EXTERN_C
void AnnotateIgnoreWritesBegin(const char* file, int line);
void AnnotateIgnoreWritesEnd(const char* file, int line);
ABSL_INTERNAL_END_EXTERN_C
#else
#define ABSL_ANNOTATE_IGNORE_WRITES_BEGIN() // empty
#define ABSL_ANNOTATE_IGNORE_WRITES_END() // empty
#endif
// -------------------------------------------------------------------------
// Define the ABSL_ANNOTATE_IGNORE_READS_AND_WRITES_* annotations using the more
// primitive annotations defined above.
//
// Instead of doing
// ABSL_ANNOTATE_IGNORE_READS_BEGIN();
// ... = x;
// ABSL_ANNOTATE_IGNORE_READS_END();
// one can use
// ... = ABSL_ANNOTATE_UNPROTECTED_READ(x);
#if defined(ABSL_INTERNAL_READS_WRITES_ANNOTATIONS_ENABLED)
// Start ignoring all memory accesses (both reads and writes).
#define ABSL_ANNOTATE_IGNORE_READS_AND_WRITES_BEGIN() \
do { \
ABSL_ANNOTATE_IGNORE_READS_BEGIN(); \
ABSL_ANNOTATE_IGNORE_WRITES_BEGIN(); \
} while (0)
// Stop ignoring both reads and writes.
#define ABSL_ANNOTATE_IGNORE_READS_AND_WRITES_END() \
do { \
ABSL_ANNOTATE_IGNORE_WRITES_END(); \
ABSL_ANNOTATE_IGNORE_READS_END(); \
} while (0)
#ifdef __cplusplus
// ABSL_ANNOTATE_UNPROTECTED_READ is the preferred way to annotate racey reads.
#define ABSL_ANNOTATE_UNPROTECTED_READ(x) \
absl::base_internal::AnnotateUnprotectedRead(x)
namespace absl {
ABSL_NAMESPACE_BEGIN
namespace base_internal {
template <typename T>
inline T AnnotateUnprotectedRead(const volatile T& x) { // NOLINT
ABSL_ANNOTATE_IGNORE_READS_BEGIN();
T res = x;
ABSL_ANNOTATE_IGNORE_READS_END();
return res;
}
} // namespace base_internal
ABSL_NAMESPACE_END
} // namespace absl
#endif
#else
#define ABSL_ANNOTATE_IGNORE_READS_AND_WRITES_BEGIN() // empty
#define ABSL_ANNOTATE_IGNORE_READS_AND_WRITES_END() // empty
#define ABSL_ANNOTATE_UNPROTECTED_READ(x) (x)
#endif
// -------------------------------------------------------------------------
// Address sanitizer annotations
#ifdef ABSL_HAVE_ADDRESS_SANITIZER
// Describe the current state of a contiguous container such as e.g.
// std::vector or std::string. For more details see
// sanitizer/common_interface_defs.h, which is provided by the compiler.
#include <sanitizer/common_interface_defs.h>
#define ABSL_ANNOTATE_CONTIGUOUS_CONTAINER(beg, end, old_mid, new_mid) \
__sanitizer_annotate_contiguous_container(beg, end, old_mid, new_mid)
#define ABSL_ADDRESS_SANITIZER_REDZONE(name) \
struct { \
alignas(8) char x[8]; \
} name
#else
#define ABSL_ANNOTATE_CONTIGUOUS_CONTAINER(beg, end, old_mid, new_mid) // empty
#define ABSL_ADDRESS_SANITIZER_REDZONE(name) static_assert(true, "")
#endif // ABSL_HAVE_ADDRESS_SANITIZER
// -------------------------------------------------------------------------
// HWAddress sanitizer annotations
#ifdef __cplusplus
namespace absl {
#ifdef ABSL_HAVE_HWADDRESS_SANITIZER
// Under HWASAN changes the tag of the pointer.
template <typename T>
T* HwasanTagPointer(T* ptr, uintptr_t tag) {
return reinterpret_cast<T*>(__hwasan_tag_pointer(ptr, tag));
}
#else
template <typename T>
T* HwasanTagPointer(T* ptr, uintptr_t) {
return ptr;
}
#endif
} // namespace absl
#endif
// -------------------------------------------------------------------------
// Undefine the macros intended only for this file.
#undef ABSL_INTERNAL_RACE_ANNOTATIONS_ENABLED
#undef ABSL_INTERNAL_READS_ANNOTATIONS_ENABLED
#undef ABSL_INTERNAL_WRITES_ANNOTATIONS_ENABLED
#undef ABSL_INTERNAL_ANNOTALYSIS_ENABLED
#undef ABSL_INTERNAL_READS_WRITES_ANNOTATIONS_ENABLED
#undef ABSL_INTERNAL_BEGIN_EXTERN_C
#undef ABSL_INTERNAL_END_EXTERN_C
#undef ABSL_INTERNAL_STATIC_INLINE
#endif // ABSL_BASE_DYNAMIC_ANNOTATIONS_H_

View File

@@ -1,45 +0,0 @@
// Copyright 2020 The Abseil Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
#ifndef ABSL_BASE_FAST_TYPE_ID_H_
#define ABSL_BASE_FAST_TYPE_ID_H_
#include "absl/base/config.h"
namespace absl {
ABSL_NAMESPACE_BEGIN
namespace base_internal {
template <typename Type>
struct FastTypeTag {
static constexpr char kDummyVar = 0;
};
} // namespace base_internal
// The type returned by `absl::FastTypeId<T>()`.
using FastTypeIdType = const void*;
// `absl::FastTypeId<Type>()` evaluates at compile-time to a unique id for the
// passed-in type. These are meant to be good match for keys into maps or
// straight up comparisons.
template <typename Type>
constexpr FastTypeIdType FastTypeId() {
return &base_internal::FastTypeTag<Type>::kDummyVar;
}
ABSL_NAMESPACE_END
} // namespace absl
#endif // ABSL_BASE_FAST_TYPE_ID_H_

View File

@@ -1,200 +0,0 @@
// Copyright 2017 The Abseil Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef ABSL_BASE_INTERNAL_ATOMIC_HOOK_H_
#define ABSL_BASE_INTERNAL_ATOMIC_HOOK_H_
#include <atomic>
#include <cassert>
#include <cstdint>
#include <utility>
#include "absl/base/attributes.h"
#include "absl/base/config.h"
#if defined(_MSC_VER) && !defined(__clang__)
#define ABSL_HAVE_WORKING_CONSTEXPR_STATIC_INIT 0
#else
#define ABSL_HAVE_WORKING_CONSTEXPR_STATIC_INIT 1
#endif
#if defined(_MSC_VER)
#define ABSL_HAVE_WORKING_ATOMIC_POINTER 0
#else
#define ABSL_HAVE_WORKING_ATOMIC_POINTER 1
#endif
namespace absl {
ABSL_NAMESPACE_BEGIN
namespace base_internal {
template <typename T>
class AtomicHook;
// To workaround AtomicHook not being constant-initializable on some platforms,
// prefer to annotate instances with `ABSL_INTERNAL_ATOMIC_HOOK_ATTRIBUTES`
// instead of `ABSL_CONST_INIT`.
#if ABSL_HAVE_WORKING_CONSTEXPR_STATIC_INIT
#define ABSL_INTERNAL_ATOMIC_HOOK_ATTRIBUTES ABSL_CONST_INIT
#else
#define ABSL_INTERNAL_ATOMIC_HOOK_ATTRIBUTES
#endif
// `AtomicHook` is a helper class, templatized on a raw function pointer type,
// for implementing Abseil customization hooks. It is a callable object that
// dispatches to the registered hook. Objects of type `AtomicHook` must have
// static or thread storage duration.
//
// A default constructed object performs a no-op (and returns a default
// constructed object) if no hook has been registered.
//
// Hooks can be pre-registered via constant initialization, for example:
//
// ABSL_INTERNAL_ATOMIC_HOOK_ATTRIBUTES static AtomicHook<void(*)()>
// my_hook(DefaultAction);
//
// and then changed at runtime via a call to `Store()`.
//
// Reads and writes guarantee memory_order_acquire/memory_order_release
// semantics.
template <typename ReturnType, typename... Args>
class AtomicHook<ReturnType (*)(Args...)> {
public:
using FnPtr = ReturnType (*)(Args...);
// Constructs an object that by default performs a no-op (and
// returns a default constructed object) when no hook as been registered.
constexpr AtomicHook() : AtomicHook(DummyFunction) {}
// Constructs an object that by default dispatches to/returns the
// pre-registered default_fn when no hook has been registered at runtime.
#if ABSL_HAVE_WORKING_ATOMIC_POINTER && ABSL_HAVE_WORKING_CONSTEXPR_STATIC_INIT
explicit constexpr AtomicHook(FnPtr default_fn)
: hook_(default_fn), default_fn_(default_fn) {}
#elif ABSL_HAVE_WORKING_CONSTEXPR_STATIC_INIT
explicit constexpr AtomicHook(FnPtr default_fn)
: hook_(kUninitialized), default_fn_(default_fn) {}
#else
// As of January 2020, on all known versions of MSVC this constructor runs in
// the global constructor sequence. If `Store()` is called by a dynamic
// initializer, we want to preserve the value, even if this constructor runs
// after the call to `Store()`. If not, `hook_` will be
// zero-initialized by the linker and we have no need to set it.
// https://developercommunity.visualstudio.com/content/problem/336946/class-with-constexpr-constructor-not-using-static.html
explicit constexpr AtomicHook(FnPtr default_fn)
: /* hook_(deliberately omitted), */ default_fn_(default_fn) {
static_assert(kUninitialized == 0, "here we rely on zero-initialization");
}
#endif
// Stores the provided function pointer as the value for this hook.
//
// This is intended to be called once. Multiple calls are legal only if the
// same function pointer is provided for each call. The store is implemented
// as a memory_order_release operation, and read accesses are implemented as
// memory_order_acquire.
void Store(FnPtr fn) {
bool success = DoStore(fn);
static_cast<void>(success);
assert(success);
}
// Invokes the registered callback. If no callback has yet been registered, a
// default-constructed object of the appropriate type is returned instead.
template <typename... CallArgs>
ReturnType operator()(CallArgs&&... args) const {
return DoLoad()(std::forward<CallArgs>(args)...);
}
// Returns the registered callback, or nullptr if none has been registered.
// Useful if client code needs to conditionalize behavior based on whether a
// callback was registered.
//
// Note that atomic_hook.Load()() and atomic_hook() have different semantics:
// operator()() will perform a no-op if no callback was registered, while
// Load()() will dereference a null function pointer. Prefer operator()() to
// Load()() unless you must conditionalize behavior on whether a hook was
// registered.
FnPtr Load() const {
FnPtr ptr = DoLoad();
return (ptr == DummyFunction) ? nullptr : ptr;
}
private:
static ReturnType DummyFunction(Args...) {
return ReturnType();
}
// Current versions of MSVC (as of September 2017) have a broken
// implementation of std::atomic<T*>: Its constructor attempts to do the
// equivalent of a reinterpret_cast in a constexpr context, which is not
// allowed.
//
// This causes an issue when building with LLVM under Windows. To avoid this,
// we use a less-efficient, intptr_t-based implementation on Windows.
#if ABSL_HAVE_WORKING_ATOMIC_POINTER
// Return the stored value, or DummyFunction if no value has been stored.
FnPtr DoLoad() const { return hook_.load(std::memory_order_acquire); }
// Store the given value. Returns false if a different value was already
// stored to this object.
bool DoStore(FnPtr fn) {
assert(fn);
FnPtr expected = default_fn_;
const bool store_succeeded = hook_.compare_exchange_strong(
expected, fn, std::memory_order_acq_rel, std::memory_order_acquire);
const bool same_value_already_stored = (expected == fn);
return store_succeeded || same_value_already_stored;
}
std::atomic<FnPtr> hook_;
#else // !ABSL_HAVE_WORKING_ATOMIC_POINTER
// Use a sentinel value unlikely to be the address of an actual function.
static constexpr intptr_t kUninitialized = 0;
static_assert(sizeof(intptr_t) >= sizeof(FnPtr),
"intptr_t can't contain a function pointer");
FnPtr DoLoad() const {
const intptr_t value = hook_.load(std::memory_order_acquire);
if (value == kUninitialized) {
return default_fn_;
}
return reinterpret_cast<FnPtr>(value);
}
bool DoStore(FnPtr fn) {
assert(fn);
const auto value = reinterpret_cast<intptr_t>(fn);
intptr_t expected = kUninitialized;
const bool store_succeeded = hook_.compare_exchange_strong(
expected, value, std::memory_order_acq_rel, std::memory_order_acquire);
const bool same_value_already_stored = (expected == value);
return store_succeeded || same_value_already_stored;
}
std::atomic<intptr_t> hook_;
#endif
const FnPtr default_fn_;
};
#undef ABSL_HAVE_WORKING_ATOMIC_POINTER
#undef ABSL_HAVE_WORKING_CONSTEXPR_STATIC_INIT
} // namespace base_internal
ABSL_NAMESPACE_END
} // namespace absl
#endif // ABSL_BASE_INTERNAL_ATOMIC_HOOK_H_

View File

@@ -1,144 +0,0 @@
//
// Copyright 2017 The Abseil Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// -----------------------------------------------------------------------------
// File: cycleclock.h
// -----------------------------------------------------------------------------
//
// This header file defines a `CycleClock`, which yields the value and frequency
// of a cycle counter that increments at a rate that is approximately constant.
//
// NOTE:
//
// The cycle counter frequency is not necessarily related to the core clock
// frequency and should not be treated as such. That is, `CycleClock` cycles are
// not necessarily "CPU cycles" and code should not rely on that behavior, even
// if experimentally observed.
//
// An arbitrary offset may have been added to the counter at power on.
//
// On some platforms, the rate and offset of the counter may differ
// slightly when read from different CPUs of a multiprocessor. Usually,
// we try to ensure that the operating system adjusts values periodically
// so that values agree approximately. If you need stronger guarantees,
// consider using alternate interfaces.
//
// The CPU is not required to maintain the ordering of a cycle counter read
// with respect to surrounding instructions.
#ifndef ABSL_BASE_INTERNAL_CYCLECLOCK_H_
#define ABSL_BASE_INTERNAL_CYCLECLOCK_H_
#include <atomic>
#include <cstdint>
#include "absl/base/attributes.h"
#include "absl/base/config.h"
#include "absl/base/internal/cycleclock_config.h"
#include "absl/base/internal/unscaledcycleclock.h"
namespace absl {
ABSL_NAMESPACE_BEGIN
namespace base_internal {
using CycleClockSourceFunc = int64_t (*)();
// -----------------------------------------------------------------------------
// CycleClock
// -----------------------------------------------------------------------------
class CycleClock {
public:
// CycleClock::Now()
//
// Returns the value of a cycle counter that counts at a rate that is
// approximately constant.
static int64_t Now();
// CycleClock::Frequency()
//
// Returns the amount by which `CycleClock::Now()` increases per second. Note
// that this value may not necessarily match the core CPU clock frequency.
static double Frequency();
private:
#if ABSL_USE_UNSCALED_CYCLECLOCK
static CycleClockSourceFunc LoadCycleClockSource();
static constexpr int32_t kShift = kCycleClockShift;
static constexpr double kFrequencyScale = kCycleClockFrequencyScale;
ABSL_CONST_INIT static std::atomic<CycleClockSourceFunc> cycle_clock_source_;
#endif // ABSL_USE_UNSCALED_CYCLECLOC
CycleClock() = delete; // no instances
CycleClock(const CycleClock&) = delete;
CycleClock& operator=(const CycleClock&) = delete;
friend class CycleClockSource;
};
class CycleClockSource {
private:
// CycleClockSource::Register()
//
// Register a function that provides an alternate source for the unscaled CPU
// cycle count value. The source function must be async signal safe, must not
// call CycleClock::Now(), and must have a frequency that matches that of the
// unscaled clock used by CycleClock. A nullptr value resets CycleClock to use
// the default source.
static void Register(CycleClockSourceFunc source);
};
#if ABSL_USE_UNSCALED_CYCLECLOCK
inline CycleClockSourceFunc CycleClock::LoadCycleClockSource() {
#if !defined(__x86_64__)
// Optimize for the common case (no callback) by first doing a relaxed load;
// this is significantly faster on non-x86 platforms.
if (cycle_clock_source_.load(std::memory_order_relaxed) == nullptr) {
return nullptr;
}
#endif // !defined(__x86_64__)
// This corresponds to the store(std::memory_order_release) in
// CycleClockSource::Register, and makes sure that any updates made prior to
// registering the callback are visible to this thread before the callback
// is invoked.
return cycle_clock_source_.load(std::memory_order_acquire);
}
// Accessing globals in inlined code in Window DLLs is problematic.
#ifndef _WIN32
inline int64_t CycleClock::Now() {
auto fn = LoadCycleClockSource();
if (fn == nullptr) {
return base_internal::UnscaledCycleClock::Now() >> kShift;
}
return fn() >> kShift;
}
#endif
inline double CycleClock::Frequency() {
return kFrequencyScale * base_internal::UnscaledCycleClock::Frequency();
}
#endif // ABSL_USE_UNSCALED_CYCLECLOCK
} // namespace base_internal
ABSL_NAMESPACE_END
} // namespace absl
#endif // ABSL_BASE_INTERNAL_CYCLECLOCK_H_

View File

@@ -1,55 +0,0 @@
// Copyright 2022 The Abseil Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef ABSL_BASE_INTERNAL_CYCLECLOCK_CONFIG_H_
#define ABSL_BASE_INTERNAL_CYCLECLOCK_CONFIG_H_
#include <cstdint>
#include "absl/base/config.h"
#include "absl/base/internal/unscaledcycleclock_config.h"
namespace absl {
ABSL_NAMESPACE_BEGIN
namespace base_internal {
#if ABSL_USE_UNSCALED_CYCLECLOCK
#ifdef NDEBUG
#ifdef ABSL_INTERNAL_UNSCALED_CYCLECLOCK_FREQUENCY_IS_CPU_FREQUENCY
// Not debug mode and the UnscaledCycleClock frequency is the CPU
// frequency. Scale the CycleClock to prevent overflow if someone
// tries to represent the time as cycles since the Unix epoch.
inline constexpr int32_t kCycleClockShift = 1;
#else
// Not debug mode and the UnscaledCycleClock isn't operating at the
// raw CPU frequency. There is no need to do any scaling, so don't
// needlessly sacrifice precision.
inline constexpr int32_t kCycleClockShift = 0;
#endif
#else // NDEBUG
// In debug mode use a different shift to discourage depending on a
// particular shift value.
inline constexpr int32_t kCycleClockShift = 2;
#endif // NDEBUG
inline constexpr double kCycleClockFrequencyScale =
1.0 / (1 << kCycleClockShift);
#endif // ABSL_USE_UNSCALED_CYCLECLOCK
} // namespace base_internal
ABSL_NAMESPACE_END
} // namespace absl
#endif // ABSL_BASE_INTERNAL_CYCLECLOCK_CONFIG_H_

View File

@@ -1,170 +0,0 @@
// Copyright 2017 The Abseil Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// Functions for directly invoking mmap() via syscall, avoiding the case where
// mmap() has been locally overridden.
#ifndef ABSL_BASE_INTERNAL_DIRECT_MMAP_H_
#define ABSL_BASE_INTERNAL_DIRECT_MMAP_H_
#include "absl/base/config.h"
#ifdef ABSL_HAVE_MMAP
#include <sys/mman.h>
#ifdef __linux__
#include <sys/types.h>
#ifdef __BIONIC__
#include <sys/syscall.h>
#else
#include <syscall.h>
#endif
#include <linux/unistd.h>
#include <unistd.h>
#include <cerrno>
#include <cstdarg>
#include <cstdint>
#ifdef __mips__
// Include definitions of the ABI currently in use.
#if defined(__BIONIC__) || !defined(__GLIBC__)
// Android doesn't have sgidefs.h, but does have asm/sgidefs.h, which has the
// definitions we need.
#include <asm/sgidefs.h>
#else
#include <sgidefs.h>
#endif // __BIONIC__ || !__GLIBC__
#endif // __mips__
// SYS_mmap and SYS_munmap are not defined in Android.
#ifdef __BIONIC__
extern "C" void* __mmap2(void*, size_t, int, int, int, size_t);
#if defined(__NR_mmap) && !defined(SYS_mmap)
#define SYS_mmap __NR_mmap
#endif
#ifndef SYS_munmap
#define SYS_munmap __NR_munmap
#endif
#endif // __BIONIC__
#if defined(__NR_mmap2) && !defined(SYS_mmap2)
#define SYS_mmap2 __NR_mmap2
#endif
namespace absl {
ABSL_NAMESPACE_BEGIN
namespace base_internal {
// Platform specific logic extracted from
// https://chromium.googlesource.com/linux-syscall-support/+/master/linux_syscall_support.h
inline void* DirectMmap(void* start, size_t length, int prot, int flags, int fd,
off_t offset) noexcept {
#if defined(__i386__) || defined(__ARM_ARCH_3__) || defined(__ARM_EABI__) || \
defined(__m68k__) || defined(__sh__) || \
(defined(__hppa__) && !defined(__LP64__)) || \
(defined(__mips__) && _MIPS_SIM == _MIPS_SIM_ABI32) || \
(defined(__PPC__) && !defined(__PPC64__)) || \
(defined(__riscv) && __riscv_xlen == 32) || \
(defined(__s390__) && !defined(__s390x__)) || \
(defined(__sparc__) && !defined(__arch64__))
// On these architectures, implement mmap with mmap2.
static int pagesize = 0;
if (pagesize == 0) {
#if defined(__wasm__) || defined(__asmjs__)
pagesize = getpagesize();
#else
pagesize = sysconf(_SC_PAGESIZE);
#endif
}
if (offset < 0 || offset % pagesize != 0) {
errno = EINVAL;
return MAP_FAILED;
}
#ifdef __BIONIC__
// SYS_mmap2 has problems on Android API level <= 16.
// Workaround by invoking __mmap2() instead.
return __mmap2(start, length, prot, flags, fd,
static_cast<size_t>(offset / pagesize));
#else
return reinterpret_cast<void*>(
syscall(SYS_mmap2, start, length, prot, flags, fd,
static_cast<unsigned long>(offset / pagesize))); // NOLINT
#endif
#elif defined(__s390x__)
// On s390x, mmap() arguments are passed in memory.
unsigned long buf[6] = {reinterpret_cast<unsigned long>(start), // NOLINT
static_cast<unsigned long>(length), // NOLINT
static_cast<unsigned long>(prot), // NOLINT
static_cast<unsigned long>(flags), // NOLINT
static_cast<unsigned long>(fd), // NOLINT
static_cast<unsigned long>(offset)}; // NOLINT
return reinterpret_cast<void*>(syscall(SYS_mmap, buf));
#elif defined(__x86_64__)
// The x32 ABI has 32 bit longs, but the syscall interface is 64 bit.
// We need to explicitly cast to an unsigned 64 bit type to avoid implicit
// sign extension. We can't cast pointers directly because those are
// 32 bits, and gcc will dump ugly warnings about casting from a pointer
// to an integer of a different size. We also need to make sure __off64_t
// isn't truncated to 32-bits under x32.
#define MMAP_SYSCALL_ARG(x) ((uint64_t)(uintptr_t)(x))
return reinterpret_cast<void*>(
syscall(SYS_mmap, MMAP_SYSCALL_ARG(start), MMAP_SYSCALL_ARG(length),
MMAP_SYSCALL_ARG(prot), MMAP_SYSCALL_ARG(flags),
MMAP_SYSCALL_ARG(fd), static_cast<uint64_t>(offset)));
#undef MMAP_SYSCALL_ARG
#else // Remaining 64-bit aritectures.
static_assert(sizeof(unsigned long) == 8, "Platform is not 64-bit");
return reinterpret_cast<void*>(
syscall(SYS_mmap, start, length, prot, flags, fd, offset));
#endif
}
inline int DirectMunmap(void* start, size_t length) {
return static_cast<int>(syscall(SYS_munmap, start, length));
}
} // namespace base_internal
ABSL_NAMESPACE_END
} // namespace absl
#else // !__linux__
// For non-linux platforms where we have mmap, just dispatch directly to the
// actual mmap()/munmap() methods.
namespace absl {
ABSL_NAMESPACE_BEGIN
namespace base_internal {
inline void* DirectMmap(void* start, size_t length, int prot, int flags, int fd,
off_t offset) {
return mmap(start, length, prot, flags, fd, offset);
}
inline int DirectMunmap(void* start, size_t length) {
return munmap(start, length);
}
} // namespace base_internal
ABSL_NAMESPACE_END
} // namespace absl
#endif // __linux__
#endif // ABSL_HAVE_MMAP
#endif // ABSL_BASE_INTERNAL_DIRECT_MMAP_H_

View File

@@ -1,279 +0,0 @@
// Copyright 2017 The Abseil Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// This file is for Abseil internal use only.
// See //absl/numeric/bits.h for supported functions related to endian-ness.
#ifndef ABSL_BASE_INTERNAL_ENDIAN_H_
#define ABSL_BASE_INTERNAL_ENDIAN_H_
#include <cstdint>
#include <cstdlib>
#include "absl/base/casts.h"
#include "absl/base/config.h"
#include "absl/base/internal/unaligned_access.h"
#include "absl/base/nullability.h"
#include "absl/base/port.h"
namespace absl {
ABSL_NAMESPACE_BEGIN
constexpr uint64_t gbswap_64(uint64_t x) {
#if ABSL_HAVE_BUILTIN(__builtin_bswap64) || defined(__GNUC__)
return __builtin_bswap64(x);
#else
return (((x & uint64_t{0xFF}) << 56) |
((x & uint64_t{0xFF00}) << 40) |
((x & uint64_t{0xFF0000}) << 24) |
((x & uint64_t{0xFF000000}) << 8) |
((x & uint64_t{0xFF00000000}) >> 8) |
((x & uint64_t{0xFF0000000000}) >> 24) |
((x & uint64_t{0xFF000000000000}) >> 40) |
((x & uint64_t{0xFF00000000000000}) >> 56));
#endif
}
constexpr uint32_t gbswap_32(uint32_t x) {
#if ABSL_HAVE_BUILTIN(__builtin_bswap32) || defined(__GNUC__)
return __builtin_bswap32(x);
#else
return (((x & uint32_t{0xFF}) << 24) |
((x & uint32_t{0xFF00}) << 8) |
((x & uint32_t{0xFF0000}) >> 8) |
((x & uint32_t{0xFF000000}) >> 24));
#endif
}
constexpr uint16_t gbswap_16(uint16_t x) {
#if ABSL_HAVE_BUILTIN(__builtin_bswap16) || defined(__GNUC__)
return __builtin_bswap16(x);
#else
return (((x & uint16_t{0xFF}) << 8) |
((x & uint16_t{0xFF00}) >> 8));
#endif
}
#ifdef ABSL_IS_LITTLE_ENDIAN
// Portable definitions for htonl (host-to-network) and friends on little-endian
// architectures.
inline uint16_t ghtons(uint16_t x) { return gbswap_16(x); }
inline uint32_t ghtonl(uint32_t x) { return gbswap_32(x); }
inline uint64_t ghtonll(uint64_t x) { return gbswap_64(x); }
#elif defined ABSL_IS_BIG_ENDIAN
// Portable definitions for htonl (host-to-network) etc on big-endian
// architectures. These definitions are simpler since the host byte order is the
// same as network byte order.
inline uint16_t ghtons(uint16_t x) { return x; }
inline uint32_t ghtonl(uint32_t x) { return x; }
inline uint64_t ghtonll(uint64_t x) { return x; }
#else
#error \
"Unsupported byte order: Either ABSL_IS_BIG_ENDIAN or " \
"ABSL_IS_LITTLE_ENDIAN must be defined"
#endif // byte order
inline uint16_t gntohs(uint16_t x) { return ghtons(x); }
inline uint32_t gntohl(uint32_t x) { return ghtonl(x); }
inline uint64_t gntohll(uint64_t x) { return ghtonll(x); }
// Utilities to convert numbers between the current hosts's native byte
// order and little-endian byte order
//
// Load/Store methods are alignment safe
namespace little_endian {
// Conversion functions.
#ifdef ABSL_IS_LITTLE_ENDIAN
inline uint16_t FromHost16(uint16_t x) { return x; }
inline uint16_t ToHost16(uint16_t x) { return x; }
inline uint32_t FromHost32(uint32_t x) { return x; }
inline uint32_t ToHost32(uint32_t x) { return x; }
inline uint64_t FromHost64(uint64_t x) { return x; }
inline uint64_t ToHost64(uint64_t x) { return x; }
inline constexpr bool IsLittleEndian() { return true; }
#elif defined ABSL_IS_BIG_ENDIAN
inline uint16_t FromHost16(uint16_t x) { return gbswap_16(x); }
inline uint16_t ToHost16(uint16_t x) { return gbswap_16(x); }
inline uint32_t FromHost32(uint32_t x) { return gbswap_32(x); }
inline uint32_t ToHost32(uint32_t x) { return gbswap_32(x); }
inline uint64_t FromHost64(uint64_t x) { return gbswap_64(x); }
inline uint64_t ToHost64(uint64_t x) { return gbswap_64(x); }
inline constexpr bool IsLittleEndian() { return false; }
#endif /* ENDIAN */
inline uint8_t FromHost(uint8_t x) { return x; }
inline uint16_t FromHost(uint16_t x) { return FromHost16(x); }
inline uint32_t FromHost(uint32_t x) { return FromHost32(x); }
inline uint64_t FromHost(uint64_t x) { return FromHost64(x); }
inline uint8_t ToHost(uint8_t x) { return x; }
inline uint16_t ToHost(uint16_t x) { return ToHost16(x); }
inline uint32_t ToHost(uint32_t x) { return ToHost32(x); }
inline uint64_t ToHost(uint64_t x) { return ToHost64(x); }
inline int8_t FromHost(int8_t x) { return x; }
inline int16_t FromHost(int16_t x) {
return bit_cast<int16_t>(FromHost16(bit_cast<uint16_t>(x)));
}
inline int32_t FromHost(int32_t x) {
return bit_cast<int32_t>(FromHost32(bit_cast<uint32_t>(x)));
}
inline int64_t FromHost(int64_t x) {
return bit_cast<int64_t>(FromHost64(bit_cast<uint64_t>(x)));
}
inline int8_t ToHost(int8_t x) { return x; }
inline int16_t ToHost(int16_t x) {
return bit_cast<int16_t>(ToHost16(bit_cast<uint16_t>(x)));
}
inline int32_t ToHost(int32_t x) {
return bit_cast<int32_t>(ToHost32(bit_cast<uint32_t>(x)));
}
inline int64_t ToHost(int64_t x) {
return bit_cast<int64_t>(ToHost64(bit_cast<uint64_t>(x)));
}
// Functions to do unaligned loads and stores in little-endian order.
inline uint16_t Load16(const void* absl_nonnull p) {
return ToHost16(ABSL_INTERNAL_UNALIGNED_LOAD16(p));
}
inline void Store16(void* absl_nonnull p, uint16_t v) {
ABSL_INTERNAL_UNALIGNED_STORE16(p, FromHost16(v));
}
inline uint32_t Load32(const void* absl_nonnull p) {
return ToHost32(ABSL_INTERNAL_UNALIGNED_LOAD32(p));
}
inline void Store32(void* absl_nonnull p, uint32_t v) {
ABSL_INTERNAL_UNALIGNED_STORE32(p, FromHost32(v));
}
inline uint64_t Load64(const void* absl_nonnull p) {
return ToHost64(ABSL_INTERNAL_UNALIGNED_LOAD64(p));
}
inline void Store64(void* absl_nonnull p, uint64_t v) {
ABSL_INTERNAL_UNALIGNED_STORE64(p, FromHost64(v));
}
} // namespace little_endian
// Utilities to convert numbers between the current hosts's native byte
// order and big-endian byte order (same as network byte order)
//
// Load/Store methods are alignment safe
namespace big_endian {
#ifdef ABSL_IS_LITTLE_ENDIAN
inline uint16_t FromHost16(uint16_t x) { return gbswap_16(x); }
inline uint16_t ToHost16(uint16_t x) { return gbswap_16(x); }
inline uint32_t FromHost32(uint32_t x) { return gbswap_32(x); }
inline uint32_t ToHost32(uint32_t x) { return gbswap_32(x); }
inline uint64_t FromHost64(uint64_t x) { return gbswap_64(x); }
inline uint64_t ToHost64(uint64_t x) { return gbswap_64(x); }
inline constexpr bool IsLittleEndian() { return true; }
#elif defined ABSL_IS_BIG_ENDIAN
inline uint16_t FromHost16(uint16_t x) { return x; }
inline uint16_t ToHost16(uint16_t x) { return x; }
inline uint32_t FromHost32(uint32_t x) { return x; }
inline uint32_t ToHost32(uint32_t x) { return x; }
inline uint64_t FromHost64(uint64_t x) { return x; }
inline uint64_t ToHost64(uint64_t x) { return x; }
inline constexpr bool IsLittleEndian() { return false; }
#endif /* ENDIAN */
inline uint8_t FromHost(uint8_t x) { return x; }
inline uint16_t FromHost(uint16_t x) { return FromHost16(x); }
inline uint32_t FromHost(uint32_t x) { return FromHost32(x); }
inline uint64_t FromHost(uint64_t x) { return FromHost64(x); }
inline uint8_t ToHost(uint8_t x) { return x; }
inline uint16_t ToHost(uint16_t x) { return ToHost16(x); }
inline uint32_t ToHost(uint32_t x) { return ToHost32(x); }
inline uint64_t ToHost(uint64_t x) { return ToHost64(x); }
inline int8_t FromHost(int8_t x) { return x; }
inline int16_t FromHost(int16_t x) {
return bit_cast<int16_t>(FromHost16(bit_cast<uint16_t>(x)));
}
inline int32_t FromHost(int32_t x) {
return bit_cast<int32_t>(FromHost32(bit_cast<uint32_t>(x)));
}
inline int64_t FromHost(int64_t x) {
return bit_cast<int64_t>(FromHost64(bit_cast<uint64_t>(x)));
}
inline int8_t ToHost(int8_t x) { return x; }
inline int16_t ToHost(int16_t x) {
return bit_cast<int16_t>(ToHost16(bit_cast<uint16_t>(x)));
}
inline int32_t ToHost(int32_t x) {
return bit_cast<int32_t>(ToHost32(bit_cast<uint32_t>(x)));
}
inline int64_t ToHost(int64_t x) {
return bit_cast<int64_t>(ToHost64(bit_cast<uint64_t>(x)));
}
// Functions to do unaligned loads and stores in big-endian order.
inline uint16_t Load16(const void* absl_nonnull p) {
return ToHost16(ABSL_INTERNAL_UNALIGNED_LOAD16(p));
}
inline void Store16(void* absl_nonnull p, uint16_t v) {
ABSL_INTERNAL_UNALIGNED_STORE16(p, FromHost16(v));
}
inline uint32_t Load32(const void* absl_nonnull p) {
return ToHost32(ABSL_INTERNAL_UNALIGNED_LOAD32(p));
}
inline void Store32(void* absl_nonnull p, uint32_t v) {
ABSL_INTERNAL_UNALIGNED_STORE32(p, FromHost32(v));
}
inline uint64_t Load64(const void* absl_nonnull p) {
return ToHost64(ABSL_INTERNAL_UNALIGNED_LOAD64(p));
}
inline void Store64(void* absl_nonnull p, uint64_t v) {
ABSL_INTERNAL_UNALIGNED_STORE64(p, FromHost64(v));
}
} // namespace big_endian
ABSL_NAMESPACE_END
} // namespace absl
#endif // ABSL_BASE_INTERNAL_ENDIAN_H_

View File

@@ -1,43 +0,0 @@
// Copyright 2017 The Abseil Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef ABSL_BASE_INTERNAL_ERRNO_SAVER_H_
#define ABSL_BASE_INTERNAL_ERRNO_SAVER_H_
#include <cerrno>
#include "absl/base/config.h"
namespace absl {
ABSL_NAMESPACE_BEGIN
namespace base_internal {
// `ErrnoSaver` captures the value of `errno` upon construction and restores it
// upon deletion. It is used in low-level code and must be super fast. Do not
// add instrumentation, even in debug modes.
class ErrnoSaver {
public:
ErrnoSaver() : saved_errno_(errno) {}
~ErrnoSaver() { errno = saved_errno_; }
int operator()() const { return saved_errno_; }
private:
const int saved_errno_;
};
} // namespace base_internal
ABSL_NAMESPACE_END
} // namespace absl
#endif // ABSL_BASE_INTERNAL_ERRNO_SAVER_H_

View File

@@ -1,51 +0,0 @@
// Copyright 2018 The Abseil Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef ABSL_BASE_INTERNAL_HIDE_PTR_H_
#define ABSL_BASE_INTERNAL_HIDE_PTR_H_
#include <cstdint>
#include "absl/base/config.h"
namespace absl {
ABSL_NAMESPACE_BEGIN
namespace base_internal {
// Arbitrary value with high bits set. Xor'ing with it is unlikely
// to map one valid pointer to another valid pointer.
constexpr uintptr_t HideMask() {
return (uintptr_t{0xF03A5F7BU} << (sizeof(uintptr_t) - 4) * 8) | 0xF03A5F7BU;
}
// Hide a pointer from the leak checker. For internal use only.
// Differs from absl::IgnoreLeak(ptr) in that absl::IgnoreLeak(ptr) causes ptr
// and all objects reachable from ptr to be ignored by the leak checker.
template <class T>
inline uintptr_t HidePtr(T* ptr) {
return reinterpret_cast<uintptr_t>(ptr) ^ HideMask();
}
// Return a pointer that has been hidden from the leak checker.
// For internal use only.
template <class T>
inline T* UnhidePtr(uintptr_t hidden) {
return reinterpret_cast<T*>(hidden ^ HideMask());
}
} // namespace base_internal
ABSL_NAMESPACE_END
} // namespace absl
#endif // ABSL_BASE_INTERNAL_HIDE_PTR_H_

View File

@@ -1,39 +0,0 @@
// Copyright 2017 The Abseil Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
#ifndef ABSL_BASE_INTERNAL_IDENTITY_H_
#define ABSL_BASE_INTERNAL_IDENTITY_H_
#include "absl/base/config.h"
namespace absl {
ABSL_NAMESPACE_BEGIN
namespace internal {
// This is a back-fill of C++20's `std::type_identity`.
template <typename T>
struct type_identity {
typedef T type;
};
// This is a back-fill of C++20's `std::type_identity_t`.
template <typename T>
using type_identity_t = typename type_identity<T>::type;
} // namespace internal
ABSL_NAMESPACE_END
} // namespace absl
#endif // ABSL_BASE_INTERNAL_IDENTITY_H_

View File

@@ -1,71 +0,0 @@
// Copyright 2025 The Abseil Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// -----------------------------------------------------------------------------
// File: internal/iterator_traits.h
// -----------------------------------------------------------------------------
//
// Helpers for querying traits of iterators, for implementing containers, etc.
#ifndef ABSL_BASE_INTERNAL_ITERATOR_TRAITS_H_
#define ABSL_BASE_INTERNAL_ITERATOR_TRAITS_H_
#include <iterator>
#include <type_traits>
#include "absl/base/config.h"
#include "absl/meta/type_traits.h"
namespace absl {
ABSL_NAMESPACE_BEGIN
namespace base_internal {
template <typename Iterator, typename = void>
struct IteratorCategory {};
template <typename Iterator>
struct IteratorCategory<
Iterator,
absl::void_t<typename std::iterator_traits<Iterator>::iterator_category>> {
using type = typename std::iterator_traits<Iterator>::iterator_category;
};
template <typename Iterator, typename = void>
struct IteratorConceptImpl : IteratorCategory<Iterator> {};
template <typename Iterator>
struct IteratorConceptImpl<
Iterator,
absl::void_t<typename std::iterator_traits<Iterator>::iterator_concept>> {
using type = typename std::iterator_traits<Iterator>::iterator_concept;
};
// The newer `std::iterator_traits<Iterator>::iterator_concept` if available,
// else `std::iterator_traits<Iterator>::iterator_category`.
template <typename Iterator>
using IteratorConcept = typename IteratorConceptImpl<Iterator>::type;
template <typename IteratorTag, typename Iterator>
using IsAtLeastIterator =
std::is_convertible<IteratorConcept<Iterator>, IteratorTag>;
template <typename Iterator>
using IsAtLeastForwardIterator =
IsAtLeastIterator<std::forward_iterator_tag, Iterator>;
} // namespace base_internal
ABSL_NAMESPACE_END
} // namespace absl
#endif // ABSL_BASE_INTERNAL_ITERATOR_TRAITS_H_

View File

@@ -1,133 +0,0 @@
// Copyright 2017 The Abseil Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
#ifndef ABSL_BASE_INTERNAL_LOW_LEVEL_ALLOC_H_
#define ABSL_BASE_INTERNAL_LOW_LEVEL_ALLOC_H_
// A simple thread-safe memory allocator that does not depend on
// mutexes or thread-specific data. It is intended to be used
// sparingly, and only when malloc() would introduce an unwanted
// dependency, such as inside the heap-checker, or the Mutex
// implementation.
// IWYU pragma: private, include "base/low_level_alloc.h"
#include <sys/types.h>
#include <cstdint>
#include "absl/base/attributes.h"
#include "absl/base/config.h"
// LowLevelAlloc requires that the platform support low-level
// allocation of virtual memory. Platforms lacking this cannot use
// LowLevelAlloc.
#ifdef ABSL_LOW_LEVEL_ALLOC_MISSING
#error ABSL_LOW_LEVEL_ALLOC_MISSING cannot be directly set
#elif !defined(ABSL_HAVE_MMAP) && !defined(_WIN32)
#define ABSL_LOW_LEVEL_ALLOC_MISSING 1
#endif
// Using LowLevelAlloc with kAsyncSignalSafe isn't supported on Windows or
// asm.js / WebAssembly.
// See https://kripken.github.io/emscripten-site/docs/porting/pthreads.html
// for more information.
#ifdef ABSL_LOW_LEVEL_ALLOC_ASYNC_SIGNAL_SAFE_MISSING
#error ABSL_LOW_LEVEL_ALLOC_ASYNC_SIGNAL_SAFE_MISSING cannot be directly set
#elif defined(_WIN32) || defined(__asmjs__) || defined(__wasm__) || \
defined(__hexagon__)
#define ABSL_LOW_LEVEL_ALLOC_ASYNC_SIGNAL_SAFE_MISSING 1
#endif
#include <cstddef>
#include "absl/base/port.h"
namespace absl {
ABSL_NAMESPACE_BEGIN
namespace base_internal {
class LowLevelAlloc {
public:
struct Arena; // an arena from which memory may be allocated
// Returns a pointer to a block of at least "request" bytes
// that have been newly allocated from the specific arena.
// for Alloc() call the DefaultArena() is used.
// Returns 0 if passed request==0.
// Does not return 0 under other circumstances; it crashes if memory
// is not available.
static void *Alloc(size_t request) ABSL_ATTRIBUTE_SECTION(malloc_hook);
static void *AllocWithArena(size_t request, Arena *arena)
ABSL_ATTRIBUTE_SECTION(malloc_hook);
// Deallocates a region of memory that was previously allocated with
// Alloc(). Does nothing if passed 0. "s" must be either 0,
// or must have been returned from a call to Alloc() and not yet passed to
// Free() since that call to Alloc(). The space is returned to the arena
// from which it was allocated.
static void Free(void *s) ABSL_ATTRIBUTE_SECTION(malloc_hook);
// ABSL_ATTRIBUTE_SECTION(malloc_hook) for Alloc* and Free
// are to put all callers of MallocHook::Invoke* in this module
// into special section,
// so that MallocHook::GetCallerStackTrace can function accurately.
// Create a new arena.
// The root metadata for the new arena is allocated in the
// meta_data_arena; the DefaultArena() can be passed for meta_data_arena.
// These values may be ored into flags:
enum {
// Report calls to Alloc() and Free() via the MallocHook interface.
// Set in the DefaultArena.
kCallMallocHook = 0x0001,
#ifndef ABSL_LOW_LEVEL_ALLOC_ASYNC_SIGNAL_SAFE_MISSING
// Make calls to Alloc(), Free() be async-signal-safe. Not set in
// DefaultArena(). Not supported on all platforms.
kAsyncSignalSafe = 0x0002,
#endif
};
// Construct a new arena. The allocation of the underlying metadata honors
// the provided flags. For example, the call NewArena(kAsyncSignalSafe)
// is itself async-signal-safe, as well as generatating an arena that provides
// async-signal-safe Alloc/Free.
static Arena *NewArena(uint32_t flags);
// Destroys an arena allocated by NewArena and returns true,
// provided no allocated blocks remain in the arena.
// If allocated blocks remain in the arena, does nothing and
// returns false.
// It is illegal to attempt to destroy the DefaultArena().
static bool DeleteArena(Arena *arena);
// The default arena that always exists.
static Arena *DefaultArena();
private:
LowLevelAlloc(); // no instances
};
// Returns a global async-signal-safe arena for LowLevelAlloc.
LowLevelAlloc::Arena *SigSafeArena();
// Ensures the global async-signal-safe arena for LowLevelAlloc is initialized.
void InitSigSafeArena();
} // namespace base_internal
ABSL_NAMESPACE_END
} // namespace absl
#endif // ABSL_BASE_INTERNAL_LOW_LEVEL_ALLOC_H_

View File

@@ -1,134 +0,0 @@
// Copyright 2017 The Abseil Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// Core interfaces and definitions used by by low-level interfaces such as
// SpinLock.
#ifndef ABSL_BASE_INTERNAL_LOW_LEVEL_SCHEDULING_H_
#define ABSL_BASE_INTERNAL_LOW_LEVEL_SCHEDULING_H_
#include "absl/base/internal/raw_logging.h"
#include "absl/base/internal/scheduling_mode.h"
#include "absl/base/macros.h"
// The following two declarations exist so SchedulingGuard may friend them with
// the appropriate language linkage. These callbacks allow libc internals, such
// as function level statics, to schedule cooperatively when locking.
extern "C" bool __google_disable_rescheduling(void);
extern "C" void __google_enable_rescheduling(bool disable_result);
namespace absl {
ABSL_NAMESPACE_BEGIN
class CondVar;
class Mutex;
namespace synchronization_internal {
int MutexDelay(int32_t c, int mode);
} // namespace synchronization_internal
namespace base_internal {
class SchedulingHelper; // To allow use of SchedulingGuard.
class SpinLock; // To allow use of SchedulingGuard.
// SchedulingGuard
// Provides guard semantics that may be used to disable cooperative rescheduling
// of the calling thread within specific program blocks. This is used to
// protect resources (e.g. low-level SpinLocks or Domain code) that cooperative
// scheduling depends on.
//
// Domain implementations capable of rescheduling in reaction to involuntary
// kernel thread actions (e.g blocking due to a pagefault or syscall) must
// guarantee that an annotated thread is not allowed to (cooperatively)
// reschedule until the annotated region is complete.
//
// It is an error to attempt to use a cooperatively scheduled resource (e.g.
// Mutex) within a rescheduling-disabled region.
//
// All methods are async-signal safe.
class SchedulingGuard {
public:
// Returns true iff the calling thread may be cooperatively rescheduled.
static bool ReschedulingIsAllowed();
SchedulingGuard(const SchedulingGuard&) = delete;
SchedulingGuard& operator=(const SchedulingGuard&) = delete;
private:
// Disable cooperative rescheduling of the calling thread. It may still
// initiate scheduling operations (e.g. wake-ups), however, it may not itself
// reschedule. Nestable. The returned result is opaque, clients should not
// attempt to interpret it.
// REQUIRES: Result must be passed to a pairing EnableScheduling().
static bool DisableRescheduling();
// Marks the end of a rescheduling disabled region, previously started by
// DisableRescheduling().
// REQUIRES: Pairs with innermost call (and result) of DisableRescheduling().
static void EnableRescheduling(bool disable_result);
// A scoped helper for {Disable, Enable}Rescheduling().
// REQUIRES: destructor must run in same thread as constructor.
struct ScopedDisable {
ScopedDisable() { disabled = SchedulingGuard::DisableRescheduling(); }
~ScopedDisable() { SchedulingGuard::EnableRescheduling(disabled); }
bool disabled;
};
// A scoped helper to enable rescheduling temporarily.
// REQUIRES: destructor must run in same thread as constructor.
class ScopedEnable {
public:
ScopedEnable();
~ScopedEnable();
private:
int scheduling_disabled_depth_;
};
// Access to SchedulingGuard is explicitly permitted.
friend class absl::CondVar;
friend class absl::Mutex;
friend class SchedulingHelper;
friend class SpinLock;
friend int absl::synchronization_internal::MutexDelay(int32_t c, int mode);
};
//------------------------------------------------------------------------------
// End of public interfaces.
//------------------------------------------------------------------------------
inline bool SchedulingGuard::ReschedulingIsAllowed() {
return false;
}
inline bool SchedulingGuard::DisableRescheduling() {
return false;
}
inline void SchedulingGuard::EnableRescheduling(bool /* disable_result */) {
return;
}
inline SchedulingGuard::ScopedEnable::ScopedEnable()
: scheduling_disabled_depth_(0) {}
inline SchedulingGuard::ScopedEnable::~ScopedEnable() {
ABSL_RAW_CHECK(scheduling_disabled_depth_ == 0, "disable unused warning");
}
} // namespace base_internal
ABSL_NAMESPACE_END
} // namespace absl
#endif // ABSL_BASE_INTERNAL_LOW_LEVEL_SCHEDULING_H_

View File

@@ -1,52 +0,0 @@
// Copyright 2017 The Abseil Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef ABSL_BASE_INTERNAL_PER_THREAD_TLS_H_
#define ABSL_BASE_INTERNAL_PER_THREAD_TLS_H_
// This header defines two macros:
//
// If the platform supports thread-local storage:
//
// * ABSL_PER_THREAD_TLS_KEYWORD is the C keyword needed to declare a
// thread-local variable
// * ABSL_PER_THREAD_TLS is 1
//
// Otherwise:
//
// * ABSL_PER_THREAD_TLS_KEYWORD is empty
// * ABSL_PER_THREAD_TLS is 0
//
// Microsoft C supports thread-local storage.
// GCC supports it if the appropriate version of glibc is available,
// which the programmer can indicate by defining ABSL_HAVE_TLS
#include "absl/base/port.h" // For ABSL_HAVE_TLS
#if defined(ABSL_PER_THREAD_TLS)
#error ABSL_PER_THREAD_TLS cannot be directly set
#elif defined(ABSL_PER_THREAD_TLS_KEYWORD)
#error ABSL_PER_THREAD_TLS_KEYWORD cannot be directly set
#elif defined(ABSL_HAVE_TLS)
#define ABSL_PER_THREAD_TLS_KEYWORD __thread
#define ABSL_PER_THREAD_TLS 1
#elif defined(_MSC_VER)
#define ABSL_PER_THREAD_TLS_KEYWORD __declspec(thread)
#define ABSL_PER_THREAD_TLS 1
#else
#define ABSL_PER_THREAD_TLS_KEYWORD
#define ABSL_PER_THREAD_TLS 0
#endif
#endif // ABSL_BASE_INTERNAL_PER_THREAD_TLS_H_

View File

@@ -1,59 +0,0 @@
// Copyright 2024 The Abseil Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef ABSL_BASE_INTERNAL_POISON_H_
#define ABSL_BASE_INTERNAL_POISON_H_
#include <cstdint>
#include "absl/base/config.h"
namespace absl {
ABSL_NAMESPACE_BEGIN
namespace base_internal {
inline void* GetBadPointerInternal() {
// A likely bad pointer. Pointers are required to have high bits that are all
// zero or all one for certain 64-bit CPUs. This pointer value will hopefully
// cause a crash on dereference and also be clearly recognizable as invalid.
constexpr uint64_t kBadPtr = 0xBAD0BAD0BAD0BAD0;
auto ret = reinterpret_cast<void*>(static_cast<uintptr_t>(kBadPtr));
#ifndef _MSC_VER // MSVC doesn't support inline asm with `volatile`.
// Try to prevent the compiler from optimizing out the undefined behavior.
asm volatile("" : : "r"(ret) :); // NOLINT
#endif
return ret;
}
void* InitializePoisonedPointerInternal();
inline void* get_poisoned_pointer() {
#if defined(NDEBUG) && !defined(ABSL_HAVE_ADDRESS_SANITIZER) && \
!defined(ABSL_HAVE_MEMORY_SANITIZER)
// In optimized non-sanitized builds, avoid the function-local static because
// of the codegen and runtime cost.
return GetBadPointerInternal();
#else
// Non-optimized builds may use more robust implementation. Note that we can't
// use a static global because Chromium doesn't allow non-constinit globals.
static void* ptr = InitializePoisonedPointerInternal();
return ptr;
#endif
}
} // namespace base_internal
ABSL_NAMESPACE_END
} // namespace absl
#endif // ABSL_BASE_INTERNAL_POISON_H_

View File

@@ -1,33 +0,0 @@
// Copyright 2017 The Abseil Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef ABSL_BASE_INTERNAL_PRETTY_FUNCTION_H_
#define ABSL_BASE_INTERNAL_PRETTY_FUNCTION_H_
// ABSL_PRETTY_FUNCTION
//
// In C++11, __func__ gives the undecorated name of the current function. That
// is, "main", not "int main()". Various compilers give extra macros to get the
// decorated function name, including return type and arguments, to
// differentiate between overload sets. ABSL_PRETTY_FUNCTION is a portable
// version of these macros which forwards to the correct macro on each compiler.
#if defined(_MSC_VER)
#define ABSL_PRETTY_FUNCTION __FUNCSIG__
#elif defined(__GNUC__)
#define ABSL_PRETTY_FUNCTION __PRETTY_FUNCTION__
#else
#error "Unsupported compiler"
#endif
#endif // ABSL_BASE_INTERNAL_PRETTY_FUNCTION_H_

View File

@@ -1,217 +0,0 @@
// Copyright 2017 The Abseil Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// Thread-safe logging routines that do not allocate any memory or
// acquire any locks, and can therefore be used by low-level memory
// allocation, synchronization, and signal-handling code.
#ifndef ABSL_BASE_INTERNAL_RAW_LOGGING_H_
#define ABSL_BASE_INTERNAL_RAW_LOGGING_H_
#include <string>
#include "absl/base/attributes.h"
#include "absl/base/config.h"
#include "absl/base/internal/atomic_hook.h"
#include "absl/base/log_severity.h"
#include "absl/base/macros.h"
#include "absl/base/optimization.h"
#include "absl/base/port.h"
// This is similar to LOG(severity) << format..., but
// * it is to be used ONLY by low-level modules that can't use normal LOG()
// * it is designed to be a low-level logger that does not allocate any
// memory and does not need any locks, hence:
// * it logs straight and ONLY to STDERR w/o buffering
// * it uses an explicit printf-format and arguments list
// * it will silently chop off really long message strings
// Usage example:
// ABSL_RAW_LOG(ERROR, "Failed foo with %i: %s", status, error);
// This will print an almost standard log line like this to stderr only:
// E0821 211317 file.cc:123] RAW: Failed foo with 22: bad_file
#define ABSL_RAW_LOG(severity, ...) \
do { \
constexpr const char* absl_raw_log_internal_basename = \
::absl::raw_log_internal::Basename(__FILE__, sizeof(__FILE__) - 1); \
::absl::raw_log_internal::RawLog(ABSL_RAW_LOG_INTERNAL_##severity, \
absl_raw_log_internal_basename, __LINE__, \
__VA_ARGS__); \
ABSL_RAW_LOG_INTERNAL_MAYBE_UNREACHABLE_##severity; \
} while (0)
// Similar to CHECK(condition) << message, but for low-level modules:
// we use only ABSL_RAW_LOG that does not allocate memory.
// We do not want to provide args list here to encourage this usage:
// if (!cond) ABSL_RAW_LOG(FATAL, "foo ...", hard_to_compute_args);
// so that the args are not computed when not needed.
#define ABSL_RAW_CHECK(condition, message) \
do { \
if (ABSL_PREDICT_FALSE(!(condition))) { \
ABSL_RAW_LOG(FATAL, "Check %s failed: %s", #condition, message); \
} \
} while (0)
// ABSL_INTERNAL_LOG and ABSL_INTERNAL_CHECK work like the RAW variants above,
// except that if the richer log library is linked into the binary, we dispatch
// to that instead. This is potentially useful for internal logging and
// assertions, where we are using RAW_LOG neither for its async-signal-safety
// nor for its non-allocating nature, but rather because raw logging has very
// few other dependencies.
//
// The API is a subset of the above: each macro only takes two arguments. Use
// StrCat if you need to build a richer message.
#define ABSL_INTERNAL_LOG(severity, message) \
do { \
constexpr const char* absl_raw_log_internal_filename = __FILE__; \
::absl::raw_log_internal::internal_log_function( \
ABSL_RAW_LOG_INTERNAL_##severity, absl_raw_log_internal_filename, \
__LINE__, message); \
ABSL_RAW_LOG_INTERNAL_MAYBE_UNREACHABLE_##severity; \
} while (0)
#define ABSL_INTERNAL_CHECK(condition, message) \
do { \
if (ABSL_PREDICT_FALSE(!(condition))) { \
std::string death_message = "Check " #condition " failed: "; \
death_message += std::string(message); \
ABSL_INTERNAL_LOG(FATAL, death_message); \
} \
} while (0)
#ifndef NDEBUG
#define ABSL_RAW_DLOG(severity, ...) ABSL_RAW_LOG(severity, __VA_ARGS__)
#define ABSL_RAW_DCHECK(condition, message) ABSL_RAW_CHECK(condition, message)
#else // NDEBUG
#define ABSL_RAW_DLOG(severity, ...) \
while (false) ABSL_RAW_LOG(severity, __VA_ARGS__)
#define ABSL_RAW_DCHECK(condition, message) \
while (false) ABSL_RAW_CHECK(condition, message)
#endif // NDEBUG
#define ABSL_RAW_LOG_INTERNAL_INFO ::absl::LogSeverity::kInfo
#define ABSL_RAW_LOG_INTERNAL_WARNING ::absl::LogSeverity::kWarning
#define ABSL_RAW_LOG_INTERNAL_ERROR ::absl::LogSeverity::kError
#define ABSL_RAW_LOG_INTERNAL_FATAL ::absl::LogSeverity::kFatal
#define ABSL_RAW_LOG_INTERNAL_DFATAL ::absl::kLogDebugFatal
#define ABSL_RAW_LOG_INTERNAL_LEVEL(severity) \
::absl::NormalizeLogSeverity(severity)
#define ABSL_RAW_LOG_INTERNAL_MAYBE_UNREACHABLE_INFO
#define ABSL_RAW_LOG_INTERNAL_MAYBE_UNREACHABLE_WARNING
#define ABSL_RAW_LOG_INTERNAL_MAYBE_UNREACHABLE_ERROR
#define ABSL_RAW_LOG_INTERNAL_MAYBE_UNREACHABLE_FATAL ABSL_UNREACHABLE()
#define ABSL_RAW_LOG_INTERNAL_MAYBE_UNREACHABLE_DFATAL
#define ABSL_RAW_LOG_INTERNAL_MAYBE_UNREACHABLE_LEVEL(severity)
namespace absl {
ABSL_NAMESPACE_BEGIN
namespace raw_log_internal {
// Helper function to implement ABSL_RAW_LOG
// Logs format... at "severity" level, reporting it
// as called from file:line.
// This does not allocate memory or acquire locks.
void RawLog(absl::LogSeverity severity, const char* file, int line,
const char* format, ...) ABSL_PRINTF_ATTRIBUTE(4, 5);
// Writes the provided buffer directly to stderr, in a signal-safe, low-level
// manner. Preserves errno.
void AsyncSignalSafeWriteError(const char* s, size_t len);
// compile-time function to get the "base" filename, that is, the part of
// a filename after the last "/" or "\" path separator. The search starts at
// the end of the string; the second parameter is the length of the string.
constexpr const char* Basename(const char* fname, int offset) {
return offset == 0 || fname[offset - 1] == '/' || fname[offset - 1] == '\\'
? fname + offset
: Basename(fname, offset - 1);
}
// For testing only.
// Returns true if raw logging is fully supported. When it is not
// fully supported, no messages will be emitted, but a log at FATAL
// severity will cause an abort.
//
// TODO(gfalcon): Come up with a better name for this method.
bool RawLoggingFullySupported();
// Function type for a raw_log customization hook for suppressing messages
// by severity, and for writing custom prefixes on non-suppressed messages.
//
// The installed hook is called for every raw log invocation. The message will
// be logged to stderr only if the hook returns true. FATAL errors will cause
// the process to abort, even if writing to stderr is suppressed. The hook is
// also provided with an output buffer, where it can write a custom log message
// prefix.
//
// The raw_log system does not allocate memory or grab locks. User-provided
// hooks must avoid these operations, and must not throw exceptions.
//
// 'severity' is the severity level of the message being written.
// 'file' and 'line' are the file and line number where the ABSL_RAW_LOG macro
// was located.
// 'buf' and 'buf_size' are pointers to the buffer and buffer size. If the
// hook writes a prefix, it must increment *buf and decrement *buf_size
// accordingly.
using LogFilterAndPrefixHook = bool (*)(absl::LogSeverity severity,
const char* file, int line, char** buf,
int* buf_size);
// Function type for a raw_log customization hook called to abort a process
// when a FATAL message is logged. If the provided AbortHook() returns, the
// logging system will call abort().
//
// 'file' and 'line' are the file and line number where the ABSL_RAW_LOG macro
// was located.
// The NUL-terminated logged message lives in the buffer between 'buf_start'
// and 'buf_end'. 'prefix_end' points to the first non-prefix character of the
// buffer (as written by the LogFilterAndPrefixHook.)
//
// The lifetime of the filename and message buffers will not end while the
// process remains alive.
using AbortHook = void (*)(const char* file, int line, const char* buf_start,
const char* prefix_end, const char* buf_end);
// Internal logging function for ABSL_INTERNAL_LOG to dispatch to.
//
// TODO(gfalcon): When string_view no longer depends on base, change this
// interface to take its message as a string_view instead.
using InternalLogFunction = void (*)(absl::LogSeverity severity,
const char* file, int line,
const std::string& message);
ABSL_INTERNAL_ATOMIC_HOOK_ATTRIBUTES ABSL_DLL extern base_internal::AtomicHook<
InternalLogFunction>
internal_log_function;
// Registers hooks of the above types. Only a single hook of each type may be
// registered. It is an error to call these functions multiple times with
// different input arguments.
//
// These functions are safe to call at any point during initialization; they do
// not block or malloc, and are async-signal safe.
void RegisterLogFilterAndPrefixHook(LogFilterAndPrefixHook func);
void RegisterAbortHook(AbortHook func);
void RegisterInternalLogFunction(InternalLogFunction func);
} // namespace raw_log_internal
ABSL_NAMESPACE_END
} // namespace absl
#endif // ABSL_BASE_INTERNAL_RAW_LOGGING_H_

View File

@@ -1,58 +0,0 @@
// Copyright 2017 The Abseil Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// Core interfaces and definitions used by by low-level interfaces such as
// SpinLock.
#ifndef ABSL_BASE_INTERNAL_SCHEDULING_MODE_H_
#define ABSL_BASE_INTERNAL_SCHEDULING_MODE_H_
#include "absl/base/config.h"
namespace absl {
ABSL_NAMESPACE_BEGIN
namespace base_internal {
// Used to describe how a thread may be scheduled. Typically associated with
// the declaration of a resource supporting synchronized access.
//
// SCHEDULE_COOPERATIVE_AND_KERNEL:
// Specifies that when waiting, a cooperative thread (e.g. a Fiber) may
// reschedule (using base::scheduling semantics); allowing other cooperative
// threads to proceed.
//
// SCHEDULE_KERNEL_ONLY: (Also described as "non-cooperative")
// Specifies that no cooperative scheduling semantics may be used, even if the
// current thread is itself cooperatively scheduled. This means that
// cooperative threads will NOT allow other cooperative threads to execute in
// their place while waiting for a resource of this type. Host operating system
// semantics (e.g. a futex) may still be used.
//
// When optional, clients should strongly prefer SCHEDULE_COOPERATIVE_AND_KERNEL
// by default. SCHEDULE_KERNEL_ONLY should only be used for resources on which
// base::scheduling (e.g. the implementation of a Scheduler) may depend.
//
// NOTE: Cooperative resources may not be nested below non-cooperative ones.
// This means that it is invalid to to acquire a SCHEDULE_COOPERATIVE_AND_KERNEL
// resource if a SCHEDULE_KERNEL_ONLY resource is already held.
enum SchedulingMode {
SCHEDULE_KERNEL_ONLY = 0, // Allow scheduling only the host OS.
SCHEDULE_COOPERATIVE_AND_KERNEL, // Also allow cooperative scheduling.
};
} // namespace base_internal
ABSL_NAMESPACE_END
} // namespace absl
#endif // ABSL_BASE_INTERNAL_SCHEDULING_MODE_H_

View File

@@ -1,45 +0,0 @@
//
// Copyright 2019 The Abseil Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
#ifndef ABSL_BASE_INTERNAL_SCOPED_SET_ENV_H_
#define ABSL_BASE_INTERNAL_SCOPED_SET_ENV_H_
#include <string>
#include "absl/base/config.h"
namespace absl {
ABSL_NAMESPACE_BEGIN
namespace base_internal {
class ScopedSetEnv {
public:
ScopedSetEnv(const char* var_name, const char* new_value);
~ScopedSetEnv();
private:
std::string var_name_;
std::string old_value_;
// True if the environment variable was initially not set.
bool was_unset_;
};
} // namespace base_internal
ABSL_NAMESPACE_END
} // namespace absl
#endif // ABSL_BASE_INTERNAL_SCOPED_SET_ENV_H_

View File

@@ -1,305 +0,0 @@
//
// Copyright 2017 The Abseil Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// Most users requiring mutual exclusion should use Mutex.
// SpinLock is provided for use in two situations:
// - for use by Abseil internal code that Mutex itself depends on
// - for async signal safety (see below)
// SpinLock with a SchedulingMode::SCHEDULE_KERNEL_ONLY is async
// signal safe. If a spinlock is used within a signal handler, all code that
// acquires the lock must ensure that the signal cannot arrive while they are
// holding the lock. Typically, this is done by blocking the signal.
//
// Threads waiting on a SpinLock may be woken in an arbitrary order.
#ifndef ABSL_BASE_INTERNAL_SPINLOCK_H_
#define ABSL_BASE_INTERNAL_SPINLOCK_H_
#include <atomic>
#include <cstdint>
#include <type_traits>
#include "absl/base/attributes.h"
#include "absl/base/config.h"
#include "absl/base/const_init.h"
#include "absl/base/internal/low_level_scheduling.h"
#include "absl/base/internal/raw_logging.h"
#include "absl/base/internal/scheduling_mode.h"
#include "absl/base/internal/tsan_mutex_interface.h"
#include "absl/base/macros.h"
#include "absl/base/thread_annotations.h"
namespace tcmalloc {
namespace tcmalloc_internal {
class AllocationGuardSpinLockHolder;
} // namespace tcmalloc_internal
} // namespace tcmalloc
namespace absl {
ABSL_NAMESPACE_BEGIN
namespace base_internal {
class ABSL_LOCKABLE ABSL_ATTRIBUTE_WARN_UNUSED SpinLock {
public:
constexpr SpinLock() : lockword_(kSpinLockCooperative) { RegisterWithTsan(); }
// Constructors that allow non-cooperative spinlocks to be created for use
// inside thread schedulers. Normal clients should not use these.
constexpr explicit SpinLock(SchedulingMode mode)
: lockword_(IsCooperative(mode) ? kSpinLockCooperative : 0) {
RegisterWithTsan();
}
#if ABSL_HAVE_ATTRIBUTE(enable_if) && !defined(_WIN32)
// Constructor to inline users of the default scheduling mode.
//
// This only needs to exists for inliner runs, but doesn't work correctly in
// clang+windows builds, likely due to mangling differences.
ABSL_DEPRECATE_AND_INLINE()
constexpr explicit SpinLock(SchedulingMode mode)
__attribute__((enable_if(mode == SCHEDULE_COOPERATIVE_AND_KERNEL,
"Cooperative use default constructor")))
: SpinLock() {}
#endif
// Constructor for global SpinLock instances. See absl/base/const_init.h.
ABSL_DEPRECATE_AND_INLINE()
constexpr SpinLock(absl::ConstInitType, SchedulingMode mode)
: SpinLock(mode) {}
// For global SpinLock instances prefer trivial destructor when possible.
// Default but non-trivial destructor in some build configurations causes an
// extra static initializer.
#ifdef ABSL_INTERNAL_HAVE_TSAN_INTERFACE
~SpinLock() { ABSL_TSAN_MUTEX_DESTROY(this, __tsan_mutex_not_static); }
#else
~SpinLock() = default;
#endif
// Acquire this SpinLock.
inline void lock() ABSL_EXCLUSIVE_LOCK_FUNCTION() {
ABSL_TSAN_MUTEX_PRE_LOCK(this, 0);
if (!TryLockImpl()) {
SlowLock();
}
ABSL_TSAN_MUTEX_POST_LOCK(this, 0, 0);
}
ABSL_DEPRECATE_AND_INLINE()
inline void Lock() ABSL_EXCLUSIVE_LOCK_FUNCTION() { return lock(); }
// Try to acquire this SpinLock without blocking and return true if the
// acquisition was successful. If the lock was not acquired, false is
// returned. If this SpinLock is free at the time of the call, try_lock will
// return true with high probability.
[[nodiscard]] inline bool try_lock() ABSL_EXCLUSIVE_TRYLOCK_FUNCTION(true) {
ABSL_TSAN_MUTEX_PRE_LOCK(this, __tsan_mutex_try_lock);
bool res = TryLockImpl();
ABSL_TSAN_MUTEX_POST_LOCK(
this, __tsan_mutex_try_lock | (res ? 0 : __tsan_mutex_try_lock_failed),
0);
return res;
}
ABSL_DEPRECATE_AND_INLINE()
[[nodiscard]] inline bool TryLock() ABSL_EXCLUSIVE_TRYLOCK_FUNCTION(true) {
return try_lock();
}
// Release this SpinLock, which must be held by the calling thread.
inline void unlock() ABSL_UNLOCK_FUNCTION() {
ABSL_TSAN_MUTEX_PRE_UNLOCK(this, 0);
uint32_t lock_value = lockword_.load(std::memory_order_relaxed);
lock_value = lockword_.exchange(lock_value & kSpinLockCooperative,
std::memory_order_release);
if ((lock_value & kSpinLockDisabledScheduling) != 0) {
SchedulingGuard::EnableRescheduling(true);
}
if ((lock_value & kWaitTimeMask) != 0) {
// Collect contentionz profile info, and speed the wakeup of any waiter.
// The wait_cycles value indicates how long this thread spent waiting
// for the lock.
SlowUnlock(lock_value);
}
ABSL_TSAN_MUTEX_POST_UNLOCK(this, 0);
}
ABSL_DEPRECATE_AND_INLINE()
inline void Unlock() ABSL_UNLOCK_FUNCTION() { unlock(); }
// Determine if the lock is held. When the lock is held by the invoking
// thread, true will always be returned. Intended to be used as
// CHECK(lock.IsHeld()).
[[nodiscard]] inline bool IsHeld() const {
return (lockword_.load(std::memory_order_relaxed) & kSpinLockHeld) != 0;
}
// Return immediately if this thread holds the SpinLock exclusively.
// Otherwise, report an error by crashing with a diagnostic.
inline void AssertHeld() const ABSL_ASSERT_EXCLUSIVE_LOCK() {
if (!IsHeld()) {
ABSL_RAW_LOG(FATAL, "thread should hold the lock on SpinLock");
}
}
protected:
// These should not be exported except for testing.
// Store number of cycles between wait_start_time and wait_end_time in a
// lock value.
static uint32_t EncodeWaitCycles(int64_t wait_start_time,
int64_t wait_end_time);
// Extract number of wait cycles in a lock value.
static int64_t DecodeWaitCycles(uint32_t lock_value);
// Provide access to protected method above. Use for testing only.
friend struct SpinLockTest;
friend class tcmalloc::tcmalloc_internal::AllocationGuardSpinLockHolder;
private:
// lockword_ is used to store the following:
//
// bit[0] encodes whether a lock is being held.
// bit[1] encodes whether a lock uses cooperative scheduling.
// bit[2] encodes whether the current lock holder disabled scheduling when
// acquiring the lock. Only set when kSpinLockHeld is also set.
// bit[3:31] encodes time a lock spent on waiting as a 29-bit unsigned int.
// This is set by the lock holder to indicate how long it waited on
// the lock before eventually acquiring it. The number of cycles is
// encoded as a 29-bit unsigned int, or in the case that the current
// holder did not wait but another waiter is queued, the LSB
// (kSpinLockSleeper) is set. The implementation does not explicitly
// track the number of queued waiters beyond this. It must always be
// assumed that waiters may exist if the current holder was required to
// queue.
//
// Invariant: if the lock is not held, the value is either 0 or
// kSpinLockCooperative.
static constexpr uint32_t kSpinLockHeld = 1;
static constexpr uint32_t kSpinLockCooperative = 2;
static constexpr uint32_t kSpinLockDisabledScheduling = 4;
static constexpr uint32_t kSpinLockSleeper = 8;
// Includes kSpinLockSleeper.
static constexpr uint32_t kWaitTimeMask =
~(kSpinLockHeld | kSpinLockCooperative | kSpinLockDisabledScheduling);
// Returns true if the provided scheduling mode is cooperative.
static constexpr bool IsCooperative(SchedulingMode scheduling_mode) {
return scheduling_mode == SCHEDULE_COOPERATIVE_AND_KERNEL;
}
constexpr void RegisterWithTsan() {
#if ABSL_HAVE_BUILTIN(__builtin_is_constant_evaluated)
if (!__builtin_is_constant_evaluated()) {
ABSL_TSAN_MUTEX_CREATE(this, __tsan_mutex_not_static);
}
#endif
}
bool IsCooperative() const {
return lockword_.load(std::memory_order_relaxed) & kSpinLockCooperative;
}
uint32_t TryLockInternal(uint32_t lock_value, uint32_t wait_cycles);
void SlowLock() ABSL_ATTRIBUTE_COLD;
void SlowUnlock(uint32_t lock_value) ABSL_ATTRIBUTE_COLD;
uint32_t SpinLoop();
inline bool TryLockImpl() {
uint32_t lock_value = lockword_.load(std::memory_order_relaxed);
return (TryLockInternal(lock_value, 0) & kSpinLockHeld) == 0;
}
std::atomic<uint32_t> lockword_;
SpinLock(const SpinLock&) = delete;
SpinLock& operator=(const SpinLock&) = delete;
};
// Corresponding locker object that arranges to acquire a spinlock for
// the duration of a C++ scope.
class ABSL_SCOPED_LOCKABLE [[nodiscard]] SpinLockHolder {
public:
inline explicit SpinLockHolder(
SpinLock& l ABSL_INTERNAL_ATTRIBUTE_CAPTURED_BY(this))
ABSL_EXCLUSIVE_LOCK_FUNCTION(l)
: lock_(l) {
l.lock();
}
ABSL_DEPRECATE_AND_INLINE()
inline explicit SpinLockHolder(SpinLock* l) ABSL_EXCLUSIVE_LOCK_FUNCTION(l)
: SpinLockHolder(*l) {}
inline ~SpinLockHolder() ABSL_UNLOCK_FUNCTION() { lock_.unlock(); }
SpinLockHolder(const SpinLockHolder&) = delete;
SpinLockHolder& operator=(const SpinLockHolder&) = delete;
private:
SpinLock& lock_;
};
// Register a hook for profiling support.
//
// The function pointer registered here will be called whenever a spinlock is
// contended. The callback is given an opaque handle to the contended spinlock
// and the number of wait cycles. This is thread-safe, but only a single
// profiler can be registered. It is an error to call this function multiple
// times with different arguments.
void RegisterSpinLockProfiler(void (*fn)(const void* lock,
int64_t wait_cycles));
//------------------------------------------------------------------------------
// Public interface ends here.
//------------------------------------------------------------------------------
// If (result & kSpinLockHeld) == 0, then *this was successfully locked.
// Otherwise, returns last observed value for lockword_.
inline uint32_t SpinLock::TryLockInternal(uint32_t lock_value,
uint32_t wait_cycles) {
if ((lock_value & kSpinLockHeld) != 0) {
return lock_value;
}
uint32_t sched_disabled_bit = 0;
if ((lock_value & kSpinLockCooperative) == 0) {
// For non-cooperative locks we must make sure we mark ourselves as
// non-reschedulable before we attempt to CompareAndSwap.
if (SchedulingGuard::DisableRescheduling()) {
sched_disabled_bit = kSpinLockDisabledScheduling;
}
}
if (!lockword_.compare_exchange_strong(
lock_value,
kSpinLockHeld | lock_value | wait_cycles | sched_disabled_bit,
std::memory_order_acquire, std::memory_order_relaxed)) {
SchedulingGuard::EnableRescheduling(sched_disabled_bit != 0);
}
return lock_value;
}
} // namespace base_internal
ABSL_NAMESPACE_END
} // namespace absl
#endif // ABSL_BASE_INTERNAL_SPINLOCK_H_

View File

@@ -1,35 +0,0 @@
// Copyright 2017 The Abseil Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// This file is an Akaros-specific part of spinlock_wait.cc
#include <atomic>
#include "absl/base/internal/scheduling_mode.h"
extern "C" {
ABSL_ATTRIBUTE_WEAK void ABSL_INTERNAL_C_SYMBOL(AbslInternalSpinLockDelay)(
std::atomic<uint32_t>* /* lock_word */, uint32_t /* value */,
int /* loop */, absl::base_internal::SchedulingMode /* mode */) {
// In Akaros, one must take care not to call anything that could cause a
// malloc(), a blocking system call, or a uthread_yield() while holding a
// spinlock. Our callers assume will not call into libraries or other
// arbitrary code.
}
ABSL_ATTRIBUTE_WEAK void ABSL_INTERNAL_C_SYMBOL(AbslInternalSpinLockWake)(
std::atomic<uint32_t>* /* lock_word */, bool /* all */) {}
} // extern "C"

View File

@@ -1,71 +0,0 @@
// Copyright 2018 The Abseil Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// This file is a Linux-specific part of spinlock_wait.cc
#include <linux/futex.h>
#include <sys/syscall.h>
#include <unistd.h>
#include <atomic>
#include <climits>
#include <cstdint>
#include <ctime>
#include "absl/base/attributes.h"
#include "absl/base/internal/errno_saver.h"
// The SpinLock lockword is `std::atomic<uint32_t>`. Here we assert that
// `std::atomic<uint32_t>` is bitwise equivalent of the `int` expected
// by SYS_futex. We also assume that reads/writes done to the lockword
// by SYS_futex have rational semantics with regard to the
// std::atomic<> API. C++ provides no guarantees of these assumptions,
// but they are believed to hold in practice.
static_assert(sizeof(std::atomic<uint32_t>) == sizeof(int),
"SpinLock lockword has the wrong size for a futex");
// Some Android headers are missing these definitions even though they
// support these futex operations.
#ifdef __BIONIC__
#ifndef SYS_futex
#define SYS_futex __NR_futex
#endif
#ifndef FUTEX_PRIVATE_FLAG
#define FUTEX_PRIVATE_FLAG 128
#endif
#endif
#if defined(__NR_futex_time64) && !defined(SYS_futex_time64)
#define SYS_futex_time64 __NR_futex_time64
#endif
#if defined(SYS_futex_time64) && !defined(SYS_futex)
#define SYS_futex SYS_futex_time64
#endif
extern "C" {
ABSL_ATTRIBUTE_WEAK void ABSL_INTERNAL_C_SYMBOL(AbslInternalSpinLockDelay)(
std::atomic<uint32_t> *w, uint32_t value, int,
absl::base_internal::SchedulingMode) {
absl::base_internal::ErrnoSaver errno_saver;
syscall(SYS_futex, w, FUTEX_WAIT | FUTEX_PRIVATE_FLAG, value, nullptr);
}
ABSL_ATTRIBUTE_WEAK void ABSL_INTERNAL_C_SYMBOL(AbslInternalSpinLockWake)(
std::atomic<uint32_t> *w, bool all) {
syscall(SYS_futex, w, FUTEX_WAKE | FUTEX_PRIVATE_FLAG, all ? INT_MAX : 1, 0);
}
} // extern "C"

View File

@@ -1,46 +0,0 @@
// Copyright 2017 The Abseil Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// This file is a Posix-specific part of spinlock_wait.cc
#include <sched.h>
#include <atomic>
#include <ctime>
#include "absl/base/internal/errno_saver.h"
#include "absl/base/internal/scheduling_mode.h"
#include "absl/base/port.h"
extern "C" {
ABSL_ATTRIBUTE_WEAK void ABSL_INTERNAL_C_SYMBOL(AbslInternalSpinLockDelay)(
std::atomic<uint32_t>* /* lock_word */, uint32_t /* value */, int loop,
absl::base_internal::SchedulingMode /* mode */) {
absl::base_internal::ErrnoSaver errno_saver;
if (loop == 0) {
} else if (loop == 1) {
sched_yield();
} else {
struct timespec tm;
tm.tv_sec = 0;
tm.tv_nsec = absl::base_internal::SpinLockSuggestedDelayNS(loop);
nanosleep(&tm, nullptr);
}
}
ABSL_ATTRIBUTE_WEAK void ABSL_INTERNAL_C_SYMBOL(AbslInternalSpinLockWake)(
std::atomic<uint32_t>* /* lock_word */, bool /* all */) {}
} // extern "C"

View File

@@ -1,95 +0,0 @@
// Copyright 2017 The Abseil Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef ABSL_BASE_INTERNAL_SPINLOCK_WAIT_H_
#define ABSL_BASE_INTERNAL_SPINLOCK_WAIT_H_
// Operations to make atomic transitions on a word, and to allow
// waiting for those transitions to become possible.
#include <stdint.h>
#include <atomic>
#include "absl/base/internal/scheduling_mode.h"
namespace absl {
ABSL_NAMESPACE_BEGIN
namespace base_internal {
// SpinLockWait() waits until it can perform one of several transitions from
// "from" to "to". It returns when it performs a transition where done==true.
struct SpinLockWaitTransition {
uint32_t from;
uint32_t to;
bool done;
};
// Wait until *w can transition from trans[i].from to trans[i].to for some i
// satisfying 0<=i<n && trans[i].done, atomically make the transition,
// then return the old value of *w. Make any other atomic transitions
// where !trans[i].done, but continue waiting.
//
// Wakeups for threads blocked on SpinLockWait do not respect priorities.
uint32_t SpinLockWait(std::atomic<uint32_t> *w, int n,
const SpinLockWaitTransition trans[],
SchedulingMode scheduling_mode);
// If possible, wake some thread that has called SpinLockDelay(w, ...). If `all`
// is true, wake all such threads. On some systems, this may be a no-op; on
// those systems, threads calling SpinLockDelay() will always wake eventually
// even if SpinLockWake() is never called.
void SpinLockWake(std::atomic<uint32_t> *w, bool all);
// Wait for an appropriate spin delay on iteration "loop" of a
// spin loop on location *w, whose previously observed value was "value".
// SpinLockDelay() may do nothing, may yield the CPU, may sleep a clock tick,
// or may wait for a call to SpinLockWake(w).
void SpinLockDelay(std::atomic<uint32_t> *w, uint32_t value, int loop,
base_internal::SchedulingMode scheduling_mode);
// Helper used by AbslInternalSpinLockDelay.
// Returns a suggested delay in nanoseconds for iteration number "loop".
int SpinLockSuggestedDelayNS(int loop);
} // namespace base_internal
ABSL_NAMESPACE_END
} // namespace absl
// In some build configurations we pass --detect-odr-violations to the
// gold linker. This causes it to flag weak symbol overrides as ODR
// violations. Because ODR only applies to C++ and not C,
// --detect-odr-violations ignores symbols not mangled with C++ names.
// By changing our extension points to be extern "C", we dodge this
// check.
extern "C" {
void ABSL_INTERNAL_C_SYMBOL(AbslInternalSpinLockWake)(std::atomic<uint32_t> *w,
bool all);
void ABSL_INTERNAL_C_SYMBOL(AbslInternalSpinLockDelay)(
std::atomic<uint32_t> *w, uint32_t value, int loop,
absl::base_internal::SchedulingMode scheduling_mode);
}
inline void absl::base_internal::SpinLockWake(std::atomic<uint32_t> *w,
bool all) {
ABSL_INTERNAL_C_SYMBOL(AbslInternalSpinLockWake)(w, all);
}
inline void absl::base_internal::SpinLockDelay(
std::atomic<uint32_t> *w, uint32_t value, int loop,
absl::base_internal::SchedulingMode scheduling_mode) {
ABSL_INTERNAL_C_SYMBOL(AbslInternalSpinLockDelay)
(w, value, loop, scheduling_mode);
}
#endif // ABSL_BASE_INTERNAL_SPINLOCK_WAIT_H_

View File

@@ -1,40 +0,0 @@
// Copyright 2017 The Abseil Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// This file is a Win32-specific part of spinlock_wait.cc
#include <windows.h>
#include <atomic>
#include "absl/base/internal/scheduling_mode.h"
extern "C" {
void ABSL_INTERNAL_C_SYMBOL(AbslInternalSpinLockDelay)(
std::atomic<uint32_t>* /* lock_word */, uint32_t /* value */, int loop,
absl::base_internal::SchedulingMode /* mode */) {
if (loop == 0) {
} else if (loop == 1) {
Sleep(0);
} else {
// SpinLockSuggestedDelayNS() always returns a positive integer, so this
// static_cast is safe.
Sleep(static_cast<DWORD>(
absl::base_internal::SpinLockSuggestedDelayNS(loop) / 1000000));
}
}
void ABSL_INTERNAL_C_SYMBOL(AbslInternalSpinLockWake)(
std::atomic<uint32_t>* /* lock_word */, bool /* all */) {}
} // extern "C"

View File

@@ -1,39 +0,0 @@
// Copyright 2020 The Abseil Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef ABSL_BASE_INTERNAL_STRERROR_H_
#define ABSL_BASE_INTERNAL_STRERROR_H_
#include <string>
#include "absl/base/config.h"
namespace absl {
ABSL_NAMESPACE_BEGIN
namespace base_internal {
// A portable and thread-safe alternative to C89's `strerror`.
//
// The C89 specification of `strerror` is not suitable for use in a
// multi-threaded application as the returned string may be changed by calls to
// `strerror` from another thread. The many non-stdlib alternatives differ
// enough in their names, availability, and semantics to justify this wrapper
// around them. `errno` will not be modified by a call to `absl::StrError`.
std::string StrError(int errnum);
} // namespace base_internal
ABSL_NAMESPACE_END
} // namespace absl
#endif // ABSL_BASE_INTERNAL_STRERROR_H_

View File

@@ -1,74 +0,0 @@
// Copyright 2017 The Abseil Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// This file includes routines to find out characteristics
// of the machine a program is running on. It is undoubtedly
// system-dependent.
// Functions listed here that accept a pid_t as an argument act on the
// current process if the pid_t argument is 0
// All functions here are thread-hostile due to file caching unless
// commented otherwise.
#ifndef ABSL_BASE_INTERNAL_SYSINFO_H_
#define ABSL_BASE_INTERNAL_SYSINFO_H_
#ifndef _WIN32
#include <sys/types.h>
#endif
#include <cstdint>
#include "absl/base/config.h"
#include "absl/base/port.h"
namespace absl {
ABSL_NAMESPACE_BEGIN
namespace base_internal {
// Nominal core processor cycles per second of each processor. This is _not_
// necessarily the frequency of the CycleClock counter (see cycleclock.h)
// Thread-safe.
double NominalCPUFrequency();
// Number of logical processors (hyperthreads) in system. Thread-safe.
int NumCPUs();
// Return the thread id of the current thread, as told by the system.
// No two currently-live threads implemented by the OS shall have the same ID.
// Thread ids of exited threads may be reused. Multiple user-level threads
// may have the same thread ID if multiplexed on the same OS thread.
//
// On Linux, you may send a signal to the resulting ID with kill(). However,
// it is recommended for portability that you use pthread_kill() instead.
#ifdef _WIN32
// On Windows, process id and thread id are of the same type according to the
// return types of GetProcessId() and GetThreadId() are both DWORD, an unsigned
// 32-bit type.
using pid_t = uint32_t;
#endif
pid_t GetTID();
// Like GetTID(), but caches the result in thread-local storage in order
// to avoid unnecessary system calls. Note that there are some cases where
// one must call through to GetTID directly, which is why this exists as a
// separate function. For example, GetCachedTID() is not safe to call in
// an asynchronous signal-handling context nor right after a call to fork().
pid_t GetCachedTID();
} // namespace base_internal
ABSL_NAMESPACE_END
} // namespace absl
#endif // ABSL_BASE_INTERNAL_SYSINFO_H_

View File

@@ -1,273 +0,0 @@
// Copyright 2017 The Abseil Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// Each active thread has an ThreadIdentity that may represent the thread in
// various level interfaces. ThreadIdentity objects are never deallocated.
// When a thread terminates, its ThreadIdentity object may be reused for a
// thread created later.
#ifndef ABSL_BASE_INTERNAL_THREAD_IDENTITY_H_
#define ABSL_BASE_INTERNAL_THREAD_IDENTITY_H_
#ifndef _WIN32
#include <pthread.h>
// Defines __GOOGLE_GRTE_VERSION__ (via glibc-specific features.h) when
// supported.
#include <unistd.h>
#endif
#include <atomic>
#include <cstdint>
#include "absl/base/config.h"
#include "absl/base/internal/per_thread_tls.h"
#include "absl/base/optimization.h"
namespace absl {
ABSL_NAMESPACE_BEGIN
struct SynchLocksHeld;
struct SynchWaitParams;
namespace base_internal {
class SpinLock;
struct ThreadIdentity;
// Used by the implementation of absl::Mutex and absl::CondVar.
struct PerThreadSynch {
// The internal representation of absl::Mutex and absl::CondVar rely
// on the alignment of PerThreadSynch. Both store the address of the
// PerThreadSynch in the high-order bits of their internal state,
// which means the low kLowZeroBits of the address of PerThreadSynch
// must be zero.
static constexpr int kLowZeroBits = 8;
static constexpr int kAlignment = 1 << kLowZeroBits;
// Returns the associated ThreadIdentity.
// This can be implemented as a cast because we guarantee
// PerThreadSynch is the first element of ThreadIdentity.
ThreadIdentity* thread_identity() {
return reinterpret_cast<ThreadIdentity*>(this);
}
PerThreadSynch* next; // Circular waiter queue; initialized to 0.
PerThreadSynch* skip; // If non-zero, all entries in Mutex queue
// up to and including "skip" have same
// condition as this, and will be woken later
bool may_skip; // if false while on mutex queue, a mutex unlocker
// is using this PerThreadSynch as a terminator. Its
// skip field must not be filled in because the loop
// might then skip over the terminator.
bool wake; // This thread is to be woken from a Mutex.
// If "x" is on a waiter list for a mutex, "x->cond_waiter" is true iff the
// waiter is waiting on the mutex as part of a CV Wait or Mutex Await.
//
// The value of "x->cond_waiter" is meaningless if "x" is not on a
// Mutex waiter list.
bool cond_waiter;
bool maybe_unlocking; // Valid at head of Mutex waiter queue;
// true if UnlockSlow could be searching
// for a waiter to wake. Used for an optimization
// in Enqueue(). true is always a valid value.
// Can be reset to false when the unlocker or any
// writer releases the lock, or a reader fully
// releases the lock. It may not be set to false
// by a reader that decrements the count to
// non-zero. protected by mutex spinlock
bool suppress_fatal_errors; // If true, try to proceed even in the face
// of broken invariants. This is used within
// fatal signal handlers to improve the
// chances of debug logging information being
// output successfully.
int priority; // Priority of thread (updated every so often).
// State values:
// kAvailable: This PerThreadSynch is available.
// kQueued: This PerThreadSynch is unavailable, it's currently queued on a
// Mutex or CondVar waistlist.
//
// Transitions from kQueued to kAvailable require a release
// barrier. This is needed as a waiter may use "state" to
// independently observe that it's no longer queued.
//
// Transitions from kAvailable to kQueued require no barrier, they
// are externally ordered by the Mutex.
enum State { kAvailable, kQueued };
std::atomic<State> state;
// The wait parameters of the current wait. waitp is null if the
// thread is not waiting. Transitions from null to non-null must
// occur before the enqueue commit point (state = kQueued in
// Enqueue() and CondVarEnqueue()). Transitions from non-null to
// null must occur after the wait is finished (state = kAvailable in
// Mutex::Block() and CondVar::WaitCommon()). This field may be
// changed only by the thread that describes this PerThreadSynch. A
// special case is Fer(), which calls Enqueue() on another thread,
// but with an identical SynchWaitParams pointer, thus leaving the
// pointer unchanged.
SynchWaitParams* waitp;
intptr_t readers; // Number of readers in mutex.
// When priority will next be read (cycles).
int64_t next_priority_read_cycles;
// Locks held; used during deadlock detection.
// Allocated in Synch_GetAllLocks() and freed in ReclaimThreadIdentity().
SynchLocksHeld* all_locks;
};
// The instances of this class are allocated in NewThreadIdentity() with an
// alignment of PerThreadSynch::kAlignment and never destroyed. Initialization
// should happen in OneTimeInitThreadIdentity().
//
// Instances may be reused by new threads - fields should be reset in
// ResetThreadIdentityBetweenReuse().
//
// NOTE: The layout of fields in this structure is critical, please do not
// add, remove, or modify the field placements without fully auditing the
// layout.
struct ThreadIdentity {
// Must be the first member. The Mutex implementation requires that
// the PerThreadSynch object associated with each thread is
// PerThreadSynch::kAlignment aligned. We provide this alignment on
// ThreadIdentity itself.
PerThreadSynch per_thread_synch;
// Private: Reserved for absl::synchronization_internal::Waiter.
struct WaiterState {
alignas(void*) char data[256];
} waiter_state;
// Used by PerThreadSem::{Get,Set}ThreadBlockedCounter().
std::atomic<int>* blocked_count_ptr;
// The following variables are mostly read/written just by the
// thread itself. The only exception is that these are read by
// a ticker thread as a hint.
std::atomic<int> ticker; // Tick counter, incremented once per second.
std::atomic<int> wait_start; // Ticker value when thread started waiting.
std::atomic<bool> is_idle; // Has thread become idle yet?
ThreadIdentity* next;
};
// Returns the ThreadIdentity object representing the calling thread; guaranteed
// to be unique for its lifetime. The returned object will remain valid for the
// program's lifetime; although it may be re-assigned to a subsequent thread.
// If one does not exist, return nullptr instead.
//
// Does not malloc(*), and is async-signal safe.
// [*] Technically pthread_setspecific() does malloc on first use; however this
// is handled internally within tcmalloc's initialization already. Note that
// darwin does *not* use tcmalloc, so this can catch you if using MallocHooks
// on Apple platforms. Whatever function is calling your MallocHooks will need
// to watch for recursion on Apple platforms.
//
// New ThreadIdentity objects can be constructed and associated with a thread
// by calling GetOrCreateCurrentThreadIdentity() in per-thread-sem.h.
ThreadIdentity* CurrentThreadIdentityIfPresent();
using ThreadIdentityReclaimerFunction = void (*)(void*);
// Sets the current thread identity to the given value. 'reclaimer' is a
// pointer to the global function for cleaning up instances on thread
// destruction.
void SetCurrentThreadIdentity(ThreadIdentity* identity,
ThreadIdentityReclaimerFunction reclaimer);
// Removes the currently associated ThreadIdentity from the running thread.
// This must be called from inside the ThreadIdentityReclaimerFunction, and only
// from that function.
void ClearCurrentThreadIdentity();
// May be chosen at compile time via: -DABSL_FORCE_THREAD_IDENTITY_MODE=<mode
// index>
#ifdef ABSL_THREAD_IDENTITY_MODE_USE_POSIX_SETSPECIFIC
#error ABSL_THREAD_IDENTITY_MODE_USE_POSIX_SETSPECIFIC cannot be directly set
#else
#define ABSL_THREAD_IDENTITY_MODE_USE_POSIX_SETSPECIFIC 0
#endif
#ifdef ABSL_THREAD_IDENTITY_MODE_USE_TLS
#error ABSL_THREAD_IDENTITY_MODE_USE_TLS cannot be directly set
#else
#define ABSL_THREAD_IDENTITY_MODE_USE_TLS 1
#endif
#ifdef ABSL_THREAD_IDENTITY_MODE_USE_CPP11
#error ABSL_THREAD_IDENTITY_MODE_USE_CPP11 cannot be directly set
#else
#define ABSL_THREAD_IDENTITY_MODE_USE_CPP11 2
#endif
#ifdef ABSL_THREAD_IDENTITY_MODE
#error ABSL_THREAD_IDENTITY_MODE cannot be directly set
#elif defined(ABSL_FORCE_THREAD_IDENTITY_MODE)
#define ABSL_THREAD_IDENTITY_MODE ABSL_FORCE_THREAD_IDENTITY_MODE
#elif defined(_WIN32) && !defined(__MINGW32__)
#define ABSL_THREAD_IDENTITY_MODE ABSL_THREAD_IDENTITY_MODE_USE_CPP11
#elif defined(__APPLE__) && defined(ABSL_HAVE_THREAD_LOCAL)
#define ABSL_THREAD_IDENTITY_MODE ABSL_THREAD_IDENTITY_MODE_USE_CPP11
#elif ABSL_PER_THREAD_TLS && defined(__GOOGLE_GRTE_VERSION__) && \
(__GOOGLE_GRTE_VERSION__ >= 20140228L)
// Support for async-safe TLS was specifically added in GRTEv4. It's not
// present in the upstream eglibc.
// Note: Current default for production systems.
#define ABSL_THREAD_IDENTITY_MODE ABSL_THREAD_IDENTITY_MODE_USE_TLS
#else
#define ABSL_THREAD_IDENTITY_MODE \
ABSL_THREAD_IDENTITY_MODE_USE_POSIX_SETSPECIFIC
#endif
#if ABSL_THREAD_IDENTITY_MODE == ABSL_THREAD_IDENTITY_MODE_USE_TLS || \
ABSL_THREAD_IDENTITY_MODE == ABSL_THREAD_IDENTITY_MODE_USE_CPP11
#if ABSL_PER_THREAD_TLS
ABSL_CONST_INIT extern ABSL_PER_THREAD_TLS_KEYWORD ThreadIdentity*
thread_identity_ptr;
#elif defined(ABSL_HAVE_THREAD_LOCAL)
ABSL_CONST_INIT extern thread_local ThreadIdentity* thread_identity_ptr;
#else
#error Thread-local storage not detected on this platform
#endif
// thread_local variables cannot be in headers exposed by DLLs or in certain
// build configurations on Apple platforms. However, it is important for
// performance reasons in general that `CurrentThreadIdentityIfPresent` be
// inlined. In the other cases we opt to have the function not be inlined. Note
// that `CurrentThreadIdentityIfPresent` is declared above so we can exclude
// this entire inline definition.
#if !defined(__APPLE__) && !defined(ABSL_BUILD_DLL) && \
!defined(ABSL_CONSUME_DLL)
#define ABSL_INTERNAL_INLINE_CURRENT_THREAD_IDENTITY_IF_PRESENT 1
#endif
#ifdef ABSL_INTERNAL_INLINE_CURRENT_THREAD_IDENTITY_IF_PRESENT
inline ThreadIdentity* CurrentThreadIdentityIfPresent() {
return thread_identity_ptr;
}
#endif
#elif ABSL_THREAD_IDENTITY_MODE != \
ABSL_THREAD_IDENTITY_MODE_USE_POSIX_SETSPECIFIC
#error Unknown ABSL_THREAD_IDENTITY_MODE
#endif
} // namespace base_internal
ABSL_NAMESPACE_END
} // namespace absl
#endif // ABSL_BASE_INTERNAL_THREAD_IDENTITY_H_

View File

@@ -1,75 +0,0 @@
//
// Copyright 2017 The Abseil Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
#ifndef ABSL_BASE_INTERNAL_THROW_DELEGATE_H_
#define ABSL_BASE_INTERNAL_THROW_DELEGATE_H_
#include <string>
#include "absl/base/config.h"
namespace absl {
ABSL_NAMESPACE_BEGIN
namespace base_internal {
// Helper functions that allow throwing exceptions consistently from anywhere.
// The main use case is for header-based libraries (eg templates), as they will
// be built by many different targets with their own compiler options.
// In particular, this will allow a safe way to throw exceptions even if the
// caller is compiled with -fno-exceptions. This is intended for implementing
// things like map<>::at(), which the standard documents as throwing an
// exception on error.
//
// Using other techniques like #if tricks could lead to ODR violations.
//
// You shouldn't use it unless you're writing code that you know will be built
// both with and without exceptions and you need to conform to an interface
// that uses exceptions.
[[noreturn]] void ThrowStdLogicError(const std::string& what_arg);
[[noreturn]] void ThrowStdLogicError(const char* what_arg);
[[noreturn]] void ThrowStdInvalidArgument(const std::string& what_arg);
[[noreturn]] void ThrowStdInvalidArgument(const char* what_arg);
[[noreturn]] void ThrowStdDomainError(const std::string& what_arg);
[[noreturn]] void ThrowStdDomainError(const char* what_arg);
[[noreturn]] void ThrowStdLengthError(const std::string& what_arg);
[[noreturn]] void ThrowStdLengthError(const char* what_arg);
[[noreturn]] void ThrowStdOutOfRange(const std::string& what_arg);
[[noreturn]] void ThrowStdOutOfRange(const char* what_arg);
[[noreturn]] void ThrowStdRuntimeError(const std::string& what_arg);
[[noreturn]] void ThrowStdRuntimeError(const char* what_arg);
[[noreturn]] void ThrowStdRangeError(const std::string& what_arg);
[[noreturn]] void ThrowStdRangeError(const char* what_arg);
[[noreturn]] void ThrowStdOverflowError(const std::string& what_arg);
[[noreturn]] void ThrowStdOverflowError(const char* what_arg);
[[noreturn]] void ThrowStdUnderflowError(const std::string& what_arg);
[[noreturn]] void ThrowStdUnderflowError(const char* what_arg);
[[noreturn]] void ThrowStdBadFunctionCall();
[[noreturn]] void ThrowStdBadAlloc();
// ThrowStdBadArrayNewLength() cannot be consistently supported because
// std::bad_array_new_length is missing in libstdc++ until 4.9.0.
// https://gcc.gnu.org/onlinedocs/gcc-4.8.3/libstdc++/api/a01379_source.html
// https://gcc.gnu.org/onlinedocs/gcc-4.9.0/libstdc++/api/a01327_source.html
// libcxx (as of 3.2) and msvc (as of 2015) both have it.
// [[noreturn]] void ThrowStdBadArrayNewLength();
} // namespace base_internal
ABSL_NAMESPACE_END
} // namespace absl
#endif // ABSL_BASE_INTERNAL_THROW_DELEGATE_H_

View File

@@ -1,81 +0,0 @@
// Copyright 2024 The Abseil Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef ABSL_BASE_INTERNAL_TRACING_H_
#define ABSL_BASE_INTERNAL_TRACING_H_
#include "absl/base/config.h"
namespace absl {
ABSL_NAMESPACE_BEGIN
namespace base_internal {
// Well known Abseil object types that have causality.
enum class ObjectKind { kUnknown, kBlockingCounter, kNotification };
// `TraceWait` and `TraceContinue` record the start and end of a potentially
// blocking wait operation on `object`. `object` typically represents a higher
// level synchronization object such as `absl::Notification`.
void TraceWait(const void* object, ObjectKind kind);
void TraceContinue(const void* object, ObjectKind kind);
// `TraceSignal` records a signal on `object`.
void TraceSignal(const void* object, ObjectKind kind);
// `TraceObserved` records the non-blocking observation of a signaled object.
void TraceObserved(const void* object, ObjectKind kind);
// ---------------------------------------------------------------------------
// Weak implementation detail:
//
// We define the weak API as extern "C": in some build configurations we pass
// `--detect-odr-violations` to the gold linker. This causes it to flag weak
// symbol overrides as ODR violations. Because ODR only applies to C++ and not
// C, `--detect-odr-violations` ignores symbols not mangled with C++ names.
// By changing our extension points to be extern "C", we dodge this check.
// ---------------------------------------------------------------------------
extern "C" {
void ABSL_INTERNAL_C_SYMBOL(AbslInternalTraceWait)(const void* object,
ObjectKind kind);
void ABSL_INTERNAL_C_SYMBOL(AbslInternalTraceContinue)(const void* object,
ObjectKind kind);
void ABSL_INTERNAL_C_SYMBOL(AbslInternalTraceSignal)(const void* object,
ObjectKind kind);
void ABSL_INTERNAL_C_SYMBOL(AbslInternalTraceObserved)(const void* object,
ObjectKind kind);
} // extern "C"
inline void TraceWait(const void* object, ObjectKind kind) {
ABSL_INTERNAL_C_SYMBOL(AbslInternalTraceWait)(object, kind);
}
inline void TraceContinue(const void* object, ObjectKind kind) {
ABSL_INTERNAL_C_SYMBOL(AbslInternalTraceContinue)(object, kind);
}
inline void TraceSignal(const void* object, ObjectKind kind) {
ABSL_INTERNAL_C_SYMBOL(AbslInternalTraceSignal)(object, kind);
}
inline void TraceObserved(const void* object, ObjectKind kind) {
ABSL_INTERNAL_C_SYMBOL(AbslInternalTraceObserved)(object, kind);
}
} // namespace base_internal
ABSL_NAMESPACE_END
} // namespace absl
#endif // ABSL_BASE_INTERNAL_TRACING_H_

View File

@@ -1,68 +0,0 @@
// Copyright 2017 The Abseil Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// This file is intended solely for spinlock.h.
// It provides ThreadSanitizer annotations for custom mutexes.
// See <sanitizer/tsan_interface.h> for meaning of these annotations.
#ifndef ABSL_BASE_INTERNAL_TSAN_MUTEX_INTERFACE_H_
#define ABSL_BASE_INTERNAL_TSAN_MUTEX_INTERFACE_H_
#include "absl/base/config.h"
// ABSL_INTERNAL_HAVE_TSAN_INTERFACE
// Macro intended only for internal use.
//
// Checks whether LLVM Thread Sanitizer interfaces are available.
// First made available in LLVM 5.0 (Sep 2017).
#ifdef ABSL_INTERNAL_HAVE_TSAN_INTERFACE
#error "ABSL_INTERNAL_HAVE_TSAN_INTERFACE cannot be directly set."
#endif
#if defined(ABSL_HAVE_THREAD_SANITIZER) && defined(__has_include)
#if __has_include(<sanitizer/tsan_interface.h>)
#define ABSL_INTERNAL_HAVE_TSAN_INTERFACE 1
#endif
#endif
#ifdef ABSL_INTERNAL_HAVE_TSAN_INTERFACE
#include <sanitizer/tsan_interface.h>
#define ABSL_TSAN_MUTEX_CREATE __tsan_mutex_create
#define ABSL_TSAN_MUTEX_DESTROY __tsan_mutex_destroy
#define ABSL_TSAN_MUTEX_PRE_LOCK __tsan_mutex_pre_lock
#define ABSL_TSAN_MUTEX_POST_LOCK __tsan_mutex_post_lock
#define ABSL_TSAN_MUTEX_PRE_UNLOCK __tsan_mutex_pre_unlock
#define ABSL_TSAN_MUTEX_POST_UNLOCK __tsan_mutex_post_unlock
#define ABSL_TSAN_MUTEX_PRE_SIGNAL __tsan_mutex_pre_signal
#define ABSL_TSAN_MUTEX_POST_SIGNAL __tsan_mutex_post_signal
#define ABSL_TSAN_MUTEX_PRE_DIVERT __tsan_mutex_pre_divert
#define ABSL_TSAN_MUTEX_POST_DIVERT __tsan_mutex_post_divert
#else
#define ABSL_TSAN_MUTEX_CREATE(...)
#define ABSL_TSAN_MUTEX_DESTROY(...)
#define ABSL_TSAN_MUTEX_PRE_LOCK(...)
#define ABSL_TSAN_MUTEX_POST_LOCK(...)
#define ABSL_TSAN_MUTEX_PRE_UNLOCK(...)
#define ABSL_TSAN_MUTEX_POST_UNLOCK(...)
#define ABSL_TSAN_MUTEX_PRE_SIGNAL(...)
#define ABSL_TSAN_MUTEX_POST_SIGNAL(...)
#define ABSL_TSAN_MUTEX_PRE_DIVERT(...)
#define ABSL_TSAN_MUTEX_POST_DIVERT(...)
#endif
#endif // ABSL_BASE_INTERNAL_TSAN_MUTEX_INTERFACE_H_

View File

@@ -1,89 +0,0 @@
//
// Copyright 2017 The Abseil Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
#ifndef ABSL_BASE_INTERNAL_UNALIGNED_ACCESS_H_
#define ABSL_BASE_INTERNAL_UNALIGNED_ACCESS_H_
#include <string.h>
#include <cstdint>
#include "absl/base/attributes.h"
#include "absl/base/config.h"
#include "absl/base/nullability.h"
// unaligned APIs
// Portable handling of unaligned loads, stores, and copies.
// The unaligned API is C++ only. The declarations use C++ features
// (namespaces, inline) which are absent or incompatible in C.
#if defined(__cplusplus)
namespace absl {
ABSL_NAMESPACE_BEGIN
namespace base_internal {
inline uint16_t UnalignedLoad16(const void* absl_nonnull p) {
uint16_t t;
memcpy(&t, p, sizeof t);
return t;
}
inline uint32_t UnalignedLoad32(const void* absl_nonnull p) {
uint32_t t;
memcpy(&t, p, sizeof t);
return t;
}
inline uint64_t UnalignedLoad64(const void* absl_nonnull p) {
uint64_t t;
memcpy(&t, p, sizeof t);
return t;
}
inline void UnalignedStore16(void* absl_nonnull p, uint16_t v) {
memcpy(p, &v, sizeof v);
}
inline void UnalignedStore32(void* absl_nonnull p, uint32_t v) {
memcpy(p, &v, sizeof v);
}
inline void UnalignedStore64(void* absl_nonnull p, uint64_t v) {
memcpy(p, &v, sizeof v);
}
} // namespace base_internal
ABSL_NAMESPACE_END
} // namespace absl
#define ABSL_INTERNAL_UNALIGNED_LOAD16(_p) \
(absl::base_internal::UnalignedLoad16(_p))
#define ABSL_INTERNAL_UNALIGNED_LOAD32(_p) \
(absl::base_internal::UnalignedLoad32(_p))
#define ABSL_INTERNAL_UNALIGNED_LOAD64(_p) \
(absl::base_internal::UnalignedLoad64(_p))
#define ABSL_INTERNAL_UNALIGNED_STORE16(_p, _val) \
(absl::base_internal::UnalignedStore16(_p, _val))
#define ABSL_INTERNAL_UNALIGNED_STORE32(_p, _val) \
(absl::base_internal::UnalignedStore32(_p, _val))
#define ABSL_INTERNAL_UNALIGNED_STORE64(_p, _val) \
(absl::base_internal::UnalignedStore64(_p, _val))
#endif // defined(__cplusplus), end of unaligned API
#endif // ABSL_BASE_INTERNAL_UNALIGNED_ACCESS_H_

View File

@@ -1,113 +0,0 @@
// Copyright 2017 The Abseil Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// UnscaledCycleClock
// An UnscaledCycleClock yields the value and frequency of a cycle counter
// that increments at a rate that is approximately constant.
// This class is for internal use only, you should consider using CycleClock
// instead.
//
// Notes:
// The cycle counter frequency is not necessarily the core clock frequency.
// That is, CycleCounter cycles are not necessarily "CPU cycles".
//
// An arbitrary offset may have been added to the counter at power on.
//
// On some platforms, the rate and offset of the counter may differ
// slightly when read from different CPUs of a multiprocessor. Usually,
// we try to ensure that the operating system adjusts values periodically
// so that values agree approximately. If you need stronger guarantees,
// consider using alternate interfaces.
//
// The CPU is not required to maintain the ordering of a cycle counter read
// with respect to surrounding instructions.
#ifndef ABSL_BASE_INTERNAL_UNSCALEDCYCLECLOCK_H_
#define ABSL_BASE_INTERNAL_UNSCALEDCYCLECLOCK_H_
#include <cstdint>
#if defined(__APPLE__)
#include <TargetConditionals.h>
#endif
#include "absl/base/config.h"
#include "absl/base/internal/unscaledcycleclock_config.h"
#if ABSL_USE_UNSCALED_CYCLECLOCK
namespace absl {
ABSL_NAMESPACE_BEGIN
namespace time_internal {
class UnscaledCycleClockWrapperForGetCurrentTime;
} // namespace time_internal
namespace base_internal {
class CycleClock;
class UnscaledCycleClockWrapperForInitializeFrequency;
class UnscaledCycleClock {
private:
UnscaledCycleClock() = delete;
// Return the value of a cycle counter that counts at a rate that is
// approximately constant.
static int64_t Now();
// Return the how much UnscaledCycleClock::Now() increases per second.
// This is not necessarily the core CPU clock frequency.
// It may be the nominal value report by the kernel, rather than a measured
// value.
static double Frequency();
// Allowed users
friend class base_internal::CycleClock;
friend class time_internal::UnscaledCycleClockWrapperForGetCurrentTime;
friend class base_internal::UnscaledCycleClockWrapperForInitializeFrequency;
};
#if defined(__x86_64__)
inline int64_t UnscaledCycleClock::Now() {
uint64_t low, high;
__asm__ volatile("rdtsc" : "=a"(low), "=d"(high));
return static_cast<int64_t>((high << 32) | low);
}
#elif defined(__aarch64__)
// System timer of ARMv8 runs at a different frequency than the CPU's.
//
// Frequency is fixed. From Armv8.6-A and Armv9.1-A on, the frequency is 1GHz.
// Pre-Armv8.6-A, the frequency was a system design choice, typically in the
// range of 1MHz to 50MHz. See also:
// https://developer.arm.com/documentation/102379/0101/What-is-the-Generic-Timer-
//
// It can be read at CNTFRQ special register. We assume the OS has set up the
// virtual timer properly.
inline int64_t UnscaledCycleClock::Now() {
int64_t virtual_timer_value;
asm volatile("mrs %0, cntvct_el0" : "=r"(virtual_timer_value));
return virtual_timer_value;
}
#endif
} // namespace base_internal
ABSL_NAMESPACE_END
} // namespace absl
#endif // ABSL_USE_UNSCALED_CYCLECLOCK
#endif // ABSL_BASE_INTERNAL_UNSCALEDCYCLECLOCK_H_

View File

@@ -1,62 +0,0 @@
// Copyright 2022 The Abseil Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef ABSL_BASE_INTERNAL_UNSCALEDCYCLECLOCK_CONFIG_H_
#define ABSL_BASE_INTERNAL_UNSCALEDCYCLECLOCK_CONFIG_H_
#if defined(__APPLE__)
#include <TargetConditionals.h>
#endif
// The following platforms have an implementation of a hardware counter.
#if defined(__i386__) || defined(__x86_64__) || defined(__aarch64__) || \
defined(__powerpc__) || defined(__ppc__) || defined(_M_IX86) || \
(defined(_M_X64) && !defined(_M_ARM64EC))
#define ABSL_HAVE_UNSCALED_CYCLECLOCK_IMPLEMENTATION 1
#else
#define ABSL_HAVE_UNSCALED_CYCLECLOCK_IMPLEMENTATION 0
#endif
// The following platforms often disable access to the hardware
// counter (through a sandbox) even if the underlying hardware has a
// usable counter. The CycleTimer interface also requires a *scaled*
// CycleClock that runs at atleast 1 MHz. We've found some Android
// ARM64 devices where this is not the case, so we disable it by
// default on Android ARM64.
#if defined(__APPLE__) || \
(defined(__ANDROID__) && defined(__aarch64__))
#define ABSL_USE_UNSCALED_CYCLECLOCK_DEFAULT 0
#else
#define ABSL_USE_UNSCALED_CYCLECLOCK_DEFAULT 1
#endif
// UnscaledCycleClock is an optional internal feature.
// Use "#if ABSL_USE_UNSCALED_CYCLECLOCK" to test for its presence.
// Can be overridden at compile-time via -DABSL_USE_UNSCALED_CYCLECLOCK=0|1
#if !defined(ABSL_USE_UNSCALED_CYCLECLOCK)
#define ABSL_USE_UNSCALED_CYCLECLOCK \
(ABSL_HAVE_UNSCALED_CYCLECLOCK_IMPLEMENTATION && \
ABSL_USE_UNSCALED_CYCLECLOCK_DEFAULT)
#endif
#if ABSL_USE_UNSCALED_CYCLECLOCK
// This macro can be used to test if UnscaledCycleClock::Frequency()
// is NominalCPUFrequency() on a particular platform.
#if (defined(__i386__) || defined(__x86_64__) || defined(_M_IX86) || \
defined(_M_X64))
#define ABSL_INTERNAL_UNSCALED_CYCLECLOCK_FREQUENCY_IS_CPU_FREQUENCY
#endif
#endif
#endif // ABSL_BASE_INTERNAL_UNSCALEDCYCLECLOCK_CONFIG_H_

View File

@@ -1,185 +0,0 @@
// Copyright 2017 The Abseil Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef ABSL_BASE_LOG_SEVERITY_H_
#define ABSL_BASE_LOG_SEVERITY_H_
#include <array>
#include <ostream>
#include "absl/base/attributes.h"
#include "absl/base/config.h"
namespace absl {
ABSL_NAMESPACE_BEGIN
// absl::LogSeverity
//
// Four severity levels are defined. Logging APIs should terminate the program
// when a message is logged at severity `kFatal`; the other levels have no
// special semantics.
//
// Values other than the four defined levels (e.g. produced by `static_cast`)
// are valid, but their semantics when passed to a function, macro, or flag
// depend on the function, macro, or flag. The usual behavior is to normalize
// such values to a defined severity level, however in some cases values other
// than the defined levels are useful for comparison.
//
// Example:
//
// // Effectively disables all logging:
// SetMinLogLevel(static_cast<absl::LogSeverity>(100));
//
// Abseil flags may be defined with type `LogSeverity`. Dependency layering
// constraints require that the `AbslParseFlag()` overload be declared and
// defined in the flags library itself rather than here. The `AbslUnparseFlag()`
// overload is defined there as well for consistency.
//
// absl::LogSeverity Flag String Representation
//
// An `absl::LogSeverity` has a string representation used for parsing
// command-line flags based on the enumerator name (e.g. `kFatal`) or
// its unprefixed name (without the `k`) in any case-insensitive form. (E.g.
// "FATAL", "fatal" or "Fatal" are all valid.) Unparsing such flags produces an
// unprefixed string representation in all caps (e.g. "FATAL") or an integer.
//
// Additionally, the parser accepts arbitrary integers (as if the type were
// `int`).
//
// Examples:
//
// --my_log_level=kInfo
// --my_log_level=INFO
// --my_log_level=info
// --my_log_level=0
//
// `DFATAL` and `kLogDebugFatal` are similarly accepted.
//
// Unparsing a flag produces the same result as `absl::LogSeverityName()` for
// the standard levels and a base-ten integer otherwise.
enum class LogSeverity : int {
kInfo = 0,
kWarning = 1,
kError = 2,
kFatal = 3,
};
// LogSeverities()
//
// Returns an iterable of all standard `absl::LogSeverity` values, ordered from
// least to most severe.
constexpr std::array<absl::LogSeverity, 4> LogSeverities() {
return {{absl::LogSeverity::kInfo, absl::LogSeverity::kWarning,
absl::LogSeverity::kError, absl::LogSeverity::kFatal}};
}
// `absl::kLogDebugFatal` equals `absl::LogSeverity::kFatal` in debug builds
// (i.e. when `NDEBUG` is not defined) and `absl::LogSeverity::kError`
// otherwise. Avoid ODR-using this variable as it has internal linkage and thus
// distinct storage in different TUs.
#ifdef NDEBUG
static constexpr absl::LogSeverity kLogDebugFatal = absl::LogSeverity::kError;
#else
static constexpr absl::LogSeverity kLogDebugFatal = absl::LogSeverity::kFatal;
#endif
// LogSeverityName()
//
// Returns the all-caps string representation (e.g. "INFO") of the specified
// severity level if it is one of the standard levels and "UNKNOWN" otherwise.
constexpr const char* LogSeverityName(absl::LogSeverity s) {
switch (s) {
case absl::LogSeverity::kInfo: return "INFO";
case absl::LogSeverity::kWarning: return "WARNING";
case absl::LogSeverity::kError: return "ERROR";
case absl::LogSeverity::kFatal: return "FATAL";
}
return "UNKNOWN";
}
// NormalizeLogSeverity()
//
// Values less than `kInfo` normalize to `kInfo`; values greater than `kFatal`
// normalize to `kError` (**NOT** `kFatal`).
constexpr absl::LogSeverity NormalizeLogSeverity(absl::LogSeverity s) {
absl::LogSeverity n = s;
if (n < absl::LogSeverity::kInfo) n = absl::LogSeverity::kInfo;
if (n > absl::LogSeverity::kFatal) n = absl::LogSeverity::kError;
return n;
}
constexpr absl::LogSeverity NormalizeLogSeverity(int s) {
return absl::NormalizeLogSeverity(static_cast<absl::LogSeverity>(s));
}
// operator<<
//
// The exact representation of a streamed `absl::LogSeverity` is deliberately
// unspecified; do not rely on it.
std::ostream& operator<<(std::ostream& os, absl::LogSeverity s);
// Enums representing a lower bound for LogSeverity. APIs that only operate on
// messages of at least a certain level (for example, `SetMinLogLevel()`) use
// this type to specify that level. absl::LogSeverityAtLeast::kInfinity is
// a level above all threshold levels and therefore no log message will
// ever meet this threshold.
enum class LogSeverityAtLeast : int {
kInfo = static_cast<int>(absl::LogSeverity::kInfo),
kWarning = static_cast<int>(absl::LogSeverity::kWarning),
kError = static_cast<int>(absl::LogSeverity::kError),
kFatal = static_cast<int>(absl::LogSeverity::kFatal),
kInfinity = 1000,
};
std::ostream& operator<<(std::ostream& os, absl::LogSeverityAtLeast s);
// Enums representing an upper bound for LogSeverity. APIs that only operate on
// messages of at most a certain level (for example, buffer all messages at or
// below a certain level) use this type to specify that level.
// absl::LogSeverityAtMost::kNegativeInfinity is a level below all threshold
// levels and therefore will exclude all log messages.
enum class LogSeverityAtMost : int {
kNegativeInfinity = -1000,
kInfo = static_cast<int>(absl::LogSeverity::kInfo),
kWarning = static_cast<int>(absl::LogSeverity::kWarning),
kError = static_cast<int>(absl::LogSeverity::kError),
kFatal = static_cast<int>(absl::LogSeverity::kFatal),
};
std::ostream& operator<<(std::ostream& os, absl::LogSeverityAtMost s);
#define COMPOP(op1, op2, T) \
constexpr bool operator op1(absl::T lhs, absl::LogSeverity rhs) { \
return static_cast<absl::LogSeverity>(lhs) op1 rhs; \
} \
constexpr bool operator op2(absl::LogSeverity lhs, absl::T rhs) { \
return lhs op2 static_cast<absl::LogSeverity>(rhs); \
}
// Comparisons between `LogSeverity` and `LogSeverityAtLeast`/
// `LogSeverityAtMost` are only supported in one direction.
// Valid checks are:
// LogSeverity >= LogSeverityAtLeast
// LogSeverity < LogSeverityAtLeast
// LogSeverity <= LogSeverityAtMost
// LogSeverity > LogSeverityAtMost
COMPOP(>, <, LogSeverityAtLeast)
COMPOP(<=, >=, LogSeverityAtLeast)
COMPOP(<, >, LogSeverityAtMost)
COMPOP(>=, <=, LogSeverityAtMost)
#undef COMPOP
ABSL_NAMESPACE_END
} // namespace absl
#endif // ABSL_BASE_LOG_SEVERITY_H_

View File

@@ -1,220 +0,0 @@
//
// Copyright 2017 The Abseil Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// -----------------------------------------------------------------------------
// File: macros.h
// -----------------------------------------------------------------------------
//
// This header file defines the set of language macros used within Abseil code.
// For the set of macros used to determine supported compilers and platforms,
// see absl/base/config.h instead.
//
// This code is compiled directly on many platforms, including client
// platforms like Windows, Mac, and embedded systems. Before making
// any changes here, make sure that you're not breaking any platforms.
#ifndef ABSL_BASE_MACROS_H_
#define ABSL_BASE_MACROS_H_
#include <cassert>
#include <cstddef>
#include "absl/base/attributes.h"
#include "absl/base/config.h"
#include "absl/base/optimization.h"
#include "absl/base/options.h"
#include "absl/base/port.h"
// ABSL_ARRAYSIZE()
//
// Returns the number of elements in an array as a compile-time constant, which
// can be used in defining new arrays. If you use this macro on a pointer by
// mistake, you will get a compile-time error.
#define ABSL_ARRAYSIZE(array) \
(sizeof(::absl::macros_internal::ArraySizeHelper(array)))
namespace absl {
ABSL_NAMESPACE_BEGIN
namespace macros_internal {
// Note: this internal template function declaration is used by ABSL_ARRAYSIZE.
// The function doesn't need a definition, as we only use its type.
template <typename T, size_t N>
auto ArraySizeHelper(const T (&array)[N]) -> char (&)[N];
} // namespace macros_internal
ABSL_NAMESPACE_END
} // namespace absl
// ABSL_BAD_CALL_IF()
//
// Used on a function overload to trap bad calls: any call that matches the
// overload will cause a compile-time error. This macro uses a clang-specific
// "enable_if" attribute, as described at
// https://clang.llvm.org/docs/AttributeReference.html#enable-if
//
// Overloads which use this macro should be bracketed by
// `#ifdef ABSL_BAD_CALL_IF`.
//
// Example:
//
// int isdigit(int c);
// #ifdef ABSL_BAD_CALL_IF
// int isdigit(int c)
// ABSL_BAD_CALL_IF(c <= -1 || c > 255,
// "'c' must have the value of an unsigned char or EOF");
// #endif // ABSL_BAD_CALL_IF
#if ABSL_HAVE_ATTRIBUTE(enable_if)
#define ABSL_BAD_CALL_IF(expr, msg) \
__attribute__((enable_if(expr, "Bad call trap"), unavailable(msg)))
#endif
// ABSL_ASSERT()
//
// In C++11, `assert` can't be used portably within constexpr functions.
// `assert` also generates spurious unused-symbol warnings.
// ABSL_ASSERT functions as a runtime assert but works in C++11 constexpr
// functions, and maintains references to symbols. Example:
//
// constexpr double Divide(double a, double b) {
// return ABSL_ASSERT(b != 0), a / b;
// }
//
// This macro is inspired by
// https://akrzemi1.wordpress.com/2017/05/18/asserts-in-constexpr-functions/
#if defined(NDEBUG)
#if ABSL_INTERNAL_CPLUSPLUS_LANG >= 202002L
// We use `decltype` here to avoid generating unnecessary code that the
// optimizer then has to optimize away.
// This not only improves compilation performance by reducing codegen bloat
// and optimization work, but also guarantees fast run-time performance without
// having to rely on the optimizer.
#define ABSL_ASSERT(expr) (decltype((expr) ? void() : void())())
#else
// Pre-C++20, lambdas can't be inside unevaluated operands, so we're forced to
// rely on the optimizer.
#define ABSL_ASSERT(expr) (false ? ((expr) ? void() : void()) : void())
#endif
#else
#define ABSL_ASSERT(expr) \
(ABSL_PREDICT_TRUE((expr)) ? static_cast<void>(0) \
: [] { assert(false && #expr); }()) // NOLINT
#endif
// `ABSL_INTERNAL_HARDENING_ABORT()` controls how `ABSL_HARDENING_ASSERT()`
// aborts the program in release mode (when NDEBUG is defined). The
// implementation should abort the program as quickly as possible and ideally it
// should not be possible to ignore the abort request.
#define ABSL_INTERNAL_HARDENING_ABORT() \
do { \
ABSL_INTERNAL_IMMEDIATE_ABORT_IMPL(); \
ABSL_INTERNAL_UNREACHABLE_IMPL(); \
} while (false)
// ABSL_HARDENING_ASSERT()
//
// `ABSL_HARDENING_ASSERT()` is like `ABSL_ASSERT()`, but used to implement
// runtime assertions that should be enabled in hardened builds even when
// `NDEBUG` is defined.
//
// When `NDEBUG` is not defined, `ABSL_HARDENING_ASSERT()` is identical to
// `ABSL_ASSERT()`.
//
// See `ABSL_OPTION_HARDENED` in `absl/base/options.h` for more information on
// hardened mode.
#if (ABSL_OPTION_HARDENED == 1 || ABSL_OPTION_HARDENED == 2) && defined(NDEBUG)
#define ABSL_HARDENING_ASSERT(expr) \
(ABSL_PREDICT_TRUE((expr)) ? static_cast<void>(0) \
: [] { ABSL_INTERNAL_HARDENING_ABORT(); }())
#else
#define ABSL_HARDENING_ASSERT(expr) ABSL_ASSERT(expr)
#endif
// ABSL_HARDENING_ASSERT_SLOW()
//
// `ABSL_HARDENING_ASSERT()` is like `ABSL_HARDENING_ASSERT()`,
// but specifically for assertions whose predicates are too slow
// to be enabled in many applications.
//
// When `NDEBUG` is not defined, `ABSL_HARDENING_ASSERT_SLOW()` is identical to
// `ABSL_ASSERT()`.
//
// See `ABSL_OPTION_HARDENED` in `absl/base/options.h` for more information on
// hardened mode.
#if ABSL_OPTION_HARDENED == 1 && defined(NDEBUG)
#define ABSL_HARDENING_ASSERT_SLOW(expr) \
(ABSL_PREDICT_TRUE((expr)) ? static_cast<void>(0) \
: [] { ABSL_INTERNAL_HARDENING_ABORT(); }())
#else
#define ABSL_HARDENING_ASSERT_SLOW(expr) ABSL_ASSERT(expr)
#endif
#ifdef ABSL_HAVE_EXCEPTIONS
#define ABSL_INTERNAL_TRY try
#define ABSL_INTERNAL_CATCH_ANY catch (...)
#define ABSL_INTERNAL_RETHROW do { throw; } while (false)
#else // ABSL_HAVE_EXCEPTIONS
#define ABSL_INTERNAL_TRY if (true)
#define ABSL_INTERNAL_CATCH_ANY else if (false)
#define ABSL_INTERNAL_RETHROW do {} while (false)
#endif // ABSL_HAVE_EXCEPTIONS
// ABSL_DEPRECATE_AND_INLINE()
//
// Marks a function or type alias as deprecated and tags it to be picked up for
// automated refactoring by go/cpp-inliner. It can added to inline function
// definitions or type aliases. It should only be used within a header file. It
// differs from `ABSL_DEPRECATED` in the following ways:
//
// 1. New uses of the function or type will be discouraged via Tricorder
// warnings.
// 2. If enabled via `METADATA`, automated changes will be sent out inlining the
// functions's body or replacing the type where it is used.
//
// For example:
//
// ABSL_DEPRECATE_AND_INLINE() inline int OldFunc(int x) {
// return NewFunc(x, 0);
// }
//
// will mark `OldFunc` as deprecated, and the go/cpp-inliner service will
// replace calls to `OldFunc(x)` with calls to `NewFunc(x, 0)`. Once all calls
// to `OldFunc` have been replaced, `OldFunc` can be deleted.
//
// See go/cpp-inliner for more information.
//
// Note: go/cpp-inliner is Google-internal service for automated refactoring.
// While open-source users do not have access to this service, the macro is
// provided for compatibility, and so that users receive deprecation warnings.
#if ABSL_HAVE_CPP_ATTRIBUTE(deprecated) && \
ABSL_HAVE_CPP_ATTRIBUTE(clang::annotate)
#define ABSL_DEPRECATE_AND_INLINE() [[deprecated, clang::annotate("inline-me")]]
#elif ABSL_HAVE_CPP_ATTRIBUTE(deprecated)
#define ABSL_DEPRECATE_AND_INLINE() [[deprecated]]
#else
#define ABSL_DEPRECATE_AND_INLINE()
#endif
// Requires the compiler to prove that the size of the given object is at least
// the expected amount.
#if ABSL_HAVE_ATTRIBUTE(diagnose_if) && ABSL_HAVE_BUILTIN(__builtin_object_size)
#define ABSL_INTERNAL_NEED_MIN_SIZE(Obj, N) \
__attribute__((diagnose_if(__builtin_object_size(Obj, 0) < N, \
"object size provably too small " \
"(this would corrupt memory)", \
"error")))
#else
#define ABSL_INTERNAL_NEED_MIN_SIZE(Obj, N)
#endif
#endif // ABSL_BASE_MACROS_H_

View File

@@ -1,191 +0,0 @@
// Copyright 2023 The Abseil Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// -----------------------------------------------------------------------------
// File: no_destructor.h
// -----------------------------------------------------------------------------
//
// This header file defines the absl::NoDestructor<T> wrapper for defining a
// static type that does not need to be destructed upon program exit. Instead,
// such an object survives during program exit (and can be safely accessed at
// any time).
//
// absl::NoDestructor<T> is useful when when a variable has static storage
// duration but its type has a non-trivial destructor. Global constructors are
// not recommended because of the C++'s static initialization order fiasco (See
// https://en.cppreference.com/w/cpp/language/siof). Global destructors are not
// allowed due to similar concerns about destruction ordering. Using
// absl::NoDestructor<T> as a function-local static prevents both of these
// issues.
//
// See below for complete details.
#ifndef ABSL_BASE_NO_DESTRUCTOR_H_
#define ABSL_BASE_NO_DESTRUCTOR_H_
#include <new>
#include <type_traits>
#include <utility>
#include "absl/base/config.h"
#include "absl/base/nullability.h"
namespace absl {
ABSL_NAMESPACE_BEGIN
// absl::NoDestructor<T>
//
// NoDestructor<T> is a wrapper around an object of type T that behaves as an
// object of type T but never calls T's destructor. NoDestructor<T> makes it
// safer and/or more efficient to use such objects in static storage contexts,
// ideally as function scope static variables.
//
// An instance of absl::NoDestructor<T> has similar type semantics to an
// instance of T:
//
// * Constructs in the same manner as an object of type T through perfect
// forwarding.
// * Provides pointer/reference semantic access to the object of type T via
// `->`, `*`, and `get()`.
// (Note that `const NoDestructor<T>` works like a pointer to const `T`.)
//
// Additionally, NoDestructor<T> provides the following benefits:
//
// * Never calls T's destructor for the object
// * If the object is a function-local static variable, the type can be
// lazily constructed.
//
// An object of type NoDestructor<T> is "trivially destructible" in the notion
// that its destructor is never run.
//
// Usage as Function Scope Static Variables
//
// Function static objects will be lazily initialized within static storage:
//
// // Function scope.
// const std::string& MyString() {
// static const absl::NoDestructor<std::string> x("foo");
// return *x;
// }
//
// For function static variables, NoDestructor avoids heap allocation and can be
// inlined in static storage, resulting in exactly-once, thread-safe
// construction of an object, and very fast access thereafter (the cost is a few
// extra cycles).
//
// Using NoDestructor<T> in this manner is generally better than other patterns
// which require pointer chasing:
//
// // Prefer using absl::NoDestructor<T> instead for the static variable.
// const std::string& MyString() {
// static const std::string* x = new std::string("foo");
// return *x;
// }
//
// Usage as Global Static Variables
//
// NoDestructor<T> allows declaration of a global object of type T that has a
// non-trivial destructor since its destructor is never run. However, such
// objects still need to worry about initialization order, so such use is not
// recommended, strongly discouraged by the Google C++ Style Guide, and outright
// banned in Chromium.
// See https://google.github.io/styleguide/cppguide.html#Static_and_Global_Variables
//
// // Global or namespace scope.
// absl::NoDestructor<MyRegistry> reg{"foo", "bar", 8008};
//
// Note that if your object already has a trivial destructor, you don't need to
// use NoDestructor<T>.
//
template <typename T>
class NoDestructor {
public:
// Forwards arguments to the T's constructor: calls T(args...).
template <typename... Ts,
// Disable this overload when it might collide with copy/move.
typename std::enable_if<!std::is_same<void(std::decay_t<Ts>&...),
void(NoDestructor&)>::value,
int>::type = 0>
explicit constexpr NoDestructor(Ts&&... args)
: impl_(std::forward<Ts>(args)...) {}
// Forwards copy and move construction for T. Enables usage like this:
// static NoDestructor<std::array<string, 3>> x{{{"1", "2", "3"}}};
// static NoDestructor<std::vector<int>> x{{1, 2, 3}};
explicit constexpr NoDestructor(const T& x) : impl_(x) {}
explicit constexpr NoDestructor(T&& x)
: impl_(std::move(x)) {}
// No copying.
NoDestructor(const NoDestructor&) = delete;
NoDestructor& operator=(const NoDestructor&) = delete;
// Pretend to be a smart pointer to T with deep constness.
// Never returns a null pointer.
T& operator*() { return *get(); }
T* absl_nonnull operator->() { return get(); }
T* absl_nonnull get() { return impl_.get(); }
const T& operator*() const { return *get(); }
const T* absl_nonnull operator->() const { return get(); }
const T* absl_nonnull get() const { return impl_.get(); }
private:
class DirectImpl {
public:
template <typename... Args>
explicit constexpr DirectImpl(Args&&... args)
: value_(std::forward<Args>(args)...) {}
const T* absl_nonnull get() const { return &value_; }
T* absl_nonnull get() { return &value_; }
private:
T value_;
};
class PlacementImpl {
public:
template <typename... Args>
explicit PlacementImpl(Args&&... args) {
new (&space_) T(std::forward<Args>(args)...);
}
const T* absl_nonnull get() const {
return std::launder(reinterpret_cast<const T*>(&space_));
}
T* absl_nonnull get() {
return std::launder(reinterpret_cast<T*>(&space_));
}
private:
alignas(T) unsigned char space_[sizeof(T)];
};
// If the object is trivially destructible we use a member directly to avoid
// potential once-init runtime initialization. It somewhat defeats the
// purpose of NoDestructor in this case, but this makes the class more
// friendly to generic code.
std::conditional_t<std::is_trivially_destructible<T>::value, DirectImpl,
PlacementImpl>
impl_;
};
// Provide 'Class Template Argument Deduction': the type of NoDestructor's T
// will be the same type as the argument passed to NoDestructor's constructor.
template <typename T>
NoDestructor(T) -> NoDestructor<T>;
ABSL_NAMESPACE_END
} // namespace absl
#endif // ABSL_BASE_NO_DESTRUCTOR_H_

View File

@@ -1,317 +0,0 @@
// Copyright 2023 The Abseil Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// -----------------------------------------------------------------------------
// File: nullability.h
// -----------------------------------------------------------------------------
//
// This header file defines a set of annotations for designating the expected
// nullability of pointers. These annotations allow you to designate pointers in
// one of three classification states:
//
// * "Non-null" (for pointers annotated `absl_nonnull`), indicating that it is
// invalid for the given pointer to ever be null.
// * "Nullable" (for pointers annotated `absl_nullable`), indicating that it is
// valid for the given pointer to be null.
// * "Unknown" (for pointers annotated `absl_nullability_unknown`), indicating
// that the given pointer has not yet been classified as either nullable or
// non-null. This is the default state of unannotated pointers.
//
// NOTE: Unannotated pointers implicitly bear the annotation
// `absl_nullability_unknown`; you should rarely, if ever, see this annotation
// used in the codebase explicitly.
//
// -----------------------------------------------------------------------------
// Nullability and Contracts
// -----------------------------------------------------------------------------
//
// These nullability annotations allow you to more clearly specify contracts on
// software components by narrowing the *preconditions*, *postconditions*, and
// *invariants* of pointer state(s) in any given interface. It then depends on
// context who is responsible for fulfilling the annotation's requirements.
//
// For example, a function may receive a pointer argument. Designating that
// pointer argument as "non-null" tightens the precondition of the contract of
// that function. It is then the responsibility of anyone calling such a
// function to ensure that the passed pointer is not null.
//
// Similarly, a function may have a pointer as a return value. Designating that
// return value as "non-null" tightens the postcondition of the contract of that
// function. In this case, however, it is the responsibility of the function
// itself to ensure that the returned pointer is not null.
//
// Clearly defining these contracts allows providers (and consumers) of such
// pointers to have more confidence in their null state. If a function declares
// a return value as "non-null", for example, the caller should not need to
// check whether the returned value is `nullptr`; it can simply assume the
// pointer is valid.
//
// Of course most interfaces already have expectations on the nullability state
// of pointers, and these expectations are, in effect, a contract; often,
// however, those contracts are either poorly or partially specified, assumed,
// or misunderstood. These nullability annotations are designed to allow you to
// formalize those contracts within the codebase.
//
// -----------------------------------------------------------------------------
// Annotation Syntax
// -----------------------------------------------------------------------------
//
// The annotations should be positioned as a qualifier for the pointer type. For
// example, the position of `const` when declaring a const pointer (not a
// pointer to a const type) is the position you should also use for these
// annotations.
//
// Example:
//
// // A const non-null pointer to an `Employee`.
// Employee* absl_nonnull const e;
//
// // A non-null pointer to a const `Employee`.
// const Employee* absl_nonnull e;
//
// // A non-null pointer to a const nullable pointer to an `Employee`.
// Employee* absl_nullable const* absl_nonnull e = nullptr;
//
// // A non-null function pointer.
// void (*absl_nonnull func)(int, double);
//
// // A non-null array of `Employee`s as a parameter.
// void func(Employee employees[absl_nonnull]);
//
// // A non-null std::unique_ptr to an `Employee`.
// // As with `const`, it is possible to place the annotation on either side of
// // a named type not ending in `*`, but placing it before the type it
// // describes is preferred, unless inconsistent with surrounding code.
// absl_nonnull std::unique_ptr<Employee> employee;
//
// // Invalid annotation usage this attempts to declare a pointer to a
// // nullable `Employee`, which is meaningless.
// absl_nullable Employee* e;
//
// -----------------------------------------------------------------------------
// Using Nullability Annotations
// -----------------------------------------------------------------------------
//
// Each annotation acts as a form of documentation about the contract for the
// given pointer. Each annotation requires providers or consumers of these
// pointers across API boundaries to take appropriate steps when setting or
// using these pointers:
//
// * "Non-null" pointers should never be null. It is the responsibility of the
// provider of this pointer to ensure that the pointer may never be set to
// null. Consumers of such pointers can treat such pointers as non-null.
// * "Nullable" pointers may or may not be null. Consumers of such pointers
// should precede any usage of that pointer (e.g. a dereference operation)
// with a a `nullptr` check.
// * "Unknown" pointers may be either "non-null" or "nullable" but have not been
// definitively determined to be in either classification state. Providers of
// such pointers across API boundaries should determine -- over time -- to
// annotate the pointer in either of the above two states. Consumers of such
// pointers across an API boundary should continue to treat such pointers as
// they currently do.
//
// Example:
//
// // PaySalary() requires the passed pointer to an `Employee` to be non-null.
// void PaySalary(Employee* absl_nonnull e) {
// pay(e->salary); // OK to dereference
// }
//
// // CompleteTransaction() guarantees the returned pointer to an `Account` to
// // be non-null.
// Account* absl_nonnull balance CompleteTransaction(double fee) {
// ...
// }
//
// // Note that specifying a nullability annotation does not prevent someone
// // from violating the contract:
//
// Employee* absl_nullable find(Map& employees, std::string_view name);
//
// void g(Map& employees) {
// Employee *e = find(employees, "Pat");
// // `e` can now be null.
// PaySalary(e); // Violates contract, but compiles!
// }
//
// Nullability annotations, in other words, are useful for defining and
// narrowing contracts; *enforcement* of those contracts depends on use and any
// additional (static or dynamic analysis) tooling.
//
// NOTE: The "unknown" annotation state indicates that a pointer's contract has
// not yet been positively identified. The unknown state therefore acts as a
// form of documentation of your technical debt, and a codebase that adopts
// nullability annotations should aspire to annotate every pointer as either
// "non-null" or "nullable".
//
// -----------------------------------------------------------------------------
// Applicability of Nullability Annotations
// -----------------------------------------------------------------------------
//
// By default, nullability annotations are applicable to raw and smart
// pointers. User-defined types can indicate compatibility with nullability
// annotations by adding the ABSL_NULLABILITY_COMPATIBLE attribute.
//
// // Example:
// struct ABSL_NULLABILITY_COMPATIBLE MyPtr {
// ...
// };
//
// Note: Compilers that don't support the `nullability_on_classes` feature will
// allow nullability annotations to be applied to any type, not just ones
// marked with `ABSL_NULLABILITY_COMPATIBLE`.
//
// DISCLAIMER:
// ===========================================================================
// These nullability annotations are primarily a human readable signal about the
// intended contract of the pointer. They are not *types* and do not currently
// provide any correctness guarantees. For example, a pointer annotated as
// `absl_nonnull` is *not guaranteed* to be non-null, and the compiler won't
// alert or prevent assignment of a `T* absl_nullable` to a `T* absl_nonnull`.
// ===========================================================================
#ifndef ABSL_BASE_NULLABILITY_H_
#define ABSL_BASE_NULLABILITY_H_
#include "absl/base/config.h"
// ABSL_POINTERS_DEFAULT_NONNULL
//
// This macro specifies that all unannotated pointer types within the given
// file are designated as nonnull (instead of the default "unknown"). This macro
// exists as a standalone statement and applies default nonnull behavior to all
// subsequent pointers; as a result, place this macro as the first non-comment,
// non-`#include` line in a file.
//
// Example:
//
// #include "absl/base/nullability.h"
//
// ABSL_POINTERS_DEFAULT_NONNULL
//
// void FillMessage(Message *m); // implicitly non-null
// T* absl_nullable GetNullablePtr(); // explicitly nullable
// T* absl_nullability_unknown GetUnknownPtr(); // explicitly unknown
//
// The macro can be safely used in header files it will not affect any files
// that include it.
//
// In files with the macro, plain `T*` syntax means `T* absl_nonnull`, and the
// exceptions (`absl_nullable` and `absl_nullability_unknown`) must be marked
// explicitly. The same holds, correspondingly, for smart pointer types.
//
// For comparison, without the macro, all unannotated pointers would default to
// unknown, and otherwise require explicit annotations to change this behavior:
//
// #include "absl/base/nullability.h"
//
// void FillMessage(Message* absl_nonnull m); // explicitly non-null
// T* absl_nullable GetNullablePtr(); // explicitly nullable
// T* GetUnknownPtr(); // implicitly unknown
//
// No-op except for being a human readable signal.
#define ABSL_POINTERS_DEFAULT_NONNULL
#if defined(__clang__) && !defined(__OBJC__) && \
ABSL_HAVE_FEATURE(nullability_on_classes)
// absl_nonnull (default with `ABSL_POINTERS_DEFAULT_NONNULL`)
//
// The indicated pointer is never null. It is the responsibility of the provider
// of this pointer across an API boundary to ensure that the pointer is never
// set to null. Consumers of this pointer across an API boundary may safely
// dereference the pointer.
//
// Example:
//
// // `employee` is designated as not null.
// void PaySalary(Employee* absl_nonnull employee) {
// pay(*employee); // OK to dereference
// }
#define absl_nonnull _Nonnull
// absl_nullable
//
// The indicated pointer may, by design, be either null or non-null. Consumers
// of this pointer across an API boundary should perform a `nullptr` check
// before performing any operation using the pointer.
//
// Example:
//
// // `employee` may be null.
// void PaySalary(Employee* absl_nullable employee) {
// if (employee != nullptr) {
// Pay(*employee); // OK to dereference
// }
// }
#define absl_nullable _Nullable
// absl_nullability_unknown (default without `ABSL_POINTERS_DEFAULT_NONNULL`)
//
// The indicated pointer has not yet been determined to be definitively
// "non-null" or "nullable." Providers of such pointers across API boundaries
// should, over time, annotate such pointers as either "non-null" or "nullable."
// Consumers of these pointers across an API boundary should treat such pointers
// with the same caution they treat currently unannotated pointers. Most
// existing code will have "unknown" pointers, which should eventually be
// migrated into one of the above two nullability states: `absl_nonnull` or
// `absl_nullable`.
//
// NOTE: For files that do not specify `ABSL_POINTERS_DEFAULT_NONNULL`,
// because this annotation is the global default state, unannotated pointers are
// are assumed to have "unknown" semantics. This assumption is designed to
// minimize churn and reduce clutter within the codebase.
//
// Example:
//
// // `employee`s nullability state is unknown.
// void PaySalary(Employee* absl_nullability_unknown employee) {
// Pay(*employee); // Potentially dangerous. API provider should investigate.
// }
//
// Note that a pointer without an annotation, by default, is assumed to have the
// annotation `NullabilityUnknown`.
//
// // `employee`s nullability state is unknown.
// void PaySalary(Employee* employee) {
// Pay(*employee); // Potentially dangerous. API provider should investigate.
// }
#define absl_nullability_unknown _Null_unspecified
#else
// No-op for non-Clang compilers or Objective-C.
#define absl_nonnull
// No-op for non-Clang compilers or Objective-C.
#define absl_nullable
// No-op for non-Clang compilers or Objective-C.
#define absl_nullability_unknown
#endif
// ABSL_NULLABILITY_COMPATIBLE
//
// Indicates that a class is compatible with nullability annotations.
//
// For example:
//
// struct ABSL_NULLABILITY_COMPATIBLE MyPtr {
// ...
// };
//
// Note: Compilers that don't support the `nullability_on_classes` feature will
// allow nullability annotations to be applied to any type, not just ones marked
// with `ABSL_NULLABILITY_COMPATIBLE`.
#if ABSL_HAVE_FEATURE(nullability_on_classes)
#define ABSL_NULLABILITY_COMPATIBLE _Nullable
#else
#define ABSL_NULLABILITY_COMPATIBLE
#endif
#endif // ABSL_BASE_NULLABILITY_H_

View File

@@ -1,310 +0,0 @@
//
// Copyright 2017 The Abseil Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// -----------------------------------------------------------------------------
// File: optimization.h
// -----------------------------------------------------------------------------
//
// This header file defines portable macros for performance optimization.
//
// This header is included in both C++ code and legacy C code and thus must
// remain compatible with both C and C++. C compatibility will be removed if
// the legacy code is removed or converted to C++. Do not include this header in
// new code that requires C compatibility or assume C compatibility will remain
// indefinitely.
// SKIP_ABSL_INLINE_NAMESPACE_CHECK
#ifndef ABSL_BASE_OPTIMIZATION_H_
#define ABSL_BASE_OPTIMIZATION_H_
#include <assert.h>
#ifdef __cplusplus
// Included for std::unreachable()
#include <utility>
#endif // __cplusplus
#include "absl/base/config.h"
#include "absl/base/options.h"
// ABSL_BLOCK_TAIL_CALL_OPTIMIZATION
//
// Instructs the compiler to avoid optimizing tail-call recursion. This macro is
// useful when you wish to preserve the existing function order within a stack
// trace for logging, debugging, or profiling purposes.
//
// Example:
//
// int f() {
// int result = g();
// ABSL_BLOCK_TAIL_CALL_OPTIMIZATION();
// return result;
// }
#if defined(__clang__)
// Clang will not tail call given inline volatile assembly.
#define ABSL_BLOCK_TAIL_CALL_OPTIMIZATION() __asm__ __volatile__("")
#elif defined(__GNUC__)
// GCC will not tail call given inline volatile assembly.
#define ABSL_BLOCK_TAIL_CALL_OPTIMIZATION() __asm__ __volatile__("")
#elif defined(_MSC_VER)
#include <intrin.h>
// The __nop() intrinsic blocks the optimisation.
#define ABSL_BLOCK_TAIL_CALL_OPTIMIZATION() __nop()
#else
#define ABSL_BLOCK_TAIL_CALL_OPTIMIZATION() if (volatile int x = 0) { (void)x; }
#endif
// ABSL_CACHELINE_SIZE
//
// Explicitly defines the size of the L1 cache for purposes of alignment.
// Setting the cacheline size allows you to specify that certain objects be
// aligned on a cacheline boundary with `ABSL_CACHELINE_ALIGNED` declarations.
// (See below.)
//
// NOTE: this macro should be replaced with the following C++17 features, when
// those are generally available:
//
// * `std::hardware_constructive_interference_size`
// * `std::hardware_destructive_interference_size`
//
// See http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2016/p0154r1.html
// for more information.
#if defined(__GNUC__)
// Cache line alignment
#if defined(__i386__) || defined(__x86_64__)
#define ABSL_CACHELINE_SIZE 64
#elif defined(__powerpc64__)
#define ABSL_CACHELINE_SIZE 128
#elif defined(__aarch64__)
// We would need to read special register ctr_el0 to find out L1 dcache size.
// This value is a good estimate based on a real aarch64 machine.
#define ABSL_CACHELINE_SIZE 64
#elif defined(__arm__)
// Cache line sizes for ARM: These values are not strictly correct since
// cache line sizes depend on implementations, not architectures. There
// are even implementations with cache line sizes configurable at boot
// time.
#if defined(__ARM_ARCH_5T__)
#define ABSL_CACHELINE_SIZE 32
#elif defined(__ARM_ARCH_7A__)
#define ABSL_CACHELINE_SIZE 64
#endif
#endif
#endif
#ifndef ABSL_CACHELINE_SIZE
// A reasonable default guess. Note that overestimates tend to waste more
// space, while underestimates tend to waste more time.
#define ABSL_CACHELINE_SIZE 64
#endif
// ABSL_CACHELINE_ALIGNED
//
// Indicates that the declared object be cache aligned using
// `ABSL_CACHELINE_SIZE` (see above). Cacheline aligning objects allows you to
// load a set of related objects in the L1 cache for performance improvements.
// Cacheline aligning objects properly allows constructive memory sharing and
// prevents destructive (or "false") memory sharing.
//
// NOTE: callers should replace uses of this macro with `alignas()` using
// `std::hardware_constructive_interference_size` and/or
// `std::hardware_destructive_interference_size` when C++17 becomes available to
// them.
//
// See http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2016/p0154r1.html
// for more information.
//
// On some compilers, `ABSL_CACHELINE_ALIGNED` expands to an `__attribute__`
// or `__declspec` attribute. For compilers where this is not known to work,
// the macro expands to nothing.
//
// No further guarantees are made here. The result of applying the macro
// to variables and types is always implementation-defined.
//
// WARNING: It is easy to use this attribute incorrectly, even to the point
// of causing bugs that are difficult to diagnose, crash, etc. It does not
// of itself guarantee that objects are aligned to a cache line.
//
// NOTE: Some compilers are picky about the locations of annotations such as
// this attribute, so prefer to put it at the beginning of your declaration.
// For example,
//
// ABSL_CACHELINE_ALIGNED static Foo* foo = ...
//
// class ABSL_CACHELINE_ALIGNED Bar { ...
//
// Recommendations:
//
// 1) Consult compiler documentation; this comment is not kept in sync as
// toolchains evolve.
// 2) Verify your use has the intended effect. This often requires inspecting
// the generated machine code.
// 3) Prefer applying this attribute to individual variables. Avoid
// applying it to types. This tends to localize the effect.
#if defined(__clang__) || defined(__GNUC__)
#define ABSL_CACHELINE_ALIGNED __attribute__((aligned(ABSL_CACHELINE_SIZE)))
#elif defined(_MSC_VER)
#define ABSL_CACHELINE_ALIGNED __declspec(align(ABSL_CACHELINE_SIZE))
#else
#define ABSL_CACHELINE_ALIGNED
#endif
// ABSL_PREDICT_TRUE, ABSL_PREDICT_FALSE
//
// Enables the compiler to prioritize compilation using static analysis for
// likely paths within a boolean branch.
//
// Example:
//
// if (ABSL_PREDICT_TRUE(expression)) {
// return result; // Faster if more likely
// } else {
// return 0;
// }
//
// Compilers can use the information that a certain branch is not likely to be
// taken (for instance, a CHECK failure) to optimize for the common case in
// the absence of better information (ie. compiling gcc with `-fprofile-arcs`).
//
// Recommendation: Modern CPUs dynamically predict branch execution paths,
// typically with accuracy greater than 97%. As a result, annotating every
// branch in a codebase is likely counterproductive; however, annotating
// specific branches that are both hot and consistently mispredicted is likely
// to yield performance improvements.
#if ABSL_HAVE_BUILTIN(__builtin_expect) || \
(defined(__GNUC__) && !defined(__clang__))
#define ABSL_PREDICT_FALSE(x) (__builtin_expect(false || (x), false))
#define ABSL_PREDICT_TRUE(x) (__builtin_expect(false || (x), true))
#else
#define ABSL_PREDICT_FALSE(x) (x)
#define ABSL_PREDICT_TRUE(x) (x)
#endif
// `ABSL_INTERNAL_IMMEDIATE_ABORT_IMPL()` aborts the program in the fastest
// possible way, with no attempt at logging. One use is to implement hardening
// aborts with ABSL_OPTION_HARDENED. Since this is an internal symbol, it
// should not be used directly outside of Abseil.
#if ABSL_HAVE_BUILTIN(__builtin_trap) || \
(defined(__GNUC__) && !defined(__clang__))
#define ABSL_INTERNAL_IMMEDIATE_ABORT_IMPL() __builtin_trap()
#else
#define ABSL_INTERNAL_IMMEDIATE_ABORT_IMPL() abort()
#endif
// `ABSL_INTERNAL_UNREACHABLE_IMPL()` is the platform specific directive to
// indicate that a statement is unreachable, and to allow the compiler to
// optimize accordingly. Clients should use `ABSL_UNREACHABLE()`, which is
// defined below.
#if defined(__cpp_lib_unreachable) && __cpp_lib_unreachable >= 202202L
#define ABSL_INTERNAL_UNREACHABLE_IMPL() std::unreachable()
#elif defined(__GNUC__) || ABSL_HAVE_BUILTIN(__builtin_unreachable)
#define ABSL_INTERNAL_UNREACHABLE_IMPL() __builtin_unreachable()
#elif ABSL_HAVE_BUILTIN(__builtin_assume)
#define ABSL_INTERNAL_UNREACHABLE_IMPL() __builtin_assume(false)
#elif defined(_MSC_VER)
#define ABSL_INTERNAL_UNREACHABLE_IMPL() __assume(false)
#else
#define ABSL_INTERNAL_UNREACHABLE_IMPL()
#endif
// `ABSL_UNREACHABLE()` is an unreachable statement. A program which reaches
// one has undefined behavior, and the compiler may optimize accordingly.
#if ABSL_OPTION_HARDENED == 1 && defined(NDEBUG)
// Abort in hardened mode to avoid dangerous undefined behavior.
#define ABSL_UNREACHABLE() \
do { \
ABSL_INTERNAL_IMMEDIATE_ABORT_IMPL(); \
ABSL_INTERNAL_UNREACHABLE_IMPL(); \
} while (false)
#else
// The assert only fires in debug mode to aid in debugging.
// When NDEBUG is defined, reaching ABSL_UNREACHABLE() is undefined behavior.
#define ABSL_UNREACHABLE() \
do { \
/* NOLINTNEXTLINE: misc-static-assert */ \
assert(false && "ABSL_UNREACHABLE reached"); \
ABSL_INTERNAL_UNREACHABLE_IMPL(); \
} while (false)
#endif
// ABSL_ASSUME(cond)
//
// Informs the compiler that a condition is always true and that it can assume
// it to be true for optimization purposes.
//
// WARNING: If the condition is false, the program can produce undefined and
// potentially dangerous behavior.
//
// In !NDEBUG mode, the condition is checked with an assert().
//
// NOTE: The expression must not have side effects, as it may only be evaluated
// in some compilation modes and not others. Some compilers may issue a warning
// if the compiler cannot prove the expression has no side effects. For example,
// the expression should not use a function call since the compiler cannot prove
// that a function call does not have side effects.
//
// Example:
//
// int x = ...;
// ABSL_ASSUME(x >= 0);
// // The compiler can optimize the division to a simple right shift using the
// // assumption specified above.
// int y = x / 16;
//
#if !defined(NDEBUG)
#define ABSL_ASSUME(cond) assert(cond)
#elif ABSL_HAVE_BUILTIN(__builtin_assume)
#define ABSL_ASSUME(cond) __builtin_assume(cond)
#elif defined(_MSC_VER)
#define ABSL_ASSUME(cond) __assume(cond)
#elif defined(__cpp_lib_unreachable) && __cpp_lib_unreachable >= 202202L
#define ABSL_ASSUME(cond) ((cond) ? void() : std::unreachable())
#elif defined(__GNUC__) || ABSL_HAVE_BUILTIN(__builtin_unreachable)
#define ABSL_ASSUME(cond) ((cond) ? void() : __builtin_unreachable())
#elif ABSL_INTERNAL_CPLUSPLUS_LANG >= 202002L
// Unimplemented. Uses the same definition as ABSL_ASSERT in the NDEBUG case.
#define ABSL_ASSUME(expr) (decltype((expr) ? void() : void())())
#else
#define ABSL_ASSUME(expr) (false ? ((expr) ? void() : void()) : void())
#endif
// ABSL_INTERNAL_UNIQUE_SMALL_NAME(cond)
// This macro forces small unique name on a static file level symbols like
// static local variables or static functions. This is intended to be used in
// macro definitions to optimize the cost of generated code. Do NOT use it on
// symbols exported from translation unit since it may cause a link time
// conflict.
//
// Example:
//
// #define MY_MACRO(txt)
// namespace {
// char VeryVeryLongVarName[] ABSL_INTERNAL_UNIQUE_SMALL_NAME() = txt;
// const char* VeryVeryLongFuncName() ABSL_INTERNAL_UNIQUE_SMALL_NAME();
// const char* VeryVeryLongFuncName() { return txt; }
// }
//
#if defined(__GNUC__)
#define ABSL_INTERNAL_UNIQUE_SMALL_NAME2(x) #x
#define ABSL_INTERNAL_UNIQUE_SMALL_NAME1(x) ABSL_INTERNAL_UNIQUE_SMALL_NAME2(x)
#define ABSL_INTERNAL_UNIQUE_SMALL_NAME() \
asm(ABSL_INTERNAL_UNIQUE_SMALL_NAME1(.absl.__COUNTER__))
#else
#define ABSL_INTERNAL_UNIQUE_SMALL_NAME()
#endif
#endif // ABSL_BASE_OPTIMIZATION_H_

View File

@@ -1,184 +0,0 @@
// Copyright 2019 The Abseil Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// -----------------------------------------------------------------------------
// File: options.h
// -----------------------------------------------------------------------------
//
// This file contains Abseil configuration options for setting specific
// implementations instead of letting Abseil determine which implementation to
// use at compile-time. Setting these options may be useful for package or build
// managers who wish to guarantee ABI stability within binary builds (which are
// otherwise difficult to enforce).
//
// *** IMPORTANT NOTICE FOR PACKAGE MANAGERS: It is important that
// maintainers of package managers who wish to package Abseil read and
// understand this file! ***
//
// Abseil contains a number of possible configuration endpoints, based on
// parameters such as the detected platform, language version, or command-line
// flags used to invoke the underlying binary. As is the case with all
// libraries, binaries which contain Abseil code must ensure that separate
// packages use the same compiled copy of Abseil to avoid a diamond dependency
// problem, which can occur if two packages built with different Abseil
// configuration settings are linked together. Diamond dependency problems in
// C++ may manifest as violations to the One Definition Rule (ODR) (resulting in
// linker errors), or undefined behavior (resulting in crashes).
//
// Diamond dependency problems can be avoided if all packages utilize the same
// exact version of Abseil. Building from source code with the same compilation
// parameters is the easiest way to avoid such dependency problems. However, for
// package managers who cannot control such compilation parameters, we are
// providing the file to allow you to inject ABI (Application Binary Interface)
// stability across builds. Settings options in this file will neither change
// API nor ABI, providing a stable copy of Abseil between packages.
//
// Care must be taken to keep options within these configurations isolated
// from any other dynamic settings, such as command-line flags which could alter
// these options. This file is provided specifically to help build and package
// managers provide a stable copy of Abseil within their libraries and binaries;
// other developers should not have need to alter the contents of this file.
//
// -----------------------------------------------------------------------------
// Usage
// -----------------------------------------------------------------------------
//
// For any particular package release, set the appropriate definitions within
// this file to whatever value makes the most sense for your package(s). Note
// that, by default, most of these options, at the moment, affect the
// implementation of types; future options may affect other implementation
// details.
//
// NOTE: the defaults within this file all assume that Abseil can select the
// proper Abseil implementation at compile-time, which will not be sufficient
// to guarantee ABI stability to package managers.
// SKIP_ABSL_INLINE_NAMESPACE_CHECK
#ifndef ABSL_BASE_OPTIONS_H_
#define ABSL_BASE_OPTIONS_H_
// -----------------------------------------------------------------------------
// Type Compatibility Options
// -----------------------------------------------------------------------------
// ABSL_OPTION_USE_STD_STRING_VIEW
//
// This option controls whether absl::string_view is implemented as an alias to
// std::string_view, or as an independent implementation.
//
// A value of 0 means to use Abseil's implementation. This requires only C++11
// support, and is expected to work on every toolchain we support.
//
// A value of 1 means to use an alias to std::string_view. This requires that
// all code using Abseil is built in C++17 mode or later.
//
// A value of 2 means to detect the C++ version being used to compile Abseil,
// and use an alias only if a working std::string_view is available. This
// option is useful when you are building your program from source. It should
// not be used otherwise -- for example, if you are distributing Abseil in a
// binary package manager -- since in mode 2, absl::string_view will name a
// different type, with a different mangled name and binary layout, depending on
// the compiler flags passed by the end user. For more info, see
// https://abseil.io/about/design/dropin-types.
//
// User code should not inspect this macro. To check in the preprocessor if
// absl::string_view is a typedef of std::string_view, use the feature macro
// ABSL_USES_STD_STRING_VIEW.
#define ABSL_OPTION_USE_STD_STRING_VIEW 2
// ABSL_OPTION_USE_STD_ORDERING
//
// This option controls whether absl::{partial,weak,strong}_ordering are
// implemented as aliases to the std:: ordering types, or as an independent
// implementation.
//
// A value of 0 means to use Abseil's implementation. This requires only C++11
// support, and is expected to work on every toolchain we support.
//
// A value of 1 means to use aliases. This requires that all code using Abseil
// is built in C++20 mode or later.
//
// A value of 2 means to detect the C++ version being used to compile Abseil,
// and use an alias only if working std:: ordering types are available. This
// option is useful when you are building your program from source. It should
// not be used otherwise -- for example, if you are distributing Abseil in a
// binary package manager -- since in mode 2, they will name different types,
// with different mangled names and binary layout, depending on the compiler
// flags passed by the end user. For more info, see
// https://abseil.io/about/design/dropin-types.
//
// User code should not inspect this macro. To check in the preprocessor if
// the ordering types are aliases of std:: ordering types, use the feature macro
// ABSL_USES_STD_ORDERING.
#define ABSL_OPTION_USE_STD_ORDERING 2
// ABSL_OPTION_USE_INLINE_NAMESPACE
// ABSL_OPTION_INLINE_NAMESPACE_NAME
//
// These options controls whether all entities in the absl namespace are
// contained within an inner inline namespace. This does not affect the
// user-visible API of Abseil, but it changes the mangled names of all symbols.
//
// This can be useful as a version tag if you are distributing Abseil in
// precompiled form. This will prevent a binary library build of Abseil with
// one inline namespace being used with headers configured with a different
// inline namespace name. Binary packagers are reminded that Abseil does not
// guarantee any ABI stability in Abseil, so any update of Abseil or
// configuration change in such a binary package should be combined with a
// new, unique value for the inline namespace name.
//
// A value of 0 means not to use inline namespaces.
//
// A value of 1 means to use an inline namespace with the given name inside
// namespace absl. If this is set, ABSL_OPTION_INLINE_NAMESPACE_NAME must also
// be changed to a new, unique identifier name. In particular "head" is not
// allowed.
#define ABSL_OPTION_USE_INLINE_NAMESPACE 0
#define ABSL_OPTION_INLINE_NAMESPACE_NAME head
// ABSL_OPTION_HARDENED
//
// This option enables a "hardened" build in release mode (in this context,
// release mode is defined as a build where the `NDEBUG` macro is defined).
//
// A value of 0 means that "hardened" mode is not enabled.
//
// A value of 1 means that "hardened" mode is enabled with all checks.
//
// A value of 2 means that "hardened" mode is partially enabled, with
// only a subset of checks chosen to minimize performance impact.
//
// Hardened builds have additional security checks enabled when `NDEBUG` is
// defined. Defining `NDEBUG` is normally used to turn `assert()` macro into a
// no-op, as well as disabling other bespoke program consistency checks. By
// defining ABSL_OPTION_HARDENED to 1, a select set of checks remain enabled in
// release mode. These checks guard against programming errors that may lead to
// security vulnerabilities. In release mode, when one of these programming
// errors is encountered, the program will immediately abort, possibly without
// any attempt at logging.
//
// The checks enabled by this option are not free; they do incur runtime cost.
//
// The checks enabled by this option are always active when `NDEBUG` is not
// defined, even in the case when ABSL_OPTION_HARDENED is defined to 0. The
// checks enabled by this option may abort the program in a different way and
// log additional information when `NDEBUG` is not defined.
#define ABSL_OPTION_HARDENED 1
#endif // ABSL_BASE_OPTIONS_H_

View File

@@ -1,115 +0,0 @@
// Copyright 2017 The Abseil Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// -----------------------------------------------------------------------------
// File: policy_checks.h
// -----------------------------------------------------------------------------
//
// This header enforces a minimum set of policies at build time, such as the
// supported compiler and library versions. Unsupported configurations are
// reported with `#error`. This enforcement is best effort, so successfully
// compiling this header does not guarantee a supported configuration.
// SKIP_ABSL_INLINE_NAMESPACE_CHECK
#ifndef ABSL_BASE_POLICY_CHECKS_H_
#define ABSL_BASE_POLICY_CHECKS_H_
// Included for the __GLIBC_PREREQ macro used below.
#include <limits.h>
// Included for the _STLPORT_VERSION macro used below.
#if defined(__cplusplus)
#include <cstddef>
#endif
// -----------------------------------------------------------------------------
// Operating System Check
// -----------------------------------------------------------------------------
#if defined(__CYGWIN__)
#error "Cygwin is not supported."
#endif
// -----------------------------------------------------------------------------
// Toolchain Check
// -----------------------------------------------------------------------------
// We support Visual Studio 2019 (MSVC++ 16.0) and later.
// This minimum will go up.
#if defined(_MSC_VER) && _MSC_VER < 1920 && !defined(__clang__)
#error "This package requires Visual Studio 2019 (MSVC++ 16.0) or higher."
#endif
// We support GCC 7 and later.
// This minimum will go up.
#if defined(__GNUC__) && !defined(__clang__)
#if __GNUC__ < 7
#error "This package requires GCC 7 or higher."
#endif
#endif
// We support Apple Xcode clang 4.2.1 (version 421.11.65) and later.
// This corresponds to Apple Xcode version 4.5.
// This minimum will go up.
#if defined(__apple_build_version__) && __apple_build_version__ < 4211165
#error "This package requires __apple_build_version__ of 4211165 or higher."
#endif
// -----------------------------------------------------------------------------
// C++ Version Check
// -----------------------------------------------------------------------------
// Enforce C++17 as the minimum.
#if defined(_MSVC_LANG)
#if _MSVC_LANG < 201703L
#error "C++ versions less than C++17 are not supported."
#endif // _MSVC_LANG < 201703L
#elif defined(__cplusplus)
#if __cplusplus < 201703L
#error "C++ versions less than C++17 are not supported."
#endif // __cplusplus < 201703L
#endif
// -----------------------------------------------------------------------------
// Standard Library Check
// -----------------------------------------------------------------------------
#if defined(_STLPORT_VERSION)
#error "STLPort is not supported."
#endif
// -----------------------------------------------------------------------------
// `char` Size Check
// -----------------------------------------------------------------------------
// Abseil currently assumes CHAR_BIT == 8. If you would like to use Abseil on a
// platform where this is not the case, please provide us with the details about
// your platform so we can consider relaxing this requirement.
#if CHAR_BIT != 8
#error "Abseil assumes CHAR_BIT == 8."
#endif
// -----------------------------------------------------------------------------
// `int` Size Check
// -----------------------------------------------------------------------------
// Abseil currently assumes that an int is 4 bytes. If you would like to use
// Abseil on a platform where this is not the case, please provide us with the
// details about your platform so we can consider relaxing this requirement.
#if INT_MAX < 2147483647
#error "Abseil assumes that int is at least 4 bytes. "
#endif
#endif // ABSL_BASE_POLICY_CHECKS_H_

View File

@@ -1,25 +0,0 @@
// Copyright 2017 The Abseil Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// This files is a forwarding header for other headers containing various
// portability macros and functions.
#ifndef ABSL_BASE_PORT_H_
#define ABSL_BASE_PORT_H_
#include "absl/base/attributes.h"
#include "absl/base/config.h"
#include "absl/base/optimization.h"
#endif // ABSL_BASE_PORT_H_

View File

@@ -1,209 +0,0 @@
// Copyright 2023 The Abseil Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// -----------------------------------------------------------------------------
// File: prefetch.h
// -----------------------------------------------------------------------------
//
// This header file defines prefetch functions to prefetch memory contents
// into the first level cache (L1) for the current CPU. The prefetch logic
// offered in this header is limited to prefetching first level cachelines
// only, and is aimed at relatively 'simple' prefetching logic.
//
#ifndef ABSL_BASE_PREFETCH_H_
#define ABSL_BASE_PREFETCH_H_
#include "absl/base/attributes.h"
#include "absl/base/config.h"
#if defined(ABSL_INTERNAL_HAVE_SSE)
#include <xmmintrin.h>
#endif
#if defined(_MSC_VER)
#include <intrin.h>
#if defined(ABSL_INTERNAL_HAVE_SSE)
#pragma intrinsic(_mm_prefetch)
#endif
#endif
namespace absl {
ABSL_NAMESPACE_BEGIN
// Moves data into the L1 cache before it is read, or "prefetches" it.
//
// The value of `addr` is the address of the memory to prefetch. If
// the target and compiler support it, data prefetch instructions are
// generated. If the prefetch is done some time before the memory is
// read, it may be in the cache by the time the read occurs.
//
// This method prefetches data with the highest degree of temporal locality;
// data is prefetched where possible into all levels of the cache.
//
// Incorrect or gratuitous use of this function can degrade performance.
// Use this function only when representative benchmarks show an improvement.
//
// Example:
//
// // Computes incremental checksum for `data`.
// int ComputeChecksum(int sum, absl::string_view data);
//
// // Computes cumulative checksum for all values in `data`
// int ComputeChecksum(absl::Span<const std::string> data) {
// int sum = 0;
// auto it = data.begin();
// auto pit = data.begin();
// auto end = data.end();
// for (int dist = 8; dist > 0 && pit != data.end(); --dist, ++pit) {
// absl::PrefetchToLocalCache(pit->data());
// }
// for (; pit != end; ++pit, ++it) {
// sum = ComputeChecksum(sum, *it);
// absl::PrefetchToLocalCache(pit->data());
// }
// for (; it != end; ++it) {
// sum = ComputeChecksum(sum, *it);
// }
// return sum;
// }
//
void PrefetchToLocalCache(const void* addr);
// Moves data into the L1 cache before it is read, or "prefetches" it.
//
// This function is identical to `PrefetchToLocalCache()` except that it has
// non-temporal locality: the fetched data should not be left in any of the
// cache tiers. This is useful for cases where the data is used only once /
// short term, for example, invoking a destructor on an object.
//
// Incorrect or gratuitous use of this function can degrade performance.
// Use this function only when representative benchmarks show an improvement.
//
// Example:
//
// template <typename Iterator>
// void DestroyPointers(Iterator begin, Iterator end) {
// size_t distance = std::min(8U, bars.size());
//
// int dist = 8;
// auto prefetch_it = begin;
// while (prefetch_it != end && --dist;) {
// absl::PrefetchToLocalCacheNta(*prefetch_it++);
// }
// while (prefetch_it != end) {
// delete *begin++;
// absl::PrefetchToLocalCacheNta(*prefetch_it++);
// }
// while (begin != end) {
// delete *begin++;
// }
// }
//
void PrefetchToLocalCacheNta(const void* addr);
// Moves data into the L1 cache with the intent to modify it.
//
// This function is similar to `PrefetchToLocalCache()` except that it
// prefetches cachelines with an 'intent to modify' This typically includes
// invalidating cache entries for this address in all other cache tiers, and an
// exclusive access intent.
//
// Incorrect or gratuitous use of this function can degrade performance. As this
// function can invalidate cached cachelines on other caches and computer cores,
// incorrect usage of this function can have an even greater negative impact
// than incorrect regular prefetches.
// Use this function only when representative benchmarks show an improvement.
//
// Example:
//
// void* Arena::Allocate(size_t size) {
// void* ptr = AllocateBlock(size);
// absl::PrefetchToLocalCacheForWrite(ptr);
// return ptr;
// }
//
void PrefetchToLocalCacheForWrite(const void* addr);
#if ABSL_HAVE_BUILTIN(__builtin_prefetch) || defined(__GNUC__)
#define ABSL_HAVE_PREFETCH 1
// See __builtin_prefetch:
// https://gcc.gnu.org/onlinedocs/gcc/Other-Builtins.html.
//
ABSL_ATTRIBUTE_ALWAYS_INLINE inline void PrefetchToLocalCache(
const void* addr) {
__builtin_prefetch(addr, 0, 3);
}
ABSL_ATTRIBUTE_ALWAYS_INLINE inline void PrefetchToLocalCacheNta(
const void* addr) {
__builtin_prefetch(addr, 0, 0);
}
ABSL_ATTRIBUTE_ALWAYS_INLINE inline void PrefetchToLocalCacheForWrite(
const void* addr) {
// [x86] gcc/clang don't generate PREFETCHW for __builtin_prefetch(.., 1)
// unless -march=broadwell or newer; this is not generally the default, so we
// manually emit prefetchw. PREFETCHW is recognized as a no-op on older Intel
// processors and has been present on AMD processors since the K6-2.
#if defined(__x86_64__) && !defined(__PRFCHW__)
asm("prefetchw %0" : : "m"(*reinterpret_cast<const char*>(addr)));
#else
__builtin_prefetch(addr, 1, 3);
#endif
}
#elif defined(ABSL_INTERNAL_HAVE_SSE)
#define ABSL_HAVE_PREFETCH 1
ABSL_ATTRIBUTE_ALWAYS_INLINE inline void PrefetchToLocalCache(
const void* addr) {
_mm_prefetch(reinterpret_cast<const char*>(addr), _MM_HINT_T0);
}
ABSL_ATTRIBUTE_ALWAYS_INLINE inline void PrefetchToLocalCacheNta(
const void* addr) {
_mm_prefetch(reinterpret_cast<const char*>(addr), _MM_HINT_NTA);
}
ABSL_ATTRIBUTE_ALWAYS_INLINE inline void PrefetchToLocalCacheForWrite(
const void* addr) {
#if defined(_MM_HINT_ET0)
_mm_prefetch(reinterpret_cast<const char*>(addr), _MM_HINT_ET0);
#elif !defined(_MSC_VER) && defined(__x86_64__)
// _MM_HINT_ET0 is not universally supported. As we commented further
// up, PREFETCHW is recognized as a no-op on older Intel processors
// and has been present on AMD processors since the K6-2. We have this
// disabled for MSVC compilers as this miscompiles on older MSVC compilers.
asm("prefetchw %0" : : "m"(*reinterpret_cast<const char*>(addr)));
#endif
}
#else
ABSL_ATTRIBUTE_ALWAYS_INLINE inline void PrefetchToLocalCache(
const void* addr) {}
ABSL_ATTRIBUTE_ALWAYS_INLINE inline void PrefetchToLocalCacheNta(
const void* addr) {}
ABSL_ATTRIBUTE_ALWAYS_INLINE inline void PrefetchToLocalCacheForWrite(
const void* addr) {}
#endif
ABSL_NAMESPACE_END
} // namespace absl
#endif // ABSL_BASE_PREFETCH_H_

View File

@@ -1,333 +0,0 @@
// Copyright 2017 The Abseil Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// -----------------------------------------------------------------------------
// File: thread_annotations.h
// -----------------------------------------------------------------------------
//
// This header file contains macro definitions for thread safety annotations
// that allow developers to document the locking policies of multi-threaded
// code. The annotations can also help program analysis tools to identify
// potential thread safety issues.
//
// These annotations are implemented using compiler attributes. Using the macros
// defined here instead of raw attributes allow for portability and future
// compatibility.
//
// When referring to mutexes in the arguments of the attributes, you should
// use variable names or more complex expressions (e.g. my_object->mutex_)
// that evaluate to a concrete mutex object whenever possible. If the mutex
// you want to refer to is not in scope, you may use a member pointer
// (e.g. &MyClass::mutex_) to refer to a mutex in some (unknown) object.
#ifndef ABSL_BASE_THREAD_ANNOTATIONS_H_
#define ABSL_BASE_THREAD_ANNOTATIONS_H_
#include "absl/base/attributes.h"
#include "absl/base/config.h"
// ABSL_GUARDED_BY()
//
// Documents if a shared field or global variable needs to be protected by a
// mutex. ABSL_GUARDED_BY() allows the user to specify a particular mutex that
// should be held when accessing the annotated variable.
//
// Although this annotation (and ABSL_PT_GUARDED_BY, below) cannot be applied to
// local variables, a local variable and its associated mutex can often be
// combined into a small class or struct, thereby allowing the annotation.
//
// Example:
//
// class Foo {
// Mutex mu_;
// int p1_ ABSL_GUARDED_BY(mu_);
// ...
// };
#if ABSL_HAVE_ATTRIBUTE(guarded_by)
#define ABSL_GUARDED_BY(x) __attribute__((guarded_by(x)))
#else
#define ABSL_GUARDED_BY(x)
#endif
// ABSL_PT_GUARDED_BY()
//
// Documents if the memory location pointed to by a pointer should be guarded
// by a mutex when dereferencing the pointer.
//
// Example:
// class Foo {
// Mutex mu_;
// int *p1_ ABSL_PT_GUARDED_BY(mu_);
// ...
// };
//
// Note that a pointer variable to a shared memory location could itself be a
// shared variable.
//
// Example:
//
// // `q_`, guarded by `mu1_`, points to a shared memory location that is
// // guarded by `mu2_`:
// int *q_ ABSL_GUARDED_BY(mu1_) ABSL_PT_GUARDED_BY(mu2_);
#if ABSL_HAVE_ATTRIBUTE(pt_guarded_by)
#define ABSL_PT_GUARDED_BY(x) __attribute__((pt_guarded_by(x)))
#else
#define ABSL_PT_GUARDED_BY(x)
#endif
// ABSL_ACQUIRED_AFTER() / ABSL_ACQUIRED_BEFORE()
//
// Documents the acquisition order between locks that can be held
// simultaneously by a thread. For any two locks that need to be annotated
// to establish an acquisition order, only one of them needs the annotation.
// (i.e. You don't have to annotate both locks with both ABSL_ACQUIRED_AFTER
// and ABSL_ACQUIRED_BEFORE.)
//
// As with ABSL_GUARDED_BY, this is only applicable to mutexes that are shared
// fields or global variables.
//
// Example:
//
// Mutex m1_;
// Mutex m2_ ABSL_ACQUIRED_AFTER(m1_);
#if ABSL_HAVE_ATTRIBUTE(acquired_after)
#define ABSL_ACQUIRED_AFTER(...) __attribute__((acquired_after(__VA_ARGS__)))
#else
#define ABSL_ACQUIRED_AFTER(...)
#endif
#if ABSL_HAVE_ATTRIBUTE(acquired_before)
#define ABSL_ACQUIRED_BEFORE(...) __attribute__((acquired_before(__VA_ARGS__)))
#else
#define ABSL_ACQUIRED_BEFORE(...)
#endif
// ABSL_EXCLUSIVE_LOCKS_REQUIRED() / ABSL_SHARED_LOCKS_REQUIRED()
//
// Documents a function that expects a mutex to be held prior to entry.
// The mutex is expected to be held both on entry to, and exit from, the
// function.
//
// An exclusive lock allows read-write access to the guarded data member(s), and
// only one thread can acquire a lock exclusively at any one time. A shared lock
// allows read-only access, and any number of threads can acquire a shared lock
// concurrently.
//
// Generally, non-const methods should be annotated with
// ABSL_EXCLUSIVE_LOCKS_REQUIRED, while const methods should be annotated with
// ABSL_SHARED_LOCKS_REQUIRED.
//
// Example:
//
// Mutex mu1, mu2;
// int a ABSL_GUARDED_BY(mu1);
// int b ABSL_GUARDED_BY(mu2);
//
// void foo() ABSL_EXCLUSIVE_LOCKS_REQUIRED(mu1, mu2) { ... }
// void bar() const ABSL_SHARED_LOCKS_REQUIRED(mu1, mu2) { ... }
#if ABSL_HAVE_ATTRIBUTE(exclusive_locks_required)
#define ABSL_EXCLUSIVE_LOCKS_REQUIRED(...) \
__attribute__((exclusive_locks_required(__VA_ARGS__)))
#else
#define ABSL_EXCLUSIVE_LOCKS_REQUIRED(...)
#endif
#if ABSL_HAVE_ATTRIBUTE(shared_locks_required)
#define ABSL_SHARED_LOCKS_REQUIRED(...) \
__attribute__((shared_locks_required(__VA_ARGS__)))
#else
#define ABSL_SHARED_LOCKS_REQUIRED(...)
#endif
// ABSL_LOCKS_EXCLUDED()
//
// Documents the locks that cannot be held by callers of this function, as they
// might be acquired by this function (Abseil's `Mutex` locks are
// non-reentrant).
#if ABSL_HAVE_ATTRIBUTE(locks_excluded)
#define ABSL_LOCKS_EXCLUDED(...) __attribute__((locks_excluded(__VA_ARGS__)))
#else
#define ABSL_LOCKS_EXCLUDED(...)
#endif
// ABSL_LOCK_RETURNED()
//
// Documents a function that returns a mutex without acquiring it. For example,
// a public getter method that returns a pointer to a private mutex should
// be annotated with ABSL_LOCK_RETURNED.
#if ABSL_HAVE_ATTRIBUTE(lock_returned)
#define ABSL_LOCK_RETURNED(x) __attribute__((lock_returned(x)))
#else
#define ABSL_LOCK_RETURNED(x)
#endif
// ABSL_LOCKABLE
//
// Documents if a class/type is a lockable type (such as the `Mutex` class).
#if ABSL_HAVE_ATTRIBUTE(lockable)
#define ABSL_LOCKABLE __attribute__((lockable))
#else
#define ABSL_LOCKABLE
#endif
// ABSL_SCOPED_LOCKABLE
//
// Documents if a class does RAII locking (such as the `MutexLock` class).
// The constructor should use `LOCK_FUNCTION()` to specify the mutex that is
// acquired, and the destructor should use `UNLOCK_FUNCTION()` with no
// arguments; the analysis will assume that the destructor unlocks whatever the
// constructor locked.
#if ABSL_HAVE_ATTRIBUTE(scoped_lockable)
#define ABSL_SCOPED_LOCKABLE __attribute__((scoped_lockable))
#else
#define ABSL_SCOPED_LOCKABLE
#endif
// ABSL_EXCLUSIVE_LOCK_FUNCTION()
//
// Documents functions that acquire a lock in the body of a function, and do
// not release it.
#if ABSL_HAVE_ATTRIBUTE(exclusive_lock_function)
#define ABSL_EXCLUSIVE_LOCK_FUNCTION(...) \
__attribute__((exclusive_lock_function(__VA_ARGS__)))
#else
#define ABSL_EXCLUSIVE_LOCK_FUNCTION(...)
#endif
// ABSL_SHARED_LOCK_FUNCTION()
//
// Documents functions that acquire a shared (reader) lock in the body of a
// function, and do not release it.
#if ABSL_HAVE_ATTRIBUTE(shared_lock_function)
#define ABSL_SHARED_LOCK_FUNCTION(...) \
__attribute__((shared_lock_function(__VA_ARGS__)))
#else
#define ABSL_SHARED_LOCK_FUNCTION(...)
#endif
// ABSL_UNLOCK_FUNCTION()
//
// Documents functions that expect a lock to be held on entry to the function,
// and release it in the body of the function.
#if ABSL_HAVE_ATTRIBUTE(unlock_function)
#define ABSL_UNLOCK_FUNCTION(...) __attribute__((unlock_function(__VA_ARGS__)))
#else
#define ABSL_UNLOCK_FUNCTION(...)
#endif
// ABSL_EXCLUSIVE_TRYLOCK_FUNCTION() / ABSL_SHARED_TRYLOCK_FUNCTION()
//
// Documents functions that try to acquire a lock, and return success or failure
// (or a non-boolean value that can be interpreted as a boolean).
// The first argument should be `true` for functions that return `true` on
// success, or `false` for functions that return `false` on success. The second
// argument specifies the mutex that is locked on success. If unspecified, this
// mutex is assumed to be `this`.
#if ABSL_HAVE_ATTRIBUTE(exclusive_trylock_function)
#define ABSL_EXCLUSIVE_TRYLOCK_FUNCTION(...) \
__attribute__((exclusive_trylock_function(__VA_ARGS__)))
#else
#define ABSL_EXCLUSIVE_TRYLOCK_FUNCTION(...)
#endif
#if ABSL_HAVE_ATTRIBUTE(shared_trylock_function)
#define ABSL_SHARED_TRYLOCK_FUNCTION(...) \
__attribute__((shared_trylock_function(__VA_ARGS__)))
#else
#define ABSL_SHARED_TRYLOCK_FUNCTION(...)
#endif
// ABSL_ASSERT_EXCLUSIVE_LOCK() / ABSL_ASSERT_SHARED_LOCK()
//
// Documents functions that dynamically check to see if a lock is held, and fail
// if it is not held.
#if ABSL_HAVE_ATTRIBUTE(assert_exclusive_lock)
#define ABSL_ASSERT_EXCLUSIVE_LOCK(...) \
__attribute__((assert_exclusive_lock(__VA_ARGS__)))
#else
#define ABSL_ASSERT_EXCLUSIVE_LOCK(...)
#endif
#if ABSL_HAVE_ATTRIBUTE(assert_shared_lock)
#define ABSL_ASSERT_SHARED_LOCK(...) \
__attribute__((assert_shared_lock(__VA_ARGS__)))
#else
#define ABSL_ASSERT_SHARED_LOCK(...)
#endif
// ABSL_NO_THREAD_SAFETY_ANALYSIS
//
// Turns off thread safety checking within the body of a particular function.
// This annotation is used to mark functions that are known to be correct, but
// the locking behavior is more complicated than the analyzer can handle.
#if ABSL_HAVE_ATTRIBUTE(no_thread_safety_analysis)
#define ABSL_NO_THREAD_SAFETY_ANALYSIS \
__attribute__((no_thread_safety_analysis))
#else
#define ABSL_NO_THREAD_SAFETY_ANALYSIS
#endif
//------------------------------------------------------------------------------
// Tool-Supplied Annotations
//------------------------------------------------------------------------------
// ABSL_TS_UNCHECKED should be placed around lock expressions that are not valid
// C++ syntax, but which are present for documentation purposes. These
// annotations will be ignored by the analysis.
#define ABSL_TS_UNCHECKED(x) ""
// ABSL_TS_FIXME is used to mark lock expressions that are not valid C++ syntax.
// It is used by automated tools to mark and disable invalid expressions.
// The annotation should either be fixed, or changed to ABSL_TS_UNCHECKED.
#define ABSL_TS_FIXME(x) ""
// Like ABSL_NO_THREAD_SAFETY_ANALYSIS, this turns off checking within the body
// of a particular function. However, this attribute is used to mark functions
// that are incorrect and need to be fixed. It is used by automated tools to
// avoid breaking the build when the analysis is updated.
// Code owners are expected to eventually fix the routine.
#define ABSL_NO_THREAD_SAFETY_ANALYSIS_FIXME ABSL_NO_THREAD_SAFETY_ANALYSIS
// Similar to ABSL_NO_THREAD_SAFETY_ANALYSIS_FIXME, this macro marks a
// ABSL_GUARDED_BY annotation that needs to be fixed, because it is producing
// thread safety warning. It disables the ABSL_GUARDED_BY.
#define ABSL_GUARDED_BY_FIXME(x)
// Disables warnings for a single read operation. This can be used to avoid
// warnings when it is known that the read is not actually involved in a race,
// but the compiler cannot confirm that.
#define ABSL_TS_UNCHECKED_READ(x) absl::base_internal::ts_unchecked_read(x)
namespace absl {
ABSL_NAMESPACE_BEGIN
namespace base_internal {
// Takes a reference to a guarded data member, and returns an unguarded
// reference.
// Do not use this function directly, use ABSL_TS_UNCHECKED_READ instead.
template <typename T>
inline const T& ts_unchecked_read(const T& v) ABSL_NO_THREAD_SAFETY_ANALYSIS {
return v;
}
template <typename T>
inline T& ts_unchecked_read(T& v) ABSL_NO_THREAD_SAFETY_ANALYSIS {
return v;
}
} // namespace base_internal
ABSL_NAMESPACE_END
} // namespace absl
#endif // ABSL_BASE_THREAD_ANNOTATIONS_H_

View File

@@ -1,891 +0,0 @@
// Copyright 2018 The Abseil Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// -----------------------------------------------------------------------------
// File: btree_map.h
// -----------------------------------------------------------------------------
//
// This header file defines B-tree maps: sorted associative containers mapping
// keys to values.
//
// * `absl::btree_map<>`
// * `absl::btree_multimap<>`
//
// These B-tree types are similar to the corresponding types in the STL
// (`std::map` and `std::multimap`) and generally conform to the STL interfaces
// of those types. However, because they are implemented using B-trees, they
// are more efficient in most situations.
//
// Unlike `std::map` and `std::multimap`, which are commonly implemented using
// red-black tree nodes, B-tree maps use more generic B-tree nodes able to hold
// multiple values per node. Holding multiple values per node often makes
// B-tree maps perform better than their `std::map` counterparts, because
// multiple entries can be checked within the same cache hit.
//
// However, these types should not be considered drop-in replacements for
// `std::map` and `std::multimap` as there are some API differences, which are
// noted in this header file. The most consequential differences with respect to
// migrating to b-tree from the STL types are listed in the next paragraph.
// Other API differences are minor.
//
// Importantly, insertions and deletions may invalidate outstanding iterators,
// pointers, and references to elements. Such invalidations are typically only
// an issue if insertion and deletion operations are interleaved with the use of
// more than one iterator, pointer, or reference simultaneously. For this
// reason, `insert()`, `erase()`, and `extract_and_get_next()` return a valid
// iterator at the current position. Another important difference is that
// key-types must be copy-constructible.
//
// There are other API differences: first, btree iterators can be subtracted,
// and this is faster than using `std::distance`. Additionally, btree
// iterators can be advanced via `operator+=` and `operator-=`, which is faster
// than using `std::advance`.
//
// B-tree maps are not exception-safe.
#ifndef ABSL_CONTAINER_BTREE_MAP_H_
#define ABSL_CONTAINER_BTREE_MAP_H_
#include "absl/base/attributes.h"
#include "absl/container/internal/btree.h" // IWYU pragma: export
#include "absl/container/internal/btree_container.h" // IWYU pragma: export
namespace absl {
ABSL_NAMESPACE_BEGIN
namespace container_internal {
template <typename Key, typename Data, typename Compare, typename Alloc,
int TargetNodeSize, bool IsMulti>
struct map_params;
} // namespace container_internal
// absl::btree_map<>
//
// An `absl::btree_map<K, V>` is an ordered associative container of
// unique keys and associated values designed to be a more efficient replacement
// for `std::map` (in most cases).
//
// Keys are sorted using an (optional) comparison function, which defaults to
// `std::less<K>`.
//
// An `absl::btree_map<K, V>` uses a default allocator of
// `std::allocator<std::pair<const K, V>>` to allocate (and deallocate)
// nodes, and construct and destruct values within those nodes. You may
// instead specify a custom allocator `A` (which in turn requires specifying a
// custom comparator `C`) as in `absl::btree_map<K, V, C, A>`.
//
template <typename Key, typename Value, typename Compare = std::less<Key>,
typename Alloc = std::allocator<std::pair<const Key, Value>>>
class ABSL_ATTRIBUTE_OWNER btree_map
: public container_internal::btree_map_container<
container_internal::btree<container_internal::map_params<
Key, Value, Compare, Alloc, /*TargetNodeSize=*/256,
/*IsMulti=*/false>>> {
using Base = typename btree_map::btree_map_container;
public:
// Constructors and Assignment Operators
//
// A `btree_map` supports the same overload set as `std::map`
// for construction and assignment:
//
// * Default constructor
//
// absl::btree_map<int, std::string> map1;
//
// * Initializer List constructor
//
// absl::btree_map<int, std::string> map2 =
// {{1, "huey"}, {2, "dewey"}, {3, "louie"},};
//
// * Copy constructor
//
// absl::btree_map<int, std::string> map3(map2);
//
// * Copy assignment operator
//
// absl::btree_map<int, std::string> map4;
// map4 = map3;
//
// * Move constructor
//
// // Move is guaranteed efficient
// absl::btree_map<int, std::string> map5(std::move(map4));
//
// * Move assignment operator
//
// // May be efficient if allocators are compatible
// absl::btree_map<int, std::string> map6;
// map6 = std::move(map5);
//
// * Range constructor
//
// std::vector<std::pair<int, std::string>> v = {{1, "a"}, {2, "b"}};
// absl::btree_map<int, std::string> map7(v.begin(), v.end());
btree_map() {}
using Base::Base;
// btree_map::begin()
//
// Returns an iterator to the beginning of the `btree_map`.
using Base::begin;
// btree_map::cbegin()
//
// Returns a const iterator to the beginning of the `btree_map`.
using Base::cbegin;
// btree_map::end()
//
// Returns an iterator to the end of the `btree_map`.
using Base::end;
// btree_map::cend()
//
// Returns a const iterator to the end of the `btree_map`.
using Base::cend;
// btree_map::empty()
//
// Returns whether or not the `btree_map` is empty.
using Base::empty;
// btree_map::max_size()
//
// Returns the largest theoretical possible number of elements within a
// `btree_map` under current memory constraints. This value can be thought
// of as the largest value of `std::distance(begin(), end())` for a
// `btree_map<Key, T>`.
using Base::max_size;
// btree_map::size()
//
// Returns the number of elements currently within the `btree_map`.
using Base::size;
// btree_map::clear()
//
// Removes all elements from the `btree_map`. Invalidates any references,
// pointers, or iterators referring to contained elements.
using Base::clear;
// btree_map::erase()
//
// Erases elements within the `btree_map`. If an erase occurs, any references,
// pointers, or iterators are invalidated.
// Overloads are listed below.
//
// iterator erase(iterator position):
// iterator erase(const_iterator position):
//
// Erases the element at `position` of the `btree_map`, returning
// the iterator pointing to the element after the one that was erased
// (or end() if none exists).
//
// iterator erase(const_iterator first, const_iterator last):
//
// Erases the elements in the open interval [`first`, `last`), returning
// the iterator pointing to the element after the interval that was erased
// (or end() if none exists).
//
// template <typename K> size_type erase(const K& key):
//
// Erases the element with the matching key, if it exists, returning the
// number of elements erased (0 or 1).
using Base::erase;
// btree_map::insert()
//
// Inserts an element of the specified value into the `btree_map`,
// returning an iterator pointing to the newly inserted element, provided that
// an element with the given key does not already exist. If an insertion
// occurs, any references, pointers, or iterators are invalidated.
// Overloads are listed below.
//
// std::pair<iterator,bool> insert(const value_type& value):
//
// Inserts a value into the `btree_map`. Returns a pair consisting of an
// iterator to the inserted element (or to the element that prevented the
// insertion) and a bool denoting whether the insertion took place.
//
// std::pair<iterator,bool> insert(value_type&& value):
//
// Inserts a moveable value into the `btree_map`. Returns a pair
// consisting of an iterator to the inserted element (or to the element that
// prevented the insertion) and a bool denoting whether the insertion took
// place.
//
// iterator insert(const_iterator hint, const value_type& value):
// iterator insert(const_iterator hint, value_type&& value):
//
// Inserts a value, using the position of `hint` as a non-binding suggestion
// for where to begin the insertion search. Returns an iterator to the
// inserted element, or to the existing element that prevented the
// insertion.
//
// void insert(InputIterator first, InputIterator last):
//
// Inserts a range of values [`first`, `last`).
//
// void insert(std::initializer_list<init_type> ilist):
//
// Inserts the elements within the initializer list `ilist`.
using Base::insert;
// btree_map::insert_or_assign()
//
// Inserts an element of the specified value into the `btree_map` provided
// that a value with the given key does not already exist, or replaces the
// corresponding mapped type with the forwarded `obj` argument if a key for
// that value already exists, returning an iterator pointing to the newly
// inserted element. Overloads are listed below.
//
// pair<iterator, bool> insert_or_assign(const key_type& k, M&& obj):
// pair<iterator, bool> insert_or_assign(key_type&& k, M&& obj):
//
// Inserts/Assigns (or moves) the element of the specified key into the
// `btree_map`. If the returned bool is true, insertion took place, and if
// it's false, assignment took place.
//
// iterator insert_or_assign(const_iterator hint,
// const key_type& k, M&& obj):
// iterator insert_or_assign(const_iterator hint, key_type&& k, M&& obj):
//
// Inserts/Assigns (or moves) the element of the specified key into the
// `btree_map` using the position of `hint` as a non-binding suggestion
// for where to begin the insertion search.
using Base::insert_or_assign;
// btree_map::emplace()
//
// Inserts an element of the specified value by constructing it in-place
// within the `btree_map`, provided that no element with the given key
// already exists.
//
// The element may be constructed even if there already is an element with the
// key in the container, in which case the newly constructed element will be
// destroyed immediately. Prefer `try_emplace()` unless your key is not
// copyable or moveable.
//
// If an insertion occurs, any references, pointers, or iterators are
// invalidated.
using Base::emplace;
// btree_map::emplace_hint()
//
// Inserts an element of the specified value by constructing it in-place
// within the `btree_map`, using the position of `hint` as a non-binding
// suggestion for where to begin the insertion search, and only inserts
// provided that no element with the given key already exists.
//
// The element may be constructed even if there already is an element with the
// key in the container, in which case the newly constructed element will be
// destroyed immediately. Prefer `try_emplace()` unless your key is not
// copyable or moveable.
//
// If an insertion occurs, any references, pointers, or iterators are
// invalidated.
using Base::emplace_hint;
// btree_map::try_emplace()
//
// Inserts an element of the specified value by constructing it in-place
// within the `btree_map`, provided that no element with the given key
// already exists. Unlike `emplace()`, if an element with the given key
// already exists, we guarantee that no element is constructed.
//
// If an insertion occurs, any references, pointers, or iterators are
// invalidated.
//
// Overloads are listed below.
//
// std::pair<iterator, bool> try_emplace(const key_type& k, Args&&... args):
// std::pair<iterator, bool> try_emplace(key_type&& k, Args&&... args):
//
// Inserts (via copy or move) the element of the specified key into the
// `btree_map`.
//
// iterator try_emplace(const_iterator hint,
// const key_type& k, Args&&... args):
// iterator try_emplace(const_iterator hint, key_type&& k, Args&&... args):
//
// Inserts (via copy or move) the element of the specified key into the
// `btree_map` using the position of `hint` as a non-binding suggestion
// for where to begin the insertion search.
using Base::try_emplace;
// btree_map::extract()
//
// Extracts the indicated element, erasing it in the process, and returns it
// as a C++17-compatible node handle. Any references, pointers, or iterators
// are invalidated. Overloads are listed below.
//
// node_type extract(const_iterator position):
//
// Extracts the element at the indicated position and returns a node handle
// owning that extracted data.
//
// template <typename K> node_type extract(const K& k):
//
// Extracts the element with the key matching the passed key value and
// returns a node handle owning that extracted data. If the `btree_map`
// does not contain an element with a matching key, this function returns an
// empty node handle.
//
// NOTE: when compiled in an earlier version of C++ than C++17,
// `node_type::key()` returns a const reference to the key instead of a
// mutable reference. We cannot safely return a mutable reference without
// std::launder (which is not available before C++17).
//
// NOTE: In this context, `node_type` refers to the C++17 concept of a
// move-only type that owns and provides access to the elements in associative
// containers (https://en.cppreference.com/w/cpp/container/node_handle).
// It does NOT refer to the data layout of the underlying btree.
using Base::extract;
// btree_map::extract_and_get_next()
//
// Extracts the indicated element, erasing it in the process, and returns it
// as a C++17-compatible node handle along with an iterator to the next
// element.
//
// extract_and_get_next_return_type extract_and_get_next(
// const_iterator position):
//
// Extracts the element at the indicated position, returns a struct
// containing a member named `node`: a node handle owning that extracted
// data and a member named `next`: an iterator pointing to the next element
// in the btree.
using Base::extract_and_get_next;
// btree_map::merge()
//
// Extracts elements from a given `source` btree_map into this
// `btree_map`. If the destination `btree_map` already contains an
// element with an equivalent key, that element is not extracted.
using Base::merge;
// btree_map::swap(btree_map& other)
//
// Exchanges the contents of this `btree_map` with those of the `other`
// btree_map, avoiding invocation of any move, copy, or swap operations on
// individual elements.
//
// All iterators and references on the `btree_map` remain valid, excepting
// for the past-the-end iterator, which is invalidated.
using Base::swap;
// btree_map::at()
//
// Returns a reference to the mapped value of the element with key equivalent
// to the passed key.
using Base::at;
// btree_map::contains()
//
// template <typename K> bool contains(const K& key) const:
//
// Determines whether an element comparing equal to the given `key` exists
// within the `btree_map`, returning `true` if so or `false` otherwise.
//
// Supports heterogeneous lookup, provided that the map has a compatible
// heterogeneous comparator.
using Base::contains;
// btree_map::count()
//
// template <typename K> size_type count(const K& key) const:
//
// Returns the number of elements comparing equal to the given `key` within
// the `btree_map`. Note that this function will return either `1` or `0`
// since duplicate elements are not allowed within a `btree_map`.
//
// Supports heterogeneous lookup, provided that the map has a compatible
// heterogeneous comparator.
using Base::count;
// btree_map::equal_range()
//
// Returns a half-open range [first, last), defined by a `std::pair` of two
// iterators, containing all elements with the passed key in the `btree_map`.
using Base::equal_range;
// btree_map::find()
//
// template <typename K> iterator find(const K& key):
// template <typename K> const_iterator find(const K& key) const:
//
// Finds an element with the passed `key` within the `btree_map`.
//
// Supports heterogeneous lookup, provided that the map has a compatible
// heterogeneous comparator.
using Base::find;
// btree_map::lower_bound()
//
// template <typename K> iterator lower_bound(const K& key):
// template <typename K> const_iterator lower_bound(const K& key) const:
//
// Finds the first element with a key that is not less than `key` within the
// `btree_map`.
//
// Supports heterogeneous lookup, provided that the map has a compatible
// heterogeneous comparator.
using Base::lower_bound;
// btree_map::upper_bound()
//
// template <typename K> iterator upper_bound(const K& key):
// template <typename K> const_iterator upper_bound(const K& key) const:
//
// Finds the first element with a key that is greater than `key` within the
// `btree_map`.
//
// Supports heterogeneous lookup, provided that the map has a compatible
// heterogeneous comparator.
using Base::upper_bound;
// btree_map::operator[]()
//
// Returns a reference to the value mapped to the passed key within the
// `btree_map`, performing an `insert()` if the key does not already
// exist.
//
// If an insertion occurs, any references, pointers, or iterators are
// invalidated. Otherwise iterators are not affected and references are not
// invalidated. Overloads are listed below.
//
// T& operator[](key_type&& key):
// T& operator[](const key_type& key):
//
// Inserts a value_type object constructed in-place if the element with the
// given key does not exist.
using Base::operator[];
// btree_map::get_allocator()
//
// Returns the allocator function associated with this `btree_map`.
using Base::get_allocator;
// btree_map::key_comp();
//
// Returns the key comparator associated with this `btree_map`.
using Base::key_comp;
// btree_map::value_comp();
//
// Returns the value comparator associated with this `btree_map`.
using Base::value_comp;
};
// absl::swap(absl::btree_map<>, absl::btree_map<>)
//
// Swaps the contents of two `absl::btree_map` containers.
template <typename K, typename V, typename C, typename A>
void swap(btree_map<K, V, C, A> &x, btree_map<K, V, C, A> &y) {
return x.swap(y);
}
// absl::erase_if(absl::btree_map<>, Pred)
//
// Erases all elements that satisfy the predicate pred from the container.
// Returns the number of erased elements.
template <typename K, typename V, typename C, typename A, typename Pred>
typename btree_map<K, V, C, A>::size_type erase_if(
btree_map<K, V, C, A> &map, Pred pred) {
return container_internal::btree_access::erase_if(map, std::move(pred));
}
// absl::btree_multimap
//
// An `absl::btree_multimap<K, V>` is an ordered associative container of
// keys and associated values designed to be a more efficient replacement for
// `std::multimap` (in most cases). Unlike `absl::btree_map`, a B-tree multimap
// allows multiple elements with equivalent keys.
//
// Keys are sorted using an (optional) comparison function, which defaults to
// `std::less<K>`.
//
// An `absl::btree_multimap<K, V>` uses a default allocator of
// `std::allocator<std::pair<const K, V>>` to allocate (and deallocate)
// nodes, and construct and destruct values within those nodes. You may
// instead specify a custom allocator `A` (which in turn requires specifying a
// custom comparator `C`) as in `absl::btree_multimap<K, V, C, A>`.
//
template <typename Key, typename Value, typename Compare = std::less<Key>,
typename Alloc = std::allocator<std::pair<const Key, Value>>>
class ABSL_ATTRIBUTE_OWNER btree_multimap
: public container_internal::btree_multimap_container<
container_internal::btree<container_internal::map_params<
Key, Value, Compare, Alloc, /*TargetNodeSize=*/256,
/*IsMulti=*/true>>> {
using Base = typename btree_multimap::btree_multimap_container;
public:
// Constructors and Assignment Operators
//
// A `btree_multimap` supports the same overload set as `std::multimap`
// for construction and assignment:
//
// * Default constructor
//
// absl::btree_multimap<int, std::string> map1;
//
// * Initializer List constructor
//
// absl::btree_multimap<int, std::string> map2 =
// {{1, "huey"}, {2, "dewey"}, {3, "louie"},};
//
// * Copy constructor
//
// absl::btree_multimap<int, std::string> map3(map2);
//
// * Copy assignment operator
//
// absl::btree_multimap<int, std::string> map4;
// map4 = map3;
//
// * Move constructor
//
// // Move is guaranteed efficient
// absl::btree_multimap<int, std::string> map5(std::move(map4));
//
// * Move assignment operator
//
// // May be efficient if allocators are compatible
// absl::btree_multimap<int, std::string> map6;
// map6 = std::move(map5);
//
// * Range constructor
//
// std::vector<std::pair<int, std::string>> v = {{1, "a"}, {2, "b"}};
// absl::btree_multimap<int, std::string> map7(v.begin(), v.end());
btree_multimap() {}
using Base::Base;
// btree_multimap::begin()
//
// Returns an iterator to the beginning of the `btree_multimap`.
using Base::begin;
// btree_multimap::cbegin()
//
// Returns a const iterator to the beginning of the `btree_multimap`.
using Base::cbegin;
// btree_multimap::end()
//
// Returns an iterator to the end of the `btree_multimap`.
using Base::end;
// btree_multimap::cend()
//
// Returns a const iterator to the end of the `btree_multimap`.
using Base::cend;
// btree_multimap::empty()
//
// Returns whether or not the `btree_multimap` is empty.
using Base::empty;
// btree_multimap::max_size()
//
// Returns the largest theoretical possible number of elements within a
// `btree_multimap` under current memory constraints. This value can be
// thought of as the largest value of `std::distance(begin(), end())` for a
// `btree_multimap<Key, T>`.
using Base::max_size;
// btree_multimap::size()
//
// Returns the number of elements currently within the `btree_multimap`.
using Base::size;
// btree_multimap::clear()
//
// Removes all elements from the `btree_multimap`. Invalidates any references,
// pointers, or iterators referring to contained elements.
using Base::clear;
// btree_multimap::erase()
//
// Erases elements within the `btree_multimap`. If an erase occurs, any
// references, pointers, or iterators are invalidated.
// Overloads are listed below.
//
// iterator erase(iterator position):
// iterator erase(const_iterator position):
//
// Erases the element at `position` of the `btree_multimap`, returning
// the iterator pointing to the element after the one that was erased
// (or end() if none exists).
//
// iterator erase(const_iterator first, const_iterator last):
//
// Erases the elements in the open interval [`first`, `last`), returning
// the iterator pointing to the element after the interval that was erased
// (or end() if none exists).
//
// template <typename K> size_type erase(const K& key):
//
// Erases the elements matching the key, if any exist, returning the
// number of elements erased.
using Base::erase;
// btree_multimap::insert()
//
// Inserts an element of the specified value into the `btree_multimap`,
// returning an iterator pointing to the newly inserted element.
// Any references, pointers, or iterators are invalidated. Overloads are
// listed below.
//
// iterator insert(const value_type& value):
//
// Inserts a value into the `btree_multimap`, returning an iterator to the
// inserted element.
//
// iterator insert(value_type&& value):
//
// Inserts a moveable value into the `btree_multimap`, returning an iterator
// to the inserted element.
//
// iterator insert(const_iterator hint, const value_type& value):
// iterator insert(const_iterator hint, value_type&& value):
//
// Inserts a value, using the position of `hint` as a non-binding suggestion
// for where to begin the insertion search. Returns an iterator to the
// inserted element.
//
// void insert(InputIterator first, InputIterator last):
//
// Inserts a range of values [`first`, `last`).
//
// void insert(std::initializer_list<init_type> ilist):
//
// Inserts the elements within the initializer list `ilist`.
using Base::insert;
// btree_multimap::emplace()
//
// Inserts an element of the specified value by constructing it in-place
// within the `btree_multimap`. Any references, pointers, or iterators are
// invalidated.
using Base::emplace;
// btree_multimap::emplace_hint()
//
// Inserts an element of the specified value by constructing it in-place
// within the `btree_multimap`, using the position of `hint` as a non-binding
// suggestion for where to begin the insertion search.
//
// Any references, pointers, or iterators are invalidated.
using Base::emplace_hint;
// btree_multimap::extract()
//
// Extracts the indicated element, erasing it in the process, and returns it
// as a C++17-compatible node handle. Overloads are listed below.
//
// node_type extract(const_iterator position):
//
// Extracts the element at the indicated position and returns a node handle
// owning that extracted data.
//
// template <typename K> node_type extract(const K& k):
//
// Extracts the element with the key matching the passed key value and
// returns a node handle owning that extracted data. If the `btree_multimap`
// does not contain an element with a matching key, this function returns an
// empty node handle.
//
// NOTE: when compiled in an earlier version of C++ than C++17,
// `node_type::key()` returns a const reference to the key instead of a
// mutable reference. We cannot safely return a mutable reference without
// std::launder (which is not available before C++17).
//
// NOTE: In this context, `node_type` refers to the C++17 concept of a
// move-only type that owns and provides access to the elements in associative
// containers (https://en.cppreference.com/w/cpp/container/node_handle).
// It does NOT refer to the data layout of the underlying btree.
using Base::extract;
// btree_multimap::extract_and_get_next()
//
// Extracts the indicated element, erasing it in the process, and returns it
// as a C++17-compatible node handle along with an iterator to the next
// element.
//
// extract_and_get_next_return_type extract_and_get_next(
// const_iterator position):
//
// Extracts the element at the indicated position, returns a struct
// containing a member named `node`: a node handle owning that extracted
// data and a member named `next`: an iterator pointing to the next element
// in the btree.
using Base::extract_and_get_next;
// btree_multimap::merge()
//
// Extracts all elements from a given `source` btree_multimap into this
// `btree_multimap`.
using Base::merge;
// btree_multimap::swap(btree_multimap& other)
//
// Exchanges the contents of this `btree_multimap` with those of the `other`
// btree_multimap, avoiding invocation of any move, copy, or swap operations
// on individual elements.
//
// All iterators and references on the `btree_multimap` remain valid,
// excepting for the past-the-end iterator, which is invalidated.
using Base::swap;
// btree_multimap::contains()
//
// template <typename K> bool contains(const K& key) const:
//
// Determines whether an element comparing equal to the given `key` exists
// within the `btree_multimap`, returning `true` if so or `false` otherwise.
//
// Supports heterogeneous lookup, provided that the map has a compatible
// heterogeneous comparator.
using Base::contains;
// btree_multimap::count()
//
// template <typename K> size_type count(const K& key) const:
//
// Returns the number of elements comparing equal to the given `key` within
// the `btree_multimap`.
//
// Supports heterogeneous lookup, provided that the map has a compatible
// heterogeneous comparator.
using Base::count;
// btree_multimap::equal_range()
//
// Returns a half-open range [first, last), defined by a `std::pair` of two
// iterators, containing all elements with the passed key in the
// `btree_multimap`.
using Base::equal_range;
// btree_multimap::find()
//
// template <typename K> iterator find(const K& key):
// template <typename K> const_iterator find(const K& key) const:
//
// Finds an element with the passed `key` within the `btree_multimap`.
//
// Supports heterogeneous lookup, provided that the map has a compatible
// heterogeneous comparator.
using Base::find;
// btree_multimap::lower_bound()
//
// template <typename K> iterator lower_bound(const K& key):
// template <typename K> const_iterator lower_bound(const K& key) const:
//
// Finds the first element with a key that is not less than `key` within the
// `btree_multimap`.
//
// Supports heterogeneous lookup, provided that the map has a compatible
// heterogeneous comparator.
using Base::lower_bound;
// btree_multimap::upper_bound()
//
// template <typename K> iterator upper_bound(const K& key):
// template <typename K> const_iterator upper_bound(const K& key) const:
//
// Finds the first element with a key that is greater than `key` within the
// `btree_multimap`.
//
// Supports heterogeneous lookup, provided that the map has a compatible
// heterogeneous comparator.
using Base::upper_bound;
// btree_multimap::get_allocator()
//
// Returns the allocator function associated with this `btree_multimap`.
using Base::get_allocator;
// btree_multimap::key_comp();
//
// Returns the key comparator associated with this `btree_multimap`.
using Base::key_comp;
// btree_multimap::value_comp();
//
// Returns the value comparator associated with this `btree_multimap`.
using Base::value_comp;
};
// absl::swap(absl::btree_multimap<>, absl::btree_multimap<>)
//
// Swaps the contents of two `absl::btree_multimap` containers.
template <typename K, typename V, typename C, typename A>
void swap(btree_multimap<K, V, C, A> &x, btree_multimap<K, V, C, A> &y) {
return x.swap(y);
}
// absl::erase_if(absl::btree_multimap<>, Pred)
//
// Erases all elements that satisfy the predicate pred from the container.
// Returns the number of erased elements.
template <typename K, typename V, typename C, typename A, typename Pred>
typename btree_multimap<K, V, C, A>::size_type erase_if(
btree_multimap<K, V, C, A> &map, Pred pred) {
return container_internal::btree_access::erase_if(map, std::move(pred));
}
namespace container_internal {
// A parameters structure for holding the type parameters for a btree_map.
// Compare and Alloc should be nothrow copy-constructible.
template <typename Key, typename Data, typename Compare, typename Alloc,
int TargetNodeSize, bool IsMulti>
struct map_params : common_params<Key, Compare, Alloc, TargetNodeSize, IsMulti,
/*IsMap=*/true, map_slot_policy<Key, Data>> {
using super_type = typename map_params::common_params;
using mapped_type = Data;
// This type allows us to move keys when it is safe to do so. It is safe
// for maps in which value_type and mutable_value_type are layout compatible.
using slot_policy = typename super_type::slot_policy;
using slot_type = typename super_type::slot_type;
using value_type = typename super_type::value_type;
using init_type = typename super_type::init_type;
template <typename V>
static auto key(const V &value ABSL_ATTRIBUTE_LIFETIME_BOUND)
-> decltype((value.first)) {
return value.first;
}
static const Key &key(const slot_type *s) { return slot_policy::key(s); }
static const Key &key(slot_type *s) { return slot_policy::key(s); }
// For use in node handle.
static auto mutable_key(slot_type *s)
-> decltype(slot_policy::mutable_key(s)) {
return slot_policy::mutable_key(s);
}
static mapped_type &value(value_type *value) { return value->second; }
};
} // namespace container_internal
ABSL_NAMESPACE_END
} // namespace absl
#endif // ABSL_CONTAINER_BTREE_MAP_H_

View File

@@ -1,826 +0,0 @@
// Copyright 2018 The Abseil Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// -----------------------------------------------------------------------------
// File: btree_set.h
// -----------------------------------------------------------------------------
//
// This header file defines B-tree sets: sorted associative containers of
// values.
//
// * `absl::btree_set<>`
// * `absl::btree_multiset<>`
//
// These B-tree types are similar to the corresponding types in the STL
// (`std::set` and `std::multiset`) and generally conform to the STL interfaces
// of those types. However, because they are implemented using B-trees, they
// are more efficient in most situations.
//
// Unlike `std::set` and `std::multiset`, which are commonly implemented using
// red-black tree nodes, B-tree sets use more generic B-tree nodes able to hold
// multiple values per node. Holding multiple values per node often makes
// B-tree sets perform better than their `std::set` counterparts, because
// multiple entries can be checked within the same cache hit.
//
// However, these types should not be considered drop-in replacements for
// `std::set` and `std::multiset` as there are some API differences, which are
// noted in this header file. The most consequential differences with respect to
// migrating to b-tree from the STL types are listed in the next paragraph.
// Other API differences are minor.
//
// Importantly, insertions and deletions may invalidate outstanding iterators,
// pointers, and references to elements. Such invalidations are typically only
// an issue if insertion and deletion operations are interleaved with the use of
// more than one iterator, pointer, or reference simultaneously. For this
// reason, `insert()`, `erase()`, and `extract_and_get_next()` return a valid
// iterator at the current position.
//
// There are other API differences: first, btree iterators can be subtracted,
// and this is faster than using `std::distance`. Additionally, btree
// iterators can be advanced via `operator+=` and `operator-=`, which is faster
// than using `std::advance`.
//
// B-tree sets are not exception-safe.
#ifndef ABSL_CONTAINER_BTREE_SET_H_
#define ABSL_CONTAINER_BTREE_SET_H_
#include "absl/base/attributes.h"
#include "absl/container/internal/btree.h" // IWYU pragma: export
#include "absl/container/internal/btree_container.h" // IWYU pragma: export
namespace absl {
ABSL_NAMESPACE_BEGIN
namespace container_internal {
template <typename Key>
struct set_slot_policy;
template <typename Key, typename Compare, typename Alloc, int TargetNodeSize,
bool IsMulti>
struct set_params;
} // namespace container_internal
// absl::btree_set<>
//
// An `absl::btree_set<K>` is an ordered associative container of unique key
// values designed to be a more efficient replacement for `std::set` (in most
// cases).
//
// Keys are sorted using an (optional) comparison function, which defaults to
// `std::less<K>`.
//
// An `absl::btree_set<K>` uses a default allocator of `std::allocator<K>` to
// allocate (and deallocate) nodes, and construct and destruct values within
// those nodes. You may instead specify a custom allocator `A` (which in turn
// requires specifying a custom comparator `C`) as in
// `absl::btree_set<K, C, A>`.
//
template <typename Key, typename Compare = std::less<Key>,
typename Alloc = std::allocator<Key>>
class ABSL_ATTRIBUTE_OWNER btree_set
: public container_internal::btree_set_container<
container_internal::btree<container_internal::set_params<
Key, Compare, Alloc, /*TargetNodeSize=*/256,
/*IsMulti=*/false>>> {
using Base = typename btree_set::btree_set_container;
public:
// Constructors and Assignment Operators
//
// A `btree_set` supports the same overload set as `std::set`
// for construction and assignment:
//
// * Default constructor
//
// absl::btree_set<std::string> set1;
//
// * Initializer List constructor
//
// absl::btree_set<std::string> set2 =
// {{"huey"}, {"dewey"}, {"louie"},};
//
// * Copy constructor
//
// absl::btree_set<std::string> set3(set2);
//
// * Copy assignment operator
//
// absl::btree_set<std::string> set4;
// set4 = set3;
//
// * Move constructor
//
// // Move is guaranteed efficient
// absl::btree_set<std::string> set5(std::move(set4));
//
// * Move assignment operator
//
// // May be efficient if allocators are compatible
// absl::btree_set<std::string> set6;
// set6 = std::move(set5);
//
// * Range constructor
//
// std::vector<std::string> v = {"a", "b"};
// absl::btree_set<std::string> set7(v.begin(), v.end());
btree_set() {}
using Base::Base;
// btree_set::begin()
//
// Returns an iterator to the beginning of the `btree_set`.
using Base::begin;
// btree_set::cbegin()
//
// Returns a const iterator to the beginning of the `btree_set`.
using Base::cbegin;
// btree_set::end()
//
// Returns an iterator to the end of the `btree_set`.
using Base::end;
// btree_set::cend()
//
// Returns a const iterator to the end of the `btree_set`.
using Base::cend;
// btree_set::empty()
//
// Returns whether or not the `btree_set` is empty.
using Base::empty;
// btree_set::max_size()
//
// Returns the largest theoretical possible number of elements within a
// `btree_set` under current memory constraints. This value can be thought
// of as the largest value of `std::distance(begin(), end())` for a
// `btree_set<Key>`.
using Base::max_size;
// btree_set::size()
//
// Returns the number of elements currently within the `btree_set`.
using Base::size;
// btree_set::clear()
//
// Removes all elements from the `btree_set`. Invalidates any references,
// pointers, or iterators referring to contained elements.
using Base::clear;
// btree_set::erase()
//
// Erases elements within the `btree_set`. Overloads are listed below.
//
// iterator erase(iterator position):
// iterator erase(const_iterator position):
//
// Erases the element at `position` of the `btree_set`, returning
// the iterator pointing to the element after the one that was erased
// (or end() if none exists).
//
// iterator erase(const_iterator first, const_iterator last):
//
// Erases the elements in the open interval [`first`, `last`), returning
// the iterator pointing to the element after the interval that was erased
// (or end() if none exists).
//
// template <typename K> size_type erase(const K& key):
//
// Erases the element with the matching key, if it exists, returning the
// number of elements erased (0 or 1).
using Base::erase;
// btree_set::insert()
//
// Inserts an element of the specified value into the `btree_set`,
// returning an iterator pointing to the newly inserted element, provided that
// an element with the given key does not already exist. If an insertion
// occurs, any references, pointers, or iterators are invalidated.
// Overloads are listed below.
//
// std::pair<iterator,bool> insert(const value_type& value):
//
// Inserts a value into the `btree_set`. Returns a pair consisting of an
// iterator to the inserted element (or to the element that prevented the
// insertion) and a bool denoting whether the insertion took place.
//
// std::pair<iterator,bool> insert(value_type&& value):
//
// Inserts a moveable value into the `btree_set`. Returns a pair
// consisting of an iterator to the inserted element (or to the element that
// prevented the insertion) and a bool denoting whether the insertion took
// place.
//
// iterator insert(const_iterator hint, const value_type& value):
// iterator insert(const_iterator hint, value_type&& value):
//
// Inserts a value, using the position of `hint` as a non-binding suggestion
// for where to begin the insertion search. Returns an iterator to the
// inserted element, or to the existing element that prevented the
// insertion.
//
// void insert(InputIterator first, InputIterator last):
//
// Inserts a range of values [`first`, `last`).
//
// void insert(std::initializer_list<init_type> ilist):
//
// Inserts the elements within the initializer list `ilist`.
using Base::insert;
// btree_set::emplace()
//
// Inserts an element of the specified value by constructing it in-place
// within the `btree_set`, provided that no element with the given key
// already exists.
//
// The element may be constructed even if there already is an element with the
// key in the container, in which case the newly constructed element will be
// destroyed immediately.
//
// If an insertion occurs, any references, pointers, or iterators are
// invalidated.
using Base::emplace;
// btree_set::emplace_hint()
//
// Inserts an element of the specified value by constructing it in-place
// within the `btree_set`, using the position of `hint` as a non-binding
// suggestion for where to begin the insertion search, and only inserts
// provided that no element with the given key already exists.
//
// The element may be constructed even if there already is an element with the
// key in the container, in which case the newly constructed element will be
// destroyed immediately.
//
// If an insertion occurs, any references, pointers, or iterators are
// invalidated.
using Base::emplace_hint;
// btree_set::extract()
//
// Extracts the indicated element, erasing it in the process, and returns it
// as a C++17-compatible node handle. Any references, pointers, or iterators
// are invalidated. Overloads are listed below.
//
// node_type extract(const_iterator position):
//
// Extracts the element at the indicated position and returns a node handle
// owning that extracted data.
//
// template <typename K> node_type extract(const K& k):
//
// Extracts the element with the key matching the passed key value and
// returns a node handle owning that extracted data. If the `btree_set`
// does not contain an element with a matching key, this function returns an
// empty node handle.
//
// NOTE: In this context, `node_type` refers to the C++17 concept of a
// move-only type that owns and provides access to the elements in associative
// containers (https://en.cppreference.com/w/cpp/container/node_handle).
// It does NOT refer to the data layout of the underlying btree.
using Base::extract;
// btree_set::extract_and_get_next()
//
// Extracts the indicated element, erasing it in the process, and returns it
// as a C++17-compatible node handle along with an iterator to the next
// element.
//
// extract_and_get_next_return_type extract_and_get_next(
// const_iterator position):
//
// Extracts the element at the indicated position, returns a struct
// containing a member named `node`: a node handle owning that extracted
// data and a member named `next`: an iterator pointing to the next element
// in the btree.
using Base::extract_and_get_next;
// btree_set::merge()
//
// Extracts elements from a given `source` btree_set into this
// `btree_set`. If the destination `btree_set` already contains an
// element with an equivalent key, that element is not extracted.
using Base::merge;
// btree_set::swap(btree_set& other)
//
// Exchanges the contents of this `btree_set` with those of the `other`
// btree_set, avoiding invocation of any move, copy, or swap operations on
// individual elements.
//
// All iterators and references on the `btree_set` remain valid, excepting
// for the past-the-end iterator, which is invalidated.
using Base::swap;
// btree_set::contains()
//
// template <typename K> bool contains(const K& key) const:
//
// Determines whether an element comparing equal to the given `key` exists
// within the `btree_set`, returning `true` if so or `false` otherwise.
//
// Supports heterogeneous lookup, provided that the set has a compatible
// heterogeneous comparator.
using Base::contains;
// btree_set::count()
//
// template <typename K> size_type count(const K& key) const:
//
// Returns the number of elements comparing equal to the given `key` within
// the `btree_set`. Note that this function will return either `1` or `0`
// since duplicate elements are not allowed within a `btree_set`.
//
// Supports heterogeneous lookup, provided that the set has a compatible
// heterogeneous comparator.
using Base::count;
// btree_set::equal_range()
//
// Returns a closed range [first, last], defined by a `std::pair` of two
// iterators, containing all elements with the passed key in the
// `btree_set`.
using Base::equal_range;
// btree_set::find()
//
// template <typename K> iterator find(const K& key):
// template <typename K> const_iterator find(const K& key) const:
//
// Finds an element with the passed `key` within the `btree_set`.
//
// Supports heterogeneous lookup, provided that the set has a compatible
// heterogeneous comparator.
using Base::find;
// btree_set::lower_bound()
//
// template <typename K> iterator lower_bound(const K& key):
// template <typename K> const_iterator lower_bound(const K& key) const:
//
// Finds the first element that is not less than `key` within the `btree_set`.
//
// Supports heterogeneous lookup, provided that the set has a compatible
// heterogeneous comparator.
using Base::lower_bound;
// btree_set::upper_bound()
//
// template <typename K> iterator upper_bound(const K& key):
// template <typename K> const_iterator upper_bound(const K& key) const:
//
// Finds the first element that is greater than `key` within the `btree_set`.
//
// Supports heterogeneous lookup, provided that the set has a compatible
// heterogeneous comparator.
using Base::upper_bound;
// btree_set::get_allocator()
//
// Returns the allocator function associated with this `btree_set`.
using Base::get_allocator;
// btree_set::key_comp();
//
// Returns the key comparator associated with this `btree_set`.
using Base::key_comp;
// btree_set::value_comp();
//
// Returns the value comparator associated with this `btree_set`. The keys to
// sort the elements are the values themselves, therefore `value_comp` and its
// sibling member function `key_comp` are equivalent.
using Base::value_comp;
};
// absl::swap(absl::btree_set<>, absl::btree_set<>)
//
// Swaps the contents of two `absl::btree_set` containers.
template <typename K, typename C, typename A>
void swap(btree_set<K, C, A> &x, btree_set<K, C, A> &y) {
return x.swap(y);
}
// absl::erase_if(absl::btree_set<>, Pred)
//
// Erases all elements that satisfy the predicate pred from the container.
// Returns the number of erased elements.
template <typename K, typename C, typename A, typename Pred>
typename btree_set<K, C, A>::size_type erase_if(btree_set<K, C, A> &set,
Pred pred) {
return container_internal::btree_access::erase_if(set, std::move(pred));
}
// absl::btree_multiset<>
//
// An `absl::btree_multiset<K>` is an ordered associative container of
// keys and associated values designed to be a more efficient replacement
// for `std::multiset` (in most cases). Unlike `absl::btree_set`, a B-tree
// multiset allows equivalent elements.
//
// Keys are sorted using an (optional) comparison function, which defaults to
// `std::less<K>`.
//
// An `absl::btree_multiset<K>` uses a default allocator of `std::allocator<K>`
// to allocate (and deallocate) nodes, and construct and destruct values within
// those nodes. You may instead specify a custom allocator `A` (which in turn
// requires specifying a custom comparator `C`) as in
// `absl::btree_multiset<K, C, A>`.
//
template <typename Key, typename Compare = std::less<Key>,
typename Alloc = std::allocator<Key>>
class ABSL_ATTRIBUTE_OWNER btree_multiset
: public container_internal::btree_multiset_container<
container_internal::btree<container_internal::set_params<
Key, Compare, Alloc, /*TargetNodeSize=*/256,
/*IsMulti=*/true>>> {
using Base = typename btree_multiset::btree_multiset_container;
public:
// Constructors and Assignment Operators
//
// A `btree_multiset` supports the same overload set as `std::set`
// for construction and assignment:
//
// * Default constructor
//
// absl::btree_multiset<std::string> set1;
//
// * Initializer List constructor
//
// absl::btree_multiset<std::string> set2 =
// {{"huey"}, {"dewey"}, {"louie"},};
//
// * Copy constructor
//
// absl::btree_multiset<std::string> set3(set2);
//
// * Copy assignment operator
//
// absl::btree_multiset<std::string> set4;
// set4 = set3;
//
// * Move constructor
//
// // Move is guaranteed efficient
// absl::btree_multiset<std::string> set5(std::move(set4));
//
// * Move assignment operator
//
// // May be efficient if allocators are compatible
// absl::btree_multiset<std::string> set6;
// set6 = std::move(set5);
//
// * Range constructor
//
// std::vector<std::string> v = {"a", "b"};
// absl::btree_multiset<std::string> set7(v.begin(), v.end());
btree_multiset() {}
using Base::Base;
// btree_multiset::begin()
//
// Returns an iterator to the beginning of the `btree_multiset`.
using Base::begin;
// btree_multiset::cbegin()
//
// Returns a const iterator to the beginning of the `btree_multiset`.
using Base::cbegin;
// btree_multiset::end()
//
// Returns an iterator to the end of the `btree_multiset`.
using Base::end;
// btree_multiset::cend()
//
// Returns a const iterator to the end of the `btree_multiset`.
using Base::cend;
// btree_multiset::empty()
//
// Returns whether or not the `btree_multiset` is empty.
using Base::empty;
// btree_multiset::max_size()
//
// Returns the largest theoretical possible number of elements within a
// `btree_multiset` under current memory constraints. This value can be
// thought of as the largest value of `std::distance(begin(), end())` for a
// `btree_multiset<Key>`.
using Base::max_size;
// btree_multiset::size()
//
// Returns the number of elements currently within the `btree_multiset`.
using Base::size;
// btree_multiset::clear()
//
// Removes all elements from the `btree_multiset`. Invalidates any references,
// pointers, or iterators referring to contained elements.
using Base::clear;
// btree_multiset::erase()
//
// Erases elements within the `btree_multiset`. Overloads are listed below.
//
// iterator erase(iterator position):
// iterator erase(const_iterator position):
//
// Erases the element at `position` of the `btree_multiset`, returning
// the iterator pointing to the element after the one that was erased
// (or end() if none exists).
//
// iterator erase(const_iterator first, const_iterator last):
//
// Erases the elements in the open interval [`first`, `last`), returning
// the iterator pointing to the element after the interval that was erased
// (or end() if none exists).
//
// template <typename K> size_type erase(const K& key):
//
// Erases the elements matching the key, if any exist, returning the
// number of elements erased.
using Base::erase;
// btree_multiset::insert()
//
// Inserts an element of the specified value into the `btree_multiset`,
// returning an iterator pointing to the newly inserted element.
// Any references, pointers, or iterators are invalidated. Overloads are
// listed below.
//
// iterator insert(const value_type& value):
//
// Inserts a value into the `btree_multiset`, returning an iterator to the
// inserted element.
//
// iterator insert(value_type&& value):
//
// Inserts a moveable value into the `btree_multiset`, returning an iterator
// to the inserted element.
//
// iterator insert(const_iterator hint, const value_type& value):
// iterator insert(const_iterator hint, value_type&& value):
//
// Inserts a value, using the position of `hint` as a non-binding suggestion
// for where to begin the insertion search. Returns an iterator to the
// inserted element.
//
// void insert(InputIterator first, InputIterator last):
//
// Inserts a range of values [`first`, `last`).
//
// void insert(std::initializer_list<init_type> ilist):
//
// Inserts the elements within the initializer list `ilist`.
using Base::insert;
// btree_multiset::emplace()
//
// Inserts an element of the specified value by constructing it in-place
// within the `btree_multiset`. Any references, pointers, or iterators are
// invalidated.
using Base::emplace;
// btree_multiset::emplace_hint()
//
// Inserts an element of the specified value by constructing it in-place
// within the `btree_multiset`, using the position of `hint` as a non-binding
// suggestion for where to begin the insertion search.
//
// Any references, pointers, or iterators are invalidated.
using Base::emplace_hint;
// btree_multiset::extract()
//
// Extracts the indicated element, erasing it in the process, and returns it
// as a C++17-compatible node handle. Overloads are listed below.
//
// node_type extract(const_iterator position):
//
// Extracts the element at the indicated position and returns a node handle
// owning that extracted data.
//
// template <typename K> node_type extract(const K& k):
//
// Extracts the element with the key matching the passed key value and
// returns a node handle owning that extracted data. If the `btree_multiset`
// does not contain an element with a matching key, this function returns an
// empty node handle.
//
// NOTE: In this context, `node_type` refers to the C++17 concept of a
// move-only type that owns and provides access to the elements in associative
// containers (https://en.cppreference.com/w/cpp/container/node_handle).
// It does NOT refer to the data layout of the underlying btree.
using Base::extract;
// btree_multiset::extract_and_get_next()
//
// Extracts the indicated element, erasing it in the process, and returns it
// as a C++17-compatible node handle along with an iterator to the next
// element.
//
// extract_and_get_next_return_type extract_and_get_next(
// const_iterator position):
//
// Extracts the element at the indicated position, returns a struct
// containing a member named `node`: a node handle owning that extracted
// data and a member named `next`: an iterator pointing to the next element
// in the btree.
using Base::extract_and_get_next;
// btree_multiset::merge()
//
// Extracts all elements from a given `source` btree_multiset into this
// `btree_multiset`.
using Base::merge;
// btree_multiset::swap(btree_multiset& other)
//
// Exchanges the contents of this `btree_multiset` with those of the `other`
// btree_multiset, avoiding invocation of any move, copy, or swap operations
// on individual elements.
//
// All iterators and references on the `btree_multiset` remain valid,
// excepting for the past-the-end iterator, which is invalidated.
using Base::swap;
// btree_multiset::contains()
//
// template <typename K> bool contains(const K& key) const:
//
// Determines whether an element comparing equal to the given `key` exists
// within the `btree_multiset`, returning `true` if so or `false` otherwise.
//
// Supports heterogeneous lookup, provided that the set has a compatible
// heterogeneous comparator.
using Base::contains;
// btree_multiset::count()
//
// template <typename K> size_type count(const K& key) const:
//
// Returns the number of elements comparing equal to the given `key` within
// the `btree_multiset`.
//
// Supports heterogeneous lookup, provided that the set has a compatible
// heterogeneous comparator.
using Base::count;
// btree_multiset::equal_range()
//
// Returns a closed range [first, last], defined by a `std::pair` of two
// iterators, containing all elements with the passed key in the
// `btree_multiset`.
using Base::equal_range;
// btree_multiset::find()
//
// template <typename K> iterator find(const K& key):
// template <typename K> const_iterator find(const K& key) const:
//
// Finds an element with the passed `key` within the `btree_multiset`.
//
// Supports heterogeneous lookup, provided that the set has a compatible
// heterogeneous comparator.
using Base::find;
// btree_multiset::lower_bound()
//
// template <typename K> iterator lower_bound(const K& key):
// template <typename K> const_iterator lower_bound(const K& key) const:
//
// Finds the first element that is not less than `key` within the
// `btree_multiset`.
//
// Supports heterogeneous lookup, provided that the set has a compatible
// heterogeneous comparator.
using Base::lower_bound;
// btree_multiset::upper_bound()
//
// template <typename K> iterator upper_bound(const K& key):
// template <typename K> const_iterator upper_bound(const K& key) const:
//
// Finds the first element that is greater than `key` within the
// `btree_multiset`.
//
// Supports heterogeneous lookup, provided that the set has a compatible
// heterogeneous comparator.
using Base::upper_bound;
// btree_multiset::get_allocator()
//
// Returns the allocator function associated with this `btree_multiset`.
using Base::get_allocator;
// btree_multiset::key_comp();
//
// Returns the key comparator associated with this `btree_multiset`.
using Base::key_comp;
// btree_multiset::value_comp();
//
// Returns the value comparator associated with this `btree_multiset`. The
// keys to sort the elements are the values themselves, therefore `value_comp`
// and its sibling member function `key_comp` are equivalent.
using Base::value_comp;
};
// absl::swap(absl::btree_multiset<>, absl::btree_multiset<>)
//
// Swaps the contents of two `absl::btree_multiset` containers.
template <typename K, typename C, typename A>
void swap(btree_multiset<K, C, A> &x, btree_multiset<K, C, A> &y) {
return x.swap(y);
}
// absl::erase_if(absl::btree_multiset<>, Pred)
//
// Erases all elements that satisfy the predicate pred from the container.
// Returns the number of erased elements.
template <typename K, typename C, typename A, typename Pred>
typename btree_multiset<K, C, A>::size_type erase_if(
btree_multiset<K, C, A> & set, Pred pred) {
return container_internal::btree_access::erase_if(set, std::move(pred));
}
namespace container_internal {
// This type implements the necessary functions from the
// absl::container_internal::slot_type interface for btree_(multi)set.
template <typename Key>
struct set_slot_policy {
using slot_type = Key;
using value_type = Key;
using mutable_value_type = Key;
static value_type &element(slot_type *slot) { return *slot; }
static const value_type &element(const slot_type *slot) { return *slot; }
template <typename Alloc, class... Args>
static void construct(Alloc *alloc, slot_type *slot, Args &&...args) {
absl::allocator_traits<Alloc>::construct(*alloc, slot,
std::forward<Args>(args)...);
}
template <typename Alloc>
static void construct(Alloc *alloc, slot_type *slot, slot_type *other) {
absl::allocator_traits<Alloc>::construct(*alloc, slot, std::move(*other));
}
template <typename Alloc>
static void construct(Alloc *alloc, slot_type *slot, const slot_type *other) {
absl::allocator_traits<Alloc>::construct(*alloc, slot, *other);
}
template <typename Alloc>
static void destroy(Alloc *alloc, slot_type *slot) {
absl::allocator_traits<Alloc>::destroy(*alloc, slot);
}
};
// A parameters structure for holding the type parameters for a btree_set.
// Compare and Alloc should be nothrow copy-constructible.
template <typename Key, typename Compare, typename Alloc, int TargetNodeSize,
bool IsMulti>
struct set_params : common_params<Key, Compare, Alloc, TargetNodeSize, IsMulti,
/*IsMap=*/false, set_slot_policy<Key>> {
using value_type = Key;
using slot_type = typename set_params::common_params::slot_type;
template <typename V>
static const V &key(const V &value) {
return value;
}
static const Key &key(const slot_type *slot) { return *slot; }
static const Key &key(slot_type *slot) { return *slot; }
};
} // namespace container_internal
ABSL_NAMESPACE_END
} // namespace absl
#endif // ABSL_CONTAINER_BTREE_SET_H_

View File

@@ -1,549 +0,0 @@
// Copyright 2018 The Abseil Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// -----------------------------------------------------------------------------
// File: fixed_array.h
// -----------------------------------------------------------------------------
//
// A `FixedArray<T>` represents a non-resizable array of `T` where the length of
// the array can be determined at run-time. It is a good replacement for
// non-standard and deprecated uses of `alloca()` and variable length arrays
// within the GCC extension. (See
// https://gcc.gnu.org/onlinedocs/gcc/Variable-Length.html).
//
// `FixedArray` allocates small arrays inline, keeping performance fast by
// avoiding heap operations. It also helps reduce the chances of
// accidentally overflowing your stack if large input is passed to
// your function.
#ifndef ABSL_CONTAINER_FIXED_ARRAY_H_
#define ABSL_CONTAINER_FIXED_ARRAY_H_
#include <algorithm>
#include <cassert>
#include <cstddef>
#include <initializer_list>
#include <iterator>
#include <limits>
#include <memory>
#include <new>
#include <type_traits>
#include "absl/algorithm/algorithm.h"
#include "absl/base/attributes.h"
#include "absl/base/config.h"
#include "absl/base/dynamic_annotations.h"
#include "absl/base/internal/iterator_traits.h"
#include "absl/base/internal/throw_delegate.h"
#include "absl/base/macros.h"
#include "absl/base/optimization.h"
#include "absl/base/port.h"
#include "absl/container/internal/compressed_tuple.h"
#include "absl/hash/internal/weakly_mixed_integer.h"
#include "absl/memory/memory.h"
namespace absl {
ABSL_NAMESPACE_BEGIN
constexpr static auto kFixedArrayUseDefault = static_cast<size_t>(-1);
// -----------------------------------------------------------------------------
// FixedArray
// -----------------------------------------------------------------------------
//
// A `FixedArray` provides a run-time fixed-size array, allocating a small array
// inline for efficiency.
//
// Most users should not specify the `N` template parameter and let `FixedArray`
// automatically determine the number of elements to store inline based on
// `sizeof(T)`. If `N` is specified, the `FixedArray` implementation will use
// inline storage for arrays with a length <= `N`.
//
// Note that a `FixedArray` constructed with a `size_type` argument will
// default-initialize its values by leaving trivially constructible types
// uninitialized (e.g. int, int[4], double), and others default-constructed.
// This matches the behavior of c-style arrays and `std::array`, but not
// `std::vector`.
template <typename T, size_t N = kFixedArrayUseDefault,
typename A = std::allocator<T>>
class ABSL_ATTRIBUTE_WARN_UNUSED FixedArray {
static_assert(!std::is_array<T>::value || std::extent<T>::value > 0,
"Arrays with unknown bounds cannot be used with FixedArray.");
static constexpr size_t kInlineBytesDefault = 256;
using AllocatorTraits = std::allocator_traits<A>;
// std::iterator_traits isn't guaranteed to be SFINAE-friendly until C++17,
// but this seems to be mostly pedantic.
template <typename Iterator>
using EnableIfForwardIterator = std::enable_if_t<
base_internal::IsAtLeastForwardIterator<Iterator>::value>;
static constexpr bool NoexceptCopyable() {
return std::is_nothrow_copy_constructible<StorageElement>::value &&
absl::allocator_is_nothrow<allocator_type>::value;
}
static constexpr bool NoexceptMovable() {
return std::is_nothrow_move_constructible<StorageElement>::value &&
absl::allocator_is_nothrow<allocator_type>::value;
}
static constexpr bool DefaultConstructorIsNonTrivial() {
return !absl::is_trivially_default_constructible<StorageElement>::value;
}
public:
using allocator_type = typename AllocatorTraits::allocator_type;
using value_type = typename AllocatorTraits::value_type;
using pointer = typename AllocatorTraits::pointer;
using const_pointer = typename AllocatorTraits::const_pointer;
using reference = value_type&;
using const_reference = const value_type&;
using size_type = typename AllocatorTraits::size_type;
using difference_type = typename AllocatorTraits::difference_type;
using iterator = pointer;
using const_iterator = const_pointer;
using reverse_iterator = std::reverse_iterator<iterator>;
using const_reverse_iterator = std::reverse_iterator<const_iterator>;
static constexpr size_type inline_elements =
(N == kFixedArrayUseDefault ? kInlineBytesDefault / sizeof(value_type)
: static_cast<size_type>(N));
FixedArray(const FixedArray& other) noexcept(NoexceptCopyable())
: FixedArray(other,
AllocatorTraits::select_on_container_copy_construction(
other.storage_.alloc())) {}
FixedArray(const FixedArray& other,
const allocator_type& a) noexcept(NoexceptCopyable())
: FixedArray(other.begin(), other.end(), a) {}
FixedArray(FixedArray&& other) noexcept(NoexceptMovable())
: FixedArray(std::move(other), other.storage_.alloc()) {}
FixedArray(FixedArray&& other,
const allocator_type& a) noexcept(NoexceptMovable())
: FixedArray(std::make_move_iterator(other.begin()),
std::make_move_iterator(other.end()), a) {}
// Creates an array object that can store `n` elements.
// Note that trivially constructible elements will be uninitialized.
explicit FixedArray(size_type n, const allocator_type& a = allocator_type())
: storage_(n, a) {
if (DefaultConstructorIsNonTrivial()) {
memory_internal::ConstructRange(storage_.alloc(), storage_.begin(),
storage_.end());
}
}
// Creates an array initialized with `n` copies of `val`.
FixedArray(size_type n, const value_type& val,
const allocator_type& a = allocator_type())
: storage_(n, a) {
memory_internal::ConstructRange(storage_.alloc(), storage_.begin(),
storage_.end(), val);
}
// Creates an array initialized with the size and contents of `init_list`.
FixedArray(std::initializer_list<value_type> init_list,
const allocator_type& a = allocator_type())
: FixedArray(init_list.begin(), init_list.end(), a) {}
// Creates an array initialized with the elements from the input
// range. The array's size will always be `std::distance(first, last)`.
// REQUIRES: Iterator must be a forward_iterator or better.
template <typename Iterator, EnableIfForwardIterator<Iterator>* = nullptr>
FixedArray(Iterator first, Iterator last,
const allocator_type& a = allocator_type())
: storage_(std::distance(first, last), a) {
memory_internal::CopyRange(storage_.alloc(), storage_.begin(), first, last);
}
~FixedArray() noexcept {
for (auto* cur = storage_.begin(); cur != storage_.end(); ++cur) {
AllocatorTraits::destroy(storage_.alloc(), cur);
}
}
// Assignments are deleted because they break the invariant that the size of a
// `FixedArray` never changes.
void operator=(FixedArray&&) = delete;
void operator=(const FixedArray&) = delete;
// FixedArray::size()
//
// Returns the length of the fixed array.
size_type size() const { return storage_.size(); }
// FixedArray::max_size()
//
// Returns the largest possible value of `std::distance(begin(), end())` for a
// `FixedArray<T>`. This is equivalent to the most possible addressable bytes
// over the number of bytes taken by T.
constexpr size_type max_size() const {
return (std::numeric_limits<difference_type>::max)() / sizeof(value_type);
}
// FixedArray::empty()
//
// Returns whether or not the fixed array is empty.
bool empty() const { return size() == 0; }
// FixedArray::memsize()
//
// Returns the memory size of the fixed array in bytes.
size_t memsize() const { return size() * sizeof(value_type); }
// FixedArray::data()
//
// Returns a const T* pointer to elements of the `FixedArray`. This pointer
// can be used to access (but not modify) the contained elements.
const_pointer data() const ABSL_ATTRIBUTE_LIFETIME_BOUND {
return AsValueType(storage_.begin());
}
// Overload of FixedArray::data() to return a T* pointer to elements of the
// fixed array. This pointer can be used to access and modify the contained
// elements.
pointer data() ABSL_ATTRIBUTE_LIFETIME_BOUND {
return AsValueType(storage_.begin());
}
// FixedArray::operator[]
//
// Returns a reference the ith element of the fixed array.
// REQUIRES: 0 <= i < size()
reference operator[](size_type i) ABSL_ATTRIBUTE_LIFETIME_BOUND {
ABSL_HARDENING_ASSERT(i < size());
return data()[i];
}
// Overload of FixedArray::operator()[] to return a const reference to the
// ith element of the fixed array.
// REQUIRES: 0 <= i < size()
const_reference operator[](size_type i) const ABSL_ATTRIBUTE_LIFETIME_BOUND {
ABSL_HARDENING_ASSERT(i < size());
return data()[i];
}
// FixedArray::at
//
// Bounds-checked access. Returns a reference to the ith element of the fixed
// array, or throws std::out_of_range
reference at(size_type i) ABSL_ATTRIBUTE_LIFETIME_BOUND {
if (ABSL_PREDICT_FALSE(i >= size())) {
base_internal::ThrowStdOutOfRange("FixedArray::at failed bounds check");
}
return data()[i];
}
// Overload of FixedArray::at() to return a const reference to the ith element
// of the fixed array.
const_reference at(size_type i) const ABSL_ATTRIBUTE_LIFETIME_BOUND {
if (ABSL_PREDICT_FALSE(i >= size())) {
base_internal::ThrowStdOutOfRange("FixedArray::at failed bounds check");
}
return data()[i];
}
// FixedArray::front()
//
// Returns a reference to the first element of the fixed array.
reference front() ABSL_ATTRIBUTE_LIFETIME_BOUND {
ABSL_HARDENING_ASSERT(!empty());
return data()[0];
}
// Overload of FixedArray::front() to return a reference to the first element
// of a fixed array of const values.
const_reference front() const ABSL_ATTRIBUTE_LIFETIME_BOUND {
ABSL_HARDENING_ASSERT(!empty());
return data()[0];
}
// FixedArray::back()
//
// Returns a reference to the last element of the fixed array.
reference back() ABSL_ATTRIBUTE_LIFETIME_BOUND {
ABSL_HARDENING_ASSERT(!empty());
return data()[size() - 1];
}
// Overload of FixedArray::back() to return a reference to the last element
// of a fixed array of const values.
const_reference back() const ABSL_ATTRIBUTE_LIFETIME_BOUND {
ABSL_HARDENING_ASSERT(!empty());
return data()[size() - 1];
}
// FixedArray::begin()
//
// Returns an iterator to the beginning of the fixed array.
iterator begin() ABSL_ATTRIBUTE_LIFETIME_BOUND { return data(); }
// Overload of FixedArray::begin() to return a const iterator to the
// beginning of the fixed array.
const_iterator begin() const ABSL_ATTRIBUTE_LIFETIME_BOUND { return data(); }
// FixedArray::cbegin()
//
// Returns a const iterator to the beginning of the fixed array.
const_iterator cbegin() const ABSL_ATTRIBUTE_LIFETIME_BOUND {
return begin();
}
// FixedArray::end()
//
// Returns an iterator to the end of the fixed array.
iterator end() ABSL_ATTRIBUTE_LIFETIME_BOUND { return data() + size(); }
// Overload of FixedArray::end() to return a const iterator to the end of the
// fixed array.
const_iterator end() const ABSL_ATTRIBUTE_LIFETIME_BOUND {
return data() + size();
}
// FixedArray::cend()
//
// Returns a const iterator to the end of the fixed array.
const_iterator cend() const ABSL_ATTRIBUTE_LIFETIME_BOUND { return end(); }
// FixedArray::rbegin()
//
// Returns a reverse iterator from the end of the fixed array.
reverse_iterator rbegin() ABSL_ATTRIBUTE_LIFETIME_BOUND {
return reverse_iterator(end());
}
// Overload of FixedArray::rbegin() to return a const reverse iterator from
// the end of the fixed array.
const_reverse_iterator rbegin() const ABSL_ATTRIBUTE_LIFETIME_BOUND {
return const_reverse_iterator(end());
}
// FixedArray::crbegin()
//
// Returns a const reverse iterator from the end of the fixed array.
const_reverse_iterator crbegin() const ABSL_ATTRIBUTE_LIFETIME_BOUND {
return rbegin();
}
// FixedArray::rend()
//
// Returns a reverse iterator from the beginning of the fixed array.
reverse_iterator rend() ABSL_ATTRIBUTE_LIFETIME_BOUND {
return reverse_iterator(begin());
}
// Overload of FixedArray::rend() for returning a const reverse iterator
// from the beginning of the fixed array.
const_reverse_iterator rend() const ABSL_ATTRIBUTE_LIFETIME_BOUND {
return const_reverse_iterator(begin());
}
// FixedArray::crend()
//
// Returns a reverse iterator from the beginning of the fixed array.
const_reverse_iterator crend() const ABSL_ATTRIBUTE_LIFETIME_BOUND {
return rend();
}
// FixedArray::fill()
//
// Assigns the given `value` to all elements in the fixed array.
void fill(const value_type& val) { std::fill(begin(), end(), val); }
// Relational operators. Equality operators are elementwise using
// `operator==`, while order operators order FixedArrays lexicographically.
friend bool operator==(const FixedArray& lhs, const FixedArray& rhs) {
return std::equal(lhs.begin(), lhs.end(), rhs.begin(), rhs.end());
}
friend bool operator!=(const FixedArray& lhs, const FixedArray& rhs) {
return !(lhs == rhs);
}
friend bool operator<(const FixedArray& lhs, const FixedArray& rhs) {
return std::lexicographical_compare(lhs.begin(), lhs.end(), rhs.begin(),
rhs.end());
}
friend bool operator>(const FixedArray& lhs, const FixedArray& rhs) {
return rhs < lhs;
}
friend bool operator<=(const FixedArray& lhs, const FixedArray& rhs) {
return !(rhs < lhs);
}
friend bool operator>=(const FixedArray& lhs, const FixedArray& rhs) {
return !(lhs < rhs);
}
template <typename H>
friend H AbslHashValue(H h, const FixedArray& v) {
return H::combine_contiguous(std::move(h), v.data(), v.size());
}
private:
// StorageElement
//
// For FixedArrays with a C-style-array value_type, StorageElement is a POD
// wrapper struct called StorageElementWrapper that holds the value_type
// instance inside. This is needed for construction and destruction of the
// entire array regardless of how many dimensions it has. For all other cases,
// StorageElement is just an alias of value_type.
//
// Maintainer's Note: The simpler solution would be to simply wrap value_type
// in a struct whether it's an array or not. That causes some paranoid
// diagnostics to misfire, believing that 'data()' returns a pointer to a
// single element, rather than the packed array that it really is.
// e.g.:
//
// FixedArray<char> buf(1);
// sprintf(buf.data(), "foo");
//
// error: call to int __builtin___sprintf_chk(etc...)
// will always overflow destination buffer [-Werror]
//
template <typename OuterT, typename InnerT = absl::remove_extent_t<OuterT>,
size_t InnerN = std::extent<OuterT>::value>
struct StorageElementWrapper {
InnerT array[InnerN];
};
using StorageElement =
absl::conditional_t<std::is_array<value_type>::value,
StorageElementWrapper<value_type>, value_type>;
static pointer AsValueType(pointer ptr) { return ptr; }
static pointer AsValueType(StorageElementWrapper<value_type>* ptr) {
return std::addressof(ptr->array);
}
static_assert(sizeof(StorageElement) == sizeof(value_type), "");
static_assert(alignof(StorageElement) == alignof(value_type), "");
class NonEmptyInlinedStorage {
public:
StorageElement* data() { return reinterpret_cast<StorageElement*>(buff_); }
void AnnotateConstruct(size_type n);
void AnnotateDestruct(size_type n);
#ifdef ABSL_HAVE_ADDRESS_SANITIZER
void* RedzoneBegin() { return &redzone_begin_; }
void* RedzoneEnd() { return &redzone_end_ + 1; }
#endif // ABSL_HAVE_ADDRESS_SANITIZER
private:
ABSL_ADDRESS_SANITIZER_REDZONE(redzone_begin_);
alignas(StorageElement) unsigned char buff_[sizeof(
StorageElement[inline_elements])];
ABSL_ADDRESS_SANITIZER_REDZONE(redzone_end_);
};
class EmptyInlinedStorage {
public:
StorageElement* data() { return nullptr; }
void AnnotateConstruct(size_type) {}
void AnnotateDestruct(size_type) {}
};
using InlinedStorage =
absl::conditional_t<inline_elements == 0, EmptyInlinedStorage,
NonEmptyInlinedStorage>;
// Storage
//
// An instance of Storage manages the inline and out-of-line memory for
// instances of FixedArray. This guarantees that even when construction of
// individual elements fails in the FixedArray constructor body, the
// destructor for Storage will still be called and out-of-line memory will be
// properly deallocated.
//
class Storage : public InlinedStorage {
public:
Storage(size_type n, const allocator_type& a)
: size_alloc_(n, a), data_(InitializeData()) {}
~Storage() noexcept {
if (UsingInlinedStorage(size())) {
InlinedStorage::AnnotateDestruct(size());
} else {
AllocatorTraits::deallocate(alloc(), AsValueType(begin()), size());
}
}
size_type size() const { return size_alloc_.template get<0>(); }
StorageElement* begin() const { return data_; }
StorageElement* end() const { return begin() + size(); }
allocator_type& alloc() { return size_alloc_.template get<1>(); }
const allocator_type& alloc() const {
return size_alloc_.template get<1>();
}
private:
static bool UsingInlinedStorage(size_type n) {
return n <= inline_elements;
}
#ifdef ABSL_HAVE_ADDRESS_SANITIZER
ABSL_ATTRIBUTE_NOINLINE
#endif // ABSL_HAVE_ADDRESS_SANITIZER
StorageElement* InitializeData() {
if (UsingInlinedStorage(size())) {
InlinedStorage::AnnotateConstruct(size());
return InlinedStorage::data();
} else {
return reinterpret_cast<StorageElement*>(
AllocatorTraits::allocate(alloc(), size()));
}
}
// `CompressedTuple` takes advantage of EBCO for stateless `allocator_type`s
container_internal::CompressedTuple<size_type, allocator_type> size_alloc_;
StorageElement* data_;
};
Storage storage_;
};
template <typename T, size_t N, typename A>
void FixedArray<T, N, A>::NonEmptyInlinedStorage::AnnotateConstruct(
typename FixedArray<T, N, A>::size_type n) {
#ifdef ABSL_HAVE_ADDRESS_SANITIZER
if (!n) return;
ABSL_ANNOTATE_CONTIGUOUS_CONTAINER(data(), RedzoneEnd(), RedzoneEnd(),
data() + n);
ABSL_ANNOTATE_CONTIGUOUS_CONTAINER(RedzoneBegin(), data(), data(),
RedzoneBegin());
#endif // ABSL_HAVE_ADDRESS_SANITIZER
static_cast<void>(n); // Mark used when not in asan mode
}
template <typename T, size_t N, typename A>
void FixedArray<T, N, A>::NonEmptyInlinedStorage::AnnotateDestruct(
typename FixedArray<T, N, A>::size_type n) {
#ifdef ABSL_HAVE_ADDRESS_SANITIZER
if (!n) return;
ABSL_ANNOTATE_CONTIGUOUS_CONTAINER(data(), RedzoneEnd(), data() + n,
RedzoneEnd());
ABSL_ANNOTATE_CONTIGUOUS_CONTAINER(RedzoneBegin(), data(), RedzoneBegin(),
data());
#endif // ABSL_HAVE_ADDRESS_SANITIZER
static_cast<void>(n); // Mark used when not in asan mode
}
ABSL_NAMESPACE_END
} // namespace absl
#endif // ABSL_CONTAINER_FIXED_ARRAY_H_

Some files were not shown because too many files have changed in this diff Show More