mirror of https://gitee.com/bigwinds/arangodb
USe smart-pointer in Priority Queue, it seems the usages have been correct everywhere (so no leaks) but memory responibility was hard to understand, should now be much simpler. (#8768)
This commit is contained in:
parent
7fd456a83b
commit
b3205dada8
|
@ -52,13 +52,14 @@ AttributeWeightShortestPathFinder::Searcher::Searcher(
|
|||
_start(start),
|
||||
_isBackward(isBackward) {}
|
||||
|
||||
void AttributeWeightShortestPathFinder::Searcher::insertNeighbor(Step* step, double newWeight) {
|
||||
void AttributeWeightShortestPathFinder::Searcher::insertNeighbor(std::unique_ptr<Step>&& step,
|
||||
double newWeight) {
|
||||
Step* s = _myInfo._pq.find(step->_vertex);
|
||||
|
||||
// Not found, so insert it:
|
||||
if (s == nullptr) {
|
||||
step->setWeight(newWeight);
|
||||
_myInfo._pq.insert(step->_vertex, step);
|
||||
_myInfo._pq.insert(step->_vertex, std::move(step));
|
||||
return;
|
||||
}
|
||||
if (!s->_done && s->weight() > newWeight) {
|
||||
|
@ -66,7 +67,6 @@ void AttributeWeightShortestPathFinder::Searcher::insertNeighbor(Step* step, dou
|
|||
std::swap(s->_edge, step->_edge);
|
||||
_myInfo._pq.lowerWeight(s->_vertex, newWeight);
|
||||
}
|
||||
delete step;
|
||||
}
|
||||
|
||||
void AttributeWeightShortestPathFinder::Searcher::lookupPeer(arangodb::velocypack::StringRef& vertex,
|
||||
|
@ -119,8 +119,9 @@ void AttributeWeightShortestPathFinder::Searcher::lookupPeer(arangodb::velocypac
|
|||
|
||||
bool AttributeWeightShortestPathFinder::Searcher::oneStep() {
|
||||
arangodb::velocypack::StringRef v;
|
||||
// Do not steal responsibility.
|
||||
Step* s = nullptr;
|
||||
bool b = _myInfo._pq.popMinimal(v, s, true);
|
||||
bool b = _myInfo._pq.popMinimal(v, s);
|
||||
|
||||
if (_pathFinder->_bingo || !b) {
|
||||
// We can leave this functino only under 2 conditions:
|
||||
|
@ -134,11 +135,13 @@ bool AttributeWeightShortestPathFinder::Searcher::oneStep() {
|
|||
|
||||
TRI_ASSERT(s != nullptr);
|
||||
|
||||
std::vector<Step*> neighbors;
|
||||
std::vector<std::unique_ptr<Step>> neighbors;
|
||||
_pathFinder->expandVertex(_isBackward, v, neighbors);
|
||||
for (Step* neighbor : neighbors) {
|
||||
insertNeighbor(neighbor, s->weight() + neighbor->weight());
|
||||
for (std::unique_ptr<Step>& neighbor : neighbors) {
|
||||
insertNeighbor(std::move(neighbor), s->weight() + neighbor->weight());
|
||||
}
|
||||
// All neighbours are moved out.
|
||||
neighbors.clear();
|
||||
lookupPeer(v, s->weight());
|
||||
|
||||
Step* s2 = _myInfo._pq.find(v);
|
||||
|
@ -170,17 +173,21 @@ bool AttributeWeightShortestPathFinder::shortestPath(arangodb::velocypack::Slice
|
|||
_bingo = false;
|
||||
_intermediateSet = false;
|
||||
|
||||
arangodb::velocypack::StringRef start = _options.cache()->persistString(arangodb::velocypack::StringRef(st));
|
||||
arangodb::velocypack::StringRef target = _options.cache()->persistString(arangodb::velocypack::StringRef(ta));
|
||||
arangodb::velocypack::StringRef start =
|
||||
_options.cache()->persistString(arangodb::velocypack::StringRef(st));
|
||||
arangodb::velocypack::StringRef target =
|
||||
_options.cache()->persistString(arangodb::velocypack::StringRef(ta));
|
||||
|
||||
// Forward with initialization:
|
||||
arangodb::velocypack::StringRef emptyVertex;
|
||||
ThreadInfo forward;
|
||||
forward._pq.insert(start, new Step(start, emptyVertex, 0, EdgeDocumentToken()));
|
||||
forward._pq.insert(start, std::make_unique<Step>(start, emptyVertex, 0,
|
||||
EdgeDocumentToken()));
|
||||
|
||||
// backward with initialization:
|
||||
ThreadInfo backward;
|
||||
backward._pq.insert(target, new Step(target, emptyVertex, 0, EdgeDocumentToken()));
|
||||
backward._pq.insert(target, std::make_unique<Step>(target, emptyVertex, 0,
|
||||
EdgeDocumentToken()));
|
||||
|
||||
// Now the searcher threads:
|
||||
Searcher forwardSearcher(this, forward, backward, start, false);
|
||||
|
@ -266,17 +273,17 @@ bool AttributeWeightShortestPathFinder::shortestPath(arangodb::velocypack::Slice
|
|||
|
||||
void AttributeWeightShortestPathFinder::inserter(
|
||||
std::unordered_map<arangodb::velocypack::StringRef, size_t>& candidates,
|
||||
std::vector<Step*>& result, arangodb::velocypack::StringRef const& s, arangodb::velocypack::StringRef const& t,
|
||||
std::vector<std::unique_ptr<Step>>& result,
|
||||
arangodb::velocypack::StringRef const& s, arangodb::velocypack::StringRef const& t,
|
||||
double currentWeight, EdgeDocumentToken&& edge) {
|
||||
auto cand = candidates.find(t);
|
||||
if (cand == candidates.end()) {
|
||||
// Add weight
|
||||
auto step = std::make_unique<Step>(t, s, currentWeight, std::move(edge));
|
||||
result.emplace_back(step.release());
|
||||
result.emplace_back(std::make_unique<Step>(t, s, currentWeight, std::move(edge)));
|
||||
candidates.emplace(t, result.size() - 1);
|
||||
} else {
|
||||
// Compare weight
|
||||
auto old = result[cand->second];
|
||||
auto& old = result[cand->second];
|
||||
auto oldWeight = old->weight();
|
||||
if (currentWeight < oldWeight) {
|
||||
old->setWeight(currentWeight);
|
||||
|
@ -286,9 +293,9 @@ void AttributeWeightShortestPathFinder::inserter(
|
|||
}
|
||||
}
|
||||
|
||||
void AttributeWeightShortestPathFinder::expandVertex(bool isBackward,
|
||||
arangodb::velocypack::StringRef const& vertex,
|
||||
std::vector<Step*>& result) {
|
||||
void AttributeWeightShortestPathFinder::expandVertex(
|
||||
bool isBackward, arangodb::velocypack::StringRef const& vertex,
|
||||
std::vector<std::unique_ptr<Step>>& result) {
|
||||
std::unique_ptr<EdgeCursor> edgeCursor;
|
||||
if (isBackward) {
|
||||
edgeCursor.reset(_options.nextReverseCursor(vertex));
|
||||
|
@ -301,14 +308,16 @@ void AttributeWeightShortestPathFinder::expandVertex(bool isBackward,
|
|||
if (edge.isString()) {
|
||||
VPackSlice doc = _options.cache()->lookupToken(eid);
|
||||
double currentWeight = _options.weightEdge(doc);
|
||||
arangodb::velocypack::StringRef other = _options.cache()->persistString(arangodb::velocypack::StringRef(edge));
|
||||
arangodb::velocypack::StringRef other =
|
||||
_options.cache()->persistString(arangodb::velocypack::StringRef(edge));
|
||||
if (other.compare(vertex) != 0) {
|
||||
inserter(candidates, result, vertex, other, currentWeight, std::move(eid));
|
||||
} else {
|
||||
inserter(candidates, result, other, vertex, currentWeight, std::move(eid));
|
||||
}
|
||||
} else {
|
||||
arangodb::velocypack::StringRef fromTmp(transaction::helpers::extractFromFromDocument(edge));
|
||||
arangodb::velocypack::StringRef fromTmp(
|
||||
transaction::helpers::extractFromFromDocument(edge));
|
||||
arangodb::velocypack::StringRef toTmp(transaction::helpers::extractToFromDocument(edge));
|
||||
arangodb::velocypack::StringRef from = _options.cache()->persistString(fromTmp);
|
||||
arangodb::velocypack::StringRef to = _options.cache()->persistString(toTmp);
|
||||
|
|
|
@ -58,8 +58,9 @@ class AttributeWeightShortestPathFinder : public ShortestPathFinder {
|
|||
arangodb::graph::EdgeDocumentToken _edge;
|
||||
bool _done;
|
||||
|
||||
Step(arangodb::velocypack::StringRef const& vert, arangodb::velocypack::StringRef const& pred,
|
||||
double weig, EdgeDocumentToken&& edge);
|
||||
Step(arangodb::velocypack::StringRef const& vert,
|
||||
arangodb::velocypack::StringRef const& pred, double weig,
|
||||
EdgeDocumentToken&& edge);
|
||||
|
||||
double weight() const { return _weight; }
|
||||
|
||||
|
@ -152,7 +153,8 @@ class AttributeWeightShortestPathFinder : public ShortestPathFinder {
|
|||
class Searcher {
|
||||
public:
|
||||
Searcher(AttributeWeightShortestPathFinder* pathFinder, ThreadInfo& myInfo,
|
||||
ThreadInfo& peerInfo, arangodb::velocypack::StringRef const& start, bool isBackward);
|
||||
ThreadInfo& peerInfo, arangodb::velocypack::StringRef const& start,
|
||||
bool isBackward);
|
||||
|
||||
public:
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -166,7 +168,7 @@ class AttributeWeightShortestPathFinder : public ShortestPathFinder {
|
|||
/// @brief Insert a neighbor to the todo list.
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void insertNeighbor(Step* step, double newWeight);
|
||||
void insertNeighbor(std::unique_ptr<Step>&& step, double newWeight);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief Lookup our current vertex in the data of our peer.
|
||||
|
@ -211,12 +213,13 @@ class AttributeWeightShortestPathFinder : public ShortestPathFinder {
|
|||
arangodb::graph::ShortestPathResult& result) override;
|
||||
|
||||
void inserter(std::unordered_map<arangodb::velocypack::StringRef, size_t>& candidates,
|
||||
std::vector<Step*>& result, arangodb::velocypack::StringRef const& s,
|
||||
std::vector<std::unique_ptr<Step>>& result,
|
||||
arangodb::velocypack::StringRef const& s,
|
||||
arangodb::velocypack::StringRef const& t, double currentWeight,
|
||||
graph::EdgeDocumentToken&& edge);
|
||||
|
||||
void expandVertex(bool isBackward, arangodb::velocypack::StringRef const& source,
|
||||
std::vector<Step*>& result);
|
||||
std::vector<std::unique_ptr<Step>>& result);
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief return the shortest path between the start and target vertex,
|
||||
|
|
|
@ -64,10 +64,10 @@ bool KShortestPathsFinder::startKShortestPathsTraversal(
|
|||
return true;
|
||||
}
|
||||
|
||||
bool KShortestPathsFinder::computeShortestPath(
|
||||
VertexRef const& start, VertexRef const& end,
|
||||
std::unordered_set<VertexRef> const& forbiddenVertices,
|
||||
std::unordered_set<Edge> const& forbiddenEdges, Path& result) {
|
||||
bool KShortestPathsFinder::computeShortestPath(VertexRef const& start, VertexRef const& end,
|
||||
std::unordered_set<VertexRef> const& forbiddenVertices,
|
||||
std::unordered_set<Edge> const& forbiddenEdges,
|
||||
Path& result) {
|
||||
bool found = false;
|
||||
Ball left(start, FORWARD);
|
||||
Ball right(end, BACKWARD);
|
||||
|
@ -91,8 +91,8 @@ bool KShortestPathsFinder::computeShortestPath(
|
|||
return found;
|
||||
}
|
||||
|
||||
void KShortestPathsFinder::computeNeighbourhoodOfVertex(
|
||||
VertexRef vertex, Direction direction, std::vector<Step>& steps) {
|
||||
void KShortestPathsFinder::computeNeighbourhoodOfVertex(VertexRef vertex, Direction direction,
|
||||
std::vector<Step>& steps) {
|
||||
std::unique_ptr<EdgeCursor> edgeCursor;
|
||||
|
||||
switch (direction) {
|
||||
|
@ -150,13 +150,14 @@ void KShortestPathsFinder::computeNeighbourhoodOfVertex(
|
|||
}
|
||||
}
|
||||
|
||||
bool KShortestPathsFinder::advanceFrontier(
|
||||
Ball& source, Ball const& target, std::unordered_set<VertexRef> const& forbiddenVertices,
|
||||
std::unordered_set<Edge> const& forbiddenEdges, VertexRef& join) {
|
||||
bool KShortestPathsFinder::advanceFrontier(Ball& source, Ball const& target,
|
||||
std::unordered_set<VertexRef> const& forbiddenVertices,
|
||||
std::unordered_set<Edge> const& forbiddenEdges,
|
||||
VertexRef& join) {
|
||||
VertexRef vr;
|
||||
FoundVertex* v;
|
||||
|
||||
bool success = source._frontier.popMinimal(vr, v, true);
|
||||
bool success = source._frontier.popMinimal(vr, v);
|
||||
if (!success) {
|
||||
return false;
|
||||
}
|
||||
|
@ -178,7 +179,8 @@ bool KShortestPathsFinder::advanceFrontier(
|
|||
}
|
||||
} else {
|
||||
source._frontier.insert(s._vertex,
|
||||
new FoundVertex(s._vertex, vr, std::move(s._edge), weight));
|
||||
std::make_unique<FoundVertex>(s._vertex, vr,
|
||||
std::move(s._edge), weight));
|
||||
|
||||
auto found = target._frontier.find(s._vertex);
|
||||
if (found != nullptr) {
|
||||
|
@ -192,8 +194,7 @@ bool KShortestPathsFinder::advanceFrontier(
|
|||
}
|
||||
|
||||
void KShortestPathsFinder::reconstructPath(Ball const& left, Ball const& right,
|
||||
VertexRef const& join,
|
||||
Path& result) {
|
||||
VertexRef const& join, Path& result) {
|
||||
result.clear();
|
||||
TRI_ASSERT(!join.empty());
|
||||
result._vertices.emplace_back(join);
|
||||
|
@ -276,13 +277,15 @@ bool KShortestPathsFinder::computeNextShortestPath(Path& result) {
|
|||
// indeed one that removes duplicates automatically
|
||||
// Sorted in reverse to have pop_back
|
||||
if (_options.useWeight()) {
|
||||
std::sort(_candidatePaths.begin(), _candidatePaths.end(), [](Path const& p1, Path const& p2) {
|
||||
return p1._weight > p2._weight;
|
||||
});
|
||||
std::sort(_candidatePaths.begin(), _candidatePaths.end(),
|
||||
[](Path const& p1, Path const& p2) {
|
||||
return p1._weight > p2._weight;
|
||||
});
|
||||
} else {
|
||||
std::sort(_candidatePaths.begin(), _candidatePaths.end(), [](Path const& p1, Path const& p2) {
|
||||
return p1._vertices.size() > p2._vertices.size();
|
||||
});
|
||||
std::sort(_candidatePaths.begin(), _candidatePaths.end(),
|
||||
[](Path const& p1, Path const& p2) {
|
||||
return p1._vertices.size() > p2._vertices.size();
|
||||
});
|
||||
}
|
||||
|
||||
// FIXME: this is of course bad.
|
||||
|
|
|
@ -126,7 +126,8 @@ class KShortestPathsFinder : public ShortestPathFinder {
|
|||
double _weight;
|
||||
|
||||
// Using negative weight to signifiy start/end vertex
|
||||
explicit FoundVertex(VertexRef const& vertex) : _vertex(vertex), _weight(0) {}
|
||||
explicit FoundVertex(VertexRef const& vertex)
|
||||
: _vertex(vertex), _weight(0) {}
|
||||
FoundVertex(VertexRef const& vertex, VertexRef const& pred, Edge&& edge, double weight)
|
||||
: _vertex(vertex), _pred(pred), _edge(std::move(edge)), _weight(weight) {}
|
||||
double weight() const { return _weight; }
|
||||
|
@ -150,13 +151,8 @@ class KShortestPathsFinder : public ShortestPathFinder {
|
|||
Ball(void) {}
|
||||
Ball(VertexRef const& centre, Direction direction)
|
||||
: _centre(centre), _direction(direction) {
|
||||
auto v = new FoundVertex(centre);
|
||||
try {
|
||||
_frontier.insert(centre, v);
|
||||
} catch (...) {
|
||||
delete v;
|
||||
throw;
|
||||
}
|
||||
auto v = std::make_unique<FoundVertex>(centre);
|
||||
_frontier.insert(centre, std::move(v));
|
||||
}
|
||||
~Ball() {
|
||||
// TODO free all vertices
|
||||
|
|
|
@ -66,12 +66,8 @@ class ShortestPathPriorityQueue {
|
|||
ShortestPathPriorityQueue() : _popped(0), _isHeap(false), _maxWeight(0) {}
|
||||
|
||||
~ShortestPathPriorityQueue() {
|
||||
for (Value* v : _heap) {
|
||||
delete v;
|
||||
}
|
||||
for (Value* v : _history) {
|
||||
delete v;
|
||||
}
|
||||
_heap.clear();
|
||||
_history.clear();
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -91,7 +87,7 @@ class ShortestPathPriorityQueue {
|
|||
/// yet exist, and false, in which case nothing else is changed.
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
bool insert(Key const& k, Value* v) {
|
||||
bool insert(Key const& k, std::unique_ptr<Value>&& v) {
|
||||
auto it = _lookup.find(k);
|
||||
if (it != _lookup.end()) {
|
||||
return false;
|
||||
|
@ -108,7 +104,7 @@ class ShortestPathPriorityQueue {
|
|||
if (w > _maxWeight) {
|
||||
_maxWeight = w;
|
||||
}
|
||||
_heap.push_back(v);
|
||||
_heap.push_back(std::move(v));
|
||||
try {
|
||||
_lookup.insert(std::make_pair(k, static_cast<ssize_t>(_heap.size() - 1 + _popped)));
|
||||
} catch (...) {
|
||||
|
@ -119,7 +115,7 @@ class ShortestPathPriorityQueue {
|
|||
}
|
||||
}
|
||||
// If we get here, we have to insert into a proper binary heap:
|
||||
_heap.push_back(v);
|
||||
_heap.push_back(std::move(v));
|
||||
try {
|
||||
size_t newpos = _heap.size() - 1;
|
||||
_lookup.insert(std::make_pair(k, static_cast<ssize_t>(newpos + _popped)));
|
||||
|
@ -146,9 +142,9 @@ class ShortestPathPriorityQueue {
|
|||
}
|
||||
|
||||
if (it->second >= 0) { // still in the queue
|
||||
return _heap.at(static_cast<size_t>(it->second) - _popped);
|
||||
return _heap.at(static_cast<size_t>(it->second) - _popped).get();
|
||||
} else { // already in the history
|
||||
return _history.at(static_cast<size_t>(-it->second) - 1);
|
||||
return _history.at(static_cast<size_t>(-it->second) - 1).get();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -186,36 +182,73 @@ class ShortestPathPriorityQueue {
|
|||
if (_heap.empty()) {
|
||||
return nullptr;
|
||||
}
|
||||
return _heap[0];
|
||||
return _heap[0].get();
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief popMinimal, returns true if something was returned and false
|
||||
/// if the structure is empty. Key and Value are stored in k and v.
|
||||
/// If keepForLookup is true then the Value is kept for lookup in the
|
||||
/// hash table but removed from the priority queue.
|
||||
/// This will keep the unique_ptr inside the history for further lookup.
|
||||
/// In case you doe not want to lookup the value, you need to call stealMinimal
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
bool popMinimal(Key& k, Value*& v, bool keepForLookup = false) {
|
||||
bool popMinimal(Key& k, Value*& v) {
|
||||
if (_heap.empty()) {
|
||||
v = nullptr;
|
||||
return false;
|
||||
}
|
||||
k = _heap[0]->getKey();
|
||||
// Note: the pointer of _heap[0] stays valid.
|
||||
// The unique-responsiblity is handed over to history.
|
||||
v = _heap[0].get();
|
||||
|
||||
auto it = _lookup.find(k);
|
||||
TRI_ASSERT(it != _lookup.end());
|
||||
// move val into history and hand over responsibility
|
||||
_history.push_back(std::move(_heap[0]));
|
||||
it->second = -static_cast<ssize_t>(_history.size());
|
||||
if (!_isHeap) {
|
||||
// remove nullptr from heap
|
||||
_heap.pop_front();
|
||||
// Note: This is intentionally one too large to shift by 1
|
||||
_popped++;
|
||||
} else {
|
||||
repairHeapAfterPop();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief stealMinimal, returns true if something was returned and false
|
||||
/// if the structure is empty. Key and Value are stored in k and v.
|
||||
/// This will hand over responsiblity to the caller, and will remove
|
||||
/// the value from further lookups. If you need it within the history here
|
||||
/// you need to call popMinimal.
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
bool stealMinimal(Key& k, std::unique_ptr<Value>& v) {
|
||||
if (_heap.empty()) {
|
||||
return false;
|
||||
}
|
||||
k = _heap[0]->getKey();
|
||||
v = _heap[0];
|
||||
|
||||
auto it = _lookup.find(k);
|
||||
TRI_ASSERT(it != _lookup.end());
|
||||
_lookup.erase(it);
|
||||
|
||||
// Responsibility handed over to v
|
||||
// Note: _heap[0] is nullptr now.
|
||||
// If we crash now this is save.
|
||||
// The code below is not allowed to use _heap[0]
|
||||
// anymore
|
||||
v = std::make_unique<Value>(_heap[0].release());
|
||||
TRI_ASSERT(v != nullptr);
|
||||
if (!_isHeap) {
|
||||
auto it = _lookup.find(k);
|
||||
TRI_ASSERT(it != _lookup.end());
|
||||
if (keepForLookup) {
|
||||
_history.push_back(_heap[0]);
|
||||
it->second = -static_cast<ssize_t>(_history.size());
|
||||
// Note: This is intentionally one too large to shift by 1
|
||||
} else {
|
||||
_lookup.erase(it);
|
||||
}
|
||||
// Remove it from heap asap.
|
||||
_heap.pop_front();
|
||||
_popped++;
|
||||
} else {
|
||||
removeFromHeap(keepForLookup);
|
||||
repairHeapAfterPop();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
@ -226,9 +259,7 @@ class ShortestPathPriorityQueue {
|
|||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void swap(size_t p, size_t q) {
|
||||
Value* v = _heap[p];
|
||||
_heap[p] = _heap[q];
|
||||
_heap[q] = v;
|
||||
_heap[p].swap(_heap[q]);
|
||||
|
||||
// Now fix the lookup:
|
||||
Key const& keyp(_heap[p]->getKey());
|
||||
|
@ -319,19 +350,10 @@ class ShortestPathPriorityQueue {
|
|||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief removeFromHeap, remove first position in the heap
|
||||
/// @brief repairHeapAfterPop, remove first position in the heap and repair it
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void removeFromHeap(bool keepForLookup) {
|
||||
auto it = _lookup.find(_heap[0]->getKey());
|
||||
TRI_ASSERT(it != _lookup.end());
|
||||
if (keepForLookup) {
|
||||
_history.push_back(_heap[0]);
|
||||
it->second = -static_cast<ssize_t>(_history.size());
|
||||
// Note: This is intentionally one too large to shift by 1
|
||||
} else {
|
||||
_lookup.erase(it);
|
||||
}
|
||||
void repairHeapAfterPop() {
|
||||
if (_heap.size() == 1) {
|
||||
_heap.clear();
|
||||
_popped = 0;
|
||||
|
@ -340,9 +362,11 @@ class ShortestPathPriorityQueue {
|
|||
return;
|
||||
}
|
||||
// Move one in front:
|
||||
_heap[0] = _heap.back();
|
||||
_heap[0].swap(_heap.back());
|
||||
// Throw away the POINTER (might be moved before).
|
||||
_heap.pop_back();
|
||||
it = _lookup.find(_heap[0]->getKey());
|
||||
// Find the lokkup of new value
|
||||
auto it = _lookup.find(_heap[0]->getKey());
|
||||
TRI_ASSERT(it != _lookup.end());
|
||||
it->second = static_cast<ssize_t>(_popped);
|
||||
repairDown();
|
||||
|
@ -376,7 +400,7 @@ class ShortestPathPriorityQueue {
|
|||
/// @brief _heap, the actual data
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
std::deque<Value*> _heap;
|
||||
std::deque<std::unique_ptr<Value>> _heap;
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief _maxWeight, the current maximal weight ever seen
|
||||
|
@ -388,7 +412,7 @@ class ShortestPathPriorityQueue {
|
|||
/// @brief _history, the actual data that is only in the key/value store
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
std::vector<Value*> _history;
|
||||
std::vector<std::unique_ptr<Value>> _history;
|
||||
};
|
||||
|
||||
} // namespace graph
|
||||
|
|
|
@ -43,395 +43,365 @@ using namespace std;
|
|||
struct MyValue {
|
||||
std::string _key;
|
||||
unsigned int _weight;
|
||||
unsigned int weight() const {
|
||||
return _weight;
|
||||
}
|
||||
std::string const& getKey() const {
|
||||
return _key;
|
||||
}
|
||||
void setWeight(unsigned int const w) {
|
||||
_weight = w;
|
||||
}
|
||||
MyValue (std::string k, unsigned int w) : _key(k), _weight(w) {
|
||||
}
|
||||
unsigned int weight() const { return _weight; }
|
||||
std::string const& getKey() const { return _key; }
|
||||
void setWeight(unsigned int const w) { _weight = w; }
|
||||
MyValue(std::string k, unsigned int w) : _key(k), _weight(w) {}
|
||||
};
|
||||
|
||||
TEST_CASE("CPriorityQueueTest", "[cpriorityqueue]") {
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief test filling in ascending weight order
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief test filling in ascending weight order
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
SECTION("tst_deque_case") {
|
||||
arangodb::graph::ShortestPathPriorityQueue<std::string, MyValue, unsigned int> pq;
|
||||
|
||||
SECTION("tst_deque_case") {
|
||||
arangodb::graph::ShortestPathPriorityQueue<std::string, MyValue, unsigned int> pq;
|
||||
|
||||
CHECK(0 == (int) pq.size());
|
||||
CHECK(true == pq.empty());
|
||||
CHECK(0 == (int)pq.size());
|
||||
CHECK(true == pq.empty());
|
||||
|
||||
bool b;
|
||||
MyValue* v;
|
||||
bool b;
|
||||
MyValue* v = nullptr;
|
||||
|
||||
b = pq.insert("a", new MyValue("a", 1));
|
||||
CHECK(b == true);
|
||||
b = pq.insert("b", new MyValue("b", 2));
|
||||
CHECK(b == true);
|
||||
b = pq.insert("c", new MyValue("c", 2));
|
||||
CHECK(b == true);
|
||||
b = pq.insert("d", new MyValue("d", 4));
|
||||
CHECK(b == true);
|
||||
v = new MyValue("c", 5);
|
||||
b = pq.insert("c", v);
|
||||
CHECK(b == false);
|
||||
delete v;
|
||||
b = pq.insert("a", std::make_unique<MyValue>("a", 1));
|
||||
CHECK(b == true);
|
||||
b = pq.insert("b", std::make_unique<MyValue>("b", 2));
|
||||
CHECK(b == true);
|
||||
b = pq.insert("c", std::make_unique<MyValue>("c", 2));
|
||||
CHECK(b == true);
|
||||
b = pq.insert("d", std::make_unique<MyValue>("d", 4));
|
||||
CHECK(b == true);
|
||||
b = pq.insert("c", std::make_unique<MyValue>("c", 5));
|
||||
CHECK(b == false);
|
||||
|
||||
CHECK(4 == (int) pq.size());
|
||||
CHECK(false == pq.empty());
|
||||
CHECK(4 == (int)pq.size());
|
||||
CHECK(false == pq.empty());
|
||||
|
||||
MyValue const* p;
|
||||
MyValue const* p;
|
||||
|
||||
p = pq.find("a");
|
||||
CHECK((int) p->_weight == 1);
|
||||
p = pq.find("b");
|
||||
CHECK((int) p->_weight == 2);
|
||||
p = pq.find("c");
|
||||
CHECK((int) p->_weight == 2);
|
||||
p = pq.find("d");
|
||||
CHECK((int) p->_weight == 4);
|
||||
p = pq.find("abc");
|
||||
CHECK(p == nullptr);
|
||||
p = pq.find("a");
|
||||
CHECK((int)p->_weight == 1);
|
||||
p = pq.find("b");
|
||||
CHECK((int)p->_weight == 2);
|
||||
p = pq.find("c");
|
||||
CHECK((int)p->_weight == 2);
|
||||
p = pq.find("d");
|
||||
CHECK((int)p->_weight == 4);
|
||||
p = pq.find("abc");
|
||||
CHECK(p == nullptr);
|
||||
|
||||
std::string k;
|
||||
std::string k;
|
||||
|
||||
p = pq.getMinimal();
|
||||
CHECK(p->_key == "a");
|
||||
b = pq.popMinimal(k, v);
|
||||
CHECK(b == true);
|
||||
CHECK(k == "a");
|
||||
CHECK(v->_key == "a");
|
||||
CHECK((int) v->_weight == 1);
|
||||
delete v;
|
||||
p = pq.getMinimal();
|
||||
CHECK(p->_key == "a");
|
||||
b = pq.popMinimal(k, v);
|
||||
CHECK(b == true);
|
||||
CHECK(k == "a");
|
||||
REQUIRE(v != nullptr);
|
||||
CHECK(v->_key == "a");
|
||||
CHECK((int)v->_weight == 1);
|
||||
|
||||
p = pq.getMinimal();
|
||||
CHECK(p->_key == "b");
|
||||
b = pq.popMinimal(k, v);
|
||||
CHECK(b == true);
|
||||
CHECK(k == "b");
|
||||
CHECK(v->_key == "b");
|
||||
CHECK((int) v->_weight == 2);
|
||||
delete v;
|
||||
p = pq.getMinimal();
|
||||
CHECK(p->_key == "b");
|
||||
b = pq.popMinimal(k, v);
|
||||
CHECK(b == true);
|
||||
CHECK(k == "b");
|
||||
CHECK(v->_key == "b");
|
||||
CHECK((int)v->_weight == 2);
|
||||
|
||||
p = pq.getMinimal();
|
||||
CHECK(p->_key == "c");
|
||||
b = pq.popMinimal(k, v);
|
||||
CHECK(b == true);
|
||||
CHECK(k == "c");
|
||||
CHECK(v->_key == "c");
|
||||
CHECK((int) v->_weight == 2);
|
||||
delete v;
|
||||
p = pq.getMinimal();
|
||||
CHECK(p->_key == "c");
|
||||
b = pq.popMinimal(k, v);
|
||||
CHECK(b == true);
|
||||
CHECK(k == "c");
|
||||
CHECK(v->_key == "c");
|
||||
CHECK((int)v->_weight == 2);
|
||||
|
||||
CHECK((int) pq.size() == 1);
|
||||
CHECK(pq.empty() == false);
|
||||
CHECK((int)pq.size() == 1);
|
||||
CHECK(pq.empty() == false);
|
||||
|
||||
p = pq.getMinimal();
|
||||
CHECK(p->_key == "d");
|
||||
b = pq.popMinimal(k, v);
|
||||
CHECK(b == true);
|
||||
CHECK(k == "d");
|
||||
CHECK(v->_key == "d");
|
||||
CHECK((int) v->_weight == 4);
|
||||
delete v;
|
||||
p = pq.getMinimal();
|
||||
CHECK(p->_key == "d");
|
||||
b = pq.popMinimal(k, v);
|
||||
CHECK(b == true);
|
||||
CHECK(k == "d");
|
||||
CHECK(v->_key == "d");
|
||||
CHECK((int)v->_weight == 4);
|
||||
|
||||
CHECK((int) pq.size() == 0);
|
||||
CHECK(pq.empty() == true);
|
||||
CHECK((int)pq.size() == 0);
|
||||
CHECK(pq.empty() == true);
|
||||
|
||||
p = pq.getMinimal();
|
||||
CHECK(p == nullptr);
|
||||
b = pq.popMinimal(k, v);
|
||||
CHECK(b == false);
|
||||
}
|
||||
p = pq.getMinimal();
|
||||
CHECK(p == nullptr);
|
||||
b = pq.popMinimal(k, v);
|
||||
CHECK(b == false);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief test filling in random weight order
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief test filling in random weight order
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
SECTION("tst_heap_case") {
|
||||
arangodb::graph::ShortestPathPriorityQueue<std::string, MyValue, unsigned int> pq;
|
||||
|
||||
CHECK(0 == (int) pq.size());
|
||||
CHECK(true == pq.empty());
|
||||
SECTION("tst_heap_case") {
|
||||
arangodb::graph::ShortestPathPriorityQueue<std::string, MyValue, unsigned int> pq;
|
||||
|
||||
bool b;
|
||||
MyValue* v;
|
||||
CHECK(0 == (int)pq.size());
|
||||
CHECK(true == pq.empty());
|
||||
|
||||
b = pq.insert("a", new MyValue("a", 4));
|
||||
CHECK(b == true);
|
||||
b = pq.insert("b", new MyValue("b", 1));
|
||||
CHECK(b == true);
|
||||
b = pq.insert("c", new MyValue("c", 2));
|
||||
CHECK(b == true);
|
||||
b = pq.insert("d", new MyValue("d", 2));
|
||||
CHECK(b == true);
|
||||
v = new MyValue("c", 5);
|
||||
b = pq.insert("c", v);
|
||||
CHECK(b == false);
|
||||
delete v;
|
||||
bool b;
|
||||
MyValue* v = nullptr;
|
||||
|
||||
CHECK(4 == (int) pq.size());
|
||||
CHECK(false == pq.empty());
|
||||
b = pq.insert("a", std::make_unique<MyValue>("a", 4));
|
||||
CHECK(b == true);
|
||||
b = pq.insert("b", std::make_unique<MyValue>("b", 1));
|
||||
CHECK(b == true);
|
||||
b = pq.insert("c", std::make_unique<MyValue>("c", 2));
|
||||
CHECK(b == true);
|
||||
b = pq.insert("d", std::make_unique<MyValue>("d", 2));
|
||||
CHECK(b == true);
|
||||
b = pq.insert("c", std::make_unique<MyValue>("c", 5));
|
||||
CHECK(b == false);
|
||||
|
||||
MyValue const* p;
|
||||
CHECK(4 == (int)pq.size());
|
||||
CHECK(false == pq.empty());
|
||||
|
||||
p = pq.find("a");
|
||||
CHECK((int) p->_weight == 4);
|
||||
p = pq.find("b");
|
||||
CHECK((int) p->_weight == 1);
|
||||
p = pq.find("c");
|
||||
CHECK((int) p->_weight == 2);
|
||||
p = pq.find("d");
|
||||
CHECK((int) p->_weight == 2);
|
||||
p = pq.find("abc");
|
||||
CHECK(p == nullptr);
|
||||
MyValue const* p;
|
||||
|
||||
std::string k;
|
||||
p = pq.find("a");
|
||||
CHECK((int)p->_weight == 4);
|
||||
p = pq.find("b");
|
||||
CHECK((int)p->_weight == 1);
|
||||
p = pq.find("c");
|
||||
CHECK((int)p->_weight == 2);
|
||||
p = pq.find("d");
|
||||
CHECK((int)p->_weight == 2);
|
||||
p = pq.find("abc");
|
||||
CHECK(p == nullptr);
|
||||
|
||||
p = pq.getMinimal();
|
||||
CHECK(p->_key == "b");
|
||||
b = pq.popMinimal(k, v);
|
||||
CHECK(b == true);
|
||||
CHECK(k == "b");
|
||||
CHECK(v->_key == "b");
|
||||
CHECK((int) v->_weight == 1);
|
||||
delete v;
|
||||
std::string k;
|
||||
|
||||
p = pq.getMinimal();
|
||||
CHECK(p->_key == "d");
|
||||
b = pq.popMinimal(k, v);
|
||||
CHECK(b == true);
|
||||
CHECK(k == "d");
|
||||
CHECK(v->_key == "d");
|
||||
CHECK((int) v->_weight == 2);
|
||||
delete v;
|
||||
p = pq.getMinimal();
|
||||
CHECK(p->_key == "b");
|
||||
b = pq.popMinimal(k, v);
|
||||
CHECK(b == true);
|
||||
CHECK(k == "b");
|
||||
CHECK(v->_key == "b");
|
||||
CHECK((int)v->_weight == 1);
|
||||
|
||||
p = pq.getMinimal();
|
||||
CHECK(p->_key == "c");
|
||||
b = pq.popMinimal(k, v);
|
||||
CHECK(b == true);
|
||||
CHECK(k == "c");
|
||||
CHECK(v->_key == "c");
|
||||
CHECK((int) v->_weight == 2);
|
||||
delete v;
|
||||
p = pq.getMinimal();
|
||||
CHECK(p->_key == "d");
|
||||
b = pq.popMinimal(k, v);
|
||||
CHECK(b == true);
|
||||
CHECK(k == "d");
|
||||
CHECK(v->_key == "d");
|
||||
CHECK((int)v->_weight == 2);
|
||||
|
||||
CHECK((int) pq.size() == 1);
|
||||
CHECK(pq.empty() == false);
|
||||
p = pq.getMinimal();
|
||||
CHECK(p->_key == "c");
|
||||
b = pq.popMinimal(k, v);
|
||||
CHECK(b == true);
|
||||
CHECK(k == "c");
|
||||
CHECK(v->_key == "c");
|
||||
CHECK((int)v->_weight == 2);
|
||||
|
||||
p = pq.getMinimal();
|
||||
CHECK(p->_key == "a");
|
||||
b = pq.popMinimal(k, v);
|
||||
CHECK(b == true);
|
||||
CHECK(k == "a");
|
||||
CHECK(v->_key == "a");
|
||||
CHECK((int) v->_weight == 4);
|
||||
delete v;
|
||||
CHECK((int)pq.size() == 1);
|
||||
CHECK(pq.empty() == false);
|
||||
|
||||
CHECK((int) pq.size() == 0);
|
||||
CHECK(pq.empty() == true);
|
||||
p = pq.getMinimal();
|
||||
CHECK(p->_key == "a");
|
||||
b = pq.popMinimal(k, v);
|
||||
CHECK(b == true);
|
||||
CHECK(k == "a");
|
||||
CHECK(v->_key == "a");
|
||||
CHECK((int)v->_weight == 4);
|
||||
|
||||
p = pq.getMinimal();
|
||||
CHECK(p == nullptr);
|
||||
b = pq.popMinimal(k, v);
|
||||
CHECK(b == false);
|
||||
}
|
||||
CHECK((int)pq.size() == 0);
|
||||
CHECK(pq.empty() == true);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief test filling in ascending weight order, but then doing lowerWeight
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
p = pq.getMinimal();
|
||||
CHECK(p == nullptr);
|
||||
b = pq.popMinimal(k, v);
|
||||
CHECK(b == false);
|
||||
}
|
||||
|
||||
SECTION("tst_deque_case_with_lowering") {
|
||||
arangodb::graph::ShortestPathPriorityQueue<std::string, MyValue, unsigned int> pq;
|
||||
|
||||
CHECK(0 == (int) pq.size());
|
||||
CHECK(true == pq.empty());
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief test filling in ascending weight order, but then doing lowerWeight
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
bool b;
|
||||
MyValue* v;
|
||||
SECTION("tst_deque_case_with_lowering") {
|
||||
arangodb::graph::ShortestPathPriorityQueue<std::string, MyValue, unsigned int> pq;
|
||||
|
||||
b = pq.insert("a", new MyValue("a", 1));
|
||||
CHECK(b == true);
|
||||
b = pq.insert("b", new MyValue("b", 2));
|
||||
CHECK(b == true);
|
||||
b = pq.insert("c", new MyValue("c", 2));
|
||||
CHECK(b == true);
|
||||
b = pq.insert("d", new MyValue("d", 4));
|
||||
CHECK(b == true);
|
||||
v = new MyValue("c", 5);
|
||||
b = pq.insert("c", v);
|
||||
CHECK(b == false);
|
||||
delete v;
|
||||
CHECK(0 == (int)pq.size());
|
||||
CHECK(true == pq.empty());
|
||||
|
||||
CHECK(4 == (int) pq.size());
|
||||
CHECK(false == pq.empty());
|
||||
bool b;
|
||||
MyValue* v = nullptr;
|
||||
|
||||
pq.lowerWeight("d", 1); // This moves "d" before "b" and "c"
|
||||
b = pq.insert("a", std::make_unique<MyValue>("a", 1));
|
||||
CHECK(b == true);
|
||||
b = pq.insert("b", std::make_unique<MyValue>("b", 2));
|
||||
CHECK(b == true);
|
||||
b = pq.insert("c", std::make_unique<MyValue>("c", 2));
|
||||
CHECK(b == true);
|
||||
b = pq.insert("d", std::make_unique<MyValue>("d", 4));
|
||||
CHECK(b == true);
|
||||
b = pq.insert("c", std::make_unique<MyValue>("c", 5));
|
||||
CHECK(b == false);
|
||||
|
||||
MyValue const* p;
|
||||
CHECK(4 == (int)pq.size());
|
||||
CHECK(false == pq.empty());
|
||||
|
||||
p = pq.find("a");
|
||||
CHECK((int) p->_weight == 1);
|
||||
p = pq.find("b");
|
||||
CHECK((int) p->_weight == 2);
|
||||
p = pq.find("c");
|
||||
CHECK((int) p->_weight == 2);
|
||||
p = pq.find("d");
|
||||
CHECK((int) p->_weight == 1);
|
||||
p = pq.find("abc");
|
||||
CHECK(p == nullptr);
|
||||
pq.lowerWeight("d", 1); // This moves "d" before "b" and "c"
|
||||
|
||||
std::string k;
|
||||
MyValue const* p;
|
||||
|
||||
p = pq.getMinimal();
|
||||
CHECK(p->_key == "a");
|
||||
b = pq.popMinimal(k, v);
|
||||
CHECK(b == true);
|
||||
CHECK(k == "a");
|
||||
CHECK(v->_key == "a");
|
||||
CHECK((int) v->_weight == 1);
|
||||
delete v;
|
||||
p = pq.find("a");
|
||||
CHECK((int)p->_weight == 1);
|
||||
p = pq.find("b");
|
||||
CHECK((int)p->_weight == 2);
|
||||
p = pq.find("c");
|
||||
CHECK((int)p->_weight == 2);
|
||||
p = pq.find("d");
|
||||
CHECK((int)p->_weight == 1);
|
||||
p = pq.find("abc");
|
||||
CHECK(p == nullptr);
|
||||
|
||||
p = pq.getMinimal();
|
||||
CHECK(p->_key == "d");
|
||||
b = pq.popMinimal(k, v);
|
||||
CHECK(b == true);
|
||||
CHECK(k == "d");
|
||||
CHECK(v->_key == "d");
|
||||
CHECK((int) v->_weight == 1);
|
||||
delete v;
|
||||
std::string k;
|
||||
|
||||
p = pq.getMinimal();
|
||||
CHECK(p->_key == "c");
|
||||
b = pq.popMinimal(k, v);
|
||||
CHECK(b == true);
|
||||
CHECK(k == "c");
|
||||
CHECK(v->_key == "c");
|
||||
CHECK((int) v->_weight == 2);
|
||||
delete v;
|
||||
p = pq.getMinimal();
|
||||
CHECK(p->_key == "a");
|
||||
b = pq.popMinimal(k, v);
|
||||
CHECK(b == true);
|
||||
CHECK(k == "a");
|
||||
CHECK(v->_key == "a");
|
||||
CHECK((int)v->_weight == 1);
|
||||
|
||||
CHECK((int) pq.size() == 1);
|
||||
CHECK(pq.empty() == false);
|
||||
p = pq.getMinimal();
|
||||
CHECK(p->_key == "d");
|
||||
b = pq.popMinimal(k, v);
|
||||
CHECK(b == true);
|
||||
CHECK(k == "d");
|
||||
CHECK(v->_key == "d");
|
||||
CHECK((int)v->_weight == 1);
|
||||
|
||||
p = pq.getMinimal();
|
||||
CHECK(p->_key == "b");
|
||||
b = pq.popMinimal(k, v);
|
||||
CHECK(b == true);
|
||||
CHECK(k == "b");
|
||||
CHECK(v->_key == "b");
|
||||
CHECK((int) v->_weight == 2);
|
||||
delete v;
|
||||
p = pq.getMinimal();
|
||||
CHECK(p->_key == "c");
|
||||
b = pq.popMinimal(k, v);
|
||||
CHECK(b == true);
|
||||
CHECK(k == "c");
|
||||
CHECK(v->_key == "c");
|
||||
CHECK((int)v->_weight == 2);
|
||||
|
||||
CHECK((int) pq.size() == 0);
|
||||
CHECK(pq.empty() == true);
|
||||
CHECK((int)pq.size() == 1);
|
||||
CHECK(pq.empty() == false);
|
||||
|
||||
p = pq.getMinimal();
|
||||
CHECK(p == nullptr);
|
||||
b = pq.popMinimal(k, v);
|
||||
CHECK(b == false);
|
||||
}
|
||||
p = pq.getMinimal();
|
||||
CHECK(p->_key == "b");
|
||||
b = pq.popMinimal(k, v);
|
||||
CHECK(b == true);
|
||||
CHECK(k == "b");
|
||||
CHECK(v->_key == "b");
|
||||
CHECK((int)v->_weight == 2);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief test filling in random weight order, and later lowering some weight
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
CHECK((int)pq.size() == 0);
|
||||
CHECK(pq.empty() == true);
|
||||
|
||||
SECTION("tst_heap_case_with_lowering") {
|
||||
arangodb::graph::ShortestPathPriorityQueue<std::string, MyValue, unsigned int> pq;
|
||||
|
||||
CHECK(0 == (int) pq.size());
|
||||
CHECK(true == pq.empty());
|
||||
p = pq.getMinimal();
|
||||
CHECK(p == nullptr);
|
||||
b = pq.popMinimal(k, v);
|
||||
CHECK(b == false);
|
||||
}
|
||||
|
||||
bool b;
|
||||
MyValue* v;
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief test filling in random weight order, and later lowering some weight
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
b = pq.insert("a", new MyValue("a", 4));
|
||||
CHECK(b == true);
|
||||
b = pq.insert("b", new MyValue("b", 2));
|
||||
CHECK(b == true);
|
||||
b = pq.insert("c", new MyValue("c", 3));
|
||||
CHECK(b == true);
|
||||
b = pq.insert("d", new MyValue("d", 3));
|
||||
CHECK(b == true);
|
||||
v = new MyValue("c", 5);
|
||||
b = pq.insert("c", v);
|
||||
CHECK(b == false);
|
||||
delete v;
|
||||
SECTION("tst_heap_case_with_lowering") {
|
||||
arangodb::graph::ShortestPathPriorityQueue<std::string, MyValue, unsigned int> pq;
|
||||
|
||||
CHECK(4 == (int) pq.size());
|
||||
CHECK(false == pq.empty());
|
||||
CHECK(0 == (int)pq.size());
|
||||
CHECK(true == pq.empty());
|
||||
|
||||
pq.lowerWeight("a", 1); // This moves "a" before all others
|
||||
bool b;
|
||||
MyValue* v = nullptr;
|
||||
|
||||
MyValue const* p;
|
||||
b = pq.insert("a", std::make_unique<MyValue>("a", 4));
|
||||
CHECK(b == true);
|
||||
b = pq.insert("b", std::make_unique<MyValue>("b", 2));
|
||||
CHECK(b == true);
|
||||
b = pq.insert("c", std::make_unique<MyValue>("c", 3));
|
||||
CHECK(b == true);
|
||||
b = pq.insert("d", std::make_unique<MyValue>("d", 3));
|
||||
CHECK(b == true);
|
||||
b = pq.insert("c", std::make_unique<MyValue>("c", 5));
|
||||
CHECK(b == false);
|
||||
delete v;
|
||||
|
||||
p = pq.find("a");
|
||||
CHECK((int) p->_weight == 1);
|
||||
p = pq.find("b");
|
||||
CHECK((int) p->_weight == 2);
|
||||
p = pq.find("c");
|
||||
CHECK((int) p->_weight == 3);
|
||||
p = pq.find("d");
|
||||
CHECK((int) p->_weight == 3);
|
||||
p = pq.find("abc");
|
||||
CHECK(p == nullptr);
|
||||
CHECK(4 == (int)pq.size());
|
||||
CHECK(false == pq.empty());
|
||||
|
||||
std::string k;
|
||||
pq.lowerWeight("a", 1); // This moves "a" before all others
|
||||
|
||||
p = pq.getMinimal();
|
||||
CHECK(p->_key == "a");
|
||||
b = pq.popMinimal(k, v);
|
||||
CHECK(b == true);
|
||||
CHECK(k == "a");
|
||||
CHECK(v->_key == "a");
|
||||
CHECK((int) v->_weight == 1);
|
||||
delete v;
|
||||
MyValue const* p;
|
||||
|
||||
p = pq.getMinimal();
|
||||
CHECK(p->_key == "b");
|
||||
b = pq.popMinimal(k, v);
|
||||
CHECK(b == true);
|
||||
CHECK(k == "b");
|
||||
CHECK(v->_key == "b");
|
||||
CHECK((int) v->_weight == 2);
|
||||
delete v;
|
||||
p = pq.find("a");
|
||||
CHECK((int)p->_weight == 1);
|
||||
p = pq.find("b");
|
||||
CHECK((int)p->_weight == 2);
|
||||
p = pq.find("c");
|
||||
CHECK((int)p->_weight == 3);
|
||||
p = pq.find("d");
|
||||
CHECK((int)p->_weight == 3);
|
||||
p = pq.find("abc");
|
||||
CHECK(p == nullptr);
|
||||
|
||||
p = pq.getMinimal();
|
||||
CHECK(p->_key == "c");
|
||||
b = pq.popMinimal(k, v);
|
||||
CHECK(b == true);
|
||||
CHECK(k == "c");
|
||||
CHECK(v->_key == "c");
|
||||
CHECK((int) v->_weight == 3);
|
||||
delete v;
|
||||
std::string k;
|
||||
|
||||
CHECK((int) pq.size() == 1);
|
||||
CHECK(pq.empty() == false);
|
||||
p = pq.getMinimal();
|
||||
CHECK(p->_key == "a");
|
||||
b = pq.popMinimal(k, v);
|
||||
CHECK(b == true);
|
||||
CHECK(k == "a");
|
||||
CHECK(v->_key == "a");
|
||||
CHECK((int)v->_weight == 1);
|
||||
|
||||
p = pq.getMinimal();
|
||||
CHECK(p->_key == "d");
|
||||
b = pq.popMinimal(k, v);
|
||||
CHECK(b == true);
|
||||
CHECK(k == "d");
|
||||
CHECK(v->_key == "d");
|
||||
CHECK((int) v->_weight == 3);
|
||||
delete v;
|
||||
p = pq.getMinimal();
|
||||
CHECK(p->_key == "b");
|
||||
b = pq.popMinimal(k, v);
|
||||
CHECK(b == true);
|
||||
CHECK(k == "b");
|
||||
CHECK(v->_key == "b");
|
||||
CHECK((int)v->_weight == 2);
|
||||
|
||||
CHECK((int) pq.size() == 0);
|
||||
CHECK(pq.empty() == true);
|
||||
p = pq.getMinimal();
|
||||
CHECK(p->_key == "c");
|
||||
b = pq.popMinimal(k, v);
|
||||
CHECK(b == true);
|
||||
CHECK(k == "c");
|
||||
CHECK(v->_key == "c");
|
||||
CHECK((int)v->_weight == 3);
|
||||
|
||||
p = pq.getMinimal();
|
||||
CHECK(p == nullptr);
|
||||
b = pq.popMinimal(k, v);
|
||||
CHECK(b == false);
|
||||
}
|
||||
CHECK((int)pq.size() == 1);
|
||||
CHECK(pq.empty() == false);
|
||||
|
||||
p = pq.getMinimal();
|
||||
CHECK(p->_key == "d");
|
||||
b = pq.popMinimal(k, v);
|
||||
CHECK(b == true);
|
||||
CHECK(k == "d");
|
||||
CHECK(v->_key == "d");
|
||||
CHECK((int)v->_weight == 3);
|
||||
|
||||
CHECK((int)pq.size() == 0);
|
||||
CHECK(pq.empty() == true);
|
||||
|
||||
p = pq.getMinimal();
|
||||
CHECK(p == nullptr);
|
||||
b = pq.popMinimal(k, v);
|
||||
CHECK(b == false);
|
||||
}
|
||||
}
|
||||
|
||||
// Local Variables:
|
||||
// mode: outline-minor
|
||||
// outline-regexp: "^\\(/// @brief\\|/// {@inheritDoc}\\|/// @addtogroup\\|// --SECTION--\\|/// @\\}\\)"
|
||||
// End:
|
||||
// outline-regexp: "^\\(/// @brief\\|/// {@inheritDoc}\\|/// @addtogroup\\|//
|
||||
// --SECTION--\\|/// @\\}\\)" End:
|
||||
|
|
Loading…
Reference in New Issue