Google OR-Tools v9.15
a fast and portable software suite for combinatorial optimization
Loading...
Searching...
No Matches
proto_tools.h
Go to the documentation of this file.
1// Copyright 2010-2025 Google LLC
2// Licensed under the Apache License, Version 2.0 (the "License");
3// you may not use this file except in compliance with the License.
4// You may obtain a copy of the License at
5//
6// http://www.apache.org/licenses/LICENSE-2.0
7//
8// Unless required by applicable law or agreed to in writing, software
9// distributed under the License is distributed on an "AS IS" BASIS,
10// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11// See the License for the specific language governing permissions and
12// limitations under the License.
13
14#ifndef ORTOOLS_UTIL_PROTO_TOOLS_H_
15#define ORTOOLS_UTIL_PROTO_TOOLS_H_
16
17#include <string>
18
19#include "absl/status/status.h"
20#include "absl/status/statusor.h"
21#include "absl/strings/str_format.h"
22#include "google/protobuf/descriptor.h"
23#include "google/protobuf/message.h"
24
25namespace operations_research {
26
27// Casts a generic google::protobuf::Message* to a specific proto type, or
28// returns an InvalidArgumentError if it doesn't seem to be of the right type.
29// Comes in non-const and const versions.
30// NOTE(user): You should rather use DynamicCastToGenerated() from message.h
31// if you don't need the fancy error message or the absl::Status.
32template <class Proto>
33absl::StatusOr<Proto*> SafeProtoDownCast(google::protobuf::Message* proto);
34template <class Proto>
35absl::StatusOr<const Proto*> SafeProtoConstDownCast(
36 const google::protobuf::Message* proto);
37
38// Prints a proto2 message as a string, it behaves like TextFormat::Print()
39// but also prints the default values of unset fields which is useful for
40// printing parameters.
42 const google::protobuf::Message& message, int indent_level);
43
44// This recursive function returns all the proto fields that are set(*) in a
45// proto instance, along with how many times they appeared. A repeated field is
46// only counted once as itself, regardless of its (non-zero) size, but then the
47// nested child fields of a repeated message are counted once per instance.
48// EXAMPLE: with these .proto message definitions:
49// message YY { repeated int z; }
50// message XX { int a; int b; repeated int c; repeated YY d; }
51// and this instance of `XX`:
52// XX x = Parse("a: 10 c: [ 11, 12] d: {z: [13, 14]} d: {z: [15]}"");
53// We'd expect ExploreAndCountAllProtoPathsInInstance() to yield the map:
54// {"a": 1, "c": 1, "d": 1, "d.z": 3}
55//
56// (*) The term 'set' has the usual semantic, which varies depending on proto
57// version. Extensions and unknown fields are ignored by this function.
59 const google::protobuf::Message& message,
60 // Output. Must be non-nullptr. Entries are added to the map, i.e., the map
61 // is not cleared. That allows cumulative use of this function across
62 // several proto instances to build a global count of proto paths.
63 absl::flat_hash_map<std::string, int>* proto_path_counts);
64
65// =============================================================================
66// Implementation of function templates.
67
68template <class Proto>
69absl::StatusOr<Proto*> SafeProtoDownCast(google::protobuf::Message* proto) {
70 const google::protobuf::Descriptor* expected_descriptor =
71 Proto::default_instance().GetDescriptor();
72 const google::protobuf::Descriptor* actual_descriptor =
73 proto->GetDescriptor();
74 if (actual_descriptor == expected_descriptor)
75 return reinterpret_cast<Proto*>(proto);
76 return absl::InvalidArgumentError(absl::StrFormat(
77 "Expected message type '%s', but got type '%s'",
78 expected_descriptor->full_name(), actual_descriptor->full_name()));
79}
80
81template <class Proto>
82absl::StatusOr<const Proto*> SafeProtoConstDownCast(
83 const google::protobuf::Message* proto) {
84 const google::protobuf::Descriptor* expected_descriptor =
85 Proto::default_instance().GetDescriptor();
86 const google::protobuf::Descriptor* actual_descriptor =
87 proto->GetDescriptor();
88 if (actual_descriptor == expected_descriptor) {
89 return reinterpret_cast<const Proto*>(proto);
90 }
91 return absl::InvalidArgumentError(absl::StrFormat(
92 "Expected message type '%s', but got type '%s'",
93 expected_descriptor->full_name(), actual_descriptor->full_name()));
94}
95
96} // namespace operations_research
97#endif // ORTOOLS_UTIL_PROTO_TOOLS_H_
OR-Tools root namespace.
std::string FullProtocolMessageAsString(const google::protobuf::Message &message, int indent_level)
absl::StatusOr< Proto * > SafeProtoDownCast(google::protobuf::Message *proto)
Definition proto_tools.h:70
void ExploreAndCountAllProtoPathsInInstance(const google::protobuf::Message &message, absl::flat_hash_map< std::string, int > *proto_path_counts)
absl::StatusOr< const Proto * > SafeProtoConstDownCast(const google::protobuf::Message *proto)
Definition proto_tools.h:83