Richard Osterloh / SemVer

Dependents:   BLE_Display

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers SemVer.h Source File

SemVer.h

Go to the documentation of this file.
00001 /**
00002  * @file
00003  * @date    30 March 2015
00004  * @author  Richard Osterloh <richardo@buddi.co.uk>
00005  */
00006 #pragma once
00007 
00008 #include <sstream>
00009 #include <string>
00010 
00011 /**
00012  * @class SemVer
00013  * @brief A basic implementation of semantic versioning
00014  */
00015 class SemVer {
00016 public:
00017 
00018     /**
00019      * SemVer constructor
00020      * @param version string to parse as a version
00021      */
00022     SemVer(const std::string& version)
00023     {
00024         m_version           = version;
00025         m_major             = 0;
00026         m_minor             = 0;
00027         m_patch             = 0;
00028     
00029         if (version.empty())
00030         {
00031             m_is_valid = false;
00032         }
00033         else
00034         {
00035             m_is_valid = true;
00036             parse();
00037         }
00038     }
00039 
00040     ~SemVer() {}
00041 
00042     /**
00043      * Get full version
00044      */
00045     const std::string& getVersion() const
00046     {
00047         return m_version;
00048     }
00049 
00050     /**
00051      * Get the major of the version
00052      */
00053     const int& getMajor() const
00054     {
00055         return m_major;
00056     }
00057 
00058     /**
00059      * Get the minor of the version
00060      */
00061     const int& getMinor() const
00062     {
00063         return m_minor;
00064     }
00065 
00066     /**
00067      * Get the patch of the version
00068      */
00069     const int& getPatch() const
00070     {
00071         return m_patch;
00072     }
00073 
00074     /**
00075      * Check if the version is valid
00076      */
00077     const bool& isValid() const
00078     {
00079         return m_is_valid;
00080     }
00081 
00082     int compare(SemVer& rgt)
00083     {
00084         if ((*this) == rgt)
00085         {
00086             return 0;
00087         }
00088     
00089         if ((*this) > rgt)
00090         {
00091             return 1;
00092         }
00093     
00094         return -1;
00095     }
00096 
00097     SemVer& operator= (SemVer& rgt)
00098     {
00099         if ((*this) != rgt)
00100         {
00101             this->m_version     = rgt.getVersion();
00102             this->m_major       = rgt.getMajor();
00103             this->m_minor       = rgt.getMinor();
00104             this->m_patch       = rgt.getPatch();
00105             this->m_is_valid    = rgt.isValid();
00106         }
00107     
00108         return *this;
00109     }
00110 
00111     friend bool operator== (SemVer &lft, SemVer &rgt)
00112     {
00113         return lft.getVersion().compare(rgt.getVersion()) == 0;
00114     }
00115 
00116     friend bool operator!= (SemVer &lft, SemVer &rgt)
00117     {
00118         return !(lft == rgt);
00119     }
00120 
00121     friend bool operator> (SemVer &lft, SemVer &rgt)
00122     {
00123         // Major
00124         if (lft.getMajor() < 0 && rgt.getMajor() >= 0)
00125         {
00126             return false;
00127         }
00128 
00129         if (lft.getMajor() >= 0 && rgt.getMajor() < 0)
00130         {
00131             return true;
00132         }
00133 
00134         if (lft.getMajor() > rgt.getMajor())
00135         {
00136             return true;
00137         }
00138 
00139         if (lft.getMajor() < rgt.getMajor())
00140         {
00141             return false;
00142         }
00143 
00144         // Minor
00145         if (lft.getMinor() < 0 && rgt.getMinor() >= 0)
00146         {
00147             return false;
00148         }
00149 
00150         if (lft.getMinor() >= 0 && rgt.getMinor() < 0)
00151         {
00152             return true;
00153         }
00154 
00155         if (lft.getMinor() > rgt.getMinor())
00156         {
00157             return true;
00158         }
00159 
00160         if (lft.getMinor() < rgt.getMinor())
00161         {
00162             return false;
00163         }
00164 
00165         // Patch
00166         if (lft.getPatch() < 0 && rgt.getPatch() >= 0)
00167         {
00168             return false;
00169         }
00170 
00171         if (lft.getPatch() >= 0 && rgt.getPatch() < 0)
00172         {
00173             return true;
00174         }
00175 
00176         if (lft.getPatch() > rgt.getPatch())
00177         {
00178             return true;
00179         }
00180 
00181         if (lft.getPatch() < rgt.getPatch())
00182         {
00183             return false;
00184         }
00185 
00186         return false;
00187     }
00188 
00189     friend bool operator>= (SemVer &lft, SemVer &rgt)
00190     {
00191         return (lft > rgt) || (lft == rgt);
00192     }
00193 
00194     friend bool operator< (SemVer &lft, SemVer &rgt)
00195     {
00196         return (rgt > lft);
00197     }
00198 
00199     friend bool operator<= (SemVer &lft, SemVer &rgt)
00200     {
00201         return (lft < rgt) || (lft == rgt);
00202     }
00203 
00204     friend std::ostream& operator<< (std::ostream& out, const SemVer& value)
00205     {
00206         out << value.getVersion();
00207 
00208         return out;
00209     }
00210 
00211 private:
00212     std::string m_version;
00213     int m_major;
00214     int m_minor;
00215     int m_patch;
00216     bool m_is_valid;
00217 
00218     enum m_type {
00219         TYPE_MAJOR,
00220         TYPE_MINOR,
00221         TYPE_PATCH,
00222     };
00223 
00224     void parse()
00225     {
00226         int type = TYPE_MAJOR;
00227 
00228         std::string major, minor, patch;
00229 
00230         for (std::size_t i = 0; i < m_version.length(); i++)
00231         {
00232             char chr = m_version[i];
00233             int chr_dec = chr;
00234 
00235             switch (type)
00236             {
00237                 case TYPE_MAJOR:
00238                     if (chr == '.')
00239                     {
00240                         type = TYPE_MINOR;
00241                         continue;
00242                     }
00243 
00244                     if (chr_dec < 48 || chr_dec > 57)
00245                     {
00246                         m_is_valid = false;
00247                     }
00248 
00249                     major += chr;
00250                     break;
00251 
00252                 case TYPE_MINOR:
00253                     if (chr == '.')
00254                     {
00255                         type = TYPE_PATCH;
00256                         continue;
00257                     }
00258         
00259                     if (chr_dec < 48 || chr_dec > 57)
00260                     {
00261                         m_is_valid = false;
00262                     }
00263         
00264                     minor += chr;
00265                     break;
00266         
00267                 case TYPE_PATCH:
00268                     if (chr_dec < 48 || chr_dec > 57)
00269                     {
00270                         m_is_valid = false;
00271                     }
00272         
00273                     patch += chr;
00274                     break;
00275 
00276             }
00277 
00278             if (m_is_valid)
00279             {
00280                 std::istringstream(major) >> m_major;
00281                 std::istringstream(minor) >> m_minor;
00282                 std::istringstream(patch) >> m_patch;
00283 
00284                 if (m_major == 0 && m_minor == 0 && m_patch == 0)
00285                 {
00286                     m_is_valid = false;
00287                 }
00288             }
00289         }
00290     }
00291 
00292 };