├── CMakeLists.txt ├── CTTM.h ├── README.md └── examples ├── 2_state_busy_beaver.cpp ├── 3_state_busy_beaver.cpp ├── 4_state_busy_beaver.cpp ├── 5_state_busy_beaver.cpp ├── binary_increment.cpp ├── first.cpp └── inverse.cpp /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.4) 2 | 3 | project(CTTM) 4 | 5 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -ftemplate-depth-100000000") 6 | 7 | include_directories(".") 8 | 9 | add_executable(2_state_busy_beaver examples/2_state_busy_beaver.cpp) 10 | add_executable(3_state_busy_beaver examples/3_state_busy_beaver.cpp) 11 | add_executable(4_state_busy_beaver examples/4_state_busy_beaver.cpp) 12 | add_executable(5_state_busy_beaver examples/5_state_busy_beaver.cpp) 13 | add_executable(binary_increment examples/binary_increment.cpp) 14 | add_executable(first examples/first.cpp) 15 | add_executable(inverse examples/inverse.cpp) -------------------------------------------------------------------------------- /CTTM.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #pragma mark - Tape 6 | 7 | constexpr int Blank = -1; 8 | 9 | template 10 | class Tape { 11 | public: 12 | using type = Tape; 13 | constexpr static int length = sizeof...(xs); 14 | }; 15 | 16 | #pragma mark - Print 17 | 18 | template 19 | void print(T); 20 | 21 | template<> 22 | void print(Tape<>) { 23 | std::cout << std::endl; 24 | } 25 | 26 | template 27 | void print(Tape) { 28 | if (x == Blank) { 29 | std::cout << "_ "; 30 | } else { 31 | std::cout << x << " "; 32 | } 33 | print(Tape()); 34 | } 35 | 36 | #pragma mark - Concatenate 37 | 38 | template 39 | class Concatenate; 40 | 41 | template 42 | class Concatenate, Tape> { 43 | public: 44 | using type = Tape; 45 | }; 46 | 47 | #pragma mark - Invert 48 | 49 | template 50 | class Invert; 51 | 52 | template<> 53 | class Invert> { 54 | public: 55 | using type = Tape<>; 56 | }; 57 | 58 | template 59 | class Invert> { 60 | public: 61 | using type = typename Concatenate< 62 | typename Invert>::type, 63 | Tape 64 | >::type; 65 | }; 66 | 67 | #pragma mark - Read 68 | 69 | template 70 | class Read; 71 | 72 | template 73 | class Read> { 74 | public: 75 | using type = typename std::conditional< 76 | (n == 0), 77 | std::integral_constant, 78 | Read> 79 | >::type::type; 80 | }; 81 | 82 | #pragma mark - N first and N last 83 | 84 | template 85 | class NLast; 86 | 87 | template 88 | class NLast> { 89 | public: 90 | using type = typename std::conditional< 91 | (n == sizeof...(xs)), 92 | Tape, 93 | NLast> 94 | >::type::type; 95 | }; 96 | 97 | template 98 | class NFirst; 99 | 100 | template 101 | class NFirst> { 102 | public: 103 | using type = typename Invert< 104 | typename NLast< 105 | n, typename Invert>::type 106 | >::type 107 | >::type; 108 | }; 109 | 110 | #pragma mark - Write 111 | 112 | template 113 | class Write; 114 | 115 | template 116 | class Write> { 117 | public: 118 | using type = typename Concatenate< 119 | typename Concatenate< 120 | typename NFirst>::type, 121 | Tape 122 | >::type, 123 | typename NLast<(sizeof...(xs) - pos - 1), Tape>::type 124 | >::type; 125 | }; 126 | 127 | #pragma mark - Move 128 | 129 | template 130 | class Hold; 131 | 132 | template 133 | class Hold> { 134 | public: 135 | constexpr static int position = pos; 136 | using tape = Tape; 137 | }; 138 | 139 | template 140 | class Left; 141 | 142 | template 143 | class Left> { 144 | public: 145 | constexpr static int position = typename std::conditional< 146 | (pos > 0), 147 | std::integral_constant, 148 | std::integral_constant 149 | >::type(); 150 | 151 | using tape = typename std::conditional< 152 | (pos > 0), 153 | Tape, 154 | Tape 155 | >::type; 156 | }; 157 | 158 | template 159 | class Right; 160 | 161 | template 162 | class Right> { 163 | public: 164 | constexpr static int position = pos + 1; 165 | 166 | using tape = typename std::conditional< 167 | (pos < sizeof...(xs) - 1), 168 | Tape, 169 | Tape 170 | >::type; 171 | }; 172 | 173 | #pragma mark - States 174 | 175 | template 176 | class Stop { 177 | public: 178 | constexpr static int write = -1; 179 | template using move = Hold; 180 | template using next = Stop; 181 | }; 182 | 183 | #define ADD_STATE(_state_) \ 184 | template \ 185 | class _state_ { }; 186 | 187 | #define ADD_RULE(_state_, _read_, _write_, _move_, _next_) \ 188 | template<> \ 189 | class _state_<_read_> { \ 190 | public: \ 191 | constexpr static int write = _write_; \ 192 | template using move = _move_; \ 193 | template using next = _next_; \ 194 | }; 195 | 196 | #pragma mark - Machine 197 | 198 | template class, int, class> 199 | class Machine; 200 | 201 | template class State, int pos, int... xs> 202 | class Machine> { 203 | constexpr static int symbol = typename Read>::type(); 204 | using state = State; 205 | 206 | template 207 | using nextState = typename State::template next; 208 | 209 | using modifiedTape = typename Write>::type; 210 | using move = typename state::template move; 211 | 212 | constexpr static int nextPos = move::position; 213 | using nextTape = typename move::tape; 214 | 215 | public: 216 | using step = Machine; 217 | }; 218 | 219 | #pragma mark - Run 220 | 221 | template 222 | class Run; 223 | 224 | template class State, int pos, int... xs> 225 | class Run>> { 226 | using step = typename Machine>::step; 227 | 228 | public: 229 | using type = typename std::conditional< 230 | std::is_same, Stop<0>>::value, 231 | Tape, 232 | Run 233 | >::type::type; 234 | }; 235 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## Compile Time Turing Machine 2 | ##### Going medieval on your compiler 3 | 4 | Everyone interested in C++ template metaprogramming probably heard about Turing-completeness of C++ templates, and this project shows how to actually build a Turing Machine with templates and constant expressions, allowing things like this: 5 | 6 | ```cpp 7 | ADD_STATE(A); 8 | ADD_STATE(B); 9 | ADD_STATE(C); 10 | ADD_STATE(D); 11 | 12 | ADD_RULE(A, Blank, 1, Right, B); 13 | ADD_RULE(A, 1, 1, Left, B); 14 | 15 | ADD_RULE(B, Blank, 1, Left, A); 16 | ADD_RULE(B, 1, Blank, Left, C); 17 | 18 | ADD_RULE(C, Blank, 1, Right, Stop); 19 | ADD_RULE(C, 1, 1, Left, D); 20 | 21 | ADD_RULE(D, Blank, 1, Right, D); 22 | ADD_RULE(D, 1, Blank, Right, A); 23 | 24 | using tape = Tape; 25 | using machine = Machine; 26 | using result = Run::type; 27 | 28 | int main() { 29 | print(result()); 30 | return 0; 31 | } 32 | ``` 33 | 34 | This is a 4-state 2-symbol busy beaver example (https://en.wikipedia.org/wiki/Busy_beaver). The result is 35 | ``` 36 | 1 _ 1 1 1 1 1 1 1 1 1 1 1 1 37 | ``` 38 | 39 | You can check out ideone run here: https://ideone.com/MvBU3Z. All the work is performed before the program is even launched! 40 | 41 | Here is a blog post with a thorough explanation of the underlying mechanics: http://victorkomarov.blogspot.ru/2016/03/compile-time-turing-machine.html 42 | -------------------------------------------------------------------------------- /examples/2_state_busy_beaver.cpp: -------------------------------------------------------------------------------- 1 | // 2-state 2-symbol busy beaver 2 | // outputs 4 ones in 6 steps 3 | 4 | #include "CTTM.h" 5 | 6 | ADD_STATE(A); 7 | ADD_STATE(B); 8 | 9 | ADD_RULE(A, Blank, 1, Right, B); 10 | ADD_RULE(A, 1, 1, Left, B); 11 | 12 | ADD_RULE(B, Blank, 1, Left, A); 13 | ADD_RULE(B, 1, 1, Right, Stop); 14 | 15 | using tape = Tape; 16 | using machine = Machine; 17 | using result = Run::type; 18 | 19 | int main() { 20 | print(result()); 21 | return 0; 22 | } 23 | -------------------------------------------------------------------------------- /examples/3_state_busy_beaver.cpp: -------------------------------------------------------------------------------- 1 | // 3-state 2-symbol busy beaver 2 | // outputs 6 ones in 14 steps 3 | 4 | #include "CTTM.h" 5 | 6 | ADD_STATE(A); 7 | ADD_STATE(B); 8 | ADD_STATE(C); 9 | 10 | ADD_RULE(A, Blank, 1, Right, B); 11 | ADD_RULE(A, 1, 1, Right, Stop); 12 | 13 | ADD_RULE(B, Blank, Blank, Right, C); 14 | ADD_RULE(B, 1, 1, Right, B); 15 | 16 | ADD_RULE(C, Blank, 1, Left, C); 17 | ADD_RULE(C, 1, 1, Left, A); 18 | 19 | using tape = Tape; 20 | using machine = Machine; 21 | using result = Run::type; 22 | 23 | int main() { 24 | print(result()); 25 | return 0; 26 | } 27 | -------------------------------------------------------------------------------- /examples/4_state_busy_beaver.cpp: -------------------------------------------------------------------------------- 1 | // 4-state 2-symbol busy beaver 2 | // outputs 13 ones in 107 steps 3 | 4 | #include "CTTM.h" 5 | 6 | ADD_STATE(A); 7 | ADD_STATE(B); 8 | ADD_STATE(C); 9 | ADD_STATE(D); 10 | 11 | ADD_RULE(A, Blank, 1, Right, B); 12 | ADD_RULE(A, 1, 1, Left, B); 13 | 14 | ADD_RULE(B, Blank, 1, Left, A); 15 | ADD_RULE(B, 1, Blank, Left, C); 16 | 17 | ADD_RULE(C, Blank, 1, Right, Stop); 18 | ADD_RULE(C, 1, 1, Left, D); 19 | 20 | ADD_RULE(D, Blank, 1, Right, D); 21 | ADD_RULE(D, 1, Blank, Right, A); 22 | 23 | using tape = Tape; 24 | using machine = Machine; 25 | using result = Run::type; 26 | 27 | int main() { 28 | print(result()); 29 | return 0; 30 | } 31 | -------------------------------------------------------------------------------- /examples/5_state_busy_beaver.cpp: -------------------------------------------------------------------------------- 1 | // 5-state 2-symbol busy beaver (actually best contender) 2 | // According to Wikipedia it results in 4098 ones in 47176870 steps. 3 | // 4 | // Apple clang used about 20 gb swap and segfaulted during compilation on my machine *_* 5 | 6 | #include "CTTM.h" 7 | 8 | ADD_STATE(A); 9 | ADD_STATE(B); 10 | ADD_STATE(C); 11 | ADD_STATE(D); 12 | ADD_STATE(E); 13 | 14 | ADD_RULE(A, Blank, 1, Right, B); 15 | ADD_RULE(A, 1, 1, Left, C); 16 | 17 | ADD_RULE(B, Blank, 1, Right, C); 18 | ADD_RULE(B, 1, 1, Right, B); 19 | 20 | ADD_RULE(C, Blank, 1, Right, D); 21 | ADD_RULE(C, 1, Blank, Left, E); 22 | 23 | ADD_RULE(D, Blank, 1, Left, A); 24 | ADD_RULE(D, 1, 1, Left, D); 25 | 26 | ADD_RULE(E, Blank, 1, Right, Stop); 27 | ADD_RULE(E, 1, Blank, Left, A); 28 | 29 | 30 | using tape = Tape; 31 | using machine = Machine; 32 | using result = Run::type; 33 | 34 | int main() { 35 | print(result()); 36 | return 0; 37 | } -------------------------------------------------------------------------------- /examples/binary_increment.cpp: -------------------------------------------------------------------------------- 1 | // Given a tape with a binary number this machine will perform an increment 2 | // 3 | // This example illustrates how to wrap a particular setup into operation class 4 | // and perform several consecutive runs. 5 | 6 | #include "CTTM.h" 7 | 8 | ADD_STATE(S0); 9 | ADD_STATE(S1); 10 | ADD_STATE(S2); 11 | 12 | ADD_RULE(S0, Blank, Blank, Left, S1); 13 | ADD_RULE(S0, 0, 0, Right, S0); 14 | ADD_RULE(S0, 1, 1, Right, S0); 15 | 16 | ADD_RULE(S1, Blank, 1, Right, S2); 17 | ADD_RULE(S1, 0, 1, Left, S2); 18 | ADD_RULE(S1, 1, 0, Left, S1); 19 | 20 | ADD_RULE(S2, Blank, Blank, Hold, Stop); 21 | ADD_RULE(S2, 0, 0, Right, S2); 22 | ADD_RULE(S2, 1, 1, Right, S2); 23 | 24 | template 25 | class Increment { }; 26 | 27 | template 28 | class Increment> { 29 | public: 30 | using type = typename Run::length - 1, Tape>>::type; 31 | }; 32 | 33 | using tape = Tape; 34 | 35 | int main() { 36 | print(tape()); 37 | print(Increment::type()); 38 | print(Increment::type>::type()); 39 | print(Increment::type>::type>::type()); 40 | print(Increment::type>::type>::type>::type()); 41 | print(Increment::type>::type>::type>::type>::type()); 42 | return 0; 43 | } -------------------------------------------------------------------------------- /examples/first.cpp: -------------------------------------------------------------------------------- 1 | // According to Wikipedia, this is Alan Turing's first example 2 | // 3 | // A cyclic transition to Q1 is replaced with Stop 4 | // to avoid infinite recursion 5 | 6 | #include "CTTM.h" 7 | 8 | ADD_STATE(Q1); 9 | ADD_STATE(Q2); 10 | ADD_STATE(Q3); 11 | ADD_STATE(Q4); 12 | 13 | ADD_RULE(Q1, Blank, 0, Right, Q2); 14 | ADD_RULE(Q2, Blank, Blank, Right, Q3); 15 | ADD_RULE(Q3, Blank, 1, Right, Q4); 16 | ADD_RULE(Q4, Blank, Blank, Hold, Stop); 17 | 18 | using tape = Tape; 19 | using machine = Machine; 20 | using result = Run::type; 21 | 22 | int main() { 23 | print(result()); 24 | return 0; 25 | } 26 | -------------------------------------------------------------------------------- /examples/inverse.cpp: -------------------------------------------------------------------------------- 1 | // A simple machine with only one state that turns zeroes 2 | // into ones and vice versa until it reaches a blank symbol 3 | 4 | #include "CTTM.h" 5 | 6 | ADD_STATE(A); 7 | 8 | ADD_RULE(A, 1, 0, Right, A); 9 | ADD_RULE(A, 0, 1, Right, A); 10 | ADD_RULE(A, Blank, Blank, Hold, Stop); 11 | 12 | using tape = Tape<1, 1, 0, 1, Blank>; 13 | using machine = Machine; 14 | using result = Run::type; 15 | 16 | int main() { 17 | print(tape()); 18 | print(result()); 19 | return 0; 20 | } --------------------------------------------------------------------------------