Pārlūkot izejas kodu

reading data in a range

Patrik Kovacs 7 gadi atpakaļ
vecāks
revīzija
e39aa7e064
3 mainītis faili ar 91 papildinājumiem un 22 dzēšanām
  1. 51 7
      include/hdf4cpp/HdfItem.h
  2. 23 15
      lib/HdfItem.cpp
  3. 17 0
      tests/HdfFileTest.cpp

+ 51 - 7
include/hdf4cpp/HdfItem.h

@@ -8,11 +8,25 @@
 #include <hdf4cpp/HdfDefines.h>
 #include <hdf4cpp/HdfAttribute.h>
 #include <iostream>
+#include <algorithm>
 #include <map>
 #include <memory>
 #include <vector>
 #include <hdf/hdf.h>
 
+
+struct Range {
+    int32 begin;
+    int32 quantity;
+    int32 stride;
+
+    Range(int32 begin = 0, int32 quantity = 0, int32 stride = 1) : begin(begin), quantity(quantity), stride(stride) {}
+
+    intn size() const {
+        return quantity / stride;
+    }
+};
+
 class HdfItemBase {
 public:
 
@@ -26,9 +40,22 @@ public:
     virtual std::vector<int32> getDims() = 0;
     virtual intn size() const = 0;
 
-    template <class T> bool read(std::vector<T> &dest) {
-        intn length = size();
-        if(length != FAIL) {
+    template <class T> bool read(std::vector<T> &dest, const std::vector<Range>& ranges) {
+        if(size() == FAIL) {
+            return false;
+        }
+        std::vector<int32> dims = getDims();
+        if(ranges.size() != dims.size()) {
+            throw std::runtime_error("HDF4CPP: incorrect number of ranges");
+        }
+        intn length = 1;
+        for(int i = 0; i < dims.size(); ++i) {
+            if(ranges[i].begin < 0 || ranges[i].begin >= dims[i] || ranges[i].quantity < 0 || ranges[i].begin + ranges[i].quantity > dims[i] || ranges[i].stride <= 0) {
+                throw std::runtime_error("HDF4CPP: incorrect range");
+            }
+            length *= ranges[i].size();
+        }
+        if(length > 0) {
             auto it = typeSizeMap.find(getDataType());
             if(it != typeSizeMap.end()) {
                 if(it->second != sizeof(T)) {
@@ -38,18 +65,27 @@ public:
                 throw std::runtime_error("HDF4CPP: hdf data set type not supported");
             }
             dest.resize(length);
-            return read(dest.data());
+            return read(dest.data(), ranges);
         } else {
             return false;
         }
     }
 
+    template <class T> bool read(std::vector<T> &dest) {
+        std::vector<int32> dims = getDims();
+        std::vector<Range> ranges(dims.size());
+        std::transform(dims.begin(), dims.end(), ranges.begin(), [](const int32& t) {
+            return Range(0, t);
+        });
+        return read(dest, ranges);
+    }
+
     virtual HdfAttribute getAttribute(const std::string& name) = 0;
 
 protected:
     int32 id;
 
-    virtual bool read(void *dest) = 0;
+    virtual bool read(void *dest, const std::vector<Range>& ranges) = 0;
     virtual int32 getDataType() const = 0;
 };
 
@@ -70,7 +106,7 @@ private:
     int32 dataType;
     std::string name;
 
-    bool read(void *dest);
+    bool read(void *dest, const std::vector<Range>& ranges);
     int32 getDataType() const;
 };
 
@@ -90,7 +126,7 @@ public:
 private:
     std::string name;
 
-    bool read(void *dest);
+    bool read(void *dest, const std::vector<Range>& ranges);
     int32 getDataType() const;
 };
 
@@ -107,6 +143,14 @@ public:
     intn size() const;
     HdfAttribute getAttribute(const std::string& name);
 
+    template <class T> bool read(std::vector<T> &dest, const std::vector<Range>& ranges) {
+        if(isValid()) {
+            return item->read(dest, ranges);
+        } else {
+            return false;
+        }
+    }
+
     template <class T> bool read(std::vector<T> &dest) {
         if(isValid()) {
             return item->read(dest);

+ 23 - 15
lib/HdfItem.cpp

@@ -8,16 +8,20 @@
 #include <iostream>
 
 HdfDatasetItem::HdfDatasetItem(int32 id) : HdfItemBase(id) {
-    std::vector<int32> dims = getDims();
-    _size = 1;
-    std::for_each(dims.begin(), dims.end(), [this](const int32& t) {
-        _size *= t;
-    });
-    int32 dim[MAX_DIMENSION];
-    int32 size, nrAtt;
-    char _name[MAX_NAME_LENGTH];
-    SDgetinfo(id, _name, &size, dim, &dataType, &nrAtt);
-    name = std::string(_name);
+    if(id == FAIL) {
+        _size = FAIL;
+    } else {
+        std::vector<int32> dims = getDims();
+        _size = 1;
+        std::for_each(dims.begin(), dims.end(), [this](const int32 &t) {
+            _size *= t;
+        });
+        int32 dim[MAX_DIMENSION];
+        int32 size, nrAtt;
+        char _name[MAX_NAME_LENGTH];
+        SDgetinfo(id, _name, &size, dim, &dataType, &nrAtt);
+        name = std::string(_name);
+    }
 }
 std::vector<int32> HdfDatasetItem::getDims() {
     int32 dims[MAX_DIMENSION];
@@ -26,10 +30,14 @@ std::vector<int32> HdfDatasetItem::getDims() {
     SDgetinfo(id, name, &size, dims, &dataType, &nrAtt);
     return std::vector<int32>(dims, dims + size);
 }
-bool HdfDatasetItem::read(void *dest) {
-    std::vector<int32> end = getDims();
-    std::vector<int32> start(end.size(), 0);
-    return SDreaddata(id, start.data(), nullptr, end.data(), dest) != FAIL;
+bool HdfDatasetItem::read(void *dest, const std::vector<Range>& ranges) {
+    std::vector<int32> start, quantity, stride;
+    for(const auto& range : ranges) {
+        start.push_back(range.begin);
+        quantity.push_back(range.quantity);
+        stride.push_back(range.stride);
+    }
+    return SDreaddata(id, start.data(), stride.data(), quantity.data(), dest) != FAIL;
 }
 HdfAttribute HdfDatasetItem::getAttribute(const std::string &name) {
     return HdfAttribute(new HdfDatasetAttribute(id, name));
@@ -62,7 +70,7 @@ HdfGroupItem::HdfGroupItem(int32 id) : HdfItemBase(id) {
 std::vector<int32> HdfGroupItem::getDims() {
     throw std::runtime_error("HDF4CPP: getDims not defined for HdfGroupItem");
 }
-bool HdfGroupItem::read(void *) {
+bool HdfGroupItem::read(void *, const std::vector<Range>&) {
     throw std::runtime_error("HDF4CPP: read not defined for HdfGroupItem");
 }
 HdfAttribute HdfGroupItem::getAttribute(const std::string &name) {

+ 17 - 0
tests/HdfFileTest.cpp

@@ -101,6 +101,23 @@ TEST_F(HdfFileTest, ReadInvalidData) {
     ASSERT_FALSE(item.read(vec));
 }
 
+TEST_F(HdfFileTest, ReadDataInRange) {
+    {
+        HdfItem item = file.get("Data");
+        ASSERT_TRUE(item.isValid());
+        std::vector<int32> vec;
+        item.read(vec, std::vector<Range>({Range(0, 2), Range(1, 2)}));
+        ASSERT_EQ(vec, std::vector<int32>({2, 3, 5, 6}));
+    }
+    {
+        HdfItem item = file.get("DataWithAttributes");
+        ASSERT_TRUE(item.isValid());
+        std::vector<float32> vec;
+        item.read(vec, std::vector<Range>({Range(2, 1), Range(0, 2)}));
+        ASSERT_EQ(vec, std::vector<float32>({2.0, 2.1}));
+    }
+}
+
 TEST_F(HdfFileTest, ReadInvalidDatasetAttribute) {
     HdfItem item = file.get("Data");
     ASSERT_TRUE(item.isValid());