February 16, 2021
On Saturday, 13 February 2021 at 00:32:30 UTC, Rumbu wrote:
> I recently started a new project for Windows bindings [1] based on metadata generated by Windows Metadata Project [2].
>
> [...]

@everyone:
"This is great to see and thanks for letting us know. I've added this project to the list of projections in our README to help with discovery and will do the same with other projects as they come online."

https://github.com/microsoft/win32metadata
February 16, 2021
On Saturday, 13 February 2021 at 00:32:30 UTC, Rumbu wrote:
> 4) On RAIFree attribute
>
> Most of the specific handles are decorated with this attribute stating the function meant to free the handle. Example:
>
> [RAIIFree(CloseDC)]
> struct HDC ...

struct RaiiFreer(T, alias f) {
	T x;
	alias x this;
	~this() {
		f(x);
	}
}
struct realHDC { original contents... }
alias HDC = RaiiFreer!(realHDC, CloseDC);

And make the win32 functions take a realHDC, but users declare HDC to get raii semantics.
February 16, 2021
On Tuesday, 16 February 2021 at 21:35:32 UTC, Elronnd wrote:
> On Saturday, 13 February 2021 at 00:32:30 UTC, Rumbu wrote:
>> 4) On RAIFree attribute
> struct RaiiFreer(T, alias f) ...

On Saturday, 13 February 2021 at 16:01:26 UTC, Steven Schveighoffer wrote:
> Don't do this, because it will close on copying too.
>
> In order to *properly* implement this, it would need reference counting.


It's easy to get double frees with that solution--right.  Can disable copy constructor, or make it a class.  I would go for the former, as it's more flexible: if you need ref semantics, just make a pointer or use phobos refcount.

I disagree that you _need_ refcounting to get it right, though.  Providing a destructor makes it a more native interface.  Manually destroying is something you would have had to do anyway, but now you can destroy the object the same as you would any other.
February 17, 2021
On 2/16/21 4:48 PM, Elronnd wrote:
> On Tuesday, 16 February 2021 at 21:35:32 UTC, Elronnd wrote:
>> On Saturday, 13 February 2021 at 00:32:30 UTC, Rumbu wrote:
>>> 4) On RAIFree attribute
>> struct RaiiFreer(T, alias f) ...
> 
> On Saturday, 13 February 2021 at 16:01:26 UTC, Steven Schveighoffer wrote:
>> Don't do this, because it will close on copying too.
>>
>> In order to *properly* implement this, it would need reference counting.
> 
> 
> It's easy to get double frees with that solution--right.  Can disable copy constructor, or make it a class.  I would go for the former, as it's more flexible: if you need ref semantics, just make a pointer or use phobos refcount.

Yes, this is a good solution -- it just alters the semantics of the function return.

> 
> I disagree that you _need_ refcounting to get it right, though. Providing a destructor makes it a more native interface. Manually destroying is something you would have had to do anyway, but now you can destroy the object the same as you would any other.

It's fine as long as it isn't the true return type. As long as you want the same *semantics* as the original type, it needs to be copyable.

I'd say, leave the type itself as the return value, add an attribute that identifies how to free it, and then provide a wrapper that does what you want based on introspecting the attribute.

e.g.:

@freeFunction!CloseDC struct HDC { ... normal contents }

HDC someWindowsFunc(...);

auto autoFree(T)(T val) if (hasUDA!(freeFunction, T)) {
   return RAIIWrapper!(extractFreeFunction!T)(val);
}

auto v = someWindowsFunc(...).autoFree;

-Steve
February 19, 2021
On Wednesday, 17 February 2021 at 14:49:58 UTC, Steven Schveighoffer wrote:
> On 2/16/21 4:48 PM, Elronnd wrote:

What do you think?

//Usage:

@RAIIFree!CloseHandle
struct SomeHandle
{
    ptrdiff_t value;
}

SomeHandle CreateSomeHandle(int x, int y);
void DoSomethingWithSomeHandle(Handle h);
void CloseSomeHandle(SomeHandle h);

auto h = autoFree(CreateSomeHandle(42, 666));
DoSomethingWithSomeHandle(h);



//Implementation
struct RAIIFree(alias H)
{
    private alias Handler = H;
}

auto autoFree(T)(T handle)
{
    return RAIIWrapper!(T, FreeFunctionOf!T)(handle);
}

struct RAIIWrapper(Handle, alias CloseHandler)
{

    Handle s;
    alias s this;
    @disable this();
    @disable this(this);
    this(Handle value)
    {
        this.s = value;
    }
    ~this()
    {
        CloseHandler(s);
    }
}


private template FreeFunctionOf(T, A...)
{
    static if (A.length == 0)
    {
        alias attrs = __traits(getAttributes, T);
        static assert(attrs.length > 0, T.stringof ~ " doesn't have any attribute attached to it");
        alias FreeFunctionOf = FreeFunctionOf!(T, attrs);
    }
    else static if (A.length == 1)
    {
        static assert(isFreeHandler!(T, A[0]), T.stringof ~ " doesn't have a correct @RAIIFree attribute attached to it");
        alias FreeFunctionOf = A[0].Handler;
    }
    else static if (isFreeHandler!(T, A[0]))
        alias FreeFunctionOf = A[0].Handler;
    else
        alias FreeFunctionOf = FreeFunctionOf!(T, A[1 .. $]);
}

private template isFreeHandler(T, alias A)
{
    enum isFreeHandler = is(typeof(A.Handler))
        && is(typeof(A.Handler(T.init)));
}

February 19, 2021
On 2/19/21 7:16 AM, Rumbu wrote:
> On Wednesday, 17 February 2021 at 14:49:58 UTC, Steven Schveighoffer wrote:
>> On 2/16/21 4:48 PM, Elronnd wrote:
> 
> What do you think?
> 

Looks pretty good :)

-Steve
1 2
Next ›   Last »