mirror of
https://github.com/NixOS/nix.git
synced 2025-11-16 07:22:43 +01:00
Store short strings in Values
The vast majority of strings are < 16 bytes, and so can be stored directly in a Value. This saves a heap allocation and an indirection.
This commit is contained in:
parent
2160258cc4
commit
742a8046de
10 changed files with 107 additions and 78 deletions
|
|
@ -51,9 +51,10 @@ static void printValue(std::ostream & str, std::set<const Value *> & active, con
|
||||||
case tBool:
|
case tBool:
|
||||||
str << (v.boolean ? "true" : "false");
|
str << (v.boolean ? "true" : "false");
|
||||||
break;
|
break;
|
||||||
case tString:
|
case tShortString:
|
||||||
|
case tLongString:
|
||||||
str << "\"";
|
str << "\"";
|
||||||
for (const char * i = v.string.s; *i; i++)
|
for (const char * i = v.getString(); *i; i++)
|
||||||
if (*i == '\"' || *i == '\\') str << "\\" << *i;
|
if (*i == '\"' || *i == '\\') str << "\\" << *i;
|
||||||
else if (*i == '\n') str << "\\n";
|
else if (*i == '\n') str << "\\n";
|
||||||
else if (*i == '\r') str << "\\r";
|
else if (*i == '\r') str << "\\r";
|
||||||
|
|
@ -140,7 +141,8 @@ string showType(const Value & v)
|
||||||
switch (v.type) {
|
switch (v.type) {
|
||||||
case tInt: return "an integer";
|
case tInt: return "an integer";
|
||||||
case tBool: return "a boolean";
|
case tBool: return "a boolean";
|
||||||
case tString: return v.string.context ? "a string with context" : "a string";
|
case tShortString: return "a string";
|
||||||
|
case tLongString: return v.string.context ? "a string with context" : "a string";
|
||||||
case tPath: return "a path";
|
case tPath: return "a path";
|
||||||
case tNull: return "null";
|
case tNull: return "null";
|
||||||
case tAttrs: return "a set";
|
case tAttrs: return "a set";
|
||||||
|
|
@ -170,8 +172,7 @@ static Symbol getName(const AttrName & name, EvalState & state, Env & env)
|
||||||
} else {
|
} else {
|
||||||
Root<Value> nameValue;
|
Root<Value> nameValue;
|
||||||
name.expr->eval(state, env, nameValue);
|
name.expr->eval(state, env, nameValue);
|
||||||
state.forceStringNoCtx(nameValue);
|
return state.symbols.create(state.forceStringNoCtx(nameValue));
|
||||||
return state.symbols.create(nameValue->string.s);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -495,14 +496,23 @@ LocalNoInline(void addErrorPrefix(Error & e, const char * s, const string & s2,
|
||||||
|
|
||||||
void mkString(Value & v, const char * s)
|
void mkString(Value & v, const char * s)
|
||||||
{
|
{
|
||||||
mkStringNoCopy(v, dupString(s));
|
auto len = strlen(s); // FIXME: only need to know if > short
|
||||||
|
if (len < WORD_SIZE * 2) {
|
||||||
|
strcpy((char *) &v.string, s);
|
||||||
|
v.type = tShortString;
|
||||||
|
} else
|
||||||
|
mkStringNoCopy(v, dupString(s));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Value & mkString(Value & v, const string & s, const PathSet & context)
|
Value & mkString(Value & v, const string & s, const PathSet & context)
|
||||||
{
|
{
|
||||||
mkString(v, s.c_str());
|
if (context.empty())
|
||||||
v.setContext(context);
|
mkString(v, s.c_str());
|
||||||
|
else {
|
||||||
|
mkStringNoCopy(v, dupString(s.c_str()));
|
||||||
|
v.setContext(context);
|
||||||
|
}
|
||||||
return v;
|
return v;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -840,8 +850,7 @@ void ExprAttrs::eval(EvalState & state, Env & env, Value & v)
|
||||||
state.forceValue(nameVal, i.pos);
|
state.forceValue(nameVal, i.pos);
|
||||||
if (nameVal->type == tNull)
|
if (nameVal->type == tNull)
|
||||||
continue;
|
continue;
|
||||||
state.forceStringNoCtx(nameVal);
|
Symbol nameSym = state.symbols.create(state.forceStringNoCtx(nameVal));
|
||||||
Symbol nameSym = state.symbols.create(nameVal->string.s);
|
|
||||||
Bindings::iterator j = v.attrs->find(nameSym);
|
Bindings::iterator j = v.attrs->find(nameSym);
|
||||||
if (j != v.attrs->end())
|
if (j != v.attrs->end())
|
||||||
throwEvalError("dynamic attribute '%1%' at %2% already defined at %3%", nameSym, i.pos, *j->pos);
|
throwEvalError("dynamic attribute '%1%' at %2% already defined at %3%", nameSym, i.pos, *j->pos);
|
||||||
|
|
@ -1313,7 +1322,7 @@ void ExprConcatStrings::eval(EvalState & state, Env & env, Value & v)
|
||||||
NixFloat nf = 0;
|
NixFloat nf = 0;
|
||||||
|
|
||||||
bool first = !forceString;
|
bool first = !forceString;
|
||||||
Tag firstType = tString;
|
Tag firstType = tLongString;
|
||||||
|
|
||||||
auto vTmp = state.allocValue();
|
auto vTmp = state.allocValue();
|
||||||
|
|
||||||
|
|
@ -1325,7 +1334,7 @@ void ExprConcatStrings::eval(EvalState & state, Env & env, Value & v)
|
||||||
since paths are copied when they are used in a derivation),
|
since paths are copied when they are used in a derivation),
|
||||||
and none of the strings are allowed to have contexts. */
|
and none of the strings are allowed to have contexts. */
|
||||||
if (first) {
|
if (first) {
|
||||||
firstType = vTmp->type;
|
firstType = vTmp->isString() ? tLongString : vTmp->type;
|
||||||
first = false;
|
first = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1347,7 +1356,7 @@ void ExprConcatStrings::eval(EvalState & state, Env & env, Value & v)
|
||||||
} else
|
} else
|
||||||
throwEvalError("cannot add %1% to a float, at %2%", showType(vTmp), pos);
|
throwEvalError("cannot add %1% to a float, at %2%", showType(vTmp), pos);
|
||||||
} else
|
} else
|
||||||
s << state.coerceToString(pos, vTmp, context, false, firstType == tString);
|
s << state.coerceToString(pos, vTmp, context, false, firstType == tLongString);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (firstType == tInt)
|
if (firstType == tInt)
|
||||||
|
|
@ -1448,13 +1457,13 @@ void EvalState::forceFunction(Value & v, const Pos & pos)
|
||||||
string EvalState::forceString(Value & v, const Pos & pos)
|
string EvalState::forceString(Value & v, const Pos & pos)
|
||||||
{
|
{
|
||||||
forceValue(v, pos);
|
forceValue(v, pos);
|
||||||
if (v.type != tString) {
|
if (!v.isString()) {
|
||||||
if (pos)
|
if (pos)
|
||||||
throwTypeError("value is %1% while a string was expected, at %2%", v, pos);
|
throwTypeError("value is %1% while a string was expected, at %2%", v, pos);
|
||||||
else
|
else
|
||||||
throwTypeError("value is %1% while a string was expected", v);
|
throwTypeError("value is %1% while a string was expected", v);
|
||||||
}
|
}
|
||||||
return string(v.string.s);
|
return string(v.getString()); // FIXME: don't copy
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -1469,15 +1478,15 @@ string EvalState::forceString(Value & v, PathSet & context, const Pos & pos)
|
||||||
string EvalState::forceStringNoCtx(Value & v, const Pos & pos)
|
string EvalState::forceStringNoCtx(Value & v, const Pos & pos)
|
||||||
{
|
{
|
||||||
string s = forceString(v, pos);
|
string s = forceString(v, pos);
|
||||||
if (v.string.context) {
|
if (v.type == tLongString && v.string.context) {
|
||||||
PathSet context;
|
PathSet context;
|
||||||
v.getContext(context);
|
v.getContext(context);
|
||||||
if (pos)
|
if (pos)
|
||||||
throwEvalError("the string '%1%' is not allowed to refer to a store path (such as '%2%'), at %3%",
|
throwEvalError("the string '%1%' is not allowed to refer to a store path (such as '%2%'), at %3%",
|
||||||
v.string.s, *context.begin(), pos);
|
v.string._s, *context.begin(), pos);
|
||||||
else
|
else
|
||||||
throwEvalError("the string '%1%' is not allowed to refer to a store path (such as '%2%')",
|
throwEvalError("the string '%1%' is not allowed to refer to a store path (such as '%2%')",
|
||||||
v.string.s, *context.begin());
|
v.string._s, *context.begin());
|
||||||
}
|
}
|
||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
|
|
@ -1489,8 +1498,8 @@ bool EvalState::isDerivation(Value & v)
|
||||||
Bindings::iterator i = v.attrs->find(sType);
|
Bindings::iterator i = v.attrs->find(sType);
|
||||||
if (i == v.attrs->end()) return false;
|
if (i == v.attrs->end()) return false;
|
||||||
forceValue(*i->value);
|
forceValue(*i->value);
|
||||||
if (i->value->type != tString) return false;
|
if (!i->value->isString()) return false;
|
||||||
return strcmp(i->value->string.s, "derivation") == 0;
|
return strcmp(i->value->getString(), "derivation") == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -1501,9 +1510,9 @@ string EvalState::coerceToString(const Pos & pos, Value & v, PathSet & context,
|
||||||
|
|
||||||
string s;
|
string s;
|
||||||
|
|
||||||
if (v.type == tString) {
|
if (v.isString()) {
|
||||||
v.getContext(context);
|
v.getContext(context);
|
||||||
return v.string.s;
|
return v.getString();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (v.type == tPath) {
|
if (v.type == tPath) {
|
||||||
|
|
@ -1603,6 +1612,9 @@ bool EvalState::eqValues(Value & v1, Value & v2)
|
||||||
if (v1.type == tFloat && v2.type == tInt)
|
if (v1.type == tFloat && v2.type == tInt)
|
||||||
return v1.fpoint == v2.integer;
|
return v1.fpoint == v2.integer;
|
||||||
|
|
||||||
|
if (v1.isString())
|
||||||
|
return v2.isString() && strcmp(v1.getString(), v2.getString()) == 0;
|
||||||
|
|
||||||
// All other types are not compatible with each other.
|
// All other types are not compatible with each other.
|
||||||
if (v1.type != v2.type) return false;
|
if (v1.type != v2.type) return false;
|
||||||
|
|
||||||
|
|
@ -1614,9 +1626,6 @@ bool EvalState::eqValues(Value & v1, Value & v2)
|
||||||
case tBool:
|
case tBool:
|
||||||
return v1.boolean == v2.boolean;
|
return v1.boolean == v2.boolean;
|
||||||
|
|
||||||
case tString:
|
|
||||||
return strcmp(v1.string.s, v2.string.s) == 0;
|
|
||||||
|
|
||||||
case tPath:
|
case tPath:
|
||||||
return strcmp(v1.path, v2.path) == 0;
|
return strcmp(v1.path, v2.path) == 0;
|
||||||
|
|
||||||
|
|
@ -1799,8 +1808,8 @@ size_t valueSize(Value & v)
|
||||||
size_t sz = sizeof(Value);
|
size_t sz = sizeof(Value);
|
||||||
|
|
||||||
switch (v.type) {
|
switch (v.type) {
|
||||||
case tString:
|
case tLongString:
|
||||||
sz += doString(v.string.s);
|
sz += doString(v.string._s);
|
||||||
break;
|
break;
|
||||||
case tPath:
|
case tPath:
|
||||||
sz += doString(v.path);
|
sz += doString(v.path);
|
||||||
|
|
|
||||||
|
|
@ -106,9 +106,10 @@ void GC::gc()
|
||||||
case tNull:
|
case tNull:
|
||||||
case tList0:
|
case tList0:
|
||||||
case tFloat:
|
case tFloat:
|
||||||
|
case tShortString:
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case tString: {
|
case tLongString: {
|
||||||
auto obj2 = (Value *) obj;
|
auto obj2 = (Value *) obj;
|
||||||
// FIXME: GC string
|
// FIXME: GC string
|
||||||
// See setContext().
|
// See setContext().
|
||||||
|
|
|
||||||
|
|
@ -25,7 +25,8 @@ enum Tag {
|
||||||
// Value tags
|
// Value tags
|
||||||
tInt,
|
tInt,
|
||||||
tBool,
|
tBool,
|
||||||
tString,
|
tShortString,
|
||||||
|
tLongString,
|
||||||
tPath,
|
tPath,
|
||||||
tNull,
|
tNull,
|
||||||
tAttrs,
|
tAttrs,
|
||||||
|
|
|
||||||
|
|
@ -122,8 +122,8 @@ DrvInfo::Outputs DrvInfo::queryOutputs(bool onlyOutputsToInstall)
|
||||||
if (!outTI->isList()) throw errMsg;
|
if (!outTI->isList()) throw errMsg;
|
||||||
Outputs result;
|
Outputs result;
|
||||||
for (auto i = outTI->listElems(); i != outTI->listElems() + outTI->listSize(); ++i) {
|
for (auto i = outTI->listElems(); i != outTI->listElems() + outTI->listSize(); ++i) {
|
||||||
if ((*i)->type != tString) throw errMsg;
|
if (!(*i)->isString()) throw errMsg;
|
||||||
auto out = outputs.find((*i)->string.s);
|
auto out = outputs.find((*i)->getString());
|
||||||
if (out == outputs.end()) throw errMsg;
|
if (out == outputs.end()) throw errMsg;
|
||||||
result.insert(*out);
|
result.insert(*out);
|
||||||
}
|
}
|
||||||
|
|
@ -178,8 +178,7 @@ bool DrvInfo::checkMeta(Value & v)
|
||||||
if (!checkMeta(*i.value)) return false;
|
if (!checkMeta(*i.value)) return false;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
else return v.type == tInt || v.type == tBool || v.type == tString ||
|
else return v.type == tInt || v.type == tBool || v.isString() || v.type == tFloat;
|
||||||
v.type == tFloat;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -195,8 +194,8 @@ Value * DrvInfo::queryMeta(const string & name)
|
||||||
string DrvInfo::queryMetaString(const string & name)
|
string DrvInfo::queryMetaString(const string & name)
|
||||||
{
|
{
|
||||||
auto v = queryMeta(name);
|
auto v = queryMeta(name);
|
||||||
if (!v || v->type != tString) return "";
|
if (!v || !v->isString()) return "";
|
||||||
return v->string.s;
|
return v->getString();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -205,11 +204,11 @@ NixInt DrvInfo::queryMetaInt(const string & name, NixInt def)
|
||||||
auto v = queryMeta(name);
|
auto v = queryMeta(name);
|
||||||
if (!v) return def;
|
if (!v) return def;
|
||||||
if (v->type == tInt) return v->integer;
|
if (v->type == tInt) return v->integer;
|
||||||
if (v->type == tString) {
|
if (v->isString()) {
|
||||||
/* Backwards compatibility with before we had support for
|
/* Backwards compatibility with before we had support for
|
||||||
integer meta fields. */
|
integer meta fields. */
|
||||||
NixInt n;
|
NixInt n;
|
||||||
if (string2Int(v->string.s, n)) return n;
|
if (string2Int(v->getString(), n)) return n;
|
||||||
}
|
}
|
||||||
return def;
|
return def;
|
||||||
}
|
}
|
||||||
|
|
@ -219,11 +218,11 @@ NixFloat DrvInfo::queryMetaFloat(const string & name, NixFloat def)
|
||||||
auto v = queryMeta(name);
|
auto v = queryMeta(name);
|
||||||
if (!v) return def;
|
if (!v) return def;
|
||||||
if (v->type == tFloat) return v->fpoint;
|
if (v->type == tFloat) return v->fpoint;
|
||||||
if (v->type == tString) {
|
if (v->isString()) {
|
||||||
/* Backwards compatibility with before we had support for
|
/* Backwards compatibility with before we had support for
|
||||||
float meta fields. */
|
float meta fields. */
|
||||||
NixFloat n;
|
NixFloat n;
|
||||||
if (string2Float(v->string.s, n)) return n;
|
if (string2Float(v->getString(), n)) return n;
|
||||||
}
|
}
|
||||||
return def;
|
return def;
|
||||||
}
|
}
|
||||||
|
|
@ -234,11 +233,12 @@ bool DrvInfo::queryMetaBool(const string & name, bool def)
|
||||||
auto v = queryMeta(name);
|
auto v = queryMeta(name);
|
||||||
if (!v) return def;
|
if (!v) return def;
|
||||||
if (v->type == tBool) return v->boolean;
|
if (v->type == tBool) return v->boolean;
|
||||||
if (v->type == tString) {
|
if (v->isString()) {
|
||||||
/* Backwards compatibility with before we had support for
|
/* Backwards compatibility with before we had support for
|
||||||
Boolean meta fields. */
|
Boolean meta fields. */
|
||||||
if (strcmp(v->string.s, "true") == 0) return true;
|
auto s = v->getString();
|
||||||
if (strcmp(v->string.s, "false") == 0) return false;
|
if (strcmp(s, "true") == 0) return true;
|
||||||
|
if (strcmp(s, "false") == 0) return false;
|
||||||
}
|
}
|
||||||
return def;
|
return def;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -238,7 +238,9 @@ static void prim_typeOf(EvalState & state, const Pos & pos, Value * * args, Valu
|
||||||
switch (args[0]->type) {
|
switch (args[0]->type) {
|
||||||
case tInt: t = "int"; break;
|
case tInt: t = "int"; break;
|
||||||
case tBool: t = "bool"; break;
|
case tBool: t = "bool"; break;
|
||||||
case tString: t = "string"; break;
|
case tShortString:
|
||||||
|
case tLongString:
|
||||||
|
t = "string"; break;
|
||||||
case tPath: t = "path"; break;
|
case tPath: t = "path"; break;
|
||||||
case tNull: t = "null"; break;
|
case tNull: t = "null"; break;
|
||||||
case tAttrs: t = "set"; break;
|
case tAttrs: t = "set"; break;
|
||||||
|
|
@ -305,7 +307,7 @@ static void prim_isFloat(EvalState & state, const Pos & pos, Value * * args, Val
|
||||||
static void prim_isString(EvalState & state, const Pos & pos, Value * * args, Value & v)
|
static void prim_isString(EvalState & state, const Pos & pos, Value * * args, Value & v)
|
||||||
{
|
{
|
||||||
state.forceValue(*args[0]);
|
state.forceValue(*args[0]);
|
||||||
mkBool(v, args[0]->type == tString);
|
mkBool(v, args[0]->isString());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -331,6 +333,8 @@ struct CompareValues
|
||||||
return v1->fpoint < v2->integer;
|
return v1->fpoint < v2->integer;
|
||||||
if (v1->type == tInt && v2->type == tFloat)
|
if (v1->type == tInt && v2->type == tFloat)
|
||||||
return v1->integer < v2->fpoint;
|
return v1->integer < v2->fpoint;
|
||||||
|
if (v1->isString() && v2->isString())
|
||||||
|
return strcmp(v1->getString(), v2->getString()) < 0;
|
||||||
if (v1->type != v2->type)
|
if (v1->type != v2->type)
|
||||||
throw EvalError(format("cannot compare %1% with %2%") % showType(*v1) % showType(*v2));
|
throw EvalError(format("cannot compare %1% with %2%") % showType(*v1) % showType(*v2));
|
||||||
switch (v1->type) {
|
switch (v1->type) {
|
||||||
|
|
@ -338,8 +342,6 @@ struct CompareValues
|
||||||
return v1->integer < v2->integer;
|
return v1->integer < v2->integer;
|
||||||
case tFloat:
|
case tFloat:
|
||||||
return v1->fpoint < v2->fpoint;
|
return v1->fpoint < v2->fpoint;
|
||||||
case tString:
|
|
||||||
return strcmp(v1->string.s, v2->string.s) < 0;
|
|
||||||
case tPath:
|
case tPath:
|
||||||
return strcmp(v1->path, v2->path) < 0;
|
return strcmp(v1->path, v2->path) < 0;
|
||||||
default:
|
default:
|
||||||
|
|
@ -495,10 +497,10 @@ static void prim_deepSeq(EvalState & state, const Pos & pos, Value * * args, Val
|
||||||
static void prim_trace(EvalState & state, const Pos & pos, Value * * args, Value & v)
|
static void prim_trace(EvalState & state, const Pos & pos, Value * * args, Value & v)
|
||||||
{
|
{
|
||||||
state.forceValue(*args[0]);
|
state.forceValue(*args[0]);
|
||||||
if (args[0]->type == tString)
|
if (args[0]->isString())
|
||||||
printError(format("trace: %1%") % args[0]->string.s);
|
printError("trace: %s", args[0]->getString());
|
||||||
else
|
else
|
||||||
printError(format("trace: %1%") % *args[0]);
|
printError("trace: %s", *args[0]);
|
||||||
state.forceValue(*args[1]);
|
state.forceValue(*args[1]);
|
||||||
v = *args[1];
|
v = *args[1];
|
||||||
}
|
}
|
||||||
|
|
@ -1134,7 +1136,7 @@ static void prim_attrNames(EvalState & state, const Pos & pos, Value * * args, V
|
||||||
mkString(*(v.listElems()[n++] = state.allocValue()), i.name);
|
mkString(*(v.listElems()[n++] = state.allocValue()), i.name);
|
||||||
|
|
||||||
std::sort(v.listElems(), v.listElems() + n,
|
std::sort(v.listElems(), v.listElems() + n,
|
||||||
[](Value * v1, Value * v2) { return strcmp(v1->string.s, v2->string.s) < 0; });
|
[](Value * v1, Value * v2) { return strcmp(v1->getString(), v2->getString()) < 0; });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -1211,10 +1213,9 @@ static void prim_removeAttrs(EvalState & state, const Pos & pos, Value * * args,
|
||||||
|
|
||||||
/* Get the attribute names to be removed. */
|
/* Get the attribute names to be removed. */
|
||||||
std::set<Symbol> names;
|
std::set<Symbol> names;
|
||||||
for (unsigned int i = 0; i < args[1]->listSize(); ++i) {
|
for (unsigned int i = 0; i < args[1]->listSize(); ++i)
|
||||||
state.forceStringNoCtx(*args[1]->listElems()[i], pos);
|
names.insert(state.symbols.create(
|
||||||
names.insert(state.symbols.create(args[1]->listElems()[i]->string.s));
|
state.forceStringNoCtx(*args[1]->listElems()[i], pos)));
|
||||||
}
|
|
||||||
|
|
||||||
/* Copy all attributes not in that set. Note that we don't need
|
/* Copy all attributes not in that set. Note that we don't need
|
||||||
to sort v.attrs because it's a subset of an already sorted
|
to sort v.attrs because it's a subset of an already sorted
|
||||||
|
|
|
||||||
|
|
@ -26,9 +26,10 @@ void printValueAsJSON(EvalState & state, bool strict,
|
||||||
out.write(v.boolean);
|
out.write(v.boolean);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case tString:
|
case tShortString:
|
||||||
|
case tLongString:
|
||||||
v.getContext(context);
|
v.getContext(context);
|
||||||
out.write(v.string.s);
|
out.write(v.getString());
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case tPath:
|
case tPath:
|
||||||
|
|
|
||||||
|
|
@ -68,10 +68,11 @@ static void printValueAsXML(EvalState & state, bool strict, bool location,
|
||||||
doc.writeEmptyElement("bool", singletonAttrs("value", v.boolean ? "true" : "false"));
|
doc.writeEmptyElement("bool", singletonAttrs("value", v.boolean ? "true" : "false"));
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case tString:
|
case tShortString:
|
||||||
|
case tLongString:
|
||||||
/* !!! show the context? */
|
/* !!! show the context? */
|
||||||
v.getContext(context);
|
v.getContext(context);
|
||||||
doc.writeEmptyElement("string", singletonAttrs("value", v.string.s));
|
doc.writeEmptyElement("string", singletonAttrs("value", v.getString()));
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case tPath:
|
case tPath:
|
||||||
|
|
@ -92,15 +93,15 @@ static void printValueAsXML(EvalState & state, bool strict, bool location,
|
||||||
a = v.attrs->find(state.sDrvPath);
|
a = v.attrs->find(state.sDrvPath);
|
||||||
if (a != v.attrs->end()) {
|
if (a != v.attrs->end()) {
|
||||||
if (strict) state.forceValue(*a->value);
|
if (strict) state.forceValue(*a->value);
|
||||||
if (a->value->type == tString)
|
if (a->value->isString())
|
||||||
xmlAttrs["drvPath"] = drvPath = a->value->string.s;
|
xmlAttrs["drvPath"] = drvPath = a->value->getString();
|
||||||
}
|
}
|
||||||
|
|
||||||
a = v.attrs->find(state.sOutPath);
|
a = v.attrs->find(state.sOutPath);
|
||||||
if (a != v.attrs->end()) {
|
if (a != v.attrs->end()) {
|
||||||
if (strict) state.forceValue(*a->value);
|
if (strict) state.forceValue(*a->value);
|
||||||
if (a->value->type == tString)
|
if (a->value->isString())
|
||||||
xmlAttrs["outPath"] = a->value->string.s;
|
xmlAttrs["outPath"] = a->value->getString();
|
||||||
}
|
}
|
||||||
|
|
||||||
XMLOpenElement _(doc, "derivation", xmlAttrs);
|
XMLOpenElement _(doc, "derivation", xmlAttrs);
|
||||||
|
|
|
||||||
|
|
@ -114,7 +114,7 @@ struct Value : Object
|
||||||
derivation, and the other store paths in C will be added to
|
derivation, and the other store paths in C will be added to
|
||||||
the inputSrcs of the derivations. */
|
the inputSrcs of the derivations. */
|
||||||
struct {
|
struct {
|
||||||
const char * s;
|
const char * _s;
|
||||||
Context * context;
|
Context * context;
|
||||||
} string;
|
} string;
|
||||||
|
|
||||||
|
|
@ -186,7 +186,7 @@ public:
|
||||||
|
|
||||||
void getContext(PathSet & context)
|
void getContext(PathSet & context)
|
||||||
{
|
{
|
||||||
if (string.context) {
|
if (type == tLongString && string.context) {
|
||||||
if (((ptrdiff_t) string.context) & 1) {
|
if (((ptrdiff_t) string.context) & 1) {
|
||||||
auto s = (const std::string *) (((ptrdiff_t) string.context) & ~1UL);
|
auto s = (const std::string *) (((ptrdiff_t) string.context) & ~1UL);
|
||||||
context.insert(*s);
|
context.insert(*s);
|
||||||
|
|
@ -197,6 +197,19 @@ public:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool isString() const
|
||||||
|
{
|
||||||
|
return type == tShortString || type == tLongString;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char * getString() const
|
||||||
|
{
|
||||||
|
if (type == tShortString)
|
||||||
|
return (const char *) &string;
|
||||||
|
else
|
||||||
|
return string._s;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -245,21 +258,22 @@ static inline void mkPrimOpApp(Value & v, Value & left, Value & right)
|
||||||
|
|
||||||
static inline void mkStringNoCopy(Value & v, const char * s)
|
static inline void mkStringNoCopy(Value & v, const char * s)
|
||||||
{
|
{
|
||||||
v.type = tString;
|
// FIXME: copy short strings?
|
||||||
v.string.s = s;
|
v.type = tLongString;
|
||||||
|
v.string._s = s;
|
||||||
v.string.context = 0;
|
v.string.context = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void mkString(Value & v, const char * s);
|
||||||
|
|
||||||
|
|
||||||
static inline void mkString(Value & v, const Symbol & s)
|
static inline void mkString(Value & v, const Symbol & s)
|
||||||
{
|
{
|
||||||
mkStringNoCopy(v, ((const string &) s).c_str());
|
mkString(v, ((const string &) s).c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void mkString(Value & v, const char * s);
|
|
||||||
|
|
||||||
|
|
||||||
static inline void mkPathNoCopy(Value & v, const char * s)
|
static inline void mkPathNoCopy(Value & v, const char * s)
|
||||||
{
|
{
|
||||||
v.type = tPath;
|
v.type = tPath;
|
||||||
|
|
|
||||||
|
|
@ -1116,9 +1116,9 @@ static void opQuery(Globals & globals, Strings opFlags, Strings opArgs)
|
||||||
if (!v)
|
if (!v)
|
||||||
printError("derivation '%s' has invalid meta attribute '%s'", i.queryName(), j);
|
printError("derivation '%s' has invalid meta attribute '%s'", i.queryName(), j);
|
||||||
else {
|
else {
|
||||||
if (v->type == tString) {
|
if (v->isString()) {
|
||||||
attrs2["type"] = "string";
|
attrs2["type"] = "string";
|
||||||
attrs2["value"] = v->string.s;
|
attrs2["value"] = v->getString();
|
||||||
xml.writeEmptyElement("meta", attrs2);
|
xml.writeEmptyElement("meta", attrs2);
|
||||||
} else if (v->type == tInt) {
|
} else if (v->type == tInt) {
|
||||||
attrs2["type"] = "int";
|
attrs2["type"] = "int";
|
||||||
|
|
@ -1136,9 +1136,9 @@ static void opQuery(Globals & globals, Strings opFlags, Strings opArgs)
|
||||||
attrs2["type"] = "strings";
|
attrs2["type"] = "strings";
|
||||||
XMLOpenElement m(xml, "meta", attrs2);
|
XMLOpenElement m(xml, "meta", attrs2);
|
||||||
for (unsigned int j = 0; j < v->listSize(); ++j) {
|
for (unsigned int j = 0; j < v->listSize(); ++j) {
|
||||||
if (v->listElems()[j]->type != tString) continue;
|
if (!v->listElems()[j]->isString()) continue;
|
||||||
XMLAttrs attrs3;
|
XMLAttrs attrs3;
|
||||||
attrs3["value"] = v->listElems()[j]->string.s;
|
attrs3["value"] = v->listElems()[j]->getString();
|
||||||
xml.writeEmptyElement("string", attrs3);
|
xml.writeEmptyElement("string", attrs3);
|
||||||
}
|
}
|
||||||
} else if (v->type == tAttrs) {
|
} else if (v->type == tAttrs) {
|
||||||
|
|
@ -1147,10 +1147,10 @@ static void opQuery(Globals & globals, Strings opFlags, Strings opArgs)
|
||||||
Bindings & attrs = *v->attrs;
|
Bindings & attrs = *v->attrs;
|
||||||
for (auto &i : attrs) {
|
for (auto &i : attrs) {
|
||||||
Attr & a(*attrs.find(i.name));
|
Attr & a(*attrs.find(i.name));
|
||||||
if(a.value->type != tString) continue;
|
if (!a.value->isString()) continue;
|
||||||
XMLAttrs attrs3;
|
XMLAttrs attrs3;
|
||||||
attrs3["type"] = i.name;
|
attrs3["type"] = i.name;
|
||||||
attrs3["value"] = a.value->string.s;
|
attrs3["value"] = a.value->getString();
|
||||||
xml.writeEmptyElement("string", attrs3);
|
xml.writeEmptyElement("string", attrs3);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -606,9 +606,10 @@ std::ostream & NixRepl::printValue(std::ostream & str, Value & v, unsigned int m
|
||||||
str << ESC_CYA << (v.boolean ? "true" : "false") << ESC_END;
|
str << ESC_CYA << (v.boolean ? "true" : "false") << ESC_END;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case tString:
|
case tShortString:
|
||||||
|
case tLongString:
|
||||||
str << ESC_YEL;
|
str << ESC_YEL;
|
||||||
printStringValue(str, v.string.s);
|
printStringValue(str, v.getString());
|
||||||
str << ESC_END;
|
str << ESC_END;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue