STL Sort with no deal breaker - sorting

Our game engine uses STL sort for sorting a whole range of different objects using the template sort function. As I understand the requirements for the comparison logic is that you have to write it on the basis that it may internally do a reverse sort ( ie reverse the pairing eg. from (a,b) to (b,a) ).
So typically my compare functions looks like this:
bool CompareSubGroupReqsByDescendingFillPriority::operator()
( const ScenSubGroupReq& lhs,
const ScenSubGroupReq& rhs ) const
{
if( lhs.mFillPriority > rhs.mFillPriority ) return true;
else if( lhs.mFillPriority < rhs.mFillPriority ) return false;
else return lhs.mForceGroup->ObjectID() > rhs.mForceGroup->ObjectID();
}
I refer to the "else" statement as the "deal breaker" - ie. it must be able to resolve a case where both lhs and rhs are the same. I typically use the object ID where we are sorting persistent objects.
My question is how can you create a deal breaker when you are sorting non-persistent objects that are simple data types (eg shorts)?
Here is the example I am wrestling with:
bool
ComparePhaseLineIndexesByAscendingValue::operator() ( const short lhs,
const short rhs ) const
{
if( lhs < rhs ) return true;
else if( lhs > rhs ) return false;
else
{
// should never be here as no two phase lines should have the same index
FPAssert( false );
return false;
}
}
Trouble is I have been testing this and found a valid case where where I can have two phase lines with the same index. I don't care which of the entries with the same value ends up first.
What would you advise?

Technically the sort function takes the less than operator. What you are trying to do seems to have something to do with making sure that even equal objects are returned in a specific order. Generally you would just do
bool
ComparePhaseLineIndexesByAscendingValue::operator() ( const short lhs,
const short rhs ) const
{
return lhs < rhs;
}
Though generally a comparison function isn't required for builtin types (I think it's any type with a < operator specified).

Related

Referencing / dereferencing a vector element in a for loop

In the code below, I want to retain number_list, after iterating over it, since the .into_iter() that for uses by default will consume. Thus, I am assuming that n: &i32 and I can get the value of n by dereferencing.
fn main() {
let number_list = vec![24, 34, 100, 65];
let mut largest = number_list[0];
for n in &number_list {
if *n > largest {
largest = *n;
}
}
println!("{}", largest);
}
It was revealed to me that instead of this, we can use &n as a 'pattern':
fn main() {
let number_list = vec![24, 34, 100, 65];
let mut largest = number_list[0];
for &n in &number_list {
if n > largest {
largest = n;
}
}
println!("{}", largest);
number_list;
}
My confusion (and bear in mind I haven't covered patterns) is that I would expect that since n: &i32, then &n: &&i32 rather than it resolving to the value (if a double ref is even possible). Why does this happen, and does the meaning of & differ depending on context?
It can help to think of a reference as a kind of container. For comparison, consider Option, where we can "unwrap" the value using pattern-matching, for example in an if let statement:
let n = 100;
let opt = Some(n);
if let Some(p) = opt {
// do something with p
}
We call Some and None constructors for Option, because they each produce a value of type Option. In the same way, you can think of & as a constructor for a reference. And the syntax is symmetric:
let n = 100;
let reference = &n;
if let &p = reference {
// do something with p
}
You can use this feature in any place where you are binding a value to a variable, which happens all over the place. For example:
if let, as above
match expressions:
match opt {
Some(1) => { ... },
Some(p) => { ... },
None => { ... },
}
match reference {
&1 => { ... },
&p => { ... },
}
In function arguments:
fn foo(&p: &i32) { ... }
Loops:
for &p in iter_of_i32_refs {
...
}
And probably more.
Note that the last two won't work for Option because they would panic if a None was found instead of a Some, but that can't happen with references because they only have one constructor, &.
does the meaning of & differ depending on context?
Hopefully, if you can interpret & as a constructor instead of an operator, then you'll see that its meaning doesn't change. It's a pretty cool feature of Rust that you can use constructors on the right hand side of an expression for creating values and on the left hand side for taking them apart (destructuring).
As apart from other languages (C++), &n in this case isn't a reference, but pattern matching, which means that this is expecting a reference.
The opposite of this would be ref n which would give you &&i32 as a type.
This is also the case for closures, e.g.
(0..).filter(|&idx| idx < 10)...
Please note, that this will move the variable, e.g. you cannot do this with types, that don't implement the Copy trait.
My confusion (and bear in mind I haven't covered patterns) is that I would expect that since n: &i32, then &n: &&i32 rather than it resolving to the value (if a double ref is even possible). Why does this happen, and does the meaning of & differ depending on context?
When you do pattern matching (for example when you write for &n in &number_list), you're not saying that n is an &i32, instead you are saying that &n (the pattern) is an &i32 (the expression) from which the compiler infers that n is an i32.
Similar things happen for all kinds of pattern, for example when pattern-matching in if let Some (x) = Some (42) { /* … */ } we are saying that Some (x) is Some (42), therefore x is 42.

How to compare enum in arduino?

I am facing an issue with arduino, since I want to change the state of my device using an enum, but it doesn't seeem to work, my code looks like below. I am not entirely sure where it goes wrong, I think as well that the comparison between settingTo and toP2P could be wrong?
Thanks in advance!
String toP2P = "503250"
String toABP = "414250";
String settingTo = LoRa_Tx.dataRX.substring(indx);
if( settingTo == toP2P ) {
//switching to P2P
Serial.println("current mode 1 "+(String) LoRa_Tx.current_modeRxTx);
if(LoRa_Tx.current_modeRxTx != LoRa_Tx.LoRaMod){
LoRa_Tx.current_modeRxTx = LoRa_Tx.LoRaMod;
}
} else if(settingTo == toABP){
//switching to ABP
if(LoRa_Tx.current_modeRxTx != LoRa_Tx.LoRaWan){
LoRa_Tx.current_modeRxTx = LoRa_Tx.LoRaWan;}
}
}
My class has the enum defined as
typedef enum modeRxTx{LoRaMod, LoRaWan, Idle} ;
modeRxTx current_modeRxTx = Idle;
In general, you should avoid the String class, as it will eventually cause problems. However, given that the LoRa_Tx appears to have a String member, here is one way to watch for those two modes:
if ((indx > -1) && (LoRa_Tx.dataRx.length() >= indx+5)) {
const char *settingTo = &LoRa_Tx.dataRx.c_str()[ indx ];
if ( strncmp_P( settingTo, PSTR("503250"), 6 ) == 0 ) {
//switching to P2P
Serial.print( F("current mode 1 ") ); // <-- saves RAM!
Serial.println( LoRa_Tx.current_modeRxTx );
if(LoRa_Tx.current_modeRxTx != LoRa_Tx.LoRaMod) {
LoRa_Tx.current_modeRxTx = LoRa_Tx.LoRaMod;
}
} else if ( strncmp_P( settingTo, PSTR("414250"), 6 ) == 0 ) {
//switching to ABP
if(LoRa_Tx.current_modeRxTx != LoRa_Tx.LoRaWan) {
LoRa_Tx.current_modeRxTx = LoRa_Tx.LoRaWan;
}
}
}
Instead of creating a substring, it just makes a pointer to the actual characters of data_Rx. The c_str() function returns a pointer to the first character (zero-based index) or the String, and the [ indx ] is the first of the mode number characters. Finally, the & is a pointer to the first mode number character.
Next, it uses a standard library function, strncmp_P (documented here), to compare those mode number characters with the modes you are looking for, and it only compares up to 6 characters. You don't say if there's a delimiter after "503250", so I don't know if "50325076" is possible and should be rejected.
The strncmp_P expects to get a PROGMEM string as the second argument, not just a const char *, so that's what the PSTR macro does. This saves RAM because the PSTR will be stored and compared from FLASH memory (aka PROGMEM). The Serial.print statements should use the F() macro for the same reason.

'Open' - undeclared identifier

Does somebody know why this code inside a .mqh file throws the error 'Open' - undeclared identifier?
It seems like Open, Close, High, Low functions aren´t "detected" in my library. ( Other system functions like Print() are properly loaded ).
bool isBlueCandle( int candle ) export {
return Open[candle] < Close[candle];
}
Not exactly, neither 1:1 copy, nor any MODs, return any error:
//+------------------------------------------------------------------+
//| isBlueCandle TESTs MetaLang.exe: Build 1154 |
//+------------------------------------------------------------------+
bool isBlueCANDLE_TEST( int candle ) export
{
return Open[candle] < Close[candle];
}
bool isBlueCANDLE_TEST2( int candle ) export {
return Open[candle] < Close[candle];
}
bool isBlueCANDLE_TEST3( const int candle ) export {
return Open[candle] < Close[candle];
}
bool isBlueCANDLE_TEST4( const int candle ) export {
return( Open[candle] < Close[candle] );
}
As posted in the comment above, the missing context would help trace the root-cause for your stated issue.
Post a complete copy of the MetaLang.exe Error-description.
Use mouse-right-click + copy ( in MetaLang.exe-Toolbox window on [Error]-page + paste that complete description on StackOverflow )
As an example:
return value of 'OrderModify' should be checked
FOREX_SimpleSAR_EA_msMOD_0.00.mq4 227 19
Just for a clarity sake:
MQL4 recognises both functions ( Print() ) and other objects ( Open ) with specific access-protocol to work with them. In case of functions, one passes "arguments" compatible with the function´s expectations.
Open, High, Volume et al, are not functions, but Arrays, the more, these arrays are special and carefully constructed in the internal MT4-engine, so as to provide a very fast & very efficient manipulation.
MetaQuotes call this a TimeSeries-object, a reversed-stepping-index into
( otherwise normal ) array.
So, your function isBlueCandle() is indeed a function, however, internally it does not call a function, but it compares a cell-values of Open ( the [anIntIndexAsPtrIntoTimeSeriesOrderedARRAY]-*referenced cell )
against a value of Close ( namely the [anIntIndexAsPtrIntoTimeSeriesOrderedARRAY]-*referenced cell ) to construct a bool which the isBlueCandle() function is about to return.

Sorting on unordered_sets

I have a list of items that are created each frame and need to be sorted.
Each Item's first member variable to sort by is an unordered_set.
I've moved this to an ordered set everywhere in the system so I can sort it in the list of items. But I'm suffering a performance hit in another are of the code foe this.
Bearing in mind that each item will be destroyed and be recreated on a per-frame basis, is there anything I can do to hold these in unordered_sets and sort them?
class item
{
public:
unordered_set< int > _sortUS;
int _sortI;
//Other members to sort
bool operator<( const item& that ) const
{
if( _sortI != that._sortI )
{
return _sortI < that._sortI;
}
else if( _sortUS != that._sortUS )
{
return ??? // this is what I need. I don't know how to compare these without converting them to sets
}
}
};
Given std::unordered_set<Key, Hash> for arbitrary hashable Key, you could define
template<class Key, class Hash = std::hash<Key>>
bool operator< (std::unordered_set<Key, Hash> const& L, std::unordered_set<Key, Hash> const& R)
{
return std::lexicographical_compare(
begin(L), end(L), begin(R), end(R),
[](Key const& kL, Key const& kR) {
return Hash()(kL) < Hash()(kR);
});
}
which will use the ordering on hash indices of Key. You can then define an ordering on item
bool operator< (item const& L, item const& R)
{
return std::tie(L.sortI, L.sortUS) < std::tie(R.sortI, R.sortUS);
}
and std::tie will make a std::tuple out of references to the members of your item so that you can use the operator< from std::tuple.
NOTE: you can easily prove that the above comparison is a StrictWeakOrder (a requirement for std::sort) since both the std::tuple comparison and the lexicographical_compare have this property.
However, the ordering of unordered_set is very unusual in other respects.
the hashed key index doesn't correspond to the order in which you iterate over elements (there is some modulo operation that maps hashed keys to indices in the container)
adding elements to an unordered_set can result in rehashing and invalidation of previous orderering

C++ STL priority_queue with struct Clearification

I have looked over this thread which talks about using this method for comparison:
struct thing
{
int a;
char b;
bool operator<(const thing &o) const
{
return a < o.a;
}
};
priority_queue<thing> pq;
On the other hand other uses method such as this:
struct Time {
int h;
int m;
int s;
};
class CompareTime {
public:
bool operator()(Time& t1, Time& t2) // Returns true if t1 is earlier than t2
{
if (t1.h < t2.h) return true;
if (t1.h == t2.h && t1.m < t2.m) return true;
if (t1.h == t2.h && t1.m == t2.m && t1.s < t2.s) return true;
return false;
}
}
priority_queue<Time, vector<Time>, CompareTime> pq;
While I logic myself with the first method, I don't quit understand the second method. Mostly because of the syntax. I am not quit sure what the overloading operator operator() means. What is that operator overloading?
Also, from cplusplus on priority_queue, I don't quite understand the following, mainly the second parameter.
template < class T, class Container = vector<T>,
class Compare = less<typename Container::value_type> > class priority_queue;
In another word, I don't understand the second method and its calling convention.
Also, what's the difference and which method is preferred?
I am not quit sure what the overloading operator operator() means.
What is that operator overloading?
What we have here is an overloading of the function call operator (see SO question) , this means that client code can 'treat' the CompareTime class instances as compare functions :
CompareTime ct;
if ( ct(t1, t2) )
{
...
}
I don't quite understand the following, mainly the second parameter.
The cplusplus reference summarizes quite well , the template parameters :
0 arg - The type of the objects within the queue.
1 arg - The underlying container/data structure for the queue, by
default its the std vector
2 arg - Operation on priority queue relies on some precedence
comparison, i.e. which item in the queue should be 'before' other item (see also Wikipedia , so this arg accepts to have compare object (functor) which mean instances of plain class which overload the () operator , the default is the std less functor which is simply a wrapper above the '<' semantics (boolean 2 valued function object).
// TEMPLATE STRUCT less
template<class _Ty>
struct less : public binary_function<_Ty, _Ty, bool>
{
// functor for operator<
bool operator()(const _Ty& _Left, const _Ty& _Right) const
{
// apply operator< to operands
return (_Left < _Right);
}
};

Resources