-
Notifications
You must be signed in to change notification settings - Fork 387
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
BaseUnit generation for the prefixed units #1485
Merged
Merged
Changes from all commits
Commits
Show all changes
6 commits
Select commit
Hold shift + click to select a range
4b6572c
BaseUnit generation for the prefixed units
lipchev b4dd739
- added a DebugDisplay for the Unit (JsonTypes)
lipchev 99b378f
Add record, renames, add TODO for documentation
angularsen b7b7568
Add ToString/DebuggDisplay for Quantity, BaseUnits
angularsen a0a201a
refactor the prefix-building part of the CodeGen, introducing a pre-p…
lipchev 3280fdb
- included the examples in the xml-docs for the UnitPrefixBuilder
lipchev File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
// Licensed under MIT No Attribution, see LICENSE file at the root. | ||
// Copyright 2013 Andreas Gullberg Larsen ([email protected]). Maintained at https://github.com/angularsen/UnitsNet. | ||
|
||
using CodeGen.JsonTypes; | ||
|
||
namespace CodeGen.Helpers.PrefixBuilder; | ||
|
||
/// <summary> | ||
/// Represents a unique key that combines a base unit and a prefix. | ||
/// </summary> | ||
/// <param name="BaseUnit"> | ||
/// The base unit associated with the prefix. For example, "Gram". | ||
/// </param> | ||
/// <param name="Prefix"> | ||
/// The prefix applied to the base unit. For example, <see cref="JsonTypes.Prefix.Kilo" />. | ||
/// </param> | ||
internal readonly record struct BaseUnitPrefix(string BaseUnit, Prefix Prefix); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,165 @@ | ||
// Licensed under MIT No Attribution, see LICENSE file at the root. | ||
// Copyright 2013 Andreas Gullberg Larsen ([email protected]). Maintained at https://github.com/angularsen/UnitsNet. | ||
|
||
using System.Collections.Generic; | ||
using System.Diagnostics.CodeAnalysis; | ||
using System.Linq; | ||
using CodeGen.JsonTypes; | ||
|
||
namespace CodeGen.Helpers.PrefixBuilder; | ||
|
||
/// <summary> | ||
/// Represents a collection of base unit prefixes and their associated mappings. | ||
/// </summary> | ||
/// <remarks> | ||
/// This class provides functionality to manage and retrieve mappings between base units and their prefixed | ||
/// counterparts, | ||
/// including scale factors and prefixed unit names. It supports operations such as creating mappings from a collection | ||
/// of base units and finding matching prefixes for specific units. | ||
/// </remarks> | ||
internal class BaseUnitPrefixes | ||
{ | ||
/// <summary> | ||
/// A dictionary that maps metric prefixes to their corresponding exponent values. | ||
/// </summary> | ||
/// <remarks> | ||
/// This dictionary excludes binary prefixes such as Kibi, Mebi, Gibi, Tebi, Pebi, and Exbi. | ||
/// </remarks> | ||
private static readonly Dictionary<Prefix, int> MetricPrefixFactors = PrefixInfo.Entries.Where(x => x.Key.IsMetricPrefix()) | ||
.ToDictionary(pair => pair.Key, pair => pair.Value.GetDecimalExponent()); | ||
|
||
/// <summary> | ||
/// A dictionary that maps the exponent values to their corresponding <see cref="Prefix" />. | ||
/// This is used to find the appropriate prefix for a given factor. | ||
/// </summary> | ||
private static readonly Dictionary<int, Prefix> PrefixFactorsByValue = MetricPrefixFactors.ToDictionary(pair => pair.Value, pair => pair.Key); | ||
|
||
/// <summary> | ||
/// Lookup of prefixed unit name from base unit + prefix pairs, such as ("Gram", Prefix.Kilo) => "Kilogram". | ||
/// </summary> | ||
private readonly Dictionary<BaseUnitPrefix, string> _baseUnitPrefixConversions; | ||
|
||
/// <summary> | ||
/// A dictionary that maps prefixed unit strings to their corresponding base unit and fractional factor. | ||
/// </summary> | ||
/// <remarks> | ||
/// This dictionary is used to handle units with SI prefixes, allowing for the conversion of prefixed units | ||
/// to their base units and the associated fractional factors. The keys are the prefixed unit strings, and the values | ||
/// are tuples containing the base unit string and the fractional factor. | ||
/// </remarks> | ||
private readonly Dictionary<string, PrefixScaleFactor> _prefixedStringFactors; | ||
|
||
private BaseUnitPrefixes(Dictionary<string, PrefixScaleFactor> prefixedStringFactors, Dictionary<BaseUnitPrefix, string> baseUnitPrefixConversions) | ||
{ | ||
_prefixedStringFactors = prefixedStringFactors; | ||
_baseUnitPrefixConversions = baseUnitPrefixConversions; | ||
} | ||
|
||
/// <summary> | ||
/// Creates an instance of <see cref="BaseUnitPrefixes" /> from a collection of base units. | ||
/// </summary> | ||
/// <param name="baseUnits"> | ||
/// A collection of base units, each containing a singular name and associated prefixes. | ||
/// </param> | ||
/// <returns> | ||
/// A new instance of <see cref="BaseUnitPrefixes" /> containing mappings of base units | ||
/// and their prefixed counterparts. | ||
/// </returns> | ||
/// <remarks> | ||
/// This method processes the provided base units to generate mappings between base unit prefixes | ||
/// and their corresponding prefixed unit names, as well as scale factors for each prefixed unit. | ||
/// </remarks> | ||
public static BaseUnitPrefixes FromBaseUnits(IEnumerable<Unit> baseUnits) | ||
{ | ||
var baseUnitPrefixConversions = new Dictionary<BaseUnitPrefix, string>(); | ||
var prefixedStringFactors = new Dictionary<string, PrefixScaleFactor>(); | ||
foreach (Unit baseUnit in baseUnits) | ||
{ | ||
var unitName = baseUnit.SingularName; | ||
prefixedStringFactors[unitName] = new PrefixScaleFactor(unitName, 0); | ||
foreach (Prefix prefix in baseUnit.Prefixes) | ||
{ | ||
var prefixedUnitName = prefix + unitName.ToCamelCase(); | ||
baseUnitPrefixConversions[new BaseUnitPrefix(unitName, prefix)] = prefixedUnitName; | ||
prefixedStringFactors[prefixedUnitName] = new PrefixScaleFactor(unitName, MetricPrefixFactors[prefix]); | ||
} | ||
} | ||
|
||
return new BaseUnitPrefixes(prefixedStringFactors, baseUnitPrefixConversions); | ||
} | ||
|
||
/// <summary> | ||
/// Attempts to find a matching prefix for a given unit name, exponent, and prefix. | ||
/// </summary> | ||
/// <param name="unitName"> | ||
/// The name of the unit to match. For example, "Meter". | ||
/// </param> | ||
/// <param name="exponent"> | ||
/// The exponent associated with the unit. For example, 3 for cubic meters. | ||
/// </param> | ||
/// <param name="prefix"> | ||
/// The prefix to match. For example, <see cref="Prefix.Kilo" />. | ||
/// </param> | ||
/// <param name="matchingPrefix"> | ||
/// When this method returns, contains the matching <see cref="BaseUnitPrefix" /> if a match is found; | ||
/// otherwise, the default value of <see cref="BaseUnitPrefix" />. | ||
/// </param> | ||
/// <returns> | ||
/// <see langword="true" /> if a matching prefix is found; otherwise, <see langword="false" />. | ||
/// </returns> | ||
/// <remarks> | ||
/// This method determines if a given unit can be associated with a specific prefix, given the exponent of the | ||
/// associated dimension. | ||
/// </remarks> | ||
internal bool TryGetMatchingPrefix(string unitName, int exponent, Prefix prefix, out BaseUnitPrefix matchingPrefix) | ||
{ | ||
if (exponent == 0 || !_prefixedStringFactors.TryGetValue(unitName, out PrefixScaleFactor? targetPrefixFactor)) | ||
{ | ||
matchingPrefix = default; | ||
return false; | ||
} | ||
|
||
if (MetricPrefixFactors.TryGetValue(prefix, out var prefixFactor)) | ||
{ | ||
var (quotient, remainder) = int.DivRem(prefixFactor, exponent); | ||
// Ensure the prefix factor is divisible by the exponent without a remainder and that there is a valid prefix matching the target scale | ||
if (remainder == 0 && TryGetPrefixWithScale(targetPrefixFactor.ScaleFactor + quotient, out Prefix calculatedPrefix)) | ||
{ | ||
matchingPrefix = new BaseUnitPrefix(targetPrefixFactor.BaseUnit, calculatedPrefix); | ||
return true; | ||
} | ||
} | ||
|
||
matchingPrefix = default; | ||
return false; | ||
} | ||
|
||
private static bool TryGetPrefixWithScale(int logScale, out Prefix calculatedPrefix) | ||
{ | ||
return PrefixFactorsByValue.TryGetValue(logScale, out calculatedPrefix); | ||
} | ||
|
||
/// <summary> | ||
/// Attempts to retrieve the prefixed unit name for a given base unit and prefix combination. | ||
/// </summary> | ||
/// <param name="prefix"> | ||
/// A <see cref="BaseUnitPrefix" /> representing the combination of a base unit and a prefix. | ||
/// </param> | ||
/// <param name="prefixedUnitName"> | ||
/// When this method returns, contains the prefixed unit name if the lookup was successful; otherwise, <c>null</c>. | ||
/// </param> | ||
/// <returns> | ||
/// <c>true</c> if the prefixed unit name was successfully retrieved; otherwise, <c>false</c>. | ||
/// </returns> | ||
internal bool TryGetPrefixForUnit(BaseUnitPrefix prefix, [NotNullWhen(true)] out string? prefixedUnitName) | ||
{ | ||
return _baseUnitPrefixConversions.TryGetValue(prefix, out prefixedUnitName); | ||
} | ||
|
||
/// <summary> | ||
/// Represents the scaling factor that is required for converting from the <see cref="BaseUnit" />. | ||
/// </summary> | ||
/// <param name="BaseUnit">Name of base unit, e.g. "Meter".</param> | ||
/// <param name="ScaleFactor">The log-scale factor, e.g. 3 for kilometer.</param> | ||
private record PrefixScaleFactor(string BaseUnit, int ScaleFactor); | ||
} |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good refactoring and docs 👍 I like concrete examples like this.