210 lines
7.0 KiB
C++
210 lines
7.0 KiB
C++
/*
|
|
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
|
* its licensors.
|
|
*
|
|
* For complete copyright and license terms please see the LICENSE at the root of this
|
|
* distribution (the "License"). All use of this software is governed by the License,
|
|
* or, if provided, by the license below or the license accompanying this file. Do not
|
|
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
*
|
|
*/
|
|
#pragma once
|
|
|
|
#include <AzCore/Outcome/Outcome.h>
|
|
#include <AzCore/std/numeric.h>
|
|
#include <AzCore/std/string/string.h>
|
|
#include <AzCore/std/string/conversions.h>
|
|
#include <AzCore/std/hash.h>
|
|
#include <AzCore/std/algorithm.h>
|
|
#include <AzCore/std/containers/array.h>
|
|
|
|
#include <initializer_list>
|
|
#include <sstream>
|
|
|
|
namespace AzFramework
|
|
{
|
|
#define VERSION_SEPARATOR_CHAR '.'
|
|
#define VERSION_SEPARATOR_STR "."
|
|
|
|
template <size_t N>
|
|
struct Version
|
|
{
|
|
/// The type each component is stored as.
|
|
using ComponentType = AZ::u64;
|
|
|
|
/// Store size of Version object
|
|
enum
|
|
{
|
|
parts_count = N
|
|
};
|
|
|
|
Version()
|
|
{
|
|
static_assert(N > 0, "Size for Version must be more than 0.");
|
|
m_parts.fill(0);
|
|
}
|
|
|
|
Version(const Version& other)
|
|
: m_parts(other.m_parts)
|
|
{
|
|
}
|
|
|
|
Version(const AZStd::array<ComponentType, N>& parts)
|
|
: m_parts(parts) { }
|
|
|
|
Version(const std::initializer_list<ComponentType>& values)
|
|
{
|
|
AZ_Assert(values.size() == N,
|
|
"Initializer size does not matches Version size. "
|
|
"Expected: %u, got: %u",
|
|
N, values.size());
|
|
|
|
AZStd::transform(values.begin(), values.end(), m_parts.begin(), [](const ComponentType& c) { return c; });
|
|
}
|
|
|
|
/**
|
|
* Parses a version from a string in the format "[part].[part].[part] ...".
|
|
*
|
|
* \param[in] versionStr The string to parse for a version.
|
|
* \returns On success, the parsed Version; on failure, a message describing the error.
|
|
*/
|
|
static AZ::Outcome<Version, AZStd::string> ParseFromString(const AZStd::string& versionStr)
|
|
{
|
|
// there is 1 more part than there are dots in the string. (1.2.3 has 3 parts but 2 dots)
|
|
size_t partCount = AZStd::accumulate(versionStr.begin(), versionStr.end(), size_t(1),
|
|
[](size_t currentValue, const char elem) -> size_t
|
|
{
|
|
return currentValue + (elem == VERSION_SEPARATOR_CHAR ? 1 : 0);
|
|
});
|
|
if (N != partCount)
|
|
{
|
|
return AZ::Failure(AZStd::string::format(
|
|
"Failed to parse invalid version string \"%s\". "
|
|
"Number of parts in the string doesn't match the size. "
|
|
"Expected: %zu, got: %zu"
|
|
, versionStr.c_str(), N, partCount));
|
|
}
|
|
|
|
Version<N> result;
|
|
std::istringstream iss(versionStr.c_str());
|
|
for (int i = 0; i < partCount; ++i)
|
|
{
|
|
iss >> result.m_parts[i];
|
|
|
|
// remove the dot before the next iteration
|
|
char throwaway;
|
|
iss >> throwaway;
|
|
if (throwaway != VERSION_SEPARATOR_CHAR)
|
|
{
|
|
return AZ::Failure(AZStd::string::format(
|
|
"Failed to parse invalid version string \"%s\". "
|
|
"Unexpected separator character encountered. "
|
|
"Expected: \"%d\", got: \"%d\""
|
|
, versionStr.c_str(), VERSION_SEPARATOR_CHAR, throwaway));
|
|
}
|
|
}
|
|
|
|
if (!iss.eof())
|
|
{
|
|
return AZ::Failure(AZStd::string::format(
|
|
"Failed to parse invalid version string \"%s\". "
|
|
, versionStr.c_str()));
|
|
}
|
|
|
|
return AZ::Success(result);
|
|
}
|
|
|
|
/**
|
|
* Returns the version in string form.
|
|
*
|
|
* \returns The version as a string formatted as "[major].[minor].[patch]".
|
|
*/
|
|
AZStd::string ToString() const
|
|
{
|
|
std::stringstream ss;
|
|
const char* separator = "";
|
|
for (int i = 0; i < N; ++i)
|
|
{
|
|
ss << separator << m_parts[i];
|
|
separator = VERSION_SEPARATOR_STR;
|
|
}
|
|
|
|
return ss.str().c_str();
|
|
}
|
|
|
|
/**
|
|
* Compare two versions.
|
|
*
|
|
* Returns: 0 if a == b, <0 if a < b, and >0 if a > b.
|
|
*/
|
|
static int Compare(const Version& a, const Version& b)
|
|
{
|
|
for (int i = 0; i < N; ++i)
|
|
{
|
|
if (a.m_parts[i] != b.m_parts[i])
|
|
{
|
|
return static_cast<int>(a.m_parts[i]) - static_cast<int>(b.m_parts[i]);
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
* Check if current version is all zero-ed out
|
|
*
|
|
* Returns: True if the current version is all zero-ed out, else false
|
|
*/
|
|
bool IsZero() const
|
|
{
|
|
for (int i = 0; i < N; ++i)
|
|
{
|
|
if (m_parts[i] != 0)
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
AZStd::array<ComponentType, N> m_parts;
|
|
};
|
|
|
|
/**
|
|
* Represents a version conforming to the Semantic Versioning standard (http://semver.org/)
|
|
*/
|
|
struct SemanticVersion
|
|
: public Version<3>
|
|
{
|
|
SemanticVersion()
|
|
: Version<3>() { }
|
|
SemanticVersion(const Version<3>& other)
|
|
: Version<3>(other) { }
|
|
SemanticVersion(ComponentType major, ComponentType minor, ComponentType patch)
|
|
{
|
|
m_parts[0] = major;
|
|
m_parts[1] = minor;
|
|
m_parts[2] = patch;
|
|
}
|
|
|
|
ComponentType GetMajor() const { return m_parts[0]; }
|
|
ComponentType GetMinor() const { return m_parts[1]; }
|
|
ComponentType GetPatch() const { return m_parts[2]; }
|
|
};
|
|
|
|
template <size_t N>
|
|
inline bool operator< (const Version<N>& a, const Version<N>& b) { return Version<N>::Compare(a, b) < 0; }
|
|
template <size_t N>
|
|
inline bool operator> (const Version<N>& a, const Version<N>& b) { return Version<N>::Compare(a, b) > 0; }
|
|
template <size_t N>
|
|
inline bool operator<=(const Version<N>& a, const Version<N>& b) { return Version<N>::Compare(a, b) <= 0; }
|
|
template <size_t N>
|
|
inline bool operator>=(const Version<N>& a, const Version<N>& b) { return Version<N>::Compare(a, b) >= 0; }
|
|
template <size_t N>
|
|
inline bool operator==(const Version<N>& a, const Version<N>& b) { return Version<N>::Compare(a, b) == 0; }
|
|
template <size_t N>
|
|
inline bool operator!=(const Version<N>& a, const Version<N>& b) { return Version<N>::Compare(a, b) != 0; }
|
|
} // namespace AzFramework
|