Skip to content
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

PR for Modernizing for C++11: replacing instances of SmallVector #6817

Closed
wants to merge 30 commits into from

Conversation

M3Henry
Copy link
Contributor

@M3Henry M3Henry commented Jun 6, 2018

After discussions on IRC about modernising the code to make it easier to work on, replacing non time-critical instances of SmallVector<T,S> with std::vector was deemed more practical than making SmallVector STL-like.

This allows use of range-based for loops and STL algorithms to improve expressiveness in the code base.

No changes to functionality have been made.

#6649

M3Henry added 30 commits June 6, 2018 16:58
@LordAro
Copy link
Member

LordAro commented Jun 6, 2018

Some build system changes will be needed to enforce c++11/14

@nielsmh
Copy link
Contributor

nielsmh commented Jun 23, 2018

LinkGraphJob::NodeAnnotationVector and GUIBridgeList (in bridge_gui.cpp) are both vectors of non-POD data types so those two are the real important ones to fix.

The former does get fixed by these changes, but GUIBridgeList does not, and from my cursory check it might be more complex to fix that one. The reason the contained data is non-POD is because of the inclusion of Money fields, that type has custom constructors which makes it non-POD.

Copy link
Member

@TrueBrain TrueBrain left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry for the slow responses; we have not forgotten about this PR. I did a fast pass on the code, and "it looks fine". The main issue with patches like this is of course that reviewing takes a bit of time ;)

As mentioned earlier, it would also need some changes to the configure system, as it should detect if the used compiler can handle C++11, and warn if not. Otherwise we will have a bug-tracker full of the same error in no time :)

So please bare with us while we prepare for modern standards ;)

@@ -102,7 +102,18 @@ static void NetworkFindBroadcastIPsInternal(NetworkAddressList *broadcast) // GE
if (ifa->ifa_broadaddr->sa_family != AF_INET) continue;

NetworkAddress addr(ifa->ifa_broadaddr, sizeof(sockaddr));
if (!broadcast->Contains(addr)) *broadcast->Append() = addr;
//if (!broadcast->Contains(addr)) *broadcast->Append() = addr;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I feel that this was by accident?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The removal was intentional, lines 108-116 replace it, but I shouldn't have left it commented out.
TBH the following would be much better than a hand rolled loop.

if (broadcast->end() == std::find(broadcast->begin(), broadcast->end(), addr)
    broadcast->push_back(addr);

@M3Henry
Copy link
Contributor Author

M3Henry commented Jul 27, 2018

@TrueBrain If the intention is to keep modernizing the code, then I can go over this patch series and do it properly. Looking back on this, it doesn't seem I put forward my best.

@M3Henry M3Henry closed this Jul 27, 2018
@M3Henry M3Henry reopened this Jul 27, 2018
Copy link
Member

@LordAro LordAro left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

First pass at an actual review, mostly codestyle related.

Firstly, great job on actually getting this done and working - it's a huge amount of effort (I tried SmallMap once, I gave up pretty quickly)

However, if I'm honest, I'm not sure this will ever get merged in its current form. There are just too many separate changes all bundled together. It would be better if it were a separate commit per change, rather than per file/type. Something like a commit to add new adapter functions, then one that actually converts types & functions (huge commit, but fundamentally quite simple to read through), then followed by a few commits that "neaten" usage (for loops, auto, etc)

Couple general comments:

  • Usage of and, or & not instead of &&, || & !
  • Lots of uses of auto here. Its desired usage in OTTD is yet to be formalised, but IMO it should only be used when the type of the variable doesn't matter, or if the typename has already been stated somewhere nearby. There's a few places in which that's not happened

@@ -7,14 +7,131 @@
* See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <http://www.gnu.org/licenses/>.
*/

/** @file smallvec_type.hpp Simple vector class that allows allocating an item without the need to copy this->data needlessly. */
/** @file smallvec_type.hpp Simple vector class that allows allocating an item without the need to copy this->data needlessly.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

text should be on a separate line, to preserve alignment

(applies to lots of functions)

* @tparam T the contained type of the vector
*/
template <typename T>
typename std::vector<T>::const_iterator Find(const std::vector<T>& vec, const T& elem) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

opening brace of a function should be on a newline

(applies to various functions)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
typename std::vector<T>::const_iterator Find(const std::vector<T>& vec, const T& elem) {
typename std::vector<T>::const_iterator Find(const std::vector<T>& vec, const T& elem)
{

* @param vec the vector to be searched
* @param elem the element to search for
* @tparam T the contained type of the vector
*/
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

missing @return doxygen command

(applies to various functions)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
*/
* @return an iterator to the position of the element if it was found. vec.end() otherwise.
*/

@@ -77,7 +77,7 @@ static inline int32 BigMulS(const int32 a, const int32 b, const uint8 shift)
return (int32)((int64)a * (int64)b >> shift);
}

typedef SmallVector<Industry *, 16> SmallIndustryList;
using SmallIndustryList = std::vector<Industry *> ;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

extra space before ;

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
using SmallIndustryList = std::vector<Industry *> ;
using SmallIndustryList = std::vector<Industry *>;

@@ -397,7 +397,7 @@ static void FiosGetFileList(SaveLoadOperation fop, fios_getlist_callback_proc *c
{
SortingBits order = _savegame_sort_order;
_savegame_sort_order = SORT_BY_NAME | SORT_ASCENDING;
QSortT(file_list.files.Begin(), file_list.files.Length(), CompareFiosItems);
QSortT(file_list.files.data(), file_list.Length(), CompareFiosItems);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's a bit more work involved, but since you're converting some stuff in this PR other than just converting SmallVector, perhaps converting to use std::sort would be a good idea as well

Alternatively, it should be a separate PR (along with the various other changes in this PR) :)

Copy link
Contributor Author

@M3Henry M3Henry Sep 19, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree that the standard algorithms would be ideal where applicable, a seperate PR would make most sense.

Copy link
Contributor

@fsimonis fsimonis Jan 23, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here an untested suggestion: (at least #include<algorithm> is missing)

Suggested change
QSortT(file_list.files.data(), file_list.Length(), CompareFiosItems);
std::sort(file_list.files.data(), file_list.files.data() + file_list.Length(), CompareFiosItems);

/** Get the end of the content inf iterator. */
ConstContentIterator End() const { return this->infos.End(); }
ConstContentIterator End() const { return this->infos.end(); }
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks like another class that could be refactored to be "better", instead of reimplementing a load of std::vector functions

}
else ++ts;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

braces required here

src/texteff.cpp Show resolved Hide resolved
w->lateness_counter = 0;
ClrBit(w->vehicle_flags, VF_TIMETABLE_STARTED);
/* Do multiplication, then division to reduce rounding errors. */
w->timetable_start = start_date + idx * total_duration / num_vehs / DAY_TICKS;
w->timetable_start = start_date + idx++ * total_duration / num_vehs / DAY_TICKS;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

idx++ in the middle is a bit scary, should probably be in a separate statement

* @tparam T the contained type of the vector
*/
template <typename T>
void Reset(std::vector<T>& vec) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

pretty sure this function isn't necessary - can be replaced with a clear() - the capacity reduction was just due to how the allocations worked

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It may be a good idea to keep the capacity reduction where it is used in case that behavior is desired.
According to cppreference: "Leaves the capacity() of the vector unchanged"

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

shrink_to_fit is only a request which may be ignored.
The guaranteed implementation looks like this:

template <typename T>
void Reset(std::vector<T>& vec) {
  std::vector<T>{}.swap(vec);
}

@M3Henry
Copy link
Contributor Author

M3Henry commented Sep 19, 2018

@LordAro
Rather than doing once large PR for a bunch of types at once, would it make more sense to submit one PR per type and do a proper conversion using standard algorithms with each one? (To avoid a PR flood I'd submit the next PR once the previous one is accepted)

@LordAro LordAro added the wip Work in progress. Feature branch that will require feedback during the development process label Oct 27, 2018
@TrueBrain
Copy link
Member

We recently switched from Jenkins as CI to Azure Pipelines as CI. This means you need to rebase before this Pull Request will pass its checks. Sorry for the troubles! (might not be applicable to this PR)

@andythenorth andythenorth added question Further information is requested stale Stale issues labels Jan 6, 2019
@nielsmh
Copy link
Contributor

nielsmh commented Jan 21, 2019

@M3Henry Yes I think several smaller PRs would be easier to integrate.

With the new build infrastructure I think usage of C++11 and possibly C++14 is good to go too.

@M3Henry
Copy link
Contributor Author

M3Henry commented Jan 21, 2019 via email

* @param vec the vector to be searched
* @param elem the element to search for
* @tparam T the contained type of the vector
*/
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
*/
* @return true if vec contains elem. false otherwise.
*/

* @param vec the vector to be searched
* @param elem the element to count instances of
* @tparam T the contained type of the vector
*/
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
*/
* @return the number of occurrences.
*/

* @param elem the element to add for and remove if missing
* @tparam T the contained type of the vector
* @tparam U the universal reference type for perfect forwarding
*/
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
*/
* @return true if the element had to be added.
*/

/** Remove an element referenced in the vector and move the last element to take its place.
* @param vec the vector to be modified
* @param it the element to remove
* @tparam T the contained type of the vector
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
* @tparam T the contained type of the vector
* @tparam T the contained type of the vector
* @return the iterator it

* @param vec the vector to be modified
* @param elem the element to search for and remove if found
* @tparam T the contained type of the vector
*/
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
*/
* @return true if the element was removed, false if it was not found.
*/

/** Extend a vector by an amount and return an iterator to the new elements.
* @param vec the vector to be modified
* @param num the number of elements to add
* @tparam T the contained type of the vector
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
* @tparam T the contained type of the vector
* @tparam T the contained type of the vector
* @return an iterator to the first of the added elements.

@@ -131,7 +131,7 @@ class FileList {
*/
inline const FiosItem *Begin() const
{
return this->files.Begin();
return this->files.data();
Copy link
Contributor

@fsimonis fsimonis Jan 23, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Make sure the vector contains files.

Suggested change
return this->files.data();
return &(this->files->at(0));

@@ -149,7 +149,7 @@ class FileList {
*/
inline const FiosItem *Get(uint index) const
{
return this->files.Get(index);
return this->files.data() + index;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
return this->files.data() + index;
return &(this->files.at(index));

@@ -158,7 +158,7 @@ class FileList {
*/
inline FiosItem *Get(uint index)
{
return this->files.Get(index);
return this->files.data() + index;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
return this->files.data() + index;
return &(this->files.at(index));

}

/** Compact the list down to the smallest block size boundary. */
inline void Compact()
{
this->files.Compact();
this->files.shrink_to_fit();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Use the "swap-trick" to force the shrink.

Suggested change
this->files.shrink_to_fit();
decltype(files)(this->files).swap(this->files);

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
question Further information is requested stale Stale issues waiting on author wip Work in progress. Feature branch that will require feedback during the development process
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

6 participants