6
\$\begingroup\$

I have a routine that can be potentially reduced.

internal ArrayBufferObject GetAccessorArray()
{
    ColladaDocument colladaDocument = GetColladaDocument();
    ColladaArray colladaArray = colladaDocument.GetSpecialElement<ColladaArray>(Source);
    ArrayBufferObject bufferObject;

    if (IsSimpleParamsConfiguration() == false)
        throw new NotSupportedException("complex accessor params not supported");

    string simpleParamsType = Params[0].Type;

    if (simpleParamsType == ArrayTypeFloat) {
        uint cursorOffset = Offset;

        ArrayBufferObject<float> arrayBufferObject = new ArrayBufferObject<float>(BufferObject.Hint.StaticCpuDraw);

        for (uint i = 0; i < Count; i++) {
            foreach (ColladaParam param in Params) {
                if (param.Name != null)
                    arrayBufferObject[cursorOffset - Offset] = (float) colladaArray[cursorOffset];
                cursorOffset++;
            }
            cursorOffset += Stride - (uint)Params.Count;
        }

        bufferObject = arrayBufferObject;

    } else if (simpleParamsType == ArrayTypeInt) {
        uint cursorOffset = Offset;

        ArrayBufferObject<int> arrayBufferObject = new ArrayBufferObject<int>(BufferObject.Hint.StaticCpuDraw);

        for (uint i = 0; i < Count; i++) {
            foreach (ColladaParam param in Params) {
                if (param.Name != null)
                    arrayBufferObject[cursorOffset - Offset] = (int) colladaArray[cursorOffset];
                cursorOffset++;
            }
            cursorOffset += Stride - (uint)Params.Count;
        }

        bufferObject = arrayBufferObject;
    } else
        throw new NotSupportedException(String.Format("simple accessor params type {0} not supported", simpleParamsType));

    return (bufferObject);
}

As you can see, there are two if branches that are the same. Essentially they create a generic class using float and int type.

The class ArrayBufferObject is the base of ArrayBufferObject<T>, but only the latter implements an indexer (strongly typed). It is implemented as following:

public T this[uint index]
{
    get
    {
        if ((MemoryBuffer == null) || (MemoryBuffer.AlignedBuffer == IntPtr.Zero))
            throw new InvalidOperationException("not defined");
        if (index >= ItemCount)
            throw new ArgumentException("index out of bounds", "index");

        return ((T) Marshal.PtrToStructure(new IntPtr(MemoryBuffer.AlignedBuffer.ToInt64() + (index * mItemSize)), typeof(T)));
    }
    set
    {
        if ((MemoryBuffer == null) || (MemoryBuffer.AlignedBuffer == IntPtr.Zero))
            throw new InvalidOperationException("not defined");
        if (index >= ItemCount)
            throw new ArgumentException("index out of bounds", "index");

        Marshal.StructureToPtr(value, new IntPtr(MemoryBuffer.AlignedBuffer.ToInt64() + (index * mItemSize)), false);
    }
}

The source of the assigned item comes from a ColladaArray class, that is an abstract class wrapping an array of values. To resolve the data accessor I've defined in it a generic numeric accessor like the following:

/// <summary>
/// Access this array.
/// </summary>
/// <param name="i">
/// The index of the element to be accessed.
/// </param>
/// <returns>
/// It returns an equivalent <see cref="System.Double"/> of the value accessed.
/// </returns>
public virtual double this[uint i] { get { throw new NotSupportedException("array accessor not implemented"); } }

Which is implemented in each derived class returning the real array value casted to double (all arrays contains numeric data... hopefully).


How would you suggest to remove the GetAccessorArray routine redundancies? Help! Soon it will grow up with all possible numeric types!

\$\endgroup\$

2 Answers 2

4
\$\begingroup\$

Presumably you could pull those sections out into a generic method.

private ArrayBufferObject CreateArrayBuffer<T>(ColladaArray colladaArray)
{
     uint cursorOffset = Offset;

     ArrayBufferObject<T> arrayBufferObject = new ArrayBufferObject<T>(BufferObject.Hint.StaticCpuDraw);

     for (uint i = 0; i < Count; i++)
     {
         foreach (ColladaParam param in Params)
         {
             if (param.Name != null)
                 arrayBufferObject[cursorOffset - Offset] = (T)Convert.ChangeType(colladaArray[cursorOffset], typeof(T));
             cursorOffset++;
         }
         cursorOffset += Stride - (uint)Params.Count;
     }

     return arrayBufferObject;
}

And then replace those sections with a call to that method.

if (simpleParamsType == ArrayTypeFloat)
    return CreateArrayBuffer<float>(colladaArray);
else if (simpleParamsType == ArrayTypeInt)
    return CreateArrayBuffer<int>(colladaArray);
else
    throw new NotSupportedException(String.Format("simple accessor params type {0} not supported", simpleParamsType));

Depending on the types that you're converting to and from, the call to Convert.ChangeType() may have to be changed to something else, but it should be sufficient for the standard numeric types. For more information on type conversion, see this.

\$\endgroup\$
1
  • \$\begingroup\$ I got it too after good sleeping, but I was missing the "generic cast"! \$\endgroup\$
    – Luca
    Commented Jan 21, 2012 at 8:37
1
\$\begingroup\$

Ahhh ... C# and numeric generics. Been experimenting with that myself quite a bit in order to interpolate any types.

Originally I used the Arithmetic library, which worked practically just as fast as normal math operators.

My latest implementation follows an idea by Marc Gravell, borrowed from the MiscUtils library. At the moment all the code in my library has been converted to use an Operator class in order to do generic calculations. First benchmarks show it runs just as fast as before when using the Arithmetic library.

There's quite a bit of theory behind it, which I'm not going to explain all here, but Arithmetic and Operator are the two most important sources on the subject. Operator uses expression trees which is only available starting from .NET 3.5, should that be a concern.

\$\endgroup\$
1
  • \$\begingroup\$ The code is quite complex. I'll attempt extracting some relevant portions of it tomorrow. \$\endgroup\$ Commented Jan 21, 2012 at 2:35

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.