dev_timestamp
Harald Wolff 2019-03-26 12:54:02 +01:00
parent aa65fc9f4e
commit 035be47c45
31 changed files with 2395 additions and 589 deletions

43
CIDR.cs
View File

@ -13,6 +13,7 @@ using System.Linq;
using System.Collections.Generic; using System.Collections.Generic;
using System.Collections; using System.Collections;
using Newtonsoft.Json; using Newtonsoft.Json;
using LiteDB;
namespace ln.types namespace ln.types
{ {
@ -35,7 +36,7 @@ namespace ln.types
return new CIDR(ip, w); return new CIDR(ip, w);
} }
} }
return new CIDR(ip,32); return new CIDR(ip, 32);
} }
private readonly uint _ip; private readonly uint _ip;
@ -45,7 +46,7 @@ namespace ln.types
public CIDR Network => new CIDR(_ip & _netmask, _netmask); public CIDR Network => new CIDR(_ip & _netmask, _netmask);
public CIDR Host => new CIDR(_ip, 0xffffffff); public CIDR Host => new CIDR(_ip, 0xffffffff);
public int Size => (1 << (32 - MaskWidth)); public int Size => (1 << (32 - MaskWidth));
public byte[] IPBytes public byte[] IPBytes
{ {
@ -115,12 +116,12 @@ namespace ln.types
for (w = 32; w > 0; w--) for (w = 32; w > 0; w--)
{ {
if ((nm & (1 << (int)(32-w))) != 0) if ((nm & (1 << (int)(32 - w))) != 0)
break; break;
} }
for (uint n = w; n > 0; n--) for (uint n = w; n > 0; n--)
{ {
if ((nm & (1 << (int)(32-n))) == 0) if ((nm & (1 << (int)(32 - n))) == 0)
throw new FormatException("Netmask with holes"); throw new FormatException("Netmask with holes");
} }
@ -136,7 +137,7 @@ namespace ln.types
uint newmask = maskFromWidth((uint)(MaskWidth + bits)); uint newmask = maskFromWidth((uint)(MaskWidth + bits));
uint nip = _ip; uint nip = _ip;
CIDR[] result = new CIDR[count]; CIDR[] result = new CIDR[count];
for (int n=0;n<count;n++) for (int n = 0; n < count; n++)
{ {
nip += (uint)(1 << (32 - MaskWidth - bits)); nip += (uint)(1 << (32 - MaskWidth - bits));
result[n] = new CIDR(nip, newmask); result[n] = new CIDR(nip, newmask);
@ -150,23 +151,32 @@ namespace ln.types
if (_netmask == 0xFFFFFFFF) if (_netmask == 0xFFFFFFFF)
return String.Format("{0}", String.Join(".", IPBytes.Select((x) => x.ToString()))); return String.Format("{0}", String.Join(".", IPBytes.Select((x) => x.ToString())));
else else
return String.Format("{0}/{1}", String.Join(".", IPBytes.Select((x) => x.ToString())),getNetWidth(_netmask)); return String.Format("{0}/{1}", String.Join(".", IPBytes.Select((x) => x.ToString())), getNetWidth(_netmask));
} }
public static implicit operator IPAddress(CIDR cidr) public static implicit operator IPAddress(CIDR cidr)
{ {
return new IPAddress( cidr.IPBytes ); return new IPAddress(cidr.IPBytes);
} }
public static implicit operator CIDR(IPAddress iPAddress) public static implicit operator CIDR(IPAddress iPAddress)
{ {
return new CIDR(BitConverter.ToUInt32(iPAddress.GetAddressBytes().Reverse().ToArray(),0),0xFFFFFFFF); return new CIDR(BitConverter.ToUInt32(iPAddress.GetAddressBytes().Reverse().ToArray(), 0), 0xFFFFFFFF);
} }
public bool Contains(CIDR you) public bool Contains(CIDR you)
{ {
return (you.MaskWidth >= MaskWidth) && ((you._ip & _netmask)==(_ip & _netmask)); return (you.MaskWidth >= MaskWidth) && ((you._ip & _netmask) == (_ip & _netmask));
} }
public bool Contains(IEnumerable<CIDR> candidates)
{
foreach (CIDR ip in candidates)
if (Contains(ip))
return true;
return false;
}
public override int GetHashCode() public override int GetHashCode()
{ {
return (int)(_ip ^ _netmask); return (int)(_ip ^ _netmask);
@ -225,13 +235,17 @@ namespace ln.types
} }
static bool ___init = ____init(); static CIDR()
static bool ____init()
{ {
BsonMapper.Global.RegisterType<CIDR>(
serialize: (ip) => ip.ToString(),
deserialize: (bson) => CIDR.Parse(bson.AsString)
);
List<JsonConverter> converters = new List<JsonConverter>(); List<JsonConverter> converters = new List<JsonConverter>();
converters.Add(new CIDRJsonConverter()); converters.Add(new CIDRJsonConverter());
JsonConvert.DefaultSettings = () => new JsonSerializerSettings { Converters = converters }; JsonConvert.DefaultSettings = () => new JsonSerializerSettings { Converters = converters };
return true;
} }
} }
@ -243,15 +257,16 @@ namespace ln.types
return (objectType == typeof(CIDR)); return (objectType == typeof(CIDR));
} }
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) public override object ReadJson(JsonReader reader, Type objectType, object existingValue, Newtonsoft.Json.JsonSerializer serializer)
{ {
return CIDR.Parse(reader.ReadAsString()); return CIDR.Parse(reader.ReadAsString());
} }
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) public override void WriteJson(JsonWriter writer, object value, Newtonsoft.Json.JsonSerializer serializer)
{ {
writer.WriteValue((value as CIDR).ToString()); writer.WriteValue((value as CIDR).ToString());
} }
} }
} }

View File

@ -1,4 +1,5 @@
using System; using System;
using System.IO;
namespace ln.types namespace ln.types
{ {
public static class Extensions public static class Extensions
@ -14,5 +15,17 @@ namespace ln.types
return true; return true;
} }
public static int ReadInteger(this Stream stream)
{
byte[] b = new byte[4];
stream.Read(b, 0, 4);
return BitConverter.ToInt32(b,0);
}
public static void WriteInteger(this Stream stream,int i)
{
stream.Write(BitConverter.GetBytes(i), 0, 4);
}
} }
} }

34
GeoLocation.cs 100644
View File

@ -0,0 +1,34 @@
// /**
// * File: GeoLocation.cs
// * Author: haraldwolff
// *
// * This file and it's content is copyrighted by the Author and / or copyright holder.
// * Any use wihtout proper permission is illegal and may lead to legal actions.
// *
// *
// **/
using System;
namespace ln.types
{
public struct GeoLocation
{
public double Latitude;
public double Longitude;
public GeoLocation(double latitude,double longitude)
{
Latitude = latitude;
Longitude = longitude;
}
public override string ToString()
{
return String.Format("{0:F}{1}{2:F}{3}",
(Latitude < 0) ? -Latitude : Latitude,
(Latitude < 0) ? 'S':'N',
(Longitude < 0) ? -Longitude : Longitude,
(Longitude < 0) ? 'W' : 'E'
);
}
}
}

246
URI.cs 100644
View File

@ -0,0 +1,246 @@
// /**
// * File: URI.cs
// * Author: haraldwolff
// *
// * This file and it's content is copyrighted by the Author and / or copyright holder.
// * Any use wihtout proper permission is illegal and may lead to legal actions.
// *
// *
// **/
using System;
using System.Text;
namespace ln.types
{
/**
* Quick and Dirty RFC3986 URI
*
**/
public class URI
{
public String Scheme { get; private set; } = String.Empty;
public String Authority { get; private set; } = String.Empty;
public String[] UserInfo { get; private set; } = new String[0];
public String Host { get; private set; } = String.Empty;
public String Port { get; private set; } = String.Empty;
public String Path { get; private set; } = String.Empty;
public String Query { get; private set; } = String.Empty;
public String Fragment { get; private set; } = String.Empty;
private URI()
{
}
public URI(String uri)
{
Parse(uri);
ParseAuthority();
}
public URI(String scheme, String authority, string path)
{
Parse(String.Format("{0}://{1}{2}", scheme, authority, path));
ParseAuthority();
}
public URI(String scheme,String authority,string path,string query,string fragment)
{
Scheme = scheme;
Authority = authority;
Path = path;
Query = query;
Fragment = fragment;
ParseAuthority();
}
public URI(URI uri, string path)
{
Parse(String.Format("{0}://{1}{2}", uri.Scheme, uri.Authority, path));
ParseAuthority();
}
public URI Follow(String path)
{
if (path.StartsWith("/",StringComparison.InvariantCulture))
{
return new URI(Scheme, Authority, path);
} else if (Path.EndsWith("/",StringComparison.InvariantCulture) || path.StartsWith("?",StringComparison.InvariantCulture) || path.StartsWith("#", StringComparison.InvariantCulture))
{
return new URI(Scheme, Authority, String.Format("{0}{1}", Path, path));
}
else
{
int indSlash = Path.LastIndexOf('/');
return new URI(Scheme, Authority, String.Format("{0}/{1}",Path.Substring(0,indSlash),path));
}
}
private void Parse(String uri)
{
char[] chUri = uri.ToCharArray();
int n = 0;
int m = 0;
// Scheme
while ((chUri[n] != ':') && ((++n) < chUri.Length)) { };
if (n < 2)
throw new FormatException(String.Format("URL malformed: {0}",uri));
Scheme = new string(chUri, 0, n);
n++;
if (n < chUri.Length)
{
if ((chUri.Length - n > 1) && (chUri[n] == '/') && (chUri[n+1] == '/'))
{
// Authority
n += 2;
m = n;
while (
(m < chUri.Length) &&
(chUri[m] != '/') &&
(chUri[m] != '?') &&
(chUri[m] != '#')
) { m++; }
Authority = new string(chUri, n, (m - n));
n = m;
}
// Path
m = n;
while (
(m < chUri.Length) &&
(chUri[m] != '?') &&
(chUri[m] != '#')
)
{ m++; }
Path = new string(chUri, n, (m - n));
n = m;
if (n < chUri.Length)
{
if (chUri[n] == '?')
{
n++;
m = n;
while (
(m < chUri.Length) &&
(chUri[m] != '#')
)
{ m++; }
Query = new string(chUri, n, (m - n));
n = m;
}
if ((n<chUri.Length) && (chUri[n] == '#'))
{
n++;
m = n;
while (
(m < chUri.Length) &&
(chUri[m] != '#')
)
{ m++; }
Fragment = new string(chUri, n, (m - n));
n = m;
}
if (n < chUri.Length)
throw new FormatException(String.Format("Malformed URI: {0}", uri));
}
}
}
private void ParseAuthority()
{
int indAt = Authority.IndexOf('@');
if (indAt != -1)
{
UserInfo = Authority.Substring(0, indAt).Split(':');
}
indAt++;
int indPort = Authority.IndexOf(':', indAt);
if (indPort != -1)
{
Host = Authority.Substring(indAt, indPort - indAt);
Port = Authority.Substring(indPort + 1);
}
else
{
Host = Authority.Substring(indAt);
}
}
public override string ToString()
{
StringBuilder stringBuilder = new StringBuilder();
stringBuilder.Append(Scheme);
stringBuilder.Append(':');
if (!String.Empty.Equals(Authority))
{
stringBuilder.Append("//");
if (UserInfo.Length > 0)
{
stringBuilder.Append(UserInfo[0]);
stringBuilder.Append('@');
}
stringBuilder.Append(Host);
if (!String.Empty.Equals(Port))
{
stringBuilder.Append(':');
stringBuilder.Append(Port);
}
}
stringBuilder.Append(Path);
if (!string.Empty.Equals(Query))
{
stringBuilder.Append("?");
stringBuilder.Append(Query);
}
if (!string.Empty.Equals(Fragment))
{
stringBuilder.Append('#');
stringBuilder.Append(Fragment);
}
return stringBuilder.ToString();
}
private int GetHashCode(String s)
{
return (s == null) ? -1 : s.GetHashCode();
}
public override int GetHashCode()
{
return GetHashCode(Scheme) ^ GetHashCode(Authority) ^ GetHashCode(Path) ^ GetHashCode(Query) ^ GetHashCode(Fragment);
}
public override bool Equals(object obj)
{
if (obj is URI)
{
URI other = obj as URI;
return Scheme.Equals(other.Scheme) && Authority.Equals(other.Authority) && Path.Equals(other.Path) && Query.Equals(other.Query) && Fragment.Equals(other.Fragment);
}
return false;
}
}
}

View File

@ -38,6 +38,9 @@
<HintPath>..\packages\Castle.Core.4.3.1\lib\net45\Castle.Core.dll</HintPath> <HintPath>..\packages\Castle.Core.4.3.1\lib\net45\Castle.Core.dll</HintPath>
</Reference> </Reference>
<Reference Include="System.Configuration" /> <Reference Include="System.Configuration" />
<Reference Include="LiteDB">
<HintPath>..\packages\LiteDB.4.1.4\lib\net40\LiteDB.dll</HintPath>
</Reference>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<Compile Include="Properties\AssemblyInfo.cs" /> <Compile Include="Properties\AssemblyInfo.cs" />
@ -60,12 +63,30 @@
<Compile Include="odb\ODBFileStorage.cs" /> <Compile Include="odb\ODBFileStorage.cs" />
<Compile Include="odb\Storage.cs" /> <Compile Include="odb\Storage.cs" />
<Compile Include="Extensions.cs" /> <Compile Include="Extensions.cs" />
<Compile Include="GeoLocation.cs" />
<Compile Include="URI.cs" />
<Compile Include="odb\ODBCollection.cs" />
<Compile Include="odb\ODBDocument.cs" />
<Compile Include="odb\values\ODBGuid.cs" />
<Compile Include="odb\values\ODBNull.cs" />
<Compile Include="odb\values\ODBStringValue.cs" />
<Compile Include="odb\values\ODBValue.cs" />
<Compile Include="odb\values\ODBInteger.cs" />
<Compile Include="odb\values\ODBLong.cs" />
<Compile Include="odb\values\ODBDouble.cs" />
<Compile Include="odb\ODBMapper.cs" />
<Compile Include="odb\ClassMapping.cs" />
<Compile Include="odb\values\ODBList.cs" />
<Compile Include="odb\ListMapping.cs" />
<Compile Include="odb\ODBCollection&lt;&gt;.cs" />
<Compile Include="odb\DictionaryMapping.cs" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<Folder Include="sync\" /> <Folder Include="sync\" />
<Folder Include="serialize\" /> <Folder Include="serialize\" />
<Folder Include="odb\" /> <Folder Include="odb\" />
<Folder Include="threads\" /> <Folder Include="threads\" />
<Folder Include="odb\values\" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\ln.logging\ln.logging.csproj"> <ProjectReference Include="..\ln.logging\ln.logging.csproj">

109
odb/ClassMapping.cs 100644
View File

@ -0,0 +1,109 @@
using System;
using ln.types.odb.values;
using System.Reflection;
using System.Collections.Generic;
using ln.logging;
namespace ln.types.odb
{
public class DocumentIDAttribute : Attribute
{
}
public class ClassMapping : IODBMapping
{
public Type MappedType { get; }
public String IDField { get; private set; }
List<FieldInfo> mappedFields = new List<FieldInfo>();
public ClassMapping(Type type)
{
Logging.Log(LogLevel.DEBUG, "Constructing ClassMapping for {0}",type);
MappedType = type;
AddFields(type);
}
private void AddFields(Type type)
{
foreach (FieldInfo fieldinfo in type.GetFields(BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public))
{
if (fieldinfo.GetCustomAttribute<IgnoreFieldAttribute>() == null)
{
mappedFields.Add(fieldinfo);
if (fieldinfo.GetCustomAttribute<DocumentIDAttribute>() != null)
{
IDField = fieldinfo.Name;
}
}
}
if ((type != null) && !type.IsValueType && (!typeof(object).Equals(type.BaseType)))
{
AddFields(type.BaseType);
}
}
public object UnmapValue(ODBMapper mapper,ODBValue oval)
{
ODBDocument document = oval as ODBDocument;
object o = Activator.CreateInstance(MappedType, true);
foreach (FieldInfo fieldInfo in mappedFields)
{
object fv = ODBMapper.Default.UnmapValue(fieldInfo.FieldType,document[fieldInfo.Name]);
fieldInfo.SetValue(o, fv);
}
return o;
}
public ODBValue MapValue(ODBMapper mapper,object value)
{
ODBDocument document = new ODBDocument();
document["__asm__"] = value.GetType().Assembly.GetName().Name;
document["__type__"] = value.GetType().FullName;
foreach (FieldInfo fieldInfo in mappedFields)
{
object fv = fieldInfo.GetValue(value);
ODBValue ov = ODBMapper.Default.MapValue(fv);
document[fieldInfo.Name] = ov;
}
if (IDField != null)
{
document.ID = document[IDField];
}
return document;
}
}
public class ObjectMapping : IODBMapping
{
public ODBValue MapValue(ODBMapper mapper, object value)
{
return new ODBDocument();
}
public object UnmapValue(ODBMapper mapper, ODBValue oval)
{
if (oval is ODBDocument)
{
ODBDocument document = oval.AsDocument;
if (!document.Contains("__type__"))
return new object();
Type dType = Assembly.Load(document["__asm__"].AsString).GetType(document["__type__"].AsString);
return mapper.UnmapValue(dType, oval);
}
else
{
return oval.Value;
}
}
}
}

View File

@ -0,0 +1,66 @@
using System;
using ln.types.odb.values;
using System.Linq;
using System.Collections;
using System.Reflection;
using Castle.Components.DictionaryAdapter;
using System.Collections.Generic;
namespace ln.types.odb
{
public class DictionaryMapping : IODBMapping
{
public DictionaryMapping()
{
}
public ODBValue MapValue(ODBMapper mapper, object value)
{
Type dType = value.GetType();
if (dType.GetInterfaces().Contains(typeof(IDictionary)))
{
IDictionary dictionary = value as IDictionary;
ODBDocument document = new ODBDocument();
document["__asm__"] = value.GetType().Assembly.GetName().Name;
document["__type__"] = value.GetType().FullName;
foreach (object key in dictionary.Keys)
{
object v = dictionary[key];
document[mapper.MapValue(key)] = mapper.MapValue(v);
}
return document;
}
throw new NotImplementedException();
}
public object UnmapValue(ODBMapper mapper, ODBValue oval)
{
ODBDocument document = oval.AsDocument;
Type dType = Assembly.Load(document["__asm__"].AsString).GetType(document["__type__"].AsString);
if (dType.IsGenericType)
{
IDictionary dictionary = (IDictionary)Activator.CreateInstance(dType, true);
if (dType.GetGenericTypeDefinition().Equals(typeof(Dictionary<,>)))
{
Type kType = dType.GetGenericArguments()[0];
Type vType = dType.GetGenericArguments()[1];
foreach (ODBValue key in document.Keys)
{
if (!key.Equals("__asm__") && !key.Equals("__type__"))
dictionary.Add(mapper.UnmapValue(kType, key), mapper.UnmapValue(vType, document[key]));
}
return dictionary;
}
}
throw new NotSupportedException();
}
}
}

59
odb/ListMapping.cs 100644
View File

@ -0,0 +1,59 @@
// /**
// * File: ListMapping.cs
// * Author: haraldwolff
// *
// * This file and it's content is copyrighted by the Author and / or copyright holder.
// * Any use wihtout proper permission is illegal and may lead to legal actions.
// *
// *
// **/
using System;
using ln.types.odb.values;
using System.Collections;
using System.Linq;
namespace ln.types.odb
{
public class ListMapping : IODBMapping
{
public Type TargetType { get; }
public ListMapping(Type targetType)
{
TargetType = targetType;
}
public object UnmapValue(ODBMapper mapper,ODBValue oval)
{
ODBList list = oval as ODBList;
if (TargetType.IsArray)
{
Array a = Array.CreateInstance(TargetType.GetElementType(), list.Count);
for (int n = 0; n < list.Count; n++)
a.SetValue(list[n], n);
return a;
} else if (TargetType.GetInterfaces().Contains(typeof(IList)))
{
IList ilist = (IList)Activator.CreateInstance(TargetType, true);
for (int n = 0; n < list.Count; n++)
ilist.Add(list[n]);
return ilist;
}
throw new NotImplementedException();
}
public ODBValue MapValue(ODBMapper mapper,object value)
{
ODBList list = new ODBList();
foreach (object item in (IEnumerable)value)
{
list.Add(ODBMapper.Default.MapValue(item));
}
return list;
}
}
}

View File

@ -14,165 +14,70 @@ using Castle.DynamicProxy;
using ln.types.serialize; using ln.types.serialize;
using Castle.Components.DictionaryAdapter; using Castle.Components.DictionaryAdapter;
using System.Linq; using System.Linq;
using ln.logging;
using ln.types.odb.values;
namespace ln.types.odb namespace ln.types.odb
{ {
public class ODB<T> : ODB where T: IPersistent
{
public T Root
{
get => (T)RootObject;
}
public ODB(String basePath) public class ODB : IDisposable
:base(basePath, typeof(T))
{
}
}
public class ODB
{ {
public String BasePath { get; set; } public String BasePath { get; set; }
public IPersistent RootObject { get; protected set; } Dictionary<string, ODBCollection> collections = new Dictionary<string, ODBCollection>();
private Type RootType;
private Storage Storage { get; set; }
private Dictionary<Guid, PreparedObject> objectCache = new Dictionary<Guid, PreparedObject>();
public ODB(string basePath) public ODB(string basePath)
{ {
BasePath = Path.GetFullPath(basePath); BasePath = Path.GetFullPath(basePath);
Storage = new ODBFileStorage(basePath); if (!Directory.Exists(BasePath))
Directory.CreateDirectory(BasePath);
} }
public ODB(String basePath, Type rootType) public ODBCollection GetCollection(string colName)
: this(basePath)
{ {
RootType = rootType; if (!collections.ContainsKey(colName))
Initialize(); collections[colName] = new ODBCollection(this, colName);
return collections[colName];
} }
public ODB(String basePath,IPersistent rootObject)
: this(basePath) public ODBCollection<T> GetCollection<T>() where T:class
{ {
RootType = rootObject.GetType(); return new ODBCollection<T>(this);
RootObject = rootObject; }
Initialize();
internal void DisposeCollection(ODBCollection collection)
{
ODBCollection check = collections[collection.CollectionName];
if (check == collection)
collections.Remove(collection.CollectionName);
} }
private void Initialize() private void Initialize()
{ {
if (RootObject == null)
{
string rootHint = Path.Combine(BasePath, "root.hint");
if (File.Exists(rootHint))
{
string rootID = File.ReadAllText(rootHint);
Guid persistenceID = Guid.Parse(rootID);
RootObject = LoadPersistent(persistenceID);
}
else
{
RootObject = (IPersistent)Activator.CreateInstance(RootType);
string rootID = RootObject.GetPersistenceID().ToString();
SavePersistent(RootObject);
File.WriteAllText(rootHint, rootID);
}
}
} }
public bool Contains(Guid persistenceID) public void Dispose()
{ {
return Storage.Contains(persistenceID) || objectCache.ContainsKey(persistenceID); foreach (ODBCollection col in collections.Values.ToArray())
{
col.Dispose();
}
} }
public void SavePersistent(IPersistent o) => SavePersistent(o, true); static ODB()
public void SavePersistent(IPersistent o,bool recurse)
{ {
lock (this) new ODBDocument();
{ new ODBNull();
SaveCollector saveCollector = new SaveCollector(this); new ODBStringValue();
saveCollector.Add(o); new ODBList();
new ODBInteger();
foreach (PreparedObject preparedObject in saveCollector.PreparedToSave) new ODBUInteger();
{ new ODBLong();
Storage.Store(preparedObject); new ODBULong();
objectCache[preparedObject.PersistenceID] = preparedObject; new ODBDouble();
} new ODBGuid();
}
} }
public T LoadPersistent<T>(Guid persistenceID) => (T)LoadPersistent(persistenceID);
public IPersistent LoadPersistent(Guid persistenceID)
{
if (!Contains(persistenceID))
throw new KeyNotFoundException();
PreparedObject preparedObject = GetCachedPersistent(persistenceID);
if (preparedObject == null)
{
preparedObject = new PreparedObject(this, typeof(IPersistent), persistenceID);
if (!Storage.Load(preparedObject))
throw new IOException(String.Format("unable to load IPersistent({0})",persistenceID));
preparedObject.CreateInstance();
objectCache.Add(persistenceID,preparedObject);
}
return preparedObject.Instance;
}
private PreparedObject GetCachedPersistent(Guid persistenceID)
{
lock (this)
{
if (objectCache.ContainsKey(persistenceID))
{
return objectCache[persistenceID];
}
}
return null;
}
class SaveCollector
{
public ODB ODB { get; }
public IEnumerable<PreparedObject> PreparedToSave => preparedObjects.Values;
private Dictionary<Guid, PreparedObject> preparedObjects = new Dictionary<Guid, PreparedObject>();
public SaveCollector(ODB odb)
{
ODB = odb;
}
public void Add(IPersistent persistent)
{
PreparedObject preparedObject = new PreparedObject(ODB,persistent);
PreparedObject cachedObject = ODB.GetCachedPersistent(preparedObject.PersistenceID);
if (!preparedObject.InstanceEquals(cachedObject) && !preparedObjects.ContainsKey(preparedObject.PersistenceID))
{
preparedObjects.Add(preparedObject.PersistenceID, preparedObject);
foreach (IPersistent referencedPersistent in preparedObject.ReferencedPersistents)
{
Add(referencedPersistent);
}
}
}
}
} }
} }

View File

@ -0,0 +1,419 @@
using System;
using System.Collections;
using System.Collections.Generic;
using ln.types.odb.values;
using System.IO;
using System.Net.Mime;
using System.Security.AccessControl;
using System.Linq;
using System.ComponentModel.Design.Serialization;
using System.ComponentModel;
using ln.logging;
namespace ln.types.odb
{
public class ODBCollection : IEnumerable<ODBDocument>, IDisposable
{
public ODB ODB { get; }
public String CollectionName { get; }
public DocumentIndex Index => documentIndex;
FileStream fileStream;
DocumentIndex documentIndex;
internal ODBCollection(ODB odb,string collectionName)
{
ODB = odb;
CollectionName = collectionName;
Initialize();
}
private void Initialize()
{
fileStream = new FileStream(Path.Combine(ODB.BasePath, String.Format("{0}.col",CollectionName)),FileMode.OpenOrCreate,FileAccess.ReadWrite);
documentIndex = new DocumentIndex(fileStream);
}
public void Close()
{
Dispose();
}
public bool Insert(ODBDocument document)
{
DocumentIndex.DocumentIndexEntry die = documentIndex.Lookup(document.ID);
if (die == null)
{
byte[] docBytes = document.ToStorage();
die = documentIndex.FindUnused(docBytes.Length);
die.Update(document.ID,docBytes);
return true;
}
return false;
}
public bool Update(ODBDocument document)
{
DocumentIndex.DocumentIndexEntry die = documentIndex.Lookup(document.ID);
if (die != null)
{
byte[] docBytes = document.ToStorage();
if (die.BufferLength < docBytes.Length)
{
DocumentIndex.DocumentIndexEntry ndie = documentIndex.FindUnused(docBytes.Length);
die.DocumentID = ODBNull.Instance;
ndie.Update(document.ID, docBytes);
die.Release();
}
else
{
die.Update(document.ID, docBytes);
}
return true;
}
return false;
}
public bool Upsert(ODBDocument document)
{
byte[] docBytes = document.ToStorage();
DocumentIndex.DocumentIndexEntry die = documentIndex.Lookup(document.ID);
DocumentIndex.DocumentIndexEntry rdie = null;
if ((die == null) || (die.BufferLength < docBytes.Length))
{
rdie = die;
die = documentIndex.FindUnused(docBytes.Length);
}
if (rdie != null)
rdie.DocumentID = ODBNull.Instance;
die.Update(document.ID, docBytes);
if (rdie != null)
rdie.Release();
return true;
}
public ODBDocument GetDocumentByID(ODBValue id)
{
Logging.Log(LogLevel.DEBUG, "ODBCollection.GetDocumentByID(): {0}",id);
DocumentIndex.DocumentIndexEntry die = documentIndex.Lookup(id);
if (die != null)
{
byte[] storageBytes = die.ReadStorageBytes();
ODBDocument document = new ODBDocument(storageBytes, 0, storageBytes.Length);
return document;
}
return null;
}
public IEnumerable<ODBDocument> Find(string propertyName, ODBValue value)
{
foreach (ODBDocument document in this)
{
if (value.Equals(document[propertyName]))
yield return document;
}
}
public ODBDocument FindOne(string propertyName, ODBValue value)
{
foreach (ODBDocument document in this)
{
if (value.Equals(document[propertyName]))
return document;
}
return null;
}
public IEnumerator<ODBDocument> GetEnumerator()
{
foreach (ODBValue id in documentIndex.ToArray())
{
yield return GetDocumentByID(id);
}
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
public void Dispose()
{
ODB.DisposeCollection(this);
if (fileStream != null)
{
fileStream.Dispose();
fileStream = null;
}
documentIndex = null;
}
public class DocumentIndex : IEnumerable<ODBValue>
{
public Stream StorageStream { get; }
public DocumentIndexEntry Head { get; private set; }
private Dictionary<ODBValue, DocumentIndexEntry> idLookup = new Dictionary<ODBValue, DocumentIndexEntry>();
public DocumentIndex(Stream stream)
{
StorageStream = stream;
Head = new DocumentIndexEntry(this);
}
public IEnumerable<DocumentIndexEntry> IndexEntries
{
get
{
DocumentIndexEntry entry = Head;
while (entry != null)
{
yield return entry;
entry = entry.Next;
}
}
}
public DocumentIndexEntry Lookup(ODBValue ID)
{
foreach (DocumentIndexEntry die in IndexEntries)
{
if (ID.Equals(die.DocumentID))
return die;
}
return null;
}
public DocumentIndexEntry FindUnused(int minLength)
{
foreach (DocumentIndexEntry die in IndexEntries)
{
if (die.IsUnused && (die.BufferLength > minLength))
return die;
if (die.Next == null)
return die.Extend(minLength);
}
return null;
}
public class DocumentIndexEntry
{
public DocumentIndex Index { get; }
public DocumentIndexEntry Next { get; private set; }
public DocumentIndexEntry Last { get; private set; }
public long Offset { get; private set; }
public int BufferLength { get; private set; }
public long NextOffset => Offset + BufferLength + 4;
private ODBValue documentID;
public ODBValue DocumentID
{
get => documentID;
set
{
lock (Index)
{
if (!ODBNull.Instance.Equals(documentID))
{
Index.idLookup.Remove(documentID);
}
documentID = value;
if (!ODBNull.Instance.Equals(documentID))
{
Index.idLookup.Add(documentID, this);
}
}
}
}
public bool IsUnused => (ODBNull.Instance.Equals(documentID));
public DocumentIndexEntry(DocumentIndex index)
: this(index, 0)
{ }
private DocumentIndexEntry(DocumentIndex index, long offset)
{
Index = index;
Offset = offset;
Read();
}
private DocumentIndexEntry(DocumentIndexEntry lastEntry,int bufferLength)
{
Last = lastEntry;
Last.Next = this;
Index = lastEntry.Index;
Offset = lastEntry.NextOffset;
BufferLength = bufferLength;
WriteHeader();
Release();
}
private DocumentIndexEntry(DocumentIndexEntry lastEntry)
{
Last = lastEntry;
Index = lastEntry.Index;
Offset = lastEntry.NextOffset;
if (Last.Next != null)
{
Next = Last.Next;
Last.Next = this;
Next.Last = this;
BufferLength = (int)(Next.Offset - Offset - 4);
WriteHeader();
Release();
}
else
{
Last.Next = this;
Read();
}
}
private void Read()
{
lock (Index)
{
if (Offset >= Index.StorageStream.Length)
{
BufferLength = 0;
DocumentID = ODBNull.Instance;
}
else
{
Index.StorageStream.Position = Offset;
BufferLength = Index.StorageStream.ReadInteger();
Index.StorageStream.Position = Offset + 4;
DocumentID = ODBValue.Read(Index.StorageStream);
if (NextOffset < Index.StorageStream.Length)
{
Next = new DocumentIndexEntry(this);
}
}
}
}
public void Update(ODBValue id,byte[] storageBytes)
{
lock (Index)
{
if (BufferLength < storageBytes.Length)
throw new ArgumentOutOfRangeException();
if (BufferLength > (storageBytes.Length + 32))
{
Split(storageBytes.Length);
}
Index.StorageStream.Position = Offset + 4;
Index.StorageStream.Write(storageBytes, 0, storageBytes.Length);
DocumentID = id;
}
}
public void Release()
{
lock (Index)
{
DocumentID = ODBNull.Instance;
Index.StorageStream.Position = Offset + 4;
Index.StorageStream.Write(new byte[BufferLength], 0, BufferLength);
if ((Next != null) && Next.IsUnused)
{
Combine();
}
if ((Last != null) && Last.IsUnused)
{
Last.Combine();
}
}
}
public DocumentIndexEntry Extend(int length)
{
if (Next == null)
{
if ((Last == null) && (IsUnused))
{
BufferLength = length;
WriteHeader();
Release();
return this;
}
return new DocumentIndexEntry(this, length);
}
throw new NotSupportedException();
}
private void Split(int length)
{
BufferLength = length;
DocumentIndexEntry dieInsert = new DocumentIndexEntry(this);
WriteHeader();
}
private void Combine()
{
BufferLength += Next.BufferLength + 4;
Next = Next.Next;
if (Next != null)
Next.Last = this;
WriteHeader();
}
private void WriteHeader()
{
lock (Index)
{
Index.StorageStream.Position = Offset;
Index.StorageStream.WriteInteger(BufferLength);
}
}
public byte[] ReadStorageBytes()
{
byte[] buffer = new byte[BufferLength];
lock (Index)
{
Index.StorageStream.Position = Offset + 4;
Index.StorageStream.Read(buffer, 0, BufferLength);
}
return buffer;
}
}
public IEnumerator<ODBValue> GetEnumerator()
{
return idLookup.Keys.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
}
}
}

View File

@ -0,0 +1,109 @@
using System;
using System.Collections;
using System.Collections.Generic;
using ln.types.odb.values;
namespace ln.types.odb
{
public class ODBCollection<T> : IEnumerable<T> where T:class
{
public ODB ODB { get; }
public Type ElementType { get; }
ODBCollection collection;
Dictionary<ODBValue, WeakReference<T>> objectCache = new Dictionary<ODBValue, WeakReference<T>>();
internal ODBCollection(ODB odb)
{
ODB = odb;
ElementType = typeof(T);
collection = new ODBCollection(odb, ElementType.FullName);
}
public T this[ODBValue documentID]
{
get => Select(documentID);
}
public T GetCachedObject(ODBValue documentID)
{
if (objectCache.ContainsKey(documentID))
{
T o = null;
if (objectCache[documentID].TryGetTarget(out o))
return o;
}
return null;
}
public void TouchCache(ODBValue documentID,T o)
{
if ((o == null)&&objectCache.ContainsKey(documentID))
{
objectCache.Remove(documentID);
}
else if (o != null)
{
objectCache[documentID] = new WeakReference<T>(o);
}
}
public T SelectOne(string fieldName, object value)
{
ODBDocument document = collection.FindOne(fieldName, ODBMapper.Default.MapValue(value));
if (document != null)
{
return Select(document.ID);
}
return null;
}
public IEnumerable<T> Select(string fieldName, object value)
{
foreach (ODBDocument document in collection.Find(fieldName, ODBMapper.Default.MapValue(value)))
{
yield return Select(document.ID);
}
}
public T Select(ODBValue documentID)
{
T o = GetCachedObject(documentID);
if (o == null)
{
ODBDocument document = collection.GetDocumentByID(documentID);
o = ODBMapper.Default.ToNativeValue<T>(document);
TouchCache(documentID, o);
}
return o;
}
public bool Insert(T o)
{
ODBDocument document = ODBMapper.Default.MapValue(o) as ODBDocument;
return collection.Insert(document);
}
public bool Update(T o)
{
ODBDocument document = ODBMapper.Default.MapValue(o) as ODBDocument;
return collection.Update(document);
}
public bool Upsert(T o)
{
ODBDocument document = ODBMapper.Default.MapValue(o) as ODBDocument;
return collection.Upsert(document);
}
public IEnumerator<T> GetEnumerator()
{
foreach (ODBValue documentID in collection.Index)
{
yield return Select(documentID);
}
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
}
}

109
odb/ODBDocument.cs 100644
View File

@ -0,0 +1,109 @@
using System;
using System.Collections.Generic;
using System.IO;
using ln.types.odb.values;
using System.Linq;
namespace ln.types.odb
{
public class ODBDocument : ODBValue
{
private Dictionary<ODBValue, ODBValue> properties = new Dictionary<ODBValue, ODBValue>();
public ODBDocument()
:base(0x1000)
{
}
public ODBValue ID { get; set; } = new ODBGuid();
public ODBDocument(byte[] bytes,int offset,int length)
:this()
{
int endOffset = offset + length;
ID = ODBValue.Deserialize(bytes, ref offset);
int nProps = BitConverter.ToInt32(bytes, offset);
offset += 4;
for (int n=0;n<nProps;n++)
{
ODBStringValue propName = ODBValue.Deserialize(bytes,ref offset) as ODBStringValue;
ODBValue propValue = ODBValue.Deserialize(bytes, ref offset);
properties.Add(propName, propValue);
}
if (offset > endOffset)
throw new FormatException("ODBDocument deserialization read behind end of buffer");
}
public ODBValue this[ODBValue propName]
{
get
{
if (properties.ContainsKey(propName))
return properties[propName];
return ODBNull.Instance;
}
set
{
if (ODBNull.Instance.Equals(value) && properties.ContainsKey(propName))
{
properties.Remove(propName);
}
else
{
properties[propName] = value;
}
}
}
public IEnumerable<ODBValue> Keys => properties.Keys;
public bool Contains(ODBStringValue propName)
{
return !ODBNull.Instance.Equals(this[propName]);
}
public override byte[] ToStorage()
{
MemoryStream stream = new MemoryStream();
BinaryWriter writer = new BinaryWriter(stream);
ID.Store(writer);
writer.Write(properties.Count);
foreach (ODBStringValue propName in properties.Keys)
{
ODBValue propValue = properties[propName];
propName.Store(writer);
propValue.Store(writer);
}
return stream.ToArray();
}
public override string ToString()
{
return String.Format("[ODBDocument ID={0} {1}]", ID.ToString(),String.Join(" ",properties.Select(kv=> String.Format("{0}={1}",kv.Key,kv.Value))));
}
public override int GetHashCode()
{
return ID.GetHashCode();
}
public override bool Equals(object obj)
{
if (obj is ODBDocument)
{
ODBDocument you = obj as ODBDocument;
return ID.Equals(you.ID);
}
return false;
}
static ODBDocument()
{
RegisterDeserializer(0x1000, (b,o,l) => new ODBDocument(b,o,l));
}
}
}

View File

@ -17,135 +17,143 @@ using System.Linq;
using System.Reflection; using System.Reflection;
namespace ln.types.odb namespace ln.types.odb
{ {
public class ODBFileStorage : Storage //public class ODBFileStorage : Storage
{ //{
public String BasePath { get; set; } // public String BasePath { get; set; }
public int StorageVersion { get; } = 0x01; // public int StorageVersion { get; } = 0x01;
public ODBFileStorage(string basePath) // public ODBFileStorage(string basePath)
{ // {
BasePath = Path.GetFullPath(basePath); // BasePath = Path.GetFullPath(basePath);
if (!Directory.Exists(BasePath)) // if (!Directory.Exists(BasePath))
{ // {
Directory.CreateDirectory(BasePath); // Directory.CreateDirectory(BasePath);
} // }
} // }
private string GetPersistentPath(Guid persistenceID) // private string GetPersistentPath(Guid persistenceID)
{ // {
byte[] idBytes = persistenceID.ToByteArray(); // byte[] idBytes = persistenceID.ToByteArray();
return Path.Combine(BasePath, BitConverter.ToString(idBytes, 0, 4)); // return Path.Combine(BasePath, BitConverter.ToString(idBytes, 0, 4));
} // }
public override bool Contains(Guid persistenceID) // public override bool Contains(Guid persistenceID)
{ // {
string fn = Path.Combine(GetPersistentPath(persistenceID), String.Format("{0}.0", persistenceID)); // string fn = Path.Combine(GetPersistentPath(persistenceID), String.Format("{0}.0", persistenceID));
return File.Exists(fn); // return File.Exists(fn);
} // }
public override bool Store(PreparedObject preparedObject) // public override bool Store(PreparedObject preparedObject)
{ // {
string targetPath = GetPersistentPath(preparedObject.PersistenceID); // string targetPath = GetPersistentPath(preparedObject.PersistenceID);
String fnbase = Path.Combine(targetPath, preparedObject.PersistenceID.ToString()); // String fnbase = Path.Combine(targetPath, preparedObject.PersistenceID.ToString());
if (!Directory.Exists(targetPath)) // if (!Directory.Exists(targetPath))
Directory.CreateDirectory(targetPath); // Directory.CreateDirectory(targetPath);
String fnn = String.Format("{0}.new", fnbase); // String fnn = String.Format("{0}.new", fnbase);
using (FileStream fs = new FileStream(fnn, FileMode.CreateNew)) // if (File.Exists(fnn))
{ // File.Delete(fnn);
ToStream(preparedObject, fs);
fs.Close();
}
for (int n = 5; n > 0; n--) // using (FileStream fs = new FileStream(fnn, FileMode.CreateNew))
{ // {
string fn1 = String.Format("{0}.{1}", fnbase, n - 1); // ToStream(preparedObject, fs);
string fn2 = String.Format("{0}.{1}", fnbase, n); // fs.Close();
// }
if (File.Exists(fn1)) // for (int n = 5; n > 0; n--)
File.Move(fn1, fn2); // {
} // string fn1 = String.Format("{0}.{1}", fnbase, n - 1);
// string fn2 = String.Format("{0}.{1}", fnbase, n);
string fn = String.Format("{0}.{1}", fnbase, 0); // if (File.Exists(fn1))
File.Move(fnn, fn); // {
// if (File.Exists(fn2))
// File.Delete(fn2);
return true; // File.Move(fn1, fn2);
} // }
// }
// string fn = String.Format("{0}.{1}", fnbase, 0);
// File.Move(fnn, fn);
// return true;
// }
public override bool Load(PreparedObject preparedObject) // public override bool Load(PreparedObject preparedObject)
{ // {
string targetPath = GetPersistentPath(preparedObject.PersistenceID); // string targetPath = GetPersistentPath(preparedObject.PersistenceID);
String fnbase = Path.Combine(targetPath, preparedObject.PersistenceID.ToString()); // String fnbase = Path.Combine(targetPath, preparedObject.PersistenceID.ToString());
string fn = String.Format("{0}.0", fnbase); // string fn = String.Format("{0}.0", fnbase);
using (FileStream fs = new FileStream(fn, FileMode.Open)) // using (FileStream fs = new FileStream(fn, FileMode.Open))
{ // {
FromStream(fs, preparedObject); // FromStream(fs, preparedObject);
fs.Close(); // fs.Close();
} // }
return true; // return true;
} // }
private void ToStream(PreparedObject preparedObject,Stream stream) // private void ToStream(PreparedObject preparedObject,Stream stream)
{ // {
using (BinaryWriter writer = new BinaryWriter(stream)) // using (BinaryWriter writer = new BinaryWriter(stream))
{ // {
writer.Write(StorageVersion); // writer.Write(StorageVersion);
writer.Write(DateTimeOffset.Now.ToUnixTimeMilliseconds()); // writer.Write(DateTimeOffset.Now.ToUnixTimeMilliseconds());
writer.Write(preparedObject.PreparedType.Assembly.FullName); // writer.Write(preparedObject.PreparedType.Assembly.GetName().Name);
writer.Write(preparedObject.PreparedType.FullName); // writer.Write(preparedObject.PreparedType.FullName);
string[] fieldNames = preparedObject.StoredFieldNames; // string[] fieldNames = preparedObject.StoredFieldNames;
writer.Write(fieldNames.Length); // writer.Write(fieldNames.Length);
foreach (String fieldName in fieldNames) // foreach (String fieldName in fieldNames)
{ // {
byte[] fieldBytes = preparedObject.GetFieldBytes(fieldName); // byte[] fieldBytes = preparedObject.GetFieldBytes(fieldName);
writer.Write(fieldName); // writer.Write(fieldName);
writer.Write(fieldBytes.Length); // writer.Write(fieldBytes.Length);
writer.Write(fieldBytes); // writer.Write(fieldBytes);
} // }
writer.Close(); // writer.Close();
} // }
} // }
private void FromStream(Stream stream,PreparedObject preparedObject) // private void FromStream(Stream stream,PreparedObject preparedObject)
{ // {
using (BinaryReader reader = new BinaryReader(stream)) // using (BinaryReader reader = new BinaryReader(stream))
{ // {
if (reader.ReadInt32() != StorageVersion) // if (reader.ReadInt32() != StorageVersion)
throw new FormatException("Unsupported Storage Version"); // throw new FormatException("Unsupported Storage Version");
DateTime timestamp = DateTimeOffset.FromUnixTimeMilliseconds(reader.ReadInt64()).DateTime; // DateTime timestamp = DateTimeOffset.FromUnixTimeMilliseconds(reader.ReadInt64()).DateTime;
string assemblyName = reader.ReadString(); // string assemblyName = reader.ReadString();
string typeName = reader.ReadString(); // string typeName = reader.ReadString();
Assembly assembly = Assembly.Load(assemblyName); // Assembly assembly = Assembly.Load(assemblyName);
Type targetType = assembly.GetType(typeName); // Type targetType = assembly.GetType(typeName);
preparedObject.ReConfigure(targetType,timestamp); // preparedObject.ReConfigure(targetType,timestamp);
int nStoredFields = reader.ReadInt32(); // int nStoredFields = reader.ReadInt32();
for (int n = 0; n < nStoredFields; n++) // for (int n = 0; n < nStoredFields; n++)
{ // {
string fieldName = reader.ReadString(); // string fieldName = reader.ReadString();
int nBytes = reader.ReadInt32(); // int nBytes = reader.ReadInt32();
byte[] fieldBytes = reader.ReadBytes(nBytes); // byte[] fieldBytes = reader.ReadBytes(nBytes);
preparedObject.SetFieldBytes(fieldName, fieldBytes); // preparedObject.SetFieldBytes(fieldName, fieldBytes);
} // }
reader.Close(); // reader.Close();
} // }
} // }
} //}
} }

220
odb/ODBMapper.cs 100644
View File

@ -0,0 +1,220 @@
using System;
using ln.types.odb.values;
using System.Collections.Generic;
using System.Runtime.Remoting.Messaging;
using System.Reflection;
using System.Linq;
using System.Collections;
namespace ln.types.odb
{
public class IgnoreFieldAttribute : Attribute
{
}
public delegate ODBValue ODBMap(ODBMapper mapper, object value);
public delegate object ODBUnmap(ODBMapper mapper, ODBValue oval);
public delegate ODBValue ODBMap<T>(ODBMapper mapper, T value);
public delegate T ODBUnmap<T>(ODBMapper mapper, ODBValue oval);
public interface IODBMapping
{
ODBValue MapValue(ODBMapper mapper, object value);
object UnmapValue(ODBMapper mapper, ODBValue oval);
}
public interface IODBMapping<T>
{
ODBValue MapValue(ODBMapper mapper, T value);
T UnmapValue(ODBMapper mapper, ODBValue oval);
}
public class SimpleMapping : IODBMapping
{
ODBMap map;
ODBUnmap unmap;
public SimpleMapping(ODBMap map,ODBUnmap unmap)
{
this.map = map;
this.unmap = unmap;
}
public ODBValue MapValue(ODBMapper mapper, object value)
{
return map(mapper, value);
}
public object UnmapValue(ODBMapper mapper, ODBValue oval)
{
return unmap(mapper, oval);
}
}
public class SimpleMapping<T> : SimpleMapping
{
public SimpleMapping(ODBMap<T> map, ODBUnmap<T> unmap)
:base((mapper, value) => map(mapper,(T)value),(mapper, oval) => unmap(mapper,oval))
{}
}
public class ODBMapper
{
public static ODBMapper Default { get; } = new ODBMapper();
Dictionary<Type, IODBMapping> mappings = new Dictionary<Type, IODBMapping>();
private ODBMapper()
{
RegisterMapping<string>(
(mapper, value) => new ODBStringValue(value),
(mapper, oval) => oval.AsString
);
RegisterMapping<int>(
(mapper, value) => new ODBInteger(value),
(mapper, oval) => oval.AsInt
);
RegisterMapping<short>(
(mapper, value) => new ODBInteger(value),
(mapper, oval) => oval.AsShort
);
RegisterMapping<byte>(
(mapper, value) => new ODBInteger(value),
(mapper, oval) => oval.AsByte
);
RegisterMapping<uint>(
(mapper, value) => new ODBUInteger(value),
(mapper, oval) => oval.AsUInt
);
RegisterMapping<ushort>(
(mapper, value) => new ODBUInteger(value),
(mapper, oval) => oval.AsUShort
);
RegisterMapping<char>(
(mapper, value) => new ODBUInteger(value),
(mapper, oval) => oval.AsChar
);
RegisterMapping<double>(
(mapper, value) => new ODBDouble(value),
(mapper, oval) => oval.AsDouble
);
RegisterMapping<float>(
(mapper, value) => new ODBDouble(value),
(mapper, oval) => oval.AsFloat
);
RegisterMapping<DateTime>(
(mapper, value) => new ODBLong(DateTime.MinValue.Equals(value) ? 0 : new DateTimeOffset(value).ToUnixTimeMilliseconds() ),
(mapper, oval) => DateTimeOffset.FromUnixTimeMilliseconds(oval.AsLong).DateTime
);
RegisterMapping<TimeSpan>(
(mapper, value) => new ODBDouble(value.TotalMilliseconds),
(mapper, oval) => TimeSpan.FromMilliseconds(oval.AsDouble)
);
RegisterMapping<Guid>(
(mapper, value) => new ODBGuid(value),
(mapper, oval) => oval.AsGuid
);
RegisterMapping<long>(
(mapper, value) => new ODBLong(value),
(mapper, oval) => oval.AsLong
);
RegisterMapping<ulong>(
(mapper, value) => new ODBULong(value),
(mapper, oval) => oval.AsULong
);
RegisterMapping<bool>(
(mapper, value) => new ODBInteger(value ? -1 : 0),
(mapper, oval) => oval.AsBool
);
RegisterMapping(typeof(object),new ObjectMapping());
}
public void RegisterMapping(Type nativeType,IODBMapping mapping)
{
mappings[nativeType] = mapping;
}
public void RegisterMapping(Type nativeType, ODBMap map, ODBUnmap unmap)
{
mappings[nativeType] = new SimpleMapping(map, unmap);
}
public void RegisterMapping<T>(ODBMap<T> map, ODBUnmap<T> unmap)
{
mappings[typeof(T)] = new SimpleMapping<T>(map, unmap);
}
public IODBMapping GetMapping<T>() => null;
public IODBMapping GetMapping(Type type)
{
if (mappings.ContainsKey(type))
return mappings[type];
if (typeof(string).Equals(type))
{
return null;
}
else if (type.IsGenericType && type.GetGenericTypeDefinition().Equals(typeof(Dictionary<,>)))
{
mappings.Add(type, new DictionaryMapping());
return mappings[type];
}
else if (type.GetInterfaces().Contains(typeof(IDictionary)))
{
mappings.Add(type, new DictionaryMapping());
return mappings[type];
}
else if (type.IsArray)
{
mappings.Add(type, new ListMapping(type));
return mappings[type];
}
else if (!type.IsPrimitive)
{
mappings.Add(type, new ClassMapping(type));
return mappings[type];
}
return null;
}
public virtual ODBValue MapValue(object value)
{
if (value == null)
return ODBNull.Instance;
IODBMapping mapping = GetMapping(value.GetType());
if (mapping != null)
return mappings[value.GetType()].MapValue(this,value);
throw new NotSupportedException(String.Format("Can't map {0} ({1})",value.GetType(),value));
}
public virtual object UnmapValue(Type targetType,ODBValue value)
{
if (ODBNull.Instance.Equals(value))
return null;
if (value is ODBDocument)
{
ODBDocument doc = value as ODBDocument;
String asmname = doc["__asm__"].AsString;
String typename = doc["__type__"].AsString;
targetType = Assembly.Load(asmname).GetType(typename);
}
IODBMapping mapping = GetMapping(targetType);
if (mapping != null)
return mappings[targetType].UnmapValue(this,value);
return Convert.ChangeType(value.Value, targetType);
}
public virtual T ToNativeValue<T>(ODBValue value)
{
return (T)UnmapValue(typeof(T), value);
}
}
}

View File

@ -12,26 +12,26 @@ using System.IO;
using ln.types.serialize; using ln.types.serialize;
namespace ln.types.odb namespace ln.types.odb
{ {
public class ODBObjectReader : ObjectReader //public class ODBObjectReader : ObjectReader
{ //{
public ODB ODB { get; } // public ODB ODB { get; }
public ODBObjectReader(ODB odb, Stream stream) : // public ODBObjectReader(ODB odb, Stream stream) :
base(stream) // base(stream)
{ // {
ODB = odb; // ODB = odb;
} // }
public override object QueryReferencedObject(object re) // public override object QueryReferencedObject(object re)
{ // {
if (re is Guid) // if (re is Guid)
{ // {
Guid persistenceID = (Guid)re; // Guid persistenceID = (Guid)re;
IPersistent persistent = ODB.LoadPersistent(persistenceID); // IPersistent persistent = ODB.LoadPersistent(persistenceID);
return persistent; // return persistent;
} // }
return base.QueryReferencedObject(re); // return base.QueryReferencedObject(re);
} // }
} //}
} }

View File

@ -14,30 +14,30 @@ using ln.types.serialize;
using System.Linq; using System.Linq;
namespace ln.types.odb namespace ln.types.odb
{ {
class ODBObjectWriter : ObjectWriter //class ODBObjectWriter : ObjectWriter
{ //{
public IPersistent[] ReferencedPersistents => referencedPersistents.Values.ToArray(); // public IPersistent[] ReferencedPersistents => referencedPersistents.Values.ToArray();
public Guid[] ReferencedPersistentIDs => referencedPersistents.Keys.ToArray(); // public Guid[] ReferencedPersistentIDs => referencedPersistents.Keys.ToArray();
private Dictionary<Guid, IPersistent> referencedPersistents = new Dictionary<Guid, IPersistent>(); // private Dictionary<Guid, IPersistent> referencedPersistents = new Dictionary<Guid, IPersistent>();
public ODBObjectWriter(Stream stream) // public ODBObjectWriter(Stream stream)
: base(stream) // : base(stream)
{} // {}
public override object QueryReference(object o) // public override object QueryReference(object o)
{ // {
if (o is IPersistent) // if (o is IPersistent)
{ // {
IPersistent persistent = o as IPersistent; // IPersistent persistent = o as IPersistent;
Guid persistenceID = persistent.GetPersistenceID(); // Guid persistenceID = persistent.GetPersistenceID();
if (!referencedPersistents.ContainsKey(persistenceID)) // if (!referencedPersistents.ContainsKey(persistenceID))
referencedPersistents.Add(persistenceID, persistent); // referencedPersistents.Add(persistenceID, persistent);
return persistenceID; // return persistenceID;
} // }
return base.QueryReference(o); // return base.QueryReference(o);
} // }
} //}
} }

View File

@ -8,10 +8,12 @@
// * // *
// **/ // **/
using System; using System;
using LiteDB;
namespace ln.types.odb namespace ln.types.odb
{ {
public class Persistent : IPersistent public class Persistent : IPersistent
{ {
[BsonId]
public Guid PersistenceID { get; private set; } public Guid PersistenceID { get; private set; }
public Persistent() public Persistent()

View File

@ -3,163 +3,163 @@ using System.Collections;
using System.Collections.Generic; using System.Collections.Generic;
namespace ln.types.odb namespace ln.types.odb
{ {
public class PersistentList<T> : IList<T> where T: IPersistent //public class PersistentList<T> : IList<T> where T: IPersistent
{ //{
private Dictionary<Guid, T> persistentInstances = new Dictionary<Guid, T>(); // private Dictionary<Guid, T> persistentInstances = new Dictionary<Guid, T>();
private List<Guid> index = new List<Guid>(); // private List<Guid> index = new List<Guid>();
public ODB ODB { get; } // public ODB ODB { get; }
public PersistentList(ODB odb) // public PersistentList(ODB odb)
{ // {
ODB = odb; // ODB = odb;
} // }
public T this[int n] // public T this[int n]
{ // {
get { // get {
Guid persistentID = index[n]; // Guid persistentID = index[n];
if (!persistentInstances.ContainsKey(persistentID)) // if (!persistentInstances.ContainsKey(persistentID))
persistentInstances[persistentID] = (T)ODB.LoadPersistent(persistentID); // persistentInstances[persistentID] = (T)ODB.LoadPersistent(persistentID);
return persistentInstances[persistentID]; // return persistentInstances[persistentID];
} // }
set { // set {
if (value == null) // if (value == null)
index[n] = Guid.Empty; // index[n] = Guid.Empty;
Guid persistenceID = value.GetPersistenceID(); // Guid persistenceID = value.GetPersistenceID();
persistentInstances[persistenceID] = value; // persistentInstances[persistenceID] = value;
index[n] = persistenceID; // index[n] = persistenceID;
} // }
} // }
public int Count => index.Count; // public int Count => index.Count;
public bool IsReadOnly => false; // public bool IsReadOnly => false;
public void Add(T item) // public void Add(T item)
{ // {
if (item == null) // if (item == null)
{ // {
index.Add(Guid.Empty); // index.Add(Guid.Empty);
} // }
else // else
{ // {
Guid persistenceID = item.GetPersistenceID(); // Guid persistenceID = item.GetPersistenceID();
persistentInstances[persistenceID] = item; // persistentInstances[persistenceID] = item;
index.Add(persistenceID); // index.Add(persistenceID);
} // }
} // }
public void Clear() // public void Clear()
{ // {
persistentInstances.Clear(); // persistentInstances.Clear();
index.Clear(); // index.Clear();
} // }
public bool Contains(T item) // public bool Contains(T item)
{ // {
Guid persistenceID = item.GetPersistenceID(); // Guid persistenceID = item.GetPersistenceID();
if (index.Contains(persistenceID)) // if (index.Contains(persistenceID))
return true; // return true;
foreach (T mine in this) // foreach (T mine in this)
{ // {
if (mine.Equals(item)) // if (mine.Equals(item))
return true; // return true;
} // }
return false; // return false;
} // }
public void CopyTo(T[] array, int arrayIndex) // public void CopyTo(T[] array, int arrayIndex)
{ // {
foreach (T item in this) // foreach (T item in this)
{ // {
array[arrayIndex] = this[arrayIndex]; // array[arrayIndex] = this[arrayIndex];
arrayIndex++; // arrayIndex++;
} // }
} // }
public IEnumerator<T> GetEnumerator() // public IEnumerator<T> GetEnumerator()
{ // {
return new PersistentListEnumerator(this); // return new PersistentListEnumerator(this);
} // }
public int IndexOf(T item) // public int IndexOf(T item)
{ // {
Guid persistenceID = item == null ? Guid.Empty : item.GetPersistenceID(); // Guid persistenceID = item == null ? Guid.Empty : item.GetPersistenceID();
int i = index.IndexOf(persistenceID); // int i = index.IndexOf(persistenceID);
if (i < 0) // if (i < 0)
{ // {
for (int n=0;n<Count;n++) // for (int n=0;n<Count;n++)
{ // {
if (this[n].Equals(item)) // if (this[n].Equals(item))
return n; // return n;
} // }
} // }
return -1; // return -1;
} // }
public void Insert(int _index, T item) // public void Insert(int _index, T item)
{ // {
Guid persistenceID = item == null ? Guid.Empty : item.GetPersistenceID(); // Guid persistenceID = item == null ? Guid.Empty : item.GetPersistenceID();
index.Insert(_index, persistenceID); // index.Insert(_index, persistenceID);
persistentInstances[persistenceID] = item; // persistentInstances[persistenceID] = item;
} // }
public bool Remove(T item) // public bool Remove(T item)
{ // {
int ind = IndexOf(item); // int ind = IndexOf(item);
if (ind >= 0) // if (ind >= 0)
RemoveAt(ind); // RemoveAt(ind);
return ind >= 0; // return ind >= 0;
} // }
public void RemoveAt(int _index) // public void RemoveAt(int _index)
{ // {
Guid persistenceID = index[_index]; // Guid persistenceID = index[_index];
if (persistentInstances.ContainsKey(persistenceID)) // if (persistentInstances.ContainsKey(persistenceID))
persistentInstances.Remove(persistenceID); // persistentInstances.Remove(persistenceID);
index.RemoveAt(_index); // index.RemoveAt(_index);
} // }
IEnumerator IEnumerable.GetEnumerator() // IEnumerator IEnumerable.GetEnumerator()
{ // {
return new PersistentListEnumerator(this); // return new PersistentListEnumerator(this);
} // }
class PersistentListEnumerator : IEnumerator<T> // class PersistentListEnumerator : IEnumerator<T>
{ // {
int currentIndex = -1; // int currentIndex = -1;
PersistentList<T> persistentList; // PersistentList<T> persistentList;
public PersistentListEnumerator(PersistentList<T> persistentList) // public PersistentListEnumerator(PersistentList<T> persistentList)
{ // {
this.persistentList = persistentList; // this.persistentList = persistentList;
} // }
public T Current => persistentList[currentIndex]; // public T Current => persistentList[currentIndex];
object IEnumerator.Current => persistentList[currentIndex]; // object IEnumerator.Current => persistentList[currentIndex];
public void Dispose() // public void Dispose()
{ // {
persistentList = null; // persistentList = null;
} // }
public bool MoveNext() // public bool MoveNext()
{ // {
currentIndex++; // currentIndex++;
return (currentIndex < persistentList.Count); // return (currentIndex < persistentList.Count);
} // }
public void Reset() // public void Reset()
{ // {
currentIndex = -1; // currentIndex = -1;
} // }
} // }
} //}
} }

View File

@ -13,171 +13,169 @@ using System.CodeDom;
using System.Reflection; using System.Reflection;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using ln.types.sync;
namespace ln.types.odb namespace ln.types.odb
{ {
public class PreparedObject //public class PreparedObject
{ //{
public ODB ODB { get; private set; } // public ODB ODB { get; private set; }
public DateTime Timestamp { get; private set; } // public DateTime Timestamp { get; private set; }
public Type PreparedType { get; private set; } // public Type PreparedType { get; private set; }
public IPersistent Instance { get; set; } // public IPersistent Instance { get; set; }
public Guid PersistenceID { get; private set; } // public Guid PersistenceID { get; private set; }
public string[] StoredFieldNames => fieldStore.Keys.ToArray(); // public string[] StoredFieldNames => fieldStore.Keys.ToArray();
public IEnumerable<Guid> ReferencedPersistentIDs => referencedPersistentIDs; // public IEnumerable<Guid> ReferencedPersistentIDs => referencedPersistentIDs;
public IEnumerable<IPersistent> ReferencedPersistents => referencedPersistents; // public IEnumerable<IPersistent> ReferencedPersistents => referencedPersistents;
List<Guid> referencedPersistentIDs = new List<Guid>(); // List<Guid> referencedPersistentIDs = new List<Guid>();
HashSet<IPersistent> referencedPersistents = new HashSet<IPersistent>(); // HashSet<IPersistent> referencedPersistents = new HashSet<IPersistent>();
Dictionary<string, byte[]> fieldStore = new Dictionary<string, byte[]>(); // Dictionary<string, byte[]> fieldStore = new Dictionary<string, byte[]>();
public PreparedObject(ODB odb,Type preparedType,Guid persistenceID) // public PreparedObject(ODB odb,Type preparedType,Guid persistenceID)
{ // {
ODB = odb; // ODB = odb;
Timestamp = DateTime.Now; // Timestamp = DateTime.Now;
PreparedType = preparedType; // PreparedType = preparedType;
PersistenceID = persistenceID; // PersistenceID = persistenceID;
Instance = null; // Instance = null;
} // }
public PreparedObject(ODB odb, IPersistent o) // public PreparedObject(ODB odb, IPersistent o)
{ // {
ODB = odb; // ODB = odb;
Timestamp = DateTime.Now; // Timestamp = DateTime.Now;
PreparedType = o.GetType(); // PreparedType = o.GetType();
PersistenceID = o.GetPersistenceID(); // PersistenceID = o.GetPersistenceID();
Instance = o; // Instance = o;
SyncFromInstance(); // SyncFromInstance();
} // }
private IEnumerable<FieldInfo> GetAllFields(Type type) // private IEnumerable<FieldInfo> GetAllFields(Type type)
{ // {
if (type == typeof(object)) // if (type == typeof(object))
{ // {
return new FieldInfo[0]; // return new FieldInfo[0];
} // }
else // else
{ // {
return GetAllFields(type.BaseType).Concat(type.GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.DeclaredOnly)); // return GetAllFields(type.BaseType).Concat(type.GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.DeclaredOnly));
} // }
} // }
private void SyncFromInstance() // public void SyncFromInstance()
{ // {
referencedPersistentIDs.Clear(); // referencedPersistentIDs.Clear();
FieldInfo[] fields = GetAllFields(PreparedType).ToArray(); // FieldInfo[] fields = GetAllFields(PreparedType).ToArray();
foreach (FieldInfo fieldInfo in fields) // foreach (FieldInfo fieldInfo in fields)
{ // {
if (!fieldInfo.IsStatic) // if (!fieldInfo.IsStatic && (fieldInfo.GetCustomAttribute<Unsynced>() == null))
{ // {
object value = fieldInfo.GetValue(Instance); // object value = fieldInfo.GetValue(Instance);
if (value == null) // if (value == null)
{ // {
fieldStore[fieldInfo.Name] = new byte[0]; // fieldStore[fieldInfo.Name] = new byte[0];
} // }
else // else
{ // {
MemoryStream objectStream = new MemoryStream(); // MemoryStream objectStream = new MemoryStream();
ODBObjectWriter objectWriter = new ODBObjectWriter(objectStream); // ODBObjectWriter objectWriter = new ODBObjectWriter(objectStream);
objectWriter.Write(value); // objectWriter.Write(value);
fieldStore[fieldInfo.Name] = objectStream.ToArray(); // fieldStore[fieldInfo.Name] = objectStream.ToArray();
referencedPersistentIDs.AddRange(objectWriter.ReferencedPersistentIDs); // referencedPersistentIDs.AddRange(objectWriter.ReferencedPersistentIDs);
foreach (IPersistent persistent in objectWriter.ReferencedPersistents) // foreach (IPersistent persistent in objectWriter.ReferencedPersistents)
referencedPersistents.Add(persistent); // referencedPersistents.Add(persistent);
} // }
} // }
} // }
} // }
private void SyncToInstance() // public void SyncToInstance()
{ // {
foreach (FieldInfo fieldInfo in GetAllFields(PreparedType)) // foreach (FieldInfo fieldInfo in GetAllFields(PreparedType))
{ // {
if (!fieldInfo.IsStatic) // if (!fieldInfo.IsStatic && (fieldInfo.GetCustomAttribute<Unsynced>() == null))
{ // {
byte[] bytes = fieldStore[fieldInfo.Name]; // byte[] bytes = fieldStore[fieldInfo.Name];
if (bytes.Length == 0) // if (bytes.Length == 0)
{ // {
fieldInfo.SetValue(Instance, null); // fieldInfo.SetValue(Instance, null);
} // }
else // else
{ // {
MemoryStream objectStream = new MemoryStream(fieldStore[fieldInfo.Name]); // MemoryStream objectStream = new MemoryStream(fieldStore[fieldInfo.Name]);
ODBObjectReader objectReader = new ODBObjectReader(ODB, objectStream); // ODBObjectReader objectReader = new ODBObjectReader(ODB, objectStream);
object value = objectReader.Read(); // object value = objectReader.Read();
fieldInfo.SetValue(Instance, value); // fieldInfo.SetValue(Instance, value);
} // }
} // }
} // }
} // }
public void ReConfigure(Type targetType,DateTime timestamp) // public void ReConfigure(Type targetType,DateTime timestamp)
{ // {
Timestamp = timestamp; // Timestamp = timestamp;
PreparedType = targetType; // PreparedType = targetType;
fieldStore.Clear(); // fieldStore.Clear();
Instance = null; // Instance = null;
} // }
public byte[] GetFieldBytes(string fieldName) // public byte[] GetFieldBytes(string fieldName)
{ // {
return fieldStore[fieldName]; // return fieldStore[fieldName];
} // }
public void SetFieldBytes(string fieldName,byte[] bytes) // public void SetFieldBytes(string fieldName,byte[] bytes)
{ // {
fieldStore[fieldName] = bytes; // fieldStore[fieldName] = bytes;
} // }
public IPersistent CreateInstance() // public IPersistent CreateInstance()
{ // {
Instance = (IPersistent)Activator.CreateInstance(PreparedType,true); // Instance = (IPersistent)Activator.CreateInstance(PreparedType,true);
SyncToInstance(); // SyncToInstance();
return Instance; // return Instance;
} // }
public bool InstanceEquals(PreparedObject other) // public bool InstanceEquals(PreparedObject other)
{ // {
if (other == null) // if (other == null)
return false; // return false;
if (Equals(other)) // if (Equals(other))
{ // {
foreach (String fieldName in fieldStore.Keys) // foreach (String fieldName in fieldStore.Keys)
{ // {
byte[] me = fieldStore[fieldName]; // byte[] me = fieldStore[fieldName];
byte[] you = other.fieldStore[fieldName]; // byte[] you = other.fieldStore[fieldName];
File.WriteAllBytes("me.bin", me); // if (!me.AreEqual(you))
File.WriteAllBytes("you.bin", you); // return false;
// }
// return true;
// }
// return false;
// }
if (!me.AreEqual(you)) // public override int GetHashCode()
return false; // {
} // return PersistenceID.GetHashCode() ^ PreparedType.GetHashCode();
return true; // }
}
return false;
}
public override int GetHashCode() // public override bool Equals(object obj)
{ // {
return PersistenceID.GetHashCode() ^ PreparedType.GetHashCode(); // if (obj is PreparedObject)
} // {
// PreparedObject you = obj as PreparedObject;
// return PreparedType.Equals(you.PreparedType) && PersistenceID.Equals(you.PersistenceID);
// }
// return false;
// }
public override bool Equals(object obj) //}
{
if (obj is PreparedObject)
{
PreparedObject you = obj as PreparedObject;
return PreparedType.Equals(you.PreparedType) && PersistenceID.Equals(you.PersistenceID);
}
return false;
}
}
} }

View File

@ -1,19 +1,19 @@
using System; using System;
namespace ln.types.odb namespace ln.types.odb
{ {
public abstract class Storage //public abstract class Storage
{ //{
public Storage() // public Storage()
{ // {
} // }
public abstract bool Contains(Guid persistenceID); // public abstract bool Contains(Guid persistenceID);
public abstract bool Store(PreparedObject preparedObject); // public abstract bool Store(PreparedObject preparedObject);
public abstract bool Load(PreparedObject preparedObject); // public abstract bool Load(PreparedObject preparedObject);
} //}
} }

View File

@ -0,0 +1,28 @@
using System;
namespace ln.types.odb.values
{
public class ODBDouble : ODBValue
{
public ODBDouble()
:base(0x18)
{
}
public ODBDouble(double value)
: this()
{
Value = value;
}
public override byte[] ToStorage()
{
return BitConverter.GetBytes(AsDouble);
}
static ODBDouble()
{
RegisterDeserializer(0x0018, (b, o, l) => BitConverter.ToDouble(b, o));
//RegisterValueFactory(typeof(double), v => new ODBDouble((double)v));
//RegisterValueFactory(typeof(float), v => new ODBDouble((double)v));
}
}
}

View File

@ -0,0 +1,36 @@
using System;
using System.Linq;
namespace ln.types.odb.values
{
public class ODBGuid : ODBValue
{
public ODBGuid()
:base(0x03)
{
Value = Guid.NewGuid();
}
public ODBGuid(Guid guid)
:this()
{
Value = guid;
}
public override byte[] ToStorage()
{
return AsGuid.ToByteArray();
}
static Guid FromByteArray(byte[] b,int offset)
{
byte[] s = new byte[16];
Array.Copy(b, offset, s, 0, 16);
return new Guid(s);
}
static ODBGuid()
{
RegisterDeserializer(0x03, (b,o,l) => FromByteArray(b,o));
}
}
}

View File

@ -0,0 +1,53 @@
using System;
using System.Runtime.CompilerServices;
namespace ln.types.odb.values
{
public class ODBInteger : ODBValue
{
public ODBInteger()
: base(0x10)
{
}
public ODBInteger(int i)
: this()
{
Value = i;
}
public override bool AsBool => AsInt != 0;
public override byte[] ToStorage() => BitConverter.GetBytes(AsInt);
static ODBInteger()
{
RegisterDeserializer(0x10, (b, o, l) => BitConverter.ToInt32(b, o));
//RegisterValueFactory(typeof(int), v => new ODBInteger((int)v));
//RegisterValueFactory(typeof(short), v => new ODBInteger((int)(short)v));
//RegisterValueFactory(typeof(byte), v => new ODBInteger((int)(byte)v));
}
}
public class ODBUInteger : ODBValue
{
public ODBUInteger()
: base(0x11)
{
}
public ODBUInteger(uint i)
: this()
{
Value = i;
}
public override byte[] ToStorage() => BitConverter.GetBytes(AsUInt);
static ODBUInteger()
{
RegisterDeserializer(0x11, (b, o, l) => BitConverter.ToUInt32(b, o));
//RegisterValueFactory(typeof(uint), v => new ODBUInteger((uint)v));
//RegisterValueFactory(typeof(ushort), v => new ODBUInteger((uint)(ushort)v));
//RegisterValueFactory(typeof(char), v => new ODBUInteger((uint)(char)v));
}
}
}

View File

@ -0,0 +1,79 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Collections;
using System.Runtime.CompilerServices;
namespace ln.types.odb.values
{
public class ODBList : ODBValue
{
List<ODBValue> items = new List<ODBValue>();
public ODBList()
:base(0x02)
{
}
public ODBList(byte[] bytes,int offset,int length)
:this()
{
MemoryStream stream = new MemoryStream(bytes, offset, length);
int nItems = stream.ReadInteger();
for (int n = 0; n < nItems; n++)
items.Add(ODBValue.Read(stream));
}
public ODBValue this[int i]
{
get => items[i];
set => items[i] = value;
}
public void Add(ODBValue value)
{
items.Add(value);
}
public void Remove(ODBValue value)
{
items.Remove(value);
}
public void RemoveAt(int i)
{
items.RemoveAt(i);
}
public int Count => items.Count;
public override object Value {
get
{
object[] a = new object[items.Count];
((IList)items).CopyTo(a, 0);
return a;
}
protected set
{
throw new NotSupportedException();
}
}
public override byte[] ToStorage()
{
MemoryStream stream = new MemoryStream();
BinaryWriter writer = new BinaryWriter(stream);
writer.Write(items.Count);
foreach (ODBValue value in items)
value.Store(writer);
return stream.ToArray();
}
static ODBList()
{
RegisterDeserializer(0x02, (b, o, l) => new ODBList(b,o,l));
}
}
}

View File

@ -0,0 +1,52 @@
using System;
using System.Runtime.CompilerServices;
namespace ln.types.odb.values
{
public class ODBLong : ODBValue
{
public ODBLong()
: base(0x12)
{
}
public ODBLong(long i)
: this()
{
Value = i;
}
public override byte[] ToStorage() => BitConverter.GetBytes(AsLong);
public override DateTime AsDateTime => DateTimeOffset.FromUnixTimeMilliseconds(AsLong).DateTime;
public override TimeSpan AsTimeSpan => TimeSpan.FromMilliseconds(AsDouble);
static ODBLong()
{
RegisterDeserializer(0x12, (b, o, l) => BitConverter.ToInt64(b, o));
//RegisterValueFactory(typeof(long), v => new ODBLong((long)v));
//RegisterValueFactory(typeof(DateTime), v => new ODBLong(new DateTimeOffset((DateTime)v).ToUnixTimeMilliseconds()));
}
}
public class ODBULong : ODBValue
{
public ODBULong()
: base(0x13)
{
}
public ODBULong(ulong i)
: this()
{
Value = i;
}
public override byte[] ToStorage() => BitConverter.GetBytes(AsULong);
static ODBULong()
{
RegisterDeserializer(0x13, (b, o, l) => BitConverter.ToUInt64(b, o));
//RegisterValueFactory(typeof(ulong), v => new ODBULong((ulong)v));
}
}
}

View File

@ -0,0 +1,32 @@
using System;
namespace ln.types.odb.values
{
public class ODBNull : ODBValue
{
public static readonly ODBNull Instance = new ODBNull();
public ODBNull()
: base(0x00)
{ }
public override byte[] ToStorage()
{
return new byte[0];
}
static ODBNull()
{
RegisterDeserializer(0x00, (b,o,l) => Instance);
}
public override int GetHashCode()
{
return 0;
}
public override bool Equals(object obj)
{
return (obj == null) || (obj is ODBNull);
}
}
}

View File

@ -0,0 +1,36 @@
using System;
using System.Text;
namespace ln.types.odb.values
{
public class ODBStringValue : ODBValue
{
public ODBStringValue()
: base(0x01)
{ }
public ODBStringValue(String text)
: this()
{
Value = text;
}
public override byte[] ToStorage()
{
return Encoding.UTF8.GetBytes(AsString);
}
public static implicit operator ODBStringValue(String text)
{
return new ODBStringValue(text);
}
static ODBStringValue()
{
RegisterDeserializer(0x01, (b, o, l) => new ODBStringValue(Encoding.UTF8.GetString(b, o, l)));
// RegisterValueFactory(typeof(string), v => new ODBStringValue((string)v));
}
}
}

View File

@ -0,0 +1,150 @@
using System;
using System.Collections.Generic;
using System.IO;
/**
* typeCode list
*
* 0x0000 ODBNull
* 0x0001 ODBStringValue
* 0x0002 ODBList
* 0x0003 ODBGuid
*
* 0x0010 ODBInteger
* 0x0011 ODBUInteger
* 0x0012 ODBLong
* 0x0013 ODBULong
*
* 0x0018 ODBDouble
*
* 0x1000 ODBDocument
*
*
*
**/
namespace ln.types.odb.values
{
public delegate ODBValue ODBValueFactory(object value);
public delegate ODBValue ODBDeserialize(byte[] storageBytes, int offset, int length);
public abstract class ODBValue
{
int storageTypeCode;
public virtual object Value { get; protected set; }
protected ODBValue(int storageTypeCode)
{
this.storageTypeCode = storageTypeCode;
}
protected ODBValue(int storageTypeCode, object value)
: this(storageTypeCode)
{
Value = value;
}
public abstract byte[] ToStorage();
public object AsObject => Value;
public virtual string AsString => (string)Value;
public virtual bool AsBool => (bool)Value;
public virtual byte AsByte => (byte)Value;
public virtual char AsChar => (char)Value;
public virtual short AsShort => (short)Value;
public virtual int AsInt => (int)Value;
public virtual long AsLong => (long)Value;
public virtual ushort AsUShort => (ushort)Value;
public virtual uint AsUInt => (uint)Value;
public virtual ulong AsULong => (ulong)Value;
public virtual double AsDouble => (double)Value;
public virtual float AsFloat => (float)Value;
public virtual Guid AsGuid => (Guid)Value;
public virtual DateTime AsDateTime => (DateTime)Value;
public virtual TimeSpan AsTimeSpan => (TimeSpan)Value;
public virtual ODBDocument AsDocument => (ODBDocument)this;
public virtual void Store(BinaryWriter storage)
{
byte[] storageBytes = ToStorage();
storage.Write(storageTypeCode);
storage.Write(storageBytes.Length);
storage.Write(storageBytes, 0, storageBytes.Length);
}
public override int GetHashCode()
{
return Value.GetHashCode();
}
public override bool Equals(object obj)
{
if (obj is ODBValue)
{
ODBValue you = obj as ODBValue;
return Value.Equals(you.Value);
}
return Value.Equals(obj);
}
//static Dictionary<Type, ODBValueFactory> valueFactories = new Dictionary<Type, ODBValueFactory>();
//public static void RegisterValueFactory(Type type, ODBValueFactory factory)
//{
// valueFactories.Add(type, factory);
//}
public static implicit operator ODBValue(ValueType v)
{
return ODBMapper.Default.MapValue(v);
}
public static implicit operator ODBValue(String v)
{
return ODBMapper.Default.MapValue(v);
}
public static ODBValue FromNative(object v)
{
return ODBMapper.Default.MapValue(v);
}
static Dictionary<int, ODBDeserialize> valueDeserializers = new Dictionary<int, ODBDeserialize>();
public static void RegisterDeserializer(int storageTypeCode, ODBDeserialize deserialize)
{
valueDeserializers.Add(storageTypeCode, deserialize);
}
public static ODBValue Deserialize(byte[] buffer, ref int offset)
{
int storageTypeCode = BitConverter.ToInt32(buffer, offset);
int storageLength = BitConverter.ToInt32(buffer, offset + 4);
ODBValue value = valueDeserializers[storageTypeCode](buffer, offset + 8, storageLength);
offset += 8 + storageLength;
return value;
}
public static ODBValue Read(Stream stream)
{
int storageTypeCode = stream.ReadInteger();
int storageLength = stream.ReadInteger();
byte[] b = new byte[storageLength];
stream.Read(b, 0, storageLength);
return valueDeserializers[storageTypeCode](b, 0, storageLength);
}
public override string ToString()
{
return String.Format("[ODBValue Value={0}]", Value);
}
}
}

View File

@ -1,5 +1,6 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<packages> <packages>
<package id="Castle.Core" version="4.3.1" targetFramework="net47" /> <package id="Castle.Core" version="4.3.1" targetFramework="net47" />
<package id="LiteDB" version="4.1.4" targetFramework="net47" />
<package id="Newtonsoft.Json" version="12.0.1" targetFramework="net47" /> <package id="Newtonsoft.Json" version="12.0.1" targetFramework="net47" />
</packages> </packages>

View File

@ -182,6 +182,7 @@ namespace ln.types.serialize
public object ReadObject() public object ReadObject()
{ {
Type type = Read<Type>(); Type type = Read<Type>();
object o = Activator.CreateInstance(type,true); object o = Activator.CreateInstance(type,true);
referencedObjects.Add(o); referencedObjects.Add(o);

View File

@ -214,33 +214,38 @@ namespace ln.types.threads
{ {
supervisorThread = Thread.CurrentThread; supervisorThread = Thread.CurrentThread;
while (CurrentPoolSize > 0) lock (supervisorThread)
{ {
while (CurrentPoolSize != TargetPoolSize)
{
if (CurrentPoolSize - TargetPoolSize > 0)
{
lock (queuedJobs)
{
releaseThreads = CurrentPoolSize - TargetPoolSize;
}
while (CurrentPoolSize > 0)
{
Monitor.Wait(supervisorThread, 1000);
while (CurrentPoolSize != TargetPoolSize)
{
if (CurrentPoolSize - TargetPoolSize > 0) if (CurrentPoolSize - TargetPoolSize > 0)
{ {
lock (queuedJobs) lock (queuedJobs)
{ {
Monitor.PulseAll(queuedJobs); releaseThreads = CurrentPoolSize - TargetPoolSize;
}
if (CurrentPoolSize - TargetPoolSize > 0)
{
lock (queuedJobs)
{
Monitor.PulseAll(queuedJobs);
}
} }
} }
} else if (CurrentPoolSize - TargetPoolSize < 0)
else if (CurrentPoolSize - TargetPoolSize < 0) {
{ for (int n = CurrentPoolSize; n < TargetPoolSize; n++)
for (int n = CurrentPoolSize; n < TargetPoolSize; n++) new PoolThread(this);
new PoolThread(this); }
} }
} }
} }
supervisorThread = null; supervisorThread = null;
} }