• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# Copyright 2003 Dave Abrahams
2# Copyright 2002, 2003 Rene Rivera
3# Copyright 2002, 2003, 2004 Vladimir Prus
4# Distributed under the Boost Software License, Version 1.0.
5# (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt)
6
7# Various container classes.
8
9# Base for container objects. This lets us construct recursive structures. That
10# is containers with containers in them, specifically so we can tell literal
11# values from node values.
12#
13class node
14{
15    rule __init__ (
16        value ?  # Optional value to set node to initially.
17    )
18    {
19        self.value = $(value) ;
20    }
21
22    # Set the value of this node, passing nothing will clear it.
23    #
24    rule set ( value * )
25    {
26        self.value = $(value) ;
27    }
28
29    # Get the value of this node.
30    #
31    rule get ( )
32    {
33        return $(self.value) ;
34    }
35}
36
37
38# A simple vector. Interface mimics the C++ std::vector and std::list, with the
39# exception that indices are one (1) based to follow Jam standard.
40#
41# TODO: Possibly add assertion checks.
42#
43class vector : node
44{
45    import numbers ;
46    import utility ;
47    import sequence ;
48
49    rule __init__ (
50        values *  # Initial contents of vector.
51    )
52    {
53        node.__init__ ;
54        self.value = $(values) ;
55    }
56
57    # Get the value of the first element.
58    #
59    rule front ( )
60    {
61        return $(self.value[1]) ;
62    }
63
64    # Get the value of the last element.
65    #
66    rule back ( )
67    {
68        return $(self.value[-1]) ;
69    }
70
71    # Get the value of the element at the given index, one based. Access to
72    # elements of recursive structures is supported directly. Specifying
73    # additional index values recursively accesses the elements as containers.
74    # For example: [ $(v).at 1 : 2 ] would retrieve the second element of our
75    # first element, assuming the first element is a container.
76    #
77    rule at (
78        index  # The element index, one based.
79        : *  # Additional indices to access recursively.
80    )
81    {
82        local r = $(self.value[$(index)]) ;
83        if $(2)
84        {
85            r = [ $(r).at $(2) : $(3) : $(4) : $(5) : $(6) : $(7) : $(8) : $(9) ] ;
86        }
87        return $(r) ;
88    }
89
90    # Get the value contained in the given element. This has the same
91    # functionality and interface as "at" but in addition gets the value of the
92    # referenced element, assuming it is a "node".
93    #
94    rule get-at (
95        index  # The element index, one based.
96        : *  # Additional indices to access recursively.
97    )
98    {
99        local r = $(self.value[$(index)]) ;
100        if $(2)
101        {
102            r = [ $(r).at $(2) : $(3) : $(4) : $(5) : $(6) : $(7) : $(8) : $(9) ] ;
103        }
104        return [ $(r).get ] ;
105    }
106
107    # Insert the given value into the front of the vector pushing the rest of
108    # the elements back.
109    #
110    rule push-front (
111        value  # Value to become first element.
112    )
113    {
114        self.value = $(value) $(self.value) ;
115    }
116
117    # Remove the front element from the vector. Does not return the value. No
118    # effect if vector is empty.
119    #
120    rule pop-front ( )
121    {
122        self.value = $(self.value[2-]) ;
123    }
124
125    # Add the given value at the end of the vector.
126    #
127    rule push-back (
128        value  # Value to become back element.
129    )
130    {
131        self.value += $(value) ;
132    }
133
134    # Remove the back element from the vector. Does not return the value. No
135    # effect if vector is empty.
136    #
137    rule pop-back ( )
138    {
139        self.value = $(self.value[1--2]) ;
140    }
141
142    # Insert the given value at the given index, one based. The values at and to
143    # the right of the index are pushed back to make room for the new value.
144    # If the index is passed the end of the vector the element is added to the
145    # end.
146    #
147    rule insert (
148        index  # The index to insert at, one based.
149        : value  # The value to insert.
150    )
151    {
152        local left = $(self.value[1-$(index)]) ;
153        local right = $(self.value[$(index)-]) ;
154        if $(right)-is-not-empty
155        {
156            left = $(left[1--2]) ;
157        }
158        self.value = $(left) $(value) $(right) ;
159    }
160
161    # Remove one or more elements from the vector. The range is inclusive, and
162    # not specifying an end is equivalent to the [start, start] range.
163    #
164    rule erase (
165        start  # Index of first element to remove.
166        end ?  # Optional, index of last element to remove.
167    )
168    {
169        end ?= $(start) ;
170        local left = $(self.value[1-$(start)]) ;
171        left = $(left[1--2]) ;
172        local right = $(self.value[$(end)-]) ;
173        right = $(right[2-]) ;
174        self.value = $(left) $(right) ;
175    }
176
177    # Remove all elements from the vector.
178    #
179    rule clear ( )
180    {
181        self.value = ;
182    }
183
184    # The number of elements in the vector.
185    #
186    rule size ( )
187    {
188        return [ sequence.length $(self.value) ] ;
189    }
190
191    # Returns "true" if there are NO elements in the vector, empty otherwise.
192    #
193    rule empty ( )
194    {
195        if ! $(self.value)-is-not-empty
196        {
197            return true ;
198        }
199    }
200
201    # Returns the textual representation of content.
202    #
203    rule str ( )
204    {
205        return "[" [ sequence.transform utility.str : $(self.value) ] "]" ;
206    }
207
208    # Sorts the vector inplace, calling 'utility.less' for comparisons.
209    #
210    rule sort ( )
211    {
212        self.value = [ sequence.insertion-sort $(self.value) : utility.less ] ;
213    }
214
215    # Returns true if content is equal to the content of other vector. Uses
216    # 'utility.equal' for comparison.
217    #
218    rule equal ( another )
219    {
220        local mismatch ;
221        local size = [ size ] ;
222        if $(size) = [ $(another).size ]
223        {
224            for local i in [ numbers.range 1 $(size) ]
225            {
226                if ! [ utility.equal [ at $(i) ] [ $(another).at $(i) ] ]
227                {
228                    mismatch = true ;
229                }
230            }
231        }
232        else
233        {
234            mismatch = true ;
235        }
236
237        if ! $(mismatch)
238        {
239            return true ;
240        }
241    }
242}
243
244
245rule __test__ ( )
246{
247    import assert ;
248    import "class" : new ;
249
250    local v1 = [ new vector ] ;
251    assert.true $(v1).equal $(v1) ;
252    assert.true $(v1).empty ;
253    assert.result 0 : $(v1).size ;
254    assert.result "[" "]" : $(v1).str ;
255    $(v1).push-back b ;
256    $(v1).push-front a ;
257    assert.result "[" a b "]" : $(v1).str ;
258    assert.result a : $(v1).front ;
259    assert.result b : $(v1).back ;
260    $(v1).insert 2 : d ;
261    $(v1).insert 2 : c ;
262    $(v1).insert 4 : f ;
263    $(v1).insert 4 : e ;
264    $(v1).pop-back ;
265    assert.result 5 : $(v1).size ;
266    assert.result d : $(v1).at 3 ;
267    $(v1).pop-front ;
268    assert.result c : $(v1).front ;
269    assert.false $(v1).empty ;
270    $(v1).erase 3 4 ;
271    assert.result 2 : $(v1).size ;
272
273    local v2 = [ new vector q w e r t y ] ;
274    assert.result 6 : $(v2).size ;
275    $(v1).push-back $(v2) ;
276    assert.result 3 : $(v1).size ;
277    local v2-alias = [ $(v1).back ] ;
278    assert.result e : $(v2-alias).at 3 ;
279    $(v1).clear ;
280    assert.true $(v1).empty ;
281    assert.false $(v2-alias).empty ;
282    $(v2).pop-back ;
283    assert.result t : $(v2-alias).back ;
284
285    local v3 = [ new vector ] ;
286    $(v3).push-back [ new vector 1 2 3 4 5 ] ;
287    $(v3).push-back [ new vector a b c ] ;
288    assert.result "[" "[" 1 2 3 4 5 "]" "[" a b c "]" "]" : $(v3).str ;
289    $(v3).push-back [ new vector [ new vector x y z ] [ new vector 7 8 9 ] ] ;
290    assert.result 1 : $(v3).at 1 : 1 ;
291    assert.result b : $(v3).at 2 : 2 ;
292    assert.result a b c : $(v3).get-at 2 ;
293    assert.result 7 8 9 : $(v3).get-at 3 : 2 ;
294
295    local v4 = [ new vector 4 3 6 ] ;
296    $(v4).sort ;
297    assert.result 3 4 6 : $(v4).get ;
298    assert.false $(v4).equal $(v3) ;
299
300    local v5 = [ new vector 3 4 6 ] ;
301    assert.true $(v4).equal $(v5) ;
302    # Check that vectors of different sizes are considered non-equal.
303    $(v5).pop-back ;
304    assert.false $(v4).equal $(v5) ;
305
306    local v6 = [ new vector [ new vector 1 2 3 ] ] ;
307    assert.true $(v6).equal [ new vector [ new vector 1 2 3 ] ] ;
308
309    local v7 = [ new vector 111 222 333 ] ;
310    assert.true $(v7).equal $(v7) ;
311    $(v7).insert 4 : 444 ;
312    assert.result 111 222 333 444 : $(v7).get ;
313    $(v7).insert 999 : xxx ;
314    assert.result 111 222 333 444 xxx : $(v7).get ;
315
316    local v8 = [ new vector "" "" "" ] ;
317    assert.true $(v8).equal $(v8) ;
318    assert.false $(v8).empty ;
319    assert.result 3  : $(v8).size ;
320    assert.result "" : $(v8).at 1 ;
321    assert.result "" : $(v8).at 2 ;
322    assert.result "" : $(v8).at 3 ;
323    assert.result    : $(v8).at 4 ;
324    $(v8).insert 2 : 222 ;
325    assert.result 4 : $(v8).size ;
326    assert.result "" 222 "" "" : $(v8).get ;
327    $(v8).insert 999 : "" ;
328    assert.result 5 : $(v8).size ;
329    assert.result "" 222 "" "" "" : $(v8).get ;
330    $(v8).insert 999 : xxx ;
331    assert.result 6 : $(v8).size ;
332    assert.result "" 222 "" "" "" xxx : $(v8).get ;
333
334    # Regression test for a bug causing vector.equal to compare only the first
335    # and the last element in the given vectors.
336    local v9 = [ new vector 111 xxx 222 ] ;
337    local v10 = [ new vector 111 yyy 222 ] ;
338    assert.false $(v9).equal $(v10) ;
339}
340