bindings: drop "get_" prefix of methods that start this way
[isl.git] / interface / cpp.cc
bloba2caa9f891d75a15d7b04934776604f7c860f103
1 /*
2 * Copyright 2016, 2017 Tobias Grosser. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above
12 * copyright notice, this list of conditions and the following
13 * disclaimer in the documentation and/or other materials provided
14 * with the distribution.
16 * THIS SOFTWARE IS PROVIDED BY TOBIAS GROSSER ''AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SVEN VERDOOLAEGE OR
20 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
21 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
22 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
23 * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 * The views and conclusions contained in the software and documentation
29 * are those of the authors and should not be interpreted as
30 * representing official policies, either expressed or implied, of
31 * Tobias Grosser.
34 #include <cstdarg>
35 #include <cstdio>
36 #include <iostream>
37 #include <map>
38 #include <sstream>
39 #include <string>
40 #include <vector>
42 #include "cpp.h"
43 #include "isl_config.h"
45 /* Print string formatted according to "fmt" to ostream "os".
47 * This osprintf method allows us to use printf style formatting constructs when
48 * writing to an ostream.
50 static void osprintf(ostream &os, const char *format, va_list arguments)
52 va_list copy;
53 char *string_pointer;
54 size_t size;
56 va_copy(copy, arguments);
57 size = vsnprintf(NULL, 0, format, copy);
58 string_pointer = new char[size + 1];
59 va_end(copy);
60 vsnprintf(string_pointer, size + 1, format, arguments);
61 os << string_pointer;
62 delete[] string_pointer;
65 /* Print string formatted according to "fmt" to ostream "os".
67 * This osprintf method allows us to use printf style formatting constructs when
68 * writing to an ostream.
70 static void osprintf(ostream &os, const char *format, ...)
72 va_list arguments;
74 va_start(arguments, format);
75 osprintf(os, format, arguments);
76 va_end(arguments);
79 /* Print string formatted according to "fmt" to ostream "os"
80 * with the given indentation.
82 * This osprintf method allows us to use printf style formatting constructs when
83 * writing to an ostream.
85 static void osprintf(ostream &os, int indent, const char *format, ...)
87 va_list arguments;
89 osprintf(os, "%*s", indent, " ");
90 va_start(arguments, format);
91 osprintf(os, format, arguments);
92 va_end(arguments);
95 /* Convert "l" to a string.
97 static std::string to_string(long l)
99 std::ostringstream strm;
100 strm << l;
101 return strm.str();
104 /* Generate a cpp interface based on the extracted types and functions.
106 * Print first a set of forward declarations for all isl wrapper
107 * classes, then the declarations of the classes, and at the end all
108 * implementations.
110 * If checked C++ bindings are being generated,
111 * then wrap them in a namespace to avoid conflicts
112 * with the default C++ bindings (with automatic checks using exceptions).
114 void cpp_generator::generate()
116 ostream &os = cout;
118 osprintf(os, "\n");
119 osprintf(os, "namespace isl {\n\n");
120 if (checked)
121 osprintf(os, "namespace checked {\n\n");
123 print_forward_declarations(os);
124 osprintf(os, "\n");
125 print_declarations(os);
126 osprintf(os, "\n");
127 print_implementations(os);
129 if (checked)
130 osprintf(os, "} // namespace checked\n");
131 osprintf(os, "} // namespace isl\n");
134 /* Print forward declarations for all classes to "os".
136 void cpp_generator::print_forward_declarations(ostream &os)
138 map<string, isl_class>::iterator ci;
140 osprintf(os, "// forward declarations\n");
142 for (ci = classes.begin(); ci != classes.end(); ++ci)
143 print_class_forward_decl(os, ci->second);
146 /* Print all declarations to "os".
148 void cpp_generator::print_declarations(ostream &os)
150 map<string, isl_class>::iterator ci;
151 bool first = true;
153 for (ci = classes.begin(); ci != classes.end(); ++ci) {
154 if (first)
155 first = false;
156 else
157 osprintf(os, "\n");
159 print_class(os, ci->second);
163 /* Print all implementations to "os".
165 void cpp_generator::print_implementations(ostream &os)
167 map<string, isl_class>::iterator ci;
168 bool first = true;
170 for (ci = classes.begin(); ci != classes.end(); ++ci) {
171 if (first)
172 first = false;
173 else
174 osprintf(os, "\n");
176 print_class_impl(os, ci->second);
180 /* If "clazz" is a subclass that is based on a type function,
181 * then introduce a "type" field that holds the value of the type
182 * corresponding to the subclass and make the fields of the class
183 * accessible to the "isa" and "as" methods of the (immediate) superclass.
184 * In particular, "isa" needs access to the type field itself,
185 * while "as" needs access to the private constructor.
186 * In case of the "isa" method, all instances are made friends
187 * to avoid access right confusion.
189 void cpp_generator::print_subclass_type(ostream &os, const isl_class &clazz)
191 std::string cppstring = type2cpp(clazz);
192 std::string super;
193 const char *cppname = cppstring.c_str();
194 const char *supername;
196 if (!clazz.is_type_subclass())
197 return;
199 super = type2cpp(clazz.superclass_name);
200 supername = super.c_str();
201 osprintf(os, " template <class T>\n");
202 osprintf(os, " friend %s %s::isa() const;\n",
203 isl_bool2cpp().c_str(), supername);
204 osprintf(os, " friend %s %s::as<%s>() const;\n",
205 cppname, supername, cppname);
206 osprintf(os, " static const auto type = %s;\n",
207 clazz.subclass_name.c_str());
210 /* Print declarations for class "clazz" to "os".
212 * If "clazz" is a subclass based on a type function,
213 * then it is made to inherit from the (immediate) superclass and
214 * a "type" attribute is added for use in the "as" and "isa"
215 * methods of the superclass.
217 * Conversely, if "clazz" is a superclass with a type function,
218 * then declare those "as" and "isa" methods.
220 * The pointer to the isl object is only added for classes that
221 * are not subclasses, since subclasses refer to the same isl object.
223 void cpp_generator::print_class(ostream &os, const isl_class &clazz)
225 const char *name = clazz.name.c_str();
226 std::string cppstring = type2cpp(clazz);
227 const char *cppname = cppstring.c_str();
229 osprintf(os, "// declarations for isl::%s\n", cppname);
231 print_class_factory_decl(os, clazz);
232 osprintf(os, "\n");
233 osprintf(os, "class %s ", cppname);
234 if (clazz.is_type_subclass())
235 osprintf(os, ": public %s ",
236 type2cpp(clazz.superclass_name).c_str());
237 osprintf(os, "{\n");
238 print_subclass_type(os, clazz);
239 print_class_factory_decl(os, clazz, " friend ");
240 osprintf(os, "\n");
241 osprintf(os, "protected:\n");
242 if (!clazz.is_type_subclass()) {
243 osprintf(os, " %s *ptr = nullptr;\n", name);
244 osprintf(os, "\n");
246 print_protected_constructors_decl(os, clazz);
247 osprintf(os, "\n");
248 osprintf(os, "public:\n");
249 print_public_constructors_decl(os, clazz);
250 print_constructors_decl(os, clazz);
251 print_copy_assignment_decl(os, clazz);
252 print_destructor_decl(os, clazz);
253 print_ptr_decl(os, clazz);
254 print_downcast_decl(os, clazz);
255 print_ctx_decl(os);
256 osprintf(os, "\n");
257 print_persistent_callbacks_decl(os, clazz);
258 print_methods_decl(os, clazz);
259 print_set_enums_decl(os, clazz);
261 osprintf(os, "};\n");
264 /* Print forward declaration of class "clazz" to "os".
266 void cpp_generator::print_class_forward_decl(ostream &os,
267 const isl_class &clazz)
269 std::string cppstring = type2cpp(clazz);
270 const char *cppname = cppstring.c_str();
272 osprintf(os, "class %s;\n", cppname);
275 /* Print global factory functions to "os".
277 * Each class has two global factory functions:
279 * set manage(__isl_take isl_set *ptr);
280 * set manage_copy(__isl_keep isl_set *ptr);
282 * A user can construct isl C++ objects from a raw pointer and indicate whether
283 * they intend to take the ownership of the object or not through these global
284 * factory functions. This ensures isl object creation is very explicit and
285 * pointers are not converted by accident. Thanks to overloading, manage() and
286 * manage_copy() can be called on any isl raw pointer and the corresponding
287 * object is automatically created, without the user having to choose the right
288 * isl object type.
290 * For a subclass based on a type function, no factory functions
291 * are introduced because they share the C object type with
292 * the superclass.
294 void cpp_generator::print_class_factory_decl(ostream &os,
295 const isl_class &clazz, const std::string &prefix)
297 const char *name = clazz.name.c_str();
298 std::string cppstring = type2cpp(clazz);
299 const char *cppname = cppstring.c_str();
301 if (clazz.is_type_subclass())
302 return;
304 os << prefix;
305 osprintf(os, "inline %s manage(__isl_take %s *ptr);\n", cppname, name);
306 os << prefix;
307 osprintf(os, "inline %s manage_copy(__isl_keep %s *ptr);\n",
308 cppname, name);
311 /* Print declarations of protected constructors for class "clazz" to "os".
313 * Each class has currently one protected constructor:
315 * 1) Constructor from a plain isl_* C pointer
317 * Example:
319 * set(__isl_take isl_set *ptr);
321 * The raw pointer constructor is kept protected. Object creation is only
322 * possible through manage() or manage_copy().
324 void cpp_generator::print_protected_constructors_decl(ostream &os,
325 const isl_class &clazz)
327 const char *name = clazz.name.c_str();
328 std::string cppstring = type2cpp(clazz);
329 const char *cppname = cppstring.c_str();
331 osprintf(os, " inline explicit %s(__isl_take %s *ptr);\n", cppname,
332 name);
335 /* Print declarations of public constructors for class "clazz" to "os".
337 * Each class currently has two public constructors:
339 * 1) A default constructor
340 * 2) A copy constructor
342 * Example:
344 * set();
345 * set(const set &set);
347 void cpp_generator::print_public_constructors_decl(ostream &os,
348 const isl_class &clazz)
350 std::string cppstring = type2cpp(clazz);
351 const char *cppname = cppstring.c_str();
352 osprintf(os, " inline /* implicit */ %s();\n", cppname);
354 osprintf(os, " inline /* implicit */ %s(const %s &obj);\n",
355 cppname, cppname);
358 /* Print declarations for constructors for class "class" to "os".
360 * For each isl function that is marked as __isl_constructor,
361 * add a corresponding C++ constructor.
363 * Example:
365 * inline /\* implicit *\/ union_set(basic_set bset);
366 * inline /\* implicit *\/ union_set(set set);
367 * inline explicit val(ctx ctx, long i);
368 * inline explicit val(ctx ctx, const std::string &str);
370 void cpp_generator::print_constructors_decl(ostream &os,
371 const isl_class &clazz)
373 set<FunctionDecl *>::const_iterator in;
374 const set<FunctionDecl *> &constructors = clazz.constructors;
376 for (in = constructors.begin(); in != constructors.end(); ++in) {
377 FunctionDecl *cons = *in;
379 print_method_decl(os, clazz, cons, function_kind_constructor);
383 /* Print declarations of copy assignment operator for class "clazz"
384 * to "os".
386 * Each class has one assignment operator.
388 * isl:set &set::operator=(set obj)
391 void cpp_generator::print_copy_assignment_decl(ostream &os,
392 const isl_class &clazz)
394 std::string cppstring = type2cpp(clazz);
395 const char *cppname = cppstring.c_str();
397 osprintf(os, " inline %s &operator=(%s obj);\n", cppname, cppname);
400 /* Print declaration of destructor for class "clazz" to "os".
402 * No explicit destructor is needed for type based subclasses.
404 void cpp_generator::print_destructor_decl(ostream &os, const isl_class &clazz)
406 std::string cppstring = type2cpp(clazz);
407 const char *cppname = cppstring.c_str();
409 if (clazz.is_type_subclass())
410 return;
412 osprintf(os, " inline ~%s();\n", cppname);
415 /* Print declaration of pointer functions for class "clazz" to "os".
416 * Since type based subclasses share the pointer with their superclass,
417 * they can also reuse these functions from the superclass.
419 * To obtain a raw pointer three functions are provided:
421 * 1) __isl_give isl_set *copy()
423 * Returns a pointer to a _copy_ of the internal object
425 * 2) __isl_keep isl_set *get()
427 * Returns a pointer to the internal object
429 * 3) __isl_give isl_set *release()
431 * Returns a pointer to the internal object and resets the
432 * internal pointer to nullptr.
434 * We also provide functionality to explicitly check if a pointer is
435 * currently managed by this object.
437 * 4) bool is_null()
439 * Check if the current object is a null pointer.
441 * The functions get() and release() model the value_ptr proposed in
442 * http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2012/n3339.pdf.
443 * The copy() function is an extension to allow the user to explicitly
444 * copy the underlying object.
446 * Also generate a declaration to delete copy() for r-values, for
447 * r-values release() should be used to avoid unnecessary copies.
449 void cpp_generator::print_ptr_decl(ostream &os, const isl_class &clazz)
451 const char *name = clazz.name.c_str();
453 if (clazz.is_type_subclass())
454 return;
456 osprintf(os, " inline __isl_give %s *copy() const &;\n", name);
457 osprintf(os, " inline __isl_give %s *copy() && = delete;\n", name);
458 osprintf(os, " inline __isl_keep %s *get() const;\n", name);
459 osprintf(os, " inline __isl_give %s *release();\n", name);
460 osprintf(os, " inline bool is_null() const;\n");
463 /* Print a template declaration with given indentation
464 * for the "isa_type" method that ensures it is only enabled
465 * when called with a template argument
466 * that represents a type that is equal to that
467 * of the return type of the type function of "super".
468 * In particular, "isa_type" gets called from "isa"
469 * with as template argument the type of the "type" field
470 * of the subclass.
471 * The check ensures that this subclass is in fact a direct subclass
472 * of "super".
474 void cpp_generator::print_isa_type_template(ostream &os, int indent,
475 const isl_class &super)
477 osprintf(os, indent,
478 "template <typename T,\n");
479 osprintf(os, indent,
480 " typename = typename std::enable_if<std::is_same<\n");
481 osprintf(os, indent,
482 " const decltype(%s(NULL)),\n",
483 super.fn_type->getNameAsString().c_str());
484 osprintf(os, indent,
485 " const T>::value>::type>\n");
488 /* Print declarations for the "as" and "isa" methods, if "clazz"
489 * is a superclass with a type function.
491 * "isa" checks whether an object is of a given subclass type.
492 * "isa_type" does the same, but gets passed the value of the type field
493 * of the subclass as a function argument and the type of this field
494 * as a template argument.
495 * "as" tries to cast an object to a given subclass type, returning
496 * an invalid object if the object is not of the given type.
498 void cpp_generator::print_downcast_decl(ostream &os, const isl_class &clazz)
500 if (!clazz.fn_type)
501 return;
503 osprintf(os, "private:\n");
504 print_isa_type_template(os, 2, clazz);
505 osprintf(os, " inline %s isa_type(T subtype) const;\n",
506 isl_bool2cpp().c_str());
507 osprintf(os, "public:\n");
508 osprintf(os, " template <class T> inline %s isa() const;\n",
509 isl_bool2cpp().c_str());
510 osprintf(os, " template <class T> inline T as() const;\n");
513 /* Print the declaration of the ctx method.
515 void cpp_generator::print_ctx_decl(ostream &os)
517 std::string ns = isl_namespace();
519 osprintf(os, " inline %sctx ctx() const;\n", ns.c_str());
522 /* Add a space to the return type "type" if needed,
523 * i.e., if it is not the type of a pointer.
525 static string add_space_to_return_type(const string &type)
527 if (type[type.size() - 1] == '*')
528 return type;
529 return type + " ";
532 /* Print the prototype of the static inline method that is used
533 * as the C callback of "clazz" set by "method" to "os".
535 void cpp_generator::print_persistent_callback_prototype(ostream &os,
536 const isl_class &clazz, FunctionDecl *method, bool is_declaration)
538 string callback_name, rettype, c_args;
539 ParmVarDecl *param = persistent_callback_arg(method);
540 const FunctionProtoType *callback;
541 QualType ptype;
542 string classname;
544 ptype = param->getType();
545 callback = extract_prototype(ptype);
547 rettype = callback->getReturnType().getAsString();
548 rettype = add_space_to_return_type(rettype);
549 callback_name = clazz.persistent_callback_name(method);
550 c_args = generate_callback_args(ptype, false);
552 if (!is_declaration)
553 classname = type2cpp(clazz) + "::";
555 osprintf(os, "%s%s%s(%s)",
556 rettype.c_str(), classname.c_str(),
557 callback_name.c_str(), c_args.c_str());
560 /* Print the prototype of the method for setting the callback function
561 * of "clazz" set by "method" to "os".
563 void cpp_generator::print_persistent_callback_setter_prototype(ostream &os,
564 const isl_class &clazz, FunctionDecl *method, bool is_declaration)
566 string classname, callback_name, cpptype;
567 ParmVarDecl *param = persistent_callback_arg(method);
569 if (!is_declaration)
570 classname = type2cpp(clazz) + "::";
572 cpptype = type2cpp(param->getOriginalType());
573 callback_name = clazz.persistent_callback_name(method);
574 osprintf(os, "void %sset_%s_data(const %s &%s)",
575 classname.c_str(), callback_name.c_str(), cpptype.c_str(),
576 param->getName().str().c_str());
579 /* Given a function "method" for setting a "clazz" persistent callback,
580 * print the fields that are needed for marshalling the callback to "os".
582 * In particular, print
583 * - the declaration of a data structure for storing the C++ callback function
584 * - a shared pointer to such a data structure
585 * - the declaration of a static inline method
586 * for use as the C callback function
587 * - the declaration of a private method for setting the callback function
589 void cpp_generator::print_persistent_callback_data(ostream &os,
590 const isl_class &clazz, FunctionDecl *method)
592 string callback_name;
593 ParmVarDecl *param = persistent_callback_arg(method);
595 callback_name = clazz.persistent_callback_name(method);
596 print_callback_data_decl(os, param, callback_name);
597 osprintf(os, ";\n");
598 osprintf(os, " std::shared_ptr<%s_data> %s_data;\n",
599 callback_name.c_str(), callback_name.c_str());
600 osprintf(os, " static inline ");
601 print_persistent_callback_prototype(os, clazz, method, true);
602 osprintf(os, ";\n");
603 osprintf(os, " inline ");
604 print_persistent_callback_setter_prototype(os, clazz, method, true);
605 osprintf(os, ";\n");
608 /* Print declarations needed for the persistent callbacks of "clazz".
610 * In particular, if there are any persistent callbacks, then
611 * print a private method for copying callback data from
612 * one object to another,
613 * private data for keeping track of the persistent callbacks and
614 * public methods for setting the persistent callbacks.
616 void cpp_generator::print_persistent_callbacks_decl(ostream &os,
617 const isl_class &clazz)
619 std::string cppstring = type2cpp(clazz);
620 const char *cppname = cppstring.c_str();
621 set<FunctionDecl *>::const_iterator in;
622 const set<FunctionDecl *> &callbacks = clazz.persistent_callbacks;
624 if (!clazz.has_persistent_callbacks())
625 return;
627 osprintf(os, "private:\n");
628 osprintf(os, " inline %s &copy_callbacks(const %s &obj);\n",
629 cppname, cppname);
630 for (in = callbacks.begin(); in != callbacks.end(); ++in)
631 print_persistent_callback_data(os, clazz, *in);
633 osprintf(os, "public:\n");
634 for (in = callbacks.begin(); in != callbacks.end(); ++in)
635 print_method_decl(os, clazz, *in, function_kind_member_method);
638 /* Print declarations for methods in class "clazz" to "os".
640 void cpp_generator::print_methods_decl(ostream &os, const isl_class &clazz)
642 map<string, set<FunctionDecl *> >::const_iterator it;
644 for (it = clazz.methods.begin(); it != clazz.methods.end(); ++it)
645 print_method_group_decl(os, clazz, it->second);
648 /* Print a declaration for a method "name" in "clazz" derived
649 * from "fd", which sets an enum, to "os".
651 * The last argument is removed because it is replaced by
652 * a break-up into several methods.
654 void cpp_generator::print_set_enum_decl(ostream &os, const isl_class &clazz,
655 FunctionDecl *fd, const string &name)
657 int n = fd->getNumParams();
659 print_method_header(os, clazz, fd, name, n - 1, true,
660 function_kind_member_method);
663 /* Print declarations for the methods in "clazz" derived from "fd",
664 * which sets an enum, to "os".
666 * A method is generated for each value in the enum, setting
667 * the enum to that value.
669 void cpp_generator::print_set_enums_decl(ostream &os, const isl_class &clazz,
670 FunctionDecl *fd)
672 vector<set_enum>::const_iterator it;
673 const vector<set_enum> &set_enums = clazz.set_enums.at(fd);
675 for (it = set_enums.begin(); it != set_enums.end(); ++it)
676 print_set_enum_decl(os, clazz, fd, it->method_name);
679 /* Print declarations for methods in "clazz" derived from functions
680 * that set an enum, to "os".
682 void cpp_generator::print_set_enums_decl(ostream &os, const isl_class &clazz)
684 map<FunctionDecl *, vector<set_enum> >::const_iterator it;
686 for (it = clazz.set_enums.begin(); it != clazz.set_enums.end(); ++it)
687 print_set_enums_decl(os, clazz, it->first);
690 /* Print declarations for methods "methods" in class "clazz" to "os".
692 * For methods that are identified as "get" methods, also
693 * print a declaration for the method using a name that includes
694 * the "get_" prefix.
696 void cpp_generator::print_method_group_decl(ostream &os, const isl_class &clazz,
697 const set<FunctionDecl *> &methods)
699 set<FunctionDecl *>::const_iterator it;
701 for (it = methods.begin(); it != methods.end(); ++it) {
702 function_kind kind = get_method_kind(clazz, *it);
703 print_method_decl(os, clazz, *it, kind);
704 if (clazz.is_get_method(*it)) {
705 string base = clazz.base_method_name(*it);
706 print_named_method_decl(os, clazz, *it, base, kind);
711 /* Print a declaration for a method called "name" in class "clazz"
712 * derived from "fd" to "os".
714 * "kind" specifies the kind of method that should be generated.
716 void cpp_generator::print_named_method_decl(ostream &os, const isl_class &clazz,
717 FunctionDecl *fd, const string &name, function_kind kind)
719 print_named_method_header(os, clazz, fd, name, true, kind);
722 /* Print declarations for "method" in class "clazz" to "os".
724 * "kind" specifies the kind of method that should be generated.
726 void cpp_generator::print_method_decl(ostream &os, const isl_class &clazz,
727 FunctionDecl *method, function_kind kind)
729 string name = clazz.method_name(method);
731 print_named_method_decl(os, clazz, method, name, kind);
734 /* Print implementations for class "clazz" to "os".
736 void cpp_generator::print_class_impl(ostream &os, const isl_class &clazz)
738 std::string cppstring = type2cpp(clazz);
739 const char *cppname = cppstring.c_str();
741 osprintf(os, "// implementations for isl::%s\n", cppname);
743 print_class_factory_impl(os, clazz);
744 osprintf(os, "\n");
745 print_public_constructors_impl(os, clazz);
746 osprintf(os, "\n");
747 print_protected_constructors_impl(os, clazz);
748 osprintf(os, "\n");
749 print_constructors_impl(os, clazz);
750 osprintf(os, "\n");
751 print_copy_assignment_impl(os, clazz);
752 osprintf(os, "\n");
753 print_destructor_impl(os, clazz);
754 osprintf(os, "\n");
755 print_ptr_impl(os, clazz);
756 osprintf(os, "\n");
757 if (print_downcast_impl(os, clazz))
758 osprintf(os, "\n");
759 print_ctx_impl(os, clazz);
760 osprintf(os, "\n");
761 print_persistent_callbacks_impl(os, clazz);
762 print_methods_impl(os, clazz);
763 print_set_enums_impl(os, clazz);
764 print_stream_insertion(os, clazz);
767 /* Print code for throwing an exception corresponding to the last error
768 * that occurred on "saved_ctx".
769 * This assumes that a valid isl::ctx is available in the "saved_ctx" variable,
770 * e.g., through a prior call to print_save_ctx.
772 static void print_throw_last_error(ostream &os)
774 osprintf(os, " exception::throw_last_error(saved_ctx);\n");
777 /* Print code with the given indentation
778 * for throwing an exception_invalid with the given message.
780 static void print_throw_invalid(ostream &os, int indent, const char *msg)
782 osprintf(os, indent,
783 "exception::throw_invalid(\"%s\", __FILE__, __LINE__);\n", msg);
786 /* Print code for throwing an exception on NULL input.
788 static void print_throw_NULL_input(ostream &os)
790 print_throw_invalid(os, 4, "NULL input");
793 /* Print code with the given indentation
794 * for acting on an invalid error with message "msg".
795 * In particular, throw an exception_invalid.
796 * In the checked C++ bindings, isl_die is called instead with the code
797 * in "checked_code".
799 void cpp_generator::print_invalid(ostream &os, int indent, const char *msg,
800 const char *checked_code)
802 if (checked)
803 osprintf(os, indent,
804 "isl_die(ctx().get(), isl_error_invalid, "
805 "\"%s\", %s);\n", msg, checked_code);
806 else
807 print_throw_invalid(os, indent, msg);
810 /* Print an operator for inserting objects of "class"
811 * into an output stream.
813 * Unless checked C++ bindings are being generated,
814 * the operator requires its argument to be non-NULL.
815 * An exception is thrown if anything went wrong during the printing.
816 * During this printing, isl is made not to print any error message
817 * because the error message is included in the exception.
819 * If checked C++ bindings are being generated and anything went wrong,
820 * then record this failure in the output stream.
822 void cpp_generator::print_stream_insertion(ostream &os, const isl_class &clazz)
824 const char *name = clazz.name.c_str();
825 std::string cppstring = type2cpp(clazz);
826 const char *cppname = cppstring.c_str();
828 if (!clazz.fn_to_str)
829 return;
831 osprintf(os, "\n");
832 osprintf(os, "inline std::ostream &operator<<(std::ostream &os, ");
833 osprintf(os, "const %s &obj)\n", cppname);
834 osprintf(os, "{\n");
835 print_check_ptr_start(os, clazz, "obj.get()");
836 osprintf(os, " char *str = %s_to_str(obj.get());\n", name);
837 print_check_ptr_end(os, "str");
838 if (checked) {
839 osprintf(os, " if (!str) {\n");
840 osprintf(os, " os.setstate(std::ios_base::badbit);\n");
841 osprintf(os, " return os;\n");
842 osprintf(os, " }\n");
844 osprintf(os, " os << str;\n");
845 osprintf(os, " free(str);\n");
846 osprintf(os, " return os;\n");
847 osprintf(os, "}\n");
850 /* Print code that checks that "ptr" is not NULL at input.
852 * Omit the check if checked C++ bindings are being generated.
854 void cpp_generator::print_check_ptr(ostream &os, const char *ptr)
856 if (checked)
857 return;
859 osprintf(os, " if (!%s)\n", ptr);
860 print_throw_NULL_input(os);
863 /* Print code that checks that "ptr" is not NULL at input and
864 * that saves a copy of the isl_ctx of "ptr" for a later check.
866 * Omit the check if checked C++ bindings are being generated.
868 void cpp_generator::print_check_ptr_start(ostream &os, const isl_class &clazz,
869 const char *ptr)
871 if (checked)
872 return;
874 print_check_ptr(os, ptr);
875 osprintf(os, " auto saved_ctx = %s_get_ctx(%s);\n",
876 clazz.name.c_str(), ptr);
877 print_on_error_continue(os);
880 /* Print code that checks that "ptr" is not NULL at the end.
881 * A copy of the isl_ctx is expected to have been saved by
882 * code generated by print_check_ptr_start.
884 * Omit the check if checked C++ bindings are being generated.
886 void cpp_generator::print_check_ptr_end(ostream &os, const char *ptr)
888 if (checked)
889 return;
891 osprintf(os, " if (!%s)\n", ptr);
892 print_throw_last_error(os);
895 /* Print implementation of global factory functions to "os".
897 * Each class has two global factory functions:
899 * set manage(__isl_take isl_set *ptr);
900 * set manage_copy(__isl_keep isl_set *ptr);
902 * Unless checked C++ bindings are being generated,
903 * both functions require the argument to be non-NULL.
904 * An exception is thrown if anything went wrong during the copying
905 * in manage_copy.
906 * During the copying, isl is made not to print any error message
907 * because the error message is included in the exception.
909 * For a subclass based on a type function, no factory functions
910 * are introduced because they share the C object type with
911 * the superclass.
913 void cpp_generator::print_class_factory_impl(ostream &os,
914 const isl_class &clazz)
916 const char *name = clazz.name.c_str();
917 std::string cppstring = type2cpp(clazz);
918 const char *cppname = cppstring.c_str();
920 if (clazz.is_type_subclass())
921 return;
923 osprintf(os, "%s manage(__isl_take %s *ptr) {\n", cppname, name);
924 print_check_ptr(os, "ptr");
925 osprintf(os, " return %s(ptr);\n", cppname);
926 osprintf(os, "}\n");
928 osprintf(os, "%s manage_copy(__isl_keep %s *ptr) {\n", cppname,
929 name);
930 print_check_ptr_start(os, clazz, "ptr");
931 osprintf(os, " ptr = %s_copy(ptr);\n", name);
932 print_check_ptr_end(os, "ptr");
933 osprintf(os, " return %s(ptr);\n", cppname);
934 osprintf(os, "}\n");
937 /* Print implementations of protected constructors for class "clazz" to "os".
939 * The pointer to the isl object is either initialized directly or
940 * through the (immediate) superclass.
942 void cpp_generator::print_protected_constructors_impl(ostream &os,
943 const isl_class &clazz)
945 const char *name = clazz.name.c_str();
946 std::string cppstring = type2cpp(clazz);
947 const char *cppname = cppstring.c_str();
948 bool subclass = clazz.is_type_subclass();
950 osprintf(os, "%s::%s(__isl_take %s *ptr)\n", cppname, cppname, name);
951 if (subclass)
952 osprintf(os, " : %s(ptr) {}\n",
953 type2cpp(clazz.superclass_name).c_str());
954 else
955 osprintf(os, " : ptr(ptr) {}\n");
958 /* Print implementations of public constructors for class "clazz" to "os".
960 * The pointer to the isl object is either initialized directly or
961 * through the (immediate) superclass.
963 * If the class has any persistent callbacks, then copy them
964 * from the original object in the copy constructor.
965 * If the class is a subclass, then the persistent callbacks
966 * are assumed to be copied by the copy constructor of the superclass.
968 * Throw an exception from the copy constructor if anything went wrong
969 * during the copying or if the input is NULL, if any copying is performed.
970 * During the copying, isl is made not to print any error message
971 * because the error message is included in the exception.
972 * No exceptions are thrown if checked C++ bindings
973 * are being generated,
975 void cpp_generator::print_public_constructors_impl(ostream &os,
976 const isl_class &clazz)
978 std::string cppstring = type2cpp(clazz);
979 std::string super;
980 const char *cppname = cppstring.c_str();
981 bool subclass = clazz.is_type_subclass();
983 if (subclass)
984 super = type2cpp(clazz.superclass_name);
985 osprintf(os, "%s::%s()\n", cppname, cppname);
986 if (subclass)
987 osprintf(os, " : %s() {}\n\n", super.c_str());
988 else
989 osprintf(os, " : ptr(nullptr) {}\n\n");
990 osprintf(os, "%s::%s(const %s &obj)\n", cppname, cppname, cppname);
991 if (subclass)
992 osprintf(os, " : %s(obj)\n", super.c_str());
993 else
994 osprintf(os, " : ptr(nullptr)\n");
995 osprintf(os, "{\n");
996 if (!subclass) {
997 print_check_ptr_start(os, clazz, "obj.ptr");
998 osprintf(os, " ptr = obj.copy();\n");
999 if (clazz.has_persistent_callbacks())
1000 osprintf(os, " copy_callbacks(obj);\n");
1001 print_check_ptr_end(os, "ptr");
1003 osprintf(os, "}\n");
1006 /* Print implementations of constructors for class "clazz" to "os".
1008 void cpp_generator::print_constructors_impl(ostream &os,
1009 const isl_class &clazz)
1011 set<FunctionDecl *>::const_iterator in;
1012 const set<FunctionDecl *> constructors = clazz.constructors;
1014 for (in = constructors.begin(); in != constructors.end(); ++in) {
1015 FunctionDecl *cons = *in;
1017 print_method_impl(os, clazz, cons, function_kind_constructor);
1021 /* Print implementation of copy assignment operator for class "clazz" to "os".
1023 * If the class has any persistent callbacks, then copy them
1024 * from the original object.
1026 void cpp_generator::print_copy_assignment_impl(ostream &os,
1027 const isl_class &clazz)
1029 const char *name = clazz.name.c_str();
1030 std::string cppstring = type2cpp(clazz);
1031 const char *cppname = cppstring.c_str();
1033 osprintf(os, "%s &%s::operator=(%s obj) {\n", cppname,
1034 cppname, cppname);
1035 osprintf(os, " std::swap(this->ptr, obj.ptr);\n", name);
1036 if (clazz.has_persistent_callbacks())
1037 osprintf(os, " copy_callbacks(obj);\n");
1038 osprintf(os, " return *this;\n");
1039 osprintf(os, "}\n");
1042 /* Print implementation of destructor for class "clazz" to "os".
1044 * No explicit destructor is needed for type based subclasses.
1046 void cpp_generator::print_destructor_impl(ostream &os,
1047 const isl_class &clazz)
1049 const char *name = clazz.name.c_str();
1050 std::string cppstring = type2cpp(clazz);
1051 const char *cppname = cppstring.c_str();
1053 if (clazz.is_type_subclass())
1054 return;
1056 osprintf(os, "%s::~%s() {\n", cppname, cppname);
1057 osprintf(os, " if (ptr)\n");
1058 osprintf(os, " %s_free(ptr);\n", name);
1059 osprintf(os, "}\n");
1062 /* Print a check that the persistent callback corresponding to "fd"
1063 * is not set, throwing an exception (or printing an error message
1064 * and returning nullptr) if it is set.
1066 void cpp_generator::print_check_no_persistent_callback(ostream &os,
1067 const isl_class &clazz, FunctionDecl *fd)
1069 string callback_name = clazz.persistent_callback_name(fd);
1071 osprintf(os, " if (%s_data)\n", callback_name.c_str());
1072 print_invalid(os, 4, "cannot release object with persistent callbacks",
1073 "return nullptr");
1076 /* Print implementation of ptr() functions for class "clazz" to "os".
1077 * Since type based subclasses share the pointer with their superclass,
1078 * they can also reuse these functions from the superclass.
1080 * If an object has persistent callbacks set, then the underlying
1081 * C object pointer cannot be released because it references data
1082 * in the C++ object.
1084 void cpp_generator::print_ptr_impl(ostream &os, const isl_class &clazz)
1086 const char *name = clazz.name.c_str();
1087 std::string cppstring = type2cpp(clazz);
1088 const char *cppname = cppstring.c_str();
1089 set<FunctionDecl *>::const_iterator in;
1090 const set<FunctionDecl *> &callbacks = clazz.persistent_callbacks;
1092 if (clazz.is_type_subclass())
1093 return;
1095 osprintf(os, "__isl_give %s *%s::copy() const & {\n", name, cppname);
1096 osprintf(os, " return %s_copy(ptr);\n", name);
1097 osprintf(os, "}\n\n");
1098 osprintf(os, "__isl_keep %s *%s::get() const {\n", name, cppname);
1099 osprintf(os, " return ptr;\n");
1100 osprintf(os, "}\n\n");
1101 osprintf(os, "__isl_give %s *%s::release() {\n", name, cppname);
1102 for (in = callbacks.begin(); in != callbacks.end(); ++in)
1103 print_check_no_persistent_callback(os, clazz, *in);
1104 osprintf(os, " %s *tmp = ptr;\n", name);
1105 osprintf(os, " ptr = nullptr;\n");
1106 osprintf(os, " return tmp;\n");
1107 osprintf(os, "}\n\n");
1108 osprintf(os, "bool %s::is_null() const {\n", cppname);
1109 osprintf(os, " return ptr == nullptr;\n");
1110 osprintf(os, "}\n");
1113 /* Print implementations for the "as" and "isa" methods, if "clazz"
1114 * is a superclass with a type function.
1116 * "isa" checks whether an object is of a given subclass type.
1117 * "isa_type" does the same, but gets passed the value of the type field
1118 * of the subclass as a function argument and the type of this field
1119 * as a template argument.
1120 * "as" casts an object to a given subclass type, erroring out
1121 * if the object is not of the given type.
1123 * If the input is an invalid object, then these methods raise
1124 * an exception.
1125 * If checked bindings are being generated,
1126 * then an invalid boolean or object is returned instead.
1128 * Return true if anything was printed.
1130 bool cpp_generator::print_downcast_impl(ostream &os, const isl_class &clazz)
1132 std::string cppstring = type2cpp(clazz);
1133 const char *cppname = cppstring.c_str();
1135 if (!clazz.fn_type)
1136 return false;
1138 osprintf(os, "template <typename T, typename>\n");
1139 osprintf(os, "%s %s::isa_type(T subtype) const\n",
1140 isl_bool2cpp().c_str(), cppname);
1141 osprintf(os, "{\n");
1142 osprintf(os, " if (is_null())\n");
1143 if (checked)
1144 osprintf(os, " return boolean();\n");
1145 else
1146 print_throw_NULL_input(os);
1147 osprintf(os, " return %s(get()) == subtype;\n",
1148 clazz.fn_type->getNameAsString().c_str());
1149 osprintf(os, "}\n");
1151 osprintf(os, "template <class T>\n");
1152 osprintf(os, "%s %s::isa() const\n", isl_bool2cpp().c_str(), cppname);
1153 osprintf(os, "{\n");
1154 osprintf(os, " return isa_type<decltype(T::type)>(T::type);\n");
1155 osprintf(os, "}\n");
1157 osprintf(os, "template <class T>\n");
1158 osprintf(os, "T %s::as() const\n", cppname);
1159 osprintf(os, "{\n");
1160 if (checked)
1161 osprintf(os, " if (isa<T>().is_false())\n");
1162 else
1163 osprintf(os, " if (!isa<T>())\n");
1164 print_invalid(os, 4, "not an object of the requested subtype",
1165 "return T()");
1166 osprintf(os, " return T(copy());\n");
1167 osprintf(os, "}\n");
1169 return true;
1172 /* Print the implementation of the ctx method.
1174 void cpp_generator::print_ctx_impl(ostream &os, const isl_class &clazz)
1176 const char *name = clazz.name.c_str();
1177 std::string cppstring = type2cpp(clazz);
1178 const char *cppname = cppstring.c_str();
1179 std::string ns = isl_namespace();
1181 osprintf(os, "%sctx %s::ctx() const {\n", ns.c_str(), cppname);
1182 osprintf(os, " return %sctx(%s_get_ctx(ptr));\n", ns.c_str(), name);
1183 osprintf(os, "}\n");
1186 /* Print the implementations of the methods needed for the persistent callbacks
1187 * of "clazz".
1189 void cpp_generator::print_persistent_callbacks_impl(ostream &os,
1190 const isl_class &clazz)
1192 std::string cppstring = type2cpp(clazz);
1193 const char *cppname = cppstring.c_str();
1194 string classname = type2cpp(clazz);
1195 set<FunctionDecl *>::const_iterator in;
1196 const set<FunctionDecl *> &callbacks = clazz.persistent_callbacks;
1198 if (!clazz.has_persistent_callbacks())
1199 return;
1201 osprintf(os, "%s &%s::copy_callbacks(const %s &obj)\n",
1202 cppname, classname.c_str(), cppname);
1203 osprintf(os, "{\n");
1204 for (in = callbacks.begin(); in != callbacks.end(); ++in) {
1205 string callback_name = clazz.persistent_callback_name(*in);
1207 osprintf(os, " %s_data = obj.%s_data;\n",
1208 callback_name.c_str(), callback_name.c_str());
1210 osprintf(os, " return *this;\n");
1211 osprintf(os, "}\n\n");
1213 for (in = callbacks.begin(); in != callbacks.end(); ++in) {
1214 function_kind kind = function_kind_member_method;
1216 print_set_persistent_callback(os, clazz, *in, kind);
1220 /* Print definitions for methods of class "clazz" to "os".
1222 void cpp_generator::print_methods_impl(ostream &os, const isl_class &clazz)
1224 map<string, set<FunctionDecl *> >::const_iterator it;
1225 bool first = true;
1227 for (it = clazz.methods.begin(); it != clazz.methods.end(); ++it) {
1228 if (first)
1229 first = false;
1230 else
1231 osprintf(os, "\n");
1232 print_method_group_impl(os, clazz, it->second);
1236 /* Print the definition for a method "method_name" in "clazz" derived
1237 * from "fd", which sets an enum, to "os".
1238 * In particular, the method "method_name" sets the enum to "enum_name".
1240 * The last argument of the C function does not appear in the method call,
1241 * but is fixed to "enum_name" instead.
1242 * Other than that, the method printed here is similar to one
1243 * printed by cpp_generator::print_method_impl, except that
1244 * some of the special cases do not occur.
1246 void cpp_generator::print_set_enum_impl(ostream &os, const isl_class &clazz,
1247 FunctionDecl *fd, const string &enum_name, const string &method_name)
1249 string c_name = fd->getName();
1250 int n = fd->getNumParams();
1251 function_kind kind = function_kind_member_method;
1253 print_method_header(os, clazz, fd, method_name, n - 1, false, kind);
1254 osprintf(os, "{\n");
1256 print_argument_validity_check(os, fd, kind);
1257 print_save_ctx(os, fd, kind);
1258 print_on_error_continue(os);
1260 osprintf(os, " auto res = %s(", c_name.c_str());
1262 for (int i = 0; i < n - 1; ++i) {
1263 ParmVarDecl *param = fd->getParamDecl(i);
1265 if (i > 0)
1266 osprintf(os, ", ");
1267 print_method_param_use(os, param, i == 0);
1269 osprintf(os, ", %s", enum_name.c_str());
1270 osprintf(os, ");\n");
1272 print_exceptional_execution_check(os, clazz, fd, kind);
1273 print_method_return(os, clazz, fd);
1275 osprintf(os, "}\n");
1278 /* Print definitions for the methods in "clazz" derived from "fd",
1279 * which sets an enum, to "os".
1281 * A method is generated for each value in the enum, setting
1282 * the enum to that value.
1284 void cpp_generator::print_set_enums_impl(ostream &os, const isl_class &clazz,
1285 FunctionDecl *fd)
1287 vector<set_enum>::const_iterator it;
1288 const vector<set_enum> &set_enums = clazz.set_enums.at(fd);
1290 for (it = set_enums.begin(); it != set_enums.end(); ++it) {
1291 osprintf(os, "\n");
1292 print_set_enum_impl(os, clazz, fd, it->name, it->method_name);
1296 /* Print definitions for methods in "clazz" derived from functions
1297 * that set an enum, to "os".
1299 void cpp_generator::print_set_enums_impl(ostream &os, const isl_class &clazz)
1301 map<FunctionDecl *, vector<set_enum> >::const_iterator it;
1303 for (it = clazz.set_enums.begin(); it != clazz.set_enums.end(); ++it)
1304 print_set_enums_impl(os, clazz, it->first);
1307 /* Print a definition for the "get" method "fd" in class "clazz",
1308 * using a name that includes the "get_" prefix, to "os".
1310 * This definition simply calls the variant without the "get_" prefix and
1311 * returns its result.
1312 * Note that static methods are not considered to be "get" methods.
1314 void cpp_generator::print_get_method_impl(ostream &os, const isl_class &clazz,
1315 FunctionDecl *fd)
1317 string get_name = clazz.base_method_name(fd);
1318 string name = clazz.method_name(fd);
1319 function_kind kind = function_kind_member_method;
1320 int num_params = fd->getNumParams();
1322 print_named_method_header(os, clazz, fd, get_name, false, kind);
1323 osprintf(os, "{\n");
1324 osprintf(os, " return %s(", name.c_str());
1325 for (int i = 1; i < num_params; ++i) {
1326 ParmVarDecl *param = fd->getParamDecl(i);
1328 if (i != 1)
1329 osprintf(os, ", ");
1330 osprintf(os, "%s", param->getName().str().c_str());
1332 osprintf(os, ");\n");
1333 osprintf(os, "}\n");
1336 /* Print definitions for methods "methods" in class "clazz" to "os".
1338 * "kind" specifies the kind of method that should be generated.
1340 * For methods that are identified as "get" methods, also
1341 * print a definition for the method using a name that includes
1342 * the "get_" prefix.
1344 void cpp_generator::print_method_group_impl(ostream &os, const isl_class &clazz,
1345 const set<FunctionDecl *> &methods)
1347 set<FunctionDecl *>::const_iterator it;
1348 bool first = true;
1350 for (it = methods.begin(); it != methods.end(); ++it) {
1351 function_kind kind;
1352 if (first)
1353 first = false;
1354 else
1355 osprintf(os, "\n");
1356 kind = get_method_kind(clazz, *it);
1357 print_method_impl(os, clazz, *it, kind);
1358 if (clazz.is_get_method(*it))
1359 print_get_method_impl(os, clazz, *it);
1363 /* Print the use of "param" to "os".
1365 * "load_from_this_ptr" specifies whether the parameter should be loaded from
1366 * the this-ptr. In case a value is loaded from a this pointer, the original
1367 * value must be preserved and must consequently be copied. Values that are
1368 * loaded from parameters do not need to be preserved, as such values will
1369 * already be copies of the actual parameters. It is consequently possible
1370 * to directly take the pointer from these values, which saves
1371 * an unnecessary copy.
1373 * In case the parameter is a callback function, two parameters get printed,
1374 * a wrapper for the callback function and a pointer to the actual
1375 * callback function. The wrapper is expected to be available
1376 * in a previously declared variable <name>_lambda, while
1377 * the actual callback function is expected to be stored
1378 * in a structure called <name>_data.
1379 * The caller of this function must ensure that these variables exist.
1381 void cpp_generator::print_method_param_use(ostream &os, ParmVarDecl *param,
1382 bool load_from_this_ptr)
1384 string name = param->getName().str();
1385 const char *name_str = name.c_str();
1386 QualType type = param->getOriginalType();
1388 if (type->isIntegerType()) {
1389 osprintf(os, "%s", name_str);
1390 return;
1393 if (is_string(type)) {
1394 osprintf(os, "%s.c_str()", name_str);
1395 return;
1398 if (is_callback(type)) {
1399 osprintf(os, "%s_lambda, ", name_str);
1400 osprintf(os, "&%s_data", name_str);
1401 return;
1404 if (!load_from_this_ptr)
1405 osprintf(os, "%s.", name_str);
1407 if (keeps(param)) {
1408 osprintf(os, "get()");
1409 } else {
1410 if (load_from_this_ptr)
1411 osprintf(os, "copy()");
1412 else
1413 osprintf(os, "release()");
1417 /* Print code that checks that all isl object arguments to "method" are valid
1418 * (not NULL) and throws an exception if they are not.
1419 * "kind" specifies the kind of method that is being generated.
1421 * If checked bindings are being generated,
1422 * then no such check is performed.
1424 void cpp_generator::print_argument_validity_check(ostream &os,
1425 FunctionDecl *method, function_kind kind)
1427 int n;
1428 bool first = true;
1430 if (checked)
1431 return;
1433 n = method->getNumParams();
1434 for (int i = 0; i < n; ++i) {
1435 bool is_this;
1436 ParmVarDecl *param = method->getParamDecl(i);
1437 string name = param->getName().str();
1438 const char *name_str = name.c_str();
1439 QualType type = param->getOriginalType();
1441 is_this = i == 0 && kind == function_kind_member_method;
1442 if (!is_this && (is_isl_ctx(type) || !is_isl_type(type)))
1443 continue;
1445 if (first)
1446 osprintf(os, " if (");
1447 else
1448 osprintf(os, " || ");
1450 if (is_this)
1451 osprintf(os, "!ptr");
1452 else
1453 osprintf(os, "%s.is_null()", name_str);
1455 first = false;
1457 if (first)
1458 return;
1459 osprintf(os, ")\n");
1460 print_throw_NULL_input(os);
1463 /* Print code for saving a copy of the isl::ctx available at the start
1464 * of the method "method" in a "saved_ctx" variable,
1465 * for use in exception handling.
1466 * "kind" specifies what kind of method "method" is.
1468 * If checked bindings are being generated,
1469 * then the "saved_ctx" variable is not needed.
1470 * If "method" is a member function, then obtain the isl_ctx from
1471 * the "this" object.
1472 * If the first argument of the method is an isl::ctx, then use that one.
1473 * Otherwise, save a copy of the isl::ctx associated to the first argument
1474 * of isl object type.
1476 void cpp_generator::print_save_ctx(ostream &os, FunctionDecl *method,
1477 function_kind kind)
1479 int n;
1480 ParmVarDecl *param = method->getParamDecl(0);
1481 QualType type = param->getOriginalType();
1483 if (checked)
1484 return;
1485 if (kind == function_kind_member_method) {
1486 osprintf(os, " auto saved_ctx = ctx();\n");
1487 return;
1489 if (is_isl_ctx(type)) {
1490 const char *name;
1492 name = param->getName().str().c_str();
1493 osprintf(os, " auto saved_ctx = %s;\n", name);
1494 return;
1496 n = method->getNumParams();
1497 for (int i = 0; i < n; ++i) {
1498 ParmVarDecl *param = method->getParamDecl(i);
1499 QualType type = param->getOriginalType();
1501 if (!is_isl_type(type))
1502 continue;
1503 osprintf(os, " auto saved_ctx = %s.ctx();\n",
1504 param->getName().str().c_str());
1505 return;
1509 /* Print code to make isl not print an error message when an error occurs
1510 * within the current scope (if exceptions are available),
1511 * since the error message will be included in the exception.
1512 * If exceptions are not available, then exception::on_error
1513 * is set to ISL_ON_ERROR_ABORT and isl is therefore made to abort instead.
1515 * If checked bindings are being generated,
1516 * then leave it to the user to decide what isl should do on error.
1517 * Otherwise, assume that a valid isl::ctx is available
1518 * in the "saved_ctx" variable,
1519 * e.g., through a prior call to print_save_ctx.
1521 void cpp_generator::print_on_error_continue(ostream &os)
1523 if (checked)
1524 return;
1525 osprintf(os, " options_scoped_set_on_error saved_on_error(saved_ctx, "
1526 "exception::on_error);\n");
1529 /* Print code to "os" that checks whether any of the persistent callbacks
1530 * of "clazz" is set and if it failed with an exception. If so, the "eptr"
1531 * in the corresponding data structure contains the exception
1532 * that was caught and that needs to be rethrown.
1533 * This field is cleared because the callback and its data may get reused.
1535 * The check only needs to be generated for member methods since
1536 * an object is needed for any of the persistent callbacks to be set.
1538 static void print_persistent_callback_exceptional_execution_check(ostream &os,
1539 const isl_class &clazz, cpp_generator::function_kind kind)
1541 const set<FunctionDecl *> &callbacks = clazz.persistent_callbacks;
1542 set<FunctionDecl *>::const_iterator in;
1544 if (kind != cpp_generator::function_kind_member_method)
1545 return;
1547 for (in = callbacks.begin(); in != callbacks.end(); ++in) {
1548 string callback_name = clazz.persistent_callback_name(*in);
1550 osprintf(os, " if (%s_data && %s_data->eptr) {\n",
1551 callback_name.c_str(), callback_name.c_str());
1552 osprintf(os, " std::exception_ptr eptr = %s_data->eptr;\n",
1553 callback_name.c_str());
1554 osprintf(os, " %s_data->eptr = nullptr;\n",
1555 callback_name.c_str());
1556 osprintf(os, " std::rethrow_exception(eptr);\n");
1557 osprintf(os, " }\n");
1561 /* Print code that checks whether the execution of the core of "method"
1562 * of class "clazz" was successful.
1563 * "kind" specifies what kind of method "method" is.
1565 * If checked bindings are being generated,
1566 * then no checks are performed.
1568 * Otherwise, first check if any of the callbacks failed with
1569 * an exception. If so, the "eptr" in the corresponding data structure
1570 * contains the exception that was caught and that needs to be rethrown.
1571 * Then check if the function call failed in any other way and throw
1572 * the appropriate exception.
1573 * In particular, if the return type is isl_stat, isl_bool or isl_size,
1574 * then a negative value indicates a failure. If the return type
1575 * is an isl type, then a NULL value indicates a failure.
1576 * Assume print_save_ctx has made sure that a valid isl::ctx
1577 * is available in the "ctx" variable.
1579 void cpp_generator::print_exceptional_execution_check(ostream &os,
1580 const isl_class &clazz, FunctionDecl *method, function_kind kind)
1582 int n;
1583 bool check_null, check_neg;
1584 QualType return_type = method->getReturnType();
1586 if (checked)
1587 return;
1589 print_persistent_callback_exceptional_execution_check(os, clazz, kind);
1591 n = method->getNumParams();
1592 for (int i = 0; i < n; ++i) {
1593 ParmVarDecl *param = method->getParamDecl(i);
1594 const char *name;
1596 if (!is_callback(param->getOriginalType()))
1597 continue;
1598 name = param->getName().str().c_str();
1599 osprintf(os, " if (%s_data.eptr)\n", name);
1600 osprintf(os, " std::rethrow_exception(%s_data.eptr);\n",
1601 name);
1604 check_neg = is_isl_neg_error(return_type);
1605 check_null = is_isl_type(return_type);
1606 if (!check_null && !check_neg)
1607 return;
1609 if (check_neg)
1610 osprintf(os, " if (res < 0)\n");
1611 else
1612 osprintf(os, " if (!res)\n");
1613 print_throw_last_error(os);
1616 /* Does "fd" modify an object of a subclass based on a type function?
1618 static bool is_subclass_mutator(const isl_class &clazz, FunctionDecl *fd)
1620 return clazz.is_type_subclass() && generator::is_mutator(clazz, fd);
1623 /* Return the C++ return type of the method corresponding to "fd" in "clazz".
1625 * If "fd" modifies an object of a subclass, then return
1626 * the type of this subclass.
1627 * Otherwise, return the C++ counterpart of the actual return type.
1629 std::string cpp_generator::get_return_type(const isl_class &clazz,
1630 FunctionDecl *fd)
1632 if (is_subclass_mutator(clazz, fd))
1633 return type2cpp(clazz);
1634 else
1635 return type2cpp(fd->getReturnType());
1638 /* Given a function "method" for setting a "clazz" persistent callback,
1639 * print the implementations of the methods needed for that callback.
1641 * In particular, print
1642 * - the implementation of a static inline method
1643 * for use as the C callback function
1644 * - the definition of a private method for setting the callback function
1645 * - the public method for constructing a new object with the callback set.
1647 void cpp_generator::print_set_persistent_callback(ostream &os,
1648 const isl_class &clazz, FunctionDecl *method,
1649 function_kind kind)
1651 string fullname = method->getName();
1652 ParmVarDecl *param = persistent_callback_arg(method);
1653 string classname = type2cpp(clazz);
1654 string pname;
1655 string callback_name = clazz.persistent_callback_name(method);
1657 print_persistent_callback_prototype(os, clazz, method, false);
1658 osprintf(os, "\n");
1659 osprintf(os, "{\n");
1660 print_callback_body(os, 2, param, callback_name);
1661 osprintf(os, "}\n\n");
1663 pname = param->getName().str();
1664 print_persistent_callback_setter_prototype(os, clazz, method, false);
1665 osprintf(os, "\n");
1666 osprintf(os, "{\n");
1667 print_check_ptr_start(os, clazz, "ptr");
1668 osprintf(os, " %s_data = std::make_shared<struct %s_data>();\n",
1669 callback_name.c_str(), callback_name.c_str());
1670 osprintf(os, " %s_data->func = %s;\n",
1671 callback_name.c_str(), pname.c_str());
1672 osprintf(os, " ptr = %s(ptr, &%s, %s_data.get());\n",
1673 fullname.c_str(), callback_name.c_str(), callback_name.c_str());
1674 print_check_ptr_end(os, "ptr");
1675 osprintf(os, "}\n\n");
1677 print_method_header(os, clazz, method, false, kind);
1678 osprintf(os, "{\n");
1679 osprintf(os, " auto copy = *this;\n");
1680 osprintf(os, " copy.set_%s_data(%s);\n",
1681 callback_name.c_str(), pname.c_str());
1682 osprintf(os, " return copy;\n");
1683 osprintf(os, "}\n\n");
1686 /* Print the return statement of the C++ method corresponding
1687 * to the C function "method" in class "clazz" to "os".
1689 * The result of the isl function is returned as a new
1690 * object if the underlying isl function returns an isl_* ptr, as a bool
1691 * if the isl function returns an isl_bool, as void if the isl functions
1692 * returns an isl_stat,
1693 * as std::string if the isl function returns 'const char *', and as
1694 * unmodified return value otherwise.
1695 * If checked C++ bindings are being generated,
1696 * then an isl_bool return type is transformed into a boolean and
1697 * an isl_stat into a stat since no exceptions can be generated
1698 * on negative results from the isl function.
1699 * If the method returns a new instance of the same object type and
1700 * if the class has any persistent callbacks, then the data
1701 * for these callbacks are copied from the original to the new object.
1702 * If "clazz" is a subclass that is based on a type function and
1703 * if the return type corresponds to the superclass data type,
1704 * then it is replaced by the subclass data type.
1706 void cpp_generator::print_method_return(ostream &os, const isl_class &clazz,
1707 FunctionDecl *method)
1709 QualType return_type = method->getReturnType();
1710 string rettype_str = get_return_type(clazz, method);
1711 bool returns_super = is_subclass_mutator(clazz, method);
1713 if (is_isl_type(return_type) ||
1714 (checked && is_isl_neg_error(return_type))) {
1715 osprintf(os, " return manage(res)");
1716 if (is_mutator(clazz, method) &&
1717 clazz.has_persistent_callbacks())
1718 osprintf(os, ".copy_callbacks(*this)");
1719 if (returns_super)
1720 osprintf(os, ".as<%s>()", rettype_str.c_str());
1721 osprintf(os, ";\n");
1722 } else if (is_isl_stat(return_type)) {
1723 osprintf(os, " return;\n");
1724 } else if (is_string(return_type)) {
1725 osprintf(os, " std::string tmp(res);\n");
1726 if (gives(method))
1727 osprintf(os, " free(res);\n");
1728 osprintf(os, " return tmp;\n");
1729 } else {
1730 osprintf(os, " return res;\n");
1734 /* Print definition for "method" in class "clazz" to "os".
1736 * "kind" specifies the kind of method that should be generated.
1738 * This method distinguishes three kinds of methods: member methods, static
1739 * methods, and constructors.
1741 * Member methods call "method" by passing to the underlying isl function the
1742 * isl object belonging to "this" as first argument and the remaining arguments
1743 * as subsequent arguments.
1745 * Static methods call "method" by passing all arguments to the underlying isl
1746 * function, as no this-pointer is available. The result is a newly managed
1747 * isl C++ object.
1749 * Constructors create a new object from a given set of input parameters. They
1750 * do not return a value, but instead update the pointer stored inside the
1751 * newly created object.
1753 * If the method has a callback argument, we reduce the number of parameters
1754 * that are exposed by one to hide the user pointer from the interface. On
1755 * the C++ side no user pointer is needed, as arguments can be forwarded
1756 * as part of the std::function argument which specifies the callback function.
1758 * Unless checked C++ bindings are being generated,
1759 * the inputs of the method are first checked for being valid isl objects and
1760 * a copy of the associated isl::ctx is saved (if needed).
1761 * If any failure occurs, either during the check for the inputs or
1762 * during the isl function call, an exception is thrown.
1763 * During the function call, isl is made not to print any error message
1764 * because the error message is included in the exception.
1766 void cpp_generator::print_method_impl(ostream &os, const isl_class &clazz,
1767 FunctionDecl *method, function_kind kind)
1769 string methodname = method->getName();
1770 int num_params = method->getNumParams();
1772 print_method_header(os, clazz, method, false, kind);
1773 osprintf(os, "{\n");
1774 print_argument_validity_check(os, method, kind);
1775 print_save_ctx(os, method, kind);
1776 print_on_error_continue(os);
1778 for (int i = 0; i < num_params; ++i) {
1779 ParmVarDecl *param = method->getParamDecl(i);
1780 if (is_callback(param->getType())) {
1781 num_params -= 1;
1782 print_callback_local(os, param);
1786 osprintf(os, " auto res = %s(", methodname.c_str());
1788 for (int i = 0; i < num_params; ++i) {
1789 ParmVarDecl *param = method->getParamDecl(i);
1790 bool load_from_this_ptr = false;
1792 if (i == 0 && kind == function_kind_member_method)
1793 load_from_this_ptr = true;
1795 print_method_param_use(os, param, load_from_this_ptr);
1797 if (i != num_params - 1)
1798 osprintf(os, ", ");
1800 osprintf(os, ");\n");
1802 print_exceptional_execution_check(os, clazz, method, kind);
1803 if (kind == function_kind_constructor) {
1804 osprintf(os, " ptr = res;\n");
1805 } else {
1806 print_method_return(os, clazz, method);
1809 osprintf(os, "}\n");
1812 /* Print the header for "method" in class "clazz", with name "cname" and
1813 * "num_params" number of arguments, to "os".
1815 * Print the header of a declaration if "is_declaration" is set, otherwise print
1816 * the header of a method definition.
1818 * "kind" specifies the kind of method that should be generated.
1820 * This function prints headers for member methods, static methods, and
1821 * constructors, either for their declaration or definition.
1823 * Member functions are declared as "const", as they do not change the current
1824 * object, but instead create a new object. They always retrieve the first
1825 * parameter of the original isl function from the this-pointer of the object,
1826 * such that only starting at the second parameter the parameters of the
1827 * original function become part of the method's interface.
1829 * A function
1831 * __isl_give isl_set *isl_set_intersect(__isl_take isl_set *s1,
1832 * __isl_take isl_set *s2);
1834 * is translated into:
1836 * inline set intersect(set set2) const;
1838 * For static functions and constructors all parameters of the original isl
1839 * function are exposed.
1841 * Parameters that are defined as __isl_keep or are of type string, are passed
1842 * as const reference, which allows the compiler to optimize the parameter
1843 * transfer.
1845 * Constructors are marked as explicit using the C++ keyword 'explicit' or as
1846 * implicit using a comment in place of the explicit keyword. By annotating
1847 * implicit constructors with a comment, users of the interface are made
1848 * aware of the potential danger that implicit construction is possible
1849 * for these constructors, whereas without a comment not every user would
1850 * know that implicit construction is allowed in absence of an explicit keyword.
1852 void cpp_generator::print_method_header(ostream &os, const isl_class &clazz,
1853 FunctionDecl *method, const string &cname, int num_params,
1854 bool is_declaration, function_kind kind)
1856 string rettype_str = get_return_type(clazz, method);
1857 string classname = type2cpp(clazz);
1858 int first_param = 0;
1860 if (kind == function_kind_member_method)
1861 first_param = 1;
1863 if (is_declaration) {
1864 osprintf(os, " ");
1866 if (kind == function_kind_static_method)
1867 osprintf(os, "static ");
1869 osprintf(os, "inline ");
1871 if (kind == function_kind_constructor) {
1872 if (is_implicit_conversion(clazz, method))
1873 osprintf(os, "/* implicit */ ");
1874 else
1875 osprintf(os, "explicit ");
1879 if (kind != function_kind_constructor)
1880 osprintf(os, "%s ", rettype_str.c_str());
1882 if (!is_declaration)
1883 osprintf(os, "%s::", classname.c_str());
1885 if (kind != function_kind_constructor)
1886 osprintf(os, "%s", cname.c_str());
1887 else
1888 osprintf(os, "%s", classname.c_str());
1890 osprintf(os, "(");
1892 for (int i = first_param; i < num_params; ++i) {
1893 ParmVarDecl *param = method->getParamDecl(i);
1894 QualType type = param->getOriginalType();
1895 string cpptype = type2cpp(type);
1897 if (is_callback(type))
1898 num_params--;
1900 if (keeps(param) || is_string(type) || is_callback(type))
1901 osprintf(os, "const %s &%s", cpptype.c_str(),
1902 param->getName().str().c_str());
1903 else
1904 osprintf(os, "%s %s", cpptype.c_str(),
1905 param->getName().str().c_str());
1907 if (i != num_params - 1)
1908 osprintf(os, ", ");
1911 osprintf(os, ")");
1913 if (kind == function_kind_member_method)
1914 osprintf(os, " const");
1916 if (is_declaration)
1917 osprintf(os, ";");
1918 osprintf(os, "\n");
1921 /* Print the header for a method called "name" in class "clazz"
1922 * derived from "method" to "os".
1924 * Print the header of a declaration if "is_declaration" is set, otherwise print
1925 * the header of a method definition.
1927 * "kind" specifies the kind of method that should be generated.
1929 void cpp_generator::print_named_method_header(ostream &os,
1930 const isl_class &clazz, FunctionDecl *method, string name,
1931 bool is_declaration, function_kind kind)
1933 int num_params = method->getNumParams();
1935 name = rename_method(name);
1936 print_method_header(os, clazz, method, name, num_params,
1937 is_declaration, kind);
1940 /* Print the header for "method" in class "clazz" to "os"
1941 * using its default name.
1943 * Print the header of a declaration if "is_declaration" is set, otherwise print
1944 * the header of a method definition.
1946 * "kind" specifies the kind of method that should be generated.
1948 void cpp_generator::print_method_header(ostream &os, const isl_class &clazz,
1949 FunctionDecl *method, bool is_declaration, function_kind kind)
1951 string name = clazz.method_name(method);
1953 print_named_method_header(os, clazz, method, name, is_declaration,
1954 kind);
1957 /* Generate the list of argument types for a callback function of
1958 * type "type". If "cpp" is set, then generate the C++ type list, otherwise
1959 * the C type list.
1961 * For a callback of type
1963 * isl_stat (*)(__isl_take isl_map *map, void *user)
1965 * the following C++ argument list is generated:
1967 * map
1969 string cpp_generator::generate_callback_args(QualType type, bool cpp)
1971 std::string type_str;
1972 const FunctionProtoType *callback;
1973 int num_params;
1975 callback = extract_prototype(type);
1976 num_params = callback->getNumArgs();
1977 if (cpp)
1978 num_params--;
1980 for (long i = 0; i < num_params; i++) {
1981 QualType type = callback->getArgType(i);
1983 if (cpp)
1984 type_str += type2cpp(type);
1985 else
1986 type_str += type.getAsString();
1988 if (!cpp)
1989 type_str += "arg_" + ::to_string(i);
1991 if (i != num_params - 1)
1992 type_str += ", ";
1995 return type_str;
1998 /* Generate the full cpp type of a callback function of type "type".
2000 * For a callback of type
2002 * isl_stat (*)(__isl_take isl_map *map, void *user)
2004 * the following type is generated:
2006 * std::function<stat(map)>
2008 string cpp_generator::generate_callback_type(QualType type)
2010 std::string type_str;
2011 const FunctionProtoType *callback = extract_prototype(type);
2012 QualType return_type = callback->getReturnType();
2013 string rettype_str = type2cpp(return_type);
2015 type_str = "std::function<";
2016 type_str += rettype_str;
2017 type_str += "(";
2018 type_str += generate_callback_args(type, true);
2019 type_str += ")>";
2021 return type_str;
2024 /* Print the call to the C++ callback function "call",
2025 * with the given indentation, wrapped
2026 * for use inside the lambda function that is used as the C callback function,
2027 * in the case where checked C++ bindings are being generated.
2029 * In particular, print
2031 * auto ret = @call@;
2032 * return ret.release();
2034 void cpp_generator::print_wrapped_call_checked(ostream &os, int indent,
2035 const string &call)
2037 osprintf(os, indent, "auto ret = %s;\n", call.c_str());
2038 osprintf(os, indent, "return ret.release();\n");
2041 /* Print the call to the C++ callback function "call",
2042 * with the given indentation and with return type "rtype", wrapped
2043 * for use inside the lambda function that is used as the C callback function.
2045 * In particular, print
2047 * ISL_CPP_TRY {
2048 * @call@;
2049 * return isl_stat_ok;
2050 * } ISL_CPP_CATCH_ALL {
2051 * data->eptr = std::current_exception();
2052 * return isl_stat_error;
2054 * or
2055 * ISL_CPP_TRY {
2056 * auto ret = @call@;
2057 * return ret ? isl_bool_true : isl_bool_false;
2058 * } ISL_CPP_CATCH_ALL {
2059 * data->eptr = std::current_exception();
2060 * return isl_bool_error;
2062 * or
2063 * ISL_CPP_TRY {
2064 * auto ret = @call@;
2065 * return ret.release();
2066 * } ISL_CPP_CATCH_ALL {
2067 * data->eptr = std::current_exception();
2068 * return NULL;
2071 * depending on the return type.
2073 * where ISL_CPP_TRY is defined to "try" and ISL_CPP_CATCH_ALL to "catch (...)"
2074 * (if exceptions are available).
2076 * If checked C++ bindings are being generated, then
2077 * the call is wrapped differently.
2079 void cpp_generator::print_wrapped_call(ostream &os, int indent,
2080 const string &call, QualType rtype)
2082 if (checked)
2083 return print_wrapped_call_checked(os, indent, call);
2085 osprintf(os, indent, "ISL_CPP_TRY {\n");
2086 if (is_isl_stat(rtype))
2087 osprintf(os, indent, " %s;\n", call.c_str());
2088 else
2089 osprintf(os, indent, " auto ret = %s;\n", call.c_str());
2090 if (is_isl_stat(rtype))
2091 osprintf(os, indent, " return isl_stat_ok;\n");
2092 else if (is_isl_bool(rtype))
2093 osprintf(os, indent,
2094 " return ret ? isl_bool_true : isl_bool_false;\n");
2095 else
2096 osprintf(os, indent, " return ret.release();\n");
2097 osprintf(os, indent, "} ISL_CPP_CATCH_ALL {\n");
2098 osprintf(os, indent, " data->eptr = std::current_exception();\n");
2099 if (is_isl_stat(rtype))
2100 osprintf(os, indent, " return isl_stat_error;\n");
2101 else if (is_isl_bool(rtype))
2102 osprintf(os, indent, " return isl_bool_error;\n");
2103 else
2104 osprintf(os, indent, " return NULL;\n");
2105 osprintf(os, indent, "}\n");
2108 /* Print the declaration for a "prefix"_data data structure
2109 * that can be used for passing to a C callback function
2110 * containing a copy of the C++ callback function "param",
2111 * along with an std::exception_ptr that is used to store any
2112 * exceptions thrown in the C++ callback.
2114 * If the C callback is of the form
2116 * isl_stat (*fn)(__isl_take isl_map *map, void *user)
2118 * then the following declaration is printed:
2120 * struct <prefix>_data {
2121 * std::function<stat(map)> func;
2122 * std::exception_ptr eptr;
2125 * (without a newline or a semicolon).
2127 * The std::exception_ptr object is not added to "prefix"_data
2128 * if checked C++ bindings are being generated.
2130 void cpp_generator::print_callback_data_decl(ostream &os, ParmVarDecl *param,
2131 const string &prefix)
2133 string cpp_args;
2135 cpp_args = generate_callback_type(param->getType());
2137 osprintf(os, " struct %s_data {\n", prefix.c_str());
2138 osprintf(os, " %s func;\n", cpp_args.c_str());
2139 if (!checked)
2140 osprintf(os, " std::exception_ptr eptr;\n");
2141 osprintf(os, " }");
2144 /* Print the body of C function callback with the given indentation
2145 * that can be use as an argument to "param" for marshalling
2146 * the corresponding C++ callback.
2147 * The data structure that contains the C++ callback is of type
2148 * "prefix"_data.
2150 * For a callback of the form
2152 * isl_stat (*fn)(__isl_take isl_map *map, void *user)
2154 * the following code is generated:
2156 * auto *data = static_cast<struct <prefix>_data *>(arg_1);
2157 * ISL_CPP_TRY {
2158 * stat ret = (data->func)(manage(arg_0));
2159 * return isl_stat_ok;
2160 * } ISL_CPP_CATCH_ALL {
2161 * data->eptr = std::current_exception();
2162 * return isl_stat_error;
2165 * If checked C++ bindings are being generated, then
2166 * generate the following code:
2168 * auto *data = static_cast<struct <prefix>_data *>(arg_1);
2169 * stat ret = (data->func)(manage(arg_0));
2170 * return isl_stat(ret);
2172 void cpp_generator::print_callback_body(ostream &os, int indent,
2173 ParmVarDecl *param, const string &prefix)
2175 QualType ptype, rtype;
2176 string call, last_idx;
2177 const FunctionProtoType *callback;
2178 int num_params;
2180 ptype = param->getType();
2182 callback = extract_prototype(ptype);
2183 rtype = callback->getReturnType();
2184 num_params = callback->getNumArgs();
2186 last_idx = ::to_string(num_params - 1);
2188 call = "(data->func)(";
2189 for (long i = 0; i < num_params - 1; i++) {
2190 if (!callback_takes_argument(param, i))
2191 call += "manage_copy";
2192 else
2193 call += "manage";
2194 call += "(arg_" + ::to_string(i) + ")";
2195 if (i != num_params - 2)
2196 call += ", ";
2198 call += ")";
2200 osprintf(os, indent,
2201 "auto *data = static_cast<struct %s_data *>(arg_%s);\n",
2202 prefix.c_str(), last_idx.c_str());
2203 print_wrapped_call(os, indent, call, rtype);
2206 /* Print the local variables that are needed for a callback argument,
2207 * in particular, print a lambda function that wraps the callback and
2208 * a pointer to the actual C++ callback function.
2210 * For a callback of the form
2212 * isl_stat (*fn)(__isl_take isl_map *map, void *user)
2214 * the following lambda function is generated:
2216 * auto fn_lambda = [](isl_map *arg_0, void *arg_1) -> isl_stat {
2217 * auto *data = static_cast<struct fn_data *>(arg_1);
2218 * try {
2219 * stat ret = (data->func)(manage(arg_0));
2220 * return isl_stat_ok;
2221 * } catch (...) {
2222 * data->eptr = std::current_exception();
2223 * return isl_stat_error;
2225 * };
2227 * A copy of the std::function C++ callback function is stored in
2228 * a fn_data data structure for passing to the C callback function,
2229 * along with an std::exception_ptr that is used to store any
2230 * exceptions thrown in the C++ callback.
2232 * struct fn_data {
2233 * std::function<stat(map)> func;
2234 * std::exception_ptr eptr;
2235 * } fn_data = { fn };
2237 * This std::function object represents the actual user
2238 * callback function together with the locally captured state at the caller.
2240 * The lambda function is expected to be used as a C callback function
2241 * where the lambda itself is provided as the function pointer and
2242 * where the user void pointer is a pointer to fn_data.
2243 * The std::function object is extracted from the pointer to fn_data
2244 * inside the lambda function.
2246 * The std::exception_ptr object is not added to fn_data
2247 * if checked C++ bindings are being generated.
2248 * The body of the generated lambda function then is as follows:
2250 * stat ret = (data->func)(manage(arg_0));
2251 * return isl_stat(ret);
2253 * If the C callback does not take its arguments, then
2254 * manage_copy is used instead of manage.
2256 void cpp_generator::print_callback_local(ostream &os, ParmVarDecl *param)
2258 string pname;
2259 QualType ptype, rtype;
2260 string c_args, cpp_args, rettype;
2261 const FunctionProtoType *callback;
2263 pname = param->getName().str();
2264 ptype = param->getType();
2266 c_args = generate_callback_args(ptype, false);
2268 callback = extract_prototype(ptype);
2269 rtype = callback->getReturnType();
2270 rettype = rtype.getAsString();
2272 print_callback_data_decl(os, param, pname);
2273 osprintf(os, " %s_data = { %s };\n", pname.c_str(), pname.c_str());
2274 osprintf(os, " auto %s_lambda = [](%s) -> %s {\n",
2275 pname.c_str(), c_args.c_str(), rettype.c_str());
2276 print_callback_body(os, 4, param, pname);
2277 osprintf(os, " };\n");
2280 /* An array listing functions that must be renamed and the function name they
2281 * should be renamed to. We currently rename functions in case their name would
2282 * match a reserved C++ keyword, which is not allowed in C++.
2284 static const char *rename_map[][2] = {
2285 { "union", "unite" },
2288 /* Rename method "name" in case the method name in the C++ bindings should not
2289 * match the name in the C bindings. We do this for example to avoid
2290 * C++ keywords.
2292 std::string cpp_generator::rename_method(std::string name)
2294 for (size_t i = 0; i < sizeof(rename_map) / sizeof(rename_map[0]); i++)
2295 if (name.compare(rename_map[i][0]) == 0)
2296 return rename_map[i][1];
2298 return name;
2301 /* Translate isl class "clazz" to its corresponding C++ type.
2302 * Use the name of the type based subclass, if any.
2304 string cpp_generator::type2cpp(const isl_class &clazz)
2306 return type2cpp(clazz.subclass_name);
2309 /* Translate type string "type_str" to its C++ name counterpart.
2311 string cpp_generator::type2cpp(string type_str)
2313 return type_str.substr(4);
2316 /* Return the C++ counterpart to the isl_bool type.
2317 * If checked C++ bindings are being generated,
2318 * then this is "boolean". Otherwise, it is simply "bool".
2320 string cpp_generator::isl_bool2cpp()
2322 return checked ? "boolean" : "bool";
2325 /* Return the namespace of the generated C++ bindings.
2327 string cpp_generator::isl_namespace()
2329 return checked ? "isl::checked::" : "isl::";
2332 /* Translate QualType "type" to its C++ name counterpart.
2334 * An isl_bool return type is translated into "bool",
2335 * while an isl_stat is translated into "void" and
2336 * an isl_size is translated to "unsigned".
2337 * The exceptional cases are handled through exceptions.
2338 * If checked C++ bindings are being generated, then
2339 * C++ counterparts of isl_bool, isl_stat and isl_size need to be used instead.
2341 string cpp_generator::type2cpp(QualType type)
2343 if (is_isl_type(type))
2344 return isl_namespace() +
2345 type2cpp(type->getPointeeType().getAsString());
2347 if (is_isl_bool(type))
2348 return isl_bool2cpp();
2350 if (is_isl_stat(type))
2351 return checked ? "stat" : "void";
2353 if (is_isl_size(type))
2354 return checked ? "class size" : "unsigned";
2356 if (type->isIntegerType())
2357 return type.getAsString();
2359 if (is_string(type))
2360 return "std::string";
2362 if (is_callback(type))
2363 return generate_callback_type(type);
2365 die("Cannot convert type to C++ type");
2368 /* Check if "subclass_type" is a subclass of "class_type".
2370 bool cpp_generator::is_subclass(QualType subclass_type,
2371 const isl_class &class_type)
2373 std::string type_str = subclass_type->getPointeeType().getAsString();
2374 std::vector<std::string> superclasses;
2375 std::vector<const isl_class *> parents;
2376 std::vector<std::string>::iterator ci;
2378 superclasses = generator::find_superclasses(classes[type_str].type);
2380 for (ci = superclasses.begin(); ci < superclasses.end(); ci++)
2381 parents.push_back(&classes[*ci]);
2383 while (!parents.empty()) {
2384 const isl_class *candidate = parents.back();
2386 parents.pop_back();
2388 if (&class_type == candidate)
2389 return true;
2391 superclasses = generator::find_superclasses(candidate->type);
2393 for (ci = superclasses.begin(); ci < superclasses.end(); ci++)
2394 parents.push_back(&classes[*ci]);
2397 return false;
2400 /* Check if "cons" is an implicit conversion constructor of class "clazz".
2402 * An implicit conversion constructor is generated in case "cons" has a single
2403 * parameter, where the parameter type is a subclass of the class that is
2404 * currently being generated.
2406 bool cpp_generator::is_implicit_conversion(const isl_class &clazz,
2407 FunctionDecl *cons)
2409 ParmVarDecl *param = cons->getParamDecl(0);
2410 QualType type = param->getOriginalType();
2412 int num_params = cons->getNumParams();
2413 if (num_params != 1)
2414 return false;
2416 if (is_isl_type(type) && !is_isl_ctx(type) && is_subclass(type, clazz))
2417 return true;
2419 return false;
2422 /* Get kind of "method" in "clazz".
2424 * Given the declaration of a static or member method, returns its kind.
2426 cpp_generator::function_kind cpp_generator::get_method_kind(
2427 const isl_class &clazz, FunctionDecl *method)
2429 if (is_static(clazz, method))
2430 return function_kind_static_method;
2431 else
2432 return function_kind_member_method;