summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--c++/codec-netcdf/.nix/derivation.nix33
-rw-r--r--c++/codec-netcdf/SConscript38
-rw-r--r--c++/codec-netcdf/SConstruct66
-rw-r--r--c++/codec-netcdf/netcdf.h93
-rw-r--r--c++/codec-netcdf/netcdf.tmpl.h106
-rw-r--r--default.nix7
-rw-r--r--tests/.nix/derivation.nix1
-rw-r--r--tests/codec-netcdf.cpp25
-rw-r--r--tests/data/simple.ncbin0 -> 68 bytes
9 files changed, 369 insertions, 0 deletions
diff --git a/c++/codec-netcdf/.nix/derivation.nix b/c++/codec-netcdf/.nix/derivation.nix
new file mode 100644
index 0000000..770942e
--- /dev/null
+++ b/c++/codec-netcdf/.nix/derivation.nix
@@ -0,0 +1,33 @@
+{ lib
+, stdenv
+, scons
+, clang
+, clang-tools
+, version
+, forstio
+, netcdf
+}:
+
+let
+
+in stdenv.mkDerivation {
+ pname = "forstio-codec-netcdf";
+ inherit version;
+ src = ./..;
+
+ enableParallelBuilding = true;
+
+ nativeBuildInputs = [
+ scons
+ clang-tools
+ ];
+
+ buildInputs = [
+ forstio.core
+ forstio.async
+ forstio.codec
+ netcdf
+ ];
+
+ outputs = ["out" "dev"];
+}
diff --git a/c++/codec-netcdf/SConscript b/c++/codec-netcdf/SConscript
new file mode 100644
index 0000000..a469f77
--- /dev/null
+++ b/c++/codec-netcdf/SConscript
@@ -0,0 +1,38 @@
+#!/bin/false
+
+import os
+import os.path
+import glob
+
+
+Import('env')
+
+dir_path = Dir('.').abspath
+
+# Environment for base library
+codec_netcdf_env = env.Clone();
+
+codec_netcdf_env.sources = sorted(glob.glob(dir_path + "/*.cpp"))
+codec_netcdf_env.headers = sorted(glob.glob(dir_path + "/*.h"))
+
+env.sources += codec_netcdf_env.sources;
+env.headers += codec_netcdf_env.headers;
+
+## Shared lib
+objects_shared = []
+codec_netcdf_env.add_source_files(objects_shared, codec_netcdf_env.sources, shared=True);
+codec_netcdf_env.library_shared = codec_netcdf_env.SharedLibrary('#build/forstio-codec-netcdf', [objects_shared]);
+
+## Static lib
+objects_static = []
+codec_netcdf_env.add_source_files(objects_static, codec_netcdf_env.sources, shared=False);
+codec_netcdf_env.library_static = codec_netcdf_env.StaticLibrary('#build/forstio-codec-netcdf', [objects_static]);
+
+# Set Alias
+env.Alias('library_codec_netcdf', [codec_netcdf_env.library_shared, codec_netcdf_env.library_static]);
+
+env.targets += ['library_codec_netcdf'];
+
+# Install
+env.Install('$prefix/lib/', [codec_netcdf_env.library_shared, codec_netcdf_env.library_static]);
+env.Install('$prefix/include/forstio/codec/netcdf/', [codec_netcdf_env.headers]);
diff --git a/c++/codec-netcdf/SConstruct b/c++/codec-netcdf/SConstruct
new file mode 100644
index 0000000..edd5f57
--- /dev/null
+++ b/c++/codec-netcdf/SConstruct
@@ -0,0 +1,66 @@
+#!/usr/bin/env python3
+
+import sys
+import os
+import os.path
+import glob
+import re
+
+
+if sys.version_info < (3,):
+ def isbasestring(s):
+ return isinstance(s,basestring)
+else:
+ def isbasestring(s):
+ return isinstance(s, (str,bytes))
+
+def add_kel_source_files(self, sources, filetype, lib_env=None, shared=False, target_post=""):
+
+ if isbasestring(filetype):
+ dir_path = self.Dir('.').abspath
+ filetype = sorted(glob.glob(dir_path+"/"+filetype))
+
+ for path in filetype:
+ target_name = re.sub( r'(.*?)(\.cpp|\.c\+\+)', r'\1' + target_post, path )
+ if shared:
+ target_name+='.os'
+ sources.append( self.SharedObject( target=target_name, source=path ) )
+ else:
+ target_name+='.o'
+ sources.append( self.StaticObject( target=target_name, source=path ) )
+ pass
+
+def isAbsolutePath(key, dirname, env):
+ assert os.path.isabs(dirname), "%r must have absolute path syntax" % (key,)
+
+env_vars = Variables(
+ args=ARGUMENTS
+)
+
+env_vars.Add('prefix',
+ help='Installation target location of build results and headers',
+ default='/usr/local/',
+ validator=isAbsolutePath
+)
+
+env=Environment(ENV=os.environ, variables=env_vars, CPPPATH=[],
+ CPPDEFINES=['SAW_UNIX'],
+ CXXFLAGS=['-std=c++20','-g','-Wall','-Wextra'],
+ LIBS=['forstio-codec'])
+env.__class__.add_source_files = add_kel_source_files
+env.Tool('compilation_db');
+env.cdb = env.CompilationDatabase('compile_commands.json');
+
+env.objects = [];
+env.sources = [];
+env.headers = [];
+env.targets = [];
+
+Export('env')
+SConscript('SConscript')
+
+env.Alias('cdb', env.cdb);
+env.Alias('all', [env.targets]);
+env.Default('all');
+
+env.Alias('install', '$prefix')
diff --git a/c++/codec-netcdf/netcdf.h b/c++/codec-netcdf/netcdf.h
new file mode 100644
index 0000000..d579b7f
--- /dev/null
+++ b/c++/codec-netcdf/netcdf.h
@@ -0,0 +1,93 @@
+#pragma once
+
+#include <forstio/core/string_literal.h>
+#include <forstio/core/error.h>
+#include <forstio/codec/codec.h>
+
+#include <netcdf.h>
+
+namespace saw {
+namespace encode {
+/**
+ * Template type hint
+ */
+struct Netcdf {};
+}
+
+/**
+ * Class representing the files system netcdf file
+ */
+template<typename Schema>
+class data<Schema, encode::Netcdf> {
+private:
+ std::string path_;
+public:
+ data(const std::string& path):
+ path_{path}
+ {}
+
+ data(std::string&& path):
+ path_{std::move(path)}
+ {}
+
+ std::string_view get_path_view() {
+ return path_;
+ }
+
+ const std::string& get_path() const {
+ return path_;
+ }
+};
+
+template<typename Schema>
+class codec<Schema, encode::Netcdf>{
+ static_assert(always_false<Schema,encode::Netcdf>, "NetCDF only supports Structs as a root object");
+};
+
+}
+#include "netcdf.tmpl.h"
+namespace saw {
+
+template<typename... Vals, string_literal... Keys>
+class codec<schema::Struct<schema::Member<Vals,Keys>...>, encode::Netcdf> {
+private:
+ using Schema = schema::Struct<schema::Member<Vals,Keys>...>;
+public:
+ SAW_FORBID_COPY(codec);
+ SAW_DEFAULT_MOVE(codec);
+
+ /**
+ * Default constructor
+ */
+ codec() = default;
+
+ /**
+ * Encoder function
+ */
+ template<typename FromEncoding>
+ error_or<void> encode() {
+ return void_t{};
+ }
+
+ /**
+ * Decoder function
+ */
+ template<typename ToEncoding>
+ error_or<void> decode(data<Schema, encode::Netcdf>& from_decode, data<Schema,ToEncoding>& to_decode) {
+ int ncid{};
+ int rc{};
+
+ rc = nc_open(from_decode.get_path().c_str(), NC_NOWRITE, &ncid);
+ if(rc){
+ // Don't know how to get the error, so fail critically.
+ return make_error<err::critical>();
+ }
+
+ auto eov = impl::netcdf_decode<Schema, ToEncoding>::decode(to_decode, ncid);
+
+ nc_close(ncid);
+
+ return eov;
+ }
+};
+}
diff --git a/c++/codec-netcdf/netcdf.tmpl.h b/c++/codec-netcdf/netcdf.tmpl.h
new file mode 100644
index 0000000..921c84e
--- /dev/null
+++ b/c++/codec-netcdf/netcdf.tmpl.h
@@ -0,0 +1,106 @@
+#pragma once
+
+namespace saw {
+namespace impl {
+template<typename Schema>
+struct netcdf_is_group {
+ static constexpr bool value = false;
+};
+
+template<typename... T, string_literal... Lits>
+struct netcdf_is_group<schema::Struct<schema::Member<T,Lits>...>> {
+ static constexpr bool value = true;
+};
+
+template<typename Schema, typename RootSchema, typename ToEncode>
+struct netcdf_decode;
+
+template<typename RootSchema, typename ToDecode>
+struct netcdf_decode<schema::Int32, RootSchema, ToDecode> {
+ using Schema = schema::Int32;
+ static error_or<void> decode(data<Schema, ToDecode>& to, int from, int nc_varid){
+ int rc{};
+
+ nc_type nc_vartype{};
+ int nc_dimnum{};
+ std::array<int,NC_MAX_VAR_DIMS> nc_dimids;
+
+ rc = nc_inq_var(from, nc_varid, nullptr, &nc_vartype, &nc_dimnum, &nc_dimids[0], nullptr);
+ if(rc != NC_NOERR){
+ return make_error<err::critical>();
+ }
+ if(nc_vartype != NC_INT){
+ return make_error<err::critical>();
+ }
+ if(nc_dimnum != 0){
+ return make_error<err::critical>();
+ }
+
+ int32_t val{};
+ rc = nc_get_var_int(from, nc_varid, &val);
+ if(rc != NC_NOERR){
+ return make_error<err::critical>();
+ }
+
+ to.set(val);
+
+ return void_t {};
+ }
+};
+
+template<typename... T, string_literal... Lits, typename RootSchema, typename ToDecode>
+struct netcdf_decode<schema::Struct<schema::Member<T,Lits>...>, RootSchema, ToDecode> {
+ using Schema = schema::Struct<schema::Member<T,Lits>...>;
+
+ template<std::size_t i>
+ static error_or<void> decode_member(data<Schema,ToDecode>& to, int from){
+ using Type = typename parameter_pack_type<i,T...>::type;
+ constexpr string_literal Literal = parameter_key_pack_type<i, Lits...>::literal;
+ {
+ /**
+ * We have to ask for the internal id of the netcdf structure
+ */
+ if constexpr (netcdf_is_group<Type>::value){
+ int nc_group_id{};
+ int rc {};
+ rc = nc_inq_ncid(from, Literal.data.data(), &nc_group_id);
+ if(rc != NC_NOERR) {
+ return make_error<err::critical>();
+ }
+ auto eov = netcdf_decode<Type, RootSchema, ToDecode>::decode(to.template get<Literal>(), nc_group_id);
+ if(eov.is_error()){
+ return eov;
+ }
+ }else{
+ int nc_varid{};
+ int rc {};
+ rc = nc_inq_varid(from, Literal.data.data(), &nc_varid);
+ if(rc != NC_NOERR) {
+ return make_error<err::critical>();
+ }
+ auto eov = netcdf_decode<Type, RootSchema, ToDecode>::decode(to.template get<Literal>(), from, nc_varid);
+ }
+
+ }
+ if constexpr ((i+1) < sizeof...(T)){
+ auto eov = decode_member<i+1>(from, to, ncid);
+ if(eov.is_error()){
+ return eov;
+ }
+ }
+
+ return void_t{};
+ }
+
+
+ static error_or<void> decode(data<Schema, ToDecode>& to, int from){
+ if constexpr (sizeof...(T) > 0){
+ auto eov = decode_member<0>(to, from);
+ return eov;
+ }
+
+ return void_t{};
+ }
+};
+}
+}
diff --git a/default.nix b/default.nix
index 397cf74..16e7c73 100644
--- a/default.nix
+++ b/default.nix
@@ -40,6 +40,13 @@ in rec {
inherit stdenv;
inherit clang-tools;
};
+
+ codec-netcdf = pkgs.callPackage c++/codec-netcdf/.nix/derivation.nix {
+ inherit version;
+ inherit forstio;
+ inherit stdenv;
+ inherit clang-tools;
+ };
io = pkgs.callPackage c++/io/.nix/derivation.nix {
inherit version;
diff --git a/tests/.nix/derivation.nix b/tests/.nix/derivation.nix
index 198095e..e096e70 100644
--- a/tests/.nix/derivation.nix
+++ b/tests/.nix/derivation.nix
@@ -19,6 +19,7 @@ stdenv.mkDerivation {
forstio.async
forstio.codec
forstio.codec-json
+ forstio.codec-netcdf
forstio.core
forstio.io
forstio.test
diff --git a/tests/codec-netcdf.cpp b/tests/codec-netcdf.cpp
new file mode 100644
index 0000000..df0037b
--- /dev/null
+++ b/tests/codec-netcdf.cpp
@@ -0,0 +1,25 @@
+#include <forstio/test/suite.h>
+#include <forstio/codec/netcdf/netcdf.h>
+
+namespace {
+namespace schema {
+using namespace saw::schema;
+using TestStruct = Struct<
+ Member<Int32, "rh">
+>;
+}
+
+SAW_TEST("NetCDF read"){
+ using namespace saw;
+
+ data<TestStruct, encode::Netcdf> net{"./data/simple.nc"};
+
+ data<TestStruct, encode::KelSimple> kel;
+
+ codec<TestStruct, encode::Netcdf> codec;
+
+ auto eov = codec.decode(net, kel);
+ SAW_EXPECT(eov.is_value(), "Decoding failed");
+ SAW_EXPECT(kel.get<"rh">.get() == 5, "Value incorrect");
+}
+}
diff --git a/tests/data/simple.nc b/tests/data/simple.nc
new file mode 100644
index 0000000..4fc2473
--- /dev/null
+++ b/tests/data/simple.nc
Binary files differ