ProjectDDD/Assets/_Datas/SLShared/SLSystem/SLEntity/Container.cs
2025-06-17 20:47:57 +09:00

670 lines
19 KiB (Stored with Git LFS)
C#

using System.Collections.Generic;
using System.Linq;
namespace Superlazy
{
internal abstract class SLContainerBase : SLEntity
{
public override string ID => id;
protected SLContainerBase parent;
protected string id;
}
internal class SLContainer : SLContainerBase
{
private SLEntity original;
private Dictionary<string, SLEntity> attributes;
private HashSet<string> removed;
private List<SLContainerLink> links;
private bool dangled;
public SLContainer(SLContainerBase original, SLContainerBase parent, string id)
{
this.original = original;
this.parent = parent;
this.id = id;
if (original.IsNullOrFalse() && this.parent is null == false)
{
dangled = true;
}
}
internal override SLEntity ToChild(SLContainerBase parent, string id)
{
if (id == null && parent is null) // 삭제시
{
dangled = true;
attributes?.Clear();
removed?.Clear();
original = null;
if (links != null)
{
foreach (var link in links)
{
link.DestroyLink();
}
}
}
else
{
if (dangled == false && this.parent is null == false)
{
return Clone().ToChild(parent, id);
}
else
{
dangled = false;
this.parent = parent;
this.id = id;
}
}
return this;
}
public override bool IsNumeric
{
get
{
if (IsExist())
{
SLLog.Error($"this is not value : {id}");
}
return false;
}
}
public override bool IsValue => false;
internal override bool IsExist()
{
if (dangled && (parent?.HasChild(id) ?? false)) return true;
if ((attributes?.Count ?? 0) != 0) return true;
if (original.IsNullOrFalse()) return false;
if ((removed?.Count ?? 0) == 0) return true;
if (original.Any(e => removed.Contains(e.ID) == false)) return true;
return false;
}
public override bool HasChild(string attributeKey)
{
if (attributeKey == "ID") return true;
if (dangled && (parent?.HasChild(id) ?? false)) return parent[id].HasChild(attributeKey);
if (removed?.Contains(attributeKey) ?? false) return false;
if (attributes?.ContainsKey(attributeKey) ?? false) return true;
if (original.IsNullOrFalse() == false)
{
return original.HasChild(attributeKey);
}
return false;
}
public override IEnumerator<SLEntity> GetEnumerator()
{
if (dangled && (parent?.HasChild(id) ?? false))
{
foreach (var value in parent[id])
{
yield return value;
}
yield break;
}
if (attributes?.Count > 0)
{
var keys = new List<string>(attributes.Keys);
foreach (var key in keys)
{
yield return attributes[key];
}
}
if (original)
{
foreach (var child in original.Where(e => (removed?.Contains(e.ID) ?? false) == false && (attributes?.ContainsKey(e.ID) ?? false) == false).ToList())
{
yield return this[child.ID];
}
}
}
internal override double GetDouble()
{
if (dangled && (parent?.HasChild(id) ?? false))
{
return parent[id].GetDouble();
}
if (IsExist())
{
SLLog.Error($"this is not value : {id}");
}
return 0;
}
internal override int GetInt()
{
if (dangled && (parent?.HasChild(id) ?? false))
{
return parent[id].GetInt();
}
if (IsExist())
{
SLLog.Error($"this is not value : {id}");
}
return 0;
}
internal override string GetString()
{
if (dangled && (parent?.HasChild(id) ?? false))
{
return parent[id].GetString();
}
if (IsExist() == false)
{
return string.Empty;
}
return $"{id}[{attributes?.Count ?? 0}]";
}
internal override object GetObj()
{
if (dangled && (parent?.HasChild(id) ?? false))
{
return parent[id].GetString();
}
SLLog.Error($"this is not value : {id}");
return false;
}
protected override int GetEntityHashCode()
{
if (dangled && (parent?.HasChild(id) ?? false)) return parent[id].GetHashCode();
if (attributes != null && removed != null) return attributes.GetHashCode() & removed.GetHashCode(); // TODO: 딕셔너리 대신 정밀한 해시코드를 만들어야함(성능이슈 체크)
if (attributes != null) return attributes.GetHashCode(); // TODO: 딕셔너리 대신 정밀한 해시코드를 만들어야함(성능이슈 체크)
if (removed != null) return removed.GetHashCode(); // TODO: 딕셔너리 대신 정밀한 해시코드를 만들어야함(성능이슈 체크)
if (original.IsNullOrFalse() == false) return original.GetHashCode();
return 0;
}
public override SLEntity Link()
{
if (dangled)
{
if (parent?.HasChild(id) ?? false) return parent[id].Link();
SLLog.Error("Can't make empty link");
return false;
}
if (links == null)
{
links = new List<SLContainerLink>();
}
var unusedLink = links.Find(l => l.Unused);
if (unusedLink is null == false)
{
return unusedLink;
}
var newLink = new SLContainerLink(this);
links.Add(newLink);
return newLink;
}
public override SLEntity Override()
{
if (dangled)
{
if (parent?.HasChild(id) ?? false) return parent[id].Override();
SLLog.Error("Can't make empty override");
return false;
}
return new SLContainer(this, null, null);
}
public override SLEntity this[string attributeKey]
{
get
{
if (attributeKey == "ID") return ID;
if (dangled)
{
if (parent?.HasChild(id) ?? false) return parent[id][attributeKey];
return new SLContainer(null, this, attributeKey); // 댕글
}
if (removed?.Contains(attributeKey) ?? false)
{
return new SLContainer(null, this, attributeKey);
}
if (attributes?.ContainsKey(attributeKey) ?? false)
{
return attributes[attributeKey];
}
if (original?.HasChild(attributeKey) ?? false)
{
var originalValue = original[attributeKey];
if (originalValue.IsValue)
{
return originalValue;
}
else
{
if (attributes == null) attributes = new Dictionary<string, SLEntity>();
attributes[attributeKey] = originalValue.Override().ToChild(this, attributeKey);
return attributes[attributeKey];
}
}
return new SLContainer(null, this, attributeKey);
}
set
{
// 댕글인경우
if (dangled)
{
if (parent?.HasChild(id) ?? false) // 다른개체로 교체된 댕글
{
parent[id][attributeKey] = value;
return;
}
if (value.IsNullOrFalse()) // 삭제
{
return;
}
// 새로 등록
attributes = new Dictionary<string, SLEntity>();
Modified(attributeKey);
attributes[attributeKey] = value.ToChild(this, attributeKey);
if (parent is null) return;
parent[id] = this;
}
else
{
if (attributes?.ContainsKey(attributeKey) ?? false) // 키가 있는 경우
{
if (value.IsNullOrFalse()) // 삭제
{
{
Modified(attributeKey);
var v = attributes[attributeKey];
attributes.Remove(attributeKey);
v.ToChild(null, null);
}
if (removed == null) removed = new HashSet<string>();
removed.Add(attributeKey);
if (IsExist() == false)
{
if (parent is null == false)
{
parent[id] = null;
}
}
}
else // 변경
{
if (value == attributes[attributeKey]) return;
{
Modified(attributeKey);
var v = attributes[attributeKey];
attributes.Remove(attributeKey);
v.ToChild(null, null);
}
attributes[attributeKey] = value.ToChild(this, attributeKey);
}
}
else // 키가 없는경우
{
if (original?.HasChild(attributeKey) ?? false) // 덮어쓰기
{
if (value.IsNullOrFalse()) // 삭제추가
{
if (removed == null) removed = new HashSet<string>();
Modified(attributeKey);
removed.Add(attributeKey);
if (IsExist() == false)
{
if (parent is null == false)
{
parent[id] = null;
}
}
}
else // 추가
{
if (attributes == null) attributes = new Dictionary<string, SLEntity>();
if (removed?.Contains(attributeKey) ?? false)
{
removed.Remove(attributeKey);
}
{
Modified(attributeKey);
attributes[attributeKey] = value.ToChild(this, attributeKey);
}
}
}
else
{
// 추가
if (value.IsNullOrFalse()) return;
if (attributes == null) attributes = new Dictionary<string, SLEntity>();
Modified(attributeKey);
attributes[attributeKey] = value.ToChild(this, attributeKey);
if (removed != null && removed.Contains(attributeKey))
{
removed.Remove(attributeKey);
}
}
}
}
}
}
public override SLEntity Clone()
{
if (dangled)
{
if (parent?.HasChild(id) ?? false) return parent[id].Clone();
SLLog.Error($"Can't clone dangle object: {id}");
return false;
}
var ret = new SLContainer(null, null, null);
foreach (var child in this)
{
ret[child.ID] = child.Clone();
}
return ret;
}
internal override void Move(SLEntity parent, string newID)
{
if (dangled)
{
if (parent?.HasChild(id) ?? false) this.parent[id].Move(parent, newID);
SLLog.Error($"Can't move dangle object : {id} -> {newID}");
return;
}
if (id != null) // 이미 루트가 없다면
{
var attrTemp = attributes;
this.parent[id] = false;
attributes = attrTemp;
id = null;
}
parent[id] = this;
}
private HashSet<string> modified;
public override bool IsModified(string child)
{
var ret = false;
ret |= original?.IsModified(child) ?? false;
if (child == null) ret |= (modified?.Count ?? 0) != 0;
else ret |= modified?.Contains(child) ?? false;
return ret;
}
public override void EndModified()
{
modified?.Clear();
}
private void Modified(string child)
{
if (modified == null) modified = new HashSet<string>();
modified.Add(child);
}
}
internal class SLContainerLink : SLContainerBase
{
public bool Unused => id == null;
private SLContainer original;
public SLContainerLink(SLContainer original)
{
this.original = original;
}
internal override SLEntity ToChild(SLContainerBase parent, string id)
{
if (id == null && parent is null) // 삭제시
{
this.parent = null;
this.id = null;
return this;
}
if (this.parent) return Clone().ToChild(parent, id);
this.parent = parent;
this.id = id;
return this;
}
internal void DestroyLink()
{
if (Unused) return;
parent[id] = false;
original = null;
}
public override bool IsNumeric
{
get
{
SLLog.Error($"this is not value : {id}");
return false;
}
}
public override bool IsValue
{
get
{
if (original.IsNullOrFalse()) return true;
return false;
}
}
internal override bool IsExist()
{
if (original.IsNullOrFalse()) return false;
return true;
}
public override bool HasChild(string attributeKey)
{
if (original.IsNullOrFalse()) return false;
return original.HasChild(attributeKey);
}
public override IEnumerator<SLEntity> GetEnumerator()
{
if (original.IsNullOrFalse()) return Enumerable.Empty<SLEntity>().GetEnumerator();
return original.GetEnumerator();
}
internal override double GetDouble()
{
SLLog.Error($"this is not value : {id}");
return 0;
}
internal override int GetInt()
{
SLLog.Error($"this is not value : {id}");
return 0;
}
internal override object GetObj()
{
SLLog.Error($"this is not value : {id}");
return false;
}
public override SLEntity Link()
{
if (original.IsNullOrFalse())
{
SLLog.Error($"Destroyed Link, {id}");
return null;
}
return original.Link();
}
public override SLEntity Override()
{
if (original.IsNullOrFalse())
{
SLLog.Error($"Destroyed Link, {id}");
return null;
}
return original.Override();
}
internal override string GetString()
{
if (original.IsNullOrFalse()) return string.Empty;
return $"{id} - {original}";
}
public override SLEntity this[string attributeKey]
{
get
{
if (attributeKey == "ID") return ID;
if (original.IsNullOrFalse())
{
if (parent?.HasChild(id) ?? false) return parent[id][attributeKey];
return false;
}
return original[attributeKey];
}
set
{
if (original.IsNullOrFalse())
{
if (parent?.HasChild(id) ?? false) parent[id][attributeKey] = value;
// 빈객체에 값을 넣어도 이값을 다시참조할 방법이 없음
SLLog.Error($"Dangle Link. Can't set new Value : {attributeKey}-{value}");
return;
}
else
{
original[attributeKey] = value;
}
}
}
public override SLEntity Clone()
{
if (original.IsNullOrFalse())
{
SLLog.Error($"Destroyed Link, {id}");
return null;
}
return original.Clone();
}
internal override void Move(SLEntity parent, string id)
{
if (original.IsNullOrFalse())
{
SLLog.Error($"Destroyed Link, {id}");
return;
}
this.parent[id] = null;
parent[id] = this;
}
protected override int GetEntityHashCode()
{
if (original.IsNullOrFalse())
{
SLLog.Error($"Destroyed Link, {id}");
return 0;
}
return original.GetHashCode();
}
public override bool IsModified(string child)
{
if (original.IsNullOrFalse())
{
return false;
}
return original.IsModified(child);
}
public override void EndModified()
{
if (original.IsNullOrFalse())
{
return;
}
original.EndModified();
}
}
}