Browse Source

refactor: build group cases

master
Dnomd343 2 years ago
parent
commit
198ad1490b
  1. 2
      src/klotski_core/group/CMakeLists.txt
  2. 4
      src/klotski_core/group/block_num.cc
  3. 109
      src/klotski_core/group/build_cases.cc
  4. 113
      src/klotski_core/group/group.cc
  5. 26
      src/klotski_core/group/group.h
  6. 34
      src/klotski_core/group/size.h
  7. 70
      src/klotski_core/group/type_id.h
  8. 21
      test/CMakeLists.txt
  9. 1
      test/group/block_num.cc
  10. 34
      test/group/build_cases.cc

2
src/klotski_core/group/CMakeLists.txt

@ -1,3 +1,3 @@
cmake_minimum_required(VERSION 3.0)
add_library(group OBJECT group.cc block_num.cc)
add_library(group OBJECT group.cc build_cases.cc block_num.cc)

4
src/klotski_core/group/block_num.cc

@ -15,9 +15,11 @@ uint32_t Group::type_id(const CommonCode &common_code) {
}
uint32_t Group::type_id(const block_num_t &block_num) {
/// flag -> ... 0000 0xxx 0xxx xxxx
/// n_x2x n_2x1 n_1x1
auto n_x2x = block_num.n_1x2 + block_num.n_2x1;
auto flag = (n_x2x << 8) | (block_num.n_2x1 << 4) | block_num.n_1x1;
return std::lower_bound(TYPE_ID_INDEX, TYPE_ID_INDEX + 204, flag) - TYPE_ID_INDEX;
return std::lower_bound(TYPE_ID_INDEX, TYPE_ID_INDEX + TYPE_ID_LIMIT, flag) - TYPE_ID_INDEX;
}
Group::block_num_t Group::block_num(uint32_t type_id) {

109
src/klotski_core/group/build_cases.cc

@ -0,0 +1,109 @@
#include <queue>
#include "core.h"
#include "group.h"
#include "common.h"
#include "type_id.h"
#include "common_code.h"
#include "absl/container/flat_hash_map.h"
namespace klotski {
using Common::check_range;
using Common::range_reverse;
std::vector<CommonCode> Group::all_cases(uint32_t type_id) {
auto tmp = block_num(type_id);
std::vector<uint32_t> ranges; // basic ranges of type_id
BasicRanges::generate(ranges, { // generate target ranges
.n1 = 16 - tmp.n_1x1 - (tmp.n_1x2 + tmp.n_2x1) * 2, /// space -> 00
.n2 = tmp.n_1x2, /// 1x2 -> 01
.n3 = tmp.n_2x1, /// 2x1 -> 10
.n4 = tmp.n_1x1, /// 1x1 -> 11
});
for (auto &range : ranges) {
range = range_reverse(range); // basic ranges reversed
}
std::vector<CommonCode> all_cases;
all_cases.reserve(TYPE_ID_SIZE[type_id]);
for (uint64_t head = 0; head < 15; ++head) { // address of 2x2 block
/// head -> 0/1/2 / 4/5/6 / 8/9/10 / 12/13/14
if ((head & 0b11) == 0b11) {
++head; // skip invalid address
}
/// head(4-bit) + basic-range(32-bit) --check--> valid cases
for (auto &&range : ranges) {
if (!check_range(head, range)) { // case valid
all_cases.emplace_back(CommonCode::unsafe_create(
head << 32 | range_reverse(range) // release valid cases
));
}
}
}
return all_cases;
}
std::vector<RawCode> Group::group_cases(const RawCode &seed) {
std::queue<uint64_t> cache;
absl::flat_hash_map<uint64_t, uint64_t> cases; // <code, mask>
cases.reserve(max_group_size(seed));
cases.emplace(seed.unwrap(), 0); // without mask
cache.emplace(seed.unwrap());
auto core = Core(
[&cache, &cases](auto &&code, auto &&mask) { // callback function
auto current = cases.find(code);
if (current != cases.end()) {
current->second |= mask; // update mask
return;
}
cases.emplace(code, mask);
cache.emplace(code);
}
);
while (!cache.empty()) { // until BFS without elements
core.next_cases(cache.front(), cases.find(cache.front())->second);
cache.pop(); // case dequeue
}
auto result = std::vector<RawCode>();
result.reserve(cases.size());
for (auto &&raw_code : cases) { // export group cases
result.emplace_back(RawCode::unsafe_create(raw_code.first));
}
return result;
}
std::vector<std::vector<CommonCode>> Group::build_groups(uint32_t type_id) {
auto all_cases = Group::all_cases(type_id);
std::vector<std::vector<CommonCode>> groups;
auto min = std::min_element(all_cases.begin(), all_cases.end()); // search min CommonCode
auto first_group = Group::group_cases(min->to_raw_code()); // expand the first group
groups.emplace_back(first_group.begin(), first_group.end());
if (first_group.size() == all_cases.size()) { // only contains one group
return groups;
}
// TODO: do not insert the elements in first group
std::set<CommonCode> cases(all_cases.begin(), all_cases.end());
for (auto &&tmp : groups[0]) {
cases.erase(tmp); // remove elements in first group
}
while (!cases.empty()) {
groups.emplace_back(); // create empty vector
auto current_group = groups.end() - 1; // insert into latest
for (auto &&tmp : Group::group_cases(cases.begin()->to_raw_code())) {
auto common_code = tmp.to_common_code();
current_group->emplace_back(common_code); // insert into current group
cases.erase(common_code); // remove from global union
}
}
auto compare_func = [](const std::vector<CommonCode> &v1, const std::vector<CommonCode> &v2) {
return v1.size() > v2.size(); // sort by vector size
};
std::stable_sort(groups.begin(), groups.end(), compare_func); // using stable sort for ordered index
return groups;
}
} // namespace klotski

113
src/klotski_core/group/group.cc

@ -1,118 +1,5 @@
#include <queue>
#include <vector>
#include "core.h"
#include "group.h"
#include "absl/container/flat_hash_map.h"
#include "common.h"
#include "size.h"
#include "group_seeds.h"
namespace klotski {
using klotski::AllCases;
using klotski::BasicRanges;
using klotski::Common::check_range;
using klotski::Common::range_reverse;
std::vector<CommonCode> Group::all_cases(uint32_t type_id) {
auto tmp = block_num(type_id);
std::vector<uint32_t> ranges; // basic ranges of type_id
BasicRanges::generate(ranges, BasicRanges::generate_t { // generate target ranges
.n1 = 16 - tmp.n_1x1 - (tmp.n_1x2 + tmp.n_2x1) * 2, /// space -> 00
.n2 = tmp.n_1x2, /// 1x2 -> 01
.n3 = tmp.n_2x1, /// 2x1 -> 10
.n4 = tmp.n_1x1, /// 1x1 -> 11
});
for (auto &range : ranges) {
range = range_reverse(range); // basic ranges reversed
}
std::vector<CommonCode> all_cases;
all_cases.reserve(GROUP_ALL_CASES_SIZE[type_id]);
for (uint64_t head = 0; head < 15; ++head) { // address of 2x2 block
/// head -> 0/1/2 / 4/5/6 / 8/9/10 / 12/13/14
if ((head & 0b11) == 0b11) {
++head; // skip invalid address
}
/// head(4-bit) + basic-range(32-bit) --check--> valid cases
for (auto &&range : ranges) {
if (!check_range(head, range)) { // case valid
all_cases.emplace_back(CommonCode::unsafe_create(
head << 32 | range_reverse(range) // release valid cases
));
}
}
}
return all_cases;
}
std::vector<RawCode> Group::group_cases(const RawCode &seed) {
std::queue<uint64_t> cache;
absl::flat_hash_map<uint64_t, uint64_t> cases; // <code, mask>
cases.reserve(max_group_size(seed));
cases.emplace(seed.unwrap(), 0); // without mask
cache.emplace(seed.unwrap());
auto core = Core(
[&cache, &cases](auto &&code, auto &&mask) { // callback function
auto current = cases.find(code);
if (current != cases.end()) {
current->second |= mask; // update mask
return;
}
cases.emplace(code, mask);
cache.emplace(code);
}
);
while (!cache.empty()) { // until BFS without elements
core.next_cases(cache.front(), cases.find(cache.front())->second);
cache.pop(); // case dequeue
}
auto result = std::vector<RawCode>();
result.reserve(cases.size());
for (auto &&raw_code : cases) { // export group cases
result.emplace_back(RawCode::unsafe_create(raw_code.first));
}
return result;
}
std::vector<std::vector<CommonCode>> Group::build_groups(uint32_t type_id) {
auto all_cases = Group::all_cases(type_id);
if (all_cases.empty()) {
return {}; // type 203 -> no element
}
std::vector<std::vector<CommonCode>> groups;
auto min = std::min_element(all_cases.begin(), all_cases.end()); // search min CommonCode
auto first_group = Group::group_cases(min->to_raw_code()); // expand the first group
groups.emplace_back(first_group.begin(), first_group.end());
if (first_group.size() == all_cases.size()) { // only contains one group
return groups;
}
std::set<CommonCode> cases(all_cases.begin(), all_cases.end());
for (auto &&tmp : groups[0]) {
cases.erase(tmp); // remove elements in first group
}
while (!cases.empty()) {
groups.emplace_back(); // create empty vector
auto current_group = groups.end() - 1; // insert into latest
for (auto &&tmp : Group::group_cases(cases.begin()->to_raw_code())) {
auto common_code = tmp.to_common_code();
current_group->emplace_back(common_code); // insert into current group
cases.erase(common_code); // remove from global union
}
}
auto compare_func = [](const std::vector<CommonCode> &v1, const std::vector<CommonCode> &v2) {
return v1.size() > v2.size(); // sort by vector size
};
std::stable_sort(groups.begin(), groups.end(), compare_func); // using stable sort for ordered index
return groups;
}
} // namespace klotski

26
src/klotski_core/group/group.h

@ -6,25 +6,40 @@
namespace klotski {
const uint32_t TYPE_ID_LIMIT = 204;
const uint32_t TYPE_ID_LIMIT = 203;
class Group {
/// ---------------------------- block statistics -----------------------------
public:
/// 1. n_1x1 + (n_1x2 + n_2x1) * 2 <= 14
/// 2. (n_1x1 != 0) && (n_2x1 != 7)
struct block_num_t {
uint8_t n_1x1 = 0;
uint8_t n_1x2 = 0;
uint8_t n_2x1 = 0;
uint8_t n_1x1 = 0; /// [0, 14]
uint8_t n_1x2 = 0; /// [0, 7]
uint8_t n_2x1 = 0; /// [0, 7]
};
/// Get type_id value (0 ~ 202).
static uint32_t type_id(const RawCode &raw_code);
static uint32_t type_id(const block_num_t &block_num);
static uint32_t type_id(const CommonCode &common_code);
/// Get the number of klotski blocks.
static block_num_t block_num(uint32_t type_id);
static block_num_t block_num(const RawCode &raw_code);
static block_num_t block_num(const CommonCode &common_code);
/// ----------------------------- cases expansion -----------------------------
/// Search for all cases of the specified type_id.
static std::vector<CommonCode> all_cases(uint32_t type_id);
/// Search for all derivatives that a case can produce.
static std::vector<RawCode> group_cases(const RawCode &seed);
/// Calculate all groups in the specified type_id.
static std::vector<std::vector<CommonCode>> build_groups(uint32_t type_id);
/// ---------------------------- xxxxxxxxxxxxxxxxx ----------------------------
@ -33,10 +48,7 @@ public:
return 65535 * 8;
};
static std::vector<CommonCode> all_cases(uint32_t type_id);
static std::vector<RawCode> group_cases(const RawCode &seed);
static std::vector<std::vector<CommonCode>> build_groups(uint32_t type_id);
};

34
src/klotski_core/group/size.h

@ -1,34 +0,0 @@
#pragma once
namespace klotski {
const uint32_t GROUP_ALL_CASES_SIZE[204] = {
12, 192, 1440, 6720, 21840, 52416, 96096, 137280,
154440, 137280, 96096, 52416, 21840, 6720, 1440, 124,
1736, 11284, 45136, 124124, 248248, 372372, 425568, 372372,
248248, 124124, 45136, 11284, 132, 1848, 12012, 48048,
132132, 264264, 396396, 453024, 396396, 264264, 132132, 48048,
12012, 512, 6144, 33792, 112640, 253440, 405504, 473088,
405504, 253440, 112640, 33792, 1044, 12528, 68904, 229680,
516780, 826848, 964656, 826848, 516780, 229680, 68904, 582,
6984, 38412, 128040, 288090, 460944, 537768, 460944, 288090,
128040, 38412, 1092, 10920, 49140, 131040, 229320, 275184,
229320, 131040, 49140, 3180, 31800, 143100, 381600, 667800,
801360, 667800, 381600, 143100, 3382, 33820, 152190, 405840,
710220, 852264, 710220, 405840, 152190, 1320, 13200, 59400,
158400, 277200, 332640, 277200, 158400, 59400, 1320, 10560,
36960, 73920, 92400, 73920, 36960, 4680, 37440, 131040,
262080, 327600, 262080, 131040, 7248, 57984, 202944, 405888,
507360, 405888, 202944, 5344, 42752, 149632, 299264, 374080,
299264, 149632, 1632, 13056, 45696, 91392, 114240, 91392,
45696, 948, 5688, 14220, 18960, 14220, 3444, 20664,
51660, 68880, 51660, 7120, 42720, 106800, 142400, 106800,
7284, 43704, 109260, 145680, 109260, 4392, 26352, 65880,
87840, 65880, 1044, 6264, 15660, 20880, 15660, 396,
1584, 2376, 1260, 5040, 7560, 3084, 12336, 18504,
4288, 17152, 25728, 3196, 12784, 19176, 1836, 7344,
11016, 270, 1080, 1620, 88, 180, 626, 772,
1036, 464, 342, 0,
};
} // namespace klotski

70
src/klotski_core/group/type_id.h

@ -2,33 +2,49 @@
namespace klotski {
const uint16_t TYPE_ID_INDEX[204] = {
0, 1, 2, 3, 4, 5, 6, 7,
8, 9, 10, 11, 12, 13, 14, 256,
257, 258, 259, 260, 261, 262, 263, 264,
265, 266, 267, 268, 272, 273, 274, 275,
276, 277, 278, 279, 280, 281, 282, 283,
284, 512, 513, 514, 515, 516, 517, 518,
519, 520, 521, 522, 528, 529, 530, 531,
532, 533, 534, 535, 536, 537, 538, 544,
545, 546, 547, 548, 549, 550, 551, 552,
553, 554, 768, 769, 770, 771, 772, 773,
774, 775, 776, 784, 785, 786, 787, 788,
789, 790, 791, 792, 800, 801, 802, 803,
804, 805, 806, 807, 808, 816, 817, 818,
819, 820, 821, 822, 823, 824, 1024, 1025,
1026, 1027, 1028, 1029, 1030, 1040, 1041, 1042,
1043, 1044, 1045, 1046, 1056, 1057, 1058, 1059,
1060, 1061, 1062, 1072, 1073, 1074, 1075, 1076,
1077, 1078, 1088, 1089, 1090, 1091, 1092, 1093,
1094, 1280, 1281, 1282, 1283, 1284, 1296, 1297,
1298, 1299, 1300, 1312, 1313, 1314, 1315, 1316,
1328, 1329, 1330, 1331, 1332, 1344, 1345, 1346,
1347, 1348, 1360, 1361, 1362, 1363, 1364, 1536,
1537, 1538, 1552, 1553, 1554, 1568, 1569, 1570,
1584, 1585, 1586, 1600, 1601, 1602, 1616, 1617,
1618, 1632, 1633, 1634, 1792, 1808, 1824, 1840,
1856, 1872, 1888, 1904,
const uint16_t TYPE_ID_INDEX[203] = {
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 256,
257, 258, 259, 260, 261, 262, 263, 264, 265, 266, 267, 268, 272, 273, 274, 275,
276, 277, 278, 279, 280, 281, 282, 283, 284, 512, 513, 514, 515, 516, 517, 518,
519, 520, 521, 522, 528, 529, 530, 531, 532, 533, 534, 535, 536, 537, 538, 544,
545, 546, 547, 548, 549, 550, 551, 552, 553, 554, 768, 769, 770, 771, 772, 773,
774, 775, 776, 784, 785, 786, 787, 788, 789, 790, 791, 792, 800, 801, 802, 803,
804, 805, 806, 807, 808, 816, 817, 818, 819, 820, 821, 822, 823, 824, 1024, 1025,
1026, 1027, 1028, 1029, 1030, 1040, 1041, 1042, 1043, 1044, 1045, 1046, 1056, 1057, 1058, 1059,
1060, 1061, 1062, 1072, 1073, 1074, 1075, 1076, 1077, 1078, 1088, 1089, 1090, 1091, 1092, 1093,
1094, 1280, 1281, 1282, 1283, 1284, 1296, 1297, 1298, 1299, 1300, 1312, 1313, 1314, 1315, 1316,
1328, 1329, 1330, 1331, 1332, 1344, 1345, 1346, 1347, 1348, 1360, 1361, 1362, 1363, 1364, 1536,
1537, 1538, 1552, 1553, 1554, 1568, 1569, 1570, 1584, 1585, 1586, 1600, 1601, 1602, 1616, 1617,
1618, 1632, 1633, 1634, 1792, 1808, 1824, 1840, 1856, 1872, 1888,
};
const uint32_t TYPE_ID_SIZE[203] = {
12, 192, 1440, 6720, 21840, 52416, 96096, 137280,
154440, 137280, 96096, 52416, 21840, 6720, 1440, 124,
1736, 11284, 45136, 124124, 248248, 372372, 425568, 372372,
248248, 124124, 45136, 11284, 132, 1848, 12012, 48048,
132132, 264264, 396396, 453024, 396396, 264264, 132132, 48048,
12012, 512, 6144, 33792, 112640, 253440, 405504, 473088,
405504, 253440, 112640, 33792, 1044, 12528, 68904, 229680,
516780, 826848, 964656, 826848, 516780, 229680, 68904, 582,
6984, 38412, 128040, 288090, 460944, 537768, 460944, 288090,
128040, 38412, 1092, 10920, 49140, 131040, 229320, 275184,
229320, 131040, 49140, 3180, 31800, 143100, 381600, 667800,
801360, 667800, 381600, 143100, 3382, 33820, 152190, 405840,
710220, 852264, 710220, 405840, 152190, 1320, 13200, 59400,
158400, 277200, 332640, 277200, 158400, 59400, 1320, 10560,
36960, 73920, 92400, 73920, 36960, 4680, 37440, 131040,
262080, 327600, 262080, 131040, 7248, 57984, 202944, 405888,
507360, 405888, 202944, 5344, 42752, 149632, 299264, 374080,
299264, 149632, 1632, 13056, 45696, 91392, 114240, 91392,
45696, 948, 5688, 14220, 18960, 14220, 3444, 20664,
51660, 68880, 51660, 7120, 42720, 106800, 142400, 106800,
7284, 43704, 109260, 145680, 109260, 4392, 26352, 65880,
87840, 65880, 1044, 6264, 15660, 20880, 15660, 396,
1584, 2376, 1260, 5040, 7560, 3084, 12336, 18504,
4288, 17152, 25728, 3196, 12784, 19176, 1836, 7344,
11016, 270, 1080, 1620, 88, 180, 626, 772,
1036, 464, 342,
};
} // namespace klotski

21
test/CMakeLists.txt

@ -34,8 +34,10 @@ include_directories(../src/klotski_core/group)
################################################################################
set(TEST_BASIC_SRC utils.cc all_cases.cc)
list(TRANSFORM TEST_BASIC_SRC PREPEND "basic/")
set(TEST_BASIC_SRC
basic/utils.cc
basic/all_cases.cc
)
add_executable(test_basic ${TEST_BASIC_SRC})
target_link_libraries(test_basic PUBLIC ${TEST_DEPS} md5)
add_test(NAME basic COMMAND test_basic)
@ -53,8 +55,7 @@ add_test(NAME codec COMMAND test_codec)
################################################################################
set(TEST_CORE_SRC core.cc)
list(TRANSFORM TEST_CORE_SRC PREPEND "core/")
set(TEST_CORE_SRC core/core.cc)
add_executable(test_core ${TEST_CORE_SRC})
target_link_libraries(test_core ${TEST_DEPS})
add_test(NAME core COMMAND test_core)
@ -63,7 +64,7 @@ add_test(NAME core COMMAND test_core)
set(TEST_GROUP_SRC
group/block_num.cc
group/group.cc
group/build_cases.cc
)
add_executable(test_group ${TEST_GROUP_SRC})
target_link_libraries(test_group ${TEST_DEPS} md5 absl::flat_hash_map)
@ -71,15 +72,19 @@ add_test(NAME group COMMAND test_group)
################################################################################
set(TEST_FFI_SRC metadata.cc codec.cc all_cases.cc)
list(TRANSFORM TEST_FFI_SRC PREPEND "ffi/")
set(TEST_FFI_SRC
ffi/metadata.cc
ffi/codec.cc
ffi/all_cases.cc
)
add_executable(test_ffi ${TEST_FFI_SRC})
target_link_libraries(test_ffi ${TEST_DEPS})
add_test(NAME ffi COMMAND test_ffi)
################################################################################
include_directories(../src/klotski_core)
# TODO: update cmake configure
add_library(test_global_utils STATIC global/global_utils.cc)
set(TEST_GLOBAL_DEPS ${TEST_DEPS} test_global_utils tiny_pool)

1
test/group/block_num.cc

@ -41,6 +41,7 @@ TEST(Group, block_num) {
for (auto &&range: AllCases::fetch()[head]) {
auto common_code = CommonCode::unsafe_create(head << 32 | range);
auto tmp = Group::block_num(common_code);
EXPECT_LE(tmp.n_1x2 * 2 + tmp.n_2x1 * 2 + tmp.n_1x1, 14);
EXPECT_EQ(tmp, Group::block_num(common_code.to_raw_code()));
sprintf(buffer, "%d,%d,%d\n", tmp.n_1x2 + tmp.n_2x1, tmp.n_1x1, tmp.n_2x1);
block_num_str[head] += buffer;

34
test/group/group.cc → test/group/build_cases.cc

@ -1,12 +1,11 @@
#include <thread>
#include <algorithm>
#include "md5.h"
#include "group.h"
#include "common_code.h"
#include "gtest/gtest.h"
#include "group/size.h"
#include "group_seeds.h"
#include "group/type_id.h"
#include "group/group_seeds.h"
using klotski::Group;
using klotski::AllCases;
@ -15,41 +14,36 @@ using klotski::RawCode;
using klotski::ShortCode;
using klotski::CommonCode;
using klotski::TYPE_ID_LIMIT;
using klotski::ALL_CASES_SIZE_SUM;
using klotski::GROUP_ALL_CASES_SIZE;
using klotski::GROUP_SEEDS;
using klotski::TYPE_ID_SIZE;
using klotski::TYPE_ID_LIMIT;
using klotski::SHORT_CODE_LIMIT;
using klotski::GROUP_SEEDS;
using klotski::ALL_CASES_SIZE_SUM;
const char GROUP_INFO_MD5[] = "976bf22530085210e68a6a4e67053506";
TEST(Group, all_cases) {
std::vector<std::vector<CommonCode>> all_cases;
for (uint32_t type_id = 0; type_id < TYPE_ID_LIMIT; ++type_id) {
all_cases.emplace_back(Group::all_cases(type_id)); // build test data
}
std::vector<uint64_t> combine_cases;
combine_cases.reserve(ALL_CASES_SIZE_SUM);
std::vector<uint64_t> combine;
combine.reserve(ALL_CASES_SIZE_SUM);
for (uint32_t id = 0; id < TYPE_ID_LIMIT; ++id) {
EXPECT_EQ(all_cases[id].size(), GROUP_ALL_CASES_SIZE[id]); // verify cases number
EXPECT_EQ(all_cases[id].size(), TYPE_ID_SIZE[id]); // verify cases number
for (auto &&common_code : all_cases[id]) {
EXPECT_EQ(Group::type_id(common_code), id); // verify type id
combine_cases.emplace_back(common_code.unwrap());
combine.emplace_back(common_code.unwrap());
}
std::is_sorted(all_cases[id].begin(), all_cases[id].end()); // verify data order
}
EXPECT_EQ(combine_cases.size(), ALL_CASES_SIZE_SUM); // verify sum
EXPECT_EQ(combine.size(), ALL_CASES_SIZE_SUM); // verify sum
auto all_cases_release = AllCases::release();
std::stable_sort(combine_cases.begin(), combine_cases.end());
for (uint32_t i = 0; i < combine_cases.size(); ++i) {
EXPECT_EQ(combine_cases[i], all_cases_release[i]); // verify after combined
std::stable_sort(combine.begin(), combine.end());
for (uint32_t i = 0; i < combine.size(); ++i) {
EXPECT_EQ(combine[i], all_cases_release[i]); // verify after combined
}
}
Loading…
Cancel
Save