diff --git a/cmake/SerialboxConfig.cmake.in b/cmake/SerialboxConfig.cmake.in index 4310bc35..9c10cfce 100644 --- a/cmake/SerialboxConfig.cmake.in +++ b/cmake/SerialboxConfig.cmake.in @@ -91,10 +91,11 @@ endif(SERIALBOX_HAS_FORTRAN) #====--------------------------------------------------------------------------------------------=== if(SERIALBOX_ROOT AND NOT(DEFINED SERIALBOX_NO_EXTERNAL_LIBS)) + include(CMakeFindDependencyMacro) # # Pthreads # - find_package(Threads REQUIRED QUIET) + find_dependency(Threads) # # Boost (Serialbox always uses the shared Boost libraries) diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt index c370b789..b4864800 100644 --- a/examples/CMakeLists.txt +++ b/examples/CMakeLists.txt @@ -1,61 +1,59 @@ -##===------------------------------------------------------------------------------*- CMake -*-===## -## -## S E R I A L B O X -## -## This file is distributed under terms of BSD license. -## See LICENSE.txt for more information. -## -##===------------------------------------------------------------------------------------------===## - -cmake_minimum_required(VERSION 3.12) - -## serialbox_add_gridtools_example -## ------------------------------- -## -## Create and install a gridtools example -## -## NAME:STRING=<> - Name of target and executable -## ARGN:STRINGS=<> - List of source files -## -function(serialbox_add_gridtools_example NAME) - add_executable(${NAME} ${ARGN}) - target_link_libraries(${NAME} - SerialboxStatic - GridTools_TARGET - ${CMAKE_THREAD_LIBS_INIT}) - target_compile_definitions(${NAME} PUBLIC BOOST_NO_CXX11_DECLTYPE) - install(TARGETS ${NAME} DESTINATION bin) - - if(SERIALBOX_TESTING) - serialbox_add_test(TARGET ${NAME} EXECUTABLE ${CMAKE_CURRENT_BINARY_DIR}/${NAME}) - endif(SERIALBOX_TESTING) -endfunction(serialbox_add_gridtools_example) - -## serialbox_add_python_example -## ---------------------------- -## -## Install a python example -## -## ARGN:STRINGS=<> - List of source files -## -function(serialbox_add_python_example NAME) - install(FILES ${NAME} ${ARGN} DESTINATION bin) -endfunction(serialbox_add_python_example) - -## Build examples -if(SERIALBOX_ENABLE_C) - add_subdirectory(c) -endif() - -if(SERIALBOX_ENABLE_FORTRAN) - add_subdirectory(fortran) -endif() - -if(SERIALBOX_ENABLE_PYTHON) - add_subdirectory(python) -endif() - -if(SERIALBOX_TESTING_GRIDTOOLS) - add_subdirectory(gridtools) -endif() - +##===------------------------------------------------------------------------------*- CMake -*-===## +## +## S E R I A L B O X +## +## This file is distributed under terms of BSD license. +## See LICENSE.txt for more information. +## +##===------------------------------------------------------------------------------------------===## + +cmake_minimum_required(VERSION 3.12) + +## serialbox_add_gridtools_example +## ------------------------------- +## +## Create and install a gridtools example +## +## NAME:STRING=<> - Name of target and executable +## ARGN:STRINGS=<> - List of source files +## +function(serialbox_add_gridtools_example NAME) + add_executable(${NAME} ${ARGN}) + target_link_libraries(${NAME} + SerialboxStatic + GridTools_TARGET + ${CMAKE_THREAD_LIBS_INIT}) + target_compile_definitions(${NAME} PUBLIC BOOST_NO_CXX11_DECLTYPE) + install(TARGETS ${NAME} DESTINATION bin) + if(SERIALBOX_TESTING) + serialbox_add_test(TARGET ${NAME} EXECUTABLE ${CMAKE_CURRENT_BINARY_DIR}/${NAME}) + endif(SERIALBOX_TESTING) +endfunction(serialbox_add_gridtools_example) + +## serialbox_add_python_example +## ---------------------------- +## +## Install a python example +## +## ARGN:STRINGS=<> - List of source files +## +function(serialbox_add_python_example NAME) + install(FILES ${NAME} ${ARGN} DESTINATION bin) +endfunction(serialbox_add_python_example) + +## Build examples +if(SERIALBOX_ENABLE_C) + add_subdirectory(c) +endif() + +if(SERIALBOX_ENABLE_FORTRAN) + add_subdirectory(fortran) +endif() + +if(SERIALBOX_ENABLE_PYTHON) + add_subdirectory(python) +endif() + +if(SERIALBOX_TESTING_GRIDTOOLS) + add_subdirectory(gridtools) +endif() diff --git a/src/serialbox/core/external/json/json.hpp b/src/external/json/json.hpp similarity index 100% rename from src/serialbox/core/external/json/json.hpp rename to src/external/json/json.hpp diff --git a/src/serialbox/core/CMakeLists.txt b/src/serialbox/core/CMakeLists.txt index c6a8535a..20e3ff6e 100644 --- a/src/serialbox/core/CMakeLists.txt +++ b/src/serialbox/core/CMakeLists.txt @@ -1,108 +1,120 @@ -##===------------------------------------------------------------------------------*- CMake -*-===## -## -## S E R I A L B O X -## -## This file is distributed under terms of BSD license. -## See LICENSE.txt for more information. -## -##===------------------------------------------------------------------------------------------===## - -cmake_minimum_required(VERSION 3.12) - -set(SOURCES - FieldMap.cpp - FieldMap.h - FieldMetainfoImpl.cpp - FieldMetainfoImpl.h - FieldID.cpp - FieldID.h - Logging.cpp - Logging.h - MetainfoMapImpl.cpp - MetainfoMapImpl.h - MetainfoValueImpl.cpp - MetainfoValueImpl.h - SavepointImpl.cpp - SavepointImpl.h - SavepointVector.cpp - SavepointVector.h - SerializerImpl.cpp - SerializerImpl.h - StorageView.cpp - StorageView.h - Type.cpp - Type.h - Unreachable.cpp - Unreachable.h - - hash/HashFactory.cpp - hash/HashFactory.h - hash/SHA256.cpp - hash/SHA256.h - hash/MD5.cpp - hash/MD5.h - - archive/ArchiveFactory.cpp - archive/ArchiveFactory.h - archive/BinaryArchive.cpp - archive/BinaryArchive.h - archive/NetCDFArchive.cpp - archive/NetCDFArchive.h - archive/MockArchive.cpp - archive/MockArchive.h - - frontend/stella/MetainfoSet.cpp - frontend/stella/MetainfoSet.h - frontend/stella/Savepoint.cpp - frontend/stella/Savepoint.h - frontend/stella/Serializer.cpp - frontend/stella/Serializer.h - frontend/stella/DataFieldInfo.cpp - frontend/stella/DataFieldInfo.h -) - -add_library(SerialboxObjects OBJECT ${SOURCES}) -target_include_directories(SerialboxObjects - PUBLIC - $ - $ - ) -target_link_libraries(SerialboxObjects PUBLIC Boost::boost) -target_link_libraries(SerialboxObjects PUBLIC SerialboxFilesytemTarget) -target_link_libraries(SerialboxObjects PUBLIC ${CMAKE_THREAD_LIBS_INIT}) # TODO target based - -add_library(SerialboxStatic STATIC $) -set_target_properties(SerialboxStatic PROPERTIES VERSION ${Serialbox_VERSION_STRING}) -target_link_libraries(SerialboxStatic PUBLIC SerialboxObjects) -if(BUILD_SHARED_LIBS) - add_library(SerialboxShared $) - set_target_properties(SerialboxShared PROPERTIES VERSION ${Serialbox_VERSION_STRING}) - target_link_libraries(SerialboxShared PUBLIC SerialboxObjects) -endif() - -if(SERIALBOX_USE_NETCDF) - target_link_libraries(SerialboxStatic PRIVATE NETCDF_TARGET) - if(BUILD_SHARED_LIBS) - target_link_libraries(SerialboxShared PUBLIC NETCDF_TARGET) - endif() - #TODO try to make private once we protect our headers - target_include_directories(SerialboxObjects PUBLIC SYSTEM ${NETCDF_INCLUDES}) -endif() - -if(BUILD_SHARED_LIBS) - set_property(TARGET SerialboxObjects PROPERTY POSITION_INDEPENDENT_CODE 1) -endif() - -install(TARGETS SerialboxStatic SerialboxObjects - EXPORT SerialboxTargets - LIBRARY DESTINATION lib - ARCHIVE DESTINATION lib - ) - -if(BUILD_SHARED_LIBS) - install(TARGETS SerialboxShared - EXPORT SerialboxTargets - LIBRARY DESTINATION lib - ARCHIVE DESTINATION lib - ) +##===------------------------------------------------------------------------------*- CMake -*-===## +## +## S E R I A L B O X +## +## This file is distributed under terms of BSD license. +## See LICENSE.txt for more information. +## +##===------------------------------------------------------------------------------------------===## + +cmake_minimum_required(VERSION 3.12) + +set(SOURCES + FieldMap.cpp + FieldMap.h + FieldMapSerializer.h + FieldMapSerializer.cpp + FieldMetainfoImpl.cpp + FieldMetainfoImpl.h + FieldMetainfoImplSerializer.cpp + FieldMetainfoImplSerializer.h + FieldID.cpp + FieldID.h + Logging.cpp + Logging.h + MetainfoMapImpl.cpp + MetainfoMapImpl.h + MetainfoMapImplSerializer.cpp + MetainfoMapImplSerializer.h + MetainfoValueImpl.cpp + MetainfoValueImpl.h + SavepointImpl.cpp + SavepointImpl.h + SavepointImplSerializer.cpp + SavepointImplSerializer.h + SavepointVector.cpp + SavepointVector.h + SavepointVectorSerializer.cpp + SavepointVectorSerializer.h + SerializerImpl.cpp + SerializerImpl.h + StorageView.cpp + StorageView.h + Type.cpp + Type.h + Unreachable.cpp + Unreachable.h + + hash/HashFactory.cpp + hash/HashFactory.h + hash/SHA256.cpp + hash/SHA256.h + hash/MD5.cpp + hash/MD5.h + + archive/ArchiveFactory.cpp + archive/ArchiveFactory.h + archive/BinaryArchive.cpp + archive/BinaryArchive.h + archive/NetCDFArchive.cpp + archive/NetCDFArchive.h + archive/MockArchive.cpp + archive/MockArchive.h + + frontend/stella/MetainfoSet.cpp + frontend/stella/MetainfoSet.h + frontend/stella/Savepoint.cpp + frontend/stella/Savepoint.h + frontend/stella/Serializer.cpp + frontend/stella/Serializer.h + frontend/stella/DataFieldInfo.cpp + frontend/stella/DataFieldInfo.h +) + +add_library(SerialboxObjects OBJECT ${SOURCES}) +target_include_directories(SerialboxObjects + PUBLIC + $ + $ + ) +target_link_libraries(SerialboxObjects PUBLIC Boost::boost) +target_link_libraries(SerialboxObjects PUBLIC SerialboxFilesytemTarget) +# we use "-lpthread" instead of ${CMAKE_THREAD_LIBS_INIT} on purpose, because ${CMAKE_THREAD_LIBS_INIT} +# contains "-pthread" instead of "-lpthread" which is a problem if it propagates to nvcc via the target +target_link_libraries(SerialboxObjects PUBLIC pthread) + +add_library(SerialboxStatic STATIC $) +set_target_properties(SerialboxStatic PROPERTIES VERSION ${Serialbox_VERSION_STRING}) +target_link_libraries(SerialboxStatic PUBLIC SerialboxObjects) +if(BUILD_SHARED_LIBS) + add_library(SerialboxShared $) + set_target_properties(SerialboxShared PROPERTIES VERSION ${Serialbox_VERSION_STRING}) + target_link_libraries(SerialboxShared PUBLIC SerialboxObjects) +endif() + +if(SERIALBOX_USE_NETCDF) + target_link_libraries(SerialboxStatic PRIVATE NETCDF_TARGET) + if(BUILD_SHARED_LIBS) + target_link_libraries(SerialboxShared PUBLIC NETCDF_TARGET) + endif() + #TODO try to make private once we protect our headers + target_include_directories(SerialboxObjects PUBLIC SYSTEM ${NETCDF_INCLUDES}) +endif() + +if(BUILD_SHARED_LIBS) + set_property(TARGET SerialboxObjects PROPERTY POSITION_INDEPENDENT_CODE 1) +endif() + +install(TARGETS SerialboxStatic SerialboxObjects + EXPORT SerialboxTargets + LIBRARY DESTINATION lib + ARCHIVE DESTINATION lib + ) + +if(BUILD_SHARED_LIBS) + install(TARGETS SerialboxShared + EXPORT SerialboxTargets + LIBRARY DESTINATION lib + ARCHIVE DESTINATION lib + ) endif() \ No newline at end of file diff --git a/src/serialbox/core/FieldMap.cpp b/src/serialbox/core/FieldMap.cpp index ecbca316..ba28535c 100644 --- a/src/serialbox/core/FieldMap.cpp +++ b/src/serialbox/core/FieldMap.cpp @@ -13,39 +13,12 @@ //===------------------------------------------------------------------------------------------===// #include "serialbox/core/FieldMap.h" +#include "serialbox/core/FieldMapSerializer.h" namespace serialbox { -json::json FieldMap::toJSON() const { - json::json jsonNode; - - if(empty()) - return jsonNode; - - for(const_iterator it = this->begin(), end = this->end(); it != end; ++it) - jsonNode[it->first] = it->second->toJSON(); - - return jsonNode; -} - -void FieldMap::fromJSON(const json::json& jsonNode) { - this->clear(); - - if(jsonNode.is_null() || jsonNode.empty()) - return; - - for(auto it = jsonNode.begin(), end = jsonNode.end(); it != end; ++it) { - try { - insert(it.key(), it.value()); - } catch(Exception& e) { - throw Exception("cannot insert node '%s' in FieldMap: JSON node ill-formed: %s", it.key(), - e.what()); - } - } -} - std::ostream& operator<<(std::ostream& stream, const FieldMap& s) { - return (stream << "FieldMap = " << s.toJSON().dump(4)); + return (stream << "FieldMap = " << json::json{s}.dump(4)); } } // namespace serialbox diff --git a/src/serialbox/core/FieldMap.h b/src/serialbox/core/FieldMap.h index 03bd5a9b..23c5a541 100644 --- a/src/serialbox/core/FieldMap.h +++ b/src/serialbox/core/FieldMap.h @@ -16,7 +16,6 @@ #define SERIALBOX_CORE_FIELDMAP_H #include "serialbox/core/FieldMetainfoImpl.h" -#include "serialbox/core/Json.h" #include namespace serialbox { @@ -52,10 +51,7 @@ class FieldMap { /// \brief Default constructor (empty table) FieldMap() : map_(){}; - /// \brief Construct from json - explicit FieldMap(const json::json jsonNode) { fromJSON(jsonNode); } - - /// \brief Copy constructor [deleted] + /// \brief Copy constructor FieldMap(const FieldMap&) = default; /// \brief Move constructor @@ -215,14 +211,6 @@ class FieldMap { /// \brief Convert to stream friend std::ostream& operator<<(std::ostream& stream, const FieldMap& s); - /// \brief Convert to JSON - json::json toJSON() const; - - /// \brief Construct from JSON node - /// - /// \throw Exception JSON node is ill-formed - void fromJSON(const json::json& jsonNode); - private: map_type map_; }; diff --git a/src/serialbox/core/FieldMapSerializer.cpp b/src/serialbox/core/FieldMapSerializer.cpp new file mode 100644 index 00000000..4191b02e --- /dev/null +++ b/src/serialbox/core/FieldMapSerializer.cpp @@ -0,0 +1,36 @@ +//===-- serialbox/core/FieldMapSerializer.cpp ----------------------------------------*- C+ -*-===// +// +// S E R I A L B O X +// +// This file is distributed under terms of BSD license. +// See LICENSE.txt for more information +// +//===------------------------------------------------------------------------------------------===// + +#include "serialbox/core/FieldMapSerializer.h" +#include "serialbox/core/FieldMetainfoImplSerializer.h" + +namespace serialbox { + +void to_json(json::json& j, FieldMap const& fieldMap) { + for(FieldMap::const_iterator it = fieldMap.begin(), end = fieldMap.end(); it != end; ++it) + j[it->first] = *(it->second); +} + +void from_json(json::json const& j, FieldMap& fieldMap) { + fieldMap.clear(); + + if(j.is_null() || j.empty()) + return; + + for(auto it = j.begin(), end = j.end(); it != end; ++it) { + try { + fieldMap.insert(it.key(), it.value()); + } catch(Exception& e) { + throw Exception("cannot insert node '%s' in FieldMap: JSON node ill-formed: %s", it.key(), + e.what()); + } + } +} + +} // namespace serialbox diff --git a/src/serialbox/core/FieldMapSerializer.h b/src/serialbox/core/FieldMapSerializer.h new file mode 100644 index 00000000..00abcf24 --- /dev/null +++ b/src/serialbox/core/FieldMapSerializer.h @@ -0,0 +1,32 @@ +//===-- serialbox/core/FieldMapSerializer.h -----------------------------------------*- C++ -*-===// +// +// S E R I A L B O X +// +// This file is distributed under terms of BSD license. +// See LICENSE.txt for more information +// +//===------------------------------------------------------------------------------------------===// +// +/// \file +/// Enable json <-> FieldMap conversions via ADL +/// +//===------------------------------------------------------------------------------------------===// + +#ifndef SERIALBOX_CORE_FIELDMAP_SERIALIZER_H +#define SERIALBOX_CORE_FIELDMAP_SERIALIZER_H + +#include "serialbox/core/FieldMap.h" +#include "serialbox/core/Json.h" + +namespace serialbox { + +/// \addtogroup core +/// @{ +void to_json(json::json& j, FieldMap const& fieldMap); + +void from_json(json::json const& j, FieldMap& fieldMap); +/// @} + +} // namespace serialbox + +#endif diff --git a/src/serialbox/core/FieldMetainfoImpl.cpp b/src/serialbox/core/FieldMetainfoImpl.cpp index ee753a8f..eb9ccca0 100644 --- a/src/serialbox/core/FieldMetainfoImpl.cpp +++ b/src/serialbox/core/FieldMetainfoImpl.cpp @@ -1,5 +1,4 @@ -//===-- serialbox/core/FieldMetainfoImplImpl.h ------------------------------------------*- C++ -//-*-===// +//===-- serialbox/core/FieldMetainfoImpl.h ------------------------------------------*- C++ -*-===// // // S E R I A L B O X // @@ -43,39 +42,6 @@ bool FieldMetainfoImpl::operator==(const FieldMetainfoImpl& right) const noexcep return (*metaInfo_ == *right.metaInfo_); } -json::json FieldMetainfoImpl::toJSON() const { - json::json jsonNode; - jsonNode["type_id"] = static_cast(type_); - jsonNode["dims"] = dims_; - jsonNode["meta_info"] = metaInfo_->toJSON(); - return jsonNode; -} - -void FieldMetainfoImpl::fromJSON(const json::json& jsonNode) { - dims_.clear(); - metaInfo_->clear(); - - if(jsonNode.is_null() || jsonNode.empty()) - throw Exception("node is empty"); - - if(!jsonNode.count("type_id")) - throw Exception("no node 'type_id'"); - type_ = static_cast(int(jsonNode["type_id"])); - - if(!jsonNode.count("dims")) - throw Exception("no node 'value'"); - for(auto it = jsonNode["dims"].begin(), end = jsonNode["dims"].end(); it != end; ++it) - dims_.push_back(int(*it)); - - if(!jsonNode.count("meta_info")) - throw Exception("no node 'meta_info'"); - try { - metaInfo_->fromJSON(jsonNode["meta_info"]); - } catch(Exception& e) { - throw Exception("in node 'meta_info': %s", e.what()); - } -} - std::string FieldMetainfoImpl::toString() const { std::stringstream ss; ss << "type = " << TypeUtil::toString(type_) << ", dims = [" << ArrayUtil::toString(dims_) diff --git a/src/serialbox/core/FieldMetainfoImpl.h b/src/serialbox/core/FieldMetainfoImpl.h index d43bf40e..11abc795 100644 --- a/src/serialbox/core/FieldMetainfoImpl.h +++ b/src/serialbox/core/FieldMetainfoImpl.h @@ -1,5 +1,4 @@ -//===-- serialbox/core/FieldMetainfoImplImpl.h ------------------------------------------*- C++ -//-*-===// +//===-- serialbox/core/FieldMetainfoImpl.h ------------------------------------------*- C++ -*-===// // // S E R I A L B O X // @@ -16,7 +15,6 @@ #ifndef SERIALBOX_CORE_FIELDMAPMETAINFOIMPL_H #define SERIALBOX_CORE_FIELDMAPMETAINFOIMPL_H -#include "serialbox/core/Json.h" #include "serialbox/core/MetainfoMapImpl.h" #include @@ -40,11 +38,6 @@ class FieldMetainfoImpl { FieldMetainfoImpl(TypeID type, const std::vector& dims) : type_(type), dims_(dims), metaInfo_(std::make_shared()) {} - /// \brief Construct from JSON - explicit FieldMetainfoImpl(const json::json& jsonNode) : FieldMetainfoImpl() { - fromJSON(jsonNode); - } - /// \brief Copy constructor FieldMetainfoImpl(const FieldMetainfoImpl& other) { *this = other; } @@ -78,14 +71,6 @@ class FieldMetainfoImpl { MetainfoMapImpl& metaInfo() noexcept { return *metaInfo_; } const MetainfoMapImpl& metaInfo() const noexcept { return *metaInfo_; } - /// \brief Convert to JSON - json::json toJSON() const; - - /// \brief Construct from JSON node - /// - /// \throw Exception JSON node is ill-formed - void fromJSON(const json::json& jsonNode); - /// \brief Convert to string std::string toString() const; diff --git a/src/serialbox/core/FieldMetainfoImplSerializer.cpp b/src/serialbox/core/FieldMetainfoImplSerializer.cpp new file mode 100644 index 00000000..8583ca42 --- /dev/null +++ b/src/serialbox/core/FieldMetainfoImplSerializer.cpp @@ -0,0 +1,40 @@ +//===-- serialbox/core/FieldMetainfoImplSerializer.h --------------------------------*- C++ -*-===// +// +// S E R I A L B O X +// +// This file is distributed under terms of BSD license. +// See LICENSE.txt for more information +// +//===------------------------------------------------------------------------------------------===// + +#include "serialbox/core/FieldMetainfoImplSerializer.h" +#include "serialbox/core/MetainfoMapImplSerializer.h" + +namespace serialbox { + +void to_json(json::json& j, FieldMetainfoImpl const& f) { + j["type_id"] = static_cast(f.type()); + j["dims"] = f.dims(); + j["meta_info"] = f.metaInfo(); +} + +void from_json(json::json const& j, FieldMetainfoImpl& f) { + f.dims().clear(); + f.metaInfo().clear(); + + if(j.is_null() || j.empty()) + throw Exception("node is empty"); + + if(!j.count("type_id")) + throw Exception("no node 'type_id'"); + f.type() = static_cast(int(j["type_id"])); + + if(!j.count("dims")) + throw Exception("no node 'value'"); + for(auto it = j["dims"].begin(), end = j["dims"].end(); it != end; ++it) + f.dims().push_back(int(*it)); + + f.metaInfo() = j.at("meta_info"); +} + +} // namespace serialbox diff --git a/src/serialbox/core/FieldMetainfoImplSerializer.h b/src/serialbox/core/FieldMetainfoImplSerializer.h new file mode 100644 index 00000000..ef489e30 --- /dev/null +++ b/src/serialbox/core/FieldMetainfoImplSerializer.h @@ -0,0 +1,33 @@ +//===-- serialbox/core/FieldMetainfoImplSerializer.h --------------------------------*- C++ -*-===// +// +// S E R I A L B O X +// +// This file is distributed under terms of BSD license. +// See LICENSE.txt for more information +// +//===------------------------------------------------------------------------------------------===// +// +/// \file +/// Enable json <-> FieldMetainfoImpl conversions via ADL +/// +//===------------------------------------------------------------------------------------------===// + +#ifndef SERIALBOX_CORE_FIELDMAPMETAINFOIMPLSERIALIZER_H +#define SERIALBOX_CORE_FIELDMAPMETAINFOIMPLSERIALIZER_H + +#include "serialbox/core/FieldMetainfoImpl.h" +#include "serialbox/core/Json.h" +#include + +namespace serialbox { + +/// \addtogroup core +/// @{ +void to_json(json::json& j, FieldMetainfoImpl const& f); + +void from_json(json::json const& j, FieldMetainfoImpl& f); +/// @} + +} // namespace serialbox + +#endif diff --git a/src/serialbox/core/Json.h b/src/serialbox/core/Json.h index f7831162..b3db7bb9 100644 --- a/src/serialbox/core/Json.h +++ b/src/serialbox/core/Json.h @@ -11,12 +11,21 @@ /// This file includes the headers of the json library. /// See: https://github.com/nlohmann/json/tree/master /// +/// IMPORTANT: Conversion between our types and json::json is enabled via assignment by ADL. +/// However the ADL-enablers (to_json, from_json) are not included in the types declaration header +/// to not pollute the public interface with the json library. Therefore we need to include the +/// Serializer.hpp in files where we want to do <-> json conversions. Do this only +/// in cpp-files or private headers. +/// //===------------------------------------------------------------------------------------------===// #ifndef SERIALBOX_CORE_JSON_H #define SERIALBOX_CORE_JSON_H -#include "serialbox/core/external/json/json.hpp" +// On purpose including relatively as we are going out of the serialbox include directory. We don't +// want to install json.hpp to prevent accidently including it in the public interface. +// TODO split public and private headers properly in separate directories. +#include "../../external/json/json.hpp" /// \namespace json /// \brief Namespace of the JSON library diff --git a/src/serialbox/core/MetainfoMapImpl.cpp b/src/serialbox/core/MetainfoMapImpl.cpp index a7f36875..843f6df5 100644 --- a/src/serialbox/core/MetainfoMapImpl.cpp +++ b/src/serialbox/core/MetainfoMapImpl.cpp @@ -19,36 +19,6 @@ namespace serialbox { -namespace { - -struct InsertHelper { - // Capture environment - MetainfoMapImpl& map; - const std::string& key; - const json::json& node; - - // Read value from JSON node (and check if the types match) and insert it into the MetainfoMapImpl - // as - // type ´T´ - template - void insertAs(CheckFunction&& checkFunction, const char* valueStr) { - if(!(node["value"].*checkFunction)()) - throw Exception("sub-node '%s' not regconized as %s", key, valueStr); - T value = node["value"]; - map.insert(key, value); - } - - // Read value from JSON node as Array of type ´T´ and insert as array of type ´T´ into the - // MetainfoMapImpl - template - void insertAsArrayOf() { - Array array = node["value"]; - map.insert(key, array); - } -}; - -} // anonymous namespace - std::vector MetainfoMapImpl::keys() const { std::vector keys; keys.reserve(map_.size()); @@ -82,151 +52,6 @@ MetainfoMapImpl::at(const MetainfoMapImpl::key_type& key) const { } } -json::json MetainfoMapImpl::toJSON() const { - json::json jsonNode; - - if(map_.empty()) - return jsonNode; - - for(auto it = map_.cbegin(), end = map_.cend(); it != end; ++it) { - const MetainfoValueImpl& value = it->second; - const std::string& key = it->first; - - jsonNode[key]["type_id"] = static_cast(value.type()); - - json::json valueNode; - const bool isArray = TypeUtil::isArray(value.type()); - - switch(TypeUtil::getPrimitive(value.type())) { - case TypeID::Boolean: - if(isArray) { - for(const bool& v : value.as>()) - valueNode.push_back(v); - } else { - valueNode = value.as(); - } - break; - case TypeID::Int32: - if(isArray) { - for(const int& v : value.as>()) - valueNode.push_back(v); - } else { - valueNode = value.as(); - } - break; - case TypeID::Int64: - if(isArray) { - for(const std::int64_t& v : value.as>()) - valueNode.push_back(v); - } else { - valueNode = value.as(); - } - break; - case TypeID::Float32: - if(isArray) { - for(const float& v : value.as>()) - valueNode.push_back(v); - } else { - valueNode = value.as(); - } - break; - case TypeID::Float64: - if(isArray) { - for(const double& v : value.as>()) - valueNode.push_back(v); - } else { - valueNode = value.as(); - } - break; - case TypeID::String: - if(isArray) { - for(const std::string& v : value.as>()) - valueNode.push_back(v); - } else { - valueNode = value.as(); - } - break; - default: - serialbox_unreachable("Invalid TypeID"); - } - - jsonNode[key]["value"] = valueNode; - } - - return jsonNode; -} - -void MetainfoMapImpl::fromJSON(const json::json& jsonNode) { - map_.clear(); - - if(jsonNode.is_null() || jsonNode.empty()) - return; - - for(auto it = jsonNode.begin(), end = jsonNode.end(); it != end; ++it) { - - if(!it->count("type_id")) - throw Exception("sub-node '%s' has no node 'type_id'", it.key()); - - if(!it->count("value")) - throw Exception("sub-node '%s' has no node 'value'", it.key()); - - const json::json& node = it.value(); - const std::string& key = it.key(); - const int typeAsInt = node["type_id"]; - const TypeID type = static_cast(typeAsInt); - const bool isArray = TypeUtil::isArray(type); - - InsertHelper insertHelper{*this, key, node}; - - switch(TypeUtil::getPrimitive(type)) { - case TypeID::Boolean: - if(isArray) { - insertHelper.insertAsArrayOf(); - } else { - insertHelper.insertAs(&json::json::is_boolean, "boolean"); - } - break; - case TypeID::Int32: - if(isArray) { - insertHelper.insertAsArrayOf(); - } else { - insertHelper.insertAs(&json::json::is_number_integer, "integer"); - } - break; - case TypeID::Int64: - if(isArray) { - insertHelper.insertAsArrayOf(); - } else { - insertHelper.insertAs(&json::json::is_number_integer, "integer"); - } - break; - case TypeID::Float32: - if(isArray) { - insertHelper.insertAsArrayOf(); - } else { - insertHelper.insertAs(&json::json::is_number, "floating pointer number"); - } - break; - case TypeID::Float64: - if(isArray) { - insertHelper.insertAsArrayOf(); - } else { - insertHelper.insertAs(&json::json::is_number, "floating pointer number"); - } - break; - case TypeID::String: - if(isArray) { - insertHelper.insertAsArrayOf(); - } else { - insertHelper.insertAs(&json::json::is_string, "string"); - } - break; - default: - serialbox_unreachable("Invalid TypeID"); - } - } -} - std::ostream& operator<<(std::ostream& stream, const MetainfoMapImpl& s) { std::stringstream ss; ss << "{"; diff --git a/src/serialbox/core/MetainfoMapImpl.h b/src/serialbox/core/MetainfoMapImpl.h index a128dabd..0328734f 100644 --- a/src/serialbox/core/MetainfoMapImpl.h +++ b/src/serialbox/core/MetainfoMapImpl.h @@ -16,7 +16,6 @@ #define SERIALBOX_CORE_METAINFOMAPIMPL_H #include "serialbox/core/Exception.h" -#include "serialbox/core/Json.h" #include "serialbox/core/MetainfoValueImpl.h" #include "serialbox/core/Type.h" #include @@ -61,9 +60,6 @@ class MetainfoMapImpl { /// \brief Default constructor (empty map) MetainfoMapImpl() : map_(){}; - /// \brief Construct from json - explicit MetainfoMapImpl(const json::json& jsonNode) { fromJSON(jsonNode); } - /// \brief Construct from initalizer-list explicit MetainfoMapImpl(std::initializer_list list) : map_(list){}; @@ -196,14 +192,6 @@ class MetainfoMapImpl { /// \brief Test for inequality bool operator!=(const MetainfoMapImpl& right) const noexcept { return (!(*this == right)); } - /// \brief Convert to JSON - json::json toJSON() const; - - /// \brief Construct from JSON node - /// - /// \throw Exception JSON node is ill-formed - void fromJSON(const json::json& jsonNode); - /// \brief Convert to stream friend std::ostream& operator<<(std::ostream& stream, const MetainfoMapImpl& s); diff --git a/src/serialbox/core/MetainfoMapImplSerializer.cpp b/src/serialbox/core/MetainfoMapImplSerializer.cpp new file mode 100644 index 00000000..c8134d3c --- /dev/null +++ b/src/serialbox/core/MetainfoMapImplSerializer.cpp @@ -0,0 +1,183 @@ +//===-- serialbox/core/MetainfoMapImplSerializer.cpp --------------------------------*- C++ -*-===// +// +// S E R I A L B O X +// +// This file is distributed under terms of BSD license. +// See LICENSE.txt for more information +// +//===------------------------------------------------------------------------------------------===// + +#include "MetainfoMapImplSerializer.h" +#include "serialbox/core/Unreachable.h" + +namespace serialbox { + +namespace { + +struct InsertHelper { + // Capture environment + MetainfoMapImpl& map; + const std::string& key; + const json::json& node; + + // Read value from JSON node (and check if the types match) and insert it into the MetainfoMapImpl + // as + // type ´T´ + template + void insertAs(CheckFunction&& checkFunction, const char* valueStr) { + if(!(node["value"].*checkFunction)()) + throw Exception("sub-node '%s' not regconized as %s", key, valueStr); + T value = node["value"]; + map.insert(key, value); + } + + // Read value from JSON node as Array of type ´T´ and insert as array of type ´T´ into the + // MetainfoMapImpl + template + void insertAsArrayOf() { + Array array = node["value"]; + map.insert(key, array); + } +}; + +} // namespace + +void to_json(json::json& jsonNode, MetainfoMapImpl const& map) { + for(auto it = map.begin(), end = map.end(); it != end; ++it) { + const MetainfoValueImpl& value = it->second; + const std::string& key = it->first; + + jsonNode[key]["type_id"] = static_cast(value.type()); + + json::json valueNode; + const bool isArray = TypeUtil::isArray(value.type()); + + switch(TypeUtil::getPrimitive(value.type())) { + case TypeID::Boolean: + if(isArray) { + for(const bool& v : value.as>()) + valueNode.push_back(v); + } else { + valueNode = value.as(); + } + break; + case TypeID::Int32: + if(isArray) { + for(const int& v : value.as>()) + valueNode.push_back(v); + } else { + valueNode = value.as(); + } + break; + case TypeID::Int64: + if(isArray) { + for(const std::int64_t& v : value.as>()) + valueNode.push_back(v); + } else { + valueNode = value.as(); + } + break; + case TypeID::Float32: + if(isArray) { + for(const float& v : value.as>()) + valueNode.push_back(v); + } else { + valueNode = value.as(); + } + break; + case TypeID::Float64: + if(isArray) { + for(const double& v : value.as>()) + valueNode.push_back(v); + } else { + valueNode = value.as(); + } + break; + case TypeID::String: + if(isArray) { + for(const std::string& v : value.as>()) + valueNode.push_back(v); + } else { + valueNode = value.as(); + } + break; + default: + serialbox_unreachable("Invalid TypeID"); + } + + jsonNode[key]["value"] = valueNode; + } +} + +void from_json(json::json const& jsonNode, MetainfoMapImpl& map) { + map.clear(); + + if(jsonNode.is_null() || jsonNode.empty()) + return; + + for(auto it = jsonNode.begin(), end = jsonNode.end(); it != end; ++it) { + + if(!it->count("type_id")) + throw Exception("sub-node '%s' has no node 'type_id'", it.key()); + + if(!it->count("value")) + throw Exception("sub-node '%s' has no node 'value'", it.key()); + + const json::json& node = it.value(); + const std::string& key = it.key(); + const int typeAsInt = node["type_id"]; + const TypeID type = static_cast(typeAsInt); + const bool isArray = TypeUtil::isArray(type); + + InsertHelper insertHelper{map, key, node}; + + switch(TypeUtil::getPrimitive(type)) { + case TypeID::Boolean: + if(isArray) { + insertHelper.insertAsArrayOf(); + } else { + insertHelper.insertAs(&json::json::is_boolean, "boolean"); + } + break; + case TypeID::Int32: + if(isArray) { + insertHelper.insertAsArrayOf(); + } else { + insertHelper.insertAs(&json::json::is_number_integer, "integer"); + } + break; + case TypeID::Int64: + if(isArray) { + insertHelper.insertAsArrayOf(); + } else { + insertHelper.insertAs(&json::json::is_number_integer, "integer"); + } + break; + case TypeID::Float32: + if(isArray) { + insertHelper.insertAsArrayOf(); + } else { + insertHelper.insertAs(&json::json::is_number, "floating pointer number"); + } + break; + case TypeID::Float64: + if(isArray) { + insertHelper.insertAsArrayOf(); + } else { + insertHelper.insertAs(&json::json::is_number, "floating pointer number"); + } + break; + case TypeID::String: + if(isArray) { + insertHelper.insertAsArrayOf(); + } else { + insertHelper.insertAs(&json::json::is_string, "string"); + } + break; + default: + serialbox_unreachable("Invalid TypeID"); + } + } +} + +} // namespace serialbox diff --git a/src/serialbox/core/MetainfoMapImplSerializer.h b/src/serialbox/core/MetainfoMapImplSerializer.h new file mode 100644 index 00000000..51a9d18b --- /dev/null +++ b/src/serialbox/core/MetainfoMapImplSerializer.h @@ -0,0 +1,32 @@ +//===-- serialbox/core/MetainfoMapImplSerializer.h ----------------------------------*- C++ -*-===// +// +// S E R I A L B O X +// +// This file is distributed under terms of BSD license. +// See LICENSE.txt for more information +// +//===------------------------------------------------------------------------------------------===// +// +/// \file +/// This file implements the meta-information map. +/// +//===------------------------------------------------------------------------------------------===// + +#ifndef SERIALBOX_CORE_METAINFOMAPIMPLSERIALIZER_H +#define SERIALBOX_CORE_METAINFOMAPIMPLSERIALIZER_H + +#include "serialbox/core/Json.h" +#include "serialbox/core/MetainfoMapImpl.h" + +namespace serialbox { + +/// \addtogroup core +/// @{ +void to_json(json::json& jsonNode, MetainfoMapImpl const& map); + +void from_json(json::json const& jsonNode, MetainfoMapImpl& map); +/// @} + +} // namespace serialbox + +#endif diff --git a/src/serialbox/core/SavepointImpl.cpp b/src/serialbox/core/SavepointImpl.cpp index 804c0980..1d97cf3c 100644 --- a/src/serialbox/core/SavepointImpl.cpp +++ b/src/serialbox/core/SavepointImpl.cpp @@ -24,31 +24,6 @@ SavepointImpl& SavepointImpl::operator=(const SavepointImpl& other) { return (*this); } -json::json SavepointImpl::toJSON() const { - json::json jsonNode; - jsonNode["name"] = name_; - jsonNode["meta_info"] = metaInfo_->toJSON(); - return jsonNode; -} - -void SavepointImpl::fromJSON(const json::json& jsonNode) { - if(!metaInfo_) - metaInfo_ = std::make_shared(); - - name_.clear(); - metaInfo_->clear(); - - if(jsonNode.is_null() || jsonNode.empty()) - throw Exception("node is empty"); - - if(!jsonNode.count("name")) - throw Exception("no node 'name'"); - name_ = jsonNode["name"]; - - if(jsonNode.count("meta_info")) - metaInfo_->fromJSON(jsonNode["meta_info"]); -} - std::string SavepointImpl::toString() const { std::stringstream ss; ss << *this; diff --git a/src/serialbox/core/SavepointImpl.h b/src/serialbox/core/SavepointImpl.h index ca59e5c1..f72a7a98 100644 --- a/src/serialbox/core/SavepointImpl.h +++ b/src/serialbox/core/SavepointImpl.h @@ -16,7 +16,6 @@ #define SERIALBOX_CORE_SAVEPOINTIMPL_H #include "serialbox/core/Exception.h" -#include "serialbox/core/Json.h" #include "serialbox/core/MetainfoMapImpl.h" #include #include @@ -37,15 +36,13 @@ namespace serialbox { /// instead. class SavepointImpl { public: - /// \brief Construct an empty savepoint (wihtout `metaInfo` i.e this->empty() == true) - template ::value>::type> - explicit SavepointImpl(const StringType& name) + /// \brief Construct an empty savepoint (without `metaInfo` i.e this->empty() == true) + explicit SavepointImpl(const std::string& name) : name_(name), metaInfo_(std::make_shared()) {} /// \brief Construct savepoint with `name` and `metaInfo` - template - SavepointImpl(StringType&& name, MetainfoType&& metaInfo) + template + SavepointImpl(const std::string& name, MetainfoType&& metaInfo) : name_(name), metaInfo_(std::make_shared(std::forward(metaInfo))) {} @@ -55,8 +52,8 @@ class SavepointImpl { /// \brief Move constructor SavepointImpl(SavepointImpl&&) = default; - /// \brief Construct from JSON - explicit SavepointImpl(const json::json& jsonNode) { fromJSON(jsonNode); } + /// \brief Default constructor + SavepointImpl() = default; /// \brief Copy assignment SavepointImpl& operator=(const SavepointImpl& other); @@ -108,6 +105,9 @@ class SavepointImpl { /// \brief Access name const std::string& name() const noexcept { return name_; } + /// \brief Set name + void setName(std::string const& name) noexcept { name_ = name; }; + /// \brief Access meta-info MetainfoMapImpl& metaInfo() noexcept { return *metaInfo_; } const MetainfoMapImpl& metaInfo() const noexcept { return *metaInfo_; } @@ -116,14 +116,6 @@ class SavepointImpl { /// meta-information attached) bool empty() const noexcept { return metaInfo_->empty(); } - /// \brief Convert to JSON - json::json toJSON() const; - - /// \brief Construct from JSON node - /// - /// \throw Exception JSON node is ill-formed - void fromJSON(const json::json& jsonNode); - /// \brief Convert savepoint to string std::string toString() const; diff --git a/src/serialbox/core/SavepointImplSerializer.cpp b/src/serialbox/core/SavepointImplSerializer.cpp new file mode 100644 index 00000000..75199509 --- /dev/null +++ b/src/serialbox/core/SavepointImplSerializer.cpp @@ -0,0 +1,35 @@ +//===-- serialbox/core/SavepointImplSerializer.cpp ----------------------------------*- C++ -*-===// +// +// S E R I A L B O X +// +// This file is distributed under terms of BSD license. +// See LICENSE.txt for more information +// +//===------------------------------------------------------------------------------------------===// + +#include "serialbox/core/SavepointImplSerializer.h" +#include "serialbox/core/MetainfoMapImplSerializer.h" + +namespace serialbox { + +void to_json(json::json& jsonNode, SavepointImpl const& savepoint) { + jsonNode["name"] = savepoint.name(); + jsonNode["meta_info"] = savepoint.metaInfo(); +} + +void from_json(json::json const& jsonNode, SavepointImpl& savepoint) { + if(!savepoint.metaInfoPtr()) + savepoint.metaInfoPtr() = std::make_shared(); + + savepoint.metaInfo().clear(); + + if(jsonNode.is_null() || jsonNode.empty()) + throw Exception("node is empty"); + + savepoint.setName(jsonNode.at("name")); + + if(jsonNode.count("meta_info")) + savepoint.metaInfo() = jsonNode["meta_info"]; +} + +} // namespace serialbox diff --git a/src/serialbox/core/SavepointImplSerializer.h b/src/serialbox/core/SavepointImplSerializer.h new file mode 100644 index 00000000..c1e1b4ab --- /dev/null +++ b/src/serialbox/core/SavepointImplSerializer.h @@ -0,0 +1,32 @@ +//===-- serialbox/core/SavepointImplSerializer.h ------------------------------------*- C++ -*-===// +// +// S E R I A L B O X +// +// This file is distributed under terms of BSD license. +// See LICENSE.txt for more information +// +//===------------------------------------------------------------------------------------------===// +// +/// \file +/// Enable json <-> FieldMap conversions via ADL +/// +//===------------------------------------------------------------------------------------------===// + +#ifndef SERIALBOX_CORE_SAVEPOINTIMPLSERIALIZER_H +#define SERIALBOX_CORE_SAVEPOINTIMPLSERIALIZER_H + +#include "serialbox/core/Json.h" +#include "serialbox/core/SavepointImpl.h" + +namespace serialbox { + +/// \addtogroup core +/// @{ +void to_json(json::json& jsonNode, SavepointImpl const& savepoint); + +void from_json(json::json const& jsonNode, SavepointImpl& savepoint); +/// @} + +} // namespace serialbox + +#endif diff --git a/src/serialbox/core/SavepointVector.cpp b/src/serialbox/core/SavepointVector.cpp index 63e4ecfb..abdcfba7 100644 --- a/src/serialbox/core/SavepointVector.cpp +++ b/src/serialbox/core/SavepointVector.cpp @@ -15,6 +15,7 @@ #include "serialbox/core/SavepointVector.h" #include "serialbox/core/Logging.h" +#include "serialbox/core/SavepointVectorSerializer.h" namespace serialbox { @@ -99,66 +100,8 @@ void SavepointVector::clear() noexcept { fields_.clear(); } -json::json SavepointVector::toJSON() const { - json::json jsonNode; - assert(savepoints_.size() == fields_.size()); - - for(std::size_t i = 0; i < savepoints_.size(); ++i) - jsonNode["savepoints"].push_back(savepoints_[i]->toJSON()); - - for(std::size_t i = 0; i < fields_.size(); ++i) { - const std::string& savepoint = savepoints_[i]->name(); - json::json fieldNode; - - if(fields_[i].empty()) - fieldNode[savepoint] = nullptr; - - for(auto it = fields_[i].begin(), end = fields_[i].end(); it != end; ++it) - fieldNode[savepoint][it->first] = it->second; - - jsonNode["fields_per_savepoint"].push_back(fieldNode); - } - - return jsonNode; -} - -void SavepointVector::fromJSON(const json::json& jsonNode) { - index_.clear(); - savepoints_.clear(); - fields_.clear(); - - if(jsonNode.is_null() || jsonNode.empty()) - return; - - // Add savepoints - if(jsonNode.count("savepoints")) { - for(auto it = jsonNode["savepoints"].begin(), end = jsonNode["savepoints"].end(); it != end; - ++it) { - SavepointImpl sp(*it); - insert(sp); - } - } - - // Eeach savepoint needs an entry in the fields array (it can be null though) - if(jsonNode.count("fields_per_savepoint") && - jsonNode["fields_per_savepoint"].size() != fields_.size()) - throw Exception("inconsistent number of 'fields_per_savepoint' and 'savepoints'"); - - for(std::size_t i = 0; i < fields_.size(); ++i) { - const json::json& fieldNode = jsonNode["fields_per_savepoint"][i][savepoints_[i]->name()]; - - // Savepoint has no fields - if(fieldNode.is_null() || fieldNode.empty()) - break; - - // Add fields - for(auto it = fieldNode.begin(), end = fieldNode.end(); it != end; ++it) - fields_[i].insert({it.key(), static_cast(it.value())}); - } -} - std::ostream& operator<<(std::ostream& stream, const SavepointVector& s) { - stream << "SavepointVector = " << s.toJSON().dump(4); + stream << "SavepointVector = " << json::json{s}.dump(4); return stream; } diff --git a/src/serialbox/core/SavepointVector.h b/src/serialbox/core/SavepointVector.h index a0c6a666..2957fe84 100644 --- a/src/serialbox/core/SavepointVector.h +++ b/src/serialbox/core/SavepointVector.h @@ -17,7 +17,6 @@ #define SERIALBOX_CORE_SAVEPOINTVECTOR_H #include "serialbox/core/FieldID.h" -#include "serialbox/core/Json.h" #include "serialbox/core/SavepointImpl.h" #include #include @@ -60,9 +59,6 @@ class SavepointVector { /// \brief Move constructor SavepointVector(SavepointVector&&) = default; - /// \brief Construct from JSON - explicit SavepointVector(const json::json& jsonNode) { fromJSON(jsonNode); } - /// \brief Copy assignment SavepointVector& operator=(const SavepointVector&) = default; @@ -155,13 +151,10 @@ class SavepointVector { const savepoint_vector_type& savepoints() const noexcept { return savepoints_; } savepoint_vector_type& savepoints() noexcept { return savepoints_; } - /// \brief Convert to JSON - json::json toJSON() const; + /// \brief Access the fields + const fields_per_savepoint_vector_type& fields() const noexcept { return fields_; } - /// \brief Construct from JSON node - /// - /// \throw Exception JSON node is ill-formed - void fromJSON(const json::json& jsonNode); + void insertField(std::size_t index, fields_per_savepoint_type const& f) { fields_[index] = f; }; /// \brief Convert to stream friend std::ostream& operator<<(std::ostream& stream, const SavepointVector& s); diff --git a/src/serialbox/core/SavepointVectorSerializer.cpp b/src/serialbox/core/SavepointVectorSerializer.cpp new file mode 100644 index 00000000..d22528a0 --- /dev/null +++ b/src/serialbox/core/SavepointVectorSerializer.cpp @@ -0,0 +1,70 @@ +//===-- serialbox/core/SavepointVectorSerializer.cpp --------------------------------*- C++ -*-===// +// +// S E R I A L B O X +// +// This file is distributed under terms of BSD license. +// See LICENSE.txt for more information +// +//===------------------------------------------------------------------------------------------===// + +#include "serialbox/core/SavepointVectorSerializer.h" +#include "serialbox/core/SavepointImplSerializer.h" + +namespace serialbox { + +void to_json(json::json& jsonNode, SavepointVector const& v) { + assert(v.size() == v.fields().size()); + + for(std::size_t i = 0; i < v.size(); ++i) + jsonNode["savepoints"].push_back(*(v.savepoints()[i])); + + for(std::size_t i = 0; i < v.fields().size(); ++i) { + const std::string& savepoint = v.savepoints()[i]->name(); + json::json fieldNode; + + if(v.fields()[i].empty()) + fieldNode[savepoint] = nullptr; + + for(auto it = v.fields()[i].begin(), end = v.fields()[i].end(); it != end; ++it) + fieldNode[savepoint][it->first] = it->second; + + jsonNode["fields_per_savepoint"].push_back(fieldNode); + } +} + +void from_json(json::json const& jsonNode, SavepointVector& v) { + v.clear(); + + if(jsonNode.is_null() || jsonNode.empty()) + return; + + // Add savepoints + if(jsonNode.count("savepoints")) { + for(auto it = jsonNode["savepoints"].begin(), end = jsonNode["savepoints"].end(); it != end; + ++it) { + SavepointImpl sp = *it; + v.insert(sp); + } + } + + // Eeach savepoint needs an entry in the fields array (it can be null though) + if(jsonNode.count("fields_per_savepoint") && + jsonNode["fields_per_savepoint"].size() != v.fields().size()) + throw Exception("inconsistent number of 'fields_per_savepoint' and 'savepoints'"); + + for(std::size_t i = 0; i < v.fields().size(); ++i) { + const json::json& fieldNode = jsonNode["fields_per_savepoint"][i][v.savepoints()[i]->name()]; + + // Savepoint has no fields + if(fieldNode.is_null() || fieldNode.empty()) + break; + + SavepointVector::fields_per_savepoint_type fields; + // Add fields + for(auto it = fieldNode.begin(), end = fieldNode.end(); it != end; ++it) + fields.insert({it.key(), static_cast(it.value())}); + v.insertField(i, fields); + } +} + +} // namespace serialbox diff --git a/src/serialbox/core/SavepointVectorSerializer.h b/src/serialbox/core/SavepointVectorSerializer.h new file mode 100644 index 00000000..42db97fb --- /dev/null +++ b/src/serialbox/core/SavepointVectorSerializer.h @@ -0,0 +1,32 @@ +//===-- serialbox/core/SavepointVectorSerializer.h ----------------------------------*- C++ -*-===// +// +// S E R I A L B O X +// +// This file is distributed under terms of BSD license. +// See LICENSE.txt for more information +// +//===------------------------------------------------------------------------------------------===// +// +/// \file +/// Enable json <-> SavepointVector conversions via ADL +/// +//===------------------------------------------------------------------------------------------===// + +#ifndef SERIALBOX_CORE_SAVEPOINTVECTORSERIALIZER_H +#define SERIALBOX_CORE_SAVEPOINTVECTORSERIALIZER_H + +#include "serialbox/core/Json.h" +#include "serialbox/core/SavepointVector.h" + +namespace serialbox { + +/// \addtogroup core +/// @{ +void to_json(json::json& jsonNode, SavepointVector const& v); + +void from_json(json::json const& jsonNode, SavepointVector& v); +/// @} + +} // namespace serialbox + +#endif diff --git a/src/serialbox/core/SerializerImpl.cpp b/src/serialbox/core/SerializerImpl.cpp index 6cc127dc..40a6dccf 100644 --- a/src/serialbox/core/SerializerImpl.cpp +++ b/src/serialbox/core/SerializerImpl.cpp @@ -14,8 +14,11 @@ #include "serialbox/core/SerializerImpl.h" #include "serialbox/core/Compiler.h" +#include "serialbox/core/FieldMapSerializer.h" #include "serialbox/core/Filesystem.h" +#include "serialbox/core/MetainfoMapImplSerializer.h" #include "serialbox/core/STLExtras.h" +#include "serialbox/core/SavepointVectorSerializer.h" #include "serialbox/core/Type.h" #include "serialbox/core/Unreachable.h" #include "serialbox/core/Version.h" @@ -34,6 +37,26 @@ namespace serialbox { +void to_json(json::json& jsonNode, SerializerImpl const& ser) { + LOG(info) << "Converting Serializer MetaData to JSON"; + + // Tag version + jsonNode["serialbox_version"] = + 100 * SERIALBOX_VERSION_MAJOR + 10 * SERIALBOX_VERSION_MINOR + SERIALBOX_VERSION_PATCH; + + // Serialize prefix + jsonNode["prefix"] = ser.prefix(); + + // Serialize globalMetainfo + jsonNode["global_meta_info"] = ser.globalMetainfo(); + + // Serialize SavepointVector + jsonNode["savepoint_vector"] = ser.savepointVector(); + + // Serialize FieldMap + jsonNode["field_map"] = ser.fieldMap(); +} + int SerializerImpl::enabled_ = 0; SerializerImpl::SerializerImpl(OpenModeKind mode, const std::string& directory, @@ -327,15 +350,15 @@ void SerializerImpl::constructMetaDataFromJson() { // Construct globalMetainfo if(jsonNode.count("global_meta_info")) - globalMetainfo_->fromJSON(jsonNode["global_meta_info"]); + *globalMetainfo_ = jsonNode.at("global_meta_info"); // Construct Savepoints if(jsonNode.count("savepoint_vector")) - savepointVector_->fromJSON(jsonNode["savepoint_vector"]); + *savepointVector_ = jsonNode["savepoint_vector"]; // Construct FieldMap if(jsonNode.count("field_map")) - fieldMap_->fromJSON(jsonNode["field_map"]); + *fieldMap_ = jsonNode["field_map"]; // TODO probably fieldMap_ shouldn't be a shared_ptr } catch(Exception& e) { throw Exception("error while parsing %s: %s", metaDataFile_, e.what()); @@ -364,34 +387,10 @@ std::ostream& operator<<(std::ostream& stream, const SerializerImpl& s) { return (stream << s.toString()); } -json::json SerializerImpl::toJSON() const { - LOG(info) << "Converting Serializer MetaData to JSON"; - - json::json jsonNode; - - // Tag version - jsonNode["serialbox_version"] = - 100 * SERIALBOX_VERSION_MAJOR + 10 * SERIALBOX_VERSION_MINOR + SERIALBOX_VERSION_PATCH; - - // Serialize prefix - jsonNode["prefix"] = prefix_; - - // Serialize globalMetainfo - jsonNode["global_meta_info"] = globalMetainfo_->toJSON(); - - // Serialize SavepointVector - jsonNode["savepoint_vector"] = savepointVector_->toJSON(); - - // Serialize FieldMap - jsonNode["field_map"] = fieldMap_->toJSON(); - - return jsonNode; -} - void SerializerImpl::updateMetaData() { LOG(info) << "Update MetaData of Serializer"; - json::json jsonNode = toJSON(); + json::json jsonNode = *this; // Write metaData to disk (just overwrite the file, we assume that there is never more than one // Serializer per data set and thus our in-memory copy is always the up-to-date one) diff --git a/src/serialbox/core/SerializerImpl.h b/src/serialbox/core/SerializerImpl.h index 67945305..1acbda6b 100644 --- a/src/serialbox/core/SerializerImpl.h +++ b/src/serialbox/core/SerializerImpl.h @@ -17,7 +17,6 @@ #include "serialbox/core/FieldMap.h" #include "serialbox/core/Filesystem.h" -#include "serialbox/core/Json.h" #include "serialbox/core/MetainfoMapImpl.h" #include "serialbox/core/SavepointVector.h" #include "serialbox/core/StorageView.h" @@ -323,7 +322,8 @@ class SerializerImpl { /// /// \see /// Archive::read - void read(const std::string& name, const SavepointImpl& savepoint, StorageView& storageView, bool alsoPrevious = false); + void read(const std::string& name, const SavepointImpl& savepoint, StorageView& storageView, + bool alsoPrevious = false); /// \brief Deserialize sliced field `name` (given as `storageView` and `slice`) at `savepoint` /// from disk. @@ -376,9 +376,6 @@ class SerializerImpl { /// savepointVector, fieldMap and globalMetainfo as well as the meta-data of the Archive. void updateMetaData(); - /// \brief Convert all members of the Serializer to JSON - json::json toJSON() const; - /// \brief Convert to string std::string toString() const; diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 9e1647fd..c5445240 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -1,85 +1,84 @@ -##===------------------------------------------------------------------------------*- CMake -*-===## -## -## S E R I A L B O X -## -## This file is distributed under terms of BSD license. -## See LICENSE.txt for more information. -## -##===------------------------------------------------------------------------------------------===## - -cmake_minimum_required(VERSION 3.12) - -## serialbox_add_unittest_executable -## --------------------------------- -## -## Add a unittest executable and register it within CMake -## -## NAME:STRING=<> - Name of the unitests -## LIBRARIES:STRING=<> - Specify external libraries or flags to be use when linking the -## target (SerialboxUnittestUtility will be added). -## SOURCES:STRING=<> - List of source files -## DEPENDS:STRING=<> - Dependency on other targets -function(serialbox_add_unittest_executable) - set(one_value_args NAME) - set(multi_value_args LIBRARIES SOURCES DEPENDS) - cmake_parse_arguments(ARG "${options}" "${one_value_args}" "${multi_value_args}" ${ARGN}) - - set(libraries ${ARG_LIBRARIES} SerialboxUnittestUtility) - set(sources ${ARG_SOURCES}) - set(depends ${ARG_DEPENDS}) - - if(ARG_UNPARSED_ARGUMENTS) - message(FATAL_ERROR - "unparsed arguments: ${ARG_UNPARSED_ARGUMENTS}") - endif() - - set(opt_arg) - if(ARG_LIBRARIES) - set(opt_arg ${opt_arg} LIBRARIES ${ARG_LIBRARIES}) - endif() - add_executable(${ARG_NAME} ${sources}) - target_link_libraries(${ARG_NAME} SerialboxUnittestUtilityStatic ${depends} ${ARG_LIBRARIES}) - - if(DEFINED SERIALBOX_VERBOSE_WARNINGS) - set_target_properties(${ARG_NAME} PROPERTIES COMPILE_FLAGS -Wall) - endif() - - if(DEFINED BUILD_SERIALBOX_OLD) - add_dependencies(${ARG_NAME} serialbox-old) - endif() - - if(DEFINED BUILD_STELLA) - add_dependencies(${ARG_NAME} stella) - endif() - - if(DEFINED COVERAGE_SUPPORTED) - set_property(TARGET ${ARG_NAME} PROPERTY COMPILE_FLAGS ${CMAKE_CXX_FLAGS_COVERAGE}) - set_property(TARGET ${ARG_NAME} PROPERTY LINK_FLAGS ${CMAKE_EXE_LINKER_FLAGS_COVERAGE}) - set_property(TARGET ${ARG_NAME} PROPERTY RUNTIME_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}) - add_dependencies(coverage ${ARG_NAME}) - endif() - - serialbox_add_test(TARGET ${ARG_NAME} - EXECUTABLE ${CMAKE_CURRENT_BINARY_DIR}/${ARG_NAME}) -endfunction(serialbox_add_unittest_executable) - -## Add subdirectories -add_subdirectory(utility) -add_subdirectory(serialbox) - -if(SERIALBOX_ENABLE_C) - add_subdirectory(serialbox-c) -endif() - -if(SERIALBOX_TESTING_PYTHON) - add_subdirectory(serialbox-python) -endif() - -if(SERIALBOX_TESTING_FORTRAN) - add_subdirectory(serialbox-fortran) -endif() - -if(SERIALBOX_BENCHMARKING) - add_subdirectory(benchmark) -endif(SERIALBOX_BENCHMARKING) - +##===------------------------------------------------------------------------------*- CMake -*-===## +## +## S E R I A L B O X +## +## This file is distributed under terms of BSD license. +## See LICENSE.txt for more information. +## +##===------------------------------------------------------------------------------------------===## + +cmake_minimum_required(VERSION 3.12) + +## serialbox_add_unittest_executable +## --------------------------------- +## +## Add a unittest executable and register it within CMake +## +## NAME:STRING=<> - Name of the unitests +## LIBRARIES:STRING=<> - Specify external libraries or flags to be use when linking the +## target (SerialboxUnittestUtility will be added). +## SOURCES:STRING=<> - List of source files +## DEPENDS:STRING=<> - Dependency on other targets +function(serialbox_add_unittest_executable) + set(one_value_args NAME) + set(multi_value_args LIBRARIES SOURCES DEPENDS) + cmake_parse_arguments(ARG "${options}" "${one_value_args}" "${multi_value_args}" ${ARGN}) + + set(libraries ${ARG_LIBRARIES} SerialboxUnittestUtility) + set(sources ${ARG_SOURCES}) + set(depends ${ARG_DEPENDS}) + + if(ARG_UNPARSED_ARGUMENTS) + message(FATAL_ERROR + "unparsed arguments: ${ARG_UNPARSED_ARGUMENTS}") + endif() + + set(opt_arg) + if(ARG_LIBRARIES) + set(opt_arg ${opt_arg} LIBRARIES ${ARG_LIBRARIES}) + endif() + add_executable(${ARG_NAME} ${sources}) + target_link_libraries(${ARG_NAME} SerialboxUnittestUtilityStatic ${depends} ${ARG_LIBRARIES}) + + if(DEFINED SERIALBOX_VERBOSE_WARNINGS) + set_target_properties(${ARG_NAME} PROPERTIES COMPILE_FLAGS -Wall) + endif() + + if(DEFINED BUILD_SERIALBOX_OLD) + add_dependencies(${ARG_NAME} serialbox-old) + endif() + + if(DEFINED BUILD_STELLA) + add_dependencies(${ARG_NAME} stella) + endif() + + if(DEFINED COVERAGE_SUPPORTED) + set_property(TARGET ${ARG_NAME} PROPERTY COMPILE_FLAGS ${CMAKE_CXX_FLAGS_COVERAGE}) + set_property(TARGET ${ARG_NAME} PROPERTY LINK_FLAGS ${CMAKE_EXE_LINKER_FLAGS_COVERAGE}) + set_property(TARGET ${ARG_NAME} PROPERTY RUNTIME_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}) + add_dependencies(coverage ${ARG_NAME}) + endif() + + serialbox_add_test(TARGET ${ARG_NAME} + EXECUTABLE ${CMAKE_CURRENT_BINARY_DIR}/${ARG_NAME}) +endfunction(serialbox_add_unittest_executable) + +## Add subdirectories +add_subdirectory(utility) +add_subdirectory(serialbox) + +if(SERIALBOX_ENABLE_C) + add_subdirectory(serialbox-c) +endif() + +if(SERIALBOX_TESTING_PYTHON) + add_subdirectory(serialbox-python) +endif() + +if(SERIALBOX_TESTING_FORTRAN) + add_subdirectory(serialbox-fortran) +endif() + +if(SERIALBOX_BENCHMARKING) + add_subdirectory(benchmark) +endif(SERIALBOX_BENCHMARKING) diff --git a/test/serialbox/core/UnittestFieldMap.cpp b/test/serialbox/core/UnittestFieldMap.cpp index 52c80356..333dbd94 100644 --- a/test/serialbox/core/UnittestFieldMap.cpp +++ b/test/serialbox/core/UnittestFieldMap.cpp @@ -13,6 +13,7 @@ //===------------------------------------------------------------------------------------------===// #include "serialbox/core/FieldMap.h" +#include "serialbox/core/FieldMapSerializer.h" #include #include @@ -44,7 +45,7 @@ TEST(FieldMapTest, Construction) { // Perfect forwarding ASSERT_TRUE(map.insert("field_forwarded_args", type, dims, metaInfo)); - + // Copy construct (deep copy) FieldMap map_copy(map); ASSERT_TRUE(map_copy == map); @@ -80,8 +81,10 @@ TEST(FieldMapTest, Construction) { EXPECT_EQ(const_map.findField("field1")->second->metaInfo().at("key1").as(), "str"); - EXPECT_EQ(const_map.getFieldMetainfoImplOf("field1").metaInfo().at("key1").as(), "str"); - EXPECT_THROW(const_map.getFieldMetainfoImplOf("X").metaInfo().at("key1").as(), Exception); + EXPECT_EQ(const_map.getFieldMetainfoImplOf("field1").metaInfo().at("key1").as(), + "str"); + EXPECT_THROW(const_map.getFieldMetainfoImplOf("X").metaInfo().at("key1").as(), + Exception); EXPECT_EQ(const_map.getMetainfoOf("field1").at("key1").as(), "str"); EXPECT_THROW(const_map.getMetainfoOf("X").at("key1").as(), Exception); @@ -134,7 +137,7 @@ TEST(FieldMapTest, toJSON) { ASSERT_TRUE(map.insert("field1", constructFieldMetainfoImpl(1.0))); ASSERT_TRUE(map.insert("field2", constructFieldMetainfoImpl(2.0))); - json::json j = map.toJSON(); + json::json j = map; // The correct serialization of the FieldMetainfoImpl is tested elsewhere ASSERT_TRUE(j.count("field1")); @@ -186,17 +189,16 @@ TEST(FieldMapTest, fromJSON) { } )"_json; - FieldMap map; - map.fromJSON(j); - + FieldMap map = j; + // type EXPECT_EQ(map.getTypeOf("field1"), TypeID::Float32); EXPECT_EQ(map.getTypeOf("field2"), TypeID::Float64); - + // dims EXPECT_EQ(map.getDimsOf("field1"), (std::vector{32, 16})); EXPECT_EQ(map.getDimsOf("field2"), (std::vector{20, 55, 1992})); - + // meta-info EXPECT_EQ(map.getMetainfoOf("field1").at("key1").as(), "field1_meta_info_str"); EXPECT_EQ(map.getMetainfoOf("field2").at("key1").as(), "field2_meta_info_str"); @@ -210,11 +212,10 @@ TEST(FieldMapTest, fromJSON) { // ----------------------------------------------------------------------------------------------- { auto j = R"({})"_json; - FieldMap map; - map.fromJSON(j); + FieldMap map = j; EXPECT_TRUE(map.empty()); } - + // ----------------------------------------------------------------------------------------------- // Failure (corrupted meta_info of field1; key1 is missing the type-id) // ----------------------------------------------------------------------------------------------- @@ -240,9 +241,9 @@ TEST(FieldMapTest, fromJSON) { } )"_json; FieldMap map; - ASSERT_THROW(map.fromJSON(j), Exception); + ASSERT_THROW(map = j, Exception); } - + // ----------------------------------------------------------------------------------------------- // Failure (multiple field1) // ----------------------------------------------------------------------------------------------- @@ -284,7 +285,7 @@ TEST(FieldMapTest, fromJSON) { } )"_json; FieldMap map; - ASSERT_THROW(map.fromJSON(j), Exception); + ASSERT_THROW(map = j, Exception); } } diff --git a/test/serialbox/core/UnittestFieldMetainfoImpl.cpp b/test/serialbox/core/UnittestFieldMetainfoImpl.cpp index f18e79c1..fa60c367 100644 --- a/test/serialbox/core/UnittestFieldMetainfoImpl.cpp +++ b/test/serialbox/core/UnittestFieldMetainfoImpl.cpp @@ -1,4 +1,5 @@ -//===-- serialbox/core/UnittestFieldMetainfoImpl.cpp ------------------------------------*- C++ -*-===// +//===-- serialbox/core/UnittestFieldMetainfoImpl.cpp ------------------------------------*- C++ +//-*-===// // // S E R I A L B O X // @@ -13,12 +14,15 @@ //===------------------------------------------------------------------------------------------===// #include "serialbox/core/FieldMetainfoImpl.h" +#include "serialbox/core/FieldMetainfoImplSerializer.h" #include #include +using nlohmann::basic_json; + using namespace serialbox; -template +template static bool mapEqual(const MetainfoMapImplType1& map1, const MetainfoMapImplType2& map2) { if(map1.size() != map2.size()) return false; @@ -83,11 +87,11 @@ TEST(FieldMetainfoImplTest, Construction) { EXPECT_EQ(f.type(), f_copy.type()); EXPECT_TRUE(std::equal(f.dims().begin(), f.dims().end(), f_copy.dims().begin())); EXPECT_TRUE(mapEqual(f.metaInfo(), f_copy.metaInfo())); - + // Check that we actually performed a deep copy f.metaInfo().insert("newKey", "str"); EXPECT_FALSE(mapEqual(f.metaInfo(), f_copy.metaInfo())); - + FieldMetainfoImpl f_move(std::move(f)); EXPECT_EQ(f_move.type(), f_copy.type()); EXPECT_TRUE(std::equal(f_move.dims().begin(), f_move.dims().end(), f_copy.dims().begin())); @@ -159,7 +163,7 @@ TEST(FieldMetainfoImplTest, toJSON) { {"key1", MetainfoValueImpl(std::string("str"))}, {"key2", MetainfoValueImpl(double(5))}}); FieldMetainfoImpl f(type, dims, metaInfo); - json::json j = f.toJSON(); + json::json j = f; // Dims ASSERT_TRUE(j.count("dims")); @@ -233,7 +237,7 @@ TEST(FieldMetainfoImplTest, fromJSON) { { json::json j; FieldMetainfoImpl f; - ASSERT_THROW(f.fromJSON(j);, Exception); + ASSERT_THROW(f = j;, Exception); } // ----------------------------------------------------------------------------------------------- @@ -257,7 +261,7 @@ TEST(FieldMetainfoImplTest, fromJSON) { )"_json; FieldMetainfoImpl f; - ASSERT_THROW(f.fromJSON(j);, Exception); + ASSERT_THROW(f = j;, Exception); } // ----------------------------------------------------------------------------------------------- @@ -284,7 +288,7 @@ TEST(FieldMetainfoImplTest, fromJSON) { )"_json; FieldMetainfoImpl f; - ASSERT_THROW(f.fromJSON(j);, Exception); + ASSERT_THROW(f = j;, Exception); } // ----------------------------------------------------------------------------------------------- @@ -302,7 +306,8 @@ TEST(FieldMetainfoImplTest, fromJSON) { )"_json; FieldMetainfoImpl f; - ASSERT_THROW(f.fromJSON(j);, Exception); + + ASSERT_ANY_THROW(f = j); } } diff --git a/test/serialbox/core/UnittestMetainfoMapImpl.cpp b/test/serialbox/core/UnittestMetainfoMapImpl.cpp index 3c1cda7e..f0560464 100644 --- a/test/serialbox/core/UnittestMetainfoMapImpl.cpp +++ b/test/serialbox/core/UnittestMetainfoMapImpl.cpp @@ -1,4 +1,5 @@ -//===-- serialbox/core/UnittestMetainfoMapImpl.cpp --------------------------------------*- C++ -*-===// +//===-- serialbox/core/UnittestMetainfoMapImpl.cpp --------------------------------------*- C++ +//-*-===// // // S E R I A L B O X // @@ -13,6 +14,7 @@ //===------------------------------------------------------------------------------------------===// #include "serialbox/core/MetainfoMapImpl.h" +#include "serialbox/core/MetainfoMapImplSerializer.h" #include #include @@ -39,12 +41,12 @@ TEST(MetainfoMapImplTest, Construction) { EXPECT_EQ(map["key1"].as(), "value2"); EXPECT_EQ(map.at("key1").as(), "value2"); EXPECT_THROW(map.at("key2").as(), Exception); - + // Get vector of keys EXPECT_EQ(map.keys(), std::vector{"key1"}); - + // Get vector of types - EXPECT_EQ(map.types(), std::vector{TypeID::String}); + EXPECT_EQ(map.types(), std::vector{TypeID::String}); const MetainfoMapImpl constMap; EXPECT_THROW(constMap.at("key2").as(), Exception); @@ -143,7 +145,11 @@ TEST(MetainfoMapImplTest, Conversion) { TEST(MetainfoMapImplTest, toJSON) { MetainfoMapImpl map; - EXPECT_TRUE(map.toJSON().empty()); + + { + json::json j = map; + EXPECT_TRUE(j.empty()); + } ASSERT_TRUE(map.insert("bool", bool(true))); ASSERT_TRUE(map.insert("int32", int(32))); @@ -159,7 +165,7 @@ TEST(MetainfoMapImplTest, toJSON) { ASSERT_TRUE(map.insert("ArrayOfFloat64", (Array{1.0, 2.0, 3.0}))); ASSERT_TRUE(map.insert("ArrayOfString", (Array{"one", "two", "three"}))); - json::json j(map.toJSON()); + json::json j = map; // bool ASSERT_TRUE(j.count("bool")); @@ -238,20 +244,20 @@ TEST(MetainfoMapImplTest, fromJSON) { { MetainfoMapImpl map; json::json j; - EXPECT_NO_THROW(map.fromJSON(j)); + EXPECT_NO_THROW(map = j); EXPECT_TRUE(map.empty()); } #define CHECK_FROM_JSON(type, type_id, value1, value2) \ { \ - MetainfoMapImpl map; \ + MetainfoMapImpl map; \ json::json j; \ j["key1"] = {{"type_id", (int)type_id}, {"value", type(value1)}}; \ j["key2"] = {{"type_id", (int)type_id}, {"value", type(value2)}}; \ j["array"] = {{"type_id", (int)type_id | (int)TypeID::Array}, \ {"value", Array{value1, value2}}}; \ std::string typeStr(TypeUtil::toString(type_id)); \ - ASSERT_NO_THROW(map.fromJSON(j)) << typeStr; \ + ASSERT_NO_THROW(map = j) << typeStr; \ EXPECT_EQ(map.size(), 3) << typeStr; \ ASSERT_TRUE(map.hasKey("key1")) << typeStr; \ ASSERT_TRUE(map.hasKey("key2")) << typeStr; \ @@ -276,7 +282,7 @@ TEST(MetainfoMapImplTest, fromJSON) { MetainfoMapImpl map; json::json ill_formed; ill_formed["key"] = {{"type_id", (int)TypeID::Boolean}}; - EXPECT_THROW(map.fromJSON(ill_formed), Exception); + EXPECT_THROW(map = ill_formed, Exception); } // Missing type id @@ -284,7 +290,7 @@ TEST(MetainfoMapImplTest, fromJSON) { MetainfoMapImpl map; json::json ill_formed; ill_formed["key"] = {{"value", (int)5}}; - EXPECT_THROW(map.fromJSON(ill_formed), Exception); + EXPECT_THROW(map = ill_formed, Exception); } // TypeId / value mismatch I @@ -292,7 +298,7 @@ TEST(MetainfoMapImplTest, fromJSON) { MetainfoMapImpl map; json::json ill_formed; ill_formed["key"] = {{"type_id", (int)TypeID::Boolean}, {"value", double(5)}}; - EXPECT_THROW(map.fromJSON(ill_formed), Exception); + EXPECT_THROW(map = ill_formed, Exception); } // TypeId / value mismatch II @@ -302,7 +308,7 @@ TEST(MetainfoMapImplTest, fromJSON) { ill_formed["key1"] = {{"type_id", (int)TypeID::Boolean}, {"value", true}}; ill_formed["key2"] = {{"type_id", (int)TypeID::Int32}, {"value", int(3)}}; ill_formed["key3"] = {{"type_id", (int)TypeID::Boolean}, {"value", double(5)}}; // Failure - EXPECT_THROW(map.fromJSON(ill_formed), Exception); + EXPECT_THROW(map = ill_formed, Exception); } } @@ -312,10 +318,10 @@ TEST(MetainfoMapImplTest, toString) { MetainfoMapImpl map; map.insert("key1", std::string("value2")); map.insert("key2", double(5.1)); - map.insert("array", std::vector{1,2,3}); - + map.insert("array", std::vector{1, 2, 3}); + ss << map; EXPECT_NE(ss.str().find("key1"), std::string::npos); EXPECT_NE(ss.str().find("key2"), std::string::npos); - EXPECT_NE(ss.str().find("array"), std::string::npos); + EXPECT_NE(ss.str().find("array"), std::string::npos); } diff --git a/test/serialbox/core/UnittestSavepointImpl.cpp b/test/serialbox/core/UnittestSavepointImpl.cpp index 0fed1fe2..0e94c770 100644 --- a/test/serialbox/core/UnittestSavepointImpl.cpp +++ b/test/serialbox/core/UnittestSavepointImpl.cpp @@ -13,6 +13,7 @@ //===------------------------------------------------------------------------------------------===// #include "serialbox/core/SavepointImpl.h" +#include "serialbox/core/SavepointImplSerializer.h" #include #include #include @@ -82,7 +83,7 @@ TEST(SavepointImplTest, Construction) { // Check for deep copy s.metaInfo().insert("newKey", "str"); ASSERT_FALSE(s.metaInfo() == s_to_copy.metaInfo()); - + ASSERT_TRUE(s.metaInfo().hasKey("key2")); EXPECT_EQ(s.metaInfo().at("key2").as(), double(5)); EXPECT_EQ(s.metaInfo().at("key2").as(), s_to_copy.metaInfo().at("key2").as()); @@ -248,7 +249,7 @@ TEST(SavepointImplTest, toJSON) { {"key1", MetainfoValueImpl(std::string("str"))}, {"key2", MetainfoValueImpl(double(5))}}); SavepointImpl s(name, metaInfo); - json::json j = s.toJSON(); + json::json j = s; // Type ASSERT_TRUE(j.count("name")); @@ -292,7 +293,7 @@ TEST(SavepointImplTest, fromJSON) { } )"_json; - SavepointImpl s(j); + SavepointImpl s = j; EXPECT_EQ(s.name(), name); ASSERT_TRUE(s.metaInfo().hasKey("key1")); @@ -312,7 +313,7 @@ TEST(SavepointImplTest, fromJSON) { } )"_json; - SavepointImpl s(j); + SavepointImpl s = j; EXPECT_EQ(s.name(), name); EXPECT_TRUE(s.metaInfo().empty()); } @@ -322,7 +323,8 @@ TEST(SavepointImplTest, fromJSON) { // ----------------------------------------------------------------------------------------------- { auto j = R"({})"_json; - ASSERT_THROW((SavepointImpl(j)), Exception); + SavepointImpl s; + ASSERT_THROW((s = j), Exception); } // ----------------------------------------------------------------------------------------------- @@ -343,7 +345,7 @@ TEST(SavepointImplTest, fromJSON) { } } )"_json; - ASSERT_THROW((SavepointImpl(j)), Exception); + ASSERT_ANY_THROW(SavepointImpl s = j); } } diff --git a/test/serialbox/core/UnittestSavepointVector.cpp b/test/serialbox/core/UnittestSavepointVector.cpp index ae446453..5329aee0 100644 --- a/test/serialbox/core/UnittestSavepointVector.cpp +++ b/test/serialbox/core/UnittestSavepointVector.cpp @@ -13,6 +13,7 @@ //===------------------------------------------------------------------------------------------===// #include "serialbox/core/SavepointVector.h" +#include "serialbox/core/SavepointVectorSerializer.h" #include #include @@ -64,7 +65,7 @@ TEST(SavepointVectorTest, Construction) { ASSERT_EQ(s.insert(savepoint3), 2); EXPECT_TRUE(s.exists(savepoint3)); EXPECT_EQ(s.size(), 3); - + // Clear it s.clear(); EXPECT_EQ(s.size(), 0); @@ -81,8 +82,8 @@ TEST(SavepointVectorTest, Construction) { // Add field u (id = 0) to savepoint1 ASSERT_TRUE(s.addField(savepoint1, FieldID{"u", 0})); - ASSERT_TRUE(s.hasField(savepoint1, "u")); - ASSERT_TRUE(s.hasField(0, "u")); + ASSERT_TRUE(s.hasField(savepoint1, "u")); + ASSERT_TRUE(s.hasField(0, "u")); ASSERT_EQ(s.fieldsOf(savepoint1).size(), 1); EXPECT_EQ(s.fieldsOf(savepoint1).find("u")->second, 0); @@ -98,21 +99,21 @@ TEST(SavepointVectorTest, Construction) { ASSERT_EQ(s.fieldsOf(savepoint1).size(), 1); // Add fields to non-existing savepoint -> Exception - ASSERT_FALSE(s.addField(savepoint3, FieldID{"u", 1})); + ASSERT_FALSE(s.addField(savepoint3, FieldID{"u", 1})); ASSERT_THROW(s.fieldsOf(savepoint3), Exception); EXPECT_THROW(s.getFieldID(savepoint3, "u"), Exception); - + // Add field via index int idx = s.find(savepoint2); ASSERT_NE(idx, -1); ASSERT_TRUE(s.addField(idx, FieldID{"v", 1})); - ASSERT_TRUE(s.hasField(idx, "v")); + ASSERT_TRUE(s.hasField(idx, "v")); EXPECT_EQ(s.getFieldID(idx, "v"), (FieldID{"v", 1})); ASSERT_FALSE(s.addField(idx, FieldID{"v", 1})); ASSERT_FALSE(s.addField(idx, FieldID{"v", 0})); ASSERT_EQ(s.fieldsOf(savepoint2).size(), 1); - + // Look for non-existing savepoint int idxToEnd = s.find(savepoint3); EXPECT_EQ(idxToEnd, -1); @@ -172,7 +173,7 @@ TEST(SavepointVectorTest, Construction) { SavepointVector s1; ASSERT_EQ(s1.insert(savepoint1), 0); ASSERT_EQ(s1.insert(savepoint2), 1); - + SavepointVector s2; s2 = std::move(s1); EXPECT_TRUE(s2.exists(savepoint1)); @@ -216,10 +217,10 @@ TEST(SavepointVectorTest, toJSON) { ASSERT_TRUE(s.addField(savepoint1, FieldID{"v", 0})); ASSERT_TRUE(s.addField(savepoint2, FieldID{"u", 1})); - json::json j = s.toJSON(); + json::json j = s; // Savepoints - ASSERT_TRUE(j.count("savepoints")); + ASSERT_TRUE(j.count("savepoints")); EXPECT_EQ(j["savepoints"][0]["name"], "savepoint"); EXPECT_EQ(j["savepoints"][0]["meta_info"]["key1"]["value"], "s1"); @@ -298,22 +299,22 @@ TEST(SavepointVectorTest, fromJSON) { SavepointVector s(j); EXPECT_EQ(s.savepoints().size(), 3); - + // Check order of savepoints is correct EXPECT_EQ(*s.savepoints()[0], savepoint1); EXPECT_EQ(*s.savepoints()[1], savepoint2); EXPECT_EQ(*s.savepoints()[2], savepoint3); - + // Check fields EXPECT_EQ(s.fieldsOf(savepoint1).size(), 2); EXPECT_EQ(s.fieldsOf(savepoint2).size(), 1); EXPECT_EQ(s.fieldsOf(savepoint3).size(), 0); - + EXPECT_EQ(s.getFieldID(savepoint1, "u"), (FieldID{"u", 0})); EXPECT_EQ(s.getFieldID(savepoint1, "v"), (FieldID{"v", 0})); EXPECT_EQ(s.getFieldID(savepoint2, "u"), (FieldID{"u", 1})); } - + // ----------------------------------------------------------------------------------------------- // Success (empty) // ----------------------------------------------------------------------------------------------- @@ -323,7 +324,7 @@ TEST(SavepointVectorTest, fromJSON) { SavepointVector s(j); EXPECT_TRUE(s.empty()); } - + // ----------------------------------------------------------------------------------------------- // Failure (entry in "fields_per_savepoint" for "different-savepoint" is missing) // ----------------------------------------------------------------------------------------------- @@ -369,23 +370,23 @@ TEST(SavepointVectorTest, fromJSON) { ] } )"_json; - + SavepointVector s; - ASSERT_THROW(s.fromJSON(j), Exception); + ASSERT_THROW(s = j, Exception); } } TEST(SavepointVectorTest, toString) { SavepointImpl savepoint1("savepoint"); ASSERT_NO_THROW(savepoint1.addMetainfo("key1", "s1")); - + std::stringstream ss; SavepointVector s; ASSERT_NE(s.insert(savepoint1), -1); ASSERT_TRUE(s.addField(savepoint1, FieldID{"u", 0})); ss << s; - EXPECT_TRUE(boost::algorithm::starts_with(ss.str(), "SavepointVector")); + EXPECT_TRUE(boost::algorithm::starts_with(ss.str(), "SavepointVector")); EXPECT_NE(ss.str().find("savepoint"), std::string::npos); EXPECT_NE(ss.str().find("key1"), std::string::npos); } diff --git a/test/serialbox/core/UnittestSerializerImpl.cpp b/test/serialbox/core/UnittestSerializerImpl.cpp index 5f38989d..989c2a9c 100644 --- a/test/serialbox/core/UnittestSerializerImpl.cpp +++ b/test/serialbox/core/UnittestSerializerImpl.cpp @@ -12,9 +12,10 @@ /// //===------------------------------------------------------------------------------------------===// +#include "serialbox/core/Json.h" +#include "serialbox/core/SerializerImpl.h" #include "utility/SerializerTestBase.h" #include "utility/Storage.h" -#include "serialbox/core/SerializerImpl.h" #include using namespace serialbox; @@ -65,8 +66,7 @@ TEST_F(SerializerImplUtilityTest, Construction) { { // MetaData-prefix.json does not exist -> Exception - filesystem::remove((directory->path() / "dir-is-created-from-write") / - "MetaData-Field.json"); + filesystem::remove((directory->path() / "dir-is-created-from-write") / "MetaData-Field.json"); ASSERT_THROW(SerializerImpl(OpenModeKind::Read, (directory->path() / "dir-is-created-from-write").string(), "Field", "Binary"), diff --git a/test/utility/CMakeLists.txt b/test/utility/CMakeLists.txt index 18e1d74d..1340da3e 100644 --- a/test/utility/CMakeLists.txt +++ b/test/utility/CMakeLists.txt @@ -1,39 +1,39 @@ -##===------------------------------------------------------------------------------*- CMake -*-===## -## -## S E R I A L B O X -## -## This file is distributed under terms of BSD license. -## See LICENSE.txt for more information. -## -##===------------------------------------------------------------------------------------------===## - -cmake_minimum_required(VERSION 3.12) - -set(SOURCES - BenchmarkEnvironment.h - BenchmarkEnvironment.cpp - CInterfaceTestBase.h - CInterfaceTestBase.cpp - FileUtility.h - GridTools.h - Storage.h - STELLA.h - Serialbox.h - SerializerTestBase.h - UnittestEnvironment.h - UnittestEnvironment.cpp -) - -add_library(SerialboxUnittestUtilityObjects OBJECT ${SOURCES}) -target_include_directories(SerialboxUnittestUtilityObjects PUBLIC ${CMAKE_SOURCE_DIR}/test) -target_link_libraries(SerialboxUnittestUtilityObjects PUBLIC Boost::boost) -target_link_libraries(SerialboxUnittestUtilityObjects PUBLIC gtest_main) -target_link_libraries(SerialboxUnittestUtilityObjects PUBLIC SerialboxFilesytemTarget) -target_link_libraries(SerialboxUnittestUtilityObjects PUBLIC SerialboxStatic) -if(GRIDTOOLS_FOUND) - target_link_libraries(SerialboxUnittestUtilityObjects PUBLIC GridTools_TARGET) -endif() - -add_library(SerialboxUnittestUtilityStatic STATIC $) -set_target_properties(SerialboxUnittestUtilityStatic PROPERTIES VERSION ${Serialbox_VERSION_STRING}) -target_link_libraries(SerialboxUnittestUtilityStatic PUBLIC SerialboxUnittestUtilityObjects) +##===------------------------------------------------------------------------------*- CMake -*-===## +## +## S E R I A L B O X +## +## This file is distributed under terms of BSD license. +## See LICENSE.txt for more information. +## +##===------------------------------------------------------------------------------------------===## + +cmake_minimum_required(VERSION 3.12) + +set(SOURCES + BenchmarkEnvironment.h + BenchmarkEnvironment.cpp + CInterfaceTestBase.h + CInterfaceTestBase.cpp + FileUtility.h + GridTools.h + Storage.h + STELLA.h + Serialbox.h + SerializerTestBase.h + UnittestEnvironment.h + UnittestEnvironment.cpp +) + +add_library(SerialboxUnittestUtilityObjects OBJECT ${SOURCES}) +target_include_directories(SerialboxUnittestUtilityObjects PUBLIC ${CMAKE_SOURCE_DIR}/test) +target_link_libraries(SerialboxUnittestUtilityObjects PUBLIC Boost::boost) +target_link_libraries(SerialboxUnittestUtilityObjects PUBLIC gtest_main) +target_link_libraries(SerialboxUnittestUtilityObjects PUBLIC SerialboxFilesytemTarget) +target_link_libraries(SerialboxUnittestUtilityObjects PUBLIC SerialboxStatic) +if(GRIDTOOLS_FOUND) + target_link_libraries(SerialboxUnittestUtilityObjects PUBLIC GridTools_TARGET) +endif() + +add_library(SerialboxUnittestUtilityStatic STATIC $) +set_target_properties(SerialboxUnittestUtilityStatic PROPERTIES VERSION ${Serialbox_VERSION_STRING}) +target_link_libraries(SerialboxUnittestUtilityStatic PUBLIC SerialboxUnittestUtilityObjects) diff --git a/tools/cscs-scripts/env_daint.sh b/tools/cscs-scripts/env_daint.sh index 2a759904..e77ed406 100644 --- a/tools/cscs-scripts/env_daint.sh +++ b/tools/cscs-scripts/env_daint.sh @@ -86,7 +86,6 @@ elif [ "$FC_COMPILER" = "ifort" ]; then module swap PrgEnv-cray PrgEnv-intel module load gcc/7.3.0 - elif [ "$FC_COMPILER" = "pgfortran18.10" ]; then module use /project/c14/data-eniac/modulefiles @@ -94,7 +93,6 @@ elif [ "$FC_COMPILER" = "pgfortran18.10" ]; then module load eniac/pgi-18.10 module load gcc FC_COMPILER="pgfortran" - else module swap PrgEnv-cray PrgEnv-gnu # module load cray-netcdf