Skip to content

Commit

Permalink
fix #6124
Browse files Browse the repository at this point in the history
BOBW, S=8 overwhelmingly serves the common case
  • Loading branch information
rt committed Feb 2, 2019
1 parent da4dbbc commit 1a28dfa
Show file tree
Hide file tree
Showing 3 changed files with 178 additions and 109 deletions.
90 changes: 77 additions & 13 deletions rts/Sim/Misc/GroundBlockingObjectMap.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,20 +6,23 @@
#include "GlobalConstants.h"
#include "Map/ReadMap.h"
#include "Sim/Path/IPathManager.h"
#include "System/ContainerUtil.h"
#include "System/Sync/HsiehHash.h"

CGroundBlockingObjectMap groundBlockingObjectMap;

CR_BIND_TEMPLATE(BlockingMapCell, )
CR_REG_METADATA_TEMPLATE(BlockingMapCell, (
CR_BIND_TEMPLATE(CGroundBlockingObjectMap::ArrCell, )
CR_REG_METADATA_TEMPLATE(CGroundBlockingObjectMap::ArrCell, (
CR_MEMBER(arr),
CR_MEMBER(vec),
CR_MEMBER(arrSize)
CR_MEMBER(numObjs),
CR_MEMBER(vecIndx)
))

CR_BIND(CGroundBlockingObjectMap, )
CR_REG_METADATA(CGroundBlockingObjectMap, (
CR_MEMBER(groundBlockingMap)
CR_MEMBER(arrCells),
CR_MEMBER(vecCells),
CR_MEMBER(vecIndcs)
))


Expand All @@ -43,7 +46,7 @@ void CGroundBlockingObjectMap::AddGroundBlockingObject(CSolidObject* object)

for (int zSqr = zminSqr; zSqr < zmaxSqr; zSqr++) {
for (int xSqr = xminSqr; xSqr < xmaxSqr; xSqr++) {
groundBlockingMap[xSqr + zSqr * mapDims.mapx].insert_unique(object);
CellInsertUnique(zSqr * mapDims.mapx + xSqr, object);
}
}

Expand All @@ -68,11 +71,10 @@ void CGroundBlockingObjectMap::AddGroundBlockingObject(CSolidObject* object, con
for (int x = xminSqr; x < xmaxSqr; x++) {
// unit yardmaps always contain sx=UnitDef::xsize * sz=UnitDef::zsize
// cells (the unit->moveDef footprint can have different dimensions)

if ((object->GetGroundBlockingMaskAtPos({x * SQUARE_SIZE * 1.0f, 0.0f, z * SQUARE_SIZE * 1.0f}) & mask) == 0)
continue;

groundBlockingMap[x + z * mapDims.mapx].insert_unique(object);
CellInsertUnique(z * mapDims.mapx + x, object);
}
}

Expand All @@ -95,7 +97,7 @@ void CGroundBlockingObjectMap::RemoveGroundBlockingObject(CSolidObject* object)

for (int z = bz; z < bz + sz; ++z) {
for (int x = bx; x < bx + sx; ++x) {
groundBlockingMap[z * mapDims.mapx + x].erase(object);
CellErase(z * mapDims.mapx + x, object);
}
}

Expand Down Expand Up @@ -204,7 +206,6 @@ bool CGroundBlockingObjectMap::CanOpenYard(CSolidObject* yardUnit) const
return CheckYard(yardUnit, YARDMAP_YARDINV);
}


bool CGroundBlockingObjectMap::CanCloseYard(CSolidObject* yardUnit) const
{
return CheckYard(yardUnit, YARDMAP_YARD);
Expand All @@ -215,12 +216,75 @@ unsigned int CGroundBlockingObjectMap::CalcChecksum() const
{
unsigned int checksum = 666;

for (unsigned int i = 0; i < groundBlockingMap.size(); ++i) {
if (!groundBlockingMap[i].empty()) {
for (unsigned int i = 0; i < arrCells.size(); ++i) {
if (!arrCells[i].Empty())
checksum = HsiehHash(&i, sizeof(i), checksum);
}
}

return checksum;
}



bool CGroundBlockingObjectMap::CellInsertUnique(unsigned int sqr, CSolidObject* o) {
ArrCell& ac = GetArrCell(sqr);
VecCell* vc = nullptr;

if (ac.Contains(o))
return false;
if (ac.Insert(o))
return true;

// array-cell is full, spill over
if ((vc = &GetVecCell(sqr)) == &vecCells[0]) {
if (vecIndcs.empty()) {
assert(vecCells.size() > 0);
ac.SetVecIndx(vecCells.size());
vc = &spring::VectorEmplaceBack(vecCells);
} else {
ac.SetVecIndx(spring::VectorBackPop(vecIndcs));
vc = &vecCells[ac.GetVecIndx()];
}
}

return (spring::VectorInsertUnique(*vc, o, true));
}

bool CGroundBlockingObjectMap::CellErase(unsigned int sqr, CSolidObject* o) {
ArrCell& ac = GetArrCell(sqr);
VecCell* vc = nullptr;

if (ac.Erase(o)) {
if ((vc = &vecCells[ac.GetVecIndx()]) == &vecCells[0])
return true;

// never allow a hole between array and vector parts
assert(!vc->empty());
ac.Insert(spring::VectorBackPop(*vc));

goto CommonExit;
}

// failed to erase, but array-cell is not filled to capacity
// this means vc must be empty and can not contain the object
if (!ac.Full())
return false;

// otherwise object must be in vc if(f) this cell contains it
// note that vc can still point to the dummy element if ac is
// full but never overflowed, which is fine since VectorErase
// will simply return false
if (!spring::VectorErase(*(vc = &GetVecCell(sqr)), o))
return false;

CommonExit:

if (vc->empty()) {
assert(ac.GetVecIndx() != 0);
vecIndcs.push_back(ac.GetVecIndx());
ac.SetVecIndx(0);
}

return true;
}

191 changes: 98 additions & 93 deletions rts/Sim/Misc/GroundBlockingObjectMap.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,118 +10,111 @@
#include "System/creg/creg_cond.h"
#include "System/float3.h"

class CGroundBlockingObjectMap
{
CR_DECLARE_STRUCT(CGroundBlockingObjectMap)

template<typename T, size_t S> struct ArrayVector {
public:
CR_DECLARE_STRUCT(ArrayVector)

ArrayVector() = default;
ArrayVector(size_t n) { vec.reserve(n); }
ArrayVector(const ArrayVector& c) = delete;
ArrayVector(ArrayVector&& c) { *this = std::move(c); }

ArrayVector& operator = (const ArrayVector& c) = delete;
ArrayVector& operator = (ArrayVector&& c) {
arr = c.arr;
vec = std::move(c.vec);

arrSize = c.arrSize;
return *this;
}

void clear() {
arr.fill(nullptr);
vec.clear();

arrSize = 0;
}
private:
template<typename T, uint32_t S = 8> struct ArrayCell {
public:
CR_DECLARE_STRUCT(ArrayCell)

void Clear() {
arr.fill(nullptr);

T* operator [] (size_t i) const {
assert(i < size());
assert(i < arrSize || (i - arrSize) < vec.size());
numObjs = 0;
vecIndx = 0; // point to dummy
}

return ((i < arrSize)? arr[i]: vec[i - arrSize]);
}
bool InsertUnique(T* o) { return (!Contains(o) && Insert(o)); }
bool Insert(T* o) {
if (Full())
return false;

arr[numObjs++] = o;
return true;
}

size_t size() const { return (arrSize + vec.size()); }
bool Erase(T* o) {
const auto ae = arr.begin() + numObjs;
const auto it = std::find(arr.begin(), ae, o);

bool empty() const { return (arrSize == 0); }
bool contains(const T* o) const {
if (empty())
return false;
if (it == ae)
return false;

const auto ab = arr.begin();
const auto ae = arr.begin() + arrSize;
*it = arr[--numObjs];
arr[numObjs] = nullptr;
return true;
}

return ((std::find(ab, ae, o) != ae) || (std::find(vec.begin(), vec.end(), o) != vec.end()));
}
bool Empty() const { return (numObjs == 0); }
bool Full() const { return (numObjs == S); }
bool Contains(const T* o) const {
const auto ab = arr.begin();
const auto ae = arr.begin() + numObjs;

bool insert_unique(T* o) { return (!contains(o) && insert(o)); }
bool insert(T* o) {
if (arrSize < S) {
arr[arrSize++] = o;
} else {
vec.push_back(o);
return (std::find(ab, ae, o) != ae);
}
return true;
}

bool erase(T* o) {
const auto ae = arr.begin() + arrSize;
const auto it = std::find(arr.begin(), ae, o);
T* operator [] (size_t i) const { return arr[i]; }

if (it != ae) {
if (vec.empty()) {
*it = arr[--arrSize];
arr[arrSize] = nullptr;
} else {
// never allow a hole between array and vector parts
*it = vec.back();
vec.pop_back();
}
uint32_t GetNumObjs() const { return numObjs; }
uint32_t GetVecIndx() const { return vecIndx; }
uint32_t SetVecIndx(uint32_t i) { return (vecIndx = i); }

private:
uint32_t numObjs = 0;
uint32_t vecIndx = 0;

return true;
}
std::array<T*, S> arr;
};

const auto jt = std::find(vec.begin(), vec.end(), o);
typedef ArrayCell<CSolidObject> ArrCell;
typedef std::vector<CSolidObject*> VecCell;

if (jt != vec.end()) {
*jt = vec.back();
vec.pop_back();
return true;
public:
struct BlockingMapCell {
public:
BlockingMapCell() = delete;
BlockingMapCell(const ArrCell& ac, const VecCell& vc): arrCell(ac), vecCell(vc) {
}

return false;
}
CSolidObject* operator [] (size_t i) const {
assert(i < size());
assert(i < arrCell.GetNumObjs() || (i - arrCell.GetNumObjs()) < vecCell.size());

public:
// how many objects currently exist in arr; vec will
// always be empty if this is smaller than arr.size()
size_t arrSize = 0;
return ((i < arrCell.GetNumObjs())? arrCell[i]: vecCell[i - arrCell.GetNumObjs()]);
}

std::array<T*, S> arr;
std::vector<T*> vec;
};
size_t size() const { return (arrCell.GetNumObjs() + vecCell.size()); }
bool empty() const { return (arrCell.Empty()); }

private:
const ArrCell& arrCell;
const VecCell& vecCell;
};


typedef ArrayVector<CSolidObject, 16> BlockingMapCell;
typedef std::vector<BlockingMapCell> BlockingMap;
void Init(unsigned int numSquares) {
arrCells.resize(numSquares);
vecCells.reserve(32);
vecIndcs.reserve(32);

class CGroundBlockingObjectMap
{
CR_DECLARE_STRUCT(CGroundBlockingObjectMap)

public:
void Init(unsigned int numSquares) { groundBlockingMap.resize(numSquares); }
// add dummy
if (vecCells.empty())
vecCells.emplace_back();
}
void Kill() {
// reuse inner vectors when reloading
// groundBlockingMap.clear();
for (BlockingMapCell& v: groundBlockingMap) {
// vecCells.clear();
for (auto& v: arrCells) {
v.Clear();
}
for (auto& v: vecCells) {
v.clear();
}

vecIndcs.clear();
}

unsigned int CalcChecksum() const;
Expand Down Expand Up @@ -156,27 +149,39 @@ class CGroundBlockingObjectMap
bool GroundBlocked(const float3& pos, const CSolidObject* ignoreObj) const;

bool ObjectInCell(unsigned int mapSquare, const CSolidObject* obj) const {
if (mapSquare >= groundBlockingMap.size())
if (mapSquare >= arrCells.size())
return false;

return (groundBlockingMap[mapSquare].contains(obj));
}
const ArrCell& ac = GetArrCell(mapSquare);
const VecCell* vc = nullptr;

if (ac.Contains(obj))
return true;

const BlockingMapCell& GetCellUnsafeConst(unsigned int mapSquare) const {
assert(mapSquare < groundBlockingMap.size());
return groundBlockingMap[mapSquare];
return (((vc = &GetVecCell(mapSquare)) != &vecCells[0]) && (std::find(vc->begin(), vc->end(), obj) != vc->end()));
}

BlockingMapCell& GetCellUnsafe(unsigned int mapSquare) {
return (const_cast<BlockingMapCell&>(GetCellUnsafeConst(mapSquare)));

BlockingMapCell GetCellUnsafeConst(unsigned int mapSquare) const {
assert(mapSquare < arrCells.size());
return {GetArrCell(mapSquare), GetVecCell(mapSquare)};
}

private:
bool CheckYard(CSolidObject* yardUnit, const YardMapStatus& mask) const;

const ArrCell& GetArrCell(unsigned int mapSquare) const { return arrCells[mapSquare] ; }
ArrCell& GetArrCell(unsigned int mapSquare) { return arrCells[mapSquare] ; }
const VecCell& GetVecCell(unsigned int mapSquare) const { return vecCells[ arrCells[mapSquare].GetVecIndx() ]; }
VecCell& GetVecCell(unsigned int mapSquare) { return vecCells[ arrCells[mapSquare].GetVecIndx() ]; }

bool CellInsertUnique(unsigned int sqr, CSolidObject* o);
bool CellErase(unsigned int sqr, CSolidObject* o);

private:
BlockingMap groundBlockingMap;
std::vector<ArrCell> arrCells;
std::vector<VecCell> vecCells;
std::vector<uint32_t> vecIndcs;
};

extern CGroundBlockingObjectMap groundBlockingObjectMap;
Expand Down
Loading

0 comments on commit 1a28dfa

Please sign in to comment.