Thread overview
Re: Manually-allocated memory and maximum array capacity
Apr 05, 2014
Artur Skawina
Apr 08, 2014
Artur Skawina
April 05, 2014
On 04/05/14 00:54, Joseph Rushton Wakeling wrote:
> Hello all,
> 
> If we change the length of a dynamic array using the normal GC-based methods, e.g. by setting the array's .length property, we find that the array's capacity typically does not simply equal the length, but some greater value; there is excess allocation.
> 
> Question: is there a comparable phenomenon for memory that is manually allocated using malloc?  That is, that if we specify a particular number of bytes to allocate, it may be rounded up to a particular larger number?
> 
> And, if so -- is there any way of guaranteeing what that larger number will be?
> 
> The reason I ask is because, suppose that I use a dynamic array as a fixed-size buffer, and that its minimum size must be n.  So, I can do:
> 
>     arr.length = n;
>     if (arr.capacity > arr.length)
>     {
>         arr.length = arr.capacity;
>     }
> 
> ... and get the largest possible buffer that is at least size n, but does not allocate any more memory than setting length = n.
> 
> I'm wondering if I can do something similar with manual memory allocation.

Not portably, as it will be libc and/or allocator specific.

For example, for glibc this would work:

   /* static if (using_glibc) */
   size_t capacity(const void* p) @property @safe {
      return malloc_usable_size(p);
   }

artur
April 07, 2014
On 05/04/14 02:18, Artur Skawina wrote:
> Not portably, as it will be libc and/or allocator specific.

I think that's fine.  I would be using it in circumstances where it's nice to have if I can get it, not a problem if I can't.  As long as I make appropriate use of version statements to ensure it's only used where available, it should be OK and not affect usability.

> For example, for glibc this would work:
>
>     /* static if (using_glibc) */
>     size_t capacity(const void* p) @property @safe {
>        return malloc_usable_size(p);
>     }

Thanks! :-)

April 08, 2014
On 04/07/14 22:58, Joseph Rushton Wakeling wrote:
> On 05/04/14 02:18, Artur Skawina wrote:
>> Not portably, as it will be libc and/or allocator specific.
> 
> I think that's fine.  I would be using it in circumstances where it's nice to have if I can get it, not a problem if I can't.  As long as I make appropriate use of version statements to ensure it's only used where available, it should be OK and not affect usability.
> 
>> For example, for glibc this would work:
>>
>>     /* static if (using_glibc) */
>>     size_t capacity(const void* p) @property @safe {
>>        return malloc_usable_size(p);
>>     }
> 
> Thanks! :-)

Just be careful; I used the name 'capacity' because it fit
into your example, but 'capacity' shouldn't be overloaded like
that - it works very differently from the magic built-in property.

The only safe way to use it would be:

   E[] aalloc(E)(size_t l) @trusted {
      if (l<size_t.max/E.sizeof)
         if (auto p = cast(E*)malloc(l*E.sizeof))
            return p[0..malloc_usable_size(p)/E.sizeof];
      return null;
   }

artur
April 08, 2014
On 08/04/14 16:58, Artur Skawina wrote:
> Just be careful; I used the name 'capacity' because it fit
> into your example, but 'capacity' shouldn't be overloaded like
> that - it works very differently from the magic built-in property.

Yes, I was thinking that I'd better use a different name.  (Actually the precise requirements are a bit different anyway, so there's no way to use it quite like that; but the principle is right.)

> The only safe way to use it would be:
>
>     E[] aalloc(E)(size_t l) @trusted {
>        if (l<size_t.max/E.sizeof)
>           if (auto p = cast(E*)malloc(l*E.sizeof))
>              return p[0..malloc_usable_size(p)/E.sizeof];
>        return null;
>     }

Nicely done! :-)