-
Notifications
You must be signed in to change notification settings - Fork 3
/
multiplicity_interval.e
executable file
·299 lines (259 loc) · 7.13 KB
/
multiplicity_interval.e
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
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
note
component: "Eiffel Object Modelling Framework"
description: "[
Integer interval, used for representing cardinality, occurrences etc.
]"
keywords: "intervals"
author: "Thomas Beale"
support: "Ocean Informatics <[email protected]>"
copyright: "Copyright (c) 2000-2005 The openEHR Foundation <http://www.openEHR.org>"
license: "Apache 2.0 License <http://www.apache.org/licenses/LICENSE-2.0.html>"
class MULTIPLICITY_INTERVAL
inherit PROPER_INTERVAL [INTEGER]
rename
make_bounded as make_bounded_interval,
make_upper_unbounded as make_upper_unbounded_interval
redefine
as_string
end
create
default_create,
make_bounded,
make_upper_unbounded,
make_point,
make_from_interval,
make_open,
make_mandatory,
make_optional,
make_prohibited,
make_from_string
convert
make_from_interval ({INTERVAL[INTEGER]})
feature -- Definitions
multiplicity_range_marker: STRING = ".."
Multiplicity_unbounded_marker: CHARACTER = '*'
feature -- Initialisation
make_bounded (a_lower, an_upper: INTEGER)
-- make with both limits set
require
Valid_order: a_lower <= an_upper
do
make_bounded_interval (a_lower, an_upper, True, True)
ensure
Lower_set: lower = a_lower
Upper_set: upper = an_upper
Bounded_upper: not upper_unbounded
end
make_upper_unbounded (a_lower: INTEGER)
-- make an interval from `a_lower' to +infinity
do
make_upper_unbounded_interval (a_lower, True)
ensure
Lower_set: lower = a_lower
Upper_unbounded: upper_unbounded
end
make_from_interval (an_int: INTERVAL[INTEGER])
-- make from a standard INTERVAL[INTEGER]
do
lower := an_int.lower
upper := an_int.upper
upper_included := an_int.upper_included
upper_unbounded := an_int.upper_unbounded
lower_included := True
end
make_open
-- make an open interval from 0 to +infinity
do
make_upper_unbounded_interval (0, True)
ensure
Lower_set: lower = 0
Upper_unbounded: upper_unbounded
open: is_open
end
make_optional
-- make an interval representing optionality, i.e. 0..1
do
make_bounded_interval (0, 1, True, True)
ensure
Lower_set: lower = 0
Upper_set: upper = 1
Upper_bounded: not upper_unbounded
optional: is_optional
end
make_mandatory
-- make an interval representing mandatoriness, i.e. 1..1
do
make_point (1)
ensure
Lower_set: lower = 1
Upper_set: upper = 1
Upper_bounded: not upper_unbounded
mandatory: is_mandatory
end
make_prohibited
-- make an interval representing prohibition, i.e. 0..0
do
make_point(0)
ensure
Lower_set: lower = 0
Upper_set: upper = 0
Upper_bounded: not upper_unbounded
prohibited: is_prohibited
end
make_from_string (a_str: STRING)
-- make from a string of the form "n..m" or just "n", where n and m are integers, or m may be '*'
require
valid_multiplicity_string: valid_multiplicity_string (a_str)
local
a_lower, an_upper, delim_pos: INTEGER
a_mult_str: STRING
do
a_mult_str := a_str.twin
-- remove any spaces
a_mult_str.prune_all (' ')
-- make the interval
delim_pos := a_mult_str.substring_index (multiplicity_range_marker, 1)
-- n..m case
if delim_pos > 0 then
a_lower := a_mult_str.substring (1, delim_pos-1).to_integer
if a_mult_str.item (a_mult_str.count) = Multiplicity_unbounded_marker then
make_upper_unbounded (a_lower)
else
an_upper := a_mult_str.substring (a_mult_str.substring_index (multiplicity_range_marker, 1) + multiplicity_range_marker.count, a_mult_str.count).to_integer
make_bounded (a_lower, an_upper)
end
-- * case
elseif a_mult_str.item (1) = Multiplicity_unbounded_marker then
make_upper_unbounded (0)
-- m (single integer) case
else
a_lower := a_mult_str.to_integer
make_bounded (a_lower, a_lower)
end
end
feature -- Status report
is_open: BOOLEAN
-- True if this interval imposes no constraints, i.e. is set to 0..*
do
Result := lower = 0 and upper_unbounded
end
is_multiple: BOOLEAN
-- True if this interval has an upper bound greater than 1
do
Result := upper_unbounded or upper > 1
end
is_optional: BOOLEAN
-- True if this interval expresses optionality, i.e. 0..1
do
Result := lower = 0 and upper = 1
end
is_mandatory: BOOLEAN
-- True if this interval expresses mandation, i.e. 1..1
do
Result := lower = 1 and upper = 1
end
is_prohibited: BOOLEAN
-- True if this interval is set to 0..0
do
Result := lower = 0 and upper = 0 and not lower_unbounded and not upper_unbounded
end
valid_multiplicity_string (a_str: STRING): BOOLEAN
-- check if string is in form "n..m; ordered; unique" where each subsection after a ';' is optional
do
-- for the moment, just assume
Result := True
end
feature -- Modification
set_lower (a_lower: INTEGER)
-- reset lower to `_lower'
require
Lower_valid: a_lower >= 0
do
lower := a_lower
lower_unbounded := False
end
set_upper (an_upper: INTEGER)
-- reset upper to `upper'
require
Upper_valid: an_upper >= 0
do
upper := an_upper
upper_unbounded := False
end
feature -- Operations
union (other: like Current)
-- generate the outer interval of Current and other
do
if upper_unbounded or other.upper_unbounded then
upper_unbounded := True
else
upper := upper.max(other.upper)
end
lower := lower.min(other.lower)
end
add (other: like Current)
-- generate the interval resulting from sum(lower, other.lower)..sum(upper, other.upper)
do
if upper_unbounded or other.upper_unbounded then
upper_unbounded := True
else
upper := upper + other.upper
end
lower := lower + other.lower
end
feature -- Output
as_string: STRING
-- output a UML-style stting of the form 0..1, 0..*, 1..3 etc
do
create Result.make(0)
if upper_unbounded then
Result.append (primitive_value_out (lower) + multiplicity_range_marker + Multiplicity_unbounded_marker.out)
elseif not is_point then
Result.append (primitive_value_out (lower) + multiplicity_range_marker + primitive_value_out (upper))
else
Result.append (primitive_value_out (lower))
end
end
as_regex_quantifier: STRING
-- output a simplified PERL regex style quantifier of the form:
-- 1..1 -> (nothing)
-- 0..1 -> ?
-- 0..* -> *
-- 1..* -> +
-- n..m -> +
do
create Result.make(0)
if is_mandatory then
-- nothing needed
elseif is_optional then
Result.append_character ('?')
elseif lower = 0 then
Result.append_character ('*')
else
Result.append_character ('+')
end
end
as_quantifier_text: STRING
-- output a simplified PERL regex style quantifier of the form:
-- 1..1 -> single_mandatory
-- 0..1 -> single_optional
-- 0..* -> multiple_optional
-- 1..* -> multiple_mandatory
-- n..m -> multiple_mandatory
do
create Result.make(0)
if is_mandatory then
Result.append ("single_mandatory")
elseif is_optional then
Result.append ("single_optional")
elseif lower = 0 then
Result.append ("multiple_optional")
else
Result.append ("multiple_mandatory")
end
end
invariant
Lower_valid: lower >= 0
Lower_bounded: not lower_unbounded
Lower_included: lower_included
end