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