experimental
This commit is contained in:
70
Experimental/CompressedArray.cs
Normal file
70
Experimental/CompressedArray.cs
Normal file
@@ -0,0 +1,70 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading;
|
||||
|
||||
namespace DTLib
|
||||
{
|
||||
public class CompressedArray
|
||||
{
|
||||
public class Array1D<T> where T : IComparable<T>
|
||||
{
|
||||
byte[] Description;
|
||||
T[] Memory;
|
||||
|
||||
public Array1D() { }
|
||||
public Array1D(T[] sourceArray) => CompressArray(sourceArray);
|
||||
|
||||
public void CompressArray(T[] sourceArray)
|
||||
{
|
||||
var listMem = new List<T>();
|
||||
var listDesc = new List<byte>();
|
||||
T prevElement = sourceArray[0];
|
||||
listMem.Add(sourceArray[0]);
|
||||
listDesc.Add(1);
|
||||
byte repeats = 1;
|
||||
for (int i = 1; i < sourceArray.Length; i++)
|
||||
{
|
||||
if (prevElement.CompareTo(sourceArray[i]) == 0)
|
||||
repeats++;
|
||||
else
|
||||
{
|
||||
listMem.Add(sourceArray[i]);
|
||||
listDesc.Add(1);
|
||||
if (repeats > 1)
|
||||
{
|
||||
listDesc[listDesc.Count - 2] = repeats;
|
||||
repeats = 1;
|
||||
}
|
||||
}
|
||||
prevElement = sourceArray[i];
|
||||
}
|
||||
Memory = listMem.ToArray();
|
||||
Description = listDesc.ToArray();
|
||||
ColoredConsole.Write("b", "listMem.Count: ", "c", listMem.Count.ToString(), "b", " listDesc.Count: ", "c", listDesc.Count + "\n");
|
||||
for (short i = 0; i < listDesc.Count; i++)
|
||||
{
|
||||
ColoredConsole.Write("y", $"{Description[i]}:{Memory[i]}\n");
|
||||
}
|
||||
}
|
||||
|
||||
// блокирует обращение к памяти из нескольких потоков
|
||||
Mutex storageUsing = new();
|
||||
|
||||
// возвращает элемент по индексу так, как если бы шло обращение к обычном массиву
|
||||
public T GetElement(int index)
|
||||
{
|
||||
storageUsing.WaitOne();
|
||||
T output = default;
|
||||
int sum = 0;
|
||||
for (int i = 0; i < Description.Length; i++)
|
||||
{
|
||||
if (sum < index)
|
||||
sum += Description[i];
|
||||
else output = sum == index ? Memory[i] : Memory[i - 1];
|
||||
}
|
||||
storageUsing.ReleaseMutex();
|
||||
return output;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
69
Experimental/ConsoleGUI/Container.cs
Normal file
69
Experimental/ConsoleGUI/Container.cs
Normal file
@@ -0,0 +1,69 @@
|
||||
using DTLib.Dtsod;
|
||||
using DTLib.Filesystem;
|
||||
using System.Collections.Generic;
|
||||
using static DTLib.PublicLog;
|
||||
|
||||
namespace DTLib.ConsoleGUI
|
||||
{
|
||||
public class Container : List<IDrawable>, IDrawable
|
||||
{
|
||||
public (ushort x, ushort y) AnchorPoint { get; set; }
|
||||
public ushort Width { get; set; }
|
||||
public ushort Height { get; set; }
|
||||
public char[] Textmap { get; private set; }
|
||||
public char[] Colormap { get; private set; }
|
||||
public string Name { get; private set; }
|
||||
|
||||
public Container(string name, string layout_file)
|
||||
{
|
||||
Name=name;
|
||||
ParseLayoutFile(layout_file);
|
||||
}
|
||||
|
||||
void ParseLayoutFile(string layout_file)
|
||||
{
|
||||
DtsodV22 layout = new(File.ReadAllText(layout_file));
|
||||
AnchorPoint=(layout[Name]["anchor"][0], layout[Name]["anchor"][1]);
|
||||
Width=layout[Name]["width"];
|
||||
Height=layout[Name]["height"];
|
||||
foreach(string element_name in layout[Name]["children"].Keys)
|
||||
{
|
||||
switch(layout[Name]["children"][element_name]["type"])
|
||||
{
|
||||
case "label":
|
||||
Add(new Label(element_name,
|
||||
layout[Name]["children"][element_name]["resdir"]+$"\\{element_name}.textmap",
|
||||
layout[Name]["children"][element_name]["resdir"]+$"\\{element_name}.colormap")
|
||||
{
|
||||
AnchorPoint=(layout[Name]["children"][element_name]["anchor"][0],
|
||||
layout[Name]["children"][element_name]["anchor"][1])
|
||||
});
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void GenTextmap()
|
||||
{
|
||||
Textmap=new char[Width*Height];
|
||||
for(int i = 0; i<Textmap.Length; i++)
|
||||
Textmap[i]=' ';
|
||||
foreach(IDrawable element in this)
|
||||
{
|
||||
element.GenTextmap();
|
||||
Log("m", $"Length: {element.Textmap.Length} calculated: {element.Width*element.Height}\n");
|
||||
for(ushort y = 0; y<element.Height; y++)
|
||||
for(ushort x = 0; x<element.Width; x++)
|
||||
{
|
||||
//Textmap[(element.AnchorPoint.y + y) * Width + element.AnchorPoint.x + x] = element.Textmap[y * element.Width + x];
|
||||
Textmap[(y)*Width+x]=element.Textmap[y*element.Width+x];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void GenColormap()
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
16
Experimental/ConsoleGUI/Control.cs
Normal file
16
Experimental/ConsoleGUI/Control.cs
Normal file
@@ -0,0 +1,16 @@
|
||||
namespace DTLib.ConsoleGUI
|
||||
{
|
||||
public class Control : Label
|
||||
{
|
||||
|
||||
public new void GenColormap()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public new void GenTextmap()
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
17
Experimental/ConsoleGUI/IDrawable.cs
Normal file
17
Experimental/ConsoleGUI/IDrawable.cs
Normal file
@@ -0,0 +1,17 @@
|
||||
namespace DTLib.ConsoleGUI
|
||||
{
|
||||
public interface IDrawable
|
||||
{
|
||||
public (ushort x, ushort y) AnchorPoint { get; set; }
|
||||
public ushort Width { get; }
|
||||
public ushort Height { get; }
|
||||
public char[] Textmap { get; }
|
||||
public char[] Colormap { get; }
|
||||
public string Name { get; }
|
||||
|
||||
public void GenTextmap();
|
||||
|
||||
public void GenColormap();
|
||||
|
||||
}
|
||||
}
|
||||
35
Experimental/ConsoleGUI/Label.cs
Normal file
35
Experimental/ConsoleGUI/Label.cs
Normal file
@@ -0,0 +1,35 @@
|
||||
using DTLib.Filesystem;
|
||||
|
||||
namespace DTLib.ConsoleGUI
|
||||
{
|
||||
public class Label : IDrawable
|
||||
{
|
||||
public (ushort x, ushort y) AnchorPoint { get; set; } = (0, 0);
|
||||
public ushort Width { get; private set; }
|
||||
public ushort Height { get; private set; }
|
||||
public char[] Textmap { get; private set; }
|
||||
public char[] Colormap { get; private set; }
|
||||
|
||||
public string TextmapFile { get; set; }
|
||||
public string ColormapFile { get; set; }
|
||||
public string Name { get; init; }
|
||||
|
||||
public Label() { }
|
||||
|
||||
public Label(string name, string textmapFile, string colormapFile)
|
||||
{
|
||||
TextmapFile=textmapFile;
|
||||
ColormapFile=colormapFile;
|
||||
Name=name;
|
||||
}
|
||||
|
||||
public void GenColormap() => Colormap=File.ReadAllText(ColormapFile).ToCharArray();
|
||||
|
||||
public void GenTextmap()
|
||||
{
|
||||
Textmap=File.ReadAllText(TextmapFile).ToCharArray();
|
||||
Width=12;
|
||||
Height=3;
|
||||
}
|
||||
}
|
||||
}
|
||||
36
Experimental/ConsoleGUI/Window.cs
Normal file
36
Experimental/ConsoleGUI/Window.cs
Normal file
@@ -0,0 +1,36 @@
|
||||
using DTLib.Filesystem;
|
||||
using System;
|
||||
using System.Text;
|
||||
|
||||
namespace DTLib.ConsoleGUI
|
||||
{
|
||||
//
|
||||
// создание gui из текста в консоли
|
||||
//
|
||||
public class Window : Container
|
||||
{
|
||||
|
||||
public Window(string layout_file) : base("window", layout_file)
|
||||
{
|
||||
Console.Clear();
|
||||
Console.SetWindowSize(Width+1, Height+1);
|
||||
Console.SetBufferSize(Width+1, Height+1);
|
||||
Console.OutputEncoding=Encoding.Unicode;
|
||||
Console.InputEncoding=Encoding.Unicode;
|
||||
Console.CursorVisible=false;
|
||||
}
|
||||
|
||||
// выводит все символы
|
||||
public void RenderFile(string file)
|
||||
{
|
||||
Console.Clear();
|
||||
Console.WriteLine(File.ReadAllText(file));
|
||||
}
|
||||
|
||||
public void Render()
|
||||
{
|
||||
GenTextmap();
|
||||
Console.WriteLine(SimpleConverter.MergeToString(Textmap));
|
||||
}
|
||||
}
|
||||
}
|
||||
186
Experimental/ConsoleGUI/WindowOld.cs
Normal file
186
Experimental/ConsoleGUI/WindowOld.cs
Normal file
@@ -0,0 +1,186 @@
|
||||
using DTLib.Filesystem;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace DTLib.ConsoleGUI
|
||||
{
|
||||
//
|
||||
// создание gui из текста в консоли
|
||||
//
|
||||
public class WindowOld
|
||||
{
|
||||
public int WindowWidth { get; private set; }
|
||||
public int WindowHeight { get; private set; }
|
||||
public char[,] Text;
|
||||
public char[,] nowText;
|
||||
public char[,] TextColors;
|
||||
public char[,] nowTextColors;
|
||||
|
||||
public Container WindowContainer;
|
||||
|
||||
public WindowOld(int windowWidth, int windowHeight)
|
||||
{
|
||||
WindowWidth=windowWidth;
|
||||
WindowHeight=windowHeight;
|
||||
Text=new char[windowWidth, windowHeight];
|
||||
TextColors=new char[windowWidth, windowHeight];
|
||||
nowText=TextColors;
|
||||
nowTextColors=new char[windowWidth, windowHeight];
|
||||
Console.WindowWidth=WindowWidth+1;
|
||||
Console.WindowHeight=WindowHeight+1;
|
||||
Console.BufferWidth=WindowWidth+1;
|
||||
Console.BufferHeight=WindowHeight+1;
|
||||
Console.OutputEncoding=Encoding.Unicode;
|
||||
Console.InputEncoding=Encoding.Unicode;
|
||||
Console.CursorVisible=false;
|
||||
// заполнение массивов
|
||||
for(sbyte y = 0; y<WindowHeight; y++)
|
||||
{
|
||||
for(sbyte x = 0; x<WindowWidth; x++)
|
||||
{
|
||||
Text[x, y]=' ';
|
||||
TextColors[x, y]='w';
|
||||
}
|
||||
}
|
||||
nowText=TextColors;
|
||||
}
|
||||
|
||||
/*// считывает массив символов из файла
|
||||
// ширина и высота текста должны быть как указанные при инициализации объекта этого класса
|
||||
public void ReadFromFile(string path)
|
||||
{
|
||||
var r = new StreamReader(path, SimpleConverter.UTF8);
|
||||
char[] s = new char[1];
|
||||
// считывание текста
|
||||
sbyte y = 0, x = 0;
|
||||
r.Read(s, 0, 1);
|
||||
while (!r.EndOfStream && y < WindowHeight)
|
||||
{
|
||||
if (x == WindowWidth)
|
||||
{
|
||||
r.Read(s, 0, 1);
|
||||
x = 0;
|
||||
y++;
|
||||
}
|
||||
else
|
||||
{
|
||||
Text[x, y] = s[0];
|
||||
x++;
|
||||
}
|
||||
r.Read(s, 0, 1);
|
||||
}
|
||||
r.Read(s, 0, 1);
|
||||
// считывание цвета
|
||||
// если не находит цвет в файле, оставляет старый
|
||||
if (s[0] == '\n')
|
||||
{
|
||||
r.Read(s, 0, 1);
|
||||
y = 0;
|
||||
x = 0;
|
||||
while (!r.EndOfStream && y < WindowHeight)
|
||||
{
|
||||
if (x == WindowWidth)
|
||||
{
|
||||
r.Read(s, 0, 1);
|
||||
x = 0;
|
||||
y++;
|
||||
}
|
||||
else
|
||||
{
|
||||
TextColors[x, y] = s[0];
|
||||
x++;
|
||||
}
|
||||
r.Read(s, 0, 1);
|
||||
}
|
||||
}
|
||||
r.Close();
|
||||
}*/
|
||||
|
||||
public void ResetCursor() => Console.SetCursorPosition(0, WindowHeight);
|
||||
|
||||
// заменяет символ выведенный, использовать после ShowAll()
|
||||
public void ChangeChar(sbyte x, sbyte y, char ch)
|
||||
{
|
||||
Text[x, y]=ch;
|
||||
nowText[x, y]=ch;
|
||||
Console.SetCursorPosition(x, y);
|
||||
ColoredConsole.Write(TextColors[x, y].ToString(), ch.ToString());
|
||||
}
|
||||
|
||||
public void ChangeColor(sbyte x, sbyte y, char color)
|
||||
{
|
||||
TextColors[x, y]=color;
|
||||
nowTextColors[x, y]=color;
|
||||
Console.SetCursorPosition(x, y);
|
||||
ColoredConsole.Write(color.ToString(), Text[x, y].ToString());
|
||||
}
|
||||
|
||||
public void ChangeCharAndColor(sbyte x, sbyte y, char color, char ch)
|
||||
{
|
||||
Text[x, y]=ch;
|
||||
nowText[x, y]=ch;
|
||||
TextColors[x, y]=color;
|
||||
nowTextColors[x, y]=color;
|
||||
Console.SetCursorPosition(x, y);
|
||||
ColoredConsole.Write(color.ToString(), ch.ToString());
|
||||
}
|
||||
|
||||
public void ChangeLine(sbyte x, sbyte y, char color, string line)
|
||||
{
|
||||
Console.SetCursorPosition(x, y);
|
||||
for(sbyte i = 0; i<line.Length; i++)
|
||||
{
|
||||
Text[x+i, y]=line[i];
|
||||
nowText[x+i, y]=line[i];
|
||||
TextColors[x+i, y]=color;
|
||||
nowTextColors[x+i, y]=color;
|
||||
}
|
||||
ColoredConsole.Write(color.ToString(), line);
|
||||
}
|
||||
|
||||
// выводит все символы
|
||||
public void ShowAll()
|
||||
{
|
||||
var l = new List<string>();
|
||||
for(sbyte y = 0; y<WindowHeight; y++)
|
||||
{
|
||||
for(sbyte x = 0; x<WindowWidth; x++)
|
||||
{
|
||||
l.Add(TextColors[x, y].ToString());
|
||||
l.Add(Text[x, y].ToString());
|
||||
nowText[x, y]=Text[x, y];
|
||||
nowTextColors[x, y]=TextColors[x, y];
|
||||
}
|
||||
l.Add("w");
|
||||
l.Add("\n");
|
||||
}
|
||||
ColoredConsole.Write(l.ToArray());
|
||||
//Console.WriteLine();
|
||||
}
|
||||
|
||||
public void UpdateAll()
|
||||
{
|
||||
for(sbyte y = 0; y<WindowHeight; y++)
|
||||
{
|
||||
for(sbyte x = 0; x<WindowWidth; x++)
|
||||
{
|
||||
Console.SetCursorPosition(x, y);
|
||||
if(TextColors[x, y]!=nowTextColors[x, y]||Text[x, y]!=nowText[x, y])
|
||||
{
|
||||
ColoredConsole.Write(TextColors[x, y].ToString(), Text[x, y].ToString());
|
||||
nowText[x, y]=Text[x, y];
|
||||
nowTextColors[x, y]=TextColors[x, y];
|
||||
}
|
||||
}
|
||||
Console.Write('\n');
|
||||
}
|
||||
}
|
||||
|
||||
public void RenderFile(string file)
|
||||
{
|
||||
Console.Clear();
|
||||
Console.WriteLine(File.ReadAllText(file));
|
||||
}
|
||||
}
|
||||
}
|
||||
127
Experimental/MyDict.cs
Normal file
127
Experimental/MyDict.cs
Normal file
@@ -0,0 +1,127 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Linq;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace DTLib
|
||||
{
|
||||
public class MyDict<TKey, TVal>
|
||||
{
|
||||
object locker = new object();
|
||||
List<TVal> values;
|
||||
List<TKey> keys;
|
||||
List<int> hashes;
|
||||
int count;
|
||||
|
||||
public int Count
|
||||
{
|
||||
get
|
||||
{
|
||||
// lock (count)
|
||||
lock (locker) return count;
|
||||
}
|
||||
}
|
||||
|
||||
public ReadOnlyCollection<TVal> Values
|
||||
{
|
||||
get
|
||||
{
|
||||
ReadOnlyCollectionBuilder<TVal> b;
|
||||
lock (locker) b = new(values);
|
||||
return b.ToReadOnlyCollection();
|
||||
}
|
||||
}
|
||||
|
||||
public ReadOnlyCollection<TKey> Keys
|
||||
{
|
||||
get
|
||||
{
|
||||
ReadOnlyCollectionBuilder<TKey> b;
|
||||
lock (locker) b = new(keys);
|
||||
return b.ToReadOnlyCollection();
|
||||
}
|
||||
}
|
||||
|
||||
public MyDict()
|
||||
{
|
||||
|
||||
values = new();
|
||||
keys = new();
|
||||
hashes = new();
|
||||
count = 0;
|
||||
}
|
||||
|
||||
public MyDict(IList<TKey> _keys, IList<TVal> _values)
|
||||
{
|
||||
if (_keys.Count != _values.Count) throw new Exception("_keys.Count != _values.Count");
|
||||
keys = (List<TKey>)_keys;
|
||||
values = (List<TVal>)_values;
|
||||
count = _keys.Count;
|
||||
hashes = new();
|
||||
for (int i = 0; i < count; i++)
|
||||
hashes.Add(keys[i].GetHashCode());
|
||||
}
|
||||
|
||||
public TVal this[TKey key]
|
||||
{
|
||||
get
|
||||
{
|
||||
lock (locker) return values[hashes.IndexOf(key.GetHashCode())];
|
||||
}
|
||||
set
|
||||
{
|
||||
lock (locker) values[hashes.IndexOf(key.GetHashCode())] = value;
|
||||
}
|
||||
}
|
||||
|
||||
public (TKey, TVal) GetByIndex(int index)
|
||||
{
|
||||
(TKey k, TVal v) output;
|
||||
lock (locker)
|
||||
{
|
||||
output.k = keys[index];
|
||||
output.v = values[index];
|
||||
}
|
||||
return output;
|
||||
}
|
||||
|
||||
public void Add(TKey key, TVal val)
|
||||
{
|
||||
// lock (keys) lock (values) lock (count)
|
||||
lock (locker)
|
||||
{
|
||||
keys.Add(key);
|
||||
values.Add(val);
|
||||
hashes.Add(key.GetHashCode());
|
||||
count++;
|
||||
}
|
||||
}
|
||||
|
||||
public void Remove(TKey key)
|
||||
{
|
||||
var hash = key.GetHashCode();
|
||||
lock (locker)
|
||||
{
|
||||
var num = hashes.IndexOf(hash);
|
||||
keys.RemoveAt(num);
|
||||
values.RemoveAt(num);
|
||||
hashes.RemoveAt(num);
|
||||
count--;
|
||||
}
|
||||
}
|
||||
|
||||
public void Clear()
|
||||
{
|
||||
lock (locker)
|
||||
{
|
||||
hashes.Clear();
|
||||
keys.Clear();
|
||||
values.Clear();
|
||||
count = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
100
Experimental/Reactive/ReactiveListener.cs
Normal file
100
Experimental/Reactive/ReactiveListener.cs
Normal file
@@ -0,0 +1,100 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace DTLib.Reactive
|
||||
{
|
||||
public class ReactiveListener<T> : ReactiveProvider<T>
|
||||
{
|
||||
public ReactiveListener() { }
|
||||
public ReactiveListener(ReactiveStream<T> stream) : base(stream) { }
|
||||
public ReactiveListener(ICollection<ReactiveStream<T>> streams) : base(streams) { }
|
||||
|
||||
|
||||
public event Action<ReactiveStream<T>, T> ElementAddedEvent;
|
||||
void ElementAdded(ReactiveStream<T> stream, TimeSignedObject<T> e) => ElementAdded(stream, e.Value);
|
||||
void ElementAdded(ReactiveStream<T> stream, T e) =>
|
||||
Task.Run(() => ElementAddedEvent?.Invoke(stream, e));
|
||||
|
||||
public override void Join(ReactiveStream<T> stream)
|
||||
{
|
||||
base.Join(stream);
|
||||
lock (Streams) stream.ElementAddedEvent += ElementAdded;
|
||||
}
|
||||
|
||||
public override void Leave(ReactiveStream<T> stream)
|
||||
{
|
||||
base.Leave(stream);
|
||||
lock (Streams) stream.ElementAddedEvent -= ElementAdded;
|
||||
}
|
||||
|
||||
public T GetFirst()
|
||||
{
|
||||
if (Streams.Count == 0) throw new Exception("ReactiveListener is not connected to any streams");
|
||||
TimeSignedObject<T> rezult = null;
|
||||
foreach (ReactiveStream<T> stream in Streams)
|
||||
if (stream.Count != 0)
|
||||
{
|
||||
TimeSignedObject<T> e = stream[0];
|
||||
if (rezult is null) rezult = e;
|
||||
else if (rezult.Time > e.Time) rezult = e;
|
||||
}
|
||||
return rezult.Value;
|
||||
}
|
||||
public T GetLast()
|
||||
{
|
||||
if (Streams.Count == 0) throw new Exception("ReactiveListener is not connected to any streams");
|
||||
TimeSignedObject<T> rezult = null;
|
||||
foreach (ReactiveStream<T> stream in Streams)
|
||||
if (stream.Count != 0)
|
||||
{
|
||||
TimeSignedObject<T> e = stream[stream.Count - 1];
|
||||
if (rezult is null) rezult = e;
|
||||
else if (rezult.Time < e.Time) rezult = e;
|
||||
}
|
||||
return rezult.Value;
|
||||
}
|
||||
|
||||
public T FindOne(Func<T, bool> condition)
|
||||
{
|
||||
if (Streams.Count == 0) throw new Exception("ReactiveListener is not connected to any streams");
|
||||
foreach (ReactiveStream<T> stream in Streams)
|
||||
foreach (TimeSignedObject<T> el in stream)
|
||||
if (condition(el.Value))
|
||||
return el.Value;
|
||||
return default;
|
||||
}
|
||||
|
||||
public TimeSignedObject<T> FindOne(Func<TimeSignedObject<T>, bool> condition)
|
||||
{
|
||||
if (Streams.Count == 0) throw new Exception("ReactiveListener is not connected to any streams");
|
||||
foreach (ReactiveStream<T> stream in Streams)
|
||||
foreach (TimeSignedObject<T> el in stream)
|
||||
if (condition(el))
|
||||
return el;
|
||||
return default;
|
||||
}
|
||||
|
||||
public List<T> FindAll(Func<T, bool> condition)
|
||||
{
|
||||
if (Streams.Count == 0) throw new Exception("ReactiveListener is not connected to any streams");
|
||||
List<T> rezults = new();
|
||||
foreach (ReactiveStream<T> stream in Streams)
|
||||
foreach (TimeSignedObject<T> el in stream)
|
||||
if (condition(el.Value))
|
||||
rezults.Add(el.Value);
|
||||
return rezults;
|
||||
}
|
||||
|
||||
public List<TimeSignedObject<T>> FindAll(Func<TimeSignedObject<T>, bool> condition)
|
||||
{
|
||||
if (Streams.Count == 0) throw new Exception("ReactiveListener is not connected to any streams");
|
||||
List<TimeSignedObject<T>> rezults = new();
|
||||
foreach (ReactiveStream<T> stream in Streams)
|
||||
foreach (TimeSignedObject<T> el in stream)
|
||||
if (condition(el))
|
||||
rezults.Add(el);
|
||||
return rezults;
|
||||
}
|
||||
}
|
||||
}
|
||||
35
Experimental/Reactive/ReactiveProvider.cs
Normal file
35
Experimental/Reactive/ReactiveProvider.cs
Normal file
@@ -0,0 +1,35 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace DTLib.Reactive
|
||||
{
|
||||
public abstract class ReactiveProvider<T>
|
||||
{
|
||||
protected List<ReactiveStream<T>> Streams
|
||||
{
|
||||
get
|
||||
{ lock (_streams) return _streams; }
|
||||
set
|
||||
{ lock (_streams) _streams = value; }
|
||||
}
|
||||
private List<ReactiveStream<T>> _streams = new();
|
||||
|
||||
public ReactiveProvider() { }
|
||||
public ReactiveProvider(ReactiveStream<T> stream) => Streams.Add(stream);
|
||||
public ReactiveProvider(ICollection<ReactiveStream<T>> streams) => Streams = streams.ToList();
|
||||
|
||||
public virtual void Join(ReactiveStream<T> stream)
|
||||
{
|
||||
if (IsConnetcedTo(stream)) throw new Exception("ReactiveListener is already connected to the stream");
|
||||
Streams.Add(stream);
|
||||
}
|
||||
|
||||
public virtual void Leave(ReactiveStream<T> stream)
|
||||
{
|
||||
if (!Streams.Remove(stream)) throw new Exception("ReactiveListener is not connected to the stream");
|
||||
}
|
||||
|
||||
public bool IsConnetcedTo(ReactiveStream<T> stream) => Streams.Contains(stream);
|
||||
}
|
||||
}
|
||||
18
Experimental/Reactive/ReactiveSender.cs
Normal file
18
Experimental/Reactive/ReactiveSender.cs
Normal file
@@ -0,0 +1,18 @@
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace DTLib.Reactive
|
||||
{
|
||||
public class ReactiveSender<T> : ReactiveProvider<T>
|
||||
{
|
||||
|
||||
public ReactiveSender() { }
|
||||
public ReactiveSender(ReactiveStream<T> stream) : base(stream) { }
|
||||
public ReactiveSender(ICollection<ReactiveStream<T>> streams) : base(streams) { }
|
||||
|
||||
public void Send(T e)
|
||||
{
|
||||
foreach (ReactiveStream<T> s in Streams)
|
||||
s.Add(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
74
Experimental/Reactive/ReactiveStream.cs
Normal file
74
Experimental/Reactive/ReactiveStream.cs
Normal file
@@ -0,0 +1,74 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace DTLib.Reactive
|
||||
{
|
||||
public class ReactiveStream<T> : IEnumerable<TimeSignedObject<T>>, IList<TimeSignedObject<T>>
|
||||
{
|
||||
public ReactiveStream() { }
|
||||
|
||||
List<TimeSignedObject<T>> _storage = new();
|
||||
List<TimeSignedObject<T>> Storage
|
||||
{
|
||||
get
|
||||
{ lock (_storage) return _storage; }
|
||||
}
|
||||
|
||||
public int Count => Storage.Count;
|
||||
|
||||
public TimeSignedObject<T> this[int index]
|
||||
{
|
||||
get => Storage[index];
|
||||
set => throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public event Action<ReactiveStream<T>, TimeSignedObject<T>> ElementAddedEvent;
|
||||
public void Add(TimeSignedObject<T> elem)
|
||||
{
|
||||
Storage.Add(elem);
|
||||
ElementAddedEvent?.Invoke(this, elem);
|
||||
}
|
||||
public void Add(T elem) => Add(new TimeSignedObject<T>(elem));
|
||||
|
||||
public void Clear() => Storage.Clear();
|
||||
public int IndexOf(TimeSignedObject<T> item) => Storage.IndexOf(item);
|
||||
public bool Contains(TimeSignedObject<T> item) => Storage.Contains(item);
|
||||
|
||||
public IEnumerator<TimeSignedObject<T>> GetEnumerator() => new Enumerator(Storage);
|
||||
IEnumerator IEnumerable.GetEnumerator() => new Enumerator(Storage);
|
||||
|
||||
struct Enumerator : IEnumerator<TimeSignedObject<T>>
|
||||
{
|
||||
public Enumerator(List<TimeSignedObject<T>> storage)
|
||||
{
|
||||
_storage = storage;
|
||||
_index = storage.Count - 1;
|
||||
}
|
||||
|
||||
List<TimeSignedObject<T>> _storage;
|
||||
int _index;
|
||||
public TimeSignedObject<T> Current => _storage[_index];
|
||||
object IEnumerator.Current => Current;
|
||||
|
||||
public void Dispose() => _storage = null;
|
||||
|
||||
public bool MoveNext()
|
||||
{
|
||||
if (_index < 0)
|
||||
return false;
|
||||
_index--;
|
||||
return true;
|
||||
}
|
||||
|
||||
public void Reset() => _index = _storage.Count - 1;
|
||||
}
|
||||
|
||||
bool ICollection<TimeSignedObject<T>>.IsReadOnly { get; } = false;
|
||||
|
||||
public void Insert(int index, TimeSignedObject<T> item) => throw new NotImplementedException();
|
||||
public void RemoveAt(int index) => throw new NotImplementedException();
|
||||
public void CopyTo(TimeSignedObject<T>[] array, int arrayIndex) => throw new NotImplementedException();
|
||||
public bool Remove(TimeSignedObject<T> item) => throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
16
Experimental/Reactive/TimeSignedObject.cs
Normal file
16
Experimental/Reactive/TimeSignedObject.cs
Normal file
@@ -0,0 +1,16 @@
|
||||
using System;
|
||||
|
||||
namespace DTLib.Reactive
|
||||
{
|
||||
public class TimeSignedObject<T>
|
||||
{
|
||||
public T Value { get; init; }
|
||||
public long Time { get; init; }
|
||||
|
||||
public TimeSignedObject(T value)
|
||||
{
|
||||
Value = value;
|
||||
Time = DateTime.Now.Ticks;
|
||||
}
|
||||
}
|
||||
}
|
||||
37
Experimental/SecureRandom.cs
Normal file
37
Experimental/SecureRandom.cs
Normal file
@@ -0,0 +1,37 @@
|
||||
using System.Security.Cryptography;
|
||||
|
||||
namespace DTLib
|
||||
{
|
||||
//
|
||||
// Вычисление псевдослучайного числа из множества параметров.
|
||||
// Работает медленнее чем класс System.Random, но выдаёт более случайные значения
|
||||
//
|
||||
public class SecureRandom
|
||||
{
|
||||
private RNGCryptoServiceProvider crypt = new();
|
||||
|
||||
// получение массива случайных байтов
|
||||
public byte[] GenBytes(uint length)
|
||||
{
|
||||
byte[] output = new byte[length];
|
||||
crypt.GetNonZeroBytes(output);
|
||||
return output;
|
||||
}
|
||||
|
||||
// получение случайного числа от 0 до 2147483647
|
||||
/*public int NextInt(uint from, int to)
|
||||
{
|
||||
int output = 0;
|
||||
int rez = 0;
|
||||
while (true)
|
||||
{
|
||||
rez = output * 10 + NextBytes(1)[0];
|
||||
if (rez < to && rez > from)
|
||||
{
|
||||
output = rez;
|
||||
return output;
|
||||
}
|
||||
}
|
||||
}*/
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user