1d169d70bSTobias Grosser /* 2d169d70bSTobias Grosser * Copyright 2016, 2017 Tobias Grosser. All rights reserved. 3d169d70bSTobias Grosser * 4d169d70bSTobias Grosser * Redistribution and use in source and binary forms, with or without 5d169d70bSTobias Grosser * modification, are permitted provided that the following conditions 6d169d70bSTobias Grosser * are met: 7d169d70bSTobias Grosser * 8d169d70bSTobias Grosser * 1. Redistributions of source code must retain the above copyright 9d169d70bSTobias Grosser * notice, this list of conditions and the following disclaimer. 10d169d70bSTobias Grosser * 11d169d70bSTobias Grosser * 2. Redistributions in binary form must reproduce the above 12d169d70bSTobias Grosser * copyright notice, this list of conditions and the following 13d169d70bSTobias Grosser * disclaimer in the documentation and/or other materials provided 14d169d70bSTobias Grosser * with the distribution. 15d169d70bSTobias Grosser * 16d169d70bSTobias Grosser * THIS SOFTWARE IS PROVIDED BY TOBIAS GROSSER ''AS IS'' AND ANY 17d169d70bSTobias Grosser * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18d169d70bSTobias Grosser * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 19d169d70bSTobias Grosser * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SVEN VERDOOLAEGE OR 20d169d70bSTobias Grosser * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 21d169d70bSTobias Grosser * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 22d169d70bSTobias Grosser * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, 23d169d70bSTobias Grosser * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24d169d70bSTobias Grosser * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25d169d70bSTobias Grosser * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 26d169d70bSTobias Grosser * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27d169d70bSTobias Grosser * 28d169d70bSTobias Grosser * The views and conclusions contained in the software and documentation 29d169d70bSTobias Grosser * are those of the authors and should not be interpreted as 30d169d70bSTobias Grosser * representing official policies, either expressed or implied, of 31d169d70bSTobias Grosser * Tobias Grosser. 32d169d70bSTobias Grosser */ 33d169d70bSTobias Grosser 34d169d70bSTobias Grosser #include <cstdarg> 35d169d70bSTobias Grosser #include <cstdio> 36d169d70bSTobias Grosser #include <iostream> 37d169d70bSTobias Grosser #include <map> 38d169d70bSTobias Grosser #include <sstream> 39d169d70bSTobias Grosser #include <string> 40d169d70bSTobias Grosser #include <vector> 41d169d70bSTobias Grosser 42d169d70bSTobias Grosser #include "cpp.h" 43d169d70bSTobias Grosser #include "isl_config.h" 44d169d70bSTobias Grosser 45d169d70bSTobias Grosser /* Print string formatted according to "fmt" to ostream "os". 46d169d70bSTobias Grosser * 47d169d70bSTobias Grosser * This osprintf method allows us to use printf style formatting constructs when 48d169d70bSTobias Grosser * writing to an ostream. 49d169d70bSTobias Grosser */ 50*e8227804SMichael Kruse static void osprintf(ostream &os, const char *format, va_list arguments) 51d169d70bSTobias Grosser { 52*e8227804SMichael Kruse va_list copy; 53d169d70bSTobias Grosser char *string_pointer; 54d169d70bSTobias Grosser size_t size; 55d169d70bSTobias Grosser 56*e8227804SMichael Kruse va_copy(copy, arguments); 57*e8227804SMichael Kruse size = vsnprintf(NULL, 0, format, copy); 58d169d70bSTobias Grosser string_pointer = new char[size + 1]; 59*e8227804SMichael Kruse va_end(copy); 60d169d70bSTobias Grosser vsnprintf(string_pointer, size + 1, format, arguments); 61d169d70bSTobias Grosser os << string_pointer; 62d169d70bSTobias Grosser delete[] string_pointer; 63d169d70bSTobias Grosser } 64d169d70bSTobias Grosser 65*e8227804SMichael Kruse /* Print string formatted according to "fmt" to ostream "os". 66*e8227804SMichael Kruse * 67*e8227804SMichael Kruse * This osprintf method allows us to use printf style formatting constructs when 68*e8227804SMichael Kruse * writing to an ostream. 69*e8227804SMichael Kruse */ 70*e8227804SMichael Kruse static void osprintf(ostream &os, const char *format, ...) 71*e8227804SMichael Kruse { 72*e8227804SMichael Kruse va_list arguments; 73*e8227804SMichael Kruse 74*e8227804SMichael Kruse va_start(arguments, format); 75*e8227804SMichael Kruse osprintf(os, format, arguments); 76*e8227804SMichael Kruse va_end(arguments); 77*e8227804SMichael Kruse } 78*e8227804SMichael Kruse 79*e8227804SMichael Kruse /* Print string formatted according to "fmt" to ostream "os" 80*e8227804SMichael Kruse * with the given indentation. 81*e8227804SMichael Kruse * 82*e8227804SMichael Kruse * This osprintf method allows us to use printf style formatting constructs when 83*e8227804SMichael Kruse * writing to an ostream. 84*e8227804SMichael Kruse */ 85*e8227804SMichael Kruse static void osprintf(ostream &os, int indent, const char *format, ...) 86*e8227804SMichael Kruse { 87*e8227804SMichael Kruse va_list arguments; 88*e8227804SMichael Kruse 89*e8227804SMichael Kruse osprintf(os, "%*s", indent, " "); 90*e8227804SMichael Kruse va_start(arguments, format); 91*e8227804SMichael Kruse osprintf(os, format, arguments); 92*e8227804SMichael Kruse va_end(arguments); 93*e8227804SMichael Kruse } 94*e8227804SMichael Kruse 95d169d70bSTobias Grosser /* Convert "l" to a string. 96d169d70bSTobias Grosser */ 97d169d70bSTobias Grosser static std::string to_string(long l) 98d169d70bSTobias Grosser { 99d169d70bSTobias Grosser std::ostringstream strm; 100d169d70bSTobias Grosser strm << l; 101d169d70bSTobias Grosser return strm.str(); 102d169d70bSTobias Grosser } 103d169d70bSTobias Grosser 104d169d70bSTobias Grosser /* Generate a cpp interface based on the extracted types and functions. 105d169d70bSTobias Grosser * 106d169d70bSTobias Grosser * Print first a set of forward declarations for all isl wrapper 107d169d70bSTobias Grosser * classes, then the declarations of the classes, and at the end all 108d169d70bSTobias Grosser * implementations. 109d169d70bSTobias Grosser * 110d169d70bSTobias Grosser * If checked C++ bindings are being generated, 111d169d70bSTobias Grosser * then wrap them in a namespace to avoid conflicts 112d169d70bSTobias Grosser * with the default C++ bindings (with automatic checks using exceptions). 113d169d70bSTobias Grosser */ 114d169d70bSTobias Grosser void cpp_generator::generate() 115d169d70bSTobias Grosser { 116d169d70bSTobias Grosser ostream &os = cout; 117d169d70bSTobias Grosser 118d169d70bSTobias Grosser osprintf(os, "\n"); 119d169d70bSTobias Grosser osprintf(os, "namespace isl {\n\n"); 120d169d70bSTobias Grosser if (checked) 121d169d70bSTobias Grosser osprintf(os, "namespace checked {\n\n"); 122d169d70bSTobias Grosser 123d169d70bSTobias Grosser print_forward_declarations(os); 124d169d70bSTobias Grosser osprintf(os, "\n"); 125d169d70bSTobias Grosser print_declarations(os); 126d169d70bSTobias Grosser osprintf(os, "\n"); 127d169d70bSTobias Grosser print_implementations(os); 128d169d70bSTobias Grosser 129d169d70bSTobias Grosser if (checked) 130d169d70bSTobias Grosser osprintf(os, "} // namespace checked\n"); 131d169d70bSTobias Grosser osprintf(os, "} // namespace isl\n"); 132d169d70bSTobias Grosser } 133d169d70bSTobias Grosser 134d169d70bSTobias Grosser /* Print forward declarations for all classes to "os". 135d169d70bSTobias Grosser */ 136d169d70bSTobias Grosser void cpp_generator::print_forward_declarations(ostream &os) 137d169d70bSTobias Grosser { 138d169d70bSTobias Grosser map<string, isl_class>::iterator ci; 139d169d70bSTobias Grosser 140d169d70bSTobias Grosser osprintf(os, "// forward declarations\n"); 141d169d70bSTobias Grosser 142d169d70bSTobias Grosser for (ci = classes.begin(); ci != classes.end(); ++ci) 143d169d70bSTobias Grosser print_class_forward_decl(os, ci->second); 144d169d70bSTobias Grosser } 145d169d70bSTobias Grosser 146d169d70bSTobias Grosser /* Print all declarations to "os". 147d169d70bSTobias Grosser */ 148d169d70bSTobias Grosser void cpp_generator::print_declarations(ostream &os) 149d169d70bSTobias Grosser { 150d169d70bSTobias Grosser map<string, isl_class>::iterator ci; 151d169d70bSTobias Grosser bool first = true; 152d169d70bSTobias Grosser 153d169d70bSTobias Grosser for (ci = classes.begin(); ci != classes.end(); ++ci) { 154d169d70bSTobias Grosser if (first) 155d169d70bSTobias Grosser first = false; 156d169d70bSTobias Grosser else 157d169d70bSTobias Grosser osprintf(os, "\n"); 158d169d70bSTobias Grosser 159d169d70bSTobias Grosser print_class(os, ci->second); 160d169d70bSTobias Grosser } 161d169d70bSTobias Grosser } 162d169d70bSTobias Grosser 163d169d70bSTobias Grosser /* Print all implementations to "os". 164d169d70bSTobias Grosser */ 165d169d70bSTobias Grosser void cpp_generator::print_implementations(ostream &os) 166d169d70bSTobias Grosser { 167d169d70bSTobias Grosser map<string, isl_class>::iterator ci; 168d169d70bSTobias Grosser bool first = true; 169d169d70bSTobias Grosser 170d169d70bSTobias Grosser for (ci = classes.begin(); ci != classes.end(); ++ci) { 171d169d70bSTobias Grosser if (first) 172d169d70bSTobias Grosser first = false; 173d169d70bSTobias Grosser else 174d169d70bSTobias Grosser osprintf(os, "\n"); 175d169d70bSTobias Grosser 176d169d70bSTobias Grosser print_class_impl(os, ci->second); 177d169d70bSTobias Grosser } 178d169d70bSTobias Grosser } 179d169d70bSTobias Grosser 180*e8227804SMichael Kruse /* If "clazz" is a subclass that is based on a type function, 181*e8227804SMichael Kruse * then introduce a "type" field that holds the value of the type 182*e8227804SMichael Kruse * corresponding to the subclass and make the fields of the class 183*e8227804SMichael Kruse * accessible to the "isa" and "as" methods of the (immediate) superclass. 184*e8227804SMichael Kruse * In particular, "isa" needs access to the type field itself, 185*e8227804SMichael Kruse * while "as" needs access to the private constructor. 186*e8227804SMichael Kruse * In case of the "isa" method, all instances are made friends 187*e8227804SMichael Kruse * to avoid access right confusion. 188*e8227804SMichael Kruse */ 189*e8227804SMichael Kruse void cpp_generator::print_subclass_type(ostream &os, const isl_class &clazz) 190*e8227804SMichael Kruse { 191*e8227804SMichael Kruse std::string cppstring = type2cpp(clazz); 192*e8227804SMichael Kruse std::string super; 193*e8227804SMichael Kruse const char *cppname = cppstring.c_str(); 194*e8227804SMichael Kruse const char *supername; 195*e8227804SMichael Kruse 196*e8227804SMichael Kruse if (!clazz.is_type_subclass()) 197*e8227804SMichael Kruse return; 198*e8227804SMichael Kruse 199*e8227804SMichael Kruse super = type2cpp(clazz.superclass_name); 200*e8227804SMichael Kruse supername = super.c_str(); 201*e8227804SMichael Kruse osprintf(os, " template <class T>\n"); 202*e8227804SMichael Kruse osprintf(os, " friend %s %s::isa() const;\n", 203*e8227804SMichael Kruse isl_bool2cpp().c_str(), supername); 204*e8227804SMichael Kruse osprintf(os, " friend %s %s::as<%s>() const;\n", 205*e8227804SMichael Kruse cppname, supername, cppname); 206*e8227804SMichael Kruse osprintf(os, " static const auto type = %s;\n", 207*e8227804SMichael Kruse clazz.subclass_name.c_str()); 208*e8227804SMichael Kruse } 209*e8227804SMichael Kruse 210d169d70bSTobias Grosser /* Print declarations for class "clazz" to "os". 211*e8227804SMichael Kruse * 212*e8227804SMichael Kruse * If "clazz" is a subclass based on a type function, 213*e8227804SMichael Kruse * then it is made to inherit from the (immediate) superclass and 214*e8227804SMichael Kruse * a "type" attribute is added for use in the "as" and "isa" 215*e8227804SMichael Kruse * methods of the superclass. 216*e8227804SMichael Kruse * 217*e8227804SMichael Kruse * Conversely, if "clazz" is a superclass with a type function, 218*e8227804SMichael Kruse * then declare those "as" and "isa" methods. 219*e8227804SMichael Kruse * 220*e8227804SMichael Kruse * The pointer to the isl object is only added for classes that 221*e8227804SMichael Kruse * are not subclasses, since subclasses refer to the same isl object. 222d169d70bSTobias Grosser */ 223d169d70bSTobias Grosser void cpp_generator::print_class(ostream &os, const isl_class &clazz) 224d169d70bSTobias Grosser { 225d169d70bSTobias Grosser const char *name = clazz.name.c_str(); 226d169d70bSTobias Grosser std::string cppstring = type2cpp(clazz); 227d169d70bSTobias Grosser const char *cppname = cppstring.c_str(); 228d169d70bSTobias Grosser 229d169d70bSTobias Grosser osprintf(os, "// declarations for isl::%s\n", cppname); 230d169d70bSTobias Grosser 231d169d70bSTobias Grosser print_class_factory_decl(os, clazz); 232d169d70bSTobias Grosser osprintf(os, "\n"); 233*e8227804SMichael Kruse osprintf(os, "class %s ", cppname); 234*e8227804SMichael Kruse if (clazz.is_type_subclass()) 235*e8227804SMichael Kruse osprintf(os, ": public %s ", 236*e8227804SMichael Kruse type2cpp(clazz.superclass_name).c_str()); 237*e8227804SMichael Kruse osprintf(os, "{\n"); 238*e8227804SMichael Kruse print_subclass_type(os, clazz); 239d169d70bSTobias Grosser print_class_factory_decl(os, clazz, " friend "); 240d169d70bSTobias Grosser osprintf(os, "\n"); 241*e8227804SMichael Kruse osprintf(os, "protected:\n"); 242*e8227804SMichael Kruse if (!clazz.is_type_subclass()) { 243d169d70bSTobias Grosser osprintf(os, " %s *ptr = nullptr;\n", name); 244d169d70bSTobias Grosser osprintf(os, "\n"); 245*e8227804SMichael Kruse } 246*e8227804SMichael Kruse print_protected_constructors_decl(os, clazz); 247d169d70bSTobias Grosser osprintf(os, "\n"); 248d169d70bSTobias Grosser osprintf(os, "public:\n"); 249d169d70bSTobias Grosser print_public_constructors_decl(os, clazz); 250d169d70bSTobias Grosser print_constructors_decl(os, clazz); 251d169d70bSTobias Grosser print_copy_assignment_decl(os, clazz); 252d169d70bSTobias Grosser print_destructor_decl(os, clazz); 253d169d70bSTobias Grosser print_ptr_decl(os, clazz); 254*e8227804SMichael Kruse print_downcast_decl(os, clazz); 255*e8227804SMichael Kruse print_ctx_decl(os); 256d169d70bSTobias Grosser osprintf(os, "\n"); 257*e8227804SMichael Kruse print_persistent_callbacks_decl(os, clazz); 258d169d70bSTobias Grosser print_methods_decl(os, clazz); 259*e8227804SMichael Kruse print_set_enums_decl(os, clazz); 260d169d70bSTobias Grosser 261d169d70bSTobias Grosser osprintf(os, "};\n"); 262d169d70bSTobias Grosser } 263d169d70bSTobias Grosser 264d169d70bSTobias Grosser /* Print forward declaration of class "clazz" to "os". 265d169d70bSTobias Grosser */ 266d169d70bSTobias Grosser void cpp_generator::print_class_forward_decl(ostream &os, 267d169d70bSTobias Grosser const isl_class &clazz) 268d169d70bSTobias Grosser { 269d169d70bSTobias Grosser std::string cppstring = type2cpp(clazz); 270d169d70bSTobias Grosser const char *cppname = cppstring.c_str(); 271d169d70bSTobias Grosser 272d169d70bSTobias Grosser osprintf(os, "class %s;\n", cppname); 273d169d70bSTobias Grosser } 274d169d70bSTobias Grosser 275d169d70bSTobias Grosser /* Print global factory functions to "os". 276d169d70bSTobias Grosser * 277d169d70bSTobias Grosser * Each class has two global factory functions: 278d169d70bSTobias Grosser * 279d169d70bSTobias Grosser * set manage(__isl_take isl_set *ptr); 280d169d70bSTobias Grosser * set manage_copy(__isl_keep isl_set *ptr); 281d169d70bSTobias Grosser * 282d169d70bSTobias Grosser * A user can construct isl C++ objects from a raw pointer and indicate whether 283d169d70bSTobias Grosser * they intend to take the ownership of the object or not through these global 284d169d70bSTobias Grosser * factory functions. This ensures isl object creation is very explicit and 285d169d70bSTobias Grosser * pointers are not converted by accident. Thanks to overloading, manage() and 286d169d70bSTobias Grosser * manage_copy() can be called on any isl raw pointer and the corresponding 287d169d70bSTobias Grosser * object is automatically created, without the user having to choose the right 288d169d70bSTobias Grosser * isl object type. 289*e8227804SMichael Kruse * 290*e8227804SMichael Kruse * For a subclass based on a type function, no factory functions 291*e8227804SMichael Kruse * are introduced because they share the C object type with 292*e8227804SMichael Kruse * the superclass. 293d169d70bSTobias Grosser */ 294d169d70bSTobias Grosser void cpp_generator::print_class_factory_decl(ostream &os, 295d169d70bSTobias Grosser const isl_class &clazz, const std::string &prefix) 296d169d70bSTobias Grosser { 297d169d70bSTobias Grosser const char *name = clazz.name.c_str(); 298d169d70bSTobias Grosser std::string cppstring = type2cpp(clazz); 299d169d70bSTobias Grosser const char *cppname = cppstring.c_str(); 300d169d70bSTobias Grosser 301*e8227804SMichael Kruse if (clazz.is_type_subclass()) 302*e8227804SMichael Kruse return; 303*e8227804SMichael Kruse 304d169d70bSTobias Grosser os << prefix; 305d169d70bSTobias Grosser osprintf(os, "inline %s manage(__isl_take %s *ptr);\n", cppname, name); 306d169d70bSTobias Grosser os << prefix; 307d169d70bSTobias Grosser osprintf(os, "inline %s manage_copy(__isl_keep %s *ptr);\n", 308d169d70bSTobias Grosser cppname, name); 309d169d70bSTobias Grosser } 310d169d70bSTobias Grosser 311*e8227804SMichael Kruse /* Print declarations of protected constructors for class "clazz" to "os". 312d169d70bSTobias Grosser * 313*e8227804SMichael Kruse * Each class has currently one protected constructor: 314d169d70bSTobias Grosser * 315d169d70bSTobias Grosser * 1) Constructor from a plain isl_* C pointer 316d169d70bSTobias Grosser * 317d169d70bSTobias Grosser * Example: 318d169d70bSTobias Grosser * 319d169d70bSTobias Grosser * set(__isl_take isl_set *ptr); 320d169d70bSTobias Grosser * 321*e8227804SMichael Kruse * The raw pointer constructor is kept protected. Object creation is only 322d169d70bSTobias Grosser * possible through manage() or manage_copy(). 323d169d70bSTobias Grosser */ 324*e8227804SMichael Kruse void cpp_generator::print_protected_constructors_decl(ostream &os, 325d169d70bSTobias Grosser const isl_class &clazz) 326d169d70bSTobias Grosser { 327d169d70bSTobias Grosser const char *name = clazz.name.c_str(); 328d169d70bSTobias Grosser std::string cppstring = type2cpp(clazz); 329d169d70bSTobias Grosser const char *cppname = cppstring.c_str(); 330d169d70bSTobias Grosser 331d169d70bSTobias Grosser osprintf(os, " inline explicit %s(__isl_take %s *ptr);\n", cppname, 332d169d70bSTobias Grosser name); 333d169d70bSTobias Grosser } 334d169d70bSTobias Grosser 335d169d70bSTobias Grosser /* Print declarations of public constructors for class "clazz" to "os". 336d169d70bSTobias Grosser * 337d169d70bSTobias Grosser * Each class currently has two public constructors: 338d169d70bSTobias Grosser * 339d169d70bSTobias Grosser * 1) A default constructor 340d169d70bSTobias Grosser * 2) A copy constructor 341d169d70bSTobias Grosser * 342d169d70bSTobias Grosser * Example: 343d169d70bSTobias Grosser * 344d169d70bSTobias Grosser * set(); 345d169d70bSTobias Grosser * set(const set &set); 346d169d70bSTobias Grosser */ 347d169d70bSTobias Grosser void cpp_generator::print_public_constructors_decl(ostream &os, 348d169d70bSTobias Grosser const isl_class &clazz) 349d169d70bSTobias Grosser { 350d169d70bSTobias Grosser std::string cppstring = type2cpp(clazz); 351d169d70bSTobias Grosser const char *cppname = cppstring.c_str(); 352d169d70bSTobias Grosser osprintf(os, " inline /* implicit */ %s();\n", cppname); 353d169d70bSTobias Grosser 354d169d70bSTobias Grosser osprintf(os, " inline /* implicit */ %s(const %s &obj);\n", 355d169d70bSTobias Grosser cppname, cppname); 356d169d70bSTobias Grosser } 357d169d70bSTobias Grosser 358*e8227804SMichael Kruse /* Print declarations for "method" in class "clazz" to "os". 359*e8227804SMichael Kruse * 360*e8227804SMichael Kruse * "kind" specifies the kind of method that should be generated. 361*e8227804SMichael Kruse * 362*e8227804SMichael Kruse * "convert" specifies which of the method arguments should 363*e8227804SMichael Kruse * be automatically converted. 364*e8227804SMichael Kruse */ 365*e8227804SMichael Kruse template <> 366*e8227804SMichael Kruse void cpp_generator::print_method<cpp_generator::decl>(ostream &os, 367*e8227804SMichael Kruse const isl_class &clazz, FunctionDecl *method, function_kind kind, 368*e8227804SMichael Kruse const std::vector<bool> &convert) 369*e8227804SMichael Kruse { 370*e8227804SMichael Kruse string name = clazz.method_name(method); 371*e8227804SMichael Kruse 372*e8227804SMichael Kruse print_named_method_decl(os, clazz, method, name, kind, convert); 373*e8227804SMichael Kruse } 374*e8227804SMichael Kruse 375*e8227804SMichael Kruse /* Print declarations for "method" in class "clazz" to "os", 376*e8227804SMichael Kruse * without any argument conversions. 377*e8227804SMichael Kruse * 378*e8227804SMichael Kruse * "kind" specifies the kind of method that should be generated. 379*e8227804SMichael Kruse */ 380*e8227804SMichael Kruse template <> 381*e8227804SMichael Kruse void cpp_generator::print_method<cpp_generator::decl>(ostream &os, 382*e8227804SMichael Kruse const isl_class &clazz, FunctionDecl *method, function_kind kind) 383*e8227804SMichael Kruse { 384*e8227804SMichael Kruse print_method<decl>(os, clazz,method, kind, {}); 385*e8227804SMichael Kruse } 386*e8227804SMichael Kruse 387d169d70bSTobias Grosser /* Print declarations for constructors for class "class" to "os". 388d169d70bSTobias Grosser * 389d169d70bSTobias Grosser * For each isl function that is marked as __isl_constructor, 390d169d70bSTobias Grosser * add a corresponding C++ constructor. 391d169d70bSTobias Grosser * 392d169d70bSTobias Grosser * Example: 393d169d70bSTobias Grosser * 394d169d70bSTobias Grosser * inline /\* implicit *\/ union_set(basic_set bset); 395d169d70bSTobias Grosser * inline /\* implicit *\/ union_set(set set); 396d169d70bSTobias Grosser * inline explicit val(ctx ctx, long i); 397d169d70bSTobias Grosser * inline explicit val(ctx ctx, const std::string &str); 398d169d70bSTobias Grosser */ 399d169d70bSTobias Grosser void cpp_generator::print_constructors_decl(ostream &os, 400d169d70bSTobias Grosser const isl_class &clazz) 401d169d70bSTobias Grosser { 402*e8227804SMichael Kruse function_set::const_iterator in; 403*e8227804SMichael Kruse const function_set &constructors = clazz.constructors; 404d169d70bSTobias Grosser 405d169d70bSTobias Grosser for (in = constructors.begin(); in != constructors.end(); ++in) { 406d169d70bSTobias Grosser FunctionDecl *cons = *in; 407d169d70bSTobias Grosser 408*e8227804SMichael Kruse print_method<decl>(os, clazz, cons, function_kind_constructor); 409d169d70bSTobias Grosser } 410d169d70bSTobias Grosser } 411d169d70bSTobias Grosser 412d169d70bSTobias Grosser /* Print declarations of copy assignment operator for class "clazz" 413d169d70bSTobias Grosser * to "os". 414d169d70bSTobias Grosser * 415d169d70bSTobias Grosser * Each class has one assignment operator. 416d169d70bSTobias Grosser * 417d169d70bSTobias Grosser * isl:set &set::operator=(set obj) 418d169d70bSTobias Grosser * 419d169d70bSTobias Grosser */ 420d169d70bSTobias Grosser void cpp_generator::print_copy_assignment_decl(ostream &os, 421d169d70bSTobias Grosser const isl_class &clazz) 422d169d70bSTobias Grosser { 423d169d70bSTobias Grosser std::string cppstring = type2cpp(clazz); 424d169d70bSTobias Grosser const char *cppname = cppstring.c_str(); 425d169d70bSTobias Grosser 426d169d70bSTobias Grosser osprintf(os, " inline %s &operator=(%s obj);\n", cppname, cppname); 427d169d70bSTobias Grosser } 428d169d70bSTobias Grosser 429d169d70bSTobias Grosser /* Print declaration of destructor for class "clazz" to "os". 430*e8227804SMichael Kruse * 431*e8227804SMichael Kruse * No explicit destructor is needed for type based subclasses. 432d169d70bSTobias Grosser */ 433d169d70bSTobias Grosser void cpp_generator::print_destructor_decl(ostream &os, const isl_class &clazz) 434d169d70bSTobias Grosser { 435d169d70bSTobias Grosser std::string cppstring = type2cpp(clazz); 436d169d70bSTobias Grosser const char *cppname = cppstring.c_str(); 437d169d70bSTobias Grosser 438*e8227804SMichael Kruse if (clazz.is_type_subclass()) 439*e8227804SMichael Kruse return; 440*e8227804SMichael Kruse 441d169d70bSTobias Grosser osprintf(os, " inline ~%s();\n", cppname); 442d169d70bSTobias Grosser } 443d169d70bSTobias Grosser 444d169d70bSTobias Grosser /* Print declaration of pointer functions for class "clazz" to "os". 445*e8227804SMichael Kruse * Since type based subclasses share the pointer with their superclass, 446*e8227804SMichael Kruse * they can also reuse these functions from the superclass. 447d169d70bSTobias Grosser * 448d169d70bSTobias Grosser * To obtain a raw pointer three functions are provided: 449d169d70bSTobias Grosser * 450d169d70bSTobias Grosser * 1) __isl_give isl_set *copy() 451d169d70bSTobias Grosser * 452d169d70bSTobias Grosser * Returns a pointer to a _copy_ of the internal object 453d169d70bSTobias Grosser * 454d169d70bSTobias Grosser * 2) __isl_keep isl_set *get() 455d169d70bSTobias Grosser * 456d169d70bSTobias Grosser * Returns a pointer to the internal object 457d169d70bSTobias Grosser * 458d169d70bSTobias Grosser * 3) __isl_give isl_set *release() 459d169d70bSTobias Grosser * 460d169d70bSTobias Grosser * Returns a pointer to the internal object and resets the 461d169d70bSTobias Grosser * internal pointer to nullptr. 462d169d70bSTobias Grosser * 463d169d70bSTobias Grosser * We also provide functionality to explicitly check if a pointer is 464d169d70bSTobias Grosser * currently managed by this object. 465d169d70bSTobias Grosser * 466d169d70bSTobias Grosser * 4) bool is_null() 467d169d70bSTobias Grosser * 468d169d70bSTobias Grosser * Check if the current object is a null pointer. 469d169d70bSTobias Grosser * 470d169d70bSTobias Grosser * The functions get() and release() model the value_ptr proposed in 471d169d70bSTobias Grosser * http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2012/n3339.pdf. 472d169d70bSTobias Grosser * The copy() function is an extension to allow the user to explicitly 473d169d70bSTobias Grosser * copy the underlying object. 474d169d70bSTobias Grosser * 475d169d70bSTobias Grosser * Also generate a declaration to delete copy() for r-values, for 476d169d70bSTobias Grosser * r-values release() should be used to avoid unnecessary copies. 477d169d70bSTobias Grosser */ 478d169d70bSTobias Grosser void cpp_generator::print_ptr_decl(ostream &os, const isl_class &clazz) 479d169d70bSTobias Grosser { 480d169d70bSTobias Grosser const char *name = clazz.name.c_str(); 481d169d70bSTobias Grosser 482*e8227804SMichael Kruse if (clazz.is_type_subclass()) 483*e8227804SMichael Kruse return; 484*e8227804SMichael Kruse 485d169d70bSTobias Grosser osprintf(os, " inline __isl_give %s *copy() const &;\n", name); 486d169d70bSTobias Grosser osprintf(os, " inline __isl_give %s *copy() && = delete;\n", name); 487d169d70bSTobias Grosser osprintf(os, " inline __isl_keep %s *get() const;\n", name); 488d169d70bSTobias Grosser osprintf(os, " inline __isl_give %s *release();\n", name); 489d169d70bSTobias Grosser osprintf(os, " inline bool is_null() const;\n"); 490d169d70bSTobias Grosser } 491d169d70bSTobias Grosser 492*e8227804SMichael Kruse /* Print a template declaration with given indentation 493*e8227804SMichael Kruse * for the "isa_type" method that ensures it is only enabled 494*e8227804SMichael Kruse * when called with a template argument 495*e8227804SMichael Kruse * that represents a type that is equal to that 496*e8227804SMichael Kruse * of the return type of the type function of "super". 497*e8227804SMichael Kruse * In particular, "isa_type" gets called from "isa" 498*e8227804SMichael Kruse * with as template argument the type of the "type" field 499*e8227804SMichael Kruse * of the subclass. 500*e8227804SMichael Kruse * The check ensures that this subclass is in fact a direct subclass 501*e8227804SMichael Kruse * of "super". 502d169d70bSTobias Grosser */ 503*e8227804SMichael Kruse void cpp_generator::print_isa_type_template(ostream &os, int indent, 504*e8227804SMichael Kruse const isl_class &super) 505d169d70bSTobias Grosser { 506*e8227804SMichael Kruse osprintf(os, indent, 507*e8227804SMichael Kruse "template <typename T,\n"); 508*e8227804SMichael Kruse osprintf(os, indent, 509*e8227804SMichael Kruse " typename = typename std::enable_if<std::is_same<\n"); 510*e8227804SMichael Kruse osprintf(os, indent, 511*e8227804SMichael Kruse " const decltype(%s(NULL)),\n", 512*e8227804SMichael Kruse super.fn_type->getNameAsString().c_str()); 513*e8227804SMichael Kruse osprintf(os, indent, 514*e8227804SMichael Kruse " const T>::value>::type>\n"); 515*e8227804SMichael Kruse } 516*e8227804SMichael Kruse 517*e8227804SMichael Kruse /* Print declarations for the "as" and "isa" methods, if "clazz" 518*e8227804SMichael Kruse * is a superclass with a type function. 519*e8227804SMichael Kruse * 520*e8227804SMichael Kruse * "isa" checks whether an object is of a given subclass type. 521*e8227804SMichael Kruse * "isa_type" does the same, but gets passed the value of the type field 522*e8227804SMichael Kruse * of the subclass as a function argument and the type of this field 523*e8227804SMichael Kruse * as a template argument. 524*e8227804SMichael Kruse * "as" tries to cast an object to a given subclass type, returning 525*e8227804SMichael Kruse * an invalid object if the object is not of the given type. 526*e8227804SMichael Kruse */ 527*e8227804SMichael Kruse void cpp_generator::print_downcast_decl(ostream &os, const isl_class &clazz) 528*e8227804SMichael Kruse { 529*e8227804SMichael Kruse if (!clazz.fn_type) 530*e8227804SMichael Kruse return; 531*e8227804SMichael Kruse 532*e8227804SMichael Kruse osprintf(os, "private:\n"); 533*e8227804SMichael Kruse print_isa_type_template(os, 2, clazz); 534*e8227804SMichael Kruse osprintf(os, " inline %s isa_type(T subtype) const;\n", 535*e8227804SMichael Kruse isl_bool2cpp().c_str()); 536*e8227804SMichael Kruse osprintf(os, "public:\n"); 537*e8227804SMichael Kruse osprintf(os, " template <class T> inline %s isa() const;\n", 538*e8227804SMichael Kruse isl_bool2cpp().c_str()); 539*e8227804SMichael Kruse osprintf(os, " template <class T> inline T as() const;\n"); 540*e8227804SMichael Kruse } 541*e8227804SMichael Kruse 542*e8227804SMichael Kruse /* Print the declaration of the ctx method. 543*e8227804SMichael Kruse */ 544*e8227804SMichael Kruse void cpp_generator::print_ctx_decl(ostream &os) 545*e8227804SMichael Kruse { 546*e8227804SMichael Kruse std::string ns = isl_namespace(); 547*e8227804SMichael Kruse 548*e8227804SMichael Kruse osprintf(os, " inline %sctx ctx() const;\n", ns.c_str()); 549*e8227804SMichael Kruse } 550*e8227804SMichael Kruse 551*e8227804SMichael Kruse /* Add a space to the return type "type" if needed, 552*e8227804SMichael Kruse * i.e., if it is not the type of a pointer. 553*e8227804SMichael Kruse */ 554*e8227804SMichael Kruse static string add_space_to_return_type(const string &type) 555*e8227804SMichael Kruse { 556*e8227804SMichael Kruse if (type[type.size() - 1] == '*') 557*e8227804SMichael Kruse return type; 558*e8227804SMichael Kruse return type + " "; 559*e8227804SMichael Kruse } 560*e8227804SMichael Kruse 561*e8227804SMichael Kruse /* Print the prototype of the static inline method that is used 562*e8227804SMichael Kruse * as the C callback of "clazz" set by "method" to "os". 563*e8227804SMichael Kruse */ 564*e8227804SMichael Kruse void cpp_generator::print_persistent_callback_prototype(ostream &os, 565*e8227804SMichael Kruse const isl_class &clazz, FunctionDecl *method, bool is_declaration) 566*e8227804SMichael Kruse { 567*e8227804SMichael Kruse string callback_name, rettype, c_args; 568*e8227804SMichael Kruse ParmVarDecl *param = persistent_callback_arg(method); 569*e8227804SMichael Kruse const FunctionProtoType *callback; 570*e8227804SMichael Kruse QualType ptype; 571*e8227804SMichael Kruse string classname; 572*e8227804SMichael Kruse 573*e8227804SMichael Kruse ptype = param->getType(); 574*e8227804SMichael Kruse callback = extract_prototype(ptype); 575*e8227804SMichael Kruse 576*e8227804SMichael Kruse rettype = callback->getReturnType().getAsString(); 577*e8227804SMichael Kruse rettype = add_space_to_return_type(rettype); 578*e8227804SMichael Kruse callback_name = clazz.persistent_callback_name(method); 579*e8227804SMichael Kruse c_args = generate_callback_args(ptype, false); 580*e8227804SMichael Kruse 581*e8227804SMichael Kruse if (!is_declaration) 582*e8227804SMichael Kruse classname = type2cpp(clazz) + "::"; 583*e8227804SMichael Kruse 584*e8227804SMichael Kruse osprintf(os, "%s%s%s(%s)", 585*e8227804SMichael Kruse rettype.c_str(), classname.c_str(), 586*e8227804SMichael Kruse callback_name.c_str(), c_args.c_str()); 587*e8227804SMichael Kruse } 588*e8227804SMichael Kruse 589*e8227804SMichael Kruse /* Print the prototype of the method for setting the callback function 590*e8227804SMichael Kruse * of "clazz" set by "method" to "os". 591*e8227804SMichael Kruse */ 592*e8227804SMichael Kruse void cpp_generator::print_persistent_callback_setter_prototype(ostream &os, 593*e8227804SMichael Kruse const isl_class &clazz, FunctionDecl *method, bool is_declaration) 594*e8227804SMichael Kruse { 595*e8227804SMichael Kruse string classname, callback_name, cpptype; 596*e8227804SMichael Kruse ParmVarDecl *param = persistent_callback_arg(method); 597*e8227804SMichael Kruse 598*e8227804SMichael Kruse if (!is_declaration) 599*e8227804SMichael Kruse classname = type2cpp(clazz) + "::"; 600*e8227804SMichael Kruse 601*e8227804SMichael Kruse cpptype = type2cpp(param->getOriginalType()); 602*e8227804SMichael Kruse callback_name = clazz.persistent_callback_name(method); 603*e8227804SMichael Kruse osprintf(os, "void %sset_%s_data(const %s &%s)", 604*e8227804SMichael Kruse classname.c_str(), callback_name.c_str(), cpptype.c_str(), 605*e8227804SMichael Kruse param->getName().str().c_str()); 606*e8227804SMichael Kruse } 607*e8227804SMichael Kruse 608*e8227804SMichael Kruse /* Given a function "method" for setting a "clazz" persistent callback, 609*e8227804SMichael Kruse * print the fields that are needed for marshalling the callback to "os". 610*e8227804SMichael Kruse * 611*e8227804SMichael Kruse * In particular, print 612*e8227804SMichael Kruse * - the declaration of a data structure for storing the C++ callback function 613*e8227804SMichael Kruse * - a shared pointer to such a data structure 614*e8227804SMichael Kruse * - the declaration of a static inline method 615*e8227804SMichael Kruse * for use as the C callback function 616*e8227804SMichael Kruse * - the declaration of a private method for setting the callback function 617*e8227804SMichael Kruse */ 618*e8227804SMichael Kruse void cpp_generator::print_persistent_callback_data(ostream &os, 619*e8227804SMichael Kruse const isl_class &clazz, FunctionDecl *method) 620*e8227804SMichael Kruse { 621*e8227804SMichael Kruse string callback_name; 622*e8227804SMichael Kruse ParmVarDecl *param = persistent_callback_arg(method); 623*e8227804SMichael Kruse 624*e8227804SMichael Kruse callback_name = clazz.persistent_callback_name(method); 625*e8227804SMichael Kruse print_callback_data_decl(os, param, callback_name); 626*e8227804SMichael Kruse osprintf(os, ";\n"); 627*e8227804SMichael Kruse osprintf(os, " std::shared_ptr<%s_data> %s_data;\n", 628*e8227804SMichael Kruse callback_name.c_str(), callback_name.c_str()); 629*e8227804SMichael Kruse osprintf(os, " static inline "); 630*e8227804SMichael Kruse print_persistent_callback_prototype(os, clazz, method, true); 631*e8227804SMichael Kruse osprintf(os, ";\n"); 632*e8227804SMichael Kruse osprintf(os, " inline "); 633*e8227804SMichael Kruse print_persistent_callback_setter_prototype(os, clazz, method, true); 634*e8227804SMichael Kruse osprintf(os, ";\n"); 635*e8227804SMichael Kruse } 636*e8227804SMichael Kruse 637*e8227804SMichael Kruse /* Print declarations needed for the persistent callbacks of "clazz". 638*e8227804SMichael Kruse * 639*e8227804SMichael Kruse * In particular, if there are any persistent callbacks, then 640*e8227804SMichael Kruse * print a private method for copying callback data from 641*e8227804SMichael Kruse * one object to another, 642*e8227804SMichael Kruse * private data for keeping track of the persistent callbacks and 643*e8227804SMichael Kruse * public methods for setting the persistent callbacks. 644*e8227804SMichael Kruse */ 645*e8227804SMichael Kruse void cpp_generator::print_persistent_callbacks_decl(ostream &os, 646*e8227804SMichael Kruse const isl_class &clazz) 647*e8227804SMichael Kruse { 648*e8227804SMichael Kruse std::string cppstring = type2cpp(clazz); 649*e8227804SMichael Kruse const char *cppname = cppstring.c_str(); 650*e8227804SMichael Kruse set<FunctionDecl *>::const_iterator in; 651*e8227804SMichael Kruse const set<FunctionDecl *> &callbacks = clazz.persistent_callbacks; 652*e8227804SMichael Kruse 653*e8227804SMichael Kruse if (!clazz.has_persistent_callbacks()) 654*e8227804SMichael Kruse return; 655*e8227804SMichael Kruse 656*e8227804SMichael Kruse osprintf(os, "private:\n"); 657*e8227804SMichael Kruse osprintf(os, " inline %s ©_callbacks(const %s &obj);\n", 658*e8227804SMichael Kruse cppname, cppname); 659*e8227804SMichael Kruse for (in = callbacks.begin(); in != callbacks.end(); ++in) 660*e8227804SMichael Kruse print_persistent_callback_data(os, clazz, *in); 661*e8227804SMichael Kruse 662*e8227804SMichael Kruse osprintf(os, "public:\n"); 663*e8227804SMichael Kruse for (in = callbacks.begin(); in != callbacks.end(); ++in) 664*e8227804SMichael Kruse print_method<decl>(os, clazz, *in, function_kind_member_method); 665d169d70bSTobias Grosser } 666d169d70bSTobias Grosser 667d169d70bSTobias Grosser /* Print declarations for methods in class "clazz" to "os". 668d169d70bSTobias Grosser */ 669d169d70bSTobias Grosser void cpp_generator::print_methods_decl(ostream &os, const isl_class &clazz) 670d169d70bSTobias Grosser { 671*e8227804SMichael Kruse map<string, function_set >::const_iterator it; 672d169d70bSTobias Grosser 673d169d70bSTobias Grosser for (it = clazz.methods.begin(); it != clazz.methods.end(); ++it) 6746145b11cSTobias Grosser print_method_group_decl(os, clazz, it->second); 675d169d70bSTobias Grosser } 676d169d70bSTobias Grosser 677*e8227804SMichael Kruse /* Print a declaration for a method "name" in "clazz" derived 678*e8227804SMichael Kruse * from "fd", which sets an enum, to "os". 679*e8227804SMichael Kruse * 680*e8227804SMichael Kruse * The last argument is removed because it is replaced by 681*e8227804SMichael Kruse * a break-up into several methods. 682*e8227804SMichael Kruse */ 683*e8227804SMichael Kruse void cpp_generator::print_set_enum_decl(ostream &os, const isl_class &clazz, 684*e8227804SMichael Kruse FunctionDecl *fd, const string &name) 685*e8227804SMichael Kruse { 686*e8227804SMichael Kruse int n = fd->getNumParams(); 687*e8227804SMichael Kruse 688*e8227804SMichael Kruse print_method_header(os, clazz, fd, name, n - 1, true, 689*e8227804SMichael Kruse function_kind_member_method); 690*e8227804SMichael Kruse } 691*e8227804SMichael Kruse 692*e8227804SMichael Kruse /* Print declarations for the methods in "clazz" derived from "fd", 693*e8227804SMichael Kruse * which sets an enum, to "os". 694*e8227804SMichael Kruse * 695*e8227804SMichael Kruse * A method is generated for each value in the enum, setting 696*e8227804SMichael Kruse * the enum to that value. 697*e8227804SMichael Kruse */ 698*e8227804SMichael Kruse void cpp_generator::print_set_enums_decl(ostream &os, const isl_class &clazz, 699*e8227804SMichael Kruse FunctionDecl *fd) 700*e8227804SMichael Kruse { 701*e8227804SMichael Kruse vector<set_enum>::const_iterator it; 702*e8227804SMichael Kruse const vector<set_enum> &set_enums = clazz.set_enums.at(fd); 703*e8227804SMichael Kruse 704*e8227804SMichael Kruse for (it = set_enums.begin(); it != set_enums.end(); ++it) 705*e8227804SMichael Kruse print_set_enum_decl(os, clazz, fd, it->method_name); 706*e8227804SMichael Kruse } 707*e8227804SMichael Kruse 708*e8227804SMichael Kruse /* Print declarations for methods in "clazz" derived from functions 709*e8227804SMichael Kruse * that set an enum, to "os". 710*e8227804SMichael Kruse */ 711*e8227804SMichael Kruse void cpp_generator::print_set_enums_decl(ostream &os, const isl_class &clazz) 712*e8227804SMichael Kruse { 713*e8227804SMichael Kruse map<FunctionDecl *, vector<set_enum> >::const_iterator it; 714*e8227804SMichael Kruse 715*e8227804SMichael Kruse for (it = clazz.set_enums.begin(); it != clazz.set_enums.end(); ++it) 716*e8227804SMichael Kruse print_set_enums_decl(os, clazz, it->first); 717*e8227804SMichael Kruse } 718*e8227804SMichael Kruse 719*e8227804SMichael Kruse /* Print a declaration for the "get" method "fd" in class "clazz", 720*e8227804SMichael Kruse * using a name that includes the "get_" prefix, to "os". 721*e8227804SMichael Kruse */ 722*e8227804SMichael Kruse template<> 723*e8227804SMichael Kruse void cpp_generator::print_get_method<cpp_generator::decl>(ostream &os, 724*e8227804SMichael Kruse const isl_class &clazz, FunctionDecl *fd) 725*e8227804SMichael Kruse { 726*e8227804SMichael Kruse function_kind kind = function_kind_member_method; 727*e8227804SMichael Kruse string base = clazz.base_method_name(fd); 728*e8227804SMichael Kruse 729*e8227804SMichael Kruse print_named_method_decl(os, clazz, fd, base, kind); 730*e8227804SMichael Kruse } 731*e8227804SMichael Kruse 732*e8227804SMichael Kruse /* Update "convert" to reflect the next combination of automatic conversions 733*e8227804SMichael Kruse * for the arguments of "fd", 734*e8227804SMichael Kruse * returning false if there are no more combinations. 735*e8227804SMichael Kruse * 736*e8227804SMichael Kruse * In particular, find the last argument for which an automatic 737*e8227804SMichael Kruse * conversion function is available mapping to the type of this argument and 738*e8227804SMichael Kruse * that is not already marked for conversion. 739*e8227804SMichael Kruse * Mark this argument, if any, for conversion and clear the markings 740*e8227804SMichael Kruse * of all subsequent arguments. 741*e8227804SMichael Kruse * Repeated calls to this method therefore run through 742*e8227804SMichael Kruse * all possible combinations. 743*e8227804SMichael Kruse * 744*e8227804SMichael Kruse * Note that the first function argument is never considered 745*e8227804SMichael Kruse * for automatic conversion since this is the argument 746*e8227804SMichael Kruse * from which the isl_ctx used in the conversion is extracted. 747*e8227804SMichael Kruse */ 748*e8227804SMichael Kruse bool cpp_generator::next_variant(FunctionDecl *fd, std::vector<bool> &convert) 749*e8227804SMichael Kruse { 750*e8227804SMichael Kruse size_t n = convert.size(); 751*e8227804SMichael Kruse 752*e8227804SMichael Kruse for (int i = n - 1; i >= 1; --i) { 753*e8227804SMichael Kruse ParmVarDecl *param = fd->getParamDecl(i); 754*e8227804SMichael Kruse const Type *type = param->getOriginalType().getTypePtr(); 755*e8227804SMichael Kruse 756*e8227804SMichael Kruse if (conversions.count(type) == 0) 757*e8227804SMichael Kruse continue; 758*e8227804SMichael Kruse if (convert[i]) 759*e8227804SMichael Kruse continue; 760*e8227804SMichael Kruse convert[i] = true; 761*e8227804SMichael Kruse for (size_t j = i + 1; j < n; ++j) 762*e8227804SMichael Kruse convert[j] = false; 763*e8227804SMichael Kruse return true; 764*e8227804SMichael Kruse } 765*e8227804SMichael Kruse 766*e8227804SMichael Kruse return false; 767*e8227804SMichael Kruse } 768*e8227804SMichael Kruse 769*e8227804SMichael Kruse /* Print a declaration or definition for method "fd" in class "clazz" 770*e8227804SMichael Kruse * to "os". 771*e8227804SMichael Kruse * 772*e8227804SMichael Kruse * For methods that are identified as "get" methods, also 773*e8227804SMichael Kruse * print a declaration or definition for the method 774*e8227804SMichael Kruse * using a name that includes the "get_" prefix. 775*e8227804SMichael Kruse * 776*e8227804SMichael Kruse * If the generated method is an object method, then check 777*e8227804SMichael Kruse * whether any of its arguments can be automatically converted 778*e8227804SMichael Kruse * from something else, and, if so, generate a method 779*e8227804SMichael Kruse * for each combination of converted arguments. 780*e8227804SMichael Kruse */ 781*e8227804SMichael Kruse template <enum cpp_generator::method_part part> 782*e8227804SMichael Kruse void cpp_generator::print_method_variants(ostream &os, const isl_class &clazz, 783*e8227804SMichael Kruse FunctionDecl *fd) 784*e8227804SMichael Kruse { 785*e8227804SMichael Kruse function_kind kind = get_method_kind(clazz, fd); 786*e8227804SMichael Kruse std::vector<bool> convert(fd->getNumParams()); 787*e8227804SMichael Kruse 788*e8227804SMichael Kruse print_method<part>(os, clazz, fd, kind); 789*e8227804SMichael Kruse if (clazz.is_get_method(fd)) 790*e8227804SMichael Kruse print_get_method<part>(os, clazz, fd); 791*e8227804SMichael Kruse if (kind == function_kind_member_method) 792*e8227804SMichael Kruse while (next_variant(fd, convert)) 793*e8227804SMichael Kruse print_method<part>(os, clazz, fd, kind, convert); 794*e8227804SMichael Kruse } 795*e8227804SMichael Kruse 7966145b11cSTobias Grosser /* Print declarations for methods "methods" in class "clazz" to "os". 797d169d70bSTobias Grosser */ 798d169d70bSTobias Grosser void cpp_generator::print_method_group_decl(ostream &os, const isl_class &clazz, 799*e8227804SMichael Kruse const function_set &methods) 800d169d70bSTobias Grosser { 801*e8227804SMichael Kruse function_set::const_iterator it; 802d169d70bSTobias Grosser 803*e8227804SMichael Kruse for (it = methods.begin(); it != methods.end(); ++it) 804*e8227804SMichael Kruse print_method_variants<decl>(os, clazz, *it); 805d169d70bSTobias Grosser } 806d169d70bSTobias Grosser 807*e8227804SMichael Kruse /* Print a declaration for a method called "name" in class "clazz" 808*e8227804SMichael Kruse * derived from "fd" to "os". 809d169d70bSTobias Grosser * 810d169d70bSTobias Grosser * "kind" specifies the kind of method that should be generated. 811*e8227804SMichael Kruse * 812*e8227804SMichael Kruse * "convert" specifies which of the method arguments should 813*e8227804SMichael Kruse * be automatically converted. 814d169d70bSTobias Grosser */ 815*e8227804SMichael Kruse void cpp_generator::print_named_method_decl(ostream &os, const isl_class &clazz, 816*e8227804SMichael Kruse FunctionDecl *fd, const string &name, function_kind kind, 817*e8227804SMichael Kruse const std::vector<bool> &convert) 818d169d70bSTobias Grosser { 819*e8227804SMichael Kruse print_named_method_header(os, clazz, fd, name, true, kind, convert); 820d169d70bSTobias Grosser } 821d169d70bSTobias Grosser 822d169d70bSTobias Grosser /* Print implementations for class "clazz" to "os". 823d169d70bSTobias Grosser */ 824d169d70bSTobias Grosser void cpp_generator::print_class_impl(ostream &os, const isl_class &clazz) 825d169d70bSTobias Grosser { 826d169d70bSTobias Grosser std::string cppstring = type2cpp(clazz); 827d169d70bSTobias Grosser const char *cppname = cppstring.c_str(); 828d169d70bSTobias Grosser 829*e8227804SMichael Kruse osprintf(os, "// implementations for isl::%s", cppname); 830d169d70bSTobias Grosser 831d169d70bSTobias Grosser print_class_factory_impl(os, clazz); 832d169d70bSTobias Grosser print_public_constructors_impl(os, clazz); 833*e8227804SMichael Kruse print_protected_constructors_impl(os, clazz); 834d169d70bSTobias Grosser print_constructors_impl(os, clazz); 835d169d70bSTobias Grosser print_copy_assignment_impl(os, clazz); 836d169d70bSTobias Grosser print_destructor_impl(os, clazz); 837d169d70bSTobias Grosser print_ptr_impl(os, clazz); 838*e8227804SMichael Kruse print_downcast_impl(os, clazz); 839*e8227804SMichael Kruse print_ctx_impl(os, clazz); 840*e8227804SMichael Kruse print_persistent_callbacks_impl(os, clazz); 841d169d70bSTobias Grosser print_methods_impl(os, clazz); 842*e8227804SMichael Kruse print_set_enums_impl(os, clazz); 843*e8227804SMichael Kruse print_stream_insertion(os, clazz); 844d169d70bSTobias Grosser } 845d169d70bSTobias Grosser 846d169d70bSTobias Grosser /* Print code for throwing an exception corresponding to the last error 847*e8227804SMichael Kruse * that occurred on "saved_ctx". 848*e8227804SMichael Kruse * This assumes that a valid isl::ctx is available in the "saved_ctx" variable, 849d169d70bSTobias Grosser * e.g., through a prior call to print_save_ctx. 850d169d70bSTobias Grosser */ 851d169d70bSTobias Grosser static void print_throw_last_error(ostream &os) 852d169d70bSTobias Grosser { 853*e8227804SMichael Kruse osprintf(os, " exception::throw_last_error(saved_ctx);\n"); 854*e8227804SMichael Kruse } 855*e8227804SMichael Kruse 856*e8227804SMichael Kruse /* Print code with the given indentation 857*e8227804SMichael Kruse * for throwing an exception_invalid with the given message. 858*e8227804SMichael Kruse */ 859*e8227804SMichael Kruse static void print_throw_invalid(ostream &os, int indent, const char *msg) 860*e8227804SMichael Kruse { 861*e8227804SMichael Kruse osprintf(os, indent, 862*e8227804SMichael Kruse "exception::throw_invalid(\"%s\", __FILE__, __LINE__);\n", msg); 863d169d70bSTobias Grosser } 864d169d70bSTobias Grosser 865d169d70bSTobias Grosser /* Print code for throwing an exception on NULL input. 866d169d70bSTobias Grosser */ 867d169d70bSTobias Grosser static void print_throw_NULL_input(ostream &os) 868d169d70bSTobias Grosser { 869*e8227804SMichael Kruse print_throw_invalid(os, 4, "NULL input"); 870*e8227804SMichael Kruse } 871*e8227804SMichael Kruse 872*e8227804SMichael Kruse /* Print code with the given indentation 873*e8227804SMichael Kruse * for acting on an invalid error with message "msg". 874*e8227804SMichael Kruse * In particular, throw an exception_invalid. 875*e8227804SMichael Kruse * In the checked C++ bindings, isl_die is called instead with the code 876*e8227804SMichael Kruse * in "checked_code". 877*e8227804SMichael Kruse */ 878*e8227804SMichael Kruse void cpp_generator::print_invalid(ostream &os, int indent, const char *msg, 879*e8227804SMichael Kruse const char *checked_code) 880*e8227804SMichael Kruse { 881*e8227804SMichael Kruse if (checked) 882*e8227804SMichael Kruse osprintf(os, indent, 883*e8227804SMichael Kruse "isl_die(ctx().get(), isl_error_invalid, " 884*e8227804SMichael Kruse "\"%s\", %s);\n", msg, checked_code); 885*e8227804SMichael Kruse else 886*e8227804SMichael Kruse print_throw_invalid(os, indent, msg); 887*e8227804SMichael Kruse } 888*e8227804SMichael Kruse 889*e8227804SMichael Kruse /* Print an operator for inserting objects of "class" 890*e8227804SMichael Kruse * into an output stream. 891*e8227804SMichael Kruse * 892*e8227804SMichael Kruse * Unless checked C++ bindings are being generated, 893*e8227804SMichael Kruse * the operator requires its argument to be non-NULL. 894*e8227804SMichael Kruse * An exception is thrown if anything went wrong during the printing. 895*e8227804SMichael Kruse * During this printing, isl is made not to print any error message 896*e8227804SMichael Kruse * because the error message is included in the exception. 897*e8227804SMichael Kruse * 898*e8227804SMichael Kruse * If checked C++ bindings are being generated and anything went wrong, 899*e8227804SMichael Kruse * then record this failure in the output stream. 900*e8227804SMichael Kruse */ 901*e8227804SMichael Kruse void cpp_generator::print_stream_insertion(ostream &os, const isl_class &clazz) 902*e8227804SMichael Kruse { 903*e8227804SMichael Kruse const char *name = clazz.name.c_str(); 904*e8227804SMichael Kruse std::string cppstring = type2cpp(clazz); 905*e8227804SMichael Kruse const char *cppname = cppstring.c_str(); 906*e8227804SMichael Kruse 907*e8227804SMichael Kruse if (!clazz.fn_to_str) 908*e8227804SMichael Kruse return; 909*e8227804SMichael Kruse 910*e8227804SMichael Kruse osprintf(os, "\n"); 911*e8227804SMichael Kruse osprintf(os, "inline std::ostream &operator<<(std::ostream &os, "); 912*e8227804SMichael Kruse osprintf(os, "const %s &obj)\n", cppname); 913*e8227804SMichael Kruse osprintf(os, "{\n"); 914*e8227804SMichael Kruse print_check_ptr_start(os, clazz, "obj.get()"); 915*e8227804SMichael Kruse osprintf(os, " char *str = %s_to_str(obj.get());\n", name); 916*e8227804SMichael Kruse print_check_ptr_end(os, "str"); 917*e8227804SMichael Kruse if (checked) { 918*e8227804SMichael Kruse osprintf(os, " if (!str) {\n"); 919*e8227804SMichael Kruse osprintf(os, " os.setstate(std::ios_base::badbit);\n"); 920*e8227804SMichael Kruse osprintf(os, " return os;\n"); 921*e8227804SMichael Kruse osprintf(os, " }\n"); 922*e8227804SMichael Kruse } 923*e8227804SMichael Kruse osprintf(os, " os << str;\n"); 924*e8227804SMichael Kruse osprintf(os, " free(str);\n"); 925*e8227804SMichael Kruse osprintf(os, " return os;\n"); 926*e8227804SMichael Kruse osprintf(os, "}\n"); 927d169d70bSTobias Grosser } 928d169d70bSTobias Grosser 92926269d34STobias Grosser /* Print code that checks that "ptr" is not NULL at input. 93026269d34STobias Grosser * 93126269d34STobias Grosser * Omit the check if checked C++ bindings are being generated. 93226269d34STobias Grosser */ 93326269d34STobias Grosser void cpp_generator::print_check_ptr(ostream &os, const char *ptr) 93426269d34STobias Grosser { 93526269d34STobias Grosser if (checked) 93626269d34STobias Grosser return; 93726269d34STobias Grosser 93826269d34STobias Grosser osprintf(os, " if (!%s)\n", ptr); 93926269d34STobias Grosser print_throw_NULL_input(os); 94026269d34STobias Grosser } 94126269d34STobias Grosser 94226269d34STobias Grosser /* Print code that checks that "ptr" is not NULL at input and 94326269d34STobias Grosser * that saves a copy of the isl_ctx of "ptr" for a later check. 94426269d34STobias Grosser * 94526269d34STobias Grosser * Omit the check if checked C++ bindings are being generated. 94626269d34STobias Grosser */ 94726269d34STobias Grosser void cpp_generator::print_check_ptr_start(ostream &os, const isl_class &clazz, 94826269d34STobias Grosser const char *ptr) 94926269d34STobias Grosser { 95026269d34STobias Grosser if (checked) 95126269d34STobias Grosser return; 95226269d34STobias Grosser 95326269d34STobias Grosser print_check_ptr(os, ptr); 954*e8227804SMichael Kruse osprintf(os, " auto saved_ctx = %s_get_ctx(%s);\n", 955*e8227804SMichael Kruse clazz.name.c_str(), ptr); 95626269d34STobias Grosser print_on_error_continue(os); 95726269d34STobias Grosser } 95826269d34STobias Grosser 95926269d34STobias Grosser /* Print code that checks that "ptr" is not NULL at the end. 96026269d34STobias Grosser * A copy of the isl_ctx is expected to have been saved by 96126269d34STobias Grosser * code generated by print_check_ptr_start. 96226269d34STobias Grosser * 96326269d34STobias Grosser * Omit the check if checked C++ bindings are being generated. 96426269d34STobias Grosser */ 96526269d34STobias Grosser void cpp_generator::print_check_ptr_end(ostream &os, const char *ptr) 96626269d34STobias Grosser { 96726269d34STobias Grosser if (checked) 96826269d34STobias Grosser return; 96926269d34STobias Grosser 97026269d34STobias Grosser osprintf(os, " if (!%s)\n", ptr); 97126269d34STobias Grosser print_throw_last_error(os); 97226269d34STobias Grosser } 97326269d34STobias Grosser 974d169d70bSTobias Grosser /* Print implementation of global factory functions to "os". 975d169d70bSTobias Grosser * 976d169d70bSTobias Grosser * Each class has two global factory functions: 977d169d70bSTobias Grosser * 978d169d70bSTobias Grosser * set manage(__isl_take isl_set *ptr); 979d169d70bSTobias Grosser * set manage_copy(__isl_keep isl_set *ptr); 980d169d70bSTobias Grosser * 981d169d70bSTobias Grosser * Unless checked C++ bindings are being generated, 982d169d70bSTobias Grosser * both functions require the argument to be non-NULL. 983d169d70bSTobias Grosser * An exception is thrown if anything went wrong during the copying 984d169d70bSTobias Grosser * in manage_copy. 985d169d70bSTobias Grosser * During the copying, isl is made not to print any error message 986d169d70bSTobias Grosser * because the error message is included in the exception. 987*e8227804SMichael Kruse * 988*e8227804SMichael Kruse * For a subclass based on a type function, no factory functions 989*e8227804SMichael Kruse * are introduced because they share the C object type with 990*e8227804SMichael Kruse * the superclass. 991d169d70bSTobias Grosser */ 992d169d70bSTobias Grosser void cpp_generator::print_class_factory_impl(ostream &os, 993d169d70bSTobias Grosser const isl_class &clazz) 994d169d70bSTobias Grosser { 995d169d70bSTobias Grosser const char *name = clazz.name.c_str(); 996d169d70bSTobias Grosser std::string cppstring = type2cpp(clazz); 997d169d70bSTobias Grosser const char *cppname = cppstring.c_str(); 998d169d70bSTobias Grosser 999*e8227804SMichael Kruse if (clazz.is_type_subclass()) 1000*e8227804SMichael Kruse return; 1001*e8227804SMichael Kruse 1002*e8227804SMichael Kruse osprintf(os, "\n"); 1003d169d70bSTobias Grosser osprintf(os, "%s manage(__isl_take %s *ptr) {\n", cppname, name); 100426269d34STobias Grosser print_check_ptr(os, "ptr"); 1005d169d70bSTobias Grosser osprintf(os, " return %s(ptr);\n", cppname); 1006d169d70bSTobias Grosser osprintf(os, "}\n"); 1007d169d70bSTobias Grosser 1008d169d70bSTobias Grosser osprintf(os, "%s manage_copy(__isl_keep %s *ptr) {\n", cppname, 1009d169d70bSTobias Grosser name); 101026269d34STobias Grosser print_check_ptr_start(os, clazz, "ptr"); 1011d169d70bSTobias Grosser osprintf(os, " ptr = %s_copy(ptr);\n", name); 101226269d34STobias Grosser print_check_ptr_end(os, "ptr"); 1013d169d70bSTobias Grosser osprintf(os, " return %s(ptr);\n", cppname); 1014d169d70bSTobias Grosser osprintf(os, "}\n"); 1015d169d70bSTobias Grosser } 1016d169d70bSTobias Grosser 1017*e8227804SMichael Kruse /* Print implementations of protected constructors for class "clazz" to "os". 1018*e8227804SMichael Kruse * 1019*e8227804SMichael Kruse * The pointer to the isl object is either initialized directly or 1020*e8227804SMichael Kruse * through the (immediate) superclass. 1021d169d70bSTobias Grosser */ 1022*e8227804SMichael Kruse void cpp_generator::print_protected_constructors_impl(ostream &os, 1023d169d70bSTobias Grosser const isl_class &clazz) 1024d169d70bSTobias Grosser { 1025d169d70bSTobias Grosser const char *name = clazz.name.c_str(); 1026d169d70bSTobias Grosser std::string cppstring = type2cpp(clazz); 1027d169d70bSTobias Grosser const char *cppname = cppstring.c_str(); 1028*e8227804SMichael Kruse bool subclass = clazz.is_type_subclass(); 1029d169d70bSTobias Grosser 1030*e8227804SMichael Kruse osprintf(os, "\n"); 1031*e8227804SMichael Kruse osprintf(os, "%s::%s(__isl_take %s *ptr)\n", cppname, cppname, name); 1032*e8227804SMichael Kruse if (subclass) 1033*e8227804SMichael Kruse osprintf(os, " : %s(ptr) {}\n", 1034*e8227804SMichael Kruse type2cpp(clazz.superclass_name).c_str()); 1035*e8227804SMichael Kruse else 1036*e8227804SMichael Kruse osprintf(os, " : ptr(ptr) {}\n"); 1037d169d70bSTobias Grosser } 1038d169d70bSTobias Grosser 1039d169d70bSTobias Grosser /* Print implementations of public constructors for class "clazz" to "os". 1040d169d70bSTobias Grosser * 1041*e8227804SMichael Kruse * The pointer to the isl object is either initialized directly or 1042*e8227804SMichael Kruse * through the (immediate) superclass. 1043*e8227804SMichael Kruse * 1044*e8227804SMichael Kruse * If the class has any persistent callbacks, then copy them 1045*e8227804SMichael Kruse * from the original object in the copy constructor. 1046*e8227804SMichael Kruse * If the class is a subclass, then the persistent callbacks 1047*e8227804SMichael Kruse * are assumed to be copied by the copy constructor of the superclass. 1048*e8227804SMichael Kruse * 1049d169d70bSTobias Grosser * Throw an exception from the copy constructor if anything went wrong 1050*e8227804SMichael Kruse * during the copying or if the input is NULL, if any copying is performed. 1051d169d70bSTobias Grosser * During the copying, isl is made not to print any error message 1052d169d70bSTobias Grosser * because the error message is included in the exception. 1053d169d70bSTobias Grosser * No exceptions are thrown if checked C++ bindings 1054d169d70bSTobias Grosser * are being generated, 1055d169d70bSTobias Grosser */ 1056d169d70bSTobias Grosser void cpp_generator::print_public_constructors_impl(ostream &os, 1057d169d70bSTobias Grosser const isl_class &clazz) 1058d169d70bSTobias Grosser { 1059d169d70bSTobias Grosser std::string cppstring = type2cpp(clazz); 1060*e8227804SMichael Kruse std::string super; 1061d169d70bSTobias Grosser const char *cppname = cppstring.c_str(); 1062*e8227804SMichael Kruse bool subclass = clazz.is_type_subclass(); 1063d169d70bSTobias Grosser 1064*e8227804SMichael Kruse osprintf(os, "\n"); 1065*e8227804SMichael Kruse if (subclass) 1066*e8227804SMichael Kruse super = type2cpp(clazz.superclass_name); 1067*e8227804SMichael Kruse osprintf(os, "%s::%s()\n", cppname, cppname); 1068*e8227804SMichael Kruse if (subclass) 1069*e8227804SMichael Kruse osprintf(os, " : %s() {}\n\n", super.c_str()); 1070*e8227804SMichael Kruse else 1071*e8227804SMichael Kruse osprintf(os, " : ptr(nullptr) {}\n\n"); 1072*e8227804SMichael Kruse osprintf(os, "%s::%s(const %s &obj)\n", cppname, cppname, cppname); 1073*e8227804SMichael Kruse if (subclass) 1074*e8227804SMichael Kruse osprintf(os, " : %s(obj)\n", super.c_str()); 1075*e8227804SMichael Kruse else 1076*e8227804SMichael Kruse osprintf(os, " : ptr(nullptr)\n"); 1077d169d70bSTobias Grosser osprintf(os, "{\n"); 1078*e8227804SMichael Kruse if (!subclass) { 107926269d34STobias Grosser print_check_ptr_start(os, clazz, "obj.ptr"); 1080d169d70bSTobias Grosser osprintf(os, " ptr = obj.copy();\n"); 1081*e8227804SMichael Kruse if (clazz.has_persistent_callbacks()) 1082*e8227804SMichael Kruse osprintf(os, " copy_callbacks(obj);\n"); 108326269d34STobias Grosser print_check_ptr_end(os, "ptr"); 1084*e8227804SMichael Kruse } 1085*e8227804SMichael Kruse osprintf(os, "}\n"); 1086*e8227804SMichael Kruse } 1087*e8227804SMichael Kruse 1088*e8227804SMichael Kruse /* Print definition for "method" in class "clazz" to "os", 1089*e8227804SMichael Kruse * without any automatic type conversions. 1090*e8227804SMichael Kruse * 1091*e8227804SMichael Kruse * "kind" specifies the kind of method that should be generated. 1092*e8227804SMichael Kruse * 1093*e8227804SMichael Kruse * This method distinguishes three kinds of methods: member methods, static 1094*e8227804SMichael Kruse * methods, and constructors. 1095*e8227804SMichael Kruse * 1096*e8227804SMichael Kruse * Member methods call "method" by passing to the underlying isl function the 1097*e8227804SMichael Kruse * isl object belonging to "this" as first argument and the remaining arguments 1098*e8227804SMichael Kruse * as subsequent arguments. 1099*e8227804SMichael Kruse * 1100*e8227804SMichael Kruse * Static methods call "method" by passing all arguments to the underlying isl 1101*e8227804SMichael Kruse * function, as no this-pointer is available. The result is a newly managed 1102*e8227804SMichael Kruse * isl C++ object. 1103*e8227804SMichael Kruse * 1104*e8227804SMichael Kruse * Constructors create a new object from a given set of input parameters. They 1105*e8227804SMichael Kruse * do not return a value, but instead update the pointer stored inside the 1106*e8227804SMichael Kruse * newly created object. 1107*e8227804SMichael Kruse * 1108*e8227804SMichael Kruse * If the method has a callback argument, we reduce the number of parameters 1109*e8227804SMichael Kruse * that are exposed by one to hide the user pointer from the interface. On 1110*e8227804SMichael Kruse * the C++ side no user pointer is needed, as arguments can be forwarded 1111*e8227804SMichael Kruse * as part of the std::function argument which specifies the callback function. 1112*e8227804SMichael Kruse * 1113*e8227804SMichael Kruse * Unless checked C++ bindings are being generated, 1114*e8227804SMichael Kruse * the inputs of the method are first checked for being valid isl objects and 1115*e8227804SMichael Kruse * a copy of the associated isl::ctx is saved (if needed). 1116*e8227804SMichael Kruse * If any failure occurs, either during the check for the inputs or 1117*e8227804SMichael Kruse * during the isl function call, an exception is thrown. 1118*e8227804SMichael Kruse * During the function call, isl is made not to print any error message 1119*e8227804SMichael Kruse * because the error message is included in the exception. 1120*e8227804SMichael Kruse */ 1121*e8227804SMichael Kruse template<> 1122*e8227804SMichael Kruse void cpp_generator::print_method<cpp_generator::impl>(ostream &os, 1123*e8227804SMichael Kruse const isl_class &clazz, FunctionDecl *method, function_kind kind) 1124*e8227804SMichael Kruse { 1125*e8227804SMichael Kruse string methodname = method->getName(); 1126*e8227804SMichael Kruse int num_params = method->getNumParams(); 1127*e8227804SMichael Kruse 1128*e8227804SMichael Kruse osprintf(os, "\n"); 1129*e8227804SMichael Kruse print_method_header(os, clazz, method, false, kind); 1130*e8227804SMichael Kruse osprintf(os, "{\n"); 1131*e8227804SMichael Kruse print_argument_validity_check(os, method, kind); 1132*e8227804SMichael Kruse print_save_ctx(os, method, kind); 1133*e8227804SMichael Kruse print_on_error_continue(os); 1134*e8227804SMichael Kruse 1135*e8227804SMichael Kruse for (int i = 0; i < num_params; ++i) { 1136*e8227804SMichael Kruse ParmVarDecl *param = method->getParamDecl(i); 1137*e8227804SMichael Kruse if (is_callback(param->getType())) { 1138*e8227804SMichael Kruse num_params -= 1; 1139*e8227804SMichael Kruse print_callback_local(os, param); 1140*e8227804SMichael Kruse } 1141*e8227804SMichael Kruse } 1142*e8227804SMichael Kruse 1143*e8227804SMichael Kruse osprintf(os, " auto res = %s(", methodname.c_str()); 1144*e8227804SMichael Kruse 1145*e8227804SMichael Kruse for (int i = 0; i < num_params; ++i) { 1146*e8227804SMichael Kruse ParmVarDecl *param = method->getParamDecl(i); 1147*e8227804SMichael Kruse bool load_from_this_ptr = false; 1148*e8227804SMichael Kruse 1149*e8227804SMichael Kruse if (i == 0 && kind == function_kind_member_method) 1150*e8227804SMichael Kruse load_from_this_ptr = true; 1151*e8227804SMichael Kruse 1152*e8227804SMichael Kruse print_method_param_use(os, param, load_from_this_ptr); 1153*e8227804SMichael Kruse 1154*e8227804SMichael Kruse if (i != num_params - 1) 1155*e8227804SMichael Kruse osprintf(os, ", "); 1156*e8227804SMichael Kruse } 1157*e8227804SMichael Kruse osprintf(os, ");\n"); 1158*e8227804SMichael Kruse 1159*e8227804SMichael Kruse print_exceptional_execution_check(os, clazz, method, kind); 1160*e8227804SMichael Kruse if (kind == function_kind_constructor) { 1161*e8227804SMichael Kruse osprintf(os, " ptr = res;\n"); 1162*e8227804SMichael Kruse } else { 1163*e8227804SMichael Kruse print_method_return(os, clazz, method); 1164*e8227804SMichael Kruse } 1165*e8227804SMichael Kruse 1166*e8227804SMichael Kruse osprintf(os, "}\n"); 1167*e8227804SMichael Kruse } 1168*e8227804SMichael Kruse 1169*e8227804SMichael Kruse /* Print a definition for "method" in class "clazz" to "os", 1170*e8227804SMichael Kruse * where at least one of the argument types needs to be converted, 1171*e8227804SMichael Kruse * as specified by "convert". 1172*e8227804SMichael Kruse * 1173*e8227804SMichael Kruse * "kind" specifies the kind of method that should be generated and 1174*e8227804SMichael Kruse * is assumed to be set to function_kind_member_method. 1175*e8227804SMichael Kruse * 1176*e8227804SMichael Kruse * The generated method performs the required conversion(s) and 1177*e8227804SMichael Kruse * calls the method generated without conversions. 1178*e8227804SMichael Kruse * 1179*e8227804SMichael Kruse * Each conversion is performed by calling the conversion function 1180*e8227804SMichael Kruse * with as arguments the isl_ctx of the object and the argument 1181*e8227804SMichael Kruse * to the generated method. 1182*e8227804SMichael Kruse * In order to be able to use this isl_ctx, the current object needs 1183*e8227804SMichael Kruse * to valid. The validity of other arguments is checked 1184*e8227804SMichael Kruse * by the called method. 1185*e8227804SMichael Kruse */ 1186*e8227804SMichael Kruse template<> 1187*e8227804SMichael Kruse void cpp_generator::print_method<cpp_generator::impl>(ostream &os, 1188*e8227804SMichael Kruse const isl_class &clazz, FunctionDecl *method, function_kind kind, 1189*e8227804SMichael Kruse const std::vector<bool> &convert) 1190*e8227804SMichael Kruse { 1191*e8227804SMichael Kruse string name = clazz.method_name(method); 1192*e8227804SMichael Kruse int num_params = method->getNumParams(); 1193*e8227804SMichael Kruse 1194*e8227804SMichael Kruse if (kind != function_kind_member_method) 1195*e8227804SMichael Kruse die("Automatic conversion currently only supported " 1196*e8227804SMichael Kruse "for object methods"); 1197*e8227804SMichael Kruse 1198*e8227804SMichael Kruse osprintf(os, "\n"); 1199*e8227804SMichael Kruse print_named_method_header(os, clazz, method, name, false, 1200*e8227804SMichael Kruse kind, convert); 1201*e8227804SMichael Kruse osprintf(os, "{\n"); 1202*e8227804SMichael Kruse print_check_ptr(os, "ptr"); 1203*e8227804SMichael Kruse osprintf(os, " return this->%s(", name.c_str()); 1204*e8227804SMichael Kruse for (int i = 1; i < num_params; ++i) { 1205*e8227804SMichael Kruse ParmVarDecl *param = method->getParamDecl(i); 1206*e8227804SMichael Kruse std::string name = param->getName().str(); 1207*e8227804SMichael Kruse 1208*e8227804SMichael Kruse if (i != 1) 1209*e8227804SMichael Kruse osprintf(os, ", "); 1210*e8227804SMichael Kruse if (convert[i]) { 1211*e8227804SMichael Kruse QualType type = param->getOriginalType(); 1212*e8227804SMichael Kruse string cpptype = type2cpp(type); 1213*e8227804SMichael Kruse osprintf(os, "%s(ctx(), %s)", 1214*e8227804SMichael Kruse cpptype.c_str(), name.c_str()); 1215*e8227804SMichael Kruse } else { 1216*e8227804SMichael Kruse osprintf(os, "%s", name.c_str()); 1217*e8227804SMichael Kruse } 1218*e8227804SMichael Kruse } 1219*e8227804SMichael Kruse osprintf(os, ");\n"); 1220d169d70bSTobias Grosser osprintf(os, "}\n"); 1221d169d70bSTobias Grosser } 1222d169d70bSTobias Grosser 1223d169d70bSTobias Grosser /* Print implementations of constructors for class "clazz" to "os". 1224d169d70bSTobias Grosser */ 1225d169d70bSTobias Grosser void cpp_generator::print_constructors_impl(ostream &os, 1226d169d70bSTobias Grosser const isl_class &clazz) 1227d169d70bSTobias Grosser { 1228*e8227804SMichael Kruse function_set::const_iterator in; 1229*e8227804SMichael Kruse const function_set constructors = clazz.constructors; 1230d169d70bSTobias Grosser 1231d169d70bSTobias Grosser for (in = constructors.begin(); in != constructors.end(); ++in) { 1232d169d70bSTobias Grosser FunctionDecl *cons = *in; 1233d169d70bSTobias Grosser 1234*e8227804SMichael Kruse print_method<impl>(os, clazz, cons, function_kind_constructor); 1235d169d70bSTobias Grosser } 1236d169d70bSTobias Grosser } 1237d169d70bSTobias Grosser 1238d169d70bSTobias Grosser /* Print implementation of copy assignment operator for class "clazz" to "os". 1239*e8227804SMichael Kruse * 1240*e8227804SMichael Kruse * If the class has any persistent callbacks, then copy them 1241*e8227804SMichael Kruse * from the original object. 1242d169d70bSTobias Grosser */ 1243d169d70bSTobias Grosser void cpp_generator::print_copy_assignment_impl(ostream &os, 1244d169d70bSTobias Grosser const isl_class &clazz) 1245d169d70bSTobias Grosser { 1246d169d70bSTobias Grosser const char *name = clazz.name.c_str(); 1247d169d70bSTobias Grosser std::string cppstring = type2cpp(clazz); 1248d169d70bSTobias Grosser const char *cppname = cppstring.c_str(); 1249d169d70bSTobias Grosser 1250*e8227804SMichael Kruse osprintf(os, "\n"); 1251d169d70bSTobias Grosser osprintf(os, "%s &%s::operator=(%s obj) {\n", cppname, 1252d169d70bSTobias Grosser cppname, cppname); 1253d169d70bSTobias Grosser osprintf(os, " std::swap(this->ptr, obj.ptr);\n", name); 1254*e8227804SMichael Kruse if (clazz.has_persistent_callbacks()) 1255*e8227804SMichael Kruse osprintf(os, " copy_callbacks(obj);\n"); 1256d169d70bSTobias Grosser osprintf(os, " return *this;\n"); 1257d169d70bSTobias Grosser osprintf(os, "}\n"); 1258d169d70bSTobias Grosser } 1259d169d70bSTobias Grosser 1260d169d70bSTobias Grosser /* Print implementation of destructor for class "clazz" to "os". 1261*e8227804SMichael Kruse * 1262*e8227804SMichael Kruse * No explicit destructor is needed for type based subclasses. 1263d169d70bSTobias Grosser */ 1264d169d70bSTobias Grosser void cpp_generator::print_destructor_impl(ostream &os, 1265d169d70bSTobias Grosser const isl_class &clazz) 1266d169d70bSTobias Grosser { 1267d169d70bSTobias Grosser const char *name = clazz.name.c_str(); 1268d169d70bSTobias Grosser std::string cppstring = type2cpp(clazz); 1269d169d70bSTobias Grosser const char *cppname = cppstring.c_str(); 1270d169d70bSTobias Grosser 1271*e8227804SMichael Kruse if (clazz.is_type_subclass()) 1272*e8227804SMichael Kruse return; 1273*e8227804SMichael Kruse 1274*e8227804SMichael Kruse osprintf(os, "\n"); 1275d169d70bSTobias Grosser osprintf(os, "%s::~%s() {\n", cppname, cppname); 1276d169d70bSTobias Grosser osprintf(os, " if (ptr)\n"); 1277d169d70bSTobias Grosser osprintf(os, " %s_free(ptr);\n", name); 1278d169d70bSTobias Grosser osprintf(os, "}\n"); 1279d169d70bSTobias Grosser } 1280d169d70bSTobias Grosser 1281*e8227804SMichael Kruse /* Print a check that the persistent callback corresponding to "fd" 1282*e8227804SMichael Kruse * is not set, throwing an exception (or printing an error message 1283*e8227804SMichael Kruse * and returning nullptr) if it is set. 1284*e8227804SMichael Kruse */ 1285*e8227804SMichael Kruse void cpp_generator::print_check_no_persistent_callback(ostream &os, 1286*e8227804SMichael Kruse const isl_class &clazz, FunctionDecl *fd) 1287*e8227804SMichael Kruse { 1288*e8227804SMichael Kruse string callback_name = clazz.persistent_callback_name(fd); 1289*e8227804SMichael Kruse 1290*e8227804SMichael Kruse osprintf(os, " if (%s_data)\n", callback_name.c_str()); 1291*e8227804SMichael Kruse print_invalid(os, 4, "cannot release object with persistent callbacks", 1292*e8227804SMichael Kruse "return nullptr"); 1293*e8227804SMichael Kruse } 1294*e8227804SMichael Kruse 1295d169d70bSTobias Grosser /* Print implementation of ptr() functions for class "clazz" to "os". 1296*e8227804SMichael Kruse * Since type based subclasses share the pointer with their superclass, 1297*e8227804SMichael Kruse * they can also reuse these functions from the superclass. 1298*e8227804SMichael Kruse * 1299*e8227804SMichael Kruse * If an object has persistent callbacks set, then the underlying 1300*e8227804SMichael Kruse * C object pointer cannot be released because it references data 1301*e8227804SMichael Kruse * in the C++ object. 1302d169d70bSTobias Grosser */ 1303d169d70bSTobias Grosser void cpp_generator::print_ptr_impl(ostream &os, const isl_class &clazz) 1304d169d70bSTobias Grosser { 1305d169d70bSTobias Grosser const char *name = clazz.name.c_str(); 1306d169d70bSTobias Grosser std::string cppstring = type2cpp(clazz); 1307d169d70bSTobias Grosser const char *cppname = cppstring.c_str(); 1308*e8227804SMichael Kruse set<FunctionDecl *>::const_iterator in; 1309*e8227804SMichael Kruse const set<FunctionDecl *> &callbacks = clazz.persistent_callbacks; 1310d169d70bSTobias Grosser 1311*e8227804SMichael Kruse if (clazz.is_type_subclass()) 1312*e8227804SMichael Kruse return; 1313*e8227804SMichael Kruse 1314*e8227804SMichael Kruse osprintf(os, "\n"); 1315d169d70bSTobias Grosser osprintf(os, "__isl_give %s *%s::copy() const & {\n", name, cppname); 1316d169d70bSTobias Grosser osprintf(os, " return %s_copy(ptr);\n", name); 1317d169d70bSTobias Grosser osprintf(os, "}\n\n"); 1318d169d70bSTobias Grosser osprintf(os, "__isl_keep %s *%s::get() const {\n", name, cppname); 1319d169d70bSTobias Grosser osprintf(os, " return ptr;\n"); 1320d169d70bSTobias Grosser osprintf(os, "}\n\n"); 1321d169d70bSTobias Grosser osprintf(os, "__isl_give %s *%s::release() {\n", name, cppname); 1322*e8227804SMichael Kruse for (in = callbacks.begin(); in != callbacks.end(); ++in) 1323*e8227804SMichael Kruse print_check_no_persistent_callback(os, clazz, *in); 1324d169d70bSTobias Grosser osprintf(os, " %s *tmp = ptr;\n", name); 1325d169d70bSTobias Grosser osprintf(os, " ptr = nullptr;\n"); 1326d169d70bSTobias Grosser osprintf(os, " return tmp;\n"); 1327d169d70bSTobias Grosser osprintf(os, "}\n\n"); 1328d169d70bSTobias Grosser osprintf(os, "bool %s::is_null() const {\n", cppname); 1329d169d70bSTobias Grosser osprintf(os, " return ptr == nullptr;\n"); 1330d169d70bSTobias Grosser osprintf(os, "}\n"); 1331d169d70bSTobias Grosser } 1332d169d70bSTobias Grosser 1333*e8227804SMichael Kruse /* Print implementations for the "as" and "isa" methods, if "clazz" 1334*e8227804SMichael Kruse * is a superclass with a type function. 1335*e8227804SMichael Kruse * 1336*e8227804SMichael Kruse * "isa" checks whether an object is of a given subclass type. 1337*e8227804SMichael Kruse * "isa_type" does the same, but gets passed the value of the type field 1338*e8227804SMichael Kruse * of the subclass as a function argument and the type of this field 1339*e8227804SMichael Kruse * as a template argument. 1340*e8227804SMichael Kruse * "as" casts an object to a given subclass type, erroring out 1341*e8227804SMichael Kruse * if the object is not of the given type. 1342*e8227804SMichael Kruse * 1343*e8227804SMichael Kruse * If the input is an invalid object, then these methods raise 1344*e8227804SMichael Kruse * an exception. 1345*e8227804SMichael Kruse * If checked bindings are being generated, 1346*e8227804SMichael Kruse * then an invalid boolean or object is returned instead. 1347d169d70bSTobias Grosser */ 1348*e8227804SMichael Kruse void cpp_generator::print_downcast_impl(ostream &os, const isl_class &clazz) 1349*e8227804SMichael Kruse { 1350*e8227804SMichael Kruse std::string cppstring = type2cpp(clazz); 1351*e8227804SMichael Kruse const char *cppname = cppstring.c_str(); 1352*e8227804SMichael Kruse 1353*e8227804SMichael Kruse if (!clazz.fn_type) 1354*e8227804SMichael Kruse return; 1355*e8227804SMichael Kruse 1356*e8227804SMichael Kruse osprintf(os, "\n"); 1357*e8227804SMichael Kruse osprintf(os, "template <typename T, typename>\n"); 1358*e8227804SMichael Kruse osprintf(os, "%s %s::isa_type(T subtype) const\n", 1359*e8227804SMichael Kruse isl_bool2cpp().c_str(), cppname); 1360*e8227804SMichael Kruse osprintf(os, "{\n"); 1361*e8227804SMichael Kruse osprintf(os, " if (is_null())\n"); 1362*e8227804SMichael Kruse if (checked) 1363*e8227804SMichael Kruse osprintf(os, " return boolean();\n"); 1364*e8227804SMichael Kruse else 1365*e8227804SMichael Kruse print_throw_NULL_input(os); 1366*e8227804SMichael Kruse osprintf(os, " return %s(get()) == subtype;\n", 1367*e8227804SMichael Kruse clazz.fn_type->getNameAsString().c_str()); 1368*e8227804SMichael Kruse osprintf(os, "}\n"); 1369*e8227804SMichael Kruse 1370*e8227804SMichael Kruse osprintf(os, "template <class T>\n"); 1371*e8227804SMichael Kruse osprintf(os, "%s %s::isa() const\n", isl_bool2cpp().c_str(), cppname); 1372*e8227804SMichael Kruse osprintf(os, "{\n"); 1373*e8227804SMichael Kruse osprintf(os, " return isa_type<decltype(T::type)>(T::type);\n"); 1374*e8227804SMichael Kruse osprintf(os, "}\n"); 1375*e8227804SMichael Kruse 1376*e8227804SMichael Kruse osprintf(os, "template <class T>\n"); 1377*e8227804SMichael Kruse osprintf(os, "T %s::as() const\n", cppname); 1378*e8227804SMichael Kruse osprintf(os, "{\n"); 1379*e8227804SMichael Kruse if (checked) 1380*e8227804SMichael Kruse osprintf(os, " if (isa<T>().is_false())\n"); 1381*e8227804SMichael Kruse else 1382*e8227804SMichael Kruse osprintf(os, " if (!isa<T>())\n"); 1383*e8227804SMichael Kruse print_invalid(os, 4, "not an object of the requested subtype", 1384*e8227804SMichael Kruse "return T()"); 1385*e8227804SMichael Kruse osprintf(os, " return T(copy());\n"); 1386*e8227804SMichael Kruse osprintf(os, "}\n"); 1387*e8227804SMichael Kruse } 1388*e8227804SMichael Kruse 1389*e8227804SMichael Kruse /* Print the implementation of the ctx method. 1390*e8227804SMichael Kruse */ 1391*e8227804SMichael Kruse void cpp_generator::print_ctx_impl(ostream &os, const isl_class &clazz) 1392d169d70bSTobias Grosser { 1393d169d70bSTobias Grosser const char *name = clazz.name.c_str(); 1394d169d70bSTobias Grosser std::string cppstring = type2cpp(clazz); 1395d169d70bSTobias Grosser const char *cppname = cppstring.c_str(); 1396*e8227804SMichael Kruse std::string ns = isl_namespace(); 1397d169d70bSTobias Grosser 1398*e8227804SMichael Kruse osprintf(os, "\n"); 1399*e8227804SMichael Kruse osprintf(os, "%sctx %s::ctx() const {\n", ns.c_str(), cppname); 1400*e8227804SMichael Kruse osprintf(os, " return %sctx(%s_get_ctx(ptr));\n", ns.c_str(), name); 1401d169d70bSTobias Grosser osprintf(os, "}\n"); 1402d169d70bSTobias Grosser } 1403d169d70bSTobias Grosser 1404*e8227804SMichael Kruse /* Print the implementations of the methods needed for the persistent callbacks 1405*e8227804SMichael Kruse * of "clazz". 1406*e8227804SMichael Kruse */ 1407*e8227804SMichael Kruse void cpp_generator::print_persistent_callbacks_impl(ostream &os, 1408*e8227804SMichael Kruse const isl_class &clazz) 1409*e8227804SMichael Kruse { 1410*e8227804SMichael Kruse std::string cppstring = type2cpp(clazz); 1411*e8227804SMichael Kruse const char *cppname = cppstring.c_str(); 1412*e8227804SMichael Kruse string classname = type2cpp(clazz); 1413*e8227804SMichael Kruse set<FunctionDecl *>::const_iterator in; 1414*e8227804SMichael Kruse const set<FunctionDecl *> &callbacks = clazz.persistent_callbacks; 1415*e8227804SMichael Kruse 1416*e8227804SMichael Kruse if (!clazz.has_persistent_callbacks()) 1417*e8227804SMichael Kruse return; 1418*e8227804SMichael Kruse 1419*e8227804SMichael Kruse osprintf(os, "\n"); 1420*e8227804SMichael Kruse osprintf(os, "%s &%s::copy_callbacks(const %s &obj)\n", 1421*e8227804SMichael Kruse cppname, classname.c_str(), cppname); 1422*e8227804SMichael Kruse osprintf(os, "{\n"); 1423*e8227804SMichael Kruse for (in = callbacks.begin(); in != callbacks.end(); ++in) { 1424*e8227804SMichael Kruse string callback_name = clazz.persistent_callback_name(*in); 1425*e8227804SMichael Kruse 1426*e8227804SMichael Kruse osprintf(os, " %s_data = obj.%s_data;\n", 1427*e8227804SMichael Kruse callback_name.c_str(), callback_name.c_str()); 1428*e8227804SMichael Kruse } 1429*e8227804SMichael Kruse osprintf(os, " return *this;\n"); 1430*e8227804SMichael Kruse osprintf(os, "}\n"); 1431*e8227804SMichael Kruse 1432*e8227804SMichael Kruse for (in = callbacks.begin(); in != callbacks.end(); ++in) { 1433*e8227804SMichael Kruse function_kind kind = function_kind_member_method; 1434*e8227804SMichael Kruse 1435*e8227804SMichael Kruse print_set_persistent_callback(os, clazz, *in, kind); 1436*e8227804SMichael Kruse } 1437*e8227804SMichael Kruse } 1438*e8227804SMichael Kruse 1439d169d70bSTobias Grosser /* Print definitions for methods of class "clazz" to "os". 1440d169d70bSTobias Grosser */ 1441d169d70bSTobias Grosser void cpp_generator::print_methods_impl(ostream &os, const isl_class &clazz) 1442d169d70bSTobias Grosser { 1443*e8227804SMichael Kruse map<string, function_set>::const_iterator it; 1444d169d70bSTobias Grosser 1445*e8227804SMichael Kruse for (it = clazz.methods.begin(); it != clazz.methods.end(); ++it) 14466145b11cSTobias Grosser print_method_group_impl(os, clazz, it->second); 1447d169d70bSTobias Grosser } 1448*e8227804SMichael Kruse 1449*e8227804SMichael Kruse /* Print the definition for a method "method_name" in "clazz" derived 1450*e8227804SMichael Kruse * from "fd", which sets an enum, to "os". 1451*e8227804SMichael Kruse * In particular, the method "method_name" sets the enum to "enum_name". 1452*e8227804SMichael Kruse * 1453*e8227804SMichael Kruse * The last argument of the C function does not appear in the method call, 1454*e8227804SMichael Kruse * but is fixed to "enum_name" instead. 1455*e8227804SMichael Kruse * Other than that, the method printed here is similar to one 1456*e8227804SMichael Kruse * printed by cpp_generator::print_method_impl, except that 1457*e8227804SMichael Kruse * some of the special cases do not occur. 1458*e8227804SMichael Kruse */ 1459*e8227804SMichael Kruse void cpp_generator::print_set_enum_impl(ostream &os, const isl_class &clazz, 1460*e8227804SMichael Kruse FunctionDecl *fd, const string &enum_name, const string &method_name) 1461*e8227804SMichael Kruse { 1462*e8227804SMichael Kruse string c_name = fd->getName(); 1463*e8227804SMichael Kruse int n = fd->getNumParams(); 1464*e8227804SMichael Kruse function_kind kind = function_kind_member_method; 1465*e8227804SMichael Kruse 1466*e8227804SMichael Kruse osprintf(os, "\n"); 1467*e8227804SMichael Kruse print_method_header(os, clazz, fd, method_name, n - 1, false, kind); 1468*e8227804SMichael Kruse osprintf(os, "{\n"); 1469*e8227804SMichael Kruse 1470*e8227804SMichael Kruse print_argument_validity_check(os, fd, kind); 1471*e8227804SMichael Kruse print_save_ctx(os, fd, kind); 1472*e8227804SMichael Kruse print_on_error_continue(os); 1473*e8227804SMichael Kruse 1474*e8227804SMichael Kruse osprintf(os, " auto res = %s(", c_name.c_str()); 1475*e8227804SMichael Kruse 1476*e8227804SMichael Kruse for (int i = 0; i < n - 1; ++i) { 1477*e8227804SMichael Kruse ParmVarDecl *param = fd->getParamDecl(i); 1478*e8227804SMichael Kruse 1479*e8227804SMichael Kruse if (i > 0) 1480*e8227804SMichael Kruse osprintf(os, ", "); 1481*e8227804SMichael Kruse print_method_param_use(os, param, i == 0); 1482*e8227804SMichael Kruse } 1483*e8227804SMichael Kruse osprintf(os, ", %s", enum_name.c_str()); 1484*e8227804SMichael Kruse osprintf(os, ");\n"); 1485*e8227804SMichael Kruse 1486*e8227804SMichael Kruse print_exceptional_execution_check(os, clazz, fd, kind); 1487*e8227804SMichael Kruse print_method_return(os, clazz, fd); 1488*e8227804SMichael Kruse 1489*e8227804SMichael Kruse osprintf(os, "}\n"); 1490*e8227804SMichael Kruse } 1491*e8227804SMichael Kruse 1492*e8227804SMichael Kruse /* Print definitions for the methods in "clazz" derived from "fd", 1493*e8227804SMichael Kruse * which sets an enum, to "os". 1494*e8227804SMichael Kruse * 1495*e8227804SMichael Kruse * A method is generated for each value in the enum, setting 1496*e8227804SMichael Kruse * the enum to that value. 1497*e8227804SMichael Kruse */ 1498*e8227804SMichael Kruse void cpp_generator::print_set_enums_impl(ostream &os, const isl_class &clazz, 1499*e8227804SMichael Kruse FunctionDecl *fd) 1500*e8227804SMichael Kruse { 1501*e8227804SMichael Kruse vector<set_enum>::const_iterator it; 1502*e8227804SMichael Kruse const vector<set_enum> &set_enums = clazz.set_enums.at(fd); 1503*e8227804SMichael Kruse 1504*e8227804SMichael Kruse for (it = set_enums.begin(); it != set_enums.end(); ++it) { 1505*e8227804SMichael Kruse osprintf(os, "\n"); 1506*e8227804SMichael Kruse print_set_enum_impl(os, clazz, fd, it->name, it->method_name); 1507*e8227804SMichael Kruse } 1508*e8227804SMichael Kruse } 1509*e8227804SMichael Kruse 1510*e8227804SMichael Kruse /* Print definitions for methods in "clazz" derived from functions 1511*e8227804SMichael Kruse * that set an enum, to "os". 1512*e8227804SMichael Kruse */ 1513*e8227804SMichael Kruse void cpp_generator::print_set_enums_impl(ostream &os, const isl_class &clazz) 1514*e8227804SMichael Kruse { 1515*e8227804SMichael Kruse map<FunctionDecl *, vector<set_enum> >::const_iterator it; 1516*e8227804SMichael Kruse 1517*e8227804SMichael Kruse for (it = clazz.set_enums.begin(); it != clazz.set_enums.end(); ++it) 1518*e8227804SMichael Kruse print_set_enums_impl(os, clazz, it->first); 1519*e8227804SMichael Kruse } 1520*e8227804SMichael Kruse 1521*e8227804SMichael Kruse /* Print a definition for the "get" method "fd" in class "clazz", 1522*e8227804SMichael Kruse * using a name that includes the "get_" prefix, to "os". 1523*e8227804SMichael Kruse * 1524*e8227804SMichael Kruse * This definition simply calls the variant without the "get_" prefix and 1525*e8227804SMichael Kruse * returns its result. 1526*e8227804SMichael Kruse * Note that static methods are not considered to be "get" methods. 1527*e8227804SMichael Kruse */ 1528*e8227804SMichael Kruse template<> 1529*e8227804SMichael Kruse void cpp_generator::print_get_method<cpp_generator::impl>(ostream &os, 1530*e8227804SMichael Kruse const isl_class &clazz, FunctionDecl *fd) 1531*e8227804SMichael Kruse { 1532*e8227804SMichael Kruse string get_name = clazz.base_method_name(fd); 1533*e8227804SMichael Kruse string name = clazz.method_name(fd); 1534*e8227804SMichael Kruse function_kind kind = function_kind_member_method; 1535*e8227804SMichael Kruse int num_params = fd->getNumParams(); 1536*e8227804SMichael Kruse 1537*e8227804SMichael Kruse osprintf(os, "\n"); 1538*e8227804SMichael Kruse print_named_method_header(os, clazz, fd, get_name, false, kind); 1539*e8227804SMichael Kruse osprintf(os, "{\n"); 1540*e8227804SMichael Kruse osprintf(os, " return %s(", name.c_str()); 1541*e8227804SMichael Kruse for (int i = 1; i < num_params; ++i) { 1542*e8227804SMichael Kruse ParmVarDecl *param = fd->getParamDecl(i); 1543*e8227804SMichael Kruse 1544*e8227804SMichael Kruse if (i != 1) 1545*e8227804SMichael Kruse osprintf(os, ", "); 1546*e8227804SMichael Kruse osprintf(os, "%s", param->getName().str().c_str()); 1547*e8227804SMichael Kruse } 1548*e8227804SMichael Kruse osprintf(os, ");\n"); 1549*e8227804SMichael Kruse osprintf(os, "}\n"); 1550d169d70bSTobias Grosser } 1551d169d70bSTobias Grosser 15526145b11cSTobias Grosser /* Print definitions for methods "methods" in class "clazz" to "os". 1553d169d70bSTobias Grosser */ 1554d169d70bSTobias Grosser void cpp_generator::print_method_group_impl(ostream &os, const isl_class &clazz, 1555*e8227804SMichael Kruse const function_set &methods) 1556d169d70bSTobias Grosser { 1557*e8227804SMichael Kruse function_set::const_iterator it; 1558d169d70bSTobias Grosser 1559*e8227804SMichael Kruse for (it = methods.begin(); it != methods.end(); ++it) 1560*e8227804SMichael Kruse print_method_variants<impl>(os, clazz, *it); 1561d169d70bSTobias Grosser } 1562d169d70bSTobias Grosser 1563d169d70bSTobias Grosser /* Print the use of "param" to "os". 1564d169d70bSTobias Grosser * 1565d169d70bSTobias Grosser * "load_from_this_ptr" specifies whether the parameter should be loaded from 1566d169d70bSTobias Grosser * the this-ptr. In case a value is loaded from a this pointer, the original 1567d169d70bSTobias Grosser * value must be preserved and must consequently be copied. Values that are 1568d169d70bSTobias Grosser * loaded from parameters do not need to be preserved, as such values will 1569d169d70bSTobias Grosser * already be copies of the actual parameters. It is consequently possible 1570d169d70bSTobias Grosser * to directly take the pointer from these values, which saves 1571d169d70bSTobias Grosser * an unnecessary copy. 1572d169d70bSTobias Grosser * 1573d169d70bSTobias Grosser * In case the parameter is a callback function, two parameters get printed, 1574d169d70bSTobias Grosser * a wrapper for the callback function and a pointer to the actual 1575d169d70bSTobias Grosser * callback function. The wrapper is expected to be available 1576d169d70bSTobias Grosser * in a previously declared variable <name>_lambda, while 1577d169d70bSTobias Grosser * the actual callback function is expected to be stored 1578d169d70bSTobias Grosser * in a structure called <name>_data. 1579d169d70bSTobias Grosser * The caller of this function must ensure that these variables exist. 1580d169d70bSTobias Grosser */ 1581d169d70bSTobias Grosser void cpp_generator::print_method_param_use(ostream &os, ParmVarDecl *param, 1582d169d70bSTobias Grosser bool load_from_this_ptr) 1583d169d70bSTobias Grosser { 1584d169d70bSTobias Grosser string name = param->getName().str(); 1585d169d70bSTobias Grosser const char *name_str = name.c_str(); 1586d169d70bSTobias Grosser QualType type = param->getOriginalType(); 1587d169d70bSTobias Grosser 1588d169d70bSTobias Grosser if (type->isIntegerType()) { 1589d169d70bSTobias Grosser osprintf(os, "%s", name_str); 1590d169d70bSTobias Grosser return; 1591d169d70bSTobias Grosser } 1592d169d70bSTobias Grosser 1593d169d70bSTobias Grosser if (is_string(type)) { 1594d169d70bSTobias Grosser osprintf(os, "%s.c_str()", name_str); 1595d169d70bSTobias Grosser return; 1596d169d70bSTobias Grosser } 1597d169d70bSTobias Grosser 1598d169d70bSTobias Grosser if (is_callback(type)) { 1599d169d70bSTobias Grosser osprintf(os, "%s_lambda, ", name_str); 1600d169d70bSTobias Grosser osprintf(os, "&%s_data", name_str); 1601d169d70bSTobias Grosser return; 1602d169d70bSTobias Grosser } 1603d169d70bSTobias Grosser 1604*e8227804SMichael Kruse if (!load_from_this_ptr) 1605d169d70bSTobias Grosser osprintf(os, "%s.", name_str); 1606d169d70bSTobias Grosser 1607d169d70bSTobias Grosser if (keeps(param)) { 1608d169d70bSTobias Grosser osprintf(os, "get()"); 1609d169d70bSTobias Grosser } else { 1610d169d70bSTobias Grosser if (load_from_this_ptr) 1611d169d70bSTobias Grosser osprintf(os, "copy()"); 1612d169d70bSTobias Grosser else 1613d169d70bSTobias Grosser osprintf(os, "release()"); 1614d169d70bSTobias Grosser } 1615d169d70bSTobias Grosser } 1616d169d70bSTobias Grosser 1617d169d70bSTobias Grosser /* Print code that checks that all isl object arguments to "method" are valid 1618d169d70bSTobias Grosser * (not NULL) and throws an exception if they are not. 1619d169d70bSTobias Grosser * "kind" specifies the kind of method that is being generated. 1620d169d70bSTobias Grosser * 1621d169d70bSTobias Grosser * If checked bindings are being generated, 1622d169d70bSTobias Grosser * then no such check is performed. 1623d169d70bSTobias Grosser */ 1624d169d70bSTobias Grosser void cpp_generator::print_argument_validity_check(ostream &os, 1625d169d70bSTobias Grosser FunctionDecl *method, function_kind kind) 1626d169d70bSTobias Grosser { 1627d169d70bSTobias Grosser int n; 1628d169d70bSTobias Grosser bool first = true; 1629d169d70bSTobias Grosser 1630d169d70bSTobias Grosser if (checked) 1631d169d70bSTobias Grosser return; 1632d169d70bSTobias Grosser 1633d169d70bSTobias Grosser n = method->getNumParams(); 1634d169d70bSTobias Grosser for (int i = 0; i < n; ++i) { 1635d169d70bSTobias Grosser bool is_this; 1636d169d70bSTobias Grosser ParmVarDecl *param = method->getParamDecl(i); 1637d169d70bSTobias Grosser string name = param->getName().str(); 1638d169d70bSTobias Grosser const char *name_str = name.c_str(); 1639d169d70bSTobias Grosser QualType type = param->getOriginalType(); 1640d169d70bSTobias Grosser 1641d169d70bSTobias Grosser is_this = i == 0 && kind == function_kind_member_method; 1642d169d70bSTobias Grosser if (!is_this && (is_isl_ctx(type) || !is_isl_type(type))) 1643d169d70bSTobias Grosser continue; 1644d169d70bSTobias Grosser 1645d169d70bSTobias Grosser if (first) 1646d169d70bSTobias Grosser osprintf(os, " if ("); 1647d169d70bSTobias Grosser else 1648d169d70bSTobias Grosser osprintf(os, " || "); 1649d169d70bSTobias Grosser 1650d169d70bSTobias Grosser if (is_this) 1651d169d70bSTobias Grosser osprintf(os, "!ptr"); 1652d169d70bSTobias Grosser else 1653d169d70bSTobias Grosser osprintf(os, "%s.is_null()", name_str); 1654d169d70bSTobias Grosser 1655d169d70bSTobias Grosser first = false; 1656d169d70bSTobias Grosser } 1657d169d70bSTobias Grosser if (first) 1658d169d70bSTobias Grosser return; 1659d169d70bSTobias Grosser osprintf(os, ")\n"); 1660d169d70bSTobias Grosser print_throw_NULL_input(os); 1661d169d70bSTobias Grosser } 1662d169d70bSTobias Grosser 1663d169d70bSTobias Grosser /* Print code for saving a copy of the isl::ctx available at the start 1664*e8227804SMichael Kruse * of the method "method" in a "saved_ctx" variable, 1665*e8227804SMichael Kruse * for use in exception handling. 1666d169d70bSTobias Grosser * "kind" specifies what kind of method "method" is. 1667d169d70bSTobias Grosser * 1668d169d70bSTobias Grosser * If checked bindings are being generated, 1669*e8227804SMichael Kruse * then the "saved_ctx" variable is not needed. 1670d169d70bSTobias Grosser * If "method" is a member function, then obtain the isl_ctx from 1671d169d70bSTobias Grosser * the "this" object. 1672*e8227804SMichael Kruse * If the first argument of the method is an isl::ctx, then use that one. 1673d169d70bSTobias Grosser * Otherwise, save a copy of the isl::ctx associated to the first argument 1674d169d70bSTobias Grosser * of isl object type. 1675d169d70bSTobias Grosser */ 1676d169d70bSTobias Grosser void cpp_generator::print_save_ctx(ostream &os, FunctionDecl *method, 1677d169d70bSTobias Grosser function_kind kind) 1678d169d70bSTobias Grosser { 1679d169d70bSTobias Grosser int n; 1680d169d70bSTobias Grosser ParmVarDecl *param = method->getParamDecl(0); 1681d169d70bSTobias Grosser QualType type = param->getOriginalType(); 1682d169d70bSTobias Grosser 1683d169d70bSTobias Grosser if (checked) 1684d169d70bSTobias Grosser return; 1685d169d70bSTobias Grosser if (kind == function_kind_member_method) { 1686*e8227804SMichael Kruse osprintf(os, " auto saved_ctx = ctx();\n"); 1687d169d70bSTobias Grosser return; 1688d169d70bSTobias Grosser } 1689d169d70bSTobias Grosser if (is_isl_ctx(type)) { 1690d169d70bSTobias Grosser const char *name; 1691d169d70bSTobias Grosser 1692d169d70bSTobias Grosser name = param->getName().str().c_str(); 1693*e8227804SMichael Kruse osprintf(os, " auto saved_ctx = %s;\n", name); 1694d169d70bSTobias Grosser return; 1695d169d70bSTobias Grosser } 1696d169d70bSTobias Grosser n = method->getNumParams(); 1697d169d70bSTobias Grosser for (int i = 0; i < n; ++i) { 1698d169d70bSTobias Grosser ParmVarDecl *param = method->getParamDecl(i); 1699d169d70bSTobias Grosser QualType type = param->getOriginalType(); 1700d169d70bSTobias Grosser 1701d169d70bSTobias Grosser if (!is_isl_type(type)) 1702d169d70bSTobias Grosser continue; 1703*e8227804SMichael Kruse osprintf(os, " auto saved_ctx = %s.ctx();\n", 1704d169d70bSTobias Grosser param->getName().str().c_str()); 1705d169d70bSTobias Grosser return; 1706d169d70bSTobias Grosser } 1707d169d70bSTobias Grosser } 1708d169d70bSTobias Grosser 1709d169d70bSTobias Grosser /* Print code to make isl not print an error message when an error occurs 1710d169d70bSTobias Grosser * within the current scope (if exceptions are available), 1711d169d70bSTobias Grosser * since the error message will be included in the exception. 1712d169d70bSTobias Grosser * If exceptions are not available, then exception::on_error 1713d169d70bSTobias Grosser * is set to ISL_ON_ERROR_ABORT and isl is therefore made to abort instead. 1714d169d70bSTobias Grosser * 1715d169d70bSTobias Grosser * If checked bindings are being generated, 1716d169d70bSTobias Grosser * then leave it to the user to decide what isl should do on error. 1717*e8227804SMichael Kruse * Otherwise, assume that a valid isl::ctx is available 1718*e8227804SMichael Kruse * in the "saved_ctx" variable, 1719d169d70bSTobias Grosser * e.g., through a prior call to print_save_ctx. 1720d169d70bSTobias Grosser */ 1721d169d70bSTobias Grosser void cpp_generator::print_on_error_continue(ostream &os) 1722d169d70bSTobias Grosser { 1723d169d70bSTobias Grosser if (checked) 1724d169d70bSTobias Grosser return; 1725*e8227804SMichael Kruse osprintf(os, " options_scoped_set_on_error saved_on_error(saved_ctx, " 1726d169d70bSTobias Grosser "exception::on_error);\n"); 1727d169d70bSTobias Grosser } 1728d169d70bSTobias Grosser 1729*e8227804SMichael Kruse /* Print code to "os" that checks whether any of the persistent callbacks 1730*e8227804SMichael Kruse * of "clazz" is set and if it failed with an exception. If so, the "eptr" 1731*e8227804SMichael Kruse * in the corresponding data structure contains the exception 1732*e8227804SMichael Kruse * that was caught and that needs to be rethrown. 1733*e8227804SMichael Kruse * This field is cleared because the callback and its data may get reused. 1734*e8227804SMichael Kruse * 1735*e8227804SMichael Kruse * The check only needs to be generated for member methods since 1736*e8227804SMichael Kruse * an object is needed for any of the persistent callbacks to be set. 1737*e8227804SMichael Kruse */ 1738*e8227804SMichael Kruse static void print_persistent_callback_exceptional_execution_check(ostream &os, 1739*e8227804SMichael Kruse const isl_class &clazz, cpp_generator::function_kind kind) 1740*e8227804SMichael Kruse { 1741*e8227804SMichael Kruse const set<FunctionDecl *> &callbacks = clazz.persistent_callbacks; 1742*e8227804SMichael Kruse set<FunctionDecl *>::const_iterator in; 1743*e8227804SMichael Kruse 1744*e8227804SMichael Kruse if (kind != cpp_generator::function_kind_member_method) 1745*e8227804SMichael Kruse return; 1746*e8227804SMichael Kruse 1747*e8227804SMichael Kruse for (in = callbacks.begin(); in != callbacks.end(); ++in) { 1748*e8227804SMichael Kruse string callback_name = clazz.persistent_callback_name(*in); 1749*e8227804SMichael Kruse 1750*e8227804SMichael Kruse osprintf(os, " if (%s_data && %s_data->eptr) {\n", 1751*e8227804SMichael Kruse callback_name.c_str(), callback_name.c_str()); 1752*e8227804SMichael Kruse osprintf(os, " std::exception_ptr eptr = %s_data->eptr;\n", 1753*e8227804SMichael Kruse callback_name.c_str()); 1754*e8227804SMichael Kruse osprintf(os, " %s_data->eptr = nullptr;\n", 1755*e8227804SMichael Kruse callback_name.c_str()); 1756*e8227804SMichael Kruse osprintf(os, " std::rethrow_exception(eptr);\n"); 1757*e8227804SMichael Kruse osprintf(os, " }\n"); 1758*e8227804SMichael Kruse } 1759*e8227804SMichael Kruse } 1760*e8227804SMichael Kruse 1761d169d70bSTobias Grosser /* Print code that checks whether the execution of the core of "method" 1762*e8227804SMichael Kruse * of class "clazz" was successful. 1763*e8227804SMichael Kruse * "kind" specifies what kind of method "method" is. 1764d169d70bSTobias Grosser * 1765d169d70bSTobias Grosser * If checked bindings are being generated, 1766d169d70bSTobias Grosser * then no checks are performed. 1767d169d70bSTobias Grosser * 1768d169d70bSTobias Grosser * Otherwise, first check if any of the callbacks failed with 1769d169d70bSTobias Grosser * an exception. If so, the "eptr" in the corresponding data structure 1770d169d70bSTobias Grosser * contains the exception that was caught and that needs to be rethrown. 1771d169d70bSTobias Grosser * Then check if the function call failed in any other way and throw 1772d169d70bSTobias Grosser * the appropriate exception. 1773*e8227804SMichael Kruse * In particular, if the return type is isl_stat, isl_bool or isl_size, 1774d169d70bSTobias Grosser * then a negative value indicates a failure. If the return type 1775d169d70bSTobias Grosser * is an isl type, then a NULL value indicates a failure. 1776d169d70bSTobias Grosser * Assume print_save_ctx has made sure that a valid isl::ctx 1777d169d70bSTobias Grosser * is available in the "ctx" variable. 1778d169d70bSTobias Grosser */ 1779d169d70bSTobias Grosser void cpp_generator::print_exceptional_execution_check(ostream &os, 1780*e8227804SMichael Kruse const isl_class &clazz, FunctionDecl *method, function_kind kind) 1781d169d70bSTobias Grosser { 1782d169d70bSTobias Grosser int n; 1783d169d70bSTobias Grosser bool check_null, check_neg; 1784d169d70bSTobias Grosser QualType return_type = method->getReturnType(); 1785d169d70bSTobias Grosser 1786d169d70bSTobias Grosser if (checked) 1787d169d70bSTobias Grosser return; 1788d169d70bSTobias Grosser 1789*e8227804SMichael Kruse print_persistent_callback_exceptional_execution_check(os, clazz, kind); 1790*e8227804SMichael Kruse 1791d169d70bSTobias Grosser n = method->getNumParams(); 1792d169d70bSTobias Grosser for (int i = 0; i < n; ++i) { 1793d169d70bSTobias Grosser ParmVarDecl *param = method->getParamDecl(i); 1794d169d70bSTobias Grosser const char *name; 1795d169d70bSTobias Grosser 1796d169d70bSTobias Grosser if (!is_callback(param->getOriginalType())) 1797d169d70bSTobias Grosser continue; 1798d169d70bSTobias Grosser name = param->getName().str().c_str(); 1799d169d70bSTobias Grosser osprintf(os, " if (%s_data.eptr)\n", name); 1800d169d70bSTobias Grosser osprintf(os, " std::rethrow_exception(%s_data.eptr);\n", 1801d169d70bSTobias Grosser name); 1802d169d70bSTobias Grosser } 1803d169d70bSTobias Grosser 1804*e8227804SMichael Kruse check_neg = is_isl_neg_error(return_type); 1805d169d70bSTobias Grosser check_null = is_isl_type(return_type); 1806d169d70bSTobias Grosser if (!check_null && !check_neg) 1807d169d70bSTobias Grosser return; 1808d169d70bSTobias Grosser 1809d169d70bSTobias Grosser if (check_neg) 1810d169d70bSTobias Grosser osprintf(os, " if (res < 0)\n"); 1811d169d70bSTobias Grosser else 1812d169d70bSTobias Grosser osprintf(os, " if (!res)\n"); 1813d169d70bSTobias Grosser print_throw_last_error(os); 1814d169d70bSTobias Grosser } 1815d169d70bSTobias Grosser 1816*e8227804SMichael Kruse /* Does "fd" modify an object of a subclass based on a type function? 1817*e8227804SMichael Kruse */ 1818*e8227804SMichael Kruse static bool is_subclass_mutator(const isl_class &clazz, FunctionDecl *fd) 1819*e8227804SMichael Kruse { 1820*e8227804SMichael Kruse return clazz.is_type_subclass() && generator::is_mutator(clazz, fd); 1821*e8227804SMichael Kruse } 1822*e8227804SMichael Kruse 1823*e8227804SMichael Kruse /* Return the C++ return type of the method corresponding to "fd" in "clazz". 1824*e8227804SMichael Kruse * 1825*e8227804SMichael Kruse * If "fd" modifies an object of a subclass, then return 1826*e8227804SMichael Kruse * the type of this subclass. 1827*e8227804SMichael Kruse * Otherwise, return the C++ counterpart of the actual return type. 1828*e8227804SMichael Kruse */ 1829*e8227804SMichael Kruse std::string cpp_generator::get_return_type(const isl_class &clazz, 1830*e8227804SMichael Kruse FunctionDecl *fd) 1831*e8227804SMichael Kruse { 1832*e8227804SMichael Kruse if (is_subclass_mutator(clazz, fd)) 1833*e8227804SMichael Kruse return type2cpp(clazz); 1834*e8227804SMichael Kruse else 1835*e8227804SMichael Kruse return type2cpp(fd->getReturnType()); 1836*e8227804SMichael Kruse } 1837*e8227804SMichael Kruse 1838*e8227804SMichael Kruse /* Given a function "method" for setting a "clazz" persistent callback, 1839*e8227804SMichael Kruse * print the implementations of the methods needed for that callback. 1840*e8227804SMichael Kruse * 1841*e8227804SMichael Kruse * In particular, print 1842*e8227804SMichael Kruse * - the implementation of a static inline method 1843*e8227804SMichael Kruse * for use as the C callback function 1844*e8227804SMichael Kruse * - the definition of a private method for setting the callback function 1845*e8227804SMichael Kruse * - the public method for constructing a new object with the callback set. 1846*e8227804SMichael Kruse */ 1847*e8227804SMichael Kruse void cpp_generator::print_set_persistent_callback(ostream &os, 1848*e8227804SMichael Kruse const isl_class &clazz, FunctionDecl *method, 1849*e8227804SMichael Kruse function_kind kind) 1850*e8227804SMichael Kruse { 1851*e8227804SMichael Kruse string fullname = method->getName(); 1852*e8227804SMichael Kruse ParmVarDecl *param = persistent_callback_arg(method); 1853*e8227804SMichael Kruse string classname = type2cpp(clazz); 1854*e8227804SMichael Kruse string pname; 1855*e8227804SMichael Kruse string callback_name = clazz.persistent_callback_name(method); 1856*e8227804SMichael Kruse 1857*e8227804SMichael Kruse osprintf(os, "\n"); 1858*e8227804SMichael Kruse print_persistent_callback_prototype(os, clazz, method, false); 1859*e8227804SMichael Kruse osprintf(os, "\n"); 1860*e8227804SMichael Kruse osprintf(os, "{\n"); 1861*e8227804SMichael Kruse print_callback_body(os, 2, param, callback_name); 1862*e8227804SMichael Kruse osprintf(os, "}\n\n"); 1863*e8227804SMichael Kruse 1864*e8227804SMichael Kruse pname = param->getName().str(); 1865*e8227804SMichael Kruse print_persistent_callback_setter_prototype(os, clazz, method, false); 1866*e8227804SMichael Kruse osprintf(os, "\n"); 1867*e8227804SMichael Kruse osprintf(os, "{\n"); 1868*e8227804SMichael Kruse print_check_ptr_start(os, clazz, "ptr"); 1869*e8227804SMichael Kruse osprintf(os, " %s_data = std::make_shared<struct %s_data>();\n", 1870*e8227804SMichael Kruse callback_name.c_str(), callback_name.c_str()); 1871*e8227804SMichael Kruse osprintf(os, " %s_data->func = %s;\n", 1872*e8227804SMichael Kruse callback_name.c_str(), pname.c_str()); 1873*e8227804SMichael Kruse osprintf(os, " ptr = %s(ptr, &%s, %s_data.get());\n", 1874*e8227804SMichael Kruse fullname.c_str(), callback_name.c_str(), callback_name.c_str()); 1875*e8227804SMichael Kruse print_check_ptr_end(os, "ptr"); 1876*e8227804SMichael Kruse osprintf(os, "}\n\n"); 1877*e8227804SMichael Kruse 1878*e8227804SMichael Kruse print_method_header(os, clazz, method, false, kind); 1879*e8227804SMichael Kruse osprintf(os, "{\n"); 1880*e8227804SMichael Kruse osprintf(os, " auto copy = *this;\n"); 1881*e8227804SMichael Kruse osprintf(os, " copy.set_%s_data(%s);\n", 1882*e8227804SMichael Kruse callback_name.c_str(), pname.c_str()); 1883*e8227804SMichael Kruse osprintf(os, " return copy;\n"); 1884*e8227804SMichael Kruse osprintf(os, "}\n"); 1885*e8227804SMichael Kruse } 1886*e8227804SMichael Kruse 188726269d34STobias Grosser /* Print the return statement of the C++ method corresponding 188826269d34STobias Grosser * to the C function "method" in class "clazz" to "os". 1889d169d70bSTobias Grosser * 189026269d34STobias Grosser * The result of the isl function is returned as a new 1891d169d70bSTobias Grosser * object if the underlying isl function returns an isl_* ptr, as a bool 1892d169d70bSTobias Grosser * if the isl function returns an isl_bool, as void if the isl functions 1893d169d70bSTobias Grosser * returns an isl_stat, 1894d169d70bSTobias Grosser * as std::string if the isl function returns 'const char *', and as 1895d169d70bSTobias Grosser * unmodified return value otherwise. 1896d169d70bSTobias Grosser * If checked C++ bindings are being generated, 1897d169d70bSTobias Grosser * then an isl_bool return type is transformed into a boolean and 1898d169d70bSTobias Grosser * an isl_stat into a stat since no exceptions can be generated 1899d169d70bSTobias Grosser * on negative results from the isl function. 1900*e8227804SMichael Kruse * If the method returns a new instance of the same object type and 1901*e8227804SMichael Kruse * if the class has any persistent callbacks, then the data 1902*e8227804SMichael Kruse * for these callbacks are copied from the original to the new object. 1903*e8227804SMichael Kruse * If "clazz" is a subclass that is based on a type function and 1904*e8227804SMichael Kruse * if the return type corresponds to the superclass data type, 1905*e8227804SMichael Kruse * then it is replaced by the subclass data type. 190626269d34STobias Grosser */ 190726269d34STobias Grosser void cpp_generator::print_method_return(ostream &os, const isl_class &clazz, 190826269d34STobias Grosser FunctionDecl *method) 190926269d34STobias Grosser { 191026269d34STobias Grosser QualType return_type = method->getReturnType(); 1911*e8227804SMichael Kruse string rettype_str = get_return_type(clazz, method); 1912*e8227804SMichael Kruse bool returns_super = is_subclass_mutator(clazz, method); 191326269d34STobias Grosser 191426269d34STobias Grosser if (is_isl_type(return_type) || 1915*e8227804SMichael Kruse (checked && is_isl_neg_error(return_type))) { 1916*e8227804SMichael Kruse osprintf(os, " return manage(res)"); 1917*e8227804SMichael Kruse if (is_mutator(clazz, method) && 1918*e8227804SMichael Kruse clazz.has_persistent_callbacks()) 1919*e8227804SMichael Kruse osprintf(os, ".copy_callbacks(*this)"); 1920*e8227804SMichael Kruse if (returns_super) 1921*e8227804SMichael Kruse osprintf(os, ".as<%s>()", rettype_str.c_str()); 1922*e8227804SMichael Kruse osprintf(os, ";\n"); 192326269d34STobias Grosser } else if (is_isl_stat(return_type)) { 192426269d34STobias Grosser osprintf(os, " return;\n"); 192526269d34STobias Grosser } else if (is_string(return_type)) { 192626269d34STobias Grosser osprintf(os, " std::string tmp(res);\n"); 192726269d34STobias Grosser if (gives(method)) 192826269d34STobias Grosser osprintf(os, " free(res);\n"); 192926269d34STobias Grosser osprintf(os, " return tmp;\n"); 193026269d34STobias Grosser } else { 193126269d34STobias Grosser osprintf(os, " return res;\n"); 193226269d34STobias Grosser } 193326269d34STobias Grosser } 193426269d34STobias Grosser 1935*e8227804SMichael Kruse /* Return the formal parameter at position "pos" of "fd". 1936*e8227804SMichael Kruse * However, if this parameter should be converted, as indicated 1937*e8227804SMichael Kruse * by "convert", then return the second formal parameter 1938*e8227804SMichael Kruse * of the conversion function instead. 193926269d34STobias Grosser * 1940*e8227804SMichael Kruse * If "convert" is empty, then it is assumed that 1941*e8227804SMichael Kruse * none of the arguments should be converted. 1942d169d70bSTobias Grosser */ 1943*e8227804SMichael Kruse ParmVarDecl *cpp_generator::get_param(FunctionDecl *fd, int pos, 1944*e8227804SMichael Kruse const std::vector<bool> &convert) 1945d169d70bSTobias Grosser { 1946*e8227804SMichael Kruse ParmVarDecl *param = fd->getParamDecl(pos); 1947d169d70bSTobias Grosser 1948*e8227804SMichael Kruse if (convert.size() == 0) 1949*e8227804SMichael Kruse return param; 1950*e8227804SMichael Kruse if (!convert[pos]) 1951*e8227804SMichael Kruse return param; 1952*e8227804SMichael Kruse return conversions[param->getOriginalType().getTypePtr()]; 1953d169d70bSTobias Grosser } 1954d169d70bSTobias Grosser 1955*e8227804SMichael Kruse /* Print the header for "method" in class "clazz", with name "cname" and 1956*e8227804SMichael Kruse * "num_params" number of arguments, to "os". 1957d169d70bSTobias Grosser * 1958d169d70bSTobias Grosser * Print the header of a declaration if "is_declaration" is set, otherwise print 1959d169d70bSTobias Grosser * the header of a method definition. 1960d169d70bSTobias Grosser * 1961d169d70bSTobias Grosser * "kind" specifies the kind of method that should be generated. 1962d169d70bSTobias Grosser * 1963*e8227804SMichael Kruse * "convert" specifies which of the method arguments should 1964*e8227804SMichael Kruse * be automatically converted. 1965*e8227804SMichael Kruse * 1966d169d70bSTobias Grosser * This function prints headers for member methods, static methods, and 1967d169d70bSTobias Grosser * constructors, either for their declaration or definition. 1968d169d70bSTobias Grosser * 1969d169d70bSTobias Grosser * Member functions are declared as "const", as they do not change the current 1970d169d70bSTobias Grosser * object, but instead create a new object. They always retrieve the first 1971d169d70bSTobias Grosser * parameter of the original isl function from the this-pointer of the object, 1972d169d70bSTobias Grosser * such that only starting at the second parameter the parameters of the 1973d169d70bSTobias Grosser * original function become part of the method's interface. 1974d169d70bSTobias Grosser * 1975d169d70bSTobias Grosser * A function 1976d169d70bSTobias Grosser * 1977d169d70bSTobias Grosser * __isl_give isl_set *isl_set_intersect(__isl_take isl_set *s1, 1978d169d70bSTobias Grosser * __isl_take isl_set *s2); 1979d169d70bSTobias Grosser * 1980d169d70bSTobias Grosser * is translated into: 1981d169d70bSTobias Grosser * 1982d169d70bSTobias Grosser * inline set intersect(set set2) const; 1983d169d70bSTobias Grosser * 1984d169d70bSTobias Grosser * For static functions and constructors all parameters of the original isl 1985d169d70bSTobias Grosser * function are exposed. 1986d169d70bSTobias Grosser * 1987d169d70bSTobias Grosser * Parameters that are defined as __isl_keep or are of type string, are passed 1988d169d70bSTobias Grosser * as const reference, which allows the compiler to optimize the parameter 1989d169d70bSTobias Grosser * transfer. 1990d169d70bSTobias Grosser * 1991d169d70bSTobias Grosser * Constructors are marked as explicit using the C++ keyword 'explicit' or as 1992d169d70bSTobias Grosser * implicit using a comment in place of the explicit keyword. By annotating 1993d169d70bSTobias Grosser * implicit constructors with a comment, users of the interface are made 1994d169d70bSTobias Grosser * aware of the potential danger that implicit construction is possible 1995d169d70bSTobias Grosser * for these constructors, whereas without a comment not every user would 1996d169d70bSTobias Grosser * know that implicit construction is allowed in absence of an explicit keyword. 1997*e8227804SMichael Kruse * 1998*e8227804SMichael Kruse * If any of the arguments needs to be converted, then the argument 1999*e8227804SMichael Kruse * of the method is changed to that of the source of the conversion. 2000*e8227804SMichael Kruse * The name of the argument is, however, derived from the original 2001*e8227804SMichael Kruse * function argument. 2002d169d70bSTobias Grosser */ 2003d169d70bSTobias Grosser void cpp_generator::print_method_header(ostream &os, const isl_class &clazz, 2004*e8227804SMichael Kruse FunctionDecl *method, const string &cname, int num_params, 2005*e8227804SMichael Kruse bool is_declaration, function_kind kind, 2006*e8227804SMichael Kruse const std::vector<bool> &convert) 2007d169d70bSTobias Grosser { 2008*e8227804SMichael Kruse string rettype_str = get_return_type(clazz, method); 2009d169d70bSTobias Grosser string classname = type2cpp(clazz); 2010d169d70bSTobias Grosser int first_param = 0; 2011d169d70bSTobias Grosser 2012d169d70bSTobias Grosser if (kind == function_kind_member_method) 2013d169d70bSTobias Grosser first_param = 1; 2014d169d70bSTobias Grosser 2015d169d70bSTobias Grosser if (is_declaration) { 2016d169d70bSTobias Grosser osprintf(os, " "); 2017d169d70bSTobias Grosser 2018d169d70bSTobias Grosser if (kind == function_kind_static_method) 2019d169d70bSTobias Grosser osprintf(os, "static "); 2020d169d70bSTobias Grosser 2021d169d70bSTobias Grosser osprintf(os, "inline "); 2022d169d70bSTobias Grosser 2023d169d70bSTobias Grosser if (kind == function_kind_constructor) { 2024d169d70bSTobias Grosser if (is_implicit_conversion(clazz, method)) 2025d169d70bSTobias Grosser osprintf(os, "/* implicit */ "); 2026d169d70bSTobias Grosser else 2027d169d70bSTobias Grosser osprintf(os, "explicit "); 2028d169d70bSTobias Grosser } 2029d169d70bSTobias Grosser } 2030d169d70bSTobias Grosser 2031d169d70bSTobias Grosser if (kind != function_kind_constructor) 2032d169d70bSTobias Grosser osprintf(os, "%s ", rettype_str.c_str()); 2033d169d70bSTobias Grosser 2034d169d70bSTobias Grosser if (!is_declaration) 2035d169d70bSTobias Grosser osprintf(os, "%s::", classname.c_str()); 2036d169d70bSTobias Grosser 2037d169d70bSTobias Grosser if (kind != function_kind_constructor) 2038d169d70bSTobias Grosser osprintf(os, "%s", cname.c_str()); 2039d169d70bSTobias Grosser else 2040d169d70bSTobias Grosser osprintf(os, "%s", classname.c_str()); 2041d169d70bSTobias Grosser 2042d169d70bSTobias Grosser osprintf(os, "("); 2043d169d70bSTobias Grosser 2044d169d70bSTobias Grosser for (int i = first_param; i < num_params; ++i) { 2045*e8227804SMichael Kruse std::string name = method->getParamDecl(i)->getName().str(); 2046*e8227804SMichael Kruse ParmVarDecl *param = get_param(method, i, convert); 2047d169d70bSTobias Grosser QualType type = param->getOriginalType(); 2048d169d70bSTobias Grosser string cpptype = type2cpp(type); 2049d169d70bSTobias Grosser 2050d169d70bSTobias Grosser if (is_callback(type)) 2051d169d70bSTobias Grosser num_params--; 2052d169d70bSTobias Grosser 2053d169d70bSTobias Grosser if (keeps(param) || is_string(type) || is_callback(type)) 2054d169d70bSTobias Grosser osprintf(os, "const %s &%s", cpptype.c_str(), 2055*e8227804SMichael Kruse name.c_str()); 2056d169d70bSTobias Grosser else 2057*e8227804SMichael Kruse osprintf(os, "%s %s", cpptype.c_str(), name.c_str()); 2058d169d70bSTobias Grosser 2059d169d70bSTobias Grosser if (i != num_params - 1) 2060d169d70bSTobias Grosser osprintf(os, ", "); 2061d169d70bSTobias Grosser } 2062d169d70bSTobias Grosser 2063d169d70bSTobias Grosser osprintf(os, ")"); 2064d169d70bSTobias Grosser 2065d169d70bSTobias Grosser if (kind == function_kind_member_method) 2066d169d70bSTobias Grosser osprintf(os, " const"); 2067d169d70bSTobias Grosser 2068d169d70bSTobias Grosser if (is_declaration) 2069d169d70bSTobias Grosser osprintf(os, ";"); 2070d169d70bSTobias Grosser osprintf(os, "\n"); 2071d169d70bSTobias Grosser } 2072d169d70bSTobias Grosser 2073*e8227804SMichael Kruse /* Print the header for a method called "name" in class "clazz" 2074*e8227804SMichael Kruse * derived from "method" to "os". 2075*e8227804SMichael Kruse * 2076*e8227804SMichael Kruse * Print the header of a declaration if "is_declaration" is set, otherwise print 2077*e8227804SMichael Kruse * the header of a method definition. 2078*e8227804SMichael Kruse * 2079*e8227804SMichael Kruse * "kind" specifies the kind of method that should be generated. 2080*e8227804SMichael Kruse * 2081*e8227804SMichael Kruse * "convert" specifies which of the method arguments should 2082*e8227804SMichael Kruse * be automatically converted. 2083*e8227804SMichael Kruse */ 2084*e8227804SMichael Kruse void cpp_generator::print_named_method_header(ostream &os, 2085*e8227804SMichael Kruse const isl_class &clazz, FunctionDecl *method, string name, 2086*e8227804SMichael Kruse bool is_declaration, function_kind kind, 2087*e8227804SMichael Kruse const std::vector<bool> &convert) 2088*e8227804SMichael Kruse { 2089*e8227804SMichael Kruse int num_params = method->getNumParams(); 2090*e8227804SMichael Kruse 2091*e8227804SMichael Kruse name = rename_method(name); 2092*e8227804SMichael Kruse print_method_header(os, clazz, method, name, num_params, 2093*e8227804SMichael Kruse is_declaration, kind, convert); 2094*e8227804SMichael Kruse } 2095*e8227804SMichael Kruse 2096*e8227804SMichael Kruse /* Print the header for "method" in class "clazz" to "os" 2097*e8227804SMichael Kruse * using its default name. 2098*e8227804SMichael Kruse * 2099*e8227804SMichael Kruse * Print the header of a declaration if "is_declaration" is set, otherwise print 2100*e8227804SMichael Kruse * the header of a method definition. 2101*e8227804SMichael Kruse * 2102*e8227804SMichael Kruse * "kind" specifies the kind of method that should be generated. 2103*e8227804SMichael Kruse */ 2104*e8227804SMichael Kruse void cpp_generator::print_method_header(ostream &os, const isl_class &clazz, 2105*e8227804SMichael Kruse FunctionDecl *method, bool is_declaration, function_kind kind) 2106*e8227804SMichael Kruse { 2107*e8227804SMichael Kruse string name = clazz.method_name(method); 2108*e8227804SMichael Kruse 2109*e8227804SMichael Kruse print_named_method_header(os, clazz, method, name, is_declaration, 2110*e8227804SMichael Kruse kind); 2111*e8227804SMichael Kruse } 2112*e8227804SMichael Kruse 2113d169d70bSTobias Grosser /* Generate the list of argument types for a callback function of 2114d169d70bSTobias Grosser * type "type". If "cpp" is set, then generate the C++ type list, otherwise 2115d169d70bSTobias Grosser * the C type list. 2116d169d70bSTobias Grosser * 2117d169d70bSTobias Grosser * For a callback of type 2118d169d70bSTobias Grosser * 2119d169d70bSTobias Grosser * isl_stat (*)(__isl_take isl_map *map, void *user) 2120d169d70bSTobias Grosser * 2121d169d70bSTobias Grosser * the following C++ argument list is generated: 2122d169d70bSTobias Grosser * 2123d169d70bSTobias Grosser * map 2124d169d70bSTobias Grosser */ 2125d169d70bSTobias Grosser string cpp_generator::generate_callback_args(QualType type, bool cpp) 2126d169d70bSTobias Grosser { 2127d169d70bSTobias Grosser std::string type_str; 2128d169d70bSTobias Grosser const FunctionProtoType *callback; 2129d169d70bSTobias Grosser int num_params; 2130d169d70bSTobias Grosser 213126269d34STobias Grosser callback = extract_prototype(type); 2132d169d70bSTobias Grosser num_params = callback->getNumArgs(); 2133d169d70bSTobias Grosser if (cpp) 2134d169d70bSTobias Grosser num_params--; 2135d169d70bSTobias Grosser 2136d169d70bSTobias Grosser for (long i = 0; i < num_params; i++) { 2137d169d70bSTobias Grosser QualType type = callback->getArgType(i); 2138d169d70bSTobias Grosser 2139d169d70bSTobias Grosser if (cpp) 2140d169d70bSTobias Grosser type_str += type2cpp(type); 2141d169d70bSTobias Grosser else 2142d169d70bSTobias Grosser type_str += type.getAsString(); 2143d169d70bSTobias Grosser 2144d169d70bSTobias Grosser if (!cpp) 2145d169d70bSTobias Grosser type_str += "arg_" + ::to_string(i); 2146d169d70bSTobias Grosser 2147d169d70bSTobias Grosser if (i != num_params - 1) 2148d169d70bSTobias Grosser type_str += ", "; 2149d169d70bSTobias Grosser } 2150d169d70bSTobias Grosser 2151d169d70bSTobias Grosser return type_str; 2152d169d70bSTobias Grosser } 2153d169d70bSTobias Grosser 2154d169d70bSTobias Grosser /* Generate the full cpp type of a callback function of type "type". 2155d169d70bSTobias Grosser * 2156d169d70bSTobias Grosser * For a callback of type 2157d169d70bSTobias Grosser * 2158d169d70bSTobias Grosser * isl_stat (*)(__isl_take isl_map *map, void *user) 2159d169d70bSTobias Grosser * 2160d169d70bSTobias Grosser * the following type is generated: 2161d169d70bSTobias Grosser * 2162d169d70bSTobias Grosser * std::function<stat(map)> 2163d169d70bSTobias Grosser */ 2164d169d70bSTobias Grosser string cpp_generator::generate_callback_type(QualType type) 2165d169d70bSTobias Grosser { 2166d169d70bSTobias Grosser std::string type_str; 216726269d34STobias Grosser const FunctionProtoType *callback = extract_prototype(type); 2168d169d70bSTobias Grosser QualType return_type = callback->getReturnType(); 2169d169d70bSTobias Grosser string rettype_str = type2cpp(return_type); 2170d169d70bSTobias Grosser 2171d169d70bSTobias Grosser type_str = "std::function<"; 2172d169d70bSTobias Grosser type_str += rettype_str; 2173d169d70bSTobias Grosser type_str += "("; 2174d169d70bSTobias Grosser type_str += generate_callback_args(type, true); 2175d169d70bSTobias Grosser type_str += ")>"; 2176d169d70bSTobias Grosser 2177d169d70bSTobias Grosser return type_str; 2178d169d70bSTobias Grosser } 2179d169d70bSTobias Grosser 2180*e8227804SMichael Kruse /* Print the call to the C++ callback function "call", 2181*e8227804SMichael Kruse * with the given indentation, wrapped 2182d169d70bSTobias Grosser * for use inside the lambda function that is used as the C callback function, 2183d169d70bSTobias Grosser * in the case where checked C++ bindings are being generated. 2184d169d70bSTobias Grosser * 2185d169d70bSTobias Grosser * In particular, print 2186d169d70bSTobias Grosser * 2187*e8227804SMichael Kruse * auto ret = @call@; 2188d169d70bSTobias Grosser * return ret.release(); 2189d169d70bSTobias Grosser */ 2190*e8227804SMichael Kruse void cpp_generator::print_wrapped_call_checked(ostream &os, int indent, 2191d169d70bSTobias Grosser const string &call) 2192d169d70bSTobias Grosser { 2193*e8227804SMichael Kruse osprintf(os, indent, "auto ret = %s;\n", call.c_str()); 2194*e8227804SMichael Kruse osprintf(os, indent, "return ret.release();\n"); 2195d169d70bSTobias Grosser } 2196d169d70bSTobias Grosser 2197*e8227804SMichael Kruse /* Print the call to the C++ callback function "call", 2198*e8227804SMichael Kruse * with the given indentation and with return type "rtype", wrapped 2199d169d70bSTobias Grosser * for use inside the lambda function that is used as the C callback function. 2200d169d70bSTobias Grosser * 2201d169d70bSTobias Grosser * In particular, print 2202d169d70bSTobias Grosser * 2203d169d70bSTobias Grosser * ISL_CPP_TRY { 2204d169d70bSTobias Grosser * @call@; 2205d169d70bSTobias Grosser * return isl_stat_ok; 2206d169d70bSTobias Grosser * } ISL_CPP_CATCH_ALL { 2207d169d70bSTobias Grosser * data->eptr = std::current_exception(); 2208d169d70bSTobias Grosser * return isl_stat_error; 2209d169d70bSTobias Grosser * } 2210*e8227804SMichael Kruse * or 2211*e8227804SMichael Kruse * ISL_CPP_TRY { 2212*e8227804SMichael Kruse * auto ret = @call@; 2213*e8227804SMichael Kruse * return ret ? isl_bool_true : isl_bool_false; 2214*e8227804SMichael Kruse * } ISL_CPP_CATCH_ALL { 2215*e8227804SMichael Kruse * data->eptr = std::current_exception(); 2216*e8227804SMichael Kruse * return isl_bool_error; 2217*e8227804SMichael Kruse * } 2218*e8227804SMichael Kruse * or 2219*e8227804SMichael Kruse * ISL_CPP_TRY { 2220*e8227804SMichael Kruse * auto ret = @call@; 2221*e8227804SMichael Kruse * return ret.release(); 2222*e8227804SMichael Kruse * } ISL_CPP_CATCH_ALL { 2223*e8227804SMichael Kruse * data->eptr = std::current_exception(); 2224*e8227804SMichael Kruse * return NULL; 2225*e8227804SMichael Kruse * } 2226*e8227804SMichael Kruse * 2227*e8227804SMichael Kruse * depending on the return type. 2228d169d70bSTobias Grosser * 2229d169d70bSTobias Grosser * where ISL_CPP_TRY is defined to "try" and ISL_CPP_CATCH_ALL to "catch (...)" 2230d169d70bSTobias Grosser * (if exceptions are available). 2231d169d70bSTobias Grosser * 2232d169d70bSTobias Grosser * If checked C++ bindings are being generated, then 2233d169d70bSTobias Grosser * the call is wrapped differently. 2234d169d70bSTobias Grosser */ 2235*e8227804SMichael Kruse void cpp_generator::print_wrapped_call(ostream &os, int indent, 2236*e8227804SMichael Kruse const string &call, QualType rtype) 2237d169d70bSTobias Grosser { 2238d169d70bSTobias Grosser if (checked) 2239*e8227804SMichael Kruse return print_wrapped_call_checked(os, indent, call); 2240d169d70bSTobias Grosser 2241*e8227804SMichael Kruse osprintf(os, indent, "ISL_CPP_TRY {\n"); 2242*e8227804SMichael Kruse if (is_isl_stat(rtype)) 2243*e8227804SMichael Kruse osprintf(os, indent, " %s;\n", call.c_str()); 2244*e8227804SMichael Kruse else 2245*e8227804SMichael Kruse osprintf(os, indent, " auto ret = %s;\n", call.c_str()); 2246*e8227804SMichael Kruse if (is_isl_stat(rtype)) 2247*e8227804SMichael Kruse osprintf(os, indent, " return isl_stat_ok;\n"); 2248*e8227804SMichael Kruse else if (is_isl_bool(rtype)) 2249*e8227804SMichael Kruse osprintf(os, indent, 2250*e8227804SMichael Kruse " return ret ? isl_bool_true : isl_bool_false;\n"); 2251*e8227804SMichael Kruse else 2252*e8227804SMichael Kruse osprintf(os, indent, " return ret.release();\n"); 2253*e8227804SMichael Kruse osprintf(os, indent, "} ISL_CPP_CATCH_ALL {\n"); 2254*e8227804SMichael Kruse osprintf(os, indent, " data->eptr = std::current_exception();\n"); 2255*e8227804SMichael Kruse if (is_isl_stat(rtype)) 2256*e8227804SMichael Kruse osprintf(os, indent, " return isl_stat_error;\n"); 2257*e8227804SMichael Kruse else if (is_isl_bool(rtype)) 2258*e8227804SMichael Kruse osprintf(os, indent, " return isl_bool_error;\n"); 2259*e8227804SMichael Kruse else 2260*e8227804SMichael Kruse osprintf(os, indent, " return NULL;\n"); 2261*e8227804SMichael Kruse osprintf(os, indent, "}\n"); 2262*e8227804SMichael Kruse } 2263*e8227804SMichael Kruse 2264*e8227804SMichael Kruse /* Print the declaration for a "prefix"_data data structure 2265*e8227804SMichael Kruse * that can be used for passing to a C callback function 2266*e8227804SMichael Kruse * containing a copy of the C++ callback function "param", 2267*e8227804SMichael Kruse * along with an std::exception_ptr that is used to store any 2268*e8227804SMichael Kruse * exceptions thrown in the C++ callback. 2269*e8227804SMichael Kruse * 2270*e8227804SMichael Kruse * If the C callback is of the form 2271*e8227804SMichael Kruse * 2272*e8227804SMichael Kruse * isl_stat (*fn)(__isl_take isl_map *map, void *user) 2273*e8227804SMichael Kruse * 2274*e8227804SMichael Kruse * then the following declaration is printed: 2275*e8227804SMichael Kruse * 2276*e8227804SMichael Kruse * struct <prefix>_data { 2277*e8227804SMichael Kruse * std::function<stat(map)> func; 2278*e8227804SMichael Kruse * std::exception_ptr eptr; 2279*e8227804SMichael Kruse * } 2280*e8227804SMichael Kruse * 2281*e8227804SMichael Kruse * (without a newline or a semicolon). 2282*e8227804SMichael Kruse * 2283*e8227804SMichael Kruse * The std::exception_ptr object is not added to "prefix"_data 2284*e8227804SMichael Kruse * if checked C++ bindings are being generated. 2285*e8227804SMichael Kruse */ 2286*e8227804SMichael Kruse void cpp_generator::print_callback_data_decl(ostream &os, ParmVarDecl *param, 2287*e8227804SMichael Kruse const string &prefix) 2288*e8227804SMichael Kruse { 2289*e8227804SMichael Kruse string cpp_args; 2290*e8227804SMichael Kruse 2291*e8227804SMichael Kruse cpp_args = generate_callback_type(param->getType()); 2292*e8227804SMichael Kruse 2293*e8227804SMichael Kruse osprintf(os, " struct %s_data {\n", prefix.c_str()); 2294*e8227804SMichael Kruse osprintf(os, " %s func;\n", cpp_args.c_str()); 2295*e8227804SMichael Kruse if (!checked) 2296*e8227804SMichael Kruse osprintf(os, " std::exception_ptr eptr;\n"); 2297*e8227804SMichael Kruse osprintf(os, " }"); 2298*e8227804SMichael Kruse } 2299*e8227804SMichael Kruse 2300*e8227804SMichael Kruse /* Print the body of C function callback with the given indentation 2301*e8227804SMichael Kruse * that can be use as an argument to "param" for marshalling 2302*e8227804SMichael Kruse * the corresponding C++ callback. 2303*e8227804SMichael Kruse * The data structure that contains the C++ callback is of type 2304*e8227804SMichael Kruse * "prefix"_data. 2305*e8227804SMichael Kruse * 2306*e8227804SMichael Kruse * For a callback of the form 2307*e8227804SMichael Kruse * 2308*e8227804SMichael Kruse * isl_stat (*fn)(__isl_take isl_map *map, void *user) 2309*e8227804SMichael Kruse * 2310*e8227804SMichael Kruse * the following code is generated: 2311*e8227804SMichael Kruse * 2312*e8227804SMichael Kruse * auto *data = static_cast<struct <prefix>_data *>(arg_1); 2313*e8227804SMichael Kruse * ISL_CPP_TRY { 2314*e8227804SMichael Kruse * stat ret = (data->func)(manage(arg_0)); 2315*e8227804SMichael Kruse * return isl_stat_ok; 2316*e8227804SMichael Kruse * } ISL_CPP_CATCH_ALL { 2317*e8227804SMichael Kruse * data->eptr = std::current_exception(); 2318*e8227804SMichael Kruse * return isl_stat_error; 2319*e8227804SMichael Kruse * } 2320*e8227804SMichael Kruse * 2321*e8227804SMichael Kruse * If checked C++ bindings are being generated, then 2322*e8227804SMichael Kruse * generate the following code: 2323*e8227804SMichael Kruse * 2324*e8227804SMichael Kruse * auto *data = static_cast<struct <prefix>_data *>(arg_1); 2325*e8227804SMichael Kruse * stat ret = (data->func)(manage(arg_0)); 2326*e8227804SMichael Kruse * return isl_stat(ret); 2327*e8227804SMichael Kruse */ 2328*e8227804SMichael Kruse void cpp_generator::print_callback_body(ostream &os, int indent, 2329*e8227804SMichael Kruse ParmVarDecl *param, const string &prefix) 2330*e8227804SMichael Kruse { 2331*e8227804SMichael Kruse QualType ptype, rtype; 2332*e8227804SMichael Kruse string call, last_idx; 2333*e8227804SMichael Kruse const FunctionProtoType *callback; 2334*e8227804SMichael Kruse int num_params; 2335*e8227804SMichael Kruse 2336*e8227804SMichael Kruse ptype = param->getType(); 2337*e8227804SMichael Kruse 2338*e8227804SMichael Kruse callback = extract_prototype(ptype); 2339*e8227804SMichael Kruse rtype = callback->getReturnType(); 2340*e8227804SMichael Kruse num_params = callback->getNumArgs(); 2341*e8227804SMichael Kruse 2342*e8227804SMichael Kruse last_idx = ::to_string(num_params - 1); 2343*e8227804SMichael Kruse 2344*e8227804SMichael Kruse call = "(data->func)("; 2345*e8227804SMichael Kruse for (long i = 0; i < num_params - 1; i++) { 2346*e8227804SMichael Kruse if (!callback_takes_argument(param, i)) 2347*e8227804SMichael Kruse call += "manage_copy"; 2348*e8227804SMichael Kruse else 2349*e8227804SMichael Kruse call += "manage"; 2350*e8227804SMichael Kruse call += "(arg_" + ::to_string(i) + ")"; 2351*e8227804SMichael Kruse if (i != num_params - 2) 2352*e8227804SMichael Kruse call += ", "; 2353*e8227804SMichael Kruse } 2354*e8227804SMichael Kruse call += ")"; 2355*e8227804SMichael Kruse 2356*e8227804SMichael Kruse osprintf(os, indent, 2357*e8227804SMichael Kruse "auto *data = static_cast<struct %s_data *>(arg_%s);\n", 2358*e8227804SMichael Kruse prefix.c_str(), last_idx.c_str()); 2359*e8227804SMichael Kruse print_wrapped_call(os, indent, call, rtype); 2360d169d70bSTobias Grosser } 2361d169d70bSTobias Grosser 2362d169d70bSTobias Grosser /* Print the local variables that are needed for a callback argument, 2363d169d70bSTobias Grosser * in particular, print a lambda function that wraps the callback and 2364d169d70bSTobias Grosser * a pointer to the actual C++ callback function. 2365d169d70bSTobias Grosser * 2366d169d70bSTobias Grosser * For a callback of the form 2367d169d70bSTobias Grosser * 2368d169d70bSTobias Grosser * isl_stat (*fn)(__isl_take isl_map *map, void *user) 2369d169d70bSTobias Grosser * 2370d169d70bSTobias Grosser * the following lambda function is generated: 2371d169d70bSTobias Grosser * 2372d169d70bSTobias Grosser * auto fn_lambda = [](isl_map *arg_0, void *arg_1) -> isl_stat { 2373d169d70bSTobias Grosser * auto *data = static_cast<struct fn_data *>(arg_1); 2374d169d70bSTobias Grosser * try { 2375*e8227804SMichael Kruse * stat ret = (data->func)(manage(arg_0)); 2376d169d70bSTobias Grosser * return isl_stat_ok; 2377d169d70bSTobias Grosser * } catch (...) { 2378d169d70bSTobias Grosser * data->eptr = std::current_exception(); 2379d169d70bSTobias Grosser * return isl_stat_error; 2380d169d70bSTobias Grosser * } 2381d169d70bSTobias Grosser * }; 2382d169d70bSTobias Grosser * 2383*e8227804SMichael Kruse * A copy of the std::function C++ callback function is stored in 2384d169d70bSTobias Grosser * a fn_data data structure for passing to the C callback function, 2385d169d70bSTobias Grosser * along with an std::exception_ptr that is used to store any 2386d169d70bSTobias Grosser * exceptions thrown in the C++ callback. 2387d169d70bSTobias Grosser * 2388d169d70bSTobias Grosser * struct fn_data { 2389*e8227804SMichael Kruse * std::function<stat(map)> func; 2390d169d70bSTobias Grosser * std::exception_ptr eptr; 2391*e8227804SMichael Kruse * } fn_data = { fn }; 2392d169d70bSTobias Grosser * 2393d169d70bSTobias Grosser * This std::function object represents the actual user 2394d169d70bSTobias Grosser * callback function together with the locally captured state at the caller. 2395d169d70bSTobias Grosser * 2396d169d70bSTobias Grosser * The lambda function is expected to be used as a C callback function 2397d169d70bSTobias Grosser * where the lambda itself is provided as the function pointer and 2398d169d70bSTobias Grosser * where the user void pointer is a pointer to fn_data. 2399d169d70bSTobias Grosser * The std::function object is extracted from the pointer to fn_data 2400d169d70bSTobias Grosser * inside the lambda function. 2401d169d70bSTobias Grosser * 2402d169d70bSTobias Grosser * The std::exception_ptr object is not added to fn_data 2403d169d70bSTobias Grosser * if checked C++ bindings are being generated. 2404d169d70bSTobias Grosser * The body of the generated lambda function then is as follows: 2405d169d70bSTobias Grosser * 2406*e8227804SMichael Kruse * stat ret = (data->func)(manage(arg_0)); 2407d169d70bSTobias Grosser * return isl_stat(ret); 24086145b11cSTobias Grosser * 24096145b11cSTobias Grosser * If the C callback does not take its arguments, then 24106145b11cSTobias Grosser * manage_copy is used instead of manage. 2411d169d70bSTobias Grosser */ 2412d169d70bSTobias Grosser void cpp_generator::print_callback_local(ostream &os, ParmVarDecl *param) 2413d169d70bSTobias Grosser { 2414d169d70bSTobias Grosser string pname; 2415*e8227804SMichael Kruse QualType ptype, rtype; 2416*e8227804SMichael Kruse string c_args, cpp_args, rettype; 2417d169d70bSTobias Grosser const FunctionProtoType *callback; 2418d169d70bSTobias Grosser 2419d169d70bSTobias Grosser pname = param->getName().str(); 2420d169d70bSTobias Grosser ptype = param->getType(); 2421d169d70bSTobias Grosser 2422d169d70bSTobias Grosser c_args = generate_callback_args(ptype, false); 2423d169d70bSTobias Grosser 242426269d34STobias Grosser callback = extract_prototype(ptype); 2425*e8227804SMichael Kruse rtype = callback->getReturnType(); 2426*e8227804SMichael Kruse rettype = rtype.getAsString(); 2427d169d70bSTobias Grosser 2428*e8227804SMichael Kruse print_callback_data_decl(os, param, pname); 2429*e8227804SMichael Kruse osprintf(os, " %s_data = { %s };\n", pname.c_str(), pname.c_str()); 2430d169d70bSTobias Grosser osprintf(os, " auto %s_lambda = [](%s) -> %s {\n", 2431d169d70bSTobias Grosser pname.c_str(), c_args.c_str(), rettype.c_str()); 2432*e8227804SMichael Kruse print_callback_body(os, 4, param, pname); 2433d169d70bSTobias Grosser osprintf(os, " };\n"); 2434d169d70bSTobias Grosser } 2435d169d70bSTobias Grosser 2436d169d70bSTobias Grosser /* An array listing functions that must be renamed and the function name they 2437d169d70bSTobias Grosser * should be renamed to. We currently rename functions in case their name would 2438d169d70bSTobias Grosser * match a reserved C++ keyword, which is not allowed in C++. 2439d169d70bSTobias Grosser */ 2440d169d70bSTobias Grosser static const char *rename_map[][2] = { 2441d169d70bSTobias Grosser { "union", "unite" }, 2442d169d70bSTobias Grosser }; 2443d169d70bSTobias Grosser 2444d169d70bSTobias Grosser /* Rename method "name" in case the method name in the C++ bindings should not 2445d169d70bSTobias Grosser * match the name in the C bindings. We do this for example to avoid 2446d169d70bSTobias Grosser * C++ keywords. 2447d169d70bSTobias Grosser */ 2448d169d70bSTobias Grosser std::string cpp_generator::rename_method(std::string name) 2449d169d70bSTobias Grosser { 2450d169d70bSTobias Grosser for (size_t i = 0; i < sizeof(rename_map) / sizeof(rename_map[0]); i++) 2451d169d70bSTobias Grosser if (name.compare(rename_map[i][0]) == 0) 2452d169d70bSTobias Grosser return rename_map[i][1]; 2453d169d70bSTobias Grosser 2454d169d70bSTobias Grosser return name; 2455d169d70bSTobias Grosser } 2456d169d70bSTobias Grosser 2457d169d70bSTobias Grosser /* Translate isl class "clazz" to its corresponding C++ type. 2458*e8227804SMichael Kruse * Use the name of the type based subclass, if any. 2459d169d70bSTobias Grosser */ 2460d169d70bSTobias Grosser string cpp_generator::type2cpp(const isl_class &clazz) 2461d169d70bSTobias Grosser { 2462*e8227804SMichael Kruse return type2cpp(clazz.subclass_name); 2463d169d70bSTobias Grosser } 2464d169d70bSTobias Grosser 2465d169d70bSTobias Grosser /* Translate type string "type_str" to its C++ name counterpart. 2466d169d70bSTobias Grosser */ 2467d169d70bSTobias Grosser string cpp_generator::type2cpp(string type_str) 2468d169d70bSTobias Grosser { 2469d169d70bSTobias Grosser return type_str.substr(4); 2470d169d70bSTobias Grosser } 2471d169d70bSTobias Grosser 2472*e8227804SMichael Kruse /* Return the C++ counterpart to the isl_bool type. 2473*e8227804SMichael Kruse * If checked C++ bindings are being generated, 2474*e8227804SMichael Kruse * then this is "boolean". Otherwise, it is simply "bool". 2475*e8227804SMichael Kruse */ 2476*e8227804SMichael Kruse string cpp_generator::isl_bool2cpp() 2477*e8227804SMichael Kruse { 2478*e8227804SMichael Kruse return checked ? "boolean" : "bool"; 2479*e8227804SMichael Kruse } 2480*e8227804SMichael Kruse 2481*e8227804SMichael Kruse /* Return the namespace of the generated C++ bindings. 2482*e8227804SMichael Kruse */ 2483*e8227804SMichael Kruse string cpp_generator::isl_namespace() 2484*e8227804SMichael Kruse { 2485*e8227804SMichael Kruse return checked ? "isl::checked::" : "isl::"; 2486*e8227804SMichael Kruse } 2487*e8227804SMichael Kruse 2488d169d70bSTobias Grosser /* Translate QualType "type" to its C++ name counterpart. 2489d169d70bSTobias Grosser * 2490d169d70bSTobias Grosser * An isl_bool return type is translated into "bool", 2491*e8227804SMichael Kruse * while an isl_stat is translated into "void" and 2492*e8227804SMichael Kruse * an isl_size is translated to "unsigned". 2493d169d70bSTobias Grosser * The exceptional cases are handled through exceptions. 2494d169d70bSTobias Grosser * If checked C++ bindings are being generated, then 2495*e8227804SMichael Kruse * C++ counterparts of isl_bool, isl_stat and isl_size need to be used instead. 2496d169d70bSTobias Grosser */ 2497d169d70bSTobias Grosser string cpp_generator::type2cpp(QualType type) 2498d169d70bSTobias Grosser { 2499d169d70bSTobias Grosser if (is_isl_type(type)) 2500*e8227804SMichael Kruse return isl_namespace() + 2501*e8227804SMichael Kruse type2cpp(type->getPointeeType().getAsString()); 2502d169d70bSTobias Grosser 2503d169d70bSTobias Grosser if (is_isl_bool(type)) 2504*e8227804SMichael Kruse return isl_bool2cpp(); 2505d169d70bSTobias Grosser 2506d169d70bSTobias Grosser if (is_isl_stat(type)) 2507d169d70bSTobias Grosser return checked ? "stat" : "void"; 2508d169d70bSTobias Grosser 2509*e8227804SMichael Kruse if (is_isl_size(type)) 2510*e8227804SMichael Kruse return checked ? "class size" : "unsigned"; 2511*e8227804SMichael Kruse 2512d169d70bSTobias Grosser if (type->isIntegerType()) 2513d169d70bSTobias Grosser return type.getAsString(); 2514d169d70bSTobias Grosser 2515d169d70bSTobias Grosser if (is_string(type)) 2516d169d70bSTobias Grosser return "std::string"; 2517d169d70bSTobias Grosser 2518d169d70bSTobias Grosser if (is_callback(type)) 2519d169d70bSTobias Grosser return generate_callback_type(type); 2520d169d70bSTobias Grosser 2521d169d70bSTobias Grosser die("Cannot convert type to C++ type"); 2522d169d70bSTobias Grosser } 2523d169d70bSTobias Grosser 2524d169d70bSTobias Grosser /* Check if "subclass_type" is a subclass of "class_type". 2525d169d70bSTobias Grosser */ 2526d169d70bSTobias Grosser bool cpp_generator::is_subclass(QualType subclass_type, 2527d169d70bSTobias Grosser const isl_class &class_type) 2528d169d70bSTobias Grosser { 2529d169d70bSTobias Grosser std::string type_str = subclass_type->getPointeeType().getAsString(); 2530d169d70bSTobias Grosser std::vector<std::string> superclasses; 2531d169d70bSTobias Grosser std::vector<const isl_class *> parents; 2532d169d70bSTobias Grosser std::vector<std::string>::iterator ci; 2533d169d70bSTobias Grosser 2534d169d70bSTobias Grosser superclasses = generator::find_superclasses(classes[type_str].type); 2535d169d70bSTobias Grosser 2536d169d70bSTobias Grosser for (ci = superclasses.begin(); ci < superclasses.end(); ci++) 2537d169d70bSTobias Grosser parents.push_back(&classes[*ci]); 2538d169d70bSTobias Grosser 2539d169d70bSTobias Grosser while (!parents.empty()) { 2540d169d70bSTobias Grosser const isl_class *candidate = parents.back(); 2541d169d70bSTobias Grosser 2542d169d70bSTobias Grosser parents.pop_back(); 2543d169d70bSTobias Grosser 2544d169d70bSTobias Grosser if (&class_type == candidate) 2545d169d70bSTobias Grosser return true; 2546d169d70bSTobias Grosser 2547d169d70bSTobias Grosser superclasses = generator::find_superclasses(candidate->type); 2548d169d70bSTobias Grosser 2549d169d70bSTobias Grosser for (ci = superclasses.begin(); ci < superclasses.end(); ci++) 2550d169d70bSTobias Grosser parents.push_back(&classes[*ci]); 2551d169d70bSTobias Grosser } 2552d169d70bSTobias Grosser 2553d169d70bSTobias Grosser return false; 2554d169d70bSTobias Grosser } 2555d169d70bSTobias Grosser 2556d169d70bSTobias Grosser /* Check if "cons" is an implicit conversion constructor of class "clazz". 2557d169d70bSTobias Grosser * 2558d169d70bSTobias Grosser * An implicit conversion constructor is generated in case "cons" has a single 2559d169d70bSTobias Grosser * parameter, where the parameter type is a subclass of the class that is 2560d169d70bSTobias Grosser * currently being generated. 2561d169d70bSTobias Grosser */ 2562d169d70bSTobias Grosser bool cpp_generator::is_implicit_conversion(const isl_class &clazz, 2563d169d70bSTobias Grosser FunctionDecl *cons) 2564d169d70bSTobias Grosser { 2565d169d70bSTobias Grosser ParmVarDecl *param = cons->getParamDecl(0); 2566d169d70bSTobias Grosser QualType type = param->getOriginalType(); 2567d169d70bSTobias Grosser 2568d169d70bSTobias Grosser int num_params = cons->getNumParams(); 2569d169d70bSTobias Grosser if (num_params != 1) 2570d169d70bSTobias Grosser return false; 2571d169d70bSTobias Grosser 2572d169d70bSTobias Grosser if (is_isl_type(type) && !is_isl_ctx(type) && is_subclass(type, clazz)) 2573d169d70bSTobias Grosser return true; 2574d169d70bSTobias Grosser 2575d169d70bSTobias Grosser return false; 2576d169d70bSTobias Grosser } 2577d169d70bSTobias Grosser 2578d169d70bSTobias Grosser /* Get kind of "method" in "clazz". 2579d169d70bSTobias Grosser * 2580d169d70bSTobias Grosser * Given the declaration of a static or member method, returns its kind. 2581d169d70bSTobias Grosser */ 2582d169d70bSTobias Grosser cpp_generator::function_kind cpp_generator::get_method_kind( 2583d169d70bSTobias Grosser const isl_class &clazz, FunctionDecl *method) 2584d169d70bSTobias Grosser { 2585d169d70bSTobias Grosser if (is_static(clazz, method)) 2586d169d70bSTobias Grosser return function_kind_static_method; 2587d169d70bSTobias Grosser else 2588d169d70bSTobias Grosser return function_kind_member_method; 2589d169d70bSTobias Grosser } 2590