Skip to content

Commit 9ec90b6

Browse files
franzpoeschelax3l
andauthored
TOML Backend (#1436)
* TOML backend * Add documentation for TOML * Fixes for long double and long integer types * Only run TOML tests if TOML is available TOML is not shown as available on NVIDIA compilers * Deactivate long double entirely for JSON/TOML * CI fix: unused variable * Hide/deactivate/warn Toml backend on nvcc compilers ToruNiina/toml11#205 * Usage notes for JSON / TOML * Update comment in test/python/unittest/API/APITest.py Co-authored-by: Axel Huebl <[email protected]> * Update documentation text Co-authored-by: Axel Huebl <[email protected]> --------- Co-authored-by: Axel Huebl <[email protected]>
1 parent 99daca7 commit 9ec90b6

File tree

15 files changed

+349
-103
lines changed

15 files changed

+349
-103
lines changed

docs/source/backends/json.rst

Lines changed: 37 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,19 @@
11
.. _backends-json:
22

3-
JSON
4-
====
3+
JSON/TOML
4+
=========
55

6-
openPMD supports writing to and reading from JSON files.
7-
The JSON backend is always available.
6+
openPMD supports writing to and reading from JSON and TOML files.
7+
The JSON and TOML backends are always available.
8+
9+
.. note::
10+
11+
Both the JSON and the TOML backends are not intended for large-scale data I/O.
12+
13+
The JSON backend is mainly intended for prototyping and learning, or similar workflows where setting up a large IO backend such as HDF5 or ADIOS2 is perceived as obstructive. It can also be used for small datasets that need to be stored in text format rather than binary.
14+
15+
The TOML backend is intended for exchanging the *structure* of a data series without its "heavy" data fields.
16+
For instance, one can easily create and exchange human-readable, machine-actionable data configurations for experiments and simulations.
817

918

1019
JSON File Format
@@ -43,9 +52,17 @@ Every such attribute is itself a JSON object with two keys:
4352
* ``datatype``: A string describing the type of the value.
4453
* ``value``: The actual value of type ``datatype``.
4554

55+
TOML File Format
56+
----------------
57+
58+
A TOML file uses the file ending ``.toml``. The TOML backend is chosen by creating a ``Series`` object with a filename that has this file ending.
59+
60+
The TOML backend internally works with JSON datasets and converts to/from TOML during I/O.
61+
As a result, data layout and usage are equivalent to the JSON backend.
62+
4663

47-
Restrictions
48-
------------
64+
JSON Restrictions
65+
-----------------
4966

5067
For creation of JSON serializations (i.e. writing), the restrictions of the JSON backend are
5168
equivalent to those of the `JSON library by Niels Lohmann <https://github.com/nlohmann/json>`_
@@ -77,6 +94,20 @@ The (keys) names ``"attributes"``, ``"data"`` and ``"datatype"`` are reserved an
7794

7895
A parallel (i.e. MPI) implementation is *not* available.
7996

97+
TOML Restrictions
98+
-----------------
99+
100+
Note that the JSON datatype-specific restrictions do not automatically hold for TOML, as those affect only the representation on disk, not the internal representation.
101+
102+
TOML supports most numeric types, with the support for long double and long integer types being platform-defined.
103+
Special floating point values such as NaN are also support.
104+
105+
TOML does not support null values.
106+
107+
The (keys) names ``"attributes"``, ``"data"`` and ``"datatype"`` are reserved and must not be used for base/mesh/particles path, records and their components.
108+
109+
A parallel (i.e. MPI) implementation is *not* available.
110+
80111

81112
Example
82113
-------

include/openPMD/IO/Format.hpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ enum class Format
3535
ADIOS2_SST,
3636
ADIOS2_SSC,
3737
JSON,
38+
TOML,
3839
DUMMY
3940
};
4041

include/openPMD/IO/JSON/JSONIOHandler.hpp

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,12 @@ namespace openPMD
2929
class JSONIOHandler : public AbstractIOHandler
3030
{
3131
public:
32-
JSONIOHandler(std::string path, Access at);
32+
JSONIOHandler(
33+
std::string path,
34+
Access at,
35+
openPMD::json::TracingJSON config,
36+
JSONIOHandlerImpl::FileFormat,
37+
std::string originalExtension);
3338

3439
~JSONIOHandler() override;
3540

include/openPMD/IO/JSON/JSONIOHandlerImpl.hpp

Lines changed: 33 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,10 @@
2626
#include "openPMD/IO/Access.hpp"
2727
#include "openPMD/IO/JSON/JSONFilePosition.hpp"
2828
#include "openPMD/auxiliary/Filesystem.hpp"
29+
#include "openPMD/auxiliary/JSON_internal.hpp"
2930
#include "openPMD/config.hpp"
3031

32+
#include <istream>
3133
#include <nlohmann/json.hpp>
3234

3335
#include <complex>
@@ -153,7 +155,17 @@ class JSONIOHandlerImpl : public AbstractIOHandlerImpl
153155
using json = nlohmann::json;
154156

155157
public:
156-
explicit JSONIOHandlerImpl(AbstractIOHandler *);
158+
enum class FileFormat
159+
{
160+
Json,
161+
Toml
162+
};
163+
164+
explicit JSONIOHandlerImpl(
165+
AbstractIOHandler *,
166+
openPMD::json::TracingJSON config,
167+
FileFormat,
168+
std::string originalExtension);
157169

158170
~JSONIOHandlerImpl() override;
159171

@@ -229,15 +241,25 @@ class JSONIOHandlerImpl : public AbstractIOHandlerImpl
229241
// files that have logically, but not physically been written to
230242
std::unordered_set<File> m_dirty;
231243

244+
/*
245+
* Is set by constructor.
246+
*/
247+
FileFormat m_fileFormat{};
248+
249+
std::string m_originalExtension;
250+
232251
// HELPER FUNCTIONS
233252

234-
// will use the IOHandler to retrieve the correct directory
235-
// shared pointer to circumvent the fact that c++ pre 17 does
236-
// not enforce (only allow) copy elision in return statements
237-
std::shared_ptr<FILEHANDLE> getFilehandle(
238-
File,
239-
Access access); //, Access
240-
// m_frontendAccess=this->m_handler->m_frontendAccess);
253+
// will use the IOHandler to retrieve the correct directory.
254+
// first tuple element will be the underlying opened file handle.
255+
// if Access is read mode, then the second tuple element will be the istream
256+
// casted to precision std::numeric_limits<double>::digits10 + 1, else null.
257+
// if Access is write mode, then the second tuple element will be the
258+
// ostream casted to precision std::numeric_limits<double>::digits10 + 1,
259+
// else null. first tuple element needs to be a pointer, since the casted
260+
// streams are references only.
261+
std::tuple<std::unique_ptr<FILEHANDLE>, std::istream *, std::ostream *>
262+
getFilehandle(File, Access access);
241263

242264
// full operating system path of the given file
243265
std::string fullPath(File);
@@ -272,15 +294,13 @@ class JSONIOHandlerImpl : public AbstractIOHandlerImpl
272294
// essentially: m_i = \prod_{j=0}^{i-1} extent_j
273295
static Extent getMultiplicators(Extent const &extent);
274296

275-
static nlohmann::json initializeNDArray(Extent const &extent);
276-
277297
static Extent getExtent(nlohmann::json &j);
278298

279299
// remove single '/' in the beginning and end of a string
280300
static std::string removeSlashes(std::string);
281301

282302
template <typename KeyT>
283-
static bool hasKey(nlohmann::json &, KeyT &&key);
303+
static bool hasKey(nlohmann::json const &, KeyT &&key);
284304

285305
// make sure that the given path exists in proper form in
286306
// the passed json value
@@ -366,7 +386,8 @@ class JSONIOHandlerImpl : public AbstractIOHandlerImpl
366386
struct AttributeReader
367387
{
368388
template <typename T>
369-
static void call(nlohmann::json &, Parameter<Operation::READ_ATT> &);
389+
static void
390+
call(nlohmann::json const &, Parameter<Operation::READ_ATT> &);
370391

371392
static constexpr char const *errorMsg = "JSON: writeAttribute";
372393
};

include/openPMD/auxiliary/TypeTraits.hpp

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
#include "openPMD/auxiliary/UniquePtr.hpp"
2525

2626
#include <array>
27+
#include <complex>
2728
#include <cstddef> // size_t
2829
#include <memory>
2930
#include <vector>
@@ -56,6 +57,18 @@ namespace detail
5657
static constexpr bool value = true;
5758
};
5859

60+
template <typename>
61+
struct IsComplex
62+
{
63+
static constexpr bool value = false;
64+
};
65+
66+
template <typename T>
67+
struct IsComplex<std::complex<T>>
68+
{
69+
static constexpr bool value = true;
70+
};
71+
5972
template <typename T>
6073
struct IsPointer
6174
{
@@ -114,6 +127,9 @@ using IsPointer_t = typename detail::IsPointer<T>::type;
114127
template <typename T>
115128
inline constexpr bool IsContiguousContainer_v = IsVector_v<T> || IsArray_v<T>;
116129

130+
template <typename T>
131+
inline constexpr bool IsComplex_v = detail::IsComplex<T>::value;
132+
117133
namespace
118134
{
119135
// see https://en.cppreference.com/w/cpp/language/if

src/Format.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,8 @@ Format determineFormat(std::string const &filename)
4343
return Format::ADIOS2_SSC;
4444
if (auxiliary::ends_with(filename, ".json"))
4545
return Format::JSON;
46+
if (auxiliary::ends_with(filename, ".toml"))
47+
return Format::TOML;
4648

4749
// Format might still be specified via JSON
4850
return Format::DUMMY;
@@ -66,6 +68,8 @@ std::string suffix(Format f)
6668
return ".ssc";
6769
case Format::JSON:
6870
return ".json";
71+
case Format::TOML:
72+
return ".toml";
6973
default:
7074
return "";
7175
}

src/IO/AbstractIOHandlerHelper.cpp

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -194,7 +194,20 @@ std::unique_ptr<AbstractIOHandler> createIOHandler<json::TracingJSON>(
194194
std::move(originalExtension));
195195
case Format::JSON:
196196
return constructIOHandler<JSONIOHandler, openPMD_HAVE_JSON>(
197-
"JSON", path, access);
197+
"JSON",
198+
path,
199+
access,
200+
std::move(options),
201+
JSONIOHandlerImpl::FileFormat::Json,
202+
std::move(originalExtension));
203+
case Format::TOML:
204+
return constructIOHandler<JSONIOHandler, openPMD_HAVE_JSON>(
205+
"JSON",
206+
path,
207+
access,
208+
std::move(options),
209+
JSONIOHandlerImpl::FileFormat::Toml,
210+
std::move(originalExtension));
198211
default:
199212
throw std::runtime_error(
200213
"Unknown file format! Did you specify a file ending? Specified "

src/IO/JSON/JSONIOHandler.cpp

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,14 @@ namespace openPMD
2525
{
2626
JSONIOHandler::~JSONIOHandler() = default;
2727

28-
JSONIOHandler::JSONIOHandler(std::string path, Access at)
29-
: AbstractIOHandler{path, at}, m_impl{JSONIOHandlerImpl{this}}
28+
JSONIOHandler::JSONIOHandler(
29+
std::string path,
30+
Access at,
31+
openPMD::json::TracingJSON jsonCfg,
32+
JSONIOHandlerImpl::FileFormat format,
33+
std::string originalExtension)
34+
: AbstractIOHandler{path, at}
35+
, m_impl{this, std::move(jsonCfg), format, std::move(originalExtension)}
3036
{}
3137

3238
std::future<void> JSONIOHandler::flush(internal::ParsedFlushParams &)

0 commit comments

Comments
 (0)