Property definitions

core $ FlatBuffer :: defaultinit
# Mutable strings of characters.
class FlatBuffer
	super FlatText
	super Buffer

	redef fun chars do return new FlatBufferCharView(self)

	redef fun bytes do return new FlatBufferByteView(self)

	private var capacity = 0

	redef fun fast_cstring do return _items.fast_cstring(0)

	redef fun substrings do return new FlatSubstringsIter(self)

	# Re-copies the `CString` into a new one and sets it as the new `Buffer`
	#
	# This happens when an operation modifies the current `Buffer` and
	# the Copy-On-Write flag `written` is set at true.
	private fun reset do
		var nns = new CString(capacity)
		if _byte_length != 0 then _items.copy_to(nns, _byte_length, 0, 0)
		_items = nns
		written = false
	end

	# Shifts the content of the buffer by `len` bytes to the right, starting at byte `from`
	#
	# Internal only, does not modify _byte_length or length, this is the caller's responsability
	private fun rshift_bytes(from: Int, len: Int) do
		var oit = _items
		var nit = _items
		var bt = _byte_length
		if bt + len > capacity then
			capacity = capacity * 2 + 2
			nit = new CString(capacity)
			oit.copy_to(nit, 0, 0, from)
		end
		oit.copy_to(nit, bt - from, from, from + len)
	end

	# Shifts the content of the buffer by `len` bytes to the left, starting at `from`
	#
	# Internal only, does not modify _byte_length or length, this is the caller's responsability
	private fun lshift_bytes(from: Int, len: Int) do
		var it = _items
		it.copy_to(it, _byte_length - from, from, from - len)
	end

	redef fun []=(index, item)
	do
		assert index >= 0 and index <= _length
		if written then reset
		if index == _length then
			add item
			return
		end
		var it = _items
		var ip = it.char_to_byte_index(index)
		var c = it.char_at(ip)
		var clen = c.u8char_len
		var itemlen = item.u8char_len
		var size_diff = itemlen - clen
		if size_diff > 0 then
			rshift_bytes(ip + clen, size_diff)
		else if size_diff < 0 then
			lshift_bytes(ip + clen, -size_diff)
		end
		_byte_length += size_diff
		it.set_char_at(ip, item)
	end

	redef fun insert(s, pos) do
		assert pos >= 0 and pos <= length
		if pos == length then
			append s
			return
		end
		var slen = s.byte_length
		enlarge(byte_length + slen)
		var it = _items
		var shpos = it.char_to_byte_index(pos)
		rshift_bytes(shpos, slen)
		s.copy_to_native(it, slen, 0, shpos)
		length += s.length
		byte_length += slen
	end

	redef fun insert_char(c, pos) do
		assert pos >= 0 and pos <= length
		if pos == length then
			add c
			return
		end
		var clen = c.u8char_len
		enlarge(byte_length + clen)
		var it = _items
		var shpos = it.char_to_byte_index(pos)
		rshift_bytes(shpos, clen)
		it.set_char_at(shpos, c)
		length += 1
		byte_length += clen
	end

	redef fun add(c)
	do
		if written then reset
		var clen = c.u8char_len
		var bt = _byte_length
		enlarge(bt + clen)
		_items.set_char_at(bt, c)
		_byte_length += clen
		_length += 1
	end

	redef fun clear do
		_byte_length = 0
		_length = 0
		if written then
			_capacity = 16
			reset
		end
	end

	redef fun empty do return new Buffer

	redef fun enlarge(cap)
	do
		var c = capacity
		if cap <= c then return
		if c <= 16 then c = 16
		while c <= cap do c = c * 2
		# The COW flag can be set at false here, since
		# it does a copy of the current `Buffer`
		written = false
		var bln = _byte_length
		var a = new CString(c)
		if bln > 0 then
			var it = _items
			if bln > 0 then it.copy_to(a, bln, 0, 0)
		end
		_items = a
		capacity = c
	end

	redef fun to_s
	do
		written = true
		var bln = _byte_length
		if bln == 0 then _items = new CString(1)
		return new FlatString.full(_items, bln, 0, _length)
	end

	redef fun to_cstring
	do
		var bln = _byte_length
		var new_native = new CString(bln + 1)
		new_native[bln] = 0
		if _length > 0 then _items.copy_to(new_native, bln, 0, 0)
		return new_native
	end

	# Create a new empty string.
	init do end

	# Low-level creation a new buffer with given data.
	#
	# `_items` will be used as is, without copy, to store the characters of the buffer.
	# Aliasing issues is the responsibility of the caller.
	#
	# If `_items` is shared, `written` should be set to true after the creation
	# so that a modification will do a copy-on-write.
	private init with_infos(items: CString, capacity, byte_length, length: Int)
	do
		self._items = items
		self.capacity = capacity
		self._byte_length = byte_length
		self._length = length
	end

	# Create a new string copied from `s`.
	init from(s: Text)
	do
		_items = new CString(s.byte_length)
		for i in s.substrings do i._items.copy_to(_items, i._byte_length, first_byte, 0)
		_byte_length = s.byte_length
		_length = s.length
		_capacity = _byte_length
	end

	# Create a new empty string with a given capacity.
	init with_capacity(cap: Int)
	do
		assert cap >= 0
		_items = new CString(cap)
		capacity = cap
		_byte_length = 0
	end

	redef fun append(s)
	do
		if s.is_empty then return
		var sl = s.byte_length
		var nln = _byte_length + sl
		enlarge(nln)
		if s isa FlatText then
			s._items.copy_to(_items, sl, s.first_byte, _byte_length)
		else
			for i in s.substrings do append i
			return
		end
		_byte_length = nln
		_length += s.length
	end

	# Copies the content of self in `dest`
	fun copy(start: Int, len: Int, dest: Buffer, new_start: Int)
	do
		var self_chars = self.chars
		var dest_chars = dest.chars
		for i in [0..len-1] do
			dest_chars[new_start+i] = self_chars[start+i]
		end
	end

	redef fun substring(from, count)
	do
		assert count >= 0
		if from < 0 then from = 0
		if (from + count) > _length then count = _length - from
		if count <= 0 then return new Buffer
		var its = _items
		var bytefrom = its.char_to_byte_index(from)
		var byteto = its.char_to_byte_index(count + from - 1)
		byteto += its.char_at(byteto).u8char_len - 1
		var byte_length = byteto - bytefrom + 1
		var r_items = new CString(byte_length)
		its.copy_to(r_items, byte_length, bytefrom, 0)
		return new FlatBuffer.with_infos(r_items, byte_length, byte_length, count)
	end

	redef fun append_substring_impl(s, from, length) do
		if length <= 0 then return
		if not s isa FlatText then
			super
			return
		end
		var sits = s._items
		var bytest = s.char_to_byte_index(from)
		var bytend = s.char_to_byte_index(from + length - 1)
		var btln = bytend - bytest + sits.char_at(bytend).u8char_len
		enlarge(btln + _byte_length)
		sits.copy_to(_items, btln, bytest, _byte_length)
		_byte_length += btln
		_length += length
	end

	redef fun remove_at(p, len) do
		if len == null then len = 1
		if len == 0 then return
		var its = _items
		var bst = char_to_byte_index(p)
		var bend = char_to_byte_index(p + len - 1)
		bend += its.char_at(bend).u8char_len
		var blen = bend - bst
		lshift_bytes(bend, bend - bst)
		byte_length -= blen
		length -= len
	end

	redef fun reverse
	do
		written = false
		var ns = new FlatBuffer.with_capacity(capacity)
		for i in chars.reverse_iterator do ns.add i
		_items = ns._items
	end

	redef fun times(repeats)
	do
		var bln = _byte_length
		var x = new FlatString.full(_items, bln, 0, _length)
		for i in [1 .. repeats[ do
			append(x)
		end
	end

	redef fun upper
	do
		if written then reset
		for i in [0 .. _length[ do self[i] = self[i].to_upper
	end

	redef fun lower
	do
		if written then reset
		for i in [0 .. _length[ do self[i] = self[i].to_lower
	end
end
lib/core/text/flat.nit:865,1--1163,3