pull/2/head
Harald Wolff 2019-10-02 09:24:42 +02:00
parent c813829b51
commit 5f6674f07c
13 changed files with 404 additions and 28 deletions

View File

@ -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;
}

31
WeakHashValue.cs 100644
View File

@ -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;
}
}
}

View File

@ -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;

View File

@ -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);
}
}

View File

@ -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;
}
}
}
}

View File

@ -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\" />

View File

@ -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));
}
}
}

View File

@ -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)

View File

@ -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)

View File

@ -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; }

View File

@ -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)

View File

@ -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);
}
}
}

View File

@ -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);
}
}
}