IODA Bundle
IteratorProxy.h
Go to the documentation of this file.
1 /*
2  * (C) Copyright 1996-2012 ECMWF.
3  *
4  * This software is licensed under the terms of the Apache Licence Version 2.0
5  * which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
6  * In applying this licence, ECMWF does not waive the privileges and immunities
7  * granted to it by virtue of its status as an intergovernmental organisation nor
8  * does it submit to any jurisdiction.
9  */
10 
11 ///
12 /// @author Piotr Kuchta
13 /// @author Simon Smart
14 /// @date Feb 2009
15 
16 /// @note (SDS, Aug 2018); IteratorProxy is a handle to various iterator objects
17 /// (Select,Read,Write,MetaData,...) that essentially implements the intrusive shared pointer
18 /// functionality of std::shared_ptr, without the thread safety or any other niceties.
19 ///
20 /// TODO: Remove it. It is really horrible.
21 
22 #ifndef odc_IteratorProxy_H
23 #define odc_IteratorProxy_H
24 
25 #include <string.h>
26 
27 #include "odc/api/ColumnType.h"
28 #include "eckit/sql/SQLTypedefs.h"
29 
30 namespace eckit { class PathName; }
31 namespace eckit { class DataHandle; }
32 
33 #ifdef SWIGPYTHON
34 
35 #include <Python.h>
36 
37 #include "odc/core/Column.h"
38 #include "odc/odccapi.h"
39 
40 struct ODBStopIteration : public std::exception {
41  const char* what() const throw() { return "end of data"; }
42 };
43 
44 struct ODBIndexError : public std::exception {
45  const char* what() const throw() { return "index out of range"; }
46 };
47 
48 extern "C" void python_api_start()
49 {
50  odb_start();
51 }
52 
53 #endif
54 
55 namespace odc {
56 
57 namespace core { class MetaData; }
58 
59 //----------------------------------------------------------------------------------------------------------------------
60 
61 class Reader;
62 
63 template <typename ITERATOR, typename O, typename DATA>
64 class IteratorProxy;
65 
66 template <typename ITERATOR, typename O, typename DATA, typename ITERATOR_PROXY>
67 class Row_
68 {
69 public:
70 #ifdef SWIGPYTHON
71  Row_() : it_() {}
72 #endif
73  Row_(ITERATOR_PROXY& it) : it_(&it) {}
74 
75  DATA& operator[](size_t i) { return (*it_)->data(i); }
76 
77  DATA* data() { return ((*it_).iter_)->data(); }
78  DATA& data(size_t i) { return ((*it_).iter_)->data(i); }
79 
80  const DATA* data() const { return ((*it_).iter_)->data(); }
81  const DATA& data(size_t i) const { return ((*it_).iter_)->data(i); }
82 
83  int integer(size_t i) { return int((*it_)->data(i)); }
84  std::string string(int i)
85  {
86  size_t maxlen = sizeof(double) * dataSizeDoubles(i);
87  const char *s = reinterpret_cast<const char *>(&data(i));
88  return std::string(s, ::strnlen(s, maxlen));
89  }
90 
91  size_t dataOffset(size_t i) const { return it_->iter_->dataOffset(i); }
92  size_t dataSizeDoubles(size_t i) const { return columns()[i]->dataSizeDoubles(); }
93 
94  const core::MetaData& columns() const { return ((*it_).iter_)->columns(); }
95  void setNumberOfColumns(size_t n) { ((*it_).iter_)->setNumberOfColumns(n); }
96  const core::MetaData& columns(const core::MetaData& md) { return ((*it_).iter_)->columns(md); }
97  bool isNewDataset() { return ((*it_).iter_)->isNewDataset(); }
98  bool isMissing(size_t i) { return ((*it_).iter_)->columns()[i]->missingValue() == (*it_)->data(i); }
99  double missingValue(size_t i) { return ((*it_).iter_)->columns()[i]->missingValue(); }
100 
101  int setColumn(size_t index, const std::string& name, api::ColumnType type)
102  { return (*((*it_).iter_)).setColumn(index, name, type); }
103 
104  int setBitfieldColumn(size_t index, const std::string& name, api::ColumnType type, eckit::sql::BitfieldDef b)
105  { return ((*it_).iter_)->setBitfieldColumn(index, name, type, b); }
106 
107  void missingValue(size_t index, double v) { ((*it_).iter_)->missingValue(index, v); }
108 
109  void writeHeader() { (*((*it_).iter_)).writeHeader(); }
110  void close() { ((*it_).iter_)->close(); }
111 
112  const std::map<std::string, std::string>& properties() const { return it_->iter_->properties(); }
113 
114  template <typename T> unsigned long pass1(T b, const T e) { return ((*it_).iter_)->pass1(b, e); }
115 
116  ITERATOR& operator*() { return *((*it_).iter_); }
117 private:
118  ITERATOR_PROXY* it_;
119 };
120 
121 template <typename ITERATOR, typename O = Reader, typename DATA = double>
123 {
124 public:
126 
127 #ifdef SWIGPYTHON
128  IteratorProxy() : iter_(), row_(*this) {}
129 #endif
130 
131  IteratorProxy(ITERATOR* iter) : iter_(iter), row_(*this)
132  { if(iter_) ++iter_->refCount_; }
133 
134  IteratorProxy(const IteratorProxy& other) : iter_(other.iter_), row_(*this)
135  { if (iter_) ++iter_->refCount_; }
136 
138  {
139  if(iter_ && (--iter_->refCount_ == 0))
140  delete iter_;
141  }
142 
144  {
145  if (iter_ == other.iter_)
146  return *this;
147 
148  if (iter_ && (--iter_->refCount_ == 0))
149  delete iter_;
150 
151  iter_ = other.iter_;
152  ++iter_->refCount_;
153  return *this;
154  }
155 
156  Row* operator->() { return &row_; }
157  const Row* operator->() const { return &row_; }
158 
159  Row& operator*() { return row_; }
160  const Row& operator*() const { return row_; }
161 
162  // TODO: This will _ONLY_ work for testing against end(). AAAAAARGH.
163  bool operator!=(const IteratorProxy&) { return iter_ != 0 && !iter_->noMore_; }
164  bool operator==(const IteratorProxy& other) { return !(*this != other); }
165 
167  {
168  iter_->next();
169  return *this;
170  }
171 
172 #ifdef SWIGPYTHON
173  size_t __len__() { return iter_->columns().size(); }
174 
175  PyObject* getitem(const char* s)
176  {
177  std::string name(s);
178  if (iter_->columns().hasColumn(name))
179  return getitem(iter_->columns().columnIndex(name));
180  else
181  throw ODBIndexError();
182  }
183 
184  PyObject* getitem(int i)
185  {
186  Column& column = *iter_->columns()[i];
187  double d = iter_->data(i);
188  if (d == column.missingValue())
189  Py_RETURN_NONE;
190 
191  switch (column.type()) {
192  case api::STRING:
193  {
194  const char *s = reinterpret_cast<const char *>(&d);
195  size_t j = 0;
196  for (; j < sizeof(double) && s[j]; ++j)
197  ;
198  return PyString_FromStringAndSize(s, j);
199  }
200  case api::INTEGER: return PyLong_FromDouble(d);
201  case api::BITFIELD:
202  {
203  //cerr << "BITFIELD" << std::endl;
204  typedef unsigned long B;
205  char buf[sizeof(B) + 1];
206  char *s = buf;
207 
208  B n = d;
209  B mask = 1 << (sizeof(B) - 1);
210  for(size_t j = 0; j < sizeof(B); ++j)
211  {
212  *s++ = (n & mask) ? '1' : '0';
213  mask >>= 1;
214  }
215  buf[sizeof(B)] = 0;
216  return PyString_FromStringAndSize(buf, sizeof(B) + 1);
217  }
218  default: return PyFloat_FromDouble(d);
219  }
220  }
221 
222  PyObject* __getitem__(PyObject* i)
223  {
224  //cerr << "__getitem__: start: " << PyString_AsString(PyObject_Repr(i)) << std::endl;
225  if (PyTuple_Check(i))
226  {
227  Py_ssize_t n = PyTuple_Size(i);
228  PyObject* l = PyTuple_New(n);
229  for(int j (0); j < n; ++j)
230  {
231  PyObject* o = PyTuple_GetItem(i, j);
232  PyTuple_SetItem(l, j, __getitem__(o));
233  }
234  return l;
235  }
236  if (PyList_Check(i))
237  {
238  Py_ssize_t n (PyList_Size(i));
239  PyObject* l (PyTuple_New(n));
240  for(ssize_t j (0); j < n; ++j)
241  {
242  PyObject* o (PyList_GetItem(i, j));
243  PyTuple_SetItem(l, j, __getitem__(o));
244  }
245  return l;
246  }
247  if (PyString_Check(i))
248  {
249  //cerr << "__getitem__: start: PyString " << PyString_AsString(PyObject_Repr(i)) << std::endl;
250  return getitem(PyString_AsString(i));
251  }
252  if (PySlice_Check(i))
253  {
254  //cerr << "__getitem__: we've got a PySliceObject here: ";
255  return getslice((PySliceObject*) i);
256  }
257 
258  long li = PyLong_AsLong(i);
259  return getitem(li);
260  }
261 
262  PyObject* getslice(PySliceObject* slice)
263  {
264  //cerr << "__getslice__(PySliceObject*):" << std::endl;
265  Py_ssize_t start = 0, stop = 0, step = 0, slicelength = 0;
266  PySlice_GetIndicesEx(slice, __len__(), &start, &stop, &step, &slicelength);
267 
268  return getslice(start, stop, step, slicelength);
269  }
270 
271  PyObject* getslice(Py_ssize_t start, Py_ssize_t stop, Py_ssize_t step, Py_ssize_t slicelength)
272  {
273  ssize_t maxIndex = __len__();
274  if (start < 0 || start > maxIndex) throw ODBIndexError();
275  if (stop < 0 || stop > maxIndex) throw ODBIndexError();
276 
277  //cerr << "__getslice__: start=" << start << ", stop=" << stop << ", step=" << step << ", slicelength=" << slicelength << std::endl;
278 
279  size_t outputSize = 0;
280  for (int index = start; (step > 0) ? (index < stop) : (index > stop); index += step)
281  ++outputSize;
282  PyObject* l = PyList_New(outputSize);
283 
284  size_t outIndex = 0;
285  for (int index = start; (step > 0) ? (index < stop) : (index > stop); index += step)
286  {
287  ASSERT(outIndex < outputSize);
288  PyList_SetItem(l, outIndex++, getitem(index));
289  }
290  return l;
291  }
292 
293  IteratorProxy __iter__() { return *this; }
294  IteratorProxy __next__() { return next(); }
295  IteratorProxy next()
296  {
297  if (! iter_->next())
298  throw ODBStopIteration();
299  return *this;
300  }
301 #endif
302 
303 //private:
304  ITERATOR *iter_;
306 
307  friend class ReaderIterator;
309  friend std::ostream& operator<<(std::ostream &o, const IteratorProxy& it) {
310  for (size_t i = 0; i < it.iter_->columns().size(); ++i)
311  o << it.iter_->data(i) << "\t";
312  return o;
313  }
314 };
315 
316 //----------------------------------------------------------------------------------------------------------------------
317 
318 
319 } // namespace odc
320 
321 #endif
const Row * operator->() const
bool operator==(const IteratorProxy &other)
IteratorProxy & operator=(const IteratorProxy &other)
IteratorProxy(const IteratorProxy &other)
IteratorProxy & operator++()
bool operator!=(const IteratorProxy &)
IteratorProxy(ITERATOR *iter)
friend std::ostream & operator<<(std::ostream &o, const IteratorProxy &it)
Row_< ITERATOR, O, DATA, IteratorProxy > Row
friend class MetaDataReaderIterator
const Row & operator*() const
void missingValue(size_t index, double v)
bool isNewDataset()
Definition: IteratorProxy.h:97
DATA & operator[](size_t i)
Definition: IteratorProxy.h:75
double missingValue(size_t i)
Definition: IteratorProxy.h:99
size_t dataSizeDoubles(size_t i) const
Definition: IteratorProxy.h:92
DATA & data(size_t i)
Definition: IteratorProxy.h:78
ITERATOR_PROXY * it_
void writeHeader()
Row_(ITERATOR_PROXY &it)
Definition: IteratorProxy.h:73
int integer(size_t i)
Definition: IteratorProxy.h:83
void setNumberOfColumns(size_t n)
Definition: IteratorProxy.h:95
const std::map< std::string, std::string > & properties() const
unsigned long pass1(T b, const T e)
std::string string(int i)
Definition: IteratorProxy.h:84
const DATA * data() const
Definition: IteratorProxy.h:80
const core::MetaData & columns(const core::MetaData &md)
Definition: IteratorProxy.h:96
DATA * data()
Definition: IteratorProxy.h:77
const core::MetaData & columns() const
Definition: IteratorProxy.h:94
void close()
ITERATOR & operator*()
const DATA & data(size_t i) const
Definition: IteratorProxy.h:81
size_t dataOffset(size_t i) const
Definition: IteratorProxy.h:91
int setColumn(size_t index, const std::string &name, api::ColumnType type)
bool isMissing(size_t i)
Definition: IteratorProxy.h:98
int setBitfieldColumn(size_t index, const std::string &name, api::ColumnType type, eckit::sql::BitfieldDef b)
@ BITFIELD
Definition: ColumnType.h:27
Definition: ColumnInfo.h:23
void odb_start()
Definition: odccapi.cc:74