34f4d7f4ad
Reviewed-by: stefank, aboldtch, tschatzl
332 lines
12 KiB
C++
332 lines
12 KiB
C++
/*
|
|
* Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved.
|
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
|
*
|
|
* This code is free software; you can redistribute it and/or modify it
|
|
* under the terms of the GNU General Public License version 2 only, as
|
|
* published by the Free Software Foundation.
|
|
*
|
|
* This code is distributed in the hope that it will be useful, but WITHOUT
|
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
|
* version 2 for more details (a copy is included in the LICENSE file that
|
|
* accompanied this code).
|
|
*
|
|
* You should have received a copy of the GNU General Public License version
|
|
* 2 along with this work; if not, write to the Free Software Foundation,
|
|
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
|
*
|
|
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
|
* or visit www.oracle.com if you need additional information or have any
|
|
* questions.
|
|
*
|
|
*/
|
|
|
|
#include "precompiled.hpp"
|
|
#include "utilities/align.hpp"
|
|
#include "utilities/bitMap.inline.hpp"
|
|
#include "utilities/debug.hpp"
|
|
#include "utilities/globalDefinitions.hpp"
|
|
#include "unittest.hpp"
|
|
|
|
using idx_t = BitMap::idx_t;
|
|
using bm_word_t = BitMap::bm_word_t;
|
|
|
|
static const idx_t BITMAP_SIZE = 1024;
|
|
static const idx_t BITMAP_WORD_SIZE = align_up(BITMAP_SIZE, BitsPerWord) / BitsPerWord;
|
|
|
|
|
|
static void test_iterate_step(const BitMap& map,
|
|
idx_t index,
|
|
const idx_t* positions,
|
|
size_t positions_index,
|
|
size_t positions_size) {
|
|
ASSERT_LT(positions_index, positions_size);
|
|
ASSERT_EQ(index, positions[positions_index]);
|
|
ASSERT_TRUE(map.at(index));
|
|
}
|
|
|
|
// Test lambda returning void.
|
|
static void test_iterate_lambda(const BitMap& map,
|
|
const idx_t* positions,
|
|
size_t positions_size) {
|
|
SCOPED_TRACE("iterate with lambda");
|
|
size_t positions_index = 0;
|
|
auto f = [&](idx_t i) {
|
|
test_iterate_step(map, i, positions, positions_index++, positions_size);
|
|
};
|
|
ASSERT_TRUE(map.iterate(f));
|
|
ASSERT_EQ(positions_index, positions_size);
|
|
}
|
|
|
|
static void test_reverse_iterate_lambda(const BitMap& map,
|
|
const idx_t* positions,
|
|
size_t positions_size) {
|
|
SCOPED_TRACE("reverse iterate with lambda");
|
|
size_t positions_index = positions_size;
|
|
auto f = [&](idx_t i) {
|
|
test_iterate_step(map, i, positions, --positions_index, positions_size);
|
|
};
|
|
ASSERT_TRUE(map.reverse_iterate(f));
|
|
ASSERT_EQ(positions_index, 0u);
|
|
}
|
|
|
|
|
|
struct TestBitMapIterationData {
|
|
const BitMap& _map;
|
|
const idx_t* _positions;
|
|
size_t _positions_index;
|
|
size_t _positions_size;
|
|
|
|
TestBitMapIterationData(const BitMap& map,
|
|
const idx_t* positions,
|
|
size_t positions_index,
|
|
size_t positions_size)
|
|
: _map(map),
|
|
_positions(positions),
|
|
_positions_index(positions_index),
|
|
_positions_size(positions_size)
|
|
{}
|
|
|
|
void test(idx_t index) const {
|
|
test_iterate_step(_map, index, _positions, _positions_index, _positions_size);
|
|
}
|
|
};
|
|
|
|
// Test closure returning bool. Also tests lambda returning bool.
|
|
static void test_iterate_closure(const BitMap& map,
|
|
const idx_t* positions,
|
|
size_t positions_size) {
|
|
SCOPED_TRACE("iterate with BitMapClosure");
|
|
struct Closure : public BitMapClosure {
|
|
TestBitMapIterationData _data;
|
|
|
|
Closure(const BitMap& map, const idx_t* positions, size_t positions_size)
|
|
: _data(map, positions, 0, positions_size)
|
|
{}
|
|
|
|
bool do_bit(idx_t i) override {
|
|
_data.test(i);
|
|
_data._positions_index += 1;
|
|
return true;
|
|
}
|
|
} closure{map, positions, positions_size};
|
|
ASSERT_TRUE(map.iterate(&closure));
|
|
ASSERT_EQ(closure._data._positions_index, positions_size);
|
|
}
|
|
|
|
static void test_reverse_iterate_closure(const BitMap& map,
|
|
const idx_t* positions,
|
|
size_t positions_size) {
|
|
SCOPED_TRACE("reverse iterate with BitMapClosure");
|
|
struct Closure : public BitMapClosure {
|
|
TestBitMapIterationData _data;
|
|
|
|
Closure(const BitMap& map, const idx_t* positions, size_t positions_size)
|
|
: _data(map, positions, positions_size, positions_size)
|
|
{}
|
|
|
|
bool do_bit(idx_t i) override {
|
|
_data._positions_index -= 1;
|
|
_data.test(i);
|
|
return true;
|
|
}
|
|
} closure{map, positions, positions_size};
|
|
ASSERT_TRUE(map.reverse_iterate(&closure));
|
|
ASSERT_EQ(closure._data._positions_index, 0u);
|
|
}
|
|
|
|
// Test closure returning void. Also tests lambda returning bool.
|
|
static void test_iterate_non_closure(const BitMap& map,
|
|
const idx_t* positions,
|
|
size_t positions_size) {
|
|
SCOPED_TRACE("iterate with non-BitMapClosure");
|
|
struct Closure {
|
|
TestBitMapIterationData _data;
|
|
Closure(const BitMap& map, const idx_t* positions, size_t positions_size)
|
|
: _data(map, positions, 0, positions_size)
|
|
{}
|
|
|
|
void do_bit(idx_t i) {
|
|
_data.test(i);
|
|
_data._positions_index += 1;
|
|
}
|
|
} closure{map, positions, positions_size};
|
|
ASSERT_TRUE(map.iterate(&closure));
|
|
ASSERT_EQ(closure._data._positions_index, positions_size);
|
|
}
|
|
|
|
static void test_reverse_iterate_non_closure(const BitMap& map,
|
|
const idx_t* positions,
|
|
size_t positions_size) {
|
|
SCOPED_TRACE("reverse iterate with non-BitMapClosure");
|
|
struct Closure {
|
|
TestBitMapIterationData _data;
|
|
Closure(const BitMap& map, const idx_t* positions, size_t positions_size)
|
|
: _data(map, positions, positions_size, positions_size)
|
|
{}
|
|
|
|
void do_bit(idx_t i) {
|
|
_data._positions_index -= 1;
|
|
_data.test(i);
|
|
}
|
|
} closure{map, positions, positions_size};
|
|
ASSERT_TRUE(map.reverse_iterate(&closure));
|
|
ASSERT_EQ(closure._data._positions_index, 0u);
|
|
}
|
|
|
|
static void test_iterator(const BitMap& map,
|
|
const idx_t* positions,
|
|
size_t positions_size) {
|
|
SCOPED_TRACE("iterate with Iterator");
|
|
size_t positions_index = 0;
|
|
for (BitMap::Iterator it{map}; !it.is_empty(); it.step()) {
|
|
test_iterate_step(map, it.index(), positions, positions_index++, positions_size);
|
|
}
|
|
ASSERT_EQ(positions_index, positions_size);
|
|
}
|
|
|
|
static void test_reverse_iterator(const BitMap& map,
|
|
const idx_t* positions,
|
|
size_t positions_size) {
|
|
SCOPED_TRACE("reverse iterate with Iterator");
|
|
size_t positions_index = positions_size;
|
|
for (BitMap::ReverseIterator it{map}; !it.is_empty(); it.step()) {
|
|
test_iterate_step(map, it.index(), positions, --positions_index, positions_size);
|
|
}
|
|
ASSERT_EQ(positions_index, 0u);
|
|
}
|
|
|
|
static void test_for_loop_iterator(const BitMap& map,
|
|
const idx_t* positions,
|
|
size_t positions_size) {
|
|
SCOPED_TRACE("iterate with range-based for loop");
|
|
size_t positions_index = 0;
|
|
for (idx_t index : BitMap::Iterator(map)) {
|
|
test_iterate_step(map, index, positions, positions_index++, positions_size);
|
|
}
|
|
ASSERT_EQ(positions_index, positions_size);
|
|
}
|
|
|
|
static void test_for_loop_reverse_iterator(const BitMap& map,
|
|
const idx_t* positions,
|
|
size_t positions_size) {
|
|
SCOPED_TRACE("reverse iterate with range-based for loop");
|
|
size_t positions_index = positions_size;
|
|
for (idx_t index : BitMap::ReverseIterator(map)) {
|
|
test_iterate_step(map, index, positions, --positions_index, positions_size);
|
|
}
|
|
ASSERT_EQ(positions_index, 0u);
|
|
}
|
|
|
|
static void fill_iterate_map(BitMap& map,
|
|
const idx_t* positions,
|
|
size_t positions_size) {
|
|
map.clear_range(0, map.size());
|
|
for (size_t i = 0; i < positions_size; ++i) {
|
|
map.set_bit(positions[i]);
|
|
}
|
|
}
|
|
|
|
static void test_iterate(BitMap& map,
|
|
const idx_t* positions,
|
|
size_t positions_size) {
|
|
fill_iterate_map(map, positions, positions_size);
|
|
|
|
test_iterate_lambda(map, positions, positions_size);
|
|
test_iterate_closure(map, positions, positions_size);
|
|
test_iterate_non_closure(map, positions, positions_size);
|
|
|
|
test_reverse_iterate_lambda(map, positions, positions_size);
|
|
test_reverse_iterate_closure(map, positions, positions_size);
|
|
test_reverse_iterate_non_closure(map, positions, positions_size);
|
|
|
|
test_iterator(map, positions, positions_size);
|
|
test_reverse_iterator(map, positions, positions_size);
|
|
|
|
test_for_loop_iterator(map, positions, positions_size);
|
|
test_for_loop_reverse_iterator(map, positions, positions_size);
|
|
}
|
|
|
|
TEST(BitMap, iterate_empty) {
|
|
bm_word_t test_data[BITMAP_WORD_SIZE];
|
|
BitMapView test_map{test_data, BITMAP_SIZE};
|
|
idx_t positions[1] = {};
|
|
test_iterate(test_map, positions, 0);
|
|
}
|
|
|
|
TEST(BitMap, iterate_with_endpoints) {
|
|
bm_word_t test_data[BITMAP_WORD_SIZE];
|
|
BitMapView test_map{test_data, BITMAP_SIZE};
|
|
idx_t positions[] = { 0, 2, 6, 31, 61, 131, 247, 578, BITMAP_SIZE - 1 };
|
|
test_iterate(test_map, positions, ARRAY_SIZE(positions));
|
|
}
|
|
|
|
TEST(BitMap, iterate_without_endpoints) {
|
|
bm_word_t test_data[BITMAP_WORD_SIZE];
|
|
BitMapView test_map{test_data, BITMAP_SIZE};
|
|
idx_t positions[] = { 1, 2, 6, 31, 61, 131, 247, 578, BITMAP_SIZE - 2 };
|
|
test_iterate(test_map, positions, ARRAY_SIZE(positions));
|
|
}
|
|
|
|
TEST(BitMap, iterate_full) {
|
|
bm_word_t test_data[BITMAP_WORD_SIZE];
|
|
BitMapView test_map{test_data, BITMAP_SIZE};
|
|
static idx_t positions[BITMAP_SIZE]; // static to avoid large stack allocation.
|
|
for (idx_t i = 0; i < BITMAP_SIZE; ++i) {
|
|
positions[i] = i;
|
|
}
|
|
test_iterate(test_map, positions, ARRAY_SIZE(positions));
|
|
}
|
|
|
|
TEST(BitMap, iterate_early_termination) {
|
|
bm_word_t test_data[BITMAP_WORD_SIZE];
|
|
BitMapView test_map{test_data, BITMAP_SIZE};
|
|
idx_t positions[] = { 1, 2, 6, 31, 61, 131, 247, 578, BITMAP_SIZE - 2 };
|
|
size_t positions_size = ARRAY_SIZE(positions);
|
|
size_t positions_index = 0;
|
|
fill_iterate_map(test_map, positions, positions_size);
|
|
idx_t stop_at = 131;
|
|
auto f = [&](idx_t i) {
|
|
test_iterate_step(test_map, i, positions, positions_index, positions_size);
|
|
if (positions[positions_index] == stop_at) {
|
|
return false;
|
|
} else {
|
|
positions_index += 1;
|
|
return true;
|
|
}
|
|
};
|
|
ASSERT_FALSE(test_map.iterate(f));
|
|
ASSERT_LT(positions_index, positions_size);
|
|
ASSERT_EQ(positions[positions_index], stop_at);
|
|
|
|
struct Closure : public BitMapClosure {
|
|
const BitMap& _map;
|
|
const idx_t* _positions;
|
|
size_t _positions_index;
|
|
size_t _positions_size;
|
|
idx_t _stop_at;
|
|
|
|
Closure(const BitMap& map, const idx_t* positions, size_t positions_size, idx_t stop_at)
|
|
: _map(map),
|
|
_positions(positions),
|
|
_positions_index(0),
|
|
_positions_size(positions_size),
|
|
_stop_at(stop_at)
|
|
{}
|
|
|
|
bool do_bit(idx_t i) override {
|
|
test_iterate_step(_map, i, _positions, _positions_index, _positions_size);
|
|
if (_positions[_positions_index] == _stop_at) {
|
|
return false;
|
|
} else {
|
|
_positions_index += 1;
|
|
return true;
|
|
}
|
|
}
|
|
} closure{test_map, positions, positions_size, stop_at};
|
|
ASSERT_FALSE(test_map.iterate(&closure));
|
|
ASSERT_LT(closure._positions_index, positions_size);
|
|
ASSERT_EQ(positions[closure._positions_index], stop_at);
|
|
}
|