-
Notifications
You must be signed in to change notification settings - Fork 0
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
initial version of InlineVector #3
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also could you add modifiers like
clear
push_back
emplace_back
pop_back
resize
Please refer to the std::vector
implementation.
The rest of modifiers like
insert
emplace
erase
swap
probably are not so important, but much mor complex.
src/include/miopen/inline_vector.hpp
Outdated
|
||
InlineVector(std::initializer_list<T> _data) : real_size(_data.size()) | ||
{ | ||
if(_data.size() > N) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You can actually use real_size
here. It is already initialized.
(see the comment about real_size
itself down below)
src/include/miopen/inline_vector.hpp
Outdated
template <typename _InputIterator, typename = std::_RequireInputIter<_InputIterator>> | ||
InlineVector(_InputIterator first, _InputIterator last) | ||
{ | ||
if(std::distance(first, last) > N) | ||
{ | ||
MIOPEN_THROW("Input data size is bigger than InlineVector's capacity"); | ||
} | ||
std::copy(first, last, data.begin()); | ||
real_size = std::distance(first, last); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You can do exactly the same as in the InlineVector(std::initializer_list<T> _data)
constructor, like : real_size(std::distance(...))
.
src/include/miopen/inline_vector.hpp
Outdated
|
||
private: | ||
std::array<T, N> data; | ||
uint8_t real_size; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Even if real size (and N) can be relatively small, it's better keeping it as size_t
. Most probably from 3 to 7 bytes will be consumed by padding.
Also it is better to keep some consistency between all the container implementations and it's safer to assign anything to that size_t real_size
- assigning to int/uint8 may lead to some unexpected truncations.
src/include/miopen/inline_vector.hpp
Outdated
T& operator[](std::size_t n) { return data[n]; } | ||
|
||
const T& operator[](std::size_t n) const { return data[n]; } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would add method .at()
which checks the boundaries and throw.
src/include/miopen/inline_vector.hpp
Outdated
bool empty() const { return real_size == 0; } | ||
|
||
// Real size | ||
uint8_t size() const { return real_size; } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
uint8_t size() const { return real_size; } | |
uint8_t size() const noexcept { return real_size; } |
The other tiny methods should have noexcept
(like operators, iterators, etc, I guess almost all of the methods)
src/include/miopen/inline_vector.hpp
Outdated
std::reverse_iterator<T*> rend() { return std::reverse_iterator<T*>(begin()); } | ||
|
||
// Element access | ||
T& operator[](std::size_t n) { return data[n]; } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also front()
, back()
and data()
methods should be added.
auto first_not_one_in_v2 = | ||
std::find_if(in_v2.rbegin(), in_v2.rend(), [](int i) { return i != 1; }); | ||
auto first_note_one_v2 = std::find_if(v2.rbegin(), v2.rend(), [](int i) { return i != 1; }); | ||
EXPECT_EQ(*first_not_one_in_v2, *first_note_one_v2); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If something got broken, first_not_one_in_v2
can be end()
and EXPECT_EQ
has undefined behavior and does not check anything.
Probably std::distance
check should be done prior to the value check.
int sum_in_v1 = std::accumulate(in_v1.begin(), in_v1.end(), 0); | ||
int sum_v1 = std::accumulate(v1.begin(), v1.end(), 0); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I know that both vectors are 4, 2, 1
, but accumulating size_t
to int
usually is not a good idea (it's not just int sum
, the most important is the last parameter of std::accumulate
).
Probably it's simpler to make both vectors int
.
src/include/miopen/inline_vector.hpp
Outdated
const T* cbegin() const noexcept { return _data.cbegin(); } | ||
|
||
const T* cend() const noexcept { return (_data.cbegin() + real_size); } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
it automatically resolves a const
version
const T* cbegin() const noexcept { return _data.cbegin(); } | |
const T* cend() const noexcept { return (_data.cbegin() + real_size); } | |
const T* cbegin() const noexcept { return begin(); } | |
const T* cend() const noexcept { return end(); } |
src/include/miopen/inline_vector.hpp
Outdated
{ | ||
MIOPEN_THROW("Cannot get back element, InlineVector is empty"); | ||
} | ||
return *(end() - 1); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
return *(end() - 1); | |
return *std::prev(end());; |
Usually front/back functions do not check ranges. but probably it's ok.
src/include/miopen/inline_vector.hpp
Outdated
void resize(std::size_t n) | ||
{ | ||
if(n > N) | ||
{ | ||
MIOPEN_THROW("It is not possible to resize beyond capacity"); | ||
} | ||
|
||
real_size = n; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That is actually
void resize(std::size_t n) | |
{ | |
if(n > N) | |
{ | |
MIOPEN_THROW("It is not possible to resize beyond capacity"); | |
} | |
real_size = n; | |
} | |
void resize(std::size_t n) | |
{ | |
resize(n, T{}); | |
} |
src/include/miopen/inline_vector.hpp
Outdated
} | ||
|
||
// Remove element from the back | ||
void pop_back() noexcept { real_size = ((real_size - 1) >= 0) ? (real_size - 1) : 0; } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
void pop_back() noexcept { real_size = ((real_size - 1) >= 0) ? (real_size - 1) : 0; } | |
void pop_back() noexcept { real_size = (real_size > 1) ? (real_size - 1) : 0; } |
src/include/miopen/inline_vector.hpp
Outdated
void pop_back() noexcept { real_size = ((real_size - 1) >= 0) ? (real_size - 1) : 0; } | ||
|
||
// Clear | ||
constexpr void clear() noexcept { real_size = 0; } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That shouldn't be a constexpr
, unless we make some extra efforts to make the whole class constexpr friendly.
While capacity
can be, should be and it is constexpr.
ROCm#3408