Skip to content

Commit

Permalink
Merge branch 'master' of https://github.com/vijos/jd4 into vijos-master
Browse files Browse the repository at this point in the history
  • Loading branch information
twd2 committed Mar 12, 2017
2 parents 5428faa + 8c0b0e5 commit 07b546f
Show file tree
Hide file tree
Showing 6 changed files with 165 additions and 27 deletions.
Empty file added jd4/__init__.py
Empty file.
46 changes: 46 additions & 0 deletions jd4/_compare.pyx
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
cdef class StreamReader:
cdef stream
cdef bytes buffer
cdef const char* begin
cdef const char* end

def __init__(self, stream):
self.stream = stream
self.begin = NULL
self.end = NULL

cdef int read(self):
if self.begin == self.end:
self.buffer = self.stream.read(32768)
if not self.buffer:
return -1
self.begin = self.buffer
self.end = self.begin + len(self.buffer)
cdef int result = self.begin[0]
self.begin += 1
return result

def compare_stream(fa, fb):
cdef StreamReader ra = StreamReader(fa)
cdef StreamReader rb = StreamReader(fb)
cdef int both_spaced = 1
cdef int a
cdef int b

while True:
a = ra.read()
b = rb.read()
while a != b:
if (a == 13 or
(both_spaced and (a == 32 or a == 9)) or
((b == -1 or b == 10) and (a == 32 or a == 10))):
a = ra.read()
elif (b == 13 or
(both_spaced and (b == 32 or b == 9)) or
((a == -1 or a == 10) and (b == 32 or b == 10))):
b = rb.read()
else:
return False
if a == -1:
return True
both_spaced = (a == 32 or a == 9)
38 changes: 13 additions & 25 deletions jd4/case.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,16 @@
import pyximport; pyximport.install()

import csv
from asyncio import gather, get_event_loop, sleep, wait_for, Event, TimeoutError
from functools import partial
from io import TextIOWrapper
from itertools import islice, zip_longest
from io import BytesIO, TextIOWrapper
from itertools import islice
from os import cpu_count, mkfifo, path
from random import randint
from shutil import copyfileobj
from zipfile import ZipFile

from jd4._compare import compare_stream
from jd4.cgroup import CGroup, try_init_cgroup
from jd4.compile import Compiler
from jd4.status import STATUS_ACCEPTED, STATUS_WRONG_ANSWER, STATUS_RUNTIME_ERROR, \
Expand All @@ -22,22 +25,6 @@
PROCESS_LIMIT = 32
DEFAULT_MEM_KB = 524288

def chunk_and_strip_lines(f):
prev = b''
cur = f.readline(CHUNK_SIZE).lstrip()
while cur:
if prev and prev[-1] in b'\r\n':
prev, cur = prev.rstrip(), cur.lstrip()
if prev: yield prev
prev, cur = cur, f.readline(CHUNK_SIZE)
if prev: prev = prev.rstrip()
if prev: yield prev

def compare_file(fa, fb):
a = chunk_and_strip_lines(fa)
b = chunk_and_strip_lines(fb)
return all(x == y for x, y in zip_longest(a, b))

def get_idle():
return float(read_text_file('/proc/uptime').split()[1])

Expand Down Expand Up @@ -123,10 +110,12 @@ def __init__(self, open_input, open_output, time_sec, mem_kb, score):
self.open_output = open_output

def do_stdin(self, stdin_file):
copyfileobj(self.open_input(), open(stdin_file, 'wb'), CHUNK_SIZE)
with self.open_input() as src, open(stdin_file, 'wb') as dst:
copyfileobj(src, dst, CHUNK_SIZE)

def do_stdout(self, stdout_file):
return compare_file(self.open_output(), open(stdout_file, 'rb'))
with self.open_output() as ans, open(stdout_file, 'rb') as out:
return compare_stream(ans, out)

class APlusBCase(CaseBase):
def __init__(self, a, b):
Expand All @@ -139,11 +128,8 @@ def do_stdin(self, stdin_file):
file.write('{} {}\n'.format(self.a, self.b))

def do_stdout(self, stdout_file):
with open(stdout_file) as file:
try:
return int(file.read()) == self.a + self.b
except (UnicodeDecodeError, ValueError):
return False
with open(stdout_file, 'rb') as file:
return compare_stream(BytesIO(str(self.a + self.b).encode()), file)

def read_legacy_cases(file):
zip_file = ZipFile(file)
Expand Down Expand Up @@ -174,6 +160,8 @@ async def main():
printf("%d\\n", a + b);
}""")
package, _ = await gcc.build(sandbox)
for case in read_legacy_cases('examples/1000.zip'):
logger.info(await case.judge(sandbox, package))
for i in range(10):
logger.info(await APlusBCase(randint(0, 32767),
randint(0, 32767)).judge(sandbox, package))
Expand Down
103 changes: 103 additions & 0 deletions jd4/compare_test.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
import pyximport; pyximport.install()

from io import BytesIO
from unittest import main, TestCase

from jd4._compare import compare_stream

def compare(a, b):
return compare_stream(BytesIO(a), BytesIO(b))

class CompareTest(TestCase):
def test_small(self):
self.assertTrue(compare(b'', b''))
self.assertTrue(compare(b'a', b'a'))
self.assertFalse(compare(b'a', b'b'))
self.assertTrue(compare(b'bar', b'bar'))
self.assertFalse(compare(b'bar', b'baz'))
self.assertFalse(compare(b'bar', b'baz'))

def test_a_plus_b(self):
answer = b'1 2\r\n'
self.assertTrue(compare(answer, b'1 2'))
self.assertTrue(compare(answer, b'1 2\n'))
self.assertTrue(compare(answer, b'1 2\r'))
self.assertTrue(compare(answer, b'1 2\r\n'))
self.assertTrue(compare(answer, b'1 2 '))
self.assertTrue(compare(answer, b'1 2 \n'))
self.assertTrue(compare(answer, b'1 2 \r'))
self.assertTrue(compare(answer, b'1 2 \r\n'))
self.assertTrue(compare(answer, b'1 2'))
self.assertTrue(compare(answer, b'1 2\n'))
self.assertTrue(compare(answer, b'1 2\r'))
self.assertTrue(compare(answer, b'1 2\r\n'))
self.assertTrue(compare(answer, b'1 2 '))
self.assertTrue(compare(answer, b'1 2 \n'))
self.assertTrue(compare(answer, b'1 2 \r'))
self.assertTrue(compare(answer, b'1 2 \r\n'))
self.assertTrue(compare(answer, b' 1 2'))
self.assertTrue(compare(answer, b' 1 2\n'))
self.assertTrue(compare(answer, b' 1 2\r'))
self.assertTrue(compare(answer, b' 1 2\r\n'))
self.assertTrue(compare(answer, b' 1 2 '))
self.assertTrue(compare(answer, b' 1 2 \n'))
self.assertTrue(compare(answer, b' 1 2 \r'))
self.assertTrue(compare(answer, b' 1 2 \r\n'))
self.assertFalse(compare(answer, b'1 1'))
self.assertFalse(compare(answer, b'1 1\n'))
self.assertFalse(compare(answer, b'1 1\r'))
self.assertFalse(compare(answer, b'1 1\r\n'))
self.assertFalse(compare(answer, b'1 1 '))
self.assertFalse(compare(answer, b'1 1 \n'))
self.assertFalse(compare(answer, b'1 1 \r'))
self.assertFalse(compare(answer, b'1 1 \r\n'))
self.assertFalse(compare(answer, b' 1 1'))
self.assertFalse(compare(answer, b' 1 1\n'))
self.assertFalse(compare(answer, b' 1 1\r'))
self.assertFalse(compare(answer, b' 1 1\r\n'))
self.assertFalse(compare(answer, b' 1 1 '))
self.assertFalse(compare(answer, b' 1 1 \n'))
self.assertFalse(compare(answer, b' 1 1 \r'))
self.assertFalse(compare(answer, b' 1 1 \r\n'))
self.assertFalse(compare(answer, b'2 2'))
self.assertFalse(compare(answer, b'2 2\n'))
self.assertFalse(compare(answer, b'2 2\r'))
self.assertFalse(compare(answer, b'2 2\r\n'))
self.assertFalse(compare(answer, b'2 2 '))
self.assertFalse(compare(answer, b'2 2 \n'))
self.assertFalse(compare(answer, b'2 2 \r'))
self.assertFalse(compare(answer, b'2 2 \r\n'))
self.assertFalse(compare(answer, b' 2 2'))
self.assertFalse(compare(answer, b' 2 2\n'))
self.assertFalse(compare(answer, b' 2 2\r'))
self.assertFalse(compare(answer, b' 2 2\r\n'))
self.assertFalse(compare(answer, b' 2 2 '))
self.assertFalse(compare(answer, b' 2 2 \n'))
self.assertFalse(compare(answer, b' 2 2 \r'))
self.assertFalse(compare(answer, b' 2 2 \r\n'))
self.assertFalse(compare(answer, b'2 1'))
self.assertFalse(compare(answer, b'2 1\n'))
self.assertFalse(compare(answer, b'2 1\r'))
self.assertFalse(compare(answer, b'2 1\r\n'))
self.assertFalse(compare(answer, b'2 1 '))
self.assertFalse(compare(answer, b'2 1 \n'))
self.assertFalse(compare(answer, b'2 1 \r'))
self.assertFalse(compare(answer, b'2 1 \r\n'))
self.assertFalse(compare(answer, b' 2 1'))
self.assertFalse(compare(answer, b' 2 1\n'))
self.assertFalse(compare(answer, b' 2 1\r'))
self.assertFalse(compare(answer, b' 2 1\r\n'))
self.assertFalse(compare(answer, b' 2 1 '))
self.assertFalse(compare(answer, b' 2 1 \n'))
self.assertFalse(compare(answer, b' 2 1 \r'))
self.assertFalse(compare(answer, b' 2 1 \r\n'))
self.assertFalse(compare(answer, b'12'))

def test_large(self):
self.assertTrue(compare(b'a' * 1048576, b'a' * 1048576))
self.assertFalse(compare(b'a' * 1048576, b'a' * 1048575 + b'b'))
self.assertTrue(compare(b'a' * 1048576 + b' ' + b'b' * 1048576 + b'\r\n',
b'a' * 1048576 + b' ' * 1048576 + b'b' * 1048576))

if __name__ == '__main__':
main()
2 changes: 1 addition & 1 deletion jd4/daemon.py
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@ async def judge(self, cases_file, package):
'time_ms': time_usage_ns // 1000000,
'memory_kb': memory_usage_bytes // 1024,
'judge_text': stderr.decode(encoding='utf-8', errors='replace')},
progress=(index + 1) / len(cases) * 100)
progress=(index + 1) * 100 // len(cases))
logger.debug('Case %d: %d, %g, %g, %g, %s',
index, status, score, time_usage_ns / 1000000, memory_usage_bytes / 1024, stderr)
total_status = max(total_status, status)
Expand Down
3 changes: 2 additions & 1 deletion requirements.txt
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
aiohttp
appdirs
butter
cloudpickle
colorlog
appdirs
cython
ruamel.yaml

0 comments on commit 07b546f

Please sign in to comment.