Google OR-Tools v9.14
a fast and portable software suite for combinatorial optimization
Loading...
Searching...
No Matches
gen_c.cc
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
15
16#include <memory>
17#include <string>
18
19#include "absl/log/check.h"
20#include "absl/strings/ascii.h"
21#include "absl/strings/str_cat.h"
22#include "absl/strings/str_format.h"
23#include "absl/strings/string_view.h"
24#include "absl/types/span.h"
26
28
29namespace {
30
31// A helper to generate parameters to pass `n` key element indices, e.g:
32// ", int64_t key_0, int64_t key_1" (parameters)
33void AddKeyParams(int n, std::string* out) {
34 for (int i = 0; i < n; ++i) {
35 absl::StrAppend(out, ", int64_t key_", i);
36 }
37}
38
39// A helper to generate an AttrKey argument to pass `n` key element indices,
40// e.g: "AttrKey<2, NoSymmetry>(key_0, key_1)".
41void AddAttrKeyArg(int n, absl::string_view symmetry, std::string* out) {
42 absl::StrAppendFormat(out, ", AttrKey<%i, %s>(", n, symmetry);
43 for (int i = 0; i < n; ++i) {
44 if (i != 0) {
45 absl::StrAppend(out, ", ");
46 }
47 absl::StrAppend(out, "key_", i);
48 }
49 absl::StrAppend(out, ")");
50}
51
52// Returns the C99 name for the given type.
53absl::string_view GetCTypeName(
55 switch (value_type) {
57 return "_Bool";
59 return "int64_t";
61 return "double";
62 }
63}
64
65// Turns an element/attribute name (e.g. "some_name") into a camel case name
66// (e.g. "SomeName").
67std::string NameToCamelCase(absl::string_view attr_name) {
68 std::string result;
69 result.reserve(attr_name.size());
70 CHECK(!attr_name.empty());
71 const char first = attr_name[0];
72 CHECK(absl::ascii_isalpha(first) && absl::ascii_islower(first))
73 << "invalid attr name: " << attr_name;
74 result.push_back(absl::ascii_toupper(first));
75 for (int i = 1; i < attr_name.size(); ++i) {
76 const char c = attr_name[i];
77 if (c == '_') {
78 ++i;
79 CHECK(i < attr_name.size()) << "invalid attr name: " << attr_name;
80 const char next_c = attr_name[i];
81 CHECK(absl::ascii_isalnum(next_c)) << "invalid attr name: " << attr_name;
82 result.push_back(absl::ascii_toupper(next_c));
83 } else {
84 CHECK(absl::ascii_isalnum(c)) << "invalid attr name: " << attr_name;
85 CHECK(absl::ascii_islower(c)) << "invalid attr name: " << attr_name;
86 result.push_back(c);
87 }
88 }
89 return result;
90}
91
92// Returns the type of the C status.
93std::shared_ptr<Type> GetStatusType() { return Type::Named("int"); }
94
95const AttrOpFunctionInfos* GetC99FunctionInfos() {
96 static const auto* const kResult = new AttrOpFunctionInfos({
97 // Get.
99 .return_type = GetStatusType(),
100 .has_key_parameter = true,
101 .extra_parameters = {{.type = Type::Pointer(Type::AttrValueType()),
102 .name = "value"}}},
103 // Set.
104 AttrOpFunctionInfo{.return_type = GetStatusType(),
105 .has_key_parameter = true,
106 .extra_parameters = {{.type = Type::AttrValueType(),
107 .name = "value"}}},
108 // IsNonDefault.
110 .return_type = GetStatusType(),
111 .has_key_parameter = true,
112 .extra_parameters = {{.type = Type::Pointer(Type::Named("_Bool")),
113 .name = "out_is_non_default"}}},
114 // NumNonDefaults.
116 .return_type = GetStatusType(),
117 .has_key_parameter = false,
118 .extra_parameters = {{.type = Type::Pointer(Type::Named("int64_t")),
119 .name = "out_num_non_defaults"}}},
120 // GetNonDefaults.
122 .return_type = GetStatusType(),
123 .has_key_parameter = false,
124 .extra_parameters =
125 {
126 {.type = Type::Pointer(Type::Named("int64_t")),
127 .name = "out_num_non_defaults"},
128 {.type = Type::Pointer(Type::Pointer(Type::Named("int64_t"))),
129 .name = "out_non_defaults"},
130 }},
131 });
132 return kResult;
133}
134
135class C99CodeGeneratorBase : public CodeGenerator {
136 public:
138
139 void EmitHeader(std::string* out) const final {
140 absl::StrAppend(out, R"(
141/* DO NOT EDIT: This file is autogenerated. */
142#ifndef MATHOPTH_GENERATED
143#error "this file is intended to be included, do not use directly"
144#endif
145)");
146 }
147};
148
149// Emits the prototype for a function.
150void EmitPrototype(absl::string_view op_name,
151 const CodegenAttrTypeDescriptor& descriptor,
152 const AttrOpFunctionInfo& info, std::string* out) {
153 absl::string_view attr_value_type = GetCTypeName(descriptor.value_type);
154 // Adds the return type, function name and common parameters.
155 info.return_type->Print(attr_value_type, out);
156 absl::StrAppendFormat(out,
157 " MathOpt%s%s(struct "
158 "MathOptElemental* e, int attr",
159 descriptor.name, op_name);
160 // Add the key.
161 if (info.has_key_parameter) {
162 AddKeyParams(descriptor.num_key_elements, out);
163 }
164 // Add extra parameters.
165 for (const auto& extra_param : info.extra_parameters) {
166 absl::StrAppend(out, ", ");
167 extra_param.type->Print(attr_value_type, out);
168 absl::StrAppend(out, " ", extra_param.name);
169 }
170 // Finish prototype.
171 absl::StrAppend(out, ")");
172}
173
174class C99DeclarationsGenerator : public C99CodeGeneratorBase {
175 public:
176 C99DeclarationsGenerator() : C99CodeGeneratorBase(GetC99FunctionInfos()) {}
177
178 void EmitElements(absl::Span<const absl::string_view> elements,
179 std::string* out) const override {
180 // Generate an enum for the elements.
181 absl::StrAppend(out,
182 "// The type of an element in the model.\n"
183 "enum MathOptElementType {\n");
184 for (const auto& element_name : elements) {
185 absl::StrAppendFormat(out, " kMathOpt%s,\n",
186 NameToCamelCase(element_name));
187 }
188 absl::StrAppend(out, "};\n\n");
189 }
190
191 void EmitAttrOp(absl::string_view op_name,
192 const CodegenAttrTypeDescriptor& descriptor,
193 const AttrOpFunctionInfo& info,
194 std::string* out) const override {
195 // Just emit a prototype.
196 EmitPrototype(op_name, descriptor, info, out);
197 absl::StrAppend(out, ";\n");
198 }
199
200 void StartAttrType(const CodegenAttrTypeDescriptor& descriptor,
201 std::string* out) const override {
202 // Generate an enum for the attribute type.
203 absl::StrAppendFormat(out, "typedef enum {\n");
204 for (absl::string_view attr_name : descriptor.attribute_names) {
205 absl::StrAppendFormat(out, " kMathOpt%s%s,\n", descriptor.name,
206 NameToCamelCase(attr_name));
207 }
208 absl::StrAppendFormat(out, "} MathOpt%s;\n", descriptor.name);
209 }
210};
211
212class C99DefinitionsGenerator : public C99CodeGeneratorBase {
213 public:
214 C99DefinitionsGenerator() : C99CodeGeneratorBase(GetC99FunctionInfos()) {}
215
216 void EmitAttrOp(absl::string_view op_name,
217 const CodegenAttrTypeDescriptor& descriptor,
218 const AttrOpFunctionInfo& info,
219 std::string* out) const override {
220 EmitPrototype(op_name, descriptor, info, out);
221 // Emit a call to the wrapper (e.g. `CAttrOp<Descriptor>::Op`).
222 absl::StrAppendFormat(out, " {\n return CAttrOp<%s>::%s(e, attr",
223 descriptor.name, op_name);
224 // Add the key argument.
225 if (info.has_key_parameter) {
226 AddAttrKeyArg(descriptor.num_key_elements, descriptor.symmetry, out);
227 }
228 // Add extra parameter arguments.
229 for (const auto& extra_param : info.extra_parameters) {
230 absl::StrAppend(out, ", ", extra_param.name);
231 }
232 absl::StrAppend(out, ");\n}\n");
233 }
234};
235} // namespace
236
237std::unique_ptr<CodeGenerator> C99Declarations() {
238 return std::make_unique<C99DeclarationsGenerator>();
239}
240
241std::unique_ptr<CodeGenerator> C99Definitions() {
242 return std::make_unique<C99DefinitionsGenerator>();
243}
244
245} // namespace operations_research::math_opt::codegen
CodeGenerator(const AttrOpFunctionInfos *attr_op_function_infos)
Definition gen.h:101
static std::shared_ptr< Type > Named(std::string name)
A named type, e.g. "double".
Definition gen.cc:68
static std::shared_ptr< Type > Pointer(std::shared_ptr< Type > pointee)
A pointer type.
Definition gen.cc:72
static std::shared_ptr< Type > AttrValueType()
Definition gen.cc:76
Language-agnostic utilities for Elemental codegen.
Definition codegen.cc:29
std::unique_ptr< CodeGenerator > C99Definitions()
Returns a generator for C99 definitions.
Definition gen_c.cc:241
std::unique_ptr< CodeGenerator > C99Declarations()
Returns a generator for C99 declarations.
Definition gen_c.cc:237
std::array< AttrOpFunctionInfo, kNumAttrOps > AttrOpFunctionInfos
Definition gen.h:96
Information about how to codegen a given AttrOp in a given language.
Definition gen.h:81
A struct to represent an attribute type descriptor during codegen.
Definition gen.h:42