diff options
author | Dmitri Gribenko <dmitrig@google.com> | 2023-12-11 09:07:07 -0800 |
---|---|---|
committer | Copybara-Service <copybara-worker@google.com> | 2023-12-11 09:07:59 -0800 |
commit | 55621d1af55be7bf9a2c8e5dcef4368d9a6d4e51 (patch) | |
tree | 4c0e74b9a45b8875e35ee543089315a0d9989df1 | |
parent | fad946221cec37175e762c399760f54b9de9a9fa (diff) |
Add nullability annotations
PiperOrigin-RevId: 589842893
Change-Id: I9657761d1f71c665582406f278c6605f6d382f6d
45 files changed, 635 insertions, 442 deletions
diff --git a/absl/algorithm/BUILD.bazel b/absl/algorithm/BUILD.bazel index a339dc13..ddf9e11f 100644 --- a/absl/algorithm/BUILD.bazel +++ b/absl/algorithm/BUILD.bazel @@ -66,6 +66,7 @@ cc_library( deps = [ ":algorithm", "//absl/base:core_headers", + "//absl/base:nullability", "//absl/meta:type_traits", ], ) diff --git a/absl/algorithm/CMakeLists.txt b/absl/algorithm/CMakeLists.txt index 181b49ca..5577164d 100644 --- a/absl/algorithm/CMakeLists.txt +++ b/absl/algorithm/CMakeLists.txt @@ -50,6 +50,7 @@ absl_cc_library( absl::algorithm absl::core_headers absl::meta + absl::nullability PUBLIC ) diff --git a/absl/algorithm/container.h b/absl/algorithm/container.h index b6684c08..934dd179 100644 --- a/absl/algorithm/container.h +++ b/absl/algorithm/container.h @@ -52,6 +52,7 @@ #include "absl/algorithm/algorithm.h" #include "absl/base/macros.h" +#include "absl/base/nullability.h" #include "absl/meta/type_traits.h" namespace absl { diff --git a/absl/base/BUILD.bazel b/absl/base/BUILD.bazel index 60d05a83..06bd4950 100644 --- a/absl/base/BUILD.bazel +++ b/absl/base/BUILD.bazel @@ -287,6 +287,7 @@ cc_library( ":cycleclock_internal", ":dynamic_annotations", ":log_severity", + ":nullability", ":raw_logging_internal", ":spinlock_wait", "//absl/meta:type_traits", @@ -549,6 +550,7 @@ cc_library( ":base", ":config", ":core_headers", + ":nullability", ], ) diff --git a/absl/base/CMakeLists.txt b/absl/base/CMakeLists.txt index 9ca5cf8b..4cfc2285 100644 --- a/absl/base/CMakeLists.txt +++ b/absl/base/CMakeLists.txt @@ -247,6 +247,7 @@ absl_cc_library( absl::core_headers absl::dynamic_annotations absl::log_severity + absl::nullability absl::raw_logging_internal absl::spinlock_wait absl::type_traits @@ -475,6 +476,7 @@ absl_cc_library( absl::base absl::config absl::core_headers + absl::nullability PUBLIC ) diff --git a/absl/base/call_once.h b/absl/base/call_once.h index 08436bac..7b0e69cc 100644 --- a/absl/base/call_once.h +++ b/absl/base/call_once.h @@ -37,6 +37,7 @@ #include "absl/base/internal/scheduling_mode.h" #include "absl/base/internal/spinlock_wait.h" #include "absl/base/macros.h" +#include "absl/base/nullability.h" #include "absl/base/optimization.h" #include "absl/base/port.h" @@ -46,7 +47,8 @@ ABSL_NAMESPACE_BEGIN class once_flag; namespace base_internal { -std::atomic<uint32_t>* ControlWord(absl::once_flag* flag); +absl::Nonnull<std::atomic<uint32_t>*> ControlWord( + absl::Nonnull<absl::once_flag*> flag); } // namespace base_internal // call_once() @@ -89,7 +91,8 @@ class once_flag { once_flag& operator=(const once_flag&) = delete; private: - friend std::atomic<uint32_t>* base_internal::ControlWord(once_flag* flag); + friend absl::Nonnull<std::atomic<uint32_t>*> base_internal::ControlWord( + absl::Nonnull<once_flag*> flag); std::atomic<uint32_t> control_; }; @@ -103,7 +106,8 @@ namespace base_internal { // Like call_once, but uses KERNEL_ONLY scheduling. Intended to be used to // initialize entities used by the scheduler implementation. template <typename Callable, typename... Args> -void LowLevelCallOnce(absl::once_flag* flag, Callable&& fn, Args&&... args); +void LowLevelCallOnce(absl::Nonnull<absl::once_flag*> flag, Callable&& fn, + Args&&... args); // Disables scheduling while on stack when scheduling mode is non-cooperative. // No effect for cooperative scheduling modes. @@ -143,10 +147,10 @@ enum { }; template <typename Callable, typename... Args> -ABSL_ATTRIBUTE_NOINLINE -void CallOnceImpl(std::atomic<uint32_t>* control, - base_internal::SchedulingMode scheduling_mode, Callable&& fn, - Args&&... args) { +ABSL_ATTRIBUTE_NOINLINE void CallOnceImpl( + absl::Nonnull<std::atomic<uint32_t>*> control, + base_internal::SchedulingMode scheduling_mode, Callable&& fn, + Args&&... args) { #ifndef NDEBUG { uint32_t old_control = control->load(std::memory_order_relaxed); @@ -185,12 +189,14 @@ void CallOnceImpl(std::atomic<uint32_t>* control, } // else *control is already kOnceDone } -inline std::atomic<uint32_t>* ControlWord(once_flag* flag) { +inline absl::Nonnull<std::atomic<uint32_t>*> ControlWord( + absl::Nonnull<once_flag*> flag) { return &flag->control_; } template <typename Callable, typename... Args> -void LowLevelCallOnce(absl::once_flag* flag, Callable&& fn, Args&&... args) { +void LowLevelCallOnce(absl::Nonnull<absl::once_flag*> flag, Callable&& fn, + Args&&... args) { std::atomic<uint32_t>* once = base_internal::ControlWord(flag); uint32_t s = once->load(std::memory_order_acquire); if (ABSL_PREDICT_FALSE(s != base_internal::kOnceDone)) { diff --git a/absl/base/internal/endian.h b/absl/base/internal/endian.h index 50747d75..943f3d97 100644 --- a/absl/base/internal/endian.h +++ b/absl/base/internal/endian.h @@ -22,6 +22,7 @@ #include "absl/base/casts.h" #include "absl/base/config.h" #include "absl/base/internal/unaligned_access.h" +#include "absl/base/nullability.h" #include "absl/base/port.h" namespace absl { @@ -160,27 +161,27 @@ inline int64_t ToHost(int64_t x) { } // Functions to do unaligned loads and stores in little-endian order. -inline uint16_t Load16(const void *p) { +inline uint16_t Load16(absl::Nonnull<const void *> p) { return ToHost16(ABSL_INTERNAL_UNALIGNED_LOAD16(p)); } -inline void Store16(void *p, uint16_t v) { +inline void Store16(absl::Nonnull<void *> p, uint16_t v) { ABSL_INTERNAL_UNALIGNED_STORE16(p, FromHost16(v)); } -inline uint32_t Load32(const void *p) { +inline uint32_t Load32(absl::Nonnull<const void *> p) { return ToHost32(ABSL_INTERNAL_UNALIGNED_LOAD32(p)); } -inline void Store32(void *p, uint32_t v) { +inline void Store32(absl::Nonnull<void *> p, uint32_t v) { ABSL_INTERNAL_UNALIGNED_STORE32(p, FromHost32(v)); } -inline uint64_t Load64(const void *p) { +inline uint64_t Load64(absl::Nonnull<const void *> p) { return ToHost64(ABSL_INTERNAL_UNALIGNED_LOAD64(p)); } -inline void Store64(void *p, uint64_t v) { +inline void Store64(absl::Nonnull<void *> p, uint64_t v) { ABSL_INTERNAL_UNALIGNED_STORE64(p, FromHost64(v)); } @@ -250,27 +251,27 @@ inline int64_t ToHost(int64_t x) { } // Functions to do unaligned loads and stores in big-endian order. -inline uint16_t Load16(const void *p) { +inline uint16_t Load16(absl::Nonnull<const void *> p) { return ToHost16(ABSL_INTERNAL_UNALIGNED_LOAD16(p)); } -inline void Store16(void *p, uint16_t v) { +inline void Store16(absl::Nonnull<void *> p, uint16_t v) { ABSL_INTERNAL_UNALIGNED_STORE16(p, FromHost16(v)); } -inline uint32_t Load32(const void *p) { +inline uint32_t Load32(absl::Nonnull<const void *> p) { return ToHost32(ABSL_INTERNAL_UNALIGNED_LOAD32(p)); } -inline void Store32(void *p, uint32_t v) { +inline void Store32(absl::Nonnull<void *>p, uint32_t v) { ABSL_INTERNAL_UNALIGNED_STORE32(p, FromHost32(v)); } -inline uint64_t Load64(const void *p) { +inline uint64_t Load64(absl::Nonnull<const void *> p) { return ToHost64(ABSL_INTERNAL_UNALIGNED_LOAD64(p)); } -inline void Store64(void *p, uint64_t v) { +inline void Store64(absl::Nonnull<void *> p, uint64_t v) { ABSL_INTERNAL_UNALIGNED_STORE64(p, FromHost64(v)); } diff --git a/absl/base/internal/unaligned_access.h b/absl/base/internal/unaligned_access.h index 093dd9b4..4fea4574 100644 --- a/absl/base/internal/unaligned_access.h +++ b/absl/base/internal/unaligned_access.h @@ -23,6 +23,7 @@ #include "absl/base/attributes.h" #include "absl/base/config.h" +#include "absl/base/nullability.h" // unaligned APIs @@ -35,29 +36,35 @@ namespace absl { ABSL_NAMESPACE_BEGIN namespace base_internal { -inline uint16_t UnalignedLoad16(const void *p) { +inline uint16_t UnalignedLoad16(absl::Nonnull<const void *> p) { uint16_t t; memcpy(&t, p, sizeof t); return t; } -inline uint32_t UnalignedLoad32(const void *p) { +inline uint32_t UnalignedLoad32(absl::Nonnull<const void *> p) { uint32_t t; memcpy(&t, p, sizeof t); return t; } -inline uint64_t UnalignedLoad64(const void *p) { +inline uint64_t UnalignedLoad64(absl::Nonnull<const void *> p) { uint64_t t; memcpy(&t, p, sizeof t); return t; } -inline void UnalignedStore16(void *p, uint16_t v) { memcpy(p, &v, sizeof v); } +inline void UnalignedStore16(absl::Nonnull<void *> p, uint16_t v) { + memcpy(p, &v, sizeof v); +} -inline void UnalignedStore32(void *p, uint32_t v) { memcpy(p, &v, sizeof v); } +inline void UnalignedStore32(absl::Nonnull<void *> p, uint32_t v) { + memcpy(p, &v, sizeof v); +} -inline void UnalignedStore64(void *p, uint64_t v) { memcpy(p, &v, sizeof v); } +inline void UnalignedStore64(absl::Nonnull<void *> p, uint64_t v) { + memcpy(p, &v, sizeof v); +} } // namespace base_internal ABSL_NAMESPACE_END diff --git a/absl/status/BUILD.bazel b/absl/status/BUILD.bazel index 3cf0a5e1..a5fad4d4 100644 --- a/absl/status/BUILD.bazel +++ b/absl/status/BUILD.bazel @@ -54,6 +54,7 @@ cc_library( "//absl/base:config", "//absl/base:core_headers", "//absl/base:no_destructor", + "//absl/base:nullability", "//absl/base:raw_logging_internal", "//absl/base:strerror", "//absl/container:inlined_vector", @@ -100,6 +101,7 @@ cc_library( "//absl/base", "//absl/base:config", "//absl/base:core_headers", + "//absl/base:nullability", "//absl/base:raw_logging_internal", "//absl/meta:type_traits", "//absl/strings", diff --git a/absl/status/CMakeLists.txt b/absl/status/CMakeLists.txt index da789901..d9d16830 100644 --- a/absl/status/CMakeLists.txt +++ b/absl/status/CMakeLists.txt @@ -37,6 +37,7 @@ absl_cc_library( absl::inlined_vector absl::memory absl::no_destructor + absl::nullability absl::optional absl::raw_logging_internal absl::span @@ -76,6 +77,7 @@ absl_cc_library( absl::base absl::config absl::core_headers + absl::nullability absl::raw_logging_internal absl::status absl::strings diff --git a/absl/status/internal/status_internal.cc b/absl/status/internal/status_internal.cc index 2307579b..a9156754 100644 --- a/absl/status/internal/status_internal.cc +++ b/absl/status/internal/status_internal.cc @@ -27,6 +27,7 @@ #include "absl/base/attributes.h" #include "absl/base/config.h" #include "absl/base/macros.h" +#include "absl/base/nullability.h" #include "absl/debugging/stacktrace.h" #include "absl/debugging/symbolize.h" #include "absl/memory/memory.h" @@ -187,7 +188,7 @@ bool StatusRep::operator==(const StatusRep& other) const { return true; } -StatusRep* StatusRep::CloneAndUnref() const { +absl::Nonnull<StatusRep*> StatusRep::CloneAndUnref() const { // Optimization: no need to create a clone if we already have a refcount of 1. if (ref_.load(std::memory_order_acquire) == 1) { // All StatusRep instances are heap allocated and mutable, therefore this @@ -233,8 +234,9 @@ absl::StatusCode MapToLocalCode(int value) { } } -std::string* MakeCheckFailString(const absl::Status* status, - const char* prefix) { +absl::Nonnull<std::string*> MakeCheckFailString( + absl::Nonnull<const absl::Status*> status, + absl::Nonnull<const char*> prefix) { return new std::string( absl::StrCat(prefix, " (", status->ToString(StatusToStringMode::kWithEverything), ")")); diff --git a/absl/status/internal/status_internal.h b/absl/status/internal/status_internal.h index c84e626f..c9f43832 100644 --- a/absl/status/internal/status_internal.h +++ b/absl/status/internal/status_internal.h @@ -22,6 +22,7 @@ #include "absl/base/attributes.h" #include "absl/base/config.h" +#include "absl/base/nullability.h" #include "absl/container/inlined_vector.h" #include "absl/strings/cord.h" #include "absl/strings/string_view.h" @@ -99,7 +100,7 @@ class StatusRep { // Returns an equivalent heap allocated StatusRep with refcount 1. // // `this` is not safe to be used after calling as it may have been deleted. - StatusRep* CloneAndUnref() const; + absl::Nonnull<StatusRep*> CloneAndUnref() const; private: mutable std::atomic<int32_t> ref_; @@ -119,8 +120,9 @@ absl::StatusCode MapToLocalCode(int value); // // This is an internal implementation detail for Abseil logging. ABSL_ATTRIBUTE_PURE_FUNCTION -std::string* MakeCheckFailString(const absl::Status* status, - const char* prefix); +absl::Nonnull<std::string*> MakeCheckFailString( + absl::Nonnull<const absl::Status*> status, + absl::Nonnull<const char*> prefix); } // namespace status_internal diff --git a/absl/status/internal/statusor_internal.h b/absl/status/internal/statusor_internal.h index 49cead7a..25c11474 100644 --- a/absl/status/internal/statusor_internal.h +++ b/absl/status/internal/statusor_internal.h @@ -18,6 +18,7 @@ #include <utility> #include "absl/base/attributes.h" +#include "absl/base/nullability.h" #include "absl/meta/type_traits.h" #include "absl/status/status.h" #include "absl/utility/utility.h" @@ -123,7 +124,7 @@ using IsForwardingAssignmentValid = absl::disjunction< class Helper { public: // Move type-agnostic error handling to the .cc. - static void HandleInvalidStatusCtorArg(Status*); + static void HandleInvalidStatusCtorArg(absl::Nonnull<Status*>); ABSL_ATTRIBUTE_NORETURN static void Crash(const absl::Status& status); }; @@ -131,7 +132,8 @@ class Helper { // the constructor. // This abstraction is here mostly for the gcc performance fix. template <typename T, typename... Args> -ABSL_ATTRIBUTE_NONNULL(1) void PlacementNew(void* p, Args&&... args) { +ABSL_ATTRIBUTE_NONNULL(1) +void PlacementNew(absl::Nonnull<void*> p, Args&&... args) { new (p) T(std::forward<Args>(args)...); } diff --git a/absl/status/status.cc b/absl/status/status.cc index 7c778ac0..4dd5ae06 100644 --- a/absl/status/status.cc +++ b/absl/status/status.cc @@ -29,6 +29,7 @@ #include "absl/base/internal/strerror.h" #include "absl/base/macros.h" #include "absl/base/no_destructor.h" +#include "absl/base/nullability.h" #include "absl/debugging/stacktrace.h" #include "absl/debugging/symbolize.h" #include "absl/status/internal/status_internal.h" @@ -90,7 +91,7 @@ std::ostream& operator<<(std::ostream& os, StatusCode code) { return os << StatusCodeToString(code); } -const std::string* Status::EmptyString() { +absl::Nonnull<const std::string*> Status::EmptyString() { static const absl::NoDestructor<std::string> kEmpty; return kEmpty.get(); } @@ -99,7 +100,7 @@ const std::string* Status::EmptyString() { constexpr const char Status::kMovedFromString[]; #endif -const std::string* Status::MovedFromString() { +absl::Nonnull<const std::string*> Status::MovedFromString() { static const absl::NoDestructor<std::string> kMovedFrom(kMovedFromString); return kMovedFrom.get(); } @@ -111,7 +112,8 @@ Status::Status(absl::StatusCode code, absl::string_view msg) } } -status_internal::StatusRep* Status::PrepareToModify(uintptr_t rep) { +absl::Nonnull<status_internal::StatusRep*> Status::PrepareToModify( + uintptr_t rep) { if (IsInlined(rep)) { return new status_internal::StatusRep(InlinedRepToCode(rep), absl::string_view(), nullptr); @@ -412,7 +414,7 @@ Status ErrnoToStatus(int error_number, absl::string_view message) { MessageForErrnoToStatus(error_number, message)); } -const char* StatusMessageAsCStr(const Status& status) { +absl::Nonnull<const char*> StatusMessageAsCStr(const Status& status) { // As an internal implementation detail, we guarantee that if status.message() // is non-empty, then the resulting string_view is null terminated. auto sv_message = status.message(); diff --git a/absl/status/status.h b/absl/status/status.h index d4f74140..9ce16db9 100644 --- a/absl/status/status.h +++ b/absl/status/status.h @@ -60,6 +60,7 @@ #include "absl/base/attributes.h" #include "absl/base/config.h" #include "absl/base/macros.h" +#include "absl/base/nullability.h" #include "absl/base/optimization.h" #include "absl/functional/function_ref.h" #include "absl/status/internal/status_internal.h" @@ -622,14 +623,15 @@ class ABSL_ATTRIBUTE_TRIVIAL_ABI Status final { // REQUIRES: !ok() // Ensures rep is not inlined or shared with any other Status. - static status_internal::StatusRep* PrepareToModify(uintptr_t rep); + static absl::Nonnull<status_internal::StatusRep*> PrepareToModify( + uintptr_t rep); // MSVC 14.0 limitation requires the const. static constexpr const char kMovedFromString[] = "Status accessed after move."; - static const std::string* EmptyString(); - static const std::string* MovedFromString(); + static absl::Nonnull<const std::string*> EmptyString(); + static absl::Nonnull<const std::string*> MovedFromString(); // Returns whether rep contains an inlined representation. // See rep_ for details. @@ -648,7 +650,8 @@ class ABSL_ATTRIBUTE_TRIVIAL_ABI Status final { // Converts between StatusRep* and the external uintptr_t representation used // by rep_. See rep_ for details. static uintptr_t PointerToRep(status_internal::StatusRep* r); - static const status_internal::StatusRep* RepToPointer(uintptr_t r); + static absl::Nonnull<const status_internal::StatusRep*> RepToPointer( + uintptr_t r); static std::string ToStringSlow(uintptr_t rep, StatusToStringMode mode); @@ -899,12 +902,14 @@ constexpr uintptr_t Status::MovedFromRep() { return CodeToInlinedRep(absl::StatusCode::kInternal) | 2; } -inline const status_internal::StatusRep* Status::RepToPointer(uintptr_t rep) { +inline absl::Nonnull<const status_internal::StatusRep*> Status::RepToPointer( + uintptr_t rep) { assert(!IsInlined(rep)); return reinterpret_cast<const status_internal::StatusRep*>(rep); } -inline uintptr_t Status::PointerToRep(status_internal::StatusRep* rep) { +inline uintptr_t Status::PointerToRep( + absl::Nonnull<status_internal::StatusRep*> rep) { return reinterpret_cast<uintptr_t>(rep); } @@ -929,7 +934,7 @@ inline Status CancelledError() { return Status(absl::StatusCode::kCancelled); } // If the status's message is empty, the empty string is returned. // // StatusMessageAsCStr exists for C support. Use `status.message()` in C++. -const char* StatusMessageAsCStr( +absl::Nonnull<const char*> StatusMessageAsCStr( const Status& status ABSL_ATTRIBUTE_LIFETIME_BOUND); ABSL_NAMESPACE_END diff --git a/absl/status/status_payload_printer.h b/absl/status/status_payload_printer.h index 5e0937f6..f22255e1 100644 --- a/absl/status/status_payload_printer.h +++ b/absl/status/status_payload_printer.h @@ -16,6 +16,7 @@ #include <string> +#include "absl/base/nullability.h" #include "absl/strings/cord.h" #include "absl/strings/string_view.h" #include "absl/types/optional.h" @@ -34,8 +35,8 @@ namespace status_internal { // NOTE: This is an internal API and the design is subject to change in the // future in a non-backward-compatible way. Since it's only meant for debugging // purpose, you should not rely on it in any critical logic. -using StatusPayloadPrinter = absl::optional<std::string> (*)(absl::string_view, - const absl::Cord&); +using StatusPayloadPrinter = absl::Nullable<absl::optional<std::string> (*)( + absl::string_view, const absl::Cord&)>; // Sets the global payload printer. Only one printer should be set per process. // If multiple printers are set, it's undefined which one will be used. diff --git a/absl/status/statusor.cc b/absl/status/statusor.cc index bfad75ef..7e6b334c 100644 --- a/absl/status/statusor.cc +++ b/absl/status/statusor.cc @@ -19,6 +19,7 @@ #include "absl/base/call_once.h" #include "absl/base/config.h" #include "absl/base/internal/raw_logging.h" +#include "absl/base/nullability.h" #include "absl/status/internal/statusor_internal.h" #include "absl/status/status.h" #include "absl/strings/str_cat.h" @@ -54,7 +55,7 @@ BadStatusOrAccess& BadStatusOrAccess::operator=(BadStatusOrAccess&& other) { BadStatusOrAccess::BadStatusOrAccess(BadStatusOrAccess&& other) : status_(std::move(other.status_)) {} -const char* BadStatusOrAccess::what() const noexcept { +absl::Nonnull<const char*> BadStatusOrAccess::what() const noexcept { InitWhat(); return what_.c_str(); } @@ -69,7 +70,7 @@ void BadStatusOrAccess::InitWhat() const { namespace internal_statusor { -void Helper::HandleInvalidStatusCtorArg(absl::Status* status) { +void Helper::HandleInvalidStatusCtorArg(absl::Nonnull<absl::Status*> status) { const char* kMessage = "An OK status is not a valid constructor argument to StatusOr<T>"; #ifdef NDEBUG diff --git a/absl/status/statusor.h b/absl/status/statusor.h index 54c7ce02..33a2cf31 100644 --- a/absl/status/statusor.h +++ b/absl/status/statusor.h @@ -44,6 +44,7 @@ #include <utility> #include "absl/base/attributes.h" +#include "absl/base/nullability.h" #include "absl/base/call_once.h" #include "absl/meta/type_traits.h" #include "absl/status/internal/statusor_internal.h" @@ -88,7 +89,7 @@ class BadStatusOrAccess : public std::exception { // // The pointer of this string is guaranteed to be valid until any non-const // function is invoked on the exception object. - const char* what() const noexcept override; + absl::Nonnull<const char*> what() const noexcept override; // BadStatusOrAccess::status() // @@ -750,13 +751,13 @@ T&& StatusOr<T>::operator*() && { } template <typename T> -const T* StatusOr<T>::operator->() const { +absl::Nonnull<const T*> StatusOr<T>::operator->() const { this->EnsureOk(); return &this->data_; } template <typename T> -T* StatusOr<T>::operator->() { +absl::Nonnull<T*> StatusOr<T>::operator->() { this->EnsureOk(); return &this->data_; } diff --git a/absl/strings/BUILD.bazel b/absl/strings/BUILD.bazel index d8883bf2..3a244b5b 100644 --- a/absl/strings/BUILD.bazel +++ b/absl/strings/BUILD.bazel @@ -41,6 +41,7 @@ cc_library( "//absl/base", "//absl/base:config", "//absl/base:core_headers", + "//absl/base:nullability", "//absl/base:throw_delegate", ], ) @@ -103,6 +104,7 @@ cc_library( "//absl/base:config", "//absl/base:core_headers", "//absl/base:endian", + "//absl/base:nullability", "//absl/base:raw_logging_internal", "//absl/base:throw_delegate", "//absl/memory", @@ -588,6 +590,7 @@ cc_library( "//absl/base:config", "//absl/base:core_headers", "//absl/base:endian", + "//absl/base:nullability", "//absl/base:raw_logging_internal", "//absl/container:inlined_vector", "//absl/crc:crc32c", @@ -869,6 +872,7 @@ cc_library( ":strings", "//absl/base:config", "//absl/base:core_headers", + "//absl/base:nullability", "@com_google_googletest//:gtest", ], ) @@ -1250,6 +1254,7 @@ cc_library( ":string_view", "//absl/base:config", "//absl/base:core_headers", + "//absl/base:nullability", "//absl/types:span", ], ) diff --git a/absl/strings/CMakeLists.txt b/absl/strings/CMakeLists.txt index 6ec9e0eb..d4116a8f 100644 --- a/absl/strings/CMakeLists.txt +++ b/absl/strings/CMakeLists.txt @@ -27,6 +27,7 @@ absl_cc_library( absl::base absl::config absl::core_headers + absl::nullability absl::throw_delegate PUBLIC ) @@ -84,6 +85,7 @@ absl_cc_library( absl::endian absl::int128 absl::memory + absl::nullability absl::raw_logging_internal absl::throw_delegate absl::type_traits @@ -472,6 +474,7 @@ absl_cc_library( DEPS absl::config absl::core_headers + absl::nullability absl::span absl::str_format_internal absl::string_view @@ -986,6 +989,7 @@ absl_cc_library( absl::endian absl::function_ref absl::inlined_vector + absl::nullability absl::optional absl::raw_logging_internal absl::span @@ -1043,6 +1047,7 @@ absl_cc_library( absl::cordz_statistics absl::cordz_update_tracker absl::core_headers + absl::nullability absl::strings TESTONLY ) diff --git a/absl/strings/ascii.cc b/absl/strings/ascii.cc index 1e6566e9..df905e05 100644 --- a/absl/strings/ascii.cc +++ b/absl/strings/ascii.cc @@ -19,6 +19,7 @@ #include <string> #include "absl/base/config.h" +#include "absl/base/nullability.h" namespace absl { ABSL_NAMESPACE_BEGIN @@ -174,7 +175,8 @@ constexpr bool AsciiInAZRange(unsigned char c) { } template <bool ToUpper> -constexpr void AsciiStrCaseFold(char* p, char* end) { +constexpr void AsciiStrCaseFold(absl::Nonnull<char*> p, + absl::Nonnull<char*> end) { // The upper- and lowercase versions of ASCII characters differ by only 1 bit. // When we need to flip the case, we can xor with this bit to achieve the // desired result. Note that the choice of 'a' and 'A' here is arbitrary. We @@ -215,17 +217,17 @@ static_assert(ValidateAsciiCasefold() == 0, "error in case conversion"); } // namespace ascii_internal -void AsciiStrToLower(std::string* s) { +void AsciiStrToLower(absl::Nonnull<std::string*> s) { char* p = &(*s)[0]; // Guaranteed to be valid for empty strings return ascii_internal::AsciiStrCaseFold<false>(p, p + s->size()); } -void AsciiStrToUpper(std::string* s) { +void AsciiStrToUpper(absl::Nonnull<std::string*> s) { char* p = &(*s)[0]; // Guaranteed to be valid for empty strings return ascii_internal::AsciiStrCaseFold<true>(p, p + s->size()); } -void RemoveExtraAsciiWhitespace(std::string* str) { +void RemoveExtraAsciiWhitespace(absl::Nonnull<std::string*> str) { auto stripped = StripAsciiWhitespace(*str); if (stripped.empty()) { diff --git a/absl/strings/ascii.h b/absl/strings/ascii.h index ba6679bd..c238f4de 100644 --- a/absl/strings/ascii.h +++ b/absl/strings/ascii.h @@ -58,6 +58,7 @@ #include "absl/base/attributes.h" #include "absl/base/config.h" +#include "absl/base/nullability.h" #include "absl/strings/string_view.h" namespace absl { @@ -166,7 +167,7 @@ inline char ascii_tolower(unsigned char c) { } // Converts the characters in `s` to lowercase, changing the contents of `s`. -void AsciiStrToLower(std::string* s); +void AsciiStrToLower(absl::Nonnull<std::string*> s); // Creates a lowercase string from a given absl::string_view. ABSL_MUST_USE_RESULT inline std::string AsciiStrToLower(absl::string_view s) { @@ -184,7 +185,7 @@ inline char ascii_toupper(unsigned char c) { } // Converts the characters in `s` to uppercase, changing the contents of `s`. -void AsciiStrToUpper(std::string* s); +void AsciiStrToUpper(absl::Nonnull<std::string*> s); // Creates an uppercase string from a given absl::string_view. ABSL_MUST_USE_RESULT inline std::string AsciiStrToUpper(absl::string_view s) { @@ -202,7 +203,7 @@ ABSL_MUST_USE_RESULT inline absl::string_view StripLeadingAsciiWhitespace( } // Strips in place whitespace from the beginning of the given string. -inline void StripLeadingAsciiWhitespace(std::string* str) { +inline void StripLeadingAsciiWhitespace(absl::Nonnull<std::string*> str) { auto it = std::find_if_not(str->begin(), str->end(), absl::ascii_isspace); str->erase(str->begin(), it); } @@ -216,7 +217,7 @@ ABSL_MUST_USE_RESULT inline absl::string_view StripTrailingAsciiWhitespace( } // Strips in place whitespace from the end of the given string -inline void StripTrailingAsciiWhitespace(std::string* str) { +inline void StripTrailingAsciiWhitespace(absl::Nonnull<std::string*> str) { auto it = std::find_if_not(str->rbegin(), str->rend(), absl::ascii_isspace); str->erase(static_cast<size_t>(str->rend() - it)); } @@ -229,13 +230,13 @@ ABSL_MUST_USE_RESULT inline absl::string_view StripAsciiWhitespace( } // Strips in place whitespace from both ends of the given string -inline void StripAsciiWhitespace(std::string* str) { +inline void StripAsciiWhitespace(absl::Nonnull<std::string*> str) { StripTrailingAsciiWhitespace(str); StripLeadingAsciiWhitespace(str); } // Removes leading, trailing, and consecutive internal whitespace. -void RemoveExtraAsciiWhitespace(std::string*); +void RemoveExtraAsciiWhitespace(absl::Nonnull<std::string*> str); ABSL_NAMESPACE_END } // namespace absl diff --git a/absl/strings/charconv.cc b/absl/strings/charconv.cc index 60b3715c..eda6d506 100644 --- a/absl/strings/charconv.cc +++ b/absl/strings/charconv.cc @@ -23,6 +23,7 @@ #include "absl/base/casts.h" #include "absl/base/config.h" +#include "absl/base/nullability.h" #include "absl/numeric/bits.h" #include "absl/numeric/int128.h" #include "absl/strings/internal/charconv_bigint.h" @@ -119,7 +120,7 @@ struct FloatTraits<double> { // Parsing a smaller N will produce something finite. static constexpr int kEiselLemireMaxExclusiveExp10 = 309; - static double MakeNan(const char* tagp) { + static double MakeNan(absl::Nullable<const char*> tagp) { #if ABSL_HAVE_BUILTIN(__builtin_nan) // Use __builtin_nan() if available since it has a fix for // https://bugs.llvm.org/show_bug.cgi?id=37778 @@ -192,7 +193,7 @@ struct FloatTraits<float> { static constexpr int kEiselLemireMinInclusiveExp10 = -46 - 18; static constexpr int kEiselLemireMaxExclusiveExp10 = 39; - static float MakeNan(const char* tagp) { + static float MakeNan(absl::Nullable<const char*> tagp) { #if ABSL_HAVE_BUILTIN(__builtin_nanf) // Use __builtin_nanf() if available since it has a fix for // https://bugs.llvm.org/show_bug.cgi?id=37778 @@ -344,7 +345,7 @@ int NormalizedShiftSize(int mantissa_width, int binary_exponent) { // `value` must be wider than the requested bit width. // // Returns the number of bits shifted. -int TruncateToBitWidth(int bit_width, uint128* value) { +int TruncateToBitWidth(int bit_width, absl::Nonnull<uint128*> value) { const int current_bit_width = BitWidth(*value); const int shift = current_bit_width - bit_width; *value >>= shift; @@ -356,7 +357,7 @@ int TruncateToBitWidth(int bit_width, uint128* value) { // the appropriate double, and returns true. template <typename FloatType> bool HandleEdgeCase(const strings_internal::ParsedFloat& input, bool negative, - FloatType* value) { + absl::Nonnull<FloatType*> value) { if (input.type == strings_internal::FloatType::kNan) { // A bug in both clang < 7 and gcc would cause the compiler to optimize // away the buffer we are building below. Declaring the buffer volatile @@ -405,7 +406,8 @@ bool HandleEdgeCase(const strings_internal::ParsedFloat& input, bool negative, // number is stored in *value. template <typename FloatType> void EncodeResult(const CalculatedFloat& calculated, bool negative, - absl::from_chars_result* result, FloatType* value) { + absl::Nonnull<absl::from_chars_result*> result, + absl::Nonnull<FloatType*> value) { if (calculated.exponent == kOverflow) { result->ec = std::errc::result_out_of_range; *value = negative ? -std::numeric_limits<FloatType>::max() @@ -451,7 +453,7 @@ void EncodeResult(const CalculatedFloat& calculated, bool negative, // Zero and negative values of `shift` are accepted, in which case the word is // shifted left, as necessary. uint64_t ShiftRightAndRound(uint128 value, int shift, bool input_exact, - bool* output_exact) { + absl::Nonnull<bool*> output_exact) { if (shift <= 0) { *output_exact = input_exact; return static_cast<uint64_t>(value << -shift); @@ -685,7 +687,8 @@ CalculatedFloat CalculateFromParsedDecimal( // this function returns false) is both fast and correct. template <typename FloatType> bool EiselLemire(const strings_internal::ParsedFloat& input, bool negative, - FloatType* value, std::errc* ec) { + absl::Nonnull<FloatType*> value, + absl::Nonnull<std::errc*> ec) { uint64_t man = input.mantissa; int exp10 = input.exponent; if (exp10 < FloatTraits<FloatType>::kEiselLemireMinInclusiveExp10) { @@ -858,7 +861,8 @@ bool EiselLemire(const strings_internal::ParsedFloat& input, bool negative, } template <typename FloatType> -from_chars_result FromCharsImpl(const char* first, const char* last, +from_chars_result FromCharsImpl(absl::Nonnull<const char*> first, + absl::Nonnull<const char*> last, FloatType& value, chars_format fmt_flags) { from_chars_result result; result.ptr = first; // overwritten on successful parse @@ -944,12 +948,14 @@ from_chars_result FromCharsImpl(const char* first, const char* last, } } // namespace -from_chars_result from_chars(const char* first, const char* last, double& value, +from_chars_result from_chars(absl::Nonnull<const char*> first, + absl::Nonnull<const char*> last, double& value, chars_format fmt) { return FromCharsImpl(first, last, value, fmt); } -from_chars_result from_chars(const char* first, const char* last, float& value, +from_chars_result from_chars(absl::Nonnull<const char*> first, + absl::Nonnull<const char*> last, float& value, chars_format fmt) { return FromCharsImpl(first, last, value, fmt); } diff --git a/absl/strings/charconv.h b/absl/strings/charconv.h index 111c7120..be250902 100644 --- a/absl/strings/charconv.h +++ b/absl/strings/charconv.h @@ -18,6 +18,7 @@ #include <system_error> // NOLINT(build/c++11) #include "absl/base/config.h" +#include "absl/base/nullability.h" namespace absl { ABSL_NAMESPACE_BEGIN @@ -44,7 +45,7 @@ enum class chars_format { // characters that were successfully parsed. If none was found, `ptr` is set // to the `first` argument to from_chars. struct from_chars_result { - const char* ptr; + absl::Nonnull<const char*> ptr; std::errc ec; }; @@ -76,11 +77,13 @@ struct from_chars_result { // format that strtod() accepts, except that a "0x" prefix is NOT matched. // (In particular, in `hex` mode, the input "0xff" results in the largest // matching pattern "0".) -absl::from_chars_result from_chars(const char* first, const char* last, +absl::from_chars_result from_chars(absl::Nonnull<const char*> first, + absl::Nonnull<const char*> last, double& value, // NOLINT chars_format fmt = chars_format::general); -absl::from_chars_result from_chars(const char* first, const char* last, +absl::from_chars_result from_chars(absl::Nonnull<const char*> first, + absl::Nonnull<const char*> last, float& value, // NOLINT chars_format fmt = chars_format::general); diff --git a/absl/strings/cord.cc b/absl/strings/cord.cc index 08a165e1..f67326fd 100644 --- a/absl/strings/cord.cc +++ b/absl/strings/cord.cc @@ -37,6 +37,7 @@ #include "absl/base/internal/raw_logging.h" #include "absl/base/macros.h" #include "absl/base/optimization.h" +#include "absl/base/nullability.h" #include "absl/container/inlined_vector.h" #include "absl/crc/crc32c.h" #include "absl/crc/internal/crc_cord_state.h" @@ -74,18 +75,21 @@ using ::absl::cord_internal::kMinFlatLength; using ::absl::cord_internal::kInlinedVectorSize; using ::absl::cord_internal::kMaxBytesToCopy; -static void DumpNode(CordRep* rep, bool include_data, std::ostream* os, - int indent = 0); -static bool VerifyNode(CordRep* root, CordRep* start_node); +static void DumpNode(absl::Nonnull<CordRep*> rep, bool include_data, + absl::Nonnull<std::ostream*> os, int indent = 0); +static bool VerifyNode(absl::Nonnull<CordRep*> root, + absl::Nonnull<CordRep*> start_node); -static inline CordRep* VerifyTree(CordRep* node) { +static inline absl::Nullable<CordRep*> VerifyTree( + absl::Nullable<CordRep*> node) { assert(node == nullptr || VerifyNode(node, node)); static_cast<void>(&VerifyNode); return node; } -static CordRepFlat* CreateFlat(const char* data, size_t length, - size_t alloc_hint) { +static absl::Nonnull<CordRepFlat*> CreateFlat(absl::Nonnull<const char*> data, + size_t length, + size_t alloc_hint) { CordRepFlat* flat = CordRepFlat::New(length + alloc_hint); flat->length = length; memcpy(flat->Data(), data, length); @@ -94,7 +98,8 @@ static CordRepFlat* CreateFlat(const char* data, size_t length, // Creates a new flat or Btree out of the specified array. // The returned node has a refcount of 1. -static CordRep* NewBtree(const char* data, size_t length, size_t alloc_hint) { +static absl::Nonnull<CordRep*> NewBtree(absl::Nonnull<const char*> data, + size_t length, size_t alloc_hint) { if (length <= kMaxFlatLength) { return CreateFlat(data, length, alloc_hint); } @@ -107,14 +112,16 @@ static CordRep* NewBtree(const char* data, size_t length, size_t alloc_hint) { // Create a new tree out of the specified array. // The returned node has a refcount of 1. -static CordRep* NewTree(const char* data, size_t length, size_t alloc_hint) { +static absl::Nullable<CordRep*> NewTree(absl::Nullable<const char*> data, + size_t length, size_t alloc_hint) { if (length == 0) return nullptr; return NewBtree(data, length, alloc_hint); } namespace cord_internal { -void InitializeCordRepExternal(absl::string_view data, CordRepExternal* rep) { +void InitializeCordRepExternal(absl::string_view data, + absl::Nonnull<CordRepExternal*> rep) { assert(!data.empty()); rep->length = data.size(); rep->tag = EXTERNAL; @@ -128,7 +135,7 @@ void InitializeCordRepExternal(absl::string_view data, CordRepExternal* rep) { // and not wasteful, we move the string into an external cord rep, preserving // the already allocated string contents. // Requires the provided string length to be larger than `kMaxInline`. -static CordRep* CordRepFromString(std::string&& src) { +static absl::Nonnull<CordRep*> CordRepFromString(std::string&& src) { assert(src.length() > cord_internal::kMaxInline); if ( // String is short: copy data to avoid external block overhead. @@ -160,12 +167,13 @@ static CordRep* CordRepFromString(std::string&& src) { constexpr unsigned char Cord::InlineRep::kMaxInline; #endif -inline void Cord::InlineRep::set_data(const char* data, size_t n) { +inline void Cord::InlineRep::set_data(absl::Nonnull<const char*> data, + size_t n) { static_assert(kMaxInline == 15, "set_data is hard-coded for a length of 15"); data_.set_inline_data(data, n); } -inline char* Cord::InlineRep::set_data(size_t n) { +inline absl::Nonnull<char*> Cord::InlineRep::set_data(size_t n) { assert(n <= kMaxInline); ResetToEmpty(); set_inline_size(n); @@ -189,13 +197,13 @@ inline void Cord::InlineRep::remove_prefix(size_t n) { // Returns `rep` converted into a CordRepBtree. // Directly returns `rep` if `rep` is already a CordRepBtree. -static CordRepBtree* ForceBtree(CordRep* rep) { +static absl::Nonnull<CordRepBtree*> ForceBtree(CordRep* rep) { return rep->IsBtree() ? rep->btree() : CordRepBtree::Create(cord_internal::RemoveCrcNode(rep)); } -void Cord::InlineRep::AppendTreeToInlined(CordRep* tree, +void Cord::InlineRep::AppendTreeToInlined(absl::Nonnull<CordRep*> tree, MethodIdentifier method) { assert(!is_tree()); if (!data_.is_empty()) { @@ -205,14 +213,16 @@ void Cord::InlineRep::AppendTreeToInlined(CordRep* tree, EmplaceTree(tree, method); } -void Cord::InlineRep::AppendTreeToTree(CordRep* tree, MethodIdentifier method) { +void Cord::InlineRep::AppendTreeToTree(absl::Nonnull<CordRep*> tree, + MethodIdentifier method) { assert(is_tree()); const CordzUpdateScope scope(data_.cordz_info(), method); tree = CordRepBtree::Append(ForceBtree(data_.as_tree()), tree); SetTree(tree, scope); } -void Cord::InlineRep::AppendTree(CordRep* tree, MethodIdentifier method) { +void Cord::InlineRep::AppendTree(absl::Nonnull<CordRep*> tree, + MethodIdentifier method) { assert(tree != nullptr); assert(tree->length != 0); assert(!tree->IsCrc()); @@ -223,7 +233,7 @@ void Cord::InlineRep::AppendTree(CordRep* tree, MethodIdentifier method) { } } -void Cord::InlineRep::PrependTreeToInlined(CordRep* tree, +void Cord::InlineRep::PrependTreeToInlined(absl::Nonnull<CordRep*> tree, MethodIdentifier method) { assert(!is_tree()); if (!data_.is_empty()) { @@ -233,7 +243,7 @@ void Cord::InlineRep::PrependTreeToInlined(CordRep* tree, EmplaceTree(tree, method); } -void Cord::InlineRep::PrependTreeToTree(CordRep* tree, +void Cord::InlineRep::PrependTreeToTree(absl::Nonnull<CordRep*> tree, MethodIdentifier method) { assert(is_tree()); const CordzUpdateScope scope(data_.cordz_info(), method); @@ -241,7 +251,8 @@ void Cord::InlineRep::PrependTreeToTree(CordRep* tree, SetTree(tree, scope); } -void Cord::InlineRep::PrependTree(CordRep* tree, MethodIdentifier method) { +void Cord::InlineRep::PrependTree(absl::Nonnull<CordRep*> tree, + MethodIdentifier method) { assert(tree != nullptr); assert(tree->length != 0); assert(!tree->IsCrc()); @@ -256,8 +267,9 @@ void Cord::InlineRep::PrependTree(CordRep* tree, MethodIdentifier method) { // suitable leaf is found, the function will update the length field for all // nodes to account for the size increase. The append region address will be // written to region and the actual size increase will be written to size. -static inline bool PrepareAppendRegion(CordRep* root, char** region, - size_t* size, size_t max_length) { +static inline bool PrepareAppendRegion( + absl::Nonnull<CordRep*> root, absl::Nonnull<absl::Nullable<char*>*> region, + absl::Nonnull<size_t*> size, size_t max_length) { if (root->IsBtree() && root->refcount.IsOne()) { Span<char> span = root->btree()->GetAppendBuffer(max_length); if (!span.empty()) { @@ -460,11 +472,11 @@ void Cord::InlineRep::AppendArray(absl::string_view src, CommitTree(root, rep, scope, method); } -inline CordRep* Cord::TakeRep() const& { +inline absl::Nonnull<CordRep*> Cord::TakeRep() const& { return CordRep::Ref(contents_.tree()); } -inline CordRep* Cord::TakeRep() && { +inline absl::Nonnull<CordRep*> Cord::TakeRep() && { CordRep* rep = contents_.tree(); contents_.clear(); return rep; @@ -522,7 +534,7 @@ inline void Cord::AppendImpl(C&& src) { contents_.AppendTree(rep, CordzUpdateTracker::kAppendCord); } -static CordRep::ExtractResult ExtractAppendBuffer(CordRep* rep, +static CordRep::ExtractResult ExtractAppendBuffer(absl::Nonnull<CordRep*> rep, size_t min_capacity) { switch (rep->tag) { case cord_internal::BTREE: @@ -769,8 +781,9 @@ int ClampResult(int memcmp_res) { return static_cast<int>(memcmp_res > 0) - static_cast<int>(memcmp_res < 0); } -int CompareChunks(absl::string_view* lhs, absl::string_view* rhs, - size_t* size_to_compare) { +int CompareChunks(absl::Nonnull<absl::string_view*> lhs, + absl::Nonnull<absl::string_view*> rhs, + absl::Nonnull<size_t*> size_to_compare) { size_t compared_size = std::min(lhs->size(), rhs->size()); assert(*size_to_compare >= compared_size); *size_to_compare -= compared_size; @@ -868,7 +881,8 @@ void Cord::SetExpectedChecksum(uint32_t crc) { SetCrcCordState(std::move(state)); } -const crc_internal::CrcCordState* Cord::MaybeGetCrcCordState() const { +absl::Nullable<const crc_internal::CrcCordState*> Cord::MaybeGetCrcCordState() + const { if (!contents_.is_tree() || !contents_.tree()->IsCrc()) { return nullptr; } @@ -885,7 +899,8 @@ absl::optional<uint32_t> Cord::ExpectedChecksum() const { inline int Cord::CompareSlowPath(absl::string_view rhs, size_t compared_size, size_t size_to_compare) const { - auto advance = [](Cord::ChunkIterator* it, absl::string_view* chunk) { + auto advance = [](absl::Nonnull<Cord::ChunkIterator*> it, + absl::Nonnull<absl::string_view*> chunk) { if (!chunk->empty()) return true; ++*it; if (it->bytes_remaining_ == 0) return false; @@ -915,7 +930,8 @@ inline int Cord::CompareSlowPath(absl::string_view rhs, size_t compared_size, inline int Cord::CompareSlowPath(const Cord& rhs, size_t compared_size, size_t size_to_compare) const { - auto advance = [](Cord::ChunkIterator* it, absl::string_view* chunk) { + auto advance = [](absl::Nonnull<Cord::ChunkIterator*> it, + absl::Nonnull<absl::string_view*> chunk) { if (!chunk->empty()) return true; ++*it; if (it->bytes_remaining_ == 0) return false; @@ -1037,7 +1053,7 @@ Cord::operator std::string() const { return s; } -void CopyCordToString(const Cord& src, std::string* dst) { +void CopyCordToString(const Cord& src, absl::Nonnull<std::string*> dst) { if (!src.contents_.is_tree()) { src.contents_.CopyTo(dst); } else { @@ -1046,7 +1062,7 @@ void CopyCordToString(const Cord& src, std::string* dst) { } } -void Cord::CopyToArraySlowPath(char* dst) const { +void Cord::CopyToArraySlowPath(absl::Nonnull<char*> dst) const { assert(contents_.is_tree()); absl::string_view fragment; if (GetFlatAux(contents_.tree(), &fragment)) { @@ -1372,7 +1388,8 @@ absl::string_view Cord::FlattenSlowPath() { return absl::string_view(new_buffer, total_size); } -/* static */ bool Cord::GetFlatAux(CordRep* rep, absl::string_view* fragment) { +/* static */ bool Cord::GetFlatAux(absl::Nonnull<CordRep*> rep, + absl::Nonnull<absl::string_view*> fragment) { assert(rep != nullptr); if (rep->length == 0) { *fragment = absl::string_view(); @@ -1406,7 +1423,7 @@ absl::string_view Cord::FlattenSlowPath() { } /* static */ void Cord::ForEachChunkAux( - absl::cord_internal::CordRep* rep, + absl::Nonnull<absl::cord_internal::CordRep*> rep, absl::FunctionRef<void(absl::string_view)> callback) { assert(rep != nullptr); if (rep->length == 0) return; @@ -1431,8 +1448,8 @@ absl::string_view Cord::FlattenSlowPath() { } } -static void DumpNode(CordRep* rep, bool include_data, std::ostream* os, - int indent) { +static void DumpNode(absl::Nonnull<CordRep*> rep, bool include_data, + absl::Nonnull<std::ostream*> os, int indent) { const int kIndentStep = 1; absl::InlinedVector<CordRep*, kInlinedVectorSize> stack; absl::InlinedVector<int, kInlinedVectorSize> indents; @@ -1482,15 +1499,17 @@ static void DumpNode(CordRep* rep, bool include_data, std::ostream* os, ABSL_INTERNAL_CHECK(indents.empty(), ""); } -static std::string ReportError(CordRep* root, CordRep* node) { +static std::string ReportError(absl::Nonnull<CordRep*> root, + absl::Nonnull<CordRep*> node) { std::ostringstream buf; buf << "Error at node " << node << " in:"; DumpNode(root, true, &buf); return buf.str(); } -static bool VerifyNode(CordRep* root, CordRep* start_node) { - absl::InlinedVector<CordRep*, 2> worklist; +static bool VerifyNode(absl::Nonnull<CordRep*> root, + absl::Nonnull<CordRep*> start_node) { + absl::InlinedVector<absl::Nonnull<CordRep*>, 2> worklist; worklist.push_back(start_node); do { CordRep* node = worklist.back(); diff --git a/absl/strings/cord.h b/absl/strings/cord.h index e4d5f7f7..b3e556b6 100644 --- a/absl/strings/cord.h +++ b/absl/strings/cord.h @@ -74,6 +74,7 @@ #include "absl/base/internal/endian.h" #include "absl/base/internal/per_thread_tls.h" #include "absl/base/macros.h" +#include "absl/base/nullability.h" #include "absl/base/port.h" #include "absl/container/inlined_vector.h" #include "absl/crc/internal/crc_cord_state.h" @@ -102,7 +103,7 @@ class Cord; class CordTestPeer; template <typename Releaser> Cord MakeCordFromExternal(absl::string_view, Releaser&&); -void CopyCordToString(const Cord& src, std::string* dst); +void CopyCordToString(const Cord& src, absl::Nonnull<std::string*> dst); // Cord memory accounting modes enum class CordMemoryAccounting { @@ -416,7 +417,8 @@ class Cord { // guarantee that pointers previously returned by `dst->data()` remain valid // even if `*dst` had enough capacity to hold `src`. If `*dst` is a new // object, prefer to simply use the conversion operator to `std::string`. - friend void CopyCordToString(const Cord& src, std::string* dst); + friend void CopyCordToString(const Cord& src, + absl::Nonnull<std::string*> dst); class CharIterator; @@ -453,7 +455,7 @@ class Cord { using iterator_category = std::input_iterator_tag; using value_type = absl::string_view; using difference_type = ptrdiff_t; - using pointer = const value_type*; + using pointer = absl::Nonnull<const value_type*>; using reference = value_type; ChunkIterator() = default; @@ -473,14 +475,14 @@ class Cord { using CordRepBtree = absl::cord_internal::CordRepBtree; using CordRepBtreeReader = absl::cord_internal::CordRepBtreeReader; - // Constructs a `begin()` iterator from `tree`. `tree` must not be null. - explicit ChunkIterator(cord_internal::CordRep* tree); + // Constructs a `begin()` iterator from `tree`. + explicit ChunkIterator(absl::Nonnull<cord_internal::CordRep*> tree); // Constructs a `begin()` iterator from `cord`. - explicit ChunkIterator(const Cord* cord); + explicit ChunkIterator(absl::Nonnull<const Cord*> cord); // Initializes this instance from a tree. Invoked by constructors. - void InitTree(cord_internal::CordRep* tree); + void InitTree(absl::Nonnull<cord_internal::CordRep*> tree); // Removes `n` bytes from `current_chunk_`. Expects `n` to be smaller than // `current_chunk_.size()`. @@ -498,7 +500,7 @@ class Cord { // The current leaf, or `nullptr` if the iterator points to short data. // If the current chunk is a substring node, current_leaf_ points to the // underlying flat or external node. - absl::cord_internal::CordRep* current_leaf_ = nullptr; + absl::Nullable<absl::cord_internal::CordRep*> current_leaf_ = nullptr; // The number of bytes left in the `Cord` over which we are iterating. size_t bytes_remaining_ = 0; @@ -555,13 +557,13 @@ class Cord { using iterator = ChunkIterator; using const_iterator = ChunkIterator; - explicit ChunkRange(const Cord* cord) : cord_(cord) {} + explicit ChunkRange(absl::Nonnull<const Cord*> cord) : cord_(cord) {} ChunkIterator begin() const; ChunkIterator end() const; private: - const Cord* cord_; + absl::Nonnull<const Cord*> cord_; }; // Cord::Chunks() @@ -614,7 +616,7 @@ class Cord { using iterator_category = std::input_iterator_tag; using value_type = char; using difference_type = ptrdiff_t; - using pointer = const char*; + using pointer = absl::Nonnull<const char*>; using reference = const char&; CharIterator() = default; @@ -629,7 +631,8 @@ class Cord { friend Cord; private: - explicit CharIterator(const Cord* cord) : chunk_iterator_(cord) {} + explicit CharIterator(absl::Nonnull<const Cord*> cord) + : chunk_iterator_(cord) {} ChunkIterator chunk_iterator_; }; @@ -640,14 +643,14 @@ class Cord { // advanced as a separate `Cord`. `n_bytes` must be less than or equal to the // number of bytes within the Cord; otherwise, behavior is undefined. It is // valid to pass `char_end()` and `0`. - static Cord AdvanceAndRead(CharIterator* it, size_t n_bytes); + static Cord AdvanceAndRead(absl::Nonnull<CharIterator*> it, size_t n_bytes); // Cord::Advance() // // Advances the `Cord::CharIterator` by `n_bytes`. `n_bytes` must be less than // or equal to the number of bytes remaining within the Cord; otherwise, // behavior is undefined. It is valid to pass `char_end()` and `0`. - static void Advance(CharIterator* it, size_t n_bytes); + static void Advance(absl::Nonnull<CharIterator*> it, size_t n_bytes); // Cord::ChunkRemaining() // @@ -696,13 +699,13 @@ class Cord { using iterator = CharIterator; using const_iterator = CharIterator; - explicit CharRange(const Cord* cord) : cord_(cord) {} + explicit CharRange(absl::Nonnull<const Cord*> cord) : cord_(cord) {} CharIterator begin() const; CharIterator end() const; private: - const Cord* cord_; + absl::Nonnull<const Cord*> cord_; }; // Cord::Chars() @@ -761,7 +764,8 @@ class Cord { CharIterator Find(const absl::Cord& needle) const; // Supports absl::Cord as a sink object for absl::Format(). - friend void AbslFormatFlush(absl::Cord* cord, absl::string_view part) { + friend void AbslFormatFlush(absl::Nonnull<absl::Cord*> cord, + absl::string_view part) { cord->Append(part); } @@ -831,7 +835,8 @@ class Cord { friend bool operator==(const Cord& lhs, const Cord& rhs); friend bool operator==(const Cord& lhs, absl::string_view rhs); - friend const CordzInfo* GetCordzInfoForTesting(const Cord& cord); + friend absl::Nullable<const CordzInfo*> GetCordzInfoForTesting( + const Cord& cord); // Calls the provided function once for each cord chunk, in order. Unlike // Chunks(), this API will not allocate memory. @@ -858,19 +863,22 @@ class Cord { InlineRep& operator=(const InlineRep& src); InlineRep& operator=(InlineRep&& src) noexcept; - explicit constexpr InlineRep(absl::string_view sv, CordRep* rep); + explicit constexpr InlineRep(absl::string_view sv, + absl::Nullable<CordRep*> rep); - void Swap(InlineRep* rhs); + void Swap(absl::Nonnull<InlineRep*> rhs); size_t size() const; - const char* data() const; // Returns nullptr if holding pointer - void set_data(const char* data, size_t n); // Discards pointer, if any - char* set_data(size_t n); // Write data to the result + // Returns nullptr if holding pointer + absl::Nullable<const char*> data() const; + // Discards pointer, if any + void set_data(absl::Nonnull<const char*> data, size_t n); + absl::Nonnull<char*> set_data(size_t n); // Write data to the result // Returns nullptr if holding bytes - absl::cord_internal::CordRep* tree() const; - absl::cord_internal::CordRep* as_tree() const; - const char* as_chars() const; + absl::Nullable<absl::cord_internal::CordRep*> tree() const; + absl::Nonnull<absl::cord_internal::CordRep*> as_tree() const; + absl::Nonnull<const char*> as_chars() const; // Returns non-null iff was holding a pointer - absl::cord_internal::CordRep* clear(); + absl::Nullable<absl::cord_internal::CordRep*> clear(); // Converts to pointer if necessary. void reduce_size(size_t n); // REQUIRES: holding data void remove_prefix(size_t n); // REQUIRES: holding data @@ -879,46 +887,52 @@ class Cord { // Creates a CordRepFlat instance from the current inlined data with `extra' // bytes of desired additional capacity. - CordRepFlat* MakeFlatWithExtraCapacity(size_t extra); + absl::Nonnull<CordRepFlat*> MakeFlatWithExtraCapacity(size_t extra); // Sets the tree value for this instance. `rep` must not be null. // Requires the current instance to hold a tree, and a lock to be held on // any CordzInfo referenced by this instance. The latter is enforced through // the CordzUpdateScope argument. If the current instance is sampled, then // the CordzInfo instance is updated to reference the new `rep` value. - void SetTree(CordRep* rep, const CordzUpdateScope& scope); + void SetTree(absl::Nonnull<CordRep*> rep, const CordzUpdateScope& scope); // Identical to SetTree(), except that `rep` is allowed to be null, in // which case the current instance is reset to an empty value. - void SetTreeOrEmpty(CordRep* rep, const CordzUpdateScope& scope); + void SetTreeOrEmpty(absl::Nullable<CordRep*> rep, + const CordzUpdateScope& scope); // Sets the tree value for this instance, and randomly samples this cord. // This function disregards existing contents in `data_`, and should be // called when a Cord is 'promoted' from an 'uninitialized' or 'inlined' // value to a non-inlined (tree / ring) value. - void EmplaceTree(CordRep* rep, MethodIdentifier method); + void EmplaceTree(absl::Nonnull<CordRep*> rep, MethodIdentifier method); // Identical to EmplaceTree, except that it copies the parent stack from // the provided `parent` data if the parent is sampled. - void EmplaceTree(CordRep* rep, const InlineData& parent, + void EmplaceTree(absl::Nonnull<CordRep*> rep, const InlineData& parent, MethodIdentifier method); // Commits the change of a newly created, or updated `rep` root value into // this cord. `old_rep` indicates the old (inlined or tree) value of the // cord, and determines if the commit invokes SetTree() or EmplaceTree(). - void CommitTree(const CordRep* old_rep, CordRep* rep, - const CordzUpdateScope& scope, MethodIdentifier method); - - void AppendTreeToInlined(CordRep* tree, MethodIdentifier method); - void AppendTreeToTree(CordRep* tree, MethodIdentifier method); - void AppendTree(CordRep* tree, MethodIdentifier method); - void PrependTreeToInlined(CordRep* tree, MethodIdentifier method); - void PrependTreeToTree(CordRep* tree, MethodIdentifier method); - void PrependTree(CordRep* tree, MethodIdentifier method); + void CommitTree(absl::Nullable<const CordRep*> old_rep, + absl::Nonnull<CordRep*> rep, const CordzUpdateScope& scope, + MethodIdentifier method); + + void AppendTreeToInlined(absl::Nonnull<CordRep*> tree, + MethodIdentifier method); + void AppendTreeToTree(absl::Nonnull<CordRep*> tree, + MethodIdentifier method); + void AppendTree(absl::Nonnull<CordRep*> tree, MethodIdentifier method); + void PrependTreeToInlined(absl::Nonnull<CordRep*> tree, + MethodIdentifier method); + void PrependTreeToTree(absl::Nonnull<CordRep*> tree, + MethodIdentifier method); + void PrependTree(absl::Nonnull<CordRep*> tree, MethodIdentifier method); bool IsSame(const InlineRep& other) const { return data_ == other.data_; } - void CopyTo(std::string* dst) const { + void CopyTo(absl::Nonnull<std::string*> dst) const { // memcpy is much faster when operating on a known size. On most supported // platforms, the small string optimization is large enough that resizing // to 15 bytes does not cause a memory allocation. @@ -930,7 +944,7 @@ class Cord { } // Copies the inline contents into `dst`. Assumes the cord is not empty. - void CopyToArray(char* dst) const; + void CopyToArray(absl::Nonnull<char*> dst) const; bool is_tree() const { return data_.is_tree(); } @@ -943,12 +957,12 @@ class Cord { } // Returns the profiled CordzInfo, or nullptr if not sampled. - absl::cord_internal::CordzInfo* cordz_info() const { + absl::Nullable<absl::cord_internal::CordzInfo*> cordz_info() const { return data_.cordz_info(); } - // Sets the profiled CordzInfo. `cordz_info` must not be null. - void set_cordz_info(cord_internal::CordzInfo* cordz_info) { + // Sets the profiled CordzInfo. + void set_cordz_info(absl::Nonnull<cord_internal::CordzInfo*> cordz_info) { assert(cordz_info != nullptr); data_.set_cordz_info(cordz_info); } @@ -980,19 +994,19 @@ class Cord { InlineRep contents_; // Helper for GetFlat() and TryFlat(). - static bool GetFlatAux(absl::cord_internal::CordRep* rep, - absl::string_view* fragment); + static bool GetFlatAux(absl::Nonnull<absl::cord_internal::CordRep*> rep, + absl::Nonnull<absl::string_view*> fragment); // Helper for ForEachChunk(). static void ForEachChunkAux( - absl::cord_internal::CordRep* rep, + absl::Nonnull<absl::cord_internal::CordRep*> rep, absl::FunctionRef<void(absl::string_view)> callback); // The destructor for non-empty Cords. void DestroyCordSlow(); // Out-of-line implementation of slower parts of logic. - void CopyToArraySlowPath(char* dst) const; + void CopyToArraySlowPath(absl::Nonnull<char*> dst) const; int CompareSlowPath(absl::string_view rhs, size_t compared_size, size_t size_to_compare) const; int CompareSlowPath(const Cord& rhs, size_t compared_size, @@ -1009,8 +1023,8 @@ class Cord { // Returns a new reference to contents_.tree(), or steals an existing // reference if called on an rvalue. - absl::cord_internal::CordRep* TakeRep() const&; - absl::cord_internal::CordRep* TakeRep() &&; + absl::Nonnull<absl::cord_internal::CordRep*> TakeRep() const&; + absl::Nonnull<absl::cord_internal::CordRep*> TakeRep() &&; // Helper for Append(). template <typename C> @@ -1047,7 +1061,8 @@ class Cord { friend class CrcCord; void SetCrcCordState(crc_internal::CrcCordState state); - const crc_internal::CrcCordState* MaybeGetCrcCordState() const; + absl::Nullable<const crc_internal::CrcCordState*> MaybeGetCrcCordState() + const; CharIterator FindImpl(CharIterator it, absl::string_view needle) const; }; @@ -1068,13 +1083,15 @@ namespace cord_internal { // Does non-template-specific `CordRepExternal` initialization. // Requires `data` to be non-empty. -void InitializeCordRepExternal(absl::string_view data, CordRepExternal* rep); +void InitializeCordRepExternal(absl::string_view data, + absl::Nonnull<CordRepExternal*> rep); // Creates a new `CordRep` that owns `data` and `releaser` and returns a pointer // to it. Requires `data` to be non-empty. template <typename Releaser> // NOLINTNEXTLINE - suppress clang-tidy raw pointer return. -CordRep* NewExternalRep(absl::string_view data, Releaser&& releaser) { +absl::Nonnull<CordRep*> NewExternalRep(absl::string_view data, + Releaser&& releaser) { assert(!data.empty()); using ReleaserType = absl::decay_t<Releaser>; CordRepExternal* rep = new CordRepExternalImpl<ReleaserType>( @@ -1086,7 +1103,7 @@ CordRep* NewExternalRep(absl::string_view data, Releaser&& releaser) { // Overload for function reference types that dispatches using a function // pointer because there are no `alignof()` or `sizeof()` a function reference. // NOLINTNEXTLINE - suppress clang-tidy raw pointer return. -inline CordRep* NewExternalRep(absl::string_view data, +inline absl::Nonnull<CordRep*> NewExternalRep(absl::string_view data, void (&releaser)(absl::string_view)) { return NewExternalRep(data, &releaser); } @@ -1109,7 +1126,8 @@ Cord MakeCordFromExternal(absl::string_view data, Releaser&& releaser) { return cord; } -constexpr Cord::InlineRep::InlineRep(absl::string_view sv, CordRep* rep) +constexpr Cord::InlineRep::InlineRep(absl::string_view sv, + absl::Nullable<CordRep*> rep) : data_(sv, rep) {} inline Cord::InlineRep::InlineRep(const Cord::InlineRep& src) @@ -1148,28 +1166,30 @@ inline Cord::InlineRep& Cord::InlineRep::operator=( return *this; } -inline void Cord::InlineRep::Swap(Cord::InlineRep* rhs) { +inline void Cord::InlineRep::Swap(absl::Nonnull<Cord::InlineRep*> rhs) { if (rhs == this) { return; } std::swap(data_, rhs->data_); } -inline const char* Cord::InlineRep::data() const { +inline absl::Nullable<const char*> Cord::InlineRep::data() const { return is_tree() ? nullptr : data_.as_chars(); } -inline const char* Cord::InlineRep::as_chars() const { +inline absl::Nonnull<const char*> Cord::InlineRep::as_chars() const { assert(!data_.is_tree()); return data_.as_chars(); } -inline absl::cord_internal::CordRep* Cord::InlineRep::as_tree() const { +inline absl::Nonnull<absl::cord_internal::CordRep*> Cord::InlineRep::as_tree() + const { assert(data_.is_tree()); return data_.as_tree(); } -inline absl::cord_internal::CordRep* Cord::InlineRep::tree() const { +inline absl::Nullable<absl::cord_internal::CordRep*> Cord::InlineRep::tree() + const { if (is_tree()) { return as_tree(); } else { @@ -1181,8 +1201,8 @@ inline size_t Cord::InlineRep::size() const { return is_tree() ? as_tree()->length : inline_size(); } -inline cord_internal::CordRepFlat* Cord::InlineRep::MakeFlatWithExtraCapacity( - size_t extra) { +inline absl::Nonnull<cord_internal::CordRepFlat*> +Cord::InlineRep::MakeFlatWithExtraCapacity(size_t extra) { static_assert(cord_internal::kMinFlatLength >= sizeof(data_), ""); size_t len = data_.inline_size(); auto* result = CordRepFlat::New(len + extra); @@ -1191,20 +1211,21 @@ inline cord_internal::CordRepFlat* Cord::InlineRep::MakeFlatWithExtraCapacity( return result; } -inline void Cord::InlineRep::EmplaceTree(CordRep* rep, +inline void Cord::InlineRep::EmplaceTree(absl::Nonnull<CordRep*> rep, MethodIdentifier method) { assert(rep); data_.make_tree(rep); CordzInfo::MaybeTrackCord(data_, method); } -inline void Cord::InlineRep::EmplaceTree(CordRep* rep, const InlineData& parent, +inline void Cord::InlineRep::EmplaceTree(absl::Nonnull<CordRep*> rep, + const InlineData& parent, MethodIdentifier method) { data_.make_tree(rep); CordzInfo::MaybeTrackCord(data_, parent, method); } -inline void Cord::InlineRep::SetTree(CordRep* rep, +inline void Cord::InlineRep::SetTree(absl::Nonnull<CordRep*> rep, const CordzUpdateScope& scope) { assert(rep); assert(data_.is_tree()); @@ -1212,7 +1233,7 @@ inline void Cord::InlineRep::SetTree(CordRep* rep, scope.SetCordRep(rep); } -inline void Cord::InlineRep::SetTreeOrEmpty(CordRep* rep, +inline void Cord::InlineRep::SetTreeOrEmpty(absl::Nullable<CordRep*> rep, const CordzUpdateScope& scope) { assert(data_.is_tree()); if (rep) { @@ -1223,7 +1244,8 @@ inline void Cord::InlineRep::SetTreeOrEmpty(CordRep* rep, scope.SetCordRep(rep); } -inline void Cord::InlineRep::CommitTree(const CordRep* old_rep, CordRep* rep, +inline void Cord::InlineRep::CommitTree(absl::Nullable<const CordRep*> old_rep, + absl::Nonnull<CordRep*> rep, const CordzUpdateScope& scope, MethodIdentifier method) { if (old_rep) { @@ -1233,7 +1255,7 @@ inline void Cord::InlineRep::CommitTree(const CordRep* old_rep, CordRep* rep, } } -inline absl::cord_internal::CordRep* Cord::InlineRep::clear() { +inline absl::Nullable<absl::cord_internal::CordRep*> Cord::InlineRep::clear() { if (is_tree()) { CordzInfo::MaybeUntrackCord(cordz_info()); } @@ -1242,7 +1264,7 @@ inline absl::cord_internal::CordRep* Cord::InlineRep::clear() { return result; } -inline void Cord::InlineRep::CopyToArray(char* dst) const { +inline void Cord::InlineRep::CopyToArray(absl::Nonnull<char*> dst) const { assert(!is_tree()); size_t n = inline_size(); assert(n != 0); @@ -1423,7 +1445,8 @@ inline bool Cord::StartsWith(absl::string_view rhs) const { return EqualsImpl(rhs, rhs_size); } -inline void Cord::ChunkIterator::InitTree(cord_internal::CordRep* tree) { +inline void Cord::ChunkIterator::InitTree( + absl::Nonnull<cord_internal::CordRep*> tree) { tree = cord_internal::SkipCrcNode(tree); if (tree->tag == cord_internal::BTREE) { current_chunk_ = btree_reader_.Init(tree->btree()); @@ -1433,12 +1456,13 @@ inline void Cord::ChunkIterator::InitTree(cord_internal::CordRep* tree) { } } -inline Cord::ChunkIterator::ChunkIterator(cord_internal::CordRep* tree) { +inline Cord::ChunkIterator::ChunkIterator( + absl::Nonnull<cord_internal::CordRep*> tree) { bytes_remaining_ = tree->length; InitTree(tree); } -inline Cord::ChunkIterator::ChunkIterator(const Cord* cord) { +inline Cord::ChunkIterator::ChunkIterator(absl::Nonnull<const Cord*> cord) { if (CordRep* tree = cord->contents_.tree()) { bytes_remaining_ = tree->length; if (ABSL_PREDICT_TRUE(bytes_remaining_ != 0)) { @@ -1578,12 +1602,13 @@ inline Cord::CharIterator::pointer Cord::CharIterator::operator->() const { return chunk_iterator_->data(); } -inline Cord Cord::AdvanceAndRead(CharIterator* it, size_t n_bytes) { +inline Cord Cord::AdvanceAndRead(absl::Nonnull<CharIterator*> it, + size_t n_bytes) { assert(it != nullptr); return it->chunk_iterator_.AdvanceAndReadBytes(n_bytes); } -inline void Cord::Advance(CharIterator* it, size_t n_bytes) { +inline void Cord::Advance(absl::Nonnull<CharIterator*> it, size_t n_bytes) { assert(it != nullptr); it->chunk_iterator_.AdvanceBytes(n_bytes); } diff --git a/absl/strings/cord_analysis.cc b/absl/strings/cord_analysis.cc index 5418a325..19b0fa44 100644 --- a/absl/strings/cord_analysis.cc +++ b/absl/strings/cord_analysis.cc @@ -20,6 +20,7 @@ #include <unordered_set> #include "absl/base/config.h" +#include "absl/base/nullability.h" #include "absl/strings/internal/cord_data_edge.h" #include "absl/strings/internal/cord_internal.h" #include "absl/strings/internal/cord_rep_btree.h" @@ -38,13 +39,15 @@ enum class Mode { kFairShare, kTotal, kTotalMorePrecise }; template <Mode mode> struct CordRepRef { // Instantiates a CordRepRef instance. - explicit CordRepRef(const CordRep* r) : rep(r) {} + explicit CordRepRef(absl::Nonnull<const CordRep*> r) : rep(r) {} // Creates a child reference holding the provided child. // Overloaded to add cumulative reference count for kFairShare. - CordRepRef Child(const CordRep* child) const { return CordRepRef(child); } + CordRepRef Child(absl::Nonnull<const CordRep*> child) const { + return CordRepRef(child); + } - const CordRep* rep; + absl::Nonnull<const CordRep*> rep; }; // RawUsage holds the computed total number of bytes. @@ -63,7 +66,7 @@ template <> struct RawUsage<Mode::kTotalMorePrecise> { size_t total = 0; // TODO(b/289250880): Replace this with a flat_hash_set. - std::unordered_set<const CordRep*> counted; + std::unordered_set<absl::Nonnull<const CordRep*>> counted; void Add(size_t size, CordRepRef<Mode::kTotalMorePrecise> repref) { if (counted.insert(repref.rep).second) { @@ -87,15 +90,15 @@ double MaybeDiv(double d, refcount_t refcount) { template <> struct CordRepRef<Mode::kFairShare> { // Creates a CordRepRef with the provided rep and top (parent) fraction. - explicit CordRepRef(const CordRep* r, double frac = 1.0) + explicit CordRepRef(absl::Nonnull<const CordRep*> r, double frac = 1.0) : rep(r), fraction(MaybeDiv(frac, r->refcount.Get())) {} // Returns a CordRepRef with a fraction of `this->fraction / child.refcount` - CordRepRef Child(const CordRep* child) const { + CordRepRef Child(absl::Nonnull<const CordRep*> child) const { return CordRepRef(child, fraction); } - const CordRep* rep; + absl::Nonnull<const CordRep*> rep; double fraction; }; @@ -147,7 +150,7 @@ void AnalyzeBtree(CordRepRef<mode> rep, RawUsage<mode>& raw_usage) { } template <Mode mode> -size_t GetEstimatedUsage(const CordRep* rep) { +size_t GetEstimatedUsage(absl::Nonnull<const CordRep*> rep) { // Zero initialized memory usage totals. RawUsage<mode> raw_usage; @@ -176,15 +179,15 @@ size_t GetEstimatedUsage(const CordRep* rep) { } // namespace -size_t GetEstimatedMemoryUsage(const CordRep* rep) { +size_t GetEstimatedMemoryUsage(absl::Nonnull<const CordRep*> rep) { return GetEstimatedUsage<Mode::kTotal>(rep); } -size_t GetEstimatedFairShareMemoryUsage(const CordRep* rep) { +size_t GetEstimatedFairShareMemoryUsage(absl::Nonnull<const CordRep*> rep) { return GetEstimatedUsage<Mode::kFairShare>(rep); } -size_t GetMorePreciseMemoryUsage(const CordRep* rep) { +size_t GetMorePreciseMemoryUsage(absl::Nonnull<const CordRep*> rep) { return GetEstimatedUsage<Mode::kTotalMorePrecise>(rep); } diff --git a/absl/strings/cord_analysis.h b/absl/strings/cord_analysis.h index 9b9527a5..f8ce3489 100644 --- a/absl/strings/cord_analysis.h +++ b/absl/strings/cord_analysis.h @@ -19,6 +19,7 @@ #include <cstdint> #include "absl/base/config.h" +#include "absl/base/nullability.h" #include "absl/strings/internal/cord_internal.h" namespace absl { @@ -28,7 +29,7 @@ namespace cord_internal { // Returns the *approximate* number of bytes held in full or in part by this // Cord (which may not remain the same between invocations). Cords that share // memory could each be "charged" independently for the same shared memory. -size_t GetEstimatedMemoryUsage(const CordRep* rep); +size_t GetEstimatedMemoryUsage(absl::Nonnull<const CordRep*> rep); // Returns the *approximate* number of bytes held in full or in part by this // Cord for the distinct memory held by this cord. This is similar to @@ -46,13 +47,13 @@ size_t GetEstimatedMemoryUsage(const CordRep* rep); // // This is more expensive than `GetEstimatedMemoryUsage()` as it requires // deduplicating all memory references. -size_t GetMorePreciseMemoryUsage(const CordRep* rep); +size_t GetMorePreciseMemoryUsage(absl::Nonnull<const CordRep*> rep); // Returns the *approximate* number of bytes held in full or in part by this // CordRep weighted by the sharing ratio of that data. For example, if some data // edge is shared by 4 different Cords, then each cord is attribute 1/4th of // the total memory usage as a 'fair share' of the total memory usage. -size_t GetEstimatedFairShareMemoryUsage(const CordRep* rep); +size_t GetEstimatedFairShareMemoryUsage(absl::Nonnull<const CordRep*> rep); } // namespace cord_internal ABSL_NAMESPACE_END diff --git a/absl/strings/cordz_test_helpers.h b/absl/strings/cordz_test_helpers.h index e410eecf..619f13c2 100644 --- a/absl/strings/cordz_test_helpers.h +++ b/absl/strings/cordz_test_helpers.h @@ -21,6 +21,7 @@ #include "gtest/gtest.h" #include "absl/base/config.h" #include "absl/base/macros.h" +#include "absl/base/nullability.h" #include "absl/strings/cord.h" #include "absl/strings/internal/cord_internal.h" #include "absl/strings/internal/cordz_info.h" @@ -33,15 +34,16 @@ namespace absl { ABSL_NAMESPACE_BEGIN // Returns the CordzInfo for the cord, or nullptr if the cord is not sampled. -inline const cord_internal::CordzInfo* GetCordzInfoForTesting( +inline absl::Nullable<const cord_internal::CordzInfo*> GetCordzInfoForTesting( const Cord& cord) { if (!cord.contents_.is_tree()) return nullptr; return cord.contents_.cordz_info(); } // Returns true if the provided cordz_info is in the list of sampled cords. -inline bool CordzInfoIsListed(const cord_internal::CordzInfo* cordz_info, - cord_internal::CordzSampleToken token = {}) { +inline bool CordzInfoIsListed( + absl::Nonnull<const cord_internal::CordzInfo*> cordz_info, + cord_internal::CordzSampleToken token = {}) { for (const cord_internal::CordzInfo& info : token) { if (cordz_info == &info) return true; } @@ -119,7 +121,7 @@ class CordzSamplingIntervalHelper { // Wrapper struct managing a small CordRep `rep` struct TestCordRep { - cord_internal::CordRepFlat* rep; + absl::Nonnull<cord_internal::CordRepFlat*> rep; TestCordRep() { rep = cord_internal::CordRepFlat::New(100); diff --git a/absl/strings/numbers.cc b/absl/strings/numbers.cc index c4f21030..b57d9e82 100644 --- a/absl/strings/numbers.cc +++ b/absl/strings/numbers.cc @@ -34,6 +34,7 @@ #include "absl/base/config.h" #include "absl/base/internal/endian.h" #include "absl/base/internal/raw_logging.h" +#include "absl/base/nullability.h" #include "absl/base/optimization.h" #include "absl/numeric/bits.h" #include "absl/numeric/int128.h" @@ -45,7 +46,7 @@ namespace absl { ABSL_NAMESPACE_BEGIN -bool SimpleAtof(absl::string_view str, float* out) { +bool SimpleAtof(absl::string_view str, absl::Nonnull<float*> out) { *out = 0.0; str = StripAsciiWhitespace(str); // std::from_chars doesn't accept an initial +, but SimpleAtof does, so if one @@ -76,7 +77,7 @@ bool SimpleAtof(absl::string_view str, float* out) { return true; } -bool SimpleAtod(absl::string_view str, double* out) { +bool SimpleAtod(absl::string_view str, absl::Nonnull<double*> out) { *out = 0.0; str = StripAsciiWhitespace(str); // std::from_chars doesn't accept an initial +, but SimpleAtod does, so if one @@ -107,7 +108,7 @@ bool SimpleAtod(absl::string_view str, double* out) { return true; } -bool SimpleAtob(absl::string_view str, bool* out) { +bool SimpleAtob(absl::string_view str, absl::Nonnull<bool*> out) { ABSL_RAW_CHECK(out != nullptr, "Output pointer must not be nullptr."); if (EqualsIgnoreCase(str, "true") || EqualsIgnoreCase(str, "t") || EqualsIgnoreCase(str, "yes") || EqualsIgnoreCase(str, "y") || @@ -166,7 +167,7 @@ constexpr uint64_t kDivisionBy100Mul = 10486u; constexpr uint64_t kDivisionBy100Div = 1 << 20; // Encode functions write the ASCII output of input `n` to `out_str`. -inline char* EncodeHundred(uint32_t n, char* out_str) { +inline char* EncodeHundred(uint32_t n, absl::Nonnull<char*> out_str) { int num_digits = static_cast<int>(n - 10) >> 8; uint32_t div10 = (n * kDivisionBy10Mul) / kDivisionBy10Div; uint32_t mod10 = n - 10u * div10; @@ -176,7 +177,7 @@ inline char* EncodeHundred(uint32_t n, char* out_str) { return out_str + 2 + num_digits; } -inline char* EncodeTenThousand(uint32_t n, char* out_str) { +inline char* EncodeTenThousand(uint32_t n, absl::Nonnull<char*> out_str) { // We split lower 2 digits and upper 2 digits of n into 2 byte consecutive // blocks. 123 -> [\0\1][\0\23]. We divide by 10 both blocks // (it's 1 division + zeroing upper bits), and compute modulo 10 as well "in @@ -232,8 +233,8 @@ inline uint64_t PrepareEightDigits(uint32_t i) { return tens; } -inline ABSL_ATTRIBUTE_ALWAYS_INLINE char* EncodeFullU32(uint32_t n, - char* out_str) { +inline ABSL_ATTRIBUTE_ALWAYS_INLINE absl::Nonnull<char*> EncodeFullU32( + uint32_t n, absl::Nonnull<char*> out_str) { if (n < 10) { *out_str = static_cast<char>('0' + n); return out_str + 1; @@ -282,7 +283,7 @@ inline ABSL_ATTRIBUTE_ALWAYS_INLINE char* EncodeFullU64(uint64_t i, } // namespace -void numbers_internal::PutTwoDigits(uint32_t i, char* buf) { +void numbers_internal::PutTwoDigits(uint32_t i, absl::Nonnull<char*> buf) { assert(i < 100); uint32_t base = kTwoZeroBytes; uint32_t div10 = (i * kDivisionBy10Mul) / kDivisionBy10Div; @@ -291,13 +292,15 @@ void numbers_internal::PutTwoDigits(uint32_t i, char* buf) { little_endian::Store16(buf, static_cast<uint16_t>(base)); } -char* numbers_internal::FastIntToBuffer(uint32_t n, char* out_str) { +absl::Nonnull<char*> numbers_internal::FastIntToBuffer( + uint32_t n, absl::Nonnull<char*> out_str) { out_str = EncodeFullU32(n, out_str); *out_str = '\0'; return out_str; } -char* numbers_internal::FastIntToBuffer(int32_t i, char* buffer) { +absl::Nonnull<char*> numbers_internal::FastIntToBuffer( + int32_t i, absl::Nonnull<char*> buffer) { uint32_t u = static_cast<uint32_t>(i); if (i < 0) { *buffer++ = '-'; @@ -311,13 +314,15 @@ char* numbers_internal::FastIntToBuffer(int32_t i, char* buffer) { return buffer; } -char* numbers_internal::FastIntToBuffer(uint64_t i, char* buffer) { +absl::Nonnull<char*> numbers_internal::FastIntToBuffer( + uint64_t i, absl::Nonnull<char*> buffer) { buffer = EncodeFullU64(i, buffer); *buffer = '\0'; return buffer; } -char* numbers_internal::FastIntToBuffer(int64_t i, char* buffer) { +absl::Nonnull<char*> numbers_internal::FastIntToBuffer( + int64_t i, absl::Nonnull<char*> buffer) { uint64_t u = static_cast<uint64_t>(i); if (i < 0) { *buffer++ = '-'; @@ -538,7 +543,8 @@ static ExpDigits SplitToSix(const double value) { // Helper function for fast formatting of floating-point. // The result is the same as "%g", a.k.a. "%.6g". -size_t numbers_internal::SixDigitsToBuffer(double d, char* const buffer) { +size_t numbers_internal::SixDigitsToBuffer(double d, + absl::Nonnull<char*> const buffer) { static_assert(std::numeric_limits<float>::is_iec559, "IEEE-754/IEC-559 support only"); @@ -685,9 +691,10 @@ static const int8_t kAsciiToInt[256] = { 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36}; // Parse the sign and optional hex or oct prefix in text. -inline bool safe_parse_sign_and_base(absl::string_view* text /*inout*/, - int* base_ptr /*inout*/, - bool* negative_ptr /*output*/) { +inline bool safe_parse_sign_and_base( + absl::Nonnull<absl::string_view*> text /*inout*/, + absl::Nonnull<int*> base_ptr /*inout*/, + absl::Nonnull<bool*> negative_ptr /*output*/) { if (text->data() == nullptr) { return false; } @@ -972,7 +979,7 @@ ABSL_CONST_INIT const IntType LookupTables<IntType>::kVminOverBase[] = template <typename IntType> inline bool safe_parse_positive_int(absl::string_view text, int base, - IntType* value_p) { + absl::Nonnull<IntType*> value_p) { IntType value = 0; const IntType vmax = std::numeric_limits<IntType>::max(); assert(vmax > 0); @@ -1009,7 +1016,7 @@ inline bool safe_parse_positive_int(absl::string_view text, int base, template <typename IntType> inline bool safe_parse_negative_int(absl::string_view text, int base, - IntType* value_p) { + absl::Nonnull<IntType*> value_p) { IntType value = 0; const IntType vmin = std::numeric_limits<IntType>::min(); assert(vmin < 0); @@ -1053,8 +1060,8 @@ inline bool safe_parse_negative_int(absl::string_view text, int base, // Input format based on POSIX.1-2008 strtol // http://pubs.opengroup.org/onlinepubs/9699919799/functions/strtol.html template <typename IntType> -inline bool safe_int_internal(absl::string_view text, IntType* value_p, - int base) { +inline bool safe_int_internal(absl::string_view text, + absl::Nonnull<IntType*> value_p, int base) { *value_p = 0; bool negative; if (!safe_parse_sign_and_base(&text, &base, &negative)) { @@ -1068,8 +1075,8 @@ inline bool safe_int_internal(absl::string_view text, IntType* value_p, } template <typename IntType> -inline bool safe_uint_internal(absl::string_view text, IntType* value_p, - int base) { +inline bool safe_uint_internal(absl::string_view text, + absl::Nonnull<IntType*> value_p, int base) { *value_p = 0; bool negative; if (!safe_parse_sign_and_base(&text, &base, &negative) || negative) { @@ -1103,27 +1110,33 @@ ABSL_CONST_INIT ABSL_DLL const char kHexTable[513] = "e0e1e2e3e4e5e6e7e8e9eaebecedeeef" "f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff"; -bool safe_strto32_base(absl::string_view text, int32_t* value, int base) { +bool safe_strto32_base(absl::string_view text, absl::Nonnull<int32_t*> value, + int base) { return safe_int_internal<int32_t>(text, value, base); } -bool safe_strto64_base(absl::string_view text, int64_t* value, int base) { +bool safe_strto64_base(absl::string_view text, absl::Nonnull<int64_t*> value, + int base) { return safe_int_internal<int64_t>(text, value, base); } -bool safe_strto128_base(absl::string_view text, int128* value, int base) { +bool safe_strto128_base(absl::string_view text, absl::Nonnull<int128*> value, + int base) { return safe_int_internal<absl::int128>(text, value, base); } -bool safe_strtou32_base(absl::string_view text, uint32_t* value, int base) { +bool safe_strtou32_base(absl::string_view text, absl::Nonnull<uint32_t*> value, + int base) { return safe_uint_internal<uint32_t>(text, value, base); } -bool safe_strtou64_base(absl::string_view text, uint64_t* value, int base) { +bool safe_strtou64_base(absl::string_view text, absl::Nonnull<uint64_t*> value, + int base) { return safe_uint_internal<uint64_t>(text, value, base); } -bool safe_strtou128_base(absl::string_view text, uint128* value, int base) { +bool safe_strtou128_base(absl::string_view text, absl::Nonnull<uint128*> value, + int base) { return safe_uint_internal<absl::uint128>(text, value, base); } diff --git a/absl/strings/numbers.h b/absl/strings/numbers.h index d7630cef..1d929de9 100644 --- a/absl/strings/numbers.h +++ b/absl/strings/numbers.h @@ -42,6 +42,7 @@ #include "absl/base/config.h" #include "absl/base/internal/endian.h" #include "absl/base/macros.h" +#include "absl/base/nullability.h" #include "absl/base/port.h" #include "absl/numeric/bits.h" #include "absl/numeric/int128.h" @@ -59,7 +60,8 @@ ABSL_NAMESPACE_BEGIN // encountered, this function returns `false`, leaving `out` in an unspecified // state. template <typename int_type> -ABSL_MUST_USE_RESULT bool SimpleAtoi(absl::string_view str, int_type* out); +ABSL_MUST_USE_RESULT bool SimpleAtoi(absl::string_view str, + absl::Nonnull<int_type*> out); // SimpleAtof() // @@ -70,7 +72,8 @@ ABSL_MUST_USE_RESULT bool SimpleAtoi(absl::string_view str, int_type* out); // allowed formats for `str`, except SimpleAtof() is locale-independent and will // always use the "C" locale. If any errors are encountered, this function // returns `false`, leaving `out` in an unspecified state. -ABSL_MUST_USE_RESULT bool SimpleAtof(absl::string_view str, float* out); +ABSL_MUST_USE_RESULT bool SimpleAtof(absl::string_view str, + absl::Nonnull<float*> out); // SimpleAtod() // @@ -81,7 +84,8 @@ ABSL_MUST_USE_RESULT bool SimpleAtof(absl::string_view str, float* out); // allowed formats for `str`, except SimpleAtod is locale-independent and will // always use the "C" locale. If any errors are encountered, this function // returns `false`, leaving `out` in an unspecified state. -ABSL_MUST_USE_RESULT bool SimpleAtod(absl::string_view str, double* out); +ABSL_MUST_USE_RESULT bool SimpleAtod(absl::string_view str, + absl::Nonnull<double*> out); // SimpleAtob() // @@ -91,7 +95,8 @@ ABSL_MUST_USE_RESULT bool SimpleAtod(absl::string_view str, double* out); // are interpreted as boolean `false`: "false", "f", "no", "n", "0". If any // errors are encountered, this function returns `false`, leaving `out` in an // unspecified state. -ABSL_MUST_USE_RESULT bool SimpleAtob(absl::string_view str, bool* out); +ABSL_MUST_USE_RESULT bool SimpleAtob(absl::string_view str, + absl::Nonnull<bool*> out); // SimpleHexAtoi() // @@ -104,13 +109,14 @@ ABSL_MUST_USE_RESULT bool SimpleAtob(absl::string_view str, bool* out); // by this function. If any errors are encountered, this function returns // `false`, leaving `out` in an unspecified state. template <typename int_type> -ABSL_MUST_USE_RESULT bool SimpleHexAtoi(absl::string_view str, int_type* out); +ABSL_MUST_USE_RESULT bool SimpleHexAtoi(absl::string_view str, + absl::Nonnull<int_type*> out); // Overloads of SimpleHexAtoi() for 128 bit integers. -ABSL_MUST_USE_RESULT inline bool SimpleHexAtoi(absl::string_view str, - absl::int128* out); -ABSL_MUST_USE_RESULT inline bool SimpleHexAtoi(absl::string_view str, - absl::uint128* out); +ABSL_MUST_USE_RESULT inline bool SimpleHexAtoi( + absl::string_view str, absl::Nonnull<absl::int128*> out); +ABSL_MUST_USE_RESULT inline bool SimpleHexAtoi( + absl::string_view str, absl::Nonnull<absl::uint128*> out); ABSL_NAMESPACE_END } // namespace absl @@ -132,18 +138,22 @@ ABSL_DLL extern const char // PutTwoDigits(42, buf); // // buf[0] == '4' // // buf[1] == '2' -void PutTwoDigits(uint32_t i, char* buf); +void PutTwoDigits(uint32_t i, absl::Nonnull<char*> buf); // safe_strto?() functions for implementing SimpleAtoi() -bool safe_strto32_base(absl::string_view text, int32_t* value, int base); -bool safe_strto64_base(absl::string_view text, int64_t* value, int base); -bool safe_strto128_base(absl::string_view text, absl::int128* value, - int base); -bool safe_strtou32_base(absl::string_view text, uint32_t* value, int base); -bool safe_strtou64_base(absl::string_view text, uint64_t* value, int base); -bool safe_strtou128_base(absl::string_view text, absl::uint128* value, - int base); +bool safe_strto32_base(absl::string_view text, absl::Nonnull<int32_t*> value, + int base); +bool safe_strto64_base(absl::string_view text, absl::Nonnull<int64_t*> value, + int base); +bool safe_strto128_base(absl::string_view text, + absl::Nonnull<absl::int128*> value, int base); +bool safe_strtou32_base(absl::string_view text, absl::Nonnull<uint32_t*> value, + int base); +bool safe_strtou64_base(absl::string_view text, absl::Nonnull<uint64_t*> value, + int base); +bool safe_strtou128_base(absl::string_view text, + absl::Nonnull<absl::uint128*> value, int base); static const int kFastToBufferSize = 32; static const int kSixDigitsToBufferSize = 16; @@ -154,20 +164,20 @@ static const int kSixDigitsToBufferSize = 16; // outside the range 0.0001-999999 are output using scientific notation // (1.23456e+06). This routine is heavily optimized. // Required buffer size is `kSixDigitsToBufferSize`. -size_t SixDigitsToBuffer(double d, char* buffer); +size_t SixDigitsToBuffer(double d, absl::Nonnull<char*> buffer); // These functions are intended for speed. All functions take an output buffer // as an argument and return a pointer to the last byte they wrote, which is the // terminating '\0'. At most `kFastToBufferSize` bytes are written. -char* FastIntToBuffer(int32_t, char*); -char* FastIntToBuffer(uint32_t, char*); -char* FastIntToBuffer(int64_t, char*); -char* FastIntToBuffer(uint64_t, char*); +absl::Nonnull<char*> FastIntToBuffer(int32_t, absl::Nonnull<char*>); +absl::Nonnull<char*> FastIntToBuffer(uint32_t, absl::Nonnull<char*>); +absl::Nonnull<char*> FastIntToBuffer(int64_t, absl::Nonnull<char*>); +absl::Nonnull<char*> FastIntToBuffer(uint64_t, absl::Nonnull<char*>); // For enums and integer types that are not an exact match for the types above, // use templates to call the appropriate one of the four overloads above. template <typename int_type> -char* FastIntToBuffer(int_type i, char* buffer) { +absl::Nonnull<char*> FastIntToBuffer(int_type i, absl::Nonnull<char*> buffer) { static_assert(sizeof(i) <= 64 / 8, "FastIntToBuffer works only with 64-bit-or-less integers."); // TODO(jorg): This signed-ness check is used because it works correctly @@ -194,7 +204,8 @@ char* FastIntToBuffer(int_type i, char* buffer) { // Implementation of SimpleAtoi, generalized to support arbitrary base (used // with base different from 10 elsewhere in Abseil implementation). template <typename int_type> -ABSL_MUST_USE_RESULT bool safe_strtoi_base(absl::string_view s, int_type* out, +ABSL_MUST_USE_RESULT bool safe_strtoi_base(absl::string_view s, + absl::Nonnull<int_type*> out, int base) { static_assert(sizeof(*out) == 4 || sizeof(*out) == 8, "SimpleAtoi works only with 32-bit or 64-bit integers."); @@ -237,7 +248,7 @@ ABSL_MUST_USE_RESULT bool safe_strtoi_base(absl::string_view s, int_type* out, // without the terminating null character. Thus `out` must be of length >= 16. // Returns the number of non-pad digits of the output (it can never be zero // since 0 has one digit). -inline size_t FastHexToBufferZeroPad16(uint64_t val, char* out) { +inline size_t FastHexToBufferZeroPad16(uint64_t val, absl::Nonnull<char*> out) { #ifdef ABSL_INTERNAL_HAVE_SSSE3 uint64_t be = absl::big_endian::FromHost64(val); const auto kNibbleMask = _mm_set1_epi8(0xf); @@ -263,32 +274,34 @@ inline size_t FastHexToBufferZeroPad16(uint64_t val, char* out) { } // namespace numbers_internal template <typename int_type> -ABSL_MUST_USE_RESULT bool SimpleAtoi(absl::string_view str, int_type* out) { +ABSL_MUST_USE_RESULT bool SimpleAtoi(absl::string_view str, + absl::Nonnull<int_type*> out) { return numbers_internal::safe_strtoi_base(str, out, 10); } ABSL_MUST_USE_RESULT inline bool SimpleAtoi(absl::string_view str, - absl::int128* out) { + absl::Nonnull<absl::int128*> out) { return numbers_internal::safe_strto128_base(str, out, 10); } ABSL_MUST_USE_RESULT inline bool SimpleAtoi(absl::string_view str, - absl::uint128* out) { + absl::Nonnull<absl::uint128*> out) { return numbers_internal::safe_strtou128_base(str, out, 10); } template <typename int_type> -ABSL_MUST_USE_RESULT bool SimpleHexAtoi(absl::string_view str, int_type* out) { +ABSL_MUST_USE_RESULT bool SimpleHexAtoi(absl::string_view str, + absl::Nonnull<int_type*> out) { return numbers_internal::safe_strtoi_base(str, out, 16); } -ABSL_MUST_USE_RESULT inline bool SimpleHexAtoi(absl::string_view str, - absl::int128* out) { +ABSL_MUST_USE_RESULT inline bool SimpleHexAtoi( + absl::string_view str, absl::Nonnull<absl::int128*> out) { return numbers_internal::safe_strto128_base(str, out, 16); } -ABSL_MUST_USE_RESULT inline bool SimpleHexAtoi(absl::string_view str, - absl::uint128* out) { +ABSL_MUST_USE_RESULT inline bool SimpleHexAtoi( + absl::string_view str, absl::Nonnull<absl::uint128*> out) { return numbers_internal::safe_strtou128_base(str, out, 16); } diff --git a/absl/strings/str_cat.cc b/absl/strings/str_cat.cc index 900dc69a..e7f7052a 100644 --- a/absl/strings/str_cat.cc +++ b/absl/strings/str_cat.cc @@ -23,6 +23,7 @@ #include <string> #include "absl/base/config.h" +#include "absl/base/nullability.h" #include "absl/strings/internal/resize_uninitialized.h" #include "absl/strings/string_view.h" @@ -40,7 +41,8 @@ ABSL_NAMESPACE_BEGIN namespace { // Append is merely a version of memcpy that returns the address of the byte // after the area just overwritten. -inline char* Append(char* out, const AlphaNum& x) { +inline absl::Nonnull<char*> Append(absl::Nonnull<char*> out, + const AlphaNum& x) { // memcpy is allowed to overwrite arbitrary memory, so doing this after the // call would force an extra fetch of x.size(). char* after = out + x.size(); @@ -128,7 +130,7 @@ std::string CatPieces(std::initializer_list<absl::string_view> pieces) { assert(((src).size() == 0) || \ (uintptr_t((src).data() - (dest).data()) > uintptr_t((dest).size()))) -void AppendPieces(std::string* dest, +void AppendPieces(absl::Nonnull<std::string*> dest, std::initializer_list<absl::string_view> pieces) { size_t old_size = dest->size(); size_t to_append = 0; @@ -152,7 +154,7 @@ void AppendPieces(std::string* dest, } // namespace strings_internal -void StrAppend(std::string* dest, const AlphaNum& a) { +void StrAppend(absl::Nonnull<std::string*> dest, const AlphaNum& a) { ASSERT_NO_OVERLAP(*dest, a); std::string::size_type old_size = dest->size(); STLStringAppendUninitializedAmortized(dest, a.size()); @@ -162,7 +164,8 @@ void StrAppend(std::string* dest, const AlphaNum& a) { assert(out == begin + dest->size()); } -void StrAppend(std::string* dest, const AlphaNum& a, const AlphaNum& b) { +void StrAppend(absl::Nonnull<std::string*> dest, const AlphaNum& a, + const AlphaNum& b) { ASSERT_NO_OVERLAP(*dest, a); ASSERT_NO_OVERLAP(*dest, b); std::string::size_type old_size = dest->size(); @@ -174,8 +177,8 @@ void StrAppend(std::string* dest, const AlphaNum& a, const AlphaNum& b) { assert(out == begin + dest->size()); } -void StrAppend(std::string* dest, const AlphaNum& a, const AlphaNum& b, - const AlphaNum& c) { +void StrAppend(absl::Nonnull<std::string*> dest, const AlphaNum& a, + const AlphaNum& b, const AlphaNum& c) { ASSERT_NO_OVERLAP(*dest, a); ASSERT_NO_OVERLAP(*dest, b); ASSERT_NO_OVERLAP(*dest, c); @@ -189,8 +192,8 @@ void StrAppend(std::string* dest, const AlphaNum& a, const AlphaNum& b, assert(out == begin + dest->size()); } -void StrAppend(std::string* dest, const AlphaNum& a, const AlphaNum& b, - const AlphaNum& c, const AlphaNum& d) { +void StrAppend(absl::Nonnull<std::string*> dest, const AlphaNum& a, + const AlphaNum& b, const AlphaNum& c, const AlphaNum& d) { ASSERT_NO_OVERLAP(*dest, a); ASSERT_NO_OVERLAP(*dest, b); ASSERT_NO_OVERLAP(*dest, c); diff --git a/absl/strings/str_cat.h b/absl/strings/str_cat.h index e7823683..68637ce8 100644 --- a/absl/strings/str_cat.h +++ b/absl/strings/str_cat.h @@ -100,6 +100,7 @@ #include <vector> #include "absl/base/attributes.h" +#include "absl/base/nullability.h" #include "absl/base/port.h" #include "absl/meta/type_traits.h" #include "absl/strings/has_absl_stringify.h" @@ -206,7 +207,7 @@ struct Hex { !std::is_pointer<Int>::value>::type* = nullptr) : Hex(spec, static_cast<uint64_t>(v)) {} template <typename Pointee> - explicit Hex(Pointee* v, PadSpec spec = absl::kNoPad) + explicit Hex(absl::Nullable<Pointee*> v, PadSpec spec = absl::kNoPad) : Hex(spec, reinterpret_cast<uintptr_t>(v)) {} template <typename S> @@ -349,7 +350,7 @@ class AlphaNum { ABSL_ATTRIBUTE_LIFETIME_BOUND) : piece_(&buf.data[0], buf.size) {} - AlphaNum(const char* c_str // NOLINT(runtime/explicit) + AlphaNum(absl::Nullable<const char*> c_str // NOLINT(runtime/explicit) ABSL_ATTRIBUTE_LIFETIME_BOUND) : piece_(NullSafeStringView(c_str)) {} AlphaNum(absl::string_view pc // NOLINT(runtime/explicit) @@ -376,7 +377,7 @@ class AlphaNum { AlphaNum& operator=(const AlphaNum&) = delete; absl::string_view::size_type size() const { return piece_.size(); } - const char* data() const { return piece_.data(); } + absl::Nullable<const char*> data() const { return piece_.data(); } absl::string_view Piece() const { return piece_; } // Match unscoped enums. Use integral promotion so that a `char`-backed @@ -446,7 +447,7 @@ namespace strings_internal { // Do not call directly - this is not part of the public API. std::string CatPieces(std::initializer_list<absl::string_view> pieces); -void AppendPieces(std::string* dest, +void AppendPieces(absl::Nonnull<std::string*> dest, std::initializer_list<absl::string_view> pieces); template <typename Integer> @@ -576,19 +577,20 @@ ABSL_MUST_USE_RESULT inline std::string StrCat( // absl::string_view p = s; // StrAppend(&s, p); -inline void StrAppend(std::string*) {} -void StrAppend(std::string* dest, const AlphaNum& a); -void StrAppend(std::string* dest, const AlphaNum& a, const AlphaNum& b); -void StrAppend(std::string* dest, const AlphaNum& a, const AlphaNum& b, - const AlphaNum& c); -void StrAppend(std::string* dest, const AlphaNum& a, const AlphaNum& b, - const AlphaNum& c, const AlphaNum& d); +inline void StrAppend(absl::Nonnull<std::string*>) {} +void StrAppend(absl::Nonnull<std::string*> dest, const AlphaNum& a); +void StrAppend(absl::Nonnull<std::string*> dest, const AlphaNum& a, + const AlphaNum& b); +void StrAppend(absl::Nonnull<std::string*> dest, const AlphaNum& a, + const AlphaNum& b, const AlphaNum& c); +void StrAppend(absl::Nonnull<std::string*> dest, const AlphaNum& a, + const AlphaNum& b, const AlphaNum& c, const AlphaNum& d); // Support 5 or more arguments template <typename... AV> -inline void StrAppend(std::string* dest, const AlphaNum& a, const AlphaNum& b, - const AlphaNum& c, const AlphaNum& d, const AlphaNum& e, - const AV&... args) { +inline void StrAppend(absl::Nonnull<std::string*> dest, const AlphaNum& a, + const AlphaNum& b, const AlphaNum& c, const AlphaNum& d, + const AlphaNum& e, const AV&... args) { strings_internal::AppendPieces( dest, {a.Piece(), b.Piece(), c.Piece(), d.Piece(), e.Piece(), static_cast<const AlphaNum&>(args).Piece()...}); diff --git a/absl/strings/str_format.h b/absl/strings/str_format.h index c9b350fd..66b6af58 100644 --- a/absl/strings/str_format.h +++ b/absl/strings/str_format.h @@ -79,6 +79,7 @@ #include "absl/base/attributes.h" #include "absl/base/config.h" +#include "absl/base/nullability.h" #include "absl/strings/internal/str_format/arg.h" // IWYU pragma: export #include "absl/strings/internal/str_format/bind.h" // IWYU pragma: export #include "absl/strings/internal/str_format/checker.h" // IWYU pragma: export @@ -110,7 +111,8 @@ class UntypedFormatSpec { explicit UntypedFormatSpec(string_view s) : spec_(s) {} protected: - explicit UntypedFormatSpec(const str_format_internal::ParsedFormatBase* pc) + explicit UntypedFormatSpec( + absl::Nonnull<const str_format_internal::ParsedFormatBase*> pc) : spec_(pc) {} private: @@ -150,7 +152,7 @@ str_format_internal::StreamedWrapper<T> FormatStreamed(const T& v) { // EXPECT_EQ(8, n); class FormatCountCapture { public: - explicit FormatCountCapture(int* p) : p_(p) {} + explicit FormatCountCapture(absl::Nonnull<int*> p) : p_(p) {} private: // FormatCountCaptureHelper is used to define FormatConvertImpl() for this @@ -159,8 +161,8 @@ class FormatCountCapture { // Unused() is here because of the false positive from -Wunused-private-field // p_ is used in the templated function of the friend FormatCountCaptureHelper // class. - int* Unused() { return p_; } - int* p_; + absl::Nonnull<int*> Unused() { return p_; } + absl::Nonnull<int*> p_; }; // FormatSpec @@ -375,7 +377,7 @@ ABSL_MUST_USE_RESULT std::string StrFormat(const FormatSpec<Args...>& format, // std::string orig("For example PI is approximately "); // std::cout << StrAppendFormat(&orig, "%12.6f", 3.14); template <typename... Args> -std::string& StrAppendFormat(std::string* dst, +std::string& StrAppendFormat(absl::Nonnull<std::string*> dst, const FormatSpec<Args...>& format, const Args&... args) { return str_format_internal::AppendPack( @@ -435,7 +437,7 @@ int PrintF(const FormatSpec<Args...>& format, const Args&... args) { // Outputs: "The capital of Mongolia is Ulaanbaatar" // template <typename... Args> -int FPrintF(std::FILE* output, const FormatSpec<Args...>& format, +int FPrintF(absl::Nonnull<std::FILE*> output, const FormatSpec<Args...>& format, const Args&... args) { return str_format_internal::FprintF( output, str_format_internal::UntypedFormatSpecImpl::Extract(format), @@ -464,8 +466,8 @@ int FPrintF(std::FILE* output, const FormatSpec<Args...>& format, // Post-condition: output == "The capital of Mongolia is Ulaanbaatar" // template <typename... Args> -int SNPrintF(char* output, std::size_t size, const FormatSpec<Args...>& format, - const Args&... args) { +int SNPrintF(absl::Nonnull<char*> output, std::size_t size, + const FormatSpec<Args...>& format, const Args&... args) { return str_format_internal::SnprintF( output, size, str_format_internal::UntypedFormatSpecImpl::Extract(format), {str_format_internal::FormatArgImpl(args)...}); @@ -498,7 +500,7 @@ class FormatRawSink { template <typename T, typename = typename std::enable_if<std::is_constructible< str_format_internal::FormatRawSinkImpl, T*>::value>::type> - FormatRawSink(T* raw) // NOLINT + FormatRawSink(absl::Nonnull<T*> raw) // NOLINT : sink_(raw) {} private: @@ -855,14 +857,16 @@ class FormatSink { } // Support `absl::Format(&sink, format, args...)`. - friend void AbslFormatFlush(FormatSink* sink, absl::string_view v) { + friend void AbslFormatFlush(absl::Nonnull<FormatSink*> sink, + absl::string_view v) { sink->Append(v); } private: friend str_format_internal::FormatSinkImpl; - explicit FormatSink(str_format_internal::FormatSinkImpl* s) : sink_(s) {} - str_format_internal::FormatSinkImpl* sink_; + explicit FormatSink(absl::Nonnull<str_format_internal::FormatSinkImpl*> s) + : sink_(s) {} + absl::Nonnull<str_format_internal::FormatSinkImpl*> sink_; }; // FormatConvertResult diff --git a/absl/strings/str_replace.cc b/absl/strings/str_replace.cc index 9ce49e56..a7ab52fe 100644 --- a/absl/strings/str_replace.cc +++ b/absl/strings/str_replace.cc @@ -21,6 +21,7 @@ #include <vector> #include "absl/base/config.h" +#include "absl/base/nullability.h" #include "absl/strings/str_cat.h" #include "absl/strings/string_view.h" @@ -36,8 +37,8 @@ using FixedMapping = // occurred. int ApplySubstitutions( absl::string_view s, - std::vector<strings_internal::ViableSubstitution>* subs_ptr, - std::string* result_ptr) { + absl::Nonnull<std::vector<strings_internal::ViableSubstitution>*> subs_ptr, + absl::Nonnull<std::string*> result_ptr) { auto& subs = *subs_ptr; int substitutions = 0; size_t pos = 0; @@ -82,7 +83,7 @@ std::string StrReplaceAll(absl::string_view s, } int StrReplaceAll(strings_internal::FixedMapping replacements, - std::string* target) { + absl::Nonnull<std::string*> target) { return StrReplaceAll<strings_internal::FixedMapping>(replacements, target); } diff --git a/absl/strings/str_replace.h b/absl/strings/str_replace.h index 273c7077..e77ced3e 100644 --- a/absl/strings/str_replace.h +++ b/absl/strings/str_replace.h @@ -43,6 +43,7 @@ #include <vector> #include "absl/base/attributes.h" +#include "absl/base/nullability.h" #include "absl/strings/string_view.h" namespace absl { @@ -113,7 +114,7 @@ std::string StrReplaceAll(absl::string_view s, int StrReplaceAll( std::initializer_list<std::pair<absl::string_view, absl::string_view>> replacements, - std::string* target); + absl::Nonnull<std::string*> target); // Overload of `StrReplaceAll()` to replace patterns within a given output // string *in place* with replacements provided within a container of key/value @@ -128,7 +129,8 @@ int StrReplaceAll( // EXPECT_EQ(count, 2); // EXPECT_EQ("if (ptr < &foo)", s); template <typename StrToStrMapping> -int StrReplaceAll(const StrToStrMapping& replacements, std::string* target); +int StrReplaceAll(const StrToStrMapping& replacements, + absl::Nonnull<std::string*> target); // Implementation details only, past this point. namespace strings_internal { @@ -185,8 +187,8 @@ std::vector<ViableSubstitution> FindSubstitutions( } int ApplySubstitutions(absl::string_view s, - std::vector<ViableSubstitution>* subs_ptr, - std::string* result_ptr); + absl::Nonnull<std::vector<ViableSubstitution>*> subs_ptr, + absl::Nonnull<std::string*> result_ptr); } // namespace strings_internal @@ -201,7 +203,8 @@ std::string StrReplaceAll(absl::string_view s, } template <typename StrToStrMapping> -int StrReplaceAll(const StrToStrMapping& replacements, std::string* target) { +int StrReplaceAll(const StrToStrMapping& replacements, + absl::Nonnull<std::string*> target) { auto subs = strings_internal::FindSubstitutions(*target, replacements); if (subs.empty()) return 0; diff --git a/absl/strings/string_view.cc b/absl/strings/string_view.cc index 1ee468c8..0500ef5c 100644 --- a/absl/strings/string_view.cc +++ b/absl/strings/string_view.cc @@ -21,6 +21,8 @@ #include <cstring> #include <ostream> +#include "absl/base/nullability.h" + namespace absl { ABSL_NAMESPACE_BEGIN @@ -28,8 +30,10 @@ namespace { // This is significantly faster for case-sensitive matches with very // few possible matches. -const char* memmatch(const char* phaystack, size_t haylen, const char* pneedle, - size_t neelen) { +absl::Nullable<const char*> memmatch(absl::Nullable<const char*> phaystack, + size_t haylen, + absl::Nullable<const char*> pneedle, + size_t neelen) { if (0 == neelen) { return phaystack; // even if haylen is 0 } diff --git a/absl/strings/string_view.h b/absl/strings/string_view.h index f88b05b6..04ca0a38 100644 --- a/absl/strings/string_view.h +++ b/absl/strings/string_view.h @@ -37,6 +37,7 @@ #include <string> #include "absl/base/attributes.h" +#include "absl/base/nullability.h" #include "absl/base/config.h" #include "absl/base/internal/throw_delegate.h" #include "absl/base/macros.h" @@ -162,11 +163,11 @@ class string_view { public: using traits_type = std::char_traits<char>; using value_type = char; - using pointer = char*; - using const_pointer = const char*; + using pointer = absl::Nullable<char*>; + using const_pointer = absl::Nullable<const char*>; using reference = char&; using const_reference = const char&; - using const_iterator = const char*; + using const_iterator = absl::Nullable<const char*>; using iterator = const_iterator; using const_reverse_iterator = std::reverse_iterator<const_iterator>; using reverse_iterator = const_reverse_iterator; @@ -194,11 +195,12 @@ class string_view { // accepting possibly null strings, use `absl::NullSafeStringView(str)` // instead (see below). // The length check is skipped since it is unnecessary and causes code bloat. - constexpr string_view(const char* str) // NOLINT(runtime/explicit) + constexpr string_view( // NOLINT(runtime/explicit) + absl::Nonnull<const char*> str) : ptr_(str), length_(str ? StrlenInternal(str) : 0) {} // Implicit constructor of a `string_view` from a `const char*` and length. - constexpr string_view(const char* data, size_type len) + constexpr string_view(absl::Nullable<const char*> data, size_type len) : ptr_(data), length_(CheckLengthInternal(len)) {} // NOTE: Harmlessly omitted to work around gdb bug. @@ -427,18 +429,21 @@ class string_view { // Overload of `string_view::compare()` for comparing a `string_view` and a // a different C-style string `s`. - constexpr int compare(const char* s) const { return compare(string_view(s)); } + constexpr int compare(absl::Nonnull<const char*> s) const { + return compare(string_view(s)); + } // Overload of `string_view::compare()` for comparing a substring of the // `string_view` and a different string C-style string `s`. - constexpr int compare(size_type pos1, size_type count1, const char* s) const { + constexpr int compare(size_type pos1, size_type count1, + absl::Nonnull<const char*> s) const { return substr(pos1, count1).compare(string_view(s)); } // Overload of `string_view::compare()` for comparing a substring of the // `string_view` and a substring of a different C-style string `s`. - constexpr int compare(size_type pos1, size_type count1, const char* s, - size_type count2) const { + constexpr int compare(size_type pos1, size_type count1, + absl::Nonnull<const char*> s, size_type count2) const { return substr(pos1, count1).compare(string_view(s, count2)); } @@ -457,13 +462,14 @@ class string_view { // Overload of `string_view::find()` for finding a substring of a different // C-style string `s` within the `string_view`. - size_type find(const char* s, size_type pos, size_type count) const { + size_type find(absl::Nonnull<const char*> s, size_type pos, + size_type count) const { return find(string_view(s, count), pos); } // Overload of `string_view::find()` for finding a different C-style string // `s` within the `string_view`. - size_type find(const char* s, size_type pos = 0) const { + size_type find(absl::Nonnull<const char *> s, size_type pos = 0) const { return find(string_view(s), pos); } @@ -480,13 +486,14 @@ class string_view { // Overload of `string_view::rfind()` for finding a substring of a different // C-style string `s` within the `string_view`. - size_type rfind(const char* s, size_type pos, size_type count) const { + size_type rfind(absl::Nonnull<const char*> s, size_type pos, + size_type count) const { return rfind(string_view(s, count), pos); } // Overload of `string_view::rfind()` for finding a different C-style string // `s` within the `string_view`. - size_type rfind(const char* s, size_type pos = npos) const { + size_type rfind(absl::Nonnull<const char*> s, size_type pos = npos) const { return rfind(string_view(s), pos); } @@ -505,14 +512,15 @@ class string_view { // Overload of `string_view::find_first_of()` for finding a substring of a // different C-style string `s` within the `string_view`. - size_type find_first_of(const char* s, size_type pos, + size_type find_first_of(absl::Nonnull<const char*> s, size_type pos, size_type count) const { return find_first_of(string_view(s, count), pos); } // Overload of `string_view::find_first_of()` for finding a different C-style // string `s` within the `string_view`. - size_type find_first_of(const char* s, size_type pos = 0) const { + size_type find_first_of(absl::Nonnull<const char*> s, + size_type pos = 0) const { return find_first_of(string_view(s), pos); } @@ -531,13 +539,15 @@ class string_view { // Overload of `string_view::find_last_of()` for finding a substring of a // different C-style string `s` within the `string_view`. - size_type find_last_of(const char* s, size_type pos, size_type count) const { + size_type find_last_of(absl::Nonnull<const char*> s, size_type pos, + size_type count) const { return find_last_of(string_view(s, count), pos); } // Overload of `string_view::find_last_of()` for finding a different C-style // string `s` within the `string_view`. - size_type find_last_of(const char* s, size_type pos = npos) const { + size_type find_last_of(absl::Nonnull<const char*> s, + size_type pos = npos) const { return find_last_of(string_view(s), pos); } @@ -554,14 +564,15 @@ class string_view { // Overload of `string_view::find_first_not_of()` for finding a substring of a // different C-style string `s` within the `string_view`. - size_type find_first_not_of(const char* s, size_type pos, + size_type find_first_not_of(absl::Nonnull<const char*> s, size_type pos, size_type count) const { return find_first_not_of(string_view(s, count), pos); } // Overload of `string_view::find_first_not_of()` for finding a different // C-style string `s` within the `string_view`. - size_type find_first_not_of(const char* s, size_type pos = 0) const { + size_type find_first_not_of(absl::Nonnull<const char*> s, + size_type pos = 0) const { return find_first_not_of(string_view(s), pos); } @@ -579,14 +590,15 @@ class string_view { // Overload of `string_view::find_last_not_of()` for finding a substring of a // different C-style string `s` within the `string_view`. - size_type find_last_not_of(const char* s, size_type pos, + size_type find_last_not_of(absl::Nonnull<const char*> s, size_type pos, size_type count) const { return find_last_not_of(string_view(s, count), pos); } // Overload of `string_view::find_last_not_of()` for finding a different // C-style string `s` within the `string_view`. - size_type find_last_not_of(const char* s, size_type pos = npos) const { + size_type find_last_not_of(absl::Nonnull<const char*> s, + size_type pos = npos) const { return find_last_not_of(string_view(s), pos); } @@ -646,7 +658,8 @@ class string_view { // The constructor from std::string delegates to this constructor. // See the comment on that constructor for the rationale. struct SkipCheckLengthTag {}; - string_view(const char* data, size_type len, SkipCheckLengthTag) noexcept + string_view(absl::Nullable<const char*> data, size_type len, + SkipCheckLengthTag) noexcept : ptr_(data), length_(len) {} static constexpr size_type kMaxSize = @@ -656,7 +669,7 @@ class string_view { return ABSL_HARDENING_ASSERT(len <= kMaxSize), len; } - static constexpr size_type StrlenInternal(const char* str) { + static constexpr size_type StrlenInternal(absl::Nonnull<const char*> str) { #if defined(_MSC_VER) && _MSC_VER >= 1910 && !defined(__clang__) // MSVC 2017+ can evaluate this at compile-time. const char* begin = str; @@ -685,7 +698,7 @@ class string_view { : (compare_result < 0 ? -1 : 1); } - const char* ptr_; + absl::Nullable<const char*> ptr_; size_type length_; }; @@ -746,7 +759,7 @@ inline string_view ClippedSubstr(string_view s, size_t pos, // Creates an `absl::string_view` from a pointer `p` even if it's null-valued. // This function should be used where an `absl::string_view` can be created from // a possibly-null pointer. -constexpr string_view NullSafeStringView(const char* p) { +constexpr string_view NullSafeStringView(absl::Nullable<const char*> p) { return p ? string_view(p) : string_view(); } diff --git a/absl/strings/strip.h b/absl/strings/strip.h index 341e66fc..e3cda5ba 100644 --- a/absl/strings/strip.h +++ b/absl/strings/strip.h @@ -25,6 +25,7 @@ #include <string> #include "absl/base/macros.h" +#include "absl/base/nullability.h" #include "absl/strings/ascii.h" #include "absl/strings/match.h" #include "absl/strings/string_view.h" @@ -43,7 +44,8 @@ ABSL_NAMESPACE_BEGIN // absl::string_view input("abc"); // EXPECT_TRUE(absl::ConsumePrefix(&input, "a")); // EXPECT_EQ(input, "bc"); -inline bool ConsumePrefix(absl::string_view* str, absl::string_view expected) { +inline bool ConsumePrefix(absl::Nonnull<absl::string_view*> str, + absl::string_view expected) { if (!absl::StartsWith(*str, expected)) return false; str->remove_prefix(expected.size()); return true; @@ -59,7 +61,8 @@ inline bool ConsumePrefix(absl::string_view* str, absl::string_view expected) { // absl::string_view input("abcdef"); // EXPECT_TRUE(absl::ConsumeSuffix(&input, "def")); // EXPECT_EQ(input, "abc"); -inline bool ConsumeSuffix(absl::string_view* str, absl::string_view expected) { +inline bool ConsumeSuffix(absl::Nonnull<absl::string_view*> str, + absl::string_view expected) { if (!absl::EndsWith(*str, expected)) return false; str->remove_suffix(expected.size()); return true; diff --git a/absl/strings/substitute.cc b/absl/strings/substitute.cc index 354c070d..dd32c75f 100644 --- a/absl/strings/substitute.cc +++ b/absl/strings/substitute.cc @@ -22,6 +22,7 @@ #include "absl/base/config.h" #include "absl/base/internal/raw_logging.h" +#include "absl/base/nullability.h" #include "absl/strings/ascii.h" #include "absl/strings/escaping.h" #include "absl/strings/internal/resize_uninitialized.h" @@ -33,9 +34,9 @@ namespace absl { ABSL_NAMESPACE_BEGIN namespace substitute_internal { -void SubstituteAndAppendArray(std::string* output, absl::string_view format, - const absl::string_view* args_array, - size_t num_args) { +void SubstituteAndAppendArray( + absl::Nonnull<std::string*> output, absl::string_view format, + absl::Nullable<const absl::string_view*> args_array, size_t num_args) { // Determine total size needed. size_t size = 0; for (size_t i = 0; i < format.size(); i++) { @@ -104,7 +105,7 @@ void SubstituteAndAppendArray(std::string* output, absl::string_view format, assert(target == output->data() + output->size()); } -Arg::Arg(const void* value) { +Arg::Arg(absl::Nullable<const void*> value) { static_assert(sizeof(scratch_) >= sizeof(value) * 2 + 2, "fix sizeof(scratch_)"); if (value == nullptr) { diff --git a/absl/strings/substitute.h b/absl/strings/substitute.h index 0d6cb7c7..6c7cba4b 100644 --- a/absl/strings/substitute.h +++ b/absl/strings/substitute.h @@ -78,6 +78,7 @@ #include <vector> #include "absl/base/macros.h" +#include "absl/base/nullability.h" #include "absl/base/port.h" #include "absl/strings/ascii.h" #include "absl/strings/escaping.h" @@ -105,7 +106,7 @@ class Arg { // Overloads for string-y things // // Explicitly overload `const char*` so the compiler doesn't cast to `bool`. - Arg(const char* value) // NOLINT(google-explicit-constructor) + Arg(absl::Nullable<const char*> value) // NOLINT(google-explicit-constructor) : piece_(absl::NullSafeStringView(value)) {} template <typename Allocator> Arg( // NOLINT @@ -197,7 +198,8 @@ class Arg { // `void*` values, with the exception of `char*`, are printed as // "0x<hex value>". However, in the case of `nullptr`, "NULL" is printed. - Arg(const void* value); // NOLINT(google-explicit-constructor) + Arg( // NOLINT(google-explicit-constructor) + absl::Nullable<const void*> value); // Normal enums are already handled by the integer formatters. // This overload matches only scoped enums. @@ -220,12 +222,12 @@ class Arg { // Internal helper function. Don't call this from outside this implementation. // This interface may change without notice. -void SubstituteAndAppendArray(std::string* output, absl::string_view format, - const absl::string_view* args_array, - size_t num_args); +void SubstituteAndAppendArray( + absl::Nonnull<std::string*> output, absl::string_view format, + absl::Nullable<const absl::string_view*> args_array, size_t num_args); #if defined(ABSL_BAD_CALL_IF) -constexpr int CalculateOneBit(const char* format) { +constexpr int CalculateOneBit(absl::Nonnull<const char*> format) { // Returns: // * 2^N for '$N' when N is in [0-9] // * 0 for correct '$' escaping: '$$'. @@ -234,11 +236,11 @@ constexpr int CalculateOneBit(const char* format) { : (1 << (*format - '0')); } -constexpr const char* SkipNumber(const char* format) { +constexpr const char* SkipNumber(absl::Nonnull<const char*> format) { return !*format ? format : (format + 1); } -constexpr int PlaceholderBitmask(const char* format) { +constexpr int PlaceholderBitmask(absl::Nonnull<const char*> format) { return !*format ? 0 : *format != '$' ? PlaceholderBitmask(format + 1) @@ -271,18 +273,21 @@ constexpr int PlaceholderBitmask(const char* format) { // absl::SubstituteAndAppend(boilerplate, format, args...); // } // -inline void SubstituteAndAppend(std::string* output, absl::string_view format) { +inline void SubstituteAndAppend(absl::Nonnull<std::string*> output, + absl::string_view format) { substitute_internal::SubstituteAndAppendArray(output, format, nullptr, 0); } -inline void SubstituteAndAppend(std::string* output, absl::string_view format, +inline void SubstituteAndAppend(absl::Nonnull<std::string*> output, + absl::string_view format, const substitute_internal::Arg& a0) { const absl::string_view args[] = {a0.piece()}; substitute_internal::SubstituteAndAppendArray(output, format, args, ABSL_ARRAYSIZE(args)); } -inline void SubstituteAndAppend(std::string* output, absl::string_view format, +inline void SubstituteAndAppend(absl::Nonnull<std::string*> output, + absl::string_view format, const substitute_internal::Arg& a0, const substitute_internal::Arg& a1) { const absl::string_view args[] = {a0.piece(), a1.piece()}; @@ -290,7 +295,8 @@ inline void SubstituteAndAppend(std::string* output, absl::string_view format, ABSL_ARRAYSIZE(args)); } -inline void SubstituteAndAppend(std::string* output, absl::string_view format, +inline void SubstituteAndAppend(absl::Nonnull<std::string*> output, + absl::string_view format, const substitute_internal::Arg& a0, const substitute_internal::Arg& a1, const substitute_internal::Arg& a2) { @@ -299,7 +305,8 @@ inline void SubstituteAndAppend(std::string* output, absl::string_view format, ABSL_ARRAYSIZE(args)); } -inline void SubstituteAndAppend(std::string* output, absl::string_view format, +inline void SubstituteAndAppend(absl::Nonnull<std::string*> output, + absl::string_view format, const substitute_internal::Arg& a0, const substitute_internal::Arg& a1, const substitute_internal::Arg& a2, @@ -310,7 +317,8 @@ inline void SubstituteAndAppend(std::string* output, absl::string_view format, ABSL_ARRAYSIZE(args)); } -inline void SubstituteAndAppend(std::string* output, absl::string_view format, +inline void SubstituteAndAppend(absl::Nonnull<std::string*> output, + absl::string_view format, const substitute_internal::Arg& a0, const substitute_internal::Arg& a1, const substitute_internal::Arg& a2, @@ -322,27 +330,23 @@ inline void SubstituteAndAppend(std::string* output, absl::string_view format, ABSL_ARRAYSIZE(args)); } -inline void SubstituteAndAppend(std::string* output, absl::string_view format, - const substitute_internal::Arg& a0, - const substitute_internal::Arg& a1, - const substitute_internal::Arg& a2, - const substitute_internal::Arg& a3, - const substitute_internal::Arg& a4, - const substitute_internal::Arg& a5) { +inline void SubstituteAndAppend( + absl::Nonnull<std::string*> output, absl::string_view format, + const substitute_internal::Arg& a0, const substitute_internal::Arg& a1, + const substitute_internal::Arg& a2, const substitute_internal::Arg& a3, + const substitute_internal::Arg& a4, const substitute_internal::Arg& a5) { const absl::string_view args[] = {a0.piece(), a1.piece(), a2.piece(), a3.piece(), a4.piece(), a5.piece()}; substitute_internal::SubstituteAndAppendArray(output, format, args, ABSL_ARRAYSIZE(args)); } -inline void SubstituteAndAppend(std::string* output, absl::string_view format, - const substitute_internal::Arg& a0, - const substitute_internal::Arg& a1, - const substitute_internal::Arg& a2, - const substitute_internal::Arg& a3, - const substitute_internal::Arg& a4, - const substitute_internal::Arg& a5, - const substitute_internal::Arg& a6) { +inline void SubstituteAndAppend( + absl::Nonnull<std::string*> output, absl::string_view format, + const substitute_internal::Arg& a0, const substitute_internal::Arg& a1, + const substitute_internal::Arg& a2, const substitute_internal::Arg& a3, + const substitute_internal::Arg& a4, const substitute_internal::Arg& a5, + const substitute_internal::Arg& a6) { const absl::string_view args[] = {a0.piece(), a1.piece(), a2.piece(), a3.piece(), a4.piece(), a5.piece(), a6.piece()}; @@ -351,7 +355,7 @@ inline void SubstituteAndAppend(std::string* output, absl::string_view format, } inline void SubstituteAndAppend( - std::string* output, absl::string_view format, + absl::Nonnull<std::string*> output, absl::string_view format, const substitute_internal::Arg& a0, const substitute_internal::Arg& a1, const substitute_internal::Arg& a2, const substitute_internal::Arg& a3, const substitute_internal::Arg& a4, const substitute_internal::Arg& a5, @@ -364,7 +368,7 @@ inline void SubstituteAndAppend( } inline void SubstituteAndAppend( - std::string* output, absl::string_view format, + absl::Nonnull<std::string*> output, absl::string_view format, const substitute_internal::Arg& a0, const substitute_internal::Arg& a1, const substitute_internal::Arg& a2, const substitute_internal::Arg& a3, const substitute_internal::Arg& a4, const substitute_internal::Arg& a5, @@ -378,7 +382,7 @@ inline void SubstituteAndAppend( } inline void SubstituteAndAppend( - std::string* output, absl::string_view format, + absl::Nonnull<std::string*> output, absl::string_view format, const substitute_internal::Arg& a0, const substitute_internal::Arg& a1, const substitute_internal::Arg& a2, const substitute_internal::Arg& a3, const substitute_internal::Arg& a4, const substitute_internal::Arg& a5, @@ -394,14 +398,16 @@ inline void SubstituteAndAppend( #if defined(ABSL_BAD_CALL_IF) // This body of functions catches cases where the number of placeholders // doesn't match the number of data arguments. -void SubstituteAndAppend(std::string* output, const char* format) +void SubstituteAndAppend(absl::Nonnull<std::string*> output, + absl::Nonnull<const char*> format) ABSL_BAD_CALL_IF( substitute_internal::PlaceholderBitmask(format) != 0, "There were no substitution arguments " "but this format string either has a $[0-9] in it or contains " "an unescaped $ character (use $$ instead)"); -void SubstituteAndAppend(std::string* output, const char* format, +void SubstituteAndAppend(absl::Nonnull<std::string*> output, + absl::Nonnull<const char*> format, const substitute_internal::Arg& a0) ABSL_BAD_CALL_IF(substitute_internal::PlaceholderBitmask(format) != 1, "There was 1 substitution argument given, but " @@ -409,7 +415,8 @@ void SubstituteAndAppend(std::string* output, const char* format, "one of $1-$9, or contains an unescaped $ character (use " "$$ instead)"); -void SubstituteAndAppend(std::string* output, const char* format, +void SubstituteAndAppend(absl::Nonnull<std::string*> output, + absl::Nonnull<const char*> format, const substitute_internal::Arg& a0, const substitute_internal::Arg& a1) ABSL_BAD_CALL_IF( @@ -418,7 +425,8 @@ void SubstituteAndAppend(std::string* output, const char* format, "missing its $0/$1, contains one of $2-$9, or contains an " "unescaped $ character (use $$ instead)"); -void SubstituteAndAppend(std::string* output, const char* format, +void SubstituteAndAppend(absl::Nonnull<std::string*> output, + absl::Nonnull<const char*> format, const substitute_internal::Arg& a0, const substitute_internal::Arg& a1, const substitute_internal::Arg& a2) @@ -428,7 +436,8 @@ void SubstituteAndAppend(std::string* output, const char* format, "this format string is missing its $0/$1/$2, contains one of " "$3-$9, or contains an unescaped $ character (use $$ instead)"); -void SubstituteAndAppend(std::string* output, const char* format, +void SubstituteAndAppend(absl::Nonnull<std::string*> output, + absl::Nonnull<const char*> format, const substitute_internal::Arg& a0, const substitute_internal::Arg& a1, const substitute_internal::Arg& a2, @@ -439,7 +448,8 @@ void SubstituteAndAppend(std::string* output, const char* format, "this format string is missing its $0-$3, contains one of " "$4-$9, or contains an unescaped $ character (use $$ instead)"); -void SubstituteAndAppend(std::string* output, const char* format, +void SubstituteAndAppend(absl::Nonnull<std::string*> output, + absl::Nonnull<const char*> format, const substitute_internal::Arg& a0, const substitute_internal::Arg& a1, const substitute_internal::Arg& a2, @@ -451,13 +461,11 @@ void SubstituteAndAppend(std::string* output, const char* format, "this format string is missing its $0-$4, contains one of " "$5-$9, or contains an unescaped $ character (use $$ instead)"); -void SubstituteAndAppend(std::string* output, const char* format, - const substitute_internal::Arg& a0, - const substitute_internal::Arg& a1, - const substitute_internal::Arg& a2, - const substitute_internal::Arg& a3, - const substitute_internal::Arg& a4, - const substitute_internal::Arg& a5) +void SubstituteAndAppend( + absl::Nonnull<std::string*> output, absl::Nonnull<const char*> format, + const substitute_internal::Arg& a0, const substitute_internal::Arg& a1, + const substitute_internal::Arg& a2, const substitute_internal::Arg& a3, + const substitute_internal::Arg& a4, const substitute_internal::Arg& a5) ABSL_BAD_CALL_IF( substitute_internal::PlaceholderBitmask(format) != 63, "There were 6 substitution arguments given, but " @@ -465,10 +473,11 @@ void SubstituteAndAppend(std::string* output, const char* format, "$6-$9, or contains an unescaped $ character (use $$ instead)"); void SubstituteAndAppend( - std::string* output, const char* format, const substitute_internal::Arg& a0, - const substitute_internal::Arg& a1, const substitute_internal::Arg& a2, - const substitute_internal::Arg& a3, const substitute_internal::Arg& a4, - const substitute_internal::Arg& a5, const substitute_internal::Arg& a6) + absl::Nonnull<std::string*> output, absl::Nonnull<const char*> format, + const substitute_internal::Arg& a0, const substitute_internal::Arg& a1, + const substitute_internal::Arg& a2, const substitute_internal::Arg& a3, + const substitute_internal::Arg& a4, const substitute_internal::Arg& a5, + const substitute_internal::Arg& a6) ABSL_BAD_CALL_IF( substitute_internal::PlaceholderBitmask(format) != 127, "There were 7 substitution arguments given, but " @@ -476,11 +485,11 @@ void SubstituteAndAppend( "$7-$9, or contains an unescaped $ character (use $$ instead)"); void SubstituteAndAppend( - std::string* output, const char* format, const substitute_internal::Arg& a0, - const substitute_internal::Arg& a1, const substitute_internal::Arg& a2, - const substitute_internal::Arg& a3, const substitute_internal::Arg& a4, - const substitute_internal::Arg& a5, const substitute_internal::Arg& a6, - const substitute_internal::Arg& a7) + absl::Nonnull<std::string*> output, absl::Nonnull<const char*> format, + const substitute_internal::Arg& a0, const substitute_internal::Arg& a1, + const substitute_internal::Arg& a2, const substitute_internal::Arg& a3, + const substitute_internal::Arg& a4, const substitute_internal::Arg& a5, + const substitute_internal::Arg& a6, const substitute_internal::Arg& a7) ABSL_BAD_CALL_IF( substitute_internal::PlaceholderBitmask(format) != 255, "There were 8 substitution arguments given, but " @@ -488,11 +497,12 @@ void SubstituteAndAppend( "$8-$9, or contains an unescaped $ character (use $$ instead)"); void SubstituteAndAppend( - std::string* output, const char* format, const substitute_internal::Arg& a0, - const substitute_internal::Arg& a1, const substitute_internal::Arg& a2, - const substitute_internal::Arg& a3, const substitute_internal::Arg& a4, - const substitute_internal::Arg& a5, const substitute_internal::Arg& a6, - const substitute_internal::Arg& a7, const substitute_internal::Arg& a8) + absl::Nonnull<std::string*> output, absl::Nonnull<const char*> format, + const substitute_internal::Arg& a0, const substitute_internal::Arg& a1, + const substitute_internal::Arg& a2, const substitute_internal::Arg& a3, + const substitute_internal::Arg& a4, const substitute_internal::Arg& a5, + const substitute_internal::Arg& a6, const substitute_internal::Arg& a7, + const substitute_internal::Arg& a8) ABSL_BAD_CALL_IF( substitute_internal::PlaceholderBitmask(format) != 511, "There were 9 substitution arguments given, but " @@ -500,12 +510,12 @@ void SubstituteAndAppend( "contains an unescaped $ character (use $$ instead)"); void SubstituteAndAppend( - std::string* output, const char* format, const substitute_internal::Arg& a0, - const substitute_internal::Arg& a1, const substitute_internal::Arg& a2, - const substitute_internal::Arg& a3, const substitute_internal::Arg& a4, - const substitute_internal::Arg& a5, const substitute_internal::Arg& a6, - const substitute_internal::Arg& a7, const substitute_internal::Arg& a8, - const substitute_internal::Arg& a9) + absl::Nonnull<std::string*> output, absl::Nonnull<const char*> format, + const substitute_internal::Arg& a0, const substitute_internal::Arg& a1, + const substitute_internal::Arg& a2, const substitute_internal::Arg& a3, + const substitute_internal::Arg& a4, const substitute_internal::Arg& a5, + const substitute_internal::Arg& a6, const substitute_internal::Arg& a7, + const substitute_internal::Arg& a8, const substitute_internal::Arg& a9) ABSL_BAD_CALL_IF( substitute_internal::PlaceholderBitmask(format) != 1023, "There were 10 substitution arguments given, but this " @@ -633,20 +643,22 @@ ABSL_MUST_USE_RESULT inline std::string Substitute( #if defined(ABSL_BAD_CALL_IF) // This body of functions catches cases where the number of placeholders // doesn't match the number of data arguments. -std::string Substitute(const char* format) +std::string Substitute(absl::Nonnull<const char*> format) ABSL_BAD_CALL_IF(substitute_internal::PlaceholderBitmask(format) != 0, "There were no substitution arguments " "but this format string either has a $[0-9] in it or " "contains an unescaped $ character (use $$ instead)"); -std::string Substitute(const char* format, const substitute_internal::Arg& a0) +std::string Substitute(absl::Nonnull<const char*> format, + const substitute_internal::Arg& a0) ABSL_BAD_CALL_IF( substitute_internal::PlaceholderBitmask(format) != 1, "There was 1 substitution argument given, but " "this format string is missing its $0, contains one of $1-$9, " "or contains an unescaped $ character (use $$ instead)"); -std::string Substitute(const char* format, const substitute_internal::Arg& a0, +std::string Substitute(absl::Nonnull<const char*> format, + const substitute_internal::Arg& a0, const substitute_internal::Arg& a1) ABSL_BAD_CALL_IF( substitute_internal::PlaceholderBitmask(format) != 3, @@ -654,7 +666,8 @@ std::string Substitute(const char* format, const substitute_internal::Arg& a0, "this format string is missing its $0/$1, contains one of " "$2-$9, or contains an unescaped $ character (use $$ instead)"); -std::string Substitute(const char* format, const substitute_internal::Arg& a0, +std::string Substitute(absl::Nonnull<const char*> format, + const substitute_internal::Arg& a0, const substitute_internal::Arg& a1, const substitute_internal::Arg& a2) ABSL_BAD_CALL_IF( @@ -663,7 +676,8 @@ std::string Substitute(const char* format, const substitute_internal::Arg& a0, "this format string is missing its $0/$1/$2, contains one of " "$3-$9, or contains an unescaped $ character (use $$ instead)"); -std::string Substitute(const char* format, const substitute_internal::Arg& a0, +std::string Substitute(absl::Nonnull<const char*> format, + const substitute_internal::Arg& a0, const substitute_internal::Arg& a1, const substitute_internal::Arg& a2, const substitute_internal::Arg& a3) @@ -673,7 +687,8 @@ std::string Substitute(const char* format, const substitute_internal::Arg& a0, "this format string is missing its $0-$3, contains one of " "$4-$9, or contains an unescaped $ character (use $$ instead)"); -std::string Substitute(const char* format, const substitute_internal::Arg& a0, +std::string Substitute(absl::Nonnull<const char*> format, + const substitute_internal::Arg& a0, const substitute_internal::Arg& a1, const substitute_internal::Arg& a2, const substitute_internal::Arg& a3, @@ -684,7 +699,8 @@ std::string Substitute(const char* format, const substitute_internal::Arg& a0, "this format string is missing its $0-$4, contains one of " "$5-$9, or contains an unescaped $ character (use $$ instead)"); -std::string Substitute(const char* format, const substitute_internal::Arg& a0, +std::string Substitute(absl::Nonnull<const char*> format, + const substitute_internal::Arg& a0, const substitute_internal::Arg& a1, const substitute_internal::Arg& a2, const substitute_internal::Arg& a3, @@ -696,27 +712,23 @@ std::string Substitute(const char* format, const substitute_internal::Arg& a0, "this format string is missing its $0-$5, contains one of " "$6-$9, or contains an unescaped $ character (use $$ instead)"); -std::string Substitute(const char* format, const substitute_internal::Arg& a0, - const substitute_internal::Arg& a1, - const substitute_internal::Arg& a2, - const substitute_internal::Arg& a3, - const substitute_internal::Arg& a4, - const substitute_internal::Arg& a5, - const substitute_internal::Arg& a6) +std::string Substitute( + absl::Nonnull<const char*> format, const substitute_internal::Arg& a0, + const substitute_internal::Arg& a1, const substitute_internal::Arg& a2, + const substitute_internal::Arg& a3, const substitute_internal::Arg& a4, + const substitute_internal::Arg& a5, const substitute_internal::Arg& a6) ABSL_BAD_CALL_IF( substitute_internal::PlaceholderBitmask(format) != 127, "There were 7 substitution arguments given, but " "this format string is missing its $0-$6, contains one of " "$7-$9, or contains an unescaped $ character (use $$ instead)"); -std::string Substitute(const char* format, const substitute_internal::Arg& a0, - const substitute_internal::Arg& a1, - const substitute_internal::Arg& a2, - const substitute_internal::Arg& a3, - const substitute_internal::Arg& a4, - const substitute_internal::Arg& a5, - const substitute_internal::Arg& a6, - const substitute_internal::Arg& a7) +std::string Substitute( + absl::Nonnull<const char*> format, const substitute_internal::Arg& a0, + const substitute_internal::Arg& a1, const substitute_internal::Arg& a2, + const substitute_internal::Arg& a3, const substitute_internal::Arg& a4, + const substitute_internal::Arg& a5, const substitute_internal::Arg& a6, + const substitute_internal::Arg& a7) ABSL_BAD_CALL_IF( substitute_internal::PlaceholderBitmask(format) != 255, "There were 8 substitution arguments given, but " @@ -724,7 +736,7 @@ std::string Substitute(const char* format, const substitute_internal::Arg& a0, "$8-$9, or contains an unescaped $ character (use $$ instead)"); std::string Substitute( - const char* format, const substitute_internal::Arg& a0, + absl::Nonnull<const char*> format, const substitute_internal::Arg& a0, const substitute_internal::Arg& a1, const substitute_internal::Arg& a2, const substitute_internal::Arg& a3, const substitute_internal::Arg& a4, const substitute_internal::Arg& a5, const substitute_internal::Arg& a6, @@ -736,7 +748,7 @@ std::string Substitute( "contains an unescaped $ character (use $$ instead)"); std::string Substitute( - const char* format, const substitute_internal::Arg& a0, + absl::Nonnull<const char*> format, const substitute_internal::Arg& a0, const substitute_internal::Arg& a1, const substitute_internal::Arg& a2, const substitute_internal::Arg& a3, const substitute_internal::Arg& a4, const substitute_internal::Arg& a5, const substitute_internal::Arg& a6, diff --git a/absl/types/BUILD.bazel b/absl/types/BUILD.bazel index 31a5daa2..ce8f605b 100644 --- a/absl/types/BUILD.bazel +++ b/absl/types/BUILD.bazel @@ -118,6 +118,7 @@ cc_library( deps = [ "//absl/algorithm", "//absl/base:core_headers", + "//absl/base:nullability", "//absl/base:throw_delegate", "//absl/meta:type_traits", ], @@ -154,6 +155,7 @@ cc_library( "//absl/base:base_internal", "//absl/base:config", "//absl/base:core_headers", + "//absl/base:nullability", "//absl/memory", "//absl/meta:type_traits", "//absl/utility", diff --git a/absl/types/CMakeLists.txt b/absl/types/CMakeLists.txt index 024c2c39..92b4ae49 100644 --- a/absl/types/CMakeLists.txt +++ b/absl/types/CMakeLists.txt @@ -115,6 +115,7 @@ absl_cc_library( DEPS absl::algorithm absl::core_headers + absl::nullability absl::throw_delegate absl::type_traits PUBLIC @@ -175,6 +176,7 @@ absl_cc_library( absl::config absl::core_headers absl::memory + absl::nullability absl::type_traits absl::utility PUBLIC diff --git a/absl/types/optional.h b/absl/types/optional.h index 0a8080dc..395fe62f 100644 --- a/absl/types/optional.h +++ b/absl/types/optional.h @@ -61,6 +61,7 @@ ABSL_NAMESPACE_END #include <utility> #include "absl/base/attributes.h" +#include "absl/base/nullability.h" #include "absl/base/internal/inline_variable.h" #include "absl/meta/type_traits.h" #include "absl/types/bad_optional_access.h" @@ -415,11 +416,11 @@ class optional : private optional_internal::optional_data<T>, // `optional` is empty, behavior is undefined. // // If you need myOpt->foo in constexpr, use (*myOpt).foo instead. - const T* operator->() const ABSL_ATTRIBUTE_LIFETIME_BOUND { + absl::Nonnull<const T*> operator->() const ABSL_ATTRIBUTE_LIFETIME_BOUND { ABSL_HARDENING_ASSERT(this->engaged_); return std::addressof(this->data_); } - T* operator->() ABSL_ATTRIBUTE_LIFETIME_BOUND { + absl::Nonnull<T*> operator->() ABSL_ATTRIBUTE_LIFETIME_BOUND { ABSL_HARDENING_ASSERT(this->engaged_); return std::addressof(this->data_); } diff --git a/absl/types/span.h b/absl/types/span.h index 70ed8eb6..7d1d0166 100644 --- a/absl/types/span.h +++ b/absl/types/span.h @@ -63,6 +63,7 @@ #include "absl/base/attributes.h" #include "absl/base/internal/throw_delegate.h" #include "absl/base/macros.h" +#include "absl/base/nullability.h" #include "absl/base/optimization.h" #include "absl/base/port.h" // TODO(strel): remove this include #include "absl/meta/type_traits.h" @@ -172,8 +173,8 @@ class Span { public: using element_type = T; using value_type = absl::remove_cv_t<T>; - using pointer = T*; - using const_pointer = const T*; + using pointer = absl::Nullable<T*>; + using const_pointer = absl::Nullable<const T*>; using reference = T&; using const_reference = const T&; using iterator = pointer; @@ -679,12 +680,12 @@ bool operator>=(Span<T> a, const U& b) { // } // template <int&... ExplicitArgumentBarrier, typename T> -constexpr Span<T> MakeSpan(T* ptr, size_t size) noexcept { +constexpr Span<T> MakeSpan(absl::Nullable<T*> ptr, size_t size) noexcept { return Span<T>(ptr, size); } template <int&... ExplicitArgumentBarrier, typename T> -Span<T> MakeSpan(T* begin, T* end) noexcept { +Span<T> MakeSpan(absl::Nullable<T*> begin, absl::Nullable<T*> end) noexcept { return ABSL_HARDENING_ASSERT(begin <= end), Span<T>(begin, static_cast<size_t>(end - begin)); } @@ -725,12 +726,14 @@ constexpr Span<T> MakeSpan(T (&array)[N]) noexcept { // ProcessInts(absl::MakeConstSpan(std::vector<int>{ 0, 0, 0 })); // template <int&... ExplicitArgumentBarrier, typename T> -constexpr Span<const T> MakeConstSpan(T* ptr, size_t size) noexcept { +constexpr Span<const T> MakeConstSpan(absl::Nullable<T*> ptr, + size_t size) noexcept { return Span<const T>(ptr, size); } template <int&... ExplicitArgumentBarrier, typename T> -Span<const T> MakeConstSpan(T* begin, T* end) noexcept { +Span<const T> MakeConstSpan(absl::Nullable<T*> begin, + absl::Nullable<T*> end) noexcept { return ABSL_HARDENING_ASSERT(begin <= end), Span<const T>(begin, end - begin); } |