mirror of
https://github.com/rayaman/multi.git
synced 2026-09-05 07:27:35 -04:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
48038429d0 | ||
|
|
91090e6dea | ||
|
|
b3b9e12fb8 | ||
|
|
19de228834 | ||
|
|
1984c167d0 | ||
|
|
a1d4d59c57 | ||
|
|
5377e3131f | ||
|
|
9c74f6c265 | ||
|
|
71b56023bb | ||
|
|
3ea801a2c4 | ||
|
|
ae9f76d938 | ||
|
|
c2488ed5ce | ||
|
|
aa92282b8a | ||
|
|
689133e71f | ||
|
|
296d56d233 | ||
|
|
7dae5d5e32 | ||
|
|
29c8282efb | ||
|
|
498aa1f9aa | ||
|
|
3e795ede05 | ||
|
|
0476164cf6 | ||
|
|
564db18933 | ||
|
|
3bbd63ba62 | ||
|
|
7126e28530 | ||
|
|
11cfb390bb | ||
|
|
afee0ace94 | ||
|
|
8afef44252 | ||
|
|
31f1e10cfc | ||
|
|
98d06ee027 | ||
|
|
87d8cfbb5b | ||
|
|
050549aeef | ||
|
|
5a05cb7525 | ||
|
|
da259bc99d | ||
|
|
6714878ae9 | ||
|
|
2fad69a1ec | ||
|
|
391625674a | ||
|
|
4272397678 | ||
|
|
8f0f404c36 | ||
|
|
11cd2805c8 | ||
|
|
28a4e37c51 | ||
|
|
20647f4738 | ||
|
|
0fd604e356 | ||
|
|
03c8f364b2 | ||
|
|
41725dc01f | ||
|
|
b5bc0f8e91 | ||
|
|
110055ffc4 | ||
|
|
4040e0d9d0 | ||
|
|
0abd8183b5 | ||
|
|
9b5acbd23e | ||
|
|
040d8842a2 | ||
|
|
72dcc95400 | ||
|
|
86845f4230 | ||
|
|
dfc75fa56c | ||
|
|
358779c793 | ||
|
|
c382eb46dc | ||
|
|
4bccb655b6 | ||
|
|
515f037c0a | ||
|
|
d1f8bc9492 | ||
|
|
29cc0b8935 | ||
|
|
7eb9cd37e9 | ||
|
|
eebd942555 | ||
|
|
8db42e19f9 | ||
|
|
21aed09d6d | ||
|
|
76dbf26793 | ||
|
|
9b67727a01 | ||
|
|
31e51ce3b3 | ||
|
|
bbce42f0aa | ||
|
|
d1507219ff | ||
|
|
5e8c50082c | ||
|
|
88dbb867a7 | ||
|
|
dce6ea201e | ||
|
|
fae39b79e7 | ||
|
|
2447526a12 | ||
|
|
d4f41c5aa7 | ||
|
|
aec5a88360 | ||
|
|
fdfb3a6388 | ||
|
|
291c30a7ac | ||
|
|
c88ad2e73b | ||
|
|
cd3aae9c1e | ||
|
|
3a46c4ae44 | ||
|
|
979a6d8674 | ||
|
|
138d61de85 | ||
|
|
644044901d | ||
|
|
de2b3ee100 | ||
|
|
02cdbc3bc2 | ||
|
|
c7734a2afa | ||
|
|
3a7aea4131 | ||
|
|
9c3e66e9cc | ||
|
|
89b4901e06 | ||
|
|
a07fe49880 | ||
|
|
67499cc5ba | ||
|
|
e32720b687 | ||
|
|
509086295c | ||
|
|
6c559b0e52 | ||
|
|
03d632c3da | ||
|
|
641845a0fa | ||
|
|
181723e1c7 | ||
|
|
fc4d53a4cc | ||
|
|
285fa7e933 | ||
|
|
842274e663 | ||
|
|
6d57c7654b | ||
|
|
eaaf5d80a7 | ||
|
|
ef1cf06416 | ||
|
|
e0c72cb8ea | ||
|
|
854862f2c8 | ||
|
|
506e8eeecd | ||
|
|
f466f80513 | ||
|
|
584e8be3a2 | ||
|
|
0203d384f0 | ||
|
|
209f833b3f | ||
|
|
01b5f865f9 | ||
|
|
112e20f788 | ||
|
|
367982898a | ||
|
|
fe123f879e | ||
|
|
03c91d84e3 | ||
|
|
6863704352 | ||
|
|
8557f2d3f8 | ||
|
|
e396c18b80 | ||
|
|
d7e8231203 | ||
|
|
943afd438a | ||
|
|
6f18a129f1 | ||
|
|
dcb98ab66b | ||
|
|
a414def307 | ||
|
|
4c3c09a109 | ||
|
|
ac1dd5f79b | ||
|
|
8997c7a301 | ||
|
|
f339b7bc22 |
+14
@@ -0,0 +1,14 @@
|
|||||||
|
|
||||||
|
test2.lua
|
||||||
|
*.mp3
|
||||||
|
*.exe
|
||||||
|
lanestestclient.lua
|
||||||
|
lanestest.lua
|
||||||
|
sample-node.lua
|
||||||
|
sample-master.lua
|
||||||
|
Ayn Rand - The Virtue of Selfishness-Mg4QJheclsQ.m4a
|
||||||
|
Atlas Shrugged by Ayn Rand Audiobook-9s2qrEau63E.webm
|
||||||
|
test.lua
|
||||||
|
test.lua
|
||||||
|
*.code-workspace
|
||||||
|
*.dat
|
||||||
+1328
File diff suppressed because one or more lines are too long
+1013
File diff suppressed because it is too large
Load Diff
@@ -1,6 +1,6 @@
|
|||||||
MIT License
|
MIT License
|
||||||
|
|
||||||
Copyright (c) 2017 Ryan Ward
|
Copyright (c) 2019 Ryan Ward
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
|||||||
@@ -0,0 +1,29 @@
|
|||||||
|
C: 3322269 ~I*7
|
||||||
|
H: 2847660 ~I*6
|
||||||
|
A: 2373050 ~I*5
|
||||||
|
N: 1898440 ~I*4
|
||||||
|
B: 1423830 ~I*3
|
||||||
|
L: 949220 ~I*2
|
||||||
|
I: 474610 ~I
|
||||||
|
~n=I*PRank
|
||||||
|
|
||||||
|
P2
|
||||||
|
---------------
|
||||||
|
C: 6700821
|
||||||
|
H: 1675205
|
||||||
|
A: 418801
|
||||||
|
N: 104700
|
||||||
|
B: 26175
|
||||||
|
L: 6543
|
||||||
|
I: 1635
|
||||||
|
~n=n*4
|
||||||
|
|
||||||
|
P3
|
||||||
|
----------------
|
||||||
|
C: 2120906
|
||||||
|
H: 2120906
|
||||||
|
A: 2120906
|
||||||
|
N: 2120906
|
||||||
|
B: 2120906
|
||||||
|
L: 2120906
|
||||||
|
I: 2120506
|
||||||
+11
-1496
File diff suppressed because one or more lines are too long
+1652
File diff suppressed because one or more lines are too long
+1433
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,5 @@
|
|||||||
|
MAIN: Love2d support is updated to 11.1
|
||||||
|
|
||||||
|
May be bugs in supporting libraries, but the multitasking library is fully updated.
|
||||||
|
|
||||||
|
The GuiManager may have a bug or 2, but I haven't found any ground breaking bugs that haven't been fixed
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
package.path="?/init.lua;"..package.path
|
||||||
|
require("multi")
|
||||||
|
multi:newAlarm(5):OnRing(function()
|
||||||
|
os.exit(10)
|
||||||
|
end)
|
||||||
|
multi:mainloop()
|
||||||
Binary file not shown.
Binary file not shown.
@@ -1,32 +0,0 @@
|
|||||||
local GLOBAL,sThread=require("multi.intergration.lanesManager").init()
|
|
||||||
require("proAudioRt") -- an audio library
|
|
||||||
-- The hosting site with precompiled binaries is down, but here is a link to a archive
|
|
||||||
-- https://web.archive.org/web/20160907180559/http://viremo.eludi.net:80/proteaAudio/proteaaudiolua.html documentation and downloads are availiable... I also have saved copies just in case :D
|
|
||||||
-- Music by: myuuji
|
|
||||||
-- His youtube channel can be found here: https://www.youtube.com/channel/UCiSKnkKCKAQVxMUWpZQobuQ
|
|
||||||
proAudio.create()
|
|
||||||
multi:newThread("test",function()
|
|
||||||
-- simple playlist
|
|
||||||
sThread.waitFor("song")
|
|
||||||
print("Playing song 1!")
|
|
||||||
proAudio.soundPlay(GLOBAL["song"])
|
|
||||||
sThread.waitFor("song2")
|
|
||||||
thread.hold(function() sThread.sleep(.001) return proAudio.soundActive()==0 end)
|
|
||||||
print("Playing song 2!")
|
|
||||||
proAudio.soundPlay(GLOBAL["song2"])
|
|
||||||
sThread.waitFor("song3")
|
|
||||||
thread.hold(function() sThread.sleep(.001) return proAudio.soundActive()==0 end)
|
|
||||||
print("Playing song 3!")
|
|
||||||
proAudio.soundPlay(GLOBAL["song3"])
|
|
||||||
end)
|
|
||||||
-- loading the audio in another thread is way faster! So lets do that
|
|
||||||
multi:newSystemThread("test1",function() -- spawns a thread in another lua process
|
|
||||||
require("proAudioRt")
|
|
||||||
GLOBAL["song"]=proAudio.sampleFromFile("test.ogg",1,1)
|
|
||||||
print("Loaded song 1!")
|
|
||||||
GLOBAL["song2"]=proAudio.sampleFromFile("test2.ogg",1,1)
|
|
||||||
print("Loaded song 2!")
|
|
||||||
GLOBAL["song3"]=proAudio.sampleFromFile("test3.ogg",1,1)
|
|
||||||
print("Loaded song 3!")
|
|
||||||
end)
|
|
||||||
multi:mainloop()
|
|
||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -1,5 +1,5 @@
|
|||||||
package.path="?/init.lua;?.lua;"..package.path
|
package.path="?/init.lua;?.lua;"..package.path
|
||||||
local GLOBAL,sThread=require("multi.intergration.lanesManager").init()
|
local GLOBAL,sThread=require("multi.integration.lanesManager").init()
|
||||||
multi:newAlarm(2):OnRing(function(self)
|
multi:newAlarm(2):OnRing(function(self)
|
||||||
GLOBAL["NumOfCores"]=sThread.getCores()
|
GLOBAL["NumOfCores"]=sThread.getCores()
|
||||||
end)
|
end)
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
package.path="?/init.lua;?.lua;"..package.path
|
package.path="?/init.lua;?.lua;"..package.path
|
||||||
local GLOBAL,sThread=require("multi.intergration.lanesManager").init() -- loads the lanesManager and includes the entire multi library
|
local GLOBAL,sThread=require("multi.integration.lanesManager").init() -- loads the lanesManager and includes the entire multi library
|
||||||
local function comma_value(amount)
|
local function comma_value(amount)
|
||||||
local formatted = amount
|
local formatted = amount
|
||||||
while true do
|
while true do
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
package.path="?/init.lua;?.lua;"..package.path -- Spawing threads using 1 method and the sThread.getCores() function!
|
package.path="?/init.lua;?.lua;"..package.path -- Spawing threads using 1 method and the sThread.getCores() function!
|
||||||
local GLOBAL,sThread=require("multi.intergration.lanesManager").init() -- loads the lanesManager and includes the entire multi library
|
local GLOBAL,sThread=require("multi.integration.lanesManager").init() -- loads the lanesManager and includes the entire multi library
|
||||||
local function comma_value(amount)
|
local function comma_value(amount)
|
||||||
local formatted = amount
|
local formatted = amount
|
||||||
while true do
|
while true do
|
||||||
@@ -32,7 +32,7 @@ multi:newThread("test0",function()
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
end)
|
end)
|
||||||
GLOBAL["BENCH"]=10
|
GLOBAL["BENCH"]=1
|
||||||
print("Platform is: ",multi:getPlatform()) -- returns love2d or lanes depending on which platform you are using... If I add more intergrations then this method will be updated! corona sdk may see this library in the future...
|
print("Platform is: ",multi:getPlatform()) -- returns love2d or lanes depending on which platform you are using... If I add more intergrations then this method will be updated! corona sdk may see this library in the future...
|
||||||
multi:mainloop()
|
multi:mainloop()
|
||||||
--[[ Output on my machine! I am using luajit and have 6 cores on my computer. Your numbers will vary, but it should look something like this
|
--[[ Output on my machine! I am using luajit and have 6 cores on my computer. Your numbers will vary, but it should look something like this
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
local GLOBAL,sThread=require("multi.intergration.lanesManager").init()
|
local GLOBAL,sThread=require("multi.integration.lanesManager").init()
|
||||||
queue=multi:newSystemThreadedQueue("QUEUE"):init()
|
queue=multi:newSystemThreadedQueue("QUEUE"):init()
|
||||||
queue:push("This is a test")
|
queue:push("This is a test")
|
||||||
queue:push("This is a test2")
|
queue:push("This is a test2")
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
package.path="?/init.lua;"..package.path -- slightly different usage of the code
|
package.path="?/init.lua;"..package.path -- slightly different usage of the code
|
||||||
local GLOBAL,sThread=require("multi.intergration.lanesManager").init()
|
local GLOBAL,sThread=require("multi.integration.lanesManager").init()
|
||||||
queue=multi:newSystemThreadedQueue("QUEUE")
|
queue=multi:newSystemThreadedQueue("QUEUE")
|
||||||
queue:push(1)
|
queue:push(1)
|
||||||
queue:push(2)
|
queue:push(2)
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
-- lanes Desktop lua! NOTE: this is in lanesintergratetest6.lua in the examples folder
|
||||||
|
local GLOBAL,sThread=require("multi.integration.lanesManager").init()
|
||||||
|
test=multi:newSystemThreadedTable("YO"):init()
|
||||||
|
test["test1"]="lol"
|
||||||
|
multi:newSystemThread("test",function()
|
||||||
|
tab=sThread.waitFor("YO"):init()
|
||||||
|
print(tab["test1"])
|
||||||
|
sThread.sleep(3)
|
||||||
|
tab["test2"]="Whats so funny?"
|
||||||
|
end)
|
||||||
|
multi:newThread("test2",function()
|
||||||
|
print(test:waitFor("test2"))
|
||||||
|
end)
|
||||||
|
multi:mainloop()
|
||||||
@@ -0,0 +1,29 @@
|
|||||||
|
-- Creating the object using lanes manager to show case this. Examples has the file for love2d
|
||||||
|
local GLOBAL,sThread=require("multi.integration.lanesManager").init()
|
||||||
|
jQueue=multi:newSystemThreadedJobQueue(n) -- this internally creates System threads. By defualt it will use the # of processors on your system You can set this number though.
|
||||||
|
-- Only create 1 jobqueue! For now making more than 1 is buggy. You only really need one though. Just register new functions if you want 1 queue to do more. The one reason though is keeping track of jobIDs. I have an idea that I will roll out in the next update.
|
||||||
|
jQueue:registerJob("TEST_JOB",function(a,s)
|
||||||
|
math.randomseed(s)
|
||||||
|
-- We will push a random #
|
||||||
|
TEST_JOB2() -- You can call other registered functions as well!
|
||||||
|
return math.random(0,255) -- send the result to the main thread
|
||||||
|
end)
|
||||||
|
jQueue:registerJob("TEST_JOB2",function()
|
||||||
|
print("Test Works!") -- this is called from the job since it is registered on the same queue
|
||||||
|
end)
|
||||||
|
jQueue:start()
|
||||||
|
tableOfOrder={} -- This is how we will keep order of our completed jobs. There is no guarantee that the order will be correct
|
||||||
|
jQueue.OnJobCompleted(function(JOBID,n) -- whenever a job is completed you hook to the event that is called. This passes the JOBID folled by the returns of the job
|
||||||
|
-- JOBID is the completed job, starts at 1 and counts up by 1.
|
||||||
|
-- Threads finish at different times so jobids may be passed out of order! Be sure to have a way to order them
|
||||||
|
tableOfOrder[JOBID]=n -- we order ours by putting them into a table
|
||||||
|
if #tableOfOrder==10 then
|
||||||
|
print("We got all of the pieces!")
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
-- LEts push the jobs now
|
||||||
|
for i=1,10 do -- Job Name of registered function, ... varargs
|
||||||
|
jQueue:pushJob("TEST_JOB","This is a test!",math.random(1,1000000))
|
||||||
|
end
|
||||||
|
print("I pushed all of the jobs :)")
|
||||||
|
multi:mainloop() -- Start the main loop :D
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
package.path="../?.lua;../?/init.lua;"..package.path
|
||||||
|
local GLOBAL,sThread=require("multi.integration.lanesManager").init()
|
||||||
|
cmd=multi:newSystemThreadedExecute("SystemThreadedExecuteTest.lua") -- This file is important!
|
||||||
|
cmd.OnCMDFinished(function(code) -- callback function to grab the exit code... Called when the command goes through
|
||||||
|
print("Got Code: "..code)
|
||||||
|
end)
|
||||||
|
multi:newTLoop(function()
|
||||||
|
print("...")
|
||||||
|
end,1)
|
||||||
|
multi:mainloop()
|
||||||
|
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
--~ package.path="?/init.lua;"..package.path
|
||||||
|
local GLOBAL,sThread=require("multi.integration.lanesManager").init()
|
||||||
|
jQueue=multi:newSystemThreadedJobQueue(n)
|
||||||
|
jQueue:registerJob("TEST_JOB",function(a,s)
|
||||||
|
math.randomseed(s)
|
||||||
|
TEST_JOB2()
|
||||||
|
return math.random(0,255)
|
||||||
|
end)
|
||||||
|
jQueue:registerJob("TEST_JOB2",function()
|
||||||
|
print("Test Works!")
|
||||||
|
end)
|
||||||
|
jQueue:start()
|
||||||
|
jQueue.OnReady:holdUT()
|
||||||
|
jQueue:doToAll(function()
|
||||||
|
print("Doing this 16? times!")
|
||||||
|
end)
|
||||||
|
for i=1,10 do -- Job Name of registered function, ... varargs
|
||||||
|
jQueue:pushJob("TEST_JOB","This is a test!",math.random(1,1000000))
|
||||||
|
end
|
||||||
|
tableOfOrder={}
|
||||||
|
jQueue.OnJobCompleted(function(JOBID,n)
|
||||||
|
tableOfOrder[JOBID]=n
|
||||||
|
if #tableOfOrder==10 then
|
||||||
|
print("We got all of the pieces!")
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
multi:mainloop()
|
||||||
@@ -1,5 +1,19 @@
|
|||||||
|
local function HSL(h, s, l, a)
|
||||||
|
if s<=0 then return l,l,l,a end
|
||||||
|
h, s, l = h/256*6, s/255, l/255
|
||||||
|
local c = (1-math.abs(2*l-1))*s
|
||||||
|
local x = (1-math.abs(h%2-1))*c
|
||||||
|
local m,r,b,g = (l-.5*c), 0,0,0
|
||||||
|
if h < 1 then r,b,g = c,x,0
|
||||||
|
elseif h < 2 then r,b,g = x,c,0
|
||||||
|
elseif h < 3 then r,b,g = 0,c,x
|
||||||
|
elseif h < 4 then r,b,g = 0,x,c
|
||||||
|
elseif h < 5 then r,b,g = x,0,c
|
||||||
|
else r,b,g = c,0,x
|
||||||
|
end return (r+m)*255,(g+m)*255,(b+m)*255,a
|
||||||
|
end
|
||||||
Color={
|
Color={
|
||||||
new=function(r,g,b)
|
new=function(r,b,g)
|
||||||
mt = {
|
mt = {
|
||||||
__add = function (c1,c2)
|
__add = function (c1,c2)
|
||||||
return Color.new(c1[1]+c2[1],c1[2]+c2[2],c1[2]+c2[2])
|
return Color.new(c1[1]+c2[1],c1[2]+c2[2],c1[2]+c2[2])
|
||||||
@@ -29,7 +43,7 @@ new=function(r,g,b)
|
|||||||
__lt = Color.LT,
|
__lt = Color.LT,
|
||||||
__le = Color.LE,
|
__le = Color.LE,
|
||||||
}
|
}
|
||||||
local temp = {r,g,b,255}
|
local temp = {r/255,b/255,g/255,1}
|
||||||
setmetatable(temp, mt)
|
setmetatable(temp, mt)
|
||||||
return temp
|
return temp
|
||||||
end,
|
end,
|
||||||
@@ -57,14 +71,13 @@ Darken=function(color,v)
|
|||||||
currentR=color[1]
|
currentR=color[1]
|
||||||
currentG=color[2]
|
currentG=color[2]
|
||||||
currentB=color[3]
|
currentB=color[3]
|
||||||
return Color.new(currentR * (1 - v),currentG * (1 - v),currentB * (1 - v))
|
return Color.new((currentR*255) * (1 - v),(currentG*255) * (1 - v),(currentB*255) * (1 - v))
|
||||||
end,
|
end,
|
||||||
Lighten=function(color,v)
|
Lighten=function(color,v)
|
||||||
currentR=color[1]
|
currentR=color[1]
|
||||||
currentG=color[2]
|
currentG=color[2]
|
||||||
currentB=color[3]
|
currentB=color[3]
|
||||||
|
return Color.new(currentR*255 + (255 - (currentR*255)) * v,currentG*255 + (255 - (currentG*255)) * v,currentB*255 + (255 - (currentB*255)) * v)
|
||||||
return Color.new(currentR + (255 - currentR) * v,currentG + (255 - currentG) * v,currentB + (255 - currentB) * v)
|
|
||||||
end
|
end
|
||||||
}
|
}
|
||||||
Color.IndexColor("Black",20,20,20)
|
Color.IndexColor("Black",20,20,20)
|
||||||
|
|||||||
@@ -42,7 +42,6 @@ function gui:newBase(tp,name, x, y, w, h, sx ,sy ,sw ,sh)
|
|||||||
c:SetName(name)
|
c:SetName(name)
|
||||||
c.BorderSize=1
|
c.BorderSize=1
|
||||||
c.BorderColor={0,0,0}
|
c.BorderColor={0,0,0}
|
||||||
c.BorderVisibility=1
|
|
||||||
c.VIS=true
|
c.VIS=true
|
||||||
c.Visible=true
|
c.Visible=true
|
||||||
c.oV=true
|
c.oV=true
|
||||||
@@ -178,6 +177,13 @@ function gui:newBase(tp,name, x, y, w, h, sx ,sy ,sw ,sh)
|
|||||||
_GuiPro.self=self
|
_GuiPro.self=self
|
||||||
if type(i)=="number" then
|
if type(i)=="number" then
|
||||||
loadstring("_GuiPro.self:"..v)()
|
loadstring("_GuiPro.self:"..v)()
|
||||||
|
elseif i:match"__self__" then
|
||||||
|
local ind=i:match"__self__(.+)"
|
||||||
|
if not self[ind] then self[ind]={} end
|
||||||
|
loadstring("_GuiPro.self."..ind.."=_GuiPro.self:"..v)()
|
||||||
|
elseif i:match"__child__" then
|
||||||
|
local ind,child = i:match"__child__(%S-)_(.+)"
|
||||||
|
self[ind][child]=v
|
||||||
else
|
else
|
||||||
self[i]=v
|
self[i]=v
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -0,0 +1,40 @@
|
|||||||
|
function gui:toString() -- oh boy this is gonna be painful lol
|
||||||
|
multi:newThread("saving data: ",function()
|
||||||
|
local dat=bin.stream("test.dat",false)
|
||||||
|
function GetAllChildren2(Object)
|
||||||
|
local Stuff = {}
|
||||||
|
function Seek(Items)
|
||||||
|
for i=1,#Items do
|
||||||
|
--table.insert(Stuff,Items[i])
|
||||||
|
for a,v in pairs(Items[i]) do
|
||||||
|
-- dat:tackE(a.."|"..tostring(v))
|
||||||
|
print(a.."|"..tostring(v))
|
||||||
|
-- dat.workingfile:flush()
|
||||||
|
end
|
||||||
|
thread.skip()
|
||||||
|
local NItems = Items[i]:getChildren()
|
||||||
|
if NItems ~= nil then
|
||||||
|
Seek(NItems)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
local Objs = Object:getChildren()
|
||||||
|
for i=1,#Objs do
|
||||||
|
-- table.insert(Stuff,Objs[i])
|
||||||
|
for a,v in pairs(Objs[i]) do
|
||||||
|
-- dat:tackE(a.."|"..tostring(v))
|
||||||
|
print(Objs[i].Type..":"..a.."|"..tostring(v))
|
||||||
|
-- dat.workingfile:flush()
|
||||||
|
end
|
||||||
|
thread.skip()
|
||||||
|
local Items = Objs[i]:getChildren()
|
||||||
|
if Items ~= nil then
|
||||||
|
Seek(Items)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
-- dat:tofile("test.dat")
|
||||||
|
return Stuff
|
||||||
|
end
|
||||||
|
GetAllChildren2(self)
|
||||||
|
end)
|
||||||
|
end
|
||||||
@@ -27,37 +27,37 @@ function gui:drawC()
|
|||||||
self.hovering=true
|
self.hovering=true
|
||||||
if love.mouse.isDown("l") and _GuiPro.hasDrag==false then
|
if love.mouse.isDown("l") and _GuiPro.hasDrag==false then
|
||||||
if string.find(self.Type, "Button") then
|
if string.find(self.Type, "Button") then
|
||||||
love.graphics.setColor(self.Color[1]-10, self.Color[2]-10, self.Color[3]-10,self.Visibility*254)
|
love.graphics.setColor(self.Color[1]-10, self.Color[2]-10, self.Color[3]-10,self.Visibility)
|
||||||
else
|
else
|
||||||
love.graphics.setColor(self.Color[1],self.Color[2],self.Color[3],self.Visibility*254)
|
love.graphics.setColor(self.Color[1],self.Color[2],self.Color[3],self.Visibility)
|
||||||
end
|
end
|
||||||
self.lclicked=true
|
self.lclicked=true
|
||||||
elseif love.mouse.isDown("r") and _GuiPro.hasDrag==false then
|
elseif love.mouse.isDown("r") and _GuiPro.hasDrag==false then
|
||||||
if string.find(self.Type, "Button") then
|
if string.find(self.Type, "Button") then
|
||||||
love.graphics.setColor(self.Color[1]-10, self.Color[2]-10, self.Color[3]-10,self.Visibility*254)
|
love.graphics.setColor(self.Color[1]-10, self.Color[2]-10, self.Color[3]-10,self.Visibility)
|
||||||
else
|
else
|
||||||
love.graphics.setColor(self.Color[1],self.Color[2],self.Color[3],self.Visibility*254)
|
love.graphics.setColor(self.Color[1],self.Color[2],self.Color[3],self.Visibility)
|
||||||
end
|
end
|
||||||
self.rclicked=true
|
self.rclicked=true
|
||||||
elseif love.mouse.isDown("m") and _GuiPro.hasDrag==false then
|
elseif love.mouse.isDown("m") and _GuiPro.hasDrag==false then
|
||||||
if string.find(self.Type, "Button") then
|
if string.find(self.Type, "Button") then
|
||||||
love.graphics.setColor(self.Color[1]-10, self.Color[2]-10, self.Color[3]-10,self.Visibility*254)
|
love.graphics.setColor(self.Color[1]-10, self.Color[2]-10, self.Color[3]-10,self.Visibility)
|
||||||
else
|
else
|
||||||
love.graphics.setColor(self.Color[1],self.Color[2],self.Color[3],self.Visibility*254)
|
love.graphics.setColor(self.Color[1],self.Color[2],self.Color[3],self.Visibility)
|
||||||
end
|
end
|
||||||
self.mclicked=true
|
self.mclicked=true
|
||||||
else
|
else
|
||||||
if string.find(self.Type, "Button") and _GuiPro.hasDrag==false then
|
if string.find(self.Type, "Button") and _GuiPro.hasDrag==false then
|
||||||
love.graphics.setColor(self.Color[1]-5, self.Color[2]-5, self.Color[3]-5,self.Visibility*254)
|
love.graphics.setColor(self.Color[1]-5, self.Color[2]-5, self.Color[3]-5,self.Visibility)
|
||||||
else
|
else
|
||||||
love.graphics.setColor(self.Color[1],self.Color[2],self.Color[3],self.Visibility*254)
|
love.graphics.setColor(self.Color[1],self.Color[2],self.Color[3],self.Visibility)
|
||||||
end
|
end
|
||||||
self.rclicked=false
|
self.rclicked=false
|
||||||
self.lclicked=false
|
self.lclicked=false
|
||||||
self.mclicked=false
|
self.mclicked=false
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
love.graphics.setColor(self.Color[1],self.Color[2],self.Color[3],self.Visibility*254)
|
love.graphics.setColor(self.Color[1],self.Color[2],self.Color[3],self.Visibility)
|
||||||
self.hovering=false
|
self.hovering=false
|
||||||
self.rclicked=false
|
self.rclicked=false
|
||||||
self.lclicked=false
|
self.lclicked=false
|
||||||
@@ -71,7 +71,7 @@ function gui:drawC()
|
|||||||
love.graphics.setStencilTest("notequal",0)
|
love.graphics.setStencilTest("notequal",0)
|
||||||
end
|
end
|
||||||
love.graphics.circle("fill",x,y,r,s)
|
love.graphics.circle("fill",x,y,r,s)
|
||||||
love.graphics.setColor(self.BorderColor[1], self.BorderColor[2], self.BorderColor[3],self.BorderVisibility*254)
|
love.graphics.setColor(self.BorderColor[1], self.BorderColor[2], self.BorderColor[3],self.Visibility)
|
||||||
for b=0,self.BorderSize-1 do
|
for b=0,self.BorderSize-1 do
|
||||||
love.graphics.circle("line",x,y,r+b,s)
|
love.graphics.circle("line",x,y,r+b,s)
|
||||||
end
|
end
|
||||||
@@ -80,7 +80,7 @@ function gui:drawC()
|
|||||||
if self.AutoScaleText then
|
if self.AutoScaleText then
|
||||||
self.FontSize=math.floor(self.height/1.45833)
|
self.FontSize=math.floor(self.height/1.45833)
|
||||||
end
|
end
|
||||||
love.graphics.setColor(self.TextColor[1],self.TextColor[2],self.TextColor[3],self.TextVisibility*254)
|
love.graphics.setColor(self.TextColor[1],self.TextColor[2],self.TextColor[3],self.TextVisibility)
|
||||||
love.graphics.setFont(self.Font)
|
love.graphics.setFont(self.Font)
|
||||||
love.graphics.printf(self.text, x-(r/2)+(self.XTween), y-(r/2)+self.Tween, r, self.TextFormat)
|
love.graphics.printf(self.text, x-(r/2)+(self.XTween), y-(r/2)+self.Tween, r, self.TextFormat)
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -27,37 +27,37 @@ function gui:drawR()
|
|||||||
self.hovering=true
|
self.hovering=true
|
||||||
if love.mouse.isDown("l") or self:touchable("r") and _GuiPro.hasDrag==false then
|
if love.mouse.isDown("l") or self:touchable("r") and _GuiPro.hasDrag==false then
|
||||||
if string.find(self.Type, "Button") then
|
if string.find(self.Type, "Button") then
|
||||||
love.graphics.setColor(self.Color[1]-10, self.Color[2]-10, self.Color[3]-10,self.Visibility*254)
|
love.graphics.setColor(self.Color[1]-10, self.Color[2]-10, self.Color[3]-10,self.Visibility)
|
||||||
else
|
else
|
||||||
love.graphics.setColor(self.Color[1],self.Color[2],self.Color[3],self.Visibility*254)
|
love.graphics.setColor(self.Color[1],self.Color[2],self.Color[3],self.Visibility)
|
||||||
end
|
end
|
||||||
self.lclicked=true
|
self.lclicked=true
|
||||||
elseif love.mouse.isDown("r") or self:touchable("r") and _GuiPro.hasDrag==false then
|
elseif love.mouse.isDown("r") or self:touchable("r") and _GuiPro.hasDrag==false then
|
||||||
if string.find(self.Type, "Button") then
|
if string.find(self.Type, "Button") then
|
||||||
love.graphics.setColor(self.Color[1]-10, self.Color[2]-10, self.Color[3]-10,self.Visibility*254)
|
love.graphics.setColor(self.Color[1]-10, self.Color[2]-10, self.Color[3]-10,self.Visibility)
|
||||||
else
|
else
|
||||||
love.graphics.setColor(self.Color[1],self.Color[2],self.Color[3],self.Visibility*254)
|
love.graphics.setColor(self.Color[1],self.Color[2],self.Color[3],self.Visibility)
|
||||||
end
|
end
|
||||||
self.rclicked=true
|
self.rclicked=true
|
||||||
elseif love.mouse.isDown("m") or self:touchable("r") and _GuiPro.hasDrag==false then
|
elseif love.mouse.isDown("m") or self:touchable("r") and _GuiPro.hasDrag==false then
|
||||||
if string.find(self.Type, "Button") then
|
if string.find(self.Type, "Button") then
|
||||||
love.graphics.setColor(self.Color[1]-10, self.Color[2]-10, self.Color[3]-10,self.Visibility*254)
|
love.graphics.setColor(self.Color[1]-10, self.Color[2]-10, self.Color[3]-10,self.Visibility)
|
||||||
else
|
else
|
||||||
love.graphics.setColor(self.Color[1],self.Color[2],self.Color[3],self.Visibility*254)
|
love.graphics.setColor(self.Color[1],self.Color[2],self.Color[3],self.Visibility)
|
||||||
end
|
end
|
||||||
self.mclicked=true
|
self.mclicked=true
|
||||||
else
|
else
|
||||||
if string.find(self.Type, "Button") or self:touchable("r") and _GuiPro.hasDrag==false then
|
if string.find(self.Type, "Button") or self:touchable("r") and _GuiPro.hasDrag==false then
|
||||||
love.graphics.setColor(self.Color[1]-5, self.Color[2]-5, self.Color[3]-5,self.Visibility*254)
|
love.graphics.setColor(self.Color[1]-5, self.Color[2]-5, self.Color[3]-5,self.Visibility)
|
||||||
else
|
else
|
||||||
love.graphics.setColor(self.Color[1],self.Color[2],self.Color[3],self.Visibility*254)
|
love.graphics.setColor(self.Color[1],self.Color[2],self.Color[3],self.Visibility)
|
||||||
end
|
end
|
||||||
self.rclicked=false
|
self.rclicked=false
|
||||||
self.lclicked=false
|
self.lclicked=false
|
||||||
self.mclicked=false
|
self.mclicked=false
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
love.graphics.setColor(self.Color[1],self.Color[2],self.Color[3],self.Visibility*254)
|
love.graphics.setColor(self.Color[1],self.Color[2],self.Color[3],self.Visibility)
|
||||||
self.hovering=false
|
self.hovering=false
|
||||||
self.rclicked=false
|
self.rclicked=false
|
||||||
self.lclicked=false
|
self.lclicked=false
|
||||||
@@ -71,6 +71,7 @@ function gui:drawR()
|
|||||||
love.graphics.stencil(self.stfunc, "replace", 1)
|
love.graphics.stencil(self.stfunc, "replace", 1)
|
||||||
love.graphics.setStencilTest("greater", 0)
|
love.graphics.setStencilTest("greater", 0)
|
||||||
end
|
end
|
||||||
|
|
||||||
love.graphics.rectangle("fill", self.x, self.y, self.width, self.height,(self.rx or 1)*self.DPI,(self.ry or 1)*self.DPI,(self.segments or 1)*self.DPI)
|
love.graphics.rectangle("fill", self.x, self.y, self.width, self.height,(self.rx or 1)*self.DPI,(self.ry or 1)*self.DPI,(self.segments or 1)*self.DPI)
|
||||||
if string.find(self.Type, "Image") then
|
if string.find(self.Type, "Image") then
|
||||||
self:ImageRule()
|
self:ImageRule()
|
||||||
@@ -81,7 +82,7 @@ function gui:drawR()
|
|||||||
if self:hasRoundness() then
|
if self:hasRoundness() then
|
||||||
love.graphics.setStencilTest()
|
love.graphics.setStencilTest()
|
||||||
end
|
end
|
||||||
love.graphics.setColor(self.BorderColor[1], self.BorderColor[2], self.BorderColor[3],self.BorderVisibility*254)
|
love.graphics.setColor(self.BorderColor[1], self.BorderColor[2], self.BorderColor[3],self.Visibility)
|
||||||
for b=0,self.BorderSize-1 do
|
for b=0,self.BorderSize-1 do
|
||||||
love.graphics.rectangle("line", self.x-(b/2), self.y-(b/2), self.width+b, self.height+b,(self.rx or 1)*self.DPI,(self.ry or 1)*self.DPI,(self.segments or 1)*self.DPI)
|
love.graphics.rectangle("line", self.x-(b/2), self.y-(b/2), self.width+b, self.height+b,(self.rx or 1)*self.DPI,(self.ry or 1)*self.DPI,(self.segments or 1)*self.DPI)
|
||||||
end
|
end
|
||||||
@@ -90,10 +91,16 @@ function gui:drawR()
|
|||||||
if self.AutoScaleText then
|
if self.AutoScaleText then
|
||||||
self.FontSize=math.floor(self.height/1.45833)
|
self.FontSize=math.floor(self.height/1.45833)
|
||||||
end
|
end
|
||||||
love.graphics.setColor(self.TextColor[1],self.TextColor[2],self.TextColor[3],self.TextVisibility*254)
|
love.graphics.setColor(self.TextColor[1],self.TextColor[2],self.TextColor[3],self.TextVisibility)
|
||||||
if self.Font==_defaultfont then
|
if self.Font==_defaultfont then
|
||||||
love.graphics.setFont(self.Font)
|
love.graphics.setFont(self.Font)
|
||||||
love.graphics.printf(self.text, self.x+2+(self.XTween*self.DPI)+((self.marginL or 0)*self.DPI or self.XTween*self.DPI), self.y+(self.FontHeight/2)+self.Tween*self.DPI, self.width+(0 or (self.marginR or 0)*self.DPI), self.TextFormat)
|
love.graphics.printf(
|
||||||
|
self.text,
|
||||||
|
(self.x+2+(self.marginL or 0) or self.XTween)*self.DPI,
|
||||||
|
(self.y+math.floor((self.FontHeight-self.FontSize)/2)+self.Tween)*self.DPI,
|
||||||
|
(self.width+(0 or (self.marginR or 0)))*self.DPI,
|
||||||
|
self.TextFormat,
|
||||||
|
self.TextRotation)
|
||||||
else
|
else
|
||||||
if type(self.Font)=="string" then
|
if type(self.Font)=="string" then
|
||||||
self.Font=love.graphics.newFont(self.Font,self.FontSize)
|
self.Font=love.graphics.newFont(self.Font,self.FontSize)
|
||||||
@@ -105,7 +112,13 @@ function gui:drawR()
|
|||||||
self.FontSize=tonumber(self.FontSize)
|
self.FontSize=tonumber(self.FontSize)
|
||||||
love.graphics.setNewFont(self.FontSize)
|
love.graphics.setNewFont(self.FontSize)
|
||||||
end
|
end
|
||||||
love.graphics.printf(self.text, self.x+2+((self.marginL or 0)*self.DPI or self.XTween*self.DPI), self.y+math.floor((self.FontHeight-self.FontSize)/2)+self.Tween*self.DPI, self.width+(0 or (self.marginR or 0)*self.DPI), self.TextFormat)
|
love.graphics.printf(
|
||||||
|
self.text,
|
||||||
|
(self.x+2+(self.marginL or 0) or self.XTween)*self.DPI,
|
||||||
|
(self.y+math.floor((self.FontHeight-self.FontSize)/2)+self.Tween)*self.DPI,
|
||||||
|
(self.width+(0 or (self.marginR or 0)))*self.DPI,
|
||||||
|
self.TextFormat,
|
||||||
|
self.TextRotation)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
function gui:SetImage(i)
|
function gui:SetImage(i)
|
||||||
if type(i)=="string" then
|
if type(i)=="string" or tostring(i):find("ImageData") then
|
||||||
self.Image=love.graphics.newImage(i)
|
self.Image=love.graphics.newImage(i)
|
||||||
else
|
else
|
||||||
self.Image=i
|
self.Image=i
|
||||||
end
|
end
|
||||||
if self.Image~=nil then
|
if self.Image then
|
||||||
self.ImageHeigth=self.Image:getHeight()
|
self.ImageHeigth=self.Image:getHeight()
|
||||||
self.ImageWidth=self.Image:getWidth()
|
self.ImageWidth=self.Image:getWidth()
|
||||||
self.Quad=love.graphics.newQuad(0,0,self.width,self.height,self.ImageWidth,self.ImageHeigth)
|
self.Quad=love.graphics.newQuad(0,0,self.width,self.height,self.ImageWidth,self.ImageHeigth)
|
||||||
|
|||||||
+1
-1
@@ -1,7 +1,7 @@
|
|||||||
function gui:newImageButton(i,name, x, y, w, h, sx ,sy ,sw ,sh)
|
function gui:newImageButton(i,name, x, y, w, h, sx ,sy ,sw ,sh)
|
||||||
x,y,w,h,sx,sy,sw,sh=filter(name, x, y, w, h, sx ,sy ,sw ,sh)
|
x,y,w,h,sx,sy,sw,sh=filter(name, x, y, w, h, sx ,sy ,sw ,sh)
|
||||||
local c=self:newBase("ImageButton",name, x, y, w, h, sx ,sy ,sw ,sh)
|
local c=self:newBase("ImageButton",name, x, y, w, h, sx ,sy ,sw ,sh)
|
||||||
if type(i)=="string" then
|
if type(i)=="string" or type(i):find("ImageData") then
|
||||||
c.Image=love.graphics.newImage(i)
|
c.Image=love.graphics.newImage(i)
|
||||||
else
|
else
|
||||||
c.Image=i
|
c.Image=i
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
function gui:newImageLabel(i,name, x, y, w, h, sx ,sy ,sw ,sh)
|
function gui:newImageLabel(i,name, x, y, w, h, sx ,sy ,sw ,sh)
|
||||||
x,y,w,h,sx,sy,sw,sh=filter(name, x, y, w, h, sx ,sy ,sw ,sh)
|
x,y,w,h,sx,sy,sw,sh=filter(name, x, y, w, h, sx ,sy ,sw ,sh)
|
||||||
local c=self:newBase("ImageLabel",name, x, y, w, h, sx ,sy ,sw ,sh)
|
local c=self:newBase("ImageLabel",name, x, y, w, h, sx ,sy ,sw ,sh)
|
||||||
if type(i)=="string" then
|
if type(i)=="string" or type(i):find("ImageData") then
|
||||||
c.Image=love.graphics.newImage(i)
|
c.Image=love.graphics.newImage(i)
|
||||||
else
|
else
|
||||||
c.Image=i
|
c.Image=i
|
||||||
@@ -9,7 +9,7 @@ function gui:newImageLabel(i,name, x, y, w, h, sx ,sy ,sw ,sh)
|
|||||||
c.Visibility=0
|
c.Visibility=0
|
||||||
c.ImageVisibility=1
|
c.ImageVisibility=1
|
||||||
c.rotation=0
|
c.rotation=0
|
||||||
if c.Image~=nil then
|
if c.Image then
|
||||||
c.ImageHeigth=c.Image:getHeight()
|
c.ImageHeigth=c.Image:getHeight()
|
||||||
c.ImageWidth=c.Image:getWidth()
|
c.ImageWidth=c.Image:getWidth()
|
||||||
c.Quad=love.graphics.newQuad(0,0,w,h,c.ImageWidth,c.ImageHeigth)
|
c.Quad=love.graphics.newQuad(0,0,w,h,c.ImageWidth,c.ImageHeigth)
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
function _GuiPro.gradient(colors)
|
function _GuiPro.gradient(colors)
|
||||||
local direction = colors.direction or "horizontal"
|
local direction = colors.direction or "horizontal"
|
||||||
colors.direction=nil
|
colors.direction=nil
|
||||||
trans = colors.trans or 255
|
trans = colors.trans or 1
|
||||||
trans=math.floor(trans)
|
trans=math.floor(trans)
|
||||||
if direction == "horizontal" then
|
if direction == "horizontal" then
|
||||||
direction = true
|
direction = true
|
||||||
@@ -10,7 +10,7 @@ function _GuiPro.gradient(colors)
|
|||||||
else
|
else
|
||||||
error("Invalid direction '" .. tostring(direction) "' for gradient. Horizontal or vertical expected.")
|
error("Invalid direction '" .. tostring(direction) "' for gradient. Horizontal or vertical expected.")
|
||||||
end
|
end
|
||||||
local result = love.image.newImageData(direction and 1 or #colors, direction and #colors or 1)
|
local result = love.image.newImageData(direction and 1 or #colors, direction and #colors or 1,"rgba32f")
|
||||||
for __i, color in ipairs(colors) do
|
for __i, color in ipairs(colors) do
|
||||||
local x, y
|
local x, y
|
||||||
if direction then
|
if direction then
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
function gui:Center()
|
function gui:center()
|
||||||
local x,y=self:getFullSize()
|
self:centerX()
|
||||||
self:SetDualDim(-math.floor(x/2),-math.floor(y/2),nil,nil,.5,.5)
|
self:centerY()
|
||||||
end
|
end
|
||||||
@@ -6,4 +6,5 @@ function gui:Destroy()
|
|||||||
table.remove(self.Parent.Children,cc)
|
table.remove(self.Parent.Children,cc)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
self.Destroyed = true
|
||||||
end
|
end
|
||||||
@@ -2,9 +2,9 @@ function gui:getFullSize()
|
|||||||
local maxx,maxy=-math.huge,-math.huge
|
local maxx,maxy=-math.huge,-math.huge
|
||||||
local temp = self:GetAllChildren()
|
local temp = self:GetAllChildren()
|
||||||
for i=1,#temp do
|
for i=1,#temp do
|
||||||
if temp[i].width>maxx then
|
if temp[i].width+temp[i].offset.pos.x>maxx then
|
||||||
maxx=temp[i].width+temp[i].offset.pos.x
|
maxx=temp[i].width+temp[i].offset.pos.x
|
||||||
elseif temp[i].height>maxy then
|
elseif temp[i].height+temp[i].offset.pos.y>maxy then
|
||||||
maxy=temp[i].height+temp[i].offset.pos.y
|
maxy=temp[i].height+temp[i].offset.pos.y
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
if love.filesystem.exists("CheckBoxes.png") then
|
if love.filesystem.getInfo("CheckBoxes.png") then
|
||||||
_GuiPro.UC=gui:getTile("CheckBoxes.png",0,0,16,16)
|
_GuiPro.UC=gui:getTile("CheckBoxes.png",0,0,16,16)
|
||||||
_GuiPro.C=gui:getTile("CheckBoxes.png",16,0,16,16)
|
_GuiPro.C=gui:getTile("CheckBoxes.png",16,0,16,16)
|
||||||
_GuiPro.UCH=gui:getTile("CheckBoxes.png",0,16,16,16)
|
_GuiPro.UCH=gui:getTile("CheckBoxes.png",0,16,16,16)
|
||||||
|
|||||||
@@ -1,3 +1,7 @@
|
|||||||
function gui:setNewFont(FontSize)
|
function gui:setNewFont(FontSize,filename)
|
||||||
|
if filename then
|
||||||
|
self.Font = love.graphics.newFont(filename, tonumber(FontSize))
|
||||||
|
else
|
||||||
self.Font=love.graphics.setNewFont(tonumber(FontSize))
|
self.Font=love.graphics.setNewFont(tonumber(FontSize))
|
||||||
end
|
end
|
||||||
|
end
|
||||||
@@ -28,7 +28,7 @@ function gui:newTextBox(t,name, x, y, w, h, sx ,sy ,sw ,sh)
|
|||||||
c.mark=nil
|
c.mark=nil
|
||||||
c.arrowkeys=false
|
c.arrowkeys=false
|
||||||
c.funcF={function()
|
c.funcF={function()
|
||||||
love.keyboard.setTextInput(true)
|
love.keyboard.setTextInput(true,0,200,400,200)
|
||||||
end}
|
end}
|
||||||
c.cooldown=false
|
c.cooldown=false
|
||||||
c.cooldown2=false
|
c.cooldown2=false
|
||||||
@@ -59,6 +59,9 @@ function gui:newTextBox(t,name, x, y, w, h, sx ,sy ,sw ,sh)
|
|||||||
table.insert(self.funcE,func)
|
table.insert(self.funcE,func)
|
||||||
end
|
end
|
||||||
c:OnClicked(function(b,self)
|
c:OnClicked(function(b,self)
|
||||||
|
self:focus()
|
||||||
|
end)
|
||||||
|
function c:focus()
|
||||||
for cc=1,#self.funcF do
|
for cc=1,#self.funcF do
|
||||||
self.funcF[cc](self)
|
self.funcF[cc](self)
|
||||||
end
|
end
|
||||||
@@ -74,7 +77,7 @@ function gui:newTextBox(t,name, x, y, w, h, sx ,sy ,sw ,sh)
|
|||||||
end
|
end
|
||||||
self.Active=true
|
self.Active=true
|
||||||
end
|
end
|
||||||
end)
|
end
|
||||||
c:OnClicked(function(b,self,x,y)
|
c:OnClicked(function(b,self,x,y)
|
||||||
local dwidth, wrappedtext = _defaultfont:getWrap(self.text:sub(1,self.cursor[1]), self.width)
|
local dwidth, wrappedtext = _defaultfont:getWrap(self.text:sub(1,self.cursor[1]), self.width)
|
||||||
local height = _defaultfont:getHeight()
|
local height = _defaultfont:getHeight()
|
||||||
@@ -144,7 +147,7 @@ function gui:newTextBox(t,name, x, y, w, h, sx ,sy ,sw ,sh)
|
|||||||
self.ttext=self.ttext.."\n"
|
self.ttext=self.ttext.."\n"
|
||||||
self.cooldown2=true
|
self.cooldown2=true
|
||||||
c.Alarm2:Reset()
|
c.Alarm2:Reset()
|
||||||
elseif (love.keyboard.isDown("return") or love.keyboard.isDown("enter") or love.keyboard.isDown("kpenter")) and self.Active and self.Enter and not(love.keyboard.isDown("lshift") or love.keyboard.isDown("rshift")) then
|
elseif (love.keyboard.isDown("return") or love.keyboard.isDown("kpenter")) and self.Active and self.Enter and not(love.keyboard.isDown("lshift") or love.keyboard.isDown("rshift")) then
|
||||||
if self.LoseFocusOnEnter then
|
if self.LoseFocusOnEnter then
|
||||||
self.Active=false
|
self.Active=false
|
||||||
else
|
else
|
||||||
|
|||||||
@@ -0,0 +1,5 @@
|
|||||||
|
function gui:widthToTextSize(n)
|
||||||
|
if self.Font then
|
||||||
|
self:setDualDim(nil,nil,self.Font:getWidth(self.text)+(n or 4),nil,nil,nil,0)
|
||||||
|
end
|
||||||
|
end
|
||||||
@@ -1,5 +1,4 @@
|
|||||||
utf8 = require("utf8")
|
utf8 = require("utf8")
|
||||||
_defaultfont = love.graphics.getFont()
|
|
||||||
gui = {}
|
gui = {}
|
||||||
gui.__index = gui
|
gui.__index = gui
|
||||||
gui.TB={}
|
gui.TB={}
|
||||||
@@ -7,14 +6,15 @@ gui.Version="VERSION" -- Is it really ready for release?
|
|||||||
_GuiPro={GBoost=true,hasDrag=false,DragItem={},Children={},Visible=true,count=0,x=0,y=0,height=0,width=0,update=function(self) local things=GetAllChildren2(self) UpdateThings(things) end,draw=function(self) local things=GetAllChildren(self) DrawThings(things) end,getChildren=function(self) return self.Children end}
|
_GuiPro={GBoost=true,hasDrag=false,DragItem={},Children={},Visible=true,count=0,x=0,y=0,height=0,width=0,update=function(self) local things=GetAllChildren2(self) UpdateThings(things) end,draw=function(self) local things=GetAllChildren(self) DrawThings(things) end,getChildren=function(self) return self.Children end}
|
||||||
_GuiPro.Clips={}
|
_GuiPro.Clips={}
|
||||||
_GuiPro.rotate=0
|
_GuiPro.rotate=0
|
||||||
|
_defaultfont = love.graphics.setNewFont(12)
|
||||||
setmetatable(_GuiPro, gui)
|
setmetatable(_GuiPro, gui)
|
||||||
function gui:LoadInterface(file)
|
function gui:LoadInterface(file)
|
||||||
local add=".int"
|
local add=".int"
|
||||||
if string.find(file,".",1,true) then add="" end
|
if string.find(file,".",1,true) then add="" end
|
||||||
if love.filesystem.exists(file..add) then
|
if love.filesystem.getInfo(file..add) then
|
||||||
a,b=pcall(love.filesystem.load(file..add))
|
a,b=pcall(love.filesystem.load(file..add))
|
||||||
if a then
|
if a then
|
||||||
print("Loaded: "..file)
|
--print("Loaded: "..file)
|
||||||
else
|
else
|
||||||
print("Error loading file: "..file)
|
print("Error loading file: "..file)
|
||||||
print(a,b)
|
print(a,b)
|
||||||
@@ -34,7 +34,6 @@ function gui.LoadAll(dir)
|
|||||||
end
|
end
|
||||||
-- Start Of Load
|
-- Start Of Load
|
||||||
|
|
||||||
--gui.LoadAll("GuiManager/LibCore")
|
|
||||||
gui.LoadAll("GuiManager/Core")
|
gui.LoadAll("GuiManager/Core")
|
||||||
gui.LoadAll("GuiManager/Image-Animation")
|
gui.LoadAll("GuiManager/Image-Animation")
|
||||||
gui.LoadAll("GuiManager/Frame")
|
gui.LoadAll("GuiManager/Frame")
|
||||||
@@ -42,10 +41,8 @@ gui.LoadAll("GuiManager/Item")
|
|||||||
gui.LoadAll("GuiManager/Misc")
|
gui.LoadAll("GuiManager/Misc")
|
||||||
gui.LoadAll("GuiManager/Text")
|
gui.LoadAll("GuiManager/Text")
|
||||||
gui.LoadAll("GuiManager/Drawing")
|
gui.LoadAll("GuiManager/Drawing")
|
||||||
gui.LoadAll("GuiManager/Combos")
|
|
||||||
--gui.LoadAll("GuiManager/WIP")
|
|
||||||
multi.boost=2
|
|
||||||
|
|
||||||
|
multi.boost=2
|
||||||
-- End of Load
|
-- End of Load
|
||||||
gui:respectHierarchy()
|
gui:respectHierarchy()
|
||||||
_GuiPro.width,_GuiPro.height=love.graphics.getDimensions()
|
_GuiPro.width,_GuiPro.height=love.graphics.getDimensions()
|
||||||
|
|||||||
@@ -0,0 +1,73 @@
|
|||||||
|
--[[
|
||||||
|
LZW String Compression demo for Gideros
|
||||||
|
This code is MIT licensed, see http://www.opensource.org/licenses/mit-license.php
|
||||||
|
(C) 2013 - Guava7
|
||||||
|
]]
|
||||||
|
CLZWCompression = {}
|
||||||
|
function CLZWCompression:InitDictionary(isEncode)
|
||||||
|
self.mDictionary = {}
|
||||||
|
-- local s = " !#$%&'\"()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~"
|
||||||
|
local s={}
|
||||||
|
for i=1,255 do
|
||||||
|
s[#s+1]=string.char(i)
|
||||||
|
end
|
||||||
|
s=table.concat(s)
|
||||||
|
local len = #s
|
||||||
|
for i = 1, len do
|
||||||
|
if isEncode then
|
||||||
|
self.mDictionary[s:sub(i, i)] = i
|
||||||
|
else
|
||||||
|
self.mDictionary[i] = s:sub(i, i)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
self.mDictionaryLen = len
|
||||||
|
end
|
||||||
|
function CLZWCompression:Encode(sInput)
|
||||||
|
self:InitDictionary(true)
|
||||||
|
local s = ""
|
||||||
|
local ch
|
||||||
|
local len = #sInput
|
||||||
|
local result = {}
|
||||||
|
local dic = self.mDictionary
|
||||||
|
local temp
|
||||||
|
for i = 1, len do
|
||||||
|
ch = sInput:sub(i, i)
|
||||||
|
temp = s..ch
|
||||||
|
if dic[temp] then
|
||||||
|
s = temp
|
||||||
|
else
|
||||||
|
result[#result + 1] = dic[s]
|
||||||
|
self.mDictionaryLen = self.mDictionaryLen + 1
|
||||||
|
dic[temp] = self.mDictionaryLen
|
||||||
|
s = ch
|
||||||
|
end
|
||||||
|
end
|
||||||
|
result[#result + 1] = dic[s]
|
||||||
|
return result
|
||||||
|
end
|
||||||
|
function CLZWCompression:Decode(data)
|
||||||
|
self:InitDictionary(false)
|
||||||
|
local dic = self.mDictionary
|
||||||
|
local entry
|
||||||
|
local ch
|
||||||
|
local prevCode, currCode
|
||||||
|
local result = {}
|
||||||
|
prevCode = data[1]
|
||||||
|
result[#result + 1] = dic[prevCode]
|
||||||
|
for i = 2, #data do
|
||||||
|
currCode = data[i]
|
||||||
|
entry = dic[currCode]
|
||||||
|
if entry then
|
||||||
|
ch = entry:sub(1, 1)
|
||||||
|
result[#result + 1] = entry
|
||||||
|
else
|
||||||
|
ch = dic[prevCode]:sub(1, 1)
|
||||||
|
result[#result + 1] = dic[prevCode]..ch
|
||||||
|
end
|
||||||
|
dic[#dic + 1] = dic[prevCode]..ch
|
||||||
|
prevCode = currCode
|
||||||
|
end
|
||||||
|
return table.concat(result)
|
||||||
|
end
|
||||||
|
|
||||||
|
return CLZWCompression
|
||||||
@@ -0,0 +1,30 @@
|
|||||||
|
local base64={}
|
||||||
|
local bs = { [0] =
|
||||||
|
'A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P',
|
||||||
|
'Q','R','S','T','U','V','W','X','Y','Z','a','b','c','d','e','f',
|
||||||
|
'g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v',
|
||||||
|
'w','x','y','z','0','1','2','3','4','5','6','7','8','9','+','/',
|
||||||
|
}
|
||||||
|
local bsd=table.flip(bs)
|
||||||
|
local char=string.char
|
||||||
|
function base64.encode(s)
|
||||||
|
local byte, rep, pad = string.byte, string.rep, 2 - ((#s-1) % 3)
|
||||||
|
s = (s..rep('\0', pad)):gsub("...", function(cs)
|
||||||
|
local a, b, c = byte(cs, 1, 3)
|
||||||
|
return bs[bit.rshift(a,2)] .. bs[bit.bor(bit.lshift(bit.band(a,3),4),bit.rshift(b,4))] .. bs[bit.bor(bit.lshift(bit.band(b,15),2),bit.rshift(c,6))] .. bs[bit.band(c,63)]
|
||||||
|
end)
|
||||||
|
return s:sub(1, #s-pad) .. rep('=', pad)
|
||||||
|
end
|
||||||
|
function base64.decode(s)
|
||||||
|
local s=s:match("["..s.."=]+")
|
||||||
|
local p,cc=s:gsub("=","A")
|
||||||
|
local r=""
|
||||||
|
local n=0
|
||||||
|
s=s:sub(1,#s-#p)..p
|
||||||
|
for c = 1,#s,4 do
|
||||||
|
n = bit.lshift(bsd[s:sub(c, c)], 18) + bit.lshift(bsd[s:sub(c+1, c+1)], 12) + bit.lshift(bsd[s:sub(c + 2, c + 2)], 6) + bsd[s:sub(c + 3, c + 3)]
|
||||||
|
r = r .. char(bit.band(bit.arshift(n, 16), 0xFF)) .. char(bit.band(bit.arshift(n, 8), 0xFF)) .. char(bit.band(n, 0xFF))
|
||||||
|
end
|
||||||
|
return r:sub(1,-(cc+1))
|
||||||
|
end
|
||||||
|
return base64
|
||||||
@@ -0,0 +1,72 @@
|
|||||||
|
local base91={}
|
||||||
|
local b91enc={[0]=
|
||||||
|
'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M',
|
||||||
|
'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
|
||||||
|
'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm',
|
||||||
|
'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
|
||||||
|
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '!', '#', '$',
|
||||||
|
'%', '&', '(', ')', '*', '+', ',', '.', '/', ':', ';', '<', '=',
|
||||||
|
'>', '?', '@', '[', ']', '^', '_', '`', '{', '|', '}', '~', '"'
|
||||||
|
}
|
||||||
|
local b91dec=table.flip(b91enc)
|
||||||
|
function base91.decode(d)
|
||||||
|
local l,v,o,b,n = #d,-1,"",0,0
|
||||||
|
for i in d:gmatch(".") do
|
||||||
|
local c=b91dec[i]
|
||||||
|
if not(c) then
|
||||||
|
-- Continue
|
||||||
|
else
|
||||||
|
if v < 0 then
|
||||||
|
v = c
|
||||||
|
else
|
||||||
|
v = v+c*91
|
||||||
|
b = bit.bor(b, bit.lshift(v,n))
|
||||||
|
if bit.band(v,8191) then
|
||||||
|
n = n + 13
|
||||||
|
else
|
||||||
|
n = n + 14
|
||||||
|
end
|
||||||
|
while true do
|
||||||
|
o=o..string.char(bit.band(b,255))
|
||||||
|
b=bit.rshift(b,8)
|
||||||
|
n=n-8
|
||||||
|
if not (n>7) then
|
||||||
|
break
|
||||||
|
end
|
||||||
|
end
|
||||||
|
v=-1
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
if v + 1>0 then
|
||||||
|
o=o..string.char(bit.band(bit.bor(b,bit.lshift(v,n)),255))
|
||||||
|
end
|
||||||
|
return o
|
||||||
|
end
|
||||||
|
function base91.encode(d)
|
||||||
|
local b,n,o,l=0,0,"",#d
|
||||||
|
for i in d:gmatch(".") do
|
||||||
|
b=bit.bor(b,bit.lshift(string.byte(i),n))
|
||||||
|
n=n+8
|
||||||
|
if n>13 then
|
||||||
|
v=bit.band(b,8191)
|
||||||
|
if v>88 then
|
||||||
|
b=bit.rshift(b,13)
|
||||||
|
n=n-13
|
||||||
|
else
|
||||||
|
v=bit.band(b,16383)
|
||||||
|
b=bit.rshift(b,14)
|
||||||
|
n=n-14
|
||||||
|
end
|
||||||
|
o=o..b91enc[v % 91] .. b91enc[math.floor(v / 91)]
|
||||||
|
end
|
||||||
|
end
|
||||||
|
if n>0 then
|
||||||
|
o=o..b91enc[b % 91]
|
||||||
|
if n>7 or b>90 then
|
||||||
|
o=o .. b91enc[math.floor(b / 91)]
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return o
|
||||||
|
end
|
||||||
|
return base91
|
||||||
@@ -0,0 +1,377 @@
|
|||||||
|
local md5 = {
|
||||||
|
_VERSION = "md5.lua 1.1.0",
|
||||||
|
_DESCRIPTION = "MD5 computation in Lua (5.1-3, LuaJIT)",
|
||||||
|
_URL = "https://github.com/kikito/md5.lua",
|
||||||
|
_LICENSE = [[
|
||||||
|
MIT LICENSE
|
||||||
|
|
||||||
|
Copyright (c) 2013 Enrique García Cota + Adam Baldwin + hanzao + Equi 4 Software
|
||||||
|
]]
|
||||||
|
}
|
||||||
|
|
||||||
|
-- bit lib implementions
|
||||||
|
|
||||||
|
local char, byte, format, rep, sub =
|
||||||
|
string.char, string.byte, string.format, string.rep, string.sub
|
||||||
|
local bit_or, bit_and, bit_not, bit_xor, bit_rshift, bit_lshift
|
||||||
|
|
||||||
|
local ok, bit = pcall(require, 'bit')
|
||||||
|
if ok then
|
||||||
|
bit_or, bit_and, bit_not, bit_xor, bit_rshift, bit_lshift = bit.bor, bit.band, bit.bnot, bit.bxor, bit.rshift, bit.lshift
|
||||||
|
else
|
||||||
|
ok, bit = pcall(require, 'bit32')
|
||||||
|
|
||||||
|
if ok then
|
||||||
|
|
||||||
|
bit_not = bit.bnot
|
||||||
|
|
||||||
|
local tobit = function(n)
|
||||||
|
return n <= 0x7fffffff and n or -(bit_not(n) + 1)
|
||||||
|
end
|
||||||
|
|
||||||
|
local normalize = function(f)
|
||||||
|
return function(a,b) return tobit(f(tobit(a), tobit(b))) end
|
||||||
|
end
|
||||||
|
|
||||||
|
bit_or, bit_and, bit_xor = normalize(bit.bor), normalize(bit.band), normalize(bit.bxor)
|
||||||
|
bit_rshift, bit_lshift = normalize(bit.rshift), normalize(bit.lshift)
|
||||||
|
|
||||||
|
else
|
||||||
|
|
||||||
|
local function tbl2number(tbl)
|
||||||
|
local result = 0
|
||||||
|
local power = 1
|
||||||
|
for i = 1, #tbl do
|
||||||
|
result = result + tbl[i] * power
|
||||||
|
power = power * 2
|
||||||
|
end
|
||||||
|
return result
|
||||||
|
end
|
||||||
|
|
||||||
|
local function expand(t1, t2)
|
||||||
|
local big, small = t1, t2
|
||||||
|
if(#big < #small) then
|
||||||
|
big, small = small, big
|
||||||
|
end
|
||||||
|
-- expand small
|
||||||
|
for i = #small + 1, #big do
|
||||||
|
small[i] = 0
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local to_bits -- needs to be declared before bit_not
|
||||||
|
|
||||||
|
bit_not = function(n)
|
||||||
|
local tbl = to_bits(n)
|
||||||
|
local size = math.max(#tbl, 32)
|
||||||
|
for i = 1, size do
|
||||||
|
if(tbl[i] == 1) then
|
||||||
|
tbl[i] = 0
|
||||||
|
else
|
||||||
|
tbl[i] = 1
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return tbl2number(tbl)
|
||||||
|
end
|
||||||
|
|
||||||
|
-- defined as local above
|
||||||
|
to_bits = function (n)
|
||||||
|
if(n < 0) then
|
||||||
|
-- negative
|
||||||
|
return to_bits(bit_not(math.abs(n)) + 1)
|
||||||
|
end
|
||||||
|
-- to bits table
|
||||||
|
local tbl = {}
|
||||||
|
local cnt = 1
|
||||||
|
local last
|
||||||
|
while n > 0 do
|
||||||
|
last = n % 2
|
||||||
|
tbl[cnt] = last
|
||||||
|
n = (n-last)/2
|
||||||
|
cnt = cnt + 1
|
||||||
|
end
|
||||||
|
|
||||||
|
return tbl
|
||||||
|
end
|
||||||
|
|
||||||
|
bit_or = function(m, n)
|
||||||
|
local tbl_m = to_bits(m)
|
||||||
|
local tbl_n = to_bits(n)
|
||||||
|
expand(tbl_m, tbl_n)
|
||||||
|
|
||||||
|
local tbl = {}
|
||||||
|
for i = 1, #tbl_m do
|
||||||
|
if(tbl_m[i]== 0 and tbl_n[i] == 0) then
|
||||||
|
tbl[i] = 0
|
||||||
|
else
|
||||||
|
tbl[i] = 1
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
return tbl2number(tbl)
|
||||||
|
end
|
||||||
|
|
||||||
|
bit_and = function(m, n)
|
||||||
|
local tbl_m = to_bits(m)
|
||||||
|
local tbl_n = to_bits(n)
|
||||||
|
expand(tbl_m, tbl_n)
|
||||||
|
|
||||||
|
local tbl = {}
|
||||||
|
for i = 1, #tbl_m do
|
||||||
|
if(tbl_m[i]== 0 or tbl_n[i] == 0) then
|
||||||
|
tbl[i] = 0
|
||||||
|
else
|
||||||
|
tbl[i] = 1
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
return tbl2number(tbl)
|
||||||
|
end
|
||||||
|
|
||||||
|
bit_xor = function(m, n)
|
||||||
|
local tbl_m = to_bits(m)
|
||||||
|
local tbl_n = to_bits(n)
|
||||||
|
expand(tbl_m, tbl_n)
|
||||||
|
|
||||||
|
local tbl = {}
|
||||||
|
for i = 1, #tbl_m do
|
||||||
|
if(tbl_m[i] ~= tbl_n[i]) then
|
||||||
|
tbl[i] = 1
|
||||||
|
else
|
||||||
|
tbl[i] = 0
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
return tbl2number(tbl)
|
||||||
|
end
|
||||||
|
|
||||||
|
bit_rshift = function(n, bits)
|
||||||
|
local high_bit = 0
|
||||||
|
if(n < 0) then
|
||||||
|
-- negative
|
||||||
|
n = bit_not(math.abs(n)) + 1
|
||||||
|
high_bit = 0x80000000
|
||||||
|
end
|
||||||
|
|
||||||
|
local floor = math.floor
|
||||||
|
|
||||||
|
for i=1, bits do
|
||||||
|
n = n/2
|
||||||
|
n = bit_or(floor(n), high_bit)
|
||||||
|
end
|
||||||
|
return floor(n)
|
||||||
|
end
|
||||||
|
|
||||||
|
bit_lshift = function(n, bits)
|
||||||
|
if(n < 0) then
|
||||||
|
-- negative
|
||||||
|
n = bit_not(math.abs(n)) + 1
|
||||||
|
end
|
||||||
|
|
||||||
|
for i=1, bits do
|
||||||
|
n = n*2
|
||||||
|
end
|
||||||
|
return bit_and(n, 0xFFFFFFFF)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- convert little-endian 32-bit int to a 4-char string
|
||||||
|
local function lei2str(i)
|
||||||
|
local f=function (s) return char( bit_and( bit_rshift(i, s), 255)) end
|
||||||
|
return f(0)..f(8)..f(16)..f(24)
|
||||||
|
end
|
||||||
|
|
||||||
|
-- convert raw string to big-endian int
|
||||||
|
local function str2bei(s)
|
||||||
|
local v=0
|
||||||
|
for i=1, #s do
|
||||||
|
v = v * 256 + byte(s, i)
|
||||||
|
end
|
||||||
|
return v
|
||||||
|
end
|
||||||
|
|
||||||
|
-- convert raw string to little-endian int
|
||||||
|
local function str2lei(s)
|
||||||
|
local v=0
|
||||||
|
for i = #s,1,-1 do
|
||||||
|
v = v*256 + byte(s, i)
|
||||||
|
end
|
||||||
|
return v
|
||||||
|
end
|
||||||
|
|
||||||
|
-- cut up a string in little-endian ints of given size
|
||||||
|
local function cut_le_str(s,...)
|
||||||
|
local o, r = 1, {}
|
||||||
|
local args = {...}
|
||||||
|
for i=1, #args do
|
||||||
|
table.insert(r, str2lei(sub(s, o, o + args[i] - 1)))
|
||||||
|
o = o + args[i]
|
||||||
|
end
|
||||||
|
return r
|
||||||
|
end
|
||||||
|
|
||||||
|
local swap = function (w) return str2bei(lei2str(w)) end
|
||||||
|
|
||||||
|
-- An MD5 mplementation in Lua, requires bitlib (hacked to use LuaBit from above, ugh)
|
||||||
|
-- 10/02/2001 jcw@equi4.com
|
||||||
|
|
||||||
|
local CONSTS = {
|
||||||
|
0xd76aa478, 0xe8c7b756, 0x242070db, 0xc1bdceee,
|
||||||
|
0xf57c0faf, 0x4787c62a, 0xa8304613, 0xfd469501,
|
||||||
|
0x698098d8, 0x8b44f7af, 0xffff5bb1, 0x895cd7be,
|
||||||
|
0x6b901122, 0xfd987193, 0xa679438e, 0x49b40821,
|
||||||
|
0xf61e2562, 0xc040b340, 0x265e5a51, 0xe9b6c7aa,
|
||||||
|
0xd62f105d, 0x02441453, 0xd8a1e681, 0xe7d3fbc8,
|
||||||
|
0x21e1cde6, 0xc33707d6, 0xf4d50d87, 0x455a14ed,
|
||||||
|
0xa9e3e905, 0xfcefa3f8, 0x676f02d9, 0x8d2a4c8a,
|
||||||
|
0xfffa3942, 0x8771f681, 0x6d9d6122, 0xfde5380c,
|
||||||
|
0xa4beea44, 0x4bdecfa9, 0xf6bb4b60, 0xbebfbc70,
|
||||||
|
0x289b7ec6, 0xeaa127fa, 0xd4ef3085, 0x04881d05,
|
||||||
|
0xd9d4d039, 0xe6db99e5, 0x1fa27cf8, 0xc4ac5665,
|
||||||
|
0xf4292244, 0x432aff97, 0xab9423a7, 0xfc93a039,
|
||||||
|
0x655b59c3, 0x8f0ccc92, 0xffeff47d, 0x85845dd1,
|
||||||
|
0x6fa87e4f, 0xfe2ce6e0, 0xa3014314, 0x4e0811a1,
|
||||||
|
0xf7537e82, 0xbd3af235, 0x2ad7d2bb, 0xeb86d391,
|
||||||
|
0x67452301, 0xefcdab89, 0x98badcfe, 0x10325476
|
||||||
|
}
|
||||||
|
|
||||||
|
local f=function (x,y,z) return bit_or(bit_and(x,y),bit_and(-x-1,z)) end
|
||||||
|
local g=function (x,y,z) return bit_or(bit_and(x,z),bit_and(y,-z-1)) end
|
||||||
|
local h=function (x,y,z) return bit_xor(x,bit_xor(y,z)) end
|
||||||
|
local i=function (x,y,z) return bit_xor(y,bit_or(x,-z-1)) end
|
||||||
|
local z=function (ff,a,b,c,d,x,s,ac)
|
||||||
|
a=bit_and(a+ff(b,c,d)+x+ac,0xFFFFFFFF)
|
||||||
|
-- be *very* careful that left shift does not cause rounding!
|
||||||
|
return bit_or(bit_lshift(bit_and(a,bit_rshift(0xFFFFFFFF,s)),s),bit_rshift(a,32-s))+b
|
||||||
|
end
|
||||||
|
|
||||||
|
local function transform(A,B,C,D,X)
|
||||||
|
local a,b,c,d=A,B,C,D
|
||||||
|
local t=CONSTS
|
||||||
|
|
||||||
|
a=z(f,a,b,c,d,X[ 0], 7,t[ 1])
|
||||||
|
d=z(f,d,a,b,c,X[ 1],12,t[ 2])
|
||||||
|
c=z(f,c,d,a,b,X[ 2],17,t[ 3])
|
||||||
|
b=z(f,b,c,d,a,X[ 3],22,t[ 4])
|
||||||
|
a=z(f,a,b,c,d,X[ 4], 7,t[ 5])
|
||||||
|
d=z(f,d,a,b,c,X[ 5],12,t[ 6])
|
||||||
|
c=z(f,c,d,a,b,X[ 6],17,t[ 7])
|
||||||
|
b=z(f,b,c,d,a,X[ 7],22,t[ 8])
|
||||||
|
a=z(f,a,b,c,d,X[ 8], 7,t[ 9])
|
||||||
|
d=z(f,d,a,b,c,X[ 9],12,t[10])
|
||||||
|
c=z(f,c,d,a,b,X[10],17,t[11])
|
||||||
|
b=z(f,b,c,d,a,X[11],22,t[12])
|
||||||
|
a=z(f,a,b,c,d,X[12], 7,t[13])
|
||||||
|
d=z(f,d,a,b,c,X[13],12,t[14])
|
||||||
|
c=z(f,c,d,a,b,X[14],17,t[15])
|
||||||
|
b=z(f,b,c,d,a,X[15],22,t[16])
|
||||||
|
|
||||||
|
a=z(g,a,b,c,d,X[ 1], 5,t[17])
|
||||||
|
d=z(g,d,a,b,c,X[ 6], 9,t[18])
|
||||||
|
c=z(g,c,d,a,b,X[11],14,t[19])
|
||||||
|
b=z(g,b,c,d,a,X[ 0],20,t[20])
|
||||||
|
a=z(g,a,b,c,d,X[ 5], 5,t[21])
|
||||||
|
d=z(g,d,a,b,c,X[10], 9,t[22])
|
||||||
|
c=z(g,c,d,a,b,X[15],14,t[23])
|
||||||
|
b=z(g,b,c,d,a,X[ 4],20,t[24])
|
||||||
|
a=z(g,a,b,c,d,X[ 9], 5,t[25])
|
||||||
|
d=z(g,d,a,b,c,X[14], 9,t[26])
|
||||||
|
c=z(g,c,d,a,b,X[ 3],14,t[27])
|
||||||
|
b=z(g,b,c,d,a,X[ 8],20,t[28])
|
||||||
|
a=z(g,a,b,c,d,X[13], 5,t[29])
|
||||||
|
d=z(g,d,a,b,c,X[ 2], 9,t[30])
|
||||||
|
c=z(g,c,d,a,b,X[ 7],14,t[31])
|
||||||
|
b=z(g,b,c,d,a,X[12],20,t[32])
|
||||||
|
|
||||||
|
a=z(h,a,b,c,d,X[ 5], 4,t[33])
|
||||||
|
d=z(h,d,a,b,c,X[ 8],11,t[34])
|
||||||
|
c=z(h,c,d,a,b,X[11],16,t[35])
|
||||||
|
b=z(h,b,c,d,a,X[14],23,t[36])
|
||||||
|
a=z(h,a,b,c,d,X[ 1], 4,t[37])
|
||||||
|
d=z(h,d,a,b,c,X[ 4],11,t[38])
|
||||||
|
c=z(h,c,d,a,b,X[ 7],16,t[39])
|
||||||
|
b=z(h,b,c,d,a,X[10],23,t[40])
|
||||||
|
a=z(h,a,b,c,d,X[13], 4,t[41])
|
||||||
|
d=z(h,d,a,b,c,X[ 0],11,t[42])
|
||||||
|
c=z(h,c,d,a,b,X[ 3],16,t[43])
|
||||||
|
b=z(h,b,c,d,a,X[ 6],23,t[44])
|
||||||
|
a=z(h,a,b,c,d,X[ 9], 4,t[45])
|
||||||
|
d=z(h,d,a,b,c,X[12],11,t[46])
|
||||||
|
c=z(h,c,d,a,b,X[15],16,t[47])
|
||||||
|
b=z(h,b,c,d,a,X[ 2],23,t[48])
|
||||||
|
|
||||||
|
a=z(i,a,b,c,d,X[ 0], 6,t[49])
|
||||||
|
d=z(i,d,a,b,c,X[ 7],10,t[50])
|
||||||
|
c=z(i,c,d,a,b,X[14],15,t[51])
|
||||||
|
b=z(i,b,c,d,a,X[ 5],21,t[52])
|
||||||
|
a=z(i,a,b,c,d,X[12], 6,t[53])
|
||||||
|
d=z(i,d,a,b,c,X[ 3],10,t[54])
|
||||||
|
c=z(i,c,d,a,b,X[10],15,t[55])
|
||||||
|
b=z(i,b,c,d,a,X[ 1],21,t[56])
|
||||||
|
a=z(i,a,b,c,d,X[ 8], 6,t[57])
|
||||||
|
d=z(i,d,a,b,c,X[15],10,t[58])
|
||||||
|
c=z(i,c,d,a,b,X[ 6],15,t[59])
|
||||||
|
b=z(i,b,c,d,a,X[13],21,t[60])
|
||||||
|
a=z(i,a,b,c,d,X[ 4], 6,t[61])
|
||||||
|
d=z(i,d,a,b,c,X[11],10,t[62])
|
||||||
|
c=z(i,c,d,a,b,X[ 2],15,t[63])
|
||||||
|
b=z(i,b,c,d,a,X[ 9],21,t[64])
|
||||||
|
|
||||||
|
return bit_and(A+a,0xFFFFFFFF),bit_and(B+b,0xFFFFFFFF),
|
||||||
|
bit_and(C+c,0xFFFFFFFF),bit_and(D+d,0xFFFFFFFF)
|
||||||
|
end
|
||||||
|
|
||||||
|
----------------------------------------------------------------
|
||||||
|
|
||||||
|
local function md5_update(self, s)
|
||||||
|
self.pos = self.pos + #s
|
||||||
|
s = self.buf .. s
|
||||||
|
for ii = 1, #s - 63, 64 do
|
||||||
|
local X = cut_le_str(sub(s,ii,ii+63),4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4)
|
||||||
|
assert(#X == 16)
|
||||||
|
X[0] = table.remove(X,1) -- zero based!
|
||||||
|
self.a,self.b,self.c,self.d = transform(self.a,self.b,self.c,self.d,X)
|
||||||
|
end
|
||||||
|
self.buf = sub(s, math.floor(#s/64)*64 + 1, #s)
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
local function md5_finish(self)
|
||||||
|
local msgLen = self.pos
|
||||||
|
local padLen = 56 - msgLen % 64
|
||||||
|
|
||||||
|
if msgLen % 64 > 56 then padLen = padLen + 64 end
|
||||||
|
|
||||||
|
if padLen == 0 then padLen = 64 end
|
||||||
|
|
||||||
|
local s = char(128) .. rep(char(0),padLen-1) .. lei2str(bit_and(8*msgLen, 0xFFFFFFFF)) .. lei2str(math.floor(msgLen/0x20000000))
|
||||||
|
md5_update(self, s)
|
||||||
|
|
||||||
|
assert(self.pos % 64 == 0)
|
||||||
|
return lei2str(self.a) .. lei2str(self.b) .. lei2str(self.c) .. lei2str(self.d)
|
||||||
|
end
|
||||||
|
|
||||||
|
----------------------------------------------------------------
|
||||||
|
|
||||||
|
function md5.new()
|
||||||
|
return { a = CONSTS[65], b = CONSTS[66], c = CONSTS[67], d = CONSTS[68],
|
||||||
|
pos = 0,
|
||||||
|
buf = '',
|
||||||
|
update = md5_update,
|
||||||
|
finish = md5_finish }
|
||||||
|
end
|
||||||
|
|
||||||
|
function md5.tohex(s)
|
||||||
|
return format("%08x%08x%08x%08x", str2bei(sub(s, 1, 4)), str2bei(sub(s, 5, 8)), str2bei(sub(s, 9, 12)), str2bei(sub(s, 13, 16)))
|
||||||
|
end
|
||||||
|
|
||||||
|
function md5.sum(s)
|
||||||
|
return md5.new():update(s):finish()
|
||||||
|
end
|
||||||
|
|
||||||
|
function md5.sumhexa(s)
|
||||||
|
return md5.tohex(md5.sum(s))
|
||||||
|
end
|
||||||
|
|
||||||
|
return md5
|
||||||
@@ -0,0 +1,739 @@
|
|||||||
|
bin={}
|
||||||
|
bin.Version={5,1,0}
|
||||||
|
bin.stage='stable'
|
||||||
|
bin.data=''
|
||||||
|
bin.t='bin'
|
||||||
|
bin.__index = bin
|
||||||
|
bin.__tostring=function(self) return self:getData() end
|
||||||
|
bin.__len=function(self) return self:getlength() end
|
||||||
|
bin.lastBlockSize=0
|
||||||
|
bin.streams={}
|
||||||
|
-- Helpers
|
||||||
|
function bin.getVersion()
|
||||||
|
return bin.Version[1]..'.'..bin.Version[2]..'.'..bin.Version[3]
|
||||||
|
end
|
||||||
|
require("bin.support.utils")
|
||||||
|
if jit then
|
||||||
|
bit=require("bit")
|
||||||
|
elseif bit32 then
|
||||||
|
bit=bit32
|
||||||
|
else
|
||||||
|
bit=require("bin.numbers.no_jit_bit")
|
||||||
|
end
|
||||||
|
base64=require("bin.converters.base64")
|
||||||
|
base91=require("bin.converters.base91")
|
||||||
|
bin.lzw=require("bin.compressors.lzw") -- A WIP
|
||||||
|
bits=require("bin.numbers.bits")
|
||||||
|
infinabits=require("bin.numbers.infinabits") -- like the bits library but works past 32 bits for 32bit lua and 64 bits for 64 bit lua.
|
||||||
|
bin.md5=require("bin.hashes.md5")
|
||||||
|
randomGen=require("bin.numbers.random")
|
||||||
|
function bin.setBitsInterface(int)
|
||||||
|
bin.defualtBit=int or bits
|
||||||
|
end
|
||||||
|
bin.setBitsInterface()
|
||||||
|
function bin.normalizeData(data) -- unified function to allow for all types to string
|
||||||
|
if type(data)=="string" then return data end
|
||||||
|
if type(data)=="table" then
|
||||||
|
if data.Type=="bin" or data.Type=="streamable" or data.Type=="buffer" then
|
||||||
|
return data:getData()
|
||||||
|
elseif data.Type=="bits" or data.Type=="infinabits" then
|
||||||
|
return data:toSbytes()
|
||||||
|
elseif data.Type=="sink" then
|
||||||
|
-- LATER
|
||||||
|
else
|
||||||
|
return ""
|
||||||
|
end
|
||||||
|
elseif type(data)=="userdata" then
|
||||||
|
if tostring(data):sub(1,4)=="file" then
|
||||||
|
local cur=data:seek("cur")
|
||||||
|
data:seek("set",0)
|
||||||
|
local dat=data:read("*a")
|
||||||
|
data:seek("set",cur)
|
||||||
|
return dat
|
||||||
|
else
|
||||||
|
error("File handles are the only userdata that can be used!")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
function bin.resolveType(tab) -- used in getblock for auto object creation. Internal method
|
||||||
|
if tab.Type then
|
||||||
|
if tab.Type=="bin" then
|
||||||
|
return bin.new(tab.data)
|
||||||
|
elseif tab.Type=="streamable" then
|
||||||
|
if bin.fileExist(tab.file) then return nil,"Cannot load the stream file, source file does not exist!" end
|
||||||
|
return bin.stream(tab.file,tab.lock)
|
||||||
|
elseif tab.Type=="buffer" then
|
||||||
|
local buf=bin.newDataBuffer(tab.size)
|
||||||
|
buf[1]=tab:getData()
|
||||||
|
return buf
|
||||||
|
elseif tab.Type=="bits" then
|
||||||
|
local b=bits.new("")
|
||||||
|
b.data=tab.data
|
||||||
|
return b
|
||||||
|
elseif tab.Type=="infinabits" then
|
||||||
|
local b=infinabits.new("")
|
||||||
|
b.data=tab.data
|
||||||
|
return b
|
||||||
|
elseif tab.Type=="sink" then
|
||||||
|
return bin.newSync(tab.data)
|
||||||
|
else -- maybe a type from another library
|
||||||
|
return tab
|
||||||
|
end
|
||||||
|
else return tab end
|
||||||
|
end
|
||||||
|
function bin.fileExist(path)
|
||||||
|
g=io.open(path or '','r')
|
||||||
|
if path =='' then
|
||||||
|
p='empty path'
|
||||||
|
return nil
|
||||||
|
end
|
||||||
|
if g~=nil and true or false then
|
||||||
|
p=(g~=nil and true or false)
|
||||||
|
end
|
||||||
|
if g~=nil then
|
||||||
|
io.close(g)
|
||||||
|
else
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
return p
|
||||||
|
end
|
||||||
|
function bin.toHex(str)
|
||||||
|
local str=bin.normalizeData(str)
|
||||||
|
return (str:gsub('.', function (c)
|
||||||
|
return string.format('%02X', string.byte(c))
|
||||||
|
end))
|
||||||
|
end
|
||||||
|
function bin.fromHex(str)
|
||||||
|
return (str:gsub('..', function (cc)
|
||||||
|
return string.char(tonumber(cc, 16))
|
||||||
|
end))
|
||||||
|
end
|
||||||
|
function bin.toBase64(s)
|
||||||
|
return base64.encode(s)
|
||||||
|
end
|
||||||
|
function bin.fromBase64(s)
|
||||||
|
return base64.decode(s)
|
||||||
|
end
|
||||||
|
function bin.toBase91(s)
|
||||||
|
return base91.encode(s)
|
||||||
|
end
|
||||||
|
function bin.fromBase91(s)
|
||||||
|
return base91.decode(s)
|
||||||
|
end
|
||||||
|
-- Constructors
|
||||||
|
function bin.new(data)
|
||||||
|
data=bin.normalizeData(data)
|
||||||
|
local c = {}
|
||||||
|
setmetatable(c, bin)
|
||||||
|
c.data=data
|
||||||
|
c.Type="bin"
|
||||||
|
c.t="bin"
|
||||||
|
c.pos=1
|
||||||
|
c.stream=false
|
||||||
|
return c
|
||||||
|
end
|
||||||
|
function bin.newFromBase64(data)
|
||||||
|
return bin.new(bin.fromBase64(data))
|
||||||
|
end
|
||||||
|
function bin.newFromBase91(data)
|
||||||
|
return bin.new(bin.fromBase91(data))
|
||||||
|
end
|
||||||
|
function bin.newFromHex(data)
|
||||||
|
return bin.new(bin.fromHex(data))
|
||||||
|
end
|
||||||
|
function bin.load(path)
|
||||||
|
if type(path) ~= "string" then error("Path must be a string!") end
|
||||||
|
local f = io.open(path, 'rb')
|
||||||
|
local content = f:read('*a')
|
||||||
|
f:close()
|
||||||
|
return bin.new(content)
|
||||||
|
end
|
||||||
|
function bin.stream(file,l)
|
||||||
|
if not(l==false) then l=true end
|
||||||
|
local c=bin.new()
|
||||||
|
c.Type="streamable"
|
||||||
|
c.t="streamable"
|
||||||
|
if bin.streams[file]~=nil then
|
||||||
|
c.file=file
|
||||||
|
c.lock = l
|
||||||
|
c.workingfile=bin.streams[file][1].workingfile
|
||||||
|
bin.streams[file][2]=bin.streams[file][2]+1
|
||||||
|
c.stream=true
|
||||||
|
return c
|
||||||
|
end
|
||||||
|
if bin.fileExist(file) then
|
||||||
|
c.file=file
|
||||||
|
c.lock = l
|
||||||
|
c.workingfile=io.open(file,'rb+')
|
||||||
|
else
|
||||||
|
c.file=file
|
||||||
|
c.lock = l
|
||||||
|
c.workingfile=io.open(file,'w')
|
||||||
|
io.close(c.workingfile)
|
||||||
|
c.workingfile=io.open(file,'rb+')
|
||||||
|
end
|
||||||
|
c.stream=true
|
||||||
|
bin.streams[file]={c,1}
|
||||||
|
return c
|
||||||
|
end
|
||||||
|
function bin.newTempFile()
|
||||||
|
local c=bin.new()
|
||||||
|
c.file=file
|
||||||
|
c.lock = false
|
||||||
|
c.workingfile=io.tmpfile()
|
||||||
|
c.stream=true
|
||||||
|
return c
|
||||||
|
end
|
||||||
|
function bin.freshStream(file)
|
||||||
|
bin.new():tofile(file)
|
||||||
|
return bin.stream(file,false)
|
||||||
|
end
|
||||||
|
function bin.newStreamFileObject(file)
|
||||||
|
local c=bin.new()
|
||||||
|
c.Type="streamable"
|
||||||
|
c.t="streamable"
|
||||||
|
c.file="FILE_OBJECT"
|
||||||
|
c.lock = false
|
||||||
|
c.workingfile=file
|
||||||
|
c.stream=true
|
||||||
|
return c
|
||||||
|
end
|
||||||
|
-- Core Methods
|
||||||
|
function bin:canStreamWrite()
|
||||||
|
return (self.stream and not(self.lock))
|
||||||
|
end
|
||||||
|
function bin:getSeek()
|
||||||
|
if self.stream then
|
||||||
|
return self.workingfile:seek("cur")+1
|
||||||
|
else
|
||||||
|
return self.pos
|
||||||
|
end
|
||||||
|
end
|
||||||
|
function bin:setSeek(n)
|
||||||
|
if self.stream then
|
||||||
|
self.workingfile:seek("set",n-1)
|
||||||
|
else
|
||||||
|
self.pos=n
|
||||||
|
end
|
||||||
|
end
|
||||||
|
function bin:seek(n)
|
||||||
|
if self.stream then
|
||||||
|
if not n then return self.workingfile:seek("cur") end
|
||||||
|
local cur=self.workingfile:seek("cur")
|
||||||
|
self.workingfile:seek("set",cur+n)
|
||||||
|
else
|
||||||
|
if not n then return self.pos end
|
||||||
|
if #self.data-(self.pos-1)<n then
|
||||||
|
print(n-((#self.data)-(self.pos-1)))
|
||||||
|
self:write(string.rep("\0",n-((#self.data)-(self.pos-1))))
|
||||||
|
return
|
||||||
|
end
|
||||||
|
self.pos=self.pos+n
|
||||||
|
end
|
||||||
|
end
|
||||||
|
function bin:read(n)
|
||||||
|
if self.stream then
|
||||||
|
return self.workingfile:read(n)
|
||||||
|
else
|
||||||
|
local data=self.data:sub(self.pos,self.pos+n-1)
|
||||||
|
self.pos=self.pos+n
|
||||||
|
if data=="" then return end
|
||||||
|
return data
|
||||||
|
end
|
||||||
|
end
|
||||||
|
function bin:write(data,size)
|
||||||
|
local data=bin.normalizeData(data)
|
||||||
|
local dsize=#data
|
||||||
|
local size=tonumber(size or dsize)
|
||||||
|
if dsize>size then
|
||||||
|
data = data:sub(1,size)
|
||||||
|
elseif dsize<size then
|
||||||
|
data=data..string.rep("\0",size-dsize)
|
||||||
|
end
|
||||||
|
if self:canStreamWrite() then
|
||||||
|
self.workingfile:write(data)
|
||||||
|
elseif self.Type=="bin" then
|
||||||
|
local tab={}
|
||||||
|
if self.pos==1 then
|
||||||
|
tab={data,self.data:sub(self.pos+size)}
|
||||||
|
else
|
||||||
|
tab={self.data:sub(1,self.pos-1),data,self.data:sub(self.pos+size)}
|
||||||
|
end
|
||||||
|
self.pos=self.pos+size
|
||||||
|
self.data=table.concat(tab)
|
||||||
|
else
|
||||||
|
error("Attempted to write to a locked file!")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
function bin:sub(a,b)
|
||||||
|
local data=""
|
||||||
|
if self.stream then
|
||||||
|
local cur=self.workingfile:seek("cur")
|
||||||
|
self.workingfile:seek("set",a-1)
|
||||||
|
data=self.workingfile:read(b-(a-1))
|
||||||
|
self.workingfile:seek("set",cur)
|
||||||
|
else
|
||||||
|
data=self.data:sub(a,b)
|
||||||
|
end
|
||||||
|
return data
|
||||||
|
end
|
||||||
|
function bin:slide(n)
|
||||||
|
local s=self:getSize()
|
||||||
|
local buf=bin.newDataBuffer(s)
|
||||||
|
buf:fillBuffer(1,self:getData())
|
||||||
|
for i=1,s do
|
||||||
|
nn=buf[i]+n
|
||||||
|
if nn>255 then
|
||||||
|
nn=nn%256
|
||||||
|
elseif nn<0 then
|
||||||
|
nn=256-math.abs(nn)
|
||||||
|
end
|
||||||
|
buf[i]=nn
|
||||||
|
end
|
||||||
|
self:setSeek(1)
|
||||||
|
self:write(buf:getData())
|
||||||
|
end
|
||||||
|
function bin:getData(a,b,fmt)
|
||||||
|
local data=""
|
||||||
|
if a or b then
|
||||||
|
data=self:sub(a,b)
|
||||||
|
else
|
||||||
|
if self.stream then
|
||||||
|
local cur=self.workingfile:seek("cur")
|
||||||
|
self.workingfile:seek("set",0)
|
||||||
|
data=self.workingfile:read("*a")
|
||||||
|
self.workingfile:seek("set",cur)
|
||||||
|
else
|
||||||
|
data=self.data
|
||||||
|
end
|
||||||
|
end
|
||||||
|
if fmt=="%x" or fmt=="hex" then
|
||||||
|
return bin.toHex(data):lower()
|
||||||
|
elseif fmt=="%X" or fmt=="HEX" then
|
||||||
|
return bin.toHex(data)
|
||||||
|
elseif fmt=="%b" or fmt=="b64" then
|
||||||
|
return bin.toB64(data)
|
||||||
|
elseif fmt then
|
||||||
|
return bin.new(data):getBlock(fmt,#data)
|
||||||
|
end
|
||||||
|
return data
|
||||||
|
end
|
||||||
|
function bin:getSize(fmt)
|
||||||
|
local len=0
|
||||||
|
if self.stream then
|
||||||
|
local cur=self.workingfile:seek("cur")
|
||||||
|
len=self.workingfile:seek("end")
|
||||||
|
self.workingfile:seek("set",cur)
|
||||||
|
else
|
||||||
|
len=#self.data
|
||||||
|
end
|
||||||
|
if fmt=="%b" then
|
||||||
|
return bin.toB64()
|
||||||
|
elseif fmt then
|
||||||
|
return string.format(fmt, len)
|
||||||
|
else
|
||||||
|
return len
|
||||||
|
end
|
||||||
|
end
|
||||||
|
function bin:tackE(data,size,h)
|
||||||
|
local data=bin.normalizeData(data)
|
||||||
|
local cur=self:getSize()
|
||||||
|
self:setSeek(self:getSize()+1)
|
||||||
|
self:write(data,size)
|
||||||
|
if h then
|
||||||
|
self:setSeek(cur+1)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
function bin:tonumber(a,b)
|
||||||
|
local temp={}
|
||||||
|
if a then
|
||||||
|
temp.data=self:sub(a,b)
|
||||||
|
else
|
||||||
|
temp=self
|
||||||
|
end
|
||||||
|
local l,r=0,0
|
||||||
|
local g=#temp.data
|
||||||
|
for i=1,g do
|
||||||
|
r=r+(256^(g-i))*string.byte(string.sub(temp.data,i,i))
|
||||||
|
l=l+(256^(i-1))*string.byte(string.sub(temp.data,i,i))
|
||||||
|
end
|
||||||
|
return r,l
|
||||||
|
end
|
||||||
|
function bin.endianflop(data)
|
||||||
|
return string.reverse(data)
|
||||||
|
end
|
||||||
|
function bin:tofile(name)
|
||||||
|
if self.stream then return end
|
||||||
|
if not name then error("Must include a filename to save as!") end
|
||||||
|
file = io.open(name, "wb")
|
||||||
|
file:write(self.data)
|
||||||
|
file:close()
|
||||||
|
end
|
||||||
|
function bin:close()
|
||||||
|
if self.stream then
|
||||||
|
if bin.streams[self.file][2]==1 then
|
||||||
|
bin.streams[self.file]=nil
|
||||||
|
self.workingfile:close()
|
||||||
|
else
|
||||||
|
bin.streams[self.file][2]=bin.streams[self.file][2]-1
|
||||||
|
self.workingfile=io.tmpfile()
|
||||||
|
self.workingfile:close()
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
function bin:getBlock(t,n)
|
||||||
|
local data=""
|
||||||
|
if not n then
|
||||||
|
if bin.registerBlocks[t] then
|
||||||
|
return bin.registerBlocks[t][1](nil,self)
|
||||||
|
else
|
||||||
|
error("Unknown format! Cannot read from file: "..tostring(t))
|
||||||
|
end
|
||||||
|
else
|
||||||
|
if t=="n" or t=="%e" or t=="%E" then
|
||||||
|
data=self:read(n)
|
||||||
|
local numB=bin.defualtBit.new(data)
|
||||||
|
local numL=bin.defualtBit.new(string.reverse(data))
|
||||||
|
local little=numL:tonumber(0)
|
||||||
|
local big=numB:tonumber(0)
|
||||||
|
if t=="%E" then
|
||||||
|
return big
|
||||||
|
elseif t=="%X" then
|
||||||
|
return bin.toHex(data):upper()
|
||||||
|
elseif t=="%x" then
|
||||||
|
return bin.toHex(data):lower()
|
||||||
|
elseif t=="%b" then
|
||||||
|
return bin.toB64(data)
|
||||||
|
elseif t=="%e" then
|
||||||
|
return little
|
||||||
|
end
|
||||||
|
return big,little
|
||||||
|
elseif t=="s" then
|
||||||
|
return self:read(n)
|
||||||
|
elseif bin.registerBlocks[t] then
|
||||||
|
return bin.registerBlocks[t][1](n,self)
|
||||||
|
else
|
||||||
|
error("Unknown format! Cannot read from file: "..tostring(t))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
function bin:addBlock(d,fit,fmt)
|
||||||
|
if not fmt then fmt=type(d):sub(1,1) end
|
||||||
|
if bin.registerBlocks[fmt] then
|
||||||
|
self:tackE(bin.registerBlocks[fmt][2](d,fit,fmt,self,bin.registerBlocks[fmt][2]))
|
||||||
|
elseif type(d)=="number" then
|
||||||
|
local data=bin.defualtBit.numToBytes(d,fit or 4,fmt,function()
|
||||||
|
error("Overflow! Space allotted for number is smaller than the number takes up. Increase the fit!")
|
||||||
|
end)
|
||||||
|
self:tackE(data)
|
||||||
|
elseif type(d)=="string" then
|
||||||
|
local data=d:sub(1,fit or -1)
|
||||||
|
if #data<(fit or #data) then
|
||||||
|
data=data..string.rep("\0",fit-#data)
|
||||||
|
end
|
||||||
|
self:tackE(data)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
bin.registerBlocks={}
|
||||||
|
function bin.registerBlock(t,funcG,funcA)
|
||||||
|
bin.registerBlocks[t]={funcG,funcA}
|
||||||
|
end
|
||||||
|
function bin.newDataBuffer(size,fill) -- fills with \0 or nul or with what you enter
|
||||||
|
local c={}
|
||||||
|
local fill=fill or "\0"
|
||||||
|
c.data={self=c}
|
||||||
|
c.Type="buffer"
|
||||||
|
c.size=size or 0 -- 0 means an infinite buffer, sometimes useful
|
||||||
|
for i=1,c.size do
|
||||||
|
c.data[i]=fill
|
||||||
|
end
|
||||||
|
local mt={
|
||||||
|
__index=function(t,k)
|
||||||
|
if type(k)=="number" then
|
||||||
|
local data=t.data[k]
|
||||||
|
if data then
|
||||||
|
return string.byte(data)
|
||||||
|
else
|
||||||
|
error("Index out of range!")
|
||||||
|
end
|
||||||
|
elseif type(k)=="string" then
|
||||||
|
local num=tonumber(k)
|
||||||
|
if num then
|
||||||
|
local data=t.data[num]
|
||||||
|
if data then
|
||||||
|
return data
|
||||||
|
else
|
||||||
|
error("Index out of range!")
|
||||||
|
end
|
||||||
|
else
|
||||||
|
error("Only number-strings and numbers can be indexed!")
|
||||||
|
end
|
||||||
|
else
|
||||||
|
error("Only number-strings and numbers can be indexed!")
|
||||||
|
end
|
||||||
|
end,
|
||||||
|
__newindex=function(t,k,v)
|
||||||
|
if type(k)~="number" then error("Can only set a buffers data with a numeric index!") end
|
||||||
|
local data=""
|
||||||
|
if type(v)=="string" then
|
||||||
|
data=v
|
||||||
|
elseif type(v)=="number" then
|
||||||
|
data=string.char(v)
|
||||||
|
else
|
||||||
|
-- try to normalize the data of type v
|
||||||
|
data=bin.normalizeData(v)
|
||||||
|
end
|
||||||
|
t:fillBuffer(k,data)
|
||||||
|
end,
|
||||||
|
__tostring=function(t)
|
||||||
|
return t:getData()
|
||||||
|
end,
|
||||||
|
}
|
||||||
|
function c:fillBuffer(a,data)
|
||||||
|
local len=#data
|
||||||
|
if len==1 then
|
||||||
|
self.data[a]=data
|
||||||
|
else
|
||||||
|
local i=a-1
|
||||||
|
for d in data:gmatch(".") do
|
||||||
|
i=i+1
|
||||||
|
if i>c.size then
|
||||||
|
return #data-i+a
|
||||||
|
end
|
||||||
|
self.data[i]=d
|
||||||
|
end
|
||||||
|
return #data-i+(a-1)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
function c:getData(a,b,fmt) -- LATER
|
||||||
|
local dat=bin.new(table.concat(self.data,"",a,b))
|
||||||
|
local n=dat:getSize()
|
||||||
|
return dat:getBlock(fmt or "s",n)
|
||||||
|
end
|
||||||
|
function c:getSize()
|
||||||
|
return #self:getData()
|
||||||
|
end
|
||||||
|
setmetatable(c,mt)
|
||||||
|
return c
|
||||||
|
end
|
||||||
|
function bin:newDataBufferFromStream(pos,size,fill) -- fills with \0 or nul or with what you enter IF the nothing exists inside the bin file.
|
||||||
|
local s=self:getSize()
|
||||||
|
if not self.stream then error("Can only created a streamed buffer on a streamable file!") end
|
||||||
|
if s==0 then
|
||||||
|
self:write(string.rep("\0",pos+size))
|
||||||
|
end
|
||||||
|
self:setSeek(1)
|
||||||
|
local c=bin.newDataBuffer(size,fill)
|
||||||
|
rawset(c,"pos",pos)
|
||||||
|
rawset(c,"size",size)
|
||||||
|
rawset(c,"fill",fill)
|
||||||
|
rawset(c,"bin",self)
|
||||||
|
rawset(c,"sync",function(self)
|
||||||
|
local cur=self.bin:getSeek()
|
||||||
|
self.bin:setSeek(self.pos)
|
||||||
|
self.bin:write(self:getData(),size)
|
||||||
|
self.bin:setSeek(cur)
|
||||||
|
end)
|
||||||
|
c:fillBuffer(1,self:sub(pos,pos+size))
|
||||||
|
function c:fillBuffer(a,data)
|
||||||
|
local len=#data
|
||||||
|
if len==1 then
|
||||||
|
self.data[a]=data
|
||||||
|
self:sync()
|
||||||
|
else
|
||||||
|
local i=a-1
|
||||||
|
for d in data:gmatch(".") do
|
||||||
|
i=i+1
|
||||||
|
if i>c.size then
|
||||||
|
self:sync()
|
||||||
|
return #data-i+a
|
||||||
|
end
|
||||||
|
self.data[i]=d
|
||||||
|
end
|
||||||
|
self:sync()
|
||||||
|
return #data-i+(a-1)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return c
|
||||||
|
end
|
||||||
|
function bin:toDataBuffer()
|
||||||
|
local s=self:getSize()
|
||||||
|
-- if self:canStreamWrite() then
|
||||||
|
-- return self:newDataBufferFromStream(0,s)
|
||||||
|
-- end
|
||||||
|
local buf=bin.newDataBuffer(s)
|
||||||
|
local data=self:read(512)
|
||||||
|
local i=1
|
||||||
|
while data~=nil do
|
||||||
|
buf[i]=data
|
||||||
|
data=self:read(512)
|
||||||
|
i=i+512
|
||||||
|
end
|
||||||
|
return buf
|
||||||
|
end
|
||||||
|
function bin:getMD5Hash()
|
||||||
|
self:setSeek(1)
|
||||||
|
local len=self:getSize()
|
||||||
|
local md5=bin.md5.new()
|
||||||
|
local SIZE=2048
|
||||||
|
if len>SIZE then
|
||||||
|
local dat=self:read(SIZE)
|
||||||
|
while dat~=nil do
|
||||||
|
md5:update(dat)
|
||||||
|
dat=self:read(SIZE)
|
||||||
|
end
|
||||||
|
return bin.md5.tohex(md5:finish()):upper()
|
||||||
|
else
|
||||||
|
return bin.md5.sumhexa(self:getData()):upper()
|
||||||
|
end
|
||||||
|
end
|
||||||
|
function bin:getHash()
|
||||||
|
if self:getSize()==0 then
|
||||||
|
return "NaN"
|
||||||
|
end
|
||||||
|
n=32
|
||||||
|
local rand = randomGen:newND(1,self:getSize(),self:getSize())
|
||||||
|
local h,g={},0
|
||||||
|
for i=1,n do
|
||||||
|
g=rand:nextInt()
|
||||||
|
table.insert(h,bin.toHex(self:sub(g,g)))
|
||||||
|
end
|
||||||
|
return table.concat(h,'')
|
||||||
|
end
|
||||||
|
function bin:flipbits()
|
||||||
|
if self:canStreamWrite() then
|
||||||
|
self:setSeek(1)
|
||||||
|
for i=1,self:getSize() do
|
||||||
|
self:write(string.char(255-string.byte(self:sub(i,i))))
|
||||||
|
end
|
||||||
|
else
|
||||||
|
local temp={}
|
||||||
|
for i=1,#self.data do
|
||||||
|
table.insert(temp,string.char(255-string.byte(string.sub(self.data,i,i))))
|
||||||
|
end
|
||||||
|
self.data=table.concat(temp,'')
|
||||||
|
end
|
||||||
|
end
|
||||||
|
function bin:encrypt()
|
||||||
|
self:flipbits()
|
||||||
|
end
|
||||||
|
function bin:decrypt()
|
||||||
|
self:flipbits()
|
||||||
|
end
|
||||||
|
-- Use with small files!
|
||||||
|
function bin:gsub(...)
|
||||||
|
local data=self:getData()
|
||||||
|
local pos=self:getSeek()
|
||||||
|
self:setSeek(1)
|
||||||
|
self:write((data:gsub(...)) or data)
|
||||||
|
self:setSeek(loc)
|
||||||
|
end
|
||||||
|
function bin:gmatch(pat)
|
||||||
|
return self:getData():gmatch(pat)
|
||||||
|
end
|
||||||
|
function bin:match(pat)
|
||||||
|
return self:getData():match(pat)
|
||||||
|
end
|
||||||
|
function bin:trim()
|
||||||
|
local data=self:getData()
|
||||||
|
local pos=self:getSeek()
|
||||||
|
self:setSeek(1)
|
||||||
|
self:write(data:match'^()%s*$' and '' or data:match'^%s*(.*%S)')
|
||||||
|
self:setSeek(loc)
|
||||||
|
end
|
||||||
|
function bin:lines()
|
||||||
|
local t = {}
|
||||||
|
local function helper(line) table.insert(t, line) return '' end
|
||||||
|
helper((self:getData():gsub('(.-)\r?\n', helper)))
|
||||||
|
return t
|
||||||
|
end
|
||||||
|
function bin._lines(str)
|
||||||
|
local t = {}
|
||||||
|
local function helper(line) table.insert(t, line) return '' end
|
||||||
|
helper((str:gsub('(.-)\r?\n', helper)))
|
||||||
|
return t
|
||||||
|
end
|
||||||
|
function bin:wipe()
|
||||||
|
if self:canStreamWrite() then
|
||||||
|
self:close()
|
||||||
|
local c=bin.freshStream(self.file)
|
||||||
|
self.workingfile=c.workingfile
|
||||||
|
else
|
||||||
|
self.data=""
|
||||||
|
end
|
||||||
|
self:setSeek(1)
|
||||||
|
end
|
||||||
|
function bin:fullTrim(empty)
|
||||||
|
local t=self:lines()
|
||||||
|
for i=#t,1,-1 do
|
||||||
|
t[i]=bin._trim(t[i])
|
||||||
|
if empty then
|
||||||
|
if t[i]=="" then
|
||||||
|
table.remove(t,i)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
self:wipe()
|
||||||
|
self:write(table.concat(t,"\n"))
|
||||||
|
end
|
||||||
|
require("bin.support.extraBlocks") -- registered blocks that you can use
|
||||||
|
if love then
|
||||||
|
function bin.load(file,s,r)
|
||||||
|
content, size = love.filesystem.read(file)
|
||||||
|
local temp=bin.new(content)
|
||||||
|
temp.filepath=file
|
||||||
|
return temp
|
||||||
|
end
|
||||||
|
function bin:tofile(filename)
|
||||||
|
if not(filename) or self.Stream then return nil end
|
||||||
|
love.filesystem.write(filename,self.data)
|
||||||
|
end
|
||||||
|
function bin.stream(file)
|
||||||
|
return bin.newStreamFileObject(love.filesystem.newFile(file))
|
||||||
|
end
|
||||||
|
function bin:getSize(fmt)
|
||||||
|
local len=0
|
||||||
|
if self.stream then
|
||||||
|
local len=self.workingfile:getSize()
|
||||||
|
else
|
||||||
|
len=#self.data
|
||||||
|
end
|
||||||
|
if fmt=="%b" then
|
||||||
|
return bin.toB64()
|
||||||
|
elseif fmt then
|
||||||
|
return string.format(fmt, len)
|
||||||
|
else
|
||||||
|
return len
|
||||||
|
end
|
||||||
|
end
|
||||||
|
function bin:getSeek()
|
||||||
|
if self.stream then
|
||||||
|
return self.workingfile:tell()+1
|
||||||
|
else
|
||||||
|
return self.pos
|
||||||
|
end
|
||||||
|
end
|
||||||
|
function bin:setSeek(n)
|
||||||
|
if self.stream then
|
||||||
|
self.workingfile:seek(n-1)
|
||||||
|
else
|
||||||
|
self.pos=n
|
||||||
|
end
|
||||||
|
end
|
||||||
|
function bin:seek(n)
|
||||||
|
if self.stream then
|
||||||
|
self.workingfile:seek(n)
|
||||||
|
else
|
||||||
|
if not n then return self.pos end
|
||||||
|
if #self.data-(self.pos-1)<n then
|
||||||
|
print(n-((#self.data)-(self.pos-1)))
|
||||||
|
self:write(string.rep("\0",n-((#self.data)-(self.pos-1))))
|
||||||
|
return
|
||||||
|
end
|
||||||
|
self.pos=self.pos+n
|
||||||
|
end
|
||||||
|
end
|
||||||
|
function bin:close()
|
||||||
|
self.workingfile:close()
|
||||||
|
end
|
||||||
|
end
|
||||||
@@ -0,0 +1,683 @@
|
|||||||
|
RADIX = 10^7 ;
|
||||||
|
RADIX_LEN = math.floor( math.log10 ( RADIX ) ) ;
|
||||||
|
|
||||||
|
BigNum = {} ;
|
||||||
|
BigNum.mt = {} ;
|
||||||
|
|
||||||
|
function BigNum.new( num ) --{{{2
|
||||||
|
local bignum = {} ;
|
||||||
|
setmetatable( bignum , BigNum.mt ) ;
|
||||||
|
BigNum.change( bignum , num ) ;
|
||||||
|
return bignum ;
|
||||||
|
end
|
||||||
|
|
||||||
|
function BigNum.mt.sub( num1 , num2 )
|
||||||
|
local temp = BigNum.new() ;
|
||||||
|
local bnum1 = BigNum.new( num1 ) ;
|
||||||
|
local bnum2 = BigNum.new( num2 ) ;
|
||||||
|
BigNum.sub( bnum1 , bnum2 , temp ) ;
|
||||||
|
return temp ;
|
||||||
|
end
|
||||||
|
function BigNum.mt.mod( num1 , num2 )
|
||||||
|
return BigNum.new(num1 - (num1/num2)*num2)
|
||||||
|
end
|
||||||
|
function BigNum.mt.add( num1 , num2 )
|
||||||
|
local temp = BigNum.new() ;
|
||||||
|
local bnum1 = BigNum.new( num1 ) ;
|
||||||
|
local bnum2 = BigNum.new( num2 ) ;
|
||||||
|
BigNum.add( bnum1 , bnum2 , temp ) ;
|
||||||
|
return temp ;
|
||||||
|
end
|
||||||
|
|
||||||
|
function BigNum.mt.mul( num1 , num2 )
|
||||||
|
local temp = BigNum.new() ;
|
||||||
|
local bnum1 = BigNum.new( num1 ) ;
|
||||||
|
local bnum2 = BigNum.new( num2 ) ;
|
||||||
|
BigNum.mul( bnum1 , bnum2 , temp ) ;
|
||||||
|
return temp ;
|
||||||
|
end
|
||||||
|
|
||||||
|
function BigNum.mt.div( num1 , num2 )
|
||||||
|
local bnum1 = {} ;
|
||||||
|
local bnum2 = {} ;
|
||||||
|
local bnum3 = BigNum.new() ;
|
||||||
|
local bnum4 = BigNum.new() ;
|
||||||
|
bnum1 = BigNum.new( num1 ) ;
|
||||||
|
bnum2 = BigNum.new( num2 ) ;
|
||||||
|
BigNum.div( bnum1 , bnum2 , bnum3 , bnum4 ) ;
|
||||||
|
return bnum3 , bnum4 ;
|
||||||
|
end
|
||||||
|
|
||||||
|
function BigNum.mt.tostring( bnum )
|
||||||
|
local i = 0 ;
|
||||||
|
local j = 0 ;
|
||||||
|
local str = "" ;
|
||||||
|
local temp = "" ;
|
||||||
|
if bnum == nil then
|
||||||
|
return "nil" ;
|
||||||
|
elseif bnum.len > 0 then
|
||||||
|
for i = bnum.len - 2 , 0 , -1 do
|
||||||
|
for j = 0 , RADIX_LEN - string.len( bnum[i] ) - 1 do
|
||||||
|
temp = temp .. '0' ;
|
||||||
|
end
|
||||||
|
temp = temp .. bnum[i] ;
|
||||||
|
end
|
||||||
|
if bnum[bnum.len - 1]==nil then
|
||||||
|
return "nil"
|
||||||
|
end
|
||||||
|
temp = bnum[bnum.len - 1] .. temp ;
|
||||||
|
if bnum.signal == '-' then
|
||||||
|
temp = bnum.signal .. temp ;
|
||||||
|
end
|
||||||
|
return temp ;
|
||||||
|
else
|
||||||
|
return "" ;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function BigNum.mt.pow( num1 , num2 )
|
||||||
|
local bnum1 = BigNum.new( num1 ) ;
|
||||||
|
local bnum2 = BigNum.new( num2 ) ;
|
||||||
|
return BigNum.pow( bnum1 , bnum2 ) ;
|
||||||
|
end
|
||||||
|
|
||||||
|
function BigNum.mt.eq( num1 , num2 )
|
||||||
|
local bnum1 = BigNum.new( num1 ) ;
|
||||||
|
local bnum2 = BigNum.new( num2 ) ;
|
||||||
|
return BigNum.eq( bnum1 , bnum2 ) ;
|
||||||
|
end
|
||||||
|
|
||||||
|
function BigNum.mt.lt( num1 , num2 )
|
||||||
|
local bnum1 = BigNum.new( num1 ) ;
|
||||||
|
local bnum2 = BigNum.new( num2 ) ;
|
||||||
|
return BigNum.lt( bnum1 , bnum2 ) ;
|
||||||
|
end
|
||||||
|
|
||||||
|
function BigNum.mt.le( num1 , num2 )
|
||||||
|
local bnum1 = BigNum.new( num1 ) ;
|
||||||
|
local bnum2 = BigNum.new( num2 ) ;
|
||||||
|
return BigNum.le( bnum1 , bnum2 ) ;
|
||||||
|
end
|
||||||
|
|
||||||
|
function BigNum.mt.unm( num )
|
||||||
|
local ret = BigNum.new( num )
|
||||||
|
if ret.signal == '+' then
|
||||||
|
ret.signal = '-'
|
||||||
|
else
|
||||||
|
ret.signal = '+'
|
||||||
|
end
|
||||||
|
return ret
|
||||||
|
end
|
||||||
|
|
||||||
|
BigNum.mt.__metatable = "hidden"
|
||||||
|
BigNum.mt.__tostring = BigNum.mt.tostring ;
|
||||||
|
BigNum.mt.__add = BigNum.mt.add ;
|
||||||
|
BigNum.mt.__sub = BigNum.mt.sub ;
|
||||||
|
BigNum.mt.__mul = BigNum.mt.mul ;
|
||||||
|
BigNum.mt.__div = BigNum.mt.div ;
|
||||||
|
BigNum.mt.__pow = BigNum.mt.pow ;
|
||||||
|
BigNum.mt.__unm = BigNum.mt.unm ;
|
||||||
|
BigNum.mt.__mod = BigNum.mt.mod ;
|
||||||
|
BigNum.mt.__eq = BigNum.mt.eq ;
|
||||||
|
BigNum.mt.__le = BigNum.mt.le ;
|
||||||
|
BigNum.mt.__lt = BigNum.mt.lt ;
|
||||||
|
setmetatable( BigNum.mt, { __index = "inexistent field", __newindex = "not available", __metatable="hidden" } ) ;
|
||||||
|
function BigNum.add( bnum1 , bnum2 , bnum3 )
|
||||||
|
local maxlen = 0 ;
|
||||||
|
local i = 0 ;
|
||||||
|
local carry = 0 ;
|
||||||
|
local signal = '+' ;
|
||||||
|
local old_len = 0 ;
|
||||||
|
--Handle the signals
|
||||||
|
if bnum1 == nil or bnum2 == nil or bnum3 == nil then
|
||||||
|
error("Function BigNum.add: parameter nil") ;
|
||||||
|
elseif bnum1.signal == '-' and bnum2.signal == '+' then
|
||||||
|
bnum1.signal = '+' ;
|
||||||
|
BigNum.sub( bnum2 , bnum1 , bnum3 ) ;
|
||||||
|
|
||||||
|
if not rawequal(bnum1, bnum3) then
|
||||||
|
bnum1.signal = '-' ;
|
||||||
|
end
|
||||||
|
return 0 ;
|
||||||
|
elseif bnum1.signal == '+' and bnum2.signal == '-' then
|
||||||
|
bnum2.signal = '+' ;
|
||||||
|
BigNum.sub( bnum1 , bnum2 , bnum3 ) ;
|
||||||
|
if not rawequal(bnum2, bnum3) then
|
||||||
|
bnum2.signal = '-' ;
|
||||||
|
end
|
||||||
|
return 0 ;
|
||||||
|
elseif bnum1.signal == '-' and bnum2.signal == '-' then
|
||||||
|
signal = '-' ;
|
||||||
|
end
|
||||||
|
--
|
||||||
|
old_len = bnum3.len ;
|
||||||
|
if bnum1.len > bnum2.len then
|
||||||
|
maxlen = bnum1.len ;
|
||||||
|
else
|
||||||
|
maxlen = bnum2.len ;
|
||||||
|
bnum1 , bnum2 = bnum2 , bnum1 ;
|
||||||
|
end
|
||||||
|
--School grade sum
|
||||||
|
for i = 0 , maxlen - 1 do
|
||||||
|
if bnum2[i] ~= nil then
|
||||||
|
bnum3[i] = bnum1[i] + bnum2[i] + carry ;
|
||||||
|
else
|
||||||
|
bnum3[i] = bnum1[i] + carry ;
|
||||||
|
end
|
||||||
|
if bnum3[i] >= RADIX then
|
||||||
|
bnum3[i] = bnum3[i] - RADIX ;
|
||||||
|
carry = 1 ;
|
||||||
|
else
|
||||||
|
carry = 0 ;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
--Update the answer's size
|
||||||
|
if carry == 1 then
|
||||||
|
bnum3[maxlen] = 1 ;
|
||||||
|
end
|
||||||
|
bnum3.len = maxlen + carry ;
|
||||||
|
bnum3.signal = signal ;
|
||||||
|
for i = bnum3.len, old_len do
|
||||||
|
bnum3[i] = nil ;
|
||||||
|
end
|
||||||
|
return 0 ;
|
||||||
|
end
|
||||||
|
|
||||||
|
function BigNum.sub( bnum1 , bnum2 , bnum3 )
|
||||||
|
local maxlen = 0 ;
|
||||||
|
local i = 0 ;
|
||||||
|
local carry = 0 ;
|
||||||
|
local old_len = 0 ;
|
||||||
|
if bnum1 == nil or bnum2 == nil or bnum3 == nil then
|
||||||
|
error("Function BigNum.sub: parameter nil") ;
|
||||||
|
elseif bnum1.signal == '-' and bnum2.signal == '+' then
|
||||||
|
bnum1.signal = '+' ;
|
||||||
|
BigNum.add( bnum1 , bnum2 , bnum3 ) ;
|
||||||
|
bnum3.signal = '-' ;
|
||||||
|
if not rawequal(bnum1, bnum3) then
|
||||||
|
bnum1.signal = '-' ;
|
||||||
|
end
|
||||||
|
return 0 ;
|
||||||
|
elseif bnum1.signal == '-' and bnum2.signal == '-' then
|
||||||
|
bnum1.signal = '+' ;
|
||||||
|
bnum2.signal = '+' ;
|
||||||
|
BigNum.sub( bnum2, bnum1 , bnum3 ) ;
|
||||||
|
if not rawequal(bnum1, bnum3) then
|
||||||
|
bnum1.signal = '-' ;
|
||||||
|
end
|
||||||
|
if not rawequal(bnum2, bnum3) then
|
||||||
|
bnum2.signal = '-' ;
|
||||||
|
end
|
||||||
|
return 0 ;
|
||||||
|
elseif bnum1.signal == '+' and bnum2.signal == '-' then
|
||||||
|
bnum2.signal = '+' ;
|
||||||
|
BigNum.add( bnum1 , bnum2 , bnum3 ) ;
|
||||||
|
if not rawequal(bnum2, bnum3) then
|
||||||
|
bnum2.signal = '-' ;
|
||||||
|
end
|
||||||
|
return 0 ;
|
||||||
|
end
|
||||||
|
--Tests if bnum2 > bnum1
|
||||||
|
if BigNum.compareAbs( bnum1 , bnum2 ) == 2 then
|
||||||
|
BigNum.sub( bnum2 , bnum1 , bnum3 ) ;
|
||||||
|
bnum3.signal = '-' ;
|
||||||
|
return 0 ;
|
||||||
|
else
|
||||||
|
maxlen = bnum1.len ;
|
||||||
|
end
|
||||||
|
old_len = bnum3.len ;
|
||||||
|
bnum3.len = 0 ;
|
||||||
|
--School grade subtraction
|
||||||
|
for i = 0 , maxlen - 1 do
|
||||||
|
if bnum2[i] ~= nil then
|
||||||
|
bnum3[i] = bnum1[i] - bnum2[i] - carry ;
|
||||||
|
else
|
||||||
|
bnum3[i] = bnum1[i] - carry ;
|
||||||
|
end
|
||||||
|
if bnum3[i] < 0 then
|
||||||
|
bnum3[i] = RADIX + bnum3[i] ;
|
||||||
|
carry = 1 ;
|
||||||
|
else
|
||||||
|
carry = 0 ;
|
||||||
|
end
|
||||||
|
|
||||||
|
if bnum3[i] ~= 0 then
|
||||||
|
bnum3.len = i + 1 ;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
bnum3.signal = '+' ;
|
||||||
|
--Check if answer's size if zero
|
||||||
|
if bnum3.len == 0 then
|
||||||
|
bnum3.len = 1 ;
|
||||||
|
bnum3[0] = 0 ;
|
||||||
|
end
|
||||||
|
if carry == 1 then
|
||||||
|
error( "Error in function sub" ) ;
|
||||||
|
end
|
||||||
|
for i = bnum3.len , max( old_len , maxlen - 1 ) do
|
||||||
|
bnum3[i] = nil ;
|
||||||
|
end
|
||||||
|
return 0 ;
|
||||||
|
end
|
||||||
|
|
||||||
|
function BigNum.mul( bnum1 , bnum2 , bnum3 )
|
||||||
|
local i = 0 ; j = 0 ;
|
||||||
|
local temp = BigNum.new( ) ;
|
||||||
|
local temp2 = 0 ;
|
||||||
|
local carry = 0 ;
|
||||||
|
local oldLen = bnum3.len ;
|
||||||
|
if bnum1 == nil or bnum2 == nil or bnum3 == nil then
|
||||||
|
error("Function BigNum.mul: parameter nil") ;
|
||||||
|
--Handle the signals
|
||||||
|
elseif bnum1.signal ~= bnum2.signal then
|
||||||
|
BigNum.mul( bnum1 , -bnum2 , bnum3 ) ;
|
||||||
|
bnum3.signal = '-' ;
|
||||||
|
return 0 ;
|
||||||
|
end
|
||||||
|
bnum3.len = ( bnum1.len ) + ( bnum2.len ) ;
|
||||||
|
--Fill with zeros
|
||||||
|
for i = 1 , bnum3.len do
|
||||||
|
bnum3[i - 1] = 0 ;
|
||||||
|
end
|
||||||
|
--Places nil where passes through this
|
||||||
|
for i = bnum3.len , oldLen do
|
||||||
|
bnum3[i] = nil ;
|
||||||
|
end
|
||||||
|
--School grade multiplication
|
||||||
|
for i = 0 , bnum1.len - 1 do
|
||||||
|
for j = 0 , bnum2.len - 1 do
|
||||||
|
carry = ( bnum1[i] * bnum2[j] + carry ) ;
|
||||||
|
carry = carry + bnum3[i + j] ;
|
||||||
|
bnum3[i + j] = ( carry % RADIX ) ;
|
||||||
|
temp2 = bnum3[i + j] ;
|
||||||
|
carry = math.floor ( carry / RADIX ) ;
|
||||||
|
end
|
||||||
|
if carry ~= 0 then
|
||||||
|
bnum3[i + bnum2.len] = carry ;
|
||||||
|
end
|
||||||
|
carry = 0 ;
|
||||||
|
end
|
||||||
|
|
||||||
|
--Update the answer's size
|
||||||
|
for i = bnum3.len - 1 , 1 , -1 do
|
||||||
|
if bnum3[i] ~= nil and bnum3[i] ~= 0 then
|
||||||
|
break ;
|
||||||
|
else
|
||||||
|
bnum3[i] = nil ;
|
||||||
|
end
|
||||||
|
bnum3.len = bnum3.len - 1 ;
|
||||||
|
end
|
||||||
|
return 0 ;
|
||||||
|
end
|
||||||
|
|
||||||
|
function BigNum.div( bnum1 , bnum2 , bnum3 , bnum4 )
|
||||||
|
local temp = BigNum.new() ;
|
||||||
|
local temp2 = BigNum.new() ;
|
||||||
|
local one = BigNum.new( "1" ) ;
|
||||||
|
local zero = BigNum.new( "0" ) ;
|
||||||
|
--Check division by zero
|
||||||
|
if BigNum.compareAbs( bnum2 , zero ) == 0 then
|
||||||
|
error( "Function BigNum.div: Division by zero" ) ;
|
||||||
|
end
|
||||||
|
--Handle the signals
|
||||||
|
if bnum1 == nil or bnum2 == nil or bnum3 == nil or bnum4 == nil then
|
||||||
|
error( "Function BigNum.div: parameter nil" ) ;
|
||||||
|
elseif bnum1.signal == "+" and bnum2.signal == "-" then
|
||||||
|
bnum2.signal = "+" ;
|
||||||
|
BigNum.div( bnum1 , bnum2 , bnum3 , bnum4 ) ;
|
||||||
|
bnum2.signal = "-" ;
|
||||||
|
bnum3.signal = "-" ;
|
||||||
|
return 0 ;
|
||||||
|
elseif bnum1.signal == "-" and bnum2.signal == "+" then
|
||||||
|
bnum1.signal = "+" ;
|
||||||
|
BigNum.div( bnum1 , bnum2 , bnum3 , bnum4 ) ;
|
||||||
|
bnum1.signal = "-" ;
|
||||||
|
if bnum4 < zero then --Check if remainder is negative
|
||||||
|
BigNum.add( bnum3 , one , bnum3 ) ;
|
||||||
|
BigNum.sub( bnum2 , bnum4 , bnum4 ) ;
|
||||||
|
end
|
||||||
|
bnum3.signal = "-" ;
|
||||||
|
return 0 ;
|
||||||
|
elseif bnum1.signal == "-" and bnum2.signal == "-" then
|
||||||
|
bnum1.signal = "+" ;
|
||||||
|
bnum2.signal = "+" ;
|
||||||
|
BigNum.div( bnum1 , bnum2 , bnum3 , bnum4 ) ;
|
||||||
|
bnum1.signal = "-" ;
|
||||||
|
if bnum4 < zero then --Check if remainder is negative
|
||||||
|
BigNum.add( bnum3 , one , bnum3 ) ;
|
||||||
|
BigNum.sub( bnum2 , bnum4 , bnum4 ) ;
|
||||||
|
end
|
||||||
|
bnum2.signal = "-" ;
|
||||||
|
return 0 ;
|
||||||
|
end
|
||||||
|
temp.len = bnum1.len - bnum2.len - 1 ;
|
||||||
|
|
||||||
|
--Reset variables
|
||||||
|
BigNum.change( bnum3 , "0" ) ;
|
||||||
|
BigNum.change( bnum4 , "0" ) ;
|
||||||
|
|
||||||
|
BigNum.copy( bnum1 , bnum4 ) ;
|
||||||
|
|
||||||
|
--Check if can continue dividing
|
||||||
|
while( BigNum.compareAbs( bnum4 , bnum2 ) ~= 2 ) do
|
||||||
|
if bnum4[bnum4.len - 1] >= bnum2[bnum2.len - 1] then
|
||||||
|
BigNum.put( temp , math.floor( bnum4[bnum4.len - 1] / bnum2[bnum2.len - 1] ) , bnum4.len - bnum2.len ) ;
|
||||||
|
temp.len = bnum4.len - bnum2.len + 1 ;
|
||||||
|
else
|
||||||
|
BigNum.put( temp , math.floor( ( bnum4[bnum4.len - 1] * RADIX + bnum4[bnum4.len - 2] ) / bnum2[bnum2.len -1] ) , bnum4.len - bnum2.len - 1 ) ;
|
||||||
|
temp.len = bnum4.len - bnum2.len ;
|
||||||
|
end
|
||||||
|
|
||||||
|
if bnum4.signal ~= bnum2.signal then
|
||||||
|
temp.signal = "-";
|
||||||
|
else
|
||||||
|
temp.signal = "+";
|
||||||
|
end
|
||||||
|
BigNum.add( temp , bnum3 , bnum3 ) ;
|
||||||
|
temp = temp * bnum2 ;
|
||||||
|
BigNum.sub( bnum4 , temp , bnum4 ) ;
|
||||||
|
end
|
||||||
|
|
||||||
|
--Update if the remainder is negative
|
||||||
|
if bnum4.signal == '-' then
|
||||||
|
decr( bnum3 ) ;
|
||||||
|
BigNum.add( bnum2 , bnum4 , bnum4 ) ;
|
||||||
|
end
|
||||||
|
return 0 ;
|
||||||
|
end
|
||||||
|
|
||||||
|
function BigNum.pow( bnum1 , bnum2 )
|
||||||
|
local n = BigNum.new( bnum2 ) ;
|
||||||
|
local y = BigNum.new( 1 ) ;
|
||||||
|
local z = BigNum.new( bnum1 ) ;
|
||||||
|
local zero = BigNum.new( "0" ) ;
|
||||||
|
if bnum2 < zero then
|
||||||
|
error( "Function BigNum.exp: domain error" ) ;
|
||||||
|
elseif bnum2 == zero then
|
||||||
|
return y ;
|
||||||
|
end
|
||||||
|
while 1 do
|
||||||
|
if ( n[0] % 2 ) == 0 then
|
||||||
|
n = n / 2 ;
|
||||||
|
else
|
||||||
|
n = n / 2 ;
|
||||||
|
y = z * y ;
|
||||||
|
if n == zero then
|
||||||
|
return y ;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
z = z * z ;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
-- Português :
|
||||||
|
BigNum.exp = BigNum.pow
|
||||||
|
|
||||||
|
function BigNum.gcd( bnum1 , bnum2 )
|
||||||
|
local a = {} ;
|
||||||
|
local b = {} ;
|
||||||
|
local c = {} ;
|
||||||
|
local d = {} ;
|
||||||
|
local zero = {} ;
|
||||||
|
zero = BigNum.new( "0" ) ;
|
||||||
|
if bnum1 == zero or bnum2 == zero then
|
||||||
|
return BigNum.new( "1" ) ;
|
||||||
|
end
|
||||||
|
a = BigNum.new( bnum1 ) ;
|
||||||
|
b = BigNum.new( bnum2 ) ;
|
||||||
|
a.signal = '+' ;
|
||||||
|
b.signal = '+' ;
|
||||||
|
c = BigNum.new() ;
|
||||||
|
d = BigNum.new() ;
|
||||||
|
while b > zero do
|
||||||
|
BigNum.div( a , b , c , d ) ;
|
||||||
|
a , b , d = b , d , a ;
|
||||||
|
end
|
||||||
|
return a ;
|
||||||
|
end
|
||||||
|
-- Português:
|
||||||
|
BigNum.mmc = BigNum.gcd
|
||||||
|
|
||||||
|
function BigNum.eq( bnum1 , bnum2 )
|
||||||
|
if BigNum.compare( bnum1 , bnum2 ) == 0 then
|
||||||
|
return true ;
|
||||||
|
else
|
||||||
|
return false ;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function BigNum.lt( bnum1 , bnum2 )
|
||||||
|
if BigNum.compare( bnum1 , bnum2 ) == 2 then
|
||||||
|
return true ;
|
||||||
|
else
|
||||||
|
return false ;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function BigNum.le( bnum1 , bnum2 )
|
||||||
|
local temp = -1 ;
|
||||||
|
temp = BigNum.compare( bnum1 , bnum2 )
|
||||||
|
if temp == 0 or temp == 2 then
|
||||||
|
return true ;
|
||||||
|
else
|
||||||
|
return false ;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function BigNum.compareAbs( bnum1 , bnum2 )
|
||||||
|
if bnum1 == nil or bnum2 == nil then
|
||||||
|
error("Function compare: parameter nil") ;
|
||||||
|
elseif bnum1.len > bnum2.len then
|
||||||
|
return 1 ;
|
||||||
|
elseif bnum1.len < bnum2.len then
|
||||||
|
return 2 ;
|
||||||
|
else
|
||||||
|
local i ;
|
||||||
|
for i = bnum1.len - 1 , 0 , -1 do
|
||||||
|
if bnum1[i] > bnum2[i] then
|
||||||
|
return 1 ;
|
||||||
|
elseif bnum1[i] < bnum2[i] then
|
||||||
|
return 2 ;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return 0 ;
|
||||||
|
end
|
||||||
|
|
||||||
|
function BigNum.compare( bnum1 , bnum2 )
|
||||||
|
local signal = 0 ;
|
||||||
|
|
||||||
|
if bnum1 == nil or bnum2 == nil then
|
||||||
|
error("Funtion BigNum.compare: parameter nil") ;
|
||||||
|
elseif bnum1.signal == '+' and bnum2.signal == '-' then
|
||||||
|
return 1 ;
|
||||||
|
elseif bnum1.signal == '-' and bnum2.signal == '+' then
|
||||||
|
return 2 ;
|
||||||
|
elseif bnum1.signal == '-' and bnum2.signal == '-' then
|
||||||
|
signal = 1 ;
|
||||||
|
end
|
||||||
|
if bnum1.len > bnum2.len then
|
||||||
|
return 1 + signal ;
|
||||||
|
elseif bnum1.len < bnum2.len then
|
||||||
|
return 2 - signal ;
|
||||||
|
else
|
||||||
|
local i ;
|
||||||
|
for i = bnum1.len - 1 , 0 , -1 do
|
||||||
|
if bnum1[i] > bnum2[i] then
|
||||||
|
return 1 + signal ;
|
||||||
|
elseif bnum1[i] < bnum2[i] then
|
||||||
|
return 2 - signal ;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return 0 ;
|
||||||
|
end
|
||||||
|
|
||||||
|
function BigNum.copy( bnum1 , bnum2 )
|
||||||
|
if bnum1 ~= nil and bnum2 ~= nil then
|
||||||
|
local i ;
|
||||||
|
for i = 0 , bnum1.len - 1 do
|
||||||
|
bnum2[i] = bnum1[i] ;
|
||||||
|
end
|
||||||
|
bnum2.len = bnum1.len ;
|
||||||
|
else
|
||||||
|
error("Function BigNum.copy: parameter nil") ;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function BigNum.change( bnum1 , num )
|
||||||
|
local j = 0 ;
|
||||||
|
local len = 0 ;
|
||||||
|
local num = num ;
|
||||||
|
local l ;
|
||||||
|
local oldLen = 0 ;
|
||||||
|
if bnum1 == nil then
|
||||||
|
error( "BigNum.change: parameter nil" ) ;
|
||||||
|
elseif type( bnum1 ) ~= "table" then
|
||||||
|
error( "BigNum.change: parameter error, type unexpected" ) ;
|
||||||
|
elseif num == nil then
|
||||||
|
bnum1.len = 1 ;
|
||||||
|
bnum1[0] = 0 ;
|
||||||
|
bnum1.signal = "+";
|
||||||
|
elseif type( num ) == "table" and num.len ~= nil then --check if num is a big number
|
||||||
|
--copy given table to the new one
|
||||||
|
for i = 0 , num.len do
|
||||||
|
bnum1[i] = num[i] ;
|
||||||
|
end
|
||||||
|
if num.signal ~= '-' and num.signal ~= '+' then
|
||||||
|
bnum1.signal = '+' ;
|
||||||
|
else
|
||||||
|
bnum1.signal = num.signal ;
|
||||||
|
end
|
||||||
|
oldLen = bnum1.len ;
|
||||||
|
bnum1.len = num.len ;
|
||||||
|
elseif type( num ) == "string" or type( num ) == "number" then
|
||||||
|
if string.sub( num , 1 , 1 ) == '+' or string.sub( num , 1 , 1 ) == '-' then
|
||||||
|
bnum1.signal = string.sub( num , 1 , 1 ) ;
|
||||||
|
num = string.sub(num, 2) ;
|
||||||
|
else
|
||||||
|
bnum1.signal = '+' ;
|
||||||
|
end
|
||||||
|
num = string.gsub( num , " " , "" ) ;
|
||||||
|
local sf = string.find( num , "e" ) ;
|
||||||
|
--Handles if the number is in exp notation
|
||||||
|
if sf ~= nil then
|
||||||
|
num = string.gsub( num , "%." , "" ) ;
|
||||||
|
local e = string.sub( num , sf + 1 ) ;
|
||||||
|
e = tonumber(e) ;
|
||||||
|
if e ~= nil and e > 0 then
|
||||||
|
e = tonumber(e) ;
|
||||||
|
else
|
||||||
|
error( "Function BigNum.change: string is not a valid number" ) ;
|
||||||
|
end
|
||||||
|
num = string.sub( num , 1 , sf - 2 ) ;
|
||||||
|
for i = string.len( num ) , e do
|
||||||
|
num = num .. "0" ;
|
||||||
|
end
|
||||||
|
else
|
||||||
|
sf = string.find( num , "%." ) ;
|
||||||
|
if sf ~= nil then
|
||||||
|
num = string.sub( num , 1 , sf - 1 ) ;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
l = string.len( num ) ;
|
||||||
|
oldLen = bnum1.len ;
|
||||||
|
if (l > RADIX_LEN) then
|
||||||
|
local mod = l-( math.floor( l / RADIX_LEN ) * RADIX_LEN ) ;
|
||||||
|
for i = 1 , l-mod, RADIX_LEN do
|
||||||
|
bnum1[j] = tonumber( string.sub( num, -( i + RADIX_LEN - 1 ) , -i ) );
|
||||||
|
--Check if string dosn't represents a number
|
||||||
|
if bnum1[j] == nil then
|
||||||
|
error( "Function BigNum.change: string is not a valid number" ) ;
|
||||||
|
bnum1.len = 0 ;
|
||||||
|
return 1 ;
|
||||||
|
end
|
||||||
|
j = j + 1 ;
|
||||||
|
len = len + 1 ;
|
||||||
|
end
|
||||||
|
if (mod ~= 0) then
|
||||||
|
bnum1[j] = tonumber( string.sub( num , 1 , mod ) ) ;
|
||||||
|
bnum1.len = len + 1 ;
|
||||||
|
else
|
||||||
|
bnum1.len = len ;
|
||||||
|
end
|
||||||
|
--Eliminate trailing zeros
|
||||||
|
for i = bnum1.len - 1 , 1 , -1 do
|
||||||
|
if bnum1[i] == 0 then
|
||||||
|
bnum1[i] = nil ;
|
||||||
|
bnum1.len = bnum1.len - 1 ;
|
||||||
|
else
|
||||||
|
break ;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
else
|
||||||
|
-- string.len(num) <= RADIX_LEN
|
||||||
|
bnum1[j] = tonumber( num ) ;
|
||||||
|
bnum1.len = 1 ;
|
||||||
|
end
|
||||||
|
else
|
||||||
|
error( "Function BigNum.change: parameter error, type unexpected" ) ;
|
||||||
|
end
|
||||||
|
|
||||||
|
--eliminates the deprecated higher order 'algarisms'
|
||||||
|
if oldLen ~= nil then
|
||||||
|
for i = bnum1.len , oldLen do
|
||||||
|
bnum1[i] = nil ;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
return 0 ;
|
||||||
|
end
|
||||||
|
|
||||||
|
function BigNum.put( bnum , int , pos )
|
||||||
|
if bnum == nil then
|
||||||
|
error("Function BigNum.put: parameter nil") ;
|
||||||
|
end
|
||||||
|
local i = 0 ;
|
||||||
|
for i = 0 , pos - 1 do
|
||||||
|
bnum[i] = 0 ;
|
||||||
|
end
|
||||||
|
bnum[pos] = int ;
|
||||||
|
for i = pos + 1 , bnum.len do
|
||||||
|
bnum[i] = nil ;
|
||||||
|
end
|
||||||
|
bnum.len = pos ;
|
||||||
|
return 0 ;
|
||||||
|
end
|
||||||
|
|
||||||
|
--printraw{{{2
|
||||||
|
function printraw( bnum )
|
||||||
|
local i = 0 ;
|
||||||
|
if bnum == nil then
|
||||||
|
error( "Function printraw: parameter nil" ) ;
|
||||||
|
end
|
||||||
|
while 1 == 1 do
|
||||||
|
if bnum[i] == nil then
|
||||||
|
io.write( ' len '..bnum.len ) ;
|
||||||
|
if i ~= bnum.len then
|
||||||
|
io.write( ' ERRO!!!!!!!!' ) ;
|
||||||
|
end
|
||||||
|
io.write( "\n" ) ;
|
||||||
|
return 0 ;
|
||||||
|
end
|
||||||
|
io.write( 'r'..bnum[i] ) ;
|
||||||
|
i = i + 1 ;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
--max{{{2
|
||||||
|
function max( int1 , int2 )
|
||||||
|
if int1 > int2 then
|
||||||
|
return int1 ;
|
||||||
|
else
|
||||||
|
return int2 ;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
--decr{{{2
|
||||||
|
function decr( bnum1 )
|
||||||
|
local temp = {} ;
|
||||||
|
temp = BigNum.new( "1" ) ;
|
||||||
|
BigNum.sub( bnum1 , temp , bnum1 ) ;
|
||||||
|
return 0 ;
|
||||||
|
end
|
||||||
@@ -0,0 +1,227 @@
|
|||||||
|
require( "bin.numbers.BigNum" ) ;
|
||||||
|
|
||||||
|
BigRat = {} ;
|
||||||
|
BigRat.mt = {} ;
|
||||||
|
function BigRat.new( num1 , num2 ) --{{{2
|
||||||
|
local bigrat = {} ;
|
||||||
|
local f ;
|
||||||
|
setmetatable(bigrat, BigRat.mt) ;
|
||||||
|
if type( num1 ) == "table" then
|
||||||
|
if num1.num ~= nil and num1.den ~= nil then
|
||||||
|
bigrat.num = BigNum.new( num1.num ) ;
|
||||||
|
bigrat.den = BigNum.new( num1.den ) ;
|
||||||
|
else
|
||||||
|
bigrat.num = BigNum.new( num1 ) ;
|
||||||
|
bigrat.den = BigNum.new( "1" ) ;
|
||||||
|
end
|
||||||
|
elseif num1 ~= nil then
|
||||||
|
if num2 == nil then
|
||||||
|
bigrat.den = BigNum.new( "1" ) ;
|
||||||
|
else
|
||||||
|
bigrat.den = BigNum.new( num2 ) ;
|
||||||
|
end
|
||||||
|
bigrat.num = BigNum.new( num1 ) ;
|
||||||
|
else
|
||||||
|
bigrat.den = BigNum.new( ) ;
|
||||||
|
bigrat.num = BigNum.new( ) ;
|
||||||
|
end
|
||||||
|
|
||||||
|
--Update the signals
|
||||||
|
if bigrat.den.signal == "-" then
|
||||||
|
if bigrat.num.signal == "-" then
|
||||||
|
bigrat.num.signal = "+" ;
|
||||||
|
else
|
||||||
|
bigrat.num.signal = "-" ;
|
||||||
|
end
|
||||||
|
bigrat.den.signal = "+" ;
|
||||||
|
end
|
||||||
|
|
||||||
|
return bigrat ;
|
||||||
|
end
|
||||||
|
|
||||||
|
function BigRat.mt.sub( num1 , num2 )
|
||||||
|
local temp = BigRat.new() ;
|
||||||
|
local brat1 = BigRat.new( num1 ) ;
|
||||||
|
local brat2 = BigRat.new( num2 ) ;
|
||||||
|
BigRat.sub( brat1 , brat2 , temp ) ;
|
||||||
|
return temp ;
|
||||||
|
end
|
||||||
|
|
||||||
|
function BigRat.mt.add( num1 , num2 )
|
||||||
|
local temp = BigRat.new() ;
|
||||||
|
local brat1 = BigRat.new( num1 ) ;
|
||||||
|
local brat2 = BigRat.new( num2 ) ;
|
||||||
|
BigRat.add( brat1 , brat2 , temp ) ;
|
||||||
|
return temp ;
|
||||||
|
end
|
||||||
|
|
||||||
|
function BigRat.mt.mul( num1 , num2 )
|
||||||
|
local temp = BigRat.new() ;
|
||||||
|
local brat1 = BigRat.new( num1 ) ;
|
||||||
|
local brat2 = BigRat.new( num2 ) ;
|
||||||
|
BigRat.mul( brat1 , brat2 , temp ) ;
|
||||||
|
return temp ;
|
||||||
|
end
|
||||||
|
|
||||||
|
function BigRat.mt.div( num1 , num2 )
|
||||||
|
local brat1 = BigRat.new( num1 ) ;
|
||||||
|
local brat2 = BigRat.new( num2 ) ;
|
||||||
|
local brat3 = BigRat.new() ;
|
||||||
|
local brat4 = BigRat.new() ;
|
||||||
|
BigRat.div( brat1 , brat2 , brat3 , brat4 ) ;
|
||||||
|
return brat3 , brat4 ;
|
||||||
|
end
|
||||||
|
|
||||||
|
function BigRat.mt.tostring( brat )
|
||||||
|
BigRat.simplify( brat ) ;
|
||||||
|
return BigNum.mt.tostring( brat.num ) .. " / " .. BigNum.mt.tostring( brat.den ) ;
|
||||||
|
end
|
||||||
|
|
||||||
|
function BigRat.mt.pow ( num1 , num2 )
|
||||||
|
local brat1 = BigRat.new( num1 ) ;
|
||||||
|
local brat2 = BigRat.new( num2 ) ;
|
||||||
|
return BigRat.pow( brat1 , brat2 )
|
||||||
|
end
|
||||||
|
|
||||||
|
function BigRat.mt.eq ( num1 , num2 )
|
||||||
|
return BigRat.eq( num1 , num2 )
|
||||||
|
end
|
||||||
|
|
||||||
|
function BigRat.mt.lt ( num1 , num2 )
|
||||||
|
return BigRat.lt( num1 , num2 )
|
||||||
|
end
|
||||||
|
|
||||||
|
function BigRat.mt.le ( num1 , num2 )
|
||||||
|
return BigRat.le( num1 , num2 )
|
||||||
|
end
|
||||||
|
|
||||||
|
function BigRat.mt.unm ( num )
|
||||||
|
local ret = BigRat.new( num )
|
||||||
|
if ret.num.signal == '-' then
|
||||||
|
ret.num.signal = '+'
|
||||||
|
else
|
||||||
|
ret.num.signal = '-'
|
||||||
|
end
|
||||||
|
return ret
|
||||||
|
end
|
||||||
|
|
||||||
|
BigRat.mt.__metatable = "hidden"
|
||||||
|
BigRat.mt.__tostring = BigRat.mt.tostring
|
||||||
|
BigRat.mt.__add = BigRat.mt.add
|
||||||
|
BigRat.mt.__sub = BigRat.mt.sub
|
||||||
|
BigRat.mt.__mul = BigRat.mt.mul
|
||||||
|
BigRat.mt.__div = BigRat.mt.div
|
||||||
|
BigRat.mt.__pow = BigRat.mt.pow
|
||||||
|
BigRat.mt.__unm = BigRat.mt.unm
|
||||||
|
BigRat.mt.__eq = BigRat.mt.eq
|
||||||
|
BigRat.mt.__le = BigRat.mt.le
|
||||||
|
BigRat.mt.__lt = BigRat.mt.lt
|
||||||
|
setmetatable( BigRat.mt, { __index = "inexistent field", __newindex = "not available", __metatable="hidden" } ) ;
|
||||||
|
function BigRat.add( brat1 , brat2 , brat3 )
|
||||||
|
brat3.den = brat1.den * brat2.den ;
|
||||||
|
brat3.num = ( brat1.num * brat2.den ) + ( brat2.num * brat1.den ) ;
|
||||||
|
return brat3 ;
|
||||||
|
end
|
||||||
|
function BigRat.sub( brat1 , brat2 , brat3 )
|
||||||
|
brat3.den = brat1.den * brat2.den ;
|
||||||
|
brat3.num = ( brat1.num * brat2.den ) - ( brat2.num * brat1.den ) ;
|
||||||
|
return brat3 ;
|
||||||
|
end
|
||||||
|
|
||||||
|
function BigRat.mul( brat1 , brat2 , brat3 )
|
||||||
|
brat3.num = brat1.num * brat2.num ;
|
||||||
|
brat3.den = brat1.den * brat2.den ;
|
||||||
|
return 0 ;
|
||||||
|
end
|
||||||
|
|
||||||
|
function BigRat.div( brat1 , brat2 , brat3 )
|
||||||
|
brat3.num = brat1.num * brat2.den ;
|
||||||
|
brat3.den = brat1.den * brat2.num ;
|
||||||
|
return brat3 ;
|
||||||
|
end
|
||||||
|
|
||||||
|
function BigRat.pow( bnum1 , bnum2 )
|
||||||
|
if bnum1 == nil or bnum2 == nil then
|
||||||
|
error( "Function BigRat.pow: parameter nil" ) ;
|
||||||
|
end
|
||||||
|
local x = BigRat.new( "8" ) ;
|
||||||
|
local n = BigRat.new( bnum2.den ) ;
|
||||||
|
local n2 ;
|
||||||
|
local y = BigRat.new( ) ;
|
||||||
|
local i ;
|
||||||
|
local temp = BigRat.new( ) ;
|
||||||
|
|
||||||
|
BigRat.simplify( bnum2 ) ;
|
||||||
|
temp.num = BigNum.exp( bnum1.num , bnum2.num ) ;
|
||||||
|
temp.den = BigNum.exp( bnum1.den , bnum2.num ) ;
|
||||||
|
n2 = n - 1 ;
|
||||||
|
|
||||||
|
for i = 0 , 4 do
|
||||||
|
y.num = x.num ^ n2.num ;
|
||||||
|
y.den = x.den ^ n2.num ;
|
||||||
|
x = (( temp / y ) + ( n2 * x )) / n ;
|
||||||
|
end
|
||||||
|
return x ;
|
||||||
|
end
|
||||||
|
|
||||||
|
function BigRat.simplify( brat )
|
||||||
|
if brat == nil then
|
||||||
|
error( "Function BigRat.simplify: parameter nil" ) ;
|
||||||
|
end
|
||||||
|
local gcd = BigNum.new( ) ;
|
||||||
|
local temp = BigRat.new( brat ) ;
|
||||||
|
local devnull = BigNum.new( ) ;
|
||||||
|
local zero = BigNum.new( "0" ) ;
|
||||||
|
--Check if numerator is zero
|
||||||
|
if BigNum.compareAbs( brat.num , zero ) == 0 then
|
||||||
|
brat.den = BigNum.new( "1" ) ;
|
||||||
|
return 0 ;
|
||||||
|
end
|
||||||
|
gcd = BigNum.gcd( brat.num , brat.den ) ;
|
||||||
|
BigNum.div( temp.num , gcd , brat.num , devnull ) ;
|
||||||
|
BigNum.div( temp.den , gcd , brat.den , devnull ) ;
|
||||||
|
--Update the signal
|
||||||
|
if brat.num.signal == '-' and brat.den.signal == '-' then
|
||||||
|
brat.num.signal = '+' ;
|
||||||
|
brat.den.signal = '+' ;
|
||||||
|
end
|
||||||
|
return 0 ;
|
||||||
|
end
|
||||||
|
|
||||||
|
function BigRat.eq( brat1 , brat2 )
|
||||||
|
if BigRat.compare( brat1 , brat2 ) == 0 then
|
||||||
|
return true ;
|
||||||
|
else
|
||||||
|
return false ;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function BigRat.lt( brat1 , brat2 )
|
||||||
|
if BigRat.compare( brat1 , brat2 ) == 2 then
|
||||||
|
return true ;
|
||||||
|
else
|
||||||
|
return false ;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function BigRat.le( brat1 , brat2 )
|
||||||
|
local temp = -1 ;
|
||||||
|
temp = BigRat.compare( brat1 , brat2 )
|
||||||
|
if temp == 0 or temp == 2 then
|
||||||
|
return true ;
|
||||||
|
else
|
||||||
|
return false ;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function BigRat.compare( bnum1 , bnum2 )
|
||||||
|
local temp ;
|
||||||
|
temp = bnum1 - bnum2 ;
|
||||||
|
if temp.num[0] == 0 and temp.num.len == 1 then --Check if is zero
|
||||||
|
return 0 ;
|
||||||
|
elseif temp.num.signal == "-" then
|
||||||
|
return 2 ;
|
||||||
|
else
|
||||||
|
return 1 ;
|
||||||
|
end
|
||||||
|
end
|
||||||
@@ -0,0 +1,191 @@
|
|||||||
|
local bits={}
|
||||||
|
bits.data=''
|
||||||
|
bits.t='bits'
|
||||||
|
bits.Type='bits'
|
||||||
|
bits.__index = bits
|
||||||
|
bits.__tostring=function(self) return self.data end
|
||||||
|
bits.__len=function(self) return (#self.data)/8 end
|
||||||
|
local floor,insert = math.floor, table.insert
|
||||||
|
function bits.newBitBuffer(n)
|
||||||
|
--
|
||||||
|
end
|
||||||
|
function bits.newConverter(bitsIn,bitsOut)
|
||||||
|
local c={}
|
||||||
|
--
|
||||||
|
end
|
||||||
|
function basen(n,b)
|
||||||
|
if not b or b == 10 then return tostring(n) end
|
||||||
|
local digits = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
||||||
|
local t = {}
|
||||||
|
local sign = ""
|
||||||
|
if n < 0 then
|
||||||
|
sign = "-"
|
||||||
|
n = -n
|
||||||
|
end
|
||||||
|
repeat
|
||||||
|
local d = n % b + 1
|
||||||
|
n = n / b
|
||||||
|
insert(t, 1, digits:sub(d,d))
|
||||||
|
until n == 0
|
||||||
|
return sign .. table.concat(t,"")
|
||||||
|
end
|
||||||
|
bits.ref={}
|
||||||
|
function bits.newByte(d)
|
||||||
|
local c={}
|
||||||
|
if type(d)=="string" then
|
||||||
|
if #d>1 or #d<1 then
|
||||||
|
error("A byte must be one character!")
|
||||||
|
else
|
||||||
|
c.data=string.byte(d)
|
||||||
|
end
|
||||||
|
elseif type(d)=="number" then
|
||||||
|
if d>255 or d<0 then
|
||||||
|
error("A byte must be between 0 and 255!")
|
||||||
|
else
|
||||||
|
c.data=d
|
||||||
|
end
|
||||||
|
else
|
||||||
|
error("cannot use type "..type(d).." as an argument! Takes only strings or numbers!")
|
||||||
|
end
|
||||||
|
c.__index=function(self,k)
|
||||||
|
if k>=0 and k<9 then
|
||||||
|
if self.data==0 then
|
||||||
|
return 0
|
||||||
|
elseif self.data==255 then
|
||||||
|
return 1
|
||||||
|
else
|
||||||
|
return bits.ref[self.data][k]
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
c.__tostring=function(self)
|
||||||
|
return bits.ref[tostring(self.data)]
|
||||||
|
end
|
||||||
|
setmetatable(c,c)
|
||||||
|
return c
|
||||||
|
end
|
||||||
|
function bits.newByteArray(s)
|
||||||
|
local c={}
|
||||||
|
if type(s)~="string" then
|
||||||
|
error("Must be a string type or bin/buffer type")
|
||||||
|
elseif type(s)=="table" then
|
||||||
|
if s.t=="sink" or s.t=="buffer" or s.t=="bin" then
|
||||||
|
local data=s:getData()
|
||||||
|
for i=1,#data do
|
||||||
|
c[#c+1]=bits.newByte(data:sub(i,i))
|
||||||
|
end
|
||||||
|
else
|
||||||
|
error("Must be a string type or bin/buffer type")
|
||||||
|
end
|
||||||
|
else
|
||||||
|
for i=1,#s do
|
||||||
|
c[#c+1]=bits.newByte(s:sub(i,i))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return c
|
||||||
|
end
|
||||||
|
function bits.new(n,binary)
|
||||||
|
local temp={}
|
||||||
|
temp.t="bits"
|
||||||
|
temp.Type="bits"
|
||||||
|
if type(n)=="string" then
|
||||||
|
if binary then
|
||||||
|
temp.data=n:match("[10]+")
|
||||||
|
else
|
||||||
|
local t={}
|
||||||
|
for i=#n,1,-1 do
|
||||||
|
table.insert(t,bits:conv(string.byte(n,i)))
|
||||||
|
end
|
||||||
|
temp.data=table.concat(t)
|
||||||
|
end
|
||||||
|
elseif type(n)=="number" or type(n)=="table" then
|
||||||
|
temp.data=basen(n,2)
|
||||||
|
end
|
||||||
|
if #temp.data%8~=0 then
|
||||||
|
temp.data=string.rep('0',8-#temp.data%8)..temp.data
|
||||||
|
end
|
||||||
|
setmetatable(temp, bits)
|
||||||
|
return temp
|
||||||
|
end
|
||||||
|
for i=0,255 do
|
||||||
|
local d=bits.new(i).data
|
||||||
|
bits.ref[i]={d:match("(%d)(%d)(%d)(%d)(%d)(%d)(%d)(%d)")}
|
||||||
|
bits.ref[tostring(i)]=d
|
||||||
|
bits.ref[d]=i
|
||||||
|
bits.ref["\255"..string.char(i)]=d
|
||||||
|
end
|
||||||
|
function bits.numToBytes(n,fit,func)
|
||||||
|
local num=string.reverse(bits.new(n):toSbytes())
|
||||||
|
local ref={["num"]=num,["fit"]=fit}
|
||||||
|
if fit then
|
||||||
|
if fit<#num then
|
||||||
|
if func then
|
||||||
|
print("Warning: attempting to store a number that takes up more space than allotted! Using provided method!")
|
||||||
|
func(ref)
|
||||||
|
else
|
||||||
|
print("Warning: attempting to store a number that takes up more space than allotted!")
|
||||||
|
end
|
||||||
|
return ref.num:sub(1,ref.fit)
|
||||||
|
elseif fit==#num then
|
||||||
|
return string.reverse(num)
|
||||||
|
else
|
||||||
|
return string.reverse(string.rep("\0",fit-#num)..num)
|
||||||
|
end
|
||||||
|
else
|
||||||
|
return string.reverse(num)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
function bits:conv(n)
|
||||||
|
local tab={}
|
||||||
|
while n>=1 do
|
||||||
|
table.insert(tab,n%2)
|
||||||
|
n=math.floor(n/2)
|
||||||
|
end
|
||||||
|
local str=string.reverse(table.concat(tab))
|
||||||
|
if #str%8~=0 or #str==0 then
|
||||||
|
str=string.rep('0',8-#str%8)..str
|
||||||
|
end
|
||||||
|
return str
|
||||||
|
end
|
||||||
|
function bits:tonumber(s,e)
|
||||||
|
if s==0 then
|
||||||
|
return tonumber(self.data,2)
|
||||||
|
end
|
||||||
|
s=s or 1
|
||||||
|
return tonumber(string.sub(self.data,(8*(s-1))+1,8*s),2) or error('Bounds!')
|
||||||
|
end
|
||||||
|
function bits:isover()
|
||||||
|
return #self.data>8
|
||||||
|
end
|
||||||
|
function bits:flipbits()
|
||||||
|
tab={}
|
||||||
|
for i=1,#self.data do
|
||||||
|
if string.sub(self.data,i,i)=='1' then
|
||||||
|
table.insert(tab,'0')
|
||||||
|
else
|
||||||
|
table.insert(tab,'1')
|
||||||
|
end
|
||||||
|
end
|
||||||
|
self.data=table.concat(tab)
|
||||||
|
end
|
||||||
|
function bits:tobytes()
|
||||||
|
local tab={}
|
||||||
|
for i=self:getbytes(),1,-1 do
|
||||||
|
table.insert(tab,string.char(self:tonumber(i)))
|
||||||
|
end
|
||||||
|
return bin.new(table.concat(tab))
|
||||||
|
end
|
||||||
|
function bits:toSbytes()
|
||||||
|
local tab={}
|
||||||
|
for i=self:getbytes(),1,-1 do
|
||||||
|
table.insert(tab,string.char(self:tonumber(i)))
|
||||||
|
end
|
||||||
|
return table.concat(tab)
|
||||||
|
end
|
||||||
|
function bits:getBin()
|
||||||
|
return self.data
|
||||||
|
end
|
||||||
|
function bits:getbytes()
|
||||||
|
return #self.data/8
|
||||||
|
end
|
||||||
|
return bits
|
||||||
@@ -0,0 +1,244 @@
|
|||||||
|
local binNum=require("bin.numbers.BigNum")
|
||||||
|
local infinabits={}
|
||||||
|
infinabits.data=''
|
||||||
|
infinabits.t='infinabits'
|
||||||
|
infinabits.Type='infinabits'
|
||||||
|
infinabits.__index = infinabits
|
||||||
|
infinabits.__tostring=function(self) return self.data end
|
||||||
|
infinabits.__len=function(self) return (#self.data)/8 end
|
||||||
|
local floor,insert = math.floor, table.insert
|
||||||
|
function basen(n,b)
|
||||||
|
n=BigNum.new(n)
|
||||||
|
if not b or b == 10 then return tostring(n) end
|
||||||
|
local digits = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
||||||
|
local t = {}
|
||||||
|
local sign = ""
|
||||||
|
if n < BigNum.new(0) then
|
||||||
|
sign = "-"
|
||||||
|
n = -n
|
||||||
|
end
|
||||||
|
repeat
|
||||||
|
local d = tonumber(tostring(n % b)) + 1
|
||||||
|
n = n / b
|
||||||
|
insert(t, 1, digits:sub(d,d))
|
||||||
|
until n == BigNum.new(0)
|
||||||
|
return sign .. table.concat(t,"")
|
||||||
|
end
|
||||||
|
function base2to10(num)
|
||||||
|
local n=BigNum.new(0)
|
||||||
|
for i = #num-1,0,-1 do
|
||||||
|
nn=BigNum.new(num:sub(i+1,i+1))*(BigNum.new(2)^((#num-i)-1))
|
||||||
|
n=n+nn
|
||||||
|
end
|
||||||
|
return n
|
||||||
|
end
|
||||||
|
function infinabits.newBitBuffer(n)
|
||||||
|
-- WIP
|
||||||
|
end
|
||||||
|
function infinabits.newConverter(bitsIn,bitsOut)
|
||||||
|
local c={}
|
||||||
|
-- WIP
|
||||||
|
end
|
||||||
|
infinabits.ref={}
|
||||||
|
function infinabits.newByte(d)-- WIP
|
||||||
|
local c={}
|
||||||
|
if type(d)=="string" then
|
||||||
|
if #d>1 or #d<1 then
|
||||||
|
error("A byte must be one character!")
|
||||||
|
else
|
||||||
|
c.data=string.byte(d)
|
||||||
|
end
|
||||||
|
elseif type(d)=="number" then
|
||||||
|
if d>255 or d<0 then
|
||||||
|
error("A byte must be between 0 and 255!")
|
||||||
|
else
|
||||||
|
c.data=d
|
||||||
|
end
|
||||||
|
else
|
||||||
|
error("cannot use type "..type(d).." as an argument! Takes only strings or numbers!")
|
||||||
|
end
|
||||||
|
c.__index=function(self,k)
|
||||||
|
if k>=0 and k<9 then
|
||||||
|
if self.data==0 then
|
||||||
|
return 0
|
||||||
|
elseif self.data==255 then
|
||||||
|
return 1
|
||||||
|
else
|
||||||
|
return infinabits.ref[self.data][k]
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
c.__tostring=function(self)
|
||||||
|
return infinabits.ref[tostring(self.data)]
|
||||||
|
end
|
||||||
|
setmetatable(c,c)
|
||||||
|
return c
|
||||||
|
end
|
||||||
|
function infinabits.newByteArray(s)-- WIP
|
||||||
|
local c={}
|
||||||
|
if type(s)~="string" then
|
||||||
|
error("Must be a string type or bin/buffer type")
|
||||||
|
elseif type(s)=="table" then
|
||||||
|
if s.t=="sink" or s.t=="buffer" or s.t=="bin" then
|
||||||
|
local data=s:getData()
|
||||||
|
for i=1,#data do
|
||||||
|
c[#c+1]=infinabits.newByte(data:sub(i,i))
|
||||||
|
end
|
||||||
|
else
|
||||||
|
error("Must be a string type or bin/buffer type")
|
||||||
|
end
|
||||||
|
else
|
||||||
|
for i=1,#s do
|
||||||
|
c[#c+1]=infinabits.newByte(s:sub(i,i))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return c
|
||||||
|
end
|
||||||
|
function infinabits.new(n,binary)
|
||||||
|
local temp={}
|
||||||
|
temp.t="infinabits"
|
||||||
|
temp.Type="infinabits"
|
||||||
|
if type(n)=="string" then
|
||||||
|
if binary then
|
||||||
|
temp.data=n:match("[10]+")
|
||||||
|
else
|
||||||
|
local t={}
|
||||||
|
for i=#n,1,-1 do
|
||||||
|
table.insert(t,infinabits:conv(string.byte(n,i)))
|
||||||
|
end
|
||||||
|
temp.data=table.concat(t)
|
||||||
|
end
|
||||||
|
elseif type(n)=="number" or type(n)=="table" then
|
||||||
|
temp.data=basen(tostring(n),2)
|
||||||
|
end
|
||||||
|
if #temp.data%8~=0 then
|
||||||
|
temp.data=string.rep('0',8-#temp.data%8)..temp.data
|
||||||
|
end
|
||||||
|
setmetatable(temp, infinabits)
|
||||||
|
return temp
|
||||||
|
end
|
||||||
|
for i=0,255 do
|
||||||
|
local d=infinabits.new(i).data
|
||||||
|
infinabits.ref[i]={d:match("(%d)(%d)(%d)(%d)(%d)(%d)(%d)(%d)")}
|
||||||
|
infinabits.ref[tostring(i)]=d
|
||||||
|
infinabits.ref[d]=i
|
||||||
|
infinabits.ref["\255"..string.char(i)]=d
|
||||||
|
end
|
||||||
|
function infinabits.numToBytes(n,fit,func)
|
||||||
|
local num=string.reverse(infinabits.new(BigNum.new(n)):toSbytes())
|
||||||
|
local ref={["num"]=num,["fit"]=fit}
|
||||||
|
if fit then
|
||||||
|
if fit<#num then
|
||||||
|
if func then
|
||||||
|
print("Warning: attempting to store a number that takes up more space than allotted! Using provided method!")
|
||||||
|
func(ref)
|
||||||
|
else
|
||||||
|
print("Warning: attempting to store a number that takes up more space than allotted!")
|
||||||
|
end
|
||||||
|
return ref.num:sub(1,ref.fit)
|
||||||
|
elseif fit==#num then
|
||||||
|
return string.reverse(num)
|
||||||
|
else
|
||||||
|
return string.reverse(string.rep("\0",fit-#num)..num)
|
||||||
|
end
|
||||||
|
else
|
||||||
|
return string.reverse(num)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
function infinabits.numToBytes(n,fit,fmt,func)
|
||||||
|
if fmt=="%e" then
|
||||||
|
local num=string.reverse(infinabits.new(BigNum.new(n)):toSbytes())
|
||||||
|
local ref={["num"]=num,["fit"]=fit}
|
||||||
|
if fit then
|
||||||
|
if fit<#num then
|
||||||
|
if func then
|
||||||
|
print("Warning: attempting to store a number that takes up more space than allotted! Using provided method!")
|
||||||
|
func(ref)
|
||||||
|
else
|
||||||
|
print("Warning: attempting to store a number that takes up more space than allotted!")
|
||||||
|
end
|
||||||
|
return ref.num:sub(1,ref.fit)
|
||||||
|
elseif fit==#num then
|
||||||
|
return num
|
||||||
|
else
|
||||||
|
return string.rep("\0",fit-#num)..num
|
||||||
|
end
|
||||||
|
else
|
||||||
|
return num
|
||||||
|
end
|
||||||
|
|
||||||
|
else
|
||||||
|
local num=string.reverse(infinabits.new(BigNum.new(n)):toSbytes())
|
||||||
|
local ref={["num"]=num,["fit"]=fit}
|
||||||
|
if fit then
|
||||||
|
if fit<#num then
|
||||||
|
if func then
|
||||||
|
print("Warning: attempting to store a number that takes up more space than allotted! Using provided method!")
|
||||||
|
func(ref)
|
||||||
|
else
|
||||||
|
print("Warning: attempting to store a number that takes up more space than allotted!")
|
||||||
|
end
|
||||||
|
return ref.num:sub(1,ref.fit)
|
||||||
|
elseif fit==#num then
|
||||||
|
return string.reverse(num)
|
||||||
|
else
|
||||||
|
return string.reverse(string.rep("\0",fit-#num)..num)
|
||||||
|
end
|
||||||
|
else
|
||||||
|
return string.reverse(num)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
function infinabits:conv(n)
|
||||||
|
local tab={}
|
||||||
|
local one=BigNum.new(1)
|
||||||
|
local n=BigNum.new(n)
|
||||||
|
while n>=one do
|
||||||
|
table.insert(tab,tonumber(tostring(n%2)))
|
||||||
|
n=n/2
|
||||||
|
end
|
||||||
|
local str=string.reverse(table.concat(tab))
|
||||||
|
if #str%8~=0 or #str==0 then
|
||||||
|
str=string.rep('0',8-#str%8)..str
|
||||||
|
end
|
||||||
|
return str
|
||||||
|
end
|
||||||
|
function infinabits:tonumber(s)
|
||||||
|
if s==0 then
|
||||||
|
return tonumber(self.data,2)
|
||||||
|
end
|
||||||
|
s=s or 1
|
||||||
|
return tonumber(tostring(base2to10(string.sub(self.data,(8*(s-1))+1,8*s)))) or error('Bounds!')
|
||||||
|
end
|
||||||
|
function infinabits:isover()
|
||||||
|
return #self.data>8
|
||||||
|
end
|
||||||
|
function infinabits:flipbits()
|
||||||
|
tab={}
|
||||||
|
local s=self.data
|
||||||
|
s=s:gsub("1","_")
|
||||||
|
s=s:gsub("0","1")
|
||||||
|
s=s:gsub("_","0")
|
||||||
|
self.data=s
|
||||||
|
end
|
||||||
|
function infinabits:tobytes()
|
||||||
|
local tab={}
|
||||||
|
for i=self:getbytes(),1,-1 do
|
||||||
|
table.insert(tab,string.char(self:tonumber(i)))
|
||||||
|
end
|
||||||
|
return bin.new(table.concat(tab))
|
||||||
|
end
|
||||||
|
function infinabits:toSbytes()
|
||||||
|
local tab={}
|
||||||
|
for i=self:getbytes(),1,-1 do
|
||||||
|
table.insert(tab,string.char(self:tonumber(i)))
|
||||||
|
end
|
||||||
|
return table.concat(tab)
|
||||||
|
end
|
||||||
|
function infinabits:getBin()
|
||||||
|
return self.data
|
||||||
|
end
|
||||||
|
function infinabits:getbytes()
|
||||||
|
return #self.data/8
|
||||||
|
end
|
||||||
|
return infinabits
|
||||||
@@ -0,0 +1,333 @@
|
|||||||
|
--[[
|
||||||
|
LICENSE
|
||||||
|
|
||||||
|
(c) 2008-2011 David Manura. Licensed under the same terms as Lua (MIT).
|
||||||
|
--]]
|
||||||
|
|
||||||
|
local M = {_TYPE='module', _NAME='bit.numberlua', _VERSION='0.3.1.20120131'}
|
||||||
|
|
||||||
|
local floor = math.floor
|
||||||
|
|
||||||
|
local MOD = 2^32
|
||||||
|
local MODM = MOD-1
|
||||||
|
|
||||||
|
local function memoize(f)
|
||||||
|
local mt = {}
|
||||||
|
local t = setmetatable({}, mt)
|
||||||
|
function mt:__index(k)
|
||||||
|
local v = f(k); t[k] = v
|
||||||
|
return v
|
||||||
|
end
|
||||||
|
return t
|
||||||
|
end
|
||||||
|
|
||||||
|
local function make_bitop_uncached(t, m)
|
||||||
|
local function bitop(a, b)
|
||||||
|
local res,p = 0,1
|
||||||
|
while a ~= 0 and b ~= 0 do
|
||||||
|
local am, bm = a%m, b%m
|
||||||
|
res = res + t[am][bm]*p
|
||||||
|
a = (a - am) / m
|
||||||
|
b = (b - bm) / m
|
||||||
|
p = p*m
|
||||||
|
end
|
||||||
|
res = res + (a+b)*p
|
||||||
|
return res
|
||||||
|
end
|
||||||
|
return bitop
|
||||||
|
end
|
||||||
|
|
||||||
|
local function make_bitop(t)
|
||||||
|
local op1 = make_bitop_uncached(t,2^1)
|
||||||
|
local op2 = memoize(function(a)
|
||||||
|
return memoize(function(b)
|
||||||
|
return op1(a, b)
|
||||||
|
end)
|
||||||
|
end)
|
||||||
|
return make_bitop_uncached(op2, 2^(t.n or 1))
|
||||||
|
end
|
||||||
|
|
||||||
|
-- ok? probably not if running on a 32-bit int Lua number type platform
|
||||||
|
function M.tobit(x)
|
||||||
|
return x % 2^32
|
||||||
|
end
|
||||||
|
|
||||||
|
M.bxor = make_bitop {[0]={[0]=0,[1]=1},[1]={[0]=1,[1]=0}, n=4}
|
||||||
|
local bxor = M.bxor
|
||||||
|
|
||||||
|
function M.bnot(a) return MODM - a end
|
||||||
|
local bnot = M.bnot
|
||||||
|
|
||||||
|
function M.band(a,b) return ((a+b) - bxor(a,b))/2 end
|
||||||
|
local band = M.band
|
||||||
|
|
||||||
|
function M.bor(a,b) return MODM - band(MODM - a, MODM - b) end
|
||||||
|
local bor = M.bor
|
||||||
|
|
||||||
|
local lshift, rshift -- forward declare
|
||||||
|
|
||||||
|
function M.rshift(a,disp) -- Lua5.2 insipred
|
||||||
|
if disp < 0 then return lshift(a,-disp) end
|
||||||
|
return floor(a % 2^32 / 2^disp)
|
||||||
|
end
|
||||||
|
rshift = M.rshift
|
||||||
|
|
||||||
|
function M.lshift(a,disp) -- Lua5.2 inspired
|
||||||
|
if disp < 0 then return rshift(a,-disp) end
|
||||||
|
return (a * 2^disp) % 2^32
|
||||||
|
end
|
||||||
|
lshift = M.lshift
|
||||||
|
|
||||||
|
function M.tohex(x, n) -- BitOp style
|
||||||
|
n = n or 8
|
||||||
|
local up
|
||||||
|
if n <= 0 then
|
||||||
|
if n == 0 then return '' end
|
||||||
|
up = true
|
||||||
|
n = - n
|
||||||
|
end
|
||||||
|
x = band(x, 16^n-1)
|
||||||
|
return ('%0'..n..(up and 'X' or 'x')):format(x)
|
||||||
|
end
|
||||||
|
local tohex = M.tohex
|
||||||
|
|
||||||
|
function M.extract(n, field, width) -- Lua5.2 inspired
|
||||||
|
width = width or 1
|
||||||
|
return band(rshift(n, field), 2^width-1)
|
||||||
|
end
|
||||||
|
local extract = M.extract
|
||||||
|
|
||||||
|
function M.replace(n, v, field, width) -- Lua5.2 inspired
|
||||||
|
width = width or 1
|
||||||
|
local mask1 = 2^width-1
|
||||||
|
v = band(v, mask1) -- required by spec?
|
||||||
|
local mask = bnot(lshift(mask1, field))
|
||||||
|
return band(n, mask) + lshift(v, field)
|
||||||
|
end
|
||||||
|
local replace = M.replace
|
||||||
|
|
||||||
|
function M.bswap(x) -- BitOp style
|
||||||
|
local a = band(x, 0xff); x = rshift(x, 8)
|
||||||
|
local b = band(x, 0xff); x = rshift(x, 8)
|
||||||
|
local c = band(x, 0xff); x = rshift(x, 8)
|
||||||
|
local d = band(x, 0xff)
|
||||||
|
return lshift(lshift(lshift(a, 8) + b, 8) + c, 8) + d
|
||||||
|
end
|
||||||
|
local bswap = M.bswap
|
||||||
|
|
||||||
|
function M.rrotate(x, disp) -- Lua5.2 inspired
|
||||||
|
disp = disp % 32
|
||||||
|
local low = band(x, 2^disp-1)
|
||||||
|
return rshift(x, disp) + lshift(low, 32-disp)
|
||||||
|
end
|
||||||
|
local rrotate = M.rrotate
|
||||||
|
|
||||||
|
function M.lrotate(x, disp) -- Lua5.2 inspired
|
||||||
|
return rrotate(x, -disp)
|
||||||
|
end
|
||||||
|
local lrotate = M.lrotate
|
||||||
|
|
||||||
|
M.rol = M.lrotate -- LuaOp inspired
|
||||||
|
M.ror = M.rrotate -- LuaOp insipred
|
||||||
|
|
||||||
|
|
||||||
|
function M.arshift(x, disp) -- Lua5.2 inspired
|
||||||
|
local z = rshift(x, disp)
|
||||||
|
if x >= 0x80000000 then z = z + lshift(2^disp-1, 32-disp) end
|
||||||
|
return z
|
||||||
|
end
|
||||||
|
local arshift = M.arshift
|
||||||
|
|
||||||
|
function M.btest(x, y) -- Lua5.2 inspired
|
||||||
|
return band(x, y) ~= 0
|
||||||
|
end
|
||||||
|
|
||||||
|
M.bit32 = {} -- Lua 5.2 'bit32' compatibility
|
||||||
|
|
||||||
|
|
||||||
|
local function bit32_bnot(x)
|
||||||
|
return (-1 - x) % MOD
|
||||||
|
end
|
||||||
|
M.bit32.bnot = bit32_bnot
|
||||||
|
|
||||||
|
local function bit32_bxor(a, b, c, ...)
|
||||||
|
local z
|
||||||
|
if b then
|
||||||
|
a = a % MOD
|
||||||
|
b = b % MOD
|
||||||
|
z = bxor(a, b)
|
||||||
|
if c then
|
||||||
|
z = bit32_bxor(z, c, ...)
|
||||||
|
end
|
||||||
|
return z
|
||||||
|
elseif a then
|
||||||
|
return a % MOD
|
||||||
|
else
|
||||||
|
return 0
|
||||||
|
end
|
||||||
|
end
|
||||||
|
M.bit32.bxor = bit32_bxor
|
||||||
|
|
||||||
|
local function bit32_band(a, b, c, ...)
|
||||||
|
local z
|
||||||
|
if b then
|
||||||
|
a = a % MOD
|
||||||
|
b = b % MOD
|
||||||
|
z = ((a+b) - bxor(a,b)) / 2
|
||||||
|
if c then
|
||||||
|
z = bit32_band(z, c, ...)
|
||||||
|
end
|
||||||
|
return z
|
||||||
|
elseif a then
|
||||||
|
return a % MOD
|
||||||
|
else
|
||||||
|
return MODM
|
||||||
|
end
|
||||||
|
end
|
||||||
|
M.bit32.band = bit32_band
|
||||||
|
|
||||||
|
local function bit32_bor(a, b, c, ...)
|
||||||
|
local z
|
||||||
|
if b then
|
||||||
|
a = a % MOD
|
||||||
|
b = b % MOD
|
||||||
|
z = MODM - band(MODM - a, MODM - b)
|
||||||
|
if c then
|
||||||
|
z = bit32_bor(z, c, ...)
|
||||||
|
end
|
||||||
|
return z
|
||||||
|
elseif a then
|
||||||
|
return a % MOD
|
||||||
|
else
|
||||||
|
return 0
|
||||||
|
end
|
||||||
|
end
|
||||||
|
M.bit32.bor = bit32_bor
|
||||||
|
|
||||||
|
function M.bit32.btest(...)
|
||||||
|
return bit32_band(...) ~= 0
|
||||||
|
end
|
||||||
|
|
||||||
|
function M.bit32.lrotate(x, disp)
|
||||||
|
return lrotate(x % MOD, disp)
|
||||||
|
end
|
||||||
|
|
||||||
|
function M.bit32.rrotate(x, disp)
|
||||||
|
return rrotate(x % MOD, disp)
|
||||||
|
end
|
||||||
|
|
||||||
|
function M.bit32.lshift(x,disp)
|
||||||
|
if disp > 31 or disp < -31 then return 0 end
|
||||||
|
return lshift(x % MOD, disp)
|
||||||
|
end
|
||||||
|
|
||||||
|
function M.bit32.rshift(x,disp)
|
||||||
|
if disp > 31 or disp < -31 then return 0 end
|
||||||
|
return rshift(x % MOD, disp)
|
||||||
|
end
|
||||||
|
|
||||||
|
function M.bit32.arshift(x,disp)
|
||||||
|
x = x % MOD
|
||||||
|
if disp >= 0 then
|
||||||
|
if disp > 31 then
|
||||||
|
return (x >= 0x80000000) and MODM or 0
|
||||||
|
else
|
||||||
|
local z = rshift(x, disp)
|
||||||
|
if x >= 0x80000000 then z = z + lshift(2^disp-1, 32-disp) end
|
||||||
|
return z
|
||||||
|
end
|
||||||
|
else
|
||||||
|
return lshift(x, -disp)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function M.bit32.extract(x, field, ...)
|
||||||
|
local width = ... or 1
|
||||||
|
if field < 0 or field > 31 or width < 0 or field+width > 32 then error 'out of range' end
|
||||||
|
x = x % MOD
|
||||||
|
return extract(x, field, ...)
|
||||||
|
end
|
||||||
|
|
||||||
|
function M.bit32.replace(x, v, field, ...)
|
||||||
|
local width = ... or 1
|
||||||
|
if field < 0 or field > 31 or width < 0 or field+width > 32 then error 'out of range' end
|
||||||
|
x = x % MOD
|
||||||
|
v = v % MOD
|
||||||
|
return replace(x, v, field, ...)
|
||||||
|
end
|
||||||
|
|
||||||
|
M.bit = {} -- LuaBitOp "bit" compatibility
|
||||||
|
|
||||||
|
function M.bit.tobit(x)
|
||||||
|
x = x % MOD
|
||||||
|
if x >= 0x80000000 then x = x - MOD end
|
||||||
|
return x
|
||||||
|
end
|
||||||
|
local bit_tobit = M.bit.tobit
|
||||||
|
|
||||||
|
function M.bit.tohex(x, ...)
|
||||||
|
return tohex(x % MOD, ...)
|
||||||
|
end
|
||||||
|
|
||||||
|
function M.bit.bnot(x)
|
||||||
|
return bit_tobit(bnot(x % MOD))
|
||||||
|
end
|
||||||
|
|
||||||
|
local function bit_bor(a, b, c, ...)
|
||||||
|
if c then
|
||||||
|
return bit_bor(bit_bor(a, b), c, ...)
|
||||||
|
elseif b then
|
||||||
|
return bit_tobit(bor(a % MOD, b % MOD))
|
||||||
|
else
|
||||||
|
return bit_tobit(a)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
M.bit.bor = bit_bor
|
||||||
|
|
||||||
|
local function bit_band(a, b, c, ...)
|
||||||
|
if c then
|
||||||
|
return bit_band(bit_band(a, b), c, ...)
|
||||||
|
elseif b then
|
||||||
|
return bit_tobit(band(a % MOD, b % MOD))
|
||||||
|
else
|
||||||
|
return bit_tobit(a)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
M.bit.band = bit_band
|
||||||
|
|
||||||
|
local function bit_bxor(a, b, c, ...)
|
||||||
|
if c then
|
||||||
|
return bit_bxor(bit_bxor(a, b), c, ...)
|
||||||
|
elseif b then
|
||||||
|
return bit_tobit(bxor(a % MOD, b % MOD))
|
||||||
|
else
|
||||||
|
return bit_tobit(a)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
M.bit.bxor = bit_bxor
|
||||||
|
|
||||||
|
function M.bit.lshift(x, n)
|
||||||
|
return bit_tobit(lshift(x % MOD, n % 32))
|
||||||
|
end
|
||||||
|
|
||||||
|
function M.bit.rshift(x, n)
|
||||||
|
return bit_tobit(rshift(x % MOD, n % 32))
|
||||||
|
end
|
||||||
|
|
||||||
|
function M.bit.arshift(x, n)
|
||||||
|
return bit_tobit(arshift(x % MOD, n % 32))
|
||||||
|
end
|
||||||
|
|
||||||
|
function M.bit.rol(x, n)
|
||||||
|
return bit_tobit(lrotate(x % MOD, n % 32))
|
||||||
|
end
|
||||||
|
|
||||||
|
function M.bit.ror(x, n)
|
||||||
|
return bit_tobit(rrotate(x % MOD, n % 32))
|
||||||
|
end
|
||||||
|
|
||||||
|
function M.bit.bswap(x)
|
||||||
|
return bit_tobit(bswap(x % MOD))
|
||||||
|
end
|
||||||
|
|
||||||
|
return M
|
||||||
@@ -0,0 +1,232 @@
|
|||||||
|
--[[----------------------------------------
|
||||||
|
Random
|
||||||
|
Not all of this is mine
|
||||||
|
------------------------------------------]]
|
||||||
|
--[[------------------------------------
|
||||||
|
RandomLua v0.3.1
|
||||||
|
Pure Lua Pseudo-Random Numbers Generator
|
||||||
|
Under the MIT license.
|
||||||
|
copyright(c) 2011 linux-man
|
||||||
|
--]]------------------------------------
|
||||||
|
|
||||||
|
local math_floor = math.floor
|
||||||
|
|
||||||
|
local function normalize(n)
|
||||||
|
return n % 0x80000000
|
||||||
|
end
|
||||||
|
|
||||||
|
local function bit_and(a, b)
|
||||||
|
local r = 0
|
||||||
|
local m = 0
|
||||||
|
for m = 0, 31 do
|
||||||
|
if (a % 2 == 1) and (b % 2 == 1) then r = r + 2^m end
|
||||||
|
if a % 2 ~= 0 then a = a - 1 end
|
||||||
|
if b % 2 ~= 0 then b = b - 1 end
|
||||||
|
a = a / 2 b = b / 2
|
||||||
|
end
|
||||||
|
return normalize(r)
|
||||||
|
end
|
||||||
|
|
||||||
|
local function bit_or(a, b)
|
||||||
|
local r = 0
|
||||||
|
local m = 0
|
||||||
|
for m = 0, 31 do
|
||||||
|
if (a % 2 == 1) or (b % 2 == 1) then r = r + 2^m end
|
||||||
|
if a % 2 ~= 0 then a = a - 1 end
|
||||||
|
if b % 2 ~= 0 then b = b - 1 end
|
||||||
|
a = a / 2 b = b / 2
|
||||||
|
end
|
||||||
|
return normalize(r)
|
||||||
|
end
|
||||||
|
|
||||||
|
local function bit_xor(a, b)
|
||||||
|
local r = 0
|
||||||
|
local m = 0
|
||||||
|
for m = 0, 31 do
|
||||||
|
if a % 2 ~= b % 2 then r = r + 2^m end
|
||||||
|
if a % 2 ~= 0 then a = a - 1 end
|
||||||
|
if b % 2 ~= 0 then b = b - 1 end
|
||||||
|
a = a / 2 b = b / 2
|
||||||
|
end
|
||||||
|
return normalize(r)
|
||||||
|
end
|
||||||
|
|
||||||
|
local function seed()
|
||||||
|
return normalize(os.time())
|
||||||
|
end
|
||||||
|
|
||||||
|
--Mersenne twister
|
||||||
|
local mersenne_twister = {}
|
||||||
|
mersenne_twister.__index = mersenne_twister
|
||||||
|
|
||||||
|
function mersenne_twister:randomseed(s)
|
||||||
|
if not s then s = seed() end
|
||||||
|
self.mt[0] = normalize(s)
|
||||||
|
for i = 1, 623 do
|
||||||
|
self.mt[i] = normalize(0x6c078965 * bit_xor(self.mt[i-1], math_floor(self.mt[i-1] / 0x40000000)) + i)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function mersenne_twister:random(a, b)
|
||||||
|
local y
|
||||||
|
if self.index == 0 then
|
||||||
|
for i = 0, 623 do
|
||||||
|
y = self.mt[(i + 1) % 624] % 0x80000000
|
||||||
|
self.mt[i] = bit_xor(self.mt[(i + 397) % 624], math_floor(y / 2))
|
||||||
|
if y % 2 ~= 0 then self.mt[i] = bit_xor(self.mt[i], 0x9908b0df) end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
y = self.mt[self.index]
|
||||||
|
y = bit_xor(y, math_floor(y / 0x800))
|
||||||
|
y = bit_xor(y, bit_and(normalize(y * 0x80), 0x9d2c5680))
|
||||||
|
y = bit_xor(y, bit_and(normalize(y * 0x8000), 0xefc60000))
|
||||||
|
y = bit_xor(y, math_floor(y / 0x40000))
|
||||||
|
self.index = (self.index + 1) % 624
|
||||||
|
if not a then return y / 0x80000000
|
||||||
|
elseif not b then
|
||||||
|
if a == 0 then return y
|
||||||
|
else return 1 + (y % a)
|
||||||
|
end
|
||||||
|
else
|
||||||
|
return a + (y % (b - a + 1))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local function twister(s)
|
||||||
|
local temp = {}
|
||||||
|
setmetatable(temp, mersenne_twister)
|
||||||
|
temp.mt = {}
|
||||||
|
temp.index = 0
|
||||||
|
temp:randomseed(s)
|
||||||
|
return temp
|
||||||
|
end
|
||||||
|
|
||||||
|
--Linear Congruential Generator
|
||||||
|
local linear_congruential_generator = {}
|
||||||
|
linear_congruential_generator.__index = linear_congruential_generator
|
||||||
|
|
||||||
|
function linear_congruential_generator:random(a, b)
|
||||||
|
local y = (self.a * self.x + self.c) % self.m
|
||||||
|
self.x = y
|
||||||
|
if not a then return y / 0x10000
|
||||||
|
elseif not b then
|
||||||
|
if a == 0 then return y
|
||||||
|
else return 1 + (y % a) end
|
||||||
|
else
|
||||||
|
return a + (y % (b - a + 1))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function linear_congruential_generator:randomseed(s)
|
||||||
|
if not s then s = seed() end
|
||||||
|
self.x = normalize(s)
|
||||||
|
end
|
||||||
|
|
||||||
|
local function lcg(s, r)
|
||||||
|
local temp = {}
|
||||||
|
setmetatable(temp, linear_congruential_generator)
|
||||||
|
temp.a, temp.c, temp.m = 1103515245, 12345, 0x10000 --from Ansi C
|
||||||
|
if r then
|
||||||
|
if r == 'nr' then temp.a, temp.c, temp.m = 1664525, 1013904223, 0x10000 --from Numerical Recipes.
|
||||||
|
elseif r == 'mvc' then temp.a, temp.c, temp.m = 214013, 2531011, 0x10000 end--from MVC
|
||||||
|
end
|
||||||
|
temp:randomseed(s)
|
||||||
|
return temp
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Multiply-with-carry
|
||||||
|
local multiply_with_carry = {}
|
||||||
|
multiply_with_carry.__index = multiply_with_carry
|
||||||
|
|
||||||
|
function multiply_with_carry:random(a, b)
|
||||||
|
local m = self.m
|
||||||
|
local t = self.a * self.x + self.c
|
||||||
|
local y = t % m
|
||||||
|
self.x = y
|
||||||
|
self.c = math_floor(t / m)
|
||||||
|
if not a then return y / 0x10000
|
||||||
|
elseif not b then
|
||||||
|
if a == 0 then return y
|
||||||
|
else return 1 + (y % a) end
|
||||||
|
else
|
||||||
|
return a + (y % (b - a + 1))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function multiply_with_carry:randomseed(s)
|
||||||
|
if not s then s = seed() end
|
||||||
|
self.c = self.ic
|
||||||
|
self.x = normalize(s)
|
||||||
|
end
|
||||||
|
|
||||||
|
local function mwc(s, r)
|
||||||
|
local temp = {}
|
||||||
|
setmetatable(temp, multiply_with_carry)
|
||||||
|
temp.a, temp.c, temp.m = 1103515245, 12345, 0x10000 --from Ansi C
|
||||||
|
if r then
|
||||||
|
if r == 'nr' then temp.a, temp.c, temp.m = 1664525, 1013904223, 0x10000 --from Numerical Recipes.
|
||||||
|
elseif r == 'mvc' then temp.a, temp.c, temp.m = 214013, 2531011, 0x10000 end--from MVC
|
||||||
|
end
|
||||||
|
temp.ic = temp.c
|
||||||
|
temp:randomseed(s)
|
||||||
|
return temp
|
||||||
|
end
|
||||||
|
-- Little bind for the methods: My code starts
|
||||||
|
local randomGen={}
|
||||||
|
randomGen.__index=randomGen
|
||||||
|
function randomGen:new(s)
|
||||||
|
local temp={}
|
||||||
|
setmetatable(temp,randomGen)
|
||||||
|
temp[1]=twister()
|
||||||
|
temp[2]=lcg()
|
||||||
|
temp[3]=mwc()
|
||||||
|
temp.pos=1
|
||||||
|
for i=1,3 do
|
||||||
|
temp[i]:randomseed(s)
|
||||||
|
end
|
||||||
|
return temp
|
||||||
|
end
|
||||||
|
function randomGen:randomseed(s)
|
||||||
|
self.pos=1
|
||||||
|
self[1]:randomseed(s)
|
||||||
|
self[2]:randomseed(s)
|
||||||
|
self[3]:randomseed(s)
|
||||||
|
end
|
||||||
|
function randomGen:randomInt(a,b)
|
||||||
|
local t=self[self.pos]:random(a,b)
|
||||||
|
self.pos=self.pos+1
|
||||||
|
if self.pos>3 then
|
||||||
|
self.pos=1
|
||||||
|
end
|
||||||
|
return t
|
||||||
|
end
|
||||||
|
function randomGen:newND(a,b,s)
|
||||||
|
if not(a) or not(b) then error('You must include a range!') end
|
||||||
|
local temp=randomGen:new(s)
|
||||||
|
temp.a=a
|
||||||
|
temp.b=b
|
||||||
|
temp.range=b-a+1
|
||||||
|
temp.dups={no=0}
|
||||||
|
function temp:nextInt()
|
||||||
|
local t=self:randomInt(self.a,self.b)
|
||||||
|
if self.dups[t]==nil then
|
||||||
|
self.dups[t]=true
|
||||||
|
self.dups.no=self.dups.no+1
|
||||||
|
else
|
||||||
|
return self:nextInt()
|
||||||
|
end
|
||||||
|
if self.dups.no==self.range then
|
||||||
|
function self:nextInt()
|
||||||
|
return 1,true
|
||||||
|
end
|
||||||
|
return t
|
||||||
|
else
|
||||||
|
return t
|
||||||
|
end
|
||||||
|
end
|
||||||
|
function temp:nextIInt()
|
||||||
|
return function() return self:nextInt() end
|
||||||
|
end
|
||||||
|
return temp
|
||||||
|
end
|
||||||
|
return randomGen
|
||||||
@@ -0,0 +1,146 @@
|
|||||||
|
local __CURRENTVERSION=2
|
||||||
|
bin.registerBlock("t",function(SIZE_OR_NIL,ref)
|
||||||
|
local header=ref:read(3)
|
||||||
|
if not header:match("(LT.)") then error("Not a valid table struct!") end
|
||||||
|
if bin.defualtBit.new(header:sub(3,3)):tonumber(1)>__CURRENTVERSION then error("Incompatible Version of LuaTable!") end
|
||||||
|
local len=ref:getBlock("n",4) -- hehe lets make life easier
|
||||||
|
local tab={}
|
||||||
|
local ind
|
||||||
|
local n=0
|
||||||
|
while true do
|
||||||
|
local _dat=ref:read(2)
|
||||||
|
if _dat==nil then break end
|
||||||
|
local it,dt=_dat:match("(.)(.)")
|
||||||
|
n=n+2
|
||||||
|
if it=="N" then -- get the index stuff out of the way first
|
||||||
|
ind=ref:getBlock("n",4)
|
||||||
|
n=n+4
|
||||||
|
else
|
||||||
|
indL=ref:getBlock("n",1)
|
||||||
|
n=n+1+indL
|
||||||
|
ind=ref:read(indL)
|
||||||
|
end
|
||||||
|
if dt=="N" then
|
||||||
|
tab[ind]=ref:getBlock("d")
|
||||||
|
n=n+8
|
||||||
|
elseif dt=="I" then
|
||||||
|
tab[ind]=math.huge
|
||||||
|
ref:getBlock("n",4)
|
||||||
|
n=n+4
|
||||||
|
elseif dt=="i" then
|
||||||
|
tab[ind]=-math.huge
|
||||||
|
ref:getBlock("n",4)
|
||||||
|
n=n+4
|
||||||
|
elseif dt=="S" then
|
||||||
|
local nn=ref:getBlock("n",4)
|
||||||
|
tab[ind]=ref:read(nn)
|
||||||
|
n=n+4+nn
|
||||||
|
elseif dt=="B" then
|
||||||
|
tab[ind]=({["\255"]=true,["\0"]=false})[ref:read(1)]
|
||||||
|
n=n+1
|
||||||
|
elseif dt=="F" then
|
||||||
|
local nn=ref:getBlock("n",4)
|
||||||
|
tab[ind]=loadstring(ref:read(nn))
|
||||||
|
n=n+4+nn
|
||||||
|
elseif dt=="T" then
|
||||||
|
local cur=ref:getSeek()
|
||||||
|
local size=ref:getBlock("n",4)
|
||||||
|
ref:setSeek(cur)
|
||||||
|
ref:read(4)
|
||||||
|
if size==7 then
|
||||||
|
tab[ind]={}
|
||||||
|
ref:read(7)
|
||||||
|
n=n+11
|
||||||
|
else
|
||||||
|
local data=bin.new(ref:read(size))
|
||||||
|
local dat=data:getBlock("t")
|
||||||
|
if dat.__RECURSIVE then
|
||||||
|
tab[ind]=tab
|
||||||
|
else
|
||||||
|
tab[ind]=dat
|
||||||
|
end
|
||||||
|
n=n+data:getSize()+4
|
||||||
|
end
|
||||||
|
end
|
||||||
|
if n==len then break end
|
||||||
|
end
|
||||||
|
return bin.resolveType(tab)
|
||||||
|
end,function(d,fit,fmt,self,rec,tabsaw)
|
||||||
|
-- INGORE FIT WE ARE CREATING A STRUCT!!!
|
||||||
|
-- fmt will apply to all numbers
|
||||||
|
local __rem=nil
|
||||||
|
if not tabsaw then rem=true end
|
||||||
|
local tabsaw=tabsaw or {}
|
||||||
|
if rem then
|
||||||
|
table.insert(tabsaw,d)
|
||||||
|
end
|
||||||
|
local bData={}
|
||||||
|
for i,v in pairs(d) do -- this is for tables, all but userdata is fine. Depending on where you are using lua functions may or may not work
|
||||||
|
local tp=type(v):sub(1,1):upper() -- uppercase of datatype
|
||||||
|
if type(i)=="number" then -- Lets handle indexies
|
||||||
|
if v==math.huge then
|
||||||
|
tp="I"
|
||||||
|
v=0
|
||||||
|
elseif v==-math.huge then
|
||||||
|
tp="i"
|
||||||
|
v=0
|
||||||
|
end
|
||||||
|
table.insert(bData,"N"..tp..bin.defualtBit.numToBytes(i,4)) -- number index?
|
||||||
|
elseif type(i)=="string" then
|
||||||
|
if #i>255 then error("A string index cannot be larger than 255 bytes!") end
|
||||||
|
table.insert(bData,"S"..tp..bin.defualtBit.numToBytes(#i,1)..i) -- string index?
|
||||||
|
else
|
||||||
|
error("Only numbers and strings can be a table index!") -- throw error?
|
||||||
|
end
|
||||||
|
if type(v)=="number" then
|
||||||
|
-- How do we handle number data
|
||||||
|
local temp=bin.new()
|
||||||
|
temp:addBlock(v,nil,"d")
|
||||||
|
table.insert(bData,temp.data)
|
||||||
|
elseif type(v)=="string" then
|
||||||
|
-- Lets work on strings
|
||||||
|
table.insert(bData,bin.defualtBit.numToBytes(#v,4)) -- add length of string
|
||||||
|
table.insert(bData,v) -- add string
|
||||||
|
elseif type(v)=="boolean" then -- bools are easy :D
|
||||||
|
table.insert(bData,({[true]="\255",[false]="\0"})[v])
|
||||||
|
elseif type(v)=="function" then -- should we allow this? why not...
|
||||||
|
local dump=string.dump(v)
|
||||||
|
table.insert(bData,bin.defualtBit.numToBytes(#dump,4)) -- add length of dumped string
|
||||||
|
table.insert(bData,dump) -- add it
|
||||||
|
elseif type(v)=="table" then -- tables...
|
||||||
|
if tabsaw[1]==v then
|
||||||
|
v={__RECURSIVE=i}
|
||||||
|
else
|
||||||
|
tabsaw[i]=v
|
||||||
|
end
|
||||||
|
local data=rec(v,nil,"t",self,rec,tabsaw)
|
||||||
|
table.insert(bData,bin.defualtBit.numToBytes(#data,4)) -- add length of string
|
||||||
|
table.insert(bData,data) -- add string
|
||||||
|
end
|
||||||
|
end
|
||||||
|
local data=table.concat(bData)
|
||||||
|
return "LT"..string.char(__CURRENTVERSION)..bin.defualtBit.numToBytes(#data,4)..data
|
||||||
|
end)
|
||||||
|
bin.registerBlock("b",function(SIZE_OR_NIL,ref)
|
||||||
|
return ({["\255"]=true,["\0"]=false})[ref:read(1)]
|
||||||
|
end,function(d)
|
||||||
|
return ({[true]="\255",[false]="\0"})[d]
|
||||||
|
end)
|
||||||
|
bin.registerBlock("f",function(SIZE_OR_NIL,ref)
|
||||||
|
local nn=ref:getBlock("n",4)
|
||||||
|
return loadstring(ref:read(nn))
|
||||||
|
end,function(d)
|
||||||
|
local dump=string.dump(d)
|
||||||
|
return bin.defualtBit.numToBytes(#dump,4)..dump
|
||||||
|
end)
|
||||||
|
bin.registerBlock("d",function(SIZE_OR_NIL,ref)
|
||||||
|
local w,p=ref:getBlock("n",4),ref:getBlock("n",4)
|
||||||
|
p=tonumber("0."..tostring(p))
|
||||||
|
return w+p
|
||||||
|
end,function(d,fit,fmt,self,rec,tabsaw)
|
||||||
|
local w,p = toFraction(d)
|
||||||
|
local temp=bin.new()
|
||||||
|
temp:addBlock(w,4)
|
||||||
|
temp:addBlock(p,4)
|
||||||
|
return temp.data
|
||||||
|
end)
|
||||||
@@ -0,0 +1,127 @@
|
|||||||
|
function table.print(tbl, indent)
|
||||||
|
if not indent then indent = 0 end
|
||||||
|
for k, v in pairs(tbl) do
|
||||||
|
formatting = string.rep(" ", indent) .. k .. ": "
|
||||||
|
if type(v) == "table" then
|
||||||
|
print(formatting)
|
||||||
|
table.print(v, indent+1)
|
||||||
|
elseif type(v) == 'boolean' then
|
||||||
|
print(formatting .. tostring(v))
|
||||||
|
else
|
||||||
|
print(formatting .. tostring(v))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
function table.flip(t)
|
||||||
|
local tt={}
|
||||||
|
for i,v in pairs(t) do
|
||||||
|
tt[v]=i
|
||||||
|
end
|
||||||
|
return tt
|
||||||
|
end
|
||||||
|
function toFraction(n)
|
||||||
|
local w,p=math.modf(n)
|
||||||
|
if p~=0 then
|
||||||
|
p=tonumber(tostring(p):sub(3))
|
||||||
|
end
|
||||||
|
return w,p
|
||||||
|
end
|
||||||
|
function io.cleanName(name)
|
||||||
|
name=name:gsub("\\","")
|
||||||
|
name=name:gsub("/","")
|
||||||
|
name=name:gsub(":","")
|
||||||
|
name=name:gsub("*","")
|
||||||
|
name=name:gsub("%?","")
|
||||||
|
name=name:gsub("\"","''")
|
||||||
|
name=name:gsub("<","")
|
||||||
|
name=name:gsub(">","")
|
||||||
|
name=name:gsub("|","")
|
||||||
|
return name
|
||||||
|
end
|
||||||
|
function math.numfix(n,x)
|
||||||
|
local str=tostring(n)
|
||||||
|
if #str<x then
|
||||||
|
str=('0'):rep(x-#str)..str
|
||||||
|
end
|
||||||
|
return str
|
||||||
|
end
|
||||||
|
function bin.stripFileName(path)
|
||||||
|
path=path:gsub("\\","/")
|
||||||
|
local npath=path:reverse()
|
||||||
|
a=npath:find("/",1,true)
|
||||||
|
npath=npath:sub(a)
|
||||||
|
npath=npath:reverse()
|
||||||
|
return npath
|
||||||
|
end
|
||||||
|
function bin._trim(str)
|
||||||
|
return str:match'^()%s*$' and '' or str:match'^%s*(.*%S)'
|
||||||
|
end
|
||||||
|
function io.dirExists(strFolderName)
|
||||||
|
strFolderName = strFolderName or io.getDir()
|
||||||
|
local fileHandle, strError = io.open(strFolderName..'\\*.*','r')
|
||||||
|
if fileHandle ~= nil then
|
||||||
|
io.close(fileHandle)
|
||||||
|
return true
|
||||||
|
else
|
||||||
|
if string.match(strError,'No such file or directory') then
|
||||||
|
return false
|
||||||
|
else
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
function bin.fileExists(name)
|
||||||
|
local f=io.open(name,"r")
|
||||||
|
if f~=nil then io.close(f) return true else return false end
|
||||||
|
end
|
||||||
|
function bin.randomName(n,ext)
|
||||||
|
n=n or math.random(7,15)
|
||||||
|
if ext then
|
||||||
|
a,b=ext:find('.',1,true)
|
||||||
|
if a and b then
|
||||||
|
ext=ext:sub(2)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
local str,h = '',0
|
||||||
|
strings = {'a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z','1','2','3','4','5','6','7','8','9','0','A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z'}
|
||||||
|
for i=1,n do
|
||||||
|
h = math.random(1,#strings)
|
||||||
|
str = str..''..strings[h]
|
||||||
|
end
|
||||||
|
return str..'.'..(ext or 'tmp')
|
||||||
|
end
|
||||||
|
function bin.trimNul(str)
|
||||||
|
return str:match("(.-)[%z]*$")
|
||||||
|
end
|
||||||
|
function io.mkDir(dirname)
|
||||||
|
os.execute('mkdir "' .. dirname..'"')
|
||||||
|
end
|
||||||
|
function string.lines(str)
|
||||||
|
local t = {}
|
||||||
|
local function helper(line) table.insert(t, line) return '' end
|
||||||
|
helper((str:gsub('(.-)\r?\n', helper)))
|
||||||
|
return t
|
||||||
|
end
|
||||||
|
function log(data,name,fmt)
|
||||||
|
if name then
|
||||||
|
name=io.cleanName(name)
|
||||||
|
end
|
||||||
|
if not bin.logger then
|
||||||
|
bin.logger = bin.stream(name or 'lua.log',false)
|
||||||
|
elseif bin.logger and name then
|
||||||
|
bin.logger:close()
|
||||||
|
bin.logger = bin.stream(name or 'lua.log',false)
|
||||||
|
end
|
||||||
|
local d=os.date('*t',os.time())
|
||||||
|
bin.logger:tackE((fmt or '['..math.numfix(d.month,2)..'-'..math.numfix(d.day,2)..'-'..d.year..'|'..math.numfix(d.hour,2)..':'..math.numfix(d.min,2)..':'..math.numfix(d.sec,2)..']\t')..data..'\r\n')
|
||||||
|
end
|
||||||
|
function table.max(t)
|
||||||
|
if #t == 0 then return end
|
||||||
|
local value = t[1]
|
||||||
|
for i = 2, #t do
|
||||||
|
if (value < t[i]) then
|
||||||
|
value = t[i]
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return value
|
||||||
|
end
|
||||||
@@ -1,69 +1,37 @@
|
|||||||
require("core.Library")
|
require("core.Library")
|
||||||
GLOBAL,sThread=require("multi.intergration.loveManager").init() -- load the love2d version of the lanesManager and requires the entire multi library
|
GLOBAL,sThread=require("multi.integration.loveManager").init{threadNamespace="THREAD"} -- load the love2d version of the lanesManager and requires the entire multi library
|
||||||
--IMPORTANT
|
--IMPORTANT
|
||||||
-- Do not make the above local, this is the one difference that the lanesManager does not have
|
-- Do not make the above local, this is the one difference that the lanesManager does not have
|
||||||
-- If these are local the functions will have the upvalues put into them that do not exist on the threaded side
|
-- If these are local the functions will have the up-values put into them that do not exist on the threaded side
|
||||||
-- You will need to ensure that the function does not refer to any upvalues in its code. It will print an error if it does though
|
-- You will need to ensure that the function does not refer to any up-values in its code. It will print an error if it does though
|
||||||
-- Also each thread has a .1 second delay! This is used to generate a random values for each thread!
|
-- Also each thread has a .1 second delay! This is used to generate a random values for each thread!
|
||||||
require("core.GuiManager") -- allows the use of graphics in the program.
|
require("core.GuiManager") -- allows the use of graphics in the program.
|
||||||
gui.ff.Color=Color.Black
|
gui.ff.Color=Color.Black
|
||||||
function comma_value(amount)
|
multi:newSystemThread("Test_Thread_1",function()
|
||||||
local formatted = amount
|
require("multi")
|
||||||
while true do
|
test = sThread.waitFor("testthing"):init()
|
||||||
formatted, k = string.gsub(formatted, "^(-?%d+)(%d%d%d)", '%1,%2')
|
multi:newTLoop(function()
|
||||||
if (k==0) then
|
print("------")
|
||||||
break
|
for i,v in pairs(test.tab) do
|
||||||
|
print("T1",i,v)
|
||||||
end
|
end
|
||||||
|
end,1)
|
||||||
|
multi:mainloop()
|
||||||
|
end)
|
||||||
|
multi:newSystemThread("Test_Thread_1",function()
|
||||||
|
require("multi")
|
||||||
|
test = sThread.waitFor("testthing"):init()
|
||||||
|
multi:newTLoop(function()
|
||||||
|
print("------")
|
||||||
|
for i,v in pairs(test.tab) do
|
||||||
|
print("T2",i,v)
|
||||||
end
|
end
|
||||||
return formatted
|
end,1)
|
||||||
end
|
multi:mainloop()
|
||||||
multi:newSystemThread("test1",function() -- Another difference is that the multi library is already loaded in the threaded enviroment as well as a call to multi:mainloop()
|
|
||||||
multi:benchMark(sThread.waitFor("Bench"),nil,"Thread 1"):OnBench(function(self,c) GLOBAL["T1"]=c multi:Stop() end)
|
|
||||||
end)
|
end)
|
||||||
multi:newSystemThread("test2",function() -- spawns a thread in another lua process
|
test = multi:newSystemThreadedTable("testthing"):init()
|
||||||
multi:benchMark(sThread.waitFor("Bench"),nil,"Thread 2"):OnBench(function(self,c) GLOBAL["T2"]=c multi:Stop() end)
|
multi:newTLoop(function()
|
||||||
end)
|
local a,b = multi.randomString(8),multi.randomString(4)
|
||||||
multi:newSystemThread("test3",function() -- spawns a thread in another lua process
|
print(">",a,b)
|
||||||
multi:benchMark(sThread.waitFor("Bench"),nil,"Thread 3"):OnBench(function(self,c) GLOBAL["T3"]=c multi:Stop() end)
|
test[a]=b
|
||||||
end)
|
end,1)
|
||||||
multi:newSystemThread("test4",function() -- spawns a thread in another lua process
|
|
||||||
multi:benchMark(sThread.waitFor("Bench"),nil,"Thread 4"):OnBench(function(self,c) GLOBAL["T4"]=c multi:Stop() end)
|
|
||||||
end)
|
|
||||||
multi:newSystemThread("test5",function() -- spawns a thread in another lua process
|
|
||||||
multi:benchMark(sThread.waitFor("Bench"),nil,"Thread 5"):OnBench(function(self,c) GLOBAL["T5"]=c multi:Stop() end)
|
|
||||||
end)
|
|
||||||
multi:newSystemThread("test6",function() -- spawns a thread in another lua process
|
|
||||||
multi:benchMark(sThread.waitFor("Bench"),nil,"Thread 6"):OnBench(function(self,c) GLOBAL["T6"]=c multi:Stop() end)
|
|
||||||
end)
|
|
||||||
multi:newSystemThread("Combiner",function() -- spawns a thread in another lua process
|
|
||||||
function comma_value(amount)
|
|
||||||
local formatted = amount
|
|
||||||
while true do
|
|
||||||
formatted, k = string.gsub(formatted, "^(-?%d+)(%d%d%d)", '%1,%2')
|
|
||||||
if (k==0) then
|
|
||||||
break
|
|
||||||
end
|
|
||||||
end
|
|
||||||
return formatted
|
|
||||||
end
|
|
||||||
local b=comma_value(tostring(sThread.waitFor("T1")+sThread.waitFor("T2")+sThread.waitFor("T3")+sThread.waitFor("T4")+sThread.waitFor("T5")+sThread.waitFor("T6")))
|
|
||||||
GLOBAL["DONE"]=b
|
|
||||||
end)
|
|
||||||
multi:newThread("test0",function()
|
|
||||||
-- sThread.waitFor("DONE") -- lets hold the main thread completely so we don't eat up cpu
|
|
||||||
-- os.exit()
|
|
||||||
-- when the main thread is holding there is a chance that error handling on the system threads may not work!
|
|
||||||
-- instead we can do this
|
|
||||||
while true do
|
|
||||||
thread.skip(1) -- allow error handling to take place... Otherwise lets keep the main thread running on the low
|
|
||||||
-- Before we held just because we could... But this is a game and we need to have logic continue
|
|
||||||
--sThreadM.sleep(.001) -- Sleeping for .001 is a greeat way to keep cpu usage down. Make sure if you aren't doing work to rest. Abuse the hell out of GLOBAL if you need to :P
|
|
||||||
if GLOBAL["DONE"] then
|
|
||||||
t.text="Bench: "..GLOBAL["DONE"]
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end)
|
|
||||||
GLOBAL["Bench"]=3
|
|
||||||
t=gui:newTextLabel("no done yet!",0,0,300,100)
|
|
||||||
t:centerX()
|
|
||||||
t:centerY()
|
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
require("core.Library")
|
require("core.Library")
|
||||||
GLOBAL,sThread=require("multi.intergration.loveManager").init() -- load the love2d version of the lanesManager and requires the entire multi library
|
GLOBAL,sThread=require("multi.integration.loveManager").init() -- load the love2d version of the lanesManager and requires the entire multi library
|
||||||
--IMPORTANT
|
--IMPORTANT
|
||||||
-- Do not make the above local, this is the one difference that the lanesManager does not have
|
-- Do not make the above local, this is the one difference that the lanesManager does not have
|
||||||
-- If these are local the functions will have the upvalues put into them that do not exist on the threaded side
|
-- If these are local the functions will have the upvalues put into them that do not exist on the threaded side
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
require("core.Library")
|
require("core.Library")
|
||||||
GLOBAL,sThread=require("multi.intergration.loveManager").init() -- load the love2d version of the lanesManager and requires the entire multi library
|
GLOBAL,sThread=require("multi.integration.loveManager").init() -- load the love2d version of the lanesManager and requires the entire multi library
|
||||||
--IMPORTANT
|
--IMPORTANT
|
||||||
-- Do not make the above local, this is the one difference that the lanesManager does not have
|
-- Do not make the above local, this is the one difference that the lanesManager does not have
|
||||||
-- If these are local the functions will have the upvalues put into them that do not exist on the threaded side
|
-- If these are local the functions will have the upvalues put into them that do not exist on the threaded side
|
||||||
|
|||||||
@@ -0,0 +1,19 @@
|
|||||||
|
require("core.Library")
|
||||||
|
GLOBAL,sThread=require("multi.integration.loveManager").init() -- load the love2d version of the lanesManager and requires the entire multi library
|
||||||
|
require("core.GuiManager")
|
||||||
|
gui.ff.Color=Color.Black
|
||||||
|
test=multi:newSystemThreadedTable("YO"):init()
|
||||||
|
test["test1"]="lol"
|
||||||
|
multi:newSystemThread("test",function()
|
||||||
|
tab=sThread.waitFor("YO"):init()
|
||||||
|
print(tab["test1"])
|
||||||
|
sThread.sleep(3)
|
||||||
|
tab["test2"]="Whats so funny?"
|
||||||
|
end)
|
||||||
|
multi:newThread("test2",function()
|
||||||
|
print(test:waitFor("test2"))
|
||||||
|
t.text="DONE!"
|
||||||
|
end)
|
||||||
|
t=gui:newTextLabel("no done yet!",0,0,300,100)
|
||||||
|
t:centerX()
|
||||||
|
t:centerY()
|
||||||
@@ -0,0 +1,32 @@
|
|||||||
|
require("core.Library")
|
||||||
|
GLOBAL,sThread=require("multi.integration.loveManager").init() -- load the love2d version of the lanesManager and requires the entire multi library
|
||||||
|
require("core.GuiManager")
|
||||||
|
gui.ff.Color=Color.Black
|
||||||
|
jQueue=multi:newSystemThreadedJobQueue() -- this internally creates System threads, We told it to use a maximum of 3 cores at any given time
|
||||||
|
jQueue:registerJob("TEST_JOB",function(a,s)
|
||||||
|
math.randomseed(s)
|
||||||
|
print("testing...")
|
||||||
|
-- We will push a random #
|
||||||
|
TEST_JOB2() -- You can call other registered functions as well!
|
||||||
|
return math.random(0,255) -- send the result to the main thread
|
||||||
|
end)
|
||||||
|
jQueue:registerJob("TEST_JOB2",function(a,s)
|
||||||
|
print("Test Works!")
|
||||||
|
end)
|
||||||
|
jQueue:start()
|
||||||
|
tableOfOrder={}
|
||||||
|
jQueue.OnJobCompleted(function(JOBID,n)
|
||||||
|
-- JOBID is the completed job, starts at 1 and counts up by 1.
|
||||||
|
-- Threads finish at different times so jobids may be returned out of order! Be sure to have a way to order them
|
||||||
|
tableOfOrder[JOBID]=n -- we order ours by putting them into a table
|
||||||
|
if #tableOfOrder==10 then
|
||||||
|
print("We got all of the pieces!")
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
for i=1,10 do -- Job Name of registered function, ... varargs
|
||||||
|
jQueue:pushJob("TEST_JOB","This is a test!",math.random(1,1000000))
|
||||||
|
end
|
||||||
|
print("I pushed all of the jobs :)")
|
||||||
|
t=gui:newTextLabel("no done yet!",0,0,300,100)
|
||||||
|
t:centerX()
|
||||||
|
t:centerY()
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
require("core.Library")
|
||||||
|
GLOBAL,sThread=require("multi.integration.loveManager").init() -- load the love2d version of the lanesManager and requires the entire multi library
|
||||||
|
require("core.GuiManager")
|
||||||
|
gui.ff.Color=Color.Black
|
||||||
|
cmd=multi:newSystemThreadedExecute("C:/SystemThreadedExecuteTest.lua")
|
||||||
|
cmd.OnCMDFinished(function(code)
|
||||||
|
print("Got Code: "..code)
|
||||||
|
end)
|
||||||
|
multi:newTLoop(function()
|
||||||
|
print("...")
|
||||||
|
end,1)
|
||||||
|
t=gui:newTextLabel("no done yet!",0,0,300,100)
|
||||||
|
t:centerX()
|
||||||
|
t:centerY()
|
||||||
@@ -0,0 +1,69 @@
|
|||||||
|
require("core.Library")
|
||||||
|
GLOBAL,sThread=require("multi.integration.loveManager").init() -- load the love2d version of the lanesManager and requires the entire multi library
|
||||||
|
--IMPORTANT
|
||||||
|
-- Do not make the above local, this is the one difference that the lanesManager does not have
|
||||||
|
-- If these are local the functions will have the upvalues put into them that do not exist on the threaded side
|
||||||
|
-- You will need to ensure that the function does not refer to any upvalues in its code. It will print an error if it does though
|
||||||
|
-- Also each thread has a .1 second delay! This is used to generate a random values for each thread!
|
||||||
|
require("core.GuiManager") -- allows the use of graphics in the program.
|
||||||
|
gui.ff.Color=Color.Black
|
||||||
|
function comma_value(amount)
|
||||||
|
local formatted = amount
|
||||||
|
while true do
|
||||||
|
formatted, k = string.gsub(formatted, "^(-?%d+)(%d%d%d)", '%1,%2')
|
||||||
|
if (k==0) then
|
||||||
|
break
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return formatted
|
||||||
|
end
|
||||||
|
multi:newSystemThread("test1",function() -- Another difference is that the multi library is already loaded in the threaded enviroment as well as a call to multi:mainloop()
|
||||||
|
multi:benchMark(sThread.waitFor("Bench"),nil,"Thread 1"):OnBench(function(self,c) GLOBAL["T1"]=c multi:Stop() end)
|
||||||
|
end)
|
||||||
|
multi:newSystemThread("test2",function() -- spawns a thread in another lua process
|
||||||
|
multi:benchMark(sThread.waitFor("Bench"),nil,"Thread 2"):OnBench(function(self,c) GLOBAL["T2"]=c multi:Stop() end)
|
||||||
|
end)
|
||||||
|
multi:newSystemThread("test3",function() -- spawns a thread in another lua process
|
||||||
|
multi:benchMark(sThread.waitFor("Bench"),nil,"Thread 3"):OnBench(function(self,c) GLOBAL["T3"]=c multi:Stop() end)
|
||||||
|
end)
|
||||||
|
multi:newSystemThread("test4",function() -- spawns a thread in another lua process
|
||||||
|
multi:benchMark(sThread.waitFor("Bench"),nil,"Thread 4"):OnBench(function(self,c) GLOBAL["T4"]=c multi:Stop() end)
|
||||||
|
end)
|
||||||
|
multi:newSystemThread("test5",function() -- spawns a thread in another lua process
|
||||||
|
multi:benchMark(sThread.waitFor("Bench"),nil,"Thread 5"):OnBench(function(self,c) GLOBAL["T5"]=c multi:Stop() end)
|
||||||
|
end)
|
||||||
|
multi:newSystemThread("test6",function() -- spawns a thread in another lua process
|
||||||
|
multi:benchMark(sThread.waitFor("Bench"),nil,"Thread 6"):OnBench(function(self,c) GLOBAL["T6"]=c multi:Stop() end)
|
||||||
|
end)
|
||||||
|
multi:newSystemThread("Combiner",function() -- spawns a thread in another lua process
|
||||||
|
function comma_value(amount)
|
||||||
|
local formatted = amount
|
||||||
|
while true do
|
||||||
|
formatted, k = string.gsub(formatted, "^(-?%d+)(%d%d%d)", '%1,%2')
|
||||||
|
if (k==0) then
|
||||||
|
break
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return formatted
|
||||||
|
end
|
||||||
|
local b=comma_value(tostring(sThread.waitFor("T1")+sThread.waitFor("T2")+sThread.waitFor("T3")+sThread.waitFor("T4")+sThread.waitFor("T5")+sThread.waitFor("T6")))
|
||||||
|
GLOBAL["DONE"]=b
|
||||||
|
end)
|
||||||
|
multi:newThread("test0",function()
|
||||||
|
-- sThread.waitFor("DONE") -- lets hold the main thread completely so we don't eat up cpu
|
||||||
|
-- os.exit()
|
||||||
|
-- when the main thread is holding there is a chance that error handling on the system threads may not work!
|
||||||
|
-- instead we can do this
|
||||||
|
while true do
|
||||||
|
thread.skip(1) -- allow error handling to take place... Otherwise lets keep the main thread running on the low
|
||||||
|
-- Before we held just because we could... But this is a game and we need to have logic continue
|
||||||
|
--sThreadM.sleep(.001) -- Sleeping for .001 is a greeat way to keep cpu usage down. Make sure if you aren't doing work to rest. Abuse the hell out of GLOBAL if you need to :P
|
||||||
|
if GLOBAL["DONE"] then
|
||||||
|
t.text="Bench: "..GLOBAL["DONE"]
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
GLOBAL["Bench"]=3
|
||||||
|
t=gui:newTextLabel("no done yet!",0,0,300,100)
|
||||||
|
t:centerX()
|
||||||
|
t:centerY()
|
||||||
@@ -1,9 +1 @@
|
|||||||
require("multi")
|
require("multi")
|
||||||
require("multi.threading")
|
|
||||||
require("multi.threading.alarm")
|
|
||||||
require("multi.threading.event")
|
|
||||||
require("multi.threading.loop")
|
|
||||||
require("multi.threading.process")
|
|
||||||
require("multi.threading.step")
|
|
||||||
require("multi.threading.tstep")
|
|
||||||
require("multi.threading.updater")
|
|
||||||
|
|||||||
@@ -21,72 +21,12 @@ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|||||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
SOFTWARE.
|
SOFTWARE.
|
||||||
]]
|
]]
|
||||||
require("multi.all")
|
require("multi")
|
||||||
os.sleep=love.timer.sleep
|
os.sleep=love.timer.sleep
|
||||||
--~ function bin.load(file,s,r)
|
|
||||||
--~ content, size = love.filesystem.read(file)
|
|
||||||
--~ local temp=bin.new(content)
|
|
||||||
--~ temp.filepath=file
|
|
||||||
--~ return temp
|
|
||||||
--~ end
|
|
||||||
--~ function bin:tofile(filename)
|
|
||||||
--~ if not(filename) or self.Stream then return nil end
|
|
||||||
--~ love.filesystem.write(filename,self.data)
|
|
||||||
--~ end
|
|
||||||
--~ function bin.stream(file,l)
|
|
||||||
--~ error("Sorry streaming is not available when using love2d :(, I am looking for a solution though :)")
|
|
||||||
--~ end
|
|
||||||
function love.run()
|
|
||||||
if love.math then
|
|
||||||
love.math.setRandomSeed(os.time())
|
|
||||||
end
|
|
||||||
if love.event then
|
|
||||||
love.event.pump()
|
|
||||||
end
|
|
||||||
if love.load then love.load(arg) end
|
|
||||||
if love.timer then love.timer.step() end
|
|
||||||
local dt = 0
|
|
||||||
while true do
|
|
||||||
-- Process events.
|
|
||||||
if love.event then
|
|
||||||
love.event.pump()
|
|
||||||
for e,a,b,c,d in love.event.poll() do
|
|
||||||
if e == "quit" then
|
|
||||||
if not love.quit or not love.quit() then
|
|
||||||
if love.audio then
|
|
||||||
love.audio.stop()
|
|
||||||
end
|
|
||||||
return
|
|
||||||
end
|
|
||||||
end
|
|
||||||
love.handlers[e](a,b,c,d)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
if love.timer then
|
|
||||||
love.timer.step()
|
|
||||||
dt = love.timer.getDelta()
|
|
||||||
end
|
|
||||||
if love.update then love.update(dt) end
|
|
||||||
if multi.boost then
|
|
||||||
for i=1,multi.boost-1 do
|
|
||||||
multi:uManager(dt)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
multi:uManager(dt)
|
|
||||||
if love.window and love.graphics and love.window.isCreated() then
|
|
||||||
love.graphics.clear()
|
|
||||||
love.graphics.origin()
|
|
||||||
if love.draw then love.draw() end
|
|
||||||
multi.dManager()
|
|
||||||
love.graphics.setColor(255,255,255,255)
|
|
||||||
if multi.draw then multi.draw() end
|
|
||||||
love.graphics.present()
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
multi.drawF={}
|
multi.drawF={}
|
||||||
function multi:dManager()
|
function multi.dManager()
|
||||||
for ii=1,#multi.drawF do
|
for ii=1,#multi.drawF do
|
||||||
|
love.graphics.setColor(255,255,255,255)
|
||||||
multi.drawF[ii]()
|
multi.drawF[ii]()
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -94,34 +34,3 @@ function multi:onDraw(func,i)
|
|||||||
i=i or 1
|
i=i or 1
|
||||||
table.insert(self.drawF,i,func)
|
table.insert(self.drawF,i,func)
|
||||||
end
|
end
|
||||||
function multi:lManager()
|
|
||||||
if love.event then
|
|
||||||
love.event.pump()
|
|
||||||
for e,a,b,c,d in love.event.poll() do
|
|
||||||
if e == "quit" then
|
|
||||||
if not love.quit or not love.quit() then
|
|
||||||
if love.audio then
|
|
||||||
love.audio.stop()
|
|
||||||
end
|
|
||||||
return nil
|
|
||||||
end
|
|
||||||
end
|
|
||||||
love.handlers[e](a,b,c,d)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
if love.timer then
|
|
||||||
love.timer.step()
|
|
||||||
dt = love.timer.getDelta()
|
|
||||||
end
|
|
||||||
if love.update then love.update(dt) end
|
|
||||||
multi:uManager(dt)
|
|
||||||
if love.window and love.graphics and love.window.isCreated() then
|
|
||||||
love.graphics.clear()
|
|
||||||
love.graphics.origin()
|
|
||||||
if love.draw then love.draw() end
|
|
||||||
multi.dManager()
|
|
||||||
love.graphics.setColor(255,255,255,255)
|
|
||||||
if multi.draw then multi.draw() end
|
|
||||||
love.graphics.present()
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
+23
-13
@@ -21,6 +21,7 @@ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|||||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
SOFTWARE.
|
SOFTWARE.
|
||||||
]]
|
]]
|
||||||
|
package.path="?/init.lua;?.lua;"..package.path
|
||||||
function os.getOS()
|
function os.getOS()
|
||||||
if package.config:sub(1,1)=='\\' then
|
if package.config:sub(1,1)=='\\' then
|
||||||
return 'windows'
|
return 'windows'
|
||||||
@@ -30,11 +31,15 @@ function os.getOS()
|
|||||||
end
|
end
|
||||||
-- Step 1 get lanes
|
-- Step 1 get lanes
|
||||||
lanes=require("lanes").configure()
|
lanes=require("lanes").configure()
|
||||||
package.path="lua/?/init.lua;lua/?.lua;"..package.path
|
--~ package.path="lua/?/init.lua;lua/?.lua;"..package.path
|
||||||
require("multi.all") -- get it all and have it on all lanes
|
require("multi") -- get it all and have it on all lanes
|
||||||
|
isMainThread=true
|
||||||
function multi:canSystemThread()
|
function multi:canSystemThread()
|
||||||
return true
|
return true
|
||||||
end
|
end
|
||||||
|
function multi:getPlatform()
|
||||||
|
return "lanes"
|
||||||
|
end
|
||||||
local multi=multi
|
local multi=multi
|
||||||
-- Step 2 set up the linda objects
|
-- Step 2 set up the linda objects
|
||||||
local __GlobalLinda = lanes.linda() -- handles global stuff
|
local __GlobalLinda = lanes.linda() -- handles global stuff
|
||||||
@@ -85,7 +90,10 @@ else
|
|||||||
THREAD.__CORES=tonumber(io.popen("nproc --all"):read("*n"))
|
THREAD.__CORES=tonumber(io.popen("nproc --all"):read("*n"))
|
||||||
end
|
end
|
||||||
function THREAD.kill() -- trigger the lane destruction
|
function THREAD.kill() -- trigger the lane destruction
|
||||||
-- coroutine.yield({"_kill_",":)"})
|
error("Thread was killed!")
|
||||||
|
end
|
||||||
|
function THREAD.getName()
|
||||||
|
return THREAD_NAME
|
||||||
end
|
end
|
||||||
--[[ Step 4 We need to get sleeping working to handle timing... We want idle wait, not busy wait
|
--[[ Step 4 We need to get sleeping working to handle timing... We want idle wait, not busy wait
|
||||||
Idle wait keeps the CPU running better where busy wait wastes CPU cycles... Lanes does not have a sleep method
|
Idle wait keeps the CPU running better where busy wait wastes CPU cycles... Lanes does not have a sleep method
|
||||||
@@ -102,12 +110,17 @@ function THREAD.hold(n)
|
|||||||
repeat wait() until n()
|
repeat wait() until n()
|
||||||
end
|
end
|
||||||
-- Step 5 Basic Threads!
|
-- Step 5 Basic Threads!
|
||||||
function multi:newSystemThread(name,func)
|
function multi:newSystemThread(name,func,...)
|
||||||
local c={}
|
local c={}
|
||||||
local __self=c
|
local __self=c
|
||||||
c.name=name
|
c.name=name
|
||||||
c.Type="sthread"
|
c.Type="sthread"
|
||||||
c.thread=lanes.gen("*", func)()
|
local THREAD_NAME=name
|
||||||
|
local function func2(...)
|
||||||
|
_G["THREAD_NAME"]=THREAD_NAME
|
||||||
|
func()
|
||||||
|
end
|
||||||
|
c.thread=lanes.gen("*", func2)(...)
|
||||||
function c:kill()
|
function c:kill()
|
||||||
--self.status:Destroy()
|
--self.status:Destroy()
|
||||||
self.thread:cancel()
|
self.thread:cancel()
|
||||||
@@ -125,12 +138,9 @@ function multi:newSystemThread(name,func)
|
|||||||
end)
|
end)
|
||||||
return c
|
return c
|
||||||
end
|
end
|
||||||
print("Intergrated Lanes!")
|
print("Integrated Lanes!")
|
||||||
multi.intergration={} -- for module creators
|
multi.integration={} -- for module creators
|
||||||
multi.intergration.GLOBAL=GLOBAL
|
multi.integration.GLOBAL=GLOBAL
|
||||||
multi.intergration.THREAD=THREAD
|
multi.integration.THREAD=THREAD
|
||||||
multi.intergration.lanes={}
|
require("multi.integration.shared")
|
||||||
multi.intergration.lanes.GLOBAL=GLOBAL -- for module creators
|
|
||||||
multi.intergration.lanes.THREAD=THREAD -- for module creators
|
|
||||||
require("multi.intergration.shared.shared")
|
|
||||||
return {init=function() return GLOBAL,THREAD end}
|
return {init=function() return GLOBAL,THREAD end}
|
||||||
+71
-88
@@ -2,20 +2,29 @@ require("multi.compat.love2d")
|
|||||||
function multi:canSystemThread()
|
function multi:canSystemThread()
|
||||||
return true
|
return true
|
||||||
end
|
end
|
||||||
multi.intergration={}
|
function multi:getPlatform()
|
||||||
multi.intergration.love2d={}
|
return "love2d"
|
||||||
multi.intergration.love2d.ThreadBase=[[
|
end
|
||||||
__THREADNAME__=({...})[1]
|
multi.integration={}
|
||||||
|
multi.integration.love2d={}
|
||||||
|
multi.integration.love2d.ThreadBase=[[
|
||||||
|
tab={...}
|
||||||
|
__THREADID__=table.remove(tab,1)
|
||||||
|
__THREADNAME__=table.remove(tab,1)
|
||||||
require("love.filesystem")
|
require("love.filesystem")
|
||||||
require("love.system")
|
require("love.system")
|
||||||
require("love.timer")
|
require("love.timer")
|
||||||
require("multi.all")
|
require("love.image")
|
||||||
|
require("multi")
|
||||||
GLOBAL={}
|
GLOBAL={}
|
||||||
|
isMainThread=false
|
||||||
setmetatable(GLOBAL,{
|
setmetatable(GLOBAL,{
|
||||||
__index=function(t,k)
|
__index=function(t,k)
|
||||||
|
__sync__()
|
||||||
return __proxy__[k]
|
return __proxy__[k]
|
||||||
end,
|
end,
|
||||||
__newindex=function(t,k,v)
|
__newindex=function(t,k,v)
|
||||||
|
__sync__()
|
||||||
__proxy__[k]=v
|
__proxy__[k]=v
|
||||||
if type(v)=="userdata" then
|
if type(v)=="userdata" then
|
||||||
__MainChan__:push(v)
|
__MainChan__:push(v)
|
||||||
@@ -24,6 +33,24 @@ setmetatable(GLOBAL,{
|
|||||||
end
|
end
|
||||||
end,
|
end,
|
||||||
})
|
})
|
||||||
|
function __sync__()
|
||||||
|
local data=__mythread__:pop()
|
||||||
|
while data do
|
||||||
|
love.timer.sleep(.01)
|
||||||
|
if type(data)=="string" then
|
||||||
|
local cmd,tp,name,d=data:match("(%S-) (%S-) (%S-) (.+)")
|
||||||
|
if name=="__DIEPLZ"..__THREADID__.."__" then
|
||||||
|
error("Thread: "..__THREADID__.." has been stopped!")
|
||||||
|
end
|
||||||
|
if cmd=="SYNC" then
|
||||||
|
__proxy__[name]=resolveType(tp,d)
|
||||||
|
end
|
||||||
|
else
|
||||||
|
__proxy__[name]=data
|
||||||
|
end
|
||||||
|
data=__mythread__:pop()
|
||||||
|
end
|
||||||
|
end
|
||||||
function ToStr(val, name, skipnewlines, depth)
|
function ToStr(val, name, skipnewlines, depth)
|
||||||
skipnewlines = skipnewlines or false
|
skipnewlines = skipnewlines or false
|
||||||
depth = depth or 0
|
depth = depth or 0
|
||||||
@@ -60,7 +87,7 @@ function resolveType(tp,d)
|
|||||||
elseif tp=="bool" then
|
elseif tp=="bool" then
|
||||||
return (d=="true")
|
return (d=="true")
|
||||||
elseif tp=="function" then
|
elseif tp=="function" then
|
||||||
return loadDump(d)
|
return loadDump("[==["..d.."]==]")
|
||||||
elseif tp=="table" then
|
elseif tp=="table" then
|
||||||
return loadstring("return "..d)()
|
return loadstring("return "..d)()
|
||||||
elseif tp=="nil" then
|
elseif tp=="nil" then
|
||||||
@@ -72,11 +99,11 @@ end
|
|||||||
function resolveData(v)
|
function resolveData(v)
|
||||||
local data=""
|
local data=""
|
||||||
if type(v)=="table" then
|
if type(v)=="table" then
|
||||||
data=ToStr(v)
|
return ToStr(v)
|
||||||
elseif type(v)=="function" then
|
elseif type(v)=="function" then
|
||||||
data=dump(v)
|
return dump(v)
|
||||||
elseif type(v)=="string" or type(v)=="number" or type(v)=="bool" or type(v)=="nil" then
|
elseif type(v)=="string" or type(v)=="number" or type(v)=="bool" or type(v)=="nil" then
|
||||||
data=tostring(v)
|
return tostring(v)
|
||||||
end
|
end
|
||||||
return data
|
return data
|
||||||
end
|
end
|
||||||
@@ -114,6 +141,12 @@ function dump(func)
|
|||||||
end
|
end
|
||||||
return table.concat(code)
|
return table.concat(code)
|
||||||
end
|
end
|
||||||
|
function sThread.getName()
|
||||||
|
return __THREADNAME__
|
||||||
|
end
|
||||||
|
function sThread.kill()
|
||||||
|
error("Thread was killed!")
|
||||||
|
end
|
||||||
function sThread.set(name,val)
|
function sThread.set(name,val)
|
||||||
GLOBAL[name]=val
|
GLOBAL[name]=val
|
||||||
end
|
end
|
||||||
@@ -121,25 +154,7 @@ function sThread.get(name)
|
|||||||
return GLOBAL[name]
|
return GLOBAL[name]
|
||||||
end
|
end
|
||||||
function sThread.waitFor(name)
|
function sThread.waitFor(name)
|
||||||
--print("Waiting:",__mythreadname__)
|
repeat __sync__() until GLOBAL[name]
|
||||||
local function wait()
|
|
||||||
local data=__mythread__:pop()
|
|
||||||
while data do
|
|
||||||
if type(data)=="string" then
|
|
||||||
local cmd,tp,name,d=data:match("(%S-) (%S-) (%S-) (.+)")
|
|
||||||
if name=="__DIEPLZ"..__THREADNAME__.."__" then
|
|
||||||
error("Thread: "..__THREADNAME__.." has been stopped!")
|
|
||||||
end
|
|
||||||
if cmd=="SYNC" then
|
|
||||||
__proxy__[name]=resolveType(tp,d)
|
|
||||||
end
|
|
||||||
else
|
|
||||||
__proxy__[name]=data
|
|
||||||
end
|
|
||||||
data=__mythread__:pop()
|
|
||||||
end
|
|
||||||
end
|
|
||||||
repeat wait() until GLOBAL[name]
|
|
||||||
return GLOBAL[name]
|
return GLOBAL[name]
|
||||||
end
|
end
|
||||||
function sThread.getCores()
|
function sThread.getCores()
|
||||||
@@ -149,44 +164,11 @@ function sThread.sleep(n)
|
|||||||
love.timer.sleep(n)
|
love.timer.sleep(n)
|
||||||
end
|
end
|
||||||
function sThread.hold(n)
|
function sThread.hold(n)
|
||||||
local function wait()
|
repeat __sync__() until n()
|
||||||
local data=__mythread__:pop()
|
|
||||||
while data do
|
|
||||||
if type(data)=="string" then
|
|
||||||
local cmd,tp,name,d=data:match("(%S-) (%S-) (%S-) (.+)")
|
|
||||||
if name=="__DIEPLZ"..__THREADNAME__.."__" then
|
|
||||||
error("Thread: "..__THREADNAME__.." has been stopped!")
|
|
||||||
end
|
|
||||||
if cmd=="SYNC" then
|
|
||||||
__proxy__[name]=resolveType(tp,d)
|
|
||||||
end
|
|
||||||
else
|
|
||||||
__proxy__[name]=data
|
|
||||||
end
|
|
||||||
data=__mythread__:pop()
|
|
||||||
end
|
|
||||||
end
|
|
||||||
repeat wait() until n()
|
|
||||||
end
|
end
|
||||||
updater=multi:newUpdater()
|
updater=multi:newUpdater()
|
||||||
updater:OnUpdate(function(self)
|
updater:OnUpdate(__sync__)
|
||||||
local data=__mythread__:pop()
|
func=loadDump([=[INSERT_USER_CODE]=])(unpack(tab))
|
||||||
while data do
|
|
||||||
if type(data)=="string" then
|
|
||||||
local cmd,tp,name,d=data:match("(%S-) (%S-) (%S-) (.+)")
|
|
||||||
if name=="__DIEPLZ"..__THREADNAME__.."__" then
|
|
||||||
error("Thread: "..__THREADNAME__.." has been stopped!")
|
|
||||||
end
|
|
||||||
if cmd=="SYNC" then
|
|
||||||
__proxy__[name]=resolveType(tp,d)
|
|
||||||
end
|
|
||||||
else
|
|
||||||
__proxy__[name]=data
|
|
||||||
end
|
|
||||||
data=__mythread__:pop()
|
|
||||||
end
|
|
||||||
end)
|
|
||||||
func=loadDump([=[INSERT_USER_CODE]=])()
|
|
||||||
multi:mainloop()
|
multi:mainloop()
|
||||||
]]
|
]]
|
||||||
GLOBAL={} -- Allow main thread to interact with these objects as well
|
GLOBAL={} -- Allow main thread to interact with these objects as well
|
||||||
@@ -207,7 +189,11 @@ setmetatable(GLOBAL,{
|
|||||||
end,
|
end,
|
||||||
})
|
})
|
||||||
THREAD={} -- Allow main thread to interact with these objects as well
|
THREAD={} -- Allow main thread to interact with these objects as well
|
||||||
multi.intergration.love2d.mainChannel=love.thread.getChannel("__MainChan__")
|
multi.integration.love2d.mainChannel=love.thread.getChannel("__MainChan__")
|
||||||
|
isMainThread=true
|
||||||
|
function THREAD.getName()
|
||||||
|
return __THREADNAME__
|
||||||
|
end
|
||||||
function ToStr(val, name, skipnewlines, depth)
|
function ToStr(val, name, skipnewlines, depth)
|
||||||
skipnewlines = skipnewlines or false
|
skipnewlines = skipnewlines or false
|
||||||
depth = depth or 0
|
depth = depth or 0
|
||||||
@@ -244,7 +230,7 @@ function resolveType(tp,d)
|
|||||||
elseif tp=="bool" then
|
elseif tp=="bool" then
|
||||||
return (d=="true")
|
return (d=="true")
|
||||||
elseif tp=="function" then
|
elseif tp=="function" then
|
||||||
return loadDump(d)
|
return loadDump("[==["..d.."]==]")
|
||||||
elseif tp=="table" then
|
elseif tp=="table" then
|
||||||
return loadstring("return "..d)()
|
return loadstring("return "..d)()
|
||||||
elseif tp=="nil" then
|
elseif tp=="nil" then
|
||||||
@@ -256,11 +242,11 @@ end
|
|||||||
function resolveData(v)
|
function resolveData(v)
|
||||||
local data=""
|
local data=""
|
||||||
if type(v)=="table" then
|
if type(v)=="table" then
|
||||||
data=ToStr(v)
|
return ToStr(v)
|
||||||
elseif type(v)=="function" then
|
elseif type(v)=="function" then
|
||||||
data=dump(v)
|
return dump(v)
|
||||||
elseif type(v)=="string" or type(v)=="number" or type(v)=="bool" or type(v)=="nil" then
|
elseif type(v)=="string" or type(v)=="number" or type(v)=="bool" or type(v)=="nil" then
|
||||||
data=tostring(v)
|
return tostring(v)
|
||||||
end
|
end
|
||||||
return data
|
return data
|
||||||
end
|
end
|
||||||
@@ -286,14 +272,14 @@ local function randomString(n)
|
|||||||
end
|
end
|
||||||
return str
|
return str
|
||||||
end
|
end
|
||||||
function multi:newSystemThread(name,func) -- the main method
|
function multi:newSystemThread(name,func,...) -- the main method
|
||||||
local c={}
|
local c={}
|
||||||
c.name=name
|
c.name=name
|
||||||
c.ID=c.name.."<ID|"..randomString(8)..">"
|
c.ID=c.name.."<ID|"..randomString(8)..">"
|
||||||
c.thread=love.thread.newThread(multi.intergration.love2d.ThreadBase:gsub("INSERT_USER_CODE",dump(func)))
|
c.thread=love.thread.newThread(multi.integration.love2d.ThreadBase:gsub("INSERT_USER_CODE",dump(func)))
|
||||||
c.thread:start(c.ID)
|
c.thread:start(c.ID,c.name,...)
|
||||||
function c:kill()
|
function c:kill()
|
||||||
multi.intergration.GLOBAL["__DIEPLZ"..self.ID.."__"]="__DIEPLZ"..self.ID.."__"
|
multi.integration.GLOBAL["__DIEPLZ"..self.ID.."__"]="__DIEPLZ"..self.ID.."__"
|
||||||
end
|
end
|
||||||
return c
|
return c
|
||||||
end
|
end
|
||||||
@@ -309,9 +295,7 @@ function THREAD.get(name)
|
|||||||
return GLOBAL[name]
|
return GLOBAL[name]
|
||||||
end
|
end
|
||||||
function THREAD.waitFor(name)
|
function THREAD.waitFor(name)
|
||||||
multi.OBJ_REF:Pause()
|
repeat multi:uManager() until GLOBAL[name]
|
||||||
repeat multi:lManager() until GLOBAL[name]
|
|
||||||
multi.OBJ_REF:Resume()
|
|
||||||
return GLOBAL[name]
|
return GLOBAL[name]
|
||||||
end
|
end
|
||||||
function THREAD.getCores()
|
function THREAD.getCores()
|
||||||
@@ -321,18 +305,15 @@ function THREAD.sleep(n)
|
|||||||
love.timer.sleep(n)
|
love.timer.sleep(n)
|
||||||
end
|
end
|
||||||
function THREAD.hold(n)
|
function THREAD.hold(n)
|
||||||
multi.OBJ_REF:Pause()
|
repeat multi:uManager() until n()
|
||||||
repeat multi:lManager() until n()
|
|
||||||
multi.OBJ_REF:Resume()
|
|
||||||
end
|
end
|
||||||
__channels__={}
|
__channels__={}
|
||||||
multi.intergration.GLOBAL=GLOBAL
|
multi.integration.GLOBAL=GLOBAL
|
||||||
multi.intergration.THREAD=THREAD
|
multi.integration.THREAD=THREAD
|
||||||
updater=multi:newUpdater()
|
updater=multi:newUpdater()
|
||||||
updater:OnUpdate(function(self)
|
updater:OnUpdate(function(self)
|
||||||
local data=multi.intergration.love2d.mainChannel:pop()
|
local data=multi.integration.love2d.mainChannel:pop()
|
||||||
while data do
|
while data do
|
||||||
--print("MAIN:",data)
|
|
||||||
if type(data)=="string" then
|
if type(data)=="string" then
|
||||||
local cmd,tp,name,d=data:match("(%S-) (%S-) (%S-) (.+)")
|
local cmd,tp,name,d=data:match("(%S-) (%S-) (%S-) (.+)")
|
||||||
if cmd=="SYNC" then
|
if cmd=="SYNC" then
|
||||||
@@ -358,19 +339,21 @@ updater:OnUpdate(function(self)
|
|||||||
else
|
else
|
||||||
__proxy__[name]=data
|
__proxy__[name]=data
|
||||||
end
|
end
|
||||||
data=multi.intergration.love2d.mainChannel:pop()
|
data=multi.integration.love2d.mainChannel:pop()
|
||||||
end
|
end
|
||||||
end)
|
end)
|
||||||
require("multi.intergration.shared.shared")
|
require("multi.integration.shared")
|
||||||
print("Intergrated Love2d!")
|
print("Integrated Love2d!")
|
||||||
return {
|
return {
|
||||||
init=function(t)
|
init=function(t)
|
||||||
if t then
|
if t then
|
||||||
if t.threadNamespace then
|
if t.threadNamespace then
|
||||||
multi.intergration.love2d.ThreadBase:gsub("sThread",t.threadNamespace)
|
multi.integration.THREADNAME=t.threadNamespace
|
||||||
|
multi.integration.love2d.ThreadBase:gsub("sThread",t.threadNamespace)
|
||||||
end
|
end
|
||||||
if t.globalNamespace then
|
if t.globalNamespace then
|
||||||
multi.intergration.love2d.ThreadBase:gsub("GLOBAL",t.globalNamespace)
|
multi.integration.GLOBALNAME=t.globalNamespace
|
||||||
|
multi.integration.love2d.ThreadBase:gsub("GLOBAL",t.globalNamespace)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
return GLOBAL,THREAD
|
return GLOBAL,THREAD
|
||||||
@@ -0,0 +1,127 @@
|
|||||||
|
--[[
|
||||||
|
MIT License
|
||||||
|
|
||||||
|
Copyright (c) 2017 Ryan Ward
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
||||||
|
]]
|
||||||
|
|
||||||
|
-- I DEMAND USAGE FOR LUVIT
|
||||||
|
-- Cannot use discordia without my multitasking library (Which I love more that the luvit platform... then again i'm partial :P)
|
||||||
|
package.path="?/init.lua;?.lua;"..package.path
|
||||||
|
local function _INIT(luvitThread,timer)
|
||||||
|
-- lots of this stuff should be able to stay the same
|
||||||
|
function os.getOS()
|
||||||
|
if package.config:sub(1,1)=='\\' then
|
||||||
|
return 'windows'
|
||||||
|
else
|
||||||
|
return 'unix'
|
||||||
|
end
|
||||||
|
end
|
||||||
|
-- Step 1 get setup threads on luvit... Sigh how do i even...
|
||||||
|
require("multi")
|
||||||
|
isMainThread=true
|
||||||
|
function multi:canSystemThread()
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
function multi:getPlatform()
|
||||||
|
return "luvit"
|
||||||
|
end
|
||||||
|
local multi=multi
|
||||||
|
-- Step 2 set up the Global table... is this possible?
|
||||||
|
local GLOBAL={}
|
||||||
|
setmetatable(GLOBAL,{
|
||||||
|
__index=function(t,k)
|
||||||
|
--print("No Global table when using luvit integration!")
|
||||||
|
return nil
|
||||||
|
end,
|
||||||
|
__newindex=function(t,k,v)
|
||||||
|
--print("No Global table when using luvit integration!")
|
||||||
|
end,
|
||||||
|
})
|
||||||
|
local THREAD={}
|
||||||
|
function THREAD.set(name,val)
|
||||||
|
--print("No Global table when using luvit integration!")
|
||||||
|
end
|
||||||
|
function THREAD.get(name)
|
||||||
|
--print("No Global table when using luvit integration!")
|
||||||
|
end
|
||||||
|
local function randomString(n)
|
||||||
|
local str = ''
|
||||||
|
local strings = {'a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z','1','2','3','4','5','6','7','8','9','0','A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z'}
|
||||||
|
for i=1,n do
|
||||||
|
str = str..''..strings[math.random(1,#strings)]
|
||||||
|
end
|
||||||
|
return str
|
||||||
|
end
|
||||||
|
function THREAD.waitFor(name)
|
||||||
|
--print("No Global table when using luvit integration!")
|
||||||
|
end
|
||||||
|
function THREAD.testFor(name,val,sym)
|
||||||
|
--print("No Global table when using luvit integration!")
|
||||||
|
end
|
||||||
|
function THREAD.getCores()
|
||||||
|
return THREAD.__CORES
|
||||||
|
end
|
||||||
|
if os.getOS()=="windows" then
|
||||||
|
THREAD.__CORES=tonumber(os.getenv("NUMBER_OF_PROCESSORS"))
|
||||||
|
else
|
||||||
|
THREAD.__CORES=tonumber(io.popen("nproc --all"):read("*n"))
|
||||||
|
end
|
||||||
|
function THREAD.kill() -- trigger the thread destruction
|
||||||
|
error("Thread was Killed!")
|
||||||
|
end
|
||||||
|
-- hmmm if im cleaver I can get this to work... but since data passing isn't going to be a thing its probably not important
|
||||||
|
function THREAD.sleep(n)
|
||||||
|
--print("No Global table when using luvit integration!")
|
||||||
|
end
|
||||||
|
function THREAD.hold(n)
|
||||||
|
--print("No Global table when using luvit integration!")
|
||||||
|
end
|
||||||
|
-- Step 5 Basic Threads!
|
||||||
|
local function entry(path,name,func,...)
|
||||||
|
local timer = require'timer'
|
||||||
|
local luvitThread = require'thread'
|
||||||
|
package.path=path
|
||||||
|
loadstring(func)(...)
|
||||||
|
end
|
||||||
|
function multi:newSystemThread(name,func,...)
|
||||||
|
local c={}
|
||||||
|
local __self=c
|
||||||
|
c.name=name
|
||||||
|
c.Type="sthread"
|
||||||
|
c.thread={}
|
||||||
|
c.func=string.dump(func)
|
||||||
|
function c:kill()
|
||||||
|
-- print("No Global table when using luvit integration!")
|
||||||
|
end
|
||||||
|
luvitThread.start(entry,package.path,name,c.func,...)
|
||||||
|
return c
|
||||||
|
end
|
||||||
|
print("Integrated Luvit!")
|
||||||
|
multi.integration={} -- for module creators
|
||||||
|
multi.integration.GLOBAL=GLOBAL
|
||||||
|
multi.integration.THREAD=THREAD
|
||||||
|
require("multi.integration.shared")
|
||||||
|
-- Start the main mainloop... This allows you to process your multi objects, but the engine on the main thread will be limited to .001 or 1 millisecond sigh...
|
||||||
|
local interval = timer.setInterval(1, function ()
|
||||||
|
multi:uManager()
|
||||||
|
end)
|
||||||
|
end
|
||||||
|
return {init=function(threadHandle,timerHandle) _INIT(threadHandle,timerHandle) return GLOBAL,THREAD end}
|
||||||
@@ -0,0 +1,519 @@
|
|||||||
|
--[[
|
||||||
|
MIT License
|
||||||
|
|
||||||
|
Copyright (c) 2017 Ryan Ward
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
||||||
|
]]
|
||||||
|
function multi:newSystemThreadedQueue(name) -- in love2d this will spawn a channel on both ends
|
||||||
|
local c={} -- where we will store our object
|
||||||
|
c.name=name -- set the name this is important for the love2d side
|
||||||
|
if love then -- check love
|
||||||
|
if love.thread then -- make sure we can use the threading module
|
||||||
|
function c:init() -- create an init function so we can mimic on both love2d and lanes
|
||||||
|
self.chan=love.thread.getChannel(self.name) -- create channel by the name self.name
|
||||||
|
function self:push(v) -- push to the channel
|
||||||
|
local tab
|
||||||
|
if type(v)=="table" then
|
||||||
|
tab = {}
|
||||||
|
for i,c in pairs(v) do
|
||||||
|
if type(c)=="function" then
|
||||||
|
tab[i]="\1"..string.dump(c)
|
||||||
|
else
|
||||||
|
tab[i]=c
|
||||||
|
end
|
||||||
|
end
|
||||||
|
self.chan:push(tab)
|
||||||
|
else
|
||||||
|
self.chan:push(c)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
function self:pop() -- pop from the channel
|
||||||
|
local v=self.chan:pop()
|
||||||
|
if not v then return end
|
||||||
|
if type(v)=="table" then
|
||||||
|
tab = {}
|
||||||
|
for i,c in pairs(v) do
|
||||||
|
if type(c)=="string" then
|
||||||
|
if c:sub(1,1)=="\1" then
|
||||||
|
tab[i]=loadstring(c:sub(2,-1))
|
||||||
|
else
|
||||||
|
tab[i]=c
|
||||||
|
end
|
||||||
|
else
|
||||||
|
tab[i]=c
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return tab
|
||||||
|
else
|
||||||
|
return self.chan:pop()
|
||||||
|
end
|
||||||
|
end
|
||||||
|
function self:peek()
|
||||||
|
local v=self.chan:peek()
|
||||||
|
if not v then return end
|
||||||
|
if type(v)=="table" then
|
||||||
|
tab = {}
|
||||||
|
for i,c in pairs(v) do
|
||||||
|
if type(c)=="string" then
|
||||||
|
if c:sub(1,1)=="\1" then
|
||||||
|
tab[i]=loadstring(c:sub(2,-1))
|
||||||
|
else
|
||||||
|
tab[i]=c
|
||||||
|
end
|
||||||
|
else
|
||||||
|
tab[i]=c
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return tab
|
||||||
|
else
|
||||||
|
return self.chan:pop()
|
||||||
|
end
|
||||||
|
end
|
||||||
|
GLOBAL[self.name]=self -- send the object to the thread through the global interface
|
||||||
|
return self -- return the object
|
||||||
|
end
|
||||||
|
return c
|
||||||
|
else
|
||||||
|
error("Make sure you required the love.thread module!") -- tell the user if he/she didn't require said module
|
||||||
|
end
|
||||||
|
else
|
||||||
|
c.linda=lanes.linda() -- lanes is a bit easier, create the linda on the main thread
|
||||||
|
function c:push(v) -- push to the queue
|
||||||
|
self.linda:send("Q",v)
|
||||||
|
end
|
||||||
|
function c:pop() -- pop the queue
|
||||||
|
return ({self.linda:receive(0,"Q")})[2]
|
||||||
|
end
|
||||||
|
function c:peek()
|
||||||
|
return self.linda:get("Q")
|
||||||
|
end
|
||||||
|
function c:init() -- mimic the feature that love2d requires, so code can be consistent
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
multi.integration.GLOBAL[name]=c -- send the object to the thread through the global interface
|
||||||
|
end
|
||||||
|
return c
|
||||||
|
end
|
||||||
|
function multi:newSystemThreadedConnection(name,protect)
|
||||||
|
local c={}
|
||||||
|
c.name = name
|
||||||
|
c.protect=protect
|
||||||
|
local sThread=multi.integration.THREAD
|
||||||
|
local GLOBAL=multi.integration.GLOBAL
|
||||||
|
function c:init()
|
||||||
|
require("multi")
|
||||||
|
if multi:getPlatform()=="love2d" then
|
||||||
|
GLOBAL=_G.GLOBAL
|
||||||
|
sThread=_G.sThread
|
||||||
|
end
|
||||||
|
local conn = {}
|
||||||
|
conn.name = self.name
|
||||||
|
conn.count = 0
|
||||||
|
if isMainThread then
|
||||||
|
if GLOBAL[self.name.."THREADED_CONNQ"] then -- if this thing exists then lets grab it, we are doing something different here. instead of cleaning things up, we will gave a dedicated queue to manage things
|
||||||
|
conn.queueCall = sThread.waitFor(self.name.."THREADED_CALLQ"):init()
|
||||||
|
else
|
||||||
|
conn.queueCall = multi:newSystemThreadedQueue(self.name.."THREADED_CALLQ"):init()
|
||||||
|
end
|
||||||
|
else
|
||||||
|
require("multi") -- so things don't break, but also allows bi-directional connections to work
|
||||||
|
conn.queueCall = sThread.waitFor(self.name.."THREADED_CALLQ"):init()
|
||||||
|
end
|
||||||
|
setmetatable(conn,{__call=function(self,...) return self:connect(...) end})
|
||||||
|
conn.obj=multi:newConnection(self.protect)
|
||||||
|
function conn:connect(func)
|
||||||
|
return self.obj(func)
|
||||||
|
end
|
||||||
|
function conn:fConnect(func)
|
||||||
|
return self.obj:fConnect(func)
|
||||||
|
end
|
||||||
|
function conn:holdUT(n)
|
||||||
|
self.obj:holdUT(n)
|
||||||
|
end
|
||||||
|
function conn:Bind(t)
|
||||||
|
self.obj:Bind(t)
|
||||||
|
end
|
||||||
|
function conn:Remove()
|
||||||
|
self.obj:Remove()
|
||||||
|
end
|
||||||
|
function conn:getConnection(name,ingore)
|
||||||
|
return self.obj:getConnection(name,ingore)
|
||||||
|
end
|
||||||
|
function conn:Fire(...)
|
||||||
|
local args = {...}
|
||||||
|
table.insert(args,1,multi.randomString(8))
|
||||||
|
table.insert(args,1,self.name)
|
||||||
|
table.insert(args,1,"F")
|
||||||
|
self.queueCall:push(args)
|
||||||
|
if self.trigger_self then
|
||||||
|
self.obj:Fire(...)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
self.cleanup = .01
|
||||||
|
function conn:SetCleanUpRate(n)
|
||||||
|
self.cleanup=n or .01
|
||||||
|
end
|
||||||
|
conn.lastid=""
|
||||||
|
conn.looper = multi:newLoop(function(self)
|
||||||
|
local con = self.link
|
||||||
|
local data = con.queueCall:peek()
|
||||||
|
if not data then return end
|
||||||
|
local id = data[3]
|
||||||
|
if data[1]=="F" and data[2]==con.name and con.lastid~=id then
|
||||||
|
con.lastid=id
|
||||||
|
table.remove(data,1)-- Remove the first 3 elements
|
||||||
|
table.remove(data,1)-- Remove the first 3 elements
|
||||||
|
table.remove(data,1)-- Remove the first 3 elements
|
||||||
|
con.obj:Fire(unpack(data))
|
||||||
|
multi:newThread("Clean_UP",function()
|
||||||
|
thread.sleep(con.cleanup)
|
||||||
|
local dat = con.queueCall:peek()
|
||||||
|
if not dat then return end
|
||||||
|
table.remove(data,1)-- Remove the first 3 elements
|
||||||
|
table.remove(data,1)-- Remove the first 3 elements
|
||||||
|
table.remove(data,1)-- Remove the first 3 elements
|
||||||
|
if dat[3]==id then
|
||||||
|
con.queueCall:pop()
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
conn.HoldUT=conn.holdUT
|
||||||
|
conn.looper.link=conn
|
||||||
|
conn.Connect=conn.connect
|
||||||
|
conn.FConnect=conn.fConnect
|
||||||
|
conn.GetConnection=conn.getConnection
|
||||||
|
return conn
|
||||||
|
end
|
||||||
|
GLOBAL[name]=c
|
||||||
|
return c
|
||||||
|
end
|
||||||
|
function multi:systemThreadedBenchmark(n,p)
|
||||||
|
n=n or 1
|
||||||
|
local cores=multi.integration.THREAD.getCores()
|
||||||
|
local queue=multi:newSystemThreadedQueue("QUEUE")
|
||||||
|
multi.integration.GLOBAL["__SYSTEMBENCHMARK__"]=n
|
||||||
|
local sThread=multi.integration.THREAD
|
||||||
|
local GLOBAL=multi.integration.GLOBAL
|
||||||
|
for i=1,cores do
|
||||||
|
multi:newSystemThread("STHREAD_BENCH",function()
|
||||||
|
require("multi")
|
||||||
|
if multi:getPlatform()=="love2d" then
|
||||||
|
GLOBAL=_G.GLOBAL
|
||||||
|
sThread=_G.sThread
|
||||||
|
end -- we cannot have upvalues... in love2d globals not locals must be used
|
||||||
|
queue=sThread.waitFor("QUEUE"):init() -- always wait for when looking for a variable at the start of the thread!
|
||||||
|
multi:benchMark(sThread.waitFor("__SYSTEMBENCHMARK__")):OnBench(function(self,count)
|
||||||
|
queue:push(count)
|
||||||
|
multi:Stop()
|
||||||
|
end)
|
||||||
|
multi:mainloop()
|
||||||
|
end)
|
||||||
|
end
|
||||||
|
local c={}
|
||||||
|
c.tt=function() end
|
||||||
|
c.p=p
|
||||||
|
function c:OnBench(func)
|
||||||
|
self.tt=func
|
||||||
|
end
|
||||||
|
multi:newThread("THREAD_BENCH",function()
|
||||||
|
thread.sleep(n+.1)
|
||||||
|
GLOBAL["QUEUE"]=nil -- time to clean up
|
||||||
|
local num=0
|
||||||
|
data=queue:pop()
|
||||||
|
while data do
|
||||||
|
num=num+data
|
||||||
|
data=queue:pop()
|
||||||
|
end
|
||||||
|
if p then
|
||||||
|
print(tostring(p)..num)
|
||||||
|
end
|
||||||
|
c.tt(c,num)
|
||||||
|
end)
|
||||||
|
return c
|
||||||
|
end
|
||||||
|
function multi:newSystemThreadedConsole(name)
|
||||||
|
local c={}
|
||||||
|
c.name = name
|
||||||
|
local sThread=multi.integration.THREAD
|
||||||
|
local GLOBAL=multi.integration.GLOBAL
|
||||||
|
function c:init()
|
||||||
|
require("multi")
|
||||||
|
if multi:getPlatform()=="love2d" then
|
||||||
|
GLOBAL=_G.GLOBAL
|
||||||
|
sThread=_G.sThread
|
||||||
|
end
|
||||||
|
local cc={}
|
||||||
|
if isMainThread then
|
||||||
|
if GLOBAL["__SYSTEM_CONSLOE__"] then
|
||||||
|
cc.stream = sThread.waitFor("__SYSTEM_CONSLOE__"):init()
|
||||||
|
else
|
||||||
|
cc.stream = multi:newSystemThreadedQueue("__SYSTEM_CONSLOE__"):init()
|
||||||
|
multi:newThread("Threaded_Console",function()
|
||||||
|
while true do
|
||||||
|
thread.sleep(.001)
|
||||||
|
local data = cc.stream:pop()
|
||||||
|
if data then
|
||||||
|
local dat = table.remove(data,1)
|
||||||
|
if dat=="w" then
|
||||||
|
io.write(unpack(data))
|
||||||
|
elseif dat=="p" then
|
||||||
|
print(unpack(data))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
end
|
||||||
|
else
|
||||||
|
cc.stream = sThread.waitFor("__SYSTEM_CONSLOE__"):init()
|
||||||
|
end
|
||||||
|
function cc:write(msg)
|
||||||
|
self.stream:push({"w",tostring(msg)})
|
||||||
|
end
|
||||||
|
function cc:print(...)
|
||||||
|
local tab = {...}
|
||||||
|
for i=1,#tab do
|
||||||
|
tab[i]=tostring(tab[i])
|
||||||
|
end
|
||||||
|
self.stream:push({"p",unpack(tab)})
|
||||||
|
end
|
||||||
|
return cc
|
||||||
|
end
|
||||||
|
GLOBAL[c.name]=c
|
||||||
|
return c
|
||||||
|
end
|
||||||
|
function multi:newSystemThreadedTable(name)
|
||||||
|
local c={}
|
||||||
|
c.name=name -- set the name this is important for identifying what is what
|
||||||
|
local sThread=multi.integration.THREAD
|
||||||
|
local GLOBAL=multi.integration.GLOBAL
|
||||||
|
function c:init() -- create an init function so we can mimic on both love2d and lanes
|
||||||
|
if multi:getPlatform()=="love2d" then
|
||||||
|
GLOBAL=_G.GLOBAL
|
||||||
|
sThread=_G.sThread
|
||||||
|
end
|
||||||
|
local cc={}
|
||||||
|
cc.tab={}
|
||||||
|
if isMainThread then
|
||||||
|
cc.conn = multi:newSystemThreadedConnection(self.name.."_Tabled_Connection"):init()
|
||||||
|
else
|
||||||
|
cc.conn = sThread.waitFor(self.name.."_Tabled_Connection"):init()
|
||||||
|
end
|
||||||
|
function cc:waitFor(name)
|
||||||
|
repeat multi:uManager() until tab[name]~=nil
|
||||||
|
return tab[name]
|
||||||
|
end
|
||||||
|
local link = cc
|
||||||
|
cc.conn(function(k,v)
|
||||||
|
link.tab[k]=v
|
||||||
|
end)
|
||||||
|
setmetatable(cc,{
|
||||||
|
__index=function(t,k)
|
||||||
|
return t.tab[k]
|
||||||
|
end,
|
||||||
|
__newindex=function(t,k,v)
|
||||||
|
t.tab[k]=v
|
||||||
|
t.conn:Fire(k,v)
|
||||||
|
end,
|
||||||
|
})
|
||||||
|
return cc
|
||||||
|
end
|
||||||
|
GLOBAL[c.name]=c
|
||||||
|
return c
|
||||||
|
end
|
||||||
|
function multi:newSystemThreadedJobQueue(numOfCores)
|
||||||
|
local c={}
|
||||||
|
c.jobnum=1
|
||||||
|
c.cores=numOfCores or multi.integration.THREAD.getCores()
|
||||||
|
c.queueIN=multi:newSystemThreadedQueue("THREADED_JQ"):init()
|
||||||
|
c.queueOUT=multi:newSystemThreadedQueue("THREADED_JQO"):init()
|
||||||
|
c.queueALL=multi:newSystemThreadedQueue("THREADED_QALL"):init()
|
||||||
|
c.REG=multi:newSystemThreadedQueue("THREADED_JQ_F_REG"):init()
|
||||||
|
c.OnReady=multi:newConnection()
|
||||||
|
function c:registerJob(name,func)
|
||||||
|
for i=1,self.cores do
|
||||||
|
self.REG:push({name,func})
|
||||||
|
end
|
||||||
|
end
|
||||||
|
function c:pushJob(name,...)
|
||||||
|
self.queueOUT:push({self.jobnum,name,...})
|
||||||
|
self.jobnum=self.jobnum+1
|
||||||
|
return self.jobnum-1
|
||||||
|
end
|
||||||
|
local GLOBAL=multi.integration.GLOBAL -- set up locals in case we are using lanes
|
||||||
|
local sThread=multi.integration.THREAD -- set up locals in case we are using lanes
|
||||||
|
function c:doToAll(func)
|
||||||
|
local TaskName=multi.randomString(16)
|
||||||
|
for i=1,self.cores do
|
||||||
|
self.queueALL:push({TaskName,func})
|
||||||
|
end
|
||||||
|
end
|
||||||
|
function c:start()
|
||||||
|
multi:newEvent(function()
|
||||||
|
return self.ThreadsLoaded==true
|
||||||
|
end):OnEvent(function(evnt)
|
||||||
|
GLOBAL["THREADED_JQ"]=nil -- remove it
|
||||||
|
GLOBAL["THREADED_JQO"]=nil -- remove it
|
||||||
|
GLOBAL["THREADED_JQ_F_REG"]=nil -- remove it
|
||||||
|
self:doToAll(function()
|
||||||
|
_G["__started__"]=true
|
||||||
|
SFunc()
|
||||||
|
end)
|
||||||
|
evnt:Destroy()
|
||||||
|
end)
|
||||||
|
end
|
||||||
|
GLOBAL["__JQ_COUNT__"]=c.cores
|
||||||
|
for i=1,c.cores do
|
||||||
|
multi:newSystemThread("System Threaded Job Queue Worker Thread #"..i,function(name,ind)
|
||||||
|
require("multi")
|
||||||
|
ThreadName=name
|
||||||
|
__sleep__=.001
|
||||||
|
if love then -- lets make sure we don't reference up-values if using love2d
|
||||||
|
GLOBAL=_G.GLOBAL
|
||||||
|
sThread=_G.sThread
|
||||||
|
__sleep__=.1
|
||||||
|
end
|
||||||
|
JQI=sThread.waitFor("THREADED_JQO"):init() -- Grab it
|
||||||
|
JQO=sThread.waitFor("THREADED_JQ"):init() -- Grab it
|
||||||
|
REG=sThread.waitFor("THREADED_JQ_F_REG"):init() -- Grab it
|
||||||
|
QALL=sThread.waitFor("THREADED_QALL"):init() -- Grab it
|
||||||
|
QALLT={}
|
||||||
|
FUNCS={}
|
||||||
|
SFunc=multi:newFunction(function(self)
|
||||||
|
MainLoop:Pause()
|
||||||
|
self:hold(.1)
|
||||||
|
MainLoop:Resume()
|
||||||
|
self:Pause()
|
||||||
|
end)
|
||||||
|
multi:newLoop(function()
|
||||||
|
local rd=REG:peek()
|
||||||
|
if rd then
|
||||||
|
if not FUNCS[rd[1]] then
|
||||||
|
FUNCS[rd[1]]=rd[2]
|
||||||
|
rd=nil -- lets clean up
|
||||||
|
REG:pop()
|
||||||
|
end
|
||||||
|
end
|
||||||
|
local d=QALL:peek()
|
||||||
|
if d then
|
||||||
|
if not QALLT[d[1]] then
|
||||||
|
QALLT[d[1]]=true
|
||||||
|
d[2]()
|
||||||
|
d=nil -- lets clean up
|
||||||
|
QALL:pop()
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
setmetatable(_G,{
|
||||||
|
__index=function(t,k)
|
||||||
|
return FUNCS[k]
|
||||||
|
end
|
||||||
|
})
|
||||||
|
lastjob=os.clock()
|
||||||
|
MainLoop=multi:newLoop(function(self)
|
||||||
|
if __started__ then
|
||||||
|
local job=JQI:pop()
|
||||||
|
if job then
|
||||||
|
lastjob=os.clock()
|
||||||
|
local d=QALL:peek()
|
||||||
|
if d then
|
||||||
|
if not QALLT[d[1]] then
|
||||||
|
QALLT[d[1]]=true
|
||||||
|
d[2]()
|
||||||
|
d=nil -- lets clean up
|
||||||
|
QALL:pop()
|
||||||
|
end
|
||||||
|
end
|
||||||
|
local ID=table.remove(job,1) -- return and remove
|
||||||
|
local name=table.remove(job,1) -- return and remove
|
||||||
|
if FUNCS[name] then
|
||||||
|
JQO:push({ID,FUNCS[name](unpack(job))})
|
||||||
|
else
|
||||||
|
self:hold(function() return FUNCS[name] end)
|
||||||
|
JQO:push({ID,FUNCS[name](unpack(job))})
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
multi:newThread("Idler",function()
|
||||||
|
while true do
|
||||||
|
if os.clock()-lastjob>1 then
|
||||||
|
sThread.sleep(.1)
|
||||||
|
end
|
||||||
|
thread.sleep(.001)
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
JQO:push({"_THREADINIT_"})
|
||||||
|
if not love then
|
||||||
|
multi:mainloop()
|
||||||
|
end
|
||||||
|
end,"Thread<"..i..">",i)
|
||||||
|
end
|
||||||
|
c.OnJobCompleted=multi:newConnection()
|
||||||
|
c.threadsResponded = 0
|
||||||
|
c.updater=multi:newLoop(function(self)
|
||||||
|
local data=self.link.queueIN:pop()
|
||||||
|
while data do
|
||||||
|
if data then
|
||||||
|
local a=unpack(data)
|
||||||
|
if a=="_THREADINIT_" then
|
||||||
|
self.link.threadsResponded=self.link.threadsResponded+1
|
||||||
|
if self.link.threadsResponded==self.link.cores then
|
||||||
|
self.link.ThreadsLoaded=true
|
||||||
|
self.link.OnReady:Fire()
|
||||||
|
end
|
||||||
|
else
|
||||||
|
self.link.OnJobCompleted:Fire(unpack(data))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
data=self.link.queueIN:pop()
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
c.updater.link=c
|
||||||
|
return c
|
||||||
|
end
|
||||||
|
function multi:newSystemThreadedExecute(cmd)
|
||||||
|
local c={}
|
||||||
|
local GLOBAL=multi.integration.GLOBAL -- set up locals incase we are using lanes
|
||||||
|
local sThread=multi.integration.THREAD -- set up locals incase we are using lanes
|
||||||
|
local name="Execute_Thread"..multi.randomString(16)
|
||||||
|
c.name=name
|
||||||
|
GLOBAL[name.."CMD"]=cmd
|
||||||
|
multi:newSystemThread(name,function()
|
||||||
|
if love then -- lets make sure we don't reference upvalues if using love2d
|
||||||
|
GLOBAL=_G.GLOBAL
|
||||||
|
sThread=_G.sThread
|
||||||
|
name=__THREADNAME__ -- global data same as the name we used in this functions creation
|
||||||
|
end -- Lanes should take the local upvalues ^^^
|
||||||
|
cmd=sThread.waitFor(name.."CMD")
|
||||||
|
local ret=os.execute(cmd)
|
||||||
|
GLOBAL[name.."R"]=ret
|
||||||
|
end)
|
||||||
|
c.OnCMDFinished=multi:newConnection()
|
||||||
|
c.looper=multi:newLoop(function(self)
|
||||||
|
local ret=GLOBAL[self.link.name.."R"]
|
||||||
|
if ret then
|
||||||
|
self.link.OnCMDFinished:Fire(ret)
|
||||||
|
self:Destroy()
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
c.looper.link=c
|
||||||
|
return c
|
||||||
|
end
|
||||||
@@ -1,130 +0,0 @@
|
|||||||
--[[
|
|
||||||
MIT License
|
|
||||||
|
|
||||||
Copyright (c) 2017 Ryan Ward
|
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
|
||||||
in the Software without restriction, including without limitation the rights
|
|
||||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
copies of the Software, and to permit persons to whom the Software is
|
|
||||||
furnished to do so, subject to the following conditions:
|
|
||||||
|
|
||||||
The above copyright notice and this permission notice shall be included in all
|
|
||||||
copies or substantial portions of the Software.
|
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
||||||
SOFTWARE.
|
|
||||||
]]
|
|
||||||
function os.getOS()
|
|
||||||
if package.config:sub(1,1)=='\\' then
|
|
||||||
return 'windows'
|
|
||||||
else
|
|
||||||
return 'unix'
|
|
||||||
end
|
|
||||||
end
|
|
||||||
-- Step 1 get lanes
|
|
||||||
lanes=require("lanes").configure()
|
|
||||||
package.path="lua/?/init.lua;lua/?.lua;"..package.path
|
|
||||||
require("multi.all") -- get it all and have it on all lanes
|
|
||||||
local multi=multi
|
|
||||||
-- Step 2 set up the linda objects
|
|
||||||
local __GlobalLinda = lanes.linda() -- handles global stuff
|
|
||||||
local __SleepingLinda = lanes.linda() -- handles sleeping stuff
|
|
||||||
-- For convience a GLOBAL table will be constructed to handle requests
|
|
||||||
local GLOBAL={}
|
|
||||||
setmetatable(GLOBAL,{
|
|
||||||
__index=function(t,k)
|
|
||||||
return __GlobalLinda:get(k)
|
|
||||||
end,
|
|
||||||
__newindex=function(t,k,v)
|
|
||||||
__GlobalLinda:set(k,v)
|
|
||||||
end,
|
|
||||||
})
|
|
||||||
-- Step 3 rewrite the thread methods to use lindas
|
|
||||||
local THREAD={}
|
|
||||||
function THREAD.set(name,val)
|
|
||||||
__GlobalLinda:set(name,val)
|
|
||||||
end
|
|
||||||
function THREAD.get(name)
|
|
||||||
__GlobalLinda:get(name)
|
|
||||||
end
|
|
||||||
local function randomString(n)
|
|
||||||
local str = ''
|
|
||||||
local strings = {'a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z','1','2','3','4','5','6','7','8','9','0','A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z'}
|
|
||||||
for i=1,n do
|
|
||||||
str = str..''..strings[math.random(1,#strings)]
|
|
||||||
end
|
|
||||||
return str
|
|
||||||
end
|
|
||||||
function THREAD.waitFor(name)
|
|
||||||
local function wait()
|
|
||||||
math.randomseed(os.time())
|
|
||||||
__SleepingLinda:receive(.001,randomString(12))
|
|
||||||
end
|
|
||||||
repeat wait() until __GlobalLinda:get(name)
|
|
||||||
return __GlobalLinda:get(name)
|
|
||||||
end
|
|
||||||
function THREAD.testFor(name,val,sym)
|
|
||||||
--
|
|
||||||
end
|
|
||||||
function THREAD.getCores()
|
|
||||||
return THREAD.__CORES
|
|
||||||
end
|
|
||||||
if os.getOS()=="windows" then
|
|
||||||
THREAD.__CORES=tonumber(os.getenv("NUMBER_OF_PROCESSORS"))
|
|
||||||
else
|
|
||||||
THREAD.__CORES=tonumber(io.popen("nproc --all"):read("*n"))
|
|
||||||
end
|
|
||||||
function THREAD.kill() -- trigger the lane destruction
|
|
||||||
-- coroutine.yield({"_kill_",":)"})
|
|
||||||
end
|
|
||||||
--[[ Step 4 We need to get sleeping working to handle timing... We want idle wait, not busy wait
|
|
||||||
Idle wait keeps the CPU running better where busy wait wastes CPU cycles... Lanes does not have a sleep method
|
|
||||||
however, a linda recieve will in fact be a idle wait! So we use that and wrap it in a nice package]]
|
|
||||||
function THREAD.sleep(n)
|
|
||||||
math.randomseed(os.time())
|
|
||||||
__SleepingLinda:receive(n,randomString(12))
|
|
||||||
end
|
|
||||||
function THREAD.hold(n)
|
|
||||||
local function wait()
|
|
||||||
math.randomseed(os.time())
|
|
||||||
__SleepingLinda:receive(.001,randomString(12))
|
|
||||||
end
|
|
||||||
repeat wait() until n()
|
|
||||||
end
|
|
||||||
-- Step 5 Basic Threads!
|
|
||||||
function multi:newSystemThread(name,func)
|
|
||||||
local c={}
|
|
||||||
local __self=c
|
|
||||||
c.name=name
|
|
||||||
c.thread=lanes.gen("*", func)()
|
|
||||||
function c:kill()
|
|
||||||
self.status:Destroy()
|
|
||||||
self.thread:cancel()
|
|
||||||
print("Thread: '"..self.name.."' has been stopped!")
|
|
||||||
end
|
|
||||||
c.status=multi:newUpdater(multi.Priority_IDLE)
|
|
||||||
c.status.link=c
|
|
||||||
c.status:OnUpdate(function(self)
|
|
||||||
local v,err,t=self.link.thread:join(.001)
|
|
||||||
if err then
|
|
||||||
print("Error in thread: '"..self.link.name.."' <"..err..">")
|
|
||||||
self:Destroy()
|
|
||||||
end
|
|
||||||
end)
|
|
||||||
return c
|
|
||||||
end
|
|
||||||
print("Intergrated Lanes!")
|
|
||||||
multi.intergration={} -- for module creators
|
|
||||||
multi.intergration.GLOBAL=GLOBAL
|
|
||||||
multi.intergration.THREAD=THREAD
|
|
||||||
multi.intergration.lanes={} -- for module creators
|
|
||||||
multi.intergration.lanes.GLOBAL=GLOBAL -- for module creators
|
|
||||||
multi.intergration.lanes.THREAD=THREAD -- for module creators
|
|
||||||
return {init=function() return GLOBAL,THREAD end}
|
|
||||||
@@ -1,343 +0,0 @@
|
|||||||
require("multi.compat.love2d")
|
|
||||||
multi.intergration={}
|
|
||||||
multi.intergration.love2d={}
|
|
||||||
multi.intergration.love2d.ThreadBase=[[
|
|
||||||
require("love.filesystem")
|
|
||||||
require("love.system")
|
|
||||||
require("love.timer")
|
|
||||||
require("multi.all")
|
|
||||||
GLOBAL={}
|
|
||||||
setmetatable(GLOBAL,{
|
|
||||||
__index=function(t,k)
|
|
||||||
return __proxy__[k]
|
|
||||||
end,
|
|
||||||
__newindex=function(t,k,v)
|
|
||||||
__proxy__[k]=v
|
|
||||||
if type(v)=="userdata" then
|
|
||||||
__MainChan__:push(v)
|
|
||||||
else
|
|
||||||
__MainChan__:push("SYNC "..type(v).." "..k.." "..resolveData(v))
|
|
||||||
end
|
|
||||||
end,
|
|
||||||
})
|
|
||||||
function ToStr(val, name, skipnewlines, depth)
|
|
||||||
skipnewlines = skipnewlines or false
|
|
||||||
depth = depth or 0
|
|
||||||
local tmp = string.rep(" ", depth)
|
|
||||||
if name then
|
|
||||||
if type(name) == "string" then
|
|
||||||
tmp = tmp .. "[\""..name.."\"] = "
|
|
||||||
else
|
|
||||||
tmp = tmp .. "["..(name or "").."] = "
|
|
||||||
end
|
|
||||||
end
|
|
||||||
if type(val) == "table" then
|
|
||||||
tmp = tmp .. "{" .. (not skipnewlines and " " or "")
|
|
||||||
for k, v in pairs(val) do
|
|
||||||
tmp = tmp .. ToStr(v, k, skipnewlines, depth + 1) .. "," .. (not skipnewlines and " " or "")
|
|
||||||
end
|
|
||||||
tmp = tmp .. string.rep(" ", depth) .. "}"
|
|
||||||
elseif type(val) == "number" then
|
|
||||||
tmp = tmp .. tostring(val)
|
|
||||||
elseif type(val) == "string" then
|
|
||||||
tmp = tmp .. string.format("%q", val)
|
|
||||||
elseif type(val) == "boolean" then
|
|
||||||
tmp = tmp .. (val and "true" or "false")
|
|
||||||
else
|
|
||||||
tmp = tmp .. "\"[inserializeable datatype:" .. type(val) .. "]\""
|
|
||||||
end
|
|
||||||
return tmp
|
|
||||||
end
|
|
||||||
function resolveType(tp,d)
|
|
||||||
if tp=="number" then
|
|
||||||
return tonumber(d)
|
|
||||||
elseif tp=="bool" then
|
|
||||||
return (d=="true")
|
|
||||||
elseif tp=="function" then
|
|
||||||
return loadDump(d)
|
|
||||||
elseif tp=="table" then
|
|
||||||
return loadstring("return "..d)()
|
|
||||||
else
|
|
||||||
return d
|
|
||||||
end
|
|
||||||
end
|
|
||||||
function resolveData(v)
|
|
||||||
local data=""
|
|
||||||
if type(v)=="table" then
|
|
||||||
data=ToStr(v)
|
|
||||||
elseif type(v)=="function" then
|
|
||||||
data=dump(v)
|
|
||||||
elseif type(v)=="string" or type(v)=="number" or type(v)=="bool" then
|
|
||||||
data=tostring(v)
|
|
||||||
end
|
|
||||||
return data
|
|
||||||
end
|
|
||||||
sThread={}
|
|
||||||
local function randomString(n)
|
|
||||||
local c=os.clock()
|
|
||||||
local a=0
|
|
||||||
while os.clock()<c+.1 do
|
|
||||||
a=a+1
|
|
||||||
end
|
|
||||||
math.randomseed(a)
|
|
||||||
local str = ''
|
|
||||||
local strings = {'a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z','1','2','3','4','5','6','7','8','9','0','A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z'}
|
|
||||||
for i=1,n do
|
|
||||||
str = str..''..strings[math.random(1,#strings)]
|
|
||||||
end
|
|
||||||
return str
|
|
||||||
end
|
|
||||||
__proxy__={} -- this is where the actual globals will live
|
|
||||||
__MainChan__=love.thread.getChannel("__MainChan__")
|
|
||||||
__mythreadname__=randomString(16)
|
|
||||||
__mythread__=love.thread.getChannel(__mythreadname__)
|
|
||||||
__MainChan__:push("NEWTHREAD "..__mythreadname__.." | |")
|
|
||||||
function loadDump(d)
|
|
||||||
local s={}
|
|
||||||
for p in d:gmatch("(%d-)\\") do
|
|
||||||
s[#s+1]=string.char(tonumber(p))
|
|
||||||
end
|
|
||||||
return loadstring(table.concat(s))
|
|
||||||
end
|
|
||||||
function dump(func)
|
|
||||||
local code,t={},string.dump(func)
|
|
||||||
for i=1,#t do
|
|
||||||
code[#code+1]=string.byte(t:sub(i,i)).."\\"
|
|
||||||
end
|
|
||||||
return table.concat(code)
|
|
||||||
end
|
|
||||||
function sThread.set(name,val)
|
|
||||||
GLOBAL[name]=val
|
|
||||||
end
|
|
||||||
function sThread.get(name)
|
|
||||||
return GLOBAL[name]
|
|
||||||
end
|
|
||||||
function sThread.waitFor(name)
|
|
||||||
--print("Waiting:",__mythreadname__)
|
|
||||||
local function wait()
|
|
||||||
local data=__mythread__:pop()
|
|
||||||
while data do
|
|
||||||
if type(data)=="string" then
|
|
||||||
local cmd,tp,name,d=data:match("(%S-) (%S-) (%S-) (.+)")
|
|
||||||
if cmd=="SYNC" then
|
|
||||||
__proxy__[name]=resolveType(tp,d)
|
|
||||||
end
|
|
||||||
else
|
|
||||||
__proxy__[name]=data
|
|
||||||
end
|
|
||||||
data=__mythread__:pop()
|
|
||||||
end
|
|
||||||
end
|
|
||||||
repeat wait() until GLOBAL[name]
|
|
||||||
return GLOBAL[name]
|
|
||||||
end
|
|
||||||
function sThread.getCores()
|
|
||||||
return love.system.getProcessorCount()
|
|
||||||
end
|
|
||||||
function sThread.sleep(n)
|
|
||||||
love.timer.sleep(n)
|
|
||||||
end
|
|
||||||
function sThread.hold(n)
|
|
||||||
local function wait()
|
|
||||||
local data=__mythread__:pop()
|
|
||||||
while data do
|
|
||||||
if type(data)=="string" then
|
|
||||||
local cmd,tp,name,d=data:match("(%S-) (%S-) (%S-) (.+)")
|
|
||||||
if cmd=="SYNC" then
|
|
||||||
__proxy__[name]=resolveType(tp,d)
|
|
||||||
end
|
|
||||||
else
|
|
||||||
__proxy__[name]=data
|
|
||||||
end
|
|
||||||
data=__mythread__:pop()
|
|
||||||
end
|
|
||||||
end
|
|
||||||
repeat wait() until n()
|
|
||||||
end
|
|
||||||
updater=multi:newUpdater()
|
|
||||||
updater:OnUpdate(function(self)
|
|
||||||
local data=__mythread__:pop()
|
|
||||||
while data do
|
|
||||||
if type(data)=="string" then
|
|
||||||
local cmd,tp,name,d=data:match("(%S-) (%S-) (%S-) (.+)")
|
|
||||||
if cmd=="SYNC" then
|
|
||||||
__proxy__[name]=resolveType(tp,d)
|
|
||||||
end
|
|
||||||
else
|
|
||||||
__proxy__[name]=data
|
|
||||||
end
|
|
||||||
data=__mythread__:pop()
|
|
||||||
end
|
|
||||||
end)
|
|
||||||
func=loadDump([=[INSERT_USER_CODE]=])()
|
|
||||||
multi:mainloop()
|
|
||||||
]]
|
|
||||||
GLOBAL={} -- Allow main thread to interact with these objects as well
|
|
||||||
__proxy__={}
|
|
||||||
setmetatable(GLOBAL,{
|
|
||||||
__index=function(t,k)
|
|
||||||
return __proxy__[k]
|
|
||||||
end,
|
|
||||||
__newindex=function(t,k,v)
|
|
||||||
__proxy__[k]=v
|
|
||||||
for i=1,#__channels__ do
|
|
||||||
if type(v)=="userdata" then
|
|
||||||
__channels__[i]:push(v)
|
|
||||||
else
|
|
||||||
__channels__[i]:push("SYNC "..type(v).." "..k.." "..resolveData(v))
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end,
|
|
||||||
})
|
|
||||||
THREAD={} -- Allow main thread to interact with these objects as well
|
|
||||||
multi.intergration.love2d.mainChannel=love.thread.getChannel("__MainChan__")
|
|
||||||
function ToStr(val, name, skipnewlines, depth)
|
|
||||||
skipnewlines = skipnewlines or false
|
|
||||||
depth = depth or 0
|
|
||||||
local tmp = string.rep(" ", depth)
|
|
||||||
if name then
|
|
||||||
if type(name) == "string" then
|
|
||||||
tmp = tmp .. "[\""..name.."\"] = "
|
|
||||||
else
|
|
||||||
tmp = tmp .. "["..(name or "").."] = "
|
|
||||||
end
|
|
||||||
end
|
|
||||||
if type(val) == "table" then
|
|
||||||
tmp = tmp .. "{" .. (not skipnewlines and " " or "")
|
|
||||||
for k, v in pairs(val) do
|
|
||||||
tmp = tmp .. ToStr(v, k, skipnewlines, depth + 1) .. "," .. (not skipnewlines and " " or "")
|
|
||||||
end
|
|
||||||
tmp = tmp .. string.rep(" ", depth) .. "}"
|
|
||||||
elseif type(val) == "number" then
|
|
||||||
tmp = tmp .. tostring(val)
|
|
||||||
elseif type(val) == "string" then
|
|
||||||
tmp = tmp .. string.format("%q", val)
|
|
||||||
elseif type(val) == "boolean" then
|
|
||||||
tmp = tmp .. (val and "true" or "false")
|
|
||||||
else
|
|
||||||
tmp = tmp .. "\"[inserializeable datatype:" .. type(val) .. "]\""
|
|
||||||
end
|
|
||||||
return tmp
|
|
||||||
end
|
|
||||||
function resolveType(tp,d)
|
|
||||||
if tp=="number" then
|
|
||||||
return tonumber(d)
|
|
||||||
elseif tp=="bool" then
|
|
||||||
return (d=="true")
|
|
||||||
elseif tp=="function" then
|
|
||||||
return loadDump(d)
|
|
||||||
elseif tp=="table" then
|
|
||||||
return loadstring("return "..d)()
|
|
||||||
else
|
|
||||||
return d
|
|
||||||
end
|
|
||||||
end
|
|
||||||
function resolveData(v)
|
|
||||||
local data=""
|
|
||||||
if type(v)=="table" then
|
|
||||||
data=ToStr(v)
|
|
||||||
elseif type(v)=="function" then
|
|
||||||
data=dump(v)
|
|
||||||
elseif type(v)=="string" or type(v)=="number" or type(v)=="bool" then
|
|
||||||
data=tostring(v)
|
|
||||||
end
|
|
||||||
return data
|
|
||||||
end
|
|
||||||
function loadDump(d)
|
|
||||||
local s={}
|
|
||||||
for p in d:gmatch("(%d-)\\") do
|
|
||||||
s[#s+1]=string.char(tonumber(p))
|
|
||||||
end
|
|
||||||
return loadstring(table.concat(s))
|
|
||||||
end
|
|
||||||
function dump(func)
|
|
||||||
local code,t={},string.dump(func)
|
|
||||||
for i=1,#t do
|
|
||||||
code[#code+1]=string.byte(t:sub(i,i)).."\\"
|
|
||||||
end
|
|
||||||
return table.concat(code)
|
|
||||||
end
|
|
||||||
function multi:newSystemThread(name,func) -- the main method
|
|
||||||
local c={}
|
|
||||||
c.name=name
|
|
||||||
c.thread=love.thread.newThread(multi.intergration.love2d.ThreadBase:gsub("INSERT_USER_CODE",dump(func)))
|
|
||||||
c.thread:start()
|
|
||||||
return c
|
|
||||||
end
|
|
||||||
function love.threaderror( thread, errorstr )
|
|
||||||
print("Error in "..tostring(thread)..": "..errorstr)
|
|
||||||
end
|
|
||||||
local THREAD={}
|
|
||||||
function THREAD.set(name,val)
|
|
||||||
GLOBAL[name]=val
|
|
||||||
end
|
|
||||||
function THREAD.get(name)
|
|
||||||
return GLOBAL[name]
|
|
||||||
end
|
|
||||||
function THREAD.waitFor(name)
|
|
||||||
multi.OBJ_REF:Pause()
|
|
||||||
repeat multi:lManager() until GLOBAL[name]
|
|
||||||
multi.OBJ_REF:Resume()
|
|
||||||
return GLOBAL[name]
|
|
||||||
end
|
|
||||||
function THREAD.getCores()
|
|
||||||
return love.system.getProcessorCount()
|
|
||||||
end
|
|
||||||
function THREAD.sleep(n)
|
|
||||||
love.timer.sleep(n)
|
|
||||||
end
|
|
||||||
function THREAD.hold(n)
|
|
||||||
multi.OBJ_REF:Pause()
|
|
||||||
repeat multi:lManager() until n()
|
|
||||||
multi.OBJ_REF:Resume()
|
|
||||||
end
|
|
||||||
__channels__={}
|
|
||||||
multi.intergration.GLOBAL=GLOBAL
|
|
||||||
multi.intergration.THREAD=THREAD
|
|
||||||
updater=multi:newUpdater()
|
|
||||||
updater:OnUpdate(function(self)
|
|
||||||
local data=multi.intergration.love2d.mainChannel:pop()
|
|
||||||
while data do
|
|
||||||
--print("MAIN:",data)
|
|
||||||
if type(data)=="string" then
|
|
||||||
local cmd,tp,name,d=data:match("(%S-) (%S-) (%S-) (.+)")
|
|
||||||
if cmd=="SYNC" then
|
|
||||||
__proxy__[name]=resolveType(tp,d)
|
|
||||||
for i=1,#__channels__ do
|
|
||||||
-- send data to other threads
|
|
||||||
if type(v)=="userdata" then
|
|
||||||
__channels__[i]:push(v)
|
|
||||||
else
|
|
||||||
__channels__[i]:push("SYNC "..tp.." "..name.." "..d)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
elseif cmd=="NEWTHREAD" then
|
|
||||||
__channels__[#__channels__+1]=love.thread.getChannel(tp)
|
|
||||||
for k,v in pairs(__proxy__) do -- sync the global with each new thread
|
|
||||||
if type(v)=="userdata" then
|
|
||||||
__channels__[#__channels__]:push(v)
|
|
||||||
else
|
|
||||||
__channels__[#__channels__]:push("SYNC "..type(v).." "..k.." "..resolveData(v))
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
else
|
|
||||||
__proxy__[name]=data
|
|
||||||
end
|
|
||||||
data=multi.intergration.love2d.mainChannel:pop()
|
|
||||||
end
|
|
||||||
end)
|
|
||||||
print("Intergrated Love2d!")
|
|
||||||
return {
|
|
||||||
init=function(t)
|
|
||||||
if t then
|
|
||||||
if t.threadNamespace then
|
|
||||||
multi.intergration.love2d.ThreadBase:gsub("sThread",t.threadNamespace)
|
|
||||||
end
|
|
||||||
if t.globalNamespace then
|
|
||||||
multi.intergration.love2d.ThreadBase:gsub("GLOBAL",t.globalNamespace)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
return GLOBAL,THREAD
|
|
||||||
end
|
|
||||||
}
|
|
||||||
@@ -1,181 +0,0 @@
|
|||||||
--[[
|
|
||||||
MIT License
|
|
||||||
|
|
||||||
Copyright (c) 2017 Ryan Ward
|
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
|
||||||
in the Software without restriction, including without limitation the rights
|
|
||||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
copies of the Software, and to permit persons to whom the Software is
|
|
||||||
furnished to do so, subject to the following conditions:
|
|
||||||
|
|
||||||
The above copyright notice and this permission notice shall be included in all
|
|
||||||
copies or substantial portions of the Software.
|
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
||||||
SOFTWARE.
|
|
||||||
]]
|
|
||||||
require("multi")
|
|
||||||
thread={}
|
|
||||||
multi.GlobalVariables={}
|
|
||||||
if os.getOS()=="windows" then
|
|
||||||
thread.__CORES=tonumber(os.getenv("NUMBER_OF_PROCESSORS"))
|
|
||||||
else
|
|
||||||
thread.__CORES=tonumber(io.popen("nproc --all"):read("*n"))
|
|
||||||
end
|
|
||||||
function thread.sleep(n)
|
|
||||||
coroutine.yield({"_sleep_",n})
|
|
||||||
end
|
|
||||||
function thread.hold(n)
|
|
||||||
coroutine.yield({"_hold_",n})
|
|
||||||
end
|
|
||||||
function thread.skip(n)
|
|
||||||
coroutine.yield({"_skip_",n})
|
|
||||||
end
|
|
||||||
function thread.kill()
|
|
||||||
coroutine.yield({"_kill_",":)"})
|
|
||||||
end
|
|
||||||
function thread.yeild()
|
|
||||||
coroutine.yield({"_sleep_",0})
|
|
||||||
end
|
|
||||||
function thread.getCores()
|
|
||||||
return thread.__CORES
|
|
||||||
end
|
|
||||||
function thread.set(name,val)
|
|
||||||
multi.GlobalVariables[name]=val
|
|
||||||
return true
|
|
||||||
end
|
|
||||||
function thread.get(name)
|
|
||||||
return multi.GlobalVariables[name]
|
|
||||||
end
|
|
||||||
function thread.waitFor(name)
|
|
||||||
thread.hold(function() return thread.get(name)~=nil end)
|
|
||||||
return thread.get(name)
|
|
||||||
end
|
|
||||||
function thread.testFor(name,val,sym)
|
|
||||||
thread.hold(function() return thread.get(name)~=nil end)
|
|
||||||
return thread.get(name)
|
|
||||||
end
|
|
||||||
function multi:newTBase(ins)
|
|
||||||
local c = {}
|
|
||||||
c.Active=true
|
|
||||||
c.func={}
|
|
||||||
c.ender={}
|
|
||||||
c.Id=0
|
|
||||||
c.PId=0
|
|
||||||
c.Parent=self
|
|
||||||
c.held=false
|
|
||||||
return c
|
|
||||||
end
|
|
||||||
function multi:newThread(name,func)
|
|
||||||
local c={}
|
|
||||||
c.ref={}
|
|
||||||
c.Name=name
|
|
||||||
c.thread=coroutine.create(func)
|
|
||||||
c.sleep=1
|
|
||||||
c.firstRunDone=false
|
|
||||||
c.timer=multi.scheduler:newTimer()
|
|
||||||
c.ref.Globals=self:linkDomain("Globals")
|
|
||||||
function c.ref:send(name,val)
|
|
||||||
ret=coroutine.yield({Name=name,Value=val})
|
|
||||||
self:syncGlobals(ret)
|
|
||||||
end
|
|
||||||
function c.ref:get(name)
|
|
||||||
return self.Globals[name]
|
|
||||||
end
|
|
||||||
function c.ref:kill()
|
|
||||||
err=coroutine.yield({"_kill_"})
|
|
||||||
if err then
|
|
||||||
error("Failed to kill a thread! Exiting...")
|
|
||||||
end
|
|
||||||
end
|
|
||||||
function c.ref:sleep(n)
|
|
||||||
if type(n)=="function" then
|
|
||||||
ret=coroutine.yield({"_hold_",n})
|
|
||||||
self:syncGlobals(ret)
|
|
||||||
elseif type(n)=="number" then
|
|
||||||
n = tonumber(n) or 0
|
|
||||||
ret=coroutine.yield({"_sleep_",n})
|
|
||||||
self:syncGlobals(ret)
|
|
||||||
else
|
|
||||||
error("Invalid Type for sleep!")
|
|
||||||
end
|
|
||||||
end
|
|
||||||
function c.ref:syncGlobals(v)
|
|
||||||
self.Globals=v
|
|
||||||
end
|
|
||||||
table.insert(self:linkDomain("Threads"),c)
|
|
||||||
if not multi.scheduler:isActive() then
|
|
||||||
multi.scheduler:Resume()
|
|
||||||
end
|
|
||||||
end
|
|
||||||
multi:setDomainName("Threads")
|
|
||||||
multi:setDomainName("Globals")
|
|
||||||
multi.scheduler=multi:newUpdater()
|
|
||||||
multi.scheduler.Type="scheduler"
|
|
||||||
function multi.scheduler:setStep(n)
|
|
||||||
self.skip=tonumber(n) or 24
|
|
||||||
end
|
|
||||||
multi.scheduler.skip=0
|
|
||||||
multi.scheduler.counter=0
|
|
||||||
multi.scheduler.Threads=multi:linkDomain("Threads")
|
|
||||||
multi.scheduler.Globals=multi:linkDomain("Globals")
|
|
||||||
multi.scheduler:OnUpdate(function(self)
|
|
||||||
self.counter=self.counter+1
|
|
||||||
for i=#self.Threads,1,-1 do
|
|
||||||
ret={}
|
|
||||||
if coroutine.status(self.Threads[i].thread)=="dead" then
|
|
||||||
table.remove(self.Threads,i)
|
|
||||||
else
|
|
||||||
if self.Threads[i].timer:Get()>=self.Threads[i].sleep then
|
|
||||||
if self.Threads[i].firstRunDone==false then
|
|
||||||
self.Threads[i].firstRunDone=true
|
|
||||||
self.Threads[i].timer:Start()
|
|
||||||
_,ret=coroutine.resume(self.Threads[i].thread,self.Threads[i].ref)
|
|
||||||
else
|
|
||||||
_,ret=coroutine.resume(self.Threads[i].thread,self.Globals)
|
|
||||||
end
|
|
||||||
if ret==true or ret==false then
|
|
||||||
print("Thread Ended!!!")
|
|
||||||
ret={}
|
|
||||||
end
|
|
||||||
end
|
|
||||||
if ret then
|
|
||||||
if ret[1]=="_kill_" then
|
|
||||||
table.remove(self.Threads,i)
|
|
||||||
elseif ret[1]=="_sleep_" then
|
|
||||||
self.Threads[i].timer:Reset()
|
|
||||||
self.Threads[i].sleep=ret[2]
|
|
||||||
elseif ret[1]=="_skip_" then
|
|
||||||
self.Threads[i].timer:Reset()
|
|
||||||
self.Threads[i].sleep=math.huge
|
|
||||||
local event=multi:newEvent(function(evnt) return multi.scheduler.counter>=evnt.counter end)
|
|
||||||
event.link=self.Threads[i]
|
|
||||||
event.counter=self.counter+ret[2]
|
|
||||||
event:OnEvent(function(evnt)
|
|
||||||
evnt.link.sleep=0
|
|
||||||
end)
|
|
||||||
elseif ret[1]=="_hold_" then
|
|
||||||
self.Threads[i].timer:Reset()
|
|
||||||
self.Threads[i].sleep=math.huge
|
|
||||||
local event=multi:newEvent(ret[2])
|
|
||||||
event.link=self.Threads[i]
|
|
||||||
event:OnEvent(function(evnt)
|
|
||||||
evnt.link.sleep=0
|
|
||||||
end)
|
|
||||||
elseif ret.Name then
|
|
||||||
self.Globals[ret.Name]=ret.Value
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end)
|
|
||||||
multi.scheduler:setStep()
|
|
||||||
multi.scheduler:Pause()
|
|
||||||
multi.OnError=multi:newConnection()
|
|
||||||
@@ -1,73 +0,0 @@
|
|||||||
--[[
|
|
||||||
MIT License
|
|
||||||
|
|
||||||
Copyright (c) 2017 Ryan Ward
|
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
|
||||||
in the Software without restriction, including without limitation the rights
|
|
||||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
copies of the Software, and to permit persons to whom the Software is
|
|
||||||
furnished to do so, subject to the following conditions:
|
|
||||||
|
|
||||||
The above copyright notice and this permission notice shall be included in all
|
|
||||||
copies or substantial portions of the Software.
|
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
||||||
SOFTWARE.
|
|
||||||
]]
|
|
||||||
require("multi.threading")
|
|
||||||
function multi:newThreadedAlarm(name,set)
|
|
||||||
local c=self:newTBase()
|
|
||||||
c.Type='alarmThread'
|
|
||||||
c.timer=self:newTimer()
|
|
||||||
c.set=set or 0
|
|
||||||
function c:tofile(path)
|
|
||||||
local m=bin.new()
|
|
||||||
m:addBlock(self.Type)
|
|
||||||
m:addBlock(self.set)
|
|
||||||
m:addBlock(self.Active)
|
|
||||||
m:tofile(path)
|
|
||||||
end
|
|
||||||
function c:Resume()
|
|
||||||
self.rest=false
|
|
||||||
self.timer:Resume()
|
|
||||||
end
|
|
||||||
function c:Reset(n)
|
|
||||||
if n then self.set=n end
|
|
||||||
self.rest=false
|
|
||||||
self.timer:Reset(n)
|
|
||||||
end
|
|
||||||
function c:OnRing(func)
|
|
||||||
table.insert(self.func,func)
|
|
||||||
end
|
|
||||||
function c:Pause()
|
|
||||||
self.timer:Pause()
|
|
||||||
self.rest=true
|
|
||||||
end
|
|
||||||
c.rest=false
|
|
||||||
c.updaterate=multi.Priority_Low -- skips
|
|
||||||
c.restRate=0 -- secs
|
|
||||||
multi:newThread(name,function(ref)
|
|
||||||
while true do
|
|
||||||
if c.rest then
|
|
||||||
thread.sleep(c.restRate) -- rest a bit more when a thread is paused
|
|
||||||
else
|
|
||||||
if c.timer:Get()>=c.set then
|
|
||||||
c:Pause()
|
|
||||||
for i=1,#c.func do
|
|
||||||
c.func[i](c)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
thread.skip(c.updaterate) -- lets rest a bit
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end)
|
|
||||||
self:create(c)
|
|
||||||
return c
|
|
||||||
end
|
|
||||||
@@ -1,7 +0,0 @@
|
|||||||
require("multi.threading.step")
|
|
||||||
require("multi.threading.tstep")
|
|
||||||
require("multi.threading.updater")
|
|
||||||
require("multi.threading.alarm")
|
|
||||||
require("multi.threading.loop")
|
|
||||||
require("multi.threading.event")
|
|
||||||
require("multi.threading.process")
|
|
||||||
@@ -1,66 +0,0 @@
|
|||||||
--[[
|
|
||||||
MIT License
|
|
||||||
|
|
||||||
Copyright (c) 2017 Ryan Ward
|
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
|
||||||
in the Software without restriction, including without limitation the rights
|
|
||||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
copies of the Software, and to permit persons to whom the Software is
|
|
||||||
furnished to do so, subject to the following conditions:
|
|
||||||
|
|
||||||
The above copyright notice and this permission notice shall be included in all
|
|
||||||
copies or substantial portions of the Software.
|
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
||||||
SOFTWARE.
|
|
||||||
]]
|
|
||||||
require("multi.threading")
|
|
||||||
function multi:newThreadedEvent(name,task)
|
|
||||||
local c=self:newTBase()
|
|
||||||
c.Type='eventThread'
|
|
||||||
c.Task=task or function() end
|
|
||||||
function c:OnEvent(func)
|
|
||||||
table.insert(self.func,func)
|
|
||||||
end
|
|
||||||
function c:tofile(path)
|
|
||||||
local m=bin.new()
|
|
||||||
m:addBlock(self.Type)
|
|
||||||
m:addBlock(self.Task)
|
|
||||||
m:addBlock(self.func)
|
|
||||||
m:addBlock(self.Active)
|
|
||||||
m:tofile(path)
|
|
||||||
end
|
|
||||||
function c:Resume()
|
|
||||||
self.rest=false
|
|
||||||
end
|
|
||||||
function c:Pause()
|
|
||||||
self.rest=true
|
|
||||||
end
|
|
||||||
c.rest=false
|
|
||||||
c.updaterate=0
|
|
||||||
c.restRate=1
|
|
||||||
multi:newThread(name,function(ref)
|
|
||||||
while true do
|
|
||||||
if c.rest then
|
|
||||||
ref:sleep(c.restRate) -- rest a bit more when a thread is paused
|
|
||||||
else
|
|
||||||
if c.Task(self) then
|
|
||||||
for _E=1,#c.func do
|
|
||||||
c.func[_E](c)
|
|
||||||
end
|
|
||||||
c:Pause()
|
|
||||||
end
|
|
||||||
ref:sleep(c.updaterate) -- lets rest a bit
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end)
|
|
||||||
self:create(c)
|
|
||||||
return c
|
|
||||||
end
|
|
||||||
@@ -1,65 +0,0 @@
|
|||||||
--[[
|
|
||||||
MIT License
|
|
||||||
|
|
||||||
Copyright (c) 2017 Ryan Ward
|
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
|
||||||
in the Software without restriction, including without limitation the rights
|
|
||||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
copies of the Software, and to permit persons to whom the Software is
|
|
||||||
furnished to do so, subject to the following conditions:
|
|
||||||
|
|
||||||
The above copyright notice and this permission notice shall be included in all
|
|
||||||
copies or substantial portions of the Software.
|
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
||||||
SOFTWARE.
|
|
||||||
]]
|
|
||||||
require("multi.threading")
|
|
||||||
function multi:newThreadedLoop(name,func)
|
|
||||||
local c=self:newTBase()
|
|
||||||
c.Type='loopThread'
|
|
||||||
c.Start=os.clock()
|
|
||||||
if func then
|
|
||||||
c.func={func}
|
|
||||||
end
|
|
||||||
function c:tofile(path)
|
|
||||||
local m=bin.new()
|
|
||||||
m:addBlock(self.Type)
|
|
||||||
m:addBlock(self.func)
|
|
||||||
m:addBlock(self.Active)
|
|
||||||
m:tofile(path)
|
|
||||||
end
|
|
||||||
function c:Resume()
|
|
||||||
self.rest=false
|
|
||||||
end
|
|
||||||
function c:Pause()
|
|
||||||
self.rest=true
|
|
||||||
end
|
|
||||||
function c:OnLoop(func)
|
|
||||||
table.insert(self.func,func)
|
|
||||||
end
|
|
||||||
c.rest=false
|
|
||||||
c.updaterate=0
|
|
||||||
c.restRate=.75
|
|
||||||
multi:newThread(name,function(ref)
|
|
||||||
while true do
|
|
||||||
if c.rest then
|
|
||||||
thread.sleep(c.restRate) -- rest a bit more when a thread is paused
|
|
||||||
else
|
|
||||||
for i=1,#c.func do
|
|
||||||
c.func[i](os.clock()-self.Start,c)
|
|
||||||
end
|
|
||||||
thread.sleep(c.updaterate) -- lets rest a bit
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end)
|
|
||||||
self:create(c)
|
|
||||||
return c
|
|
||||||
end
|
|
||||||
@@ -1,106 +0,0 @@
|
|||||||
--[[
|
|
||||||
MIT License
|
|
||||||
|
|
||||||
Copyright (c) 2017 Ryan Ward
|
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
|
||||||
in the Software without restriction, including without limitation the rights
|
|
||||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
copies of the Software, and to permit persons to whom the Software is
|
|
||||||
furnished to do so, subject to the following conditions:
|
|
||||||
|
|
||||||
The above copyright notice and this permission notice shall be included in all
|
|
||||||
copies or substantial portions of the Software.
|
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
||||||
SOFTWARE.
|
|
||||||
]]
|
|
||||||
require("multi.threading")
|
|
||||||
function multi:newThreadedProcess(name)
|
|
||||||
local c = {}
|
|
||||||
setmetatable(c, multi)
|
|
||||||
function c:newBase(ins)
|
|
||||||
local ct = {}
|
|
||||||
setmetatable(ct, self.Parent)
|
|
||||||
ct.Active=true
|
|
||||||
ct.func={}
|
|
||||||
ct.ender={}
|
|
||||||
ct.Id=0
|
|
||||||
ct.PId=0
|
|
||||||
ct.Act=function() end
|
|
||||||
ct.Parent=self
|
|
||||||
ct.held=false
|
|
||||||
ct.ref=self.ref
|
|
||||||
table.insert(self.Mainloop,ct)
|
|
||||||
return ct
|
|
||||||
end
|
|
||||||
c.Parent=self
|
|
||||||
c.Active=true
|
|
||||||
c.func={}
|
|
||||||
c.Id=0
|
|
||||||
c.Type='process'
|
|
||||||
c.Mainloop={}
|
|
||||||
c.Tasks={}
|
|
||||||
c.Tasks2={}
|
|
||||||
c.Garbage={}
|
|
||||||
c.Children={}
|
|
||||||
c.Paused={}
|
|
||||||
c.Active=true
|
|
||||||
c.Id=-1
|
|
||||||
c.Rest=0
|
|
||||||
c.updaterate=.01
|
|
||||||
c.restRate=.1
|
|
||||||
c.Jobs={}
|
|
||||||
c.queue={}
|
|
||||||
c.jobUS=2
|
|
||||||
c.rest=false
|
|
||||||
function c:getController()
|
|
||||||
return nil
|
|
||||||
end
|
|
||||||
function c:Start()
|
|
||||||
self.rest=false
|
|
||||||
end
|
|
||||||
function c:Resume()
|
|
||||||
self.rest=false
|
|
||||||
end
|
|
||||||
function c:Pause()
|
|
||||||
self.rest=true
|
|
||||||
end
|
|
||||||
function c:Remove()
|
|
||||||
self.ref:kill()
|
|
||||||
end
|
|
||||||
function c:kill()
|
|
||||||
err=coroutine.yield({"_kill_"})
|
|
||||||
if err then
|
|
||||||
error("Failed to kill a thread! Exiting...")
|
|
||||||
end
|
|
||||||
end
|
|
||||||
function c:sleep(n)
|
|
||||||
if type(n)=="function" then
|
|
||||||
ret=coroutine.yield({"_hold_",n})
|
|
||||||
elseif type(n)=="number" then
|
|
||||||
n = tonumber(n) or 0
|
|
||||||
ret=coroutine.yield({"_sleep_",n})
|
|
||||||
else
|
|
||||||
error("Invalid Type for sleep!")
|
|
||||||
end
|
|
||||||
end
|
|
||||||
c.hold=c.sleep
|
|
||||||
multi:newThread(name,function(ref)
|
|
||||||
while true do
|
|
||||||
if c.rest then
|
|
||||||
ref:Sleep(c.restRate) -- rest a bit more when a thread is paused
|
|
||||||
else
|
|
||||||
c:uManager()
|
|
||||||
ref:sleep(c.updaterate) -- lets rest a bit
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end)
|
|
||||||
return c
|
|
||||||
end
|
|
||||||
@@ -1,115 +0,0 @@
|
|||||||
--[[
|
|
||||||
MIT License
|
|
||||||
|
|
||||||
Copyright (c) 2017 Ryan Ward
|
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
|
||||||
in the Software without restriction, including without limitation the rights
|
|
||||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
copies of the Software, and to permit persons to whom the Software is
|
|
||||||
furnished to do so, subject to the following conditions:
|
|
||||||
|
|
||||||
The above copyright notice and this permission notice shall be included in all
|
|
||||||
copies or substantial portions of the Software.
|
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
||||||
SOFTWARE.
|
|
||||||
]]
|
|
||||||
require("multi.threading")
|
|
||||||
function multi:newThreadedStep(name,start,reset,count,skip)
|
|
||||||
local c=self:newTBase()
|
|
||||||
local think=1
|
|
||||||
c.Type='stepThread'
|
|
||||||
c.pos=start or 1
|
|
||||||
c.endAt=reset or math.huge
|
|
||||||
c.skip=skip or 0
|
|
||||||
c.spos=0
|
|
||||||
c.count=count or 1*think
|
|
||||||
c.funcE={}
|
|
||||||
c.funcS={}
|
|
||||||
c.start=start or 1
|
|
||||||
if start~=nil and reset~=nil then
|
|
||||||
if start>reset then
|
|
||||||
think=-1
|
|
||||||
end
|
|
||||||
end
|
|
||||||
function c:tofile(path)
|
|
||||||
local m=bin.new()
|
|
||||||
m:addBlock(self.Type)
|
|
||||||
m:addBlock(self.func)
|
|
||||||
m:addBlock(self.funcE)
|
|
||||||
m:addBlock(self.funcS)
|
|
||||||
m:addBlock({pos=self.pos,endAt=self.endAt,skip=self.skip,spos=self.spos,count=self.count,start=self.start})
|
|
||||||
m:addBlock(self.Active)
|
|
||||||
m:tofile(path)
|
|
||||||
end
|
|
||||||
function c:Resume()
|
|
||||||
self.rest=false
|
|
||||||
end
|
|
||||||
function c:Pause()
|
|
||||||
self.rest=true
|
|
||||||
end
|
|
||||||
c.Reset=c.Resume
|
|
||||||
function c:OnStart(func)
|
|
||||||
table.insert(self.funcS,func)
|
|
||||||
end
|
|
||||||
function c:OnStep(func)
|
|
||||||
table.insert(self.func,1,func)
|
|
||||||
end
|
|
||||||
function c:OnEnd(func)
|
|
||||||
table.insert(self.funcE,func)
|
|
||||||
end
|
|
||||||
function c:Break()
|
|
||||||
self.rest=true
|
|
||||||
end
|
|
||||||
function c:Update(start,reset,count,skip)
|
|
||||||
self.start=start or self.start
|
|
||||||
self.endAt=reset or self.endAt
|
|
||||||
self.skip=skip or self.skip
|
|
||||||
self.count=count or self.count
|
|
||||||
self:Resume()
|
|
||||||
end
|
|
||||||
c.updaterate=0
|
|
||||||
c.restRate=.1
|
|
||||||
multi:newThread(name,function(ref)
|
|
||||||
while true do
|
|
||||||
if c.rest then
|
|
||||||
ref:sleep(c.restRate) -- rest a bit more when a thread is paused
|
|
||||||
else
|
|
||||||
if c~=nil then
|
|
||||||
if c.spos==0 then
|
|
||||||
if c.pos==c.start then
|
|
||||||
for fe=1,#c.funcS do
|
|
||||||
c.funcS[fe](c)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
for i=1,#c.func do
|
|
||||||
c.func[i](c.pos,c)
|
|
||||||
end
|
|
||||||
c.pos=c.pos+c.count
|
|
||||||
if c.pos-c.count==c.endAt then
|
|
||||||
c:Pause()
|
|
||||||
for fe=1,#c.funcE do
|
|
||||||
c.funcE[fe](c)
|
|
||||||
end
|
|
||||||
c.pos=c.start
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
c.spos=c.spos+1
|
|
||||||
if c.spos>=c.skip then
|
|
||||||
c.spos=0
|
|
||||||
end
|
|
||||||
ref:sleep(c.updaterate) -- lets rest a bit
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end)
|
|
||||||
self:create(c)
|
|
||||||
return c
|
|
||||||
end
|
|
||||||
@@ -1,65 +0,0 @@
|
|||||||
--[[
|
|
||||||
MIT License
|
|
||||||
|
|
||||||
Copyright (c) 2017 Ryan Ward
|
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
|
||||||
in the Software without restriction, including without limitation the rights
|
|
||||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
copies of the Software, and to permit persons to whom the Software is
|
|
||||||
furnished to do so, subject to the following conditions:
|
|
||||||
|
|
||||||
The above copyright notice and this permission notice shall be included in all
|
|
||||||
copies or substantial portions of the Software.
|
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
||||||
SOFTWARE.
|
|
||||||
]]
|
|
||||||
require("multi.threading")
|
|
||||||
function multi:newThreadedTLoop(name,func,n)
|
|
||||||
local c=self:newTBase()
|
|
||||||
c.Type='tloopThread'
|
|
||||||
c.restN=n or 1
|
|
||||||
if func then
|
|
||||||
c.func={func}
|
|
||||||
end
|
|
||||||
function c:tofile(path)
|
|
||||||
local m=bin.new()
|
|
||||||
m:addBlock(self.Type)
|
|
||||||
m:addBlock(self.func)
|
|
||||||
m:addBlock(self.Active)
|
|
||||||
m:tofile(path)
|
|
||||||
end
|
|
||||||
function c:Resume()
|
|
||||||
self.rest=false
|
|
||||||
end
|
|
||||||
function c:Pause()
|
|
||||||
self.rest=true
|
|
||||||
end
|
|
||||||
function c:OnLoop(func)
|
|
||||||
table.insert(self.func,func)
|
|
||||||
end
|
|
||||||
c.rest=false
|
|
||||||
c.updaterate=0
|
|
||||||
c.restRate=.75
|
|
||||||
multi:newThread(name,function(ref)
|
|
||||||
while true do
|
|
||||||
if c.rest then
|
|
||||||
thread.sleep(c.restRate) -- rest a bit more when a thread is paused
|
|
||||||
else
|
|
||||||
for i=1,#c.func do
|
|
||||||
c.func[i](c)
|
|
||||||
end
|
|
||||||
thread.sleep(c.restN) -- lets rest a bit
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end)
|
|
||||||
self:create(c)
|
|
||||||
return c
|
|
||||||
end
|
|
||||||
@@ -1,114 +0,0 @@
|
|||||||
--[[
|
|
||||||
MIT License
|
|
||||||
|
|
||||||
Copyright (c) 2017 Ryan Ward
|
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
|
||||||
in the Software without restriction, including without limitation the rights
|
|
||||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
copies of the Software, and to permit persons to whom the Software is
|
|
||||||
furnished to do so, subject to the following conditions:
|
|
||||||
|
|
||||||
The above copyright notice and this permission notice shall be included in all
|
|
||||||
copies or substantial portions of the Software.
|
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
||||||
SOFTWARE.
|
|
||||||
]]
|
|
||||||
require("multi.threading")
|
|
||||||
function multi:newThreadedTStep(name,start,reset,count,set)
|
|
||||||
local c=self:newTBase()
|
|
||||||
local think=1
|
|
||||||
c.Type='tstepThread'
|
|
||||||
c.Priority=self.Priority_Low
|
|
||||||
c.start=start or 1
|
|
||||||
local reset = reset or math.huge
|
|
||||||
c.endAt=reset
|
|
||||||
c.pos=start or 1
|
|
||||||
c.skip=skip or 0
|
|
||||||
c.count=count or 1*think
|
|
||||||
c.funcE={}
|
|
||||||
c.timer=os.clock()
|
|
||||||
c.set=set or 1
|
|
||||||
c.funcS={}
|
|
||||||
function c:Update(start,reset,count,set)
|
|
||||||
self.start=start or self.start
|
|
||||||
self.pos=self.start
|
|
||||||
self.endAt=reset or self.endAt
|
|
||||||
self.set=set or self.set
|
|
||||||
self.count=count or self.count or 1
|
|
||||||
self.timer=os.clock()
|
|
||||||
self:Resume()
|
|
||||||
end
|
|
||||||
function c:tofile(path)
|
|
||||||
local m=bin.new()
|
|
||||||
m:addBlock(self.Type)
|
|
||||||
m:addBlock(self.func)
|
|
||||||
m:addBlock(self.funcE)
|
|
||||||
m:addBlock(self.funcS)
|
|
||||||
m:addBlock({pos=self.pos,endAt=self.endAt,skip=self.skip,timer=self.timer,count=self.count,start=self.start,set=self.set})
|
|
||||||
m:addBlock(self.Active)
|
|
||||||
m:tofile(path)
|
|
||||||
end
|
|
||||||
function c:Resume()
|
|
||||||
self.rest=false
|
|
||||||
end
|
|
||||||
function c:Pause()
|
|
||||||
self.rest=true
|
|
||||||
end
|
|
||||||
function c:OnStart(func)
|
|
||||||
table.insert(self.funcS,func)
|
|
||||||
end
|
|
||||||
function c:OnStep(func)
|
|
||||||
table.insert(self.func,func)
|
|
||||||
end
|
|
||||||
function c:OnEnd(func)
|
|
||||||
table.insert(self.funcE,func)
|
|
||||||
end
|
|
||||||
function c:Break()
|
|
||||||
self.Active=nil
|
|
||||||
end
|
|
||||||
function c:Reset(n)
|
|
||||||
if n then self.set=n end
|
|
||||||
self.timer=os.clock()
|
|
||||||
self:Resume()
|
|
||||||
end
|
|
||||||
c.updaterate=0--multi.Priority_Low -- skips
|
|
||||||
c.restRate=0
|
|
||||||
multi:newThread(name,function(ref)
|
|
||||||
while true do
|
|
||||||
if c.rest then
|
|
||||||
thread.sleep(c.restRate) -- rest a bit more when a thread is paused
|
|
||||||
else
|
|
||||||
if os.clock()-c.timer>=c.set then
|
|
||||||
c:Reset()
|
|
||||||
if c.pos==c.start then
|
|
||||||
for fe=1,#c.funcS do
|
|
||||||
c.funcS[fe](c)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
for i=1,#c.func do
|
|
||||||
c.func[i](c.pos,c)
|
|
||||||
end
|
|
||||||
c.pos=c.pos+c.count
|
|
||||||
if c.pos-c.count==c.endAt then
|
|
||||||
c:Pause()
|
|
||||||
for fe=1,#c.funcE do
|
|
||||||
c.funcE[fe](c)
|
|
||||||
end
|
|
||||||
c.pos=c.start
|
|
||||||
end
|
|
||||||
end
|
|
||||||
thread.skip(c.updaterate) -- lets rest a bit
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end)
|
|
||||||
self:create(c)
|
|
||||||
return c
|
|
||||||
end
|
|
||||||
@@ -0,0 +1,54 @@
|
|||||||
|
-- set up the package
|
||||||
|
package.path="?/init.lua;?.lua;"..package.path
|
||||||
|
-- Import the libraries
|
||||||
|
multi = require("multi")
|
||||||
|
local GLOBAL, THREAD = require("multi.integration.lanesManager").init()
|
||||||
|
nGLOBAL = require("multi.integration.networkManager").init()
|
||||||
|
-- Act as a master node
|
||||||
|
master = multi:newMaster{
|
||||||
|
name = "Main", -- the name of the master
|
||||||
|
--noBroadCast = true, -- if using the node manager, set this to true to save on some cpu cycles
|
||||||
|
--managerDetails = {"localhost",12345}, -- the details to connect to the node manager (ip,port)
|
||||||
|
}
|
||||||
|
-- Send to all the nodes that are connected to the master
|
||||||
|
master.OnError(function(name,err)
|
||||||
|
print(name.." has encountered an error: "..err)
|
||||||
|
end)
|
||||||
|
master.OnNodeConnected(function(name)
|
||||||
|
print("Lets Go!")
|
||||||
|
master:newNetworkThread("Thread",function(node) -- spawn a network thread on a node that can execute code and return date
|
||||||
|
local print = node:getConsole().print -- it is important to define things as local... another thing i could do is fenv to make sure all masters work in a protectd isolated enviroment
|
||||||
|
multi:newTLoop(function()
|
||||||
|
print("Yo whats up man!")
|
||||||
|
error("doing a test")
|
||||||
|
end,1)
|
||||||
|
end)
|
||||||
|
master:execute("RemoteTest",name,1,2,3) -- calls a predefined or registered global method on a node
|
||||||
|
multi:newThread("waiter",function()
|
||||||
|
print("Hello!",name)
|
||||||
|
while true do
|
||||||
|
thread.sleep(2)
|
||||||
|
master:pushTo(name,"This is a test 2")
|
||||||
|
if master.connections["NODE_"..name]==nil then
|
||||||
|
thread.kill()
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
end)
|
||||||
|
multi:newThread("some-test",function()
|
||||||
|
local dat = master:pop()
|
||||||
|
while true do
|
||||||
|
thread.skip(10)
|
||||||
|
if dat then
|
||||||
|
print(dat)
|
||||||
|
end
|
||||||
|
dat = master:pop()
|
||||||
|
end
|
||||||
|
end,"NODE_TESTNODE")
|
||||||
|
-- Starting the multitasker
|
||||||
|
settings = {
|
||||||
|
priority = 0, -- 0, 1 or 2
|
||||||
|
protect = true,
|
||||||
|
}
|
||||||
|
multi:threadloop(settings)
|
||||||
|
--multi:mainloop(settings)
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
package.path="?/init.lua;?.lua;"..package.path
|
||||||
|
multi = require("multi")
|
||||||
|
local GLOBAL, THREAD = require("multi.integration.lanesManager").init()
|
||||||
|
nGLOBAL = require("multi.integration.networkManager").init()
|
||||||
|
node = multi:newNode{
|
||||||
|
crossTalk = false, -- default value, allows nodes to talk to eachother. WIP NOT READY YET!
|
||||||
|
allowRemoteRegistering = true, -- allows you to register functions from the master on the node, default is false
|
||||||
|
name = "MASTERPC", -- default value is nil, if nil a random name is generated. Naming nodes are important if you assign each node on a network with a different task
|
||||||
|
--noBroadCast = true, -- if using the node manager, set this to true to save on some cpu cycles
|
||||||
|
--managerDetails = {"localhost",12345}, -- connects to the node manager if one exists
|
||||||
|
}
|
||||||
|
function RemoteTest(a,b,c) -- a function that we will be executing remotely
|
||||||
|
print("Yes I work!",a,b,c)
|
||||||
|
end
|
||||||
|
settings = {
|
||||||
|
priority = 0, -- 1 or 2
|
||||||
|
stopOnError = true,
|
||||||
|
protect = true, -- if something goes wrong we will crash hard, but the speed gain is good
|
||||||
|
}
|
||||||
|
multi:mainloop(settings)
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
package.path="?/init.lua;?.lua;"..package.path
|
||||||
|
multi = require("multi")
|
||||||
|
local GLOBAL, THREAD = require("multi.integration.lanesManager").init()
|
||||||
|
nGLOBAL = require("multi.integration.networkManager").init()
|
||||||
|
multi:nodeManager(12345) -- Host a node manager on port: 12345
|
||||||
|
print("Node Manager Running...")
|
||||||
|
settings = {
|
||||||
|
priority = 0, -- 1 or 2
|
||||||
|
protect = false,
|
||||||
|
}
|
||||||
|
multi:mainloop(settings)
|
||||||
|
-- Thats all you need to run the node manager, everything else is done automatically
|
||||||
@@ -1,9 +0,0 @@
|
|||||||
require("multi")
|
|
||||||
require("multi.threading")
|
|
||||||
require("multi.threading.alarm")
|
|
||||||
require("multi.threading.event")
|
|
||||||
require("multi.threading.loop")
|
|
||||||
require("multi.threading.process")
|
|
||||||
require("multi.threading.step")
|
|
||||||
require("multi.threading.tstep")
|
|
||||||
require("multi.threading.updater")
|
|
||||||
@@ -1,305 +0,0 @@
|
|||||||
--[[
|
|
||||||
MIT License
|
|
||||||
|
|
||||||
Copyright (c) 2017 Ryan Ward
|
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
|
||||||
in the Software without restriction, including without limitation the rights
|
|
||||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
copies of the Software, and to permit persons to whom the Software is
|
|
||||||
furnished to do so, subject to the following conditions:
|
|
||||||
|
|
||||||
The above copyright notice and this permission notice shall be included in all
|
|
||||||
copies or substantial portions of the Software.
|
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
||||||
SOFTWARE.
|
|
||||||
]]
|
|
||||||
multi.OnObjectCreated(function(obj)
|
|
||||||
if obj.Type=="loop" then
|
|
||||||
function obj:Act()
|
|
||||||
for i=1,#self.func do
|
|
||||||
self.func[i](self.Parent.clock()-self.Start,self)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
elseif obj.Type=="step" then
|
|
||||||
function obj:Act()
|
|
||||||
if self~=nil then
|
|
||||||
if self.spos==0 then
|
|
||||||
if self.pos==self.start then
|
|
||||||
for fe=1,#self.funcS do
|
|
||||||
self.funcS[fe](self)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
for i=1,#self.func do
|
|
||||||
self.func[i](self.pos,self)
|
|
||||||
end
|
|
||||||
self.pos=self.pos+self.count
|
|
||||||
if self.pos-self.count==self.endAt then
|
|
||||||
self:Pause()
|
|
||||||
for fe=1,#self.funcE do
|
|
||||||
self.funcE[fe](self)
|
|
||||||
end
|
|
||||||
self.pos=self.start
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
self.spos=self.spos+1
|
|
||||||
if self.spos>=self.skip then
|
|
||||||
self.spos=0
|
|
||||||
end
|
|
||||||
end
|
|
||||||
elseif obj.Type=="tstep" then
|
|
||||||
function c:Act()
|
|
||||||
if self.clock()-self.timer>=self.set then
|
|
||||||
self:Reset()
|
|
||||||
if self.pos==self.start then
|
|
||||||
for fe=1,#self.funcS do
|
|
||||||
self.funcS[fe](self)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
for i=1,#self.func do
|
|
||||||
self.func[i](self.pos,self)
|
|
||||||
end
|
|
||||||
self.pos=self.pos+self.count
|
|
||||||
if self.pos-self.count==self.endAt then
|
|
||||||
self:Pause()
|
|
||||||
for fe=1,#self.funcE do
|
|
||||||
self.funcE[fe](self)
|
|
||||||
end
|
|
||||||
self.pos=self.start
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end)
|
|
||||||
if thread then
|
|
||||||
function multi:newThreadedLoop(name,func)
|
|
||||||
local c=self:newTBase()
|
|
||||||
c.Type='loopThread'
|
|
||||||
c.Start=os.clock()
|
|
||||||
if func then
|
|
||||||
c.func={func}
|
|
||||||
end
|
|
||||||
function c:tofile(path)
|
|
||||||
local m=bin.new()
|
|
||||||
m:addBlock(self.Type)
|
|
||||||
m:addBlock(self.func)
|
|
||||||
m:addBlock(self.Active)
|
|
||||||
m:tofile(path)
|
|
||||||
end
|
|
||||||
function c:Resume()
|
|
||||||
self.rest=false
|
|
||||||
end
|
|
||||||
function c:Pause()
|
|
||||||
self.rest=true
|
|
||||||
end
|
|
||||||
function c:OnLoop(func)
|
|
||||||
table.insert(self.func,func)
|
|
||||||
end
|
|
||||||
c.rest=false
|
|
||||||
c.updaterate=0
|
|
||||||
c.restRate=.75
|
|
||||||
multi:newThread(name,function(ref)
|
|
||||||
while true do
|
|
||||||
if c.rest then
|
|
||||||
thread.sleep(c.restRate)
|
|
||||||
else
|
|
||||||
for i=1,#c.func do
|
|
||||||
c.func[i](os.clock()-self.Start,c)
|
|
||||||
end
|
|
||||||
thread.sleep(c.updaterate)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end)
|
|
||||||
self:create(c)
|
|
||||||
return c
|
|
||||||
end
|
|
||||||
function multi:newThreadedStep(name,start,reset,count,skip)
|
|
||||||
local c=self:newTBase()
|
|
||||||
local think=1
|
|
||||||
c.Type='stepThread'
|
|
||||||
c.pos=start or 1
|
|
||||||
c.endAt=reset or math.huge
|
|
||||||
c.skip=skip or 0
|
|
||||||
c.spos=0
|
|
||||||
c.count=count or 1*think
|
|
||||||
c.funcE={}
|
|
||||||
c.funcS={}
|
|
||||||
c.start=start or 1
|
|
||||||
if start~=nil and reset~=nil then
|
|
||||||
if start>reset then
|
|
||||||
think=-1
|
|
||||||
end
|
|
||||||
end
|
|
||||||
function c:tofile(path)
|
|
||||||
local m=bin.new()
|
|
||||||
m:addBlock(self.Type)
|
|
||||||
m:addBlock(self.func)
|
|
||||||
m:addBlock(self.funcE)
|
|
||||||
m:addBlock(self.funcS)
|
|
||||||
m:addBlock({pos=self.pos,endAt=self.endAt,skip=self.skip,spos=self.spos,count=self.count,start=self.start})
|
|
||||||
m:addBlock(self.Active)
|
|
||||||
m:tofile(path)
|
|
||||||
end
|
|
||||||
function c:Resume()
|
|
||||||
self.rest=false
|
|
||||||
end
|
|
||||||
function c:Pause()
|
|
||||||
self.rest=true
|
|
||||||
end
|
|
||||||
c.Reset=c.Resume
|
|
||||||
function c:OnStart(func)
|
|
||||||
table.insert(self.funcS,func)
|
|
||||||
end
|
|
||||||
function c:OnStep(func)
|
|
||||||
table.insert(self.func,1,func)
|
|
||||||
end
|
|
||||||
function c:OnEnd(func)
|
|
||||||
table.insert(self.funcE,func)
|
|
||||||
end
|
|
||||||
function c:Break()
|
|
||||||
self.rest=true
|
|
||||||
end
|
|
||||||
function c:Update(start,reset,count,skip)
|
|
||||||
self.start=start or self.start
|
|
||||||
self.endAt=reset or self.endAt
|
|
||||||
self.skip=skip or self.skip
|
|
||||||
self.count=count or self.count
|
|
||||||
self:Resume()
|
|
||||||
end
|
|
||||||
c.updaterate=0
|
|
||||||
c.restRate=.1
|
|
||||||
multi:newThread(name,function(ref)
|
|
||||||
while true do
|
|
||||||
if c.rest then
|
|
||||||
ref:sleep(c.restRate)
|
|
||||||
else
|
|
||||||
if c~=nil then
|
|
||||||
if c.spos==0 then
|
|
||||||
if c.pos==c.start then
|
|
||||||
for fe=1,#c.funcS do
|
|
||||||
c.funcS[fe](c)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
for i=1,#c.func do
|
|
||||||
c.func[i](c.pos,c)
|
|
||||||
end
|
|
||||||
c.pos=c.pos+c.count
|
|
||||||
if c.pos-c.count==c.endAt then
|
|
||||||
c:Pause()
|
|
||||||
for fe=1,#c.funcE do
|
|
||||||
c.funcE[fe](c)
|
|
||||||
end
|
|
||||||
c.pos=c.start
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
c.spos=c.spos+1
|
|
||||||
if c.spos>=c.skip then
|
|
||||||
c.spos=0
|
|
||||||
end
|
|
||||||
ref:sleep(c.updaterate)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end)
|
|
||||||
self:create(c)
|
|
||||||
return c
|
|
||||||
end
|
|
||||||
function multi:newThreadedTStep(name,start,reset,count,set)
|
|
||||||
local c=self:newTBase()
|
|
||||||
local think=1
|
|
||||||
c.Type='tstepThread'
|
|
||||||
c.Priority=self.Priority_Low
|
|
||||||
c.start=start or 1
|
|
||||||
local reset = reset or math.huge
|
|
||||||
c.endAt=reset
|
|
||||||
c.pos=start or 1
|
|
||||||
c.skip=skip or 0
|
|
||||||
c.count=count or 1*think
|
|
||||||
c.funcE={}
|
|
||||||
c.timer=os.clock()
|
|
||||||
c.set=set or 1
|
|
||||||
c.funcS={}
|
|
||||||
function c:Update(start,reset,count,set)
|
|
||||||
self.start=start or self.start
|
|
||||||
self.pos=self.start
|
|
||||||
self.endAt=reset or self.endAt
|
|
||||||
self.set=set or self.set
|
|
||||||
self.count=count or self.count or 1
|
|
||||||
self.timer=os.clock()
|
|
||||||
self:Resume()
|
|
||||||
end
|
|
||||||
function c:tofile(path)
|
|
||||||
local m=bin.new()
|
|
||||||
m:addBlock(self.Type)
|
|
||||||
m:addBlock(self.func)
|
|
||||||
m:addBlock(self.funcE)
|
|
||||||
m:addBlock(self.funcS)
|
|
||||||
m:addBlock({pos=self.pos,endAt=self.endAt,skip=self.skip,timer=self.timer,count=self.count,start=self.start,set=self.set})
|
|
||||||
m:addBlock(self.Active)
|
|
||||||
m:tofile(path)
|
|
||||||
end
|
|
||||||
function c:Resume()
|
|
||||||
self.rest=false
|
|
||||||
end
|
|
||||||
function c:Pause()
|
|
||||||
self.rest=true
|
|
||||||
end
|
|
||||||
function c:OnStart(func)
|
|
||||||
table.insert(self.funcS,func)
|
|
||||||
end
|
|
||||||
function c:OnStep(func)
|
|
||||||
table.insert(self.func,func)
|
|
||||||
end
|
|
||||||
function c:OnEnd(func)
|
|
||||||
table.insert(self.funcE,func)
|
|
||||||
end
|
|
||||||
function c:Break()
|
|
||||||
self.Active=nil
|
|
||||||
end
|
|
||||||
function c:Reset(n)
|
|
||||||
if n then self.set=n end
|
|
||||||
self.timer=os.clock()
|
|
||||||
self:Resume()
|
|
||||||
end
|
|
||||||
c.updaterate=0
|
|
||||||
c.restRate=0
|
|
||||||
multi:newThread(name,function(ref)
|
|
||||||
while true do
|
|
||||||
if c.rest then
|
|
||||||
thread.sleep(c.restRate)
|
|
||||||
else
|
|
||||||
if os.clock()-c.timer>=c.set then
|
|
||||||
c:Reset()
|
|
||||||
if c.pos==c.start then
|
|
||||||
for fe=1,#c.funcS do
|
|
||||||
c.funcS[fe](c)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
for i=1,#c.func do
|
|
||||||
c.func[i](c.pos,c)
|
|
||||||
end
|
|
||||||
c.pos=c.pos+c.count
|
|
||||||
if c.pos-c.count==c.endAt then
|
|
||||||
c:Pause()
|
|
||||||
for fe=1,#c.funcE do
|
|
||||||
c.funcE[fe](c)
|
|
||||||
end
|
|
||||||
c.pos=c.start
|
|
||||||
end
|
|
||||||
end
|
|
||||||
thread.skip(c.updaterate)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end)
|
|
||||||
self:create(c)
|
|
||||||
return c
|
|
||||||
end
|
|
||||||
end
|
|
||||||
+44
-95
@@ -1,12 +1,12 @@
|
|||||||
--[[
|
--[[
|
||||||
MIT License
|
MIT License
|
||||||
|
|
||||||
Copyright (c) 2017 Ryan Ward
|
Copyright (c) 2020 Ryan Ward
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
in the Software without restriction, including without limitation the rights
|
in the Software without restriction, including without limitation the rights
|
||||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
to use, copy, modify, merge, publish, distribute, sub-license, and/or sell
|
||||||
copies of the Software, and to permit persons to whom the Software is
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
furnished to do so, subject to the following conditions:
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
@@ -21,107 +21,56 @@ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|||||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
SOFTWARE.
|
SOFTWARE.
|
||||||
]]
|
]]
|
||||||
require("multi.all")
|
local multi, thread = require("multi").init()
|
||||||
os.sleep = love.timer.sleep
|
os.sleep = love.timer.sleep
|
||||||
--~ function bin.load(file,s,r)
|
|
||||||
--~ content, size = love.filesystem.read(file)
|
|
||||||
--~ local temp=bin.new(content)
|
|
||||||
--~ temp.filepath=file
|
|
||||||
--~ return temp
|
|
||||||
--~ end
|
|
||||||
--~ function bin:tofile(filename)
|
|
||||||
--~ if not(filename) or self.Stream then return nil end
|
|
||||||
--~ love.filesystem.write(filename,self.data)
|
|
||||||
--~ end
|
|
||||||
--~ function bin.stream(file,l)
|
|
||||||
--~ error("Sorry streaming is not available when using love2d :(, I am looking for a solution though :)")
|
|
||||||
--~ end
|
|
||||||
function love.run()
|
|
||||||
if love.math then
|
|
||||||
love.math.setRandomSeed(os.time())
|
|
||||||
end
|
|
||||||
if love.event then
|
|
||||||
love.event.pump()
|
|
||||||
end
|
|
||||||
if love.load then love.load(arg) end
|
|
||||||
if love.timer then love.timer.step() end
|
|
||||||
local dt = 0
|
|
||||||
while true do
|
|
||||||
-- Process events.
|
|
||||||
if love.event then
|
|
||||||
love.event.pump()
|
|
||||||
for e,a,b,c,d in love.event.poll() do
|
|
||||||
if e == "quit" then
|
|
||||||
if not love.quit or not love.quit() then
|
|
||||||
if love.audio then
|
|
||||||
love.audio.stop()
|
|
||||||
end
|
|
||||||
return
|
|
||||||
end
|
|
||||||
end
|
|
||||||
love.handlers[e](a,b,c,d)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
if love.timer then
|
|
||||||
love.timer.step()
|
|
||||||
dt = love.timer.getDelta()
|
|
||||||
end
|
|
||||||
if love.update then love.update(dt) end
|
|
||||||
if multi.boost then
|
|
||||||
for i=1,multi.boost-1 do
|
|
||||||
multi:uManager(dt)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
multi:uManager(dt)
|
|
||||||
if love.window and love.graphics and love.window.isCreated() then
|
|
||||||
love.graphics.clear()
|
|
||||||
love.graphics.origin()
|
|
||||||
if love.draw then love.draw() end
|
|
||||||
multi.dManager()
|
|
||||||
love.graphics.setColor(255,255,255,255)
|
|
||||||
if multi.draw then multi.draw() end
|
|
||||||
love.graphics.present()
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
multi.drawF = {}
|
multi.drawF = {}
|
||||||
function multi:dManager()
|
|
||||||
for ii=1,#multi.drawF do
|
|
||||||
multi.drawF[ii]()
|
|
||||||
end
|
|
||||||
end
|
|
||||||
function multi:onDraw(func, i)
|
function multi:onDraw(func, i)
|
||||||
i = i or 1
|
i = i or 1
|
||||||
table.insert(self.drawF, i, func)
|
table.insert(self.drawF, i, func)
|
||||||
end
|
end
|
||||||
function multi:lManager()
|
multi.OnKeyPressed = multi:newConnection()
|
||||||
if love.event then
|
multi.OnKeyReleased = multi:newConnection()
|
||||||
love.event.pump()
|
multi.OnMousePressed = multi:newConnection()
|
||||||
for e,a,b,c,d in love.event.poll() do
|
multi.OnMouseReleased = multi:newConnection()
|
||||||
if e == "quit" then
|
multi.OnMouseWheelMoved = multi:newConnection()
|
||||||
if not love.quit or not love.quit() then
|
multi.OnMouseMoved = multi:newConnection()
|
||||||
if love.audio then
|
multi.OnDraw = multi:newConnection()
|
||||||
love.audio.stop()
|
multi.OnTextInput = multi:newConnection()
|
||||||
end
|
multi.OnUpdate = multi:newConnection()
|
||||||
return nil
|
multi.OnQuit = multi:newConnection()
|
||||||
|
multi.OnPreLoad(function()
|
||||||
|
local function Hook(func, conn)
|
||||||
|
if love[func] ~= nil then
|
||||||
|
love[func] = Library.convert(love[func])
|
||||||
|
love[func]:inject(function(...)
|
||||||
|
conn:Fire(...)
|
||||||
|
return {...}
|
||||||
|
end,1)
|
||||||
|
elseif love[func] == nil then
|
||||||
|
love[func] = function(...)
|
||||||
|
conn:Fire(...)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
love.handlers[e](a,b,c,d)
|
|
||||||
end
|
end
|
||||||
end
|
Hook("quit", multi.OnQuit)
|
||||||
if love.timer then
|
Hook("keypressed", multi.OnKeyPressed)
|
||||||
love.timer.step()
|
Hook("keyreleased", multi.OnKeyReleased)
|
||||||
dt = love.timer.getDelta()
|
Hook("mousepressed", multi.OnMousePressed)
|
||||||
end
|
Hook("mousereleased", multi.OnMouseReleased)
|
||||||
if love.update then love.update(dt) end
|
Hook("wheelmoved", multi.OnMouseWheelMoved)
|
||||||
multi:uManager(dt)
|
Hook("mousemoved", multi.OnMouseMoved)
|
||||||
if love.window and love.graphics and love.window.isCreated() then
|
Hook("draw", multi.OnDraw)
|
||||||
love.graphics.clear()
|
Hook("textinput", multi.OnTextInput)
|
||||||
love.graphics.origin()
|
Hook("update", multi.OnUpdate)
|
||||||
if love.draw then love.draw() end
|
multi.OnDraw(function()
|
||||||
multi.dManager()
|
for i = 1, #multi.drawF do
|
||||||
love.graphics.setColor(255, 255, 255, 255)
|
love.graphics.setColor(255, 255, 255, 255)
|
||||||
if multi.draw then multi.draw() end
|
multi.drawF[i]()
|
||||||
love.graphics.present()
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
end)
|
||||||
|
end)
|
||||||
|
multi.OnQuit(function()
|
||||||
|
multi.Stop()
|
||||||
|
love.event.quit()
|
||||||
|
end)
|
||||||
|
return multi
|
||||||
|
|||||||
+1839
-609
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,139 @@
|
|||||||
|
--[[
|
||||||
|
MIT License
|
||||||
|
|
||||||
|
Copyright (c) 2020 Ryan Ward
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sub-license, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
||||||
|
]]
|
||||||
|
local multi, thread = require("multi"):init()
|
||||||
|
local GLOBAL, THREAD = multi.integration.GLOBAL,multi.integration.THREAD
|
||||||
|
function multi:newSystemThreadedQueue(name)
|
||||||
|
local c = {}
|
||||||
|
c.linda = lanes.linda()
|
||||||
|
function c:push(v)
|
||||||
|
self.linda:send("Q", v)
|
||||||
|
end
|
||||||
|
function c:pop()
|
||||||
|
return ({self.linda:receive(0, "Q")})[2]
|
||||||
|
end
|
||||||
|
function c:peek()
|
||||||
|
return self.linda:get("Q")
|
||||||
|
end
|
||||||
|
function c:init()
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
GLOBAL[name or "_"] = c
|
||||||
|
return c
|
||||||
|
end
|
||||||
|
function multi:newSystemThreadedTable(name)
|
||||||
|
local c = {}
|
||||||
|
c.link = lanes.linda()
|
||||||
|
setmetatable(c,{
|
||||||
|
__index = function(t,k)
|
||||||
|
return c.link:get(k)
|
||||||
|
end,
|
||||||
|
__newindex = function(t,k,v)
|
||||||
|
c.link:set(k,v)
|
||||||
|
end
|
||||||
|
})
|
||||||
|
function c:init()
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
GLOBAL[name or "_"] = c
|
||||||
|
return c
|
||||||
|
end
|
||||||
|
function multi:newSystemThreadedJobQueue(n)
|
||||||
|
local c = {}
|
||||||
|
c.cores = n or THREAD.getCores()*2
|
||||||
|
c.OnJobCompleted = multi:newConnection()
|
||||||
|
local funcs = multi:newSystemThreadedTable()
|
||||||
|
local queueJob = multi:newSystemThreadedQueue()
|
||||||
|
local queueReturn = multi:newSystemThreadedQueue()
|
||||||
|
local doAll = multi:newSystemThreadedQueue()
|
||||||
|
local ID=1
|
||||||
|
local jid = 1
|
||||||
|
function c:doToAll(func)
|
||||||
|
for i=1,c.cores do
|
||||||
|
doAll:push{ID,func}
|
||||||
|
end
|
||||||
|
ID = ID + 1
|
||||||
|
end
|
||||||
|
function c:registerFunction(name,func)
|
||||||
|
funcs[name]=func
|
||||||
|
end
|
||||||
|
function c:pushJob(name,...)
|
||||||
|
queueJob:push{name,jid,{...}}
|
||||||
|
jid = jid + 1
|
||||||
|
end
|
||||||
|
multi:newThread("JobQueueManager",function()
|
||||||
|
while true do
|
||||||
|
local job = thread.hold(function()
|
||||||
|
return queueReturn:pop()
|
||||||
|
end)
|
||||||
|
local id = table.remove(job,1)
|
||||||
|
c.OnJobCompleted:Fire(id,unpack(job))
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
for i=1,c.cores do
|
||||||
|
multi:newSystemThread("SystemThreadedJobQueue",function(queue)
|
||||||
|
local multi,thread = require("multi"):init()
|
||||||
|
local idle = os.clock()
|
||||||
|
local clock = os.clock
|
||||||
|
local ref = 0
|
||||||
|
setmetatable(_G,{__index = funcs})
|
||||||
|
multi:newThread("JobHandler",function()
|
||||||
|
while true do
|
||||||
|
local dat = thread.hold(function()
|
||||||
|
return queueJob:pop()
|
||||||
|
end)
|
||||||
|
idle = clock()
|
||||||
|
local name = table.remove(dat,1)
|
||||||
|
local jid = table.remove(dat,1)
|
||||||
|
local args = table.remove(dat,1)
|
||||||
|
queueReturn:push{jid, funcs[name](unpack(args)),queue}
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
multi:newThread("DoAllHandler",function()
|
||||||
|
while true do
|
||||||
|
local dat = thread.hold(function()
|
||||||
|
return doAll:peek()
|
||||||
|
end)
|
||||||
|
if dat then
|
||||||
|
if dat[1]>ref then
|
||||||
|
idle = clock()
|
||||||
|
ref = dat[1]
|
||||||
|
dat[2]()
|
||||||
|
doAll:pop()
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
multi:newThread("IdleHandler",function()
|
||||||
|
while true do
|
||||||
|
thread.hold(function()
|
||||||
|
return clock()-idle>3
|
||||||
|
end)
|
||||||
|
THREAD.sleep(.01)
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
multi:mainloop()
|
||||||
|
end,i).priority = thread.Priority_Core
|
||||||
|
end
|
||||||
|
return c
|
||||||
|
end
|
||||||
@@ -0,0 +1,129 @@
|
|||||||
|
--[[
|
||||||
|
MIT License
|
||||||
|
|
||||||
|
Copyright (c) 2020 Ryan Ward
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sub-license, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
||||||
|
]]
|
||||||
|
package.path = "?/init.lua;?.lua;" .. package.path
|
||||||
|
multi, thread = require("multi").init() -- get it all and have it on all lanes
|
||||||
|
if multi.integration then -- This allows us to call the lanes manager from supporting modules without a hassel
|
||||||
|
return {
|
||||||
|
init = function()
|
||||||
|
return multi.integration.GLOBAL, multi.integration.THREAD
|
||||||
|
end
|
||||||
|
}
|
||||||
|
end
|
||||||
|
-- Step 1 get lanes
|
||||||
|
lanes = require("lanes").configure()
|
||||||
|
multi.SystemThreads = {}
|
||||||
|
multi.isMainThread = true
|
||||||
|
function multi:canSystemThread()
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
function multi:getPlatform()
|
||||||
|
return "lanes"
|
||||||
|
end
|
||||||
|
-- Step 2 set up the Linda objects
|
||||||
|
local __GlobalLinda = lanes.linda() -- handles global stuff
|
||||||
|
local __SleepingLinda = lanes.linda() -- handles sleeping stuff
|
||||||
|
local GLOBAL,THREAD = require("multi.integration.lanesManager.threads").init(__GlobalLinda,__SleepingLinda)
|
||||||
|
local threads = {}
|
||||||
|
local count = 1
|
||||||
|
local started = false
|
||||||
|
local livingThreads = {}
|
||||||
|
function multi:newSystemThread(name, func, ...)
|
||||||
|
multi.InitSystemThreadErrorHandler()
|
||||||
|
rand = math.random(1, 10000000)
|
||||||
|
local c = {}
|
||||||
|
local __self = c
|
||||||
|
c.name = name
|
||||||
|
c.Name = name
|
||||||
|
c.Id = count
|
||||||
|
c.loadString = {"base","package","os,math","table","string","coroutine"}
|
||||||
|
livingThreads[count] = {true, name}
|
||||||
|
c.Type = "sthread"
|
||||||
|
c.creationTime = os.clock()
|
||||||
|
c.alive = true
|
||||||
|
c.priority = thread.Priority_Normal
|
||||||
|
local args = {...}
|
||||||
|
multi.nextStep(function()
|
||||||
|
c.thread = lanes.gen(table.concat(c.loadString,","),{globals={
|
||||||
|
THREAD_NAME=name,
|
||||||
|
THREAD_ID=count
|
||||||
|
},priority=c.priority}, func)(unpack(args))
|
||||||
|
end)
|
||||||
|
count = count + 1
|
||||||
|
function c:kill()
|
||||||
|
self.thread:cancel()
|
||||||
|
multi.print("Thread: '" .. self.name .. "' has been stopped!")
|
||||||
|
self.alive = false
|
||||||
|
end
|
||||||
|
table.insert(multi.SystemThreads, c)
|
||||||
|
c.OnError = multi:newConnection()
|
||||||
|
GLOBAL["__THREADS__"] = livingThreads
|
||||||
|
return c
|
||||||
|
end
|
||||||
|
multi.OnSystemThreadDied = multi:newConnection()
|
||||||
|
function multi.InitSystemThreadErrorHandler()
|
||||||
|
if started == true then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
started = true
|
||||||
|
multi:newThread(
|
||||||
|
"ThreadErrorHandler",
|
||||||
|
function()
|
||||||
|
local threads = multi.SystemThreads
|
||||||
|
while true do
|
||||||
|
thread.sleep(.5) -- switching states often takes a huge hit on performance. half a second to tell me there is an error is good enough.
|
||||||
|
for i = #threads, 1, -1 do
|
||||||
|
local v, err, t = threads[i].thread:join(.001)
|
||||||
|
if err then
|
||||||
|
if err:find("Thread was killed!") then
|
||||||
|
print(err)
|
||||||
|
livingThreads[threads[i].Id] = {false, threads[i].Name}
|
||||||
|
threads[i].alive = false
|
||||||
|
multi.OnSystemThreadDied:Fire(threads[i].Id)
|
||||||
|
GLOBAL["__THREADS__"] = livingThreads
|
||||||
|
table.remove(threads, i)
|
||||||
|
elseif err:find("stack traceback") then
|
||||||
|
print(err)
|
||||||
|
threads[i].OnError:Fire(threads[i], err, "Error in systemThread: '" .. threads[i].name .. "' <" .. err .. ">")
|
||||||
|
threads[i].alive = false
|
||||||
|
livingThreads[threads[i].Id] = {false, threads[i].Name}
|
||||||
|
multi.OnSystemThreadDied:Fire(threads[i].Id)
|
||||||
|
GLOBAL["__THREADS__"] = livingThreads
|
||||||
|
table.remove(threads, i)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
)
|
||||||
|
end
|
||||||
|
multi.print("Integrated Lanes!")
|
||||||
|
multi.integration = {} -- for module creators
|
||||||
|
multi.integration.GLOBAL = GLOBAL
|
||||||
|
multi.integration.THREAD = THREAD
|
||||||
|
require("multi.integration.lanesManager.extensions")
|
||||||
|
return {
|
||||||
|
init = function()
|
||||||
|
return GLOBAL, THREAD
|
||||||
|
end
|
||||||
|
}
|
||||||
@@ -0,0 +1,101 @@
|
|||||||
|
--[[
|
||||||
|
MIT License
|
||||||
|
|
||||||
|
Copyright (c) 2020 Ryan Ward
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sub-license, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
||||||
|
]]
|
||||||
|
local function getOS()
|
||||||
|
if package.config:sub(1, 1) == "\\" then
|
||||||
|
return "windows"
|
||||||
|
else
|
||||||
|
return "unix"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
local function INIT(__GlobalLinda,__SleepingLinda)
|
||||||
|
local THREAD = {}
|
||||||
|
function THREAD.set(name, val)
|
||||||
|
__GlobalLinda:set(name, val)
|
||||||
|
end
|
||||||
|
function THREAD.get(name)
|
||||||
|
__GlobalLinda:get(name)
|
||||||
|
end
|
||||||
|
function THREAD.waitFor(name)
|
||||||
|
local function wait()
|
||||||
|
math.randomseed(os.time())
|
||||||
|
__SleepingLinda:receive(.001, "__non_existing_variable")
|
||||||
|
end
|
||||||
|
repeat
|
||||||
|
wait()
|
||||||
|
until __GlobalLinda:get(name)
|
||||||
|
return __GlobalLinda:get(name)
|
||||||
|
end
|
||||||
|
if getOS() == "windows" then
|
||||||
|
THREAD.__CORES = tonumber(os.getenv("NUMBER_OF_PROCESSORS"))
|
||||||
|
else
|
||||||
|
THREAD.__CORES = tonumber(io.popen("nproc --all"):read("*n"))
|
||||||
|
end
|
||||||
|
function THREAD.getCores()
|
||||||
|
return THREAD.__CORES
|
||||||
|
end
|
||||||
|
function THREAD.getThreads()
|
||||||
|
return GLOBAL.__THREADS__
|
||||||
|
end
|
||||||
|
if os.getOS() == "windows" then
|
||||||
|
THREAD.__CORES = tonumber(os.getenv("NUMBER_OF_PROCESSORS"))
|
||||||
|
else
|
||||||
|
THREAD.__CORES = tonumber(io.popen("nproc --all"):read("*n"))
|
||||||
|
end
|
||||||
|
function THREAD.kill() -- trigger the lane destruction
|
||||||
|
error("Thread was killed!")
|
||||||
|
end
|
||||||
|
function THREAD.getName()
|
||||||
|
return THREAD_NAME
|
||||||
|
end
|
||||||
|
function THREAD.getID()
|
||||||
|
return THREAD_ID
|
||||||
|
end
|
||||||
|
_G.THREAD_ID = 0
|
||||||
|
function THREAD.sleep(n)
|
||||||
|
math.randomseed(os.time())
|
||||||
|
__SleepingLinda:receive(n, "__non_existing_variable")
|
||||||
|
end
|
||||||
|
function THREAD.hold(n)
|
||||||
|
local function wait()
|
||||||
|
math.randomseed(os.time())
|
||||||
|
__SleepingLinda:receive(.001, "__non_existing_variable")
|
||||||
|
end
|
||||||
|
repeat
|
||||||
|
wait()
|
||||||
|
until n()
|
||||||
|
end
|
||||||
|
local GLOBAL = {}
|
||||||
|
setmetatable(GLOBAL, {
|
||||||
|
__index = function(t, k)
|
||||||
|
return __GlobalLinda:get(k)
|
||||||
|
end,
|
||||||
|
__newindex = function(t, k, v)
|
||||||
|
__GlobalLinda:set(k, v)
|
||||||
|
end
|
||||||
|
})
|
||||||
|
return GLOBAL, THREAD
|
||||||
|
end
|
||||||
|
return {init = function(g,s)
|
||||||
|
return INIT(g,s)
|
||||||
|
end}
|
||||||
@@ -0,0 +1,182 @@
|
|||||||
|
--[[
|
||||||
|
MIT License
|
||||||
|
|
||||||
|
Copyright (c) 2020 Ryan Ward
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sub-license, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
||||||
|
]]
|
||||||
|
local multi, thread = require("multi").init()
|
||||||
|
local pad = require("multi.integration.loveManager.scratchpad")
|
||||||
|
GLOBAL = multi.integration.GLOBAL
|
||||||
|
THREAD = multi.integration.THREAD
|
||||||
|
function multi:newSystemThreadedQueue(name)
|
||||||
|
local c = {}
|
||||||
|
c.Name = name
|
||||||
|
local fRef = {"func",nil}
|
||||||
|
function c:init()
|
||||||
|
local q = {}
|
||||||
|
q.chan = love.thread.getChannel(self.Name)
|
||||||
|
function q:push(dat)
|
||||||
|
if type(dat) == "function" then
|
||||||
|
fRef[2] = THREAD.dump(dat)
|
||||||
|
self.chan:push(fRef)
|
||||||
|
return
|
||||||
|
else
|
||||||
|
self.chan:push(dat)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
function q:pop()
|
||||||
|
local dat = self.chan:pop()
|
||||||
|
if type(dat)=="table" and dat[1]=="func" then
|
||||||
|
return THREAD.loadDump(dat[2])
|
||||||
|
else
|
||||||
|
return dat
|
||||||
|
end
|
||||||
|
end
|
||||||
|
function q:peek()
|
||||||
|
local dat = self.chan:peek()
|
||||||
|
if type(dat)=="table" and dat[1]=="func" then
|
||||||
|
return THREAD.loadDump(dat[2])
|
||||||
|
else
|
||||||
|
return dat
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return q
|
||||||
|
end
|
||||||
|
THREAD.package(name,c)
|
||||||
|
return c
|
||||||
|
end
|
||||||
|
function multi:newSystemThreadedTable(name)
|
||||||
|
local c = {}
|
||||||
|
c.name = name
|
||||||
|
function c:init()
|
||||||
|
return THREAD.createTable(self.name)
|
||||||
|
end
|
||||||
|
THREAD.package(name,c)
|
||||||
|
return c
|
||||||
|
end
|
||||||
|
local jqc = 1
|
||||||
|
function multi:newSystemThreadedJobQueue(n)
|
||||||
|
local c = {}
|
||||||
|
c.cores = n or THREAD.getCores()
|
||||||
|
c.registerQueue = {}
|
||||||
|
c.funcs = THREAD.createStaticTable("__JobQueue_"..jqc.."_table")
|
||||||
|
c.queue = love.thread.getChannel("__JobQueue_"..jqc.."_queue")
|
||||||
|
c.queueReturn = love.thread.getChannel("__JobQueue_"..jqc.."_queueReturn")
|
||||||
|
c.queueAll = love.thread.getChannel("__JobQueue_"..jqc.."_queueAll")
|
||||||
|
c.id = 0
|
||||||
|
c.OnJobCompleted = multi:newConnection()
|
||||||
|
c._bytedata = love.data.newByteData(string.rep(status.BUSY,c.cores))
|
||||||
|
c.bytedata = pad:new(c._bytedata)
|
||||||
|
local allfunc = 0
|
||||||
|
function c:doToAll(func)
|
||||||
|
self.bytedata:write(string.rep(status.BUSY,c.cores)) -- set all variables to busy
|
||||||
|
local f = THREAD.dump(func)
|
||||||
|
for i = 1, self.cores do
|
||||||
|
self.queueAll:push({allfunc,f})
|
||||||
|
end
|
||||||
|
allfunc = allfunc + 1
|
||||||
|
end
|
||||||
|
function c:registerFunction(name,func)
|
||||||
|
if self.funcs[name] then
|
||||||
|
error("A function by the name "..name.." has already been registered!")
|
||||||
|
end
|
||||||
|
self.bytedata:write(string.rep(status.BUSY,c.cores)) -- set all variables to busy
|
||||||
|
self.funcs[name] = func
|
||||||
|
end
|
||||||
|
function c:pushJob(name,...)
|
||||||
|
self.id = self.id + 1
|
||||||
|
self.queue:push{name,self.id,...}
|
||||||
|
return self.id
|
||||||
|
end
|
||||||
|
multi:newThread("jobManager",function()
|
||||||
|
while true do
|
||||||
|
thread.yield()
|
||||||
|
local dat = c.queueReturn:pop()
|
||||||
|
if dat then
|
||||||
|
print(dat)
|
||||||
|
c.OnJobCompleted:Fire(unpack(dat))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
for i=1,c.cores do
|
||||||
|
multi:newSystemThread("JobQueue_"..jqc.."_worker_"..i,function(jqc)
|
||||||
|
local multi, thread = require("multi"):init()
|
||||||
|
local function atomic(channel)
|
||||||
|
return channel:pop()
|
||||||
|
end
|
||||||
|
require("love.timer")
|
||||||
|
local clock = os.clock
|
||||||
|
local pad = require("multi.integration.loveManager.scratchpad")
|
||||||
|
local status = require("multi.integration.loveManager.status")
|
||||||
|
local funcs = THREAD.createStaticTable("__JobQueue_"..jqc.."_table")
|
||||||
|
local queue = love.thread.getChannel("__JobQueue_"..jqc.."_queue")
|
||||||
|
local queueReturn = love.thread.getChannel("__JobQueue_"..jqc.."_queueReturn")
|
||||||
|
local lastProc = clock()
|
||||||
|
local queueAll = love.thread.getChannel("__JobQueue_"..jqc.."_queueAll")
|
||||||
|
local registry = {}
|
||||||
|
setmetatable(_G,{__index = funcs})
|
||||||
|
multi:newThread("startUp",function()
|
||||||
|
while true do
|
||||||
|
thread.yield()
|
||||||
|
local all = queueAll:peek()
|
||||||
|
if all and not registry[all[1]] then
|
||||||
|
lastProc = os.clock()
|
||||||
|
THREAD.loadDump(queueAll:pop()[2])()
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
multi:newThread("runner",function()
|
||||||
|
thread.sleep(.1)
|
||||||
|
while true do
|
||||||
|
thread.yield()
|
||||||
|
local all = queueAll:peek()
|
||||||
|
if all and not registry[all[1]] then
|
||||||
|
lastProc = os.clock()
|
||||||
|
THREAD.loadDump(queueAll:pop()[2])()
|
||||||
|
end
|
||||||
|
local dat = queue:performAtomic(atomic)
|
||||||
|
if dat then
|
||||||
|
lastProc = os.clock()
|
||||||
|
local name = table.remove(dat,1)
|
||||||
|
local id = table.remove(dat,1)
|
||||||
|
local tab = {funcs[name](unpack(dat))}
|
||||||
|
table.insert(tab,1,id)
|
||||||
|
queueReturn:push(tab)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end):OnError(function(...)
|
||||||
|
error(...)
|
||||||
|
end)
|
||||||
|
multi:newThread("Idler",function()
|
||||||
|
while true do
|
||||||
|
thread.yield()
|
||||||
|
if clock()-lastProc> 2 then
|
||||||
|
THREAD.sleep(.05)
|
||||||
|
else
|
||||||
|
THREAD.sleep(.001)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
multi:mainloop()
|
||||||
|
end,jqc)
|
||||||
|
end
|
||||||
|
jqc = jqc + 1
|
||||||
|
return c
|
||||||
|
end
|
||||||
@@ -0,0 +1,62 @@
|
|||||||
|
--[[
|
||||||
|
MIT License
|
||||||
|
|
||||||
|
Copyright (c) 2020 Ryan Ward
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sub-license, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
||||||
|
]]
|
||||||
|
if ISTHREAD then
|
||||||
|
error("You cannot require the loveManager from within a thread!")
|
||||||
|
end
|
||||||
|
local ThreadFileData = [[
|
||||||
|
ISTHREAD = true
|
||||||
|
THREAD = require("multi.integration.loveManager.threads") -- order is important!
|
||||||
|
STATUS = require("multi.integration.loveManager.status")
|
||||||
|
__IMPORTS = {...}
|
||||||
|
__FUNC__=table.remove(__IMPORTS,1)
|
||||||
|
__THREADID__=table.remove(__IMPORTS,1)
|
||||||
|
__THREADNAME__=table.remove(__IMPORTS,1)
|
||||||
|
GLOBAL = THREAD.getGlobal()
|
||||||
|
multi, thread = require("multi").init()
|
||||||
|
THREAD.loadDump(__FUNC__)(unpack(__IMPORTS))]]
|
||||||
|
local multi, thread = require("multi.compat.love2d"):init()
|
||||||
|
local THREAD = {}
|
||||||
|
__THREADID__ = 0
|
||||||
|
__THREADNAME__ = "MainThread"
|
||||||
|
multi.integration={}
|
||||||
|
multi.integration.love2d={}
|
||||||
|
local THREAD = require("multi.integration.loveManager.threads")
|
||||||
|
local GLOBAL = THREAD.getGlobal()
|
||||||
|
local THREAD_ID = 1
|
||||||
|
local OBJECT_ID = 0
|
||||||
|
function multi:newSystemThread(name,func,...)
|
||||||
|
local c = {}
|
||||||
|
c.name = name
|
||||||
|
c.ID=THREAD_ID
|
||||||
|
c.thread=love.thread.newThread(ThreadFileData)
|
||||||
|
c.thread:start(THREAD.dump(func),c.ID,c.name,...)
|
||||||
|
GLOBAL["__THREAD_"..c.ID] = {ID=c.ID,Name=c.name,Thread=c.thread}
|
||||||
|
GLOBAL["__THREAD_COUNT"] = THREAD_ID
|
||||||
|
THREAD_ID=THREAD_ID+1
|
||||||
|
end
|
||||||
|
multi.integration.GLOBAL = GLOBAL
|
||||||
|
multi.integration.THREAD = THREAD
|
||||||
|
return {init=function()
|
||||||
|
return GLOBAL,THREAD
|
||||||
|
end}
|
||||||
@@ -0,0 +1,221 @@
|
|||||||
|
--[[
|
||||||
|
MIT License
|
||||||
|
|
||||||
|
Copyright (c) 2020 Ryan Ward
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sub-license, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
||||||
|
]]
|
||||||
|
require("love.timer")
|
||||||
|
require("love.system")
|
||||||
|
require("love.data")
|
||||||
|
local socket = require("socket")
|
||||||
|
local multi, thread = require("multi").init()
|
||||||
|
local threads = {}
|
||||||
|
function threads.loadDump(d)
|
||||||
|
return loadstring(d:getString())
|
||||||
|
end
|
||||||
|
function threads.dump(func)
|
||||||
|
return love.data.newByteData(string.dump(func))
|
||||||
|
end
|
||||||
|
local fRef = {"func",nil}
|
||||||
|
local function manage(channel, value)
|
||||||
|
channel:clear()
|
||||||
|
if type(value) == "function" then
|
||||||
|
fRef[2] = THREAD.dump(value)
|
||||||
|
channel:push(fRef)
|
||||||
|
return
|
||||||
|
else
|
||||||
|
channel:push(value)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
local function RandomVariable(length)
|
||||||
|
local res = {}
|
||||||
|
math.randomseed(socket.gettime()*10000)
|
||||||
|
for i = 1, length do
|
||||||
|
res[#res+1] = string.char(math.random(97, 122))
|
||||||
|
end
|
||||||
|
return table.concat(res)
|
||||||
|
end
|
||||||
|
local GNAME = "__GLOBAL_"
|
||||||
|
local proxy = {}
|
||||||
|
function threads.set(name,val)
|
||||||
|
if not proxy[name] then proxy[name] = love.thread.getChannel(GNAME..name) end
|
||||||
|
proxy[name]:performAtomic(manage, val)
|
||||||
|
end
|
||||||
|
function threads.get(name)
|
||||||
|
if not proxy[name] then proxy[name] = love.thread.getChannel(GNAME..name) end
|
||||||
|
local dat = proxy[name]:peek()
|
||||||
|
if type(dat)=="table" and dat[1]=="func" then
|
||||||
|
return THREAD.loadDump(dat[2])
|
||||||
|
else
|
||||||
|
return dat
|
||||||
|
end
|
||||||
|
end
|
||||||
|
function threads.waitFor(name)
|
||||||
|
if thread.isThread() then
|
||||||
|
return thread.hold(function()
|
||||||
|
return threads.get(name)
|
||||||
|
end)
|
||||||
|
end
|
||||||
|
while threads.get(name)==nil do
|
||||||
|
love.timer.sleep(.001)
|
||||||
|
end
|
||||||
|
local dat = threads.get(name)
|
||||||
|
if type(dat) == "table" and dat.init then
|
||||||
|
dat.init = threads.loadDump(dat.init)
|
||||||
|
end
|
||||||
|
return dat
|
||||||
|
end
|
||||||
|
function threads.package(name,val)
|
||||||
|
local init = val.init
|
||||||
|
val.init=threads.dump(val.init)
|
||||||
|
GLOBAL[name]=val
|
||||||
|
val.init=init
|
||||||
|
end
|
||||||
|
function threads.getCores()
|
||||||
|
return love.system.getProcessorCount()
|
||||||
|
end
|
||||||
|
function threads.kill()
|
||||||
|
error("Thread Killed!")
|
||||||
|
end
|
||||||
|
function threads.getThreads()
|
||||||
|
local t = {}
|
||||||
|
for i=1,GLOBAL["__THREAD_COUNT"] do
|
||||||
|
t[#t+1]=GLOBAL["__THREAD_"..i]
|
||||||
|
end
|
||||||
|
return t
|
||||||
|
end
|
||||||
|
function threads.getThread(n)
|
||||||
|
return GLOBAL["__THREAD_"..n]
|
||||||
|
end
|
||||||
|
function threads.getName()
|
||||||
|
return __THREADNAME__
|
||||||
|
end
|
||||||
|
function threads.getID()
|
||||||
|
return __THREADID__
|
||||||
|
end
|
||||||
|
function threads.sleep(n)
|
||||||
|
love.timer.sleep(n)
|
||||||
|
end
|
||||||
|
function threads.getGlobal()
|
||||||
|
return setmetatable({},
|
||||||
|
{
|
||||||
|
__index = function(t, k)
|
||||||
|
return THREAD.get(k)
|
||||||
|
end,
|
||||||
|
__newindex = function(t, k, v)
|
||||||
|
THREAD.set(k,v)
|
||||||
|
end
|
||||||
|
}
|
||||||
|
)
|
||||||
|
end
|
||||||
|
function threads.createTable(n)
|
||||||
|
local _proxy = {}
|
||||||
|
local function set(name,val)
|
||||||
|
if not _proxy[name] then _proxy[name] = love.thread.getChannel(n..name) end
|
||||||
|
_proxy[name]:performAtomic(manage, val)
|
||||||
|
end
|
||||||
|
local function get(name)
|
||||||
|
if not _proxy[name] then _proxy[name] = love.thread.getChannel(n..name) end
|
||||||
|
local dat = _proxy[name]:peek()
|
||||||
|
if type(dat)=="table" and dat[1]=="func" then
|
||||||
|
return THREAD.loadDump(dat[2])
|
||||||
|
else
|
||||||
|
return dat
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return setmetatable({},
|
||||||
|
{
|
||||||
|
__index = function(t, k)
|
||||||
|
return get(k)
|
||||||
|
end,
|
||||||
|
__newindex = function(t, k, v)
|
||||||
|
set(k,v)
|
||||||
|
end
|
||||||
|
}
|
||||||
|
)
|
||||||
|
end
|
||||||
|
function threads.getConsole()
|
||||||
|
local c = {}
|
||||||
|
c.queue = love.thread.getChannel("__CONSOLE__")
|
||||||
|
function c.print(...)
|
||||||
|
c.queue:push{...}
|
||||||
|
end
|
||||||
|
function c.error(err)
|
||||||
|
c.queue:push{"ERROR in <"..__THREADNAME__..">: "..err,__THREADID__}
|
||||||
|
error(err)
|
||||||
|
end
|
||||||
|
return c
|
||||||
|
end
|
||||||
|
if not ISTHREAD then
|
||||||
|
local clock = os.clock
|
||||||
|
local lastproc = clock()
|
||||||
|
local queue = love.thread.getChannel("__CONSOLE__")
|
||||||
|
multi:newThread("consoleManager",function()
|
||||||
|
while true do
|
||||||
|
thread.yield()
|
||||||
|
dat = queue:pop()
|
||||||
|
if dat then
|
||||||
|
lastproc = clock()
|
||||||
|
print(unpack(dat))
|
||||||
|
end
|
||||||
|
if clock()-lastproc>2 then
|
||||||
|
thread.sleep(.1)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
end
|
||||||
|
function threads.createStaticTable(n)
|
||||||
|
local __proxy = {}
|
||||||
|
local function set(name,val)
|
||||||
|
if __proxy[name] then return end
|
||||||
|
local chan = love.thread.getChannel(n..name)
|
||||||
|
if chan:getCount()>0 then return end
|
||||||
|
chan:performAtomic(manage, val)
|
||||||
|
__proxy[name] = val
|
||||||
|
end
|
||||||
|
local function get(name)
|
||||||
|
if __proxy[name] then return __proxy[name] end
|
||||||
|
local dat = love.thread.getChannel(n..name):peek()
|
||||||
|
if type(dat)=="table" and dat[1]=="func" then
|
||||||
|
__proxy[name] = THREAD.loadDump(dat[2])
|
||||||
|
return __proxy[name]
|
||||||
|
else
|
||||||
|
__proxy[name] = dat
|
||||||
|
return __proxy[name]
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return setmetatable({},
|
||||||
|
{
|
||||||
|
__index = function(t, k)
|
||||||
|
return get(k)
|
||||||
|
end,
|
||||||
|
__newindex = function(t, k, v)
|
||||||
|
set(k,v)
|
||||||
|
end
|
||||||
|
}
|
||||||
|
)
|
||||||
|
end
|
||||||
|
function threads.hold(n)
|
||||||
|
local dat
|
||||||
|
while not(dat) do
|
||||||
|
dat = n()
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return threads
|
||||||
@@ -0,0 +1,137 @@
|
|||||||
|
--[[
|
||||||
|
MIT License
|
||||||
|
|
||||||
|
Copyright (c) 2020 Ryan Ward
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sub-license, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
||||||
|
]]
|
||||||
|
|
||||||
|
-- This module probably will not be maintained any longer!
|
||||||
|
package.path = "?/init.lua;?.lua;" .. package.path
|
||||||
|
local function _INIT(luvitThread, timer)
|
||||||
|
-- lots of this stuff should be able to stay the same
|
||||||
|
function os.getOS()
|
||||||
|
if package.config:sub(1, 1) == "\\" then
|
||||||
|
return "windows"
|
||||||
|
else
|
||||||
|
return "unix"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
-- Step 1 get setup threads on luvit... Sigh how do i even...
|
||||||
|
local multi, thread = require("multi").init()
|
||||||
|
isMainThread = true
|
||||||
|
function multi:canSystemThread()
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
function multi:getPlatform()
|
||||||
|
return "luvit"
|
||||||
|
end
|
||||||
|
local multi = multi
|
||||||
|
-- Step 2 set up the Global table... is this possible?
|
||||||
|
local GLOBAL = {}
|
||||||
|
setmetatable(
|
||||||
|
GLOBAL,
|
||||||
|
{
|
||||||
|
__index = function(t, k)
|
||||||
|
--print("No Global table when using luvit integration!")
|
||||||
|
return nil
|
||||||
|
end,
|
||||||
|
__newindex = function(t, k, v)
|
||||||
|
--print("No Global table when using luvit integration!")
|
||||||
|
end
|
||||||
|
}
|
||||||
|
)
|
||||||
|
local THREAD = {}
|
||||||
|
function THREAD.set(name, val)
|
||||||
|
--print("No Global table when using luvit integration!")
|
||||||
|
end
|
||||||
|
function THREAD.get(name)
|
||||||
|
--print("No Global table when using luvit integration!")
|
||||||
|
end
|
||||||
|
local function randomString(n)
|
||||||
|
local str = ""
|
||||||
|
local strings = {"a","b","c","d","e","f","g","h","i","j","k","l","m","n","o","p","q","r","s","t","u","v","w","x","y","z","1","2","3","4","5","6","7","8","9","0","A","B","C","D","E","F","G","H","I","J","K","L","M","N","O","P","Q","R","S","T","U","V","W","X","Y","Z"}
|
||||||
|
for i = 1, n do
|
||||||
|
str = str .. "" .. strings[math.random(1, #strings)]
|
||||||
|
end
|
||||||
|
return str
|
||||||
|
end
|
||||||
|
function THREAD.waitFor(name)
|
||||||
|
--print("No Global table when using luvit integration!")
|
||||||
|
end
|
||||||
|
function THREAD.testFor(name, val, sym)
|
||||||
|
--print("No Global table when using luvit integration!")
|
||||||
|
end
|
||||||
|
function THREAD.getCores()
|
||||||
|
return THREAD.__CORES
|
||||||
|
end
|
||||||
|
if os.getOS() == "windows" then
|
||||||
|
THREAD.__CORES = tonumber(os.getenv("NUMBER_OF_PROCESSORS"))
|
||||||
|
else
|
||||||
|
THREAD.__CORES = tonumber(io.popen("nproc --all"):read("*n"))
|
||||||
|
end
|
||||||
|
function THREAD.kill() -- trigger the thread destruction
|
||||||
|
error("Thread was Killed!")
|
||||||
|
end
|
||||||
|
-- hmmm if im cleaver I can get this to work... but since data passing isn't going to be a thing its probably not important
|
||||||
|
function THREAD.sleep(n)
|
||||||
|
--print("No Global table when using luvit integration!")
|
||||||
|
end
|
||||||
|
function THREAD.hold(n)
|
||||||
|
--print("No Global table when using luvit integration!")
|
||||||
|
end
|
||||||
|
-- Step 5 Basic Threads!
|
||||||
|
local function entry(path, name, func, ...)
|
||||||
|
local timer = require "timer"
|
||||||
|
local luvitThread = require "thread"
|
||||||
|
package.path = path
|
||||||
|
loadstring(func)(...)
|
||||||
|
end
|
||||||
|
function multi:newSystemThread(name, func, ...)
|
||||||
|
local c = {}
|
||||||
|
local __self = c
|
||||||
|
c.name = name
|
||||||
|
c.Type = "sthread"
|
||||||
|
c.thread = {}
|
||||||
|
c.func = string.dump(func)
|
||||||
|
function c:kill()
|
||||||
|
-- print("No Global table when using luvit integration!")
|
||||||
|
end
|
||||||
|
luvitThread.start(entry, package.path, name, c.func, ...)
|
||||||
|
return c
|
||||||
|
end
|
||||||
|
multi.print("Integrated Luvit!")
|
||||||
|
multi.integration = {} -- for module creators
|
||||||
|
multi.integration.GLOBAL = GLOBAL
|
||||||
|
multi.integration.THREAD = THREAD
|
||||||
|
require("multi.integration.shared")
|
||||||
|
-- Start the main mainloop... This allows you to process your multi objects, but the engine on the main thread will be limited to .001 or 1 millisecond sigh...
|
||||||
|
local interval =
|
||||||
|
timer.setInterval(
|
||||||
|
1,
|
||||||
|
function()
|
||||||
|
multi:uManager()
|
||||||
|
end
|
||||||
|
)
|
||||||
|
return multi
|
||||||
|
end
|
||||||
|
return {init = function(threadHandle, timerHandle)
|
||||||
|
local multi = _INIT(threadHandle, timerHandle)
|
||||||
|
return GLOBAL, THREAD
|
||||||
|
end}
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
_G["__CHANNEL__"] = {}
|
||||||
|
local channel = {}
|
||||||
|
channel.__index = channel
|
||||||
|
|
||||||
|
-- Creates/Gets a channel of name
|
||||||
|
function channel:newChannel(name)
|
||||||
|
local chan = _G["__CHANNEL__"]
|
||||||
|
if chan then
|
||||||
|
|
||||||
|
end
|
||||||
|
end
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
local multi, thread = require("multi"):init()
|
||||||
|
local cmd = require("multi.integration.networkManager.cmds")
|
||||||
|
local node = require("multi.integration.networkManager.node")
|
||||||
|
local net = require("net")
|
||||||
|
local bin = require("bin")
|
||||||
|
local child = {}
|
||||||
|
child.__index = child
|
||||||
|
function multi:newChildNode(cd)
|
||||||
|
local c = {}
|
||||||
|
setmetatable(c,child)
|
||||||
|
local name
|
||||||
|
if cd then
|
||||||
|
if cd.name then
|
||||||
|
name = cd.name
|
||||||
|
end
|
||||||
|
c.node = node:new(cd.nodePort or cmd.defaultPort,nil,name)
|
||||||
|
if cd.managerHost then
|
||||||
|
cd.managerPort = cd.managerPort or cmd.defaultManagerPort
|
||||||
|
c.node:registerWithManager(cd.managerHost,cd.managerPort)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return c
|
||||||
|
end
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user