"{ 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) = __mkSmallInteger(pos);
}
__INST(position) = __mkSmallInteger(__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) = __mkSmallInteger(pos);
}
__INST(position) = __mkSmallInteger(__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) = __mkSmallInteger(pos);
}
__INST(position) = __mkSmallInteger(__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.4 2005-07-08 17:15:01 cg Exp $'
! !