Property definitions

core $ FlatString :: defaultinit
# Immutable strings of characters.
abstract class FlatString
	super FlatText
	super String

	# Index at which `self` begins in `_items`, inclusively
	redef var first_byte is noinit

	redef fun chars do return new FlatStringCharView(self)

	redef fun bytes do return new FlatStringByteView(self)

	redef fun to_cstring do
		var blen = _byte_length
		var new_items = new CString(blen + 1)
		_items.copy_to(new_items, blen, _first_byte, 0)
		new_items[blen] = 0
		return new_items
	end

	redef fun reversed do
		var b = new FlatBuffer.with_capacity(_byte_length + 1)
		var i = _length - 1
		while i >= 0 do
			b.add self.fetch_char_at(i)
			i -= 1
		end
		var s = b.to_s.as(FlatString)
		s._length = self._length
		return s
	end

	redef fun fast_cstring do return _items.fast_cstring(_first_byte)

	redef fun substring(from, count)
	do
		if count <= 0 then return ""

		if from < 0 then
			count += from
			if count <= 0 then return ""
			from = 0
		end

		var ln = _length
		if (count + from) > ln then count = ln - from
		if count <= 0 then return ""
		var end_index = from + count - 1
		return substring_impl(from, count, end_index)
	end

	private fun substring_impl(from, count, end_index: Int): String do
		var cache = _position
		var dfrom = (cache - from).abs
		var dend = (end_index - from).abs

		var bytefrom: Int
		var byteto: Int
		if dfrom < dend then
			bytefrom = char_to_byte_index(from)
			byteto = char_to_byte_index(end_index)
		else
			byteto = char_to_byte_index(end_index)
			bytefrom = char_to_byte_index(from)
		end

		var its = _items
		byteto += its.length_of_char_at(byteto) - 1

		var s = new FlatString.full(its, byteto - bytefrom + 1, bytefrom, count)
		return s
	end

	redef fun empty do return "".as(FlatString)

	redef fun to_upper
	do
		var outstr = new FlatBuffer.with_capacity(self._byte_length + 1)

		var mylen = _length
		var pos = 0

		while pos < mylen do
			outstr.add(chars[pos].to_upper)
			pos += 1
		end

		return outstr.to_s
	end

	redef fun to_lower
	do
		var outstr = new FlatBuffer.with_capacity(self._byte_length + 1)

		var mylen = _length
		var pos = 0

		while pos < mylen do
			outstr.add(chars[pos].to_lower)
			pos += 1
		end

		return outstr.to_s
	end

	redef fun output
	do
		for i in chars do i.output
	end

	##################################################
	#              String Specific Methods           #
	##################################################

	# Low-level creation of a new string with minimal data.
	#
	# `_items` will be used as is, without copy, to retrieve the characters of the string.
	# Aliasing issues is the responsibility of the caller.
	private new with_infos(items: CString, byte_length, from: Int)
	do
		var len = items.utf8_length(from, byte_length)
		if byte_length == len then return new ASCIIFlatString.full_data(items, byte_length, from, len)
		return new UnicodeFlatString.full_data(items, byte_length, from, len)
	end

	# Low-level creation of a new string with all the data.
	#
	# `_items` will be used as is, without copy, to retrieve the characters of the string.
	# Aliasing issues is the responsibility of the caller.
	private new full(items: CString, byte_length, from, length: Int)
	do
		if byte_length == length then return new ASCIIFlatString.full_data(items, byte_length, from, length)
		return new UnicodeFlatString.full_data(items, byte_length, from, length)
	end

	redef fun ==(other)
	do
		if not other isa FlatText then return super

		if self.object_id == other.object_id then return true

		var my_length = _byte_length

		if other._byte_length != my_length then return false

		var my_index = _first_byte
		var its_index = other.first_byte

		var last_iteration = my_index + my_length

		var its_items = other._items
		var my_items = self._items

		while my_index < last_iteration do
			if my_items[my_index] != its_items[its_index] then return false
			my_index += 1
			its_index += 1
		end

		return true
	end

	redef fun <(other)
	do
		if not other isa FlatText then return super

		if self.object_id == other.object_id then return false

		var myits = _items
		var itsits = other._items

		var mbt = _byte_length
		var obt = other.byte_length

		var minln = if mbt < obt then mbt else obt
		var mst = _first_byte
		var ost = other.first_byte

		for i in [0 .. minln[ do
			var my_curr_char = myits[mst]
			var its_curr_char = itsits[ost]

			if my_curr_char > its_curr_char then return false
			if my_curr_char < its_curr_char then return true

			mst += 1
			ost += 1
		end

		return mbt < obt
	end

	redef fun +(o) do
		var s = o.to_s
		var slen = s.byte_length
		var mlen = _byte_length
		var nlen = mlen + slen
		var mits = _items
		var mifrom = _first_byte
		if s isa FlatText then
			var sits = s._items
			var sifrom = s.first_byte
			var ns = new CString(nlen + 1)
			mits.copy_to(ns, mlen, mifrom, 0)
			sits.copy_to(ns, slen, sifrom, mlen)
			return new FlatString.full(ns, nlen, 0, _length + o.length)
		else
			abort
		end
	end

	redef fun *(i) do
		var mybtlen = _byte_length
		var new_byte_length = mybtlen * i
		var mylen = _length
		var newlen = mylen * i
		var its = _items
		var fb = _first_byte
		var ns = new CString(new_byte_length + 1)
		ns[new_byte_length] = 0
		var offset = 0
		while i > 0 do
			its.copy_to(ns, mybtlen, fb, offset)
			offset += mybtlen
			i -= 1
		end
		return new FlatString.full(ns, new_byte_length, 0, newlen)
	end

	redef fun hash
	do
		if hash_cache == null then
			# djb2 hash algorithm
			var h = 5381
			var i = _first_byte

			var my_items = _items
			var max = last_byte

			while i <= max do
				h = (h << 5) + h + my_items[i].to_i
				i += 1
			end

			hash_cache = h
		end

		return hash_cache.as(not null)
	end

	redef fun substrings do return new FlatSubstringsIter(self)
end
lib/core/text/flat.nit:408,1--659,3