Risky operator incantations? - c++

I have read somewhere that overloading type coercion operators is risky. And I'm having some segfaults here and there. So, have I upset the hornets' nest? Here is my code:
template <typename Wee>
struct xl_type_proxy_t {
static_assert(
boost::mpl::or_<
boost::is_same< Wee, WORD > ,
boost::is_same< Wee, DWORD >
>::value, "xl_type_proxy: should instantiate correctly" );
Wee* where_to_drop;
xl_type_proxy_t( Wee* wtd):
where_to_drop( wtd )
{}
operator Wee() const {
// Return stuff with state bits cleared
//return xltypeNil;
return (*where_to_drop) & 0xAFFF;
}
xl_type_proxy_t& operator=( Wee w )
{
// Save only the flags that were already in
// 'where_to_drop'.
(*where_to_drop) = (*where_to_drop) & 0x5000;
// And now over-write the rest
(*where_to_drop) = (*where_to_drop) | w;
return *this;
}
};
...
xl_type_proxy_t< decltype(this->xl) > proxy_xl()
{
return xl_type_proxy_t<decltype(this->xl)>( &(this->xl));
}
... // In some places:
proxy_xl() = ... // Some numeric constant
... // In some others:
if ( proxy_xl() == /* some numeric constant */ )
{
...
}

Related

How does this default template struct assignment work? [duplicate]

This question already has answers here:
Arrow operator (->) in function heading
(3 answers)
Closed 4 months ago.
I have been digging into some embedded C++ firmware used by DaveJone's (eevblog) uSupply project
https://gitlab.com/eevblog/usupply-firmware.
There is common pattern of code that I just can't quite wrap my head around what is happening.
For example:
In the file "RegistersRCC.hpp" there is a template struct:
template <std::size_t A>
struct CR : public General::u32_reg<A>
{
using base_t = General::u32_reg<A>;
using base_t::base_t;
//PLL register bits
auto PLLRDY () { return base_t::template Actual<RCC_CR_PLLRDY>(); }
auto PLLON () { return base_t::template Actual<RCC_CR_PLLON>(); }
//PLL Management functions
void EnablePLL() noexcept
{
if ( not PLLON().Get() )
{
PLLON() = true;
while ( not PLLRDY().Get() );
}
}
void DisablePLL() noexcept
{
if ( PLLON().Get() )
{
PLLON() = false;
while ( PLLRDY().Get() );
}
}
//Enable clock security
auto CSSON () { return base_t::template Actual<RCC_CR_CSSON>(); }
//High speed external oscillator bits
auto HSEBYP () { return base_t::template Actual<RCC_CR_HSEBYP>(); }
auto HSERDY () { return base_t::template Actual<RCC_CR_HSERDY>(); }
auto HSEON () { return base_t::template Actual<RCC_CR_HSEON>(); }
//HSE Management functions
void EnableHSE()
{
if ( not HSEON().Get() )
{
HSEON() = true; //Enable the clock
while( not HSERDY().Get() ); //Wait for it to stable
}
}
void DisableHSE()
{
if ( HSEON().Get() )
{
HSEON() = false; //Disable the clock
while( HSERDY().Get() ); //Wait for it to disable
}
}
void ConnectHSE()
{
HSEBYP() = false; //Connect it to system
}
void BypassHSE()
{
HSEBYP() = true; //Disconnect it to system
}
//High speed internal oscillator bits
auto HSICAL () { return base_t::template Actual<RCC_CR_HSICAL>(); }
auto HSITRIM() { return base_t::template Actual<RCC_CR_HSITRIM>(); }
auto HSIRDY () { return base_t::template Actual<RCC_CR_HSIRDY>(); }
auto HSION () { return base_t::template Actual<RCC_CR_HSION>(); }
//HSI Management functions, No calibration provided
// these chips are factory calibrated
void EnableHSI()
{
if (not HSION().Get())
{
HSION() = true;
while (!HSIRDY());
}
}
void DisableHSI()
{
if ( HSION().Get() )
{
HSION() = false;
while (HSIRDY());
}
}
};
This struct exists in the namespace:
namespace Peripherals::RCCGeneral
{
}
Within the same namespace/header file there is this "Default"
CR() -> CR<RCC_BASE + offsetof(RCC_TypeDef, CR)>;
I think this is where my gap in understanding lies. What is happening here? Specifically with the lvalue and arrow operator, and why this is located within the header.
Within the files that utilize the RCCRegisters you see usages like:
CR{}.DisablePLL();
This is called class template argument deduction(CTAD) which allows writing deduction guides to the compiler about how to deduce the template arguments from constructor calls.
It is a handy C++17 addition that saves on typing:
std::vector x{1.,2.,3.} //deduces std::vector<double>
C++14 and older requires to explicitly write std::vector<double> which gets tedious and too verbose for some more complex examples.
In this case, the guide
CR() -> CR<RCC_BASE + offsetof(RCC_TypeDef, CR)>;
specifies that the default constructor should deduce A template parameter to RCC_BASE + offsetof(RCC_TypeDef, CR).
The same could have been achieved by simply using a default template argument:
template <std::size_t A = default_value>
struct CR : public General::u32_reg<A>{ ... };
But here comes the catch, offsetof(RCC_TypeDef, CR) is not valid here because at this line, CR doesn't exist yet.
So my assumption is this a fix around this limitation to allow making the default value depend on the class definition itself, quite clever I think.

Adding XPointer/XPath searches to ALL(?) C++ JSON libraries, is it doable?

Is it possible to extend all(?) existing C++ JSON libraries with XPath/XPointer or subset with just one C++ implementation? At least those with iterators for object and array values?
I have reviewed three C++ JSON libraries (reviewing nlohmann, Boost.JSON and RapidJSON) to see the internals and check their search functionality. Some have implemented Json pointer. Json pointer is basic, almost like working with json as a name-value list.
XML has XPath and XPointer searches and rules are standardized. With XPath and XPointer you can do more.
One reason to reviewing these libraries was to see if it is possible to extend any of them with better search functionality. Or might it be possible to extend all(?) C++ JSON libraries at once?
A longer text describing this can be found here, trying to be brief.
I tried to do one traverse method that selects json values with one specific property name and that method should work an all tested JSON libraries. If I got that to work it may be possible to add more search logic and get it to work on almost all C++ JSON.
I got this C++ templated function to work an all tested json libraries. It can walk the JSON tree and select json values on all tested libraries.
What is needed to is to implement specializations of is_object, is_array, compare_name, get_value, begin and end. That are just one liners so it's easy.
template<typename json_value>
bool is_object( const json_value* p )
{ static_assert(sizeof(json_value) == 0, "Only specializations of is_object is allowed"); }
template<typename json_value>
bool is_array( const json_value* p )
{ static_assert(sizeof(json_value) == 0, "Only specializations of is_array is allowed"); }
template<typename iterator>
bool compare_name( iterator it, std::string_view stringName )
{ static_assert(sizeof(it) == 0, "Only specializations of compare_name is allowed"); }
template<typename iterator, typename json_value>
const json_value* get_value( iterator it )
{ static_assert(sizeof(it) == 0, "Only specializations of get_value is allowed"); }
template<typename iterator, typename json_value>
iterator begin( const json_value& v ) { return std::begin( v ); }
template<typename iterator, typename json_value>
iterator end( const json_value& v ) { return std::end( v ); }
// ------------------------------------------------
// Selects all json values that match property name
template<typename json_value, typename object_iterator,typename array_iterator = object_iterator>
uint32_t select( const json_value& jsonValue, std::string_view stringQuery, std::vector<const json_value*>* pvectorValue = nullptr )
{ assert( is_object( &jsonValue ) || is_array( &jsonValue ) );
uint32_t uCount = 0;
if( is_object( &jsonValue ) == true ) // found object ?
{
for( auto it = begin<object_iterator,json_value>( jsonValue ); it != end<object_iterator,json_value>( jsonValue ); it++ )
{
if( is_object( get_value<object_iterator,json_value>( it ) ) == true )
{ // found object, scan it
auto value = get_value<object_iterator,json_value>( it );
uCount += select<json_value,object_iterator>( *value, stringQuery, pvectorValue );
}
else if( is_array( get_value<object_iterator,json_value>( it ) ) == true )
{ // found array, scan it
auto parray = get_value<object_iterator,json_value>( it );
uCount += select<json_value,object_iterator,array_iterator>( *parray, stringQuery, pvectorValue );
}
else if( compare_name<object_iterator>( it, stringQuery ) == true )
{ // property name matches, store value if pointer to vector
if( pvectorValue != nullptr ) pvectorValue->push_back( get_value<object_iterator,json_value>( it ) );
uCount++;
}
}
}
else if( is_array( &jsonValue ) == true ) // found array
{
for( auto it = begin<array_iterator,json_value>( jsonValue ); it != end<array_iterator,json_value>( jsonValue ); it++ )
{
if( is_object( get_value<array_iterator,json_value>( it ) ) == true )
{ // found object, scan it
auto value = get_value<array_iterator,json_value>( it );
uCount += select<json_value,object_iterator>( *value, stringQuery, pvectorValue );
}
else if( is_array( get_value<array_iterator,json_value>( it ) ) == true )
{ // found array, scan it
auto parray = get_value<array_iterator,json_value>( it );
uCount += select<json_value,object_iterator,array_iterator>( *parray, stringQuery, pvectorValue );
}
}
}
return uCount;
}
if this works and if I haven't forgot something, shouldn't it be possible to extend all libraries with just one implementation? The additional logic for XPath and XPointer is not dependent on the implementation of these C++ JSON libraries.
Am I missing something

CString used on static method

I am stuck into a problem, and I will be very grateful if you help me.
I have a MDI, and in CDocument class, I have a struct:
CMyDoc.h
class CMyDoc : public CDocument
{
...
struct SRecord
{
SRecord(){}
virtual ~SRecord(){}
CString sName;
CString sState;
CString sDateu;
CString sDatec;
};
CTypedPtrArray<CPtrArray, SRecord*> m_arrRecord;
and somewhere I load this struct with data:
SRecord* pItem = new SRecord;
pItem->sName = saItem.GetAt(ML_ASSETNAME);
pItem->sState = saItem.GetAt(ML_STATE);
pItem->sDateu = saItem.GetAt(ML_DATEU;
pItem->sDatec = saItem.GetAt(ML_DATEC);
m_arrRecord.Add(pItem);
ok. I am trying to sort data:
void CMyDoc::SortData(int nColumn, BOOL bAscending)
{
switch(nColumn)
{
case 9:
if(bAscending)qsort((void*)m_arrRecord.GetData(), m_arrRecord.GetSize(), sizeof(SRecord), CompareDateUAscending);
else qsort((void*)m_arrRecord.GetData(), m_arrRecord.GetSize(), sizeof(SRecord), CompareDateUDescending);
break;
...
}
but the problem become when data is access in static method:
int CMyDoc::CompareDateUDescending(const void* arg1, const void* arg2)
{
SRecord* Record1 = (SRecord*)arg1;
SRecord* Record2 = (SRecord*)arg2;
if(Record1->sDateu.IsEmpty() || Record2->sDateu.IsEmpty()) // <--- crash !
return 0;
COleDateTime dL, dR;
dL.ParseDateTime(Record1->sDateu);
dR.ParseDateTime(Record2->sDateu);
return (dL == dR ? 0 : (dL < dR ? 1 : -1));
}
and the crash take me here (atlsimpstr.h):
CStringData* GetData() const throw()
{
return( reinterpret_cast< CStringData* >( m_pszData )-1 ); // the crash lead me on this line
}
what I am doing wrong ?
Any help will be very appreciated !
Update:
I have tried this:
int CMyDoc::CompareDateUDescending(const void* arg1, const void* arg2)
{
SRecord* Record1 = *(SRecord**)arg1; // <-- OK
SRecord* Record2 = *(SRecord**)arg2; // <-- Unhandled exception* see note below
if(Record1->sDateu.IsEmpty() || Record2->sDateu.IsEmpty())
return 0;
COleDateTime dL, dR;
dL.ParseDateTime(Record1->sDateu);
dR.ParseDateTime(Record2->sDateu);
return (dL == dR ? 0 : (dL < dR ? 1 : -1));
}
and the crash told me:
"An unhandled exception was encountered during a user callback." strange ...
The qsort comparison function receives pointers to the elements in the array. But since the elements in the array are themselves pointers what your specific function receives as arguments are pointers to pointers to SRecord, i.e. SRecord**.
You can solve it by doing e.g.
const SRecord* Record1 = *reinterpret_cast<const SRecord**>(arg1);
That is, you cast arg1 to SRecord** and then dereference that pointer to get a SRecord*.
Example on how to use the C++ standard sort function.
First you need to update your comparison function a little:
// The comparison function should return true if Record1 is *smaller* than Record2,
// and return false otherwise
bool CMyDoc::CompareDateUDescending(const SRecord* Record1, const SRecord* Record2)
{
return Record1->sDateu < Record2->sDateu;
}
Then to call sort:
std::sort(m_arrRecord.GetData(), m_arrRecord.GetData() + m_arrRecord.GetSize(), CompareDateUDescending);
Much simpler!

C++ code refactoring for if scenario

I'm looking to refactor the c++ code for if conditions which will reduce the number of lines of code as well as it should have min complexity.
Here is the example:
if (xyz->a != cmd->aa)
{
xyz->a = cmd->aa;
obj->isFound = true; //common code for all ifs
}
if (xyz->b != cmd->bb)
{
xyz->b = cmd->bb;
obj->isFound = true;
}
And so on.. Here a, b, aa, bb are defined as a struct element.
Another example having if condition with arrays:
if (abc->r16[0] != cmd->r0m)
{
abc>r16[0] = cmd->r0m;
obj->isFound = true; //some common code for all ifs
}
if (abc->r16[1] != cmd->r1m)
{
abc>r16[1] = cmd->r1m;
obj->isFound = true; //some common code for all ifs
}
And so on for r16[0] to r16[15]. Here r16[15] is defined inside struct.
Last scenario is for if condition with multidimensional array:
if (pqr->c_0_15_r_0_15[0][0] != cmd->obj0000)
{
pqr->c_0_15_r_0_15[0][0] = cmd->obj0000
obj->isFound = true; //some common code for all ifs
}
if (pqr->c_0_15_r_0_15[1][0] != cmd->obj0100)
{
pqr->c_0_15_r_0_15[1][0] = cmd->obj0100
obj->isFound = true; //some common code for all ifs
}
if (pqr->c_0_15_r_0_15[2][0] != cmd->obj0000)
{
pqr->c_0_15_r_0_15[2][0] = cmd->obj0200
obj->isFound = true; //some common code for all ifs
}
Here c_0_15_r_0_15[2][0] will go through [0][0] to [15][0] and then [0][1] to [15][1] and so on...
For all such if condition scenario there will me 100's of if statements which should be reduced. How can we refactor such code?
First, find the duplication in your code. As you already aware - the following scheme is duplicated many times:
if (a != b)
{
a = b;
found = true;
}
So - encapsulate this in a function (template if there are multiple types:
template <typename Dst, typename Src>
inline void updateIfNeeded(Dst& dst, const Src& src, bool& wasNeeded)
{
if (dst != src)
{
dst = src;
wasNeeded = true;
}
}
See - how it helps:
updateIfNeeded(abc->r16[0], cmd->r0m, obj->isFound);
updateIfNeeded(abc->r16[1], cmd->r1m, obj->isFound);
// ...
updateIfNeeded(pqr->c_0_15_r_0_15[0][0], cmd->obj0000, obj->isFound);
updateIfNeeded(pqr->c_0_15_r_0_15[1][0], cmd->obj0100, obj->isFound);
// ...
So far - reduction is quite big - and it is much more readable what is going on in this code.
What I see more - obj->isFound is repeating many times - maybe - some encapsulation in a class this time:
class Updater
{
public:
bool anyUpdateWasNeeded = false;
template <typename Dst, typename Src>
void updateIfNeeded(Dst& dst, const Src& src)
{
if (dst != src)
{
dst = src;
anyUpdateWasNeeded = true;
}
}
};
You see - not needed to pass obj->isFound so many times:
Updater upd;
upd.updateIfNeeded(abc->r16[0], cmd->r0m);
upd.updateIfNeeded(abc->r16[1], cmd->r1m);
// ...
upd.updateIfNeeded(pqr->c_0_15_r_0_15[0][0], cmd->obj0000);
upd.updateIfNeeded(pqr->c_0_15_r_0_15[1][0], cmd->obj0100);
// ...
obj->isFound = upd.anyUpdateWasNeeded;
Frankly, at this point I would consider to use preprocessor - I mean to shorten all these arrays update - this is because on left you have arrays - on right you have many fields of similar names ("indexed" names...?)
But using preprocessor is bad style - let try to update arrays with pure C++:
class Updater
{
public:
bool anyUpdateWasNeeded = false;
template <typename Dst, typename Src>
void updateIfNeeded(Dst& dst, const Src& src);
template <typename Dst, typename Src1, typename ...Src>
void updateArrayIfNeeded(Dst* dst, const Src1& src1, const Src& ...src)
{
updateIfNeeded(*dst, src1);
updateArrayIfNeeded(dst + 1, src...);
}
template <typename Dst>
void updateArrayIfNeeded(Dst* dst)
{
// nothing left
}
};
So - this is what left:
upd.updateArrayIfNeeded(abc->r16, cmd->r0m, cmd->r1m, ....);
upd.updateArrayIfNeeded(pqr->c_0_15_r_0_15[0], cmd->obj0000, cmd->obj0001, ...);
upd.updateArrayIfNeeded(pqr->c_0_15_r_0_15[1], cmd->obj0100, ...);
// ...
obj->isFound = upd.anyUpdateWasNeeded;
And so on...
You can put it in some function, for a start:
template<typename Lhs, typename Rhs>
void flagSetIfNEq(Lhs & lhs, Rhs const & rhs, bool & flag) {
if (lhs != rhs) {
lhs = rhs;
flag = true;
}
}
// call it like
flagSetIfNEq(xyz->a, uvw->aa, obj->found)!
I'm assuming that found in your code is of type bool.
Though if you have that "100s of times" in your code you probably should consider a more aggressive refactoring.
And give that function a better name.

Parsing template tuple parameters in D

I'm implementing a multi-dimensional tensor for a linear algebra library in D and this is basically what I was aiming to for the base class:
class Tensor( T_scalar, T_dimensions ..., int T_storageOrder = StorageOrder.columnMajor )
{
}
In the idea, the user can define the characteristics of the tensor through template parameters and as a result I can deduce as many things as possible during compile-time, a bit like Eigen does.
Unfortunately the compiler is not so happy with that definition and triggers an error such as:
Tensor(T_scalar,T_args...,int T_storageOrder = StorageOrder.columnMajor) template tuple parameter must be last one
I'm not so sure why this restriction is in place but I ended up doing what I consider being a hack... basically, having defined the StorageOrder as an enum allows me to check if the last argument of the template tuple parameter matches one of the values from the enum, and if so I can use it to set the value of the StorageOrder for that tensor, otherwise I set it up with a default value.
enum StorageOrder : int
{
columnMajor = -1,
rowMajor = -2
}
class Tensor( T_scalar, T_args ... )
{
private:
alias TensorTraits!( T_scalar, T_args ) traits;
alias traits.dimensions T_dimensions;
alias traits.storageOrder T_storageOrder;
}
struct TensorTraits( T_scalar, T_args ... )
if ( areTemplateParametersValid!( T_scalar, T_args )() )
{
static immutable auto dimensions = mixin( extractDataFromTemplateTupleParameter.dimensions );
static immutable int storageOrder = extractDataFromTemplateTupleParameter.storageOrder;
private:
static auto extractDataFromTemplateTupleParameter()
{
Tuple!( string, "dimensions", int, "storageOrder" ) templateTupleParameterData;
static if ( T_args[$ - 1] == StorageOrder.columnMajor || T_args[$ - 1] == StorageOrder.rowMajor )
{
alias TypeTuple!( T_args[0 .. $ - 1] ) dimensionsTuple;
templateTupleParameterData.storageOrder = T_args[$ - 1];
}
else
{
alias TypeTuple!( T_args ) dimensionsTuple;
templateTupleParameterData.storageOrder = StorageOrder.columnMajor;
}
static assert( dimensionsTuple.length > 0,
"No dimensions have been defined." );
foreach ( dimension; dimensionsTuple )
{
static assert( isIntegral!( typeof( dimension ) ),
"Dimensions sizes needs to be defined as integrals." );
static assert( dimension >= 0,
"Dimensions sizes cannot be negative." );
}
templateTupleParameterData.dimensions = dimensionsTuple.stringof;
return templateTupleParameterData;
}
}
static bool areTemplateParametersValid( T_scalar, T_args ... )()
{
static assert( isNumeric!( T_scalar ),
"The 'T_scalar' template argument is not a numeric type." );
static assert( T_args.length > 0,
"No dimensions have been defined." );
return true;
}
Since I've just started with D, and since I'm not so sure about this hack, I would like to know if this sounds good to you guys or if there's maybe a better way of handling this?
Like you say, it's a hack, and you should avoid hacks where unnecessary.
One (obvious) solution is to move the storage order before the dimensions, although I'm guessing you want to use that default parameter.
To work around that, you could create have specific templates for row and column major:
// Generic Tensor with storage order before dimensions.
class Tensor( T_scalar, int T_storageOrder, T_dimensions... )
{
}
template TensorRowOrder( T_scalar, T_dimensions... )
{
alias Tensor( T_scalar, StorageOrder.rowMajor, T_dimensions ) TensorRowOrder;
}
template TensorColumnOrder( T_scalar, T_dimensions... )
{
alias Tensor( T_scalar, StorageOrder.columnMajor, T_dimensions ) TensorColumnOrder;
}
You can then use TensorRowOrder or TensorColumnOrder in user code, or just Tensor when you need the generic T_storageOrder.
FYI this is what I ended up doing.
class Array( T_scalar, T_args ... )
{
private:
alias ArrayTraits!( T_scalar, T_args ) traits;
alias traits.isDynamic T_isDynamic;
alias traits.shapeAtCompileTime T_shapeAtCompileTime;
alias traits.sizeAtCompileTime T_sizeAtCompileTime;
alias traits.storageOrder T_storageOrder;
alias traits.dataType T_dataType;
}
struct ArrayTraits( T_scalar, T_args ... )
if ( areTemplateParametersValid!( T_scalar, T_args )() )
{
private:
static if ( hasFlag( Flags.storageOrder ) )
alias T_args[0 .. $ - 1] shapeTuple;
else
alias T_args shapeTuple;
public:
static immutable bool isDynamic = hasFlag( Flags.dynamic ) ? true : false;
static immutable auto shapeAtCompileTime = getShapeAtCompileTime();
static immutable size_t sizeAtCompileTime = getSizeAtCompileTime();
static immutable StorageOrder storageOrder = hasFlag( Flags.storageOrder ) ?
T_args[$ - 1] : defaultStorageOrder;
static if ( hasFlag( Flags.dynamic ) == true )
alias T_scalar[] dataType;
else
alias T_scalar[sizeAtCompileTime] dataType;
public:
static auto getShapeAtCompileTime()
{
static if ( hasFlag( Flags.dynamic ) == true )
{
static assert( shapeTuple.length == 1,
"The shape of a dynamic array needs to be defined at run-time." );
size_t[1] shapeAtCompileTime = [Storage.dynamic];
return shapeAtCompileTime;
}
else
{
static assert( shapeTuple.length > 0,
"No dimensions have been defined." );
size_t[shapeTuple.length] shapeAtCompileTime;
foreach ( i, dimension; shapeTuple )
{
static assert( isIntegral!( typeof( dimension ) ),
"Dimensions sizes for a static array needs to be defined as integrals." );
static assert( dimension > 0,
"Dimensions sizes for a static array cannot be null or negative." );
shapeAtCompileTime[i] = dimension;
}
return shapeAtCompileTime;
}
}
static size_t getSizeAtCompileTime()
{
if ( hasFlag( Flags.dynamic ) == true )
return 0;
size_t size = 1;
foreach ( dimension; shapeAtCompileTime )
size *= dimension;
return size;
}
private:
/++ Parses the template tuple parameter to extract the different flags passed, if any. +/
static int getFlags()
{
int flags = 0;
if ( is( typeof( T_args[0] ) == Storage ) && T_args[0] == Storage.dynamic )
flags |= Flags.dynamic;
if ( is( typeof( T_args[$ - 1] ) == StorageOrder ) )
flags |= Flags.storageOrder;
return flags;
}
/++ Checks if the template tuple parameter contains a specific flag. +/
static bool hasFlag( Flags flag )
{
return (getFlags() & flag) == 0 ? false : true;
}
private:
enum Flags : int
{
dynamic = 1 << 0,
storageOrder = 1 << 1
}
}
bool areTemplateParametersValid( T_scalar, T_args ... )()
{
static assert( T_args.length > 0,
"No dimensions have been defined." );
return true;
}