Coverage Report

Created: 2026-05-27 07:00

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/proc/self/cwd/base/attribute.cc
Line
Count
Source
1
// Copyright 2022 Google LLC
2
//
3
// Licensed under the Apache License, Version 2.0 (the "License");
4
// you may not use this file except in compliance with the License.
5
// You may obtain a copy of the License at
6
//
7
//     https://www.apache.org/licenses/LICENSE-2.0
8
//
9
// Unless required by applicable law or agreed to in writing, software
10
// distributed under the License is distributed on an "AS IS" BASIS,
11
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
// See the License for the specific language governing permissions and
13
// limitations under the License.
14
15
#include "base/attribute.h"
16
17
#include <cstddef>
18
#include <cstdint>
19
#include <string>
20
21
#include "absl/base/macros.h"
22
#include "absl/base/nullability.h"
23
#include "absl/status/status.h"
24
#include "absl/status/statusor.h"
25
#include "absl/strings/str_cat.h"
26
#include "absl/types/variant.h"
27
#include "base/kind.h"
28
#include "internal/status_macros.h"
29
30
namespace cel {
31
32
namespace {
33
34
// Visitor for appending string representation for different qualifier kinds.
35
class AttributeStringPrinter {
36
 public:
37
  // String representation for the given qualifier is appended to output.
38
  // output must be non-null.
39
  explicit AttributeStringPrinter(std::string* output, Kind type)
40
0
      : output_(*output), type_(type) {}
41
42
0
  absl::Status operator()(const Kind& ignored) const {
43
    // Attributes are represented as a variant, with illegal attribute
44
    // qualifiers represented with their type as the first alternative.
45
0
    return absl::InvalidArgumentError(
46
0
        absl::StrCat("Unsupported attribute qualifier ", KindToString(type_)));
47
0
  }
48
49
0
  absl::Status operator()(int64_t index) {
50
0
    absl::StrAppend(&output_, "[", index, "]");
51
0
    return absl::OkStatus();
52
0
  }
53
54
0
  absl::Status operator()(uint64_t index) {
55
0
    absl::StrAppend(&output_, "[", index, "]");
56
0
    return absl::OkStatus();
57
0
  }
58
59
0
  absl::Status operator()(bool bool_key) {
60
0
    absl::StrAppend(&output_, "[", (bool_key) ? "true" : "false", "]");
61
0
    return absl::OkStatus();
62
0
  }
63
64
0
  absl::Status operator()(const std::string& field) {
65
0
    absl::StrAppend(&output_, ".", field);
66
0
    return absl::OkStatus();
67
0
  }
68
69
 private:
70
  std::string& output_;
71
  Kind type_;
72
};
73
74
// Visitor for appending string representation for different qualifier kinds.
75
class AttributeQualifierStringPrinter {
76
 public:
77
  // String representation for the given qualifier is appended to output.
78
  explicit AttributeQualifierStringPrinter(std::string* absl_nonnull output,
79
                                           Kind type)
80
0
      : output_(*output), type_(type) {}
81
82
0
  absl::Status operator()(const Kind& ignored) const {
83
    // Attributes are represented as a variant, with illegal attribute
84
    // qualifiers represented with their type as the first alternative.
85
0
    return absl::InvalidArgumentError(
86
0
        absl::StrCat("Unsupported attribute qualifier ", KindToString(type_)));
87
0
  }
88
89
0
  absl::Status operator()(int64_t index) {
90
0
    absl::StrAppend(&output_, index);
91
0
    return absl::OkStatus();
92
0
  }
93
94
0
  absl::Status operator()(uint64_t index) {
95
0
    absl::StrAppend(&output_, index);
96
0
    return absl::OkStatus();
97
0
  }
98
99
0
  absl::Status operator()(bool bool_key) {
100
0
    absl::StrAppend(&output_, (bool_key) ? "true" : "false");
101
0
    return absl::OkStatus();
102
0
  }
103
104
0
  absl::Status operator()(const std::string& field) {
105
0
    absl::StrAppend(&output_, field);
106
0
    return absl::OkStatus();
107
0
  }
108
109
 private:
110
  std::string& output_;
111
  Kind type_;
112
};
113
114
struct AttributeQualifierTypeVisitor final {
115
0
  Kind operator()(const Kind& type) const { return type; }
116
117
0
  Kind operator()(int64_t ignored) const {
118
0
    static_cast<void>(ignored);
119
0
    return Kind::kInt64;
120
0
  }
121
122
0
  Kind operator()(uint64_t ignored) const {
123
0
    static_cast<void>(ignored);
124
0
    return Kind::kUint64;
125
0
  }
126
127
0
  Kind operator()(const std::string& ignored) const {
128
0
    static_cast<void>(ignored);
129
0
    return Kind::kString;
130
0
  }
131
132
0
  Kind operator()(bool ignored) const {
133
0
    static_cast<void>(ignored);
134
0
    return Kind::kBool;
135
0
  }
136
};
137
138
struct AttributeQualifierTypeComparator final {
139
  const Kind lhs;
140
141
0
  bool operator()(const Kind& rhs) const {
142
0
    return static_cast<int>(lhs) < static_cast<int>(rhs);
143
0
  }
144
145
0
  bool operator()(int64_t) const { return false; }
146
147
0
  bool operator()(uint64_t other) const { return false; }
148
149
0
  bool operator()(const std::string&) const { return false; }
150
151
0
  bool operator()(bool other) const { return false; }
152
};
153
154
struct AttributeQualifierIntComparator final {
155
  const int64_t lhs;
156
157
0
  bool operator()(const Kind&) const { return true; }
158
159
0
  bool operator()(int64_t rhs) const { return lhs < rhs; }
160
161
0
  bool operator()(uint64_t) const { return true; }
162
163
0
  bool operator()(const std::string&) const { return true; }
164
165
0
  bool operator()(bool) const { return false; }
166
};
167
168
struct AttributeQualifierUintComparator final {
169
  const uint64_t lhs;
170
171
0
  bool operator()(const Kind&) const { return true; }
172
173
0
  bool operator()(int64_t) const { return false; }
174
175
0
  bool operator()(uint64_t rhs) const { return lhs < rhs; }
176
177
0
  bool operator()(const std::string&) const { return true; }
178
179
0
  bool operator()(bool) const { return false; }
180
};
181
182
struct AttributeQualifierStringComparator final {
183
  const std::string& lhs;
184
185
0
  bool operator()(const Kind&) const { return true; }
186
187
0
  bool operator()(int64_t) const { return false; }
188
189
0
  bool operator()(uint64_t) const { return false; }
190
191
0
  bool operator()(const std::string& rhs) const { return lhs < rhs; }
192
193
0
  bool operator()(bool) const { return false; }
194
};
195
196
struct AttributeQualifierBoolComparator final {
197
  const bool lhs;
198
199
0
  bool operator()(const Kind&) const { return true; }
200
201
0
  bool operator()(int64_t) const { return true; }
202
203
0
  bool operator()(uint64_t) const { return true; }
204
205
0
  bool operator()(const std::string&) const { return true; }
206
207
0
  bool operator()(bool rhs) const { return lhs < rhs; }
208
};
209
210
}  // namespace
211
212
struct AttributeQualifier::ComparatorVisitor final {
213
  const AttributeQualifier::Variant& rhs;
214
215
0
  bool operator()(const Kind& lhs) const {
216
0
    return absl::visit(AttributeQualifierTypeComparator{lhs}, rhs);
217
0
  }
218
219
0
  bool operator()(int64_t lhs) const {
220
0
    return absl::visit(AttributeQualifierIntComparator{lhs}, rhs);
221
0
  }
222
223
0
  bool operator()(uint64_t lhs) const {
224
0
    return absl::visit(AttributeQualifierUintComparator{lhs}, rhs);
225
0
  }
226
227
0
  bool operator()(const std::string& lhs) const {
228
0
    return absl::visit(AttributeQualifierStringComparator{lhs}, rhs);
229
0
  }
230
231
0
  bool operator()(bool lhs) const {
232
0
    return absl::visit(AttributeQualifierBoolComparator{lhs}, rhs);
233
0
  }
234
};
235
236
0
Kind AttributeQualifier::kind() const {
237
0
  return absl::visit(AttributeQualifierTypeVisitor{}, value_);
238
0
}
239
240
0
bool AttributeQualifier::operator<(const AttributeQualifier& other) const {
241
  // The order is not publicly documented because it is subject to change.
242
  // Currently we sort in the following order, with each type being sorted
243
  // against itself: bool, int, uint, string, type.
244
0
  return absl::visit(ComparatorVisitor{other.value_}, value_);
245
0
}
246
247
0
bool Attribute::operator==(const Attribute& other) const {
248
  // We cannot check pointer equality as a short circuit because we have to
249
  // treat all invalid AttributeQualifier as not equal to each other.
250
  // TODO(issues/41) we only support Ident-rooted attributes at the moment.
251
0
  if (variable_name() != other.variable_name()) {
252
0
    return false;
253
0
  }
254
255
0
  if (qualifier_path().size() != other.qualifier_path().size()) {
256
0
    return false;
257
0
  }
258
259
0
  for (size_t i = 0; i < qualifier_path().size(); i++) {
260
0
    if (!(qualifier_path()[i] == other.qualifier_path()[i])) {
261
0
      return false;
262
0
    }
263
0
  }
264
265
0
  return true;
266
0
}
267
268
0
bool Attribute::operator<(const Attribute& other) const {
269
0
  if (impl_.get() == other.impl_.get()) {
270
0
    return false;
271
0
  }
272
0
  auto lhs_begin = qualifier_path().begin();
273
0
  auto lhs_end = qualifier_path().end();
274
0
  auto rhs_begin = other.qualifier_path().begin();
275
0
  auto rhs_end = other.qualifier_path().end();
276
0
  while (lhs_begin != lhs_end && rhs_begin != rhs_end) {
277
0
    if (*lhs_begin < *rhs_begin) {
278
0
      return true;
279
0
    }
280
0
    if (!(*lhs_begin == *rhs_begin)) {
281
0
      return false;
282
0
    }
283
0
    lhs_begin++;
284
0
    rhs_begin++;
285
0
  }
286
0
  if (lhs_begin == lhs_end && rhs_begin == rhs_end) {
287
    // Neither has any elements left, they are equal. Compare variable names.
288
0
    return variable_name() < other.variable_name();
289
0
  }
290
0
  if (lhs_begin == lhs_end) {
291
    // Left has no more elements. Right is greater.
292
0
    return true;
293
0
  }
294
  // Right has no more elements. Left is greater.
295
0
  ABSL_ASSERT(rhs_begin == rhs_end);
296
0
  return false;
297
0
}
298
299
0
const absl::StatusOr<std::string> Attribute::AsString() const {
300
0
  if (variable_name().empty()) {
301
0
    return absl::InvalidArgumentError(
302
0
        "Only ident rooted attributes are supported.");
303
0
  }
304
305
0
  std::string result = std::string(variable_name());
306
307
0
  for (const auto& qualifier : qualifier_path()) {
308
0
    CEL_RETURN_IF_ERROR(absl::visit(
309
0
        AttributeStringPrinter(&result, qualifier.kind()), qualifier.value_));
310
0
  }
311
312
0
  return result;
313
0
}
314
315
0
bool AttributeQualifier::IsMatch(const AttributeQualifier& other) const {
316
0
  if (absl::holds_alternative<Kind>(value_) ||
317
0
      absl::holds_alternative<Kind>(other.value_)) {
318
0
    return false;
319
0
  }
320
0
  return value_ == other.value_;
321
0
}
322
323
0
absl::StatusOr<std::string> AttributeQualifier::AsString() const {
324
0
  std::string result;
325
0
  CEL_RETURN_IF_ERROR(
326
0
      absl::visit(AttributeQualifierStringPrinter(&result, kind()), value_));
327
0
  return result;
328
0
}
329
330
}  // namespace cel