From: Jiyun Yang Date: Mon, 18 Mar 2024 11:13:14 +0000 (+0900) Subject: [NUI] Move WeakEvent to public and remove unused WeakEventHandler class X-Git-Tag: submit/tizen_7.0/20240321.151506~1^2~1 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=74dbd345e4c46f702038bdb54987321b50736178;p=platform%2Fcore%2Fcsapi%2Ftizenfx.git [NUI] Move WeakEvent to public and remove unused WeakEventHandler class Signed-off-by: Jiyun Yang --- diff --git a/src/Tizen.NUI/src/internal/Common/WeakEvent.cs b/src/Tizen.NUI/src/internal/Common/WeakEvent.cs deleted file mode 100755 index 1b12cef4b..000000000 --- a/src/Tizen.NUI/src/internal/Common/WeakEvent.cs +++ /dev/null @@ -1,155 +0,0 @@ -/* - * Copyright (c) 2020 Samsung Electronics Co., Ltd. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -using System; -using System.Collections.Generic; -using System.Reflection; - -namespace Tizen.NUI -{ - internal class WeakEvent where T : Delegate - { - private const int addThreshold = 1000; // Experimetal constant - private const int listLengthThreshold = 1000; // Experimetal constant - private int cleanUpAddCount = 0; - private List> handlers = new List>(); - - protected int Count => handlers.Count; - - public virtual void Add(T handler) - { - handlers.Add(new WeakHandler(handler)); - OnCountIncreased(); - - CleanUpDeadHandlersIfNeeds(); - } - - public virtual void Remove(T handler) - { - int lastIndex = handlers.FindLastIndex(item => item.Equals(handler)); - - if (lastIndex >= 0) - { - handlers.RemoveAt(lastIndex); - OnCountDicreased(); - } - } - - public void Invoke(object sender, EventArgs args) - { - // Iterate copied one to prevent addition/removal item in the handler call. - var copiedArray = handlers.ToArray(); - foreach (var item in copiedArray) - { - item.Invoke(sender, args); - } - - // Clean up GC items - CleanUpDeadHandlers(); - } - - protected virtual void OnCountIncreased() - { - } - - - protected virtual void OnCountDicreased() - { - } - - private void CleanUpDeadHandlersIfNeeds() - { - // Once the list count exceed 'listLengthThreshold', do the clean-up every 'addThreshold' add operations. - // When list count go below `listLengthThreshold` before clean-up, pause operation counting. - if (handlers.Count > listLengthThreshold && ++cleanUpAddCount > addThreshold) - { - CleanUpDeadHandlers(); - } - } - - private void CleanUpDeadHandlers() - { - cleanUpAddCount = 0; - int count = handlers.Count; - handlers.RemoveAll(item => !item.IsAlive); - if (count > handlers.Count) OnCountDicreased(); - } - - internal class WeakHandler where U : Delegate - { - private WeakReference weakTarget; // Null value means the method is static. - private MethodInfo methodInfo; - - public WeakHandler(U handler) - { - Delegate d = (Delegate)(object)handler; - if (d.Target != null) weakTarget = new WeakReference(d.Target); - methodInfo = d.Method; - } - - private bool IsStatic => weakTarget == null; - - public bool IsAlive - { - get - { - var rooting = weakTarget?.Target; - - return IsStatic || !IsDisposed(rooting); - } - } - - private static bool IsDisposed(object target) - { - if (target == null) return true; - - if (target is BaseHandle basehandle) return basehandle.Disposed || basehandle.IsDisposeQueued; - - if (target is Disposable disposable) return disposable.Disposed || disposable.IsDisposeQueued; - - return false; - } - - public bool Equals(U handler) - { - Delegate other = (Delegate)(object)handler; - bool isOtherStatic = other.Target == null; - return (isOtherStatic || weakTarget?.Target == other.Target) && methodInfo.Equals(other.Method); - } - - public void Invoke(params object[] args) - { - if (IsStatic) - { - Delegate.CreateDelegate(typeof(U), methodInfo).DynamicInvoke(args); - } - else - { - // Because GC is done in other thread, - // it needs to check again that the reference is still alive before calling method. - // To do that, the reference should be assigned to the local variable first. - var rooting = weakTarget.Target; - - if (IsAlive) - { - Delegate.CreateDelegate(typeof(U), rooting, methodInfo).DynamicInvoke(args); - } - } - } - } - } -} diff --git a/src/Tizen.NUI/src/internal/Common/WeakEventHandler.cs b/src/Tizen.NUI/src/internal/Common/WeakEventHandler.cs deleted file mode 100755 index 016b8fd5e..000000000 --- a/src/Tizen.NUI/src/internal/Common/WeakEventHandler.cs +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright (c) 2021 Samsung Electronics Co., Ltd. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -using System; -using System.Reflection; - -namespace Tizen.NUI -{ - internal sealed class WeakEventHandler where TEventArgs : EventArgs - { - private readonly WeakReference targetReference; - private readonly MethodInfo method; - - public WeakEventHandler(EventHandler callback) - { - method = callback.GetMethodInfo(); - targetReference = new WeakReference(callback.Target, true); - } - - public void Handler(object sender, TEventArgs e) - { - var target = targetReference.Target; - if (target != null) - { - var callback = (Action)method.CreateDelegate(typeof(Action), target); - if (callback != null) - { - callback(sender, e); - } - } - } - } -} - diff --git a/src/Tizen.NUI/src/public/Common/WeakEvent.cs b/src/Tizen.NUI/src/public/Common/WeakEvent.cs new file mode 100755 index 000000000..dc84a0c7e --- /dev/null +++ b/src/Tizen.NUI/src/public/Common/WeakEvent.cs @@ -0,0 +1,182 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +using System; +using System.ComponentModel; +using System.Collections.Generic; +using System.Reflection; + +namespace Tizen.NUI +{ + /// + /// The WeakEvent without holding strong reference of event handler. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public class WeakEvent where T : Delegate + { + private const int addThreshold = 1000; // Experimetal constant + private const int listLengthThreshold = 1000; // Experimetal constant + private int cleanUpAddCount = 0; + private List> handlers = new List>(); + + /// + /// The count of currently added event handlers. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + protected int Count => handlers.Count; + + /// + /// Add an event handler. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public virtual void Add(T handler) + { + handlers.Add(new WeakHandler(handler)); + OnCountIncreased(); + + CleanUpDeadHandlersIfNeeds(); + } + + /// + /// Remove last added event handler. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public virtual void Remove(T handler) + { + int lastIndex = handlers.FindLastIndex(item => item.Equals(handler)); + + if (lastIndex >= 0) + { + handlers.RemoveAt(lastIndex); + OnCountDicreased(); + } + } + + /// + /// Invoke event handlers. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public void Invoke(object sender, EventArgs args) + { + // Iterate copied one to prevent addition/removal item in the handler call. + var copiedArray = handlers.ToArray(); + foreach (var item in copiedArray) + { + item.Invoke(sender, args); + } + + // Clean up GC items + CleanUpDeadHandlers(); + } + + /// + /// Invoked when the event handler count is increased. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + protected virtual void OnCountIncreased() + { + } + + /// + /// Invoked when the event handler count is decreased. + /// + protected virtual void OnCountDicreased() + { + } + + private void CleanUpDeadHandlersIfNeeds() + { + // Once the list count exceed 'listLengthThreshold', do the clean-up every 'addThreshold' add operations. + // When list count go below `listLengthThreshold` before clean-up, pause operation counting. + if (handlers.Count > listLengthThreshold && ++cleanUpAddCount > addThreshold) + { + CleanUpDeadHandlers(); + } + } + + private void CleanUpDeadHandlers() + { + cleanUpAddCount = 0; + int count = handlers.Count; + handlers.RemoveAll(item => !item.IsAlive); + if (count > handlers.Count) OnCountDicreased(); + } + + internal class WeakHandler where U : Delegate + { + private WeakReference weakTarget; // Null value means the method is static. + private MethodInfo methodInfo; + + public WeakHandler(U handler) + { + Delegate d = (Delegate)(object)handler; + if (d.Target != null) weakTarget = new WeakReference(d.Target); + methodInfo = d.Method; + } + + private bool IsStatic => weakTarget == null; + + public bool IsAlive + { + get + { + var rooting = weakTarget?.Target; + + return IsStatic || !IsDisposed(rooting); + } + } + + private static bool IsDisposed(object target) + { + if (target == null) return true; + + if (target is BaseHandle basehandle) return basehandle.Disposed || basehandle.IsDisposeQueued; + + if (target is Disposable disposable) return disposable.Disposed || disposable.IsDisposeQueued; + + return false; + } + + public bool Equals(U handler) + { + Delegate other = (Delegate)(object)handler; + bool isOtherStatic = other.Target == null; + return (isOtherStatic || weakTarget?.Target == other.Target) && methodInfo.Equals(other.Method); + } + + public void Invoke(params object[] args) + { + if (IsStatic) + { + Delegate.CreateDelegate(typeof(U), methodInfo).DynamicInvoke(args); + } + else + { + // Because GC is done in other thread, + // it needs to check again that the reference is still alive before calling method. + // To do that, the reference should be assigned to the local variable first. + var rooting = weakTarget.Target; + + if (IsAlive) + { + Delegate.CreateDelegate(typeof(U), rooting, methodInfo).DynamicInvoke(args); + } + } + } + } + } +}