ErrorsManager/CSharp/ErrorsManager.cs

444 lines
15 KiB
C#

using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Mail;
using System.Text.RegularExpressions;
namespace ErrorsManager{
// public abstract record Error{
// private Error(){}
// public sealed record String(string value):Error;
// public sealed record Array(byte[] value):Error;
// public sealed record Integer(int value):Error;
// }
class ErrorsManager{
public static readonly char[] ALPHABET = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=".ToCharArray();
public static readonly Regex RE_KEY = new Regex(@"^[a-z_][a-z0-9_]*$", RegexOptions.IgnoreCase | RegexOptions.Compiled);
private Error error = 0;
private char[] alphabet;
private Dictionary<char, byte> dictionary = new Dictionary<char, byte>();
private byte _base;
private byte power;
public ErrorsManager(object? inputs = null){
set_alphabet(get<object?>("alphabet", inputs, ALPHABET));
}
public int set_alphabet(object? alphabet = null){
int original_length;
error = 0;
if(alphabet == null)
this.alphabet = ALPHABET;
else if(alphabet is string alphabet_string)
this.alphabet = alphabet_string.ToCharArray();
else if(alphabet is IEnumerable<char> alphabet_enumerable)
this.alphabet = alphabet_enumerable.ToArray<char>();
else{
error |= 1 << 2;
this.alphabet = ALPHABET;
}
original_length = this.alphabet.Length;
this.alphabet = this.alphabet.Distinct<char>().ToArray<char>();
if(this.alphabet.Length < 2){
error |= 1 << 3;
this.alphabet = ALPHABET;
}
if(this.alphabet.Length != original_length)
error |= 1 << 4;
if(this.alphabet.Length > 128)
error |= 1 << 5;
this.alphabet = this.alphabet.Take(
_base = (byte)Math.Pow(2,
power = (byte)Math.Log2(this.alphabet.Length)
)
).ToArray<char>();
dictionary.Clear();
for(byte i = 0; i < this.alphabet.Length; i ++)
dictionary[this.alphabet[i]] = i;
return error;
}
public string get_alphabet(){
return new string(alphabet);
}
public byte[] to_array(object code){
if(code is string _string)
return _string.Select<char, byte>(character => dictionary[character]).ToArray<byte>();
if(code is byte[] array)
return array;
if(code is int integer){
List<byte> hexas = new List<byte>();
while(integer != 0){
hexas.Add((byte)(integer % _base));
integer /= _base;
}
return hexas.ToArray<byte>();
}
return new byte[]{};
}
public string to_string(object code){
if(code is string _string)
return _string;
if(code is byte[] array)
return new string(array.Select<byte, char>(value => alphabet[value]).ToArray<char>());
if(code is int integer){
string hexas = new string();
while(integer != 0){
hexas += alphabet[(byte)(integer % _base)];
integer /= _base;
}
return hexas;
}
return "";
}
public int to_integer(object code){
if(code is string _string){
int integer = 0;
for(byte i = 0; i < _string.Length; i ++)
integer = integer * _base + dictionary[_string[i]];
return integer;
}
if(code is byte[] array){
int integer = 0;
for(byte i = 0; i < array.Length; i ++)
integer = integer * _base + array[i];
return integer;
}
if(code is int integer)
return integer;
return 0;
}
public (int, string)[] process(Error code, IEnumerable<string> messages){
List<(int, string)> response = new List<(int, string)>();
for_each_enumerate(get_hexas_from(code), (hexa, i) => {
for(byte j = 0; j < power && (hexa & 1 << j) <= hexa; j ++)
if((hexa & 1 << j) != 0){
int x = i * power + j;
response.Add((x, messages.ElementAtOrDefault(x) ?? "error_message_" + x.ToString()));
}
});
return response.ToArray();
}
public int get_bits(object code){
if(code is string _string)
return _string.Length == 0 ? 0 : (_string.Length - 1) * power + (int)Math.Ceiling(Math.Log2(dictionary[_string.Last<char>()] + 1));
if(code is byte[] array)
return array.Length == 0 ? 0 : (array.Length - 1) * power + (int)Math.Ceiling(Math.Log2(array.Last<byte>() + 1));
if(code is int integer)
return (int)Math.Ceiling(Math.Log2(integer + 1));
return 0;
}
public T bitwise<T>(T code, int bits){
if(code is string _string)
return (T)(object)to_string(bitwise<byte[]>(to_array(_string), bits));
if(code is byte[] array){
byte shift;
int mask;
List<byte> hexas;
if(bits < 0){
if(array.Length < (int)((bits *= -1) / power))
return (T)(object)new byte[]{0};
shift = (byte)(bits % power);
mask = _base - 1;
hexas = array.ToList<byte>();
hexas.RemoveRange(0, (int)(bits / power));
if(shift != 0 && hexas.Count != 0){
int l = hexas.Count - 1;
for(int i = 0; i < l; i ++)
hexas[i] = (byte)((hexas[i] >> shift) | ((hexas[i + 1] << (power - shift)) & mask));
hexas[hexas.Count - 1] >>= shift;
}
return (T)(object)hexas.ToArray<byte>();
};
if(bits > 0){
shift = (byte)(bits % power);
mask = _base - 1;
hexas = array.ToList<byte>();
if(shift != 0){
int last_hexa = hexas[hexas.Count - 1] << shift;
for(int i = hexas.Count - 1; i > 0; i --)
hexas[i] = (byte)((hexas[i] << shift) | ((hexas[i - 1] >> (power - shift)) & mask));
hexas[0] = (byte)((hexas[0] << shift) & mask);
if(last_hexa >= _base)
hexas.Add((byte)(last_hexa >> power));
}
for(int i = bits / power; i > 0; i --)
hexas.Insert(0, 0);
return (T)(object)hexas.ToArray<byte>();
}
return (T)(object)array;
}
if(code is int integer)
return (T)(object)(
bits > 0 ? integer << bits :
bits < 0 ? integer >> -bits :
integer);
return code;
}
public void get_from_bits(object code, ref int from, ref int bits){
if(from < 0){
from = get_bits(code) + from;
if(from < 0)
from = 0;
}
if(bits < 0){
from += bits;
bits *= -1;
if(from < 0){
bits += from;
from = 0;
}
}
}
public T reset<T>(T code, int from, int bits = 0, bool reversed = false){
if(bits == 0 || (from == 0 && bits < 0))
return code;
if(code is string _string)
return (T)(object)to_string(reset<byte[]>(to_array(_string), from, bits, reversed));
if(code is byte[] array){
List<byte> hexas = array.ToList<byte>();
int hexa_from;
int hexa_to;
int l;
byte from_mask;
byte to_mask;
get_from_bits(array, ref from, ref bits);
hexa_from = (int)(from / power);
hexa_to = (int)((from + bits) / power);
if(reversed){
l = from % power;
from_mask = (byte)(~-(1 << power - l) << l);
to_mask = (byte)~-(1 << (from + bits) % power);
for(int i = 0; i < hexas.Count; i ++)
if(i < hexa_from || i > hexa_to)
hexas[i] = 0;
if(hexa_from == hexa_to)
hexas[hexa_to] &= (byte)(from_mask & to_mask);
else{
hexas[hexa_from] &= from_mask;
if(hexa_to < hexas.Count)
hexas[hexa_to] &= to_mask;
}
}else{
l = (from + bits) % power;
from_mask = (byte)~-(1 << (from % power));
to_mask = (byte)(~-(1 << power - l) << l);
if(hexa_from == hexa_to){
hexas[hexa_to] &= (byte)(from_mask | to_mask);
}else{
hexas[hexa_from] &= from_mask;
for(int i = hexa_from + 1; i < hexa_to && i < hexas.Count; i ++)
hexas[i] = 0;
if(hexa_to < hexas.Count)
hexas[hexa_to] &= to_mask;
}
}
return (T)(object)hexas.ToArray<byte>();
}
if(code is int integer){
get_from_bits(integer, ref from, ref bits);
return (T)(object)(integer & (reversed ?
~-(1 << bits) << from :
(~-(1 << get_bits(integer)) << from + bits) | ~-(1 << from)));
}
return code;
}
public T get_range<T>(T code, int from, int length = 0){
if(code is string _string)
return to_string(get_range(to_array(_string), length));
if(code is byte[] array){
List<byte> hexas = new List<byte>();
if(from > 0){
byte shift = (byte)(from % power);
int mask = ~-_base;
hexas.AddRange(array.Take(from / power));
if(shift != 0){
for(int i = hexas.Count - 2; i >= 0; i --)
hexas[i] = (byte)((hexas[i] >> shift) | ((hexas[i + 1] << (power - shift)) & mask));
hexas[hexas.Count - 1] = (byte)(hexas.Last<byte>() >> shift);
}
}
if(length > 0){
byte shift = (byte)(length % power);
hexas.Take<byte>((int)Math.Ceiling(hexas.Count / (double)power));
if(shift != 0)
hexas[hexas.Count - 1] = (byte)(hexas.Last<byte>() & ~-(1 << shift));
}
return to_integer(array.Skip(from / power).Take((int)Math.Ceiling((length != 0 ? length : get_bits(array) - from) / (double)power)).ToArray<byte>());
}
if(code is int integer)
return (from > 0 ? integer >> from : integer) & (length > 0 ? ~(-1 << length) : integer);
return code;
}
public bool has(Error code, int? bits = null){
return code switch{
Error.String _string => _string.value.ToList<char>().Take<byte>(get_hexas_from_bits(bits)).Length * power > bits,
Error.Array array => array.value.ToList<byte>().Take<byte>(Math.Ceiling(Math.Log2(bits))).Where<byte>(hexa => hexa != 0).Count<byte>() != 0,
Error.Integer integer => (bits != null && bits != 0 ? ~-(1 << bits) & integer.value : integer.value) != 0,
_ => false
};
}
public static List<string> get_keys(object? items){
List<string> keys = new List<string>();
if(items is string item_string){
if(RE_KEY.IsMatch(item_string))
keys.Add(item_string);
}else if(items is IEnumerable<string> strings){
foreach(string item_i in strings)
if(!keys.Contains(item_i) && RE_KEY.IsMatch(item_i))
keys.Add(item_i);
}else if(items is IEnumerable<object?> list)
foreach(object? item in list){
if(item == null)
continue;
if(item is string string_item){
if(!keys.Contains(string_item) && RE_KEY.IsMatch(string_item))
keys.Add(string_item);
}else
foreach(string key in get_keys(item))
if(!keys.Contains(key) && RE_KEY.IsMatch(key))
keys.Add(key);
}
return keys;
}
public static List<Dictionary<string, object?>> get_dictionaries(object? items){
List<Dictionary<string, object?>> dictionaries = new List<Dictionary<string, object?>>();
if(items is Dictionary<string, object?> dictionary)
dictionaries.Add(dictionary);
else if(items is IEnumerable<object?> list)
foreach(object? item in list)
dictionaries.AddRange(get_dictionaries(item));
return dictionaries;
}
public static T? get<T>(object keys, object? dictionaries, T? _default = default(T?)){
List<string> keys_list = get_keys(keys);
if(keys_list.Count != 0)
foreach(Dictionary<string, object?> dictionary in get_dictionaries(dictionaries))
foreach(string key in keys_list)
if(dictionary.TryGetValue(key, out object? value) && value is T typed)
return typed;
return _default;
}
public static T[] unique<T>(IEnumerable<T> items){
return items.Distinct<T>().ToArray<T>();
}
public static bool is_string(object value){
return value is string;
}
public static bool is_array(object value){
return value is byte[];
}
public static bool is_integer(object value){
return value is int;
}
public static void for_each_enumerate<T>(IEnumerable<T> items, Action<T, int> action){
int i = 0;
foreach(T item in items)
action(item, i ++);
}
}
}