1// PyView.cpp --
2// $Id: PyView.cpp 1230 2007-03-09 15:58:53Z jcw $
3// This is part of MetaKit, the homepage is http://www.equi4.com/metakit.html
4// Copyright (C) 1999-2004 Gordon McMillan and Jean-Claude Wippler.
5//
6//  View class implementation
7//  setsize method added by J. Barnard
8
9#include "PyView.h"
10#include "PyProperty.h"
11#include "PyRowRef.h"
12#include <PWOMSequence.h>
13#include <PWONumber.h>
14#include <PWOMapping.h>
15#include <PWOCallable.h>
16
17// see pep 353 at http://www.python.org/dev/peps/pep-0353/
18#if PY_VERSION_HEX < 0x02050000
19typedef int Py_ssize_t;
20#define PY_SSIZE_T_MAX INT_MAX
21#define PY_SSIZE_T_MIN INT_MIN
22#endif
23
24static void MustBeView(PyObject *o) {
25  if (!PyGenericView_Check(o))
26    Fail(PyExc_TypeError, "Arg must be a view object");
27}
28
29static char *setsize__doc =
30  "setsize(nrows) -- adjust the number of rows in a view";
31
32static PyObject *PyView_setsize(PyView *o, PyObject *_args) {
33  try {
34    PWOSequence args(_args);
35    if (args.len() != 1)
36      Fail(PyExc_TypeError, "setsize() takes exactly one argument");
37    PWONumber nrows = PWONumber(args[0]);
38    o->SetSize((int)nrows);
39    return nrows.disOwn();
40  } catch (...) {
41    return 0;
42  }
43}
44
45static char *structure__doc = "structure() -- return list of properties";
46
47static PyObject *PyView_structure(PyView *o, PyObject *_args) {
48  try {
49    PWOSequence args(_args);
50    if (args.len() != 0)
51      Fail(PyExc_TypeError, "method takes no arguments");
52    return o->structure();
53  } catch (...) {
54    return 0;
55  }
56}
57
58static char *properties__doc =
59  "properties() -- return a dictionary mapping property names to property objects";
60
61static PyObject *PyView_properties(PyView *o, PyObject *_args) {
62  try {
63    PWOSequence args(_args);
64    if (args.len() != 0)
65      Fail(PyExc_TypeError, "method takes no arguments");
66    return o->properties();
67  } catch (...) {
68    return 0;
69  }
70}
71
72static char *insert__doc =
73  "insert(position, obj) -- coerce obj (or keyword args) to row and insert before position";
74
75static PyObject *PyView_insert(PyView *o, PyObject *_args, PyObject *kwargs) {
76  try {
77    PWOSequence args(_args);
78    int argcount = args.len();
79    if (argcount == 0 || argcount > 2) {
80      Fail(PyExc_TypeError,
81        "insert() takes exactly two arguments, or one argument and keyword arguments");
82    } else {
83      int size = PWONumber(o->GetSize()), ndx = PWONumber(args[0]);
84      if (ndx < 0) {
85        ndx += size;
86        if (ndx < 0) {
87          ndx = 0;
88        }
89      } else if (ndx > size) {
90        ndx = size;
91      }
92      if (argcount == 1)
93        o->insertAt(ndx, kwargs);
94      else if (argcount == 2)
95        o->insertAt(ndx, args[1]);
96      Py_INCREF(Py_None);
97      return Py_None;
98    }
99  } catch (...){}
100  return 0; /* satisfy compiler */
101}
102
103static char *append__doc =
104  "append(obj) -- coerce obj (or keyword args) to row and append, returns position";
105
106static PyObject *PyView_append(PyView *o, PyObject *_args, PyObject *kwargs) {
107  try {
108    PWOSequence args(_args);
109    PWONumber ndx(o->GetSize());
110    int argcount = args.len();
111    if (argcount == 0)
112      o->insertAt(ndx, kwargs);
113    else if (argcount == 1)
114      o->insertAt(ndx, args[0]);
115    else
116      Fail(PyExc_TypeError,
117        "append() takes exactly one argument, or multiple keyword arguments");
118    return ndx.disOwn();
119  } catch (...) {
120    return 0;
121  }
122}
123
124static char *delete__doc =
125  "delete(position) -- delete row at specified position";
126
127static PyObject *PyView_delete(PyView *o, PyObject *_args) {
128  try {
129    PWOSequence args(_args);
130    int ndx = PWONumber(args[0]);
131    PWOTuple seq;
132    o->setSlice(ndx, ndx + 1, seq);
133    Py_INCREF(Py_None);
134    return Py_None;
135  } catch (...) {
136    return 0;
137  }
138}
139
140static char *addproperty__doc =
141  "addproperty(property) -- add temp column to view (use getas() for persistent columns)";
142
143static PyObject *PyView_addproperty(PyView *o, PyObject *_args) {
144  try {
145    PWOSequence args(_args);
146    PWOBase prop(args[0]);
147    if (!PyProperty_Check((PyObject*)prop))
148      Fail(PyExc_TypeError, "Not a Property object");
149    PWONumber rslt(o->AddProperty(*(PyProperty*)(PyObject*)prop));
150    return rslt.disOwn();
151  } catch (...) {
152    return 0;
153  }
154}
155
156static char *select__doc =
157  "select(criteria) -- return virtual view with selected rows\n"
158  "select(crit_lo, crit_hi) -- select rows in specified range (inclusive)\n"
159  "  criteria may be keyword args or dictionary";
160
161static PyObject *PyView_select(PyView *o, PyObject *_args, PyObject *kwargs) {
162  try {
163    c4_Row temp;
164    PWOSequence args(_args);
165    if (args.len() == 0) {
166      o->makeRow(temp, kwargs, false);
167      return new PyView(o->Select(temp), o, o->computeState(NOTIFIABLE));
168    }
169    if (args.len() == 1) {
170      o->makeRow(temp, args[0], false);
171      return new PyView(o->Select(temp), o, o->computeState(NOTIFIABLE));
172    }
173
174    if (PyObject_Length(args[0]) > 0)
175      o->makeRow(temp, args[0], false);
176
177    c4_Row temp2; // force an error if neither boundary has useful values
178    if (temp.Container().NumProperties() == 0 || PyObject_Length(args[1]) > 0)
179      o->makeRow(temp2, args[1], false);
180
181    return new PyView(o->SelectRange(temp, temp2), o, o->computeState
182      (NOTIFIABLE));
183  } catch (...) {
184    return 0;
185  }
186}
187
188static char *sort__doc =
189  "sort() -- return virtual sorted view (native key order)\n"
190  "sort(property...) -- sort on the specified properties";
191
192static PyObject *PyView_sort(PyView *o, PyObject *_args) {
193  try {
194    PWOSequence args(_args);
195    if (args.len()) {
196      PyView crit;
197      crit.addProperties(args);
198      return new PyView(o->SortOn(crit), o, o->computeState(FINALNOTIFIABLE));
199    }
200    return new PyView(o->Sort(), o, o->computeState(FINALNOTIFIABLE));
201  } catch (...) {
202    return 0;
203  }
204}
205
206static char *sortrev__doc =
207  "sortrev(props,propsdown) -- return sorted view, with optional reversed order\n"" arguments are lists of properties";
208
209static PyObject *PyView_sortrev(PyView *o, PyObject *_args) {
210  try {
211    PWOSequence args(_args);
212
213    PWOSequence all(args[0]);
214    PyView propsAll;
215    propsAll.addProperties(all);
216
217    PWOSequence down(args[1]);
218    PyView propsDown;
219    propsDown.addProperties(down);
220
221    return new PyView(o->SortOnReverse(propsAll, propsDown), 0, o->computeState
222      (FINALNOTIFIABLE));
223  } catch (...) {
224    return 0;
225  }
226}
227
228static char *project__doc =
229  "project(property...) -- returns virtual view with only the named columns";
230
231static PyObject *PyView_project(PyView *o, PyObject *_args) {
232  try {
233    PWOSequence args(_args);
234    PyView crit;
235    crit.addProperties(args);
236    return new PyView(o->Project(crit), 0, o->computeState(NOTIFIABLE));
237  } catch (...) {
238    return 0;
239  }
240}
241
242static char *flatten__doc =
243  "flatten(subview_property, outer) -- produces 'flat' view from nested view\n"
244  " outer defaults to 0";
245
246static PyObject *PyView_flatten(PyView *o, PyObject *_args, PyObject *_kwargs) {
247  try {
248    PWOSequence args(_args);
249    PWOMapping kwargs;
250    if (_kwargs)
251      kwargs = PWOBase(_kwargs);
252    if (!PyProperty_Check((PyObject*)args[0]))
253      Fail(PyExc_TypeError,
254        "First arg must be a property object identifying the subview");
255    const c4_Property &subview = *(PyProperty*)(PyObject*)args[0];
256    bool outer = false;
257    if (args.len() > 1) {
258      PWONumber flag(args[1]);
259      if ((int)flag > 0)
260        outer = true;
261    }
262    if (kwargs.hasKey("outer")) {
263      if (int(PWONumber(kwargs["outer"])))
264        outer = true;
265    }
266    return new PyView(o->JoinProp((const c4_ViewProp &)subview, outer), 0, o
267      ->computeState(ROVIEWER));
268  } catch (...) {
269    return 0;
270  }
271}
272
273static char *join__doc =
274  "join(otherview, property..., outer) -- join views on properties of same name and type\n"" outer defaults to 0";
275
276static PyObject *PyView_join(PyView *o, PyObject *_args, PyObject *_kwargs) {
277  PWOMapping kwargs;
278  try {
279    PWOSequence args(_args);
280    if (_kwargs)
281      kwargs = PWOBase(_kwargs);
282    MustBeView(args[0]);
283    PyView *other = (PyView*)(PyObject*)args[0];
284    bool outer = false;
285    int last = args.len();
286    if (PyInt_Check((PyObject*)args[last - 1])) {
287      PWONumber flag(args[--last]);
288      if ((int)flag > 0)
289        outer = true;
290    }
291    if (kwargs.hasKey("outer")) {
292      if (int(PWONumber(kwargs["outer"])))
293        outer = true;
294    }
295    PyView crit;
296    crit.addProperties(args.getSlice(1, last));
297    return new PyView(o->Join(crit,  *other, outer), 0, o->computeState
298      (ROVIEWER));
299  } catch (...) {
300    return 0;
301  }
302}
303
304static char *groupby__doc =
305  "groupby(property..., 'subname') -- group by given properties, creating subviews";
306
307static PyObject *PyView_groupby(PyView *o, PyObject *_args) {
308  try {
309    PWOSequence args(_args);
310    int last = args.len();
311    PWOString subname(args[--last]);
312    PyView crit;
313    crit.addProperties(args.getSlice(0, last));
314    c4_ViewProp sub(subname);
315    return new PyView(o->GroupBy(crit, sub), 0, o->computeState(ROVIEWER));
316  } catch (...) {
317    return 0;
318  }
319}
320
321static char *counts__doc =
322  "counts(property..., 'name') -- group by given properties, adding a count property";
323
324static PyObject *PyView_counts(PyView *o, PyObject *_args) {
325  try {
326    PWOSequence args(_args);
327    int last = args.len();
328    PWOString name(args[--last]);
329    PyView crit;
330    crit.addProperties(args.getSlice(0, last));
331    c4_IntProp count(name);
332    return new PyView(o->Counts(crit, count), 0, o->computeState(ROVIEWER));
333  } catch (...) {
334    return 0;
335  }
336}
337
338static char *rename__doc =
339  "rename('oldname', 'newname') -- derive a view with one property renamed";
340
341static PyObject *PyView_rename(PyView *o, PyObject *_args) {
342  try {
343    PWOSequence args(_args);
344
345    PWOString oldName(args[0]);
346    int n = o->FindPropIndexByName(oldName);
347    if (n < 0)
348      Fail(PyExc_TypeError, "Property not found in view");
349    const c4_Property &oProp = o->NthProperty(n);
350
351    PWOString newName(args[1]);
352    c4_Property nProp(oProp.Type(), newName);
353
354    return new PyView(o->Rename(oProp, nProp), 0, o->computeState(RWVIEWER));
355  } catch (...) {
356    return 0;
357  }
358}
359
360static char *unique__doc =
361  "unique() -- returns a view without duplicate rows, i.e. a set";
362
363static PyObject *PyView_unique(PyView *o, PyObject *_args) {
364  try {
365    return new PyView(o->Unique(), 0, o->computeState(ROVIEWER));
366  } catch (...) {
367    return 0;
368  }
369}
370
371static char *product__doc =
372  "product(view2) -- produce the cartesian product of both views";
373
374static PyObject *PyView_product(PyView *o, PyObject *_args) {
375  try {
376    PWOSequence args(_args);
377    MustBeView(args[0]);
378    return new PyView(o->Product(*(PyView*)(PyObject*)args[0]), 0, o
379      ->computeState(ROVIEWER));
380  } catch (...) {
381    return 0;
382  }
383}
384
385static char *union__doc = "union(view2) -- produce the set union of both views";
386
387static PyObject *PyView_union(PyView *o, PyObject *_args) {
388  try {
389    PWOSequence args(_args);
390    MustBeView(args[0]);
391    return new PyView(o->Union(*(PyView*)(PyObject*)args[0]), 0, o
392      ->computeState(ROVIEWER));
393  } catch (...) {
394    return 0;
395  }
396}
397
398static char *intersect__doc =
399  "intersect(view2) -- produce the set intersection of both views";
400
401static PyObject *PyView_intersect(PyView *o, PyObject *_args) {
402  try {
403    PWOSequence args(_args);
404    MustBeView(args[0]);
405    return new PyView(o->Intersect(*(PyView*)(PyObject*)args[0]), 0, o
406      ->computeState(ROVIEWER));
407  } catch (...) {
408    return 0;
409  }
410}
411
412static char *different__doc =
413  "different(view2) -- produce the set difference of both views (XOR)";
414
415static PyObject *PyView_different(PyView *o, PyObject *_args) {
416  try {
417    PWOSequence args(_args);
418    MustBeView(args[0]);
419    return new PyView(o->Different(*(PyView*)(PyObject*)args[0]), 0, o
420      ->computeState(ROVIEWER));
421  } catch (...) {
422    return 0;
423  }
424}
425
426static char *minus__doc = "minus(view2) -- all rows in view, but not in view2";
427
428static PyObject *PyView_minus(PyView *o, PyObject *_args) {
429  try {
430    PWOSequence args(_args);
431    MustBeView(args[0]);
432    return new PyView(o->Minus(*(PyView*)(PyObject*)args[0]), 0, o
433      ->computeState(ROVIEWER));
434  } catch (...) {
435    return 0;
436  }
437}
438
439static char *remapwith__doc =
440  "remapwith(view2) -- remap rows according to first (int) prop in view2";
441
442static PyObject *PyView_remapwith(PyView *o, PyObject *_args) {
443  try {
444    PWOSequence args(_args);
445    MustBeView(args[0]);
446    return new PyView(o->RemapWith(*(PyView*)(PyObject*)args[0]), 0, o
447      ->computeState(RWVIEWER));
448  } catch (...) {
449    return 0;
450  }
451}
452
453static char *pair__doc =
454  "pair(view2) -- concatenate rows pairwise, side by side";
455
456static PyObject *PyView_pair(PyView *o, PyObject *_args) {
457  try {
458    PWOSequence args(_args);
459    MustBeView(args[0]);
460    return new PyView(o->Pair(*(PyView*)(PyObject*)args[0]), 0, o->computeState
461      (MVIEWER));
462  } catch (...) {
463    return 0;
464  }
465}
466
467static char *hash__doc =
468  "hash(mapview,numkeys) -- create a hashed view mapping\n"
469  " numkeys defaults to 1\n"
470  " without args, creates a temporary hash on one key";
471
472static PyObject *PyView_hash(PyView *o, PyObject *_args) {
473  try {
474    PWOSequence args(_args);
475
476    c4_View map;
477    if (args.len() > 0) {
478      MustBeView(args[0]);
479      map = *(PyView*)(PyObject*)args[0];
480    }
481    int numkeys = args.len() <= 1 ? 1 : (int)PWONumber(args[1]);
482    return new PyView(o->Hash(map, numkeys), 0, o->computeState(MVIEWER));
483  } catch (...) {
484    return 0;
485  }
486}
487
488static char *blocked__doc =
489  "blocked() -- create a blocked/balanced view mapping";
490
491static PyObject *PyView_blocked(PyView *o, PyObject *_args) {
492  try {
493    return new PyView(o->Blocked(), 0, o->computeState(MVIEWER));
494  } catch (...) {
495    return 0;
496  }
497}
498
499static char *ordered__doc =
500  "ordered(numkeys) -- create a order-maintaining view mapping\n"
501  " numkeys defaults to 1";
502
503static PyObject *PyView_ordered(PyView *o, PyObject *_args) {
504  try {
505    PWOSequence args(_args);
506    int numkeys = args.len() <= 0 ? 1 : (int)PWONumber(args[0]);
507    return new PyView(o->Ordered(numkeys), 0, o->computeState(MVIEWER));
508  } catch (...) {
509    return 0;
510  }
511}
512
513static char *indexed__doc =
514  "indexed(map, property..., unique) -- create a mapped view which manages an index\n"" unique defaults to 0 (not unique)";
515
516static PyObject *PyView_indexed(PyView *o, PyObject *_args) {
517  try {
518    PWOSequence args(_args);
519    MustBeView(args[0]);
520    PyView *other = (PyView*)(PyObject*)args[0];
521    bool unique = false;
522    int last = args.len();
523    if (PyInt_Check((PyObject*)args[last - 1])) {
524      PWONumber flag(args[--last]); //XXX kwargs?
525      if ((int)flag > 0)
526        unique = true;
527    }
528    PyView crit;
529    crit.addProperties(args.getSlice(1, last));
530    return new PyView(o->Indexed(crit,  *other, unique), 0, o->computeState
531      (MVIEWER));
532  } catch (...) {
533    return 0;
534  }
535}
536
537static char *find__doc =
538  "find(criteria, start) -- return index of row found, matching criteria\n"
539  " criteria maybe keyword args, or a dictionary";
540
541static PyObject *PyView_find(PyView *o, PyObject *_args, PyObject *_kwargs) {
542  PWONumber start(0);
543  PWOMapping crit;
544  try {
545    PWOSequence args(_args);
546    if (_kwargs) {
547      PWOMapping kwargs(_kwargs);
548      if (kwargs.hasKey("start")) {
549        start = kwargs["start"];
550        kwargs.delItem("start");
551      }
552      crit = kwargs;
553    }
554    int numargs = args.len();
555    for (int i = 0; i < numargs; ++i) {
556      if (PyNumber_Check((PyObject*)args[i]))
557        start = args[i];
558      else
559        crit = args[i];
560    }
561    c4_Row temp;
562    o->makeRow(temp, crit, false);
563    return PWONumber(o->Find(temp, start)).disOwn();
564  } catch (...) {
565    return 0;
566  }
567}
568
569static char *search__doc =
570  "search(criteria) -- binary search (native view order), returns match or insert pos";
571
572static PyObject *PyView_search(PyView *o, PyObject *_args, PyObject *kwargs) {
573  try {
574    PWOSequence args(_args);
575    if (args.len() != 0)
576      kwargs = args[0];
577    c4_Row temp;
578    o->makeRow(temp, kwargs, false);
579    return PWONumber(o->Search(temp)).disOwn();
580  } catch (...) {
581    return 0;
582  }
583}
584
585static char *locate__doc =
586  "locate(criteria) -- binary search, returns tuple with pos and count";
587
588static PyObject *PyView_locate(PyView *o, PyObject *_args, PyObject *kwargs) {
589  try {
590    PWOSequence args(_args);
591    if (args.len() != 0)
592      kwargs = args[0];
593    c4_Row temp;
594    o->makeRow(temp, kwargs, false);
595    int pos = 0;
596    PWONumber n(o->Locate(temp, &pos));
597    PWONumber r(pos);
598    PWOTuple tmp(2);
599    tmp.setItem(0, r);
600    tmp.setItem(1, n);
601    return tmp.disOwn();
602  } catch (...) {
603    return 0;
604  }
605}
606
607static char *access__doc =
608  "access(memoprop, rownum, offset, length=0) -- get (partial) memo property contents";
609
610static PyObject *PyView_access(PyView *o, PyObject *_args) {
611  try {
612    PWOSequence args(_args);
613    if (!PyProperty_Check((PyObject*)args[0]))
614      Fail(PyExc_TypeError, "First arg must be a property");
615
616    c4_BytesProp &prop = *(c4_BytesProp*)(c4_Property*)(PyProperty*)(PyObject*)
617      args[0];
618
619    int index = PyInt_AsLong(args[1]);
620    if (index < 0 || index >= o->GetSize())
621      Fail(PyExc_IndexError, "Index out of range");
622
623    c4_RowRef row = o->GetAt(index);
624
625    long offset = PyInt_AsLong(args[2]);
626    int length = args.len() == 3 ? 0 : PyInt_AsLong(args[3]);
627    if (length <= 0) {
628      length = prop(row).GetSize() - offset;
629      if (length < 0)
630        length = 0;
631    }
632
633    PyObject *buffer = PyString_FromStringAndSize(0, length);
634    int o = 0;
635
636    while (o < length) {
637      c4_Bytes buf = prop(row).Access(offset + o, length - o);
638      int n = buf.Size();
639      if (n == 0)
640        break;
641      memcpy(PyString_AS_STRING(buffer) + o, buf.Contents(), n);
642      o += n;
643    }
644
645    if (o < length)
646      _PyString_Resize(&buffer, o);
647
648    return buffer;
649  } catch (...) {
650    return 0;
651  }
652}
653
654static char *modify__doc =
655  "modify(memoprop, rownum, string, offset, diff=0) -- store (partial) memo contents\n""diff removes (<0) or inserts (>0) bytes, and is adjusted to within sensible range";
656
657static PyObject *PyView_modify(PyView *o, PyObject *_args) {
658  try {
659    PWOSequence args(_args);
660    if (!PyProperty_Check((PyObject*)args[0]))
661      Fail(PyExc_TypeError, "First arg must be a property");
662
663    c4_BytesProp &prop = *(c4_BytesProp*)(c4_Property*)(PyProperty*)(PyObject*)
664      args[0];
665
666    int index = PWONumber(args[1]);
667    if (index < 0 || index >= o->GetSize())
668      Fail(PyExc_IndexError, "Index out of range");
669
670    c4_RowRef row = o->GetAt(index);
671
672    PWOString buffer(args[2]);
673    c4_Bytes data((void*)(const char*)buffer, buffer.len());
674
675    long offset = PWONumber(args[3]);
676    int diff = args.len() == 4 ? 0 : (int)PWONumber(args[4]);
677
678    if (!prop(row).Modify(data, offset, diff))
679      Fail(PyExc_TypeError, "Failed to modify memo field");
680
681    Py_INCREF(Py_None);
682    return Py_None;
683  } catch (...) {
684    return 0;
685  }
686}
687
688static char *itemsize__doc =
689  "itemsize(prop, rownum=0) -- return size of item (rownum only needed for S/B/M types)\n""with integer fields, a result of -1/-2/-4 means 1/2/4 bits per value, respectively";
690
691static PyObject *PyView_itemsize(PyView *o, PyObject *_args) {
692  try {
693    PWOSequence args(_args);
694    if (!PyProperty_Check((PyObject*)args[0]))
695      Fail(PyExc_TypeError, "First arg must be a property");
696
697    c4_BytesProp &prop = *(c4_BytesProp*)(c4_Property*)(PyProperty*)(PyObject*)
698      args[0];
699    int index = args.len() == 1 ? 0 : (int)PWONumber(args[1]);
700    if (index < 0 || index >= o->GetSize())
701      Fail(PyExc_IndexError, "Index out of range");
702
703    return PWONumber(prop(o->GetAt(index)).GetSize()).disOwn();
704  } catch (...) {
705    return 0;
706  }
707}
708
709static char *relocrows__doc =
710  "relocrows(from, count, dest, pos) -- relocate rows within views of same storage\n""from is source offset, count is number of rows, pos is destination offset\n""both views must have a compatible structure (field names may differ)";
711
712static PyObject *PyView_relocrows(PyView *o, PyObject *_args) {
713  try {
714    PWOSequence args(_args);
715    if (!PyView_Check((PyObject*)args[2]))
716      Fail(PyExc_TypeError, "Third arg must be a view object");
717
718    PyView &dest = *(PyView*)(PyObject*)args[2];
719
720    int from = PWONumber(args[0]);
721    if (from < 0)
722      from += o->GetSize();
723    int count = PWONumber(args[1]);
724    if (from < 0 || count < 0 || from + count > o->GetSize())
725      Fail(PyExc_IndexError, "Source index out of range");
726
727    int pos = PWONumber(args[3]);
728    if (pos < 0)
729      pos += dest.GetSize();
730    if (pos < 0 || pos > dest.GetSize())
731      Fail(PyExc_IndexError, "Destination index out of range");
732
733    if (!o->IsCompatibleWith(dest))
734      Fail(PyExc_TypeError, "Views are not compatible");
735
736    o->RelocateRows(from, count, dest, pos);
737
738    Py_INCREF(Py_None);
739    return Py_None;
740  } catch (...) {
741    return 0;
742  }
743}
744
745static char *map__doc =
746  "map(func, subset=None) -- apply func to each row of view,\n"
747  "or (if subset specified) to each row in view that is also in subset.\n"
748  "Returns None: view is mutated\n"
749  "func must have the signature func(row), and may mutate row.\n"
750  "subset must be a subset of view: eg, customers.map(func, customers.select(....)).\n";
751
752static PyObject *PyView_map(PyView *o, PyObject *_args) {
753  try {
754    PWOSequence args(_args);
755    PWOCallable func(args[0]);
756    if (args.len() > 1) {
757      if (!PyView_Check((PyObject*)args[1]))
758        Fail(PyExc_TypeError, "Second arg must be a view object");
759
760      PyView &subset = *(PyView*)(PyObject*)args[1];
761
762      o->map(func, subset);
763    } else
764      o->map(func);
765
766    Py_INCREF(Py_None);
767    return Py_None;
768  } catch (...) {
769    return 0;
770  }
771}
772
773static char *filter__doc =
774  "filter(func) -- return a new view containing the indices of those rows satisfying func.\n""  func must have the signature func(row), and should return a false value to omit row.";
775
776static PyObject *PyView_filter(PyView *o, PyObject *_args) {
777  try {
778    PWOSequence args(_args);
779    PWOCallable func(args[0]);
780    return o->filter(func);
781  } catch (...) {
782    return 0;
783  }
784}
785
786static char *reduce__doc =
787  "reduce(func, start=0) -- return the result of applying func(row, lastresult) to\n""each row in view.\n";
788
789static PyObject *PyView_reduce(PyView *o, PyObject *_args) {
790  try {
791    PWOSequence args(_args);
792    PWOCallable func(args[0]);
793    PWONumber start(0);
794    if (args.len() > 1)
795      start = args[1];
796    return o->reduce(func, start);
797  } catch (...) {
798    return 0;
799  }
800}
801
802static char *remove__doc =
803  "remove(indices) -- remove all rows whose indices are in subset from view\n"
804  "Not the same as minus, because unique is not required, and view is not reordered.\n";
805
806static PyObject *PyView_remove(PyView *o, PyObject *_args) {
807  try {
808    PWOSequence args(_args);
809    MustBeView(args[0]);
810
811    PyView &subset = *(PyView*)(PyObject*)args[0];
812    o->remove(subset);
813    Py_INCREF(Py_None);
814    return Py_None;
815  } catch (...) {
816    return 0;
817  }
818}
819
820static char *indices__doc =
821  "indices(subset) -- returns a view containing the indices in view of the rows of subset";
822
823static PyObject *PyView_indices(PyView *o, PyObject *_args) {
824  try {
825    PWOSequence args(_args);
826    MustBeView(args[0]);
827
828    PyView &subset = *(PyView*)(PyObject*)args[0];
829    return o->indices(subset);
830  } catch (...) {
831    return 0;
832  }
833}
834
835static char *copy__doc = "copy() -- returns a copy of the view\n";
836
837static PyObject *PyView_copy(PyView *o, PyObject *_args) {
838  try {
839    return new PyView(o->Duplicate());
840  } catch (...) {
841    return 0;
842  }
843}
844
845static PyMethodDef ViewMethods[] =  {
846   {
847    "setsize", (PyCFunction)PyView_setsize, METH_VARARGS, setsize__doc
848  }
849  ,  {
850    "insert", (PyCFunction)PyView_insert, METH_VARARGS | METH_KEYWORDS,
851      insert__doc
852  }
853  ,  {
854    "append", (PyCFunction)PyView_append, METH_VARARGS | METH_KEYWORDS,
855      append__doc
856  }
857  ,  {
858    "delete", (PyCFunction)PyView_delete, METH_VARARGS, delete__doc
859  }
860  ,  {
861    "structure", (PyCFunction)PyView_structure, METH_VARARGS, structure__doc
862  }
863  ,  {
864    "select", (PyCFunction)PyView_select, METH_VARARGS | METH_KEYWORDS,
865      select__doc
866  }
867  ,  {
868    "addproperty", (PyCFunction)PyView_addproperty, METH_VARARGS,
869      addproperty__doc
870  }
871  ,  {
872    "sort", (PyCFunction)PyView_sort, METH_VARARGS, sort__doc
873  }
874  ,  {
875    "sortrev", (PyCFunction)PyView_sortrev, METH_VARARGS, sortrev__doc
876  }
877  ,  {
878    "project", (PyCFunction)PyView_project, METH_VARARGS, project__doc
879  }
880  ,  {
881    "flatten", (PyCFunction)PyView_flatten, METH_VARARGS | METH_KEYWORDS,
882      flatten__doc
883  }
884  ,  {
885    "join", (PyCFunction)PyView_join, METH_VARARGS | METH_KEYWORDS, join__doc
886  }
887  ,  {
888    "groupby", (PyCFunction)PyView_groupby, METH_VARARGS, groupby__doc
889  }
890  ,  {
891    "counts", (PyCFunction)PyView_counts, METH_VARARGS, counts__doc
892  }
893  ,  {
894    "product", (PyCFunction)PyView_product, METH_VARARGS, product__doc
895  }
896  ,  {
897    "union", (PyCFunction)PyView_union, METH_VARARGS, union__doc
898  }
899  ,  {
900    "intersect", (PyCFunction)PyView_intersect, METH_VARARGS, intersect__doc
901  }
902  ,  {
903    "different", (PyCFunction)PyView_different, METH_VARARGS, different__doc
904  }
905  ,  {
906    "minus", (PyCFunction)PyView_minus, METH_VARARGS, minus__doc
907  }
908  ,  {
909    "remapwith", (PyCFunction)PyView_remapwith, METH_VARARGS, remapwith__doc
910  }
911  ,  {
912    "pair", (PyCFunction)PyView_pair, METH_VARARGS, pair__doc
913  }
914  ,  {
915    "rename", (PyCFunction)PyView_rename, METH_VARARGS, rename__doc
916  }
917  ,  {
918    "unique", (PyCFunction)PyView_unique, METH_VARARGS, unique__doc
919  }
920  ,  {
921    "hash", (PyCFunction)PyView_hash, METH_VARARGS, hash__doc
922  }
923  ,  {
924    "blocked", (PyCFunction)PyView_blocked, METH_VARARGS, blocked__doc
925  }
926  ,  {
927    "ordered", (PyCFunction)PyView_ordered, METH_VARARGS, ordered__doc
928  }
929  ,  {
930    "indexed", (PyCFunction)PyView_indexed, METH_VARARGS, indexed__doc
931  }
932  ,  {
933    "find", (PyCFunction)PyView_find, METH_VARARGS | METH_KEYWORDS, find__doc
934  }
935  ,  {
936    "search", (PyCFunction)PyView_search, METH_VARARGS | METH_KEYWORDS,
937      search__doc
938  }
939  ,  {
940    "locate", (PyCFunction)PyView_locate, METH_VARARGS | METH_KEYWORDS,
941      locate__doc
942  }
943  ,  {
944    "access", (PyCFunction)PyView_access, METH_VARARGS, access__doc
945  }
946  ,  {
947    "modify", (PyCFunction)PyView_modify, METH_VARARGS, modify__doc
948  }
949  ,  {
950    "itemsize", (PyCFunction)PyView_itemsize, METH_VARARGS, itemsize__doc
951  }
952  ,
953  // {"relocrows", (PyCFunction)PyView_relocrows, METH_VARARGS, relocrows__doc},
954   {
955    "map", (PyCFunction)PyView_map, METH_VARARGS, map__doc
956  }
957  ,  {
958    "filter", (PyCFunction)PyView_filter, METH_VARARGS, filter__doc
959  }
960  ,  {
961    "reduce", (PyCFunction)PyView_reduce, METH_VARARGS, reduce__doc
962  }
963  ,  {
964    "remove", (PyCFunction)PyView_remove, METH_VARARGS, remove__doc
965  }
966  ,  {
967    "indices", (PyCFunction)PyView_indices, METH_VARARGS, indices__doc
968  }
969  ,  {
970    "copy", (PyCFunction)PyView_copy, METH_VARARGS, copy__doc
971  }
972  ,  {
973    "properties", (PyCFunction)PyView_properties, METH_VARARGS, properties__doc
974  }
975  ,  {
976    0, 0, 0, 0
977  }
978};
979static PyMethodDef ViewerMethods[] =  {
980   {
981    "structure", (PyCFunction)PyView_structure, METH_VARARGS, structure__doc
982  }
983  ,  {
984    "select", (PyCFunction)PyView_select, METH_VARARGS | METH_KEYWORDS,
985      select__doc
986  }
987  ,  {
988    "addproperty", (PyCFunction)PyView_addproperty, METH_VARARGS,
989      addproperty__doc
990  }
991  ,  {
992    "sort", (PyCFunction)PyView_sort, METH_VARARGS, sort__doc
993  }
994  ,  {
995    "sortrev", (PyCFunction)PyView_sortrev, METH_VARARGS, sortrev__doc
996  }
997  ,  {
998    "project", (PyCFunction)PyView_project, METH_VARARGS, project__doc
999  }
1000  ,  {
1001    "flatten", (PyCFunction)PyView_flatten, METH_VARARGS | METH_KEYWORDS,
1002      flatten__doc
1003  }
1004  ,  {
1005    "join", (PyCFunction)PyView_join, METH_VARARGS | METH_KEYWORDS, join__doc
1006  }
1007  ,  {
1008    "groupby", (PyCFunction)PyView_groupby, METH_VARARGS, groupby__doc
1009  }
1010  ,  {
1011    "counts", (PyCFunction)PyView_counts, METH_VARARGS, counts__doc
1012  }
1013  ,  {
1014    "product", (PyCFunction)PyView_product, METH_VARARGS, product__doc
1015  }
1016  ,  {
1017    "union", (PyCFunction)PyView_union, METH_VARARGS, union__doc
1018  }
1019  ,  {
1020    "intersect", (PyCFunction)PyView_intersect, METH_VARARGS, intersect__doc
1021  }
1022  ,  {
1023    "different", (PyCFunction)PyView_different, METH_VARARGS, different__doc
1024  }
1025  ,  {
1026    "minus", (PyCFunction)PyView_minus, METH_VARARGS, minus__doc
1027  }
1028  ,  {
1029    "remapwith", (PyCFunction)PyView_remapwith, METH_VARARGS, remapwith__doc
1030  }
1031  ,  {
1032    "pair", (PyCFunction)PyView_pair, METH_VARARGS, pair__doc
1033  }
1034  ,  {
1035    "rename", (PyCFunction)PyView_rename, METH_VARARGS, rename__doc
1036  }
1037  ,  {
1038    "unique", (PyCFunction)PyView_unique, METH_VARARGS, unique__doc
1039  }
1040  ,  {
1041    "hash", (PyCFunction)PyView_hash, METH_VARARGS, hash__doc
1042  }
1043  ,  {
1044    "blocked", (PyCFunction)PyView_blocked, METH_VARARGS, blocked__doc
1045  }
1046  ,  {
1047    "ordered", (PyCFunction)PyView_ordered, METH_VARARGS, ordered__doc
1048  }
1049  ,  {
1050    "indexed", (PyCFunction)PyView_indexed, METH_VARARGS, indexed__doc
1051  }
1052  ,  {
1053    "find", (PyCFunction)PyView_find, METH_VARARGS | METH_KEYWORDS, find__doc
1054  }
1055  ,  {
1056    "search", (PyCFunction)PyView_search, METH_VARARGS | METH_KEYWORDS,
1057      search__doc
1058  }
1059  ,  {
1060    "locate", (PyCFunction)PyView_locate, METH_VARARGS | METH_KEYWORDS,
1061      locate__doc
1062  }
1063  ,  {
1064    "access", (PyCFunction)PyView_access, METH_VARARGS, access__doc
1065  }
1066  ,  {
1067    "modify", (PyCFunction)PyView_modify, METH_VARARGS, modify__doc
1068  }
1069  ,  {
1070    "itemsize", (PyCFunction)PyView_itemsize, METH_VARARGS, itemsize__doc
1071  }
1072  ,
1073  //{"map", (PyCFunction)PyView_map, METH_VARARGS, map__doc},
1074   {
1075    "filter", (PyCFunction)PyView_filter, METH_VARARGS, filter__doc
1076  }
1077  ,  {
1078    "reduce", (PyCFunction)PyView_reduce, METH_VARARGS, reduce__doc
1079  }
1080  ,  {
1081    "indices", (PyCFunction)PyView_indices, METH_VARARGS, indices__doc
1082  }
1083  ,  {
1084    "copy", (PyCFunction)PyView_copy, METH_VARARGS, copy__doc
1085  }
1086  ,  {
1087    "properties", (PyCFunction)PyView_properties, METH_VARARGS, properties__doc
1088  }
1089  ,  {
1090    0, 0, 0, 0
1091  }
1092};
1093
1094/*
1095Duplicate(deep=0)  (__copy__ and __deepcopy__ as methods, too)
1096Clone()
1097 */
1098static Py_ssize_t PyView_length(PyObject *_o) {
1099  PyView *o = (PyView*)_o;
1100
1101  try {
1102    return o->GetSize();
1103  } catch (...) {
1104    return  - 1;
1105  }
1106}
1107
1108static PyObject *PyView_concat(PyObject *_o, PyObject *_other) {
1109  PyView *o = (PyView*)_o;
1110  PyView *other = (PyView*)_other;
1111
1112  try {
1113    if (!PyGenericView_Check(other))
1114      Fail(PyExc_TypeError, "Not a PyView(er)");
1115    return new PyView(o->Concat(*other), 0, o->computeState(RWVIEWER));
1116  } catch (...) {
1117    return 0;
1118  }
1119}
1120
1121static PyObject *PyView_repeat(PyObject *_o, Py_ssize_t n) {
1122  PyView *o = (PyView*)_o;
1123
1124  try {
1125    PyView *tmp = new PyView(*o, 0, o->computeState(RWVIEWER));
1126    while (--n > 0) {
1127      //!! a huge stack of views?
1128      PyView *tmp1 = new PyView(tmp->Concat(*o), 0, o->computeState(RWVIEWER));
1129      delete tmp;
1130      tmp = tmp1;
1131    }
1132    return tmp;
1133  } catch (...) {
1134    return 0;
1135  }
1136}
1137
1138static PyObject *PyView_getitem(PyObject *_o, Py_ssize_t n) {
1139  PyView *o = (PyView*)_o;
1140
1141  try {
1142    PyObject *rslt = o->getItem(n);
1143    if (rslt == 0)
1144      PyErr_SetString(PyExc_IndexError, "row index out of range");
1145    return rslt;
1146  } catch (...) {
1147    return 0;
1148  }
1149}
1150
1151static PyObject *PyView_getslice(PyObject *_o, Py_ssize_t s, Py_ssize_t e) {
1152  PyView *o = (PyView*)_o;
1153
1154  try {
1155    return o->getSlice(s, e);
1156  } catch (...) {
1157    return 0;
1158  }
1159}
1160
1161static int PyView_setitem(PyObject *_o, Py_ssize_t n, PyObject *v) {
1162  PyView *o = (PyView*)_o;
1163
1164  try {
1165    if (n < 0)
1166      n += o->GetSize();
1167    if (n >= o->GetSize() || n < 0)
1168      Fail(PyExc_IndexError, "Index out of range");
1169    if (v == 0) {
1170      o->RemoveAt(n);
1171      return 0;
1172    }
1173
1174    return o->setItem(n, v);
1175  } catch (...) {
1176    return  - 1;
1177  }
1178}
1179
1180static int PyView_setslice(PyObject *_o, Py_ssize_t s, Py_ssize_t e, PyObject
1181  *v) {
1182  PyView *o = (PyView*)_o;
1183
1184  try {
1185    if (v == 0) {
1186      PWOTuple seq;
1187      return o->setSlice(s, e, seq);
1188    }
1189
1190    PWOSequence seq(v);
1191    return o->setSlice(s, e, seq);
1192  } catch (...) {
1193    return  - 1;
1194  }
1195}
1196
1197static PySequenceMethods ViewAsSeq =  {
1198  PyView_length,  //sq_length
1199  PyView_concat,  //sq_concat
1200  PyView_repeat,  //sq_repeat
1201  PyView_getitem,  //sq_item
1202  PyView_getslice,  //sq_slice
1203  PyView_setitem,  //sq_ass_item
1204  PyView_setslice,  //sq_ass_slice
1205};
1206
1207static PySequenceMethods ViewerAsSeq =  {
1208  PyView_length,  //sq_length
1209  PyView_concat,  //sq_concat
1210  PyView_repeat,  //sq_repeat
1211  PyView_getitem,  //sq_item
1212  PyView_getslice,  //sq_slice
1213  0,  //sq_ass_item
1214  0,  //sq_ass_slice
1215};
1216
1217static void PyView_dealloc(PyView *o) {
1218  //o->~PyView();
1219  delete o;
1220}
1221
1222static int PyView_print(PyView *o, FILE *f, int) {
1223  fprintf(f, "<PyView object at %p>", (void*)o);
1224  return 0;
1225}
1226
1227static int PyViewer_print(PyView *o, FILE *f, int) {
1228  fprintf(f, "<PyViewer object at %p>", (void*)o);
1229  return 0;
1230}
1231
1232static int PyROViewer_print(PyView *o, FILE *f, int) {
1233  fprintf(f, "<PyROViewer object at %p>", (void*)o);
1234  return 0;
1235}
1236
1237static PyObject *PyView_getattr(PyView *o, char *nm) {
1238  PyObject *rslt;
1239  try {
1240    rslt = Py_FindMethod(ViewMethods, o, nm);
1241    if (rslt)
1242      return rslt;
1243    PyErr_Clear();
1244    int ndx = o->FindPropIndexByName(nm);
1245    if (ndx >  - 1)
1246      return new PyProperty(o->NthProperty(ndx));
1247    Fail(PyExc_AttributeError, nm);
1248  } catch (...) {
1249    return 0;
1250  }
1251  return 0;
1252}
1253
1254static PyObject *PyViewer_getattr(PyView *o, char *nm) {
1255  PyObject *rslt;
1256  try {
1257    rslt = Py_FindMethod(ViewerMethods, o, nm);
1258    if (rslt)
1259      return rslt;
1260    PyErr_Clear();
1261    int ndx = o->FindPropIndexByName(nm);
1262    if (ndx >  - 1)
1263      return new PyProperty(o->NthProperty(ndx));
1264    Fail(PyExc_AttributeError, nm);
1265  } catch (...) {
1266    return 0;
1267  }
1268  return 0;
1269}
1270
1271
1272PyTypeObject PyViewtype =  {
1273  PyObject_HEAD_INIT(&PyType_Type)0, "PyView", sizeof(PyView), 0, (destructor)
1274    PyView_dealloc,  /*tp_dealloc*/
1275  (printfunc)PyView_print,  /*tp_print*/
1276  (getattrfunc)PyView_getattr,  /*tp_getattr*/
1277  0,  /*tp_setattr*/
1278  (cmpfunc)0,  /*tp_compare*/
1279  (reprfunc)0,  /*tp_repr*/
1280  0,  /*tp_as_number*/
1281   &ViewAsSeq,  /*tp_as_sequence*/
1282  0,  /*tp_as_mapping*/
1283};
1284PyTypeObject PyViewertype =  {
1285  PyObject_HEAD_INIT(&PyType_Type)0, "PyViewer", sizeof(PyView), 0, (destructor)
1286    PyView_dealloc,  /*tp_dealloc*/
1287  (printfunc)PyViewer_print,  /*tp_print*/
1288  (getattrfunc)PyViewer_getattr,  /*tp_getattr*/
1289  0,  /*tp_setattr*/
1290  (cmpfunc)0,  /*tp_compare*/
1291  (reprfunc)0,  /*tp_repr*/
1292  0,  /*tp_as_number*/
1293   &ViewerAsSeq,  /*tp_as_sequence*/
1294  0,  /*tp_as_mapping*/
1295};
1296PyTypeObject PyROViewertype =  {
1297  PyObject_HEAD_INIT(&PyType_Type)0, "PyROViewer", sizeof(PyView), 0,
1298    (destructor)PyView_dealloc,  /*tp_dealloc*/
1299  (printfunc)PyROViewer_print,  /*tp_print*/
1300  (getattrfunc)PyViewer_getattr,  /*tp_getattr*/
1301  0,  /*tp_setattr*/
1302  (cmpfunc)0,  /*tp_compare*/
1303  (reprfunc)0,  /*tp_repr*/
1304  0,  /*tp_as_number*/
1305   &ViewerAsSeq,  /*tp_as_sequence*/
1306  0,  /*tp_as_mapping*/
1307};
1308int PyView::computeState(int targettype) {
1309  int newtype = _state | targettype;
1310  if (newtype > FINALNOTIFIABLE)
1311    newtype = ROVIEWER;
1312  if (_state == FINALNOTIFIABLE)
1313    newtype = ROVIEWER;
1314  return newtype;
1315}
1316
1317PyTypeObject *getTypeObject(int type) {
1318  switch (type) {
1319    case BASE:
1320    case MVIEWER:
1321      return  &PyViewtype;
1322      break;
1323    case NOTIFIABLE:
1324    case RWVIEWER:
1325    case FINALNOTIFIABLE:
1326      return  &PyViewertype;
1327    case ROVIEWER:
1328      return  &PyROViewertype;
1329  }
1330  return  &PyViewtype;
1331}
1332
1333
1334PyObject *PyView_new(PyObject *o, PyObject *_args) {
1335  return new PyView;
1336}
1337
1338PyView::PyView(): PyHead(PyViewtype), _base(0), _state(BASE){}
1339
1340PyView::PyView(const c4_View &o, PyView *owner, int state): PyHead(PyViewtype),
1341  c4_View(o), _base(owner), _state(state) {
1342  ob_type = getTypeObject(_state);
1343  if (owner && owner->_base)
1344    _base = owner->_base;
1345}
1346
1347/* For dicts, use the Python names so MK's case insensitivity works */
1348void PyView::makeRowFromDict(c4_Row &tmp, PyObject *o, bool useDefaults) {
1349  PWOMapping dict(o);
1350  PWOList keys = dict.keys();
1351  for (int i = 0; i < dict.len(); ++i) {
1352    PWOString key = keys[i];
1353    int ndx = FindPropIndexByName(key);
1354    if (ndx >  - 1) {
1355      const c4_Property &prop = NthProperty(ndx);
1356      PyRowRef::setFromPython(tmp, prop, dict[(const char*)key]);
1357    }
1358  }
1359}
1360
1361void PyView::makeRow(c4_Row &tmp, PyObject *o, bool useDefaults) {
1362  /* can't just check if mapping type; strings are mappings in Python 2.3
1363  (but not in 2.2 or earlier) */
1364  if (o && PyDict_Check(o))
1365    makeRowFromDict(tmp, o, useDefaults);
1366  else {
1367    enum {
1368      instance, sequence, none
1369    } pyobject_type = none;
1370    int n = NumProperties();
1371
1372    if (!o) {
1373      pyobject_type = none;
1374    } else if (PyInstance_Check(o)) {
1375      /* instances of new-style classes (Python 2.2+) do not return true */
1376      pyobject_type = instance;
1377    } else if (PySequence_Check(o)) {
1378      int seq_length = PyObject_Length(o);
1379      if (seq_length > n) {
1380        PyErr_Format(PyExc_IndexError,
1381          "Sequence has %d elements; view has %d properties", seq_length, n);
1382        throw PWDPyException;
1383      }
1384      n = seq_length;
1385      pyobject_type = sequence;
1386    } else {
1387      /* new-style class, not a number */
1388      if (PyObject_HasAttrString(o, "__class__") && !PyNumber_Check(o)) {
1389        pyobject_type = instance;
1390      } else {
1391        Fail(PyExc_TypeError,
1392          "Argument is not an instance, sequence or dictionary: cannot be coerced to row");
1393      }
1394    }
1395
1396    for (int i = 0; i < n; i++) {
1397      const c4_Property &prop = NthProperty(i);
1398      PyObject *attr = 0;
1399      if (pyobject_type == instance) {
1400        attr = PyObject_GetAttrString(o, (char*)prop.Name());
1401        if (attr == 0 && i == 0 && NumProperties() == 1) {
1402          PyErr_Clear();
1403          attr = o;
1404          Py_XINCREF(attr);
1405        }
1406      } else if (pyobject_type == sequence) {
1407        attr = PySequence_GetItem(o, i);
1408      }
1409      if (attr) {
1410        try {
1411          PyRowRef::setFromPython(tmp, prop, attr);
1412        } catch (...) {
1413          Py_DECREF(attr);
1414          throw;
1415        }
1416        Py_DECREF(attr);
1417      } else {
1418        PyErr_Clear();
1419        if (useDefaults)
1420          PyRowRef::setDefault(tmp, prop);
1421      }
1422    }
1423  }
1424  if (!useDefaults)
1425    if (tmp.Container().NumProperties() == 0)
1426      Fail(PyExc_ValueError, "Object has no usable attributes");
1427}
1428
1429void PyView::insertAt(int i, PyObject *o) {
1430  if (PyGenericView_Check(o))
1431    InsertAt(i, *(PyView*)o);
1432  else {
1433    c4_Row temp;
1434    makeRow(temp, o);
1435    InsertAt(i, temp);
1436  }
1437}
1438
1439PyObject *PyView::structure() {
1440  int n = NumProperties();
1441  //  PyObject* list=PyList_New(n);
1442  //  for (int i = 0; i < n; i++)
1443  //    PyList_SET_ITEM(list, i, new PyProperty(NthProperty(i)));
1444  //  return list;
1445  PWOList rslt(n);
1446  for (int i = 0; i < n; i++) {
1447    PyProperty *prop = new PyProperty(NthProperty(i));
1448    rslt.setItem(i, prop);
1449  }
1450  return rslt.disOwn();
1451}
1452
1453
1454PyObject *PyView::properties() {
1455  int n = NumProperties();
1456  PWOMapping rslt;
1457  for (int i = 0; i < n; i++) {
1458    PyProperty *item = new PyProperty(NthProperty(i));
1459    rslt.setItem(item->Name(), item);
1460    Py_DECREF(item);
1461  }
1462  return rslt.disOwn();
1463}
1464
1465
1466PyView *PyView::getSlice(int s, int e) {
1467  int sz = GetSize();
1468  if (s < 0)
1469    s += sz;
1470  if (e < 0)
1471    e += sz;
1472  if (e > sz)
1473    e = sz;
1474  if (s >= 0 && s < sz)
1475    if (e > s && e <= sz)
1476      return new PyView(Slice(s, e), 0, computeState(RWVIEWER));
1477  return new PyView(Clone());
1478}
1479
1480int PyView::setSlice(int s, int e, const PWOSequence &lst) {
1481  int sz = GetSize();
1482  if (s < 0)
1483    s += sz;
1484  if (e < 0)
1485    e += sz;
1486  if (e > sz)
1487    e = sz;
1488  int i = 0;
1489  for (; i < lst.len() && s < e; i++, s++)
1490    setItem(s, lst[i]);
1491  for (; i < lst.len(); i++, s++) {
1492    if (_base)
1493      Fail(PyExc_RuntimeError, "Can't insert in this view");
1494    insertAt(s, lst[i]);
1495  }
1496  if (s < e)
1497    if (_base)
1498  while (s < e) {
1499    int ndx = _base->GetIndexOf(GetAt(s));
1500    _base->RemoveAt(ndx, 1);
1501    --e;
1502  } else
1503    RemoveAt(s, e-s);
1504  return 0;
1505}
1506
1507PyRowRef *PyView::getItem(int i) {
1508  if (i < 0)
1509    i += GetSize();
1510  if (i >= GetSize() || i < 0)
1511    return 0;
1512  if (_base && !(_state &IMMUTABLEROWS)) {
1513    c4_RowRef derived = GetAt(i);
1514    int ndx = _base->GetIndexOf(derived);
1515    if (ndx >= 0)
1516      return new PyRowRef(_base->GetAt(ndx), _state &IMMUTABLEROWS);
1517  }
1518  return new PyRowRef(GetAt(i), _state &IMMUTABLEROWS);
1519}
1520
1521int PyView::setItem(int i, PyObject *v) {
1522  if (PyGenericRowRef_Check(v))
1523    return setItemRow(i, *(PyRowRef*)v);
1524  c4_Row temp;
1525  makeRow(temp, v, false);
1526  return setItemRow(i, temp);
1527}
1528
1529void PyView::addProperties(const PWOSequence &lst) {
1530  for (int i = 0; i < lst.len(); i++) {
1531    if (PyProperty_Check((PyObject*)lst[i])) {
1532      AddProperty(*(PyProperty*)(PyObject*)lst[i]);
1533    }
1534  }
1535}
1536
1537void PyView::map(const PWOCallable &func) {
1538  PWOTuple tmp(1);
1539  for (int i = 0; i < GetSize(); ++i) {
1540    PyRowRef *row = new PyRowRef(GetAt(i));
1541    PWOBase r2(row);
1542    tmp.setItem(0, r2);
1543    func.call(tmp);
1544    Py_DECREF(row);
1545  }
1546}
1547
1548void PyView::map(const PWOCallable &func, const PyView &subset) {
1549  int sz = subset.GetSize();
1550  PWOTuple tmp(1);
1551  for (int i = 0; i < sz; ++i) {
1552    PyRowRef *row = new PyRowRef(GetAt(GetIndexOf(subset.GetAt(i))));
1553    PWOBase r2(row);
1554    tmp.setItem(0, r2);
1555    func.call(tmp);
1556    Py_DECREF(row);
1557  }
1558}
1559
1560static c4_IntProp _index("index");
1561
1562PyView *PyView::indices(const PyView &subset) {
1563  c4_View tmp(_index);
1564  tmp.SetSize(subset.GetSize());
1565  c4_Row row;
1566  for (int i = 0; i < subset.GetSize(); ++i) {
1567    _index(row) = GetIndexOf(subset.GetAt(i));
1568    tmp.SetAt(i, row);
1569  }
1570  return new PyView(tmp);
1571}
1572
1573void PyView::remove(const PyView &indices) {
1574  c4_View tmp = indices.Sort();
1575  for (int i = indices.GetSize() - 1; i >= 0; --i)
1576    RemoveAt(_index(tmp.GetAt(i)));
1577}
1578
1579PyView *PyView::filter(const PWOCallable &func) {
1580  c4_View indices(_index);
1581  c4_Row ndx;
1582  PWOTuple tmp(1);
1583  for (int i = 0; i < GetSize(); ++i) {
1584    PyRowRef *row = new PyRowRef(GetAt(i));
1585    PWOBase r2(row);
1586    tmp.setItem(0, r2);
1587    PWOBase rslt(func.call(tmp));
1588    if (rslt.isTrue()) {
1589      _index(ndx) = i;
1590      indices.Add(ndx);
1591    }
1592    Py_DECREF(row);
1593  }
1594  return new PyView(indices);
1595}
1596
1597PyObject *PyView::reduce(const PWOCallable &func, PWONumber &start) {
1598  PWONumber accum = start;
1599  PWOTuple tmp(2);
1600  for (int i = 0; i < GetSize(); ++i) {
1601    PyRowRef *row = new PyRowRef(GetAt(i));
1602    PWOBase r2(row);
1603    tmp.setItem(0, r2);
1604    tmp.setItem(1, accum);
1605    PWOBase rslt(func.call(tmp));
1606    accum = rslt;
1607    Py_DECREF(row);
1608  }
1609  return accum;
1610}
1611