Discussion:
overengineered
(too old to reply)
Bonita Montero
2024-04-28 15:31:29 UTC
Permalink
This is just overengineered ?

#include <iostream>
#include <intrin.h>

using namespace std;

int main()
{
struct feature_t
{
uint8_t id, leaf;
uint8_t reg, bit;
string_view descr;
};
enum { EAX, EBX, ECX, EDX };
static feature_t const features[] =
{
{ 7, 0, EBX, 16, "AVX512F" },
{ 7, 0, EBX, 17, "AVX512DQ" },
{ 7, 0, EBX, 21, "AVX512IFMA" },
{ 7, 0, EBX, 26, "AVX512PF" },
{ 7, 0, EBX, 27, "AVX512ER" },
{ 7, 0, EBX, 28, "AVX512CD" },
{ 7, 0, EBX, 30, "AVX512BW" },
{ 7, 0, EBX, 31, "AVX512VL" },
{ 7, 0, ECX, 0, "AVX512_VBMI" },
{ 7, 0, ECX, 6, "AVX512_VBMI2" },
{ 7, 0, ECX, 11, "AVX512_VNNI" },
{ 7, 0, ECX, 12, "AVX512_BITALG" },
{ 7, 0, ECX, 14, "AVX512_VPOPCNTDQ" },
{ 7, 0, EDX, 2, "AVX512_4VNNIW" },
{ 7, 0, EDX, 3, "AVX512_4FMAPS" },
{ 7, 0, EDX, 8, "AVX512_VP2INTERSECT" },
{ 7, 0, EDX, 23, "AVX512_FP16" },
{ 7, 1, EAX, 5, "AVX512_BF16" }
};
auto enumerate = [&]<typename Fn>( Fn fn )
requires requires( Fn fn, feature_t const &ft ) { { fn( ft ) }; }
{
int regs[4];
for( feature_t const *ftLast = nullptr; feature_t const &ft : features )
{
if( !ftLast || ft.id != ftLast->id || ft.leaf != ftLast->leaf )
__cpuidex( regs, ft.id, ft.leaf );
if( regs[ft.reg] >> ft.bit & 1 )
fn( ft );
ftLast = &ft;
}
};
size_t n = 0;
enumerate( [&]( feature_t const &ft ) { n += (size_t)(bool)n * 2 +
ft.descr.length(); } );
string strFt;
strFt.reserve( n );
enumerate( [&]( feature_t const &ft )
{
if( strFt.size() )
strFt += ", ";
strFt += ft.descr;
} );
cout << strFt << endl;
}

I could have used /proc/cpuinfo also.
Ross Finlayson
2024-04-28 18:54:11 UTC
Permalink
Post by Bonita Montero
This is just overengineered ?
#include <iostream>
#include <intrin.h>
using namespace std;
int main()
{
struct feature_t
{
uint8_t id, leaf;
uint8_t reg, bit;
string_view descr;
};
enum { EAX, EBX, ECX, EDX };
static feature_t const features[] =
{
{ 7, 0, EBX, 16, "AVX512F" },
{ 7, 0, EBX, 17, "AVX512DQ" },
{ 7, 0, EBX, 21, "AVX512IFMA" },
{ 7, 0, EBX, 26, "AVX512PF" },
{ 7, 0, EBX, 27, "AVX512ER" },
{ 7, 0, EBX, 28, "AVX512CD" },
{ 7, 0, EBX, 30, "AVX512BW" },
{ 7, 0, EBX, 31, "AVX512VL" },
{ 7, 0, ECX, 0, "AVX512_VBMI" },
{ 7, 0, ECX, 6, "AVX512_VBMI2" },
{ 7, 0, ECX, 11, "AVX512_VNNI" },
{ 7, 0, ECX, 12, "AVX512_BITALG" },
{ 7, 0, ECX, 14, "AVX512_VPOPCNTDQ" },
{ 7, 0, EDX, 2, "AVX512_4VNNIW" },
{ 7, 0, EDX, 3, "AVX512_4FMAPS" },
{ 7, 0, EDX, 8, "AVX512_VP2INTERSECT" },
{ 7, 0, EDX, 23, "AVX512_FP16" },
{ 7, 1, EAX, 5, "AVX512_BF16" }
};
auto enumerate = [&]<typename Fn>( Fn fn )
requires requires( Fn fn, feature_t const &ft ) { { fn( ft ) }; }
{
int regs[4];
for( feature_t const *ftLast = nullptr; feature_t const &ft : features )
{
if( !ftLast || ft.id != ftLast->id || ft.leaf !=
ftLast->leaf )
__cpuidex( regs, ft.id, ft.leaf );
if( regs[ft.reg] >> ft.bit & 1 )
fn( ft );
ftLast = &ft;
}
};
size_t n = 0;
enumerate( [&]( feature_t const &ft ) { n += (size_t)(bool)n * 2 +
ft.descr.length(); } );
string strFt;
strFt.reserve( n );
enumerate( [&]( feature_t const &ft )
{
if( strFt.size() )
strFt += ", ";
strFt += ft.descr;
} );
cout << strFt << endl;
}
I could have used /proc/cpuinfo also.
(Could you name ftLast to ftPrev instead pls. Also "(size_t)(bool)n"
seems "(n > 0 ? 1 : 0)", or, you know, I suppose. Then it would seem so
regular and conventional and idiomatic as to not seem over-engineered,
particularly as it's standard in libraries where the worst
sort of "over-engineered" seems "import world". Don't get me wrong,
I'm a big fan of over-engineering, especially when it results a clean,
factorized, composable design. The idea of comma-join is
a totally usual sort of thing in joining and splitting, about
things like "bool first" above loops "if (!first)" and all these kinds
things. Sometimes if/else in loops seems making for "(expr) &&
continue", or what are loop invariants and entry/exit automatics,
yet then it starts looking like shell scripting.

Is it, is it not-over-engineered? Implicits in the functions,
implicits in the loops, implicits in the routines,
all standard in only library functions, ...,
functional and procedural styles together. It could be
written all functional, or written all procedural,
flow-of-control is a deliberately didactic determinism.)
Bonita Montero
2024-04-29 04:51:15 UTC
Permalink
Post by Ross Finlayson
(Could you name ftLast to ftPrev instead pls. Also "(size_t)(bool)n"
seems "(n > 0 ? 1 : 0)", or, you know, I suppose. ...
It's just my style, not yours.
Chris M. Thomasson
2024-04-29 20:38:32 UTC
Permalink
Post by Bonita Montero
Post by Ross Finlayson
(Could you name ftLast to ftPrev instead pls. Also "(size_t)(bool)n"
seems "(n > 0 ? 1 : 0)", or, you know, I suppose. ...
It's just my style, not yours.
Sometimes, your style makes blood want to shoot out of my eyes!

;^)
Bonita Montero
2024-05-06 13:05:04 UTC
Permalink
Post by Chris M. Thomasson
Post by Bonita Montero
Post by Ross Finlayson
(Could you name ftLast to ftPrev instead pls. Also "(size_t)(bool)n"
seems "(n > 0 ? 1 : 0)", or, you know, I suppose. ...
It's just my style, not yours.
Sometimes, your style makes blood want to shoot out of my eyes!
;^)
I love my style, mostly the srtong affinity
to functional programming in C++.

Loading...