• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2019 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "util/yet_another_bit_vector.h"
6 
7 #include <algorithm>
8 
9 #include "absl/algorithm/container.h"
10 #include "absl/types/span.h"
11 #include "gtest/gtest.h"
12 
13 namespace openscreen {
14 namespace {
15 
16 constexpr uint8_t kBitPatterns[] = {0b00000000, 0b11111111, 0b01010101,
17                                     0b10101010, 0b00100100, 0b01001001,
18                                     0b10010010, 0b00110110};
19 
20 // These are used for testing various vector sizes, begins/ends of ranges, etc.
21 // They will exercise both the "inlined storage" (size <= 64 case) and
22 // "heap-allocated storage" cases. These are all of the prime numbers less than
23 // 100, and also any non-negative multiples of 64 less than 192.
24 const int kTestSizes[] = {0,  1,  2,  3,  5,  7,  11, 13, 17,  19,
25                           23, 29, 31, 37, 41, 43, 47, 53, 59,  61,
26                           64, 67, 71, 73, 79, 83, 89, 97, 127, 128};
27 
28 // Returns a subspan of |kTestSizes| that contains all values in the range
29 // [first,last].
GetTestSizesInRange(int first,int last)30 absl::Span<const int> GetTestSizesInRange(int first, int last) {
31   const auto begin = absl::c_lower_bound(kTestSizes, first);
32   const auto end = absl::c_upper_bound(kTestSizes, last);
33   return absl::Span<const int>(&*begin, std::distance(begin, end));
34 }
35 
36 // Returns true if an infinitely-repeating |pattern| has a bit set at the given
37 // |position|.
IsSetInPattern(uint8_t pattern,int position)38 constexpr bool IsSetInPattern(uint8_t pattern, int position) {
39   constexpr int kRepeatPeriod = sizeof(pattern) * CHAR_BIT;
40   return !!((pattern >> (position % kRepeatPeriod)) & 1);
41 }
42 
43 // Fills an infinitely-repeating |pattern| in |v|, but only modifies the bits at
44 // and after the given |from| position.
FillWithPattern(uint8_t pattern,int from,YetAnotherBitVector * v)45 void FillWithPattern(uint8_t pattern, int from, YetAnotherBitVector* v) {
46   for (int i = from; i < v->size(); ++i) {
47     if (IsSetInPattern(pattern, i)) {
48       v->Set(i);
49     } else {
50       v->Clear(i);
51     }
52   }
53 }
54 
55 // Tests that construction and resizes initialize the vector to the correct size
56 // and set or clear all of its bits, as requested.
TEST(YetAnotherBitVectorTest,ConstructsAndResizes)57 TEST(YetAnotherBitVectorTest, ConstructsAndResizes) {
58   YetAnotherBitVector v;
59   ASSERT_EQ(v.size(), 0);
60 
61   for (int fill_set = 0; fill_set <= 1; ++fill_set) {
62     for (int size : kTestSizes) {
63       const bool all_bits_should_be_set = !!fill_set;
64       v.Resize(size, all_bits_should_be_set ? YetAnotherBitVector::SET
65                                             : YetAnotherBitVector::CLEARED);
66       ASSERT_EQ(size, v.size());
67       for (int i = 0; i < size; ++i) {
68         ASSERT_EQ(all_bits_should_be_set, v.IsSet(i));
69       }
70     }
71   }
72 }
73 
74 // Tests that individual bits can be set and cleared for various vector sizes
75 // and bit patterns.
TEST(YetAnotherBitVectorTest,SetsAndClearsIndividualBits)76 TEST(YetAnotherBitVectorTest, SetsAndClearsIndividualBits) {
77   YetAnotherBitVector v;
78   for (int fill_set = 0; fill_set <= 1; ++fill_set) {
79     for (int size : kTestSizes) {
80       v.Resize(size, fill_set ? YetAnotherBitVector::SET
81                               : YetAnotherBitVector::CLEARED);
82 
83       for (uint8_t pattern : kBitPatterns) {
84         FillWithPattern(pattern, 0, &v);
85         for (int i = 0; i < size; ++i) {
86           ASSERT_EQ(IsSetInPattern(pattern, i), v.IsSet(i));
87         }
88       }
89     }
90   }
91 }
92 
93 // Tests that the vector shifts its bits right by various amounts, for various
94 // vector sizes and bit patterns.
TEST(YetAnotherBitVectorTest,ShiftsRight)95 TEST(YetAnotherBitVectorTest, ShiftsRight) {
96   YetAnotherBitVector v;
97   for (int size : kTestSizes) {
98     v.Resize(size, YetAnotherBitVector::CLEARED);
99 
100     for (int steps_per_shift : GetTestSizesInRange(0, size)) {
101       for (uint8_t pattern : kBitPatterns) {
102         FillWithPattern(pattern, 0, &v);
103 
104         if (size == 0 || steps_per_shift == 0) {
105           v.ShiftRight(0);
106           for (int i = 0; i < size; ++i) {
107             ASSERT_EQ(IsSetInPattern(pattern, i), v.IsSet(i));
108           }
109         } else {
110           const int num_shifts = 2 * size / steps_per_shift;
111           for (int iteration = 1; iteration <= num_shifts; ++iteration) {
112             v.ShiftRight(steps_per_shift);
113             const int total_shift_amount = iteration * steps_per_shift;
114             for (int i = 0; i < size; ++i) {
115               const int original_position = i + total_shift_amount;
116               if (original_position >= size) {
117                 ASSERT_FALSE(v.IsSet(i));
118               } else {
119                 ASSERT_EQ(IsSetInPattern(pattern, original_position),
120                           v.IsSet(i));
121               }
122             }
123           }
124         }
125       }
126     }
127   }
128 }
129 
130 // Tests the FindFirstSet() operation, for various vector sizes and bit
131 // patterns.
TEST(YetAnotherBitVectorTest,FindsTheFirstBitSet)132 TEST(YetAnotherBitVectorTest, FindsTheFirstBitSet) {
133   YetAnotherBitVector v;
134 
135   // For various sizes of vector where no bits are set, the FFS operation should
136   // always return size().
137   for (int size : kTestSizes) {
138     v.Resize(size, YetAnotherBitVector::CLEARED);
139     ASSERT_EQ(size, v.FindFirstSet());
140   }
141 
142   // For various sizes of vector where only one bit is set, the FFS operation
143   // should always return the position of that bit.
144   for (int size : kTestSizes) {
145     v.Resize(size, YetAnotherBitVector::CLEARED);
146 
147     for (int position_plus_one : GetTestSizesInRange(1, size)) {
148       const int position = position_plus_one - 1;
149       v.Set(position);
150       ASSERT_EQ(position, v.FindFirstSet());
151       v.Clear(position);
152     }
153   }
154 
155   // For various sizes of vector where a pattern of bits are set, the FFS
156   // operation should always return the first one set.
157   for (int size : kTestSizes) {
158     v.Resize(size, YetAnotherBitVector::CLEARED);
159 
160     for (int position_plus_one : GetTestSizesInRange(1, size)) {
161       const int position = position_plus_one - 1;
162       v.ClearAll();
163       v.Set(position);
164       for (uint8_t pattern : kBitPatterns) {
165         FillWithPattern(pattern, position_plus_one, &v);
166         ASSERT_EQ(position, v.FindFirstSet());
167       }
168       v.Clear(position);
169     }
170   }
171 }
172 
173 // Tests the CountBitsSet() operation, for various vector sizes, bit patterns,
174 // and ranges of bits being counted.
TEST(YetAnotherBitVector,CountsTheNumberOfBitsSet)175 TEST(YetAnotherBitVector, CountsTheNumberOfBitsSet) {
176   YetAnotherBitVector v;
177 
178   // For various sizes of vector where no bits are set, the operation should
179   // always return zero for any range.
180   for (int size : kTestSizes) {
181     v.Resize(size, YetAnotherBitVector::CLEARED);
182     for (int begin : GetTestSizesInRange(0, size)) {
183       for (int end : GetTestSizesInRange(begin, size)) {
184         ASSERT_EQ(0, v.CountBitsSet(begin, end));
185       }
186     }
187   }
188 
189   // For various sizes of vector where all bits are set, the operation should
190   // always return the length of the range (or zero for invalid ranges).
191   for (int size : kTestSizes) {
192     v.Resize(size, YetAnotherBitVector::SET);
193     for (int begin : GetTestSizesInRange(0, size)) {
194       for (int end : GetTestSizesInRange(begin, size)) {
195         ASSERT_EQ(end - begin, v.CountBitsSet(begin, end));
196       }
197     }
198   }
199 
200   // Test various sizes of vector where various patterns of bits are set.
201   for (int size : kTestSizes) {
202     v.Resize(size, YetAnotherBitVector::CLEARED);
203     for (uint8_t pattern : kBitPatterns) {
204       FillWithPattern(pattern, 0, &v);
205 
206       for (int begin : GetTestSizesInRange(0, size)) {
207         for (int end : GetTestSizesInRange(begin, size)) {
208           // Note: The expected value being manually computed by examining each
209           // bit individually by calling IsSet(). Thus, this value is only good
210           // if IsSet() is working (which is tested by a different unit test).
211           int expected_popcount = 0;
212           for (int i = begin; i < end; ++i) {
213             if (v.IsSet(i)) {
214               ++expected_popcount;
215             }
216           }
217 
218           ASSERT_EQ(expected_popcount, v.CountBitsSet(begin, end));
219         }
220       }
221     }
222   }
223 }
224 
225 }  // namespace
226 }  // namespace openscreen
227