]> git.lizzy.rs Git - minetest.git/blobdiff - src/util/areastore.cpp
Fix undeclared global in devtest (#10133)
[minetest.git] / src / util / areastore.cpp
index cf972586c495731b21d417824891c2f43ce2349d..cea526336b66b8d5ec1e16e9baf2833c8bbbc2bd 100644 (file)
@@ -54,72 +54,69 @@ AreaStore *AreaStore::getOptimalImplementation()
 #endif
 }
 
-u16 AreaStore::size() const
+const Area *AreaStore::getArea(u32 id) const
 {
-       return areas_map.size();
+       AreaMap::const_iterator it = areas_map.find(id);
+       if (it == areas_map.end())
+               return nullptr;
+       return &it->second;
 }
 
-const Area *AreaStore::getArea(u32 id) const
+void AreaStore::serialize(std::ostream &os) const
 {
-       const Area *res = NULL;
-       std::map<u32, Area>::const_iterator itr = areas_map.find(id);
-       if (itr != areas_map.end()) {
-               res = &itr->second;
+       // WARNING:
+       // Before 5.1.0-dev: version != 0 throws SerializationError
+       // After 5.1.0-dev:  version >= 5 throws SerializationError
+       // Forwards-compatibility is assumed before version 5.
+
+       writeU8(os, 0); // Serialisation version
+
+       // TODO: Compression?
+       writeU16(os, areas_map.size());
+       for (const auto &it : areas_map) {
+               const Area &a = it.second;
+               writeV3S16(os, a.minedge);
+               writeV3S16(os, a.maxedge);
+               writeU16(os, a.data.size());
+               os.write(a.data.data(), a.data.size());
        }
-       return res;
+
+       // Serialize IDs
+       for (const auto &it : areas_map)
+               writeU32(os, it.second.id);
 }
 
-#if 0
-Currently, serialisation is commented out. This is because of multiple reasons:
-1. Why do we store the areastore into a file, why not into the database?
-2. We don't use libspatial's serialisation, but we should, or perhaps not, because
-       it would remove the ability to switch. Perhaps write migration routines?
-3. Various things need fixing, e.g. the size is serialized as
-       c++ implementation defined size_t
-bool AreaStore::deserialize(std::istream &is)
+void AreaStore::deserialize(std::istream &is)
 {
        u8 ver = readU8(is);
-       if (ver != 1)
-               return false;
-       u16 count_areas = readU16(is);
-       for (u16 i = 0; i < count_areas; i++) {
-               // deserialize an area
-               Area a;
-               a.id = readU32(is);
+       // Assume forwards-compatibility before version 5
+       if (ver >= 5)
+               throw SerializationError("Unknown AreaStore "
+                               "serialization version!");
+
+       u16 num_areas = readU16(is);
+       std::vector<Area> areas;
+       for (u32 i = 0; i < num_areas; ++i) {
+               Area a(U32_MAX);
                a.minedge = readV3S16(is);
                a.maxedge = readV3S16(is);
-               a.datalen = readU16(is);
-               a.data = new char[a.datalen];
-               is.read((char *) a.data, a.datalen);
-               insertArea(a);
+               u16 data_len = readU16(is);
+               char *data = new char[data_len];
+               is.read(data, data_len);
+               a.data = std::string(data, data_len);
+               areas.emplace_back(a);
+               delete [] data;
        }
-       return true;
-}
-
 
-static bool serialize_area(void *ostr, Area *a)
-{
-       std::ostream &os = *((std::ostream *) ostr);
-       writeU32(os, a->id);
-       writeV3S16(os, a->minedge);
-       writeV3S16(os, a->maxedge);
-       writeU16(os, a->datalen);
-       os.write(a->data, a->datalen);
-
-       return false;
-}
+       bool read_ids = is.good(); // EOF for old formats
 
-
-void AreaStore::serialize(std::ostream &os) const
-{
-       // write initial data
-       writeU8(os, 1); // serialisation version
-       writeU16(os, areas_map.size()); //DANGER: not platform independent
-       forEach(&serialize_area, &os);
+       for (auto &area : areas) {
+               if (read_ids)
+                       area.id = readU32(is);
+               insertArea(&area);
+       }
 }
 
-#endif
-
 void AreaStore::invalidateCache()
 {
        if (m_cache_enabled) {
@@ -127,6 +124,19 @@ void AreaStore::invalidateCache()
        }
 }
 
+u32 AreaStore::getNextId() const
+{
+       u32 free_id = 0;
+       for (const auto &area : areas_map) {
+               if (area.first > free_id)
+                       return free_id; // Found gap
+
+               free_id = area.first + 1;
+       }
+       // End of map
+       return free_id;
+}
+
 void AreaStore::setCacheParams(bool enabled, u8 block_radius, size_t limit)
 {
        m_cache_enabled = enabled;
@@ -182,8 +192,9 @@ void AreaStore::getAreasForPos(std::vector<Area *> *result, v3s16 pos)
 
 bool VectorAreaStore::insertArea(Area *a)
 {
-       a->id = getNextId();
-       std::pair<std::map<u32, Area>::iterator, bool> res =
+       if (a->id == U32_MAX)
+               a->id = getNextId();
+       std::pair<AreaMap::iterator, bool> res =
                        areas_map.insert(std::make_pair(a->id, *a));
        if (!res.second)
                // ID is not unique
@@ -193,38 +204,29 @@ bool VectorAreaStore::insertArea(Area *a)
        return true;
 }
 
-void VectorAreaStore::reserve(size_t count)
-{
-       m_areas.reserve(count);
-}
-
 bool VectorAreaStore::removeArea(u32 id)
 {
-       std::map<u32, Area>::iterator itr = areas_map.find(id);
-       if (itr != areas_map.end()) {
-               size_t msiz = m_areas.size();
-               for (size_t i = 0; i < msiz; i++) {
-                       Area * b = m_areas[i];
-                       if (b->id == id) {
-                               areas_map.erase(itr);
-                               m_areas.erase(m_areas.begin() + i);
-                               invalidateCache();
-                               return true;
-                       }
+       AreaMap::iterator it = areas_map.find(id);
+       if (it == areas_map.end())
+               return false;
+       Area *a = &it->second;
+       for (std::vector<Area *>::iterator v_it = m_areas.begin();
+                       v_it != m_areas.end(); ++v_it) {
+               if (*v_it == a) {
+                       m_areas.erase(v_it);
+                       break;
                }
-               // we should never get here, it means we did find it in map,
-               // but not in the vector
        }
-       return false;
+       areas_map.erase(it);
+       invalidateCache();
+       return true;
 }
 
 void VectorAreaStore::getAreasForPosImpl(std::vector<Area *> *result, v3s16 pos)
 {
-       size_t msiz = m_areas.size();
-       for (size_t i = 0; i < msiz; i++) {
-               Area *b = m_areas[i];
-               if (AST_CONTAINS_PT(b, pos)) {
-                       result->push_back(b);
+       for (Area *area : m_areas) {
+               if (AST_CONTAINS_PT(area, pos)) {
+                       result->push_back(area);
                }
        }
 }
@@ -232,29 +234,14 @@ void VectorAreaStore::getAreasForPosImpl(std::vector<Area *> *result, v3s16 pos)
 void VectorAreaStore::getAreasInArea(std::vector<Area *> *result,
                v3s16 minedge, v3s16 maxedge, bool accept_overlap)
 {
-       size_t msiz = m_areas.size();
-       for (size_t i = 0; i < msiz; i++) {
-               Area * b = m_areas[i];
-               if (accept_overlap ? AST_AREAS_OVERLAP(minedge, maxedge, b) :
-                               AST_CONTAINS_AREA(minedge, maxedge, b)) {
-                       result->push_back(b);
+       for (Area *area : m_areas) {
+               if (accept_overlap ? AST_AREAS_OVERLAP(minedge, maxedge, area) :
+                               AST_CONTAINS_AREA(minedge, maxedge, area)) {
+                       result->push_back(area);
                }
        }
 }
 
-#if 0
-bool VectorAreaStore::forEach(bool (*callback)(void *args, Area *a), void *args) const
-{
-       size_t msiz = m_areas.size();
-       for (size_t i = 0; i < msiz; i++) {
-               if (callback(args, m_areas[i])) {
-                       return true;
-               }
-       }
-       return false;
-}
-#endif
-
 #if USE_SPATIAL
 
 static inline SpatialIndex::Region get_spatial_region(const v3s16 minedge,
@@ -276,11 +263,12 @@ static inline SpatialIndex::Point get_spatial_point(const v3s16 pos)
 
 bool SpatialAreaStore::insertArea(Area *a)
 {
-       a->id = getNextId();
+       if (a->id == U32_MAX)
+               a->id = getNextId();
        if (!areas_map.insert(std::make_pair(a->id, *a)).second)
                // ID is not unique
                return false;
-       m_tree->insertData(0, NULL, get_spatial_region(a->minedge, a->maxedge), a->id);
+       m_tree->insertData(0, nullptr, get_spatial_region(a->minedge, a->maxedge), a->id);
        invalidateCache();
        return true;
 }
@@ -292,6 +280,7 @@ bool SpatialAreaStore::removeArea(u32 id)
                Area *a = &itr->second;
                bool result = m_tree->deleteData(get_spatial_region(a->minedge,
                        a->maxedge), id);
+               areas_map.erase(itr);
                invalidateCache();
                return result;
        } else {
@@ -317,14 +306,6 @@ void SpatialAreaStore::getAreasInArea(std::vector<Area *> *result,
        }
 }
 
-#if 0
-bool SpatialAreaStore::forEach(bool (*callback)(void *args, Area *a), void *args) const
-{
-       // TODO ?? (this is only needed for serialisation, but libspatial has its own serialisation)
-       return false;
-}
-#endif
-
 SpatialAreaStore::~SpatialAreaStore()
 {
        delete m_tree;