add isl_space_get_tuple_hash
[isl.git] / interface / cpp.cc
blobcab1d9a08409f9e582aa1e8ee4ba1a3423edcbbc
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 FILE *string_stream;
54 char *string_pointer;
55 size_t size;
57 va_start(arguments, format);
59 string_stream = open_memstream(&string_pointer, &size);
61 if (!string_stream) {
62 fprintf(stderr, "open_memstream failed -- aborting!\n");
63 exit(1);
66 vfprintf(string_stream, format, arguments);
67 fclose(string_stream);
68 os << string_pointer;
69 free(string_pointer);
72 /* Convert "l" to a string.
74 static std::string to_string(long l)
76 std::ostringstream strm;
77 strm << l;
78 return strm.str();
81 /* Generate a cpp interface based on the extracted types and functions.
83 * Print first a set of forward declarations for all isl wrapper
84 * classes, then the declarations of the classes, and at the end all
85 * implementations.
87 void cpp_generator::generate()
89 ostream &os = cout;
91 osprintf(os, "\n");
92 osprintf(os, "namespace isl {\n\n");
93 osprintf(os, "inline namespace noexceptions {\n\n");
95 print_forward_declarations(os);
96 osprintf(os, "\n");
97 print_declarations(os);
98 osprintf(os, "\n");
99 print_implementations(os);
101 osprintf(os, "} // namespace noexceptions\n");
102 osprintf(os, "} // namespace isl\n\n");
103 osprintf(os, "#endif /* ISL_CPP_NOEXCEPTIONS */\n");
106 /* Print forward declarations for all classes to "os".
108 void cpp_generator::print_forward_declarations(ostream &os)
110 map<string, isl_class>::iterator ci;
112 osprintf(os, "// forward declarations\n");
114 for (ci = classes.begin(); ci != classes.end(); ++ci)
115 print_class_forward_decl(os, ci->second);
118 /* Print all declarations to "os".
120 void cpp_generator::print_declarations(ostream &os)
122 map<string, isl_class>::iterator ci;
123 bool first = true;
125 for (ci = classes.begin(); ci != classes.end(); ++ci) {
126 if (first)
127 first = false;
128 else
129 osprintf(os, "\n");
131 print_class(os, ci->second);
135 /* Print all implementations to "os".
137 void cpp_generator::print_implementations(ostream &os)
139 map<string, isl_class>::iterator ci;
140 bool first = true;
142 for (ci = classes.begin(); ci != classes.end(); ++ci) {
143 if (first)
144 first = false;
145 else
146 osprintf(os, "\n");
148 print_class_impl(os, ci->second);
152 /* Print declarations for class "clazz" to "os".
154 void cpp_generator::print_class(ostream &os, const isl_class &clazz)
156 const char *name = clazz.name.c_str();
157 std::string cppstring = type2cpp(clazz);
158 const char *cppname = cppstring.c_str();
160 osprintf(os, "// declarations for isl::%s\n", cppname);
162 print_class_factory_decl(os, clazz);
163 osprintf(os, "\n");
164 osprintf(os, "class %s {\n", cppname);
165 osprintf(os, " friend ");
166 print_class_factory_decl(os, clazz);
167 osprintf(os, "\n");
168 osprintf(os, " %s *ptr = nullptr;\n", name);
169 osprintf(os, "\n");
170 print_private_constructors_decl(os, clazz);
171 osprintf(os, "\n");
172 osprintf(os, "public:\n");
173 print_public_constructors_decl(os, clazz);
174 print_constructors_decl(os, clazz);
175 print_copy_assignment_decl(os, clazz);
176 print_destructor_decl(os, clazz);
177 print_ptr_decl(os, clazz);
178 osprintf(os, "\n");
179 print_methods_decl(os, clazz);
181 osprintf(os, "};\n");
184 /* Print forward declaration of class "clazz" to "os".
186 void cpp_generator::print_class_forward_decl(ostream &os,
187 const isl_class &clazz)
189 std::string cppstring = type2cpp(clazz);
190 const char *cppname = cppstring.c_str();
192 osprintf(os, "class %s;\n", cppname);
195 /* Print global factory function to "os".
197 * Each class has one global factory function:
199 * isl::set manage(__isl_take isl_set *ptr);
201 * The only public way to construct isl C++ objects from a raw pointer is
202 * through this global factory function. This ensures isl object creation
203 * is very explicit and pointers are not converted by accident. Due to
204 * overloading, manage() can be called on any isl raw pointer and the
205 * corresponding object is automatically created, without the user having
206 * to choose the right isl object type.
208 void cpp_generator::print_class_factory_decl(ostream &os,
209 const isl_class &clazz)
211 const char *name = clazz.name.c_str();
212 std::string cppstring = type2cpp(clazz);
213 const char *cppname = cppstring.c_str();
215 osprintf(os, "inline isl::%s manage(__isl_take %s *ptr);\n", cppname,
216 name);
219 /* Print declarations of private constructors for class "clazz" to "os".
221 * Each class has currently one private constructor:
223 * 1) Constructor from a plain isl_* C pointer
225 * Example:
227 * set(__isl_take isl_set *ptr);
229 * The raw pointer constructor is kept private. Object creation is only
230 * possible through isl::manage().
232 void cpp_generator::print_private_constructors_decl(ostream &os,
233 const isl_class &clazz)
235 const char *name = clazz.name.c_str();
236 std::string cppstring = type2cpp(clazz);
237 const char *cppname = cppstring.c_str();
239 osprintf(os, " inline explicit %s(__isl_take %s *ptr);\n", cppname,
240 name);
243 /* Print declarations of public constructors for class "clazz" to "os".
245 * Each class currently has two public constructors:
247 * 1) A default constructor
248 * 2) A copy constructor
250 * Example:
252 * set();
253 * set(const isl::set &set);
255 void cpp_generator::print_public_constructors_decl(ostream &os,
256 const isl_class &clazz)
258 std::string cppstring = type2cpp(clazz);
259 const char *cppname = cppstring.c_str();
260 osprintf(os, " inline /* implicit */ %s();\n", cppname);
262 osprintf(os, " inline /* implicit */ %s(const isl::%s &obj);\n",
263 cppname, cppname);
266 /* Print declarations for constructors for class "class" to "os".
268 * For each isl function that is marked as __isl_constructor,
269 * add a corresponding C++ constructor.
271 * Example:
273 * inline /\* implicit *\/ union_set(isl::basic_set bset);
274 * inline /\* implicit *\/ union_set(isl::set set);
275 * inline explicit val(isl::ctx ctx, long i);
276 * inline explicit val(isl::ctx ctx, const std::string &str);
278 void cpp_generator::print_constructors_decl(ostream &os,
279 const isl_class &clazz)
281 set<FunctionDecl *>::const_iterator in;
282 const set<FunctionDecl *> &constructors = clazz.constructors;
284 for (in = constructors.begin(); in != constructors.end(); ++in) {
285 FunctionDecl *cons = *in;
286 string fullname = cons->getName();
287 function_kind kind = function_kind_constructor;
289 print_method_decl(os, clazz, fullname, cons, kind);
293 /* Print declarations of copy assignment operator for class "clazz"
294 * to "os".
296 * Each class has one assignment operator.
298 * isl:set &set::operator=(isl::set obj)
301 void cpp_generator::print_copy_assignment_decl(ostream &os,
302 const isl_class &clazz)
304 std::string cppstring = type2cpp(clazz);
305 const char *cppname = cppstring.c_str();
307 osprintf(os, " inline isl::%s &operator=(isl::%s obj);\n", cppname,
308 cppname);
311 /* Print declaration of destructor for class "clazz" to "os".
313 void cpp_generator::print_destructor_decl(ostream &os, const isl_class &clazz)
315 std::string cppstring = type2cpp(clazz);
316 const char *cppname = cppstring.c_str();
318 osprintf(os, " inline ~%s();\n", cppname);
321 /* Print declaration of pointer functions for class "clazz" to "os".
323 * To obtain a raw pointer three functions are provided:
325 * 1) __isl_give isl_set *copy()
327 * Returns a pointer to a _copy_ of the internal object
329 * 2) __isl_keep isl_set *get()
331 * Returns a pointer to the internal object
333 * 3) __isl_give isl_set *release()
335 * Returns a pointer to the internal object and resets the
336 * internal pointer to nullptr.
338 * We also provide functionality to explicitly check if a pointer is
339 * currently managed by this object.
341 * 4) bool is_null()
343 * Check if the current object is a null pointer.
345 * The functions get() and release() model the value_ptr proposed in
346 * http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2012/n3339.pdf.
347 * The copy() function is an extension to allow the user to explicitly
348 * copy the underlying object.
350 * Also generate a declaration to delete copy() for r-values, for
351 * r-values release() should be used to avoid unnecessary copies.
353 void cpp_generator::print_ptr_decl(ostream &os, const isl_class &clazz)
355 const char *name = clazz.name.c_str();
357 osprintf(os, " inline __isl_give %s *copy() const &;\n", name);
358 osprintf(os, " inline __isl_give %s *copy() && = delete;\n", name);
359 osprintf(os, " inline __isl_keep %s *get() const;\n", name);
360 osprintf(os, " inline __isl_give %s *release();\n", name);
361 osprintf(os, " inline bool is_null() const;\n");
364 /* Print declarations for methods in class "clazz" to "os".
366 void cpp_generator::print_methods_decl(ostream &os, const isl_class &clazz)
368 map<string, set<FunctionDecl *> >::const_iterator it;
370 for (it = clazz.methods.begin(); it != clazz.methods.end(); ++it)
371 print_method_group_decl(os, clazz, it->first, it->second);
374 /* Print declarations for methods "methods" of name "fullname" in class "clazz"
375 * to "os".
377 * "fullname" is the name of the generated C++ method. It commonly corresponds
378 * to the isl name, with the object type prefix dropped.
379 * In case of overloaded methods, the result type suffix has also been removed.
381 void cpp_generator::print_method_group_decl(ostream &os, const isl_class &clazz,
382 const string &fullname, const set<FunctionDecl *> &methods)
384 set<FunctionDecl *>::const_iterator it;
386 for (it = methods.begin(); it != methods.end(); ++it) {
387 function_kind kind = get_method_kind(clazz, *it);
388 print_method_decl(os, clazz, fullname, *it, kind);
392 /* Print declarations for "method" in class "clazz" to "os".
394 * "fullname" is the name of the generated C++ method. It commonly corresponds
395 * to the isl name, with the object type prefix dropped.
396 * In case of overloaded methods, the result type suffix has also been removed.
398 * "kind" specifies the kind of method that should be generated.
400 void cpp_generator::print_method_decl(ostream &os, const isl_class &clazz,
401 const string &fullname, FunctionDecl *method, function_kind kind)
403 print_method_header(os, clazz, method, fullname, true, kind);
406 /* Print implementations for class "clazz" to "os".
408 void cpp_generator::print_class_impl(ostream &os, const isl_class &clazz)
410 std::string cppstring = type2cpp(clazz);
411 const char *cppname = cppstring.c_str();
413 osprintf(os, "// implementations for isl::%s\n", cppname);
415 print_class_factory_impl(os, clazz);
416 osprintf(os, "\n");
417 print_public_constructors_impl(os, clazz);
418 osprintf(os, "\n");
419 print_private_constructors_impl(os, clazz);
420 osprintf(os, "\n");
421 print_constructors_impl(os, clazz);
422 osprintf(os, "\n");
423 print_copy_assignment_impl(os, clazz);
424 osprintf(os, "\n");
425 print_destructor_impl(os, clazz);
426 osprintf(os, "\n");
427 print_ptr_impl(os, clazz);
428 osprintf(os, "\n");
429 print_methods_impl(os, clazz);
432 /* Print implementation of global factory function to "os".
434 void cpp_generator::print_class_factory_impl(ostream &os,
435 const isl_class &clazz)
437 const char *name = clazz.name.c_str();
438 std::string cppstring = type2cpp(clazz);
439 const char *cppname = cppstring.c_str();
441 osprintf(os, "isl::%s manage(__isl_take %s *ptr) {\n", cppname, name);
442 osprintf(os, " return %s(ptr);\n", cppname);
443 osprintf(os, "}\n");
446 /* Print implementations of private constructors for class "clazz" to "os".
448 void cpp_generator::print_private_constructors_impl(ostream &os,
449 const isl_class &clazz)
451 const char *name = clazz.name.c_str();
452 std::string cppstring = type2cpp(clazz);
453 const char *cppname = cppstring.c_str();
455 osprintf(os, "%s::%s(__isl_take %s *ptr)\n : ptr(ptr) {}\n",
456 cppname, cppname, name);
459 /* Print implementations of public constructors for class "clazz" to "os".
461 void cpp_generator::print_public_constructors_impl(ostream &os,
462 const isl_class &clazz)
464 const char *name = clazz.name.c_str();
465 std::string cppstring = type2cpp(clazz);
466 const char *cppname = cppstring.c_str();
468 osprintf(os, "%s::%s()\n : ptr(nullptr) {}\n\n", cppname, cppname);
469 osprintf(os, "%s::%s(const isl::%s &obj)\n : ptr(obj.copy()) {}\n",
470 cppname, cppname, cppname, name);
473 /* Print implementations of constructors for class "clazz" to "os".
475 void cpp_generator::print_constructors_impl(ostream &os,
476 const isl_class &clazz)
478 set<FunctionDecl *>::const_iterator in;
479 const set<FunctionDecl *> constructors = clazz.constructors;
481 for (in = constructors.begin(); in != constructors.end(); ++in) {
482 FunctionDecl *cons = *in;
483 string fullname = cons->getName();
484 function_kind kind = function_kind_constructor;
486 print_method_impl(os, clazz, fullname, cons, kind);
490 /* Print implementation of copy assignment operator for class "clazz" to "os".
492 void cpp_generator::print_copy_assignment_impl(ostream &os,
493 const isl_class &clazz)
495 const char *name = clazz.name.c_str();
496 std::string cppstring = type2cpp(clazz);
497 const char *cppname = cppstring.c_str();
499 osprintf(os, "%s &%s::operator=(isl::%s obj) {\n", cppname,
500 cppname, cppname);
501 osprintf(os, " std::swap(this->ptr, obj.ptr);\n", name);
502 osprintf(os, " return *this;\n");
503 osprintf(os, "}\n");
506 /* Print implementation of destructor for class "clazz" to "os".
508 void cpp_generator::print_destructor_impl(ostream &os,
509 const isl_class &clazz)
511 const char *name = clazz.name.c_str();
512 std::string cppstring = type2cpp(clazz);
513 const char *cppname = cppstring.c_str();
515 osprintf(os, "%s::~%s() {\n", cppname, cppname);
516 osprintf(os, " if (ptr)\n");
517 osprintf(os, " %s_free(ptr);\n", name);
518 osprintf(os, "}\n");
521 /* Print implementation of ptr() functions for class "clazz" to "os".
523 void cpp_generator::print_ptr_impl(ostream &os, const isl_class &clazz)
525 const char *name = clazz.name.c_str();
526 std::string cppstring = type2cpp(clazz);
527 const char *cppname = cppstring.c_str();
529 osprintf(os, "__isl_give %s *%s::copy() const & {\n", name, cppname);
530 osprintf(os, " return %s_copy(ptr);\n", name);
531 osprintf(os, "}\n\n");
532 osprintf(os, "__isl_keep %s *%s::get() const {\n", name, cppname);
533 osprintf(os, " return ptr;\n");
534 osprintf(os, "}\n\n");
535 osprintf(os, "__isl_give %s *%s::release() {\n", name, cppname);
536 osprintf(os, " %s *tmp = ptr;\n", name);
537 osprintf(os, " ptr = nullptr;\n");
538 osprintf(os, " return tmp;\n");
539 osprintf(os, "}\n\n");
540 osprintf(os, "bool %s::is_null() const {\n", cppname);
541 osprintf(os, " return ptr == nullptr;\n");
542 osprintf(os, "}\n");
545 /* Print definitions for methods of class "clazz" to "os".
547 void cpp_generator::print_methods_impl(ostream &os, const isl_class &clazz)
549 map<string, set<FunctionDecl *> >::const_iterator it;
550 bool first = true;
552 for (it = clazz.methods.begin(); it != clazz.methods.end(); ++it) {
553 if (first)
554 first = false;
555 else
556 osprintf(os, "\n");
557 print_method_group_impl(os, clazz, it->first, it->second);
561 /* Print definitions for methods "methods" of name "fullname" in class "clazz"
562 * to "os".
564 * "fullname" is the name of the generated C++ method. It commonly corresponds
565 * to the isl name, with the object type prefix dropped.
566 * In case of overloaded methods, the result type suffix has also been removed.
568 * "kind" specifies the kind of method that should be generated.
570 void cpp_generator::print_method_group_impl(ostream &os, const isl_class &clazz,
571 const string &fullname, const set<FunctionDecl *> &methods)
573 set<FunctionDecl *>::const_iterator it;
574 bool first = true;
576 for (it = methods.begin(); it != methods.end(); ++it) {
577 function_kind kind;
578 if (first)
579 first = false;
580 else
581 osprintf(os, "\n");
582 kind = get_method_kind(clazz, *it);
583 print_method_impl(os, clazz, fullname, *it, kind);
587 /* Print the use of "param" to "os".
589 * "load_from_this_ptr" specifies whether the parameter should be loaded from
590 * the this-ptr. In case a value is loaded from a this pointer, the original
591 * value must be preserved and must consequently be copied. Values that are
592 * loaded from parameters do not need to be preserved, as such values will
593 * already be copies of the actual parameters. It is consequently possible
594 * to directly take the pointer from these values, which saves
595 * an unnecessary copy.
597 * In case the parameter is a callback function, two parameters get printed,
598 * a wrapper for the callback function and a pointer to the actual
599 * callback function. The wrapper is expected to be available
600 * in a previously declared variable <name>_lambda, while
601 * the actual callback function is expected in <name>_p.
602 * The caller of this function must ensure that these variables exist.
604 void cpp_generator::print_method_param_use(ostream &os, ParmVarDecl *param,
605 bool load_from_this_ptr)
607 string name = param->getName().str();
608 const char *name_str = name.c_str();
609 QualType type = param->getOriginalType();
611 if (type->isIntegerType()) {
612 osprintf(os, "%s", name_str);
613 return;
616 if (is_string(type)) {
617 osprintf(os, "%s.c_str()", name_str);
618 return;
621 if (is_callback(type)) {
622 osprintf(os, "%s_lambda, ", name_str);
623 osprintf(os, "&%s_p", name_str);
624 return;
627 if (!load_from_this_ptr && !is_callback(type))
628 osprintf(os, "%s.", name_str);
630 if (keeps(param)) {
631 osprintf(os, "get()");
632 } else {
633 if (load_from_this_ptr)
634 osprintf(os, "copy()");
635 else
636 osprintf(os, "release()");
640 /* Print definition for "method" in class "clazz" to "os".
642 * "fullname" is the name of the generated C++ method. It commonly corresponds
643 * to the isl name, with the object type prefix dropped.
644 * In case of overloaded methods, the result type suffix has also been removed.
646 * "kind" specifies the kind of method that should be generated.
648 * This method distinguishes three kinds of methods: member methods, static
649 * methods, and constructors.
651 * Member methods call "method" by passing to the underlying isl function the
652 * isl object belonging to "this" as first argument and the remaining arguments
653 * as subsequent arguments. The result of the isl function is returned as a new
654 * object if the underlying isl function returns an isl_* ptr or an isl_bool
655 * value, as std::string if the isl function returns 'const char *', and as
656 * unmodified return value otherwise.
658 * Static methods call "method" by passing all arguments to the underlying isl
659 * function, as no this-pointer is available. The result is a newly managed
660 * isl C++ object.
662 * Constructors create a new object from a given set of input parameters. They
663 * do not return a value, but instead update the pointer stored inside the
664 * newly created object.
666 * If the method has a callback argument, we reduce the number of parameters
667 * that are exposed by one to hide the user pointer from the interface. On
668 * the C++ side no user pointer is needed, as arguments can be forwarded
669 * as part of the std::function argument which specifies the callback function.
671 void cpp_generator::print_method_impl(ostream &os, const isl_class &clazz,
672 const string &fullname, FunctionDecl *method, function_kind kind)
674 string cname = fullname.substr(clazz.name.length() + 1);
675 string methodname = method->getName();
676 int num_params = method->getNumParams();
677 QualType return_type = method->getReturnType();
678 string rettype_str = type2cpp(return_type);
679 bool has_callback = false;
681 print_method_header(os, clazz, method, fullname, false, kind);
683 for (int i = 0; i < num_params; ++i) {
684 ParmVarDecl *param = method->getParamDecl(i);
685 if (is_callback(param->getType())) {
686 has_callback = true;
687 num_params -= 1;
688 print_callback_local(os, param);
692 osprintf(os, " auto res = %s(", methodname.c_str());
694 for (int i = 0; i < num_params; ++i) {
695 ParmVarDecl *param = method->getParamDecl(i);
696 bool load_from_this_ptr = false;
698 if (i == 0 && kind == function_kind_member_method)
699 load_from_this_ptr = true;
701 print_method_param_use(os, param, load_from_this_ptr);
703 if (i != num_params - 1)
704 osprintf(os, ", ");
706 osprintf(os, ");\n");
708 if (kind == function_kind_constructor) {
709 osprintf(os, " ptr = res;\n");
710 } else if (is_isl_type(return_type) || is_isl_bool(return_type)) {
711 osprintf(os, " return manage(res);\n");
712 } else if (has_callback) {
713 osprintf(os, " return %s(res);\n", rettype_str.c_str());
714 } else if (is_string(return_type)) {
715 osprintf(os, " std::string tmp(res);\n");
716 if (gives(method))
717 osprintf(os, " free(res);\n");
718 osprintf(os, " return tmp;\n");
719 } else {
720 osprintf(os, " return res;\n");
723 osprintf(os, "}\n");
726 /* Print the header for "method" in class "clazz" to "os".
728 * Print the header of a declaration if "is_declaration" is set, otherwise print
729 * the header of a method definition.
731 * "fullname" is the name of the generated C++ method. It commonly corresponds
732 * to the isl name, with the object type prefix dropped.
733 * In case of overloaded methods, the result type suffix has also been removed.
735 * "kind" specifies the kind of method that should be generated.
737 * This function prints headers for member methods, static methods, and
738 * constructors, either for their declaration or definition.
740 * Member functions are declared as "const", as they do not change the current
741 * object, but instead create a new object. They always retrieve the first
742 * parameter of the original isl function from the this-pointer of the object,
743 * such that only starting at the second parameter the parameters of the
744 * original function become part of the method's interface.
746 * A function
748 * __isl_give isl_set *isl_set_intersect(__isl_take isl_set *s1,
749 * __isl_take isl_set *s2);
751 * is translated into:
753 * inline isl::set intersect(isl::set set2) const;
755 * For static functions and constructors all parameters of the original isl
756 * function are exposed.
758 * Parameters that are defined as __isl_keep or are of type string, are passed
759 * as const reference, which allows the compiler to optimize the parameter
760 * transfer.
762 * Constructors are marked as explicit using the C++ keyword 'explicit' or as
763 * implicit using a comment in place of the explicit keyword. By annotating
764 * implicit constructors with a comment, users of the interface are made
765 * aware of the potential danger that implicit construction is possible
766 * for these constructors, whereas without a comment not every user would
767 * know that implicit construction is allowed in absence of an explicit keyword.
769 void cpp_generator::print_method_header(ostream &os, const isl_class &clazz,
770 FunctionDecl *method, const string &fullname, bool is_declaration,
771 function_kind kind)
773 string cname = fullname.substr(clazz.name.length() + 1);
774 string rettype_str = type2cpp(method->getReturnType());
775 string classname = type2cpp(clazz);
776 int num_params = method->getNumParams();
777 int first_param = 0;
779 cname = rename_method(cname);
780 if (kind == function_kind_member_method)
781 first_param = 1;
783 if (is_declaration) {
784 osprintf(os, " ");
786 if (kind == function_kind_static_method)
787 osprintf(os, "static ");
789 osprintf(os, "inline ");
791 if (kind == function_kind_constructor) {
792 if (is_implicit_conversion(clazz, method))
793 osprintf(os, "/* implicit */ ");
794 else
795 osprintf(os, "explicit ");
799 if (kind != function_kind_constructor)
800 osprintf(os, "%s ", rettype_str.c_str());
802 if (!is_declaration)
803 osprintf(os, "%s::", classname.c_str());
805 if (kind != function_kind_constructor)
806 osprintf(os, "%s", cname.c_str());
807 else
808 osprintf(os, "%s", classname.c_str());
810 osprintf(os, "(");
812 for (int i = first_param; i < num_params; ++i) {
813 ParmVarDecl *param = method->getParamDecl(i);
814 QualType type = param->getOriginalType();
815 string cpptype = type2cpp(type);
817 if (is_callback(type))
818 num_params--;
820 if (keeps(param) || is_string(type) || is_callback(type))
821 osprintf(os, "const %s &%s", cpptype.c_str(),
822 param->getName().str().c_str());
823 else
824 osprintf(os, "%s %s", cpptype.c_str(),
825 param->getName().str().c_str());
827 if (i != num_params - 1)
828 osprintf(os, ", ");
831 osprintf(os, ")");
833 if (kind == function_kind_member_method)
834 osprintf(os, " const");
836 if (is_declaration)
837 osprintf(os, ";\n");
838 else
839 osprintf(os, " {\n");
842 /* Generate the list of argument types for a callback function of
843 * type "type". If "cpp" is set, then generate the C++ type list, otherwise
844 * the C type list.
846 * For a callback of type
848 * isl_stat (*)(__isl_take isl_map *map, void *user)
850 * the following C++ argument list is generated:
852 * isl::map
854 string cpp_generator::generate_callback_args(QualType type, bool cpp)
856 std::string type_str;
857 const FunctionProtoType *callback;
858 int num_params;
860 callback = type->getPointeeType()->getAs<FunctionProtoType>();
861 num_params = callback->getNumArgs();
862 if (cpp)
863 num_params--;
865 for (long i = 0; i < num_params; i++) {
866 QualType type = callback->getArgType(i);
868 if (cpp)
869 type_str += type2cpp(type);
870 else
871 type_str += type.getAsString();
873 if (!cpp)
874 type_str += "arg_" + ::to_string(i);
876 if (i != num_params - 1)
877 type_str += ", ";
880 return type_str;
883 /* Generate the full cpp type of a callback function of type "type".
885 * For a callback of type
887 * isl_stat (*)(__isl_take isl_map *map, void *user)
889 * the following type is generated:
891 * std::function<isl::stat(isl::map)>
893 string cpp_generator::generate_callback_type(QualType type)
895 std::string type_str;
896 const FunctionProtoType *callback = type->getPointeeType()->getAs<FunctionProtoType>();
897 QualType return_type = callback->getReturnType();
898 string rettype_str = type2cpp(return_type);
900 type_str = "std::function<";
901 type_str += rettype_str;
902 type_str += "(";
903 type_str += generate_callback_args(type, true);
904 type_str += ")>";
906 return type_str;
909 /* Print the local variables that are needed for a callback argument,
910 * in particular, print a lambda function that wraps the callback and
911 * a pointer to the actual C++ callback function.
913 * For a callback of the form
915 * isl_stat (*fn)(__isl_take isl_map *map, void *user)
917 * the following lambda function is generated:
919 * auto fn_lambda = [](isl_map *arg_0, void *arg_1) -> isl_stat {
920 * auto *func = *static_cast<const std::function<stat(map)> **>(arg_1);
921 * stat ret = (*func)(isl::manage(arg_0));
922 * return isl_stat(ret);
923 * };
925 * The pointer to the std::function C++ callback function is stored in fn_p.
926 * This std::function object represents the actual user
927 * callback function together with the locally captured state at the caller.
929 * The lambda function is expected to be used as a C callback function
930 * where the lambda itself is provided as the function pointer and
931 * where the user void pointer is a pointer to fn_p.
932 * The std::function object is extracted from the pointer to fn_p
933 * inside the lambda function.
934 * The double indirection is used to avoid having to worry about
935 * const casting.
937 void cpp_generator::print_callback_local(ostream &os, ParmVarDecl *param) {
938 string pname;
939 QualType ptype;
940 string call_args, c_args, cpp_args, rettype, last_idx;
941 const FunctionProtoType *callback;
942 int num_params;
944 pname = param->getName().str();
945 ptype = param->getType();
947 c_args = generate_callback_args(ptype, false);
948 cpp_args = generate_callback_type(ptype);
950 callback = ptype->getPointeeType()->getAs<FunctionProtoType>();
951 rettype = callback->getReturnType().getAsString();
952 num_params = callback->getNumArgs();
954 last_idx = ::to_string(num_params - 1);
956 for (long i = 0; i < num_params - 1; i++) {
957 call_args += "isl::manage(arg_" + ::to_string(i) + ")";
958 if (i != num_params - 2)
959 call_args += ", ";
962 osprintf(os, " auto %s_p = &fn;\n", pname.c_str());
963 osprintf(os,
964 " auto %s_lambda = [](%s) -> %s {\n"
965 " auto *func = *static_cast<const %s **>(arg_%s);\n"
966 " stat ret = (*func)(%s);\n"
967 " return isl_stat(ret);\n"
968 " };\n",
969 pname.c_str(), c_args.c_str(), rettype.c_str(),
970 cpp_args.c_str(), last_idx.c_str(), call_args.c_str());
973 /* An array listing functions that must be renamed and the function name they
974 * should be renamed to. We currently rename functions in case their name would
975 * match a reserved C++ keyword, which is not allowed in C++.
977 static const char *rename_map[][2] = {
978 { "union", "unite" },
981 /* Rename method "name" in case the method name in the C++ bindings should not
982 * match the name in the C bindings. We do this for example to avoid
983 * C++ keywords.
985 std::string cpp_generator::rename_method(std::string name)
987 for (size_t i = 0; i < sizeof(rename_map) / sizeof(rename_map[0]); i++)
988 if (name.compare(rename_map[i][0]) == 0)
989 return rename_map[i][1];
991 return name;
994 /* Translate isl class "clazz" to its corresponding C++ type.
996 string cpp_generator::type2cpp(const isl_class &clazz)
998 return type2cpp(clazz.name);
1001 /* Translate type string "type_str" to its C++ name counterpart.
1003 string cpp_generator::type2cpp(string type_str)
1005 return type_str.substr(4);
1008 /* Translate QualType "type" to its C++ name counterpart.
1010 string cpp_generator::type2cpp(QualType type)
1012 if (is_isl_type(type))
1013 return "isl::" + type2cpp(type->getPointeeType().getAsString());
1015 if (is_isl_bool(type))
1016 return "isl::boolean";
1018 if (is_isl_stat(type))
1019 return "isl::stat";
1021 if (type->isIntegerType())
1022 return type.getAsString();
1024 if (is_string(type))
1025 return "std::string";
1027 if (is_callback(type))
1028 return generate_callback_type(type);
1030 die("Cannot convert type to C++ type");
1033 /* Check if "subclass_type" is a subclass of "class_type".
1035 bool cpp_generator::is_subclass(QualType subclass_type,
1036 const isl_class &class_type)
1038 std::string type_str = subclass_type->getPointeeType().getAsString();
1039 std::vector<std::string> superclasses;
1040 std::vector<const isl_class *> parents;
1041 std::vector<std::string>::iterator ci;
1043 superclasses = generator::find_superclasses(classes[type_str].type);
1045 for (ci = superclasses.begin(); ci < superclasses.end(); ci++)
1046 parents.push_back(&classes[*ci]);
1048 while (!parents.empty()) {
1049 const isl_class *candidate = parents.back();
1051 parents.pop_back();
1053 if (&class_type == candidate)
1054 return true;
1056 superclasses = generator::find_superclasses(candidate->type);
1058 for (ci = superclasses.begin(); ci < superclasses.end(); ci++)
1059 parents.push_back(&classes[*ci]);
1062 return false;
1065 /* Check if "cons" is an implicit conversion constructor of class "clazz".
1067 * An implicit conversion constructor is generated in case "cons" has a single
1068 * parameter, where the parameter type is a subclass of the class that is
1069 * currently being generated.
1071 bool cpp_generator::is_implicit_conversion(const isl_class &clazz,
1072 FunctionDecl *cons)
1074 ParmVarDecl *param = cons->getParamDecl(0);
1075 QualType type = param->getOriginalType();
1077 int num_params = cons->getNumParams();
1078 if (num_params != 1)
1079 return false;
1081 if (is_isl_type(type) && !is_isl_ctx(type) && is_subclass(type, clazz))
1082 return true;
1084 return false;
1087 /* Get kind of "method" in "clazz".
1089 * Given the declaration of a static or member method, returns its kind.
1091 cpp_generator::function_kind cpp_generator::get_method_kind(
1092 const isl_class &clazz, FunctionDecl *method)
1094 if (is_static(clazz, method))
1095 return function_kind_static_method;
1096 else
1097 return function_kind_member_method;