summaryrefslogtreecommitdiff
path: root/tools/build/v2/util/numbers.jam
blob: 665347d3184c74c640908e1e5b84729ed88e4b7c (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
# Copyright 2001, 2002 Dave Abrahams
# Copyright 2002, 2003 Vladimir Prus
# Distributed under the Boost Software License, Version 1.0.
# (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt)

import errors ;


rule trim-leading-zeroes ( value )
{
    return [ CALC $(value) + 0 ] ;
}


rule check ( numbers * )
{
    for local n in $(numbers)
    {
        switch $(n)
        {
            case *[^0-9]* :
                errors.error $(n) "in" $(numbers) : is not a number ;
        }
    }
}


rule increment ( number )
{
    return [ CALC $(number) + 1 ] ;
}


rule decrement ( number )
{
    return [ CALC $(number) - 1 ] ;
}


rule range ( start finish ? : step ? )
{
    if ! $(finish)
    {
        finish = $(start) ;
        start = 1 ;
    }
    step ?= 1 ;

    check $(start) $(finish) $(step) ;

    if $(finish) != 0
    {
        local result ;
        while [ less $(start) $(finish) ] || $(start) = $(finish)
        {
            result += $(start) ;
            start = [ CALC $(start) + $(step) ] ;
        }
        return $(result) ;
    }
}


rule less ( n1 n2 )
{
    switch [ CALC $(n2) - $(n1) ]
    {
        case [1-9]* : return true ;
    }
}


rule log10 ( number )
{
    switch $(number)
    {
        case *[^0-9]* : errors.error $(number) is not a number ;
        case 0 : errors.error can't take log of zero ;
        case [1-9] : return 0 ;
        case [1-9]? : return 1 ;
        case [1-9]?? : return 2 ;
        case [1-9]??? : return 3 ;
        case [1-9]???? : return 4 ;
        case [1-9]????? : return 5 ;
        case [1-9]?????? : return 6 ;
        case [1-9]??????? : return 7 ;
        case [1-9]???????? : return 8 ;
        case [1-9]????????? : return 9 ;
        case * :
        {
            import sequence ;
            import string ;
            local chars = [ string.chars $(number) ] ;
            while $(chars[1]) = 0
            {
                chars = $(chars[2-]) ;
            }
            if ! $(chars)
            {
                errors.error can't take log of zero ;
            }
            else
            {
                return [ decrement [ sequence.length $(chars) ] ] ;
            }
        }
    }
}


rule __test__ ( )
{
    import assert ;

    assert.result 1 : increment 0 ;
    assert.result 2 : increment 1 ;
    assert.result 1 : decrement 2 ;
    assert.result 0 : decrement 1 ;
    assert.result 50 : increment 49 ;
    assert.result 49 : decrement 50 ;
    assert.result 99 : increment 98 ;
    assert.result 99 : decrement 100 ;
    assert.result 100 : increment 99 ;
    assert.result 999 : decrement 1000 ;
    assert.result 1000 : increment 999 ;

    assert.result 1 2 3 : range 3 ;
    assert.result 1 2 3 4 5 6 7 8 9 10 11 12 : range 12 ;
    assert.result 3 4 5 6 7 8 9 10 11 : range 3 11 ;
    assert.result : range 0 ;
    assert.result 1 4 7 10 : range 10 : 3 ;
    assert.result 2 4 6 8 10 : range 2 10 : 2 ;
    assert.result 25 50 75 100 : range 25 100 : 25 ;

    assert.result 0           : trim-leading-zeroes 0           ;
    assert.result 1234        : trim-leading-zeroes 1234        ;
    assert.result 123456      : trim-leading-zeroes 0000123456  ;
    assert.result 1000123456  : trim-leading-zeroes 1000123456  ;
    assert.result 10000       : trim-leading-zeroes 10000       ;
    assert.result 10000       : trim-leading-zeroes 00010000    ;

    assert.true  less 1 2 ;
    assert.true  less 1 12 ;
    assert.true  less 1 21 ;
    assert.true  less 005 217 ;
    assert.false less 0 0 ;
    assert.false less 03 3 ;
    assert.false less 3 03 ;
    assert.true  less 005 217 ;
    assert.true  less 0005 217 ;
    assert.true  less 5 00217 ;

    # TEMPORARY disabled, because nested "try"/"catch" do not work and I do no
    # have the time to fix that right now.
    if $(0)
    {
    try ;
    {
        decrement 0 ;
    }
    catch can't decrement zero! ;

    try ;
    {
        check foo ;
    }
    catch : not a number ;

    try ;
    {
        increment foo ;
    }
    catch : not a number ;

    try ;
    {
        log10 0 ;
    }
    catch can't take log of zero ;

    try ;
    {
        log10 000 ;
    }
    catch can't take log of zero ;

    }

    assert.result 0 : log10 1 ;
    assert.result 0 : log10 9 ;
    assert.result 1 : log10 10 ;
    assert.result 1 : log10 99 ;
    assert.result 2 : log10 100 ;
    assert.result 2 : log10 101 ;
    assert.result 2 : log10 125 ;
    assert.result 2 : log10 999 ;
    assert.result 3 : log10 1000 ;
    assert.result 10 : log10 12345678901 ;

    for local x in [ range 75 110 : 5 ]
    {
        for local y in [ range $(x) 111 : 3 ]
        {
            if $(x) != $(y)
            {
                assert.true less $(x) $(y) ;
            }
        }
    }

    for local x in [ range 90 110 : 2 ]
    {
        for local y in [ range 80 $(x) : 4 ]
        {
            assert.false less $(x) $(y) ;
        }
    }
}