#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_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 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{}; } }; } }