! ========================================================================
! Copyright (C) by VMware, Inc. 1991-2011.  All Rights Reserved
!
! $Id: doublebytestring.gs,v 1.14 2008-01-09 22:50:10 stever Exp $
!
! ========================================================================
removeallmethods DoubleByteString
removeallclassmethods DoubleByteString

category: 'For Documentation Installation only'
classmethod: DoubleByteString
installDocumentation

| doc txt |
doc := GsClassDocumentation newForClass: self.

txt := (GsDocText new) details:
'A DoubleByteString is a string for which each Character occupies two bytes.
 The first byte of each Character in a DoubleByteString is the more significant
 byte; the second byte is the less significant byte.

 DoubleByteString is in the ClassHistory of String, so instances of
 DoubleByteString may be stored into instance variables that are constrained
 to hold instances of String.  The inverse is not true, so in an application
 that uses a mixture of DoubleByteStrings and Strings, string constraints
 should always be expressed as String.' .
doc documentClassWith: txt.

txt := (GsDocText new) details:
'Unless noted otherwise, comparisons between DoubleByteStrings are 
 case-sensitive.

 Some of these methods determine whether one strings collates before
 another.  In collation, the Characters of the receiver and aString are
 compared Character-by-Character, from left to right, in case-sensitive
 fashion.  If two strings are of different length, and all Characters in the
 shorter string are equal to their counterparts in the longer strings, the
 shorter string collates before the longer.

 These methods require that the argument be a kind of CharacterCollection, not
 necessarily a String.'.
doc documentCategory: #Comparing with: txt.

self description: doc.
%

! ------------------- Class methods for DoubleByteString

category 'Instance Creation'
classmethod: DoubleByteString
new: aSize

"(R) Returns a new instance of the receiver, of sufficient size to hold aSize
 Characters of two bytes each."

^ super new: (aSize * 2)
%

category 'Instance Creation'
classmethod: DoubleByteString
withAll: aString

"Returns an instance of the receiver containing the elements of the argument."

<primitive: 456>

^ super withAll: aString
%

! ------------------- Instance methods for DoubleByteString
category: 'Concatenating'
method: DoubleByteString
, aCharOrCharColl

"Returns a new instance of the receiver's class that contains the elements of
 the receiver followed by the elements of aCharOrCharColl.  The argument
 must be a String, a DoubleByteString, or an AbstractCharacter.

 The result may not be an instance of the class of the receiver if one of the
 following rules applies:

 1) If the receiver or argument is a kind of Symbol, DoubleByteSymbol, or 
    ObsoleteInvariantString, the result is a DoubleByteString.

 2) If the argument is not a DoubleByteString, and is a subclass of
    DoubleByteString, then the result is an instance of the class of the
    argument.

 Warning: Creating a new instance and copying the receiver take time.  If you
 can safely modify the receiver, it can be much faster to use the addAll:
 method.  See the documentation of the Concatenating category of class
 SequenceableCollection for more details."

<primitive: 614 >
| result |
(aCharOrCharColl isKindOf: String) ifTrue:[
  result := self class new.
  result addAll: self ; addAll: aCharOrCharColl .
  ^ result
  ].
aCharOrCharColl _validateClasses: #[ AbstractCharacter, CharacterCollection].
^ super , aCharOrCharColl
%

category: 'Converting'
method: DoubleByteString
asDoubleByteSymbol

"Returns a symbol representation of the receiver."

^ DoubleByteSymbol withAll: self.
%

category: 'Converting'
method: DoubleByteString
_asString

"Returns a (single byte) String representation of the receiver if all of the
 Characters in the receiver can be represented as single-byte Characters.
 Returns nil if any of the Characters in the receiver cannot be represented as
 single-byte Characters."

<primitive: 229> 
^ self _primitiveFailed: #_asString .
%

category: 'Converting'
method: DoubleByteString
asString

"Returns a (single byte) String representation of the receiver if all of the
 Characters in the receiver can be represented as single-byte Characters.
 Otherwise, returns the receiver."

| result |
result := self _asString .
result == nil ifTrue:[ ^ self ].
^ result
%

category: 'Converting'
method: DoubleByteString
asSymbol

"Returns a canonical Symbol representation of the receiver."

^ Symbol withAll: self .
%

category: 'Converting'
method: DoubleByteString
asSymbolKind

"Returns a (single byte) Symbol representation of the receiver."

^ Symbol withAll: self 
%

! Fix 36125
category: 'Accessing'
method: DoubleByteString
wordAt: anIndex

"Returns the integer value of the Character at anIndex in the receiver."

^ (self at: anIndex) asciiValue
%
category: 'Updating'
method: DoubleByteString
wordAt: anIndex put: aValue

"Stores the integer value aValue in the character cell of the receiver
 specified by anIndex. Return aValue."

self at: anIndex put: (Character withValue: aValue) .
^ aValue
%

category: 'Accessing'
method: DoubleByteString
at: anIndex

"Returns the Character at anIndex."

<primitive: 435>

(anIndex _isInteger)
  ifTrue: [^ self _errorIndexOutOfRange: anIndex]
  ifFalse: [^ self _errorNonIntegerIndex: anIndex].
self _primitiveFailed: #at: .
self _uncontinuableError
%

category: 'Updating'
method: DoubleByteString
at: anIndex put: aChar

"(R) Stores aChar at the specified location and returns aChar."

<primitive: 436>

(aChar _class == Character) ifFalse:[
  aChar _validateClass: AbstractCharacter .
  ^ self at: anIndex put: aChar asCharacter
  ].
(anIndex _isInteger) ifTrue: [
  ((anIndex > (self size + 1)) _or: [anIndex <= 0]) ifTrue: [
    ^ self _errorIndexOutOfRange: anIndex
    ].
  ]
  ifFalse:[^ self _errorNonIntegerIndex: anIndex] .
self _primitiveFailed: #at:put:
%
category: 'Case-Sensitive Comparisons'
method: DoubleByteString
= aCharCollection

"Returns true if corresponding Characters in the receiver and argument are equal
 and aCharCollection is comparable with the receiver, and aCharCollection is
 not a kind of Symbol.  Returns false otherwise.

 The comparison for 'equal' is case-sensitive .

 Note that 'kind of Symbol' means either an instance of Symbol or instance of
 DoubleByteSymbol."

<primitive: 449>

(aCharCollection isKindOf: CharacterCollection)
   ifTrue:[ ^ aCharCollection = self]
   ifFalse:[ ^ false]
%

category: 'Accessing'
method: DoubleByteString
numArgs

"Returns the number of arguments the receiver would take, if the receiver were
 a message selector."

self isInfix ifTrue: [ ^1 ].
self isKeyword ifTrue: [ ^self occurrencesOf: $: ].
^0
%

category: 'Searching'
method: DoubleByteString
speciesForCollect

"(R) Returns a class, an instance of which should be used as the result
 of collect: or other projections applied to the receiver."

^ DoubleByteString
%

category: 'Adding'
method: DoubleByteString
add: aCharOrCharColl

"(R) Appends all of the elements of aCharOrCharColl to the receiver and returns
 aCharOrCharColl."

<primitive: 437> 

aCharOrCharColl _validateClass: CharacterCollection .
^ self add: aCharOrCharColl asDoubleByteString 
%

category: 'Adding'
method: DoubleByteString
addAll: aCharOrCharColl

"Equivalent to add: aCharOrCharColl."

<primitive: 437> 

aCharOrCharColl _validateClass: CharacterCollection .
^ self add: aCharOrCharColl asDoubleByteString 
%

category: 'Adding'
method: DoubleByteString
addLast: aCharOrCharColl

"Equivalent to add: aCharOrCharColl."

<primitive: 437> 

aCharOrCharColl _validateClass: CharacterCollection .
^ self add: aCharOrCharColl asDoubleByteString 
%

category: 'Accessing'
method: DoubleByteString
size

"Returns the number of double-byte Characters in the receiver, which is also
 half the number of bytes that the receiver occupies."

^ self _basicSize // 2.
%

category: 'Updating'
method: DoubleByteString
size: anInteger

"Changes the size of the receiver to anInteger.

 If anInteger is less than the current size of the receiver, the receiver is
 shrunk accordingly.  If anInteger is greater than the current size of the
 receiver, the receiver is extended and new elements are initialized to nil."

^ self _basicSize: anInteger * 2
%

category: 'Accessing'
method: DoubleByteString
valueAt: anIndex

"Returns the value of the (double-byte) Character at anIndex."

^ (self at: anIndex) asciiValue
%

category: 'Copying'
method: DoubleByteString
withLFs

"Returns a copy of the receiver with all back-slashes replaced by line-feeds."

^self copyReplaceAll: '\' with: (self class with: Character lf)
%

category: 'Private'
method: DoubleByteString
_at: anIndex equals: aCharCollection ignoreCase: aBoolean

"Returns true if aCharCollection is contained in the receiver, starting at
 anIndex.  Returns false otherwise.  The comparison is case-insensitive."

<primitive: 438>

anIndex _validateClass: Integer.
((anIndex <= 0) _or: [(anIndex > self size)])
ifTrue: [ ^ self _errorIndexOutOfRange: anIndex ].
aBoolean ifTrue:[ ^ self _primitiveFailed: #_at:equals:ignoreCase: ]
         ifFalse:[ ^ super at: anIndex equals: aCharCollection ].
%

category: 'Case-Insensitive Comparisons'
method: DoubleByteString
at: anIndex equalsNoCase: aCharCollection

"Returns true if aCharCollection is contained in the receiver, starting at
 anIndex.  Returns false otherwise.  The comparison is case-insensitive."

^ self _at: anIndex equals: aCharCollection ignoreCase: true
%

category: 'Case-Sensitive Comparisons'
method: DoubleByteString
at: anIndex equals: aCharCollection

"Returns true if aCharCollection is contained in the receiver, starting at
 anIndex.  Returns false otherwise.  The comparison is case-sensitive."

^ self _at: anIndex equals: aCharCollection ignoreCase: false
%

category: 'Case-Insensitive Comparisons'
method: DoubleByteString
< aCharCollection

"Returns true if the receiver collates before the argument.
 Returns false otherwise.

 The comparison is case-insensitive."

"The ASCII letters A and a collate the same.
   'A' < 'a' returns false.
   'A' < 'b' returns true. "

<primitive: 440>

aCharCollection _validateClass: CharacterCollection .
^ aCharCollection > self
%

category: 'Case-Insensitive Comparisons'
method: DoubleByteString
<= aCharCollection

"Returns true if the receiver collates before the argument or if all of the
 corresponding Characters in the receiver and argument are equal.
 Returns false otherwise.

 The comparison is consistent with that defined for the < method."

^(self > aCharCollection) not
%

category: 'Other Comparisons'
method: DoubleByteString
asciiLessThan: aString

"Returns true if the receiver collates before the argument using the
 ASCII collating table, which collates AB...Z...ab..z."

^ self lessThan: aString collatingTable: DoubleByteAsciiCollatingTable

%

category: 'Case-Insensitive Comparisons'
method: DoubleByteString
> aCharCollection

"Returns true if the receiver collates after the argument.  Returns false
 otherwise.

 The comparison is case-insensitive."

<primitive: 442>

aCharCollection _validateClass: CharacterCollection.
^ aCharCollection < self
%

category: 'Case-Insensitive Comparisons'
method: DoubleByteString
>= aCharCollection

"Returns true if the receiver collates after the argument or if all of the
 corresponding Characters in the receiver and argument are equal.
 Returns false otherwise.

 The comparison is consistent with that defined for the < method."

^ (self < aCharCollection) not
%

category: 'Other Comparisons'
method: DoubleByteString
lessThan: aString collatingTable: aTable

"Returns true if the receiver collates before the argument.

 The aString argument may be a String or a DoubleByteString.

 The collating sequence is defined by aTable, which must be an instance of
 DoubleByteString.  The argument aTable is accessed with wordAt: to retrieve the
 collating sequence for a particular Character.  Use wordAt:put: to populate it.
 Characters beyond the range of aTable are collated using their raw character
 value."

<primitive: 444 >

aTable _validateInstanceOf: DoubleByteString .
aString _validateClass: String .
self _primitiveFailed: #lessThan:collatingTable:
%

category: 'Other Comparisons'
method: DoubleByteString
greaterThan: aString collatingTable: aTable

"Returns true if the receiver collates after the argument.

 The aString argument may be a String or a DoubleByteString.

 The collating sequence is defined by aTable, which must be an instance of
 DoubleByteString.  The argument aTable is accessed with wordAt: to retrieve the
 collating sequence for a particular Character.  Use wordAt:put: to populate it.
 Characters beyond the range of aTable are collated using their raw character
 value."

<primitive: 445 >

aTable _validateInstanceOf: DoubleByteString .
aString _validateClass: String .
self _primitiveFailed: #greaterThan:collatingTable:
%

category: 'Other Comparisons'
method: DoubleByteString
greaterThanOrEqual: aString collatingTable: aTable

"Returns true if the receiver collates after or the same as the argument.

 The aString argument may be a String or a DoubleByteString.

 The collating sequence is defined by aTable, which must be an instance of
 DoubleByteString.  The argument aTable is accessed with wordAt: to retrieve the
 collating sequence for a particular Character.  Use wordAt:put: to populate it.
 Characters beyond the range of aTable are collated using their raw character
 value."

^ (self lessThan: aString collatingTable: aTable) not
%

category: 'Other Comparisons'
method: DoubleByteString
lessThanOrEqual: aString collatingTable: aTable

"Returns true if the receiver collates before or the same as the argument.

 The aString argument may be a String or a DoubleByteString.

 The collating sequence is defined by aTable, which must be an instance of
 DoubleByteString.  The argument aTable is accessed with wordAt: to retrieve the
 collating sequence for a particular Character.  Use wordAt:put: to populate it.
 Characters beyond the range of aTable are collated using their raw character
 value."

^ (self greaterThan: aString collatingTable: aTable) not
%

category: 'Other Comparisons'
method: DoubleByteString
equals: aString collatingTable: aTable

"Returns true if the receiver collates the same as the argument.

 The aString argument may be a String or a DoubleByteString.

 The collating sequence is defined by aTable, which must be an instance of
 DoubleByteString.  The argument aTable is accessed with wordAt: to retrieve the
 collating sequence for a particular Character.  Use wordAt:put: to populate it.
 Characters beyond the range of aTable are collated using their raw character
 value."

<primitive: 447 >

aTable _validateInstanceOf: DoubleByteString .
aString _validateClass: String .
self _primitiveFailed: #greaterThan:collatingTable:
%

category: 'Copying'
method: DoubleByteString
copyFrom: index1 to: index2 into: anObject startingAt: index3

"Copies the elements of the receiver between index1 and index2, inclusive, into
 anObject starting at index3, overwriting the previous contents.  If anObject is
 the same object as the receiver, the source and destination blocks may
 overlap.

 The argument anObject should be a SequenceableCollection."

<primitive: 439>

(index1 > index2)
  ifTrue: [ ^ index1 _error: #rtErrBadCopyFromTo args: #[index2]].

(index1 < 1)
  ifTrue: [ ^ self _errorIndexOutOfRange: index1].

(index2 > self size)
  ifTrue: [ ^ self _errorIndexOutOfRange: index2].

((index3 < 1) _or: [(index3 > (anObject size + 1))])
  ifTrue: [ ^ anObject _errorIndexOutOfRange: index3].

^ super copyFrom: index1
              to: index2
            into: anObject
      startingAt: index3.
%

! deleted _idxCompareLessThan: v2.0

!deleted _idxCompareGreaterThan: v2.0

category: 'Case-Insensitive Comparisons'
method: DoubleByteString
equalsNoCase: aCharCollection

"Returns true if corresponding Characters in the receiver and argument are equal
 and aCharCollection is comparable with the receiver, and aCharCollection is
 not a kind of Symbol.  Returns false otherwise.

 The comparison for equal is case-insensitive.

 Note that 'kind of Symbol' means either an instance of Symbol or instance of
 DoubleByteSymbol."

<primitive: 450>

(aCharCollection isKindOf: String) ifTrue:[
  self _primitiveFailed: #equalsNoCase: .
  ^ self _uncontinuableError
  ].
^super isEquivalent: aCharCollection
%

category: 'Case-Insensitive Comparisons'
method: DoubleByteString
isEquivalent: aCharCollection
    "Returns true if the receiver is equivalent to aCharCollection.
    The receiver is equivalent to aCharCollection if the receiver
    contains the same Characters as aCharCollection regardless of case
    or internal representation.  For example, if $a is in
    aCharCollection, it is equivalent to any representation of an 'a'
    in the receiver's character set."

    ^self equalsNoCase: aCharCollection
%

category: 'Private'
method: DoubleByteString
_findSmallString: subString startingAt: startIndex ignoreCase: aBoolean

"If a receiver contains subString beginning at some point at or after
 startIndex, this returns the index at which subString begins.  If the
 receiver does not contain subString, this returns 0."

<primitive: 451>

startIndex _validateClass: Integer.
(startIndex < 1) | (startIndex > self size)
ifTrue: [ ^ self _error: #objErrBadOffsetIncomplete args: #[startIndex] ].
subString _validateClasses:[ String, DoubleByteString ].
subString basicSize > 16272  "virtual machine constant, OBJ_BYTES_SIZE" ifTrue:[
  subString _halt: 'String too large for string search primitive.'
  ].
aBoolean _validateClass: Boolean .
^ self _primitiveFailed: #_findSmallString:startingAt:
%

category: 'Case-Sensitive Searching'
method: DoubleByteString
includesValue: aCharacter

"Returns true if the receiver contains aCharacter.  The search is
 case-sensitive."

<primitive: 452>

"the following code is executed if aCharacter is a JISCharacter "

aCharacter _validateClass: AbstractCharacter .
^ self includesValue: aCharacter asCharacter .
%

category: 'Case-Sensitive Searching'
method: DoubleByteString
indexOf: aCharacter startingAt: startIndex

"Returns the index of the first occurrence of aCharacter in the receiver,
 not preceding startIndex.  If the receiver does not contain aCharacter,
 returns zero.

 The search is case sensitive."

<primitive: 453>
startIndex _validateClass: Integer .
startIndex < 1 ifTrue:[ ^ self _errorIndexOutOfRange: startIndex].
^ self indexOf: aCharacter asCharacter startingAt: startIndex
%

category: 'Adding'
method: DoubleByteString
insertAll: aCharOrCharColl at: anIndex

"Inserts aCharOrCharColl at the specified index.  Returns aCharOrCharColl."

<primitive: 454>

anIndex _validateClass: Integer .
((anIndex <= 0) _or: [anIndex > (self size + 1)])
  ifTrue: [ ^ self _errorIndexOutOfRange: anIndex].

aCharOrCharColl _validateClasses: #[AbstractCharacter, CharacterCollection].
^self insertAll: aCharOrCharColl asDoubleByteString at: anIndex.
%

category: 'Converting'
method: DoubleByteString
asUppercase

"Returns a new instance of the receiver's class, with all lower-case Characters
 in the receiver changed to upper-case.  Lower-case Characters are the
 ASCII characters $a to $z inclusive.  If the receiver is a DoubleByteSymbol, 
 returns an instance of DoubleByteString."

<primitive: 455>

self _primitiveFailed: #asUppercase .
self _uncontinuableError
%

! finish fixing 9288
category: 'Execution'
method: DoubleByteString
_compileInContext: anObject symbolList: aSymbolList

"Returns a GsMethod that is not in the method dictionary of any class, or
 else generates an error if there are compilation errors."

<primitive: 150>

aSymbolList _validateClass: SymbolList .
^ self _primitiveFailed: #_compileInContext:symbolList:
%

category: 'Execution'
method: DoubleByteString
evaluate

"Compiles the receiver as an unbound method and executes it using the current
 default symbol list."

^ (self _compileInContext: nil 
       symbolList: GsSession currentSession symbolList)
  _executeInContext: nil
%

category: 'Execution'
method: DoubleByteString
evaluateInContext: anObject symbolList: aSymbolList

"Compiles the receiver as an instance method for the class of anObject, using
 aSymbolList as the symbol list.  Executes the resulting GsMethod using anObject
 as self and returns the result of the execution.  Generates an error if
 compilation errors occur."

^ (self _compileInContext: anObject symbolList: aSymbolList)
    _executeInContext: anObject
%

category: 'Hashing'
method: DoubleByteString
hash

"Returns a positive Integer based on a case-sensitive hash of the contents 
 of the receiver."

"The algorithm implemented is described in:

 [Pearson 90]
 Pearson, Peter K., Fast Hashing of Variable-Length Text Strings,
 Communications of the ACM 33, 6, (June 1990), 677-680."

<primitive: 282>
self _primitiveFailed: #hash .
self _uncontinuableError
%

category: 'Storing and Loading'
classmethod: DoubleByteString
loadFrom: passiveObj

"Reads from passiveObj the passive form of an object.  Converts the object to
 its active form by loading the information into a new instance of the receiver.
 Returns the new instance."

| inst |

inst := String new: passiveObj readSize . "yes, make a String !!"
inst loadFrom: passiveObj.
inst _changeClassToDoubleByte: self .  "Now change to double byte"
^inst
%

category: 'Storing and Loading'
method: DoubleByteString
writeTo: passiveObj

"Converts the receiver to its passive form and writes that information on
 passiveObj."

passiveObj writeClass: self class;
  writeSize: self _basicSize;
    nextPutAllBytes: self; space
%
category: 'Removing'
method: DoubleByteString
removeFrom: startIndex to: stopIndex

"(R) Deletes the elements of the receiver from startIndex to stopIndex.  The
 size of the receiver is decreased by stopIndex - startIndex + 1.

 Both startIndex and stopIndex must be positive integers not larger than the
 size of the receiver, with startIndex <= stopIndex."

<primitive: 271>

(stopIndex < startIndex)
ifTrue:
   [ ^ startIndex _error: #rtErrBadCopyFromTo args: #[stopIndex]].
((stopIndex > self size) _or: [(stopIndex < 1)])
   ifTrue: [ ^ self _errorIndexOutOfRange: stopIndex].
(startIndex < 1)
   ifTrue: [ ^ self _errorIndexOutOfRange: startIndex].
^ self _primitiveFailed: #removeFrom:to:
%
category: 'Indexing Support'
method: DoubleByteString
_changingSizeTo: newSize
 
"Notifies any modification tracking objects that the receiver (an indexable
 object) is having its size changed."
 
"the object manager reports size changes in number of bytes; convert this
 to number of characters."

^ super _changingSizeTo: newSize // 2
%
category: 'Testing'
method: DoubleByteString
containsSeparator

"Returns true if the receiver contains a separator Character."

1 to: self size do: [:i |
  (self at: i) isSeparator ifTrue: [^true].
].
^false
%

category: 'New Indexing Comparison'
method: DoubleByteString
_idxForCompareEqualTo: arg

""

^arg _idxForCompareEqualToDoubleByteString: self
%

category: 'New Indexing Comparison - prims'
method: DoubleByteString
_idxPrimCompareLessThan: aCharCollection

"This comparison operation is used for the indexing subsystem to
 determine an ordering for insertion into indexing objects.

 This method collates letters AaBb..Zz."

"The comparison should be compatible with the case-insensitive semantics
 of the String method with selector #< .
 Same primitive as String>>lessThan: "

<primitive: 441>

aCharCollection == nil ifTrue: [ ^ false ].
aCharCollection _validateClass: CharacterCollection.
^ aCharCollection > self
%

category: 'New Indexing Comparison - prims'
method: DoubleByteString
_idxPrimCompareGreaterThan: aCharCollection

"This comparison operation is used for the indexing subsystem to
 determine an ordering for insertion into indexing objects such as B-trees.

 This method collates letters AaBb..Zz."

"The comparison should be compatible with the case-insensitive semantics
 of the String method with selector #> .
 Same primitive as String>>greaterThan: ."

<primitive: 443>
aCharCollection == nil ifTrue: [ ^ true ].
aCharCollection _validateClass: CharacterCollection.
^ aCharCollection < self
%
