-- This flag toggles between alternative iteration modes in the multiplication function -- Set it false to have the function add very large numbers a small number of times in each call -- Set it true to have the function add very small numbers a large number of times in each call MULT_MODE_IMPOSSIBLY_SLOW = false -- Set the lower and upper bounds of the numbers you want to multiply here. -- This will multiply 10*11*12*13*14*15*16*17*18*19*20 local limitDigits = { Lower = { 1 , 0 , }, Upper = { 2 , 0 , }, } -- Utility functions do function wipe ( table ) for k , v in pairs ( table ) do table [ k ] = nil end return table end function ValidateType ( argN , methodName , var , reqType , errLvl ) local varType = type ( var ) local isGood , foundMatch = true , false --for _, reqType in Vararg(string.split(";", reqType)) do local negate = reqType : sub ( 1 , 1 ) == " !" local reqType = negate and reqType : sub ( 2 ) or reqType --reqType = reqType:trim(" ") if reqType == " frame" and varType == " table" and type ( var [ 0 ]) == " userdata" then varType = " frame" end if negate then if varType == reqType then isGood = false -- break end else if varType == reqType then foundMatch = true end end --end if not isGood or not foundMatch then error (( " Bad argument #%s to %q. %s expected, got %s" ): format ( argN , methodName , reqType , varType ), 3 + ( errLvl or 0 )) end end do -- vararg iterator local states = {} local function getstate (...) local state = wipe ( table.remove ( states ) or {}) state . i = 0 state . l = select ( " #" , ...) for n = 1 , state . l do state [ n ] = select ( n , ...) end return state end local function iter ( state ) local i = state . i i = i + 1 if i > state . l then table.insert ( states , state ) return end state . i = i return i , state [ i ], state . l end function Vararg (...) return iter , getstate (...) end end do -- safecall --[[ xpcall safecall implementation ]] local xpcall = xpcall local function errorhandler ( err ) return geterrorhandler ()( err ) end local function CreateDispatcher ( argCount ) local code = [[ local xpcall, eh = ... local method, ARGS local function call() return method(ARGS) end local function dispatch(func, ...) method = func if not method then return end ARGS = ... return xpcall(call, eh) end return dispatch ]] local ARGS = {} for i = 1 , argCount do ARGS [ i ] = " arg" .. i end ARGS = table.concat ( ARGS , " , " ) code = code : gsub ( " ARGS" , ARGS ) return assert ( loadstring ( code , " safecall Dispatcher[" .. argCount .. " ]" ))( xpcall , errorhandler ) end local Dispatchers = setmetatable ({}, { __index = function ( self , argCount ) local dispatcher = CreateDispatcher ( argCount ) rawset ( self , argCount , dispatcher ) return dispatcher end }) Dispatchers [ 0 ] = function ( func ) return xpcall ( func , errorhandler ) end function safecall ( func , ...) -- I don't check if func is a function here because i hope that whoever calls it -- is smart enough to check when they need it so we dont need to check when we probably dont need to. -- if type(func) == "function" then return Dispatchers [ select ( ' #' , ...)]( func , ...) -- end end end do -- Class Lib ClassLib = {} ClassLib . Classes = {} local metamethods = { __add = true , __call = true , __concat = true , __div = true , __le = true , __lt = true , __mod = true , __mul = true , __pow = true , __sub = true , __tostring = true , __unm = true , } local function callFunc ( class , instance , func , ...) -- check for all functions that dont match exactly, like OnNewInstance_1, _2, _3, ... -- functions can be named whatever you want, but a numbering system helps make sure that -- they are called in the order that you want them to be called in for k , v in pairs ( class . instancemeta . __index ) do if type ( k ) == " string" and k : find ( " ^" .. func ) and k ~= func then safecall ( v , instance , ...) end end if instance . isClassInstance then -- If this is being called on an instance of a class instead of a class, -- search the instance itself for matching functions too. -- This will never step on the toes of class.instancemeta.__index because -- iterating over an instance will only yield things explicity set on an instance - -- it will never directly contain anything inherited from a class. for k , v in pairs ( instance ) do if type ( k ) == " string" and k : find ( " ^" .. func ) and k ~= func then safecall ( v , instance , ...) end end end -- now check for the function that exactly matches. this should be called last because -- it should be the function that handles the real class being instantiated, not any inherited classes local normalFunc = instance [ func ] if normalFunc then safecall ( normalFunc , instance , ...) end end local function initializeClass ( self ) if not self . instances [ 1 ] then -- set any defined metamethods for k , v in pairs ( self . instancemeta . __index ) do if metamethods [ k ] then self . instancemeta [ k ] = v end end callFunc ( self , self , " OnFirstInstance" ) end end local __call = function ( self , arg ) -- allow something like ClassLib:NewClass("Name"){Foo = function() end, Bar = 5} if type ( arg ) == " table" then for k , v in pairs ( arg ) do if k == " METHOD_EXTENSIONS" and type ( v ) == " table" then for methodName , func in pairs ( v ) do self : ExtendMethod ( methodName , func ) end else self [ k ] = v end end end return self end local inherit = function ( self , source ) if source then local metatable = getmetatable ( self ) local index , didInherit if ClassLib . Classes [ source ] then callFunc ( ClassLib . Classes [ source ], ClassLib . Classes [ source ], " OnClassInherit" , self ) index = getmetatable ( ClassLib . Classes [ source ]). __index didInherit = true elseif type ( source ) == " table" then index = source didInherit = true end if not didInherit then error (( " Could not figure out how to inherit %s into class %s. Are you sure it exists?" ): format ( source , self . className ), 3 ) end if index then for k , source in pairs ( index ) do metatable . __index [ k ] = metatable . __index [ k ] or source end end end end function ClassLib : NewClass ( className , ...) ValidateType ( 2 , " ClassLib:NewClass()" , className , " string" ) if ClassLib . Classes [ className ] then error ( " ClassLib: A class with name " .. className .. " already exists. You can't overwrite existing classes, so pick a different name" , 2 ) end local metatable = { __index = {}, __call = __call , } local class = { className = className , instances = {}, inherits = {}, inheritedBy = {}, embeds = {}, isClass = true , } class . instancemeta = { __index = metatable . __index } setmetatable ( class , metatable ) metatable . __newindex = metatable . __index for n , v in Vararg ( ClassLib . Classes . Class and " Class" , ...) do inherit ( class , v ) end ClassLib . Classes [ className ] = class return class end -- Define the base class. All other classes implicitly inherit from this class. ClassLib : NewClass ( " Class" ){ New = function ( self , ...) local instance = {} -- if this is the first instance of the class, do some magic to it: initializeClass ( self ) instance . class = self instance . className = self . className instance . isClassInstance = true setmetatable ( instance , self . instancemeta ) self . instances [ # self . instances + 1 ] = instance for k , v in pairs ( self . instancemeta . __index ) do if self . isFrameObject and instance . HasScript and instance : HasScript ( k ) then instance : HookScript ( k , v ) end end callFunc ( self , instance , " OnNewInstance" , ...) return instance end , Embed = function ( self , target , canOverwrite ) -- if this is the first instance (not really an instance here, but we need to anyway) of the class, do some magic to it: initializeClass ( self ) self . embeds [ target ] = true for k , v in pairs ( self . instancemeta . __index ) do if target [ k ] and target [ k ] ~= v and not canOverwrite then error (( " Error embedding class %s into target %s: Field %q already exists on the target." ): format ( self . className , tostring ( target : GetName () or target ), k )) else target [ k ] = v end end for k , v in pairs ( self . instancemeta . __index ) do if self . isFrameObject and target . HasScript and target : HasScript ( k ) then target : HookScript ( k , v ) end end callFunc ( self , target , " OnNewInstance" ) target . class = self target . className = self . className return target end , Disembed = function ( self , target , clearDifferentValues ) self . embeds [ target ] = false for k , v in pairs ( self . instancemeta . __index ) do if ( target [ k ] == v ) or ( target [ k ] and clearDifferentValues ) then target [ k ] = nil else error (( " Error disembedding class %s from target %s: Field %q should exist on the target, but it doesnt." ): format ( self . className , tostring ( target : GetName () or target ), k )) end end return target end , ExtendMethod = function ( self , method , newFunction ) local existingFunction = self [ method ] if existingFunction then self [ method ] = function (...) existingFunction (...) newFunction (...) end else self [ method ] = newFunction end end , AssertSelfIsClass = function ( self ) assert ( self . isClass , ( " Caller must be the class %q, not an instance of the class" ): format ( self . className )) end , AssertSelfIsInstance = function ( self ) assert ( self . isClassInstance , ( " Caller must be an instance of the class %q, not the class itself" ): format ( self . className )) end , AssertIsProtectedCall = function ( self , message ) -- debugstack can be a bit heavy on CPU usage, so use this sparingly local lineOne , lineTwo = ( "

" ): split ( debugstack ( 2 )) local func = lineOne : match ( " in function `(.*)'" ) local caller = lineTwo : match ( " in function `(.*)'" ) if not self [ caller ] then local method = self . className .. " :" .. func .. " ()" if message then message = method .. " is a protected method and can only be called by methods within its own class. " .. message else message = method .. " is a protected method and can only be called by methods within its own class." end error ( message , 3 ) end end , Inherit = function ( self , source ) self : AssertSelfIsClass () inherit ( self , source ) end , InheritTable = function ( self , sourceClass , tableKey ) ValidateType ( 2 , " Class:InheritTable()" , sourceClass , " table" ) ValidateType ( 3 , " Class:InheritTable()" , tableKey , " string" ) self [ tableKey ] = {} for k , v in pairs ( sourceClass [ tableKey ]) do self [ tableKey ][ k ] = v end -- not needed to return the table, but helpful because -- sometimes i set a variable to the result by mistake, -- and if i forget that this doesnt work then i spend a long time debugging -- trying to figure out why a single attributes table -- is shared by all icons... yeah, i did that once. return self [ tableKey ] end , CallFunc = function ( self , funcName , ...) if self . isClass then callFunc ( self , self , funcName ) else callFunc ( self . class , self , funcName , ...) end end , OnClassInherit_Class = function ( self , newClass ) for class in pairs ( self . inherits ) do newClass . inherits [ class ] = true class . inheritedBy [ newClass ] = true end newClass . inherits [ self ] = true self . inheritedBy [ newClass ] = true end , } end end Digit = ClassLib : NewClass ( " Digit" ){ SetDigit = function ( self , digit ) ValidateType ( 2 , " Digit:SetDigit(digit)" , digit , " number" ) assert ( digit < 10 , " Digit out of bounds (upper)" ) assert ( digit >= 0 , " Digit out of bounds (lower)" ) assert ( math.floor ( digit ) == digit , " Digit must be an integer" ) self . digit = digit end , GetDigit = function ( self ) return self . digit end , } MultiDigitUnsignedInt = ClassLib : NewClass ( " MultiDigitUnsignedInt" ){ OnNewInstance = function ( self ) self . digitMap = {} end , LoadDigit = function ( self , Digit ) ValidateType ( 2 , " MultiDigitUnsignedInt:LoadDigit(Digit)" , Digit , " table" ) self : SetDigitPosition ( self : GetNumDigits () + 1 , Digit ) end , LoadLargeNumber = function ( self , number ) ValidateType ( 2 , " MultiDigitUnsignedInt:LoadLargeNumber(number)" , number , " number" ) local numberAsString = tostring ( number ) for i = 1 , # numberAsString do local digit = Digit : New () digit : SetDigit ( tonumber ( numberAsString : sub ( i , i ))) self : LoadDigit ( digit ) end end , PrependDigit = function ( self , Digit ) ValidateType ( 2 , " MultiDigitUnsignedInt:SetDigitPosition(Digit)" , Digit , " table" ) assert ( Digit and Digit . isClassInstance and Digit . class . className == " Digit" , " Bad argument #2 to MultiDigitUnsignedInt:LoadDigit(Digit). Expected an instance of ClassLib.Classes.Digit" ) table.insert ( self . digitMap , 1 , Digit ) end , SetDigitPosition = function ( self , position , Digit ) ValidateType ( 2 , " MultiDigitUnsignedInt:SetDigitPosition(position, Digit)" , position , " number" ) ValidateType ( 3 , " MultiDigitUnsignedInt:SetDigitPosition(position, Digit)" , Digit , " table" ) assert ( math.floor ( position ) == position , " position must be an integer" ) assert ( Digit and Digit . isClassInstance and Digit . class . className == " Digit" , " Bad argument #3 to MultiDigitUnsignedInt:SetDigitPosition(position, Digit). Expected an instance of ClassLib.Classes.Digit" ) self . digitMap [ position ] = Digit end , GetDigitPosition = function ( self , position ) ValidateType ( 2 , " MultiDigitUnsignedInt:SetDigitPosition(position)" , position , " number" ) assert ( math.floor ( position ) == position , " position must be an integer" ) return self . digitMap [ position ] end , GetNumDigits = function ( self ) return # self . digitMap end , SerializeToNumber = function ( self ) local s = " " for i = 1 , self : GetNumDigits () do s = s .. self : GetDigitPosition ( i ): GetDigit () end return tonumber ( s ) end , __lt = function ( self1 , self2 ) if self1 : GetNumDigits () ~= self2 : GetNumDigits () then return self1 : GetNumDigits () < self2 : GetNumDigits () else for digitIndex = 1 , self1 : GetNumDigits () do if self1 : GetDigitPosition ( digitIndex ): GetDigit () ~= self2 : GetDigitPosition ( digitIndex ): GetDigit () then return self1 : GetDigitPosition ( digitIndex ): GetDigit () < self2 : GetDigitPosition ( digitIndex ): GetDigit () end end end return true end , __add = function ( self1 , arg1 ) local self2 if tonumber ( arg1 ) then self2 = MultiDigitUnsignedInt : New () self2 : LoadLargeNumber ( arg1 ) else self2 = arg1 end local result = MultiDigitUnsignedInt : New () local maxDigits = math.max ( self1 : GetNumDigits (), self2 : GetNumDigits ()) local overflow = 0 local offsetFromEnd = 0 repeat local digit1 = self1 : GetDigitPosition ( self1 : GetNumDigits () - offsetFromEnd ) local digit2 = self2 : GetDigitPosition ( self2 : GetNumDigits () - offsetFromEnd ) local newInt = ( digit1 and digit1 : GetDigit () or 0 ) + ( digit2 and digit2 : GetDigit () or 0 ) + ( overflow or 0 ) local newDigit = Digit : New () local newFinalDigit = newInt % 10 overflow = math.floor ( math.max ( 0 , newInt - newFinalDigit ) / 10 ) newDigit : SetDigit ( newFinalDigit ) result : PrependDigit ( newDigit ) offsetFromEnd = offsetFromEnd + 1 until not ( digit1 or digit2 or overflow > 0 ) while result : GetDigitPosition ( 1 ): GetDigit () == 0 do table.remove ( result . digitMap , 1 ) end return result end , __mul = function ( self1 , arg1 ) local self2 if tonumber ( arg1 ) then self2 = MultiDigitUnsignedInt : New () self2 : LoadLargeNumber ( arg1 ) else self2 = arg1 end local result = MultiDigitUnsignedInt : New () result : LoadLargeNumber ( 0 ) local num1 , num2 = self1 : SerializeToNumber (), self2 : SerializeToNumber () if MULT_MODE_IMPOSSIBLY_SLOW then for i = 1 , num1 do result = result + self2 end else for i = 1 , num2 do result = result + self1 end end return result end , } -- Main do local allNumbersToMultiply = {} -- Represent the limits as MultiDigitUnsignedInts for limitName , limits in pairs ( limitDigits ) do local multiDigitUnsignedInt = MultiDigitUnsignedInt : New () _G [ " MultiDigitUnsignedInt_" .. limitName ] = multiDigitUnsignedInt for index , digit in pairs ( limits ) do local Digit = Digit : New () Digit : SetDigit ( digit ) multiDigitUnsignedInt : LoadDigit ( Digit ) end end local currentNumber = MultiDigitUnsignedInt_Lower local lastResult = MultiDigitUnsignedInt : New () lastResult : LoadLargeNumber ( 1 ) while currentNumber < MultiDigitUnsignedInt_Upper do lastResult = lastResult * currentNumber currentNumber = currentNumber + 1 end print ( lastResult : SerializeToNumber ()) end