Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -181,6 +181,35 @@ Attributes Reflect the Underlying Type
Shade : Color range Red .. Blue := Brown; -- run-time error
Hue : Rainbow := Rainbow'Succ (Blue); -- run-time error

---------------
Valid attribute
---------------

* :ada:`The_Type'Valid` is a :ada:`Boolean`
* :ada:`True` |rightarrow| the current representation for the given scalar is valid

.. code:: Ada

procedure Main is
subtype Small_T is Integer range 1 .. 3;
Big : aliased Integer := 0;
Small : Small_T with Address => Big'Address;
begin
for V in 0 .. 5 loop
Big := V;
Put_Line (Big'Image & " => " & Boolean'Image (Small'Valid));
end loop;
end Main;

.. code::

0 => FALSE
1 => TRUE
2 => TRUE
3 => TRUE
4 => FALSE
5 => FALSE

------------------------
Idiom: Extended Ranges
------------------------
Expand Down
1 change: 1 addition & 0 deletions courses/fundamentals_of_ada/140_access_types-in_depth.rst
Original file line number Diff line number Diff line change
Expand Up @@ -57,5 +57,6 @@ Access Types In Depth
.. include:: 140_access_types/08-memory_management.rst
.. include:: 140_access_types/09-memory_debugging.rst
.. include:: 140_access_types/10-memory_control.rst
.. include:: 140_access_types/11-type_safe_idioms.rst
.. include:: labs/140_access_types-in_depth.lab.rst
.. include:: 140_access_types/99-summary_with_pools.rst
Original file line number Diff line number Diff line change
Expand Up @@ -123,4 +123,3 @@ System.Storage_Pools Example (Partial)
end if;
end loop;
end Deallocate;

Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
===========================
Advanced Access Type Safety
===========================

-----------------------------------
Elaboration-Only Dynamic Allocation
-----------------------------------

* Common in critical contexts
* Rationale:

1. We (might) need dynamically allocated date

- e.g. loading configuration data of unknown size

2. Deallocations can cause leaks, corruption

- |rightarrow| **Disallow** them entirely

3. A dynamically allocated object will need deallocation

- |rightarrow| Unless it never goes out of **scope**

* |rightarrow| Allow only allocation onto globals

.. tip::

And restrict allocations to program elaboration

--------------------------
Prevent Heap Deallocations
--------------------------

* :ada:`Ada.Unchecked_Deallocation` cannot be used anymore
* No heap deallocation is possible

- The total number of allocations should be bounded
- e.g. elaboration-only allocations

.. code:: Ada

pragma Restrictions
(No_Dependence => Unchecked_Deallocation);

--------------------------------
Constant Access at Library Level
--------------------------------

.. code:: Ada

type Acc is access T;
procedure Free is new Ada.Unchecked_Deallocation (T, Acc);

A : constant Acc := new T;

* :ada:`A` is :ada:`constant`

* Cannot be deallocated

-------------------------------
Constant Access as Discriminant
-------------------------------

.. code:: Ada

type R (A : access T) is limited record

* :ada:`A` is :ada:`constant`

* Cannot be deallocated

* :ada:`R` is :ada:`limited`

* Cannot be copied

------------------------
Idiom: Access to Subtype
------------------------

.. tip::

:ada:`subtype` improves access-related code safety

* Subtype constraints still apply through the access type

.. code:: Ada

type Values_T is array (Positive range <>) of Integer;
subtype Two_Values_T is Values_T (1 .. 2);
type Two_Values_A is access all Two_Values_T;

function Get return Values_T is (1 => 10);

-- O : aliased Two_Values_T := Get;
-- Runtime FAIL: Constraint check
O : aliased Values_T := Get; -- Single value, bounds are 1 .. 1
-- P : Two_Values_A := O'Access;
-- Compile-time FAIL: Bounds must statically match
Original file line number Diff line number Diff line change
@@ -0,0 +1,151 @@
==========================================
Refcounting Wrapper for External C Objects
==========================================

-------
Context
-------

* From :url:`https://blog.adacore.com/the-road-to-a-thick-opengl-binding-for-ada-part-2`
* OpenGL API create various objects like textures or vertex buffers
* Creating them gives us an ID

- Can then be used to refer to the object

* Simple approach: Manually reclaiming them

- Could cause leaks

* Refcount approach: automatic ID management

- From an Ada wrapper
- Automatic reclaim once the last reference vanishes

-----------------
Wrapper Interface
-----------------

* :ada:`type GL_Object is abstract tagged private`

- Implements smart pointer logic

.. code:: Ada

procedure Initialize_Id (Object : in out GL_Object);

procedure Clear (Object : in out GL_Object);

function Initialized (Object : GL_Object) return Boolean;

* Derived by the **actual** object types

.. code:: Ada

procedure Internal_Create_Id
(Object : GL_Object; Id : out UInt) is abstract;

procedure Internal_Release_Id
(Object : GL_Object; Id : UInt) is abstract;

* Example usage

.. code:: Ada

type Shader (Kind : Shader_Type) is new GL_Object with null record;

------------------------------------
Wrapper Implementation: Private part
------------------------------------

* Object ID's holder: :ada:`GL_Object_Reference`

- All derived types have a handle to this

.. code:: Ada

type GL_Object_Reference;
type GL_Object_Reference_Access is access all GL_Object_Reference;

type GL_Object is abstract new Ada.Finalization.Controlled
with record
Reference : GL_Object_Reference_Access := null;
end record;

* Controlled type implementing **ref-counting**

.. code:: Ada

overriding procedure Adjust (Object : in out GL_Object);
-- Increases reference count.

overriding procedure Finalize (Object : in out GL_Object);
-- Decreases reference count.
-- Destroys underlying resource when it reaches zero.

------------------------------------
Wrapper Implementation: Full Picture
------------------------------------

.. image:: controlled_gl_object.svg

.. code:: Ada

type GL_Object_Reference is record
GL_Id : UInt;
Reference_Count : Natural;
Is_Owner : Boolean;
end record;

------------------------
:ada:`Adjust` Completion
------------------------

* :ada:`Adjust` is called every time a new reference is **created**
* Increments the ref-counter

.. code:: Ada

overriding procedure Adjust (Object : in out GL_Object) is
begin
if Object.Reference /= null then
Object.Reference.Reference_Count := @ + 1;
end if;
end Adjust;

--------------------------
:ada:`Finalize` Completion
--------------------------

.. note::

* :ada:`Finalize` should always be :dfn:`idempotent`

- Compiler might call it multiple times on the same object
- In particular when **exceptions** occur

.. code:: Ada

overriding procedure Finalize (Object : in out GL_Object) is
Ref : GL_Object_Reference_Access
renames Object.Reference;
begin


.. warning::

Do **not** decrement the reference counter for every call

* A given object will own **only one** reference

.. code:: Ada

-- Idempotence: the next call to Finalize will have no effect
Ref := null;

if Ref /= null then
Ref.Reference_Count := @ - 1;
if Ref.Reference_Count = 0 then
Free (Ref.all); -- Call to user-defined primitive
Unchecked_Free (Ref);
end if;
end if;
34 changes: 34 additions & 0 deletions courses/fundamentals_of_ada/240_tasking/05-task_types_in_depth.rst
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,40 @@ Protected Object Entries
...
end Object;

-------------------------------------
Discriminated Protected or Task types
-------------------------------------

* Discriminant can be an :ada:`access` or discrete type
* Resulting type is indefinite

- Unless mutable

* Example: counter shared between tasks

.. code:: Ada

protected type Counter_T is
procedure Increment;
end Counter_T

task type My_Task (Counter : not null access Counter_T) is [...]

task body My_Task is
begin
Counter.Increment;
[...]

----------------------------------------
Using discriminant for Real-Time aspects
----------------------------------------

.. code:: Ada

protected type Protected_With_Priority (Prio : System.Priority)
with Priority => Prio
is

------------------------------------------
Example: Protected Objects - Declaration
------------------------------------------
Expand Down
Loading