// // Copyright (c) 2019- yutopp (yutopp@gmail.com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at https://www.boost.org/LICENSE_1_0.txt) // using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; namespace VGltf.Unity { public sealed class IndexedResourceDict : IDisposable where V : UnityEngine.Object { readonly IndexedDisposableResourceDict> _internal; public IndexedResourceDict(IEqualityComparer equalityComparer = default) { _internal = new IndexedDisposableResourceDict>(equalityComparer); } public IndexedResource Add(K k, int index, string name, V v) { var res = _internal.Add(k, index, name, new Utils.DestroyOnDispose(v)); return Unwrap(res); } public IndexedResource this[K k] { get => Unwrap(_internal[k]); } public IndexedResource GetOrCall(K k, Func> generator) { return Unwrap(_internal.GetOrCall(k, () => Wrap(generator()))); } public async Task> GetOrCallAsync(K k, Func>> generator) { return Unwrap(await _internal.GetOrCallAsync(k, async () => Wrap(await generator()))); } public IEnumerable Map(Func, T> f) { return _internal.Map(wres => f(Unwrap(wres))); } public bool Contains(K k) { return _internal.Contains(k); } public bool TryGetValue(K k, out IndexedResource res) { var found = _internal.TryGetValue(k, out var wres); if (found) { res = Unwrap(wres); return true; } res = default; return false; } public bool TryGetValueByName(string k, out IndexedResource res) { var found = _internal.TryGetValueByName(k, out var wres); if (found) { res = Unwrap(wres); return true; } res = default; return false; } public void Dispose() { _internal.Dispose(); } static IndexedResource> Wrap(IndexedResource wres) { return new IndexedResource>( index: wres.Index, value: new Utils.DestroyOnDispose(wres.Value) ); } static IndexedResource Unwrap(IndexedResource> wres) { return new IndexedResource( index: wres.Index, value: wres.Value.Value ); } } public sealed class IndexedDisposableResourceDict : IDisposable where V : IDisposable { readonly Dictionary> _dict; readonly MultiMap> _nameDict = new MultiMap>(); public IndexedDisposableResourceDict(IEqualityComparer equalityComparer = default) { _dict = new Dictionary>(equalityComparer); } public IndexedResource Add(K k, int index, string name, V v) { var resource = new IndexedResource(index, v); _dict.Add(k, resource); if (!string.IsNullOrEmpty(name)) { _nameDict.Add(name, resource); } return resource; } public IndexedResource this[K k] { get => _dict[k]; } public IndexedResource GetOrCall(K k, Func> generator) { // Cached by reference if (TryGetValue(k, out var res)) { return res; } return generator(); } public async Task> GetOrCallAsync(K k, Func>> generator) { // Cached by reference if (TryGetValue(k, out var res)) { return res; } return await generator(); } public IEnumerable Map(Func, T> f) { return _dict.Select(kv => f(kv.Value)); } public bool Contains(K k) { return _dict.ContainsKey(k); } public bool TryGetValue(K k, out IndexedResource res) { return _dict.TryGetValue(k, out res); } public bool TryGetValueByName(string k, out IndexedResource res) { if (!_nameDict.TryGetValues(k, out var resList)) { res = default; return false; } // Can not distinguish that there is no element or more elements... (bad interface) if (resList.Count != 1) { res = default; return false; } res = resList.First(); return true; } public void Dispose() { foreach (var v in _dict.Values) { v.Value.Dispose(); } _dict.Clear(); _nameDict.Clear(); } } sealed class MultiMap { readonly Dictionary> _dict = new Dictionary>(); public void Add(K key, V value) { if (_dict.TryGetValue(key, out var values)) { values.Add(value); return; } _dict.Add(key, new List{ value }); } public bool TryGetValues(K key, out List values) { return _dict.TryGetValue(key, out values); } public void Clear() { _dict.Clear(); } } }