diff --git a/libsrc/core/CMakeLists.txt b/libsrc/core/CMakeLists.txt index 8b14b211..332740bb 100644 --- a/libsrc/core/CMakeLists.txt +++ b/libsrc/core/CMakeLists.txt @@ -5,6 +5,6 @@ set_target_properties(ngcore PROPERTIES POSITION_INDEPENDENT_CODE ON ) install(TARGETS ngcore DESTINATION ${NG_INSTALL_DIR} COMPONENT netgen) -install(FILES ngcore.hpp archive.hpp basearchive.hpp +install(FILES ngcore.hpp archive.hpp basearchive.hpp version.hpp DESTINATION ${NG_INSTALL_DIR_INCLUDE}/core COMPONENT netgen_devel ) diff --git a/libsrc/core/archive.hpp b/libsrc/core/archive.hpp index 7b213b8d..7da24f98 100644 --- a/libsrc/core/archive.hpp +++ b/libsrc/core/archive.hpp @@ -6,16 +6,22 @@ namespace ngcore // BinaryOutArchive ====================================================================== class BinaryOutArchive : public Archive { - std::shared_ptr fout; size_t ptr = 0; enum { BUFFERSIZE = 1024 }; char buffer[BUFFERSIZE]; + std::shared_ptr fout; public: - BinaryOutArchive (std::shared_ptr afout) : Archive(true), fout(afout) { ; } - BinaryOutArchive (std::string filename) + BinaryOutArchive(std::shared_ptr afout) : Archive(true), fout(afout) + { + (*this) & GetLibraryVersions(); + } + BinaryOutArchive(std::string filename) : BinaryOutArchive(std::make_shared(filename)) {} virtual ~BinaryOutArchive () { FlushBuffer(); } + const VersionInfo& getVersion(const std::string& library) + { return GetLibraryVersions()[library]; } + using Archive::operator&; virtual Archive & operator & (double & d) { return Write(d); } @@ -76,11 +82,18 @@ namespace ngcore // BinaryInArchive ====================================================================== class BinaryInArchive : public Archive { + std::map vinfo; std::shared_ptr fin; public: - BinaryInArchive (std::shared_ptr afin) : Archive(false), fin(afin) { ; } + BinaryInArchive (std::shared_ptr afin) : Archive(false), fin(afin) + { + (*this) & vinfo; + } BinaryInArchive (std::string filename) - : BinaryInArchive(std::make_shared(filename)) {} + : BinaryInArchive(std::make_shared(filename)) { ; } + + const VersionInfo& getVersion(const std::string& library) + { return vinfo[library]; } using Archive::operator&; virtual Archive & operator & (double & d) @@ -133,10 +146,16 @@ namespace ngcore { std::shared_ptr fout; public: - TextOutArchive (std::shared_ptr afout) : Archive(true), fout(afout) { } + TextOutArchive (std::shared_ptr afout) : Archive(true), fout(afout) + { + (*this) & GetLibraryVersions(); + } TextOutArchive (std::string filename) : TextOutArchive(std::make_shared(filename.c_str())) { } + const VersionInfo& getVersion(const std::string& library) + { return GetLibraryVersions()[library]; } + using Archive::operator&; virtual Archive & operator & (double & d) { *fout << d << '\n'; return *this; } @@ -156,16 +175,22 @@ namespace ngcore { int len = str.length(); *fout << len << '\n'; - fout->write(&str[0], len); - *fout << '\n'; + if(len) + { + fout->write(&str[0], len); + *fout << '\n'; + } return *this; } virtual Archive & operator & (char *& str) { int len = strlen (str); *fout << len << '\n'; - fout->write (&str[0], len); - *fout << '\n'; + if(len) + { + fout->write (&str[0], len); + *fout << '\n'; + } return *this; } }; @@ -173,12 +198,19 @@ namespace ngcore // TextInArchive ====================================================================== class TextInArchive : public Archive { + std::map vinfo; std::shared_ptr fin; public: - TextInArchive (std::shared_ptr afin) : Archive(false), fin(afin) { ; } + TextInArchive (std::shared_ptr afin) : Archive(false), fin(afin) + { + (*this) & vinfo; + } TextInArchive (std::string filename) : TextInArchive(std::make_shared(filename)) {} + const VersionInfo& getVersion(const std::string& library) + { return vinfo[library]; } + using Archive::operator&; virtual Archive & operator & (double & d) { *fin >> d; return *this; } @@ -201,7 +233,8 @@ namespace ngcore char ch; fin->get(ch); // '\n' str.resize(len); - fin->get(&str[0], len+1, '\0'); + if(len) + fin->get(&str[0], len+1, '\0'); return *this; } virtual Archive & operator & (char *& str) @@ -211,7 +244,8 @@ namespace ngcore char ch; fin->get(ch); // '\n' str = new char[len+1]; - fin->get(&str[0], len, '\0'); + if(len) + fin->get(&str[0], len, '\0'); str[len] = 0; return *this; } diff --git a/libsrc/core/basearchive.cpp b/libsrc/core/basearchive.cpp index 1fb0d713..975006fc 100644 --- a/libsrc/core/basearchive.cpp +++ b/libsrc/core/basearchive.cpp @@ -7,6 +7,11 @@ namespace ngcore { + std::map& GetLibraryVersions() + { + static std::map library_versions; + return library_versions; + } #ifdef WIN // windows does demangling in typeid(T).name() std::string demangle(const char* typeinfo) { return typeinfo; } diff --git a/libsrc/core/basearchive.hpp b/libsrc/core/basearchive.hpp index 26ca217e..9fdf95e0 100644 --- a/libsrc/core/basearchive.hpp +++ b/libsrc/core/basearchive.hpp @@ -3,6 +3,10 @@ namespace ngcore { + class VersionInfo; + // Libraries using this archive can store their version here to implement backwards compatibility + std::map& GetLibraryVersions(); + class Archive; std::string demangle(const char* typeinfo); @@ -75,6 +79,7 @@ namespace ngcore bool Output () { return is_output; } bool Input () { return !is_output; } + virtual const VersionInfo& getVersion(const std::string& library) = 0; // Pure virtual functions that have to be implemented by In-/OutArchive virtual Archive & operator & (double & d) = 0; @@ -116,6 +121,29 @@ namespace ngcore Do(&v[0], size); return (*this); } + template + Archive& operator& (std::map& map) + { + if(is_output) + { + (*this) << size_t(map.size()); + for(auto& pair : map) + (*this) << pair.first << pair.second; + } + else + { + size_t size; + (*this) & size; + T1 key; T2 val; + for(size_t i = 0; i < size; i++) + { + T1 key; T2 val; + (*this) & key & val; + map[key] = val; + } + } + return (*this); + } // Archive arrays ===================================================== // this functions can be overloaded in Archive implementations for more efficiency template diff --git a/libsrc/core/ngcore.hpp b/libsrc/core/ngcore.hpp index e93a506c..0a37c977 100644 --- a/libsrc/core/ngcore.hpp +++ b/libsrc/core/ngcore.hpp @@ -6,6 +6,7 @@ #include #include #include +#include #include #include #include @@ -15,6 +16,8 @@ #include +namespace ngcore +{ #if defined(__GNUC__) inline bool likely (bool x) { return __builtin_expect((x), true); } inline bool unlikely (bool x) { return __builtin_expect((x), false); } @@ -22,9 +25,11 @@ inline bool likely (bool x) { return x; } inline bool unlikely (bool x) { return x; } #endif +} // own includes #include "basearchive.hpp" +#include "version.hpp" #include "archive.hpp" #endif // NG_CORE_HPP diff --git a/libsrc/core/version.hpp b/libsrc/core/version.hpp new file mode 100644 index 00000000..bf11b3e9 --- /dev/null +++ b/libsrc/core/version.hpp @@ -0,0 +1,84 @@ + +namespace ngcore +{ + class VersionInfo + { + private: + size_t mayor, minor, date, commit_offset; + std::string git_hash; + public: + VersionInfo() : mayor(0), minor(0), date(0), commit_offset(0), git_hash("") {} + VersionInfo(std::string vstring) + { + minor = date = commit_offset = 0; + git_hash = ""; + if(vstring.substr(0,1) == "v") + vstring = vstring.substr(1,vstring.size()-1); + auto dot = vstring.find("."); + mayor = std::stoi(vstring.substr(0,dot)); + if(dot == size_t(-1)) vstring = ""; + else vstring = vstring.substr(dot+1, vstring.size()-dot-1); + if(vstring.size()) + { + dot = vstring.find("."); + minor = std::stoi(vstring.substr(0,dot)); + if (dot == size_t(-1)) vstring = ""; + else vstring = vstring.substr(dot+1, vstring.size()-dot-1); + if(vstring.size()) + { + dot = vstring.find("-"); + date = std::stoi(vstring.substr(0,dot)); + if(dot == size_t(-1)) vstring = ""; + else vstring = vstring.substr(dot+1,vstring.size()-dot-1); + if(vstring.size()) + { + dot = vstring.find("-"); + commit_offset = std::stoi(vstring.substr(0,dot)); + if(dot == size_t(-1)) vstring = ""; + else vstring = vstring.substr(dot+1, vstring.size()-dot-1); + if(vstring.size()) + git_hash = vstring; + } + } + } + } + VersionInfo(const char* cstr) : VersionInfo(std::string(cstr)) { } + + std::string to_string() const + { std::string vstring = "v" + std::to_string(mayor); + if(minor || date || commit_offset || git_hash.size()) + { + vstring += "." + std::to_string(minor); + if(date || commit_offset || git_hash.size()) + { + vstring += "." + std::to_string(date); + if(commit_offset || git_hash.size()) + { + vstring += "-" + std::to_string(commit_offset); + if(git_hash.size()) + vstring += "-" + git_hash; + } + } + } + return vstring; + } + bool operator <(const VersionInfo& other) const + { + return std::tie(mayor, minor, date, commit_offset) < + std::tie(other.mayor, other.minor, other.date, other.commit_offset); + } + bool operator ==(const VersionInfo& other) const + { + return mayor == other.mayor && minor == other.minor && date == other.date + && commit_offset == other.commit_offset; + } + bool operator >(const VersionInfo& other) const { return other < (*this); } + bool operator <=(const VersionInfo& other) const { return !((*this) > other); } + bool operator >=(const VersionInfo& other) const { return !((*this) < other); } + + void DoArchive(Archive& ar) + { + ar & mayor & minor & date & commit_offset & git_hash; + } + }; +} diff --git a/libsrc/csg/python_csg.cpp b/libsrc/csg/python_csg.cpp index 05ac4acc..e9895738 100644 --- a/libsrc/csg/python_csg.cpp +++ b/libsrc/csg/python_csg.cpp @@ -371,19 +371,17 @@ However, when r = 0, the top part becomes a point(tip) and meshing fails! .def(py::pickle( [](CSGeometry& self) { - stringstream ss; - self.Save(ss); - cout << "pickle = " << endl << ss.str() << endl; - return py::make_tuple(ss.str()); + auto ss = make_shared(); + BinaryOutArchive archive(ss); + archive & self; + return py::make_tuple(ss->str()); }, [](py::tuple state) { auto geo = make_shared(); - auto val = py::cast(state[0]); - cout << "unpickle = " << endl << val << endl; - stringstream ss(py::cast(state[0])); - // geo->Load(ss); - // geo->FindIdenticSurfaces(1e-8 * geo->MaxSize()); + auto ss = make_shared (py::cast(state[0])); + BinaryInArchive archive(ss); + archive & (*geo); return geo; })) .def("Save", FunctionPointer([] (CSGeometry & self, string filename) diff --git a/tests/catch/CMakeLists.txt b/tests/catch/CMakeLists.txt index d980d7f8..53cacdda 100644 --- a/tests/catch/CMakeLists.txt +++ b/tests/catch/CMakeLists.txt @@ -27,4 +27,5 @@ macro(add_unit_test name sources) endmacro() add_unit_test(archive archive.cpp) +add_unit_test(version version.cpp) endif(ENABLE_UNIT_TESTS) diff --git a/tests/catch/archive.cpp b/tests/catch/archive.cpp index 40ee202b..f6fb4bc8 100644 --- a/tests/catch/archive.cpp +++ b/tests/catch/archive.cpp @@ -203,8 +203,24 @@ void testMultipleInheritance(Archive& in, Archive& out) } } +void testLibraryVersion(Archive& in, Archive& out) +{ + GetLibraryVersions()["netgen"] = "v6.2.1812"; + CHECK(in.getVersion("netgen") == "v6.2.1811"); + CHECK(out.getVersion("netgen") == "v6.2.1812"); +} + void testArchive(Archive& in, Archive& out) { + SECTION("Empty String") + { + out << string("") << 1; + out.FlushBuffer(); + string str; int i; + in & str & i; + CHECK(str == ""); + CHECK(i == 1); + } SECTION("SharedPtr") { testSharedPointer(in, out); @@ -226,10 +242,15 @@ void testArchive(Archive& in, Archive& out) { testNullPtr(in, out); } + SECTION("Library Version") + { + testLibraryVersion(in,out); + } } TEST_CASE("BinaryArchive") { + GetLibraryVersions()["netgen"] = "v6.2.1811"; auto stream = make_shared(); BinaryOutArchive out(stream); BinaryInArchive in(stream); @@ -238,6 +259,7 @@ TEST_CASE("BinaryArchive") TEST_CASE("TextArchive") { + GetLibraryVersions()["netgen"] = "v6.2.1811"; auto stream = make_shared(); TextOutArchive out(stream); TextInArchive in(stream); diff --git a/tests/catch/version.cpp b/tests/catch/version.cpp new file mode 100644 index 00000000..5655ab23 --- /dev/null +++ b/tests/catch/version.cpp @@ -0,0 +1,19 @@ + +#include "catch.hpp" +#include <../core/ngcore.hpp> +using namespace ngcore; +using namespace std; + + +TEST_CASE("Version") +{ + VersionInfo v("v6.2.1811-3-asdf"); + CHECK(v.to_string() == "v6.2.1811-3-asdf"); + VersionInfo v2("6.2"); + CHECK(v2.to_string() == "v6.2"); + CHECK(v < "v7"); + CHECK(v >= "6.2"); + CHECK(v > "6.2.1811"); + CHECK(v < "6.2.1811-5"); + CHECK(v == "v6.2.1811-3"); +}