1
0
Fork 0

stringification of function parameters

This commit is contained in:
Jan Steemann 2014-08-07 11:44:22 +02:00
parent 720285acfe
commit 8e229ec2b2
9 changed files with 404 additions and 143 deletions

View File

@ -1025,6 +1025,7 @@ namespace triagens {
AggregateNode (std::vector<std::pair<Variable const*, Variable const*>> aggregateVariables, AggregateNode (std::vector<std::pair<Variable const*, Variable const*>> aggregateVariables,
Variable const* outVariable) Variable const* outVariable)
: ExecutionNode(), _aggregateVariables(aggregateVariables), _outVariable(outVariable) { : ExecutionNode(), _aggregateVariables(aggregateVariables), _outVariable(outVariable) {
// outVariable can be a nullptr
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
@ -1068,7 +1069,7 @@ namespace triagens {
private: private:
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
/// @brief input/output variables for the aggregation (out = in) /// @brief input/output variables for the aggregation (out, in)
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
std::vector<std::pair<Variable const*, Variable const*>> _aggregateVariables; std::vector<std::pair<Variable const*, Variable const*>> _aggregateVariables;

180
arangod/Aql/Function.cpp Normal file
View File

@ -0,0 +1,180 @@
////////////////////////////////////////////////////////////////////////////////
/// @brief Aql, built-in AQL function
///
/// @file
///
/// DISCLAIMER
///
/// Copyright 2014 ArangoDB GmbH, Cologne, Germany
/// Copyright 2004-2014 triAGENS GmbH, Cologne, Germany
///
/// Licensed under the Apache License, Version 2.0 (the "License");
/// you may not use this file except in compliance with the License.
/// You may obtain a copy of the License at
///
/// http://www.apache.org/licenses/LICENSE-2.0
///
/// Unless required by applicable law or agreed to in writing, software
/// distributed under the License is distributed on an "AS IS" BASIS,
/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
/// See the License for the specific language governing permissions and
/// limitations under the License.
///
/// Copyright holder is ArangoDB GmbH, Cologne, Germany
///
/// @author Jan Steemann
/// @author Copyright 2014, ArangoDB GmbH, Cologne, Germany
/// @author Copyright 2012-2013, triAGENS GmbH, Cologne, Germany
////////////////////////////////////////////////////////////////////////////////
#include "Aql/Function.h"
#include "Utils/Exception.h"
using namespace triagens::aql;
// -----------------------------------------------------------------------------
// --SECTION-- constructors / destructors
// -----------------------------------------------------------------------------
////////////////////////////////////////////////////////////////////////////////
/// @brief create the function
////////////////////////////////////////////////////////////////////////////////
Function::Function (std::string const& name,
std::string const& arguments,
bool isDeterministic)
: name(name),
arguments(arguments),
isDeterministic(isDeterministic),
containsCollectionParameter(false) {
initArguments();
}
////////////////////////////////////////////////////////////////////////////////
/// @brief destroy the function
////////////////////////////////////////////////////////////////////////////////
Function::~Function () {
}
// -----------------------------------------------------------------------------
// --SECTION-- public methods
// -----------------------------------------------------------------------------
////////////////////////////////////////////////////////////////////////////////
/// @brief whether or not a positional argument needs to be converted from a
/// collection parameter to a collection name parameter
////////////////////////////////////////////////////////////////////////////////
bool Function::mustConvertArgument (size_t position) const {
bool foundArg = false;
size_t i = 0;
char const* p = arguments.c_str();
while (true) {
char const c = *p++;
switch (c) {
case '\0':
return false;
case '|':
case ',':
if (foundArg) {
if (++i > position) {
return false;
}
}
foundArg = false;
break;
case 'h':
if (i == position) {
// found an argument to convert
return true;
}
foundArg = true;
break;
default:
foundArg = true;
}
}
return false;
}
////////////////////////////////////////////////////////////////////////////////
/// @brief parse the argument list and set the minimum and maximum number of
/// arguments
////////////////////////////////////////////////////////////////////////////////
void Function::initArguments () {
minRequiredArguments = maxRequiredArguments = 0;
// setup some parsing state
bool inOptional = false;
bool foundArg = false;
char const* p = arguments.c_str();
while (true) {
char const c = *p++;
switch (c) {
case '\0':
// end of argument list
if (foundArg) {
if (! inOptional) {
++minRequiredArguments;
}
++maxRequiredArguments;
}
return;
case '|':
// beginning of optional arguments
TRI_ASSERT(! inOptional);
if (foundArg) {
++minRequiredArguments;
++maxRequiredArguments;
}
inOptional = true;
foundArg = false;
break;
case ',':
// next argument
TRI_ASSERT(foundArg);
if (! inOptional) {
++minRequiredArguments;
}
++maxRequiredArguments;
foundArg = false;
break;
case '+':
// repeated optional argument
TRI_ASSERT(inOptional);
maxRequiredArguments = MaxArguments;
return;
default:
if (c == 'h') {
// note that we found a collection parameter
containsCollectionParameter = true;
}
foundArg = true;
}
}
}
// -----------------------------------------------------------------------------
// --SECTION-- END-OF-FILE
// -----------------------------------------------------------------------------
// Local Variables:
// mode: outline-minor
// outline-regexp: "/// @brief\\|/// {@inheritDoc}\\|/// @page\\|// --SECTION--\\|/// @\\}"
// End:

View File

@ -1,5 +1,5 @@
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
/// @brief Aql, built-in function /// @brief Aql, built-in AQL function
/// ///
/// @file /// @file
/// ///
@ -43,19 +43,20 @@ namespace triagens {
Function () = delete; Function () = delete;
Function (std::string const& name, ////////////////////////////////////////////////////////////////////////////////
std::string const& arguments, /// @brief create the function
bool isDeterministic) ////////////////////////////////////////////////////////////////////////////////
: name(name),
arguments(arguments),
isDeterministic(isDeterministic) {
initArguments(); Function (std::string const&,
} std::string const&,
bool);
~Function () { ////////////////////////////////////////////////////////////////////////////////
} /// @brief destroy the function
////////////////////////////////////////////////////////////////////////////////
~Function ();
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
// --SECTION-- public methods // --SECTION-- public methods
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
@ -77,67 +78,20 @@ namespace triagens {
return std::make_pair(minRequiredArguments, maxRequiredArguments); return std::make_pair(minRequiredArguments, maxRequiredArguments);
} }
////////////////////////////////////////////////////////////////////////////////
/// @brief whether or not a positional argument needs to be converted from a
/// collection parameter to a collection name parameter
////////////////////////////////////////////////////////////////////////////////
bool mustConvertArgument (size_t) const;
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
/// @brief parse the argument list and set the minimum and maximum number of /// @brief parse the argument list and set the minimum and maximum number of
/// arguments /// arguments
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
void initArguments () { void initArguments ();
minRequiredArguments = maxRequiredArguments = 0;
// setup some parsing state
bool inOptional = false;
bool foundArg = false;
char const* p = arguments.c_str();
while (true) {
char const c = *p++;
switch (c) {
case '\0':
// end of argument list
if (foundArg) {
if (! inOptional) {
++minRequiredArguments;
}
++maxRequiredArguments;
}
return;
case '|':
// beginning of optional arguments
TRI_ASSERT(! inOptional);
if (foundArg) {
++minRequiredArguments;
++maxRequiredArguments;
}
inOptional = true;
foundArg = false;
break;
case ',':
// next argument
TRI_ASSERT(foundArg);
if (! inOptional) {
++minRequiredArguments;
}
++maxRequiredArguments;
foundArg = false;
break;
case '+':
// repeated optional argument
TRI_ASSERT(inOptional);
maxRequiredArguments = MaxArguments;
return;
default:
foundArg = true;
}
}
}
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
// --SECTION-- public variables // --SECTION-- public variables
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
@ -161,6 +115,13 @@ namespace triagens {
bool const isDeterministic; bool const isDeterministic;
////////////////////////////////////////////////////////////////////////////////
/// @brief whether or not the function contains a collection parameter that
/// will cause some special conversion during function calls
////////////////////////////////////////////////////////////////////////////////
bool containsCollectionParameter;
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
/// @brief minimum number of required arguments /// @brief minimum number of required arguments
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////

View File

@ -404,6 +404,18 @@ void V8Executor::generateCodeExpression (AstNode const* node) {
_buffer->appendText("; })"); _buffer->appendText("; })");
} }
////////////////////////////////////////////////////////////////////////////////
/// @brief generates code for a string value
////////////////////////////////////////////////////////////////////////////////
void V8Executor::generateCodeString (char const* value) {
TRI_ASSERT(value != nullptr);
_buffer->appendChar('"');
_buffer->appendJsonEncoded(value);
_buffer->appendChar('"');
}
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
/// @brief generate JavaScript code for a list /// @brief generate JavaScript code for a list
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
@ -440,11 +452,12 @@ void V8Executor::generateCodeArray (AstNode const* node) {
} }
auto member = node->getMember(i); auto member = node->getMember(i);
_buffer->appendText("\""); if (member != nullptr) {
_buffer->appendJsonEncoded(member->getStringValue()); generateCodeString(member->getStringValue());
_buffer->appendText("\" : "); _buffer->appendText(" : ");
generateCodeNode(member->getMember(0)); generateCodeNode(member->getMember(0));
}
} }
_buffer->appendText(" }"); _buffer->appendText(" }");
} }
@ -547,9 +560,9 @@ void V8Executor::generateCodeReference (AstNode const* node) {
auto variable = static_cast<Variable*>(node->getData()); auto variable = static_cast<Variable*>(node->getData());
_buffer->appendText("vars[\""); _buffer->appendText("vars[");
_buffer->appendJsonEncoded(variable->name.c_str()); generateCodeString(variable->name.c_str());
_buffer->appendText("\"]"); _buffer->appendText("]");
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
@ -561,10 +574,10 @@ void V8Executor::generateCodeVariable (AstNode const* node) {
TRI_ASSERT(node->numMembers() == 0); TRI_ASSERT(node->numMembers() == 0);
auto variable = static_cast<Variable*>(node->getData()); auto variable = static_cast<Variable*>(node->getData());
_buffer->appendText("vars[\""); _buffer->appendText("vars[");
_buffer->appendJsonEncoded(variable->name.c_str()); generateCodeString(variable->name.c_str());
_buffer->appendText("\"]"); _buffer->appendText("]");
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
@ -577,9 +590,9 @@ void V8Executor::generateCodeCollection (AstNode const* node) {
char const* name = node->getStringValue(); char const* name = node->getStringValue();
_buffer->appendText("aql.GET_DOCUMENTS(\""); _buffer->appendText("aql.GET_DOCUMENTS(");
_buffer->appendJsonEncoded(name); generateCodeString(name);
_buffer->appendText("\")"); _buffer->appendText(")");
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
@ -606,7 +619,20 @@ void V8Executor::generateCodeFunctionCall (AstNode const* node) {
_buffer->appendText(", "); _buffer->appendText(", ");
} }
generateCodeNode(args->getMember(i)); auto member = args->getMember(i);
if (member != nullptr) {
if (member->type == NODE_TYPE_COLLECTION &&
func->containsCollectionParameter) {
// do a parameter conversion from a collection parameter to a collection name parameter
char const* name = member->getStringValue();
generateCodeString(name);
}
else {
// generate regular code for the node
generateCodeNode(args->getMember(i));
}
}
} }
_buffer->appendText(")"); _buffer->appendText(")");
} }
@ -626,9 +652,9 @@ void V8Executor::generateCodeUserFunctionCall (AstNode const* node) {
TRI_ASSERT(args != nullptr); TRI_ASSERT(args != nullptr);
TRI_ASSERT(args->type == NODE_TYPE_LIST); TRI_ASSERT(args->type == NODE_TYPE_LIST);
_buffer->appendText("aql.FCALL_USER(\""); _buffer->appendText("aql.FCALL_USER(");
_buffer->appendJsonEncoded(name); generateCodeString(name);
_buffer->appendText("\", ["); _buffer->appendText(", [");
size_t const n = args->numMembers(); size_t const n = args->numMembers();
for (size_t i = 0; i < n; ++i) { for (size_t i = 0; i < n; ++i) {
@ -693,9 +719,9 @@ void V8Executor::generateCodeNamedAccess (AstNode const* node) {
_buffer->appendText("aql.DOCUMENT_MEMBER("); _buffer->appendText("aql.DOCUMENT_MEMBER(");
generateCodeNode(node->getMember(0)); generateCodeNode(node->getMember(0));
_buffer->appendText(", \""); _buffer->appendText(", ");
_buffer->appendJsonEncoded(node->getStringValue()); generateCodeString(node->getStringValue());
_buffer->appendText("\")"); _buffer->appendText(")");
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////

View File

@ -114,6 +114,12 @@ namespace triagens {
void generateCodeExpression (AstNode const*); void generateCodeExpression (AstNode const*);
////////////////////////////////////////////////////////////////////////////////
/// @brief generates code for a string value
////////////////////////////////////////////////////////////////////////////////
void generateCodeString (char const*);
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
/// @brief generate JavaScript code for a list /// @brief generate JavaScript code for a list
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////

View File

@ -0,0 +1,113 @@
////////////////////////////////////////////////////////////////////////////////
/// @brief Aql, V8 expression
///
/// @file
///
/// DISCLAIMER
///
/// Copyright 2014 ArangoDB GmbH, Cologne, Germany
/// Copyright 2004-2014 triAGENS GmbH, Cologne, Germany
///
/// Licensed under the Apache License, Version 2.0 (the "License");
/// you may not use this file except in compliance with the License.
/// You may obtain a copy of the License at
///
/// http://www.apache.org/licenses/LICENSE-2.0
///
/// Unless required by applicable law or agreed to in writing, software
/// distributed under the License is distributed on an "AS IS" BASIS,
/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
/// See the License for the specific language governing permissions and
/// limitations under the License.
///
/// Copyright holder is ArangoDB GmbH, Cologne, Germany
///
/// @author Jan Steemann
/// @author Copyright 2014, ArangoDB GmbH, Cologne, Germany
/// @author Copyright 2012-2013, triAGENS GmbH, Cologne, Germany
////////////////////////////////////////////////////////////////////////////////
#include "Aql/V8Expression.h"
#include "Aql/V8Executor.h"
#include "BasicsC/json.h"
#include "V8/v8-conv.h"
using namespace triagens::aql;
// -----------------------------------------------------------------------------
// --SECTION-- constructors / destructors
// -----------------------------------------------------------------------------
////////////////////////////////////////////////////////////////////////////////
/// @brief create the v8 expression
////////////////////////////////////////////////////////////////////////////////
V8Expression::V8Expression (v8::Isolate* isolate,
v8::Persistent<v8::Function> func)
: isolate(isolate),
func(func) {
}
////////////////////////////////////////////////////////////////////////////////
/// @brief destroy the v8 expression
////////////////////////////////////////////////////////////////////////////////
V8Expression::~V8Expression () {
func.Dispose(isolate);
func.Clear();
}
// -----------------------------------------------------------------------------
// --SECTION-- public methods
// -----------------------------------------------------------------------------
////////////////////////////////////////////////////////////////////////////////
/// @brief execute the expression
////////////////////////////////////////////////////////////////////////////////
AqlValue V8Expression::execute (AQL_TRANSACTION_V8* trx,
std::vector<TRI_document_collection_t const*>& docColls,
std::vector<AqlValue>& argv,
size_t startPos,
std::vector<Variable*> const& vars,
std::vector<RegisterId> const& regs) {
size_t const n = vars.size();
TRI_ASSERT(regs.size() == n); // assert same vector length
v8::Handle<v8::Object> values = v8::Object::New();
for (size_t i = 0; i < n; ++i) {
auto varname = vars[i]->name;
auto reg = regs[i];
TRI_ASSERT(! argv[reg].isEmpty());
values->Set(v8::String::New(varname.c_str(), (int) varname.size()), argv[startPos + reg].toV8(trx, docColls[reg]));
}
// set function arguments
v8::Handle<v8::Value> args[] = { values };
// execute the function
v8::TryCatch tryCatch;
v8::Handle<v8::Value> result = func->Call(func, 1, args);
V8Executor::HandleV8Error(tryCatch, result);
TRI_json_t* json = TRI_ObjectToJson(result);
if (json == nullptr) {
THROW_ARANGO_EXCEPTION(TRI_ERROR_OUT_OF_MEMORY);
}
return AqlValue(new triagens::basics::Json(TRI_UNKNOWN_MEM_ZONE, json));
}
// -----------------------------------------------------------------------------
// --SECTION-- END-OF-FILE
// -----------------------------------------------------------------------------
// Local Variables:
// mode: outline-minor
// outline-regexp: "/// @brief\\|/// {@inheritDoc}\\|/// @page\\|// --SECTION--\\|/// @\\}"
// End:

View File

@ -1,5 +1,5 @@
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
/// @brief Aql, V8 execution context /// @brief Aql, V8 expression
/// ///
/// @file /// @file
/// ///
@ -31,10 +31,7 @@
#define ARANGODB_AQL_V8_EXPRESSION_H 1 #define ARANGODB_AQL_V8_EXPRESSION_H 1
#include "Basics/Common.h" #include "Basics/Common.h"
#include "Basics/JsonHelper.h"
#include "BasicsC/json.h"
#include "Aql/Types.h" #include "Aql/Types.h"
#include "V8/v8-conv.h"
#include <v8.h> #include <v8.h>
namespace triagens { namespace triagens {
@ -46,73 +43,46 @@ namespace triagens {
struct V8Expression { struct V8Expression {
// -----------------------------------------------------------------------------
// --SECTION-- constructors / destructors
// -----------------------------------------------------------------------------
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
/// @brief create the v8 expression /// @brief create the v8 expression
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
V8Expression (v8::Isolate* isolate, V8Expression (v8::Isolate*,
v8::Persistent<v8::Function> func) v8::Persistent<v8::Function>);
: isolate(isolate),
func(func) {
}
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
/// @brief destroy the v8 expression /// @brief destroy the v8 expression
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
~V8Expression () { ~V8Expression ();
func.Dispose(isolate);
func.Clear(); // -----------------------------------------------------------------------------
} // --SECTION-- public methods
// -----------------------------------------------------------------------------
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
/// @brief execute the expression /// @brief execute the expression
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
AqlValue execute (AQL_TRANSACTION_V8* trx, AqlValue execute (AQL_TRANSACTION_V8*,
std::vector<TRI_document_collection_t const*>& docColls, std::vector<TRI_document_collection_t const*>&,
std::vector<AqlValue>& argv, std::vector<AqlValue>&,
size_t startPos, size_t,
std::vector<Variable*> const& vars, std::vector<Variable*> const&,
std::vector<RegisterId> const& regs) { std::vector<RegisterId> const&);
// TODO: decide whether a separate handle scope is needed
size_t const n = vars.size(); // -----------------------------------------------------------------------------
TRI_ASSERT(regs.size() == n); // assert same vector length // --SECTION-- public variables
// -----------------------------------------------------------------------------
v8::Handle<v8::Object> values = v8::Object::New(); v8::Isolate* isolate;
for (size_t i = 0; i < n; ++i) {
auto varname = vars[i]->name;
auto reg = regs[i];
TRI_ASSERT(! argv[reg].isEmpty()); v8::Persistent<v8::Function> func;
values->Set(v8::String::New(varname.c_str(), (int) varname.size()), argv[startPos + reg].toV8(trx, docColls[reg]));
}
// set function arguments
v8::Handle<v8::Value> args[] = { values };
// execute the function
v8::TryCatch tryCatch;
v8::Handle<v8::Value> result = func->Call(func, 1, args);
V8Executor::HandleV8Error(tryCatch, result);
TRI_json_t* json = TRI_ObjectToJson(result);
if (json == nullptr) {
THROW_ARANGO_EXCEPTION(TRI_ERROR_OUT_OF_MEMORY);
}
return AqlValue(new triagens::basics::Json(TRI_UNKNOWN_MEM_ZONE, json));
}
v8::Isolate* isolate;
v8::Persistent<v8::Function> func;
}; };
} }

View File

@ -65,6 +65,7 @@ add_executable(
Aql/ExecutionNode.cpp Aql/ExecutionNode.cpp
Aql/ExecutionPlan.cpp Aql/ExecutionPlan.cpp
Aql/Expression.cpp Aql/Expression.cpp
Aql/Function.cpp
Aql/grammar.cpp Aql/grammar.cpp
Aql/Parser.cpp Aql/Parser.cpp
Aql/Query.cpp Aql/Query.cpp
@ -72,6 +73,7 @@ add_executable(
Aql/Types.cpp Aql/Types.cpp
Aql/tokens.cpp Aql/tokens.cpp
Aql/V8Executor.cpp Aql/V8Executor.cpp
Aql/V8Expression.cpp
Aql/Variable.cpp Aql/Variable.cpp
Aql/VariableGenerator.cpp Aql/VariableGenerator.cpp
BitIndexes/bitarray.cpp BitIndexes/bitarray.cpp

View File

@ -46,6 +46,7 @@ arangod_libarangod_a_SOURCES = \
arangod/Aql/ExecutionNode.cpp \ arangod/Aql/ExecutionNode.cpp \
arangod/Aql/ExecutionPlan.cpp \ arangod/Aql/ExecutionPlan.cpp \
arangod/Aql/Expression.cpp \ arangod/Aql/Expression.cpp \
arangod/Aql/Function.cpp \
arangod/Aql/grammar.cpp \ arangod/Aql/grammar.cpp \
arangod/Aql/Parser.cpp \ arangod/Aql/Parser.cpp \
arangod/Aql/Query.cpp \ arangod/Aql/Query.cpp \
@ -53,6 +54,7 @@ arangod_libarangod_a_SOURCES = \
arangod/Aql/Types.cpp \ arangod/Aql/Types.cpp \
arangod/Aql/tokens.cpp \ arangod/Aql/tokens.cpp \
arangod/Aql/V8Executor.cpp \ arangod/Aql/V8Executor.cpp \
arangod/Aql/V8Expression.cpp \
arangod/Aql/Variable.cpp \ arangod/Aql/Variable.cpp \
arangod/Aql/VariableGenerator.cpp \ arangod/Aql/VariableGenerator.cpp \
arangod/BitIndexes/bitarray.cpp \ arangod/BitIndexes/bitarray.cpp \