A basic semantic versioning library

Dependents:   BLE_Display

SemVer.h

Committer:
rosterloh84
Date:
2015-03-30
Revision:
0:91466b3b925e

File content as of revision 0:91466b3b925e:

/**
 * @file
 * @date    30 March 2015
 * @author  Richard Osterloh <richardo@buddi.co.uk>
 */
#pragma once

#include <sstream>
#include <string>

/**
 * @class SemVer
 * @brief A basic implementation of semantic versioning
 */
class SemVer {
public:

    /**
     * SemVer constructor
     * @param version string to parse as a version
     */
    SemVer(const std::string& version)
    {
        m_version           = version;
        m_major             = 0;
        m_minor             = 0;
        m_patch             = 0;
    
        if (version.empty())
        {
            m_is_valid = false;
        }
        else
        {
            m_is_valid = true;
            parse();
        }
    }

    ~SemVer() {}

    /**
     * Get full version
     */
    const std::string& getVersion() const
    {
        return m_version;
    }

    /**
     * Get the major of the version
     */
    const int& getMajor() const
    {
        return m_major;
    }

    /**
     * Get the minor of the version
     */
    const int& getMinor() const
    {
        return m_minor;
    }

    /**
     * Get the patch of the version
     */
    const int& getPatch() const
    {
        return m_patch;
    }

    /**
     * Check if the version is valid
     */
    const bool& isValid() const
    {
        return m_is_valid;
    }

    int compare(SemVer& rgt)
    {
        if ((*this) == rgt)
        {
            return 0;
        }
    
        if ((*this) > rgt)
        {
            return 1;
        }
    
        return -1;
    }

    SemVer& operator= (SemVer& rgt)
    {
        if ((*this) != rgt)
        {
            this->m_version     = rgt.getVersion();
            this->m_major       = rgt.getMajor();
            this->m_minor       = rgt.getMinor();
            this->m_patch       = rgt.getPatch();
            this->m_is_valid    = rgt.isValid();
        }
    
        return *this;
    }

    friend bool operator== (SemVer &lft, SemVer &rgt)
    {
        return lft.getVersion().compare(rgt.getVersion()) == 0;
    }

    friend bool operator!= (SemVer &lft, SemVer &rgt)
    {
        return !(lft == rgt);
    }

    friend bool operator> (SemVer &lft, SemVer &rgt)
    {
        // Major
        if (lft.getMajor() < 0 && rgt.getMajor() >= 0)
        {
            return false;
        }

        if (lft.getMajor() >= 0 && rgt.getMajor() < 0)
        {
            return true;
        }

        if (lft.getMajor() > rgt.getMajor())
        {
            return true;
        }

        if (lft.getMajor() < rgt.getMajor())
        {
            return false;
        }

        // Minor
        if (lft.getMinor() < 0 && rgt.getMinor() >= 0)
        {
            return false;
        }

        if (lft.getMinor() >= 0 && rgt.getMinor() < 0)
        {
            return true;
        }

        if (lft.getMinor() > rgt.getMinor())
        {
            return true;
        }

        if (lft.getMinor() < rgt.getMinor())
        {
            return false;
        }

        // Patch
        if (lft.getPatch() < 0 && rgt.getPatch() >= 0)
        {
            return false;
        }

        if (lft.getPatch() >= 0 && rgt.getPatch() < 0)
        {
            return true;
        }

        if (lft.getPatch() > rgt.getPatch())
        {
            return true;
        }

        if (lft.getPatch() < rgt.getPatch())
        {
            return false;
        }

        return false;
    }

    friend bool operator>= (SemVer &lft, SemVer &rgt)
    {
        return (lft > rgt) || (lft == rgt);
    }

    friend bool operator< (SemVer &lft, SemVer &rgt)
    {
        return (rgt > lft);
    }

    friend bool operator<= (SemVer &lft, SemVer &rgt)
    {
        return (lft < rgt) || (lft == rgt);
    }

    friend std::ostream& operator<< (std::ostream& out, const SemVer& value)
    {
        out << value.getVersion();

        return out;
    }

private:
    std::string m_version;
    int m_major;
    int m_minor;
    int m_patch;
    bool m_is_valid;

    enum m_type {
        TYPE_MAJOR,
        TYPE_MINOR,
        TYPE_PATCH,
    };

    void parse()
    {
        int type = TYPE_MAJOR;

        std::string major, minor, patch;

        for (std::size_t i = 0; i < m_version.length(); i++)
        {
            char chr = m_version[i];
            int chr_dec = chr;

            switch (type)
            {
                case TYPE_MAJOR:
                    if (chr == '.')
                    {
                        type = TYPE_MINOR;
                        continue;
                    }

                    if (chr_dec < 48 || chr_dec > 57)
                    {
                        m_is_valid = false;
                    }

                    major += chr;
                    break;

                case TYPE_MINOR:
                    if (chr == '.')
                    {
                        type = TYPE_PATCH;
                        continue;
                    }
        
                    if (chr_dec < 48 || chr_dec > 57)
                    {
                        m_is_valid = false;
                    }
        
                    minor += chr;
                    break;
        
                case TYPE_PATCH:
                    if (chr_dec < 48 || chr_dec > 57)
                    {
                        m_is_valid = false;
                    }
        
                    patch += chr;
                    break;

            }

            if (m_is_valid)
            {
                std::istringstream(major) >> m_major;
                std::istringstream(minor) >> m_minor;
                std::istringstream(patch) >> m_patch;

                if (m_major == 0 && m_minor == 0 && m_patch == 0)
                {
                    m_is_valid = false;
                }
            }
        }
    }

};