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