Skip to content

Commit e40846f

Browse files
committed
Remove exceptions and add normalization
1 parent 7559686 commit e40846f

8 files changed

Lines changed: 213 additions & 257 deletions

File tree

Makefile

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,8 @@ endif
1515
CXX ?= g++
1616
AR ?= ar
1717

18-
# Base flags
19-
CXXFLAGS ?= -std=c++17 -Wall -Wextra -Werror -O2
18+
# Base flags (no exceptions/RTTI for smaller binaries)
19+
CXXFLAGS ?= -std=c++17 -Wall -Wextra -Werror -O2 -fno-exceptions -fno-rtti -DJSON_NOEXCEPTION
2020
INCLUDES = -I./include -I./extern/json/single_include
2121

2222
# Platform-specific settings

src/archspec_c.cpp

Lines changed: 37 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -36,19 +36,16 @@ static bool s_initialized = false;
3636

3737
static void ensure_initialized() {
3838
if (!s_initialized) {
39-
try {
40-
auto host_arch = archspec::host();
41-
s_host_name = host_arch.name();
42-
43-
auto info = archspec::detect_cpu_info();
44-
s_host_vendor = info.vendor;
45-
46-
// Cache target names
47-
const auto& db = archspec::MicroarchitectureDatabase::instance();
48-
s_target_names = db.all_names();
49-
} catch (...) {
50-
// Ignore errors during initialization
51-
}
39+
auto host_arch = archspec::host();
40+
s_host_name = host_arch.name();
41+
42+
auto info = archspec::detect_cpu_info();
43+
s_host_vendor = info.vendor;
44+
45+
// Cache target names
46+
const auto& db = archspec::MicroarchitectureDatabase::instance();
47+
s_target_names = db.all_names();
48+
5249
s_initialized = true;
5350
}
5451
}
@@ -61,12 +58,8 @@ const char* archspec_host_name(void) {
6158
}
6259

6360
char* archspec_host_features(void) {
64-
try {
65-
auto host_arch = archspec::host();
66-
return to_c_string(join_features(host_arch.features()));
67-
} catch (...) {
68-
return nullptr;
69-
}
61+
auto host_arch = archspec::host();
62+
return to_c_string(join_features(host_arch.features()));
7063
}
7164

7265
const char* archspec_host_vendor(void) {
@@ -77,73 +70,53 @@ const char* archspec_host_vendor(void) {
7770
char* archspec_get_features(const char* name) {
7871
if (!name)
7972
return nullptr;
80-
try {
81-
const auto& db = archspec::MicroarchitectureDatabase::instance();
82-
const auto* target = db.get(name);
83-
if (!target)
84-
return nullptr;
85-
return to_c_string(join_features(target->features()));
86-
} catch (...) {
73+
const auto& db = archspec::MicroarchitectureDatabase::instance();
74+
const auto* target = db.get(name);
75+
if (!target)
8776
return nullptr;
88-
}
77+
return to_c_string(join_features(target->features()));
8978
}
9079

9180
char* archspec_get_flags(const char* name, const char* compiler) {
9281
if (!name || !compiler)
9382
return nullptr;
94-
try {
95-
const auto& db = archspec::MicroarchitectureDatabase::instance();
96-
const auto* target = db.get(name);
97-
if (!target)
98-
return nullptr;
99-
// Use empty version string to get default flags
100-
std::string flags = target->optimization_flags(compiler, "");
101-
if (flags.empty())
102-
return nullptr;
103-
return to_c_string(flags);
104-
} catch (...) {
83+
const auto& db = archspec::MicroarchitectureDatabase::instance();
84+
const auto* target = db.get(name);
85+
if (!target)
10586
return nullptr;
106-
}
87+
// Use empty version string to get default flags
88+
std::string flags = target->optimization_flags(compiler, "");
89+
if (flags.empty())
90+
return nullptr;
91+
return to_c_string(flags);
10792
}
10893

10994
char* archspec_host_flags(const char* compiler) {
11095
if (!compiler)
11196
return nullptr;
112-
try {
113-
auto host_arch = archspec::host();
114-
// Use empty version string to get default flags
115-
std::string flags = host_arch.optimization_flags(compiler, "");
116-
if (flags.empty())
117-
return nullptr;
118-
return to_c_string(flags);
119-
} catch (...) {
97+
auto host_arch = archspec::host();
98+
// Use empty version string to get default flags
99+
std::string flags = host_arch.optimization_flags(compiler, "");
100+
if (flags.empty())
120101
return nullptr;
121-
}
102+
return to_c_string(flags);
122103
}
123104

124105
int archspec_has_feature(const char* name, const char* feature) {
125106
if (!name || !feature)
126107
return 0;
127-
try {
128-
const auto& db = archspec::MicroarchitectureDatabase::instance();
129-
const auto* target = db.get(name);
130-
if (!target)
131-
return 0;
132-
return target->has_feature(feature) ? 1 : 0;
133-
} catch (...) {
108+
const auto& db = archspec::MicroarchitectureDatabase::instance();
109+
const auto* target = db.get(name);
110+
if (!target)
134111
return 0;
135-
}
112+
return target->has_feature(feature) ? 1 : 0;
136113
}
137114

138115
int archspec_host_has_feature(const char* feature) {
139116
if (!feature)
140117
return 0;
141-
try {
142-
auto host_arch = archspec::host();
143-
return host_arch.has_feature(feature) ? 1 : 0;
144-
} catch (...) {
145-
return 0;
146-
}
118+
auto host_arch = archspec::host();
119+
return host_arch.has_feature(feature) ? 1 : 0;
147120
}
148121

149122
size_t archspec_target_count(void) {
@@ -161,12 +134,8 @@ const char* archspec_target_name(size_t index) {
161134
int archspec_target_exists(const char* name) {
162135
if (!name)
163136
return 0;
164-
try {
165-
const auto& db = archspec::MicroarchitectureDatabase::instance();
166-
return db.exists(name) ? 1 : 0;
167-
} catch (...) {
168-
return 0;
169-
}
137+
const auto& db = archspec::MicroarchitectureDatabase::instance();
138+
return db.exists(name) ? 1 : 0;
170139
}
171140

172141
void archspec_free(char* str) {

src/detect.cpp

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,15 @@ std::string get_machine() {
105105
#else
106106
struct utsname uts;
107107
if (uname(&uts) == 0) {
108-
return uts.machine;
108+
std::string machine = uts.machine;
109+
// Normalize architecture names
110+
if (machine == "arm64") {
111+
return ARCH_AARCH64;
112+
}
113+
if (machine == "amd64") {
114+
return ARCH_X86_64;
115+
}
116+
return machine;
109117
}
110118
return "unknown";
111119
#endif
@@ -191,9 +199,12 @@ DetectedCpuInfo detect_from_proc_cpuinfo() {
191199
std::smatch match;
192200
std::string cpu_str = data["cpu"];
193201
if (std::regex_search(cpu_str, match, power_re)) {
194-
try {
195-
info.generation = std::stoi(match[1].str());
196-
} catch (...) {}
202+
std::string gen_str = match[1].str();
203+
char* end = nullptr;
204+
long val = std::strtol(gen_str.c_str(), &end, 10);
205+
if (end != gen_str.c_str()) {
206+
info.generation = static_cast<int>(val);
207+
}
197208
}
198209
}
199210
} else if (arch == ARCH_RISCV64) {

src/microarchitecture.cpp

Lines changed: 52 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -196,11 +196,13 @@ std::vector<int> parse_version(const std::string& version) {
196196
std::string part;
197197
while (std::getline(ss, part, '.')) {
198198
if (!part.empty()) {
199-
try {
200-
result.push_back(std::stoi(part));
201-
} catch (...) {
202-
// Ignore non-numeric parts
199+
// Parse without exceptions
200+
char* end = nullptr;
201+
long val = std::strtol(part.c_str(), &end, 10);
202+
if (end != part.c_str()) {
203+
result.push_back(static_cast<int>(val));
203204
}
205+
// Ignore non-numeric parts
204206
}
205207
}
206208
return result;
@@ -338,73 +340,71 @@ bool MicroarchitectureDatabase::load_from_file(const std::string& path) {
338340
}
339341

340342
bool MicroarchitectureDatabase::load_from_json_internal(const void* json_ptr) {
341-
try {
342-
const nlohmann::json& j = *static_cast<const nlohmann::json*>(json_ptr);
343-
344-
// Parse microarchitectures
345-
if (j.contains("microarchitectures")) {
346-
const auto& uarchs = j["microarchitectures"];
347-
for (auto it = uarchs.begin(); it != uarchs.end(); ++it) {
348-
fill_target(it.key(), &it.value());
349-
}
343+
const nlohmann::json& j = *static_cast<const nlohmann::json*>(json_ptr);
344+
345+
if (j.is_discarded()) {
346+
return false;
347+
}
348+
349+
// Parse microarchitectures
350+
if (j.contains("microarchitectures")) {
351+
const auto& uarchs = j["microarchitectures"];
352+
for (auto it = uarchs.begin(); it != uarchs.end(); ++it) {
353+
fill_target(it.key(), &it.value());
350354
}
355+
}
356+
357+
// Parse feature aliases
358+
if (j.contains("feature_aliases")) {
359+
const auto& aliases = j["feature_aliases"];
360+
for (auto it = aliases.begin(); it != aliases.end(); ++it) {
361+
const auto& alias_data = it.value();
362+
std::set<std::string> features;
351363

352-
// Parse feature aliases
353-
if (j.contains("feature_aliases")) {
354-
const auto& aliases = j["feature_aliases"];
355-
for (auto it = aliases.begin(); it != aliases.end(); ++it) {
356-
const auto& alias_data = it.value();
357-
std::set<std::string> features;
358-
359-
if (alias_data.contains("any_of")) {
360-
for (const auto& f : alias_data["any_of"]) {
361-
features.insert(f.get<std::string>());
362-
}
363-
feature_aliases_[it.key()] = features;
364+
if (alias_data.contains("any_of")) {
365+
for (const auto& f : alias_data["any_of"]) {
366+
features.insert(f.get<std::string>());
364367
}
368+
feature_aliases_[it.key()] = features;
369+
}
365370

366-
if (alias_data.contains("families")) {
367-
std::set<std::string> families;
368-
for (const auto& f : alias_data["families"]) {
369-
families.insert(f.get<std::string>());
370-
}
371-
family_features_[it.key()] = families;
371+
if (alias_data.contains("families")) {
372+
std::set<std::string> families;
373+
for (const auto& f : alias_data["families"]) {
374+
families.insert(f.get<std::string>());
372375
}
376+
family_features_[it.key()] = families;
373377
}
374378
}
379+
}
375380

376-
// Parse conversions
377-
if (j.contains("conversions")) {
378-
const auto& conv = j["conversions"];
381+
// Parse conversions
382+
if (j.contains("conversions")) {
383+
const auto& conv = j["conversions"];
379384

380-
if (conv.contains("darwin_flags")) {
381-
for (auto it = conv["darwin_flags"].begin(); it != conv["darwin_flags"].end();
382-
++it) {
383-
darwin_flags_[it.key()] = it.value().get<std::string>();
384-
}
385+
if (conv.contains("darwin_flags")) {
386+
for (auto it = conv["darwin_flags"].begin(); it != conv["darwin_flags"].end(); ++it) {
387+
darwin_flags_[it.key()] = it.value().get<std::string>();
385388
}
389+
}
386390

387-
if (conv.contains("arm_vendors")) {
388-
for (auto it = conv["arm_vendors"].begin(); it != conv["arm_vendors"].end(); ++it) {
389-
arm_vendors_[it.key()] = it.value().get<std::string>();
390-
}
391+
if (conv.contains("arm_vendors")) {
392+
for (auto it = conv["arm_vendors"].begin(); it != conv["arm_vendors"].end(); ++it) {
393+
arm_vendors_[it.key()] = it.value().get<std::string>();
391394
}
392395
}
393-
394-
loaded_ = true;
395-
return true;
396-
} catch (const std::exception& e) {
397-
return false;
398396
}
397+
398+
loaded_ = true;
399+
return true;
399400
}
400401

401402
bool MicroarchitectureDatabase::load_from_string(const std::string& json_data) {
402-
try {
403-
nlohmann::json j = nlohmann::json::parse(json_data);
404-
return load_from_json_internal(&j);
405-
} catch (const std::exception& e) {
403+
nlohmann::json j = nlohmann::json::parse(json_data, nullptr, false);
404+
if (j.is_discarded()) {
406405
return false;
407406
}
407+
return load_from_json_internal(&j);
408408
}
409409

410410
void MicroarchitectureDatabase::fill_target(const std::string& name, const void* json_ptr) {

tests/test_common.hpp

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
// This file is a part of Julia. License is MIT: https://julialang.org/license
2+
//
3+
// Common test framework without exceptions
4+
5+
#ifndef ARCHSPEC_TEST_COMMON_HPP
6+
#define ARCHSPEC_TEST_COMMON_HPP
7+
8+
#include <iostream>
9+
#include <optional>
10+
#include <string>
11+
12+
// Simple test framework without exceptions
13+
// Tests return std::optional<std::string> - nullopt on success, error message on failure
14+
inline int g_tests_passed = 0;
15+
inline int g_tests_failed = 0;
16+
17+
using TestResult = std::optional<std::string>;
18+
19+
#define TEST(name) TestResult test_##name()
20+
21+
#define RUN_TEST(name) \
22+
do { \
23+
std::cout << "Running " #name "... "; \
24+
TestResult result = test_##name(); \
25+
if (!result.has_value()) { \
26+
std::cout << "PASSED" << std::endl; \
27+
g_tests_passed++; \
28+
} else { \
29+
std::cout << "FAILED: " << *result << std::endl; \
30+
g_tests_failed++; \
31+
} \
32+
} while (0)
33+
34+
#define TEST_PASS() return std::nullopt
35+
#define TEST_FAIL(msg) return std::string(msg)
36+
37+
#define ASSERT(cond) \
38+
do { \
39+
if (!(cond)) { \
40+
return "Assertion failed: " #cond; \
41+
} \
42+
} while (0)
43+
44+
#define ASSERT_EQ(a, b) \
45+
do { \
46+
if ((a) != (b)) { \
47+
return "Assertion failed: " #a " == " #b; \
48+
} \
49+
} while (0)
50+
51+
#endif // ARCHSPEC_TEST_COMMON_HPP

0 commit comments

Comments
 (0)