// 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.

#include "arrow/util/basic_decimal.h"

#include <algorithm>
#include <array>
#include <climits>
#include <cstdint>
#include <cstdlib>
#include <cstring>
#include <iomanip>
#include <limits>
#include <string>

#include "arrow/util/bit_util.h"
#include "arrow/util/config.h"  // for ARROW_USE_NATIVE_INT128
#include "arrow/util/endian.h"
#include "arrow/util/int128_internal.h"
#include "arrow/util/int_util_overflow.h"
#include "arrow/util/logging.h"
#include "arrow/util/macros.h"

namespace arrow {

using internal::AddWithOverflow;
using internal::SafeLeftShift;
using internal::SafeSignedAdd;
using internal::SafeSignedSubtract;
using internal::SubtractWithOverflow;

static const BasicDecimal128 ScaleMultipliers[] = {
    BasicDecimal128(1LL),
    BasicDecimal128(10LL),
    BasicDecimal128(100LL),
    BasicDecimal128(1000LL),
    BasicDecimal128(10000LL),
    BasicDecimal128(100000LL),
    BasicDecimal128(1000000LL),
    BasicDecimal128(10000000LL),
    BasicDecimal128(100000000LL),
    BasicDecimal128(1000000000LL),
    BasicDecimal128(10000000000LL),
    BasicDecimal128(100000000000LL),
    BasicDecimal128(1000000000000LL),
    BasicDecimal128(10000000000000LL),
    BasicDecimal128(100000000000000LL),
    BasicDecimal128(1000000000000000LL),
    BasicDecimal128(10000000000000000LL),
    BasicDecimal128(100000000000000000LL),
    BasicDecimal128(1000000000000000000LL),
    BasicDecimal128(0LL, 10000000000000000000ULL),
    BasicDecimal128(5LL, 7766279631452241920ULL),
    BasicDecimal128(54LL, 3875820019684212736ULL),
    BasicDecimal128(542LL, 1864712049423024128ULL),
    BasicDecimal128(5421LL, 200376420520689664ULL),
    BasicDecimal128(54210LL, 2003764205206896640ULL),
    BasicDecimal128(542101LL, 1590897978359414784ULL),
    BasicDecimal128(5421010LL, 15908979783594147840ULL),
    BasicDecimal128(54210108LL, 11515845246265065472ULL),
    BasicDecimal128(542101086LL, 4477988020393345024ULL),
    BasicDecimal128(5421010862LL, 7886392056514347008ULL),
    BasicDecimal128(54210108624LL, 5076944270305263616ULL),
    BasicDecimal128(542101086242LL, 13875954555633532928ULL),
    BasicDecimal128(5421010862427LL, 9632337040368467968ULL),
    BasicDecimal128(54210108624275LL, 4089650035136921600ULL),
    BasicDecimal128(542101086242752LL, 4003012203950112768ULL),
    BasicDecimal128(5421010862427522LL, 3136633892082024448ULL),
    BasicDecimal128(54210108624275221LL, 12919594847110692864ULL),
    BasicDecimal128(542101086242752217LL, 68739955140067328ULL),
    BasicDecimal128(5421010862427522170LL, 687399551400673280ULL)};

static const BasicDecimal128 ScaleMultipliersHalf[] = {
    BasicDecimal128(0ULL),
    BasicDecimal128(5ULL),
    BasicDecimal128(50ULL),
    BasicDecimal128(500ULL),
    BasicDecimal128(5000ULL),
    BasicDecimal128(50000ULL),
    BasicDecimal128(500000ULL),
    BasicDecimal128(5000000ULL),
    BasicDecimal128(50000000ULL),
    BasicDecimal128(500000000ULL),
    BasicDecimal128(5000000000ULL),
    BasicDecimal128(50000000000ULL),
    BasicDecimal128(500000000000ULL),
    BasicDecimal128(5000000000000ULL),
    BasicDecimal128(50000000000000ULL),
    BasicDecimal128(500000000000000ULL),
    BasicDecimal128(5000000000000000ULL),
    BasicDecimal128(50000000000000000ULL),
    BasicDecimal128(500000000000000000ULL),
    BasicDecimal128(5000000000000000000ULL),
    BasicDecimal128(2LL, 13106511852580896768ULL),
    BasicDecimal128(27LL, 1937910009842106368ULL),
    BasicDecimal128(271LL, 932356024711512064ULL),
    BasicDecimal128(2710LL, 9323560247115120640ULL),
    BasicDecimal128(27105LL, 1001882102603448320ULL),
    BasicDecimal128(271050LL, 10018821026034483200ULL),
    BasicDecimal128(2710505LL, 7954489891797073920ULL),
    BasicDecimal128(27105054LL, 5757922623132532736ULL),
    BasicDecimal128(271050543LL, 2238994010196672512ULL),
    BasicDecimal128(2710505431LL, 3943196028257173504ULL),
    BasicDecimal128(27105054312LL, 2538472135152631808ULL),
    BasicDecimal128(271050543121LL, 6937977277816766464ULL),
    BasicDecimal128(2710505431213LL, 14039540557039009792ULL),
    BasicDecimal128(27105054312137LL, 11268197054423236608ULL),
    BasicDecimal128(271050543121376LL, 2001506101975056384ULL),
    BasicDecimal128(2710505431213761LL, 1568316946041012224ULL),
    BasicDecimal128(27105054312137610LL, 15683169460410122240ULL),
    BasicDecimal128(271050543121376108LL, 9257742014424809472ULL),
    BasicDecimal128(2710505431213761085LL, 343699775700336640ULL)};

#define BasicDecimal256FromLE(v1, v2, v3, v4) \
  BasicDecimal256(bit_util::little_endian::ToNative<uint64_t, 4>(v1, v2, v3, v4))

static const BasicDecimal256 ScaleMultipliersDecimal256[] = {
    BasicDecimal256FromLE({1ULL, 0ULL, 0ULL, 0ULL}),
    BasicDecimal256FromLE({10ULL, 0ULL, 0ULL, 0ULL}),
    BasicDecimal256FromLE({100ULL, 0ULL, 0ULL, 0ULL}),
    BasicDecimal256FromLE({1000ULL, 0ULL, 0ULL, 0ULL}),
    BasicDecimal256FromLE({10000ULL, 0ULL, 0ULL, 0ULL}),
    BasicDecimal256FromLE({100000ULL, 0ULL, 0ULL, 0ULL}),
    BasicDecimal256FromLE({1000000ULL, 0ULL, 0ULL, 0ULL}),
    BasicDecimal256FromLE({10000000ULL, 0ULL, 0ULL, 0ULL}),
    BasicDecimal256FromLE({100000000ULL, 0ULL, 0ULL, 0ULL}),
    BasicDecimal256FromLE({1000000000ULL, 0ULL, 0ULL, 0ULL}),
    BasicDecimal256FromLE({10000000000ULL, 0ULL, 0ULL, 0ULL}),
    BasicDecimal256FromLE({100000000000ULL, 0ULL, 0ULL, 0ULL}),
    BasicDecimal256FromLE({1000000000000ULL, 0ULL, 0ULL, 0ULL}),
    BasicDecimal256FromLE({10000000000000ULL, 0ULL, 0ULL, 0ULL}),
    BasicDecimal256FromLE({100000000000000ULL, 0ULL, 0ULL, 0ULL}),
    BasicDecimal256FromLE({1000000000000000ULL, 0ULL, 0ULL, 0ULL}),
    BasicDecimal256FromLE({10000000000000000ULL, 0ULL, 0ULL, 0ULL}),
    BasicDecimal256FromLE({100000000000000000ULL, 0ULL, 0ULL, 0ULL}),
    BasicDecimal256FromLE({1000000000000000000ULL, 0ULL, 0ULL, 0ULL}),
    BasicDecimal256FromLE({10000000000000000000ULL, 0ULL, 0ULL, 0ULL}),
    BasicDecimal256FromLE({7766279631452241920ULL, 5ULL, 0ULL, 0ULL}),
    BasicDecimal256FromLE({3875820019684212736ULL, 54ULL, 0ULL, 0ULL}),
    BasicDecimal256FromLE({1864712049423024128ULL, 542ULL, 0ULL, 0ULL}),
    BasicDecimal256FromLE({200376420520689664ULL, 5421ULL, 0ULL, 0ULL}),
    BasicDecimal256FromLE({2003764205206896640ULL, 54210ULL, 0ULL, 0ULL}),
    BasicDecimal256FromLE({1590897978359414784ULL, 542101ULL, 0ULL, 0ULL}),
    BasicDecimal256FromLE({15908979783594147840ULL, 5421010ULL, 0ULL, 0ULL}),
    BasicDecimal256FromLE({11515845246265065472ULL, 54210108ULL, 0ULL, 0ULL}),
    BasicDecimal256FromLE({4477988020393345024ULL, 542101086ULL, 0ULL, 0ULL}),
    BasicDecimal256FromLE({7886392056514347008ULL, 5421010862ULL, 0ULL, 0ULL}),
    BasicDecimal256FromLE({5076944270305263616ULL, 54210108624ULL, 0ULL, 0ULL}),
    BasicDecimal256FromLE({13875954555633532928ULL, 542101086242ULL, 0ULL, 0ULL}),
    BasicDecimal256FromLE({9632337040368467968ULL, 5421010862427ULL, 0ULL, 0ULL}),
    BasicDecimal256FromLE({4089650035136921600ULL, 54210108624275ULL, 0ULL, 0ULL}),
    BasicDecimal256FromLE({4003012203950112768ULL, 542101086242752ULL, 0ULL, 0ULL}),
    BasicDecimal256FromLE({3136633892082024448ULL, 5421010862427522ULL, 0ULL, 0ULL}),
    BasicDecimal256FromLE({12919594847110692864ULL, 54210108624275221ULL, 0ULL, 0ULL}),
    BasicDecimal256FromLE({68739955140067328ULL, 542101086242752217ULL, 0ULL, 0ULL}),
    BasicDecimal256FromLE({687399551400673280ULL, 5421010862427522170ULL, 0ULL, 0ULL}),
    BasicDecimal256FromLE({6873995514006732800ULL, 17316620476856118468ULL, 2ULL, 0ULL}),
    BasicDecimal256FromLE({13399722918938673152ULL, 7145508105175220139ULL, 29ULL, 0ULL}),
    BasicDecimal256FromLE(
        {4870020673419870208ULL, 16114848830623546549ULL, 293ULL, 0ULL}),
    BasicDecimal256FromLE(
        {11806718586779598848ULL, 13574535716559052564ULL, 2938ULL, 0ULL}),
    BasicDecimal256FromLE(
        {7386721425538678784ULL, 6618148649623664334ULL, 29387ULL, 0ULL}),
    BasicDecimal256FromLE(
        {80237960548581376ULL, 10841254275107988496ULL, 293873ULL, 0ULL}),
    BasicDecimal256FromLE(
        {802379605485813760ULL, 16178822382532126880ULL, 2938735ULL, 0ULL}),
    BasicDecimal256FromLE(
        {8023796054858137600ULL, 14214271235644855872ULL, 29387358ULL, 0ULL}),
    BasicDecimal256FromLE(
        {6450984253743169536ULL, 13015503840481697412ULL, 293873587ULL, 0ULL}),
    BasicDecimal256FromLE(
        {9169610316303040512ULL, 1027829888850112811ULL, 2938735877ULL, 0ULL}),
    BasicDecimal256FromLE(
        {17909126868192198656ULL, 10278298888501128114ULL, 29387358770ULL, 0ULL}),
    BasicDecimal256FromLE(
        {13070572018536022016ULL, 10549268516463523069ULL, 293873587705ULL, 0ULL}),
    BasicDecimal256FromLE(
        {1578511669393358848ULL, 13258964796087472617ULL, 2938735877055ULL, 0ULL}),
    BasicDecimal256FromLE(
        {15785116693933588480ULL, 3462439444907864858ULL, 29387358770557ULL, 0ULL}),
    BasicDecimal256FromLE(
        {10277214349659471872ULL, 16177650375369096972ULL, 293873587705571ULL, 0ULL}),
    BasicDecimal256FromLE(
        {10538423128046960640ULL, 14202551164014556797ULL, 2938735877055718ULL, 0ULL}),
    BasicDecimal256FromLE(
        {13150510911921848320ULL, 12898303124178706663ULL, 29387358770557187ULL, 0ULL}),
    BasicDecimal256FromLE(
        {2377900603251621888ULL, 18302566799529756941ULL, 293873587705571876ULL, 0ULL}),
    BasicDecimal256FromLE(
        {5332261958806667264ULL, 17004971331911604867ULL, 2938735877055718769ULL, 0ULL}),
    BasicDecimal256FromLE(
        {16429131440647569408ULL, 4029016655730084128ULL, 10940614696847636083ULL, 1ULL}),
    BasicDecimal256FromLE({16717361816799281152ULL, 3396678409881738056ULL,
                           17172426599928602752ULL, 15ULL}),
    BasicDecimal256FromLE({1152921504606846976ULL, 15520040025107828953ULL,
                           5703569335900062977ULL, 159ULL}),
    BasicDecimal256FromLE({11529215046068469760ULL, 7626447661401876602ULL,
                           1695461137871974930ULL, 1593ULL}),
    BasicDecimal256FromLE({4611686018427387904ULL, 2477500319180559562ULL,
                           16954611378719749304ULL, 15930ULL}),
    BasicDecimal256FromLE({9223372036854775808ULL, 6328259118096044006ULL,
                           3525417123811528497ULL, 159309ULL}),
    BasicDecimal256FromLE(
        {0ULL, 7942358959831785217ULL, 16807427164405733357ULL, 1593091ULL}),
    BasicDecimal256FromLE(
        {0ULL, 5636613303479645706ULL, 2053574980671369030ULL, 15930919ULL}),
    BasicDecimal256FromLE(
        {0ULL, 1025900813667802212ULL, 2089005733004138687ULL, 159309191ULL}),
    BasicDecimal256FromLE(
        {0ULL, 10259008136678022120ULL, 2443313256331835254ULL, 1593091911ULL}),
    BasicDecimal256FromLE(
        {0ULL, 10356360998232463120ULL, 5986388489608800929ULL, 15930919111ULL}),
    BasicDecimal256FromLE(
        {0ULL, 11329889613776873120ULL, 4523652674959354447ULL, 159309191113ULL}),
    BasicDecimal256FromLE(
        {0ULL, 2618431695511421504ULL, 8343038602174441244ULL, 1593091911132ULL}),
    BasicDecimal256FromLE(
        {0ULL, 7737572881404663424ULL, 9643409726906205977ULL, 15930919111324ULL}),
    BasicDecimal256FromLE(
        {0ULL, 3588752519208427776ULL, 4200376900514301694ULL, 159309191113245ULL}),
    BasicDecimal256FromLE(
        {0ULL, 17440781118374726144ULL, 5110280857723913709ULL, 1593091911132452ULL}),
    BasicDecimal256FromLE(
        {0ULL, 8387114520361296896ULL, 14209320429820033867ULL, 15930919111324522ULL}),
    BasicDecimal256FromLE(
        {0ULL, 10084168908774762496ULL, 12965995782233477362ULL, 159309191113245227ULL}),
    BasicDecimal256FromLE(
        {0ULL, 8607968719199866880ULL, 532749306367912313ULL, 1593091911132452277ULL})};

static const BasicDecimal256 ScaleMultipliersHalfDecimal256[] = {
    BasicDecimal256FromLE({0ULL, 0ULL, 0ULL, 0ULL}),
    BasicDecimal256FromLE({5ULL, 0ULL, 0ULL, 0ULL}),
    BasicDecimal256FromLE({50ULL, 0ULL, 0ULL, 0ULL}),
    BasicDecimal256FromLE({500ULL, 0ULL, 0ULL, 0ULL}),
    BasicDecimal256FromLE({5000ULL, 0ULL, 0ULL, 0ULL}),
    BasicDecimal256FromLE({50000ULL, 0ULL, 0ULL, 0ULL}),
    BasicDecimal256FromLE({500000ULL, 0ULL, 0ULL, 0ULL}),
    BasicDecimal256FromLE({5000000ULL, 0ULL, 0ULL, 0ULL}),
    BasicDecimal256FromLE({50000000ULL, 0ULL, 0ULL, 0ULL}),
    BasicDecimal256FromLE({500000000ULL, 0ULL, 0ULL, 0ULL}),
    BasicDecimal256FromLE({5000000000ULL, 0ULL, 0ULL, 0ULL}),
    BasicDecimal256FromLE({50000000000ULL, 0ULL, 0ULL, 0ULL}),
    BasicDecimal256FromLE({500000000000ULL, 0ULL, 0ULL, 0ULL}),
    BasicDecimal256FromLE({5000000000000ULL, 0ULL, 0ULL, 0ULL}),
    BasicDecimal256FromLE({50000000000000ULL, 0ULL, 0ULL, 0ULL}),
    BasicDecimal256FromLE({500000000000000ULL, 0ULL, 0ULL, 0ULL}),
    BasicDecimal256FromLE({5000000000000000ULL, 0ULL, 0ULL, 0ULL}),
    BasicDecimal256FromLE({50000000000000000ULL, 0ULL, 0ULL, 0ULL}),
    BasicDecimal256FromLE({500000000000000000ULL, 0ULL, 0ULL, 0ULL}),
    BasicDecimal256FromLE({5000000000000000000ULL, 0ULL, 0ULL, 0ULL}),
    BasicDecimal256FromLE({13106511852580896768ULL, 2ULL, 0ULL, 0ULL}),
    BasicDecimal256FromLE({1937910009842106368ULL, 27ULL, 0ULL, 0ULL}),
    BasicDecimal256FromLE({932356024711512064ULL, 271ULL, 0ULL, 0ULL}),
    BasicDecimal256FromLE({9323560247115120640ULL, 2710ULL, 0ULL, 0ULL}),
    BasicDecimal256FromLE({1001882102603448320ULL, 27105ULL, 0ULL, 0ULL}),
    BasicDecimal256FromLE({10018821026034483200ULL, 271050ULL, 0ULL, 0ULL}),
    BasicDecimal256FromLE({7954489891797073920ULL, 2710505ULL, 0ULL, 0ULL}),
    BasicDecimal256FromLE({5757922623132532736ULL, 27105054ULL, 0ULL, 0ULL}),
    BasicDecimal256FromLE({2238994010196672512ULL, 271050543ULL, 0ULL, 0ULL}),
    BasicDecimal256FromLE({3943196028257173504ULL, 2710505431ULL, 0ULL, 0ULL}),
    BasicDecimal256FromLE({2538472135152631808ULL, 27105054312ULL, 0ULL, 0ULL}),
    BasicDecimal256FromLE({6937977277816766464ULL, 271050543121ULL, 0ULL, 0ULL}),
    BasicDecimal256FromLE({14039540557039009792ULL, 2710505431213ULL, 0ULL, 0ULL}),
    BasicDecimal256FromLE({11268197054423236608ULL, 27105054312137ULL, 0ULL, 0ULL}),
    BasicDecimal256FromLE({2001506101975056384ULL, 271050543121376ULL, 0ULL, 0ULL}),
    BasicDecimal256FromLE({1568316946041012224ULL, 2710505431213761ULL, 0ULL, 0ULL}),
    BasicDecimal256FromLE({15683169460410122240ULL, 27105054312137610ULL, 0ULL, 0ULL}),
    BasicDecimal256FromLE({9257742014424809472ULL, 271050543121376108ULL, 0ULL, 0ULL}),
    BasicDecimal256FromLE({343699775700336640ULL, 2710505431213761085ULL, 0ULL, 0ULL}),
    BasicDecimal256FromLE({3436997757003366400ULL, 8658310238428059234ULL, 1ULL, 0ULL}),
    BasicDecimal256FromLE(
        {15923233496324112384ULL, 12796126089442385877ULL, 14ULL, 0ULL}),
    BasicDecimal256FromLE(
        {11658382373564710912ULL, 17280796452166549082ULL, 146ULL, 0ULL}),
    BasicDecimal256FromLE(
        {5903359293389799424ULL, 6787267858279526282ULL, 1469ULL, 0ULL}),
    BasicDecimal256FromLE(
        {3693360712769339392ULL, 12532446361666607975ULL, 14693ULL, 0ULL}),
    BasicDecimal256FromLE(
        {40118980274290688ULL, 14643999174408770056ULL, 146936ULL, 0ULL}),
    BasicDecimal256FromLE(
        {401189802742906880ULL, 17312783228120839248ULL, 1469367ULL, 0ULL}),
    BasicDecimal256FromLE(
        {4011898027429068800ULL, 7107135617822427936ULL, 14693679ULL, 0ULL}),
    BasicDecimal256FromLE(
        {3225492126871584768ULL, 15731123957095624514ULL, 146936793ULL, 0ULL}),
    BasicDecimal256FromLE(
        {13808177195006296064ULL, 9737286981279832213ULL, 1469367938ULL, 0ULL}),
    BasicDecimal256FromLE(
        {8954563434096099328ULL, 5139149444250564057ULL, 14693679385ULL, 0ULL}),
    BasicDecimal256FromLE(
        {15758658046122786816ULL, 14498006295086537342ULL, 146936793852ULL, 0ULL}),
    BasicDecimal256FromLE(
        {10012627871551455232ULL, 15852854434898512116ULL, 1469367938527ULL, 0ULL}),
    BasicDecimal256FromLE(
        {7892558346966794240ULL, 10954591759308708237ULL, 14693679385278ULL, 0ULL}),
    BasicDecimal256FromLE(
        {5138607174829735936ULL, 17312197224539324294ULL, 146936793852785ULL, 0ULL}),
    BasicDecimal256FromLE(
        {14492583600878256128ULL, 7101275582007278398ULL, 1469367938527859ULL, 0ULL}),
    BasicDecimal256FromLE(
        {15798627492815699968ULL, 15672523598944129139ULL, 14693679385278593ULL, 0ULL}),
    BasicDecimal256FromLE(
        {10412322338480586752ULL, 9151283399764878470ULL, 146936793852785938ULL, 0ULL}),
    BasicDecimal256FromLE(
        {11889503016258109440ULL, 17725857702810578241ULL, 1469367938527859384ULL, 0ULL}),
    BasicDecimal256FromLE(
        {8214565720323784704ULL, 11237880364719817872ULL, 14693679385278593849ULL, 0ULL}),
    BasicDecimal256FromLE(
        {8358680908399640576ULL, 1698339204940869028ULL, 17809585336819077184ULL, 7ULL}),
    BasicDecimal256FromLE({9799832789158199296ULL, 16983392049408690284ULL,
                           12075156704804807296ULL, 79ULL}),
    BasicDecimal256FromLE({5764607523034234880ULL, 3813223830700938301ULL,
                           10071102605790763273ULL, 796ULL}),
    BasicDecimal256FromLE({2305843009213693952ULL, 1238750159590279781ULL,
                           8477305689359874652ULL, 7965ULL}),
    BasicDecimal256FromLE({4611686018427387904ULL, 12387501595902797811ULL,
                           10986080598760540056ULL, 79654ULL}),
    BasicDecimal256FromLE({9223372036854775808ULL, 13194551516770668416ULL,
                           17627085619057642486ULL, 796545ULL}),
    BasicDecimal256FromLE(
        {0ULL, 2818306651739822853ULL, 10250159527190460323ULL, 7965459ULL}),
    BasicDecimal256FromLE(
        {0ULL, 9736322443688676914ULL, 10267874903356845151ULL, 79654595ULL}),
    BasicDecimal256FromLE(
        {0ULL, 5129504068339011060ULL, 10445028665020693435ULL, 796545955ULL}),
    BasicDecimal256FromLE(
        {0ULL, 14401552535971007368ULL, 12216566281659176272ULL, 7965459555ULL}),
    BasicDecimal256FromLE(
        {0ULL, 14888316843743212368ULL, 11485198374334453031ULL, 79654595556ULL}),
    BasicDecimal256FromLE(
        {0ULL, 1309215847755710752ULL, 4171519301087220622ULL, 796545955566ULL}),
    BasicDecimal256FromLE(
        {0ULL, 13092158477557107520ULL, 4821704863453102988ULL, 7965459555662ULL}),
    BasicDecimal256FromLE(
        {0ULL, 1794376259604213888ULL, 11323560487111926655ULL, 79654595556622ULL}),
    BasicDecimal256FromLE(
        {0ULL, 17943762596042138880ULL, 2555140428861956854ULL, 796545955566226ULL}),
    BasicDecimal256FromLE(
        {0ULL, 13416929297035424256ULL, 7104660214910016933ULL, 7965459555662261ULL}),
    BasicDecimal256FromLE(
        {0ULL, 5042084454387381248ULL, 15706369927971514489ULL, 79654595556622613ULL}),
    BasicDecimal256FromLE(
        {0ULL, 13527356396454709248ULL, 9489746690038731964ULL, 796545955566226138ULL})};

#undef BasicDecimal256FromLE

#ifdef ARROW_USE_NATIVE_INT128
static constexpr uint64_t kInt64Mask = 0xFFFFFFFFFFFFFFFF;
#else
static constexpr uint64_t kInt32Mask = 0xFFFFFFFF;
#endif

// same as ScaleMultipliers[38] - 1
static constexpr BasicDecimal128 kMaxValue =
    BasicDecimal128(5421010862427522170LL, 687399551400673280ULL - 1);

constexpr int BasicDecimal128::kMaxPrecision;
constexpr int BasicDecimal128::kMaxScale;

BasicDecimal128& BasicDecimal128::Negate() {
  uint64_t result_lo = ~low_bits() + 1;
  int64_t result_hi = ~high_bits();
  if (result_lo == 0) {
    result_hi = SafeSignedAdd<int64_t>(result_hi, 1);
  }
  *this = BasicDecimal128(result_hi, result_lo);
  return *this;
}

BasicDecimal128& BasicDecimal128::Abs() { return *this < 0 ? Negate() : *this; }

BasicDecimal128 BasicDecimal128::Abs(const BasicDecimal128& in) {
  BasicDecimal128 result(in);
  return result.Abs();
}

bool BasicDecimal128::FitsInPrecision(int32_t precision) const {
  DCHECK_GT(precision, 0);
  DCHECK_LE(precision, 38);
  return BasicDecimal128::Abs(*this) < ScaleMultipliers[precision];
}

BasicDecimal128& BasicDecimal128::operator+=(const BasicDecimal128& right) {
  int64_t result_hi = SafeSignedAdd(high_bits(), right.high_bits());
  uint64_t result_lo = low_bits() + right.low_bits();
  result_hi = SafeSignedAdd<int64_t>(result_hi, result_lo < low_bits());
  *this = BasicDecimal128(result_hi, result_lo);
  return *this;
}

BasicDecimal128& BasicDecimal128::operator-=(const BasicDecimal128& right) {
  int64_t result_hi = SafeSignedSubtract(high_bits(), right.high_bits());
  uint64_t result_lo = low_bits() - right.low_bits();
  result_hi = SafeSignedSubtract<int64_t>(result_hi, result_lo > low_bits());
  *this = BasicDecimal128(result_hi, result_lo);
  return *this;
}

BasicDecimal128& BasicDecimal128::operator/=(const BasicDecimal128& right) {
  BasicDecimal128 remainder;
  auto s = Divide(right, this, &remainder);
  DCHECK_EQ(s, DecimalStatus::kSuccess);
  return *this;
}

BasicDecimal128& BasicDecimal128::operator|=(const BasicDecimal128& right) {
  array_[0] |= right.array_[0];
  array_[1] |= right.array_[1];
  return *this;
}

BasicDecimal128& BasicDecimal128::operator&=(const BasicDecimal128& right) {
  array_[0] &= right.array_[0];
  array_[1] &= right.array_[1];
  return *this;
}

BasicDecimal128& BasicDecimal128::operator<<=(uint32_t bits) {
  if (bits != 0) {
    uint64_t result_lo;
    int64_t result_hi;
    if (bits < 64) {
      result_hi = SafeLeftShift(high_bits(), bits);
      result_hi |= (low_bits() >> (64 - bits));
      result_lo = low_bits() << bits;
    } else if (bits < 128) {
      result_hi = static_cast<int64_t>(low_bits() << (bits - 64));
      result_lo = 0;
    } else {
      result_hi = 0;
      result_lo = 0;
    }
    *this = BasicDecimal128(result_hi, result_lo);
  }
  return *this;
}

BasicDecimal128& BasicDecimal128::operator>>=(uint32_t bits) {
  if (bits != 0) {
    uint64_t result_lo;
    int64_t result_hi;
    if (bits < 64) {
      result_lo = low_bits() >> bits;
      result_lo |= static_cast<uint64_t>(high_bits()) << (64 - bits);
      result_hi = high_bits() >> bits;
    } else if (bits < 128) {
      result_lo = static_cast<uint64_t>(high_bits() >> (bits - 64));
      result_hi = high_bits() >> 63;
    } else {
      result_hi = high_bits() >> 63;
      result_lo = static_cast<uint64_t>(result_hi);
    }
    *this = BasicDecimal128(result_hi, result_lo);
  }
  return *this;
}

namespace {

// Convenience wrapper type over 128 bit unsigned integers. We opt not to
// replace the uint128_t type in int128_internal.h because it would require
// significantly more implementation work to be done. This class merely
// provides the minimum necessary set of functions to perform 128+ bit
// multiplication operations when there may or may not be native support.
#ifdef ARROW_USE_NATIVE_INT128
struct uint128_t {
  uint128_t() {}
  uint128_t(uint64_t hi, uint64_t lo) : val_((static_cast<__uint128_t>(hi) << 64) | lo) {}
  explicit uint128_t(const BasicDecimal128& decimal) {
    val_ = (static_cast<__uint128_t>(decimal.high_bits()) << 64) | decimal.low_bits();
  }

  explicit uint128_t(uint64_t value) : val_(value) {}

  uint64_t hi() { return val_ >> 64; }
  uint64_t lo() { return val_ & kInt64Mask; }

  uint128_t& operator+=(const uint128_t& other) {
    val_ += other.val_;
    return *this;
  }

  uint128_t& operator*=(const uint128_t& other) {
    val_ *= other.val_;
    return *this;
  }

  __uint128_t val_;
};

#else
// Multiply two 64 bit word components into a 128 bit result, with high bits
// stored in hi and low bits in lo.
inline void ExtendAndMultiply(uint64_t x, uint64_t y, uint64_t* hi, uint64_t* lo) {
  // Perform multiplication on two 64 bit words x and y into a 128 bit result
  // by splitting up x and y into 32 bit high/low bit components,
  // allowing us to represent the multiplication as
  // x * y = x_lo * y_lo + x_hi * y_lo * 2^32 + y_hi * x_lo * 2^32
  // + x_hi * y_hi * 2^64
  //
  // Now, consider the final output as lo_lo || lo_hi || hi_lo || hi_hi
  // Therefore,
  // lo_lo is (x_lo * y_lo)_lo,
  // lo_hi is ((x_lo * y_lo)_hi + (x_hi * y_lo)_lo + (x_lo * y_hi)_lo)_lo,
  // hi_lo is ((x_hi * y_hi)_lo + (x_hi * y_lo)_hi + (x_lo * y_hi)_hi)_hi,
  // hi_hi is (x_hi * y_hi)_hi
  const uint64_t x_lo = x & kInt32Mask;
  const uint64_t y_lo = y & kInt32Mask;
  const uint64_t x_hi = x >> 32;
  const uint64_t y_hi = y >> 32;

  const uint64_t t = x_lo * y_lo;
  const uint64_t t_lo = t & kInt32Mask;
  const uint64_t t_hi = t >> 32;

  const uint64_t u = x_hi * y_lo + t_hi;
  const uint64_t u_lo = u & kInt32Mask;
  const uint64_t u_hi = u >> 32;

  const uint64_t v = x_lo * y_hi + u_lo;
  const uint64_t v_hi = v >> 32;

  *hi = x_hi * y_hi + u_hi + v_hi;
  *lo = (v << 32) + t_lo;
}

struct uint128_t {
  uint128_t() {}
  uint128_t(uint64_t hi, uint64_t lo) : hi_(hi), lo_(lo) {}
  explicit uint128_t(const BasicDecimal128& decimal) {
    hi_ = decimal.high_bits();
    lo_ = decimal.low_bits();
  }

  uint64_t hi() const { return hi_; }
  uint64_t lo() const { return lo_; }

  uint128_t& operator+=(const uint128_t& other) {
    // To deduce the carry bit, we perform "65 bit" addition on the low bits and
    // seeing if the resulting high bit is 1. This is accomplished by shifting the
    // low bits to the right by 1 (chopping off the lowest bit), then adding 1 if the
    // result of adding the two chopped bits would have produced a carry.
    uint64_t carry = (((lo_ & other.lo_) & 1) + (lo_ >> 1) + (other.lo_ >> 1)) >> 63;
    hi_ += other.hi_ + carry;
    lo_ += other.lo_;
    return *this;
  }

  uint128_t& operator*=(const uint128_t& other) {
    uint128_t r;
    ExtendAndMultiply(lo_, other.lo_, &r.hi_, &r.lo_);
    r.hi_ += (hi_ * other.lo_) + (lo_ * other.hi_);
    *this = r;
    return *this;
  }

  uint64_t hi_;
  uint64_t lo_;
};
#endif

// Multiplies two N * 64 bit unsigned integer types, represented by a uint64_t
// array into a same sized output. Elements in the array should be in
// native endian order, and output will be the same. Overflow in multiplication
// will result in the lower N * 64 bits of the result being set.
template <int N>
inline void MultiplyUnsignedArray(const std::array<uint64_t, N>& lh,
                                  const std::array<uint64_t, N>& rh,
                                  std::array<uint64_t, N>* result) {
  const auto lh_le = bit_util::little_endian::Make(lh);
  const auto rh_le = bit_util::little_endian::Make(rh);
  auto result_le = bit_util::little_endian::Make(result);

  for (int j = 0; j < N; ++j) {
    uint64_t carry = 0;
    for (int i = 0; i < N - j; ++i) {
      uint128_t tmp(lh_le[i]);
      tmp *= uint128_t(rh_le[j]);
      tmp += uint128_t(result_le[i + j]);
      tmp += uint128_t(carry);
      result_le[i + j] = tmp.lo();
      carry = tmp.hi();
    }
  }
}

}  // namespace

BasicDecimal128& BasicDecimal128::operator*=(const BasicDecimal128& right) {
  // Since the max value of BasicDecimal128 is supposed to be 1e38 - 1 and the
  // min the negation taking the absolute values here should always be safe.
  const bool negate = Sign() != right.Sign();
  BasicDecimal128 x = BasicDecimal128::Abs(*this);
  BasicDecimal128 y = BasicDecimal128::Abs(right);
  uint128_t r(x);
  r *= uint128_t{y};
  *this = BasicDecimal128(static_cast<int64_t>(r.hi()), r.lo());
  if (negate) {
    Negate();
  }
  return *this;
}

/// Expands the given native endian array of uint64_t into a big endian array of
/// uint32_t. The value of input array is expected to be non-negative. The result_array
/// will remove leading zeros from the input array.
/// \param value_array a native endian array to represent the value
/// \param result_array a big endian array of length N*2 to set with the value
/// \result the output length of the array
template <size_t N>
static int64_t FillInArray(const std::array<uint64_t, N>& value_array,
                           uint32_t* result_array) {
  const auto value_array_le = bit_util::little_endian::Make(value_array);
  int64_t next_index = 0;
  // 1st loop to find out 1st non-negative value in input
  int64_t i = N - 1;
  for (; i >= 0; i--) {
    if (value_array_le[i] != 0) {
      if (value_array_le[i] <= std::numeric_limits<uint32_t>::max()) {
        result_array[next_index++] = static_cast<uint32_t>(value_array_le[i]);
        i--;
      }
      break;
    }
  }
  // 2nd loop to fill in the rest of the array.
  for (int64_t j = i; j >= 0; j--) {
    result_array[next_index++] = static_cast<uint32_t>(value_array_le[j] >> 32);
    result_array[next_index++] = static_cast<uint32_t>(value_array_le[j]);
  }
  return next_index;
}

/// Expands the given value into a big endian array of ints so that we can work on
/// it. The array will be converted to an absolute value and the was_negative
/// flag will be set appropriately. The array will remove leading zeros from
/// the value.
/// \param array a big endian array of length 4 to set with the value
/// \param was_negative a flag for whether the value was original negative
/// \result the output length of the array
static int64_t FillInArray(const BasicDecimal128& value, uint32_t* array,
                           bool& was_negative) {
  BasicDecimal128 abs_value = BasicDecimal128::Abs(value);
  was_negative = value.high_bits() < 0;
  uint64_t high = static_cast<uint64_t>(abs_value.high_bits());
  uint64_t low = abs_value.low_bits();

  // FillInArray(std::array<uint64_t, N>& value_array, uint32_t* result_array) is not
  // called here as the following code has better performance, to avoid regression on
  // BasicDecimal128 Division.
  if (high != 0) {
    if (high > std::numeric_limits<uint32_t>::max()) {
      array[0] = static_cast<uint32_t>(high >> 32);
      array[1] = static_cast<uint32_t>(high);
      array[2] = static_cast<uint32_t>(low >> 32);
      array[3] = static_cast<uint32_t>(low);
      return 4;
    }

    array[0] = static_cast<uint32_t>(high);
    array[1] = static_cast<uint32_t>(low >> 32);
    array[2] = static_cast<uint32_t>(low);
    return 3;
  }

  if (low > std::numeric_limits<uint32_t>::max()) {
    array[0] = static_cast<uint32_t>(low >> 32);
    array[1] = static_cast<uint32_t>(low);
    return 2;
  }

  if (low == 0) {
    return 0;
  }

  array[0] = static_cast<uint32_t>(low);
  return 1;
}

/// Expands the given value into a big endian array of ints so that we can work on
/// it. The array will be converted to an absolute value and the was_negative
/// flag will be set appropriately. The array will remove leading zeros from
/// the value.
/// \param array a big endian array of length 8 to set with the value
/// \param was_negative a flag for whether the value was original negative
/// \result the output length of the array
static int64_t FillInArray(const BasicDecimal256& value, uint32_t* array,
                           bool& was_negative) {
  BasicDecimal256 positive_value = value;
  was_negative = false;
  if (positive_value.IsNegative()) {
    positive_value.Negate();
    was_negative = true;
  }
  return FillInArray<4>(positive_value.native_endian_array(), array);
}

/// Shift the number in the array left by bits positions.
/// \param array the number to shift, must have length elements
/// \param length the number of entries in the array
/// \param bits the number of bits to shift (0 <= bits < 32)
static void ShiftArrayLeft(uint32_t* array, int64_t length, int64_t bits) {
  if (length > 0 && bits != 0) {
    for (int64_t i = 0; i < length - 1; ++i) {
      array[i] = (array[i] << bits) | (array[i + 1] >> (32 - bits));
    }
    array[length - 1] <<= bits;
  }
}

/// Shift the number in the array right by bits positions.
/// \param array the number to shift, must have length elements
/// \param length the number of entries in the array
/// \param bits the number of bits to shift (0 <= bits < 32)
static inline void ShiftArrayRight(uint32_t* array, int64_t length, int64_t bits) {
  if (length > 0 && bits != 0) {
    for (int64_t i = length - 1; i > 0; --i) {
      array[i] = (array[i] >> bits) | (array[i - 1] << (32 - bits));
    }
    array[0] >>= bits;
  }
}

/// \brief Fix the signs of the result and remainder at the end of the division based on
/// the signs of the dividend and divisor.
template <class DecimalClass>
static inline void FixDivisionSigns(DecimalClass* result, DecimalClass* remainder,
                                    bool dividend_was_negative,
                                    bool divisor_was_negative) {
  if (dividend_was_negative != divisor_was_negative) {
    result->Negate();
  }

  if (dividend_was_negative) {
    remainder->Negate();
  }
}

/// \brief Build a native endian array of uint64_t from a big endian array of uint32_t.
template <size_t N>
static DecimalStatus BuildFromArray(std::array<uint64_t, N>* result_array,
                                    const uint32_t* array, int64_t length) {
  for (int64_t i = length - 2 * N - 1; i >= 0; i--) {
    if (array[i] != 0) {
      return DecimalStatus::kOverflow;
    }
  }
  int64_t next_index = length - 1;
  size_t i = 0;
  auto result_array_le = bit_util::little_endian::Make(result_array);
  for (; i < N && next_index >= 0; i++) {
    uint64_t lower_bits = array[next_index--];
    result_array_le[i] =
        (next_index < 0)
            ? lower_bits
            : ((static_cast<uint64_t>(array[next_index--]) << 32) + lower_bits);
  }
  for (; i < N; i++) {
    result_array_le[i] = 0;
  }
  return DecimalStatus::kSuccess;
}

/// \brief Build a BasicDecimal128 from a big endian array of uint32_t.
static DecimalStatus BuildFromArray(BasicDecimal128* value, const uint32_t* array,
                                    int64_t length) {
  std::array<uint64_t, 2> result_array;
  auto status = BuildFromArray(&result_array, array, length);
  if (status != DecimalStatus::kSuccess) {
    return status;
  }
  const auto result_array_le = bit_util::little_endian::Make(result_array);
  *value = {static_cast<int64_t>(result_array_le[1]), result_array_le[0]};
  return DecimalStatus::kSuccess;
}

/// \brief Build a BasicDecimal256 from a big endian array of uint32_t.
static DecimalStatus BuildFromArray(BasicDecimal256* value, const uint32_t* array,
                                    int64_t length) {
  std::array<uint64_t, 4> result_array;
  auto status = BuildFromArray(&result_array, array, length);
  if (status != DecimalStatus::kSuccess) {
    return status;
  }
  *value = result_array;
  return DecimalStatus::kSuccess;
}

/// \brief Do a division where the divisor fits into a single 32 bit value.
template <class DecimalClass>
static inline DecimalStatus SingleDivide(const uint32_t* dividend,
                                         int64_t dividend_length, uint32_t divisor,
                                         DecimalClass* remainder,
                                         bool dividend_was_negative,
                                         bool divisor_was_negative,
                                         DecimalClass* result) {
  uint64_t r = 0;
  constexpr int64_t kDecimalArrayLength = DecimalClass::kBitWidth / sizeof(uint32_t) + 1;
  uint32_t result_array[kDecimalArrayLength];
  for (int64_t j = 0; j < dividend_length; j++) {
    r <<= 32;
    r += dividend[j];
    result_array[j] = static_cast<uint32_t>(r / divisor);
    r %= divisor;
  }
  auto status = BuildFromArray(result, result_array, dividend_length);
  if (status != DecimalStatus::kSuccess) {
    return status;
  }

  *remainder = static_cast<int64_t>(r);
  FixDivisionSigns(result, remainder, dividend_was_negative, divisor_was_negative);
  return DecimalStatus::kSuccess;
}

/// \brief Do a decimal division with remainder.
template <class DecimalClass>
static inline DecimalStatus DecimalDivide(const DecimalClass& dividend,
                                          const DecimalClass& divisor,
                                          DecimalClass* result, DecimalClass* remainder) {
  constexpr int64_t kDecimalArrayLength = DecimalClass::kBitWidth / sizeof(uint32_t);
  // Split the dividend and divisor into integer pieces so that we can
  // work on them.
  uint32_t dividend_array[kDecimalArrayLength + 1];
  uint32_t divisor_array[kDecimalArrayLength];
  bool dividend_was_negative;
  bool divisor_was_negative;
  // leave an extra zero before the dividend
  dividend_array[0] = 0;
  int64_t dividend_length =
      FillInArray(dividend, dividend_array + 1, dividend_was_negative) + 1;
  int64_t divisor_length = FillInArray(divisor, divisor_array, divisor_was_negative);

  // Handle some of the easy cases.
  if (dividend_length <= divisor_length) {
    *remainder = dividend;
    *result = 0;
    return DecimalStatus::kSuccess;
  }

  if (divisor_length == 0) {
    return DecimalStatus::kDivideByZero;
  }

  if (divisor_length == 1) {
    return SingleDivide(dividend_array, dividend_length, divisor_array[0], remainder,
                        dividend_was_negative, divisor_was_negative, result);
  }

  int64_t result_length = dividend_length - divisor_length;
  uint32_t result_array[kDecimalArrayLength];
  DCHECK_LE(result_length, kDecimalArrayLength);

  // Normalize by shifting both by a multiple of 2 so that
  // the digit guessing is better. The requirement is that
  // divisor_array[0] is greater than 2**31.
  int64_t normalize_bits = bit_util::CountLeadingZeros(divisor_array[0]);
  ShiftArrayLeft(divisor_array, divisor_length, normalize_bits);
  ShiftArrayLeft(dividend_array, dividend_length, normalize_bits);

  // compute each digit in the result
  for (int64_t j = 0; j < result_length; ++j) {
    // Guess the next digit. At worst it is two too large
    uint32_t guess = std::numeric_limits<uint32_t>::max();
    const auto high_dividend =
        static_cast<uint64_t>(dividend_array[j]) << 32 | dividend_array[j + 1];
    if (dividend_array[j] != divisor_array[0]) {
      guess = static_cast<uint32_t>(high_dividend / divisor_array[0]);
    }

    // catch all of the cases where guess is two too large and most of the
    // cases where it is one too large
    auto rhat = static_cast<uint32_t>(high_dividend -
                                      guess * static_cast<uint64_t>(divisor_array[0]));
    while (static_cast<uint64_t>(divisor_array[1]) * guess >
           (static_cast<uint64_t>(rhat) << 32) + dividend_array[j + 2]) {
      --guess;
      rhat += divisor_array[0];
      if (static_cast<uint64_t>(rhat) < divisor_array[0]) {
        break;
      }
    }

    // subtract off the guess * divisor from the dividend
    uint64_t mult = 0;
    for (int64_t i = divisor_length - 1; i >= 0; --i) {
      mult += static_cast<uint64_t>(guess) * divisor_array[i];
      uint32_t prev = dividend_array[j + i + 1];
      dividend_array[j + i + 1] -= static_cast<uint32_t>(mult);
      mult >>= 32;
      if (dividend_array[j + i + 1] > prev) {
        ++mult;
      }
    }
    uint32_t prev = dividend_array[j];
    dividend_array[j] -= static_cast<uint32_t>(mult);

    // if guess was too big, we add back divisor
    if (dividend_array[j] > prev) {
      --guess;
      uint32_t carry = 0;
      for (int64_t i = divisor_length - 1; i >= 0; --i) {
        const auto sum =
            static_cast<uint64_t>(divisor_array[i]) + dividend_array[j + i + 1] + carry;
        dividend_array[j + i + 1] = static_cast<uint32_t>(sum);
        carry = static_cast<uint32_t>(sum >> 32);
      }
      dividend_array[j] += carry;
    }

    result_array[j] = guess;
  }

  // denormalize the remainder
  ShiftArrayRight(dividend_array, dividend_length, normalize_bits);

  // return result and remainder
  auto status = BuildFromArray(result, result_array, result_length);
  if (status != DecimalStatus::kSuccess) {
    return status;
  }
  status = BuildFromArray(remainder, dividend_array, dividend_length);
  if (status != DecimalStatus::kSuccess) {
    return status;
  }

  FixDivisionSigns(result, remainder, dividend_was_negative, divisor_was_negative);
  return DecimalStatus::kSuccess;
}

DecimalStatus BasicDecimal128::Divide(const BasicDecimal128& divisor,
                                      BasicDecimal128* result,
                                      BasicDecimal128* remainder) const {
  return DecimalDivide(*this, divisor, result, remainder);
}

bool operator==(const BasicDecimal128& left, const BasicDecimal128& right) {
  return left.high_bits() == right.high_bits() && left.low_bits() == right.low_bits();
}

bool operator!=(const BasicDecimal128& left, const BasicDecimal128& right) {
  return !operator==(left, right);
}

bool operator<(const BasicDecimal128& left, const BasicDecimal128& right) {
  return left.high_bits() < right.high_bits() ||
         (left.high_bits() == right.high_bits() && left.low_bits() < right.low_bits());
}

bool operator<=(const BasicDecimal128& left, const BasicDecimal128& right) {
  return !operator>(left, right);
}

bool operator>(const BasicDecimal128& left, const BasicDecimal128& right) {
  return operator<(right, left);
}

bool operator>=(const BasicDecimal128& left, const BasicDecimal128& right) {
  return !operator<(left, right);
}

BasicDecimal128 operator-(const BasicDecimal128& operand) {
  BasicDecimal128 result(operand.high_bits(), operand.low_bits());
  return result.Negate();
}

BasicDecimal128 operator~(const BasicDecimal128& operand) {
  BasicDecimal128 result(~operand.high_bits(), ~operand.low_bits());
  return result;
}

BasicDecimal128 operator+(const BasicDecimal128& left, const BasicDecimal128& right) {
  BasicDecimal128 result(left.high_bits(), left.low_bits());
  result += right;
  return result;
}

BasicDecimal128 operator-(const BasicDecimal128& left, const BasicDecimal128& right) {
  BasicDecimal128 result(left.high_bits(), left.low_bits());
  result -= right;
  return result;
}

BasicDecimal128 operator*(const BasicDecimal128& left, const BasicDecimal128& right) {
  BasicDecimal128 result(left.high_bits(), left.low_bits());
  result *= right;
  return result;
}

BasicDecimal128 operator/(const BasicDecimal128& left, const BasicDecimal128& right) {
  BasicDecimal128 remainder;
  BasicDecimal128 result;
  auto s = left.Divide(right, &result, &remainder);
  DCHECK_EQ(s, DecimalStatus::kSuccess);
  return result;
}

BasicDecimal128 operator%(const BasicDecimal128& left, const BasicDecimal128& right) {
  BasicDecimal128 remainder;
  BasicDecimal128 result;
  auto s = left.Divide(right, &result, &remainder);
  DCHECK_EQ(s, DecimalStatus::kSuccess);
  return remainder;
}

template <class DecimalClass>
static bool RescaleWouldCauseDataLoss(const DecimalClass& value, int32_t delta_scale,
                                      const DecimalClass& multiplier,
                                      DecimalClass* result) {
  if (delta_scale < 0) {
    DCHECK_NE(multiplier, 0);
    DecimalClass remainder;
    auto status = value.Divide(multiplier, result, &remainder);
    DCHECK_EQ(status, DecimalStatus::kSuccess);
    return remainder != 0;
  }

  *result = value * multiplier;
  return (value < 0) ? *result > value : *result < value;
}

template <class DecimalClass>
DecimalStatus DecimalRescale(const DecimalClass& value, int32_t original_scale,
                             int32_t new_scale, DecimalClass* out) {
  DCHECK_NE(out, nullptr);

  if (original_scale == new_scale) {
    *out = value;
    return DecimalStatus::kSuccess;
  }

  const int32_t delta_scale = new_scale - original_scale;
  const int32_t abs_delta_scale = std::abs(delta_scale);

  DecimalClass multiplier = DecimalClass::GetScaleMultiplier(abs_delta_scale);

  const bool rescale_would_cause_data_loss =
      RescaleWouldCauseDataLoss(value, delta_scale, multiplier, out);

  // Fail if we overflow or truncate
  if (ARROW_PREDICT_FALSE(rescale_would_cause_data_loss)) {
    return DecimalStatus::kRescaleDataLoss;
  }

  return DecimalStatus::kSuccess;
}

DecimalStatus BasicDecimal128::Rescale(int32_t original_scale, int32_t new_scale,
                                       BasicDecimal128* out) const {
  return DecimalRescale(*this, original_scale, new_scale, out);
}

void BasicDecimal128::GetWholeAndFraction(int scale, BasicDecimal128* whole,
                                          BasicDecimal128* fraction) const {
  DCHECK_GE(scale, 0);
  DCHECK_LE(scale, 38);

  BasicDecimal128 multiplier(ScaleMultipliers[scale]);
  auto s = Divide(multiplier, whole, fraction);
  DCHECK_EQ(s, DecimalStatus::kSuccess);
}

const BasicDecimal128& BasicDecimal128::GetScaleMultiplier(int32_t scale) {
  DCHECK_GE(scale, 0);
  DCHECK_LE(scale, 38);

  return ScaleMultipliers[scale];
}

const BasicDecimal128& BasicDecimal128::GetHalfScaleMultiplier(int32_t scale) {
  DCHECK_GE(scale, 0);
  DCHECK_LE(scale, 38);

  return ScaleMultipliersHalf[scale];
}

const BasicDecimal128& BasicDecimal128::GetMaxValue() { return kMaxValue; }

BasicDecimal128 BasicDecimal128::GetMaxValue(int32_t precision) {
  DCHECK_GE(precision, 0);
  DCHECK_LE(precision, 38);
  return ScaleMultipliers[precision] - 1;
}

BasicDecimal128 BasicDecimal128::IncreaseScaleBy(int32_t increase_by) const {
  DCHECK_GE(increase_by, 0);
  DCHECK_LE(increase_by, 38);

  return (*this) * ScaleMultipliers[increase_by];
}

BasicDecimal128 BasicDecimal128::ReduceScaleBy(int32_t reduce_by, bool round) const {
  DCHECK_GE(reduce_by, 0);
  DCHECK_LE(reduce_by, 38);

  if (reduce_by == 0) {
    return *this;
  }

  BasicDecimal128 divisor(ScaleMultipliers[reduce_by]);
  BasicDecimal128 result;
  BasicDecimal128 remainder;
  auto s = Divide(divisor, &result, &remainder);
  DCHECK_EQ(s, DecimalStatus::kSuccess);
  if (round) {
    auto divisor_half = ScaleMultipliersHalf[reduce_by];
    if (remainder.Abs() >= divisor_half) {
      result += Sign();
    }
  }
  return result;
}

int32_t BasicDecimal128::CountLeadingBinaryZeros() const {
  DCHECK_GE(*this, BasicDecimal128(0));

  if (high_bits() == 0) {
    return bit_util::CountLeadingZeros(low_bits()) + 64;
  } else {
    return bit_util::CountLeadingZeros(static_cast<uint64_t>(high_bits()));
  }
}

constexpr int BasicDecimal256::kMaxPrecision;
constexpr int BasicDecimal256::kMaxScale;

BasicDecimal256& BasicDecimal256::Negate() {
  auto array_le = bit_util::little_endian::Make(&array_);
  uint64_t carry = 1;
  for (size_t i = 0; i < array_.size(); ++i) {
    uint64_t& elem = array_le[i];
    elem = ~elem + carry;
    carry &= (elem == 0);
  }
  return *this;
}

BasicDecimal256& BasicDecimal256::Abs() { return *this < 0 ? Negate() : *this; }

BasicDecimal256 BasicDecimal256::Abs(const BasicDecimal256& in) {
  BasicDecimal256 result(in);
  return result.Abs();
}

BasicDecimal256& BasicDecimal256::operator+=(const BasicDecimal256& right) {
  auto array_le = bit_util::little_endian::Make(&array_);
  const auto right_array_le = bit_util::little_endian::Make(right.array_);
  uint64_t carry = 0;
  for (size_t i = 0; i < array_.size(); i++) {
    const uint64_t right_value = right_array_le[i];
    uint64_t sum = right_value + carry;
    carry = 0;
    if (sum < right_value) {
      carry += 1;
    }
    sum += array_le[i];
    if (sum < array_le[i]) {
      carry += 1;
    }
    array_le[i] = sum;
  }
  return *this;
}

BasicDecimal256& BasicDecimal256::operator-=(const BasicDecimal256& right) {
  *this += -right;
  return *this;
}

BasicDecimal256& BasicDecimal256::operator<<=(uint32_t bits) {
  if (bits == 0) {
    return *this;
  }
  int cross_word_shift = bits / 64;
  if (static_cast<size_t>(cross_word_shift) >= array_.size()) {
    array_ = {0, 0, 0, 0};
    return *this;
  }
  uint32_t in_word_shift = bits % 64;
  auto array_le = bit_util::little_endian::Make(&array_);
  for (int i = static_cast<int>(array_.size() - 1); i >= cross_word_shift; i--) {
    // Account for shifts larger then 64 bits
    array_le[i] = array_le[i - cross_word_shift];
    array_le[i] <<= in_word_shift;
    if (in_word_shift != 0 && i >= cross_word_shift + 1) {
      array_le[i] |= array_le[i - (cross_word_shift + 1)] >> (64 - in_word_shift);
    }
  }
  for (int i = cross_word_shift - 1; i >= 0; i--) {
    array_le[i] = 0;
  }
  return *this;
}

BasicDecimal256& BasicDecimal256::operator*=(const BasicDecimal256& right) {
  // Since the max value of BasicDecimal256 is supposed to be 1e76 - 1 and the
  // min the negation taking the absolute values here should always be safe.
  const bool negate = Sign() != right.Sign();
  BasicDecimal256 x = BasicDecimal256::Abs(*this);
  BasicDecimal256 y = BasicDecimal256::Abs(right);

  std::array<uint64_t, 4> res{0, 0, 0, 0};
  MultiplyUnsignedArray<4>(x.array_, y.array_, &res);
  array_ = res;
  if (negate) {
    Negate();
  }
  return *this;
}

DecimalStatus BasicDecimal256::Divide(const BasicDecimal256& divisor,
                                      BasicDecimal256* result,
                                      BasicDecimal256* remainder) const {
  return DecimalDivide(*this, divisor, result, remainder);
}

DecimalStatus BasicDecimal256::Rescale(int32_t original_scale, int32_t new_scale,
                                       BasicDecimal256* out) const {
  return DecimalRescale(*this, original_scale, new_scale, out);
}

BasicDecimal256 BasicDecimal256::IncreaseScaleBy(int32_t increase_by) const {
  DCHECK_GE(increase_by, 0);
  DCHECK_LE(increase_by, 76);

  return (*this) * ScaleMultipliersDecimal256[increase_by];
}

BasicDecimal256 BasicDecimal256::ReduceScaleBy(int32_t reduce_by, bool round) const {
  DCHECK_GE(reduce_by, 0);
  DCHECK_LE(reduce_by, 76);

  if (reduce_by == 0) {
    return *this;
  }

  BasicDecimal256 divisor(ScaleMultipliersDecimal256[reduce_by]);
  BasicDecimal256 result;
  BasicDecimal256 remainder;
  auto s = Divide(divisor, &result, &remainder);
  DCHECK_EQ(s, DecimalStatus::kSuccess);
  if (round) {
    auto divisor_half = ScaleMultipliersHalfDecimal256[reduce_by];
    if (remainder.Abs() >= divisor_half) {
      result += Sign();
    }
  }
  return result;
}

bool BasicDecimal256::FitsInPrecision(int32_t precision) const {
  DCHECK_GT(precision, 0);
  DCHECK_LE(precision, 76);
  return BasicDecimal256::Abs(*this) < ScaleMultipliersDecimal256[precision];
}

const BasicDecimal256& BasicDecimal256::GetScaleMultiplier(int32_t scale) {
  DCHECK_GE(scale, 0);
  DCHECK_LE(scale, 76);

  return ScaleMultipliersDecimal256[scale];
}

const BasicDecimal256& BasicDecimal256::GetHalfScaleMultiplier(int32_t scale) {
  DCHECK_GE(scale, 0);
  DCHECK_LE(scale, 76);

  return ScaleMultipliersHalfDecimal256[scale];
}

BasicDecimal256 BasicDecimal256::GetMaxValue(int32_t precision) {
  DCHECK_GE(precision, 0);
  DCHECK_LE(precision, 76);
  return ScaleMultipliersDecimal256[precision] + (-1);
}

BasicDecimal256 operator*(const BasicDecimal256& left, const BasicDecimal256& right) {
  BasicDecimal256 result = left;
  result *= right;
  return result;
}

bool operator<(const BasicDecimal256& left, const BasicDecimal256& right) {
  const auto lhs_le = bit_util::little_endian::Make(left.native_endian_array());
  const auto rhs_le = bit_util::little_endian::Make(right.native_endian_array());
  return lhs_le[3] != rhs_le[3]
             ? static_cast<int64_t>(lhs_le[3]) < static_cast<int64_t>(rhs_le[3])
         : lhs_le[2] != rhs_le[2] ? lhs_le[2] < rhs_le[2]
         : lhs_le[1] != rhs_le[1] ? lhs_le[1] < rhs_le[1]
                                  : lhs_le[0] < rhs_le[0];
}

BasicDecimal256 operator-(const BasicDecimal256& operand) {
  BasicDecimal256 result(operand);
  return result.Negate();
}

BasicDecimal256 operator~(const BasicDecimal256& operand) {
  const std::array<uint64_t, 4>& arr = operand.native_endian_array();
  BasicDecimal256 result({~arr[0], ~arr[1], ~arr[2], ~arr[3]});
  return result;
}

BasicDecimal256& BasicDecimal256::operator/=(const BasicDecimal256& right) {
  BasicDecimal256 remainder;
  auto s = Divide(right, this, &remainder);
  DCHECK_EQ(s, DecimalStatus::kSuccess);
  return *this;
}

BasicDecimal256 operator+(const BasicDecimal256& left, const BasicDecimal256& right) {
  BasicDecimal256 sum = left;
  sum += right;
  return sum;
}

BasicDecimal256 operator/(const BasicDecimal256& left, const BasicDecimal256& right) {
  BasicDecimal256 remainder;
  BasicDecimal256 result;
  auto s = left.Divide(right, &result, &remainder);
  DCHECK_EQ(s, DecimalStatus::kSuccess);
  return result;
}

// Explicitly instantiate template base class, for DLL linking on Windows
template class GenericBasicDecimal<BasicDecimal128, 128>;
template class GenericBasicDecimal<BasicDecimal256, 256>;

}  // namespace arrow
