Add builtin function "partition"

The implementation of "partition" in Nixpkgs is O(n^2) (because of the
use of ++), and for some reason was causing stack overflows in
multi-threaded evaluation (not sure why).

This reduces "nix-env -qa --drv-path" runtime by 0.197s and memory
usage by 298 MiB (in non-Boehm mode).
This commit is contained in:
Eelco Dolstra 2016-08-29 17:28:20 +02:00
parent c0a7b84748
commit 26d92017d3
7 changed files with 54 additions and 10 deletions

View file

@ -293,6 +293,8 @@ EvalState::EvalState(const Strings & _searchPath, ref<Store> store)
, sColumn(symbols.create("column")) , sColumn(symbols.create("column"))
, sFunctor(symbols.create("__functor")) , sFunctor(symbols.create("__functor"))
, sToString(symbols.create("__toString")) , sToString(symbols.create("__toString"))
, sRight(symbols.create("right"))
, sWrong(symbols.create("wrong"))
, store(store) , store(store)
, baseEnv(allocEnv(128)) , baseEnv(allocEnv(128))
, staticBaseEnv(false, 0) , staticBaseEnv(false, 0)

View file

@ -71,7 +71,8 @@ public:
const Symbol sWith, sOutPath, sDrvPath, sType, sMeta, sName, sValue, const Symbol sWith, sOutPath, sDrvPath, sType, sMeta, sName, sValue,
sSystem, sOverrides, sOutputs, sOutputName, sIgnoreNulls, sSystem, sOverrides, sOutputs, sOutputName, sIgnoreNulls,
sFile, sLine, sColumn, sFunctor, sToString; sFile, sLine, sColumn, sFunctor, sToString,
sRight, sWrong;
Symbol sDerivationNix; Symbol sDerivationNix;
/* If set, force copying files to the Nix store even if they /* If set, force copying files to the Nix store even if they

View file

@ -12,15 +12,6 @@ static void skipWhitespace(const char * & s)
} }
#if HAVE_BOEHMGC
typedef std::vector<Value *, gc_allocator<Value *> > ValueVector;
typedef std::map<Symbol, Value *, std::less<Symbol>, gc_allocator<Value *> > ValueMap;
#else
typedef std::vector<Value *> ValueVector;
typedef std::map<Symbol, Value *> ValueMap;
#endif
static string parseJSONString(const char * & s) static string parseJSONString(const char * & s)
{ {
string res; string res;

View file

@ -1443,6 +1443,40 @@ static void prim_sort(EvalState & state, const Pos & pos, Value * * args, Value
} }
static void prim_partition(EvalState & state, const Pos & pos, Value * * args, Value & v)
{
state.forceFunction(*args[0], pos);
state.forceList(*args[1], pos);
auto len = args[1]->listSize();
ValueVector right, wrong;
for (unsigned int n = 0; n < len; ++n) {
auto vElem = args[1]->listElems()[n];
state.forceValue(*vElem);
Value res;
state.callFunction(*args[0], *vElem, res, pos);
if (state.forceBool(res))
right.push_back(vElem);
else
wrong.push_back(vElem);
}
state.mkAttrs(v, 2);
Value * vRight = state.allocAttr(v, state.sRight);
state.mkList(*vRight, right.size());
memcpy(vRight->listElems(), right.data(), sizeof(Value *) * right.size());
Value * vWrong = state.allocAttr(v, state.sWrong);
state.mkList(*vWrong, wrong.size());
memcpy(vWrong->listElems(), wrong.data(), sizeof(Value *) * wrong.size());
v.attrs->sort();
}
/************************************************************* /*************************************************************
* Integer arithmetic * Integer arithmetic
*************************************************************/ *************************************************************/
@ -1881,6 +1915,7 @@ void EvalState::createBaseEnv()
addPrimOp("__all", 2, prim_all); addPrimOp("__all", 2, prim_all);
addPrimOp("__genList", 2, prim_genList); addPrimOp("__genList", 2, prim_genList);
addPrimOp("__sort", 2, prim_sort); addPrimOp("__sort", 2, prim_sort);
addPrimOp("__partition", 2, prim_partition);
// Integer arithmetic // Integer arithmetic
addPrimOp("__add", 2, prim_add); addPrimOp("__add", 2, prim_add);

View file

@ -250,4 +250,13 @@ void mkPath(Value & v, const char * s);
size_t valueSize(Value & v); size_t valueSize(Value & v);
#if HAVE_BOEHMGC
typedef std::vector<Value *, gc_allocator<Value *> > ValueVector;
typedef std::map<Symbol, Value *, std::less<Symbol>, gc_allocator<Value *> > ValueMap;
#else
typedef std::vector<Value *> ValueVector;
typedef std::map<Symbol, Value *> ValueMap;
#endif
} }

View file

@ -0,0 +1 @@
{ right = [ 0 2 4 6 8 10 100 102 104 106 108 110 ]; wrong = [ 1 3 5 7 9 101 103 105 107 109 ]; }

View file

@ -0,0 +1,5 @@
with import ./lib.nix;
builtins.partition
(x: x / 2 * 2 == x)
(builtins.concatLists [ (range 0 10) (range 100 110) ])