This reverts the previous commit.
Signed-off-by: Sven Verdoolaege <sven.verdoolaege@gmail.com>
@@ -390,6 +390,9 @@ EXTRA_DIST = \
imath/imrat.c \
imath/imrat.h \
interface/all.h \
+ interface/isl-noexceptions.h.top \
+ interface/isl-noexceptions.h.pre \
+ interface/isl-noexceptions.h.bot \
interface/isl.py.top \
interface/isl_test_python.py \
test_inputs
@@ -25,6 +25,17 @@ AX_CC_MAXOPT
AX_GCC_WARN_UNUSED_RESULT
AX_C___ATTRIBUTE__
+# CXX11FLAGS contains the flags (if any) added by AX_CXX_COMPILE_STDCXX_11
+# Original state of CXX and CXXCPP is preserved because CXX11FLAGS
+# is only needed for compiling interface/isl_test_cpp
+AC_SUBST(CXX11FLAGS)
+ac_save_CXX="$CXX"
+ac_save_CXXCPP="$CXXCPP"
+AX_CXX_COMPILE_STDCXX_11([noext], [optional])
+CXX11FLAGS=${CXX#$ac_save_CXX}
+CXX="$ac_save_CXX"
+CXXCPP="$ac_save_CXXCPP"
+
AC_PROG_GREP
AC_PROG_LIBTOOL
AC_PROG_SED
AM_CONDITIONAL(IMATH_FOR_MP, test x$with_int = ximath -o x$with_int = ximath-32)
AM_CONDITIONAL(GMP_FOR_MP, test x$with_int = xgmp)
+AM_CONDITIONAL(HAVE_CXX11, test "x$HAVE_CXX11" = "x1")
AM_CONDITIONAL(SMALL_INT_OPT, test "x$with_int" == "ximath-32")
AS_IF([test "x$with_int" == "ximath-32"], [
AC_DEFINE([USE_SMALL_INT_OPT], [], [Use small integer optimization])
@@ -2,6 +2,10 @@ AUTOMAKE_OPTIONS = nostdinc
noinst_PROGRAMS = extract_interface
TESTS =
+if HAVE_CXX11
+ noinst_PROGRAMS += isl_test_cpp-noexceptions
+ TESTS += isl_test_cpp-noexceptions
+endif
if HAVE_PYTHON
TESTS += isl_test_python.py
isl_test_python.py: isl.py
@@ -22,6 +26,8 @@ extract_interface_SOURCES = \
generator.cc \
python.h \
python.cc \
+ cpp.h \
+ cpp.cc \
extract_interface.h \
extract_interface.cc
extract_interface_LDFLAGS = $(CLANG_LDFLAGS)
@@ -31,7 +37,16 @@ extract_interface_LDADD = \
-lclangAnalysis -lclangAST -lclangLex -lclangBasic -lclangDriver \
$(CLANG_LIBS) $(CLANG_LDFLAGS)
-CLEANFILES = isl.py
+isl_test_cpp_noexceptions_CPPFLAGS = $(includes) -I.
+isl_test_cpp_noexceptions_CXXFLAGS = @CXX11FLAGS@
+isl_test_cpp_noexceptions_SOURCES = \
+ isl_test_cpp-noexceptions.cc \
+ isl-noexceptions.h
+isl_test_cpp_noexceptions_LDFLAGS = @MP_LDFLAGS@
+isl_test_cpp_noexceptions_LDADD = ../libisl.la @MP_LIBS@
+
+BUILT_SOURCES = isl-noexceptions.h
+CLEANFILES = isl.py isl-noexceptions.h
# dummy library that captures the dependencies on all headers
# that are relevant for the bindings
@@ -45,5 +60,14 @@ isl.py: extract_interface libdep.a isl.py.top
$(srcdir)/all.h) \
> isl.py
-dist-hook: isl.py
- cp isl.py $(distdir)/
+isl-noexceptions.h: extract_interface libdep.a isl-noexceptions.h.top \
+ isl-noexceptions.h.pre isl-noexceptions.h.bot
+ (cat $(srcdir)/isl-noexceptions.h.top $(srcdir)/all.h \
+ $(srcdir)/isl-noexceptions.h.pre; \
+ ./extract_interface$(EXEEXT) --language=cpp $(includes) \
+ $(srcdir)/all.h; \
+ cat $(srcdir)/isl-noexceptions.h.bot) \
+ > isl-noexceptions.h
+
+dist-hook: isl.py isl-noexceptions.h
+ cp isl.py isl-noexceptions.h $(distdir)/
--- /dev/null
+/*
+ * Copyright 2016, 2017 Tobias Grosser. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY TOBIAS GROSSER ''AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SVEN VERDOOLAEGE OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
+ * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * The views and conclusions contained in the software and documentation
+ * are those of the authors and should not be interpreted as
+ * representing official policies, either expressed or implied, of
+ * Tobias Grosser.
+ */
+
+#include <cstdarg>
+#include <cstdio>
+#include <iostream>
+#include <map>
+#include <sstream>
+#include <string>
+#include <vector>
+
+#include "cpp.h"
+#include "isl_config.h"
+
+/* Print string formatted according to "fmt" to ostream "os".
+ *
+ * This osprintf method allows us to use printf style formatting constructs when
+ * writing to an ostream.
+ */
+static void osprintf(ostream &os, const char *format, ...)
+{
+ va_list arguments;
+ char *string_pointer;
+ size_t size;
+
+ va_start(arguments, format);
+ size = vsnprintf(NULL, 0, format, arguments);
+ string_pointer = new char[size + 1];
+ va_end(arguments);
+ va_start(arguments, format);
+ vsnprintf(string_pointer, size + 1, format, arguments);
+ va_end(arguments);
+ os << string_pointer;
+ delete[] string_pointer;
+}
+
+/* Convert "l" to a string.
+ */
+static std::string to_string(long l)
+{
+ std::ostringstream strm;
+ strm << l;
+ return strm.str();
+}
+
+/* Generate a cpp interface based on the extracted types and functions.
+ *
+ * Print first a set of forward declarations for all isl wrapper
+ * classes, then the declarations of the classes, and at the end all
+ * implementations.
+ */
+void cpp_generator::generate()
+{
+ ostream &os = cout;
+
+ osprintf(os, "\n");
+ osprintf(os, "namespace isl {\n\n");
+ osprintf(os, "inline namespace noexceptions {\n\n");
+
+ print_forward_declarations(os);
+ osprintf(os, "\n");
+ print_declarations(os);
+ osprintf(os, "\n");
+ print_implementations(os);
+
+ osprintf(os, "} // namespace noexceptions\n");
+ osprintf(os, "} // namespace isl\n");
+}
+
+/* Print forward declarations for all classes to "os".
+*/
+void cpp_generator::print_forward_declarations(ostream &os)
+{
+ map<string, isl_class>::iterator ci;
+
+ osprintf(os, "// forward declarations\n");
+
+ for (ci = classes.begin(); ci != classes.end(); ++ci)
+ print_class_forward_decl(os, ci->second);
+}
+
+/* Print all declarations to "os".
+ */
+void cpp_generator::print_declarations(ostream &os)
+{
+ map<string, isl_class>::iterator ci;
+ bool first = true;
+
+ for (ci = classes.begin(); ci != classes.end(); ++ci) {
+ if (first)
+ first = false;
+ else
+ osprintf(os, "\n");
+
+ print_class(os, ci->second);
+ }
+}
+
+/* Print all implementations to "os".
+ */
+void cpp_generator::print_implementations(ostream &os)
+{
+ map<string, isl_class>::iterator ci;
+ bool first = true;
+
+ for (ci = classes.begin(); ci != classes.end(); ++ci) {
+ if (first)
+ first = false;
+ else
+ osprintf(os, "\n");
+
+ print_class_impl(os, ci->second);
+ }
+}
+
+/* Print declarations for class "clazz" to "os".
+ */
+void cpp_generator::print_class(ostream &os, const isl_class &clazz)
+{
+ const char *name = clazz.name.c_str();
+ std::string cppstring = type2cpp(clazz);
+ const char *cppname = cppstring.c_str();
+
+ osprintf(os, "// declarations for isl::%s\n", cppname);
+
+ print_class_factory_decl(os, clazz);
+ osprintf(os, "\n");
+ osprintf(os, "class %s {\n", cppname);
+ print_class_factory_decl(os, clazz, " friend ");
+ osprintf(os, "\n");
+ osprintf(os, " %s *ptr = nullptr;\n", name);
+ osprintf(os, "\n");
+ print_private_constructors_decl(os, clazz);
+ osprintf(os, "\n");
+ osprintf(os, "public:\n");
+ print_public_constructors_decl(os, clazz);
+ print_constructors_decl(os, clazz);
+ print_copy_assignment_decl(os, clazz);
+ print_destructor_decl(os, clazz);
+ print_ptr_decl(os, clazz);
+ print_get_ctx_decl(os);
+ osprintf(os, "\n");
+ print_methods_decl(os, clazz);
+
+ osprintf(os, "};\n");
+}
+
+/* Print forward declaration of class "clazz" to "os".
+ */
+void cpp_generator::print_class_forward_decl(ostream &os,
+ const isl_class &clazz)
+{
+ std::string cppstring = type2cpp(clazz);
+ const char *cppname = cppstring.c_str();
+
+ osprintf(os, "class %s;\n", cppname);
+}
+
+/* Print global factory functions to "os".
+ *
+ * Each class has two global factory functions:
+ *
+ * isl::set manage(__isl_take isl_set *ptr);
+ * isl::set manage_copy(__isl_keep isl_set *ptr);
+ *
+ * A user can construct isl C++ objects from a raw pointer and indicate whether
+ * they intend to take the ownership of the object or not through these global
+ * factory functions. This ensures isl object creation is very explicit and
+ * pointers are not converted by accident. Thanks to overloading, manage() and
+ * manage_copy() can be called on any isl raw pointer and the corresponding
+ * object is automatically created, without the user having to choose the right
+ * isl object type.
+ */
+void cpp_generator::print_class_factory_decl(ostream &os,
+ const isl_class &clazz, const std::string &prefix)
+{
+ const char *name = clazz.name.c_str();
+ std::string cppstring = type2cpp(clazz);
+ const char *cppname = cppstring.c_str();
+
+ os << prefix;
+ osprintf(os, "inline isl::%s manage(__isl_take %s *ptr);\n", cppname,
+ name);
+ os << prefix;
+ osprintf(os, "inline isl::%s manage_copy(__isl_keep %s *ptr);\n",
+ cppname, name);
+}
+
+/* Print declarations of private constructors for class "clazz" to "os".
+ *
+ * Each class has currently one private constructor:
+ *
+ * 1) Constructor from a plain isl_* C pointer
+ *
+ * Example:
+ *
+ * set(__isl_take isl_set *ptr);
+ *
+ * The raw pointer constructor is kept private. Object creation is only
+ * possible through isl::manage() or isl::manage_copy().
+ */
+void cpp_generator::print_private_constructors_decl(ostream &os,
+ const isl_class &clazz)
+{
+ const char *name = clazz.name.c_str();
+ std::string cppstring = type2cpp(clazz);
+ const char *cppname = cppstring.c_str();
+
+ osprintf(os, " inline explicit %s(__isl_take %s *ptr);\n", cppname,
+ name);
+}
+
+/* Print declarations of public constructors for class "clazz" to "os".
+ *
+ * Each class currently has two public constructors:
+ *
+ * 1) A default constructor
+ * 2) A copy constructor
+ *
+ * Example:
+ *
+ * set();
+ * set(const isl::set &set);
+ */
+void cpp_generator::print_public_constructors_decl(ostream &os,
+ const isl_class &clazz)
+{
+ std::string cppstring = type2cpp(clazz);
+ const char *cppname = cppstring.c_str();
+ osprintf(os, " inline /* implicit */ %s();\n", cppname);
+
+ osprintf(os, " inline /* implicit */ %s(const isl::%s &obj);\n",
+ cppname, cppname);
+}
+
+/* Print declarations for constructors for class "class" to "os".
+ *
+ * For each isl function that is marked as __isl_constructor,
+ * add a corresponding C++ constructor.
+ *
+ * Example:
+ *
+ * inline /\* implicit *\/ union_set(isl::basic_set bset);
+ * inline /\* implicit *\/ union_set(isl::set set);
+ * inline explicit val(isl::ctx ctx, long i);
+ * inline explicit val(isl::ctx ctx, const std::string &str);
+ */
+void cpp_generator::print_constructors_decl(ostream &os,
+ const isl_class &clazz)
+{
+ set<FunctionDecl *>::const_iterator in;
+ const set<FunctionDecl *> &constructors = clazz.constructors;
+
+ for (in = constructors.begin(); in != constructors.end(); ++in) {
+ FunctionDecl *cons = *in;
+ string fullname = cons->getName();
+ function_kind kind = function_kind_constructor;
+
+ print_method_decl(os, clazz, fullname, cons, kind);
+ }
+}
+
+/* Print declarations of copy assignment operator for class "clazz"
+ * to "os".
+ *
+ * Each class has one assignment operator.
+ *
+ * isl:set &set::operator=(isl::set obj)
+ *
+ */
+void cpp_generator::print_copy_assignment_decl(ostream &os,
+ const isl_class &clazz)
+{
+ std::string cppstring = type2cpp(clazz);
+ const char *cppname = cppstring.c_str();
+
+ osprintf(os, " inline isl::%s &operator=(isl::%s obj);\n", cppname,
+ cppname);
+}
+
+/* Print declaration of destructor for class "clazz" to "os".
+ */
+void cpp_generator::print_destructor_decl(ostream &os, const isl_class &clazz)
+{
+ std::string cppstring = type2cpp(clazz);
+ const char *cppname = cppstring.c_str();
+
+ osprintf(os, " inline ~%s();\n", cppname);
+}
+
+/* Print declaration of pointer functions for class "clazz" to "os".
+ *
+ * To obtain a raw pointer three functions are provided:
+ *
+ * 1) __isl_give isl_set *copy()
+ *
+ * Returns a pointer to a _copy_ of the internal object
+ *
+ * 2) __isl_keep isl_set *get()
+ *
+ * Returns a pointer to the internal object
+ *
+ * 3) __isl_give isl_set *release()
+ *
+ * Returns a pointer to the internal object and resets the
+ * internal pointer to nullptr.
+ *
+ * We also provide functionality to explicitly check if a pointer is
+ * currently managed by this object.
+ *
+ * 4) bool is_null()
+ *
+ * Check if the current object is a null pointer.
+ *
+ * The functions get() and release() model the value_ptr proposed in
+ * http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2012/n3339.pdf.
+ * The copy() function is an extension to allow the user to explicitly
+ * copy the underlying object.
+ *
+ * Also generate a declaration to delete copy() for r-values, for
+ * r-values release() should be used to avoid unnecessary copies.
+ */
+void cpp_generator::print_ptr_decl(ostream &os, const isl_class &clazz)
+{
+ const char *name = clazz.name.c_str();
+
+ osprintf(os, " inline __isl_give %s *copy() const &;\n", name);
+ osprintf(os, " inline __isl_give %s *copy() && = delete;\n", name);
+ osprintf(os, " inline __isl_keep %s *get() const;\n", name);
+ osprintf(os, " inline __isl_give %s *release();\n", name);
+ osprintf(os, " inline bool is_null() const;\n");
+}
+
+/* Print the declaration of the get_ctx method.
+ */
+void cpp_generator::print_get_ctx_decl(ostream &os)
+{
+ osprintf(os, " inline isl::ctx get_ctx() const;\n");
+}
+
+/* Print declarations for methods in class "clazz" to "os".
+ */
+void cpp_generator::print_methods_decl(ostream &os, const isl_class &clazz)
+{
+ map<string, set<FunctionDecl *> >::const_iterator it;
+
+ for (it = clazz.methods.begin(); it != clazz.methods.end(); ++it)
+ print_method_group_decl(os, clazz, it->first, it->second);
+}
+
+/* Print declarations for methods "methods" of name "fullname" in class "clazz"
+ * to "os".
+ *
+ * "fullname" is the name of the generated C++ method. It commonly corresponds
+ * to the isl name, with the object type prefix dropped.
+ * In case of overloaded methods, the result type suffix has also been removed.
+ */
+void cpp_generator::print_method_group_decl(ostream &os, const isl_class &clazz,
+ const string &fullname, const set<FunctionDecl *> &methods)
+{
+ set<FunctionDecl *>::const_iterator it;
+
+ for (it = methods.begin(); it != methods.end(); ++it) {
+ function_kind kind = get_method_kind(clazz, *it);
+ print_method_decl(os, clazz, fullname, *it, kind);
+ }
+}
+
+/* Print declarations for "method" in class "clazz" to "os".
+ *
+ * "fullname" is the name of the generated C++ method. It commonly corresponds
+ * to the isl name, with the object type prefix dropped.
+ * In case of overloaded methods, the result type suffix has also been removed.
+ *
+ * "kind" specifies the kind of method that should be generated.
+ */
+void cpp_generator::print_method_decl(ostream &os, const isl_class &clazz,
+ const string &fullname, FunctionDecl *method, function_kind kind)
+{
+ print_method_header(os, clazz, method, fullname, true, kind);
+}
+
+/* Print implementations for class "clazz" to "os".
+ */
+void cpp_generator::print_class_impl(ostream &os, const isl_class &clazz)
+{
+ std::string cppstring = type2cpp(clazz);
+ const char *cppname = cppstring.c_str();
+
+ osprintf(os, "// implementations for isl::%s\n", cppname);
+
+ print_class_factory_impl(os, clazz);
+ osprintf(os, "\n");
+ print_public_constructors_impl(os, clazz);
+ osprintf(os, "\n");
+ print_private_constructors_impl(os, clazz);
+ osprintf(os, "\n");
+ print_constructors_impl(os, clazz);
+ osprintf(os, "\n");
+ print_copy_assignment_impl(os, clazz);
+ osprintf(os, "\n");
+ print_destructor_impl(os, clazz);
+ osprintf(os, "\n");
+ print_ptr_impl(os, clazz);
+ osprintf(os, "\n");
+ print_get_ctx_impl(os, clazz);
+ osprintf(os, "\n");
+ print_methods_impl(os, clazz);
+}
+
+/* Print implementation of global factory functions to "os".
+ */
+void cpp_generator::print_class_factory_impl(ostream &os,
+ const isl_class &clazz)
+{
+ const char *name = clazz.name.c_str();
+ std::string cppstring = type2cpp(clazz);
+ const char *cppname = cppstring.c_str();
+
+ osprintf(os, "isl::%s manage(__isl_take %s *ptr) {\n", cppname, name);
+ osprintf(os, " return %s(ptr);\n", cppname);
+ osprintf(os, "}\n");
+
+ osprintf(os, "isl::%s manage_copy(__isl_keep %s *ptr) {\n", cppname,
+ name);
+ osprintf(os, " return %s(%s_copy(ptr));\n", cppname, name);
+ osprintf(os, "}\n");
+}
+
+/* Print implementations of private constructors for class "clazz" to "os".
+ */
+void cpp_generator::print_private_constructors_impl(ostream &os,
+ const isl_class &clazz)
+{
+ const char *name = clazz.name.c_str();
+ std::string cppstring = type2cpp(clazz);
+ const char *cppname = cppstring.c_str();
+
+ osprintf(os, "%s::%s(__isl_take %s *ptr)\n : ptr(ptr) {}\n",
+ cppname, cppname, name);
+}
+
+/* Print implementations of public constructors for class "clazz" to "os".
+ */
+void cpp_generator::print_public_constructors_impl(ostream &os,
+ const isl_class &clazz)
+{
+ std::string cppstring = type2cpp(clazz);
+ const char *cppname = cppstring.c_str();
+
+ osprintf(os, "%s::%s()\n : ptr(nullptr) {}\n\n", cppname, cppname);
+ osprintf(os, "%s::%s(const isl::%s &obj)\n : ptr(obj.copy()) {}\n",
+ cppname, cppname, cppname);
+}
+
+/* Print implementations of constructors for class "clazz" to "os".
+ */
+void cpp_generator::print_constructors_impl(ostream &os,
+ const isl_class &clazz)
+{
+ set<FunctionDecl *>::const_iterator in;
+ const set<FunctionDecl *> constructors = clazz.constructors;
+
+ for (in = constructors.begin(); in != constructors.end(); ++in) {
+ FunctionDecl *cons = *in;
+ string fullname = cons->getName();
+ function_kind kind = function_kind_constructor;
+
+ print_method_impl(os, clazz, fullname, cons, kind);
+ }
+}
+
+/* Print implementation of copy assignment operator for class "clazz" to "os".
+ */
+void cpp_generator::print_copy_assignment_impl(ostream &os,
+ const isl_class &clazz)
+{
+ const char *name = clazz.name.c_str();
+ std::string cppstring = type2cpp(clazz);
+ const char *cppname = cppstring.c_str();
+
+ osprintf(os, "%s &%s::operator=(isl::%s obj) {\n", cppname,
+ cppname, cppname);
+ osprintf(os, " std::swap(this->ptr, obj.ptr);\n", name);
+ osprintf(os, " return *this;\n");
+ osprintf(os, "}\n");
+}
+
+/* Print implementation of destructor for class "clazz" to "os".
+ */
+void cpp_generator::print_destructor_impl(ostream &os,
+ const isl_class &clazz)
+{
+ const char *name = clazz.name.c_str();
+ std::string cppstring = type2cpp(clazz);
+ const char *cppname = cppstring.c_str();
+
+ osprintf(os, "%s::~%s() {\n", cppname, cppname);
+ osprintf(os, " if (ptr)\n");
+ osprintf(os, " %s_free(ptr);\n", name);
+ osprintf(os, "}\n");
+}
+
+/* Print implementation of ptr() functions for class "clazz" to "os".
+ */
+void cpp_generator::print_ptr_impl(ostream &os, const isl_class &clazz)
+{
+ const char *name = clazz.name.c_str();
+ std::string cppstring = type2cpp(clazz);
+ const char *cppname = cppstring.c_str();
+
+ osprintf(os, "__isl_give %s *%s::copy() const & {\n", name, cppname);
+ osprintf(os, " return %s_copy(ptr);\n", name);
+ osprintf(os, "}\n\n");
+ osprintf(os, "__isl_keep %s *%s::get() const {\n", name, cppname);
+ osprintf(os, " return ptr;\n");
+ osprintf(os, "}\n\n");
+ osprintf(os, "__isl_give %s *%s::release() {\n", name, cppname);
+ osprintf(os, " %s *tmp = ptr;\n", name);
+ osprintf(os, " ptr = nullptr;\n");
+ osprintf(os, " return tmp;\n");
+ osprintf(os, "}\n\n");
+ osprintf(os, "bool %s::is_null() const {\n", cppname);
+ osprintf(os, " return ptr == nullptr;\n");
+ osprintf(os, "}\n");
+}
+
+/* Print the implementation of the get_ctx method.
+ */
+void cpp_generator::print_get_ctx_impl(ostream &os, const isl_class &clazz)
+{
+ const char *name = clazz.name.c_str();
+ std::string cppstring = type2cpp(clazz);
+ const char *cppname = cppstring.c_str();
+
+ osprintf(os, "isl::ctx %s::get_ctx() const {\n", cppname);
+ osprintf(os, " return isl::ctx(%s_get_ctx(ptr));\n", name);
+ osprintf(os, "}\n");
+}
+
+/* Print definitions for methods of class "clazz" to "os".
+ */
+void cpp_generator::print_methods_impl(ostream &os, const isl_class &clazz)
+{
+ map<string, set<FunctionDecl *> >::const_iterator it;
+ bool first = true;
+
+ for (it = clazz.methods.begin(); it != clazz.methods.end(); ++it) {
+ if (first)
+ first = false;
+ else
+ osprintf(os, "\n");
+ print_method_group_impl(os, clazz, it->first, it->second);
+ }
+}
+
+/* Print definitions for methods "methods" of name "fullname" in class "clazz"
+ * to "os".
+ *
+ * "fullname" is the name of the generated C++ method. It commonly corresponds
+ * to the isl name, with the object type prefix dropped.
+ * In case of overloaded methods, the result type suffix has also been removed.
+ *
+ * "kind" specifies the kind of method that should be generated.
+ */
+void cpp_generator::print_method_group_impl(ostream &os, const isl_class &clazz,
+ const string &fullname, const set<FunctionDecl *> &methods)
+{
+ set<FunctionDecl *>::const_iterator it;
+ bool first = true;
+
+ for (it = methods.begin(); it != methods.end(); ++it) {
+ function_kind kind;
+ if (first)
+ first = false;
+ else
+ osprintf(os, "\n");
+ kind = get_method_kind(clazz, *it);
+ print_method_impl(os, clazz, fullname, *it, kind);
+ }
+}
+
+/* Print the use of "param" to "os".
+ *
+ * "load_from_this_ptr" specifies whether the parameter should be loaded from
+ * the this-ptr. In case a value is loaded from a this pointer, the original
+ * value must be preserved and must consequently be copied. Values that are
+ * loaded from parameters do not need to be preserved, as such values will
+ * already be copies of the actual parameters. It is consequently possible
+ * to directly take the pointer from these values, which saves
+ * an unnecessary copy.
+ *
+ * In case the parameter is a callback function, two parameters get printed,
+ * a wrapper for the callback function and a pointer to the actual
+ * callback function. The wrapper is expected to be available
+ * in a previously declared variable <name>_lambda, while
+ * the actual callback function is expected in <name>_p.
+ * The caller of this function must ensure that these variables exist.
+ */
+void cpp_generator::print_method_param_use(ostream &os, ParmVarDecl *param,
+ bool load_from_this_ptr)
+{
+ string name = param->getName().str();
+ const char *name_str = name.c_str();
+ QualType type = param->getOriginalType();
+
+ if (type->isIntegerType()) {
+ osprintf(os, "%s", name_str);
+ return;
+ }
+
+ if (is_string(type)) {
+ osprintf(os, "%s.c_str()", name_str);
+ return;
+ }
+
+ if (is_callback(type)) {
+ osprintf(os, "%s_lambda, ", name_str);
+ osprintf(os, "&%s_p", name_str);
+ return;
+ }
+
+ if (!load_from_this_ptr && !is_callback(type))
+ osprintf(os, "%s.", name_str);
+
+ if (keeps(param)) {
+ osprintf(os, "get()");
+ } else {
+ if (load_from_this_ptr)
+ osprintf(os, "copy()");
+ else
+ osprintf(os, "release()");
+ }
+}
+
+/* Print definition for "method" in class "clazz" to "os".
+ *
+ * "fullname" is the name of the generated C++ method. It commonly corresponds
+ * to the isl name, with the object type prefix dropped.
+ * In case of overloaded methods, the result type suffix has also been removed.
+ *
+ * "kind" specifies the kind of method that should be generated.
+ *
+ * This method distinguishes three kinds of methods: member methods, static
+ * methods, and constructors.
+ *
+ * Member methods call "method" by passing to the underlying isl function the
+ * isl object belonging to "this" as first argument and the remaining arguments
+ * as subsequent arguments. The result of the isl function is returned as a new
+ * object if the underlying isl function returns an isl_* ptr or an isl_bool
+ * value, as std::string if the isl function returns 'const char *', and as
+ * unmodified return value otherwise.
+ *
+ * Static methods call "method" by passing all arguments to the underlying isl
+ * function, as no this-pointer is available. The result is a newly managed
+ * isl C++ object.
+ *
+ * Constructors create a new object from a given set of input parameters. They
+ * do not return a value, but instead update the pointer stored inside the
+ * newly created object.
+ *
+ * If the method has a callback argument, we reduce the number of parameters
+ * that are exposed by one to hide the user pointer from the interface. On
+ * the C++ side no user pointer is needed, as arguments can be forwarded
+ * as part of the std::function argument which specifies the callback function.
+ */
+void cpp_generator::print_method_impl(ostream &os, const isl_class &clazz,
+ const string &fullname, FunctionDecl *method, function_kind kind)
+{
+ string methodname = method->getName();
+ int num_params = method->getNumParams();
+ QualType return_type = method->getReturnType();
+ string rettype_str = type2cpp(return_type);
+ bool has_callback = false;
+
+ print_method_header(os, clazz, method, fullname, false, kind);
+
+ for (int i = 0; i < num_params; ++i) {
+ ParmVarDecl *param = method->getParamDecl(i);
+ if (is_callback(param->getType())) {
+ has_callback = true;
+ num_params -= 1;
+ print_callback_local(os, param);
+ }
+ }
+
+ osprintf(os, " auto res = %s(", methodname.c_str());
+
+ for (int i = 0; i < num_params; ++i) {
+ ParmVarDecl *param = method->getParamDecl(i);
+ bool load_from_this_ptr = false;
+
+ if (i == 0 && kind == function_kind_member_method)
+ load_from_this_ptr = true;
+
+ print_method_param_use(os, param, load_from_this_ptr);
+
+ if (i != num_params - 1)
+ osprintf(os, ", ");
+ }
+ osprintf(os, ");\n");
+
+ if (kind == function_kind_constructor) {
+ osprintf(os, " ptr = res;\n");
+ } else if (is_isl_type(return_type) || is_isl_bool(return_type)) {
+ osprintf(os, " return manage(res);\n");
+ } else if (has_callback) {
+ osprintf(os, " return %s(res);\n", rettype_str.c_str());
+ } else if (is_string(return_type)) {
+ osprintf(os, " std::string tmp(res);\n");
+ if (gives(method))
+ osprintf(os, " free(res);\n");
+ osprintf(os, " return tmp;\n");
+ } else {
+ osprintf(os, " return res;\n");
+ }
+
+ osprintf(os, "}\n");
+}
+
+/* Print the header for "method" in class "clazz" to "os".
+ *
+ * Print the header of a declaration if "is_declaration" is set, otherwise print
+ * the header of a method definition.
+ *
+ * "fullname" is the name of the generated C++ method. It commonly corresponds
+ * to the isl name, with the object type prefix dropped.
+ * In case of overloaded methods, the result type suffix has also been removed.
+ *
+ * "kind" specifies the kind of method that should be generated.
+ *
+ * This function prints headers for member methods, static methods, and
+ * constructors, either for their declaration or definition.
+ *
+ * Member functions are declared as "const", as they do not change the current
+ * object, but instead create a new object. They always retrieve the first
+ * parameter of the original isl function from the this-pointer of the object,
+ * such that only starting at the second parameter the parameters of the
+ * original function become part of the method's interface.
+ *
+ * A function
+ *
+ * __isl_give isl_set *isl_set_intersect(__isl_take isl_set *s1,
+ * __isl_take isl_set *s2);
+ *
+ * is translated into:
+ *
+ * inline isl::set intersect(isl::set set2) const;
+ *
+ * For static functions and constructors all parameters of the original isl
+ * function are exposed.
+ *
+ * Parameters that are defined as __isl_keep or are of type string, are passed
+ * as const reference, which allows the compiler to optimize the parameter
+ * transfer.
+ *
+ * Constructors are marked as explicit using the C++ keyword 'explicit' or as
+ * implicit using a comment in place of the explicit keyword. By annotating
+ * implicit constructors with a comment, users of the interface are made
+ * aware of the potential danger that implicit construction is possible
+ * for these constructors, whereas without a comment not every user would
+ * know that implicit construction is allowed in absence of an explicit keyword.
+ */
+void cpp_generator::print_method_header(ostream &os, const isl_class &clazz,
+ FunctionDecl *method, const string &fullname, bool is_declaration,
+ function_kind kind)
+{
+ string cname = fullname.substr(clazz.name.length() + 1);
+ string rettype_str = type2cpp(method->getReturnType());
+ string classname = type2cpp(clazz);
+ int num_params = method->getNumParams();
+ int first_param = 0;
+
+ cname = rename_method(cname);
+ if (kind == function_kind_member_method)
+ first_param = 1;
+
+ if (is_declaration) {
+ osprintf(os, " ");
+
+ if (kind == function_kind_static_method)
+ osprintf(os, "static ");
+
+ osprintf(os, "inline ");
+
+ if (kind == function_kind_constructor) {
+ if (is_implicit_conversion(clazz, method))
+ osprintf(os, "/* implicit */ ");
+ else
+ osprintf(os, "explicit ");
+ }
+ }
+
+ if (kind != function_kind_constructor)
+ osprintf(os, "%s ", rettype_str.c_str());
+
+ if (!is_declaration)
+ osprintf(os, "%s::", classname.c_str());
+
+ if (kind != function_kind_constructor)
+ osprintf(os, "%s", cname.c_str());
+ else
+ osprintf(os, "%s", classname.c_str());
+
+ osprintf(os, "(");
+
+ for (int i = first_param; i < num_params; ++i) {
+ ParmVarDecl *param = method->getParamDecl(i);
+ QualType type = param->getOriginalType();
+ string cpptype = type2cpp(type);
+
+ if (is_callback(type))
+ num_params--;
+
+ if (keeps(param) || is_string(type) || is_callback(type))
+ osprintf(os, "const %s &%s", cpptype.c_str(),
+ param->getName().str().c_str());
+ else
+ osprintf(os, "%s %s", cpptype.c_str(),
+ param->getName().str().c_str());
+
+ if (i != num_params - 1)
+ osprintf(os, ", ");
+ }
+
+ osprintf(os, ")");
+
+ if (kind == function_kind_member_method)
+ osprintf(os, " const");
+
+ if (is_declaration)
+ osprintf(os, ";\n");
+ else
+ osprintf(os, " {\n");
+}
+
+/* Generate the list of argument types for a callback function of
+ * type "type". If "cpp" is set, then generate the C++ type list, otherwise
+ * the C type list.
+ *
+ * For a callback of type
+ *
+ * isl_stat (*)(__isl_take isl_map *map, void *user)
+ *
+ * the following C++ argument list is generated:
+ *
+ * isl::map
+ */
+string cpp_generator::generate_callback_args(QualType type, bool cpp)
+{
+ std::string type_str;
+ const FunctionProtoType *callback;
+ int num_params;
+
+ callback = type->getPointeeType()->getAs<FunctionProtoType>();
+ num_params = callback->getNumArgs();
+ if (cpp)
+ num_params--;
+
+ for (long i = 0; i < num_params; i++) {
+ QualType type = callback->getArgType(i);
+
+ if (cpp)
+ type_str += type2cpp(type);
+ else
+ type_str += type.getAsString();
+
+ if (!cpp)
+ type_str += "arg_" + ::to_string(i);
+
+ if (i != num_params - 1)
+ type_str += ", ";
+ }
+
+ return type_str;
+}
+
+/* Generate the full cpp type of a callback function of type "type".
+ *
+ * For a callback of type
+ *
+ * isl_stat (*)(__isl_take isl_map *map, void *user)
+ *
+ * the following type is generated:
+ *
+ * std::function<isl::stat(isl::map)>
+ */
+string cpp_generator::generate_callback_type(QualType type)
+{
+ std::string type_str;
+ const FunctionProtoType *callback = type->getPointeeType()->getAs<FunctionProtoType>();
+ QualType return_type = callback->getReturnType();
+ string rettype_str = type2cpp(return_type);
+
+ type_str = "std::function<";
+ type_str += rettype_str;
+ type_str += "(";
+ type_str += generate_callback_args(type, true);
+ type_str += ")>";
+
+ return type_str;
+}
+
+/* Print the local variables that are needed for a callback argument,
+ * in particular, print a lambda function that wraps the callback and
+ * a pointer to the actual C++ callback function.
+ *
+ * For a callback of the form
+ *
+ * isl_stat (*fn)(__isl_take isl_map *map, void *user)
+ *
+ * the following lambda function is generated:
+ *
+ * auto fn_lambda = [](isl_map *arg_0, void *arg_1) -> isl_stat {
+ * auto *func = *static_cast<const std::function<stat(map)> **>(arg_1);
+ * stat ret = (*func)(isl::manage(arg_0));
+ * return isl_stat(ret);
+ * };
+ *
+ * The pointer to the std::function C++ callback function is stored in fn_p.
+ * This std::function object represents the actual user
+ * callback function together with the locally captured state at the caller.
+ *
+ * The lambda function is expected to be used as a C callback function
+ * where the lambda itself is provided as the function pointer and
+ * where the user void pointer is a pointer to fn_p.
+ * The std::function object is extracted from the pointer to fn_p
+ * inside the lambda function.
+ * The double indirection is used to avoid having to worry about
+ * const casting.
+ */
+void cpp_generator::print_callback_local(ostream &os, ParmVarDecl *param)
+{
+ string pname;
+ QualType ptype;
+ string call_args, c_args, cpp_args, rettype, last_idx;
+ const FunctionProtoType *callback;
+ int num_params;
+
+ pname = param->getName().str();
+ ptype = param->getType();
+
+ c_args = generate_callback_args(ptype, false);
+ cpp_args = generate_callback_type(ptype);
+
+ callback = ptype->getPointeeType()->getAs<FunctionProtoType>();
+ rettype = callback->getReturnType().getAsString();
+ num_params = callback->getNumArgs();
+
+ last_idx = ::to_string(num_params - 1);
+
+ for (long i = 0; i < num_params - 1; i++) {
+ call_args += "isl::manage(arg_" + ::to_string(i) + ")";
+ if (i != num_params - 2)
+ call_args += ", ";
+ }
+
+ osprintf(os, " auto %s_p = &%s;\n", pname.c_str(), pname.c_str());
+ osprintf(os,
+ " auto %s_lambda = [](%s) -> %s {\n"
+ " auto *func = *static_cast<const %s **>(arg_%s);\n"
+ " stat ret = (*func)(%s);\n"
+ " return isl_stat(ret);\n"
+ " };\n",
+ pname.c_str(), c_args.c_str(), rettype.c_str(),
+ cpp_args.c_str(), last_idx.c_str(), call_args.c_str());
+}
+
+/* An array listing functions that must be renamed and the function name they
+ * should be renamed to. We currently rename functions in case their name would
+ * match a reserved C++ keyword, which is not allowed in C++.
+ */
+static const char *rename_map[][2] = {
+ { "union", "unite" },
+};
+
+/* Rename method "name" in case the method name in the C++ bindings should not
+ * match the name in the C bindings. We do this for example to avoid
+ * C++ keywords.
+ */
+std::string cpp_generator::rename_method(std::string name)
+{
+ for (size_t i = 0; i < sizeof(rename_map) / sizeof(rename_map[0]); i++)
+ if (name.compare(rename_map[i][0]) == 0)
+ return rename_map[i][1];
+
+ return name;
+}
+
+/* Translate isl class "clazz" to its corresponding C++ type.
+ */
+string cpp_generator::type2cpp(const isl_class &clazz)
+{
+ return type2cpp(clazz.name);
+}
+
+/* Translate type string "type_str" to its C++ name counterpart.
+*/
+string cpp_generator::type2cpp(string type_str)
+{
+ return type_str.substr(4);
+}
+
+/* Translate QualType "type" to its C++ name counterpart.
+ */
+string cpp_generator::type2cpp(QualType type)
+{
+ if (is_isl_type(type))
+ return "isl::" + type2cpp(type->getPointeeType().getAsString());
+
+ if (is_isl_bool(type))
+ return "isl::boolean";
+
+ if (is_isl_stat(type))
+ return "isl::stat";
+
+ if (type->isIntegerType())
+ return type.getAsString();
+
+ if (is_string(type))
+ return "std::string";
+
+ if (is_callback(type))
+ return generate_callback_type(type);
+
+ die("Cannot convert type to C++ type");
+}
+
+/* Check if "subclass_type" is a subclass of "class_type".
+ */
+bool cpp_generator::is_subclass(QualType subclass_type,
+ const isl_class &class_type)
+{
+ std::string type_str = subclass_type->getPointeeType().getAsString();
+ std::vector<std::string> superclasses;
+ std::vector<const isl_class *> parents;
+ std::vector<std::string>::iterator ci;
+
+ superclasses = generator::find_superclasses(classes[type_str].type);
+
+ for (ci = superclasses.begin(); ci < superclasses.end(); ci++)
+ parents.push_back(&classes[*ci]);
+
+ while (!parents.empty()) {
+ const isl_class *candidate = parents.back();
+
+ parents.pop_back();
+
+ if (&class_type == candidate)
+ return true;
+
+ superclasses = generator::find_superclasses(candidate->type);
+
+ for (ci = superclasses.begin(); ci < superclasses.end(); ci++)
+ parents.push_back(&classes[*ci]);
+ }
+
+ return false;
+}
+
+/* Check if "cons" is an implicit conversion constructor of class "clazz".
+ *
+ * An implicit conversion constructor is generated in case "cons" has a single
+ * parameter, where the parameter type is a subclass of the class that is
+ * currently being generated.
+ */
+bool cpp_generator::is_implicit_conversion(const isl_class &clazz,
+ FunctionDecl *cons)
+{
+ ParmVarDecl *param = cons->getParamDecl(0);
+ QualType type = param->getOriginalType();
+
+ int num_params = cons->getNumParams();
+ if (num_params != 1)
+ return false;
+
+ if (is_isl_type(type) && !is_isl_ctx(type) && is_subclass(type, clazz))
+ return true;
+
+ return false;
+}
+
+/* Get kind of "method" in "clazz".
+ *
+ * Given the declaration of a static or member method, returns its kind.
+ */
+cpp_generator::function_kind cpp_generator::get_method_kind(
+ const isl_class &clazz, FunctionDecl *method)
+{
+ if (is_static(clazz, method))
+ return function_kind_static_method;
+ else
+ return function_kind_member_method;
+}
--- /dev/null
+#include "generator.h"
+
+using namespace std;
+using namespace clang;
+
+class cpp_generator : public generator {
+public:
+ cpp_generator(set<RecordDecl *> &exported_types,
+ set<FunctionDecl *> exported_functions,
+ set<FunctionDecl *> functions) :
+ generator(exported_types, exported_functions, functions) {}
+
+ enum function_kind {
+ function_kind_static_method,
+ function_kind_member_method,
+ function_kind_constructor,
+ };
+
+ virtual void generate();
+private:
+ void print_file(ostream &os, std::string filename);
+ void print_forward_declarations(ostream &os);
+ void print_declarations(ostream &os);
+ void print_class(ostream &os, const isl_class &clazz);
+ void print_class_forward_decl(ostream &os, const isl_class &clazz);
+ void print_class_factory_decl(ostream &os, const isl_class &clazz,
+ const std::string &prefix = std::string());
+ void print_private_constructors_decl(ostream &os,
+ const isl_class &clazz);
+ void print_copy_assignment_decl(ostream &os, const isl_class &clazz);
+ void print_public_constructors_decl(ostream &os,
+ const isl_class &clazz);
+ void print_constructors_decl(ostream &os, const isl_class &clazz);
+ void print_destructor_decl(ostream &os, const isl_class &clazz);
+ void print_ptr_decl(ostream &os, const isl_class &clazz);
+ void print_get_ctx_decl(ostream &os);
+ void print_methods_decl(ostream &os, const isl_class &clazz);
+ void print_method_group_decl(ostream &os, const isl_class &clazz,
+ const string &fullname, const set<FunctionDecl *> &methods);
+ void print_method_decl(ostream &os, const isl_class &clazz,
+ const string &fullname, FunctionDecl *method,
+ function_kind kind);
+ void print_implementations(ostream &os);
+ void print_class_impl(ostream &os, const isl_class &clazz);
+ void print_class_factory_impl(ostream &os, const isl_class &clazz);
+ void print_private_constructors_impl(ostream &os,
+ const isl_class &clazz);
+ void print_public_constructors_impl(ostream &os,
+ const isl_class &clazz);
+ void print_constructors_impl(ostream &os, const isl_class &clazz);
+ void print_copy_assignment_impl(ostream &os, const isl_class &clazz);
+ void print_destructor_impl(ostream &os, const isl_class &clazz);
+ void print_ptr_impl(ostream &os, const isl_class &clazz);
+ void print_get_ctx_impl(ostream &os, const isl_class &clazz);
+ void print_methods_impl(ostream &os, const isl_class &clazz);
+ void print_method_group_impl(ostream &os, const isl_class &clazz,
+ const string &fullname, const set<FunctionDecl *> &methods);
+ void print_method_impl(ostream &os, const isl_class &clazz,
+ const string &fullname, FunctionDecl *method,
+ function_kind kind);
+ void print_method_param_use(ostream &os, ParmVarDecl *param,
+ bool load_from_this_ptr);
+ void print_method_header(ostream &os, const isl_class &clazz,
+ FunctionDecl *method, const string &fullname,
+ bool is_declaration, function_kind kind);
+ string generate_callback_args(QualType type, bool cpp);
+ string generate_callback_type(QualType type);
+ void print_callback_local(ostream &os, ParmVarDecl *param);
+ std::string rename_method(std::string name);
+ string type2cpp(const isl_class &clazz);
+ string type2cpp(string type_string);
+ string type2cpp(QualType type);
+ bool is_implicit_conversion(const isl_class &clazz, FunctionDecl *cons);
+ bool is_subclass(QualType subclass_type, const isl_class &class_type);
+ function_kind get_method_kind(const isl_class &clazz,
+ FunctionDecl *method);
+};
#include "extract_interface.h"
#include "generator.h"
#include "python.h"
+#include "cpp.h"
using namespace std;
using namespace clang;
@@ -449,6 +450,9 @@ int main(int argc, char *argv[])
if (Language.compare("python") == 0)
gen = new python_generator(consumer.exported_types,
consumer.exported_functions, consumer.functions);
+ else if (Language.compare("cpp") == 0)
+ gen = new cpp_generator(consumer.exported_types,
+ consumer.exported_functions, consumer.functions);
else
cerr << "Language '" << Language << "' not recognized." << endl
<< "Not generating bindings." << endl;
--- /dev/null
+
+#endif /* ISL_CPP_NOEXCEPTIONS */
--- /dev/null
+
+#include <functional>
+#include <string>
+
+namespace isl {
+inline namespace noexceptions {
+
+#define ISLPP_STRINGIZE_(X) #X
+#define ISLPP_STRINGIZE(X) ISLPP_STRINGIZE_(X)
+
+#define ISLPP_ASSERT(test, message) \
+ do { \
+ if (test) \
+ break; \
+ fputs("Assertion \"" #test "\" failed at " __FILE__ \
+ ":" ISLPP_STRINGIZE(__LINE__) "\n " message "\n", \
+ stderr); \
+ } while (0)
+
+class boolean {
+private:
+ isl_bool val;
+
+ friend isl::boolean manage(isl_bool val);
+ boolean(isl_bool val): val(val) {}
+public:
+ boolean()
+ : val(isl_bool_error) {}
+
+ /* implicit */ boolean(bool val)
+ : val(val ? isl_bool_true : isl_bool_false) {}
+
+ bool is_error() const { return val == isl_bool_error; }
+ bool is_false() const { return val == isl_bool_false; }
+ bool is_true() const { return val == isl_bool_true; }
+
+ explicit operator bool() const {
+ ISLPP_ASSERT(!is_error(), "IMPLEMENTATION ERROR: Unhandled error state");
+ return is_true();
+ }
+
+ boolean operator!() const {
+ if (is_error())
+ return *this;
+ return !is_true();
+ }
+};
+
+inline isl::boolean manage(isl_bool val) {
+ return isl::boolean(val);
+}
+
+class ctx {
+ isl_ctx *ptr;
+public:
+ /* implicit */ ctx(isl_ctx *ctx)
+ : ptr(ctx) {}
+ isl_ctx *release() {
+ auto tmp = ptr;
+ ptr = nullptr;
+ return tmp;
+ }
+ isl_ctx *get() {
+ return ptr;
+ }
+};
+
+enum class stat {
+ ok = isl_stat_ok,
+ error = isl_stat_error
+};
+
+}
+} // namespace isl
--- /dev/null
+/// These are automatically generated C++ bindings without exceptions for isl.
+///
+/// isl is a library for computing with integer sets and maps described by
+/// Presburger formulas. On top of this, isl provides various tools for
+/// polyhedral compilation, ranging from dependence analysis over scheduling
+/// to AST generation.
+
+#ifndef ISL_CPP_NOEXCEPTIONS
+#define ISL_CPP_NOEXCEPTIONS
+
--- /dev/null
+/* Copyright 2016-2017 Tobias Grosser
+ *
+ * Use of this software is governed by the MIT license
+ *
+ * Written by Tobias Grosser, Weststrasse 47, CH-8003, Zurich
+ */
+
+#include <vector>
+#include <string>
+#include <limits.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <isl/options.h>
+#include <isl-noexceptions.h>
+
+static void assert_impl(bool condition, const char *file, int line,
+ const char *message)
+{
+ if (condition)
+ return;
+
+ fprintf(stderr, "Assertion failed in %s:%d %s\n", file, line, message);
+ exit(EXIT_FAILURE);
+}
+
+static void assert_impl(isl::boolean condition, const char *file, int line,
+ const char *message)
+{
+ assert_impl(bool(condition), file, line, message);
+}
+
+#define assert(exp) assert_impl(exp, __FILE__, __LINE__, #exp)
+
+/* Test the pointer interface for interaction between isl C and C++ types.
+ *
+ * This tests:
+ * - construction from an isl C object
+ * - check that constructed objects are non-null
+ * - get a non-owned C pointer from an isl C++ object usable in __isl_keep
+ * methods
+ * - use copy to get an owned C pointer from an isl C++ object which is usable
+ * in __isl_take methods. Verify that the original C++ object retains a valid
+ * pointer.
+ * - use release to get an owned C pointer from an isl C++ object which is
+ * usable in __isl_take methods. Verify that the original C++ object gave up
+ * its pointer and now is null.
+ */
+void test_pointer(isl::ctx ctx)
+{
+ isl_set *c_empty = isl_set_read_from_str(ctx.get(), "{ : false }");
+ isl::set empty = isl::manage(c_empty);
+ assert(empty.is_empty());
+ assert(isl_set_is_empty(empty.get()));
+
+ assert(!empty.is_null());
+ isl_set_free(empty.copy());
+ assert(!empty.is_null());
+ isl_set_free(empty.release());
+ assert(empty.is_null());
+}
+
+/* Test that isl objects can be constructed.
+ *
+ * This tests:
+ * - construction of a null object
+ * - construction from a string
+ * - construction from an integer
+ * - static constructor without a parameter
+ * - conversion construction (implicit)
+ * - conversion construction (explicit)
+ *
+ * The tests to construct from integers and strings cover functionality that
+ * is also tested in the parameter type tests, but here we verify that
+ * multiple overloaded constructors are available and that overload resolution
+ * works as expected.
+ *
+ * Construction from an isl C pointer is tested in test_pointer.
+ */
+void test_constructors(isl::ctx ctx)
+{
+ isl::val null;
+ assert(null.is_null());
+
+ isl::val zero_from_str = isl::val(ctx, "0");
+ assert(zero_from_str.is_zero());
+
+ isl::val zero_int_con = isl::val(ctx, 0);
+ assert(zero_int_con.is_zero());
+
+ isl::val zero_static_con = isl::val::zero(ctx);
+ assert(zero_static_con.is_zero());
+
+ isl::basic_set bs(ctx, "{ [1] }");
+ isl::set result(ctx, "{ [1] }");
+ isl::set s = bs;
+ assert(s.is_equal(result));
+ isl::set s2(bs);
+ assert(s.unite(s2).is_equal(result));
+}
+
+/* Test integer function parameters.
+ *
+ * Verify that extreme values and zero work.
+ */
+void test_parameters_int(isl::ctx ctx)
+{
+ isl::val long_max_str(ctx, std::to_string(LONG_MAX));
+ isl::val long_max_int(ctx, LONG_MAX);
+ assert(long_max_str.eq(long_max_int));
+
+ isl::val long_min_str(ctx, std::to_string(LONG_MIN));
+ isl::val long_min_int(ctx, LONG_MIN);
+ assert(long_min_str.eq(long_min_int));
+
+ isl::val long_zero_str = isl::val(ctx, std::to_string(0));
+ isl::val long_zero_int = isl::val(ctx, 0);
+ assert(long_zero_str.eq(long_zero_int));
+}
+
+/* Test isl objects parameters.
+ *
+ * Verify that isl objects can be passed as lvalue and rvalue parameters.
+ * Also verify that isl object parameters are automatically type converted if
+ * there is an inheritance relation. Finally, test function calls without
+ * any additional parameters, apart from the isl object on which
+ * the method is called.
+ */
+void test_parameters_obj(isl::ctx ctx)
+{
+ isl::set a(ctx, "{ [0] }");
+ isl::set b(ctx, "{ [1] }");
+ isl::set c(ctx, "{ [2] }");
+ isl::set expected(ctx, "{ [i] : 0 <= i <= 2 }");
+
+ isl::set tmp = a.unite(b);
+ isl::set res_lvalue_param = tmp.unite(c);
+ assert(res_lvalue_param.is_equal(expected));
+
+ isl::set res_rvalue_param = a.unite(b).unite(c);
+ assert(res_rvalue_param.is_equal(expected));
+
+ isl::basic_set a2(ctx, "{ [0] }");
+ assert(a.is_equal(a2));
+
+ isl::val two(ctx, 2);
+ isl::val half(ctx, "1/2");
+ isl::val res_only_this_param = two.inv();
+ assert(res_only_this_param.eq(half));
+}
+
+/* Test different kinds of parameters to be passed to functions.
+ *
+ * This includes integer and isl C++ object parameters.
+ */
+void test_parameters(isl::ctx ctx)
+{
+ test_parameters_int(ctx);
+ test_parameters_obj(ctx);
+}
+
+/* Test that isl objects are returned correctly.
+ *
+ * This only tests that after combining two objects, the result is successfully
+ * returned.
+ */
+void test_return_obj(isl::ctx ctx)
+{
+ isl::val one(ctx, "1");
+ isl::val two(ctx, "2");
+ isl::val three(ctx, "3");
+
+ isl::val res = one.add(two);
+
+ assert(res.eq(three));
+}
+
+/* Test that integer values are returned correctly.
+ */
+void test_return_int(isl::ctx ctx)
+{
+ isl::val one(ctx, "1");
+ isl::val neg_one(ctx, "-1");
+ isl::val zero(ctx, "0");
+
+ assert(one.sgn() > 0);
+ assert(neg_one.sgn() < 0);
+ assert(zero.sgn() == 0);
+}
+
+/* Test that isl_bool values are returned correctly.
+ *
+ * We check in detail the following parts of the isl::boolean class:
+ * - The is_true, is_false, and is_error functions return true in case they
+ * are called on a true, false, or error instance of isl::boolean,
+ * respectively
+ * - Explicit conversion to 'bool'
+ * - Implicit conversion to 'bool'
+ * - The complement operator
+ * - Explicit construction from 'true' and 'false'
+ * - Explicit construction form isl_bool
+ */
+void test_return_bool(isl::ctx ctx)
+{
+ isl::set empty(ctx, "{ : false }");
+ isl::set univ(ctx, "{ : }");
+ isl::set null;
+
+ isl::boolean b_true = empty.is_empty();
+ isl::boolean b_false = univ.is_empty();
+ isl::boolean b_error = null.is_empty();
+
+ assert(b_true.is_true());
+ assert(!b_true.is_false());
+ assert(!b_true.is_error());
+
+ assert(!b_false.is_true());
+ assert(b_false.is_false());
+ assert(!b_false.is_error());
+
+ assert(!b_error.is_true());
+ assert(!b_error.is_false());
+ assert(b_error.is_error());
+
+ assert(bool(b_true) == true);
+ assert(bool(b_false) == false);
+
+ assert(b_true);
+
+ assert((!b_false).is_true());
+ assert((!b_true).is_false());
+ assert((!b_error).is_error());
+
+ assert(isl::boolean(true).is_true());
+ assert(!isl::boolean(true).is_false());
+ assert(!isl::boolean(true).is_error());
+
+ assert(isl::boolean(false).is_false());
+ assert(!isl::boolean(false).is_true());
+ assert(!isl::boolean(false).is_error());
+
+ assert(isl::manage(isl_bool_true).is_true());
+ assert(!isl::manage(isl_bool_true).is_false());
+ assert(!isl::manage(isl_bool_true).is_error());
+
+ assert(isl::manage(isl_bool_false).is_false());
+ assert(!isl::manage(isl_bool_false).is_true());
+ assert(!isl::manage(isl_bool_false).is_error());
+
+ assert(isl::manage(isl_bool_error).is_error());
+ assert(!isl::manage(isl_bool_error).is_true());
+ assert(!isl::manage(isl_bool_error).is_false());
+}
+
+/* Test that strings are returned correctly.
+ * Do so by calling overloaded isl::ast_build::from_expr methods.
+ */
+void test_return_string(isl::ctx ctx)
+{
+ isl::set context(ctx, "[n] -> { : }");
+ isl::ast_build build = isl::ast_build::from_context(context);
+ isl::pw_aff pw_aff(ctx, "[n] -> { [n] }");
+ isl::set set(ctx, "[n] -> { : n >= 0 }");
+
+ isl::ast_expr expr = build.expr_from(pw_aff);
+ const char *expected_string = "n";
+ assert(expected_string == expr.to_C_str());
+
+ expr = build.expr_from(set);
+ expected_string = "n >= 0";
+ assert(expected_string == expr.to_C_str());
+}
+
+/* Test that return values are handled correctly.
+ *
+ * Test that isl C++ objects, integers, boolean values, and strings are
+ * returned correctly.
+ */
+void test_return(isl::ctx ctx)
+{
+ test_return_obj(ctx);
+ test_return_int(ctx);
+ test_return_bool(ctx);
+ test_return_string(ctx);
+}
+
+/* Test that foreach functions are modeled correctly.
+ *
+ * Verify that lambdas are correctly called as callback of a 'foreach'
+ * function and that variables captured by the lambda work correctly. Also
+ * check that the foreach function takes account of the return value of the
+ * lambda and aborts in case isl::stat::error is returned and then returns
+ * isl::stat::error itself.
+ */
+void test_foreach(isl::ctx ctx)
+{
+ isl::set s(ctx, "{ [0]; [1]; [2] }");
+
+ std::vector<isl::basic_set> basic_sets;
+
+ auto add_to_vector = [&] (isl::basic_set bs) {
+ basic_sets.push_back(bs);
+ return isl::stat::ok;
+ };
+
+ isl::stat ret1 = s.foreach_basic_set(add_to_vector);
+
+ assert(ret1 == isl::stat::ok);
+ assert(basic_sets.size() == 3);
+ assert(isl::set(basic_sets[0]).is_subset(s));
+ assert(isl::set(basic_sets[1]).is_subset(s));
+ assert(isl::set(basic_sets[2]).is_subset(s));
+ assert(!basic_sets[0].is_equal(basic_sets[1]));
+
+ auto fail = [&] (isl::basic_set bs) {
+ return isl::stat::error;
+ };
+
+ isl::stat ret2 = s.foreach_basic_set(fail);
+
+ assert(ret2 == isl::stat::error);
+}
+
+/* Test the isl C++ interface
+ *
+ * This includes:
+ * - The isl C <-> C++ pointer interface
+ * - Object construction
+ * - Different parameter types
+ * - Different return types
+ * - Foreach functions
+ */
+int main()
+{
+ isl_ctx *ctx = isl_ctx_alloc();
+
+ isl_options_set_on_error(ctx, ISL_ON_ERROR_ABORT);
+
+ test_pointer(ctx);
+ test_constructors(ctx);
+ test_parameters(ctx);
+ test_return(ctx);
+ test_foreach(ctx);
+
+ isl_ctx_free(ctx);
+}
--- /dev/null
+# ===========================================================================
+# https://www.gnu.org/software/autoconf-archive/ax_cxx_compile_stdcxx.html
+# ===========================================================================
+#
+# SYNOPSIS
+#
+# AX_CXX_COMPILE_STDCXX(VERSION, [ext|noext], [mandatory|optional])
+#
+# DESCRIPTION
+#
+# Check for baseline language coverage in the compiler for the specified
+# version of the C++ standard. If necessary, add switches to CXX and
+# CXXCPP to enable support. VERSION may be '11' (for the C++11 standard)
+# or '14' (for the C++14 standard).
+#
+# The second argument, if specified, indicates whether you insist on an
+# extended mode (e.g. -std=gnu++11) or a strict conformance mode (e.g.
+# -std=c++11). If neither is specified, you get whatever works, with
+# preference for an extended mode.
+#
+# The third argument, if specified 'mandatory' or if left unspecified,
+# indicates that baseline support for the specified C++ standard is
+# required and that the macro should error out if no mode with that
+# support is found. If specified 'optional', then configuration proceeds
+# regardless, after defining HAVE_CXX${VERSION} if and only if a
+# supporting mode is found.
+#
+# LICENSE
+#
+# Copyright (c) 2008 Benjamin Kosnik <bkoz@redhat.com>
+# Copyright (c) 2012 Zack Weinberg <zackw@panix.com>
+# Copyright (c) 2013 Roy Stogner <roystgnr@ices.utexas.edu>
+# Copyright (c) 2014, 2015 Google Inc.; contributed by Alexey Sokolov <sokolov@google.com>
+# Copyright (c) 2015 Paul Norman <penorman@mac.com>
+# Copyright (c) 2015 Moritz Klammler <moritz@klammler.eu>
+# Copyright (c) 2016 Krzesimir Nowak <qdlacz@gmail.com>
+#
+# Copying and distribution of this file, with or without modification, are
+# permitted in any medium without royalty provided the copyright notice
+# and this notice are preserved. This file is offered as-is, without any
+# warranty.
+
+#serial 7
+
+dnl This macro is based on the code from the AX_CXX_COMPILE_STDCXX_11 macro
+dnl (serial version number 13).
+
+AX_REQUIRE_DEFINED([AC_MSG_WARN])
+AC_DEFUN([AX_CXX_COMPILE_STDCXX], [dnl
+ m4_if([$1], [11], [ax_cxx_compile_alternatives="11 0x"],
+ [$1], [14], [ax_cxx_compile_alternatives="14 1y"],
+ [$1], [17], [ax_cxx_compile_alternatives="17 1z"],
+ [m4_fatal([invalid first argument `$1' to AX_CXX_COMPILE_STDCXX])])dnl
+ m4_if([$2], [], [],
+ [$2], [ext], [],
+ [$2], [noext], [],
+ [m4_fatal([invalid second argument `$2' to AX_CXX_COMPILE_STDCXX])])dnl
+ m4_if([$3], [], [ax_cxx_compile_cxx$1_required=true],
+ [$3], [mandatory], [ax_cxx_compile_cxx$1_required=true],
+ [$3], [optional], [ax_cxx_compile_cxx$1_required=false],
+ [m4_fatal([invalid third argument `$3' to AX_CXX_COMPILE_STDCXX])])
+ AC_LANG_PUSH([C++])dnl
+ ac_success=no
+ AC_CACHE_CHECK(whether $CXX supports C++$1 features by default,
+ ax_cv_cxx_compile_cxx$1,
+ [AC_COMPILE_IFELSE([AC_LANG_SOURCE([_AX_CXX_COMPILE_STDCXX_testbody_$1])],
+ [ax_cv_cxx_compile_cxx$1=yes],
+ [ax_cv_cxx_compile_cxx$1=no])])
+ if test x$ax_cv_cxx_compile_cxx$1 = xyes; then
+ ac_success=yes
+ fi
+
+ m4_if([$2], [noext], [], [dnl
+ if test x$ac_success = xno; then
+ for alternative in ${ax_cxx_compile_alternatives}; do
+ switch="-std=gnu++${alternative}"
+ cachevar=AS_TR_SH([ax_cv_cxx_compile_cxx$1_$switch])
+ AC_CACHE_CHECK(whether $CXX supports C++$1 features with $switch,
+ $cachevar,
+ [ac_save_CXX="$CXX"
+ CXX="$CXX $switch"
+ AC_COMPILE_IFELSE([AC_LANG_SOURCE([_AX_CXX_COMPILE_STDCXX_testbody_$1])],
+ [eval $cachevar=yes],
+ [eval $cachevar=no])
+ CXX="$ac_save_CXX"])
+ if eval test x\$$cachevar = xyes; then
+ CXX="$CXX $switch"
+ if test -n "$CXXCPP" ; then
+ CXXCPP="$CXXCPP $switch"
+ fi
+ ac_success=yes
+ break
+ fi
+ done
+ fi])
+
+ m4_if([$2], [ext], [], [dnl
+ if test x$ac_success = xno; then
+ dnl HP's aCC needs +std=c++11 according to:
+ dnl http://h21007.www2.hp.com/portal/download/files/unprot/aCxx/PDF_Release_Notes/769149-001.pdf
+ dnl Cray's crayCC needs "-h std=c++11"
+ for alternative in ${ax_cxx_compile_alternatives}; do
+ for switch in -std=c++${alternative} +std=c++${alternative} "-h std=c++${alternative}"; do
+ cachevar=AS_TR_SH([ax_cv_cxx_compile_cxx$1_$switch])
+ AC_CACHE_CHECK(whether $CXX supports C++$1 features with $switch,
+ $cachevar,
+ [ac_save_CXX="$CXX"
+ CXX="$CXX $switch"
+ AC_COMPILE_IFELSE([AC_LANG_SOURCE([_AX_CXX_COMPILE_STDCXX_testbody_$1])],
+ [eval $cachevar=yes],
+ [eval $cachevar=no])
+ CXX="$ac_save_CXX"])
+ if eval test x\$$cachevar = xyes; then
+ CXX="$CXX $switch"
+ if test -n "$CXXCPP" ; then
+ CXXCPP="$CXXCPP $switch"
+ fi
+ ac_success=yes
+ break
+ fi
+ done
+ if test x$ac_success = xyes; then
+ break
+ fi
+ done
+ fi])
+ AC_LANG_POP([C++])
+ if test x$ax_cxx_compile_cxx$1_required = xtrue; then
+ if test x$ac_success = xno; then
+ AC_MSG_ERROR([*** A compiler with support for C++$1 language features is required.])
+ fi
+ fi
+ if test x$ac_success = xno; then
+ HAVE_CXX$1=0
+ AC_MSG_NOTICE([No compiler with C++$1 support was found])
+ else
+ HAVE_CXX$1=1
+ AC_DEFINE(HAVE_CXX$1,1,
+ [define if the compiler supports basic C++$1 syntax])
+ fi
+ AC_SUBST(HAVE_CXX$1)
+ m4_if([$1], [17], [AC_MSG_WARN([C++17 is not yet standardized, so the checks may change in incompatible ways anytime])])
+])
+
+
+dnl Test body for checking C++11 support
+
+m4_define([_AX_CXX_COMPILE_STDCXX_testbody_11],
+ _AX_CXX_COMPILE_STDCXX_testbody_new_in_11
+)
+
+
+dnl Test body for checking C++14 support
+
+m4_define([_AX_CXX_COMPILE_STDCXX_testbody_14],
+ _AX_CXX_COMPILE_STDCXX_testbody_new_in_11
+ _AX_CXX_COMPILE_STDCXX_testbody_new_in_14
+)
+
+m4_define([_AX_CXX_COMPILE_STDCXX_testbody_17],
+ _AX_CXX_COMPILE_STDCXX_testbody_new_in_11
+ _AX_CXX_COMPILE_STDCXX_testbody_new_in_14
+ _AX_CXX_COMPILE_STDCXX_testbody_new_in_17
+)
+
+dnl Tests for new features in C++11
+
+m4_define([_AX_CXX_COMPILE_STDCXX_testbody_new_in_11], [[
+
+// If the compiler admits that it is not ready for C++11, why torture it?
+// Hopefully, this will speed up the test.
+
+#ifndef __cplusplus
+
+#error "This is not a C++ compiler"
+
+#elif __cplusplus < 201103L
+
+#error "This is not a C++11 compiler"
+
+#else
+
+namespace cxx11
+{
+
+ namespace test_static_assert
+ {
+
+ template <typename T>
+ struct check
+ {
+ static_assert(sizeof(int) <= sizeof(T), "not big enough");
+ };
+
+ }
+
+ namespace test_final_override
+ {
+
+ struct Base
+ {
+ virtual void f() {}
+ };
+
+ struct Derived : public Base
+ {
+ virtual void f() override {}
+ };
+
+ }
+
+ namespace test_double_right_angle_brackets
+ {
+
+ template < typename T >
+ struct check {};
+
+ typedef check<void> single_type;
+ typedef check<check<void>> double_type;
+ typedef check<check<check<void>>> triple_type;
+ typedef check<check<check<check<void>>>> quadruple_type;
+
+ }
+
+ namespace test_decltype
+ {
+
+ int
+ f()
+ {
+ int a = 1;
+ decltype(a) b = 2;
+ return a + b;
+ }
+
+ }
+
+ namespace test_type_deduction
+ {
+
+ template < typename T1, typename T2 >
+ struct is_same
+ {
+ static const bool value = false;
+ };
+
+ template < typename T >
+ struct is_same<T, T>
+ {
+ static const bool value = true;
+ };
+
+ template < typename T1, typename T2 >
+ auto
+ add(T1 a1, T2 a2) -> decltype(a1 + a2)
+ {
+ return a1 + a2;
+ }
+
+ int
+ test(const int c, volatile int v)
+ {
+ static_assert(is_same<int, decltype(0)>::value == true, "");
+ static_assert(is_same<int, decltype(c)>::value == false, "");
+ static_assert(is_same<int, decltype(v)>::value == false, "");
+ auto ac = c;
+ auto av = v;
+ auto sumi = ac + av + 'x';
+ auto sumf = ac + av + 1.0;
+ static_assert(is_same<int, decltype(ac)>::value == true, "");
+ static_assert(is_same<int, decltype(av)>::value == true, "");
+ static_assert(is_same<int, decltype(sumi)>::value == true, "");
+ static_assert(is_same<int, decltype(sumf)>::value == false, "");
+ static_assert(is_same<int, decltype(add(c, v))>::value == true, "");
+ return (sumf > 0.0) ? sumi : add(c, v);
+ }
+
+ }
+
+ namespace test_noexcept
+ {
+
+ int f() { return 0; }
+ int g() noexcept { return 0; }
+
+ static_assert(noexcept(f()) == false, "");
+ static_assert(noexcept(g()) == true, "");
+
+ }
+
+ namespace test_constexpr
+ {
+
+ template < typename CharT >
+ unsigned long constexpr
+ strlen_c_r(const CharT *const s, const unsigned long acc) noexcept
+ {
+ return *s ? strlen_c_r(s + 1, acc + 1) : acc;
+ }
+
+ template < typename CharT >
+ unsigned long constexpr
+ strlen_c(const CharT *const s) noexcept
+ {
+ return strlen_c_r(s, 0UL);
+ }
+
+ static_assert(strlen_c("") == 0UL, "");
+ static_assert(strlen_c("1") == 1UL, "");
+ static_assert(strlen_c("example") == 7UL, "");
+ static_assert(strlen_c("another\0example") == 7UL, "");
+
+ }
+
+ namespace test_rvalue_references
+ {
+
+ template < int N >
+ struct answer
+ {
+ static constexpr int value = N;
+ };
+
+ answer<1> f(int&) { return answer<1>(); }
+ answer<2> f(const int&) { return answer<2>(); }
+ answer<3> f(int&&) { return answer<3>(); }
+
+ void
+ test()
+ {
+ int i = 0;
+ const int c = 0;
+ static_assert(decltype(f(i))::value == 1, "");
+ static_assert(decltype(f(c))::value == 2, "");
+ static_assert(decltype(f(0))::value == 3, "");
+ }
+
+ }
+
+ namespace test_uniform_initialization
+ {
+
+ struct test
+ {
+ static const int zero {};
+ static const int one {1};
+ };
+
+ static_assert(test::zero == 0, "");
+ static_assert(test::one == 1, "");
+
+ }
+
+ namespace test_lambdas
+ {
+
+ void
+ test1()
+ {
+ auto lambda1 = [](){};
+ auto lambda2 = lambda1;
+ lambda1();
+ lambda2();
+ }
+
+ int
+ test2()
+ {
+ auto a = [](int i, int j){ return i + j; }(1, 2);
+ auto b = []() -> int { return '0'; }();
+ auto c = [=](){ return a + b; }();
+ auto d = [&](){ return c; }();
+ auto e = [a, &b](int x) mutable {
+ const auto identity = [](int y){ return y; };
+ for (auto i = 0; i < a; ++i)
+ a += b--;
+ return x + identity(a + b);
+ }(0);
+ return a + b + c + d + e;
+ }
+
+ int
+ test3()
+ {
+ const auto nullary = [](){ return 0; };
+ const auto unary = [](int x){ return x; };
+ using nullary_t = decltype(nullary);
+ using unary_t = decltype(unary);
+ const auto higher1st = [](nullary_t f){ return f(); };
+ const auto higher2nd = [unary](nullary_t f1){
+ return [unary, f1](unary_t f2){ return f2(unary(f1())); };
+ };
+ return higher1st(nullary) + higher2nd(nullary)(unary);
+ }
+
+ }
+
+ namespace test_variadic_templates
+ {
+
+ template <int...>
+ struct sum;
+
+ template <int N0, int... N1toN>
+ struct sum<N0, N1toN...>
+ {
+ static constexpr auto value = N0 + sum<N1toN...>::value;
+ };
+
+ template <>
+ struct sum<>
+ {
+ static constexpr auto value = 0;
+ };
+
+ static_assert(sum<>::value == 0, "");
+ static_assert(sum<1>::value == 1, "");
+ static_assert(sum<23>::value == 23, "");
+ static_assert(sum<1, 2>::value == 3, "");
+ static_assert(sum<5, 5, 11>::value == 21, "");
+ static_assert(sum<2, 3, 5, 7, 11, 13>::value == 41, "");
+
+ }
+
+ // http://stackoverflow.com/questions/13728184/template-aliases-and-sfinae
+ // Clang 3.1 fails with headers of libstd++ 4.8.3 when using std::function
+ // because of this.
+ namespace test_template_alias_sfinae
+ {
+
+ struct foo {};
+
+ template<typename T>
+ using member = typename T::member_type;
+
+ template<typename T>
+ void func(...) {}
+
+ template<typename T>
+ void func(member<T>*) {}
+
+ void test();
+
+ void test() { func<foo>(0); }
+
+ }
+
+} // namespace cxx11
+
+#endif // __cplusplus >= 201103L
+
+]])
+
+
+dnl Tests for new features in C++14
+
+m4_define([_AX_CXX_COMPILE_STDCXX_testbody_new_in_14], [[
+
+// If the compiler admits that it is not ready for C++14, why torture it?
+// Hopefully, this will speed up the test.
+
+#ifndef __cplusplus
+
+#error "This is not a C++ compiler"
+
+#elif __cplusplus < 201402L
+
+#error "This is not a C++14 compiler"
+
+#else
+
+namespace cxx14
+{
+
+ namespace test_polymorphic_lambdas
+ {
+
+ int
+ test()
+ {
+ const auto lambda = [](auto&&... args){
+ const auto istiny = [](auto x){
+ return (sizeof(x) == 1UL) ? 1 : 0;
+ };
+ const int aretiny[] = { istiny(args)... };
+ return aretiny[0];
+ };
+ return lambda(1, 1L, 1.0f, '1');
+ }
+
+ }
+
+ namespace test_binary_literals
+ {
+
+ constexpr auto ivii = 0b0000000000101010;
+ static_assert(ivii == 42, "wrong value");
+
+ }
+
+ namespace test_generalized_constexpr
+ {
+
+ template < typename CharT >
+ constexpr unsigned long
+ strlen_c(const CharT *const s) noexcept
+ {
+ auto length = 0UL;
+ for (auto p = s; *p; ++p)
+ ++length;
+ return length;
+ }
+
+ static_assert(strlen_c("") == 0UL, "");
+ static_assert(strlen_c("x") == 1UL, "");
+ static_assert(strlen_c("test") == 4UL, "");
+ static_assert(strlen_c("another\0test") == 7UL, "");
+
+ }
+
+ namespace test_lambda_init_capture
+ {
+
+ int
+ test()
+ {
+ auto x = 0;
+ const auto lambda1 = [a = x](int b){ return a + b; };
+ const auto lambda2 = [a = lambda1(x)](){ return a; };
+ return lambda2();
+ }
+
+ }
+
+ namespace test_digit_separators
+ {
+
+ constexpr auto ten_million = 100'000'000;
+ static_assert(ten_million == 100000000, "");
+
+ }
+
+ namespace test_return_type_deduction
+ {
+
+ auto f(int& x) { return x; }
+ decltype(auto) g(int& x) { return x; }
+
+ template < typename T1, typename T2 >
+ struct is_same
+ {
+ static constexpr auto value = false;
+ };
+
+ template < typename T >
+ struct is_same<T, T>
+ {
+ static constexpr auto value = true;
+ };
+
+ int
+ test()
+ {
+ auto x = 0;
+ static_assert(is_same<int, decltype(f(x))>::value, "");
+ static_assert(is_same<int&, decltype(g(x))>::value, "");
+ return x;
+ }
+
+ }
+
+} // namespace cxx14
+
+#endif // __cplusplus >= 201402L
+
+]])
+
+
+dnl Tests for new features in C++17
+
+m4_define([_AX_CXX_COMPILE_STDCXX_testbody_new_in_17], [[
+
+// If the compiler admits that it is not ready for C++17, why torture it?
+// Hopefully, this will speed up the test.
+
+#ifndef __cplusplus
+
+#error "This is not a C++ compiler"
+
+#elif __cplusplus <= 201402L
+
+#error "This is not a C++17 compiler"
+
+#else
+
+#if defined(__clang__)
+ #define REALLY_CLANG
+#else
+ #if defined(__GNUC__)
+ #define REALLY_GCC
+ #endif
+#endif
+
+#include <initializer_list>
+#include <utility>
+#include <type_traits>
+
+namespace cxx17
+{
+
+#if !defined(REALLY_CLANG)
+ namespace test_constexpr_lambdas
+ {
+
+ // TODO: test it with clang++ from git
+
+ constexpr int foo = [](){return 42;}();
+
+ }
+#endif // !defined(REALLY_CLANG)
+
+ namespace test::nested_namespace::definitions
+ {
+
+ }
+
+ namespace test_fold_expression
+ {
+
+ template<typename... Args>
+ int multiply(Args... args)
+ {
+ return (args * ... * 1);
+ }
+
+ template<typename... Args>
+ bool all(Args... args)
+ {
+ return (args && ...);
+ }
+
+ }
+
+ namespace test_extended_static_assert
+ {
+
+ static_assert (true);
+
+ }
+
+ namespace test_auto_brace_init_list
+ {
+
+ auto foo = {5};
+ auto bar {5};
+
+ static_assert(std::is_same<std::initializer_list<int>, decltype(foo)>::value);
+ static_assert(std::is_same<int, decltype(bar)>::value);
+ }
+
+ namespace test_typename_in_template_template_parameter
+ {
+
+ template<template<typename> typename X> struct D;
+
+ }
+
+ namespace test_fallthrough_nodiscard_maybe_unused_attributes
+ {
+
+ int f1()
+ {
+ return 42;
+ }
+
+ [[nodiscard]] int f2()
+ {
+ [[maybe_unused]] auto unused = f1();
+
+ switch (f1())
+ {
+ case 17:
+ f1();
+ [[fallthrough]];
+ case 42:
+ f1();
+ }
+ return f1();
+ }
+
+ }
+
+ namespace test_extended_aggregate_initialization
+ {
+
+ struct base1
+ {
+ int b1, b2 = 42;
+ };
+
+ struct base2
+ {
+ base2() {
+ b3 = 42;
+ }
+ int b3;
+ };
+
+ struct derived : base1, base2
+ {
+ int d;
+ };
+
+ derived d1 {{1, 2}, {}, 4}; // full initialization
+ derived d2 {{}, {}, 4}; // value-initialized bases
+
+ }
+
+ namespace test_general_range_based_for_loop
+ {
+
+ struct iter
+ {
+ int i;
+
+ int& operator* ()
+ {
+ return i;
+ }
+
+ const int& operator* () const
+ {
+ return i;
+ }
+
+ iter& operator++()
+ {
+ ++i;
+ return *this;
+ }
+ };
+
+ struct sentinel
+ {
+ int i;
+ };
+
+ bool operator== (const iter& i, const sentinel& s)
+ {
+ return i.i == s.i;
+ }
+
+ bool operator!= (const iter& i, const sentinel& s)
+ {
+ return !(i == s);
+ }
+
+ struct range
+ {
+ iter begin() const
+ {
+ return {0};
+ }
+
+ sentinel end() const
+ {
+ return {5};
+ }
+ };
+
+ void f()
+ {
+ range r {};
+
+ for (auto i : r)
+ {
+ [[maybe_unused]] auto v = i;
+ }
+ }
+
+ }
+
+ namespace test_lambda_capture_asterisk_this_by_value
+ {
+
+ struct t
+ {
+ int i;
+ int foo()
+ {
+ return [*this]()
+ {
+ return i;
+ }();
+ }
+ };
+
+ }
+
+ namespace test_enum_class_construction
+ {
+
+ enum class byte : unsigned char
+ {};
+
+ byte foo {42};
+
+ }
+
+ namespace test_constexpr_if
+ {
+
+ template <bool cond>
+ int f ()
+ {
+ if constexpr(cond)
+ {
+ return 13;
+ }
+ else
+ {
+ return 42;
+ }
+ }
+
+ }
+
+ namespace test_selection_statement_with_initializer
+ {
+
+ int f()
+ {
+ return 13;
+ }
+
+ int f2()
+ {
+ if (auto i = f(); i > 0)
+ {
+ return 3;
+ }
+
+ switch (auto i = f(); i + 4)
+ {
+ case 17:
+ return 2;
+
+ default:
+ return 1;
+ }
+ }
+
+ }
+
+#if !defined(REALLY_CLANG)
+ namespace test_template_argument_deduction_for_class_templates
+ {
+
+ // TODO: test it with clang++ from git
+
+ template <typename T1, typename T2>
+ struct pair
+ {
+ pair (T1 p1, T2 p2)
+ : m1 {p1},
+ m2 {p2}
+ {}
+
+ T1 m1;
+ T2 m2;
+ };
+
+ void f()
+ {
+ [[maybe_unused]] auto p = pair{13, 42u};
+ }
+
+ }
+#endif // !defined(REALLY_CLANG)
+
+ namespace test_non_type_auto_template_parameters
+ {
+
+ template <auto n>
+ struct B
+ {};
+
+ B<5> b1;
+ B<'a'> b2;
+
+ }
+
+#if !defined(REALLY_CLANG)
+ namespace test_structured_bindings
+ {
+
+ // TODO: test it with clang++ from git
+
+ int arr[2] = { 1, 2 };
+ std::pair<int, int> pr = { 1, 2 };
+
+ auto f1() -> int(&)[2]
+ {
+ return arr;
+ }
+
+ auto f2() -> std::pair<int, int>&
+ {
+ return pr;
+ }
+
+ struct S
+ {
+ int x1 : 2;
+ volatile double y1;
+ };
+
+ S f3()
+ {
+ return {};
+ }
+
+ auto [ x1, y1 ] = f1();
+ auto& [ xr1, yr1 ] = f1();
+ auto [ x2, y2 ] = f2();
+ auto& [ xr2, yr2 ] = f2();
+ const auto [ x3, y3 ] = f3();
+
+ }
+#endif // !defined(REALLY_CLANG)
+
+#if !defined(REALLY_CLANG)
+ namespace test_exception_spec_type_system
+ {
+
+ // TODO: test it with clang++ from git
+
+ struct Good {};
+ struct Bad {};
+
+ void g1() noexcept;
+ void g2();
+
+ template<typename T>
+ Bad
+ f(T*, T*);
+
+ template<typename T1, typename T2>
+ Good
+ f(T1*, T2*);
+
+ static_assert (std::is_same_v<Good, decltype(f(g1, g2))>);
+
+ }
+#endif // !defined(REALLY_CLANG)
+
+ namespace test_inline_variables
+ {
+
+ template<class T> void f(T)
+ {}
+
+ template<class T> inline T g(T)
+ {
+ return T{};
+ }
+
+ template<> inline void f<>(int)
+ {}
+
+ template<> int g<>(int)
+ {
+ return 5;
+ }
+
+ }
+
+} // namespace cxx17
+
+#endif // __cplusplus <= 201402L
+
+]])
--- /dev/null
+# ============================================================================
+# http://www.gnu.org/software/autoconf-archive/ax_cxx_compile_stdcxx_11.html
+# ============================================================================
+#
+# SYNOPSIS
+#
+# AX_CXX_COMPILE_STDCXX_11([ext|noext], [mandatory|optional])
+#
+# DESCRIPTION
+#
+# Check for baseline language coverage in the compiler for the C++11
+# standard; if necessary, add switches to CXX and CXXCPP to enable
+# support.
+#
+# This macro is a convenience alias for calling the AX_CXX_COMPILE_STDCXX
+# macro with the version set to C++11. The two optional arguments are
+# forwarded literally as the second and third argument respectively.
+# Please see the documentation for the AX_CXX_COMPILE_STDCXX macro for
+# more information. If you want to use this macro, you also need to
+# download the ax_cxx_compile_stdcxx.m4 file.
+#
+# LICENSE
+#
+# Copyright (c) 2008 Benjamin Kosnik <bkoz@redhat.com>
+# Copyright (c) 2012 Zack Weinberg <zackw@panix.com>
+# Copyright (c) 2013 Roy Stogner <roystgnr@ices.utexas.edu>
+# Copyright (c) 2014, 2015 Google Inc.; contributed by Alexey Sokolov <sokolov@google.com>
+# Copyright (c) 2015 Paul Norman <penorman@mac.com>
+# Copyright (c) 2015 Moritz Klammler <moritz@klammler.eu>
+#
+# Copying and distribution of this file, with or without modification, are
+# permitted in any medium without royalty provided the copyright notice
+# and this notice are preserved. This file is offered as-is, without any
+# warranty.
+
+#serial 17
+
+AX_REQUIRE_DEFINED([AX_CXX_COMPILE_STDCXX])
+AC_DEFUN([AX_CXX_COMPILE_STDCXX_11], [AX_CXX_COMPILE_STDCXX([11], [$1], [$2])])