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>
297 Array2& operator=(const Array2<OtherType>& a);
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>
686 SPL_ARRAY2_INLINE Array2<T>::Array2()
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>
699 SPL_ARRAY2_INLINE Array2<T>::Array2(const Array2<T>& a)
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>
725 SPL_ARRAY2_INLINE Array2<T>::~Array2()
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>
735 SPL_ARRAY2_INLINE Array2<T>::Array2(const Array2<OtherType>& a)
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>
748 SPL_ARRAY2_INLINE Array2<T>& Array2<T>::operator=(const Array2<T>& a)
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>
765 Array2<T>& Array2<T>::operator=(const Array2<OtherType>& a)
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>
784 SPL_ARRAY2_INLINE Array2<T>& Array2<T>::operator+=(const Array2<T>& a)
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>
794 SPL_ARRAY2_INLINE Array2<T>& Array2<T>::operator-=(const Array2<T>& a)
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>
804 SPL_ARRAY2_INLINE Array2<T>& Array2<T>::operator*=(const Array2<T>& a)
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>
814 SPL_ARRAY2_INLINE Array2<T>& Array2<T>::operator/=(const Array2<T>& a)
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>
824 SPL_ARRAY2_INLINE Array2<T>& Array2<T>::operator+=(const T& value)
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>
833 SPL_ARRAY2_INLINE Array2<T>& Array2<T>::operator-=(const T& value)
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>
842 SPL_ARRAY2_INLINE Array2<T>& Array2<T>::operator*=(const T& value)
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>
851 SPL_ARRAY2_INLINE Array2<T>& Array2<T>::operator/=(const T& value)
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>
864 SPL_ARRAY2_INLINE int Array2<T>::getWidth() const
865 {
866 return ptr_->width_;
867 }
868
869 template <class T>
870 SPL_ARRAY2_INLINE int Array2<T>::getHeight() const
871 {
872 return ptr_->height_;
873 }
874
875 template <class T>
876 SPL_ARRAY2_INLINE int Array2<T>::getSize() const
877 {
878 assert(ptr_->width_ * ptr_->height_ == ptr_->data_.size());
879 return ptr_->data_.size();
880 }
881
882 template <class T>
883 SPL_ARRAY2_INLINE bool Array2<T>::isShared() const
884 {
885 return ptr_->getRefCount() > 1;
886 }
887
888 template <class T>
889 SPL_ARRAY2_INLINE bool Array2<T>::isSharedWith(const Array2& a) const
890 {
891 return ptr_ == a.ptr_;
892 }
893
895 // Accessors
897
898 template <class T>
899 SPL_ARRAY2_INLINE T& Array2<T>::operator()(int x, int y)
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>
914 SPL_ARRAY2_INLINE T& Array2<T>::operator()(int i)
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>
923 SPL_ARRAY2_INLINE const T& Array2<T>::operator()(int i) const
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>
935 SPL_ARRAY2_INLINE typename Array2<T>::ConstIterator Array2<T>::begin() const
936 {
937 return ptr_->data_.begin();
938 }
939
940 template <class T>
941 SPL_ARRAY2_INLINE typename Array2<T>::Iterator Array2<T>::begin()
942 {
943 unshare();
944 return ptr_->data_.begin();
945 }
946
947 template <class T>
948 SPL_ARRAY2_INLINE typename Array2<T>::ConstIterator Array2<T>::end() const
949 {
950 return ptr_->data_.end();
951 }
952
953 template <class T>
954 SPL_ARRAY2_INLINE typename Array2<T>::Iterator Array2<T>::end()
955 {
956 unshare();
957 return ptr_->data_.end();
958 }
959
960 template <class T>
961 SPL_ARRAY2_INLINE typename Array2<T>::ConstXIterator Array2<T>::rowBegin(int y) const
962 {
963 assert(y >= 0 && y < getHeight());
964 return begin() + (y * getWidth());
965 }
966
967 template <class T>
968 SPL_ARRAY2_INLINE typename Array2<T>::XIterator Array2<T>::rowBegin(int y)
969 {
970 assert(y >= 0 && y < getHeight());
971 unshare();
972 return begin() + (y * getWidth());
973 }
974
975 template <class T>
976 SPL_ARRAY2_INLINE typename Array2<T>::ConstXIterator Array2<T>::rowEnd(int y) const
977 {
978 assert(y >= 0 && y < getHeight());
979 return begin() + ((y + 1) * getWidth());
980 }
981
982 template <class T>
983 SPL_ARRAY2_INLINE typename Array2<T>::XIterator Array2<T>::rowEnd(int y)
984 {
985 assert(y >= 0 && y < getHeight());
986 unshare();
987 return begin() + ((y + 1) * getWidth());
988 }
989
990 template <class T>
991 SPL_ARRAY2_INLINE typename Array2<T>::ConstYIterator Array2<T>::colBegin(int x) const
992 {
993 assert(x >= 0 && x < getWidth());
994 return ConstYIterator(getWidth(), &(*(begin() + x)));
995 }
996
997 template <class T>
998 SPL_ARRAY2_INLINE typename Array2<T>::YIterator Array2<T>::colBegin(int x)
999 {
1000 assert(x >= 0 && x < getWidth());
1001 unshare();
1002 return YIterator(getWidth(), &(*(begin() + x)));
1003 }
1004
1005 template <class T>
1006 SPL_ARRAY2_INLINE typename Array2<T>::ConstYIterator Array2<T>::colEnd(int x) const
1007 {
1008 assert(x >= 0 && x < getWidth());
1009 return ConstYIterator(getWidth(), &(*(begin() + (getSize() + x))));
1010 }
1011
1012 template <class T>
1013 SPL_ARRAY2_INLINE typename Array2<T>::YIterator Array2<T>::colEnd(int x)
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>
1052 SPL_ARRAY2_INLINE T Array2<T>::max() const
1053 {
1054 assert(getSize() > 0);
1055 return *std::max_element(begin(), end());
1056 }
1057
1058 template <class T>
1059 SPL_ARRAY2_INLINE T Array2<T>::min() const
1060 {
1061 assert(getSize() > 0);
1062 return *std::min_element(begin(), end());
1063 }
1064
1065 template <class T>
1066 SPL_ARRAY2_INLINE T Array2<T>::sum() const
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>
1182 void Array2<T>::swap(Array2<T>& a)
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>
1193 SPL_ARRAY2_INLINE void Array2<T>::fill(const T& value)
1194 {
1195 unshare();
1196 std::fill(begin(), end(), value);
1197 }
1198
1199 template <class T>
1200 Array2<T>& Array2<T>::flipud()
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>
1216 Array2<T>& Array2<T>::fliplr()
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>
1235 Array2<T> transpose(const Array2<T>& a)
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>
1302 SPL_ARRAY2_INLINE void Array2<T>::copyOnWrite() const
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>
1316 SPL_ARRAY2_INLINE void Array2<T>::unshare() const
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
1699 typedef Array2<int> IntArray2;
1700
1705 //
1708
1709 }
1710
1711 #endif
SPL::Array2::resize
void resize(int width, int height)
Change the size of the array.
Definition: Array2.hpp:1025
SPL::Array2::rowEnd
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
misc.hpp
This file contains miscellaneous code.
SPL::Array2::operator=
Array2 & operator=(const Array2 &a)
The assignment operator.
Definition: Array2.hpp:748
SPL::operator>>
std::istream & operator>>(std::istream &in, Array2< T > &a)
Input an array from the specified stream.
Definition: Array2.hpp:1147
SPL::Array2::min
T min() const
Get the minimum of the elements in the array.
Definition: Array2.hpp:1059
SPL::Array2::operator()
T & operator()(int x, int y)
Get a mutable reference to the (x,y)-th element in the array.
Definition: Array2.hpp:899
SPL::transpose
Array2< T > transpose(const Array2< T > &a)
Get the transpose of the array.
Definition: Array2.hpp:1235
SPL::Array2::sum
T sum() const
Get the sum of the elements in the array.
Definition: Array2.hpp:1066
SPL
Definition: Arcball.hpp:48
SPL::Array2::operator*=
Array2 & operator*=(const Array2 &a)
Multiply another array (elementwise) by this array.
Definition: Array2.hpp:804
SPL::Array2::unshare
void unshare() const
Force the underlying data to be copied if the data is shared.
Definition: Array2.hpp:1316
SPL::RealArray2
Array2< double > RealArray2
A two-dimensional array with real elements.
Definition: Array2.hpp:1696
SPL::encodePnm
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
SPL::Array2::ElemType
T ElemType
The type of the elements in the array.
Definition: Array2.hpp:166
SPL::Array2::Array2
Array2()
Create an empty array.
Definition: Array2.hpp:686
SPL_ARRAY2_INLINE
#define SPL_ARRAY2_INLINE
Defining this symbol will enable extra code for debugging.
Definition: Array2.hpp:47
SPL::decodePbm
int decodePbm(std::istream &inStream, Array2< T > &bits)
Input an array as an image in the PNM format.
Definition: Array2.hpp:1613
SPL::Array2::ConstXIterator
std::vector< T >::const_iterator ConstXIterator
A constant iterator for elements of a row in the array.
Definition: Array2.hpp:231
SPL::Array2::flipud
Array2 & flipud()
Flip the array upside down.
Definition: Array2.hpp:1200
SPL::encodePgm
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
SPL::Array2::isSharedWith
bool isSharedWith(const Array2 &a) const
Is the data for this array shared with the specified array?
Definition: Array2.hpp:889
SPL::Array2::isShared
bool isShared() const
Is the data for this array shared with another array?
Definition: Array2.hpp:883
SPL::decodePgm
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
SPL::Array2::colEnd
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
SPL::Array2::dump
void dump(std::ostream &out) const
Output information about an array to a stream for debugging.
Definition: Array2.hpp:1290
SPL::decodePpm
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
SPL::Array2::Iterator
std::vector< T >::iterator Iterator
A mutable iterator for all elements in the array.
Definition: Array2.hpp:222
SPL::Array2::~Array2
~Array2()
The destructor.
Definition: Array2.hpp:725
SPL::Array2::YIterator
YIter< T > YIterator
A mutable iterator for elements of a column in the array.
Definition: Array2.hpp:234
SPL::Array2::rowBegin
ConstXIterator rowBegin(int y) const
Get a const iterator for the first element in the specified row of the array.
Definition: Array2.hpp:961
SPL::encodePbm
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
SPL::Array2::fill
void fill(const T &value=T(0))
Set all elements in the array to the specified value.
Definition: Array2.hpp:1193
SPL::Array2::swap
void swap(Array2 &a)
Swap the array data with the data of the specified array.
Definition: Array2.hpp:1182
SPL::Array2
A two-dimensional array class with lazy copying and reference counting.
Definition: Array2.hpp:83
SPL::Array2::output
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
SPL::Array2::operator/=
Array2 & operator/=(const Array2 &a)
Divide this array (elementwise) by another array.
Definition: Array2.hpp:814
SPL::Array2::colBegin
ConstYIterator colBegin(int x) const
Get a const iterator for the first element in the specified column of the array.
Definition: Array2.hpp:991
SPL::Array2::max
T max() const
Get the maximum of the elements in the array.
Definition: Array2.hpp:1052
SPL::Array2::load
int load(const char *fileName)
Load an array from the file with the specified name.
Definition: Array2.hpp:1100
pnmCodec.hpp
This file contains a PNM codec.
SPL::Array2::ConstYIterator
YIter< const T > ConstYIterator
A constant iterator for elements of a column in the array.
Definition: Array2.hpp:237
SPL::Array2::getHeight
int getHeight() const
Get the height of the array.
Definition: Array2.hpp:870
SPL::Array2::operator+=
Array2 & operator+=(const Array2 &a)
Add another array (elementwise) to this array.
Definition: Array2.hpp:784
SPL::IntArray2
Array2< int > IntArray2
A two-dimensional array with integer elements.
Definition: Array2.hpp:1699
SPL::Array2::begin
ConstIterator begin() const
Get a const iterator for the first element in the array.
Definition: Array2.hpp:935
SPL::Array2::save
int save(const char *fileName) const
Save an array to the file with the specified name.
Definition: Array2.hpp:1111
SPL::decodePnm
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
SPL::Array2::XIterator
Iterator XIterator
A mutable iterator for elements of a row in the array.
Definition: Array2.hpp:228
SPL::encodePpm
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
SPL::Array2::ConstIterator
std::vector< T >::const_iterator ConstIterator
A constant iterator for all elements in the array.
Definition: Array2.hpp:225
SPL::operator!=
bool operator!=(const Array2< T > &a, const Array2< T > &b)
Test two arrays for inequality.
Definition: Array2.hpp:1280
SPL::Array2::end
ConstIterator end() const
Get a const iterator for one past the last element in the array.
Definition: Array2.hpp:948
SPL::operator==
bool operator==(const Array2< T > &a, const Array2< T > &b)
Test two arrays for equality.
Definition: Array2.hpp:1252
SPL::Array2::fliplr
Array2 & fliplr()
Flip the array left to right.
Definition: Array2.hpp:1216
SPL::Array2::operator-=
Array2 & operator-=(const Array2 &a)
Subtract another array (elementwise) from this array.
Definition: Array2.hpp:794
SPL::Array2::getSize
int getSize() const
Get the number of elements in the array.
Definition: Array2.hpp:876
SPL::Array2::getWidth
int getWidth() const
Get the width of the array.
Definition: Array2.hpp:864