File: IntervalList.rb

package info (click to toggle)
tj3 3.8.1-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 5,048 kB
  • sloc: ruby: 36,481; javascript: 1,113; sh: 19; makefile: 17
file content (100 lines) | stat: -rw-r--r-- 3,154 bytes parent folder | download | duplicates (4)
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
#!/usr/bin/env ruby -w
# encoding: UTF-8
#
# = IntervalList.rb -- The TaskJuggler III Project Management Software
#
# Copyright (c) 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014
#               by Chris Schlaeger <cs@taskjuggler.org>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of version 2 of the GNU General Public License as
# published by the Free Software Foundation.
#

require 'taskjuggler/Interval'

class TaskJuggler

  # A list of Intervals. The intervals in the list must not overlap and must
  # be in ascending order.
  class IntervalList < Array

    alias append <<

    def &(list)
      res = IntervalList.new
      si = li = 0
      while si < length && li < list.length do
        if self[si].start < list[li].start
          # The current Interval of self starts earlier than the current
          # Interval of list.
          if self[si].end <= list[li].start
            # self[si] does not overlap with list[li]. Ignore it.
            si += 1
          elsif self[si].end < list[li].end
            # self[si] does overlap with list[li] but list[li] goes further
            res << self[si].class.new(list[li].start, self[si].end)
            si += 1
          else
            # self[si] does overlap with list[li] but self[si] goes further
            res << self[si].class.new(list[li].start, list[li].end)
            li += 1
          end
        elsif list[li].start < self[si].start
          # The current Interval of list starts earlier than the current
          # Interval of self.
          if list[li].end <= self[si].start
            # list[li] does not overlap with self[si]. Ignore it.
            li += 1
          elsif list[li].end < self[si].end
            # list[li] does overlap with self[si] but self[si] goes further
            res << self[si].class.new(self[si].start, list[li].end)
            li += 1
          else
            # list[li] does overlap with self[si] but list[li] goes further
            res << self[si].class.new(self[si].start, self[si].end)
            si += 1
          end
        else
          # self[si].start and list[li].start are identical
          if self[si].end == list[li].end
            # self[si] and list[li] are identical. Add the Interval and
            # increase both pointers.
            res << self[si]
            li += 1
            si += 1
          elsif self[si].end < list[li].end
            # self[si] ends earlier.
            res << self[si]
            si += 1
          else
            # list[li] ends earlier.
            res << list[li]
            li += 1
          end
        end
      end

      res
    end

    # Append the Interval _iv_. If the start of _iv_ matches the end of the
    # list list item, _iv_ is merged with the last item.
    def <<(iv)
      if last
        if last.end > iv.start
          raise "Intervals may not overlap and must be added in " +
                "ascending order."
        elsif last.end == iv.start
          self[-1] = last.class.new(last.start, iv.end)
          return self
        end
      end

      append(iv)
    end

  end

end