note
	description: "[
		Sequential, one-way linked lists that call add/remove features
		when an item is removed or added.
	]"
	legal: "See notice at end of class."
	status: "See notice at end of class."
	keywords: "event, linked, list"
	date: "$Date: 2018-11-13 12:58:34 +0000 (Tue, 13 Nov 2018) $"
	revision: "$Revision: 102449 $"

deferred class 
	INTERACTIVE_LIST [G]

inherit
	ARRAYED_LIST [G]
		undefine
			new_filled_list
		redefine
			default_create,
			merge_left,
			merge_right,
			wipe_out,
			put_front,
			put_left,
			put_right,
			remove_right,
			replace,
			remove,
			put_i_th,
			append,
			make_from_array,
			prune_all,
			extend
		end

feature {NONE} -- Initialization

	default_create
			-- Initialize linked list.
		do
			make (4)
		end

	make_from_array (a: ARRAY [like item])
			-- Create list from array a.
		local
			l_index: INTEGER_32
		do
			make (a.count)
			from
				l_index := a.lower
			until
				l_index > a.upper
			loop
				extend (a.item (l_index))
				l_index := l_index + 1
			end
		end
	
feature -- Miscellaneous

	on_item_added_at (an_item: like item; item_index: INTEGER_32)
			-- an_item has just been added at index item_index.
		require
			item_index_valid: (1 <= item_index) and (item_index <= count)
		do
		end

	on_item_removed_at (an_item: like item; item_index: INTEGER_32)
			-- an_item has just been removed from index item_index.
		require
			item_index_valid: (1 <= item_index) and (item_index <= count + 1)
		do
		end
	
feature -- Element Change

	put_front (v: like item)
			-- Add v to beginning.
			-- Do not move cursor.
		do
			in_operation := True
			Precursor {ARRAYED_LIST} (v)
			in_operation := False
			added_item (v, 1)
		end

	extend (v: like item)
			-- Add v to end.
			-- Do not move cursor.
		do
			in_operation := True
			Precursor {ARRAYED_LIST} (v)
			in_operation := False
			added_item (v, count)
		end

	append (s: SEQUENCE [like item])
			-- Append a copy of s.
		local
			new_count: INTEGER_32
		do
			new_count := count + s.count
			if new_count > capacity then
				grow (new_count)
			end
			across
				if s = Current then
					s.twin
				else
					s
				end as c
			loop
				extend (c.item)
			end
		end

	put_left (v: like item)
			-- Add v to the left of cursor position.
			-- Do not move cursor.
		do
			in_operation := True
			Precursor {ARRAYED_LIST} (v)
			in_operation := False
			added_item (v, index - 1)
		end

	put_right (v: like item)
			-- Add v to the right of cursor position.
			-- Do not move cursor.
		do
			in_operation := True
			Precursor {ARRAYED_LIST} (v)
			in_operation := False
			added_item (v, index + 1)
		end

	put_i_th (v: like i_th; i: INTEGER_32)
			-- Replace i-th entry, if in index interval, by v.
		local
			original_item: like item
		do
			original_item := i_th (i)
			in_operation := True
			Precursor {ARRAYED_LIST} (v, i)
			in_operation := False
			if original_item /= Void then
				removed_item (original_item, i)
			end
			added_item (v, i)
		end

	replace (v: like item)
			-- Replace current item by v.
		local
			original_index: INTEGER_32
			original_item: like item
		do
			original_index := index
			original_item := item
			in_operation := True
			Precursor {ARRAYED_LIST} (v)
			in_operation := False
			removed_item (original_item, original_index)
			added_item (v, original_index)
		end

	remove
			-- Remove current item.
			-- Move cursor to right neighbor
			-- (or after if no right neighbor).
		local
			original_index: INTEGER_32
			original_item: like item
		do
			original_index := index
			original_item := item
			in_operation := True
			Precursor {ARRAYED_LIST}
			in_operation := False
			removed_item (original_item, original_index)
		end

	remove_right
			-- Remove item to the right of cursor position.
			-- Do not move cursor.
		local
			item_removed: like item
		do
			item_removed := i_th (index + 1)
			in_operation := True
			Precursor {ARRAYED_LIST}
			in_operation := False
			removed_item (item_removed, index + 1)
		end

	merge_left (other: like Current)
			-- Merge other into current structure after cursor
			-- position. Do not move cursor. Empty other
		local
			original_index: INTEGER_32
			original_other_count: INTEGER_32
		do
			original_index := index
			original_other_count := other.count
			index := index - 1
			merge_right (other)
			index := original_index + original_other_count
		end

	merge_right (other: like Current)
			-- Merge other into current structure before cursor
			-- position. Do not move cursor. Empty other
		local
			original_index: INTEGER_32
		do
			original_index := index
			in_operation := True
			Precursor {ARRAYED_LIST} (other)
			in_operation := False
			update_for_added (original_index + 1)
			go_i_th (original_index)
		end

	prune_all (v: like item)
			-- Remove all occurrences of v.
			-- (Reference or object equality,
			-- based on object_comparison.)
		local
			i, nb: INTEGER_32
			offset: INTEGER_32
			res: BOOLEAN
			obj_cmp: BOOLEAN
			l_item: like item
			l_area: like area
		do
			obj_cmp := object_comparison
			from
				l_area := area
				i := 0
				nb := count
			until
				i = count
			loop
				if i < nb - offset then
					if offset > 0 then
						l_area.put (l_area.item (i + offset), i)
					end
					l_item := l_area.item (i)
					if obj_cmp then
						res := v ~ l_item
					else
						res := v = l_item
					end
					if res then
						removed_item (l_item, i + Lower)
						offset := offset + 1
					else
						i := i + 1
					end
				else
					i := i + 1
				end
			end;
			l_area.remove_tail (offset)
			index := count + 1
		ensure then
			is_after: after
		end

	update_for_added (start_index: INTEGER_32)
			-- Call added_item for all items from index start_index to count
		local
			l_index: INTEGER_32
		do
			l_index := index
			from
				go_i_th (start_index)
			until
				index > count
			loop
				added_item (item, index)
				forth
			end
			go_i_th (l_index)
		end
	
feature -- Removal

	wipe_out
			-- Remove all items.
		local
			l: like area
			i, l_count: INTEGER_32
		do
			l := area.twin
			l_count := count
			Precursor {ARRAYED_LIST}
			from
				i := 0
			until
				i = l_count
			loop
				on_item_removed_at (l @ i, 1)
				i := i + 1
			end
		end
	
feature {NONE} -- Implementation

	add_all (other: like Current; start_index: INTEGER_32)
			-- Call on_item_added for all elements in other.
		local
			cur: CURSOR
			current_index: INTEGER_32
		do
			current_index := start_index
			cur := other.cursor
			from
				other.start
			until
				other.after
			loop
				added_item (other.item, current_index);
				other.forth
				current_index := current_index + 1
			end;
			other.go_to (cur)
		end

	in_operation: BOOLEAN
			-- Are we executing an operation from ARRAYED_LIST?

	added_item (an_item: like item; item_index: INTEGER_32)
			-- an_item is has been added.
		do
			if not in_operation then
				on_item_added_at (an_item, item_index)
			end
		end

	removed_item (an_item: like item; item_index: INTEGER_32)
			-- an_item has been removed.
		do
			if not in_operation then
				on_item_removed_at (an_item, item_index)
			end
		end
	
note
	library: "EiffelBase: Library of reusable components for Eiffel."
	copyright: "Copyright (c) 1984-2018, Eiffel Software and others"
	license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
	source: "[
		Eiffel Software
		5949 Hollister Ave., Goleta, CA 93117 USA
		Telephone 805-685-1006, Fax 805-685-6869
		Website http://www.eiffel.com
		Customer support http://support.eiffel.com
	]"

end -- class INTERACTIVE_LIST

Generated by ISE EiffelStudio