Fixed routing bug. #326

Merged
vng merged 3 commits from vng-fix into master 2021-04-23 20:16:40 +00:00
8 changed files with 56 additions and 93 deletions

View file

@ -17,6 +17,19 @@ namespace
}
}
UNIT_TEST(BufferVector_PushBack_And_Realloc)
{
using ElementT = std::vector<int>;
ElementT element({1, 2, 3});
buffer_vector<ElementT, 2> v;
v.append(2, element);
v.push_back(v[0]);
biodranik commented 2021-04-23 10:52:37 +00:00 (Migrated from github.com)
Review

А есть такой же тест на emplace?

А есть такой же тест на emplace?
vng commented 2021-04-23 15:02:02 +00:00 (Migrated from github.com)
Review

Ох, emplace не используется в таком контексте (ну или не надо использовать). Если ее так предусматривать, надо извращаться.

Ох, emplace не используется в таком контексте (ну или не надо использовать). Если ее так предусматривать, надо извращаться.
biodranik commented 2021-04-23 15:44:13 +00:00 (Migrated from github.com)
Review

Я бы критически просмотрел ещё раз имеющиеся тесты buffer_vector, чтобы всякие странные кейзы точно были покрыты, а то мало ли.

Я бы критически просмотрел ещё раз имеющиеся тесты buffer_vector, чтобы всякие странные кейзы точно были покрыты, а то мало ли.
TEST_EQUAL(v.size(), 3, ());
TEST_EQUAL(v[2], element, ());
}
UNIT_TEST(BufferVectorBounds)
{
buffer_vector<size_t, 2> v;
@ -280,11 +293,14 @@ struct CopyCtorChecker
CopyCtorChecker() = default;
explicit CopyCtorChecker(char const * s) : m_s(s) {}
CopyCtorChecker(CopyCtorChecker const & rhs)
{
TEST(rhs.m_s.empty(), ("Copy ctor is called only in resize with default element"));
}
CopyCtorChecker(CopyCtorChecker && rhs) = default;
CopyCtorChecker & operator=(CopyCtorChecker &&) = default;
CopyCtorChecker & operator=(CopyCtorChecker const &)
{
TEST(false, ("Assigment operator should not be called"));

View file

@ -29,33 +29,10 @@ private:
inline bool IsDynamic() const { return m_size == USE_DYNAMIC; }
/// @todo clang on linux doesn't have is_trivially_copyable.
#ifndef OMIM_OS_LINUX
template <class U = T>
std::enable_if_t<std::is_trivially_copyable<U>::value, void> MoveStatic(buffer_vector<T, N> & rhs)
void MoveStatic(buffer_vector<T, N> & rhs)
{
memcpy(m_static, rhs.m_static, rhs.m_size*sizeof(T));
std::move(rhs.m_static, rhs.m_static + rhs.m_size, m_static);
}
template <class U = T>
std::enable_if_t<!std::is_trivially_copyable<U>::value, void> MoveStatic(
buffer_vector<T, N> & rhs)
{
for (size_t i = 0; i < rhs.m_size; ++i)
Swap(m_static[i], rhs.m_static[i]);
}
#else
template <class U = T>
std::enable_if_t<std::is_pod<U>::value, void> MoveStatic(buffer_vector<T, N> & rhs)
{
memcpy(m_static, rhs.m_static, rhs.m_size*sizeof(T));
}
template <class U = T>
std::enable_if_t<!std::is_pod<U>::value, void> MoveStatic(buffer_vector<T, N> & rhs)
{
for (size_t i = 0; i < rhs.m_size; ++i)
Swap(m_static[i], rhs.m_static[i]);
}
#endif
public:
typedef T value_type;
@ -115,24 +92,20 @@ public:
template <typename TIt>
void append(TIt beg, TIt end)
{
if (IsDynamic())
if (!IsDynamic())
{
m_dynamic.insert(m_dynamic.end(), beg, end);
return;
size_t const newSize = std::distance(beg, end) + m_size;
if (newSize <= N)
{
std::copy(beg, end, &m_static[m_size]);
m_size = newSize;
return;
}
else
SwitchToDynamic(newSize);
}
while (beg != end)
{
if (m_size == N)
{
m_dynamic.reserve(N * 2);
SwitchToDynamic();
while (beg != end)
m_dynamic.push_back(*beg++);
break;
}
m_static[m_size++] = *beg++;
}
m_dynamic.insert(m_dynamic.end(), beg, end);
}
void append(size_t count, T const & c)
@ -142,12 +115,12 @@ public:
size_t const newSize = count + m_size;
if (newSize <= N)
{
while (m_size < newSize)
m_static[m_size++] = c;
std::fill_n(&m_static[m_size], count, c);
m_size = newSize;
return;
}
else
biodranik commented 2021-04-23 10:54:28 +00:00 (Migrated from github.com)
Review

Может делать это внутри SwitchToDynamic, передавая размер?

Может делать это внутри SwitchToDynamic, передавая размер?
vng commented 2021-04-23 15:02:28 +00:00 (Migrated from github.com)
Review

Можно, да

Можно, да
SwitchToDynamic();
SwitchToDynamic(newSize);
}
m_dynamic.insert(m_dynamic.end(), count, c);
@ -186,8 +159,7 @@ public:
}
else
{
m_dynamic.reserve(n);
SwitchToDynamic();
SwitchToDynamic(n);
m_dynamic.resize(n);
ASSERT_EQUAL(m_dynamic.size(), n, ());
}
@ -209,9 +181,8 @@ public:
}
else
{
m_dynamic.reserve(n);
size_t const oldSize = m_size;
SwitchToDynamic();
SwitchToDynamic(n);
m_dynamic.insert(m_dynamic.end(), n - oldSize, c);
ASSERT_EQUAL(m_dynamic.size(), n, ());
}
@ -305,7 +276,8 @@ public:
Swap(m_static[i], rhs.m_static[i]);
}
void push_back(T const & t)
/// By value to be consistent with m_vec.push_back(m_vec[0]).
void push_back(T t)
{
if (IsDynamic())
{
@ -313,35 +285,13 @@ public:
return;
}
if (m_size < N)
{
m_static[m_size++] = t;
}
else
{
ASSERT_EQUAL(m_size, N, ());
SwitchToDynamic();
m_dynamic.push_back(t);
ASSERT_EQUAL(m_dynamic.size(), N + 1, ());
}
}
void push_back(T && t)
{
if (IsDynamic())
{
m_dynamic.push_back(std::move(t));
return;
}
if (m_size < N)
{
Swap(m_static[m_size++], t);
}
else
{
ASSERT_EQUAL(m_size, N, ());
SwitchToDynamic();
SwitchToDynamic(N + 1);
m_dynamic.push_back(std::move(t));
ASSERT_EQUAL(m_dynamic.size(), N + 1, ());
}
@ -375,8 +325,7 @@ public:
}
else
{
ASSERT_EQUAL(m_size, N, ());
SwitchToDynamic();
SwitchToDynamic(N + 1);
m_dynamic.emplace_back(std::forward<Args>(args)...);
ASSERT_EQUAL(m_dynamic.size(), N + 1, ());
}
@ -410,8 +359,7 @@ public:
}
else
{
m_dynamic.reserve(m_size + n);
SwitchToDynamic();
SwitchToDynamic(m_size + n);
m_dynamic.insert(m_dynamic.begin() + pos, beg, end);
}
}
@ -446,16 +394,15 @@ public:
void erase(iterator it) { erase(it, it + 1); }
private:
void SwitchToDynamic()
void SwitchToDynamic(size_t toReserve)
biodranik commented 2021-04-23 10:55:38 +00:00 (Migrated from github.com)
Review

Сигнатура не как у вектора, будут же много где копирования ненужные. Может обе оставить? Или добавить пушбэк с &&?

Сигнатура не как у вектора, будут же много где копирования ненужные. Может обе оставить? Или добавить пушбэк с &&?
vng commented 2021-04-23 15:04:55 +00:00 (Migrated from github.com)
Review

std::vector push_back как раз таки внутри создает копию. Тут я сделал явно - это и есть фикс ошибки. Лучше иметь одну функцию (T t), чтобы можно было либо push_back(t), либо push_back(std::move(t)).

std::vector push_back как раз таки внутри создает копию. Тут я сделал явно - это и есть фикс ошибки. Лучше иметь одну функцию (T t), чтобы можно было либо push_back(t), либо push_back(std::move(t)).
vng commented 2021-04-23 15:08:56 +00:00 (Migrated from github.com)
Review

Решил не усложнять и всегда принимать по значению - на самом деле экономии никакой не будет от 2-х сигнатур.

Решил не усложнять и всегда принимать по значению - на самом деле экономии никакой не будет от 2-х сигнатур.
biodranik commented 2021-04-23 15:42:58 +00:00 (Migrated from github.com)
Review

Лучше иметь одну функцию (T t), чтобы можно было либо push_back(t), либо push_back(std::move(t)).

buffer_vector::push_back(T t) создаст первую копию, а если вызовется m_vec.push_back(T const & t) вместо (T &&) то и вторая копия будет. Если хочешь эффективно, то внутри надо явно std::move версию push_back всегда вызывать, вместо обычной копирующей.

> Лучше иметь одну функцию (T t), чтобы можно было либо push_back(t), либо push_back(std::move(t)). buffer_vector::push_back(T t) создаст первую копию, а если вызовется m_vec.push_back(T const & t) вместо (T &&) то и вторая копия будет. Если хочешь эффективно, то внутри надо явно std::move версию push_back всегда вызывать, вместо обычной копирующей.
vng commented 2021-04-23 16:02:49 +00:00 (Migrated from github.com)
Review

так и делается, в любом случае будет одна копия

так и делается, в любом случае будет одна копия
{
ASSERT_NOT_EQUAL(m_size, static_cast<size_t>(USE_DYNAMIC), ());
ASSERT_EQUAL(m_dynamic.size(), 0, ());
m_dynamic.reserve(m_size);
for (size_t i = 0; i < m_size; ++i)
{
m_dynamic.emplace_back();
Swap(m_static[i], m_dynamic.back());
}
m_dynamic.reserve(toReserve);
m_dynamic.resize(m_size);
std::move(m_static, m_static + m_size, m_dynamic.begin());
m_size = USE_DYNAMIC;
}
};

View file

@ -28,12 +28,12 @@ void GetRegularEdges(geometry::PointWithAltitude const & junction, IRoadGraph co
{
auto & es = cache[junction];
(graph.*edgeGetter)(junction, es);
edges.insert(end(edges), begin(es), end(es));
edges.append(begin(es), end(es));
}
else
{
auto const & es = it->second;
edges.insert(end(edges), begin(es), end(es));
edges.append(begin(es), end(es));
}
}
} // namespace

View file

@ -478,12 +478,12 @@ void Router::GetEdges(
{
auto & es = cache[u];
(m_graph.*getRegular)(u, es);
edges.insert(edges.end(), es.begin(), es.end());
edges.append(es.begin(), es.end());
}
else
{
auto const & es = it->second;
edges.insert(edges.end(), es.begin(), es.end());
edges.append(es.begin(), es.end());
}
(m_graph.*getFake)(u, edges);
}

View file

@ -582,7 +582,7 @@ void IndexGraphStarter::AddFakeEdges(Segment const & segment, bool isOutgoing, E
}
}
}
edges.insert(edges.end(), fakeEdges.begin(), fakeEdges.end());
edges.append(fakeEdges.begin(), fakeEdges.end());
}
bool IndexGraphStarter::EndingPassThroughAllowed(Ending const & ending)

View file

@ -456,13 +456,13 @@ bool IndexGraphStarterJoints<Graph>::FillEdgesAndParentsWeights(
// from start to start or end to end vertex.
if (vertex == GetStartJoint())
{
edges.insert(edges.end(), m_startOutEdges.begin(), m_startOutEdges.end());
edges.append(m_startOutEdges.begin(), m_startOutEdges.end());
parentWeights.append(edges.size(), Weight(0.0));
firstFakeId = edges.size();
}
else if (vertex == GetFinishJoint())
{
edges.insert(edges.end(), m_endOutEdges.begin(), m_endOutEdges.end());
edges.append(m_endOutEdges.begin(), m_endOutEdges.end());
// If vertex is FinishJoint, parentWeight is equal to zero, because the first vertex is zero-weight loop.
parentWeights.append(edges.size(), Weight(0.0));
}
@ -494,7 +494,7 @@ bool IndexGraphStarterJoints<Graph>::FillEdgesAndParentsWeights(
if (edges.size() != prevSize)
{
CHECK_LESS(i, parentWeights.size(), ());
parentWeights.emplace_back(parentWeights[i]);
parentWeights.push_back(parentWeights[i]);
}
}
}

View file

@ -226,7 +226,7 @@ void IRoadGraph::GetFakeOutgoingEdges(geometry::PointWithAltitude const & juncti
{
auto const it = m_fakeOutgoingEdges.find(junction);
if (it != m_fakeOutgoingEdges.cend())
edges.insert(edges.end(), it->second.cbegin(), it->second.cend());
edges.append(it->second.cbegin(), it->second.cend());
}
void IRoadGraph::GetFakeIngoingEdges(geometry::PointWithAltitude const & junction,
@ -234,7 +234,7 @@ void IRoadGraph::GetFakeIngoingEdges(geometry::PointWithAltitude const & junctio
{
auto const it = m_fakeIngoingEdges.find(junction);
if (it != m_fakeIngoingEdges.cend())
edges.insert(edges.end(), it->second.cbegin(), it->second.cend());
edges.append(it->second.cbegin(), it->second.cend());
}
void IRoadGraph::ResetFakes()

View file

@ -66,7 +66,7 @@ void TransitWorldGraph::GetEdgeList(astar::VertexData<Segment, RouteWeight> cons
fakeFromReal.emplace_back(s, edge.GetWeight());
}
}
edges.insert(edges.end(), fakeFromReal.begin(), fakeFromReal.end());
edges.append(fakeFromReal.begin(), fakeFromReal.end());
}
void TransitWorldGraph::GetEdgeList(