|
|
|
@ -41,6 +41,8 @@ |
|
|
|
|
#include "absl/memory/memory.h" |
|
|
|
|
#include "absl/strings/str_join.h" |
|
|
|
|
#include "absl/strings/str_split.h" |
|
|
|
|
#include "absl/strings/string_view.h" |
|
|
|
|
#include "absl/strings/strip.h" |
|
|
|
|
#include "google/protobuf/message.h" |
|
|
|
|
|
|
|
|
|
// Must be included last.
|
|
|
|
@ -58,8 +60,8 @@ std::string FieldMaskUtil::ToString(const FieldMask& mask) { |
|
|
|
|
|
|
|
|
|
void FieldMaskUtil::FromString(absl::string_view str, FieldMask* out) { |
|
|
|
|
out->Clear(); |
|
|
|
|
std::vector<std::string> paths = absl::StrSplit(str, ','); |
|
|
|
|
for (const std::string& path : paths) { |
|
|
|
|
std::vector<absl::string_view> paths = absl::StrSplit(str, ','); |
|
|
|
|
for (absl::string_view path : paths) { |
|
|
|
|
if (path.empty()) continue; |
|
|
|
|
out->add_paths(path); |
|
|
|
|
} |
|
|
|
@ -116,7 +118,7 @@ bool FieldMaskUtil::CamelCaseToSnakeCase(absl::string_view input, |
|
|
|
|
bool FieldMaskUtil::ToJsonString(const FieldMask& mask, std::string* out) { |
|
|
|
|
out->clear(); |
|
|
|
|
for (int i = 0; i < mask.paths_size(); ++i) { |
|
|
|
|
const std::string& path = mask.paths(i); |
|
|
|
|
absl::string_view path = mask.paths(i); |
|
|
|
|
std::string camelcase_path; |
|
|
|
|
if (!SnakeCaseToCamelCase(path, &camelcase_path)) { |
|
|
|
|
return false; |
|
|
|
@ -131,8 +133,8 @@ bool FieldMaskUtil::ToJsonString(const FieldMask& mask, std::string* out) { |
|
|
|
|
|
|
|
|
|
bool FieldMaskUtil::FromJsonString(absl::string_view str, FieldMask* out) { |
|
|
|
|
out->Clear(); |
|
|
|
|
std::vector<std::string> paths = absl::StrSplit(str, ','); |
|
|
|
|
for (const std::string& path : paths) { |
|
|
|
|
std::vector<absl::string_view> paths = absl::StrSplit(str, ','); |
|
|
|
|
for (absl::string_view path : paths) { |
|
|
|
|
if (path.empty()) continue; |
|
|
|
|
std::string snakecase_path; |
|
|
|
|
if (!CamelCaseToSnakeCase(path, &snakecase_path)) { |
|
|
|
@ -149,8 +151,8 @@ bool FieldMaskUtil::GetFieldDescriptors( |
|
|
|
|
if (field_descriptors != nullptr) { |
|
|
|
|
field_descriptors->clear(); |
|
|
|
|
} |
|
|
|
|
std::vector<std::string> parts = absl::StrSplit(path, '.'); |
|
|
|
|
for (const std::string& field_name : parts) { |
|
|
|
|
std::vector<absl::string_view> parts = absl::StrSplit(path, '.'); |
|
|
|
|
for (absl::string_view field_name : parts) { |
|
|
|
|
if (descriptor == nullptr) { |
|
|
|
|
return false; |
|
|
|
|
} |
|
|
|
@ -206,18 +208,18 @@ class FieldMaskTree { |
|
|
|
|
// be added to the tree. If the path matches an existing non-leaf node in the
|
|
|
|
|
// tree, that non-leaf node will be turned into a leaf node with all its
|
|
|
|
|
// children removed because the path matches all the node's children.
|
|
|
|
|
void AddPath(const std::string& path); |
|
|
|
|
void AddPath(absl::string_view path); |
|
|
|
|
|
|
|
|
|
// Remove a path from the tree.
|
|
|
|
|
// If the path is a sub-path of an existing field path in the tree, it means
|
|
|
|
|
// we need remove the existing field path and add all sub-paths except
|
|
|
|
|
// specified path. If the path matches an existing node in the tree, this node
|
|
|
|
|
// will be moved.
|
|
|
|
|
void RemovePath(const std::string& path, const Descriptor* descriptor); |
|
|
|
|
void RemovePath(absl::string_view path, const Descriptor* descriptor); |
|
|
|
|
|
|
|
|
|
// Calculate the intersection part of a field path with this tree and add
|
|
|
|
|
// the intersection field path into out.
|
|
|
|
|
void IntersectPath(const std::string& path, FieldMaskTree* out); |
|
|
|
|
void IntersectPath(absl::string_view path, FieldMaskTree* out); |
|
|
|
|
|
|
|
|
|
// Merge all fields specified by this tree from one message to another.
|
|
|
|
|
void MergeMessage(const Message& source, |
|
|
|
@ -269,11 +271,11 @@ class FieldMaskTree { |
|
|
|
|
|
|
|
|
|
// Merge a sub-tree to mask. This method adds the field paths represented
|
|
|
|
|
// by all leaf nodes descended from "node" to mask.
|
|
|
|
|
void MergeToFieldMask(const std::string& prefix, const Node* node, |
|
|
|
|
void MergeToFieldMask(absl::string_view prefix, const Node* node, |
|
|
|
|
FieldMask* out); |
|
|
|
|
|
|
|
|
|
// Merge all leaf nodes of a sub-tree to another tree.
|
|
|
|
|
void MergeLeafNodesToTree(const std::string& prefix, const Node* node, |
|
|
|
|
void MergeLeafNodesToTree(absl::string_view prefix, const Node* node, |
|
|
|
|
FieldMaskTree* out); |
|
|
|
|
|
|
|
|
|
// Merge all fields specified by a sub-tree from one message to another.
|
|
|
|
@ -308,8 +310,8 @@ void FieldMaskTree::MergeToFieldMask(FieldMask* mask) { |
|
|
|
|
MergeToFieldMask("", &root_, mask); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void FieldMaskTree::MergeToFieldMask(const std::string& prefix, |
|
|
|
|
const Node* node, FieldMask* out) { |
|
|
|
|
void FieldMaskTree::MergeToFieldMask(absl::string_view prefix, const Node* node, |
|
|
|
|
FieldMask* out) { |
|
|
|
|
if (node->children.empty()) { |
|
|
|
|
if (prefix.empty()) { |
|
|
|
|
// This is the root node.
|
|
|
|
@ -325,7 +327,7 @@ void FieldMaskTree::MergeToFieldMask(const std::string& prefix, |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void FieldMaskTree::AddPath(const std::string& path) { |
|
|
|
|
void FieldMaskTree::AddPath(absl::string_view path) { |
|
|
|
|
std::vector<absl::string_view> parts = absl::StrSplit(path, '.'); |
|
|
|
|
if (parts.empty()) { |
|
|
|
|
return; |
|
|
|
@ -351,7 +353,7 @@ void FieldMaskTree::AddPath(const std::string& path) { |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void FieldMaskTree::RemovePath(const std::string& path, |
|
|
|
|
void FieldMaskTree::RemovePath(absl::string_view path, |
|
|
|
|
const Descriptor* descriptor) { |
|
|
|
|
if (root_.children.empty()) { |
|
|
|
|
// Nothing to be removed from an empty tree. We shortcut it here so an empty
|
|
|
|
@ -407,13 +409,13 @@ void FieldMaskTree::RemovePath(const std::string& path, |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void FieldMaskTree::IntersectPath(const std::string& path, FieldMaskTree* out) { |
|
|
|
|
std::vector<std::string> parts = absl::StrSplit(path, '.'); |
|
|
|
|
void FieldMaskTree::IntersectPath(absl::string_view path, FieldMaskTree* out) { |
|
|
|
|
std::vector<absl::string_view> parts = absl::StrSplit(path, '.'); |
|
|
|
|
if (parts.empty()) { |
|
|
|
|
return; |
|
|
|
|
} |
|
|
|
|
const Node* node = &root_; |
|
|
|
|
for (const std::string& node_name : parts) { |
|
|
|
|
for (absl::string_view node_name : parts) { |
|
|
|
|
if (node->children.empty()) { |
|
|
|
|
if (node != &root_) { |
|
|
|
|
out->AddPath(path); |
|
|
|
@ -432,7 +434,7 @@ void FieldMaskTree::IntersectPath(const std::string& path, FieldMaskTree* out) { |
|
|
|
|
MergeLeafNodesToTree(path, node, out); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void FieldMaskTree::MergeLeafNodesToTree(const std::string& prefix, |
|
|
|
|
void FieldMaskTree::MergeLeafNodesToTree(absl::string_view prefix, |
|
|
|
|
const Node* node, FieldMaskTree* out) { |
|
|
|
|
if (node->children.empty()) { |
|
|
|
|
out->AddPath(prefix); |
|
|
|
@ -452,7 +454,7 @@ void FieldMaskTree::MergeMessage(const Node* node, const Message& source, |
|
|
|
|
const Reflection* destination_reflection = destination->GetReflection(); |
|
|
|
|
const Descriptor* descriptor = source.GetDescriptor(); |
|
|
|
|
for (const auto& kv : node->children) { |
|
|
|
|
const std::string& field_name = kv.first; |
|
|
|
|
absl::string_view field_name = kv.first; |
|
|
|
|
const Node* child = kv.second.get(); |
|
|
|
|
const FieldDescriptor* field = descriptor->FindFieldByName(field_name); |
|
|
|
|
if (field == nullptr) { |
|
|
|
@ -552,7 +554,7 @@ void FieldMaskTree::AddRequiredFieldPath(Node* node, |
|
|
|
|
for (int index = 0; index < field_count; ++index) { |
|
|
|
|
const FieldDescriptor* field = descriptor->field(index); |
|
|
|
|
if (field->is_required()) { |
|
|
|
|
const std::string& node_name = field->name(); |
|
|
|
|
absl::string_view node_name = field->name(); |
|
|
|
|
std::unique_ptr<Node>& child = node->children[node_name]; |
|
|
|
|
if (child == nullptr) { |
|
|
|
|
// Add required field path to the tree
|
|
|
|
@ -662,15 +664,16 @@ void FieldMaskUtil::Subtract(const Descriptor* descriptor, |
|
|
|
|
bool FieldMaskUtil::IsPathInFieldMask(absl::string_view path, |
|
|
|
|
const FieldMask& mask) { |
|
|
|
|
for (int i = 0; i < mask.paths_size(); ++i) { |
|
|
|
|
const std::string& mask_path = mask.paths(i); |
|
|
|
|
if (path == mask_path) { |
|
|
|
|
absl::string_view current = path; |
|
|
|
|
absl::string_view mask_path = mask.paths(i); |
|
|
|
|
if (current == mask_path) { |
|
|
|
|
return true; |
|
|
|
|
} else if (mask_path.length() < path.length()) { |
|
|
|
|
} |
|
|
|
|
// Also check whether mask.paths(i) is a prefix of path.
|
|
|
|
|
if (path.substr(0, mask_path.length() + 1).compare(mask_path + ".") == |
|
|
|
|
0) { |
|
|
|
|
return true; |
|
|
|
|
} |
|
|
|
|
if (mask_path.length() < current.length() && |
|
|
|
|
absl::ConsumePrefix(¤t, mask_path) && |
|
|
|
|
absl::ConsumePrefix(¤t, ".")) { |
|
|
|
|
return true; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
return false; |
|
|
|
|