Here a a couple of bits of D (google DLANG) for you to enjoy the first one is a one-liner but has a vast mountain of test-code, a lot of it all done at compile-time in fact so it won't build if it has bugs. That is because if D’s amazing CTFE (compile-time function evaluation) whereby it evaluates absolutely everything that is conceivably possible at compile-time and when it can it deletes an entire complex routine just replacing it with the computed result. Of course C can evaluate expressions at compile-time but it seems to be relatively shy about it. The first example just tests to see whether a number is a power of two or not.
// dlang d ispowerof2
module test;
import std.stdint;
pure nothrow @safe @nogc
bool IsPowerOf2(T)( T x )
// Return non-zero if arg is a power of two
// Is currently strictly true or false ret val - despite the choice of implementation with &
in {
}
out ( ret )
{
assert( ret == true || ret == false ); // strict bool restriction currently
debug
{
bool b = false;
//for ( uint s = 0; s <= 8 * x.sizeof -1; s++ )
foreach( s; 0.. 8 * x.sizeof )
{
b = b || ( x == (1uL << s) );
}
assert( ret == b );
}
}
body
{
return ( ( x & (x - 1) ) == 0 ) & (x > 0); /* Should really be an '&&' */
/* but using an '&' is in fact completely safe in ANY CASE as both operands contain proper comparisons in them anyway
// and alternatively the function could be re-specced to be ret non-zero=true.
// The change to a '&' is just in case a horrid compiler emits branches.
// GDC and LDC do not do so even with &&, as it happens, a miracle (tested with -O3 in both compilers. */
}
bool t1( int x )
{
return IsPowerOf2( x );
}
bool t1( uint x )
{
return IsPowerOf2( x );
}
bool t1( uint64_t x )
{
return IsPowerOf2( x );
}
bool xxx8()
{
const uint x = 8;
return IsPowerOf2( x );
}
bool yay5()
{
const size_t x = 5;
return IsPowerOf2( x );
}
bool zzz0()
{
const size_t x = 0;
return IsPowerOf2( x );
}
bool zzz1()
{
const uint64_t x = 1;
return IsPowerOf2( x );
}
void do_static_unittests()
{
static assert( ! IsPowerOf2( 32 / 4 * (4 +1 ) -1 ) );
static assert( ! IsPowerOf2( 512 / 2 * (2 +1 ) -1 ) );
{
enum n = 6;
static assert( ! IsPowerOf2( cast(uint) n ) );
static assert( ! IsPowerOf2( cast(int) n ) );
static assert( ! IsPowerOf2( cast(ulong) n ) );
static assert( ! IsPowerOf2( cast(long) n ) );
}
{
enum n = 7;
static assert( ! IsPowerOf2( cast(uint) n ) );
static assert( ! IsPowerOf2( cast(int) n ) );
static assert( ! IsPowerOf2( cast(ulong) n ) );
static assert( ! IsPowerOf2( cast(long) n ) );
}
{
enum n = 9;
static assert( ! IsPowerOf2( cast(uint) n ) );
static assert( ! IsPowerOf2( cast(int) n ) );
static assert( ! IsPowerOf2( cast(ulong) n ) );
static assert( ! IsPowerOf2( cast(long) n ) );
}
static assert( ! IsPowerOf2( 0u ) );
static assert( ! IsPowerOf2( 0 ) );
static assert( ! IsPowerOf2( 0uL ) );
static assert( ! IsPowerOf2( 0L ) );
static assert( ! IsPowerOf2( ~0u ) );
static assert( ! IsPowerOf2( ~0 ) );
static assert( ! IsPowerOf2( ~0uL ) );
static assert( ! IsPowerOf2( ~0L ) );
{
enum i = 30;
static assert( IsPowerOf2( 1u << i ) );
static assert( IsPowerOf2( 1 << i ) );
static assert( IsPowerOf2( 1uL << i ) );
static assert( IsPowerOf2( 1L << i ) );
static assert( ! IsPowerOf2( (1u << i) + 1) );
static assert( ! IsPowerOf2( (1 << i ) + 1) );
static assert( ! IsPowerOf2( (1uL << i ) + 1) );
static assert( ! IsPowerOf2( (1L << i ) + 1) );
static assert( ! IsPowerOf2( (1u << i) - 1) );
static assert( ! IsPowerOf2( (1 << i ) - 1) );
static assert( ! IsPowerOf2( (1uL << i ) - 1) );
static assert( ! IsPowerOf2( (1L << i ) - 1) );
}
{
enum i = 31;
static assert( IsPowerOf2( 1u << i ) );
static assert( IsPowerOf2( 1uL << i ) );
static assert( ! IsPowerOf2( (1u << i) + 1) );
static assert( ! IsPowerOf2( (1uL << i ) + 1) );
static assert( ! IsPowerOf2( (1u << i) - 1) );
static assert( ! IsPowerOf2( (1 << i ) - 1) );
static assert( ! IsPowerOf2( (1uL << i ) - 1) );
static assert( ! IsPowerOf2( (1L << i ) - 1) );
}
{
enum i = 62;
static assert( IsPowerOf2( 1uL << i ) );
static assert( IsPowerOf2( 1L << i ) );
static assert( ! IsPowerOf2( (1uL << i ) + 1) );
static assert( ! IsPowerOf2( (1L << i ) + 1) );
static assert( ! IsPowerOf2( (1uL << i ) - 1) );
static assert( ! IsPowerOf2( (1L << i ) - 1) );
}
{
enum i = 63;
static assert( IsPowerOf2( 1uL << i ) );
static assert( ! IsPowerOf2( (1uL << i ) + 1) );
static assert( ! IsPowerOf2( (1uL << i ) - 1) );
}
}
A more substantial example which provides access to the Intel x86-64 pext instruction, with a software replacement if the instruction is not there controlled by a version switch. This produces an alternative build controlled by compiler switches. An externally defined #define and an #ifdef would be used in C for this, but D does not have a preprocessor. Every use-case where you would need the preprocessor is dealt with by a raft of specially designed features to cover all the advanced C programmer’s needs. This routine is specific to the GDC compiler a member of the GCC family and it uses a an interfacing facility to integrate assembler code into the program which is very similar to that used by the GCC C compiler. The pext_insn routine shows some assembler which will generate the x64 pext instruction inline optimally if the instruction is available. Older Intel CPUs will not have this instruction and so some longwinded code is generated in that build.
import std.stdint;
pure nothrow @nogc @safe
T min( T )( T a, T b) { return a < b ? a : b; }
pure nothrow @nogc @safe
T max( T )( T a, T b) { return a > b ? a : b; }
/+
bool test_ffff()
{
bool t = true;
enum uint64_t v = ~0uL;
for ( uint64_t m = 0; m <= 0xffff; m++ )
{
for ( uint s = 1; s <= m.sizeof * 8 -1; s++ )
{
//assert( test_pext_soft( v, m >>> s ) == (test_pext_soft( v, m ) >>> s) );
}
}
return t;
}
+/
unittest { do_unittest(); }
static
void do_unittest()
{
assert ( test_pext( ~0UL, ~0UL ) == ~0UL );
assert ( test_pext( ~0UL, 0xffff ) == 0xffff );
assert ( test_pext( ~0UL, 0xf0f0) == 0xff );
assert ( test_pext( ~0UL, 0x5555 ) == 0xff );
assert ( test_pext( ~0UL, 0 ) == 0 );
assert ( test_pext( ~0UL, 5 ) == 3 );
assert ( test_pext( ~0UL, 9 ) == 3 );
assert ( test_pext( 0x10 | 2, 0x10 | 2 ) == (2 | 1 ) );
assert ( test_pext( 0x10 | 0, 0x10 | 2 ) == (2 | 0 ) );
assert ( test_pext( 0x08 | 4, 0x10 | 2 ) == (0 | 0 ) );
assert ( test_pext( 0x110 | 2, 0x10 | 2 ) == (2 | 1 ) );
assert ( test_pext( 0x110 | 1, 0x10 | 2 ) == (2 | 0 ) );
assert ( test_pext( 0x208 | 4, 0x10 | 2 ) == (0 | 0 ) );
static assert ( test_pext_soft( ~0UL, ~0UL ) == ~0UL );
static assert ( test_pext_soft( ~0UL, 0xffff ) == 0xffff );
static assert ( test_pext_soft( ~0UL, 0xf0f0) == 0xff );
static assert ( test_pext_soft( ~0UL, 0x5555 ) == 0xff );
static assert ( test_pext_soft( ~0UL, 0 ) == 0 );
static assert ( test_pext_soft( ~0UL, 5 ) == 3 );
static assert ( test_pext_soft( ~0UL, 9 ) == 3 );
static assert ( test_pext_soft( 0x10 | 2, 0x10 | 2 ) == (2 | 1 ) );
static assert ( test_pext_soft( 0x10 | 0, 0x10 | 2 ) == (2 | 0 ) );
static assert ( test_pext_soft( 0x08 | 4, 0x10 | 2 ) == (0 | 0 ) );
static assert ( test_pext_soft( 0x110 | 2, 0x10 | 2 ) == (2 | 1 ) );
static assert ( test_pext_soft( 0x110 | 1, 0x10 | 2 ) == (2 | 0 ) );
static assert ( test_pext_soft( 0x208 | 4, 0x10 | 2 ) == (0 | 0 ) );
assert ( test_pext_insn( ~0UL, ~0UL ) == ~0UL );
assert ( test_pext_insn( ~0UL, 0xffff ) == 0xffff );
assert ( test_pext_insn( ~0UL, 0xf0f0) == 0xff );
assert ( test_pext_insn( ~0UL, 0x5555 ) == 0xff );
assert ( test_pext_insn( ~0UL, 0 ) == 0 );
assert ( test_pext_insn( ~0UL, 5 ) == 3 );
assert ( test_pext_insn( ~0UL, 9 ) == 3 );
assert ( test_pext_insn( 0x10 | 2, 0x10 | 2 ) == (2 | 1 ) );
assert ( test_pext_insn( 0x10 | 0, 0x10 | 2 ) == (2 | 0 ) );
assert ( test_pext_insn( 0x08 | 4, 0x10 | 2 ) == (0 | 0 ) );
assert ( test_pext_insn( 0x110 | 2, 0x10 | 2 ) == (2 | 1 ) );
assert ( test_pext_insn( 0x110 | 1, 0x10 | 2 ) == (2 | 0 ) );
assert ( test_pext_insn( 0x208 | 4, 0x10 | 2 ) == (0 | 0 ) );
}
uint64_t test_pext( ulong x, ulong mask ) pure nothrow @nogc @safe
{
return pext( x, mask );
}
uint64_t test_pext_soft( ulong x, ulong mask ) pure nothrow @nogc @safe
{
return pext_soft( x, mask );
}
uint64_t test_pext_soft_0( ulong x ) pure nothrow @nogc @safe
{
return pext_soft( x, 0 );
}
uint64_t test_pext_soft_7( ulong x ) pure nothrow @nogc @safe
{
return pext_soft( x, 7 );
}
uint64_t test_pext_soft_56( ulong x, ulong mask ) pure nothrow @nogc @safe
{
return pext_soft( x, 56 );
}
static
uint64_t test_pext_insn( ulong x, ulong mask ) pure nothrow @nogc @safe
{
return pext( x, mask );
}
// bogus assumption about current target cpu
version = Ver_Pext_Instruction_Available;
//not//version = Ver_Pext_Instruction_Disabled;
version ( Ver_Pext_Instruction_Available )
{
version ( Ver_Pext_Instruction_Disabled ) // if instruction use is force-disabled / overridden
{
enum bool use_pext_insn = false;
}
else // instruction use is not force-disabled / overridden
{
enum bool use_pext_insn = true;
}
}
else // if cpu does not have the pext insn
{
enum bool use_pext_insn = false;
}
// specialization for all-1s mask
pure nothrow @nogc @safe
TVal_t pext( TVal_t, uint M : ~0u)( in TVal_t x, in uint mask ) { return x & M; }
pure nothrow @nogc @safe
TVal_t pext( TVal_t, ulong M : ~0uL)( in TVal_t x, in ulong mask ) { return x & M; }
pure nothrow @nogc @safe
TVal_t pext( TVal_t, int M : ~0)( in TVal_t x, in int mask ) { return x & M; }
pure nothrow @nogc @safe
TVal_t pext( TVal_t, long M : ~0L)( in TVal_t x, in long mask ) { return x & M; }
// specialization for zero mask
pure nothrow @nogc @safe
TVal_t pext( TVal_t, uint M : 0u)( in TVal_t x, in uint mask ) { return 0; }
pure nothrow @nogc @safe
TVal_t pext( TVal_t, ulong M : 0uL)( in TVal_t x, in ulong mask ) { return 0; }
pure nothrow @nogc @safe
TVal_t pext( TVal_t, int M : 0)( in TVal_t x, in int mask ) { return 0; }
pure nothrow @nogc @safe
TVal_t pext( TVal_t, long M : 0L)( in TVal_t x, in long mask ) { return 0; }
/* ====== */
pure nothrow @nogc @trusted
TVal_t pext( TVal_t, TMask_t )( in TVal_t x, in TMask_t mask )
if ( is( typeof( x & mask ) ) )
in
{
static assert( is( typeof( x & mask ) ) );
}
out (ret)
{
static assert( is( typeof( ret == (x & mask) ) ) );
assert( ret.sizeof >= x.sizeof );
}
body
{
if ( __ctfe ) // make sure that we do not prevent ctfe from working
{
return pext_soft( x, mask );
}
static if ( use_pext_insn )
{
// deal with mixed types, as far as possible - the instruction template doesnt handle differing types
// also optimize tha case where the mask is too narrow, can use a cheaper width op
static if ( mask.sizeof < x.sizeof )
{ // mask is narrow, optimize
static assert( is( typeof( x & mask ) ) ); // the cast can narrow values, but eg will not handle eg floats
const typeof(mask) narrowed_val = cast(const(typeof(mask))) x; // narrow the x, also ensure same type to make the insn template match
const TVal_t ret = pext_insn( narrowed_val, mask );
}
else
{
static assert( is( typeof( x & mask ) ) ); // the cast can definitely narrow masks, and should, but a cast that is a conversion involving insane types must not be attempted as it would change the mask
const typeof(x) narrowed_mask = cast(const(typeof(x))) mask; // ensure same type to make the insn template match - but it is essential that this merely be a change of width at most
const TVal_t ret = pext_insn( x, narrowed_mask );
}
}
else // if not using the pext insn, use routine with a software loop
{
const TVal_t ret = pext_soft( x, mask );
}
return ret;
}
version ( Ver_Pext_Instruction_Available )
{
pure nothrow @nogc @trusted
T pext_insn( T )( in T x, in T mask )
if ( is( typeof( x & mask ) ) )
in {
static assert( T.sizeof * 8 == 32 || T.sizeof * 8 ==64 ); // reqd by insn
static assert( x.sizeof == mask.sizeof ); // reqd by insn
static assert( is( typeof( x & mask ) ) );
}
out (ret )
{
static assert( ret.sizeof == x.sizeof );
static assert( is( typeof( ret == (x & mask) ) ) );
}
body
{
/* Any choices of type conversions, or widening/narrowing would be applied here */
const T asm_src = x;
const T asm_mask = mask;
T asm_ret;
/* Checks on the restrictions on the pext instruction's operands' widths */
static assert( asm_src.sizeof * 8 == 32 || asm_src.sizeof * 8 ==64 );
static assert( asm_src.sizeof == asm_mask.sizeof );
static assert( asm_src.sizeof == asm_ret.sizeof );
asm {
".intel_syntax" "\n\t"
"pext %[ret], %[src], %[mask]" "\n\t"
".att_syntax" "\n"
: [ret] "=r" (asm_ret) /* the format is ret= out r64, src = in r64, mask= in r64 or mem64 or 32-bits for all three instead*/
: [src] "r" (asm_src),
[mask] "rm" (asm_mask)
: "cc" ;
}
return asm_ret;
}
} // end version
// ====
// Choice of case optimisation strategy for pext_soft() - optimize the worst case to be flat time, or variable time for mask values that are low, in the hope these are more frequent
enum pext_algorithm { alg_default, optimize_worst_case, assume_low_values };
alias pext_algorithm_t = pext_algorithm;
pure nothrow @nogc @safe
TVal_t pext_soft( TVal_t, TMask_t, pext_algorithm_t algorithm_preference = pext_algorithm.alg_default )( in TVal_t x, in TMask_t mask )
if ( is( typeof( x & mask ) ) )
in {
}
out (ret) {
static assert( is( typeof( ret == (x & mask) ) ) );
}
body
{
import std.traits : __traits;
enum bool is_mask_known_at_compile_time = __traits( compiles, { enum e_ = mask; } );
// The working accumulator is based on the width of TVal_t narrowed if mask is narrower, then adjusted up for efficient accumulator ops
enum eff_src_bit_width = min( TVal_t.sizeof, TMask_t.sizeof ) * 8;
static if ( eff_src_bit_width <= 32 )
{
alias TSrcAcc_t = uint32_t;
}
else static if ( eff_src_bit_width == 64 )
{
alias TSrcAcc_t = uint64_t;
}
else static assert( false, "First argument is of a type not supported" );
static assert( TSrcAcc_t.sizeof >= min( TVal_t.sizeof, TMask_t.sizeof ) );
alias TRet_t = TSrcAcc_t;
TRet_t ret = 0;
static assert( ret.sizeof >= min( TVal_t.sizeof, TMask_t.sizeof ) );
uint destbitpos = 0;
static assert( is( typeof( x & mask ) ) );
alias TMaskAcc_t = TSrcAcc_t; // narrowed as an optimization based on the bits masked off
TSrcAcc_t src = cast(TSrcAcc_t) x & cast(TSrcAcc_t) mask; // knock out the source bits that are zero-ed out by the mask, saves a src & mask in the loop
static if ( algorithm_preference == pext_algorithm.assume_low_values || is_mask_known_at_compile_time ) // variable time, optimize hoping for low mask values being frequent - could actually be much worse, as cost of jumps not measured!
{
for ( TMaskAcc_t m = mask; m; m >>>= 1 )
{
assert( destbitpos >= 0 && destbitpos < src.sizeof * 8 );
ret |= ( src & 1 ) << destbitpos; // dont need to do (src & m & 1) as zero-masked bits were already knocked out of src at the start by src = x & mask
destbitpos += m & 1;
src >>>= 1;
}
}
else static if ( algorithm_preference == pext_algorithm.optimize_worst_case || algorithm_preference == pext_algorithm.alg_default )
{ // optimize the worst case, all runtimes are flat (checks for special cases - ie mask = all 1s or 0 - are handled earlier)
static assert( eff_src_bit_width <= src.sizeof * 8 );
enum loop_bits = eff_src_bit_width;
TMaskAcc_t m = mask; // using a possibly narrowed type, from min() above
for ( uint i = 0; i < loop_bits; i++ )
{
assert( destbitpos >= 0 && destbitpos < src.sizeof * 8 );
ret |= ( src & 1 ) << destbitpos; // dont need to do (src & m & 1) as zero-masked bits already knocked out of src at the start by src = x & mask
destbitpos += m & 1;
src >>>= 1;
m >>>= 1;
}
}
else static assert( 0, "no pext_soft implementation algorithm was chosen" );
assert( ret <= ( mask & x ) );
return ret;
}