File: interval.rb

package info (click to toggle)
ruby-hitimes 3.1.0-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 372 kB
  • sloc: ruby: 1,385; makefile: 7
file content (171 lines) | stat: -rw-r--r-- 4,885 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
# frozen_string_literal: true

# Copyright (c) 2008 Jeremy Hinegardner
# All rights reserved.  See LICENSE and/or COPYING for details.
#
module Hitimes
  # This is the lowest level timing mechanism available.  It allows for easy
  # measuring based upon a block:
  #
  #   duration = Interval.measure { ... }
  #
  # Or measuring something specifically
  #
  #   interval = Interval.new
  #   interval.start
  #   duration = interval.stop
  #
  # Allocating and starting an interval can be done in one method call with
  #
  #   interval = Interval.now
  #
  # Interval is useful when you only need to track a single interval of time, or
  # if you do not want to track statistics about an operation.
  class Interval
    # Public: The integer representing the start instant of the Interval.  This
    # valuea is not useful on its own.  It is a platform dependent value.
    attr_reader :start_instant

    # Public: The integer representing the stop instant of the Interval.  This
    # value is not useful on its own.  It is a platform dependent value.
    attr_reader :stop_instant

    def initialize(start = nil, stop = nil)
      @start_instant = start
      @stop_instant  = stop
      @duration      = -Float::INFINITY
    end

    # call-seq:
    #    Interval.now -> Interval
    #
    # Create an interval that has already started
    #
    def self.now
      Interval.new(Hitimes.raw_instant)
    end

    # call-seq:
    #    Interval.measure {  }  -> Float
    #
    # Times the execution of the block returning the number of seconds it took
    def self.measure
      raise Error, "No block given to Interval.measure" unless block_given?

      interval = Interval.now
      yield
      interval.stop

      interval.duration
    end

    # call-seq:
    #    interval.split -> Interval
    #
    # Immediately stop the current interval and start a new interval that has a
    # start_instant equivalent to the stop_interval of self.
    def split
      @stop_instant = ::Hitimes.raw_instant
      Interval.new(@stop_instant)
    end

    # call-seq:
    #    interval.start -> boolean
    #
    # mark the start of the interval.  Calling start on an already started
    # interval has no effect.  An interval can only be started once.  If the
    # interval is truely started +true+ is returned otherwise +false+.
    def start
      return false if started?

      @start_instant = ::Hitimes.raw_instant
      true
    end

    # call-seq:
    #    interval.stop -> bool or Float
    #
    # mark the stop of the interval.  Calling stop on an already stopped interval
    # has no effect.  An interval can only be stopped once.  If the interval is
    # truely stopped then the duration is returned, otherwise +false+.
    def stop
      raise Error, "Attempt to stop an interval that has not started" unless started?
      return false if stopped?

      @stop_instant = ::Hitimes.raw_instant

      duration
    end

    # call-seq:
    #     interval.duration_so_far -> Float or false
    #
    # return how the duration so far.  This will return the duration from the time
    # the Interval was started if the interval is running, otherwise it will return
    # false.
    def duration_so_far
      return false unless running?

      raw = Hitimes.raw_instant
      calculate_duration(@start_instant, raw)
    end

    # call-seq:
    #    interval.started? -> boolean
    #
    # returns whether or not the interval has been started
    def started?
      !!@start_instant
    end

    # call-seq:
    #    interval.stopped? -> boolean
    #
    # returns whether or not the interval has been stopped
    def stopped?
      !!@stop_instant
    end

    # call-seq:
    #    interval.running? -> boolean
    #
    # returns whether or not the interval is running or not.  This means that it
    # has started, but not stopped.
    #
    def running?
      started? && !stopped?
    end

    # call-seq:
    #    interval.duration -> Float
    #    interval.to_f -> Float
    #    interval.to_seconds -> Float
    #    interval.length -> Float
    #
    # Returns the Float value of the interval, the value is in seconds.  If the
    # interval has not had stop called yet, it will report the number of seconds
    # in the interval up to the current point in time.
    #
    # Raises Error if duration is called on an interval that has not started yet.
    #
    def duration
      raise Error, "Attempt to report a duration on an interval that has not started" unless started?

      return duration_so_far unless stopped?

      @duration = calculate_duration(@start_instant, @stop_instant) if @duration.negative?

      @duration
    end

    alias to_f       duration
    alias to_seconds duration
    alias length     duration

    private

    def calculate_duration(start, stop)
      (stop - start) / ::Hitimes::NANOSECONDS_PER_SECOND
    end
  end
end