Wie man Versionsnummern vergleichen kann

SemVer as an Integer

·

2 min read

Wie man Versionsnummern vergleichen kann

Eine beliebte Methode Software zu versionieren, ist Semantic Versioning. Hierbei wird häufig eine Versionsnummer als eine Zusammensetzung von drei Integers, die mit Punkten getrennt werden, angegeben, beispielsweise: 8.3.47. Hierbei ist 8 die sogenannte Major Versionsnummer, 3 die sogenannte Minor Versionsnummer und 47 die sogenannte Patch Versionsnummer.

Wenn man diese Nummern vergleichen möchte, kann das ziemlich mühselig werden, wenn man das anhand des SemVer Strings machen möchte. Doch es gibt auch eine andere Möglichkeit. Man kann den SemVer String auch in einen Integer überführen und Integers lassen sich ziemlich einfach vergleichen.

Angenommen wir speichern die Versionsnummer statisch als 24-Bit Integer und geben jeweils ein Oktett für Major, Minor und Patch für das Speichern zur Verfügung. Dann kann jedes Oktett 2^8 = 256 Werte darstellen. Das heißt in Summe könnte man damit über 16 Millionen Versionsnummern darstellen. Eine Einschränkung wäre, dass man allerdings als höchsten Wert des Oktetts nur 255 speichern könnte, das bedeutet nach der Version 0.2.255 käme nicht die 0.2.256, sondern die 0.3.0. Das ist ein Kompromiss, den man durchaus eingehen kann.

Das Ganze lässt sich auch erweitern auf beispielsweise 48-Bit und jedes Versionslevel hätte dann 16-Bit zur Verfügung und könnte einen noch größeren Wert annehmen. Oder aber man überlegt sich, dass die Major Versionsnummer in absehbarer Zeit gar nicht so hoch werden wird, die Patch Versionsnummer hingegen schon. Dann kann man die 24 Bit auch ungleichmäßig aufteilen und der Major Versionsnummer beispielsweise 5 Bit zuweisen, der Minor Versionsnummer weiterhin 8 Bit und hat für die Patch Versionsnummer noch 13 Bit übrig. Damit kann die Patch Versionsnummer als höchsten Wert nun immerhin 8192 annehmen, die Major Versionsnummer hingegen nur noch 32. Bei mancher Software würde es da nun schon eng werden, aber dann kann man ja immer noch erweitern.

Doch wie kann man denn nun einen SemVer String in einen Integer überführen? Dafür benötigt man eigentlich nur ein paar Bit-Operationen. Ich zeige es am besten an einem Beispiel. Nehmen wir an, wir wollen 3.15.92 als 24-Bit Integer speichern und jedes Oktett hat 8 Bit zur Verfügung.

def semver_to_int(semver):
    octets = semver.split('.')
    return int(octets[0]) << 16 | int(octets[1]) << 8 | int(octets[2])

Rechnen wir also 3 << 16 | 15 << 8 | 92 erhalten wir 200540. Wandeln wir dann noch die Version 4.0.0 in einen Integer um, erhalten wir 262144, was wiederum um einiges größer ist als 200540. Somit lassen sich SemVer versionierte Softwareversionen sehr einfach miteinander vergleichen.

Falls man relativ fit darin ist, Zahlen in Hexadezimal umzurechnen, ist es auch möglich, diese schnell im Kopf zu berechnen. Im obigen Beispiel 3.15.92 wäre das also 0x030f5c und 4.0.0 wäre dann 0x040000. Diese lassen sich natürlich genauso schnell vergleichen wie ihre dezimalen Darstellungen.