2222#pragma once
2323
2424#include " adt/Array1DRef.h"
25+ #include " adt/CroppedArray1DRef.h" // IWYU pragma: keep
2526#include " adt/Invariant.h"
2627#include " adt/Optional.h"
2728#include < cstddef>
3132namespace rawspeed {
3233
3334template <class T > class Array2DRef final {
34- T* _data ;
35+ Array1DRef<T> data ;
3536 int _pitch;
3637
38+ int _width;
39+ int _height;
40+
3741 friend Array2DRef<const T>; // We need to be able to convert to const version.
3842
3943 // We need to be able to convert to std::byte.
4044 friend Array2DRef<std::byte>;
4145 friend Array2DRef<const std::byte>;
4246
47+ Array2DRef (Array1DRef<T> data, int width, int height, int pitch);
48+
4349public:
4450 void establishClassInvariants () const noexcept ;
4551
4652 using value_type = T;
4753 using cvless_value_type = std::remove_cv_t <value_type>;
4854
49- int width;
50- int height;
55+ [[nodiscard]] int RAWSPEED_READONLY width () const ;
56+ [[nodiscard]] int RAWSPEED_READONLY height () const ;
5157
5258 Array2DRef () = delete ;
5359
54- Array2DRef (T* data, int width, int height, int pitch = 0 );
60+ Array2DRef (T* data, int width, int height, int pitch);
61+
62+ Array2DRef (T* data, int width, int height);
5563
5664 // Can not cast away constness.
5765 template <typename T2>
@@ -70,8 +78,8 @@ template <class T> class Array2DRef final {
7078 requires (!std::is_const_v<T2> && std::is_const_v<T> &&
7179 std::is_same_v<std::remove_const_t <T>, std::remove_const_t <T2>>)
7280 Array2DRef (Array2DRef<T2> RHS) // NOLINT google-explicit-constructor
73- : _data (RHS._data ), _pitch(RHS._pitch), width (RHS.width),
74- height (RHS.height) {}
81+ : data (RHS.data ), _pitch(RHS._pitch), _width (RHS.width() ),
82+ _height (RHS.height() ) {}
7583
7684 // Const-preserving conversion from Array2DRef<T> to Array2DRef<std::byte>.
7785 template <typename T2>
@@ -80,8 +88,8 @@ template <class T> class Array2DRef final {
8088 std::remove_const_t <T2>>) &&
8189 std::is_same_v<std::remove_const_t<T>, std::byte>)
8290 Array2DRef(Array2DRef<T2> RHS) // NOLINT google-explicit-constructor
83- : _data( reinterpret_cast <T*>( RHS._data) ), _pitch(sizeof (T2) * RHS._pitch),
84- width (sizeof (T2) * RHS.width), height (RHS.height) {}
91+ : data( RHS.data ), _pitch(sizeof (T2) * RHS._pitch),
92+ _width (sizeof (T2) * RHS.width()), _height (RHS.height() ) {}
8593
8694 template <typename AllocatorType =
8795 typename std::vector<cvless_value_type>::allocator_type>
@@ -102,53 +110,81 @@ template <class T> class Array2DRef final {
102110
103111// CTAD deduction guide
104112template <typename T>
105- explicit Array2DRef (T* data, int width, int height, int pitch = 0 )
113+ explicit Array2DRef (Array1DRef<T> data, int width, int height, int pitch)
106114 -> Array2DRef<T>;
107115
116+ // CTAD deduction guide
117+ template <typename T>
118+ explicit Array2DRef (T* data, int width, int height, int pitch) -> Array2DRef<T>;
119+
120+ // CTAD deduction guide
121+ template <typename T>
122+ explicit Array2DRef (T* data, int width, int height) -> Array2DRef<T>;
123+
108124template <class T >
109125inline void Array2DRef<T>::establishClassInvariants() const noexcept {
110- invariant (_data);
111- invariant (width >= 0 );
112- invariant (height >= 0 );
126+ data.establishClassInvariants ();
127+ invariant (_width >= 0 );
128+ invariant (_height >= 0 );
129+ invariant (_pitch != 0 );
113130 invariant (_pitch >= 0 );
114- invariant (_pitch >= width);
131+ invariant (_pitch >= _width);
132+ invariant ((_width == 0 ) == (_height == 0 ));
133+ invariant (data.size () == _pitch * _height);
115134}
116135
117136template <class T >
118- Array2DRef<T>::Array2DRef(T* data, const int width_, const int height_,
119- const int pitch_ /* = 0 */ )
120- : _data(data), _pitch(pitch_ == 0 ? width_ : pitch_), width(width_),
121- height (height_) {
137+ Array2DRef<T>::Array2DRef(Array1DRef<T> data_, const int width_,
138+ const int height_, const int pitch_)
139+ : data(data_), _pitch(pitch_), _width(width_), _height(height_) {
140+ establishClassInvariants ();
141+ }
142+
143+ template <class T >
144+ Array2DRef<T>::Array2DRef(T* data_, const int width_, const int height_,
145+ const int pitch_)
146+ : Array2DRef({data_, pitch_ * height_}, width_, height_, pitch_) {
147+ establishClassInvariants ();
148+ }
149+
150+ template <class T >
151+ Array2DRef<T>::Array2DRef(T* data_, const int width_, const int height_)
152+ : Array2DRef(data_, width_, height_, /* pitch=*/ width_) {
153+ establishClassInvariants ();
154+ }
155+
156+ template <class T > inline int Array2DRef<T>::width() const {
157+ establishClassInvariants ();
158+ return _width;
159+ }
160+
161+ template <class T > inline int Array2DRef<T>::height() const {
122162 establishClassInvariants ();
163+ return _height;
123164}
124165
125166template <class T >
126167[[nodiscard]] inline Optional<Array1DRef<T>>
127168Array2DRef<T>::getAsArray1DRef() const {
128169 establishClassInvariants ();
129- if (height == 1 || _pitch == width)
130- return {{_data , width * height}} ;
170+ if (height () == 1 || _pitch == width () )
171+ return data. getCrop ( /* offset= */ 0 , width () * height ()). getAsArray1DRef () ;
131172 return std::nullopt ;
132173}
133174
134175template <class T >
135176inline Array1DRef<T> Array2DRef<T>::operator [](const int row) const {
136177 establishClassInvariants ();
137178 invariant (row >= 0 );
138- invariant (row < height);
139- #pragma GCC diagnostic push
140- #pragma GCC diagnostic ignored "-Wpragmas"
141- #pragma GCC diagnostic ignored "-Wunknown-warning-option"
142- #pragma GCC diagnostic ignored "-Wunsafe-buffer-usage"
143- return Array1DRef<T>(&_data[row * _pitch], width);
144- #pragma GCC diagnostic pop
179+ invariant (row < height ());
180+ return data.getCrop (row * _pitch, width ()).getAsArray1DRef ();
145181}
146182
147183template <class T >
148184inline T& Array2DRef<T>::operator ()(const int row, const int col) const {
149185 establishClassInvariants ();
150186 invariant (col >= 0 );
151- invariant (col < width);
187+ invariant (col < width () );
152188 return (operator [](row))(col);
153189}
154190
0 commit comments