File size: 4,558 Bytes
5b33b3c
 
 
 
 
 
 
 
 
 
 
 
 
2898fad
 
 
 
 
 
 
 
5b33b3c
 
2898fad
 
5b33b3c
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2898fad
 
 
 
 
 
 
 
 
 
 
 
 
 
5b33b3c
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
import os
import subprocess
import time
import psutil
import tempfile
import shutil

class CppCompiler:
    def __init__(self, workdir: str = None):
        self.workdir = workdir or tempfile.mkdtemp(prefix="algo_finder_")
        os.makedirs(self.workdir, exist_ok=True)

    def compile(self, filename: str, source_code: str) -> dict:
        if shutil.which("g++") is None:
            return {
                "compiled": False,
                "binary_path": None,
                "compile_error": "g++ not found. On Hugging Face Spaces add 'g++' to packages.txt; locally install a C++ toolchain (e.g. 'apt install g++').",
                "compile_stderr": "",
            }

        source_path = os.path.join(self.workdir, f"{filename}.cpp")
        binary_path = os.path.join(self.workdir, filename)
        if os.name == "nt" and not binary_path.lower().endswith(".exe"):
            binary_path = binary_path + ".exe"

        with open(source_path, "w", encoding="utf-8") as f:
            f.write(source_code)

        compile_cmd = ["g++", "-std=c++17", "-O2", source_path, "-o", binary_path]
        try:
            compile_result = subprocess.run(
                compile_cmd,
                capture_output=True,
                text=True,
                timeout=60,
            )
        except subprocess.TimeoutExpired:
            return {
                "compiled": False,
                "binary_path": None,
                "compile_error": "Compilation timed out (60s limit)",
                "compile_stderr": "",
            }
        except FileNotFoundError as e:
            return {
                "compiled": False,
                "binary_path": None,
                "compile_error": f"g++ executable not found: {e}. Install g++ (packages.txt on Spaces).",
                "compile_stderr": "",
            }
        except OSError as e:
            return {
                "compiled": False,
                "binary_path": None,
                "compile_error": f"Compilation failed to start: {e}",
                "compile_stderr": "",
            }

        if compile_result.returncode != 0:
            return {
                "compiled": False,
                "binary_path": None,
                "compile_error": compile_result.stderr.strip(),
                "compile_stderr": compile_result.stderr.strip(),
            }

        return {
            "compiled": True,
            "binary_path": binary_path,
            "compile_error": None,
            "compile_stderr": None,
        }

    def run(self, binary_path: str, timeout: int = 30) -> dict:
        if not binary_path or not os.path.exists(binary_path):
            return {
                "ran": False,
                "returncode": None,
                "stdout": "",
                "stderr": "Binary not found",
                "execution_time_s": None,
                "memory_kb": None,
            }

        process = psutil.Process()
        start_time = time.perf_counter()
        try:
            run_result = subprocess.run(
                [binary_path],
                capture_output=True,
                text=True,
                timeout=timeout,
            )
            end_time = time.perf_counter()
            execution_time = end_time - start_time

            try:
                mem_info = process.memory_info()
                memory_kb = mem_info.rss / 1024
            except Exception:
                memory_kb = None

            return {
                "ran": True,
                "returncode": run_result.returncode,
                "stdout": run_result.stdout.strip(),
                "stderr": run_result.stderr.strip(),
                "execution_time_s": round(execution_time, 6),
                "memory_kb": round(memory_kb, 2) if memory_kb is not None else None,
            }
        except subprocess.TimeoutExpired:
            return {
                "ran": False,
                "returncode": None,
                "stdout": "",
                "stderr": f"Execution timed out ({timeout}s limit)",
                "execution_time_s": timeout,
                "memory_kb": None,
            }
        except Exception as e:
            return {
                "ran": False,
                "returncode": None,
                "stdout": "",
                "stderr": str(e),
                "execution_time_s": None,
                "memory_kb": None,
            }

    def cleanup(self):
        if os.path.exists(self.workdir):
            shutil.rmtree(self.workdir, ignore_errors=True)