Provide an efficient implementation of ‘elem’

The one in Nixpkgs is O(n^2), this one is O(n).  Big reduction in the
number of list allocations.

Statistics before (on a NixOS system config):

  time elapsed: 1.17982
  size of a value: 24
  environments allocated: 1543334 (39624560 bytes)
  list elements: 9612638 (76901104 bytes)
  list concatenations: 37434
  values allocated: 1854933 (44518392 bytes)
  attribute sets allocated: 392040
  right-biased unions: 186334
  values copied in right-biased unions: 591137
  symbols in symbol table: 18272
  number of thunks: 1392467
  number of thunks avoided: 1507311
  number of attr lookups: 430801
  number of primop calls: 691600
  number of function calls: 1492502

Statistics after:

  time elapsed: 1.08683
  size of a value: 24
  environments allocated: 1384376 (35809568 bytes)
  list elements: 6946783 (55574264 bytes)
  list concatenations: 37434
  values allocated: 1760440 (42250560 bytes)
  attribute sets allocated: 392040
  right-biased unions: 186334
  values copied in right-biased unions: 591137
  symbols in symbol table: 18273
  number of thunks: 1297673
  number of thunks avoided: 1380759
  number of attr lookups: 430802
  number of primop calls: 628912
  number of function calls: 1333544
This commit is contained in:
Eelco Dolstra 2012-08-13 01:05:35 -04:00
parent 4ccd48ce24
commit b9e5b908ed

View file

@ -880,7 +880,8 @@ static void prim_head(EvalState & state, Value * * args, Value & v)
/* Return a list consisting of everything but the the first element of /* Return a list consisting of everything but the the first element of
a list. */ a list. Warning: this function takes O(n) time, so you probably
don't want to use it! */
static void prim_tail(EvalState & state, Value * * args, Value & v) static void prim_tail(EvalState & state, Value * * args, Value & v)
{ {
state.forceList(*args[0]); state.forceList(*args[0]);
@ -930,6 +931,19 @@ static void prim_filter(EvalState & state, Value * * args, Value & v)
} }
static void prim_elem(EvalState & state, Value * * args, Value & v)
{
bool res = false;
state.forceList(*args[1]);
for (unsigned int n = 0; n < args[1]->list.length; ++n)
if (state.eqValues(*args[0], *args[1]->list.elems[n])) {
res = true;
break;
}
mkBool(v, res);
}
/* Return the length of a list. This is an O(1) time operation. */ /* Return the length of a list. This is an O(1) time operation. */
static void prim_length(EvalState & state, Value * * args, Value & v) static void prim_length(EvalState & state, Value * * args, Value & v)
{ {
@ -1145,8 +1159,9 @@ void EvalState::createBaseEnv()
addPrimOp("__tail", 1, prim_tail); addPrimOp("__tail", 1, prim_tail);
addPrimOp("map", 2, prim_map); addPrimOp("map", 2, prim_map);
addPrimOp("__filter", 2, prim_filter); addPrimOp("__filter", 2, prim_filter);
addPrimOp("__elem", 2, prim_elem);
addPrimOp("__length", 1, prim_length); addPrimOp("__length", 1, prim_length);
// Integer arithmetic // Integer arithmetic
addPrimOp("__add", 2, prim_add); addPrimOp("__add", 2, prim_add);
addPrimOp("__sub", 2, prim_sub); addPrimOp("__sub", 2, prim_sub);