Signal/Geometry Processing Library (SPL)  2.0.8
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 #if 0
690  std::transform(ptr_->data_.begin(), ptr_->data_.end(),
691  ptr_->data_.begin(), std::bind2nd(std::plus<T>(), value));
692 #else
693  std::transform(ptr_->data_.begin(), ptr_->data_.end(),
694  ptr_->data_.begin(), [=](auto x){return x + value;});
695 #endif
696  return *this;
697 }
698 
699 template <class T>
701 {
702  unshare();
703 #if 0
704  std::transform(ptr_->data_.begin(), ptr_->data_.end(),
705  ptr_->data_.begin(), std::bind2nd(std::minus<T>(), value));
706 #else
707  std::transform(ptr_->data_.begin(), ptr_->data_.end(),
708  ptr_->data_.begin(), [=](auto x){return x - value;});
709 #endif
710  return *this;
711 }
712 
713 template <class T>
715 {
716  unshare();
717 #if 0
718  std::transform(ptr_->data_.begin(), ptr_->data_.end(),
719  ptr_->data_.begin(), std::bind2nd(std::multiplies<T>(), value));
720 #else
721  std::transform(ptr_->data_.begin(), ptr_->data_.end(),
722  ptr_->data_.begin(), [=](auto x){return x * value;});
723 #endif
724  return *this;
725 }
726 
727 template <class T>
729 {
730  unshare();
731 #if 0
732  std::transform(ptr_->data_.begin(), ptr_->data_.end(),
733  ptr_->data_.begin(), std::bind2nd(std::divides<T>(), value));
734 #else
735  std::transform(ptr_->data_.begin(), ptr_->data_.end(),
736  ptr_->data_.begin(), [=](auto x){return x / value;});
737 #endif
738  return *this;
739 }
740 
742 // Basic queries
744 
745 template <class T>
747 {
748  return ptr_->data_.size();
749 }
750 
751 template <class T>
753 {
754  return ptr_->getRefCount() > 1;
755 }
756 
757 template <class T>
759 {
760  return ptr_ == a.ptr_;
761 }
762 
764 // Accessors
766 
767 template <class T>
769 {
770  assert(i >= 0 && i < getSize());
771  unshare();
772  return ptr_->data_[i];
773 }
774 
775 template <class T>
777 {
778  assert(i >= 0 && i < getSize());
779  return ptr_->data_[i];
780 }
781 
783 // Iterators
785 
786 template <class T>
788 {
789  unshare();
790  return ptr_->data_.begin();
791 }
792 
793 template <class T>
795 {
796  unshare();
797  return ptr_->data_.end();
798 }
799 
800 template <class T>
802 {
803  return ptr_->data_.begin();
804 }
805 
806 template <class T>
808 {
809  return ptr_->data_.end();
810 }
811 
813 // Resizing
815 
816 template <class T>
817 void Array1<T>::resize(int size)
818 {
819  assert(size >= 0);
820  if (getSize() != size) {
821  ptr_->release();
822  ptr_ = new Rep(size);
823  }
824 }
825 
826 template <class T>
827 template <class InputIterator>
828 void Array1<T>::resize(int size, InputIterator data)
829 {
830  assert(size >= 0);
831  if (getSize() == size && ptr_->getRefCount() == 1) {
832  SPL::copy_n(data, size, ptr_->data_.begin());
833  } else {
834  ptr_->release();
835  ptr_ = new Rep(size, data);
836  }
837 }
838 
840 // Get various statistics
842 
843 template<class T>
845 {
846  assert(getSize() > 0);
847  return *std::max_element(begin(), end());
848 }
849 
850 template<class T>
852 {
853  assert(getSize() > 0);
854  return *std::min_element(begin(), end());
855 }
856 
857 template<class T>
859 {
860  return std::accumulate(begin(), end(), T(0));
861 }
862 
864 // Input/output
866 
867 template<class T>
868 std::ostream& Array1<T>::output(std::ostream& out, int fieldWidth) const
869 {
870  out << getSize() << "\n";
871  for (int i = 0; i < getSize(); ++i) {
872  T val = operator()(i);
873  std::stringstream str;
874  str << std::setw(fieldWidth) << val;
875  std::string buf = str.str();
876  if (buf.size() > fieldWidth) {
877  buf = buf.substr(0, fieldWidth);
878  }
879  out << buf;
880  if (i < getSize() - 1) {
881  out << " ";
882  }
883  }
884  out << "\n";
885  return out;
886 }
887 
888 template<class T>
889 int Array1<T>::load(const char* fileName)
890 {
891  std::ifstream in(fileName);
892  in >> *this;
893  if (!in) {
894  return -1;
895  }
896  return 0;
897 }
898 
899 template<class T>
900 int Array1<T>::save(const char* fileName) const
901 {
902  std::ofstream out(fileName);
903  out << *this;
904  if (!out) {
905  return -1;
906  }
907  out.close();
908  return 0;
909 }
910 
914 template <class T>
915 std::ostream& operator<<(std::ostream& out, const Array1<T>& a)
916 {
917  out << a.getSize() << " ";
918  typename Array1<T>::ConstIterator dataIter = a.begin();
919  for (int i = 0; i < a.getSize(); ++i) {
920  if (i) {
921  out << " ";
922  }
923  out << *dataIter;
924  ++dataIter;
925  }
926 // out << " ";
927  return out;
928 }
929 
933 template<class T>
934 std::istream& operator>>(std::istream& in, Array1<T>& a)
935 {
936  int size;
937  in >> size;
938  if (!in) {
939  return in;
940  }
941  a.resize(size);
942  for (int i = 0; i < a.getSize(); ++i) {
943  T value;
944  in >> value;
945  if (!in) {
946  return in;
947  }
948  a(i) = value;
949  }
950  return in;
951 }
952 
954 // Miscellaneous
956 
957 template <class T>
959 {
960  if (this != &a) {
961  // Both reference counts increase and then decrease, for no
962  // overall net change.
963  std::swap(ptr_, a.ptr_);
964  }
965 }
966 
967 template <class T>
968 SPL_ARRAY1_INLINE void Array1<T>::fill(const T& value)
969 {
970  unshare();
971  std::fill(begin(), end(), value);
972 }
973 
977 template<class T>
978 bool operator==(const Array1<T>& a, const Array1<T>& b)
979 {
980  if (a.getSize() != b.getSize()) {
981  return false;
982  } else {
983  if (a.isSharedWith(b)) {
984  return true;
985  }
986  return std::equal(a.begin(), a.end(), b.begin());
987  }
988 }
989 
993 template<class T>
995 {
996  return !(a == b);
997 }
998 
999 template<class T>
1000 void Array1<T>::dump(std::ostream& out) const
1001 {
1002  out
1003  << "refCount=" << ptr_->getRefCount() << " "
1004  << "size=" << getSize() << "\n";
1005 }
1006 
1008 // Private code
1010 
1011 template <class T>
1013 {
1014 #if defined(SPL_ARRAY1_DEBUG)
1015  std::cerr << "copyOnWrite "
1016  << "["
1017  << this << " "
1018  << ptr_ << " "
1019  << ptr_->getRefCount()
1020  << "]"
1021  << "\n";
1022  std::cerr << "copied array size " << getSize() << "\n";
1023 #endif
1024  assert(ptr_->getRefCount() > 1);
1025  ptr_->release();
1026  //const_cast<Array1*>(this)->ptr_ = ptr_->clone();
1027  this->ptr_ = ptr_->clone();
1028 }
1029 
1030 template <class T>
1031 SPL_ARRAY1_INLINE void Array1<T>::unshare() const
1032 {
1033  if (ptr_->getRefCount() > 1) {
1034  copyOnWrite();
1035  }
1036 }
1037 
1039 // Basic types
1041 
1044 
1047 
1049 //
1051 
1056 }
1057 
1058 #endif
bool operator==(const Array1< T > &a, const Array1< T > &b)
Test two arrays for equality.
Definition: Array1.hpp:978
Array1()
Create an empty array.
Definition: Array1.hpp:506
This file contains miscellaneous code.
SPL_ARRAY1_INLINE bool operator!=(const Array1< T > &a, const Array1< T > &b)
Test two arrays for inequality.
Definition: Array1.hpp:994
void fill(const T &value=T(0))
Set all elements in the array to the specified value.
Definition: Array1.hpp:968
Definition: Arcball.hpp:48
void dump(std::ostream &out) const
Output information about an array to a stream for debugging.
Definition: Array1.hpp:1000
~Array1()
Destroy an array.
Definition: Array1.hpp:578
bool isSharedWith(const Array1 &a) const
Is the data for this array shared with the specified array?
Definition: Array1.hpp:758
Array1< double > RealArray1
A one-dimensional array with real elements.
Definition: Array1.hpp:1043
std::vector< T >::const_iterator ConstIterator
A constant iterator for the array elements.
Definition: Array1.hpp:158
ConstIterator begin() const
Get a const iterator referring to the first element in the array.
Definition: Array1.hpp:801
OutputIterator copy_n(InputIterator first, Size count, OutputIterator result)
This template function is equivalent to std::copy_n in the new C++ 0x standard.
Definition: misc.hpp:56
bool isShared() const
Is the data for this array shared with another array?
Definition: Array1.hpp:752
ConstIterator end() const
Get a const iterator referring to one past the last element in the array.
Definition: Array1.hpp:807
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:934
T min() const
Get the minimum of the elements in the array.
Definition: Array1.hpp:851
T max() const
Get the maximum of the elements in the array.
Definition: Array1.hpp:844
A one-dimensional array class with lazy copying and reference counting.
Definition: Array1.hpp:83
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:868
int getSize() const
Get the number of elements in the array.
Definition: Array1.hpp:746
Array1< int > IntArray1
A one-dimensional array with integer elements.
Definition: Array1.hpp:1046
T & operator()(int i)
Get a mutable reference to the specified element in the array.
Definition: Array1.hpp:768
T ElemType
The type of the elements in the array.
Definition: Array1.hpp:152
Array1 & operator=(const Array1 &a)
Assign one array to another.
Definition: Array1.hpp:607
T sum() const
Get the sum of the elements in the array.
Definition: Array1.hpp:858
Array1 & operator-=(const Array1 &a)
Subtract another array (elementwise) from this array.
Definition: Array1.hpp:656
int save(const char *fileName) const
Save an array to the file with the specified name.
Definition: Array1.hpp:900
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:817
#define SPL_ARRAY1_INLINE
Defining this symbol will enable extra code for debugging.
Definition: Array1.hpp:47
void swap(Array1 &a)
Swap the contents of the array with the contents of another array.
Definition: Array1.hpp:958
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:889
Array1 & operator*=(const Array1 &a)
Multiply another array (elementwise) by this array.
Definition: Array1.hpp:666