Tanoda
SerializableHashSet.cs
Go to the documentation of this file.
1/******************************************************************************
2 * Copyright (C) Ultraleap, Inc. 2011-2020. *
3 * *
4 * Use subject to the terms of the Apache License 2.0 available at *
5 * http://www.apache.org/licenses/LICENSE-2.0, or another agreement *
6 * between Ultraleap and you, your company or other organization. *
7 ******************************************************************************/
8
9using System;
10using System.Collections.Generic;
11using UnityEngine;
12using Leap.Unity.Query;
13using System.Collections;
14
15namespace Leap.Unity {
16
17 [Obsolete("It is no longer required to annotate SerializableHashSets with the SHashSet attribute.")]
18 public class SHashSetAttribute : PropertyAttribute { }
19
20 public abstract class SerializableHashSetBase { }
21
24 ISerializationCallbackReceiver,
25 IEnumerable<T> {
26
27 [SerializeField]
28 private List<T> _values = new List<T>();
29
30 [NonSerialized]
31 private HashSet<T> _set = new HashSet<T>();
32
33 #region HASH SET API
34
35 public int Count {
36 get { return _set.Count; }
37 }
38
39 public bool Add(T item) {
40 return _set.Add(item);
41 }
42
43 public void Clear() {
44 _set.Clear();
45 }
46
47 public bool Contains(T item) {
48 return _set.Contains(item);
49 }
50
51 public bool Remove(T item) {
52 return _set.Remove(item);
53 }
54
55 public static implicit operator HashSet<T>(SerializableHashSet<T> serializableHashSet) {
56 return serializableHashSet._set;
57 }
58
59 public IEnumerator<T> GetEnumerator() {
60 return _set.GetEnumerator();
61 }
62
63 IEnumerator IEnumerable.GetEnumerator() {
64 return _set.GetEnumerator();
65 }
66
67 #endregion
68
69 public void ClearDuplicates() {
70 HashSet<T> takenValues = new HashSet<T>();
71 for (int i = _values.Count; i-- != 0;) {
72 var value = _values[i];
73 if (takenValues.Contains(value)) {
74 _values.RemoveAt(i);
75 } else {
76 takenValues.Add(value);
77 }
78 }
79 }
80
81 public List<int> GetDuplicationInformation() {
82 Dictionary<T, int> info = new Dictionary<T, int>();
83
84 foreach (var value in _values) {
85 if (value == null) {
86 continue;
87 }
88
89 if (info.ContainsKey(value)) {
90 info[value]++;
91 } else {
92 info[value] = 1;
93 }
94 }
95
96 List<int> dups = new List<int>();
97 foreach (var value in _values) {
98 if (value == null) {
99 continue;
100 }
101
102 dups.Add(info[value]);
103 }
104
105 return dups;
106 }
107
108 public void OnAfterDeserialize() {
109 _set.Clear();
110
111 if (_values != null) {
112 foreach (var value in _values) {
113 if (value != null) {
114 _set.Add(value);
115 }
116 }
117 }
118
119#if !UNITY_EDITOR
120 _values.Clear();
121#endif
122 }
123
124 public void OnBeforeSerialize() {
125 if (_values == null) {
126 _values = new List<T>();
127 }
128
129#if UNITY_EDITOR
130 //Delete any values not present
131 for (int i = _values.Count; i-- != 0;) {
132 T value = _values[i];
133 if (value == null) {
134 continue;
135 }
136
137 if (!_set.Contains(value)) {
138 _values.RemoveAt(i);
139 }
140 }
141
142 //Add any values not accounted for
143 foreach (var value in _set) {
144 if (isNull(value)) {
145 if (!_values.Query().Any(obj => isNull(obj))) {
146 _values.Add(value);
147 }
148 } else {
149 if (!_values.Contains(value)) {
150 _values.Add(value);
151 }
152 }
153 }
154#else
155 //At runtime we just recreate the list
156 _values.Clear();
157 _values.AddRange(this);
158#endif
159 }
160
161 private bool isNull(object obj) {
162 if (obj == null) {
163 return true;
164 }
165
166 if (obj is UnityEngine.Object) {
167 return (obj as UnityEngine.Object) == null;
168 }
169
170 return false;
171 }
172 }
173}