Since the dawn of times (FG commit
1bcaf4bfdd38f18ac7c375dd9319935ff3df56ac, where SGBinding was called
FGBinding), SGBinding's destructor has had a strange behavior:
SGBinding::~SGBinding()
{
if(_arg && _arg->getParent())
_arg->getParent()->removeChild(_arg->getName(), _arg->getIndex());
}
In other words, it used to remove the passed-in <binding> node from its
parent node (if any) once the SGBinding instance got destroyed. This
behavior is very unintuitive to several people and has resulted in a few
workarounds in the FG code base just to cope with this strangeness.
This commit gives SGBinding the implictly-generated destructor,
therefore SGBinding::~SGBinding() does not attempt to remove the
property node anymore.
See disussion at:
https://sourceforge.net/p/flightgear/mailman/flightgear-devel/thread/87d12b1h0h.fsf%40frougon.crabdance.com/#msg36190666
this is to use some kind of utc time for timestamps in mp protocol,
to improve the lag correction system for mp planes, using a
"real time" mode when possible.
Remove an apparently bogus portability workaround (which was presumably
targetting one of the bugs fixed in the previous commit [1]) and further
simplify the code using std::find().
[1] da099d4312/
Explicitly enable the CMP0067 policy to have try_compile use the correct
C/C++ standard flags; otherwise, CMake will default to not honoring those,
causing the C/C++ checks to be compiled with no standard flags and SimGear
to be compiled with them. This causes errors if we try to detect a new
prototype which is only present in C++14 and above).
Indent the test code in a nicer way and shorten it, taking advantage of
this guarantee from the C++ standard:
If control reaches the end of main without encountering a return
statement, the effect is that of executing return 0.
-> no need for "#include <cstdlib>" nor for "return EXIT_SUCCESS".
Define HAVE_WORKING_STD_REGEX if, and only if <regex> is usable.
Normally, <regex> should be available and working in any compliant C++11
implementation, however at least g++ 4.8[1] lies about its C++11
compliance: its <regex> is utterly unusable, see [2] and [3] for
details.
[1] Which appears to be (precisely 4.8.5) the version shipped in
CentOS 7, and used on FlightGear's current Jenkins installation.
[2] https://stackoverflow.com/a/12665408/4756009
[3] https://sourceforge.net/p/flightgear/mailman/message/36170781/
Calling a virtual method in a destructor has undefined behaviour.
Furthermore passing 'this' to nasal from within the destructor
is not safe. 'onRemove' is called for widgets within layouts
on destruction anyhow, so no need to call it here again. If widgets
are arranged manually without any layout 'onRemoved' should be
called upon removing them from a dialog.
This allows one to use SGPath in containers such as std::map,
std::unordered_map and std::unordered_set.
Like the existing == and !=, all these operators rely solely on the
UTF-8 internal representation of the path.
We'll use this to cleanly declare std::hash<SGPath> as 'noexcept' in the
next commit, which appears to be desirable for std::hash template
specializations, according to:
http://en.cppreference.com/w/cpp/utility/hash
This is done by simply not user-defining the copy constructor,
copy-assignment operator and destructor. See [1] for more info.
[1] http://accu.org/content/conf2014/Howard_Hinnant_Accu_2014.pdf
For the benchmark below (compiled with the next commit to allow sorting
SGPath instances), on Linux amd64 with g++ 6.3.0, I observe that
enabling SGPath move operations with this commit increases the
performance by 31% or 28% respectively, depending on whether I use this:
// Typical code that creates a data structure in several steps and
// benefits from move operations (the std::move() does nothing when
// running the test with move operations disabled: a copy is made).
auto p = SGPath::fromUtf8(randomString(0, 30));
v.emplace_back(std::move(p));
or that:
v.emplace_back(randomString(0, 30))
for the initialization code. Now the benchmark code:
using std::string;
static std::default_random_engine randomNumbersGenerator;
// Utility function: generate a random string whose length is in the
// [minLen, maxLen] range.
string randomString(string::size_type minLen, string::size_type maxLen)
{
std::uniform_int_distribution<string::size_type> sLenDist(minLen, maxLen);
std::uniform_int_distribution<int> byteDist(0, 255);
auto randomByte = std::bind(byteDist, randomNumbersGenerator);
string::size_type len = sLenDist(randomNumbersGenerator);
string str;
while (str.size() < len) {
str += std::char_traits<char>::to_char_type(randomByte());
}
return str;
}
// The test function, run with nbIterations = 500000, minSize = 0 and
// maxSize = 200 to obtain the figures given above.
void SGPath_perfTest(std::size_t nbIterations,
std::size_t minSize, std::size_t maxSize)
{
std::uniform_int_distribution<std::size_t> sizeDist(minSize, maxSize);
auto randomSize = std::bind(sizeDist, randomNumbersGenerator);
std::chrono::time_point<std::chrono::system_clock> start, end;
start = std::chrono::system_clock::now();
vector<SGPath> v;
for (std::size_t i=0; i < nbIterations; i++) {
v = vector<SGPath>{}; // start anew
for (std::size_t j=0; j < randomSize(); j++) {
v.emplace_back(randomString(0, 30));
}
std::shuffle(v.begin(), v.end(), randomNumbersGenerator);
std::sort(v.begin(), v.end());
}
end = std::chrono::system_clock::now();
std::chrono::duration<double> elapsedSecs = end - start;
std::cout << elapsedSecs.count() << "\n"; // duration in seconds
}