henrikrudstrom/oce-wrap

View on GitHub
src/features/collection.js

Summary

Maintainability
B
5 hrs
Test Coverage
const features = require('../features.js');


// ----------------------------------------------------------------------------
// configuration functions
// ----------------------------------------------------------------------------

function typemapIndexedMap(collectionMod, elemType) {
  var listType = collectionMod + '_IndexedMapOf' + elemType.split('_')[1];
  return this.typemap(listType, 'Array', 'indexedMap', { elemType });
}

function typemapList(collectionMod, elemType) {
  var listType = collectionMod + '_ListOf' + elemType.split('_')[1];
  return this.typemap(listType, 'Array', 'list', { elemType });
}

function typemapArray1(collectionMod, elemType) {
  var listType = collectionMod + '_Array1Of' + elemType.split('_')[1];
  return this.typemap(listType, 'Array', 'array1', { elemType });
}

features.registerConfig(typemapIndexedMap, typemapList, typemapArray1);


// ----------------------------------------------------------------------------
// SWIG rendering
// ----------------------------------------------------------------------------

function isPrimitive(elemType) {
  return elemType === 'Standard_Real' ||
    elemType === 'Standard_Integer' ||
    elemType === 'Standard_Boolean';
}

function swigValue(type, arg) {
  if (type.indexOf('Standard_Real') !== -1)
    return `SWIGV8_NUMBER_NEW(${arg})`;
  if (type.indexOf('Standard_Boolean') !== -1)
    return `SWIGV8_BOOLEAN_NEW(${arg})`;
  if (type.indexOf('Standard_Integer') !== -1)
    return `SWIGV8_INTEGER_NEW(${arg})`;

  return `SWIG_NewPointerObj((${type}*)(${arg}), $descriptor(${type} *), SWIG_POINTER_OWN |  0 )`;
}

function nativeValue(type, arg) {
  if (type.indexOf('Standard_Real') !== -1)
    return `SWIG_AsVal(double)(${arg}, &argpointer)`;
  if (type.indexOf('Standard_Boolean') !== -1)
    return `SWIG_AsVal(bool)(${arg}, &argpointer)`;
  if (type.indexOf('Standard_Integer') !== -1)
  // not sure if SWIG_AsVal is always in the swig file
    return `SWIG_AsVal(int)(${arg}, &argpointer)`;

  return `SWIG_ConvertPtr(${arg}, (void **)&argpointer, $descriptor(${type} *), 0)`;
}


// ----------------------------------------------------------------------------
// array to native collection helpers
// ----------------------------------------------------------------------------

function arrayToNative(input, output, content) {
  return `\
    v8::Handle<v8::Array> array = v8::Handle<v8::Array>::Cast(${input});
    int length = array->Get(SWIGV8_SYMBOL_NEW("length"))->ToObject()->Uint32Value();

    ${content}

    ${output} = list;`;
}

function arrayToSettable(listType, elemType, setter) {
  var deref = isPrimitive(elemType) ? '' : '*';
  return `\
    ${listType} * list = new ${listType}(1, length);
    ${elemType} ${deref}argpointer;

    for(int i = 1; i <= length; i++){
      ${nativeValue(elemType, 'array->Get(i-1)')};
      list->${setter}(i, (const ${elemType} &)${deref}argpointer);
    }`;
}

function arrayToAppendable(listType, elemType, add) {
  var deref = isPrimitive(elemType) ? '' : '*';
  return `\
    ${listType} * list = new ${listType}();
    ${elemType} ${deref}argpointer;

    for(int i = 1; i <= length; i++){
      ${nativeValue(elemType, 'array->Get(i-1)')};
      list->${add}((const ${elemType} &)${deref}argpointer);
    }`;
}


// ----------------------------------------------------------------------------
// Native collections to array helpers
// -------------------------------------------------------------------------

function nativeToArray(input, output, getSize, content, byVal) {
  var op = byVal ? '.' : '->';
  return `\
    v8::Local<v8::Array> array = v8::Array::New(
      v8::Isolate::GetCurrent(), ${input}${op}${getSize}());
    int length = ${input}${op}${getSize}();
    ${content}
    ${output} = array;
    `;
}

function assignSettable(input, elemType, getExpr) {
  if (isPrimitive(elemType)) {
    return `array->Set(i-1, ${swigValue(elemType, getExpr)});`;
  }
  var typemap = features.getTypemap(elemType);
  var render = features.getTypemapRenderer(typemap);
  if (render) {
    return 'v8::Handle<v8::Value> '
      + render.toWrapped(getExpr, 'val') + '\n    array->Set(i-1, val);';
  }
  return `\
    ${elemType} * val = new ${elemType}(${getExpr});
    array->Set(i-1, ${swigValue(elemType, 'val')});`;
}

function iterableToArray(input, listType, elemType) {
  var name = listType.split('_')[1];
  var mod = listType.split('_')[0];
  var assign = assignSettable(input, elemType, 'iterator.Value()');
  return `\
       ${mod}_ListIteratorOf${name} iterator($1);
    int i = 0;
    while(iterator.More()) {
      ${assign}
      iterator.Next();
      i++;
    }`;
}

function indexableToArray(input, elemType, getter) {
  var assign = assignSettable(input, elemType, input + '->' + getter + '(i)');
  return `\
    for(int i = 1; i <= length; i++){
      ${assign}
    }`;
}


features.registerTypemapRenderer('array1', function array1Typemap(tm) {
  return {
    toNative(input, output) {
      return arrayToNative(input, output,
        arrayToSettable(tm.native, tm.elemType, 'SetValue')
      );
    },

    toWrapped(input, output) {
      return nativeToArray(input, output, 'Length',
        indexableToArray(input, tm.elemType, 'Value')
      );
    },

    initArgout(decl) {
      return `new ${tm.native}(1,arg1->${decl.getParent().lengthProperty});`;
    },
    freearg(arg) {
      return `${arg}->Destroy();`;
    }
  };
});

features.registerTypemapRenderer('list', function listTypemap(tm) {
  return {
    toNative(input, output) {
      return arrayToNative(input, output,
        arrayToAppendable(tm.native, tm.elemType, 'Append')
      );
    },

    toWrapped(input, output) {
      return nativeToArray(input, output, 'Extent',
        iterableToArray(input, tm.native, tm.elemType), true
      );
    }
  };
});

features.registerTypemapRenderer('indexedMap', function indexedMapTypemap(tm) {
  return {
    toNative(input, output) {
      return arrayToNative(input, output,
        arrayToAppendable(tm.native, tm.elemType, 'Add')
      );
    },

    toWrapped(input, output) {
      return nativeToArray(input, output, 'Extent',
        indexableToArray(input, tm.elemType, 'FindKey')
      );
    }
  };
});