├── CONTRIBUTING.md ├── FutureExecutor └── FutureExecutorsThen.cpp ├── LICENSE ├── Presentations └── cppcon2019 │ ├── polymorphism.md │ └── polymorphism_presentation.html ├── README.md ├── cpp20_sql ├── cpp20_sql.md ├── example.cpp └── tagged_sqlite.h ├── cpp20_tagged_tuple ├── CMakeLists.txt ├── example.cpp ├── soa_vector.h ├── tagged_tuple.h ├── tagged_tuple_test.cpp └── to_from_nlohmann_json.h ├── futures └── futures.cpp ├── iterators-algorithms-ranges └── algorithm.cpp ├── meta_struct_20 └── cppcon_version │ ├── CMakeLists.txt │ ├── fixed_string.cpp │ ├── meta_struct.h │ ├── meta_struct_1.cpp │ ├── meta_struct_applications_10.cpp │ ├── meta_struct_attributes_9.cpp │ ├── meta_struct_constructed_2.cpp │ ├── meta_struct_conversion_8.cpp │ ├── meta_struct_example_11.cpp │ ├── meta_struct_init_3.cpp │ ├── meta_struct_init_self_4.cpp │ ├── meta_struct_optional_arguments_6.cpp │ ├── meta_struct_print_5.cpp │ ├── meta_struct_required_named_args_7.cpp │ ├── meta_struct_sqlite.h │ ├── meta_struct_sqlite_example.cpp │ └── struct.cpp ├── metaprogrammed_polymorphism ├── benchmark.cpp ├── benchmark_imp.cpp ├── benchmark_imp.h ├── entity_examples │ ├── overload.cpp │ ├── polymorphic.cpp │ ├── regular.cpp │ └── virtual.cpp ├── example.cpp ├── polymorphic.hpp └── polymorphic_test.cpp ├── metaprogramming_examples └── metaprogramming_examples.cpp ├── mutex_condition └── mutex_condition.cpp ├── polymorphism ├── crtp │ └── crtp.cpp ├── inheritance │ ├── inheritance.cpp │ ├── shape_drawer.cpp │ ├── shape_drawer.hpp │ ├── shapes.hpp │ └── shapes_interface.hpp ├── overloading │ └── overloading.cpp └── regular_polymorphism │ ├── regular_polymorphism.cpp │ ├── shapes.hpp │ ├── shapes_drawer.cpp │ ├── shapes_drawer.hpp │ └── shapes_interface.hpp ├── rust ├── .gitignore ├── Cargo.lock ├── Cargo.toml ├── tagged_rusqlite │ ├── Cargo.toml │ ├── README.md │ └── src │ │ └── lib.rs ├── tagged_rusqlite_example │ ├── Cargo.toml │ └── src │ │ ├── lib.rs │ │ └── main.rs ├── tagged_rusqlite_proc │ ├── Cargo.toml │ └── src │ │ └── lib.rs └── tagged_rusqlite_proc_impl │ ├── Cargo.toml │ └── src │ ├── lib.rs │ └── main.rs ├── rust_gmail_sorter ├── Cargo.lock ├── Cargo.toml └── src │ └── main.rs ├── scratch └── actions │ ├── CMakeLists.txt │ └── main.cpp ├── sfinae └── sfinae.cpp ├── simple_type_name ├── example.cpp └── simple_type_name.h ├── string └── string.cpp ├── tafn ├── 1521R0.pdf ├── example.cpp ├── tafn.hpp └── tafn.md ├── tagged_sqlite ├── CMakeLists.txt ├── example.cpp └── tagged_sqlite.h ├── tagged_tuple ├── example.cpp └── tagged_tuple.h ├── template-meta-programming └── fibonacci.cpp ├── units ├── units.hpp └── units_example.cpp └── variadics_examples ├── tuple_no_variadics_hard_coded_index.cpp ├── tuple_no_variadics_no_index_get.cpp ├── tuple_no_variadics_sequence_index.cpp ├── tuple_variadics.cpp ├── tuple_variadics_print_fold.cpp ├── tuple_variadics_print_recursive.cpp ├── tuple_variadics_reverse_recursive.cpp └── tuple_variadics_reverse_sequence.cpp /FutureExecutor/FutureExecutorsThen.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | template 11 | class mtq { 12 | public: 13 | mtq(std::size_t max_size) : max_size_(max_size) {} 14 | 15 | void push(T t) { 16 | std::unique_lock lock{mut_}; 17 | for (;;) { 18 | if (q_.size() < max_size_) { 19 | q_.push(std::move(t)); 20 | cvar_.notify_all(); 21 | return; 22 | } else { 23 | cvar_.wait(lock); 24 | } 25 | } 26 | } 27 | 28 | std::optional pop() { 29 | std::unique_lock lock{mut_}; 30 | for (;;) { 31 | if (!q_.empty()) { 32 | T t = q_.front(); 33 | q_.pop(); 34 | cvar_.notify_all(); 35 | return t; 36 | } else { 37 | if (done_) return std::nullopt; 38 | cvar_.wait(lock); 39 | } 40 | } 41 | } 42 | 43 | bool done() const { 44 | std::unique_lock lock{mut_}; 45 | return done_; 46 | } 47 | 48 | void set_done() { 49 | std::unique_lock lock{mut_}; 50 | done_ = true; 51 | cvar_.notify_all(); 52 | } 53 | 54 | private: 55 | std::size_t max_size_ = 0; 56 | bool done_ = false; 57 | std::queue q_; 58 | mutable std::mutex mut_; 59 | mutable std::condition_variable cvar_; 60 | }; 61 | 62 | #include 63 | 64 | class thread_pool { 65 | public: 66 | thread_pool() : q_(std::numeric_limits::max() - 1) { add_thread(); } 67 | ~thread_pool() { 68 | q_.set_done(); 69 | for (auto& thread : threads_) { 70 | if (thread.joinable()) { 71 | thread.join(); 72 | } 73 | } 74 | } 75 | 76 | void add(std::function f) { q_.push(std::move(f)); } 77 | 78 | void add_thread() { 79 | std::unique_lock lock{mut_}; 80 | threads_.emplace_back([this]() mutable { 81 | while (true) { 82 | auto f = q_.pop(); 83 | if (f) { 84 | (*f)(); 85 | } else { 86 | if (q_.done()) return; 87 | } 88 | } 89 | }); 90 | } 91 | 92 | private: 93 | mtq> q_; 94 | std::mutex mut_; 95 | std::vector threads_; 96 | }; 97 | 98 | template 99 | struct shared { 100 | T value; 101 | std::exception_ptr eptr = nullptr; 102 | std::mutex mutex; 103 | std::condition_variable cvar; 104 | bool done = false; 105 | std::function then; 106 | std::shared_ptr pool; 107 | }; 108 | 109 | template 110 | class future { 111 | public: 112 | void wait() { 113 | std::unique_lock lock{shared_->mutex}; 114 | while (!shared_->done) { 115 | shared_->cvar.wait(lock); 116 | } 117 | } 118 | template 119 | auto then(F f) -> future; 120 | 121 | T& get() { 122 | wait(); 123 | if (shared_->eptr) { 124 | std::rethrow_exception(shared_->eptr); 125 | } 126 | return shared_->value; 127 | } 128 | 129 | explicit future(const std::shared_ptr>& shared) : shared_(shared) {} 130 | 131 | private: 132 | std::shared_ptr> shared_; 133 | }; 134 | 135 | template 136 | void run_then(std::unique_lock lock, 137 | std::shared_ptr>& s) { 138 | std::function f; 139 | if (s->done) { 140 | std::swap(f, s->then); 141 | } 142 | lock.unlock(); 143 | if (f) f(); 144 | } 145 | 146 | template 147 | class promise { 148 | public: 149 | promise() : shared_(std::make_shared>()) {} 150 | template 151 | void set_value(V&& v) { 152 | std::unique_lock lock{shared_->mutex}; 153 | shared_->value = std::forward(v); 154 | shared_->done = true; 155 | run_then(std::move(lock), shared_); 156 | shared_->cvar.notify_one(); 157 | shared_ = nullptr; 158 | } 159 | void set_exception(std::exception_ptr eptr) { 160 | std::unique_lock lock{shared_->mutex}; 161 | shared_->eptr = eptr; 162 | shared_->done = true; 163 | run_then(std::move(lock), shared_); 164 | shared_->cvar.notify_one(); 165 | shared_ = nullptr; 166 | } 167 | 168 | future get_future() { return future{shared_}; } 169 | 170 | explicit promise(const std::shared_ptr>& shared) 171 | : shared_(shared) {} 172 | 173 | private: 174 | std::shared_ptr> shared_; 175 | }; 176 | 177 | template 178 | template 179 | auto future::then(F f) -> future { 180 | std::unique_lock lock{shared_->mutex}; 181 | using type = decltype(f(*this)); 182 | auto then_shared = std::make_shared>(); 183 | then_shared->pool = shared_->pool; 184 | shared_->then = [shared = shared_, then_shared, f = std::move(f), 185 | pool = shared_->pool]() mutable { 186 | pool->add([shared, then_shared, f = std::move(f), 187 | p = promise(then_shared)]() mutable { 188 | future fut(shared); 189 | try { 190 | p.set_value(f(fut)); 191 | } catch (...) { 192 | p.set_exception(std::current_exception()); 193 | } 194 | }); 195 | }; 196 | run_then(std::move(lock), shared_); 197 | return future(then_shared); 198 | } 199 | 200 | template 201 | auto async(std::shared_ptr pool, F f, Args... args) 202 | -> future { 203 | using T = decltype(f(args...)); 204 | auto state = std::make_shared>(); 205 | state->pool = pool; 206 | promise p(state); 207 | auto fut = p.get_future(); 208 | auto future_func = [p = std::move(p), f = std::move(f), args...]() mutable { 209 | try { 210 | p.set_value(f(args...)); 211 | } catch (...) { 212 | p.set_exception(std::current_exception()); 213 | } 214 | }; 215 | pool->add(std::move(future_func)); 216 | return fut; 217 | } 218 | 219 | #include 220 | int main() { 221 | auto pool = std::make_shared(); 222 | pool->add([]() { std::cout << "Hi from thread pool\n"; }); 223 | auto f = async(pool, []() { 224 | std::cout << "Hello\n"; 225 | return 1; 226 | }); 227 | auto f2 = f.then([](auto& f) { 228 | std::cout << f.get() << " World\n"; 229 | return 2.0; 230 | }); 231 | f2.get(); 232 | } 233 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # C++ From The Sky Down - Libraries and Examples 2 | 3 | This repository will hold explanations, documentations,examples and libraries developed for C++ From The Sky 4 | Down. 5 | 6 | C++ From the Sky Down is a series designed to present C++ as a high-level language and to show techniques and libraries (including some developed during this course) to use C++ as a high level language while hiding the low-level stuff. 7 | 8 | This will use C++17 and C++20 (as they become available) features. 9 | 10 | More explanations/documentations/examples/libraries will be added as the series progresses. 11 | 12 | g/cpp-from-the-sky-down 13 | 14 | This is not an officially supported Google product. 15 | -------------------------------------------------------------------------------- /cpp20_sql/cpp20_sql.md: -------------------------------------------------------------------------------- 1 | 2 | # A thin, typesafe SQL wrapper in C++20 3 | 4 | For data accessing databases, SQL is the champ. It is cross-platform and cross database. There is a ton of information online, and you can probably find an SQL snippet to do almost anything. 5 | 6 | In addition, SQL has a nice property, in that you can typically develop and debug it an interactive manner by using the database environment. You can quickly run a query, and check that you are getting the expected result. The REPL(read, eavaluate, print loop) makes for quick development. 7 | 8 | Now that we have a working SQL query. How do we get it into C++. There are a whole host of existing solutions. However, they often fall short in a few areas: 9 | 10 | * Typesafe SQL columns and parameters. We would like compile time typesafety when we are reading the results and when we bind parameters to our parameterized queries. 11 | 12 | * Be able to copy and paste working SQL without too much modification and with no external code generators. 13 | 14 | * No macros 15 | 16 | C++20 provides us with improved compile time features that can allow us to accomplish these goals. 17 | 18 | The code can be found here: [https://github.com/google/cpp-from-the-sky-down/tree/master/cpp20_sql] 19 | 20 | `tagged_sqlite.h` is a single self-contained header with no depedencies other than the C++ standard library and SQLite. 21 | 22 | `example.cpp` is an example program. 23 | 24 | Note: This is *not* an officially supported Google library. 25 | 26 | Also, it is only at a proof of concept state, and *not* ready for use in production. 27 | 28 | Currently, only GCC 10 supports enough of C++20 to be able to use the library 29 | 30 | The library lives in the `skydown` namespace, with the user defined literals in `skydown::literals`. 31 | 32 | To illustrate, let us do a quick `customers` and `orders` database. 33 | 34 | Assume we have the following tables from SQL: 35 | 36 | 37 | ``` sql 38 | CREATE TABLE customers( 39 | id INTEGER NOT NULL PRIMARY KEY, 40 | name TEXT NOT NULL" 41 | ); 42 | ``` 43 | 44 | ``` sql 45 | CREATE TABLE orders( 46 | id INTEGER NOT NULL PRIMARY KEY, 47 | item TEXT NOT NULL, 48 | customerid INTEGER NOT NULL, 49 | price REAL NOT NULL, 50 | discount_code TEXT 51 | ); 52 | ``` 53 | 54 | Now we want to find all the orders that are above a certain price and join them with the customer's name. 55 | 56 | ```sql 57 | SELECT orders.id, name, item, price, 58 | discount_code 59 | FROM orders JOIN customers ON customers.id = customerid 60 | WHERE price > 100; 61 | 62 | ``` 63 | 64 | This will give us a list of of orders. 65 | 66 | Now in a program, we want to be able to specify our minimum price at runtime, instead of hard coding. 67 | 68 | The temptation would be to use string substitution. However, that is the wrong answer, as it opens you up to all sorts of SQL injection attacks. Instead you want to do parameterized queries. 69 | 70 | ```sql 71 | SELECT orders.id, name, item, price, 72 | discount_code 73 | FROM orders JOIN customers ON customers.id = customerid 74 | WHERE price > ?; 75 | ``` 76 | 77 | This is the syntax for a parameterized query that we use with a prepared statement. Then we just bind the value we want to our parameter and execute the statement. 78 | 79 | Now let us see what the code looks like to do this query and get the results. 80 | 81 | ```c++ 82 | skydown::prepared_statement< 83 | "SELECT orders.id:integer, name:text, item:text, price:real, " 84 | "discount_code:text? " 85 | "FROM orders JOIN customers ON customers.id = customerid " 86 | "WHERE price > ?min_price:real;" 87 | >select_orders{sqldb}; 88 | ``` 89 | 90 | Here we are construction an object of template class `skydown::prepared_statement` passing our SQL query as the template parameter. 91 | 92 | However, if we look closely at the query string, we will notice it is slightly different from the SQL string. 93 | 94 | Instead of `orders.id,` in the SQL string, we have `orders.id:integer`. Also, instead of `?` for the parameters, we have `?min_price:real` 95 | 96 | What is going on here? 97 | 98 | Turns out, if we can just annotate the resulting columns with types, and the parameters with names and types, we can have nicely named and typed input and output for the query, and treat the rest of the query as a black box. 99 | 100 | The library uses those annotations to construct tags with types for parameters and fields. 101 | 102 | Prior to sending the query to the SQL engine, it strips out the annotations. 103 | 104 | This allows us to not have to care about the internals of what the SQL statement is doing. We just care about the inputs (which are the annotated parameters) and the outputs(which are the annotated selected columns). 105 | 106 | Here is the list of currently supported types: 107 | 108 | * `:text` ==> `std::string_view` 109 | * `:integer` ==> `std::int64_t` 110 | * `:real` ==> `double` 111 | 112 | You can add a `?` to the end of the type to make it `std::optional` 113 | For example `:real?` would map to `std::optional`. 114 | 115 | Let us see how we use this in our C++ code. 116 | 117 | ```c++ 118 | for (auto &row : 119 | select_orders.execute_rows("min_price"_param = 100)) { 120 | std::cout << row["orders.id"_col] << " "; 121 | std::cout << row["price"_col] << " "; 122 | std::cout << row["name"_col] << " "; 123 | std::cout << row["item"_col] << " "; 124 | std::cout << row["discount_code"_col].value_or("") << "\n"; 125 | } 126 | 127 | ``` 128 | Here we are calling the `execute_rows` member function of our `select orders` object, passing in the parameters. `_param` is a user defined string literal in namespace `skydown::literals`. If a parameter is not specified, or an incorrect string is used, or if an incorrect type is used, you will get a compile time error. 129 | 130 | 131 | In our query for `select_orders` we had `?min_price:real` so if we assign a value `"min_price"_param` that cannot be converted to a `double` we will get a compile time error. 132 | 133 | We use a `range for` loop to iterate ther eturned rows. `_col` is another used defined string literal, and we index the `row` object using the string literal. Again, if we have the wrong name, it is a compile time error. In addition, the returned values have the correct type according to our annotated SQL statement. 134 | 135 | * `orders.id:integer` ==> `std::int64_t` 136 | * `price:real` ==> `double` 137 | * `name:text` ==> `std::string_view` 138 | * `item:text` ==> `std::string_view` 139 | * `discount_code:text?` ==> `std::optional` 140 | 141 | What happens, if we mess up and type the wrong column name. 142 | 143 | To see what happens, I changed `discount_code` to `discount_core` in the following expression: 144 | 145 | ```c++ 146 | std::cout << row["discount_core"_col].value_or("") << "\n"; 147 | ``` 148 | 149 | I get a compiler error which includes the following output. 150 | 151 | ``` 152 | 1>C:\Users\johnb\source\repos\cpp-from-the-sky-down\cpp20_sql\tagged_sqlite.h(220,16): message : template argument deduction/substitution failed: 153 | 1>C:\Users\johnb\source\repos\cpp-from-the-sky-down\cpp20_sql\tagged_sqlite.h(228,20): message : 'skydown::sqlite_experimental::fixed_string<13>{"discount_core"}' is not equivalent to 'skydown::sqlite_experimental::fixed_string<9>{"orders.id"}' 154 | 1>C:\Users\johnb\source\repos\cpp-from-the-sky-down\cpp20_sql\tagged_sqlite.h(228,20): message : 'skydown::sqlite_experimental::fixed_string<13>{"discount_core"}' is not equivalent to 'skydown::sqlite_experimental::fixed_string<4>{"name"}' 155 | 1>C:\Users\johnb\source\repos\cpp-from-the-sky-down\cpp20_sql\tagged_sqlite.h(228,20): message : 'skydown::sqlite_experimental::fixed_string<13>{"discount_core"}' is not equivalent to 'skydown::sqlite_experimental::fixed_string<4>{"item"}' 156 | 1>C:\Users\johnb\source\repos\cpp-from-the-sky-down\cpp20_sql\tagged_sqlite.h(228,20): message : 'skydown::sqlite_experimental::fixed_string<13>{"discount_core"}' is not equivalent to 'skydown::sqlite_experimental::fixed_string<5>{"price"}' 157 | 1>C:\Users\johnb\source\repos\cpp-from-the-sky-down\cpp20_sql\tagged_sqlite.h(228,20): message : 'skydown::sqlite_experimental::fixed_string<13>{"discount_core"}' is not equivalent to 'skydown::sqlite_experimental::fixed_string<13>{"discount_code"}' 158 | 159 | 160 | ``` 161 | 162 | Notice how it is is showing us the typo, `discount_core` and showing us the actual columns: `orders.id`, `name`, `item`, `price`, `discount_code`. 163 | 164 | 165 | Next time, we will talk a bit more about using the library, and start looking at some of the techniques used in implementing it. 166 | 167 | If you want to play with this code, you can just compile `example.cpp` with `g++10` and link to `sqlite3`. 168 | 169 | One of the nice things about this kind of approach, is that the library can be agnostic to the actual SQL. This allows it to be relatively small (around 600 lines of code, about half of which is interfacing to SQLite3) as well as be able to support all the features of a database, because we are just passing in SQL to be executed by the engine. 170 | 171 | In addition, because the SQL query is a compile time string, you cannot get runtime SQL injection attacks. 172 | 173 | Right now, only SQLite is supported, but I plan on separating out SQLite from the library and supporting multiple databases such as MySQL and Postgres SQL. 174 | 175 | Please feel let me know what you think in the comments. 176 | 177 | 178 | 179 | 180 | -------------------------------------------------------------------------------- /cpp20_sql/example.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2020 Google LLC 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // https://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | #include "tagged_sqlite.h" 16 | 17 | #include 18 | int main() { 19 | using ftsd::bind; 20 | using ftsd::field; 21 | 22 | sqlite3 *sqldb; 23 | sqlite3_open(":memory:", &sqldb); 24 | 25 | ftsd::prepared_statement< 26 | "CREATE TABLE customers(" 27 | "id INTEGER NOT NULL PRIMARY KEY, " 28 | "name TEXT NOT NULL" 29 | ");" // 30 | >{sqldb} 31 | .execute(); 32 | 33 | ftsd::prepared_statement< 34 | "CREATE TABLE orders(" 35 | "id INTEGER NOT NULL PRIMARY KEY," 36 | "item TEXT NOT NULL, " 37 | "customerid INTEGER NOT NULL," 38 | "price REAL NOT NULL, " 39 | "discount_code TEXT " 40 | ");" // 41 | >{sqldb} 42 | .execute(); 43 | 44 | ftsd::prepared_statement< 45 | "INSERT INTO customers(name) " 46 | "VALUES(? /*:name:text*/);" // 47 | >{sqldb} 48 | .execute({bind<"name">("John")}); 49 | 50 | auto customer_id_or = ftsd::prepared_statement< 51 | "select id/*:integer*/ from customers " 52 | "where name = ? /*:name:text*/;" // 53 | > 54 | {sqldb}.execute_single_row({bind<"name">("John")}); 55 | 56 | if(!customer_id_or){ 57 | std::cerr << "Unable to find customer name\n"; 58 | return 1; 59 | } 60 | auto customer_id = field<"id">(customer_id_or.value()); 61 | 62 | ftsd::prepared_statement< 63 | "INSERT INTO orders(item , customerid , price, discount_code ) " 64 | "VALUES (?/*:item:text*/, ?/*:customerid:integer*/, ?/*:price:real*/, " 65 | "?/*:discount_code:text?*/ );" // 66 | > 67 | insert_order{sqldb}; 68 | 69 | insert_order.execute({bind<"item">("Phone"), bind<"price">(1444.44), 70 | bind<"customerid">(customer_id)}); 71 | insert_order.execute({bind<"item">("Laptop"), bind<"price">(1300.44), 72 | bind<"customerid">(customer_id)}); 73 | insert_order.execute({bind<"customerid">(customer_id), bind<"price">(2000), 74 | bind<"item">("MacBook"), 75 | ftsd::bind<"discount_code">("BIGSALE")}); 76 | 77 | ftsd::prepared_statement< 78 | "SELECT orders.id /*:integer*/, name/*:text*/, item/*:text*/, price/*:real*/, " 79 | "discount_code/*:text?*/ " 80 | "FROM orders JOIN customers ON customers.id = customerid " 81 | "WHERE price > ?/*:min_price:real*/;"> 82 | select_orders{sqldb}; 83 | 84 | for (;;) { 85 | std::cout << "Enter min price.\n"; 86 | double min_price = 0; 87 | std::cin >> min_price; 88 | 89 | for (auto &row : 90 | select_orders.execute_rows({bind<"min_price">(min_price)})) { 91 | // Access the fields using by indexing the row with the column (`_col`). 92 | // We will get a compiler error if we try to access a column that is not 93 | // part of the select statement. 94 | std::cout << field<"orders.id">(row) << " "; 95 | std::cout << field<"price">(row) << " "; 96 | std::cout << field<"name">(row) << " "; 97 | std::cout << field<"item">(row) << " "; 98 | std::cout << ftsd::field<"item">(row) << " "; 99 | std::cout << field<"discount_code">(row).value_or("") << "\n"; 100 | } 101 | } 102 | } 103 | -------------------------------------------------------------------------------- /cpp20_tagged_tuple/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # CMakeList.txt : CMake project for tagged_sqlite, include source and define 2 | # project specific logic here. 3 | # 4 | cmake_minimum_required (VERSION 3.8) 5 | 6 | project(cpp20_tagged_struct) 7 | 8 | set(CMAKE_CXX_STANDARD 20) 9 | set(CMAKE_CXX_STANDARD_REQUIRED ON) 10 | find_package(GTest CONFIG REQUIRED) 11 | find_package(Threads REQUIRED) 12 | find_package(Boost REQUIRED) 13 | 14 | 15 | # Add source to this project's executable. 16 | add_executable (tagged_tuple_test "tagged_tuple_test.cpp" "tagged_tuple.h" "to_from_nlohmann_json.h") 17 | target_link_libraries(tagged_tuple_test PRIVATE GTest::gtest GTest::gtest_main Boost::boost) 18 | 19 | add_executable (example "example.cpp" "tagged_tuple.h" "to_from_nlohmann_json.h") 20 | target_link_libraries (example PRIVATE Boost::boost) 21 | 22 | 23 | 24 | 25 | 26 | # TODO: Add tests and instal l targets if needed. 27 | -------------------------------------------------------------------------------- /cpp20_tagged_tuple/example.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | 6 | #include "tagged_tuple.h" 7 | #include "soa_vector.h" 8 | 9 | using ftsd::get; 10 | using ftsd::tagged_tuple; 11 | using namespace ftsd::literals; 12 | using ftsd::auto_; 13 | using ftsd::member; 14 | using ftsd::tag; 15 | 16 | using test_arguments = 17 | tagged_tuple, // Required argument. 18 | member<"b", auto_, [](auto& t) { return get<"a">(t) + 2; }>, 19 | member<"c", auto_, [](auto& t) { return get<"b">(t) + 2; }>, 20 | member<"d", auto_, []() { return 5; }>>; 21 | 22 | void test(test_arguments args) { 23 | std::cout << get<"a">(args) << "\n"; 24 | std::cout << get<"b">(args) << "\n"; 25 | std::cout << get<"c">(args) << "\n"; 26 | std::cout << get<"d">(args) << "\n"; 27 | } 28 | 29 | template 30 | void print(const T& t) { 31 | auto f = [](auto&&... m) { 32 | auto print = [](auto& m) { 33 | std::cout << m.key() << ": " << m.value() << "\n"; 34 | }; 35 | (print(m), ...); 36 | }; 37 | std::cout << "{\n"; 38 | t.apply(f); 39 | std::cout << "}\n"; 40 | } 41 | 42 | template 43 | auto make_ref(TaggedTuple& t) { 44 | return ftsd::tagged_tuple_ref_t(t); 45 | } 46 | 47 | using ftsd::soa_vector; 48 | void soa_vector_example(){ 49 | using Person = tagged_tuple< 50 | member<"name",std::string>, 51 | member<"address",std::string>, 52 | member<"id", std::int64_t>, 53 | member<"score", double>>; 54 | 55 | soa_vector v; 56 | 57 | v.push_back(Person{tag<"name"> = "John", tag<"address"> = "somewhere", tag<"id"> = 1, tag<"score"> = 10.5}); 58 | v.push_back(Person{tag<"name"> = "Jane", tag<"address"> = "there", tag<"id"> = 2, tag<"score"> = 12.5}); 59 | 60 | assert(get<"name">(v[1]) == "Jane"); 61 | 62 | auto scores = get<"score">(v); 63 | assert(*std::max_element(scores.begin(),scores.end()) == 12.5); 64 | 65 | 66 | } 67 | 68 | int main() { 69 | soa_vector_example(); 70 | tagged_tuple, 71 | member<"world", std::string, 72 | [](auto& self) { return get<"hello">(self); }>, 73 | member<"test", auto_, 74 | [](auto& t) { 75 | return 2 * get<"hello">(t) + get<"world">(t).size(); 76 | }>, 77 | member<"last", int>> 78 | ts{tag<"world"> = "Universe", tag<"hello"> = 1}; 79 | 80 | auto ref_ts = make_ref(ts); 81 | print(ref_ts); 82 | 83 | 84 | 85 | 86 | using T = decltype(ts); 87 | T t2{tag<"world"> = "JRB"}; 88 | 89 | 90 | ftsd::soa_vector v; 91 | 92 | v.push_back(t2); 93 | 94 | print(v[0]); 95 | 96 | get<"world">(v[0]) = "Changed"; 97 | 98 | print(v[0]); 99 | 100 | auto v0 = get<"world">(v); 101 | v0.front() = "Changed again"; 102 | 103 | 104 | std::cout << get<"world">(v).front(); 105 | 106 | 107 | 108 | return 0; 109 | 110 | std::cout << get<"hello">(ts) << "\n"; 111 | std::cout << get<"world">(ts) << "\n"; 112 | std::cout << get<"test">(ts) << "\n"; 113 | std::cout << get<"hello">(t2) << "\n"; 114 | std::cout << get<"world">(t2) << "\n"; 115 | std::cout << get<"test">(t2) << "\n"; 116 | 117 | test({tag<"c"> = 1, tag<"a"> = 5}); 118 | test({tag<"a"> = 1}); 119 | test({"a"_tag = 1}); 120 | 121 | tagged_tuple ctad{"a"_tag = 15, "b"_tag = std::string("Hello ctad")}; 122 | 123 | std::cout << ts["world"_tag] << "\n"; 124 | std::cout << ts[tag<"world">] << "\n"; 125 | std::cout << ctad["a"_tag] << "\n"; 126 | } -------------------------------------------------------------------------------- /cpp20_tagged_tuple/soa_vector.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | #include 5 | 6 | #include "tagged_tuple.h" 7 | 8 | namespace ftsd { 9 | 10 | template 11 | class soa_vector; 12 | 13 | template 14 | class soa_vector...>> { 15 | using TaggedTuple = tagged_tuple...>; 16 | tagged_tuple>>...> 18 | vectors_; 19 | 20 | template 21 | decltype(auto) first_helper() { 22 | return get(vectors_); 23 | } 24 | 25 | template 26 | decltype(auto) first_helper() const { 27 | return get(vectors_); 28 | } 29 | 30 | decltype(auto) first() { return first_helper(); } 31 | 32 | decltype(auto) first() const { return first_helper(); } 33 | 34 | public: 35 | soa_vector() = default; 36 | decltype(auto) vectors() { return (vectors_); } 37 | decltype(auto) vectors() const { return (vectors_); } 38 | 39 | void push_back(TaggedTuple t) { 40 | (ftsd::get(vectors_).push_back(get(t)), ...); 41 | } 42 | 43 | void pop_back() { (get(vectors_).pop_back(), ...); } 44 | 45 | void clear() { (get(vectors_).clear(), ...); } 46 | 47 | std::size_t size() const { return first().size(); } 48 | 49 | bool empty() const { return first().empty(); } 50 | 51 | auto operator[](std::size_t i) { 52 | return tagged_tuple_ref_t( 53 | (ftsd::tag = std::ref(ftsd::get(vectors_)[i]))...); 54 | } 55 | 56 | auto operator[](std::size_t i) const { 57 | return tagged_tuple_ref_t( 58 | (ftsd::tag = std::ref(ftsd::get(vectors_)[i]))...); 59 | } 60 | 61 | auto front() { return (*this)[0]; } 62 | auto back() { return (*this)[size() - 1]; } 63 | }; 64 | 65 | template 66 | decltype(auto) get_impl(soa_vector& s) { 67 | return std::span{ftsd::get(s.vectors())}; 68 | } 69 | 70 | template 71 | auto get_impl(const soa_vector& s) { 72 | return std::span{ftsd::get(s.vectors())}; 73 | } 74 | 75 | template 76 | auto get_impl(soa_vector&& s) { 77 | return std::span{ftsd::get(std::move(s.vectors()))}; 78 | } 79 | 80 | } // namespace ftsd 81 | -------------------------------------------------------------------------------- /cpp20_tagged_tuple/to_from_nlohmann_json.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | 4 | #include "tagged_tuple.h" 5 | 6 | namespace nlohmann { 7 | template 8 | struct adl_serializer> { 9 | using TTuple = ftsd::tagged_tuple; 10 | 11 | template 12 | static auto get_from_json(const json& j) { 13 | using ftsd::tag; 14 | if constexpr (!Member::has_default_init()) { 15 | return tag = 16 | j.at(Member::key().data()).get(); 17 | } else { 18 | if (j.contains(Member::key().data())) { 19 | return tag = 20 | std::optional( 21 | j.at(Member::key().data()).get()); 22 | } else { 23 | return tag = std::optional(); 24 | } 25 | } 26 | } 27 | static TTuple from_json(const json& j) { 28 | return TTuple::apply_static([&](M * ...) { 29 | return TTuple(get_from_json(j)...); 30 | }); 31 | } 32 | 33 | static void to_json(json& j, const TTuple& t) { 34 | t.for_each([&](auto& member) { j[member.key().data()] = member.value(); }); 35 | } 36 | }; 37 | } // namespace nlohmann 38 | -------------------------------------------------------------------------------- /futures/futures.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | template 11 | struct overload : T... { 12 | using T::operator()...; 13 | }; 14 | 15 | template 16 | overload(T... t)->overload; 17 | 18 | template 19 | struct shared { 20 | T value; 21 | std::exception_ptr eptr = nullptr; 22 | std::mutex mutex; 23 | std::condition_variable cvar; 24 | bool done = false; 25 | std::variant> thread_or_function; 26 | }; 27 | 28 | template <> 29 | struct shared { 30 | std::exception_ptr eptr = nullptr; 31 | std::mutex mutex; 32 | std::condition_variable cvar; 33 | bool done = false; 34 | std::variant> thread_or_function; 35 | }; 36 | 37 | template 38 | struct ref_not_void{ 39 | using type = T&; 40 | }; 41 | template<> 42 | struct ref_not_void{ 43 | using type = void; 44 | }; 45 | 46 | template 47 | using ref_not_void_t = typename ref_not_void::type; 48 | 49 | 50 | template 51 | class future { 52 | public: 53 | void wait() { 54 | std::unique_lock lock{shared_->mutex}; 55 | while (!shared_->done) { 56 | shared_->cvar.wait(lock); 57 | } 58 | } 59 | 60 | ref_not_void_t get() { 61 | wait(); 62 | if (shared_->eptr) { 63 | std::rethrow_exception(shared_->eptr); 64 | } 65 | std::visit( 66 | overload{[&](std::thread& t) { t.join(); }, 67 | [&](auto& f) { f(); }}, 68 | shared_->thread_or_function); 69 | if constexpr (!std::is_same_v) { 70 | return shared_->value; 71 | } 72 | } 73 | 74 | explicit future(const std::shared_ptr>& shared) : shared_(shared) {} 75 | private: 76 | std::shared_ptr> shared_; 77 | }; 78 | enum class launch { async, deferred }; 79 | 80 | template 81 | class promise { 82 | public: 83 | promise():shared_(std::make_shared>()){} 84 | void set_value() { 85 | shared_->done = true; 86 | shared_->cvar.notify_one(); 87 | shared_ = nullptr; 88 | } 89 | template 90 | void set_value(V&& v) { 91 | std::unique_lock lock{shared_->mutex}; 92 | shared_->value = std::forward(v); 93 | shared_->done = true; 94 | shared_->cvar.notify_one(); 95 | shared_ = nullptr; 96 | } 97 | void set_exception(std::exception_ptr eptr) { 98 | std::unique_lock lock{shared_->mutex}; 99 | shared_->eptr = eptr; 100 | shared_->done = true; 101 | shared_->cvar.notify_one(); 102 | shared_ = nullptr; 103 | } 104 | 105 | future get_future() { return future{shared_}; } 106 | 107 | explicit promise(const std::shared_ptr>& shared) 108 | : shared_(shared) {} 109 | 110 | private: 111 | std::shared_ptr> shared_; 112 | }; 113 | 114 | template 115 | auto async(launch policy, F f, Args... args) -> future { 116 | using T = decltype(f(args...)); 117 | auto state = std::make_shared>(); 118 | promise p(state); 119 | auto fut = p.get_future(); 120 | auto future_func = [p = std::move(p), f = std::move(f), args...]() mutable { 121 | try { 122 | if constexpr (std::is_same_v) { 123 | f(args...); 124 | p.set_value(); 125 | } else { 126 | p.set_value(f(args...)); 127 | } 128 | } catch (...) { 129 | p.set_exception(std::current_exception()); 130 | } 131 | }; 132 | if (policy == launch::async) { 133 | state->done = false; 134 | state->thread_or_function = std::thread(std::move(future_func)); 135 | } else { 136 | state->done = true; 137 | state->thread_or_function = std::move(future_func); 138 | } 139 | return fut; 140 | } 141 | 142 | #include 143 | 144 | int main() { 145 | auto fut = async(launch::async, []() { return 5; }); 146 | std::cout << fut.get() << "\n"; 147 | auto fut2 = async(launch::deferred, []() { return 5; }); 148 | std::cout << fut2.get() << "\n"; 149 | int v = 0; 150 | auto fut3 = async(launch::async, [&]()mutable{v = 4;}); 151 | fut3.get(); 152 | std::cout << v << "\n"; 153 | } -------------------------------------------------------------------------------- /iterators-algorithms-ranges/algorithm.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2018 Google LLC 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // https://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // limitations under the License. 13 | 14 | #include 15 | #include 16 | #include 17 | #include 18 | 19 | 20 | template 21 | void insert_sorted(V& v, T&& t) { 22 | v.push_back(std::forward(t)); 23 | auto last = std::prev(v.end()); 24 | auto pos = std::lower_bound(v.begin(), last, *last); 25 | std::rotate(pos, last, v.end()); 26 | } 27 | 28 | 29 | template 30 | void nearest_k(V& v, const T& t, int k) { 31 | if (v.size() <= k) return; 32 | auto comp = [&t](auto& a, auto& b) { 33 | return std::abs(a - t) < std::abs(b - t); 34 | }; 35 | 36 | auto iter = v.begin() + k; 37 | std::nth_element(v.begin(),iter , v.end(),comp); 38 | if (iter != v.end()) { 39 | v.erase(iter, v.end()); 40 | } 41 | } 42 | 43 | 44 | template 45 | std::size_t distance(I1 begin, I2 end) { 46 | if constexpr (std::is_same_v::iterator_category, std::random_access_iterator_tag>) { 47 | return end - begin; 48 | } 49 | else { 50 | std::size_t d = 0; 51 | for (; begin != end; ++begin) { 52 | ++d; 53 | } 54 | return d; 55 | } 56 | } 57 | 58 | #include 59 | 60 | int main() { 61 | std::vector v; 62 | 63 | insert_sorted(v, 5); 64 | insert_sorted(v, 1); 65 | insert_sorted(v, 2); 66 | insert_sorted(v, 4); 67 | 68 | insert_sorted(v, 3); 69 | 70 | std::copy(v.begin(), v.end(), std::ostream_iterator(std::cout, "\n")); 71 | std::cout << "\n\n"; 72 | 73 | nearest_k(v, 5, 2); 74 | std::copy(v.begin(), v.end(), std::ostream_iterator(std::cout, "\n")); 75 | 76 | 77 | std::list l(v.begin(), v.end()); 78 | std::cout << "vector size:" << distance(v.begin(), v.end()) << " list size:" << distance(l.begin(), l.end()) << "\n"; 79 | 80 | 81 | 82 | } -------------------------------------------------------------------------------- /meta_struct_20/cppcon_version/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # CMakeList.txt : CMake project for tagged_sqlite, include source and define 2 | # project specific logic here. 3 | # 4 | cmake_minimum_required (VERSION 3.8) 5 | 6 | project(cpp20_tagged_struct) 7 | 8 | set(CMAKE_CXX_STANDARD 20) 9 | set(CMAKE_CXX_STANDARD_REQUIRED ON) 10 | find_package(Threads REQUIRED) 11 | find_package(SQLite3 REQUIRED) 12 | 13 | 14 | # Add source to this project's executable. 15 | add_executable (meta_struct_sqlite_example "meta_struct_sqlite_example.cpp" "meta_struct_sqlite.h") 16 | target_link_libraries(meta_struct_sqlite_example SQLite::SQLite3 Threads::Threads ${CMAKE_DL_LIBS}) 17 | 18 | 19 | # Add source to this project's executable. 20 | add_executable (fixed_string "fixed_string.cpp") 21 | add_executable (meta_struct_1 "meta_struct_1.cpp") 22 | add_executable (meta_struct_constructed_2 "meta_struct_constructed_2.cpp") 23 | add_executable (meta_struct_init_3 "meta_struct_init_3.cpp") 24 | add_executable (meta_struct_init_self_4 "meta_struct_init_self_4.cpp") 25 | add_executable (meta_struct_print_5 "meta_struct_print_5.cpp") 26 | add_executable (meta_struct_optional_arguments_6 "meta_struct_optional_arguments_6.cpp") 27 | add_executable (meta_struct_required_named_args_7 "meta_struct_required_named_args_7.cpp") 28 | add_executable (meta_struct_conversion_8 "meta_struct_conversion_8.cpp") 29 | add_executable (meta_struct_attributes_9 "meta_struct_applications_10.cpp") 30 | add_executable (meta_struct_applications_10 "meta_struct_applications_10.cpp") 31 | add_executable (meta_struct_example_11 "meta_struct_example_11.cpp" "meta_struct.h") 32 | 33 | 34 | 35 | 36 | 37 | # TODO: Add tests and instal l targets if needed. 38 | -------------------------------------------------------------------------------- /meta_struct_20/cppcon_version/fixed_string.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | template 4 | struct fixed_string { 5 | constexpr fixed_string(const char (&foo)[N + 1]) { 6 | std::copy_n(foo, N + 1, data); 7 | } 8 | auto operator<=>(const fixed_string&) const = default; 9 | char data[N + 1] = {}; 10 | }; 11 | template 12 | fixed_string(const char (&str)[N]) -> fixed_string; 13 | 14 | #include 15 | template 16 | void print(std::ostream& os) { 17 | static_assert(s == fixed_string("hello world")); 18 | } 19 | 20 | int main() { print<"hello world">(std::cout); } 21 | -------------------------------------------------------------------------------- /meta_struct_20/cppcon_version/meta_struct_1.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | template 4 | struct fixed_string { 5 | constexpr fixed_string(const char (&foo)[N + 1]) { 6 | std::copy_n(foo, N + 1, data); 7 | } 8 | auto operator<=>(const fixed_string&) const = default; 9 | char data[N + 1] = {}; 10 | }; 11 | template 12 | fixed_string(const char (&str)[N]) -> fixed_string; 13 | 14 | template 15 | struct member { 16 | constexpr static auto tag() { return Tag; } 17 | using element_type = T; 18 | T value; 19 | }; 20 | 21 | template 22 | struct meta_struct : Members... {}; 23 | 24 | 25 | template 26 | decltype(auto) get_impl(member& m) { 27 | return (m.value); 28 | } 29 | 30 | template 31 | decltype(auto) get_impl(const member& m) { 32 | return (m.value); 33 | } 34 | 35 | template 36 | decltype(auto) get_impl(member&& m) { 37 | return std::move(m.value); 38 | } 39 | 40 | template 41 | decltype(auto) get(MetaStruct&& s) { 42 | return get_impl(std::forward(s)); 43 | } 44 | 45 | #include 46 | #include 47 | 48 | int main() { 49 | using Person = meta_struct< // 50 | member<"id", int>, // 51 | member<"name", std::string> // 52 | >; 53 | 54 | Person p; 55 | get<"id">(p) = 1; 56 | get<"name">(p) = "John"; 57 | 58 | std::cout << get<"id">(p) << " " << get<"name">(p) << "\n"; 59 | 60 | 61 | } 62 | -------------------------------------------------------------------------------- /meta_struct_20/cppcon_version/meta_struct_constructed_2.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | template 4 | struct fixed_string { 5 | constexpr fixed_string(const char (&foo)[N + 1]) { 6 | std::copy_n(foo, N + 1, data); 7 | } 8 | auto operator<=>(const fixed_string&) const = default; 9 | char data[N + 1] = {}; 10 | }; 11 | template 12 | fixed_string(const char (&str)[N]) -> fixed_string; 13 | 14 | template 15 | struct tag_and_value { 16 | T value; 17 | }; 18 | 19 | template 20 | struct parms : TagsAndValues... {}; 21 | 22 | template 23 | parms(TagsAndValues...) -> parms; 24 | 25 | template 26 | struct arg_type { 27 | template 28 | constexpr auto operator=(T t) const { 29 | return tag_and_value{std::move(t)}; 30 | } 31 | }; 32 | 33 | template 34 | inline constexpr auto arg = arg_type{}; 35 | 36 | template 37 | struct member { 38 | constexpr static auto tag() { return Tag; } 39 | using element_type = T; 40 | T value; 41 | template 42 | constexpr member(tag_and_value tv) : value(std::move(tv.value)) {} 43 | 44 | constexpr member() = default; 45 | constexpr member(member&&) = default; 46 | constexpr member(const member&) = default; 47 | 48 | constexpr member& operator=(member&&) = default; 49 | constexpr member& operator=(const member&) = default; 50 | 51 | auto operator<=>(const member&) const = default; 52 | }; 53 | 54 | template 55 | struct meta_struct_impl : Members... { 56 | template 57 | constexpr meta_struct_impl(Parms p) 58 | : Members(std::move(p))... {} 59 | 60 | constexpr meta_struct_impl() = default; 61 | constexpr meta_struct_impl(meta_struct_impl&&) = default; 62 | constexpr meta_struct_impl(const meta_struct_impl&) = default; 63 | constexpr meta_struct_impl& operator=(meta_struct_impl&&) = default; 64 | constexpr meta_struct_impl& operator=(const meta_struct_impl&) = default; 65 | 66 | auto operator<=>(const meta_struct_impl&) const = default; 67 | }; 68 | 69 | template 70 | struct meta_struct : meta_struct_impl { 71 | using super = meta_struct_impl; 72 | template 73 | constexpr meta_struct(TagsAndValues... tags_and_values) 74 | : super(parms(std::move(tags_and_values)...)) {} 75 | 76 | constexpr meta_struct() = default; 77 | constexpr meta_struct(meta_struct&&) = default; 78 | constexpr meta_struct(const meta_struct&) = default; 79 | constexpr meta_struct& operator=(meta_struct&&) = default; 80 | constexpr meta_struct& operator=(const meta_struct&) = default; 81 | 82 | auto operator<=>(const meta_struct&) const = default; 83 | }; 84 | 85 | template 86 | decltype(auto) get_impl(member& m) { 87 | return (m.value); 88 | } 89 | 90 | template 91 | decltype(auto) get_impl(const member& m) { 92 | return (m.value); 93 | } 94 | 95 | template 96 | decltype(auto) get_impl(member&& m) { 97 | return std::move(m.value); 98 | } 99 | 100 | template 101 | decltype(auto) get(MetaStruct&& s) { 102 | return get_impl(std::forward(s)); 103 | } 104 | 105 | #include 106 | #include 107 | 108 | int main() { 109 | using Person = meta_struct< // 110 | member<"id", int>, // 111 | member<"name", std::string> // 112 | >; 113 | 114 | Person p{arg<"id"> = 1, arg<"name"> = "John"}; 115 | 116 | std::cout << get<"id">(p) << " " << get<"name">(p) << "\n"; 117 | p = Person{arg<"name"> = "John", arg<"id"> = 1}; 118 | std::cout << get<"id">(p) << " " << get<"name">(p) << "\n"; 119 | } 120 | -------------------------------------------------------------------------------- /meta_struct_20/cppcon_version/meta_struct_example_11.cpp: -------------------------------------------------------------------------------- 1 | #include "meta_struct.h" 2 | 3 | #include 4 | #include 5 | 6 | 7 | template 8 | void print(std::ostream& os, const MetaStruct& ms) { 9 | ftsd::meta_struct_apply( 10 | [&](const auto&... m) { 11 | auto print_item = [&](auto& m) { 12 | std::cout << m.tag().sv() << ":" << m.value << "\n"; 13 | }; 14 | (print_item(m), ...); 15 | }, 16 | ms); 17 | }; 18 | 19 | using NameAndIdArgs = ftsd::meta_struct< // 20 | ftsd::member<"name", std::string_view>, // 21 | ftsd::member<"id", const int&> // 22 | >; 23 | 24 | void print_name_id(NameAndIdArgs args) { 25 | std::cout << "Name is " << get<"name">(args) << " and id is " 26 | << get<"id">(args) << "\n"; 27 | } 28 | 29 | enum class encoding : int { fixed = 0, variable = 1 }; 30 | 31 | int main() { 32 | using Person = ftsd::meta_struct< // 33 | ftsd::member<"id", int, ftsd::required, {ftsd::arg<"encoding"> = encoding::variable}>, // 34 | ftsd::member<"name", std::string, ftsd::required>, // 35 | ftsd::member<"score", int, [](auto& self) { return ftsd::get<"id">(self) + 1; }> // 36 | >; 37 | 38 | constexpr auto attributes = ftsd::get_attributes<"id", Person>(); 39 | 40 | if constexpr (ftsd::has<"encoding">(attributes) && 41 | ftsd::get<"encoding">(attributes) == encoding::variable) { 42 | std::cout << "Encoding was variable"; 43 | } else { 44 | std::cout << "Encoding was fixed"; 45 | } 46 | 47 | auto print = [](auto& t) { 48 | meta_struct_apply( 49 | [&](const auto&... m) { 50 | ((std::cout << m.tag().sv() << ":" << m.value << "\n"), ...); 51 | }, 52 | t); 53 | }; 54 | 55 | Person p{ftsd::arg<"id"> = 2, ftsd::arg<"name"> = "John"}; 56 | 57 | using NameAndId = ftsd::meta_struct< // 58 | ftsd::member<"name", std::string_view>, // 59 | ftsd::member<"id", int> // 60 | >; 61 | 62 | print(p); 63 | std::cout << "\n"; 64 | NameAndId n = p; 65 | print(n); 66 | std::cout << "\n"; 67 | 68 | print_name_id(p); 69 | print_name_id(n); 70 | 71 | static_assert(ftsd::meta_struct_size() == 2); 72 | static_assert(ftsd::meta_struct_size(n) == 2); 73 | 74 | constexpr auto fs = ftsd::fixed_string<4>::from_string_view("John"); 75 | } 76 | -------------------------------------------------------------------------------- /meta_struct_20/cppcon_version/meta_struct_init_3.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | template 6 | struct fixed_string { 7 | constexpr fixed_string(const char (&foo)[N + 1]) { 8 | std::copy_n(foo, N + 1, data); 9 | } 10 | auto operator<=>(const fixed_string&) const = default; 11 | char data[N + 1] = {}; 12 | }; 13 | template 14 | fixed_string(const char (&str)[N]) -> fixed_string; 15 | 16 | template 17 | struct tag_and_value { 18 | T value; 19 | }; 20 | 21 | template 22 | struct parms : TagsAndValues... {}; 23 | 24 | template 25 | parms(TagsAndValues...) -> parms; 26 | 27 | template 28 | struct arg_type { 29 | template 30 | constexpr auto operator=(T t) const { 31 | return tag_and_value{std::move(t)}; 32 | } 33 | }; 34 | 35 | template 36 | inline constexpr auto arg = arg_type{}; 37 | 38 | template 39 | struct default_init { 40 | constexpr default_init() = default; 41 | auto operator<=>(const default_init&) const = default; 42 | constexpr auto operator()() const { 43 | if constexpr (std::is_default_constructible_v) { 44 | return T{}; 45 | } 46 | } 47 | }; 48 | 49 | template ()> 50 | struct member { 51 | constexpr static auto tag() { return Tag; } 52 | constexpr static auto init() { return Init; } 53 | using element_type = T; 54 | T value; 55 | template 56 | constexpr member(tag_and_value tv) 57 | : value(std::move(tv.value)) {} 58 | 59 | constexpr member() : value(Init()) {} 60 | constexpr member(member&&) = default; 61 | constexpr member(const member&) = default; 62 | 63 | constexpr member& operator=(member&&) = default; 64 | constexpr member& operator=(const member&) = default; 65 | 66 | auto operator<=>(const member&) const = default; 67 | }; 68 | 69 | template 70 | struct meta_struct_impl : Members... { 71 | template 72 | constexpr meta_struct_impl(Parms p) : Members(std::move(p))... {} 73 | 74 | constexpr meta_struct_impl() = default; 75 | constexpr meta_struct_impl(meta_struct_impl&&) = default; 76 | constexpr meta_struct_impl(const meta_struct_impl&) = default; 77 | constexpr meta_struct_impl& operator=(meta_struct_impl&&) = default; 78 | constexpr meta_struct_impl& operator=(const meta_struct_impl&) = default; 79 | 80 | auto operator<=>(const meta_struct_impl&) const = default; 81 | }; 82 | 83 | template 84 | struct meta_struct : meta_struct_impl { 85 | using super = meta_struct_impl; 86 | template 87 | constexpr meta_struct(TagsAndValues... tags_and_values) 88 | : super(parms(std::move(tags_and_values)...)) {} 89 | 90 | constexpr meta_struct() = default; 91 | constexpr meta_struct(meta_struct&&) = default; 92 | constexpr meta_struct(const meta_struct&) = default; 93 | constexpr meta_struct& operator=(meta_struct&&) = default; 94 | constexpr meta_struct& operator=(const meta_struct&) = default; 95 | 96 | auto operator<=>(const meta_struct&) const = default; 97 | }; 98 | 99 | template 100 | decltype(auto) get_impl(member& m) { 101 | return (m.value); 102 | } 103 | 104 | template 105 | decltype(auto) get_impl(const member& m) { 106 | return (m.value); 107 | } 108 | 109 | template 110 | decltype(auto) get_impl(member&& m) { 111 | return std::move(m.value); 112 | } 113 | 114 | template 115 | decltype(auto) get(MetaStruct&& s) { 116 | return get_impl(std::forward(s)); 117 | } 118 | 119 | #include 120 | #include 121 | 122 | int main() { 123 | using Person = meta_struct< // 124 | member<"id", int>, // 125 | member<"name", std::string, [] { return "John"; }> // 126 | >; 127 | 128 | Person p; 129 | 130 | std::cout << get<"id">(p) << " " << get<"name">(p) << "\n"; 131 | } 132 | -------------------------------------------------------------------------------- /meta_struct_20/cppcon_version/meta_struct_init_self_4.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | template 6 | struct fixed_string { 7 | constexpr fixed_string(const char (&foo)[N + 1]) { 8 | std::copy_n(foo, N + 1, data); 9 | } 10 | auto operator<=>(const fixed_string&) const = default; 11 | char data[N + 1] = {}; 12 | }; 13 | template 14 | fixed_string(const char (&str)[N]) -> fixed_string; 15 | 16 | template 17 | struct tag_and_value { 18 | T value; 19 | }; 20 | 21 | template 22 | struct parms : TagsAndValues... {}; 23 | 24 | template 25 | parms(TagsAndValues...) -> parms; 26 | 27 | template 28 | struct arg_type { 29 | template 30 | constexpr auto operator=(T t) const { 31 | return tag_and_value{std::move(t)}; 32 | } 33 | }; 34 | 35 | template 36 | inline constexpr auto arg = arg_type{}; 37 | 38 | template 39 | struct default_init { 40 | constexpr default_init() = default; 41 | constexpr auto operator<=>(const default_init&) const = default; 42 | constexpr auto operator()() const { 43 | if constexpr (std::is_default_constructible_v) { 44 | return T{}; 45 | } 46 | } 47 | }; 48 | 49 | template 50 | auto call_init(Self&, F& f) requires(requires { 51 | { f() } -> std::convertible_to; 52 | }) { 53 | return f(); 54 | } 55 | 56 | template 57 | auto call_init(Self& self, F& f) requires(requires { 58 | { f(self) } -> std::convertible_to; 59 | }) { 60 | return f(self); 61 | } 62 | 63 | template 64 | auto call_init(Self& self, F& f) requires(requires { 65 | { f() } -> std::same_as; 66 | }) {} 67 | 68 | template ()> 69 | struct member { 70 | constexpr static auto tag() { return Tag; } 71 | constexpr static auto init() { return Init; } 72 | using element_type = T; 73 | T value; 74 | template 75 | constexpr member(tag_and_value tv) 76 | : value(std::move(tv.value)) {} 77 | 78 | template 79 | constexpr member(Self& self) : value(call_init(self, Init)) {} 80 | constexpr member(member&&) = default; 81 | constexpr member(const member&) = default; 82 | 83 | constexpr member& operator=(member&&) = default; 84 | constexpr member& operator=(const member&) = default; 85 | 86 | auto operator<=>(const member&) const = default; 87 | }; 88 | 89 | template 90 | struct meta_struct_impl : Members... { 91 | template 92 | constexpr meta_struct_impl(Parms p) : Members(std::move(p))... {} 93 | 94 | constexpr meta_struct_impl() : Members(*this)... {} 95 | constexpr meta_struct_impl(meta_struct_impl&&) = default; 96 | constexpr meta_struct_impl(const meta_struct_impl&) = default; 97 | constexpr meta_struct_impl& operator=(meta_struct_impl&&) = default; 98 | constexpr meta_struct_impl& operator=(const meta_struct_impl&) = default; 99 | 100 | constexpr auto operator<=>(const meta_struct_impl&) const = default; 101 | }; 102 | 103 | template 104 | struct meta_struct : meta_struct_impl { 105 | using super = meta_struct_impl; 106 | template 107 | constexpr meta_struct(TagsAndValues... tags_and_values) 108 | : super(parms(std::move(tags_and_values)...)) {} 109 | 110 | constexpr meta_struct() = default; 111 | constexpr meta_struct(meta_struct&&) = default; 112 | constexpr meta_struct(const meta_struct&) = default; 113 | constexpr meta_struct& operator=(meta_struct&&) = default; 114 | constexpr meta_struct& operator=(const meta_struct&) = default; 115 | 116 | constexpr auto operator<=>(const meta_struct&) const = default; 117 | }; 118 | 119 | template 120 | decltype(auto) get_impl(member& m) { 121 | return (m.value); 122 | } 123 | 124 | template 125 | decltype(auto) get_impl(const member& m) { 126 | return (m.value); 127 | } 128 | 129 | template 130 | decltype(auto) get_impl(member&& m) { 131 | return std::move(m.value); 132 | } 133 | 134 | template 135 | decltype(auto) get(MetaStruct&& s) { 136 | return get_impl(std::forward(s)); 137 | } 138 | 139 | #include 140 | #include 141 | 142 | int main() { 143 | using Person = meta_struct< // 144 | member<"id", int>, // 145 | member<"score", int, [](auto& self) { return get<"id">(self) + 1; }>, // 146 | member<"name", std::string, [] { return "John"; }> // 147 | >; 148 | 149 | Person p; 150 | 151 | std::cout << get<"id">(p) << " " << get<"name">(p) << " " << get<"score">(p) 152 | << "\n"; 153 | } 154 | -------------------------------------------------------------------------------- /meta_struct_20/cppcon_version/meta_struct_optional_arguments_6.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | template 8 | struct fixed_string { 9 | constexpr fixed_string(const char (&foo)[N + 1]) { 10 | std::copy_n(foo, N + 1, data); 11 | } 12 | constexpr fixed_string(std::string_view s) { 13 | static_assert(s.size() <= N); 14 | std::copy(s.begin(), s.end(), data); 15 | } 16 | constexpr std::string_view sv() const { return std::string_view(data); } 17 | auto operator<=>(const fixed_string&) const = default; 18 | char data[N + 1] = {}; 19 | }; 20 | template 21 | fixed_string(const char (&str)[N]) -> fixed_string; 22 | 23 | template 24 | struct tag_and_value { 25 | T value; 26 | }; 27 | 28 | struct no_conversion {}; 29 | template 30 | struct parms : TagsAndValues... { 31 | constexpr operator no_conversion() const { return no_conversion{}; } 32 | }; 33 | 34 | template 35 | parms(TagsAndValues...) -> parms; 36 | 37 | template 38 | struct arg_type { 39 | template 40 | constexpr auto operator=(T t) const { 41 | return tag_and_value{std::move(t)}; 42 | } 43 | }; 44 | 45 | template 46 | inline constexpr auto arg = arg_type{}; 47 | 48 | template 49 | struct default_init { 50 | constexpr default_init() = default; 51 | auto operator<=>(const default_init&) const = default; 52 | constexpr auto operator()() const { 53 | if constexpr (std::is_default_constructible_v) { 54 | return T{}; 55 | } 56 | } 57 | }; 58 | 59 | template 60 | auto call_init(Self&, F& f) requires(requires { 61 | { f() } -> std::convertible_to; 62 | }) { 63 | return f(); 64 | } 65 | 66 | template 67 | auto call_init(Self& self, F& f) requires(requires { 68 | { f(self) } -> std::convertible_to; 69 | }) { 70 | return f(self); 71 | } 72 | 73 | template 74 | auto call_init(Self& self, F& f) requires(requires { 75 | { f() } -> std::same_as; 76 | }) {} 77 | 78 | template ()> 79 | struct member { 80 | constexpr static auto tag() { return Tag; } 81 | constexpr static auto init() { return Init; } 82 | using element_type = T; 83 | T value; 84 | template 85 | constexpr member(Self&, tag_and_value tv) 86 | : value(std::move(tv.value)) {} 87 | 88 | template 89 | constexpr member(Self& self) : value(call_init(self, Init)) {} 90 | template 91 | constexpr member(Self& self, no_conversion) 92 | : value(call_init(self, Init)) {} 93 | template 94 | constexpr member(Self& self, tag_and_value> tv_or) 95 | : value(tv_or.value.has_value() ? std::move(*tv_or.value) 96 | : call_init(self, Init)) {} 97 | 98 | constexpr member(member&&) = default; 99 | constexpr member(const member&) = default; 100 | 101 | constexpr member& operator=(member&&) = default; 102 | constexpr member& operator=(const member&) = default; 103 | 104 | auto operator<=>(const member&) const = default; 105 | }; 106 | 107 | template 108 | struct meta_struct_impl : Members... { 109 | template 110 | constexpr meta_struct_impl(Parms p) : Members(*this, std::move(p))... {} 111 | 112 | constexpr meta_struct_impl() : Members(*this)... {} 113 | constexpr meta_struct_impl(meta_struct_impl&&) = default; 114 | constexpr meta_struct_impl(const meta_struct_impl&) = default; 115 | constexpr meta_struct_impl& operator=(meta_struct_impl&&) = default; 116 | constexpr meta_struct_impl& operator=(const meta_struct_impl&) = default; 117 | 118 | auto operator<=>(const meta_struct_impl&) const = default; 119 | }; 120 | 121 | template 122 | struct meta_struct : meta_struct_impl { 123 | using super = meta_struct_impl; 124 | template 125 | constexpr meta_struct(TagsAndValues... tags_and_values) 126 | : super(parms(std::move(tags_and_values)...)) {} 127 | 128 | constexpr meta_struct() = default; 129 | constexpr meta_struct(meta_struct&&) = default; 130 | constexpr meta_struct(const meta_struct&) = default; 131 | constexpr meta_struct& operator=(meta_struct&&) = default; 132 | constexpr meta_struct& operator=(const meta_struct&) = default; 133 | 134 | auto operator<=>(const meta_struct&) const = default; 135 | }; 136 | 137 | template 138 | constexpr decltype(auto) meta_struct_apply( 139 | F&& f, meta_struct_impl& m) { 140 | return std::forward(f)(static_cast(m)...); 141 | } 142 | 143 | template 144 | constexpr decltype(auto) meta_struct_apply( 145 | F&& f, const meta_struct_impl& m) { 146 | return std::forward(f)(static_cast(m)...); 147 | } 148 | 149 | template 150 | constexpr decltype(auto) meta_struct_apply( 151 | F&& f, meta_struct_impl&& m) { 152 | return std::forward(f)(static_cast(m)...); 153 | } 154 | 155 | template 156 | struct apply_static_impl; 157 | 158 | template 159 | struct apply_static_impl> { 160 | template 161 | constexpr static decltype(auto) apply(F&& f) { 162 | return f(static_cast(nullptr)...); 163 | } 164 | }; 165 | 166 | template 167 | auto meta_struct_apply(F&& f) { 168 | return apply_static_impl::apply( 169 | std::forward(f)); 170 | } 171 | 172 | template 173 | decltype(auto) get_impl(member& m) { 174 | return (m.value); 175 | } 176 | 177 | template 178 | decltype(auto) get_impl(const member& m) { 179 | return (m.value); 180 | } 181 | 182 | template 183 | decltype(auto) get_impl(member&& m) { 184 | return std::move(m.value); 185 | } 186 | 187 | template 188 | decltype(auto) get(MetaStruct&& s) { 189 | return get_impl(std::forward(s)); 190 | } 191 | 192 | #include 193 | #include 194 | 195 | template 196 | void print(std::ostream& os, const MetaStruct& ms) { 197 | meta_struct_apply( 198 | [&](const auto&... m) { 199 | auto print_item = [&](auto& m) { 200 | std::cout << m.tag().sv() << ":" << m.value << "\n"; 201 | }; 202 | (print_item(m), ...); 203 | }, 204 | ms); 205 | }; 206 | 207 | int main() { 208 | using Person = meta_struct< // 209 | member<"id", int>, // 210 | member<"score", int, [](auto& self) { return get<"id">(self) + 1; }>, // 211 | member<"name", std::string, [] { return "John"; }> // 212 | >; 213 | 214 | meta_struct_apply([](M * ...) { 215 | std::cout << "The tags are: "; 216 | auto print_tag = [](auto t) { std::cout << t.sv() << " "; }; 217 | (print_tag(M::tag()), ...); 218 | std::cout << "\n"; 219 | }); 220 | 221 | Person p{arg<"id"> = 2}; 222 | 223 | std::cout << get<"id">(p) << " " << get<"name">(p) << " " << get<"score">(p) 224 | << "\n"; 225 | 226 | Person p2{arg<"id"> = 2, arg<"score"> = std::optional()}; 227 | print(std::cout, p2); 228 | 229 | Person p3{arg<"id"> = 2, arg<"score"> = std::optional(500)}; 230 | print(std::cout, p3); 231 | } 232 | -------------------------------------------------------------------------------- /meta_struct_20/cppcon_version/meta_struct_print_5.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | template 7 | struct fixed_string { 8 | constexpr fixed_string(const char (&foo)[N + 1]) { 9 | std::copy_n(foo, N + 1, data); 10 | } 11 | constexpr fixed_string(std::string_view s) { 12 | static_assert(s.size() <= N); 13 | std::copy(s.begin(), s.end(), data); 14 | } 15 | constexpr std::string_view sv() const { return std::string_view(data); } 16 | auto operator<=>(const fixed_string&) const = default; 17 | char data[N + 1] = {}; 18 | }; 19 | template 20 | fixed_string(const char (&str)[N]) -> fixed_string; 21 | 22 | template 23 | struct tag_and_value { 24 | T value; 25 | }; 26 | 27 | template 28 | struct parms : TagsAndValues... {}; 29 | 30 | template 31 | parms(TagsAndValues...) -> parms; 32 | 33 | template 34 | struct arg_type { 35 | template 36 | constexpr auto operator=(T t) const { 37 | return tag_and_value{std::move(t)}; 38 | } 39 | }; 40 | 41 | template 42 | inline constexpr auto arg = arg_type{}; 43 | 44 | template 45 | struct default_init { 46 | constexpr default_init() = default; 47 | auto operator<=>(const default_init&) const = default; 48 | constexpr auto operator()() const { 49 | if constexpr (std::is_default_constructible_v) { 50 | return T{}; 51 | } 52 | } 53 | }; 54 | 55 | template 56 | auto call_init(Self&, F& f) requires(requires { 57 | { f() } -> std::convertible_to; 58 | }) { 59 | return f(); 60 | } 61 | 62 | template 63 | auto call_init(Self& self, F& f) requires(requires { 64 | { f(self) } -> std::convertible_to; 65 | }) { 66 | return f(self); 67 | } 68 | 69 | template 70 | auto call_init(Self& self, F& f) requires(requires { 71 | { f() } -> std::same_as; 72 | }) {} 73 | 74 | template ()> 75 | struct member { 76 | constexpr static auto tag() { return Tag; } 77 | constexpr static auto init() { return Init; } 78 | using element_type = T; 79 | T value; 80 | template 81 | constexpr member(tag_and_value tv) 82 | : value(std::move(tv.value)) {} 83 | 84 | template 85 | constexpr member(Self& self) : value(call_init(self, Init)) {} 86 | constexpr member(member&&) = default; 87 | constexpr member(const member&) = default; 88 | 89 | constexpr member& operator=(member&&) = default; 90 | constexpr member& operator=(const member&) = default; 91 | 92 | auto operator<=>(const member&) const = default; 93 | }; 94 | 95 | template 96 | struct meta_struct_impl : Members... { 97 | template 98 | constexpr meta_struct_impl(Parms p) : Members(std::move(p))... {} 99 | 100 | constexpr meta_struct_impl() : Members(*this)... {} 101 | constexpr meta_struct_impl(meta_struct_impl&&) = default; 102 | constexpr meta_struct_impl(const meta_struct_impl&) = default; 103 | constexpr meta_struct_impl& operator=(meta_struct_impl&&) = default; 104 | constexpr meta_struct_impl& operator=(const meta_struct_impl&) = default; 105 | 106 | auto operator<=>(const meta_struct_impl&) const = default; 107 | }; 108 | 109 | template 110 | struct meta_struct : meta_struct_impl { 111 | using super = meta_struct_impl; 112 | template 113 | constexpr meta_struct(TagsAndValues... tags_and_values) 114 | : super(parms(std::move(tags_and_values)...)) {} 115 | 116 | constexpr meta_struct() = default; 117 | constexpr meta_struct(meta_struct&&) = default; 118 | constexpr meta_struct(const meta_struct&) = default; 119 | constexpr meta_struct& operator=(meta_struct&&) = default; 120 | constexpr meta_struct& operator=(const meta_struct&) = default; 121 | 122 | auto operator<=>(const meta_struct&) const = default; 123 | }; 124 | 125 | template 126 | constexpr decltype(auto) meta_struct_apply( 127 | F&& f, meta_struct_impl& m) { 128 | return std::forward(f)(static_cast(m)...); 129 | } 130 | 131 | template 132 | constexpr decltype(auto) meta_struct_apply( 133 | F&& f, const meta_struct_impl& m) { 134 | return std::forward(f)(static_cast(m)...); 135 | } 136 | 137 | template 138 | constexpr decltype(auto) meta_struct_apply( 139 | F&& f, meta_struct_impl&& m) { 140 | return std::forward(f)(static_cast(m)...); 141 | } 142 | 143 | template 144 | struct apply_static_impl; 145 | 146 | template 147 | struct apply_static_impl> { 148 | template 149 | constexpr static decltype(auto) apply(F&& f) { 150 | return f(static_cast(nullptr)...); 151 | } 152 | }; 153 | 154 | template 155 | auto meta_struct_apply(F&& f) { 156 | return apply_static_impl::apply( 157 | std::forward(f)); 158 | } 159 | 160 | template 161 | decltype(auto) get_impl(member& m) { 162 | return (m.value); 163 | } 164 | 165 | template 166 | decltype(auto) get_impl(const member& m) { 167 | return (m.value); 168 | } 169 | 170 | template 171 | decltype(auto) get_impl(member&& m) { 172 | return std::move(m.value); 173 | } 174 | 175 | template 176 | decltype(auto) get(MetaStruct&& s) { 177 | return get_impl(std::forward(s)); 178 | } 179 | 180 | #include 181 | #include 182 | 183 | int main() { 184 | using Person = meta_struct< // 185 | member<"id", int>, // 186 | member<"score", int, [](auto& self) { return get<"id">(self) + 1; }>, // 187 | member<"name", std::string, [] { return "John"; }> // 188 | >; 189 | 190 | meta_struct_apply([](M * ...) { 191 | std::cout << "The tags are: "; 192 | ((std::cout << M::tag().sv() << " "), ...); 193 | std::cout << "\n"; 194 | }); 195 | 196 | Person p; 197 | meta_struct_apply( 198 | [&](const auto&... m) { 199 | ((std::cout << m.tag().sv() << ":" << m.value << "\n"), ...); 200 | }, 201 | p); 202 | 203 | } 204 | -------------------------------------------------------------------------------- /meta_struct_20/cppcon_version/meta_struct_required_named_args_7.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | template 8 | struct fixed_string { 9 | constexpr fixed_string(const char (&foo)[N + 1]) { 10 | std::copy_n(foo, N + 1, data); 11 | } 12 | constexpr fixed_string(std::string_view s) { 13 | static_assert(s.size() <= N); 14 | std::copy(s.begin(), s.end(), data); 15 | } 16 | constexpr std::string_view sv() const { return std::string_view(data); } 17 | auto operator<=>(const fixed_string&) const = default; 18 | char data[N + 1] = {}; 19 | }; 20 | template 21 | fixed_string(const char (&str)[N]) -> fixed_string; 22 | 23 | template 24 | struct tag_and_value { 25 | T value; 26 | }; 27 | 28 | struct no_conversion {}; 29 | template 30 | struct parms : TagsAndValues... { 31 | constexpr operator no_conversion() const { return no_conversion{}; } 32 | }; 33 | 34 | template 35 | parms(TagsAndValues...) -> parms; 36 | 37 | template 38 | struct arg_type { 39 | template 40 | constexpr auto operator=(T t) const { 41 | return tag_and_value{std::move(t)}; 42 | } 43 | }; 44 | 45 | template 46 | inline constexpr auto arg = arg_type{}; 47 | 48 | template 49 | struct default_init { 50 | constexpr default_init() = default; 51 | auto operator<=>(const default_init&) const = default; 52 | constexpr auto operator()() const { 53 | if constexpr (std::is_default_constructible_v) { 54 | return T{}; 55 | } 56 | } 57 | }; 58 | 59 | template 60 | auto call_init(Self&, F& f) requires(requires { 61 | { f() } -> std::convertible_to; 62 | }) { 63 | return f(); 64 | } 65 | 66 | template 67 | auto call_init(Self& self, F& f) requires(requires { 68 | { f(self) } -> std::convertible_to; 69 | }) { 70 | return f(self); 71 | } 72 | 73 | template 74 | auto call_init(Self& self, F& f) requires(requires { 75 | { f() } -> std::same_as; 76 | }) { 77 | static_assert(!std::is_same_v, 78 | "Required argument not specified"); 79 | } 80 | 81 | inline constexpr auto required = [] {}; 82 | 83 | template ()> 84 | struct member { 85 | constexpr static auto tag() { return Tag; } 86 | constexpr static auto init() { return Init; } 87 | using element_type = T; 88 | T value; 89 | template 90 | constexpr member(Self&, tag_and_value tv) 91 | : value(std::move(tv.value)) {} 92 | 93 | template 94 | constexpr member(Self& self) : value(call_init(self, Init)) {} 95 | template 96 | constexpr member(Self& self, no_conversion) 97 | : value(call_init(self, Init)) {} 98 | template 99 | constexpr member(Self& self, 100 | tag_and_value>> 101 | tv_or) requires(!std::is_reference_v) 102 | : value(tv_or.value.has_value() ? std::move(*tv_or.value) 103 | : call_init(self, Init)) {} 104 | 105 | constexpr member(member&&) = default; 106 | constexpr member(const member&) = default; 107 | 108 | constexpr member& operator=(member&&) = default; 109 | constexpr member& operator=(const member&) = default; 110 | 111 | auto operator<=>(const member&) const = default; 112 | }; 113 | 114 | template 115 | struct meta_struct_impl : Members... { 116 | template 117 | constexpr meta_struct_impl(Parms p) : Members(*this, std::move(p))... {} 118 | 119 | constexpr meta_struct_impl() : Members(*this)... {} 120 | constexpr meta_struct_impl(meta_struct_impl&&) = default; 121 | constexpr meta_struct_impl(const meta_struct_impl&) = default; 122 | constexpr meta_struct_impl& operator=(meta_struct_impl&&) = default; 123 | constexpr meta_struct_impl& operator=(const meta_struct_impl&) = default; 124 | 125 | auto operator<=>(const meta_struct_impl&) const = default; 126 | }; 127 | 128 | template 129 | struct meta_struct : meta_struct_impl { 130 | using super = meta_struct_impl; 131 | template 132 | constexpr meta_struct(TagsAndValues... tags_and_values) 133 | : super(parms(std::move(tags_and_values)...)) {} 134 | 135 | constexpr meta_struct() = default; 136 | constexpr meta_struct(meta_struct&&) = default; 137 | constexpr meta_struct(const meta_struct&) = default; 138 | constexpr meta_struct& operator=(meta_struct&&) = default; 139 | constexpr meta_struct& operator=(const meta_struct&) = default; 140 | 141 | auto operator<=>(const meta_struct&) const = default; 142 | }; 143 | 144 | template 145 | constexpr decltype(auto) meta_struct_apply( 146 | F&& f, meta_struct_impl& m) { 147 | return std::forward(f)(static_cast(m)...); 148 | } 149 | 150 | template 151 | constexpr decltype(auto) meta_struct_apply( 152 | F&& f, const meta_struct_impl& m) { 153 | return std::forward(f)(static_cast(m)...); 154 | } 155 | 156 | template 157 | constexpr decltype(auto) meta_struct_apply( 158 | F&& f, meta_struct_impl&& m) { 159 | return std::forward(f)(static_cast(m)...); 160 | } 161 | 162 | template 163 | struct apply_static_impl; 164 | 165 | template 166 | struct apply_static_impl> { 167 | template 168 | constexpr static decltype(auto) apply(F&& f) { 169 | return f(static_cast(nullptr)...); 170 | } 171 | }; 172 | 173 | template 174 | auto meta_struct_apply(F&& f) { 175 | return apply_static_impl::apply( 176 | std::forward(f)); 177 | } 178 | 179 | template 180 | decltype(auto) get_impl(member& m) { 181 | return (m.value); 182 | } 183 | 184 | template 185 | decltype(auto) get_impl(const member& m) { 186 | return (m.value); 187 | } 188 | 189 | template 190 | decltype(auto) get_impl(member&& m) { 191 | return std::move(m.value); 192 | } 193 | 194 | template 195 | decltype(auto) get(MetaStruct&& s) { 196 | return get_impl(std::forward(s)); 197 | } 198 | 199 | #include 200 | #include 201 | 202 | template 203 | void print(std::ostream& os, const MetaStruct& ms) { 204 | meta_struct_apply( 205 | [&](const auto&... m) { 206 | auto print_item = [&](auto& m) { 207 | std::cout << m.tag().sv() << ":" << m.value << "\n"; 208 | }; 209 | (print_item(m), ...); 210 | }, 211 | ms); 212 | }; 213 | 214 | using substr_args = meta_struct< // 215 | member<"str", const std::string&, required>, // 216 | member<"offset", std::size_t, [] { return 0; }>, // 217 | member<"count", std::size_t, 218 | [](auto& self) { 219 | return get<"str">(self).size() - get<"offset">(self); 220 | }> // 221 | >; 222 | 223 | auto substr(substr_args args) { 224 | return get<"str">(args).substr(get<"offset">(args), get<"count">(args)); 225 | } 226 | 227 | int main() { 228 | using Person = meta_struct< // 229 | member<"id", int, required>, // 230 | member<"name", std::string, required>, // 231 | member<"score", int, [](auto& self) { return get<"id">(self) + 1; }> // 232 | >; 233 | 234 | meta_struct_apply([](M * ...) { 235 | std::cout << "The tags are: "; 236 | auto print_tag = [](auto t) { std::cout << t.sv() << " "; }; 237 | (print_tag(M::tag()), ...); 238 | std::cout << "\n"; 239 | }); 240 | 241 | Person p{arg<"id"> = 2, arg<"name"> = "John"}; 242 | 243 | std::cout << get<"id">(p) << " " << get<"name">(p) << " " << get<"score">(p) 244 | << "\n"; 245 | 246 | Person p2{arg<"name"> = "JRB", arg<"id"> = 2, 247 | arg<"score"> = std::optional()}; 248 | print(std::cout, p2); 249 | 250 | std::string s = "Hello World"; 251 | auto pos = s.find(' '); 252 | auto all = substr({arg<"str"> = std::ref(s)}); 253 | auto first = substr({arg<"str"> = std::ref(s), arg<"count"> = pos}); 254 | auto second = substr({arg<"str"> = std::ref(s), arg<"offset"> = pos + 1}); 255 | 256 | std::cout << all << "\n" << first << "\n" << second << "\n"; 257 | } 258 | -------------------------------------------------------------------------------- /meta_struct_20/cppcon_version/meta_struct_sqlite_example.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2020 Google LLC 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // https://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | #include 16 | 17 | #include "meta_struct_sqlite.h" 18 | int main() { 19 | using ftsd::arg; 20 | 21 | sqlite3 *sqldb; 22 | sqlite3_open(":memory:", &sqldb); 23 | 24 | ftsd::prepared_statement< // 25 | R"( CREATE TABLE customers( 26 | id INTEGER NOT NULL PRIMARY KEY, 27 | name TEXT NOT NULL 28 | );)" // 29 | >{sqldb} 30 | .execute(); 31 | 32 | ftsd::prepared_statement< // 33 | R"( CREATE TABLE orders( 34 | id INTEGER NOT NULL PRIMARY KEY, 35 | item TEXT NOT NULL, 36 | customerid INTEGER NOT NULL, 37 | price REAL NOT NULL, 38 | discount_code TEXT 39 | );)" // 40 | >{sqldb} 41 | .execute(); 42 | 43 | ftsd::prepared_statement< 44 | R"(INSERT INTO customers(name) 45 | VALUES(? /*:name:text*/);)" // 46 | >{sqldb} 47 | .execute({arg<"name"> = "John"}); 48 | 49 | auto customer_id_or = ftsd::prepared_statement< 50 | R"(SELECT id /*:integer*/ from customers 51 | WHERE name = ? /*:name:text*/;)" // 52 | >{sqldb} 53 | .execute_single_row({arg<"name"> = "John"}); 54 | 55 | if (!customer_id_or) { 56 | std::cerr << "Unable to find customer name\n"; 57 | return 1; 58 | } 59 | auto customer_id = get<"id">(customer_id_or.value()); 60 | 61 | ftsd::prepared_statement< 62 | R"(INSERT INTO orders(item , customerid , price, discount_code ) 63 | VALUES (?/*:item:text*/, ?/*:customerid:integer*/, ?/*:price:real*/, 64 | ?/*:discount_code:text?*/ );)" // 65 | > 66 | insert_order{sqldb}; 67 | 68 | insert_order.execute({arg<"item"> = "Phone", arg<"price"> = 1444.4, 69 | arg<"customerid"> = customer_id}); 70 | insert_order.execute({arg<"item"> = "Laptop", arg<"price"> = 1300.4, 71 | arg<"customerid"> = customer_id}); 72 | insert_order.execute({arg<"customerid"> = customer_id, arg<"price"> = 2000, 73 | arg<"item"> = "MacBook", 74 | ftsd::arg<"discount_code"> = "BIGSALE"}); 75 | 76 | ftsd::prepared_statement< 77 | R"(SELECT orders.id /*:integer*/, name/*:text*/, item/*:text*/, 78 | price/*:real*/, 79 | discount_code/*:text?*/ 80 | FROM orders JOIN customers ON customers.id = customerid 81 | WHERE price > ?/*:min_price:real*/;)" // 82 | > 83 | select_orders{sqldb}; 84 | 85 | for (;;) { 86 | std::cout << "Enter min price.\n"; 87 | double min_price = 0; 88 | std::cin >> min_price; 89 | 90 | for (auto &row : 91 | select_orders.execute_rows({arg<"min_price"> = min_price})) { 92 | // Access the fields using by indexing the row with the column (`_col`). 93 | // We will get a compiler error if we try to access a column that is not 94 | // part of the select statement. 95 | std::cout << get<"orders.id">(row) << " "; 96 | std::cout << get<"price">(row) << " "; 97 | std::cout << get<"name">(row) << " "; 98 | std::cout << get<"item">(row) << " "; 99 | std::cout << ftsd::get<"item">(row) << " "; 100 | std::cout << get<"discount_code">(row).value_or("") << "\n"; 101 | } 102 | } 103 | } 104 | -------------------------------------------------------------------------------- /meta_struct_20/cppcon_version/struct.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | struct person { 5 | int id = 1; 6 | std::string name; 7 | int score = 0; 8 | }; 9 | 10 | int main() { 11 | person p{.id = 1, .name = "John"}; 12 | p.id = 2; 13 | p.name = "JRB"; 14 | std::cout << p.id << " " << p.name; 15 | } -------------------------------------------------------------------------------- /metaprogrammed_polymorphism/benchmark.cpp: -------------------------------------------------------------------------------- 1 | #include "polymorphic.hpp" 2 | #include 3 | #include 4 | 5 | #ifdef _MSC_VER 6 | #pragma comment(lib,"shlwapi.lib") 7 | #endif 8 | 9 | #include "benchmark_imp.h" 10 | 11 | 12 | void SomeFunction() {} 13 | 14 | 15 | std::vector GetRandVector() { 16 | static std::vector vec = []() { 17 | std::vector vec; 18 | for (int i = 0; i < 100; ++i) { 19 | vec.push_back(std::rand()); 20 | } 21 | return vec; 22 | }(); 23 | return vec; 24 | } 25 | 26 | static void BM_Virtual(benchmark::State& state) { 27 | auto b = MakeBase(); 28 | auto pb = b.get(); 29 | // Perform setup here 30 | for (auto _ : state) { 31 | // This code gets timed 32 | benchmark::DoNotOptimize(pb->draw()); 33 | } 34 | } 35 | 36 | constexpr int size = 100; 37 | static void BM_VirtualVector(benchmark::State& state) { 38 | std::vector> objects; 39 | for (int i:GetRandVector()) { 40 | objects.push_back(MakeBaseRand(i)); 41 | } 42 | // Perform setup here 43 | for (auto _ : state) { 44 | // This code gets timed 45 | for (auto& o : objects) { 46 | benchmark::DoNotOptimize(o->draw()); 47 | } 48 | } 49 | } 50 | static void BM_PolyRef(benchmark::State& state) { 51 | Dummy d; 52 | polymorphic::ref ref(d); 53 | // Perform setup here 54 | for (auto _ : state) { 55 | // This code gets timed 56 | benchmark::DoNotOptimize(ref.call()); 57 | } 58 | static_assert(sizeof(ref) == 3 * sizeof(void*)); 59 | } 60 | 61 | static void BM_PolyObject(benchmark::State& state) { 62 | Dummy d; 63 | polymorphic::object ref(d); 64 | // Perform setup here 65 | for (auto _ : state) { 66 | // This code gets timed 67 | benchmark::DoNotOptimize(ref.call()); 68 | } 69 | static_assert(sizeof(ref) == 4 * sizeof(void*)); 70 | } 71 | 72 | static void BM_PolyObjectVector(benchmark::State& state) { 73 | std::vector> objects; 74 | for (int i:GetRandVector()) { 75 | objects.push_back(GetObjectRand(i)); 76 | } 77 | // Perform setup here 78 | for (auto _ : state) { 79 | // This code gets timed 80 | for (auto& o : objects) { 81 | benchmark::DoNotOptimize(o.call()); 82 | } 83 | } 84 | } 85 | 86 | static void BM_PolyRefVector(benchmark::State& state) { 87 | std::vector> objects; 88 | for (int i:GetRandVector()) { 89 | objects.push_back(GetObjectRand(i)); 90 | } 91 | 92 | std::vector> refs(objects.begin(), objects.end()); 93 | // Perform setup here 94 | for (auto _ : state) { 95 | // This code gets timed 96 | for (auto& r : refs) { 97 | benchmark::DoNotOptimize(r.call()); 98 | } 99 | } 100 | } 101 | 102 | static void BM_Function(benchmark::State& state) { 103 | auto f = GetFunction(); 104 | // Perform setup here 105 | for (auto _ : state) { 106 | // This code gets timed 107 | benchmark::DoNotOptimize(f()); 108 | } 109 | } 110 | 111 | static void BM_FunctionVector(benchmark::State& state) { 112 | std::vector> objects; 113 | for (int i:GetRandVector()) { 114 | objects.push_back(GetFunctionRand(i)); 115 | } 116 | // Perform setup here 117 | for (auto _ : state) { 118 | // This code gets timed 119 | for (auto& o : objects) { 120 | benchmark::DoNotOptimize(o()); 121 | } 122 | } 123 | } 124 | 125 | static void BM_NonVirtual(benchmark::State& state) { 126 | NonVirtual n; 127 | // Perform setup here 128 | for (auto _ : state) { 129 | // This code gets timed 130 | benchmark::DoNotOptimize(n.draw()); 131 | } 132 | } 133 | 134 | static void BM_NonVirtualVector(benchmark::State& state) { 135 | std::vector objects; 136 | for (int i = 0; i < GetRandVector().size(); ++i) { 137 | objects.push_back(NonVirtual{}); 138 | } 139 | // Perform setup here 140 | for (auto _ : state) { 141 | // This code gets timed 142 | for (auto& o : objects) { 143 | benchmark::DoNotOptimize(o.draw()); 144 | } 145 | } 146 | } 147 | // Register the function as a benchmark 148 | BENCHMARK(BM_NonVirtual); 149 | BENCHMARK(BM_Virtual); 150 | BENCHMARK(BM_Function); 151 | BENCHMARK(BM_PolyRef); 152 | BENCHMARK(BM_PolyObject); 153 | 154 | BENCHMARK(BM_NonVirtualVector); 155 | BENCHMARK(BM_VirtualVector); 156 | BENCHMARK(BM_FunctionVector); 157 | BENCHMARK(BM_PolyRefVector); 158 | BENCHMARK(BM_PolyObjectVector); 159 | 160 | 161 | BENCHMARK_MAIN(); 162 | -------------------------------------------------------------------------------- /metaprogrammed_polymorphism/benchmark_imp.cpp: -------------------------------------------------------------------------------- 1 | #include "benchmark_imp.h" 2 | 3 | struct Imp :Base { 4 | int draw() override { return 5; } 5 | 6 | }; 7 | 8 | struct Imp2 :Base { 9 | int draw() override { return 10; } 10 | 11 | }; 12 | 13 | 14 | 15 | std::unique_ptr MakeBase() { 16 | return std::make_unique(); 17 | } 18 | int poly_extend(draw, Dummy&) { return 5; } 19 | int poly_extend(draw, int&) { return 10; } 20 | 21 | 22 | std::function GetFunction() { 23 | return []() {return 5; }; 24 | } 25 | 26 | int NonVirtual::draw() { return 5; } 27 | 28 | std::function GetFunctionRand(int r) { 29 | if (r % 2) { 30 | return []() {return 5; }; 31 | } 32 | else { 33 | return []() {return 10; }; 34 | } 35 | } 36 | std::unique_ptr MakeBaseRand(int r) { 37 | if (r % 2) { 38 | return std::make_unique(); 39 | } 40 | else { 41 | return std::make_unique(); 42 | } 43 | } 44 | polymorphic::object GetObjectRand(int r) { 45 | if (r % 2) { 46 | return { Dummy{} }; 47 | 48 | } 49 | else { 50 | return { int{} }; 51 | } 52 | 53 | 54 | } 55 | -------------------------------------------------------------------------------- /metaprogrammed_polymorphism/benchmark_imp.h: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "polymorphic.hpp" 4 | struct Dummy {}; 5 | 6 | class draw {}; 7 | int poly_extend(draw, Dummy&); 8 | 9 | struct Base { 10 | virtual int draw() = 0; 11 | virtual ~Base() {} 12 | }; 13 | 14 | struct NonVirtual { 15 | 16 | int draw(); 17 | }; 18 | 19 | std::function GetFunction(); 20 | std::unique_ptr MakeBase(); 21 | 22 | std::function GetFunctionRand(int r); 23 | std::unique_ptr MakeBaseRand(int r); 24 | polymorphic::object GetObjectRand(int r); -------------------------------------------------------------------------------- /metaprogrammed_polymorphism/entity_examples/overload.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | using my_time = int; 6 | 7 | template 8 | void draw(const T& t, std::ostream& os) { 9 | os << t << "\n"; 10 | } 11 | 12 | template 13 | void debug_draw(const T& t, std::ostream& os) { 14 | os << "Debug\n"; 15 | draw(t, os); 16 | } 17 | 18 | // By default do nothing 19 | template 20 | void update(T& t, my_time time) {} 21 | 22 | struct my_clock { 23 | my_time time = 0; 24 | void update(my_time t) { time = t; } 25 | }; 26 | 27 | inline void draw(const my_clock& c, std::ostream& os) { 28 | os << "The time is now: " << c.time << "\n"; 29 | } 30 | 31 | inline void update(my_clock& c, my_time time) { c.update(time); } 32 | 33 | 34 | template 35 | void draw_helper(const T& t){ 36 | draw(t, std::cout); 37 | } 38 | 39 | int main() { 40 | int a = 5; 41 | std::string s = "Hello"; 42 | my_clock c; 43 | 44 | update(a, 1); 45 | update(s, 1); 46 | update(c, 1); 47 | 48 | draw(a, std::cout); 49 | draw(s, std::cout); 50 | draw(c, std::cout); 51 | 52 | debug_draw(a, std::cout); 53 | debug_draw(s, std::cout); 54 | debug_draw(c, std::cout); 55 | 56 | draw_helper(c); 57 | } 58 | -------------------------------------------------------------------------------- /metaprogrammed_polymorphism/entity_examples/polymorphic.cpp: -------------------------------------------------------------------------------- 1 | #include "..//polymorphic.hpp" 2 | #include 3 | #include 4 | 5 | using my_time = int; 6 | 7 | class draw {}; 8 | class debug_draw {}; 9 | class update {}; 10 | 11 | template void poly_extend(draw, const T& t, std::ostream& os) { 12 | os << t << "\n"; 13 | } 14 | 15 | template 16 | void poly_extend(debug_draw, const T& t, std::ostream& os) { 17 | os << "Debug "; 18 | poly_extend(draw{}, t, os); 19 | } 20 | 21 | // By default do nothing 22 | template void poly_extend(update, T& t, my_time time) {} 23 | 24 | using entity = polymorphic::object; 27 | 28 | struct my_clock { 29 | my_time time = 0; 30 | void update(my_time t) { time = t; } 31 | }; 32 | 33 | inline void poly_extend(draw, const my_clock& c, std::ostream& os) { 34 | os << "The time is now: " << c.time << "\n"; 35 | } 36 | 37 | inline void poly_extend(update, my_clock& c, my_time time) { c.update(time); } 38 | 39 | #include 40 | #include 41 | 42 | inline void 43 | draw_helper(polymorphic::ref d) { 44 | d.call(std::cout); 45 | } 46 | 47 | inline void 48 | debug_draw_helper(polymorphic::ref d) { 49 | d.call(std::cout); 50 | } 51 | 52 | int main() { 53 | std::vector entities{ 5, std::string("Hello"), my_clock() }; 54 | auto entities2 = entities; 55 | for (auto& e : entities) { 56 | e.call(1); 57 | e.call(std::cout); 58 | } 59 | for (const auto& e : entities2) { 60 | e.call(std::cout); 61 | } 62 | for (auto& e : entities) { 63 | draw_helper(e); 64 | debug_draw_helper(e); 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /metaprogrammed_polymorphism/entity_examples/regular.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | using my_time = int; 5 | 6 | template void draw(const T &t, std::ostream &os) { 7 | os << t << "\n"; 8 | } 9 | 10 | template void debug_draw(const T &t, std::ostream &os) { 11 | os << "Debug\n"; 12 | draw(t, os); 13 | } 14 | 15 | // By default do nothing 16 | template void update(T &t, my_time time) {} 17 | 18 | namespace detail { 19 | struct entity_interface { 20 | virtual void draw_(std::ostream &os) const = 0; 21 | virtual void debug_draw_(std::ostream &os) const = 0; 22 | virtual void update_(my_time t) = 0; 23 | virtual entity_interface *clone_() const = 0; 24 | virtual ~entity_interface() {} 25 | }; 26 | 27 | template struct entity_imp : entity_interface { 28 | void draw_(std::ostream &os) const override { draw(t_, os); } 29 | void debug_draw_(std::ostream &os) const override { debug_draw(t_, os); } 30 | void update_(my_time t) override { update(t_, t); } 31 | entity_interface *clone_() const { return new entity_imp(t_); } 32 | 33 | entity_imp(T t) : t_(std::move(t)) {} 34 | 35 | T t_; 36 | }; 37 | } // namespace detail 38 | 39 | struct entity { 40 | template 41 | entity(T t) : e_(std::make_unique>(std::move(t))) {} 42 | entity(entity &&) = default; 43 | entity &operator=(entity &&) = default; 44 | 45 | entity(const entity &other) : e_(other.e_ ? other.e_->clone_() : nullptr) {} 46 | entity &operator=(const entity &other) { 47 | entity tmp(other); 48 | *this = std::move(tmp); 49 | return *this; 50 | } 51 | 52 | explicit operator bool() const { return e_ != nullptr; } 53 | void draw(std::ostream &os) const { e_->draw_(os); } 54 | void debug_draw(std::ostream &os) const { e_->debug_draw_(os); } 55 | void update(my_time t) { e_->update_(t); } 56 | 57 | std::unique_ptr e_; 58 | }; 59 | 60 | struct my_clock { 61 | my_time time = 0; 62 | void update(my_time t) { time = t; } 63 | }; 64 | 65 | inline void draw(const my_clock &c, std::ostream &os) { 66 | os << "The time is now: " << c.time << "\n"; 67 | } 68 | 69 | inline void update(my_clock &c, my_time time) { c.update(time); } 70 | 71 | #include 72 | #include 73 | int main() { 74 | std::vector entities{5, std::string("Hello"), my_clock()}; 75 | auto entities2 = entities; 76 | for (auto &e : entities) { 77 | e.update(1); 78 | e.draw(std::cout); 79 | } 80 | for (const auto &e : entities2) { 81 | e.draw(std::cout); 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /metaprogrammed_polymorphism/entity_examples/virtual.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | using my_time = int; 6 | 7 | struct draw_interface { 8 | virtual void draw(std::ostream& os) const = 0; 9 | virtual ~draw_interface() {} 10 | }; 11 | struct entity_interface : draw_interface { 12 | virtual void debug_draw(std::ostream& os) const = 0; 13 | virtual void update(my_time t) = 0; 14 | }; 15 | 16 | struct int_holder : entity_interface { 17 | void draw(std::ostream& os) const override { os << value << "\n"; } 18 | void debug_draw(std::ostream& os) const override { 19 | os << "Debug\n" << value << "\n"; 20 | } 21 | void update(my_time t) override {} 22 | 23 | int_holder(int v) : value(v) {} 24 | int value; 25 | }; 26 | 27 | struct my_clock : entity_interface { 28 | my_time time = 0; 29 | void draw(std::ostream& os) const override { 30 | os << "The time is: " << time << "\n"; 31 | } 32 | void debug_draw(std::ostream& os) const override { 33 | os << "Debug\n" << time << "\n"; 34 | } 35 | void update(my_time t) override { time = t; } 36 | }; 37 | 38 | void draw_helper(const draw_interface& d) { d.draw(std::cout); } 39 | 40 | int main() { 41 | std::vector> entities; 42 | 43 | entities.push_back(std::make_unique(5)); 44 | entities.push_back(std::make_unique()); 45 | 46 | for (auto& e : entities) { 47 | draw_helper(*e); 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /metaprogrammed_polymorphism/example.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2018 Google LLC 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // https://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // limitations under the License. 13 | 14 | #include "polymorphic.hpp" 15 | 16 | #include 17 | #include 18 | #include 19 | #include 20 | 21 | class draw {}; 22 | class x2 {}; 23 | 24 | // Use types instead of names 25 | // void draw(std::ostream&) -> void(draw, std::ostream&) 26 | void call_draw(polymorphic::ref d) { 27 | std::cout << "in call_draw\n"; 28 | d.call(std::cout); 29 | } 30 | 31 | 32 | template 33 | void poly_extend(draw, const T& t, std::ostream& os) { 34 | os << t << "\n"; 35 | } 36 | 37 | class x2; 38 | template 39 | void poly_extend(x2, T& t, std::unique_ptr) { 40 | t = t + t; 41 | } 42 | 43 | int main() { 44 | std::vector), 46 | void(draw, std::ostream & os) const 47 | >> objects; 48 | for (int i = 0; i < 30; ++i) { 49 | switch (i % 3) { 50 | case 0: 51 | objects.emplace_back(i); 52 | break; 53 | case 1: 54 | objects.emplace_back(double(i) + double(i) / 10.0); 55 | break; 56 | case 2: 57 | objects.emplace_back(std::to_string(i) + " string"); 58 | break; 59 | } 60 | } 61 | auto o = objects.front(); 62 | polymorphic::object co(10); 63 | auto co1 = co; 64 | call_draw(co); 65 | for (const auto& o : objects) call_draw(o); 66 | for (auto& o : objects) o.call(nullptr); 67 | for (auto& o : objects) call_draw(o); 68 | } 69 | -------------------------------------------------------------------------------- /metaprogrammed_polymorphism/polymorphic_test.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2018 Google LLC 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // https://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // limitations under the License. 13 | 14 | #include 15 | #include 16 | #include "polymorphic.hpp" 17 | 18 | struct x2 {}; 19 | struct stupid_hash {}; 20 | 21 | void poly_extend(x2, int& i) { i *= 2; } 22 | void poly_extend(x2, std::string& s) { s = s + s; } 23 | 24 | int poly_extend(stupid_hash, const int& i) { return i; } 25 | int poly_extend(stupid_hash, const std::string& s) { return static_cast(s.size()); } 26 | 27 | 28 | 29 | TEST(Polymorphic, MutableRef) { 30 | std::string s("hello"); 31 | int i = 5; 32 | 33 | polymorphic::ref r{ s }; 34 | r.call(); 35 | r = i; 36 | r.call(); 37 | 38 | EXPECT_THAT(i, 10); 39 | EXPECT_THAT(s, "hellohello"); 40 | 41 | } 42 | 43 | TEST(Polymorphic, CopyMutableRef) { 44 | std::string s("hello"); 45 | int i = 5; 46 | 47 | polymorphic::ref r{ s }; 48 | r.call(); 49 | r = i; 50 | r.call(); 51 | auto r2 = r; 52 | r2.call(); 53 | 54 | EXPECT_THAT(i, 20); 55 | EXPECT_THAT(s, "hellohello"); 56 | 57 | } 58 | 59 | TEST(Polymorphic, MutableObject) { 60 | std::string s("hello"); 61 | int i = 5; 62 | 63 | polymorphic::object o{ s }; 64 | o.call(); 65 | const auto& s_ref = *static_cast(o.get_ptr()); 66 | EXPECT_THAT(s_ref, "hellohello"); 67 | o = i; 68 | o.call(); 69 | 70 | const auto& i_ref = *static_cast(o.get_ptr()); 71 | EXPECT_THAT(i_ref, 10); 72 | 73 | } 74 | 75 | TEST(Polymorphic, CopyMutableObject) { 76 | std::string s("hello"); 77 | int i = 5; 78 | 79 | polymorphic::object o{ s }; 80 | auto o2 = o; 81 | 82 | o.call(); 83 | const auto& s_ref = *static_cast(o.get_ptr()); 84 | const auto& s_ref2 = *static_cast(o2.get_ptr()); 85 | EXPECT_THAT(s_ref, "hellohello"); 86 | EXPECT_THAT(s_ref2, "hello"); 87 | o = i; 88 | o2 = o; 89 | o2.call(); 90 | 91 | const auto& i_ref = *static_cast(o.get_ptr()); 92 | const auto& i_ref2 = *static_cast(o2.get_ptr()); 93 | EXPECT_THAT(i_ref, 5); 94 | EXPECT_THAT(i_ref2, 10); 95 | } 96 | 97 | TEST(Polymorphic, ConstRef) { 98 | const std::string s("hello"); 99 | const int i = 5; 100 | 101 | polymorphic::ref r{ s }; 102 | EXPECT_THAT(r.call(),static_cast(s.size())); 103 | 104 | r = i; 105 | EXPECT_THAT(r.call(),i); 106 | } 107 | 108 | TEST(Polymorphic, CopyConstRef) { 109 | std::string s("hello"); 110 | const int i = 5; 111 | 112 | polymorphic::ref r{ std::as_const(s) }; 113 | EXPECT_THAT(r.call(),static_cast(s.size())); 114 | auto r2 = r; 115 | 116 | s = "jrb"; 117 | EXPECT_THAT(r.call(),static_cast(s.size())); 118 | EXPECT_THAT(r2.call(),static_cast(s.size())); 119 | 120 | r = i; 121 | EXPECT_THAT(r.call(),i); 122 | EXPECT_THAT(r2.call(),static_cast(s.size())); 123 | } 124 | 125 | TEST(Polymorphic, CopyConstRefFromMutable) { 126 | std::string s("hello world"); 127 | const int i = 5; 128 | 129 | polymorphic::ref r{ s }; 130 | EXPECT_THAT(r.call(),static_cast(s.size())); 131 | 132 | polymorphic::ref r2{ i }; 133 | 134 | EXPECT_THAT(r2.call(),i); 135 | r2 = r; 136 | EXPECT_THAT(r2.call(),static_cast(s.size())); 137 | r.call(); 138 | EXPECT_THAT(r2.call(),static_cast(s.size())); 139 | EXPECT_THAT(s, "hello worldhello world"); 140 | } 141 | 142 | TEST(Polymorphic, CopyMutableRefFromObject) { 143 | int i = 5; 144 | 145 | polymorphic::object o{ i }; 146 | o.call(); 147 | polymorphic::ref r = o; 148 | r.call(); 149 | 150 | EXPECT_THAT(20, o.call()); 151 | 152 | } 153 | 154 | TEST(Polymorphic, CopyConstRefFromObject) { 155 | int i = 5; 156 | 157 | polymorphic::object o{ i }; 158 | o.call(); 159 | polymorphic::ref r = std::as_const(o); 160 | EXPECT_THAT(10, r.call()); 161 | o.call(); 162 | EXPECT_THAT(20, r.call()); 163 | 164 | 165 | } 166 | 167 | 168 | 169 | 170 | int main(int argc, char **argv) { 171 | testing::InitGoogleTest(&argc, argv); 172 | return RUN_ALL_TESTS(); 173 | } 174 | -------------------------------------------------------------------------------- /metaprogramming_examples/metaprogramming_examples.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | template struct holder { T t; }; 4 | 5 | template struct tuple_impl; 6 | 7 | template 8 | struct tuple_impl, Ts...> : holder... {}; 9 | 10 | template 11 | using tuple = tuple_impl, Ts...>; 12 | 13 | template T &get(holder &h) { return h.t; } 14 | 15 | template T &get(holder &h) { return h.t; } 16 | 17 | #include 18 | #include 19 | 20 | 21 | void test_tuple() { 22 | tuple t{1, "hello"}; 23 | std::cout << get<1>(t) << "\n"; 24 | std::cout << get<0>(t) << "\n"; 25 | 26 | get(t) = 5; 27 | get(t) = "world"; 28 | 29 | std::cout << get<1>(t) << "\n"; 30 | std::cout << get<0>(t) << "\n"; 31 | } 32 | 33 | #include 34 | 35 | template struct overload : F... { using F::operator()...; }; 36 | 37 | template overload(F...)->overload; 38 | 39 | void test_overload() { 40 | std::variant v; 41 | v = std::string("hello"); 42 | 43 | std::visit( 44 | overload{[](int i) { std::cout << i << " int \n"; }, 45 | [](const std::string &s) { std::cout << s << " string \n"; }}, 46 | v); 47 | } 48 | 49 | #include 50 | template 51 | struct pair {}; 52 | 53 | template 54 | struct map :Pairs...{}; 55 | 56 | template 57 | V value_impl(pair); 58 | 59 | template 60 | D value_impl(...); 61 | 62 | 63 | 64 | template 65 | using value = decltype(value_impl(M{})); 66 | 67 | 68 | 69 | void test_map() { 70 | 71 | using m1 = map, pair>; 72 | using m2 = map, pair>; 73 | 74 | static_assert(std::is_same_v < value, std::string>); 75 | static_assert(std::is_same_v < value, int>); 76 | static_assert(std::is_same_v < value, char>); 77 | 78 | 79 | 80 | 81 | } 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | int main() { 90 | test_tuple(); 91 | test_overload(); 92 | test_map(); 93 | } 94 | -------------------------------------------------------------------------------- /mutex_condition/mutex_condition.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | template 9 | class mtq { 10 | public: 11 | mtq(int max_size) : max_size_(max_size) {} 12 | 13 | void push(T t) { 14 | std::unique_lock lock{mut_}; 15 | for (;;) { 16 | if (q_.size() < max_size_) { 17 | q_.push(std::move(t)); 18 | cvar_.notify_all(); 19 | return; 20 | } else { 21 | cvar_.wait(lock); 22 | } 23 | } 24 | } 25 | 26 | std::optional pop() { 27 | std::unique_lock lock{mut_}; 28 | for (;;) { 29 | if (!q_.empty()) { 30 | T t = q_.front(); 31 | q_.pop(); 32 | cvar_.notify_all(); 33 | return t; 34 | } else { 35 | if (done_) return std::nullopt; 36 | cvar_.wait(lock); 37 | } 38 | } 39 | } 40 | 41 | bool done() const { 42 | std::unique_lock lock{mut_}; 43 | return done_; 44 | } 45 | 46 | void set_done() { 47 | std::unique_lock lock{mut_}; 48 | done_ = true; 49 | cvar_.notify_all(); 50 | } 51 | 52 | private: 53 | int max_size_ = 0; 54 | bool done_ = false; 55 | std::queue q_; 56 | mutable std::mutex mut_; 57 | mutable std::condition_variable cvar_; 58 | }; 59 | 60 | class latch { 61 | public: 62 | latch(int counter) : counter_(counter) {} 63 | 64 | void wait() { 65 | std::unique_lock lock{mut_}; 66 | for (;;) { 67 | if (counter_ <= 0) { 68 | return; 69 | } else { 70 | cvar_.wait(lock); 71 | } 72 | } 73 | } 74 | 75 | void count_down(std::ptrdiff_t n = 1) { 76 | std::unique_lock lock{mut_}; 77 | if (counter_ > 0) { 78 | counter_ -= n; 79 | } 80 | cvar_.notify_all(); 81 | } 82 | 83 | private: 84 | int counter_ = 0; 85 | mutable std::mutex mut_; 86 | mutable std::condition_variable cvar_; 87 | }; 88 | 89 | class thread_group { 90 | public: 91 | template 92 | void push(Args &&... args) { 93 | threads_.emplace_back(std::forward(args)...); 94 | } 95 | 96 | void join_all() { 97 | for (auto &thread : threads_) { 98 | if (thread.joinable()) { 99 | thread.join(); 100 | } 101 | } 102 | } 103 | 104 | ~thread_group() { join_all(); } 105 | 106 | private: 107 | std::vector threads_; 108 | }; 109 | 110 | std::vector compress(const std::vector &in) { 111 | std::this_thread::sleep_for(std::chrono::seconds(rand() % 5 + 1)); 112 | return in; 113 | } 114 | 115 | std::vector read(std::istream &is, size_t n) { 116 | std::vector in(n); 117 | if (!is.read(in.data(), n)) { 118 | in.resize(is.gcount()); 119 | } 120 | return in; 121 | } 122 | 123 | void write(std::ostream &os, const std::vector &out) { 124 | os.write(out.data(), out.size()); 125 | } 126 | 127 | using block_q = mtq>>; 128 | 129 | void reader(block_q &reader_q, mtq &back_pressure, std::istream &is) { 130 | int id = 0; 131 | while (is) { 132 | back_pressure.pop(); 133 | reader_q.push({id, read(is, 3)}); 134 | ++id; 135 | } 136 | reader_q.set_done(); 137 | } 138 | 139 | void compressor(block_q &reader_q, block_q &writer_q, latch &l) { 140 | for (;;) { 141 | auto block = reader_q.pop(); 142 | if (!block) { 143 | l.count_down(); 144 | return; 145 | } 146 | writer_q.push({block->first, compress(block->second)}); 147 | } 148 | } 149 | 150 | void writer_q_closer(block_q &writer_q, latch &l) { 151 | l.wait(); 152 | writer_q.set_done(); 153 | } 154 | 155 | struct in_order_comparator { 156 | template 157 | bool operator()(T &a, T &b) { 158 | return a.first > b.first; 159 | } 160 | }; 161 | void in_order_writer(block_q &writer_q, mtq &back_pressure, 162 | std::ostream &os) { 163 | int counter = 0; 164 | std::priority_queue>, 165 | std::vector>>, 166 | in_order_comparator> 167 | pq; 168 | for (;;) { 169 | while (!pq.empty() && pq.top().first == counter) { 170 | write(os, pq.top().second); 171 | back_pressure.push(1); 172 | ++counter; 173 | pq.pop(); 174 | } 175 | auto block = writer_q.pop(); 176 | if (!block) return; 177 | pq.push(std::move(*block)); 178 | } 179 | } 180 | 181 | #include 182 | int main() { 183 | thread_group tg; 184 | std::string instring = "abcdefghijklmnopqrstuvwxyz"; 185 | std::istringstream is(instring); 186 | std::ostringstream os; 187 | const int q_depth = 15; 188 | block_q reader_q(q_depth); 189 | block_q writer_q(q_depth); 190 | mtq back_pressure(q_depth); 191 | for (int i = 0; i < q_depth; ++i) { 192 | back_pressure.push(1); 193 | } 194 | latch l(std::thread::hardware_concurrency()); 195 | tg.push([&]() mutable { reader(reader_q, back_pressure, is); }); 196 | for (int i = 0; i < std::thread::hardware_concurrency(); ++i) { 197 | tg.push([&]() mutable { compressor(reader_q, writer_q, l); }); 198 | } 199 | tg.push([&]() mutable { writer_q_closer(writer_q, l); }); 200 | tg.push([&]() mutable { in_order_writer(writer_q, back_pressure, os); }); 201 | tg.join_all(); 202 | 203 | if (os.str() == instring) { 204 | std::cout << "SUCCESS\n"; 205 | } else { 206 | std::cout << "FAILURE\n"; 207 | } 208 | std::cout << os.str() << "\n"; 209 | } 210 | -------------------------------------------------------------------------------- /polymorphism/crtp/crtp.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | template 5 | struct shape { 6 | void draw()const { 7 | std::cout << "Preparing screen\n"; 8 | static_cast(this)->draw_implementation(); 9 | } 10 | }; 11 | 12 | struct square : shape { 13 | void draw_implementation() const { std::cout << "square::draw\n"; } 14 | }; 15 | 16 | struct circle : shape { 17 | void draw_implementation()const { std::cout << "circle::draw\n"; } 18 | }; 19 | 20 | template 21 | void draw(const Shape& shape) { 22 | shape.draw(); 23 | } 24 | 25 | 26 | int main() { 27 | circle c; 28 | square s; 29 | 30 | draw(c); 31 | draw(s); 32 | 33 | } -------------------------------------------------------------------------------- /polymorphism/inheritance/inheritance.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "shapes.hpp" 4 | #include "shape_drawer.hpp" 5 | 6 | 7 | int main() { 8 | 9 | std::vector> shapes; 10 | 11 | shapes.push_back(std::make_unique()); 12 | shapes.push_back(std::make_unique()); 13 | 14 | draw_shapes(shapes); 15 | 16 | 17 | } -------------------------------------------------------------------------------- /polymorphism/inheritance/shape_drawer.cpp: -------------------------------------------------------------------------------- 1 | #include "shape_drawer.hpp" 2 | 3 | void draw_shapes(const std::vector>& shapes) { 4 | for (const auto& shape : shapes) shape->draw(); 5 | } 6 | -------------------------------------------------------------------------------- /polymorphism/inheritance/shape_drawer.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "shapes_interface.hpp" 3 | #include 4 | 5 | void draw_shapes(const std::vector>& shapes); 6 | -------------------------------------------------------------------------------- /polymorphism/inheritance/shapes.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include "shapes_interface.hpp" 4 | 5 | struct square :public shape { 6 | void draw() const { 7 | std::cout << "square::draw\n"; 8 | } 9 | }; 10 | 11 | struct circle :public shape { 12 | void draw() const { 13 | std::cout << "circle::draw\n"; 14 | } 15 | }; 16 | 17 | -------------------------------------------------------------------------------- /polymorphism/inheritance/shapes_interface.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | 4 | struct shape { 5 | virtual void draw()const = 0; 6 | virtual ~shape() {} 7 | }; 8 | -------------------------------------------------------------------------------- /polymorphism/overloading/overloading.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | struct circle { 4 | void draw() const { 5 | std::cout << "circle::draw\n"; 6 | } 7 | }; 8 | 9 | struct square { 10 | void draw() const { 11 | std::cout << "square::draw\n"; 12 | } 13 | }; 14 | 15 | template 16 | void draw(const Shape& shape) { 17 | shape.draw(); 18 | } 19 | 20 | struct point {}; 21 | 22 | void draw(point) { 23 | std::cout << "point::draw\n"; 24 | } 25 | 26 | int main() { 27 | square s; 28 | circle c; 29 | point p; 30 | 31 | draw(s); 32 | draw(c); 33 | draw(p); 34 | 35 | 36 | 37 | } -------------------------------------------------------------------------------- /polymorphism/regular_polymorphism/regular_polymorphism.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include "shapes.hpp" 5 | #include "shapes_drawer.hpp" 6 | 7 | int main() { 8 | std::vector shapes; 9 | shapes.emplace_back(); 10 | shapes.emplace_back(circle{}); 11 | shapes.emplace_back(square{}); 12 | composite c; 13 | c.shapes_.emplace_back(square{}); 14 | c.shapes_.emplace_back(circle{}); 15 | shapes.emplace_back(std::move(c)); 16 | shapes.emplace_back(other_library::triangle{}); 17 | shapes.emplace_back(my_namespace::my_shape{}); 18 | 19 | draw_shapes(shapes); 20 | 21 | 22 | } 23 | -------------------------------------------------------------------------------- /polymorphism/regular_polymorphism/shapes.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "shapes_interface.hpp" 3 | 4 | struct circle { 5 | void draw() const { std::cout << "circle::draw\n"; } 6 | }; 7 | 8 | struct square { 9 | void draw() const { std::cout << "square::draw\n"; } 10 | }; 11 | 12 | struct composite { 13 | std::vector shapes_; 14 | void draw() const { 15 | std::cout << "begin composite\n"; 16 | for (auto& s : shapes_) s.draw(); 17 | std::cout << "end composite\n"; 18 | } 19 | }; 20 | 21 | namespace other_library { 22 | struct triangle { 23 | void display()const { std::cout << "triangle::display\n"; } 24 | }; 25 | 26 | void draw_implementation(const triangle& t) { t.display(); } 27 | 28 | } 29 | 30 | namespace my_namespace { 31 | struct my_shape {}; 32 | void draw_implementation(my_shape) { std::cout << "my_shape:draw\n"; } 33 | } // namespace my_namespace 34 | 35 | -------------------------------------------------------------------------------- /polymorphism/regular_polymorphism/shapes_drawer.cpp: -------------------------------------------------------------------------------- 1 | #include "shapes_drawer.hpp" 2 | 3 | void draw_shapes(const std::vector& shapes) { 4 | for (const auto& shape : shapes) shape.draw(); 5 | } 6 | -------------------------------------------------------------------------------- /polymorphism/regular_polymorphism/shapes_drawer.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "shapes_interface.hpp" 3 | #include 4 | 5 | void draw_shapes(const std::vector& shapes); -------------------------------------------------------------------------------- /polymorphism/regular_polymorphism/shapes_interface.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | namespace my_shapes { 5 | 6 | struct empty_shape {}; 7 | 8 | template 9 | void draw_implementation(T& t) { 10 | t.draw(); 11 | } 12 | 13 | inline void draw_implementation(empty_shape) { std::cout << "empty\n"; } 14 | 15 | class shape { 16 | public: 17 | shape() = default; 18 | template 19 | explicit shape(T&& t) 20 | : ptr_(std::make_unique>(std::forward(t))) {} 21 | shape(shape&&) = default; 22 | shape(const shape& other) : ptr_(other.ptr_->clone()) {} 23 | shape& operator=(shape&&) = default; 24 | shape& operator=(const shape& other) { 25 | auto new_shape = other; 26 | (*this) = std::move(new_shape); 27 | return *this; 28 | } 29 | 30 | void draw()const { 31 | if (ptr_) 32 | ptr_->draw_(); 33 | else 34 | draw_implementation(empty_shape{}); 35 | } 36 | 37 | private: 38 | struct shape_interface { 39 | virtual void draw_() const = 0; 40 | virtual std::unique_ptr clone() const = 0; 41 | ~shape_interface() = default; 42 | }; 43 | 44 | template 45 | struct shape_implementation : shape_interface { 46 | void draw_() const override { 47 | draw_implementation(t_); 48 | } 49 | std::unique_ptr clone() const override { 50 | return std::make_unique(t_); 51 | } 52 | shape_implementation() = default; 53 | template 54 | explicit shape_implementation(U&& u) : t_(std::forward(u)) {} 55 | 56 | T t_; 57 | }; 58 | 59 | std::unique_ptr ptr_; 60 | }; 61 | 62 | } // namespace shapes 63 | 64 | -------------------------------------------------------------------------------- /rust/.gitignore: -------------------------------------------------------------------------------- 1 | **/target/ 2 | **/dist/ 3 | **/.idea/ 4 | 5 | # Remove Cargo.lock from gitignore if creating an executable, leave it for libraries 6 | # More information here https://doc.rust-lang.org/cargo/guide/cargo-toml-vs-cargo-lock.html 7 | #Cargo.lock 8 | 9 | # These are backup files generated by rustfmt 10 | **/*.rs.bk -------------------------------------------------------------------------------- /rust/Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | version = 3 4 | 5 | [[package]] 6 | name = "ahash" 7 | version = "0.7.6" 8 | source = "registry+https://github.com/rust-lang/crates.io-index" 9 | checksum = "fcb51a0695d8f838b1ee009b3fbf66bda078cd64590202a864a8f3e8c4315c47" 10 | dependencies = [ 11 | "getrandom", 12 | "once_cell", 13 | "version_check", 14 | ] 15 | 16 | [[package]] 17 | name = "aho-corasick" 18 | version = "0.7.15" 19 | source = "registry+https://github.com/rust-lang/crates.io-index" 20 | checksum = "7404febffaa47dac81aa44dba71523c9d069b1bdc50a77db41195149e17f68e5" 21 | dependencies = [ 22 | "memchr", 23 | ] 24 | 25 | [[package]] 26 | name = "bitflags" 27 | version = "1.2.1" 28 | source = "registry+https://github.com/rust-lang/crates.io-index" 29 | checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693" 30 | 31 | [[package]] 32 | name = "cc" 33 | version = "1.0.67" 34 | source = "registry+https://github.com/rust-lang/crates.io-index" 35 | checksum = "e3c69b077ad434294d3ce9f1f6143a2a4b89a8a2d54ef813d85003a4fd1137fd" 36 | 37 | [[package]] 38 | name = "cfg-if" 39 | version = "1.0.0" 40 | source = "registry+https://github.com/rust-lang/crates.io-index" 41 | checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" 42 | 43 | [[package]] 44 | name = "fallible-iterator" 45 | version = "0.2.0" 46 | source = "registry+https://github.com/rust-lang/crates.io-index" 47 | checksum = "4443176a9f2c162692bd3d352d745ef9413eec5782a80d8fd6f8a1ac692a07f7" 48 | 49 | [[package]] 50 | name = "fallible-streaming-iterator" 51 | version = "0.1.9" 52 | source = "registry+https://github.com/rust-lang/crates.io-index" 53 | checksum = "7360491ce676a36bf9bb3c56c1aa791658183a54d2744120f27285738d90465a" 54 | 55 | [[package]] 56 | name = "getrandom" 57 | version = "0.2.6" 58 | source = "registry+https://github.com/rust-lang/crates.io-index" 59 | checksum = "9be70c98951c83b8d2f8f60d7065fa6d5146873094452a1008da8c2f1e4205ad" 60 | dependencies = [ 61 | "cfg-if", 62 | "libc", 63 | "wasi", 64 | ] 65 | 66 | [[package]] 67 | name = "hashbrown" 68 | version = "0.11.2" 69 | source = "registry+https://github.com/rust-lang/crates.io-index" 70 | checksum = "ab5ef0d4909ef3724cc8cce6ccc8572c5c817592e9285f5464f8e86f8bd3726e" 71 | dependencies = [ 72 | "ahash", 73 | ] 74 | 75 | [[package]] 76 | name = "hashlink" 77 | version = "0.7.0" 78 | source = "registry+https://github.com/rust-lang/crates.io-index" 79 | checksum = "7249a3129cbc1ffccd74857f81464a323a152173cdb134e0fd81bc803b29facf" 80 | dependencies = [ 81 | "hashbrown", 82 | ] 83 | 84 | [[package]] 85 | name = "libc" 86 | version = "0.2.126" 87 | source = "registry+https://github.com/rust-lang/crates.io-index" 88 | checksum = "349d5a591cd28b49e1d1037471617a32ddcda5731b99419008085f72d5a53836" 89 | 90 | [[package]] 91 | name = "libsqlite3-sys" 92 | version = "0.22.2" 93 | source = "registry+https://github.com/rust-lang/crates.io-index" 94 | checksum = "290b64917f8b0cb885d9de0f9959fe1f775d7fa12f1da2db9001c1c8ab60f89d" 95 | dependencies = [ 96 | "cc", 97 | "pkg-config", 98 | "vcpkg", 99 | ] 100 | 101 | [[package]] 102 | name = "memchr" 103 | version = "2.3.4" 104 | source = "registry+https://github.com/rust-lang/crates.io-index" 105 | checksum = "0ee1c47aaa256ecabcaea351eae4a9b01ef39ed810004e298d2511ed284b1525" 106 | 107 | [[package]] 108 | name = "once_cell" 109 | version = "1.12.0" 110 | source = "registry+https://github.com/rust-lang/crates.io-index" 111 | checksum = "7709cef83f0c1f58f666e746a08b21e0085f7440fa6a29cc194d68aac97a4225" 112 | 113 | [[package]] 114 | name = "pkg-config" 115 | version = "0.3.19" 116 | source = "registry+https://github.com/rust-lang/crates.io-index" 117 | checksum = "3831453b3449ceb48b6d9c7ad7c96d5ea673e9b470a1dc578c2ce6521230884c" 118 | 119 | [[package]] 120 | name = "proc-macro2" 121 | version = "1.0.26" 122 | source = "registry+https://github.com/rust-lang/crates.io-index" 123 | checksum = "a152013215dca273577e18d2bf00fa862b89b24169fb78c4c95aeb07992c9cec" 124 | dependencies = [ 125 | "unicode-xid", 126 | ] 127 | 128 | [[package]] 129 | name = "quote" 130 | version = "1.0.9" 131 | source = "registry+https://github.com/rust-lang/crates.io-index" 132 | checksum = "c3d0b9745dc2debf507c8422de05d7226cc1f0644216dfdfead988f9b1ab32a7" 133 | dependencies = [ 134 | "proc-macro2", 135 | ] 136 | 137 | [[package]] 138 | name = "regex" 139 | version = "1.4.5" 140 | source = "registry+https://github.com/rust-lang/crates.io-index" 141 | checksum = "957056ecddbeba1b26965114e191d2e8589ce74db242b6ea25fc4062427a5c19" 142 | dependencies = [ 143 | "aho-corasick", 144 | "memchr", 145 | "regex-syntax", 146 | ] 147 | 148 | [[package]] 149 | name = "regex-syntax" 150 | version = "0.6.23" 151 | source = "registry+https://github.com/rust-lang/crates.io-index" 152 | checksum = "24d5f089152e60f62d28b835fbff2cd2e8dc0baf1ac13343bef92ab7eed84548" 153 | 154 | [[package]] 155 | name = "rusqlite" 156 | version = "0.25.4" 157 | source = "registry+https://github.com/rust-lang/crates.io-index" 158 | checksum = "5c4b1eaf239b47034fb450ee9cdedd7d0226571689d8823030c4b6c2cb407152" 159 | dependencies = [ 160 | "bitflags", 161 | "fallible-iterator", 162 | "fallible-streaming-iterator", 163 | "hashlink", 164 | "libsqlite3-sys", 165 | "memchr", 166 | "smallvec", 167 | ] 168 | 169 | [[package]] 170 | name = "smallvec" 171 | version = "1.6.1" 172 | source = "registry+https://github.com/rust-lang/crates.io-index" 173 | checksum = "fe0f37c9e8f3c5a4a66ad655a93c74daac4ad00c441533bf5c6e7990bb42604e" 174 | 175 | [[package]] 176 | name = "syn" 177 | version = "1.0.68" 178 | source = "registry+https://github.com/rust-lang/crates.io-index" 179 | checksum = "3ce15dd3ed8aa2f8eeac4716d6ef5ab58b6b9256db41d7e1a0224c2788e8fd87" 180 | dependencies = [ 181 | "proc-macro2", 182 | "quote", 183 | "unicode-xid", 184 | ] 185 | 186 | [[package]] 187 | name = "tagged_rusqlite" 188 | version = "0.1.0" 189 | dependencies = [ 190 | "rusqlite", 191 | "tagged_rusqlite_proc", 192 | "tagged_rusqlite_proc_impl", 193 | ] 194 | 195 | [[package]] 196 | name = "tagged_rusqlite_example" 197 | version = "0.1.0" 198 | dependencies = [ 199 | "rusqlite", 200 | "tagged_rusqlite", 201 | ] 202 | 203 | [[package]] 204 | name = "tagged_rusqlite_proc" 205 | version = "0.1.0" 206 | dependencies = [ 207 | "proc-macro2", 208 | "quote", 209 | "syn", 210 | "tagged_rusqlite_proc_impl", 211 | ] 212 | 213 | [[package]] 214 | name = "tagged_rusqlite_proc_impl" 215 | version = "0.1.0" 216 | dependencies = [ 217 | "proc-macro2", 218 | "quote", 219 | "regex", 220 | "rusqlite", 221 | "syn", 222 | ] 223 | 224 | [[package]] 225 | name = "unicode-xid" 226 | version = "0.2.1" 227 | source = "registry+https://github.com/rust-lang/crates.io-index" 228 | checksum = "f7fe0bb3479651439c9112f72b6c505038574c9fbb575ed1bf3b797fa39dd564" 229 | 230 | [[package]] 231 | name = "vcpkg" 232 | version = "0.2.11" 233 | source = "registry+https://github.com/rust-lang/crates.io-index" 234 | checksum = "b00bca6106a5e23f3eee943593759b7fcddb00554332e856d990c893966879fb" 235 | 236 | [[package]] 237 | name = "version_check" 238 | version = "0.9.4" 239 | source = "registry+https://github.com/rust-lang/crates.io-index" 240 | checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" 241 | 242 | [[package]] 243 | name = "wasi" 244 | version = "0.10.2+wasi-snapshot-preview1" 245 | source = "registry+https://github.com/rust-lang/crates.io-index" 246 | checksum = "fd6fbd9a79829dd1ad0cc20627bf1ed606756a7f77edff7b66b7064f9cb327c6" 247 | -------------------------------------------------------------------------------- /rust/Cargo.toml: -------------------------------------------------------------------------------- 1 | [workspace] 2 | members = ["tagged_rusqlite_example","tagged_rusqlite_proc","tagged_rusqlite_proc_impl", "tagged_rusqlite"] -------------------------------------------------------------------------------- /rust/tagged_rusqlite/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "tagged_rusqlite" 3 | version = "0.1.0" 4 | authors = ["Your Name "] 5 | edition = "2018" 6 | 7 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 8 | 9 | [dependencies] 10 | tagged_rusqlite_proc = {path = "../tagged_rusqlite_proc"} 11 | tagged_rusqlite_proc_impl = {path = "../tagged_rusqlite_proc_impl"} 12 | rusqlite = {version="0.25",features=["bundled"]} 13 | -------------------------------------------------------------------------------- /rust/tagged_rusqlite/README.md: -------------------------------------------------------------------------------- 1 | *This library is in a very preliminary state. Mainly posting to see if other people think this might be interesting* 2 | 3 | # TLDR: 4 | 5 | Annotate your sql statements with special comments, and this library will generate structs that make working with your queries easier. 6 | 7 | # Why another SQL library 8 | 9 | I was looking for a library with the following criteria: 10 | 11 | * Use SQL instead of a DSL for queries 12 | * Don't read environmental variables or connect to databases 13 | * Minimum boilerplate to get started. No need to define a file with the entire schema 14 | * Make query results and parameters strongly typed 15 | * Focus on prepared statements. 16 | * Lightweight 17 | 18 | Actually to be honest, I have been playing around with how to do this in C++20 using bleeding edge features like strings as template parameters ( [http://jrb-programming.blogspot.com/2020/05/c20-sql.html](http://jrb-programming.blogspot.com/2020/05/c20-sql.html) ), decided to try to do this in Rust. 19 | 20 | This is my very preliminary result. 21 | 22 | # Powered by Rusqlite (and SQLite) 23 | Rusqlite does most of the heavy lifting, and this is a rather lightweight veneer on top of it. I started with SQLite because it is super simple and self-contained. If there is interest, it can be extended to other databases. 24 | 25 | The example below is also largely taken from the Rusqlite example. 26 | 27 | # Main idea 28 | 29 | The main idea for me was the I very rarely write SQL in my code de novo or from first principles. Rather, I will play around with some sort of interactive SQL environment. Thus, I want something where it is easy to move the SQL back and forth with a minimum of bother. 30 | 31 | # What you do 32 | 33 | You call the proc macro `tagged_sql` supplying it with the name of your query, and the sql string, annotated with sql comments (which are old c-style `/* */` comments). You annotate the columns you are selecting with `/*:Type*/` and any parameters with `/*:name:Type*/`. 34 | 35 | The library then generates several helper structs. Let's use an example (taken largely from the Rusqlite example with some modifications): 36 | 37 | tagged_sql!( 38 | SearchByName, 39 | r#"SELECT 40 | id /*:i64*/, 41 | name /*:String*/, 42 | data /*:Option>*/ 43 | FROM person 44 | WHERE name = ? /*:name:String*/; 45 | "# 46 | ); 47 | 48 | `SearchByName` is the name of the query; `id,name,data` are the columns we are selecting. We annotate each of those columns with a special comment specifying the type those should be. There is one parameter, which we annotate with a comment saying it should be named `name` and have type `String`. 49 | 50 | Notice, because of how the annotations are all comments, this is a valid SQL string, so it is easy to copy and paste it into an interactive SQL tool. 51 | 52 | `tagged_sql` will generate 3 classes: 53 | 54 | * `SearchByName` which has a public static function `prepare` which takes a connection and returns a prepared statement specialized for this query. 55 | 56 | * `SearchByNameRow` which has members corresponding to the columns based on the annotated type. 57 | 58 | * `SearchByNameParams` which has members corresponding to the parameters based on the name and type annotations. 59 | 60 | The returned statement object has the following methods: 61 | 62 | * execute 63 | * execute_bind 64 | * query 65 | * query_bind 66 | * query_row 67 | * query_row_bind 68 | 69 | The methods with `bind` all take `Params`. Otherwise, these are very similar to the Rusqlite methods of Statement. 70 | 71 | The full code is at: 72 | https://github.com/google/cpp-from-the-sky-down/blob/master/rust/ 73 | 74 | Below is the example from: 75 | https://github.com/google/cpp-from-the-sky-down/blob/master/rust/tagged_rusqlite_example/src/main.rs 76 | 77 | 78 | use rusqlite::{Connection, Result}; 79 | use tagged_rusqlite::tagged_sql; 80 | 81 | fn main() -> Result<()> { 82 | let conn = Connection::open_in_memory()?; 83 | 84 | tagged_sql!( 85 | CreateTable, 86 | "CREATE TABLE person ( 87 | id INTEGER PRIMARY KEY, 88 | name TEXT NOT NULL, 89 | data BLOB 90 | );" 91 | ); 92 | 93 | CreateTable::prepare(&conn).execute()?; 94 | 95 | tagged_sql!( 96 | InsertPerson, 97 | r#"INSERT INTO 98 | person (name, data) 99 | VALUES ( 100 | ?1 /*:name:String*/, 101 | ?2 /*:data:Option>*/ 102 | ); 103 | "# 104 | ); 105 | 106 | let mut insert = InsertPerson::prepare(&conn); 107 | insert.execute_bind(&InsertPersonParams { 108 | name: "Steven".to_string(), 109 | data: Some(vec![1u8, 2u8]), 110 | })?; 111 | insert.execute_bind(&InsertPersonParams { 112 | name: "John".to_string(), 113 | data: None, 114 | })?; 115 | insert.execute_bind(&InsertPersonParams { 116 | name: "Bill".to_string(), 117 | data: None, 118 | })?; 119 | 120 | tagged_sql!( 121 | SelectPerson, 122 | r#"SELECT 123 | id /*:i64*/, 124 | name /*:String*/, 125 | data /*:Option>*/ 126 | FROM person; 127 | "# 128 | ); 129 | 130 | let mut stmt = SelectPerson::prepare(&conn); 131 | let person_iterator = stmt.query()?; 132 | 133 | for person in person_iterator { 134 | println!("Found person {:?}", &person.unwrap()); 135 | } 136 | 137 | tagged_sql!( 138 | SearchByName, 139 | r#"SELECT 140 | id /*:i64*/, 141 | name /*:String*/, 142 | data /*:Option>*/ 143 | FROM person 144 | WHERE name = ? /*:name:String*/; 145 | "# 146 | ); 147 | let search_params = SearchByNameParams { 148 | name: "John".into(), 149 | }; 150 | for person in SearchByName::prepare(&conn).query_bind(&search_params)? { 151 | println!( 152 | "Found person with name {} {:?}", 153 | &search_params.name, 154 | &person.unwrap() 155 | ); 156 | } 157 | 158 | let mut stmt = SelectPerson::prepare(&conn); 159 | println!("Found single person {:?} ", stmt.query_row()?); 160 | 161 | let mut stmt = SearchByName::prepare(&conn); 162 | let search_params = SearchByNameParams { 163 | name: "Bill".into(), 164 | }; 165 | println!( 166 | "Found single person with name {}, {:?} ", 167 | &search_params.name, 168 | stmt.query_row_bind(&search_params)? 169 | ); 170 | 171 | Ok(()) 172 | } 173 | 174 | /* Output 175 | Found person SelectPersonRow { id: 1, name: "Steven", data: Some([1, 2]) } 176 | Found person SelectPersonRow { id: 2, name: "John", data: None } 177 | Found person SelectPersonRow { id: 3, name: "Bill", data: None } 178 | Found person with name John SearchByNameRow { id: 2, name: "John", data: None } 179 | Found single person SelectPersonRow { id: 1, name: "Steven", data: Some([1, 2]) } 180 | Found single person with name Bill, SearchByNameRow { id: 3, name: "Bill", data: None } 181 | */ -------------------------------------------------------------------------------- /rust/tagged_rusqlite/src/lib.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2021 Google LLC 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // https://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // limitations under the License. 13 | 14 | use std::marker::PhantomData; 15 | pub use tagged_rusqlite_proc::tagged_sql; 16 | 17 | pub trait NoParams {} 18 | 19 | pub trait HasParams {} 20 | 21 | pub trait TaggedQuery { 22 | type Row; 23 | type Params; 24 | fn sql_str() -> &'static str; 25 | } 26 | 27 | pub trait TaggedRow { 28 | fn sql_str() -> &'static str; 29 | 30 | fn from_row(row: &rusqlite::Row<'_>) -> rusqlite::Result 31 | where 32 | Self: Sized; 33 | } 34 | 35 | pub trait TaggedParams { 36 | fn bind_all(&self, s: &mut rusqlite::Statement) -> rusqlite::Result<()>; 37 | } 38 | 39 | pub struct StatementHolder<'a, T: TaggedQuery> { 40 | stmt: rusqlite::Statement<'a>, 41 | fake: PhantomData, 42 | } 43 | 44 | impl<'a, T: TaggedQuery> StatementHolder<'a, T> { 45 | pub fn new(connection: &'a rusqlite::Connection) -> Self { 46 | Self { 47 | stmt: connection.prepare(T::sql_str()).unwrap(), 48 | fake: Default::default(), 49 | } 50 | } 51 | } 52 | 53 | impl<'a, T: TaggedQuery> StatementHolder<'a, T> 54 | where 55 | T: TaggedQuery + NoParams, 56 | T::Row: TaggedRow, 57 | { 58 | pub fn query( 59 | &'_ mut self, 60 | ) -> rusqlite::Result rusqlite::Result>> 61 | { 62 | self.stmt.query_map(rusqlite::params![], T::Row::from_row) 63 | } 64 | 65 | pub fn execute(&'_ mut self) -> rusqlite::Result { 66 | self.stmt.execute(rusqlite::params![]) 67 | } 68 | 69 | pub fn query_row(&'_ mut self) -> rusqlite::Result { 70 | self.stmt.query_row(rusqlite::params![], T::Row::from_row) 71 | } 72 | } 73 | 74 | impl<'a, T: TaggedQuery> StatementHolder<'a, T> 75 | where 76 | T: TaggedQuery, 77 | T::Row: TaggedRow, 78 | T::Params: TaggedParams, 79 | { 80 | pub fn query_bind( 81 | &'_ mut self, 82 | params: &T::Params, 83 | ) -> rusqlite::Result rusqlite::Result>> 84 | { 85 | params.bind_all(&mut self.stmt)?; 86 | Ok(self.stmt.raw_query().mapped(T::Row::from_row)) 87 | } 88 | 89 | pub fn execute_bind(&'_ mut self, params: &T::Params) -> rusqlite::Result { 90 | params.bind_all(&mut self.stmt)?; 91 | self.stmt.raw_execute() 92 | } 93 | 94 | pub fn query_row_bind(&'_ mut self, params: &T::Params) -> rusqlite::Result { 95 | let mut iterator = self.query_bind(¶ms)?; 96 | match iterator.next() { 97 | Some(result) => result, 98 | None => rusqlite::Result::Err(rusqlite::Error::QueryReturnedNoRows), 99 | } 100 | } 101 | } 102 | 103 | -------------------------------------------------------------------------------- /rust/tagged_rusqlite_example/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "tagged_rusqlite_example" 3 | version = "0.1.0" 4 | authors = ["Your Name "] 5 | edition = "2018" 6 | 7 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 8 | 9 | [dependencies] 10 | tagged_rusqlite = {path = "../tagged_rusqlite"} 11 | rusqlite = {version="0.25",features=["bundled"]} 12 | 13 | -------------------------------------------------------------------------------- /rust/tagged_rusqlite_example/src/lib.rs: -------------------------------------------------------------------------------- 1 | #[cfg(test)] 2 | mod tests { 3 | use rusqlite::{Connection, Result}; 4 | use tagged_rusqlite::tagged_sql; 5 | 6 | #[test] 7 | fn smoke_test() -> Result<()> { 8 | let conn = Connection::open_in_memory()?; 9 | 10 | tagged_sql!( 11 | CreateTable, 12 | "CREATE TABLE person ( 13 | id INTEGER PRIMARY KEY, 14 | name TEXT NOT NULL, 15 | data BLOB 16 | );" 17 | ); 18 | 19 | CreateTable::prepare(&conn).execute()?; 20 | 21 | tagged_sql!( 22 | InsertPerson, 23 | r#"INSERT INTO 24 | person (name, data) 25 | VALUES ( 26 | ?1 /*:name:String*/, 27 | ?2 /*:data:Option>*/ 28 | ) 29 | RETURNING id /*:i64*/; 30 | "# 31 | ); 32 | 33 | let mut insert = InsertPerson::prepare(&conn); 34 | let id = insert.query_row_bind(&InsertPersonParams { 35 | name: "Steven".to_string(), 36 | data: Some(vec![1u8, 2u8]), 37 | })?; 38 | assert_eq!(id.id,1); 39 | let id = insert.query_row_bind(&InsertPersonParams { 40 | name: "John".to_string(), 41 | data: None, 42 | })?; 43 | assert_eq!(id.id,2); 44 | let id = insert.query_row_bind(&InsertPersonParams { 45 | name: "Bill".to_string(), 46 | data: None, 47 | })?; 48 | assert_eq!(id.id,3); 49 | 50 | tagged_sql!( 51 | SelectPerson, 52 | r#"SELECT 53 | id /*:i64*/, 54 | name /*:String*/, 55 | data /*:Option>*/ 56 | FROM person; 57 | "# 58 | ); 59 | 60 | let mut stmt = SelectPerson::prepare(&conn); 61 | let people: Result, _> = stmt.query()?.collect(); 62 | assert_eq!(people?, vec![SelectPersonRow { id: 1, name: "Steven".into(), data: Some(vec![1u8, 2u8]) }, 63 | SelectPersonRow { id: 2, name: "John".into(), data: None }, 64 | SelectPersonRow { id: 3, name: "Bill".into(), data: None }, ]); 65 | 66 | tagged_sql!( 67 | SearchByName, 68 | r#"SELECT 69 | id /*:i64*/, 70 | name /*:String*/, 71 | data /*:Option>*/ 72 | FROM person 73 | WHERE name = ? /*:name2:String*/; 74 | "# 75 | ); 76 | let search_params = SearchByNameParams { 77 | name2: "John".into(), 78 | }; 79 | let people: Result, _> = SearchByName::prepare(&conn).query_bind(&search_params)?.collect(); 80 | assert_eq!(people?, vec![ 81 | SearchByNameRow { id: 2, name: "John".into(), data: None }, 82 | ]); 83 | 84 | 85 | let mut stmt = SelectPerson::prepare(&conn); 86 | assert_eq!(stmt.query_row()?, SelectPersonRow { id: 1, name: "Steven".into(), data: Some(vec![1u8, 2u8]) }); 87 | 88 | let mut stmt = SearchByName::prepare(&conn); 89 | let search_params = SearchByNameParams { 90 | name2: "Bill".into(), 91 | }; 92 | assert_eq!(stmt.query_row_bind(&search_params)?, SearchByNameRow { id: 3, name: "Bill".into(), data: None }); 93 | Ok(()) 94 | } 95 | } -------------------------------------------------------------------------------- /rust/tagged_rusqlite_example/src/main.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2021 Google LLC 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // https://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // limitations under the License. 13 | 14 | mod lib; 15 | 16 | use rusqlite::{Connection, Result}; 17 | use tagged_rusqlite::tagged_sql; 18 | 19 | fn main() -> Result<()> { 20 | let conn = Connection::open_in_memory()?; 21 | 22 | tagged_sql!( 23 | CreateCustomers, 24 | r#"CREATE TABLE customers ( 25 | id INTEGER PRIMARY KEY, 26 | name TEXT NOT NULL 27 | );"# 28 | ); 29 | 30 | CreateCustomers::prepare(&conn).execute()?; 31 | 32 | tagged_sql!( 33 | CreateOrders, 34 | r#"CREATE TABLE orders ( 35 | id INTEGER PRIMARY KEY, 36 | item TEXT NOT NULL, 37 | customerid INTEGER NOT NULL, 38 | price REAL NOT NULL, 39 | discount_code TEXT 40 | );"# 41 | ); 42 | 43 | CreateOrders::prepare(&conn).execute()?; 44 | 45 | tagged_sql!( 46 | InsertCustomer, 47 | r#"INSERT INTO customers (name) 48 | VALUES ( 49 | ? /*:name:String*/ 50 | ); 51 | "# 52 | ); 53 | 54 | InsertCustomer::prepare(&conn).execute_bind(&InsertCustomerParams { 55 | name: "John".to_string(), 56 | })?; 57 | 58 | tagged_sql!( 59 | InsertOrder, 60 | r#" 61 | INSERT into orders(item, customerid, price, discount_code) 62 | VALUES( 63 | ? /*:item:String*/, 64 | ? /*:customerid:i64*/, 65 | ? /*:price:f64*/, 66 | ? /*:discount_code:Option*/ 67 | ) 68 | "# 69 | ); 70 | 71 | tagged_sql!( 72 | FindCustomer, 73 | r#" 74 | SELECT id /*:i64*/ from customers 75 | where name = ? /*:name:String*/ 76 | "# 77 | ); 78 | 79 | let customerid: i64 = FindCustomer::prepare(&conn) 80 | .query_row_bind(&FindCustomerParams { 81 | name: "John".into(), 82 | })? 83 | .id; 84 | 85 | let mut insert_order = InsertOrder::prepare(&conn); 86 | insert_order.execute_bind(&InsertOrderParams { 87 | item: "Phone".into(), 88 | price: 1444.44, 89 | customerid, 90 | discount_code: None, 91 | })?; 92 | insert_order.execute_bind(&InsertOrderParams { 93 | item: "Laptop".into(), 94 | price: 1300.44, 95 | customerid, 96 | discount_code: None, 97 | })?; 98 | insert_order.execute_bind(&InsertOrderParams { 99 | item: "Laptop".into(), 100 | price: 2000.0, 101 | customerid, 102 | discount_code: Some("BIGSALE".to_owned()), 103 | })?; 104 | 105 | tagged_sql!( 106 | FindOrders, 107 | r#" 108 | SELECT 109 | orders.id as oid /*:i64*/, 110 | name /*:String*/, 111 | item /*:String*/, 112 | price /*:f64*/, 113 | discount_code /*:Option*/ 114 | FROM orders JOIN customers on customers.id = customerid 115 | WHERE price > ?/*:min_price:f64*/ 116 | "# 117 | ); 118 | 119 | let mut find_orders = FindOrders::prepare(&conn); 120 | for orders in find_orders.query_bind(&FindOrdersParams { min_price: 100.0 })? { 121 | let orders = orders?; 122 | println!( 123 | "{} {} {} {} {:?}", 124 | &orders.oid, &orders.name, &orders.item, &orders.price, &orders.discount_code 125 | ); 126 | } 127 | Ok(()) 128 | } 129 | -------------------------------------------------------------------------------- /rust/tagged_rusqlite_proc/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "tagged_rusqlite_proc" 3 | version = "0.1.0" 4 | authors = ["Your Name "] 5 | edition = "2018" 6 | 7 | 8 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 9 | [lib] 10 | proc-macro = true 11 | 12 | [dependencies] 13 | syn="1.0" 14 | quote="1.0" 15 | proc-macro2 = "1.0" 16 | 17 | tagged_rusqlite_proc_impl = {path = "../tagged_rusqlite_proc_impl"} 18 | -------------------------------------------------------------------------------- /rust/tagged_rusqlite_proc/src/lib.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2021 Google LLC 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // https://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // limitations under the License. 13 | 14 | use proc_macro::TokenStream; 15 | 16 | use syn::parse::{Parse, ParseStream, Result}; 17 | use syn::{parse_macro_input, Ident, LitStr, Token}; 18 | 19 | struct TaggedSql { 20 | name: String, 21 | sql: String, 22 | } 23 | 24 | impl Parse for TaggedSql { 25 | fn parse(input: ParseStream) -> Result { 26 | let name_ident: Ident = input.parse()?; 27 | input.parse::()?; 28 | 29 | let sql_lit: LitStr = input.parse()?; 30 | Ok(Self { 31 | name: name_ident.to_string(), 32 | sql: sql_lit.value(), 33 | }) 34 | } 35 | } 36 | 37 | /// Example of [function-like procedural macro][1]. 38 | /// 39 | /// [1]: https://doc.rust-lang.org/reference/procedural-macros.html#function-like-procedural-macros 40 | #[proc_macro] 41 | pub fn tagged_sql(input: TokenStream) -> TokenStream { 42 | // tagged_sql_impl(input).into() 43 | let tagged_sql = parse_macro_input!(input as TaggedSql); 44 | 45 | let tokens = tagged_rusqlite_proc_impl::tagged_sql(&tagged_sql.name, &tagged_sql.sql); 46 | 47 | tokens.into() 48 | } 49 | -------------------------------------------------------------------------------- /rust/tagged_rusqlite_proc_impl/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "tagged_rusqlite_proc_impl" 3 | version = "0.1.0" 4 | authors = ["Your Name "] 5 | edition = "2018" 6 | 7 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 8 | 9 | [dependencies] 10 | syn="1.0" 11 | quote="1.0" 12 | proc-macro2 = "1.0" 13 | regex="1" 14 | rusqlite = {version="0.25",features=["bundled"]} 15 | -------------------------------------------------------------------------------- /rust/tagged_rusqlite_proc_impl/src/lib.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2021 Google LLC 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // https://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // limitations under the License. 13 | 14 | use proc_macro2::TokenStream; 15 | use quote::quote; 16 | use regex::Regex; 17 | 18 | #[derive(Debug)] 19 | struct SqlMember { 20 | name: String, 21 | type_name: String, 22 | } 23 | 24 | impl SqlMember { 25 | fn to_decl(&self) -> TokenStream { 26 | let name = syn::parse_str::(&self.name).unwrap(); 27 | let type_name = syn::parse_str::(&self.type_name).unwrap(); 28 | quote! {#name:#type_name} 29 | } 30 | fn to_member_ref(&self, s: &str) -> TokenStream { 31 | let s = syn::parse_str::(&s).unwrap(); 32 | let member = syn::parse_str::(&self.name).unwrap(); 33 | quote! { 34 | &#s.#member 35 | } 36 | } 37 | 38 | fn to_read_from_row(&self, row: &str, index: usize) -> TokenStream { 39 | let member = syn::parse_str::(&self.name).unwrap(); 40 | let row = syn::parse_str::(row).unwrap(); 41 | quote! { 42 | #member:#row.get(#index)? 43 | } 44 | } 45 | } 46 | 47 | pub fn tagged_sql(struct_name_str: &str, sql: &str) -> proc_macro2::TokenStream { 48 | let r = Regex::new(r#"([ ]*[a-zA-Z0-9_]+)|([ ]*/\*:[^*]+\*/)"#).unwrap(); 49 | 50 | let v: Vec<_> = r 51 | .captures_iter(sql) 52 | .map(|c| c.get(0).unwrap().as_str()) 53 | .collect(); 54 | let struct_name = syn::parse_str::(&struct_name_str).unwrap(); 55 | let param_name = syn::parse_str::(&format!("{}Params", struct_name_str)).unwrap(); 56 | let row_name = syn::parse_str::(&format!("{}Row", struct_name_str)).unwrap(); 57 | let mut select_members = Vec::new(); 58 | let mut param_members = Vec::new(); 59 | for (index, &part) in v.iter().enumerate() { 60 | let part = part.trim(); 61 | if part.starts_with("/*:") && part.ends_with("*/") { 62 | let middle = part 63 | .strip_prefix("/*:") 64 | .unwrap() 65 | .strip_suffix("*/") 66 | .unwrap() 67 | .trim(); 68 | if middle.find(":").is_none() { 69 | let name = v[index - 1].trim(); 70 | select_members.push(SqlMember { 71 | name: name.to_owned(), 72 | type_name: middle.to_owned(), 73 | }); 74 | } else { 75 | let parts: Vec<_> = middle.split(":").collect(); 76 | let name = parts[0].trim(); 77 | param_members.push(SqlMember { 78 | name: name.to_owned(), 79 | type_name: parts[1].to_owned(), 80 | }); 81 | } 82 | } 83 | } 84 | 85 | let select_decls: Vec<_> = select_members.iter().map(|m| m.to_decl()).collect(); 86 | 87 | let mut tokens = Vec::new(); 88 | 89 | tokens.push(quote! { 90 | #[derive(PartialOrd, PartialEq, Debug)] 91 | struct #row_name{ 92 | #(#select_decls),* 93 | }}); 94 | 95 | let read_from_rows: Vec<_> = select_members 96 | .iter() 97 | .enumerate() 98 | .map(|(index, m)| m.to_read_from_row("row", index)) 99 | .collect(); 100 | 101 | tokens.push(quote! { 102 | impl tagged_rusqlite::TaggedRow for #row_name{ 103 | fn sql_str() ->&'static str{ 104 | #sql 105 | } 106 | fn from_row(row:&rusqlite::Row<'_>) -> rusqlite::Result 107 | where Self:Sized{ 108 | Ok(Self{ 109 | #(#read_from_rows),* 110 | }) 111 | } 112 | } 113 | }); 114 | 115 | let param_decls: Vec<_> = param_members.iter().map(|m| m.to_decl()).collect(); 116 | tokens.push(quote! { 117 | struct #param_name{ 118 | #(#param_decls),* 119 | }}); 120 | 121 | let param_refs: Vec<_> = param_members 122 | .iter() 123 | .map(|m| m.to_member_ref("self")) 124 | .collect(); 125 | let mut binds = Vec::new(); 126 | for (i, r) in param_refs.iter().enumerate() { 127 | let index = i + 1; 128 | binds.push(quote! { 129 | s.raw_bind_parameter(#index,#r)?; 130 | }); 131 | } 132 | 133 | tokens.push(quote! { 134 | impl tagged_rusqlite::TaggedParams for #param_name{ 135 | fn bind_all(&self,s:&mut rusqlite::Statement) ->rusqlite::Result<()>{ 136 | #(#binds)* 137 | Ok(()) 138 | } 139 | } 140 | }); 141 | 142 | tokens.push(quote! { 143 | struct #struct_name{} 144 | }); 145 | 146 | tokens.push(quote! { 147 | impl tagged_rusqlite::TaggedQuery for #struct_name{ 148 | type Row = #row_name; 149 | type Params = #param_name; 150 | fn sql_str() ->&'static str{ 151 | #sql 152 | } 153 | } 154 | }); 155 | 156 | tokens.push(quote! { 157 | impl<'a> #struct_name{ 158 | pub fn prepare(connection: &'a rusqlite::Connection)->tagged_rusqlite::StatementHolder<'a,#struct_name>{ 159 | tagged_rusqlite::StatementHolder::new(connection) 160 | } 161 | } 162 | }); 163 | 164 | let struct_trait = if param_members.is_empty() { 165 | syn::parse_str::("NoParams").unwrap() 166 | } else { 167 | syn::parse_str::("HasParams").unwrap() 168 | }; 169 | 170 | tokens.push(quote! { 171 | impl tagged_rusqlite::#struct_trait for #struct_name{} 172 | }); 173 | 174 | quote! {#(#tokens)*} 175 | } 176 | -------------------------------------------------------------------------------- /rust/tagged_rusqlite_proc_impl/src/main.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2021 Google LLC 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // https://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // limitations under the License. 13 | 14 | use tagged_rusqlite_proc_impl::tagged_sql; 15 | 16 | fn main() { 17 | println!( 18 | "{}", 19 | tagged_sql("MyStruct", "Select name /*:String*/ ? /*:user:i32*/") 20 | ); 21 | println!("{:?}", tagged_sql("MyStruct", "Select name /*:String*/")); 22 | } 23 | -------------------------------------------------------------------------------- /rust_gmail_sorter/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "rust_gmail_sorter" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | google-gmail1 = "*" 10 | hyper = "^0.14" 11 | hyper-rustls = "^0.22" 12 | serde = "^1.0" 13 | serde_json = "^1.0" 14 | tokio = { version = "1", features = ["full"] } 15 | chrono = "0.4.19" 16 | html2text = "0.2.1" 17 | pancurses = {version = "0.16.1", features = ["win32"]} 18 | dotenv = "0.15.0" 19 | itertools = "0.10.0" 20 | 21 | anyhow = "1.0.40" 22 | -------------------------------------------------------------------------------- /scratch/actions/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.24) 2 | project(actions) 3 | 4 | set(CMAKE_CXX_STANDARD 23) 5 | 6 | add_executable(actions main.cpp) 7 | -------------------------------------------------------------------------------- /sfinae/sfinae.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | struct AdGroup { 6 | int customer_id() const { return 5; } 7 | int campaign_id() const { return 5; } 8 | int ad_group_id() const { return 5; } 9 | }; 10 | 11 | struct Campaign { 12 | int customer_id() const { return 5; } 13 | int campaign_id() const { return 5; } 14 | }; 15 | 16 | struct Customer { 17 | int customer_id() const { return 5; } 18 | }; 19 | 20 | template 21 | typename T::value_type get_value(const T& t) { 22 | return t(); 23 | } 24 | 25 | int get_value(int i) { return i; } 26 | 27 | template 28 | struct enable_if {}; 29 | 30 | template 31 | struct enable_if { 32 | using type = T; 33 | }; 34 | 35 | template 36 | using enable_if_t = typename enable_if::type; 37 | 38 | template = true> 39 | std::string Size(const T&) { 40 | return "small"; 41 | } 42 | 43 | template = 4, bool> = true> 44 | std::string Size(const T&) { 45 | return "big"; 46 | } 47 | 48 | template 49 | using void_t = void; 50 | 51 | template 52 | T declval(); 53 | 54 | template 55 | struct HasCampaignId : std::false_type {}; 56 | 57 | template 58 | struct HasCampaignId().campaign_id())>> 59 | : std::true_type {}; 60 | 61 | template 62 | constexpr bool has_campaign_id(){ 63 | return false; 64 | } 65 | 66 | 67 | 68 | 69 | template 70 | constexpr bool has_campaign_id() 71 | requires requires(T t){t.campaign_id();} 72 | { 73 | return true; 74 | } 75 | 76 | 77 | template 78 | constexpr bool has_ad_group_id(){ 79 | if constexpr(requires(T t){t.ad_group_id();}){ 80 | return true; 81 | } 82 | else{ 83 | return false; 84 | } 85 | } 86 | 87 | 88 | int main() { 89 | std::integral_constant ic; 90 | int i = 3; 91 | std::cout << get_value(ic) << " " << get_value(i) << "\n"; 92 | std::cout << Size(1) << " " << Size('a') << "\n"; 93 | std::cout << HasCampaignId::value << " " 94 | << HasCampaignId::value << "\n"; 95 | std::cout << has_campaign_id() << " " 96 | << has_campaign_id() << "\n"; 97 | std::cout << has_ad_group_id() << " " 98 | << has_ad_group_id() << "\n"; 99 | 100 | 101 | 102 | 103 | } 104 | -------------------------------------------------------------------------------- /simple_type_name/example.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2019 Google LLC 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // https://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | #include 16 | #include "simple_type_name.h" 17 | 18 | namespace test { 19 | struct MyClass; 20 | } 21 | 22 | template 23 | class TemplateTester; 24 | 25 | int main() { 26 | std::cout << skydown::short_type_name << "\n"; 27 | std::cout << skydown::long_type_name << "\n"; 28 | 29 | static_assert(skydown::short_type_name == "int"); 30 | static_assert(skydown::short_type_name> == 31 | "TemplateTester"); 32 | static_assert(skydown::short_type_name == "MyClass"); 33 | } -------------------------------------------------------------------------------- /simple_type_name/simple_type_name.h: -------------------------------------------------------------------------------- 1 | // Copyright 2019 Google LLC 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // https://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | #pragma once 16 | 17 | #include 18 | #include 19 | 20 | namespace skydown { 21 | 22 | namespace detail { 23 | 24 | #if !defined(__clang__) && !defined(__GNUC__) && defined(_MSC_VER) 25 | #define SIMPLE_TYPE_NAME_PRETTY_FUNCTION __FUNCSIG__ 26 | #else 27 | #define SIMPLE_TYPE_NAME_PRETTY_FUNCTION __PRETTY_FUNCTION__ 28 | 29 | #endif 30 | 31 | template 32 | constexpr std::string_view type_to_string_raw() { 33 | return SIMPLE_TYPE_NAME_PRETTY_FUNCTION; 34 | } 35 | 36 | constexpr std::string_view long_double_raw_string = 37 | type_to_string_raw(); 38 | 39 | constexpr std::string_view long_double_string = "long double"; 40 | 41 | constexpr std::size_t begin_type_name = 42 | long_double_raw_string.find(long_double_string); 43 | static_assert(begin_type_name != std::string_view::npos); 44 | 45 | constexpr std::size_t end_type_name = 46 | begin_type_name + long_double_string.size(); 47 | static_assert(begin_type_name != std::string_view::npos); 48 | 49 | constexpr std::size_t suffix_type_name_size = 50 | long_double_raw_string.size() - end_type_name; 51 | 52 | template 53 | constexpr std::string_view long_name() { 54 | std::string_view raw_name = type_to_string_raw(); 55 | auto size = raw_name.size(); 56 | raw_name.remove_prefix(begin_type_name); 57 | raw_name.remove_suffix(suffix_type_name_size); 58 | std::string_view struct_name("struct "); 59 | std::string_view class_name("class "); 60 | 61 | if (raw_name.substr(0, struct_name.size()) == struct_name) 62 | raw_name.remove_prefix(struct_name.size()); 63 | if (raw_name.substr(0, class_name.size()) == class_name) 64 | raw_name.remove_prefix(class_name.size()); 65 | 66 | while (!raw_name.empty() && raw_name.back() == ' ') { 67 | raw_name.remove_suffix(1); 68 | } 69 | return raw_name; 70 | } 71 | 72 | #undef SIMPLE_TYPE_NAME_PRETTY_FUNCTION 73 | 74 | template 75 | constexpr std::string_view short_name() { 76 | auto raw_str = long_name(); 77 | int last = -1; 78 | int count = 0; 79 | for (std::size_t pos = 0; pos < raw_str.size(); ++pos) { 80 | auto& c = raw_str[pos]; 81 | if (c == '<') ++count; 82 | if (c == '>') --count; 83 | if (c == ':' && count == 0) last = pos; 84 | } 85 | if (last != -1) { 86 | raw_str.remove_prefix(last + 1); 87 | } 88 | return raw_str; 89 | } 90 | 91 | } // namespace detail 92 | 93 | template 94 | inline constexpr std::string_view short_type_name = detail::short_name(); 95 | 96 | template 97 | inline constexpr std::string_view long_type_name = detail::long_name(); 98 | 99 | namespace simple_type_name_testing { 100 | static_assert(long_type_name == detail::long_double_string); 101 | static_assert(short_type_name == detail::long_double_string); 102 | 103 | struct MyClass; 104 | 105 | template 106 | class TemplateTester; 107 | 108 | static_assert(skydown::short_type_name == "int"); 109 | static_assert(skydown::short_type_name> == 110 | "TemplateTester"); 111 | static_assert(skydown::short_type_name == "MyClass"); 112 | } // namespace simple_type_name_testing 113 | } // namespace skydown 114 | -------------------------------------------------------------------------------- /string/string.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2018 Google LLC 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // https://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | 22 | template 23 | struct move_zero { 24 | T t{}; 25 | move_zero() = default; 26 | move_zero(T t) : t(t){}; 27 | move_zero(const move_zero&) = default; 28 | move_zero(move_zero&& other) { 29 | t = other.t; 30 | other.t = {}; 31 | } 32 | move_zero& operator=(const move_zero&) = default; 33 | move_zero& operator=(move_zero&& other) { 34 | auto temp = move_zero(std::move(other)); 35 | return *this = temp; 36 | } 37 | operator T() const { return t; } 38 | }; 39 | 40 | class string_rep { 41 | public: 42 | template 43 | string_rep(Iter1 b, Iter2 e, std::size_t capacity) 44 | : ptr_(capacity ? std::make_unique(capacity) : nullptr), 45 | size_(std::distance(b, e)), 46 | capacity_(capacity) { 47 | if (capacity_) { 48 | std::copy(b, e, ptr_.get()); 49 | ptr_.get()[size_] = 0; 50 | } 51 | } 52 | 53 | string_rep() = default; 54 | string_rep(const string_rep& other) 55 | : string_rep(other.data(), other.data() + other.size(), 56 | other.capacity()) {} 57 | string_rep(string_rep&&) = default; 58 | string_rep& operator=(string_rep&&) = default; 59 | string_rep& operator=(const string_rep& other) { 60 | auto temp = other; 61 | return *this = std::move(temp); 62 | } 63 | 64 | std::size_t size() const { return size_; } 65 | void size(std::size_t size) { size_ = size; } 66 | std::size_t capacity() const { return capacity_; } 67 | const char* data() const { return ptr_.get(); } 68 | char* data() { return ptr_.get(); } 69 | 70 | private: 71 | std::unique_ptr ptr_; 72 | move_zero size_ = 0; 73 | move_zero capacity_ = 0; 74 | }; 75 | 76 | class string { 77 | public: 78 | string() = default; 79 | string(const char* s) : rep_(s, s + std::strlen(s), std::strlen(s) + 1) {} 80 | 81 | auto data() const { return rep_.data(); } 82 | auto data() { return rep_.data(); } 83 | auto size() const { return rep_.size(); } 84 | auto capacity() const { return rep_.capacity(); } 85 | auto begin() const { return data(); } 86 | auto begin() { return data(); } 87 | auto end() const { return begin() + size(); } 88 | auto end() { return begin() + size(); } 89 | void reserve(size_t new_capacity) { 90 | if (new_capacity > capacity()) { 91 | rep_ = string_rep(begin(), end(), new_capacity); 92 | } 93 | } 94 | 95 | string& operator+=(const string& other) { 96 | auto new_size = size() + other.size(); 97 | reserve(new_size + 1); 98 | std::copy(other.begin(), other.end(), end()); 99 | data()[new_size] = 0; 100 | rep_.size(new_size); 101 | return *this; 102 | } 103 | 104 | private: 105 | string_rep rep_; 106 | }; 107 | 108 | inline string operator+(string a, const string& b) { 109 | a += b; 110 | return a; 111 | } 112 | 113 | inline bool operator==(const string& a, const string& b) { 114 | return std::equal(a.begin(), a.end(), b.begin(), b.end()); 115 | } 116 | 117 | inline std::ostream& operator<<(std::ostream& os, const string& s) { 118 | os.write(s.data(), s.size()); 119 | return os; 120 | } 121 | 122 | template 123 | string concat(string first, String&&... strings) { 124 | first.reserve(1 + (strings.size() + ...)); 125 | return (first += ... += strings); 126 | } 127 | 128 | int main() { 129 | string a = "Hello world"; 130 | string hi = "hi "; 131 | string there = "there"; 132 | auto b = a + hi + there; 133 | if (a == "Hello world") { 134 | std::cout << "Yes\n"; 135 | } 136 | 137 | std::cout << b; 138 | std::cout << std::boolalpha << (b == concat(a, hi, there)); 139 | } 140 | -------------------------------------------------------------------------------- /tafn/1521R0.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/google/cpp-from-the-sky-down/9676fd002cecfa82d800cb2cc5cdc672e79387e8/tafn/1521R0.pdf -------------------------------------------------------------------------------- /tafn/example.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2018 Google LLC 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // https://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // limitations under the License. 13 | 14 | #include 15 | #include 16 | #include 17 | #include "tafn.hpp" 18 | #include 19 | 20 | 21 | struct multiply {}; 22 | struct add {}; 23 | 24 | void tafn_customization_point(multiply, tafn::type, int& i, int value) { 25 | i *= value; 26 | } 27 | int tafn_customization_point(add, tafn::type, const int& i, int value) { 28 | return i + value; 29 | } 30 | 31 | namespace algs { 32 | struct sort {}; 33 | struct unique {}; 34 | struct copy {}; 35 | template 36 | struct get {}; 37 | 38 | template //,typename = std::void_t()))>> 39 | decltype(auto) tafn_customization_point(sort, tafn::all_types, T&& t) { 40 | std::sort(t.begin(), t.end()); 41 | return std::forward(t); 42 | } 43 | template ()))>> 44 | decltype(auto) tafn_customization_point(unique, tafn::all_types, T&& t) { 45 | auto iter = std::unique(t.begin(), t.end()); 46 | t.erase(iter, t.end()); 47 | return std::forward(t); 48 | } 49 | template ()))>> 50 | decltype(auto) tafn_customization_point(copy, tafn::all_types, T&& t, I iter) { 51 | std::copy(t.begin(), t.end(), iter); 52 | return std::forward(t); 53 | } 54 | template 55 | decltype(auto) tafn_customization_point(get, tafn::all_types, T&& t) { 56 | using std::get; 57 | return get(std::forward(t)); 58 | } 59 | 60 | } // namespace algs 61 | 62 | template 63 | void sort_unique(T&& t) { 64 | using tafn::_; 65 | t* _()*_(); 66 | } 67 | 68 | #include 69 | 70 | struct dummy {}; 71 | 72 | struct operation1 {}; 73 | struct operation2 {}; 74 | 75 | dummy& tafn_customization_point(operation1, tafn::type, dummy& d, int i, 76 | std::error_code& ec) { 77 | if (i == 2) { 78 | ec = std::make_error_code(std::errc::function_not_supported); 79 | } 80 | return d; 81 | } 82 | 83 | 84 | void tafn_customization_point(operation2, tafn::type, dummy& d, int i, 85 | int j, std::error_code& ec) { 86 | if (j == 2) { 87 | ec = std::make_error_code(std::errc::function_not_supported); 88 | } 89 | } 90 | 91 | template >...>>, typename = 92 | std::enable_if_t> 93 | > 94 | decltype(auto) tafn_customization_point(tafn::all_functions, 95 | tafn::type, dummy& d, Args&&... args) { 96 | using tafn::_; 97 | std::error_code ec; 98 | 99 | auto call = [&]() mutable { 100 | return d * _(std::forward(args)..., ec); 101 | }; 102 | 103 | using V = decltype(call()); 104 | if constexpr (!std::is_same_v) { 105 | V r = call(); 106 | if (ec) throw std::system_error(ec); 107 | return r; 108 | } 109 | else { 110 | call(); 111 | if (ec) throw std::system_error(ec); 112 | } 113 | } 114 | 115 | void test_exception() { 116 | using tafn::_; 117 | try { 118 | dummy d; 119 | std::error_code ec; 120 | d*_(1, ec)*_(2, 2); 121 | } 122 | catch (const std::exception& e) { 123 | std::cerr << e.what() << "\n"; 124 | } 125 | } 126 | 127 | #include 128 | #include 129 | 130 | struct get_all_lines {}; 131 | 132 | std::vector tafn_customization_point(get_all_lines, tafn::all_types, std::istream& is) { 133 | std::vector result; 134 | std::string line; 135 | while (std::getline(is, line)) { 136 | result.push_back(line); 137 | } 138 | return result; 139 | } 140 | 141 | struct output {}; 142 | template() << std::forward(std::declval())) 145 | >> 146 | void tafn_customization_point(output, tafn::all_types, const T& t, std::ostream& os, std::string_view delimit = "") { 147 | os << t << delimit; 148 | } 149 | 150 | template 151 | struct c_value_type { 152 | using D = std::decay_t; 153 | using type = typename D::value_type; 154 | }; 155 | 156 | template 157 | using c_value_type_t = typename c_value_type::type; 158 | 159 | template 160 | struct call_for_each {}; 161 | template(std::declval()).begin()), Args...>>> 164 | void tafn_customization_point(call_for_each, tafn::all_types, C&& c, Args&&... args) { 165 | using tafn::_; 166 | for (auto&& v : std::forward(c)) { 167 | v * _(std::forward(args)...); 168 | } 169 | } 170 | 171 | namespace smart_reference { 172 | template 173 | struct reference { 174 | T* t; 175 | }; 176 | 177 | template>> 178 | decltype(auto) tafn_customization_point(tafn::all_functions, tafn::type>, T&& t, Args&&... args) { 179 | using tafn::_; 180 | return *t.t * _(std::forward(args)...); 181 | } 182 | 183 | void test() { 184 | using tafn::_; 185 | std::vector v{ 4,3,2,1,2,3 }; 186 | reference> a{ &v }; 187 | a * _() * _() * _>(std::cout, "\n"); 188 | 189 | 190 | } 191 | } 192 | 193 | 194 | namespace simple { 195 | 196 | struct get_data {}; 197 | 198 | class my_class { 199 | std::string data_; 200 | template 201 | friend decltype(auto) tafn_customization_point(get_data, tafn::type, T&& t) { 202 | return (std::forward(t).data_); 203 | } 204 | }; 205 | 206 | 207 | 208 | 209 | template 210 | struct smart_reference { 211 | T& r_; 212 | }; 213 | 214 | template>> 215 | decltype(auto) tafn_customization_point(tafn::all_functions, tafn::type>, Self&& self, Args&&... args) { 216 | using tafn::_; 217 | return std::forward(self).r_ * _(std::forward(args)...); 218 | } 219 | 220 | 221 | namespace my_methods { 222 | 223 | struct to_string {}; 224 | 225 | std::string tafn_customization_point(to_string, tafn::type, int i) { 226 | return std::to_string(i); 227 | } 228 | 229 | } 230 | 231 | void test() { 232 | using tafn::_; 233 | my_class c; 234 | c *_() = "hello world"; 235 | const my_class& cc = c; 236 | const auto& str = cc * _(); 237 | std::string& s = c * _(); 238 | 239 | smart_reference ref{ c }; 240 | std::string&& rref_str = std::move(c) * _(); 241 | std::string& cref_str = ref * _(); 242 | 243 | 244 | 5 * _(); 245 | 246 | 247 | 248 | } 249 | 250 | } 251 | 252 | 253 | 254 | #include 255 | #include 256 | int main() { 257 | 258 | using tafn::_; 259 | 260 | int i{ 5 }; 261 | 262 | i * _(10); 263 | 264 | std::cout << i; 265 | 266 | int j = 9; 267 | auto k = i * _(2)*_(3); 268 | std::cout << k << " " << (j * _(4) * _(5)) << " "; 269 | 270 | std::vector v{ 271 | 4, 4, 1, 2, 2, 9, 9, 9, 7, 6, 6, 272 | }; 273 | v * _()*_()*_>(std::cout, "\n"); 274 | sort_unique(v); 275 | 276 | auto t = std::tuple{ 1, 2, 3 }; 277 | std::cout << (t*_>()); 278 | 279 | test_exception(); 280 | 281 | 282 | //std::cin | _() | _() | _() | _>(std::cout, "\n"); 283 | std::cin * _() * _() * _() * _>(std::cout, "\n"); 284 | 285 | // std::cin.().().().>(std::cout, "\n"); 286 | } 287 | -------------------------------------------------------------------------------- /tafn/tafn.hpp: -------------------------------------------------------------------------------- 1 | // Copyright 2018 Google LLC 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // https://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // limitations under the License. 13 | 14 | #pragma once 15 | #include 16 | #include 17 | namespace tafn { 18 | template 19 | struct type {}; 20 | 21 | struct all_types {}; 22 | 23 | template 24 | struct all_functions {}; 25 | 26 | namespace detail { 27 | 28 | struct call_customization_point_imp_t { 29 | template 30 | auto operator()(Args&&... args) const -> decltype(tafn_customization_point(std::declval()...)){ 31 | return tafn_customization_point(std::forward(args)...); 32 | } 33 | }; 34 | 35 | inline constexpr call_customization_point_imp_t call_customization_point_imp; 36 | 37 | } // namespace detail 38 | 39 | template 40 | struct has_customization_point { 41 | static constexpr bool value = false; 42 | }; 43 | 44 | template 45 | struct has_customization_point { 46 | static constexpr bool value = 47 | std::is_invocable_v; 49 | }; 50 | 51 | template 52 | inline constexpr bool has_customization_point_v = 53 | has_customization_point::value; 54 | 55 | enum class customization_point_type { 56 | type_function, 57 | all_function, 58 | type_all, 59 | all_all, 60 | none 61 | }; 62 | 63 | // Calculate which customization point to use. Prefer type and function specific, though if have to choose, prefer function specific over type specific. 64 | template 65 | struct get_customization_type { 66 | using D = std::decay_t; 67 | static constexpr bool type_function = 68 | has_customization_point_v, T, Args...>; 69 | static constexpr bool type_all = has_customization_point < !type_function, 70 | all_functions, type, T, Args... > ::value; 71 | static constexpr bool all_function = 72 | has_customization_point_v; 73 | static constexpr bool all_all = has_customization_point_v < !type_function && 74 | !all_function && !type_all, 75 | all_functions, all_types, T, Args... >; 76 | 77 | static constexpr customization_point_type value = 78 | type_function 79 | ? customization_point_type::type_function 80 | : all_function 81 | ? customization_point_type::all_function 82 | : type_all ? customization_point_type::type_all 83 | : all_all ? customization_point_type::all_all 84 | : customization_point_type::none; 85 | }; 86 | 87 | // For all_functions, make sure we do not all_functions again as that will create infinite recursion. 88 | template 89 | struct get_customization_type, T, Args...> { 90 | using D = std::decay_t; 91 | static constexpr bool type_function = 92 | has_customization_point_v, T, Args...>; 93 | static constexpr bool all_function = 94 | has_customization_point_v; 95 | static constexpr customization_point_type value = 96 | type_function 97 | ? customization_point_type::type_function 98 | : all_function 99 | ? customization_point_type::all_function 100 | : customization_point_type::none; 101 | }; 102 | 103 | 104 | 105 | 106 | template 107 | struct is_action_tag_invocable : std::integral_constant::value != customization_point_type::none>{}; 108 | template 109 | inline constexpr bool is_action_tag_invocable_v = is_action_tag_invocable::value; 110 | 111 | 112 | namespace detail { 113 | 114 | template 115 | struct call_customization_point_t { 116 | template 117 | decltype(auto) operator()(T&& t, Args&&... args) const { 118 | using D = std::decay_t; 119 | 120 | constexpr auto customization_type = 121 | get_customization_type::value; 122 | static_assert(customization_type != customization_point_type::none, 123 | "No implementation of F for T"); 124 | if constexpr (customization_type == 125 | customization_point_type::type_function) { 126 | return call_customization_point_imp(F{}, type{}, std::forward(t), 127 | std::forward(args)...); 128 | } 129 | if constexpr (customization_type == customization_point_type::type_all) { 130 | return call_customization_point_imp(all_functions{}, type{}, 131 | std::forward(t), 132 | std::forward(args)...); 133 | } 134 | 135 | if constexpr (customization_type == 136 | customization_point_type::all_function) { 137 | return call_customization_point_imp(F{}, all_types{}, std::forward(t), 138 | std::forward(args)...); 139 | } 140 | if constexpr (customization_type == customization_point_type::all_all) { 141 | return call_customization_point_imp(all_functions{}, all_types{}, 142 | std::forward(t), 143 | std::forward(args)...); 144 | } 145 | } 146 | }; 147 | template 148 | struct call_customization_point_t> { 149 | template 150 | decltype(auto) operator()(T&& t, Args&&... args) const { 151 | using D = std::decay_t; 152 | 153 | constexpr auto customization_type = 154 | get_customization_type, T, Args...>::value; 155 | 156 | static_assert( 157 | customization_type == customization_point_type::type_function || 158 | customization_type == customization_point_type::type_all, 159 | "No Implementation of F for T"); 160 | if constexpr (customization_type == 161 | customization_point_type::type_function) { 162 | return call_customization_point_imp(F{}, type{}, std::forward(t), 163 | std::forward(args)...); 164 | } 165 | if constexpr (customization_type == customization_point_type::type_all) { 166 | return call_customization_point_imp(F{}, all_types{}, std::forward(t), 167 | std::forward(args)...); 168 | } 169 | } 170 | }; 171 | 172 | } // namespace detail 173 | 174 | template 175 | inline constexpr detail::call_customization_point_t 176 | call_customization_point{}; 177 | 178 | namespace detail { 179 | template 180 | struct f_args_holder { 181 | Tuple t; 182 | }; 183 | 184 | template 185 | decltype(auto) call_with_tuple_imp(std::index_sequence, T&& t, Tuple&& tuple) { 186 | return call_customization_point(std::forward(t), std::get(std::forward(tuple))...); 187 | } 188 | 189 | template 190 | decltype(auto) call_with_tuple(T&& t, Tuple&& tuple) { 191 | return call_with_tuple_imp(std::make_index_sequence>>(),std::forward(t),std::forward(tuple)); 192 | } 193 | 194 | 195 | 196 | template 197 | auto make_f_args_holder(Args&&... args) { 198 | return f_args_holder < F, 199 | decltype(std::forward_as_tuple(std::forward(args)...)) > {std::forward_as_tuple(std::forward(args)...)}; 200 | } 201 | 202 | template 203 | decltype(auto) operator|(T&& t, f_args_holder&& h) { 204 | return call_with_tuple(std::forward(t), std::move(h.t)); 205 | } 206 | 207 | template 208 | decltype(auto) operator*(T&& t, f_args_holder&& h) { 209 | return call_with_tuple(std::forward(t), std::move(h.t)); 210 | } 211 | 212 | template 213 | decltype(auto) operator*(f_args_holder&& h) { 214 | return std::apply(call_customization_point, 215 | std::move(h.t)); 216 | } 217 | 218 | 219 | 220 | 221 | template 222 | struct f_args_maker { 223 | template 224 | auto operator()(Args&&... args) const { 225 | return make_f_args_holder(std::forward(args)...); 226 | } 227 | }; 228 | 229 | 230 | } 231 | template 232 | inline constexpr detail::f_args_maker _{}; 233 | 234 | 235 | 236 | 237 | 238 | 239 | 240 | 241 | 242 | 243 | 244 | } // namespace tafn 245 | -------------------------------------------------------------------------------- /tagged_sqlite/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # CMakeList.txt : CMake project for tagged_sqlite, include source and define 2 | # project specific logic here. 3 | # 4 | cmake_minimum_required (VERSION 3.8) 5 | 6 | project(tagged_sqlite) 7 | 8 | set(CMAKE_CXX_STANDARD 17) 9 | set(CMAKE_CXX_STANDARD_REQUIRED ON) 10 | find_package(SQLite3 REQUIRED) 11 | find_package(Threads REQUIRED) 12 | 13 | 14 | # Add source to this project's executable. 15 | add_executable (example "example.cpp" "tagged_sqlite.h") 16 | target_link_libraries(example SQLite::SQLite3 Threads::Threads ${CMAKE_DL_LIBS}) 17 | 18 | 19 | # TODO: Add tests and instal l targets if needed. 20 | -------------------------------------------------------------------------------- /tagged_sqlite/example.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2020 Google LLC 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // https://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | #include "tagged_sqlite.h" 16 | 17 | inline constexpr std::string_view 18 | 19 | // Queries 20 | create_customers = R"( 21 | CREATE TABLE customers(id INTEGER NOT NULL PRIMARY KEY, name TEXT); 22 | )", 23 | create_orders = R"( 24 | CREATE TABLE orders(id INTEGER NOT NULL PRIMARY KEY, item TEXT, customerid INTEGER, price REAL); 25 | )", 26 | 27 | // Annotate typed parameters via {{?tag:type}}. In the final sql these will 28 | // be replaced with '?'. 29 | insert_customer = R"( 30 | INSERT INTO customers(id, name) VALUES( {{?id:int}}, {{?name:string}}); 31 | )", 32 | insert_order = R"( 33 | INSERT INTO orders(item , customerid , price ) 34 | VALUES ({{?item:string}},{{?customerid:int}},{{?price:double}}); 35 | )", 36 | 37 | // Annotated selected columns via {{tag:type}} a '?' after type, means to 38 | // use std::optional instead of type. Also, annotate the one parameter 39 | // price. 40 | select_orders = R"( 41 | SELECT {{orders.id:int}}, {{name:string}}, {{item:string?}}, {{price:double}} 42 | FROM orders JOIN customers ON customers.id = customerid where price > {{?price:double}} 43 | )", 44 | 45 | // Tags used in the queries (i.e. all the stuff wrapped in '{{ }}'). 46 | customers = "customers", id = "id", name = "name", orders = "orders", 47 | item = "item", customerid = "customerid", price = "price"; 48 | 49 | int main() { 50 | sqlite3 *sqldb; 51 | sqlite3_open(":memory:", &sqldb); 52 | 53 | using skydown::bind; 54 | 55 | skydown::prepare(sqldb).execute(); 56 | skydown::prepare(sqldb).execute(); 57 | skydown::prepare(sqldb).execute(bind(1), 58 | bind("John")); 59 | 60 | auto prepared_insert_order = skydown::prepare(sqldb); 61 | 62 | prepared_insert_order.execute(bind("Phone"), bind(1444.44), 63 | bind(1)); 64 | prepared_insert_order.execute(bind("Laptop"), bind(1300.44), 65 | bind(1)); 66 | prepared_insert_order.execute(bind(1), bind(2000), 67 | bind("MacBook")); 68 | 69 | using skydown::field; 70 | 71 | auto prepared_select_orders = skydown::prepare(sqldb); 72 | 73 | for (;;) { 74 | std::cout << "Enter min price.\n"; 75 | double min_price = 0; 76 | std::cin >> min_price; 77 | 78 | for (auto &row : 79 | prepared_select_orders.execute_rows(bind(min_price))) { 80 | // Access the fields using `field`. We will get a compiler error if we try 81 | // to access a field that is not part of the select statement. 82 | std::cout << field(row) << " "; 83 | // The statement below would cause a compiler error since we did not 84 | // select customers.id. 85 | // std::cout << field(row) << " "; 86 | std::cout << field(row) << " "; 87 | std::cout << field(row) << " "; 88 | std::cout << field(row).value() << "\n"; 89 | } 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /tagged_tuple/example.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2019 Google LLC 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // https://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | #include 16 | 17 | #include "../simple_type_name/simple_type_name.h" 18 | #include "tagged_tuple.h" 19 | 20 | int main() { 21 | using skydown::tagged_tuple; 22 | using skydown::tag; 23 | using skydown::make_member; 24 | using skydown::has_tag; 25 | using skydown::remove_tag; 26 | 27 | auto t = tagged_tuple{tag = 1, tag = 2.0}; 28 | 29 | std::cout << "B = " << tag(t) << "\n"; 30 | 31 | for_each(t, [](auto& t) { std::cout << t.value << "\n"; }); 32 | 33 | auto nt = append(t, make_member(3)); 34 | for_each(nt, [](auto& t) { 35 | std::cout << "\n" << t.tag_name << ": " << t.value; 36 | }); 37 | 38 | static_assert(tuple_size(nt) == 3); 39 | 40 | static_assert(has_tag); 41 | 42 | { 43 | auto t = tagged_tuple{tag = 5, 44 | make_member(std::string("value"))}; 45 | auto t2 = tagged_tuple{make_member(std::string("zvalue")), 46 | make_member(6)}; 47 | auto t3 = merge(t, t2); 48 | 49 | std::cout << "\n" << t3 << "\n"; 50 | auto t4 = tagged_tuple{make_member(t)}; 51 | auto t5 = tagged_tuple{make_member(t2)}; 52 | auto t6 = merge(t4, t5); 53 | std::cout << "\n" << t6 << "\n"; 54 | std::cout << merge(t6, tagged_tuple{make_member( 55 | tagged_tuple{remove_tag})}) 56 | << "\n"; 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /template-meta-programming/fibonacci.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2018 Google LLC 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // https://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | 21 | namespace specialization { 22 | template 23 | struct fib { 24 | enum { value = fib::value + fib::value }; 25 | }; 26 | 27 | template <> 28 | struct fib<0> { 29 | enum { value = 1 }; 30 | }; 31 | 32 | template <> 33 | struct fib<1> { 34 | enum { value = 1 }; 35 | }; 36 | 37 | } // namespace specialization 38 | 39 | namespace constexpr_function { 40 | constexpr int fibonacci(int i) { 41 | return (i < 2) ? 1 : fibonacci(i - 1) + fibonacci(i - 2); 42 | } 43 | } // namespace constexpr_function 44 | 45 | namespace constexpr_function_iterative { 46 | constexpr int fibonacci(int i) { 47 | if (i < 2) return 1; 48 | auto fib_prev = 1; 49 | auto fib_cur = 1; 50 | for (; i > 1; --i) { 51 | auto fib_next = fib_prev + fib_cur; 52 | fib_prev = fib_cur; 53 | fib_cur = fib_next; 54 | } 55 | return fib_cur; 56 | } 57 | } // namespace constexpr_function_iterative 58 | 59 | namespace templated { 60 | template 61 | struct make_ptr { 62 | using type = T *; 63 | }; 64 | 65 | template 66 | struct make_ptr { 67 | using type = T *; 68 | }; 69 | } // namespace templated 70 | 71 | template 72 | struct t2t { 73 | using type = T; 74 | }; 75 | namespace function { 76 | template 77 | auto make_ptr(t2t) { 78 | if constexpr (std::is_pointer_v) { 79 | return t2t{}; 80 | } else { 81 | return t2t{}; 82 | } 83 | } 84 | } // namespace function 85 | 86 | namespace variadic { 87 | template 88 | struct fib; 89 | 90 | template 91 | constexpr auto reverse_array(Array ar) { 92 | Array ret{}; 93 | auto begin = ar.rbegin(); 94 | for (auto &a : ret) { 95 | a = *begin++; 96 | } 97 | return ret; 98 | } 99 | 100 | template 101 | struct fib { 102 | static constexpr std::array sequence = 103 | reverse_array(std::array{I...}); 104 | }; 105 | 106 | template 107 | struct fib 108 | : fib < std::numeric_limits::max() - fcur 109 | - fprev {}; 110 | 111 | constexpr auto fibonacci = fib::sequence; 112 | 113 | } // namespace variadic 114 | 115 | int main() { 116 | static_assert(specialization::fib<4>::value == 5); 117 | static_assert(constexpr_function::fibonacci(4) == 5); 118 | static_assert(constexpr_function_iterative::fibonacci(4) == 5); 119 | static_assert(variadic::fibonacci[4] == 5); 120 | std::copy(variadic::fibonacci.begin(), variadic::fibonacci.end(), 121 | std::ostream_iterator(std::cout, "\n")); 122 | static_assert(std::is_same_v::type, int *>); 123 | static_assert(std::is_same_v::type, int *>); 124 | static_assert( 125 | std::is_same_v{}))::type, int *>); 126 | static_assert( 127 | std::is_same_v{}))::type, int *>); 128 | } 129 | -------------------------------------------------------------------------------- /units/units.hpp: -------------------------------------------------------------------------------- 1 | // Copyright 2018 Google LLC 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // https://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // limitations under the License. 13 | 14 | #include 15 | #include 16 | #include 17 | template 18 | struct unit { 19 | long double value; 20 | }; 21 | 22 | using meter = unit<1, 0, 0>; 23 | using kilogram = unit<0, 1, 0>; 24 | using second = unit<0, 0, 1>; 25 | 26 | template 27 | unit operator+(unit a, unit b) { 28 | return {a.value + b.value}; 29 | } 30 | 31 | template 32 | unit operator-(unit a, unit b) { 33 | return {a.value - b.value}; 34 | } 35 | 36 | template 37 | unit operator*(unit a, 38 | unit b) { 39 | return {a.value * b.value}; 40 | } 41 | 42 | template 43 | unit operator*(T a, unit b) { 44 | return {a * b.value}; 45 | } 46 | 47 | template 48 | unit operator/(unit a, 49 | unit b) { 50 | return {a.value / b.value}; 51 | } 52 | 53 | template 54 | unit pow(unit u) { 55 | static_assert(N >= 0, "pow only supports positive powers for now"); 56 | 57 | if (N == 0) return {1.0}; 58 | auto value = u.value; 59 | for (int i = 1; i < N; ++i) { 60 | value = value * value; 61 | } 62 | return {value}; 63 | } 64 | 65 | template 66 | unit sqrt(unit u) { 67 | constexpr auto m = M / 2; 68 | constexpr auto k = K / 2; 69 | constexpr auto s = S / 2; 70 | static_assert(m * 2 == M && k * 2 == K && s * 2 == S, 71 | "Don't yet support fractional exponents"); 72 | return {std::sqrt(u.value)}; 73 | } 74 | 75 | using newton = unit<1, 1, -2>; 76 | 77 | template 78 | std::ostream& print_unit(std::ostream& os, std::string_view abbrev) { 79 | switch (V) { 80 | case 0: 81 | break; 82 | case 1: 83 | os << abbrev; 84 | break; 85 | default: 86 | os << abbrev << "^" << V; 87 | } 88 | return os; 89 | } 90 | 91 | template 92 | std::ostream& operator<<(std::ostream& os, unit u) { 93 | os << u.value; 94 | print_unit(os, "m"); 95 | print_unit(os, "kg"); 96 | print_unit(os, "s"); 97 | return os; 98 | } 99 | 100 | std::ostream& operator<<(std::ostream& os, newton n) { 101 | os << n.value << "N"; 102 | return os; 103 | } 104 | 105 | using joule = unit<2, 1, -2>; 106 | std::ostream& operator<<(std::ostream& os, joule n) { 107 | os << n.value << "J"; 108 | return os; 109 | } 110 | 111 | meter operator""_m(long double v) { return {v}; } 112 | kilogram operator""_kg(long double v) { return {v}; } 113 | second operator""_s(long double v) { return {v}; } 114 | 115 | 116 | -------------------------------------------------------------------------------- /units/units_example.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2018 Google LLC 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // https://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // limitations under the License. 13 | 14 | #include "units.hpp" 15 | #include 16 | 17 | int main() { 18 | // A 3.4m high block is stacked on a 7.1m bock. Drop a 5.5kg weight is droped 19 | // from the top of the stack. How long will it take before it hits the ground, 20 | // and what will be force it exerts on the ground, and how much kinetic energy 21 | // will it have. 22 | 23 | auto mass = 5.5_kg; 24 | auto height = 3.4_m + 7.1_m; 25 | auto g = 9.8_m / pow<2>(1.0_s); 26 | 27 | // height = 1/2 a * t^2 28 | // 2*height/a = t^2 29 | 30 | auto t = sqrt(2 * height / g); 31 | 32 | auto velocity = t * g; 33 | 34 | // Does not compile 35 | // auto v = mass + g; 36 | 37 | std::cout << "Time to fall: " << t << "\n"; 38 | std::cout << "Velocity prior to impact: " << velocity << "\n"; 39 | std::cout << "Force of impact: " << mass * g << "\n"; 40 | std::cout << "Kinetic energy at impact: " << 0.5 * mass * pow<2>(velocity) 41 | << "\n"; 42 | } 43 | -------------------------------------------------------------------------------- /variadics_examples/tuple_no_variadics_hard_coded_index.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | using std::size_t; 5 | 6 | template 7 | struct Holder{ 8 | T value; 9 | }; 10 | 11 | template 12 | decltype(auto) get(const Holder& h){ 13 | return h.value; 14 | } 15 | 16 | template 17 | decltype(auto) get(Holder& h){ 18 | return h.value; 19 | } 20 | 21 | template 22 | decltype(auto) get(const Holder& h){ 23 | return h.value; 24 | } 25 | 26 | template 27 | decltype(auto) get(Holder& h){ 28 | return h.value; 29 | } 30 | 31 | struct null_t{}; 32 | 33 | template 34 | struct tuple; 35 | 36 | 37 | template 38 | struct tuple:Holder<0,T0>{ 39 | tuple() = default; 40 | tuple(T0 t0):Holder<0,T0>(std::move(t0)){} 41 | }; 42 | 43 | template 44 | struct tuple:Holder<0,T0>, Holder<1,T1>{ 45 | tuple() = default; 46 | tuple(T0 t0,T1 t1):Holder<0,T0>(std::move(t0)),Holder<1,T1>(std::move(t1)){} 47 | }; 48 | 49 | 50 | int main(){ 51 | tuple t{1}; 52 | std::cout << get(t) << "\n"; 53 | 54 | tuple t2{1,3.5}; 55 | std::cout << get(t2) << "\n"; 56 | std::cout << get<0>(t2) << "\n"; 57 | std::cout << get<1>(t2) << "\n"; 58 | 59 | } -------------------------------------------------------------------------------- /variadics_examples/tuple_no_variadics_no_index_get.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | template 4 | struct Holder{ 5 | T value; 6 | }; 7 | 8 | template 9 | decltype(auto) get(const Holder& h){ 10 | return h.value; 11 | } 12 | 13 | template 14 | decltype(auto) get(Holder& h){ 15 | return h.value; 16 | } 17 | 18 | struct null_t{}; 19 | 20 | template 21 | struct tuple; 22 | 23 | 24 | template 25 | struct tuple:Holder{ 26 | tuple() = default; 27 | tuple(T0 t0):Holder(std::move(t0)){} 28 | }; 29 | 30 | template 31 | struct tuple:Holder, Holder{ 32 | tuple() = default; 33 | tuple(T0 t0,T1 t1):Holder(std::move(t0)),Holder(std::move(t1)){} 34 | }; 35 | 36 | int main(){ 37 | tuple t{1}; 38 | std::cout << get(t) << "\n"; 39 | 40 | tuple t2{1,3.5}; 41 | std::cout << get(t2) << "\n"; 42 | 43 | } -------------------------------------------------------------------------------- /variadics_examples/tuple_no_variadics_sequence_index.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | using std::size_t; 5 | 6 | template 7 | struct Holder{ 8 | T value; 9 | }; 10 | 11 | template 12 | decltype(auto) get(const Holder& h){ 13 | return h.value; 14 | } 15 | 16 | template 17 | decltype(auto) get(Holder& h){ 18 | return h.value; 19 | } 20 | 21 | template 22 | decltype(auto) get(const Holder& h){ 23 | return h.value; 24 | } 25 | 26 | template 27 | decltype(auto) get(Holder& h){ 28 | return h.value; 29 | } 30 | 31 | struct null_t{}; 32 | 33 | template 34 | struct tuple; 35 | 36 | constexpr auto no_idx = static_cast(-1); 37 | 38 | template 39 | struct sequence{}; 40 | 41 | template 42 | struct tuple_impl; 43 | 44 | 45 | template 46 | struct tuple_impl,T0>:Holder{ 47 | tuple_impl() = default; 48 | tuple_impl(T0 t0):Holder{std::move(t0)}{} 49 | }; 50 | 51 | template 52 | struct tuple:tuple_impl,T0>{ 53 | using base = tuple_impl,T0>; 54 | using base::base; 55 | }; 56 | 57 | template 58 | struct tuple_impl,T0,T1>:Holder, Holder{ 59 | tuple_impl() = default; 60 | tuple_impl(T0 t0,T1 t1):Holder{std::move(t0)},Holder{std::move(t1)}{} 61 | }; 62 | 63 | template 64 | struct tuple:tuple_impl,T0,T1>{ 65 | using base = tuple_impl,T0,T1>; 66 | using base::base; 67 | }; 68 | 69 | 70 | int main(){ 71 | tuple t{1}; 72 | std::cout << get(t) << "\n"; 73 | 74 | tuple t2{1,3.5}; 75 | std::cout << get(t2) << "\n"; 76 | std::cout << get<0>(t2) << "\n"; 77 | std::cout << get<1>(t2) << "\n"; 78 | 79 | } -------------------------------------------------------------------------------- /variadics_examples/tuple_variadics.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | using std::size_t; 6 | 7 | template 8 | struct Holder{ 9 | T value; 10 | }; 11 | 12 | template 13 | decltype(auto) get(const Holder& h){ 14 | return h.value; 15 | } 16 | 17 | template 18 | decltype(auto) get(Holder& h){ 19 | return h.value; 20 | } 21 | 22 | template 23 | decltype(auto) get(const Holder& h){ 24 | return h.value; 25 | } 26 | 27 | template 28 | decltype(auto) get(Holder& h){ 29 | return h.value; 30 | } 31 | 32 | template 33 | struct tuple_impl; 34 | 35 | template 36 | struct tuple_impl,Ts...>:Holder...{ 37 | tuple_impl() = default; 38 | tuple_impl(Ts... ts):Holder{std::move(ts)}...{} 39 | }; 40 | 41 | template 42 | struct tuple:tuple_impl,Ts...>{ 43 | using base = tuple_impl,Ts...>; 44 | using base::base; 45 | }; 46 | 47 | 48 | int main(){ 49 | tuple t{1}; 50 | std::cout << get(t) << "\n"; 51 | 52 | tuple t2{1,3.5}; 53 | std::cout << get(t2) << "\n"; 54 | std::cout << get<0>(t2) << "\n"; 55 | std::cout << get<1>(t2) << "\n"; 56 | 57 | } -------------------------------------------------------------------------------- /variadics_examples/tuple_variadics_print_fold.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | using std::size_t; 7 | 8 | template 9 | struct Holder { 10 | T value; 11 | }; 12 | 13 | template 14 | decltype(auto) get(const Holder& h) { 15 | return h.value; 16 | } 17 | 18 | template 19 | decltype(auto) get(Holder& h) { 20 | return h.value; 21 | } 22 | 23 | template 24 | decltype(auto) get(const Holder& h) { 25 | return h.value; 26 | } 27 | 28 | template 29 | decltype(auto) get(Holder& h) { 30 | return h.value; 31 | } 32 | 33 | template 34 | struct tuple_impl; 35 | 36 | template 37 | struct tuple_impl, Ts...> : Holder... { 38 | tuple_impl() = default; 39 | tuple_impl(Ts... ts) : Holder{std::move(ts)}... {} 40 | }; 41 | 42 | template 43 | struct tuple : tuple_impl, Ts...> { 44 | using base = tuple_impl, Ts...>; 45 | using base::base; 46 | }; 47 | 48 | template 49 | struct type2type { 50 | using type = T; 51 | }; 52 | 53 | template 54 | type2type element_helper(Holder& h); 55 | 56 | template 57 | using tuple_element_t = 58 | typename decltype(element_helper(std::declval()))::type; 59 | 60 | template 61 | struct tuple_select; 62 | 63 | template 64 | struct tuple_select> { 65 | using type = tuple...>; 66 | }; 67 | 68 | template 69 | using tuple_select_t = typename tuple_select::type; 70 | 71 | template 72 | constexpr auto index_reversed = Last - I; 73 | 74 | template 75 | struct tuple_size; 76 | 77 | template 78 | struct tuple_size> { 79 | static constexpr size_t value = sizeof...(Ts); 80 | }; 81 | 82 | template 83 | inline constexpr auto tuple_size_v = tuple_size::value; 84 | 85 | template 86 | decltype(auto) apply_helper(Tuple& t, F& f, std::index_sequence) { 87 | return f(get(t)...); 88 | } 89 | 90 | template 91 | decltype(auto) apply(Tuple& t, F&& f) { 92 | return apply_helper( 93 | t, f, std::make_index_sequence>>()); 94 | } 95 | 96 | template 97 | void print(std::ostream& os, const Tuple& t) { 98 | auto print_one = [&](auto& t) mutable { os << t << "\n"; }; 99 | auto print_args = [&](auto&&... ts) mutable { (print_one(ts), ...); }; 100 | apply(t, print_args); 101 | } 102 | 103 | int main() { 104 | tuple t2{1, 3.5}; 105 | print(std::cout, t2); 106 | } -------------------------------------------------------------------------------- /variadics_examples/tuple_variadics_print_recursive.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | using std::size_t; 7 | 8 | template 9 | struct Holder{ 10 | T value; 11 | }; 12 | 13 | template 14 | decltype(auto) get(const Holder& h){ 15 | return h.value; 16 | } 17 | 18 | template 19 | decltype(auto) get(Holder& h){ 20 | return h.value; 21 | } 22 | 23 | template 24 | decltype(auto) get(const Holder& h){ 25 | return h.value; 26 | } 27 | 28 | template 29 | decltype(auto) get(Holder& h){ 30 | return h.value; 31 | } 32 | 33 | 34 | template 35 | struct tuple_impl; 36 | 37 | template 38 | struct tuple_impl,Ts...>:Holder...{ 39 | tuple_impl() = default; 40 | tuple_impl(Ts... ts):Holder{std::move(ts)}...{} 41 | }; 42 | 43 | template 44 | struct tuple:tuple_impl,Ts...>{ 45 | using base = tuple_impl,Ts...>; 46 | using base::base; 47 | }; 48 | 49 | template 50 | struct type2type{ 51 | using type = T; 52 | }; 53 | 54 | template 55 | type2type element_helper(Holder& h); 56 | 57 | template 58 | using tuple_element_t = typename decltype(element_helper(std::declval()))::type; 59 | 60 | template 61 | struct tuple_select; 62 | 63 | template 64 | struct tuple_select>{ 65 | using type = tuple...>; 66 | }; 67 | 68 | template 69 | using tuple_select_t = typename tuple_select::type; 70 | 71 | template 72 | constexpr auto index_reversed = Last - I; 73 | 74 | template 75 | struct tuple_size; 76 | 77 | template 78 | struct tuple_size>{ 79 | static constexpr size_t value = sizeof...(Ts); 80 | }; 81 | 82 | template 83 | inline constexpr auto tuple_size_v = tuple_size::value; 84 | 85 | template 86 | decltype(auto) apply_helper(Tuple& t, F& f, std::index_sequence){ 87 | return f(get(t)...); 88 | } 89 | 90 | template 91 | decltype(auto) apply(Tuple& t, F&& f){ 92 | return apply_helper(t,f,std::make_index_sequence>>()); 93 | } 94 | 95 | struct print_args{ 96 | 97 | std::ostream& os; 98 | 99 | void operator()()const{} 100 | 101 | template 102 | void operator()(const First& first, const Ts&... ts)const{ 103 | os << first << "\n"; 104 | (*this)(ts...); 105 | } 106 | 107 | }; 108 | 109 | template 110 | void print(std::ostream& os, const Tuple& t){ 111 | apply(t,print_args{os}); 112 | } 113 | 114 | 115 | 116 | int main(){ 117 | 118 | tuple t2{1,3.5}; 119 | print(std::cout,t2); 120 | 121 | 122 | 123 | 124 | } -------------------------------------------------------------------------------- /variadics_examples/tuple_variadics_reverse_recursive.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | using std::size_t; 6 | 7 | template 8 | struct Holder{ 9 | T value; 10 | }; 11 | 12 | template 13 | decltype(auto) get(const Holder& h){ 14 | return h.value; 15 | } 16 | 17 | template 18 | decltype(auto) get(Holder& h){ 19 | return h.value; 20 | } 21 | 22 | template 23 | decltype(auto) get(const Holder& h){ 24 | return h.value; 25 | } 26 | 27 | template 28 | decltype(auto) get(Holder& h){ 29 | return h.value; 30 | } 31 | 32 | template 33 | struct tuple_impl; 34 | 35 | template 36 | struct tuple_impl,Ts...>:Holder...{ 37 | tuple_impl() = default; 38 | tuple_impl(Ts... ts):Holder{std::move(ts)}...{} 39 | }; 40 | 41 | template 42 | struct tuple:tuple_impl,Ts...>{ 43 | using base = tuple_impl,Ts...>; 44 | using base::base; 45 | }; 46 | 47 | template 48 | struct reverse_tuple; 49 | 50 | template 51 | struct reverse_tuple,Rs...>{ 52 | using type = tuple; 53 | }; 54 | 55 | template 56 | struct reverse_tuple,Rs...>{ 57 | using type = typename reverse_tuple,First,Rs...>::type; 58 | }; 59 | 60 | 61 | template 62 | using reverse_tuple_t = typename reverse_tuple::type; 63 | 64 | 65 | int main(){ 66 | tuple t{1}; 67 | std::cout << get(t) << "\n"; 68 | 69 | tuple t2{1,3.5}; 70 | std::cout << get(t2) << "\n"; 71 | std::cout << get<0>(t2) << "\n"; 72 | std::cout << get<1>(t2) << "\n"; 73 | 74 | reverse_tuple_t> t3{3.5,1}; 75 | static_assert(std::is_same_v,reverse_tuple_t>>); 76 | std::cout << get<0>(t3) << "\n"; 77 | std::cout << get<1>(t3) << "\n"; 78 | 79 | 80 | 81 | } -------------------------------------------------------------------------------- /variadics_examples/tuple_variadics_reverse_sequence.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | using std::size_t; 6 | 7 | template 8 | struct Holder{ 9 | T value; 10 | }; 11 | 12 | template 13 | decltype(auto) get(const Holder& h){ 14 | return h.value; 15 | } 16 | 17 | template 18 | decltype(auto) get(Holder& h){ 19 | return h.value; 20 | } 21 | 22 | template 23 | decltype(auto) get(const Holder& h){ 24 | return h.value; 25 | } 26 | 27 | template 28 | decltype(auto) get(Holder& h){ 29 | return h.value; 30 | } 31 | 32 | 33 | template 34 | struct tuple_impl; 35 | 36 | template 37 | struct tuple_impl,Ts...>:Holder...{ 38 | tuple_impl() = default; 39 | tuple_impl(Ts... ts):Holder{std::move(ts)}...{} 40 | }; 41 | 42 | template 43 | struct tuple:tuple_impl,Ts...>{ 44 | using base = tuple_impl,Ts...>; 45 | using base::base; 46 | }; 47 | 48 | template 49 | struct type2type{ 50 | using type = T; 51 | }; 52 | 53 | template 54 | type2type element_helper(Holder& h); 55 | 56 | template 57 | using tuple_element_t = typename decltype(element_helper(std::declval()))::type; 58 | 59 | template 60 | struct tuple_select; 61 | 62 | template 63 | struct tuple_select>{ 64 | using type = tuple...>; 65 | }; 66 | 67 | template 68 | using tuple_select_t = typename tuple_select::type; 69 | 70 | template 71 | constexpr auto index_reversed = Last - I; 72 | 73 | template 74 | struct tuple_size; 75 | 76 | template 77 | struct tuple_size>{ 78 | static constexpr size_t value = sizeof...(Ts); 79 | }; 80 | 81 | template 82 | inline constexpr auto tuple_size_v = tuple_size::value; 83 | 84 | template 85 | struct reverse_tuple; 86 | 87 | template 88 | struct reverse_tuple>{ 89 | using type = tuple_select_t...>>; 90 | }; 91 | 92 | template 93 | using reverse_tuple_t = typename reverse_tuple>>::type; 94 | 95 | 96 | 97 | int main(){ 98 | tuple t{1}; 99 | std::cout << get(t) << "\n"; 100 | 101 | tuple t2{1,3.5}; 102 | std::cout << get(t2) << "\n"; 103 | std::cout << get<0>(t2) << "\n"; 104 | std::cout << get<1>(t2) << "\n"; 105 | 106 | reverse_tuple_t> t3{3.5,1}; 107 | static_assert(std::is_same_v,reverse_tuple_t>>); 108 | std::cout << get<0>(t3) << "\n"; 109 | std::cout << get<1>(t3) << "\n"; 110 | 111 | 112 | 113 | } --------------------------------------------------------------------------------