Tesseract  3.02
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
genericvector.h
Go to the documentation of this file.
1 
2 // File: genericvector.h
3 // Description: Generic vector class
4 // Author: Daria Antonova
5 // Created: Mon Jun 23 11:26:43 PDT 2008
6 //
7 // (C) Copyright 2007, Google Inc.
8 // Licensed under the Apache License, Version 2.0 (the "License");
9 // you may not use this file except in compliance with the License.
10 // You may obtain a copy of the License at
11 // http://www.apache.org/licenses/LICENSE-2.0
12 // Unless required by applicable law or agreed to in writing, software
13 // distributed under the License is distributed on an "AS IS" BASIS,
14 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 // See the License for the specific language governing permissions and
16 // limitations under the License.
17 //
19 //
20 #ifndef TESSERACT_CCUTIL_GENERICVECTOR_H_
21 #define TESSERACT_CCUTIL_GENERICVECTOR_H_
22 
23 #include <stdio.h>
24 #include <stdlib.h>
25 
26 #include "tesscallback.h"
27 #include "errcode.h"
28 #include "helpers.h"
29 #include "ndminx.h"
30 
31 // Use PointerVector<T> below in preference to GenericVector<T*>, as that
32 // provides automatic deletion of pointers, [De]Serialize that works, and
33 // sort that works.
34 template <typename T>
36  public:
38  explicit GenericVector(int size) { this->init(size); }
39 
40  // Copy
41  GenericVector(const GenericVector& other) {
42  this->init(other.size());
43  this->operator+=(other);
44  }
47 
48  virtual ~GenericVector();
49 
50  // Reserve some memory.
51  void reserve(int size);
52  // Double the size of the internal array.
53  void double_the_size();
54 
55  // Resizes to size and sets all values to t.
56  void init_to_size(int size, T t);
57 
58  // Return the size used.
59  int size() const {
60  return size_used_;
61  }
62 
63  int length() const {
64  return size_used_;
65  }
66 
67  // Return true if empty.
68  bool empty() const {
69  return size_used_ == 0;
70  }
71 
72  // Return the object from an index.
73  T &get(int index) const;
74  T &back() const;
75  T &operator[](int index) const;
76 
77  // Return the index of the T object.
78  // This method NEEDS a compare_callback to be passed to
79  // set_compare_callback.
80  int get_index(T object) const;
81 
82  // Return true if T is in the array
83  bool contains(T object) const;
84 
85  // Return true if the index is valid
86  T contains_index(int index) const;
87 
88  // Push an element in the end of the array
89  int push_back(T object);
90  void operator+=(T t);
91 
92  // Push an element in the end of the array if the same
93  // element is not already contained in the array.
94  int push_back_new(T object);
95 
96  // Push an element in the front of the array
97  // Note: This function is O(n)
98  int push_front(T object);
99 
100  // Set the value at the given index
101  void set(T t, int index);
102 
103  // Insert t at the given index, push other elements to the right.
104  void insert(T t, int index);
105 
106  // Removes an element at the given index and
107  // shifts the remaining elements to the left.
108  virtual void remove(int index);
109 
110  // Truncates the array to the given size by removing the end.
111  // If the current size is less, the array is not expanded.
112  virtual void truncate(int size) {
113  if (size < size_used_)
114  size_used_ = size;
115  }
116 
117  // Add a callback to be called to delete the elements when the array took
118  // their ownership.
120 
121  // Add a callback to be called to compare the elements when needed (contains,
122  // get_id, ...)
124 
125  // Clear the array, calling the clear callback function if any.
126  // All the owned callbacks are also deleted.
127  // If you don't want the callbacks to be deleted, before calling clear, set
128  // the callback to NULL.
129  virtual void clear();
130 
131  // Delete objects pointed to by data_[i]
132  void delete_data_pointers();
133 
134  // This method clears the current object, then, does a shallow copy of
135  // its argument, and finally invalidates its argument.
136  // Callbacks are moved to the current object;
137  void move(GenericVector<T>* from);
138 
139  // Read/Write the array to a file. This does _NOT_ read/write the callbacks.
140  // The callback given must be permanent since they will be called more than
141  // once. The given callback will be deleted at the end.
142  // If the callbacks are NULL, then the data is simply read/written using
143  // fread (and swapping)/fwrite.
144  // Returns false on error or if the callback returns false.
145  // DEPRECATED. Use [De]Serialize[Classes] instead.
146  bool write(FILE* f, TessResultCallback2<bool, FILE*, T const &>* cb) const;
147  bool read(FILE* f, TessResultCallback3<bool, FILE*, T*, bool>* cb, bool swap);
148  // Writes a vector of simple types to the given file. Assumes that bitwise
149  // read/write of T will work. Returns false in case of error.
150  virtual bool Serialize(FILE* fp) const;
151  // Reads a vector of simple types from the given file. Assumes that bitwise
152  // read/write will work with ReverseN according to sizeof(T).
153  // Returns false in case of error.
154  // If swap is true, assumes a big/little-endian swap is needed.
155  virtual bool DeSerialize(bool swap, FILE* fp);
156  // Writes a vector of classes to the given file. Assumes the existence of
157  // bool T::Serialize(FILE* fp) const that returns false in case of error.
158  // Returns false in case of error.
159  bool SerializeClasses(FILE* fp) const;
160  // Reads a vector of classes from the given file. Assumes the existence of
161  // bool T::Deserialize(bool swap, FILE* fp) that returns false in case of
162  // error. Also needs T::T() and T::T(constT&), as init_to_size is used in
163  // this function. Returns false in case of error.
164  // If swap is true, assumes a big/little-endian swap is needed.
165  bool DeSerializeClasses(bool swap, FILE* fp);
166 
167  // Allocates a new array of double the current_size, copies over the
168  // information from data to the new location, deletes data and returns
169  // the pointed to the new larger array.
170  // This function uses memcpy to copy the data, instead of invoking
171  // operator=() for each element like double_the_size() does.
172  static T *double_the_size_memcpy(int current_size, T *data) {
173  T *data_new = new T[current_size * 2];
174  memcpy(data_new, data, sizeof(T) * current_size);
175  delete[] data;
176  return data_new;
177  }
178 
179  // Sorts the members of this vector using the less than comparator (cmp_lt),
180  // which compares the values. Useful for GenericVectors to primitive types.
181  // Will not work so great for pointers (unless you just want to sort some
182  // pointers). You need to provide a specialization to sort_cmp to use
183  // your type.
184  void sort();
185 
186  // Sort the array into the order defined by the qsort function comparator.
187  // The comparator function is as defined by qsort, ie. it receives pointers
188  // to two Ts and returns negative if the first element is to appear earlier
189  // in the result and positive if it is to appear later, with 0 for equal.
190  void sort(int (*comparator)(const void*, const void*)) {
191  qsort(data_, size_used_, sizeof(*data_), comparator);
192  }
193 
194  // Searches the array (assuming sorted in ascending order, using sort()) for
195  // an element equal to target and returns true if it is present.
196  // Use binary_search to get the index of target, or its nearest candidate.
197  bool bool_binary_search(const T& target) const {
198  int index = binary_search(target);
199  if (index >= size_used_)
200  return false;
201  return data_[index] == target;
202  }
203  // Searches the array (assuming sorted in ascending order, using sort()) for
204  // an element equal to target and returns the index of the best candidate.
205  // The return value is conceptually the largest index i such that
206  // data_[i] <= target or 0 if target < the whole vector.
207  // NOTE that this function uses operator> so really the return value is
208  // the largest index i such that data_[i] > target is false.
209  int binary_search(const T& target) const {
210  int bottom = 0;
211  int top = size_used_;
212  do {
213  int middle = (bottom + top) / 2;
214  if (data_[middle] > target)
215  top = middle;
216  else
217  bottom = middle;
218  }
219  while (top - bottom > 1);
220  return bottom;
221  }
222 
223  // Compact the vector by deleting elements using operator!= on basic types.
224  // The vector must be sorted.
225  void compact_sorted() {
226  if (size_used_ == 0)
227  return;
228 
229  // First element is in no matter what, hence the i = 1.
230  int last_write = 0;
231  for (int i = 1; i < size_used_; ++i) {
232  // Finds next unique item and writes it.
233  if (data_[last_write] != data_[i])
234  data_[++last_write] = data_[i];
235  }
236  // last_write is the index of a valid data cell, so add 1.
237  size_used_ = last_write + 1;
238  }
239 
240  // Compact the vector by deleting elements for which delete_cb returns
241  // true. delete_cb is a permanent callback and will be deleted.
243  int new_size = 0;
244  int old_index = 0;
245  // Until the callback returns true, the elements stay the same.
246  while (old_index < size_used_ && !delete_cb->Run(old_index++))
247  ++new_size;
248  // Now just copy anything else that gets false from delete_cb.
249  for (; old_index < size_used_; ++old_index) {
250  if (!delete_cb->Run(old_index)) {
251  data_[new_size++] = data_[old_index];
252  }
253  }
254  size_used_ = new_size;
255  delete delete_cb;
256  }
257 
258  T dot_product(const GenericVector<T>& other) const {
259  T result = static_cast<T>(0);
260  for (int i = MIN(size_used_, other.size_used_) - 1; i >= 0; --i)
261  result += data_[i] * other.data_[i];
262  return result;
263  }
264 
265  protected:
266 
267  // Init the object, allocating size memory.
268  void init(int size);
269 
270  // We are assuming that the object generally placed in thie
271  // vector are small enough that for efficiency it makes sence
272  // to start with a larger initial size.
273  static const int kDefaultVectorSize = 4;
276  T* data_;
278  // Mutable because Run method is not const
280 };
281 
282 namespace tesseract {
283 
284 template <typename T>
285 bool cmp_eq(T const & t1, T const & t2) {
286  return t1 == t2;
287 }
288 
289 // Used by sort()
290 // return < 0 if t1 < t2
291 // return 0 if t1 == t2
292 // return > 0 if t1 > t2
293 template <typename T>
294 int sort_cmp(const void* t1, const void* t2) {
295  const T* a = static_cast<const T *> (t1);
296  const T* b = static_cast<const T *> (t2);
297  if (*a < *b) {
298  return -1;
299  } else if (*b < *a) {
300  return 1;
301  } else {
302  return 0;
303  }
304 }
305 
306 // Used by PointerVector::sort()
307 // return < 0 if t1 < t2
308 // return 0 if t1 == t2
309 // return > 0 if t1 > t2
310 template <typename T>
311 int sort_ptr_cmp(const void* t1, const void* t2) {
312  const T* a = *reinterpret_cast<T * const *>(t1);
313  const T* b = *reinterpret_cast<T * const *>(t2);
314  if (*a < *b) {
315  return -1;
316  } else if (*b < *a) {
317  return 1;
318  } else {
319  return 0;
320  }
321 }
322 
323 // Subclass for a vector of pointers. Use in preference to GenericVector<T*>
324 // as it provides automatic deletion and correct serialization, with the
325 // corollary that all copy operations are deep copies of the pointed-to objects.
326 template<typename T>
327 class PointerVector : public GenericVector<T*> {
328  public:
330  explicit PointerVector(int size) : GenericVector<T*>(size) { }
331  virtual ~PointerVector() {
332  // Clear must be called here, even though it is called again by the base,
333  // as the base will call the wrong clear.
334  clear();
335  }
336  // Copy must be deep, as the pointers will be automatically deleted on
337  // destruction.
338  PointerVector(const PointerVector& other) {
339  this->init(other.size());
340  this->operator+=(other);
341  }
343  this->reserve(this->size_used_ + other.size_used_);
344  for (int i = 0; i < other.size(); ++i) {
345  this->push_back(new T(*other.data_[i]));
346  }
347  return *this;
348  }
349 
351  this->truncate(0);
352  this->operator+=(other);
353  return *this;
354  }
355 
356  // Removes an element at the given index and
357  // shifts the remaining elements to the left.
358  virtual void remove(int index) {
359  delete GenericVector<T*>::data_[index];
361  }
362 
363  // Truncates the array to the given size by removing the end.
364  // If the current size is less, the array is not expanded.
365  virtual void truncate(int size) {
366  for (int i = size; i < GenericVector<T*>::size_used_; ++i)
367  delete GenericVector<T*>::data_[i];
369  }
370 
371  // Compact the vector by deleting elements for which delete_cb returns
372  // true. delete_cb is a permanent callback and will be deleted.
374  int new_size = 0;
375  int old_index = 0;
376  // Until the callback returns true, the elements stay the same.
377  while (old_index < GenericVector<T*>::size_used_ &&
378  !delete_cb->Run(GenericVector<T*>::data_[old_index++]))
379  ++new_size;
380  // Now just copy anything else that gets false from delete_cb.
381  for (; old_index < GenericVector<T*>::size_used_; ++old_index) {
382  if (!delete_cb->Run(GenericVector<T*>::data_[old_index])) {
383  GenericVector<T*>::data_[new_size++] =
384  GenericVector<T*>::data_[old_index];
385  } else {
386  delete GenericVector<T*>::data_[old_index];
387  }
388  }
390  delete delete_cb;
391  }
392 
393  // Clear the array, calling the clear callback function if any.
394  // All the owned callbacks are also deleted.
395  // If you don't want the callbacks to be deleted, before calling clear, set
396  // the callback to NULL.
397  virtual void clear() {
400  }
401 
402  // Writes a vector of simple types to the given file. Assumes that bitwise
403  // read/write of T will work. Returns false in case of error.
404  virtual bool Serialize(FILE* fp) const {
406  if (fwrite(&used, sizeof(used), 1, fp) != 1) return false;
407  for (int i = 0; i < used; ++i) {
408  inT8 non_null = GenericVector<T*>::data_[i] != NULL;
409  if (fwrite(&non_null, sizeof(non_null), 1, fp) != 1) return false;
410  if (non_null && !GenericVector<T*>::data_[i]->Serialize(fp)) return false;
411  }
412  return true;
413  }
414  // Reads a vector of simple types from the given file. Assumes that bitwise
415  // read/write will work with ReverseN according to sizeof(T).
416  // Also needs T::T(), as new T is used in this function.
417  // Returns false in case of error.
418  // If swap is true, assumes a big/little-endian swap is needed.
419  virtual bool DeSerialize(bool swap, FILE* fp) {
420  inT32 reserved;
421  if (fread(&reserved, sizeof(reserved), 1, fp) != 1) return false;
422  if (swap) Reverse32(&reserved);
423  GenericVector<T*>::reserve(reserved);
424  for (int i = 0; i < reserved; ++i) {
425  inT8 non_null;
426  if (fread(&non_null, sizeof(non_null), 1, fp) != 1) return false;
427  T* item = NULL;
428  if (non_null) {
429  item = new T;
430  if (!item->DeSerialize(swap, fp)) return false;
431  }
432  this->push_back(item);
433  }
434  return true;
435  }
436 
437  // Sorts the items pointed to by the members of this vector using
438  // t::operator<().
439  void sort() {
440  sort(&sort_ptr_cmp<T>);
441  }
442 };
443 
444 } // namespace tesseract
445 
446 // A useful vector that uses operator== to do comparisons.
447 template <typename T>
448 class GenericVectorEqEq : public GenericVector<T> {
449  public:
452  NewPermanentTessCallback(tesseract::cmp_eq<T>));
453  }
456  NewPermanentTessCallback(tesseract::cmp_eq<T>));
457  }
458 };
459 
460 template <typename T>
461 void GenericVector<T>::init(int size) {
462  size_used_ = 0;
463  size_reserved_ = 0;
464  data_ = 0;
465  clear_cb_ = 0;
466  compare_cb_ = 0;
467  reserve(size);
468 }
469 
470 template <typename T>
472  clear();
473 }
474 
475 // Reserve some memory. If the internal array contains elements, they are
476 // copied.
477 template <typename T>
479  if (size_reserved_ >= size || size <= 0)
480  return;
481  T* new_array = new T[size];
482  for (int i = 0; i < size_used_; ++i)
483  new_array[i] = data_[i];
484  if (data_ != NULL) delete[] data_;
485  data_ = new_array;
486  size_reserved_ = size;
487 }
488 
489 template <typename T>
491  if (size_reserved_ == 0) {
492  reserve(kDefaultVectorSize);
493  }
494  else {
495  reserve(2 * size_reserved_);
496  }
497 }
498 
499 // Resizes to size and sets all values to t.
500 template <typename T>
501 void GenericVector<T>::init_to_size(int size, T t) {
502  reserve(size);
503  size_used_ = size;
504  for (int i = 0; i < size; ++i)
505  data_[i] = t;
506 }
507 
508 
509 // Return the object from an index.
510 template <typename T>
511 T &GenericVector<T>::get(int index) const {
512  ASSERT_HOST(index >= 0 && index < size_used_);
513  return data_[index];
514 }
515 
516 template <typename T>
517 T &GenericVector<T>::operator[](int index) const {
518  return data_[index];
519 }
520 
521 template <typename T>
523  ASSERT_HOST(size_used_ > 0);
524  return data_[size_used_ - 1];
525 }
526 
527 // Return the object from an index.
528 template <typename T>
529 void GenericVector<T>::set(T t, int index) {
530  ASSERT_HOST(index >= 0 && index < size_used_);
531  data_[index] = t;
532 }
533 
534 // Shifts the rest of the elements to the right to make
535 // space for the new elements and inserts the given element
536 // at the specified index.
537 template <typename T>
538 void GenericVector<T>::insert(T t, int index) {
539  ASSERT_HOST(index >= 0 && index < size_used_);
540  if (size_reserved_ == size_used_)
541  double_the_size();
542  for (int i = size_used_; i > index; --i) {
543  data_[i] = data_[i-1];
544  }
545  data_[index] = t;
546  size_used_++;
547 }
548 
549 // Removes an element at the given index and
550 // shifts the remaining elements to the left.
551 template <typename T>
552 void GenericVector<T>::remove(int index) {
553  ASSERT_HOST(index >= 0 && index < size_used_);
554  for (int i = index; i < size_used_ - 1; ++i) {
555  data_[i] = data_[i+1];
556  }
557  size_used_--;
558 }
559 
560 // Return true if the index is valindex
561 template <typename T>
563  return index >= 0 && index < size_used_;
564 }
565 
566 // Return the index of the T object.
567 template <typename T>
568 int GenericVector<T>::get_index(T object) const {
569  for (int i = 0; i < size_used_; ++i) {
570  ASSERT_HOST(compare_cb_ != NULL);
571  if (compare_cb_->Run(object, data_[i]))
572  return i;
573  }
574  return -1;
575 }
576 
577 // Return true if T is in the array
578 template <typename T>
579 bool GenericVector<T>::contains(T object) const {
580  return get_index(object) != -1;
581 }
582 
583 // Add an element in the array
584 template <typename T>
586  int index = 0;
587  if (size_used_ == size_reserved_)
588  double_the_size();
589  index = size_used_++;
590  data_[index] = object;
591  return index;
592 }
593 
594 template <typename T>
596  int index = get_index(object);
597  if (index >= 0)
598  return index;
599  return push_back(object);
600 }
601 
602 // Add an element in the array (front)
603 template <typename T>
605  if (size_used_ == size_reserved_)
606  double_the_size();
607  for (int i = size_used_; i > 0; --i)
608  data_[i] = data_[i-1];
609  data_[0] = object;
610  ++size_used_;
611  return 0;
612 }
613 
614 template <typename T>
616  push_back(t);
617 }
618 
619 template <typename T>
621  this->reserve(size_used_ + other.size_used_);
622  for (int i = 0; i < other.size(); ++i) {
623  this->operator+=(other.data_[i]);
624  }
625  return *this;
626 }
627 
628 template <typename T>
630  this->truncate(0);
631  this->operator+=(other);
632  return *this;
633 }
634 
635 // Add a callback to be called to delete the elements when the array took
636 // their ownership.
637 template <typename T>
639  clear_cb_ = cb;
640 }
641 
642 // Add a callback to be called to delete the elements when the array took
643 // their ownership.
644 template <typename T>
646  compare_cb_ = cb;
647 }
648 
649 // Clear the array, calling the callback function if any.
650 template <typename T>
652  if (size_reserved_ > 0) {
653  if (clear_cb_ != NULL)
654  for (int i = 0; i < size_used_; ++i)
655  clear_cb_->Run(data_[i]);
656  delete[] data_;
657  data_ = NULL;
658  size_used_ = 0;
659  size_reserved_ = 0;
660  }
661  if (clear_cb_ != NULL) {
662  delete clear_cb_;
663  clear_cb_ = NULL;
664  }
665  if (compare_cb_ != NULL) {
666  delete compare_cb_;
667  compare_cb_ = NULL;
668  }
669 }
670 
671 template <typename T>
673  for (int i = 0; i < size_used_; ++i)
674  if (data_[i]) {
675  delete data_[i];
676  }
677 }
678 
679 
680 template <typename T>
683  if (fwrite(&size_reserved_, sizeof(size_reserved_), 1, f) != 1) return false;
684  if (fwrite(&size_used_, sizeof(size_used_), 1, f) != 1) return false;
685  if (cb != NULL) {
686  for (int i = 0; i < size_used_; ++i) {
687  if (!cb->Run(f, data_[i])) {
688  delete cb;
689  return false;
690  }
691  }
692  delete cb;
693  } else {
694  if (fwrite(data_, sizeof(T), size_used_, f) != size_used_) return false;
695  }
696  return true;
697 }
698 
699 template <typename T>
702  bool swap) {
703  inT32 reserved;
704  if (fread(&reserved, sizeof(reserved), 1, f) != 1) return false;
705  if (swap) Reverse32(&reserved);
706  reserve(reserved);
707  if (fread(&size_used_, sizeof(size_used_), 1, f) != 1) return false;
708  if (swap) Reverse32(&size_used_);
709  if (cb != NULL) {
710  for (int i = 0; i < size_used_; ++i) {
711  if (!cb->Run(f, data_ + i, swap)) {
712  delete cb;
713  return false;
714  }
715  }
716  delete cb;
717  } else {
718  if (fread(data_, sizeof(T), size_used_, f) != size_used_) return false;
719  if (swap) {
720  for (int i = 0; i < size_used_; ++i)
721  ReverseN(&data_[i], sizeof(T));
722  }
723  }
724  return true;
725 }
726 
727 // Writes a vector of simple types to the given file. Assumes that bitwise
728 // read/write of T will work. Returns false in case of error.
729 template <typename T>
730 bool GenericVector<T>::Serialize(FILE* fp) const {
731  if (fwrite(&size_used_, sizeof(size_used_), 1, fp) != 1) return false;
732  if (fwrite(data_, sizeof(*data_), size_used_, fp) != size_used_) return false;
733  return true;
734 }
735 
736 // Reads a vector of simple types from the given file. Assumes that bitwise
737 // read/write will work with ReverseN according to sizeof(T).
738 // Returns false in case of error.
739 // If swap is true, assumes a big/little-endian swap is needed.
740 template <typename T>
741 bool GenericVector<T>::DeSerialize(bool swap, FILE* fp) {
742  inT32 reserved;
743  if (fread(&reserved, sizeof(reserved), 1, fp) != 1) return false;
744  if (swap) Reverse32(&reserved);
745  reserve(reserved);
746  size_used_ = reserved;
747  if (fread(data_, sizeof(T), size_used_, fp) != size_used_) return false;
748  if (swap) {
749  for (int i = 0; i < size_used_; ++i)
750  ReverseN(&data_[i], sizeof(data_[i]));
751  }
752  return true;
753 }
754 
755 // Writes a vector of classes to the given file. Assumes the existence of
756 // bool T::Serialize(FILE* fp) const that returns false in case of error.
757 // Returns false in case of error.
758 template <typename T>
760  if (fwrite(&size_used_, sizeof(size_used_), 1, fp) != 1) return false;
761  for (int i = 0; i < size_used_; ++i) {
762  if (!data_[i].Serialize(fp)) return false;
763  }
764  return true;
765 }
766 
767 // Reads a vector of classes from the given file. Assumes the existence of
768 // bool T::Deserialize(bool swap, FILE* fp) that returns false in case of
769 // error. Alse needs T::T() and T::T(constT&), as init_to_size is used in
770 // this function. Returns false in case of error.
771 // If swap is true, assumes a big/little-endian swap is needed.
772 template <typename T>
773 bool GenericVector<T>::DeSerializeClasses(bool swap, FILE* fp) {
774  uinT32 reserved;
775  if (fread(&reserved, sizeof(reserved), 1, fp) != 1) return false;
776  if (swap) Reverse32(&reserved);
777  T empty;
778  init_to_size(reserved, empty);
779  for (int i = 0; i < reserved; ++i) {
780  if (!data_[i].DeSerialize(swap, fp)) return false;
781  }
782  return true;
783 }
784 
785 // This method clear the current object, then, does a shallow copy of
786 // its argument, and finally invalidates its argument.
787 template <typename T>
789  this->clear();
790  this->data_ = from->data_;
791  this->size_reserved_ = from->size_reserved_;
792  this->size_used_ = from->size_used_;
793  this->compare_cb_ = from->compare_cb_;
794  this->clear_cb_ = from->clear_cb_;
795  from->data_ = NULL;
796  from->clear_cb_ = NULL;
797  from->compare_cb_ = NULL;
798  from->size_used_ = 0;
799  from->size_reserved_ = 0;
800 }
801 
802 template <typename T>
804  sort(&tesseract::sort_cmp<T>);
805 }
806 
807 #endif // TESSERACT_CCUTIL_GENERICVECTOR_H_