Skip to content

Commit 18b6b38

Browse files
jckingcopybara-github
authored andcommitted
Drop cel::Value back down to 32 bytes
PiperOrigin-RevId: 733781507
1 parent b424503 commit 18b6b38

File tree

5 files changed

+100
-74
lines changed

5 files changed

+100
-74
lines changed

common/value.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2643,6 +2643,8 @@ struct NativeTypeTraits<Value> final {
26432643
};
26442644

26452645
// Statically assert some expectations.
2646+
static_assert(sizeof(Value) <= 32);
2647+
static_assert(alignof(Value) <= alignof(std::max_align_t));
26462648
static_assert(std::is_default_constructible_v<Value>);
26472649
static_assert(std::is_copy_constructible_v<Value>);
26482650
static_assert(std::is_copy_assignable_v<Value>);

common/values/error_value.cc

Lines changed: 25 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -13,19 +13,18 @@
1313
// limitations under the License.
1414

1515
#include <cstddef>
16+
#include <new>
1617
#include <string>
1718
#include <utility>
1819

1920
#include "absl/base/no_destructor.h"
2021
#include "absl/base/nullability.h"
21-
#include "absl/functional/overload.h"
2222
#include "absl/log/absl_check.h"
2323
#include "absl/status/status.h"
2424
#include "absl/strings/cord.h"
2525
#include "absl/strings/match.h"
2626
#include "absl/strings/str_cat.h"
2727
#include "absl/strings/string_view.h"
28-
#include "absl/types/variant.h"
2928
#include "common/allocator.h"
3029
#include "common/type.h"
3130
#include "common/value.h"
@@ -152,60 +151,46 @@ ErrorValue ErrorValue::Clone(Allocator<> allocator) const {
152151
ABSL_DCHECK(*this);
153152
if (absl::Nullable<google::protobuf::Arena*> arena = allocator.arena();
154153
arena != nullptr) {
155-
return ErrorValue(absl::visit(
156-
absl::Overload(
157-
[arena](const absl::Status& status) -> ArenaStatus {
158-
return ArenaStatus{
159-
arena, google::protobuf::Arena::Create<absl::Status>(arena, status)};
160-
},
161-
[arena](const ArenaStatus& status) -> ArenaStatus {
162-
if (status.first != nullptr && status.first != arena) {
163-
return ArenaStatus{arena, google::protobuf::Arena::Create<absl::Status>(
164-
arena, *status.second)};
165-
}
166-
return status;
167-
}),
168-
variant_));
154+
if (arena_ == nullptr || arena_ != arena) {
155+
return ErrorValue(arena,
156+
google::protobuf::Arena::Create<absl::Status>(arena, ToStatus()));
157+
}
169158
}
170159
return ErrorValue(ToStatus());
171160
}
172161

173162
absl::Status ErrorValue::ToStatus() const& {
174163
ABSL_DCHECK(*this);
175-
return absl::visit(absl::Overload(
176-
[](const absl::Status& status) -> const absl::Status& {
177-
return status;
178-
},
179-
[](const ArenaStatus& status) -> const absl::Status& {
180-
return *status.second;
181-
}),
182-
variant_);
164+
165+
if (arena_ == nullptr) {
166+
return *std::launder(
167+
reinterpret_cast<const absl::Status*>(&status_.val[0]));
168+
}
169+
return *status_.ptr;
183170
}
184171

185172
absl::Status ErrorValue::ToStatus() && {
186173
ABSL_DCHECK(*this);
187-
return absl::visit(absl::Overload(
188-
[](absl::Status&& status) -> absl::Status {
189-
return std::move(status);
190-
},
191-
[](const ArenaStatus& status) -> absl::Status {
192-
return *status.second;
193-
}),
194-
std::move(variant_));
174+
175+
if (arena_ == nullptr) {
176+
return std::move(
177+
*std::launder(reinterpret_cast<absl::Status*>(&status_.val[0])));
178+
}
179+
return *status_.ptr;
195180
}
196181

197182
ErrorValue::operator bool() const {
198-
return absl::visit(
199-
absl::Overload(
200-
[](const absl::Status& status) -> bool { return !status.ok(); },
201-
[](const ArenaStatus& status) -> bool {
202-
return !status.second->ok();
203-
}),
204-
variant_);
183+
if (arena_ == nullptr) {
184+
return !std::launder(reinterpret_cast<const absl::Status*>(&status_.val[0]))
185+
->ok();
186+
}
187+
return status_.ptr != nullptr && !status_.ptr->ok();
205188
}
206189

207190
void swap(ErrorValue& lhs, ErrorValue& rhs) noexcept {
208-
lhs.variant_.swap(rhs.variant_);
191+
ErrorValue tmp(std::move(lhs));
192+
lhs = std::move(rhs);
193+
rhs = std::move(tmp);
209194
}
210195

211196
} // namespace cel

common/values/error_value.h

Lines changed: 62 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
#define THIRD_PARTY_CEL_CPP_COMMON_VALUES_ERROR_VALUE_H_
2020

2121
#include <cstddef>
22+
#include <new>
2223
#include <ostream>
2324
#include <string>
2425
#include <type_traits>
@@ -30,8 +31,6 @@
3031
#include "absl/status/status.h"
3132
#include "absl/strings/cord.h"
3233
#include "absl/strings/string_view.h"
33-
#include "absl/types/variant.h"
34-
#include "absl/utility/utility.h"
3534
#include "common/allocator.h"
3635
#include "common/type.h"
3736
#include "common/value_kind.h"
@@ -43,36 +42,47 @@
4342
namespace cel {
4443

4544
class Value;
46-
class ErrorValue;
47-
class TypeManager;
4845

4946
// `ErrorValue` represents values of the `ErrorType`.
50-
class ErrorValue final : private common_internal::ValueMixin<ErrorValue> {
47+
class ABSL_ATTRIBUTE_TRIVIAL_ABI ErrorValue final
48+
: private common_internal::ValueMixin<ErrorValue> {
5149
public:
5250
static constexpr ValueKind kKind = ValueKind::kError;
5351

54-
explicit ErrorValue(absl::Status value)
55-
: variant_(absl::in_place_type<absl::Status>, std::move(value)) {
52+
explicit ErrorValue(absl::Status value) : arena_(nullptr) {
53+
::new (static_cast<void*>(&status_.val[0])) absl::Status(std::move(value));
5654
ABSL_DCHECK(*this) << "ErrorValue requires a non-OK absl::Status";
5755
}
5856

59-
ErrorValue& operator=(absl::Status status) {
60-
variant_.emplace<absl::Status>(std::move(status));
61-
ABSL_DCHECK(*this) << "ErrorValue requires a non-OK absl::Status";
62-
return *this;
63-
}
64-
6557
// By default, this creates an UNKNOWN error. You should always create a more
6658
// specific error value.
6759
ErrorValue();
68-
ErrorValue(const ErrorValue&) = default;
69-
ErrorValue(ErrorValue&&) = default;
70-
ErrorValue& operator=(const ErrorValue&) = default;
71-
ErrorValue& operator=(ErrorValue&&) = default;
7260

73-
constexpr ValueKind kind() const { return kKind; }
61+
ErrorValue(const ErrorValue& other) { CopyConstruct(other); }
62+
63+
ErrorValue(ErrorValue&& other) noexcept { MoveConstruct(other); }
64+
65+
~ErrorValue() { Destruct(); }
66+
67+
ErrorValue& operator=(const ErrorValue& other) {
68+
if (this != &other) {
69+
Destruct();
70+
CopyConstruct(other);
71+
}
72+
return *this;
73+
}
74+
75+
ErrorValue& operator=(ErrorValue&& other) noexcept {
76+
if (this != &other) {
77+
Destruct();
78+
MoveConstruct(other);
79+
}
80+
return *this;
81+
}
7482

75-
absl::string_view GetTypeName() const { return ErrorType::kName; }
83+
static constexpr ValueKind kind() { return kKind; }
84+
85+
static absl::string_view GetTypeName() { return ErrorType::kName; }
7686

7787
std::string DebugString() const;
7888

@@ -116,18 +126,42 @@ class ErrorValue final : private common_internal::ValueMixin<ErrorValue> {
116126
private:
117127
friend class common_internal::ValueMixin<ErrorValue>;
118128

119-
using ArenaStatus = std::pair<absl::Nullable<google::protobuf::Arena*>,
120-
absl::Nonnull<const absl::Status*>>;
121-
using Variant = absl::variant<absl::Status, ArenaStatus>;
122-
123-
ErrorValue(absl::Nullable<google::protobuf::Arena*> arena,
129+
ErrorValue(absl::Nonnull<google::protobuf::Arena*> arena,
124130
absl::Nonnull<const absl::Status*> status)
125-
: variant_(absl::in_place_type<ArenaStatus>, arena, status) {}
131+
: arena_(arena), status_{.ptr = status} {}
132+
133+
void CopyConstruct(const ErrorValue& other) {
134+
arena_ = other.arena_;
135+
if (arena_ == nullptr) {
136+
::new (static_cast<void*>(&status_.val[0])) absl::Status(*std::launder(
137+
reinterpret_cast<const absl::Status*>(&other.status_.val[0])));
138+
} else {
139+
status_.ptr = other.status_.ptr;
140+
}
141+
}
142+
143+
void MoveConstruct(ErrorValue& other) {
144+
arena_ = other.arena_;
145+
if (arena_ == nullptr) {
146+
::new (static_cast<void*>(&status_.val[0]))
147+
absl::Status(std::move(*std::launder(
148+
reinterpret_cast<absl::Status*>(&other.status_.val[0]))));
149+
} else {
150+
status_.ptr = other.status_.ptr;
151+
}
152+
}
126153

127-
explicit ErrorValue(const ArenaStatus& status)
128-
: ErrorValue(status.first, status.second) {}
154+
void Destruct() {
155+
if (arena_ == nullptr) {
156+
std::launder(reinterpret_cast<absl::Status*>(&status_.val[0]))->~Status();
157+
}
158+
}
129159

130-
Variant variant_;
160+
absl::Nullable<google::protobuf::Arena*> arena_;
161+
union {
162+
alignas(absl::Status) char val[sizeof(absl::Status)];
163+
absl::Nonnull<const absl::Status*> ptr;
164+
} status_;
131165
};
132166

133167
ErrorValue NoSuchFieldError(absl::string_view field);

common/values/type_value.h

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,9 @@ class TypeValue final : private common_internal::ValueMixin<TypeValue> {
4646
public:
4747
static constexpr ValueKind kKind = ValueKind::kType;
4848

49-
explicit TypeValue(Type value) : value_(std::move(value)) {}
49+
explicit TypeValue(Type value) {
50+
::new (static_cast<void*>(&value_[0])) Type(value);
51+
}
5052

5153
TypeValue() = default;
5254
TypeValue(const TypeValue&) = default;
@@ -58,7 +60,7 @@ class TypeValue final : private common_internal::ValueMixin<TypeValue> {
5860

5961
absl::string_view GetTypeName() const { return TypeType::kName; }
6062

61-
std::string DebugString() const { return value_.DebugString(); }
63+
std::string DebugString() const { return type().DebugString(); }
6264

6365
// See Value::SerializeTo().
6466
absl::Status SerializeTo(
@@ -83,10 +85,12 @@ class TypeValue final : private common_internal::ValueMixin<TypeValue> {
8385

8486
ABSL_DEPRECATED(("Use type()"))
8587
const Type& NativeValue() const ABSL_ATTRIBUTE_LIFETIME_BOUND {
86-
return value_;
88+
return type();
8789
}
8890

89-
const Type& type() const ABSL_ATTRIBUTE_LIFETIME_BOUND { return value_; }
91+
const Type& type() const ABSL_ATTRIBUTE_LIFETIME_BOUND {
92+
return *reinterpret_cast<const Type*>(&value_[0]);
93+
}
9094

9195
void swap(TypeValue& other) noexcept {
9296
using std::swap;
@@ -104,7 +108,7 @@ class TypeValue final : private common_internal::ValueMixin<TypeValue> {
104108
friend struct NativeTypeTraits<TypeValue>;
105109
friend class common_internal::ValueMixin<TypeValue>;
106110

107-
Type value_;
111+
alignas(Type) char value_[sizeof(Type)];
108112
};
109113

110114
inline std::ostream& operator<<(std::ostream& out, const TypeValue& value) {

common/values/values.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
#include <type_traits>
2424
#include <utility>
2525

26+
#include "absl/base/attributes.h"
2627
#include "absl/base/nullability.h"
2728
#include "absl/functional/function_ref.h"
2829
#include "absl/status/status.h"
@@ -50,7 +51,7 @@ class BoolValue;
5051
class BytesValue;
5152
class DoubleValue;
5253
class DurationValue;
53-
class ErrorValue;
54+
class ABSL_ATTRIBUTE_TRIVIAL_ABI ErrorValue;
5455
class IntValue;
5556
class ListValue;
5657
class MapValue;

0 commit comments

Comments
 (0)