1# Copyright 2001, 2002, 2003 Dave Abrahams 2# Copyright 2006 Rene Rivera 3# Copyright 2002, 2003 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 7import assert ; 8import numbers ; 9import modules ; 10 11 12# Note that algorithms in this module execute largely in the caller's module 13# namespace, so that local rules can be used as function objects. Also note that 14# most predicates can be multi-element lists. In that case, all but the first 15# element are prepended to the first argument which is passed to the rule named 16# by the first element. 17 18 19# Return the elements e of $(sequence) for which [ $(predicate) e ] has a 20# non-null value. 21# 22rule filter ( predicate + : sequence * ) 23{ 24 local caller = [ CALLER_MODULE ] ; 25 local result ; 26 27 for local e in $(sequence) 28 { 29 if [ modules.call-in $(caller) : $(predicate) $(e) ] 30 { 31 result += $(e) ; 32 } 33 } 34 return $(result) ; 35} 36 37 38# Return a new sequence consisting of [ $(function) $(e) ] for each element e of 39# $(sequence). 40# 41rule transform ( function + : sequence * ) 42{ 43 local caller = [ CALLER_MODULE ] ; 44 local result ; 45 46 for local e in $(sequence) 47 { 48 result += [ modules.call-in $(caller) : $(function) $(e) ] ; 49 } 50 return $(result) ; 51} 52 53if [ HAS_NATIVE_RULE sequence : transform : 1 ] 54{ 55 NATIVE_RULE sequence : transform ; 56} 57 58# Returns the elements of 's' in reverse order 59rule reverse ( s * ) 60{ 61 local r ; 62 for local x in $(s) 63 { 64 r = $(x) $(r) ; 65 } 66 return $(r) ; 67} 68 69 70rule less ( a b ) 71{ 72 if $(a) < $(b) 73 { 74 return true ; 75 } 76} 77 78 79# Insertion-sort s using the BinaryPredicate ordered. 80# 81rule insertion-sort ( s * : ordered * ) 82{ 83 if ! $(ordered) 84 { 85 return [ SORT $(s) ] ; 86 } 87 else 88 { 89 local caller = [ CALLER_MODULE ] ; 90 ordered ?= sequence.less ; 91 local result = $(s[1]) ; 92 if $(ordered) = sequence.less 93 { 94 local head tail ; 95 for local x in $(s[2-]) 96 { 97 head = ; 98 tail = $(result) ; 99 while $(tail) && ( $(tail[1]) < $(x) ) 100 { 101 head += $(tail[1]) ; 102 tail = $(tail[2-]) ; 103 } 104 result = $(head) $(x) $(tail) ; 105 } 106 } 107 else 108 { 109 for local x in $(s[2-]) 110 { 111 local head tail ; 112 tail = $(result) ; 113 while $(tail) && [ modules.call-in $(caller) : $(ordered) $(tail[1]) $(x) ] 114 { 115 head += $(tail[1]) ; 116 tail = $(tail[2-]) ; 117 } 118 result = $(head) $(x) $(tail) ; 119 } 120 } 121 122 return $(result) ; 123 } 124} 125 126 127# Merge two ordered sequences using the BinaryPredicate ordered. 128# 129rule merge ( s1 * : s2 * : ordered * ) 130{ 131 ordered ?= sequence.less ; 132 local result__ ; 133 local caller = [ CALLER_MODULE ] ; 134 135 while $(s1) && $(s2) 136 { 137 if [ modules.call-in $(caller) : $(ordered) $(s1[1]) $(s2[1]) ] 138 { 139 result__ += $(s1[1]) ; 140 s1 = $(s1[2-]) ; 141 } 142 else if [ modules.call-in $(caller) : $(ordered) $(s2[1]) $(s1[1]) ] 143 { 144 result__ += $(s2[1]) ; 145 s2 = $(s2[2-]) ; 146 } 147 else 148 { 149 s2 = $(s2[2-]) ; 150 } 151 152 } 153 result__ += $(s1) ; 154 result__ += $(s2) ; 155 156 return $(result__) ; 157} 158 159# Compares two sequences lexicagraphically 160# 161rule compare ( s1 * : s2 * : ordered * ) 162{ 163 if ! $(ordered) 164 { 165 if $(s1) < $(s2) 166 { 167 return true ; 168 } 169 } 170 else 171 { 172 while true 173 { 174 if ! $(s2[1])-is-defined 175 { 176 return ; 177 } 178 else if ! $(s1[1])-is-defined 179 { 180 return true ; 181 } 182 else if [ $(ordered) $(s1[1]) $(s2[1]) ] 183 { 184 return true ; 185 } 186 else if [ $(ordered) $(s2[1]) $(s1[1]) ] 187 { 188 return ; 189 } 190 s1 = $(s1[2-]) ; 191 s2 = $(s2[2-]) ; 192 } 193 } 194} 195 196# Join the elements of s into one long string. If joint is supplied, it is used 197# as a separator. 198# 199rule join ( s * : joint ? ) 200{ 201 joint ?= "" ; 202 return $(s:J=$(joint)) ; 203} 204 205 206# Find the length of any sequence. 207# 208rule length ( s * ) 209{ 210 local result = 0 ; 211 for local i in $(s) 212 { 213 result = [ CALC $(result) + 1 ] ; 214 } 215 return $(result) ; 216} 217 218# Removes duplicates from 'list'. If 'stable' is 219# passed, then the order of the elements will 220# be unchanged. 221rule unique ( list * : stable ? ) 222{ 223 local result ; 224 local prev ; 225 if $(stable) 226 { 227 for local f in $(list) 228 { 229 if ! $(f) in $(result) 230 { 231 result += $(f) ; 232 } 233 } 234 } 235 else 236 { 237 for local i in [ SORT $(list) ] 238 { 239 if $(i) != $(prev) 240 { 241 result += $(i) ; 242 } 243 prev = $(i) ; 244 } 245 } 246 return $(result) ; 247} 248 249 250# Returns the maximum number in 'elements'. Uses 'ordered' for comparisons or 251# 'numbers.less' if none is provided. 252# 253rule max-element ( elements + : ordered ? ) 254{ 255 ordered ?= numbers.less ; 256 257 local max = $(elements[1]) ; 258 for local e in $(elements[2-]) 259 { 260 if [ $(ordered) $(max) $(e) ] 261 { 262 max = $(e) ; 263 } 264 } 265 return $(max) ; 266} 267 268 269# Returns all of 'elements' for which corresponding element in parallel list 270# 'rank' is equal to the maximum value in 'rank'. 271# 272rule select-highest-ranked ( elements * : ranks * ) 273{ 274 if $(elements) 275 { 276 local max-rank = [ max-element $(ranks) ] ; 277 local result ; 278 while $(elements) 279 { 280 if $(ranks[1]) = $(max-rank) 281 { 282 result += $(elements[1]) ; 283 } 284 elements = $(elements[2-]) ; 285 ranks = $(ranks[2-]) ; 286 } 287 return $(result) ; 288 } 289} 290NATIVE_RULE sequence : select-highest-ranked ; 291 292 293rule __test__ ( ) 294{ 295 # Use a unique module so we can test the use of local rules. 296 module sequence.__test__ 297 { 298 import assert ; 299 import sequence ; 300 301 local rule is-even ( n ) 302 { 303 if $(n) in 0 2 4 6 8 304 { 305 return true ; 306 } 307 } 308 309 assert.result 4 6 4 2 8 : sequence.filter is-even : 1 4 6 3 4 7 2 3 8 ; 310 311 # Test that argument binding works. 312 local rule is-equal-test ( x y ) 313 { 314 if $(x) = $(y) 315 { 316 return true ; 317 } 318 } 319 320 assert.result 3 3 3 : sequence.filter is-equal-test 3 : 1 2 3 4 3 5 3 5 7 ; 321 322 local rule append-x ( n ) 323 { 324 return $(n)x ; 325 } 326 327 assert.result 1x 2x 3x : sequence.transform append-x : 1 2 3 ; 328 329 local rule repeat2 ( x ) 330 { 331 return $(x) $(x) ; 332 } 333 334 assert.result 1 1 2 2 3 3 : sequence.transform repeat2 : 1 2 3 ; 335 336 local rule test-greater ( a b ) 337 { 338 if $(a) > $(b) 339 { 340 return true ; 341 } 342 } 343 assert.result 1 2 3 4 5 6 7 8 9 : sequence.insertion-sort 9 6 5 3 8 7 1 2 4 ; 344 assert.result 9 8 7 6 5 4 3 2 1 : sequence.insertion-sort 9 6 5 3 8 7 1 2 4 : test-greater ; 345 assert.result 1 2 3 4 5 6 : sequence.merge 1 3 5 : 2 4 6 ; 346 assert.result 6 5 4 3 2 1 : sequence.merge 5 3 1 : 6 4 2 : test-greater ; 347 assert.result 1 2 3 : sequence.merge 1 2 3 : ; 348 assert.result 1 : sequence.merge 1 : 1 ; 349 350 assert.result foo-bar-baz : sequence.join foo bar baz : - ; 351 assert.result substandard : sequence.join sub stan dard ; 352 assert.result 3.0.1 : sequence.join 3.0.1 : - ; 353 354 assert.result 0 : sequence.length ; 355 assert.result 3 : sequence.length a b c ; 356 assert.result 17 : sequence.length 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 ; 357 358 assert.result 1 : sequence.length a ; 359 assert.result 10 : sequence.length a b c d e f g h i j ; 360 assert.result 11 : sequence.length a b c d e f g h i j k ; 361 assert.result 12 : sequence.length a b c d e f g h i j k l ; 362 363 local p2 = x ; 364 for local i in 1 2 3 4 5 6 7 8 365 { 366 p2 = $(p2) $(p2) ; 367 } 368 assert.result 256 : sequence.length $(p2) ; 369 370 assert.result 1 2 3 4 5 : sequence.unique 1 2 3 2 4 3 3 5 5 5 ; 371 372 assert.result 5 : sequence.max-element 1 3 5 0 4 ; 373 374 assert.result e-3 h-3 : sequence.select-highest-ranked e-1 e-3 h-3 m-2 : 1 3 3 2 ; 375 376 assert.result 7 6 5 4 3 2 1 : sequence.reverse 1 2 3 4 5 6 7 ; 377 } 378} 379