1
0
Fork 0

fixed array range accesses

This commit is contained in:
Jan Steemann 2015-06-12 23:45:08 +02:00
parent 3e9f2e8873
commit c5d099a1c5
4 changed files with 214 additions and 77 deletions

View File

@ -278,9 +278,91 @@ void Expression::invalidate () {
} }
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
// --SECTION-- private functions // --SECTION-- private methods
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
////////////////////////////////////////////////////////////////////////////////
/// @brief extracts a range from an array
////////////////////////////////////////////////////////////////////////////////
AqlValue Expression::extractRange (AqlValue const& result,
AqlValue const& indexResult,
TRI_document_collection_t const* collection,
triagens::arango::AqlTransaction* trx) const {
TRI_ASSERT(result.isArray());
size_t const length = result.arraySize();
if (length == 0) {
// cannot extract anything from an empty array
return AqlValue(new Json(Json::Array));
}
int64_t low = indexResult.getRange()->_low;
int64_t high = indexResult.getRange()->_high;
// negative positions are translated into their positive counterparts
if (low < 0) {
low = static_cast<int64_t>(length) + low;
}
if (high < 0) {
high = static_cast<int64_t>(length) + high;
}
std::unique_ptr<Json> array(new Json(Json::Array));
if (low <= high) {
// forward iteration
// adjust bounds
if (low < 0) {
low = 0;
}
if (high >= static_cast<int64_t>(length)) {
high = static_cast<int64_t>(length);
}
else {
// increase by one so we include the last specified element
++high;
}
if (low <= high) {
array->reserve(static_cast<size_t>(high - low));
// forward iteration
for (int64_t position = low; position < high; ++position) {
auto j = result.extractArrayMember(trx, collection, position, true);
array->add(j);
}
}
}
else {
// backward iteration
// swap low and high
int64_t tmp = low;
low = high;
high = tmp;
// backward iteration
if (low < 0) {
low = 0;
}
if (high < 0) {
high = 0;
}
else if (high >= static_cast<int64_t>(length)) {
high = static_cast<int64_t>(length) - 1;
}
if (high >= low) {
array->reserve(static_cast<size_t>(high - low + 1));
for (int64_t position = high; position >= low; --position) {
auto j = result.extractArrayMember(trx, collection, position, true);
array->add(j);
}
}
}
return AqlValue(array.release());
}
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
/// @brief find a value in an AQL list node /// @brief find a value in an AQL list node
/// this performs either a binary search (if the node is sorted) or a /// this performs either a binary search (if the node is sorted) or a
@ -521,78 +603,14 @@ AqlValue Expression::executeSimpleExpression (AstNode const* node,
} }
} }
else if (indexResult.isRange()) { else if (indexResult.isRange()) {
size_t const length = result.arraySize();
if (length == 0) {
// cannot extract anything from an empty array
result.destroy();
return AqlValue(new Json(Json::Array));
}
int64_t low = indexResult.getRange()->_low;
int64_t high = indexResult.getRange()->_high;
indexResult.destroy();
// negative positions are translated into their positive counterparts
if (low < 0) {
low = static_cast<int64_t>(length) + low;
}
if (high < 0) {
high = static_cast<int64_t>(length) + high;
}
try { try {
std::unique_ptr<Json> array(new Json(Json::Array)); auto range = extractRange(result, indexResult, myCollection, trx);
indexResult.destroy();
if (low <= high) {
// adjust bounds
if (low < 0) {
low = 0;
}
if (high >= static_cast<int64_t>(length)) {
high = static_cast<int64_t>(length);
}
else {
// increase by one so we include the last specified element
++high;
}
if (low <= high) {
array->reserve(static_cast<size_t>(high - low));
// forward iteration
for (int64_t position = low; position < high; ++position) {
auto j = result.extractArrayMember(trx, myCollection, position, true);
array->add(j);
}
}
}
else {
// swap
int64_t tmp = low;
low = high;
high = tmp;
// backward iteration
if (low < 0) {
low = 0;
}
if (high < 0) {
high = 0;
}
else if (high >= static_cast<int64_t>(length)) {
high = static_cast<int64_t>(length) - 1;
}
array->reserve(static_cast<size_t>(high - low + 1));
for (int64_t position = high; position >= low; --position) {
auto j = result.extractArrayMember(trx, myCollection, position, true);
array->add(j);
}
}
result.destroy(); result.destroy();
return range;
return AqlValue(array.release());
} }
catch (...) { catch (...) {
indexResult.destroy();
result.destroy(); result.destroy();
throw; throw;
} }

View File

@ -291,11 +291,20 @@ namespace triagens {
void invalidate (); void invalidate ();
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
// --SECTION-- private functions // --SECTION-- private methods
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
private: private:
////////////////////////////////////////////////////////////////////////////////
/// @brief extracts a range from an array
////////////////////////////////////////////////////////////////////////////////
AqlValue extractRange (AqlValue const&,
AqlValue const&,
TRI_document_collection_t const*,
triagens::arango::AqlTransaction*) const;
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
/// @brief find a value in an array /// @brief find a value in an array
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////

View File

@ -994,7 +994,7 @@ function GET_RANGE (value, low, high) {
'use strict'; 'use strict';
if (TYPEWEIGHT(value) !== TYPEWEIGHT_ARRAY) { if (TYPEWEIGHT(value) !== TYPEWEIGHT_ARRAY) {
return [ ]; return null;
} }
low = parseInt(low, 10); low = parseInt(low, 10);
@ -1039,10 +1039,12 @@ function GET_RANGE (value, low, high) {
else if (high >= value.length) { else if (high >= value.length) {
high = value.length - 1; high = value.length - 1;
} }
if (high >= low) {
for (position = high; position >= low; --position) { for (position = high; position >= low; --position) {
result.push(value[position]); result.push(value[position]);
} }
} }
}
return result; return result;
} }

View File

@ -131,6 +131,24 @@ function arrayAccessTestSuite () {
assertEqual([ null ], result); assertEqual([ null ], result);
}, },
////////////////////////////////////////////////////////////////////////////////
/// @brief test non-array access
////////////////////////////////////////////////////////////////////////////////
testV8NonArrayRange1 : function () {
var result = AQL_EXECUTE("RETURN NOOPT(V8({ foo: 'bar' }))[0..1]").json;
assertEqual([ null ], result);
},
////////////////////////////////////////////////////////////////////////////////
/// @brief test non-array access
////////////////////////////////////////////////////////////////////////////////
testV8NonArrayRange2 : function () {
var result = AQL_EXECUTE("RETURN NOOPT(V8({ foo: 'bar' }))[-2..-1]").json;
assertEqual([ null ], result);
},
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
/// @brief test subquery result /// @brief test subquery result
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
@ -143,7 +161,7 @@ function arrayAccessTestSuite () {
}, },
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
/// @brief test subquery result /// @brief test range result
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
testSubqueryResultRangeForward1 : function () { testSubqueryResultRangeForward1 : function () {
@ -158,7 +176,7 @@ function arrayAccessTestSuite () {
}, },
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
/// @brief test subquery result /// @brief test range result
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
testSubqueryResultRangeForward2 : function () { testSubqueryResultRangeForward2 : function () {
@ -170,6 +188,96 @@ function arrayAccessTestSuite () {
} }
assertEqual([ expected ], result); assertEqual([ expected ], result);
} }
},
////////////////////////////////////////////////////////////////////////////////
/// @brief test range result
////////////////////////////////////////////////////////////////////////////////
testSubqueryResultRangeBackward1 : function () {
for (var to = 0; to < 10; ++to) {
var result = AQL_EXECUTE("RETURN (FOR value IN @values RETURN value)[10.." + to + "]", { values: values }).json;
var expected = [ ];
for (var i = Math.min(10, values.length - 1); i >= to; --i) {
expected.push(values[i]);
}
assertEqual([ expected ], result);
}
},
////////////////////////////////////////////////////////////////////////////////
/// @brief test range result
////////////////////////////////////////////////////////////////////////////////
testSubqueryResultRangeBackward2 : function () {
for (var from = 0; from < 10; ++from) {
var result = AQL_EXECUTE("RETURN (FOR value IN @values RETURN value)[" + from + "..0]", { values: values }).json;
var expected = [ ];
for (var i = Math.min(from, values.length - 1); i >= 0; --i) {
expected.push(values[i]);
}
assertEqual([ expected ], result);
}
},
////////////////////////////////////////////////////////////////////////////////
/// @brief test range result
////////////////////////////////////////////////////////////////////////////////
testV8SubqueryResultRangeForward1 : function () {
for (var to = 0; to < 10; ++to) {
var result = AQL_EXECUTE("RETURN NOOPT(V8(FOR value IN @values RETURN value))[0.." + to + "]", { values: values }).json;
var expected = [ ];
for (var i = 0; i < Math.min(to + 1, values.length); ++i) {
expected.push(values[i]);
}
assertEqual([ expected ], result);
}
},
////////////////////////////////////////////////////////////////////////////////
/// @brief test range result
////////////////////////////////////////////////////////////////////////////////
testV8SubqueryResultRangeForward2 : function () {
for (var from = 0; from < 10; ++from) {
var result = AQL_EXECUTE("RETURN NOOPT(V8(FOR value IN @values RETURN value))[" + from + "..99]", { values: values }).json;
var expected = [ ];
for (var i = Math.min(from, values.length); i < values.length; ++i) {
expected.push(values[i]);
}
assertEqual([ expected ], result);
}
},
////////////////////////////////////////////////////////////////////////////////
/// @brief test range result
////////////////////////////////////////////////////////////////////////////////
testV8SubqueryResultRangeBackward1 : function () {
for (var to = 0; to < 10; ++to) {
var result = AQL_EXECUTE("RETURN NOOPT(V8(FOR value IN @values RETURN value))[10.." + to + "]", { values: values }).json;
var expected = [ ];
for (var i = Math.min(10, values.length - 1); i >= to; --i) {
expected.push(values[i]);
}
assertEqual([ expected ], result);
}
},
////////////////////////////////////////////////////////////////////////////////
/// @brief test range result
////////////////////////////////////////////////////////////////////////////////
testV8SubqueryResultRangeBackward2 : function () {
for (var from = 0; from < 10; ++from) {
var result = AQL_EXECUTE("RETURN NOOPT(V8(FOR value IN @values RETURN value))[" + from + "..0]", { values: values }).json;
var expected = [ ];
for (var i = Math.min(from, values.length - 1); i >= 0; --i) {
expected.push(values[i]);
}
assertEqual([ expected ], result);
}
} }
}; };