Creating a subtype using struct template

From D Wiki
Jump to: navigation, search
Level: Novice
Cookbook Type: Recipe
Cookbook Status: Draft
Approximate reading time: 5 min
0.083 hr
D Version: D2


This recipe shows how to create a subtype for an integral / floating point range using a struct template. Run the code

Program Code

import std.traits : isIntegral, isFloatingPoint;

struct SubType(Type, Type Min, Type Max, Type Init = Min, alias Ex = Exception,
               alias Tolerance = 0.001f)
    if( isIntegral!(Type) || isFloatingPoint!(Type) )
{    
    private 
    {    
        Type value = Init;
    }
    //static const Type min = Min;
    //static const Type max = Max;    
    
    @property Type access()
    {
        return value;    
    }
    
    @property void access(Type new_val)
    {
        static if (isIntegral!(Type))
        {
            if ( !((new_val >= Min) && (new_val <= Max)) )
                throw new Ex("Value not in range [min,max]");
        }
        else static if (isFloatingPoint!(Type))
        {
            Type amin = new_val - Min;
            amin = (amin < 0.0)? -amin : amin;
            
            Type amax = new_val - Max;
            amax = (amax < 0.0)? -amax : amax;
            
            if ( !( ((new_val > Min) || (amin < Tolerance)) &&
                    ((new_val < Max) || (amax < Tolerance))    ) )
                throw new Ex("Value not in range [min,max]");
        }
        else
            static assert(false, "Not Implemented!");
        
        value = new_val;    
    }
    
    alias access this;
}

class MyException : Exception
{
    this(string msg, string f = __FILE__, size_t l = __LINE__)
    {
        super( "MyException: " ~ msg, f, l);
    }
}

//pragma(msg, SubType!(int, 0, 123).max );

unittest 
{ 
    import std.conv      : to;
    import std.exception : assertThrown;
    
    alias SubType!(int, 0, 123, 100, MyException) MyInt1;
    alias SubType!(int, 0, 123) MyInt2;
    
    MyInt1 m1;
    MyInt2 m2;
    
    assert(m1 == 100);
    assert(m2 == 0);
    
    
    m1 = 123;
    assert(m1 == 123);
    
    m2 = to!(uint)("123");
    assert(m2 == 123);
    
    assertThrown!(MyException)(m1 = -1);
    assertThrown!(MyException)(m1 = 124);
    m1 = 99;
    assert(m1 == 99);
    
    assertThrown(m2 = -1);
    assertThrown(m2 = 124);
    m2 = 99;
    assert(m2 == 99);


    SubType!(float, 0.0, 1.0) f1;
    
    const float tol = 0.001f;
    
    float diff;
    
    diff = f1 - 0.0f;
    diff = (diff < 0.0f)? -diff : diff;
    assert(diff < tol);
    
    
    f1 = 1.0f;
    diff = f1 - 1.0f;
    diff = (diff < 0.0f)? -diff : diff;
    assert(diff < tol);
    
    
    assertThrown(f1 = -0.01f);
    assertThrown(f1 =  1.01f);
    
    
    SubType!(double, 0.000_1, 0.000_9, 0.000_1, MyException, 0.000_001) d1;
    
    const double dtol = 0.000_001;
    
    double ddiff;
    
    ddiff = d1 - 0.000_1;
    ddiff = (ddiff < 0)? -ddiff : ddiff;
    assert(ddiff < dtol);
    
    d1 = 0.000_9;
    
    ddiff = d1 - 0.000_9;
    ddiff = (ddiff < 0)? -ddiff : ddiff;
    assert(ddiff < dtol);
    
    assertThrown!(MyException)(d1 = 0.000_09);
    assertThrown!(MyException)(d1 = 0.000_099);
    assertThrown!(MyException)(d1 = 0.000_91);
    assertThrown!(MyException)(d1 = 0.000_901);
    
    d1 = 0.000_0999;
    
    ddiff = d1 - 0.000_0999;
    ddiff = (ddiff < 0)? -ddiff : ddiff;
    assert(ddiff < dtol);
    
    d1 = 0.000_9001;
    
    ddiff = d1 - 0.000_9001;
    ddiff = (ddiff < 0)? -ddiff : ddiff;
    assert(ddiff < dtol);
    
}

void main() { }