Signal/Geometry Processing Library (SPL)  1.1.24
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 
228  typedef Iterator XIterator;
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  std::transform(ptr_->data_.begin(), ptr_->data_.end(),
828  ptr_->data_.begin(), std::bind2nd(std::plus<T>(), value));
829  return *this;
830 }
831 
832 template <class T>
834 {
835  unshare();
836  std::transform(ptr_->data_.begin(), ptr_->data_.end(),
837  ptr_->data_.begin(), std::bind2nd(std::minus<T>(), value));
838  return *this;
839 }
840 
841 template <class T>
843 {
844  unshare();
845  std::transform(ptr_->data_.begin(), ptr_->data_.end(),
846  ptr_->data_.begin(), std::bind2nd(std::multiplies<T>(), value));
847  return *this;
848 }
849 
850 template <class T>
852 {
853  unshare();
854  std::transform(ptr_->data_.begin(), ptr_->data_.end(),
855  ptr_->data_.begin(), std::bind2nd(std::divides<T>(), value));
856  return *this;
857 }
858 
860 // Basic queries
862 
863 template <class T>
865 {
866  return ptr_->width_;
867 }
868 
869 template <class T>
871 {
872  return ptr_->height_;
873 }
874 
875 template <class T>
877 {
878  assert(ptr_->width_ * ptr_->height_ == ptr_->data_.size());
879  return ptr_->data_.size();
880 }
881 
882 template <class T>
884 {
885  return ptr_->getRefCount() > 1;
886 }
887 
888 template <class T>
890 {
891  return ptr_ == a.ptr_;
892 }
893 
895 // Accessors
897 
898 template <class T>
900 {
901  assert(x >= 0 && x < getWidth() && y >= 0 && y < getHeight());
902  unshare();
903  return ptr_->data_[y * getWidth() + x];
904 }
905 
906 template <class T>
907 SPL_ARRAY2_INLINE const T& Array2<T>::operator()(int x, int y) const
908 {
909  assert(x >= 0 && x < getWidth() && y >= 0 && y < getHeight());
910  return ptr_->data_[y * getWidth() + x];
911 }
912 
913 template <class T>
915 {
916  assert(getWidth() == 1 || getHeight() == 1);
917  assert(i >= 0 && i < getSize());
918  unshare();
919  return ptr_->data_[i];
920 }
921 
922 template <class T>
924 {
925  assert(getWidth() == 1 || getHeight() == 1);
926  assert(i >= 0 && i < getSize());
927  return ptr_->data_[i];
928 }
929 
931 // Iterators
933 
934 template <class T>
936 {
937  return ptr_->data_.begin();
938 }
939 
940 template <class T>
942 {
943  unshare();
944  return ptr_->data_.begin();
945 }
946 
947 template <class T>
949 {
950  return ptr_->data_.end();
951 }
952 
953 template <class T>
955 {
956  unshare();
957  return ptr_->data_.end();
958 }
959 
960 template <class T>
962 {
963  assert(y >= 0 && y < getHeight());
964  return begin() + (y * getWidth());
965 }
966 
967 template <class T>
969 {
970  assert(y >= 0 && y < getHeight());
971  unshare();
972  return begin() + (y * getWidth());
973 }
974 
975 template <class T>
977 {
978  assert(y >= 0 && y < getHeight());
979  return begin() + ((y + 1) * getWidth());
980 }
981 
982 template <class T>
984 {
985  assert(y >= 0 && y < getHeight());
986  unshare();
987  return begin() + ((y + 1) * getWidth());
988 }
989 
990 template <class T>
992 {
993  assert(x >= 0 && x < getWidth());
994  return ConstYIterator(getWidth(), &(*(begin() + x)));
995 }
996 
997 template <class T>
999 {
1000  assert(x >= 0 && x < getWidth());
1001  unshare();
1002  return YIterator(getWidth(), &(*(begin() + x)));
1003 }
1004 
1005 template <class T>
1007 {
1008  assert(x >= 0 && x < getWidth());
1009  return ConstYIterator(getWidth(), &(*(begin() + (getSize() + x))));
1010 }
1011 
1012 template <class T>
1014 {
1015  assert(x >= 0 && x < getWidth());
1016  unshare();
1017  return YIterator(getWidth(), &(*(begin() + (getSize() + x))));
1018 }
1019 
1021 // Resizing
1023 
1024 template <class T>
1025 void Array2<T>::resize(int width, int height)
1026 {
1027  assert(width >= 0 && height >= 0);
1028  if (getWidth() != width || getHeight() != height) {
1029  ptr_->release();
1030  ptr_ = new Rep(width, height);
1031  }
1032 }
1033 
1034 template <class T>
1035 template <class InputIterator>
1036 void Array2<T>::resize(int width, int height, InputIterator data)
1037 {
1038  assert(width >= 0 && height >= 0);
1039  if (getWidth() == width && getHeight() == height && ptr_->getRefCount() == 1) {
1040  SPL::copy_n(data, getSize(), begin());
1041  } else {
1042  ptr_->release();
1043  ptr_ = new Rep(width, height, data);
1044  }
1045 }
1046 
1048 // Get various statistics
1050 
1051 template <class T>
1053 {
1054  assert(getSize() > 0);
1055  return *std::max_element(begin(), end());
1056 }
1057 
1058 template <class T>
1060 {
1061  assert(getSize() > 0);
1062  return *std::min_element(begin(), end());
1063 }
1064 
1065 template <class T>
1067 {
1068  return std::accumulate(begin(), end(), T(0));
1069 }
1070 
1072 // Input/output
1074 
1075 template <class T>
1076 std::ostream& Array2<T>::output(std::ostream& out, int fieldWidth) const
1077 {
1078  out << getWidth() << " " << getHeight() << "\n";
1079  for (int j = 0; j < getHeight(); ++j) {
1080  for (int i = 0; i < getWidth(); ++i) {
1081  T val = operator()(i, j);
1082  std::stringstream str;
1083  str << std::setw(fieldWidth) << val;
1084  std::string buf = str.str();
1085  if (buf.size() > fieldWidth) {
1086  buf = buf.substr(0, fieldWidth);
1087  }
1088  //out << std::setw(fieldWidth) << val;
1089  out << buf;
1090  if (i < getWidth() - 1) {
1091  out << " ";
1092  }
1093  }
1094  out << "\n";
1095  }
1096  return out;
1097 }
1098 
1099 template<class T>
1100 int Array2<T>::load(const char* fileName)
1101 {
1102  std::ifstream in(fileName);
1103  in >> *this;
1104  if (!in) {
1105  return -1;
1106  }
1107  return 0;
1108 }
1109 
1110 template<class T>
1111 int Array2<T>::save(const char* fileName) const
1112 {
1113  std::ofstream out(fileName);
1114  out << *this;
1115  if (!out) {
1116  return -1;
1117  }
1118  out.close();
1119  return 0;
1120 }
1121 
1125 template <class T>
1126 std::ostream& operator<<(std::ostream& out, const Array2<T>& a)
1127 {
1128  out << a.getWidth() << " " << a.getHeight() << "\n";
1129  for (int y = 0; y < a.getHeight(); ++y) {
1130  typename Array2<T>::ConstXIterator src = a.rowBegin(y);
1131  for (int x = 0; x < a.getWidth(); ++x) {
1132  if (x) {
1133  out << " ";
1134  }
1135  out << *src;
1136  ++src;
1137  }
1138  out << "\n";
1139  }
1140  return out;
1141 }
1142 
1146 template <class T>
1147 std::istream& operator>>(std::istream& in, Array2<T>& a)
1148 {
1149  int width;
1150  if (!(in >> width)) {
1151  return in;
1152  }
1153  int height;
1154  if (!(in >> height)) {
1155  return in;
1156  }
1157  if (width < 0 || height < 0) {
1158  in.setstate(std::ios::failbit);
1159  return in;
1160  }
1161 
1162  a = Array2<T>(width, height);
1163  for (int y = 0; y < a.getHeight(); ++y) {
1164  typename Array2<T>::XIterator dst = a.rowBegin(y);
1165  for (int x = 0; x < a.getWidth(); ++x) {
1166  T value;
1167  if (!(in >> value)) {
1168  return in;
1169  }
1170  *dst = value;
1171  ++dst;
1172  }
1173  }
1174  return in;
1175 }
1176 
1178 // Miscellaneous
1180 
1181 template <class T>
1183 {
1184  if (this != &a) {
1185  // Overall, the reference counts do not change.
1186  // Technically, both reference counts increase and then decrease,
1187  // for no net change.
1188  std::swap(ptr_, a.ptr_);
1189  }
1190 }
1191 
1192 template <class T>
1194 {
1195  unshare();
1196  std::fill(begin(), end(), value);
1197 }
1198 
1199 template <class T>
1201 {
1202  unshare();
1203  for (int k = 0; k < getHeight() / 2; ++k) {
1204  XIterator i = rowBegin(k);
1205  XIterator j = rowBegin(getHeight() - 1 - k);
1206  for (int n = getWidth(); n > 0; --n) {
1207  std::swap(*i, *j);
1208  ++i;
1209  ++j;
1210  }
1211  }
1212  return *this;
1213 }
1214 
1215 template <class T>
1217 {
1218  unshare();
1219  for (int y = 0; y < getHeight(); ++y) {
1220  XIterator i = rowBegin(y);
1221  XIterator j = i + (getWidth() - 1);
1222  for (int n = getWidth() / 2; n > 0; --n) {
1223  std::swap(*i, *j);
1224  ++i;
1225  --j;
1226  }
1227  }
1228  return *this;
1229 }
1230 
1234 template <class T>
1236 {
1237  int width = a.getWidth();
1238  int height = a.getHeight();
1239  Array2<T> result(height, width);
1240  for (int y = 0; y < width; ++y) {
1241  for (int x = 0; x < height; ++x) {
1242  result(x, y) = a(y, x);
1243  }
1244  }
1245  return result;
1246 }
1247 
1251 template <class T>
1252 bool operator==(const Array2<T>& a, const Array2<T>& b)
1253 {
1254  bool result;
1255  if (a.getWidth() == b.getWidth() && a.getHeight() == b.getHeight()) {
1256  result = true;
1257  for (int y = 0; y < a.getHeight(); ++y) {
1258  typename Array2<T>::ConstXIterator src = a.rowBegin(y);
1259  typename Array2<T>::ConstXIterator dst = b.rowBegin(y);
1260  for (int x = 0; x < a.getWidth(); ++x) {
1261  if (*src != *dst) {
1262  result = false;
1263  y = a.getHeight();
1264  break;
1265  }
1266  ++src;
1267  ++dst;
1268  }
1269  }
1270  } else {
1271  result = false;
1272  }
1273  return result;
1274 }
1275 
1279 template <class T>
1280 bool operator!=(const Array2<T>& a, const Array2<T>& b)
1281 {
1282  return !(a == b);
1283 }
1284 
1289 template <class T>
1290 void Array2<T>::dump(std::ostream& out) const
1291 {
1292  out << "Array2<T> " << this << " ";
1293  ptr_->dump(out);
1294  out << "\n";
1295 }
1296 
1298 // Private code
1300 
1301 template <class T>
1303 {
1304 #if defined(SPL_ARRAY2_DEBUG)
1305  std::cerr << "Array2<T>::copyOnWrite() " << this << "\n";
1306  dump(std::cerr);
1307 #endif
1308  // The underlying data must be shared.
1309  assert(ptr_->getRefCount() > 1);
1310  ptr_->release();
1311  //const_cast<Array2*>(this)->ptr_ = ptr_->clone();
1312  this->ptr_ = ptr_->clone();
1313 }
1314 
1315 template <class T>
1317 {
1318  if (ptr_->getRefCount() > 1) {
1319  copyOnWrite();
1320  }
1321 }
1322 
1327 // PNM Support
1330 
1336 
1338 template <class T>
1339 class PnmPutData
1340 {
1341 public:
1342 
1343  typedef Array2<T> Array;
1344  typedef typename Array::XIterator ArrayIter;
1345 
1346  PnmPutData() : comps_(0)
1347  {
1348  }
1349 
1350  void initialize(typename std::vector<Array>& comps)
1351  {
1352  comps_ = &comps;
1353  assert(comps.size() >= 0);
1354  dataIters_.reserve(3);
1355  y_ = (*comps_)[0].getHeight() - 1;
1356  remaining_ = (*comps_)[0].getWidth();
1357  for (typename std::vector<Array>::iterator i = comps_->begin();
1358  i != comps_->end(); ++i) {
1359  assert(!i->isShared());
1360  dataIters_.push_back(i->rowBegin(y_));
1361  }
1362  comp_ = 0;
1363  }
1364 
1365  void operator()(int value)
1366  {
1367  assert(y_ >= 0);
1368  ArrayIter& iter = dataIters_[comp_];
1369 //std::cerr << "writing " << y_ << " " << remaining_ << " " << value << "\n";
1370  *iter = value;
1371  ++iter;
1372  ++comp_;
1373 
1374  if (comp_ >= comps_->size()) {
1375  comp_ = 0;
1376  --remaining_;
1377  if (remaining_ <= 0) {
1378  remaining_ = (*comps_)[0].getWidth();
1379  --y_;
1380  if (y_ >= 0) {
1381  typename std::vector<Array>::iterator comp =
1382  (*comps_).begin();
1383  for (typename std::vector<ArrayIter>::iterator i =
1384  dataIters_.begin(); i != dataIters_.end(); ++i) {
1385  *i = comp->rowBegin(y_);
1386  ++comp;
1387  }
1388  }
1389  }
1390  }
1391  }
1392 private:
1393  std::vector<Array>* comps_;
1394  typename std::vector<ArrayIter> dataIters_;
1395  int y_;
1396  int remaining_;
1397  int comp_;
1398 };
1399 
1400 template <class T>
1401 class PnmInitialize
1402 {
1403 public:
1404  typedef PnmPutData<T> PutData;
1405  void operator()(int width, int height, int numComps, int maxVal,
1406  bool sgnd, PutData& putData) {
1407  comps_.clear();
1408  for (int i = 0; i < numComps; ++i) {
1409  comps_.push_back(Array2<T>(width, height));
1410  }
1411  putData.initialize(comps_);
1412  maxVal_ = maxVal;
1413  sgnd_ = sgnd;
1414  }
1415  typename std::vector<Array2<T> > comps_;
1416  int maxVal_;
1417  bool sgnd_;
1418 };
1419 
1420 template <class T>
1421 class PnmGetData
1422 {
1423 public:
1424 
1425  typedef Array2<T> Array;
1426  typedef typename Array::ConstXIterator ConstArrayIter;
1427 
1428  PnmGetData(const typename std::vector<Array>& comps, int maxVal,
1429  bool sgnd) : comps_(comps)
1430  {
1431  assert(comps.size() >= 0);
1432  dataIters_.reserve(3);
1433  int width = comps[0].getWidth();
1434  int height = comps[0].getHeight();
1435  y_ = height - 1;
1436  remaining_ = width;
1437  for (typename std::vector<Array>::const_iterator i = comps.begin();
1438  i != comps.end(); ++i) {
1439  dataIters_.push_back(i->rowBegin(y_));
1440  }
1441  comp_ = 0;
1442  }
1443 
1444  int operator()()
1445  {
1446  assert(y_ >= 0);
1447  ConstArrayIter& iter = dataIters_[comp_];
1448  int value = *iter;
1449  ++iter;
1450  ++comp_;
1451 
1452  if (comp_ >= comps_.size()) {
1453  comp_ = 0;
1454  --remaining_;
1455  if (remaining_ <= 0) {
1456  remaining_ = comps_[0].getWidth();
1457  --y_;
1458  if (y_ >= 0) {
1459  typename std::vector<Array>::const_iterator comp =
1460  comps_.begin();
1461  for (typename std::vector<ConstArrayIter>::iterator i =
1462  dataIters_.begin(); i != dataIters_.end(); ++i) {
1463  *i = comp->rowBegin(y_);
1464  ++comp;
1465  }
1466  }
1467  }
1468  }
1469 
1470  return value;
1471  }
1472 
1473 private:
1474  const std::vector<Array>& comps_;
1475  typename std::vector<ConstArrayIter> dataIters_;
1476  int y_;
1477  int remaining_;
1478  int comp_;
1479 };
1480 
1482 
1498 template <class T>
1499 int encodePnm(std::ostream& outStream, const std::vector<Array2<T> >& comps,
1500  int maxVal, bool sgnd, bool binaryFormat = true)
1501 {
1502  PnmGetData<T> getData(comps, maxVal, sgnd);
1503  return pnmEncode(outStream, comps[0].getWidth(), comps[0].getHeight(),
1504  comps.size(), maxVal, sgnd, getData, binaryFormat);
1505 }
1506 
1518 template <class T>
1519 int encodePbm(std::ostream& outStream, const Array2<T>& bits, bool binaryFormat = true)
1520 {
1521  return encodePnm(outStream, std::vector<Array2<T> >(1, bits), 1, binaryFormat);
1522 }
1523 
1537 template <class T>
1538 int encodePgm(std::ostream& outStream, const Array2<T>& gray, int maxVal,
1539  bool sgnd, bool binaryFormat = true)
1540 {
1541  return encodePnm(outStream, std::vector<Array2<T> >(1, gray), maxVal,
1542  sgnd, binaryFormat);
1543 }
1544 
1559 template <class T>
1560 int encodePpm(std::ostream& outStream, const Array2<T>& red,
1561  const Array2<T>& green, const Array2<T>& blue, int maxVal, bool sgnd,
1562  bool binaryFormat = true)
1563 {
1564  std::vector<Array2<T> > comps;
1565  comps.push_back(red);
1566  comps.push_back(green);
1567  comps.push_back(blue);
1568  return encodePnm(outStream, comps, maxVal, sgnd, binaryFormat);
1569 }
1570 
1585 template <class T>
1586 int decodePnm(std::istream& inStream, std::vector<Array2<T> >& comps,
1587  int& maxVal, bool& sgnd)
1588 {
1589  PnmInitialize<T> initialize;
1590  int ret;
1591  if ((ret = pnmDecode(inStream, initialize))) {
1592  return ret;
1593  }
1594  comps = initialize.comps_;
1595  maxVal = initialize.maxVal_;
1596  sgnd = initialize.sgnd_;
1597  return 0;
1598 }
1599 
1612 template <class T>
1613 int decodePbm(std::istream& inStream, Array2<T>& bits)
1614 {
1615  int ret;
1616  int maxVal;
1617  bool sgnd;
1618  std::vector<Array2<T> > comps;
1619  if ((ret = decodePnm(inStream, comps, maxVal, sgnd))) {
1620  return ret;
1621  }
1622  assert(maxVal == 1);
1623  assert(!sgnd);
1624  bits = comps[0];
1625  return 0;
1626 }
1627 
1641 template <class T>
1642 int decodePgm(std::istream& inStream, Array2<T>& gray, int& maxVal, bool& sgnd)
1643 {
1644  int ret;
1645  std::vector<Array2<T> > comps;
1646  if ((ret = decodePnm(inStream, comps, maxVal, sgnd))) {
1647  return ret;
1648  }
1649  gray = comps[0];
1650  return 0;
1651 }
1652 
1667 template <class T>
1668 int decodePpm(std::istream& inStream, Array2<T>& red, Array2<T>& green,
1669  Array2<T>& blue, int& maxVal, bool& sgnd)
1670 {
1671  int ret;
1672  std::vector<Array2<T> > comps;
1673  if ((ret = decodePnm(inStream, comps, maxVal, sgnd))) {
1674  return ret;
1675  }
1676  red = comps[0];
1677  green = comps[1];
1678  blue = comps[2];
1679  return 0;
1680 }
1681 
1686 // Basic type defintions.
1689 
1695 typedef Array2<double> RealArray2;
1697 
1700 
1705 //
1708 
1709 }
1710 
1711 #endif
void resize(int width, int height)
Change the size of the array.
Definition: Array2.hpp:1025
ConstXIterator rowEnd(int y) const
Get a const iterator for one past the end in the specified row of the array.
Definition: Array2.hpp:976
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:1147
T min() const
Get the minimum of the elements in the array.
Definition: Array2.hpp:1059
T & operator()(int x, int y)
Get a mutable reference to the (x,y)-th element in the array.
Definition: Array2.hpp:899
Array2< T > transpose(const Array2< T > &a)
Get the transpose of the array.
Definition: Array2.hpp:1235
T sum() const
Get the sum of the elements in the array.
Definition: Array2.hpp:1066
Definition: Arcball.hpp:48
Array2 & operator*=(const Array2 &a)
Multiply another array (elementwise) by this array.
Definition: Array2.hpp:804
void unshare() const
Force the underlying data to be copied if the data is shared.
Definition: Array2.hpp:1316
Array2< double > RealArray2
A two-dimensional array with real elements.
Definition: Array2.hpp:1696
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:1499
T ElemType
The type of the elements in the array.
Definition: Array2.hpp:166
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:1613
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:1200
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:1538
bool isSharedWith(const Array2 &a) const
Is the data for this array shared with the specified array?
Definition: Array2.hpp:889
bool isShared() const
Is the data for this array shared with another array?
Definition: Array2.hpp:883
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:1642
ConstYIterator colEnd(int x) const
Get a const iterator for one past the end in the specified column of the array.
Definition: Array2.hpp:1006
void dump(std::ostream &out) const
Output information about an array to a stream for debugging.
Definition: Array2.hpp:1290
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:1668
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
ConstXIterator rowBegin(int y) const
Get a const iterator for the first element in the specified row of the array.
Definition: Array2.hpp:961
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:1519
void fill(const T &value=T(0))
Set all elements in the array to the specified value.
Definition: Array2.hpp:1193
void swap(Array2 &a)
Swap the array data with the data of the specified array.
Definition: Array2.hpp:1182
A two-dimensional array class with lazy copying and reference counting.
Definition: Array2.hpp:83
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:1076
Array2 & operator/=(const Array2 &a)
Divide this array (elementwise) by another array.
Definition: Array2.hpp:814
ConstYIterator colBegin(int x) const
Get a const iterator for the first element in the specified column of the array.
Definition: Array2.hpp:991
T max() const
Get the maximum of the elements in the array.
Definition: Array2.hpp:1052
int load(const char *fileName)
Load an array from the file with the specified name.
Definition: Array2.hpp:1100
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
int getHeight() const
Get the height of the array.
Definition: Array2.hpp:870
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:1699
ConstIterator begin() const
Get a const iterator for the first element in the array.
Definition: Array2.hpp:935
int save(const char *fileName) const
Save an array to the file with the specified name.
Definition: Array2.hpp:1111
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:1586
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:1560
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:1280
ConstIterator end() const
Get a const iterator for one past the last element in the array.
Definition: Array2.hpp:948
bool operator==(const Array2< T > &a, const Array2< T > &b)
Test two arrays for equality.
Definition: Array2.hpp:1252
Array2 & fliplr()
Flip the array left to right.
Definition: Array2.hpp:1216
Array2 & operator-=(const Array2 &a)
Subtract another array (elementwise) from this array.
Definition: Array2.hpp:794
int getSize() const
Get the number of elements in the array.
Definition: Array2.hpp:876
int getWidth() const
Get the width of the array.
Definition: Array2.hpp:864