isl_basic_map_make_strides_explicit: use isl_basic_map_var_offset
[isl.git] / interface / cpp.cc
blobc0448ab679c7c233d0b7bd1a1c7e039444d9ca24
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 * If checked C++ bindings are being generated,
83 * then wrap them in a namespace to avoid conflicts
84 * with the default C++ bindings (with automatic checks using exceptions).
86 void cpp_generator::generate()
88 ostream &os = cout;
90 osprintf(os, "\n");
91 osprintf(os, "namespace isl {\n\n");
92 if (checked)
93 osprintf(os, "namespace checked {\n\n");
95 print_forward_declarations(os);
96 osprintf(os, "\n");
97 print_declarations(os);
98 osprintf(os, "\n");
99 print_implementations(os);
101 if (checked)
102 osprintf(os, "} // namespace checked\n");
103 osprintf(os, "} // namespace isl\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 print_class_factory_decl(os, clazz, " friend ");
166 osprintf(os, "\n");
167 osprintf(os, " %s *ptr = nullptr;\n", name);
168 osprintf(os, "\n");
169 print_private_constructors_decl(os, clazz);
170 osprintf(os, "\n");
171 osprintf(os, "public:\n");
172 print_public_constructors_decl(os, clazz);
173 print_constructors_decl(os, clazz);
174 print_copy_assignment_decl(os, clazz);
175 print_destructor_decl(os, clazz);
176 print_ptr_decl(os, clazz);
177 print_get_ctx_decl(os);
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 functions to "os".
197 * Each class has two global factory functions:
199 * set manage(__isl_take isl_set *ptr);
200 * set manage_copy(__isl_keep isl_set *ptr);
202 * A user can construct isl C++ objects from a raw pointer and indicate whether
203 * they intend to take the ownership of the object or not through these global
204 * factory functions. This ensures isl object creation is very explicit and
205 * pointers are not converted by accident. Thanks to overloading, manage() and
206 * manage_copy() can be called on any isl raw pointer and the corresponding
207 * object is automatically created, without the user having to choose the right
208 * isl object type.
210 void cpp_generator::print_class_factory_decl(ostream &os,
211 const isl_class &clazz, const std::string &prefix)
213 const char *name = clazz.name.c_str();
214 std::string cppstring = type2cpp(clazz);
215 const char *cppname = cppstring.c_str();
217 os << prefix;
218 osprintf(os, "inline %s manage(__isl_take %s *ptr);\n", cppname, name);
219 os << prefix;
220 osprintf(os, "inline %s manage_copy(__isl_keep %s *ptr);\n",
221 cppname, name);
224 /* Print declarations of private constructors for class "clazz" to "os".
226 * Each class has currently one private constructor:
228 * 1) Constructor from a plain isl_* C pointer
230 * Example:
232 * set(__isl_take isl_set *ptr);
234 * The raw pointer constructor is kept private. Object creation is only
235 * possible through manage() or manage_copy().
237 void cpp_generator::print_private_constructors_decl(ostream &os,
238 const isl_class &clazz)
240 const char *name = clazz.name.c_str();
241 std::string cppstring = type2cpp(clazz);
242 const char *cppname = cppstring.c_str();
244 osprintf(os, " inline explicit %s(__isl_take %s *ptr);\n", cppname,
245 name);
248 /* Print declarations of public constructors for class "clazz" to "os".
250 * Each class currently has two public constructors:
252 * 1) A default constructor
253 * 2) A copy constructor
255 * Example:
257 * set();
258 * set(const set &set);
260 void cpp_generator::print_public_constructors_decl(ostream &os,
261 const isl_class &clazz)
263 std::string cppstring = type2cpp(clazz);
264 const char *cppname = cppstring.c_str();
265 osprintf(os, " inline /* implicit */ %s();\n", cppname);
267 osprintf(os, " inline /* implicit */ %s(const %s &obj);\n",
268 cppname, cppname);
271 /* Print declarations for constructors for class "class" to "os".
273 * For each isl function that is marked as __isl_constructor,
274 * add a corresponding C++ constructor.
276 * Example:
278 * inline /\* implicit *\/ union_set(basic_set bset);
279 * inline /\* implicit *\/ union_set(set set);
280 * inline explicit val(ctx ctx, long i);
281 * inline explicit val(ctx ctx, const std::string &str);
283 void cpp_generator::print_constructors_decl(ostream &os,
284 const isl_class &clazz)
286 set<FunctionDecl *>::const_iterator in;
287 const set<FunctionDecl *> &constructors = clazz.constructors;
289 for (in = constructors.begin(); in != constructors.end(); ++in) {
290 FunctionDecl *cons = *in;
292 print_method_decl(os, clazz, cons, function_kind_constructor);
296 /* Print declarations of copy assignment operator for class "clazz"
297 * to "os".
299 * Each class has one assignment operator.
301 * isl:set &set::operator=(set obj)
304 void cpp_generator::print_copy_assignment_decl(ostream &os,
305 const isl_class &clazz)
307 std::string cppstring = type2cpp(clazz);
308 const char *cppname = cppstring.c_str();
310 osprintf(os, " inline %s &operator=(%s obj);\n", cppname, cppname);
313 /* Print declaration of destructor for class "clazz" to "os".
315 void cpp_generator::print_destructor_decl(ostream &os, const isl_class &clazz)
317 std::string cppstring = type2cpp(clazz);
318 const char *cppname = cppstring.c_str();
320 osprintf(os, " inline ~%s();\n", cppname);
323 /* Print declaration of pointer functions for class "clazz" to "os".
325 * To obtain a raw pointer three functions are provided:
327 * 1) __isl_give isl_set *copy()
329 * Returns a pointer to a _copy_ of the internal object
331 * 2) __isl_keep isl_set *get()
333 * Returns a pointer to the internal object
335 * 3) __isl_give isl_set *release()
337 * Returns a pointer to the internal object and resets the
338 * internal pointer to nullptr.
340 * We also provide functionality to explicitly check if a pointer is
341 * currently managed by this object.
343 * 4) bool is_null()
345 * Check if the current object is a null pointer.
347 * The functions get() and release() model the value_ptr proposed in
348 * http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2012/n3339.pdf.
349 * The copy() function is an extension to allow the user to explicitly
350 * copy the underlying object.
352 * Also generate a declaration to delete copy() for r-values, for
353 * r-values release() should be used to avoid unnecessary copies.
355 void cpp_generator::print_ptr_decl(ostream &os, const isl_class &clazz)
357 const char *name = clazz.name.c_str();
359 osprintf(os, " inline __isl_give %s *copy() const &;\n", name);
360 osprintf(os, " inline __isl_give %s *copy() && = delete;\n", name);
361 osprintf(os, " inline __isl_keep %s *get() const;\n", name);
362 osprintf(os, " inline __isl_give %s *release();\n", name);
363 osprintf(os, " inline bool is_null() const;\n");
366 /* Print the declaration of the get_ctx method.
368 void cpp_generator::print_get_ctx_decl(ostream &os)
370 osprintf(os, " inline ctx get_ctx() const;\n");
373 /* Print declarations for methods in class "clazz" to "os".
375 void cpp_generator::print_methods_decl(ostream &os, const isl_class &clazz)
377 map<string, set<FunctionDecl *> >::const_iterator it;
379 for (it = clazz.methods.begin(); it != clazz.methods.end(); ++it)
380 print_method_group_decl(os, clazz, it->second);
383 /* Print declarations for methods "methods" in class "clazz" to "os".
385 void cpp_generator::print_method_group_decl(ostream &os, const isl_class &clazz,
386 const set<FunctionDecl *> &methods)
388 set<FunctionDecl *>::const_iterator it;
390 for (it = methods.begin(); it != methods.end(); ++it) {
391 function_kind kind = get_method_kind(clazz, *it);
392 print_method_decl(os, clazz, *it, kind);
396 /* Print declarations for "method" in class "clazz" to "os".
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 FunctionDecl *method, function_kind kind)
403 print_method_header(os, clazz, method, 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_get_ctx_impl(os, clazz);
430 osprintf(os, "\n");
431 print_methods_impl(os, clazz);
432 print_stream_insertion(os, clazz);
435 /* Print code for throwing an exception corresponding to the last error
436 * that occurred on "ctx".
437 * This assumes that a valid isl::ctx is available in the "ctx" variable,
438 * e.g., through a prior call to print_save_ctx.
440 static void print_throw_last_error(ostream &os)
442 osprintf(os, " exception::throw_last_error(ctx);\n");
445 /* Print code for throwing an exception on NULL input.
447 static void print_throw_NULL_input(ostream &os)
449 osprintf(os, " exception::throw_NULL_input(__FILE__, __LINE__);\n");
452 /* Print an operator for inserting objects of "class"
453 * into an output stream.
455 * Unless checked C++ bindings are being generated,
456 * the operator requires its argument to be non-NULL.
457 * An exception is thrown if anything went wrong during the printing.
458 * During this printing, isl is made not to print any error message
459 * because the error message is included in the exception.
461 * If checked C++ bindings are being generated and anything went wrong,
462 * then record this failure in the output stream.
464 void cpp_generator::print_stream_insertion(ostream &os, 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 if (!clazz.fn_to_str)
471 return;
473 osprintf(os, "\n");
474 osprintf(os, "inline std::ostream &operator<<(std::ostream &os, ");
475 osprintf(os, "const %s &obj)\n", cppname);
476 osprintf(os, "{\n");
477 print_check_ptr_start(os, clazz, "obj.get()");
478 osprintf(os, " char *str = %s_to_str(obj.get());\n", name);
479 print_check_ptr_end(os, "str");
480 if (checked) {
481 osprintf(os, " if (!str) {\n");
482 osprintf(os, " os.setstate(std::ios_base::badbit);\n");
483 osprintf(os, " return os;\n");
484 osprintf(os, " }\n");
486 osprintf(os, " os << str;\n");
487 osprintf(os, " free(str);\n");
488 osprintf(os, " return os;\n");
489 osprintf(os, "}\n");
492 /* Print code that checks that "ptr" is not NULL at input.
494 * Omit the check if checked C++ bindings are being generated.
496 void cpp_generator::print_check_ptr(ostream &os, const char *ptr)
498 if (checked)
499 return;
501 osprintf(os, " if (!%s)\n", ptr);
502 print_throw_NULL_input(os);
505 /* Print code that checks that "ptr" is not NULL at input and
506 * that saves a copy of the isl_ctx of "ptr" for a later check.
508 * Omit the check if checked C++ bindings are being generated.
510 void cpp_generator::print_check_ptr_start(ostream &os, const isl_class &clazz,
511 const char *ptr)
513 if (checked)
514 return;
516 print_check_ptr(os, ptr);
517 osprintf(os, " auto ctx = %s_get_ctx(%s);\n", clazz.name.c_str(), ptr);
518 print_on_error_continue(os);
521 /* Print code that checks that "ptr" is not NULL at the end.
522 * A copy of the isl_ctx is expected to have been saved by
523 * code generated by print_check_ptr_start.
525 * Omit the check if checked C++ bindings are being generated.
527 void cpp_generator::print_check_ptr_end(ostream &os, const char *ptr)
529 if (checked)
530 return;
532 osprintf(os, " if (!%s)\n", ptr);
533 print_throw_last_error(os);
536 /* Print implementation of global factory functions to "os".
538 * Each class has two global factory functions:
540 * set manage(__isl_take isl_set *ptr);
541 * set manage_copy(__isl_keep isl_set *ptr);
543 * Unless checked C++ bindings are being generated,
544 * both functions require the argument to be non-NULL.
545 * An exception is thrown if anything went wrong during the copying
546 * in manage_copy.
547 * During the copying, isl is made not to print any error message
548 * because the error message is included in the exception.
550 void cpp_generator::print_class_factory_impl(ostream &os,
551 const isl_class &clazz)
553 const char *name = clazz.name.c_str();
554 std::string cppstring = type2cpp(clazz);
555 const char *cppname = cppstring.c_str();
557 osprintf(os, "%s manage(__isl_take %s *ptr) {\n", cppname, name);
558 print_check_ptr(os, "ptr");
559 osprintf(os, " return %s(ptr);\n", cppname);
560 osprintf(os, "}\n");
562 osprintf(os, "%s manage_copy(__isl_keep %s *ptr) {\n", cppname,
563 name);
564 print_check_ptr_start(os, clazz, "ptr");
565 osprintf(os, " ptr = %s_copy(ptr);\n", name);
566 print_check_ptr_end(os, "ptr");
567 osprintf(os, " return %s(ptr);\n", cppname);
568 osprintf(os, "}\n");
571 /* Print implementations of private constructors for class "clazz" to "os".
573 void cpp_generator::print_private_constructors_impl(ostream &os,
574 const isl_class &clazz)
576 const char *name = clazz.name.c_str();
577 std::string cppstring = type2cpp(clazz);
578 const char *cppname = cppstring.c_str();
580 osprintf(os, "%s::%s(__isl_take %s *ptr)\n : ptr(ptr) {}\n",
581 cppname, cppname, name);
584 /* Print implementations of public constructors for class "clazz" to "os".
586 * Throw an exception from the copy constructor if anything went wrong
587 * during the copying or if the input is NULL.
588 * During the copying, isl is made not to print any error message
589 * because the error message is included in the exception.
590 * No exceptions are thrown if checked C++ bindings
591 * are being generated,
593 void cpp_generator::print_public_constructors_impl(ostream &os,
594 const isl_class &clazz)
596 std::string cppstring = type2cpp(clazz);
597 const char *cppname = cppstring.c_str();
599 osprintf(os, "%s::%s()\n : ptr(nullptr) {}\n\n", cppname, cppname);
600 osprintf(os, "%s::%s(const %s &obj)\n : ptr(nullptr)\n",
601 cppname, cppname, cppname);
602 osprintf(os, "{\n");
603 print_check_ptr_start(os, clazz, "obj.ptr");
604 osprintf(os, " ptr = obj.copy();\n");
605 print_check_ptr_end(os, "ptr");
606 osprintf(os, "}\n");
609 /* Print implementations of constructors for class "clazz" to "os".
611 void cpp_generator::print_constructors_impl(ostream &os,
612 const isl_class &clazz)
614 set<FunctionDecl *>::const_iterator in;
615 const set<FunctionDecl *> constructors = clazz.constructors;
617 for (in = constructors.begin(); in != constructors.end(); ++in) {
618 FunctionDecl *cons = *in;
620 print_method_impl(os, clazz, cons, function_kind_constructor);
624 /* Print implementation of copy assignment operator for class "clazz" to "os".
626 void cpp_generator::print_copy_assignment_impl(ostream &os,
627 const isl_class &clazz)
629 const char *name = clazz.name.c_str();
630 std::string cppstring = type2cpp(clazz);
631 const char *cppname = cppstring.c_str();
633 osprintf(os, "%s &%s::operator=(%s obj) {\n", cppname,
634 cppname, cppname);
635 osprintf(os, " std::swap(this->ptr, obj.ptr);\n", name);
636 osprintf(os, " return *this;\n");
637 osprintf(os, "}\n");
640 /* Print implementation of destructor for class "clazz" to "os".
642 void cpp_generator::print_destructor_impl(ostream &os,
643 const isl_class &clazz)
645 const char *name = clazz.name.c_str();
646 std::string cppstring = type2cpp(clazz);
647 const char *cppname = cppstring.c_str();
649 osprintf(os, "%s::~%s() {\n", cppname, cppname);
650 osprintf(os, " if (ptr)\n");
651 osprintf(os, " %s_free(ptr);\n", name);
652 osprintf(os, "}\n");
655 /* Print implementation of ptr() functions for class "clazz" to "os".
657 void cpp_generator::print_ptr_impl(ostream &os, const isl_class &clazz)
659 const char *name = clazz.name.c_str();
660 std::string cppstring = type2cpp(clazz);
661 const char *cppname = cppstring.c_str();
663 osprintf(os, "__isl_give %s *%s::copy() const & {\n", name, cppname);
664 osprintf(os, " return %s_copy(ptr);\n", name);
665 osprintf(os, "}\n\n");
666 osprintf(os, "__isl_keep %s *%s::get() const {\n", name, cppname);
667 osprintf(os, " return ptr;\n");
668 osprintf(os, "}\n\n");
669 osprintf(os, "__isl_give %s *%s::release() {\n", name, cppname);
670 osprintf(os, " %s *tmp = ptr;\n", name);
671 osprintf(os, " ptr = nullptr;\n");
672 osprintf(os, " return tmp;\n");
673 osprintf(os, "}\n\n");
674 osprintf(os, "bool %s::is_null() const {\n", cppname);
675 osprintf(os, " return ptr == nullptr;\n");
676 osprintf(os, "}\n");
679 /* Print the implementation of the get_ctx method.
681 void cpp_generator::print_get_ctx_impl(ostream &os, const isl_class &clazz)
683 const char *name = clazz.name.c_str();
684 std::string cppstring = type2cpp(clazz);
685 const char *cppname = cppstring.c_str();
687 osprintf(os, "ctx %s::get_ctx() const {\n", cppname);
688 osprintf(os, " return ctx(%s_get_ctx(ptr));\n", name);
689 osprintf(os, "}\n");
692 /* Print definitions for methods of class "clazz" to "os".
694 void cpp_generator::print_methods_impl(ostream &os, const isl_class &clazz)
696 map<string, set<FunctionDecl *> >::const_iterator it;
697 bool first = true;
699 for (it = clazz.methods.begin(); it != clazz.methods.end(); ++it) {
700 if (first)
701 first = false;
702 else
703 osprintf(os, "\n");
704 print_method_group_impl(os, clazz, it->second);
708 /* Print definitions for methods "methods" in class "clazz" to "os".
710 * "kind" specifies the kind of method that should be generated.
712 void cpp_generator::print_method_group_impl(ostream &os, const isl_class &clazz,
713 const set<FunctionDecl *> &methods)
715 set<FunctionDecl *>::const_iterator it;
716 bool first = true;
718 for (it = methods.begin(); it != methods.end(); ++it) {
719 function_kind kind;
720 if (first)
721 first = false;
722 else
723 osprintf(os, "\n");
724 kind = get_method_kind(clazz, *it);
725 print_method_impl(os, clazz, *it, kind);
729 /* Print the use of "param" to "os".
731 * "load_from_this_ptr" specifies whether the parameter should be loaded from
732 * the this-ptr. In case a value is loaded from a this pointer, the original
733 * value must be preserved and must consequently be copied. Values that are
734 * loaded from parameters do not need to be preserved, as such values will
735 * already be copies of the actual parameters. It is consequently possible
736 * to directly take the pointer from these values, which saves
737 * an unnecessary copy.
739 * In case the parameter is a callback function, two parameters get printed,
740 * a wrapper for the callback function and a pointer to the actual
741 * callback function. The wrapper is expected to be available
742 * in a previously declared variable <name>_lambda, while
743 * the actual callback function is expected to be stored
744 * in a structure called <name>_data.
745 * The caller of this function must ensure that these variables exist.
747 void cpp_generator::print_method_param_use(ostream &os, ParmVarDecl *param,
748 bool load_from_this_ptr)
750 string name = param->getName().str();
751 const char *name_str = name.c_str();
752 QualType type = param->getOriginalType();
754 if (type->isIntegerType()) {
755 osprintf(os, "%s", name_str);
756 return;
759 if (is_string(type)) {
760 osprintf(os, "%s.c_str()", name_str);
761 return;
764 if (is_callback(type)) {
765 osprintf(os, "%s_lambda, ", name_str);
766 osprintf(os, "&%s_data", name_str);
767 return;
770 if (!load_from_this_ptr && !is_callback(type))
771 osprintf(os, "%s.", name_str);
773 if (keeps(param)) {
774 osprintf(os, "get()");
775 } else {
776 if (load_from_this_ptr)
777 osprintf(os, "copy()");
778 else
779 osprintf(os, "release()");
783 /* Print code that checks that all isl object arguments to "method" are valid
784 * (not NULL) and throws an exception if they are not.
785 * "kind" specifies the kind of method that is being generated.
787 * If checked bindings are being generated,
788 * then no such check is performed.
790 void cpp_generator::print_argument_validity_check(ostream &os,
791 FunctionDecl *method, function_kind kind)
793 int n;
794 bool first = true;
796 if (checked)
797 return;
799 n = method->getNumParams();
800 for (int i = 0; i < n; ++i) {
801 bool is_this;
802 ParmVarDecl *param = method->getParamDecl(i);
803 string name = param->getName().str();
804 const char *name_str = name.c_str();
805 QualType type = param->getOriginalType();
807 is_this = i == 0 && kind == function_kind_member_method;
808 if (!is_this && (is_isl_ctx(type) || !is_isl_type(type)))
809 continue;
811 if (first)
812 osprintf(os, " if (");
813 else
814 osprintf(os, " || ");
816 if (is_this)
817 osprintf(os, "!ptr");
818 else
819 osprintf(os, "%s.is_null()", name_str);
821 first = false;
823 if (first)
824 return;
825 osprintf(os, ")\n");
826 print_throw_NULL_input(os);
829 /* Print code for saving a copy of the isl::ctx available at the start
830 * of the method "method" in a "ctx" variable, for use in exception handling.
831 * "kind" specifies what kind of method "method" is.
833 * If checked bindings are being generated,
834 * then the "ctx" variable is not needed.
835 * If "method" is a member function, then obtain the isl_ctx from
836 * the "this" object.
837 * If the first argument of the method is an isl::ctx, then use that one,
838 * assuming it is not already called "ctx".
839 * Otherwise, save a copy of the isl::ctx associated to the first argument
840 * of isl object type.
842 void cpp_generator::print_save_ctx(ostream &os, FunctionDecl *method,
843 function_kind kind)
845 int n;
846 ParmVarDecl *param = method->getParamDecl(0);
847 QualType type = param->getOriginalType();
849 if (checked)
850 return;
851 if (kind == function_kind_member_method) {
852 osprintf(os, " auto ctx = get_ctx();\n");
853 return;
855 if (is_isl_ctx(type)) {
856 const char *name;
858 name = param->getName().str().c_str();
859 if (strcmp(name, "ctx") != 0)
860 osprintf(os, " auto ctx = %s;\n", name);
861 return;
863 n = method->getNumParams();
864 for (int i = 0; i < n; ++i) {
865 ParmVarDecl *param = method->getParamDecl(i);
866 QualType type = param->getOriginalType();
868 if (!is_isl_type(type))
869 continue;
870 osprintf(os, " auto ctx = %s.get_ctx();\n",
871 param->getName().str().c_str());
872 return;
876 /* Print code to make isl not print an error message when an error occurs
877 * within the current scope (if exceptions are available),
878 * since the error message will be included in the exception.
879 * If exceptions are not available, then exception::on_error
880 * is set to ISL_ON_ERROR_ABORT and isl is therefore made to abort instead.
882 * If checked bindings are being generated,
883 * then leave it to the user to decide what isl should do on error.
884 * Otherwise, assume that a valid isl::ctx is available in the "ctx" variable,
885 * e.g., through a prior call to print_save_ctx.
887 void cpp_generator::print_on_error_continue(ostream &os)
889 if (checked)
890 return;
891 osprintf(os, " options_scoped_set_on_error saved_on_error(ctx, "
892 "exception::on_error);\n");
895 /* Print code that checks whether the execution of the core of "method"
896 * was successful.
898 * If checked bindings are being generated,
899 * then no checks are performed.
901 * Otherwise, first check if any of the callbacks failed with
902 * an exception. If so, the "eptr" in the corresponding data structure
903 * contains the exception that was caught and that needs to be rethrown.
904 * Then check if the function call failed in any other way and throw
905 * the appropriate exception.
906 * In particular, if the return type is isl_stat or isl_bool,
907 * then a negative value indicates a failure. If the return type
908 * is an isl type, then a NULL value indicates a failure.
909 * Assume print_save_ctx has made sure that a valid isl::ctx
910 * is available in the "ctx" variable.
912 void cpp_generator::print_exceptional_execution_check(ostream &os,
913 FunctionDecl *method)
915 int n;
916 bool check_null, check_neg;
917 QualType return_type = method->getReturnType();
919 if (checked)
920 return;
922 n = method->getNumParams();
923 for (int i = 0; i < n; ++i) {
924 ParmVarDecl *param = method->getParamDecl(i);
925 const char *name;
927 if (!is_callback(param->getOriginalType()))
928 continue;
929 name = param->getName().str().c_str();
930 osprintf(os, " if (%s_data.eptr)\n", name);
931 osprintf(os, " std::rethrow_exception(%s_data.eptr);\n",
932 name);
935 check_neg = is_isl_stat(return_type) || is_isl_bool(return_type);
936 check_null = is_isl_type(return_type);
937 if (!check_null && !check_neg)
938 return;
940 if (check_neg)
941 osprintf(os, " if (res < 0)\n");
942 else
943 osprintf(os, " if (!res)\n");
944 print_throw_last_error(os);
947 /* Print the return statement of the C++ method corresponding
948 * to the C function "method" in class "clazz" to "os".
950 * The result of the isl function is returned as a new
951 * object if the underlying isl function returns an isl_* ptr, as a bool
952 * if the isl function returns an isl_bool, as void if the isl functions
953 * returns an isl_stat,
954 * as std::string if the isl function returns 'const char *', and as
955 * unmodified return value otherwise.
956 * If checked C++ bindings are being generated,
957 * then an isl_bool return type is transformed into a boolean and
958 * an isl_stat into a stat since no exceptions can be generated
959 * on negative results from the isl function.
961 void cpp_generator::print_method_return(ostream &os, const isl_class &clazz,
962 FunctionDecl *method)
964 QualType return_type = method->getReturnType();
966 if (is_isl_type(return_type) ||
967 (checked &&
968 (is_isl_bool(return_type) || is_isl_stat(return_type)))) {
969 osprintf(os, " return manage(res);\n");
970 } else if (is_isl_stat(return_type)) {
971 osprintf(os, " return;\n");
972 } else if (is_string(return_type)) {
973 osprintf(os, " std::string tmp(res);\n");
974 if (gives(method))
975 osprintf(os, " free(res);\n");
976 osprintf(os, " return tmp;\n");
977 } else {
978 osprintf(os, " return res;\n");
982 /* Print definition for "method" in class "clazz" to "os".
984 * "kind" specifies the kind of method that should be generated.
986 * This method distinguishes three kinds of methods: member methods, static
987 * methods, and constructors.
989 * Member methods call "method" by passing to the underlying isl function the
990 * isl object belonging to "this" as first argument and the remaining arguments
991 * as subsequent arguments.
993 * Static methods call "method" by passing all arguments to the underlying isl
994 * function, as no this-pointer is available. The result is a newly managed
995 * isl C++ object.
997 * Constructors create a new object from a given set of input parameters. They
998 * do not return a value, but instead update the pointer stored inside the
999 * newly created object.
1001 * If the method has a callback argument, we reduce the number of parameters
1002 * that are exposed by one to hide the user pointer from the interface. On
1003 * the C++ side no user pointer is needed, as arguments can be forwarded
1004 * as part of the std::function argument which specifies the callback function.
1006 * Unless checked C++ bindings are being generated,
1007 * the inputs of the method are first checked for being valid isl objects and
1008 * a copy of the associated isl::ctx is saved (if needed).
1009 * If any failure occurs, either during the check for the inputs or
1010 * during the isl function call, an exception is thrown.
1011 * During the function call, isl is made not to print any error message
1012 * because the error message is included in the exception.
1014 void cpp_generator::print_method_impl(ostream &os, const isl_class &clazz,
1015 FunctionDecl *method, function_kind kind)
1017 string methodname = method->getName();
1018 int num_params = method->getNumParams();
1020 print_method_header(os, clazz, method, false, kind);
1021 osprintf(os, "{\n");
1022 print_argument_validity_check(os, method, kind);
1023 print_save_ctx(os, method, kind);
1024 print_on_error_continue(os);
1026 for (int i = 0; i < num_params; ++i) {
1027 ParmVarDecl *param = method->getParamDecl(i);
1028 if (is_callback(param->getType())) {
1029 num_params -= 1;
1030 print_callback_local(os, param);
1034 osprintf(os, " auto res = %s(", methodname.c_str());
1036 for (int i = 0; i < num_params; ++i) {
1037 ParmVarDecl *param = method->getParamDecl(i);
1038 bool load_from_this_ptr = false;
1040 if (i == 0 && kind == function_kind_member_method)
1041 load_from_this_ptr = true;
1043 print_method_param_use(os, param, load_from_this_ptr);
1045 if (i != num_params - 1)
1046 osprintf(os, ", ");
1048 osprintf(os, ");\n");
1050 print_exceptional_execution_check(os, method);
1051 if (kind == function_kind_constructor) {
1052 osprintf(os, " ptr = res;\n");
1053 } else {
1054 print_method_return(os, clazz, method);
1057 osprintf(os, "}\n");
1060 /* Print the header for "method" in class "clazz" to "os".
1062 * Print the header of a declaration if "is_declaration" is set, otherwise print
1063 * the header of a method definition.
1065 * "kind" specifies the kind of method that should be generated.
1067 * This function prints headers for member methods, static methods, and
1068 * constructors, either for their declaration or definition.
1070 * Member functions are declared as "const", as they do not change the current
1071 * object, but instead create a new object. They always retrieve the first
1072 * parameter of the original isl function from the this-pointer of the object,
1073 * such that only starting at the second parameter the parameters of the
1074 * original function become part of the method's interface.
1076 * A function
1078 * __isl_give isl_set *isl_set_intersect(__isl_take isl_set *s1,
1079 * __isl_take isl_set *s2);
1081 * is translated into:
1083 * inline set intersect(set set2) const;
1085 * For static functions and constructors all parameters of the original isl
1086 * function are exposed.
1088 * Parameters that are defined as __isl_keep or are of type string, are passed
1089 * as const reference, which allows the compiler to optimize the parameter
1090 * transfer.
1092 * Constructors are marked as explicit using the C++ keyword 'explicit' or as
1093 * implicit using a comment in place of the explicit keyword. By annotating
1094 * implicit constructors with a comment, users of the interface are made
1095 * aware of the potential danger that implicit construction is possible
1096 * for these constructors, whereas without a comment not every user would
1097 * know that implicit construction is allowed in absence of an explicit keyword.
1099 void cpp_generator::print_method_header(ostream &os, const isl_class &clazz,
1100 FunctionDecl *method, bool is_declaration, function_kind kind)
1102 string cname = clazz.method_name(method);
1103 string rettype_str = type2cpp(method->getReturnType());
1104 string classname = type2cpp(clazz);
1105 int num_params = method->getNumParams();
1106 int first_param = 0;
1108 cname = rename_method(cname);
1109 if (kind == function_kind_member_method)
1110 first_param = 1;
1112 if (is_declaration) {
1113 osprintf(os, " ");
1115 if (kind == function_kind_static_method)
1116 osprintf(os, "static ");
1118 osprintf(os, "inline ");
1120 if (kind == function_kind_constructor) {
1121 if (is_implicit_conversion(clazz, method))
1122 osprintf(os, "/* implicit */ ");
1123 else
1124 osprintf(os, "explicit ");
1128 if (kind != function_kind_constructor)
1129 osprintf(os, "%s ", rettype_str.c_str());
1131 if (!is_declaration)
1132 osprintf(os, "%s::", classname.c_str());
1134 if (kind != function_kind_constructor)
1135 osprintf(os, "%s", cname.c_str());
1136 else
1137 osprintf(os, "%s", classname.c_str());
1139 osprintf(os, "(");
1141 for (int i = first_param; i < num_params; ++i) {
1142 ParmVarDecl *param = method->getParamDecl(i);
1143 QualType type = param->getOriginalType();
1144 string cpptype = type2cpp(type);
1146 if (is_callback(type))
1147 num_params--;
1149 if (keeps(param) || is_string(type) || is_callback(type))
1150 osprintf(os, "const %s &%s", cpptype.c_str(),
1151 param->getName().str().c_str());
1152 else
1153 osprintf(os, "%s %s", cpptype.c_str(),
1154 param->getName().str().c_str());
1156 if (i != num_params - 1)
1157 osprintf(os, ", ");
1160 osprintf(os, ")");
1162 if (kind == function_kind_member_method)
1163 osprintf(os, " const");
1165 if (is_declaration)
1166 osprintf(os, ";");
1167 osprintf(os, "\n");
1170 /* Generate the list of argument types for a callback function of
1171 * type "type". If "cpp" is set, then generate the C++ type list, otherwise
1172 * the C type list.
1174 * For a callback of type
1176 * isl_stat (*)(__isl_take isl_map *map, void *user)
1178 * the following C++ argument list is generated:
1180 * map
1182 string cpp_generator::generate_callback_args(QualType type, bool cpp)
1184 std::string type_str;
1185 const FunctionProtoType *callback;
1186 int num_params;
1188 callback = extract_prototype(type);
1189 num_params = callback->getNumArgs();
1190 if (cpp)
1191 num_params--;
1193 for (long i = 0; i < num_params; i++) {
1194 QualType type = callback->getArgType(i);
1196 if (cpp)
1197 type_str += type2cpp(type);
1198 else
1199 type_str += type.getAsString();
1201 if (!cpp)
1202 type_str += "arg_" + ::to_string(i);
1204 if (i != num_params - 1)
1205 type_str += ", ";
1208 return type_str;
1211 /* Generate the full cpp type of a callback function of type "type".
1213 * For a callback of type
1215 * isl_stat (*)(__isl_take isl_map *map, void *user)
1217 * the following type is generated:
1219 * std::function<stat(map)>
1221 string cpp_generator::generate_callback_type(QualType type)
1223 std::string type_str;
1224 const FunctionProtoType *callback = extract_prototype(type);
1225 QualType return_type = callback->getReturnType();
1226 string rettype_str = type2cpp(return_type);
1228 type_str = "std::function<";
1229 type_str += rettype_str;
1230 type_str += "(";
1231 type_str += generate_callback_args(type, true);
1232 type_str += ")>";
1234 return type_str;
1237 /* Print the call to the C++ callback function "call", wrapped
1238 * for use inside the lambda function that is used as the C callback function,
1239 * in the case where checked C++ bindings are being generated.
1241 * In particular, print
1243 * stat ret = @call@;
1244 * return ret.release();
1246 void cpp_generator::print_wrapped_call_checked(ostream &os,
1247 const string &call)
1249 osprintf(os, " stat ret = %s;\n", call.c_str());
1250 osprintf(os, " return ret.release();\n");
1253 /* Print the call to the C++ callback function "call", wrapped
1254 * for use inside the lambda function that is used as the C callback function.
1256 * In particular, print
1258 * ISL_CPP_TRY {
1259 * @call@;
1260 * return isl_stat_ok;
1261 * } ISL_CPP_CATCH_ALL {
1262 * data->eptr = std::current_exception();
1263 * return isl_stat_error;
1266 * where ISL_CPP_TRY is defined to "try" and ISL_CPP_CATCH_ALL to "catch (...)"
1267 * (if exceptions are available).
1269 * If checked C++ bindings are being generated, then
1270 * the call is wrapped differently.
1272 void cpp_generator::print_wrapped_call(ostream &os, const string &call)
1274 if (checked)
1275 return print_wrapped_call_checked(os, call);
1277 osprintf(os, " ISL_CPP_TRY {\n");
1278 osprintf(os, " %s;\n", call.c_str());
1279 osprintf(os, " return isl_stat_ok;\n");
1280 osprintf(os, " } ISL_CPP_CATCH_ALL {\n"
1281 " data->eptr = std::current_exception();\n");
1282 osprintf(os, " return isl_stat_error;\n");
1283 osprintf(os, " }\n");
1286 /* Print the local variables that are needed for a callback argument,
1287 * in particular, print a lambda function that wraps the callback and
1288 * a pointer to the actual C++ callback function.
1290 * For a callback of the form
1292 * isl_stat (*fn)(__isl_take isl_map *map, void *user)
1294 * the following lambda function is generated:
1296 * auto fn_lambda = [](isl_map *arg_0, void *arg_1) -> isl_stat {
1297 * auto *data = static_cast<struct fn_data *>(arg_1);
1298 * try {
1299 * stat ret = (*data->func)(manage(arg_0));
1300 * return isl_stat_ok;
1301 * } catch (...) {
1302 * data->eptr = std::current_exception();
1303 * return isl_stat_error;
1305 * };
1307 * The pointer to the std::function C++ callback function is stored in
1308 * a fn_data data structure for passing to the C callback function,
1309 * along with an std::exception_ptr that is used to store any
1310 * exceptions thrown in the C++ callback.
1312 * struct fn_data {
1313 * const std::function<stat(map)> *func;
1314 * std::exception_ptr eptr;
1315 * } fn_data = { &fn };
1317 * This std::function object represents the actual user
1318 * callback function together with the locally captured state at the caller.
1320 * The lambda function is expected to be used as a C callback function
1321 * where the lambda itself is provided as the function pointer and
1322 * where the user void pointer is a pointer to fn_data.
1323 * The std::function object is extracted from the pointer to fn_data
1324 * inside the lambda function.
1326 * The std::exception_ptr object is not added to fn_data
1327 * if checked C++ bindings are being generated.
1328 * The body of the generated lambda function then is as follows:
1330 * stat ret = (*data->func)(manage(arg_0));
1331 * return isl_stat(ret);
1333 * If the C callback does not take its arguments, then
1334 * manage_copy is used instead of manage.
1336 void cpp_generator::print_callback_local(ostream &os, ParmVarDecl *param)
1338 string pname;
1339 QualType ptype;
1340 string call, c_args, cpp_args, rettype, last_idx;
1341 const FunctionProtoType *callback;
1342 int num_params;
1344 pname = param->getName().str();
1345 ptype = param->getType();
1347 c_args = generate_callback_args(ptype, false);
1348 cpp_args = generate_callback_type(ptype);
1350 callback = extract_prototype(ptype);
1351 rettype = callback->getReturnType().getAsString();
1352 num_params = callback->getNumArgs();
1354 last_idx = ::to_string(num_params - 1);
1356 call = "(*data->func)(";
1357 for (long i = 0; i < num_params - 1; i++) {
1358 if (!callback_takes_argument(param, i))
1359 call += "manage_copy";
1360 else
1361 call += "manage";
1362 call += "(arg_" + ::to_string(i) + ")";
1363 if (i != num_params - 2)
1364 call += ", ";
1366 call += ")";
1368 osprintf(os, " struct %s_data {\n", pname.c_str());
1369 osprintf(os, " const %s *func;\n", cpp_args.c_str());
1370 if (!checked)
1371 osprintf(os, " std::exception_ptr eptr;\n");
1372 osprintf(os, " } %s_data = { &%s };\n", pname.c_str(), pname.c_str());
1373 osprintf(os, " auto %s_lambda = [](%s) -> %s {\n",
1374 pname.c_str(), c_args.c_str(), rettype.c_str());
1375 osprintf(os,
1376 " auto *data = static_cast<struct %s_data *>(arg_%s);\n",
1377 pname.c_str(), last_idx.c_str());
1378 print_wrapped_call(os, call);
1379 osprintf(os, " };\n");
1382 /* An array listing functions that must be renamed and the function name they
1383 * should be renamed to. We currently rename functions in case their name would
1384 * match a reserved C++ keyword, which is not allowed in C++.
1386 static const char *rename_map[][2] = {
1387 { "union", "unite" },
1390 /* Rename method "name" in case the method name in the C++ bindings should not
1391 * match the name in the C bindings. We do this for example to avoid
1392 * C++ keywords.
1394 std::string cpp_generator::rename_method(std::string name)
1396 for (size_t i = 0; i < sizeof(rename_map) / sizeof(rename_map[0]); i++)
1397 if (name.compare(rename_map[i][0]) == 0)
1398 return rename_map[i][1];
1400 return name;
1403 /* Translate isl class "clazz" to its corresponding C++ type.
1405 string cpp_generator::type2cpp(const isl_class &clazz)
1407 return type2cpp(clazz.name);
1410 /* Translate type string "type_str" to its C++ name counterpart.
1412 string cpp_generator::type2cpp(string type_str)
1414 return type_str.substr(4);
1417 /* Translate QualType "type" to its C++ name counterpart.
1419 * An isl_bool return type is translated into "bool",
1420 * while an isl_stat is translated into "void".
1421 * The exceptional cases are handled through exceptions.
1422 * If checked C++ bindings are being generated, then
1423 * C++ counterparts of isl_bool and isl_stat need to be used instead.
1425 string cpp_generator::type2cpp(QualType type)
1427 if (is_isl_type(type))
1428 return type2cpp(type->getPointeeType().getAsString());
1430 if (is_isl_bool(type))
1431 return checked ? "boolean" : "bool";
1433 if (is_isl_stat(type))
1434 return checked ? "stat" : "void";
1436 if (type->isIntegerType())
1437 return type.getAsString();
1439 if (is_string(type))
1440 return "std::string";
1442 if (is_callback(type))
1443 return generate_callback_type(type);
1445 die("Cannot convert type to C++ type");
1448 /* Check if "subclass_type" is a subclass of "class_type".
1450 bool cpp_generator::is_subclass(QualType subclass_type,
1451 const isl_class &class_type)
1453 std::string type_str = subclass_type->getPointeeType().getAsString();
1454 std::vector<std::string> superclasses;
1455 std::vector<const isl_class *> parents;
1456 std::vector<std::string>::iterator ci;
1458 superclasses = generator::find_superclasses(classes[type_str].type);
1460 for (ci = superclasses.begin(); ci < superclasses.end(); ci++)
1461 parents.push_back(&classes[*ci]);
1463 while (!parents.empty()) {
1464 const isl_class *candidate = parents.back();
1466 parents.pop_back();
1468 if (&class_type == candidate)
1469 return true;
1471 superclasses = generator::find_superclasses(candidate->type);
1473 for (ci = superclasses.begin(); ci < superclasses.end(); ci++)
1474 parents.push_back(&classes[*ci]);
1477 return false;
1480 /* Check if "cons" is an implicit conversion constructor of class "clazz".
1482 * An implicit conversion constructor is generated in case "cons" has a single
1483 * parameter, where the parameter type is a subclass of the class that is
1484 * currently being generated.
1486 bool cpp_generator::is_implicit_conversion(const isl_class &clazz,
1487 FunctionDecl *cons)
1489 ParmVarDecl *param = cons->getParamDecl(0);
1490 QualType type = param->getOriginalType();
1492 int num_params = cons->getNumParams();
1493 if (num_params != 1)
1494 return false;
1496 if (is_isl_type(type) && !is_isl_ctx(type) && is_subclass(type, clazz))
1497 return true;
1499 return false;
1502 /* Get kind of "method" in "clazz".
1504 * Given the declaration of a static or member method, returns its kind.
1506 cpp_generator::function_kind cpp_generator::get_method_kind(
1507 const isl_class &clazz, FunctionDecl *method)
1509 if (is_static(clazz, method))
1510 return function_kind_static_method;
1511 else
1512 return function_kind_member_method;