elapsed.sa
Generated by gen_html_sa_files from ICSI. Contact gomes@icsi.berkeley.edu for details
-------------------------> GNU Sather - sourcefile <-------------------------
-- Copyright (C) 2000 by K Hopper, University of Waikato, New Zealand --
-- This file is part of the GNU Sather library. It is free software; you may --
-- redistribute and/or modify it under the terms of the GNU Library General --
-- Public License (LGPL) as published by the Free Software Foundation; --
-- either version 2 of the license, or (at your option) any later version. --
-- This library is distributed in the hope that it will be useful, but --
-- WITHOUT ANY WARRANTY without even the implied warranty of MERCHANTABILITY --
-- or FITNESS FOR A PARTICULAR PURPOSE. See Doc/LGPL for more details. --
-- The license text is also available from: Free Software Foundation, Inc., --
-- 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA --
--------------> Please email comments to <bug-sather@gnu.org> <--------------
immutable class ELAPSED < $ORDERED{ELAPSED}, $HASH, $BINARY, $TEXT, $ANCHORED_FMT
immutable class ELAPSED < $ORDERED{ELAPSED}, $HASH, $BINARY, $TEXT, $ANCHORED_FMT is
-- This class embodies the abstraction of a period of time rather than
-- an instant or time-stamp. Values of this kind are never negative.
-- Version 1.4 May 2001. Copyright K Hopper, U of Waikato
-- Development History
-- -------------------
-- Date Who By Detail
-- ---- ------ ------
-- 3 Jun 96 kh Original from std Sather distrib.
-- 8 Apr 97 kh Modified for INT to CARD
-- 25 Feb 98 kh made a sub-class of $BINARY
-- 5 Oct 98 kh factored out ELAPSED_STR.
-- 29 Oct 98 kh Refined, added pre/post conditions
-- 31 May 01 kh Added $ORDERED sub-typing
include COMPARABLE ;
include BINARY ;
include ELAPSED_STR ;
private const Millisecs_per_Second : CARD := 1000 ;
private const Millisecs_per_Minute : CARD := 1000 * 60 ;
private const Minutes_per_Hour : CARD := 60 ;
private const Seconds_per_Minute : CARD := 60 ;
private const Millisecs_per_Hour : CARD := 1000 * 60 * 60 ;
private const Hours_per_Day : CARD := 24 ;
private const Minutes_per_Day : CARD := 60 * Hours_per_Day ;
private const Seconds_per_Day : CARD := 60 * Minutes_per_Day ;
private const Millisecs_per_Day : CARD := Millisecs_per_Second *
Seconds_per_Day ;
const Invalid : SAME := days(CARD::nil).millisecs(CARD::nil) ;
readonly attr days : CARD ;
readonly attr millisecs : CARD ;
-- The above components correspond exactly to the components of a time
-- stamp, but they contain a time difference, rather than a 'clock' time.
create(dtime : TIME_STAMP) : SAME is
-- This routine creates a new elapsed time -- elapsed between the 'base
-- date' and dtime.
me: SAME;
return me.days(dtime.num_days).millisecs(dtime.num_milliseconds);
end ;
create(days : CARD, millis : CARD ) : SAME
pre (millis < Millisecs_per_Day)
post (result.days = days) and (result.millisecs = millis)
is
-- This routine creates a new elapsed time -- elapsed between the 'base
-- date' zero and the given component values.
me : SAME;
return me.days(days).millisecs(millis);
end ;
nil : SAME is
-- This routine yields a nil elapsed time.
return days(0).millisecs(CARD::nil)
end ;
one_second : SAME is
-- This routine yields a one second elapsed time.
return days(0).millisecs(Millisecs_per_Second)
end ;
one_minute : SAME is
-- This routine yields a one minute elapsed time.
return days(0).millisecs(Millisecs_per_Minute)
end ;
one_hour : SAME is
-- This routine yields a one hour elapsed time.
return days(0).millisecs(Millisecs_per_Hour)
end ;
one_day : SAME is
-- This routine yields a one day elapsed time.
return days(1).millisecs(0)
end ;
build(cursor : BIN_CURSOR) : SAME
pre (cursor.remaining >= (2 * CARD::zero.binstr.asize))
post true
is
-- This routine creates a new elapsed time from the given binary string.
me : SAME ;
return me.days(cursor.card).millisecs(cursor.card)
end ;
binstr : BINSTR
pre true
post (result.size = (days.binstr.size + millisecs.binstr.size))
is
-- This routine creates a storage representation of self in the form of
-- a binary string.
return days.binstr + millisecs.binstr
end ;
is_eq(other : SAME) : BOOL is
-- This predicate returns true if and only if self and other represent
-- the same elapsed time.
return (days = other.days) and (millisecs = other.millisecs)
end ;
is_lt(other : SAME ) : BOOL is
-- This predicate returns true if and only if self and other represent
-- the same elapsed time.
return (days < other.days)
or ((days = other.days) and (millisecs < other.millisecs))
end ;
is_nil : BOOL is
-- This predicate returns true if and only if self is a nil time.
return (days = 0) and (millisecs = CARD::nil)
end ;
plus( other : SAME) : SAME
pre ~self.is_nil and ~other.is_nil
post (((millisecs + other.millisecs) > Millisecs_per_Day)
and (result.days = (days + other.days + 1))
and (result.millisecs = (millisecs +
other.millisecs - Millisecs_per_Day)))
or ((result.days = (days + other.days))
and (result.millisecs = (millisecs + other.millisecs)))
is
-- This routine adds together the two elapsed times, self and other
-- and returns the result!
res : SAME ;
loc_time : CARD := millisecs + other.millisecs ;
if loc_time > Millisecs_per_Day then
loc_time := loc_time - Millisecs_per_Day ;
res := res.days(days + other.days + 1)
else
res := res.days(days + other.days)
end ;
res := res.millisecs(loc_time) ;
return res
end ;
private subtract(from, sub : SAME ) : SAME
pre ~self.is_nil and ~sub.is_nil and (from >= sub)
post ((sub.millisecs > from.millisecs)
and (((from.days > sub.days)
and (result.days = (from.days - sub.days - 1)))
or ((from.days = sub.days)
and (result.days = 0)))
and (result.millisecs = (from.millisecs +
Millisecs_per_Day - sub.millisecs)))
or((sub.millisecs <= from.millisecs)
and (result.days = (from.days - sub.days))
and (result.millisecs = (from.millisecs - sub.millisecs)))
is
-- This private routine subtracts sub, returning the difference as
-- an elapsed time.
num_days : CARD := from.days - sub.days ;
millis : CARD := from.millisecs ;
if sub.millisecs > from.millisecs then
millis := millis + Millisecs_per_Day ;
if num_days > 0 then
num_days := num_days - 1
end
end ;
return ELAPSED::create(num_days,(millis - sub.millisecs))
end ;
minus( other : SAME ) : SAME
pre ~self.is_nil and ~other.is_nil
post ((self < other) and (result = subtract(other,self)))
or ((self >= other) and (result = subtract(self,other)))
is
-- This returns the result of subtracting other from self. The result
-- is the time difference which is always positive!
if self < other then return subtract(other,self)
else return subtract(self,other)
end
end ;
private do_times( factor : CARD ) : SAME is
-- This routine returns an elapsed time which has been multiplied by
-- the factor indicated provided that this is possible without over-run when
-- the maximum representable elapsed time is returned - which is nevertheless
-- an invalid elapsed time!!
--
-- NOTE This has no pre-conditions in order to break a mutual recursion which
-- would otherwise happen indefinitely!
if (CARD::maxval / factor) < days then
return Invalid
else
loc_days : CARD ;
loc_millis : CARD ;
loc_days := loc_days * factor ;
extra_days := 0 ;
multiplier : CARD := Millisecs_per_Day / millisecs ;
loop_cnt : CARD := factor / multiplier ;
-- NOTE The count is in 'chunks' of milliseconds which
-- total less than millisecs from Milliseconds_per_Day.
-- This considerably reduces the loop count in most cases.
left_over : CARD := factor % multiplier ;
milliseconds : CARD := left_over * millisecs ;
difference : CARD := Millisecs_per_Day - milliseconds ;
loop -- to multiply millisecs
loop_cnt.times! ;
if left_over > difference then
extra_days := extra_days + 1 ;
left_over := left_over - difference
else
left_over := left_over + milliseconds
end
end ;
if CARD::maxval - extra_days > loc_days then
return Invalid
else
return days(loc_days + extra_days).millisecs(left_over)
end
end
end ;
times( factor : CARD ) : SAME
pre ~self.is_nil and (CARD::maxval / factor <= days)
post true
is
-- This routine returns an elapsed time which has been multiplied by
-- the factor indicated provided that this is possible without over-run when
-- the maximum representable elapsed time is returned - which is nevertheless
-- an invalid elapsed time!!
return do_times(factor)
end ;
div( factor : CARD ) : SAME
pre ~self.is_nil and factor > 0
post true
is
-- This routine returns an elapsed time which has been divided by
-- the given factor. Division is integer division and may result in the loss
-- of some fraction of a millisecond when calculating the result.
loc_days : CARD := days / factor ;
extra_days : CARD := days % factor ;
millisecs_per_day : CARD := Millisecs_per_Day / factor ;
loc_millisecs : CARD := (extra_days * millisecs_per_day) +
(millisecs / factor) ;
return days(loc_days).millisecs(loc_millisecs)
end ;
total_days : CARD is
-- This routine returns the whole number of days in self
return days
end ;
hours : CARD
pre ~self.is_nil
post (result = (millisecs / Millisecs_per_Hour))
is
-- This routine returns the number of hours in the part of a day
-- represented by self.
return millisecs / Millisecs_per_Hour
end ;
total_hours : CARD
pre ~self.is_nil and (((CARD::maxval / Hours_per_Day) - 1) >= days)
post (result = ((days * Hours_per_Day) + hours))
is
-- This routine returns the whole number of hours in self if this is
-- representable.
return days * Hours_per_Day + hours
end ;
minutes : CARD
pre ~self.is_nil
post (result = (millisecs / Millisecs_per_Minute))
is
-- This routine returns the number of minutes in the part of the day
-- represented by self.
return millisecs / Millisecs_per_Minute
end ;
minutes_in_hour : CARD
pre ~self.is_nil
post (result = (minutes % Minutes_per_Hour))
is
-- This routine returns the number of minutes in the part of the day
-- represented by self.
return minutes % Minutes_per_Hour
end ;
total_minutes : CARD
pre ~self.is_nil and (((CARD::maxval / Minutes_per_Day) - 1) >= days)
post (result = ((days * Minutes_per_Day) + minutes))
is
-- This routine returns the whole number of minutes in self if this is
-- representable.
return days * Minutes_per_Day + minutes
end ;
seconds : CARD
pre ~self.is_nil
post (result = (millisecs / Millisecs_per_Second))
is
-- This routine returns the number of seconds in the part of a day
-- represented by self.
return millisecs / Millisecs_per_Second
end ;
seconds_in_minute : CARD
pre ~self.is_nil
post (result = (seconds % Seconds_per_Minute))
is
-- This routine returns the number of seconds in the part of a day
-- represented by self.
return seconds % Seconds_per_Minute
end ;
total_seconds : CARD
pre ~self.is_nil and (((CARD::maxval / Seconds_per_Day) - 1) >= days)
post (result = ((days * Seconds_per_Day) + seconds))
is
-- This routine returns the whole number of seconds in self if this is
-- representable, otherwise raises an exception.
return days * Seconds_per_Day + seconds
end ;
milliseconds : CARD
pre ~self.is_nil
post (result = (millisecs % Millisecs_per_Second))
is
-- This routine returns the number of milliseconds in the part of
-- a second represented by self.
return millisecs % Millisecs_per_Second
end ;
total_milliseconds : CARD
pre ~self.is_nil and (((CARD::maxval / Millisecs_per_Day) - 1) >= days)
post (result = ((days * Millisecs_per_Day) + millisecs))
is
-- This routine returns the whole number of milliseconds in self
-- if this is representable (ie satisfies the pre-condition!).
return days * Millisecs_per_Day + millisecs
end ;
hash : CARD
pre ~self.is_nil
post true -- irrespective of result
is
-- This routine provides a hash value for self so that elapsed time
-- based lists, queues, etc may be created.
dbits : NUM_BITS := NUM_BITS::create(days) ;
mbits : NUM_BITS := NUM_BITS::create(millisecs) ;
return dbits.convolve(mbits).hash
end ;
end ; -- ELAPSED