C++ Extended Template Library
- GCC 8.3.0+
- Clang 10.0+
- Visual Studio 2008 SP1+
- Boost 1.69.0++ (optional)
- Git 2.0+
- CMake 3.14+
- ext
- Requirements
- Contents
- Test Environments
- Features
- Test
- Usage
-
Windows 10
- Visual Studio 2008 SP1, 2010, 2017, 2019
- MSYS2
- MSYS (GCC 10.2.0)
- MinGW32 (GCC 10.3.0)
- MinGW64 (GCC 10.3.0)
- CLANG32 (Clang 12.0.1)
- CLANG64 (Clang 12.0.1)
- UCRT64 (GCC 10.3.0)
-
macOS 10.14, macOS 10.15
- Clang 10.0.0, 11.0.0
-
Linux (Ubuntu 18.04.3 LTS / Debian 10 / Gooroom 2.0, 2.3)
- GCC 7.5.0, 8.3.0
- GCC 8.3.0+
- Clang 10.0+
- Visual Studio 2017+
- std::any required
- if constexpr required
#include <ext/any_function>
ext::any_function fn(strlen);
if (fn.call("test") == 4) {
}
if (std::any_cast<decltype(fn)::result_type>(fn({"test"})) == 4) {
}
size_t len;
std::any result;
result = fn({"test"});
if (result.has_value())
len = std::any_cast<size_t>(result);
std::vector<std::any> args;
args.push_back("test");
result = fn(args);
if (result.has_value())
len = std::any_cast<size_t>(result);
- GCC 8.3.0+
- Clang 10.0+
- Visual Studio 2008 SP1+ with Boost 1.69.0+
- Visual Studio 2017+
#include <ext/async_result>
typedef ext::async_result<int> int_result;
int_result res([](int_result::context &ctx) {
ctx.push(1);
ctx.push(2);
...
});
....
for (auto &i : res) {
...
}
- GCC 8.3.0+
- Clang 10.0+
- Visual Studio 2008 SP1+
-
string
#include <ext/base64> // std::string <--> base64(std::string). std::string encoded = ext::base64::encode("1234"); std::string decoded = ext::base64::decode_str(encoded); // "1234" std::vector<std::byte> decoded_vec = ext::base64::decode(encoded); // '1', '2', '3', '4 // std::string <--> base64(std::wstring). std::wstring encoded_w = ext::base64::encode<wchar_t>("1234"); decoded = ext::base64::decode_str(encoded_w); decoded_vec = ext::base64::decode(encoded_w);
-
wstring
#include <ext/base64> // std::wstring <--> base64(std::string). std::string encoded = ext::base64::encode(L"1234"); std::wstring decoded = ext::base64::decode_str<wchar_t>(encoded); // L"1234" std::vector<std::byte> decoded_vec = ext::base64::decode(encoded); // L'1', L'2', L'3', L'4 // std::wstring <--> base64(std::wstring). std::wstring encoded_w = ext::base64::encode<wchar_t>(L"1234"); decoded = ext::base64::decode_str<wchar_t>(encoded_w); // L"1234" decoded_vec = ext::base64::decode(encoded_w); // L'1', L'2', L'3', L'4
-
std::vector<std::byte>
#include <ext/base64> // std::vector<std::byte> <--> base64(std::string). std::vector<std::byte> vec = {(std::byte)'1', (std::byte)'2', (std::byte)'3', (std::byte)'4'}; std::string encoded = ext::base64::encode(vec); std::vector<std::byte> decoded = ext::base64::decode(encoded); // '1', '2', '3', '4 std::string decoded_str = ext::base64::decode_str(encoded); // "1234" // std::vector<std::byte> <--> base64(std::wstring). std::wstring encoded_w = ext::base64::encode<wchar_t>(vec); decoded = ext::base64::decode(encoded_w); // '1', '2', '3', '4 decoded_str = ext::base64::decode_str(encoded_w); // "1234"
-
structure
#include <ext/base64> struct test { char a; char b; char c; char d; }; test data = {'1', '2', '3', '4'}; std::string encoded = ext::base64::encode(data); test decoded; ext::base64::decode(encoded, decoded); // a='1', b='2', c='3', d='4' std::shared_ptr<test> decoded_ptr = ext::base64::decode_shared_ptr<test>(encoded); // a='1', b='2', c='3', d='4' std::string decoded_str = ext::base64::decode_str(encoded); // "1234" std::wstring encoded_w = ext::base64::encode<wchar_t>(data); decoded = { 0, }; ext::base64::decode(encoded_w, decoded); // a='1', b='2', c='3', d='4' decoded_ptr = ext::base64::decode_shared_ptr<test>(encoded_w); // a='1', b='2', c='3', d='4' decoded_str = ext::base64::decode_str(encoded_w); // "1234"
- GCC 8.3.0+
- Clang 10.0+
- Visual Studio 2008 SP1+ with Boost 1.69.0+
- Visual Studio 2017+
-
Register a callbacks.
#include <ext/callback> int sum = 1; ext::callback<int> int_callback; int_callback += [&sum](int val) { sum += val; }; int_callback += [&sum](int val) { sum *= val; }; int_callback(5); // sum == 10
-
Register a callbacks.
#include <ext/callback> int sum = 1; ext::callback<int> int_callback; int_callback += [&sum](int val) { sum *= val; }; int_callback += [&sum](int val) { sum += val; }; int_callback(5); // sum == 30
-
Unregister a callback.
#include <ext/callback> int sum = 0; ext::callback<int> int_callback; int_callback += [&sum](int val) { sum += val; }; auto cookie = int_callback += [&sum](int val) { sum += val; }; int_callback(1); // sum == 2 sum = 0; int_callback -= cookie; int_callback(1); //sum == 1
- GCC 8.3.0+
- Clang 10.0+
- Visual Studio 2008 SP1+ with Boost 1.69.0+
- Visual Studio 2017+
-
Cancel
-
MSYS is not supported.
-
Like PTHREAD_CANCEL_DEFERRED
#include <ext/cancelable_thread> std::mutex mtx; ext::cancelable_thread t([&mtx]() { std::unique_lock<std::mutex> lk(mtx); ... }); ... t.cancel_request(); t.wait_for(std::chrono::milliseconds(500)); t.join(); // or t.cancel(); if (t.canceled()) ...
-
-
Cancel immediately.
-
Use this method with extreme caution
-
macOS and MinGW Clang32/Clang64 is not supported.
-
Like PTHREAD_CANCEL_ASYNCHRONOUS
#include <ext/cancelable_thread> std::mutex mtx; ext::cancelable_thread t([&mtx]() { std::unique_lock<std::mutex> lk(mtx); ... }, [&mtx]() { mtx.unlock(); }); ... t.cancel_request(); t.wait_for(std::chrono::milliseconds(500)); t.join(); // or t.cancel(); if (t.canceled()) ...
-
- GCC 8.3.0+
- Clang 10.0+
- Visual Studio 2008 SP1+
- Sends a string to the debugger for display.
-
Like OutputDebugStringA
#include <ext/cdbg> ext::cdbg << "test\n";
-
Like OutputDebugStringW
#include <ext/cdbg> ext::wcdbg << L"test\n";
-
- GCC 8.3.0+
- Clang 10.0+
- Visual Studio 2008 SP1+
-
Implements an http request chain.
#include <map> #include <string> #include <string> #include <tuple> #include <ext/chain> namespace http { struct request { enum method { http_get, http_post, http_delete, http_put, http_invalid }; request() : method(method::http_invalid) {} request(const std::string &path, method method, const std::map<std::string, std::string> headers = {}) : path(path), method(method), headers(headers) {} method method; std::string path; std::map<std::string, std::string> headers; std::string get_method() const { switch (method) { case method::http_get: return "GET"; case method::http_post: return "POST"; case method::http_delete: return "DELETE"; case method::http_put: return "PUT"; default: throw std::runtime_error("Invalid method"); } } void validate() const { if (path[0] != '/') throw std::runtime_error("Invalid path : " + path); } }; struct response { enum status { ok = 200, unauthorized = 401, forbidden = 403, not_found = 404, internal_server_error = 500 }; response() : status(internal_server_error) {} response(status s, const std::string &body = {}) : status(s), body(body) {} status status; std::string body; }; template <class T> struct validation_chain : T { typename T::result execute(const request &req) { try { req.validate(); return T::execute(req); } catch (const std::exception &e) { return T::done(response(response::internal_server_error, e.what())); } } }; struct basic_chain : ext::chain<basic_chain, response, const request &> {}; } // namespace http struct auth_check_chain_type : public http::basic_chain { result execute(const http::request &req) { auto it = req.headers.find("auth"); if (it != req.headers.cend() && it->second == "authorized") return chain::next(req); return chain::done(http::response(http::response::unauthorized)); } }; http::validation_chain<auth_check_chain_type> auth_check_chain; struct get_info_chain_type : public http::basic_chain { result execute(const http::request &req) { if ((req.path == "/info") && (req.method == http::request::http_get)) return chain::done(http::response( http::response::ok, "[" + req.get_method() + "] " + req.path)); return chain::next(req); } }; http::validation_chain<get_info_chain_type> get_info_chain; struct not_found_chain_type : public http::basic_chain { result execute(const http::request &req) { return chain::done(http::response( http::response::not_found, "[" + req.get_method() + "] " + req.path)); } }; http::validation_chain<not_found_chain_type> not_found_chain; // Build a chain. auth_check_chain >> get_info_chain >> not_found_chain; // Execute the first chain (auth_check_chain). auto res = auth_check_chain(http::request("/info", http::request::http_get)).get(); // res.status == http::response::unauthorized res = auth_check_chain(http::request("/info", http::request::http_post, {{"auth", "authorized"}})).get(); // res.status == http::response::not_found res = auth_check_chain(http::request("/test", http::request::http_get, {{"auth", "authorized"}})).get(); // res.status == http::response::not_found res = auth_check_chain(http::request("1234", http::request::http_post, {{"auth", "authorized"}})).get(); // res.status == http::response::internal_server_error // res.body == "Invalid path : 1234" res = auth_check_chain(http::request("/info", http::request::http_get, {{"auth", "authorized"}})).get(); // res.status == http::response::ok // res.body == "[GET] /info" // Execute the second chain (get_info_chain). res = get_info_chain(http::request("/info", http::request::http_get)).get(); // res.status == http::response::ok // res.body == "[GET] /info"
- GCC 8.3.0+
- Clang 10.0+
- Visual Studio 2008 SP1+
-
Wait for debugger (C/C++)
#include <ext/debug_utils> wait_for_debugger(100); if (is_debugger_present()) { ... } msleep(500);
- GCC 8.3.0+
- Clang 10.0+
- Visual Studio 2008 SP1+ with Boost 1.69.0+
- Visual Studio 2017+
- std::shared_mutex or std::shared_timed_mutex required
-
Managed (Automatically add/remove items to the collection.)
#include <ext/collection> class managed_data : public ext::collection<managed_data>::item { public: managed_data() : id(0), value(0) {} int id; int value; }; typedef ext::collection<managed_data> managed_data_list_rw; typedef ext::const_collection<managed_data> managed_data_list_r; managed_data managed_data_list[20]; // managed_data_list_r::size() == 20; // managed_data_list_rw::size() == 20; managed_data data0; //managed_data_list_r::size() == 21; //managed_data_list_rw::size() == 21; managed_data *ptr = new managed_data; //managed_data_list_r::size() == 22; //managed_data_list_rw::size() == 22; delete ptr; //managed_data_list_r::size() == 21; //managed_data_list_rw::size() == 21; size_t cnt = 0; for (auto data : managed_data_list_r()) { int val = data->value; // data->value = 10; compile error cnt++; } // cnt == 21 cnt = 0; for (auto data : managed_data_list_rw()) { int val = dat->value; data->value = 10; cnt++; } // cnt == 21
-
Unmanaged (Manually add/remove items to the collection.)
#include <ext/collection> class data { public: data() : id(0), value(0) {} int id; int value; }; typedef ext::collection<data> data_list_rw; typedef ext::const_collection<data> data_list_r; data data_list[20]; // data_list_r::size() == 0; // data_list_rw::size() == 0; data data0; //data_list_r::size() == 21; //data_list_rw::size() == 21; data *ptr = new data; // data_list_r::size() == 22; // data_list_rw::size() == 22; delete ptr; // data_list_r::size() == 21; // data_list_rw::size() == 21; // data_list_r::size() == 0 // data_list_rw::size() == 0 data data1; // data_list_r::size() == 0 // data_list_rw::size() == 0 ext::collection_mgr<data> mgr; mgr.add(data0); // data_list_r::size() == 1 // data_list_rw::size() == 1 size_t cnt = 0; for (auto data : data_list_r()) { int val = data->value; // data->value = 10; compile error cnt++; } // cnt == 1 cnt = 0; for (auto data : data_list_rw()) { int val = dat->value; data->value = 10; cnt++; } // cnt == 1 // data0.value == 10 mgr.remove(data0); // data_list_r::size() == 0 // data_list_rw::size() == 0
- GCC 8.3.0+
- Clang 10.0+
- Visual Studio 2008 SP1+ with Boost 1.69.0+
- Visual Studio 2010+
- std::regex required
-
Create an ini file from a string.
#include <ext/ini> std::istringstream ss("[TEST]\nX=10\nY=20\n[TEST1]\nZ=30"); ext::ini ini(ss); // ini["TEST"]["X"] == "10" // ini["TEST"]["Y"] == "20" // ini["TEST1"]["Z"] == "30" std::ofstream ofs("sample.ini"); ofs << ini;
-
ini file (sample.ini)
[TEST] X=10 Y=20 [TEST1] Z=30
-
Load ini from file.
#include <ext/ini> ext::ini ini(std::ifstream("sample.ini")); // ini["TEST"]["X"] == "10" // ini["TEST"]["Y"] == "20" // ini["TEST1"]["Z"] == "30"
-
Edit the ini file.
#include <ext/ini> ext::ini ini(std::ifstream("sample.ini")); // ini["TEST"]["X"] == "10" // ini["TEST"]["Y"] == "20" // ini["TEST1"]["Z"] == "30" ini["TEST"].erase("X"); // ini["TEST"].find("X") == ini["TEST"].end() ini.erase("TEST1"); // ini.contains("TEST1") == false std::ofstream ofs("output.ini"); ofs << ini;
-
ini file (output.ini)
[TEST] Y=20
- GCC 8.3.0+
- Clang 10.0+
- Visual Studio 2008 SP1+
-
ko_kr::syllable
#include <ext/lang> ext::lang::ko_kr::syllable::letter lt = L'a'; EXPECT_FALSE(lt.valid()); lt = L'ㄱ'; EXPECT_FALSE(lt.valid()); EXPECT_EQ(lt.onset, L'ㄱ'); lt = L'ㅏ'; EXPECT_FALSE(lt.valid()); EXPECT_EQ(lt.nucleus, L'ㅏ'); lt = L'가'; EXPECT_TRUE(lt.valid()); EXPECT_EQ(lt.onset, L'ㄱ'); EXPECT_EQ(lt.nucleus, L'ㅏ'); lt = L'간'; EXPECT_TRUE(lt.valid()); EXPECT_EQ(lt.onset, L'ㄱ'); EXPECT_EQ(lt.nucleus, L'ㅏ'); EXPECT_EQ(lt.coda, L'ㄴ');
-
ko_kr::postposition
#include <ext/lang> using namespace ext::lang::ko_kr; EXPECT_STREQ(postposition::topic(L"산").c_str(), L"은"); EXPECT_STREQ(postposition::topic(L"바다").c_str(), L"는"); EXPECT_STREQ(postposition::identifier(L"산").c_str(), L"이"); EXPECT_STREQ(postposition::identifier(L"바다").c_str(), L"가"); EXPECT_STREQ(postposition::objective(L"산").c_str(), L"을"); EXPECT_STREQ(postposition::objective(L"바다").c_str(), L"를"); EXPECT_STREQ(postposition::destination(L"산").c_str(), L"으로"); EXPECT_STREQ(postposition::destination(L"바다").c_str(), L"로"); EXPECT_STREQ(postposition::destination(L"산").c_str(), L"으로"); EXPECT_STREQ(postposition::destination(L"바다").c_str(), L"로"); EXPECT_STREQ(postposition::conjunction(L"산").c_str(), L"과"); EXPECT_STREQ(postposition::conjunction(L"바다").c_str(), L"와"); EXPECT_STREQ(postposition::vocative(L"산").c_str(), L"아"); EXPECT_STREQ(postposition::vocative(L"바다").c_str(), L"야"); EXPECT_STREQ(postposition::exclamation(L"산").c_str(), L"이여"); EXPECT_STREQ(postposition::exclamation(L"바다").c_str(), L"여");
-
ko_kr::numeric
#include <ext/lang> using namespace ext::lang::ko_kr; EXPECT_STREQ(numeric::nominal(1).c_str(), "일"); EXPECT_STREQ(numeric::nominal(2).c_str(), "이"); EXPECT_STREQ(numeric::nominal(3).c_str(), "삼"); EXPECT_STREQ(numeric::ordinal(1).c_str(), "첫째"); EXPECT_STREQ(numeric::ordinal(2).c_str(), "둘째"); EXPECT_STREQ(numeric::ordinal(3).c_str(), "셋째"); EXPECT_STREQ(numeric::ordinal(1, " 번째").c_str(), "첫 번째"); EXPECT_STREQ(numeric::ordinal(2, " 번째").c_str(), "두 번째"); EXPECT_STREQ(numeric::ordinal(3, " 번째").c_str(), "세 번째"); EXPECT_STREQ(numeric::cardinal(1).c_str(), "하나"); EXPECT_STREQ(numeric::cardinal(2).c_str(), "둘"); EXPECT_STREQ(numeric::cardinal(3).c_str(), "셋"); EXPECT_STREQ(numeric::cardinal(1, " 번").c_str(), "한 번"); EXPECT_STREQ(numeric::cardinal(2, " 번").c_str(), "두 번"); EXPECT_STREQ(numeric::cardinal(3, " 번").c_str(), "세 번"); EXPECT_STREQ(numeric::wnominal(1).c_str(), L"일"); EXPECT_STREQ(numeric::wnominal(2).c_str(), L"이"); EXPECT_STREQ(numeric::wnominal(3).c_str(), L"삼"); EXPECT_STREQ(numeric::wordinal(1).c_str(), L"첫째"); EXPECT_STREQ(numeric::wordinal(2).c_str(), L"둘째"); EXPECT_STREQ(numeric::wordinal(3).c_str(), L"셋째"); EXPECT_STREQ(numeric::wordinal(1, L" 번째").c_str(), L"첫 번째"); EXPECT_STREQ(numeric::wordinal(2, L" 번째").c_str(), L"두 번째"); EXPECT_STREQ(numeric::wordinal(3, L" 번째").c_str(), L"세 번째"); EXPECT_STREQ(numeric::wcardinal(1).c_str(), L"하나"); EXPECT_STREQ(numeric::wcardinal(2).c_str(), L"둘"); EXPECT_STREQ(numeric::wcardinal(3).c_str(), L"셋"); EXPECT_STREQ(numeric::wcardinal(1, L" 번").c_str(), L"한 번"); EXPECT_STREQ(numeric::wcardinal(2, L" 번").c_str(), L"두 번"); EXPECT_STREQ(numeric::wcardinal(3, L" 번").c_str(), L"세 번");
- GCC 8.3.0+
- Clang 10.0+
- Visual Studio 2008 SP1+ with Boost 1.69.0+
- Visual Studio 2017+
- std::shared_mutex or std::shared_timed_mutex required
- GCC 8.3.0+
- Clang 10.0+
- Visual Studio 2008 SP1+
#include <ext/path>
ext::path::join("aaa", "bbb", "ccc"); // aaa/bbb/ccc
ext::path::is_relative("./test"); // true
ext::path::is_relative("/test"); // false
ext::path::exists("/test");
- GCC 8.3.0+
- Clang 10.0+
- Visual Studio 2008 SP1+
#include <ext/pipe>
#include <thread>
ext::pipe pipe;
std::thread t([stream = std::move(pipe.out())]() mutable {
stream << "test" << std::endl;
});
std::string val;
pipe.in() >> val;
EXPECT_STREQ(val.c_str(), "test");
if (t.joinable())
t.join();
- GCC 8.3.0+
- Clang 10.0+
- Visual Studio 2008 SP1+
-
stdout
#include <ext/process> ext::process process("ls", {"-al", "."}); std::cout << process.get_cmdline() << std::endl; std::cout << process.out().rdbuf() << std::endl; if (process.joinable()) process.join();
-
stdin
#include <ext/process> ext::process process("more"); process.in() << "test 1\n"; process.in() << "test 2\ntest 3\n"; process.in().close(); std::cout << process.out().rdbuf() << std::endl; if (process.joinable()) process.join();
-
pipe (stdin, stdout)
#include <ext/process> auto result = ext::process("ps", {"-ef"}) | ext::process("grep", {"root"}) | ext::process("grep", {"/usr"}) | ext::process("wc", {"-l"}); result.get_cmdline(); // "ps -ef | grep root | grep /usr | wc -l" std::cout << "cmdline : " << result.get_cmdline() << std::endl; std::cout << "result :" << result.out().rdbuf() << std::endl; if (result.joinable()) result.join();
- GCC 8.3.0+
- Clang 10.0+
- Visual Studio 2017+
- C++17 or later
#include <ext/property>
ext::property<size_t> val1;
ext::property<size_t> val2;
ext::property<size_t> total;
val1 = 10;
val2 = 0;
total = val1 + val2;
total.value(); // 10;
val1 = 20;
val2 = 40;
total.value(); // 60
- GCC 8.3.0+
- Clang 10.0+
- Visual Studio 2008 SP1+
- GCC 8.3.0+
- Clang 10.0+
- Visual Studio 2008 SP1+
-
ext::void_result<error_t>
#include <ext/result> #include <errno.h> ext::void_result<error_t> ok_fn() { return ext::ok<void>(); } ext::void_result<error_t> err_fn() { return ext::err(EBUSY); } ext::void_result<error_t> result = ok_fn(); if (result) { // true } result = err_fn(); if (!result) { // false result.error(); // EBUSY }
-
ext::result<int, error_t>
-
Basic
#include <ext/result> #include <errno.h> ext::result<int, error_t> ok_fn() { return ext::ok(10); } ext::result<int, error_t> err_fn() { return ext::err(EBUSY); } ext::result<int, error_t> result = ok_fn(); if (result) { // true result.get(); // 10 } result = err_fn(); if (!result) { // false result.error(); // EBUSY }
-
Error with message
#include <ext/result> #include <errno.h> ext::result<int, error_t> ok_fn() { return ext::ok(10); } ext::result<int, error_t> err_fn() { return ext::err(EBUSY, "I'm busy"); } ext::result<int, error_t> result = ok_fn(); if (result) { // true result.get(); // 10 } try { result.error(); } catch (const ext::result_error &e) { e.what(); // "No error occurred." } result = err_fn(); if (!result) { // false result.error(); // EBUSY } try { result.get(); } catch (const ext::result_error &e) { e.what(); // "I'm busy" } try { result.get(); } catch (const ext::error_occurred &e) { e.what(); // "I'm busy" }
-
- GCC 8.3.0+
- Clang 10.0+
- Visual Studio 2017+
- std::shared_mutex or std::shared_timed_mutex required
- C++14 or later
- GCC 8.3.0+
- Clang 10.0+
- Visual Studio 2008 SP1+ with Boost 1.69.0+
- Visual Studio 2017+
- std::shared_mutex or std::shared_timed_mutex required
- GCC 8.3.0+
- Clang 10.0+
- Visual Studio 2008 SP1+
-
Process A
#include <ext/shared_mem> struct memory_struct0 { int i; int j; }; ext::shared_mem<memory_struct0> st_mem("memory_struct0", shared_mem_all_access); if (st_mem.opened()) { st_mem.destroy(); st_mem.create(); } if (st_mem.created()) { st_mem->i = 10; st_mem->j = 20; }
-
Pocess B
#include <ext/shared_mem> struct memory_struct0 { int i; int j; }; ext::shared_mem<memory_struct0> st_mem("memory_struct0"); if (st_mem.opened()) { st_mem2->i; // 10 st_mem2->j; // 20 }
- GCC 8.3.0+
- Clang 10.0+
- Visual Studio 2008 SP1+
- GCC 8.3.0+
- Clang 10.0+
- Visual Studio 2008 SP1+
-
split
std::vector<std::string> list = ext::split("a,b,c,d", ","); EXPECT_EQ(list.size(), 4); EXPECT_EQ(list[0], "a"); EXPECT_EQ(list[1], "b"); EXPECT_EQ(list[2], "c"); EXPECT_EQ(list[3], "d");
-
u8string
#define CXX_USE_STD_U8STRING #include <ext/string> #if defined(CXX_STD_U8STRING_NOT_SUPPORTED) #if defined(__cpp_user_defined_literals) && \ (CXX_VER >= __cpp_user_defined_literals) std::u8string str = ext::from_u8(u8"한글+english"); EXPECT_STREQ((const char *)str.c_str(), u8"한글+english"); #else std::u8string str = ext::from_u8(ext::to_u8string(L"한글+english")); EXPECT_STREQ((const char *)str.c_str(), "\xED\x95\x9C\xEA\xB8\x80+english"); #endif #else std::u8string str = u8"한글+english"; EXPECT_STREQ(str.c_str(), u8"한글+english"); #endif
- GCC 8.3.0+
- Clang 10.0+
- Visual Studio 2017+
- C++14 or later
- GCC 8.3.0+
- Clang 10.0+
- Visual Studio 2008 SP1+
-
ext::remove_class
#include <ext/type_traits> #include <ext/typeinfo> class test_callable { public: std::string operator()(int, char, std::vector<std::string>) { return "1"; } }; class test_callable_2 { public: void operator()(){}; std::string operator()(int, char, std::vector<std::string>) { return "2"; } }; std::string (test_callable_2::*ptr)(int, char, std::vector<std::string>) = &test_callable_2::operator(); EXPECT_STREQ( ext::get_type_name<ext::remove_class<decltype(ptr)>::type>().c_str(), ext::get_type_name<std::string(int, char, std::vector<std::string>)>() .c_str());
-
ext::deduce_mem_fn
#include <ext/type_traits> #include <ext/typeinfo> auto ld = []() {}; EXPECT_STREQ( ext::get_type_name<void()>().c_str(), ext::get_type_name<ext::deduce_mem_fn<decltype(ld)>::type>().c_str());
- GCC 8.3.0+
- Clang 10.0+
- Visual Studio 2008 SP1+
#include <ext/typeinfo>
ext::get_type_name<void()>();
ext::get_type_name(typeid(std::string));
- SI
- IEC
- GCC 8.3.0+
- Clang 10.0+
- Visual Studio 2008 SP1+
-
to_string
#include <ext/units> // IEC size_t size = 2 * ext::units::IEC::TiB; ext::units::to_string(size, ext::units::POLICY_IEC); // "2TiB" ext::units::to_wstring(size, ext::units::POLICY_IEC); // L"2TiB" ext::units::IEC::to_string(size, ext::units::IEC::KiB); // "2147483648KiB" ext::units::IEC::to_wstring(size, ext::units::IEC::KiB); // L"2147483648KiB" // SI size = 2 * ext::units::SI::tB; ext::units::to_string(size, ext::units::POLICY_SI); // "2tB" ext::units::to_wstring(size, ext::units::POLICY_SI); // L"2tB" ext::units::IEC::to_string(2 * ext::units::IEC::TiB, ext::units::IEC::KiB); // "2147483648KiB" ext::units::IEC::to_wstring(2 * ext::units::IEC::TiB, ext::units::IEC::KiB); // L"2147483648KiB"
-
to_size_t
#include <ext/units> // IEC ext::units::to_size_t("2TiB"); // 2 * ext::units::IEC::TiB ext::units::to_size_t(L"2TiB"); // 2 * ext::units::IEC::TiB // SI ext::units::to_size_t("2tB"); // 2 * ext::units::SI::tB ext::units::to_size_t(L"2tB"); // 2 * ext::units::SI::tB
-
User-defined literals
#include <ext/units> // IEC using namespace ext::units::IEC::literals; size_t value = 5_MiB; EXPECT_EQ(value, 5 * ext::units::IEC::MiB); std::string str = 5_MiB; EXPECT_STREQ(str.c_str(), "5MiB"); std::wstring wstr = 5_MiB; EXPECT_STREQ(wstr.c_str(), L"5MiB"); // SI using namespace ext::units::SI::literals; size_t value = 5_mB; EXPECT_EQ(value, 5 * ext::units::SI::mB); std::string str = 5_mB; EXPECT_STREQ(str.c_str(), "5mB"); std::wstring wstr = 5_mB; EXPECT_STREQ(wstr.c_str(), L"5mB");
- GCC 8.3.0+
- Clang 10.0+
- Visual Studio 2008 SP1+
-
uri
ext::uri u("https://localhost:8443/test"); EXPECT_STREQ(u.scheme.c_str(), "https"); EXPECT_STREQ(u.host.c_str(), "localhost"); EXPECT_EQ(u.port, 8443); EXPECT_STREQ(u.path.c_str(), "/test"); EXPECT_STREQ(u.scheme_host_port().c_str(), "https://localhost:8443"); u = ext::uri("foo://info.example.com?fred"); EXPECT_STREQ(u.scheme.c_str(), "foo"); EXPECT_STREQ(u.host.c_str(), "info.example.com"); EXPECT_TRUE(u.path.empty()); EXPECT_STREQ(u.query.c_str(), "?fred");
-
wuri
ext::wuri u(L"https://localhost:8443/test"); EXPECT_STREQ(u.scheme.c_str(), L"https"); EXPECT_STREQ(u.host.c_str(), L"localhost"); EXPECT_EQ(u.port, 8443); EXPECT_STREQ(u.path.c_str(), L"/test"); EXPECT_STREQ(u.scheme_host_port().c_str(), L"https://localhost:8443"); u = ext::wuri(L"foo://info.example.com?fred"); EXPECT_STREQ(u.scheme.c_str(), L"foo"); EXPECT_STREQ(u.host.c_str(), L"info.example.com"); EXPECT_TRUE(u.path.empty()); EXPECT_STREQ(u.query.c_str(), L"?fred");
-
User-defined literals
#include <ext/uri> using namespace ext::literals; ext::uri u = "http://test.com:1234/test?key=value&key1=value1"_uri; ext::wuri u = L"http://test.com:1234/test?key=value&key1=value1"_uri;
-
encode
#define CXX_USE_STD_U8STRING #include <ext/uri> #if defined(CXX_STD_U8STRING_NOT_SUPPORTED) #if defined(__cpp_user_defined_literals) && \ (CXX_VER >= __cpp_user_defined_literals) const std::u8string uri_u8str = ext::from_u8(u8"https://www.google.com/search?q=한글+english"); #else const std::u8string uri_u8str =ext::to_u8string(L"https://www.google.com/search?q=한글+english"); #endif #else const std::u8string uri_u8str = u8"https://www.google.com/search?q=한글+english"; #endif ext::uri u(uri_u8str); ext::wuri u(uri_u8str);
- GCC 8.3.0+
- Clang 10.0+
- Visual Studio 2008 SP1+ with Boost 1.69.0+
- Visual Studio 2010+
- std::regex required
-
Basic
ext::version v("a.b.c"); // std::invalid_argument ext::version v("0.0.4"); v.major(); // 0 v.minor(); // 0 v.patch(); // 4 v.released(); // true v.prerelease(); // "" v.build_metadata(); // "" ext::version v("1.1.2-prerelease+meta"); v.major(); // 1 v.minor(); // 1 v.patch(); // 2 v.released(); // false v.prerelease(); // "prerelease" v.build_metadata(); // "meta"
-
std::hash
std::unordered_map<ext::version, std::string> map = { {ext::version("1.2.3"), "abc"}, {ext::version("5.0.0"), "def"}, {ext::version("1.2.3-prerelease"), "ghi"}, }; auto it = map.find(ext::version("1.2.3")); EXPECT_EQ(it->second, "abc"); it = map.find(ext::version("5.0.0")); EXPECT_NE(it, map.end()); EXPECT_EQ(it->second, "def"); it = map.find(ext::version("1.2.0")); EXPECT_EQ(it, map.end()); it = map.find(ext::version("1.2.3-prerelease")); EXPECT_NE(it, map.end()); EXPECT_EQ(it->second, "ghi"); it = map.find(ext::version("1.2.3-prerelease+meta")); EXPECT_NE(it, map.end()); EXPECT_EQ(it->second, "ghi"); it = map.find(ext::version("1.2.3-test+meta")); EXPECT_EQ(it, map.end());
Expands environment-variable strings and replaces them with the values defined for the current user.
- GCC 8.3.0+
- Clang 10.0+
- Visual Studio 2008 SP1+
#if defined(_WIN32)
std::string system_drive = ext::wordexp("%SYSTEMDRIVE%");
std::string windir = ext::wordexp("%WINDIR%");
std::string user_profile = ext::wordexp("%USERPROFILE%");
std::string user_name = ext::wordexp("%USERNAME%");
#else
std::string home_path = ext::wordexp("$HOME");
std::string user = ext::wordexp("$USER");
#endif
- Default
- CMAKE_CXX_STANDARD=17
- CMAKE_BUILD_TYPE=Debug
- Examples
- cmake -DCMAKE_CXX_STANDARD=11 ..
- cmake -DCMAKE_CXX_STANDARD=14 ..
- cmake -DCMAKE_CXX_STANDARD=17 ..
- cmake -G "Visual Studio 10 2010" -DCXX_USE_BOOST=On ..
- cmake -DEXT_NO_WIN32_EX=On ..
cd test
mkdir build && cd build
cmake ..
cmake --build .
ctest . -C Debug --verbose
pacman -Syu
pacman -Su
pacman -S --needed base-devel git
case "${MSYSTEM}" in
"MINGW32") pacman -S --needed mingw-w64-i686-toolchain mingw-w64-i686-cmake;;
"MINGW64") pacman -S --needed mingw-w64-x86_64-toolchain mingw-w64-x86_64-cmake;;
"CLANG32") pacman -S --needed mingw-w64-clang-i686-toolchain mingw-w64-clang-i686-cmake;;
"CLANG64") pacman -S --needed mingw-w64-clang-x86_64-toolchain mingw-w64-clang-x86_64-cmake;;
"CLANGARM64") pacman -S --needed mingw-w64-clang-aarch64-toolchain mingw-w64-clang-aarch64-cmake;;
"UCRT64") pacman -S --needed mingw-w64-ucrt-x86_64-toolchain mingw-w64-ucrt-x86_64-cmake;;
"MSYS") pacman -S --needed gcc cmake;;
*) pacman -S --needed gcc cmake;;
esac
cd test
mkdir build && cd build
if [ "$MSYSTEM" = "MSYS" ]; then
cmake ..
else
cmake -G "MinGW Makefiles" ..
fi
cmake --build .
export LC_ALL=C; unset LANGUAGE
ctest . --verbose
cd test
mkdir build && cd build
cmake ..
cmake --build .
ctest . --verbose
cmake_minimum_required(VERSION 3.14 FATAL_ERROR)
# create project
project(MyProject)
# add executable
add_executable(tests tests.cpp)
# add dependencies
include(cmake/CPM.cmake)
CPMAddPackage("gh:ntoskrnl7/ext@0.5.17")
# link dependencies
target_link_libraries(tests ext)