1/* -----------------------------------------------------------------------------
2 * See the LICENSE file for information on copyright, usage and redistribution
3 * of SWIG, and the README file for authors - http://www.swig.org/release.html.
4 *
5 * std_vector.i
6 *
7 * SWIG typemaps for std::vector types
8 * ----------------------------------------------------------------------------- */
9
10%include <std_common.i>
11
12// ------------------------------------------------------------------------
13// std::vector
14//
15// The aim of all that follows would be to integrate std::vector with
16// Perl as much as possible, namely, to allow the user to pass and
17// be returned Perl arrays.
18// const declarations are used to guess the intent of the function being
19// exported; therefore, the following rationale is applied:
20//
21//   -- f(std::vector<T>), f(const std::vector<T>&), f(const std::vector<T>*):
22//      the parameter being read-only, either a Perl sequence or a
23//      previously wrapped std::vector<T> can be passed.
24//   -- f(std::vector<T>&), f(std::vector<T>*):
25//      the parameter must be modified; therefore, only a wrapped std::vector
26//      can be passed.
27//   -- std::vector<T> f():
28//      the vector is returned by copy; therefore, a Perl sequence of T:s
29//      is returned which is most easily used in other Perl functions
30//   -- std::vector<T>& f(), std::vector<T>* f(), const std::vector<T>& f(),
31//      const std::vector<T>* f():
32//      the vector is returned by reference; therefore, a wrapped std::vector
33//      is returned
34// ------------------------------------------------------------------------
35
36%{
37#include <vector>
38#include <algorithm>
39#include <stdexcept>
40%}
41
42// exported class
43
44namespace std {
45
46    template<class T> class vector {
47        %typemap(in) vector<T> (std::vector<T>* v) {
48            if (SWIG_ConvertPtr($input,(void **) &v,
49                                $&1_descriptor,1) != -1) {
50                $1 = *v;
51            } else if (SvROK($input)) {
52                AV *av = (AV *)SvRV($input);
53                if (SvTYPE(av) != SVt_PVAV)
54                    SWIG_croak("Type error in argument $argnum of $symname. "
55                               "Expected an array of " #T);
56                SV **tv;
57                I32 len = av_len(av) + 1;
58                T* obj;
59                for (int i=0; i<len; i++) {
60                    tv = av_fetch(av, i, 0);
61                    if (SWIG_ConvertPtr(*tv, (void **)&obj,
62                                        $descriptor(T *),0) != -1) {
63                        $1.push_back(*obj);
64                    } else {
65                        SWIG_croak("Type error in argument $argnum of "
66                                   "$symname. "
67                                   "Expected an array of " #T);
68                    }
69                }
70            } else {
71                SWIG_croak("Type error in argument $argnum of $symname. "
72                           "Expected an array of " #T);
73            }
74        }
75        %typemap(in) const vector<T>& (std::vector<T> temp,
76                                       std::vector<T>* v),
77                     const vector<T>* (std::vector<T> temp,
78                                       std::vector<T>* v) {
79            if (SWIG_ConvertPtr($input,(void **) &v,
80                                $1_descriptor,1) != -1) {
81                $1 = v;
82            } else if (SvROK($input)) {
83                AV *av = (AV *)SvRV($input);
84                if (SvTYPE(av) != SVt_PVAV)
85                    SWIG_croak("Type error in argument $argnum of $symname. "
86                               "Expected an array of " #T);
87                SV **tv;
88                I32 len = av_len(av) + 1;
89                T* obj;
90                for (int i=0; i<len; i++) {
91                    tv = av_fetch(av, i, 0);
92                    if (SWIG_ConvertPtr(*tv, (void **)&obj,
93                                        $descriptor(T *),0) != -1) {
94                        temp.push_back(*obj);
95                    } else {
96                        SWIG_croak("Type error in argument $argnum of "
97                                   "$symname. "
98                                   "Expected an array of " #T);
99                    }
100                }
101                $1 = &temp;
102            } else {
103                SWIG_croak("Type error in argument $argnum of $symname. "
104                           "Expected an array of " #T);
105            }
106        }
107        %typemap(out) vector<T> {
108            size_t len = $1.size();
109            SV **svs = new SV*[len];
110            for (size_t i=0; i<len; i++) {
111                T* ptr = new T($1[i]);
112                svs[i] = sv_newmortal();
113                SWIG_MakePtr(svs[i], (void*) ptr,
114                             $descriptor(T *), $shadow|$owner);
115            }
116            AV *myav = av_make(len, svs);
117            delete[] svs;
118            $result = newRV_noinc((SV*) myav);
119            sv_2mortal($result);
120            argvi++;
121        }
122        %typecheck(SWIG_TYPECHECK_VECTOR) vector<T> {
123            {
124                /* wrapped vector? */
125                std::vector<T >* v;
126                if (SWIG_ConvertPtr($input,(void **) &v,
127                                    $&1_descriptor,0) != -1) {
128                    $1 = 1;
129                } else if (SvROK($input)) {
130                    /* native sequence? */
131                    AV *av = (AV *)SvRV($input);
132                    if (SvTYPE(av) == SVt_PVAV) {
133                        I32 len = av_len(av) + 1;
134                        if (len == 0) {
135                            /* an empty sequence can be of any type */
136                            $1 = 1;
137                        } else {
138                            /* check the first element only */
139                            T* obj;
140                            SV **tv = av_fetch(av, 0, 0);
141                            if (SWIG_ConvertPtr(*tv, (void **)&obj,
142                                                $descriptor(T *),0) != -1)
143                                $1 = 1;
144                            else
145                                $1 = 0;
146                        }
147                    }
148                } else {
149                    $1 = 0;
150                }
151            }
152        }
153        %typecheck(SWIG_TYPECHECK_VECTOR) const vector<T>&,
154                                          const vector<T>* {
155            {
156                /* wrapped vector? */
157                std::vector<T >* v;
158                if (SWIG_ConvertPtr($input,(void **) &v,
159                                    $1_descriptor,0) != -1) {
160                    $1 = 1;
161                } else if (SvROK($input)) {
162                    /* native sequence? */
163                    AV *av = (AV *)SvRV($input);
164                    if (SvTYPE(av) == SVt_PVAV) {
165                        I32 len = av_len(av) + 1;
166                        if (len == 0) {
167                            /* an empty sequence can be of any type */
168                            $1 = 1;
169                        } else {
170                            /* check the first element only */
171                            T* obj;
172                            SV **tv = av_fetch(av, 0, 0);
173                            if (SWIG_ConvertPtr(*tv, (void **)&obj,
174                                                $descriptor(T *),0) != -1)
175                                $1 = 1;
176                            else
177                                $1 = 0;
178                        }
179                    }
180                } else {
181                    $1 = 0;
182                }
183            }
184        }
185      public:
186        vector(unsigned int size = 0);
187        vector(unsigned int size, const T& value);
188        vector(const vector<T> &);
189
190        unsigned int size() const;
191        bool empty() const;
192        void clear();
193        %rename(push) push_back;
194        void push_back(const T& x);
195        %extend {
196            T pop() throw (std::out_of_range) {
197                if (self->size() == 0)
198                    throw std::out_of_range("pop from empty vector");
199                T x = self->back();
200                self->pop_back();
201                return x;
202            }
203            T& get(int i) throw (std::out_of_range) {
204                int size = int(self->size());
205                if (i>=0 && i<size)
206                    return (*self)[i];
207                else
208                    throw std::out_of_range("vector index out of range");
209            }
210            void set(int i, const T& x) throw (std::out_of_range) {
211                int size = int(self->size());
212                if (i>=0 && i<size)
213                    (*self)[i] = x;
214                else
215                    throw std::out_of_range("vector index out of range");
216            }
217        }
218    };
219
220    // specializations for pointers
221    template<class T> class vector<T*> {
222        %typemap(in) vector<T*> (std::vector<T*>* v) {
223	    int res = SWIG_ConvertPtr($input,(void **) &v, $&1_descriptor,0);
224            if (SWIG_IsOK(res)){
225                $1 = *v;
226            } else if (SvROK($input)) {
227                AV *av = (AV *)SvRV($input);
228                if (SvTYPE(av) != SVt_PVAV)
229                    SWIG_croak("Type error in argument $argnum of $symname. "
230                               "Expected an array of " #T);
231                I32 len = av_len(av) + 1;
232                for (int i=0; i<len; i++) {
233		    void *v;
234		    SV **tv = av_fetch(av, i, 0);
235		    int res = SWIG_ConvertPtr(*tv, &v, $descriptor(T *),0);
236                    if (SWIG_IsOK(res)) {
237                        $1.push_back(%static_cast(v, T *));
238                    } else {
239                        SWIG_croak("Type error in argument $argnum of "
240                                   "$symname. "
241                                   "Expected an array of " #T);
242                    }
243                }
244            } else {
245                SWIG_croak("Type error in argument $argnum of $symname. "
246                           "Expected an array of " #T);
247            }
248        }
249        %typemap(in) const vector<T *>& (std::vector<T *> temp,std::vector<T *>* v),
250                     const vector<T *>* (std::vector<T *> temp,std::vector<T *>* v) {
251	    int res = SWIG_ConvertPtr($input,(void **) &v, $1_descriptor,0);
252            if (SWIG_IsOK(res)) {
253                $1 = v;
254            } else if (SvROK($input)) {
255                AV *av = (AV *)SvRV($input);
256                if (SvTYPE(av) != SVt_PVAV)
257                    SWIG_croak("Type error in argument $argnum of $symname. "
258                               "Expected an array of " #T);
259                I32 len = av_len(av) + 1;
260                for (int i=0; i<len; i++) {
261		    void *v;
262		    SV **tv = av_fetch(av, i, 0);
263		    int res = SWIG_ConvertPtr(*tv, &v, $descriptor(T *),0);
264                    if (SWIG_IsOK(res)) {
265                        temp.push_back(%static_cast(v, T *));
266                    } else {
267                        SWIG_croak("Type error in argument $argnum of "
268                                   "$symname. "
269                                   "Expected an array of " #T);
270                    }
271                }
272                $1 = &temp;
273            } else {
274                SWIG_croak("Type error in argument $argnum of $symname. "
275                           "Expected an array of " #T);
276            }
277        }
278        %typemap(out) vector<T *> {
279            size_t len = $1.size();
280            SV **svs = new SV*[len];
281            for (size_t i=0; i<len; i++) {
282                T *x = (($1_type &)$1)[i];
283                svs[i] = sv_newmortal();
284		sv_setsv(svs[i], SWIG_NewPointerObj(x, $descriptor(T *), 0));
285            }
286            AV *myav = av_make(len, svs);
287            delete[] svs;
288            $result = newRV_noinc((SV*) myav);
289            sv_2mortal($result);
290            argvi++;
291        }
292        %typecheck(SWIG_TYPECHECK_VECTOR) vector<T *> {
293            {
294                /* wrapped vector? */
295                std::vector<T *>* v;
296		int res = SWIG_ConvertPtr($input,(void **) &v, $&1_descriptor,0);
297                if (SWIG_IsOK(res)) {
298                    $1 = 1;
299                } else if (SvROK($input)) {
300                    /* native sequence? */
301                    AV *av = (AV *)SvRV($input);
302                    if (SvTYPE(av) == SVt_PVAV) {
303                        I32 len = av_len(av) + 1;
304                        if (len == 0) {
305                            /* an empty sequence can be of any type */
306                            $1 = 1;
307                        } else {
308                            /* check the first element only */
309			    void *v;
310			    SV **tv = av_fetch(av, 0, 0);
311			    int res = SWIG_ConvertPtr(*tv, &v, $descriptor(T *),0);
312                            if (SWIG_IsOK(res))
313                                $1 = 1;
314                            else
315                                $1 = 0;
316                        }
317                    }
318                } else {
319                    $1 = 0;
320                }
321            }
322        }
323        %typecheck(SWIG_TYPECHECK_VECTOR) const vector<T *>&,const vector<T *>* {
324            {
325                /* wrapped vector? */
326                std::vector<T *> *v;
327		int res = SWIG_ConvertPtr($input,%as_voidptrptr(&v), $1_descriptor,0);
328                if (SWIG_IsOK(res)) {
329                    $1 = 1;
330                } else if (SvROK($input)) {
331                    /* native sequence? */
332                    AV *av = (AV *)SvRV($input);
333                    if (SvTYPE(av) == SVt_PVAV) {
334                        I32 len = av_len(av) + 1;
335                        if (len == 0) {
336                            /* an empty sequence can be of any type */
337                            $1 = 1;
338                        } else {
339                            /* check the first element only */
340			    void *v;
341			    SV **tv = av_fetch(av, 0, 0);
342			    int res = SWIG_ConvertPtr(*tv, &v, $descriptor(T *),0);
343                            if (SWIG_IsOK(res))
344                                $1 = 1;
345                            else
346                                $1 = 0;
347                        }
348                    }
349                } else {
350                    $1 = 0;
351                }
352            }
353        }
354      public:
355        vector(unsigned int size = 0);
356        vector(unsigned int size, T *value);
357        vector(const vector<T *> &);
358
359        unsigned int size() const;
360        bool empty() const;
361        void clear();
362        %rename(push) push_back;
363        void push_back(T *x);
364        %extend {
365            T *pop() throw (std::out_of_range) {
366                if (self->size() == 0)
367                    throw std::out_of_range("pop from empty vector");
368                T *x = self->back();
369                self->pop_back();
370                return x;
371            }
372            T *get(int i) throw (std::out_of_range) {
373                int size = int(self->size());
374                if (i>=0 && i<size)
375                    return (*self)[i];
376                else
377                    throw std::out_of_range("vector index out of range");
378            }
379            void set(int i, T *x) throw (std::out_of_range) {
380                int size = int(self->size());
381                if (i>=0 && i<size)
382                    (*self)[i] = x;
383                else
384                    throw std::out_of_range("vector index out of range");
385            }
386        }
387    };
388
389
390    // specializations for built-ins
391
392    %define specialize_std_vector(T,CHECK_T,TO_T,FROM_T)
393    template<> class vector<T> {
394        %typemap(in) vector<T> (std::vector<T>* v) {
395            if (SWIG_ConvertPtr($input,(void **) &v,
396                                $&1_descriptor,1) != -1){
397                $1 = *v;
398            } else if (SvROK($input)) {
399                AV *av = (AV *)SvRV($input);
400                if (SvTYPE(av) != SVt_PVAV)
401                    SWIG_croak("Type error in argument $argnum of $symname. "
402                               "Expected an array of " #T);
403                SV **tv;
404                I32 len = av_len(av) + 1;
405                for (int i=0; i<len; i++) {
406                    tv = av_fetch(av, i, 0);
407                    if (CHECK_T(*tv)) {
408                        $1.push_back((T)TO_T(*tv));
409                    } else {
410                        SWIG_croak("Type error in argument $argnum of "
411                                   "$symname. "
412                                   "Expected an array of " #T);
413                    }
414                }
415            } else {
416                SWIG_croak("Type error in argument $argnum of $symname. "
417                           "Expected an array of " #T);
418            }
419        }
420        %typemap(in) const vector<T>& (std::vector<T> temp,
421                                       std::vector<T>* v),
422                     const vector<T>* (std::vector<T> temp,
423                                       std::vector<T>* v) {
424            if (SWIG_ConvertPtr($input,(void **) &v,
425                                $1_descriptor,1) != -1) {
426                $1 = v;
427            } else if (SvROK($input)) {
428                AV *av = (AV *)SvRV($input);
429                if (SvTYPE(av) != SVt_PVAV)
430                    SWIG_croak("Type error in argument $argnum of $symname. "
431                               "Expected an array of " #T);
432                SV **tv;
433                I32 len = av_len(av) + 1;
434                for (int i=0; i<len; i++) {
435                    tv = av_fetch(av, i, 0);
436                    if (CHECK_T(*tv)) {
437                        temp.push_back((T)TO_T(*tv));
438                    } else {
439                        SWIG_croak("Type error in argument $argnum of "
440                                   "$symname. "
441                                   "Expected an array of " #T);
442                    }
443                }
444                $1 = &temp;
445            } else {
446                SWIG_croak("Type error in argument $argnum of $symname. "
447                           "Expected an array of " #T);
448            }
449        }
450        %typemap(out) vector<T> {
451            size_t len = $1.size();
452            SV **svs = new SV*[len];
453            for (size_t i=0; i<len; i++) {
454                svs[i] = sv_newmortal();
455                FROM_T(svs[i], $1[i]);
456            }
457            AV *myav = av_make(len, svs);
458            delete[] svs;
459            $result = newRV_noinc((SV*) myav);
460            sv_2mortal($result);
461            argvi++;
462        }
463        %typecheck(SWIG_TYPECHECK_VECTOR) vector<T> {
464            {
465                /* wrapped vector? */
466                std::vector<T >* v;
467                if (SWIG_ConvertPtr($input,(void **) &v,
468                                    $&1_descriptor,0) != -1) {
469                    $1 = 1;
470                } else if (SvROK($input)) {
471                    /* native sequence? */
472                    AV *av = (AV *)SvRV($input);
473                    if (SvTYPE(av) == SVt_PVAV) {
474                        I32 len = av_len(av) + 1;
475                        if (len == 0) {
476                            /* an empty sequence can be of any type */
477                            $1 = 1;
478                        } else {
479                            /* check the first element only */
480                            SV **tv = av_fetch(av, 0, 0);
481                            if (CHECK_T(*tv))
482                                $1 = 1;
483                            else
484                                $1 = 0;
485                        }
486                    }
487                } else {
488                    $1 = 0;
489                }
490            }
491        }
492        %typecheck(SWIG_TYPECHECK_VECTOR) const vector<T>&,
493                                          const vector<T>* {
494            {
495                /* wrapped vector? */
496                std::vector<T >* v;
497                if (SWIG_ConvertPtr($input,(void **) &v,
498                                    $1_descriptor,0) != -1) {
499                    $1 = 1;
500                } else if (SvROK($input)) {
501                    /* native sequence? */
502                    AV *av = (AV *)SvRV($input);
503                    if (SvTYPE(av) == SVt_PVAV) {
504                        I32 len = av_len(av) + 1;
505                        if (len == 0) {
506                            /* an empty sequence can be of any type */
507                            $1 = 1;
508                        } else {
509                            /* check the first element only */
510                            SV **tv = av_fetch(av, 0, 0);
511                            if (CHECK_T(*tv))
512                                $1 = 1;
513                            else
514                                $1 = 0;
515                        }
516                    }
517                } else {
518                    $1 = 0;
519                }
520            }
521        }
522      public:
523        vector(unsigned int size = 0);
524        vector(unsigned int size, T value);
525        vector(const vector<T> &);
526
527        unsigned int size() const;
528        bool empty() const;
529        void clear();
530        %rename(push) push_back;
531        void push_back(T x);
532        %extend {
533            T pop() throw (std::out_of_range) {
534                if (self->size() == 0)
535                    throw std::out_of_range("pop from empty vector");
536                T x = self->back();
537                self->pop_back();
538                return x;
539            }
540            T get(int i) throw (std::out_of_range) {
541                int size = int(self->size());
542                if (i>=0 && i<size)
543                    return (*self)[i];
544                else
545                    throw std::out_of_range("vector index out of range");
546            }
547            void set(int i, T x) throw (std::out_of_range) {
548                int size = int(self->size());
549                if (i>=0 && i<size)
550                    (*self)[i] = x;
551                else
552                    throw std::out_of_range("vector index out of range");
553            }
554        }
555    };
556    %enddef
557
558    specialize_std_vector(bool,SvIOK,SvIVX,sv_setiv);
559    specialize_std_vector(char,SvIOK,SvIVX,sv_setiv);
560    specialize_std_vector(int,SvIOK,SvIVX,sv_setiv);
561    specialize_std_vector(short,SvIOK,SvIVX,sv_setiv);
562    specialize_std_vector(long,SvIOK,SvIVX,sv_setiv);
563    specialize_std_vector(unsigned char,SvIOK,SvIVX,sv_setiv);
564    specialize_std_vector(unsigned int,SvIOK,SvIVX,sv_setiv);
565    specialize_std_vector(unsigned short,SvIOK,SvIVX,sv_setiv);
566    specialize_std_vector(unsigned long,SvIOK,SvIVX,sv_setiv);
567    specialize_std_vector(float,SvNIOK,SwigSvToNumber,sv_setnv);
568    specialize_std_vector(double,SvNIOK,SwigSvToNumber,sv_setnv);
569    specialize_std_vector(std::string,SvPOK,SwigSvToString,SwigSvFromString);
570}
571
572