note
	description: "Functionality to query the status of an arbitrary precision integer"
	author: "Colin LeMahieu"
	date: "$Date: 2011-11-11 18:13:16 +0100 (ven., 11 nov. 2011) $"
	revision: "$Revision: 87787 $"
	quote: "The urge to save humanity is almost always a false front for the urge to rule. - H.L. Mencken"

deferred class
	READABLE_INTEGER_X

inherit
	ANY
		undefine
			default_create,
			is_equal,
			copy
		redefine
			out
		select
			out
		end

	DEBUG_OUTPUT
		undefine
			default_create,
			is_equal,
			copy,
			out
		redefine
			debug_output
		end

	NUMERIC
		rename
			plus as plus_value alias "+",
			minus as minus_value alias "-",
			product as product_value alias "*",
			quotient as quotient_value alias "/",
			opposite as opposite_value alias "-"
		undefine
			default_create,
			out
		redefine
			copy,
			is_equal
		end

	COMPARABLE
		undefine
			default_create,
			out
		redefine
			copy,
			is_equal,
			three_way_comparison
		end

	INTEGER_X_ASSIGNMENT
		rename
			add as add_special,
			sub as sub_special,
			mul as mul_special,
			bit_xor_lshift as bit_xor_lshift_special,
			bit_xor as bit_xor_special
		export
			{NONE}
				all
		undefine
			default_create,
			is_equal,
			copy,
			out
		end

	INTEGER_X_ACCESS
		rename
			add as add_special,
			sub as sub_special,
			mul as mul_special,
			cmp as cmp_special,
			tdiv_qr as tdiv_qr_special,
			sizeinbase as sizeinbase_special,
			bit_xor_lshift as bit_xor_lshift_special,
			bit_xor as bit_xor_special
		export
			{NONE}
				all
		undefine
			default_create,
			is_equal,
			copy,
			out
		end

	INTEGER_X_ARITHMETIC
		rename
			abs as abs_integer_x,
			cmp as cmp_special,
			bit_xor_lshift as bit_xor_lshift_special,
			bit_xor as bit_xor_special
		export
			{NONE}
				all
		undefine
			default_create,
			is_equal,
			copy,
			out
		end

	INTEGER_X_COMPARISON
		export
			{NONE}
				all
		undefine
			default_create,
			is_equal,
			copy,
			out
		end

	INTEGER_X_LOGIC
		rename
			add as add_special,
			sub as sub_special,
			mul as mul_special,
			bit_and as bit_and_integer_x,
			bit_complement as bit_complement_integer_x,
			bit_or as bit_or_integer_x,
			bit_test as bit_test_integer_x,
			bit_xor as bit_xor_integer_x,
			bit_xor_lshift as bit_xor_lshift_integer_x
		export
			{NONE}
				all
		undefine
			default_create,
			is_equal,
			copy,
			out
		end

	INTEGER_X_IO
		rename
			sizeinbase as sizeinbase_special
		export
			{NONE}
				all
		undefine
			default_create,
			is_equal,
			copy,
			out
		end

	INTEGER_X_RANDOM
		rename
			add as add_special,
			sub as sub_special,
			mul as mul_special,
			cmp as cmp_special,
			bit_xor_lshift as bit_xor_lshift_special,
			bit_xor as bit_xor_special
		export
			{NONE}
				all
		undefine
			default_create,
			is_equal,
			copy,
			out
		end

	INTEGER_X_SIZING
		export
			{NONE}
				all
		undefine
			default_create,
			is_equal,
			copy,
			out
		end

	INTEGER_X_NUMBER_THEORY
		rename
			abs as abs_integer_x,
			mod as mod_integer_x,
			gcd as gcd_integer_x,
			bit_and as bit_and_integer_x,
			bit_complement as bit_complement_integer_x,
			bit_or as bit_or_integer_x,
			bit_test as bit_test_integer_x,
			bit_xor as bit_xor_integer_x,
			powm as powm_integer_x,
			bit_xor_lshift as bit_xor_lshift_integer_x,
			invert_gf as invert_gf_integer_x
		export
			{NONE}
				all
		undefine
			default_create,
			is_equal,
			copy,
			out
		end

	INTEGER_X_DIVISION
		rename
			abs as abs_integer_x,
			cmp as cmp_special,
			mod as mod_integer_x,
			bit_xor_lshift as bit_xor_lshift_special,
			bit_xor as bit_xor_special
		export
			{NONE}
				all
		undefine
			default_create,
			is_equal,
			copy,
			out
		end

	SPECIAL_UTILITY
		export
			{INTEGER_X_FACILITIES}
				all
		undefine
			default_create,
			is_equal,
			copy,
			out
		end

feature {NONE} -- Initialization

	default_create
			-- Initialize `Current' to zero
		do
			create item.make_filled (0, 1)
			count := 0
		ensure then
			zero: is_zero
		end

	make_set (other: READABLE_INTEGER_X)
			-- Initialize `Current' to be a copy of `other'
		do
			create item.make_filled (0, 0)
			set_from_other (other)
		ensure
			equal: Current ~ other
		end

	make_from_integer (i: INTEGER)
			-- Initialize `Current' from `i'.
		do
			default_create
			set_from_integer (i)
		ensure
			set: as_integer = i
		end

	make_from_integer_64 (i: INTEGER_64)
			-- Initialize `Current' from `i'.
		do
			default_create
			set_from_integer_64 (i)
		ensure
			set: as_integer_64 = i
		end

	make_from_integer_32 (i: INTEGER_32)
			-- Initialize `Current' from `i'.
		do
			default_create
			set_from_integer_32 (i)
		ensure
			set: as_integer_32 = i
		end

	make_from_integer_16 (i: INTEGER_16)
			-- Initialize `Current' from `i'.
		do
			default_create
			set_from_integer_16 (i)
		ensure
			set: as_integer_16 = i
		end

	make_from_integer_8 (i: INTEGER_8)
			-- Initialize `Current' from `i'.
		do
			default_create
			set_from_integer_8 (i)
		ensure
			set: as_integer_8 = i
		end

	make_from_natural (n: NATURAL)
			-- Initialize `Current' from `n'.
		do
			default_create
			set_from_natural (n)
		ensure
			set: as_natural = n
		end

	make_from_natural_64 (n: NATURAL_64)
			-- Initialize `Current' from `n'.
		do
			default_create
			set_from_natural_64 (n)
		ensure
			set: as_natural_64 = n
		end

	make_from_natural_32 (n: NATURAL_32)
			-- Initialize `Current' from `n'.
		do
			default_create
			set_from_natural_32 (n)
		ensure
			set: as_natural_32 = n
		end

	make_from_natural_16 (n: NATURAL_16)
			-- Initialize `Current' from `n'.
		do
			default_create
			set_from_natural_16 (n)
		ensure
			set: as_natural_16 = n
		end

	make_from_natural_8 (n: NATURAL_8)
			-- Initialize `Current' from `n'.
		do
			default_create
			set_from_natural_8 (n)
		ensure
			set: as_natural_8 = n
		end

	make_from_string (s: STRING)
			-- Initialize `Current' from `s' where `s' is a base 10 string
		require
			s_not_empty: not s.is_empty
		do
			default_create
			set_str (Current, s, 10)
		end

	make_from_hex_string (s: STRING)
			-- Initialize `Current' from `s' where `s' is a base 16 string
		require
			s_not_empty: not s.is_empty
		do
			default_create
			set_str (Current, s, 16)
		end

	make_from_string_base (s: STRING base: INTEGER)
			-- Initialize `Current' from `s' where `s' is a string of base `base'
		require
			s_not_empty: not s.is_empty
			base_too_small: base >= 2
			base_too_big: base <= 62
		do
			default_create
			set_str (Current, s, base)
		end

	make_random (bits_a: INTEGER)
			-- Initialize as a random number of `bits_a' bits
		require
			valid_bits: bits_a > 0
		do
			default_create
			set_random (bits_a)
		ensure
			correct_bits: bits <= bits_a
		end

	make_random_prime (bits_a: INTEGER)
			-- Initialise a random number of `bits_a' bits that is probably prime
		require
			valid_bits: bits_a > 0
		do
			default_create
			from
				set_random (bits_a)
			until
				is_probably_prime
			loop
				set_random (bits_a)
			end
		ensure
			prime: is_probably_prime
			correct_bits: bits <= bits_a
		end

	make_from_bytes (bytes_array: SPECIAL[NATURAL_8] first: INTEGER last: INTEGER)
			-- Initialize from byte array
		require
			last_after_first: last >= first
			valid_offset: bytes_array.valid_index (first)
			valid_end: bytes_array.valid_index (last)
		do
			default_create
			input (Current, last - first + 1, 1, 1, -1, bytes_array, first)
		end

	make_random_max (max_value: like Current)
			--Generate a uniform random integer in the range 0 to max_value-1, inclusive.
		require
			positive_max: max_value.is_positive
		do
			default_create
			urandomm (Current, random_state, max_value)
		ensure
			valid_range: Current < max_value
		end

	make_limbs (limbs: INTEGER)
			-- Initialize `Current' with space for `limbs' limbs in the internal representation
		do
			create item.make_filled (0, limbs)
			count := 0
		ensure
			is_zero
		end

	make_bits (bits_a: INTEGER)
		do
			create item.make_filled (0, (bits_a + (limb_bits - 1)) // limb_bits)
			count := 0
		ensure
			is_zero
		end

feature -- Constants

	one: like Current
			-- Neutral element for "*" and "/"
		deferred
		end

	zero: like Current
			-- Neutral element for "+" and "-"
		deferred
		end

feature -- Comparison

	is_less alias "<" (other: like Current): BOOLEAN
			-- Is current object less than `other'?
		do
			Result := three_way_comparison (other) < 0
		end

	is_equal (other: like Current): BOOLEAN
			-- Is `other' attached to an object considered
			-- equal to current object?
		do
			Result := three_way_comparison (other) = 0
		end

	three_way_comparison (other: like Current): INTEGER
			-- Perform a three way comparison between `Current' and `other'
		do
			Result := compare (Current, other).three_way_comparison (0)
		end

feature -- Measurement

	bytes: INTEGER
			-- Minimum number of bytes the absolute value of this number would occupy
		do
			Result := (bits + 7).bit_and (0xfffffff8).bit_shift_right (3)
		end

	bits: INTEGER
			-- Minimum number of bits the absolute value of this number would occupy
		do
			Result := size_in_base (2)
		ensure
			valid_result: Result >= 1
		end

feature -- Status report

	divisible (other: like Current): BOOLEAN
			-- May `Current' be divided by `other'?
		do
			Result := not other.is_zero
		end

	exponentiable (other: NATURAL_32_REF): BOOLEAN
			-- May `Current' be elevated to the power `other'?
		do
			Result := True
		end

	fits_natural: BOOLEAN
			-- Does `Current' fit in a {NATURAL} without truncation?
		do
			Result := fits_natural_32
		end

	fits_natural_64: BOOLEAN
			-- Does `Current' fit in a {NATURAL_64} without truncation?
		local
			n: INTEGER
		do
			resize (2)
			n := count
			Result := n >= 0 and n <= 2
		end

	fits_natural_32: BOOLEAN
			-- Does `Current' fit in a {NATURAL_32} without truncation?
		local
			n: INTEGER
		do
			n := count
			Result := n = 0 or n = 1
		end

	fits_natural_16: BOOLEAN
			-- Does `Current' fit in a {NATURAL_16} without truncation?
		local
			n: INTEGER_32
		do
			n := count
			Result := n = 0 or (n = 1 and then item [0] <= (0).to_natural_16.max_value)
		end

	fits_natural_8: BOOLEAN
			-- Does `Current' fit in a {NATURAL_8} without truncation?
		local
			n: INTEGER_32
		do
			n := count
			Result := n = 0 or (n = 1 and then item [0] <= (0).to_natural_8.max_value)
		end

	fits_integer: BOOLEAN
			-- Does `Current' fit in an {INTEGER} without truncation?
		do
			Result := fits_integer_32
		end

	fits_integer_64: BOOLEAN
			-- Does `Current' fit in an {INTEGER_64} without truncation?
		local
			n: INTEGER
			limb1: NATURAL_32
			limb2: NATURAL_32
		do
			n := count
			limb1 := item [0]
			if n = 0 or n = 1 or n = -1 then
				Result := True
			elseif n = 2 then
				limb2 := item [1]
				Result := not limb2.bit_test (31)
			elseif n = -2 then
				limb2 := item [1]
				if limb2.bit_test (31) then
					Result := limb2.bit_and (0x7fffffff) = 0 and limb1 = 0
				else
					Result := True
				end
			end
		end

	fits_integer_32: BOOLEAN
			-- Does `Current' fit in an {INTEGER_32} without truncation?
		local
			n: INTEGER_32
			limb: NATURAL_32
		do
			n := count
			limb := item [0]
			if
				n = 0
			then
				Result := True
			elseif n = 1 then
				Result := not limb.bit_test (31)
			elseif n = -1 then
				if limb.bit_test (31) then
					Result := limb.bit_and (0x7fffffff) = 0
				else
					Result := True
				end
			end
		end

	fits_integer_16: BOOLEAN
			-- Does `Current' fit in an {INTEGER_16} without truncation?
		local
			n: INTEGER
			limb: NATURAL_32
		do
			n := count
			limb := item [0]
			if n = 0 then
				Result := True
			elseif n = 1 then
				Result := limb <= (0).to_integer_16.max_value.to_natural_32
			elseif n = -1 then
				Result := limb <= (0).to_integer_16.min_value.to_integer_32.abs.to_natural_32
			else
				Result := False
			end
		end

	fits_integer_8: BOOLEAN
			-- Does `Current' fit in an {INTEGER_8} without truncation?
		local
			n: INTEGER
			limb: NATURAL_32
		do
			n := count
			limb := item [0]
			if n = 0 then
				Result := True
			elseif n = 1 then
				Result := limb <= (0).to_integer_8.max_value.to_natural_32
			elseif n = -1 then
				Result := limb <= (0).to_integer_8.min_value.to_integer_32.abs.to_natural_32
			end
		end

	is_odd: BOOLEAN
			-- Is `Current' odd
		do
			Result := count /= 0 and then item [0].bit_test (0)
		end

	is_even: BOOLEAN
			-- Is `Current' even?
		do
			Result := not is_odd
		end

	is_zero: BOOLEAN
			-- Is `Current' equal to zero
		do
			Result := sign = 0
		end

	is_positive: BOOLEAN
			-- Is `Current' positive
		do
			Result := sign = 1
		end

	is_negative: BOOLEAN
			-- Is `Current' negative
		do
			Result := sign = -1
		end

	sign: INTEGER
			-- Return the sign of `Current' where -1 is negative, 0 is zero, and 1 is positive
		do
			Result := count.three_way_comparison (0)
		ensure
			is_positive implies (Result = 1)
			is_zero implies (Result = 0)
			is_negative implies (Result = -1)
		end

	size_in_base (base: INTEGER): INTEGER
			-- What is the size of the string representing the absolute value of `Current' in base `base'
		require
			base_too_small: base >= 2
			base_too_big: base <= 62
		do
			Result := sizeinbase (Current, base)
		end

feature -- Primality testing

	is_composite: BOOLEAN
			-- Is `Current' a composite number?
		do
			Result := probab_prime_p (Current, 10) = 0
		end

	is_prime: BOOLEAN
			-- Is `Current' definitely a prime number?
		do
			Result := probab_prime_p (Current, 10) = 2
		end

	is_probably_prime: BOOLEAN
			-- Is `Current' probably a prime number?
			-- May return `False' if `Current' is actually prime.
		do
			Result := probab_prime_p (Current, 10) > 0
		end

feature {INTEGER_X_FACILITIES}-- Element change

	set_from_other (other: READABLE_INTEGER_X)
		local
			other_count: INTEGER
		do
			other_count := other.count
			resize (other_count)
			item.copy_data (other.item, 0, 0, other_count)
			count := other_count
		end

	set_from_integer (value_a: INTEGER)
			-- Initialize `Current' from `value_a'.
		do
			set_from_integer_32 (value_a)
		ensure
			value_a > 0 implies count = 1
			value_a = 0 implies count = 0
			value_a < 0 implies count = -1
			fits_integer
			as_integer = value_a
		end

	set_from_integer_64 (value_a: INTEGER_64)
			-- Initialize `Current' from `value_a'
		local
			new_value: NATURAL_64
			upper_limb: NATURAL_32
			new_count: INTEGER
		do
			resize (2)
			new_value := value_a.abs.to_natural_64
			item [0] := new_value.to_natural_32
			upper_limb := (new_value |>> 32).to_natural_32
			item [1] := upper_limb
			new_count := value_a.three_way_comparison (0)
			new_count := new_count * ((upper_limb /= 0).to_integer + 1)
			count_set (new_count)
		ensure
			value_a > 0 implies (count = 1 or count = 2)
			value_a = 0 implies (count = 0)
			value_a < 0 implies (count = -1 or count = -2)
			fits_integer_64
			as_integer_64 = value_a
		end

	set_from_integer_32 (value_a: INTEGER_32)
			-- Initialize `Current' from `value_a'.
		local
			limb: NATURAL_32
		do
			if value_a < 0 then
				limb := value_a.to_natural_32.bit_not + 1
			else
				limb := value_a.to_natural_32
			end
			item [0] := limb
			count_set (value_a.three_way_comparison (0))
		ensure
			value_a > 0 implies count = 1
			value_a = 0 implies count = 0
			value_a < 0 implies count = -1
			fits_integer_32
			as_integer_32 = value_a
		end

	set_from_integer_16 (value_a: INTEGER_16)
			-- Initialize `Current' from `value_a'.
		local
			limb: NATURAL_32
		do
			if value_a < 0 then
				limb := value_a.to_natural_32.bit_not + 1
			else
				limb := value_a.to_natural_32
			end
			item [0] := limb
			count_set (value_a.three_way_comparison (0))
		ensure
			value_a > 0 implies count = 1
			value_a = 0 implies count = 0
			value_a < 0 implies count = -1
			fits_integer_16
			as_integer_16 = value_a
		end

	set_from_integer_8 (value_a: INTEGER_8)
			-- Initialize `Current' from `value_a'.
		local
			limb: NATURAL_32
		do
			if value_a < 0 then
				limb := value_a.to_natural_32.bit_not + 1
			else
				limb := value_a.to_natural_32
			end
			item [0] := limb
			count_set (value_a.three_way_comparison (0))
		ensure
			value_a > 0 implies count = 1
			value_a = 0 implies count = 0
			value_a < 0 implies count = -1
			fits_integer_8
			as_integer_8 = value_a
		end

	set_from_natural (value_a: NATURAL)
			-- Initialize `Current' from `value_a'.
		do
			set_from_natural_32 (value_a)
		ensure
			value_a = 0 implies count = 0
			value_a /= 0 implies count = 1
			fits_natural
			as_natural = value_a
		end

	set_from_natural_64 (value_a: NATURAL_64)
			-- Initialize `Current' from `value_a'.
		local
			upper_limb: NATURAL_32
			new_count: INTEGER
		do
			resize (2)
			item [0] := value_a.to_natural_32
			upper_limb := (value_a |>> 32).to_natural_32
			item [1] := upper_limb
			new_count := value_a.three_way_comparison (0)
			new_count := new_count + (upper_limb /= 0).to_integer
			count_set (new_count)
		ensure
			value_a = 0 implies count = 0
			value_a /= 0 implies (count = 1 or count = 2)
			fits_natural_64
			as_natural_64 = value_a
		end

	set_from_natural_32 (value_a: NATURAL_32)
			-- Initialize `Current' from `value_a'.
		do
			item [0] := value_a
			if
				value_a /= 0
			then
				count_set (1)
			else
				count_set (0)
			end
		ensure
			value_a = 0 implies count = 0
			value_a /= 0 implies count = 1
			fits_natural_32
			as_natural_32 = value_a
		end

	set_from_natural_16 (value_a: NATURAL_16)
			-- Initialize `Current' from `value_a'.
		do
			item [0] := value_a.to_natural_32
			if
				value_a /= 0
			then
				count_set (1)
			else
				count_set (0)
			end
		ensure
			value_a = 0 implies count = 0
			value_a /= 0 implies count = 1
			fits_natural_16
			as_natural_16 = value_a
		end

	set_from_natural_8 (value_a: NATURAL_8)
			-- Initialize `Current' from `value_a'.
		do
			item [0] := value_a.to_natural_32
			if
				value_a /= 0
			then
				count_set (1)
			else
				count_set (0)
			end
		ensure
			value_a = 0 implies count = 0
			value_a /= 0 implies count = 1
			fits_natural_8
			as_natural = value_a
		end

	set_from_string (s: STRING)
			-- Initialize `Current' from `s' where `s' is a base 10 string
		require
			s_not_empty: not s.is_empty
		do
			set_str (Current, s, 10)
		end

	set_random (bits_a: INTEGER)
			-- Initialize `Current' to random bits up to `bits_a' bits
		require
			valid_bits: bits_a >= 1
		do
			urandomb (Current, random_state, bits_a)
		ensure
			bits <= bits_a
		end

feature -- Conversion with possible truncation.
		-- Negatives wrap around in the negatives, non-negatives wrap around in the non-negatives

	as_integer: INTEGER
			-- Return the value of `Current' truncated to an {INTEGER}
		do
			Result := as_integer_32
		end

	as_integer_64: INTEGER_64
			-- Return the value of `Current' truncated to an {INTEGER_64}
		local
			size: INTEGER
			unsigned_result: NATURAL_64
		do
			size := count
			if size > 1 then
				unsigned_result := item [1].to_natural_64.bit_shift_left (32)
			end
			unsigned_result := unsigned_result.bit_or (item [0].to_natural_64)
			if size > 0 then
				Result := unsigned_result.to_integer_64.bit_and (0x7fff_ffff_ffff_ffff)
			elseif size < 0 then
				Result := (unsigned_result.to_integer_64 - 1).bit_and (0x7fff_ffff_ffff_ffff).bit_not
			else
				Result := 0
			end
		end

	as_integer_32: INTEGER_32
			-- Return the value of `Current' truncated to an {INTEGER_32}
		local
			size: INTEGER
			zl: NATURAL_32
		do
			size := count
			zl := item [0]
			if size > 0 then
				Result := zl.to_integer_32.bit_and (0x7fffffff)
			elseif size < 0 then
				Result := (zl.to_integer_32 - 1).bit_and (0x7fffffff).bit_not
			else
				Result := 0
			end
		end

	as_integer_16: INTEGER_16
			-- Return the value of `Current' truncated to an {INTEGER_16}
		local
			size: INTEGER
			limb: NATURAL_32
		do
			size := count
			limb := item [0]
			if size > 0 then
				Result := limb.to_integer_16.bit_and (0x7fff)
			elseif size < 0 then
				Result := (limb.to_integer_16 - 1).bit_and (0x7fff).bit_not
			else
				Result := 0
			end
		end

	as_integer_8: INTEGER_8
			-- Return the value of `Current' truncated to an {INTEGER_8}
		local
			size: INTEGER
			limb: NATURAL_32
		do
			size := count
			limb := item [0]
			if size > 0 then
				Result := limb.to_integer_8.bit_and (0x7f)
			elseif size < 0 then
				Result := (limb.to_integer_8 - 1).bit_and (0x7f).bit_not
			else
				Result := 0
			end
		end

	as_natural: NATURAL
			-- Return the value of the absolute value of `Current' truncated to a {NATURAL}
		do
			Result := as_natural_32
		end

	as_natural_64: NATURAL_64
			-- Return the value of the absolute value of `Current' truncated to a {NATURAL_64}
		local
			n: INTEGER
			data: SPECIAL [NATURAL_32]
		do
			n := count
			data := item
			if
				n = 0
			then
				Result := 0
			elseif n = 1 then
				Result := data [0]
			else
				Result := data [1]
				Result := Result |<< 32
				Result := Result.bit_or (data [0])
			end
		end

	as_natural_32: NATURAL_32
			-- Return the value of the absolute value of `Current' truncated to a {NATURAL_32}
		do
			if
				count = 0
			then
				Result := 0
			else
				Result := item [0]
			end
		end

	as_natural_16: NATURAL_16
			-- Return the value of the absolute value of `Current' truncated to a {NATURAL_16}
		do
			if
				count = 0
			then
				Result := 0
			else
				Result := item [0].as_natural_16
			end
		end

	as_natural_8: NATURAL_8
			-- Return the value of the absolute value of `Current' truncated to a {NATURAL_8}
		do
			if
				count = 0
			then
				Result := 0
			else
				Result := item [0].as_natural_8
			end
		end

feature -- Lossless conversion

	to_integer: INTEGER
			-- Return the value of `Current' as an {INTEGER}
		require
			fits: fits_integer_32
		do
			Result := as_integer_32
		ensure
			Current ~ (create {INTEGER_X}.make_from_integer (Result))
		end

	to_integer_64: INTEGER_64
			-- Return the value of `Current' as an {INTEGER_64}
		require
			fits: fits_integer_64
		do
			Result := as_integer_64
		ensure
			Current ~ (create {INTEGER_X}.make_from_integer_64 (Result))
		end

	to_integer_32: INTEGER_32
			-- Return the value of `Current' as an {INTEGER_32}
		require
			fits: fits_integer_32
		do
			Result := as_integer_32
		ensure
			Current ~ (create {INTEGER_X}.make_from_integer_32 (Result))
		end

	to_integer_16: INTEGER_16
			-- Return the value of `Current' as an {INTEGER_16}
		require
			fits: fits_integer_16
		do
			Result := as_integer_16
		ensure
			Current ~ (create {INTEGER_X}.make_from_integer_16 (Result))
		end

	to_integer_8: INTEGER_8
			-- Return the value of `Current' as an {INTEGER_8}
		require
			fits: fits_integer_8
		do
			Result := as_integer_8
		ensure
			Current ~ (create {INTEGER_X}.make_from_integer_8 (Result))
		end

	to_natural: NATURAL_32
			-- Return the value of `Current' as a {NATURAL}
		require
			fits: fits_natural
		do
			Result := to_natural_32
		ensure
			Current ~ (create {INTEGER_X}.make_from_natural (Result))
		end

	to_natural_64: NATURAL_64
			-- Return the value of `Current' as a {NATURAL_64}
		require
			fits: fits_natural_64
		do
			Result := as_natural_64
		ensure
			Current ~ (create {INTEGER_X}.make_from_natural_64 (Result))
		end

	to_natural_32: NATURAL_32
			-- Return the value of `Current' as a {NATURAL_32}
		require
			fits: fits_natural_32
		do
			Result := as_natural_32
		ensure
			Current ~ (create {INTEGER_X}.make_from_natural_32 (Result))
		end

	to_natural_16: NATURAL_16
			-- Return the value of `Current' as a {NATURAL_16}
		require
			fits: fits_natural_16
		do
			Result := as_natural_16
		ensure
			Current ~ (create {INTEGER_X}.make_from_natural_16 (Result))
		end

	to_natural_8: NATURAL_8
			-- Return the value of `Current' as a {NATURAL_8}
		require
			fits: fits_natural_8
		do
			Result := as_natural_8
		ensure
			Current ~ (create {INTEGER_X}.make_from_natural_8 (Result))
		end

	to_bytes (target: SPECIAL [NATURAL_8] offset: INTEGER)
			-- Convert the absolute value of `Current' to a byte array
		require
			big_enough: bytes <= target.upper - offset + 1
		local
			junk: TUPLE [junk: INTEGER]
		do
			create junk
			output (target, offset, junk, 1, 1, -1, Current)
		ensure
			reversable: (create {INTEGER_X}.make_from_bytes (target, offset, offset + bytes - 1)) ~ Current
		end

	as_bytes: SPECIAL[NATURAL_8]
			-- Convert the absolute value of `Current' to a byte array
		do
			create Result.make_filled (0, bytes)
			to_bytes (Result, Result.lower)
		ensure
			reversable: (create {INTEGER_X}.make_from_bytes (Result, Result.lower, Result.upper)) ~ Current
		end

	to_fixed_width_byte_array (target: SPECIAL [NATURAL_8] first: INTEGER last: INTEGER)
		require
			valid_first: target.valid_index (first)
			valid_last: target.valid_index (last)
			enough_space: last - bytes + 1 >= first
		local
			junk: TUPLE [junk: INTEGER_32]
		do
			create junk
			target.fill_with (0x0, first, last)
			output (target, first + (last - first - bytes + 1), junk, 1, 1, -1, Current)
		ensure
			reversable: (create {INTEGER_X}.make_from_bytes (target, first, last)) ~ Current
		end

	as_fixed_width_byte_array (byte_size: INTEGER): SPECIAL[NATURAL_8]
			-- Convert the absolute value of `Current' to a byte array of `byte_size' bytes
		require
			enough_space: bytes <= byte_size
		do
			create Result.make_filled (0, byte_size)
			to_fixed_width_byte_array (Result, 0, byte_size - 1)
		ensure
			reversable: (create {INTEGER_X}.make_from_bytes (Result, Result.lower, Result.upper)) ~ Current
		end

feature -- Duplication

	copy (other: like Current)
			-- Update `Current' to be a copy of `other'
		local
			usize: INTEGER
			size: INTEGER
		do
			usize := other.count
			size := usize.abs
			resize (size)
			item.copy_data (other.item, 0, 0, size)
			count := usize
		end

feature {INTEGER_X_FACILITIES}-- Basic operations stateful

	abs
			-- Modify `Current' to be non-negative
		do
			abs_integer_x (Current, Current)
		ensure
			non_negative: not is_negative
		end

	plus (other: like Current)
			-- Modify `Current' to be the sum of `Current' and `other'
		do
			add (Current, Current, other)
		end

	minus (other: like Current)
			-- Modify `Current' to be the subtraction of `Current' and `other'
		do
			sub (Current, Current, other)
		end

	product (other: like Current)
			-- Modify `Current' to be the product of `Current' and `other'
		do
			mul (Current, Current, other)
		end

	quotient (other: like Current)
			-- Modify `Current' to be the quotient by truncation division of `Current' by `other'
		do
			tdiv_q (Current, Current, other)
		end

	opposite
			-- Modify `Current' to be the opposite sign or do nothing if `Current'.is_zero
		do
			neg (Current, Current)
		end

feature -- Basic operations stateless
	abs_value: like Current
			-- Return the absolute value of `Current'
		do
			Result := identity
			Result.abs
		ensure
			non_negative: not Result.is_negative
			same_absolute_value: (Result ~ (Current)) or (Result ~ (-Current))
		end

	plus_value alias "+" (other: like Current): like Current
			-- Return the sum of `Current' and `other'
		do
			Result := identity
			Result.plus (other)
		ensure then
			Result - Current ~ other
			Result - other ~ Current
		end

	minus_value alias "-" (other: like Current): like Current
			-- Return the subtraction of `Current' and `other'
		do
			Result := identity
			Result.minus (other)
		ensure then
			Result + other ~ Current
			Current - Result ~ other
		end

	product_value alias "*" (other: like Current): like Current
			-- Return the product of `Current' and `other'
		do
			Result := identity
			Result.product (other)
		ensure then
			Result / Current ~ other
			Result / other ~ Current
		end

	quotient_value alias "/" (other: like Current): like Current
			-- Return the integer quotient by truncation division of `Current' by `other'
		do
			Result := identity
			Result.quotient (other)
		end

	identity alias "+": like Current
			-- Return the identity of `Current'
		do
			Result := deep_twin
		end

	opposite_value alias "-": like Current
			-- Return the negative of `Current'
		do
			Result := identity
			Result.opposite
		end

feature {INTEGER_X_FACILITIES}-- Bit operations stateful

	bit_complement (bit_a: INTEGER)
			-- Modify `Current' to have bit `bit_a' complemented
		do
			bit_complement_integer_x (Current, bit_a)
		ensure
			is_negative implies not old is_positive
			is_positive implies not old is_negative
		end

	bit_and (other: like Current)
			-- Modify `Current' to be the bitwise AND of `Current' and `other'
		do
			bit_and_integer_x (Current, Current, other)
		ensure
			is_negative implies not old is_positive
			is_positive implies not old is_negative
		end

	bit_or (other: like Current)
			-- Modify `Current' to be the bitwise OR of `Current' and `other'
		do
			bit_or_integer_x (Current, Current, other)
		ensure
			is_negative implies not old is_positive
			is_positive implies not old is_negative
		end

	bit_xor (other: like Current)
			-- Modify `Current' to be the bitwise XOR of `Current' and `other'
		do
			bit_xor_integer_x (Current, Current, other)
		ensure
			is_negative implies not old is_positive
			is_positive implies not old is_negative
		end

	bit_not
			-- Modify `Current' to be a bitwise NOT of `Current'
		do
			bit_one_complement (Current, Current)
		ensure
			is_negative implies not old is_positive
			is_positive implies not old is_negative
		end

	bit_xor_left_shift (other: like Current left_shift_bits: INTEGER)
			-- Modify `Current' to be the bitwise XOR of `Current' and (`other' shifted left `left_shift_bits' bits)
		do
			bit_xor_lshift_integer_x (Current, Current, other, left_shift_bits)
		ensure
			is_negative implies not old is_positive
			is_positive implies not old is_negative
		end

	bit_shift_right (bits_a: INTEGER)
			-- Modify `Current' to be bit shifted right `bits_a' bits
		do
			tdiv_q_2exp (Current, Current, bits_a)
		ensure
			is_negative implies not old is_positive
			is_positive implies not old is_negative
		end

	bit_shift_left (bits_a: INTEGER)
			-- Modify `Current' to be bit shifted left `bits_a' bits
		do
			mul_2exp (Current, Current, bits_a)
		ensure
			is_negative implies not old is_positive
			is_positive implies not old is_negative
		end

	set_bit (value: BOOLEAN; bit_a: INTEGER)
			-- Modify `Current' and set bit `bit_a' if `value' is True
		do
			if value then
				bit_set (Current, bit_a)
			else
				bit_clear (Current, bit_a)
			end
		ensure
			is_negative implies not old is_positive
			is_positive implies not old is_negative
		end

feature -- Bit operations stateless
		-- All bit operations are performed as if the number was stored in two-complement format

	bit_complement_value (bit_a: INTEGER): like Current
			-- Return a copy of `Current' with bit `bit_a' complemented
		require
			valid_i: bit_a >= 0
		do
			Result := identity
			Result.bit_complement (bit_a)
		ensure
			is_negative implies not Result.is_positive
			is_positive implies not Result.is_negative
		end

	bit_and_value alias "&" (other: like Current): like Current
			-- Return the bitwise AND of `Current' and `other'
		do
			Result := identity
			Result.bit_and (other)
		ensure
			is_negative implies not Result.is_positive
			is_positive implies not Result.is_negative
		end

	bit_or_value alias "|" (other: like Current): like Current
			-- Return the bitwise OR of `Current' and `other'
		do
			Result := identity
			Result.bit_or (other)
		ensure
			is_negative implies not Result.is_positive
			is_positive implies not Result.is_negative
		end

	bit_xor_value (other: like Current): like Current
			-- Return the bitwise XOR of `Current' and `other'
		do
			Result := identity
			Result.bit_xor (other)
		ensure
			Result.bit_xor_value (Current) ~ other
			Result.bit_xor_value (other) ~ Current
		end

	bit_xor_left_shift_value (other: like Current left_shift_bits: INTEGER): like Current
			-- Return the bitwise XOR of `Current' and (`other' shifted left `left_shift_bits' bits)
		do
			Result := identity
			Result.bit_xor_left_shift (other, left_shift_bits)
		ensure
			is_negative implies not old is_positive
			is_positive implies not old is_negative
		end

	bit_not_value: like Current
			-- Return the a bitwise NOT of `Current'
		do
			Result := identity
			Result.bit_not
		ensure
			is_negative implies not Result.is_positive
			is_positive implies not Result.is_negative
		end

	bit_shift_left_value alias "|<<" (bits_a: INTEGER): like Current
			-- Return `Current' bit shifted left `bits_a' bits
		require
			n_nonnegative: bits_a >= 0
		do
			Result := identity
			Result.bit_shift_left (bits_a)
		ensure
			is_negative implies not Result.is_positive
			is_positive implies not Result.is_negative
		end

	bit_shift_right_value alias "|>>" (bits_a: INTEGER): like Current
			-- Return `Current' bit shifted right `bits_a' bits, truncating lower bits
		require
			n_nonnegative: bits_a >= 0
		do
			Result := identity
			Result.bit_shift_right (bits_a)
		ensure
			is_negative implies not Result.is_positive
			is_positive implies not Result.is_negative
		end

	bit_test (bit_a: INTEGER): BOOLEAN
			-- Is bit at position `bit_a' set
		require
			n_nonnegative: bit_a >= 0
		do
			Result := bit_test_integer_x (Current, bit_a)
		end

	set_bit_value (value: BOOLEAN; bit_a: INTEGER): like Current
			-- Return a copy of `Current' with bit `bit_a' set if `value' is True
		require
			n_nonnegative: bit_a >= 0
		do
			Result := identity
			Result.set_bit (value, bit_a)
		ensure
			is_negative implies not Result.is_positive
			is_positive implies not Result.is_negative
		end

feature {INTEGER_X_FACILITIES}-- Discrete operations stateful

	powm (exponent: like Current; modulus: like Current)
			-- Modify `Current' to be (`Current' raised to `exponent') modulo `modulus'
			-- Negative `exponent' is supported if an inverse base^-1 mod mod exists {INTEGER_X}.invert
			-- If `exponent' does not have an inverse modulo `modulus', an {INVERSE_EXCEPTION} will be raised
		do
			powm_integer_x (Current, Current, exponent, modulus)
		end

	inverse (modulus: like Current)
			-- Set `Current' to be the inverse of `Current' modulo `modulus'
			-- If `Current' does not have an inverse modulo `modulus', an {INVERSE_EXCEPTION} will be raised
		local
			has_inverse: BOOLEAN
		do
			has_inverse := invert (Current, Current, modulus)
			if not has_inverse then
				(create {INVERSE_EXCEPTION}).raise
			end
		ensure
			coprime: coprime (modulus)
		end

	modulo (mod: like Current)
			-- Set `Current' to `Current' modulo `modulus'
		do
			mod_integer_x (Current, Current, mod)
		end

	gcd (op1: like Current; op2: like Current)
			-- Set `Current' to the Greatest Common Divisor between `op1' and `op2'
		do
			gcd_integer_x (Current, op1, op2)
		ensure
			positive_result: Current.is_positive
			op1.coprime (op2) = (Current ~ one)
		end

feature -- Discrete operations stateless

	powm_value (exponent: like Current; modulus: like Current): like Current
			-- Return (`Current' raised to `exponent') modulo `modulus'.
			-- Negative `exponent' is supported if an inverse base^-1 mod mod exists {INTEGER_X}.invert
			-- If an inverse doesn't exist then a divide by zero is raised
		do
			Result := identity
			Result.powm (exponent, modulus)
		end

	inverse_value (modulus: like Current): like Current
			-- Return the inverse of `Current' modulo `modulus'
			-- If `Current' does not have an inverse modulo `modulus', an {INVERSE_EXCEPTION} will be raised
		do
			Result := identity
			Result.inverse (modulus)
		ensure
			correct_result: ((Result * Current) \\ modulus) ~ (one)
			coprime: coprime (modulus)
		end

	modulo_value alias "\\" (modulus: like Current): like Current
			-- Return `Current' modulo `modulus'
		do
			Result := identity
			Result.modulo (modulus)
		end

	gcd_value (other: like Current): like Current
			-- Return the Greatest Common Divisor between `Current' and `other'
		do
			Result := identity
			Result.gcd (Current, other)
		ensure
			positive_result: Result.is_positive
			coprime (other) = (Result ~ one)
		end

	coprime (other: like Current): BOOLEAN
			-- Are `Current' and `other' coprime?
		do
			Result := gcd_value (other) ~ (one)
		ensure
			Result = (gcd_value (other) ~ (one))
		end

feature {INTEGER_X_FACILITIES}-- Galois field arithmetic stateful
	invert_gf (other: like Current)
		require
			not is_negative
			not other.is_negative
		do
			invert_gf_integer_x (Current, Current, other)
		ensure
			not is_negative
			other.identity ~ old other.identity
		end

feature -- Galois field arithmetic stateless
	invert_gf_value (other: like Current): like Current
		require
			not is_negative
			not other.is_negative
		do
			Result := identity
			Result.invert_gf (other)
		ensure
			not Result.is_negative
			identity ~ old identity
			other.identity ~ old other.identity
		end

feature -- Output

	debug_output: STRING
			-- Return a debug string of `Current'
		do
			Result := out_hex
		end

	out: STRING
			-- Return a hexicedimal representation of the value of `Current'
		do
			Result := out_hex
		end

	out_decimal: STRING
			-- Return a decimal representation of the value of `Current'
		do
			Result := out_base (10)
		end

	out_hex: STRING
			-- Return a hexidecimal representation ofthe value of `Current'
		do
			Result := out_base (16)
		end

	out_base (base: INTEGER_32): STRING
			-- Return a representation of `Current' in base `base'
		require
			base_too_small: base >= 2
			base_too_big: base <= 62
		do
			Result := get_string (Current, base)
		end

feature {NONE} -- Implementation

	random_state: RANDOM_NUMBER_GENERATOR
		once
			create {LINEAR_CONGRUENTIAL_RNG}Result.make (32)
		end

feature {INTEGER_X_FACILITIES}

	normalized: BOOLEAN
			-- Does `count' represent the number of non-zero limbs in `item'
		do
			Result := normalize (item, 0, count) = count
		end

	components_set (item_value: SPECIAL [NATURAL_32] count_value: INTEGER)
			-- Set `item' and `count' simultaneously
		do
			item_set (item_value)
			count_set (count_value)
		end

	capacity: INTEGER
			-- Number of limbs allocated in `item'
		do
			Result := item.capacity
		end

	item: SPECIAL [NATURAL_32] assign item_set
			-- Backing storage for the number

	item_set (value_a: SPECIAL [NATURAL_32])
			-- Change `item' to `value_a'
		do
			item := value_a
		end

	count: INTEGER assign count_set
			-- `count.abs' is the number of limbs in `item' that have meaning
			-- If `size' is negative this is a negative number.
		attribute
		end

	count_set (value_a: INTEGER)
			-- Change `count' to `value_a'
		do
			count := value_a
		end

	resize (new_alloc: INTEGER)
			-- Change the space for integer to at least `new_alloc' limbs.
		local
			allocate_size: INTEGER_32
		do
			if new_alloc > capacity then
				allocate_size := new_alloc.max (1)
				item := item.aliased_resized_area_with_default (0, allocate_size)
			end
		end

	set_components (item_a: SPECIAL [NATURAL_32] count_a: INTEGER)
		do
			item := item_a
			count := count_a
		end

invariant
--	normalized: normalized
	capacity >= 1
	count <= item.count
	item.count = item.capacity
end
