+ ret[i] = k;
+ }
+ return ret;
+}
+
+int main(int argc, char **argv)
+{
+ int num_buckets = atoi(argv[2]);
+ mtbl_reader** mtbls = new mtbl_reader*[num_buckets];
+ const mtbl_source** srcs = new const mtbl_source*[num_buckets];
+ for (int i = 0; i < num_buckets; ++i) {
+ mtbls[i] = NULL;
+ srcs[i] = NULL;
+ }
+
+ while (!feof(stdin)) {
+ string bpfen = read_hex_line(stdin);
+ if (bpfen.empty()) {
+ break;
+ }
+ string prev_pos_hash = read_hex_line(stdin);
+
+ string searchkey = bpfen + prev_pos_hash;
+ int bucket = hash_key_to_bucket(searchkey.data(), searchkey.size(), num_buckets);
+ if (mtbls[bucket] == NULL) {
+ char filename[256];
+ snprintf(filename, sizeof(filename), "%s.part%04d", argv[1], bucket);
+
+ mtbls[bucket] = mtbl_reader_init(filename, NULL);
+ srcs[bucket] = mtbl_reader_source(mtbls[bucket]);
+ }
+
+ // Give back the hash of the position to be kind to the user
+ uint16_t board_hash = util::Hash32(bpfen.data(), bpfen.size());
+ printf("%d\n", board_hash);
+
+ mtbl_iter *it = mtbl_source_get_prefix(srcs[bucket], (const uint8_t *)searchkey.data(), searchkey.size());
+
+ const uint8_t *key, *val;
+ size_t len_key, len_val;
+
+ Count c;
+ bool has_c = false;
+ while (mtbl_iter_next(it, &key, &len_key, &val, &len_val)) {
+ if (has_c) {
+ Count tmpc;
+ tmpc.ParseFromArray(val, len_val);
+ c = merge_count(c, tmpc);
+ } else {
+ c.ParseFromArray(val, len_val);
+ has_c = true;
+ }
+ }
+
+ if (has_c) {
+ printf("%d %d %d %d %u %ld %ld %d %ld %d %ld",
+ c.white(), c.draw(), c.black(), c.computer(),
+ c.opening_num(), c.sum_white_elo(), c.sum_black_elo(),
+ c.num_elo(), c.first_timestamp(),
+ c.pgn_file_num(),
+ c.pgn_start_position());
+ for (int j = 0; j < c.move_size(); ++j) {
+ printf(" %s", c.move(j).c_str());
+ }
+ printf("\n");
+ } else {
+ printf("-\n");
+ }
+ fflush(stdout);
+ mtbl_iter_destroy(&it);