note
	description: "Summary description for {NUMBER_ACCESS}."
	author: "Colin LeMahieu"
	date: "$Date: 2011-11-11 18:13:16 +0100 (ven., 11 nov. 2011) $"
	revision: "$Revision: 87787 $"
	quote: "State-mandated compassion produces, not love for ones fellow man, but hatred and resentment. -  Lizard"

deferred class
	SPECIAL_ACCESS

inherit
	LIMB_MANIPULATION
	MP_BASES
	SPECIAL_ARITHMETIC
	SPECIAL_DIVISION

feature

	dc_get_str (target_a: STRING_8; target_offset_a: INTEGER; len_a: INTEGER; op1: SPECIAL [NATURAL_32]; op1_offset: INTEGER; op1_count: INTEGER; powtab: SPECIAL [POWERS]; powtab_offset: INTEGER; tmp: SPECIAL [NATURAL_32]; tmp_offset: INTEGER): INTEGER
		local
			target: STRING_8
			len: INTEGER
			pwp: SPECIAL [NATURAL_32]
			pwp_offset: INTEGER
			qp: SPECIAL [NATURAL_32]
			qp_offset: INTEGER
			rp: SPECIAL [NATURAL_32]
			rp_offset: INTEGER
			pwn: INTEGER
			qn: INTEGER
			target_offset: INTEGER
		do
			target := target_a
			len := len_a
			target_offset := target_offset_a
			if op1_count < 15 then
				if op1_count /= 0 then
					target_offset := sb_get_str (target, target_offset, len, op1, op1_offset, op1_count, powtab, powtab_offset)
				else
					from
					until
						len /= 0
					loop
						target [target_offset] := '%U'
						target_offset := target_offset + 1
						len := len - 1
					end
				end
			else
				pwp := powtab [powtab_offset].p
				pwn := powtab [powtab_offset].n
				if op1_count < pwn or (op1_count = pwn and cmp (op1, op1_offset, pwp, pwp_offset, op1_count) < 0) then
					target_offset := dc_get_str (target, target_offset, len, op1, op1_offset, op1_count, powtab, powtab_offset - 1, tmp, tmp_offset)
				else
					qp := tmp
					qp_offset := tmp_offset
					rp := op1
					rp_offset := op1_offset
					tdiv_qr (qp, qp_offset, rp, rp_offset, op1, op1_offset, op1_count, pwp, pwp_offset, pwn)
					qn := op1_count - pwn
					qn := qn + (qp [qp_offset + qn] /= 0).to_integer
					if len /= 0 then
						len := len - powtab [powtab_offset].digits_in_base
					end
					target_offset := dc_get_str (target, target_offset, len, qp, qp_offset, qn, powtab, powtab_offset - 1, tmp, tmp_offset + op1_count - pwn + 1)
					target_offset := dc_get_str (target, target_offset, powtab [powtab_offset].digits_in_base, rp, rp_offset, pwn, powtab, powtab_offset - 1, tmp, tmp_offset)
				end
			end
			Result := target_offset
		end

	get_str (target: STRING_8; target_offset: INTEGER; base: INTEGER; op1: SPECIAL [NATURAL_32]; op1_offset: INTEGER; op1_count: INTEGER): INTEGER
		local
			powtab_mem_ptr: SPECIAL [NATURAL_32]
			powtab_mem_ptr_offset: INTEGER
			big_base_l: NATURAL_32
			digits_in_base: INTEGER
			powtab: SPECIAL [POWERS]
			pi: INTEGER
			n: INTEGER
			t: INTEGER
			p: SPECIAL [NATURAL_32]
			p_offset: INTEGER
			n1: NATURAL_32
			n0: NATURAL_32
			bits_per_digit: INTEGER
			count: INTEGER
			bit_pos: INTEGER
			i: INTEGER
			s: INTEGER
			bits: INTEGER
		do
			if op1_count = 0 then
				target [target_offset] := '%U'
				Result := 1
			else
				if pow2_p (base.to_natural_32) then
					bits_per_digit := big_base (base).to_integer_32
					s := target_offset
					n1 := op1 [op1_offset + op1_count - 1]
					count := leading_zeros (n1)
					bits := limb_bits * op1_count - count
					count := bits \\ bits_per_digit
					if count /= 0 then
						bits := bits + bits_per_digit - count
					end
					bit_pos := bits - (op1_count - 1) * limb_bits
					from
						i := op1_count - 1
					until
						i < 0
					loop
						bit_pos := bit_pos - bits_per_digit
						from
						until
							bit_pos < 0
						loop
							target [s] := ((n1 |>> bit_pos).bit_and (((1).to_natural_32 |<< bits_per_digit) - 1)).to_character_8
							s := s + 1
							bit_pos := bit_pos - bits_per_digit
						end
						i := i - 1
						if i >= 0 then
							n0 := (n1 |<< -bit_pos).bit_and (((1).to_natural_32 |<< bits_per_digit) - 1)
							n1 := op1 [op1_offset + i]
							bit_pos := bit_pos + limb_bits
							target [s] := (n0.bit_or (n1 |>> bit_pos)).to_character_8
							s := s + 1
						end
					end
					Result := s - target_offset
				else
					if op1_count < 30 then
						create powtab.make_empty (1)
						create p.make_empty (0)
						powtab.extend (create {POWERS}.make (0, p, 0, 0, base))
						Result := sb_get_str (target, target_offset, 0, op1, op1_offset, op1_count, powtab, 0)
					else
						create powtab_mem_ptr.make_filled (0, 2 * op1_count + 30)
						big_base_l := big_base (base)
						digits_in_base := chars_per_limb (base)
						create powtab.make_empty (30)
						create p.make_filled (0, 0)
						powtab.extend (create {POWERS}.make (0, p, 0, 0, base))
						create p.make_filled (big_base_l, 1)
						powtab.extend (create {POWERS}.make (digits_in_base, p, 0, 1, base))
						create p.make_filled (big_base_l, 1)
						powtab.extend (create {POWERS}.make (digits_in_base, p, 0, 1, base))
						n := 1
						pi := 2
						create p.make_filled (big_base_l, 1)
						p_offset := 0
						from
						until
							2 * n > op1_count
						loop
							pi := pi + 1
							t := powtab_mem_ptr_offset
							powtab_mem_ptr_offset := powtab_mem_ptr_offset + 2 * n
							sqr_n (powtab_mem_ptr, t, p, p_offset, n)
							n := n * 2
							n := n - (powtab_mem_ptr [t + n - 1] = 0).to_integer
							digits_in_base := digits_in_base * 2
							powtab_mem_ptr_offset := t
							powtab.extend (create {POWERS}.make (digits_in_base, p, 0, n, base))
						end
					end
				end
			end
		end

	sb_get_str (target: STRING_8; target_offset_a: INTEGER; len_a: INTEGER; op1: SPECIAL [NATURAL_32]; op1_offset: INTEGER; op1_count_a: INTEGER; powtab: SPECIAL [POWERS]; powtab_offset: INTEGER): INTEGER
		local
			rl: CELL [NATURAL_32]
			ul: CELL [NATURAL_32]
			s: INTEGER
			base: INTEGER
			l: INTEGER
			buf: SPECIAL [NATURAL_8]
			buf_offset: INTEGER
			rp: SPECIAL [NATURAL_32]
			rp_offset: INTEGER
			buff_alloc: INTEGER
			op1_count: INTEGER
			i: INTEGER
			frac: CELL [NATURAL_32]
			digit: CELL [NATURAL_32]
			junk: NATURAL_32
			chars_per_limb_l: INTEGER
			big_base_l: NATURAL_32
			big_base_inverted_l: NATURAL_32
			normalization_steps: INTEGER
			target_offset: INTEGER
			len: INTEGER
		do
			create digit.put (0)
			create frac.put (0)
			create ul.put (0)
			create rl.put (0)
			len := len_a
			target_offset := target_offset_a
			op1_count := op1_count_a
			buff_alloc := 30 * 8 * 4 * 7 // 11
			create buf.make_filled (0, buff_alloc)
			create rp.make_filled (0, 30)
			base := powtab [powtab_offset].base
			chars_per_limb_l := chars_per_limb (base)
			big_base_l := big_base (base)
			big_base_inverted_l := big_base_inverted (base)
			normalization_steps := leading_zeros (big_base_l)
			rp.copy_data (op1, op1_offset, rp_offset + 1, op1_count)
			s := buf_offset + buff_alloc
			from
			until
				op1_count <= 1
			loop
				junk := preinv_divrem_1 (rp, rp_offset, 1, rp, rp_offset + 1, op1_count, big_base_l, big_base_inverted_l, normalization_steps)
				op1_count := op1_count - (rp [rp_offset + op1_count] = 0).to_integer
				frac.put (rp [rp_offset] + 1)
				s := s - chars_per_limb_l
				i := chars_per_limb_l
				from
				until
					i = 0
				loop
					umul_ppmm (digit, frac, frac.item, base.to_natural_32)
					buf [s] := digit.item.to_natural_8
					s := s + 1
					i := i - 1
				end
				s := s - chars_per_limb_l
			end
			ul.put (rp [rp_offset + 1])
			from
			until
				ul.item = 0
			loop
				udiv_qrnd_unnorm (ul, rl, ul.item, base.to_natural_32)
				s := s - 1
				buf [s] := rl.item.to_natural_8
			end
			l := buf_offset + buff_alloc - s
			from
			until
				l >= len
			loop
				target [target_offset] := '%U'
				target_offset := target_offset + 1
				len := len - 1
			end
			from
			until
				l = 0
			loop
				target [target_offset] := buf [s].to_character_8
				s := s + 1
				target_offset := target_offset + 1
				l := l - 1
			end
			Result := target_offset - target_offset_a
		end
end
