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