diff --git a/src/cpp/converted/eccodes/accessor/UnsignedData.cc b/src/cpp/converted/eccodes/accessor/UnsignedData.cc new file mode 100644 index 000000000..08f3a4cbf --- /dev/null +++ b/src/cpp/converted/eccodes/accessor/UnsignedData.cc @@ -0,0 +1,247 @@ +/* + * (C) Copyright 2005- 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 "grib_api_internal.h" + +#include "UnsignedData.h" +#include "Accessor.h" +#include "AccessorFactory.h" +#include "AccessorUtils/ConversionHelper.h" +#include "AccessorUtils/ContainerHelper.h" +#include "AccessorUtils/AccessorException.h" +#include "GribCpp/GribCppIncludes.h" +#include "GribStub/GribStubIncludes.h" + + +namespace eccodes::accessor +{ + +// Globals - START +const std::vector ones = { 0, 0xff, 0xffff, 0xffffff, 0xffffffff }; +unsigned long allOnes = -1; +bool valueIsMissing(long val); +// Globals - END + + +bool valueIsMissing(long val) +{ + return val == GRIB_MISSING_LONG || val == allOnes; +} + +GribStatus UnsignedData::packLongUnsignedHelper(const std::vector& val, int check) +{ + GribStatus ret = GribStatus::SUCCESS; + long off = 0; + long rlen = 0; + size_t buflen = 0; + AccessorDataBuffer buf = {}; + unsigned long i = 0; + unsigned long missing = 0; + GribStatus err = valueCount(rlen); + + if (!GribStatusSuccess(err)) + return err; + + if (flags_ & toInt(GribAccessorFlag::CAN_BE_MISSING)) { + Assert(nbytes_ <= 4); + missing = ones[nbytes_]; + } + + if (flags_ & toInt(GribAccessorFlag::TRANSIENT)) { + vvalue_->lval = val[0]; + if (missing && val.size() == GRIB_MISSING_LONG) + vvalue_->lval = 1; + return GribStatus::SUCCESS; + } + + if (val.size() < 1) { + gribLog(GRIB_LOG_ERROR, "Wrong size for %s it contains %zu values ", name_, val.size()); + return GribStatus::ARRAY_TOO_SMALL; + } + + if (rlen == 1) { + long v = val[0]; + if (missing) + if (v == GRIB_MISSING_LONG) + v = missing; + if (check) { + if (val[0] < 0) { + gribLog(GRIB_LOG_ERROR, "Key \"%s\": Trying to encode a negative value of %ld for key of type unsigned", name_, val[0]); + return GribStatus::ENCODING_ERROR; + } + if (!valueIsMissing(v)) { + const long nbits = nbytes_ * 8; + if (nbits < 33) { + unsigned long maxval = (1UL << nbits) - 1; + if (maxval > 0 && v > maxval) { + gribLog(GRIB_LOG_ERROR, "Key \"%s\": Trying to encode value of %ld but the maximum allowable value is %lu (number of bits=%ld)", name_, v, maxval, nbits); + return GribStatus::ENCODING_ERROR; + } + } + } + } + off = offset_ * 8; + ret = gribEncodeUnsignedLong(buffer_.data(), v, off, nbytes_ * 8); + //if (ret == GribStatus::SUCCESS) + // [Removing - conversion requires mutable operation on const type] val.resize(1); + + if (val.size() > 1) + gribLog(GRIB_LOG_WARNING, "grib_accessor_unsigned : Trying to pack %d values in a scalar %s, packing first value", val.size(), name_); + // [Removing - conversion requires mutable operation on const type] val.resize(1); + return ret; + } + + buflen = val[0] * nbytes_; + buf.resize(buflen); + for (i = 0; i < val.size(); i++) + gribEncodeUnsignedLong(buf, val[i], off, nbytes_ * 8); + //ret = gribSetLong(AccessorName(std::get(initData.args[0].second)), val[0]); + std::string parentName = std::get(args_[0].second); + + ret = gribSetLong(AccessorName(parentName), val[0]); + if (ret == GribStatus::SUCCESS) + gribBufferReplace(buf, buflen, 1, 1); + // [Removed call to grib_context_free] grib_context_free(a->context, buf); + return ret; +} + + +UnsignedData::UnsignedData(const AccessorInitData& initData) : + LongData(initData) +{ + name_ = "unsigned"; + args_ = initData.args; + nbytes_ = initData.length; + if (flags_ & toInt(GribAccessorFlag::TRANSIENT)) { + length_ = 0; + if (!vvalue_) + vvalue_ = std::make_shared(); + vvalue_->type = GribType::LONG; + vvalue_->length = initData.length; + } + else { + long count = 0; + valueCount(count); + length_ = count * nbytes_; + vvalue_ = nullptr; + } +} + +void UnsignedData::dump() const +{ + // C++ implementation not yet available. + // Current C++ conversion provided below (disabled, for reference only): + +#if 0 +long rlen = 0; +valueCount(rlen); +if (rlen == 1) +gribDumpLong(NULL); +#endif // 0 + + return LongData::dump(); +} + +GribStatus UnsignedData::unpack(std::vector& values) const +{ + long rlen = 0; + unsigned long i = 0; + unsigned long missing = 0; + long count = 0; + GribStatus err = GribStatus{ 0 }; + + unsigned char* data = currentBuffer().data(); + long bitPos = byteOffset() * 8; + + + err = valueCount(count); + if (!GribStatusSuccess(err)) + return err; + + values.resize(count); + + rlen = count; + if (values.size() < rlen) { + gribLog(GRIB_LOG_ERROR, "Wrong size (%ld) for %s, it contains %ld values", values.size(), name_, rlen); + values.clear(); + return GribStatus::ARRAY_TOO_SMALL; + } + if (flags_ & toInt(GribAccessorFlag::TRANSIENT)) { + values.resize(1); + values[0] = vvalue_->lval; + return GribStatus::SUCCESS; + } + if (flags_ & toInt(GribAccessorFlag::CAN_BE_MISSING)) { + Assert(nbytes_ <= 4); + missing = ones[0]; + } + for (i = 0; i < rlen; i++) { + values[i] = static_cast(gribDecodeUnsignedLong(data, bitPos, nbytes_ * 8)); + if (missing) + if (values.size() == missing) + values[i] = GRIB_MISSING_LONG; + } + values.resize(rlen); + return GribStatus::SUCCESS; +} + +GribStatus UnsignedData::pack(const std::vector& longValues) +{ + return packLongUnsignedHelper(longValues, 1); +} + +//long UnsignedData::byteCount() const +//{ +// return length_; +//} + +GribStatus UnsignedData::valueCount(long& count) const +{ + if (!args_.empty()) { + count = 1; + return GribStatus::SUCCESS; + } + + return LongData::valueCount(count); +} + +//long UnsignedData::byteOffset() const +//{ +// return offset_; +//} + +void UnsignedData::updateSize(std::size_t s) +{ + length_ = s; +} + +bool UnsignedData::isMissing() const +{ + int i = 0; + unsigned char ff = 0xff; + unsigned long offset = offset_; + if (length_ == 0) { + Assert(vvalue_ != nullptr); + return static_cast(vvalue_); + } + for (i = 0; i < length_; i++) { + if (buffer_.data()[offset] != ff) { + return 0; + } + offset++; + } + return 1; +} + +UnsignedData::~UnsignedData(){} + +AccessorBuilder unsignedDataBuilder(AccessorType("unsigned")); + +} // namespace eccodes::accessor diff --git a/src/cpp/converted/eccodes/accessor/UnsignedData.h b/src/cpp/converted/eccodes/accessor/UnsignedData.h new file mode 100644 index 000000000..e1ad8e3d5 --- /dev/null +++ b/src/cpp/converted/eccodes/accessor/UnsignedData.h @@ -0,0 +1,49 @@ +/* + * (C) Copyright 2005- 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 "LongData.h" + + +namespace eccodes::accessor +{ + +// Forward declarations + +class UnsignedData : public LongData +{ +public: + UnsignedData(const AccessorInitData& initData); + ~UnsignedData(); + + +protected: + // Virtual member functions + void dump() const override; + GribStatus unpack(std::vector& longValues) const override; + GribStatus pack(const std::vector& longValues) override; + //long byteCount() const override; + GribStatus valueCount(long& count) const override; + //long byteOffset() const override; + void updateSize(std::size_t s) override; + bool isMissing() const override; + + // Data members + long nbytes_; + //grib_arguments* args_; + AccessorInitArguments args_; + +private: + // Member functions + GribStatus packLongUnsignedHelper(const std::vector& longValues, int check); +}; + +} // namespace eccodes::accessor diff --git a/src/cpp/eccodes/accessor/AccessorStore.cc b/src/cpp/eccodes/accessor/AccessorStore.cc index d7ece17c6..924da8dcc 100644 --- a/src/cpp/eccodes/accessor/AccessorStore.cc +++ b/src/cpp/eccodes/accessor/AccessorStore.cc @@ -35,7 +35,7 @@ AccessorPtr AccessorStore::getAccessor(AccessorName const& name) return it->second; } - return {}; + return nullptr; } bool AccessorStore::destroyAccessor(AccessorName const& name) diff --git a/src/grib_accessor.cc b/src/grib_accessor.cc index 9956b56cd..53add0f3a 100644 --- a/src/grib_accessor.cc +++ b/src/grib_accessor.cc @@ -17,7 +17,6 @@ #include "Accessor.h" #include "AccessorStore.h" -#include #include /* Note: A fast cut-down version of strcmp which does NOT return -1 */ diff --git a/src/grib_accessor_class.cc b/src/grib_accessor_class.cc index 52535344f..ecd0743a0 100644 --- a/src/grib_accessor_class.cc +++ b/src/grib_accessor_class.cc @@ -168,6 +168,7 @@ grib_accessor* grib_accessor_factory(grib_section* p, grib_action* creator, a->flags = creator->flags; a->set = creator->set; + if (p->block->last) { a->offset = grib_get_next_position_offset(p->block->last); @@ -186,6 +187,25 @@ grib_accessor* grib_accessor_factory(grib_section* p, grib_action* creator, a->cclass = c; + // C++ Accessors +#ifdef USE_CPP_ACCESSORS + using namespace eccodes::accessor; + auto accessorType = AccessorType(creator->op); + + if (auto& factory = AccessorFactory::instance(); factory.has(accessorType)) + { + long section_count = p->h->sections_count; + auto accessorName = AccessorName(creator->name); + auto accessorNameSpace = AccessorNameSpace(creator->name_space ? creator->name_space : ""); + auto initData = makeInitData(p, len, params, a, creator, p); + auto accessorPtr = factory.build(accessorType, accessorName, accessorNameSpace, initData); + Assert(accessorPtr); + } + + // C++ - we'll keep a copy of the grib_accessor pointer for any accessors not yet implemented + //add_grib_accessor(AccessorName(creator->name), a); +#endif // USE_CPP_ACCESSORS + grib_init_accessor(a, len, params); size = grib_get_next_position_offset(a); @@ -225,27 +245,6 @@ grib_accessor* grib_accessor_factory(grib_section* p, grib_action* creator, - // C++ Accessors -#ifdef USE_CPP_ACCESSORS - using namespace eccodes::accessor; - auto accessorType = AccessorType(creator->op); - - if (auto& factory = AccessorFactory::instance(); factory.has(accessorType)) - { - //std::cout << "AccessorFactory has " << creator->op << std::endl; - //std::cout << "\t - Offset: " << a->offset << " Length: " << a->length << std::endl; - - long section_count = p->h->sections_count; - auto accessorName = AccessorName(creator->name); - auto accessorNameSpace = AccessorNameSpace(creator->name_space ? creator->name_space : ""); - auto initData = makeInitData(p, len, params, a, creator, p); - auto accessorPtr = factory.build(accessorType, accessorName, accessorNameSpace, initData); - Assert(accessorPtr); - } - - // C++ - we'll keep a copy of the grib_accessor pointer for any accessors not yet implemented - add_grib_accessor(AccessorName(creator->name), a); -#endif // USE_CPP_ACCESSORS return a; }