CharacterWriteStream.st
author penk
Tue, 14 Dec 2004 14:14:09 +0100
changeset 8657 1df84e8daa15
parent 8321 eb23a697cd98
child 8913 b9498d27a554
permissions -rw-r--r--
care for nil suspendedContext in description

"{ Package: 'stx:libbasic' }"

WriteStream subclass:#CharacterWriteStream
	instanceVariableNames:'currentCharacterSize'
	classVariableNames:''
	poolDictionaries:''
	category:'Streams'
!

!CharacterWriteStream class methodsFor:'documentation'!

documentation
"
    This is a WriteStream, which automagically changes the underlying collection,
    if a character does fit into the current collectuin

    String -> Unicode16String -> Unicode32Sting

    [author:]
        Stefan Vogel (stefan@zwerg)

    [instance variables:]

    [class variables:]

    [see also:]
     String Unicode16String Unicode32Sting

"
!

examples
"

                                                                [exBegin]
    |stream|

    stream := CharacterWriteStream on:(String new:32).
    stream nextPutAll:'abc'.
    stream nextPut:(Character value:16r2c00).
    stream contents inspect
                                                                [exEnd]

"
! !

!CharacterWriteStream methodsFor:'private'!

characterSizeChanged:aCharacterOrString
    "change aCollection to fit the size of aCharacter"

    |sz newSz bitsPerCharacter|

    bitsPerCharacter := aCharacterOrString bitsPerCharacter. 
    currentCharacterSize < bitsPerCharacter ifTrue:[
        sz := collection size.
        (position + 1 - ZeroPosition) > sz ifTrue:[
            newSz := sz + 1.
        ] ifFalse:[
            newSz := sz.
        ].
        collection := (aCharacterOrString stringSpecies new:newSz) 
                        replaceFrom:1 to:sz with:collection startingAt:1.
        currentCharacterSize := bitsPerCharacter.
    ].
! !

!CharacterWriteStream methodsFor:'private-accessing'!

on:aCollection

    currentCharacterSize := aCollection bitsPerCharacter.
    ^ super on:aCollection.
!

on:aCollection from:start to:stop

    currentCharacterSize := aCollection bitsPerCharacter.
    ^ super on:aCollection from:start to:stop.
!

with:aCollection

    currentCharacterSize := aCollection bitsPerCharacter.
    ^ super with:aCollection.
! !

!CharacterWriteStream methodsFor:'writing'!

next:count put:aCharacter
    "append anObject count times to the receiver.
     Redefined to avoid count grows of the underlying collection -
     instead a single grow on the final size is performed."


    aCharacter bitsPerCharacter > currentCharacterSize ifTrue:[
        self characterSizeChanged:aCharacter.
    ].
    ^ super next:count put:aCharacter
!

nextPut:aCharacter
    "append the argument, aCharacter to the stream.
     Specially tuned for appending to String, ByteArray and Array streams."

%{  /* NOCONTEXT */

#ifndef NO_PRIM_STREAM
    REGISTER int pos;
    unsigned ch;
    OBJ coll;
    OBJ p, wL, rL;
    int __readLimit = -1;

    coll = __INST(collection);
    p = __INST(position);

    if (__isNonNilObject(coll) && __isSmallInteger(p) && __isCharacter(aCharacter)) {
        pos = __intVal(p);
        /* make 1-based */
        pos = pos + 1 - __intVal( @global(PositionableStream:ZeroPosition));
        wL = __INST(writeLimit);

        if ((wL == nil)
         || (__isSmallInteger(wL) && (pos <= __intVal(wL)))) {
            OBJ cls;

            cls = __qClass(coll);
            ch = __intVal(__characterVal(aCharacter));

            rL = __INST(readLimit);
            if (__isSmallInteger(rL)) {
                __readLimit = __intVal(rL);
            }

            if (cls == @global(String)) {
                if (ch > 0xFF) {
                    goto resize;
                }
                if (pos <= __stringSize(coll)) {
                    __StringInstPtr(coll)->s_element[pos-1] = ch;
                    if ((__readLimit >= 0) && (pos >= __readLimit)) {
                        __INST(readLimit) = __MKSMALLINT(pos);
                    }
                    __INST(position) = __MKSMALLINT(__intVal(__INST(position)) + 1);
                    RETURN ( aCharacter );
                }
            } else if (cls == @global(Unicode16String)) {
                if (ch > 0xFFFF) {
                    goto resize;
                }
                if (pos <= __unicode16StringSize(coll)) {
                     __Unicode16StringInstPtr(coll)->s_element[pos-1] = ch;
                    if ((__readLimit >= 0) && (pos >= __readLimit)) {
                        __INST(readLimit) = __MKSMALLINT(pos);
                    }
                    __INST(position) = __MKSMALLINT(__intVal(__INST(position)) + 1);
                    RETURN ( aCharacter );
                }
            } else if (cls == @global(Unicode32String)) {
                if ((pos <= __unicode32StringSize(coll))) {
                     __Unicode32StringInstPtr(coll)->s_element[pos-1] = ch;
                    if ((__readLimit >= 0) && (pos >= __readLimit)) {
                        __INST(readLimit) = __MKSMALLINT(pos);
                    }
                    __INST(position) = __MKSMALLINT(__intVal(__INST(position)) + 1);
                    RETURN ( aCharacter );
                }
            }
        }
    }
    resize:;
#endif
%}.


    (writeLimit isNil
     or:[(position + 1 - ZeroPosition) <= writeLimit]) ifTrue:[
        currentCharacterSize < aCharacter bitsPerCharacter ifTrue:[
            self characterSizeChanged:aCharacter
        ].
        ((position + 1 - ZeroPosition) > collection size) ifTrue:[self growCollection].
        collection at:(position + 1 - ZeroPosition) put:aCharacter.
        ((position + 1 - ZeroPosition) > readLimit) ifTrue:[readLimit := (position + 1 - ZeroPosition)].
        position := position + 1.
    ] ifFalse:[
        WriteError raiseErrorString:'write beyond writeLimit'
    ].
    ^ aCharacter
!

nextPutAll:aCollection
    "append anObject count times to the receiver.
     Redefined to avoid count grows of the underlying collection -
     instead a single grow on the final size is performed."


    aCollection bitsPerCharacter > currentCharacterSize ifTrue:[
        self characterSizeChanged:aCollection.
    ].
    ^ super nextPutAll:aCollection
!

nextPutAll:aCollection startingAt:start to:stop
    "append anObject count times to the receiver.
     Redefined to avoid count grows of the underlying collection -
     instead a single grow on the final size is performed."


    aCollection bitsPerCharacter > currentCharacterSize ifTrue:[
        self characterSizeChanged:aCollection.
    ].
    ^ super nextPutAll:aCollection startingAt:start to:stop
! !

!CharacterWriteStream class methodsFor:'documentation'!

version
    ^ '$Header: /cvs/stx/stx/libbasic/CharacterWriteStream.st,v 1.3 2004-04-21 14:12:07 stefan Exp $'
! !