Add a primop ‘concatLists’
This can serve as a generic efficient list builder. For instance, the function ‘catAttrs’ in Nixpkgs can be rewritten from attr: l: fold (s: l: if hasAttr attr s then [(getAttr attr s)] ++ l else l) [] l to attr: l: builtins.concatLists (map (s: if hasAttr attr s then [(getAttr attr s)] else []) l) Statistics before: 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 Statistics after (including new catAttrs): time elapsed: 0.959854 size of a value: 24 environments allocated: 1010198 (26829296 bytes) list elements: 1984878 (15879024 bytes) list concatenations: 30488 values allocated: 1589760 (38154240 bytes) attribute sets allocated: 392040 right-biased unions: 186334 values copied in right-biased unions: 591137 symbols in symbol table: 18274 number of thunks: 1040925 number of thunks avoided: 1038428 number of attr lookups: 438419 number of primop calls: 474844 number of function calls: 959366
This commit is contained in:
		
							parent
							
								
									b9e5b908ed
								
							
						
					
					
						commit
						198d0338be
					
				
					 3 changed files with 33 additions and 8 deletions
				
			
		|  | @ -912,16 +912,29 @@ void ExprOpUpdate::eval(EvalState & state, Env & env, Value & v) | ||||||
| 
 | 
 | ||||||
| void ExprOpConcatLists::eval(EvalState & state, Env & env, Value & v) | void ExprOpConcatLists::eval(EvalState & state, Env & env, Value & v) | ||||||
| { | { | ||||||
|     state.nrListConcats++; |  | ||||||
|     Value v1; e1->eval(state, env, v1); |     Value v1; e1->eval(state, env, v1); | ||||||
|     state.forceList(v1); |  | ||||||
|     Value v2; e2->eval(state, env, v2); |     Value v2; e2->eval(state, env, v2); | ||||||
|     state.forceList(v2); |     Value * lists[2] = { &v1, &v2 }; | ||||||
|     state.mkList(v, v1.list.length + v2.list.length); |     state.concatLists(v, 2, lists); | ||||||
|     for (unsigned int n = 0; n < v1.list.length; ++n) | } | ||||||
|         v.list.elems[n] = v1.list.elems[n]; | 
 | ||||||
|     for (unsigned int n = 0; n < v2.list.length; ++n) | 
 | ||||||
|         v.list.elems[n + v1.list.length] = v2.list.elems[n]; | void EvalState::concatLists(Value & v, unsigned int nrLists, Value * * lists) | ||||||
|  | { | ||||||
|  |     nrListConcats++; | ||||||
|  |      | ||||||
|  |     unsigned int len = 0; | ||||||
|  |     for (unsigned int n = 0; n < nrLists; ++n) { | ||||||
|  |         forceList(*lists[n]); | ||||||
|  |         len += lists[n]->list.length; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     mkList(v, len); | ||||||
|  |     for (unsigned int n = 0, pos = 0; n < nrLists; ++n) { | ||||||
|  |         unsigned int l = lists[n]->list.length; | ||||||
|  |         memcpy(v.list.elems + pos, lists[n]->list.elems, l * sizeof(Value *)); | ||||||
|  |         pos += l; | ||||||
|  |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -232,6 +232,8 @@ public: | ||||||
|     void mkAttrs(Value & v, unsigned int expected); |     void mkAttrs(Value & v, unsigned int expected); | ||||||
|     void mkThunk_(Value & v, Expr * expr); |     void mkThunk_(Value & v, Expr * expr); | ||||||
| 
 | 
 | ||||||
|  |     void concatLists(Value & v, unsigned int nrLists, Value * * lists); | ||||||
|  | 
 | ||||||
|     /* Print statistics. */ |     /* Print statistics. */ | ||||||
|     void printStats(); |     void printStats(); | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -931,6 +931,7 @@ static void prim_filter(EvalState & state, Value * * args, Value & v) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|  | /* Return true if a list contains a given element. */ | ||||||
| static void prim_elem(EvalState & state, Value * * args, Value & v) | static void prim_elem(EvalState & state, Value * * args, Value & v) | ||||||
| { | { | ||||||
|     bool res = false; |     bool res = false; | ||||||
|  | @ -944,6 +945,14 @@ static void prim_elem(EvalState & state, Value * * args, Value & v) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|  | /* Concatenate a list of lists. */ | ||||||
|  | static void prim_concatLists(EvalState & state, Value * * args, Value & v) | ||||||
|  | { | ||||||
|  |     state.forceList(*args[0]); | ||||||
|  |     state.concatLists(v, args[0]->list.length, args[0]->list.elems); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
| /* 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) | ||||||
| { | { | ||||||
|  | @ -1160,6 +1169,7 @@ void EvalState::createBaseEnv() | ||||||
|     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("__elem", 2, prim_elem); | ||||||
|  |     addPrimOp("__concatLists", 1, prim_concatLists); | ||||||
|     addPrimOp("__length", 1, prim_length); |     addPrimOp("__length", 1, prim_length); | ||||||
| 
 | 
 | ||||||
|     // Integer arithmetic
 |     // Integer arithmetic
 | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue