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) {
try {
ObjectArray *array = RJSGetInternal<ObjectArray *>(thisObject);
RJSValidateArgumentCount(argumentCount, 1);
array->link_view->add(RJSAccessor::to_object_index(ctx, array->realm, const_cast<JSValueRef &>(arguments[0]), array->object_schema.name, false));
RJSValidateArgumentCountIsAtLeast(argumentCount, 1);
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) {
if (jsException) {
@ -101,6 +190,10 @@ JSObjectRef RJSArrayCreate(JSContextRef ctx, realm::ObjectArray *array) {
JSClassRef RJSArrayClass() {
const JSStaticFunction arrayFuncs[] = {
{"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},
};
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) {
if (argumentCount < min || argumentCount > max) {
throw std::invalid_argument("Invalid arguments");

View File

@ -113,18 +113,48 @@ var ArrayTests = {
TestCase.assertEqual(obj.arrayCol.length, 1);
array = obj.arrayCol;
array.push([4]);
TestCase.assertEqual(array.push([4]), 2);
TestCase.assertEqual(array.length, 2);
TestCase.assertEqual(array[1].doubleCol, 4);
array.push(obj.objectCol);
TestCase.assertEqual(array.length, 3);
TestCase.assertEqual(array.push(obj.objectCol, obj.objectCol1), 4);
TestCase.assertEqual(array.length, 4);
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() {
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]);
});
},
};