Coverage Report

Created: 2026-05-27 07:00

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/proc/self/cwd/common/values/map_value.h
Line
Count
Source
1
// Copyright 2023 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
// IWYU pragma: private, include "common/value.h"
16
// IWYU pragma: friend "common/value.h"
17
18
// `MapValue` represents values of the primitive `map` type. It provides a
19
// unified interface for accessing map contents, regardless of the underlying
20
// implementation (e.g., JSON, protobuf map field, or custom implementation).
21
//
22
// Public member functions:
23
// - `IsEmpty()` / `Size()`: Query map size.
24
// - `Get()` / `Find()` / `Has()`: Access entries by key.
25
// - `ListKeys()` / `NewIterator()` / `ForEach()`: Iterate over entries.
26
// - `ConvertToJson()` / `ConvertToJsonObject()`: JSON conversion.
27
// - `IsCustom()` / `AsCustom()` / `GetCustom()`: Access custom implementation.
28
29
#ifndef THIRD_PARTY_CEL_CPP_COMMON_VALUES_MAP_VALUE_H_
30
#define THIRD_PARTY_CEL_CPP_COMMON_VALUES_MAP_VALUE_H_
31
32
#include <cstddef>
33
#include <memory>
34
#include <ostream>
35
#include <string>
36
#include <type_traits>
37
#include <utility>
38
39
#include "absl/base/attributes.h"
40
#include "absl/base/nullability.h"
41
#include "absl/meta/type_traits.h"
42
#include "absl/status/status.h"
43
#include "absl/status/statusor.h"
44
#include "absl/strings/string_view.h"
45
#include "absl/types/optional.h"
46
#include "absl/utility/utility.h"
47
#include "common/native_type.h"
48
#include "common/optional_ref.h"
49
#include "common/value_kind.h"
50
#include "common/values/custom_map_value.h"
51
#include "common/values/legacy_map_value.h"
52
#include "common/values/map_value_variant.h"
53
#include "common/values/parsed_json_map_value.h"
54
#include "common/values/parsed_map_field_value.h"
55
#include "common/values/values.h"
56
#include "google/protobuf/arena.h"
57
#include "google/protobuf/descriptor.h"
58
#include "google/protobuf/io/zero_copy_stream.h"
59
#include "google/protobuf/message.h"
60
61
namespace cel {
62
63
class MapValue;
64
class Value;
65
66
absl::Status CheckMapKey(const Value& key);
67
68
class MapValue final : private common_internal::MapValueMixin<MapValue> {
69
 public:
70
  static constexpr ValueKind kKind = ValueKind::kMap;
71
72
  // Move constructor for alternative struct values.
73
  template <typename T,
74
            typename = std::enable_if_t<common_internal::IsMapValueAlternativeV<
75
                absl::remove_cvref_t<T>>>>
76
  // NOLINTNEXTLINE(google-explicit-constructor)
77
  MapValue(T&& value)
78
9.03k
      : variant_(absl::in_place_type<absl::remove_cvref_t<T>>,
79
9.03k
                 std::forward<T>(value)) {}
cel::MapValue::MapValue<cel::CustomMapValue const&, void>(cel::CustomMapValue const&)
Line
Count
Source
78
5.71k
      : variant_(absl::in_place_type<absl::remove_cvref_t<T>>,
79
5.71k
                 std::forward<T>(value)) {}
cel::MapValue::MapValue<cel::common_internal::LegacyMapValue const&, void>(cel::common_internal::LegacyMapValue const&)
Line
Count
Source
78
666
      : variant_(absl::in_place_type<absl::remove_cvref_t<T>>,
79
666
                 std::forward<T>(value)) {}
Unexecuted instantiation: cel::MapValue::MapValue<cel::ParsedJsonMapValue const&, void>(cel::ParsedJsonMapValue const&)
Unexecuted instantiation: cel::MapValue::MapValue<cel::ParsedMapFieldValue const&, void>(cel::ParsedMapFieldValue const&)
cel::MapValue::MapValue<cel::CustomMapValue, void>(cel::CustomMapValue&&)
Line
Count
Source
78
1.97k
      : variant_(absl::in_place_type<absl::remove_cvref_t<T>>,
79
1.97k
                 std::forward<T>(value)) {}
cel::MapValue::MapValue<cel::common_internal::LegacyMapValue, void>(cel::common_internal::LegacyMapValue&&)
Line
Count
Source
78
677
      : variant_(absl::in_place_type<absl::remove_cvref_t<T>>,
79
677
                 std::forward<T>(value)) {}
Unexecuted instantiation: cel::MapValue::MapValue<cel::ParsedJsonMapValue, void>(cel::ParsedJsonMapValue&&)
Unexecuted instantiation: cel::MapValue::MapValue<cel::ParsedMapFieldValue, void>(cel::ParsedMapFieldValue&&)
80
81
6.15k
  MapValue() = default;
82
  MapValue(const MapValue&) = default;
83
  MapValue(MapValue&&) = default;
84
  MapValue& operator=(const MapValue&) = default;
85
  MapValue& operator=(MapValue&&) = default;
86
87
0
  constexpr ValueKind kind() const { return kKind; }
88
89
0
  static absl::string_view GetTypeName() { return "map"; }
90
91
  NativeTypeId GetTypeId() const;
92
93
  std::string DebugString() const;
94
95
  // See Value::SerializeTo().
96
  absl::Status SerializeTo(
97
      const google::protobuf::DescriptorPool* absl_nonnull descriptor_pool,
98
      google::protobuf::MessageFactory* absl_nonnull message_factory,
99
      google::protobuf::io::ZeroCopyOutputStream* absl_nonnull output) const;
100
101
  // See Value::ConvertToJson().
102
  absl::Status ConvertToJson(
103
      const google::protobuf::DescriptorPool* absl_nonnull descriptor_pool,
104
      google::protobuf::MessageFactory* absl_nonnull message_factory,
105
      google::protobuf::Message* absl_nonnull json) const;
106
107
  // Like ConvertToJson(), except `json` **MUST** be an instance of
108
  // `google.protobuf.Struct`.
109
  absl::Status ConvertToJsonObject(
110
      const google::protobuf::DescriptorPool* absl_nonnull descriptor_pool,
111
      google::protobuf::MessageFactory* absl_nonnull message_factory,
112
      google::protobuf::Message* absl_nonnull json) const;
113
114
  absl::Status Equal(const Value& other,
115
                     const google::protobuf::DescriptorPool* absl_nonnull descriptor_pool,
116
                     google::protobuf::MessageFactory* absl_nonnull message_factory,
117
                     google::protobuf::Arena* absl_nonnull arena,
118
                     Value* absl_nonnull result) const;
119
  using MapValueMixin::Equal;
120
121
  bool IsZeroValue() const;
122
123
  absl::StatusOr<bool> IsEmpty() const;
124
125
  absl::StatusOr<size_t> Size() const;
126
127
  // `Get` sets the value `result` to (via `result`) the value associated with
128
  // `key`. If `key` is not found, `no such key` is set to `result`. If an error
129
  // occurs (e.g., invalid key type), an `no such key` is returned.
130
  //
131
  // A non-ok status may be returned if an unexpected error is encountered or to
132
  // propagate an error from a custom implementation, in which case `result` is
133
  // unspecified.
134
  absl::Status Get(const Value& key,
135
                   const google::protobuf::DescriptorPool* absl_nonnull descriptor_pool,
136
                   google::protobuf::MessageFactory* absl_nonnull message_factory,
137
                   google::protobuf::Arena* absl_nonnull arena,
138
                   Value* absl_nonnull result) const;
139
  using MapValueMixin::Get;
140
141
  // `Find` returns `true` if `key` is found in the map, and stores the
142
  // associated value in `result`. If `key` is not found, `false` is returned
143
  // and `result` is unchanged.
144
  //
145
  // A non-ok status may be returned if an unexpected error is encountered or to
146
  // propagate an error from a custom implementation, in which case `result` is
147
  // unspecified.
148
  absl::StatusOr<bool> Find(
149
      const Value& key,
150
      const google::protobuf::DescriptorPool* absl_nonnull descriptor_pool,
151
      google::protobuf::MessageFactory* absl_nonnull message_factory,
152
      google::protobuf::Arena* absl_nonnull arena, Value* absl_nonnull result) const;
153
  using MapValueMixin::Find;
154
155
  // `Has` returns `true` if `key` is found in the map, and stores the BoolValue
156
  // result in `result`. In case of an error, the result is set to an
157
  // ErrorValue.
158
  //
159
  // A non-ok status may be returned if an unexpected error is encountered or to
160
  // propagate an error from a custom implementation, in which case `result` is
161
  // unspecified.
162
  absl::Status Has(const Value& key,
163
                   const google::protobuf::DescriptorPool* absl_nonnull descriptor_pool,
164
                   google::protobuf::MessageFactory* absl_nonnull message_factory,
165
                   google::protobuf::Arena* absl_nonnull arena,
166
                   Value* absl_nonnull result) const;
167
  using MapValueMixin::Has;
168
169
  // `ListKeys` returns a `ListValue` containing all keys in the map.
170
  absl::Status ListKeys(
171
      const google::protobuf::DescriptorPool* absl_nonnull descriptor_pool,
172
      google::protobuf::MessageFactory* absl_nonnull message_factory,
173
      google::protobuf::Arena* absl_nonnull arena, ListValue* absl_nonnull result) const;
174
  using MapValueMixin::ListKeys;
175
176
  // `ForEachCallback` is the callback type for `ForEach`.
177
  using ForEachCallback = typename CustomMapValueInterface::ForEachCallback;
178
179
  // `ForEach` calls `callback` for each entry in the map. Iteration continues
180
  // until all entries are visited or `callback` returns an error or `false`.
181
  absl::Status ForEach(
182
      ForEachCallback callback,
183
      const google::protobuf::DescriptorPool* absl_nonnull descriptor_pool,
184
      google::protobuf::MessageFactory* absl_nonnull message_factory,
185
      google::protobuf::Arena* absl_nonnull arena) const;
186
187
  // `NewIterator` returns a new iterator for the map.
188
  absl::StatusOr<absl_nonnull ValueIteratorPtr> NewIterator() const;
189
190
  // Returns `true` if this value is an instance of a custom map value.
191
0
  bool IsCustom() const { return variant_.Is<CustomMapValue>(); }
192
193
  // Convenience method for use with template metaprogramming. See
194
  // `IsCustom()`.
195
  template <typename T>
196
  std::enable_if_t<std::is_same_v<CustomMapValue, T>, bool> Is() const {
197
    return IsCustom();
198
  }
199
200
  // Performs a checked cast from a value to a custom map value,
201
  // returning a non-empty optional with either a value or reference to the
202
  // custom map value. Otherwise an empty optional is returned.
203
  optional_ref<const CustomMapValue> AsCustom() &
204
0
      ABSL_ATTRIBUTE_LIFETIME_BOUND {
205
0
    return std::as_const(*this).AsCustom();
206
0
  }
207
  optional_ref<const CustomMapValue> AsCustom()
208
      const& ABSL_ATTRIBUTE_LIFETIME_BOUND;
209
  absl::optional<CustomMapValue> AsCustom() &&;
210
0
  absl::optional<CustomMapValue> AsCustom() const&& {
211
0
    return common_internal::AsOptional(AsCustom());
212
0
  }
213
214
  // Convenience method for use with template metaprogramming. See
215
  // `AsCustom()`.
216
  template <typename T>
217
      std::enable_if_t<std::is_same_v<CustomMapValue, T>,
218
                       optional_ref<const CustomMapValue>>
219
      As() & ABSL_ATTRIBUTE_LIFETIME_BOUND {
220
    return AsCustom();
221
  }
222
  template <typename T>
223
  std::enable_if_t<std::is_same_v<CustomMapValue, T>,
224
                   optional_ref<const CustomMapValue>>
225
  As() const& ABSL_ATTRIBUTE_LIFETIME_BOUND {
226
    return AsCustom();
227
  }
228
  template <typename T>
229
  std::enable_if_t<std::is_same_v<CustomMapValue, T>,
230
                   absl::optional<CustomMapValue>>
231
  As() && {
232
    return std::move(*this).AsCustom();
233
  }
234
  template <typename T>
235
  std::enable_if_t<std::is_same_v<CustomMapValue, T>,
236
                   absl::optional<CustomMapValue>>
237
  As() const&& {
238
    return std::move(*this).AsCustom();
239
  }
240
241
  // Performs an unchecked cast from a value to a custom map value. In
242
  // debug builds a best effort is made to crash. If `IsCustom()` would
243
  // return false, calling this method is undefined behavior.
244
0
  const CustomMapValue& GetCustom() & ABSL_ATTRIBUTE_LIFETIME_BOUND {
245
0
    return std::as_const(*this).GetCustom();
246
0
  }
247
  const CustomMapValue& GetCustom() const& ABSL_ATTRIBUTE_LIFETIME_BOUND;
248
  CustomMapValue GetCustom() &&;
249
0
  CustomMapValue GetCustom() const&& { return GetCustom(); }
250
251
  // Convenience method for use with template metaprogramming. See
252
  // `GetCustom()`.
253
  template <typename T>
254
      std::enable_if_t<std::is_same_v<CustomMapValue, T>, const CustomMapValue&>
255
      Get() & ABSL_ATTRIBUTE_LIFETIME_BOUND {
256
    return GetCustom();
257
  }
258
  template <typename T>
259
  std::enable_if_t<std::is_same_v<CustomMapValue, T>, const CustomMapValue&>
260
  Get() const& ABSL_ATTRIBUTE_LIFETIME_BOUND {
261
    return GetCustom();
262
  }
263
  template <typename T>
264
  std::enable_if_t<std::is_same_v<CustomMapValue, T>, CustomMapValue> Get() && {
265
    return std::move(*this).GetCustom();
266
  }
267
  template <typename T>
268
  std::enable_if_t<std::is_same_v<CustomMapValue, T>, CustomMapValue> Get()
269
      const&& {
270
    return std::move(*this).GetCustom();
271
  }
272
273
0
  friend void swap(MapValue& lhs, MapValue& rhs) noexcept {
274
0
    using std::swap;
275
0
    swap(lhs.variant_, rhs.variant_);
276
0
  }
277
278
 private:
279
  friend class Value;
280
  friend class common_internal::ValueMixin<MapValue>;
281
  friend class common_internal::MapValueMixin<MapValue>;
282
283
  common_internal::ValueVariant ToValueVariant() const&;
284
  common_internal::ValueVariant ToValueVariant() &&;
285
286
  // Unlike many of the other derived values, `MapValue` is itself a composed
287
  // type. This is to avoid making `MapValue` too big and by extension
288
  // `Value` too big. Instead we store the derived `MapValue` values in
289
  // `Value` and not `MapValue` itself.
290
  common_internal::MapValueVariant variant_;
291
};
292
293
0
inline std::ostream& operator<<(std::ostream& out, const MapValue& value) {
294
0
  return out << value.DebugString();
295
0
}
296
297
template <>
298
struct NativeTypeTraits<MapValue> final {
299
0
  static NativeTypeId Id(const MapValue& value) { return value.GetTypeId(); }
300
};
301
302
class MapValueBuilder {
303
 public:
304
8.29k
  virtual ~MapValueBuilder() = default;
305
306
  virtual absl::Status Put(Value key, Value value) = 0;
307
308
  virtual void UnsafePut(Value key, Value value) = 0;
309
310
0
  virtual bool IsEmpty() const { return Size() == 0; }
311
312
  virtual size_t Size() const = 0;
313
314
0
  virtual void Reserve(size_t capacity [[maybe_unused]]) {}
315
316
  virtual MapValue Build() && = 0;
317
};
318
319
using MapValueBuilderPtr = std::unique_ptr<MapValueBuilder>;
320
321
}  // namespace cel
322
323
#endif  // THIRD_PARTY_CEL_CPP_COMMON_VALUES_MAP_VALUE_H_