@ -32,15 +32,16 @@
# define GOOGLE_PROTOBUF_ARENASTRING_H__
# include <algorithm>
# include <cstdint>
# include <string>
# include <type_traits>
# include <utility>
# include "absl/log/absl_check.h"
# include "google/protobuf/arena.h"
# include "google/protobuf/port.h"
# include "absl/strings/string_view.h"
# include "google/protobuf/explicitly_constructed.h"
# include "google/protobuf/port.h"
// must be last:
# include "google/protobuf/port_def.inc"
@ -94,7 +95,7 @@ class PROTOBUF_EXPORT LazyString {
const std : : string & Init ( ) const ;
} ;
class TaggedStringPtr {
class PROTOBUF_EXPORT TaggedStringPtr {
public :
// Bit flags qualifying string properties. We can use 2 bits as
// ptr_ is guaranteed and enforced to be aligned on 4 byte boundaries.
@ -193,13 +194,25 @@ class TaggedStringPtr {
// Returns true if the contained pointer is null, indicating some error.
// The Null value is only used during parsing for temporary values.
// A persisted ArenaStringPtr value is never null.
inline bool IsNull ( ) { return ptr_ = = nullptr ; }
inline bool IsNull ( ) const { return ptr_ = = nullptr ; }
// Returns a copy of this instance. In debug builds, the returned value may be
// a forced copy regardless if the current instance is a compile time default.
TaggedStringPtr Copy ( Arena * arena ) const ;
// Identical to the above `Copy` function except that in debug builds,
// `default_value` can be used to substitute an empty default with a
// hardened copy of the default value.
TaggedStringPtr Copy ( Arena * arena , const LazyString & default_value ) const ;
private :
static inline void assert_aligned ( const void * p ) {
ABSL_DCHECK_EQ ( reinterpret_cast < uintptr_t > ( p ) & kMask , 0UL ) ;
}
// Creates a heap or arena allocated copy of this instance.
TaggedStringPtr ForceCopy ( Arena * arena ) const ;
inline std : : string * TagAs ( Type type , std : : string * p ) {
ABSL_DCHECK ( p ! = nullptr ) ;
assert_aligned ( p ) ;
@ -234,11 +247,54 @@ static_assert(std::is_trivial<TaggedStringPtr>::value,
// See TaggedStringPtr for more information about the types of string values
// being held, and the mutable and ownership invariants for each type.
struct PROTOBUF_EXPORT ArenaStringPtr {
// Default constructor, leaves current instance uninitialized (does nothing)
ArenaStringPtr ( ) = default ;
// Constexpr constructor, initializes to a constexpr, empty string value.
constexpr ArenaStringPtr ( ExplicitlyConstructedArenaString * default_value ,
ConstantInitialized )
: tagged_ptr_ ( default_value ) { }
// Arena enabled constructor for strings without a default value.
// Initializes this instance to a constexpr, empty string value, unless debug
// hardening is enabled, in which case this instance will hold a forced copy.
explicit ArenaStringPtr ( Arena * arena )
: tagged_ptr_ ( & fixed_address_empty_string ) {
if ( DebugHardenStringValues ( ) ) {
Set ( absl : : string_view ( " " ) , arena ) ;
}
}
// Arena enabled constructor for strings with a non-empty default value.
// Initializes this instance to a constexpr, empty string value, unless debug
// hardening is enabled, in which case this instance will be forced to hold a
// forced copy of the value in `default_value`.
ArenaStringPtr ( Arena * arena , const LazyString & default_value )
: tagged_ptr_ ( & fixed_address_empty_string ) {
if ( DebugHardenStringValues ( ) ) {
Set ( absl : : string_view ( default_value . get ( ) ) , arena ) ;
}
}
// Arena enabled copy constructor for strings without a default value.
// This instance will be initialized with a copy of the value in `rhs`.
// If `rhs` holds a default (empty) value, then this instance will also be
// initialized with the default empty value, unless debug hardening is
// enabled, in which case this instance will be forced to hold a copy of
// an empty default value.
ArenaStringPtr ( Arena * arena , const ArenaStringPtr & rhs )
: tagged_ptr_ ( rhs . tagged_ptr_ . Copy ( arena ) ) { }
// Arena enabled copy constructor for strings with a non-empty default value.
// This instance will be initialized with a copy of the value in `rhs`.
// If `rhs` holds a default (empty) value, then this instance will also be
// initialized with the default empty value, unless debug hardening is
// enabled, in which case this instance will be forced to hold forced copy
// of the value in `default_value`.
ArenaStringPtr ( Arena * arena , const ArenaStringPtr & rhs ,
const LazyString & default_value )
: tagged_ptr_ ( rhs . tagged_ptr_ . Copy ( arena , default_value ) ) { }
// Called from generated code / reflection runtime only. Resets value to point
// to a default string pointer, with the semantics that this ArenaStringPtr
// does not own the pointed-to memory. Disregards initial value of ptr_ (so
@ -392,6 +448,27 @@ struct PROTOBUF_EXPORT ArenaStringPtr {
friend class EpsCopyInputStream ;
} ;
inline TaggedStringPtr TaggedStringPtr : : Copy ( Arena * arena ) const {
if ( DebugHardenStringValues ( ) ) {
// Harden by forcing an allocated string value.
return IsNull ( ) ? * this : ForceCopy ( arena ) ;
}
return IsDefault ( ) ? * this : ForceCopy ( arena ) ;
}
inline TaggedStringPtr TaggedStringPtr : : Copy (
Arena * arena , const LazyString & default_value ) const {
if ( DebugHardenStringValues ( ) ) {
// Harden by forcing an allocated string value.
TaggedStringPtr hardened ( * this ) ;
if ( IsDefault ( ) ) {
hardened . SetDefault ( & default_value . get ( ) ) ;
}
return hardened . ForceCopy ( arena ) ;
}
return IsDefault ( ) ? * this : ForceCopy ( arena ) ;
}
inline void ArenaStringPtr : : InitDefault ( ) {
tagged_ptr_ = TaggedStringPtr ( & fixed_address_empty_string ) ;
}