├── .gitignore ├── CMakeLists.txt ├── LICENSE ├── README.md ├── c_strings ├── CMakeLists.txt ├── c_strings.cpp └── c_strings.h ├── catch2 └── catch.hpp ├── common └── main.cpp ├── iterator ├── CMakeLists.txt ├── iterator.cpp └── iterator.h ├── koans.md ├── string_view ├── CMakeLists.txt ├── string_view.cpp └── string_view.h ├── strings ├── CMakeLists.txt ├── strings.cpp └── strings.h └── type_traits ├── CMakeLists.txt ├── type_traits.cpp └── type_traits.h /.gitignore: -------------------------------------------------------------------------------- 1 | build 2 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.8.0) 2 | project(koans CXX) 3 | 4 | add_library(catch2 STATIC common/main.cpp catch2/catch.hpp) 5 | target_include_directories(catch2 PUBLIC ${PROJECT_SOURCE_DIR}/catch2) 6 | 7 | if("${CMAKE_CXX_COMPILER_ID}" MATCHES "(GNU|Clang)") 8 | set(CMAKE_CXX_FLAGS "-std=c++11") 9 | endif() 10 | 11 | function(add_koan name) 12 | add_executable(${name} ${name}.cpp ${name}.h) 13 | target_link_libraries(${name} PRIVATE catch2) 14 | add_custom_command(TARGET ${name} POST_BUILD COMMAND ${name} --reporter compact) 15 | endfunction() 16 | 17 | add_subdirectory(type_traits) 18 | add_subdirectory(iterator) 19 | add_subdirectory(c_strings) 20 | add_subdirectory(strings) 21 | add_subdirectory(string_view) 22 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 Richard Thomson 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # C++ Koans 2 | 3 | This repository exists as a set of C++ koans. A [koan](https://en.wikipedia.org/wiki/K%C5%8Dan) in general terms is: 4 | 5 | > a story, dialogue, question, or statement, which is used in Zen practice to provoke the "great doubt" and test 6 | > a student's progress in Zen practice. [Wikipedia] 7 | 8 | In programming terms, a koan is expressed as a series of programming questions written as failing unit test assertions. 9 | You progress through the koan by modifying the code to make the assertions pass. By answering the questions it is 10 | hoped that you achieve "enlightenment" about the feature in question. 11 | 12 | # Organization 13 | 14 | This repository is organized as a set of source files, each representing a particular area of study in koan form. 15 | Each koan corresponds to a unit test executable described by the [CMake](http://www.cmake.org) build script. 16 | There is an associated header file for each koan that contains just enough infrastructure to express the koans. 17 | You can safely ignore this header file if you are only interested in consuming the koans as a student. If you 18 | are interested in writing new koans, you may find useful tricks inside those header files. 19 | 20 | Current [list of koans](koans.md). 21 | 22 | # Practicing the Koans 23 | 24 | Each koan consists of a number of test cases. Each test case consists of a number of related statements posed 25 | as assertions. Initially all the assertions fail. To practice the koan, edit each assertion to make the 26 | assertion true. Typically each assertion will contain the symbol `XXX` or `xxx` representing the portion you 27 | edit to make the assertion true. 28 | 29 | A koan is designed to increase your understanding in some way; it is not a test. Feel free to consult documentation, 30 | leverage your IDE to research function signatures, etc., in order to figure out how to make an assertion pass. 31 | Sometimes running the tests will tell you how the right answer compared to your incorrect answer. Feel free to 32 | copy/paste correct answers from the build output to pass the assertion! 33 | 34 | The build script is configured to run the tests after a successful compile, so simply building the code will run 35 | the tests and report failed assertions. 36 | 37 | # First Time Setup 38 | 39 | 1. Obtain the [dependencies](#dependencies) and install them appropriately. 40 | 2. Generate a suitable project/build script with CMake. 41 | 3. Build the code to validate that your dependencies and build are correctly configured and working. You should 42 | see the code being compiled and the unit test executables being run after compilation. 43 | 44 | # Dependencies 45 | 46 | - [CMake 3.8.0](http://www.cmake.org) for the build infrastructure. 47 | - [Catch2](http://catch-lib.net) for the unit test framework. Catch2 is included in the cpp-koans repository, 48 | so there is nothing to download. 49 | 50 | # Contributing 51 | 52 | New koans or improvements to existing koans are most welcome! Simply fork and submit a pull request as usual on github. 53 | -------------------------------------------------------------------------------- /c_strings/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_koan(c_strings) 2 | -------------------------------------------------------------------------------- /c_strings/c_strings.cpp: -------------------------------------------------------------------------------- 1 | #include "c_strings.h" 2 | 3 | TEST_CASE("type of character literals") 4 | { 5 | REQUIRE((std::is_same_v)); 6 | REQUIRE((std::is_same_v)); 7 | REQUIRE((std::is_same_v)); 8 | REQUIRE((std::is_same_v)); 9 | REQUIRE((std::is_same_v)); 10 | } 11 | 12 | TEST_CASE("special character literals") 13 | { 14 | // see 15 | REQUIRE(xxx == static_cast('\020')); 16 | REQUIRE(xxx == static_cast('\x20')); 17 | REQUIRE(xxx == static_cast('\a')); 18 | REQUIRE(xxx == static_cast('\b')); 19 | REQUIRE(xxx == static_cast('\f')); 20 | REQUIRE(xxx == static_cast('\n')); 21 | REQUIRE(xxx == static_cast('\r')); 22 | REQUIRE(xxx == static_cast('\t')); 23 | REQUIRE(xxx == static_cast('\v')); 24 | REQUIRE(xxx == static_cast('\'')); 25 | REQUIRE(xxx == static_cast('\"')); 26 | REQUIRE(xxx == static_cast('\?')); 27 | REQUIRE(xxx == static_cast('\\')); 28 | REQUIRE(xxx == static_cast(L'\x1234')); 29 | REQUIRE(xxx == static_cast(u'\u1234')); 30 | REQUIRE(xxx == static_cast(U'\U00001E00')); 31 | REQUIRE(xxx == static_cast(u8'A')); 32 | } 33 | 34 | TEST_CASE("type of string literals") 35 | { 36 | auto s1{"Hello, world!"}; 37 | auto s2{L"Hello, world!"}; 38 | auto s3{u"Hello, world!"}; 39 | auto s4{U"Hello, world!"}; 40 | auto s5{u8"Hello, world!"}; 41 | REQUIRE((std::is_same_v)); 42 | REQUIRE((std::is_same_v)); 43 | REQUIRE((std::is_same_v)); 44 | REQUIRE((std::is_same_v)); 45 | REQUIRE((std::is_same_v)); 46 | } 47 | 48 | TEST_CASE("type of raw string literals") 49 | { 50 | auto r1{R"one(Hello, world!)one"}; 51 | auto r2{LR"two(Hello, world!)two"}; 52 | auto r3{uR"three(Hello, world!)three"}; 53 | auto r4{UR"four(Hello, world!)four"}; 54 | auto r5{u8R"five(Hello, world!)five"}; 55 | REQUIRE((std::is_same_v)); 56 | REQUIRE((std::is_same_v)); 57 | REQUIRE((std::is_same_v)); 58 | REQUIRE((std::is_same_v)); 59 | REQUIRE((std::is_same_v)); 60 | } 61 | 62 | TEST_CASE("raw string literals") 63 | { 64 | auto s{R"lit( 65 | Hello, world! 66 | )lit"}; 67 | REQUIRE(xxx == s[0]); 68 | } 69 | 70 | TEST_CASE("begin end on character arrays") 71 | { 72 | char s[]{"Hello, world!"}; 73 | 74 | REQUIRE(xxx == std::begin(s)); 75 | REQUIRE(xxx == std::end(s)); 76 | } 77 | -------------------------------------------------------------------------------- /c_strings/c_strings.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | #include 8 | 9 | struct XXX 10 | { 11 | operator bool() { throw std::runtime_error("Oops"); } 12 | operator int() { throw std::runtime_error("Oops"); } 13 | }; 14 | 15 | XXX xxx; 16 | 17 | inline std::ostream &operator<<(std::ostream &stream, XXX const &) 18 | { 19 | return stream << "xxx"; 20 | } 21 | 22 | template 23 | inline bool operator==(XXX const &lhs, T const &rhs) 24 | { 25 | return false; 26 | } 27 | 28 | #pragma warning(disable : 4101) // unreferenced local variable 29 | #pragma warning(disable : 4930) // prototyped function not called 30 | -------------------------------------------------------------------------------- /common/main.cpp: -------------------------------------------------------------------------------- 1 | #define CATCH_CONFIG_MAIN 2 | #include 3 | -------------------------------------------------------------------------------- /iterator/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_koan(iterator) 2 | -------------------------------------------------------------------------------- /iterator/iterator.cpp: -------------------------------------------------------------------------------- 1 | #include "iterator.h" 2 | #include 3 | 4 | // In each test, replace XXX with syntax that passes the test. 5 | 6 | TEST_CASE("array iterators") 7 | { 8 | int values[5]{ 1, 2, 3, 4, 5 }; 9 | 10 | REQUIRE(&values[xxx] == std::begin(values)); 11 | REQUIRE(&values[xxx] == std::end(values)); 12 | REQUIRE((std::is_same::value)); 13 | REQUIRE((std::is_same::value)); 14 | } 15 | 16 | TEST_CASE("iterator traits of array iterators") 17 | { 18 | int values[]{ 1, 2, 3, 4, 5 }; 19 | auto start = std::begin(values); 20 | 21 | REQUIRE((std::is_same::value_type>::value)); 22 | REQUIRE((std::is_same::difference_type>::value)); 23 | REQUIRE((std::is_same::pointer>::value)); 24 | REQUIRE((std::is_same::reference>::value)); 25 | REQUIRE((std::is_same::iterator_category>::value)); 26 | } 27 | -------------------------------------------------------------------------------- /iterator/iterator.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | #include 12 | 13 | struct XXX 14 | { 15 | operator bool() { throw std::runtime_error("Oops"); } 16 | operator int() { throw std::runtime_error("Oops"); } 17 | }; 18 | 19 | XXX xxx; 20 | 21 | inline std::ostream &operator<<(std::ostream &stream, XXX const &) 22 | { 23 | return stream << "xxx"; 24 | } 25 | 26 | template 27 | inline bool operator==(XXX const &lhs, T const &rhs) 28 | { 29 | return false; 30 | } 31 | 32 | #pragma warning(disable : 4101) // unreferenced local variable 33 | #pragma warning(disable : 4930) // prototyped function not called 34 | -------------------------------------------------------------------------------- /koans.md: -------------------------------------------------------------------------------- 1 | # List of Existing Koans 2 | 3 | Note: These koans are not considered to be exhaustive. Pull requests are welcome! 4 | 5 | - [iterator](iterator/iterator.cpp): Exploring the [<iterator>](http://en.cppreference.com/w/cpp/header/iterator) header. 6 | - [type_traits](type_traits/type_traits.cpp): Exploring the [<type_traits>](http://en.cppreference.com/w/cpp/header/type_traits) header. 7 | - [c_strings](c_strings/c_strings.cpp): Exploring C-style [string](http://en.cppreference.com/w/cpp/language/string_literal) and [character](http://en.cppreference.com/w/cpp/language/character_literal) literals. 8 | - [strings](strings/strings.cpp): Exploring [std::string](http://en.cppreference.com/w/cpp/string/basic_string). 9 | - [string_view](string_view/string_view.cpp): Exploring [std::string_view](http://en.cppreference.com/w/cpp/string/basic_string_view). 10 | -------------------------------------------------------------------------------- /string_view/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_koan(string_view) 2 | if(MSVC) 3 | target_compile_options(string_view PRIVATE /std:c++17) 4 | endif() 5 | if("${CMAKE_CXX_COMPILER_ID}" MATCHES "(GNU|Clang)") 6 | set(CMAKE_CXX_FLAGS "-std=c++17") 7 | endif() 8 | -------------------------------------------------------------------------------- /string_view/string_view.cpp: -------------------------------------------------------------------------------- 1 | #include "string_view.h" 2 | 3 | using namespace std::string_literals; 4 | using namespace std::string_view_literals; 5 | 6 | TEST_CASE("std::string view variants") 7 | { 8 | REQUIRE((std::is_same_v>)); 9 | REQUIRE((std::is_same_v)); 10 | REQUIRE((std::is_same_v)); 11 | REQUIRE((std::is_same_v)); 12 | } 13 | 14 | TEST_CASE("std::string_view literals") 15 | { 16 | REQUIRE((std::is_same_v)); 17 | } 18 | 19 | TEST_CASE("std::string_view related types") 20 | { 21 | REQUIRE((std::is_same_v)); 22 | REQUIRE((std::is_same_v)); 23 | REQUIRE((std::is_same_v)); 24 | REQUIRE((std::is_same_v)); 25 | REQUIRE((std::is_same_v)); 26 | REQUIRE((std::is_same_v)); 27 | REQUIRE((std::is_same_v)); 28 | REQUIRE((std::is_same_v)); 29 | } 30 | 31 | TEST_CASE("std::string_view constructors") 32 | { 33 | constexpr std::string_view s; 34 | REQUIRE(xxx == s.empty()); 35 | 36 | constexpr std::string_view s2{"Hello, world!", 5}; 37 | REQUIRE(xxx == s2.length()); 38 | REQUIRE(xxx == s2); 39 | 40 | /* constexpr */ std::string_view s3{"Hello, world!"}; 41 | REQUIRE(xxx == s3.length()); 42 | } 43 | 44 | TEST_CASE("std::string_view accessors") 45 | { 46 | constexpr std::string_view s{"Hello, world!", 13}; 47 | REQUIRE(xxx == s[0]); 48 | REQUIRE(xxx == s.at(0)); 49 | REQUIRE_THROWS_AS(s.at(100), XXX); 50 | REQUIRE(xxx == s.front()); 51 | REQUIRE(xxx == s.back()); 52 | REQUIRE((std::is_same_v)); 53 | REQUIRE(xxx == *s.data()); 54 | } 55 | 56 | TEST_CASE("std::string_view capacity") 57 | { 58 | constexpr std::string_view s{"Hello, world!", 13}; 59 | REQUIRE(xxx == s.size()); 60 | REQUIRE(xxx == s.length()); 61 | REQUIRE(xxx == s.empty()); 62 | REQUIRE(s.max_size() >= static_cast(xxx)); 63 | } 64 | 65 | TEST_CASE("std::string_view modifiers") 66 | { 67 | std::string_view s{"Hello, world!", 13}; 68 | s.remove_prefix(xxx); 69 | REQUIRE("world!"sv == s); 70 | s.remove_suffix(xxx); 71 | REQUIRE("world"sv == s); 72 | } 73 | 74 | TEST_CASE("std::string_view swap") 75 | { 76 | std::string_view s{"Hello, world!", 13}; 77 | std::string_view s2{"Woof!", 5}; 78 | s.swap(s2); 79 | REQUIRE("xxx"sv == s); 80 | REQUIRE("xxx"sv == s2); 81 | } 82 | 83 | TEST_CASE("std::string_view copy") 84 | { 85 | constexpr std::string_view s{"Hello, world!", 13}; 86 | char dest[5]; 87 | s.copy(dest, sizeof(dest)); 88 | REQUIRE("xxx"s == std::string(std::begin(dest), std::end(dest))); 89 | s.copy(dest, sizeof(dest), xxx); 90 | REQUIRE("world"s == std::string(std::begin(dest), std::end(dest))); 91 | } 92 | 93 | TEST_CASE("std::string_view substr") 94 | { 95 | constexpr std::string_view s{"Hello, world!", 13}; 96 | constexpr auto s2{s.substr()}; 97 | REQUIRE((std::is_same_v)); 98 | REQUIRE("xxx"sv == s2); 99 | auto s3{s.substr(xxx)}; 100 | REQUIRE("world!"sv == s3); 101 | auto s4{s.substr(xxx, xxx)}; 102 | REQUIRE("world"sv == s4); 103 | constexpr auto s5{s.substr(3, std::string_view::npos)}; 104 | REQUIRE("xxx"sv == s5); 105 | } 106 | 107 | TEST_CASE("std_string_comparison_operators") 108 | { 109 | constexpr std::string_view alpha{"Alpha", 5}; 110 | REQUIRE("xxx"sv < alpha); 111 | REQUIRE("xxx"sv > alpha); 112 | REQUIRE("xxx"sv <= alpha); 113 | REQUIRE("xxx"sv >= alpha); 114 | REQUIRE("xxx"sv == alpha); 115 | REQUIRE("xxx"sv != alpha); 116 | } 117 | 118 | TEST_CASE("std::string_view compare") 119 | { 120 | std::string_view s1{"Alphabetical", 12}; 121 | std::string_view s2{"Alphanumerical", 14}; 122 | auto res1 = s1.compare(s2); 123 | REQUIRE((std::is_same_v)); 124 | REQUIRE(xxx == res1); 125 | 126 | REQUIRE(0 == s1.compare(xxx, 5, s2)); 127 | REQUIRE(0 == s1.compare(xxx, 3, s2, 11, 3)); 128 | REQUIRE(0 == s1.compare("xxx")); 129 | REQUIRE(0 == s1.compare(xxx, 4, "ical")); 130 | REQUIRE(0 == s1.compare(xxx, 4, "Canonical", 5)); 131 | } 132 | 133 | TEST_CASE("std::string_view find") 134 | { 135 | constexpr std::string_view s{"Have a fun day at the zoo.", 26}; 136 | auto res = s.find("a"sv); 137 | REQUIRE((std::is_same_v)); 138 | REQUIRE(xxx == res); 139 | 140 | char ch{xxx}; 141 | REQUIRE(4 == s.find(ch)); 142 | REQUIRE(6 == s.find(ch, xxx)); 143 | REQUIRE(xxx == s.find("!"sv)); 144 | REQUIRE(xxx == s.find("!"s)); 145 | REQUIRE(14 == s.find(" a"sv, xxx)); 146 | REQUIRE(xxx == s.find(" a")); 147 | REQUIRE(14 == s.find(" a", xxx)); 148 | REQUIRE(4 == s.find(" a", xxx, 1)); 149 | 150 | REQUIRE(xxx == ""sv.find(ch)); 151 | REQUIRE(xxx == "foo"sv.find(ch, 10)); 152 | REQUIRE(xxx == "foo"sv.find("f"sv, 10)); 153 | REQUIRE(xxx == "foo"sv.find("fo", 10)); 154 | } 155 | 156 | TEST_CASE("std::string_view rfind") 157 | { 158 | constexpr std::string_view s{"Foobar Googly Eyes", 18}; 159 | auto res = s.rfind("oo"sv); 160 | REQUIRE((std::is_same_v)); 161 | REQUIRE(xxx == res); 162 | 163 | REQUIRE(xxx == s.rfind("oo"sv, 6)); 164 | REQUIRE(xxx == s.rfind("oo")); 165 | REQUIRE(xxx == s.rfind("oo", 6)); 166 | REQUIRE(xxx == s.rfind("oo", 6, 1)); 167 | REQUIRE(xxx == s.rfind('y')); 168 | REQUIRE(xxx == s.rfind('y', 14)); 169 | } 170 | 171 | TEST_CASE("std::string_view find_first_of") 172 | { 173 | constexpr std::string_view s{"Foobar Googly Eyes", 18}; 174 | auto res = s.find_first_of("EGF"sv); 175 | REQUIRE((std::is_same_v)); 176 | REQUIRE(xxx == res); 177 | 178 | REQUIRE(xxx == s.find_first_of("EGF"sv, 1)); 179 | REQUIRE(xxx == s.find_first_of("EGF")); 180 | REQUIRE(xxx == s.find_first_of("EGF", 1)); 181 | REQUIRE(xxx == s.find_first_of("EGF", 1, 1)); 182 | REQUIRE(xxx == s.find_first_of('o')); 183 | REQUIRE(xxx == s.find_first_of('o', 3)); 184 | 185 | REQUIRE(xxx == s.find_first_of(""sv)); 186 | REQUIRE(xxx == s.find_first_of("")); 187 | REQUIRE(xxx == s.find_first_of("ABC"sv)); 188 | REQUIRE(xxx == s.find_first_of("ABC")); 189 | REQUIRE(xxx == s.find_first_of('A')); 190 | REQUIRE(xxx == s.find_first_of("o"sv, 100)); 191 | REQUIRE(xxx == s.find_first_of("o", 100)); 192 | REQUIRE(xxx == s.find_first_of("o", 100, 1)); 193 | REQUIRE(xxx == s.find_first_of('o', 100)); 194 | } 195 | 196 | TEST_CASE("std::string_view find_first_not_of") 197 | { 198 | constexpr std::string_view s{"Foobar Googly Eyes", 18}; 199 | auto res = s.find_first_not_of("ABCDEFG"sv); 200 | REQUIRE((std::is_same_v)); 201 | REQUIRE(xxx == res); 202 | 203 | REQUIRE(xxx == s.find_first_not_of("oab"sv, 1)); 204 | REQUIRE(xxx == s.find_first_not_of("abF")); 205 | REQUIRE(xxx == s.find_first_not_of("abF", 3)); 206 | REQUIRE(xxx == s.find_first_not_of("abF", 3, 1)); 207 | REQUIRE(xxx == s.find_first_not_of('F')); 208 | REQUIRE(xxx == s.find_first_not_of('o', 1)); 209 | 210 | REQUIRE(xxx == s.find_first_not_of("Fobar GglyEes"sv)); 211 | REQUIRE(xxx == s.find_first_not_of("Fobar GglyEes")); 212 | REQUIRE(xxx == s.substr(1, 1).find_first_not_of('F')); 213 | REQUIRE(xxx == s.find_first_not_of("o"sv, 100)); 214 | REQUIRE(xxx == s.find_first_not_of("o", 100)); 215 | REQUIRE(xxx == s.find_first_not_of("o", 100, 1)); 216 | REQUIRE(xxx == s.find_first_not_of('o', 100)); 217 | } 218 | 219 | TEST_CASE("std::string_view find_last_of") 220 | { 221 | constexpr std::string_view s{"Foobar Googly Eyes", 18}; 222 | auto res = s.find_last_of("EGF"sv); 223 | REQUIRE((std::is_same_v)); 224 | REQUIRE(xxx == res); 225 | 226 | REQUIRE(xxx == s.find_last_of("EGF"sv, 1)); 227 | REQUIRE(xxx == s.find_last_of("EGF")); 228 | REQUIRE(xxx == s.find_last_of("EGF", 1)); 229 | REQUIRE(xxx == s.find_last_of("EGF", 1, 1)); 230 | REQUIRE(xxx == s.find_last_of('o')); 231 | REQUIRE(xxx == s.find_last_of('o', 3)); 232 | 233 | REQUIRE(xxx == s.find_last_of(""sv)); 234 | REQUIRE(xxx == s.find_last_of("")); 235 | REQUIRE(xxx == s.find_last_of("ABC"sv)); 236 | REQUIRE(xxx == s.find_last_of("ABC")); 237 | REQUIRE(xxx == s.find_last_of('A')); 238 | REQUIRE(xxx == s.find_last_of("o"sv, 100)); 239 | REQUIRE(xxx == s.find_last_of("o", 100)); 240 | REQUIRE(xxx == s.find_last_of("o", 100, 1)); 241 | REQUIRE(xxx == s.find_last_of('o', 100)); 242 | } 243 | 244 | TEST_CASE("std::string_view find_last_not_of") 245 | { 246 | constexpr std::string_view s{"Foobar Googly Eyes", 18}; 247 | auto res = s.find_last_not_of("ABCDEFG"sv); 248 | REQUIRE((std::is_same_v)); 249 | REQUIRE(xxx == res); 250 | 251 | REQUIRE(xxx == s.find_last_not_of("oab"sv, 1)); 252 | REQUIRE(xxx == s.find_last_not_of("abF")); 253 | REQUIRE(xxx == s.find_last_not_of("abF", 3)); 254 | REQUIRE(xxx == s.find_last_not_of("abF", 3, 1)); 255 | REQUIRE(xxx == s.find_last_not_of('F')); 256 | REQUIRE(xxx == s.find_last_not_of('o', 1)); 257 | 258 | REQUIRE(xxx == s.find_last_not_of("Fobar GglyEes"sv)); 259 | REQUIRE(xxx == s.find_last_not_of("Fobar GglyEes")); 260 | REQUIRE(xxx == s.substr(1, 1).find_last_not_of('F')); 261 | REQUIRE(xxx == s.find_last_not_of("o"sv, 100)); 262 | REQUIRE(xxx == s.find_last_not_of("o", 100)); 263 | REQUIRE(xxx == s.find_last_not_of("o", 100, 1)); 264 | REQUIRE(xxx == s.find_last_not_of('o', 100)); 265 | } 266 | 267 | TEST_CASE("std::string_view iterators") 268 | { 269 | std::string_view s{"Hello, world!"}; 270 | 271 | REQUIRE((std::is_same_v)); 272 | REQUIRE((std::is_same_v)); 273 | REQUIRE(xxx == *s.begin()); 274 | REQUIRE(xxx == *(s.end() - 1)); 275 | REQUIRE(xxx == *s.rbegin()); 276 | REQUIRE(xxx == *(s.rend() - 1)); 277 | } 278 | -------------------------------------------------------------------------------- /string_view/string_view.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | #pragma warning(disable: 4996) 9 | 10 | #include 11 | 12 | struct XXX 13 | { 14 | operator bool() const { throw std::runtime_error{"Oops"}; } 15 | operator char() const { throw std::runtime_error{"Oops"}; } 16 | operator std::string_view::size_type() const { throw std::runtime_error{"Oops"}; } 17 | explicit operator std::string_view() const { throw std::runtime_error{"Oops"}; } 18 | }; 19 | 20 | XXX xxx; 21 | 22 | inline std::ostream &operator<<(std::ostream &stream, XXX const &) 23 | { 24 | return stream << "xxx"; 25 | } 26 | 27 | template 28 | inline bool operator==(XXX const &lhs, T const &rhs) 29 | { 30 | return false; 31 | } 32 | 33 | #pragma warning(disable : 4101) // unreferenced local variable 34 | #pragma warning(disable : 4930) // prototyped function not called 35 | -------------------------------------------------------------------------------- /strings/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_koan(strings) 2 | if(MSVC) 3 | target_compile_definitions(strings PRIVATE _SCL_SECURE_NO_WARNINGS) 4 | endif() 5 | -------------------------------------------------------------------------------- /strings/strings.cpp: -------------------------------------------------------------------------------- 1 | #include "strings.h" 2 | 3 | using namespace std::string_literals; 4 | 5 | TEST_CASE("std::string literals") 6 | { 7 | auto s1{"Hello, world!"s}; 8 | auto s2{L"Hello, world!"s}; 9 | auto s3{u"Hello, world!"s}; 10 | auto s4{U"Hello, world!"s}; 11 | REQUIRE((std::is_same_v)); 12 | REQUIRE((std::is_same_v)); 13 | REQUIRE((std::is_same_v)); 14 | REQUIRE((std::is_same_v)); 15 | } 16 | 17 | TEST_CASE("std::string variants") 18 | { 19 | REQUIRE((std::is_same_v, XXX>)); 20 | REQUIRE((std::is_same_v>)); 21 | REQUIRE((std::is_same_v>)); 22 | REQUIRE((std::is_same_v>)); 23 | REQUIRE((std::is_same_v>)); 24 | } 25 | 26 | TEST_CASE("std::string related types") 27 | { 28 | REQUIRE((std::is_same_v)); 29 | REQUIRE((std::is_same_v)); 30 | REQUIRE((std::is_same_v)); 31 | REQUIRE((std::is_same_v)); 32 | REQUIRE((std::is_same_v>)); 33 | REQUIRE((std::is_same_v>)); 34 | } 35 | 36 | TEST_CASE("std::string constructors") 37 | { 38 | std::string const s1; 39 | REQUIRE(xxx == s1.length()); 40 | 41 | std::string const s2{5, 'E'}; 42 | REQUIRE(xxx == s2.length()); 43 | 44 | std::string const s3{s2}; 45 | REQUIRE(xxx == s3.length()); 46 | 47 | std::string const s4{s2, 1}; 48 | REQUIRE(xxx == s4.length()); 49 | 50 | std::string const hw{"Hello, world!"}; 51 | std::string const s5{hw, 1, 4}; 52 | REQUIRE(xxx == s5); 53 | 54 | std::string const s6{"Hello, world!"}; 55 | REQUIRE(xxx == s6.length()); 56 | 57 | std::string const s7{"Hello, world!", 5}; 58 | REQUIRE(xxx == s7); 59 | 60 | std::string const s8{s7.begin(), s7.begin() + 1}; 61 | REQUIRE(xxx == s8); 62 | 63 | std::string const s9{'H', 'e', 'l', 'l', 'o'}; 64 | REQUIRE(xxx == s9); 65 | } 66 | 67 | TEST_CASE("std::string accessors") 68 | { 69 | std::string const s{"Hello, world!"}; 70 | 71 | REQUIRE(xxx == s[0]); 72 | REQUIRE('w' == s.at(xxx)); 73 | REQUIRE_THROWS_AS(s.at(1000), XXX); 74 | REQUIRE(xxx == s.front()); 75 | REQUIRE(xxx == s.back()); 76 | REQUIRE((std::is_same_v)); 77 | REQUIRE((std::is_same_v)); 78 | } 79 | 80 | TEST_CASE("string_iterators") 81 | { 82 | std::string const s{"Hello, world!"}; 83 | REQUIRE((std::is_same_v)); 84 | REQUIRE((std::is_same_v)); 85 | REQUIRE(xxx == *s.begin()); 86 | REQUIRE(xxx == *(s.end() - 1)); 87 | REQUIRE(xxx == *s.rbegin()); 88 | REQUIRE(xxx == *(s.rend() - 1)); 89 | } 90 | 91 | TEST_CASE("std::string capacity") 92 | { 93 | std::string s{"Hello, world!"}; 94 | REQUIRE(xxx == s.length()); 95 | REQUIRE(xxx == s.empty()); 96 | REQUIRE(static_cast(xxx) >= s.capacity()); 97 | 98 | s += s; 99 | s = "Hello, world!"; 100 | REQUIRE(xxx == s.length()); 101 | REQUIRE(static_cast(xxx) >= s.capacity()); 102 | 103 | s.shrink_to_fit(); 104 | REQUIRE(xxx == s.length()); 105 | REQUIRE(static_cast(xxx) >= s.capacity()); 106 | 107 | s.reserve(1024); 108 | REQUIRE(xxx == s.length()); 109 | REQUIRE(xxx == s.capacity()); 110 | } 111 | 112 | TEST_CASE("std::string clear") 113 | { 114 | std::string s{"Hello, world!"}; 115 | s.clear(); 116 | REQUIRE(xxx == s.length()); 117 | REQUIRE(xxx == s.empty()); 118 | REQUIRE(s.capacity() >= static_cast(xxx)); 119 | } 120 | 121 | TEST_CASE("std::string insert") 122 | { 123 | std::string s2{"Bob"}; 124 | auto res1 = s2.insert(1, "illy B"); 125 | REQUIRE((std::is_same_v)); 126 | REQUIRE(xxx == s2); 127 | 128 | auto res2 = s2.insert(0, 2, '-'); 129 | REQUIRE((std::is_same_v)); 130 | REQUIRE(xxx == s2); 131 | 132 | auto res3 = s2.insert(2, "Hello, world!", 7); 133 | REQUIRE((std::is_same_v)); 134 | REQUIRE(xxx == s2); 135 | 136 | std::string s3{"Hello, world!"}; 137 | std::string s4{"big, fat "}; 138 | auto res4 = s3.insert(7, s4); 139 | REQUIRE((std::is_same_v)); 140 | REQUIRE(xxx == s3); 141 | 142 | std::string s5{"Hello, world!"}; 143 | auto res5 = s5.insert(7, s4, xxx, 3); 144 | REQUIRE((std::is_same_v)); 145 | REQUIRE("Hello, fat world!"s == s5); 146 | 147 | std::string s6{"Hello? "}; 148 | std::string::iterator it6{xxx}; 149 | auto res6 = s5.insert(s5.begin(), s6.begin(), it6); 150 | REQUIRE((std::is_same_v)); 151 | REQUIRE("Hello? Hello, fat world!"s == s5); 152 | REQUIRE(xxx == *res6); 153 | 154 | std::string s7{", world"}; 155 | auto res7 = s7.insert(0, {'H', 'e', 'l', 'l', 'o'}); 156 | REQUIRE((std::is_same_v)); 157 | REQUIRE(xxx == s7); 158 | } 159 | 160 | TEST_CASE("std::string erase") 161 | { 162 | std::string s1{"Hello, world!"}; 163 | s1.erase(5); 164 | REQUIRE(xxx == s1); 165 | 166 | std::string s2{"Hello, world!"}; 167 | s2.erase(5, 1); 168 | REQUIRE(xxx == s2); 169 | 170 | std::string s3{"Hello, world!"}; 171 | s3.erase(s3.end() - 1); 172 | REQUIRE(xxx == s3); 173 | 174 | std::string s4{"Hello, world!"}; 175 | std::string::iterator it4{xxx}; 176 | s4.erase(it4, s4.end() - 1); 177 | REQUIRE("H!"s == s4); 178 | } 179 | 180 | TEST_CASE("std::string push_back") 181 | { 182 | std::string s{"<"}; 183 | char c{xxx}; 184 | s.push_back(c); 185 | REQUIRE("<>"s == s); 186 | } 187 | 188 | TEST_CASE("std::string pop_back") 189 | { 190 | std::string s{"[]"}; 191 | s.pop_back(); 192 | REQUIRE(xxx == s); 193 | } 194 | 195 | TEST_CASE("std::string append") 196 | { 197 | std::string s1{"<["}; 198 | auto res1 = s1.append(xxx, 2); 199 | REQUIRE((std::is_same_v)); 200 | REQUIRE("<[]>"s == s1); 201 | 202 | std::string s2{"Foo"}; 203 | s2.append("bar"s); 204 | REQUIRE(xxx == s2); 205 | 206 | std::string s3{"Meta"}; 207 | s3.append("Well, what about the--"s, xxx); 208 | REQUIRE("Meta--"s == s3); 209 | 210 | std::string s4{"Wafer "}; 211 | s4.append("Something"s, 4, xxx); 212 | REQUIRE("Wafer thin"s == s4); 213 | 214 | std::string s5{"The good "}; 215 | s5.append(" wicked witch", xxx); 216 | REQUIRE("The good witch"s == s5); 217 | 218 | std::string s6{"Powdered "}; 219 | const char lit[] = "donut"; 220 | s6.append(std::begin(lit), xxx); 221 | REQUIRE("Powdered donut"s == s6); 222 | 223 | std::string s7{"+"}; 224 | std::initializer_list il{ xxx, xxx, xxx }; 225 | s7.append(il); 226 | REQUIRE("+--+"s == s7); 227 | } 228 | 229 | TEST_CASE("std::string operator+") 230 | { 231 | std::string s1{"One"}; 232 | std::string s2{s1 + static_cast(xxx)}; 233 | REQUIRE("One!"s == s2); 234 | 235 | std::string s3{static_cast(xxx) + s2}; 236 | REQUIRE("!One!"s == s3); 237 | 238 | std::string s4{"One, "}; 239 | std::string s5{xxx}; 240 | std::string s6{s4 + s5}; 241 | REQUIRE("One, Two"s == s6); 242 | 243 | const char *lit = "Ten"; 244 | std::string s7{s4 + lit}; 245 | REQUIRE(xxx == s7); 246 | } 247 | 248 | TEST_CASE("std::string comparison operators") 249 | { 250 | const std::string alpha{"Alpha"}; 251 | REQUIRE("xxx"s < alpha); 252 | REQUIRE("xxx"s > alpha); 253 | REQUIRE("xxx"s <= alpha); 254 | REQUIRE("xxx"s >= alpha); 255 | REQUIRE("xxx"s == alpha); 256 | REQUIRE("xxx"s != alpha); 257 | } 258 | 259 | TEST_CASE("std::string compare") 260 | { 261 | const std::string s1{"Alphabetical"}; 262 | const std::string s2{"Alphanumerical"}; 263 | auto res1 = s1.compare(s2); 264 | REQUIRE((std::is_same_v)); 265 | REQUIRE(xxx == res1); 266 | 267 | REQUIRE(0 == s1.compare(xxx, 5, s2)); 268 | REQUIRE(0 == s1.compare(xxx, 3, s2, 11, 3)); 269 | REQUIRE(0 == s1.compare("xxx")); 270 | REQUIRE(0 == s1.compare(xxx, 4, "ical")); 271 | REQUIRE(0 == s1.compare(xxx, 4, "Canonical", 5)); 272 | } 273 | 274 | TEST_CASE("std::string replace") 275 | { 276 | std::string s{"Canonical"}; 277 | auto res = s.replace(xxx, xxx, "Med"s); 278 | REQUIRE((std::is_same_v)); 279 | REQUIRE("Medical"s == s); 280 | 281 | std::string::iterator first1{xxx}; 282 | std::string::iterator last1{xxx}; 283 | s.replace(first1, last1, "Gargantuan"s); 284 | REQUIRE("Gargantuan"s == s); 285 | 286 | s.replace(xxx, xxx, " Two Face"s, xxx, xxx); 287 | REQUIRE("Gargantua Two"s == s); 288 | 289 | s.replace(xxx, xxx, "Orion double"s, xxx); 290 | REQUIRE("Gargantuan double"s == s); 291 | 292 | s.replace(xxx, xxx, "single minded", xxx); 293 | REQUIRE("Gargantuan single"s == s); 294 | 295 | std::string::iterator first2{xxx}; 296 | std::string::iterator last2{xxx}; 297 | s.replace(first2, last2, "double sided", xxx); 298 | REQUIRE("Gargantuan double"s == s); 299 | 300 | s.replace(xxx, xxx, "le carefully"); 301 | REQUIRE("Gargle carefully"s == s); 302 | 303 | std::string::iterator first3{xxx}; 304 | std::string::iterator last3{xxx}; 305 | s.replace(first3, last3, "is funny sometimes", xxx); 306 | REQUIRE("Gargle is funny"s == s); 307 | 308 | s.replace(xxx, 4, xxx, '-'); 309 | REQUIRE("Gargle--funny"s == s); 310 | 311 | std::string::iterator first4{xxx}; 312 | std::string::iterator last4{xxx}; 313 | s.replace(first4, last4, 1, '!'); 314 | REQUIRE("Gargle!"s == s); 315 | 316 | std::string::iterator first5{xxx}; 317 | std::string::iterator last5{xxx}; 318 | s.replace(first5, last5, std::initializer_list{ xxx, xxx, xxx }); 319 | REQUIRE("Woo!"s == s); 320 | } 321 | 322 | TEST_CASE("std::string substr") 323 | { 324 | std::string s{"Holly Jolly Folly"}; 325 | REQUIRE(xxx == s.substr()); 326 | 327 | REQUIRE("Folly"s == s.substr(xxx)); 328 | 329 | REQUIRE("Jolly"s == s.substr(xxx, xxx)); 330 | } 331 | 332 | TEST_CASE("std::string copy") 333 | { 334 | char dest[5]; 335 | std::string s{"Holly Jolly Folly"}; 336 | auto res = s.copy(dest, xxx); 337 | REQUIRE((std::is_same_v)); 338 | REQUIRE(std::string(std::begin(dest), std::end(dest)) == "Holly"s); 339 | REQUIRE(xxx == res); 340 | 341 | char dest2[5]; 342 | s.copy(dest2, xxx, xxx); 343 | REQUIRE(std::string(std::begin(dest2), std::end(dest2)) == "Jolly"s); 344 | 345 | REQUIRE_THROWS_AS(s.copy(dest2, 0, std::string::npos), XXX); 346 | 347 | char dest3[80]; 348 | auto res2 = s.copy(dest3, std::string::npos); 349 | REQUIRE(xxx == res2); 350 | 351 | char dest4[5]; 352 | s.copy(dest4, std::string::npos, xxx); 353 | REQUIRE(std::string(std::begin(dest4), std::end(dest4)) == "Folly"s); 354 | } 355 | 356 | TEST_CASE("std::string resize") 357 | { 358 | std::string s; 359 | s.resize(xxx); 360 | REQUIRE("\0\0\0"s == s); 361 | 362 | s.resize(5, xxx); 363 | REQUIRE("====="s == s); 364 | } 365 | 366 | TEST_CASE("std::string swap") 367 | { 368 | std::string s1{"Laurel"}; 369 | std::string s2{"Hardy"}; 370 | s1.swap(s2); 371 | REQUIRE("xxx"s == s1); 372 | REQUIRE("xxx"s == s2); 373 | } 374 | 375 | TEST_CASE("std::string find") 376 | { 377 | const std::string s{"Have a fun day at the zoo."}; 378 | auto res = s.find("a"s); 379 | REQUIRE((std::is_same_v)); 380 | REQUIRE(xxx == res); 381 | 382 | char ch{xxx}; 383 | REQUIRE(4 == s.find(ch)); 384 | REQUIRE(6 == s.find(ch, xxx)); 385 | REQUIRE(xxx == s.find("!"s)); 386 | REQUIRE(14 == s.find(" a"s, xxx)); 387 | REQUIRE(xxx == s.find(" a")); 388 | REQUIRE(14 == s.find(" a", xxx)); 389 | REQUIRE(4 == s.find(" a", xxx, 1)); 390 | 391 | REQUIRE(xxx == ""s.find(ch)); 392 | REQUIRE(xxx == "foo"s.find(ch, 10)); 393 | REQUIRE(xxx == "foo"s.find("f"s, 10)); 394 | REQUIRE(xxx == "foo"s.find("f", 10)); 395 | } 396 | 397 | TEST_CASE("std::string rfind") 398 | { 399 | std::string s{"Foobar Googly Eyes"}; 400 | auto res = s.rfind("oo"s); 401 | REQUIRE((std::is_same_v)); 402 | REQUIRE(xxx == res); 403 | 404 | REQUIRE(xxx == s.rfind("oo"s, 6)); 405 | REQUIRE(xxx == s.rfind("oo")); 406 | REQUIRE(xxx == s.rfind("oo", 6)); 407 | REQUIRE(xxx == s.rfind("oo", 6, 1)); 408 | REQUIRE(xxx == s.rfind('y')); 409 | REQUIRE(xxx == s.rfind('y', 14)); 410 | } 411 | 412 | TEST_CASE("std::string find_first_of") 413 | { 414 | std::string s{"Foobar Googly Eyes"}; 415 | auto res = s.find_first_of("EGF"s); 416 | REQUIRE((std::is_same_v)); 417 | REQUIRE(xxx == res); 418 | 419 | REQUIRE(xxx == s.find_first_of("EGF"s, 1)); 420 | REQUIRE(xxx == s.find_first_of("EGF")); 421 | REQUIRE(xxx == s.find_first_of("EGF", 1)); 422 | REQUIRE(xxx == s.find_first_of("EGF", 1, 1)); 423 | REQUIRE(xxx == s.find_first_of('o')); 424 | REQUIRE(xxx == s.find_first_of('o', 3)); 425 | 426 | REQUIRE(xxx == s.find_first_of(""s)); 427 | REQUIRE(xxx == s.find_first_of("")); 428 | REQUIRE(xxx == s.find_first_of("ABC"s)); 429 | REQUIRE(xxx == s.find_first_of("ABC")); 430 | REQUIRE(xxx == s.find_first_of('A')); 431 | REQUIRE(xxx == s.find_first_of("o"s, 100)); 432 | REQUIRE(xxx == s.find_first_of("o", 100)); 433 | REQUIRE(xxx == s.find_first_of("o", 100, 1)); 434 | REQUIRE(xxx == s.find_first_of('o', 100)); 435 | } 436 | 437 | TEST_CASE("std::string find_first_not_of") 438 | { 439 | std::string s{"Foobar Googly Eyes"}; 440 | auto res = s.find_first_not_of("ABCDEFG"s); 441 | REQUIRE((std::is_same_v)); 442 | REQUIRE(xxx == res); 443 | 444 | REQUIRE(xxx == s.find_first_not_of("oab"s, 1)); 445 | REQUIRE(xxx == s.find_first_not_of("abF")); 446 | REQUIRE(xxx == s.find_first_not_of("abF", 3)); 447 | REQUIRE(xxx == s.find_first_not_of("abF", 3, 1)); 448 | REQUIRE(xxx == s.find_first_not_of('F')); 449 | REQUIRE(xxx == s.find_first_not_of('o', 1)); 450 | 451 | REQUIRE(xxx == s.find_first_not_of("Fobar GglyEes"s)); 452 | REQUIRE(xxx == s.find_first_not_of("Fobar GglyEes")); 453 | REQUIRE(xxx == s.substr(1, 1).find_first_not_of('F')); 454 | REQUIRE(xxx == s.find_first_not_of("o"s, 100)); 455 | REQUIRE(xxx == s.find_first_not_of("o", 100)); 456 | REQUIRE(xxx == s.find_first_not_of("o", 100, 1)); 457 | REQUIRE(xxx == s.find_first_not_of('o', 100)); 458 | } 459 | 460 | TEST_CASE("std::string find_last_of") 461 | { 462 | std::string s{"Foobar Googly Eyes"}; 463 | auto res = s.find_last_of("EGF"s); 464 | REQUIRE((std::is_same_v)); 465 | REQUIRE(xxx == res); 466 | 467 | REQUIRE(xxx == s.find_last_of("EGF"s, 1)); 468 | REQUIRE(xxx == s.find_last_of("EGF")); 469 | REQUIRE(xxx == s.find_last_of("EGF", 1)); 470 | REQUIRE(xxx == s.find_last_of("EGF", 1, 1)); 471 | REQUIRE(xxx == s.find_last_of('o')); 472 | REQUIRE(xxx == s.find_last_of('o', 3)); 473 | 474 | REQUIRE(xxx == s.find_last_of(""s)); 475 | REQUIRE(xxx == s.find_last_of("")); 476 | REQUIRE(xxx == s.find_last_of("ABC"s)); 477 | REQUIRE(xxx == s.find_last_of("ABC")); 478 | REQUIRE(xxx == s.find_last_of('A')); 479 | REQUIRE(xxx == s.find_last_of("o"s, 100)); 480 | REQUIRE(xxx == s.find_last_of("o", 100)); 481 | REQUIRE(xxx == s.find_last_of("o", 100, 1)); 482 | REQUIRE(xxx == s.find_last_of('o', 100)); 483 | } 484 | 485 | TEST_CASE("std::string find_last_not_of") 486 | { 487 | std::string s{"Foobar Googly Eyes"}; 488 | auto res = s.find_last_not_of("ABCDEFG"s); 489 | REQUIRE((std::is_same_v)); 490 | REQUIRE(xxx == res); 491 | 492 | REQUIRE(xxx == s.find_last_not_of("oab"s, 1)); 493 | REQUIRE(xxx == s.find_last_not_of("abF")); 494 | REQUIRE(xxx == s.find_last_not_of("abF", 3)); 495 | REQUIRE(xxx == s.find_last_not_of("abF", 3, 1)); 496 | REQUIRE(xxx == s.find_last_not_of('F')); 497 | REQUIRE(xxx == s.find_last_not_of('o', 1)); 498 | 499 | REQUIRE(xxx == s.find_last_not_of("Fobar GglyEes"s)); 500 | REQUIRE(xxx == s.find_last_not_of("Fobar GglyEes")); 501 | REQUIRE(xxx == s.substr(1, 1).find_last_not_of('F')); 502 | REQUIRE(xxx == s.find_last_not_of("o"s, 100)); 503 | REQUIRE(xxx == s.find_last_not_of("o", 100)); 504 | REQUIRE(xxx == s.find_last_not_of("o", 100, 1)); 505 | REQUIRE(xxx == s.find_last_not_of('o', 100)); 506 | } 507 | 508 | TEST_CASE("std::string signed integer conversions") 509 | { 510 | auto res1 = std::stoi("111"s); 511 | REQUIRE((std::is_same_v)); 512 | REQUIRE(xxx == res1); 513 | auto res2 = std::stol("222"s); 514 | REQUIRE((std::is_same_v)); 515 | REQUIRE(xxx == res2); 516 | auto res3 = std::stoll("333"s); 517 | REQUIRE((std::is_same_v)); 518 | REQUIRE(xxx == res3); 519 | 520 | REQUIRE(xxx == std::stoi(L"111"s)); 521 | REQUIRE(xxx == std::stol(L"222"s)); 522 | REQUIRE(xxx == std::stoll(L"333"s)); 523 | 524 | REQUIRE(xxx == std::stoi(" \t\v\r\n\f111"s)); 525 | REQUIRE(xxx == std::stol(" \t\v\r\n\f222"s)); 526 | REQUIRE(xxx == std::stoll(" \t\v\r\n\f333"s)); 527 | 528 | REQUIRE(xxx == std::stoi("-1")); 529 | REQUIRE(xxx == std::stoi("+1")); 530 | 531 | std::size_t pos = 0; 532 | REQUIRE(xxx == std::stoi("100x"s, &pos)); 533 | REQUIRE(xxx == pos); 534 | 535 | for( int base = 2; base <= 36; ++base) 536 | { 537 | REQUIRE(xxx == std::stoi("10", nullptr, base)); 538 | } 539 | 540 | REQUIRE(xxx == std::stoi("10", nullptr, 0)); 541 | REQUIRE(xxx == std::stoi("010", nullptr, 0)); 542 | REQUIRE(xxx == std::stoi("010", nullptr, 8)); 543 | REQUIRE(xxx == std::stoi("0x10", nullptr, 0)); 544 | REQUIRE(xxx == std::stoi("0X10", nullptr, 0)); 545 | REQUIRE(xxx == std::stoi("0x10", nullptr, 16)); 546 | REQUIRE(xxx == std::stoi("0xa", nullptr, 16)); 547 | REQUIRE(xxx == std::stoi("0xA", nullptr, 16)); 548 | 549 | REQUIRE_THROWS_AS(std::stoi("Yikes!"), XXX); 550 | REQUIRE_THROWS_AS(std::stoi("0xFFFFFFFFFFFFFFFFFFFFFFFF", nullptr, 16), XXX); 551 | } 552 | 553 | TEST_CASE("std::string unsigned integer conversions") 554 | { 555 | auto res1 = std::stoul("111"s); 556 | REQUIRE((std::is_same_v)); 557 | REQUIRE(xxx == res1); 558 | auto res2 = std::stoull("222"s); 559 | REQUIRE((std::is_same_v)); 560 | REQUIRE(xxx == res2); 561 | 562 | REQUIRE(xxx == std::stoul(L"111"s)); 563 | REQUIRE(xxx == std::stoull(L"222"s)); 564 | 565 | REQUIRE(xxx == std::stoul(" \t\v\r\n\f111"s)); 566 | REQUIRE(xxx == std::stoull(" \t\v\r\n\f222"s)); 567 | 568 | REQUIRE(xxx == std::stoul("-1")); 569 | REQUIRE(xxx == std::stoul("+1")); 570 | 571 | std::size_t pos = 0; 572 | REQUIRE(xxx == std::stoul("100x"s, &pos)); 573 | REQUIRE(xxx == pos); 574 | 575 | for( int base = 2; base <= 36; ++base) 576 | { 577 | REQUIRE(xxx == std::stoul("10", nullptr, base)); 578 | } 579 | 580 | REQUIRE(xxx == std::stoul("10", nullptr, 0)); 581 | REQUIRE(xxx == std::stoul("010", nullptr, 0)); 582 | REQUIRE(xxx == std::stoul("010", nullptr, 8)); 583 | REQUIRE(xxx == std::stoul("0x10", nullptr, 0)); 584 | REQUIRE(xxx == std::stoul("0X10", nullptr, 0)); 585 | REQUIRE(xxx == std::stoul("0x10", nullptr, 16)); 586 | 587 | REQUIRE_THROWS_AS(std::stoul("Yikes!"), XXX); 588 | REQUIRE_THROWS_AS(std::stoul("0xFFFFFFFFFFFFFFFFFFFFFFFF", nullptr, 16), XXX); 589 | } 590 | 591 | TEST_CASE("std::string float conversions") 592 | { 593 | auto res1 = std::stof("111"s); 594 | REQUIRE((std::is_same_v)); 595 | REQUIRE(xxx == res1); 596 | auto res2 = std::stod("222"s); 597 | REQUIRE((std::is_same_v)); 598 | REQUIRE(xxx == res2); 599 | 600 | REQUIRE(xxx == std::stof(L"111"s)); 601 | REQUIRE(xxx == std::stod(L"222"s)); 602 | 603 | REQUIRE(xxx == std::stof(" \t\v\r\n\f111"s)); 604 | REQUIRE(xxx == std::stod(" \t\v\r\n\f222"s)); 605 | 606 | REQUIRE(xxx == std::stof("-1.5e1")); 607 | REQUIRE(xxx == std::stof("+1.5E1")); 608 | REQUIRE(xxx == std::stof("inf")); 609 | REQUIRE(xxx == std::stof("-INFINITY")); 610 | REQUIRE(xxx == std::stof("+nan")); 611 | REQUIRE(xxx == std::stof("-nanotechnology")); 612 | 613 | std::size_t pos = 0; 614 | REQUIRE(xxx == std::stof("100x"s, &pos)); 615 | REQUIRE(xxx == pos); 616 | 617 | REQUIRE_THROWS_AS(std::stof("Yikes!"), XXX); 618 | REQUIRE_THROWS_AS(std::stof("0xFFFFFFFFFFFFFFFFFFFFFFFF", nullptr), XXX); 619 | } 620 | 621 | TEST_CASE("std::string to_string function") 622 | { 623 | REQUIRE((std::is_same_v)); 624 | REQUIRE((std::is_same_v)); 625 | REQUIRE("xxx"s == std::to_string(-1)); 626 | REQUIRE("xxx"s == std::to_string(2L)); 627 | REQUIRE("xxx"s == std::to_string(3LL)); 628 | REQUIRE("xxx"s == std::to_string(4U)); 629 | REQUIRE("xxx"s == std::to_string(5UL)); 630 | REQUIRE("xxx"s == std::to_string(6ULL)); 631 | REQUIRE("xxx"s == std::to_string(23.43f)); 632 | REQUIRE("xxx"s == std::to_string(23.43)); 633 | REQUIRE("xxx"s == std::to_string(23.43L)); 634 | REQUIRE("xxx"s == std::to_string(1e-40)); 635 | } 636 | 637 | TEST_CASE("std::string allocators") 638 | { 639 | REQUIRE((std::is_same_v)); 640 | REQUIRE((std::is_same_v)); 641 | REQUIRE((std::is_same_v)); 642 | REQUIRE((std::is_same_v)); 643 | REQUIRE((std::is_same_v)); 644 | } 645 | -------------------------------------------------------------------------------- /strings/strings.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | #include 8 | 9 | struct XXX 10 | { 11 | operator bool() const { throw std::runtime_error{"Oops"}; } 12 | operator char() const { throw std::runtime_error{"Oops"}; } 13 | operator int() const { throw std::runtime_error{"Oops"}; } 14 | operator std::string::size_type() const { throw std::runtime_error{"Oops"}; } 15 | explicit operator std::string::iterator() const { throw std::runtime_error{"Oops"}; } 16 | explicit operator std::string() const { throw std::runtime_error{"Ooops"}; } 17 | explicit operator const char *() const { throw std::runtime_error{"Ooops"}; } 18 | }; 19 | 20 | XXX xxx; 21 | 22 | inline std::ostream &operator<<(std::ostream &stream, XXX const &) 23 | { 24 | return stream << "xxx"; 25 | } 26 | 27 | template 28 | inline bool operator==(XXX const &lhs, T const &rhs) 29 | { 30 | return false; 31 | } 32 | 33 | #pragma warning(disable : 4101) // unreferenced local variable 34 | #pragma warning(disable : 4930) // prototyped function not called 35 | -------------------------------------------------------------------------------- /type_traits/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_koan(type_traits) 2 | -------------------------------------------------------------------------------- /type_traits/type_traits.cpp: -------------------------------------------------------------------------------- 1 | #include "type_traits.h" 2 | #include 3 | 4 | // In each test, replace XXX with syntax that passes the test. 5 | 6 | TEST_CASE("is_void") 7 | { 8 | REQUIRE(std::is_void::value); 9 | std::is_void val; 10 | REQUIRE(static_cast(val)); 11 | } 12 | 13 | TEST_CASE("is_integral") 14 | { 15 | REQUIRE(std::is_integral::value); 16 | REQUIRE(xxx == std::is_integral::value); 17 | REQUIRE(xxx == std::is_integral::value); 18 | REQUIRE(xxx == std::is_integral::value); 19 | REQUIRE(xxx == std::is_integral::value); 20 | REQUIRE(xxx == std::is_integral::value); 21 | REQUIRE(xxx == std::is_integral::value); 22 | REQUIRE(xxx == std::is_integral::value); 23 | REQUIRE(xxx == std::is_integral::value); 24 | REQUIRE(xxx == std::is_integral::value); 25 | REQUIRE(xxx == std::is_integral::value); 26 | REQUIRE(xxx == std::is_integral::value); 27 | REQUIRE(xxx == std::is_integral::value); 28 | } 29 | 30 | TEST_CASE("is_floating_point") 31 | { 32 | REQUIRE(xxx == std::is_floating_point::value); 33 | REQUIRE(xxx == std::is_floating_point::value); 34 | REQUIRE(xxx == std::is_floating_point::value); 35 | REQUIRE(xxx == std::is_floating_point::value); 36 | REQUIRE(xxx == std::is_floating_point::value); 37 | REQUIRE(xxx == std::is_floating_point::value); 38 | REQUIRE(xxx == std::is_floating_point::value); 39 | } 40 | 41 | TEST_CASE("is_array") 42 | { 43 | REQUIRE(xxx == std::is_array::value); 44 | typedef std::array std_array; 45 | REQUIRE(xxx == std::is_array::value); 46 | REQUIRE(xxx == std::is_array::value); 47 | REQUIRE(xxx == std::is_array::value); 48 | REQUIRE(std::is_array::value); 49 | REQUIRE(xxx == std::is_array::value); 50 | } 51 | 52 | TEST_CASE("is_enum") 53 | { 54 | REQUIRE(std::is_enum::value); 55 | } 56 | 57 | TEST_CASE("is_union") 58 | { 59 | REQUIRE(std::is_union::value); 60 | struct S {}; 61 | REQUIRE(xxx == std::is_union::value); 62 | } 63 | 64 | TEST_CASE("is_class") 65 | { 66 | REQUIRE(xxx == std::is_class::value); 67 | struct S {}; 68 | REQUIRE(xxx == std::is_class::value); 69 | class C {}; 70 | REQUIRE(xxx == std::is_class::value); 71 | union U {}; 72 | REQUIRE(xxx == std::is_class::value); 73 | typedef int A[10]; 74 | REQUIRE(xxx == std::is_class::value); 75 | } 76 | 77 | TEST_CASE("is_function") 78 | { 79 | struct S {}; 80 | S s1(); 81 | REQUIRE(xxx == std::is_function::value); 82 | S s2{}; 83 | REQUIRE(xxx == std::is_function::value); 84 | REQUIRE(xxx == std::is_function::value); 85 | typedef void p(); 86 | REQUIRE(xxx == std::is_function

::value); 87 | REQUIRE(xxx == std::is_function

::value); 88 | REQUIRE(xxx == std::is_function>::value); 89 | } 90 | 91 | TEST_CASE("is_pointer") 92 | { 93 | REQUIRE(xxx == std::is_pointer::value); 94 | REQUIRE(xxx == std::is_pointer::value); 95 | int i; 96 | REQUIRE(xxx == std::is_pointer::value); 97 | REQUIRE(xxx == std::is_pointer::value); 98 | REQUIRE(xxx == std::is_pointer::value); 99 | REQUIRE(xxx == std::is_pointer::value); 100 | } 101 | 102 | TEST_CASE("is_lvalue_reference") 103 | { 104 | REQUIRE(xxx == std::is_lvalue_reference::value); 105 | REQUIRE(xxx == std::is_lvalue_reference::value); 106 | REQUIRE(xxx == std::is_lvalue_reference::value); 107 | int i; 108 | REQUIRE(xxx == std::is_lvalue_reference::value); 109 | } 110 | 111 | TEST_CASE("is_rvalue_reference") 112 | { 113 | REQUIRE(xxx == std::is_rvalue_reference::value); 114 | REQUIRE(xxx == std::is_rvalue_reference::value); 115 | REQUIRE(xxx == std::is_rvalue_reference::value); 116 | int i; 117 | REQUIRE(xxx == std::is_rvalue_reference::value); 118 | REQUIRE(xxx == std::is_rvalue_reference::value); 119 | } 120 | 121 | TEST_CASE("is_member_object_pointer") 122 | { 123 | struct S { int i; }; 124 | S s; 125 | REQUIRE(xxx == std::is_member_object_pointer::value); 126 | REQUIRE(xxx == std::is_member_object_pointer::value); 127 | REQUIRE(xxx == std::is_member_object_pointer::value); 128 | union U { int i; char c; }; 129 | U u; 130 | REQUIRE(xxx == std::is_member_object_pointer::value); 131 | REQUIRE(xxx == std::is_member_object_pointer::value); 132 | REQUIRE(xxx == std::is_member_object_pointer::value); 133 | } 134 | 135 | TEST_CASE("is_member_function_pointer") 136 | { 137 | struct S { char c; void i() {} }; 138 | S s; 139 | REQUIRE(xxx == std::is_member_function_pointer::value); 140 | REQUIRE(xxx == std::is_member_function_pointer::value); 141 | REQUIRE(xxx == std::is_member_function_pointer::value); 142 | REQUIRE(xxx == std::is_member_function_pointer::value); 143 | } 144 | 145 | TEST_CASE("is_arithmetic") 146 | { 147 | REQUIRE(!std::is_arithmetic::value); 148 | REQUIRE(!std::is_arithmetic::value); 149 | REQUIRE(std::is_integral::value == std::is_arithmetic::value); 150 | REQUIRE(std::is_floating_point::value == std::is_arithmetic::value); 151 | REQUIRE(xxx == std::is_arithmetic::value); 152 | REQUIRE(xxx == std::is_arithmetic::value); 153 | REQUIRE(xxx == std::is_arithmetic::value); 154 | REQUIRE(xxx == std::is_arithmetic::value); 155 | REQUIRE(xxx == std::is_arithmetic::value); 156 | REQUIRE(std::is_arithmetic::value_type>::value); 157 | } 158 | 159 | TEST_CASE("is_fundamental") 160 | { 161 | REQUIRE(xxx == std::is_fundamental::value); 162 | REQUIRE(xxx == std::is_fundamental::value); 163 | REQUIRE(std::is_arithmetic::value == std::is_fundamental::value); 164 | REQUIRE(xxx == std::is_fundamental::value); 165 | REQUIRE(xxx == std::is_fundamental::value); 166 | REQUIRE(xxx == std::is_fundamental::value); 167 | REQUIRE(xxx == std::is_fundamental::value); 168 | REQUIRE(xxx == std::is_fundamental::value); 169 | REQUIRE(xxx == std::is_fundamental::value); 170 | REQUIRE(xxx == std::is_fundamental::value); 171 | REQUIRE(xxx == std::is_fundamental>::value); 172 | REQUIRE(xxx == std::is_fundamental *>::value); 173 | REQUIRE(xxx == std::is_fundamental::value_type>::value); 174 | } 175 | 176 | TEST_CASE("is_const") 177 | { 178 | REQUIRE(xxx == std::is_const::value); 179 | REQUIRE(xxx == std::is_const::value); 180 | REQUIRE(xxx == std::is_const::value); 181 | REQUIRE(xxx == std::is_const::value); 182 | REQUIRE(xxx == std::is_const::value); 183 | REQUIRE(xxx == std::is_const::value); 184 | REQUIRE(xxx == std::is_const::value); 185 | } 186 | 187 | TEST_CASE("is_volatile") 188 | { 189 | REQUIRE(xxx == std::is_volatile::value); 190 | REQUIRE(xxx == std::is_volatile::value); 191 | REQUIRE(xxx == std::is_volatile::value); 192 | REQUIRE(xxx == std::is_volatile::value); 193 | REQUIRE(xxx == std::is_volatile::value); 194 | REQUIRE(xxx == std::is_volatile::value); 195 | REQUIRE(xxx == std::is_volatile::value); 196 | } 197 | 198 | TEST_CASE("is_trivial") 199 | { 200 | REQUIRE(xxx == std::is_trivial::value); 201 | class Empty {}; 202 | REQUIRE(xxx == std::is_trivial::value); 203 | REQUIRE(xxx == std::is_trivial::value); 204 | class CustomConstructor 205 | { 206 | public: 207 | CustomConstructor(int i) : i_(i) {} 208 | private: 209 | int &i_; 210 | }; 211 | REQUIRE(xxx == std::is_trivial::value); 212 | } 213 | -------------------------------------------------------------------------------- /type_traits/type_traits.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | #include 11 | 12 | struct XXX 13 | { 14 | operator bool() { throw std::runtime_error("Oops"); } 15 | }; 16 | 17 | XXX xxx; 18 | 19 | inline std::ostream &operator<<(std::ostream &stream, XXX const &) 20 | { 21 | return stream << "xxx"; 22 | } 23 | 24 | template 25 | inline bool operator==(XXX const &lhs, T const &rhs) 26 | { 27 | return false; 28 | } 29 | 30 | #pragma warning(disable : 4101) // unreferenced local variable 31 | #pragma warning(disable : 4930) // prototyped function not called 32 | --------------------------------------------------------------------------------