/* * This file is part of the LibreOffice project. * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ using System; using System.Collections.Generic; using System.Linq; using System.Runtime.CompilerServices; using System.Threading; namespace com.sun.star.uno.native { internal class WeakIndexTable { private readonly Dictionary> _objectByIndex; private readonly Dictionary, int> _indexByObject; private readonly List _cleanupIndices; private readonly object _lock; private int _counter; private int _updateOps; public WeakIndexTable() { _objectByIndex = new Dictionary>(); _indexByObject = new Dictionary, int>(new WeakReferenceComparer()); _cleanupIndices = new List(); _lock = new object(); _counter = 1; // index 0 is reserved for null _updateOps = 0; } public object Lookup(int index) { if (index == 0) return null; if (_objectByIndex.TryGetValue(index, out WeakReference weakRef)) if (weakRef.TryGetTarget(out object obj)) return obj; throw new RuntimeException($"no object was found at index {index}", null); } public int Register(object obj) { if (obj == null) return 0; WeakReference weakRef = new WeakReference(obj); if (_indexByObject.TryGetValue(weakRef, out int index)) return index; lock (_lock) { _objectByIndex.Add(_counter, weakRef); _indexByObject.Add(weakRef, _counter); _updateOps++; AutoClean(); return _counter++; } } private void AutoClean() { if (_updateOps >= _objectByIndex.Count) { _updateOps = 0; foreach (int key in _objectByIndex.Keys) { WeakReference weakRef = _objectByIndex[key]; if (!weakRef.TryGetTarget(out _)) _cleanupIndices.Add(key); } foreach (int key in _cleanupIndices) _objectByIndex.Remove(key); _cleanupIndices.Clear(); } } private class WeakReferenceComparer : IEqualityComparer> { public bool Equals(WeakReference x, WeakReference y) { if (x.TryGetTarget(out object first)) if (y.TryGetTarget(out object second)) return ReferenceEquals(first, second); return false; } public int GetHashCode(WeakReference obj) => obj.TryGetTarget(out object target) ? target.GetHashCode() : 0; } } }