Cons.st
author Claus Gittinger <cg@exept.de>
Thu, 06 Sep 2007 17:31:09 +0200
changeset 1894 8bf137acc445
parent 1627 5bc113e1f2f3
child 2437 58c3242dc76d
permissions -rw-r--r--
if no unit is given in the readString, assume seconds.

"
 COPYRIGHT (c) 2002 by eXept Software AG
              All Rights Reserved

 This software is furnished under a license and may be used
 only in accordance with the terms of that license and with the
 inclusion of the above copyright notice.   This software may not
 be provided or otherwise made available to, or used by, any
 other person.  No title to or ownership of the software is
 hereby transferred.
"

"{ Package: 'stx:libbasic2' }"

SequenceableCollection subclass:#Cons
	instanceVariableNames:'car cdr'
	classVariableNames:''
	poolDictionaries:''
	category:'Collections-Linked'
!

!Cons class methodsFor:'documentation'!

copyright
"
 COPYRIGHT (c) 2002 by eXept Software AG
              All Rights Reserved

 This software is furnished under a license and may be used
 only in accordance with the terms of that license and with the
 inclusion of the above copyright notice.   This software may not
 be provided or otherwise made available to, or used by, any
 other person.  No title to or ownership of the software is
 hereby transferred.
"
!

documentation
"
    A pair as in lisp.
    Create with:
        a !! b
    or:
        Cons car:a cdr:b

    Conses are not heavily used by Smalltalk (actually: not at all).
    Consider this a demo class.

    [author:]
        Claus Gittinger

    [see also:]

"
!

examples
"
                                                                        [exBegin]
    |p1 p2 p3|

    p3 := Cons car:3 cdr:nil.
    p2 := Cons car:2 cdr:p3.
    p1 := Cons car:1 cdr:p2.
    p1 head.
    p1 tail.
    p1 size.
    p1 do:[:each | Transcript showCR:each].
    p1 at:2
                                                                        [exEnd]
"
! !

!Cons class methodsFor:'instance creation'!

car:carArg cdr:cdrArg
    ^ self basicNew car:carArg cdr:cdrArg
!

fromArray:anArray
    |p last first|

    anArray do:[:el |
        p := self car:el cdr:nil.
        first isNil ifTrue:[
            first := p.
        ] ifFalse:[
            last cdr:p.
        ].
        last := p.
    ].
    ^ first.

    "
     Cons fromArray:#(1 2 3 4)   
     Cons fromArray:#()    
     Cons fromArray:#(1)    
     Cons fromArray:(1 to:10000)    
    "
! !

!Cons methodsFor:'accessing'!

at:n
    "for collection compatibility:
     a slow indexed accessor"

    ^ (self nth:n)

    "
     (Cons fromArray:#(1))       at:1     
     (Cons fromArray:#(1 2 3 4)) at:1 
     (Cons fromArray:#(1 2 3 4)) at:3  
     (Cons fromArray:#(1 2 3 4)) at:4  
     (Cons fromArray:#(1 2 3 4)) at:5  
    "
!

at:n put:newValue
    "destructive: 
     for collection compatibility: a slow indexed accessor"

    (self nthPair:n) car:newValue.
    ^ newValue.

    "
     |l|

     l := Cons fromArray:#(1 2 3 4).
     l at:1 put:'one'.
     l at:3 put:'three'.
     l       
    "
!

first
    "return the head, first or car - whatever you wonna call it"

    ^ self car
!

head
    "return the head, first or car - whatever you wonna call it"

    ^ self car
!

last
    "for lispers:
     return the last element of a list"

    |p rest|

    p := self.
    [(rest := p cdr) notNil] whileTrue:[
        p := rest
    ].
    ^ p car

    "
     (Cons fromArray:#(1))       last     
     (Cons fromArray:#(1 2 3 4)) last    
    "
!

nth:n
    "for lispers:
     return the nth element of a list"

    ^ (self nthPair:n) car

    "
     (Cons fromArray:#(1))       nth:1     
     (Cons fromArray:#(1 2 3 4)) nth:1 
     (Cons fromArray:#(1 2 3 4)) nth:3  
     (Cons fromArray:#(1 2 3 4)) nth:4  
     (Cons fromArray:#(1 2 3 4)) nth:5  
     (Cons fromArray:#( ))       nth:1  -> error    
    "
!

rest
    "return the head, first or car - whatever you wonna call it"

    ^ self cdr
!

reversed
    "for lispers:
     return a new list with the cars in reverse order"

"/ for now, tail recursion is not yet optimized by the st/x jitter...
"/
"/    |rev|
"/
"/    rev := [:lst :acc |
"/                lst isNil ifTrue:[
"/                    acc
"/                ] ifFalse:[
"/                    rev value:(lst tail)
"/                        value:(Cons car:(lst head) cdr:acc)
"/                ]
"/           ].
"/    ^ rev value:self value:nil

    | lst acc|

    lst := self.
    acc := nil.

    [
        |nLst nAcc|

        lst isNil ifTrue:[ ^ acc].

        nLst := lst tail.
        nAcc := Cons car:(lst head) cdr:acc.
        lst := nLst.
        acc := nAcc.
   ] loop

    "
     (Cons fromArray:#(1))       reversed     
     (Cons fromArray:#(1 2))     reversed     
     (Cons fromArray:#(1 2 3 4)) reversed    
     (Cons fromArray:(1 to:10000)) reversed    
    "
!

tail
    "return the tail, second or cdr - whatever you wonna call it"

    ^ self cdr
! !

!Cons methodsFor:'accessing - basic'!

car
    "return the head, first or car - whatever you wonna call it"

    ^ car
!

car:something
    "set the head, first or car - whatever you wonna call it"

    car := something.
!

car:carArg cdr:cdrArg 
    "set both car and cdr"

    car := carArg.
    cdr := cdrArg.
!

cdr
    "return the tail, second or cdr - whatever you wonna call it"

    ^ cdr
!

cdr:something
    "set the tail, second or cdr - whatever you wonna call it"

    cdr := something.
!

first:carArg rest:cdrArg 
    "set both car and cdr"

    car := carArg.
    cdr := cdrArg.
!

head:carArg tail:cdrArg 
    "set both car and cdr"

    car := carArg.
    cdr := cdrArg.
!

nthPair:n
    "a helper:
     return the nth pair of a list"

    |cnt p|

    cnt := n.
    p := self.
    [
        cnt := cnt - 1.
        cnt == 0 ifTrue:[^ p].
        p := p cdr.
        p isNil ifTrue:[
            self error:'no such element' mayProceed:true.
            ^ nil
        ].
    ] loop.
! !

!Cons methodsFor:'enumerating'!

do:aBlock
    |ptr|

    aBlock value:car.
    ptr := cdr.
    [ ptr notNil ] whileTrue:[
        aBlock value:ptr car.
        ptr := ptr cdr.
    ].
! !

!Cons methodsFor:'list processing'!

append:aCons
    "for lispers:
     append the arg. Return a new list, where the 2nd part is shared.
     Destructive: the receivers last cdr is modified."

    |p rest|

    p := self.
    [(rest := p cdr) notNil] whileTrue:[
        p := rest
    ].
    p cdr:aCons.
    ^ self

    "
     (Cons fromArray:#(1 2 3 4)) 
        append:(Cons fromArray:#(5 6 7 8)) 
    "

    "sharing demonstrated:

     |a b ab|

     a := Cons fromArray:#(1 2 3 4).
     b := Cons fromArray:#(5 6 7 8).
     ab := a append:b.
     b car:'five'.
     ab      
    "

    "destruction demonstrated:

     |a b ab|

     a := Cons fromArray:#(1 2 3 4).
     b := Cons fromArray:#(5 6 7 8).
     ab := a append:b.
     a  
    "
!

take:nTaken
    "for lispers:
     take n elements from the list; return a new list"

    |nRemain l rslt lastCons cons|

    nTaken > 0 ifTrue:[
        "/ avoiding recursion here...
        "/ instead of:
        "/        ^ Cons car:(self car) cdr:(self cdr take:nTaken-1)
        "/ we do:
        nRemain := nTaken.
        l := self.
        rslt := lastCons := Cons car:(l car) cdr:nil.
        [nRemain > 1] whileTrue:[
            l := l cdr.
            cons := Cons car:(l car) cdr:nil.    
            lastCons cdr:cons.
            lastCons := cons.
            nRemain := nRemain - 1.
        ].
        ^ rslt.
    ].
    ^ nil

    "
     (Cons fromArray:#(1 2 3 4)) take:3  
     (Cons fromArray:#(1)) take:0  
     (Cons fromArray:#()) take:3  
     (Cons fromArray:(1 to: 1000)) take:999  
    "
! !

!Cons methodsFor:'printing'!

displayString
    ^ self printString
!

printOn:aStream
    (car isLazyValue not and:[ car isCons ]) ifTrue:[
        aStream nextPutAll:'('.
        car printOn:aStream.
        aStream nextPutAll:')'.
    ] ifFalse:[
        car printOn:aStream.
    ].

    aStream nextPutAll:'!!'.

    (cdr isLazyValue not and:[ cdr isCons ]) ifTrue:[
        aStream nextPutAll:'('.
        cdr printOn:aStream.
        aStream nextPutAll:')'.
    ] ifFalse:[
        cdr printOn:aStream.
    ].
! !

!Cons methodsFor:'queries'!

isCons
    ^ true
!

size
    "for smalltalkers: the lists length"

    |l p rest|

    l := 1.
    p := self.
    [(rest := p cdr) notNil] whileTrue:[
        l := l + 1.
        p := rest
    ].
    ^ l

    "
     (Cons fromArray:#( )) size    
     (Cons fromArray:#(1)) size     
     (Cons fromArray:#(1 2 3 4)) size    
    "
! !

!Cons methodsFor:'streaming'!

readStream
    ^ ConsStream on:self.
! !

!Cons class methodsFor:'documentation'!

version
    ^ '$Header: /cvs/stx/stx/libbasic2/Cons.st,v 1.9 2006-04-13 15:21:03 cg Exp $'
! !