using System.Linq; using System.Collections; using System.Collections.Generic; namespace LeanCloud.Storage.Internal.Object { internal class LCBatch { internal HashSet objects; internal LCBatch(IEnumerable objs) { if (objs == null) { objects = new HashSet(); } else { objects = new HashSet(objs); } } internal static bool HasCircleReference(object obj, HashSet parents) { if (obj is LCObject lcObj && parents.Contains(lcObj)) { return true; } IEnumerable deps = null; if (obj is IList list) { deps = list; } else if (obj is IDictionary dict) { deps = dict.Values; } else if (obj is LCObject lcObject) { deps = lcObject.estimatedData.Values; } HashSet depParents = new HashSet(parents); if (obj is LCObject) { depParents.Add(obj as LCObject); } if (deps != null) { foreach (object dep in deps) { HashSet ps = new HashSet(depParents); if (HasCircleReference(dep, ps)) { return true; } } } return false; } internal static Stack BatchObjects(IEnumerable objects, bool containSelf) { Stack batches = new Stack(); if (containSelf) { batches.Push(new LCBatch(objects)); } HashSet deps = new HashSet(); foreach (LCObject obj in objects) { deps.UnionWith(obj.operationDict.Values.Select(op => op.GetNewObjectList())); } do { HashSet childSet = new HashSet(); foreach (object dep in deps) { IEnumerable children = null; if (dep is IList list) { children = list; } else if (dep is IDictionary dict) { children = dict; } else if (dep is LCObject lcDep && lcDep.ObjectId == null) { children = lcDep.operationDict.Values.Select(op => op.GetNewObjectList()); } if (children != null) { childSet.UnionWith(children.Cast()); } } IEnumerable depObjs = deps.Where(item => item is LCObject lcItem && lcItem.ObjectId == null) .Cast(); if (depObjs != null && depObjs.Count() > 0) { batches.Push(new LCBatch(depObjs)); } deps = childSet; } while (deps != null && deps.Count > 0); return batches; } } }