Signal/Geometry Processing Library (SPL)  2.0.8
All Classes Files Functions Variables Typedefs Enumerations Macros Modules Pages
Array2.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_Array2_hpp
33 #define SPL_Array2_hpp
34 
36 //
38 
40 //#define SPL_ARRAY2_DEBUG
41 
42 #if defined(SPL_ARRAY2_DEBUG)
43 #define SPL_ARRAY2_INLINE
45 #else
46 #define SPL_ARRAY2_INLINE inline
48 #endif
49 
51 // Header Files.
53 
54 #include <SPL/config.hpp>
55 #include <iostream>
56 #include <iomanip>
57 #include <fstream>
58 #include <vector>
59 #include <cassert>
60 #include <iterator>
61 #include <algorithm>
62 #include <numeric>
63 #include <boost/iterator/iterator_facade.hpp>
64 #include <SPL/pnmCodec.hpp>
65 #include <SPL/misc.hpp>
66 
68 //
70 
71 namespace SPL {
72 
74 // Two-Dimensional Array Template Class
75 // (with lazy copying and reference counting)
77 
83 template <class> class Array2;
84 
86 
87 /*
88  * An array data block, which can be shared by multiple arrays.
89  */
90 
91 template <class T>
92 class ArrayRep2
93 {
94 private:
95  template <class> friend class Array2;
96 
97  ArrayRep2(int width, int height);
98 
99  ArrayRep2(int width, int height, const T& value);
100 
101  template <class InputIterator>
102  ArrayRep2(int width, int height, InputIterator data);
103 
104  ~ArrayRep2();
105 
106  // Prevent copy construction.
107  // This function is never defined.
108  ArrayRep2(const ArrayRep2&);
109 
110  // Prevent assignment.
111  // This function is never defined.
112  ArrayRep2& operator=(const ArrayRep2&);
113 
114  // Create a copy of this data block.
115  ArrayRep2* clone() const;
116 
120  int getRefCount() const;
121 
125  void hold();
126 
131  void release();
132 
133  // Output information to a stream for debugging.
134  void dump(std::ostream& out) const;
135 
136  // The width of the array.
137  int width_;
138 
139  // The height of the array.
140  int height_;
141 
142  // The array data.
143  std::vector<T> data_;
144 
145  // The number of arrays referencing the array data.
146  int refCount_;
147 };
148 
150 
156 template <class T>
157 class Array2
158 {
159 public:
160 
162  // Types
164 
166  typedef T ElemType;
167 
169  // Provide a random access iterator for the elements of an array.
170  // NOTE: It would be more elegant to have this class use
171  // vector iterators instead of raw pointers.
172  template <class Value>
173  class YIter : public boost::iterator_facade<YIter<Value>, Value,
174  std::random_access_iterator_tag>
175  {
176  public:
177  YIter() : step_(0), ptr_(0)
178  {
179  }
180  explicit YIter(int step, Value* ptr) : step_(step), ptr_(ptr)
181  {
182  }
183  template <class OtherValue>
184  YIter(const YIter<OtherValue>& other) : step_(other.step_),
185  ptr_(other.ptr_)
186  {
187  }
188  private:
189  friend class boost::iterator_core_access;
190  template <class> friend class YIter;
191  template <class OtherValue>
192  bool equal(const YIter<OtherValue>& other) const
193  {
194  return ptr_ == other.ptr_;
195  }
196  void increment()
197  {
198  ptr_ += step_;
199  }
200  void decrement()
201  {
202  ptr_ -= step_;
203  }
204  void advance(int n)
205  {
206  ptr_ += n * step_;
207  }
208  template <class OtherValue>
209  int distance_to(const YIter<OtherValue>& other) const
210  {
211  return (other.ptr_ - ptr_) / step_;
212  }
213  Value& dereference() const {
214  return *ptr_;
215  }
216  int step_;
217  Value* ptr_;
218  };
220 
222  typedef typename std::vector<T>::iterator Iterator;
223 
225  typedef typename std::vector<T>::const_iterator ConstIterator;
226 
229 
231  typedef typename std::vector<T>::const_iterator ConstXIterator;
232 
234  typedef YIter<T> YIterator;
235 
237  typedef YIter<const T> ConstYIterator;
238 
240  // Constructors and destructor
242 
246  Array2();
247 
251  Array2(int width, int height);
252 
257  Array2(int width, int height, const T& value);
258 
263  template <class InputIter>
264  Array2(int width, int height, InputIter data);
265 
269  ~Array2();
270 
274  Array2(const Array2& a);
275 
280  template <class OtherType>
281  Array2(const Array2<OtherType>& a);
282 
284  // Assignment operators
286 
290  Array2& operator=(const Array2& a);
291 
296  template <class OtherType>
298 
300  // Compound assignment operators
302 
306  Array2& operator+=(const Array2& a);
307 
311  Array2& operator-=(const Array2& a);
312 
316  Array2& operator*=(const Array2& a);
317 
321  Array2& operator/=(const Array2& a);
322 
326  Array2& operator+=(const T& a);
327 
331  Array2& operator-=(const T& a);
332 
336  Array2& operator*=(const T& a);
337 
341  Array2& operator/=(const T& a);
342 
344  // Basic queries
346 
350  int getWidth() const;
351 
355  int getHeight() const;
356 
360  int getSize() const;
361 
370  bool isShared() const;
371 
376  bool isSharedWith(const Array2& a) const;
377 
379  // Accessors
381 
385  T& operator()(int x, int y);
386 
390  const T& operator()(int x, int y) const;
391 
397  T& operator()(int i);
398 
404  const T& operator()(int i) const;
405 
407  // Iterators
409 
413  ConstIterator begin() const;
414 
418  Iterator begin();
419 
424  ConstIterator end() const;
425 
430  Iterator end();
431 
437  ConstXIterator rowBegin(int y) const;
438 
444  XIterator rowBegin(int y);
445 
451  ConstXIterator rowEnd(int y) const;
452 
458  XIterator rowEnd(int y);
459 
465  ConstYIterator colBegin(int x) const;
466 
472  YIterator colBegin(int x);
473 
479  ConstYIterator colEnd(int x) const;
480 
486  YIterator colEnd(int x);
487 
489  // Array resizing
491 
500  void resize(int width, int height);
501 
506  template <class InputIterator>
507  void resize(int width, int height, InputIterator data);
508 
510  // Get various statistics
512 
518  T max() const;
519 
525  T min() const;
526 
530  T sum() const;
531 
533  // Input/output
535 
540  std::ostream& output(std::ostream& out, int fieldWidth) const;
541 
545  int load(const char* fileName);
546 
550  int save(const char* fileName) const;
551 
553  // Miscellaneous
555 
559  void fill(const T& value = T(0));
560 
564  Array2& flipud();
565 
569  Array2& fliplr();
570 
574  void swap(Array2& a);
575 
579  void dump(std::ostream& out) const;
580 
584  void unshare() const;
585 
586 private:
587 
588  template <class> friend class Array2;
589 
591  typedef ArrayRep2<T> Rep;
592 
597  void copyOnWrite() const;
598 
600  mutable Rep* ptr_;
601 };
602 
604 // Code for ArrayRep2 class.
606 
608 
609 template <class T>
610 SPL_ARRAY2_INLINE ArrayRep2<T>::ArrayRep2(int width, int height) :
611  width_(width), height_(height), data_(width * height), refCount_(1)
612 {
613  assert(width >= 0 && height >= 0);
614 }
615 
616 template <class T>
617 SPL_ARRAY2_INLINE ArrayRep2<T>::ArrayRep2(int width, int height,
618  const T& value) : width_(width), height_(height),
619  data_(width * height, value), refCount_(1)
620 {
621  assert(width >= 0 && height >= 0);
622 }
623 
624 template <class T>
625 template <class InputIterator>
626 SPL_ARRAY2_INLINE ArrayRep2<T>::ArrayRep2(int width, int height,
627  InputIterator data) : width_(width), height_(height), data_(), refCount_(1)
628 {
629  assert(width >= 0 && height >= 0);
630  int n = width * height;
631  data_.reserve(n);
632  SPL::copy_n(data, n, std::back_inserter(data_));
633 }
634 
635 template <class T>
636 SPL_ARRAY2_INLINE ArrayRep2<T>::~ArrayRep2()
637 {
638  // The destructor should only be called if nothing is referencing
639  // this object.
640  assert(!refCount_);
641 }
642 
643 template <class T>
644 SPL_ARRAY2_INLINE ArrayRep2<T>* ArrayRep2<T>::clone() const
645 {
646  return new ArrayRep2(width_, height_, data_.begin());
647 }
648 
649 template <class T>
650 SPL_ARRAY2_INLINE void ArrayRep2<T>::hold()
651 {
652  ++refCount_;
653 }
654 
655 template <class T>
656 SPL_ARRAY2_INLINE void ArrayRep2<T>::release()
657 {
658  if (--refCount_ == 0) {
659  delete this;
660  }
661 }
662 
663 template <class T>
664 SPL_ARRAY2_INLINE int ArrayRep2<T>::getRefCount() const
665 {
666  return refCount_;
667 }
668 
669 template <class T>
670 void ArrayRep2<T>::dump(typename std::ostream& out) const
671 {
672  out << "Rep: "
673  << this << " "
674  << width_ << " " << height_ << " "
675  << (&*data_.begin()) << " "
676  << refCount_ << " ";
677 }
678 
680 
682 // Constructors and destructor
684 
685 template <class T>
687 {
688  ptr_ = new Rep(0, 0);
689 }
690 
691 template <class T>
692 SPL_ARRAY2_INLINE Array2<T>::Array2(int width, int height)
693 {
694  assert(width >= 0 && height >= 0);
695  ptr_ = new Rep(width, height);
696 }
697 
698 template <class T>
700 {
701 #if defined(SPL_ARRAY2_DEBUG)
702  std::cerr << "Array2<T>::Array2(const Array2<T>&) "
703  << this << " " << (&a) << "\n";
704 #endif
705  ptr_ = a.ptr_;
706  ptr_->hold();
707 }
708 
709 template <class T>
710 SPL_ARRAY2_INLINE Array2<T>::Array2(int width, int height, const T& value)
711 {
712  assert(width >= 0 && height >= 0);
713  ptr_ = new Rep(width, height, value);
714 }
715 
716 template <class T>
717 template <class InputIterator>
718 SPL_ARRAY2_INLINE Array2<T>::Array2(int width, int height, InputIterator data)
719 {
720  assert(width >= 0 && height >= 0);
721  ptr_ = new Rep(width, height, data);
722 }
723 
724 template <class T>
726 {
727 #if defined(SPL_ARRAY2_DEBUG)
728  std::cerr << "Array2<T>::~Array2() " << this << " " << ptr_ << "\n";
729 #endif
730  ptr_->release();
731 }
732 
733 template <class T>
734 template <class OtherType>
736 {
737 #if defined(SPL_ARRAY2_DEBUG)
738  std::cerr << "Array2::pseudo_copy_ctor " << this << " " << ptr_ << "\n";
739 #endif
740  ptr_ = new Rep(a.getWidth(), a.getHeight(), a.begin());
741 }
742 
744 // Assignment operators
746 
747 template <class T>
749 {
750 #if defined(SPL_ARRAY2_DEBUG)
751  std::cerr << "Array2<T>& Array2<T>::operator=(const Array2<T>&) "
752  << this << " " << (&a) << "\n";
753 #endif
754  if (this != &a) {
755  // Not self assignment.
756  ptr_->release();
757  ptr_ = a.ptr_;
758  ptr_->hold();
759  }
760  return *this;
761 }
762 
763 template <class T>
764 template <class OtherType>
766 {
767 #if defined(SPL_ARRAY2_DEBUG)
768  std::cerr << "Array2::operator= special\n";
769 #endif
770  if (reinterpret_cast<void*>(this) != reinterpret_cast<const void*>(&a)) {
771  resize(a.getWidth(), a.getHeight());
772  unshare();
773  std::copy(a.ptr_->data_.begin(), a.ptr_->data_.end(),
774  ptr_->data_.begin());
775  }
776  return *this;
777 }
778 
780 // Compound assignment operators
782 
783 template <class T>
785 {
786  assert(getWidth() == a.getWidth() && getHeight() == a.getHeight());
787  unshare();
788  std::transform(ptr_->data_.begin(), ptr_->data_.end(),
789  a.ptr_->data_.begin(), ptr_->data_.begin(), std::plus<T>());
790  return *this;
791 }
792 
793 template <class T>
795 {
796  assert(getWidth() == a.getWidth() && getHeight() == a.getHeight());
797  unshare();
798  std::transform(ptr_->data_.begin(), ptr_->data_.end(),
799  a.ptr_->data_.begin(), ptr_->data_.begin(), std::minus<T>());
800  return *this;
801 }
802 
803 template <class T>
805 {
806  assert(getWidth() == a.getWidth() && getHeight() == a.getHeight());
807  unshare();
808  std::transform(ptr_->data_.begin(), ptr_->data_.end(),
809  a.ptr_->data_.begin(), ptr_->data_.begin(), std::multiplies<T>());
810  return *this;
811 }
812 
813 template <class T>
815 {
816  assert(getWidth() == a.getWidth() && getHeight() == a.getHeight());
817  unshare();
818  std::transform(ptr_->data_.begin(), ptr_->data_.end(),
819  a.ptr_->data_.begin(), ptr_->data_.begin(), std::divides<T>());
820  return *this;
821 }
822 
823 template <class T>
825 {
826  unshare();
827 #if 0
828  std::transform(ptr_->data_.begin(), ptr_->data_.end(),
829  ptr_->data_.begin(), std::bind2nd(std::plus<T>(), value));
830 #else
831  std::transform(ptr_->data_.begin(), ptr_->data_.end(),
832  ptr_->data_.begin(), [=](auto x){return x + value;});
833 #endif
834  return *this;
835 }
836 
837 template <class T>
839 {
840  unshare();
841 #if 0
842  std::transform(ptr_->data_.begin(), ptr_->data_.end(),
843  ptr_->data_.begin(), std::bind2nd(std::minus<T>(), value));
844 #else
845  std::transform(ptr_->data_.begin(), ptr_->data_.end(),
846  ptr_->data_.begin(), [=](auto x){return x - value;});
847 #endif
848  return *this;
849 }
850 
851 template <class T>
853 {
854  unshare();
855 #if 0
856  std::transform(ptr_->data_.begin(), ptr_->data_.end(),
857  ptr_->data_.begin(), std::bind2nd(std::multiplies<T>(), value));
858 #else
859  std::transform(ptr_->data_.begin(), ptr_->data_.end(),
860  ptr_->data_.begin(), [=](auto x){return x * value;});
861 #endif
862  return *this;
863 }
864 
865 template <class T>
867 {
868  unshare();
869 #if 0
870  std::transform(ptr_->data_.begin(), ptr_->data_.end(),
871  ptr_->data_.begin(), std::bind2nd(std::divides<T>(), value));
872 #else
873  std::transform(ptr_->data_.begin(), ptr_->data_.end(),
874  ptr_->data_.begin(), [=](auto x){return x / value;});
875 #endif
876  return *this;
877 }
878 
880 // Basic queries
882 
883 template <class T>
885 {
886  return ptr_->width_;
887 }
888 
889 template <class T>
891 {
892  return ptr_->height_;
893 }
894 
895 template <class T>
897 {
898  assert(ptr_->width_ * ptr_->height_ == ptr_->data_.size());
899  return ptr_->data_.size();
900 }
901 
902 template <class T>
904 {
905  return ptr_->getRefCount() > 1;
906 }
907 
908 template <class T>
910 {
911  return ptr_ == a.ptr_;
912 }
913 
915 // Accessors
917 
918 template <class T>
920 {
921  assert(x >= 0 && x < getWidth() && y >= 0 && y < getHeight());
922  unshare();
923  return ptr_->data_[y * getWidth() + x];
924 }
925 
926 template <class T>
927 SPL_ARRAY2_INLINE const T& Array2<T>::operator()(int x, int y) const
928 {
929  assert(x >= 0 && x < getWidth() && y >= 0 && y < getHeight());
930  return ptr_->data_[y * getWidth() + x];
931 }
932 
933 template <class T>
935 {
936  assert(getWidth() == 1 || getHeight() == 1);
937  assert(i >= 0 && i < getSize());
938  unshare();
939  return ptr_->data_[i];
940 }
941 
942 template <class T>
944 {
945  assert(getWidth() == 1 || getHeight() == 1);
946  assert(i >= 0 && i < getSize());
947  return ptr_->data_[i];
948 }
949 
951 // Iterators
953 
954 template <class T>
956 {
957  return ptr_->data_.begin();
958 }
959 
960 template <class T>
962 {
963  unshare();
964  return ptr_->data_.begin();
965 }
966 
967 template <class T>
969 {
970  return ptr_->data_.end();
971 }
972 
973 template <class T>
975 {
976  unshare();
977  return ptr_->data_.end();
978 }
979 
980 template <class T>
982 {
983  assert(y >= 0 && y < getHeight());
984  return begin() + (y * getWidth());
985 }
986 
987 template <class T>
989 {
990  assert(y >= 0 && y < getHeight());
991  unshare();
992  return begin() + (y * getWidth());
993 }
994 
995 template <class T>
997 {
998  assert(y >= 0 && y < getHeight());
999  return begin() + ((y + 1) * getWidth());
1000 }
1001 
1002 template <class T>
1004 {
1005  assert(y >= 0 && y < getHeight());
1006  unshare();
1007  return begin() + ((y + 1) * getWidth());
1008 }
1009 
1010 template <class T>
1012 {
1013  assert(x >= 0 && x < getWidth());
1014  return ConstYIterator(getWidth(), &(*(begin() + x)));
1015 }
1016 
1017 template <class T>
1019 {
1020  assert(x >= 0 && x < getWidth());
1021  unshare();
1022  return YIterator(getWidth(), &(*(begin() + x)));
1023 }
1024 
1025 template <class T>
1027 {
1028  assert(x >= 0 && x < getWidth());
1029  return ConstYIterator(getWidth(), &(*(begin() + (getSize() + x))));
1030 }
1031 
1032 template <class T>
1034 {
1035  assert(x >= 0 && x < getWidth());
1036  unshare();
1037  return YIterator(getWidth(), &(*(begin() + (getSize() + x))));
1038 }
1039 
1041 // Resizing
1043 
1044 template <class T>
1045 void Array2<T>::resize(int width, int height)
1046 {
1047  assert(width >= 0 && height >= 0);
1048  if (getWidth() != width || getHeight() != height) {
1049  ptr_->release();
1050  ptr_ = new Rep(width, height);
1051  }
1052 }
1053 
1054 template <class T>
1055 template <class InputIterator>
1056 void Array2<T>::resize(int width, int height, InputIterator data)
1057 {
1058  assert(width >= 0 && height >= 0);
1059  if (getWidth() == width && getHeight() == height && ptr_->getRefCount() == 1) {
1060  SPL::copy_n(data, getSize(), begin());
1061  } else {
1062  ptr_->release();
1063  ptr_ = new Rep(width, height, data);
1064  }
1065 }
1066 
1068 // Get various statistics
1070 
1071 template <class T>
1073 {
1074  assert(getSize() > 0);
1075  return *std::max_element(begin(), end());
1076 }
1077 
1078 template <class T>
1080 {
1081  assert(getSize() > 0);
1082  return *std::min_element(begin(), end());
1083 }
1084 
1085 template <class T>
1087 {
1088  return std::accumulate(begin(), end(), T(0));
1089 }
1090 
1092 // Input/output
1094 
1095 template <class T>
1096 std::ostream& Array2<T>::output(std::ostream& out, int fieldWidth) const
1097 {
1098  out << getWidth() << " " << getHeight() << "\n";
1099  for (int j = 0; j < getHeight(); ++j) {
1100  for (int i = 0; i < getWidth(); ++i) {
1101  T val = operator()(i, j);
1102  std::stringstream str;
1103  str << std::setw(fieldWidth) << val;
1104  std::string buf = str.str();
1105  if (buf.size() > fieldWidth) {
1106  buf = buf.substr(0, fieldWidth);
1107  }
1108  //out << std::setw(fieldWidth) << val;
1109  out << buf;
1110  if (i < getWidth() - 1) {
1111  out << " ";
1112  }
1113  }
1114  out << "\n";
1115  }
1116  return out;
1117 }
1118 
1119 template<class T>
1120 int Array2<T>::load(const char* fileName)
1121 {
1122  std::ifstream in(fileName);
1123  in >> *this;
1124  if (!in) {
1125  return -1;
1126  }
1127  return 0;
1128 }
1129 
1130 template<class T>
1131 int Array2<T>::save(const char* fileName) const
1132 {
1133  std::ofstream out(fileName);
1134  out << *this;
1135  if (!out) {
1136  return -1;
1137  }
1138  out.close();
1139  return 0;
1140 }
1141 
1145 template <class T>
1146 std::ostream& operator<<(std::ostream& out, const Array2<T>& a)
1147 {
1148  out << a.getWidth() << " " << a.getHeight() << "\n";
1149  for (int y = 0; y < a.getHeight(); ++y) {
1150  typename Array2<T>::ConstXIterator src = a.rowBegin(y);
1151  for (int x = 0; x < a.getWidth(); ++x) {
1152  if (x) {
1153  out << " ";
1154  }
1155  out << *src;
1156  ++src;
1157  }
1158  out << "\n";
1159  }
1160  return out;
1161 }
1162 
1166 template <class T>
1167 std::istream& operator>>(std::istream& in, Array2<T>& a)
1168 {
1169  int width;
1170  if (!(in >> width)) {
1171  return in;
1172  }
1173  int height;
1174  if (!(in >> height)) {
1175  return in;
1176  }
1177  if (width < 0 || height < 0) {
1178  in.setstate(std::ios::failbit);
1179  return in;
1180  }
1181 
1182  a = Array2<T>(width, height);
1183  for (int y = 0; y < a.getHeight(); ++y) {
1184  typename Array2<T>::XIterator dst = a.rowBegin(y);
1185  for (int x = 0; x < a.getWidth(); ++x) {
1186  T value;
1187  if (!(in >> value)) {
1188  return in;
1189  }
1190  *dst = value;
1191  ++dst;
1192  }
1193  }
1194  return in;
1195 }
1196 
1198 // Miscellaneous
1200 
1201 template <class T>
1203 {
1204  if (this != &a) {
1205  // Overall, the reference counts do not change.
1206  // Technically, both reference counts increase and then decrease,
1207  // for no net change.
1208  std::swap(ptr_, a.ptr_);
1209  }
1210 }
1211 
1212 template <class T>
1214 {
1215  unshare();
1216  std::fill(begin(), end(), value);
1217 }
1218 
1219 template <class T>
1221 {
1222  unshare();
1223  for (int k = 0; k < getHeight() / 2; ++k) {
1224  XIterator i = rowBegin(k);
1225  XIterator j = rowBegin(getHeight() - 1 - k);
1226  for (int n = getWidth(); n > 0; --n) {
1227  std::swap(*i, *j);
1228  ++i;
1229  ++j;
1230  }
1231  }
1232  return *this;
1233 }
1234 
1235 template <class T>
1237 {
1238  unshare();
1239  for (int y = 0; y < getHeight(); ++y) {
1240  XIterator i = rowBegin(y);
1241  XIterator j = i + (getWidth() - 1);
1242  for (int n = getWidth() / 2; n > 0; --n) {
1243  std::swap(*i, *j);
1244  ++i;
1245  --j;
1246  }
1247  }
1248  return *this;
1249 }
1250 
1254 template <class T>
1256 {
1257  int width = a.getWidth();
1258  int height = a.getHeight();
1259  Array2<T> result(height, width);
1260  for (int y = 0; y < width; ++y) {
1261  for (int x = 0; x < height; ++x) {
1262  result(x, y) = a(y, x);
1263  }
1264  }
1265  return result;
1266 }
1267 
1271 template <class T>
1272 bool operator==(const Array2<T>& a, const Array2<T>& b)
1273 {
1274  bool result;
1275  if (a.getWidth() == b.getWidth() && a.getHeight() == b.getHeight()) {
1276  result = true;
1277  for (int y = 0; y < a.getHeight(); ++y) {
1278  typename Array2<T>::ConstXIterator src = a.rowBegin(y);
1279  typename Array2<T>::ConstXIterator dst = b.rowBegin(y);
1280  for (int x = 0; x < a.getWidth(); ++x) {
1281  if (*src != *dst) {
1282  result = false;
1283  y = a.getHeight();
1284  break;
1285  }
1286  ++src;
1287  ++dst;
1288  }
1289  }
1290  } else {
1291  result = false;
1292  }
1293  return result;
1294 }
1295 
1299 template <class T>
1300 bool operator!=(const Array2<T>& a, const Array2<T>& b)
1301 {
1302  return !(a == b);
1303 }
1304 
1309 template <class T>
1310 void Array2<T>::dump(std::ostream& out) const
1311 {
1312  out << "Array2<T> " << this << " ";
1313  ptr_->dump(out);
1314  out << "\n";
1315 }
1316 
1318 // Private code
1320 
1321 template <class T>
1323 {
1324 #if defined(SPL_ARRAY2_DEBUG)
1325  std::cerr << "Array2<T>::copyOnWrite() " << this << "\n";
1326  dump(std::cerr);
1327 #endif
1328  // The underlying data must be shared.
1329  assert(ptr_->getRefCount() > 1);
1330  ptr_->release();
1331  //const_cast<Array2*>(this)->ptr_ = ptr_->clone();
1332  this->ptr_ = ptr_->clone();
1333 }
1334 
1335 template <class T>
1337 {
1338  if (ptr_->getRefCount() > 1) {
1339  copyOnWrite();
1340  }
1341 }
1342 
1347 // PNM Support
1350 
1356 
1358 template <class T>
1359 class PnmPutData
1360 {
1361 public:
1362 
1363  typedef Array2<T> Array;
1364  typedef typename Array::XIterator ArrayIter;
1365 
1366  PnmPutData() : comps_(0)
1367  {
1368  }
1369 
1370  void initialize(typename std::vector<Array>& comps)
1371  {
1372  comps_ = &comps;
1373  assert(comps.size() >= 0);
1374  dataIters_.reserve(3);
1375  y_ = (*comps_)[0].getHeight() - 1;
1376  remaining_ = (*comps_)[0].getWidth();
1377  for (typename std::vector<Array>::iterator i = comps_->begin();
1378  i != comps_->end(); ++i) {
1379  assert(!i->isShared());
1380  dataIters_.push_back(i->rowBegin(y_));
1381  }
1382  comp_ = 0;
1383  }
1384 
1385  void operator()(int value)
1386  {
1387  assert(y_ >= 0);
1388  ArrayIter& iter = dataIters_[comp_];
1389 //std::cerr << "writing " << y_ << " " << remaining_ << " " << value << "\n";
1390  *iter = value;
1391  ++iter;
1392  ++comp_;
1393 
1394  if (comp_ >= comps_->size()) {
1395  comp_ = 0;
1396  --remaining_;
1397  if (remaining_ <= 0) {
1398  remaining_ = (*comps_)[0].getWidth();
1399  --y_;
1400  if (y_ >= 0) {
1401  typename std::vector<Array>::iterator comp =
1402  (*comps_).begin();
1403  for (typename std::vector<ArrayIter>::iterator i =
1404  dataIters_.begin(); i != dataIters_.end(); ++i) {
1405  *i = comp->rowBegin(y_);
1406  ++comp;
1407  }
1408  }
1409  }
1410  }
1411  }
1412 private:
1413  std::vector<Array>* comps_;
1414  typename std::vector<ArrayIter> dataIters_;
1415  int y_;
1416  int remaining_;
1417  int comp_;
1418 };
1419 
1420 template <class T>
1421 class PnmInitialize
1422 {
1423 public:
1424  typedef PnmPutData<T> PutData;
1425  void operator()(int width, int height, int numComps, int maxVal,
1426  bool sgnd, PutData& putData) {
1427  comps_.clear();
1428  for (int i = 0; i < numComps; ++i) {
1429  comps_.push_back(Array2<T>(width, height));
1430  }
1431  putData.initialize(comps_);
1432  maxVal_ = maxVal;
1433  sgnd_ = sgnd;
1434  }
1435  typename std::vector<Array2<T> > comps_;
1436  int maxVal_;
1437  bool sgnd_;
1438 };
1439 
1440 template <class T>
1441 class PnmGetData
1442 {
1443 public:
1444 
1445  typedef Array2<T> Array;
1446  typedef typename Array::ConstXIterator ConstArrayIter;
1447 
1448  PnmGetData(const typename std::vector<Array>& comps, int maxVal,
1449  bool sgnd) : comps_(comps)
1450  {
1451  assert(comps.size() >= 0);
1452  dataIters_.reserve(3);
1453  int width = comps[0].getWidth();
1454  int height = comps[0].getHeight();
1455  y_ = height - 1;
1456  remaining_ = width;
1457  for (typename std::vector<Array>::const_iterator i = comps.begin();
1458  i != comps.end(); ++i) {
1459  dataIters_.push_back(i->rowBegin(y_));
1460  }
1461  comp_ = 0;
1462  }
1463 
1464  int operator()()
1465  {
1466  assert(y_ >= 0);
1467  ConstArrayIter& iter = dataIters_[comp_];
1468  int value = *iter;
1469  ++iter;
1470  ++comp_;
1471 
1472  if (comp_ >= comps_.size()) {
1473  comp_ = 0;
1474  --remaining_;
1475  if (remaining_ <= 0) {
1476  remaining_ = comps_[0].getWidth();
1477  --y_;
1478  if (y_ >= 0) {
1479  typename std::vector<Array>::const_iterator comp =
1480  comps_.begin();
1481  for (typename std::vector<ConstArrayIter>::iterator i =
1482  dataIters_.begin(); i != dataIters_.end(); ++i) {
1483  *i = comp->rowBegin(y_);
1484  ++comp;
1485  }
1486  }
1487  }
1488  }
1489 
1490  return value;
1491  }
1492 
1493 private:
1494  const std::vector<Array>& comps_;
1495  typename std::vector<ConstArrayIter> dataIters_;
1496  int y_;
1497  int remaining_;
1498  int comp_;
1499 };
1500 
1502 
1518 template <class T>
1519 int encodePnm(std::ostream& outStream, const std::vector<Array2<T> >& comps,
1520  int maxVal, bool sgnd, bool binaryFormat = true)
1521 {
1522  PnmGetData<T> getData(comps, maxVal, sgnd);
1523  return pnmEncode(outStream, comps[0].getWidth(), comps[0].getHeight(),
1524  comps.size(), maxVal, sgnd, getData, binaryFormat);
1525 }
1526 
1538 template <class T>
1539 int encodePbm(std::ostream& outStream, const Array2<T>& bits, bool binaryFormat = true)
1540 {
1541  return encodePnm(outStream, std::vector<Array2<T> >(1, bits), 1, binaryFormat);
1542 }
1543 
1557 template <class T>
1558 int encodePgm(std::ostream& outStream, const Array2<T>& gray, int maxVal,
1559  bool sgnd, bool binaryFormat = true)
1560 {
1561  return encodePnm(outStream, std::vector<Array2<T> >(1, gray), maxVal,
1562  sgnd, binaryFormat);
1563 }
1564 
1579 template <class T>
1580 int encodePpm(std::ostream& outStream, const Array2<T>& red,
1581  const Array2<T>& green, const Array2<T>& blue, int maxVal, bool sgnd,
1582  bool binaryFormat = true)
1583 {
1584  std::vector<Array2<T> > comps;
1585  comps.push_back(red);
1586  comps.push_back(green);
1587  comps.push_back(blue);
1588  return encodePnm(outStream, comps, maxVal, sgnd, binaryFormat);
1589 }
1590 
1605 template <class T>
1606 int decodePnm(std::istream& inStream, std::vector<Array2<T> >& comps,
1607  int& maxVal, bool& sgnd)
1608 {
1609  PnmInitialize<T> initialize;
1610  int ret;
1611  if ((ret = pnmDecode(inStream, initialize))) {
1612  return ret;
1613  }
1614  comps = initialize.comps_;
1615  maxVal = initialize.maxVal_;
1616  sgnd = initialize.sgnd_;
1617  return 0;
1618 }
1619 
1632 template <class T>
1633 int decodePbm(std::istream& inStream, Array2<T>& bits)
1634 {
1635  int ret;
1636  int maxVal;
1637  bool sgnd;
1638  std::vector<Array2<T> > comps;
1639  if ((ret = decodePnm(inStream, comps, maxVal, sgnd))) {
1640  return ret;
1641  }
1642  assert(maxVal == 1);
1643  assert(!sgnd);
1644  bits = comps[0];
1645  return 0;
1646 }
1647 
1661 template <class T>
1662 int decodePgm(std::istream& inStream, Array2<T>& gray, int& maxVal, bool& sgnd)
1663 {
1664  int ret;
1665  std::vector<Array2<T> > comps;
1666  if ((ret = decodePnm(inStream, comps, maxVal, sgnd))) {
1667  return ret;
1668  }
1669  gray = comps[0];
1670  return 0;
1671 }
1672 
1687 template <class T>
1688 int decodePpm(std::istream& inStream, Array2<T>& red, Array2<T>& green,
1689  Array2<T>& blue, int& maxVal, bool& sgnd)
1690 {
1691  int ret;
1692  std::vector<Array2<T> > comps;
1693  if ((ret = decodePnm(inStream, comps, maxVal, sgnd))) {
1694  return ret;
1695  }
1696  red = comps[0];
1697  green = comps[1];
1698  blue = comps[2];
1699  return 0;
1700 }
1701 
1706 // Basic type defintions.
1709 
1715 typedef Array2<double> RealArray2;
1717 
1720 
1725 //
1728 
1729 }
1730 
1731 #endif
void resize(int width, int height)
Change the size of the array.
Definition: Array2.hpp:1045
ConstYIterator colEnd(int x) const
Get a const iterator for one past the end in the specified column of the array.
Definition: Array2.hpp:1026
ConstXIterator rowEnd(int y) const
Get a const iterator for one past the end in the specified row of the array.
Definition: Array2.hpp:996
bool isShared() const
Is the data for this array shared with another array?
Definition: Array2.hpp:903
This file contains miscellaneous code.
Array2 & operator=(const Array2 &a)
The assignment operator.
Definition: Array2.hpp:748
std::istream & operator>>(std::istream &in, Array2< T > &a)
Input an array from the specified stream.
Definition: Array2.hpp:1167
T & operator()(int x, int y)
Get a mutable reference to the (x,y)-th element in the array.
Definition: Array2.hpp:919
Array2< T > transpose(const Array2< T > &a)
Get the transpose of the array.
Definition: Array2.hpp:1255
Definition: Arcball.hpp:48
int getWidth() const
Get the width of the array.
Definition: Array2.hpp:884
Array2 & operator*=(const Array2 &a)
Multiply another array (elementwise) by this array.
Definition: Array2.hpp:804
std::ostream & output(std::ostream &out, int fieldWidth) const
Output an array to a stream using the specified field width for each array element.
Definition: Array2.hpp:1096
ConstIterator begin() const
Get a const iterator for the first element in the array.
Definition: Array2.hpp:955
Array2< double > RealArray2
A two-dimensional array with real elements.
Definition: Array2.hpp:1716
int encodePnm(std::ostream &outStream, const std::vector< Array2< T > > &comps, int maxVal, bool sgnd, bool binaryFormat=true)
Output the array as an image in the PNM format.
Definition: Array2.hpp:1519
T ElemType
The type of the elements in the array.
Definition: Array2.hpp:166
ConstXIterator rowBegin(int y) const
Get a const iterator for the first element in the specified row of the array.
Definition: Array2.hpp:981
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
Array2()
Create an empty array.
Definition: Array2.hpp:686
#define SPL_ARRAY2_INLINE
Defining this symbol will enable extra code for debugging.
Definition: Array2.hpp:47
int decodePbm(std::istream &inStream, Array2< T > &bits)
Input an array as an image in the PNM format.
Definition: Array2.hpp:1633
std::vector< T >::const_iterator ConstXIterator
A constant iterator for elements of a row in the array.
Definition: Array2.hpp:231
Array2 & flipud()
Flip the array upside down.
Definition: Array2.hpp:1220
int encodePgm(std::ostream &outStream, const Array2< T > &gray, int maxVal, bool sgnd, bool binaryFormat=true)
Output the array as an image in the PNM format (PGM type).
Definition: Array2.hpp:1558
int putData(std::ostream &out, PnmHeader &header, GetData &getData)
Write the actual image data to a stream.
Definition: pnmCodec.hpp:228
ConstIterator end() const
Get a const iterator for one past the last element in the array.
Definition: Array2.hpp:968
int decodePgm(std::istream &inStream, Array2< T > &gray, int &maxVal, bool &sgnd)
Input an array as an image in the PNM format.
Definition: Array2.hpp:1662
T min() const
Get the minimum of the elements in the array.
Definition: Array2.hpp:1079
T sum() const
Get the sum of the elements in the array.
Definition: Array2.hpp:1086
void dump(std::ostream &out) const
Output information about an array to a stream for debugging.
Definition: Array2.hpp:1310
int decodePpm(std::istream &inStream, Array2< T > &red, Array2< T > &green, Array2< T > &blue, int &maxVal, bool &sgnd)
Input an array as an image in the PNM format.
Definition: Array2.hpp:1688
std::vector< T >::iterator Iterator
A mutable iterator for all elements in the array.
Definition: Array2.hpp:222
~Array2()
The destructor.
Definition: Array2.hpp:725
YIter< T > YIterator
A mutable iterator for elements of a column in the array.
Definition: Array2.hpp:234
int encodePbm(std::ostream &outStream, const Array2< T > &bits, bool binaryFormat=true)
Output the array as an image in the PNM format (PBM type).
Definition: Array2.hpp:1539
void fill(const T &value=T(0))
Set all elements in the array to the specified value.
Definition: Array2.hpp:1213
void swap(Array2 &a)
Swap the array data with the data of the specified array.
Definition: Array2.hpp:1202
void unshare() const
Force the underlying data to be copied if the data is shared.
Definition: Array2.hpp:1336
A two-dimensional array class with lazy copying and reference counting.
Definition: Array2.hpp:83
Array2 & operator/=(const Array2 &a)
Divide this array (elementwise) by another array.
Definition: Array2.hpp:814
int load(const char *fileName)
Load an array from the file with the specified name.
Definition: Array2.hpp:1120
This file contains a PNM codec.
YIter< const T > ConstYIterator
A constant iterator for elements of a column in the array.
Definition: Array2.hpp:237
ConstYIterator colBegin(int x) const
Get a const iterator for the first element in the specified column of the array.
Definition: Array2.hpp:1011
int save(const char *fileName) const
Save an array to the file with the specified name.
Definition: Array2.hpp:1131
int getData(std::istream &in, PnmHeader &header, PutData &putData)
Read the actual image data from the specified stream.
Definition: pnmCodec.hpp:337
int pnmDecode(std::istream &inStream, Initialize &initialize)
Read data encoded in the PNM format from the specified stream.
Definition: pnmCodec.hpp:309
Array2 & operator+=(const Array2 &a)
Add another array (elementwise) to this array.
Definition: Array2.hpp:784
Array2< int > IntArray2
A two-dimensional array with integer elements.
Definition: Array2.hpp:1719
int decodePnm(std::istream &inStream, std::vector< Array2< T > > &comps, int &maxVal, bool &sgnd)
Input an array as an image in the PNM format.
Definition: Array2.hpp:1606
Iterator XIterator
A mutable iterator for elements of a row in the array.
Definition: Array2.hpp:228
int encodePpm(std::ostream &outStream, const Array2< T > &red, const Array2< T > &green, const Array2< T > &blue, int maxVal, bool sgnd, bool binaryFormat=true)
Output the array as an image in the PNM format (PPM type).
Definition: Array2.hpp:1580
int getSize() const
Get the number of elements in the array.
Definition: Array2.hpp:896
int getHeight() const
Get the height of the array.
Definition: Array2.hpp:890
std::vector< T >::const_iterator ConstIterator
A constant iterator for all elements in the array.
Definition: Array2.hpp:225
bool operator!=(const Array2< T > &a, const Array2< T > &b)
Test two arrays for inequality.
Definition: Array2.hpp:1300
bool isSharedWith(const Array2 &a) const
Is the data for this array shared with the specified array?
Definition: Array2.hpp:909
T max() const
Get the maximum of the elements in the array.
Definition: Array2.hpp:1072
bool operator==(const Array2< T > &a, const Array2< T > &b)
Test two arrays for equality.
Definition: Array2.hpp:1272
Array2 & fliplr()
Flip the array left to right.
Definition: Array2.hpp:1236
Array2 & operator-=(const Array2 &a)
Subtract another array (elementwise) from this array.
Definition: Array2.hpp:794
int pnmEncode(std::ostream &outStream, int width, int height, int numComps, int maxVal, bool sgnd, GetData &getData, bool binaryFormat)
Write data encoded in the PNM format to the specified stream.
Definition: pnmCodec.hpp:195