Optimize small lists
The value pointers of lists with 1 or 2 elements are now stored in the list value itself. In particular, this makes the "concatMap (x: if cond then [(f x)] else [])" idiom cheaper.
This commit is contained in:
		
							parent
							
								
									14be783676
								
							
						
					
					
						commit
						b83801f8b3
					
				
					 11 changed files with 157 additions and 121 deletions
				
			
		| 
						 | 
				
			
			@ -76,15 +76,15 @@ Value * findAlongAttrPath(EvalState & state, const string & attrPath,
 | 
			
		|||
 | 
			
		||||
        else if (apType == apIndex) {
 | 
			
		||||
 | 
			
		||||
            if (v->type != tList)
 | 
			
		||||
            if (!v->isList())
 | 
			
		||||
                throw TypeError(
 | 
			
		||||
                    format("the expression selected by the selection path ‘%1%’ should be a list but is %2%")
 | 
			
		||||
                    % attrPath % showType(*v));
 | 
			
		||||
 | 
			
		||||
            if (attrIndex >= v->list.length)
 | 
			
		||||
            if (attrIndex >= v->listSize())
 | 
			
		||||
                throw Error(format("list index %1% in selection path ‘%2%’ is out of range") % attrIndex % attrPath);
 | 
			
		||||
 | 
			
		||||
            v = v->list.elems[attrIndex];
 | 
			
		||||
            v = v->listElems()[attrIndex];
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
    }
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -66,7 +66,7 @@ inline void EvalState::forceAttrs(Value & v, const Pos & pos)
 | 
			
		|||
inline void EvalState::forceList(Value & v)
 | 
			
		||||
{
 | 
			
		||||
    forceValue(v);
 | 
			
		||||
    if (v.type != tList)
 | 
			
		||||
    if (!v.isList())
 | 
			
		||||
        throwTypeError("value is %1% while a list was expected", v);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -74,7 +74,7 @@ inline void EvalState::forceList(Value & v)
 | 
			
		|||
inline void EvalState::forceList(Value & v, const Pos & pos)
 | 
			
		||||
{
 | 
			
		||||
    forceValue(v);
 | 
			
		||||
    if (v.type != tList)
 | 
			
		||||
    if (!v.isList())
 | 
			
		||||
        throwTypeError("value is %1% while a list was expected, at %2%", v, pos);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -108,10 +108,12 @@ static void printValue(std::ostream & str, std::set<const Value *> & active, con
 | 
			
		|||
        str << "}";
 | 
			
		||||
        break;
 | 
			
		||||
    }
 | 
			
		||||
    case tList:
 | 
			
		||||
    case tList1:
 | 
			
		||||
    case tList2:
 | 
			
		||||
    case tListN:
 | 
			
		||||
        str << "[ ";
 | 
			
		||||
        for (unsigned int n = 0; n < v.list.length; ++n) {
 | 
			
		||||
            printValue(str, active, *v.list.elems[n]);
 | 
			
		||||
        for (unsigned int n = 0; n < v.listSize(); ++n) {
 | 
			
		||||
            printValue(str, active, *v.listElems()[n]);
 | 
			
		||||
            str << " ";
 | 
			
		||||
        }
 | 
			
		||||
        str << "]";
 | 
			
		||||
| 
						 | 
				
			
			@ -157,7 +159,7 @@ string showType(const Value & v)
 | 
			
		|||
        case tPath: return "a path";
 | 
			
		||||
        case tNull: return "null";
 | 
			
		||||
        case tAttrs: return "a set";
 | 
			
		||||
        case tList: return "a list";
 | 
			
		||||
        case tList1: case tList2: case tListN: return "a list";
 | 
			
		||||
        case tThunk: return "a thunk";
 | 
			
		||||
        case tApp: return "a function application";
 | 
			
		||||
        case tLambda: return "a function";
 | 
			
		||||
| 
						 | 
				
			
			@ -519,13 +521,19 @@ Bindings * EvalState::allocBindings(Bindings::size_t capacity)
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
void EvalState::mkList(Value & v, unsigned int length)
 | 
			
		||||
void EvalState::mkList(Value & v, unsigned int size)
 | 
			
		||||
{
 | 
			
		||||
    clearValue(v);
 | 
			
		||||
    v.type = tList;
 | 
			
		||||
    v.list.length = length;
 | 
			
		||||
    v.list.elems = length ? (Value * *) allocBytes(length * sizeof(Value *)) : 0;
 | 
			
		||||
    nrListElems += length;
 | 
			
		||||
    if (size == 1)
 | 
			
		||||
        v.type = tList1;
 | 
			
		||||
    else if (size == 2)
 | 
			
		||||
        v.type = tList2;
 | 
			
		||||
    else {
 | 
			
		||||
        v.type = tListN;
 | 
			
		||||
        v.bigList.size = size;
 | 
			
		||||
        v.bigList.elems = size ? (Value * *) allocBytes(size * sizeof(Value *)) : 0;
 | 
			
		||||
    }
 | 
			
		||||
    nrListElems += size;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -807,8 +815,8 @@ void ExprLet::eval(EvalState & state, Env & env, Value & v)
 | 
			
		|||
void ExprList::eval(EvalState & state, Env & env, Value & v)
 | 
			
		||||
{
 | 
			
		||||
    state.mkList(v, elems.size());
 | 
			
		||||
    for (unsigned int n = 0; n < v.list.length; ++n)
 | 
			
		||||
        v.list.elems[n] = elems[n]->maybeThunk(state, env);
 | 
			
		||||
    for (unsigned int n = 0; n < elems.size(); ++n)
 | 
			
		||||
        v.listElems()[n] = elems[n]->maybeThunk(state, env);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -1201,20 +1209,21 @@ void EvalState::concatLists(Value & v, unsigned int nrLists, Value * * lists, co
 | 
			
		|||
    unsigned int len = 0;
 | 
			
		||||
    for (unsigned int n = 0; n < nrLists; ++n) {
 | 
			
		||||
        forceList(*lists[n], pos);
 | 
			
		||||
        unsigned int l = lists[n]->list.length;
 | 
			
		||||
        unsigned int l = lists[n]->listSize();
 | 
			
		||||
        len += l;
 | 
			
		||||
        if (l) nonEmpty = lists[n];
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (nonEmpty && len == nonEmpty->list.length) {
 | 
			
		||||
    if (nonEmpty && len == nonEmpty->listSize()) {
 | 
			
		||||
        v = *nonEmpty;
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    mkList(v, len);
 | 
			
		||||
    auto out = v.listElems();
 | 
			
		||||
    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 *));
 | 
			
		||||
        unsigned int l = lists[n]->listSize();
 | 
			
		||||
        memcpy(out + pos, lists[n]->listElems(), l * sizeof(Value *));
 | 
			
		||||
        pos += l;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -1290,9 +1299,9 @@ void EvalState::forceValueDeep(Value & v)
 | 
			
		|||
                }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        else if (v.type == tList) {
 | 
			
		||||
            for (unsigned int n = 0; n < v.list.length; ++n)
 | 
			
		||||
                recurse(*v.list.elems[n]);
 | 
			
		||||
        else if (v.isList()) {
 | 
			
		||||
            for (unsigned int n = 0; n < v.listSize(); ++n)
 | 
			
		||||
                recurse(*v.listElems()[n]);
 | 
			
		||||
        }
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -1416,14 +1425,14 @@ string EvalState::coerceToString(const Pos & pos, Value & v, PathSet & context,
 | 
			
		|||
        if (v.type == tInt) return int2String(v.integer);
 | 
			
		||||
        if (v.type == tNull) return "";
 | 
			
		||||
 | 
			
		||||
        if (v.type == tList) {
 | 
			
		||||
        if (v.isList()) {
 | 
			
		||||
            string result;
 | 
			
		||||
            for (unsigned int n = 0; n < v.list.length; ++n) {
 | 
			
		||||
                result += coerceToString(pos, *v.list.elems[n],
 | 
			
		||||
            for (unsigned int n = 0; n < v.listSize(); ++n) {
 | 
			
		||||
                result += coerceToString(pos, *v.listElems()[n],
 | 
			
		||||
                    context, coerceMore, copyToStore);
 | 
			
		||||
                if (n < v.list.length - 1
 | 
			
		||||
                if (n < v.listSize() - 1
 | 
			
		||||
                    /* !!! not quite correct */
 | 
			
		||||
                    && (v.list.elems[n]->type != tList || v.list.elems[n]->list.length != 0))
 | 
			
		||||
                    && (!v.listElems()[n]->isList() || v.listElems()[n]->listSize() != 0))
 | 
			
		||||
                    result += " ";
 | 
			
		||||
            }
 | 
			
		||||
            return result;
 | 
			
		||||
| 
						 | 
				
			
			@ -1494,10 +1503,12 @@ bool EvalState::eqValues(Value & v1, Value & v2)
 | 
			
		|||
        case tNull:
 | 
			
		||||
            return true;
 | 
			
		||||
 | 
			
		||||
        case tList:
 | 
			
		||||
            if (v1.list.length != v2.list.length) return false;
 | 
			
		||||
            for (unsigned int n = 0; n < v1.list.length; ++n)
 | 
			
		||||
                if (!eqValues(*v1.list.elems[n], *v2.list.elems[n])) return false;
 | 
			
		||||
        case tList1:
 | 
			
		||||
        case tList2:
 | 
			
		||||
        case tListN:
 | 
			
		||||
            if (v1.listSize() != v2.listSize()) return false;
 | 
			
		||||
            for (unsigned int n = 0; n < v1.listSize(); ++n)
 | 
			
		||||
                if (!eqValues(*v1.listElems()[n], *v2.listElems()[n])) return false;
 | 
			
		||||
            return true;
 | 
			
		||||
 | 
			
		||||
        case tAttrs: {
 | 
			
		||||
| 
						 | 
				
			
			@ -1645,12 +1656,14 @@ size_t valueSize(Value & v)
 | 
			
		|||
                    sz += doValue(*i.value);
 | 
			
		||||
            }
 | 
			
		||||
            break;
 | 
			
		||||
        case tList:
 | 
			
		||||
            if (seen.find(v.list.elems) == seen.end()) {
 | 
			
		||||
                seen.insert(v.list.elems);
 | 
			
		||||
                sz += v.list.length * sizeof(Value *);
 | 
			
		||||
                for (unsigned int n = 0; n < v.list.length; ++n)
 | 
			
		||||
                    sz += doValue(*v.list.elems[n]);
 | 
			
		||||
        case tList1:
 | 
			
		||||
        case tList2:
 | 
			
		||||
        case tListN:
 | 
			
		||||
            if (seen.find(v.listElems()) == seen.end()) {
 | 
			
		||||
                seen.insert(v.listElems());
 | 
			
		||||
                sz += v.listSize() * sizeof(Value *);
 | 
			
		||||
                for (unsigned int n = 0; n < v.listSize(); ++n)
 | 
			
		||||
                    sz += doValue(*v.listElems()[n]);
 | 
			
		||||
            }
 | 
			
		||||
            break;
 | 
			
		||||
        case tThunk:
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -39,9 +39,9 @@ DrvInfo::Outputs DrvInfo::queryOutputs()
 | 
			
		|||
            state->forceList(*i->value, *i->pos);
 | 
			
		||||
 | 
			
		||||
            /* For each output... */
 | 
			
		||||
            for (unsigned int j = 0; j < i->value->list.length; ++j) {
 | 
			
		||||
            for (unsigned int j = 0; j < i->value->listSize(); ++j) {
 | 
			
		||||
                /* Evaluate the corresponding set. */
 | 
			
		||||
                string name = state->forceStringNoCtx(*i->value->list.elems[j], *i->pos);
 | 
			
		||||
                string name = state->forceStringNoCtx(*i->value->listElems()[j], *i->pos);
 | 
			
		||||
                Bindings::iterator out = attrs->find(state->symbols.create(name));
 | 
			
		||||
                if (out == attrs->end()) continue; // FIXME: throw error?
 | 
			
		||||
                state->forceAttrs(*out->value);
 | 
			
		||||
| 
						 | 
				
			
			@ -94,9 +94,9 @@ StringSet DrvInfo::queryMetaNames()
 | 
			
		|||
bool DrvInfo::checkMeta(Value & v)
 | 
			
		||||
{
 | 
			
		||||
    state->forceValue(v);
 | 
			
		||||
    if (v.type == tList) {
 | 
			
		||||
        for (unsigned int n = 0; n < v.list.length; ++n)
 | 
			
		||||
            if (!checkMeta(*v.list.elems[n])) return false;
 | 
			
		||||
    if (v.isList()) {
 | 
			
		||||
        for (unsigned int n = 0; n < v.listSize(); ++n)
 | 
			
		||||
            if (!checkMeta(*v.listElems()[n])) return false;
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
    else if (v.type == tAttrs) {
 | 
			
		||||
| 
						 | 
				
			
			@ -277,13 +277,13 @@ static void getDerivations(EvalState & state, Value & vIn,
 | 
			
		|||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    else if (v.type == tList) {
 | 
			
		||||
        for (unsigned int n = 0; n < v.list.length; ++n) {
 | 
			
		||||
    else if (v.isList()) {
 | 
			
		||||
        for (unsigned int n = 0; n < v.listSize(); ++n) {
 | 
			
		||||
            startNest(nest, lvlDebug,
 | 
			
		||||
                format("evaluating list element"));
 | 
			
		||||
            string pathPrefix2 = addToPath(pathPrefix, (format("%1%") % n).str());
 | 
			
		||||
            if (getDerivation(state, *v.list.elems[n], pathPrefix2, drvs, done, ignoreAssertionFailures))
 | 
			
		||||
                getDerivations(state, *v.list.elems[n], pathPrefix2, autoArgs, drvs, done, ignoreAssertionFailures);
 | 
			
		||||
            if (getDerivation(state, *v.listElems()[n], pathPrefix2, drvs, done, ignoreAssertionFailures))
 | 
			
		||||
                getDerivations(state, *v.listElems()[n], pathPrefix2, autoArgs, drvs, done, ignoreAssertionFailures);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -73,7 +73,7 @@ static void parseJSON(EvalState & state, const char * & s, Value & v)
 | 
			
		|||
        s++;
 | 
			
		||||
        state.mkList(v, values.size());
 | 
			
		||||
        for (size_t n = 0; n < values.size(); ++n)
 | 
			
		||||
            v.list.elems[n] = values[n];
 | 
			
		||||
            v.listElems()[n] = values[n];
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    else if (*s == '{') {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -100,8 +100,8 @@ static void prim_scopedImport(EvalState & state, const Pos & pos, Value * * args
 | 
			
		|||
            v2 = state.allocAttr(w, state.symbols.create(o.first));
 | 
			
		||||
            mkString(*v2, o.second.path,
 | 
			
		||||
                singleton<PathSet>("!" + o.first + "!" + path));
 | 
			
		||||
            outputsVal->list.elems[outputs_index] = state.allocValue();
 | 
			
		||||
            mkString(*(outputsVal->list.elems[outputs_index++]), o.first);
 | 
			
		||||
            outputsVal->listElems()[outputs_index] = state.allocValue();
 | 
			
		||||
            mkString(*(outputsVal->listElems()[outputs_index++]), o.first);
 | 
			
		||||
        }
 | 
			
		||||
        w.attrs->sort();
 | 
			
		||||
        Value fun;
 | 
			
		||||
| 
						 | 
				
			
			@ -188,7 +188,7 @@ static void prim_typeOf(EvalState & state, const Pos & pos, Value * * args, Valu
 | 
			
		|||
        case tPath: t = "path"; break;
 | 
			
		||||
        case tNull: t = "null"; break;
 | 
			
		||||
        case tAttrs: t = "set"; break;
 | 
			
		||||
        case tList: t = "list"; break;
 | 
			
		||||
        case tList1: case tList2: case tListN: t = "list"; break;
 | 
			
		||||
        case tLambda:
 | 
			
		||||
        case tPrimOp:
 | 
			
		||||
        case tPrimOpApp:
 | 
			
		||||
| 
						 | 
				
			
			@ -284,8 +284,8 @@ static void prim_genericClosure(EvalState & state, const Pos & pos, Value * * ar
 | 
			
		|||
    state.forceList(*startSet->value, pos);
 | 
			
		||||
 | 
			
		||||
    ValueList workSet;
 | 
			
		||||
    for (unsigned int n = 0; n < startSet->value->list.length; ++n)
 | 
			
		||||
        workSet.push_back(startSet->value->list.elems[n]);
 | 
			
		||||
    for (unsigned int n = 0; n < startSet->value->listSize(); ++n)
 | 
			
		||||
        workSet.push_back(startSet->value->listElems()[n]);
 | 
			
		||||
 | 
			
		||||
    /* Get the operator. */
 | 
			
		||||
    Bindings::iterator op =
 | 
			
		||||
| 
						 | 
				
			
			@ -323,9 +323,9 @@ static void prim_genericClosure(EvalState & state, const Pos & pos, Value * * ar
 | 
			
		|||
        state.forceList(call, pos);
 | 
			
		||||
 | 
			
		||||
        /* Add the values returned by the operator to the work set. */
 | 
			
		||||
        for (unsigned int n = 0; n < call.list.length; ++n) {
 | 
			
		||||
            state.forceValue(*call.list.elems[n]);
 | 
			
		||||
            workSet.push_back(call.list.elems[n]);
 | 
			
		||||
        for (unsigned int n = 0; n < call.listSize(); ++n) {
 | 
			
		||||
            state.forceValue(*call.listElems()[n]);
 | 
			
		||||
            workSet.push_back(call.listElems()[n]);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -333,7 +333,7 @@ static void prim_genericClosure(EvalState & state, const Pos & pos, Value * * ar
 | 
			
		|||
    state.mkList(v, res.size());
 | 
			
		||||
    unsigned int n = 0;
 | 
			
		||||
    for (auto & i : res)
 | 
			
		||||
        v.list.elems[n++] = i;
 | 
			
		||||
        v.listElems()[n++] = i;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -495,8 +495,8 @@ static void prim_derivationStrict(EvalState & state, const Pos & pos, Value * *
 | 
			
		|||
               command-line arguments to the builder. */
 | 
			
		||||
            if (key == "args") {
 | 
			
		||||
                state.forceList(*i.value, pos);
 | 
			
		||||
                for (unsigned int n = 0; n < i.value->list.length; ++n) {
 | 
			
		||||
                    string s = state.coerceToString(posDrvName, *i.value->list.elems[n], context, true);
 | 
			
		||||
                for (unsigned int n = 0; n < i.value->listSize(); ++n) {
 | 
			
		||||
                    string s = state.coerceToString(posDrvName, *i.value->listElems()[n], context, true);
 | 
			
		||||
                    drv.args.push_back(s);
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
| 
						 | 
				
			
			@ -766,8 +766,8 @@ static void prim_findFile(EvalState & state, const Pos & pos, Value * * args, Va
 | 
			
		|||
    SearchPath searchPath;
 | 
			
		||||
 | 
			
		||||
    PathSet context;
 | 
			
		||||
    for (unsigned int n = 0; n < args[0]->list.length; ++n) {
 | 
			
		||||
        Value & v2(*args[0]->list.elems[n]);
 | 
			
		||||
    for (unsigned int n = 0; n < args[0]->listSize(); ++n) {
 | 
			
		||||
        Value & v2(*args[0]->listElems()[n]);
 | 
			
		||||
        state.forceAttrs(v2, pos);
 | 
			
		||||
 | 
			
		||||
        string prefix;
 | 
			
		||||
| 
						 | 
				
			
			@ -972,9 +972,9 @@ static void prim_attrNames(EvalState & state, const Pos & pos, Value * * args, V
 | 
			
		|||
 | 
			
		||||
    unsigned int n = 0;
 | 
			
		||||
    for (auto & i : *args[0]->attrs)
 | 
			
		||||
        mkString(*(v.list.elems[n++] = state.allocValue()), i.name);
 | 
			
		||||
        mkString(*(v.listElems()[n++] = state.allocValue()), i.name);
 | 
			
		||||
 | 
			
		||||
    std::sort(v.list.elems, v.list.elems + n,
 | 
			
		||||
    std::sort(v.listElems(), v.listElems() + n,
 | 
			
		||||
        [](Value * v1, Value * v2) { return strcmp(v1->string.s, v2->string.s) < 0; });
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -989,13 +989,13 @@ static void prim_attrValues(EvalState & state, const Pos & pos, Value * * args,
 | 
			
		|||
 | 
			
		||||
    unsigned int n = 0;
 | 
			
		||||
    for (auto & i : *args[0]->attrs)
 | 
			
		||||
        v.list.elems[n++] = (Value *) &i;
 | 
			
		||||
        v.listElems()[n++] = (Value *) &i;
 | 
			
		||||
 | 
			
		||||
    std::sort(v.list.elems, v.list.elems + n,
 | 
			
		||||
    std::sort(v.listElems(), v.listElems() + n,
 | 
			
		||||
        [](Value * v1, Value * v2) { return (string) ((Attr *) v1)->name < (string) ((Attr *) v2)->name; });
 | 
			
		||||
 | 
			
		||||
    for (unsigned int i = 0; i < n; ++i)
 | 
			
		||||
        v.list.elems[i] = ((Attr *) v.list.elems[i])->value;
 | 
			
		||||
        v.listElems()[i] = ((Attr *) v.listElems()[i])->value;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -1052,9 +1052,9 @@ static void prim_removeAttrs(EvalState & state, const Pos & pos, Value * * args,
 | 
			
		|||
 | 
			
		||||
    /* Get the attribute names to be removed. */
 | 
			
		||||
    std::set<Symbol> names;
 | 
			
		||||
    for (unsigned int i = 0; i < args[1]->list.length; ++i) {
 | 
			
		||||
        state.forceStringNoCtx(*args[1]->list.elems[i], pos);
 | 
			
		||||
        names.insert(state.symbols.create(args[1]->list.elems[i]->string.s));
 | 
			
		||||
    for (unsigned int i = 0; i < args[1]->listSize(); ++i) {
 | 
			
		||||
        state.forceStringNoCtx(*args[1]->listElems()[i], pos);
 | 
			
		||||
        names.insert(state.symbols.create(args[1]->listElems()[i]->string.s));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /* Copy all attributes not in that set.  Note that we don't need
 | 
			
		||||
| 
						 | 
				
			
			@ -1077,12 +1077,12 @@ static void prim_listToAttrs(EvalState & state, const Pos & pos, Value * * args,
 | 
			
		|||
{
 | 
			
		||||
    state.forceList(*args[0], pos);
 | 
			
		||||
 | 
			
		||||
    state.mkAttrs(v, args[0]->list.length);
 | 
			
		||||
    state.mkAttrs(v, args[0]->listSize());
 | 
			
		||||
 | 
			
		||||
    std::set<Symbol> seen;
 | 
			
		||||
 | 
			
		||||
    for (unsigned int i = 0; i < args[0]->list.length; ++i) {
 | 
			
		||||
        Value & v2(*args[0]->list.elems[i]);
 | 
			
		||||
    for (unsigned int i = 0; i < args[0]->listSize(); ++i) {
 | 
			
		||||
        Value & v2(*args[0]->listElems()[i]);
 | 
			
		||||
        state.forceAttrs(v2, pos);
 | 
			
		||||
 | 
			
		||||
        Bindings::iterator j = v2.attrs->find(state.sName);
 | 
			
		||||
| 
						 | 
				
			
			@ -1135,11 +1135,11 @@ static void prim_catAttrs(EvalState & state, const Pos & pos, Value * * args, Va
 | 
			
		|||
    Symbol attrName = state.symbols.create(state.forceStringNoCtx(*args[0], pos));
 | 
			
		||||
    state.forceList(*args[1], pos);
 | 
			
		||||
 | 
			
		||||
    Value * res[args[1]->list.length];
 | 
			
		||||
    Value * res[args[1]->listSize()];
 | 
			
		||||
    unsigned int found = 0;
 | 
			
		||||
 | 
			
		||||
    for (unsigned int n = 0; n < args[1]->list.length; ++n) {
 | 
			
		||||
        Value & v2(*args[1]->list.elems[n]);
 | 
			
		||||
    for (unsigned int n = 0; n < args[1]->listSize(); ++n) {
 | 
			
		||||
        Value & v2(*args[1]->listElems()[n]);
 | 
			
		||||
        state.forceAttrs(v2, pos);
 | 
			
		||||
        Bindings::iterator i = v2.attrs->find(attrName);
 | 
			
		||||
        if (i != v2.attrs->end())
 | 
			
		||||
| 
						 | 
				
			
			@ -1148,7 +1148,7 @@ static void prim_catAttrs(EvalState & state, const Pos & pos, Value * * args, Va
 | 
			
		|||
 | 
			
		||||
    state.mkList(v, found);
 | 
			
		||||
    for (unsigned int n = 0; n < found; ++n)
 | 
			
		||||
        v.list.elems[n] = res[n];
 | 
			
		||||
        v.listElems()[n] = res[n];
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -1193,17 +1193,17 @@ static void prim_functionArgs(EvalState & state, const Pos & pos, Value * * args
 | 
			
		|||
static void prim_isList(EvalState & state, const Pos & pos, Value * * args, Value & v)
 | 
			
		||||
{
 | 
			
		||||
    state.forceValue(*args[0]);
 | 
			
		||||
    mkBool(v, args[0]->type == tList);
 | 
			
		||||
    mkBool(v, args[0]->isList());
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
static void elemAt(EvalState & state, const Pos & pos, Value & list, int n, Value & v)
 | 
			
		||||
{
 | 
			
		||||
    state.forceList(list, pos);
 | 
			
		||||
    if (n < 0 || (unsigned int) n >= list.list.length)
 | 
			
		||||
    if (n < 0 || (unsigned int) n >= list.listSize())
 | 
			
		||||
        throw Error(format("list index %1% is out of bounds, at %2%") % n % pos);
 | 
			
		||||
    state.forceValue(*list.list.elems[n]);
 | 
			
		||||
    v = *list.list.elems[n];
 | 
			
		||||
    state.forceValue(*list.listElems()[n]);
 | 
			
		||||
    v = *list.listElems()[n];
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -1227,11 +1227,11 @@ static void prim_head(EvalState & state, const Pos & pos, Value * * args, Value
 | 
			
		|||
static void prim_tail(EvalState & state, const Pos & pos, Value * * args, Value & v)
 | 
			
		||||
{
 | 
			
		||||
    state.forceList(*args[0], pos);
 | 
			
		||||
    if (args[0]->list.length == 0)
 | 
			
		||||
    if (args[0]->listSize() == 0)
 | 
			
		||||
        throw Error(format("‘tail’ called on an empty list, at %1%") % pos);
 | 
			
		||||
    state.mkList(v, args[0]->list.length - 1);
 | 
			
		||||
    for (unsigned int n = 0; n < v.list.length; ++n)
 | 
			
		||||
        v.list.elems[n] = args[0]->list.elems[n + 1];
 | 
			
		||||
    state.mkList(v, args[0]->listSize() - 1);
 | 
			
		||||
    for (unsigned int n = 0; n < v.listSize(); ++n)
 | 
			
		||||
        v.listElems()[n] = args[0]->listElems()[n + 1];
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -1241,11 +1241,11 @@ static void prim_map(EvalState & state, const Pos & pos, Value * * args, Value &
 | 
			
		|||
    state.forceFunction(*args[0], pos);
 | 
			
		||||
    state.forceList(*args[1], pos);
 | 
			
		||||
 | 
			
		||||
    state.mkList(v, args[1]->list.length);
 | 
			
		||||
    state.mkList(v, args[1]->listSize());
 | 
			
		||||
 | 
			
		||||
    for (unsigned int n = 0; n < v.list.length; ++n)
 | 
			
		||||
        mkApp(*(v.list.elems[n] = state.allocValue()),
 | 
			
		||||
            *args[0], *args[1]->list.elems[n]);
 | 
			
		||||
    for (unsigned int n = 0; n < v.listSize(); ++n)
 | 
			
		||||
        mkApp(*(v.listElems()[n] = state.allocValue()),
 | 
			
		||||
            *args[0], *args[1]->listElems()[n]);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -1258,15 +1258,15 @@ static void prim_filter(EvalState & state, const Pos & pos, Value * * args, Valu
 | 
			
		|||
    state.forceList(*args[1], pos);
 | 
			
		||||
 | 
			
		||||
    // FIXME: putting this on the stack is risky.
 | 
			
		||||
    Value * vs[args[1]->list.length];
 | 
			
		||||
    Value * vs[args[1]->listSize()];
 | 
			
		||||
    unsigned int k = 0;
 | 
			
		||||
 | 
			
		||||
    bool same = true;
 | 
			
		||||
    for (unsigned int n = 0; n < args[1]->list.length; ++n) {
 | 
			
		||||
    for (unsigned int n = 0; n < args[1]->listSize(); ++n) {
 | 
			
		||||
        Value res;
 | 
			
		||||
        state.callFunction(*args[0], *args[1]->list.elems[n], res, noPos);
 | 
			
		||||
        state.callFunction(*args[0], *args[1]->listElems()[n], res, noPos);
 | 
			
		||||
        if (state.forceBool(res))
 | 
			
		||||
            vs[k++] = args[1]->list.elems[n];
 | 
			
		||||
            vs[k++] = args[1]->listElems()[n];
 | 
			
		||||
        else
 | 
			
		||||
            same = false;
 | 
			
		||||
    }
 | 
			
		||||
| 
						 | 
				
			
			@ -1275,7 +1275,7 @@ static void prim_filter(EvalState & state, const Pos & pos, Value * * args, Valu
 | 
			
		|||
        v = *args[1];
 | 
			
		||||
    else {
 | 
			
		||||
        state.mkList(v, k);
 | 
			
		||||
        for (unsigned int n = 0; n < k; ++n) v.list.elems[n] = vs[n];
 | 
			
		||||
        for (unsigned int n = 0; n < k; ++n) v.listElems()[n] = vs[n];
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -1285,8 +1285,8 @@ static void prim_elem(EvalState & state, const Pos & pos, Value * * args, Value
 | 
			
		|||
{
 | 
			
		||||
    bool res = false;
 | 
			
		||||
    state.forceList(*args[1], pos);
 | 
			
		||||
    for (unsigned int n = 0; n < args[1]->list.length; ++n)
 | 
			
		||||
        if (state.eqValues(*args[0], *args[1]->list.elems[n])) {
 | 
			
		||||
    for (unsigned int n = 0; n < args[1]->listSize(); ++n)
 | 
			
		||||
        if (state.eqValues(*args[0], *args[1]->listElems()[n])) {
 | 
			
		||||
            res = true;
 | 
			
		||||
            break;
 | 
			
		||||
        }
 | 
			
		||||
| 
						 | 
				
			
			@ -1298,7 +1298,7 @@ static void prim_elem(EvalState & state, const Pos & pos, Value * * args, Value
 | 
			
		|||
static void prim_concatLists(EvalState & state, const Pos & pos, Value * * args, Value & v)
 | 
			
		||||
{
 | 
			
		||||
    state.forceList(*args[0], pos);
 | 
			
		||||
    state.concatLists(v, args[0]->list.length, args[0]->list.elems, pos);
 | 
			
		||||
    state.concatLists(v, args[0]->listSize(), args[0]->listElems(), pos);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -1306,7 +1306,7 @@ static void prim_concatLists(EvalState & state, const Pos & pos, Value * * args,
 | 
			
		|||
static void prim_length(EvalState & state, const Pos & pos, Value * * args, Value & v)
 | 
			
		||||
{
 | 
			
		||||
    state.forceList(*args[0], pos);
 | 
			
		||||
    mkInt(v, args[0]->list.length);
 | 
			
		||||
    mkInt(v, args[0]->listSize());
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -1319,12 +1319,12 @@ static void prim_foldlStrict(EvalState & state, const Pos & pos, Value * * args,
 | 
			
		|||
 | 
			
		||||
    Value * vCur = args[1];
 | 
			
		||||
 | 
			
		||||
    if (args[2]->list.length)
 | 
			
		||||
        for (unsigned int n = 0; n < args[2]->list.length; ++n) {
 | 
			
		||||
    if (args[2]->listSize())
 | 
			
		||||
        for (unsigned int n = 0; n < args[2]->listSize(); ++n) {
 | 
			
		||||
            Value vTmp;
 | 
			
		||||
            state.callFunction(*args[0], *vCur, vTmp, pos);
 | 
			
		||||
            vCur = n == args[2]->list.length - 1 ? &v : state.allocValue();
 | 
			
		||||
            state.callFunction(vTmp, *args[2]->list.elems[n], *vCur, pos);
 | 
			
		||||
            vCur = n == args[2]->listSize() - 1 ? &v : state.allocValue();
 | 
			
		||||
            state.callFunction(vTmp, *args[2]->listElems()[n], *vCur, pos);
 | 
			
		||||
        }
 | 
			
		||||
    else
 | 
			
		||||
        v = *vCur;
 | 
			
		||||
| 
						 | 
				
			
			@ -1339,8 +1339,8 @@ static void anyOrAll(bool any, EvalState & state, const Pos & pos, Value * * arg
 | 
			
		|||
    state.forceList(*args[1], pos);
 | 
			
		||||
 | 
			
		||||
    Value vTmp;
 | 
			
		||||
    for (unsigned int n = 0; n < args[1]->list.length; ++n) {
 | 
			
		||||
        state.callFunction(*args[0], *args[1]->list.elems[n], vTmp, pos);
 | 
			
		||||
    for (unsigned int n = 0; n < args[1]->listSize(); ++n) {
 | 
			
		||||
        state.callFunction(*args[0], *args[1]->listElems()[n], vTmp, pos);
 | 
			
		||||
        bool res = state.forceBool(vTmp);
 | 
			
		||||
        if (res == any) {
 | 
			
		||||
            mkBool(v, any);
 | 
			
		||||
| 
						 | 
				
			
			@ -1507,9 +1507,9 @@ static void prim_match(EvalState & state, const Pos & pos, Value * * args, Value
 | 
			
		|||
    for (unsigned int n = 0; n < len; ++n) {
 | 
			
		||||
        auto i = subs.find(n);
 | 
			
		||||
        if (i == subs.end())
 | 
			
		||||
            mkNull(*(v.list.elems[n] = state.allocValue()));
 | 
			
		||||
            mkNull(*(v.listElems()[n] = state.allocValue()));
 | 
			
		||||
        else
 | 
			
		||||
            mkString(*(v.list.elems[n] = state.allocValue()), i->second);
 | 
			
		||||
            mkString(*(v.listElems()[n] = state.allocValue()), i->second);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -1743,7 +1743,7 @@ void EvalState::createBaseEnv()
 | 
			
		|||
    mkList(v, searchPath.size());
 | 
			
		||||
    int n = 0;
 | 
			
		||||
    for (auto & i : searchPath) {
 | 
			
		||||
        v2 = v.list.elems[n++] = allocValue();
 | 
			
		||||
        v2 = v.listElems()[n++] = allocValue();
 | 
			
		||||
        mkAttrs(*v2, 2);
 | 
			
		||||
        mkString(*allocAttr(*v2, symbols.create("path")), i.second);
 | 
			
		||||
        mkString(*allocAttr(*v2, symbols.create("prefix")), i.first);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -71,11 +71,11 @@ void printValueAsJSON(EvalState & state, bool strict,
 | 
			
		|||
            break;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        case tList: {
 | 
			
		||||
        case tList1: case tList2: case tListN: {
 | 
			
		||||
            JSONList json(str);
 | 
			
		||||
            for (unsigned int n = 0; n < v.list.length; ++n) {
 | 
			
		||||
            for (unsigned int n = 0; n < v.listSize(); ++n) {
 | 
			
		||||
                json.elem();
 | 
			
		||||
                printValueAsJSON(state, strict, *v.list.elems[n], str, context);
 | 
			
		||||
                printValueAsJSON(state, strict, *v.listElems()[n], str, context);
 | 
			
		||||
            }
 | 
			
		||||
            break;
 | 
			
		||||
        }
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -119,10 +119,10 @@ static void printValueAsXML(EvalState & state, bool strict, bool location,
 | 
			
		|||
 | 
			
		||||
            break;
 | 
			
		||||
 | 
			
		||||
        case tList: {
 | 
			
		||||
        case tList1: case tList2: case tListN: {
 | 
			
		||||
            XMLOpenElement _(doc, "list");
 | 
			
		||||
            for (unsigned int n = 0; n < v.list.length; ++n)
 | 
			
		||||
                printValueAsXML(state, strict, location, *v.list.elems[n], doc, context, drvsSeen);
 | 
			
		||||
            for (unsigned int n = 0; n < v.listSize(); ++n)
 | 
			
		||||
                printValueAsXML(state, strict, location, *v.listElems()[n], doc, context, drvsSeen);
 | 
			
		||||
            break;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -12,7 +12,9 @@ typedef enum {
 | 
			
		|||
    tPath,
 | 
			
		||||
    tNull,
 | 
			
		||||
    tAttrs,
 | 
			
		||||
    tList,
 | 
			
		||||
    tList1,
 | 
			
		||||
    tList2,
 | 
			
		||||
    tListN,
 | 
			
		||||
    tThunk,
 | 
			
		||||
    tApp,
 | 
			
		||||
    tLambda,
 | 
			
		||||
| 
						 | 
				
			
			@ -119,9 +121,10 @@ struct Value
 | 
			
		|||
        const char * path;
 | 
			
		||||
        Bindings * attrs;
 | 
			
		||||
        struct {
 | 
			
		||||
            unsigned int length;
 | 
			
		||||
            unsigned int size;
 | 
			
		||||
            Value * * elems;
 | 
			
		||||
        } list;
 | 
			
		||||
        } bigList;
 | 
			
		||||
        Value * smallList[2];
 | 
			
		||||
        struct {
 | 
			
		||||
            Env * env;
 | 
			
		||||
            Expr * expr;
 | 
			
		||||
| 
						 | 
				
			
			@ -139,6 +142,26 @@ struct Value
 | 
			
		|||
        } primOpApp;
 | 
			
		||||
        ExternalValueBase * external;
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    bool isList() const
 | 
			
		||||
    {
 | 
			
		||||
        return type == tList1 || type == tList2 || type == tListN;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    Value * * listElems()
 | 
			
		||||
    {
 | 
			
		||||
        return type == tList1 || type == tList2 ? smallList : bigList.elems;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    const Value * const * listElems() const
 | 
			
		||||
    {
 | 
			
		||||
        return type == tList1 || type == tList2 ? smallList : bigList.elems;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    unsigned int listSize() const
 | 
			
		||||
    {
 | 
			
		||||
        return type == tList1 ? 1 : type == tList2 ? 2 : bigList.size;
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue