#pragma once namespace saw { namespace impl { template struct netcdf_primitive_id { static_assert(always_false, "Not a primitive id"); }; template<> struct netcdf_primitive_id { static constexpr nc_type value = NC_INT; }; template<> struct netcdf_primitive_id { static constexpr nc_type value = NC_UINT; }; template<> struct netcdf_primitive_id { static constexpr nc_type value = NC_INT64; }; template<> struct netcdf_primitive_id { static constexpr nc_type value = NC_UINT64; }; template<> struct netcdf_primitive_id { static constexpr nc_type value = NC_FLOAT; }; template<> struct netcdf_primitive_id { static constexpr nc_type value = NC_DOUBLE; }; template struct netcdf_is_group { static constexpr bool value = false; }; template struct netcdf_is_group...>> { static constexpr bool value = true; }; template struct netcdf_encode; template struct netcdf_encode, ToEncode> { using Schema = schema::Primitive; static error_or encode(const data& from, int ncid, int ncvarid){ int rc{}; typename native_data_type::type val = from.get(); rc = nc_put_var(ncid, ncvarid, &val); if(rc != NC_NOERR) { return make_error(); } return void_t{}; } static error_or encode_meta(const data& from, int ncid, int ncvarid){ (void) from; (void) ncid; (void) ncvarid; return void_t{}; } }; template struct netcdf_encode...>, ToEncode> { using Schema = schema::Struct...>; template static error_or encode_member(const data& from, int ncid){ using Type = typename parameter_pack_type::type; constexpr string_literal Literal = parameter_key_pack_type::literal; { /** * We have to ask for the internal id of the netcdf structure */ if constexpr (netcdf_is_group::value){ return make_error(); }else{ int nc_varid{}; int rc {}; rc = nc_inq_varid(ncid, Literal.data.data(), &nc_varid); if(rc != NC_NOERR) { return make_error(); } auto eov = netcdf_encode::encode(from.template get(), ncid, nc_varid); if(eov.is_error()){ return eov; } } } if constexpr ((i+1) < sizeof...(T)){ auto eov = encode_member(from, ncid); if(eov.is_error()){ return eov; } } return void_t{}; } static error_or encode(const data& from, int ncid){ if constexpr (sizeof...(T) > 0){ auto eov = encode_member<0>(from, ncid); return eov; } return void_t{}; } template static error_or encode_meta_member(const data& from, int ncid){ using Type = typename parameter_pack_type::type; constexpr string_literal Literal = parameter_key_pack_type::literal; { /** * We have to ask for the internal id of the netcdf structure */ if constexpr (netcdf_is_group::value){ return make_error(); }else{ int nc_varid{}; int rc {}; rc = nc_def_var(ncid, Literal.data.data(), netcdf_primitive_id::value, 0, nullptr, &nc_varid); if(rc != NC_NOERR) { return make_error(); } auto eov = netcdf_encode::encode_meta(from.template get(), ncid, nc_varid); if(eov.is_error()){ return eov; } } } if constexpr ((i+1) < sizeof...(T)){ auto eov = encode_meta_member(from, ncid); if(eov.is_error()){ return eov; } } return void_t{}; } static error_or encode_meta(const data& from, int ncid){ if constexpr (sizeof...(T) > 0){ auto eov = encode_meta_member<0>(from, ncid); return eov; } return void_t{}; } }; template struct netcdf_decode; template struct netcdf_decode, ToDecode> { using Schema = schema::Primitive; static error_or decode(data& to, int from, int nc_varid){ int rc{}; nc_type nc_vartype{}; int nc_dimnum{}; std::array 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(); } if(nc_vartype != netcdf_primitive_id>::value){ return make_error(); } if(nc_dimnum != 0){ return make_error(); } typename native_data_type>::type val{}; rc = nc_get_var(from, nc_varid, &val); if(rc != NC_NOERR){ return make_error(); } to.set(val); return void_t {}; } }; template struct netcdf_decode, ToDecode> { using Schema = schema::Array; template static error_or decode_level(data& to, int from, int nc_varid, std::array& index, const std::array& count){ if constexpr ( Level == Dim ){ int rc{}; typename native_data_type::type val; rc = nc_get_vara(from, nc_varid, index.data(), count.data(), &val); if(rc != NC_NOERR){ return make_error(); } to.at(index).set(val); }else{ const std::size_t dim_size = to.get_dim_size(Level); for(index[Level] = 0; index[Level] < dim_size; ++index[Level]){ auto eov = decode_level(to, from, nc_varid, index, count); if(eov.is_error()){ return eov; } } } return void_t{}; } static error_or decode(data& to, int from, int nc_varid){ int rc{}; nc_type nc_vartype{}; int nc_dimnum{}; std::array 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(); } if(nc_vartype != netcdf_primitive_id::value){ return make_error(); } if(nc_dimnum != Dim){ return make_error(); } std::array dims; std::array count; for(std::size_t i = 0; i < Dim; ++i){ rc = nc_inq_dim(from, nc_dimids[i], nullptr, &dims[i]); if(rc != NC_NOERR){ return make_error(); } count[i] = 1; } to = {dims}; std::array index; return decode_level<0>(to, from, nc_varid, index, count); } }; template struct netcdf_decode...>, ToDecode> { using Schema = schema::Struct...>; template static error_or decode_member(data& to, int from){ using Type = typename parameter_pack_type::type; constexpr string_literal Literal = parameter_key_pack_type::literal; { /** * We have to ask for the internal id of the netcdf structure */ if constexpr (netcdf_is_group::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(); } auto eov = netcdf_decode::decode(to.template get(), 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(); } auto eov = netcdf_decode::decode(to.template get(), from, nc_varid); if(eov.is_error()){ return eov; } } } if constexpr ((i+1) < sizeof...(T)){ auto eov = decode_member(to, from); if(eov.is_error()){ return eov; } } return void_t{}; } static error_or decode(data& to, int from){ if constexpr (sizeof...(T) > 0){ auto eov = decode_member<0>(to, from); return eov; } return void_t{}; } }; } }