comp.lang.ada
 help / color / mirror / Atom feed
* Custom Storage Pool questions
@ 2021-09-13  0:53 Jere
  2021-09-13  5:29 ` Randy Brukardt
                   ` (2 more replies)
  0 siblings, 3 replies; 62+ messages in thread
From: Jere @ 2021-09-13  0:53 UTC (permalink / raw)


I was learning about making user defined storage pools when
I came across an article that made me pause and wonder how
portable storage pools actually can be.  In particular, I assumed
that the Size_In_Storage_Elements parameter in the Allocate 
operation actually indicated the total number of storage elements 
needed.

procedure Allocate(
      Pool : in out Root_Storage_Pool;
      Storage_Address : out Address;
      Size_In_Storage_Elements : in Storage_Elements.Storage_Count;
      Alignment : in Storage_Elements.Storage_Count) is abstract;

But after reading the following AdaCore article, my assumption is now
called into question:
https://blog.adacore.com/header-storage-pools

In particular, the blog there advocates for separately counting for 
things like unconstrained array First/Last indices or the Prev/Next
pointers used for Controlled objects.  Normally I would have assumed
that the Size_In_Storage_Elements parameter in Allocate would account
for that, but the blog clearly shows that it doesn't

So that seems to mean to make a storage pool, I have to make it 
compiler specific or else risk someone creating a type like an
array and my allocation size and address values will be off.

Is it intended not to be able to do portable Storage Pools or am
I missing some Ada functionality that helps me out here.  I 
scanned through the list of attributes but none seem to give
any info about where the object's returned address is relative
to the top of the memory actually allocated for the object.  I saw
the attribute Max_Size_In_Storage_Elements, but it doesn't seem
to guarantee to include things like the array indices and it still
doesn't solve the issue of knowing where the returned address
needs to be relative to the top of allocated memory.

I can easily use a generic to ensure that the types I care about
are portably made by the pool, but I can't prevent someone from
using my pool to create other objects that I hadn't accounted for.
Unless there is a way to restrict a pool from allocating objects 
of other types?

^ permalink raw reply	[flat|nested] 62+ messages in thread

* Re: Custom Storage Pool questions
  2021-09-13  0:53 Custom Storage Pool questions Jere
@ 2021-09-13  5:29 ` Randy Brukardt
  2021-09-14  1:04   ` Jere
                     ` (2 more replies)
  2021-09-13 11:12 ` J-P. Rosen
  2021-09-15 16:43 ` Simon Wright
  2 siblings, 3 replies; 62+ messages in thread
From: Randy Brukardt @ 2021-09-13  5:29 UTC (permalink / raw)


Not sure what you are expecting. There is no requirement that objects are 
allocated contigiously. Indeed, Janus/Ada will call Allocate as many times 
as needed for each object; for instance, unconstrained arrays are in two 
parts (descriptor and data area).

The only thing that you can assume in a portable library is that you get 
called the same number of times and sizes/alignment for Allocate and 
Deallocate; there's no assumptions about size or alignment that you can 
make.

If you want to build a pool around some specific allocated size, then if it 
needs to be portable, (A) you have to calculate the allocated size, and (B) 
you have to have a mechanism for what to do if some other size is requested. 
(Allocate a whole block for smaller sizes, fall back to built-in heap for 
too large is what I usually do).

More likely, you'll build a pool for a particular implementation. Pools are 
very low level by their nature, and useful ones are even more so (because 
they are using target facilities to allocate memory, or need to assume 
something about the allocations, or because they are doing icky things like 
address math, or ...).

                   Randy.


                             Randy.



"Jere" <jhb.chat@gmail.com> wrote in message 
news:e3c5c553-4a7f-408a-aaa7-60ec0b70202dn@googlegroups.com...
>I was learning about making user defined storage pools when
> I came across an article that made me pause and wonder how
> portable storage pools actually can be.  In particular, I assumed
> that the Size_In_Storage_Elements parameter in the Allocate
> operation actually indicated the total number of storage elements
> needed.
>
> procedure Allocate(
>      Pool : in out Root_Storage_Pool;
>      Storage_Address : out Address;
>      Size_In_Storage_Elements : in Storage_Elements.Storage_Count;
>      Alignment : in Storage_Elements.Storage_Count) is abstract;
>
> But after reading the following AdaCore article, my assumption is now
> called into question:
> https://blog.adacore.com/header-storage-pools
>
> In particular, the blog there advocates for separately counting for
> things like unconstrained array First/Last indices or the Prev/Next
> pointers used for Controlled objects.  Normally I would have assumed
> that the Size_In_Storage_Elements parameter in Allocate would account
> for that, but the blog clearly shows that it doesn't
>
> So that seems to mean to make a storage pool, I have to make it
> compiler specific or else risk someone creating a type like an
> array and my allocation size and address values will be off.
>
> Is it intended not to be able to do portable Storage Pools or am
> I missing some Ada functionality that helps me out here.  I
> scanned through the list of attributes but none seem to give
> any info about where the object's returned address is relative
> to the top of the memory actually allocated for the object.  I saw
> the attribute Max_Size_In_Storage_Elements, but it doesn't seem
> to guarantee to include things like the array indices and it still
> doesn't solve the issue of knowing where the returned address
> needs to be relative to the top of allocated memory.
>
> I can easily use a generic to ensure that the types I care about
> are portably made by the pool, but I can't prevent someone from
> using my pool to create other objects that I hadn't accounted for.
> Unless there is a way to restrict a pool from allocating objects
> of other types? 


^ permalink raw reply	[flat|nested] 62+ messages in thread

* Re: Custom Storage Pool questions
  2021-09-13  0:53 Custom Storage Pool questions Jere
  2021-09-13  5:29 ` Randy Brukardt
@ 2021-09-13 11:12 ` J-P. Rosen
  2021-09-14  0:48   ` Jere
  2021-09-15 16:43 ` Simon Wright
  2 siblings, 1 reply; 62+ messages in thread
From: J-P. Rosen @ 2021-09-13 11:12 UTC (permalink / raw)


Le 13/09/2021 à 02:53, Jere a écrit :
> I was learning about making user defined storage pools when
> I came across an article that made me pause and wonder how
> portable storage pools actually can be.  In particular, I assumed
> that the Size_In_Storage_Elements parameter in the Allocate
> operation actually indicated the total number of storage elements
> needed.
> 
> procedure Allocate(
>        Pool : in out Root_Storage_Pool;
>        Storage_Address : out Address;
>        Size_In_Storage_Elements : in Storage_Elements.Storage_Count;
>        Alignment : in Storage_Elements.Storage_Count) is abstract;
> 
> But after reading the following AdaCore article, my assumption is now
> called into question:
> https://blog.adacore.com/header-storage-pools
> 
> In particular, the blog there advocates for separately counting for
> things like unconstrained array First/Last indices or the Prev/Next
> pointers used for Controlled objects.  Normally I would have assumed
> that the Size_In_Storage_Elements parameter in Allocate would account
> for that, but the blog clearly shows that it doesn't
[...]

That blog shows a special use for Storage_Pools, where you allocate 
/user/ data on top of the requested memory. When called by the compiler, 
it is up to the compiler to compute how much memory is needed, and your 
duty is to just allocate that.

-- 
J-P. Rosen
Adalog
2 rue du Docteur Lombard, 92441 Issy-les-Moulineaux CEDEX
Tel: +33 1 45 29 21 52
https://www.adalog.fr

^ permalink raw reply	[flat|nested] 62+ messages in thread

* Re: Custom Storage Pool questions
  2021-09-13 11:12 ` J-P. Rosen
@ 2021-09-14  0:48   ` Jere
  2021-09-14  6:08     ` J-P. Rosen
                       ` (2 more replies)
  0 siblings, 3 replies; 62+ messages in thread
From: Jere @ 2021-09-14  0:48 UTC (permalink / raw)


On Monday, September 13, 2021 at 7:12:43 AM UTC-4, J-P. Rosen wrote:
> Le 13/09/2021 à 02:53, Jere a écrit : 
> > I was learning about making user defined storage pools when 
> > I came across an article that made me pause and wonder how 
> > portable storage pools actually can be. In particular, I assumed 
> > that the Size_In_Storage_Elements parameter in the Allocate 
> > operation actually indicated the total number of storage elements 
> > needed. 
> > 
> > procedure Allocate( 
> > Pool : in out Root_Storage_Pool; 
> > Storage_Address : out Address; 
> > Size_In_Storage_Elements : in Storage_Elements.Storage_Count; 
> > Alignment : in Storage_Elements.Storage_Count) is abstract; 
> > 
> > But after reading the following AdaCore article, my assumption is now 
> > called into question: 
> > https://blog.adacore.com/header-storage-pools 
> > 
> > In particular, the blog there advocates for separately counting for 
> > things like unconstrained array First/Last indices or the Prev/Next 
> > pointers used for Controlled objects. Normally I would have assumed 
> > that the Size_In_Storage_Elements parameter in Allocate would account 
> > for that, but the blog clearly shows that it doesn't
> [...] 
> 
> That blog shows a special use for Storage_Pools, where you allocate 
> /user/ data on top of the requested memory. When called by the compiler, 
> it is up to the compiler to compute how much memory is needed, and your 
> duty is to just allocate that. 
> 
Yes, but if you look at that blog, they are allocating space for the /user/ data 
and for the Next/Prev for controlled types and First/Last for unconstrained
arrays in addition to the size specified by allocate.  

I agree I feel it is up to the compiler to provide the correct size to Allocate, 
but the blog would indicate that GNAT does not (or did not..old blog..so 
who knows?).  Does the RM require that an implementation pass the full
amount of memory needed to Allocate when new is called?  

^ permalink raw reply	[flat|nested] 62+ messages in thread

* Re: Custom Storage Pool questions
  2021-09-13  5:29 ` Randy Brukardt
@ 2021-09-14  1:04   ` Jere
  2021-09-21  0:06     ` Randy Brukardt
  2021-09-18 11:32   ` Simon Wright
  2021-09-20  0:31   ` Jere
  2 siblings, 1 reply; 62+ messages in thread
From: Jere @ 2021-09-14  1:04 UTC (permalink / raw)


On Monday, September 13, 2021 at 1:29:39 AM UTC-4, Randy Brukardt wrote:
> Not sure what you are expecting. There is no requirement that objects are 
> allocated contigiously. Indeed, Janus/Ada will call Allocate as many times 
> as needed for each object; for instance, unconstrained arrays are in two 
> parts (descriptor and data area). 
> 
No expectations.  Just questions.  I wasn't concerned with whether the
allocated memory was contiguous or not, but whether an implementation
is required to supply the correct size of memory needed to allocate an object
or if it is allowed to pass a value to Size that is less than the amount of
memory actually needed.  For example, the blog there indicates the 
maintainer of the custom storage pool needs to account for First/Last
indexes of an unconstrained array separately instead of assuming that value is
included as part of the Size parameter's value.

If the Size parameter doesn't require that it includes space for First/Last
for unconstrained arrays or Prev/Next for controlled objects (assuming
that is even the implementation picked of course), then I'm not seeing
a way to write a custom storage pool that is portable because you need
to account for each implementation's "hidden" values that are not represented
in the Size parameter.  For example if Janus calculated Size to have
both the size of the array and the size of First and Last but GNAT didn't 
and my storage pool assumed the JANUS method, then if someone
used my storage pool with GNAT then it would access memory 
from some other location potentially and erroneously.

> The only thing that you can assume in a portable library is that you get 
> called the same number of times and sizes/alignment for Allocate and 
> Deallocate; there's no assumptions about size or alignment that you can 
> make. 
So to be clear, you cannot assume that Size and Alignment are appropriate
for the actual object being allocated correct?  Size could actually be
less than the actual amount of memory needed and the alignment may only
apply to part of the object being allocated, not the full object?

Is that correct?  I'm asking because that is what the blog suggests with
the example it gave.

> 
> If you want to build a pool around some specific allocated size, then if it 
> needs to be portable, (A) you have to calculate the allocated size, and (B) 
> you have to have a mechanism for what to do if some other size is requested. 
> (Allocate a whole block for smaller sizes, fall back to built-in heap for 
> too large is what I usually do). 
> 
Are there any good tricks to handle this?  For example, if I design a 
storage pool around constructing a particular type of object, what is
normally done to discourage another programmer from using the pool with
an entirely different type?  Maybe raise an exception if the size isn't exact?
I'm not sure what else, unless maybe there is an Aspect/Attribute that 
can be set to ensure only a specific type of object can be constructed.



HISTORY:
> 
> 
> 
> "Jere" <> wrote in message 
> news:e3c5c553-4a7f-408a...@googlegroups.com...
> >I was learning about making user defined storage pools when 
> > I came across an article that made me pause and wonder how 
> > portable storage pools actually can be. In particular, I assumed 
> > that the Size_In_Storage_Elements parameter in the Allocate 
> > operation actually indicated the total number of storage elements 
> > needed. 
> > 
> > procedure Allocate( 
> > Pool : in out Root_Storage_Pool; 
> > Storage_Address : out Address; 
> > Size_In_Storage_Elements : in Storage_Elements.Storage_Count; 
> > Alignment : in Storage_Elements.Storage_Count) is abstract; 
> > 
> > But after reading the following AdaCore article, my assumption is now 
> > called into question: 
> > https://blog.adacore.com/header-storage-pools 
> > 
> > In particular, the blog there advocates for separately counting for 
> > things like unconstrained array First/Last indices or the Prev/Next 
> > pointers used for Controlled objects. Normally I would have assumed 
> > that the Size_In_Storage_Elements parameter in Allocate would account 
> > for that, but the blog clearly shows that it doesn't 
> > 
> > So that seems to mean to make a storage pool, I have to make it 
> > compiler specific or else risk someone creating a type like an 
> > array and my allocation size and address values will be off. 
> > 
> > Is it intended not to be able to do portable Storage Pools or am 
> > I missing some Ada functionality that helps me out here. I 
> > scanned through the list of attributes but none seem to give 
> > any info about where the object's returned address is relative 
> > to the top of the memory actually allocated for the object. I saw 
> > the attribute Max_Size_In_Storage_Elements, but it doesn't seem 
> > to guarantee to include things like the array indices and it still 
> > doesn't solve the issue of knowing where the returned address 
> > needs to be relative to the top of allocated memory. 
> > 
> > I can easily use a generic to ensure that the types I care about 
> > are portably made by the pool, but I can't prevent someone from 
> > using my pool to create other objects that I hadn't accounted for. 
> > Unless there is a way to restrict a pool from allocating objects 
> > of other types?

^ permalink raw reply	[flat|nested] 62+ messages in thread

* Re: Custom Storage Pool questions
  2021-09-14  0:48   ` Jere
@ 2021-09-14  6:08     ` J-P. Rosen
  2021-09-15  0:39       ` Jere
  2021-09-14  6:23     ` Dmitry A. Kazakov
  2021-09-14 10:54     ` Egil H H
  2 siblings, 1 reply; 62+ messages in thread
From: J-P. Rosen @ 2021-09-14  6:08 UTC (permalink / raw)


Le 14/09/2021 à 02:48, Jere a écrit :
>>> In particular, the blog there advocates for separately counting for
>>> things like unconstrained array First/Last indices or the Prev/Next
>>> pointers used for Controlled objects. Normally I would have assumed
>>> that the Size_In_Storage_Elements parameter in Allocate would account
>>> for that, but the blog clearly shows that it doesn't
>> [...]
>>
>> That blog shows a special use for Storage_Pools, where you allocate
>> /user/ data on top of the requested memory. When called by the compiler,
>> it is up to the compiler to compute how much memory is needed, and your
>> duty is to just allocate that.
>>
> Yes, but if you look at that blog, they are allocating space for the /user/ data
> and for the Next/Prev for controlled types and First/Last for unconstrained
> arrays in addition to the size specified by allocate.
> 
> I agree I feel it is up to the compiler to provide the correct size to Allocate,
> but the blog would indicate that GNAT does not (or did not..old blog..so
> who knows?).  Does the RM require that an implementation pass the full
> amount of memory needed to Allocate when new is called?
> 

The RM says that an allocator allocates storage from the storage pool. 
You could argue that it does not say "allocates all needed storage...", 
but that would be a bit far fetched.

Anyway, a blog is not the proper place to get information from for that 
kind of issue. Look at the Gnat documentation.

-- 
J-P. Rosen
Adalog
2 rue du Docteur Lombard, 92441 Issy-les-Moulineaux CEDEX
Tel: +33 1 45 29 21 52
https://www.adalog.fr

^ permalink raw reply	[flat|nested] 62+ messages in thread

* Re: Custom Storage Pool questions
  2021-09-14  0:48   ` Jere
  2021-09-14  6:08     ` J-P. Rosen
@ 2021-09-14  6:23     ` Dmitry A. Kazakov
  2021-09-14  6:42       ` J-P. Rosen
                         ` (2 more replies)
  2021-09-14 10:54     ` Egil H H
  2 siblings, 3 replies; 62+ messages in thread
From: Dmitry A. Kazakov @ 2021-09-14  6:23 UTC (permalink / raw)


On 2021-09-14 02:48, Jere wrote:

> Yes, but if you look at that blog, they are allocating space for the /user/ data
> and for the Next/Prev for controlled types and First/Last for unconstrained
> arrays in addition to the size specified by allocate.

I do not understand your concern. The blog discusses how to add service 
data to the objects allocated in the pool.

I use such pools extensively in Simple Components. E.g. linked lists are 
implemented this way. The list links are allocated in front of list 
elements which can be of any type, unconstrained arrays included.

The problem with unconstrained arrays is not that the bounds are not 
allocated, they are, but the semantics of X'Address when applied to arrays.

A'Address is the address of the first array element, not of the array 
object. For a pool designer it constitutes a problem of getting the 
array object by address. This is what Emmanuel discusses in the blog.

[ The motivation behind Ada choice was probably to keep the semantics 
implementation-independent. ]

Consider for example a list of String elements. When Allocate is called 
with String, it returns the address of all String. But that is not the 
address you would get if you applied 'Address. You have to add/subtract 
some offset in order to get one from another.

In Simple Components this offset is determined at run-time for each 
generic instance.

Of course, a proper solution would be fixing Ada by adding another 
address attribute:

    X'Object_Address

returning the first address of the object as allocated.

-- 
Regards,
Dmitry A. Kazakov
http://www.dmitry-kazakov.de

^ permalink raw reply	[flat|nested] 62+ messages in thread

* Re: Custom Storage Pool questions
  2021-09-14  6:23     ` Dmitry A. Kazakov
@ 2021-09-14  6:42       ` J-P. Rosen
  2021-09-14  7:00         ` Dmitry A. Kazakov
  2021-09-20 23:58         ` Randy Brukardt
  2021-09-15  0:21       ` Jere
  2021-09-20 23:48       ` Randy Brukardt
  2 siblings, 2 replies; 62+ messages in thread
From: J-P. Rosen @ 2021-09-14  6:42 UTC (permalink / raw)


Le 14/09/2021 à 08:23, Dmitry A. Kazakov a écrit :
> Of course, a proper solution would be fixing Ada by adding another 
> address attribute:
> 
>     X'Object_Address
> 
> returning the first address of the object as allocated.
But you cannot assume that the object is allocated as one big chunk.
Bounds can be allocated at a different place. What would be 
X'Object_Address in that case?

-- 
J-P. Rosen
Adalog
2 rue du Docteur Lombard, 92441 Issy-les-Moulineaux CEDEX
Tel: +33 1 45 29 21 52
https://www.adalog.fr

^ permalink raw reply	[flat|nested] 62+ messages in thread

* Re: Custom Storage Pool questions
  2021-09-14  6:42       ` J-P. Rosen
@ 2021-09-14  7:00         ` Dmitry A. Kazakov
  2021-09-20 23:58         ` Randy Brukardt
  1 sibling, 0 replies; 62+ messages in thread
From: Dmitry A. Kazakov @ 2021-09-14  7:00 UTC (permalink / raw)


On 2021-09-14 08:42, J-P. Rosen wrote:
> Le 14/09/2021 à 08:23, Dmitry A. Kazakov a écrit :
>> Of course, a proper solution would be fixing Ada by adding another 
>> address attribute:
>>
>>     X'Object_Address
>>
>> returning the first address of the object as allocated.
> But you cannot assume that the object is allocated as one big chunk.
> Bounds can be allocated at a different place. What would be 
> X'Object_Address in that case?

The object address, without bounds, same as X'Address.

What Allocate returns is not what A'Address tells. The compiler always 
knows the difference, the programmer have to know it too. Nothing more.

-- 
Regards,
Dmitry A. Kazakov
http://www.dmitry-kazakov.de

^ permalink raw reply	[flat|nested] 62+ messages in thread

* Re: Custom Storage Pool questions
  2021-09-14  0:48   ` Jere
  2021-09-14  6:08     ` J-P. Rosen
  2021-09-14  6:23     ` Dmitry A. Kazakov
@ 2021-09-14 10:54     ` Egil H H
  2021-09-15  0:11       ` Jere
  2 siblings, 1 reply; 62+ messages in thread
From: Egil H H @ 2021-09-14 10:54 UTC (permalink / raw)


On Tuesday, September 14, 2021 at 2:48:16 AM UTC+2, Jere wrote:
> 
> Yes, but if you look at that blog, they are allocating space for the /user/ data 
> and for the Next/Prev for controlled types and First/Last for unconstrained 
> arrays in addition to the size specified by allocate. 
> 

Yes, but if you look at that blog, they explain the default layout of fat pointers, 
and the special value that need to be set on access types for the layout to 
change. If you use such a GNAT-ism, your storage pool will also be bound
to GNAT...


ie: 
"GNAT typically uses a "fat pointer" for this purpose: the access itself is in fact
a record of two pointers, one of which points to the bounds, the other points to
the data. This representation is not appropriate in the case of the header 
storage pool, so we need to change the memory layout here."

and:
"we need to ensure that the bounds for unconstrained arrays are stored next to 
the element, not in a separate memory block, to improve performance. This is 
done by setting the Size attribute on the type. When we set this size to that of 
a standard pointer, GNAT automatically changes the layout,"


-- 
~egilhh

^ permalink raw reply	[flat|nested] 62+ messages in thread

* Re: Custom Storage Pool questions
  2021-09-14 10:54     ` Egil H H
@ 2021-09-15  0:11       ` Jere
  0 siblings, 0 replies; 62+ messages in thread
From: Jere @ 2021-09-15  0:11 UTC (permalink / raw)


On Tuesday, September 14, 2021 at 6:54:54 AM UTC-4, ehh wrote:
> On Tuesday, September 14, 2021 at 2:48:16 AM UTC+2, Jere wrote: 
> > 
> > Yes, but if you look at that blog, they are allocating space for the /user/ data 
> > and for the Next/Prev for controlled types and First/Last for unconstrained 
> > arrays in addition to the size specified by allocate. 
> >
> Yes, but if you look at that blog, they explain the default layout of fat pointers, 
> and the special value that need to be set on access types for the layout to 
> change. If you use such a GNAT-ism, your storage pool will also be bound 
> to GNAT... 
> 
> 
> ie: 
> "GNAT typically uses a "fat pointer" for this purpose: the access itself is in fact 
> a record of two pointers, one of which points to the bounds, the other points to 
> the data. This representation is not appropriate in the case of the header 
> storage pool, so we need to change the memory layout here." 
> 
> and: 
> "we need to ensure that the bounds for unconstrained arrays are stored next to 
> the element, not in a separate memory block, to improve performance. This is 
> done by setting the Size attribute on the type. When we set this size to that of 
> a standard pointer, GNAT automatically changes the layout," 
> 

What I am seeing in the blog is if I *do not* use the GNAT ism in my storage pool
and assume that the Size parameter indicates the full size needed, then if someone
uses my pool with a GNAT compiler it would erroneously access memory.

You can clearly see the calculation in the blog is:
Aligned_Size : constant Storage_Count :=   --  bytes
            Size + Header_Allocation + Extra_Offset;

Where Size is specified by Allocate, Header_Allocation is the user supplied fields
of the storage pool, and ***Extra_Offset*** is a separate size value that accounts
for First/Last or Previous/Next

Finalization_Master_Size : constant Storage_Count :=
         2 * Standard'Address_Size;   --  for Previous and Next
Extra_Offset : constant Storage_Count :=
         (Element_Type'Descriptor_Size + Finalization_Master_Size)
         / Storage_Unit;       --  convert from bits to bytes

The blog quotes:
"""The size for the bounds is given by the attribute Descriptor_Size. For most types, 
the value of this attribute is 0. However, in the case of unconstrained array types, it
 is the size of two integers"""

These values are specified separate from the Size parameter and added to it in the
Allocate function shown in the blog there.

If I were to write my own storage pool and I didn't do the Extra_Offset calculation and just
assumed the compiler would call Allocate with the correct Size value for everything,
the logic in that blog then would indicate that GNAT would assume I did the Extra_Offset
calculation anyways and it could access those fields even if I didn't explicitly allocate
them separately as GNAT does.  In that case the fields would be part of some other object's
memory or random memory.

My original question is if the intended premise in Ada is that Storage pools aren't expected to be 
created to be portable due to just being low level because compilers can just assume 
you will know to allocate hidden fields in addition to what the Size parameter specifies.

Does that help clarify what I'm confused on?  Sorry, I am not great with wording.

^ permalink raw reply	[flat|nested] 62+ messages in thread

* Re: Custom Storage Pool questions
  2021-09-14  6:23     ` Dmitry A. Kazakov
  2021-09-14  6:42       ` J-P. Rosen
@ 2021-09-15  0:21       ` Jere
  2021-09-15  6:54         ` Dmitry A. Kazakov
  2021-09-20 23:48       ` Randy Brukardt
  2 siblings, 1 reply; 62+ messages in thread
From: Jere @ 2021-09-15  0:21 UTC (permalink / raw)


On Tuesday, September 14, 2021 at 2:23:15 AM UTC-4, Dmitry A. Kazakov wrote:
> On 2021-09-14 02:48, Jere wrote: 
> 
> > Yes, but if you look at that blog, they are allocating space for the /user/ data 
> > and for the Next/Prev for controlled types and First/Last for unconstrained 
> > arrays in addition to the size specified by allocate.
> I do not understand your concern. The blog discusses how to add service 
> data to the objects allocated in the pool. 
> 
I tried to better articulate my concern in my response to egilhh if you want
to take a quick look at that and see if it clarifies better.  

> I use such pools extensively in Simple Components. E.g. linked lists are 
> implemented this way. The list links are allocated in front of list 
> elements which can be of any type, unconstrained arrays included. 
> 
The blog I saw was old, so it is completely possible it no longer is 
true that GNAT does what the blog suggests.  I'll take a look at your
storage pools and see how they handle things like this. 


^ permalink raw reply	[flat|nested] 62+ messages in thread

* Re: Custom Storage Pool questions
  2021-09-14  6:08     ` J-P. Rosen
@ 2021-09-15  0:39       ` Jere
  2021-09-15  7:01         ` Simon Wright
  0 siblings, 1 reply; 62+ messages in thread
From: Jere @ 2021-09-15  0:39 UTC (permalink / raw)


On Tuesday, September 14, 2021 at 2:08:49 AM UTC-4, J-P. Rosen wrote:
> Le 14/09/2021 à 02:48, Jere a écrit : 
> >>> In particular, the blog there advocates for separately counting for 
> >>> things like unconstrained array First/Last indices or the Prev/Next 
> >>> pointers used for Controlled objects. Normally I would have assumed 
> >>> that the Size_In_Storage_Elements parameter in Allocate would account 
> >>> for that, but the blog clearly shows that it doesn't 
> >> [...] 
> >> 
> >> That blog shows a special use for Storage_Pools, where you allocate 
> >> /user/ data on top of the requested memory. When called by the compiler, 
> >> it is up to the compiler to compute how much memory is needed, and your 
> >> duty is to just allocate that. 
> >> 
> > Yes, but if you look at that blog, they are allocating space for the /user/ data 
> > and for the Next/Prev for controlled types and First/Last for unconstrained 
> > arrays in addition to the size specified by allocate. 
> > 
> > I agree I feel it is up to the compiler to provide the correct size to Allocate, 
> > but the blog would indicate that GNAT does not (or did not..old blog..so 
> > who knows?). Does the RM require that an implementation pass the full 
> > amount of memory needed to Allocate when new is called? 
> >
> The RM says that an allocator allocates storage from the storage pool. 
> You could argue that it does not say "allocates all needed storage...", 
> but that would be a bit far fetched. 
I agree, but the blog made reconsider how far fetched it was.

> 
> Anyway, a blog is not the proper place to get information from for that 
> kind of issue. Look at the Gnat documentation.
> -- 
I'll take a look at the GNAT docs to see (and of course that blog is old,
so GNAT may not do this anymore anyways), but I mainly asking in the
frame of what Ada allows and/or expects.  I'd like to be able to allocate
storage simply without worrying how the compiler does it under the hood
and just assume that any calls to Allocate will ask for the full amount of
memory.   

Am I correct to assume that Ada doesn't provide any language means
to restrict what types a pool can make objects of.  The times that I have
wanted to make a pool are generally for specific types and it is often 
simpler to design them if I can assume only those types are being generated

Thanks for the response.  I'm sorry for all the questions.  That's how I 
learn and I realize it isn't a popular way to learn in the community, but
I have always learned very differently than most.

^ permalink raw reply	[flat|nested] 62+ messages in thread

* Re: Custom Storage Pool questions
  2021-09-15  0:21       ` Jere
@ 2021-09-15  6:54         ` Dmitry A. Kazakov
  0 siblings, 0 replies; 62+ messages in thread
From: Dmitry A. Kazakov @ 2021-09-15  6:54 UTC (permalink / raw)


On 2021-09-15 02:21, Jere wrote:
> On Tuesday, September 14, 2021 at 2:23:15 AM UTC-4, Dmitry A. Kazakov wrote:
>> On 2021-09-14 02:48, Jere wrote:
>>
>>> Yes, but if you look at that blog, they are allocating space for the /user/ data
>>> and for the Next/Prev for controlled types and First/Last for unconstrained
>>> arrays in addition to the size specified by allocate.
>> I do not understand your concern. The blog discusses how to add service
>> data to the objects allocated in the pool.
>>
> I tried to better articulate my concern in my response to egilhh if you want
> to take a quick look at that and see if it clarifies better.

Not really. It seems that you are under impression that Allocate must 
allocate more size than its Size parameter asks. The answer is no, 
unless *you* wanted to add something to each allocated object.

>> I use such pools extensively in Simple Components. E.g. linked lists are
>> implemented this way. The list links are allocated in front of list
>> elements which can be of any type, unconstrained arrays included.
>>
> The blog I saw was old, so it is completely possible it no longer is
> true that GNAT does what the blog suggests.  I'll take a look at your
> storage pools and see how they handle things like this.

I calculate the offset at run time. I keep the list of recently 
allocated blocks. The first time the address is asked from an element, 
that is, the first time an element allocated in the pool becomes known 
to the pool, its address is searched through the list of blocks. The 
minimal difference between the block address and the element address 
(X'Address) is the offset.

This is more portable than GNAT-specific attribute Descriptor_Size.

Again, if attributes to be added, then it should be the object address 
as allocated. The compiler always knows the proper address because this 
address is passed to Free, not X'Address!

-- 
Regards,
Dmitry A. Kazakov
http://www.dmitry-kazakov.de

^ permalink raw reply	[flat|nested] 62+ messages in thread

* Re: Custom Storage Pool questions
  2021-09-15  0:39       ` Jere
@ 2021-09-15  7:01         ` Simon Wright
  2021-09-16 23:32           ` Jere
  0 siblings, 1 reply; 62+ messages in thread
From: Simon Wright @ 2021-09-15  7:01 UTC (permalink / raw)


Jere <jhb.chat@gmail.com> writes:

> Thanks for the response.  I'm sorry for all the questions.  That's how
> I learn and I realize it isn't a popular way to learn in the
> community, but I have always learned very differently than most.

Seems to me you ask interesting questions which generate enlightening
responses!

^ permalink raw reply	[flat|nested] 62+ messages in thread

* Re: Custom Storage Pool questions
  2021-09-13  0:53 Custom Storage Pool questions Jere
  2021-09-13  5:29 ` Randy Brukardt
  2021-09-13 11:12 ` J-P. Rosen
@ 2021-09-15 16:43 ` Simon Wright
  2021-09-15 17:03   ` Simon Wright
  2021-09-15 19:07   ` Dmitry A. Kazakov
  2 siblings, 2 replies; 62+ messages in thread
From: Simon Wright @ 2021-09-15 16:43 UTC (permalink / raw)


Jere <jhb.chat@gmail.com> writes:

> But after reading the following AdaCore article, my assumption is now
> called into question:
> https://blog.adacore.com/header-storage-pools
>
> In particular, the blog there advocates for separately counting for
> things like unconstrained array First/Last indices or the Prev/Next
> pointers used for Controlled objects.  Normally I would have assumed
> that the Size_In_Storage_Elements parameter in Allocate would account
> for that, but the blog clearly shows that it doesn't

Well, I may well have missed the point somewhere, and maybe things have
changed since 2015, but as far as I can see, with FSF GCC 11.1.0, the
technique described in the blog is completely unnecessary.

To save having to recompile the runtime with debug symbols, I wrote a
tiny pool which delegates to GNAT's
System.Pool_Global.Global_Pool_Object (the default pool), e.g.

   overriding procedure Allocate
     (Pool                     : in out My_Pool.Pool;
      Storage_Address          :    out Address;
      Size_In_Storage_Elements : in     Storage_Elements.Storage_Count;
      Alignment                : in     Storage_Elements.Storage_Count)
   is
      pragma Unreferenced (Pool);
   begin
      Global_Pool_Object.Allocate
        (Address      => Storage_Address,
         Storage_Size => Size_In_Storage_Elements,
         Alignment    => Alignment);
   end Allocate;

and I find with

      Pool : My_Pool.Pool;

      type C is new Ada.Finalization.Controlled with null record;
      type Cs is array (Natural range <>) of C;
      type Csp is access Cs with Storage_Pool => Pool;
      procedure Free is new Ada.Unchecked_Deallocation (Cs, Csp);
      Pcs : Csp;

   begin

      Pcs := new Cs (0 .. 5);
      Free (Pcs);

that

* the alignment requested is 8 (was 4 for an array of Boolean);
* the size requested is 72, which is 24 bytes more than required for the
  6 minimal POs;
* the value returned by Allocate is 24 bytes more than the address of
  the array object Pcs (which is the same as that of Pcs(0));
* the value passed to Deallocate is the same as that returned by
  Allocate.

I think it's more than likely (!) that the extra allocation of 24 bytes
is made up of 2 pointers at 8 bytes each, used to implement the
finalization chain, and two integers at 4 bytes each, holding the array
bounds.

So I'd say that to create a pool with extra header information, you'd
need to allocate space for your header + padding to ensure that the
compiler's object is properly aligned + the compiler-requested size,
aligned to the max of your header's alignment and the compiler-requested
alignment.

Mind, I don't quite see how to actually access the header info for a
particular allocation ...

^ permalink raw reply	[flat|nested] 62+ messages in thread

* Re: Custom Storage Pool questions
  2021-09-15 16:43 ` Simon Wright
@ 2021-09-15 17:03   ` Simon Wright
  2021-09-15 19:07   ` Dmitry A. Kazakov
  1 sibling, 0 replies; 62+ messages in thread
From: Simon Wright @ 2021-09-15 17:03 UTC (permalink / raw)


Simon Wright <simon@pushface.org> writes:

> Well, I may well have missed the point somewhere, and maybe things
> have changed since 2015, but as far as I can see, with FSF GCC 11.1.0,
> the technique described in the blog is completely unnecessary.

Looking at the current implementation in [1] it seems that I was right
(I don't quite follow the complication of Typed.Header_Of at line 114;
goes to show that if you're writing the compiler you can add attributes
whenever it suits you, even if IMO they weren't actually needed)

[1] https://github.com/AdaCore/gnatcoll-core/blob/master/src/gnatcoll-storage_pools-headers.adb 

^ permalink raw reply	[flat|nested] 62+ messages in thread

* Re: Custom Storage Pool questions
  2021-09-15 16:43 ` Simon Wright
  2021-09-15 17:03   ` Simon Wright
@ 2021-09-15 19:07   ` Dmitry A. Kazakov
  2021-09-15 20:40     ` Simon Wright
  1 sibling, 1 reply; 62+ messages in thread
From: Dmitry A. Kazakov @ 2021-09-15 19:07 UTC (permalink / raw)


On 2021-09-15 18:43, Simon Wright wrote:

> To save having to recompile the runtime with debug symbols, I wrote a
> tiny pool which delegates to GNAT's
> System.Pool_Global.Global_Pool_Object (the default pool), e.g.
> 
>     overriding procedure Allocate
>       (Pool                     : in out My_Pool.Pool;
>        Storage_Address          :    out Address;
>        Size_In_Storage_Elements : in     Storage_Elements.Storage_Count;
>        Alignment                : in     Storage_Elements.Storage_Count)
>     is
>        pragma Unreferenced (Pool);
>     begin
>        Global_Pool_Object.Allocate
>          (Address      => Storage_Address,
>           Storage_Size => Size_In_Storage_Elements,
>           Alignment    => Alignment);
>     end Allocate;
> 
> and I find with
> 
>        Pool : My_Pool.Pool;
> 
>        type C is new Ada.Finalization.Controlled with null record;
>        type Cs is array (Natural range <>) of C;
>        type Csp is access Cs with Storage_Pool => Pool;

Now define and implement the following function:

    function Get_Allocation_Time (Pointer : Csp) return Time;

The function returns the time when the pointed object was allocated in 
the pool.

[...]

> Mind, I don't quite see how to actually access the header info for a
> particular allocation ...

By subtracting a fixed offset from Pointer.all'Address. The offset is to 
be determined, because X'Address lies.

-- 
Regards,
Dmitry A. Kazakov
http://www.dmitry-kazakov.de

^ permalink raw reply	[flat|nested] 62+ messages in thread

* Re: Custom Storage Pool questions
  2021-09-15 19:07   ` Dmitry A. Kazakov
@ 2021-09-15 20:40     ` Simon Wright
  2021-09-16  7:12       ` Emmanuel Briot
  2021-09-16  8:41       ` Dmitry A. Kazakov
  0 siblings, 2 replies; 62+ messages in thread
From: Simon Wright @ 2021-09-15 20:40 UTC (permalink / raw)


"Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> writes:

>> Mind, I don't quite see how to actually access the header info for a
>> particular allocation ...
>
> By subtracting a fixed offset from Pointer.all'Address. The offset is
> to be determined, because X'Address lies.

Obvs.

But my main point was, the blog which was Jere's original problem is in
fact (now?) wrong.

Anyway, the Gnatcoll solution is here ...
https://github.com/AdaCore/gnatcoll-core/blob/master/src/gnatcoll-storage_pools-headers.adb#L114

^ permalink raw reply	[flat|nested] 62+ messages in thread

* Re: Custom Storage Pool questions
  2021-09-15 20:40     ` Simon Wright
@ 2021-09-16  7:12       ` Emmanuel Briot
  2021-09-16 23:21         ` Jere
  2021-09-16  8:41       ` Dmitry A. Kazakov
  1 sibling, 1 reply; 62+ messages in thread
From: Emmanuel Briot @ 2021-09-16  7:12 UTC (permalink / raw)


I am the original implementor of GNATCOLL.Storage_Pools.Headers, and I have been silent in this discussion because I must admit I forgot a lot of the details... To be sure, we did not add new attributes just for the sake of GNATCOLL, those existed previously so likely had already found other uses.

As has been mentioned several time in the discussion, the compiler is already passing the full size it needs to Allocate, and the storage pool only needs to allocate that exact amount in general. This applies for the usual kinds of storage pools, which would for instance preallocate a pool for objects of fixed sizes, or add stronger alignment requirements.

In the case of the GNATCOLL headers pool, we need to allocate more because the user wants to store extra data. For that data, we are left on our own to find the number of bytes we need, which is part of the computation we do: we of course need the number of bytes for the header's object_size, but also perhaps some extra bytes that are not returned by that object_size in particular for controlled types and arrays.
Note again that those additional bytes are for the header type, not for the type the user is allocating (for which, again, the compiler already passes the number of bytes it needs).

The next difficulty is then to convert from the object's 'Address back to your extra header data. This is when you need to know the size of the prefix added by the compiler (array bounds, tag,...) to skip them and then take into account the alignment, and finally the size of your header.
Dmitry's suggested exercice (storing the timestamp of the allocation) seems like a useful one indeed. It would be nice indeed if GNATCOLL's code was too complicated, but I am afraid this isn't the case. We had used those pools to implement reference counting for various complex types, and ended up with that complexity.

AdaCore (Olivier Hainque) has made a change to the implementation since the blog was published (https://github.com/AdaCore/gnatcoll-core/commits/master/src/gnatcoll-storage_pools-headers.adb), so I got some details wrong in the initial implementation apparently.

Emmanuel

^ permalink raw reply	[flat|nested] 62+ messages in thread

* Re: Custom Storage Pool questions
  2021-09-15 20:40     ` Simon Wright
  2021-09-16  7:12       ` Emmanuel Briot
@ 2021-09-16  8:41       ` Dmitry A. Kazakov
  1 sibling, 0 replies; 62+ messages in thread
From: Dmitry A. Kazakov @ 2021-09-16  8:41 UTC (permalink / raw)


On 2021-09-15 22:40, Simon Wright wrote:

> But my main point was, the blog which was Jere's original problem is in
> fact (now?) wrong.

Right, when nothing to be added to the allocated object, there is 
nothing to worry about.

-- 
Regards,
Dmitry A. Kazakov
http://www.dmitry-kazakov.de

^ permalink raw reply	[flat|nested] 62+ messages in thread

* Re: Custom Storage Pool questions
  2021-09-16  7:12       ` Emmanuel Briot
@ 2021-09-16 23:21         ` Jere
  2021-09-17  7:08           ` Emmanuel Briot
                             ` (2 more replies)
  0 siblings, 3 replies; 62+ messages in thread
From: Jere @ 2021-09-16 23:21 UTC (permalink / raw)


On Thursday, September 16, 2021 at 3:13:00 AM UTC-4, Emmanuel wrote:
> In the case of the GNATCOLL headers pool, we need to allocate more because the user wants to store extra data. For that data, we are left on our own to find the number of bytes we need, which is part of the computation we do: we of course need the number of bytes for the header's object_size, but also perhaps some extra bytes that are not returned by that object_size in particular for controlled types and arrays. 
> Note again that those additional bytes are for the header type, not for the type the user is allocating (for which, again, the compiler already passes the number of bytes it needs). 
> 
> <SNIPEED>
> Emmanuel

Thanks for the response Emmanuel.  That clears it up for me.  I think the confusion for me 
came from the terminology used then.  In the blog, that extra space for First/Last and Prev/Next 
was mentioned as if it were for the element, which I mistook was the user's object being allocated 
and not the header portion.  I didn't catch that as the generic formal's name, so that is my mistake.  
I guess in my head, I would have expected the formal name to be Header_Type or similar so I
misread it in my haste.

I appreciate the clarity and apologize if I caused too much of a stir.  I was asking the question 
because I didn't understand, so I hope you don't think too poorly of me for it, despite my mistake.

^ permalink raw reply	[flat|nested] 62+ messages in thread

* Re: Custom Storage Pool questions
  2021-09-15  7:01         ` Simon Wright
@ 2021-09-16 23:32           ` Jere
  2021-09-20 23:51             ` Randy Brukardt
  0 siblings, 1 reply; 62+ messages in thread
From: Jere @ 2021-09-16 23:32 UTC (permalink / raw)


On Wednesday, September 15, 2021 at 3:01:52 AM UTC-4, Simon Wright wrote:
> Jere <> writes: 
> 
> > Thanks for the response. I'm sorry for all the questions. That's how 
> > I learn and I realize it isn't a popular way to learn in the 
> > community, but I have always learned very differently than most.
> Seems to me you ask interesting questions which generate enlightening 
> responses!
Thanks!  though in this case, my question was ill formed after I missed a detail 
in the blog, so the mistake is on me.  I will say I hold back some questions 
as it is very intimidating to ask on C.L.A.  I mean the first response led off 
with "Not sure what you are expecting" so it is hard to know how to formulate
a good question as I always seem to get some harsh responses (which I am 
sure is because I asked the question poorly).  I'm unfortunately a very visual
person and words are not my forte and I feel like when I ask questions about
the boundaries of the language I manage to put folks on the defensive.  I 
don't dislike Ada at all, it is my favorite language, but I think it is hard to 
craft questions on some topics without putting forth the impression that 
I don't like it, at least with my limited ability to word craft.  

^ permalink raw reply	[flat|nested] 62+ messages in thread

* Re: Custom Storage Pool questions
  2021-09-16 23:21         ` Jere
@ 2021-09-17  7:08           ` Emmanuel Briot
  2021-09-17  7:18           ` Simon Wright
  2021-09-17 13:56           ` Dmitry A. Kazakov
  2 siblings, 0 replies; 62+ messages in thread
From: Emmanuel Briot @ 2021-09-17  7:08 UTC (permalink / raw)


> Thanks for the response Emmanuel. That clears it up for me. I think the confusion for me 
> came from the terminology used then. In the blog, that extra space for First/Last and Prev/Next 
> was mentioned as if it were for the element, which I mistook was the user's object being allocated 
> and not the header portion. I didn't catch that as the generic formal's name, so that is my mistake. 
> I guess in my head, I would have expected the formal name to be Header_Type or similar so I 
> misread it in my haste. 

Sure, and maybe the blog was not as readable as it should have been. Unfortunately I no longer have
any possibility to amend it, so I guess we'll live with it !

Thanks for the questions

Emmanuel

^ permalink raw reply	[flat|nested] 62+ messages in thread

* Re: Custom Storage Pool questions
  2021-09-16 23:21         ` Jere
  2021-09-17  7:08           ` Emmanuel Briot
@ 2021-09-17  7:18           ` Simon Wright
  2021-09-17 13:56           ` Dmitry A. Kazakov
  2 siblings, 0 replies; 62+ messages in thread
From: Simon Wright @ 2021-09-17  7:18 UTC (permalink / raw)


Jere <jhb.chat@gmail.com> writes:

> On Thursday, September 16, 2021 at 3:13:00 AM UTC-4, Emmanuel wrote:
>> In the case of the GNATCOLL headers pool, we need to allocate more
>> because the user wants to store extra data. For that data, we are
>> left on our own to find the number of bytes we need, which is part of
>> the computation we do: we of course need the number of bytes for the
>> header's object_size, but also perhaps some extra bytes that are not
>> returned by that object_size in particular for controlled types and
>> arrays.
>> Note again that those additional bytes are for the header type, not
>> for the type the user is allocating (for which, again, the compiler
>> already passes the number of bytes it needs).

> Thanks for the response Emmanuel.  That clears it up for me.  I think
> the confusion for me came from the terminology used then.  In the
> blog, that extra space for First/Last and Prev/Next was mentioned as
> if it were for the element, which I mistook was the user's object
> being allocated and not the header portion.  I didn't catch that as
> the generic formal's name, so that is my mistake.

Given this diagram from the blog, you can hardly be blamed (says a
person who leapt to the same conclusion):
 
 +--------+-------+------+----------+------+---------+
 | Header | First | Last | Previous | Next | Element |
 +--------+-------+------+----------+------+---------+

^ permalink raw reply	[flat|nested] 62+ messages in thread

* Re: Custom Storage Pool questions
  2021-09-16 23:21         ` Jere
  2021-09-17  7:08           ` Emmanuel Briot
  2021-09-17  7:18           ` Simon Wright
@ 2021-09-17 13:56           ` Dmitry A. Kazakov
  2021-09-17 19:46             ` Simon Wright
  2 siblings, 1 reply; 62+ messages in thread
From: Dmitry A. Kazakov @ 2021-09-17 13:56 UTC (permalink / raw)


On 2021-09-17 01:21, Jere wrote:

> I appreciate the clarity and apologize if I caused too much of a stir.

It is not that we have huge traffic in c.l.a.

> I was asking the question
> because I didn't understand, so I hope you don't think too poorly of me for it, despite my mistake.

Nope, especially because the issue with X'Address being unusable for 
memory pool developers is a long standing painful problem that need to 
be resolved. That will never happen until a measurable group of people 
start asking questions. So you are doubly welcome.

-- 
Regards,
Dmitry A. Kazakov
http://www.dmitry-kazakov.de

^ permalink raw reply	[flat|nested] 62+ messages in thread

* Re: Custom Storage Pool questions
  2021-09-17 13:56           ` Dmitry A. Kazakov
@ 2021-09-17 19:46             ` Simon Wright
  2021-09-17 20:39               ` Dmitry A. Kazakov
  0 siblings, 1 reply; 62+ messages in thread
From: Simon Wright @ 2021-09-17 19:46 UTC (permalink / raw)


"Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> writes:

> Nope, especially because the issue with X'Address being unusable for
> memory pool developers is a long standing painful problem that need to
> be resolved. That will never happen until a measurable group of people
> start asking questions. So you are doubly welcome.

There are two attributes that we should all have known about,
Descriptor_Size[1] (bits, introduced in 2011) and Finalization_Size[2]
(storage units, I think, introduced in 2017)

[1]
https://docs.adacore.com/live/wave/gnat_rm/html/gnat_rm/gnat_rm/implementation_defined_attributes.html#attribute-descriptor-size
[2]
https://docs.adacore.com/live/wave/gnat_rm/html/gnat_rm/gnat_rm/implementation_defined_attributes.html#attribute-finalization-size

^ permalink raw reply	[flat|nested] 62+ messages in thread

* Re: Custom Storage Pool questions
  2021-09-17 19:46             ` Simon Wright
@ 2021-09-17 20:39               ` Dmitry A. Kazakov
  2021-09-17 21:17                 ` Niklas Holsti
  2021-09-21  0:18                 ` Randy Brukardt
  0 siblings, 2 replies; 62+ messages in thread
From: Dmitry A. Kazakov @ 2021-09-17 20:39 UTC (permalink / raw)


On 2021-09-17 21:46, Simon Wright wrote:
> "Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> writes:
> 
>> Nope, especially because the issue with X'Address being unusable for
>> memory pool developers is a long standing painful problem that need to
>> be resolved. That will never happen until a measurable group of people
>> start asking questions. So you are doubly welcome.
> 
> There are two attributes that we should all have known about,
> Descriptor_Size[1] (bits, introduced in 2011) and Finalization_Size[2]
> (storage units, I think, introduced in 2017)

They are non-standard and have murky semantics I doubt anybody really 
cares about.

What is needed is the address passed to Deallocate should the object be 
freed = the address returned by Allocate. Is that too much to ask?

BTW, finalization lists (#2) should have been removed from the language 
long ago. They have absolutely no use, except maybe for debugging, and 
introduce huge overhead. The semantics should have been either 
Unchecked_Deallocation or compiler allocated objects/components may call 
Finalize, nothing else.

-- 
Regards,
Dmitry A. Kazakov
http://www.dmitry-kazakov.de

^ permalink raw reply	[flat|nested] 62+ messages in thread

* Re: Custom Storage Pool questions
  2021-09-17 20:39               ` Dmitry A. Kazakov
@ 2021-09-17 21:17                 ` Niklas Holsti
  2021-09-18  7:49                   ` Dmitry A. Kazakov
  2021-09-21  0:18                 ` Randy Brukardt
  1 sibling, 1 reply; 62+ messages in thread
From: Niklas Holsti @ 2021-09-17 21:17 UTC (permalink / raw)


On 2021-09-17 23:39, Dmitry A. Kazakov wrote:
> On 2021-09-17 21:46, Simon Wright wrote:
>> "Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> writes:
>>
>>> Nope, especially because the issue with X'Address being unusable for
>>> memory pool developers is a long standing painful problem that need to
>>> be resolved. That will never happen until a measurable group of people
>>> start asking questions. So you are doubly welcome.
>>
>> There are two attributes that we should all have known about,
>> Descriptor_Size[1] (bits, introduced in 2011) and Finalization_Size[2]
>> (storage units, I think, introduced in 2017)
> 
> They are non-standard and have murky semantics I doubt anybody really 
> cares about.
> 
> What is needed is the address passed to Deallocate should the object be 
> freed = the address returned by Allocate. Is that too much to ask?


That is already required by RM 13.11(21.7/3): "The value of the 
Storage_Address parameter for a call to Deallocate is the value returned 
in the Storage_Address parameter of the corresponding successful call to 
Allocate."

The "size" parameters are also required to be the same in the calls to 
Deallocate and to Allocate.


> BTW, finalization lists (#2) should have been removed from the language 
> long ago. 


Huh? Where does the RM _require_ finalization lists? I see them 
mentioned here and there as a _possible_ implementation technique, and 
an alternative "PC-map" technique is described in RM 7.6.1 (24.r .. 24.t).

^ permalink raw reply	[flat|nested] 62+ messages in thread

* Re: Custom Storage Pool questions
  2021-09-17 21:17                 ` Niklas Holsti
@ 2021-09-18  7:49                   ` Dmitry A. Kazakov
  2021-09-18  9:03                     ` Niklas Holsti
  2021-09-21  0:19                     ` Randy Brukardt
  0 siblings, 2 replies; 62+ messages in thread
From: Dmitry A. Kazakov @ 2021-09-18  7:49 UTC (permalink / raw)


On 2021-09-17 23:17, Niklas Holsti wrote:
> On 2021-09-17 23:39, Dmitry A. Kazakov wrote:
>> On 2021-09-17 21:46, Simon Wright wrote:
>>> "Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> writes:
>>>
>>>> Nope, especially because the issue with X'Address being unusable for
>>>> memory pool developers is a long standing painful problem that need to
>>>> be resolved. That will never happen until a measurable group of people
>>>> start asking questions. So you are doubly welcome.
>>>
>>> There are two attributes that we should all have known about,
>>> Descriptor_Size[1] (bits, introduced in 2011) and Finalization_Size[2]
>>> (storage units, I think, introduced in 2017)
>>
>> They are non-standard and have murky semantics I doubt anybody really 
>> cares about.
>>
>> What is needed is the address passed to Deallocate should the object 
>> be freed = the address returned by Allocate. Is that too much to ask?
> 
> That is already required by RM 13.11(21.7/3): "The value of the 
> Storage_Address parameter for a call to Deallocate is the value returned 
> in the Storage_Address parameter of the corresponding successful call to 
> Allocate."

You missed the discussion totally. It is about X'Address attribute.

The challenge: write pool with a function returning object allocation 
time by its pool-specific access type.

>> BTW, finalization lists (#2) should have been removed from the 
>> language long ago. 
> 
> Huh? Where does the RM _require_ finalization lists?

7.6.1 (11 1/3)

> I see them 
> mentioned here and there as a _possible_ implementation technique, and 
> an alternative "PC-map" technique is described in RM 7.6.1 (24.r .. 24.t).

I don't care about techniques to implement meaningless stuff. It should 
be out, at least there must be a representation aspect for turning this 
mess off.

-- 
Regards,
Dmitry A. Kazakov
http://www.dmitry-kazakov.de

^ permalink raw reply	[flat|nested] 62+ messages in thread

* Re: Custom Storage Pool questions
  2021-09-18  7:49                   ` Dmitry A. Kazakov
@ 2021-09-18  9:03                     ` Niklas Holsti
  2021-09-18 10:22                       ` Dmitry A. Kazakov
  2021-09-21  0:19                     ` Randy Brukardt
  1 sibling, 1 reply; 62+ messages in thread
From: Niklas Holsti @ 2021-09-18  9:03 UTC (permalink / raw)


On 2021-09-18 10:49, Dmitry A. Kazakov wrote:
> On 2021-09-17 23:17, Niklas Holsti wrote:
>> On 2021-09-17 23:39, Dmitry A. Kazakov wrote:
>>> On 2021-09-17 21:46, Simon Wright wrote:
>>>> "Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> writes:
>>>>
>>>>> Nope, especially because the issue with X'Address being unusable for
>>>>> memory pool developers is a long standing painful problem that need to
>>>>> be resolved. That will never happen until a measurable group of people
>>>>> start asking questions. So you are doubly welcome.
>>>>
>>>> There are two attributes that we should all have known about,
>>>> Descriptor_Size[1] (bits, introduced in 2011) and Finalization_Size[2]
>>>> (storage units, I think, introduced in 2017)
>>>
>>> They are non-standard and have murky semantics I doubt anybody really 
>>> cares about.
>>>
>>> What is needed is the address passed to Deallocate should the object 
>>> be freed = the address returned by Allocate. Is that too much to ask?
>>
>> That is already required by RM 13.11(21.7/3): "The value of the 
>> Storage_Address parameter for a call to Deallocate is the value 
>> returned in the Storage_Address parameter of the corresponding 
>> successful call to Allocate."
> 
> You missed the discussion totally. It is about X'Address attribute.


Sure, I understand that the address returned by Allocate, and passed to 
Deallocate, for an object X, is not always X'Address, and that you would 
like some means to get the Allocate/Deallocate address from (an access 
to) X. But what you stated as not "too much to ask" is specifically 
required in the RM paragraph I quoted. Perhaps you meant to state 
something else, about X'Address or some other attribute, but that was 
not what you wrote.

Given that an object can be allocated in multiple independent pieces, it 
seems unlikely that what you want will be provided. You would need some 
way of iterating over all the pieces allocated for a given object, or 
some way of defining a "main" or "prime" piece and a means to get the 
Allocate/Deallocate address for that piece.


>>> BTW, finalization lists (#2) should have been removed from the 
>>> language long ago. 
>>
>> Huh? Where does the RM _require_ finalization lists?
> 
> 7.6.1 (11 1/3)


RM (2012) 7.6.1 (11.1/3) says only that objects must be finalized in 
reverse order of their creation. There is no mention of "list".


>> I see them mentioned here and there as a _possible_ implementation 
>> technique, and an alternative "PC-map" technique is described in RM 
>> 7.6.1 (24.r .. 24.t).
> 
> I don't care about techniques to implement meaningless stuff. It should 
> be out, at least there must be a representation aspect for turning this 
> mess off.


Then your complaint seems to be about something specified for the order 
of finalization, but you haven't said clearly what that something is.

^ permalink raw reply	[flat|nested] 62+ messages in thread

* Re: Custom Storage Pool questions
  2021-09-18  9:03                     ` Niklas Holsti
@ 2021-09-18 10:22                       ` Dmitry A. Kazakov
  2021-09-18 15:59                         ` Niklas Holsti
  2021-09-21  0:26                         ` Randy Brukardt
  0 siblings, 2 replies; 62+ messages in thread
From: Dmitry A. Kazakov @ 2021-09-18 10:22 UTC (permalink / raw)


On 2021-09-18 11:03, Niklas Holsti wrote:
> On 2021-09-18 10:49, Dmitry A. Kazakov wrote:
>> On 2021-09-17 23:17, Niklas Holsti wrote:
>>> On 2021-09-17 23:39, Dmitry A. Kazakov wrote:
>>>> On 2021-09-17 21:46, Simon Wright wrote:
>>>>> "Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> writes:
>>>>>
>>>>>> Nope, especially because the issue with X'Address being unusable for
>>>>>> memory pool developers is a long standing painful problem that 
>>>>>> need to
>>>>>> be resolved. That will never happen until a measurable group of 
>>>>>> people
>>>>>> start asking questions. So you are doubly welcome.
>>>>>
>>>>> There are two attributes that we should all have known about,
>>>>> Descriptor_Size[1] (bits, introduced in 2011) and Finalization_Size[2]
>>>>> (storage units, I think, introduced in 2017)
>>>>
>>>> They are non-standard and have murky semantics I doubt anybody 
>>>> really cares about.
>>>>
>>>> What is needed is the address passed to Deallocate should the object 
>>>> be freed = the address returned by Allocate. Is that too much to ask?
>>>
>>> That is already required by RM 13.11(21.7/3): "The value of the 
>>> Storage_Address parameter for a call to Deallocate is the value 
>>> returned in the Storage_Address parameter of the corresponding 
>>> successful call to Allocate."
>>
>> You missed the discussion totally. It is about X'Address attribute.
> 
> 
> Sure, I understand that the address returned by Allocate, and passed to 
> Deallocate, for an object X, is not always X'Address, and that you would 
> like some means to get the Allocate/Deallocate address from (an access 
> to) X. But what you stated as not "too much to ask" is specifically 
> required in the RM paragraph I quoted. Perhaps you meant to state 
> something else, about X'Address or some other attribute, but that was 
> not what you wrote.

I wrote about attributes, specifically GNAT-specific ones used in the 
blog to calculate the correct address. "Too much to ask" was about an 
attribute that would return the object address directly.

> Given that an object can be allocated in multiple independent pieces, it 
> seems unlikely that what you want will be provided.

Such implementations would automatically disqualify the compiler. 
Compiler-generated piecewise allocation is OK for the stack, not for 
user storage pools.

And anyway, all this equally applies to X'Address.

>>>> BTW, finalization lists (#2) should have been removed from the 
>>>> language long ago. 
>>>
>>> Huh? Where does the RM _require_ finalization lists?
>>
>> 7.6.1 (11 1/3)
> 
> 
> RM (2012) 7.6.1 (11.1/3) says only that objects must be finalized in 
> reverse order of their creation. There is no mention of "list".

It talks about "collection."

> Then your complaint seems to be about something specified for the order 
> of finalization, but you haven't said clearly what that something is.

No, it is about the overhead of maintaining "collections" associated 
with an access type in order to call Finalization for all members of the 
collection.

-- 
Regards,
Dmitry A. Kazakov
http://www.dmitry-kazakov.de

^ permalink raw reply	[flat|nested] 62+ messages in thread

* Re: Custom Storage Pool questions
  2021-09-13  5:29 ` Randy Brukardt
  2021-09-14  1:04   ` Jere
@ 2021-09-18 11:32   ` Simon Wright
  2021-09-20  0:31   ` Jere
  2 siblings, 0 replies; 62+ messages in thread
From: Simon Wright @ 2021-09-18 11:32 UTC (permalink / raw)


"Randy Brukardt" <randy@rrsoftware.com> writes:

> Not sure what you are expecting. There is no requirement that objects
> are allocated contigiously. Indeed, Janus/Ada will call Allocate as
> many times as needed for each object; for instance, unconstrained
> arrays are in two parts (descriptor and data area).

The referenced blog[1] says

    "As we mentioned before, we need to ensure that the bounds for
    unconstrained arrays are stored next to the element, not in a
    separate memory block, to improve performance. This is done by
    setting the Size attribute on the type. When we set this size to
    that of a standard pointer, GNAT automatically changes the layout,
    so that we now have:

     +-------+------+---------+
     | First | Last | Element |
     +-------+------+---------+

I _think_ I was aware of this before, in fact I remember using it, but
not where! Is it documented anywhere?

[1] https://blog.adacore.com/header-storage-pools

^ permalink raw reply	[flat|nested] 62+ messages in thread

* Re: Custom Storage Pool questions
  2021-09-18 10:22                       ` Dmitry A. Kazakov
@ 2021-09-18 15:59                         ` Niklas Holsti
  2021-09-18 16:19                           ` Dmitry A. Kazakov
  2021-09-21  0:26                         ` Randy Brukardt
  1 sibling, 1 reply; 62+ messages in thread
From: Niklas Holsti @ 2021-09-18 15:59 UTC (permalink / raw)


On 2021-09-18 13:22, Dmitry A. Kazakov wrote:
> On 2021-09-18 11:03, Niklas Holsti wrote:
>> On 2021-09-18 10:49, Dmitry A. Kazakov wrote:
>>> On 2021-09-17 23:17, Niklas Holsti wrote:
>>>> On 2021-09-17 23:39, Dmitry A. Kazakov wrote:
>>>>> On 2021-09-17 21:46, Simon Wright wrote:
>>>>>> "Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> writes:
>>>>>>
>>>>>>> Nope, especially because the issue with X'Address being unusable for
>>>>>>> memory pool developers is a long standing painful problem that 
>>>>>>> need to
>>>>>>> be resolved. That will never happen until a measurable group of 
>>>>>>> people
>>>>>>> start asking questions. So you are doubly welcome.
>>>>>>
>>>>>> There are two attributes that we should all have known about,
>>>>>> Descriptor_Size[1] (bits, introduced in 2011) and 
>>>>>> Finalization_Size[2]
>>>>>> (storage units, I think, introduced in 2017)
>>>>>
>>>>> They are non-standard and have murky semantics I doubt anybody 
>>>>> really cares about.
>>>>>
>>>>> What is needed is the address passed to Deallocate should the 
>>>>> object be freed = the address returned by Allocate. Is that too 
>>>>> much to ask?
>>>>
>>>> That is already required by RM 13.11(21.7/3): "The value of the 
>>>> Storage_Address parameter for a call to Deallocate is the value 
>>>> returned in the Storage_Address parameter of the corresponding 
>>>> successful call to Allocate."
>>>
>>> You missed the discussion totally. It is about X'Address attribute.
>>
>>
>> Sure, I understand that the address returned by Allocate, and passed 
>> to Deallocate, for an object X, is not always X'Address, and that you 
>> would like some means to get the Allocate/Deallocate address from (an 
>> access to) X. But what you stated as not "too much to ask" is 
>> specifically required in the RM paragraph I quoted. Perhaps you meant 
>> to state something else, about X'Address or some other attribute, but 
>> that was not what you wrote.
> 
> I wrote about attributes, specifically GNAT-specific ones used in the 
> blog to calculate the correct address.


You wrote about the attributes in an earlier paragraph, not the one that 
said "too much to ask" -- see the quotes above. But ok, enough said.


> "Too much to ask" was about an 
> attribute that would return the object address directly.
> 
>> Given that an object can be allocated in multiple independent pieces, 
>> it seems unlikely that what you want will be provided.
> 
> Such implementations would automatically disqualify the compiler. 
> Compiler-generated piecewise allocation is OK for the stack, not for 
> user storage pools.


That is your opinion (or need), to which you are entitled, of course, 
but it is not an RM requirement on compilers -- see Randy's posts about 
what Janus/Ada does.


>>>>> BTW, finalization lists (#2) should have been removed from the 
>>>>> language long ago. 
>>>>
>>>> Huh? Where does the RM _require_ finalization lists?
>>>
>>> 7.6.1 (11 1/3)
>>
>>
>> RM (2012) 7.6.1 (11.1/3) says only that objects must be finalized in 
>> reverse order of their creation. 


Oops, I quoted the above from 7.6.1 (11/3), which specifies the order of 
finalization in another case (finalization of a master). RM 7.6.1 
(11.1/3) leaves the order arbitrary for the finalization of a collection.


>> There is no mention of "list".
> 
> It talks about "collection."
> 
>> Then your complaint seems to be about something specified for the 
>> order of finalization, but you haven't said clearly what that 
>> something is.
> 
> No, it is about the overhead of maintaining "collections" associated 
> with an access type in order to call Finalization for all members of the 
> collection.


So you want a way to specify that for a given access type, although the 
accessed object type has a Finalize operation or needs finalization, the 
objects left over in the (at least conceptually) associated collection 
should _not_ be finalized when the scope of the access type is left? 
Have you proposed this to the ARG?

To me it seems a risky think to do, subverting the normal semantics of 
initialization and finalization. Perhaps it could be motivated for 
library-level collections in programs that are known to never terminate 
(that is, to not need any clean-up when they do stop or are stopped).

^ permalink raw reply	[flat|nested] 62+ messages in thread

* Re: Custom Storage Pool questions
  2021-09-18 15:59                         ` Niklas Holsti
@ 2021-09-18 16:19                           ` Dmitry A. Kazakov
  2021-09-19 10:36                             ` Niklas Holsti
  0 siblings, 1 reply; 62+ messages in thread
From: Dmitry A. Kazakov @ 2021-09-18 16:19 UTC (permalink / raw)


On 2021-09-18 17:59, Niklas Holsti wrote:

> So you want a way to specify that for a given access type, although the 
> accessed object type has a Finalize operation or needs finalization, the 
> objects left over in the (at least conceptually) associated collection 
> should _not_ be finalized when the scope of the access type is left?

Exactly, especially because these objects are not deallocated, as you 
say they are left over. If they wanted GC they should do that. If they 
do not, then they should keep their hands off the objects maintained by 
the programmer.

> To me it seems a risky think to do, subverting the normal semantics of 
> initialization and finalization.

Quite the opposite, it is the collection rule that subverts semantics 
because objects are not freed, yet mangled.

-- 
Regards,
Dmitry A. Kazakov
http://www.dmitry-kazakov.de

^ permalink raw reply	[flat|nested] 62+ messages in thread

* Re: Custom Storage Pool questions
  2021-09-18 16:19                           ` Dmitry A. Kazakov
@ 2021-09-19 10:36                             ` Niklas Holsti
  2021-09-19 11:41                               ` Dmitry A. Kazakov
  0 siblings, 1 reply; 62+ messages in thread
From: Niklas Holsti @ 2021-09-19 10:36 UTC (permalink / raw)


On 2021-09-18 19:19, Dmitry A. Kazakov wrote:
> On 2021-09-18 17:59, Niklas Holsti wrote:
> 
>> So you want a way to specify that for a given access type, although 
>> the accessed object type has a Finalize operation or needs 
>> finalization, the objects left over in the (at least conceptually) 
>> associated collection should _not_ be finalized when the scope of the 
>> access type is left?
> 
> Exactly, especially because these objects are not deallocated, as you 
> say they are left over. If they wanted GC they should do that. If they 
> do not, then they should keep their hands off the objects maintained by 
> the programmer.
> 
>> To me it seems a risky think to do, subverting the normal semantics of 
>> initialization and finalization.
> 
> Quite the opposite, it is the collection rule that subverts semantics 
> because objects are not freed, yet mangled.


Local variables declared in a subprogram are also not explicitly freed 
(deallocated), yet they are automatically finalized when the subprogram 
returns.

My understanding of Ada semantic principles is that any object that is 
initialized should also be finalized. Since the objects left in a 
collection associated with a local access type become inaccessible when 
the scope of the access type is left, finalizing them automatically, 
even without an explicit free, makes sense to me. If you disagree, 
suggest a change to the ARG and see if you can find supporters.

Has this feature of Ada caused you real problems in real applications, 
or is it only a point of principle for you?

^ permalink raw reply	[flat|nested] 62+ messages in thread

* Re: Custom Storage Pool questions
  2021-09-19 10:36                             ` Niklas Holsti
@ 2021-09-19 11:41                               ` Dmitry A. Kazakov
  2021-09-20  7:05                                 ` Niklas Holsti
                                                   ` (2 more replies)
  0 siblings, 3 replies; 62+ messages in thread
From: Dmitry A. Kazakov @ 2021-09-19 11:41 UTC (permalink / raw)


On 2021-09-19 12:36, Niklas Holsti wrote:
> On 2021-09-18 19:19, Dmitry A. Kazakov wrote:
>> On 2021-09-18 17:59, Niklas Holsti wrote:
>>
>>> So you want a way to specify that for a given access type, although 
>>> the accessed object type has a Finalize operation or needs 
>>> finalization, the objects left over in the (at least conceptually) 
>>> associated collection should _not_ be finalized when the scope of the 
>>> access type is left?
>>
>> Exactly, especially because these objects are not deallocated, as you 
>> say they are left over. If they wanted GC they should do that. If they 
>> do not, then they should keep their hands off the objects maintained 
>> by the programmer.
>>
>>> To me it seems a risky think to do, subverting the normal semantics 
>>> of initialization and finalization.
>>
>> Quite the opposite, it is the collection rule that subverts semantics 
>> because objects are not freed, yet mangled.
> 
> Local variables declared in a subprogram are also not explicitly freed 
> (deallocated), yet they are automatically finalized when the subprogram 
> returns.

Local objects are certainly freed. Explicit or not, aggregated or not, 
is irrelevant.

> My understanding of Ada semantic principles is that any object that is 
> initialized should also be finalized.

IFF deallocated.

An application that runs continuously will never deallocate, HENCE 
finalize certain objects.

> Has this feature of Ada caused you real problems in real applications, 
> or is it only a point of principle for you?

1. It is a massive overhead in both memory and performance terms with no 
purpose whatsoever. I fail to see where that sort of thing might be even 
marginally useful. Specialized pools, e.g. mark-and-release will deploy 
their own bookkeeping, not rely on this.

2. What is worse that a collection is not bound to the pool. It is to an 
access type, which may have a narrower scope. So the user could declare 
an unfortunate access type, which would corrupt objects in the pool and 
the pool designer has no means to prevent that.

-- 
Regards,
Dmitry A. Kazakov
http://www.dmitry-kazakov.de

^ permalink raw reply	[flat|nested] 62+ messages in thread

* Re: Custom Storage Pool questions
  2021-09-13  5:29 ` Randy Brukardt
  2021-09-14  1:04   ` Jere
  2021-09-18 11:32   ` Simon Wright
@ 2021-09-20  0:31   ` Jere
  2021-09-20  6:34     ` Niklas Holsti
  2 siblings, 1 reply; 62+ messages in thread
From: Jere @ 2021-09-20  0:31 UTC (permalink / raw)


Followup question cause Randy's statement (below) got me thinking:
If a compiler is allowed to break up an allocation into multiple
calls to Allocate (and of course Deallocate), how does one go about
enforcing that the user's header is only created once?  In the example
Randy gave (unconstrained arrays), in Janus there is an allocation for the 
descriptor and a separate allocation for the data.  If I am making a storage
pool that is intending to create a hidden header for my objects, this means
in Janus Ada (and potentially other compilers) I would instead create two
headers, one for the descriptor and one for the data, when I might intend
to have one header for the entire object. 

On Monday, September 13, 2021 at 1:29:39 AM UTC-4, Randy Brukardt wrote:
> Not sure what you are expecting. There is no requirement that objects are 
> allocated contigiously. Indeed, Janus/Ada will call Allocate as many times 
> as needed for each object; for instance, unconstrained arrays are in two 
> parts (descriptor and data area). 
> 
> <SNIPPED>
> 
> Randy. 
> 
> 
> "Jere" <> wrote in message 
> news:e3c5c553-4a7f-408a...@googlegroups.com...
> >I was learning about making user defined storage pools when 
> > I came across an article that made me pause and wonder how 
> > portable storage pools actually can be. In particular, I assumed 
> > that the Size_In_Storage_Elements parameter in the Allocate 
> > operation actually indicated the total number of storage elements 
> > needed. 
> > 
> > <SNIPPED>
> > 

^ permalink raw reply	[flat|nested] 62+ messages in thread

* Re: Custom Storage Pool questions
  2021-09-20  0:31   ` Jere
@ 2021-09-20  6:34     ` Niklas Holsti
  2021-09-20  6:48       ` Emmanuel Briot
  0 siblings, 1 reply; 62+ messages in thread
From: Niklas Holsti @ 2021-09-20  6:34 UTC (permalink / raw)


On 2021-09-20 3:31, Jere wrote:
> Followup question cause Randy's statement (below) got me thinking:
> If a compiler is allowed to break up an allocation into multiple
> calls to Allocate (and of course Deallocate), how does one go about
> enforcing that the user's header is only created once?


I think one cannot enforce that, because the calls to Allocate do not 
indicate (with parameters) which set of calls concern the same object 
allocation.

This is probably why Dmitry said that such compiler behaviour would 
"disqualify the compiler" for his uses.

^ permalink raw reply	[flat|nested] 62+ messages in thread

* Re: Custom Storage Pool questions
  2021-09-20  6:34     ` Niklas Holsti
@ 2021-09-20  6:48       ` Emmanuel Briot
  2021-09-20  7:35         ` Dmitry A. Kazakov
                           ` (2 more replies)
  0 siblings, 3 replies; 62+ messages in thread
From: Emmanuel Briot @ 2021-09-20  6:48 UTC (permalink / raw)


> > If a compiler is allowed to break up an allocation into multiple 
> > calls to Allocate (and of course Deallocate), how does one go about 
> > enforcing that the user's header is only created once?
> I think one cannot enforce that, because the calls to Allocate do not 
> indicate (with parameters) which set of calls concern the same object 
> allocation. 

I think the only solution would be for this compiler to have another attribute similar to 'Storage_Pool, but that would define the pool for the  descriptor:

    for X'Storage_Pool use Pool;
    for X'Descriptor_Storage_Pool use Other_Pool;

That way the user can decide when to add (or not) extra headers.

^ permalink raw reply	[flat|nested] 62+ messages in thread

* Re: Custom Storage Pool questions
  2021-09-19 11:41                               ` Dmitry A. Kazakov
@ 2021-09-20  7:05                                 ` Niklas Holsti
  2021-09-20  7:35                                   ` Dmitry A. Kazakov
  2021-09-21  0:30                                 ` Randy Brukardt
  2021-09-21  0:37                                 ` Randy Brukardt
  2 siblings, 1 reply; 62+ messages in thread
From: Niklas Holsti @ 2021-09-20  7:05 UTC (permalink / raw)


On 2021-09-19 14:41, Dmitry A. Kazakov wrote:
> On 2021-09-19 12:36, Niklas Holsti wrote:
>> On 2021-09-18 19:19, Dmitry A. Kazakov wrote:
>>> On 2021-09-18 17:59, Niklas Holsti wrote:
>>>
>>>> So you want a way to specify that for a given access type, although 
>>>> the accessed object type has a Finalize operation or needs 
>>>> finalization, the objects left over in the (at least conceptually) 
>>>> associated collection should _not_ be finalized when the scope of 
>>>> the access type is left?
>>>
>>> Exactly, especially because these objects are not deallocated, as you 
>>> say they are left over. If they wanted GC they should do that. If 
>>> they do not, then they should keep their hands off the objects 
>>> maintained by the programmer.
>>>
>>>> To me it seems a risky think to do, subverting the normal semantics 
>>>> of initialization and finalization.
>>>
>>> Quite the opposite, it is the collection rule that subverts semantics 
>>> because objects are not freed, yet mangled.
>>
>> Local variables declared in a subprogram are also not explicitly freed 
>> (deallocated), yet they are automatically finalized when the 
>> subprogram returns.
> 
> Local objects are certainly freed. Explicit or not, aggregated or not, 
> is irrelevant.


Objects left over in a local collection may certainly be freed 
automatically, if the implementation has created a local pool for them. 
See ARM 13.11 (2.a): "Alternatively, [the implementation] might choose 
to create a new pool at each accessibility level, which might mean that 
storage is reclaimed for an access type when leaving the appropriate scope."


>> My understanding of Ada semantic principles is that any object that is 
>> initialized should also be finalized.
> 
> IFF deallocated.
> 
> An application that runs continuously will never deallocate, HENCE 
> finalize certain objects.


And I agreed that in this case it could be nice to let the programmer 
specify that keeping collections is not needed.


>> Has this feature of Ada caused you real problems in real applications, 
>> or is it only a point of principle for you?
> 
> 1. It is a massive overhead in both memory and performance terms with no 
> purpose whatsoever. [...]


Have you actually measured or observed that overhead in some application?


> 2. What is worse that a collection is not bound to the pool. It is to an 
> access type, which may have a narrower scope. So the user could declare 
> an unfortunate access type, which would corrupt objects in the pool and 
> the pool designer has no means to prevent that.


So there is a possibility of programmer mistake, leading to unintended 
finalization of those (now inaccessible) objects.

However, your semantic argument (as opposed to the overhead argument) 
seems to be based on an assumption that the objects "left over" in a 
local collection, and which thus are inaccessible, will still, somehow, 
participate in the later execution of the program, which is why you say 
that finalizing those objects would "corrupt" them.

It seems to me that such continued participation is possible only if the 
objects contain tasks or are accessed through some kind of unchecked 
programming. Do you agree?

^ permalink raw reply	[flat|nested] 62+ messages in thread

* Re: Custom Storage Pool questions
  2021-09-20  6:48       ` Emmanuel Briot
@ 2021-09-20  7:35         ` Dmitry A. Kazakov
  2021-09-20 16:59         ` Shark8
  2021-09-21  0:50         ` Randy Brukardt
  2 siblings, 0 replies; 62+ messages in thread
From: Dmitry A. Kazakov @ 2021-09-20  7:35 UTC (permalink / raw)


On 2021-09-20 08:48, Emmanuel Briot wrote:
>>> If a compiler is allowed to break up an allocation into multiple
>>> calls to Allocate (and of course Deallocate), how does one go about
>>> enforcing that the user's header is only created once?
>> I think one cannot enforce that, because the calls to Allocate do not
>> indicate (with parameters) which set of calls concern the same object
>> allocation.
> 
> I think the only solution would be for this compiler to have another attribute similar to 'Storage_Pool, but that would define the pool for the  descriptor:
> 
>      for X'Storage_Pool use Pool;
>      for X'Descriptor_Storage_Pool use Other_Pool;
> 
> That way the user can decide when to add (or not) extra headers.

This will not work with arenas and stack pools. And it is error-prone 
because the attribute is associated with the access type. Furthermore, 
it is the descriptor you wanted to tag with extra data.

One could add another primitive operation to Root_Storage_Pool:

    procedure Allocate_Secondary (
       Pool : in out Root_Storage_Pool;
       Storage_Address : out Address;
       Size_In_Storage_Elements : in Storage_Elements.Storage_Count;
       Alignment : in Storage_Elements.Storage_Count;
       Segment_No : in Positive); -- Re-dispatches to Allocate

The object allocation protocol would be:

    Allocate_Secondary (Pool, ..., 1);
    Allocate_Secondary (Pool, ..., 2);
    ...
    Allocate_Secondary (Pool, ..., N);
    Allocate (Pool, ...); -- Header goes here

-- 
Regards,
Dmitry A. Kazakov
http://www.dmitry-kazakov.de

^ permalink raw reply	[flat|nested] 62+ messages in thread

* Re: Custom Storage Pool questions
  2021-09-20  7:05                                 ` Niklas Holsti
@ 2021-09-20  7:35                                   ` Dmitry A. Kazakov
  2021-09-20  8:08                                     ` Niklas Holsti
  0 siblings, 1 reply; 62+ messages in thread
From: Dmitry A. Kazakov @ 2021-09-20  7:35 UTC (permalink / raw)


On 2021-09-20 09:05, Niklas Holsti wrote:
> On 2021-09-19 14:41, Dmitry A. Kazakov wrote:
>> On 2021-09-19 12:36, Niklas Holsti wrote:
>>> On 2021-09-18 19:19, Dmitry A. Kazakov wrote:
>>>> On 2021-09-18 17:59, Niklas Holsti wrote:
>>>>
>>>>> So you want a way to specify that for a given access type, although 
>>>>> the accessed object type has a Finalize operation or needs 
>>>>> finalization, the objects left over in the (at least conceptually) 
>>>>> associated collection should _not_ be finalized when the scope of 
>>>>> the access type is left?
>>>>
>>>> Exactly, especially because these objects are not deallocated, as 
>>>> you say they are left over. If they wanted GC they should do that. 
>>>> If they do not, then they should keep their hands off the objects 
>>>> maintained by the programmer.
>>>>
>>>>> To me it seems a risky think to do, subverting the normal semantics 
>>>>> of initialization and finalization.
>>>>
>>>> Quite the opposite, it is the collection rule that subverts 
>>>> semantics because objects are not freed, yet mangled.
>>>
>>> Local variables declared in a subprogram are also not explicitly 
>>> freed (deallocated), yet they are automatically finalized when the 
>>> subprogram returns.
>>
>> Local objects are certainly freed. Explicit or not, aggregated or not, 
>> is irrelevant.
> 
> Objects left over in a local collection may certainly be freed 
> automatically, if the implementation has created a local pool for them. 
> See ARM 13.11 (2.a): "Alternatively, [the implementation] might choose 
> to create a new pool at each accessibility level, which might mean that 
> storage is reclaimed for an access type when leaving the appropriate 
> scope."

May or may not. The feature which correctness depends on scopes and lots 
of further assumptions has no place in a language like Ada.

>>> Has this feature of Ada caused you real problems in real 
>>> applications, or is it only a point of principle for you?
>>
>> 1. It is a massive overhead in both memory and performance terms with 
>> no purpose whatsoever. [...]
> 
> Have you actually measured or observed that overhead in some application?

How?

However you could estimate it from the most likely implementation as a 
doubly-linked list. You add new element for each allocation and remove 
one for each deallocation. The elements are allocated in the same pool 
or in some other pool. Finalization is not time bounded, BTW. Nice?

>> 2. What is worse that a collection is not bound to the pool. It is to 
>> an access type, which may have a narrower scope. So the user could 
>> declare an unfortunate access type, which would corrupt objects in the 
>> pool and the pool designer has no means to prevent that.
> 
> So there is a possibility of programmer mistake, leading to unintended 
> finalization of those (now inaccessible) objects.
> 
> However, your semantic argument (as opposed to the overhead argument) 
> seems to be based on an assumption that the objects "left over" in a 
> local collection, and which thus are inaccessible, will still, somehow, 
> participate in the later execution of the program, which is why you say 
> that finalizing those objects would "corrupt" them.
> 
> It seems to me that such continued participation is possible only if the 
> objects contain tasks or are accessed through some kind of unchecked 
> programming. Do you agree?

No. You can have them accessible over other access types with wider scopes:

    Collection_Pointer := new X;
    Global_Pointer := Collection_Pointer.all'Unchecked_Access;

access discriminants etc. As I said, hands off!

-- 
Regards,
Dmitry A. Kazakov
http://www.dmitry-kazakov.de

^ permalink raw reply	[flat|nested] 62+ messages in thread

* Re: Custom Storage Pool questions
  2021-09-20  7:35                                   ` Dmitry A. Kazakov
@ 2021-09-20  8:08                                     ` Niklas Holsti
  2021-09-20  8:28                                       ` Dmitry A. Kazakov
  2021-09-21  0:40                                       ` Randy Brukardt
  0 siblings, 2 replies; 62+ messages in thread
From: Niklas Holsti @ 2021-09-20  8:08 UTC (permalink / raw)


On 2021-09-20 10:35, Dmitry A. Kazakov wrote:
> On 2021-09-20 09:05, Niklas Holsti wrote:


   [snipping context]


>> However, your semantic argument (as opposed to the overhead argument) 
>> seems to be based on an assumption that the objects "left over" in a 
>> local collection, and which thus are inaccessible, will still, 
>> somehow, participate in the later execution of the program, which is 
>> why you say that finalizing those objects would "corrupt" them.
>>
>> It seems to me that such continued participation is possible only if 
>> the objects contain tasks or are accessed through some kind of 
>> unchecked programming. Do you agree?
> 
> No. You can have them accessible over other access types with wider scopes:
> 
>     Collection_Pointer := new X;
>     Global_Pointer := Collection_Pointer.all'Unchecked_Access;
> 


So, unchecked programming, as I said.

^ permalink raw reply	[flat|nested] 62+ messages in thread

* Re: Custom Storage Pool questions
  2021-09-20  8:08                                     ` Niklas Holsti
@ 2021-09-20  8:28                                       ` Dmitry A. Kazakov
  2021-09-21  0:45                                         ` Randy Brukardt
  2021-09-21  0:40                                       ` Randy Brukardt
  1 sibling, 1 reply; 62+ messages in thread
From: Dmitry A. Kazakov @ 2021-09-20  8:28 UTC (permalink / raw)


On 2021-09-20 10:08, Niklas Holsti wrote:
> On 2021-09-20 10:35, Dmitry A. Kazakov wrote:

>> No. You can have them accessible over other access types with wider 
>> scopes:
>>
>>     Collection_Pointer := new X;
>>     Global_Pointer := Collection_Pointer.all'Unchecked_Access;
>>
> So, unchecked programming, as I said.

Right, working with pools is all that thing. Maybe "new" should be named 
"unchecked_new" (:-))

Finalize and Initialize certainly should have been Unchecked_Finalize 
and Unchecked_Initialize as they are not enforced. You can override the 
parent's Initialize and never call it. It is a plain primitive 
operations anybody can call any time any place. You can even call it 
before the object is fully initialized!

So, why bother with objects the user manually allocates (and forgets to 
free)?

-- 
Regards,
Dmitry A. Kazakov
http://www.dmitry-kazakov.de

^ permalink raw reply	[flat|nested] 62+ messages in thread

* Re: Custom Storage Pool questions
  2021-09-20  6:48       ` Emmanuel Briot
  2021-09-20  7:35         ` Dmitry A. Kazakov
@ 2021-09-20 16:59         ` Shark8
  2021-09-21  0:50         ` Randy Brukardt
  2 siblings, 0 replies; 62+ messages in thread
From: Shark8 @ 2021-09-20 16:59 UTC (permalink / raw)


On Monday, September 20, 2021 at 12:48:21 AM UTC-6, briot.e wrote:
> > > If a compiler is allowed to break up an allocation into multiple 
> > > calls to Allocate (and of course Deallocate), how does one go about 
> > > enforcing that the user's header is only created once? 
> > I think one cannot enforce that, because the calls to Allocate do not 
> > indicate (with parameters) which set of calls concern the same object 
> > allocation.
> I think the only solution would be for this compiler to have another attribute similar to 'Storage_Pool, but that would define the pool for the descriptor: 
> 
> for X'Storage_Pool use Pool; 
> for X'Descriptor_Storage_Pool use Other_Pool; 
> 
> That way the user can decide when to add (or not) extra headers.
Hmmm, smells like a place to use generics and subpools; perhaps something like:

Generic
   Type Element(<>) is limited private;
   Type Descriptor(<>) is limited private;
   with Create( Item : Element ) return Descriptor;
Package Descriptor_Subpool is
   Type Pool_Type is new System.Storage_Pools.Subpools.Root_Storage_Pool_With_Subpools with private;
Private
   -- Element-subpool & descriptor-subpool defined here.
   -- Allocation of element also allocates Descriptor.
End Descriptor_Subpool;

Just top-of-the-head musings though.

^ permalink raw reply	[flat|nested] 62+ messages in thread

* Re: Custom Storage Pool questions
  2021-09-14  6:23     ` Dmitry A. Kazakov
  2021-09-14  6:42       ` J-P. Rosen
  2021-09-15  0:21       ` Jere
@ 2021-09-20 23:48       ` Randy Brukardt
  2 siblings, 0 replies; 62+ messages in thread
From: Randy Brukardt @ 2021-09-20 23:48 UTC (permalink / raw)


"Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> wrote in message 
news:shpf4d$1a6s$1@gioia.aioe.org...
> On 2021-09-14 02:48, Jere wrote:
...
> The problem with unconstrained arrays is not that the bounds are not 
> allocated, they are, but the semantics of X'Address when applied to 
> arrays.
>
> A'Address is the address of the first array element, not of the array 
> object. For a pool designer it constitutes a problem of getting the array 
> object by address. This is what Emmanuel discusses in the blog.

Right, this is why Janus/Ada never "fixed" 'Address to follow the Ada 
requirement. (Our Ada 83 compiler treats the "object" as whatever the 
top-level piece is, for an unconstrained array, that's the bounds -- the 
data lies elsewhere and is separately allocated -- something that follows 
from slice semantics.)

I suppose your suggestion of implementing yet-another-attribute is probably 
the right way to go, and then finding every use of 'Address in existing RRS 
Janus/Ada code and changing it to use the new attribute that works "right".

                                               Randy.



> [ The motivation behind Ada choice was probably to keep the semantics 
> implementation-independent. ]
>
> Consider for example a list of String elements. When Allocate is called 
> with String, it returns the address of all String. But that is not the 
> address you would get if you applied 'Address. You have to add/subtract 
> some offset in order to get one from another.
>
> In Simple Components this offset is determined at run-time for each 
> generic instance.
>
> Of course, a proper solution would be fixing Ada by adding another address 
> attribute:
>
>    X'Object_Address
>
> returning the first address of the object as allocated.
>
> -- 
> Regards,
> Dmitry A. Kazakov
> http://www.dmitry-kazakov.de 


^ permalink raw reply	[flat|nested] 62+ messages in thread

* Re: Custom Storage Pool questions
  2021-09-16 23:32           ` Jere
@ 2021-09-20 23:51             ` Randy Brukardt
  2021-09-21 22:40               ` Jere
  0 siblings, 1 reply; 62+ messages in thread
From: Randy Brukardt @ 2021-09-20 23:51 UTC (permalink / raw)


Sorry about that, I didn't understand what you were asking. And I get 
defensive about people who think that a pool should get some specific Size 
(and only that size), so I leapt to a conclusion and answered accordingly.

The compiler requests all of the memory IT needs, but if the pool needs some 
additional memory for it's purposes (pretty common), it will need to add 
that space itself. It's hard to imagine how it could be otherwise, I guess I 
would have thought that goes without saying. (And that rather proves that 
there is nothing that goes without saying.)

                  Randy.

"Jere" <jhb.chat@gmail.com> wrote in message 
news:96e7199f-c354-402f-a6c6-2a0e042b6747n@googlegroups.com...
> On Wednesday, September 15, 2021 at 3:01:52 AM UTC-4, Simon Wright wrote:
>> Jere <> writes:
>>
>> > Thanks for the response. I'm sorry for all the questions. That's how
>> > I learn and I realize it isn't a popular way to learn in the
>> > community, but I have always learned very differently than most.
>> Seems to me you ask interesting questions which generate enlightening
>> responses!
> Thanks!  though in this case, my question was ill formed after I missed a 
> detail
> in the blog, so the mistake is on me.  I will say I hold back some 
> questions
> as it is very intimidating to ask on C.L.A.  I mean the first response led 
> off
> with "Not sure what you are expecting" so it is hard to know how to 
> formulate
> a good question as I always seem to get some harsh responses (which I am
> sure is because I asked the question poorly).  I'm unfortunately a very 
> visual
> person and words are not my forte and I feel like when I ask questions 
> about
> the boundaries of the language I manage to put folks on the defensive.  I
> don't dislike Ada at all, it is my favorite language, but I think it is 
> hard to
> craft questions on some topics without putting forth the impression that
> I don't like it, at least with my limited ability to word craft. 


^ permalink raw reply	[flat|nested] 62+ messages in thread

* Re: Custom Storage Pool questions
  2021-09-14  6:42       ` J-P. Rosen
  2021-09-14  7:00         ` Dmitry A. Kazakov
@ 2021-09-20 23:58         ` Randy Brukardt
  1 sibling, 0 replies; 62+ messages in thread
From: Randy Brukardt @ 2021-09-20 23:58 UTC (permalink / raw)


[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #1: Type: text/plain, Size: 1842 bytes --]

"J-P. Rosen" <rosen@adalog.fr> wrote in message 
news:shpg9b$t23$1@dont-email.me...
> Le 14/09/2021 à 08:23, Dmitry A. Kazakov a écrit :
>> Of course, a proper solution would be fixing Ada by adding another 
>> address attribute:
>>
>>  X'Object_Address
>>
>> returning the first address of the object as allocated.
> But you cannot assume that the object is allocated as one big chunk.
> Bounds can be allocated at a different place. What would be 
> X'Object_Address in that case?

The address of the real object, which is the bounds. (I'm using "object" in 
the Janus/Ada compiler sense and not in the Ada sense.) The only way I could 
make sense of the implementation requirements for Janus/Ada was to have 
every object be statically sized. If the Ada object is *not* statically 
sized, then the Janus/Ada object is a descriptor that provides access to 
that Ada object data.

Generally, one wants access to the statically sized object, as that provides 
access to everything else (there may be multiple levels if 
discriminant-dependent arrays are involved). That's not what 'Address is 
supposed to provide, so the address used internally to the compiler is the 
wrong answer in Ada terms, but it is the right answer for most uses (storage 
pools being an obvious example).

When one specifies 'Address in Janus/Ada, you are specifying the address of 
the statically allocated data. The rest of the object lives in some storage 
pool and it makes absolutely no sense to try to force that somewhere.

There's no sensible reason to expect 'Address to be 
implementation-independent; specifying the address of unconstrained arrays 
is nonsense unless you know that the same Ada compiler is creating the 
object you are accessing -- hardly a common case.

                                   Randy.



^ permalink raw reply	[flat|nested] 62+ messages in thread

* Re: Custom Storage Pool questions
  2021-09-14  1:04   ` Jere
@ 2021-09-21  0:06     ` Randy Brukardt
  0 siblings, 0 replies; 62+ messages in thread
From: Randy Brukardt @ 2021-09-21  0:06 UTC (permalink / raw)


"Jere" <jhb.chat@gmail.com> wrote in message 
news:036086ba-ea40-44cb-beb7-cded0f501cfbn@googlegroups.com...
> On Monday, September 13, 2021 at 1:29:39 AM UTC-4, Randy Brukardt wrote:
>> Not sure what you are expecting. There is no requirement that objects are
>> allocated contigiously. Indeed, Janus/Ada will call Allocate as many 
>> times
>> as needed for each object; for instance, unconstrained arrays are in two
>> parts (descriptor and data area).
>>
> No expectations.  Just questions.  I wasn't concerned with whether the
> allocated memory was contiguous or not, but whether an implementation
> is required to supply the correct size of memory needed to allocate an 
> object
> or if it is allowed to pass a value to Size that is less than the amount 
> of
> memory actually needed.  For example, the blog there indicates the
> maintainer of the custom storage pool needs to account for First/Last
> indexes of an unconstrained array separately instead of assuming that 
> value is
> included as part of the Size parameter's value.
>
> If the Size parameter doesn't require that it includes space for 
> First/Last
> for unconstrained arrays or Prev/Next for controlled objects (assuming
> that is even the implementation picked of course), then I'm not seeing
> a way to write a custom storage pool that is portable because you need
> to account for each implementation's "hidden" values that are not 
> represented
> in the Size parameter.

No, that would be wrong. The implementation has to calculate the Size of 
memory that it needs, no less.

>  For example if Janus calculated Size to have
> both the size of the array and the size of First and Last but GNAT didn't
> and my storage pool assumed the JANUS method, then if someone
> used my storage pool with GNAT then it would access memory
> from some other location potentially and erroneously.

No. What you cannot assume is that all of the memory is allocated at once. 
There can be multiple parts. But the compiler has to figure out the right 
size for each part, it can't tell you it needs 8 bytes and use 10. That 
would be a broken compiler.

>> The only thing that you can assume in a portable library is that you get
>> called the same number of times and sizes/alignment for Allocate and
>> Deallocate; there's no assumptions about size or alignment that you can
>> make.
> So to be clear, you cannot assume that Size and Alignment are appropriate
> for the actual object being allocated correct?  Size could actually be
> less than the actual amount of memory needed and the alignment may only
> apply to part of the object being allocated, not the full object?

Yes and no. You can't assume anything about the Size and Alignment passed. 
But whatever is passed has to be what the compiler actually needs.

> Is that correct?  I'm asking because that is what the blog suggests with
> the example it gave.

The blog sounds like nonsense for most uses. It sounds like someone is 
trying to do something very GNAT-specific -- and that's fine (I have lots of 
pools that assume the size of array descriptors in Janus/Ada to separate 
those from the array data allocations). But it's irrelevant for normal use.

>>
>> If you want to build a pool around some specific allocated size, then if 
>> it
>> needs to be portable, (A) you have to calculate the allocated size, and 
>> (B)
>> you have to have a mechanism for what to do if some other size is 
>> requested.
>> (Allocate a whole block for smaller sizes, fall back to built-in heap for
>> too large is what I usually do).
>>
> Are there any good tricks to handle this?  For example, if I design a
> storage pool around constructing a particular type of object, what is
> normally done to discourage another programmer from using the pool with
> an entirely different type?  Maybe raise an exception if the size isn't 
> exact?
> I'm not sure what else, unless maybe there is an Aspect/Attribute that
> can be set to ensure only a specific type of object can be constructed.

I either raise Program_Error (if I'm lazy), or simply hand off "wrong-sized" 
allocations/deallocations to the standard Storage_Pool.

                             Randy.


^ permalink raw reply	[flat|nested] 62+ messages in thread

* Re: Custom Storage Pool questions
  2021-09-17 20:39               ` Dmitry A. Kazakov
  2021-09-17 21:17                 ` Niklas Holsti
@ 2021-09-21  0:18                 ` Randy Brukardt
  1 sibling, 0 replies; 62+ messages in thread
From: Randy Brukardt @ 2021-09-21  0:18 UTC (permalink / raw)


Janus/Ada uses chains for everything; there is no attempt to do anything 
else. They make dealing with partially initialized objects (when some 
initialization fails) much easier, and are strongly related to the lists of 
allocated memory that Janus/Ada uses anyway.

It's easy to deal with a stand-alone controlled object, but when you have 
components of dynamic components of dynamically sized object and have to 
deal with failures and allocated objects, the headaches just aren't worth it 
(IMHO). The cost is insignificant unless you actually have controlled 
objects, so you only pay for what you use (to steal a line from a commercial 
that runs far too often in the US).

                                Randy.


"Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> wrote in message 
news:si2ud7$fv2$1@gioia.aioe.org...
> On 2021-09-17 21:46, Simon Wright wrote:
>> "Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> writes:
>>
>>> Nope, especially because the issue with X'Address being unusable for
>>> memory pool developers is a long standing painful problem that need to
>>> be resolved. That will never happen until a measurable group of people
>>> start asking questions. So you are doubly welcome.
>>
>> There are two attributes that we should all have known about,
>> Descriptor_Size[1] (bits, introduced in 2011) and Finalization_Size[2]
>> (storage units, I think, introduced in 2017)
>
> They are non-standard and have murky semantics I doubt anybody really 
> cares about.
>
> What is needed is the address passed to Deallocate should the object be 
> freed = the address returned by Allocate. Is that too much to ask?
>
> BTW, finalization lists (#2) should have been removed from the language 
> long ago. They have absolutely no use, except maybe for debugging, and 
> introduce huge overhead. The semantics should have been either 
> Unchecked_Deallocation or compiler allocated objects/components may call 
> Finalize, nothing else.
>
> -- 
> Regards,
> Dmitry A. Kazakov
> http://www.dmitry-kazakov.de 


^ permalink raw reply	[flat|nested] 62+ messages in thread

* Re: Custom Storage Pool questions
  2021-09-18  7:49                   ` Dmitry A. Kazakov
  2021-09-18  9:03                     ` Niklas Holsti
@ 2021-09-21  0:19                     ` Randy Brukardt
  1 sibling, 0 replies; 62+ messages in thread
From: Randy Brukardt @ 2021-09-21  0:19 UTC (permalink / raw)


There is: Restriction No_Controlled_Types. - Randy

"Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> wrote in message 
news:si45ls$1goa$1@gioia.aioe.org...
> On 2021-09-17 23:17, Niklas Holsti wrote:
>> On 2021-09-17 23:39, Dmitry A. Kazakov wrote:
>>> On 2021-09-17 21:46, Simon Wright wrote:
>>>> "Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> writes:
>>>>
>>>>> Nope, especially because the issue with X'Address being unusable for
>>>>> memory pool developers is a long standing painful problem that need to
>>>>> be resolved. That will never happen until a measurable group of people
>>>>> start asking questions. So you are doubly welcome.
>>>>
>>>> There are two attributes that we should all have known about,
>>>> Descriptor_Size[1] (bits, introduced in 2011) and Finalization_Size[2]
>>>> (storage units, I think, introduced in 2017)
>>>
>>> They are non-standard and have murky semantics I doubt anybody really 
>>> cares about.
>>>
>>> What is needed is the address passed to Deallocate should the object be 
>>> freed = the address returned by Allocate. Is that too much to ask?
>>
>> That is already required by RM 13.11(21.7/3): "The value of the 
>> Storage_Address parameter for a call to Deallocate is the value returned 
>> in the Storage_Address parameter of the corresponding successful call to 
>> Allocate."
>
> You missed the discussion totally. It is about X'Address attribute.
>
> The challenge: write pool with a function returning object allocation time 
> by its pool-specific access type.
>
>>> BTW, finalization lists (#2) should have been removed from the language 
>>> long ago.
>>
>> Huh? Where does the RM _require_ finalization lists?
>
> 7.6.1 (11 1/3)
>
>> I see them mentioned here and there as a _possible_ implementation 
>> technique, and an alternative "PC-map" technique is described in RM 7.6.1 
>> (24.r .. 24.t).
>
> I don't care about techniques to implement meaningless stuff. It should be 
> out, at least there must be a representation aspect for turning this mess 
> off.
>
> -- 
> Regards,
> Dmitry A. Kazakov
> http://www.dmitry-kazakov.de 


^ permalink raw reply	[flat|nested] 62+ messages in thread

* Re: Custom Storage Pool questions
  2021-09-18 10:22                       ` Dmitry A. Kazakov
  2021-09-18 15:59                         ` Niklas Holsti
@ 2021-09-21  0:26                         ` Randy Brukardt
  2021-09-21  6:51                           ` Dmitry A. Kazakov
  1 sibling, 1 reply; 62+ messages in thread
From: Randy Brukardt @ 2021-09-21  0:26 UTC (permalink / raw)


"Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> wrote in message 
news:si4ell$1b25$1@gioia.aioe.org...
...
>> Given that an object can be allocated in multiple independent pieces, it 
>> seems unlikely that what you want will be provided.
>
> Such implementations would automatically disqualify the compiler. 
> Compiler-generated piecewise allocation is OK for the stack, not for user 
> storage pools.

If someone wants to require contigious allocation of objects, there should 
be a representation attribute to specify it. And there should not be an 
nonsense restrictions on records with defaulted discriminants unless you 
specify that you require contiguous allocation. There is no good reason to 
need that for 99% of objects, why insist on a very expensive implementation 
of slices/unconstrained arrays unless it's required??

...
> No, it is about the overhead of maintaining "collections" associated with 
> an access type in order to call Finalization for all members of the 
> collection.

How else would you ensure that Finalize is always called on an allocated 
object? Unchecked_Deallocation need not be called on an allocated object. 
The Ada model is that Finalize will ALWAYS be called on every controlled 
object before the program ends; there are no "leaks" of finalization. 
Otherwise, one cannot depend on finalization for anything important; you 
would often leak resources (especially for simple kernels that don't try to 
free unreleased resources themselves).

                               Randy.


^ permalink raw reply	[flat|nested] 62+ messages in thread

* Re: Custom Storage Pool questions
  2021-09-19 11:41                               ` Dmitry A. Kazakov
  2021-09-20  7:05                                 ` Niklas Holsti
@ 2021-09-21  0:30                                 ` Randy Brukardt
  2021-09-21  0:37                                 ` Randy Brukardt
  2 siblings, 0 replies; 62+ messages in thread
From: Randy Brukardt @ 2021-09-21  0:30 UTC (permalink / raw)


"Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> wrote in message 
news:si77kd$rka$1@gioia.aioe.org...
> On 2021-09-19 12:36, Niklas Holsti wrote:
...
>> Local variables declared in a subprogram are also not explicitly freed 
>> (deallocated), yet they are automatically finalized when the subprogram 
>> returns.
>
> Local objects are certainly freed. Explicit or not, aggregated or not, is 
> irrelevant.

OK...

>> My understanding of Ada semantic principles is that any object that is 
>> initialized should also be finalized.
>
> IFF deallocated.

...as you note above for stack objects, all objects are conceptually 
deallocated. Whether the memory is actually returned to a storage pool is 
irrelevant.

The original Ada model was that Unchecked_Deallocation is something to be 
avoided if at all possible (thus the name), one would never want to tie 
finalization to such a thing.

                         Randy.


^ permalink raw reply	[flat|nested] 62+ messages in thread

* Re: Custom Storage Pool questions
  2021-09-19 11:41                               ` Dmitry A. Kazakov
  2021-09-20  7:05                                 ` Niklas Holsti
  2021-09-21  0:30                                 ` Randy Brukardt
@ 2021-09-21  0:37                                 ` Randy Brukardt
  2021-09-21  6:28                                   ` Dmitry A. Kazakov
  2 siblings, 1 reply; 62+ messages in thread
From: Randy Brukardt @ 2021-09-21  0:37 UTC (permalink / raw)


"Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> wrote in message 
news:si77kd$rka$1@gioia.aioe.org...
...
> 1. It is a massive overhead in both memory and performance terms with no 
> purpose whatsoever. I fail to see where that sort of thing might be even 
> marginally useful.

The classic example of Finalization is file management on a simple kernel (I 
use CP/M as the example in my head). CP/M did not try to recover any 
resources on program exit, it was the programs responsibility to recover 
them all (or reboot after every run). If you had holes in finalization, you 
would easily leak files and since you could only open a limited number of 
them at a time, you could easily make a system non-responsive.

You get similar things on some embedded kernels.

If you only write programs that live in ROM and never, ever terminate, then 
you probably have different requirements. Most likely, you shouldn't be 
using Finalization at all (or at least not putting such object in allocated 
things).

...
> 2. What is worse that a collection is not bound to the pool. It is to an 
> access type, which may have a narrower scope. So the user could declare an 
> unfortunate access type, which would corrupt objects in the pool and the 
> pool designer has no means to prevent that.

Pools are extremely low-level things that cannot be safe in any sense of the 
word. A badly designed pool will corrupt everything. Using a pool with the 
"wrong" access type generally has to be programmed for (as I answered 
earlier, if I assume anything about allocations, I check for violations and 
do something else.) And a pool can be used with many access types; many 
useful ones are.

Some of what you want is provided by the subpool mechanism, but it is even 
more complex at runtime, so it probably doesn't help you.

                     Randy. 


^ permalink raw reply	[flat|nested] 62+ messages in thread

* Re: Custom Storage Pool questions
  2021-09-20  8:08                                     ` Niklas Holsti
  2021-09-20  8:28                                       ` Dmitry A. Kazakov
@ 2021-09-21  0:40                                       ` Randy Brukardt
  1 sibling, 0 replies; 62+ messages in thread
From: Randy Brukardt @ 2021-09-21  0:40 UTC (permalink / raw)


"Niklas Holsti" <niklas.holsti@tidorum.invalid> wrote in message 
news:iqqtskF3losU1@mid.individual.net...
> On 2021-09-20 10:35, Dmitry A. Kazakov wrote:
>> On 2021-09-20 09:05, Niklas Holsti wrote:
>
>
>   [snipping context]
>
>
>>> However, your semantic argument (as opposed to the overhead argument) 
>>> seems to be based on an assumption that the objects "left over" in a 
>>> local collection, and which thus are inaccessible, will still, somehow, 
>>> participate in the later execution of the program, which is why you say 
>>> that finalizing those objects would "corrupt" them.
>>>
>>> It seems to me that such continued participation is possible only if the 
>>> objects contain tasks or are accessed through some kind of unchecked 
>>> programming. Do you agree?
>>
>> No. You can have them accessible over other access types with wider 
>> scopes:
>>
>>  Collection_Pointer := new X;
>>  Global_Pointer := Collection_Pointer.all'Unchecked_Access;
>>
>
>
> So, unchecked programming, as I said.

Yup, and when you do stuff like that, you deserve for the compiler to shoot 
you in the head.

                       Randy.


^ permalink raw reply	[flat|nested] 62+ messages in thread

* Re: Custom Storage Pool questions
  2021-09-20  8:28                                       ` Dmitry A. Kazakov
@ 2021-09-21  0:45                                         ` Randy Brukardt
  0 siblings, 0 replies; 62+ messages in thread
From: Randy Brukardt @ 2021-09-21  0:45 UTC (permalink / raw)


User calls on Initialize and Finalize have no special meaning; they're 
igorned for the purposes of language-defined finalization. The fact that 
they're normal routines and can be called by someone else means that some 
defensive programming is needed. That all happened because of the "scope 
reduction" of Ada 9x; the dedicated creation/finalization mechanism got 
dumped. Finalization was too important to lose completely, so Tucker cooked 
up the current much simpler mechanism in order to avoid the objections. It's 
not ideal for that reason -- but Finalize would still have been a normal 
subprogram that anyone could call (what else could it have been -- the 
mechanism of stream attributes could have been used instead). I don't think 
there is a way that one could have prevented user-defined calls to these 
routines (even if they had a special name, you still could have renamed an 
existing subprogram to the special name).

                                Randy.


"Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> wrote in message 
news:si9gnb$926$1@gioia.aioe.org...
> On 2021-09-20 10:08, Niklas Holsti wrote:
>> On 2021-09-20 10:35, Dmitry A. Kazakov wrote:
>
>>> No. You can have them accessible over other access types with wider 
>>> scopes:
>>>
>>> Collection_Pointer := new X;
>>> Global_Pointer := Collection_Pointer.all'Unchecked_Access;
>>>
>> So, unchecked programming, as I said.
>
> Right, working with pools is all that thing. Maybe "new" should be named 
> "unchecked_new" (:-))
>
> Finalize and Initialize certainly should have been Unchecked_Finalize and 
> Unchecked_Initialize as they are not enforced. You can override the 
> parent's Initialize and never call it. It is a plain primitive operations 
> anybody can call any time any place. You can even call it before the 
> object is fully initialized!
>
> So, why bother with objects the user manually allocates (and forgets to 
> free)?
>
> -- 
> Regards,
> Dmitry A. Kazakov
> http://www.dmitry-kazakov.de 


^ permalink raw reply	[flat|nested] 62+ messages in thread

* Re: Custom Storage Pool questions
  2021-09-20  6:48       ` Emmanuel Briot
  2021-09-20  7:35         ` Dmitry A. Kazakov
  2021-09-20 16:59         ` Shark8
@ 2021-09-21  0:50         ` Randy Brukardt
  2021-09-21 23:08           ` Jere
  2 siblings, 1 reply; 62+ messages in thread
From: Randy Brukardt @ 2021-09-21  0:50 UTC (permalink / raw)


A better solution would be to know the size of those bounds objects and 
treat them differently (I've done that). And the next allocation is going to 
be the data, so I don't do anything special for them. Probably would be nice 
to have an attribute for that. But no one has ever asked for any such thing, 
so I haven't defined anything.

Such pools are highly implementation specific, so I haven't worried about 
this much..

                            Randy.

"Emmanuel Briot" <briot.emmanuel@gmail.com> wrote in message 
news:44be7c73-f69e-45da-9916-b14a43a05ea3n@googlegroups.com...
>> > If a compiler is allowed to break up an allocation into multiple
>> > calls to Allocate (and of course Deallocate), how does one go about
>> > enforcing that the user's header is only created once?
>> I think one cannot enforce that, because the calls to Allocate do not
>> indicate (with parameters) which set of calls concern the same object
>> allocation.
>
> I think the only solution would be for this compiler to have another 
> attribute similar to 'Storage_Pool, but that would define the pool for the 
> descriptor:
>
>    for X'Storage_Pool use Pool;
>    for X'Descriptor_Storage_Pool use Other_Pool;
>
> That way the user can decide when to add (or not) extra headers. 


^ permalink raw reply	[flat|nested] 62+ messages in thread

* Re: Custom Storage Pool questions
  2021-09-21  0:37                                 ` Randy Brukardt
@ 2021-09-21  6:28                                   ` Dmitry A. Kazakov
  0 siblings, 0 replies; 62+ messages in thread
From: Dmitry A. Kazakov @ 2021-09-21  6:28 UTC (permalink / raw)


On 2021-09-21 02:37, Randy Brukardt wrote:
> "Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> wrote in message
> news:si77kd$rka$1@gioia.aioe.org...
> ...
>> 1. It is a massive overhead in both memory and performance terms with no
>> purpose whatsoever. I fail to see where that sort of thing might be even
>> marginally useful.
> 
> The classic example of Finalization is file management on a simple kernel (I
> use CP/M as the example in my head). CP/M did not try to recover any
> resources on program exit, it was the programs responsibility to recover
> them all (or reboot after every run). If you had holes in finalization, you
> would easily leak files and since you could only open a limited number of
> them at a time, you could easily make a system non-responsive.

This is why system resources are handled by the OS rather than by the 
application. But I do not see how this justifies "collections."

>> 2. What is worse that a collection is not bound to the pool. It is to an
>> access type, which may have a narrower scope. So the user could declare an
>> unfortunate access type, which would corrupt objects in the pool and the
>> pool designer has no means to prevent that.
> 
> Pools are extremely low-level things that cannot be safe in any sense of the
> word. A badly designed pool will corrupt everything. Using a pool with the
> "wrong" access type generally has to be programmed for (as I answered
> earlier, if I assume anything about allocations, I check for violations and
> do something else.) And a pool can be used with many access types; many
> useful ones are.

This is also true, but again unrelated to the point that tying 
finalization *without* deallocation to a pointer type is just wrong, 
semantically on any abstraction level.

-- 
Regards,
Dmitry A. Kazakov
http://www.dmitry-kazakov.de

^ permalink raw reply	[flat|nested] 62+ messages in thread

* Re: Custom Storage Pool questions
  2021-09-21  0:26                         ` Randy Brukardt
@ 2021-09-21  6:51                           ` Dmitry A. Kazakov
  0 siblings, 0 replies; 62+ messages in thread
From: Dmitry A. Kazakov @ 2021-09-21  6:51 UTC (permalink / raw)


On 2021-09-21 02:26, Randy Brukardt wrote:
> "Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> wrote in message
> news:si4ell$1b25$1@gioia.aioe.org...
> ...
>>> Given that an object can be allocated in multiple independent pieces, it
>>> seems unlikely that what you want will be provided.
>>
>> Such implementations would automatically disqualify the compiler.
>> Compiler-generated piecewise allocation is OK for the stack, not for user
>> storage pools.
> 
> If someone wants to require contigious allocation of objects, there should
> be a representation attribute to specify it.

It would be difficult, because the types are declared prior to pools. 
That is when object layout does change.

If the layout does not then you need no attribute.

You can always run a mock allocation to compute overall size and offsets 
to the pieces and then do one true allocation. And with stream 
attributes you need to implement introspection anyway. So this might 
have been an issue for Ada 83, but now one can simply require contiguous 
allocation in pools.

> And there should not be an
> nonsense restrictions on records with defaulted discriminants unless you
> specify that you require contiguous allocation.

You can keep the object layout. It is only the question of "trolling" 
the pool, no how objects are represented there.

>> No, it is about the overhead of maintaining "collections" associated with
>> an access type in order to call Finalization for all members of the
>> collection.
> 
> How else would you ensure that Finalize is always called on an allocated
> object?

I would not, because it is plain wrong. Finalize must be called for each 
*deallocated* object.

-- 
Regards,
Dmitry A. Kazakov
http://www.dmitry-kazakov.de

^ permalink raw reply	[flat|nested] 62+ messages in thread

* Re: Custom Storage Pool questions
  2021-09-20 23:51             ` Randy Brukardt
@ 2021-09-21 22:40               ` Jere
  0 siblings, 0 replies; 62+ messages in thread
From: Jere @ 2021-09-21 22:40 UTC (permalink / raw)


It's ok!  I realize I am not great at wording questions, so I just assume
I asked it poorly.  If it helps, your response did get me thinking more
about the specifics of contiguous allocation vs not and how it would
affect my design, which didn't even cross my mind before.

On Monday, September 20, 2021 at 7:51:17 PM UTC-4, Randy Brukardt wrote:
> Sorry about that, I didn't understand what you were asking. And I get 
> defensive about people who think that a pool should get some specific Size 
> (and only that size), so I leapt to a conclusion and answered accordingly. 
> 
> The compiler requests all of the memory IT needs, but if the pool needs some 
> additional memory for it's purposes (pretty common), it will need to add 
> that space itself. It's hard to imagine how it could be otherwise, I guess I 
> would have thought that goes without saying. (And that rather proves that 
> there is nothing that goes without saying.) 
> 
> Randy. 
> 
> "Jere" <> wrote in message 
> news:96e7199f-c354-402f...@googlegroups.com...
> > On Wednesday, September 15, 2021 at 3:01:52 AM UTC-4, Simon Wright wrote: 
> >> Jere <> writes: 
> >> 
> >> > Thanks for the response. I'm sorry for all the questions. That's how 
> >> > I learn and I realize it isn't a popular way to learn in the 
> >> > community, but I have always learned very differently than most. 
> >> Seems to me you ask interesting questions which generate enlightening 
> >> responses! 
> > Thanks! though in this case, my question was ill formed after I missed a 
> > detail 
> > in the blog, so the mistake is on me. I will say I hold back some 
> > questions 
> > as it is very intimidating to ask on C.L.A. I mean the first response led 
> > off 
> > with "Not sure what you are expecting" so it is hard to know how to 
> > formulate 
> > a good question as I always seem to get some harsh responses (which I am 
> > sure is because I asked the question poorly). I'm unfortunately a very 
> > visual 
> > person and words are not my forte and I feel like when I ask questions 
> > about 
> > the boundaries of the language I manage to put folks on the defensive. I 
> > don't dislike Ada at all, it is my favorite language, but I think it is 
> > hard to 
> > craft questions on some topics without putting forth the impression that 
> > I don't like it, at least with my limited ability to word craft.

^ permalink raw reply	[flat|nested] 62+ messages in thread

* Re: Custom Storage Pool questions
  2021-09-21  0:50         ` Randy Brukardt
@ 2021-09-21 23:08           ` Jere
  0 siblings, 0 replies; 62+ messages in thread
From: Jere @ 2021-09-21 23:08 UTC (permalink / raw)


I think the only thing that misses is scenarios where the compiler vendor 
isn't allocating a descriptor/bounds but is still using multiple allocations for the
object.  I don't know if that is a practical use, but it is one the RM allows?  If
so, it is probably more useful to know if a specific Allocate call is somehow
a unique call relative to the others (the first call, the last call, etc.) so that the
developer could earmark that one to be the one to add the custom header
to.  

We can't change the Allocate specification since it is what it is, but is there
any consideration to adding functionality to the root storage pool type,
maybe a classwide function that lets the compiler developer set an internal 
flag for that unique allocation and a classwide function for the storage
pool developer to see if that flag was set for the allocation.  Or some other
mechanism.  It seems like this would need to be some sort of runtime 
mechanism if the multiple allocations can occur in the absence of needing
a descriptor or bounds.

Or maybe a generic version of the Storage_Pools package that allows a 
header type to be specified, that gives the compiler vendor some 
interface that easily facilitates allocating the header along side any object
at the time and place the vendor finds convenient, and provides the 
custom storage pool implementer a means of knowing when that happens
so they can initialize the header in the allocate function that creates it.

I'm obviously not a compiler developer so I don't know the practicalness
of any of that.  But I think one root problem for a custom storage pool 
developer is "when is it safe to make a custom header for my object?".  



On Monday, September 20, 2021 at 8:50:41 PM UTC-4, Randy Brukardt wrote:
> A better solution would be to know the size of those bounds objects and 
> treat them differently (I've done that). And the next allocation is going to 
> be the data, so I don't do anything special for them. Probably would be nice 
> to have an attribute for that. But no one has ever asked for any such thing, 
> so I haven't defined anything. 
> 
> Such pools are highly implementation specific, so I haven't worried about 
> this much.. 
> 
> Randy. 
> 
> "Emmanuel Briot" <> wrote in message 
> news:44be7c73-f69e-45da...@googlegroups.com...
> >> > If a compiler is allowed to break up an allocation into multiple 
> >> > calls to Allocate (and of course Deallocate), how does one go about 
> >> > enforcing that the user's header is only created once? 
> >> I think one cannot enforce that, because the calls to Allocate do not 
> >> indicate (with parameters) which set of calls concern the same object 
> >> allocation. 
> > 
> > I think the only solution would be for this compiler to have another 
> > attribute similar to 'Storage_Pool, but that would define the pool for the 
> > descriptor: 
> > 
> > for X'Storage_Pool use Pool; 
> > for X'Descriptor_Storage_Pool use Other_Pool; 
> > 
> > That way the user can decide when to add (or not) extra headers.

^ permalink raw reply	[flat|nested] 62+ messages in thread

end of thread, other threads:[~2021-09-21 23:08 UTC | newest]

Thread overview: 62+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-09-13  0:53 Custom Storage Pool questions Jere
2021-09-13  5:29 ` Randy Brukardt
2021-09-14  1:04   ` Jere
2021-09-21  0:06     ` Randy Brukardt
2021-09-18 11:32   ` Simon Wright
2021-09-20  0:31   ` Jere
2021-09-20  6:34     ` Niklas Holsti
2021-09-20  6:48       ` Emmanuel Briot
2021-09-20  7:35         ` Dmitry A. Kazakov
2021-09-20 16:59         ` Shark8
2021-09-21  0:50         ` Randy Brukardt
2021-09-21 23:08           ` Jere
2021-09-13 11:12 ` J-P. Rosen
2021-09-14  0:48   ` Jere
2021-09-14  6:08     ` J-P. Rosen
2021-09-15  0:39       ` Jere
2021-09-15  7:01         ` Simon Wright
2021-09-16 23:32           ` Jere
2021-09-20 23:51             ` Randy Brukardt
2021-09-21 22:40               ` Jere
2021-09-14  6:23     ` Dmitry A. Kazakov
2021-09-14  6:42       ` J-P. Rosen
2021-09-14  7:00         ` Dmitry A. Kazakov
2021-09-20 23:58         ` Randy Brukardt
2021-09-15  0:21       ` Jere
2021-09-15  6:54         ` Dmitry A. Kazakov
2021-09-20 23:48       ` Randy Brukardt
2021-09-14 10:54     ` Egil H H
2021-09-15  0:11       ` Jere
2021-09-15 16:43 ` Simon Wright
2021-09-15 17:03   ` Simon Wright
2021-09-15 19:07   ` Dmitry A. Kazakov
2021-09-15 20:40     ` Simon Wright
2021-09-16  7:12       ` Emmanuel Briot
2021-09-16 23:21         ` Jere
2021-09-17  7:08           ` Emmanuel Briot
2021-09-17  7:18           ` Simon Wright
2021-09-17 13:56           ` Dmitry A. Kazakov
2021-09-17 19:46             ` Simon Wright
2021-09-17 20:39               ` Dmitry A. Kazakov
2021-09-17 21:17                 ` Niklas Holsti
2021-09-18  7:49                   ` Dmitry A. Kazakov
2021-09-18  9:03                     ` Niklas Holsti
2021-09-18 10:22                       ` Dmitry A. Kazakov
2021-09-18 15:59                         ` Niklas Holsti
2021-09-18 16:19                           ` Dmitry A. Kazakov
2021-09-19 10:36                             ` Niklas Holsti
2021-09-19 11:41                               ` Dmitry A. Kazakov
2021-09-20  7:05                                 ` Niklas Holsti
2021-09-20  7:35                                   ` Dmitry A. Kazakov
2021-09-20  8:08                                     ` Niklas Holsti
2021-09-20  8:28                                       ` Dmitry A. Kazakov
2021-09-21  0:45                                         ` Randy Brukardt
2021-09-21  0:40                                       ` Randy Brukardt
2021-09-21  0:30                                 ` Randy Brukardt
2021-09-21  0:37                                 ` Randy Brukardt
2021-09-21  6:28                                   ` Dmitry A. Kazakov
2021-09-21  0:26                         ` Randy Brukardt
2021-09-21  6:51                           ` Dmitry A. Kazakov
2021-09-21  0:19                     ` Randy Brukardt
2021-09-21  0:18                 ` Randy Brukardt
2021-09-16  8:41       ` Dmitry A. Kazakov

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox