The Wayback Machine - https://web.archive.org/web/20230203051723/https://github.com/ntoskrnl7/ext
Skip to content

ntoskrnl7/ext

master
Switch branches/tags

Name already in use

A tag already exists with the provided branch name. Many Git commands accept both tag and branch names, so creating this branch may cause unexpected behavior. Are you sure you want to create this branch?
Code

Latest commit

 

Git stats

Files

Permalink
Failed to load latest commit information.
Type
Name
Latest commit message
Commit time
 
 
 
 
 
 
 
 
 
 
 
 
 
 

ext

C++ Extended Template Library

CMake MSYS2 GitHub GitHub release (latest SemVer) Windows 7+ Linux gcc 8.3.0+ macOS 10.11+ Visual Studio 2008 SP1+ MSYS2 MSYS MSYS2 MinGW 32 bit MSYS2 MinGW 64 bit MSYS2 Clang 32 bit MSYS2 Clang 64 bit MSYS2 MinGW UCRT 64 bit CMake 3.14+ C++ 03+

Requirements

  • GCC 8.3.0+
  • Clang 10.0+
  • Visual Studio 2008 SP1+
  • Boost 1.69.0++ (optional)
  • Git 2.0+
  • CMake 3.14+

Contents

Test Environments

  • 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

Features

any_function

Requirements

  • GCC 8.3.0+
  • Clang 10.0+
  • Visual Studio 2017+
  • std::any required
  • if constexpr required

Examples

#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);

async_result

Requirements

  • GCC 8.3.0+
  • Clang 10.0+
  • Visual Studio 2008 SP1+ with Boost 1.69.0+
  • Visual Studio 2017+

Examples

#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) {
    ...
}

base64

Requirements

  • GCC 8.3.0+
  • Clang 10.0+
  • Visual Studio 2008 SP1+

Examples

  • 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"

callback

Requirements

  • GCC 8.3.0+
  • Clang 10.0+
  • Visual Studio 2008 SP1+ with Boost 1.69.0+
  • Visual Studio 2017+

Examples

  • 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

cancelable_thread

Requirements

  • GCC 8.3.0+
  • Clang 10.0+
  • Visual Studio 2008 SP1+ with Boost 1.69.0+
  • Visual Studio 2017+

Examples

  • 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()) ...

cdbg

Requirements

  • GCC 8.3.0+
  • Clang 10.0+
  • Visual Studio 2008 SP1+

Examples

  • 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";

chain

Requirements

  • GCC 8.3.0+
  • Clang 10.0+
  • Visual Studio 2008 SP1+

Examples

  • 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"

debug_utils

Requirements

  • GCC 8.3.0+
  • Clang 10.0+
  • Visual Studio 2008 SP1+

Examples

  • Wait for debugger (C/C++)

    #include <ext/debug_utils>
    
    wait_for_debugger(100);
    
    if (is_debugger_present()) {
        ...
    }
    
    msleep(500);

collection

Requirements

  • 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

Examples

  • 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

ini

Requirements

  • GCC 8.3.0+
  • Clang 10.0+
  • Visual Studio 2008 SP1+ with Boost 1.69.0+
  • Visual Studio 2010+
  • std::regex required

Examples

  • 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

lang

Requirements

  • GCC 8.3.0+
  • Clang 10.0+
  • Visual Studio 2008 SP1+

Examples

  • 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"세 번");

observable

Requirements

  • 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

Examples

path

Requirements

  • GCC 8.3.0+
  • Clang 10.0+
  • Visual Studio 2008 SP1+

Examples

#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");

pipe

Requirements

  • GCC 8.3.0+
  • Clang 10.0+
  • Visual Studio 2008 SP1+

Examples

#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();

process

Requirements

  • GCC 8.3.0+
  • Clang 10.0+
  • Visual Studio 2008 SP1+

Examples

  • 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();

property

Requirements

  • GCC 8.3.0+
  • Clang 10.0+
  • Visual Studio 2017+
  • C++17 or later

Examples

#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

pstream

Requirements

  • GCC 8.3.0+
  • Clang 10.0+
  • Visual Studio 2008 SP1+

Examples

result

Requirements

  • GCC 8.3.0+
  • Clang 10.0+
  • Visual Studio 2008 SP1+

Examples

  • 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"
      }

safe_object

Requirements

  • GCC 8.3.0+
  • Clang 10.0+
  • Visual Studio 2017+
  • std::shared_mutex or std::shared_timed_mutex required
  • C++14 or later

Examples

shared_recursive_mutex

Requirements

  • 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

Examples

shared_mem

Requirements

  • GCC 8.3.0+
  • Clang 10.0+
  • Visual Studio 2008 SP1+

Examples

  • 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
    }

singleton

Requirements

  • GCC 8.3.0+
  • Clang 10.0+
  • Visual Studio 2008 SP1+

Examples

string

Requirements

  • GCC 8.3.0+
  • Clang 10.0+
  • Visual Studio 2008 SP1+

Examples

  • 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

stl_compat

thread_pool

Requirements

  • GCC 8.3.0+
  • Clang 10.0+
  • Visual Studio 2017+
  • C++14 or later

Examples

type_traits

Requirements

  • GCC 8.3.0+
  • Clang 10.0+
  • Visual Studio 2008 SP1+

Examples

  • 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());

typeinfo

Requirements

  • GCC 8.3.0+
  • Clang 10.0+
  • Visual Studio 2008 SP1+

Examples

#include <ext/typeinfo>

ext::get_type_name<void()>();

ext::get_type_name(typeid(std::string));

units

  • SI
  • IEC

Requirements

  • GCC 8.3.0+
  • Clang 10.0+
  • Visual Studio 2008 SP1+

Examples

  • 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");

uri

Requirements

  • GCC 8.3.0+
  • Clang 10.0+
  • Visual Studio 2008 SP1+

Examples

  • 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);

version

Semantic Versioning

Requirements

  • GCC 8.3.0+
  • Clang 10.0+
  • Visual Studio 2008 SP1+ with Boost 1.69.0+
  • Visual Studio 2010+
  • std::regex required

Examples

  • 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());

wordexp

Expands environment-variable strings and replaces them with the values defined for the current user.

Requirements

  • GCC 8.3.0+
  • Clang 10.0+
  • Visual Studio 2008 SP1+

Examples

#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

Test

Windows

Visual Studio

  • 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

MSYS or MinGW(32/64/CLANG32/CLANG64/CLANGARM64/UCRT64)

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

Linux or macOS

cd test
mkdir build && cd build
cmake ..
cmake --build .
ctest . --verbose

Usage

CMakeLists.txt

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)