Skip to content

Commit cbb3e66

Browse files
committed
Add first revision of cppmatch.
0 parents  commit cbb3e66

14 files changed

Lines changed: 1243 additions & 0 deletions

LICENSE

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
MIT License
2+
3+
Copyright (c) 2025 Ruben Cano Diaz
4+
5+
Permission is hereby granted, free of charge, to any person obtaining a copy
6+
of this software and associated documentation files (the "Software"), to deal
7+
in the Software without restriction, including without limitation the rights
8+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
copies of the Software, and to permit persons to whom the Software is
10+
furnished to do so, subject to the following conditions:
11+
12+
The above copyright notice and this permission notice shall be included in all
13+
copies or substantial portions of the Software.
14+
15+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21+
SOFTWARE.

examples/coordinates.cpp

Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
#include "match.hpp"
2+
#include <print>
3+
#include <sstream>
4+
#include <vector>
5+
#include <string>
6+
#include <charconv>
7+
using namespace cppmatch;
8+
9+
// ANSI escape codes for colors
10+
inline constexpr std::string_view RESET = "\033[0m";
11+
inline constexpr std::string_view RED = "\033[31m";
12+
inline constexpr std::string_view GREEN = "\033[32m";
13+
inline constexpr std::string_view YELLOW = "\033[33m";
14+
inline constexpr std::string_view BLUE = "\033[34m";
15+
inline constexpr std::string_view CYAN = "\033[36m";
16+
17+
// Define a simple structure to hold latitude & longitude
18+
struct Coordinate {
19+
double latitude;
20+
double longitude;
21+
};
22+
23+
// Exception-free string to double conversion using std::from_chars
24+
Result<double, std::string> safe_str_to_double(const std::string& str) {
25+
double value = 0.0;
26+
auto [ptr, ec] = std::from_chars(str.data(), str.data() + str.size(), value);
27+
28+
if (ec == std::errc::invalid_argument) return "Invalid number format";
29+
if (ec == std::errc::result_out_of_range) return "Number out of range";
30+
if (ptr != str.data() + str.size()) return "Extra characters found in number";
31+
32+
return value;
33+
}
34+
35+
// Parses a single latitude,longitude pair safely
36+
Result<Coordinate, std::string> parse_coordinate(const std::string& input) {
37+
std::istringstream ss(input);
38+
std::string lat_str, lon_str;
39+
40+
if (!std::getline(ss, lat_str, ',') || !std::getline(ss, lon_str)) {
41+
return "Invalid format (expected 'latitude,longitude')";
42+
}
43+
44+
// Convert latitude and longitude safely
45+
double latitude = expect(safe_str_to_double(lat_str));
46+
double longitude = expect(safe_str_to_double(lon_str));
47+
48+
// Validate ranges
49+
if (latitude < -90 || latitude > 90) return "Latitude out of range (-90 to 90)";
50+
if (longitude < -180 || longitude > 180) return "Longitude out of range (-180 to 180)";
51+
52+
return Coordinate{latitude, longitude};
53+
}
54+
55+
// Parses a string containing multiple coordinates separated by semicolons
56+
Result<std::vector<Coordinate>, std::string> parse_coordinates(const std::string& input) {
57+
std::vector<Coordinate> coordinates;
58+
std::istringstream ss(input);
59+
std::string token;
60+
61+
while (std::getline(ss, token, ';')) {
62+
token.erase(0, token.find_first_not_of(" \t")); // Trim left
63+
token.erase(token.find_last_not_of(" \t") + 1); // Trim right
64+
65+
Coordinate coord = expect(parse_coordinate(token));
66+
coordinates.push_back(coord);
67+
}
68+
69+
return coordinates;
70+
}
71+
72+
// Pretty-printing a coordinate
73+
void print_coordinate(const Coordinate& coord) {
74+
std::print("{}Parsed Coordinate -> Latitude: {}, Longitude: {}{}\n",
75+
GREEN, coord.latitude, coord.longitude, RESET);
76+
}
77+
78+
// Testing our parser
79+
void test_parser() {
80+
std::vector<std::string> test_cases = {
81+
"40.7128,-74.0060; 34.0522,-118.2437; 48.8566,2.3522", // Valid
82+
"91.0000,45.0000; 50.0000,-30.0000", // Invalid latitude
83+
"50.0000,190.0000; -20.0000,120.0000", // Invalid longitude
84+
"abcd,efgh; 10.0,20.0", // Invalid number format
85+
"10.5,20.5", // Single valid coordinate
86+
" 40.0 , -75.0 ; 50.0 , -45.0 ", // With extra spaces
87+
";;" // Empty inputs
88+
};
89+
90+
for (const auto& test : test_cases) {
91+
std::print("{}\nInput: \"{}\"{}\n", CYAN, test, RESET);
92+
auto result = parse_coordinates(test);
93+
94+
match(result,
95+
[](const std::vector<Coordinate>& coords) {
96+
std::print("{}Successfully parsed {} coordinates:\n{}", GREEN, coords.size(), RESET);
97+
for (const auto& coord : coords) {
98+
print_coordinate(coord);
99+
}
100+
},
101+
[](const std::string& err) {
102+
std::print("{}Error: {}{}\n", RED, err, RESET);
103+
}
104+
);
105+
}
106+
}
107+
108+
// Entry point
109+
int main() {
110+
test_parser();
111+
return 0;
112+
}

examples/coordinates_types.cpp

Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,118 @@
1+
#include "match.hpp"
2+
#include <print>
3+
#include <sstream>
4+
#include <vector>
5+
#include <string>
6+
#include <charconv>
7+
#include <string_view>
8+
using namespace cppmatch;
9+
10+
// ANSI escape codes for colors
11+
inline constexpr std::string_view RESET = "\033[0m";
12+
inline constexpr std::string_view RED = "\033[31m";
13+
inline constexpr std::string_view GREEN = "\033[32m";
14+
inline constexpr std::string_view YELLOW = "\033[33m";
15+
inline constexpr std::string_view BLUE = "\033[34m";
16+
inline constexpr std::string_view CYAN = "\033[36m";
17+
18+
// Define a simple structure to hold latitude & longitude
19+
struct Coordinate {
20+
double latitude;
21+
double longitude;
22+
};
23+
24+
25+
struct InvalidDoubleConversion { std::string_view message; };
26+
struct InvalidCoordinate { std::string_view message; };
27+
struct InvalidCoordinateFormat { std::string_view message; };
28+
29+
// Exception-free string to double conversion using std::from_chars
30+
auto safe_str_to_double(std::string_view str) -> Result<double, InvalidDoubleConversion> {
31+
double value = 0.0;
32+
auto [ptr, ec] = std::from_chars(str.data(), str.data() + str.size(), value);
33+
34+
if (ec == std::errc::invalid_argument) return InvalidDoubleConversion{"Invalid number format"};
35+
if (ec == std::errc::result_out_of_range) return InvalidDoubleConversion{"Number out of range"};
36+
if (ptr != str.data() + str.size()) return InvalidDoubleConversion{"Extra characters found in number"};
37+
38+
return value;
39+
}
40+
41+
// Parses a single latitude,longitude pair safely
42+
auto parse_coordinate(const std::string& input) -> Result<Coordinate, Error<InvalidDoubleConversion, InvalidCoordinate, InvalidCoordinateFormat>> {
43+
std::istringstream ss(input);
44+
std::string lat_str, lon_str;
45+
46+
if (!std::getline(ss, lat_str, ',') || !std::getline(ss, lon_str)) {
47+
return InvalidCoordinateFormat{"Invalid format (expected 'latitude,longitude')"};
48+
}
49+
50+
// Convert latitude and longitude safely
51+
double latitude = expect(safe_str_to_double(lat_str));
52+
double longitude = expect(safe_str_to_double(lon_str));
53+
54+
// Validate ranges
55+
if (latitude < -90 || latitude > 90) return InvalidCoordinate{"Latitude out of range (-90 to 90)"};
56+
if (longitude < -180 || longitude > 180) return InvalidCoordinate{"Longitude out of range (-180 to 180)"};
57+
58+
return Coordinate{latitude, longitude};
59+
}
60+
61+
// Parses a string containing multiple coordinates separated by semicolons
62+
auto parse_coordinates(const std::string& input) -> Result<std::vector<Coordinate>, Error<InvalidDoubleConversion, InvalidCoordinate, InvalidCoordinateFormat>> {
63+
std::vector<Coordinate> coordinates;
64+
std::istringstream ss(input);
65+
std::string token;
66+
67+
while (std::getline(ss, token, ';')) {
68+
token.erase(0, token.find_first_not_of(" \t")); // Trim left
69+
token.erase(token.find_last_not_of(" \t") + 1); // Trim right
70+
71+
Coordinate coord = expect(parse_coordinate(token));
72+
coordinates.push_back(coord);
73+
}
74+
75+
return coordinates;
76+
}
77+
78+
// Pretty-printing a coordinate
79+
void print_coordinate(const Coordinate& coord) {
80+
std::print("{}Parsed Coordinate -> Latitude: {}, Longitude: {}{}\n",
81+
GREEN, coord.latitude, coord.longitude, RESET);
82+
}
83+
84+
// Testing our parser
85+
int main() {
86+
std::vector<std::string> test_cases = {
87+
"40.7128,-74.0060; 34.0522,-118.2437; 48.8566,2.3522", // Valid
88+
"91.0000,45.0000; 50.0000,-30.0000", // Invalid latitude
89+
"50.0000,190.0000; -20.0000,120.0000", // Invalid longitude
90+
"abcd,efgh; 10.0,20.0", // Invalid number format
91+
"10.5,20.5", // Single valid coordinate
92+
" 40.0 , -75.0 ; 50.0 , -45.0 ", // With extra spaces
93+
";;" // Empty inputs
94+
};
95+
96+
for (const auto& test : test_cases) {
97+
std::print("{}\nInput: \"{}\"{}\n", CYAN, test, RESET);
98+
auto result = parse_coordinates(test);
99+
100+
match(result,
101+
[](const std::vector<Coordinate>& coords) {
102+
std::print("{}Successfully parsed {} coordinates:\n{}", GREEN, coords.size(), RESET);
103+
for (const auto& coord : coords) {
104+
print_coordinate(coord);
105+
}
106+
},
107+
[](const InvalidCoordinate err) {
108+
std::print("{}Error: {}{}\n", RED, err.message, RESET);
109+
},
110+
[](const InvalidCoordinateFormat err) {
111+
std::print("{}Error: {}{}\n", RED, err.message, RESET);
112+
},
113+
[](const InvalidDoubleConversion err) {
114+
std::print("{}Error: {}{}\n", RED, err.message, RESET);
115+
}
116+
);
117+
}
118+
}

examples/default_expect.cpp

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
#include "match.hpp"
2+
#include <string_view>
3+
#include <iostream>
4+
#include <cmath>
5+
using namespace cppmatch;
6+
7+
enum class MathError {
8+
NegativeSquareRoot
9+
};
10+
11+
Result<double, MathError> sqrt_(double x) {
12+
if (x < 0.0)
13+
return MathError::NegativeSquareRoot;
14+
else
15+
return std::sqrt(x);
16+
}
17+
18+
int main() {
19+
double result = default_expect(sqrt_(-4.0), -5.1);
20+
21+
std::cout << result << std::endl;
22+
23+
return 0;
24+
}

examples/enums_match.cpp

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
#include <iostream>
2+
#include <variant>
3+
#include <string>
4+
#include <cstdint>
5+
#include <vector>
6+
#include <print>
7+
#include "match.hpp"
8+
using namespace cppmatch;
9+
10+
struct WebEvent
11+
{
12+
struct PageLoad{};
13+
struct PageUnload{};
14+
struct KeyPress{char c;};
15+
struct Paste{std::string str;};
16+
struct Click{uint64_t x,y;};
17+
using webEvent = std::variant<PageLoad, PageUnload, KeyPress, Paste, Click>;
18+
};
19+
20+
21+
int main()
22+
{
23+
// Create a vector of various web events
24+
std::vector<WebEvent::webEvent> events = {
25+
WebEvent::PageLoad{},
26+
WebEvent::PageUnload{},
27+
WebEvent::KeyPress{'a'},
28+
WebEvent::Paste{"Copied text"},
29+
WebEvent::Click{32, 64},
30+
WebEvent::KeyPress{'z'},
31+
WebEvent::Paste{"Another paste"},
32+
WebEvent::Click{100, 200}
33+
};
34+
35+
// Process each event in the vector
36+
for (const auto& event : events) {
37+
match(event,
38+
[](const WebEvent::PageLoad&) {
39+
std::print("Page loaded\n");
40+
},
41+
[](const WebEvent::PageUnload&) {
42+
std::print("Page unloaded\n");
43+
},
44+
[](const WebEvent::KeyPress& kp) {
45+
std::print("Key pressed: {}\n", kp.c);
46+
},
47+
[](const WebEvent::Paste& paste) {
48+
std::print("Pasted: {}\n", paste.str);
49+
},
50+
[](const WebEvent::Click& click) {
51+
std::print("Clicked at x={}, y={}\n", click.x, click.y);
52+
}
53+
);
54+
}
55+
56+
return 0;
57+
}

0 commit comments

Comments
 (0)