ero
ero
CC#
Created by ero on 7/26/2023 in #help
❔ Lazily evaluating Dictionary in update loop with good performance
Situation I have an update loop which receives some data which is Dictionary-like. Due to a version difference, I receive two types of data. The receiving of this data is not a concern and is relatively cheap. The two types of data I receive are as follows: - an array of type (TKey, TValue)[], - two arrays of types TKey[] and TValue[]. I cannot change these input types (no, I cannot change the array of tuples to an array of KeyValuePair<TKey, TValue>s). I know with certainty that the keys are unique, and I know with certainty that they map to exactly one value. Goal I want to use this received data just like a Dictionary (an IReadOnlyDictionary<TKey, TValue> to be precise) without actually building the Dictionary the moment I receive it. By this I mean, I do not want to populate a Dictionary<TKey, TValue> with the data, which may be quite large. Doing this would potentially delay the update loop unnecessarily (not actually needing all the data, since only a selection of it will be accessed). Problem I can safely have two types of implementations for the two different types of data received. The issue now is making accesses performant (like the hashing in Dictionaries usually is). My current idea is the naïve way of making the evaluation linear and caching anything we've already seen. For the ContainsKey implementation, it may be possible to implement a HashSet<TKey>. This, however, would add an extra allocation, would need to do potentially unnecessary computation, and would require some pretty bad logic for the tuple array data. I'm simply not sure how to implement this very well such that the lazy evaluation is not simply linear with a cache. Any ideas?
102 replies
CC#
Created by ero on 3/23/2023 in #help
❔ Creating a "Lazy" Factory with a Fluent API
I'm looking to create a kind of factory, which creates commands instead of the actual results. The results are then conditionally returned upon a call to the factory's Run() or Execute() method. The reason for the "laziness" of the factory is that executing one of these commands may fail (TryExecute()). This command is then skipped (the failure may be logged) and tried again later, at which point it may no longer fail. Assume these result objects;
interface IFoo { }
abstract class FooBase : IFoo { }

class Foo<T> : FooBase { }
class Bar<T> : FooBase { }
class Qux : FooBase { }
interface IFoo { }
abstract class FooBase : IFoo { }

class Foo<T> : FooBase { }
class Bar<T> : FooBase { }
class Qux : FooBase { }
These objects are all "created" differently (as in, they have different constructor parameters), meaning the factory must also have MakeFoo<T>, MakeBar<T>, and MakeQux. But unfortunately, that's not it. All implementations of FooBase take an instance of IFoo as a sort-of parent. This can be nested infinitely. Let's assume something like this;
Foo<int> foo1 = new(/* */);
Foo<long> foo2 = new(foo1, /* */);
Foo<byte> foo3 = new(foo2, /* */);
Foo<int> foo1 = new(/* */);
Foo<long> foo2 = new(foo1, /* */);
Foo<byte> foo3 = new(foo2, /* */);
This means that the factory needs some way to create a parent which then has at least 1 or more children. I also want to modify some of the objects' properties fluently;
factory.MakeFoo<T>(/* */).Prop1(/* */).Prop2(/* */);
factory.MakeFoo<T>(/* */).Prop1(/* */).Prop2(/* */);
Potential implementations I've considered use a setup such as this;
interface IMakeFooCommand { }
abstract class MakeFooCommandBase : IMakeFooCommand { }

class MakeFooCommand<T> : MakeFooCommandBase { }
class MakeBarCommand<T> : MakeFooCommandBase { }
class MakeQuxCommand : MakeFooCommandBase { }
interface IMakeFooCommand { }
abstract class MakeFooCommandBase : IMakeFooCommand { }

class MakeFooCommand<T> : MakeFooCommandBase { }
class MakeBarCommand<T> : MakeFooCommandBase { }
class MakeQuxCommand : MakeFooCommandBase { }
interface ILazyFactory { }
class LazyFactory : ILazyFactory { }
interface ILazyFactory { }
class LazyFactory : ILazyFactory { }
79 replies
CC#
Created by ero on 11/27/2022 in #help
Creating and using an incremental source generator
I wanna create an incremental source generator for my web API project, but I cannot for the life of me understand how to create a source generator at all. I'm even having a hard time understanding the documentation that does exist. Is there anyone that's able to help? I have a pretty clear idea of what I wanna do: I have a collection of HTTP endpoints in one class, which get turned into controllers, commands, and DTOs.
namespace Endpoints;

[GenerateHttpEndpoints] // better name ideas?
public partial class User
{
[HttpPost("/api/users")]
public async Task<ActionResult<Entities.User>> Create(
string name,
string email,
string password)
{
// ...

return Ok(createdUser);
}
}
namespace Endpoints;

[GenerateHttpEndpoints] // better name ideas?
public partial class User
{
[HttpPost("/api/users")]
public async Task<ActionResult<Entities.User>> Create(
string name,
string email,
string password)
{
// ...

return Ok(createdUser);
}
}
UserEndpoints.g.cs
file record CreateUserDto(
string Name,
string Email,
string Password);

// other things related to handling the command
file record CreateUserDto(
string Name,
string Email,
string Password);

// other things related to handling the command
47 replies
CC#
Created by ero on 11/23/2022 in #help
❔ Creating a backend in .NET
Hi! I have absolutely zero knowledge about web development, databases, or making any kinds of web requests. Basically, I'm a complete noob when it comes to literally anything web-related (and I know databases aren't necessarily web, but you get the idea). I would like to build a backend for a website idea that's already pretty big on paper. I have a lot of ideas, have a lot of thoughts about how things should work, I just can't create it. I was wondering if there are any very beginner friendly, modern tutorials on this stuff? Preferrably videos, as I have a hard time focussing on reading a lot. If I should go into any more detail, let me know.
1423 replies
CC#
Created by ero on 10/30/2022 in #help
How to handle depending on a library which is not available as a NuGet?
I would like to use a library which is open source on GitHub on my own repo. My problem is in handling how to supply that library to people who clone my repo to contribute. How do I do this?
3 replies
CC#
Created by ero on 10/5/2022 in #help
Need help creating a small installer
Using Spectre.Console, I wanna create a really small console app which simply downloads Trace Spy (https://github.com/smourier/TraceSpy), a custom config for it, and a font to go with it (Cascadia Code). I just need some guidance on how to use Spectre, and some insights into best practices and the like. I'll also need a lot of help getting progress bars to work, as well as unzipping and installing the font for the user.
124 replies
CC#
Created by ero on 10/4/2022 in #help
Progress bar in console app to show download progress
Wanting to create a very simple console application (.NET 7) which downloads a few files and installs them on the user's machine (less "install" and moreso "place a self-contained executable in a directory they choose"). What're my options to create a progress bar for the download process?
15 replies
CC#
Created by ero on 9/17/2022 in #help
Optimizing some string manipulation
I want to both substring an input string at the last occurrence of '/' and normalize it into only alphanumeric (a-z, A-Z, 0-9) characters, turning any characters unable to be normalized (meaning characters with diacritics turning into their non-diacritic versions (ä -> a)) into _. Here's what I've got so far;
if (input.Length == 0)
{
return "";
}

Span<char> outBuf = stackalloc char[128];
char* pNorm = stackalloc char[128];

fixed (char* pIn = input, pOut = outBuf)
{
int dLength = NormalizeString(2, (ushort*)pIn, input.Length, (ushort*)pNorm, 128);

int start = 127, length = 0;
char first = default;

for (int i = dLength - 1; i >= 0; i--)
{
char c = pNorm[i];

if (CharUnicodeInfo.GetUnicodeCategory(c) == UnicodeCategory.NonSpacingMark)
{
continue;
}

if (c is '/')
{
break;
}

pOut[start] = first = c switch
{
(>= '0' and <= '9') or (>= 'A' and <= 'Z') or (>= 'a' and <= 'z') => c,
_ => '_'
};

start--;
length++;
}

if (first is >= '0' and <= '9')
{
pOut[start] = '_';
length++;
}

return outBuf.Slice(start, length).ToString();
}

[DllImport("normaliz")]
static extern int NormalizeString(
int normForm,
ushort* source,
int sourceLength,
ushort* destination,
int destinationLength);
if (input.Length == 0)
{
return "";
}

Span<char> outBuf = stackalloc char[128];
char* pNorm = stackalloc char[128];

fixed (char* pIn = input, pOut = outBuf)
{
int dLength = NormalizeString(2, (ushort*)pIn, input.Length, (ushort*)pNorm, 128);

int start = 127, length = 0;
char first = default;

for (int i = dLength - 1; i >= 0; i--)
{
char c = pNorm[i];

if (CharUnicodeInfo.GetUnicodeCategory(c) == UnicodeCategory.NonSpacingMark)
{
continue;
}

if (c is '/')
{
break;
}

pOut[start] = first = c switch
{
(>= '0' and <= '9') or (>= 'A' and <= 'Z') or (>= 'a' and <= 'z') => c,
_ => '_'
};

start--;
length++;
}

if (first is >= '0' and <= '9')
{
pOut[start] = '_';
length++;
}

return outBuf.Slice(start, length).ToString();
}

[DllImport("normaliz")]
static extern int NormalizeString(
int normForm,
ushort* source,
int sourceLength,
ushort* destination,
int destinationLength);
However, this is hardly faster than using Substring and Normalize (with some custom code involving CharUnicodeInfo.GetUnicodeCategory). Any ideas?
18 replies
CC#
Created by ero on 9/5/2022 in #help
Fast look-up algorithms
I'm looking to use a sort of cache of objects which are stored each with a unique key. Currently, I do this simply using a Dictionary<TKey, TValue>. This is to prevent having to fetch the items anew, when I can simply get them from that cache. My question is, what are some quicker and more efficient collections or algorithms to use for storing pairs of keys and values and fetching them when needed? (Obviously the logic to "refresh" the cache will run when an item cannot be found.)
22 replies
CC#
Created by ero on 9/2/2022 in #help
Parsing a string into a Vector of bytes most efficiently
Given a string with an even amount of characters, what's the most efficient way to parse that into a Vector<byte> along with another Vector<byte> of bit masks? A sample input is 12 34 ?? 78 87 ?5 ?3 21 -- these are meant to be hex bytes -- which would get turned into < 0x12 0x34 0x00 0x78 0x87 0x05 0x03 0x21 > for the values, and < 0xFF 0xFF 0x00 0xFF 0xFF 0x0F 0x0F 0xFF > for the masks. Currently I'm doing the input.Length % 2 != 0 check first, of course, followed by Regex.Matches(input, @"..").Select(match => match.Value).ToList();. From here I do this to parse all of the bytes;
int length = bytes.Length;
if (length < Vector<byte>.Count)
length = Vector<byte>.Count;

byte[] values = new byte[length], masks = new byte[length];

for (int i = 0; i < bytes.Length; i++)
{
var currByte = bytes[i];

var hasUpper = byte.TryParse(currByte[0].ToString(), NumberStyles.HexNumber, null, out byte upper);
var hasLower = byte.TryParse(currByte[1].ToString(), NumberStyles.HexNumber, null, out byte lower);

switch ((hasUpper, hasLower))
{
case (true, true):
{
values[i] = (byte)((upper << 4) + lower);
masks[i] = 0xFF;
break;
}

case (true, false):
{
values[i] = (byte)(upper << 4);
masks[i] = 0xF0;
break;
}

case (false, true):
{
values[i] = lower;
masks[i] = 0x0F;
break;
}

case (false, false):
{
values[i] = 0x00;
masks[i] = 0x00;
break;
}
}
}

return (length, new(values), new(masks));
int length = bytes.Length;
if (length < Vector<byte>.Count)
length = Vector<byte>.Count;

byte[] values = new byte[length], masks = new byte[length];

for (int i = 0; i < bytes.Length; i++)
{
var currByte = bytes[i];

var hasUpper = byte.TryParse(currByte[0].ToString(), NumberStyles.HexNumber, null, out byte upper);
var hasLower = byte.TryParse(currByte[1].ToString(), NumberStyles.HexNumber, null, out byte lower);

switch ((hasUpper, hasLower))
{
case (true, true):
{
values[i] = (byte)((upper << 4) + lower);
masks[i] = 0xFF;
break;
}

case (true, false):
{
values[i] = (byte)(upper << 4);
masks[i] = 0xF0;
break;
}

case (false, true):
{
values[i] = lower;
masks[i] = 0x0F;
break;
}

case (false, false):
{
values[i] = 0x00;
masks[i] = 0x00;
break;
}
}
}

return (length, new(values), new(masks));
Obviously the big one is using Regex. Any ideas?
11 replies
CC#
Created by ero on 8/19/2022 in #help
Compile .NET Framework class library with NuGets to single DLL [Answered]
I have a .NET Framework 4.8.1 (unable to upgrade) class library which references a number of NuGet packages. I would like to compile this library to a single, self-contained DLL file. Is this possible? How?
18 replies
CC#
Created by ero on 8/15/2022 in #help
❔ Any known .NET 7 implementations of an Int24?
Just wondering if there's an implementation of an Int24 type using the new signatures for the numeric types. Something akin to this;
readonly struct Int24
: IBinaryInteger<Int24>,
IComparable,
IComparable<Int24>,
IConvertible,
IEquatable<Int24>,
IMinMaxValue<Int24>,
ISignedNumber<Int24>,
ISpanFormattable
{

}
readonly struct Int24
: IBinaryInteger<Int24>,
IComparable,
IComparable<Int24>,
IConvertible,
IEquatable<Int24>,
IMinMaxValue<Int24>,
ISignedNumber<Int24>,
ISpanFormattable
{

}
9 replies