From 20d070f09ad6360760a1ab00d43fecc6cbbbcd61 Mon Sep 17 00:00:00 2001 From: Willem Deconinck Date: Mon, 6 Nov 2023 12:03:07 +0100 Subject: [PATCH] atlas_io is an adaptor library when eckit_codec is available --- atlas_io/CMakeLists.txt | 18 +++- atlas_io/eckit_codec_adaptor/CMakeLists.txt | 1 + .../eckit_codec_adaptor/src/CMakeLists.txt | 2 + .../src/atlas_io/CMakeLists.txt | 19 ++++ .../eckit_codec_adaptor/src/atlas_io/Trace.cc | 43 ++++++++ .../eckit_codec_adaptor/src/atlas_io/Trace.h | 77 +++++++++++++ .../src/atlas_io/atlas-io.h | 99 +++++++++++++++++ .../src/atlas_io/detail/BlackMagic.h | 101 ++++++++++++++++++ atlas_io/tests/TestEnvironment.h | 2 +- atlas_io/tests/test_io_stream.cc | 4 +- 10 files changed, 360 insertions(+), 6 deletions(-) create mode 100644 atlas_io/eckit_codec_adaptor/CMakeLists.txt create mode 100644 atlas_io/eckit_codec_adaptor/src/CMakeLists.txt create mode 100644 atlas_io/eckit_codec_adaptor/src/atlas_io/CMakeLists.txt create mode 100644 atlas_io/eckit_codec_adaptor/src/atlas_io/Trace.cc create mode 100644 atlas_io/eckit_codec_adaptor/src/atlas_io/Trace.h create mode 100644 atlas_io/eckit_codec_adaptor/src/atlas_io/atlas-io.h create mode 100644 atlas_io/eckit_codec_adaptor/src/atlas_io/detail/BlackMagic.h diff --git a/atlas_io/CMakeLists.txt b/atlas_io/CMakeLists.txt index 26f549808..0df4f1fcb 100644 --- a/atlas_io/CMakeLists.txt +++ b/atlas_io/CMakeLists.txt @@ -28,6 +28,16 @@ ecbuild_debug( " eckit_FEATURES : [${eckit_FEATURES}]" ) ################################################################################ # Features that can be enabled / disabled with -DENABLE_ +set( eckit_HAVE_ECKIT_CODEC 0 ) +if( TARGET eckit_codec ) + set( eckit_HAVE_ECKIT_CODEC 1 ) +endif() + +ecbuild_add_option( FEATURE ECKIT_CODEC + DEFAULT ON + DESCRIPTION "Use eckit::codec with adaptor" + CONDITION eckit_HAVE_ECKIT_CODEC ) + ################################################################################ # sources @@ -47,8 +57,12 @@ else() set( ATLAS_IO_LITTLE_ENDIAN 1 ) endif() - -add_subdirectory( src ) +if( HAVE_ECKIT_CODEC ) + ecbuild_info("atlas_io is configured to be an adaptor library which delegates calls to eckit_codec") + add_subdirectory(eckit_codec_adaptor) +else() + add_subdirectory( src ) +endif() add_subdirectory( tests ) ################################################################################ diff --git a/atlas_io/eckit_codec_adaptor/CMakeLists.txt b/atlas_io/eckit_codec_adaptor/CMakeLists.txt new file mode 100644 index 000000000..febd4f0ab --- /dev/null +++ b/atlas_io/eckit_codec_adaptor/CMakeLists.txt @@ -0,0 +1 @@ +add_subdirectory(src) diff --git a/atlas_io/eckit_codec_adaptor/src/CMakeLists.txt b/atlas_io/eckit_codec_adaptor/src/CMakeLists.txt new file mode 100644 index 000000000..e91bc52fd --- /dev/null +++ b/atlas_io/eckit_codec_adaptor/src/CMakeLists.txt @@ -0,0 +1,2 @@ +add_subdirectory(atlas_io) + diff --git a/atlas_io/eckit_codec_adaptor/src/atlas_io/CMakeLists.txt b/atlas_io/eckit_codec_adaptor/src/atlas_io/CMakeLists.txt new file mode 100644 index 000000000..1794974b1 --- /dev/null +++ b/atlas_io/eckit_codec_adaptor/src/atlas_io/CMakeLists.txt @@ -0,0 +1,19 @@ + +ecbuild_add_library( TARGET atlas_io + + INSTALL_HEADERS ALL + HEADER_DESTINATION include/atlas_io + PUBLIC_LIBS eckit_codec + PUBLIC_INCLUDES + $ + + SOURCES + atlas-io.h + Trace.cc + Trace.h + detail/BlackMagic.h + LINKER_LANGUAGE CXX +) + +target_compile_features( atlas_io PUBLIC cxx_std_17 ) + diff --git a/atlas_io/eckit_codec_adaptor/src/atlas_io/Trace.cc b/atlas_io/eckit_codec_adaptor/src/atlas_io/Trace.cc new file mode 100644 index 000000000..5e52b7dc9 --- /dev/null +++ b/atlas_io/eckit_codec_adaptor/src/atlas_io/Trace.cc @@ -0,0 +1,43 @@ +/* + * (C) Copyright 2020 ECMWF. + * + * This software is licensed under the terms of the Apache Licence Version 2.0 + * which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. + * In applying this licence, ECMWF does not waive the privileges and immunities + * granted to it by virtue of its status as an intergovernmental organisation + * nor does it submit to any jurisdiction. + */ + +#include "Trace.h" + +#include "eckit/log/CodeLocation.h" + +namespace atlas { +namespace io { + +atlas::io::Trace::Trace(const eckit::CodeLocation& loc) { + for (size_t id = 0; id < TraceHookRegistry::size(); ++id) { + if (TraceHookRegistry::enabled(id)) { + hooks_.emplace_back(TraceHookRegistry::hook(id)(loc, loc.func())); + } + } +} + +Trace::Trace(const eckit::CodeLocation& loc, const std::string& title) { + for (size_t id = 0; id < TraceHookRegistry::size(); ++id) { + if (TraceHookRegistry::enabled(id)) { + hooks_.emplace_back(TraceHookRegistry::hook(id)(loc, title)); + } + } +} + +Trace::Trace(const eckit::CodeLocation& loc, const std::string& title, const Labels& labels) { + for (size_t id = 0; id < TraceHookRegistry::size(); ++id) { + if (TraceHookRegistry::enabled(id)) { + hooks_.emplace_back(TraceHookRegistry::hook(id)(loc, title)); + } + } +} + +} // namespace io +} // namespace atlas diff --git a/atlas_io/eckit_codec_adaptor/src/atlas_io/Trace.h b/atlas_io/eckit_codec_adaptor/src/atlas_io/Trace.h new file mode 100644 index 000000000..43da3f526 --- /dev/null +++ b/atlas_io/eckit_codec_adaptor/src/atlas_io/Trace.h @@ -0,0 +1,77 @@ +/* + * (C) Copyright 2020 ECMWF. + * + * This software is licensed under the terms of the Apache Licence Version 2.0 + * which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. + * In applying this licence, ECMWF does not waive the privileges and immunities + * granted to it by virtue of its status as an intergovernmental organisation + * nor does it submit to any jurisdiction. + */ + +#pragma once + + +#include +#include +#include +#include +#include + +namespace eckit { +class CodeLocation; +} + +namespace atlas { +namespace io { + +struct TraceHook { + TraceHook() = default; + virtual ~TraceHook() = default; +}; + +struct TraceHookRegistry { + using TraceHookBuilder = std::function(const eckit::CodeLocation&, const std::string&)>; + std::vector hooks; + std::vector enabled_; + static TraceHookRegistry& instance() { + static TraceHookRegistry instance; + return instance; + } + static size_t add(TraceHookBuilder&& hook) { + instance().hooks.emplace_back(hook); + instance().enabled_.emplace_back(true); + return instance().hooks.size() - 1; + } + static size_t add(const TraceHookBuilder& hook) { + instance().hooks.emplace_back(hook); + instance().enabled_.emplace_back(true); + return instance().hooks.size() - 1; + } + static void enable(size_t id) { instance().enabled_[id] = true; } + static void disable(size_t id) { instance().enabled_[id] = false; } + static bool enabled(size_t id) { return instance().enabled_[id]; } + static size_t size() { return instance().hooks.size(); } + static TraceHookBuilder& hook(size_t id) { return instance().hooks[id]; } + static size_t invalidId() { return std::numeric_limits::max(); } + +private: + TraceHookRegistry() = default; +}; + +struct Trace { + using Labels = std::vector; + Trace(const eckit::CodeLocation& loc); + Trace(const eckit::CodeLocation& loc, const std::string& title); + Trace(const eckit::CodeLocation& loc, const std::string& title, const Labels& labels); + +private: + std::vector> hooks_; +}; + +} // namespace io +} // namespace atlas + +#include "atlas_io/detail/BlackMagic.h" + +#define ATLAS_IO_TRACE(...) __ATLAS_IO_TYPE(::atlas::io::Trace, Here() __ATLAS_IO_COMMA_ARGS(__VA_ARGS__)) +#define ATLAS_IO_TRACE_SCOPE(...) __ATLAS_IO_TYPE_SCOPE(::atlas::io::Trace, Here() __ATLAS_IO_COMMA_ARGS(__VA_ARGS__)) diff --git a/atlas_io/eckit_codec_adaptor/src/atlas_io/atlas-io.h b/atlas_io/eckit_codec_adaptor/src/atlas_io/atlas-io.h new file mode 100644 index 000000000..7c5f49d20 --- /dev/null +++ b/atlas_io/eckit_codec_adaptor/src/atlas_io/atlas-io.h @@ -0,0 +1,99 @@ +/* + * (C) Copyright 2023- ECMWF. + * + * This software is licensed under the terms of the Apache Licence Version 2.0 + * which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. + * In applying this licence, ECMWF does not waive the privileges and immunities + * granted to it by virtue of its status as an intergovernmental organisation + * nor does it submit to any jurisdiction. + */ + +#pragma once + +#include "eckit/codec/codec.h" + +namespace atlas::io { + + // Encoding/Decoding + using Metadata = ::eckit::codec::Metadata; + using DataType = ::eckit::codec::DataType; + using Data = ::eckit::codec::Data; + using Encoder = ::eckit::codec::Encoder; + using Decoder = ::eckit::codec::Decoder; + + // Record + using Record = ::eckit::codec::Record; + using RecordWriter = ::eckit::codec::RecordWriter; + using RecordPrinter = ::eckit::codec::RecordPrinter; + using RecordItemReader = ::eckit::codec::RecordItemReader; + using RecordReader = ::eckit::codec::RecordReader; + + // I/O + using Session = ::eckit::codec::Session; + using Mode = ::eckit::codec::Mode; + using Stream = ::eckit::codec::Stream; + using FileStream = ::eckit::codec::FileStream; + using InputFileStream = ::eckit::codec::InputFileStream; + using OutputFileStream = ::eckit::codec::OutputFileStream; + + // Array + using ArrayReference = ::eckit::codec::ArrayReference; + using ArrayMetadata = ::eckit::codec::ArrayMetadata; + using ArrayShape = ::eckit::codec::ArrayShape; + + // Exceptions + using Exception = ::eckit::codec::Exception; + using NotEncodable = ::eckit::codec::NotEncodable; + using NotDecodable = ::eckit::codec::NotDecodable; + using InvalidRecord = ::eckit::codec::InvalidRecord; + using DataCorruption = ::eckit::codec::DataCorruption; + using WriteError = ::eckit::codec::WriteError; + + // Type traits + template + static constexpr bool is_interpretable() { + return ::eckit::codec::is_interpretable(); + } + template + static constexpr bool is_encodable() { + return ::eckit::codec::is_encodable(); + } + template + static constexpr bool is_decodable() { + return ::eckit::codec::is_decodable(); + } + template + static constexpr bool can_encode_metadata() { + return ::eckit::codec::can_encode_metadata(); + } + template + static constexpr bool can_encode_data() { + return ::eckit::codec::can_encode_metadata(); + } + + namespace tag { + using disable_static_assert = ::eckit::codec::tag::disable_static_assert; + using enable_static_assert = ::eckit::codec::tag::enable_static_assert; + } + + // Functions + using ::eckit::codec::ref; + using ::eckit::codec::copy; + using ::eckit::codec::encode; + using ::eckit::codec::decode; + using ::eckit::codec::interprete; + using ::eckit::codec::link; + using ::eckit::codec::make_datatype; + // template + // using make_datatype = eckit::codec::make_datatype; + + namespace defaults { + using ::eckit::codec::defaults::compression_algorithm; + using ::eckit::codec::defaults::checksum_algorithm; + using ::eckit::codec::defaults::checksum_read; + using ::eckit::codec::defaults::checksum_write; + } +} + +#define ATLAS_IO_ASSERT(X) ASSERT(X) +#define ATLAS_IO_ASSERT_MSG(X, M) ASSERT_MSG(X, M) diff --git a/atlas_io/eckit_codec_adaptor/src/atlas_io/detail/BlackMagic.h b/atlas_io/eckit_codec_adaptor/src/atlas_io/detail/BlackMagic.h new file mode 100644 index 000000000..a889c5e19 --- /dev/null +++ b/atlas_io/eckit_codec_adaptor/src/atlas_io/detail/BlackMagic.h @@ -0,0 +1,101 @@ +/* + * (C) Copyright 2013 ECMWF. + * + * This software is licensed under the terms of the Apache Licence Version 2.0 + * which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. + * In applying this licence, ECMWF does not waive the privileges and immunities + * granted to it by virtue of its status as an intergovernmental organisation + * nor does it submit to any jurisdiction. + */ + +#pragma once + +// This file contains preprocessor black magic. It contains macros that +// can return the number of arguments passed + +//----------------------------------------------------------------------------------------------------------- +// Public + +/// Returns the number of passed arguments +#define __ATLAS_IO_NARG(...) + +/// Splice a and b together +#define __ATLAS_IO_SPLICE(a, b) + +#define __ATLAS_IO_STRINGIFY(a) a + +#define __ATLAS_IO_TYPE(Type, ...) +#define __ATLAS_IO_TYPE_SCOPE(Type, ...) + +//----------------------------------------------------------------------------------------------------------- +// Details + +// Undefine these, to be redefined further down. +#undef __ATLAS_IO_NARG +#undef __ATLAS_IO_SPLICE +#undef __ATLAS_IO_TYPE +#undef __ATLAS_IO_TYPE_SCOPE + +#define __ATLAS_IO_REVERSE 5, 4, 3, 2, 1, 0 +#define __ATLAS_IO_ARGN(_1, _2, _3, _4, _5, N, ...) N +#define __ATLAS_IO_NARG__(dummy, ...) __ATLAS_IO_ARGN(__VA_ARGS__) +#define __ATLAS_IO_NARG_(...) __ATLAS_IO_NARG__(dummy, ##__VA_ARGS__, __ATLAS_IO_REVERSE) +#define __ATLAS_IO_SPLICE(a, b) __ATLAS_IO_SPLICE_1(a, b) +#define __ATLAS_IO_SPLICE_1(a, b) __ATLAS_IO_SPLICE_2(a, b) +#define __ATLAS_IO_SPLICE_2(a, b) a##b + +#define __ATLAS_IO_ARG16(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, ...) _15 +#define __ATLAS_IO_HAS_COMMA(...) __ATLAS_IO_ARG16(__VA_ARGS__, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0) +#define __ATLAS_IO_TRIGGER_PARENTHESIS(...) , +#define __ATLAS_IO_ISEMPTY(...) \ + __ATLAS_IO_ISEMPTY_(/* test if there is just one argument, eventually an empty \ + one */ \ + __ATLAS_IO_HAS_COMMA(__VA_ARGS__), /* test if \ + _TRIGGER_PARENTHESIS_ \ + together with the \ + argument adds a comma */ \ + __ATLAS_IO_HAS_COMMA( \ + __ATLAS_IO_TRIGGER_PARENTHESIS __VA_ARGS__), /* test if the argument together with \ + a parenthesis adds a comma */ \ + __ATLAS_IO_HAS_COMMA(__VA_ARGS__(/*empty*/)), /* test if placing it between \ + __ATLAS_IO_TRIGGER_PARENTHESIS and the \ + parenthesis adds a comma */ \ + __ATLAS_IO_HAS_COMMA(__ATLAS_IO_TRIGGER_PARENTHESIS __VA_ARGS__(/*empty*/))) + +#define __ATLAS_IO_PASTE5(_0, _1, _2, _3, _4) _0##_1##_2##_3##_4 +#define __ATLAS_IO_ISEMPTY_(_0, _1, _2, _3) \ + __ATLAS_IO_HAS_COMMA(__ATLAS_IO_PASTE5(__ATLAS_IO_IS_EMPTY_CASE_, _0, _1, _2, _3)) +#define __ATLAS_IO_IS_EMPTY_CASE_0001 , + +#define __ATLAS_IO_NARG(...) __ATLAS_IO_SPLICE(__ATLAS_IO_CALL_NARG_, __ATLAS_IO_ISEMPTY(__VA_ARGS__))(__VA_ARGS__) +#define __ATLAS_IO_CALL_NARG_1(...) 0 +#define __ATLAS_IO_CALL_NARG_0 __ATLAS_IO_NARG_ + +#define __ATLAS_IO_COMMA_ARGS(...) \ + __ATLAS_IO_SPLICE(__ATLAS_IO_COMMA_ARGS_, __ATLAS_IO_ISEMPTY(__VA_ARGS__))(__VA_ARGS__) +#define __ATLAS_IO_COMMA_ARGS_1(...) +#define __ATLAS_IO_COMMA_ARGS_0(...) , __VA_ARGS__ + +#define __ATLAS_IO_ARGS_OR_DUMMY(...) \ + __ATLAS_IO_SPLICE(__ATLAS_IO_ARGS_OR_DUMMY_, __ATLAS_IO_ISEMPTY(__VA_ARGS__)) \ + (__VA_ARGS__) +#define __ATLAS_IO_ARGS_OR_DUMMY_0(...) __VA_ARGS__ +#define __ATLAS_IO_ARGS_OR_DUMMY_1(...) 0 + +#define __ATLAS_IO_TYPE(Type, ...) \ + __ATLAS_IO_SPLICE(__ATLAS_IO_TYPE_, __ATLAS_IO_ISEMPTY(__VA_ARGS__)) \ + (Type, __ATLAS_IO_ARGS_OR_DUMMY(__VA_ARGS__)) +#define __ATLAS_IO_TYPE_1(Type, dummy) Type __ATLAS_IO_SPLICE(__variable_, __LINE__) +#define __ATLAS_IO_TYPE_0(Type, ...) Type __ATLAS_IO_SPLICE(__variable_, __LINE__)(__VA_ARGS__) + +#define __ATLAS_IO_TYPE_SCOPE(Type, ...) \ + __ATLAS_IO_SPLICE(__ATLAS_IO_TYPE_SCOPE_, __ATLAS_IO_ISEMPTY(__VA_ARGS__)) \ + (Type, __ATLAS_IO_ARGS_OR_DUMMY(__VA_ARGS__)) +#define __ATLAS_IO_TYPE_SCOPE_1(Type, ...) \ + for (bool __ATLAS_IO_SPLICE(__done_, __LINE__) = false; __ATLAS_IO_SPLICE(__done_, __LINE__) != true;) \ + for (Type __ATLAS_IO_SPLICE(__variable_, __LINE__); __ATLAS_IO_SPLICE(__done_, __LINE__) != true; \ + __ATLAS_IO_SPLICE(__done_, __LINE__) = true) +#define __ATLAS_IO_TYPE_SCOPE_0(Type, ...) \ + for (bool __ATLAS_IO_SPLICE(__done_, __LINE__) = false; __ATLAS_IO_SPLICE(__done_, __LINE__) != true;) \ + for (Type __ATLAS_IO_SPLICE(__variable_, __LINE__)(__VA_ARGS__); __ATLAS_IO_SPLICE(__done_, __LINE__) != true; \ + __ATLAS_IO_SPLICE(__done_, __LINE__) = true) diff --git a/atlas_io/tests/TestEnvironment.h b/atlas_io/tests/TestEnvironment.h index aa2b99e90..7b66cee8f 100644 --- a/atlas_io/tests/TestEnvironment.h +++ b/atlas_io/tests/TestEnvironment.h @@ -27,7 +27,7 @@ #include "eckit/types/Types.h" #include "atlas_io/atlas-io.h" -#include "atlas_io/detail/BlackMagic.h" +#include "atlas_io/Trace.h" namespace atlas { namespace test { diff --git a/atlas_io/tests/test_io_stream.cc b/atlas_io/tests/test_io_stream.cc index 46ed49874..598e26b04 100644 --- a/atlas_io/tests/test_io_stream.cc +++ b/atlas_io/tests/test_io_stream.cc @@ -8,12 +8,10 @@ * nor does it submit to any jurisdiction. */ -#include "atlas_io/FileStream.h" -#include "atlas_io/Session.h" +#include "atlas_io/atlas-io.h" #include "eckit/io/FileHandle.h" #include "eckit/io/PooledHandle.h" - #include "TestEnvironment.h"