utils.hpp
View source code here on GitHub!
Includes
<windows.h>
(if compiled for Windows)<libgen.h>
(if not compiled for Windows)<unistd.h>
(if not compiled for Windows)
-
std::string get_data_file(const std::string name)
Return a character array containing the whole contents of a file found in _data.
-
std::string get_parent_directory(const std::string &path, uint32_t levels)
-
struct Answer
The Answer object represents the solution to a Project Euler problems. It can hold different types of values and an identifier.
-
union value
-
uint8_t int8
Represents an 8-bit signed integer.
-
uint16_t int16
Represents a 16-bit signed integer.
-
uint32_t int32
Represents a 32-bit signed integer.
-
uint64_t int64
Represents a 64-bit signed integer.
-
uint8_t uint8
Represents an 8-bit unsigned integer.
-
uint16_t uint16
Represents a 16-bit unsigned integer.
-
uint32_t uint32
Represents a 32-bit unsigned integer.
-
uint64_t uint64
Represents a 64-bit unsigned integer.
-
char *string
Represents a c-string value.
-
uint8_t int8
-
uint16_t id
Represents the problem ID.
-
AnswerType type
Specifies the type of value stored in the
value
union. It is of typeAnswerType
.
-
union value
-
enum struct AnswerType
The AnswerType enum defines various types of values that can be stored in an Answer.
-
enumerator ERROR
Represents an error state.
-
enumerator INT8
Represents an 8-bit signed integer.
-
enumerator INT16
Represents a 16-bit signed integer.
-
enumerator INT32
Represents a 32-bit signed integer.
-
enumerator INT64
Represents a 64-bit signed integer.
-
enumerator UINT8
Represents an 8-bit unsigned integer.
-
enumerator UINT16
Represents a 16-bit unsigned integer.
-
enumerator UINT32
Represents a 32-bit unsigned integer.
-
enumerator UINT64
Represents a 64-bit unsigned integer.
-
enumerator STR
Represents a c-string value.
-
enumerator ERROR
1#pragma once
2
3#include <cerrno>
4#include <iostream>
5#include <stdexcept>
6#include <stdint.h>
7#include <inttypes.h>
8#include <cstring>
9#include <string>
10#include <sstream>
11#include <fstream>
12#include "macros.hpp"
13
14#ifdef _WIN32
15#include <windows.h>
16#define PATH_SEPARATOR "\\"
17#else
18#include <libgen.h>
19#include <unistd.h>
20#define PATH_SEPARATOR "/"
21#endif
22
23#ifndef MAX_PATH
24#define MAX_PATH 4096
25#endif
26
27std::string get_parent_directory(const std::string &path, const uint32_t levels) {
28 std::string dir = path;
29 for (uint32_t i = 0; i < levels; ++i) {
30 size_t pos = dir.find_last_of(PATH_SEPARATOR);
31 if (pos != std::string::npos)
32 dir.erase(pos);
33 else
34 break;
35 }
36 return dir;
37}
38
39std::string get_data_file(const std::string &name) {
40 char absolute_path[MAX_PATH];
41 std::ostringstream oss;
42#ifdef _WIN32
43 if (!_fullpath(absolute_path, __FILE__, sizeof(absolute_path))) {
44 oss << "_fullpath failed with error code " << GetLastError();
45 throw std::runtime_error(oss.str());
46 }
47#else
48 if (!realpath(__FILE__, absolute_path)) {
49 oss << "realpath failed with error code " << errno;
50 throw std::runtime_error(oss.str());
51 }
52#endif
53
54 std::string file_path = get_parent_directory(std::string(absolute_path), 4) + PATH_SEPARATOR "_data" PATH_SEPARATOR + name;
55 std::ifstream file(file_path.c_str(), std::ios::in | std::ios::binary);
56 if (!file) {
57 oss << "Failed to open file: " << file_path << " with error code " << errno;
58 throw std::runtime_error(oss.str());
59 }
60
61 std::ostringstream content_stream;
62 content_stream << file.rdbuf();
63 if (!file) {
64 oss << "Error reading file: " << file_path << " with error code " << errno;
65 throw std::runtime_error(oss.str());
66 }
67
68 return content_stream.str();
69}
70
71typedef enum {
72 ERRORT,
73 INT8T,
74 INT16T,
75 INT32T,
76 INT64T,
77 UINT8T,
78 UINT16T,
79 UINT32T,
80 UINT64T,
81 STRINGT
82} AnswerType;
83
84typedef struct {
85 union {
86 uint8_t uint8;
87 uint16_t uint16;
88 uint32_t uint32;
89 uint64_t uint64;
90 int8_t int8;
91 int16_t int16;
92 int32_t int32;
93 int64_t int64;
94 char *string;
95 } value;
96 uint16_t id;
97 AnswerType type;
98} Answer;
99
100Answer EMSCRIPTEN_KEEPALIVE get_answer(const uint16_t id) {
101 Answer answer;
102 char c_id[6];
103 snprintf(c_id, sizeof(c_id), "%" PRIu16, id);
104 std::string s_id(c_id);
105 std::string answers = get_data_file("answers.tsv");
106 if (answers.empty()) {
107 std::cerr << "Error: Failed to read data from file\n";
108 return answer;
109 }
110
111 std::string line;
112 std::istringstream stream(answers);
113
114 // Read and skip the header
115 if (!std::getline(stream, line)) {
116 std::cerr << "Error: Empty or invalid input\n";
117 return answer;
118 }
119
120 while (std::getline(stream, line)) {
121 std::istringstream lineStream(line);
122 std::string token;
123
124 if (!std::getline(lineStream, token, '\t') || token != s_id)
125 continue;
126
127 if (!std::getline(lineStream, token, '\t'))
128 continue;
129
130 if (token == "uint")
131 answer.type = UINT8T; // will adjust size later
132 else if (token == "int")
133 answer.type = INT8T; // will adjust size later
134 else if (token == "str")
135 answer.type = STRINGT;
136 else {
137 std::cerr << "Error: Unknown type '" << token << "'\n";
138 return answer;
139 }
140
141 if (!std::getline(lineStream, token, '\t'))
142 continue;
143 size_t size = strtoull(token.c_str(), NULL, 10);
144
145 if (!std::getline(lineStream, token, '\t'))
146 continue;
147
148 switch (answer.type) {
149 case UINT8T:
150 switch (size) {
151 case 8:
152 answer.value.uint8 = (uint8_t)strtoul(token.c_str(), NULL, 10);
153 break;
154 case 16:
155 answer.value.uint16 = (uint16_t)strtoul(token.c_str(), NULL, 10);
156 answer.type = UINT16T;
157 break;
158 case 32:
159 answer.value.uint32 = strtoul(token.c_str(), NULL, 10);
160 answer.type = UINT32T;
161 break;
162 case 64:
163 answer.value.uint64 = strtoull(token.c_str(), NULL, 10);
164 answer.type = UINT64T;
165 break;
166 default:
167 std::cerr << "Error: Unsupported int size " << size << "'\n";
168 Answer err = {{0}};
169 return err;
170 }
171 break;
172 case INT8T:
173 switch (size) {
174 case 8:
175 answer.value.int8 = (int8_t)strtol(token.c_str(), NULL, 10);
176 break;
177 case 16:
178 answer.value.int16 = (int16_t)strtol(token.c_str(), NULL, 10);
179 answer.type = INT16T;
180 break;
181 case 32:
182 answer.value.int32 = strtol(token.c_str(), NULL, 10);
183 answer.type = INT32T;
184 break;
185 case 64:
186 answer.value.int64 = strtoll(token.c_str(), NULL, 10);
187 answer.type = INT64T;
188 break;
189 default:
190 std::cerr << "Error: Unsupported uint size " << size << "'\n";
191 Answer err = {{0}};
192 return err;
193 }
194 break;
195 case STRINGT:
196 answer.value.string = (char *)malloc(size + 1);
197 if (answer.value.string) {
198 strncpy(answer.value.string, token.c_str(), size);
199 answer.value.string[size] = 0;
200 } else {
201 std::cerr << "Error: Memory allocation failed for string\n";
202 Answer err = {{0}};
203 return err;
204 }
205 break;
206 default:
207 std::cerr << "Error: Unknown type (should be unreachable)\n";
208 Answer err = {{0}};
209 return err;
210 }
211 }
212
213 return answer;
214}