Proton  1.1.1
Make porting easy from Python to C++11
vector.hpp
Go to the documentation of this file.
1 #ifndef PROTON_VECTOR_HEADER
2 #define PROTON_VECTOR_HEADER
3 
4 
5 /** @file vector.hpp
6  * @brief vector support.
7  * Please include this header instead of <vector>.
8  */
9 
10 #include <vector>
11 #include <algorithm>
12 #include <iostream>
13 #include <initializer_list>
14 #include <algorithm>
15 #include <stdexcept>
16 
17 #include <proton/base.hpp>
18 #include <proton/pool.hpp>
19 #include <proton/ref.hpp>
20 
21 namespace proton{
22 
23 /** @addtogroup vector_
24  * @{
25  */
26 
27 /** add an item in streaming style.
28  * @param x the vector to be added
29  * @param val the new item
30  * @return the new x
31  */
32 template <typename T, typename A, typename V>
33 std::vector<T,A>& operator<<(std::vector<T,A>& x, V&& val)
34 {
35  x.push_back(val);
36  return x;
37 }
38 
39 /** pop an item in streaming style.
40  * @param x the vector to be popped from
41  * @param val the popped item
42  * @return the new x
43  */
44 template <typename T, typename A, typename V>
45 std::vector<T,A>& operator>>(std::vector<T,A>& x, V& val)
46 {
47  PROTON_THROW_IF(x.empty(), "want to pop an empty vector.");
48  val=x.back();
49  x.pop_back();
50  return x;
51 }
52 
53 /** general output for vector.
54  * @param s the output stream
55  * @param x the vector to be outputed
56  * @return s
57  */
58 template <typename T, typename A>
59 std::ostream& operator<<(std::ostream& s, const std::vector<T,A>& x)
60 {
61  s << "[";
62  bool first=true;
63  for(auto& t: x){
64  if(first)
65  first=false;
66  else
67  s <<", ";
68  s << t;
69  }
70  s << "]";
71  return s;
72 }
73 
74 template <typename T, typename A>
75 std::wostream& operator<<(std::wostream& s, const std::vector<T,A>& x)
76 {
77  s << L"[";
78  bool first=true;
79  for(auto& t: x){
80  if(first)
81  first=false;
82  else
83  s <<L", ";
84  s << t;
85  }
86  s << L"]";
87  return s;
88 }
89 
90 /* sort a vector
91  * @param x the vector to be sorted
92  */
93 template <typename T, typename A>
94 void sort(std::vector<T,A>& x)
95 {
96  std::sort(x.begin(), x.end());
97 }
98 
99 /* get an item like python.
100  * @param x the sequence
101  * @param i the index
102  * @return x[i]
103  */
104 template <typename T, typename A>
105 T& get(std::vector<T,A>& x, long i)
106 {
107  unsigned long s=x.size();
108  if(i<0)
109  i=s+i;
110  if(i<0 || (unsigned long)i >= s )
111  PROTON_ERR("out of range: look up "<<i<<" in vector whose size is " << s);
112  return x[i];
113 }
114 
115 /* get a const item like python.
116  * @param x the sequence
117  * @param i the index
118  * @return x[i]
119  */
120 template <typename T, typename A>
121 const T& get(const std::vector<T,A>& x, long i)
122 {
123  unsigned long s=x.size();
124  if(i<0)
125  i=s+i;
126  if(i<0 || (unsigned long)i >= s )
127  PROTON_ERR("out of range: look up "<<i<<" in vector whose size is " << s);
128  return x[i];
129 }
130 
131 /* get a slice like python.
132  * @param x the sequence
133  * @param first the start
134  * @return x[first:]
135  */
136 template <typename T, typename A>
137 std::vector<T,A> sub(const std::vector<T,A>& x, long first)
138 {
139  std::vector<T,A> r;
140  unsigned long s=x.size();
141  if(first<0)
142  first=first+s;
143  if(first<0)
144  first=0;
145  if((unsigned long)first >= s )
146  return r;
147 
148  auto start=x.begin();
149  std::copy(start+first, x.end(), std::back_inserter(r));
150  return r;
151 }
152 
153 /* get a slice like python.
154  * @param x the sequence
155  * @param first the start
156  * @param last the end
157  * @return x[first:last]
158  */
159 template <typename T, typename A>
160 std::vector<T,A> sub(const std::vector<T,A>& x, long first, long last)
161 {
162  std::vector<T,A> r;
163  unsigned long s=x.size();
164  if(first<0)
165  first=first+s;
166  if(first<0)
167  first=0;
168  if((unsigned long)first >= s )
169  return r;
170 
171  if(last<0)
172  last=last+s;
173  if(last<=0)
174  return r;
175 
176  if((unsigned long)last>s)
177  last=s;
178  auto start=x.begin();
179  std::copy(start+first, start+last, std::back_inserter(r));
180  return r;
181 }
182 
183 /** a vector extension implementing python's list-like interfaces.
184  */
185 template <typename T, typename A=smart_allocator<T> >
186 class vector_ : public std::vector<T,A>{
187  public:
188  typedef std::vector<T,A> baseT;
189  typedef typename baseT::difference_type offset_t;
190 
191 protected:
192  offset_t __offset(offset_t i)const
193  {
194  if(i<0)
195  i+=this->size();
196  return i;
197  }
198 
199  offset_t offset(offset_t i)const
200  {
201  i=__offset(i);
202  PROTON_THROW_IF(i<0 || (size_t)i>=this->size(), "out of range, offset is " << i
203  << " while size is " << this->size() );
204  return i;
205  }
206 
207  int fix_offset(offset_t begin)const
208  {
209  offset_t size=(offset_t)this->size();
210  begin=__offset(begin);
211  if(begin>=size){
212  return size;
213  }
214  if(begin<0)
215  return 0;
216  return begin;
217  }
218 
219  void fix_range(offset_t& begin, offset_t& end)const
220  {
221  offset_t size=(offset_t)this->size();
222  begin=__offset(begin);
223  end=__offset(end);
224  if(begin>=size || end<=0 || end<=begin){
225  begin=0;
226  end=0;
227  return;
228  }
229  if(begin<0)
230  begin=0;
231  if(end>=size)
232  end=size;
233  }
234 
235 public:
236  /** forwarding ctor.
237  */
238  template<typename ...argT> vector_(argT&& ...a):baseT(a...)
239  {}
240 
241  /** initializer_list forwarding ctor.
242  */
243  vector_(std::initializer_list<T> a):baseT(a)
244  {}
245 
246  /** copy ctor.
247  */
248  vector_(const vector_& x):baseT(x)
249  {}
250 
251  /** move ctor.
252  */
253  vector_(vector_&& x)noexcept:baseT(x)
254  {}
255 
256  explicit vector_(const baseT& x):baseT(x)
257  {}
258 
259  vector_(baseT&& x)noexcept:baseT(x)
260  {}
261 
262  /** assign.
263  */
265  {
266  baseT::operator=(x);
267  return *this;
268  }
269 
270  vector_& operator=(vector_&& x)noexcept
271  {
272  baseT::operator=(x);
273  return *this;
274  }
275 
276  vector_& operator=(const baseT& x)
277  {
278  baseT::operator=(x);
279  return *this;
280  }
281 
282  vector_& operator=(baseT&& x)noexcept
283  {
284  baseT::operator=(x);
285  return *this;
286  }
287 
288  template<typename argT> vector_& operator=(argT&& a)
289  {
290  baseT::operator=(a);
291  return *this;
292  }
293 
294  vector_& operator=(std::initializer_list<T> a)
295  {
296  baseT::operator=(a);
297  return *this;
298  }
299 
300  /** cast to std::vector<>&.
301  */
302  operator baseT&()
303  {
304  return reinterpret_cast<baseT&>(*this);
305  }
306 
307  /** [i] in python
308  */
309  T& operator[](offset_t i)
310  {
311  return *(this->begin()+offset(i));
312  }
313 
314  /** [i] in python
315  */
316  const T& operator[](offset_t i)const
317  {
318  return *(this->begin()+offset(i));
319  }
320 
321  /** slice of [i:]
322  */
323  vector_ operator()(offset_t i)const
324  {
325  auto begin=this->begin();
326  return vector_(begin+offset(i),this->end());
327  }
328 
329  /** slice of [i:j]
330  */
331  vector_ operator()(offset_t i, offset_t j)const
332  {
333  auto begin=this->begin();
334  fix_range(i,j);
335  return vector_(begin+i,begin+j);
336  }
337 
338  /** slice of [i:j:k]
339  */
340  vector_ operator()(offset_t i, offset_t j, size_t k)const
341  {
342  fix_range(i,j);
343  vector_ r;
344  r.reserve((j-i)/k+1);
345  auto it=this->begin()+i;
346  for(offset_t n=i; n<j; n+=k,it+=k)
347  r.push_back(*it);
348  return r;
349  }
350 
351  /** append an item at the end.
352  */
353  void append(const T& x)
354  {
355  this->push_back(x);
356  }
357 
358  void append(T&& x)
359  {
360  this->push_back(x);
361  }
362 
363  /** total number of occurences of x.
364  */
365  size_t count(const T& x)const
366  {
367  return std::count(this->begin(), this->end(), x);
368  }
369 
370  /** delete the i-th item
371  */
372  void del(offset_t i)
373  {
374  this->erase(this->begin()+offset(i));
375  }
376 
377  /** delete from i-th to the j-th items
378  */
379  void del(offset_t i, offset_t j)
380  {
381  fix_range(i,j);
382  auto begin=this->begin();
383  this->erase(begin+i, begin+j);
384  }
385 
386  /** delete from i-th item to the end
387  */
388  void del_to_end(offset_t i)
389  {
390  this->erase(this->begin()+offset(i), this->end());
391  }
392 
393  /** append items from a sequence.
394  */
395  template<typename seqT>void extend(const seqT& x)
396  {
397  for(auto& i:x){
398  this->push_back(i);
399  }
400  }
401 
402  template<typename seqT>void extend(seqT&& x)
403  {
404  for(auto&& i:x){
405  this->push_back(i);
406  }
407  }
408 
409  /** index of the first occurence of a value.
410  * @param val the value.
411  * @throw std::invalid_argument if there is no such a value.
412  */
413  offset_t index(const T& val)const
414  {
415  auto begin=this->begin(), end=this->end();
416  auto it=std::find(begin, end, val);
417  if(it==end)
418  throw std::invalid_argument("The given value doesn't exist in this sequence.");
419  return it-begin;
420  }
421 
422  /** insert value at offset i.
423  * @param i the offset, like python, -1 means the last position.
424  * @param val the value.
425  * @throw proton::err if i is bad.
426  */
427  void insert(offset_t i, const T& val)
428  {
429  auto it=this->begin()+ offset(i);
430  baseT::insert(it, val);
431  }
432 
433  void insert(offset_t i, T&& val)
434  {
435  auto it=this->begin()+offset(i);
436  baseT::insert(it, val);
437  }
438 
439  /** pop an item from the sequence.
440  * @param i the index of the itme, default is -1, the last item.
441  * @return the value at offset i.
442  * @throw proton::err if i is bad.
443  */
444  T pop(offset_t i=-1)
445  {
446  auto it=this->begin()+offset(i);
447  T r=*it;
448  this->erase(it);
449  return r;
450  }
451 
452  /** remove the first occurence of a value.
453  * @param val the value.
454  * @throw std::invalid_argument if there is no such a value.
455  */
456  void remove(const T& val)
457  {
458  auto begin=this->begin(), end=this->end();
459  auto it=std::find(begin, end, val);
460  if(it==end)
461  throw std::invalid_argument("The given value doesn't exist in this sequence.");
462  this->erase(it);
463  }
464 
465  /** reverses the items in place.
466  */
467  void reverse()
468  {
469  std::reverse(this->begin(), this->end());
470  }
471 
472  /** sort the items in place.
473  */
474  void sort()
475  {
476  std::sort(this->begin(), this->end());
477  }
478 
479  /** sort the items in place using a customized cmp.
480  */
481  template<class cmpT>void sort(cmpT cmp)
482  {
483  std::sort(this->begin(), this->end(),cmp);
484  }
485 
486 };
487 
488 /**
489  * @example vector.cpp
490  */
491 
492 /** vector + vector
493  */
494 template<typename T, typename A, typename X>
495 vector_<T,A> operator+(const std::vector<T,A>& s, X&& t)
496 {
497  vector_<T,A> r(s);
498  r.extend(std::forward<X>(t));
499  return r;
500 }
501 
502 template<typename T, typename A, typename X>
503 vector_<T,A> operator+(std::vector<T,A>&& s, X&& t)
504 {
505  vector_<T,A> r(s);
506  r.extend(std::forward<X>(t));
507  return r;
508 }
509 
510 /** vector_ * n
511  */
512 template<typename T, typename A>
513 vector_<T,A> operator*(const std::vector<T,A>& s, size_t n)
514 {
515  vector_<T,A> r;
516  r.reserve(s.size()*n);
517  for(size_t i=0; i<n; i++)
518  r.extend(s);
519  return r;
520 }
521 
522 /** n * vector_
523  */
524 template<typename T, typename A>
525 vector_<T,A> operator*(size_t n, const std::vector<T,A>& s)
526 {
527  return s*n;
528 }
529 
530 /** cast to proton::vector_<>& from std::vector<>&.
531  */
532 template<typename T, typename A>
533 vector_<T,A>& cast_(std::vector<T,A>& x)
534 {
535  return reinterpret_cast<vector_<T,A>&>(x);
536 }
537 
538 template<typename T, typename A>
539 const vector_<T,A>& cast_(const std::vector<T,A>& x)
540 {
541  return reinterpret_cast<const vector_<T,A>&>(x);
542 }
543 
544 template<typename T, typename A>
545 vector_<T,A>&& cast_(std::vector<T,A>&& x)
546 {
547  return reinterpret_cast<vector_<T,A>&&>(x);
548 }
549 
550 template<typename T, typename A>
551 const vector_<T,A>&& cast_(const std::vector<T,A>&& x)
552 {
553  return reinterpret_cast<const vector_<T,A>&&>(x);
554 }
555 
556 /**
557  * @}
558  */
559 }
560 
561 #endif // PROTON_VECTOR_HEADER