1
1
using System ;
2
+ using System . Runtime . InteropServices ;
2
3
using System . Text ;
3
4
using LibGit2Sharp . Core ;
4
5
@@ -9,45 +10,54 @@ namespace LibGit2Sharp
9
10
/// </summary>
10
11
public sealed class Filter
11
12
{
12
- private GitFilter filter ;
13
- private readonly string name ;
13
+ private GitFilter managedFilter ;
14
+ private IntPtr nativeFilter ;
15
+
16
+ private readonly string filterName ;
14
17
private readonly string attributes ;
15
18
private readonly int version ;
16
19
20
+
17
21
/// <summary>
18
22
/// Initializes a new instance of the <see cref="Filter"/> class.
23
+ /// And allocates the filter natively.
19
24
/// </summary>
20
25
public Filter ( string name , string attributes , int version )
21
26
{
22
27
Ensure . ArgumentNotNullOrEmptyString ( name , "name" ) ;
23
28
Ensure . ArgumentNotNullOrEmptyString ( attributes , "attributes" ) ;
24
29
Ensure . ArgumentNotNull ( version , "version" ) ;
25
30
26
- this . name = name ;
31
+ this . filterName = name ;
27
32
this . attributes = attributes ;
28
33
this . version = version ;
29
- filter = new GitFilter
34
+
35
+ managedFilter = new GitFilter
30
36
{
31
37
attributes = EncodingMarshaler . FromManaged ( Encoding . UTF8 , attributes ) ,
32
- version = ( uint ) version
38
+ version = ( uint ) version ,
39
+ shutdown = FilterCallbacks . ShutdownCallback ,
33
40
} ;
41
+
42
+ nativeFilter = Marshal . AllocHGlobal ( Marshal . SizeOf ( managedFilter ) ) ;
43
+ Marshal . StructureToPtr ( managedFilter , nativeFilter , false ) ;
34
44
}
35
45
36
46
internal Filter ( string name , IntPtr filterPtr )
37
47
{
38
- var handle = filterPtr . MarshalAs < GitFilter > ( ) ;
39
- this . name = name ;
40
- this . version = ( int ) handle . version ;
41
- this . attributes = LaxUtf8Marshaler . FromNative ( handle . attributes ) ;
48
+ nativeFilter = filterPtr ;
49
+ managedFilter = nativeFilter . MarshalAs < GitFilter > ( ) ;
50
+ filterName = name ;
51
+ attributes = EncodingMarshaler . FromNative ( Encoding . UTF8 , this . managedFilter . attributes ) ;
52
+ version = ( int ) managedFilter . version ;
42
53
}
43
54
44
-
45
55
/// <summary>
46
56
/// The name that this filter was registered with
47
57
/// </summary>
48
58
public string Name
49
59
{
50
- get { return name ; }
60
+ get { return filterName ; }
51
61
}
52
62
53
63
/// <summary>
@@ -71,15 +81,30 @@ public int Version
71
81
/// </summary>
72
82
public void Register ( )
73
83
{
74
- filter = Proxy . git_filter_register ( name , ref filter , 1 ) ;
84
+ Proxy . git_filter_register ( filterName , nativeFilter , 1 ) ;
75
85
}
76
86
77
87
/// <summary>
78
- /// Remove the filter from the registry.
88
+ /// Remove the filter from the registry, and frees the native heap allocation .
79
89
/// </summary>
80
90
public void Deregister ( )
81
91
{
82
92
Proxy . git_filter_unregister ( Name ) ;
93
+ Marshal . FreeHGlobal ( nativeFilter ) ;
94
+ }
95
+
96
+ private static class FilterCallbacks
97
+ {
98
+ // Because our GitFilter structure exists on the managed heap only for a short time (to be marshaled
99
+ // to native memory with StructureToPtr), we need to bind to static delegates. If at construction time
100
+ // we were to bind to the methods directly, that's the same as newing up a fresh delegate every time.
101
+ // Those delegates won't be rooted in the object graph and can be collected as soon as StructureToPtr finishes.
102
+ public static readonly GitFilter . git_filter_shutdown_fn ShutdownCallback = Shutdown ;
103
+
104
+ private static void Shutdown ( IntPtr gitFilter )
105
+ {
106
+ Console . WriteLine ( "Shut down mother fucker" ) ;
107
+ }
83
108
}
84
109
}
85
110
0 commit comments