PageRenderTime 30ms CodeModel.GetById 8ms app.highlight 10ms RepoModel.GetById 1ms app.codeStats 1ms

/trunk/Lib/d/std_vector.i

#
Swig | 591 lines | 486 code | 88 blank | 17 comment | 0 complexity | db4d32ef8f493efdef696cbc5f266391 MD5 | raw file
  1/* -----------------------------------------------------------------------------
  2 * std_vector.i
  3 *
  4 * SWIG typemaps for std::vector<T>, D implementation.
  5 *
  6 * The D wrapper is made to loosely resemble a tango.util.container.more.Vector
  7 * and to provide built-in array-like access.
  8 *
  9 * If T does define an operator==, then use the SWIG_STD_VECTOR_ENHANCED
 10 * macro to obtain enhanced functionality (none yet), for example:
 11 *
 12 *   SWIG_STD_VECTOR_ENHANCED(SomeNamespace::Klass)
 13 *   %template(VectKlass) std::vector<SomeNamespace::Klass>;
 14 *
 15 * Warning: heavy macro usage in this file. Use swig -E to get a sane view on
 16 * the real file contents!
 17 * ----------------------------------------------------------------------------- */
 18
 19// Warning: Use the typemaps here in the expectation that the macros they are in will change name.
 20
 21%include <std_common.i>
 22
 23// MACRO for use within the std::vector class body
 24%define SWIG_STD_VECTOR_MINIMUM_INTERNAL(CONST_REFERENCE, CTYPE...)
 25#if (SWIG_D_VERSION == 1)
 26%typemap(dimports) std::vector< CTYPE > "static import tango.core.Exception;"
 27%typemap(dcode) std::vector< CTYPE > %{
 28public this($typemap(dtype, CTYPE)[] values) {
 29  this();
 30  append(values);
 31}
 32
 33alias push_back add;
 34alias push_back push;
 35alias push_back opCatAssign;
 36alias size length;
 37alias opSlice slice;
 38
 39public $typemap(dtype, CTYPE) opIndexAssign($typemap(dtype, CTYPE) value, size_t index) {
 40  if (index >= size()) {
 41    throw new tango.core.Exception.NoSuchElementException("Tried to assign to element out of vector bounds.");
 42  }
 43  setElement(index, value);
 44  return value;
 45}
 46
 47public $typemap(dtype, CTYPE) opIndex(size_t index) {
 48  if (index >= size()) {
 49    throw new tango.core.Exception.NoSuchElementException("Tried to read from element out of vector bounds.");
 50  }
 51  return getElement(index);
 52}
 53
 54public void append($typemap(dtype, CTYPE)[] value...) {
 55  foreach (v; value) {
 56    add(v);
 57  }
 58}
 59
 60public $typemap(dtype, CTYPE)[] opSlice() {
 61  $typemap(dtype, CTYPE)[] array = new $typemap(dtype, CTYPE)[size()];
 62  foreach (i, ref value; array) {
 63    value = getElement(i);
 64  }
 65  return array;
 66}
 67
 68public int opApply(int delegate(ref $typemap(dtype, CTYPE) value) dg) {
 69  int result;
 70
 71  size_t currentSize = size();
 72  for (size_t i = 0; i < currentSize; ++i) {
 73    auto value = getElement(i);
 74    result = dg(value);
 75    setElement(i, value);
 76  }
 77  return result;
 78}
 79
 80public int opApply(int delegate(ref size_t index, ref $typemap(dtype, CTYPE) value) dg) {
 81  int result;
 82
 83  size_t currentSize = size();
 84  for (size_t i = 0; i < currentSize; ++i) {
 85    auto value = getElement(i);
 86
 87    // Workaround for http://d.puremagic.com/issues/show_bug.cgi?id=2443.
 88    auto index = i;
 89
 90    result = dg(index, value);
 91    setElement(i, value);
 92  }
 93  return result;
 94}
 95
 96public void capacity(size_t value) {
 97  if (value < size()) {
 98    throw new tango.core.Exception.IllegalArgumentException("Tried to make the capacity of a vector smaller than its size.");
 99  }
100
101  reserve(value);
102}
103%}
104
105  public:
106    typedef size_t size_type;
107    typedef CTYPE value_type;
108    typedef CONST_REFERENCE const_reference;
109    void clear();
110    void push_back(CTYPE const& x);
111    size_type size() const;
112    size_type capacity() const;
113    void reserve(size_type n) throw (std::length_error);
114    vector();
115    vector(const vector &other);
116    %extend {
117      vector(size_type capacity) throw (std::length_error) {
118        std::vector< CTYPE >* pv = 0;
119        pv = new std::vector< CTYPE >();
120
121        // Might throw std::length_error.
122        pv->reserve(capacity);
123
124        return pv;
125      }
126
127      size_type unused() const {
128        return $self->capacity() - $self->size();
129      }
130
131      const_reference remove() throw (std::out_of_range) {
132        if ($self->empty()) {
133          throw std::out_of_range("Tried to remove last element from empty vector.");
134        }
135
136        std::vector< CTYPE >::const_reference value = $self->back();
137        $self->pop_back();
138        return value;
139      }
140
141      const_reference remove(size_type index) throw (std::out_of_range) {
142        if (index >= $self->size()) {
143          throw std::out_of_range("Tried to remove element with invalid index.");
144        }
145
146        std::vector< CTYPE >::iterator it = $self->begin() + index;
147        std::vector< CTYPE >::const_reference value = *it;
148        $self->erase(it);
149        return value;
150      }
151    }
152
153    // Wrappers for setting/getting items with the possibly thrown exception
154    // specified (important for SWIG wrapper generation).
155    %extend {
156      const_reference getElement(size_type index) throw (std::out_of_range) {
157        if ((index < 0) || ($self->size() <= index)) {
158          throw std::out_of_range("Tried to get value of element with invalid index.");
159        }
160        return (*$self)[index];
161      }
162    }
163
164    // Use CTYPE const& instead of const_reference to work around SWIG code
165    // generation issue when using const pointers as vector elements (like
166    // std::vector< const int* >).
167    %extend {
168      void setElement(size_type index, CTYPE const& val) throw (std::out_of_range) {
169        if ((index < 0) || ($self->size() <= index)) {
170          throw std::out_of_range("Tried to set value of element with invalid index.");
171        }
172        (*$self)[index] = val;
173      }
174    }
175
176%dmethodmodifiers std::vector::getElement "private"
177%dmethodmodifiers std::vector::setElement "private"
178%dmethodmodifiers std::vector::reserve "private"
179
180#else
181
182%typemap(dimports) std::vector< CTYPE > %{
183static import std.algorithm;
184static import std.exception;
185static import std.range;
186static import std.traits;
187%}
188%typemap(dcode) std::vector< CTYPE > %{
189alias size_t KeyType;
190alias $typemap(dtype, CTYPE) ValueType;
191
192this(ValueType[] values...) {
193  this();
194  reserve(values.length);
195  foreach (e; values) {
196    this ~= e;
197  }
198}
199
200struct Range {
201  private $typemap(dtype, std::vector< CTYPE >) _outer;
202  private size_t _a, _b;
203
204  this($typemap(dtype, std::vector< CTYPE >) data, size_t a, size_t b) {
205    _outer = data;
206    _a = a;
207    _b = b;
208  }
209
210  @property bool empty() const {
211    assert((cast($typemap(dtype, std::vector< CTYPE >))_outer).length >= _b);
212    return _a >= _b;
213  }
214
215  @property Range save() {
216    return this;
217  }
218
219  @property ValueType front() {
220    std.exception.enforce(!empty);
221    return _outer[_a];
222  }
223
224  @property void front(ValueType value) {
225    std.exception.enforce(!empty);
226    _outer[_a] = std.algorithm.move(value);
227  }
228
229  void popFront() {
230    std.exception.enforce(!empty);
231    ++_a;
232  }
233
234  void opIndexAssign(ValueType value, size_t i) {
235    i += _a;
236    std.exception.enforce(i < _b && _b <= _outer.length);
237    _outer[i] = value;
238  }
239
240  void opIndexOpAssign(string op)(ValueType value, size_t i) {
241    std.exception.enforce(_outer && _a + i < _b && _b <= _outer.length);
242    auto element = _outer[i];
243    mixin("element "~op~"= value;");
244    _outer[i] = element;
245  }
246}
247
248// TODO: dup?
249
250Range opSlice() {
251  return Range(this, 0, length);
252}
253
254Range opSlice(size_t a, size_t b) {
255  std.exception.enforce(a <= b && b <= length);
256  return Range(this, a, b);
257}
258
259size_t opDollar() const {
260  return length;
261}
262
263@property ValueType front() {
264  std.exception.enforce(!empty);
265  return getElement(0);
266}
267
268@property void front(ValueType value) {
269  std.exception.enforce(!empty);
270  setElement(0, value);
271}
272
273@property ValueType back() {
274  std.exception.enforce(!empty);
275  return getElement(length - 1);
276}
277
278@property void back(ValueType value) {
279  std.exception.enforce(!empty);
280  setElement(length - 1, value);
281}
282
283ValueType opIndex(size_t i) {
284  return getElement(i);
285}
286
287void opIndexAssign(ValueType value, size_t i) {
288  setElement(i, value);
289}
290
291void opIndexOpAssign(string op)(ValueType value, size_t i) {
292  auto element = this[i];
293  mixin("element "~op~"= value;");
294  this[i] = element;
295}
296
297ValueType[] opBinary(string op, Stuff)(Stuff stuff) if (op == "~") {
298  ValueType[] result;
299  result ~= this[];
300  assert(result.length == length);
301  result ~= stuff[];
302  return result;
303}
304
305void opOpAssign(string op, Stuff)(Stuff stuff) if (op == "~") {
306  static if (is(typeof(insertBack(stuff)))) {
307    insertBack(stuff);
308  } else if (is(typeof(insertBack(stuff[])))) {
309    insertBack(stuff[]);
310  } else {
311    static assert(false, "Cannot append " ~ Stuff.stringof ~ " to " ~ typeof(this).stringof);
312  }
313}
314
315alias size length;
316
317alias remove removeAny;
318alias removeAny stableRemoveAny;
319
320size_t insertBack(Stuff)(Stuff stuff)
321if (std.traits.isImplicitlyConvertible!(Stuff, ValueType)){
322  push_back(stuff);
323  return 1;
324}
325size_t insertBack(Stuff)(Stuff stuff)
326if (std.range.isInputRange!Stuff &&
327    std.traits.isImplicitlyConvertible!(std.range.ElementType!Stuff, ValueType)) {
328  size_t itemCount;
329  foreach(item; stuff) {
330    insertBack(item);
331    ++itemCount;
332  }
333  return itemCount;
334}
335alias insertBack insert;
336
337alias pop_back removeBack;
338alias pop_back stableRemoveBack;
339
340size_t insertBefore(Stuff)(Range r, Stuff stuff)
341if (std.traits.isImplicitlyConvertible!(Stuff, ValueType)) {
342  std.exception.enforce(r._outer.swigCPtr == swigCPtr && r._a < length);
343  insertAt(r._a, stuff);
344  return 1;
345}
346
347size_t insertBefore(Stuff)(Range r, Stuff stuff)
348if (std.range.isInputRange!Stuff && std.traits.isImplicitlyConvertible!(ElementType!Stuff, ValueType)) {
349  std.exception.enforce(r._outer.swigCPtr == swigCPtr && r._a <= length);
350
351  size_t insertCount;
352  foreach(i, item; stuff) {
353    insertAt(r._a + i, item);
354    ++insertCount;
355  }
356
357  return insertCount;
358}
359
360size_t insertAfter(Stuff)(Range r, Stuff stuff) {
361  // TODO: optimize
362  immutable offset = r._a + r.length;
363  std.exception.enforce(offset <= length);
364  auto result = insertBack(stuff);
365  std.algorithm.bringToFront(this[offset .. length - result],
366    this[length - result .. length]);
367  return result;
368}
369
370size_t replace(Stuff)(Range r, Stuff stuff)
371if (std.range.isInputRange!Stuff &&
372    std.traits.isImplicitlyConvertible!(ElementType!Stuff, ValueType)) {
373  immutable offset = r._a;
374  std.exception.enforce(offset <= length);
375  size_t result;
376  for (; !stuff.empty; stuff.popFront()) {
377    if (r.empty) {
378      // append the rest
379      return result + insertBack(stuff);
380    }
381    r.front = stuff.front;
382    r.popFront();
383    ++result;
384  }
385  // Remove remaining stuff in r
386  remove(r);
387  return result;
388}
389
390size_t replace(Stuff)(Range r, Stuff stuff)
391if (std.traits.isImplicitlyConvertible!(Stuff, ValueType))
392{
393    if (r.empty)
394    {
395        insertBefore(r, stuff);
396    }
397    else
398    {
399        r.front = stuff;
400        r.popFront();
401        remove(r);
402    }
403    return 1;
404}
405
406Range linearRemove(Range r) {
407  std.exception.enforce(r._a <= r._b && r._b <= length);
408  immutable tailLength = length - r._b;
409  linearRemove(r._a, r._b);
410  return this[length - tailLength .. length];
411}
412alias remove stableLinearRemove;
413
414int opApply(int delegate(ref $typemap(dtype, CTYPE) value) dg) {
415  int result;
416
417  size_t currentSize = size();
418  for (size_t i = 0; i < currentSize; ++i) {
419    auto value = getElement(i);
420    result = dg(value);
421    setElement(i, value);
422  }
423  return result;
424}
425
426int opApply(int delegate(ref size_t index, ref $typemap(dtype, CTYPE) value) dg) {
427  int result;
428
429  size_t currentSize = size();
430  for (size_t i = 0; i < currentSize; ++i) {
431    auto value = getElement(i);
432
433    // Workaround for http://d.puremagic.com/issues/show_bug.cgi?id=2443.
434    auto index = i;
435
436    result = dg(index, value);
437    setElement(i, value);
438  }
439  return result;
440}
441%}
442
443  public:
444    typedef size_t size_type;
445    typedef CTYPE value_type;
446    typedef CONST_REFERENCE const_reference;
447    bool empty() const;
448    void clear();
449    void push_back(CTYPE const& x);
450    void pop_back();
451    size_type size() const;
452    size_type capacity() const;
453    void reserve(size_type n) throw (std::length_error);
454    vector();
455    vector(const vector &other);
456    %extend {
457      vector(size_type capacity) throw (std::length_error) {
458        std::vector< CTYPE >* pv = 0;
459        pv = new std::vector< CTYPE >();
460
461        // Might throw std::length_error.
462        pv->reserve(capacity);
463
464        return pv;
465      }
466
467      const_reference remove() throw (std::out_of_range) {
468        if ($self->empty()) {
469          throw std::out_of_range("Tried to remove last element from empty vector.");
470        }
471
472        std::vector< CTYPE >::const_reference value = $self->back();
473        $self->pop_back();
474        return value;
475      }
476
477      const_reference remove(size_type index) throw (std::out_of_range) {
478        if (index >= $self->size()) {
479          throw std::out_of_range("Tried to remove element with invalid index.");
480        }
481
482        std::vector< CTYPE >::iterator it = $self->begin() + index;
483        std::vector< CTYPE >::const_reference value = *it;
484        $self->erase(it);
485        return value;
486      }
487
488      void removeBack(size_type how_many) throw (std::out_of_range) {
489        std::vector< CTYPE >::iterator end = $self->end();
490        std::vector< CTYPE >::iterator start = end - how_many;
491        $self->erase(start, end);
492      }
493
494      void linearRemove(size_type start_index, size_type end_index) throw (std::out_of_range) {
495        std::vector< CTYPE >::iterator start = $self->begin() + start_index;
496        std::vector< CTYPE >::iterator end = $self->begin() + end_index;
497        $self->erase(start, end);
498      }
499
500      void insertAt(size_type index, CTYPE const& x) throw (std::out_of_range) {
501        std::vector< CTYPE >::iterator it = $self->begin() + index;
502        $self->insert(it, x);
503      }
504    }
505
506    // Wrappers for setting/getting items with the possibly thrown exception
507    // specified (important for SWIG wrapper generation).
508    %extend {
509      const_reference getElement(size_type index) throw (std::out_of_range) {
510        if ((index < 0) || ($self->size() <= index)) {
511          throw std::out_of_range("Tried to get value of element with invalid index.");
512        }
513        return (*$self)[index];
514      }
515    }
516    // Use CTYPE const& instead of const_reference to work around SWIG code
517    // generation issue when using const pointers as vector elements (like
518    // std::vector< const int* >).
519    %extend {
520      void setElement(size_type index, CTYPE const& val) throw (std::out_of_range) {
521        if ((index < 0) || ($self->size() <= index)) {
522          throw std::out_of_range("Tried to set value of element with invalid index.");
523        }
524        (*$self)[index] = val;
525      }
526    }
527
528%dmethodmodifiers std::vector::getElement "private"
529%dmethodmodifiers std::vector::setElement "private"
530#endif
531%enddef
532
533// Extra methods added to the collection class if operator== is defined for the class being wrapped
534// The class will then implement IList<>, which adds extra functionality
535%define SWIG_STD_VECTOR_EXTRA_OP_EQUALS_EQUALS(CTYPE...)
536    %extend {
537    }
538%enddef
539
540// For vararg handling in macros, from swigmacros.swg
541#define %arg(X...) X
542
543// Macros for std::vector class specializations/enhancements
544%define SWIG_STD_VECTOR_ENHANCED(CTYPE...)
545namespace std {
546  template<> class vector<CTYPE > {
547    SWIG_STD_VECTOR_MINIMUM_INTERNAL(%arg(CTYPE const&), %arg(CTYPE))
548    SWIG_STD_VECTOR_EXTRA_OP_EQUALS_EQUALS(CTYPE)
549  };
550}
551%enddef
552
553%{
554#include <vector>
555#include <stdexcept>
556%}
557
558namespace std {
559  // primary (unspecialized) class template for std::vector
560  // does not require operator== to be defined
561  template<class T> class vector {
562    SWIG_STD_VECTOR_MINIMUM_INTERNAL(T const&, T)
563  };
564  // specializations for pointers
565  template<class T> class vector<T *> {
566    SWIG_STD_VECTOR_MINIMUM_INTERNAL(T *const&, T *)
567    SWIG_STD_VECTOR_EXTRA_OP_EQUALS_EQUALS(T *)
568  };
569  // bool is a bit different in the C++ standard - const_reference in particular
570  template<> class vector<bool> {
571    SWIG_STD_VECTOR_MINIMUM_INTERNAL(bool, bool)
572    SWIG_STD_VECTOR_EXTRA_OP_EQUALS_EQUALS(bool)
573  };
574}
575
576// template specializations for std::vector
577// these provide extra collections methods as operator== is defined
578SWIG_STD_VECTOR_ENHANCED(char)
579SWIG_STD_VECTOR_ENHANCED(signed char)
580SWIG_STD_VECTOR_ENHANCED(unsigned char)
581SWIG_STD_VECTOR_ENHANCED(short)
582SWIG_STD_VECTOR_ENHANCED(unsigned short)
583SWIG_STD_VECTOR_ENHANCED(int)
584SWIG_STD_VECTOR_ENHANCED(unsigned int)
585SWIG_STD_VECTOR_ENHANCED(long)
586SWIG_STD_VECTOR_ENHANCED(unsigned long)
587SWIG_STD_VECTOR_ENHANCED(long long)
588SWIG_STD_VECTOR_ENHANCED(unsigned long long)
589SWIG_STD_VECTOR_ENHANCED(float)
590SWIG_STD_VECTOR_ENHANCED(double)
591SWIG_STD_VECTOR_ENHANCED(std::string) // also requires a %include <std_string.i>