HdfItem.h 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422
  1. /// \copyright Copyright (c) Catalysts GmbH
  2. /// \author Patrik Kovacs, Catalysts GmbH
  3. #ifndef HDF4CPP_HDFITEM_H
  4. #define HDF4CPP_HDFITEM_H
  5. #include <hdf4cpp/HdfDefines.h>
  6. #include <hdf4cpp/HdfFile.h>
  7. #include <hdf4cpp/HdfException.h>
  8. #include <algorithm>
  9. #include <map>
  10. #include <memory>
  11. #include <vector>
  12. #include <hdf/hdf.h>
  13. namespace hdf4cpp {
  14. /// Structure to define in which range we want to read the data from the SData
  15. /// It must be defined for every dimension
  16. struct Range {
  17. /// The index in which begins the reading of the data
  18. int32 begin;
  19. /// The number of data to be read
  20. int32 quantity;
  21. /// The increasing number (stride = 1 : every data, stride = 2 : every second data, ...)
  22. int32 stride;
  23. Range(int32 begin = 0, int32 quantity = 0, int32 stride = 1) : begin(begin), quantity(quantity), stride(stride) {}
  24. /// What would be the number of data to read, if we read in this range
  25. intn size() const {
  26. if (!stride) {
  27. return 0;
  28. }
  29. return quantity / stride;
  30. }
  31. /// Checks if the range is correct for a specific dimension
  32. bool check(const int32& dim) const {
  33. return begin >= 0 ||
  34. begin < dim ||
  35. quantity >= 0 ||
  36. begin + quantity <= dim ||
  37. stride > 0;
  38. }
  39. /// Fills a range vector with a dimension array
  40. static void fill(std::vector<Range>& ranges, const std::vector<int32>& dims) {
  41. for (size_t i = ranges.size(); i < dims.size(); ++i) {
  42. ranges.push_back(Range(0, dims[i]));
  43. }
  44. }
  45. };
  46. class HdfAttribute;
  47. /// Represents an hdf item
  48. class HdfItem : public HdfObject {
  49. public:
  50. HdfItem(const HdfItem& item) = delete;
  51. HdfItem(HdfItem&& item);
  52. HdfItem& operator=(const HdfItem& item) = delete;
  53. HdfItem& operator=(HdfItem&& it);
  54. /// \returns The name of the item
  55. std::string getName() const;
  56. /// \returns The dimensions of the item
  57. /// \note This operation is not supported for every item type
  58. std::vector<int32> getDims();
  59. /// \returns The number of data being in the item
  60. intn size() const;
  61. /// \returns the attribute of the item with the given name
  62. /// \param name the name of the attribute
  63. /// \note If there are multiple attributes with the same name then the first will be returned
  64. HdfAttribute getAttribute(const std::string& name) const;
  65. /// Reads the entire data from the item
  66. /// \param dest the destination vector in which the data will be stored
  67. template <class T> void read(std::vector<T>& dest) {
  68. switch(item->getType()) {
  69. case SDATA: {
  70. HdfDatasetItem *dItem = dynamic_cast<HdfDatasetItem *>(item.get());
  71. dItem->read(dest);
  72. break;
  73. }
  74. default:
  75. raiseException(INVALID_OPERATION);
  76. }
  77. }
  78. /// Reads the data from the item in a specified range
  79. /// \param dest the destination vector in which the data will be stored
  80. /// \param ranges specifies the range in which the data will be read
  81. template <class T> void read(std::vector<T>& dest, std::vector<Range> ranges) {
  82. switch(item->getType()) {
  83. case SDATA: {
  84. HdfDatasetItem *dItem = dynamic_cast<HdfDatasetItem *>(item.get());
  85. dItem->read(dest, ranges);
  86. break;
  87. }
  88. default:
  89. raiseException(INVALID_OPERATION);
  90. }
  91. }
  92. /// Reads the given field from the item
  93. /// \param dest the destination vector in which the data will be stored
  94. /// \param field the name of the field
  95. /// \param records the number of records to be read
  96. template <class T> void read(std::vector<T>& dest, const std::string& field, int32 records = 0) {
  97. switch(item->getType()) {
  98. case VDATA: {
  99. HdfDataItem *vItem = dynamic_cast<HdfDataItem*>(item.get());
  100. vItem->read(dest, field, records);
  101. break;
  102. }
  103. default:
  104. raiseException(INVALID_OPERATION);
  105. }
  106. }
  107. class Iterator;
  108. Iterator begin() const;
  109. Iterator end() const;
  110. friend HdfItem HdfFile::get(const std::string& name) const;
  111. friend std::vector<HdfItem> HdfFile::getAll(const std::string& name) const;
  112. friend HdfItem HdfFile::Iterator::operator*();
  113. friend class HdfAttribute;
  114. private:
  115. /// The base class of the item classes
  116. class HdfItemBase : public HdfObject {
  117. public:
  118. HdfItemBase(int32 id, const Type& type, const HdfDestroyerChain& chain) : HdfObject(type, ITEM, chain), id(id) {
  119. if (id == FAIL) {
  120. raiseException(INVALID_ID);
  121. }
  122. }
  123. virtual ~HdfItemBase() {}
  124. /// Get the id which is held by this object
  125. virtual int32 getId() const = 0;
  126. /// Get the name of the item
  127. virtual std::string getName() const = 0;
  128. /// Get the dimensions of the item
  129. virtual std::vector<int32> getDims() = 0;
  130. /// Get the number of data from the item
  131. virtual intn size() const = 0;
  132. /// Get the attribute from the item given by its name
  133. virtual HdfAttribute getAttribute(const std::string& name) const = 0;
  134. protected:
  135. int32 id;
  136. virtual int32 getDataType() const = 0;
  137. };
  138. /// Item class for the SData items
  139. class HdfDatasetItem : public HdfItemBase {
  140. public:
  141. HdfDatasetItem(int32 id, const HdfDestroyerChain& chain);
  142. ~HdfDatasetItem();
  143. int32 getId() const;
  144. std::string getName() const;
  145. std::vector<int32> getDims();
  146. intn size() const;
  147. HdfAttribute getAttribute(const std::string& name) const;
  148. /// Reads the data in a specific range. See Range
  149. /// \param dest The destination vector
  150. /// \param ranges The vector of ranges
  151. template <class T>
  152. void read(std::vector<T>& dest, std::vector<Range>& ranges) {
  153. std::vector<int32> dims = getDims();
  154. Range::fill(ranges, dims);
  155. intn length = 1;
  156. for (size_t i = 0; i < ranges.size(); ++i) {
  157. if (!ranges[i].check(dims[i])) {
  158. raiseException(INVALID_RANGES);
  159. }
  160. length *= ranges[i].size();
  161. }
  162. auto it = typeSizeMap.find(getDataType());
  163. if (it != typeSizeMap.end()) {
  164. if ((size_t)it->second != sizeof(T)) {
  165. raiseException(BUFFER_SIZE_NOT_ENOUGH);
  166. }
  167. } else {
  168. raiseException(INVALID_DATA_TYPE);
  169. }
  170. dest.resize(length);
  171. std::vector<int32> start, quantity, stride;
  172. for (const auto& range : ranges) {
  173. start.push_back(range.begin);
  174. quantity.push_back(range.quantity);
  175. stride.push_back(range.stride);
  176. }
  177. if (SDreaddata(id, start.data(), stride.data(), quantity.data(), dest.data()) == FAIL) {
  178. raiseException(STATUS_RETURN_FAIL);
  179. }
  180. }
  181. /// Reads the whole data
  182. /// \param dest The destination vector
  183. template <class T>
  184. void read(std::vector<T>& dest) {
  185. std::vector<int32> dims = getDims();
  186. std::vector<Range> ranges;
  187. for (const auto& dim : dims) {
  188. ranges.push_back(Range(0, dim));
  189. }
  190. read(dest, ranges);
  191. }
  192. private:
  193. intn _size;
  194. int32 dataType;
  195. std::string name;
  196. std::vector<int32> dims;
  197. int32 getDataType() const;
  198. };
  199. /// Item class for VGroup items
  200. class HdfGroupItem : public HdfItemBase {
  201. public:
  202. HdfGroupItem(int32 id, const HdfDestroyerChain& chain);
  203. ~HdfGroupItem();
  204. int32 getId() const;
  205. std::string getName() const;
  206. std::vector<int32> getDims();
  207. intn size() const;
  208. HdfAttribute getAttribute(const std::string& name) const;
  209. private:
  210. std::string name;
  211. int32 getDataType() const;
  212. };
  213. /// Item class for VData items
  214. class HdfDataItem : public HdfItemBase {
  215. public:
  216. HdfDataItem(int32 id, const HdfDestroyerChain& chain);
  217. ~HdfDataItem();
  218. int32 getId() const;
  219. std::string getName() const;
  220. std::vector<int32> getDims();
  221. intn size() const;
  222. HdfAttribute getAttribute(const std::string& name) const;
  223. /// Reads a specific number of the data of a specific field
  224. /// The records are simple values
  225. /// \param dest The destination vector
  226. /// \param field The specific field name
  227. /// \param records The number of records to be read
  228. template <class T>
  229. void read(std::vector<T>& dest, const std::string& field, int32 records) {
  230. if (!records) {
  231. records = nrRecords;
  232. }
  233. if (VSsetfields(id, field.c_str()) == FAIL) {
  234. raiseException(STATUS_RETURN_FAIL);
  235. }
  236. int32 fieldSize = VSsizeof(id, (char*)field.c_str());
  237. if (sizeof(T) < (size_t) fieldSize) {
  238. raiseException(BUFFER_SIZE_NOT_ENOUGH);
  239. }
  240. size_t size = records * fieldSize;
  241. std::vector<uint8> buff(size);
  242. if (VSread(id, buff.data(), records, interlace) == FAIL) {
  243. raiseException(STATUS_RETURN_FAIL);
  244. }
  245. dest.resize(records);
  246. VOIDP buffptrs[1];
  247. buffptrs[0] = dest.data();
  248. if (VSfpack(id, _HDF_VSUNPACK, field.c_str(), buff.data(), size, records, field.c_str(), buffptrs) == FAIL) {
  249. raiseException(STATUS_RETURN_FAIL);
  250. }
  251. }
  252. /// Reads a specific number of the data of a specific field
  253. /// The records are arrays itself
  254. /// \param dest The destination matrix (every record is a vector)
  255. /// \param field The specific field name
  256. /// \param records The number of records to be read
  257. template <class T>
  258. void read(std::vector<std::vector<T> >& dest, const std::string& field, int32 records) {
  259. if (!records) {
  260. records = nrRecords;
  261. }
  262. if (VSsetfields(id, field.c_str()) == FAIL) {
  263. raiseException(STATUS_RETURN_FAIL);
  264. }
  265. int32 fieldSize = VSsizeof(id, (char*)field.c_str());
  266. if (fieldSize % sizeof(T) != 0) {
  267. raiseException(BUFFER_SIZE_NOT_DIVISIBLE);
  268. }
  269. size_t size = records * fieldSize;
  270. std::vector<uint8> buff(size);
  271. if (VSread(id, buff.data(), records, interlace) == FAIL) {
  272. raiseException(STATUS_RETURN_FAIL);
  273. }
  274. int32 divided = fieldSize / sizeof(T);
  275. dest.resize(records, std::vector<T>(divided));
  276. std::vector<T> linearDest(records * divided);
  277. VOIDP buffptrs[1];
  278. buffptrs[0] = linearDest.data();
  279. VSfpack(id, _HDF_VSUNPACK, field.c_str(), buff.data(), size, records, field.c_str(), buffptrs);
  280. int i = 0;
  281. int j;
  282. while (i < records) {
  283. j = 0;
  284. while (j < divided) {
  285. dest[i][j] = linearDest[i * divided + j];
  286. ++j;
  287. }
  288. ++i;
  289. }
  290. }
  291. private:
  292. intn _size;
  293. std::string name;
  294. int32 nrRecords;
  295. int32 interlace;
  296. int32 recordSize;
  297. int32 getDataType() const;
  298. };
  299. HdfItem(HdfItemBase *item, int32 sId, int32 vId);
  300. /// Holds an item object address
  301. std::unique_ptr<HdfItemBase> item;
  302. /// The file handle ids (needed by the iterator)
  303. int32 sId;
  304. int32 vId;
  305. };
  306. /// HdfItem iterator, gives the possibility to iterate over the items from the item
  307. class HdfItem::Iterator : public HdfObject, public std::iterator<std::bidirectional_iterator_tag, HdfItem> {
  308. public:
  309. Iterator(int32 sId, int32 vId, int32 key, int32 index, Type type, const HdfDestroyerChain& chain) :
  310. HdfObject(type, ITERATOR, chain),
  311. sId(sId),
  312. vId(vId),
  313. key(key),
  314. index(index) {}
  315. bool operator!=(const Iterator& it) { return index != it.index; }
  316. bool operator==(const Iterator& it) { return index == it.index; }
  317. Iterator& operator++() {
  318. ++index;
  319. return *this;
  320. }
  321. Iterator operator++(int) {
  322. Iterator it(*this);
  323. ++index;
  324. return it;
  325. }
  326. Iterator& operator--() {
  327. --index;
  328. return *this;
  329. }
  330. Iterator operator--(int) {
  331. Iterator it(*this);
  332. --index;
  333. return it;
  334. }
  335. HdfItem operator*() {
  336. int32 tag, ref;
  337. if(Vgettagref(key, index, &tag, &ref) == FAIL) {
  338. raiseException(OUT_OF_RANGE);
  339. }
  340. if(Visvs(key, ref)) {
  341. int32 id = VSattach(vId, ref, "r");
  342. return HdfItem(new HdfDataItem(id, chain), sId, vId);
  343. } else if(Visvg(key, ref)) {
  344. int32 id = Vattach(vId, ref, "r");
  345. return HdfItem(new HdfGroupItem(id, chain), sId, vId);
  346. } else {
  347. int32 id = SDselect(sId, SDreftoindex(sId, ref));
  348. return HdfItem(new HdfDatasetItem(id, chain), sId, vId);
  349. }
  350. }
  351. private:
  352. int32 sId;
  353. int32 vId;
  354. int32 key;
  355. int32 index;
  356. };
  357. }
  358. #endif //HDF4CPP_HDFITEM_H