/****************************************************************************** * Copyright (C) Ultraleap, Inc. 2011-2021. * * * * Use subject to the terms of the Apache License 2.0 available at * * http://www.apache.org/licenses/LICENSE-2.0, or another agreement * * between Ultraleap and you, your company or other organization. * ******************************************************************************/ using Leap.Unity.Query; using System; using System.Collections; using System.Collections.Generic; using UnityEngine; namespace Leap.Unity { [Obsolete("It is no longer required to annotate SerializableHashSets with the SHashSet attribute.")] public class SHashSetAttribute : PropertyAttribute { } public abstract class SerializableHashSetBase { } public class SerializableHashSet : SerializableHashSetBase, ICanReportDuplicateInformation, ISerializationCallbackReceiver, IEnumerable { [SerializeField] private List _values = new List(); [NonSerialized] private HashSet _set = new HashSet(); #region HASH SET API public int Count { get { return _set.Count; } } public bool Add(T item) { return _set.Add(item); } public void Clear() { _set.Clear(); } public bool Contains(T item) { return _set.Contains(item); } public bool Remove(T item) { return _set.Remove(item); } public static implicit operator HashSet(SerializableHashSet serializableHashSet) { return serializableHashSet._set; } public IEnumerator GetEnumerator() { return _set.GetEnumerator(); } IEnumerator IEnumerable.GetEnumerator() { return _set.GetEnumerator(); } #endregion public void ClearDuplicates() { HashSet takenValues = new HashSet(); for (int i = _values.Count; i-- != 0;) { var value = _values[i]; if (takenValues.Contains(value)) { _values.RemoveAt(i); } else { takenValues.Add(value); } } } public List GetDuplicationInformation() { Dictionary info = new Dictionary(); foreach (var value in _values) { if (value == null) { continue; } if (info.ContainsKey(value)) { info[value]++; } else { info[value] = 1; } } List dups = new List(); foreach (var value in _values) { if (value == null) { continue; } dups.Add(info[value]); } return dups; } public void OnAfterDeserialize() { _set.Clear(); if (_values != null) { foreach (var value in _values) { if (value != null) { _set.Add(value); } } } #if !UNITY_EDITOR _values.Clear(); #endif } public void OnBeforeSerialize() { if (_values == null) { _values = new List(); } #if UNITY_EDITOR //Delete any values not present for (int i = _values.Count; i-- != 0;) { T value = _values[i]; if (value == null) { continue; } if (!_set.Contains(value)) { _values.RemoveAt(i); } } //Add any values not accounted for foreach (var value in _set) { if (isNull(value)) { if (!_values.Query().Any(obj => isNull(obj))) { _values.Add(value); } } else { if (!_values.Contains(value)) { _values.Add(value); } } } #else //At runtime we just recreate the list _values.Clear(); _values.AddRange(this); #endif } private bool isNull(object obj) { if (obj == null) { return true; } if (obj is UnityEngine.Object) { return (obj as UnityEngine.Object) == null; } return false; } } }