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