note
	description: "Summary description for {NUMBER_LOGIC}."
	author: "Colin LeMahieu"
	date: "$Date$"
	revision: "$Revision$"
	quote: "It is a free market that makes monopolies impossible. -  Ayn Rand"

deferred class
	SPECIAL_LOGIC

inherit
	LIMB_MANIPULATION

feature

	com_n (target: SPECIAL [NATURAL_32]; target_offset_a: INTEGER; op1: SPECIAL [NATURAL_32]; op1_offset_a: INTEGER; op1_count_a: INTEGER)
		require
			op1_count_a >= 1
		local
			target_offset: INTEGER
			op1_offset: INTEGER
			op1_count: INTEGER
		do
			target_offset := target_offset_a
			op1_offset := op1_offset_a
			op1_count := op1_count_a
			from
			until
				op1_count = 0
			loop
				target [target_offset] := op1 [op1_offset].bit_not
				target_offset := target_offset + 1
				op1_offset := op1_offset + 1
				op1_count := op1_count - 1
			end
		end

	hamdist (op1: SPECIAL [NATURAL_32]; op1_offset_a: INTEGER; op2: SPECIAL [NATURAL_32]; op2_offset_a: INTEGER; n_a: INTEGER): INTEGER
		local
			p0: NATURAL_32
			p1: NATURAL_32
			p2: NATURAL_32
			p3: NATURAL_32
			x: NATURAL_32
			p01: NATURAL_32
			p23: NATURAL_32
			i: INTEGER
			op1_offset: INTEGER
			n: INTEGER
			op2_offset: INTEGER
		do
			op2_offset := op2_offset_a
			n := n_a
			op1_offset := op1_offset_a
			from
				i := n |>> 2
			until
				i = 0
			loop
				p0 := op1 [op1_offset].bit_xor (op2 [op2_offset])
				p0 := p0 - (p0 |>> 1).bit_and (limb_max // 3)
				p0 := (p0 |>> 2).bit_and (limb_max // 5) + p0.bit_and (limb_max // 5)

				p1 := op1 [op1_offset + 1].bit_xor (op2 [op2_offset + 1])
				p1 := p1 - (p1 |>> 1).bit_and (limb_max // 3)
				p1 := (p1 |>> 2).bit_and (limb_max // 5) + p1.bit_and (limb_max // 5)

				p01 := p0 + p1
				p01 := (p01 |>> 4).bit_and (limb_max // 17) + p01.bit_and (limb_max // 17)

				p2 := op1 [op1_offset + 2].bit_xor (op2 [op2_offset + 2])
				p2 := p2 - (p2 |>> 1).bit_and (limb_max // 3)
				p2 := (p2 |>> 2).bit_and (limb_max // 5) + p2.bit_and (limb_max // 5)

				p3 := op1 [op1_offset + 3].bit_xor (op2 [op2_offset + 3])
				p3 := p3 - (p3 |>> 1).bit_and (limb_max // 3)
				p3 := (p3 |>> 2).bit_and (limb_max // 5) + p3.bit_and (limb_max // 5)

				p23 := p2 + p3
				p23 := (p23 |>> 4).bit_and (limb_max // 17) + p23.bit_and (limb_max // 17)

				x := p01 + p23
				x := (x |>> 8) + x
				x := (x |>> 16) + x
				Result := Result + x.bit_and (0xff).to_integer_32
				op1_offset := op1_offset + 4
				op2_offset := op2_offset + 4
				i := i - 1
			end
			n := n.bit_and (3)
			if n /= 0 then
				x := 0
				from
				until
					n = 0
				loop
					p0 := op1 [op1_offset].bit_xor (op2 [op2_offset])
					p0 := p0 - (p0 |>> 1).bit_and (limb_max // 3)
					p0 := (p0 |>> 2).bit_and (limb_max // 5) + p0.bit_and (limb_max // 5)
					p0 := ((p0 |>> 4) | p0).bit_and (limb_max // 17)
					x := x + p0
					op1_offset := op1_offset + 1
					op2_offset := op2_offset + 1
					n := n - 1
				end
				x := (x |>> 8) + x
				x := (x |>> 16) + x
				Result := Result + x.bit_and (0xff).to_integer_32
			end
		end

	lshift (target: SPECIAL [NATURAL_32]; target_offset: INTEGER_32; op1: SPECIAL [NATURAL_32]; op1_offset: INTEGER_32; n: INTEGER_32; count: INTEGER_32; carry: CELL [NATURAL_32])
		require
			target.valid_index (target_offset)
			target.valid_index (target_offset + n - 1)
			op1.valid_index (op1_offset)
			op1.valid_index (op1_offset + n - 1)
			count > 0
			count < 32
		local
			high_limb: NATURAL_32
			low_limb: NATURAL_32
			tnc: INTEGER_32
			i: INTEGER_32
			up: INTEGER_32
			rp: INTEGER_32
		do
			up := op1_offset + n
			rp := target_offset + n
			tnc := 32 - count
			up := up - 1
			low_limb := op1 [up]
			carry.put (low_limb |>> tnc)
			high_limb := low_limb |<< count
			from
				i := n - 1
			until
				i = 0
			loop
				up := up - 1
				low_limb := op1 [up]
				rp := rp - 1
				target [rp] := high_limb.bit_or (low_limb |>> tnc)
				high_limb := low_limb |<< count
				i := i - 1
			end
			rp := rp - 1
			target [rp] := high_limb
		end

	rshift (target: SPECIAL [NATURAL_32]; target_offset: INTEGER_32; op1: SPECIAL [NATURAL_32]; op1_offset: INTEGER_32; n: INTEGER_32; count: INTEGER_32; carry: CELL [NATURAL_32])
		local
			high_limb: NATURAL_32
			low_limb: NATURAL_32
			tnc: INTEGER_32
			i: INTEGER_32
			op1_cursor: INTEGER_32
			target_cursor: INTEGER_32
		do
			tnc := 32 - count
			op1_cursor := op1_offset
			high_limb := op1 [op1_cursor]
			op1_cursor := op1_cursor + 1
			carry.put (high_limb |<< tnc)
			low_limb := high_limb |>> count
			from
				i := n - 1
			until
				i = 0
			loop
				high_limb := op1 [op1_cursor]
				op1_cursor := op1_cursor + 1
				target [target_cursor] := low_limb.bit_or (high_limb |<< tnc)
				target_cursor := target_cursor + 1
				low_limb := high_limb |>> count
				i := i - 1
			end
			target [target_cursor] := low_limb
		end

	popcount (op1: SPECIAL [NATURAL_32]; op1_offset_a: INTEGER; n_a: INTEGER): INTEGER
		local
			p0: NATURAL_32
			p1: NATURAL_32
			p2: NATURAL_32
			p3: NATURAL_32
			x: NATURAL_32
			p01: NATURAL_32
			p23: NATURAL_32
			i: INTEGER
			op1_offset: INTEGER
			n: INTEGER
		do
			n := n_a
			op1_offset := op1_offset_a
			from
				i := n |>> 2
			until
				i = 0
			loop
				p0 := op1 [op1_offset]
				p0 := p0 - (p0 |>> 1).bit_and (limb_max // 3)
				p0 := (p0 |>> 2).bit_and (limb_max // 5) + p0.bit_and (limb_max // 5)

				p1 := op1 [op1_offset + 1]
				p1 := p1 - (p1 |>> 1).bit_and (limb_max // 3)
				p1 := (p1 |>> 2).bit_and (limb_max // 5) + p1.bit_and (limb_max // 5)

				p01 := p0 + p1
				p01 := (p01 |>> 4).bit_and (limb_max // 17) + p01.bit_and (limb_max // 17)

				p2 := op1 [op1_offset + 2]
				p2 := p2 - (p2 |>> 1).bit_and (limb_max // 3)
				p2 := (p2 |>> 2).bit_and (limb_max // 5) + p2.bit_and (limb_max // 5)

				p3 := op1 [op1_offset + 3]
				p3 := p3 - (p3 |>> 1).bit_and (limb_max // 3)
				p3 := (p3 |>> 2).bit_and (limb_max // 5) + p3.bit_and (limb_max // 5)

				p23 := p2 + p3
				p23 := (p23 |>> 4).bit_and (limb_max // 17) + p23.bit_and (limb_max // 17)

				x := p01 + p23
				x := (x |>> 8) + x
				x := (x |>> 16) + x
				Result := Result + x.bit_and (0xff).to_integer_32
				op1_offset := op1_offset + 4
				i := i - 1
			end
			n := n.bit_and (3)
			if n /= 0 then
				x := 0
				from
				until
					n = 0
				loop
					p0 := op1 [op1_offset]
					p0 := p0 - (p0 |>> 1).bit_and (limb_max // 3)
					p0 := (p0 |>> 2).bit_and (limb_max // 5) + p0.bit_and (limb_max // 5)
					p0 := ((p0 |>> 4) | p0).bit_and (limb_max // 17)
					x := x + p0
					op1_offset := op1_offset + 1
					n := n - 1
				end
				x := (x |>> 8) + x
				x := (x |>> 16) + x
				Result := Result + x.bit_and (0xff).to_integer_32
			end
		end

	bit_xor_lshift (target: SPECIAL [NATURAL_32] target_offset: INTEGER op1: SPECIAL [NATURAL_32] op1_offset: INTEGER op1_count: INTEGER op2: SPECIAL [NATURAL_32] op2_offset: INTEGER op2_count: INTEGER op2_lshift: INTEGER)
		require
			op2_lshift >= 0
			op1 /= op2
			target /= op2
			op1_count = 0 or op1.valid_index (op1_offset)
			op1_count = 0 or op1.valid_index (op1_offset + op1_count - 1)
			op2_count = 0 or op2.valid_index (op2_offset)
			op2_count = 0 or op2.valid_index (op2_offset + op2_count - 1)
			(op1_count = 0 and op2_count = 0) or target.valid_index (target_offset)
			(op1_count = 0 and op2_count = 0) or target.valid_index (target_offset + op1_count.max (op2_count + bits_to_limbs (op2_lshift)) - 1)
		local
			op2_limb_high: NATURAL_32
			op2_limb_low: NATURAL_32
			op2_limb: NATURAL_32
			cursor: INTEGER
			shift_limbs: INTEGER
			shift_bits: INTEGER
		do
			shift_limbs := op2_lshift // limb_bits
			shift_bits := op2_lshift \\ limb_bits
			target.copy_data (op1, op1_offset, target_offset, shift_limbs)
			from
			until
				cursor >= op2_count or cursor >= op1_count - shift_limbs
			loop
				op2_limb_low := op2_limb_high
				op2_limb_high := op2 [op2_offset + cursor]
				op2_limb := extract_limb (shift_bits, op2_limb_high, op2_limb_low)
				target [target_offset + shift_limbs + cursor] := op2_limb.bit_xor (op1 [op1_offset + shift_limbs + cursor])
				cursor := cursor + 1
			end
			if cursor >= op2_count then
				op2_limb_low := op2_limb_high
				op2_limb := extract_limb (shift_bits, 0, op2_limb_low)
				if cursor >= op1_count - shift_limbs then
					target [target_offset + shift_limbs + cursor] := op2_limb
				else
					target [target_offset + shift_limbs + cursor] := op2_limb.bit_xor (op1 [op1_offset + shift_limbs + cursor])
					cursor := cursor + 1
					target.copy_data (op1, op1_offset + shift_limbs + cursor, target_offset + shift_limbs + cursor, op1_count - cursor - shift_limbs)
				end
			else
				from
				until
					cursor >= op2_count
				loop
					op2_limb_low := op2_limb_high
					op2_limb_high := op2 [op2_offset + cursor]
					op2_limb := extract_limb (shift_bits, op2_limb_high, op2_limb_low)
					target [target_offset + shift_limbs + cursor] := op2_limb
					cursor := cursor + 1
				end
				op2_limb_low := op2_limb_high
				op2_limb := extract_limb (shift_bits, 0, op2_limb_low)
				target [target_offset + shift_limbs + cursor] := op2_limb
			end
		end

	bit_xor (target: SPECIAL [NATURAL_32]; target_offset: INTEGER; op1: SPECIAL [NATURAL_32]; op1_offset: INTEGER; op1_count: INTEGER; op2: SPECIAL [NATURAL_32]; op2_offset: INTEGER; op2_count: INTEGER)
		require
			(op1_count = 0 and op2_count = 0) or target.valid_index (target_offset)
			(op1_count = 0 and op2_count = 0) or target.valid_index (target_offset + op1_count.max (op2_count) - 1)
		local
			cursor: INTEGER
			min: INTEGER
		do
			from
				min := op1_count.min (op2_count)
			until
				cursor >= min
			loop
				target [target_offset + cursor] := op1 [op1_offset + cursor].bit_xor (op2 [op2_offset + cursor])
				cursor := cursor + 1
			end
			if op1_count > op2_count then
				target.copy_data (op1, op1_offset + cursor, target_offset + cursor, op1_count - cursor)
			elseif op2_count > op1_count then
				target.copy_data (op2, op2_offset + cursor, target_offset + cursor, op2_count - cursor)
			end
		end
end