WIP
parent
c813829b51
commit
5f6674f07c
6
Cast.cs
6
Cast.cs
|
@ -25,14 +25,16 @@ namespace ln.types
|
|||
return value;
|
||||
|
||||
object casted;
|
||||
|
||||
|
||||
if (
|
||||
!Implicit(value, targetType, out casted) &&
|
||||
!Implicit(value, value.GetType(), targetType, out casted) &&
|
||||
!Explicit(value, targetType, out casted) &&
|
||||
!Explicit(value, value.GetType(), targetType, out casted)
|
||||
)
|
||||
throw new InvalidCastException();
|
||||
{
|
||||
casted = Convert.ChangeType(value, targetType);
|
||||
}
|
||||
return casted;
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,31 @@
|
|||
using System;
|
||||
namespace ln.types
|
||||
{
|
||||
class WeakHashValue<T> where T:class
|
||||
{
|
||||
readonly int keyHashCode;
|
||||
|
||||
WeakReference<T> reference;
|
||||
|
||||
public T Value => reference.TryGetTarget(out T target) ? target : null;
|
||||
public bool IsStrong => reference.TryGetTarget(out T target);
|
||||
|
||||
public WeakHashValue(T value)
|
||||
{
|
||||
reference = new WeakReference<T>(value);
|
||||
keyHashCode = value.GetHashCode();
|
||||
}
|
||||
|
||||
public override int GetHashCode() => keyHashCode;
|
||||
public override bool Equals(object obj)
|
||||
{
|
||||
T value = Value;
|
||||
if ((value != null) && (obj is WeakHashValue<T>))
|
||||
{
|
||||
WeakHashValue<T> other = obj as WeakHashValue<T>;
|
||||
return object.Equals(value,other.Value);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -30,11 +30,15 @@ namespace ln.types.btree
|
|||
|
||||
public BTree()
|
||||
{
|
||||
if (!typeof(K).GetInterfaces().Contains(typeof(IComparable<K>)))
|
||||
throw new ArgumentException("BTree need to be constructed with Comparer<K> if T is not providing IComparable<K>");
|
||||
|
||||
Comparison = (K x, K y) => ((IComparable<K>)x).CompareTo(y);
|
||||
}
|
||||
if (!typeof(K).GetInterfaces().Contains(typeof(IComparable<K>)))
|
||||
{
|
||||
Comparison = (K x, K y) => x.GetHashCode() - y.GetHashCode();
|
||||
}
|
||||
else
|
||||
{
|
||||
Comparison = (K x, K y) => ((IComparable<K>)x).CompareTo(y);
|
||||
}
|
||||
}
|
||||
public BTree(Comparison<K> comparison)
|
||||
{
|
||||
Comparison = comparison;
|
||||
|
@ -62,7 +66,7 @@ namespace ln.types.btree
|
|||
}
|
||||
}
|
||||
}
|
||||
public Boolean TryGet(K key,ref V value)
|
||||
public Boolean TryGet(K key,ref V value)
|
||||
{
|
||||
TreeNode node = Find(key);
|
||||
if (object.ReferenceEquals(node, null))
|
||||
|
@ -112,7 +116,28 @@ namespace ln.types.btree
|
|||
return Values.Contains(value);
|
||||
}
|
||||
|
||||
public void Clear()
|
||||
public K GetKey(K key)
|
||||
{
|
||||
if (TryGetKey(key, out K storedKey))
|
||||
return storedKey;
|
||||
throw new KeyNotFoundException();
|
||||
}
|
||||
public bool TryGetKey(K key,out K storedKey)
|
||||
{
|
||||
TreeNode treeNode = Find(key);
|
||||
if (treeNode == null)
|
||||
{
|
||||
storedKey = default(K);
|
||||
return false;
|
||||
} else
|
||||
{
|
||||
storedKey = treeNode.Key;
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public void Clear()
|
||||
{
|
||||
headNode = null;
|
||||
count = 0;
|
||||
|
|
|
@ -107,7 +107,12 @@ namespace ln.types.btree
|
|||
return _values.Count;
|
||||
}
|
||||
|
||||
public IEnumerable<K> Keys => bTree.Keys;
|
||||
public void Clear()
|
||||
{
|
||||
bTree.Clear();
|
||||
}
|
||||
|
||||
public IEnumerable<K> Keys => bTree.Keys;
|
||||
public IEnumerable<V> Values => bTree.Values.SelectMany(vl => vl);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,217 @@
|
|||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using ln.types.btree;
|
||||
using System.Linq;
|
||||
|
||||
namespace ln.types.collections
|
||||
{
|
||||
public class WeakKeyDictionary<K, V> : IDictionary<K, V> where K : class
|
||||
{
|
||||
BTreeValueList<int, WeakKeyValuePair<K, V>> store = new BTreeValueList<int, WeakKeyValuePair<K, V>>();
|
||||
|
||||
public WeakKeyDictionary()
|
||||
{
|
||||
}
|
||||
|
||||
public V this[K key]
|
||||
{
|
||||
get
|
||||
{
|
||||
if (TryGetValue(key, out V value))
|
||||
return value;
|
||||
throw new KeyNotFoundException();
|
||||
}
|
||||
set
|
||||
{
|
||||
SetValue(key, value, true);
|
||||
}
|
||||
}
|
||||
|
||||
private WeakKeyValuePair<K, V> FindKeyValuePair(K key)
|
||||
{
|
||||
int keyHashCode = key.GetHashCode();
|
||||
if (store.ContainsKey(keyHashCode))
|
||||
foreach (WeakKeyValuePair<K, V> weakKeyValuePair in store[keyHashCode])
|
||||
{
|
||||
K weakKey = weakKeyValuePair.Key;
|
||||
if (weakKey == null)
|
||||
{
|
||||
store.Remove(keyHashCode, weakKeyValuePair);
|
||||
}
|
||||
else if (Object.Equals(key, weakKey))
|
||||
{
|
||||
return weakKeyValuePair;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public bool TryGetValue(K key, out V value)
|
||||
{
|
||||
WeakKeyValuePair<K, V> weakKeyValuePair = FindKeyValuePair(key);
|
||||
if (weakKeyValuePair != null)
|
||||
{
|
||||
value = weakKeyValuePair.Value;
|
||||
return true;
|
||||
}
|
||||
value = default(V);
|
||||
return false;
|
||||
}
|
||||
|
||||
public void SetValue(K key, V value) => SetValue(key, value, false);
|
||||
public bool SetValue(K key, V value, bool replace)
|
||||
{
|
||||
WeakKeyValuePair<K, V> weakKeyValuePair = FindKeyValuePair(key);
|
||||
if (weakKeyValuePair == null)
|
||||
{
|
||||
weakKeyValuePair = new WeakKeyValuePair<K, V>(key, value);
|
||||
store.Add(key.GetHashCode(), weakKeyValuePair);
|
||||
return false;
|
||||
} else if (replace)
|
||||
{
|
||||
weakKeyValuePair.Value = value;
|
||||
return true;
|
||||
} else
|
||||
{
|
||||
throw new ArgumentException("Key already present");
|
||||
}
|
||||
}
|
||||
|
||||
public ICollection<K> Keys
|
||||
{
|
||||
get
|
||||
{
|
||||
List<K> keys = new List<K>();
|
||||
|
||||
foreach (WeakKeyValuePair<K,V> weakKeyValuePair in store.Values)
|
||||
{
|
||||
if (weakKeyValuePair.IsStrong)
|
||||
keys.Add(weakKeyValuePair.Key);
|
||||
else
|
||||
store.Remove(weakKeyValuePair.keyHashCode, weakKeyValuePair);
|
||||
}
|
||||
|
||||
return keys;
|
||||
}
|
||||
}
|
||||
|
||||
public ICollection<V> Values
|
||||
{
|
||||
get
|
||||
{
|
||||
List<V> values = new List<V>();
|
||||
|
||||
foreach (WeakKeyValuePair<K, V> weakKeyValuePair in store.Values)
|
||||
{
|
||||
if (weakKeyValuePair.IsStrong)
|
||||
values.Add(weakKeyValuePair.Value);
|
||||
else
|
||||
store.Remove(weakKeyValuePair.keyHashCode, weakKeyValuePair);
|
||||
}
|
||||
|
||||
return values;
|
||||
}
|
||||
}
|
||||
|
||||
public int Count => store.Keys.Count();
|
||||
public bool IsReadOnly => false;
|
||||
|
||||
public void Add(K key, V value)
|
||||
{
|
||||
SetValue(key, value);
|
||||
}
|
||||
public void Add(KeyValuePair<K, V> item) => Add(item.Key, item.Value);
|
||||
|
||||
public void Clear() => store.Clear();
|
||||
public bool Contains(KeyValuePair<K, V> item)
|
||||
{
|
||||
WeakKeyValuePair<K, V> weakKeyValuePair = FindKeyValuePair(item.Key);
|
||||
if ((weakKeyValuePair != null) && weakKeyValuePair.IsStrong)
|
||||
{
|
||||
return Object.Equals(item.Value, weakKeyValuePair.Value);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
public bool ContainsKey(K key)
|
||||
{
|
||||
WeakKeyValuePair<K, V> weakKeyValuePair = FindKeyValuePair(key);
|
||||
return (weakKeyValuePair != null) && weakKeyValuePair.IsStrong;
|
||||
}
|
||||
|
||||
public void CopyTo(KeyValuePair<K, V>[] array, int arrayIndex)
|
||||
{
|
||||
foreach (WeakKeyValuePair<K, V> weakKeyValuePair in store.Values)
|
||||
{
|
||||
if (weakKeyValuePair.IsStrong)
|
||||
array[arrayIndex++] = new KeyValuePair<K, V>(weakKeyValuePair.Key,weakKeyValuePair.Value);
|
||||
}
|
||||
}
|
||||
|
||||
public IEnumerator<KeyValuePair<K, V>> GetEnumerator()
|
||||
{
|
||||
foreach (WeakKeyValuePair<K,V> weakKeyValuePair in store.Values)
|
||||
{
|
||||
if (weakKeyValuePair.IsStrong)
|
||||
yield return new KeyValuePair<K, V>(weakKeyValuePair.Key,weakKeyValuePair.Value);
|
||||
}
|
||||
}
|
||||
|
||||
public bool Remove(K key)
|
||||
{
|
||||
WeakKeyValuePair<K, V> weakKeyValuePair = FindKeyValuePair(key);
|
||||
if (weakKeyValuePair != null)
|
||||
{
|
||||
store.Remove(weakKeyValuePair.keyHashCode, weakKeyValuePair);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public bool Remove(KeyValuePair<K, V> item)
|
||||
{
|
||||
WeakKeyValuePair<K, V> weakKeyValuePair = FindKeyValuePair(item.Key);
|
||||
if ((weakKeyValuePair != null) && (object.Equals(item.Value, weakKeyValuePair.Value)))
|
||||
{
|
||||
store.Remove(weakKeyValuePair.keyHashCode, weakKeyValuePair);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
|
||||
|
||||
class WeakKeyValuePair<TK,TV> where TK: class
|
||||
{
|
||||
public readonly int keyHashCode;
|
||||
|
||||
WeakReference<TK> reference;
|
||||
|
||||
public TK Key => reference.TryGetTarget(out TK target) ? target : null;
|
||||
public bool IsStrong => reference.TryGetTarget(out TK target);
|
||||
|
||||
public V Value { get; set; }
|
||||
|
||||
public WeakKeyValuePair(TK key,V value)
|
||||
{
|
||||
reference = new WeakReference<TK>(key);
|
||||
keyHashCode = value.GetHashCode();
|
||||
Value = value;
|
||||
}
|
||||
|
||||
public override int GetHashCode() => keyHashCode;
|
||||
public override bool Equals(object obj)
|
||||
{
|
||||
TK key = Key;
|
||||
if ((key != null) && (obj is WeakKeyValuePair<TK,TV>))
|
||||
{
|
||||
WeakKeyValuePair<TK, TV> other = obj as WeakKeyValuePair<TK, TV>;
|
||||
return object.Equals(key, other.Value);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
|
@ -119,6 +119,9 @@
|
|||
<Compile Include="odb\ng\diff\Diff.cs" />
|
||||
<Compile Include="odb\ng\diff\DocumentDiff.cs" />
|
||||
<Compile Include="odb\ng\diff\ListDiff.cs" />
|
||||
<Compile Include="collections\WeakKeyDictionary.cs" />
|
||||
<Compile Include="test\WeakKeyDictionaryTests.cs" />
|
||||
<Compile Include="WeakHashValue.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Folder Include="odb\" />
|
||||
|
|
|
@ -166,7 +166,7 @@ namespace ln.types.odb.ng
|
|||
|
||||
static Document()
|
||||
{
|
||||
RegisterDeserializer(0x1001, (b,o,l) => new Document(b,o+16,l));
|
||||
RegisterDeserializer(0x1001, (b,o,l) => new Document(b,o,l));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -41,7 +41,7 @@ namespace ln.types.odb.ng
|
|||
if (object.ReferenceEquals(value,null))
|
||||
value = ODBNull.Instance;
|
||||
|
||||
return IF(propertyName, (v) => value.Equals(v));
|
||||
return IF(propertyName, (v) => value.CompareTo(v)==0);
|
||||
}
|
||||
public static Query EqualsNot<T>(string propertyName, ODBEntity value) => EqualsNot(IndexPath.TranslatePropertyPath(typeof(T), propertyName), value);
|
||||
public static Query EqualsNot(String propertyName, ODBEntity value)
|
||||
|
@ -49,13 +49,18 @@ namespace ln.types.odb.ng
|
|||
if (object.ReferenceEquals(value, null))
|
||||
value = ODBNull.Instance;
|
||||
|
||||
return IF(propertyName, (v) => !value.Equals(v));
|
||||
return IF(propertyName, (v) => value.CompareTo(v)!=0);
|
||||
}
|
||||
|
||||
public static Query Equals<T>(string propertyName, ODBEntity[] values) => Equals(IndexPath.TranslatePropertyPath(typeof(T), propertyName), values);
|
||||
public static Query Equals(String propertyName, ODBEntity[] values)
|
||||
{
|
||||
return IF(propertyName, (v) => values.Contains(v));
|
||||
return IF(propertyName, (v) => {
|
||||
foreach (ODBEntity value in values)
|
||||
if (value.CompareTo(v) == 0)
|
||||
return true;
|
||||
return false;
|
||||
});
|
||||
}
|
||||
|
||||
public static Query Contains<T, A>(string propertyName, IEnumerable<A> values)
|
||||
|
|
|
@ -4,20 +4,21 @@ using System.Reflection;
|
|||
using System.Collections.Generic;
|
||||
using ln.logging;
|
||||
using System.Linq;
|
||||
using ln.types.collections;
|
||||
|
||||
namespace ln.types.odb.ng.mappings
|
||||
{
|
||||
|
||||
public class ClassMapping : IODBMapping
|
||||
{
|
||||
WeakKeyDictionary<object, Guid> cache = new WeakKeyDictionary<object, Guid>();
|
||||
|
||||
|
||||
public delegate object GetID(object o);
|
||||
public delegate object SetID(object o, object id);
|
||||
|
||||
public Type MappedType { get; }
|
||||
|
||||
//public GetID getID { get; private set; } = (o) => Guid.NewGuid();
|
||||
//public Type IDType { get; private set; }
|
||||
|
||||
List<FieldInfo> mappedFields = new List<FieldInfo>();
|
||||
|
||||
public ClassMapping(Type type)
|
||||
|
@ -139,8 +140,11 @@ namespace ln.types.odb.ng.mappings
|
|||
{
|
||||
if (Object.ReferenceEquals(value, null))
|
||||
return ODBNull.Instance;
|
||||
|
||||
return MapDocument(mapper, Guid.Empty, value);
|
||||
|
||||
if (!cache.TryGetValue(value, out Guid documentID))
|
||||
documentID = Guid.NewGuid();
|
||||
|
||||
return MapDocument(mapper, documentID, value);
|
||||
}
|
||||
|
||||
public Type GetFieldType(Mapper mapper,string fieldName)
|
||||
|
|
|
@ -7,7 +7,7 @@ using ln.types.threads;
|
|||
using ln.types.odb.ng.diff;
|
||||
namespace ln.types.odb.ng.storage.session
|
||||
{
|
||||
class SessionStorage : ChainedStorage
|
||||
public class SessionStorage : ChainedStorage
|
||||
{
|
||||
public SessionStorageContainer SessionContainer { get; }
|
||||
|
||||
|
|
|
@ -25,7 +25,7 @@ namespace ln.types.odb.values
|
|||
public override byte[] GetStorageBytes() => BitConverter.GetBytes((uint)Value);
|
||||
protected override int compare(ODBEntity other)
|
||||
{
|
||||
long d = (long)Value - (long)(other as ODBValue).Value;
|
||||
long d = Convert.ToInt64((uint)Value) - Convert.ToInt64((uint)(other as ODBValue).Value);
|
||||
if (d == 0)
|
||||
return 0;
|
||||
if (d < 0)
|
||||
|
|
|
@ -1,15 +1,15 @@
|
|||
using NUnit.Framework;
|
||||
using System;
|
||||
using ln.types.odb.ng;
|
||||
using ln.types.odb.ng.storage;
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using ln.types.odb.values;
|
||||
using ln.types.odb.ng;
|
||||
using ln.types.odb.ng.storage;
|
||||
using ln.types.odb.ng.storage.fs;
|
||||
using ln.types.odb.ng.storage.session;
|
||||
using ln.types.odb.values;
|
||||
using NUnit.Framework;
|
||||
namespace ln.types.test
|
||||
{
|
||||
[TestFixture()]
|
||||
[TestFixture()]
|
||||
public class ODBTests
|
||||
{
|
||||
[SetUp()]
|
||||
|
@ -48,6 +48,9 @@ namespace ln.types.test
|
|||
|
||||
document[new ODBStringValue("FeldA")] = new ODBStringValue("FeldA");
|
||||
document[new ODBStringValue("FeldB")] = new ODBStringValue("FeldB");
|
||||
Document nestedDocument = new Document();
|
||||
nestedDocument["EineZeichenkette"] = new ODBStringValue("Ich bin eine Zeichenkette");
|
||||
document[new ODBStringValue("FeldDokument")] = nestedDocument;
|
||||
|
||||
storage.Save(document);
|
||||
|
||||
|
@ -110,6 +113,9 @@ namespace ln.types.test
|
|||
Assert.AreEqual(1, mapper.Load<Person>(Query.Equals<Person>("FirstName", "Harald")).Count());
|
||||
Assert.AreEqual(1, mapper.Load<Person>(Query.Equals<Person>("FirstName", "Liesschen")).Count());
|
||||
|
||||
Person harald = mapper.Load<Person>(Query.Equals<Person>("FirstName", "Harald")).FirstOrDefault();
|
||||
|
||||
Assert.AreEqual(persons[0], harald);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -161,12 +167,24 @@ namespace ln.types.test
|
|||
|
||||
public class Person
|
||||
{
|
||||
public readonly Guid ID;
|
||||
|
||||
public String FirstName = "";
|
||||
public String[] MiddleNames = new string[0];
|
||||
public String LastName = "";
|
||||
|
||||
public int Age = 18;
|
||||
}
|
||||
|
||||
public Person()
|
||||
{
|
||||
ID = Guid.NewGuid();
|
||||
}
|
||||
|
||||
public override int GetHashCode() => ID.GetHashCode();
|
||||
public override bool Equals(object obj) => (obj is Person) && ID.Equals((obj as Person).ID);
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,66 @@
|
|||
using System;
|
||||
using NUnit.Framework;
|
||||
using ln.types.collections;
|
||||
using System.Threading;
|
||||
namespace ln.types.test
|
||||
{
|
||||
[TestFixture]
|
||||
public class WeakKeyDictionaryTests
|
||||
{
|
||||
class KeyClass
|
||||
{
|
||||
static int next = 1;
|
||||
|
||||
public readonly int Value = next++;
|
||||
|
||||
public override int GetHashCode() => Value;
|
||||
public override bool Equals(object obj)
|
||||
{
|
||||
return ((obj is KeyClass) && ((obj as KeyClass).Value == Value));
|
||||
}
|
||||
public override string ToString()
|
||||
{
|
||||
return string.Format("[KeyClass Value={0}]",Value);
|
||||
}
|
||||
}
|
||||
|
||||
KeyClass[] keys = new KeyClass[1024];
|
||||
WeakKeyDictionary<KeyClass, int> testDict = new WeakKeyDictionary<KeyClass, int>();
|
||||
|
||||
public void Fill()
|
||||
{
|
||||
for (int n = 0; n < keys.Length; n++)
|
||||
{
|
||||
keys[n] = new KeyClass();
|
||||
testDict.Add(keys[n], n);
|
||||
}
|
||||
}
|
||||
|
||||
public void Strip()
|
||||
{
|
||||
keys[0] = null;
|
||||
keys[keys.Length - 1] = null;
|
||||
}
|
||||
|
||||
[TestCase()]
|
||||
public void TestWeakKeyDictionary()
|
||||
{
|
||||
Fill();
|
||||
|
||||
Thread.Sleep(250);
|
||||
|
||||
Assert.AreEqual(keys.Length, testDict.Count);
|
||||
Assert.AreEqual(keys.Length, testDict.Keys.Count);
|
||||
|
||||
Strip();
|
||||
|
||||
Thread.Sleep(250);
|
||||
|
||||
GC.Collect();
|
||||
|
||||
Thread.Sleep(250);
|
||||
|
||||
Assert.AreEqual(keys.Length-2, testDict.Keys.Count);
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue