Coverage Report

Created: 2026-10-09 06:57

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/proc/self/cwd/common/values/value_variant.cc
Line
Count
Source
1
// Copyright 2025 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 "common/values/value_variant.h"
16
17
#include <cstddef>
18
#include <cstring>
19
#include <memory>
20
#include <utility>
21
22
#include "absl/base/optimization.h"
23
#include "absl/log/absl_check.h"
24
#include "common/values/unknown_value.h"
25
#include "common/values/values.h"
26
27
namespace cel::common_internal {
28
29
0
void ValueVariant::SlowCopyConstruct(const ValueVariant& other) noexcept {
30
0
  ABSL_DCHECK((flags_ & ValueFlags::kNonTrivial) == ValueFlags::kNonTrivial);
31
32
0
  switch (index_) {
33
0
    case ValueIndex::kUnknown:
34
0
      ::new (static_cast<void*>(&raw_[0]))
35
0
          UnknownValue(*other.At<UnknownValue>());
36
0
      break;
37
0
    default:
38
0
      ABSL_UNREACHABLE();
39
0
  }
40
0
}
41
42
0
void ValueVariant::SlowMoveConstruct(ValueVariant& other) noexcept {
43
0
  ABSL_DCHECK((flags_ & ValueFlags::kNonTrivial) == ValueFlags::kNonTrivial);
44
45
0
  switch (index_) {
46
0
    case ValueIndex::kUnknown:
47
0
      ::new (static_cast<void*>(&raw_[0]))
48
0
          UnknownValue(std::move(*other.At<UnknownValue>()));
49
0
      break;
50
0
    default:
51
0
      ABSL_UNREACHABLE();
52
0
  }
53
0
}
54
55
0
void ValueVariant::SlowDestruct() noexcept {
56
0
  ABSL_DCHECK((flags_ & ValueFlags::kNonTrivial) == ValueFlags::kNonTrivial);
57
58
0
  switch (index_) {
59
0
    case ValueIndex::kUnknown:
60
0
      At<UnknownValue>()->~UnknownValue();
61
0
      break;
62
0
    default:
63
0
      ABSL_UNREACHABLE();
64
0
  }
65
0
}
66
67
void ValueVariant::SlowCopyAssign(const ValueVariant& other, bool trivial,
68
0
                                  bool other_trivial) noexcept {
69
0
  ABSL_DCHECK(!trivial || !other_trivial);
70
71
0
  if (trivial) {
72
0
    switch (other.index_) {
73
0
      case ValueIndex::kUnknown:
74
0
        ::new (static_cast<void*>(&raw_[0]))
75
0
            UnknownValue(*other.At<UnknownValue>());
76
0
        break;
77
0
      default:
78
0
        ABSL_UNREACHABLE();
79
0
    }
80
0
    index_ = other.index_;
81
0
    kind_ = other.kind_;
82
0
    flags_ = other.flags_;
83
0
  } else if (other_trivial) {
84
0
    switch (index_) {
85
0
      case ValueIndex::kUnknown:
86
0
        At<UnknownValue>()->~UnknownValue();
87
0
        break;
88
0
      default:
89
0
        ABSL_UNREACHABLE();
90
0
    }
91
0
    FastCopyAssign(other);
92
0
  } else {
93
0
    switch (index_) {
94
0
      case ValueIndex::kUnknown:
95
0
        switch (other.index_) {
96
0
          case ValueIndex::kUnknown:
97
0
            At<UnknownValue>()->~UnknownValue();
98
0
            ::new (static_cast<void*>(&raw_[0]))
99
0
                UnknownValue(*other.At<UnknownValue>());
100
0
            index_ = other.index_;
101
0
            kind_ = other.kind_;
102
0
            break;
103
0
          default:
104
0
            ABSL_UNREACHABLE();
105
0
        }
106
0
        break;
107
0
      default:
108
0
        ABSL_UNREACHABLE();
109
0
    }
110
0
    flags_ = other.flags_;
111
0
  }
112
0
}
113
114
void ValueVariant::SlowMoveAssign(ValueVariant& other, bool trivial,
115
0
                                  bool other_trivial) noexcept {
116
0
  ABSL_DCHECK(!trivial || !other_trivial);
117
118
0
  if (trivial) {
119
0
    switch (other.index_) {
120
0
      case ValueIndex::kUnknown:
121
0
        ::new (static_cast<void*>(&raw_[0]))
122
0
            UnknownValue(std::move(*other.At<UnknownValue>()));
123
0
        break;
124
0
      default:
125
0
        ABSL_UNREACHABLE();
126
0
    }
127
0
    index_ = other.index_;
128
0
    kind_ = other.kind_;
129
0
    flags_ = other.flags_;
130
0
  } else if (other_trivial) {
131
0
    switch (index_) {
132
0
      case ValueIndex::kUnknown:
133
0
        At<UnknownValue>()->~UnknownValue();
134
0
        break;
135
0
      default:
136
0
        ABSL_UNREACHABLE();
137
0
    }
138
0
    FastMoveAssign(other);
139
0
  } else {
140
0
    switch (index_) {
141
0
      case ValueIndex::kUnknown:
142
0
        switch (other.index_) {
143
0
          case ValueIndex::kUnknown:
144
0
            *At<UnknownValue>() = std::move(*other.At<UnknownValue>());
145
0
            break;
146
0
          default:
147
0
            ABSL_UNREACHABLE();
148
0
        }
149
0
        break;
150
0
      default:
151
0
        ABSL_UNREACHABLE();
152
0
    }
153
0
    flags_ = other.flags_;
154
0
  }
155
0
}
156
157
void ValueVariant::SlowSwap(ValueVariant& lhs, ValueVariant& rhs,
158
0
                            bool lhs_trivial, bool rhs_trivial) noexcept {
159
0
  using std::swap;
160
0
  ABSL_DCHECK(!lhs_trivial || !rhs_trivial);
161
162
0
  if (lhs_trivial) {
163
0
    alignas(ValueVariant) std::byte tmp[sizeof(ValueVariant)];
164
    // This is acceptable. We know that both are trivially copyable at runtime.
165
    // NOLINTNEXTLINE(bugprone-undefined-memory-manipulation)
166
0
    std::memcpy(tmp, std::addressof(lhs), sizeof(ValueVariant));
167
0
    switch (rhs.index_) {
168
0
      case ValueIndex::kUnknown:
169
0
        ::new (static_cast<void*>(&lhs.raw_[0]))
170
0
            UnknownValue(*rhs.At<UnknownValue>());
171
0
        rhs.At<UnknownValue>()->~UnknownValue();
172
0
        break;
173
0
      default:
174
0
        ABSL_UNREACHABLE();
175
0
    }
176
0
    lhs.index_ = rhs.index_;
177
0
    lhs.kind_ = rhs.kind_;
178
0
    lhs.flags_ = rhs.flags_;
179
    // This is acceptable. We know that both are trivially copyable at runtime.
180
    // NOLINTNEXTLINE(bugprone-undefined-memory-manipulation)
181
0
    std::memcpy(std::addressof(rhs), tmp, sizeof(ValueVariant));
182
0
  } else if (rhs_trivial) {
183
0
    alignas(ValueVariant) std::byte tmp[sizeof(ValueVariant)];
184
    // This is acceptable. We know that both are trivially copyable at runtime.
185
    // NOLINTNEXTLINE(bugprone-undefined-memory-manipulation)
186
0
    std::memcpy(tmp, std::addressof(rhs), sizeof(ValueVariant));
187
0
    switch (lhs.index_) {
188
0
      case ValueIndex::kUnknown:
189
0
        ::new (static_cast<void*>(&rhs.raw_[0]))
190
0
            UnknownValue(*lhs.At<UnknownValue>());
191
0
        lhs.At<UnknownValue>()->~UnknownValue();
192
0
        break;
193
0
      default:
194
0
        ABSL_UNREACHABLE();
195
0
    }
196
0
    rhs.index_ = lhs.index_;
197
0
    rhs.kind_ = lhs.kind_;
198
0
    rhs.flags_ = lhs.flags_;
199
    // This is acceptable. We know that both are trivially copyable at runtime.
200
    // NOLINTNEXTLINE(bugprone-undefined-memory-manipulation)
201
0
    std::memcpy(std::addressof(lhs), tmp, sizeof(ValueVariant));
202
0
  } else {
203
0
    ValueVariant tmp = std::move(lhs);
204
0
    lhs = std::move(rhs);
205
0
    rhs = std::move(tmp);
206
0
  }
207
0
}
208
209
}  // namespace cel::common_internal