Fixed routing bug. #326
|
@ -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]);
|
||||
![]() Ох, emplace не используется в таком контексте (ну или не надо использовать). Если ее так предусматривать, надо извращаться. Ох, emplace не используется в таком контексте (ну или не надо использовать). Если ее так предусматривать, надо извращаться.
![]() Я бы критически просмотрел ещё раз имеющиеся тесты 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"));
|
||||
|
|
|
@ -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
|
||||
![]() Может делать это внутри SwitchToDynamic, передавая размер? Может делать это внутри SwitchToDynamic, передавая размер?
![]() Можно, да Можно, да
|
||||
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)
|
||||
![]() Сигнатура не как у вектора, будут же много где копирования ненужные. Может обе оставить? Или добавить пушбэк с &&? Сигнатура не как у вектора, будут же много где копирования ненужные. Может обе оставить? Или добавить пушбэк с &&?
![]() 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)).
![]() Решил не усложнять и всегда принимать по значению - на самом деле экономии никакой не будет от 2-х сигнатур. Решил не усложнять и всегда принимать по значению - на самом деле экономии никакой не будет от 2-х сигнатур.
![]()
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 всегда вызывать, вместо обычной копирующей.
![]() так и делается, в любом случае будет одна копия так и делается, в любом случае будет одна копия
|
||||
{
|
||||
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;
|
||||
}
|
||||
};
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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(
|
||||
|
|
А есть такой же тест на emplace?