Comments improvements; minor header files cleanup.

This commit is contained in:
Marko Zivanovic
2015-10-13 21:05:24 +02:00
parent 522e8b484b
commit 398ca786c4
5 changed files with 249 additions and 235 deletions
+50 -43
View File
@@ -30,7 +30,7 @@ SOFTWARE.
namespace version { namespace version {
/// Parse_error is thrown on all parsing and validation errors. /// Any error in parsing or validation of version string will result in Parse_error exception being thrown.
class Parse_error : public std::runtime_error { class Parse_error : public std::runtime_error {
using std::runtime_error::runtime_error; using std::runtime_error::runtime_error;
}; };
@@ -40,7 +40,7 @@ namespace version {
Type of identifier affects comparison: alphanumeric identifiers are compared as ASCII strings, while Type of identifier affects comparison: alphanumeric identifiers are compared as ASCII strings, while
numeric identifiers are compared as numbers. numeric identifiers are compared as numbers.
*/ */
enum class Identifier_type { enum class Id_type {
alnum, ///< Identifier is alphanumerical alnum, ///< Identifier is alphanumerical
num ///< Identifier is numeric num ///< Identifier is numeric
}; };
@@ -51,22 +51,22 @@ namespace version {
These identifiers can be either numerical or alphanumerical. These identifiers can be either numerical or alphanumerical.
This structure describes one such identifier. This structure describes one such identifier.
*/ */
using Prerelease_identifier = std::pair<std::string, Identifier_type>; using Prerelease_identifier = std::pair<std::string, Id_type>;
/// Container for all prerelease identifiers for a given version string. /// Container for all prerelease identifiers for a given version string.
using Prerelease_identifiers = std::vector<Prerelease_identifier>; using Prerelease_identifiers = std::vector<Prerelease_identifier>;
/// Build identifier is just a string and has no meaning for the purpose of version precedence. /// Build identifier is arbitrary string with no special meaning with regards to version precedence.
using Build_identifier = std::string; using Build_identifier = std::string;
/// Container for all build identifiers for a given version string. /// Container for all build identifiers of a given version string.
using Build_identifiers = std::vector<Build_identifier>; using Build_identifiers = std::vector<Build_identifier>;
/// Description of version broken into parts, as per semantic versioning specification. /// Description of version broken into parts, as per semantic versioning specification.
struct Version_data { struct Version_data {
int major; ///< Major version, change only on incompatible API modifications int major; ///< Major version, change only on incompatible API modifications.
int minor; ///< Minor version, change on compatible API modifications int minor; ///< Minor version, change on backwards-compatible API modifications.
int patch; ///< Patch version, change only on bugfixes int patch; ///< Patch version, change only on bugfixes.
/// Optional series of prerelease identifiers. /// Optional series of prerelease identifiers.
Prerelease_identifiers prerelease_ids; Prerelease_identifiers prerelease_ids;
@@ -75,40 +75,47 @@ namespace version {
Build_identifiers build_ids; Build_identifiers build_ids;
}; };
/// Forward declaration required for operators' template declarations. // Forward declaration required for operators' template declarations.
template<typename P, typename C> template<typename Parser, typename Comparator>
class Basic_version; class Basic_version;
/// Compare if left version object is less than the right. /// Test if left-hand version operand is of lower precedence than the right-hand version.
template<typename P, typename C> template<typename Parser, typename Comparator>
bool operator<(const Basic_version<P, C>&, const Basic_version<P, C>&); bool operator<(const Basic_version<Parser, Comparator>&,
const Basic_version<Parser, Comparator>&);
/// Compare if two version objects are equal. /// Test if left-hand version operand if of equal precedence as the right-hand version.
template<typename P, typename C> template<typename Parser, typename Comparator>
bool operator==(const Basic_version<P, C>& l, const Basic_version<P, C>& r); bool operator==(const Basic_version<Parser, Comparator>&,
const Basic_version<Parser, Comparator>&);
/// Output version object to stream using standard semver format (X.Y.Z-PR+B). /// Output version object to stream using standard semver format (X.Y.Z-PR+B).
template<typename P, typename C> template<typename Parser, typename Comparator>
std::ostream& operator<<(std::ostream& os, const Basic_version<P, C>& v); std::ostream& operator<<(std::ostream&,
const Basic_version<Parser, Comparator>&);
/// Compare if two version objects are different. /// Test if left-hand version and right-hand version are of different precedence.
template<typename P, typename C> template<typename Parser, typename Comparator>
bool operator!=(const version::Basic_version<P, C>& l, const version::Basic_version<P, C>& r); bool operator!=(const Basic_version<Parser, Comparator>&,
const Basic_version<Parser, Comparator>&);
/// Compare if left version object is greater than the right. /// Test if left-hand version operand is of higher precedence than the right-hand version.
template<typename P, typename C> template<typename Parser, typename Comparator>
bool operator>(const version::Basic_version<P, C>& l, const version::Basic_version<P, C>& r); bool operator>(const Basic_version<Parser, Comparator>&,
const Basic_version<Parser, Comparator>&);
/// Compare if left version object is greater than or equal the right. /// Test if left-hand version operand is of higher or equal precedence as the right-hand version.
template<typename P, typename C> template<typename Parser, typename Comparator>
bool operator>=(const version::Basic_version<P, C>& l, const version::Basic_version<P, C>& r); bool operator>=(const Basic_version<Parser, Comparator>&,
const Basic_version<Parser, Comparator>&);
/// Compare if left version object is less than or equal the right. /// Test if left-hand version operand is of lower or equal precedence as the right-hand version.
template<typename P, typename C> template<typename Parser, typename Comparator>
bool operator<=(const version::Basic_version<P, C>& l, const version::Basic_version<P, C>& r); bool operator<=(const Basic_version<Parser, Comparator>&,
const Basic_version<Parser, Comparator>&);
/// Generic version description and comparison class. /// Base class for various version parsing and precedence ordering schemes.
/** /**
Basic_version class describes general version object without prescribing parsing, Basic_version class describes general version object without prescribing parsing,
validation and comparison rules. These rules are implemented by supplied Parser and validation and comparison rules. These rules are implemented by supplied Parser and
@@ -117,11 +124,11 @@ namespace version {
template<typename Parser, typename Comparator> template<typename Parser, typename Comparator>
class Basic_version { class Basic_version {
public: public:
/// Construct Basic_version object using P to parse default ("0.0.0") version string and C for comparison. /// Construct Basic_version object using Parser object to parse default ("0.0.0") version string and Comparator for comparison.
Basic_version(Parser p, Comparator c); Basic_version(Parser, Comparator);
/// Construct Basic_version object using P to parse version string and C for comparison. /// Construct Basic_version object using Parser to parse supplied version string and Comparator for comparison.
Basic_version(const std::string& v, Parser p, Comparator c); Basic_version(const std::string&, Parser, Comparator);
/// Construct Basic_version by copying data from another one. /// Construct Basic_version by copying data from another one.
Basic_version(const Basic_version&); Basic_version(const Basic_version&);
@@ -129,15 +136,15 @@ namespace version {
/// Copy version data from another Basic_version to this one. /// Copy version data from another Basic_version to this one.
Basic_version& operator=(const Basic_version&); Basic_version& operator=(const Basic_version&);
const int major() const; const int major() const; ///< Get major version.
const int minor() const; const int minor() const; ///< Get minor version.
const int patch() const; const int patch() const; ///< Get patch version.
const std::string prerelease() const; const std::string prerelease() const; ///< Get prerelease version string.
const std::string build() const; const std::string build() const; ///< Get build version string.
friend bool operator< <>(const Basic_version& l, const Basic_version& r); friend bool operator< <>(const Basic_version&, const Basic_version&);
friend bool operator== <>(const Basic_version& l, const Basic_version& r); friend bool operator== <>(const Basic_version&, const Basic_version&);
friend std::ostream& operator<< <>(std::ostream& os, const Basic_version& v); friend std::ostream& operator<< <>(std::ostream&s, const Basic_version&);
private: private:
Parser parser_; Parser parser_;
+44 -40
View File
@@ -33,73 +33,77 @@ namespace version {
/// Utility function to splice all vector elements to output stream, using designated separator /// Utility function to splice all vector elements to output stream, using designated separator
/// between elements and function object for getting values from vector elements. /// between elements and function object for getting values from vector elements.
template<typename T, typename F> template<typename T, typename F>
std::ostream& splice(std::ostream& os, const std::vector<T>& v, const std::string& sep, F read) { std::ostream& splice(std::ostream& os, const std::vector<T>& vec, const std::string& sep, F read) {
if (!v.empty()) { if (!vec.empty()) {
for (auto it = v.cbegin(); it < v.cend() - 1; ++it) { for (auto it = vec.cbegin(); it < vec.cend() - 1; ++it) {
os << read(*it) << sep; os << read(*it) << sep;
} }
os << read(*v.crbegin()); os << read(*vec.crbegin());
} }
return os; return os;
} }
} }
template<typename P, typename C> template<typename Parser, typename Comparator>
Basic_version<P, C>::Basic_version(P p, C c) Basic_version<Parser, Comparator>::Basic_version(Parser p, Comparator c)
: parser_(p), comparator_(c), ver_(parser_.parse("0.0.0")) {}; : parser_(p), comparator_(c), ver_(parser_.parse("0.0.0")) {};
template<typename P, typename C> template<typename Parser, typename Comparator>
Basic_version<P, C>::Basic_version(const std::string& v, P p, C c) Basic_version<Parser, Comparator>::Basic_version(const std::string& v, Parser p, Comparator c)
: parser_(p), comparator_(c), ver_(parser_.parse(v)) {}; : parser_(p), comparator_(c), ver_(parser_.parse(v)) {};
template<typename P, typename C> template<typename Parser, typename Comparator>
Basic_version<P, C>::Basic_version(const Basic_version<P, C>&) = default; Basic_version<Parser, Comparator>::Basic_version(const Basic_version<Parser, Comparator>&) = default;
template<typename P, typename C> template<typename Parser, typename Comparator>
Basic_version<P, C>& Basic_version<P, C>::operator=(const Basic_version<P, C>&) = default; Basic_version<Parser, Comparator>& Basic_version<Parser, Comparator>::operator=(
const Basic_version<Parser, Comparator>&) = default;
template<typename P, typename C> template<typename Parser, typename Comparator>
const int Basic_version<P, C>::major() const { const int Basic_version<Parser, Comparator>::major() const {
return ver_.major; return ver_.major;
} }
template<typename P, typename C> template<typename Parser, typename Comparator>
const int Basic_version<P, C>::minor() const { const int Basic_version<Parser, Comparator>::minor() const {
return ver_.minor; return ver_.minor;
} }
template<typename P, typename C> template<typename Parser, typename Comparator>
const int Basic_version<P, C>::patch() const { const int Basic_version<Parser, Comparator>::patch() const {
return ver_.patch; return ver_.patch;
} }
template<typename P, typename C> template<typename Parser, typename Comparator>
const std::string Basic_version<P, C>::prerelease() const { const std::string Basic_version<Parser, Comparator>::prerelease() const {
std::stringstream ss; std::stringstream ss;
splice(ss, ver_.prerelease_ids, ".", [](const auto& id) { return id.first;}); splice(ss, ver_.prerelease_ids, ".", [](const auto& id) { return id.first;});
return ss.str(); return ss.str();
} }
template<typename P, typename C> template<typename Parser, typename Comparator>
const std::string Basic_version<P, C>::build() const { const std::string Basic_version<Parser, Comparator>::build() const {
std::stringstream ss; std::stringstream ss;
splice(ss, ver_.build_ids, ".", [](const auto& id) { return id;}); splice(ss, ver_.build_ids, ".", [](const auto& id) { return id;});
return ss.str(); return ss.str();
} }
template<typename P, typename C> template<typename Parser, typename Comparator>
bool operator<(const Basic_version<P, C>& l, const Basic_version<P, C>& r) { bool operator<(const Basic_version<Parser, Comparator>& l,
const Basic_version<Parser, Comparator>& r) {
return l.comparator_.compare(l.ver_, r.ver_) == -1; return l.comparator_.compare(l.ver_, r.ver_) == -1;
} }
template<typename P, typename C> template<typename Parser, typename Comparator>
bool operator==(const version::Basic_version<P, C>& l, const version::Basic_version<P, C>& r) { bool operator==(const Basic_version<Parser, Comparator>& l,
const Basic_version<Parser, Comparator>& r) {
return l.comparator_.compare(l.ver_, r.ver_) == 0; return l.comparator_.compare(l.ver_, r.ver_) == 0;
} }
template<typename P, typename C> template<typename Parser, typename Comparator>
std::ostream& operator<<(std::ostream& os, const version::Basic_version<P, C>& v) { std::ostream& operator<<(std::ostream& os,
const Basic_version<Parser, Comparator>& v) {
os << v.ver_.major << "." << v.ver_.minor << "." << v.ver_.patch; os << v.ver_.major << "." << v.ver_.minor << "." << v.ver_.patch;
std::string prl = v.prerelease(); std::string prl = v.prerelease();
if (!prl.empty()) { if (!prl.empty()) {
@@ -112,27 +116,27 @@ namespace version {
return os; return os;
} }
/// Compare if two version objects are different. template<typename Parser, typename Comparator>
template<typename P, typename C> inline bool operator!=(const Basic_version<Parser, Comparator>& l,
inline bool operator!=(const version::Basic_version<P, C>& l, const version::Basic_version<P, C>& r) { const Basic_version<Parser, Comparator>& r) {
return !(l == r); return !(l == r);
} }
/// Compare if left version object is greater than the right. template<typename Parser, typename Comparator>
template<typename P, typename C> inline bool operator>(const Basic_version<Parser, Comparator>& l,
inline bool operator>(const version::Basic_version<P, C>& l, const version::Basic_version<P, C>& r) { const Basic_version<Parser, Comparator>& r) {
return r < l; return r < l;
} }
/// Compare if left version object is greater than or equal the right. template<typename Parser, typename Comparator>
template<typename P, typename C> inline bool operator>=(const Basic_version<Parser, Comparator>& l,
inline bool operator>=(const version::Basic_version<P, C>& l, const version::Basic_version<P, C>& r) { const Basic_version<Parser, Comparator>& r) {
return !(l < r); return !(l < r);
} }
/// Compare if left version object is less than or equal the right. template<typename Parser, typename Comparator>
template<typename P, typename C> inline bool operator<=(const Basic_version<Parser, Comparator>& l,
inline bool operator<=(const version::Basic_version<P, C>& l, const version::Basic_version<P, C>& r) { const Basic_version<Parser, Comparator>& r) {
return !(l > r); return !(l > r);
} }
} }
+51 -53
View File
@@ -25,73 +25,71 @@ SOFTWARE.
#include <algorithm> #include <algorithm>
#include <functional> #include <functional>
#include <map> #include <map>
#include "common/semver200.h" #include "semver200.h"
using namespace std; using namespace std;
namespace { namespace version {
using namespace version; namespace {
// Compare normal version identifiers. // Compare normal version identifiers.
int compare_normal(const Version_data& l, const Version_data& r) { int compare_normal(const Version_data& l, const Version_data& r) {
if (l.major > r.major) return 1; if (l.major > r.major) return 1;
if (l.major < r.major) return -1; if (l.major < r.major) return -1;
if (l.minor > r.minor) return 1; if (l.minor > r.minor) return 1;
if (l.minor < r.minor) return -1; if (l.minor < r.minor) return -1;
if (l.patch > r.patch) return 1; if (l.patch > r.patch) return 1;
if (l.patch < r.patch) return -1; if (l.patch < r.patch) return -1;
return 0; return 0;
} }
// Compare alphanumeric prerelease identifiers. // Compare alphanumeric prerelease identifiers.
inline int cmp_alnum_prerel_ids(const string& l, const string& r) { inline int cmp_alnum_prerel_ids(const string& l, const string& r) {
auto cmp = l.compare(r); auto cmp = l.compare(r);
if (cmp == 0) { if (cmp == 0) {
return cmp; return cmp;
} else { } else {
return cmp > 0 ? 1 : -1; return cmp > 0 ? 1 : -1;
}
}
// Compare numeric prerelease identifiers.
inline int cmp_num_prerel_ids(const string& l, const string& r) {
long long li = stoll(l);
long long ri = stoll(r);
if (li == ri) return 0;
return li > ri ? 1 : -1;
}
using Prerel_type_pair = pair<Id_type, Id_type>;
using Prerel_id_comparator = function<int(const string&, const string&)>;
const map<Prerel_type_pair, Prerel_id_comparator> comparators = {
{ { Id_type::alnum, Id_type::alnum }, cmp_alnum_prerel_ids },
{ { Id_type::alnum, Id_type::num }, [](const string&, const string&) {return 1;} },
{ { Id_type::num, Id_type::alnum }, [](const string&, const string&) {return -1;} },
{ { Id_type::num, Id_type::num }, cmp_num_prerel_ids }
};
// Compare prerelease identifiers based on their types.
int compare_prerel_identifiers(const Prerelease_identifier& l, const Prerelease_identifier& r) {
auto cmp = comparators.at({ l.second, r.second });
return cmp(l.first, r.first);
}
inline int cmp_rel_prerel(const Prerelease_identifiers& l, const Prerelease_identifiers& r) {
if (l.empty() && !r.empty()) return 1;
if (r.empty() && !l.empty()) return -1;
return 0;
} }
} }
// Compare numeric prerelease identifiers.
inline int cmp_num_prerel_ids(const string& l, const string& r) {
long long li = stoll(l);
long long ri = stoll(r);
if (li == ri) return 0;
return li > ri ? 1 : -1;
}
using Prerel_types = pair<Identifier_type, Identifier_type>;
using Prerel_id_comparator = function<int(const string&, const string&)>;
const map<Prerel_types, Prerel_id_comparator> comparators = {
{ { Identifier_type::alnum, Identifier_type::alnum }, cmp_alnum_prerel_ids },
{ { Identifier_type::alnum, Identifier_type::num }, [](const string&, const string&) {return 1;} },
{ { Identifier_type::num, Identifier_type::alnum }, [](const string&, const string&) {return -1;} },
{ { Identifier_type::num, Identifier_type::num }, cmp_num_prerel_ids }
};
// Compare prerelease identifiers based on their types.
int compare_prerel_identifiers(const Prerelease_identifier& l, const Prerelease_identifier& r) {
auto cmp = comparators.at({ l.second, r.second });
return cmp(l.first, r.first);
}
inline int cmp_rel_prerel(const Prerelease_identifiers& l, const Prerelease_identifiers& r) {
if (l.empty() && !r.empty()) return 1;
if (r.empty() && !l.empty()) return -1;
return 0;
}
}
namespace version {
int Semver200_comparator::compare(const Version_data& l, const Version_data& r) const { int Semver200_comparator::compare(const Version_data& l, const Version_data& r) const {
// Compare normal version components. // Compare normal version components.
int cmp = compare_normal(l, r); int cmp = compare_normal(l, r);
if (cmp != 0) return cmp; if (cmp != 0) return cmp;
// Compare if one version is release and the other prerelease; release is always higher than prerelease. // Compare if one version is release and the other prerelease - release is always higher.
cmp = cmp_rel_prerel(l.prerelease_ids, r.prerelease_ids); cmp = cmp_rel_prerel(l.prerelease_ids, r.prerelease_ids);
if (cmp != 0) return cmp; if (cmp != 0) return cmp;
+102 -97
View File
@@ -24,108 +24,113 @@ SOFTWARE.
#include <functional> #include <functional>
#include <map> #include <map>
#include "common/semver200.h" #include "semver200.h"
#ifdef _MSC_VER
// disable symbol name too long warning
#pragma warning(disable:4503)
#endif
using namespace std; using namespace std;
namespace {
enum class Parser_state {
major, minor, patch, prerelease, build
};
using Validator = function<void(const string&, const char)>;
using State_transition_hook = function<void(string&)>;
/// State transition is described by a character that triggers it, a state to transition to and
/// optional hook to be invoked on transition.
using Transition = tuple<const char, Parser_state, State_transition_hook>;
using Transitions = vector<Transition>;
using State = tuple<Transitions, string&, Validator>;
using State_machine = map<Parser_state, State>;
// Ranges of characters allowed in prerelease and build identifiers.
const vector<pair<char, char>> allowed_prerel_id_chars = {
{ '0', '9' },{ 'A','Z' },{ 'a','z' },{ '-','-' }
};
inline Transition mkx(const char c, Parser_state p, State_transition_hook pth) {
return make_tuple(c, p, pth);
}
/// Advance parser state machine by a single step.
/**
Perform single step of parser state machine: if character matches one from transition tables -
trigger transition to next state; otherwise, validate if current token is in legal state
(throw Parse_error if not) and then add character to current token; State transition includes
preparing various vars for next state and invoking state transition hook (if specified) which is
where whole tokens are validated.
*/
inline void process_char(const char c, Parser_state& cstate, Parser_state& pstate,
const Transitions& transitions, string& target, Validator validate) {
for (const auto& transition : transitions) {
if (c == get<0>(transition)) {
if (get<2>(transition)) get<2>(transition)(target);
pstate = cstate;
cstate = get<1>(transition);
return;
}
}
validate(target, c);
target.push_back(c);
}
/// Validate normal (major, minor, patch) version components.
inline void normal_version_validator(const string& tgt, const char c) {
if (c < '0' || c > '9') throw version::Parse_error("invalid character encountered: " + string(1, c));
if (tgt.compare(0, 1, "0") == 0) throw version::Parse_error("leading 0 not allowed");
}
/// Validate that prerelease and build version identifiers are comprised of allowed chars only.
inline void prerelease_version_validator(const string&, const char c) {
bool res = false;
for (const auto& r : allowed_prerel_id_chars) {
res |= (c >= r.first && c <= r.second);
}
if (!res)
throw version::Parse_error("invalid character encountered: " + string(1, c));
}
inline bool is_identifier_numeric(const string& id) {
return id.find_first_not_of("0123456789") == string::npos;
}
inline bool check_for_leading_0(const string& str) {
return str.length() > 1 && str[0] == '0';
}
/// Validate every individual prerelease identifier, determine it's type and add it to collection.
void prerelease_hook_impl(string& id, version::Prerelease_identifiers& prerelease) {
using namespace version;
if (id.empty()) throw Parse_error("version identifier cannot be empty");
Identifier_type t = Identifier_type::alnum;
if (is_identifier_numeric(id)) {
t = Identifier_type::num;
if (check_for_leading_0(id)) {
throw Parse_error("numeric identifiers cannot have leading 0");
}
}
prerelease.push_back(Prerelease_identifier(id, t));
id.clear();
}
/// Validate every individual build identifier and add it to collection.
void build_hook_impl(string& id, Parser_state& pstate, version::Build_identifiers& build,
std::string& prerelease_id, version::Prerelease_identifiers& prerelease) {
// process last token left from parsing prerelease data
if (pstate == Parser_state::prerelease) prerelease_hook_impl(prerelease_id, prerelease);
if (id.empty()) throw version::Parse_error("version identifier cannot be empty");
build.push_back(id);
id.clear();
}
}
namespace version { namespace version {
namespace {
enum class Parser_state {
major, minor, patch, prerelease, build
};
using Validator = function<void(const string&, const char)>;
using State_transition_hook = function<void(string&)>;
/// State transition is described by a character that triggers it, a state to transition to and
/// optional hook to be invoked on transition.
using Transition = tuple<const char, Parser_state, State_transition_hook>;
using Transitions = vector<Transition>;
using State = tuple<Transitions, string&, Validator>;
using State_machine = map<Parser_state, State>;
// Ranges of characters allowed in prerelease and build identifiers.
const vector<pair<char, char>> allowed_prerel_id_chars = {
{ '0', '9' },{ 'A','Z' },{ 'a','z' },{ '-','-' }
};
inline Transition mkx(const char c, Parser_state p, State_transition_hook pth) {
return make_tuple(c, p, pth);
}
/// Advance parser state machine by a single step.
/**
Perform single step of parser state machine: if character matches one from transition tables -
trigger transition to next state; otherwise, validate if current token is in legal state
(throw Parse_error if not) and then add character to current token; State transition includes
preparing various vars for next state and invoking state transition hook (if specified) which is
where whole tokens are validated.
*/
inline void process_char(const char c, Parser_state& cstate, Parser_state& pstate,
const Transitions& transitions, string& target, Validator validate) {
for (const auto& transition : transitions) {
if (c == get<0>(transition)) {
if (get<2>(transition)) get<2>(transition)(target);
pstate = cstate;
cstate = get<1>(transition);
return;
}
}
validate(target, c);
target.push_back(c);
}
/// Validate normal (major, minor, patch) version components.
inline void normal_version_validator(const string& tgt, const char c) {
if (c < '0' || c > '9') throw Parse_error("invalid character encountered: " + string(1, c));
if (tgt.compare(0, 1, "0") == 0) throw Parse_error("leading 0 not allowed");
}
/// Validate that prerelease and build version identifiers are comprised of allowed chars only.
inline void prerelease_version_validator(const string&, const char c) {
bool res = false;
for (const auto& r : allowed_prerel_id_chars) {
res |= (c >= r.first && c <= r.second);
}
if (!res)
throw Parse_error("invalid character encountered: " + string(1, c));
}
inline bool is_identifier_numeric(const string& id) {
return id.find_first_not_of("0123456789") == string::npos;
}
inline bool check_for_leading_0(const string& str) {
return str.length() > 1 && str[0] == '0';
}
/// Validate every individual prerelease identifier, determine it's type and add it to collection.
void prerelease_hook_impl(string& id, Prerelease_identifiers& prerelease) {
using namespace version;
if (id.empty()) throw Parse_error("version identifier cannot be empty");
Id_type t = Id_type::alnum;
if (is_identifier_numeric(id)) {
t = Id_type::num;
if (check_for_leading_0(id)) {
throw Parse_error("numeric identifiers cannot have leading 0");
}
}
prerelease.push_back(Prerelease_identifier(id, t));
id.clear();
}
/// Validate every individual build identifier and add it to collection.
void build_hook_impl(string& id, Parser_state& pstate, Build_identifiers& build,
std::string& prerelease_id, Prerelease_identifiers& prerelease) {
// process last token left from parsing prerelease data
if (pstate == Parser_state::prerelease) prerelease_hook_impl(prerelease_id, prerelease);
if (id.empty()) throw Parse_error("version identifier cannot be empty");
build.push_back(id);
id.clear();
}
}
/// Parse semver 2.0.0-compatible string to Version_data structure. /// Parse semver 2.0.0-compatible string to Version_data structure.
/** /**
Version text parser is implemented as a state machine. In each step one successive character from version Version text parser is implemented as a state machine. In each step one successive character from version
+2 -2
View File
@@ -32,8 +32,8 @@ version::Semver200_parser p;
const version::Prerelease_identifiers no_rel_ids; const version::Prerelease_identifiers no_rel_ids;
const version::Build_identifiers no_build_ids; const version::Build_identifiers no_build_ids;
#define N Identifier_type::num #define N Id_type::num
#define A Identifier_type::alnum #define A Id_type::alnum
#define BOOST_PATCH BOOST_VERSION % 100 #define BOOST_PATCH BOOST_VERSION % 100
#define BOOST_MINOR BOOST_VERSION / 100 % 1000 #define BOOST_MINOR BOOST_VERSION / 100 % 1000