From: mfb@mbunix.mitre.org (Michael F Brenner)
Subject: Re: discriminant
Date: 1997/01/15
Date: 1997-01-15T00:00:00+00:00 [thread overview]
Message-ID: <5bjl7d$fe7@top.mitre.org> (raw)
In-Reply-To: 5bdvm5$p52@rc1.vub.ac.be
q: what is a discriminant. Why do some types carry discriminant.
q2: I have a project. I have to simulate a scheduler of tasks. What
would the body the main sccheduler be like. This is my first ada project
and I haven't a clue how to procceed.
A: A discriminant is an element of an object that that tells you which
of several choices of forms the object takes. It is a little like
God creating animals with a paramete called gender. The gender
then Discriminates between various genders and also Determines what
parts are glued onto the animal. Ada records can have discriminants
which determine what elements are glued onto the record in each
instance. In the following Free (copyleft) code, variable length
character strings are defined to have a discriminant which is the
length which then decides how many characters are included in the
record.
You could have downloaded this code from the Net, but if you had
access to Net search utilities, you would not have posted such
a basic question to a newsgroup. You could also have gotten a very
similar package to this from the PAL, a text book, or several
universities. You should get on the Net as soon as possible.
Meanwhile, the most effective way to learn how to do discriminants is
to do them, and the fastest way to do them is to see a working example
of one. The following example was written by me and has no bugs.
The sentence that is contains no bugs means the following: it is not
warranted or guaranteed, but it has been tested for each of the
preconditions it was designed for, and every one is welcome to come
up with additional preconditions, which would require it to be
enhanced or further tested, if you desire it to meet those preconditions.
Since it is subject to the Ada modification to the FSF GPPL, you are
welcome to make those modifications yourself, even if you are a
commercial company, but you may not do anything that would detract
from the Free status of the code.
The design is fully represented by the test program that follows
the package, and, like all software, any uses of the package not
tested by the test program, should first be done by upgrading the
test package to test the software for what you wish it would do.
packagy variable_string_control is
pragma elaborate_body (variable_string_control);
-- Variable strings are each allocated to any maximum length, and vary
-- from 0 to that maximum in length. Compiler enforces specifying that
-- maximum length when each variable is declared.
type variable_strings (size: natural) is private;
null_variable_string: constant variable_strings;
-- The concatenation of variable_strings is an unconstrained string.
function "&" (left: variable_strings;
right: variable_strings)
return string;
function "&" (left: string;
right: variable_strings)
return string;
function "&" (left: variable_strings;
right: string)
return string;
-- When strings agree up to the minimum of their lengths,
-- the shorter string is considered less than the longer string.
function "<" (left, right: variable_strings) return boolean;
function ">" (left, right: variable_strings) return boolean;
-- The assignment method is used to change variable_strings.
procedure assign(message: in out variable_strings; value: string);
procedure assign(message: in out variable_strings; value: variable_strings);
-- The concatenation method is used to append a string onto the end
-- of a variable_string.
procedure concat(onto: in out variable_strings; appendage: string);
-- The ELEMENT method returns a column of a variable_string just like
-- array references get columns from ordinary_strings.
function element (message: variable_strings;
col: natural) return character;
-- The IMAGE method returns the string image of a variable_string.
function image (message: variable_strings) return string;
-- The in_place_lower_case function converts
-- alphabetic character from upper to lower
-- case, ignoring all other characters.
-- It is done in place on a variable_string.
procedure in_place_lower_case (message: in out variable_strings);
-- The in_place_truncate method is a procedure instead of a function,
-- for efficiency.
procedure in_place_truncate (message: in out variable_strings;
ch: character := ' ');
-- The in_place_upper_case function converts
-- alphabetic character from lower to upper
-- case, ignoring all other characters.
procedure in_place_upper_case (message: in out variable_strings);
-- The LENGTH method returns the length of the variable_string.
function length (message: variable_strings) return natural;
-- The SAME method is the equality operator for variable_strings. To
-- be equal, the two strings must be of the same length, and agree
-- for each of their characters.
function same (left, right: variable_strings) return boolean;
function same (left: variable_strings; right: string) return boolean;
-- The set_element method sets a character in a single column
-- of a variable_string like array references do for character
-- strings.
procedure set_element (message: in out variable_strings;
col: natural;
value: character);
-- The set_length method truncates a string to a given length or else
-- extends its current length with blanks.
procedure set_length (message: in out variable_strings;
new_length: natural);
-- The SLICE method emulates array slices for variable_strings. The
-- SUBSTR method is similar, but based on length instead of final column.
-- The two-argument SUBSTR gets all characters on or after the given column.
-- All of these permit the START argument to take on a value equal to the
-- length of the variable_string plus 1, returning the null ordinary_string.
function slice (message: variable_strings;
start, finish: natural) return string;
function substr (message: variable_strings;
start, length: natural) return string;
function substr (message: variable_strings;
start: natural) return string;
-- The variable_string method converts an ordinary_string to a variable string.
function variable_string (size: natural;
message: string) return variable_strings;
private
type variable_strings (size: natural) is record
length: integer := -1; -- Causes arrays of strings to fully Allocate.
list: string (1..size);
end record;
null_variable_string: constant variable_strings (0) :=
(size => 0, length => 0, list => string'(""));
end variable_string_control;
package body variable_string_control is
type char_to_char is array (character) of character;
to_lower_case,
to_upper_case: char_to_char;
initialized: boolean := False;
not_init: exception;
out_of_range: exception;
too_long: exception;
procedure initialize_variable_strings is
cc: character;
begin
for c in char_to_char'range loop
to_lower_case(c) := c;
to_upper_case(c) := c;
end loop;
for c in character'('a')..'z' loop
cc := character'val (character'pos (c) - 32);
to_upper_case(c) := cc;
to_lower_case(cc) := c;
end loop;
end initialize_variable_strings;
procedure is_okay (message: variable_strings) is
begin
if message.length < 0 then
raise not_init;
end if;
end is_okay;
function "&" (left: variable_strings;
right: variable_strings)
return string is
hold: variable_strings (left.length + right.length);
begin
is_okay (left);
is_okay (right);
assign (hold, left);
concat (hold, right.list(1..right.length));
return hold.list(1..hold.length);
end "&";
function "&" (left: string; right: variable_strings) return string is
hold: variable_strings (left'length + right.length);
begin
is_okay (right);
assign (hold, left);
concat (hold, right.list(1..right.length));
return hold.list(1..hold.length);
end "&";
function "&" (left: variable_strings; right: string) return string is
hold: variable_strings (left.length + right'length);
begin
is_okay (left);
assign (hold, left);
concat (hold, right);
return hold.list(1..hold.length);
end "&";
function "<" (left, right: variable_strings) return boolean is
begin
is_okay(left);
is_okay(right);
if left.length < right.length then
return left.list(1..left.length) <= right.list(1..left.length);
elsif left.length = right.length then
return left.list(1..left.length) < right.list(1..left.length);
else -- left.length > right.length
return left.list(1..right.length) < right.list(1..right.length);
end if;
end "<";
function ">" (left, right: variable_strings) return boolean is
begin
is_okay(left);
is_okay(right);
if left.length < right.length then
return left.list(1..left.length) > right.list(1..left.length);
elsif left.length = right.length then
return left.list(1..left.length) > right.list(1..left.length);
else -- left.length > right.length
return left.list(1..right.length) >= right.list(1..right.length);
end if;
end ">";
procedure assign (message: in out variable_strings; value: string) is
begin
if value'length > message.size then
raise too_long;
else
message.length := value'length;
message.list (1..value'length) := value;
end if;
end assign;
procedure assign (message: in out variable_strings;
value: variable_strings) is
begin
is_okay (value);
if value.length > message.size then
raise too_long;
end if;
message.length:=value.length;
message.list (1..value.length) := value.list (1..value.length);
end assign;
procedure concat (onto: in out variable_strings; appendage: string) is
new_length: constant integer := onto.length + appendage'length;
begin
is_okay (onto);
if new_length > onto.size then
raise too_long;
else
onto.list(onto.length+1..new_length) := appendage;
onto.length := new_length;
end if;
end concat;
function element (message: variable_strings;
col: natural) return character is
begin
is_okay (message);
if col not in 1..message.length then
raise out_of_range;
end if;
return message.list (col);
end element;
function image (message: variable_strings) return string is
begin
is_okay (message);
if message.length=0 then return "";
else return message.list (1..message.length);
end if;
end image;
procedure in_place_lower_case (message: in out variable_strings) is
begin
is_okay (message);
if not initialized then
initialize_variable_strings;
end if;
for i in 1..message.length loop
message.list(i) := to_lower_case (message.list(i));
end loop;
end in_place_lower_case;
procedure in_place_truncate (message: in out variable_strings;
ch: character := ' ') is
begin
is_okay (message);
-- This is a good example of an Ada loop. Compare the following
-- loop to loops in other computer languages familiar to you, to
-- see how easy it is to check this loop for termination and for
-- effectiveness. Also compare how easy it is to see that the
-- loop is not "off by 1." This style was created in 1978 as part
-- of the DOD-I HOLWG goals, long before DOD-1 was named Ada as
-- part of the solution to ever increasing software maintenance
-- costs. It uses the idea that structured code must have a single
-- entrance at the top, but may (and often should) have multiple exits.
loop
exit when message.length = 0;
exit when message.list (message.length) /= ch;
message.length := message.length - 1;
end loop;
end in_place_truncate;
procedure in_place_upper_case (message: in out variable_strings) is
begin
is_okay (message);
if not initialized then
initialize_variable_strings;
end if;
for i in 1..message.length loop
message.list(i) := to_upper_case (message.list(i));
end loop;
end in_place_upper_case;
function length (message: variable_strings) return natural is
begin
is_okay (message);
return message.length;
end length;
function same (left, right: variable_strings) return boolean is
begin
is_okay (left);
is_okay(right);
return left.length=right.length and then
left.list(1..left.length) = right.list(1..left.length);
end same;
function same (left: variable_strings; right: string) return boolean is
begin
is_okay (left);
return left.length=right'length and then
left.list(1..left.length) = right;
end same;
procedure set_element (message: in out variable_strings;
col: natural;
value: character) is
begin
is_okay (message);
if col > message.size then
raise out_of_range;
elsif col = message.length+1 then
message.length := message.length + 1;
message.list (col) := value;
elsif col > message.length then
raise too_long;
else
message.list (col) := value;
end if;
end set_element;
procedure set_length (message: in out variable_strings;
new_length: natural) is
hold_length: integer := message.length;
begin
if hold_length > message.size then
raise too_long;
end if;
message.length := new_length;
if hold_length < 0 then
for i in 1..message.size loop
message.list (i) := ' ';
end loop;
end if;
if hold_length > 0 then
for i in hold_length+1 .. new_length loop
message.list (i) := ' ';
end loop;
end if;
end set_length;
function slice (message: variable_strings;
start, finish: natural) return string is
hold: variable_strings (finish+1-start);
begin
is_okay (message);
if start not in 1..message.length then
raise out_of_range;
elsif finish not in 0..message.length then
raise out_of_range;
end if;
if finish < start then
return "";
else
hold.length := finish+1-start;
hold.list (1..hold.length) := message.list (start..finish);
return hold.list (1..hold.length);
end if;
end slice;
function substr (message: variable_strings;
start, length: natural) return string is
begin
is_okay (message);
return slice (message, start, start+length-1);
end substr;
function substr (message: variable_strings;
start: natural)
return string is
begin
is_okay (message);
return slice (message, start, message.length);
end substr;
function variable_string (size: natural;
message: string) return variable_strings is
temp: variable_strings (size);
begin
if message'length > size then
raise too_long;
end if;
temp.length := message'length;
if message'length>0 then
temp.list (1..message'length) := message;
end if;
return temp;
end variable_string;
end variable_string_control;
-- Status is a package with tell and telln (like text_io.put and
-- text_io.put_line, only it puts it to both the console and the
-- error accumulation file. It also provides the method REPORT
-- which does a telln and then raises an exception.
with variable_string_control;
with status;
procedure tsstrvar is
use variable_string_control;
use status;
test_message: constant string := " Now is tHe time k1!";
procedure test_assign_1 is
x: variable_strings (4);
begin
assign(x,"");
if image(x)/="" then
report("Failed variable_strings.test_assign_1 bad null");
end if;
assign(X,"A");
if image(x)/="A" then
report("Failed var_str.test_assing_2");
end if;
status.telln("test_assign_1 passed");
end test_assign_1;
procedure test_case_1 is
message: variable_strings (5000) :=
variable_string (5000, "okay, I have - UPs & 96 Downs");
upped: variable_strings (200):=
variable_string (200, "OKAY, I HAVE - UPS & 96 DOWNS");
lowed: variable_strings (200) :=
variable_string (200, "okay, i have - ups & 96 downs");
work: variable_strings(60);
begin
assign(work,"abc");
in_place_upper_case(work);
if not same(work,"ABC") then
report("Failed variable_strings.test_case_1 abc [" & work & ']');
end if;
assign(work,message);
in_place_upper_case(work);
if not same (work, upped) then
report("Failed variable_strings.test_case_1 a [" & work & ']');
end if;
assign(work,message);
in_place_lower_case(work);
if not same (work, lowed) then
report("Failed variable_strings.test_case_1 b");
end if;
end test_case_1;
procedure test_concat_1 is
f,g,h,k: variable_strings (5);
begin
assign(f, "A");
assign(g, "B");
assign(h, "AB");
assign(k, f&g);
if not same (k,h) then
report("Failed variable_strings.test_concat_1 a ");
end if;
end test_concat_1;
procedure test_element_1 is
d: variable_strings(3) := variable_string (3, "");
begin
set_element (d, 1, 'a');
set_element (d, 2, 'b');
set_element (d, 3, 'c');
if element (d, 2) /= 'b' then
report("Failed variable_strings.test_element_1 a ");
end if;
end test_element_1;
procedure test_in_place_truncate_1 is
message: variable_strings(10) := variable_string(10, "abc ");
begin
in_place_truncate (message);
if not same (message, "abc") then
report("Failed variable_strings.test_in_place_truncate_1 a");
end if;
if length(message)/=3 then
report("Failed variable_strings.length b");
end if;
end test_in_place_truncate_1;
procedure test_lessthan_1 is
begin
if variable_string(25, "abc")<variable_string(25, "ab") then
report("Failed variable_strings test <1 got abc<ab");
elsif not (variable_string(25, "ab") <variable_string(25, "abc")) then
report("Failed variable_strings test <1 got ab>=abc");
elsif variable_string(25, "ac") <variable_string(25, "ab") then
report("Failed variable_strings test <1 got ac<ab");
elsif not (variable_string(25, "ab") <variable_string(25, "ac")) then
report("Failed variable_strings test <1 got ab>=ac");
elsif variable_string(25, "abc")<variable_string(25, "aa") then
report("Failed variable_strings test <1 got abc<aa");
elsif not (variable_string(25, "aa") <variable_string(25, "abc")) then
report("Failed variable_strings test <1 got aa>=abc");
elsif variable_string(25, "ac") <variable_string(25, "abc") then
report("Failed variable_strings test <1 got ac<abc");
elsif not (variable_string(25, "abc")<variable_string(25, "ac")) then
report("Failed variable_strings test <1 got abc>=ac");
elsif not (variable_string(25, "abc")>variable_string(25, "ab")) then
report("Failed variable_strings test >1 got abc<ab");
elsif not (variable_string(25, "abc")<variable_string(25, "ac")) then
report("Failed variable_strings test <1 got abc>=ac");
elsif (variable_string(25, "ab") >variable_string(25, "abc")) then
report("Failed variable_strings test <1 got ab>=abc");
elsif not (variable_string(25, "ac") >variable_string(25, "ab")) then
report("Failed variable_strings test <1 got ac<ab");
elsif (variable_string(25, "ab") >variable_string(25, "ac")) then
report("Failed variable_strings test <1 got ab>=ac");
elsif not (variable_string(25, "abc")>variable_string(25, "aa")) then
report("Failed variable_strings test <1 got abc<aa");
elsif (variable_string(25, "aa") >variable_string(25, "abc")) then
report("Failed variable_strings test <1 got aa>=abc");
elsif not (variable_string(25, "ac") >variable_string(25, "abc")) then
report("Failed variable_strings test <1 got ac<abc");
end if;
end test_lessthan_1;
procedure test_same_1 is
SS: constant string :="Now is the time for all good men to come to the";
a,b,c,d: variable_strings(100);
begin
assign(a,"Now");
assign(b,"Now");
assign(c,"Now ");
assign(d," Now");
if not same (a, b) then
report("Failed variable_strings.test_same_1 1");
elsif same (a,c) then
report("Failed variable_strings.test_same_1 2");
elsif same (a,d) then
report("Failed variable_strings.test_same_1 3");
end if;
assign(c,SS);
assign(d,SS);
if not same (c,d) then
report("Failed variable_strings.test_same_1 4");
end if;
end test_same_1;
procedure test_slice_1 is
x, y, z: variable_strings(10);
okay: constant string := "abcd";
begin
assign(x, "abc");
assign(y, okay(2..3));
assign(z, slice(x, 2, 3));
if not same (y,z) then
report("Failed variable_strings.test_slice_1 a");
end if;
assign(z, substr(x,2,2));
if not same (z,y) then
report("Failed variable_strings.test_slice_1 b");
end if;
if substr(z,1,0)/="" then
report("Failed variable_strings.test_slice_1 c");
end if;
end test_slice_1;
procedure test_variable_string is
temp: constant string:= "(abcdefg)";
temp_fixed: variable_strings(10);
begin
temp_fixed:= variable_string (10, temp (2..8));
if not same(temp_fixed, "abcdefg") then
report ("Failed variable_string_MANAGMENT.fixed string A");
end if;
end test_variable_string;
begin
test_variable_string;
test_assign_1;
test_case_1;
test_concat_1;
test_element_1;
test_in_place_truncate_1;
test_lessthan_1;
test_same_1;
test_slice_1;
status.telln("tsstrvar passed");
end tsstrvar;
next prev parent reply other threads:[~1997-01-15 0:00 UTC|newest]
Thread overview: 13+ messages / expand[flat|nested] mbox.gz Atom feed top
1997-01-13 0:00 discriminant AGBOH CHARLES
1997-01-13 0:00 ` discriminant KJPrice
1997-01-15 0:00 ` Michael F Brenner [this message]
-- strict thread matches above, loose matches on Subject: below --
1999-07-11 0:00 discriminant fluffy_doo
1999-07-12 0:00 ` discriminant Roger Racine
1999-07-12 0:00 ` discriminant fluffy_doo
1999-07-12 0:00 ` discriminant Roger Racine
1999-07-13 0:00 ` discriminant fluffy_puff
1999-07-13 0:00 ` discriminant Ted Dennison
1999-07-13 0:00 ` discriminant fluffy_dong
1999-07-15 0:00 ` discriminant Ted Dennison
1999-07-16 0:00 ` discriminant fluffy_puff
1999-07-13 0:00 ` discriminant Roger Racine
replies disabled
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox