cpp_generator::print_method_header: extract out variant taking name and arity
[isl.git] / interface / cpp.cc
blobc814e2469b852ec0c34a6a7d3bd83d2063b0f63c
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_get_ctx_decl(os);
256 osprintf(os, "\n");
257 print_persistent_callbacks_decl(os, clazz);
258 print_methods_decl(os, clazz);
260 osprintf(os, "};\n");
263 /* Print forward declaration of class "clazz" to "os".
265 void cpp_generator::print_class_forward_decl(ostream &os,
266 const isl_class &clazz)
268 std::string cppstring = type2cpp(clazz);
269 const char *cppname = cppstring.c_str();
271 osprintf(os, "class %s;\n", cppname);
274 /* Print global factory functions to "os".
276 * Each class has two global factory functions:
278 * set manage(__isl_take isl_set *ptr);
279 * set manage_copy(__isl_keep isl_set *ptr);
281 * A user can construct isl C++ objects from a raw pointer and indicate whether
282 * they intend to take the ownership of the object or not through these global
283 * factory functions. This ensures isl object creation is very explicit and
284 * pointers are not converted by accident. Thanks to overloading, manage() and
285 * manage_copy() can be called on any isl raw pointer and the corresponding
286 * object is automatically created, without the user having to choose the right
287 * isl object type.
289 * For a subclass based on a type function, no factory functions
290 * are introduced because they share the C object type with
291 * the superclass.
293 void cpp_generator::print_class_factory_decl(ostream &os,
294 const isl_class &clazz, const std::string &prefix)
296 const char *name = clazz.name.c_str();
297 std::string cppstring = type2cpp(clazz);
298 const char *cppname = cppstring.c_str();
300 if (clazz.is_type_subclass())
301 return;
303 os << prefix;
304 osprintf(os, "inline %s manage(__isl_take %s *ptr);\n", cppname, name);
305 os << prefix;
306 osprintf(os, "inline %s manage_copy(__isl_keep %s *ptr);\n",
307 cppname, name);
310 /* Print declarations of protected constructors for class "clazz" to "os".
312 * Each class has currently one protected constructor:
314 * 1) Constructor from a plain isl_* C pointer
316 * Example:
318 * set(__isl_take isl_set *ptr);
320 * The raw pointer constructor is kept protected. Object creation is only
321 * possible through manage() or manage_copy().
323 void cpp_generator::print_protected_constructors_decl(ostream &os,
324 const isl_class &clazz)
326 const char *name = clazz.name.c_str();
327 std::string cppstring = type2cpp(clazz);
328 const char *cppname = cppstring.c_str();
330 osprintf(os, " inline explicit %s(__isl_take %s *ptr);\n", cppname,
331 name);
334 /* Print declarations of public constructors for class "clazz" to "os".
336 * Each class currently has two public constructors:
338 * 1) A default constructor
339 * 2) A copy constructor
341 * Example:
343 * set();
344 * set(const set &set);
346 void cpp_generator::print_public_constructors_decl(ostream &os,
347 const isl_class &clazz)
349 std::string cppstring = type2cpp(clazz);
350 const char *cppname = cppstring.c_str();
351 osprintf(os, " inline /* implicit */ %s();\n", cppname);
353 osprintf(os, " inline /* implicit */ %s(const %s &obj);\n",
354 cppname, cppname);
357 /* Print declarations for constructors for class "class" to "os".
359 * For each isl function that is marked as __isl_constructor,
360 * add a corresponding C++ constructor.
362 * Example:
364 * inline /\* implicit *\/ union_set(basic_set bset);
365 * inline /\* implicit *\/ union_set(set set);
366 * inline explicit val(ctx ctx, long i);
367 * inline explicit val(ctx ctx, const std::string &str);
369 void cpp_generator::print_constructors_decl(ostream &os,
370 const isl_class &clazz)
372 set<FunctionDecl *>::const_iterator in;
373 const set<FunctionDecl *> &constructors = clazz.constructors;
375 for (in = constructors.begin(); in != constructors.end(); ++in) {
376 FunctionDecl *cons = *in;
378 print_method_decl(os, clazz, cons, function_kind_constructor);
382 /* Print declarations of copy assignment operator for class "clazz"
383 * to "os".
385 * Each class has one assignment operator.
387 * isl:set &set::operator=(set obj)
390 void cpp_generator::print_copy_assignment_decl(ostream &os,
391 const isl_class &clazz)
393 std::string cppstring = type2cpp(clazz);
394 const char *cppname = cppstring.c_str();
396 osprintf(os, " inline %s &operator=(%s obj);\n", cppname, cppname);
399 /* Print declaration of destructor for class "clazz" to "os".
401 * No explicit destructor is needed for type based subclasses.
403 void cpp_generator::print_destructor_decl(ostream &os, const isl_class &clazz)
405 std::string cppstring = type2cpp(clazz);
406 const char *cppname = cppstring.c_str();
408 if (clazz.is_type_subclass())
409 return;
411 osprintf(os, " inline ~%s();\n", cppname);
414 /* Print declaration of pointer functions for class "clazz" to "os".
415 * Since type based subclasses share the pointer with their superclass,
416 * they can also reuse these functions from the superclass.
418 * To obtain a raw pointer three functions are provided:
420 * 1) __isl_give isl_set *copy()
422 * Returns a pointer to a _copy_ of the internal object
424 * 2) __isl_keep isl_set *get()
426 * Returns a pointer to the internal object
428 * 3) __isl_give isl_set *release()
430 * Returns a pointer to the internal object and resets the
431 * internal pointer to nullptr.
433 * We also provide functionality to explicitly check if a pointer is
434 * currently managed by this object.
436 * 4) bool is_null()
438 * Check if the current object is a null pointer.
440 * The functions get() and release() model the value_ptr proposed in
441 * http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2012/n3339.pdf.
442 * The copy() function is an extension to allow the user to explicitly
443 * copy the underlying object.
445 * Also generate a declaration to delete copy() for r-values, for
446 * r-values release() should be used to avoid unnecessary copies.
448 void cpp_generator::print_ptr_decl(ostream &os, const isl_class &clazz)
450 const char *name = clazz.name.c_str();
452 if (clazz.is_type_subclass())
453 return;
455 osprintf(os, " inline __isl_give %s *copy() const &;\n", name);
456 osprintf(os, " inline __isl_give %s *copy() && = delete;\n", name);
457 osprintf(os, " inline __isl_keep %s *get() const;\n", name);
458 osprintf(os, " inline __isl_give %s *release();\n", name);
459 osprintf(os, " inline bool is_null() const;\n");
462 /* Print a template declaration with given indentation
463 * for the "isa_type" method that ensures it is only enabled
464 * when called with a template argument
465 * that represents a type that is equal to that
466 * of the return type of the type function of "super".
467 * In particular, "isa_type" gets called from "isa"
468 * with as template argument the type of the "type" field
469 * of the subclass.
470 * The check ensures that this subclass is in fact a direct subclass
471 * of "super".
473 void cpp_generator::print_isa_type_template(ostream &os, int indent,
474 const isl_class &super)
476 osprintf(os, indent,
477 "template <typename T,\n");
478 osprintf(os, indent,
479 " typename = typename std::enable_if<std::is_same<\n");
480 osprintf(os, indent,
481 " const decltype(%s(NULL)),\n",
482 super.fn_type->getNameAsString().c_str());
483 osprintf(os, indent,
484 " const T>::value>::type>\n");
487 /* Print declarations for the "as" and "isa" methods, if "clazz"
488 * is a superclass with a type function.
490 * "isa" checks whether an object is of a given subclass type.
491 * "isa_type" does the same, but gets passed the value of the type field
492 * of the subclass as a function argument and the type of this field
493 * as a template argument.
494 * "as" tries to cast an object to a given subclass type, returning
495 * an invalid object if the object is not of the given type.
497 void cpp_generator::print_downcast_decl(ostream &os, const isl_class &clazz)
499 if (!clazz.fn_type)
500 return;
502 osprintf(os, "private:\n");
503 print_isa_type_template(os, 2, clazz);
504 osprintf(os, " inline %s isa_type(T subtype) const;\n",
505 isl_bool2cpp().c_str());
506 osprintf(os, "public:\n");
507 osprintf(os, " template <class T> inline %s isa() const;\n",
508 isl_bool2cpp().c_str());
509 osprintf(os, " template <class T> inline T as() const;\n");
512 /* Print the declaration of the get_ctx method.
514 void cpp_generator::print_get_ctx_decl(ostream &os)
516 osprintf(os, " inline ctx get_ctx() const;\n");
519 /* Add a space to the return type "type" if needed,
520 * i.e., if it is not the type of a pointer.
522 static string add_space_to_return_type(const string &type)
524 if (type[type.size() - 1] == '*')
525 return type;
526 return type + " ";
529 /* Print the prototype of the static inline method that is used
530 * as the C callback of "clazz" set by "method" to "os".
532 void cpp_generator::print_persistent_callback_prototype(ostream &os,
533 const isl_class &clazz, FunctionDecl *method, bool is_declaration)
535 string callback_name, rettype, c_args;
536 ParmVarDecl *param = persistent_callback_arg(method);
537 const FunctionProtoType *callback;
538 QualType ptype;
539 string classname;
541 ptype = param->getType();
542 callback = extract_prototype(ptype);
544 rettype = callback->getReturnType().getAsString();
545 rettype = add_space_to_return_type(rettype);
546 callback_name = clazz.persistent_callback_name(method);
547 c_args = generate_callback_args(ptype, false);
549 if (!is_declaration)
550 classname = type2cpp(clazz) + "::";
552 osprintf(os, "%s%s%s(%s)",
553 rettype.c_str(), classname.c_str(),
554 callback_name.c_str(), c_args.c_str());
557 /* Print the prototype of the method for setting the callback function
558 * of "clazz" set by "method" to "os".
560 void cpp_generator::print_persistent_callback_setter_prototype(ostream &os,
561 const isl_class &clazz, FunctionDecl *method, bool is_declaration)
563 string classname, callback_name, cpptype;
564 ParmVarDecl *param = persistent_callback_arg(method);
566 if (!is_declaration)
567 classname = type2cpp(clazz) + "::";
569 cpptype = type2cpp(param->getOriginalType());
570 callback_name = clazz.persistent_callback_name(method);
571 osprintf(os, "void %sset_%s_data(const %s &%s)",
572 classname.c_str(), callback_name.c_str(), cpptype.c_str(),
573 param->getName().str().c_str());
576 /* Given a function "method" for setting a "clazz" persistent callback,
577 * print the fields that are needed for marshalling the callback to "os".
579 * In particular, print
580 * - the declaration of a data structure for storing the C++ callback function
581 * - a shared pointer to such a data structure
582 * - the declaration of a static inline method
583 * for use as the C callback function
584 * - the declaration of a private method for setting the callback function
586 void cpp_generator::print_persistent_callback_data(ostream &os,
587 const isl_class &clazz, FunctionDecl *method)
589 string callback_name;
590 ParmVarDecl *param = persistent_callback_arg(method);
592 callback_name = clazz.persistent_callback_name(method);
593 print_callback_data_decl(os, param, callback_name);
594 osprintf(os, ";\n");
595 osprintf(os, " std::shared_ptr<%s_data> %s_data;\n",
596 callback_name.c_str(), callback_name.c_str());
597 osprintf(os, " static inline ");
598 print_persistent_callback_prototype(os, clazz, method, true);
599 osprintf(os, ";\n");
600 osprintf(os, " inline ");
601 print_persistent_callback_setter_prototype(os, clazz, method, true);
602 osprintf(os, ";\n");
605 /* Print declarations needed for the persistent callbacks of "clazz".
607 * In particular, if there are any persistent callbacks, then
608 * print a private method for copying callback data from
609 * one object to another,
610 * private data for keeping track of the persistent callbacks and
611 * public methods for setting the persistent callbacks.
613 void cpp_generator::print_persistent_callbacks_decl(ostream &os,
614 const isl_class &clazz)
616 std::string cppstring = type2cpp(clazz);
617 const char *cppname = cppstring.c_str();
618 set<FunctionDecl *>::const_iterator in;
619 const set<FunctionDecl *> &callbacks = clazz.persistent_callbacks;
621 if (!clazz.has_persistent_callbacks())
622 return;
624 osprintf(os, "private:\n");
625 osprintf(os, " inline %s &copy_callbacks(const %s &obj);\n",
626 cppname, cppname);
627 for (in = callbacks.begin(); in != callbacks.end(); ++in)
628 print_persistent_callback_data(os, clazz, *in);
630 osprintf(os, "public:\n");
631 for (in = callbacks.begin(); in != callbacks.end(); ++in)
632 print_method_decl(os, clazz, *in, function_kind_member_method);
635 /* Print declarations for methods in class "clazz" to "os".
637 void cpp_generator::print_methods_decl(ostream &os, const isl_class &clazz)
639 map<string, set<FunctionDecl *> >::const_iterator it;
641 for (it = clazz.methods.begin(); it != clazz.methods.end(); ++it)
642 print_method_group_decl(os, clazz, it->second);
645 /* Print declarations for methods "methods" in class "clazz" to "os".
647 void cpp_generator::print_method_group_decl(ostream &os, const isl_class &clazz,
648 const set<FunctionDecl *> &methods)
650 set<FunctionDecl *>::const_iterator it;
652 for (it = methods.begin(); it != methods.end(); ++it) {
653 function_kind kind = get_method_kind(clazz, *it);
654 print_method_decl(os, clazz, *it, kind);
658 /* Print declarations for "method" in class "clazz" to "os".
660 * "kind" specifies the kind of method that should be generated.
662 void cpp_generator::print_method_decl(ostream &os, const isl_class &clazz,
663 FunctionDecl *method, function_kind kind)
665 print_method_header(os, clazz, method, true, kind);
668 /* Print implementations for class "clazz" to "os".
670 void cpp_generator::print_class_impl(ostream &os, const isl_class &clazz)
672 std::string cppstring = type2cpp(clazz);
673 const char *cppname = cppstring.c_str();
675 osprintf(os, "// implementations for isl::%s\n", cppname);
677 print_class_factory_impl(os, clazz);
678 osprintf(os, "\n");
679 print_public_constructors_impl(os, clazz);
680 osprintf(os, "\n");
681 print_protected_constructors_impl(os, clazz);
682 osprintf(os, "\n");
683 print_constructors_impl(os, clazz);
684 osprintf(os, "\n");
685 print_copy_assignment_impl(os, clazz);
686 osprintf(os, "\n");
687 print_destructor_impl(os, clazz);
688 osprintf(os, "\n");
689 print_ptr_impl(os, clazz);
690 osprintf(os, "\n");
691 if (print_downcast_impl(os, clazz))
692 osprintf(os, "\n");
693 print_get_ctx_impl(os, clazz);
694 osprintf(os, "\n");
695 print_persistent_callbacks_impl(os, clazz);
696 print_methods_impl(os, clazz);
697 print_stream_insertion(os, clazz);
700 /* Print code for throwing an exception corresponding to the last error
701 * that occurred on "ctx".
702 * This assumes that a valid isl::ctx is available in the "ctx" variable,
703 * e.g., through a prior call to print_save_ctx.
705 static void print_throw_last_error(ostream &os)
707 osprintf(os, " exception::throw_last_error(ctx);\n");
710 /* Print code with the given indentation
711 * for throwing an exception_invalid with the given message.
713 static void print_throw_invalid(ostream &os, int indent, const char *msg)
715 osprintf(os, indent,
716 "exception::throw_invalid(\"%s\", __FILE__, __LINE__);\n", msg);
719 /* Print code for throwing an exception on NULL input.
721 static void print_throw_NULL_input(ostream &os)
723 print_throw_invalid(os, 4, "NULL input");
726 /* Print code with the given indentation
727 * for acting on an invalid error with message "msg".
728 * In particular, throw an exception_invalid.
729 * In the checked C++ bindings, isl_die is called instead with the code
730 * in "checked_code".
732 void cpp_generator::print_invalid(ostream &os, int indent, const char *msg,
733 const char *checked_code)
735 if (checked)
736 osprintf(os, indent,
737 "isl_die(get_ctx().get(), isl_error_invalid, "
738 "\"%s\", %s);\n", msg, checked_code);
739 else
740 print_throw_invalid(os, indent, msg);
743 /* Print an operator for inserting objects of "class"
744 * into an output stream.
746 * Unless checked C++ bindings are being generated,
747 * the operator requires its argument to be non-NULL.
748 * An exception is thrown if anything went wrong during the printing.
749 * During this printing, isl is made not to print any error message
750 * because the error message is included in the exception.
752 * If checked C++ bindings are being generated and anything went wrong,
753 * then record this failure in the output stream.
755 void cpp_generator::print_stream_insertion(ostream &os, const isl_class &clazz)
757 const char *name = clazz.name.c_str();
758 std::string cppstring = type2cpp(clazz);
759 const char *cppname = cppstring.c_str();
761 if (!clazz.fn_to_str)
762 return;
764 osprintf(os, "\n");
765 osprintf(os, "inline std::ostream &operator<<(std::ostream &os, ");
766 osprintf(os, "const %s &obj)\n", cppname);
767 osprintf(os, "{\n");
768 print_check_ptr_start(os, clazz, "obj.get()");
769 osprintf(os, " char *str = %s_to_str(obj.get());\n", name);
770 print_check_ptr_end(os, "str");
771 if (checked) {
772 osprintf(os, " if (!str) {\n");
773 osprintf(os, " os.setstate(std::ios_base::badbit);\n");
774 osprintf(os, " return os;\n");
775 osprintf(os, " }\n");
777 osprintf(os, " os << str;\n");
778 osprintf(os, " free(str);\n");
779 osprintf(os, " return os;\n");
780 osprintf(os, "}\n");
783 /* Print code that checks that "ptr" is not NULL at input.
785 * Omit the check if checked C++ bindings are being generated.
787 void cpp_generator::print_check_ptr(ostream &os, const char *ptr)
789 if (checked)
790 return;
792 osprintf(os, " if (!%s)\n", ptr);
793 print_throw_NULL_input(os);
796 /* Print code that checks that "ptr" is not NULL at input and
797 * that saves a copy of the isl_ctx of "ptr" for a later check.
799 * Omit the check if checked C++ bindings are being generated.
801 void cpp_generator::print_check_ptr_start(ostream &os, const isl_class &clazz,
802 const char *ptr)
804 if (checked)
805 return;
807 print_check_ptr(os, ptr);
808 osprintf(os, " auto ctx = %s_get_ctx(%s);\n", clazz.name.c_str(), ptr);
809 print_on_error_continue(os);
812 /* Print code that checks that "ptr" is not NULL at the end.
813 * A copy of the isl_ctx is expected to have been saved by
814 * code generated by print_check_ptr_start.
816 * Omit the check if checked C++ bindings are being generated.
818 void cpp_generator::print_check_ptr_end(ostream &os, const char *ptr)
820 if (checked)
821 return;
823 osprintf(os, " if (!%s)\n", ptr);
824 print_throw_last_error(os);
827 /* Print implementation of global factory functions to "os".
829 * Each class has two global factory functions:
831 * set manage(__isl_take isl_set *ptr);
832 * set manage_copy(__isl_keep isl_set *ptr);
834 * Unless checked C++ bindings are being generated,
835 * both functions require the argument to be non-NULL.
836 * An exception is thrown if anything went wrong during the copying
837 * in manage_copy.
838 * During the copying, isl is made not to print any error message
839 * because the error message is included in the exception.
841 * For a subclass based on a type function, no factory functions
842 * are introduced because they share the C object type with
843 * the superclass.
845 void cpp_generator::print_class_factory_impl(ostream &os,
846 const isl_class &clazz)
848 const char *name = clazz.name.c_str();
849 std::string cppstring = type2cpp(clazz);
850 const char *cppname = cppstring.c_str();
852 if (clazz.is_type_subclass())
853 return;
855 osprintf(os, "%s manage(__isl_take %s *ptr) {\n", cppname, name);
856 print_check_ptr(os, "ptr");
857 osprintf(os, " return %s(ptr);\n", cppname);
858 osprintf(os, "}\n");
860 osprintf(os, "%s manage_copy(__isl_keep %s *ptr) {\n", cppname,
861 name);
862 print_check_ptr_start(os, clazz, "ptr");
863 osprintf(os, " ptr = %s_copy(ptr);\n", name);
864 print_check_ptr_end(os, "ptr");
865 osprintf(os, " return %s(ptr);\n", cppname);
866 osprintf(os, "}\n");
869 /* Print implementations of protected constructors for class "clazz" to "os".
871 * The pointer to the isl object is either initialized directly or
872 * through the (immediate) superclass.
874 void cpp_generator::print_protected_constructors_impl(ostream &os,
875 const isl_class &clazz)
877 const char *name = clazz.name.c_str();
878 std::string cppstring = type2cpp(clazz);
879 const char *cppname = cppstring.c_str();
880 bool subclass = clazz.is_type_subclass();
882 osprintf(os, "%s::%s(__isl_take %s *ptr)\n", cppname, cppname, name);
883 if (subclass)
884 osprintf(os, " : %s(ptr) {}\n",
885 type2cpp(clazz.superclass_name).c_str());
886 else
887 osprintf(os, " : ptr(ptr) {}\n");
890 /* Print implementations of public constructors for class "clazz" to "os".
892 * The pointer to the isl object is either initialized directly or
893 * through the (immediate) superclass.
895 * If the class has any persistent callbacks, then copy them
896 * from the original object in the copy constructor.
897 * If the class is a subclass, then the persistent callbacks
898 * are assumed to be copied by the copy constructor of the superclass.
900 * Throw an exception from the copy constructor if anything went wrong
901 * during the copying or if the input is NULL, if any copying is performed.
902 * During the copying, isl is made not to print any error message
903 * because the error message is included in the exception.
904 * No exceptions are thrown if checked C++ bindings
905 * are being generated,
907 void cpp_generator::print_public_constructors_impl(ostream &os,
908 const isl_class &clazz)
910 std::string cppstring = type2cpp(clazz);
911 std::string super;
912 const char *cppname = cppstring.c_str();
913 bool subclass = clazz.is_type_subclass();
915 if (subclass)
916 super = type2cpp(clazz.superclass_name);
917 osprintf(os, "%s::%s()\n", cppname, cppname);
918 if (subclass)
919 osprintf(os, " : %s() {}\n\n", super.c_str());
920 else
921 osprintf(os, " : ptr(nullptr) {}\n\n");
922 osprintf(os, "%s::%s(const %s &obj)\n", cppname, cppname, cppname);
923 if (subclass)
924 osprintf(os, " : %s(obj)\n", super.c_str());
925 else
926 osprintf(os, " : ptr(nullptr)\n");
927 osprintf(os, "{\n");
928 if (!subclass) {
929 print_check_ptr_start(os, clazz, "obj.ptr");
930 osprintf(os, " ptr = obj.copy();\n");
931 if (clazz.has_persistent_callbacks())
932 osprintf(os, " copy_callbacks(obj);\n");
933 print_check_ptr_end(os, "ptr");
935 osprintf(os, "}\n");
938 /* Print implementations of constructors for class "clazz" to "os".
940 void cpp_generator::print_constructors_impl(ostream &os,
941 const isl_class &clazz)
943 set<FunctionDecl *>::const_iterator in;
944 const set<FunctionDecl *> constructors = clazz.constructors;
946 for (in = constructors.begin(); in != constructors.end(); ++in) {
947 FunctionDecl *cons = *in;
949 print_method_impl(os, clazz, cons, function_kind_constructor);
953 /* Print implementation of copy assignment operator for class "clazz" to "os".
955 * If the class has any persistent callbacks, then copy them
956 * from the original object.
958 void cpp_generator::print_copy_assignment_impl(ostream &os,
959 const isl_class &clazz)
961 const char *name = clazz.name.c_str();
962 std::string cppstring = type2cpp(clazz);
963 const char *cppname = cppstring.c_str();
965 osprintf(os, "%s &%s::operator=(%s obj) {\n", cppname,
966 cppname, cppname);
967 osprintf(os, " std::swap(this->ptr, obj.ptr);\n", name);
968 if (clazz.has_persistent_callbacks())
969 osprintf(os, " copy_callbacks(obj);\n");
970 osprintf(os, " return *this;\n");
971 osprintf(os, "}\n");
974 /* Print implementation of destructor for class "clazz" to "os".
976 * No explicit destructor is needed for type based subclasses.
978 void cpp_generator::print_destructor_impl(ostream &os,
979 const isl_class &clazz)
981 const char *name = clazz.name.c_str();
982 std::string cppstring = type2cpp(clazz);
983 const char *cppname = cppstring.c_str();
985 if (clazz.is_type_subclass())
986 return;
988 osprintf(os, "%s::~%s() {\n", cppname, cppname);
989 osprintf(os, " if (ptr)\n");
990 osprintf(os, " %s_free(ptr);\n", name);
991 osprintf(os, "}\n");
994 /* Print a check that the persistent callback corresponding to "fd"
995 * is not set, throwing an exception (or printing an error message
996 * and returning nullptr) if it is set.
998 void cpp_generator::print_check_no_persistent_callback(ostream &os,
999 const isl_class &clazz, FunctionDecl *fd)
1001 string callback_name = clazz.persistent_callback_name(fd);
1003 osprintf(os, " if (%s_data)\n", callback_name.c_str());
1004 print_invalid(os, 4, "cannot release object with persistent callbacks",
1005 "return nullptr");
1008 /* Print implementation of ptr() functions for class "clazz" to "os".
1009 * Since type based subclasses share the pointer with their superclass,
1010 * they can also reuse these functions from the superclass.
1012 * If an object has persistent callbacks set, then the underlying
1013 * C object pointer cannot be released because it references data
1014 * in the C++ object.
1016 void cpp_generator::print_ptr_impl(ostream &os, const isl_class &clazz)
1018 const char *name = clazz.name.c_str();
1019 std::string cppstring = type2cpp(clazz);
1020 const char *cppname = cppstring.c_str();
1021 set<FunctionDecl *>::const_iterator in;
1022 const set<FunctionDecl *> &callbacks = clazz.persistent_callbacks;
1024 if (clazz.is_type_subclass())
1025 return;
1027 osprintf(os, "__isl_give %s *%s::copy() const & {\n", name, cppname);
1028 osprintf(os, " return %s_copy(ptr);\n", name);
1029 osprintf(os, "}\n\n");
1030 osprintf(os, "__isl_keep %s *%s::get() const {\n", name, cppname);
1031 osprintf(os, " return ptr;\n");
1032 osprintf(os, "}\n\n");
1033 osprintf(os, "__isl_give %s *%s::release() {\n", name, cppname);
1034 for (in = callbacks.begin(); in != callbacks.end(); ++in)
1035 print_check_no_persistent_callback(os, clazz, *in);
1036 osprintf(os, " %s *tmp = ptr;\n", name);
1037 osprintf(os, " ptr = nullptr;\n");
1038 osprintf(os, " return tmp;\n");
1039 osprintf(os, "}\n\n");
1040 osprintf(os, "bool %s::is_null() const {\n", cppname);
1041 osprintf(os, " return ptr == nullptr;\n");
1042 osprintf(os, "}\n");
1045 /* Print implementations for the "as" and "isa" methods, if "clazz"
1046 * is a superclass with a type function.
1048 * "isa" checks whether an object is of a given subclass type.
1049 * "isa_type" does the same, but gets passed the value of the type field
1050 * of the subclass as a function argument and the type of this field
1051 * as a template argument.
1052 * "as" casts an object to a given subclass type, erroring out
1053 * if the object is not of the given type.
1055 * If the input is an invalid object, then these methods raise
1056 * an exception.
1057 * If checked bindings are being generated,
1058 * then an invalid boolean or object is returned instead.
1060 * Return true if anything was printed.
1062 bool cpp_generator::print_downcast_impl(ostream &os, const isl_class &clazz)
1064 std::string cppstring = type2cpp(clazz);
1065 const char *cppname = cppstring.c_str();
1067 if (!clazz.fn_type)
1068 return false;
1070 osprintf(os, "template <typename T, typename>\n");
1071 osprintf(os, "%s %s::isa_type(T subtype) const\n",
1072 isl_bool2cpp().c_str(), cppname);
1073 osprintf(os, "{\n");
1074 osprintf(os, " if (is_null())\n");
1075 if (checked)
1076 osprintf(os, " return boolean();\n");
1077 else
1078 print_throw_NULL_input(os);
1079 osprintf(os, " return %s(get()) == subtype;\n",
1080 clazz.fn_type->getNameAsString().c_str());
1081 osprintf(os, "}\n");
1083 osprintf(os, "template <class T>\n");
1084 osprintf(os, "%s %s::isa() const\n", isl_bool2cpp().c_str(), cppname);
1085 osprintf(os, "{\n");
1086 osprintf(os, " return isa_type<decltype(T::type)>(T::type);\n");
1087 osprintf(os, "}\n");
1089 osprintf(os, "template <class T>\n");
1090 osprintf(os, "T %s::as() const\n", cppname);
1091 osprintf(os, "{\n");
1092 if (checked)
1093 osprintf(os, " if (isa<T>().is_false())\n");
1094 else
1095 osprintf(os, " if (!isa<T>())\n");
1096 print_invalid(os, 4, "not an object of the requested subtype",
1097 "return T()");
1098 osprintf(os, " return T(copy());\n");
1099 osprintf(os, "}\n");
1101 return true;
1104 /* Print the implementation of the get_ctx method.
1106 void cpp_generator::print_get_ctx_impl(ostream &os, const isl_class &clazz)
1108 const char *name = clazz.name.c_str();
1109 std::string cppstring = type2cpp(clazz);
1110 const char *cppname = cppstring.c_str();
1112 osprintf(os, "ctx %s::get_ctx() const {\n", cppname);
1113 osprintf(os, " return ctx(%s_get_ctx(ptr));\n", name);
1114 osprintf(os, "}\n");
1117 /* Print the implementations of the methods needed for the persistent callbacks
1118 * of "clazz".
1120 void cpp_generator::print_persistent_callbacks_impl(ostream &os,
1121 const isl_class &clazz)
1123 std::string cppstring = type2cpp(clazz);
1124 const char *cppname = cppstring.c_str();
1125 string classname = type2cpp(clazz);
1126 set<FunctionDecl *>::const_iterator in;
1127 const set<FunctionDecl *> &callbacks = clazz.persistent_callbacks;
1129 if (!clazz.has_persistent_callbacks())
1130 return;
1132 osprintf(os, "%s &%s::copy_callbacks(const %s &obj)\n",
1133 cppname, classname.c_str(), cppname);
1134 osprintf(os, "{\n");
1135 for (in = callbacks.begin(); in != callbacks.end(); ++in) {
1136 string callback_name = clazz.persistent_callback_name(*in);
1138 osprintf(os, " %s_data = obj.%s_data;\n",
1139 callback_name.c_str(), callback_name.c_str());
1141 osprintf(os, " return *this;\n");
1142 osprintf(os, "}\n\n");
1144 for (in = callbacks.begin(); in != callbacks.end(); ++in) {
1145 function_kind kind = function_kind_member_method;
1147 print_set_persistent_callback(os, clazz, *in, kind);
1151 /* Print definitions for methods of class "clazz" to "os".
1153 void cpp_generator::print_methods_impl(ostream &os, const isl_class &clazz)
1155 map<string, set<FunctionDecl *> >::const_iterator it;
1156 bool first = true;
1158 for (it = clazz.methods.begin(); it != clazz.methods.end(); ++it) {
1159 if (first)
1160 first = false;
1161 else
1162 osprintf(os, "\n");
1163 print_method_group_impl(os, clazz, it->second);
1167 /* Print definitions for methods "methods" in class "clazz" to "os".
1169 * "kind" specifies the kind of method that should be generated.
1171 void cpp_generator::print_method_group_impl(ostream &os, const isl_class &clazz,
1172 const set<FunctionDecl *> &methods)
1174 set<FunctionDecl *>::const_iterator it;
1175 bool first = true;
1177 for (it = methods.begin(); it != methods.end(); ++it) {
1178 function_kind kind;
1179 if (first)
1180 first = false;
1181 else
1182 osprintf(os, "\n");
1183 kind = get_method_kind(clazz, *it);
1184 print_method_impl(os, clazz, *it, kind);
1188 /* Print the use of "param" to "os".
1190 * "load_from_this_ptr" specifies whether the parameter should be loaded from
1191 * the this-ptr. In case a value is loaded from a this pointer, the original
1192 * value must be preserved and must consequently be copied. Values that are
1193 * loaded from parameters do not need to be preserved, as such values will
1194 * already be copies of the actual parameters. It is consequently possible
1195 * to directly take the pointer from these values, which saves
1196 * an unnecessary copy.
1198 * In case the parameter is a callback function, two parameters get printed,
1199 * a wrapper for the callback function and a pointer to the actual
1200 * callback function. The wrapper is expected to be available
1201 * in a previously declared variable <name>_lambda, while
1202 * the actual callback function is expected to be stored
1203 * in a structure called <name>_data.
1204 * The caller of this function must ensure that these variables exist.
1206 void cpp_generator::print_method_param_use(ostream &os, ParmVarDecl *param,
1207 bool load_from_this_ptr)
1209 string name = param->getName().str();
1210 const char *name_str = name.c_str();
1211 QualType type = param->getOriginalType();
1213 if (type->isIntegerType()) {
1214 osprintf(os, "%s", name_str);
1215 return;
1218 if (is_string(type)) {
1219 osprintf(os, "%s.c_str()", name_str);
1220 return;
1223 if (is_callback(type)) {
1224 osprintf(os, "%s_lambda, ", name_str);
1225 osprintf(os, "&%s_data", name_str);
1226 return;
1229 if (!load_from_this_ptr)
1230 osprintf(os, "%s.", name_str);
1232 if (keeps(param)) {
1233 osprintf(os, "get()");
1234 } else {
1235 if (load_from_this_ptr)
1236 osprintf(os, "copy()");
1237 else
1238 osprintf(os, "release()");
1242 /* Print code that checks that all isl object arguments to "method" are valid
1243 * (not NULL) and throws an exception if they are not.
1244 * "kind" specifies the kind of method that is being generated.
1246 * If checked bindings are being generated,
1247 * then no such check is performed.
1249 void cpp_generator::print_argument_validity_check(ostream &os,
1250 FunctionDecl *method, function_kind kind)
1252 int n;
1253 bool first = true;
1255 if (checked)
1256 return;
1258 n = method->getNumParams();
1259 for (int i = 0; i < n; ++i) {
1260 bool is_this;
1261 ParmVarDecl *param = method->getParamDecl(i);
1262 string name = param->getName().str();
1263 const char *name_str = name.c_str();
1264 QualType type = param->getOriginalType();
1266 is_this = i == 0 && kind == function_kind_member_method;
1267 if (!is_this && (is_isl_ctx(type) || !is_isl_type(type)))
1268 continue;
1270 if (first)
1271 osprintf(os, " if (");
1272 else
1273 osprintf(os, " || ");
1275 if (is_this)
1276 osprintf(os, "!ptr");
1277 else
1278 osprintf(os, "%s.is_null()", name_str);
1280 first = false;
1282 if (first)
1283 return;
1284 osprintf(os, ")\n");
1285 print_throw_NULL_input(os);
1288 /* Print code for saving a copy of the isl::ctx available at the start
1289 * of the method "method" in a "ctx" variable, for use in exception handling.
1290 * "kind" specifies what kind of method "method" is.
1292 * If checked bindings are being generated,
1293 * then the "ctx" variable is not needed.
1294 * If "method" is a member function, then obtain the isl_ctx from
1295 * the "this" object.
1296 * If the first argument of the method is an isl::ctx, then use that one,
1297 * assuming it is not already called "ctx".
1298 * Otherwise, save a copy of the isl::ctx associated to the first argument
1299 * of isl object type.
1301 void cpp_generator::print_save_ctx(ostream &os, FunctionDecl *method,
1302 function_kind kind)
1304 int n;
1305 ParmVarDecl *param = method->getParamDecl(0);
1306 QualType type = param->getOriginalType();
1308 if (checked)
1309 return;
1310 if (kind == function_kind_member_method) {
1311 osprintf(os, " auto ctx = get_ctx();\n");
1312 return;
1314 if (is_isl_ctx(type)) {
1315 const char *name;
1317 name = param->getName().str().c_str();
1318 if (strcmp(name, "ctx") != 0)
1319 osprintf(os, " auto ctx = %s;\n", name);
1320 return;
1322 n = method->getNumParams();
1323 for (int i = 0; i < n; ++i) {
1324 ParmVarDecl *param = method->getParamDecl(i);
1325 QualType type = param->getOriginalType();
1327 if (!is_isl_type(type))
1328 continue;
1329 osprintf(os, " auto ctx = %s.get_ctx();\n",
1330 param->getName().str().c_str());
1331 return;
1335 /* Print code to make isl not print an error message when an error occurs
1336 * within the current scope (if exceptions are available),
1337 * since the error message will be included in the exception.
1338 * If exceptions are not available, then exception::on_error
1339 * is set to ISL_ON_ERROR_ABORT and isl is therefore made to abort instead.
1341 * If checked bindings are being generated,
1342 * then leave it to the user to decide what isl should do on error.
1343 * Otherwise, assume that a valid isl::ctx is available in the "ctx" variable,
1344 * e.g., through a prior call to print_save_ctx.
1346 void cpp_generator::print_on_error_continue(ostream &os)
1348 if (checked)
1349 return;
1350 osprintf(os, " options_scoped_set_on_error saved_on_error(ctx, "
1351 "exception::on_error);\n");
1354 /* Print code to "os" that checks whether any of the persistent callbacks
1355 * of "clazz" is set and if it failed with an exception. If so, the "eptr"
1356 * in the corresponding data structure contains the exception
1357 * that was caught and that needs to be rethrown.
1358 * This field is cleared because the callback and its data may get reused.
1360 * The check only needs to be generated for member methods since
1361 * an object is needed for any of the persistent callbacks to be set.
1363 static void print_persistent_callback_exceptional_execution_check(ostream &os,
1364 const isl_class &clazz, cpp_generator::function_kind kind)
1366 const set<FunctionDecl *> &callbacks = clazz.persistent_callbacks;
1367 set<FunctionDecl *>::const_iterator in;
1369 if (kind != cpp_generator::function_kind_member_method)
1370 return;
1372 for (in = callbacks.begin(); in != callbacks.end(); ++in) {
1373 string callback_name = clazz.persistent_callback_name(*in);
1375 osprintf(os, " if (%s_data && %s_data->eptr) {\n",
1376 callback_name.c_str(), callback_name.c_str());
1377 osprintf(os, " std::exception_ptr eptr = %s_data->eptr;\n",
1378 callback_name.c_str());
1379 osprintf(os, " %s_data->eptr = nullptr;\n",
1380 callback_name.c_str());
1381 osprintf(os, " std::rethrow_exception(eptr);\n");
1382 osprintf(os, " }\n");
1386 /* Print code that checks whether the execution of the core of "method"
1387 * of class "clazz" was successful.
1388 * "kind" specifies what kind of method "method" is.
1390 * If checked bindings are being generated,
1391 * then no checks are performed.
1393 * Otherwise, first check if any of the callbacks failed with
1394 * an exception. If so, the "eptr" in the corresponding data structure
1395 * contains the exception that was caught and that needs to be rethrown.
1396 * Then check if the function call failed in any other way and throw
1397 * the appropriate exception.
1398 * In particular, if the return type is isl_stat, isl_bool or isl_size,
1399 * then a negative value indicates a failure. If the return type
1400 * is an isl type, then a NULL value indicates a failure.
1401 * Assume print_save_ctx has made sure that a valid isl::ctx
1402 * is available in the "ctx" variable.
1404 void cpp_generator::print_exceptional_execution_check(ostream &os,
1405 const isl_class &clazz, FunctionDecl *method, function_kind kind)
1407 int n;
1408 bool check_null, check_neg;
1409 QualType return_type = method->getReturnType();
1411 if (checked)
1412 return;
1414 print_persistent_callback_exceptional_execution_check(os, clazz, kind);
1416 n = method->getNumParams();
1417 for (int i = 0; i < n; ++i) {
1418 ParmVarDecl *param = method->getParamDecl(i);
1419 const char *name;
1421 if (!is_callback(param->getOriginalType()))
1422 continue;
1423 name = param->getName().str().c_str();
1424 osprintf(os, " if (%s_data.eptr)\n", name);
1425 osprintf(os, " std::rethrow_exception(%s_data.eptr);\n",
1426 name);
1429 check_neg = is_isl_neg_error(return_type);
1430 check_null = is_isl_type(return_type);
1431 if (!check_null && !check_neg)
1432 return;
1434 if (check_neg)
1435 osprintf(os, " if (res < 0)\n");
1436 else
1437 osprintf(os, " if (!res)\n");
1438 print_throw_last_error(os);
1441 /* Does "fd" modify an object of a subclass based on a type function?
1443 static bool is_subclass_mutator(const isl_class &clazz, FunctionDecl *fd)
1445 return clazz.is_type_subclass() && generator::is_mutator(clazz, fd);
1448 /* Return the C++ return type of the method corresponding to "fd" in "clazz".
1450 * If "fd" modifies an object of a subclass, then return
1451 * the type of this subclass.
1452 * Otherwise, return the C++ counterpart of the actual return type.
1454 std::string cpp_generator::get_return_type(const isl_class &clazz,
1455 FunctionDecl *fd)
1457 if (is_subclass_mutator(clazz, fd))
1458 return type2cpp(clazz);
1459 else
1460 return type2cpp(fd->getReturnType());
1463 /* Given a function "method" for setting a "clazz" persistent callback,
1464 * print the implementations of the methods needed for that callback.
1466 * In particular, print
1467 * - the implementation of a static inline method
1468 * for use as the C callback function
1469 * - the definition of a private method for setting the callback function
1470 * - the public method for constructing a new object with the callback set.
1472 void cpp_generator::print_set_persistent_callback(ostream &os,
1473 const isl_class &clazz, FunctionDecl *method,
1474 function_kind kind)
1476 string fullname = method->getName();
1477 ParmVarDecl *param = persistent_callback_arg(method);
1478 string classname = type2cpp(clazz);
1479 string pname;
1480 string callback_name = clazz.persistent_callback_name(method);
1482 print_persistent_callback_prototype(os, clazz, method, false);
1483 osprintf(os, "\n");
1484 osprintf(os, "{\n");
1485 print_callback_body(os, 2, param, callback_name);
1486 osprintf(os, "}\n\n");
1488 pname = param->getName().str();
1489 print_persistent_callback_setter_prototype(os, clazz, method, false);
1490 osprintf(os, "\n");
1491 osprintf(os, "{\n");
1492 print_check_ptr_start(os, clazz, "ptr");
1493 osprintf(os, " %s_data = std::make_shared<struct %s_data>();\n",
1494 callback_name.c_str(), callback_name.c_str());
1495 osprintf(os, " %s_data->func = %s;\n",
1496 callback_name.c_str(), pname.c_str());
1497 osprintf(os, " ptr = %s(ptr, &%s, %s_data.get());\n",
1498 fullname.c_str(), callback_name.c_str(), callback_name.c_str());
1499 print_check_ptr_end(os, "ptr");
1500 osprintf(os, "}\n\n");
1502 print_method_header(os, clazz, method, false, kind);
1503 osprintf(os, "{\n");
1504 osprintf(os, " auto copy = *this;\n");
1505 osprintf(os, " copy.set_%s_data(%s);\n",
1506 callback_name.c_str(), pname.c_str());
1507 osprintf(os, " return copy;\n");
1508 osprintf(os, "}\n\n");
1511 /* Print the return statement of the C++ method corresponding
1512 * to the C function "method" in class "clazz" to "os".
1514 * The result of the isl function is returned as a new
1515 * object if the underlying isl function returns an isl_* ptr, as a bool
1516 * if the isl function returns an isl_bool, as void if the isl functions
1517 * returns an isl_stat,
1518 * as std::string if the isl function returns 'const char *', and as
1519 * unmodified return value otherwise.
1520 * If checked C++ bindings are being generated,
1521 * then an isl_bool return type is transformed into a boolean and
1522 * an isl_stat into a stat since no exceptions can be generated
1523 * on negative results from the isl function.
1524 * If the method returns a new instance of the same object type and
1525 * if the class has any persistent callbacks, then the data
1526 * for these callbacks are copied from the original to the new object.
1527 * If "clazz" is a subclass that is based on a type function and
1528 * if the return type corresponds to the superclass data type,
1529 * then it is replaced by the subclass data type.
1531 void cpp_generator::print_method_return(ostream &os, const isl_class &clazz,
1532 FunctionDecl *method)
1534 QualType return_type = method->getReturnType();
1535 string rettype_str = get_return_type(clazz, method);
1536 bool returns_super = is_subclass_mutator(clazz, method);
1538 if (is_isl_type(return_type) ||
1539 (checked && is_isl_neg_error(return_type))) {
1540 osprintf(os, " return manage(res)");
1541 if (is_mutator(clazz, method) &&
1542 clazz.has_persistent_callbacks())
1543 osprintf(os, ".copy_callbacks(*this)");
1544 if (returns_super)
1545 osprintf(os, ".as<%s>()", rettype_str.c_str());
1546 osprintf(os, ";\n");
1547 } else if (is_isl_stat(return_type)) {
1548 osprintf(os, " return;\n");
1549 } else if (is_string(return_type)) {
1550 osprintf(os, " std::string tmp(res);\n");
1551 if (gives(method))
1552 osprintf(os, " free(res);\n");
1553 osprintf(os, " return tmp;\n");
1554 } else {
1555 osprintf(os, " return res;\n");
1559 /* Print definition for "method" in class "clazz" to "os".
1561 * "kind" specifies the kind of method that should be generated.
1563 * This method distinguishes three kinds of methods: member methods, static
1564 * methods, and constructors.
1566 * Member methods call "method" by passing to the underlying isl function the
1567 * isl object belonging to "this" as first argument and the remaining arguments
1568 * as subsequent arguments.
1570 * Static methods call "method" by passing all arguments to the underlying isl
1571 * function, as no this-pointer is available. The result is a newly managed
1572 * isl C++ object.
1574 * Constructors create a new object from a given set of input parameters. They
1575 * do not return a value, but instead update the pointer stored inside the
1576 * newly created object.
1578 * If the method has a callback argument, we reduce the number of parameters
1579 * that are exposed by one to hide the user pointer from the interface. On
1580 * the C++ side no user pointer is needed, as arguments can be forwarded
1581 * as part of the std::function argument which specifies the callback function.
1583 * Unless checked C++ bindings are being generated,
1584 * the inputs of the method are first checked for being valid isl objects and
1585 * a copy of the associated isl::ctx is saved (if needed).
1586 * If any failure occurs, either during the check for the inputs or
1587 * during the isl function call, an exception is thrown.
1588 * During the function call, isl is made not to print any error message
1589 * because the error message is included in the exception.
1591 void cpp_generator::print_method_impl(ostream &os, const isl_class &clazz,
1592 FunctionDecl *method, function_kind kind)
1594 string methodname = method->getName();
1595 int num_params = method->getNumParams();
1597 print_method_header(os, clazz, method, false, kind);
1598 osprintf(os, "{\n");
1599 print_argument_validity_check(os, method, kind);
1600 print_save_ctx(os, method, kind);
1601 print_on_error_continue(os);
1603 for (int i = 0; i < num_params; ++i) {
1604 ParmVarDecl *param = method->getParamDecl(i);
1605 if (is_callback(param->getType())) {
1606 num_params -= 1;
1607 print_callback_local(os, param);
1611 osprintf(os, " auto res = %s(", methodname.c_str());
1613 for (int i = 0; i < num_params; ++i) {
1614 ParmVarDecl *param = method->getParamDecl(i);
1615 bool load_from_this_ptr = false;
1617 if (i == 0 && kind == function_kind_member_method)
1618 load_from_this_ptr = true;
1620 print_method_param_use(os, param, load_from_this_ptr);
1622 if (i != num_params - 1)
1623 osprintf(os, ", ");
1625 osprintf(os, ");\n");
1627 print_exceptional_execution_check(os, clazz, method, kind);
1628 if (kind == function_kind_constructor) {
1629 osprintf(os, " ptr = res;\n");
1630 } else {
1631 print_method_return(os, clazz, method);
1634 osprintf(os, "}\n");
1637 /* Print the header for "method" in class "clazz", with name "cname" and
1638 * "num_params" number of arguments, to "os".
1640 * Print the header of a declaration if "is_declaration" is set, otherwise print
1641 * the header of a method definition.
1643 * "kind" specifies the kind of method that should be generated.
1645 * This function prints headers for member methods, static methods, and
1646 * constructors, either for their declaration or definition.
1648 * Member functions are declared as "const", as they do not change the current
1649 * object, but instead create a new object. They always retrieve the first
1650 * parameter of the original isl function from the this-pointer of the object,
1651 * such that only starting at the second parameter the parameters of the
1652 * original function become part of the method's interface.
1654 * A function
1656 * __isl_give isl_set *isl_set_intersect(__isl_take isl_set *s1,
1657 * __isl_take isl_set *s2);
1659 * is translated into:
1661 * inline set intersect(set set2) const;
1663 * For static functions and constructors all parameters of the original isl
1664 * function are exposed.
1666 * Parameters that are defined as __isl_keep or are of type string, are passed
1667 * as const reference, which allows the compiler to optimize the parameter
1668 * transfer.
1670 * Constructors are marked as explicit using the C++ keyword 'explicit' or as
1671 * implicit using a comment in place of the explicit keyword. By annotating
1672 * implicit constructors with a comment, users of the interface are made
1673 * aware of the potential danger that implicit construction is possible
1674 * for these constructors, whereas without a comment not every user would
1675 * know that implicit construction is allowed in absence of an explicit keyword.
1677 void cpp_generator::print_method_header(ostream &os, const isl_class &clazz,
1678 FunctionDecl *method, const string &cname, int num_params,
1679 bool is_declaration, function_kind kind)
1681 string rettype_str = get_return_type(clazz, method);
1682 string classname = type2cpp(clazz);
1683 int first_param = 0;
1685 if (kind == function_kind_member_method)
1686 first_param = 1;
1688 if (is_declaration) {
1689 osprintf(os, " ");
1691 if (kind == function_kind_static_method)
1692 osprintf(os, "static ");
1694 osprintf(os, "inline ");
1696 if (kind == function_kind_constructor) {
1697 if (is_implicit_conversion(clazz, method))
1698 osprintf(os, "/* implicit */ ");
1699 else
1700 osprintf(os, "explicit ");
1704 if (kind != function_kind_constructor)
1705 osprintf(os, "%s ", rettype_str.c_str());
1707 if (!is_declaration)
1708 osprintf(os, "%s::", classname.c_str());
1710 if (kind != function_kind_constructor)
1711 osprintf(os, "%s", cname.c_str());
1712 else
1713 osprintf(os, "%s", classname.c_str());
1715 osprintf(os, "(");
1717 for (int i = first_param; i < num_params; ++i) {
1718 ParmVarDecl *param = method->getParamDecl(i);
1719 QualType type = param->getOriginalType();
1720 string cpptype = type2cpp(type);
1722 if (is_callback(type))
1723 num_params--;
1725 if (keeps(param) || is_string(type) || is_callback(type))
1726 osprintf(os, "const %s &%s", cpptype.c_str(),
1727 param->getName().str().c_str());
1728 else
1729 osprintf(os, "%s %s", cpptype.c_str(),
1730 param->getName().str().c_str());
1732 if (i != num_params - 1)
1733 osprintf(os, ", ");
1736 osprintf(os, ")");
1738 if (kind == function_kind_member_method)
1739 osprintf(os, " const");
1741 if (is_declaration)
1742 osprintf(os, ";");
1743 osprintf(os, "\n");
1746 /* Print the header for "method" in class "clazz" to "os".
1748 * Print the header of a declaration if "is_declaration" is set, otherwise print
1749 * the header of a method definition.
1751 * "kind" specifies the kind of method that should be generated.
1753 void cpp_generator::print_method_header(ostream &os, const isl_class &clazz,
1754 FunctionDecl *method, bool is_declaration, function_kind kind)
1756 string cname = clazz.method_name(method);
1757 int num_params = method->getNumParams();
1759 cname = rename_method(cname);
1760 print_method_header(os, clazz, method, cname, num_params,
1761 is_declaration, kind);
1764 /* Generate the list of argument types for a callback function of
1765 * type "type". If "cpp" is set, then generate the C++ type list, otherwise
1766 * the C type list.
1768 * For a callback of type
1770 * isl_stat (*)(__isl_take isl_map *map, void *user)
1772 * the following C++ argument list is generated:
1774 * map
1776 string cpp_generator::generate_callback_args(QualType type, bool cpp)
1778 std::string type_str;
1779 const FunctionProtoType *callback;
1780 int num_params;
1782 callback = extract_prototype(type);
1783 num_params = callback->getNumArgs();
1784 if (cpp)
1785 num_params--;
1787 for (long i = 0; i < num_params; i++) {
1788 QualType type = callback->getArgType(i);
1790 if (cpp)
1791 type_str += type2cpp(type);
1792 else
1793 type_str += type.getAsString();
1795 if (!cpp)
1796 type_str += "arg_" + ::to_string(i);
1798 if (i != num_params - 1)
1799 type_str += ", ";
1802 return type_str;
1805 /* Generate the full cpp type of a callback function of type "type".
1807 * For a callback of type
1809 * isl_stat (*)(__isl_take isl_map *map, void *user)
1811 * the following type is generated:
1813 * std::function<stat(map)>
1815 string cpp_generator::generate_callback_type(QualType type)
1817 std::string type_str;
1818 const FunctionProtoType *callback = extract_prototype(type);
1819 QualType return_type = callback->getReturnType();
1820 string rettype_str = type2cpp(return_type);
1822 type_str = "std::function<";
1823 type_str += rettype_str;
1824 type_str += "(";
1825 type_str += generate_callback_args(type, true);
1826 type_str += ")>";
1828 return type_str;
1831 /* Print the call to the C++ callback function "call",
1832 * with the given indentation, wrapped
1833 * for use inside the lambda function that is used as the C callback function,
1834 * in the case where checked C++ bindings are being generated.
1836 * In particular, print
1838 * auto ret = @call@;
1839 * return ret.release();
1841 void cpp_generator::print_wrapped_call_checked(ostream &os, int indent,
1842 const string &call)
1844 osprintf(os, indent, "auto ret = %s;\n", call.c_str());
1845 osprintf(os, indent, "return ret.release();\n");
1848 /* Print the call to the C++ callback function "call",
1849 * with the given indentation and with return type "rtype", wrapped
1850 * for use inside the lambda function that is used as the C callback function.
1852 * In particular, print
1854 * ISL_CPP_TRY {
1855 * @call@;
1856 * return isl_stat_ok;
1857 * } ISL_CPP_CATCH_ALL {
1858 * data->eptr = std::current_exception();
1859 * return isl_stat_error;
1861 * or
1862 * ISL_CPP_TRY {
1863 * auto ret = @call@;
1864 * return ret ? isl_bool_true : isl_bool_false;
1865 * } ISL_CPP_CATCH_ALL {
1866 * data->eptr = std::current_exception();
1867 * return isl_bool_error;
1869 * or
1870 * ISL_CPP_TRY {
1871 * auto ret = @call@;
1872 * return ret.release();
1873 * } ISL_CPP_CATCH_ALL {
1874 * data->eptr = std::current_exception();
1875 * return NULL;
1878 * depending on the return type.
1880 * where ISL_CPP_TRY is defined to "try" and ISL_CPP_CATCH_ALL to "catch (...)"
1881 * (if exceptions are available).
1883 * If checked C++ bindings are being generated, then
1884 * the call is wrapped differently.
1886 void cpp_generator::print_wrapped_call(ostream &os, int indent,
1887 const string &call, QualType rtype)
1889 if (checked)
1890 return print_wrapped_call_checked(os, indent, call);
1892 osprintf(os, indent, "ISL_CPP_TRY {\n");
1893 if (is_isl_stat(rtype))
1894 osprintf(os, indent, " %s;\n", call.c_str());
1895 else
1896 osprintf(os, indent, " auto ret = %s;\n", call.c_str());
1897 if (is_isl_stat(rtype))
1898 osprintf(os, indent, " return isl_stat_ok;\n");
1899 else if (is_isl_bool(rtype))
1900 osprintf(os, indent,
1901 " return ret ? isl_bool_true : isl_bool_false;\n");
1902 else
1903 osprintf(os, indent, " return ret.release();\n");
1904 osprintf(os, indent, "} ISL_CPP_CATCH_ALL {\n");
1905 osprintf(os, indent, " data->eptr = std::current_exception();\n");
1906 if (is_isl_stat(rtype))
1907 osprintf(os, indent, " return isl_stat_error;\n");
1908 else if (is_isl_bool(rtype))
1909 osprintf(os, indent, " return isl_bool_error;\n");
1910 else
1911 osprintf(os, indent, " return NULL;\n");
1912 osprintf(os, indent, "}\n");
1915 /* Print the declaration for a "prefix"_data data structure
1916 * that can be used for passing to a C callback function
1917 * containing a copy of the C++ callback function "param",
1918 * along with an std::exception_ptr that is used to store any
1919 * exceptions thrown in the C++ callback.
1921 * If the C callback is of the form
1923 * isl_stat (*fn)(__isl_take isl_map *map, void *user)
1925 * then the following declaration is printed:
1927 * struct <prefix>_data {
1928 * std::function<stat(map)> func;
1929 * std::exception_ptr eptr;
1932 * (without a newline or a semicolon).
1934 * The std::exception_ptr object is not added to "prefix"_data
1935 * if checked C++ bindings are being generated.
1937 void cpp_generator::print_callback_data_decl(ostream &os, ParmVarDecl *param,
1938 const string &prefix)
1940 string cpp_args;
1942 cpp_args = generate_callback_type(param->getType());
1944 osprintf(os, " struct %s_data {\n", prefix.c_str());
1945 osprintf(os, " %s func;\n", cpp_args.c_str());
1946 if (!checked)
1947 osprintf(os, " std::exception_ptr eptr;\n");
1948 osprintf(os, " }");
1951 /* Print the body of C function callback with the given indentation
1952 * that can be use as an argument to "param" for marshalling
1953 * the corresponding C++ callback.
1954 * The data structure that contains the C++ callback is of type
1955 * "prefix"_data.
1957 * For a callback of the form
1959 * isl_stat (*fn)(__isl_take isl_map *map, void *user)
1961 * the following code is generated:
1963 * auto *data = static_cast<struct <prefix>_data *>(arg_1);
1964 * ISL_CPP_TRY {
1965 * stat ret = (data->func)(manage(arg_0));
1966 * return isl_stat_ok;
1967 * } ISL_CPP_CATCH_ALL {
1968 * data->eptr = std::current_exception();
1969 * return isl_stat_error;
1972 * If checked C++ bindings are being generated, then
1973 * generate the following code:
1975 * auto *data = static_cast<struct <prefix>_data *>(arg_1);
1976 * stat ret = (data->func)(manage(arg_0));
1977 * return isl_stat(ret);
1979 void cpp_generator::print_callback_body(ostream &os, int indent,
1980 ParmVarDecl *param, const string &prefix)
1982 QualType ptype, rtype;
1983 string call, last_idx;
1984 const FunctionProtoType *callback;
1985 int num_params;
1987 ptype = param->getType();
1989 callback = extract_prototype(ptype);
1990 rtype = callback->getReturnType();
1991 num_params = callback->getNumArgs();
1993 last_idx = ::to_string(num_params - 1);
1995 call = "(data->func)(";
1996 for (long i = 0; i < num_params - 1; i++) {
1997 if (!callback_takes_argument(param, i))
1998 call += "manage_copy";
1999 else
2000 call += "manage";
2001 call += "(arg_" + ::to_string(i) + ")";
2002 if (i != num_params - 2)
2003 call += ", ";
2005 call += ")";
2007 osprintf(os, indent,
2008 "auto *data = static_cast<struct %s_data *>(arg_%s);\n",
2009 prefix.c_str(), last_idx.c_str());
2010 print_wrapped_call(os, indent, call, rtype);
2013 /* Print the local variables that are needed for a callback argument,
2014 * in particular, print a lambda function that wraps the callback and
2015 * a pointer to the actual C++ callback function.
2017 * For a callback of the form
2019 * isl_stat (*fn)(__isl_take isl_map *map, void *user)
2021 * the following lambda function is generated:
2023 * auto fn_lambda = [](isl_map *arg_0, void *arg_1) -> isl_stat {
2024 * auto *data = static_cast<struct fn_data *>(arg_1);
2025 * try {
2026 * stat ret = (data->func)(manage(arg_0));
2027 * return isl_stat_ok;
2028 * } catch (...) {
2029 * data->eptr = std::current_exception();
2030 * return isl_stat_error;
2032 * };
2034 * A copy of the std::function C++ callback function is stored in
2035 * a fn_data data structure for passing to the C callback function,
2036 * along with an std::exception_ptr that is used to store any
2037 * exceptions thrown in the C++ callback.
2039 * struct fn_data {
2040 * std::function<stat(map)> func;
2041 * std::exception_ptr eptr;
2042 * } fn_data = { fn };
2044 * This std::function object represents the actual user
2045 * callback function together with the locally captured state at the caller.
2047 * The lambda function is expected to be used as a C callback function
2048 * where the lambda itself is provided as the function pointer and
2049 * where the user void pointer is a pointer to fn_data.
2050 * The std::function object is extracted from the pointer to fn_data
2051 * inside the lambda function.
2053 * The std::exception_ptr object is not added to fn_data
2054 * if checked C++ bindings are being generated.
2055 * The body of the generated lambda function then is as follows:
2057 * stat ret = (data->func)(manage(arg_0));
2058 * return isl_stat(ret);
2060 * If the C callback does not take its arguments, then
2061 * manage_copy is used instead of manage.
2063 void cpp_generator::print_callback_local(ostream &os, ParmVarDecl *param)
2065 string pname;
2066 QualType ptype, rtype;
2067 string c_args, cpp_args, rettype;
2068 const FunctionProtoType *callback;
2070 pname = param->getName().str();
2071 ptype = param->getType();
2073 c_args = generate_callback_args(ptype, false);
2075 callback = extract_prototype(ptype);
2076 rtype = callback->getReturnType();
2077 rettype = rtype.getAsString();
2079 print_callback_data_decl(os, param, pname);
2080 osprintf(os, " %s_data = { %s };\n", pname.c_str(), pname.c_str());
2081 osprintf(os, " auto %s_lambda = [](%s) -> %s {\n",
2082 pname.c_str(), c_args.c_str(), rettype.c_str());
2083 print_callback_body(os, 4, param, pname);
2084 osprintf(os, " };\n");
2087 /* An array listing functions that must be renamed and the function name they
2088 * should be renamed to. We currently rename functions in case their name would
2089 * match a reserved C++ keyword, which is not allowed in C++.
2091 static const char *rename_map[][2] = {
2092 { "union", "unite" },
2095 /* Rename method "name" in case the method name in the C++ bindings should not
2096 * match the name in the C bindings. We do this for example to avoid
2097 * C++ keywords.
2099 std::string cpp_generator::rename_method(std::string name)
2101 for (size_t i = 0; i < sizeof(rename_map) / sizeof(rename_map[0]); i++)
2102 if (name.compare(rename_map[i][0]) == 0)
2103 return rename_map[i][1];
2105 return name;
2108 /* Translate isl class "clazz" to its corresponding C++ type.
2109 * Use the name of the type based subclass, if any.
2111 string cpp_generator::type2cpp(const isl_class &clazz)
2113 return type2cpp(clazz.subclass_name);
2116 /* Translate type string "type_str" to its C++ name counterpart.
2118 string cpp_generator::type2cpp(string type_str)
2120 return type_str.substr(4);
2123 /* Return the C++ counterpart to the isl_bool type.
2124 * If checked C++ bindings are being generated,
2125 * then this is "boolean". Otherwise, it is simply "bool".
2127 string cpp_generator::isl_bool2cpp()
2129 return checked ? "boolean" : "bool";
2132 /* Translate QualType "type" to its C++ name counterpart.
2134 * An isl_bool return type is translated into "bool",
2135 * while an isl_stat is translated into "void" and
2136 * an isl_size is translated to "unsigned".
2137 * The exceptional cases are handled through exceptions.
2138 * If checked C++ bindings are being generated, then
2139 * C++ counterparts of isl_bool, isl_stat and isl_size need to be used instead.
2141 string cpp_generator::type2cpp(QualType type)
2143 if (is_isl_type(type))
2144 return type2cpp(type->getPointeeType().getAsString());
2146 if (is_isl_bool(type))
2147 return isl_bool2cpp();
2149 if (is_isl_stat(type))
2150 return checked ? "stat" : "void";
2152 if (is_isl_size(type))
2153 return checked ? "class size" : "unsigned";
2155 if (type->isIntegerType())
2156 return type.getAsString();
2158 if (is_string(type))
2159 return "std::string";
2161 if (is_callback(type))
2162 return generate_callback_type(type);
2164 die("Cannot convert type to C++ type");
2167 /* Check if "subclass_type" is a subclass of "class_type".
2169 bool cpp_generator::is_subclass(QualType subclass_type,
2170 const isl_class &class_type)
2172 std::string type_str = subclass_type->getPointeeType().getAsString();
2173 std::vector<std::string> superclasses;
2174 std::vector<const isl_class *> parents;
2175 std::vector<std::string>::iterator ci;
2177 superclasses = generator::find_superclasses(classes[type_str].type);
2179 for (ci = superclasses.begin(); ci < superclasses.end(); ci++)
2180 parents.push_back(&classes[*ci]);
2182 while (!parents.empty()) {
2183 const isl_class *candidate = parents.back();
2185 parents.pop_back();
2187 if (&class_type == candidate)
2188 return true;
2190 superclasses = generator::find_superclasses(candidate->type);
2192 for (ci = superclasses.begin(); ci < superclasses.end(); ci++)
2193 parents.push_back(&classes[*ci]);
2196 return false;
2199 /* Check if "cons" is an implicit conversion constructor of class "clazz".
2201 * An implicit conversion constructor is generated in case "cons" has a single
2202 * parameter, where the parameter type is a subclass of the class that is
2203 * currently being generated.
2205 bool cpp_generator::is_implicit_conversion(const isl_class &clazz,
2206 FunctionDecl *cons)
2208 ParmVarDecl *param = cons->getParamDecl(0);
2209 QualType type = param->getOriginalType();
2211 int num_params = cons->getNumParams();
2212 if (num_params != 1)
2213 return false;
2215 if (is_isl_type(type) && !is_isl_ctx(type) && is_subclass(type, clazz))
2216 return true;
2218 return false;
2221 /* Get kind of "method" in "clazz".
2223 * Given the declaration of a static or member method, returns its kind.
2225 cpp_generator::function_kind cpp_generator::get_method_kind(
2226 const isl_class &clazz, FunctionDecl *method)
2228 if (is_static(clazz, method))
2229 return function_kind_static_method;
2230 else
2231 return function_kind_member_method;