type Some_Array is array (Natural range <>) of Integer with
Dynamic_Predicate => Some_Array'First = 0;
You can also add a precondition to the function. However there will a few cases where the compiler won’t catch violations at compile time.
That sounds a lot like premature optimisation. Trust the optimiser to optimise array access.
2** is not needed. Ada can provide modulus types with any range. I use unconventional modulus types in my PI Ada Tutorial. The compiler takes care of it.
Suppose “Foo_Actual” is a procedure that does the actual processing and NEEDS to have a zero-based in out array. We can use “Foo_Wrapper” to slide any non-zero based array to a zero-based and pass this slided version to “Foo_Actual”
procedure Foo_Wrapper(X: in out myArray) is
subtype Slide is myArray (0..X'Length-1);
begin
Foo_Actual( Slide(X));
end Foo_Wrapper;
Foo_Actual does all its reading and writing in the zero-based domain, and the wrapper can return the result to the original based domain.
If I am not deceiving myself, this will contains no copies.
I fed the TP’s question to a free Claude (Sonnet5 Med). Here’s what she says. Sounds reasonable, but I didn’t test it. Ada.Containers.Vectors doesn’t hard-code the starting index — the generic has an Index_Type formal, and the container’s first index is always Index_Type'First. So to get 0-based indexing, instantiate with an index type whose 'First is 0:
with Ada.Containers.Vectors;
type Index_Type is range 0 .. Ada.Containers.Count_Type'Last - 1;
-- starts at 0, so Index_Type'First = 0
package Float_Vectors is new Ada.Containers.Vectors
(Index_Type => Index_Type,
Element_Type => Float);
use Float_Vectors;
V : Vector;
Now First_Index (V) = 0 always, and V (0) is valid as soon as the first element is appended:
ada
Append (V, 1.0); -- goes into index 0
Append (V, 2.0); -- goes into index 1
Important caveat — this is a run-time guarantee, not a compile-time one, and it’s weaker than what you got with the discriminated-record Vector in your earlier question.
Unlike the earlier case, here there’s nothing in the typeFloat_Vectors.Vector that forces zero-basing at compile time in the way a literal-0 discriminant bound does. What actually pins it to 0 is that you chose Index_Type'First = 0 in the instantiation, and the container’s First_Index function is specified (by the RM) to always equal Index_Type'First for a non-empty vector — it’s a property of the instantiated package, fixed once you write that type Index_Type is range 0 .. ..., not a property visible in the Vector type’s structure itself. So:
Using a container is not helpful if the aim is optimise for speed. Native arrays will always be faster as the compiler can optimise access better.
Claude saw the word “vector” and went on a wild goose chaise not considering the performance implications. As a human it was immediately clear to me why the OP wanted a zero based index.
Personally I think it’s premature optimisation as I expect the compiler to optimise any arithmetic operations surrounding A’First.
Since it’s trivial to change I would would confirm my expectation by making both version and measure performance or compile with assembler output and compare the generated code. Only if there is a measured difference I would start index optimisation.
Thanks All for the inputs and ideas on this topic.
I have marked the “Foo_Wrapper” (a couple of messages before this one) as the solution, even though it side-steps the original phrasing of the question.
It actually has a strong benefit over the original thinking. By using a “Foo Wrapper” approach, the library functions can receive arrays with arbitrary indexing, and then by sliding see everything handed to it as a zero-based indexed array.
The original thinking requiring the type to have zero-based indexing would limit broad use of any functions (since they could only operate on those special types.)