Skip to content
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

ToString() reimplementation #1843

Merged
merged 32 commits into from
Mar 2, 2021
Merged

Conversation

SandorDobos
Copy link
Contributor

@SandorDobos SandorDobos commented Feb 28, 2021

Numeric ToString() related managed code parts moved from lib-CoreLibrary to native code in nf-interpreter.

Description

Code changes impact in flash usage:
nanoCLR (MinSizeRel build): +1872 byte
mscorlib.pe (release build): -880 byte

Motivation and Context

How Has This Been Tested?

      I create an nf project in VS and added the following class to it:

      public static class ToStringAsserts
      {
          public static void Run()
          {
              //AssertToConsole("(123.456).ToString(\"C\"))","",(123.456).ToString("C"));
              //AssertToConsole("(-123.456).ToString(\"C\"))","",(-123.456).ToString("C"));
              //AssertToConsole("(123.456).ToString(\"C3\"))","",(123.456).ToString("C3"));
              //AssertToConsole("(-123.456).ToString(\"C3\"))","",(-123.456).ToString("C3"));
              AssertToConsole("(1).ToString(\"Da1x\")", "Da1x", (1).ToString("Da1x"));
              AssertToConsole("(1).ToString(\"D\")", "1", (1).ToString("D"));
              AssertToConsole("(-1).ToString(\"D\")", "-1", (-1).ToString("D"));
              AssertToConsole("(1234).ToString(\"D\")", "1234", (1234).ToString("D"));
              AssertToConsole("(-1234).ToString(\"D\")", "-1234", (-1234).ToString("D"));
              AssertToConsole("(1234).ToString(\"D6\")", "001234", (1234).ToString("D6"));
              AssertToConsole("(-1234).ToString(\"D6\")", "-001234", (-1234).ToString("D6"));
              AssertToConsole("(Int32.MaxValue).ToString(\"D\")", "2147483647", (Int32.MaxValue).ToString("D"));
              AssertToConsole("(Int32.MinValue).ToString(\"D\")", "-2147483648", (Int32.MinValue).ToString("D"));
              AssertToConsole("(Int32.MaxValue).ToString(\"D21\")", "000000000002147483647",
      (Int32.MaxValue).ToString("D21")); AssertToConsole("(Int32.MinValue).ToString(\"D21\")",
      "-000000000002147483648", (Int32.MinValue).ToString("D21"));
              AssertToConsole("(Int64.MaxValue).ToString(\"D\")", "9223372036854775807",
      (Int64.MaxValue).ToString("D")); AssertToConsole("(Int64.MinValue).ToString(\"D\")", "-9223372036854775808",
      (Int64.MinValue).ToString("D")); AssertToConsole("(Int64.MaxValue).ToString(\"D21\")",
      "009223372036854775807", (Int64.MaxValue).ToString("D21"));
              AssertToConsole("(Int64.MinValue).ToString(\"D21\")", "-009223372036854775808",
      (Int64.MinValue).ToString("D21")); AssertToConsole("(Int32.MaxValue+100).ToString(\"D\")", "2147483747",
      ((Int64)Int32.MaxValue + 100).ToString("D")); AssertToConsole("(Int32.MinValue-100).ToString(\"D\")",
      "-2147483748", ((Int64)Int32.MinValue - 100).ToString("D"));
              AssertToConsole("(Int32.MaxValue+100).ToString(\"D21\")", "000000000002147483747",
      ((Int64)Int32.MaxValue + 100).ToString("D21")); AssertToConsole("(Int32.MinValue-100).ToString(\"D21\")",
      "-000000000002147483748", ((Int64)Int32.MinValue - 100).ToString("D21"));
              //AssertToConsole("(1052.0329112756).ToString(\"E\"))","",(1052.0329112756).ToString("E"));
              //AssertToConsole("(-1052.0329112756).ToString(\"E\"))","",(-1052.0329112756).ToString("E"));
              //AssertToConsole("(1052.0329112756).ToString(\"E2\"))","",(1052.0329112756).ToString("E2"));
              //AssertToConsole("(-1052.0329112756).ToString(\"E2\"))","",(-1052.0329112756).ToString("E2"));
              //AssertToConsole("(1052.0329112756).ToString(\"e\"))","",(1052.0329112756).ToString("e"));
              //AssertToConsole("(-1052.0329112756).ToString(\"e\"))","",(-1052.0329112756).ToString("e"));
              //AssertToConsole("(1052.0329112756).ToString(\"e2\"))","",(1052.0329112756).ToString("e2"));
              //AssertToConsole("(-1052.0329112756).ToString(\"e2\"))","",(-1052.0329112756).ToString("e2"));
              AssertToConsole("(1234.567).ToString(\"F\"))", "1234.57", (1234.567).ToString("F"));
              AssertToConsole("(-1234.567).ToString(\"F\"))", "-1234.57", (-1234.567).ToString("F"));
              AssertToConsole("(1234.567).ToString(\"F0\"))", "1235", (1234.567).ToString("F0"));
              AssertToConsole("(-1234.567).ToString(\"F0\"))", "-1235", (-1234.567).ToString("F0"));
              AssertToConsole("(1234).ToString(\"F1\"))", "1234.0", (1234).ToString("F1"));
              AssertToConsole("(-1234).ToString(\"F1\"))", "-1234.0", (-1234).ToString("F1"));
              AssertToConsole("(1234.56).ToString(\"F4\"))", "1234.5600", (1234.56).ToString("F4"));
              AssertToConsole("(-1234.56).ToString(\"F4\"))", "-1234.5600", (-1234.56).ToString("F4"));
              AssertToConsole("(1234.56).ToString(\"F1\"))", "1234.6", (1234.56).ToString("F1"));
              AssertToConsole("(-1234.56).ToString(\"F1\"))", "-1234.6", (-1234.56).ToString("F1"));
              AssertToConsole("(1234.0056).ToString(\"F1\"))", "1234.0", (1234.0056).ToString("F1"));
              AssertToConsole("(-1234.0056).ToString(\"F1\"))", "-1234.0", (-1234.0056).ToString("F1"));
              AssertToConsole("(1).ToString()", "1", (1).ToString());
              AssertToConsole("(1).ToString(null)", "1", (1).ToString((string)null));
              AssertToConsole("(1).ToString(String.Empty)", "1", (1).ToString(String.Empty));
              AssertToConsole("(1234.567).ToString())", "1234.567", (1234.567).ToString());
              AssertToConsole("(123.456).ToString(\"G\"))", "123.456", (123.456).ToString("G"));
              AssertToConsole("(-123.456).ToString(\"G\"))", "-123.456", (-123.456).ToString("G"));
              AssertToConsole("(123.4546).ToString(\"G2\"))", "1.2E+02", (123.4546).ToString("G2"));
              AssertToConsole("(-123.4546).ToString(\"G2\"))", "-1.2E+02", (-123.4546).ToString("G2"));
              AssertToConsole("(123.4546).ToString(\"G4\"))", "123.5", (123.4546).ToString("G4"));
              AssertToConsole("(-123.4546).ToString(\"G4\"))", "-123.5", (-123.4546).ToString("G4"));
              AssertToConsole("(123.4546).ToString(\"G10\"))", "123.4546", (123.4546).ToString("G10"));
              AssertToConsole("(-123.4546).ToString(\"G10\"))", "-123.4546", (-123.4546).ToString("G10"));
              AssertToConsole("(99.9999).ToString(\"G4\"))", "100", (99.9999).ToString("G4"));
              AssertToConsole("(-99.9999).ToString(\"G4\"))", "-100", (-99.9999).ToString("G4"));
              AssertToConsole("(1234567890).ToString(\"G\"))", "1234567890", (1234567890).ToString("G"));
              AssertToConsole("(-1234567890).ToString(\"G\"))", "-1234567890", (-1234567890).ToString("G"));
              AssertToConsole("(1234567890).ToString(\"G4\"))", "1.235E+09", (1234567890).ToString("G4"));
              AssertToConsole("(-1234567890).ToString(\"G4\"))", "-1.235E+09", (-1234567890).ToString("G4"));
              AssertToConsole("(9876543210).ToString(\"G4\"))", "9.877E+09", (9876543210).ToString("G4"));
              AssertToConsole("(-9876543210).ToString(\"G4\"))", "-9.877E+09", (-9876543210).ToString("G4"));
              AssertToConsole("(1234567890).ToString(\"G15\"))", "1234567890", (1234567890).ToString("G15"));
              AssertToConsole("(-1234567890).ToString(\"G15\"))", "-1234567890", (-1234567890).ToString("G15"));
              AssertToConsole("(1234.567).ToString(\"N\"))", "1,234.57", (1234.567).ToString("N"));
              AssertToConsole("(-1234.567).ToString(\"N\"))", "-1,234.57", (-1234.567).ToString("N"));
              AssertToConsole("(0).ToString(\"N0\"))", "0", (0).ToString("N0"));
              AssertToConsole("(1234).ToString(\"N0\"))", "1,234", (1234).ToString("N0"));
              AssertToConsole("(-1234).ToString(\"N0\"))", "-1,234", (-1234).ToString("N0"));
              AssertToConsole("(12).ToString(\"N1\"))", "12.0", (12).ToString("N1"));
              AssertToConsole("(-12).ToString(\"N1\"))", "-12.0", (-12).ToString("N1"));
              AssertToConsole("(1234).ToString(\"N1\"))", "1,234.0", (1234).ToString("N1"));
              AssertToConsole("(-1234).ToString(\"N1\"))", "-1,234.0", (-1234).ToString("N1"));
              AssertToConsole("(1234.56).ToString(\"N3\"))", "1,234.560", (1234.56).ToString("N3"));
              AssertToConsole("(-1234.56).ToString(\"N3\"))", "-1,234.560", (-1234.56).ToString("N3"));
              AssertToConsole("(34561234.56).ToString(\"N3\"))", "34,561,234.560", (34561234.56).ToString("N3"));
              AssertToConsole("(-34561234.56).ToString(\"N3\"))", "-34,561,234.560", (-34561234.56).ToString("N3"));
              //AssertToConsole("(1).ToString(\"P\"))","",(1).ToString("P"));
              //AssertToConsole("(-0.39678).ToString(\"P\"))","",(-0.39678).ToString("P"));
              //AssertToConsole("(123456789.12345678).ToString(\"R\"))","",(123456789.12345678).ToString("R"));
              //AssertToConsole("(-123456789.12345678).ToString(\"R\"))","",(-123456789.12345678).ToString("R"));
              AssertToConsole("(255).ToString(\"X\"))", "FF", (255).ToString("X"));
              AssertToConsole("((Int32)1).ToString(\"X\"))", "1", ((Int32)1).ToString("X"));
              AssertToConsole("((Int32)(-1)).ToString(\"x\"))", "ffffffff", ((Int32)(-1)).ToString("x"));
              AssertToConsole("((byte)1).ToString(\"x\"))", "1", (unchecked((byte)1)).ToString("x"));
              AssertToConsole("((byte)(-1)).ToString(\"x\"))", "ff", (unchecked((byte)(-1))).ToString("x"));
              AssertToConsole("((short)1).ToString(\"x\"))", "1", ((short)1).ToString("x"));
              AssertToConsole("((short)1).ToString(\"x2\"))", "01", ((short)1).ToString("x2"));
              AssertToConsole("((short)(-1)).ToString(\"x\"))", "ffff", ((short)(-1)).ToString("x"));
              AssertToConsole("(255).ToString(\"x4\"))", "00ff", (255).ToString("x4"));
              AssertToConsole("((Int32)(-1)).ToString(\"X4\"))", "FFFFFFFF", ((Int32)(-1)).ToString("X4"));
              AssertToConsole("(Int64.MaxValue-10).ToString(\"x\"))", "7ffffffffffffff5", (Int64.MaxValue -
      10).ToString("x")); AssertToConsole("((Int64)10).ToString(\"x\"))", "a", ((Int64)10).ToString("x"));
              AssertToConsole("((Int64)10).ToString(\"x5\"))", "0000a", ((Int64)10).ToString("x5"));
          }

          private static void AssertToConsole(string lbl, string expected, string str)
          {
              if (str != expected)
              {
                  Debug.WriteLine($"BAD: {lbl} expected: {expected} found: {str}");
              }
              else
              {
                  Debug.WriteLine($" OK: {lbl} expected: {expected}");
              }
          }
      }

      All expectations in assert lines above was captured during execution of the above under official .net runtime, see below.

      From the Main() call this class:
        ToStringAsserts.Run();

      I added a second old-school (running on "official" .net environment, like a Windows Console app) project to the
      solution. Added ToStringAsserts.cs as existing item via link to it. 
      Call from it's main() the test class as above. Execute this second project. You will see how the
      official implementation formats the various things. Adjust the "expected" strings to reflect the received
      output. E.g. if you want to check how we format (255).ToString("X") then add the following line:

        AssertToConsole("(255).ToString(\"X\"))", "dunnoyet", (255).ToString("X"));

      Execute the old-school project and you will see this line:
        BAD: (255).ToString("X")) expected: dunnoyet found: FF

      Now replace the "dunnoyet" with "FF" and the test case ready.
      Now execute the nf project and check what nanoCLR formats for you.
      Implement, fix, etc.
      But always check your test project results in OK on all lines!

Screenshots

Types of changes

  • Improvement (non-breaking change that improves a feature, code or algorithm)
  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to change)
  • Config and build (change in the configuration and build system, has no impact on code or features)
  • Dependencies (update dependencies and changes associated, has no impact on code or features)

Checklist:

  • My code follows the code style of this project.
  • My change requires a change to the documentation.
  • I have updated the documentation accordingly.
  • I have read the CONTRIBUTING document.
  • I have added tests to cover my changes.
  • All new and existing tests passed.

SandorDobos and others added 25 commits February 23, 2021 15:16
sprintf isn't supported by nanoprintf, using snprintf instead everywhere.
Automated fixes for code style.
Automated fixes for code style.
…8b6-d532-48ba-a4cb-e3c8449108e2

Code style fixes for nanoframework/nf-interpreter PR#1841
…614-b9c3-4de5-a376-4f3f25cf0cd9

Code style fixes for nanoframework/nf-interpreter PR#1841
precision value -1 means nothing set.
common funcs extracted.
Automated fixes for code style.
@nfbot
Copy link
Member

nfbot commented Feb 28, 2021

@SandorDobos there are issues with the code style on the source files.
A PR was submitted with the code style fixes. Please review and merge the changes. See SandorDobos#3.

Make sure you are using the project code style. Check the details here.

…fe9-518b-4334-b98b-f07ab8c8a0c8

Code style fixes for nanoframework/nf-interpreter PR#1843
Copy link
Member

@josesimoes josesimoes left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great work on this!! Congrats and thankyou. 👍🏻 💯

@josesimoes
Copy link
Member

@SandorDobos if you could squash all the commits into a single one, that would be great.

@SandorDobos SandorDobos requested a review from josesimoes March 1, 2021 22:11
@josesimoes josesimoes merged commit d5f01e7 into nanoframework:develop Mar 2, 2021
@josesimoes josesimoes added the Area: Common libs Everything related with common libraries label Mar 2, 2021
josesimoes added a commit that referenced this pull request Mar 16, 2021
josesimoes added a commit that referenced this pull request Mar 16, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Area: Common libs Everything related with common libraries Type: bug Type: enhancement
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Bug in formatting numbers into a string with D5 format
3 participants