tags:

views:

497

answers:

2

I am trying to perform some generic number manipulation independent of the number type. However, I know of no way to use generics to do this. The first idea was to filter the incoming types with a where statement, but all of the number types are closed and are, therefore, not valid for a generic filter. Also, the generics don't allow standard numeric operations (addition, shift, etc), so the only solution I can come up with is to re-write each method non-generically. Any other ideas?

For reference, following is the code that I initially tried:

    private const int BYTE_SIZE = 8;

    private const int UINT16_SIZE = 16;

    private const int UINT32_SIZE = 32;

    private const int UINT64_SIZE = 64;

    public static byte[] ToBytes(UInt16[] pnaValues)
    {
        return ToSmaller<byte, UInt16>(pnaValues, BYTE_SIZE, UINT16_SIZE);
    }

    public static byte[] ToBytes(UInt32[] pnaValues)
    {
        return ToSmaller<byte, UInt32>(pnaValues, BYTE_SIZE, UINT32_SIZE);
    }

    ....

    public static UInt16[] ToUInt16s(byte[] pnaValues)
    {
        return ToLarger<UInt16, byte>(pnaValues, UINT16_SIZE, BYTE_SIZE);
    }

    public static UInt16[] ToUInt16s(UInt32[] pnaValues)
    {
        return ToSmaller<UInt16, UInt32>(pnaValues, UINT16_SIZE, UINT32_SIZE);
    }

    ...

    public static UInt64[] ToUInt64s(UInt32[] pnaValues)
    {
        return ToLarger<UInt64, UInt32>(pnaValues, UINT64_SIZE, UINT32_SIZE);
    }

    private static TLarger[] ToLarger<TLarger, TSmaller>(TSmaller[] pnaSmaller, int pnLargerSize, int pnSmallerSize)
        where TLarger : byte, UInt16, UInt32, UInt64
        where TSmaller : byte, UInt16, UInt32, UInt64
    {
        TLarger[] lnaRetVal = null;
        int lnSmallerPerLarger = pnLargerSize / pnSmallerSize;

        System.Diagnostics.Debug.Assert((pnLargerSize % pnSmallerSize) == 0);

        if (pnaSmaller != null)
        {
            System.Diagnostics.Debug.Assert((pnaSmaller % lnSmallerPerLarger) == 0);

            lnaRetVal = new TLarger[pnaSmaller.Length / lnSmallerPerLarger];

            for (int i = 0; i < lnaRetVal.Length; i++)
            {
                lnaRetVal[i] = 0;

                for (int j = 0; j < lnSmallerPerLarger; j++)
                {
                    lnaRetVal[i] = (lnaRetVal[i] << pnLargerSize) + pnaSmaller[i * lnSmallerPerLarger + j];
                }
            }
        }

        return lnaRetVal;
    }

    private static TSmaller[] ToSmaller<TSmaller, TLarger>(TLarger[] pnaLarger, int pnSmallerSize, int pnLargerSize)
        where TSmaller : byte, UInt16, UInt32, UInt64
        where TLarger : byte, UInt16, UInt32, UInt64
    {
        TSmaller[] lnaRetVal = null;
        int lnSmallerPerLarger = pnLargerSize / pnSmallerSize;

        System.Diagnostics.Debug.Assert((pnLargerSize % pnSmallerSize) == 0);

        if (pnaSmaller != null)
        {
            lnaRetVal = new TSmaller[pnaLarger.Length * lnSmallerPerLarger];

            for (int i = 0; i < lnaRetVal.Length; i++)
            {
                for (int j = 0; j < lnSmallerPerLarger; j++)
                {
                    lnaRetVal[i * lnSmallerPerLarger + (lnSmallerPerLarger - 1 - j)]
                        = pnaLarger[i] >> (j * pnLargerSize);
                }
            }
        }

        return lnaRetVal;
    }
+7  A: 

There's no common interface for arithmetic operations implemented by numeric types. Generic operators might help solving your problem.

Mehrdad Afshari
In particular for this case, `Operator.Convert<TFrom, TTo>(TFrom value)` may be useful.
Marc Gravell
Note that I didn't implement `LeftShift` and `RightShift`, but they would be trivial to add.
Marc Gravell
+1  A: 

Rewriting is probably easiest. The only other solution I can come up with is to go beyond templates, write a String that represents your function, with placeholder chars for the type, then replace it with each type name and compile it at runtime.

Apart from the initial performance hit due to compilation it will also be difficult to call these functions.

David Rutten