Getters and setters Ada - object

I just started programming on Ada and I was wondering how to code getters and setters to work with classes attributes.
In fact I am interested in obtaining getters and setters of attributes deadline, period and computingTime of the following package:
with Ada.Text_IO; use Ada.Text_IO;
with Ada.Real_Time; use Ada.Real_Time;
package body pkg_tasks is
task body task_a is
deadline : Time_Span := To_Time_Span(25.0);
period : Time_Span := To_Time_Span(25.0);
computingTime : Time_Span := To_Time_Span(10.0);
startingTime : Time;
begin
entry start do
startingTime := Clock;
while (Clock - startingTime) < computingTime loop
end loop;
New_line;
Put_Line("End of task A");
end start;
end task_a;
end pkg_tasks;

In the case of a task, it's quite easy... You can't for the same reason that we answered in your last question, tasks can only have entries which act as a way to synchronize tasks (read part on entries and the followings).
But in fact, you could perform a kind of getters as entries and using selective wait depending on when you want to query your attributes.
Now, about setting attributes on your task, using parameters on your start entry seems to me as the best way to do.
As a note, you are writing about classes attributes but you are currently using no classes at all. Tasks are a first-citizen type in Ada and is not implemented through a class type as it's done in Java. Using object oriented programming is a different beast here.

As said above, generally tasks are not the normal way to do it. Back in Ada83, there were no protected types, so if you needed something like that then you emulated it with a task. That aside, here are some examples using tasks, protected types and classes (or as Ada calls them, Tagged types):
with Ada.Text_IO; use Ada.Text_IO;
with Ada.Real_Time; use Ada.Real_Time;
procedure jdoodle is
------------------------------------------------------
-- Task Example
------------------------------------------------------
task Task_Example is
entry Get(Time : out Time_Span);
entry Set(Time : in Time_Span);
end Task_Example;
task body Task_Example is
Value : Time_Span := To_Time_Span(0.0);
begin
loop
select
accept Get(Time : out Time_Span) do
Time := Value;
end Get;
or
accept Set(Time : in Time_Span) do
Value := Time;
end Set;
or
terminate;
end select;
end loop;
end Task_Example;
------------------------------------------------------
-- Protected type example
------------------------------------------------------
protected type Protected_Example is
procedure Put(Time : Time_Span); -- or use entry
function Get return Time_Span; -- or use procedure or entry
private
Value : Time_Span := To_Time_Span(0.0);
end Protected_Example;
protected body Protected_Example is
procedure Put(Time : Time_Span) is
begin
Value := Time;
end Put;
function Get return Time_Span is
begin
return Value;
end Get;
end Protected_Example;
------------------------------------------------------
-- Class Example
------------------------------------------------------
package Classes is
type Class_Example is tagged limited private;
procedure Put(Self : in out Class_Example; Time : Time_Span);
function Get(Self : in Class_Example) return Time_Span; -- or use procedure
private
type Class_Example is tagged limited record
Value : Time_Span := To_Time_Span(0.0);
end record;
end Classes;
package body Classes is
procedure Put(Self : in out Class_Example; Time : Time_Span) is
begin
Self.Value := Time;
end Put;
function Get(Self : in Class_Example) return Time_Span is
begin
return Self.Value;
end Get;
end Classes;
begin
Put_Line("Starting");
end jdoodle;
Keep in mind the tagged type example is also applicable to regular records and other private types.

Related

Automatically constrain string size using initialization in VHDL

I'm working with VHDL, and I'm wondering if there is any way to constrain the string size when declaring it, using initialization. For example, we declare a string as follow:
variable sequence : string(1 to 20) := "AGTAACCAATTCGCATTCGC";
I would like to know if there is any way to do something like:
variable sequence : string := "AGTAACCAATTCGCATTCGC";
Of course, second line isn't valid, because interpreter says:
[VRFC 10-1547] variable cannot be unconstrained
Constants don't have to be constrained, so you could do this:
constant Csequence : string := "AGTAACCAATTCGCATTCGC";
variable Vsequence : string(Csequence'range) := Csequence;
https://www.edaplayground.com/x/r3wK
entity E is
end entity E;
architecture A of E is
begin
process
constant Csequence : string := "AGTAACCAATTCGCATTCGC";
variable Vsequence : string(Csequence'range) := Csequence;
begin
wait;
end process;
end architecture A;

Creating files that contain REAL values which can be read by VHDL / modelsim

What I want to do
I want to have a script in python or matlab that creates files which can be read by VHDL / modelsim as a file of real values.
What I've done so far
I've written a small VHDL entity that creates a file of real values so I can find out what format it uses. It looks like this:
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use ieee.math_real.all;
library std;
use std.textio.all;
entity read_arr is
end entity read_arr;
architecture reader of read_arr is
type t_real_arr is array (0 to 1023) of real;
signal real_arr : t_real_arr := (others => 0.0);
signal start : std_logic := '0';
signal filled : std_logic := '0';
type t_real_file is file of t_real_arr;
file real_file : t_real_file;
begin -- architecture reader
start <= '0', '1' after 10 ns;
fill_arr : process (start) is
variable real_fill : real := -10.0;
begin -- process fill_arr
if rising_edge(start) then
for i in real_arr'range loop
real_arr(i) <= real_fill;
real_fill := real_fill + 0.25;
end loop; -- i
filled <= '1';
end if;
end process fill_arr;
wr_arr : process (filled) is
variable filename : string (1 to 10) := "realvc.dat";
variable status : file_open_status := status_error;
begin -- process fill_arr
if rising_edge(filled) then
file_open(status, real_file, filename, write_mode);
write(real_file, real_arr);
file_close(real_file);
end if;
end process wr_arr;
end architecture reader;
What it does is it fills an array of 1024 elements with real values starting from -10.0 and incrementing in steps of 0.25. It then writes this data into the binary file realvc.dat. The content of the file (viewed with a hex editor) can be seen in this gist.
It's easy to see that modelsim uses 64 bit to store each real value, but I haven't figured out what kind of format that is. It isn't ieee double-precision.
The Question
Does anyone know what kind of data format that is and how I can recreate it in a script language such as python or matlab?
The standard VHDL package std.textio makes it possible to read/write real in
literal format to a text file, whereby scripting languages like Python can
easily access it. The binary format is thereby avoided, which improves portability.
An example similar to the question code, doing first write then read of an array of real with std.textio is:
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
library std;
use std.textio.all;
entity test_arr is
end entity test_arr;
architecture test of test_arr is
begin
process is
type real_arr_t is array (0 to 1023) of real;
variable real_arr_v : real_arr_t := (others => 0.0);
variable real_fill_v : real := -10.0;
procedure real_arr_write(variable real_arr : in real_arr_t) is
file txt_file : text;
variable real_v : real;
variable line_v : line;
begin
file_open(txt_file, "real.txt", write_mode);
for idx in real_arr'range loop
write(line_v, real_arr(idx));
writeline(txt_file, line_v);
end loop;
file_close(txt_file);
end procedure;
procedure real_arr_read(variable real_arr : out real_arr_t) is
file txt_file : text;
variable line_v : line;
variable good_v : boolean;
begin
file_open(txt_file, "real.txt", read_mode);
for idx in real_arr'range loop
readline(txt_file, line_v);
read(line_v, real_arr(idx), good_v);
assert good_v report "Failed convert to real of: " & line_v.all severity FAILURE;
end loop;
file_close(txt_file);
end procedure;
begin
-- Make and write real array to text file
for i in real_arr_v'range loop
real_arr_v(i) := real_fill_v;
real_fill_v := real_fill_v + 0.25;
end loop;
real_arr_write(real_arr_v);
-- Read real array from text file
real_arr_read(real_arr_v);
-- End
wait;
end process;
end architecture test;
The real values in the "real.txt" file are then:
-1.000000e+001
-9.750000e+000
-9.500000e+000
-9.250000e+000
Python 3 can create strings like this with '{:e}'.format(x), and convert from this format using float(s).

How to update GUI controls with versions of Delphi (Pre Delphi 2010) without Synchronize

I have some apps built with Delphi 2010 and XE4 that use Synchronize in a thread. I think Synchronize was introduced to Delphi in Delphi 2010. My thread operates very well so that is not the problem.
My question is: Is there any way to "Synchronize" with versions of Delphi prior to Delphi 2010 or to ask it in a different way, how do you update GUI controls in these earlier versions of Delphi without Synchronize?
The code shown below is a subset of the actual code to reduce the length of this post.
type
{ A TThread descendent for loading Images from a folder }
TFolderLoadingThread = class(TThread)
private
{ Private declarations }
AspectRatio: double;
protected
{ Protected declarations }
procedure Execute; override;
public
{ Public declarations }
constructor Create(CreateSuspended: Boolean);
end;
procedure TFolderLoadingThread.Execute;
{ Load images ImageEnView in the thread. }
begin
inherited;
{ Free the thread onTerminate }
FreeOnTerminate := True;
if not Terminated then
begin
{ Set the Progressbar.Max Value }
**Synchronize**(
procedure
begin
if iFileCount > 0 then
Form1.Gauge1.MaxValue := iFileCount - 1;
end);
end;
Synchronize is very old routine, but there are no anonymous procedures in Delphi versions prior to D2009. Synchronize was intended to call a method without parameters in these versions.
procedure TFolderLoadingThread.UpdateProgress;
begin
if iFileCount > 0 then
Form1.Gauge1.MaxValue := iFileCount - 1;
end;
in Execute:
do thead work...
Synchronize(UpdateProgress);
P.S. You have not to call Terminate in the Execute body
Synchronize was there almost forever. I used it in Delphi 5. But that already was told above.
You can also use Windows API (namely PostMessage) to do it, if you can afford the change happening "soon after", in other words if your thread does not have to stop and wait until GUI updated. For example if there is a long calculations, and you want to have a gauge "1234 of 5678 complete" - then there is little point to stop the calculation processes. Let the counter would be inaccurate, plus-minus a dozen. Why care ?
Now, how to implement it... For simplistic cases you can use direct Windows access.
For example, if we have a windowed text label - the one inherited from TWinControl
http://docwiki.embarcadero.com/Libraries/XE4/en/Vcl.StdCtrls.TStaticText
Then we can bypass VCL and all its goodies and change the caption with a standard Windows API
http://msdn.microsoft.com/en-us/library/windows/desktop/ms632644.aspx
http://msdn.microsoft.com/en-us/library/windows/desktop/ms644944.aspx
You would also have to make a proper calculation of total numbers and messages to display. Yet this is not related to GUI and VCL. But hopefully you know about synchronization primitives, for example
http://www.freepascal.org/docs-html/fcl/syncobjs/tcriticalsection.html
AS. Yes, there is AtomicIncrement for you, i just show the framework in details.
There below i assume TMyThread to be one of the pool of workers, processing some common set of work items. It might be the only worker thread or one of many, it just does not know it, nor care about.
TThreadsCoordinator = class
...
private
CounterCS; TCriticalSection;
public
property CompleteItemsCount: integer
read FCompleteItemsCount;
function IncCompleteItemsCount(const Delta: integer): integer;
end;
...
function TThreadsCoordinator.IncCompleteItemsCount;
begin
CounterCS.Acquire;
try
Inc(FCompleteItemsCount, Delta);
finally
CounterCS.Release;
end;
Result := FCompleteItemsCount;
end;
var GlobalCaptionBuffer: array[0..127] of char;
// should be filled through with #0 before threads are started
procedure TMyThread.WorkItemComplete;
var s: string;
begin
...
s := Format('Done: %d of %d',
[ Self.Coordinator.IncCompleteItemsCount( +1 ),
Self.Coordinator.TotalItemsCount ] );
StrCopy( #GlobalCaptionBuffer[0], PChar(s));
if MyProgressForm1.Visible then // avoid ReCreateWnd inside .ShowModal
PostMessage( MyProgressForm1.StaticText1.Handle,
WM_SETTEXT, 0, Integer(#GlobalCaptionBuffer[0]));
...
end;
This implementation - while being straight-forward - may suffer from synchronization issues.
* you need some global buffer for the text, that would not be deleted before WM_SETTEXT would actually be received and executed.
* you need to think what would happen, when the text in that buffer would be in process of updating when the label would read it simultaneously
* David Heffernan below claims that in some conditions the Windows controls might be in process of destruction and re-creation (read: RecreateWnd method), thus unexpected consequences might happen. Personally - as long as that ProgressForm would only be controlled by WinGDI meeans avoiding all VCL goodies (such as changing combobox styles on the go, which does trigger RecreateWnd, but which is not possible by native WinGDI API) - i cannot see why that can happen. But David claims it can. Choose for yourself, if that suits you.
However for more complex tasks (or for using window-less text labels) you can resort to "message methods" - the foundation of VCL.
http://www.freepascal.org/docs-html/ref/refsu31.html
http://docwiki.embarcadero.com/RADStudio/XE4/en/Methods
This implementation is more flexible (separating data generation and data visualiation) and arguable more reliable (see RecreateWnd remarks in comments). But it need more of a boilerplate code.
const WM_IncCounter = WM_USER + 10;
type TMyProgressForm = class(TForm)
private
FCompleteItemsCount: integer;
procedure IncCounter(var Msg: TMessage ); message WM_IncCounter;
...
end;
procedure TMyProgressForm.IncCounter(var Msg: TMessage );
var s: string;
begin
Inc(FCompleteItemsCount, Msg.WParam);
s := Format('Done: %d of %d',
[ FCompleteItemsCount, TotalItemsCount ] );
Label1.Caption := s;
ProgressBar1.Position := FCompleteItemsCount;
end;
procedure TMyThread.WorkItemComplete;
begin
Inc(Self.UncommittedTicks);
if MyProgressForm1.Visible then // avoid ReCreateWnd inside .ShowModal
begin
PostMessage( MyProgressForm1.Handle, WM_IncCounter, Self.UncommittedTicks, 0);
Self.UncommittedTicks := 0;
end;
end;

Ada tasks and termination

I've been reading a little bit about tasks in ada at http://en.wikibooks.org/wiki/Ada_Programming/Tasking and thought that i'll write a little thing with tasks myself. Since i've read a small course on Pintos recently i thought i'd implement a little readers-writers algorithm. This is my attempt at it:
procedure Test_Queue is
type Int_Array is array(1..10) of Integer;
task type Queue is
entry Quit;
entry Pop(Elem : out Integer);
entry Push(Elem : in Integer);
end Queue;
task body Queue is
Elems_In_Queue : Integer := 0;
Q : Int_Array;
begin
loop
select
accept Push(Elem : in Integer) do
Put_Line("Push");
Elems_In_Queue := Elems_In_Queue + 1;
Q(Elems_In_Queue) := Elem;
end Push;
or
when Elems_In_Queue > 0 =>
accept Pop(Elem : out Integer) do
Put_Line("Pop");
Elem := Q(Elems_In_Queue);
Elems_In_Queue := Elems_In_Queue - 1;
end Pop;
else
delay 1.0;
Put_Line("Waited");
accept Quit;
exit;
end select;
end loop;
Put_Line("Got out of the loop");
end Queue;
Q : Queue;
X : Integer;
begin
Put_Line("Started");
Q.Push(10);
Put_Line("Pushed");
Q.Push(11);
Put_Line("Pushed");
Q.Pop(X);
Put_Line("Integer:" & Integer'Image(X));
Q.Quit;
Put_Line("Done");
end Test_Queue;
Might be worth mentioning that the behaviour i would like to see is that when no operations (push/pop) have been made to the queue/stack for 1 second i would like the task to terminate/exit the infinite loop.
But this just outputs "Started" and then goes to my delay 1.0 and outputs "Wait". This is not exactly what I expected since i have accept for at least push and that is the first thing i call. Where have i been thinking wrong and why doesn't this work? Also, are there any more sources with some examples as for how to do tasking in Ada? I managed to implement this by creating a Semaphore and Lock in 2 different tasks but that seemed to be a bad solution and not very adaesque.
Having improved the diagnostics, it is clear that on startup, neither of the Select alternatives was immediately available so the Queue task was going straight to the Else part, and after 1 second delay, waiting to accept Quit.
Meanwhile the main task was blocking on its first (unconditional, untimed!) Push entry call, so that it could never issue the Quit entry call. Result : Deadlock.
The solution (described in Burns & Welling on p.108) is simply to change ELSE to OR so that the third (Delay) option is still a Select alternative. Then in each iteration, the earliest of (Push, Pop or Delay) will be accepted.

BeginThread Structure - Delphi

I've got a almost completed app now and the next feature I want to implement is threading. I chose to go with BeginThread(), although am aware of TThread in delphi. The problem I'm coming across is the structure of BeginThread() call. Normally the line in the program that would call the function I want to be threaded is
CompareFiles(form1.Edit3.Text,Form1.Edit4.Text,Form1.StringGrid2,op);
op is a integer.
The line I've switched it out for to create a thread from it is
BeginThread(nil,0,CompareFiles,Addr('form1.Edit3.Text,Form1.Edit4.Text,Form1.StringGrid2,op'),0,x);
From the little amount of infromation I can find on how to actually use BeginThread() this should be a fine call, however on compling all I get is complier errors regarding the structure of my BeginThread() statement paramenters.
EDIT FOR INFORMATION.
The current procedure that calls CompareFiles is
procedure TForm1.Panel29Click(Sender: TObject);
var
op,x : integer;
begin
if (Form1.Edit3.Text <> '') AND (Form1.Edit4.Text <> '') then
begin
op := 3;
if RadioButton7.Checked = True then op := 0;
if RadioButton3.Checked = True then op := 1;
if RadioButton4.Checked = True then op := 2;
if RadioButton5.Checked = True then op := 3;
if RadioButton6.Checked = True then op := 4;
CompareFiles(form1.Edit3.Text,Form1.Edit4.Text,Form1.StringGrid2,op);
end;
end;
If I was to use TThread as suggested by a couple of people, and as displayed by Rob below, I'm confused at how a) I would pass op,Edit3/4.Text and StringGrid2 to the CompareFiles. Guessing from the example of TThread I've seen I thought I would replace the code above with TCompareFilesThread.Executeand the put the current code from Panel29Click into TCompareFilesThread.Create and then add
FEdit3Text := Edit3Text;
FEdit4Text := Edit4Text;
FGrid := Grid;
to this
FEdit3Text := Form1.Edit3.Text;
FEdit4Text := Form1.Edit4.Text;
FGrid := Form1.StringGrid2;
But I've got this nagging feeling that is totally off the mark.
That's not at all the way to use BeginThread. That function expects a pointer to a function that takes one parameter, but the function you're trying to call wants four. The one parameter you're giving to BeginThread for it to forward to the thread procedure is a string, but you evidently hope that some sort of magic will turn that string of characters into the values that those variables contain.
That's not how Delphi works, and even for the languages that can do something like that, it's generally discouraged to actually do it.
To pass multiple parameters to BeginThread, define a record with all the values you'll need, and also define a record pointer:
type
PCompareFilesParams = ^TCompareFilesParams;
TCompareFilesParams = record
Edit3Text,
Edit4Text: string;
Grid: TStringGrid;
Op: Integer;
end;
Change CompareFiles to accept a pointer to that record:
function CompareFiles(Params: PCompareFilesParams): Integer;
To start the thread, you'll need to allocate an instance of that record and populate its fields:
var
Params: PCompareFilesParams;
begin
New(Params);
Params.Edit3Text := Edit3.Text;
Params.Edit4Text := Edit4.Text;
Params.Grid := StringGrid2;
Params.Op := op;
BeginThread(nil, 0, #CompareFiles, Params, 0, x);
Implement CompareFiles like this so that the record will get freed before the thread terminates:
function CompareFiles(Params: PCompareFilesParams): Integer;
begin
try
// <Normal implementation goes here.>
finally
Dispose(Params);
end;
end;
You can make it all a lot easier if you just use TThread, though. You can make your descendant class have as many parameters as you want in its constructor, so you don't have to mess around with dynamically allocating and freeing a special record.
type
TCompareFilesThread = class(TThread)
private
FEdit3Text,
FEdit4Text: string;
FGrid: TStringGrid;
FOp: Integer;
procedure Execute; override;
public
constructor Create(const Edit3Text, Edit4Text: string; Grid: TStringGrid; Op: Integer);
property ReturnValue;
end;
constructor TCompareFilesThread.Create;
begin
inherited Create(False);
FEdit3Text := Edit3Text;
FEdit4Text := Edit4Text;
FGrid := Grid;
FOp := Op;
end;
procedure TCompareFilesThread.Execute;
begin
ReturnValue := CompareFiles(FEdit3Text, FEdit4Text, FGrid, FOp);
end;
Instead of calling BeginThread, you just instantiate the class and let it run:
var
ThreadRef: TThread;
ThreadRef := TCompareFilesThread.Create(Edit3.Text, Edit4.Text, StringGrid2, Op);
There's more to using threads, such as knowing when the thread has finished running, but I think you have enough to get started. One last thing to beware of, though, is that TStringGrid is a VCL control. You mustn't do anything with it from this new thread you create (regardless of how you end up creating it). Eveything you do with the grid control need to be done from the main thread. Use TThread.Synchronize and TThread.Queue to shift any VCL operations onto the main thread. Your file-comparing thread will wait for the synchronized operation to complete, but it will keep running without waiting for a queued operation to complete.

Resources