changeset 19216:ac8a49be686f

compare_versions.m: Overhaul function. 20% speed improvement. Clearer error messages. Improved BIST. * compare_versions.m: Replace slow function calls to ismember with direct operator tests. Use 'end' keyword rather than length(vector) for clarity. Replace str2num with str2double for speed and safety. Reference variable names from documentation in error messages. Add expected error message to %!error tests.
author Rik <rik@octave.org>
date Sun, 28 Sep 2014 09:40:19 -0700
parents 751d4a76c221
children 666c4e0aca1e
files scripts/miscellaneous/compare_versions.m
diffstat 1 files changed, 60 insertions(+), 69 deletions(-) [+]
line wrap: on
line diff
--- a/scripts/miscellaneous/compare_versions.m	Sat Sep 27 22:39:24 2014 -0700
+++ b/scripts/miscellaneous/compare_versions.m	Sun Sep 28 09:40:19 2014 -0700
@@ -80,87 +80,68 @@
 
   ## Make sure that the version numbers are valid.
   if (! (ischar (v1) && ischar (v2)))
-    error ("compare_versions: both version numbers must be strings");
+    error ("compare_versions: version numbers V1 and V2 must be strings");
   elseif (rows (v1) != 1 || rows (v2) != 1)
-    error ("compare_versions: version numbers must be a single row");
+    error ("compare_versions: version numbers V1 and V2 must be a single row");
   endif
 
   ## check and make sure that the operator is valid
   if (! ischar (operator))
-    error ("compare_versions: OPERATOR must be a character string");
+    error ("compare_versions: OPERATOR must be a string");
   elseif (numel (operator) > 2)
     error ("compare_versions: OPERATOR must be 1 or 2 characters long");
   endif
 
-  ## trim off any character data that is not part of a normal version
-  ## number
-  numbers = "0123456789.";
+  ## trim off any character data that is not part of a normal version number
+  v1firstchar = find (! (isdigit (v1) | v1 == "."), 1);
+  v2firstchar = find (! (isdigit (v2) | v2 == "."), 1);
 
-  v1firstchar = find (! ismember (v1, numbers), 1);
-  v2firstchar = find (! ismember (v2, numbers), 1);
-  if (! isempty (v1firstchar))
-    v1c = v1(v1firstchar:length (v1));
-    v1nochar = v1(1:v1firstchar-1);
-  else
+  if (isempty (v1firstchar))
     v1c = "";
     v1nochar = v1;
+  else
+    v1c = v1(v1firstchar:end);
+    v1nochar = v1(1:v1firstchar-1);
   endif
-  if (! isempty (v2firstchar))
-    v2c = v2(v2firstchar:length (v2));
-    v2nochar = v2(1:v2firstchar-1);
-  else
+  if (isempty (v2firstchar))
     v2c = "";
     v2nochar = v2;
-  endif
-
-  v1n = str2num (char (ostrsplit (v1nochar, ".")));
-  v2n = str2num (char (ostrsplit (v2nochar, ".")));
-  if ((isempty (v1n) && isempty (v1c)) || (isempty (v2n) && isempty (v2c)))
-    error ("compare_versions: given version strings are not valid: %s %s",
-           v1, v2);
+  else
+    v2c = v2(v2firstchar:end);
+    v2nochar = v2(1:v2firstchar-1);
   endif
 
-  ## Assume that any additional elements would be 0 if one is longer
-  ## than the other.
-  maxnumlen = max ([length(v1n) length(v2n)]);
-  if (length (v1n) < maxnumlen)
-    v1n(length(v1n)+1:maxnumlen) = 0;
+  v1n = str2double (ostrsplit (v1nochar, ".")');
+  if (isnan (v1n))
+    v1n = [];
   endif
-  if (length (v2n) < maxnumlen)
-    v2n(length(v2n)+1:maxnumlen) = 0;
+  v2n = str2double (ostrsplit (v2nochar, ".")');
+  if (isnan (v2n))
+    v2n = [];
   endif
 
-  ## Assume that any additional character elements would be 0 if one is
-  ## longer than the other.
+  if (isempty (v1n) && isempty (v1c))
+    error ("compare_versions: version string V1 is not valid: %s", v1);
+  elseif  (isempty (v2n) && isempty (v2c))
+    error ("compare_versions: version string V2 is not valid: %s", v2);
+  endif
+
+  ## Assume any additional elements would be 0 if one is longer than the other.
+  maxnumlen = max ([length(v1n) length(v2n)]);
+  v1n(end+1:maxnumlen) = 0;
+  v2n(end+1:maxnumlen) = 0;
+
+  ## Assume any additional character elements would be 0,
+  ## if one is longer than the other.
   maxcharlen = max ([length(v1c), length(v2c)]);
-  if (length (v1c) < maxcharlen)
-    v1c(length(v1c)+1:maxcharlen) = "\0";
-  endif
-  if (length (v2c) < maxcharlen)
-    v2c(length(v2c)+1:maxcharlen) = "\0";
-  endif
+  v1c(end+1:maxcharlen) = "\0";
+  v2c(end+1:maxcharlen) = "\0";
 
   ## Determine the operator.
-  if (any (ismember (operator, "=")))
-    equal_op = true;
-  else
-    equal_op = false;
-  endif
-  if (any (ismember (operator, "~!")))
-    not_op = true;
-  else
-    not_op = false;
-  endif
-  if (any (ismember (operator, "<")))
-    lt_op = true;
-  else
-    lt_op = false;
-  endif
-  if (any (ismember (operator, ">")))
-    gt_op = true;
-  else
-    gt_op = false;
-  endif
+  equal_op = any (operator == "=");
+  not_op = any (operator == "!" | operator == "~");
+  lt_op = any (operator == "<");
+  gt_op = any (operator == ">");
 
   ## Make sure that we don't have conflicting operators.
   if (gt_op && lt_op)
@@ -168,9 +149,9 @@
   elseif ((gt_op || lt_op) && not_op)
     error ("compare_versions: OPERATOR cannot contain not and greater than or less than symbols");
   elseif (strcmp (operator, "="))
-    error ("compare_versions: equality OPERATOR is \"==\", not \"=\"");
+    error ('compare_versions: equality OPERATOR is "==", not "="');
   elseif (! (equal_op || not_op || lt_op || gt_op))
-    error ("compare_versions: No valid OPERATOR specified");
+    error ("compare_versions: no valid OPERATOR specified");
   endif
 
   ## Compare the versions (making sure that they're the same shape)
@@ -180,7 +161,7 @@
     ## so that we only need to check for the output being greater than 1
     vcmp = -vcmp;
   endif
-  firstdiff = find (vcmp != 0, 1);
+  firstdiff = find (vcmp, 1);
 
   if (isempty (firstdiff))
     ## They're equal.
@@ -242,12 +223,22 @@
 %!assert (compare_versions ("0.1", "0.1", "~="), false)
 
 %% Test input validation
-%!error (compare_versions (0.1, "0.1", "=="))
-%!error (compare_versions ("0.1", 0.1, "=="))
-%!error (compare_versions (["0";".";"1"], "0.1", "=="))
-%!error (compare_versions ("0.1", ["0";".";"1"], "=="))
-%!error (compare_versions ("0.1", "0.1", "<>"))
-%!error (compare_versions ("0.1", "0.1", "!>"))
-%!error (compare_versions ("0.1", "0.1", "="))
-%!error (compare_versions ("0.1", "0.1", "aa"))
+%!error compare_versions ()
+%!error compare_versions (1)
+%!error compare_versions (1,2)
+%!error compare_versions (1,2,3,4)
+%!error <V1 and V2 must be strings> compare_versions (0.1, "0.1", "==")
+%!error <V1 and V2 must be strings> compare_versions ("0.1", 0.1, "==")
+%!error <V1 and V2 must be a single row> compare_versions (["0";".";"1"], "0.1", "==")
+%!error <V1 and V2 must be a single row> compare_versions ("0.1", ["0";".";"1"], "==")
+%!error <OPERATOR must be a string> compare_versions ("0.1", "0.1", 1)
+%!error <OPERATOR must be 1 or 2> compare_versions ("0.1", "0.1", "==>")
+%!error <V1 is not valid> compare_versions (".", "0.1", "==")
+%!error <V2 is not valid> compare_versions ("0.1", ".", "==")
 
+%!error <cannot contain both greater and less than> compare_versions ("0.1", "0.1", "<>")
+%!error <cannot contain not and greater than> compare_versions ("0.1", "0.1", "!>")
+%!error <cannot contain not and greater than> compare_versions ("0.1", "0.1", "!<")
+%!error <equality OPERATOR is "=="> compare_versions ("0.1", "0.1", "=")
+%!error <no valid OPERATOR> compare_versions ("0.1", "0.1", "aa")
+