Skip to content

Commit

Permalink
Merge pull request #971 from gusthoff/content/advanced_ada/new_conten…
Browse files Browse the repository at this point in the history
…t/memory_management/storage_elements/20231223

Adding section: Storage Elements
  • Loading branch information
gusthoff authored Dec 30, 2023
2 parents dc96df0 + b8bb032 commit 7d440d2
Show file tree
Hide file tree
Showing 2 changed files with 121 additions and 20 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -116,12 +116,12 @@ Ada offers multiple attributes to retrieve the size of a type or an object:
| Attribute | Description |
+=======================+=====================================================+
| :ada:`Size` | Size of the representation of a subtype or an |
| | object. |
| | object (in bits). |
+-----------------------+-----------------------------------------------------+
| :ada:`Object_Size` | Size of a component or an aliased object. |
| :ada:`Object_Size` | Size of a component or an aliased object (in bits). |
| | |
+-----------------------+-----------------------------------------------------+
| :ada:`Component_Size` | Size of a component of an array. |
| :ada:`Component_Size` | Size of a component of an array (in bits). |
+-----------------------+-----------------------------------------------------+
| :ada:`Storage_Size` | Number of storage elements reserved for an access |
| | type or a task object. |
Expand All @@ -132,6 +132,24 @@ For the first three attributes, the size is measured in bits. In the case of
size information depends your target architecture. We'll discuss some examples
to better understand the differences among those attributes.

.. _Adv_Ada_Storage_Elements:

.. admonition:: Important

A storage element is the smallest element we can use to store data in
memory. As we'll see soon, a storage element corresponds to a byte in
many architectures.

The size of a storage element is represented by the
:ada:`System.Storage_Unit` constant. In other words, the storage unit
corresponds to the number of bits used for a single storage element.

In typical architectures, :ada:`System.Storage_Unit` is 8 bits. In this
specific case, a storage element is equal to a byte in memory. Note,
however, that :ada:`System.Storage_Unit` might have a value different than
eight in certain architectures.


Size attribute and aspect
^^^^^^^^^^^^^^^^^^^^^^^^^

Expand Down Expand Up @@ -427,8 +445,7 @@ because we haven't indicated that memory should be reserved for this data type.
Thus, the compiler doesn't reserve memory and simply sets the size to zero.

Because :ada:`Storage_Size` gives us the number of storage elements, we have
to multiply this value by :ada:`System.Storage_Unit` |mdash| which gives
us the size (in bits) of a single storage element |mdash| to get the total
to multiply this value by :ada:`System.Storage_Unit` to get the total
storage size in bits. (In this particular example, however, the multiplication
doesn't make any difference, as the number of storage elements is zero.)

Expand Down Expand Up @@ -517,9 +534,9 @@ In this case, we're reserving 8 storage elements in the declaration of
type UInt_7_Reserved_Access is access UInt_7
with Storage_Size => 8;

Since each storage unit corresponds to one byte (8 bits) in this architecture,
we're reserving a maximum of 64 bits for the :ada:`UInt_7_Reserved_Access`
type.
Since each storage element corresponds to one byte (8 bits) in this
architecture, we're reserving a maximum of 64 bits (or 8 bytes) for the
:ada:`UInt_7_Reserved_Access` type.

This example raises an exception at runtime |mdash| a storage error, to be more
specific. This is because the maximum reserved size is 64 bits, and the size of
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ Code example with scalar type
Let's see a simple type :ada:`T` and two types based on it |mdash| an array and
an access type:

.. code:: ada compile_button project=Courses.Advanced_Ada.Resource_Management.Memory_Management.Storage_Elements
.. code:: ada compile_button project=Courses.Advanced_Ada.Resource_Management.Memory_Management.Max_Allocation_Size_Alignment

package Custom_Types is

Expand All @@ -78,7 +78,7 @@ The test procedure :ada:`Show_Sizes` shows the values returned by the
:ada:`Size`, :ada:`Max_Size_In_Storage_Elements`, and
:ada:`Max_Alignment_For_Allocation` attributes for the :ada:`T` type:

.. code:: ada run_button project=Courses.Advanced_Ada.Resource_Management.Memory_Management.Storage_Elements
.. code:: ada run_button project=Courses.Advanced_Ada.Resource_Management.Memory_Management.Max_Allocation_Size_Alignment

with Ada.Text_IO; use Ada.Text_IO;
with System;
Expand Down Expand Up @@ -123,7 +123,7 @@ In the original implementation of the :ada:`Custom_Types` package, we allowed
the compiler to select the size of type :ada:`T`. We can be more specific in
the type declarations and use the :ada:`Size` aspect for that type:

.. code:: ada compile_button project=Courses.Advanced_Ada.Resource_Management.Memory_Management.Storage_Elements
.. code:: ada compile_button project=Courses.Advanced_Ada.Resource_Management.Memory_Management.Max_Allocation_Size_Alignment

package Custom_Types is

Expand All @@ -141,7 +141,7 @@ Let's see how this change affects the :ada:`Size`,
:ada:`Max_Size_In_Storage_Elements`, and :ada:`Max_Alignment_For_Allocation`
attributes:

.. code:: ada run_button project=Courses.Advanced_Ada.Resource_Management.Memory_Management.Storage_Elements
.. code:: ada run_button project=Courses.Advanced_Ada.Resource_Management.Memory_Management.Max_Allocation_Size_Alignment

with Ada.Text_IO; use Ada.Text_IO;
with System;
Expand Down Expand Up @@ -192,7 +192,7 @@ Code example with array type
Note that using the :ada:`Size` and :ada:`Max_Size_In_Storage_Elements`
attributes on array types can give you a potentially higher number:

.. code:: ada run_button project=Courses.Advanced_Ada.Resource_Management.Memory_Management.Storage_Elements
.. code:: ada run_button project=Courses.Advanced_Ada.Resource_Management.Memory_Management.Max_Allocation_Size_Alignment

with Ada.Text_IO; use Ada.Text_IO;
with System;
Expand Down Expand Up @@ -235,7 +235,7 @@ theoretically available for the array in the memory pool. This information
allows us to calculate the (theoretical) maximum number of components for an
array of this type:

.. code:: ada run_button project=Courses.Advanced_Ada.Resource_Management.Memory_Management.Storage_Elements
.. code:: ada run_button project=Courses.Advanced_Ada.Resource_Management.Memory_Management.Max_Allocation_Size_Alignment

with Ada.Text_IO; use Ada.Text_IO;
with System;
Expand Down Expand Up @@ -263,15 +263,99 @@ number of components.
Storage elements
----------------

.. admonition:: Relevant topics
We saw parts of the :ada:`System.Storage_Elements` package while discussing
:ref:`addresses <Adv_Ada_Addresses>`. However, we haven't discussed yet
the main types from that package: :ada:`Storage_Element` and
:ada:`Storage_Array`.

- :ada:`System.Storage_Elements` package
- :ada:`System.Storage_Elements.Storage_Element'Size`
- :arm22:`The Package System.Storage_Elements <13-7-1>`
We defined :ref:`storage elements <Adv_Ada_Storage_Elements>` previously.
In the :ada:`System.Storage_Elements` package, a storage element is represented
by the :ada:`Storage_Element` type. Its size (:ada:`Storage_Element'Size`) is
equal to :ada:`Storage_Unit` |mdash| which we also mentioned previously.

.. todo::
The :ada:`Storage_Array` type is an array type of storage elements. This is its
definition:

Complete section!
.. code-block:: ada

type Storage_Array is
array (Storage_Offset range <>) of
aliased Storage_Element;

A storage array is used to represent a contiguous sequence of storage elements
in memory. In other words, you can think of an object of :ada:`Storage_Array`
type as a (memory) buffer.

.. admonition:: Important

Note that arrays of :ada:`Storage_Array` type are guaranteed by the
language to be contiguous. In contrast, storage pools are not required to
be contiguous blocks of memory. However, each memory allocation in a
storage pool returns a pointer to a contiguous block of memory.

.. admonition:: For further reading

Note that the :ada:`Storage_Offset` is an integer type with a range defined
by the compiler implementation. It's used not only
in the definition of the :ada:`Storage_Array` but also in
:ref:`address arithmetic <Adv_Ada_Address_Arithmetic>`, which we discussed
in an earlier chapter.

In fact, the :ada:`Storage_Array` is used in the generic :ada:`Storage_IO`
package to define a memory buffer:

.. code-block:: ada

with System.Storage_Elements;
use System.Storage_Elements;

subtype Buffer_Type is
Storage_Array (1 .. Buffer_Size);

Let's see a simple example that makes use of the :ada:`Storage_IO` package:

.. code:: ada run_button project=Courses.Advanced_Ada.Resource_Management.Storage_Elements

pragma Ada_2022;

with Ada.Text_IO; use Ada.Text_IO;
with Ada.Storage_IO;

procedure Show_Storage_IO is
type Rec is record
A, B : Integer;
C : Float;
end record;

package Rec_Storage_IO is new
Ada.Storage_IO (Element_Type => Rec);
use Rec_Storage_IO;

Buf : Buffer_Type;
R1, R2 : Rec;
begin
R1 := (1, 2, 3.0);
Put_Line ("R1 : " & R1'Image);

-- Writing from R1 to the buffer Buf:
Write (Buf, R1);

-- Reading from the buffer Buf to R2:
Read (Buf, R2);

Put_Line ("R2 : " & R2'Image);
end Show_Storage_IO;

In this example, we instantiate the :ada:`Storage_IO` package for the
:ada:`Rec` type and declare a buffer :ada:`Buf` of :ada:`Buffer_Type` type.
(Note that :ada:`Buf` is essentially an array of :ada:`Storage_Array` type.)
We then use this buffer and write an element to it (via :ada:`Write`) and read
from it (via :ada:`Read`).

.. admonition:: Relevant topics

- :arm22:`13.7.1 The Package System.Storage_Elements <13-7-1>`
- :arm22:`A.9 The Generic Package Storage_IO <A-9>`


.. _Adv_Ada_Finalization:
Expand Down

0 comments on commit 7d440d2

Please sign in to comment.