1*09537850SAkhilesh Sanikop // Copyright 2021 The libgav1 Authors
2*09537850SAkhilesh Sanikop //
3*09537850SAkhilesh Sanikop // Licensed under the Apache License, Version 2.0 (the "License");
4*09537850SAkhilesh Sanikop // you may not use this file except in compliance with the License.
5*09537850SAkhilesh Sanikop // You may obtain a copy of the License at
6*09537850SAkhilesh Sanikop //
7*09537850SAkhilesh Sanikop // http://www.apache.org/licenses/LICENSE-2.0
8*09537850SAkhilesh Sanikop //
9*09537850SAkhilesh Sanikop // Unless required by applicable law or agreed to in writing, software
10*09537850SAkhilesh Sanikop // distributed under the License is distributed on an "AS IS" BASIS,
11*09537850SAkhilesh Sanikop // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12*09537850SAkhilesh Sanikop // See the License for the specific language governing permissions and
13*09537850SAkhilesh Sanikop // limitations under the License.
14*09537850SAkhilesh Sanikop
15*09537850SAkhilesh Sanikop #include "src/utils/array_2d.h"
16*09537850SAkhilesh Sanikop
17*09537850SAkhilesh Sanikop #include <cstdint>
18*09537850SAkhilesh Sanikop #include <memory>
19*09537850SAkhilesh Sanikop #include <new>
20*09537850SAkhilesh Sanikop #include <type_traits>
21*09537850SAkhilesh Sanikop
22*09537850SAkhilesh Sanikop #include "gtest/gtest.h"
23*09537850SAkhilesh Sanikop #include "src/utils/compiler_attributes.h"
24*09537850SAkhilesh Sanikop
25*09537850SAkhilesh Sanikop #if LIBGAV1_MSAN
26*09537850SAkhilesh Sanikop #include <sanitizer/msan_interface.h>
27*09537850SAkhilesh Sanikop #endif
28*09537850SAkhilesh Sanikop
29*09537850SAkhilesh Sanikop namespace libgav1 {
30*09537850SAkhilesh Sanikop namespace {
31*09537850SAkhilesh Sanikop
32*09537850SAkhilesh Sanikop constexpr int kRows = 50;
33*09537850SAkhilesh Sanikop constexpr int kColumns = 200;
34*09537850SAkhilesh Sanikop
TEST(Array2dViewTest,TestUint8)35*09537850SAkhilesh Sanikop TEST(Array2dViewTest, TestUint8) {
36*09537850SAkhilesh Sanikop uint8_t data[kRows * kColumns] = {};
37*09537850SAkhilesh Sanikop Array2DView<uint8_t> data2d(kRows, kColumns, data);
38*09537850SAkhilesh Sanikop
39*09537850SAkhilesh Sanikop // Verify data.
40*09537850SAkhilesh Sanikop data[kColumns] = 100;
41*09537850SAkhilesh Sanikop data[kColumns + 1] = 101;
42*09537850SAkhilesh Sanikop data[kColumns * 2 + 10] = 210;
43*09537850SAkhilesh Sanikop data[kColumns * 2 + 40] = 240;
44*09537850SAkhilesh Sanikop EXPECT_EQ(data2d[1][0], 100);
45*09537850SAkhilesh Sanikop EXPECT_EQ(data2d[1][1], 101);
46*09537850SAkhilesh Sanikop EXPECT_EQ(data2d[2][10], 210);
47*09537850SAkhilesh Sanikop EXPECT_EQ(data2d[2][40], 240);
48*09537850SAkhilesh Sanikop
49*09537850SAkhilesh Sanikop // Verify pointers.
50*09537850SAkhilesh Sanikop EXPECT_EQ(data2d[10], data + 10 * kColumns);
51*09537850SAkhilesh Sanikop }
52*09537850SAkhilesh Sanikop
TEST(Array2dViewTest,TestUint16)53*09537850SAkhilesh Sanikop TEST(Array2dViewTest, TestUint16) {
54*09537850SAkhilesh Sanikop uint16_t data[kRows * kColumns] = {};
55*09537850SAkhilesh Sanikop Array2DView<uint16_t> data2d(kRows, kColumns, data);
56*09537850SAkhilesh Sanikop
57*09537850SAkhilesh Sanikop // Verify data.
58*09537850SAkhilesh Sanikop data[kColumns] = 100;
59*09537850SAkhilesh Sanikop data[kColumns + 1] = 101;
60*09537850SAkhilesh Sanikop data[kColumns * 2 + 10] = 210;
61*09537850SAkhilesh Sanikop data[kColumns * 2 + 40] = 240;
62*09537850SAkhilesh Sanikop EXPECT_EQ(data2d[1][0], 100);
63*09537850SAkhilesh Sanikop EXPECT_EQ(data2d[1][1], 101);
64*09537850SAkhilesh Sanikop EXPECT_EQ(data2d[2][10], 210);
65*09537850SAkhilesh Sanikop EXPECT_EQ(data2d[2][40], 240);
66*09537850SAkhilesh Sanikop
67*09537850SAkhilesh Sanikop // Verify pointers.
68*09537850SAkhilesh Sanikop EXPECT_EQ(data2d[10], data + 10 * kColumns);
69*09537850SAkhilesh Sanikop }
70*09537850SAkhilesh Sanikop
TEST(Array2dViewTest,TestUint8Const)71*09537850SAkhilesh Sanikop TEST(Array2dViewTest, TestUint8Const) {
72*09537850SAkhilesh Sanikop uint8_t data[kRows * kColumns] = {};
73*09537850SAkhilesh Sanikop // Declared as const to provide a read-only view of |data|.
74*09537850SAkhilesh Sanikop const Array2DView<uint8_t> data2d(kRows, kColumns, data);
75*09537850SAkhilesh Sanikop
76*09537850SAkhilesh Sanikop // Verify data.
77*09537850SAkhilesh Sanikop data[kColumns] = 100;
78*09537850SAkhilesh Sanikop data[kColumns + 1] = 101;
79*09537850SAkhilesh Sanikop data[kColumns * 2 + 10] = 210;
80*09537850SAkhilesh Sanikop data[kColumns * 2 + 40] = 240;
81*09537850SAkhilesh Sanikop EXPECT_EQ(data2d[1][0], 100);
82*09537850SAkhilesh Sanikop EXPECT_EQ(data2d[1][1], 101);
83*09537850SAkhilesh Sanikop EXPECT_EQ(data2d[2][10], 210);
84*09537850SAkhilesh Sanikop EXPECT_EQ(data2d[2][40], 240);
85*09537850SAkhilesh Sanikop
86*09537850SAkhilesh Sanikop // Verify pointers.
87*09537850SAkhilesh Sanikop EXPECT_EQ(data2d[10], data + 10 * kColumns);
88*09537850SAkhilesh Sanikop }
89*09537850SAkhilesh Sanikop
TEST(Array2dTest,TestUint8)90*09537850SAkhilesh Sanikop TEST(Array2dTest, TestUint8) {
91*09537850SAkhilesh Sanikop Array2D<uint8_t> data2d;
92*09537850SAkhilesh Sanikop ASSERT_TRUE(data2d.Reset(kRows, kColumns, true));
93*09537850SAkhilesh Sanikop
94*09537850SAkhilesh Sanikop EXPECT_EQ(data2d.rows(), kRows);
95*09537850SAkhilesh Sanikop EXPECT_EQ(data2d.columns(), kColumns);
96*09537850SAkhilesh Sanikop
97*09537850SAkhilesh Sanikop // Verify pointers.
98*09537850SAkhilesh Sanikop for (int i = 0; i < kRows; ++i) {
99*09537850SAkhilesh Sanikop EXPECT_NE(data2d[i], nullptr);
100*09537850SAkhilesh Sanikop }
101*09537850SAkhilesh Sanikop
102*09537850SAkhilesh Sanikop // Verify data (must be zero initialized).
103*09537850SAkhilesh Sanikop for (int i = 0; i < kRows; ++i) {
104*09537850SAkhilesh Sanikop for (int j = 0; j < kColumns; ++j) {
105*09537850SAkhilesh Sanikop EXPECT_EQ(data2d[i][j], 0) << "Mismatch in [" << i << "][" << j << "]";
106*09537850SAkhilesh Sanikop }
107*09537850SAkhilesh Sanikop }
108*09537850SAkhilesh Sanikop
109*09537850SAkhilesh Sanikop // Reset to a 2d array of smaller size with zero_initialize == false.
110*09537850SAkhilesh Sanikop data2d[0][0] = 10;
111*09537850SAkhilesh Sanikop ASSERT_TRUE(data2d.Reset(kRows - 1, kColumns - 1, false));
112*09537850SAkhilesh Sanikop
113*09537850SAkhilesh Sanikop EXPECT_EQ(data2d.rows(), kRows - 1);
114*09537850SAkhilesh Sanikop EXPECT_EQ(data2d.columns(), kColumns - 1);
115*09537850SAkhilesh Sanikop
116*09537850SAkhilesh Sanikop // Verify pointers.
117*09537850SAkhilesh Sanikop for (int i = 0; i < kRows - 1; ++i) {
118*09537850SAkhilesh Sanikop EXPECT_NE(data2d[i], nullptr);
119*09537850SAkhilesh Sanikop }
120*09537850SAkhilesh Sanikop
121*09537850SAkhilesh Sanikop // Verify data (must be zero except for 0,0 because it was zero initialized in
122*09537850SAkhilesh Sanikop // the previous call to Reset).
123*09537850SAkhilesh Sanikop for (int i = 0; i < kRows - 1; ++i) {
124*09537850SAkhilesh Sanikop for (int j = 0; j < kColumns - 1; ++j) {
125*09537850SAkhilesh Sanikop if (i == 0 && j == 0) {
126*09537850SAkhilesh Sanikop EXPECT_EQ(data2d[i][j], 10) << "Mismatch in [" << i << "][" << j << "]";
127*09537850SAkhilesh Sanikop } else {
128*09537850SAkhilesh Sanikop EXPECT_EQ(data2d[i][j], 0) << "Mismatch in [" << i << "][" << j << "]";
129*09537850SAkhilesh Sanikop }
130*09537850SAkhilesh Sanikop }
131*09537850SAkhilesh Sanikop }
132*09537850SAkhilesh Sanikop
133*09537850SAkhilesh Sanikop // Reset to a 2d array of smaller size with zero_initialize == true.
134*09537850SAkhilesh Sanikop ASSERT_TRUE(data2d.Reset(kRows - 2, kColumns - 2, true));
135*09537850SAkhilesh Sanikop
136*09537850SAkhilesh Sanikop EXPECT_EQ(data2d.rows(), kRows - 2);
137*09537850SAkhilesh Sanikop EXPECT_EQ(data2d.columns(), kColumns - 2);
138*09537850SAkhilesh Sanikop
139*09537850SAkhilesh Sanikop // Verify pointers.
140*09537850SAkhilesh Sanikop for (int i = 0; i < kRows - 2; ++i) {
141*09537850SAkhilesh Sanikop EXPECT_NE(data2d[i], nullptr);
142*09537850SAkhilesh Sanikop }
143*09537850SAkhilesh Sanikop
144*09537850SAkhilesh Sanikop // Verify data (must be zero initialized).
145*09537850SAkhilesh Sanikop for (int i = 0; i < kRows - 2; ++i) {
146*09537850SAkhilesh Sanikop for (int j = 0; j < kColumns - 2; ++j) {
147*09537850SAkhilesh Sanikop EXPECT_EQ(data2d[i][j], 0) << "Mismatch in [" << i << "][" << j << "]";
148*09537850SAkhilesh Sanikop }
149*09537850SAkhilesh Sanikop }
150*09537850SAkhilesh Sanikop }
151*09537850SAkhilesh Sanikop
TEST(Array2dTest,TestUniquePtr1)152*09537850SAkhilesh Sanikop TEST(Array2dTest, TestUniquePtr1) {
153*09537850SAkhilesh Sanikop // A simple class that sets an int value to 0 in the destructor.
154*09537850SAkhilesh Sanikop class Cleaner {
155*09537850SAkhilesh Sanikop public:
156*09537850SAkhilesh Sanikop explicit Cleaner(int* value) : value_(value) {}
157*09537850SAkhilesh Sanikop ~Cleaner() { *value_ = 0; }
158*09537850SAkhilesh Sanikop
159*09537850SAkhilesh Sanikop private:
160*09537850SAkhilesh Sanikop int* value_;
161*09537850SAkhilesh Sanikop };
162*09537850SAkhilesh Sanikop int value = 100;
163*09537850SAkhilesh Sanikop Array2D<std::unique_ptr<Cleaner>> data2d;
164*09537850SAkhilesh Sanikop ASSERT_TRUE(data2d.Reset(4, 4, true));
165*09537850SAkhilesh Sanikop data2d[0][0].reset(new (std::nothrow) Cleaner(&value));
166*09537850SAkhilesh Sanikop EXPECT_EQ(value, 100);
167*09537850SAkhilesh Sanikop // Reset to a smaller size. Depending on the implementation, the data_ buffer
168*09537850SAkhilesh Sanikop // may or may not be reused.
169*09537850SAkhilesh Sanikop ASSERT_TRUE(data2d.Reset(2, 2, true));
170*09537850SAkhilesh Sanikop // Reset to a much larger size. The data_ buffer will be reallocated.
171*09537850SAkhilesh Sanikop ASSERT_TRUE(data2d.Reset(32, 32, true));
172*09537850SAkhilesh Sanikop // The destructors of all elements in the former data_ buffer should have
173*09537850SAkhilesh Sanikop // been invoked.
174*09537850SAkhilesh Sanikop EXPECT_EQ(value, 0);
175*09537850SAkhilesh Sanikop }
176*09537850SAkhilesh Sanikop
TEST(Array2dTest,TestUniquePtr2)177*09537850SAkhilesh Sanikop TEST(Array2dTest, TestUniquePtr2) {
178*09537850SAkhilesh Sanikop // A simple class that sets an int value to 0 in the destructor.
179*09537850SAkhilesh Sanikop class Cleaner {
180*09537850SAkhilesh Sanikop public:
181*09537850SAkhilesh Sanikop explicit Cleaner(int* value) : value_(value) {}
182*09537850SAkhilesh Sanikop ~Cleaner() { *value_ = 0; }
183*09537850SAkhilesh Sanikop
184*09537850SAkhilesh Sanikop private:
185*09537850SAkhilesh Sanikop int* value_;
186*09537850SAkhilesh Sanikop };
187*09537850SAkhilesh Sanikop int value1 = 100;
188*09537850SAkhilesh Sanikop int value2 = 200;
189*09537850SAkhilesh Sanikop Array2D<std::unique_ptr<Cleaner>> data2d;
190*09537850SAkhilesh Sanikop ASSERT_TRUE(data2d.Reset(4, 4, false));
191*09537850SAkhilesh Sanikop data2d[0][0].reset(new (std::nothrow) Cleaner(&value1));
192*09537850SAkhilesh Sanikop data2d[3][3].reset(new (std::nothrow) Cleaner(&value2));
193*09537850SAkhilesh Sanikop EXPECT_EQ(value1, 100);
194*09537850SAkhilesh Sanikop EXPECT_EQ(value2, 200);
195*09537850SAkhilesh Sanikop // Reset to a smaller size. Whether or not the data_ buffer is reused, the
196*09537850SAkhilesh Sanikop // destructors of all existing elements should be invoked.
197*09537850SAkhilesh Sanikop ASSERT_TRUE(data2d.Reset(2, 2, false));
198*09537850SAkhilesh Sanikop EXPECT_EQ(value1, 0);
199*09537850SAkhilesh Sanikop EXPECT_EQ(value2, 0);
200*09537850SAkhilesh Sanikop }
201*09537850SAkhilesh Sanikop
202*09537850SAkhilesh Sanikop // Shows that std::is_standard_layout is not relevant to the default
203*09537850SAkhilesh Sanikop // initialization vs. value initialization issue, but std::is_trivial is.
TEST(Array2dTest,TestStructInit)204*09537850SAkhilesh Sanikop TEST(Array2dTest, TestStructInit) {
205*09537850SAkhilesh Sanikop // Make one data member private so that this struct does not have a standard
206*09537850SAkhilesh Sanikop // layout. This also makes the struct not a POD type.
207*09537850SAkhilesh Sanikop struct Point {
208*09537850SAkhilesh Sanikop int x;
209*09537850SAkhilesh Sanikop int Y() const { return y; }
210*09537850SAkhilesh Sanikop
211*09537850SAkhilesh Sanikop private:
212*09537850SAkhilesh Sanikop int y;
213*09537850SAkhilesh Sanikop };
214*09537850SAkhilesh Sanikop
215*09537850SAkhilesh Sanikop EXPECT_TRUE(std::is_trivial<Point>::value);
216*09537850SAkhilesh Sanikop EXPECT_FALSE(std::is_standard_layout<Point>::value);
217*09537850SAkhilesh Sanikop
218*09537850SAkhilesh Sanikop // The Point structs in this array are default initialized.
219*09537850SAkhilesh Sanikop Array2D<Point> data2d_default_init;
220*09537850SAkhilesh Sanikop ASSERT_TRUE(data2d_default_init.Reset(kRows, kColumns, false));
221*09537850SAkhilesh Sanikop // The Point structs in this array are value initialized (i.e., zero
222*09537850SAkhilesh Sanikop // initialized).
223*09537850SAkhilesh Sanikop Array2D<Point> data2d;
224*09537850SAkhilesh Sanikop ASSERT_TRUE(data2d.Reset(kRows, kColumns, true));
225*09537850SAkhilesh Sanikop
226*09537850SAkhilesh Sanikop #if LIBGAV1_MSAN
227*09537850SAkhilesh Sanikop // Use MemorySanitizer to check Reset(rows, columns, false) does not
228*09537850SAkhilesh Sanikop // initialize the memory while Reset(rows, columns, true) does.
229*09537850SAkhilesh Sanikop //
230*09537850SAkhilesh Sanikop // __msan_test_shadow(const void *x, uptr size) returns the offset of the
231*09537850SAkhilesh Sanikop // first (at least partially) poisoned byte in the range, or -1 if the whole
232*09537850SAkhilesh Sanikop // range is good.
233*09537850SAkhilesh Sanikop for (int i = 0; i < kRows; ++i) {
234*09537850SAkhilesh Sanikop EXPECT_EQ(__msan_test_shadow(data2d_default_init[i],
235*09537850SAkhilesh Sanikop sizeof(data2d_default_init[0][0]) * kColumns),
236*09537850SAkhilesh Sanikop 0);
237*09537850SAkhilesh Sanikop EXPECT_EQ(__msan_test_shadow(data2d[i], sizeof(data2d[0][0]) * kColumns),
238*09537850SAkhilesh Sanikop -1);
239*09537850SAkhilesh Sanikop for (int j = 0; j < kColumns; ++j) {
240*09537850SAkhilesh Sanikop EXPECT_EQ(data2d[i][j].x, 0);
241*09537850SAkhilesh Sanikop EXPECT_EQ(data2d[i][j].Y(), 0);
242*09537850SAkhilesh Sanikop }
243*09537850SAkhilesh Sanikop }
244*09537850SAkhilesh Sanikop #endif
245*09537850SAkhilesh Sanikop }
246*09537850SAkhilesh Sanikop
247*09537850SAkhilesh Sanikop } // namespace
248*09537850SAkhilesh Sanikop } // namespace libgav1
249