Home | History | Annotate | Line # | Download | only in interface
plain_cpp.cc revision 1.1.1.1
      1 /*
      2  * Copyright 2016, 2017 Tobias Grosser. All rights reserved.
      3  *
      4  * Redistribution and use in source and binary forms, with or without
      5  * modification, are permitted provided that the following conditions
      6  * are met:
      7  *
      8  *    1. Redistributions of source code must retain the above copyright
      9  *       notice, this list of conditions and the following disclaimer.
     10  *
     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.
     15  *
     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 TOBIAS GROSSER 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.
     27  *
     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.
     32  */
     33 
     34 #include <cstdarg>
     35 #include <cstdio>
     36 #include <iostream>
     37 #include <map>
     38 #include <memory>
     39 #include <sstream>
     40 #include <string>
     41 #include <vector>
     42 
     43 #include "plain_cpp.h"
     44 #include "isl_config.h"
     45 
     46 /* Print string formatted according to "fmt" to ostream "os".
     47  *
     48  * This osprintf method allows us to use printf style formatting constructs when
     49  * writing to an ostream.
     50  */
     51 static void osprintf(ostream &os, const char *format, va_list arguments)
     52 {
     53 	va_list copy;
     54 	char *string_pointer;
     55 	size_t size;
     56 
     57 	va_copy(copy, arguments);
     58 	size = vsnprintf(NULL, 0, format, copy);
     59 	string_pointer = new char[size + 1];
     60 	va_end(copy);
     61 	vsnprintf(string_pointer, size + 1, format, arguments);
     62 	os << string_pointer;
     63 	delete[] string_pointer;
     64 }
     65 
     66 /* Print string formatted according to "fmt" to ostream "os".
     67  *
     68  * This osprintf method allows us to use printf style formatting constructs when
     69  * writing to an ostream.
     70  */
     71 static void osprintf(ostream &os, const char *format, ...)
     72 {
     73 	va_list arguments;
     74 
     75 	va_start(arguments, format);
     76 	osprintf(os, format, arguments);
     77 	va_end(arguments);
     78 }
     79 
     80 /* Print string formatted according to "fmt" to ostream "os"
     81  * with the given indentation.
     82  *
     83  * This osprintf method allows us to use printf style formatting constructs when
     84  * writing to an ostream.
     85  */
     86 static void osprintf(ostream &os, int indent, const char *format, ...)
     87 {
     88 	va_list arguments;
     89 
     90 	osprintf(os, "%*s", indent, " ");
     91 	va_start(arguments, format);
     92 	osprintf(os, format, arguments);
     93 	va_end(arguments);
     94 }
     95 
     96 /* Convert "l" to a string.
     97  */
     98 static std::string to_string(long l)
     99 {
    100 	std::ostringstream strm;
    101 	strm << l;
    102 	return strm.str();
    103 }
    104 
    105 /* Construct a generator for plain C++ bindings.
    106  *
    107  * "checked" is set if C++ bindings should be generated
    108  * that rely on the user to check for error conditions.
    109  */
    110 plain_cpp_generator::plain_cpp_generator(SourceManager &SM,
    111 	set<RecordDecl *> &exported_types,
    112 	set<FunctionDecl *> exported_functions, set<FunctionDecl *> functions,
    113 	bool checked) :
    114 		cpp_generator(SM, exported_types, exported_functions,
    115 			functions),
    116 		checked(checked)
    117 {
    118 }
    119 
    120 /* Generate a cpp interface based on the extracted types and functions.
    121  *
    122  * Print first a set of forward declarations for all isl wrapper
    123  * classes, then the declarations of the classes, and at the end all
    124  * implementations.
    125  *
    126  * If checked C++ bindings are being generated,
    127  * then wrap them in a namespace to avoid conflicts
    128  * with the default C++ bindings (with automatic checks using exceptions).
    129  */
    130 void plain_cpp_generator::generate()
    131 {
    132 	ostream &os = cout;
    133 
    134 	osprintf(os, "\n");
    135 	osprintf(os, "namespace isl {\n\n");
    136 	if (checked)
    137 		osprintf(os, "namespace checked {\n\n");
    138 
    139 	print_forward_declarations(os);
    140 	osprintf(os, "\n");
    141 	print_declarations(os);
    142 	osprintf(os, "\n");
    143 	print_implementations(os);
    144 
    145 	if (checked)
    146 		osprintf(os, "} // namespace checked\n");
    147 	osprintf(os, "} // namespace isl\n");
    148 }
    149 
    150 /* Print forward declarations for all classes to "os".
    151 */
    152 void plain_cpp_generator::print_forward_declarations(ostream &os)
    153 {
    154 	map<string, isl_class>::iterator ci;
    155 
    156 	osprintf(os, "// forward declarations\n");
    157 
    158 	for (ci = classes.begin(); ci != classes.end(); ++ci)
    159 		print_class_forward_decl(os, ci->second);
    160 }
    161 
    162 /* Print all declarations to "os".
    163  */
    164 void plain_cpp_generator::print_declarations(ostream &os)
    165 {
    166 	map<string, isl_class>::iterator ci;
    167 	bool first = true;
    168 
    169 	for (ci = classes.begin(); ci != classes.end(); ++ci) {
    170 		if (first)
    171 			first = false;
    172 		else
    173 			osprintf(os, "\n");
    174 
    175 		print_class(os, ci->second);
    176 	}
    177 }
    178 
    179 /* Print all implementations to "os".
    180  */
    181 void plain_cpp_generator::print_implementations(ostream &os)
    182 {
    183 	map<string, isl_class>::iterator ci;
    184 	bool first = true;
    185 
    186 	for (ci = classes.begin(); ci != classes.end(); ++ci) {
    187 		if (first)
    188 			first = false;
    189 		else
    190 			osprintf(os, "\n");
    191 
    192 		print_class_impl(os, ci->second);
    193 	}
    194 }
    195 
    196 /* If the printed class is a subclass that is based on a type function,
    197  * then introduce a "type" field that holds the value of the type
    198  * corresponding to the subclass and make the fields of the class
    199  * accessible to the "isa" and "as" methods of the (immediate) superclass.
    200  * In particular, "isa" needs access to the type field itself,
    201  * while "as" needs access to the private constructor.
    202  * In case of the "isa" method, all instances are made friends
    203  * to avoid access right confusion.
    204  */
    205 void plain_cpp_generator::decl_printer::print_subclass_type()
    206 {
    207 	std::string super;
    208 	const char *cppname = cppstring.c_str();
    209 	const char *supername;
    210 
    211 	if (!clazz.is_type_subclass())
    212 		return;
    213 
    214 	super = type2cpp(clazz.superclass_name);
    215 	supername = super.c_str();
    216 	osprintf(os, "  template <class T>\n");
    217 	osprintf(os, "  friend %s %s::isa() const;\n",
    218 		generator.isl_bool2cpp().c_str(), supername);
    219 	osprintf(os, "  friend %s %s::as<%s>() const;\n",
    220 		cppname, supername, cppname);
    221 	osprintf(os, "  static const auto type = %s;\n",
    222 		clazz.subclass_name.c_str());
    223 }
    224 
    225 /* Print declarations for class "clazz" to "os".
    226  *
    227  * If "clazz" is a subclass based on a type function,
    228  * then it is made to inherit from the (immediate) superclass and
    229  * a "type" attribute is added for use in the "as" and "isa"
    230  * methods of the superclass.
    231  *
    232  * Conversely, if "clazz" is a superclass with a type function,
    233  * then declare those "as" and "isa" methods.
    234  *
    235  * The pointer to the isl object is only added for classes that
    236  * are not subclasses, since subclasses refer to the same isl object.
    237  */
    238 void plain_cpp_generator::print_class(ostream &os, const isl_class &clazz)
    239 {
    240 	decl_printer printer(os, clazz, *this);
    241 	const char *name = clazz.name.c_str();
    242 	const char *cppname = printer.cppstring.c_str();
    243 
    244 	osprintf(os, "// declarations for isl::%s\n", cppname);
    245 
    246 	printer.print_class_factory();
    247 	osprintf(os, "\n");
    248 	osprintf(os, "class %s ", cppname);
    249 	if (clazz.is_type_subclass())
    250 		osprintf(os, ": public %s ",
    251 			type2cpp(clazz.superclass_name).c_str());
    252 	osprintf(os, "{\n");
    253 	printer.print_subclass_type();
    254 	printer.print_class_factory("  friend ");
    255 	osprintf(os, "\n");
    256 	osprintf(os, "protected:\n");
    257 	if (!clazz.is_type_subclass()) {
    258 		osprintf(os, "  %s *ptr = nullptr;\n", name);
    259 		osprintf(os, "\n");
    260 	}
    261 	printer.print_protected_constructors();
    262 	osprintf(os, "\n");
    263 	osprintf(os, "public:\n");
    264 	printer.print_public_methods();
    265 
    266 	osprintf(os, "};\n");
    267 }
    268 
    269 /* Print forward declaration of class "clazz" to "os".
    270  */
    271 void plain_cpp_generator::print_class_forward_decl(ostream &os,
    272 	const isl_class &clazz)
    273 {
    274 	std::string cppstring = type2cpp(clazz);
    275 	const char *cppname = cppstring.c_str();
    276 
    277 	osprintf(os, "class %s;\n", cppname);
    278 }
    279 
    280 /* Print global factory functions.
    281  *
    282  * Each class has two global factory functions:
    283  *
    284  * 	set manage(__isl_take isl_set *ptr);
    285  * 	set manage_copy(__isl_keep isl_set *ptr);
    286  *
    287  * A user can construct isl C++ objects from a raw pointer and indicate whether
    288  * they intend to take the ownership of the object or not through these global
    289  * factory functions. This ensures isl object creation is very explicit and
    290  * pointers are not converted by accident. Thanks to overloading, manage() and
    291  * manage_copy() can be called on any isl raw pointer and the corresponding
    292  * object is automatically created, without the user having to choose the right
    293  * isl object type.
    294  *
    295  * For a subclass based on a type function, no factory functions
    296  * are introduced because they share the C object type with
    297  * the superclass.
    298  */
    299 void plain_cpp_generator::decl_printer::print_class_factory(
    300 	const std::string &prefix)
    301 {
    302 	const char *name = clazz.name.c_str();
    303 	const char *cppname = cppstring.c_str();
    304 
    305 	if (clazz.is_type_subclass())
    306 		return;
    307 
    308 	os << prefix;
    309 	osprintf(os, "inline %s manage(__isl_take %s *ptr);\n", cppname, name);
    310 	os << prefix;
    311 	osprintf(os, "inline %s manage_copy(__isl_keep %s *ptr);\n",
    312 		cppname, name);
    313 }
    314 
    315 /* Print declarations of protected constructors.
    316  *
    317  * Each class has currently one protected constructor:
    318  *
    319  * 	1) Constructor from a plain isl_* C pointer
    320  *
    321  * Example:
    322  *
    323  * 	set(__isl_take isl_set *ptr);
    324  *
    325  * The raw pointer constructor is kept protected. Object creation is only
    326  * possible through manage() or manage_copy().
    327  */
    328 void plain_cpp_generator::decl_printer::print_protected_constructors()
    329 {
    330 	const char *name = clazz.name.c_str();
    331 	const char *cppname = cppstring.c_str();
    332 
    333 	osprintf(os, "  inline explicit %s(__isl_take %s *ptr);\n", cppname,
    334 		 name);
    335 }
    336 
    337 /* Print declarations of public constructors.
    338  *
    339  * Each class currently has two public constructors:
    340  *
    341  * 	1) A default constructor
    342  * 	2) A copy constructor
    343  *
    344  * Example:
    345  *
    346  *	set();
    347  *	set(const set &set);
    348  */
    349 void plain_cpp_generator::decl_printer::print_public_constructors()
    350 {
    351 	const char *cppname = cppstring.c_str();
    352 	osprintf(os, "  inline /* implicit */ %s();\n", cppname);
    353 
    354 	osprintf(os, "  inline /* implicit */ %s(const %s &obj);\n",
    355 		 cppname, cppname);
    356 }
    357 
    358 /* Print declarations for "method".
    359  */
    360 void plain_cpp_generator::decl_printer::print_method(
    361 	const ConversionMethod &method)
    362 {
    363 	print_full_method_header(method);
    364 }
    365 
    366 /* Print declarations for "method".
    367  */
    368 void plain_cpp_generator::decl_printer::print_method(const Method &method)
    369 {
    370 	print_full_method_header(method);
    371 }
    372 
    373 /* Print a declaration for a constructor for the "id" class
    374  * that takes a user object.
    375  */
    376 void plain_cpp_generator::decl_printer::print_id_constructor_user()
    377 {
    378 	print_id_constructor_user_header();
    379 }
    380 
    381 /* Print a declaration for an "id" method
    382  * for retrieving the user object associated to the identifier.
    383  * If "optional" is set, the method returns a std::optional user object.
    384  */
    385 void plain_cpp_generator::decl_printer::print_id_user(bool optional)
    386 {
    387 	print_id_user_header(optional);
    388 }
    389 
    390 /* Print declarations of copy assignment operator.
    391  *
    392  * Each class has one assignment operator.
    393  *
    394  * 	isl:set &set::operator=(set obj)
    395  *
    396  */
    397 void plain_cpp_generator::decl_printer::print_copy_assignment()
    398 {
    399 	const char *cppname = cppstring.c_str();
    400 
    401 	osprintf(os, "  inline %s &operator=(%s obj);\n", cppname, cppname);
    402 }
    403 
    404 /* Print declaration of destructor.
    405  *
    406  * No explicit destructor is needed for type based subclasses.
    407  */
    408 void plain_cpp_generator::decl_printer::print_destructor()
    409 {
    410 	const char *cppname = cppstring.c_str();
    411 
    412 	if (clazz.is_type_subclass())
    413 		return;
    414 
    415 	osprintf(os, "  inline ~%s();\n", cppname);
    416 }
    417 
    418 /* Print declaration of pointer functions.
    419  * Since type based subclasses share the pointer with their superclass,
    420  * they can also reuse these functions from the superclass.
    421  *
    422  * To obtain a raw pointer three functions are provided:
    423  *
    424  * 	1) __isl_give isl_set *copy()
    425  *
    426  * 	  Returns a pointer to a _copy_ of the internal object
    427  *
    428  * 	2) __isl_keep isl_set *get()
    429  *
    430  * 	  Returns a pointer to the internal object
    431  *
    432  * 	3) __isl_give isl_set *release()
    433  *
    434  * 	  Returns a pointer to the internal object and resets the
    435  * 	  internal pointer to nullptr.
    436  *
    437  * We also provide functionality to explicitly check if a pointer is
    438  * currently managed by this object.
    439  *
    440  * 	4) bool is_null()
    441  *
    442  * 	  Check if the current object is a null pointer.
    443  *
    444  * The functions get() and release() model the value_ptr proposed in
    445  * http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2012/n3339.pdf.
    446  * The copy() function is an extension to allow the user to explicitly
    447  * copy the underlying object.
    448  *
    449  * Also generate a declaration to delete copy() for r-values, for
    450  * r-values release() should be used to avoid unnecessary copies.
    451  */
    452 void plain_cpp_generator::decl_printer::print_ptr()
    453 {
    454 	const char *name = clazz.name.c_str();
    455 
    456 	if (clazz.is_type_subclass())
    457 		return;
    458 
    459 	osprintf(os, "  inline __isl_give %s *copy() const &;\n", name);
    460 	osprintf(os, "  inline __isl_give %s *copy() && = delete;\n", name);
    461 	osprintf(os, "  inline __isl_keep %s *get() const;\n", name);
    462 	osprintf(os, "  inline __isl_give %s *release();\n", name);
    463 	osprintf(os, "  inline bool is_null() const;\n");
    464 }
    465 
    466 /* Print a template declaration with given indentation
    467  * for the "isa_type" method that ensures it is only enabled
    468  * when called with a template argument
    469  * that represents a type that is equal to that
    470  * of the return type of the type function of "super".
    471  * In particular, "isa_type" gets called from "isa"
    472  * with as template argument the type of the "type" field
    473  * of the subclass.
    474  * The check ensures that this subclass is in fact a direct subclass
    475  * of "super".
    476  */
    477 void plain_cpp_generator::decl_printer::print_isa_type_template(int indent,
    478 	const isl_class &super)
    479 {
    480 	osprintf(os, indent,
    481 		"template <typename T,\n");
    482 	osprintf(os, indent,
    483 		"        typename = typename std::enable_if<std::is_same<\n");
    484 	osprintf(os, indent,
    485 		"                const decltype(%s(NULL)),\n",
    486 		super.fn_type->getNameAsString().c_str());
    487 	osprintf(os, indent,
    488 		"                const T>::value>::type>\n");
    489 }
    490 
    491 /* Print declarations for the "as" and "isa" methods, if the printed class
    492  * is a superclass with a type function.
    493  *
    494  * "isa" checks whether an object is of a given subclass type.
    495  * "isa_type" does the same, but gets passed the value of the type field
    496  * of the subclass as a function argument and the type of this field
    497  * as a template argument.
    498  * "as" tries to cast an object to a given subclass type, returning
    499  * an invalid object if the object is not of the given type.
    500  */
    501 void plain_cpp_generator::decl_printer::print_downcast()
    502 {
    503 	if (!clazz.fn_type)
    504 		return;
    505 
    506 	osprintf(os, "private:\n");
    507 	print_isa_type_template(2, clazz);
    508 	osprintf(os, "  inline %s isa_type(T subtype) const;\n",
    509 		generator.isl_bool2cpp().c_str());
    510 	osprintf(os, "public:\n");
    511 	osprintf(os, "  template <class T> inline %s isa() const;\n",
    512 		generator.isl_bool2cpp().c_str());
    513 	osprintf(os, "  template <class T> inline T as() const;\n");
    514 }
    515 
    516 /* Print the declaration of the ctx method.
    517  */
    518 void plain_cpp_generator::decl_printer::print_ctx()
    519 {
    520 	std::string ns = generator.isl_namespace();
    521 
    522 	osprintf(os, "  inline %sctx ctx() const;\n", ns.c_str());
    523 }
    524 
    525 /* Print a separator between groups of method declarations.
    526  */
    527 void plain_cpp_generator::decl_printer::print_method_separator()
    528 {
    529 	os << "\n";
    530 }
    531 
    532 /* Add a space to the return type "type" if needed,
    533  * i.e., if it is not the type of a pointer.
    534  */
    535 static string add_space_to_return_type(const string &type)
    536 {
    537 	if (type[type.size() - 1] == '*')
    538 		return type;
    539 	return type + " ";
    540 }
    541 
    542 /* Print the prototype of the static inline method that is used
    543  * as the C callback set by "method".
    544  */
    545 void plain_cpp_generator::plain_printer::print_persistent_callback_prototype(
    546 	FunctionDecl *method)
    547 {
    548 	string callback_name, rettype, c_args;
    549 	ParmVarDecl *param = persistent_callback_arg(method);
    550 	const FunctionProtoType *callback;
    551 	QualType ptype;
    552 	string classname;
    553 
    554 	ptype = param->getType();
    555 	callback = extract_prototype(ptype);
    556 
    557 	rettype = callback->getReturnType().getAsString();
    558 	rettype = add_space_to_return_type(rettype);
    559 	callback_name = clazz.persistent_callback_name(method);
    560 	c_args = generator.generate_callback_args(ptype, false);
    561 
    562 	if (!declarations)
    563 		classname = type2cpp(clazz) + "::";
    564 
    565 	osprintf(os, "%s%s%s(%s)",
    566 		 rettype.c_str(), classname.c_str(),
    567 		 callback_name.c_str(), c_args.c_str());
    568 }
    569 
    570 /* Print the prototype of the method for setting the callback function
    571  * set by "method".
    572  */
    573 void
    574 plain_cpp_generator::plain_printer::print_persistent_callback_setter_prototype(
    575 	FunctionDecl *method)
    576 {
    577 	string classname, callback_name, cpptype;
    578 	ParmVarDecl *param = persistent_callback_arg(method);
    579 
    580 	if (!declarations)
    581 		classname = type2cpp(clazz) + "::";
    582 
    583 	cpptype = generator.param2cpp(param->getOriginalType());
    584 	callback_name = clazz.persistent_callback_name(method);
    585 	osprintf(os, "void %sset_%s_data(const %s &%s)",
    586 		classname.c_str(), callback_name.c_str(), cpptype.c_str(),
    587 		param->getName().str().c_str());
    588 }
    589 
    590 /* Given a method "method" for setting a persistent callback,
    591  * print the fields that are needed for marshalling the callback.
    592  *
    593  * In particular, print
    594  * - the declaration of a data structure for storing the C++ callback function
    595  * - a shared pointer to such a data structure
    596  * - the declaration of a static inline method
    597  *   for use as the C callback function
    598  * - the declaration of a private method for setting the callback function
    599  */
    600 void plain_cpp_generator::decl_printer::print_persistent_callback_data(
    601 	FunctionDecl *method)
    602 {
    603 	string callback_name;
    604 	ParmVarDecl *param = generator.persistent_callback_arg(method);
    605 
    606 	callback_name = clazz.persistent_callback_name(method);
    607 	print_callback_data_decl(param, callback_name);
    608 	osprintf(os, ";\n");
    609 	osprintf(os, "  std::shared_ptr<%s_data> %s_data;\n",
    610 		callback_name.c_str(), callback_name.c_str());
    611 	osprintf(os, "  static inline ");
    612 	print_persistent_callback_prototype(method);
    613 	osprintf(os, ";\n");
    614 	osprintf(os, "  inline ");
    615 	print_persistent_callback_setter_prototype(method);
    616 	osprintf(os, ";\n");
    617 }
    618 
    619 /* Print declarations needed for the persistent callbacks of the class.
    620  *
    621  * In particular, if there are any persistent callbacks, then
    622  * print a private method for copying callback data from
    623  * one object to another,
    624  * private data for keeping track of the persistent callbacks and
    625  * public methods for setting the persistent callbacks.
    626  */
    627 void plain_cpp_generator::decl_printer::print_persistent_callbacks()
    628 {
    629 	const char *cppname = cppstring.c_str();
    630 
    631 	if (!clazz.has_persistent_callbacks())
    632 		return;
    633 
    634 	osprintf(os, "private:\n");
    635 	osprintf(os, "  inline %s &copy_callbacks(const %s &obj);\n",
    636 		cppname, cppname);
    637 	for (const auto &callback : clazz.persistent_callbacks)
    638 		print_persistent_callback_data(callback);
    639 
    640 	osprintf(os, "public:\n");
    641 	for (const auto &callback : clazz.persistent_callbacks)
    642 		print_method(Method(clazz, callback));
    643 }
    644 
    645 /* Print a declaration for the "get" method "fd",
    646  * using a name that includes the "get_" prefix.
    647  */
    648 void plain_cpp_generator::decl_printer::print_get_method(FunctionDecl *fd)
    649 {
    650 	string base = clazz.base_method_name(fd);
    651 
    652 	print_method(Method(clazz, fd, base));
    653 }
    654 
    655 /* Print implementations for class "clazz" to "os".
    656  */
    657 void plain_cpp_generator::print_class_impl(ostream &os, const isl_class &clazz)
    658 {
    659 	impl_printer printer(os, clazz, *this);
    660 	const char *cppname = printer.cppstring.c_str();
    661 
    662 	osprintf(os, "// implementations for isl::%s", cppname);
    663 
    664 	printer.print_class_factory();
    665 	printer.print_protected_constructors();
    666 	printer.print_public_methods();
    667 	printer.print_stream_insertion();
    668 }
    669 
    670 /* Print code for throwing an exception corresponding to the last error
    671  * that occurred on "saved_ctx".
    672  * This assumes that a valid isl::ctx is available in the "saved_ctx" variable,
    673  * e.g., through a prior call to print_save_ctx.
    674  */
    675 static void print_throw_last_error(ostream &os)
    676 {
    677 	osprintf(os, "    exception::throw_last_error(saved_ctx);\n");
    678 }
    679 
    680 /* Print code with the given indentation
    681  * for throwing an exception_invalid with the given message.
    682  */
    683 static void print_throw_invalid(ostream &os, int indent, const char *msg)
    684 {
    685 	osprintf(os, indent,
    686 		"exception::throw_invalid(\"%s\", __FILE__, __LINE__);\n", msg);
    687 }
    688 
    689 /* Print code for throwing an exception on NULL input.
    690  */
    691 static void print_throw_NULL_input(ostream &os)
    692 {
    693 	print_throw_invalid(os, 4, "NULL input");
    694 }
    695 
    696 /* Print code with the given indentation
    697  * for acting on an invalid error with message "msg".
    698  * In particular, throw an exception_invalid.
    699  * In the checked C++ bindings, isl_die is called instead with the code
    700  * in "checked_code".
    701  */
    702 void plain_cpp_generator::print_invalid(ostream &os, int indent,
    703 	const char *msg, const char *checked_code)
    704 {
    705 	if (checked)
    706 		osprintf(os, indent,
    707 			"isl_die(ctx().get(), isl_error_invalid, "
    708 			"\"%s\", %s);\n", msg, checked_code);
    709 	else
    710 		print_throw_invalid(os, indent, msg);
    711 }
    712 
    713 /* Print an operator for inserting objects of the class
    714  * into an output stream.
    715  *
    716  * Unless checked C++ bindings are being generated,
    717  * the operator requires its argument to be non-NULL.
    718  * An exception is thrown if anything went wrong during the printing.
    719  * During this printing, isl is made not to print any error message
    720  * because the error message is included in the exception.
    721  *
    722  * If checked C++ bindings are being generated and anything went wrong,
    723  * then record this failure in the output stream.
    724  */
    725 void plain_cpp_generator::impl_printer::print_stream_insertion()
    726 {
    727 	const char *name = clazz.name.c_str();
    728 	const char *cppname = cppstring.c_str();
    729 
    730 	if (!clazz.fn_to_str)
    731 		return;
    732 
    733 	osprintf(os, "\n");
    734 	osprintf(os, "inline std::ostream &operator<<(std::ostream &os, ");
    735 	osprintf(os, "const %s &obj)\n", cppname);
    736 	osprintf(os, "{\n");
    737 	print_check_ptr_start("obj.get()");
    738 	osprintf(os, "  char *str = %s_to_str(obj.get());\n", name);
    739 	print_check_ptr_end("str");
    740 	if (generator.checked) {
    741 		osprintf(os, "  if (!str) {\n");
    742 		osprintf(os, "    os.setstate(std::ios_base::badbit);\n");
    743 		osprintf(os, "    return os;\n");
    744 		osprintf(os, "  }\n");
    745 	}
    746 	osprintf(os, "  os << str;\n");
    747 	osprintf(os, "  free(str);\n");
    748 	osprintf(os, "  return os;\n");
    749 	osprintf(os, "}\n");
    750 }
    751 
    752 /* Print code that checks that "ptr" is not NULL at input.
    753  *
    754  * Omit the check if checked C++ bindings are being generated.
    755  */
    756 void plain_cpp_generator::impl_printer::print_check_ptr(const char *ptr)
    757 {
    758 	if (generator.checked)
    759 		return;
    760 
    761 	osprintf(os, "  if (!%s)\n", ptr);
    762 	print_throw_NULL_input(os);
    763 }
    764 
    765 /* Print code that checks that "ptr" is not NULL at input and
    766  * that saves a copy of the isl_ctx of "ptr" for a later check.
    767  *
    768  * Omit the check if checked C++ bindings are being generated.
    769  */
    770 void plain_cpp_generator::impl_printer::print_check_ptr_start(const char *ptr)
    771 {
    772 	if (generator.checked)
    773 		return;
    774 
    775 	print_check_ptr(ptr);
    776 	print_save_ctx(clazz.name + "_get_ctx(" + ptr + ")");
    777 	print_on_error_continue();
    778 }
    779 
    780 /* Print code that checks that "ptr" is not NULL at the end.
    781  * A copy of the isl_ctx is expected to have been saved by
    782  * code generated by print_check_ptr_start.
    783  *
    784  * Omit the check if checked C++ bindings are being generated.
    785  */
    786 void plain_cpp_generator::impl_printer::print_check_ptr_end(const char *ptr)
    787 {
    788 	if (generator.checked)
    789 		return;
    790 
    791 	osprintf(os, "  if (!%s)\n", ptr);
    792 	print_throw_last_error(os);
    793 }
    794 
    795 /* Print implementation of global factory functions.
    796  *
    797  * Each class has two global factory functions:
    798  *
    799  * 	set manage(__isl_take isl_set *ptr);
    800  * 	set manage_copy(__isl_keep isl_set *ptr);
    801  *
    802  * Unless checked C++ bindings are being generated,
    803  * both functions require the argument to be non-NULL.
    804  * An exception is thrown if anything went wrong during the copying
    805  * in manage_copy.
    806  * During the copying, isl is made not to print any error message
    807  * because the error message is included in the exception.
    808  *
    809  * For a subclass based on a type function, no factory functions
    810  * are introduced because they share the C object type with
    811  * the superclass.
    812  */
    813 void plain_cpp_generator::impl_printer::print_class_factory()
    814 {
    815 	const char *name = clazz.name.c_str();
    816 	const char *cppname = cppstring.c_str();
    817 
    818 	if (clazz.is_type_subclass())
    819 		return;
    820 
    821 	osprintf(os, "\n");
    822 	osprintf(os, "%s manage(__isl_take %s *ptr) {\n", cppname, name);
    823 	print_check_ptr("ptr");
    824 	osprintf(os, "  return %s(ptr);\n", cppname);
    825 	osprintf(os, "}\n");
    826 
    827 	osprintf(os, "%s manage_copy(__isl_keep %s *ptr) {\n", cppname,
    828 		name);
    829 	print_check_ptr_start("ptr");
    830 	osprintf(os, "  ptr = %s_copy(ptr);\n", name);
    831 	print_check_ptr_end("ptr");
    832 	osprintf(os, "  return %s(ptr);\n", cppname);
    833 	osprintf(os, "}\n");
    834 }
    835 
    836 /* Print implementations of protected constructors.
    837  *
    838  * The pointer to the isl object is either initialized directly or
    839  * through the (immediate) superclass.
    840  */
    841 void plain_cpp_generator::impl_printer::print_protected_constructors()
    842 {
    843 	const char *name = clazz.name.c_str();
    844 	const char *cppname = cppstring.c_str();
    845 	bool subclass = clazz.is_type_subclass();
    846 
    847 	osprintf(os, "\n");
    848 	osprintf(os, "%s::%s(__isl_take %s *ptr)\n", cppname, cppname, name);
    849 	if (subclass)
    850 		osprintf(os, "    : %s(ptr) {}\n",
    851 			type2cpp(clazz.superclass_name).c_str());
    852 	else
    853 		osprintf(os, "    : ptr(ptr) {}\n");
    854 }
    855 
    856 /* Print implementations of public constructors.
    857  *
    858  * The pointer to the isl object is either initialized directly or
    859  * through the (immediate) superclass.
    860  *
    861  * If the class has any persistent callbacks, then copy them
    862  * from the original object in the copy constructor.
    863  * If the class is a subclass, then the persistent callbacks
    864  * are assumed to be copied by the copy constructor of the superclass.
    865  *
    866  * Throw an exception from the copy constructor if anything went wrong
    867  * during the copying or if the input is NULL, if any copying is performed.
    868  * During the copying, isl is made not to print any error message
    869  * because the error message is included in the exception.
    870  * No exceptions are thrown if checked C++ bindings
    871  * are being generated,
    872  */
    873 void plain_cpp_generator::impl_printer::print_public_constructors()
    874 {
    875 	std::string super;
    876 	const char *cppname = cppstring.c_str();
    877 	bool subclass = clazz.is_type_subclass();
    878 
    879 	osprintf(os, "\n");
    880 	if (subclass)
    881 		super = type2cpp(clazz.superclass_name);
    882 	osprintf(os, "%s::%s()\n", cppname, cppname);
    883 	if (subclass)
    884 		osprintf(os, "    : %s() {}\n\n", super.c_str());
    885 	else
    886 		osprintf(os, "    : ptr(nullptr) {}\n\n");
    887 	osprintf(os, "%s::%s(const %s &obj)\n", cppname, cppname, cppname);
    888 	if (subclass)
    889 		osprintf(os, "    : %s(obj)\n", super.c_str());
    890 	else
    891 		osprintf(os, "    : ptr(nullptr)\n");
    892 	osprintf(os, "{\n");
    893 	if (!subclass) {
    894 		print_check_ptr_start("obj.ptr");
    895 		osprintf(os, "  ptr = obj.copy();\n");
    896 		if (clazz.has_persistent_callbacks())
    897 			osprintf(os, "  copy_callbacks(obj);\n");
    898 		print_check_ptr_end("ptr");
    899 	}
    900 	osprintf(os, "}\n");
    901 }
    902 
    903 /* Print definition for "method",
    904  * without any automatic type conversions.
    905  *
    906  * This method distinguishes three kinds of methods: member methods, static
    907  * methods, and constructors.
    908  *
    909  * Member methods and static methods return a newly managed
    910  * isl C++ object.
    911  *
    912  * Constructors create a new object from a given set of input parameters. They
    913  * do not return a value, but instead update the pointer stored inside the
    914  * newly created object.
    915  *
    916  * Unless checked C++ bindings are being generated,
    917  * the inputs of the method are first checked for being valid isl objects and
    918  * a copy of the associated isl::ctx is saved (if needed).
    919  * If any failure occurs, either during the check for the inputs or
    920  * during the isl function call, an exception is thrown.
    921  * During the function call, isl is made not to print any error message
    922  * because the error message is included in the exception.
    923  */
    924 void plain_cpp_generator::impl_printer::print_method(const Method &method)
    925 {
    926 	string methodname = method.fd->getName().str();
    927 	int num_params = method.c_num_params();
    928 
    929 	osprintf(os, "\n");
    930 	print_full_method_header(method);
    931 	osprintf(os, "{\n");
    932 	print_argument_validity_check(method);
    933 	print_save_ctx(method);
    934 	print_on_error_continue();
    935 
    936 	for (const auto &callback : method.callbacks)
    937 		print_callback_local(callback);
    938 
    939 	osprintf(os, "  auto res = %s", methodname.c_str());
    940 
    941 	method.print_fd_arg_list(os, 0, num_params, [&] (int i, int arg) {
    942 		method.print_param_use(os, i);
    943 	});
    944 	osprintf(os, ";\n");
    945 
    946 	print_exceptional_execution_check(method);
    947 	if (method.kind == Method::Kind::constructor) {
    948 		osprintf(os, "  ptr = res;\n");
    949 	} else {
    950 		print_method_return(method);
    951 	}
    952 
    953 	osprintf(os, "}\n");
    954 }
    955 
    956 /* Convert argument of type "src" to "dst", with a name specified by "dst".
    957  *
    958  * If "src" is the same as "dst", then no argument conversion is needed.
    959  *
    960  * Otherwise, call the conversion function
    961  * with as arguments the isl_ctx of the object and the argument name,
    962  * or simply the argument name if the source type is an isl type.
    963  * This means this isl_ctx should be available.
    964  */
    965 void plain_cpp_generator::impl_printer::print_arg_conversion(ParmVarDecl *dst,
    966 	ParmVarDecl *src)
    967 {
    968 	std::string name = dst->getName().str();
    969 	QualType type = dst->getOriginalType();
    970 	string cpptype = generator.param2cpp(type);
    971 
    972 	if (dst == src)
    973 		os << name;
    974 	else if (is_isl_type(src->getOriginalType()))
    975 		os << cpptype << "(" << name << ")";
    976 	else
    977 		os << cpptype << "(ctx(), " << name << ")";
    978 }
    979 
    980 /* Print a definition for "method",
    981  * where "this" or at least one of the argument types needs to be converted.
    982  *
    983  * "method" is assumed to be a member method.
    984  *
    985  * The generated method performs the required conversion(s) and
    986  * calls the method generated without conversions.
    987  *
    988  * Perform a conversion from the argument in the method declaration
    989  * (as specified by Method::get_param) to the argument of the C function,
    990  * if needed.
    991  * Such a conversion may require the isl_ctx to be available.
    992  * In order to be able to use this isl_ctx, the current object needs
    993  * to valid.  The validity of other arguments is checked
    994  * by the called method.
    995  */
    996 void plain_cpp_generator::impl_printer::print_method(
    997 	const ConversionMethod &method)
    998 {
    999 	if (method.kind != Method::Kind::member_method)
   1000 		die("Automatic conversion currently only supported "
   1001 		    "for object methods");
   1002 
   1003 	osprintf(os, "\n");
   1004 	print_full_method_header(method);
   1005 	osprintf(os, "{\n");
   1006 	print_check_ptr("ptr");
   1007 	osprintf(os, "  return ");
   1008 	method.print_call(os, generator.isl_namespace());
   1009 	method.print_cpp_arg_list(os, [&] (int i, int arg) {
   1010 		ParmVarDecl *param = method.fd->getParamDecl(i);
   1011 
   1012 		print_arg_conversion(param, method.get_param(i));
   1013 	});
   1014 	osprintf(os, ";\n");
   1015 	osprintf(os, "}\n");
   1016 }
   1017 
   1018 /* Print a definition for a constructor for the "id" class
   1019  * that takes a user object.
   1020  *
   1021  * The user object is taken as a std::any and copied into
   1022  * a new std::any object on the heap.
   1023  * A pointer to this heap object is stored in the isl_id and
   1024  * is scheduled to be freed when the reference count of the isl_id
   1025  * drops to zero.
   1026  * If the allocation of the isl_id fails, then the heap object
   1027  * will not be freed automatically, so it needs to be freed manually.
   1028  *
   1029  * Unless checked C++ bindings are being generated,
   1030  * the ctx argument is copied into the save_ctx variable
   1031  * for use by print_throw_last_error, which throws an exception
   1032  * if the construction fails.
   1033  * During the function call, isl is made not to print any error message
   1034  * because the error message is included in the exception.
   1035  */
   1036 void plain_cpp_generator::impl_printer::print_id_constructor_user()
   1037 {
   1038 	print_id_constructor_user_header();
   1039 	os << "{\n";
   1040 	if (!generator.checked) {
   1041 		print_save_ctx("ctx");
   1042 		print_on_error_continue();
   1043 	}
   1044 	os << "  std::any *p = new std::any(any);\n";
   1045 	os << "  auto res = isl_id_alloc(ctx.get(), str.c_str(), p);\n";
   1046 	os << "  res = isl_id_set_free_user(res, &ctx::free_user);\n";
   1047 	os << "  if (!res) {\n";
   1048 	os << "    delete p;\n";
   1049 	if (!generator.checked)
   1050 		print_throw_last_error(os);
   1051 	os << "  }\n";
   1052 	os << "  ptr = res;\n";
   1053 	os << "}\n";
   1054 }
   1055 
   1056 /* Print a definition for an "id" method
   1057  * for retrieving the user object associated to the identifier.
   1058  * If "optional" is set, the method returns a std::optional user object.
   1059  * The returned object is of a type specified by template parameter T.
   1060  *
   1061  * The isl_id needs to have been created by the constructor generated
   1062  * by print_id_constructor_user.  That is, it needs to have a user pointer and
   1063  * it needs to have its free_user callback set to &ctx::free_user.
   1064  * The object stored in the std::any also needs to be of the required type.
   1065  *
   1066  * If "optional" is set, return a std::nullopt if any of the checks fail.
   1067  * Otherwise, throw an exception_invalid (or call isl_die and
   1068  * return a default T in the checked C++ bindings).
   1069  */
   1070 void plain_cpp_generator::impl_printer::print_id_user(bool optional)
   1071 {
   1072 	auto fail = [&] (const char *msg) {
   1073 		if (optional)
   1074 			os << "    return std::nullopt;\n";
   1075 		else
   1076 			generator.print_invalid(os, 4, msg, "return T()");
   1077 	};
   1078 	os << "\n";
   1079 	print_id_user_header(optional);
   1080 	os << "{\n";
   1081 	print_check_ptr("ptr");
   1082 	os << "  std::any *p = (std::any *) isl_id_get_user(ptr);\n";
   1083 	os << "  if (!p)\n";
   1084 	fail("no user pointer");
   1085 	os << "  if (isl_id_get_free_user(ptr) != &ctx::free_user)\n";
   1086 	fail("user pointer not attached by C++ interface");
   1087 	os << "  T *res = std::any_cast<T>(p);\n";
   1088 	os << "  if (!res)\n";
   1089 	fail("user pointer not of given type");
   1090 	os << "  return *res;\n";
   1091 	os << "}\n";
   1092 }
   1093 
   1094 /* Print implementation of copy assignment operator.
   1095  *
   1096  * If the class has any persistent callbacks, then copy them
   1097  * from the original object.
   1098  */
   1099 void plain_cpp_generator::impl_printer::print_copy_assignment()
   1100 {
   1101 	const char *name = clazz.name.c_str();
   1102 	const char *cppname = cppstring.c_str();
   1103 
   1104 	osprintf(os, "\n");
   1105 	osprintf(os, "%s &%s::operator=(%s obj) {\n", cppname,
   1106 		 cppname, cppname);
   1107 	osprintf(os, "  std::swap(this->ptr, obj.ptr);\n", name);
   1108 	if (clazz.has_persistent_callbacks())
   1109 		osprintf(os, "  copy_callbacks(obj);\n");
   1110 	osprintf(os, "  return *this;\n");
   1111 	osprintf(os, "}\n");
   1112 }
   1113 
   1114 /* Print implementation of destructor.
   1115  *
   1116  * No explicit destructor is needed for type based subclasses.
   1117  */
   1118 void plain_cpp_generator::impl_printer::print_destructor()
   1119 {
   1120 	const char *name = clazz.name.c_str();
   1121 	const char *cppname = cppstring.c_str();
   1122 
   1123 	if (clazz.is_type_subclass())
   1124 		return;
   1125 
   1126 	osprintf(os, "\n");
   1127 	osprintf(os, "%s::~%s() {\n", cppname, cppname);
   1128 	osprintf(os, "  if (ptr)\n");
   1129 	osprintf(os, "    %s_free(ptr);\n", name);
   1130 	osprintf(os, "}\n");
   1131 }
   1132 
   1133 /* Print a check that the persistent callback corresponding to "fd"
   1134  * is not set, throwing an exception (or printing an error message
   1135  * and returning nullptr) if it is set.
   1136  */
   1137 void plain_cpp_generator::print_check_no_persistent_callback(ostream &os,
   1138 	const isl_class &clazz, FunctionDecl *fd)
   1139 {
   1140 	string callback_name = clazz.persistent_callback_name(fd);
   1141 
   1142 	osprintf(os, "  if (%s_data)\n", callback_name.c_str());
   1143 	print_invalid(os, 4, "cannot release object with persistent callbacks",
   1144 			    "return nullptr");
   1145 }
   1146 
   1147 /* Print implementation of ptr() functions.
   1148  * Since type based subclasses share the pointer with their superclass,
   1149  * they can also reuse these functions from the superclass.
   1150  *
   1151  * If an object has persistent callbacks set, then the underlying
   1152  * C object pointer cannot be released because it references data
   1153  * in the C++ object.
   1154  */
   1155 void plain_cpp_generator::impl_printer::print_ptr()
   1156 {
   1157 	const char *name = clazz.name.c_str();
   1158 	const char *cppname = cppstring.c_str();
   1159 	set<FunctionDecl *>::const_iterator in;
   1160 	const set<FunctionDecl *> &callbacks = clazz.persistent_callbacks;
   1161 
   1162 	if (clazz.is_type_subclass())
   1163 		return;
   1164 
   1165 	osprintf(os, "\n");
   1166 	osprintf(os, "__isl_give %s *%s::copy() const & {\n", name, cppname);
   1167 	osprintf(os, "  return %s_copy(ptr);\n", name);
   1168 	osprintf(os, "}\n\n");
   1169 	osprintf(os, "__isl_keep %s *%s::get() const {\n", name, cppname);
   1170 	osprintf(os, "  return ptr;\n");
   1171 	osprintf(os, "}\n\n");
   1172 	osprintf(os, "__isl_give %s *%s::release() {\n", name, cppname);
   1173 	for (in = callbacks.begin(); in != callbacks.end(); ++in)
   1174 		generator.print_check_no_persistent_callback(os, clazz, *in);
   1175 	osprintf(os, "  %s *tmp = ptr;\n", name);
   1176 	osprintf(os, "  ptr = nullptr;\n");
   1177 	osprintf(os, "  return tmp;\n");
   1178 	osprintf(os, "}\n\n");
   1179 	osprintf(os, "bool %s::is_null() const {\n", cppname);
   1180 	osprintf(os, "  return ptr == nullptr;\n");
   1181 	osprintf(os, "}\n");
   1182 }
   1183 
   1184 /* Print implementations for the "as" and "isa" methods, if the printed class
   1185  * is a superclass with a type function.
   1186  *
   1187  * "isa" checks whether an object is of a given subclass type.
   1188  * "isa_type" does the same, but gets passed the value of the type field
   1189  * of the subclass as a function argument and the type of this field
   1190  * as a template argument.
   1191  * "as" casts an object to a given subclass type, erroring out
   1192  * if the object is not of the given type.
   1193  *
   1194  * If the input is an invalid object, then these methods raise
   1195  * an exception.
   1196  * If checked bindings are being generated,
   1197  * then an invalid boolean or object is returned instead.
   1198  */
   1199 void plain_cpp_generator::impl_printer::print_downcast()
   1200 {
   1201 	const char *cppname = cppstring.c_str();
   1202 
   1203 	if (!clazz.fn_type)
   1204 		return;
   1205 
   1206 	osprintf(os, "\n");
   1207 	osprintf(os, "template <typename T, typename>\n");
   1208 	osprintf(os, "%s %s::isa_type(T subtype) const\n",
   1209 		generator.isl_bool2cpp().c_str(), cppname);
   1210 	osprintf(os, "{\n");
   1211 	osprintf(os, "  if (is_null())\n");
   1212 	if (generator.checked)
   1213 		osprintf(os, "    return boolean();\n");
   1214 	else
   1215 		print_throw_NULL_input(os);
   1216 	osprintf(os, "  return %s(get()) == subtype;\n",
   1217 		clazz.fn_type->getNameAsString().c_str());
   1218 	osprintf(os, "}\n");
   1219 
   1220 	osprintf(os, "template <class T>\n");
   1221 	osprintf(os, "%s %s::isa() const\n",
   1222 		generator.isl_bool2cpp().c_str(), cppname);
   1223 	osprintf(os, "{\n");
   1224 	osprintf(os, "  return isa_type<decltype(T::type)>(T::type);\n");
   1225 	osprintf(os, "}\n");
   1226 
   1227 	osprintf(os, "template <class T>\n");
   1228 	osprintf(os, "T %s::as() const\n", cppname);
   1229 	osprintf(os, "{\n");
   1230 	if (generator.checked)
   1231 		osprintf(os, " if (isa<T>().is_false())\n");
   1232 	else
   1233 		osprintf(os, " if (!isa<T>())\n");
   1234 	generator.print_invalid(os, 4, "not an object of the requested subtype",
   1235 		    "return T()");
   1236 	osprintf(os, "  return T(copy());\n");
   1237 	osprintf(os, "}\n");
   1238 }
   1239 
   1240 /* Print the implementation of the ctx method.
   1241  */
   1242 void plain_cpp_generator::impl_printer::print_ctx()
   1243 {
   1244 	const char *name = clazz.name.c_str();
   1245 	const char *cppname = cppstring.c_str();
   1246 	std::string ns = generator.isl_namespace();
   1247 
   1248 	osprintf(os, "\n");
   1249 	osprintf(os, "%sctx %s::ctx() const {\n", ns.c_str(), cppname);
   1250 	osprintf(os, "  return %sctx(%s_get_ctx(ptr));\n", ns.c_str(), name);
   1251 	osprintf(os, "}\n");
   1252 }
   1253 
   1254 /* Print a separator between groups of method definitions.
   1255  *
   1256  * No additional separator is required between method definitions.
   1257  */
   1258 void plain_cpp_generator::impl_printer::print_method_separator()
   1259 {
   1260 }
   1261 
   1262 /* Print the implementations of the methods needed for the persistent callbacks
   1263  * of the class.
   1264  */
   1265 void plain_cpp_generator::impl_printer::print_persistent_callbacks()
   1266 {
   1267 	const char *cppname = cppstring.c_str();
   1268 	string classname = type2cpp(clazz);
   1269 
   1270 	if (!clazz.has_persistent_callbacks())
   1271 		return;
   1272 
   1273 	osprintf(os, "\n");
   1274 	osprintf(os, "%s &%s::copy_callbacks(const %s &obj)\n",
   1275 		cppname, classname.c_str(), cppname);
   1276 	osprintf(os, "{\n");
   1277 	for (const auto &callback : clazz.persistent_callbacks) {
   1278 		string callback_name = clazz.persistent_callback_name(callback);
   1279 
   1280 		osprintf(os, "  %s_data = obj.%s_data;\n",
   1281 			callback_name.c_str(), callback_name.c_str());
   1282 	}
   1283 	osprintf(os, "  return *this;\n");
   1284 	osprintf(os, "}\n");
   1285 
   1286 	for (const auto &callback : clazz.persistent_callbacks)
   1287 		print_set_persistent_callback(Method(clazz, callback));
   1288 }
   1289 
   1290 /* Print a definition for the "get" method "fd" in class "clazz",
   1291  * using a name that includes the "get_" prefix, to "os".
   1292  *
   1293  * This definition simply calls the variant without the "get_" prefix and
   1294  * returns its result.
   1295  * Note that static methods are not considered to be "get" methods.
   1296  */
   1297 void plain_cpp_generator::impl_printer::print_get_method(FunctionDecl *fd)
   1298 {
   1299 	string get_name = clazz.base_method_name(fd);
   1300 	string name = clazz.method_name(fd);
   1301 	int num_params = fd->getNumParams();
   1302 
   1303 	osprintf(os, "\n");
   1304 	print_full_method_header(Method(clazz, fd, get_name));
   1305 	osprintf(os, "{\n");
   1306 	osprintf(os, "  return %s(", name.c_str());
   1307 	for (int i = 1; i < num_params; ++i) {
   1308 		ParmVarDecl *param = fd->getParamDecl(i);
   1309 
   1310 		if (i != 1)
   1311 			osprintf(os, ", ");
   1312 		osprintf(os, "%s", param->getName().str().c_str());
   1313 	}
   1314 	osprintf(os, ");\n");
   1315 	osprintf(os, "}\n");
   1316 }
   1317 
   1318 /* Print code that checks that all isl object arguments to "method" are valid
   1319  * (not NULL) and throws an exception if they are not.
   1320  *
   1321  * If checked bindings are being generated,
   1322  * then no such check is performed.
   1323  */
   1324 void plain_cpp_generator::impl_printer::print_argument_validity_check(
   1325 	const Method &method)
   1326 {
   1327 	int n;
   1328 	bool first = true;
   1329 
   1330 	if (generator.checked)
   1331 		return;
   1332 
   1333 	n = method.num_params();
   1334 	for (int i = 0; i < n; ++i) {
   1335 		bool is_this;
   1336 		ParmVarDecl *param = method.fd->getParamDecl(i);
   1337 		string name = param->getName().str();
   1338 		const char *name_str = name.c_str();
   1339 		QualType type = param->getOriginalType();
   1340 
   1341 		is_this = i == 0 && method.kind == Method::Kind::member_method;
   1342 		if (!is_this && (is_isl_ctx(type) || !is_isl_type(type)))
   1343 			continue;
   1344 
   1345 		if (first)
   1346 			osprintf(os, "  if (");
   1347 		else
   1348 			osprintf(os, " || ");
   1349 
   1350 		if (is_this)
   1351 			osprintf(os, "!ptr");
   1352 		else
   1353 			osprintf(os, "%s.is_null()", name_str);
   1354 
   1355 		first = false;
   1356 	}
   1357 	if (first)
   1358 		return;
   1359 	osprintf(os, ")\n");
   1360 	print_throw_NULL_input(os);
   1361 }
   1362 
   1363 /* Print code for saving a copy of "ctx" in a "saved_ctx" variable.
   1364  */
   1365 void plain_cpp_generator::impl_printer::print_save_ctx(const std::string &ctx)
   1366 {
   1367 	os << "  auto saved_ctx = " << ctx << ";\n";
   1368 }
   1369 
   1370 /* Print code for saving a copy of the isl::ctx available at the start
   1371  * of the method "method" in a "saved_ctx" variable,
   1372  * for use in exception handling.
   1373  *
   1374  * If checked bindings are being generated,
   1375  * then the "saved_ctx" variable is not needed.
   1376  * If "method" is a member function, then obtain the isl_ctx from
   1377  * the "this" object.
   1378  * If the first argument of the method is an isl::ctx, then use that one.
   1379  * Otherwise, save a copy of the isl::ctx associated to the first argument
   1380  * of isl object type.
   1381  */
   1382 void plain_cpp_generator::impl_printer::print_save_ctx(const Method &method)
   1383 {
   1384 	int n;
   1385 	ParmVarDecl *param = method.fd->getParamDecl(0);
   1386 	QualType type = param->getOriginalType();
   1387 
   1388 	if (generator.checked)
   1389 		return;
   1390 	if (method.kind == Method::Kind::member_method)
   1391 		return print_save_ctx("ctx()");
   1392 	if (is_isl_ctx(type))
   1393 		return print_save_ctx(param->getName().str());
   1394 	n = method.num_params();
   1395 	for (int i = 0; i < n; ++i) {
   1396 		ParmVarDecl *param = method.fd->getParamDecl(i);
   1397 		QualType type = param->getOriginalType();
   1398 
   1399 		if (!is_isl_type(type))
   1400 			continue;
   1401 		print_save_ctx(param->getName().str() + ".ctx()");
   1402 		return;
   1403 	}
   1404 }
   1405 
   1406 /* Print code to make isl not print an error message when an error occurs
   1407  * within the current scope (if exceptions are available),
   1408  * since the error message will be included in the exception.
   1409  * If exceptions are not available, then exception::on_error
   1410  * is set to ISL_ON_ERROR_ABORT and isl is therefore made to abort instead.
   1411  *
   1412  * If checked bindings are being generated,
   1413  * then leave it to the user to decide what isl should do on error.
   1414  * Otherwise, assume that a valid isl::ctx is available
   1415  * in the "saved_ctx" variable,
   1416  * e.g., through a prior call to print_save_ctx.
   1417  */
   1418 void plain_cpp_generator::impl_printer::print_on_error_continue()
   1419 {
   1420 	if (generator.checked)
   1421 		return;
   1422 	osprintf(os, "  options_scoped_set_on_error saved_on_error(saved_ctx, "
   1423 		     "exception::on_error);\n");
   1424 }
   1425 
   1426 /* Print code to "os" that checks whether any of the persistent callbacks
   1427  * of the class of "method" is set and if it failed with an exception.
   1428  * If so, the "eptr" in the corresponding data structure contains the exception
   1429  * that was caught and that needs to be rethrown.
   1430  * This field is cleared because the callback and its data may get reused.
   1431  *
   1432  * The check only needs to be generated for member methods since
   1433  * an object is needed for any of the persistent callbacks to be set.
   1434  */
   1435 static void print_persistent_callback_exceptional_execution_check(ostream &os,
   1436 	const Method &method)
   1437 {
   1438 	if (method.kind != Method::Kind::member_method)
   1439 		return;
   1440 
   1441 	for (const auto &pcb : method.clazz.persistent_callbacks) {
   1442 		auto callback_name = method.clazz.persistent_callback_name(pcb);
   1443 
   1444 		osprintf(os, "  if (%s_data && %s_data->eptr) {\n",
   1445 			callback_name.c_str(), callback_name.c_str());
   1446 		osprintf(os, "    std::exception_ptr eptr = %s_data->eptr;\n",
   1447 			callback_name.c_str());
   1448 		osprintf(os, "    %s_data->eptr = nullptr;\n",
   1449 			callback_name.c_str());
   1450 		osprintf(os, "    std::rethrow_exception(eptr);\n");
   1451 		osprintf(os, "  }\n");
   1452 	}
   1453 }
   1454 
   1455 /* Print code that checks whether the execution of the core of "method"
   1456  * was successful.
   1457  *
   1458  * If checked bindings are being generated,
   1459  * then no checks are performed.
   1460  *
   1461  * Otherwise, first check if any of the callbacks failed with
   1462  * an exception.  If so, the "eptr" in the corresponding data structure
   1463  * contains the exception that was caught and that needs to be rethrown.
   1464  * Then check if the function call failed in any other way and throw
   1465  * the appropriate exception.
   1466  * In particular, if the return type is isl_stat, isl_bool or isl_size,
   1467  * then a negative value indicates a failure.  If the return type
   1468  * is an isl type, then a NULL value indicates a failure.
   1469  * Assume print_save_ctx has made sure that a valid isl::ctx
   1470  * is available in the "ctx" variable.
   1471  */
   1472 void plain_cpp_generator::impl_printer::print_exceptional_execution_check(
   1473 	const Method &method)
   1474 {
   1475 	bool check_null, check_neg;
   1476 	QualType return_type = method.fd->getReturnType();
   1477 
   1478 	if (generator.checked)
   1479 		return;
   1480 
   1481 	print_persistent_callback_exceptional_execution_check(os, method);
   1482 
   1483 	for (const auto &callback : method.callbacks) {
   1484 		std::string name;
   1485 
   1486 		name = callback->getName().str();
   1487 		osprintf(os, "  if (%s_data.eptr)\n", name.c_str());
   1488 		osprintf(os, "    std::rethrow_exception(%s_data.eptr);\n",
   1489 			name.c_str());
   1490 	}
   1491 
   1492 	check_neg = is_isl_neg_error(return_type);
   1493 	check_null = is_isl_type(return_type);
   1494 	if (!check_null && !check_neg)
   1495 		return;
   1496 
   1497 	if (check_neg)
   1498 		osprintf(os, "  if (res < 0)\n");
   1499 	else
   1500 		osprintf(os, "  if (!res)\n");
   1501 	print_throw_last_error(os);
   1502 }
   1503 
   1504 /* Return a pointer to the appropriate type printer,
   1505  * i.e., the regular type printer or the checked type printer
   1506  * depending on the setting of this->checked.
   1507  */
   1508 std::unique_ptr<cpp_type_printer> plain_cpp_generator::type_printer()
   1509 {
   1510 	cpp_type_printer *printer;
   1511 
   1512 	if (checked)
   1513 		printer = new checked_cpp_type_printer();
   1514 	else
   1515 		printer = new cpp_type_printer();
   1516 
   1517 	return std::unique_ptr<cpp_type_printer>(printer);
   1518 }
   1519 
   1520 /* Return the C++ return type of the method "method".
   1521  *
   1522  * Use the appropriate type printer.
   1523  */
   1524 std::string plain_cpp_generator::get_return_type(const Method &method)
   1525 {
   1526 	return type_printer()->return_type(method);
   1527 }
   1528 
   1529 /* Given a method "method" for setting a persistent callback of its class,
   1530  * print the implementations of the methods needed for that callback.
   1531  *
   1532  * In particular, print
   1533  * - the implementation of a static inline method
   1534  *   for use as the C callback function
   1535  * - the definition of a private method for setting the callback function
   1536  * - the public method for constructing a new object with the callback set.
   1537  */
   1538 void plain_cpp_generator::impl_printer::print_set_persistent_callback(
   1539 	const Method &method)
   1540 {
   1541 	string fullname = method.fd->getName().str();
   1542 	ParmVarDecl *param = persistent_callback_arg(method.fd);
   1543 	string pname;
   1544 	string callback_name = clazz.persistent_callback_name(method.fd);
   1545 
   1546 	osprintf(os, "\n");
   1547 	print_persistent_callback_prototype(method.fd);
   1548 	osprintf(os, "\n");
   1549 	osprintf(os, "{\n");
   1550 	print_callback_body(2, param, callback_name);
   1551 	osprintf(os, "}\n\n");
   1552 
   1553 	pname = param->getName().str();
   1554 	print_persistent_callback_setter_prototype(method.fd);
   1555 	osprintf(os, "\n");
   1556 	osprintf(os, "{\n");
   1557 	print_check_ptr_start("ptr");
   1558 	osprintf(os, "  %s_data = std::make_shared<struct %s_data>();\n",
   1559 		callback_name.c_str(), callback_name.c_str());
   1560 	osprintf(os, "  %s_data->func = %s;\n",
   1561 		callback_name.c_str(), pname.c_str());
   1562 	osprintf(os, "  ptr = %s(ptr, &%s, %s_data.get());\n",
   1563 		fullname.c_str(), callback_name.c_str(), callback_name.c_str());
   1564 	print_check_ptr_end("ptr");
   1565 	osprintf(os, "}\n\n");
   1566 
   1567 	print_full_method_header(method);
   1568 	osprintf(os, "{\n");
   1569 	osprintf(os, "  auto copy = *this;\n");
   1570 	osprintf(os, "  copy.set_%s_data(%s);\n",
   1571 		callback_name.c_str(), pname.c_str());
   1572 	osprintf(os, "  return copy;\n");
   1573 	osprintf(os, "}\n");
   1574 }
   1575 
   1576 /* Print the return statement of the C++ method "method".
   1577  *
   1578  * The result of the corresponding isl function is returned as a new
   1579  * object if the underlying isl function returns an isl_* ptr, as a bool
   1580  * if the isl function returns an isl_bool, as void if the isl functions
   1581  * returns an isl_stat,
   1582  * as std::string if the isl function returns 'const char *', and as
   1583  * unmodified return value otherwise.
   1584  * If checked C++ bindings are being generated,
   1585  * then an isl_bool return type is transformed into a boolean and
   1586  * an isl_stat into a stat since no exceptions can be generated
   1587  * on negative results from the isl function.
   1588  * If the method returns a new instance of the same object type and
   1589  * if the class has any persistent callbacks, then the data
   1590  * for these callbacks are copied from the original to the new object.
   1591  * If "clazz" is a subclass that is based on a type function and
   1592  * if the return type corresponds to the superclass data type,
   1593  * then it is replaced by the subclass data type.
   1594  */
   1595 void plain_cpp_generator::impl_printer::print_method_return(
   1596 	const Method &method)
   1597 {
   1598 	QualType return_type = method.fd->getReturnType();
   1599 	string rettype_str = generator.get_return_type(method);
   1600 	bool returns_super = method.is_subclass_mutator();
   1601 
   1602 	if (is_isl_type(return_type) ||
   1603 		    (generator.checked && is_isl_neg_error(return_type))) {
   1604 		osprintf(os, "  return manage(res)");
   1605 		if (is_mutator(clazz, method.fd) &&
   1606 		    clazz.has_persistent_callbacks())
   1607 			osprintf(os, ".copy_callbacks(*this)");
   1608 		if (returns_super)
   1609 			osprintf(os, ".as<%s>()", rettype_str.c_str());
   1610 		osprintf(os, ";\n");
   1611 	} else if (is_isl_stat(return_type)) {
   1612 		osprintf(os, "  return;\n");
   1613 	} else if (is_string(return_type)) {
   1614 		osprintf(os, "  std::string tmp(res);\n");
   1615 		if (gives(method.fd))
   1616 			osprintf(os, "  free(res);\n");
   1617 		osprintf(os, "  return tmp;\n");
   1618 	} else {
   1619 		osprintf(os, "  return res;\n");
   1620 	}
   1621 }
   1622 
   1623 /* Print the header for "method", including the terminating semicolon
   1624  * in case of a declaration and a newline.
   1625  *
   1626  * Use the appropriate type printer to print argument and return types.
   1627  */
   1628 void plain_cpp_generator::plain_printer::print_full_method_header(
   1629 	const Method &method)
   1630 {
   1631 	auto type_printer = generator.type_printer();
   1632 
   1633 	print_method_header(method, *type_printer);
   1634 
   1635 	if (declarations)
   1636 		osprintf(os, ";");
   1637 	osprintf(os, "\n");
   1638 }
   1639 
   1640 /* Generate the list of argument types for a callback function of
   1641  * type "type".  If "cpp" is set, then generate the C++ type list, otherwise
   1642  * the C type list.
   1643  *
   1644  * Use the appropriate type printer.
   1645  * For the plain C++ interface, the argument position is irrelevant,
   1646  * so simply pass in -1.
   1647  */
   1648 string plain_cpp_generator::generate_callback_args(QualType type, bool cpp)
   1649 {
   1650 	return type_printer()->generate_callback_args(-1, type, cpp);
   1651 }
   1652 
   1653 /* Generate the full cpp type of a callback function of type "type".
   1654  *
   1655  * Use the appropriate type printer.
   1656  * For the plain C++ interface, the argument position is irrelevant,
   1657  * so simply pass in -1.
   1658  */
   1659 string plain_cpp_generator::generate_callback_type(QualType type)
   1660 {
   1661 	return type_printer()->generate_callback_type(-1, type);
   1662 }
   1663 
   1664 /* Print the call to the C++ callback function "call",
   1665  * with the given indentation, wrapped
   1666  * for use inside the lambda function that is used as the C callback function,
   1667  * in the case where checked C++ bindings are being generated.
   1668  *
   1669  * In particular, print
   1670  *
   1671  *        auto ret = @call@;
   1672  *        return ret.release();
   1673  */
   1674 void plain_cpp_generator::impl_printer::print_wrapped_call_checked(int indent,
   1675 	const string &call)
   1676 {
   1677 	osprintf(os, indent, "auto ret = %s;\n", call.c_str());
   1678 	osprintf(os, indent, "return ret.release();\n");
   1679 }
   1680 
   1681 /* Print the call to the C++ callback function "call",
   1682  * with the given indentation and with return type "rtype", wrapped
   1683  * for use inside the lambda function that is used as the C callback function.
   1684  *
   1685  * In particular, print
   1686  *
   1687  *        ISL_CPP_TRY {
   1688  *          @call@;
   1689  *          return isl_stat_ok;
   1690  *        } ISL_CPP_CATCH_ALL {
   1691  *          data->eptr = std::current_exception();
   1692  *          return isl_stat_error;
   1693  *        }
   1694  * or
   1695  *        ISL_CPP_TRY {
   1696  *          auto ret = @call@;
   1697  *          return ret ? isl_bool_true : isl_bool_false;
   1698  *        } ISL_CPP_CATCH_ALL {
   1699  *          data->eptr = std::current_exception();
   1700  *          return isl_bool_error;
   1701  *        }
   1702  * or
   1703  *        ISL_CPP_TRY {
   1704  *          auto ret = @call@;
   1705  *          return ret.release();
   1706  *        } ISL_CPP_CATCH_ALL {
   1707  *          data->eptr = std::current_exception();
   1708  *          return NULL;
   1709  *        }
   1710  *
   1711  * depending on the return type.
   1712  *
   1713  * where ISL_CPP_TRY is defined to "try" and ISL_CPP_CATCH_ALL to "catch (...)"
   1714  * (if exceptions are available).
   1715  *
   1716  * If checked C++ bindings are being generated, then
   1717  * the call is wrapped differently.
   1718  */
   1719 void plain_cpp_generator::impl_printer::print_wrapped_call(int indent,
   1720 	const string &call, QualType rtype)
   1721 {
   1722 	if (generator.checked)
   1723 		return print_wrapped_call_checked(indent, call);
   1724 
   1725 	osprintf(os, indent, "ISL_CPP_TRY {\n");
   1726 	if (is_isl_stat(rtype))
   1727 		osprintf(os, indent, "  %s;\n", call.c_str());
   1728 	else
   1729 		osprintf(os, indent, "  auto ret = %s;\n", call.c_str());
   1730 	if (is_isl_stat(rtype))
   1731 		osprintf(os, indent, "  return isl_stat_ok;\n");
   1732 	else if (is_isl_bool(rtype))
   1733 		osprintf(os, indent,
   1734 			"  return ret ? isl_bool_true : isl_bool_false;\n");
   1735 	else
   1736 		osprintf(os, indent, "  return ret.release();\n");
   1737 	osprintf(os, indent, "} ISL_CPP_CATCH_ALL {\n");
   1738 	osprintf(os, indent, "  data->eptr = std::current_exception();\n");
   1739 	if (is_isl_stat(rtype))
   1740 		osprintf(os, indent, "  return isl_stat_error;\n");
   1741 	else if (is_isl_bool(rtype))
   1742 		osprintf(os, indent, "  return isl_bool_error;\n");
   1743 	else
   1744 		osprintf(os, indent, "  return NULL;\n");
   1745 	osprintf(os, indent, "}\n");
   1746 }
   1747 
   1748 /* Print the declaration for a "prefix"_data data structure
   1749  * that can be used for passing to a C callback function
   1750  * containing a copy of the C++ callback function "param",
   1751  * along with an std::exception_ptr that is used to store any
   1752  * exceptions thrown in the C++ callback.
   1753  *
   1754  * If the C callback is of the form
   1755  *
   1756  *      isl_stat (*fn)(__isl_take isl_map *map, void *user)
   1757  *
   1758  * then the following declaration is printed:
   1759  *
   1760  *      struct <prefix>_data {
   1761  *        std::function<stat(map)> func;
   1762  *        std::exception_ptr eptr;
   1763  *      }
   1764  *
   1765  * (without a newline or a semicolon).
   1766  *
   1767  * The std::exception_ptr object is not added to "prefix"_data
   1768  * if checked C++ bindings are being generated.
   1769  */
   1770 void plain_cpp_generator::plain_printer::print_callback_data_decl(
   1771 	ParmVarDecl *param,
   1772 	const string &prefix)
   1773 {
   1774 	string cpp_args;
   1775 
   1776 	cpp_args = generator.generate_callback_type(param->getType());
   1777 
   1778 	osprintf(os, "  struct %s_data {\n", prefix.c_str());
   1779 	osprintf(os, "    %s func;\n", cpp_args.c_str());
   1780 	if (!generator.checked)
   1781 		osprintf(os, "    std::exception_ptr eptr;\n");
   1782 	osprintf(os, "  }");
   1783 }
   1784 
   1785 /* Given a group of methods with the same name,
   1786  * should extra methods be added that take as arguments
   1787  * those types that can be converted to the original argument type
   1788  * through a unary constructor?
   1789  *
   1790  * Note that even if this method returns true,
   1791  * the extra methods are only printed by the caller
   1792  * if exactly one of the methods in the group was originally defined
   1793  * in the printed class.
   1794  * Signal that they should be printed if the group contains
   1795  * both methods originally defined in the printed class and
   1796  * methods that have been copied from an ancestor
   1797  * by checking whether there are at least two methods in the group.
   1798  */
   1799 bool plain_cpp_generator::plain_printer::want_descendent_overloads(
   1800 	const function_set &methods)
   1801 {
   1802 	return methods.size() > 1;
   1803 }
   1804 
   1805 /* Print the header of the constructor for the "id" class
   1806  * that takes a user object.
   1807  *
   1808  * The user object is taken as a std::any.
   1809  */
   1810 void plain_cpp_generator::plain_printer::print_id_constructor_user_header()
   1811 {
   1812 	if (declarations)
   1813 		os << "  inline explicit ";
   1814 	else
   1815 		os << "id::";
   1816 	os << "id(" << generator.isl_namespace() << "ctx ctx, "
   1817 	   << "const std::string &str, const std::any &any)";
   1818 	if (declarations)
   1819 		os << ";";
   1820 	os << "\n";
   1821 }
   1822 
   1823 /* Print the header of the "id" method
   1824  * for retrieving the user object associated to the identifier.
   1825  * If "optional" is set, the method returns a std::optional user object.
   1826  * The returned object is of a type specified by template parameter T.
   1827  */
   1828 void plain_cpp_generator::plain_printer::print_id_user_header(bool optional)
   1829 {
   1830 	auto indent = declarations ? "  " : "";
   1831 	os << indent << "template <class T>\n";
   1832 	os << indent << (optional ? "std::optional<T> " : "T ");
   1833 	if (!declarations)
   1834 		os << "id::";
   1835 	os << (optional ? "try_" : "");
   1836 	os << "user() const";
   1837 	if (declarations)
   1838 		os << ";";
   1839 	os << "\n";
   1840 }
   1841 
   1842 /* Perform printing by "fn" in a context that only gets compiled
   1843  * by C++17 compilers.
   1844  */
   1845 static void on_cplusplus17(ostream &os, const std::function<void(void)> &fn)
   1846 {
   1847 	os << "#if __cplusplus >= 201703L\n";
   1848 	fn();
   1849 	os << "#endif\n";
   1850 }
   1851 
   1852 /* Print declarations or definitions of the special methods of the "id" class
   1853  * that are not automatically derived from the C interface.
   1854  *
   1855  * In particular, print a constructor that takes a user pointer
   1856  * as well as methods for retrieving this user pointer.
   1857  *
   1858  * These methods require C++17 features.
   1859  */
   1860 void plain_cpp_generator::plain_printer::print_special_id()
   1861 {
   1862 	os << "\n";
   1863 	on_cplusplus17(os, [this] () {
   1864 		print_id_constructor_user();
   1865 		print_id_user(true);
   1866 		print_id_user(false);
   1867 	});
   1868 }
   1869 
   1870 /* Print declarations or definitions of any special methods of this class
   1871  * not automatically derived from the C interface.
   1872  *
   1873  * In particular, print special methods for the "id" class.
   1874  */
   1875 void plain_cpp_generator::plain_printer::print_special()
   1876 {
   1877 	if (clazz.name == "isl_id")
   1878 		print_special_id();
   1879 }
   1880 
   1881 /* Print declarations or definitions of the public methods.
   1882  */
   1883 void plain_cpp_generator::plain_printer::print_public_methods()
   1884 {
   1885 	print_public_constructors();
   1886 	print_constructors();
   1887 	print_copy_assignment();
   1888 	print_destructor();
   1889 	print_ptr();
   1890 	print_downcast();
   1891 	print_ctx();
   1892 	print_method_separator();
   1893 	print_persistent_callbacks();
   1894 	print_methods();
   1895 	print_set_enums();
   1896 	print_special();
   1897 }
   1898 
   1899 /* Print the body of C function callback with the given indentation
   1900  * that can be use as an argument to "param" for marshalling
   1901  * the corresponding C++ callback.
   1902  * The data structure that contains the C++ callback is of type
   1903  * "prefix"_data.
   1904  *
   1905  * For a callback of the form
   1906  *
   1907  *      isl_stat (*fn)(__isl_take isl_map *map, void *user)
   1908  *
   1909  * the following code is generated:
   1910  *
   1911  *        auto *data = static_cast<struct <prefix>_data *>(arg_1);
   1912  *        ISL_CPP_TRY {
   1913  *          stat ret = (data->func)(manage(arg_0));
   1914  *          return isl_stat_ok;
   1915  *        } ISL_CPP_CATCH_ALL {
   1916  *          data->eptr = std::current_exception();
   1917  *          return isl_stat_error;
   1918  *        }
   1919  *
   1920  * If checked C++ bindings are being generated, then
   1921  * generate the following code:
   1922  *
   1923  *        auto *data = static_cast<struct <prefix>_data *>(arg_1);
   1924  *        stat ret = (data->func)(manage(arg_0));
   1925  *        return isl_stat(ret);
   1926  */
   1927 void plain_cpp_generator::impl_printer::print_callback_body(int indent,
   1928 	ParmVarDecl *param, const string &prefix)
   1929 {
   1930 	QualType ptype, rtype;
   1931 	string call, last_idx;
   1932 	const FunctionProtoType *callback;
   1933 	int num_params;
   1934 
   1935 	ptype = param->getType();
   1936 
   1937 	callback = extract_prototype(ptype);
   1938 	rtype = callback->getReturnType();
   1939 	num_params = callback->getNumArgs();
   1940 
   1941 	last_idx = ::to_string(num_params - 1);
   1942 
   1943 	call = "(data->func)(";
   1944 	for (long i = 0; i < num_params - 1; i++) {
   1945 		if (!generator.callback_takes_argument(param, i))
   1946 			call += "manage_copy";
   1947 		else
   1948 			call += "manage";
   1949 		call += "(arg_" + ::to_string(i) + ")";
   1950 		if (i != num_params - 2)
   1951 			call += ", ";
   1952 	}
   1953 	call += ")";
   1954 
   1955 	osprintf(os, indent,
   1956 		 "auto *data = static_cast<struct %s_data *>(arg_%s);\n",
   1957 		 prefix.c_str(), last_idx.c_str());
   1958 	print_wrapped_call(indent, call, rtype);
   1959 }
   1960 
   1961 /* Print the local variables that are needed for a callback argument,
   1962  * in particular, print a lambda function that wraps the callback and
   1963  * a pointer to the actual C++ callback function.
   1964  *
   1965  * For a callback of the form
   1966  *
   1967  *      isl_stat (*fn)(__isl_take isl_map *map, void *user)
   1968  *
   1969  * the following lambda function is generated:
   1970  *
   1971  *      auto fn_lambda = [](isl_map *arg_0, void *arg_1) -> isl_stat {
   1972  *        auto *data = static_cast<struct fn_data *>(arg_1);
   1973  *        try {
   1974  *          stat ret = (data->func)(manage(arg_0));
   1975  *          return isl_stat_ok;
   1976  *        } catch (...) {
   1977  *          data->eptr = std::current_exception();
   1978  *          return isl_stat_error;
   1979  *        }
   1980  *      };
   1981  *
   1982  * A copy of the std::function C++ callback function is stored in
   1983  * a fn_data data structure for passing to the C callback function,
   1984  * along with an std::exception_ptr that is used to store any
   1985  * exceptions thrown in the C++ callback.
   1986  *
   1987  *      struct fn_data {
   1988  *        std::function<stat(map)> func;
   1989  *        std::exception_ptr eptr;
   1990  *      } fn_data = { fn };
   1991  *
   1992  * This std::function object represents the actual user
   1993  * callback function together with the locally captured state at the caller.
   1994  *
   1995  * The lambda function is expected to be used as a C callback function
   1996  * where the lambda itself is provided as the function pointer and
   1997  * where the user void pointer is a pointer to fn_data.
   1998  * The std::function object is extracted from the pointer to fn_data
   1999  * inside the lambda function.
   2000  *
   2001  * The std::exception_ptr object is not added to fn_data
   2002  * if checked C++ bindings are being generated.
   2003  * The body of the generated lambda function then is as follows:
   2004  *
   2005  *        stat ret = (data->func)(manage(arg_0));
   2006  *        return isl_stat(ret);
   2007  *
   2008  * If the C callback does not take its arguments, then
   2009  * manage_copy is used instead of manage.
   2010  */
   2011 void plain_cpp_generator::impl_printer::print_callback_local(ParmVarDecl *param)
   2012 {
   2013 	string pname;
   2014 	QualType ptype, rtype;
   2015 	string c_args, cpp_args, rettype;
   2016 	const FunctionProtoType *callback;
   2017 
   2018 	pname = param->getName().str();
   2019 	ptype = param->getType();
   2020 
   2021 	c_args = generator.generate_callback_args(ptype, false);
   2022 
   2023 	callback = extract_prototype(ptype);
   2024 	rtype = callback->getReturnType();
   2025 	rettype = rtype.getAsString();
   2026 
   2027 	print_callback_data_decl(param, pname);
   2028 	osprintf(os, " %s_data = { %s };\n", pname.c_str(), pname.c_str());
   2029 	osprintf(os, "  auto %s_lambda = [](%s) -> %s {\n",
   2030 		 pname.c_str(), c_args.c_str(), rettype.c_str());
   2031 	print_callback_body(4, param, pname);
   2032 	osprintf(os, "  };\n");
   2033 }
   2034 
   2035 /* Return the C++ counterpart to the isl_bool type.
   2036  *
   2037  * For the checked C++ bindings this is "boolean".
   2038  */
   2039 std::string checked_cpp_type_printer::isl_bool() const
   2040 {
   2041 	return "boolean";
   2042 }
   2043 
   2044 /* Return the C++ counterpart to the isl_bool type.
   2045  *
   2046  * Use the appropriate type printer.
   2047  */
   2048 string plain_cpp_generator::isl_bool2cpp()
   2049 {
   2050 	return type_printer()->isl_bool();
   2051 }
   2052 
   2053 /* Return the C++ counterpart to the isl_stat type.
   2054  *
   2055  * For the checked C++ bindings this is "stat".
   2056  */
   2057 string checked_cpp_type_printer::isl_stat() const
   2058 {
   2059 	return "stat";
   2060 }
   2061 
   2062 /* Return the C++ counterpart to the isl_size type.
   2063  *
   2064  * For the checked C++ bindings this is "class size".
   2065  */
   2066 string checked_cpp_type_printer::isl_size() const
   2067 {
   2068 	return "class size";
   2069 }
   2070 
   2071 /* Return the namespace of the generated C++ bindings.
   2072  *
   2073  * For the checked C++ bindings this is "isl::checked::".
   2074  */
   2075 std::string checked_cpp_type_printer::isl_namespace() const
   2076 {
   2077 	return "isl::checked::";
   2078 }
   2079 
   2080 /* Return the namespace of the generated C++ bindings.
   2081  *
   2082  * Use the appropriate type printer.
   2083  */
   2084 string plain_cpp_generator::isl_namespace()
   2085 {
   2086 	return type_printer()->isl_namespace();
   2087 }
   2088 
   2089 /* Translate parameter or return type "type" to its C++ name counterpart.
   2090  *
   2091  * Use the appropriate type printer.
   2092  * For the plain C++ interface, the argument position is irrelevant,
   2093  * so simply pass in -1.
   2094  */
   2095 string plain_cpp_generator::param2cpp(QualType type)
   2096 {
   2097 	return type_printer()->param(-1, type);
   2098 }
   2099