String View APIs

Umfasst verschiedene string_view-Migrationen

C++-Stringfeld-APIs, die std::string stark nutzen, schränken die interne Implementierung und Weiterentwicklung von Protobuf erheblich ein. Zum Beispiel gibt mutable_string_field() einen std::string* zurück, der uns zwingt, std::string zur Speicherung des Feldes zu verwenden. Dies erschwert die Interaktion mit Arenen und wir müssen Arena-Spendenstatus verwalten, um zu verfolgen, ob die String-Payload-Allokation von der Arena oder dem Heap stammt.

Langfristig möchten wir alle unsere Laufzeit- und generierten APIs so umstellen, dass sie string_view als Eingaben akzeptieren und von Accessors zurückgeben. Dieses Dokument beschreibt den Stand der Migration zum Release 30.x.

String Feld-Zugriffsmethoden

Als Teil der Edition 2023 wurde das Feature string_type mit der Option VIEW veröffentlicht, um eine inkrementelle Migration zu generierten string_view-APIs zu ermöglichen. Die Verwendung dieses Features wirkt sich auf den C++-generierten Code von string- und bytes-Feldern aus.

Interaktion mit ctype

In Edition 2023 können Sie ctype immer noch auf Feld-Ebene angeben, während Sie string_type entweder auf Datei- oder Feld-Ebene angeben können. Die gleichzeitige Angabe auf demselben Feld ist nicht zulässig. Wenn string_type auf Datei-Ebene gesetzt ist, haben die auf Feldern angegebenen ctype Vorrang.

Mit Ausnahme der Option VIEW haben alle möglichen Werte von string_type einen entsprechenden ctype-Wert, der gleich geschrieben ist und das gleiche Verhalten aufweist. Beide Enums haben zum Beispiel einen CORD-Wert.

In Edition 2024 und darüber hinaus wird es nicht mehr möglich sein, ctype anzugeben.

Generierte singuläre Felder

Für eine dieser Felddefinitionen in Edition 2023

bytes foo = 1 [features.(pb.cpp).string_type=VIEW];
string foo = 1 [features.(pb.cpp).string_type=VIEW];

Der Compiler generiert die folgenden Accessor-Methoden:

  • ::absl::string_view foo() const: Gibt den aktuellen Wert des Feldes zurück. Wenn das Feld nicht gesetzt ist, wird der Standardwert zurückgegeben.
  • void clear_foo(): Löscht den Wert des Feldes. Nach dem Aufruf dieser Methode gibt foo() den Standardwert zurück.
  • bool has_foo(): Gibt true zurück, wenn das Feld gesetzt ist.
  • void set_foo(::absl::string_view value): Setzt den Wert des Feldes. Nach dem Aufruf dieser Methode gibt has_foo() true zurück und foo() gibt eine Kopie von value zurück.
  • void set_foo(const string& value): Setzt den Wert des Feldes. Nach dem Aufruf dieser Methode gibt has_foo() true zurück und foo() gibt eine Kopie von value zurück.
  • void set_foo(string&& value): Setzt den Wert des Feldes, indem der übergebene String verschoben wird. Nach dem Aufruf dieser Methode gibt has_foo() true zurück und foo() gibt value zurück.
  • void set_foo(const char* value): Setzt den Wert des Feldes mit einem C-Style-String mit Nullterminierung. Nach dem Aufruf dieser Methode gibt has_foo() true zurück und foo() gibt eine Kopie von value zurück.

Generierte wiederholte Felder

Für eine dieser Felddefinitionen

repeated string foo = 1 [features.(pb.cpp).string_type=VIEW];
repeated bytes foo = 1 [features.(pb.cpp).string_type=VIEW];

Der Compiler generiert die folgenden Accessor-Methoden:

  • int foo_size() const: Gibt die aktuelle Anzahl der Elemente im Feld zurück.
  • ::absl::string_view foo(int index) const: Gibt das Element am angegebenen nullbasierten Index zurück. Der Aufruf dieser Methode mit einem Index außerhalb von [0, foo_size()-1] führt zu undefiniertem Verhalten.
  • void set_foo(int index, ::absl::string_view value): Setzt den Wert des Elements am angegebenen nullbasierten Index.
  • void set_foo(int index, const string& value): Setzt den Wert des Elements am angegebenen nullbasierten Index.
  • void set_foo(int index, string&& value): Setzt den Wert des Elements am angegebenen nullbasierten Index, indem der übergebene String verschoben wird.
  • void set_foo(int index, const char* value): Setzt den Wert des Elements am angegebenen nullbasierten Index mit einem C-Style-String mit Nullterminierung.
  • void add_foo(::absl::string_view value): Fügt am Ende des Feldes ein neues Element mit dem angegebenen Wert hinzu.
  • void add_foo(const string& value): Fügt am Ende des Feldes ein neues Element mit dem angegebenen Wert hinzu.
  • void add_foo(string&& value): Fügt am Ende des Feldes ein neues Element hinzu, indem der übergebene String verschoben wird.
  • void add_foo(const char* value): Fügt am Ende des Feldes ein neues Element mit einem C-Style-String mit Nullterminierung hinzu.
  • void clear_foo(): Entfernt alle Elemente aus dem Feld. Nach dem Aufruf dieser Methode gibt foo_size() Null zurück.
  • const RepeatedPtrField<string>& foo() const: Gibt das zugrundeliegende RepeatedPtrField zurück, das die Elemente des Feldes speichert. Diese Containerklasse bietet STL-ähnliche Iteratoren und weitere Methoden.
  • RepeatedPtrField<string>* mutable_foo(): Gibt einen Zeiger auf das zugrundeliegende veränderbare RepeatedPtrField zurück, das die Elemente des Feldes speichert. Diese Containerklasse bietet STL-ähnliche Iteratoren und weitere Methoden.

Generierte Oneof-Felder

Für eine dieser oneof-Felddefinitionen

oneof example_name {
    string foo = 1 [features.(pb.cpp).string_type=VIEW];
    ...
}
oneof example_name {
    bytes foo = 1 [features.(pb.cpp).string_type=VIEW];
    ...
}

Der Compiler generiert die folgenden Accessor-Methoden:

  • bool has_foo() const: Gibt true zurück, wenn der Oneof-Fall kFoo ist.
  • ::absl::string_view foo() const: Gibt den aktuellen Wert des Feldes zurück, wenn der Oneof-Fall kFoo ist. Andernfalls wird der Standardwert zurückgegeben.
  • void set_foo(::absl::string_view value):
    • Wenn ein anderes Oneof-Feld im selben Oneof gesetzt ist, wird clear_example_name() aufgerufen.
    • Setzt den Wert dieses Feldes und den Oneof-Fall auf kFoo.
    • has_foo() gibt true zurück, foo() gibt eine Kopie von value zurück und example_name_case() gibt kFoo zurück.
  • void set_foo(const string& value): Wie das erste set_foo(), aber kopiert von einer const string Referenz.
  • void set_foo(string&& value): Wie das erste set_foo(), aber verschiebt vom übergebenen String.
  • void set_foo(const char* value): Wie das erste set_foo(), aber kopiert von einem C-Style-String mit Nullterminierung.
  • void clear_foo():
    • Wenn der Oneof-Fall nicht kFoo ist, wird nichts geändert.
    • Wenn der Oneof-Fall kFoo ist, wird das Feld freigegeben und der Oneof-Fall gelöscht. has_foo() gibt false zurück, foo() gibt den Standardwert zurück und example_name_case() gibt EXAMPLE_NAME_NOT_SET zurück.

Enumerationsnamen-Hilfsfunktion

Ab der Edition 2024 wird ein neues Feature enum_name_uses_string_view eingeführt und ist standardmäßig auf true gesetzt. Sofern nicht deaktiviert, wird für eine Enum wie diese

enum Foo {
  VALUE_A = 0;
  VALUE_B = 5;
  VALUE_C = 1234;
}

Der Protocol Buffer Compiler generiert zusätzlich zur Foo-Enum die folgende neue Funktion zusätzlich zum Standard generierten Code

  • ::absl::string_view Foo_Name(int value): Gibt den Namen für den gegebenen numerischen Wert zurück. Gibt einen leeren String zurück, wenn kein solcher Wert existiert. Wenn mehrere Werte diese Nummer haben, wird der erste definierte zurückgegeben. Im obigen Beispiel würde Foo_Name(5) VALUE_B zurückgeben.

Dies kann durch Hinzufügen eines Feature-Overrides wie folgt zum alten Verhalten zurückgesetzt werden:

enum Foo {
  option features.(pb.cpp).enum_name_uses_string_view = false;

  VALUE_A = 0;
  VALUE_B = 5;
  VALUE_C = 1234;
}

In diesem Fall wechselt die Namens-Hilfsfunktion zurück zu const string& Foo_Name(int value).