Signal/Geometry Processing Library (SPL)  1.1.24
Array1.hpp
Go to the documentation of this file.
1 // Copyright (c) 2011 Michael D. Adams
2 // All rights reserved.
3 
4 // __START_OF_LICENSE__
5 //
6 // Copyright (c) 2015 Michael D. Adams
7 // All rights reserved.
8 //
9 // This file is part of the Signal Processing Library (SPL).
10 //
11 // This program is free software; you can redistribute it and/or
12 // modify it under the terms of the GNU General Public License as
13 // published by the Free Software Foundation; either version 3,
14 // or (at your option) any later version.
15 //
16 // This program is distributed in the hope that it will be useful,
17 // but WITHOUT ANY WARRANTY; without even the implied warranty of
18 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 // GNU General Public License for more details.
20 //
21 // You should have received a copy of the GNU General Public
22 // License along with this program; see the file LICENSE. If not,
23 // see <http://www.gnu.org/licenses/>.
24 //
25 // __END_OF_LICENSE__
26 
32 #ifndef SPL_Array1_hpp
33 #define SPL_Array1_hpp
34 
36 //
38 
40 //#define SPL_ARRAY1_DEBUG
41 
42 #if defined(SPL_ARRAY1_DEBUG)
43 #define SPL_ARRAY1_INLINE
45 #else
46 #define SPL_ARRAY1_INLINE inline
48 #endif
49 
51 // Header Files.
53 
54 #include <SPL/config.hpp>
55 #include <iostream>
56 #include <fstream>
57 #include <sstream>
58 #include <iomanip>
59 #include <vector>
60 #include <cassert>
61 #include <algorithm>
62 #include <functional>
63 #include <iterator>
64 #include <numeric>
65 #include <SPL/misc.hpp>
66 
68 //
70 
71 namespace SPL {
72 
74 // One-Dimensional Array Template Class
75 // (with lazy copying and reference counting)
77 
83 template <class> class Array1;
84 
86 
87 /*
88  * An array data block, which can be shared by multiple arrays.
89  */
90 
91 template <class T>
92 class ArrayRep1
93 {
94 private:
95 
96  template <class> friend class Array1;
97 
98  ArrayRep1(int size);
99 
100  ArrayRep1(int size, const T& value);
101 
102  template <class InputIterator>
103  ArrayRep1(int size, InputIterator data);
104 
105  ~ArrayRep1();
106 
107  // Prevent copy construction.
108  // This function is never defined.
109  ArrayRep1(const ArrayRep1&);
110 
111  // Prevent copy assignment.
112  // This function is never defined.
113  ArrayRep1& operator=(const ArrayRep1&);
114 
115  // Create a copy of this data block.
116  ArrayRep1* clone() const;
117 
118  // Get the reference count for the underlying data.
119  int getRefCount() const;
120 
121  // Increment the reference count for the underlying data.
122  void hold();
123 
124  // Decrement the reference count for the underlying data, deallocating
125  // the underlying data if the reference count reaches zero.
126  void release();
127 
128  // The array data.
129  std::vector<T> data_;
130 
131  // The number of arrays referencing the array data.
132  int refCount_;
133 };
134 
136 
142 template <class T>
143 class Array1
144 {
145 public:
146 
148  // Types
150 
152  typedef T ElemType;
153 
155  typedef typename std::vector<T>::iterator Iterator;
156 
158  typedef typename std::vector<T>::const_iterator ConstIterator;
159 
161  // Constructors and destructor
163 
167  Array1();
168 
172  explicit Array1(int size);
173 
178  Array1(int size, const T& value);
179 
184  template <class InputIterator>
185  Array1(int size, InputIterator data);
186 
190  Array1(const Array1& a);
191 
198  template<class OtherType>
199  Array1(const Array1<OtherType>& a);
200 
204  ~Array1();
205 
207  // Assignment operators
209 
213  Array1& operator=(const Array1& a);
214 
219  template<class OtherType>
221 
223  // Compound assignment operators
225 
229  Array1& operator+=(const Array1& a);
230 
234  Array1& operator-=(const Array1& a);
235 
239  Array1& operator*=(const Array1& a);
240 
244  Array1& operator/=(const Array1& a);
245 
249  Array1& operator+=(const T& value);
250 
254  Array1& operator-=(const T& value);
255 
259  Array1& operator*=(const T& value);
260 
264  Array1& operator/=(const T& value);
265 
267  // Basic queries
269 
273  int getSize() const;
274 
283  bool isShared() const;
284 
289  bool isSharedWith(const Array1& a) const;
290 
292  // Accessors
294 
298  T& operator()(int i);
299 
303  const T& operator()(int i) const;
304 
306  // Iterators
308 
313  ConstIterator begin() const;
314 
319  Iterator begin();
320 
325  ConstIterator end() const;
326 
331  Iterator end();
332 
334  // Array resizing
336 
345  void resize(int size);
346 
351  template <class InputIterator>
352  void resize(int size, InputIterator data);
353 
355  // Get various statistics
357 
363  T max() const;
364 
370  T min() const;
371 
375  T sum() const;
376 
378  // Input/output
380 
385  std::ostream& output(std::ostream& out, int fieldWidth) const;
386 
390  int load(const char* fileName);
391 
395  int save(const char* fileName) const;
396 
398  // Miscellaneous
400 
404  void fill(const T& value = T(0));
405 
410  void swap(Array1& a);
411 
415  void dump(std::ostream& out) const;
416 
417 private:
418 
419  template <class> friend class Array1;
420  typedef ArrayRep1<T> Rep;
421 
422  // Get the reference count for the underlying data.
423  int getRefCount() const;
424 
425  // Force the underlying data to be copied if the data is shared.
426  void unshare() const;
427 
428  // Force the underlying data to be copied.
429  // The data is assumed to be shared.
430  void copyOnWrite() const;
431 
432  // The underlying data.
433  mutable Rep* ptr_;
434 };
435 
437 // Code for the ArrayRep1 class
439 
441 
442 template <class T>
443 SPL_ARRAY1_INLINE int ArrayRep1<T>::getRefCount() const
444 {
445  return refCount_;
446 }
447 
448 template <class T>
449 SPL_ARRAY1_INLINE void ArrayRep1<T>::hold()
450 {
451  ++refCount_;
452 }
453 
454 template <class T>
455 SPL_ARRAY1_INLINE void ArrayRep1<T>::release()
456 {
457  if (--refCount_ == 0) {
458  delete this;
459  }
460 }
461 
462 template <class T>
463 SPL_ARRAY1_INLINE ArrayRep1<T>::ArrayRep1(int size) : data_(size),
464  refCount_(1)
465 {
466  assert(size >= 0);
467 }
468 
469 template <class T>
470 SPL_ARRAY1_INLINE ArrayRep1<T>::ArrayRep1(int size, const T& value) : data_(size, value),
471  refCount_(1)
472 {
473  assert(size >= 0);
474 }
475 
476 template <class T>
477 template <class InputIterator>
478 SPL_ARRAY1_INLINE ArrayRep1<T>::ArrayRep1(int size, InputIterator data) :
479  data_(), refCount_(1)
480 {
481  assert(size >= 0);
482  data_.reserve(size);
483  SPL::copy_n(data, size, std::back_inserter(data_));
484  assert(data_.size() == size);
485 }
486 
487 template <class T>
488 SPL_ARRAY1_INLINE ArrayRep1<T>::~ArrayRep1()
489 {
490  assert(!refCount_);
491 }
492 
493 template <class T>
494 SPL_ARRAY1_INLINE ArrayRep1<T>* ArrayRep1<T>::clone() const
495 {
496  return new ArrayRep1(data_.size(), data_.begin());
497 }
498 
500 
502 // Constructors and destructor
504 
505 template <class T>
507 {
508  ptr_ = new Rep(0);
509 #if defined(SPL_ARRAY1_DEBUG)
510  std::cerr << "Array1::default_ctor() "
511  << "["
512  << this << " "
513  << ptr_
514  << "]"
515  << "\n";
516 #endif
517 }
518 
519 template <class T>
521 {
522  ptr_ = new Rep(size);
523 #if defined(SPL_ARRAY1_DEBUG)
524  std::cerr << "Array1::ctor(" << size << ") "
525  << "["
526  << this << " "
527  << ptr_
528  << "]"
529  << "\n";
530 #endif
531 }
532 
533 template <class T>
535 {
536  ptr_ = a.ptr_;
537  ptr_->hold();
538 #if defined(SPL_ARRAY1_DEBUG)
539  std::cerr << "Array1::copy_ctor(" << (&a) << ") "
540  << "["
541  << this << " "
542  << ptr_
543  << "]"
544  << "\n";
545 #endif
546 }
547 
548 template <class T>
549 SPL_ARRAY1_INLINE Array1<T>::Array1(int size, const T& value)
550 {
551  ptr_ = new Rep(size, value);
552 #if defined(SPL_ARRAY1_DEBUG)
553  std::cerr << "Array1::ctor(" << size << ", " << value << ") "
554  << "["
555  << this << " "
556  << ptr_
557  << "]"
558  << "\n";
559 #endif
560 }
561 
562 template <class T>
563 template <class InputIterator>
564 SPL_ARRAY1_INLINE Array1<T>::Array1(int size, InputIterator data)
565 {
566  ptr_ = new Rep(size, data);
567 #if defined(SPL_ARRAY1_DEBUG)
568  std::cerr << "Array1::ctor(" << size << ", " << "InputIterator" << ") "
569  << "["
570  << this << " "
571  << ptr_
572  << "]"
573  << "\n";
574 #endif
575 }
576 
577 template <class T>
579 {
580 #if defined(SPL_ARRAY1_DEBUG)
581  std::cerr << "Array1::dtor() "
582  << "["
583  << this << " "
584  << ptr_
585  << "]"
586  << "\n";
587 #endif
588  ptr_->release();
589 }
590 
591 template <class T>
592 template <class OtherType>
594 {
595  ptr_ = new Rep(a.getSize(), a.begin());
596 #if defined(SPL_ARRAY1_DEBUG)
597  std::cerr << "pseudo_copy_ctor(" << this << ") "
598  << this << " " << ptr_ << "\n";
599 #endif
600 }
601 
603 // Assignment operators
605 
606 template <class T>
608 {
609 #if defined(SPL_ARRAY1_DEBUG)
610  std::cerr << "Array1::operator=(" << (&a) << ") "
611  << "["
612  << this << " " << ptr_ << " "
613  << (&a) << " " << a.ptr_ << ""
614  << "]"
615  << "\n";
616 #endif
617  if (this != &a) {
618  ptr_->release();
619  ptr_ = a.ptr_;
620  ptr_->hold();
621  }
622  return *this;
623 }
624 
625 template <class T>
626 template <class OtherType>
628 {
629 #if defined(SPL_ARRAY1_DEBUG)
630  std::cerr << "Array1::operator= special\n";
631 #endif
632  if (reinterpret_cast<void*>(this) != reinterpret_cast<const void*>(&a)) {
633  resize(a.getSize());
634  unshare();
635  std::copy(a.ptr_->data_.begin(), a.ptr_->data_.end(),
636  ptr_->data_.begin());
637  }
638  return *this;
639 }
640 
642 // Compound assignment operators
644 
645 template <class T>
647 {
648  assert(getSize() == a.getSize());
649  unshare();
650  std::transform(ptr_->data_.begin(), ptr_->data_.end(),
651  a.ptr_->data_.begin(), ptr_->data_.begin(), std::plus<T>());
652  return *this;
653 }
654 
655 template <class T>
657 {
658  assert(getSize() == a.getSize());
659  unshare();
660  std::transform(ptr_->data_.begin(), ptr_->data_.end(),
661  a.ptr_->data_.begin(), ptr_->data_.begin(), std::minus<T>());
662  return *this;
663 }
664 
665 template <class T>
667 {
668  assert(getSize() == a.getSize());
669  unshare();
670  std::transform(ptr_->data_.begin(), ptr_->data_.end(),
671  a.ptr_->data_.begin(), ptr_->data_.begin(), std::multiplies<T>());
672  return *this;
673 }
674 
675 template <class T>
677 {
678  assert(getSize() == a.getSize());
679  unshare();
680  std::transform(ptr_->data_.begin(), ptr_->data_.end(),
681  a.ptr_->data_.begin(), ptr_->data_.begin(), std::divides<T>());
682  return *this;
683 }
684 
685 template <class T>
687 {
688  unshare();
689  std::transform(ptr_->data_.begin(), ptr_->data_.end(),
690  ptr_->data_.begin(), std::bind2nd(std::plus<T>(), value));
691  return *this;
692 }
693 
694 template <class T>
696 {
697  unshare();
698  std::transform(ptr_->data_.begin(), ptr_->data_.end(),
699  ptr_->data_.begin(), std::bind2nd(std::minus<T>(), value));
700  return *this;
701 }
702 
703 template <class T>
705 {
706  unshare();
707  std::transform(ptr_->data_.begin(), ptr_->data_.end(),
708  ptr_->data_.begin(), std::bind2nd(std::multiplies<T>(), value));
709  return *this;
710 }
711 
712 template <class T>
714 {
715  unshare();
716  std::transform(ptr_->data_.begin(), ptr_->data_.end(),
717  ptr_->data_.begin(), std::bind2nd(std::divides<T>(), value));
718  return *this;
719 }
720 
722 // Basic queries
724 
725 template <class T>
727 {
728  return ptr_->data_.size();
729 }
730 
731 template <class T>
733 {
734  return ptr_->getRefCount() > 1;
735 }
736 
737 template <class T>
739 {
740  return ptr_ == a.ptr_;
741 }
742 
744 // Accessors
746 
747 template <class T>
749 {
750  assert(i >= 0 && i < getSize());
751  unshare();
752  return ptr_->data_[i];
753 }
754 
755 template <class T>
757 {
758  assert(i >= 0 && i < getSize());
759  return ptr_->data_[i];
760 }
761 
763 // Iterators
765 
766 template <class T>
768 {
769  unshare();
770  return ptr_->data_.begin();
771 }
772 
773 template <class T>
775 {
776  unshare();
777  return ptr_->data_.end();
778 }
779 
780 template <class T>
782 {
783  return ptr_->data_.begin();
784 }
785 
786 template <class T>
788 {
789  return ptr_->data_.end();
790 }
791 
793 // Resizing
795 
796 template <class T>
797 void Array1<T>::resize(int size)
798 {
799  assert(size >= 0);
800  if (getSize() != size) {
801  ptr_->release();
802  ptr_ = new Rep(size);
803  }
804 }
805 
806 template <class T>
807 template <class InputIterator>
808 void Array1<T>::resize(int size, InputIterator data)
809 {
810  assert(size >= 0);
811  if (getSize() == size && ptr_->getRefCount() == 1) {
812  SPL::copy_n(data, size, ptr_->data_.begin());
813  } else {
814  ptr_->release();
815  ptr_ = new Rep(size, data);
816  }
817 }
818 
820 // Get various statistics
822 
823 template<class T>
825 {
826  assert(getSize() > 0);
827  return *std::max_element(begin(), end());
828 }
829 
830 template<class T>
832 {
833  assert(getSize() > 0);
834  return *std::min_element(begin(), end());
835 }
836 
837 template<class T>
839 {
840  return std::accumulate(begin(), end(), T(0));
841 }
842 
844 // Input/output
846 
847 template<class T>
848 std::ostream& Array1<T>::output(std::ostream& out, int fieldWidth) const
849 {
850  out << getSize() << "\n";
851  for (int i = 0; i < getSize(); ++i) {
852  T val = operator()(i);
853  std::stringstream str;
854  str << std::setw(fieldWidth) << val;
855  std::string buf = str.str();
856  if (buf.size() > fieldWidth) {
857  buf = buf.substr(0, fieldWidth);
858  }
859  out << buf;
860  if (i < getSize() - 1) {
861  out << " ";
862  }
863  }
864  out << "\n";
865  return out;
866 }
867 
868 template<class T>
869 int Array1<T>::load(const char* fileName)
870 {
871  std::ifstream in(fileName);
872  in >> *this;
873  if (!in) {
874  return -1;
875  }
876  return 0;
877 }
878 
879 template<class T>
880 int Array1<T>::save(const char* fileName) const
881 {
882  std::ofstream out(fileName);
883  out << *this;
884  if (!out) {
885  return -1;
886  }
887  out.close();
888  return 0;
889 }
890 
894 template <class T>
895 std::ostream& operator<<(std::ostream& out, const Array1<T>& a)
896 {
897  out << a.getSize() << " ";
898  typename Array1<T>::ConstIterator dataIter = a.begin();
899  for (int i = 0; i < a.getSize(); ++i) {
900  if (i) {
901  out << " ";
902  }
903  out << *dataIter;
904  ++dataIter;
905  }
906 // out << " ";
907  return out;
908 }
909 
913 template<class T>
914 std::istream& operator>>(std::istream& in, Array1<T>& a)
915 {
916  int size;
917  in >> size;
918  if (!in) {
919  return in;
920  }
921  a.resize(size);
922  for (int i = 0; i < a.getSize(); ++i) {
923  T value;
924  in >> value;
925  if (!in) {
926  return in;
927  }
928  a(i) = value;
929  }
930  return in;
931 }
932 
934 // Miscellaneous
936 
937 template <class T>
939 {
940  if (this != &a) {
941  // Both reference counts increase and then decrease, for no
942  // overall net change.
943  std::swap(ptr_, a.ptr_);
944  }
945 }
946 
947 template <class T>
948 SPL_ARRAY1_INLINE void Array1<T>::fill(const T& value)
949 {
950  unshare();
951  std::fill(begin(), end(), value);
952 }
953 
957 template<class T>
958 bool operator==(const Array1<T>& a, const Array1<T>& b)
959 {
960  if (a.getSize() != b.getSize()) {
961  return false;
962  } else {
963  if (a.isSharedWith(b)) {
964  return true;
965  }
966  return std::equal(a.begin(), a.end(), b.begin());
967  }
968 }
969 
973 template<class T>
975 {
976  return !(a == b);
977 }
978 
979 template<class T>
980 void Array1<T>::dump(std::ostream& out) const
981 {
982  out
983  << "refCount=" << ptr_->getRefCount() << " "
984  << "size=" << getSize() << "\n";
985 }
986 
988 // Private code
990 
991 template <class T>
993 {
994 #if defined(SPL_ARRAY1_DEBUG)
995  std::cerr << "copyOnWrite "
996  << "["
997  << this << " "
998  << ptr_ << " "
999  << ptr_->getRefCount()
1000  << "]"
1001  << "\n";
1002  std::cerr << "copied array size " << getSize() << "\n";
1003 #endif
1004  assert(ptr_->getRefCount() > 1);
1005  ptr_->release();
1006  //const_cast<Array1*>(this)->ptr_ = ptr_->clone();
1007  this->ptr_ = ptr_->clone();
1008 }
1009 
1010 template <class T>
1011 SPL_ARRAY1_INLINE void Array1<T>::unshare() const
1012 {
1013  if (ptr_->getRefCount() > 1) {
1014  copyOnWrite();
1015  }
1016 }
1017 
1019 // Basic types
1021 
1024 
1027 
1029 //
1031 
1036 }
1037 
1038 #endif
T max() const
Get the maximum of the elements in the array.
Definition: Array1.hpp:824
bool operator==(const Array1< T > &a, const Array1< T > &b)
Test two arrays for equality.
Definition: Array1.hpp:958
Array1()
Create an empty array.
Definition: Array1.hpp:506
This file contains miscellaneous code.
ConstIterator begin() const
Get a const iterator referring to the first element in the array.
Definition: Array1.hpp:781
SPL_ARRAY1_INLINE bool operator!=(const Array1< T > &a, const Array1< T > &b)
Test two arrays for inequality.
Definition: Array1.hpp:974
void fill(const T &value=T(0))
Set all elements in the array to the specified value.
Definition: Array1.hpp:948
Definition: Arcball.hpp:48
int save(const char *fileName) const
Save an array to the file with the specified name.
Definition: Array1.hpp:880
~Array1()
Destroy an array.
Definition: Array1.hpp:578
Array1< double > RealArray1
A one-dimensional array with real elements.
Definition: Array1.hpp:1023
std::vector< T >::const_iterator ConstIterator
A constant iterator for the array elements.
Definition: Array1.hpp:158
Array1 & operator/=(const Array1 &a)
Divide this array (elementwise) by another array.
Definition: Array1.hpp:676
std::istream & operator>>(std::istream &in, Array1< T > &a)
Input an array from the specified stream.
Definition: Array1.hpp:914
T sum() const
Get the sum of the elements in the array.
Definition: Array1.hpp:838
A one-dimensional array class with lazy copying and reference counting.
Definition: Array1.hpp:83
void dump(std::ostream &out) const
Output information about an array to a stream for debugging.
Definition: Array1.hpp:980
Array1< int > IntArray1
A one-dimensional array with integer elements.
Definition: Array1.hpp:1026
T & operator()(int i)
Get a mutable reference to the specified element in the array.
Definition: Array1.hpp:748
T ElemType
The type of the elements in the array.
Definition: Array1.hpp:152
std::ostream & output(std::ostream &out, int fieldWidth) const
Output an array to a stream with a particular field width to be used for each element.
Definition: Array1.hpp:848
Array1 & operator=(const Array1 &a)
Assign one array to another.
Definition: Array1.hpp:607
Array1 & operator-=(const Array1 &a)
Subtract another array (elementwise) from this array.
Definition: Array1.hpp:656
T min() const
Get the minimum of the elements in the array.
Definition: Array1.hpp:831
int getSize() const
Get the number of elements in the array.
Definition: Array1.hpp:726
bool isShared() const
Is the data for this array shared with another array?
Definition: Array1.hpp:732
Array1 & operator+=(const Array1 &a)
Add another array (elementwise) to this array.
Definition: Array1.hpp:646
void resize(int size)
Change the size of the array.
Definition: Array1.hpp:797
#define SPL_ARRAY1_INLINE
Defining this symbol will enable extra code for debugging.
Definition: Array1.hpp:47
bool isSharedWith(const Array1 &a) const
Is the data for this array shared with the specified array?
Definition: Array1.hpp:738
void swap(Array1 &a)
Swap the contents of the array with the contents of another array.
Definition: Array1.hpp:938
std::vector< T >::iterator Iterator
A mutable iterator for the array elements.
Definition: Array1.hpp:155
int load(const char *fileName)
Load an array from the file with the specified name.
Definition: Array1.hpp:869
Array1 & operator*=(const Array1 &a)
Multiply another array (elementwise) by this array.
Definition: Array1.hpp:666
ConstIterator end() const
Get a const iterator referring to one past the last element in the array.
Definition: Array1.hpp:787