mirror of
https://github.com/bkaradzic/bgfx.git
synced 2026-02-17 20:52:36 +01:00
committed by
GitHub
parent
0d7526dfb9
commit
cc923c5165
1
3rdparty/dawn/include/webgpu/webgpu.h
vendored
1
3rdparty/dawn/include/webgpu/webgpu.h
vendored
@@ -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;
|
||||
|
||||
|
||||
2097
3rdparty/dawn/src/tint/lang/core/ir/binary/decode.cc
vendored
2097
3rdparty/dawn/src/tint/lang/core/ir/binary/decode.cc
vendored
File diff suppressed because it is too large
Load Diff
@@ -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_
|
||||
1462
3rdparty/dawn/src/tint/lang/core/ir/binary/encode.cc
vendored
1462
3rdparty/dawn/src/tint/lang/core/ir/binary/encode.cc
vendored
File diff suppressed because it is too large
Load Diff
@@ -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_
|
||||
@@ -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
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
100
3rdparty/dawn/src/tint/lang/core/ir/validator.cc
vendored
100
3rdparty/dawn/src/tint/lang/core/ir/validator.cc
vendored
@@ -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();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
@@ -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_
|
||||
@@ -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
|
||||
@@ -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_
|
||||
@@ -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
|
||||
@@ -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_
|
||||
@@ -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
|
||||
51
3rdparty/dawn/src/tint/lang/null/writer/writer.h
vendored
51
3rdparty/dawn/src/tint/lang/null/writer/writer.h
vendored
@@ -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_
|
||||
@@ -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.
|
||||
|
||||
@@ -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;
|
||||
|
||||
5
3rdparty/dawn/src/tint/lang/wgsl/enums.cc
vendored
5
3rdparty/dawn/src/tint/lang/wgsl/enums.cc
vendored
@@ -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:
|
||||
|
||||
3
3rdparty/dawn/src/tint/lang/wgsl/enums.h
vendored
3
3rdparty/dawn/src/tint/lang/wgsl/enums.h
vendored
@@ -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,
|
||||
|
||||
@@ -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
|
||||
@@ -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_
|
||||
@@ -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_
|
||||
@@ -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
|
||||
@@ -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_
|
||||
@@ -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_
|
||||
1343
3rdparty/dawn/src/tint/lang/wgsl/reader/parser/lexer.cc
vendored
1343
3rdparty/dawn/src/tint/lang/wgsl/reader/parser/lexer.cc
vendored
File diff suppressed because it is too large
Load Diff
@@ -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_
|
||||
3542
3rdparty/dawn/src/tint/lang/wgsl/reader/parser/parser.cc
vendored
3542
3rdparty/dawn/src/tint/lang/wgsl/reader/parser/parser.cc
vendored
File diff suppressed because it is too large
Load Diff
@@ -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_
|
||||
@@ -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
|
||||
@@ -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
@@ -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_
|
||||
@@ -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
|
||||
75
3rdparty/dawn/src/tint/lang/wgsl/reader/reader.h
vendored
75
3rdparty/dawn/src/tint/lang/wgsl/reader/reader.h
vendored
@@ -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_
|
||||
@@ -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
|
||||
|
||||
4
3rdparty/dawn/src/tint/utils/math/math.h
vendored
4
3rdparty/dawn/src/tint/utils/math/math.h
vendored
@@ -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)
|
||||
|
||||
21506
3rdparty/dawn/src/tint/utils/protos/ir/ir.pb.cc
vendored
21506
3rdparty/dawn/src/tint/utils/protos/ir/ir.pb.cc
vendored
File diff suppressed because it is too large
Load Diff
23930
3rdparty/dawn/src/tint/utils/protos/ir/ir.pb.h
vendored
23930
3rdparty/dawn/src/tint/utils/protos/ir/ir.pb.h
vendored
File diff suppressed because it is too large
Load Diff
115
3rdparty/dawn/src/tint/utils/strconv/parse_num.cc
vendored
115
3rdparty/dawn/src/tint/utils/strconv/parse_num.cc
vendored
@@ -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
|
||||
145
3rdparty/dawn/src/tint/utils/strconv/parse_num.h
vendored
145
3rdparty/dawn/src/tint/utils/strconv/parse_num.h
vendored
@@ -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_
|
||||
203
3rdparty/dawn/third_party/abseil-cpp/LICENSE
vendored
203
3rdparty/dawn/third_party/abseil-cpp/LICENSE
vendored
@@ -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.
|
||||
|
||||
@@ -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
@@ -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; }
|
||||
@@ -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_
|
||||
@@ -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_
|
||||
@@ -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_
|
||||
@@ -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_
|
||||
@@ -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_
|
||||
@@ -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_
|
||||
@@ -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_
|
||||
@@ -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_
|
||||
@@ -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_
|
||||
@@ -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_
|
||||
@@ -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_
|
||||
@@ -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_
|
||||
@@ -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_
|
||||
@@ -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_
|
||||
@@ -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_
|
||||
@@ -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_
|
||||
@@ -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_
|
||||
@@ -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_
|
||||
@@ -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_
|
||||
@@ -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_
|
||||
@@ -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_
|
||||
@@ -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_
|
||||
@@ -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_
|
||||
@@ -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_
|
||||
@@ -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"
|
||||
@@ -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"
|
||||
@@ -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"
|
||||
@@ -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_
|
||||
@@ -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"
|
||||
@@ -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_
|
||||
@@ -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_
|
||||
@@ -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_
|
||||
@@ -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_
|
||||
@@ -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_
|
||||
@@ -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_
|
||||
@@ -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_
|
||||
@@ -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_
|
||||
@@ -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_
|
||||
@@ -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_
|
||||
@@ -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_
|
||||
@@ -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_
|
||||
@@ -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_
|
||||
@@ -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_
|
||||
@@ -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_
|
||||
@@ -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_
|
||||
@@ -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_
|
||||
@@ -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_
|
||||
@@ -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_
|
||||
@@ -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_
|
||||
@@ -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_
|
||||
@@ -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
Reference in New Issue
Block a user