TempAlloc review starts now

Steven Schveighoffer schveiguy at yahoo.com
Mon Jun 6 12:40:40 PDT 2011


On Mon, 06 Jun 2011 15:10:49 -0400, dsimcha <dsimcha at yahoo.com> wrote:

> == Quote from Steven Schveighoffer (schveiguy at yahoo.com)'s article

>> alignedMalloc:
>> I seriously question having such a feature.  According to my C++ book
>> malloc returns a pointer "suitably aligned for any type".  According to
>> Microsoft, malloc is 16-byte aligned (of course, D doesn't use  
>> microsoft's
>> runtime, DMC doesn't seem to identify alignment in malloc docs).  GNU
>> appears to guarantee 8-byte alignment on 32-bit systems, 16 on 64-bit
>> systems (making this function mostly useless on 64-bit dmd).
>> There are also some posix functions that align a malloc to a requested
>> size (see memalign).
>
> I definitely need it in the implementation of TempAlloc, so it's gonna  
> be there
> but it can be made private if there's a consensus that it's not needed  
> in the
> public API.

What about in the cases where malloc aligns to 16 bits (i.e. on 32-bit  
windows or 64-bit linux)?  Does this not seem like a waste of 16 bytes?

>
>> At the very least, the function should identify what the alignment is if
>> you *don't* use it.  I'd like to see a good use case for this feature in
>> an example, otherwise, I think it should be killed.
>
> The alignment if you don't use it depends on the C malloc function for  
> your
> platform.

Which should be minimum 8 byte aligned (required by doubles).  In my C++  
book it says "suitably aligned for any type".  I would say this is likely  
a requirement for any C compiler.

Essentially, I would say that malloc on 32-bit systems must be at least  
8-byte aligned, but could already be 16-byte aligned.

> A use case might be if you need 16-byte aligned arrays to use SSE
> instructions, but that's hard to demonstrate in a short example.

It doesn't have to be complete, just something showing the allocation and  
the usage which requires 16-byte alignment.

>> That being said, wrapping malloc might have some nice other features  
>> too.
>> I like the auto-adding of the range to the GC.
>> tempdup:
>> 1. If this uses ElemType!(R)[] as the return type, duping a char[] will
>> give you a dchar[].  I don't think this is very desirable.
>
> This seems right to me.  tempdup() is supposed to be basically a  
> TempAlloc version
> of array().  IMHO it should **ALWAYS** return a random-access range.   
> Returning a
> narrow string creates an obscure special case where it doesn't.

I expected it to be a TempAlloc version of .dup.

IMO, it should return an array, which char[] is.  Note that an array *is*  
random access, despite what std.range is telling you :)

counter case:

assert(is(typeof(str) == char[]));
str = str.tempdup; // ensure allocation on the tempstack.

Also, note that newStack!char(50) works and seems inconsistent with your  
choice for tempdup.

>> 2. What happens for something like immutable(uint *)[]?  Does it become
>> uint *[]?  Because that would be bad...
>
> No.  It becomes an immutable(uint*)[].  ElementType!(immutable(uint*)[])  
> ==
> immutable(uint*).

I am looking at Unqual, which according to D's documentation, removes all  
qualifiers.  But testing shows that this isn't the case.  The  
documentation seems very sketchy on that trait, but it appears to be the  
most unqualified (!) implicitly converting type.  So I guess my gripe is  
more with std.traits' documentation than your module.

>> TempAlloc.malloc:
>> I don't like void * as a return value.  Would it not be more appropriate
>> to use at least void[]?  I'd suggest actually for malloc to take a
>> template parameter of the type to return, defaulting to void.  i.e.:
>> T[] malloc(T = void)(size_t size);
>
> Here I'm going to have to strongly disagree.  I want to keep  
> TempAlloc.malloc
> consistent with GC.malloc and core.stdc.stdlib.malloc.

I can understand that point of view.  I just would like to avoid using  
pointers where it's not necessary.  And I especially like this:

auto buf = TempAlloc.malloc!uint(1024);

better than this:

auto buf = (cast(uint *)TempAlloc.malloc(1024 * uint.sizeof))[0..1024];

I would actually argue that GC.malloc might be better off returning  
void[].  You can always get the pointer with .ptr.

I'll also point out that as a function that is not constrained by compiler  
requirements, we have more flexibility, such as using templates.

I noticed that newStack does exactly what I'm saying, but then I question  
having two different functions that essentially do the same thing.  Is  
there a reason other than consistency with GC.malloc?

Perhaps TempAlloc.malloc should be private?  That would solve the problem.

I just thought of something else, there's newStack, but no freeStack.  It  
seems odd to use newStack to allocate and then TempAlloc.free to  
deallocate.

-Steve


More information about the Digitalmars-d mailing list