Skip to content

Commit

Permalink
Set a VIPS_TYPE_BLOB derived GValue with g_value_set_boxed
Browse files Browse the repository at this point in the history
Since creating a new blob from an already existing one is not correct.
  • Loading branch information
kleisauke committed Jan 29, 2020
1 parent 58432d9 commit 1f4f1bf
Show file tree
Hide file tree
Showing 3 changed files with 49 additions and 39 deletions.
77 changes: 38 additions & 39 deletions src/NetVips/GValue.cs
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,7 @@ public class GValue : IDisposable
/// <summary>
/// Hint of how much native memory is actually occupied by the object.
/// </summary>
private long? _memoryPressure;
private long _memoryPressure;

static GValue()
{
Expand Down Expand Up @@ -215,6 +215,25 @@ public void SetType(IntPtr gtype)
Internal.GValue.Init(ref Struct, gtype);
}

/// <summary>
/// Ensure that the GC knows the true cost of the object during collection.
/// </summary>
/// <remarks>
/// If the object is actually bigger than the managed size reflects, it may
/// be a candidate for quick(er) collection.
/// </remarks>
/// <param name="bytesAllocated">The amount of unmanaged memory that has been allocated.</param>
private void AddMemoryPressure(long bytesAllocated)
{
if (bytesAllocated <= 0)
{
return;
}

GC.AddMemoryPressure(bytesAllocated);
_memoryPressure += bytesAllocated;
}

/// <summary>
/// Set a GValue.
/// </summary>
Expand Down Expand Up @@ -262,14 +281,8 @@ public void Set(object value)
ReadOnlySpan<byte> span = Encoding.UTF8.GetBytes(Convert.ToString(value));
VipsValue.SetRefString(ref Struct, MemoryMarshal.GetReference(span));
}
else if (fundamental == GObjectType)
else if (fundamental == GObjectType && value is GObject gObject)
{
if (!(value is GObject gObject))
{
throw new Exception(
$"unsupported value type {value.GetType()} for gtype {NetVips.TypeName(gtype)}");
}

Internal.GValue.SetObject(ref Struct, gObject);
}
else if (gtype == ArrayIntType)
Expand Down Expand Up @@ -324,14 +337,8 @@ public void Set(object value)

VipsValue.SetArrayDouble(ref Struct, doubles, doubles.Length);
}
else if (gtype == ArrayImageType)
else if (gtype == ArrayImageType && value is Image[] images)
{
if (!(value is Image[] images))
{
throw new Exception(
$"unsupported value type {value.GetType()} for gtype {NetVips.TypeName(gtype)}");
}

var size = images.Length;
VipsValue.SetArrayImage(ref Struct, size);

Expand All @@ -346,49 +353,40 @@ public void Set(object value)
image.ObjectRef();
}
}
else if (gtype == BlobType && value is VipsBlob blob)
{
AddMemoryPressure((long)blob.Length);
Internal.GValue.SetBoxed(ref Struct, blob);
}
else if (gtype == BlobType)
{
var ptr = IntPtr.Zero;
ulong length;
byte[] memory;

byte[] memory = null;
switch (value)
{
case string strValue:
memory = Encoding.UTF8.GetBytes(strValue);
length = (ulong)memory.Length;
break;
case char[] charArrValue:
memory = Encoding.UTF8.GetBytes(charArrValue);
length = (ulong)memory.Length;
break;
case byte[] byteArrValue:
memory = byteArrValue;
length = (ulong)memory.Length;
break;
case VipsBlob blobValue:
ptr = blobValue.GetData(out length);
break;
default:
throw new Exception(
$"unsupported value type {value.GetType()} for gtype {NetVips.TypeName(gtype)}");
}

if (memory != null)
{
// We need to set the blob to a copy of the string that vips can own
ptr = GLib.GMalloc(length);
Marshal.Copy(memory, 0, ptr, (int)length);
}
// We need to set the blob to a copy of the string that vips can own
var ptr = GLib.GMalloc((ulong)memory.Length);
Marshal.Copy(memory, 0, ptr, memory.Length);

// Make sure that the GC knows the true cost of the object during collection.
// If the object is actually bigger than the managed size reflects, it may be a candidate for quick(er) collection.
GC.AddMemoryPressure((long)length);
_memoryPressure = (long)length;
AddMemoryPressure(memory.Length);

if (NetVips.AtLeastLibvips(8, 6))
{
VipsValue.SetBlobFree(ref Struct, ptr, length);
VipsValue.SetBlobFree(ref Struct, ptr, (ulong)memory.Length);
}
else
{
Expand All @@ -399,7 +397,7 @@ int FreeFn(IntPtr a, IntPtr b)
return 0;
}

VipsValue.SetBlob(ref Struct, FreeFn, ptr, length);
VipsValue.SetBlob(ref Struct, FreeFn, ptr, (ulong)memory.Length);
}
}
else
Expand Down Expand Up @@ -457,7 +455,7 @@ public object Get()
}
else if (gtype == ImageType)
{
// GValueGetObject() will not add a ref ... that is
// g_value_get_object() will not add a ref ... that is
// held by the gvalue
var vi = Internal.GValue.GetObject(in Struct);

Expand Down Expand Up @@ -554,9 +552,10 @@ protected void Dispose(bool disposing)
// and tag it to be unset on GC as well
Internal.GValue.Unset(ref Struct);

if (_memoryPressure.HasValue)
if (_memoryPressure > 0)
{
GC.RemoveMemoryPressure(_memoryPressure.Value);
GC.RemoveMemoryPressure(_memoryPressure);
_memoryPressure = 0;
}

// Note disposing has been done.
Expand Down
6 changes: 6 additions & 0 deletions src/NetVips/Internal/GObject.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ namespace NetVips.Internal
using System.Security;
using Interop;
using GObjectManaged = global::NetVips.GObject;
using VipsBlobManaged = global::NetVips.VipsBlob;

internal static class GObject
{
Expand Down Expand Up @@ -168,6 +169,11 @@ internal struct Struct
[DllImport(Libraries.GObject, CallingConvention = CallingConvention.Cdecl,
EntryPoint = "g_value_get_object")]
internal static extern IntPtr GetObject(in Struct value);

[SuppressUnmanagedCodeSecurity]
[DllImport(Libraries.GObject, CallingConvention = CallingConvention.Cdecl,
EntryPoint = "g_value_set_boxed")]
internal static extern void SetBoxed(ref Struct value, VipsBlobManaged boxed);
}

internal static class GParamSpec
Expand Down
5 changes: 5 additions & 0 deletions src/NetVips/VipsBlob.cs
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,11 @@ protected override bool ReleaseHandle()
/// <returns><see langword="true"/> if the handle is not valid; otherwise, <see langword="false"/>.</returns>
public override bool IsInvalid => handle == IntPtr.Zero;

/// <summary>
/// Get the number of bytes of data.
/// </summary>
internal ulong Length => (ulong) handle.Dereference<Internal.VipsArea.Struct>().Length;

/// <summary>
/// Get the reference count of the blob. Handy for debugging.
/// </summary>
Expand Down

0 comments on commit 1f4f1bf

Please sign in to comment.