Skip to content

Commit 66ee94a

Browse files
authored
Merge pull request #2104 from lucabart97/iox-2082-fast-vector-on-pod
iox-#2082 faster vector on POD data
2 parents 55444bc + 687a426 commit 66ee94a

File tree

2 files changed

+108
-37
lines changed

2 files changed

+108
-37
lines changed

doc/website/release-notes/iceoryx-unreleased.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@
5555
- Switch to C++17 on all platforms [#2066](https://github.com/eclipse-iceoryx/iceoryx/issues/2066)
5656
- Implement `unsafe_raw_access` in `iox::string` and add `BufferInfo` struct [#1431](https://github.com/eclipse-iceoryx/iceoryx/issues/1431)
5757
- Add the introspection to the ROS release [\#2099](https://github.com/eclipse-iceoryx/iceoryx/issues/2099)
58+
- Fast POD data in `iox::vector` [#2082](https://github.com/eclipse-iceoryx/iceoryx/issues/2082)
5859

5960
**Bugfixes:**
6061

iceoryx_hoofs/container/include/iox/detail/vector.inl

Lines changed: 107 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,9 @@
1919

2020
#include "iox/vector.hpp"
2121

22+
#include <cstring> // std::memcpy, std::memmove
2223
#include <iostream>
24+
#include <type_traits>
2325

2426
namespace iox
2527
{
@@ -52,10 +54,14 @@ inline vector<T, Capacity>::vector(const uint64_t count) noexcept
5254
}
5355

5456
m_size = std::min(count, Capacity);
55-
for (uint64_t i{0U}; i < m_size; ++i)
57+
// If the type is a trivial class without member initialization the constructor would not initialize the data
58+
if constexpr (!(std::is_trivial<T>::value && std::is_class<T>::value))
5659
{
57-
// AXIVION Next Line AutosarC++19_03-A18.5.2, FaultDetection-IndirectAssignmentOverflow : False positive, it is a placement new. Size guaranteed by T.
58-
new (&at(i)) T();
60+
for (uint64_t i{0U}; i < m_size; ++i)
61+
{
62+
// AXIVION Next Line AutosarC++19_03-A18.5.2, FaultDetection-IndirectAssignmentOverflow : False positive, it is a placement new. Size guaranteed by T.
63+
new (&at_unchecked(i)) T();
64+
}
5965
}
6066
}
6167

@@ -84,19 +90,28 @@ inline vector<T, Capacity>& vector<T, Capacity>::operator=(const vector& rhs) no
8490
{
8591
uint64_t i{0U};
8692
const uint64_t rhsSize{rhs.size()};
87-
const uint64_t minSize{algorithm::minVal(m_size, rhsSize)};
8893

89-
// copy using copy assignment
90-
for (; i < minSize; ++i)
94+
if constexpr (std::is_trivially_copyable<T>::value)
9195
{
92-
// AXIVION Next Line AutosarC++19_03-A5.0.1 : Expands to basic variable assignment. Evaluation order is inconsequential.
93-
at(i) = rhs.at(i);
96+
std::memcpy(data(), rhs.data(), rhsSize * sizeof(T));
97+
i = rhsSize;
9498
}
95-
96-
// copy using copy ctor
97-
for (; i < rhsSize; ++i)
99+
else
98100
{
99-
IOX_DISCARD_RESULT(emplace_back(rhs.at(i)));
101+
const uint64_t minSize{algorithm::minVal(m_size, rhsSize)};
102+
103+
// copy using copy assignment
104+
for (; i < minSize; ++i)
105+
{
106+
// AXIVION Next Line AutosarC++19_03-A5.0.1 : Expands to basic variable assignment. Evaluation order is inconsequential.
107+
at(i) = rhs.at(i);
108+
}
109+
110+
// copy using copy ctor
111+
for (; i < rhsSize; ++i)
112+
{
113+
IOX_DISCARD_RESULT(emplace_back(rhs.at(i)));
114+
}
100115
}
101116

102117
// delete remaining elements
@@ -114,19 +129,28 @@ inline vector<T, Capacity>& vector<T, Capacity>::operator=(vector&& rhs) noexcep
114129
{
115130
uint64_t i{0U};
116131
const uint64_t rhsSize{rhs.size()};
117-
const uint64_t minSize{algorithm::minVal(m_size, rhsSize)};
118132

119-
// move using move assignment
120-
for (; i < minSize; ++i)
133+
if constexpr (std::is_trivially_copyable<T>::value)
121134
{
122-
// AXIVION Next Line AutosarC++19_03-A5.0.1 : Expands to basic variable assignment. Evaluation order is inconsequential.
123-
at(i) = std::move(rhs.at(i));
135+
std::memcpy(data(), rhs.data(), rhsSize * sizeof(T));
136+
i = rhsSize;
124137
}
125-
126-
// move using move ctor
127-
for (; i < rhsSize; ++i)
138+
else
128139
{
129-
IOX_DISCARD_RESULT(emplace_back(std::move(rhs.at(i))));
140+
const uint64_t minSize{algorithm::minVal(m_size, rhsSize)};
141+
142+
// move using move assignment
143+
for (; i < minSize; ++i)
144+
{
145+
// AXIVION Next Line AutosarC++19_03-A5.0.1 : Expands to basic variable assignment. Evaluation order is inconsequential.
146+
at(i) = std::move(rhs.at(i));
147+
}
148+
149+
// move using move ctor
150+
for (; i < rhsSize; ++i)
151+
{
152+
IOX_DISCARD_RESULT(emplace_back(std::move(rhs.at(i))));
153+
}
130154
}
131155

132156
// delete remaining elements
@@ -168,8 +192,15 @@ inline bool vector<T, Capacity>::emplace_back(Targs&&... args) noexcept
168192
{
169193
if (m_size < Capacity)
170194
{
171-
// AXIVION Next Line AutosarC++19_03-A5.0.1, FaultDetection-IndirectAssignmentOverflow: Size guaranteed by T. Evaluation order is inconsequential.
172-
new (&at(m_size++)) T(std::forward<Targs>(args)...);
195+
if constexpr (std::is_trivial<T>::value)
196+
{
197+
at_unchecked(m_size++) = T{std::forward<Targs>(args)...};
198+
}
199+
else
200+
{
201+
// AXIVION Next Line AutosarC++19_03-A5.0.1, FaultDetection-IndirectAssignmentOverflow: Size guaranteed by T. Evaluation order is inconsequential.
202+
new (&at_unchecked(m_size++)) T{std::forward<Targs>(args)...};
203+
}
173204
return true;
174205
}
175206
return false;
@@ -189,14 +220,26 @@ inline bool vector<T, Capacity>::emplace(const uint64_t position, Targs&&... arg
189220
{
190221
return emplace_back(std::forward<Targs>(args)...);
191222
}
192-
IOX_DISCARD_RESULT(emplace_back(std::move(at_unchecked(sizeBeforeEmplace - 1U))));
193-
for (uint64_t i{sizeBeforeEmplace - 1U}; i > position; --i)
223+
if constexpr (std::is_trivial<T>::value)
194224
{
195-
at_unchecked(i) = std::move(at_unchecked(i - 1U));
225+
resize(size() + 1U);
226+
const uint64_t dataLen{sizeBeforeEmplace - position};
227+
std::memmove(data() + position + 1U, data() + position, dataLen * sizeof(T));
228+
at_unchecked(position) = T{std::forward<Targs>(args)...};
229+
}
230+
else
231+
{
232+
IOX_DISCARD_RESULT(emplace_back(std::move(at_unchecked(sizeBeforeEmplace - 1U))));
233+
for (uint64_t i{sizeBeforeEmplace - 1U}; i > position; --i)
234+
{
235+
at_unchecked(i) = std::move(at_unchecked(i - 1U));
236+
}
237+
if constexpr (!std::is_trivially_destructible<T>::value)
238+
{
239+
at_unchecked(position).~T();
240+
}
241+
new (&at_unchecked(position)) T(std::forward<Targs>(args)...);
196242
}
197-
198-
at(position).~T();
199-
new (&at(position)) T(std::forward<Targs>(args)...);
200243
return true;
201244
}
202245

@@ -218,7 +261,14 @@ inline bool vector<T, Capacity>::pop_back() noexcept
218261
{
219262
if (m_size > 0U)
220263
{
221-
at_unchecked(--m_size).~T();
264+
if constexpr (std::is_trivial<T>::value)
265+
{
266+
m_size--;
267+
}
268+
else
269+
{
270+
at_unchecked(--m_size).~T();
271+
}
222272
return true;
223273
}
224274
return false;
@@ -359,13 +409,26 @@ inline bool vector<T, Capacity>::erase(iterator position) noexcept
359409
// AXIVION Next Line AutosarC++19_03-M5.0.9 : False positive. Pointer arithmetic occurs here.
360410
uint64_t index{static_cast<uint64_t>(position - begin())};
361411
uint64_t n{index};
362-
while ((n + 1U) < size())
412+
if constexpr (std::is_trivially_copyable<T>::value)
413+
{
414+
if constexpr (!(std::is_trivially_destructible<T>::value))
415+
{
416+
at_unchecked(n).~T();
417+
}
418+
uint64_t dataLen{size() - n - 1U};
419+
std::memmove(data() + n, data() + n + 1U, dataLen * sizeof(T));
420+
}
421+
else
363422
{
364-
// AXIVION Next Line AutosarC++19_03-A5.0.1 : Expands to basic variable assignment. Evaluation order is inconsequential.
365-
at(n) = std::move(at(n + 1U));
366-
++n;
423+
while ((n + 1U) < size())
424+
{
425+
// AXIVION Next Line AutosarC++19_03-A5.0.1 : Expands to basic variable assignment. Evaluation order is inconsequential.
426+
at_unchecked(n) = std::move(at(n + 1U));
427+
++n;
428+
}
429+
at_unchecked(n).~T();
367430
}
368-
at(n).~T();
431+
369432
m_size--;
370433
return true;
371434
}
@@ -391,9 +454,16 @@ inline const T& vector<T, Capacity>::at_unchecked(const uint64_t index) const no
391454
template <typename T, uint64_t Capacity>
392455
inline void vector<T, Capacity>::clearFrom(const uint64_t startPosition) noexcept
393456
{
394-
while (m_size > startPosition)
457+
if constexpr (std::is_trivially_destructible<T>::value)
395458
{
396-
at_unchecked(--m_size).~T();
459+
m_size = startPosition;
460+
}
461+
else
462+
{
463+
while (m_size > startPosition)
464+
{
465+
at_unchecked(--m_size).~T();
466+
}
397467
}
398468
}
399469

0 commit comments

Comments
 (0)