[ create a new paste ] login | about

Link: http://codepad.org/zpmFSND6    [ raw code | output | fork ]

Lua, pasted on Jun 8:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
-- 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 = ("\n"):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


Output:
1
6704425728000


Create a new paste based on this one


Comments: