<commit_before>// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA

//
//
// Copyright (C) 2006 Novell Inc.
// Copyright (C) 2009 <NAME> <<EMAIL>>
// Copyright (C) 2013 <NAME> <<EMAIL>>
//
// This class implements functions to bind callbacks to GObject signals
// dynamically and to emit signals dynamically.
//
//

using GLib;
using System;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Collections;

namespace Gst
{

	[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
	delegate void GClosureMarshal (IntPtr closure, ref GLib.Value retval, uint argc, IntPtr argsPtr,
                                 IntPtr invocation_hint, IntPtr data);

	public delegate void SignalHandler (object o, SignalArgs args);

	public static class DynamicSignal
	{

		private static readonly int gvalue_struct_size = Marshal.SizeOf (typeof(GLib.Value));

		class ObjectSignalKey
		{
			object o;
			string signal_name;

			public ObjectSignalKey (object o, string name)
			{
				this.o = o;
				signal_name = name;
			}

			public override bool Equals (object o)
			{
				if (o is ObjectSignalKey) {
					ObjectSignalKey k = (ObjectSignalKey)o;
					return k.o.Equals (this.o) && signal_name.Equals (k.signal_name);
				}
				return base.Equals (o);
			}

			public override int GetHashCode ()
			{
				return o.GetHashCode () ^ signal_name.GetHashCode ();
			}
		}

		class SignalInfo
		{
			uint handlerId;
			IntPtr closure;
			Delegate registeredHandler;
			Type argsType;

			public IntPtr Closure {
				get {
					return closure;
				}
				set {
					closure = value;
				}
			}

			public uint HandlerId {
				get {
					return handlerId;
				}
				set {
					handlerId = value;
				}
			}

			public Delegate RegisteredHandler {
				get {
					return registeredHandler;
				}
				set {
					registeredHandler = value;
				}
			}

			public Type ArgsType {
				get {
					return argsType;
				}
				set {
					argsType = value;
				}
			}

			public SignalInfo (uint handlerId, IntPtr closure, Delegate registeredHandler)
			{
				this.handlerId = handlerId;
				this.closure = closure;
				this.registeredHandler = registeredHandler;

				if (!IsValidDelegate (registeredHandler))
					throw new Exception ("Invalid delegate");

				MethodInfo mi = registeredHandler.Method;
				ParameterInfo[] parms = mi.GetParameters ();
				this.argsType = parms [1].ParameterType;
			}

			public void UpdateArgsType (Delegate d)
			{
				if (!IsCompatibleDelegate (d))
					throw new Exception ("Incompatible delegate");

				MethodInfo mi = d.Method;
				ParameterInfo[] parms = mi.GetParameters ();

				Type t1 = parms [1].ParameterType;
				Type t2 = argsType;

				if (t1 == t2)
					return;

				if (t1.IsSubclassOf (t2))
					argsType = t1;
				else if (t2.IsSubclassOf (t1))
					argsType = t2;
				else
					throw new Exception ("Incompatible delegate");
			}

			public bool IsCompatibleDelegate (Delegate d)
			{
				if (!IsValidDelegate (d))
					return false;

				MethodInfo mi = d.Method;
				ParameterInfo[] parms = mi.GetParameters ();

				if (parms [1].ParameterType != this.argsType &&
				        !parms [1].ParameterType.IsSubclassOf (this.argsType) &&
				        !this.argsType.IsSubclassOf (parms [1].ParameterType))
					return false;

				return true;
			}

			public static bool IsValidDelegate (Delegate d)
			{
				MethodInfo mi = d.Method;

				if (mi.ReturnType != typeof(void))
					return false;

				ParameterInfo[] parms = mi.GetParameters ();
				if (parms.Length != 2)
					return false;

				if (parms [1].ParameterType != typeof(GLib.SignalArgs) &&
				        !parms [1].ParameterType.IsSubclassOf (typeof(GLib.SignalArgs)))
					return false;

				return true;
			}
		}

		static Hashtable SignalHandlers = new Hashtable ();

		static GClosureMarshal marshalHandler = new GClosureMarshal (OnMarshal);

		public static void Connect (GLib.Object o, string name, SignalHandler handler)
		{
			Connect (o, name, false, (Delegate)handler);
		}

		public static void Connect (GLib.Object o, string name,
		                              bool after, SignalHandler handler)
		{
			Connect (o, name, after, (Delegate)handler);
		}

		public static void Connect (GLib.Object o, string name, Delegate handler)
		{
			Connect (o, name, false, handler);
		}

		public static void Connect (GLib.Object o, string name,
		                              bool after, Delegate handler)
		{
			Delegate newHandler;

			ObjectSignalKey k = new ObjectSignalKey (o, name);

			if (!SignalInfo.IsValidDelegate (handler))
				throw new Exception ("Invalid delegate");

			if (SignalHandlers [k] != null) {
				SignalInfo si = (SignalInfo)SignalHandlers [k];
				if (!si.IsCompatibleDelegate (handler))
					throw new Exception ("Incompatible delegate");

				newHandler = Delegate.Combine (si.RegisteredHandler, handler);
				si.UpdateArgsType (handler);
				si.RegisteredHandler = newHandler;
			} else {
				if (!SignalInfo.IsValidDelegate (handler))
					throw new Exception ("Invalid delegate");

				// Let's allocate 64bytes for the GClosure, it should be more than necessary.
				IntPtr closure = g_closure_new_simple (64, IntPtr.Zero);
				g_closure_set_meta_marshal (closure, (IntPtr)GCHandle.Alloc (k), marshalHandler);
				uint signalId = g_signal_connect_closure (o.Handle, name, closure, after);
				SignalHandlers.Add (k, new SignalInfo (signalId, closure, handler));
			}
		}

		public static void Disconnect (GLib.Object o, string name, Delegate handler)
		{
			ObjectSignalKey k = new ObjectSignalKey (o, name);
			if (SignalHandlers [k] != null) {
				SignalInfo si = (SignalInfo)SignalHandlers [k];
				Delegate newHandler = Delegate.Remove (si.RegisteredHandler, handler);
				if (newHandler == null || handler == null) {
					g_signal_handler_disconnect (o.Handle, si.HandlerId);
					SignalHandlers.Remove (k);
				} else {
					si.RegisteredHandler = newHandler;
				}
			}
		}

		static void OnMarshal (IntPtr closure, ref GLib.Value retval, uint argc, IntPtr argsPtr,
		                         IntPtr ihint, IntPtr data)
		{
			object[] args = new object[argc - 1];
			object o = ((GLib.Value)Marshal.PtrToStructure (argsPtr, typeof(GLib.Value))).Val;

			for (int i = 1; i < argc; i++) {
				IntPtr struct_ptr = (IntPtr)((long)argsPtr + (i * gvalue_struct_size));
				GLib.Value argument = (GLib.Value)Marshal.PtrToStructure (struct_ptr, typeof(GLib.Value));
				args [i - 1] = argument.Val;
			}<commit_msg>DynamicSignal: Add Dispose to SignalInfo<commit_after>// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA

//
//
// Copyright (C) 2006 Novell Inc.
// Copyright (C) 2009 <NAME> <<EMAIL>>
// Copyright (C) 2013 <NAME> <<EMAIL>>
//
// This class implements functions to bind callbacks to GObject signals
// dynamically and to emit signals dynamically.
//
//

using GLib;
using System;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Collections;

namespace Gst
{

	[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
	delegate void GClosureMarshal (IntPtr closure, ref GLib.Value retval, uint argc, IntPtr argsPtr,
                                 IntPtr invocation_hint, IntPtr data);

	public delegate void SignalHandler (object o, SignalArgs args);

	public static class DynamicSignal
	{

		private static readonly int gvalue_struct_size = Marshal.SizeOf (typeof(GLib.Value));

		class ObjectSignalKey
		{
			object o;
			string signal_name;

			public ObjectSignalKey (object o, string name)
			{
				this.o = o;
				signal_name = name;
			}

			public override bool Equals (object o)
			{
				if (o is ObjectSignalKey) {
					ObjectSignalKey k = (ObjectSignalKey)o;
					return k.o.Equals (this.o) && signal_name.Equals (k.signal_name);
				}
				return base.Equals (o);
			}

			public override int GetHashCode ()
			{
				return o.GetHashCode () ^ signal_name.GetHashCode ();
			}
		}

		class SignalInfo : IDisposable
		{
			uint handlerId;
			IntPtr closure;
			Delegate registeredHandler;
			Type argsType;
			GCHandle gch;

			public IntPtr Closure {
				get {
					return closure;
				}
				set {
					closure = value;
				}
			}

			public uint HandlerId {
				get {
					return handlerId;
				}
				set {
					handlerId = value;
				}
			}

			public Delegate RegisteredHandler {
				get {
					return registeredHandler;
				}
				set {
					registeredHandler = value;
				}
			}

			public Type ArgsType {
				get {
					return argsType;
				}
				set {
					argsType = value;
				}
			}

			public SignalInfo (uint handlerId, IntPtr closure, Delegate registeredHandler, GCHandle gch)
			{
				this.handlerId = handlerId;
				this.closure = closure;
				this.registeredHandler = registeredHandler;
				this.gch = gch;

				if (!IsValidDelegate (registeredHandler))
					throw new Exception ("Invalid delegate");

				MethodInfo mi = registeredHandler.Method;
				ParameterInfo[] parms = mi.GetParameters ();
				this.argsType = parms [1].ParameterType;
			}

			public void UpdateArgsType (Delegate d)
			{
				if (!IsCompatibleDelegate (d))
					throw new Exception ("Incompatible delegate");

				MethodInfo mi = d.Method;
				ParameterInfo[] parms = mi.GetParameters ();

				Type t1 = parms [1].ParameterType;
				Type t2 = argsType;

				if (t1 == t2)
					return;

				if (t1.IsSubclassOf (t2))
					argsType = t1;
				else if (t2.IsSubclassOf (t1))
					argsType = t2;
				else
					throw new Exception ("Incompatible delegate");
			}

			public bool IsCompatibleDelegate (Delegate d)
			{
				if (!IsValidDelegate (d))
					return false;

				MethodInfo mi = d.Method;
				ParameterInfo[] parms = mi.GetParameters ();

				if (parms [1].ParameterType != this.argsType &&
				        !parms [1].ParameterType.IsSubclassOf (this.argsType) &&
				        !this.argsType.IsSubclassOf (parms [1].ParameterType))
					return false;

				return true;
			}

			public void Dispose ()
			{
				registeredHandler = null;
				gch.Free ();
				GC.SuppressFinalize (this);
			}

			public static bool IsValidDelegate (Delegate d)
			{
				MethodInfo mi = d.Method;

				if (mi.ReturnType != typeof(void))
					return false;

				ParameterInfo[] parms = mi.GetParameters ();
				if (parms.Length != 2)
					return false;

				if (parms [1].ParameterType != typeof(GLib.SignalArgs) &&
				        !parms [1].ParameterType.IsSubclassOf (typeof(GLib.SignalArgs)))
					return false;

				return true;
			}
		}

		static Hashtable SignalHandlers = new Hashtable ();

		static GClosureMarshal marshalHandler = new GClosureMarshal (OnMarshal);

		public static void Connect (GLib.Object o, string name, SignalHandler handler)
		{
			Connect (o, name, false, (Delegate)handler);
		}

		public static void Connect (GLib.Object o, string name,
		                              bool after, SignalHandler handler)
		{
			Connect (o, name, after, (Delegate)handler);
		}

		public static void Connect (GLib.Object o, string name, Delegate handler)
		{
			Connect (o, name, false, handler);
		}

		public static void Connect (GLib.Object o, string name,
		                              bool after, Delegate handler)
		{
			Delegate newHandler;

			ObjectSignalKey k = new ObjectSignalKey (o, name);

			if (!SignalInfo.IsValidDelegate (handler))
				throw new Exception ("Invalid delegate");

			if (SignalHandlers [k] != null) {
				SignalInfo si = (SignalInfo)SignalHandlers [k];
				if (!si.IsCompatibleDelegate (handler))
					throw new Exception ("Incompatible delegate");

				newHandler = Delegate.Combine (si.RegisteredHandler, handler);
				si.UpdateArgsType (handler);
				si.RegisteredHandler = newHandler;
			} else {
				if (!SignalInfo.IsValidDelegate (handler))
					throw new Exception ("Invalid delegate");

				// Let's allocate 64bytes for the GClosure, it should be more than necessary.
				IntPtr closure = g_closure_new_simple (64, IntPtr.Zero);
				GCHandle gch = GCHandle.Alloc (k);
				g_closure_set_meta_marshal (closure, (IntPtr)gch, marshalHandler);
				uint signalId = g_signal_connect_closure (o.Handle, name, closure, after);
				SignalHandlers.Add (k, new SignalInfo (signalId, closure, handler, gch));
			}
		}

		public static void Disconnect (GLib.Object o, string name, Delegate handler)
		{
			ObjectSignalKey k = new ObjectSignalKey (o, name);
			if (SignalHandlers [k] != null) {
				SignalInfo si = (SignalInfo)SignalHandlers [k];
				Delegate newHandler = Delegate.Remove (si.RegisteredHandler, handler);
				if (newHandler == null || handler == null) {
					g_signal_handler_disconnect (o.Handle, si.HandlerId);
					SignalHandlers.Remove (k);
					si.Dispose ();
				} else {
					si.RegisteredHandler = newHandler;
				}
			}
		}

		static void OnMarshal (IntPtr closure, ref GLib.Value retval, uint argc, IntPtr argsPtr,
		                         IntPtr ihint, IntPtr data)
		{
			object[] args = new object[argc - 1];
			object o = ((GLib.Value)Marshal.PtrToStructure (argsPtr, typeof(GLib.Value))).Val;

			for (int i = 1; i < argc; i++) {
				IntPtr struct_ptr = (IntPtr)((long)argsPtr + (i * gvalue_struct_size));
				GLib.Value argument = (GLib.Value)Marshal.PtrToStructure (struct_ptr, typeof(GLib.Value));
				args [i - 1] = argument.Val;
			}
{'fraction_non_alphanumeric': 0.10061164181155935, 'fraction_numerical': 0.0068723799051611575, 'mean_word_length': 2.962962962962963, 'pattern_counts': {'":': 0, '<': 17, '<?xml version=': 0, '>': 15, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 2, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4530822', 'n_tokens_mistral': 5421, 'n_tokens_neox': 4277, 'n_words': 1366}