Home | History | Annotate | Download | only in d
      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 > %{
     28 public this($typemap(dtype, CTYPE)[] values) {
     29   this();
     30   append(values);
     31 }
     32 
     33 alias push_back add;
     34 alias push_back push;
     35 alias push_back opCatAssign;
     36 alias size length;
     37 alias opSlice slice;
     38 
     39 public $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 
     47 public $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 
     54 public void append($typemap(dtype, CTYPE)[] value...) {
     55   foreach (v; value) {
     56     add(v);
     57   }
     58 }
     59 
     60 public $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 
     68 public 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 
     80 public 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 
     96 public 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 > %{
    183 static import std.algorithm;
    184 static import std.exception;
    185 static import std.range;
    186 static import std.traits;
    187 %}
    188 %typemap(dcode) std::vector< CTYPE > %{
    189 alias size_t KeyType;
    190 alias $typemap(dtype, CTYPE) ValueType;
    191 
    192 this(ValueType[] values...) {
    193   this();
    194   reserve(values.length);
    195   foreach (e; values) {
    196     this ~= e;
    197   }
    198 }
    199 
    200 struct 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 
    250 Range opSlice() {
    251   return Range(this, 0, length);
    252 }
    253 
    254 Range opSlice(size_t a, size_t b) {
    255   std.exception.enforce(a <= b && b <= length);
    256   return Range(this, a, b);
    257 }
    258 
    259 size_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 
    283 ValueType opIndex(size_t i) {
    284   return getElement(i);
    285 }
    286 
    287 void opIndexAssign(ValueType value, size_t i) {
    288   setElement(i, value);
    289 }
    290 
    291 void opIndexOpAssign(string op)(ValueType value, size_t i) {
    292   auto element = this[i];
    293   mixin("element "~op~"= value;");
    294   this[i] = element;
    295 }
    296 
    297 ValueType[] 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 
    305 void 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 
    315 alias size length;
    316 
    317 alias remove removeAny;
    318 alias removeAny stableRemoveAny;
    319 
    320 size_t insertBack(Stuff)(Stuff stuff)
    321 if (std.traits.isImplicitlyConvertible!(Stuff, ValueType)){
    322   push_back(stuff);
    323   return 1;
    324 }
    325 size_t insertBack(Stuff)(Stuff stuff)
    326 if (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 }
    335 alias insertBack insert;
    336 
    337 alias pop_back removeBack;
    338 alias pop_back stableRemoveBack;
    339 
    340 size_t insertBefore(Stuff)(Range r, Stuff stuff)
    341 if (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 
    347 size_t insertBefore(Stuff)(Range r, Stuff stuff)
    348 if (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 
    360 size_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 
    370 size_t replace(Stuff)(Range r, Stuff stuff)
    371 if (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 
    390 size_t replace(Stuff)(Range r, Stuff stuff)
    391 if (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 
    406 Range 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 }
    412 alias remove stableLinearRemove;
    413 
    414 int 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 
    426 int 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...)
    545 namespace 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 
    558 namespace 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
    578 SWIG_STD_VECTOR_ENHANCED(char)
    579 SWIG_STD_VECTOR_ENHANCED(signed char)
    580 SWIG_STD_VECTOR_ENHANCED(unsigned char)
    581 SWIG_STD_VECTOR_ENHANCED(short)
    582 SWIG_STD_VECTOR_ENHANCED(unsigned short)
    583 SWIG_STD_VECTOR_ENHANCED(int)
    584 SWIG_STD_VECTOR_ENHANCED(unsigned int)
    585 SWIG_STD_VECTOR_ENHANCED(long)
    586 SWIG_STD_VECTOR_ENHANCED(unsigned long)
    587 SWIG_STD_VECTOR_ENHANCED(long long)
    588 SWIG_STD_VECTOR_ENHANCED(unsigned long long)
    589 SWIG_STD_VECTOR_ENHANCED(float)
    590 SWIG_STD_VECTOR_ENHANCED(double)
    591 SWIG_STD_VECTOR_ENHANCED(std::string) // also requires a %include <std_string.i>
    592