work in progress | string

Class STRING

Jim McKim's specifications
September 1999


Here's a cut at STRING. The starting point was the Elks 2000 proposal from Dominique, Manu, and Olivier. That version was quite well done with many features completely or nearly completely specified. (The inclusion of a concatenation operator, "+" is particularly important and useful.) I've tried to be even more complete and to use compilable specs whenever possible. In a few cases I've recommended some additional features as I think they may be useful in their own right as well as helping with the spec. I particular, "has_substring" seems like a natural.

In each case I've tried to mark the changes I made from the original. I've also tried to be clear where I'm not sure how to write the spec.

I _think_ the only really controversial issue here is that of `capacity'. I've pretty much punted on that issue for now.

Enjoy,
-- Jim McKim


indexing
description: "Resizable sequences of characters, accessible through %
    %integer indices in a contiguous range. If not empty, first element%
    %is at index 1."

Basic specifiers: count, item
Auxiliary specifiers (1): valid_index, substring, is_equal, "<" Auxiliary specifiers (2): has, has_substring, same_as, "+" Auxiliary specifiers (3): occurrences

class interface
	STRING
creation
	make (n: INTEGER)
	        -- Allocate space for at least n characters.
	    require
	        non_negative_size: n >= 0
	    ensure
	        empty_string: count = 0
	        correctly_allocated_size: capacity >= n

[Same problems with `capacity' as in ARRAY. Just kill it and provide a  `make_empty' routine? Include `requested_capacity'? Leave as is?]

	make_from_external (ptr: POINTER)
	        -- Set Current with a copy of the content of ptr.
	        -- Assume ptr is a null-terminated memory area containing
	        -- only characters.
	        -- The extra null character is not part of the Eiffel string
	    require
	        ptr_exists: ptr /= default_pointer

	make_from_string (s: STRING)
 	       -- Initialize from the characters of s.
 	       -- (Useful in proper descendants of class STRING,
	        -- to initialize a string-like object from a manifest string.)
	    require
	        string_exists: s /= Void
	    ensure
	        count_set: count = s.count

[Can't claim is_equal (s) here, 'cause descendant won't be of type STRING.  Can we say for_all i, 1..count (item (i) = s.item (i))? Can we say anything?]

feature -- Initialization
	make (n: INTEGER)
	        -- Allocate space for at least n characters.
	    require
	        non_negative_size: n >= 0
	    ensure
	       empty_string: count = 0
 	       correctly_allocated_size: capacity >= n

	make_from_external (ptr: POINTER)
	       -- Set Current with a copy of the content of ptr.
 	       -- Assume ptr is a null-terminated memory area containing
 	       -- only characters.
 	       -- The extra null character is not part of the Eiffel string
 	   require
  	      ptr_exists: ptr /= default_pointer

	make_from_string (s: STRING)  	       -- Initialize from the characters of s.
  	       -- (Useful in proper descendants of class STRING,
 	       -- to initialize a string-like object from a manifest string.)
	    require
	        string_exists: s /= Void
	    ensure
 	       count_set: count = s.count

feature - Access

	first: CHARACTER
   	     -- First character of Current.
  	   require
   	     not_empty_string: count > 0
   	   ensure
   	     definition: Result = item (1)

[Changed precondition to reduce dependencies, changed tag of postcondition]

	has (c: CHARACTER): BOOLEAN
	     -- Does Current contain c? 
 	   ensure
   	     false_if_empty: count = 0 implies not Result
 	     true_if_first: count > 0 and then item (1) = c implies Result
	     recurse: (count > 0 and then item (1) /= c) implies 
						(Result = substring (2, count).has (c))

[Complete spec.]

	has_substring (other : STRING ) : BOOLEAN
		-- Does Current contain `other'?
	   require
		other_not_void: other /= Void
		other_not_empty: other.count > 0
	   ensure
		false_if_too_small: count < other.count implies not Result
		true_if_initial: (count >= other.count and then
  			other.is_equal (substring (1, other.count)) implies Result
		recurse: (count >= other.count and then
			not other.is_equal (substring (1, other.count)) implies 
			(Result = substring (2, count).has_substring (other))

[New routine. Parallel to `has'. Makes corresponding `index' routines easier  to describe. Useful in its own right?]

	hash_code: INTEGER   	      -- Hash code value
 	       -- (From HASHABLE.)
 	   ensure
   	     good_hash_value: Result >= 0	-- Vendor dependent hashing function

[Added comment]

	index_from (c: CHARACTER; start_index: INTEGER): INTEGER
     			-- Index of first occurrence of c at or after start_index; 
   	     		-- 0 if none.
    		require
  	      	valid_start_index: valid_index (start_index)
  	    	ensure
	  		valid_result: 
				Result >= 0 or (start_index <= Result and Result <= count)
	  		zero_if_absent: (Result = 0) = not has (c)
	  		found_if_present: has (c) implies item (Result) = c
	  		none_before: has (c) implies 
				not substring (start_index, Result - 1).has (c) 

[Compilable version, perhaps simpler.]

	index_of (c: CHARACTER): INTEGER
        		-- Index of first occurrence of c; 
        		-- 0 if none.
    		ensure
	  		valid_result: Result >= 0 and Result <= count
	  		zero_if_absent: (Result = 0) = not has (c)
	  		found_if_present: has (c) implies item (Result) = c
	  		none_before: has (c) implies 
				not substring (1, Result - 1).has (c)
 
[Removed dependency on `index_from', not necessarily a good thing, as 
this version is more complex.]

	item (i: INTEGER): CHARACTER
			-- Character at index i
			-- Basic specifier
    	    require
 	       	good_key: valid_index (i)

	infix "@": CHARACTER
        		-- Character at index i
    		require
        		good_key: valid_index (i)
    		ensure
	  		definition: Result = item (i)

[Split `item' and `@' in order to define one in terms of the other.]

	last: CHARACTER
        		-- Last character of Current.
    		require
        		not_empty_string: count > 0
 	    	ensure
  	        	definition: Result = item (count)

[Changed precondition to reduce dependencies, changed tag of postcondition]

	reverse_index_from (c: CHARACTER; last_index: INTEGER): INTEGER
  	      	-- Index of first occurrence of c at or before last_index; 
  	      	-- 0 if none.
 	   	require
	        	valid_last_index: valid_index (last_index)
	   	ensure
		  	valid_result: Result >= 0 and Result <= last_index
		  	zero_if_absent: (Result = 0) = not has (c)
		  	present_implies_found: has (c) implies item (Result) = c
		  	none_after: has (c) implies 
				not substring (Result + 1, last_index).has (c)

[Compilable, perhaps simpler]

	reverse_index_of (c: CHARACTER): INTEGER
 	       -- Index of last occurrence of c; 
 	       -- 0 if none.
 	   ensure
		  valid_result: Result >= 0 and Result <= count
		  zero_if_absent: (Result = 0) = not has (c)
		  present_implies_found: has (c) implies item (Result) = c
		  none_after: has (c) implies 
			not substring (Result + 1, count).has (c)

[Removed dependency on `index_from', not necessarily a good thing, as this  version is more complex.]

	reverse_string_index_from (other: STRING; last_index: INTEGER): INTEGER
  	      	-- Index of first occurrence of `other' at or before 
			-- `last_index'; 0 if none.
 	   	require
	 		other_not_void: other /= Void
 	       	other_not_empty: other.count > 0
 	       	valid_last_index: valid_index (last_index)
    		ensure
	  		valid_result: Result >= 0 and Result <= last_index
	  		zero_if_absent: (Result = 0) = 
not substring (1, count.min (last_index + other.count-1).has_substring (other)
	  		enough_room: Result > 0 implies 
				(Result + other.count-1 <= count)
	  		at_this_index: Result > 0 implies 
			   other.is_equal (substring (Result, Result + other.count - 1))
	  		none_after: 
not substring (Result + 1, count.min (last_index + other.count - 1).has_substring (other))

[Added not_void precondition. Used has_substring to simplify and make compilable.]

	reverse_string_index_of (other: STRING): INTEGER
	        	-- Index of last occurrence of other; 
 	        	-- 0 if none.
	    	require
	        	other_not_void: other /= Void
	        	other_not_empty: other.count > 0
	    	ensure
	  		valid_result: Result >= 0 and Result <= count
	  		zero_if_absent: (Result = 0) = not has_substring (other)
	  		enough_room: Result > 0 implies Result + other.count - 1 <= count
	  		at_this_index: Result > 0 implies 
			  other.is_equal (substring (Result, Result + other.count - 1))
	  		none_after: not substring (Result + 1, count).has_substring (other))

[Removed dependency on reverse_string_index_from. Adds complexity though.]

	
	string_index_from (other: STRING; start_index: INTEGER): INTEGER
  	       	-- Index of first occurrence of other at or after start; 
 	       	-- 0 if none.
 	   	require
	  		other_not_void: other /= Void
 	      	other_not_empty: other.count > 0
        		valid_start_index: valid_index (start_index)
 	   	ensure
		 	valid_result: Result = 0 or else 
				(start_index <= Result and Result <= count)
		 	zero_if_absent: (Result = 0) = 
				not substring (start_index, count).has_substring (other)
		 	enough_room: Result >= start_index implies 
				Result + other.count - 1 <= count
		 	at_this_index: Result >= start_index implies 
			  other.is_equal (substring (Result, Result + other.count - 1))
		 	none_before: Result >= start_index implies 
not substring (start_index, Result + other.count - 2).has_substring (other))

[Used has_substring to simplify and make compilable.]

	string_index_of (other: STRING): INTEGER
  	      	-- Index of first occurrence of other; 
  	      	-- 0 if none.
  	  	require
			other_not_void: other /= Void
 	      	other_not_empty: other.count > 0
  	  	ensure
			valid_index: 0 <= Result and Result <= count
			zero_if_absent: (Result = 0) = not has_substring (other)
			enough_room: Result > 0 implies Result + other.count - 1 < count
			at_index: Result > 0 implies 
			  other.is_equal (substring (Result, Result + other.count - 1))
			none_before: Result > 0 implies 
not substring (1, Result + other.count - 2).has_substring (other))

[Removed dependency on string_index_from, paying some cost in complexity.]

feature -- Measurement
	count: INTEGER
        		-- Current number of characters making up the string
	  		-- Basic specifier

	capacity: INTEGER
        		-- Number of characters that Current can currently contain 
			-- in the internal storage area.
        		-- Automatically updated when resizing is needed. Useful 
			-- for fine tuning.
		ensure
	  		large_enough: Result >= count  -- nondeterministic

[Added postcondition]

	occurrences (c: CHARACTER): INTEGER
        		-- Number of times c appears in the string
    		ensure
        		zero_if_empty: count = 0 implies Result = 0
	  		simple_recurse: (count > 0 and then item (1) /= c) implies 
				Result = substring (2, count).occurrences
	  		Recurse_and_add: (count > 0 and then item (1) = c) implies
				Result = 1 + substring (2, count).occurrences
[Complete spec.]

feature - Comparison

	is_equal (other: like Current): BOOLEAN
        		-- Is string made of same character sequence as other?
        		-- (Redefined from GENERAL.)
    		require
        		other_not_void: other /= Void
		ensure
			definition: Result = (count = other.count and then
				(count > 0 implies (item (1) = other.item (1) and 
				substring (2, count).is_equal (other.substring (2, count)))

[Added postcondition]

    
	infix "<" (other: like Current): BOOLEAN
        	-- Is string lexicographically lower than other?
        	-- (False if other is void)
        	-- (From COMPARABLE.)
    	require
        	other_exists: other /= Void
    	ensure
        	asymmetric: Result implies not (other < Current)
	ensure then
		definition: Result = (count = 0 and other.count > 0) or else
			(count > 0 and then other.count > 0 and then 
			(item (1) < other.item (1) or 
(item (1) = other.item (1) and substring (2, count) < other.substring (2, count))))

[Completed spec.]

	
	infix "<=" (other: like Current): BOOLEAN
        		-- Is current object less than or equal to other?
        		-- (From COMPARABLE.)
    		require
        		other_exists: other /= Void
    		ensure
        		definition: Result = (Current < other) or is_equal (other);

	infix ">=" (other: like Current): BOOLEAN
        		-- Is current object greater than or equal to other?
        		-- (From COMPARABLE.)
    		require
        		other_exists: other /= Void
    		ensure
        		definition: Result = (other <= Current)

	infix ">" (other: like Current): BOOLEAN
        		-- Is current object greater than other?
        		-- (From COMPARABLE.)
    		require
        		other_exists: other /= Void
    		ensure
        		definition: Result = (other < Current)

	max (other: like Current): like Current)
        		-- The greater of current object and other
        		-- (From COMPARABLE.)
    		require
        		other_exists: other /= Void
    		ensure
        		current_if_not_smaller: 
				(Current >= other) implies (Result = Current)
        		other_if_smaller: 
				(Current < other) implies (Result = other)

	min (other: like Current): like Current)
        		-- The smaller of current object and other
        		-- (From COMPARABLE.)
    		require
        		other_exists: other /= Void
    		ensure
        		current_if_not_greater: 
				(Current <= other) implies (Result = Current)
        	other_if_greater: 
				(Current > other) implies (Result = other)

	same_as (other: STRING): BOOLEAN
        		-- Is string made of same character sequence as other?
        		-- Case insensitive comparison.
    		require
        		other_exists: other /= Void
		ensure
			definition: 
				Result = (count = other.count and then (count > 0 implies
				(item (1).upper = other.item (1).upper and
				substring (2, count).same_as (other.substring (2, count))))

[Completed spec, note that this assumes CHARACTER has a feature `upper'  or equivalent.]

	three_way_comparison (other: like Current): INTEGER
        		-- If current object equal to other, 0; if smaller,
        		-- -1; if greater, 1.
        		-- (From COMPARABLE.)
    		require
        		other_exists: other /= Void
    		ensure
        		equal_zero: (Result = 0) = is_equal (other);
        		smaller: (Result = -1) = Current < other;
        		greater_positive: (Result = 1) = Current > other

feature -- Status report

	is_empty: BOOLEAN
        		-- Is string empty?
    		ensure
        		definition: Result = (count = 0)

	valid_index (index: INTEGER): BOOLEAN
        		-- Is `index' within the bounds of the string?
    		ensure
        		definition: Result = (1 <= index and index <= count)

[Changed comment `i' to `index']

	is_boolean: BOOLEAN
        		-- Is Current representing a boolean ("true" or "false" with no
        		-- case consideration)?
		ensure
			definition: Result = (same_as ("TRUE") or same_as ("FALSE"))

[Added postcondition.]

		
	is_double: BOOLEAN
        		-- Can Current be read as a DOUBLE?
		false_if_empty: count = 0 implies not Result
[gulp. Not sure what all the possibilities are here.]

	is_integer: BOOLEAN
        		-- Can Current be read as an INTEGER?
		false_if_empty: count = 0 implies not Result
		false_if_bad_start: 
			count > 0 and not item (1).is_digit implies not Result
		true_anchor: count = 1 and item (1).is_digit implies Result
		recurse: count > 0 and item (1).is_digit implies 
				Result = substring (2, count).is_integer

[Added postcondition. Assumes no leading or trailing white space is allowed.]

	is_real: BOOLEAN
        		-- Can Current be read as a REAL?
		false_if_empty: count = 0 implies not Result

[gulp. Not sure what all the possibilities are here.]

feature -- Element change

	add, insert (c: CHARACTER; i: INTEGER)
        		-- Insert c at index i, shifting characters between ranks i 
			-- and count rightwards.
    		require
        		valid_insertion_index: 1 <= i and i <= count + 1
    		ensure
			inserted: 
		is_equal (old substring (1, i - 1) + c.out + old substring (i, count)

[Completed and simplified postcondition. Needed, given `put'?]

	add_first, precede (c: CHARACTER)
        		-- Prepend c at beginning.
    		ensure
        		inserted: is_equal (c.out + old clone (Current))

[Completed and simplified postcondition]

	add_last, append_character, extend (c: CHARACTER)
        		-- Append c at end.
    		ensure
        		inserted: is_equal (old clone (Current) + c.out)

[Completed and simplified postcondition]

	append, append_string (s: STRING)
        		-- Append a copy of s at end.
    		require
        		other_exists: s /= Void
    		ensure
			appended: is_equal (old clone (Current) + old clone (s))

[Completed and simplified postcondition.]

	append_boolean (b: BOOLEAN)
        		-- Append the string representation of b at end.
    		ensure
			appended: is_equal (old clone (Current) + b.out)

[Completed and simplified postcondition.]

	append_double (d: DOUBLE)
        		-- Append the string representation of d at end.
    		ensure
			appended: is_equal (old clone (Current) + d.out)

[Completed and simplified postcondition.]

	append_integer (i: INTEGER)
        		-- Append the string representation of i at end.
    		ensure
			appended: is_equal (old clone (Current) + i.out)

[Completed and simplified postcondition.]

	append_real (r: REAL)
        		-- Append the string representation of r at end.
    		ensure
			appended: is_equal (old clone (Current) + r.out)

[Completed and simplified postcondition.]

	fill (c: CHARACTER)
        		-- Replace every character with c.
    		ensure
        		same_count: old count = count
        		filled: occurrences(c) = count

	head (n: INTEGER)
        		-- Remove all characters except for the first n; 
        		-- do nothing if n >= count.
    		require
        		non_negative_argument: n >= 0
    		ensure
			first_kept: is_equal (old substring (1, n.min (count)))

[Should have a verb name. Completed and simplified postcondition.]

	insert_string (s: like Current; i: INTEGER)
        		-- Insert s at index i, shifting characters between ranks 
			-- i and count rightwards.
    		require
        		string_exists: s /= Void; 
        		valid_insertion_index: 1 <= i and i <= count + 1
    		ensure
			inserted: 
is_equal(old substring (1, i - 1) + old clone (s) + old substring (i, count))

[Completed and simplified postcondition.]

	left_adjust
        		-- Remove leading white space.
    		ensure
        		shorter: count <= old count
        		first_not_white_space: not is_empty implies 
						("%T%R%N ").index_of (first) = 0

[Warning! _Long_ comment coming. (That second clause is really quite clever!)  I've never been sure why this feature isn't called `remove_leading_white_space'.  Anyway, I don't see a way to give a complete, compilable spec without some help.  I can give a complete spec as a comment. Something like

-- there_exists k, 1..old count 
	((old clone(Current)).is_equal(old substring(1, k) + Current) and
	 for_all i, 1..k (("%T%R%N ").index_of (old item (i)) > 0)) and
	 (k = old count or else (("%T%R%N ").index_of (old item (k + 1) = 0)))
Whew!
The help I would need to write a compilable spec is a feature like
	first_dark_index : INTEGER
      		-- Index of first character that is not white space, count + 1
			-- if no such character.
	ensure
		empty_case: count = 0 implies Result = 1
		dark_anchor: 
count > 0 and then ("%T%R%N ").index_of (item (1)) = 0 implies Result = 1
		recurse: 
count > 0 and then ("%T%R%N ").index_of (item (1)) > 0 implies 
				Result = 1 + substring (2, count).first_dark_index

Now the postcondition for `left_adjust' is just one line

(old clone (Current)).is_equal (old substring(1, first_dark_index-1) + Current)

Trouble is, I'm not convinced `first_dark_index' is independently useful enough to be in the kernel.]

	put (c: CHARACTER; i: INTEGER)
        		-- Replace character at index i by c.
    		require
        		good_key: valid_index (i)
    		ensure
        		inserted:
is_equal (old substring (1, i - 1) + c.out + old substring (i, count))

[Completed postcondition.]

	right_adjust
        		-- Remove trailing white space.
    		ensure
        		shorter: count <= old count
        		last_not_white_space: not is_empty implies 
						("%T%R%N ").index_of (last) = 0

[Similar comments to `left_adjust'.]

	subcopy (other: like Current; start_pos, end_pos, from_index: INTEGER) is
        		-- Copy characters of other within bounds start_pos and
        		-- end_pos to current string starting at index from_index.
    		require
        		other_not_void: other /= Void;
        		valid_start_pos: other.valid_index (start_pos)
        		valid_end_pos: other.valid_index (end_pos)
        		valid_bounds: start_pos <= end_pos
        		valid_from_index: valid_index (from_index)
        		enough_space: valid_index (from_index + end_pos - start_pos)
    		ensure
			copied: is_equal (old substring (1, from_index - 1) + 
			   old other.substring (start_pos, end_pos) +
			   old substring (from_index + end_pos - start_pos + 1, old count))

[Completed postcondition.]

	tail (n: INTEGER)
        		-- Remove all characters except for the last n; 
        		-- do nothing if n >= count.
    		require
        		non_negative_argument: n >= 0
    		ensure
			last_kept: 
			   is_equal (old substring (count - n.min (count) + 1, count))

[Should have a verb name. Completed and simplified postcondition.]

feature -- Removal

	remove (i: INTEGER)
         		-- Remove i-th character, shifting characters between 
			-- ranks i + 1 and count leftwards.
    		require
        		valid_removal_index: valid_index (i)
    		ensure
			removed: is_equal (old substring (1, i - 1) +
							old substring (i + 1, count)

[Completed postcondition.]

	wipe_out
        		-- Remove all characters.
    		ensure
        		empty_string: count = 0

[Removed `same_capacity' from postcondition as not sure what to do about `capacity' in general yet. Removed `same_lower', I think it was just a slip that it was there in the first place.]

feature -- Conversion

	to_boolean: BOOLEAN
        		-- Boolean value; 
        		-- "true" yields true, "false" yields false
        		-- (case-insensitive)
    		require
        		is_boolean: is_boolean
		ensure
			converted: Result = same_as ("TRUE")

[The comment doesn't say anything about removing white space, but ISE's
implementation does. If that's what we want then maybe those `dark_index'
features aren't so crazy. We could use
  
converted: Result = substring (first_dark_index, last_dark_index).same_as ("TRUE")
			

	to_double: DOUBLE
        		-- Double value; for example, when applied to "123.0",
        		-- will yield 123.0 (double)
    		require
        		is_double: is_integer or is_real or is_double

[Not sure what to do for postcondition here. Help!]                

	to_external: POINTER
        		-- Address of the storage area containing the actual 
			-- sequence of characters,
        		-- to be passed to some external (non-Eiffel) routine.
        		-- Keep in mind that this storage area is subject to garbage 
			-- collection.

	to_integer: INTEGER
        		-- Integer value; 
        		-- for example, when applied to "123", will yield 123
    		require
        		is_integer: is_integer

[Not sure what to do for postcondition here. Help!]                

	to_lower
        		-- Convert to lower case.
		ensure
			same_count: count = old count
			converted: 
				-- for_all i, 1..count (item (i) = old item (i).lower)

[I don't see a compilable version without a query version of this (lower?), but at least the comment is pretty simple in this case.]

	to_real: REAL
        		-- Real value; 
        		-- for example, when applied to "123.0", will yield 123.0
    		require
        		is_real: is_integer or is_real

[Not sure what to do for postcondition here. Help!]                

	to_upper
        		-- Convert to upper case.
		ensure
			same_count: count = old count
			converted: 
				-- for_all i, 1..count (item (i) = old item (i).upper)

[Same issues as with `to_lower'.]

feature -- Duplication

	copy (other: like Current)
        		-- Reinitialize by copying the characters of other.
        		-- (From GENERAL.)
    		ensure
        		new_result_count: count = other.count
        		-- same_characters: For every i in 1..count,
        		--     item (i) = other.item (i)

[I didn't change this, but there's no need for any new postconditions, is there? The postcondition from GENERAL is `is_equal (other)' which covers both of these.]

	infix "+" (other: STRING): like Current
        		-- Create a new object which is the concatenation of Current and other.
    		require
        		other_exists: other /= Void
    		ensure
        		result_count: Result.count = count + other.count
			initial: Result.substring (1..count).is_equal (Current)
			final: 
Result.substring (count + 1, count + other.count).is_equal (other)

[Completed postcondition]

	substring (start_index, end_index: INTEGER): like Current
        		-- Create a substring containing all characters from start_index
        		-- to end_index included.
    		require
        		valid_start_index: 1 <= start_index
        		valid_end_index: end_index <= count
        		meaningful_interval: start_index <= end_index + 1
    		ensure
        		result_count: Result.count = end_index - start_index + 1
			first_item: Result.count > 0 implies 
						Result.item (1) = item (start_index)
			recurse: Result.count > 0 implies
Result.substring(2, Result.count).is_equal(substring(start_index + 1, end_index))

[Major changes in precondition to allow various empty cases. Completed  postcondition.]

feature -- Output

	out: STRING
        		-- Printable representation
        		-- (From GENERAL.)
    		ensure
        		result_not_void: Result /= Void
        		duplicated_result: Result /= Current and Result.is_equal (Current)

feature -- Optimization

	adjust_capacity (n: INTEGER)
        		-- Rearrange string so that it can accommodate
        		-- at least n characters.
        		-- Do not lose any previously entered character.
    		require
        		no_item_lost: n >= count
    		ensure
        		enough_capacity: capacity >= n

invariant
	non_negative_count: count >= 0
	capacity_big_enough: capacity >= count
end

Copyright (c) 1995, Nonprofit International Consortium for Eiffel
            
            Last Updated:  01 September 1999