diff --git a/include/isl/ctx.h b/include/isl/ctx.h index 7c925233..ecb04406 100644 --- a/include/isl/ctx.h +++ b/include/isl/ctx.h @@ -39,6 +39,9 @@ #ifndef __isl_subclass #define __isl_subclass(super) #endif +#ifndef __isl_list +#define __isl_list(elem) +#endif #if defined(__cplusplus) extern "C" { diff --git a/include/isl/id.h b/include/isl/id.h index c025d513..f6a31e7d 100644 --- a/include/isl/id.h +++ b/include/isl/id.h @@ -10,7 +10,7 @@ extern "C" { #endif -struct isl_id; +struct __isl_export isl_id; typedef struct isl_id isl_id; ISL_DECLARE_LIST(id) @@ -23,7 +23,9 @@ __isl_give isl_id *isl_id_alloc(isl_ctx *ctx, __isl_give isl_id *isl_id_copy(isl_id *id); __isl_null isl_id *isl_id_free(__isl_take isl_id *id); +__isl_export void *isl_id_get_user(__isl_keep isl_id *id); +__isl_export __isl_keep const char *isl_id_get_name(__isl_keep isl_id *id); __isl_give isl_id *isl_id_set_free_user(__isl_take isl_id *id, diff --git a/include/isl/map.h b/include/isl/map.h index 0ff17fe5..8c5fb4ab 100644 --- a/include/isl/map.h +++ b/include/isl/map.h @@ -146,6 +146,7 @@ __isl_export __isl_give isl_basic_map *isl_basic_map_intersect( __isl_take isl_basic_map *bmap1, __isl_take isl_basic_map *bmap2); +__isl_export __isl_give isl_basic_map *isl_basic_map_list_intersect( __isl_take isl_basic_map_list *list); __isl_export diff --git a/include/isl/map_type.h b/include/isl/map_type.h index 7c30056f..d09a937c 100644 --- a/include/isl/map_type.h +++ b/include/isl/map_type.h @@ -10,6 +10,7 @@ extern "C" { struct __isl_subclass(isl_map) isl_basic_map; typedef struct isl_basic_map isl_basic_map; +struct __isl_list(isl_basic_map) isl_basic_map_list; ISL_DECLARE_LIST_TYPE(basic_map) struct __isl_subclass(isl_union_map) isl_map; typedef struct isl_map isl_map; diff --git a/include/isl/set.h b/include/isl/set.h index 793195b0..9041774c 100644 --- a/include/isl/set.h +++ b/include/isl/set.h @@ -75,10 +75,13 @@ isl_bool isl_set_has_dim_id(__isl_keep isl_set *set, enum isl_dim_type type, unsigned pos); __isl_give isl_id *isl_set_get_dim_id(__isl_keep isl_set *set, enum isl_dim_type type, unsigned pos); +__isl_export __isl_give isl_set *isl_set_set_tuple_id(__isl_take isl_set *set, __isl_take isl_id *id); __isl_give isl_set *isl_set_reset_tuple_id(__isl_take isl_set *set); +__isl_export isl_bool isl_set_has_tuple_id(__isl_keep isl_set *set); +__isl_export __isl_give isl_id *isl_set_get_tuple_id(__isl_keep isl_set *set); __isl_give isl_set *isl_set_reset_user(__isl_take isl_set *set); diff --git a/include/isl/val.h b/include/isl/val.h index fb50eaa4..225c9cb6 100644 --- a/include/isl/val.h +++ b/include/isl/val.h @@ -13,6 +13,7 @@ extern "C" { struct __isl_export isl_val; typedef struct isl_val isl_val; +struct __isl_list(isl_val) isl_val_list; ISL_DECLARE_LIST(val) struct __isl_export isl_multi_val; diff --git a/interface/cpp.cc b/interface/cpp.cc index 5668088f..78eedf5e 100644 --- a/interface/cpp.cc +++ b/interface/cpp.cc @@ -73,6 +73,22 @@ static std::string to_string(long l) return strm.str(); } +cpp_generator::cpp_generator(set &exported_types, + set exported_functions, + set functions) : + generator(exported_types, exported_functions, functions) +{ + map::iterator ci; + + for (ci = classes.begin(); ci != classes.end(); ++ci) { + vector element_type = + get_list_element_type_name(ci->second.type); + if (element_type.empty()) + continue; + list_types[ci->second.name] = element_type[0]; + } +} + /* Generate a cpp interface based on the extracted types and functions. * * Print first a set of forward declarations for all isl wrapper @@ -123,7 +139,10 @@ void cpp_generator::print_declarations(ostream &os) else osprintf(os, "\n"); - print_class(os, ci->second); + if (is_list_type(ci->second)) + print_list_specialization(os, ci->second); + else + print_class(os, ci->second); } } @@ -144,9 +163,8 @@ void cpp_generator::print_implementations(ostream &os) } } -/* Print declarations for class "clazz" to "os". - */ -void cpp_generator::print_class(ostream &os, const isl_class &clazz) +void cpp_generator::print_common_class_body(ostream &os, const isl_class &clazz, + bool is_template_specialization) { const char *name = clazz.name.c_str(); std::string cppstring = type2cpp(clazz); @@ -156,6 +174,8 @@ void cpp_generator::print_class(ostream &os, const isl_class &clazz) print_class_factory_decl(os, clazz); osprintf(os, "\n"); + if (is_template_specialization) + osprintf(os, "template <>\n"); osprintf(os, "class %s {\n", cppname); print_class_factory_decl(os, clazz, " friend "); osprintf(os, "\n"); @@ -171,15 +191,31 @@ void cpp_generator::print_class(ostream &os, const isl_class &clazz) print_ptr_decl(os, clazz); osprintf(os, "\n"); print_methods_decl(os, clazz); - + print_custom_public_decl(os, clazz); osprintf(os, "};\n"); } +/* Print declarations for class "clazz" to "os". + */ +void cpp_generator::print_class(ostream &os, const isl_class &clazz) +{ + print_common_class_body(os, clazz); +} + +void cpp_generator::print_list_specialization(ostream &os, + const isl_class &clazz) +{ + print_common_class_body(os, clazz, true); +} + /* Print forward declaration of class "clazz" to "os". */ void cpp_generator::print_class_forward_decl(ostream &os, const isl_class &clazz) { + if (is_list_type(clazz)) + return; + std::string cppstring = type2cpp(clazz); const char *cppname = cppstring.c_str(); @@ -234,6 +270,10 @@ void cpp_generator::print_private_constructors_decl(ostream &os, { const char *name = clazz.name.c_str(); std::string cppstring = type2cpp(clazz); + + if (is_list_type(clazz)) + cppstring = instance_type(cppstring); + const char *cppname = cppstring.c_str(); osprintf(os, " inline explicit %s(__isl_take %s *ptr);\n", cppname, @@ -256,11 +296,17 @@ void cpp_generator::print_public_constructors_decl(ostream &os, const isl_class &clazz) { std::string cppstring = type2cpp(clazz); + std::string constructor_string = cppstring; + + if (is_list_type(clazz)) + constructor_string = instance_type(constructor_string); + const char *cppname = cppstring.c_str(); - osprintf(os, " inline /* implicit */ %s();\n", cppname); + const char *constructor_name = constructor_string.c_str(); + osprintf(os, " inline /* implicit */ %s();\n", constructor_name); osprintf(os, " inline /* implicit */ %s(const isl::%s &obj);\n", - cppname, cppname); + constructor_name, cppname); } /* Print declarations for constructors for class "class" to "os". @@ -371,6 +417,48 @@ void cpp_generator::print_methods_decl(ostream &os, const isl_class &clazz) print_method_group_decl(os, clazz, it->first, it->second); } +/* Print declarations for custom members of a class "clazz" to "os", based on + * the class name. + */ +void cpp_generator::print_custom_public_decl(ostream &os, + const isl_class &clazz) +{ + string cppname = type2cpp(clazz); + + if (is_list_type(clazz)) { + const char *declarations = + " template \n" + " inline list(isl::ctx ctx, InputIt1 from, " + "InputIt2 to);\n\n" + " inline int size() const;\n" + " iterator begin() const;\n" + " iterator end() const;\n"; + string element_string = type2cpp(list_element_type_name(clazz)); + const char *element_type = element_string.c_str(); + + osprintf(os, " typedef list_iterator<%s> iterator;\n", + element_type); + osprintf(os, "%s", declarations); + osprintf(os, " inline %s at(int pos) const;\n", element_type); + osprintf(os, " inline %s operator[](int pos) const;\n", + element_type); + } else if ("id" == cppname) { + const char *declarations = + " inline id(isl::ctx ctx, const std::string &name);\n" + " inline id(isl::ctx ctx, const std::string &name,\n" + " void *usr,\n" + " void (*deleter)(void *) = nullptr);\n" + " inline id(isl::ctx ctx, void *usr,\n" + " void (*deleter)(void *) = nullptr);\n" + " inline bool has_name() const;\n" + " inline id set_free_user(" + "void (*deleter)(void *)) const;\n" + " inline bool operator==(const id &other) const;\n" + " inline bool operator!=(const id &other) const;\n"; + osprintf(os, "%s", declarations); + } +} + /* Print declarations for methods "methods" of name "fullname" in class "clazz" * to "os". * @@ -427,6 +515,8 @@ void cpp_generator::print_class_impl(ostream &os, const isl_class &clazz) print_ptr_impl(os, clazz); osprintf(os, "\n"); print_methods_impl(os, clazz); + osprintf(os, "\n"); + print_custom_methods_impl(os, clazz); } /* Print implementation of global factory function to "os". @@ -456,9 +546,12 @@ void cpp_generator::print_private_constructors_impl(ostream &os, const char *name = clazz.name.c_str(); std::string cppstring = type2cpp(clazz); const char *cppname = cppstring.c_str(); + std::string constructor_string = + is_list_type(clazz) ? instance_type(cppstring) : cppstring; + const char *constructor_name = constructor_string.c_str(); osprintf(os, "%s::%s(__isl_take %s *ptr)\n : ptr(ptr) {}\n", - cppname, cppname, name); + cppname, constructor_name, name); } /* Print implementations of public constructors for class "clazz" to "os". @@ -466,13 +559,16 @@ void cpp_generator::print_private_constructors_impl(ostream &os, void cpp_generator::print_public_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(); + std::string constructor_string = + is_list_type(clazz) ? instance_type(cppstring) : cppstring; + const char *constructor_name = constructor_string.c_str(); - osprintf(os, "%s::%s()\n : ptr(nullptr) {}\n\n", cppname, cppname); + osprintf(os, "%s::%s()\n : ptr(nullptr) {}\n\n", cppname, + constructor_name); osprintf(os, "%s::%s(const isl::%s &obj)\n : ptr(obj.copy()) {}\n", - cppname, cppname, cppname, name); + cppname, constructor_name, cppname); } /* Print implementations of constructors for class "clazz" to "os". @@ -516,8 +612,11 @@ void cpp_generator::print_destructor_impl(ostream &os, const char *name = clazz.name.c_str(); std::string cppstring = type2cpp(clazz); const char *cppname = cppstring.c_str(); + std::string constructor_string = + is_list_type(clazz) ? instance_type(cppstring) : cppstring; + const char *constructor_name = constructor_string.c_str(); - osprintf(os, "%s::~%s() {\n", cppname, cppname); + osprintf(os, "%s::~%s() {\n", cppname, constructor_name); osprintf(os, " if (ptr)\n"); osprintf(os, " %s_free(ptr);\n", name); osprintf(os, "}\n"); @@ -563,6 +662,101 @@ void cpp_generator::print_methods_impl(ostream &os, const isl_class &clazz) } } +/* Print definitions for custom methods of class "clazz" to "os", based on the + * class name. + */ +void cpp_generator::print_custom_methods_impl(ostream &os, + const isl_class &clazz) +{ + string name = type2cpp(clazz); + const char *cname = name.c_str(); + if (is_list_type(clazz)) { + string element_string = list_element_type_name(clazz); + const char *element_type = element_string.c_str(); + string element_string_noprefix = element_string.substr(4); + const char *element_name = element_string_noprefix.c_str(); + string element_cppstring = type2cpp(element_string); + const char *element_cpptype = element_cppstring.c_str(); + + osprintf(os, + "template \n"); + osprintf(os, "%s::list(isl::ctx ctx, InputIt1 from, " + "InputIt2 to) {\n", cname); + osprintf(os, + " ptr = %s_list_alloc(ctx.get(), ", element_type); + osprintf(os, "std::distance(from, to));\n"); + osprintf(os, " for ( ; from != to; ++from) {\n"); + osprintf(os, " ptr = %s_list_add(ptr, from->copy());\n", + element_type); + osprintf(os, " }\n"); + osprintf(os, "}\n\n"); + + osprintf(os, "int %s::size() const {\n", cname); + osprintf(os, " return %s_list_n_%s(ptr);\n", element_type, + element_name); + osprintf(os, "}\n\n"); + + osprintf(os, "isl::%s %s::at(int pos) const {\n", element_cpptype, + cname); + osprintf(os, " ISLPP_ASSERT(pos >= 0 && pos < size(),\n"); + osprintf(os, " \"position out of range\");\n"); + osprintf(os, " return manage(%s_list_get_%s(ptr, pos));\n", + element_type, element_name); + osprintf(os, "}\n\n"); + + osprintf(os, "isl::%s %s::operator[](int pos) const {\n", + element_cpptype, cname); + osprintf(os, " return manage(%s_list_get_%s(ptr, pos));\n", + element_type, element_name); + osprintf(os, "}\n\n"); + + osprintf(os, "typename isl::%s::iterator\n", cname); + osprintf(os, "%s::begin() const {\n", cname); + osprintf(os, " return list_iterator<%s>(this, 0);\n", + element_cpptype); + osprintf(os, "}\n\n"); + + osprintf(os, "typename isl::%s::iterator\n", cname); + osprintf(os, "%s::end() const {\n", cname); + osprintf(os, " return list_iterator<%s>(this, -1);\n", + element_cpptype); + osprintf(os, "}\n\n"); + } else if ("id" == name) { + const char *definitions = + "id::id(isl::ctx ctx, const std::string &name) {\n" + " ptr = isl_id_alloc(ctx.get(), name.c_str(),\n" + " nullptr);\n" + "}\n\n" + "id::id(isl::ctx ctx, const std::string &name,\n" + " void *user, void (*deleter)(void *)) {\n" + " ptr = isl_id_alloc(ctx.get(), name.c_str(), user);\n" + " if (deleter)\n" + " ptr = isl_id_set_free_user(ptr, deleter);\n" + "}\n\n" + "id::id(isl::ctx ctx, void *user,\n" + " void (*deleter)(void *)) {\n" + " ptr = isl_id_alloc(ctx.get(), nullptr, user);\n" + " if (deleter)\n" + " ptr = isl_id_set_free_user(ptr, deleter);\n" + "}\n\n" + "bool id::has_name() const {\n" + " return isl_id_get_name(ptr) != nullptr;\n" + "}\n\n" + "id id::set_free_user(" + "void (*deleter)(void *)) const {\n" + " auto res = isl_id_set_free_user(copy(), deleter);\n" + " return manage(res);\n" + "}\n\n" + "bool id::operator==(const isl::id &other) const {\n" + " return ptr == other.ptr;\n" + "}\n\n" + "bool id::operator!=(const isl::id &other) const {\n" + " return !operator==(other);\n" + "}\n\n"; + osprintf(os, "%s", definitions); + } +} + /* Print definitions for methods "methods" of name "fullname" in class "clazz" * to "os". * @@ -1000,6 +1194,9 @@ std::string cpp_generator::rename_method(std::string name) */ string cpp_generator::type2cpp(const isl_class &clazz) { + if (is_list_type(clazz)) + return "list<" + type2cpp(list_types[clazz.name]) + ">"; + return type2cpp(clazz.name); } @@ -1014,6 +1211,10 @@ string cpp_generator::type2cpp(string type_str) */ string cpp_generator::type2cpp(QualType type) { + if (is_list_type(type)) + return "isl::list"; + if (is_isl_type(type)) return "isl::" + type2cpp(type->getPointeeType().getAsString()); @@ -1023,7 +1224,8 @@ string cpp_generator::type2cpp(QualType type) if (is_isl_stat(type)) return "isl::stat"; - if (type->isIntegerType()) + if (type->isIntegerType() || type->isVoidType() || + type->isVoidPointerType()) return type.getAsString(); if (is_string(type)) @@ -1101,3 +1303,31 @@ cpp_generator::function_kind cpp_generator::get_method_kind( else return function_kind_member_method; } + +bool cpp_generator::is_list_type(QualType type) +{ + if (!type->isPointerType()) + return false; + return list_types.count(type->getPointeeType().getAsString()) != 0; +} + +bool cpp_generator::is_list_type(const isl_class &clazz) +{ + return list_types.count(clazz.name) != 0; +} + +string cpp_generator::list_element_type_name(QualType type) +{ + return list_types.at(type->getPointeeType().getAsString()); +} + +string cpp_generator::list_element_type_name(const isl_class &clazz) +{ + return list_types.at(clazz.name); +} + +string cpp_generator::instance_type(const string &type_string) +{ + size_t pos = type_string.find('<'); + return type_string.substr(0, pos); +} diff --git a/interface/cpp.h b/interface/cpp.h index 1978e261..a6e94837 100644 --- a/interface/cpp.h +++ b/interface/cpp.h @@ -4,11 +4,13 @@ using namespace std; using namespace clang; class cpp_generator : public generator { +protected: + map list_types; + public: cpp_generator(set &exported_types, set exported_functions, - set functions) : - generator(exported_types, exported_functions, functions) {} + set functions); enum function_kind { function_kind_static_method, @@ -21,7 +23,10 @@ class cpp_generator : public generator { void print_file(ostream &os, std::string filename); void print_forward_declarations(ostream &os); void print_declarations(ostream &os); + void print_common_class_body(ostream &os, const isl_class &clazz, + bool is_template_specialization = false); void print_class(ostream &os, const isl_class &clazz); + void print_list_specialization(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()); @@ -34,6 +39,7 @@ class cpp_generator : public generator { void print_destructor_decl(ostream &os, const isl_class &clazz); void print_ptr_decl(ostream &os, const isl_class &clazz); void print_methods_decl(ostream &os, const isl_class &clazz); + void print_custom_public_decl(ostream &os, const isl_class &clazz); void print_method_group_decl(ostream &os, const isl_class &clazz, const string &fullname, const set &methods); void print_method_decl(ostream &os, const isl_class &clazz, @@ -51,6 +57,7 @@ class cpp_generator : public generator { void print_destructor_impl(ostream &os, const isl_class &clazz); void print_ptr_impl(ostream &os, const isl_class &clazz); void print_methods_impl(ostream &os, const isl_class &clazz); + void print_custom_methods_impl(ostream &os, const isl_class &clazz); void print_method_group_impl(ostream &os, const isl_class &clazz, const string &fullname, const set &methods); void print_method_impl(ostream &os, const isl_class &clazz, @@ -72,4 +79,9 @@ class cpp_generator : public generator { bool is_subclass(QualType subclass_type, const isl_class &class_type); function_kind get_method_kind(const isl_class &clazz, FunctionDecl *method); + bool is_list_type(QualType type); + bool is_list_type(const isl_class &clazz); + string list_element_type_name(QualType type); + string list_element_type_name(const isl_class &clazz); + string instance_type(const string &type_string); }; diff --git a/interface/extract_interface.cc b/interface/extract_interface.cc index 1275b345..171b2f34 100644 --- a/interface/extract_interface.cc +++ b/interface/extract_interface.cc @@ -428,6 +428,7 @@ int main(int argc, char *argv[]) "__attribute__((annotate(\"isl_export\")))"); PO.addMacroDef("__isl_constructor=__attribute__((annotate(\"isl_constructor\"))) __attribute__((annotate(\"isl_export\")))"); PO.addMacroDef("__isl_subclass(super)=__attribute__((annotate(\"isl_subclass(\" #super \")\"))) __attribute__((annotate(\"isl_export\")))"); + PO.addMacroDef("__isl_list(elem)=__attribute__((annotate(\"isl_list(\" #elem \")\"))) __attribute__((annotate(\"isl_export\")))"); create_preprocessor(Clang); Preprocessor &PP = Clang->getPreprocessor(); diff --git a/interface/generator.cc b/interface/generator.cc index 15bc34df..bcb57c61 100644 --- a/interface/generator.cc +++ b/interface/generator.cc @@ -129,35 +129,56 @@ void generator::die(string msg) die(msg.c_str()); } -/* Return a sequence of the types of which the given type declaration is - * marked as being a subtype. - * The order of the types is the opposite of the order in which they - * appear in the source. In particular, the first annotation - * is the one that is closest to the annotated type and the corresponding - * type is then also the first that will appear in the sequence of types. +/* Find all "decl" annotations with prefix "annotation" and return their + * arguments in a vector. More specifically, find all annotations of the form + * 'annotate("annotation(something)")' and return a vector that contains + * 'something'. */ -std::vector generator::find_superclasses(RecordDecl *decl) +vector generator::extract_annotation_arguments(RecordDecl *decl, + const string &annotation) const { - vector super; + vector arguments; if (!decl->hasAttrs()) - return super; + return arguments; - string sub = "isl_subclass"; - size_t len = sub.length(); + size_t len = annotation.length(); AttrVec attrs = decl->getAttrs(); for (AttrVec::const_iterator i = attrs.begin(); i != attrs.end(); ++i) { const AnnotateAttr *ann = dyn_cast(*i); if (!ann) continue; string s = ann->getAnnotation().str(); - if (s.substr(0, len) == sub) { + if (s.substr(0, len) == annotation) { s = s.substr(len + 1, s.length() - len - 2); - super.push_back(s); + arguments.push_back(s); } } - return super; + return arguments; +} + +/* Return a sequence of the types of which the given type declaration is + * marked as being a subtype. + * The order of the types is the opposite of the order in which they + * appear in the source. In particular, the first annotation + * is the one that is closest to the annotated type and the corresponding + * type is then also the first that will appear in the sequence of types. + */ +std::vector generator::find_superclasses(RecordDecl *decl) +{ + return extract_annotation_arguments(decl, "isl_subclass"); +} + +/* Return a type name that the given declaration is marked as being a list of. + * If the declaration is not marked as a list, return an empty vector. + */ +vector generator::get_list_element_type_name(RecordDecl *decl) +{ + vector elems = extract_annotation_arguments(decl, "isl_list"); + if (elems.size() > 1) + die("multiple element types provided for a list"); + return elems; } /* Is decl marked as being part of an overloaded method? diff --git a/interface/generator.h b/interface/generator.h index b235add6..91bdf3eb 100644 --- a/interface/generator.h +++ b/interface/generator.h @@ -50,6 +50,7 @@ class generator { void die(const char *msg) __attribute__((noreturn)); void die(string msg) __attribute__((noreturn)); vector find_superclasses(RecordDecl *decl); + vector get_list_element_type_name(RecordDecl *decl); bool is_overload(Decl *decl); bool is_constructor(Decl *decl); bool takes(Decl *decl); @@ -67,6 +68,10 @@ class generator { bool is_static(const isl_class &clazz, FunctionDecl *method); string extract_type(QualType type); FunctionDecl *find_by_name(const string &name, bool required); + +private: + vector extract_annotation_arguments(RecordDecl *decl, + const string &annotation) const; }; #endif /* ISL_INTERFACE_GENERATOR_H */ diff --git a/interface/isl.h.top b/interface/isl.h.top index 37749c29..fb4e614e 100644 --- a/interface/isl.h.top +++ b/interface/isl.h.top @@ -91,5 +91,103 @@ enum class stat { error = isl_stat_error }; +template +class list; + +template +class list_iterator { + const list *lst; + int pos; + mutable T elementHolder; + + inline list_iterator(const list *l, int p); + + friend list_iterator list::begin() const; + friend list_iterator list::end() const; + +public: + typedef T value_type; + typedef int difference_type; + typedef std::input_iterator_tag iterator_category; + typedef const T *pointer; + typedef T reference; + + inline list_iterator(); + inline list_iterator(const list_iterator &it); + inline ~list_iterator(); + inline list_iterator &operator=(const list_iterator &it); + + inline reference operator*() const; + inline pointer operator->() const; + inline list_iterator operator++(int); + inline list_iterator &operator++(); + inline bool operator==(const list_iterator &it) const; + inline bool operator!=(const list_iterator &it) const; + + static inline void swap(list_iterator &it1, list_iterator &it2); +}; + +template +list_iterator::list_iterator(const list *l, int p) : + lst(l), pos(p) {} + +template +list_iterator::list_iterator() : + lst(nullptr), pos(-1) {} + +template +list_iterator::list_iterator(const list_iterator &it) : + lst(it.lst), pos(it.pos) {} + +template +list_iterator &list_iterator::operator=(const list_iterator &it) { + lst = it.lst; + pos = it.pos; + return *this; +} + +template +list_iterator::~list_iterator() {} + +template +typename list_iterator::reference list_iterator::operator*() const { + return lst->at(pos); +} + +template +typename list_iterator::pointer list_iterator::operator->() const { + elementHolder = lst->at(pos); + return &elementHolder; +} + +template +list_iterator list_iterator::operator++(int) { + list_iterator it = *this; + ++*this; + return it; +} + +template +list_iterator &list_iterator::operator++() { + if (pos == -1 || !lst || pos >= lst->size() - 1) + pos = -1; + else + ++pos; + + return *this; +} + +template +bool list_iterator::operator==(const list_iterator &it) const { + ISLPP_ASSERT(lst == it.lst, + "cannot compare iterators from different containers"); + return pos == it.pos; +} + +template +bool list_iterator::operator!=(const list_iterator &it) const { + return !(*this == it); +} + } } // namespace isl diff --git a/interface/isl_test_cpp.cpp b/interface/isl_test_cpp.cpp index a6b1e631..bea117f7 100644 --- a/interface/isl_test_cpp.cpp +++ b/interface/isl_test_cpp.cpp @@ -314,6 +314,187 @@ void test_foreach(isl::ctx ctx) assert(ret2 == isl::stat::error); } +/* Test that ids are handled correctly and remain unique. + * + * Verify that id names are stored and returned correctly. Check that ids with + * identical names are equal and those with different names are different. + * Check that ids with identical names and different user pointers are + * different. Verify that equality holds across ids constructed from C and C++ + * interfaces. + */ +void test_id(isl::ctx ctx) +{ + isl::id id_whatever(ctx, std::string("whatever")); + assert(id_whatever.has_name()); + assert(std::string("whatever") == id_whatever.get_name()); + + isl::id id_other(ctx, std::string("whatever")); + assert(id_whatever == id_other); + + int fourtytwo = 42; + isl::id id_whatever_42(ctx, std::string("whatever"), &fourtytwo); + assert(id_whatever != id_whatever_42); + + isl::id id_whatever_42_copy(id_whatever_42); + assert(id_whatever_42 == id_whatever_42_copy); + + isl::id id_whatever_42_other(ctx, std::string("whatever"), &fourtytwo); + assert(id_whatever_42 == id_whatever_42_other); + + isl_id *cid = isl_id_alloc(ctx.get(), "whatever", &fourtytwo); + assert(cid == id_whatever_42.get()); + isl_id_free(cid); +} + +static void reset_flag(void *user) { + *static_cast(user) = 0; +} + +/* Test that user pointers of the ids are not freed as long as the exists at + * least one id pointing to them, either in C or C++. + * + * In a scope, create an id with a flag as a user object and a user_free that + * resets the flag. Use the id in a set object that lives outside the given + * scope. Check that flag is still set after the id object went out of the + * scope. Check that flag is reset after the set object went of of scope. + */ +void test_id_lifetime(isl::ctx ctx) +{ + int *flag = new int(1); + + { + isl::set set(ctx, "{:}"); + { + isl::id id(ctx, std::string("whatever"), flag, + &reset_flag); + set = set.set_tuple_id(id); + } + assert(1 == *flag); + assert(set.has_tuple_id()); + + isl::id same_id(ctx, std::string("whatever"), flag); + assert(set.get_tuple_id() == same_id); + } + assert(0 == *flag); + delete flag; +} + +/* Test that read-only list of vals are modeled correctly. + * + * Construct an std::vector of isl::vals and use its iterators to construct a + * C++ isl list of vals. Compare these containers. Extract the C isl list from + * the C++ one, verify that is has expected size and content. Modify the C isl + * list and convert it back to C++. Verify that the new managed list has + * expected content. + */ +void test_val_list(isl::ctx ctx) +{ + std::vector val_vector; + for (int i = 0; i < 42; ++i) { + isl::val val(ctx, i); + val_vector.push_back(val); + } + isl::list val_list(ctx, val_vector.begin(), + val_vector.end()); + + assert(42 == val_list.size()); + for (int i = 0; i < 42; ++i) { + isl::val val_at = val_list.at(i); + isl::val val_op = val_list[i]; + isl::val expected(ctx, i); + assert(val_at.eq(expected)); + assert(val_op.eq(expected)); + } + + isl_val_list *c_val_list = val_list.release(); + assert(42 == isl_val_list_n_val(c_val_list)); + for (int i = 0; i < 42; ++i) { + isl_val *val = isl_val_list_get_val(c_val_list, i); + assert(i == isl_val_get_num_si(val)); + isl_val_free(val); + } + + c_val_list = isl_val_list_drop(c_val_list, 0, 32); + val_list = isl::manage(c_val_list); + assert(10 == val_list.size()); + for (int i = 0; i < 10; ++i) { + isl::val expected(ctx, 32 + i); + isl::val val_op = val_list[i]; + assert(val_op.eq(expected)); + } +} + +/* Test that supplementary functions on lists are handled properly. + * + * Construct a list of basic_maps from an array thereof. Compute the + * interaction of all basic_map in the list. + */ +void test_basic_map_list(isl::ctx ctx) +{ + isl::basic_map bmap1(ctx, "{[]->[a]: 0 <= a <= 42}"); + isl::basic_map bmap2(ctx, "{[]->[a]: 21 <= a <= 63}"); + isl::basic_map bmap3(ctx, "{[]->[a]: 21 <= a <= 42}"); + + isl::basic_map bmap_array[] = { bmap1, bmap2, bmap3 }; + isl::list bmap_list(ctx, bmap_array, bmap_array + 3); + isl::basic_map result = bmap_list.intersect(); + assert(result.is_equal(bmap3)); +} + +/* Test if the list iterators are operating properly and whether they are + * compatible with the standard library. + * + * Construct a standard vector from an isl list using list iterators. Check + * that the size and content of the vector is equal to the size and content of + * the list. + * + * Check that prefix and postfix increments of the iterators are implemented + * correctly. + */ +void test_list_iterators(isl::ctx ctx) +{ + std::vector val_vector; + for (int i = 0; i < 42; ++i) { + isl::val val(ctx, i); + val_vector.push_back(val); + } + isl::list val_list(ctx, val_vector.begin(), + val_vector.end()); + + std::vector other_val_vector; + other_val_vector.resize(42); + std::copy(val_list.begin(), val_list.end(), other_val_vector.begin()); + + assert(42 == other_val_vector.size()); + for (int i = 0; i < 42; ++i) { + isl::val expected(ctx, i); + assert(expected.eq(other_val_vector[i])); + } + + isl::list::iterator it = val_list.begin(); + for (int i = 0; i < 42; ++i) { + isl::val expected(ctx, i); + assert(it != val_list.end()); + assert(it->eq(expected)); + assert((*it).eq(expected)); + ++it; + } + + it = val_list.begin(); + isl::list::iterator it2 = val_list.begin(); + ++it2; + assert(it++ != it2); + assert(it++ == it2); + assert(it != it2); + + it = val_list.begin(); + it2 = val_list.begin(); + ++it2; + assert(++it == it2); + assert(++it == ++it2); + assert(++it != it2); +} + /* Test the isl C++ interface * * This includes: @@ -322,6 +503,11 @@ void test_foreach(isl::ctx ctx) * - Different parameter types * - Different return types * - Foreach functions + * - isl::id uniqueness + * - isl::id lifetime + * - List of isl::val + * - Custom function of the list of isl::basic_map + * - List iterators */ int main() { @@ -332,6 +518,11 @@ int main() test_parameters(ctx); test_return(ctx); test_foreach(ctx); + test_id(ctx); + test_id_lifetime(ctx); + test_val_list(ctx); + test_basic_map_list(ctx); + test_list_iterators(ctx); isl_ctx_free(ctx); }