array mutation functions

This commit is contained in:
Ari Lazier 2015-08-28 14:41:30 -07:00
parent 36703bebcb
commit bd39239f00
3 changed files with 136 additions and 7 deletions

View File

@ -83,8 +83,97 @@ void ArrayPropertyNames(JSContextRef ctx, JSObjectRef object, JSPropertyNameAccu
JSValueRef ArrayPush(JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* jsException) { JSValueRef ArrayPush(JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* jsException) {
try { try {
ObjectArray *array = RJSGetInternal<ObjectArray *>(thisObject); ObjectArray *array = RJSGetInternal<ObjectArray *>(thisObject);
RJSValidateArgumentCount(argumentCount, 1); RJSValidateArgumentCountIsAtLeast(argumentCount, 1);
array->link_view->add(RJSAccessor::to_object_index(ctx, array->realm, const_cast<JSValueRef &>(arguments[0]), array->object_schema.name, false)); for (size_t i = 0; i < argumentCount; i++) {
array->link_view->add(RJSAccessor::to_object_index(ctx, array->realm, const_cast<JSValueRef &>(arguments[i]), array->object_schema.name, false));
}
return JSValueMakeNumber(ctx, array->link_view->size());
}
catch (std::exception &exp) {
if (jsException) {
*jsException = RJSMakeError(ctx, exp);
}
}
return NULL;
}
JSValueRef ArrayPop(JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* jsException) {
try {
ObjectArray *array = RJSGetInternal<ObjectArray *>(thisObject);
RJSValidateArgumentCount(argumentCount, 0);
if (array->link_view->size() == 0) {
return JSValueMakeUndefined(ctx);
}
size_t index = array->link_view->size()-1;
JSValueRef obj = RJSObjectCreate(ctx, Object(array->realm, array->object_schema, array->get(array->link_view->size()-1)));
array->link_view->remove(index);
return obj;
}
catch (std::exception &exp) {
if (jsException) {
*jsException = RJSMakeError(ctx, exp);
}
}
return NULL;
}
JSValueRef ArrayUnshift(JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* jsException) {
try {
ObjectArray *array = RJSGetInternal<ObjectArray *>(thisObject);
RJSValidateArgumentCountIsAtLeast(argumentCount, 1);
for (size_t i = 0; i < argumentCount; i++) {
array->link_view->insert(i, RJSAccessor::to_object_index(ctx, array->realm, const_cast<JSValueRef &>(arguments[i]), array->object_schema.name, false));
}
return JSValueMakeNumber(ctx, array->link_view->size());
}
catch (std::exception &exp) {
if (jsException) {
*jsException = RJSMakeError(ctx, exp);
}
}
return NULL;
}
JSValueRef ArrayShift(JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* jsException) {
try {
ObjectArray *array = RJSGetInternal<ObjectArray *>(thisObject);
RJSValidateArgumentCount(argumentCount, 0);
if (array->link_view->size() == 0) {
return JSValueMakeUndefined(ctx);
}
JSValueRef obj = RJSObjectCreate(ctx, Object(array->realm, array->object_schema, array->get(0)));
array->link_view->remove(0);
return obj;
}
catch (std::exception &exp) {
if (jsException) {
*jsException = RJSMakeError(ctx, exp);
}
}
return NULL;
}
JSValueRef ArraySplice(JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* jsException) {
try {
ObjectArray *array = RJSGetInternal<ObjectArray *>(thisObject);
RJSValidateArgumentCountIsAtLeast(argumentCount, 2);
long index = RJSValidatedValueToNumber(ctx, arguments[0]);
if (index < 0) {
index = array->link_view->size() - index;
}
long remove = RJSValidatedValueToNumber(ctx, arguments[1]);
if (index + remove >= array->link_view->size()) {
throw std::runtime_error("Attempting to slice elements beyond Array bounds.");
}
while (remove-- > 0) {
array->link_view->remove(index);
}
for (size_t i = 2; i < argumentCount; i++) {
array->link_view->insert(index + i - 2, RJSAccessor::to_object_index(ctx, array->realm, const_cast<JSValueRef &>(arguments[i]), array->object_schema.name, false));
}
return JSValueMakeNumber(ctx, array->link_view->size());
} }
catch (std::exception &exp) { catch (std::exception &exp) {
if (jsException) { if (jsException) {
@ -101,6 +190,10 @@ JSObjectRef RJSArrayCreate(JSContextRef ctx, realm::ObjectArray *array) {
JSClassRef RJSArrayClass() { JSClassRef RJSArrayClass() {
const JSStaticFunction arrayFuncs[] = { const JSStaticFunction arrayFuncs[] = {
{"push", ArrayPush, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontEnum | kJSPropertyAttributeDontDelete}, {"push", ArrayPush, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontEnum | kJSPropertyAttributeDontDelete},
{"pop", ArrayPop, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontEnum | kJSPropertyAttributeDontDelete},
{"shift", ArrayShift, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontEnum | kJSPropertyAttributeDontDelete},
{"unshift", ArrayUnshift, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontEnum | kJSPropertyAttributeDontDelete},
{"splice", ArraySplice, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontEnum | kJSPropertyAttributeDontDelete},
{NULL, NULL}, {NULL, NULL},
}; };
static JSClassRef s_arrayClass = RJSCreateWrapperClass<Object>("RealmArray", ArrayGetProperty, NULL, arrayFuncs, NULL, ArrayPropertyNames); static JSClassRef s_arrayClass = RJSCreateWrapperClass<Object>("RealmArray", ArrayGetProperty, NULL, arrayFuncs, NULL, ArrayPropertyNames);

View File

@ -66,6 +66,12 @@ inline void RJSValidateArgumentCount(size_t argumentCount, size_t expected) {
} }
} }
inline void RJSValidateArgumentCountIsAtLeast(size_t argumentCount, size_t expected) {
if (argumentCount < expected) {
throw std::invalid_argument("Invalid arguments");
}
}
inline void RJSValidateArgumentRange(size_t argumentCount, size_t min, size_t max) { inline void RJSValidateArgumentRange(size_t argumentCount, size_t min, size_t max) {
if (argumentCount < min || argumentCount > max) { if (argumentCount < min || argumentCount > max) {
throw std::invalid_argument("Invalid arguments"); throw std::invalid_argument("Invalid arguments");

View File

@ -113,18 +113,48 @@ var ArrayTests = {
TestCase.assertEqual(obj.arrayCol.length, 1); TestCase.assertEqual(obj.arrayCol.length, 1);
array = obj.arrayCol; array = obj.arrayCol;
array.push([4]); TestCase.assertEqual(array.push([4]), 2);
TestCase.assertEqual(array.length, 2); TestCase.assertEqual(array.length, 2);
TestCase.assertEqual(array[1].doubleCol, 4); TestCase.assertEqual(array[1].doubleCol, 4);
array.push(obj.objectCol); TestCase.assertEqual(array.push(obj.objectCol, obj.objectCol1), 4);
TestCase.assertEqual(array.length, 3); TestCase.assertEqual(array.length, 4);
TestCase.assertEqual(array[2].doubleCol, 1); TestCase.assertEqual(array[2].doubleCol, 1);
TestCase.assertEqual(array[3].doubleCol, 2);
TestCase.assertThrows(function() {
array.push();
});
}); });
TestCase.assertEqual(array.length, 3); TestCase.assertEqual(array.length, 4);
TestCase.assertThrows(function() { TestCase.assertThrows(function() {
array.push([1]); array.push([1]);
}); });
} },
testUnshift: function() {
var realm = new Realm({schema: [LinkTypesObjectSchema, TestObjectSchema]});
var array;
realm.write(function() {
var obj = realm.create('LinkTypesObject', [[1], [2], [[3]]]);
TestCase.assertEqual(obj.arrayCol.length, 1);
array = obj.arrayCol;
TestCase.assertEqual(array.unshift([5]), 2);
TestCase.assertEqual(array.length, 2);
TestCase.assertEqual(array[0].doubleCol, 5);
TestCase.assertEqual(array.unshift(obj.objectCol, obj.objectCol1), 4);
TestCase.assertEqual(array.length, 4);
TestCase.assertEqual(array[0].doubleCol, 1);
TestCase.assertEqual(array[1].doubleCol, 2);
});
TestCase.assertEqual(array.length, 4);
TestCase.assertThrows(function() {
array.unshift([1]);
});
},
}; };