string2Int(): Return std::optional
This commit is contained in:
parent
29a445840a
commit
6548b89cc4
17 changed files with 82 additions and 69 deletions
|
@ -52,9 +52,7 @@ std::pair<Value *, Pos> findAlongAttrPath(EvalState & state, const string & attr
|
||||||
for (auto & attr : tokens) {
|
for (auto & attr : tokens) {
|
||||||
|
|
||||||
/* Is i an index (integer) or a normal attribute name? */
|
/* Is i an index (integer) or a normal attribute name? */
|
||||||
enum { apAttr, apIndex } apType = apAttr;
|
auto attrIndex = string2Int<unsigned int>(attr);
|
||||||
unsigned int attrIndex;
|
|
||||||
if (string2Int(attr, attrIndex)) apType = apIndex;
|
|
||||||
|
|
||||||
/* Evaluate the expression. */
|
/* Evaluate the expression. */
|
||||||
Value * vNew = state.allocValue();
|
Value * vNew = state.allocValue();
|
||||||
|
@ -65,7 +63,7 @@ std::pair<Value *, Pos> findAlongAttrPath(EvalState & state, const string & attr
|
||||||
/* It should evaluate to either a set or an expression,
|
/* It should evaluate to either a set or an expression,
|
||||||
according to what is specified in the attrPath. */
|
according to what is specified in the attrPath. */
|
||||||
|
|
||||||
if (apType == apAttr) {
|
if (!attrIndex) {
|
||||||
|
|
||||||
if (v->type() != nAttrs)
|
if (v->type() != nAttrs)
|
||||||
throw TypeError(
|
throw TypeError(
|
||||||
|
@ -82,17 +80,17 @@ std::pair<Value *, Pos> findAlongAttrPath(EvalState & state, const string & attr
|
||||||
pos = *a->pos;
|
pos = *a->pos;
|
||||||
}
|
}
|
||||||
|
|
||||||
else if (apType == apIndex) {
|
else {
|
||||||
|
|
||||||
if (!v->isList())
|
if (!v->isList())
|
||||||
throw TypeError(
|
throw TypeError(
|
||||||
"the expression selected by the selection path '%1%' should be a list but is %2%",
|
"the expression selected by the selection path '%1%' should be a list but is %2%",
|
||||||
attrPath,
|
attrPath,
|
||||||
showType(*v));
|
showType(*v));
|
||||||
if (attrIndex >= v->listSize())
|
if (*attrIndex >= v->listSize())
|
||||||
throw AttrPathNotFound("list index %1% in selection path '%2%' is out of range", attrIndex, attrPath);
|
throw AttrPathNotFound("list index %1% in selection path '%2%' is out of range", *attrIndex, attrPath);
|
||||||
|
|
||||||
v = v->listElems()[attrIndex];
|
v = v->listElems()[*attrIndex];
|
||||||
pos = noPos;
|
pos = noPos;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -214,8 +214,8 @@ NixInt DrvInfo::queryMetaInt(const string & name, NixInt def)
|
||||||
if (v->type() == nString) {
|
if (v->type() == nString) {
|
||||||
/* Backwards compatibility with before we had support for
|
/* Backwards compatibility with before we had support for
|
||||||
integer meta fields. */
|
integer meta fields. */
|
||||||
NixInt n;
|
if (auto n = string2Int<NixInt>(v->string.s))
|
||||||
if (string2Int(v->string.s, n)) return n;
|
return *n;
|
||||||
}
|
}
|
||||||
return def;
|
return def;
|
||||||
}
|
}
|
||||||
|
@ -228,8 +228,8 @@ NixFloat DrvInfo::queryMetaFloat(const string & name, NixFloat def)
|
||||||
if (v->type() == nString) {
|
if (v->type() == nString) {
|
||||||
/* Backwards compatibility with before we had support for
|
/* Backwards compatibility with before we had support for
|
||||||
float meta fields. */
|
float meta fields. */
|
||||||
NixFloat n;
|
if (auto n = string2Float<NixFloat>(v->string.s))
|
||||||
if (string2Float(v->string.s, n)) return n;
|
return *n;
|
||||||
}
|
}
|
||||||
return def;
|
return def;
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,10 +20,10 @@ struct PathInputScheme : InputScheme
|
||||||
if (name == "rev" || name == "narHash")
|
if (name == "rev" || name == "narHash")
|
||||||
input.attrs.insert_or_assign(name, value);
|
input.attrs.insert_or_assign(name, value);
|
||||||
else if (name == "revCount" || name == "lastModified") {
|
else if (name == "revCount" || name == "lastModified") {
|
||||||
uint64_t n;
|
if (auto n = string2Int<uint64_t>(value))
|
||||||
if (!string2Int(value, n))
|
input.attrs.insert_or_assign(name, *n);
|
||||||
|
else
|
||||||
throw Error("path URL '%s' has invalid parameter '%s'", url.to_string(), name);
|
throw Error("path URL '%s' has invalid parameter '%s'", url.to_string(), name);
|
||||||
input.attrs.insert_or_assign(name, n);
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
throw Error("path URL '%s' has unsupported parameter '%s'", url.to_string(), name);
|
throw Error("path URL '%s' has unsupported parameter '%s'", url.to_string(), name);
|
||||||
|
|
|
@ -219,10 +219,10 @@ LegacyArgs::LegacyArgs(const std::string & programName,
|
||||||
.description = description,
|
.description = description,
|
||||||
.labels = {"n"},
|
.labels = {"n"},
|
||||||
.handler = {[=](std::string s) {
|
.handler = {[=](std::string s) {
|
||||||
unsigned int n;
|
if (auto n = string2Int<unsigned int>(s))
|
||||||
if (!string2Int(s, n))
|
settings.set(dest, std::to_string(*n));
|
||||||
|
else
|
||||||
throw UsageError("'%s' is not an integer", s);
|
throw UsageError("'%s' is not an integer", s);
|
||||||
settings.set(dest, std::to_string(n));
|
|
||||||
}}
|
}}
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
|
@ -70,10 +70,9 @@ template<class N> N getIntArg(const string & opt,
|
||||||
s.resize(s.size() - 1);
|
s.resize(s.size() - 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
N n;
|
if (auto n = string2Int<N>(s))
|
||||||
if (!string2Int(s, n))
|
return *n * multiplier;
|
||||||
throw UsageError("'%1%' requires an integer argument", opt);
|
throw UsageError("'%1%' requires an integer argument", opt);
|
||||||
return n * multiplier;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1699,12 +1699,10 @@ void DerivationGoal::startBuilder()
|
||||||
userNamespaceSync.writeSide = -1;
|
userNamespaceSync.writeSide = -1;
|
||||||
});
|
});
|
||||||
|
|
||||||
pid_t tmp;
|
|
||||||
auto ss = tokenizeString<std::vector<std::string>>(readLine(builderOut.readSide.get()));
|
auto ss = tokenizeString<std::vector<std::string>>(readLine(builderOut.readSide.get()));
|
||||||
assert(ss.size() == 2);
|
assert(ss.size() == 2);
|
||||||
usingUserNamespace = ss[0] == "1";
|
usingUserNamespace = ss[0] == "1";
|
||||||
if (!string2Int<pid_t>(ss[1], tmp)) abort();
|
pid = string2Int<pid_t>(ss[1]).value();
|
||||||
pid = tmp;
|
|
||||||
|
|
||||||
if (usingUserNamespace) {
|
if (usingUserNamespace) {
|
||||||
/* Set the UID/GID mapping of the builder's user namespace
|
/* Set the UID/GID mapping of the builder's user namespace
|
||||||
|
|
|
@ -228,8 +228,12 @@ template<> void BaseSetting<SandboxMode>::convertToArg(Args & args, const std::s
|
||||||
void MaxBuildJobsSetting::set(const std::string & str, bool append)
|
void MaxBuildJobsSetting::set(const std::string & str, bool append)
|
||||||
{
|
{
|
||||||
if (str == "auto") value = std::max(1U, std::thread::hardware_concurrency());
|
if (str == "auto") value = std::max(1U, std::thread::hardware_concurrency());
|
||||||
else if (!string2Int(str, value))
|
else {
|
||||||
throw UsageError("configuration setting '%s' should be 'auto' or an integer", name);
|
if (auto n = string2Int<decltype(value)>(str))
|
||||||
|
value = *n;
|
||||||
|
else
|
||||||
|
throw UsageError("configuration setting '%s' should be 'auto' or an integer", name);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -66,8 +66,10 @@ int getSchema(Path schemaPath)
|
||||||
int curSchema = 0;
|
int curSchema = 0;
|
||||||
if (pathExists(schemaPath)) {
|
if (pathExists(schemaPath)) {
|
||||||
string s = readFile(schemaPath);
|
string s = readFile(schemaPath);
|
||||||
if (!string2Int(s, curSchema))
|
auto n = string2Int<int>(s);
|
||||||
|
if (!n)
|
||||||
throw Error("'%1%' is corrupt", schemaPath);
|
throw Error("'%1%' is corrupt", schemaPath);
|
||||||
|
curSchema = *n;
|
||||||
}
|
}
|
||||||
return curSchema;
|
return curSchema;
|
||||||
}
|
}
|
||||||
|
|
|
@ -80,16 +80,16 @@ string nextComponent(string::const_iterator & p,
|
||||||
|
|
||||||
static bool componentsLT(const string & c1, const string & c2)
|
static bool componentsLT(const string & c1, const string & c2)
|
||||||
{
|
{
|
||||||
int n1, n2;
|
auto n1 = string2Int<int>(c1);
|
||||||
bool c1Num = string2Int(c1, n1), c2Num = string2Int(c2, n2);
|
auto n2 = string2Int<int>(c2);
|
||||||
|
|
||||||
if (c1Num && c2Num) return n1 < n2;
|
if (n1 && n2) return *n1 < *n2;
|
||||||
else if (c1 == "" && c2Num) return true;
|
else if (c1 == "" && n2) return true;
|
||||||
else if (c1 == "pre" && c2 != "pre") return true;
|
else if (c1 == "pre" && c2 != "pre") return true;
|
||||||
else if (c2 == "pre") return false;
|
else if (c2 == "pre") return false;
|
||||||
/* Assume that `2.3a' < `2.3.1'. */
|
/* Assume that `2.3a' < `2.3.1'. */
|
||||||
else if (c2Num) return true;
|
else if (n2) return true;
|
||||||
else if (c1Num) return false;
|
else if (n1) return false;
|
||||||
else return c1 < c2;
|
else return c1 < c2;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -46,14 +46,18 @@ NarInfo::NarInfo(const Store & store, const std::string & s, const std::string &
|
||||||
else if (name == "FileHash")
|
else if (name == "FileHash")
|
||||||
fileHash = parseHashField(value);
|
fileHash = parseHashField(value);
|
||||||
else if (name == "FileSize") {
|
else if (name == "FileSize") {
|
||||||
if (!string2Int(value, fileSize)) throw corrupt();
|
auto n = string2Int<decltype(fileSize)>(value);
|
||||||
|
if (!n) throw corrupt();
|
||||||
|
fileSize = *n;
|
||||||
}
|
}
|
||||||
else if (name == "NarHash") {
|
else if (name == "NarHash") {
|
||||||
narHash = parseHashField(value);
|
narHash = parseHashField(value);
|
||||||
haveNarHash = true;
|
haveNarHash = true;
|
||||||
}
|
}
|
||||||
else if (name == "NarSize") {
|
else if (name == "NarSize") {
|
||||||
if (!string2Int(value, narSize)) throw corrupt();
|
auto n = string2Int<decltype(narSize)>(value);
|
||||||
|
if (!n) throw corrupt();
|
||||||
|
narSize = *n;
|
||||||
}
|
}
|
||||||
else if (name == "References") {
|
else if (name == "References") {
|
||||||
auto refs = tokenizeString<Strings>(value, " ");
|
auto refs = tokenizeString<Strings>(value, " ");
|
||||||
|
|
|
@ -21,9 +21,8 @@ static std::optional<GenerationNumber> parseName(const string & profileName, con
|
||||||
string s = string(name, profileName.size() + 1);
|
string s = string(name, profileName.size() + 1);
|
||||||
string::size_type p = s.find("-link");
|
string::size_type p = s.find("-link");
|
||||||
if (p == string::npos) return {};
|
if (p == string::npos) return {};
|
||||||
unsigned int n;
|
if (auto n = string2Int<unsigned int>(s.substr(0, p)))
|
||||||
if (string2Int(string(s, 0, p), n) && n >= 0)
|
return *n;
|
||||||
return n;
|
|
||||||
else
|
else
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
@ -214,12 +213,12 @@ void deleteGenerationsOlderThan(const Path & profile, const string & timeSpec, b
|
||||||
{
|
{
|
||||||
time_t curTime = time(0);
|
time_t curTime = time(0);
|
||||||
string strDays = string(timeSpec, 0, timeSpec.size() - 1);
|
string strDays = string(timeSpec, 0, timeSpec.size() - 1);
|
||||||
int days;
|
auto days = string2Int<int>(strDays);
|
||||||
|
|
||||||
if (!string2Int(strDays, days) || days < 1)
|
if (!days || *days < 1)
|
||||||
throw Error("invalid number of days specifier '%1%'", timeSpec);
|
throw Error("invalid number of days specifier '%1%'", timeSpec);
|
||||||
|
|
||||||
time_t oldTime = curTime - days * 24 * 3600;
|
time_t oldTime = curTime - *days * 24 * 3600;
|
||||||
|
|
||||||
deleteGenerationsOlderThan(profile, oldTime, dryRun);
|
deleteGenerationsOlderThan(profile, oldTime, dryRun);
|
||||||
}
|
}
|
||||||
|
|
|
@ -932,19 +932,20 @@ std::optional<ValidPathInfo> decodeValidPathInfo(const Store & store, std::istre
|
||||||
getline(str, s);
|
getline(str, s);
|
||||||
auto narHash = Hash::parseAny(s, htSHA256);
|
auto narHash = Hash::parseAny(s, htSHA256);
|
||||||
getline(str, s);
|
getline(str, s);
|
||||||
uint64_t narSize;
|
auto narSize = string2Int<uint64_t>(s);
|
||||||
if (!string2Int(s, narSize)) throw Error("number expected");
|
if (!narSize) throw Error("number expected");
|
||||||
hashGiven = { narHash, narSize };
|
hashGiven = { narHash, *narSize };
|
||||||
}
|
}
|
||||||
ValidPathInfo info(store.parseStorePath(path), hashGiven->first);
|
ValidPathInfo info(store.parseStorePath(path), hashGiven->first);
|
||||||
info.narSize = hashGiven->second;
|
info.narSize = hashGiven->second;
|
||||||
std::string deriver;
|
std::string deriver;
|
||||||
getline(str, deriver);
|
getline(str, deriver);
|
||||||
if (deriver != "") info.deriver = store.parseStorePath(deriver);
|
if (deriver != "") info.deriver = store.parseStorePath(deriver);
|
||||||
string s; int n;
|
string s;
|
||||||
getline(str, s);
|
getline(str, s);
|
||||||
if (!string2Int(s, n)) throw Error("number expected");
|
auto n = string2Int<int>(s);
|
||||||
while (n--) {
|
if (!n) throw Error("number expected");
|
||||||
|
while ((*n)--) {
|
||||||
getline(str, s);
|
getline(str, s);
|
||||||
info.references.insert(store.parseStorePath(s));
|
info.references.insert(store.parseStorePath(s));
|
||||||
}
|
}
|
||||||
|
|
|
@ -87,7 +87,9 @@ protected:
|
||||||
template<class I>
|
template<class I>
|
||||||
Handler(I * dest)
|
Handler(I * dest)
|
||||||
: fun([=](std::vector<std::string> ss) {
|
: fun([=](std::vector<std::string> ss) {
|
||||||
if (!string2Int(ss[0], *dest))
|
if (auto n = string2Int<I>(ss[0]))
|
||||||
|
*dest = *n;
|
||||||
|
else
|
||||||
throw UsageError("'%s' is not an integer", ss[0]);
|
throw UsageError("'%s' is not an integer", ss[0]);
|
||||||
})
|
})
|
||||||
, arity(1)
|
, arity(1)
|
||||||
|
|
|
@ -230,7 +230,9 @@ template<typename T>
|
||||||
void BaseSetting<T>::set(const std::string & str, bool append)
|
void BaseSetting<T>::set(const std::string & str, bool append)
|
||||||
{
|
{
|
||||||
static_assert(std::is_integral<T>::value, "Integer required.");
|
static_assert(std::is_integral<T>::value, "Integer required.");
|
||||||
if (!string2Int(str, value))
|
if (auto n = string2Int<T>(str))
|
||||||
|
value = *n;
|
||||||
|
else
|
||||||
throw UsageError("setting '%s' has invalid value '%s'", name, str);
|
throw UsageError("setting '%s' has invalid value '%s'", name, str);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -397,21 +397,27 @@ bool statusOk(int status);
|
||||||
|
|
||||||
|
|
||||||
/* Parse a string into an integer. */
|
/* Parse a string into an integer. */
|
||||||
template<class N> bool string2Int(const string & s, N & n)
|
template<class N>
|
||||||
|
std::optional<N> string2Int(const std::string & s)
|
||||||
{
|
{
|
||||||
if (string(s, 0, 1) == "-" && !std::numeric_limits<N>::is_signed)
|
if (s.substr(0, 1) == "-" && !std::numeric_limits<N>::is_signed)
|
||||||
return false;
|
return {};
|
||||||
std::istringstream str(s);
|
std::istringstream str(s);
|
||||||
|
N n;
|
||||||
str >> n;
|
str >> n;
|
||||||
return str && str.get() == EOF;
|
if (str && str.get() == EOF) return n;
|
||||||
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Parse a string into a float. */
|
/* Parse a string into a float. */
|
||||||
template<class N> bool string2Float(const string & s, N & n)
|
template<class N>
|
||||||
|
std::optional<N> string2Float(const string & s)
|
||||||
{
|
{
|
||||||
std::istringstream str(s);
|
std::istringstream str(s);
|
||||||
|
N n;
|
||||||
str >> n;
|
str >> n;
|
||||||
return str && str.get() == EOF;
|
if (str && str.get() == EOF) return n;
|
||||||
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1250,11 +1250,10 @@ static void opSwitchGeneration(Globals & globals, Strings opFlags, Strings opArg
|
||||||
if (opArgs.size() != 1)
|
if (opArgs.size() != 1)
|
||||||
throw UsageError("exactly one argument expected");
|
throw UsageError("exactly one argument expected");
|
||||||
|
|
||||||
GenerationNumber dstGen;
|
if (auto dstGen = string2Int<GenerationNumber>(opArgs.front()))
|
||||||
if (!string2Int(opArgs.front(), dstGen))
|
switchGeneration(globals, *dstGen);
|
||||||
|
else
|
||||||
throw UsageError("expected a generation number");
|
throw UsageError("expected a generation number");
|
||||||
|
|
||||||
switchGeneration(globals, dstGen);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -1308,17 +1307,17 @@ static void opDeleteGenerations(Globals & globals, Strings opFlags, Strings opAr
|
||||||
if(opArgs.front().size() < 2)
|
if(opArgs.front().size() < 2)
|
||||||
throw Error("invalid number of generations ‘%1%’", opArgs.front());
|
throw Error("invalid number of generations ‘%1%’", opArgs.front());
|
||||||
string str_max = string(opArgs.front(), 1, opArgs.front().size());
|
string str_max = string(opArgs.front(), 1, opArgs.front().size());
|
||||||
GenerationNumber max;
|
auto max = string2Int<GenerationNumber>(str_max);
|
||||||
if (!string2Int(str_max, max) || max == 0)
|
if (!max || *max == 0)
|
||||||
throw Error("invalid number of generations to keep ‘%1%’", opArgs.front());
|
throw Error("invalid number of generations to keep ‘%1%’", opArgs.front());
|
||||||
deleteGenerationsGreaterThan(globals.profile, max, globals.dryRun);
|
deleteGenerationsGreaterThan(globals.profile, *max, globals.dryRun);
|
||||||
} else {
|
} else {
|
||||||
std::set<GenerationNumber> gens;
|
std::set<GenerationNumber> gens;
|
||||||
for (auto & i : opArgs) {
|
for (auto & i : opArgs) {
|
||||||
GenerationNumber n;
|
if (auto n = string2Int<GenerationNumber>(i))
|
||||||
if (!string2Int(i, n))
|
gens.insert(*n);
|
||||||
|
else
|
||||||
throw UsageError("invalid generation number '%1%'", i);
|
throw UsageError("invalid generation number '%1%'", i);
|
||||||
gens.insert(n);
|
|
||||||
}
|
}
|
||||||
deleteGenerations(globals.profile, gens, globals.dryRun);
|
deleteGenerations(globals.profile, gens, globals.dryRun);
|
||||||
}
|
}
|
||||||
|
|
|
@ -209,9 +209,8 @@ public:
|
||||||
std::vector<Matcher> res;
|
std::vector<Matcher> res;
|
||||||
|
|
||||||
for (auto & s : _matchers) {
|
for (auto & s : _matchers) {
|
||||||
size_t n;
|
if (auto n = string2Int<size_t>(s))
|
||||||
if (string2Int(s, n))
|
res.push_back(*n);
|
||||||
res.push_back(n);
|
|
||||||
else if (store->isStorePath(s))
|
else if (store->isStorePath(s))
|
||||||
res.push_back(s);
|
res.push_back(s);
|
||||||
else
|
else
|
||||||
|
|
Loading…
Reference in a new issue