[REBOL] [tuple version build round] Tuple tricks, build numbers, and rounding
From: gregg::pointillistic::com at: 27-Apr-2007 10:13
Tuples are an interesting datatype. They aren't a series, but you can
use LENGTH?, PICK, POKE, and path notation, on them. Each segment is
limited to a value of 255 (one byte) and you are limited to 10
segments in a tuple. If you assign a value greater than 255 to a
segment, it becomes 255; a negative value becomes 0; no errors are
thrown in either case. This makes them somewhat flexible, yet somewhat
frustrating, but still very useful.
If you add two tuples, the result is the length of the longer of the
two, which can be very handy, as seen in the function below. Here, I
want to use a tuple as a version number, with the first three segments
being Major, Minor, and Revision; the last two being the build number.
Originally I was going to use just one segment for the build number,
but that limits you to 255 builds and, probably, an auto-incrementing
revision number, which I didn't want.
; Convert an integral build number--a build counter--to the last
; two segments of a five segment version tuple. A single segment
; only gives us 255 builds before stepping into the third segment,
; which is usually the revision. If you want to force the revision
; number to step every 255 builds, use a four segement tuple base.
set-build-num: func [tuple [tuple!] build [integer!]] [
tuple: tuple + 0.0.0.0.0 ; ensure we have five segments in our base tuple
tuple/4: round/down build / 255
tuple/5: remainder build 255
tuple
]
For display purposes, I don't necessarily want to show the full
version to the end user (though that may be preferred in some cases).
So, how do you go about keeping just part of a tuple? You can't use
COPY/PART, because they aren't series! values, and you can't just
assign 0 to the trailing segments, because they'll still show up. What
you need to do is build a new tuple, using just the parts you want.
This function does that, using my COLLECT function (available on
REBOL.org) to keep the body to one line.
round-tuple: func [
"Round a tuple to the given number of segments, truncating the rest."
tuple [tuple!]
scale [integer!] "The number of segments to keep"
][
to tuple! collect n [repeat i min scale length? tuple [n: tuple/:i]]
]
This logic differs from the default algorithm for ROUND; this
truncates, which is the same as ROUND/DOWN. I didn't like
TRUNCATE-TUPLE or CHOP-TUPLE as names, but I'm not sure if having
round
in the name will be somewhat confusing. And I don't think it
makes sense to round tuples in the same sense as rounding other
values; I think it makes sense to always truncate them.
I'd like to hear your thoughts an suggestions, and see what tuple
tricks you all have up your sleeves.
-- Gregg