B.3.2 The Generic Package Interfaces.C.Pointers

From OC Systems Wiki!
< Guide:95lrm
Revision as of 22:08, 1 May 2019 by imported>WikiVisor
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Jump to: navigation, search

The generic package Interfaces.C.Pointers allows the Ada programmer to perform C-style operations on pointers. It includes an access type Pointer, Value functions that dereference a Pointer and deliver the designated array, several pointer arithmetic operations, and copy procedures that copy the contents of a source pointer into the array designated by a destination pointer. As in C, it treats an object Ptr of type Pointer as a pointer to the first element of an array, so that for example, adding 1 to Ptr yields a pointer to the second element of the array.

The generic allows two styles of usage: one in which the array is terminated by a special terminator element; and another in which the programmer needs to keep track of the length.

Static Semantics

The generic library package Interfaces.C.Pointers has the following declaration:

generic
    type Index is (<>);
    type Element is private; 
    type Element_Array is array (Index range <>) of aliased Element; 
    Default_Terminator : Element;
package Interfaces.C.Pointers is 
    pragma Preelaborate(Pointers);

    type Pointer is access all Element;

    function Value(Ref        in Pointer; 
                   Terminator in Element := Default_Terminator)
        return Element_Array;

    function Value(Ref    in Pointer;
                   Length in ptrdiff_t)
        return Element_Array;

    Pointer_Error : exception;

    -- C-style Pointer arithmetic

    function "+" (Left in Pointer;   Right in ptrdiff_t) return Pointer; 
    function "+" (Left in ptrdiff_t; Right in Pointer)   return Pointer; 
    function "-" (Left in Pointer;   Right in ptrdiff_t) return Pointer; 
    function "-" (Left in Pointer;   Right in Pointer) return ptrdiff_t;

    procedure Increment (Ref in out Pointer); 
    procedure Decrement (Ref in out Pointer);

    pragma Convention (Intrinsic, "+");
    pragma Convention (Intrinsic, "-");
    pragma Convention (Intrinsic, Increment);
    pragma Convention (Intrinsic, Decrement);

    function Virtual_Length (Ref        in Pointer; 
                             Terminator in Element := Default_Terminator) 
        return ptrdiff_t;

    procedure Copy_Terminated_Array
        (Source     in Pointer;
         Target     in Pointer;
         Limit      in ptrdiff_t := ptrdiff_t'Last; 
         Terminator in Element :=  Default_Terminator);

    procedure Copy_Array
        (Source  in Pointer;
         Target  in Pointer;
         Length  in ptrdiff_t);

end Interfaces.C.Pointers;

The type Pointer is C-compatible and corresponds to one use of C's Element *. An object of type Pointer is interpreted as a pointer to the initial Element in an Element_Array. Two styles are supported:

  • Explicit termination of an array value with Default_Terminator (a special terminator value);
  • Programmer-managed length, with Default_Terminator treated simply as a data element.

function Value(Ref        in Pointer; 
               Terminator in Element := Default_Terminator)
    return Element_Array;

This function returns an Element_Array whose value is the array pointed to by Ref, up to and including the first Terminator; the lower bound of the array is Index'First. Interfaces.C.Strings.Dereference_Error is propagated if Ref is null.

function Value(Ref    in Pointer;
               Length in ptrdiff_t) 
    return Element_Array;

This function returns an Element_Array comprising the first Length elements pointed to by Ref. The exception Interfaces.C.Strings.Dereference_Error is propagated if Ref is null.

The "+" and "-" functions perform arithmetic on Pointer values, based on the Size of the array elements. In each of these functions, Pointer_Error is propagated if a Pointer parameter is null.

procedure Increment (Ref in out Pointer);

Equivalent to Ref := Ref+1.

procedure Decrement (Ref in out Pointer);

Equivalent to Ref := Ref-1.

function Virtual_Length (Ref        in Pointer; 
                         Terminator in Element := Default_Terminator)
    return ptrdiff_t;

Returns the number of Elements, up to the one just before the first Terminator, in Value(Ref, Terminator).

procedure Copy_Terminated_Array
    (Source     in Pointer;
     Target     in Pointer;
     Limit      in ptrdiff_t := ptrdiff_t'Last; 
     Terminator in Element := Default_Terminator);

This procedure copies Value(Source, Terminator) into the array pointed to by Target; it stops either after Terminator has been copied, or the number of elements copied is Limit, whichever occurs first. Dereference_Error is propagated if either Source or Target is null.

procedure Copy_Array (Source  in Pointer;
                      Target  in Pointer;
                      Length  in ptrdiff_t);

This procedure copies the first Length elements from the array pointed to by Source, into the array pointed to by Target. Dereference_Error is propagated if either Source or Target is null.

Erroneous Execution

It is erroneous to dereference a Pointer that does not designate an aliased Element.

Execution of Value(Ref, Terminator) is erroneous if Ref does not designate an aliased Element in an Element_Array terminated by Terminator.

Execution of Value(Ref, Length) is erroneous if Ref does not designate an aliased Element in an Element_Array containing at least Length Elements between the designated Element and the end of the array, inclusive.

Execution of Virtual_Length(Ref, Terminator) is erroneous if Ref does not designate an aliased Element in an Element_Array terminated by Terminator.

Execution of Copy_Terminated_Array(Source, Target, Limit, Terminator) is erroneous in either of the following situations:

  • Execution of both Value(Source,Terminator) and Value(Source,Limit) are erroneous, or
  • Copying writes past the end of the array containing the Element designated by Target.

Execution of Copy_Array(Source, Target, Length) is erroneous if either Value(Source, Length) is erroneous, or copying writes past the end of the array containing the Element designated by Target.

Notes

14  To compose a Pointer from an Element_Array, use 'Access on the first element. For example (assuming appropriate instantiations):

Some_Array   : Element_Array(0..5) ; 
Some_Pointer : Pointer := Some_Array(0)'Access;

Examples

Example of Interfaces.C.Pointers:

with Interfaces.C.Pointers;
with Interfaces.C.Strings;
procedure Test_Pointers is 
    package C renames Interfaces.C;
    package Char_Ptrs is
        new C.Pointers (Index              => C.size_t, 
                        Element            => C.char, 
                        Element_Array      => C.char_array, 
                        Default_Terminator => C.nul);

    use type Char_Ptrs.Pointer; 
    subtype Char_Star is Char_Ptrs.Pointer;

    procedure Strcpy (Target_Ptr, Source_Ptr Char_Star) is 
        Target_Temp_Ptr : Char_Star := Target_Ptr; 
        Source_Temp_Ptr : Char_Star := Source_Ptr;
        Element : C.char; 
    begin   
        if Target_Temp_Ptr = null or Source_Temp_Ptr = null then 
            raise C.Strings.Dereference_Error;
        end if;

        loop
            Element             := Source_Temp_Ptr.all; 
            Target_Temp_Ptr.all := Element;
            exit when C."="(Element, C.nul);
            Char_Ptrs.Increment(Target_Temp_Ptr); 
            Char_Ptrs.Increment(Source_Temp_Ptr);
         end loop; 
     end Strcpy;
     begin
         ...
end Test_Pointers;

Copyright © 1992,1993,1994,1995 Intermetrics, Inc.
Copyright © 2000 The MITRE Corporation, Inc. Ada Reference Manual