1
1
#include < stdexcept>
2
2
#include < sstream>
3
+ #include < algorithm>
3
4
#include " db-leveldb.h"
4
5
#include " types.h"
5
6
@@ -18,14 +19,20 @@ static inline std::string i64tos(int64_t i)
18
19
return os.str ();
19
20
}
20
21
22
+ // finds the first position in the list where it.x >= x
23
+ #define lower_bound_x (container, find_x ) \
24
+ std::lower_bound ((container).begin(), (container).end(), (find_x), \
25
+ [] (const vec2 &left, int16_t right) { \
26
+ return left.x < right; \
27
+ })
21
28
22
29
DBLevelDB::DBLevelDB (const std::string &mapdir)
23
30
{
24
31
leveldb::Options options;
25
32
options.create_if_missing = false ;
26
33
leveldb::Status status = leveldb::DB::Open (options, mapdir + " map.db" , &db);
27
34
if (!status.ok ()) {
28
- throw std::runtime_error (std::string (" Failed to open Database : " ) + status.ToString ());
35
+ throw std::runtime_error (std::string (" Failed to open database : " ) + status.ToString ());
29
36
}
30
37
31
38
/* LevelDB is a dumb key-value store, so the only optimization we can do
@@ -41,18 +48,24 @@ DBLevelDB::~DBLevelDB()
41
48
}
42
49
43
50
44
- std::vector<BlockPos> DBLevelDB::getBlockPos (BlockPos min, BlockPos max)
51
+ std::vector<BlockPos> DBLevelDB::getBlockPosXZ (BlockPos min, BlockPos max)
45
52
{
46
53
std::vector<BlockPos> res;
47
54
for (const auto &it : posCache) {
48
- if (it.first < min.z || it.first >= max.z )
55
+ const int16_t zpos = it.first ;
56
+ if (zpos < min.z || zpos >= max.z )
49
57
continue ;
50
- for (auto pos2 : it.second ) {
51
- if (pos2.first < min.x || pos2.first >= max.x )
58
+ auto it2 = lower_bound_x (it.second , min.x );
59
+ for (; it2 != it.second .end (); it2++) {
60
+ const auto &pos2 = *it2;
61
+ if (pos2.x >= max.x )
62
+ break ; // went past
63
+ if (pos2.y < min.y || pos2.y >= max.y )
52
64
continue ;
53
- if (pos2.second < min.y || pos2.second >= max.y )
65
+ // skip duplicates
66
+ if (!res.empty () && res.back ().x == pos2.x && res.back ().z == zpos)
54
67
continue ;
55
- res.emplace_back (pos2.first , pos2.second , it. first );
68
+ res.emplace_back (pos2.x , pos2.y , zpos );
56
69
}
57
70
}
58
71
return res;
@@ -61,14 +74,17 @@ std::vector<BlockPos> DBLevelDB::getBlockPos(BlockPos min, BlockPos max)
61
74
62
75
void DBLevelDB::loadPosCache ()
63
76
{
64
- leveldb::Iterator * it = db->NewIterator (leveldb::ReadOptions ());
77
+ leveldb::Iterator *it = db->NewIterator (leveldb::ReadOptions ());
65
78
for (it->SeekToFirst (); it->Valid (); it->Next ()) {
66
79
int64_t posHash = stoi64 (it->key ().ToString ());
67
80
BlockPos pos = decodeBlockPos (posHash);
68
81
69
82
posCache[pos.z ].emplace_back (pos.x , pos.y );
70
83
}
71
84
delete it;
85
+
86
+ for (auto &it : posCache)
87
+ std::sort (it.second .begin (), it.second .end ());
72
88
}
73
89
74
90
@@ -81,13 +97,18 @@ void DBLevelDB::getBlocksOnXZ(BlockList &blocks, int16_t x, int16_t z,
81
97
auto it = posCache.find (z);
82
98
if (it == posCache.cend ())
83
99
return ;
84
- for (auto pos2 : it->second ) {
85
- if (pos2.first != x)
86
- continue ;
87
- if (pos2.second < min_y || pos2.second >= max_y)
100
+ auto it2 = lower_bound_x (it->second , x);
101
+ if (it2 == it->second .end () || it2->x != x)
102
+ return ;
103
+ // it2 is now pointing to a contigous part where it2->x == x
104
+ for (; it2 != it->second .end (); it2++) {
105
+ const auto &pos2 = *it2;
106
+ if (pos2.x != x)
107
+ break ; // went past
108
+ if (pos2.y < min_y || pos2.y >= max_y)
88
109
continue ;
89
110
90
- BlockPos pos (x, pos2.second , z);
111
+ BlockPos pos (x, pos2.y , z);
91
112
status = db->Get (leveldb::ReadOptions (), i64tos (encodeBlockPos (pos)), &datastr);
92
113
if (status.ok ()) {
93
114
blocks.emplace_back (
0 commit comments