birschick-bq commented on code in PR #2152:
URL: https://github.com/apache/arrow-adbc/pull/2152#discussion_r1775625822


##########
csharp/src/Drivers/Apache/Hive2/DecimalUtility.cs:
##########
@@ -0,0 +1,452 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one or more
+* contributor license agreements.  See the NOTICE file distributed with
+* this work for additional information regarding copyright ownership.
+* The ASF licenses this file to You under the Apache License, Version 2.0
+* (the "License"); you may not use this file except in compliance with
+* the License.  You may obtain a copy of the License at
+*
+*    http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+
+using System;
+using System.Numerics;
+
+namespace Apache.Arrow.Adbc.Drivers.Apache.Hive2
+{
+    internal static class DecimalUtility
+    {
+        private const char AsciiZero = '0';
+        private const int AsciiDigitMaxIndex = '9' - AsciiZero;
+        private const char AsciiMinus = '-';
+        private const char AsciiPlus = '+';
+        private const char AsciiUpperE = 'E';
+        private const char AsciiLowerE = 'e';
+        private const char AsciiPeriod = '.';
+
+        /// <summary>
+        /// Gets the BigInteger bytes for the given string value.
+        /// </summary>
+        /// <param name="value">The numeric string value to get bytes 
for.</param>
+        /// <param name="precision">The decimal precision for the target 
Decimal[128|256]</param>
+        /// <param name="scale">The decimal scale for the target 
Decimal[128|256]</param>
+        /// <param name="byteWidth">The width in bytes for the target buffer. 
Should match the length of the bytes parameter.</param>
+        /// <param name="bytes">The buffer to place the BigInteger bytes 
into.</param>
+        /// <exception cref="ArgumentOutOfRangeException"></exception>
+        internal static void GetBytes(string value, int precision, int scale, 
int byteWidth, Span<byte> bytes)
+        {
+            if (precision < 1)
+            {
+                throw new ArgumentOutOfRangeException(nameof(precision), 
precision, "precision value must be greater than zero.");
+            }
+            if (scale < 0 || scale >= precision)
+            {
+                throw new ArgumentOutOfRangeException(nameof(scale), scale, 
"scale value must be in the range 0 .. precision.");
+            }
+            if (byteWidth > bytes.Length)
+            {
+                throw new ArgumentOutOfRangeException(nameof(byteWidth), 
byteWidth, $"value for byteWidth {byteWidth} exceeds the the size of bytes.");
+            }
+
+            BigInteger intergerValue = ToBigInteger(value, precision, scale);
+
+            FillBytes(bytes, intergerValue, byteWidth);
+        }
+
+        private static void FillBytes(Span<byte> bytes, BigInteger 
integerValue, int byteWidth)
+        {
+            int bytesWritten = 0;
+#if NETCOREAPP
+            if (!integerValue.TryWriteBytes(bytes, out bytesWritten, false, 
!BitConverter.IsLittleEndian))
+            {
+                throw new OverflowException("Could not extract bytes from 
integer value " + integerValue);
+            }
+#else
+            byte[] tempBytes = integerValue.ToByteArray();
+            bytesWritten = tempBytes.Length;
+            if (bytesWritten > bytes.Length)
+            {
+                throw new OverflowException($"Decimal size greater than 
{byteWidth} bytes: {bytesWritten}");
+            }
+            tempBytes.CopyTo(bytes);
+#endif
+            byte fillByte = (byte)(integerValue < 0 ? 255 : 0);
+            for (int i = bytesWritten; i < byteWidth; i++)
+            {
+                bytes[i] = fillByte;
+            }
+        }
+
+        private static BigInteger ToBigInteger(string value, int precision, 
int scale)
+        {
+            BigInteger intergerValue;
+#if NETCOREAPP
+            ReadOnlySpan<char> significantValue = GetSignificantValue(value, 
precision, scale);
+            intergerValue = BigInteger.Parse(significantValue);
+#else
+            ReadOnlySpan<char> significantValue = 
GetSignificantValue(value.AsSpan(), precision, scale);
+            intergerValue = BigInteger.Parse(significantValue.ToString());
+#endif
+            return intergerValue;
+        }
+
+        private static ReadOnlySpan<char> 
GetSignificantValue(ReadOnlySpan<char> value, int precision, int scale)
+        {
+            ParseDecimal(value, out ParserState state);
+
+            ProcessDecimal(value,
+                precision,
+                scale,
+                state,
+                out char sign,
+                out ReadOnlySpan<char> integerSpan,
+                out ReadOnlySpan<char> fractionalSpan,
+                out int neededScale);
+
+            Span<char> significant = new char[precision + 1];
+            BuildSignificantValue(
+                sign,
+                scale,
+                integerSpan,
+                fractionalSpan,
+                neededScale,
+                significant);
+
+            return significant;
+        }
+
+        private static void ProcessDecimal(ReadOnlySpan<char> value, int 
precision, int scale, ParserState state, out char sign, out ReadOnlySpan<char> 
integerSpan, out ReadOnlySpan<char> fractionalSpan, out int neededScale)
+        {
+            int int_length = 0;
+            int frac_length = 0;
+            int exponent = 0;
+
+            if (state.IntegerStart != -1 && state.IntegerEnd != -1) int_length 
= state.IntegerEnd - state.IntegerStart + 1;
+            if (state.FractionalStart != -1 && state.FractionalEnd != -1) 
frac_length = state.FractionalEnd - state.FractionalStart + 1;
+            if (state.ExponentIndex != -1 && state.ExponentStart != -1 && 
state.ExponentEnd != -1 && state.ExponentEnd >= state.ExponentStart)
+            {
+                int expStart = state.ExpSignIndex != -1 ? state.ExpSignIndex : 
state.ExponentStart;
+                int expLength = state.ExponentEnd - expStart + 1;
+                ReadOnlySpan<char> exponentSpan = value.Slice(expStart, 
expLength);
+#if NETCOREAPP
+                exponent = int.Parse(exponentSpan);
+#else
+                exponent = int.Parse(exponentSpan.ToString());

Review Comment:
   @CurtHagenlocher - Sounds like a good plan. There is also parsing for 
`DateTime` and `DateTimeOffset`. 
   
   In general, because all these conversions are expected to have only ASCII 
characters, we may not even need to convert to string in most cases 
(`BigInteger.Parse` being the exception).
   
   I'll create a follow-up task.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: github-unsubscr...@arrow.apache.org

For queries about this service, please contact Infrastructure at:
us...@infra.apache.org

Reply via email to