cpp: generate get_ctx method for all exported classes
[isl.git] / interface / cpp.cc
blob916a9d36fad322627731bafe18d604947570828f
1 /*
2 * Copyright 2016, 2017 Tobias Grosser. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above
12 * copyright notice, this list of conditions and the following
13 * disclaimer in the documentation and/or other materials provided
14 * with the distribution.
16 * THIS SOFTWARE IS PROVIDED BY TOBIAS GROSSER ''AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SVEN VERDOOLAEGE OR
20 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
21 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
22 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
23 * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 * The views and conclusions contained in the software and documentation
29 * are those of the authors and should not be interpreted as
30 * representing official policies, either expressed or implied, of
31 * Tobias Grosser.
34 #include <cstdarg>
35 #include <cstdio>
36 #include <iostream>
37 #include <map>
38 #include <sstream>
39 #include <string>
40 #include <vector>
42 #include "cpp.h"
43 #include "isl_config.h"
45 /* Print string formatted according to "fmt" to ostream "os".
47 * This osprintf method allows us to use printf style formatting constructs when
48 * writing to an ostream.
50 static void osprintf(ostream &os, const char *format, ...)
52 va_list arguments;
53 char *string_pointer;
54 size_t size;
56 va_start(arguments, format);
57 size = vsnprintf(NULL, 0, format, arguments);
58 string_pointer = new char[size + 1];
59 va_end(arguments);
60 va_start(arguments, format);
61 vsnprintf(string_pointer, size + 1, format, arguments);
62 va_end(arguments);
63 os << string_pointer;
64 delete[] string_pointer;
67 /* Convert "l" to a string.
69 static std::string to_string(long l)
71 std::ostringstream strm;
72 strm << l;
73 return strm.str();
76 /* Generate a cpp interface based on the extracted types and functions.
78 * Print first a set of forward declarations for all isl wrapper
79 * classes, then the declarations of the classes, and at the end all
80 * implementations.
82 void cpp_generator::generate()
84 ostream &os = cout;
86 osprintf(os, "\n");
87 osprintf(os, "namespace isl {\n\n");
88 osprintf(os, "inline namespace noexceptions {\n\n");
90 print_forward_declarations(os);
91 osprintf(os, "\n");
92 print_declarations(os);
93 osprintf(os, "\n");
94 print_implementations(os);
96 osprintf(os, "} // namespace noexceptions\n");
97 osprintf(os, "} // namespace isl\n\n");
98 osprintf(os, "#endif /* ISL_CPP_NOEXCEPTIONS */\n");
101 /* Print forward declarations for all classes to "os".
103 void cpp_generator::print_forward_declarations(ostream &os)
105 map<string, isl_class>::iterator ci;
107 osprintf(os, "// forward declarations\n");
109 for (ci = classes.begin(); ci != classes.end(); ++ci)
110 print_class_forward_decl(os, ci->second);
113 /* Print all declarations to "os".
115 void cpp_generator::print_declarations(ostream &os)
117 map<string, isl_class>::iterator ci;
118 bool first = true;
120 for (ci = classes.begin(); ci != classes.end(); ++ci) {
121 if (first)
122 first = false;
123 else
124 osprintf(os, "\n");
126 print_class(os, ci->second);
130 /* Print all implementations to "os".
132 void cpp_generator::print_implementations(ostream &os)
134 map<string, isl_class>::iterator ci;
135 bool first = true;
137 for (ci = classes.begin(); ci != classes.end(); ++ci) {
138 if (first)
139 first = false;
140 else
141 osprintf(os, "\n");
143 print_class_impl(os, ci->second);
147 /* Print declarations for class "clazz" to "os".
149 void cpp_generator::print_class(ostream &os, const isl_class &clazz)
151 const char *name = clazz.name.c_str();
152 std::string cppstring = type2cpp(clazz);
153 const char *cppname = cppstring.c_str();
155 osprintf(os, "// declarations for isl::%s\n", cppname);
157 print_class_factory_decl(os, clazz);
158 osprintf(os, "\n");
159 osprintf(os, "class %s {\n", cppname);
160 print_class_factory_decl(os, clazz, " friend ");
161 osprintf(os, "\n");
162 osprintf(os, " %s *ptr = nullptr;\n", name);
163 osprintf(os, "\n");
164 print_private_constructors_decl(os, clazz);
165 osprintf(os, "\n");
166 osprintf(os, "public:\n");
167 print_public_constructors_decl(os, clazz);
168 print_constructors_decl(os, clazz);
169 print_copy_assignment_decl(os, clazz);
170 print_destructor_decl(os, clazz);
171 print_ptr_decl(os, clazz);
172 print_get_ctx_decl(os);
173 osprintf(os, "\n");
174 print_methods_decl(os, clazz);
176 osprintf(os, "};\n");
179 /* Print forward declaration of class "clazz" to "os".
181 void cpp_generator::print_class_forward_decl(ostream &os,
182 const isl_class &clazz)
184 std::string cppstring = type2cpp(clazz);
185 const char *cppname = cppstring.c_str();
187 osprintf(os, "class %s;\n", cppname);
190 /* Print global factory functions to "os".
192 * Each class has two global factory functions:
194 * isl::set manage(__isl_take isl_set *ptr);
195 * isl::set manage_copy(__isl_keep isl_set *ptr);
197 * A user can construct isl C++ objects from a raw pointer and indicate whether
198 * they intend to take the ownership of the object or not through these global
199 * factory functions. This ensures isl object creation is very explicit and
200 * pointers are not converted by accident. Thanks to overloading, manage() and
201 * manage_copy() can be called on any isl raw pointer and the corresponding
202 * object is automatically created, without the user having to choose the right
203 * isl object type.
205 void cpp_generator::print_class_factory_decl(ostream &os,
206 const isl_class &clazz, const std::string &prefix)
208 const char *name = clazz.name.c_str();
209 std::string cppstring = type2cpp(clazz);
210 const char *cppname = cppstring.c_str();
212 os << prefix;
213 osprintf(os, "inline isl::%s manage(__isl_take %s *ptr);\n", cppname,
214 name);
215 os << prefix;
216 osprintf(os, "inline isl::%s manage_copy(__isl_keep %s *ptr);\n",
217 cppname, name);
220 /* Print declarations of private constructors for class "clazz" to "os".
222 * Each class has currently one private constructor:
224 * 1) Constructor from a plain isl_* C pointer
226 * Example:
228 * set(__isl_take isl_set *ptr);
230 * The raw pointer constructor is kept private. Object creation is only
231 * possible through isl::manage() or isl::manage_copy().
233 void cpp_generator::print_private_constructors_decl(ostream &os,
234 const isl_class &clazz)
236 const char *name = clazz.name.c_str();
237 std::string cppstring = type2cpp(clazz);
238 const char *cppname = cppstring.c_str();
240 osprintf(os, " inline explicit %s(__isl_take %s *ptr);\n", cppname,
241 name);
244 /* Print declarations of public constructors for class "clazz" to "os".
246 * Each class currently has two public constructors:
248 * 1) A default constructor
249 * 2) A copy constructor
251 * Example:
253 * set();
254 * set(const isl::set &set);
256 void cpp_generator::print_public_constructors_decl(ostream &os,
257 const isl_class &clazz)
259 std::string cppstring = type2cpp(clazz);
260 const char *cppname = cppstring.c_str();
261 osprintf(os, " inline /* implicit */ %s();\n", cppname);
263 osprintf(os, " inline /* implicit */ %s(const isl::%s &obj);\n",
264 cppname, cppname);
267 /* Print declarations for constructors for class "class" to "os".
269 * For each isl function that is marked as __isl_constructor,
270 * add a corresponding C++ constructor.
272 * Example:
274 * inline /\* implicit *\/ union_set(isl::basic_set bset);
275 * inline /\* implicit *\/ union_set(isl::set set);
276 * inline explicit val(isl::ctx ctx, long i);
277 * inline explicit val(isl::ctx ctx, const std::string &str);
279 void cpp_generator::print_constructors_decl(ostream &os,
280 const isl_class &clazz)
282 set<FunctionDecl *>::const_iterator in;
283 const set<FunctionDecl *> &constructors = clazz.constructors;
285 for (in = constructors.begin(); in != constructors.end(); ++in) {
286 FunctionDecl *cons = *in;
287 string fullname = cons->getName();
288 function_kind kind = function_kind_constructor;
290 print_method_decl(os, clazz, fullname, cons, kind);
294 /* Print declarations of copy assignment operator for class "clazz"
295 * to "os".
297 * Each class has one assignment operator.
299 * isl:set &set::operator=(isl::set obj)
302 void cpp_generator::print_copy_assignment_decl(ostream &os,
303 const isl_class &clazz)
305 std::string cppstring = type2cpp(clazz);
306 const char *cppname = cppstring.c_str();
308 osprintf(os, " inline isl::%s &operator=(isl::%s obj);\n", cppname,
309 cppname);
312 /* Print declaration of destructor for class "clazz" to "os".
314 void cpp_generator::print_destructor_decl(ostream &os, const isl_class &clazz)
316 std::string cppstring = type2cpp(clazz);
317 const char *cppname = cppstring.c_str();
319 osprintf(os, " inline ~%s();\n", cppname);
322 /* Print declaration of pointer functions for class "clazz" to "os".
324 * To obtain a raw pointer three functions are provided:
326 * 1) __isl_give isl_set *copy()
328 * Returns a pointer to a _copy_ of the internal object
330 * 2) __isl_keep isl_set *get()
332 * Returns a pointer to the internal object
334 * 3) __isl_give isl_set *release()
336 * Returns a pointer to the internal object and resets the
337 * internal pointer to nullptr.
339 * We also provide functionality to explicitly check if a pointer is
340 * currently managed by this object.
342 * 4) bool is_null()
344 * Check if the current object is a null pointer.
346 * The functions get() and release() model the value_ptr proposed in
347 * http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2012/n3339.pdf.
348 * The copy() function is an extension to allow the user to explicitly
349 * copy the underlying object.
351 * Also generate a declaration to delete copy() for r-values, for
352 * r-values release() should be used to avoid unnecessary copies.
354 void cpp_generator::print_ptr_decl(ostream &os, const isl_class &clazz)
356 const char *name = clazz.name.c_str();
358 osprintf(os, " inline __isl_give %s *copy() const &;\n", name);
359 osprintf(os, " inline __isl_give %s *copy() && = delete;\n", name);
360 osprintf(os, " inline __isl_keep %s *get() const;\n", name);
361 osprintf(os, " inline __isl_give %s *release();\n", name);
362 osprintf(os, " inline bool is_null() const;\n");
365 /* Print the declaration of the get_ctx method.
367 void cpp_generator::print_get_ctx_decl(ostream &os)
369 osprintf(os, " inline isl::ctx get_ctx() const;\n");
372 /* Print declarations for methods in class "clazz" to "os".
374 void cpp_generator::print_methods_decl(ostream &os, const isl_class &clazz)
376 map<string, set<FunctionDecl *> >::const_iterator it;
378 for (it = clazz.methods.begin(); it != clazz.methods.end(); ++it)
379 print_method_group_decl(os, clazz, it->first, it->second);
382 /* Print declarations for methods "methods" of name "fullname" in class "clazz"
383 * to "os".
385 * "fullname" is the name of the generated C++ method. It commonly corresponds
386 * to the isl name, with the object type prefix dropped.
387 * In case of overloaded methods, the result type suffix has also been removed.
389 void cpp_generator::print_method_group_decl(ostream &os, const isl_class &clazz,
390 const string &fullname, const set<FunctionDecl *> &methods)
392 set<FunctionDecl *>::const_iterator it;
394 for (it = methods.begin(); it != methods.end(); ++it) {
395 function_kind kind = get_method_kind(clazz, *it);
396 print_method_decl(os, clazz, fullname, *it, kind);
400 /* Print declarations for "method" in class "clazz" to "os".
402 * "fullname" is the name of the generated C++ method. It commonly corresponds
403 * to the isl name, with the object type prefix dropped.
404 * In case of overloaded methods, the result type suffix has also been removed.
406 * "kind" specifies the kind of method that should be generated.
408 void cpp_generator::print_method_decl(ostream &os, const isl_class &clazz,
409 const string &fullname, FunctionDecl *method, function_kind kind)
411 print_method_header(os, clazz, method, fullname, true, kind);
414 /* Print implementations for class "clazz" to "os".
416 void cpp_generator::print_class_impl(ostream &os, const isl_class &clazz)
418 std::string cppstring = type2cpp(clazz);
419 const char *cppname = cppstring.c_str();
421 osprintf(os, "// implementations for isl::%s\n", cppname);
423 print_class_factory_impl(os, clazz);
424 osprintf(os, "\n");
425 print_public_constructors_impl(os, clazz);
426 osprintf(os, "\n");
427 print_private_constructors_impl(os, clazz);
428 osprintf(os, "\n");
429 print_constructors_impl(os, clazz);
430 osprintf(os, "\n");
431 print_copy_assignment_impl(os, clazz);
432 osprintf(os, "\n");
433 print_destructor_impl(os, clazz);
434 osprintf(os, "\n");
435 print_ptr_impl(os, clazz);
436 osprintf(os, "\n");
437 print_get_ctx_impl(os, clazz);
438 osprintf(os, "\n");
439 print_methods_impl(os, clazz);
442 /* Print implementation of global factory function to "os".
444 void cpp_generator::print_class_factory_impl(ostream &os,
445 const isl_class &clazz)
447 const char *name = clazz.name.c_str();
448 std::string cppstring = type2cpp(clazz);
449 const char *cppname = cppstring.c_str();
451 osprintf(os, "isl::%s manage(__isl_take %s *ptr) {\n", cppname, name);
452 osprintf(os, " return %s(ptr);\n", cppname);
453 osprintf(os, "}\n");
455 osprintf(os, "isl::%s manage_copy(__isl_keep %s *ptr) {\n", cppname,
456 name);
457 osprintf(os, " return %s(%s_copy(ptr));\n", cppname, name);
458 osprintf(os, "}\n");
461 /* Print implementations of private constructors for class "clazz" to "os".
463 void cpp_generator::print_private_constructors_impl(ostream &os,
464 const isl_class &clazz)
466 const char *name = clazz.name.c_str();
467 std::string cppstring = type2cpp(clazz);
468 const char *cppname = cppstring.c_str();
470 osprintf(os, "%s::%s(__isl_take %s *ptr)\n : ptr(ptr) {}\n",
471 cppname, cppname, name);
474 /* Print implementations of public constructors for class "clazz" to "os".
476 void cpp_generator::print_public_constructors_impl(ostream &os,
477 const isl_class &clazz)
479 const char *name = clazz.name.c_str();
480 std::string cppstring = type2cpp(clazz);
481 const char *cppname = cppstring.c_str();
483 osprintf(os, "%s::%s()\n : ptr(nullptr) {}\n\n", cppname, cppname);
484 osprintf(os, "%s::%s(const isl::%s &obj)\n : ptr(obj.copy()) {}\n",
485 cppname, cppname, cppname, name);
488 /* Print implementations of constructors for class "clazz" to "os".
490 void cpp_generator::print_constructors_impl(ostream &os,
491 const isl_class &clazz)
493 set<FunctionDecl *>::const_iterator in;
494 const set<FunctionDecl *> constructors = clazz.constructors;
496 for (in = constructors.begin(); in != constructors.end(); ++in) {
497 FunctionDecl *cons = *in;
498 string fullname = cons->getName();
499 function_kind kind = function_kind_constructor;
501 print_method_impl(os, clazz, fullname, cons, kind);
505 /* Print implementation of copy assignment operator for class "clazz" to "os".
507 void cpp_generator::print_copy_assignment_impl(ostream &os,
508 const isl_class &clazz)
510 const char *name = clazz.name.c_str();
511 std::string cppstring = type2cpp(clazz);
512 const char *cppname = cppstring.c_str();
514 osprintf(os, "%s &%s::operator=(isl::%s obj) {\n", cppname,
515 cppname, cppname);
516 osprintf(os, " std::swap(this->ptr, obj.ptr);\n", name);
517 osprintf(os, " return *this;\n");
518 osprintf(os, "}\n");
521 /* Print implementation of destructor for class "clazz" to "os".
523 void cpp_generator::print_destructor_impl(ostream &os,
524 const isl_class &clazz)
526 const char *name = clazz.name.c_str();
527 std::string cppstring = type2cpp(clazz);
528 const char *cppname = cppstring.c_str();
530 osprintf(os, "%s::~%s() {\n", cppname, cppname);
531 osprintf(os, " if (ptr)\n");
532 osprintf(os, " %s_free(ptr);\n", name);
533 osprintf(os, "}\n");
536 /* Print implementation of ptr() functions for class "clazz" to "os".
538 void cpp_generator::print_ptr_impl(ostream &os, const isl_class &clazz)
540 const char *name = clazz.name.c_str();
541 std::string cppstring = type2cpp(clazz);
542 const char *cppname = cppstring.c_str();
544 osprintf(os, "__isl_give %s *%s::copy() const & {\n", name, cppname);
545 osprintf(os, " return %s_copy(ptr);\n", name);
546 osprintf(os, "}\n\n");
547 osprintf(os, "__isl_keep %s *%s::get() const {\n", name, cppname);
548 osprintf(os, " return ptr;\n");
549 osprintf(os, "}\n\n");
550 osprintf(os, "__isl_give %s *%s::release() {\n", name, cppname);
551 osprintf(os, " %s *tmp = ptr;\n", name);
552 osprintf(os, " ptr = nullptr;\n");
553 osprintf(os, " return tmp;\n");
554 osprintf(os, "}\n\n");
555 osprintf(os, "bool %s::is_null() const {\n", cppname);
556 osprintf(os, " return ptr == nullptr;\n");
557 osprintf(os, "}\n");
560 /* Print the implementation of the get_ctx method.
562 void cpp_generator::print_get_ctx_impl(ostream &os, const isl_class &clazz)
564 const char *name = clazz.name.c_str();
565 std::string cppstring = type2cpp(clazz);
566 const char *cppname = cppstring.c_str();
568 osprintf(os, "isl::ctx %s::get_ctx() const {\n", cppname);
569 osprintf(os, " return isl::ctx(%s_get_ctx(ptr));\n", name);
570 osprintf(os, "}\n");
573 /* Print definitions for methods of class "clazz" to "os".
575 void cpp_generator::print_methods_impl(ostream &os, const isl_class &clazz)
577 map<string, set<FunctionDecl *> >::const_iterator it;
578 bool first = true;
580 for (it = clazz.methods.begin(); it != clazz.methods.end(); ++it) {
581 if (first)
582 first = false;
583 else
584 osprintf(os, "\n");
585 print_method_group_impl(os, clazz, it->first, it->second);
589 /* Print definitions for methods "methods" of name "fullname" in class "clazz"
590 * to "os".
592 * "fullname" is the name of the generated C++ method. It commonly corresponds
593 * to the isl name, with the object type prefix dropped.
594 * In case of overloaded methods, the result type suffix has also been removed.
596 * "kind" specifies the kind of method that should be generated.
598 void cpp_generator::print_method_group_impl(ostream &os, const isl_class &clazz,
599 const string &fullname, const set<FunctionDecl *> &methods)
601 set<FunctionDecl *>::const_iterator it;
602 bool first = true;
604 for (it = methods.begin(); it != methods.end(); ++it) {
605 function_kind kind;
606 if (first)
607 first = false;
608 else
609 osprintf(os, "\n");
610 kind = get_method_kind(clazz, *it);
611 print_method_impl(os, clazz, fullname, *it, kind);
615 /* Print the use of "param" to "os".
617 * "load_from_this_ptr" specifies whether the parameter should be loaded from
618 * the this-ptr. In case a value is loaded from a this pointer, the original
619 * value must be preserved and must consequently be copied. Values that are
620 * loaded from parameters do not need to be preserved, as such values will
621 * already be copies of the actual parameters. It is consequently possible
622 * to directly take the pointer from these values, which saves
623 * an unnecessary copy.
625 * In case the parameter is a callback function, two parameters get printed,
626 * a wrapper for the callback function and a pointer to the actual
627 * callback function. The wrapper is expected to be available
628 * in a previously declared variable <name>_lambda, while
629 * the actual callback function is expected in <name>_p.
630 * The caller of this function must ensure that these variables exist.
632 void cpp_generator::print_method_param_use(ostream &os, ParmVarDecl *param,
633 bool load_from_this_ptr)
635 string name = param->getName().str();
636 const char *name_str = name.c_str();
637 QualType type = param->getOriginalType();
639 if (type->isIntegerType()) {
640 osprintf(os, "%s", name_str);
641 return;
644 if (is_string(type)) {
645 osprintf(os, "%s.c_str()", name_str);
646 return;
649 if (is_callback(type)) {
650 osprintf(os, "%s_lambda, ", name_str);
651 osprintf(os, "&%s_p", name_str);
652 return;
655 if (!load_from_this_ptr && !is_callback(type))
656 osprintf(os, "%s.", name_str);
658 if (keeps(param)) {
659 osprintf(os, "get()");
660 } else {
661 if (load_from_this_ptr)
662 osprintf(os, "copy()");
663 else
664 osprintf(os, "release()");
668 /* Print definition for "method" in class "clazz" to "os".
670 * "fullname" is the name of the generated C++ method. It commonly corresponds
671 * to the isl name, with the object type prefix dropped.
672 * In case of overloaded methods, the result type suffix has also been removed.
674 * "kind" specifies the kind of method that should be generated.
676 * This method distinguishes three kinds of methods: member methods, static
677 * methods, and constructors.
679 * Member methods call "method" by passing to the underlying isl function the
680 * isl object belonging to "this" as first argument and the remaining arguments
681 * as subsequent arguments. The result of the isl function is returned as a new
682 * object if the underlying isl function returns an isl_* ptr or an isl_bool
683 * value, as std::string if the isl function returns 'const char *', and as
684 * unmodified return value otherwise.
686 * Static methods call "method" by passing all arguments to the underlying isl
687 * function, as no this-pointer is available. The result is a newly managed
688 * isl C++ object.
690 * Constructors create a new object from a given set of input parameters. They
691 * do not return a value, but instead update the pointer stored inside the
692 * newly created object.
694 * If the method has a callback argument, we reduce the number of parameters
695 * that are exposed by one to hide the user pointer from the interface. On
696 * the C++ side no user pointer is needed, as arguments can be forwarded
697 * as part of the std::function argument which specifies the callback function.
699 void cpp_generator::print_method_impl(ostream &os, const isl_class &clazz,
700 const string &fullname, FunctionDecl *method, function_kind kind)
702 string cname = fullname.substr(clazz.name.length() + 1);
703 string methodname = method->getName();
704 int num_params = method->getNumParams();
705 QualType return_type = method->getReturnType();
706 string rettype_str = type2cpp(return_type);
707 bool has_callback = false;
709 print_method_header(os, clazz, method, fullname, false, kind);
711 for (int i = 0; i < num_params; ++i) {
712 ParmVarDecl *param = method->getParamDecl(i);
713 if (is_callback(param->getType())) {
714 has_callback = true;
715 num_params -= 1;
716 print_callback_local(os, param);
720 osprintf(os, " auto res = %s(", methodname.c_str());
722 for (int i = 0; i < num_params; ++i) {
723 ParmVarDecl *param = method->getParamDecl(i);
724 bool load_from_this_ptr = false;
726 if (i == 0 && kind == function_kind_member_method)
727 load_from_this_ptr = true;
729 print_method_param_use(os, param, load_from_this_ptr);
731 if (i != num_params - 1)
732 osprintf(os, ", ");
734 osprintf(os, ");\n");
736 if (kind == function_kind_constructor) {
737 osprintf(os, " ptr = res;\n");
738 } else if (is_isl_type(return_type) || is_isl_bool(return_type)) {
739 osprintf(os, " return manage(res);\n");
740 } else if (has_callback) {
741 osprintf(os, " return %s(res);\n", rettype_str.c_str());
742 } else if (is_string(return_type)) {
743 osprintf(os, " std::string tmp(res);\n");
744 if (gives(method))
745 osprintf(os, " free(res);\n");
746 osprintf(os, " return tmp;\n");
747 } else {
748 osprintf(os, " return res;\n");
751 osprintf(os, "}\n");
754 /* Print the header for "method" in class "clazz" to "os".
756 * Print the header of a declaration if "is_declaration" is set, otherwise print
757 * the header of a method definition.
759 * "fullname" is the name of the generated C++ method. It commonly corresponds
760 * to the isl name, with the object type prefix dropped.
761 * In case of overloaded methods, the result type suffix has also been removed.
763 * "kind" specifies the kind of method that should be generated.
765 * This function prints headers for member methods, static methods, and
766 * constructors, either for their declaration or definition.
768 * Member functions are declared as "const", as they do not change the current
769 * object, but instead create a new object. They always retrieve the first
770 * parameter of the original isl function from the this-pointer of the object,
771 * such that only starting at the second parameter the parameters of the
772 * original function become part of the method's interface.
774 * A function
776 * __isl_give isl_set *isl_set_intersect(__isl_take isl_set *s1,
777 * __isl_take isl_set *s2);
779 * is translated into:
781 * inline isl::set intersect(isl::set set2) const;
783 * For static functions and constructors all parameters of the original isl
784 * function are exposed.
786 * Parameters that are defined as __isl_keep or are of type string, are passed
787 * as const reference, which allows the compiler to optimize the parameter
788 * transfer.
790 * Constructors are marked as explicit using the C++ keyword 'explicit' or as
791 * implicit using a comment in place of the explicit keyword. By annotating
792 * implicit constructors with a comment, users of the interface are made
793 * aware of the potential danger that implicit construction is possible
794 * for these constructors, whereas without a comment not every user would
795 * know that implicit construction is allowed in absence of an explicit keyword.
797 void cpp_generator::print_method_header(ostream &os, const isl_class &clazz,
798 FunctionDecl *method, const string &fullname, bool is_declaration,
799 function_kind kind)
801 string cname = fullname.substr(clazz.name.length() + 1);
802 string rettype_str = type2cpp(method->getReturnType());
803 string classname = type2cpp(clazz);
804 int num_params = method->getNumParams();
805 int first_param = 0;
807 cname = rename_method(cname);
808 if (kind == function_kind_member_method)
809 first_param = 1;
811 if (is_declaration) {
812 osprintf(os, " ");
814 if (kind == function_kind_static_method)
815 osprintf(os, "static ");
817 osprintf(os, "inline ");
819 if (kind == function_kind_constructor) {
820 if (is_implicit_conversion(clazz, method))
821 osprintf(os, "/* implicit */ ");
822 else
823 osprintf(os, "explicit ");
827 if (kind != function_kind_constructor)
828 osprintf(os, "%s ", rettype_str.c_str());
830 if (!is_declaration)
831 osprintf(os, "%s::", classname.c_str());
833 if (kind != function_kind_constructor)
834 osprintf(os, "%s", cname.c_str());
835 else
836 osprintf(os, "%s", classname.c_str());
838 osprintf(os, "(");
840 for (int i = first_param; i < num_params; ++i) {
841 ParmVarDecl *param = method->getParamDecl(i);
842 QualType type = param->getOriginalType();
843 string cpptype = type2cpp(type);
845 if (is_callback(type))
846 num_params--;
848 if (keeps(param) || is_string(type) || is_callback(type))
849 osprintf(os, "const %s &%s", cpptype.c_str(),
850 param->getName().str().c_str());
851 else
852 osprintf(os, "%s %s", cpptype.c_str(),
853 param->getName().str().c_str());
855 if (i != num_params - 1)
856 osprintf(os, ", ");
859 osprintf(os, ")");
861 if (kind == function_kind_member_method)
862 osprintf(os, " const");
864 if (is_declaration)
865 osprintf(os, ";\n");
866 else
867 osprintf(os, " {\n");
870 /* Generate the list of argument types for a callback function of
871 * type "type". If "cpp" is set, then generate the C++ type list, otherwise
872 * the C type list.
874 * For a callback of type
876 * isl_stat (*)(__isl_take isl_map *map, void *user)
878 * the following C++ argument list is generated:
880 * isl::map
882 string cpp_generator::generate_callback_args(QualType type, bool cpp)
884 std::string type_str;
885 const FunctionProtoType *callback;
886 int num_params;
888 callback = type->getPointeeType()->getAs<FunctionProtoType>();
889 num_params = callback->getNumArgs();
890 if (cpp)
891 num_params--;
893 for (long i = 0; i < num_params; i++) {
894 QualType type = callback->getArgType(i);
896 if (cpp)
897 type_str += type2cpp(type);
898 else
899 type_str += type.getAsString();
901 if (!cpp)
902 type_str += "arg_" + ::to_string(i);
904 if (i != num_params - 1)
905 type_str += ", ";
908 return type_str;
911 /* Generate the full cpp type of a callback function of type "type".
913 * For a callback of type
915 * isl_stat (*)(__isl_take isl_map *map, void *user)
917 * the following type is generated:
919 * std::function<isl::stat(isl::map)>
921 string cpp_generator::generate_callback_type(QualType type)
923 std::string type_str;
924 const FunctionProtoType *callback = type->getPointeeType()->getAs<FunctionProtoType>();
925 QualType return_type = callback->getReturnType();
926 string rettype_str = type2cpp(return_type);
928 type_str = "std::function<";
929 type_str += rettype_str;
930 type_str += "(";
931 type_str += generate_callback_args(type, true);
932 type_str += ")>";
934 return type_str;
937 /* Print the local variables that are needed for a callback argument,
938 * in particular, print a lambda function that wraps the callback and
939 * a pointer to the actual C++ callback function.
941 * For a callback of the form
943 * isl_stat (*fn)(__isl_take isl_map *map, void *user)
945 * the following lambda function is generated:
947 * auto fn_lambda = [](isl_map *arg_0, void *arg_1) -> isl_stat {
948 * auto *func = *static_cast<const std::function<stat(map)> **>(arg_1);
949 * stat ret = (*func)(isl::manage(arg_0));
950 * return isl_stat(ret);
951 * };
953 * The pointer to the std::function C++ callback function is stored in fn_p.
954 * This std::function object represents the actual user
955 * callback function together with the locally captured state at the caller.
957 * The lambda function is expected to be used as a C callback function
958 * where the lambda itself is provided as the function pointer and
959 * where the user void pointer is a pointer to fn_p.
960 * The std::function object is extracted from the pointer to fn_p
961 * inside the lambda function.
962 * The double indirection is used to avoid having to worry about
963 * const casting.
965 void cpp_generator::print_callback_local(ostream &os, ParmVarDecl *param) {
966 string pname;
967 QualType ptype;
968 string call_args, c_args, cpp_args, rettype, last_idx;
969 const FunctionProtoType *callback;
970 int num_params;
972 pname = param->getName().str();
973 ptype = param->getType();
975 c_args = generate_callback_args(ptype, false);
976 cpp_args = generate_callback_type(ptype);
978 callback = ptype->getPointeeType()->getAs<FunctionProtoType>();
979 rettype = callback->getReturnType().getAsString();
980 num_params = callback->getNumArgs();
982 last_idx = ::to_string(num_params - 1);
984 for (long i = 0; i < num_params - 1; i++) {
985 call_args += "isl::manage(arg_" + ::to_string(i) + ")";
986 if (i != num_params - 2)
987 call_args += ", ";
990 osprintf(os, " auto %s_p = &%s;\n", pname.c_str(), pname.c_str());
991 osprintf(os,
992 " auto %s_lambda = [](%s) -> %s {\n"
993 " auto *func = *static_cast<const %s **>(arg_%s);\n"
994 " stat ret = (*func)(%s);\n"
995 " return isl_stat(ret);\n"
996 " };\n",
997 pname.c_str(), c_args.c_str(), rettype.c_str(),
998 cpp_args.c_str(), last_idx.c_str(), call_args.c_str());
1001 /* An array listing functions that must be renamed and the function name they
1002 * should be renamed to. We currently rename functions in case their name would
1003 * match a reserved C++ keyword, which is not allowed in C++.
1005 static const char *rename_map[][2] = {
1006 { "union", "unite" },
1009 /* Rename method "name" in case the method name in the C++ bindings should not
1010 * match the name in the C bindings. We do this for example to avoid
1011 * C++ keywords.
1013 std::string cpp_generator::rename_method(std::string name)
1015 for (size_t i = 0; i < sizeof(rename_map) / sizeof(rename_map[0]); i++)
1016 if (name.compare(rename_map[i][0]) == 0)
1017 return rename_map[i][1];
1019 return name;
1022 /* Translate isl class "clazz" to its corresponding C++ type.
1024 string cpp_generator::type2cpp(const isl_class &clazz)
1026 return type2cpp(clazz.name);
1029 /* Translate type string "type_str" to its C++ name counterpart.
1031 string cpp_generator::type2cpp(string type_str)
1033 return type_str.substr(4);
1036 /* Translate QualType "type" to its C++ name counterpart.
1038 string cpp_generator::type2cpp(QualType type)
1040 if (is_isl_type(type))
1041 return "isl::" + type2cpp(type->getPointeeType().getAsString());
1043 if (is_isl_bool(type))
1044 return "isl::boolean";
1046 if (is_isl_stat(type))
1047 return "isl::stat";
1049 if (type->isIntegerType())
1050 return type.getAsString();
1052 if (is_string(type))
1053 return "std::string";
1055 if (is_callback(type))
1056 return generate_callback_type(type);
1058 die("Cannot convert type to C++ type");
1061 /* Check if "subclass_type" is a subclass of "class_type".
1063 bool cpp_generator::is_subclass(QualType subclass_type,
1064 const isl_class &class_type)
1066 std::string type_str = subclass_type->getPointeeType().getAsString();
1067 std::vector<std::string> superclasses;
1068 std::vector<const isl_class *> parents;
1069 std::vector<std::string>::iterator ci;
1071 superclasses = generator::find_superclasses(classes[type_str].type);
1073 for (ci = superclasses.begin(); ci < superclasses.end(); ci++)
1074 parents.push_back(&classes[*ci]);
1076 while (!parents.empty()) {
1077 const isl_class *candidate = parents.back();
1079 parents.pop_back();
1081 if (&class_type == candidate)
1082 return true;
1084 superclasses = generator::find_superclasses(candidate->type);
1086 for (ci = superclasses.begin(); ci < superclasses.end(); ci++)
1087 parents.push_back(&classes[*ci]);
1090 return false;
1093 /* Check if "cons" is an implicit conversion constructor of class "clazz".
1095 * An implicit conversion constructor is generated in case "cons" has a single
1096 * parameter, where the parameter type is a subclass of the class that is
1097 * currently being generated.
1099 bool cpp_generator::is_implicit_conversion(const isl_class &clazz,
1100 FunctionDecl *cons)
1102 ParmVarDecl *param = cons->getParamDecl(0);
1103 QualType type = param->getOriginalType();
1105 int num_params = cons->getNumParams();
1106 if (num_params != 1)
1107 return false;
1109 if (is_isl_type(type) && !is_isl_ctx(type) && is_subclass(type, clazz))
1110 return true;
1112 return false;
1115 /* Get kind of "method" in "clazz".
1117 * Given the declaration of a static or member method, returns its kind.
1119 cpp_generator::function_kind cpp_generator::get_method_kind(
1120 const isl_class &clazz, FunctionDecl *method)
1122 if (is_static(clazz, method))
1123 return function_kind_static_method;
1124 else
1125 return function_kind_member_method;