Compare commits
4 commits
master
...
reduce-cac
Author | SHA1 | Date | |
---|---|---|---|
6468f63994 | |||
9416202465 | |||
4941ba3413 | |||
7244b9b861 |
|
@ -3,7 +3,7 @@ pkglib_LTLIBRARIES = libexpr.la
|
||||||
libexpr_la_SOURCES = \
|
libexpr_la_SOURCES = \
|
||||||
nixexpr.cc eval.cc primops.cc lexer-tab.cc parser-tab.cc \
|
nixexpr.cc eval.cc primops.cc lexer-tab.cc parser-tab.cc \
|
||||||
get-drvs.cc attr-path.cc expr-to-xml.cc common-opts.cc \
|
get-drvs.cc attr-path.cc expr-to-xml.cc common-opts.cc \
|
||||||
names.cc
|
names.cc normal-forms.cc
|
||||||
|
|
||||||
pkginclude_HEADERS = \
|
pkginclude_HEADERS = \
|
||||||
nixexpr.hh eval.hh parser.hh lexer-tab.hh parser-tab.hh \
|
nixexpr.hh eval.hh parser.hh lexer-tab.hh parser-tab.hh \
|
||||||
|
|
|
@ -16,15 +16,23 @@ namespace nix {
|
||||||
|
|
||||||
|
|
||||||
EvalState::EvalState()
|
EvalState::EvalState()
|
||||||
: normalForms(32768), primOps(128)
|
: sessionNormalForms(32768), normalForms(32768), primOps(128)
|
||||||
{
|
{
|
||||||
nrEvaluated = nrCached = 0;
|
nrEvaluated = nrCached = nrDepthAfterReset = 0;
|
||||||
|
|
||||||
initNixExprHelpers();
|
initNixExprHelpers();
|
||||||
|
|
||||||
addPrimOps();
|
addPrimOps();
|
||||||
|
|
||||||
allowUnsafeEquality = getEnv("NIX_NO_UNSAFE_EQ", "") == "";
|
allowUnsafeEquality = getEnv("NIX_NO_UNSAFE_EQ", "") == "";
|
||||||
|
safeCache = true;
|
||||||
|
|
||||||
|
loadNormalForms();
|
||||||
|
}
|
||||||
|
|
||||||
|
EvalState::~EvalState()
|
||||||
|
{
|
||||||
|
saveNormalForms();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -468,8 +476,10 @@ LocalNoInline(Expr evalVar(EvalState & state, ATerm name))
|
||||||
if (arity == 0)
|
if (arity == 0)
|
||||||
/* !!! backtrace for primop call */
|
/* !!! backtrace for primop call */
|
||||||
return ((PrimOp) ATgetBlobData(fun)) (state, ATermVector());
|
return ((PrimOp) ATgetBlobData(fun)) (state, ATermVector());
|
||||||
else
|
else {
|
||||||
|
state.safeCache = false;
|
||||||
return makePrimOp(arity, fun, ATempty);
|
return makePrimOp(arity, fun, ATempty);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -495,6 +505,7 @@ LocalNoInline(Expr evalCall(EvalState & state, Expr fun, Expr arg))
|
||||||
for (ATermIterator i(args); i; ++i)
|
for (ATermIterator i(args); i; ++i)
|
||||||
args2[--arity] = *i;
|
args2[--arity] = *i;
|
||||||
/* !!! backtrace for primop call */
|
/* !!! backtrace for primop call */
|
||||||
|
state.safeCache = true;
|
||||||
return ((PrimOp) ATgetBlobData(funBlob))
|
return ((PrimOp) ATgetBlobData(funBlob))
|
||||||
(state, args2);
|
(state, args2);
|
||||||
} else
|
} else
|
||||||
|
@ -802,11 +813,19 @@ Expr evalExpr(EvalState & state, Expr e)
|
||||||
format("evaluating expression: %1%") % e);
|
format("evaluating expression: %1%") % e);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
state.nrEvaluated++;
|
const unsigned int hugeEvalExpr = 100;
|
||||||
|
unsigned int nrEvaluated = state.nrEvaluated++;
|
||||||
|
state.nrDepthAfterReset++;
|
||||||
|
|
||||||
/* Consult the memo table to quickly get the normal form of
|
/* Consult the memo table to quickly get the normal form of
|
||||||
previously evaluated expressions. */
|
previously evaluated expressions. */
|
||||||
Expr nf = state.normalForms.get(e);
|
Expr nf = state.normalForms.get(e);
|
||||||
|
if (nf) {
|
||||||
|
state.nrCached++;
|
||||||
|
return nf;
|
||||||
|
}
|
||||||
|
|
||||||
|
nf = state.sessionNormalForms.get(e);
|
||||||
if (nf) {
|
if (nf) {
|
||||||
if (nf == makeBlackHole())
|
if (nf == makeBlackHole())
|
||||||
throwEvalError("infinite recursion encountered");
|
throwEvalError("infinite recursion encountered");
|
||||||
|
@ -815,14 +834,25 @@ Expr evalExpr(EvalState & state, Expr e)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Otherwise, evaluate and memoize. */
|
/* Otherwise, evaluate and memoize. */
|
||||||
state.normalForms.set(e, makeBlackHole());
|
state.sessionNormalForms.set(e, makeBlackHole());
|
||||||
try {
|
try {
|
||||||
nf = evalExpr2(state, e);
|
nf = evalExpr2(state, e);
|
||||||
} catch (Error & err) {
|
} catch (Error & err) {
|
||||||
state.normalForms.remove(e);
|
state.sessionNormalForms.remove(e);
|
||||||
throw;
|
throw;
|
||||||
}
|
}
|
||||||
state.normalForms.set(e, nf);
|
|
||||||
|
// session independent condition
|
||||||
|
if (state.nrDepthAfterReset && state.safeCache &&
|
||||||
|
// heuristic condition
|
||||||
|
state.nrEvaluated - nrEvaluated > hugeEvalExpr) {
|
||||||
|
state.sessionNormalForms.remove(e);
|
||||||
|
state.normalForms.set(e, nf);
|
||||||
|
state.nrDepthAfterReset--;
|
||||||
|
} else {
|
||||||
|
state.sessionNormalForms.set(e, nf);
|
||||||
|
}
|
||||||
|
|
||||||
return nf;
|
return nf;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -830,6 +860,7 @@ Expr evalExpr(EvalState & state, Expr e)
|
||||||
Expr evalFile(EvalState & state, const Path & path)
|
Expr evalFile(EvalState & state, const Path & path)
|
||||||
{
|
{
|
||||||
startNest(nest, lvlTalkative, format("evaluating file `%1%'") % path);
|
startNest(nest, lvlTalkative, format("evaluating file `%1%'") % path);
|
||||||
|
state.nrDepthAfterReset = 0;
|
||||||
Expr e = parseExprFromFile(state, path);
|
Expr e = parseExprFromFile(state, path);
|
||||||
try {
|
try {
|
||||||
return evalExpr(state, e);
|
return evalExpr(state, e);
|
||||||
|
@ -901,11 +932,13 @@ void printEvalStats(EvalState & state)
|
||||||
char x;
|
char x;
|
||||||
bool showStats = getEnv("NIX_SHOW_STATS", "0") != "0";
|
bool showStats = getEnv("NIX_SHOW_STATS", "0") != "0";
|
||||||
printMsg(showStats ? lvlInfo : lvlDebug,
|
printMsg(showStats ? lvlInfo : lvlDebug,
|
||||||
format("evaluated %1% expressions, %2% cache hits, %3%%% efficiency, used %4% ATerm bytes, used %5% bytes of stack space")
|
format("evaluated %1% expressions, %2% cache hits, %3%%% efficiency, used %4% ATerm bytes, used %5% bytes of stack space, %6% cached normal reduction, %7% session dependent reduction.")
|
||||||
% state.nrEvaluated % state.nrCached
|
% state.nrEvaluated % state.nrCached
|
||||||
% ((float) state.nrCached / (float) state.nrEvaluated * 100)
|
% ((float) state.nrCached / (float) state.nrEvaluated * 100)
|
||||||
% AT_calcAllocatedSize()
|
% AT_calcAllocatedSize()
|
||||||
% (&x - deepestStack));
|
% (&x - deepestStack)
|
||||||
|
% state.normalForms.size()
|
||||||
|
% state.sessionNormalForms.size());
|
||||||
if (showStats)
|
if (showStats)
|
||||||
printATermMapStats();
|
printATermMapStats();
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,6 +30,7 @@ typedef Expr (* PrimOp) (EvalState &, const ATermVector & args);
|
||||||
struct EvalState
|
struct EvalState
|
||||||
{
|
{
|
||||||
ATermMap normalForms;
|
ATermMap normalForms;
|
||||||
|
ATermMap sessionNormalForms;
|
||||||
ATermMap primOps;
|
ATermMap primOps;
|
||||||
DrvRoots drvRoots;
|
DrvRoots drvRoots;
|
||||||
DrvHashes drvHashes; /* normalised derivation hashes */
|
DrvHashes drvHashes; /* normalised derivation hashes */
|
||||||
|
@ -37,14 +38,19 @@ struct EvalState
|
||||||
|
|
||||||
unsigned int nrEvaluated;
|
unsigned int nrEvaluated;
|
||||||
unsigned int nrCached;
|
unsigned int nrCached;
|
||||||
|
unsigned int nrDepthAfterReset;
|
||||||
|
|
||||||
bool allowUnsafeEquality;
|
bool allowUnsafeEquality;
|
||||||
|
bool safeCache;
|
||||||
|
|
||||||
EvalState();
|
EvalState();
|
||||||
|
~EvalState();
|
||||||
|
|
||||||
void addPrimOps();
|
void addPrimOps();
|
||||||
void addPrimOp(const string & name,
|
void addPrimOp(const string & name,
|
||||||
unsigned int arity, PrimOp primOp);
|
unsigned int arity, PrimOp primOp);
|
||||||
|
void loadNormalForms();
|
||||||
|
void saveNormalForms();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
64
src/libexpr/normal-forms.cc
Normal file
64
src/libexpr/normal-forms.cc
Normal file
|
@ -0,0 +1,64 @@
|
||||||
|
#include "eval.hh"
|
||||||
|
#include "util.hh"
|
||||||
|
#include "globals.hh"
|
||||||
|
#include "serialise.hh"
|
||||||
|
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
|
||||||
|
namespace nix {
|
||||||
|
|
||||||
|
|
||||||
|
void EvalState::loadNormalForms()
|
||||||
|
{
|
||||||
|
// nixCacheFile = getEnv("NIX_CACHE_FILE", nixStateDir + "/reduce-cache");
|
||||||
|
nixCacheFile = getEnv("NIX_CACHE_FILE");
|
||||||
|
string loadFlag = getEnv("NIX_CACHE_FILE_LOAD", "1");
|
||||||
|
|
||||||
|
if(nixCacheFile == "" || loadFlag == "")
|
||||||
|
return;
|
||||||
|
if(!pathExists(nixCacheFile))
|
||||||
|
return;
|
||||||
|
|
||||||
|
printMsg(lvlInfo, format("Load cache: ..."));
|
||||||
|
try {
|
||||||
|
int fd = open(nixCacheFile.c_str(), O_RDONLY);
|
||||||
|
if (fd == -1)
|
||||||
|
throw SysError(format("opening file `%1%'") % nixCacheFile);
|
||||||
|
AutoCloseFD auto_fd = fd;
|
||||||
|
|
||||||
|
FdSource source = fd;
|
||||||
|
normalForms = readATermMap(source);
|
||||||
|
} catch (Error & e) {
|
||||||
|
e.addPrefix(format("Cannot load cached reduce operations from %1%:\n") % nixCacheFile);
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
printMsg(lvlInfo, format("Load cache: end"));
|
||||||
|
}
|
||||||
|
|
||||||
|
void EvalState::saveNormalForms()
|
||||||
|
{
|
||||||
|
string saveFlag = getEnv("NIX_CACHE_FILE_SAVE", "");
|
||||||
|
|
||||||
|
if(nixCacheFile == "" || saveFlag == "")
|
||||||
|
return;
|
||||||
|
|
||||||
|
printMsg(lvlInfo, format("Save cache: ..."));
|
||||||
|
try {
|
||||||
|
int fd = open(nixCacheFile.c_str(), O_WRONLY | O_TRUNC | O_CREAT, 0666);
|
||||||
|
if (fd == -1)
|
||||||
|
throw SysError(format("opening file `%1%'") % nixCacheFile);
|
||||||
|
AutoCloseFD auto_fd = fd;
|
||||||
|
|
||||||
|
FdSink sink = fd;
|
||||||
|
writeATermMap(normalForms, sink);
|
||||||
|
} catch (Error & e) {
|
||||||
|
e.addPrefix(format("Cannot save cached reduce operations to %1%:\n") % nixCacheFile);
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
printMsg(lvlInfo, format("Save cache: end"));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
|
@ -74,12 +74,14 @@ static Expr prim_null(EvalState & state, const ATermVector & args)
|
||||||
platforms. */
|
platforms. */
|
||||||
static Expr prim_currentSystem(EvalState & state, const ATermVector & args)
|
static Expr prim_currentSystem(EvalState & state, const ATermVector & args)
|
||||||
{
|
{
|
||||||
|
state.nrDepthAfterReset = 0;
|
||||||
return makeStr(thisSystem);
|
return makeStr(thisSystem);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static Expr prim_currentTime(EvalState & state, const ATermVector & args)
|
static Expr prim_currentTime(EvalState & state, const ATermVector & args)
|
||||||
{
|
{
|
||||||
|
state.nrDepthAfterReset = 0;
|
||||||
return ATmake("Int(<int>)", time(0));
|
return ATmake("Int(<int>)", time(0));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -228,6 +230,7 @@ static Expr prim_addErrorContext(EvalState & state, const ATermVector & args)
|
||||||
static Expr prim_getEnv(EvalState & state, const ATermVector & args)
|
static Expr prim_getEnv(EvalState & state, const ATermVector & args)
|
||||||
{
|
{
|
||||||
string name = evalStringNoCtx(state, args[0]);
|
string name = evalStringNoCtx(state, args[0]);
|
||||||
|
state.nrDepthAfterReset = 0;
|
||||||
return makeStr(getEnv(name));
|
return makeStr(getEnv(name));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -316,6 +319,7 @@ static Hash hashDerivationModulo(EvalState & state, Derivation drv)
|
||||||
static Expr prim_derivationStrict(EvalState & state, const ATermVector & args)
|
static Expr prim_derivationStrict(EvalState & state, const ATermVector & args)
|
||||||
{
|
{
|
||||||
startNest(nest, lvlVomit, "evaluating derivation");
|
startNest(nest, lvlVomit, "evaluating derivation");
|
||||||
|
state.nrDepthAfterReset = 0;
|
||||||
|
|
||||||
ATermMap attrs;
|
ATermMap attrs;
|
||||||
queryAllAttrs(evalExpr(state, args[0]), attrs, true);
|
queryAllAttrs(evalExpr(state, args[0]), attrs, true);
|
||||||
|
@ -549,6 +553,7 @@ static Expr prim_storePath(EvalState & state, const ATermVector & args)
|
||||||
{
|
{
|
||||||
PathSet context;
|
PathSet context;
|
||||||
Path path = canonPath(coerceToPath(state, args[0], context));
|
Path path = canonPath(coerceToPath(state, args[0], context));
|
||||||
|
state.nrDepthAfterReset = 0;
|
||||||
if (!isInStore(path))
|
if (!isInStore(path))
|
||||||
throw EvalError(format("path `%1%' is not in the Nix store") % path);
|
throw EvalError(format("path `%1%' is not in the Nix store") % path);
|
||||||
Path path2 = toStorePath(path);
|
Path path2 = toStorePath(path);
|
||||||
|
@ -565,6 +570,7 @@ static Expr prim_pathExists(EvalState & state, const ATermVector & args)
|
||||||
Path path = coerceToPath(state, args[0], context);
|
Path path = coerceToPath(state, args[0], context);
|
||||||
if (!context.empty())
|
if (!context.empty())
|
||||||
throw EvalError(format("string `%1%' cannot refer to other paths") % path);
|
throw EvalError(format("string `%1%' cannot refer to other paths") % path);
|
||||||
|
state.nrDepthAfterReset = 0;
|
||||||
return makeBool(pathExists(path));
|
return makeBool(pathExists(path));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -598,6 +604,7 @@ static Expr prim_readFile(EvalState & state, const ATermVector & args)
|
||||||
Path path = coerceToPath(state, args[0], context);
|
Path path = coerceToPath(state, args[0], context);
|
||||||
if (!context.empty())
|
if (!context.empty())
|
||||||
throw EvalError(format("string `%1%' cannot refer to other paths") % path);
|
throw EvalError(format("string `%1%' cannot refer to other paths") % path);
|
||||||
|
state.nrDepthAfterReset = 0;
|
||||||
return makeStr(readFile(path));
|
return makeStr(readFile(path));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -637,6 +644,7 @@ static Expr prim_toFile(EvalState & state, const ATermVector & args)
|
||||||
refs.insert(path);
|
refs.insert(path);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
state.nrDepthAfterReset = 0;
|
||||||
Path storePath = readOnlyMode
|
Path storePath = readOnlyMode
|
||||||
? computeStorePathForText(name, contents, refs)
|
? computeStorePathForText(name, contents, refs)
|
||||||
: store->addTextToStore(name, contents, refs);
|
: store->addTextToStore(name, contents, refs);
|
||||||
|
@ -689,6 +697,7 @@ static Expr prim_filterSource(EvalState & state, const ATermVector & args)
|
||||||
|
|
||||||
FilterFromExpr filter(state, args[0]);
|
FilterFromExpr filter(state, args[0]);
|
||||||
|
|
||||||
|
state.nrDepthAfterReset = 0;
|
||||||
Path dstPath = readOnlyMode
|
Path dstPath = readOnlyMode
|
||||||
? computeStorePathForPath(path, true, htSHA256, filter).first
|
? computeStorePathForPath(path, true, htSHA256, filter).first
|
||||||
: store->addToStore(path, true, htSHA256, filter);
|
: store->addToStore(path, true, htSHA256, filter);
|
||||||
|
|
|
@ -13,6 +13,7 @@ string nixDataDir = "/UNINIT";
|
||||||
string nixLogDir = "/UNINIT";
|
string nixLogDir = "/UNINIT";
|
||||||
string nixStateDir = "/UNINIT";
|
string nixStateDir = "/UNINIT";
|
||||||
string nixDBPath = "/UNINIT";
|
string nixDBPath = "/UNINIT";
|
||||||
|
string nixCacheFile = "/UNINIT";
|
||||||
string nixConfDir = "/UNINIT";
|
string nixConfDir = "/UNINIT";
|
||||||
string nixLibexecDir = "/UNINIT";
|
string nixLibexecDir = "/UNINIT";
|
||||||
string nixBinDir = "/UNINIT";
|
string nixBinDir = "/UNINIT";
|
||||||
|
|
|
@ -24,6 +24,9 @@ extern string nixStateDir;
|
||||||
/* nixDBPath is the path name of our Berkeley DB environment. */
|
/* nixDBPath is the path name of our Berkeley DB environment. */
|
||||||
extern string nixDBPath;
|
extern string nixDBPath;
|
||||||
|
|
||||||
|
/* nixCacheFile is the path name of the normal form cache. */
|
||||||
|
extern string nixCacheFile;
|
||||||
|
|
||||||
/* nixConfDir is the directory where configuration files are
|
/* nixConfDir is the directory where configuration files are
|
||||||
stored. */
|
stored. */
|
||||||
extern string nixConfDir;
|
extern string nixConfDir;
|
||||||
|
|
|
@ -215,7 +215,7 @@ void ATermMap::remove(ATerm key)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
unsigned int ATermMap::size()
|
unsigned int ATermMap::size() const
|
||||||
{
|
{
|
||||||
return count; /* STL nomenclature */
|
return count; /* STL nomenclature */
|
||||||
}
|
}
|
||||||
|
|
|
@ -59,7 +59,7 @@ public:
|
||||||
|
|
||||||
void remove(ATerm key);
|
void remove(ATerm key);
|
||||||
|
|
||||||
unsigned int size();
|
unsigned int size() const;
|
||||||
|
|
||||||
struct const_iterator
|
struct const_iterator
|
||||||
{
|
{
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
#include "serialise.hh"
|
#include "serialise.hh"
|
||||||
#include "util.hh"
|
#include "util.hh"
|
||||||
|
#include "aterm.hh"
|
||||||
|
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
|
|
||||||
|
|
||||||
namespace nix {
|
namespace nix {
|
||||||
|
|
||||||
|
|
||||||
|
@ -73,6 +73,67 @@ void writeStringSet(const StringSet & ss, Sink & sink)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void writeATerm(ATerm t, Sink & sink)
|
||||||
|
{
|
||||||
|
int len;
|
||||||
|
unsigned char *buf = (unsigned char *) ATwriteToBinaryString(t, &len);
|
||||||
|
AutoDeleteArray<unsigned char> d(buf);
|
||||||
|
writeInt(len, sink);
|
||||||
|
sink(buf, len);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* convert the ATermMap to a list of couple because many terms are shared
|
||||||
|
between the keys and between the values. Thus the BAF stored by
|
||||||
|
writeATerm consume less memory space. The list of couples is saved
|
||||||
|
inside a tree structure of /treedepth/ height because the serialiasation
|
||||||
|
of ATerm cause a tail recurssion on list tails. */
|
||||||
|
void writeATermMap(const ATermMap & tm, Sink & sink)
|
||||||
|
{
|
||||||
|
const unsigned int treedepth = 5;
|
||||||
|
const unsigned int maxarity = 128; // 2 < maxarity < MAX_ARITY (= 255)
|
||||||
|
const unsigned int bufsize = treedepth * maxarity;
|
||||||
|
|
||||||
|
AFun map = ATmakeAFun("map", 2, ATfalse);
|
||||||
|
AFun node = ATmakeAFun("node", maxarity, ATfalse);
|
||||||
|
ATerm empty = (ATerm) ATmakeAppl0(ATmakeAFun("empty", 0, ATfalse));
|
||||||
|
|
||||||
|
unsigned int c[treedepth];
|
||||||
|
ATerm *buf = new ATerm[bufsize];
|
||||||
|
AutoDeleteArray<ATerm> d(buf);
|
||||||
|
|
||||||
|
memset(buf, 0, bufsize * sizeof(ATerm));
|
||||||
|
ATprotectArray(buf, bufsize);
|
||||||
|
|
||||||
|
for (unsigned int j = 0; j < treedepth; j++)
|
||||||
|
c[j] = 0;
|
||||||
|
|
||||||
|
for (ATermMap::const_iterator i = tm.begin(); i != tm.end(); ++i) {
|
||||||
|
unsigned int depth = treedepth - 1;
|
||||||
|
ATerm term = (ATerm) ATmakeAppl2(map, i->key, i->value);
|
||||||
|
buf[depth * maxarity + c[depth]++] = term;
|
||||||
|
while (c[depth] % maxarity == 0) {
|
||||||
|
c[depth] = 0;
|
||||||
|
term = (ATerm) ATmakeApplArray(node, &buf[depth * maxarity]);
|
||||||
|
depth--;
|
||||||
|
buf[depth * maxarity + c[depth]++] = term;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int depth = treedepth;
|
||||||
|
ATerm last_node = empty;
|
||||||
|
while (depth--) {
|
||||||
|
buf[depth * maxarity + c[depth]++] = last_node;
|
||||||
|
while (c[depth] % maxarity)
|
||||||
|
buf[depth * maxarity + c[depth]++] = empty;
|
||||||
|
last_node = (ATerm) ATmakeApplArray(node, &buf[depth * maxarity]);
|
||||||
|
}
|
||||||
|
|
||||||
|
writeATerm(last_node, sink);
|
||||||
|
ATunprotectArray(buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void readPadding(unsigned int len, Source & source)
|
void readPadding(unsigned int len, Source & source)
|
||||||
{
|
{
|
||||||
if (len % 8) {
|
if (len % 8) {
|
||||||
|
@ -136,4 +197,48 @@ StringSet readStringSet(Source & source)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
ATerm readATerm(Source & source)
|
||||||
|
{
|
||||||
|
unsigned int len = readInt(source);
|
||||||
|
unsigned char * buf = new unsigned char[len];
|
||||||
|
AutoDeleteArray<unsigned char> d(buf);
|
||||||
|
source(buf, len);
|
||||||
|
ATerm t = ATreadFromBinaryString((char *) buf, len);
|
||||||
|
if (t == 0)
|
||||||
|
throw SerialisationError("cannot read a valid ATerm.");
|
||||||
|
return t;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void recursiveInitATermMap(ATermMap &tm, bool &stop, ATermAppl node)
|
||||||
|
{
|
||||||
|
const unsigned int arity = ATgetArity(ATgetAFun(node));
|
||||||
|
ATerm key, value;
|
||||||
|
|
||||||
|
switch (arity) {
|
||||||
|
case 0:
|
||||||
|
stop = true;
|
||||||
|
return;
|
||||||
|
case 2:
|
||||||
|
key = ATgetArgument(node, 0);
|
||||||
|
value = ATgetArgument(node, 1);
|
||||||
|
tm.set(key, value);
|
||||||
|
return;
|
||||||
|
default:
|
||||||
|
for (unsigned int i = 0; i < arity && !stop; i++)
|
||||||
|
recursiveInitATermMap(tm, stop, (ATermAppl) ATgetArgument(node, i));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ATermMap readATermMap(Source & source)
|
||||||
|
{
|
||||||
|
ATermMap tm;
|
||||||
|
bool stop = false;
|
||||||
|
|
||||||
|
recursiveInitATermMap(tm, stop, (ATermAppl) readATerm(source));
|
||||||
|
return tm;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
#define __SERIALISE_H
|
#define __SERIALISE_H
|
||||||
|
|
||||||
#include "types.hh"
|
#include "types.hh"
|
||||||
|
#include "aterm-map.hh"
|
||||||
|
|
||||||
namespace nix {
|
namespace nix {
|
||||||
|
|
||||||
|
@ -98,12 +98,16 @@ void writeInt(unsigned int n, Sink & sink);
|
||||||
void writeLongLong(unsigned long long n, Sink & sink);
|
void writeLongLong(unsigned long long n, Sink & sink);
|
||||||
void writeString(const string & s, Sink & sink);
|
void writeString(const string & s, Sink & sink);
|
||||||
void writeStringSet(const StringSet & ss, Sink & sink);
|
void writeStringSet(const StringSet & ss, Sink & sink);
|
||||||
|
void writeATerm(ATerm t, Sink & sink);
|
||||||
|
void writeATermMap(const ATermMap & tm, Sink & sink);
|
||||||
|
|
||||||
void readPadding(unsigned int len, Source & source);
|
void readPadding(unsigned int len, Source & source);
|
||||||
unsigned int readInt(Source & source);
|
unsigned int readInt(Source & source);
|
||||||
unsigned long long readLongLong(Source & source);
|
unsigned long long readLongLong(Source & source);
|
||||||
string readString(Source & source);
|
string readString(Source & source);
|
||||||
StringSet readStringSet(Source & source);
|
StringSet readStringSet(Source & source);
|
||||||
|
ATerm readATerm(Source & source);
|
||||||
|
ATermMap readATermMap(Source & source);
|
||||||
|
|
||||||
|
|
||||||
MakeError(SerialisationError, Error)
|
MakeError(SerialisationError, Error)
|
||||||
|
|
Loading…
Reference in a new issue