[Issue 8143] Safe std.conv.to enum conversion

d-bugmail at puremagic.com d-bugmail at puremagic.com
Wed Oct 24 10:13:53 PDT 2012


http://d.puremagic.com/issues/show_bug.cgi?id=8143


Andrej Mitrovic <andrej.mitrovich at gmail.com> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
         AssignedTo|nobody at puremagic.com        |andrej.mitrovich at gmail.com


--- Comment #5 from Andrej Mitrovic <andrej.mitrovich at gmail.com> 2012-10-24 10:13:51 PDT ---
Ok here's a first implementation, let me know if it can be improved before a
pull request is made (the docs will be improved too):

External: http://dpaste.dzfl.pl/ee99ce99
And copied here:

import std.traits;
import std.conv : ConvException, assertThrown;
import std.string;
import std.math;
import std.stdio;

/**
Convert a value that is implicitly convertible to the enum base type
into an Enum value.
If the value does not match any enum member values, or
if it matches more than one member value throw a ConvException.
*/
T toImpl(T, S)(S value)
    if (is(T == enum) && is(S : OriginalType!T) &&
!isFloatingPoint!(OriginalType!T))
{
    T result;
    size_t matches;

    foreach (Member; EnumMembers!T)
    {
        if (Member == value)
        {
            result = Member;
            if (++matches > 1)
                throw new ConvException(format("Value (%s) matches more than
one member value of enum '%s'", value, fullyQualifiedName!T));
        }
    }

    if (!matches)
        throw new ConvException(format("Value (%s) does not match any member
value of enum '%s'", value, fullyQualifiedName!T));

    return result;
}

/**
    Ditto:

    Specialization for Enums that have a floating point base type.
    @equal must be a function which takes the enum base type as
    its first parameter, the type of @value as its second parameter,
    and return true if the two compare equal.
*/
T toImpl(T, alias equal, S)(S value)
    if (is(T == enum) && is(S : OriginalType!T) &&
isFloatingPoint!(OriginalType!T))
{
    T result;
    size_t matches;

    foreach (Member; EnumMembers!T)
    {
        if (equal(Member, value))
        {
            result = Member;
            if (++matches > 1)
                throw new ConvException(format("Value (%s) matches more than
one member value of enum '%s'", value, fullyQualifiedName!T));
        }
    }

    if (!matches)
        throw new ConvException(format("Value (%s) does not match any member
value of enum '%s'", value, fullyQualifiedName!T));

    return result;
}

alias toImpl to;

void test()
{
    enum En : int { A = 10, B = 20, C = 30, D = 20 }
    En en1 = to!En(10);
    assert(en1 == En.A);
    assertThrown!ConvException(to!En(5));
    // matches more than one
    assertThrown!ConvException(to!En(20));

    static bool equal(float a, float b) { return feqrel(a, b) >= 24; }
    enum EF : float { C = 4.9 }
    float f = 4.9;
    EF enf = to!(EF, equal)(f);

    enum EF2 : float { A = 4.9, B = 1.0, C = 4.9 }
    float f2 = 4.9;
    // matches more than one
    assertThrown!ConvException(to!(EF2, equal)(f2));
}

void main()
{
    test();
}

-- 
Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email
------- You are receiving this mail because: -------


More information about the Digitalmars-d-bugs mailing list