This site contains older material on Eiffel. For the main Eiffel page, see http://www.eiffel.com.

EiffelBase class
(HTML page generated by ISE Eiffel 4.2)

Eiffel Class
indexing
	description: "Sequential, two-way linked lists";
	status: "See notice at end of class";
	names: two_way_list, sequence;
	representation: linked;
	access: index, cursor, membership;
	contents: generic;
	date: "$Date: 2007-03-30 19:10:11 +0000 (Fri, 30 Mar 2007) $";
	revision: "$Revision: 95354 $"

class TWO_WAY_LIST [G]

inherit
	LINKED_LIST [G]
		redefine
			first_element, last_element, extend, put_front, put_left, put_right, merge_right, merge_left, new_cell, remove, remove_left, remove_right, wipe_out, previous, finish, move, islast, new_chain, forth, back
		select
			put_front, merge_right, move, put_right, wipe_out
		end;
	LINKED_LIST [G]
		rename
			put_front as ll_put_front,
			put_right as ll_put_right,
			merge_right as ll_merge_right,
			move as ll_move,
			wipe_out as ll_wipe_out
		export
			{NONE} ll_put_front, ll_put_right, ll_move, ll_merge_right, ll_wipe_out
		redefine
			put_left, merge_left, remove, new_chain, remove_left, finish, islast, first_element, extend, last_element, previous, new_cell, remove_right, forth, back
		end

creation
	make_sublist,
	make

feature -- Access

	first_element: BI_LINKABLE [G];
			-- Head of list
			-- (Anchor redefinition)

	last_element: like first_element;
			-- Tail of the list

	sublist: like Current;
			-- Result produced by last split

feature -- Status report

	islast: BOOLEAN is
			-- Is cursor at last position?
		do
			Result := (active = last_element) and then notafter and then notbefore
		end;

feature -- Cursor movement

	forth is
			-- Move cursor to next position, if any.
		do
			if before then
				before := false;
				if empty then
					after := true
				end
			else
				active := active.right;
				if active = void then
					active := last_element;
					after := true
				end
			end
		end;

	back is
			-- Move cursor to previous position, if any.
		do
			if after then
				after := false;
				if empty then
					before := true
				end
			else
				active := active.left;
				if active = void then
					active := first_element;
					before := true
				end
			end
		end;

	finish is
			-- Move cursor to last position.
			-- (Go before if empty)
		do
			if notempty then
				active := last_element;
				after := false;
				before := false
			else
				after := false;
				before := true
			end
		ensure
			not_after: notafter
		end;

	move (i: INTEGER) is
			-- Move cursor i positions. The cursor
			-- may end up off if the offset is to big.
		local
			c: CURSOR;
			counter: INTEGER;
			p: like first_element
		do
			if i > 0 then
				ll_move (i)
			elseif i < 0 then
				if after then
					after := false;
					counter := -1
				end;
				from
					p := active
				until
					(counter = i) or else (p = void)
				loop
					p := p.left;
					counter := counter - 1
				end;
				if p = void then
					before := true;
					active := first_element
				else
					active := p
				end
			end
		end;

feature -- Element change

	put_front (v: like item) is
			-- Add v to beginning.
			-- Do not move cursor.
		do
			ll_put_front (v);
			if count = 1 then
				last_element := first_element
			end
		end;

	extend (v: like item) is
			-- Add v to end.
			-- Do not move cursor.
		local
			p: like first_element
		do
			p := new_cell (v);
			if empty then
				first_element := p;
				active := p
			else
				p.put_left (last_element)
			end;
			last_element := p;
			if after then
				active := p
			end;
			count := count + 1
		end;

	put_left (v: like item) is
			-- Add v to the left of cursor position.
			-- Do not move cursor.
		local
			p: like first_element
		do
			p := new_cell (v);
			if empty then
				first_element := p;
				last_element := p;
				active := p;
				before := false
			elseif after then
				p.put_left (last_element);
				last_element := p;
				active := p
			elseif isfirst then
				p.put_right (active);
				first_element := p
			else
				p.put_left (active.left);
				p.put_right (active)
			end;
			count := count + 1
		end;

	put_right (v: like item) is
			-- Add v to the right of cursor position.
			-- Do not move cursor.
		local
			was_last: BOOLEAN
		do
			was_last := islast;
			ll_put_right (v);
			if count = 1 then
				last_element := active
			elseif was_last then
				last_element := active.right
			end
		end;

	merge_left (other: like Current) is
			-- Merge other into current structure before cursor
			-- position. Do not move cursor. Empty other.
		local
			other_first_element: like first_element;
			other_last_element: like first_element;
			other_count: INTEGER
		do
			if notother.empty then
				other_first_element := other.first_element;
				other_last_element := other.last_element;
				other_count := other.count;
				check
					other_first_element /= void;
					other_last_element /= void
				end;
				if empty then
					last_element := other_last_element;
					first_element := other_first_element;
					if before then
						active := first_element
					else
						active := last_element
					end
				elseif isfirst then
					other_last_element.put_right (first_element);
					first_element := other_first_element
				elseif after then
					other_first_element.put_left (last_element);
					last_element := other_last_element;
					active := last_element
				else
					other_first_element.put_left (active.left);
					active.put_left (other_last_element)
				end;
				count := count + other_count;
				other.wipe_out
			end
		end;

	merge_right (other: like Current) is
			-- Merge other into current structure after cursor
			-- position. Do not move cursor. Empty other.
		do
			if empty or else islast then
				last_element := other.last_element
			end;
			ll_merge_right (other)
		end;

feature -- Removal

	remove is
			-- Remove current item.
			-- Move cursor to right neighbor
			-- (or after if no right neighbor).
		local
			succ, pred, removed: like first_element
		do
			removed := active;
			if isfirst then
				active := first_element.right;
				first_element.forget_right;
				first_element := active;
				if count = 1 then
					check
						no_active: active = void
					end;
					after := true;
					last_element := void
				end
			elseif islast then
				active := last_element.left;
				last_element.forget_left;
				last_element := active;
				after := true
			else
				pred := active.left;
				succ := active.right;
				pred.forget_right;
				succ.forget_left;
				pred.put_right (succ);
				active := succ
			end;
			count := count - 1;
			cleanup_after_remove (removed)
		end;

	remove_left is
			-- Remove item to the left of cursor position.
			-- Do not move cursor.
		do
			back;
			remove
		end;

	remove_right is
			-- Remove item to the right of cursor position.
			-- Do not move cursor.
		do
			forth;
			remove;
			back
		end;

	wipe_out is
			-- Remove all items.
		do
			ll_wipe_out;
			last_element := void
		end;

	split (n: INTEGER) is
			-- Remove from current list
			-- min (n, count - index - 1) items
			-- starting at cursor position.
			-- Move cursor right one position.
			-- Make extracted sublist accessible
			-- through attribute sublist.
		require
			not_off: notoff;
			valid_sublist: n >= 0
		local
			actual_number, active_index: INTEGER;
			p_elem, s_elem, e_elem, n_elem: like first_element
		do
			if n = 0 then
				create sublist.make
			else
				active_index := index;
				if active_index + n > count + 1 then
					actual_number := count + 1 - active_index
				else
					actual_number := n
				end;
				s_elem := active;
				p_elem := previous;
				move (actual_number - 1);
				e_elem := active;
				n_elem := next;
				s_elem.forget_left;
				e_elem.forget_right;
				create sublist.make_sublist (s_elem, e_elem, actual_number);
				count := count - actual_number;
				if p_elem /= void then
					p_elem.put_right (n_elem)
				else
					first_element := n_elem
				end;
				if n_elem /= void then
					active := n_elem
				else
					last_element := p_elem;
					active := p_elem;
					after := true
				end
			end
		end;

	remove_sublist is
		do
			sublist := void
		end;

feature {TWO_WAY_LIST} -- Implementation

	make_sublist (first_item, last_item: like first_element; n: INTEGER) is
			-- Create sublist
		do
			make;
			first_element := first_item;
			last_element := last_item;
			active := first_element;
			count := n
		end;

	new_chain: like Current is
			-- A newly created instance of the same type.
			-- This feature may be redefined in descendants so as to
			-- produce an adequately allocated and initialized object.
		do
			create Result.make
		end;

	new_cell (v: like item): like first_element is
			-- A newly created instance of the type of first_element.
		do
			create Result;
			Result.put (v)
		end;

	previous: like first_element is
			-- Element left of cursor
		do
			if after then
				Result := active
			elseif active /= void then
				Result := active.left
			end
		end;

end -- class TWO_WAY_LIST