Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 2 additions & 3 deletions common/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -830,6 +830,7 @@ cc_library(
"@com_google_absl//absl/strings:string_view",
"@com_google_absl//absl/time",
"@com_google_absl//absl/types:optional",
"@com_google_absl//absl/types:optional_ref",
"@com_google_absl//absl/types:source_location",
"@com_google_absl//absl/types:span",
"@com_google_absl//absl/types:variant",
Expand Down Expand Up @@ -976,9 +977,7 @@ cc_library(
hdrs = ["optional_ref.h"],
deps = [
"@com_google_absl//absl/base:core_headers",
"@com_google_absl//absl/base:nullability",
"@com_google_absl//absl/types:optional",
"@com_google_absl//absl/utility",
"@com_google_absl//absl/types:optional_ref",
],
)

Expand Down
128 changes: 9 additions & 119 deletions common/optional_ref.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,144 +15,34 @@
#ifndef THIRD_PARTY_CEL_CPP_OPTIONAL_REF_H_
#define THIRD_PARTY_CEL_CPP_OPTIONAL_REF_H_

#include <memory>
#include <optional>
#include <type_traits>

#include "absl/base/attributes.h"
#include "absl/base/macros.h"
#include "absl/base/nullability.h"
#include "absl/base/optimization.h"
#include "absl/types/optional.h"
#include "absl/utility/utility.h"
#include "absl/types/optional_ref.h"

namespace cel {

// `optional_ref<T>` looks and feels like `absl::optional<T>`, but instead of
// owning the underlying value, it retains a reference to the value it accepts
// in its constructor.
template <typename T>
class optional_ref final {
public:
static_assert(!std::is_reference_v<T>, "T must not be a reference.");
static_assert(!std::is_same_v<absl::nullopt_t, std::remove_cv_t<T>>,
"optional_ref<absl::nullopt_t> is not allowed.");
static_assert(!std::is_same_v<absl::in_place_t, std::remove_cv_t<T>>,
"optional_ref<absl::in_place_t> is not allowed.");

using value_type = T;

optional_ref() = default;

// NOLINTNEXTLINE(google-explicit-constructor)
constexpr optional_ref(absl::nullopt_t) : optional_ref() {}

// NOLINTNEXTLINE(google-explicit-constructor)
constexpr optional_ref(T& value ABSL_ATTRIBUTE_LIFETIME_BOUND)
: value_(std::addressof(value)) {}

template <
typename U,
typename = std::enable_if_t<std::conjunction_v<
std::is_const<T>, std::is_same<std::decay_t<U>, std::decay_t<T>>>>>
// NOLINTNEXTLINE(google-explicit-constructor)
constexpr optional_ref(
const absl::optional<U>& value ABSL_ATTRIBUTE_LIFETIME_BOUND)
: value_(value.has_value() ? std::addressof(*value) : nullptr) {}

template <typename U, typename = std::enable_if_t<
std::is_same_v<std::decay_t<U>, std::decay_t<T>>>>
// NOLINTNEXTLINE(google-explicit-constructor)
constexpr optional_ref(absl::optional<U>& value ABSL_ATTRIBUTE_LIFETIME_BOUND)
: value_(value.has_value() ? std::addressof(*value) : nullptr) {}

template <
typename U,
typename = std::enable_if_t<std::conjunction_v<
std::negation<std::is_same<U, T>>,
std::is_convertible<std::add_pointer_t<U>, std::add_pointer_t<T>>>>>
// NOLINTNEXTLINE(google-explicit-constructor)
constexpr optional_ref(const optional_ref<U>& other) : value_(other.value_) {}

optional_ref(const optional_ref<T>&) = default;

optional_ref<T>& operator=(const optional_ref<T>&) = delete;

constexpr bool has_value() const { return value_ != nullptr; }

constexpr explicit operator bool() const { return has_value(); }

constexpr T& value() const {
return ABSL_PREDICT_TRUE(has_value())
? *value_
// Replicate the same error logic as in `absl::optional`'s
// `value()`. It either throws an exception or aborts the
// program. We intentionally ignore the return value of
// the constructed optional's value as we only need to run
// the code for error checking.
: ((void)absl::optional<T>().value(), *value_);
}

constexpr T& operator*() const {
ABSL_ASSERT(has_value());
return *value_;
}

constexpr T* absl_nonnull operator->() const {
ABSL_ASSERT(has_value());
return value_;
}

private:
template <typename U>
friend class optional_ref;

T* const value_ = nullptr;
};

template <typename T>
optional_ref(const T&) -> optional_ref<const T>;

template <typename T>
optional_ref(T&) -> optional_ref<T>;

template <typename T>
optional_ref(const absl::optional<T>&) -> optional_ref<const T>;

template <typename T>
optional_ref(absl::optional<T>&) -> optional_ref<T>;

template <typename T>
constexpr bool operator==(const optional_ref<T>& lhs, absl::nullopt_t) {
return !lhs.has_value();
}

template <typename T>
constexpr bool operator==(absl::nullopt_t, const optional_ref<T>& rhs) {
return !rhs.has_value();
}

template <typename T>
constexpr bool operator!=(const optional_ref<T>& lhs, absl::nullopt_t) {
return !operator==(lhs, absl::nullopt);
}

template <typename T>
constexpr bool operator!=(absl::nullopt_t, const optional_ref<T>& rhs) {
return !operator==(absl::nullopt, rhs);
}
using optional_ref ABSL_DEPRECATE_AND_INLINE() = absl::optional_ref<T>;

namespace common_internal {

template <typename T>
absl::optional<std::decay_t<T>> AsOptional(optional_ref<T> ref) {
if (ref) {
[[nodiscard]]
std::optional<std::decay_t<T>> AsOptional(absl::optional_ref<T> ref) {
if (ref.has_value()) {
return *ref;
}
return absl::nullopt;
return std::nullopt;
}

template <typename T>
absl::optional<T> AsOptional(absl::optional<T> opt) {
[[nodiscard]]
std::optional<T> AsOptional(std::optional<T> opt) {
return opt;
}

Expand Down
34 changes: 17 additions & 17 deletions common/value.cc
Original file line number Diff line number Diff line change
Expand Up @@ -40,11 +40,11 @@
#include "absl/strings/string_view.h"
#include "absl/time/time.h"
#include "absl/types/optional.h"
#include "absl/types/optional_ref.h"
#include "absl/types/source_location.h"
#include "absl/types/variant.h"
#include "common/allocator.h"
#include "common/memory.h"
#include "common/optional_ref.h"
#include "common/type.h"
#include "common/value_kind.h"
#include "common/values/list_value_builder.h"
Expand Down Expand Up @@ -2008,7 +2008,7 @@ Value Value::WrapMapFieldValueUnsafe(
message_factory, arena);
}

optional_ref<const BytesValue> Value::AsBytes() const& {
absl::optional_ref<const BytesValue> Value::AsBytes() const& {
if (const auto* alternative = variant_.As<BytesValue>();
alternative != nullptr) {
return *alternative;
Expand Down Expand Up @@ -2039,7 +2039,7 @@ absl::optional<DurationValue> Value::AsDuration() const {
return std::nullopt;
}

optional_ref<const ErrorValue> Value::AsError() const& {
absl::optional_ref<const ErrorValue> Value::AsError() const& {
if (const auto* alternative = variant_.As<ErrorValue>();
alternative != nullptr) {
return *alternative;
Expand Down Expand Up @@ -2166,7 +2166,7 @@ absl::optional<NullValue> Value::AsNull() const {
return std::nullopt;
}

optional_ref<const OpaqueValue> Value::AsOpaque() const& {
absl::optional_ref<const OpaqueValue> Value::AsOpaque() const& {
if (const auto* alternative = variant_.As<OpaqueValue>();
alternative != nullptr) {
return *alternative;
Expand All @@ -2181,7 +2181,7 @@ absl::optional<OpaqueValue> Value::AsOpaque() && {
return std::nullopt;
}

optional_ref<const OptionalValue> Value::AsOptional() const& {
absl::optional_ref<const OptionalValue> Value::AsOptional() const& {
if (const auto* alternative = variant_.As<OpaqueValue>();
alternative != nullptr && alternative->IsOptional()) {
return static_cast<const OptionalValue&>(*alternative);
Expand All @@ -2197,7 +2197,7 @@ absl::optional<OptionalValue> Value::AsOptional() && {
return std::nullopt;
}

optional_ref<const ParsedJsonListValue> Value::AsParsedJsonList() const& {
absl::optional_ref<const ParsedJsonListValue> Value::AsParsedJsonList() const& {
if (const auto* alternative = variant_.As<ParsedJsonListValue>();
alternative != nullptr) {
return *alternative;
Expand All @@ -2213,7 +2213,7 @@ absl::optional<ParsedJsonListValue> Value::AsParsedJsonList() && {
return std::nullopt;
}

optional_ref<const ParsedJsonMapValue> Value::AsParsedJsonMap() const& {
absl::optional_ref<const ParsedJsonMapValue> Value::AsParsedJsonMap() const& {
if (const auto* alternative = variant_.As<ParsedJsonMapValue>();
alternative != nullptr) {
return *alternative;
Expand All @@ -2229,7 +2229,7 @@ absl::optional<ParsedJsonMapValue> Value::AsParsedJsonMap() && {
return std::nullopt;
}

optional_ref<const CustomListValue> Value::AsCustomList() const& {
absl::optional_ref<const CustomListValue> Value::AsCustomList() const& {
if (const auto* alternative = variant_.As<CustomListValue>();
alternative != nullptr) {
return *alternative;
Expand All @@ -2245,7 +2245,7 @@ absl::optional<CustomListValue> Value::AsCustomList() && {
return std::nullopt;
}

optional_ref<const CustomMapValue> Value::AsCustomMap() const& {
absl::optional_ref<const CustomMapValue> Value::AsCustomMap() const& {
if (const auto* alternative = variant_.As<CustomMapValue>();
alternative != nullptr) {
return *alternative;
Expand All @@ -2261,7 +2261,7 @@ absl::optional<CustomMapValue> Value::AsCustomMap() && {
return std::nullopt;
}

optional_ref<const ParsedMapFieldValue> Value::AsParsedMapField() const& {
absl::optional_ref<const ParsedMapFieldValue> Value::AsParsedMapField() const& {
if (const auto* alternative = variant_.As<ParsedMapFieldValue>();
alternative != nullptr) {
return *alternative;
Expand All @@ -2277,7 +2277,7 @@ absl::optional<ParsedMapFieldValue> Value::AsParsedMapField() && {
return std::nullopt;
}

optional_ref<const ParsedMessageValue> Value::AsParsedMessage() const& {
absl::optional_ref<const ParsedMessageValue> Value::AsParsedMessage() const& {
if (const auto* alternative = variant_.As<ParsedMessageValue>();
alternative != nullptr) {
return *alternative;
Expand All @@ -2293,8 +2293,8 @@ absl::optional<ParsedMessageValue> Value::AsParsedMessage() && {
return std::nullopt;
}

optional_ref<const ParsedRepeatedFieldValue> Value::AsParsedRepeatedField()
const& {
absl::optional_ref<const ParsedRepeatedFieldValue>
Value::AsParsedRepeatedField() const& {
if (const auto* alternative = variant_.As<ParsedRepeatedFieldValue>();
alternative != nullptr) {
return *alternative;
Expand All @@ -2310,7 +2310,7 @@ absl::optional<ParsedRepeatedFieldValue> Value::AsParsedRepeatedField() && {
return std::nullopt;
}

optional_ref<const CustomStructValue> Value::AsCustomStruct() const& {
absl::optional_ref<const CustomStructValue> Value::AsCustomStruct() const& {
if (const auto* alternative = variant_.As<CustomStructValue>();
alternative != nullptr) {
return *alternative;
Expand All @@ -2326,7 +2326,7 @@ absl::optional<CustomStructValue> Value::AsCustomStruct() && {
return std::nullopt;
}

optional_ref<const StringValue> Value::AsString() const& {
absl::optional_ref<const StringValue> Value::AsString() const& {
if (const auto* alternative = variant_.As<StringValue>();
alternative != nullptr) {
return *alternative;
Expand Down Expand Up @@ -2382,7 +2382,7 @@ absl::optional<TimestampValue> Value::AsTimestamp() const {
return std::nullopt;
}

optional_ref<const TypeValue> Value::AsType() const& {
absl::optional_ref<const TypeValue> Value::AsType() const& {
if (const auto* alternative = variant_.As<TypeValue>();
alternative != nullptr) {
return *alternative;
Expand All @@ -2405,7 +2405,7 @@ absl::optional<UintValue> Value::AsUint() const {
return std::nullopt;
}

optional_ref<const UnknownValue> Value::AsUnknown() const& {
absl::optional_ref<const UnknownValue> Value::AsUnknown() const& {
if (const auto* alternative = variant_.As<UnknownValue>();
alternative != nullptr) {
return *alternative;
Expand Down
Loading
Loading