├── .gitattributes ├── .gitignore ├── LICENSE ├── README.md ├── example.cpp ├── generator.py ├── include ├── cexpr │ └── string.hpp ├── ra │ ├── cross.hpp │ ├── join.hpp │ ├── natural.hpp │ ├── operation.hpp │ ├── projection.hpp │ ├── relation.hpp │ ├── rename.hpp │ └── selection.hpp └── sql │ ├── column.hpp │ ├── index.hpp │ ├── predicate.hpp │ ├── query.hpp │ ├── row.hpp │ ├── schema.hpp │ └── tokens.hpp ├── presentation.pdf ├── single-header └── sql.hpp └── tests ├── data.hpp ├── data ├── authored.tsv ├── books.tsv ├── collected.tsv ├── library-cross.db ├── library.db └── stories.tsv ├── perf ├── data │ ├── lib-query0 │ ├── lib-query1 │ ├── lib-query2 │ ├── lib-query3 │ ├── lib-query4 │ ├── lib-query5 │ ├── query0 │ ├── query1 │ ├── query2 │ ├── query3 │ ├── query4 │ └── query5 ├── queries │ ├── lib-query0.cpp │ ├── lib-query1.cpp │ ├── lib-query2.cpp │ ├── lib-query3.cpp │ ├── lib-query4.cpp │ ├── lib-query5.cpp │ ├── query0.cpp │ ├── query1.cpp │ ├── query2.cpp │ ├── query3.cpp │ ├── query4.cpp │ └── query5.cpp ├── runner.sh └── scripts │ └── runner.py ├── runner.sh └── scripts ├── compose.py ├── generate.py ├── runner.py └── select.py /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | tests/*.txt 2 | tests/test.cpp 3 | tests/test 4 | tests/queries/* 5 | .vscode/* 6 | example 7 | .DS_STORE 8 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 Michael Kitzan 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 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Constexpr SQL 2 | 3 | A light weight single header alternative to DBMS 4 | 5 | This library was developed during my honors project at the [University of Victoria](https://www.uvic.ca/engineering/computerscience/index.php) under the supervision of [Bill Bird](https://github.com/billbird). The original development occurred in this [Metaprogramming Optimization](https://github.com/mkitzan/metaprogramming-optimization) repository, but was moved into a new, dedicated, home repository. The project was inspired and influenced by [Hana Dusíková](https://github.com/hanickadot)'s great [Compile Time Regular Expressions](https://github.com/hanickadot/compile-time-regular-expressions) library (CTRE). 6 | 7 | Maintenance may slow in the near future due to my employer's open source software policy. I will be looking into getting approval to continue maintaining this project. 8 | 9 | ## Library Features and Compiler Support 10 | 11 | Supported features: 12 | 13 | - SQL query syntax for data processing 14 | - `SELECT` data querying 15 | - `AS` column renaming 16 | - `CROSS JOIN` (note: all column names of each relation must be unique) 17 | - `NATURAL JOIN` (note: natural join will attempt to join on the first column of each relation) 18 | - `WHERE` clause predicates on numeric and `std::string` types 19 | - Wildcard selection with `*` 20 | - Nested queries 21 | - Uppercase and lowercase SQL keywords 22 | - Modern `!=` and legacy `<>` not-equal operator 23 | - Standard SQL operator precedence in `WHERE` clause 24 | - Schemas support all default constructable types 25 | - Indexes for schemas (used for sorting the data) 26 | - Range loop and structured binding declaration support 27 | - [Loading data](https://github.com/mkitzan/constexpr-sql/blob/master/include/sql/schema.hpp#L180) from files (no header row) 28 | - [Storing data](https://github.com/mkitzan/constexpr-sql/blob/master/include/sql/schema.hpp#L210) from `sql::schema` and `sql::query` objects to files 29 | - Element querying from `sql::row` objects with [`sql::get<"column-name">`](https://github.com/mkitzan/constexpr-sql/blob/master/include/sql/row.hpp#L81) 30 | 31 | Unsupported features (future work): 32 | 33 | - `INNER JOIN`, `OUTER JOIN`, `LEFT JOIN`, and `RIGHT JOIN` 34 | - `GROUP BY`, `HAVING`, and `ORDER BY` (using indexes can simulate some of these features) 35 | - `IN` operation within `WHERE` clause 36 | - Template argument error detection 37 | 38 | As of April 2020, Constexpr SQL is only supported by **`GCC 9.0+`**. The compiler support is constrained because of the widespread use of the new `C++20` feature ["Class Types in Non-Type Template Parameters"](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2018/p0732r2.pdf) (proposal `P0732R2`) which is only implemented by `GCC 9.0+`. Library users specify SQL queries and column labels with string literals which are converted into `constexpr` objects all of which relies on functionality from `P0732R2`. 39 | 40 | ## Example 41 | 42 | The following example shows usage of all class templates a user is expected to define to use the library. 43 | 44 | ```c++ 45 | #include 46 | #include 47 | 48 | #include "sql.hpp" 49 | 50 | using books = 51 | sql::schema< 52 | "books", sql::index<"title">, 53 | sql::column<"title", std::string>, 54 | sql::column<"genre", std::string>, 55 | sql::column<"year", unsigned>, 56 | sql::column<"pages", unsigned> 57 | >; 58 | 59 | using authored = 60 | sql::schema< 61 | "authored", sql::index<>, 62 | sql::column<"title", std::string>, 63 | sql::column<"name", std::string> 64 | >; 65 | 66 | using query = 67 | sql::query< 68 | "SELECT title AS book, name AS author, year, pages " 69 | "FROM books NATURAL JOIN (SELECT * FROM authored WHERE name = \"Harlan Ellison\") " 70 | "WHERE year = 1967 OR year >= 1972 AND genre = \"science fiction\"", 71 | books, authored 72 | >; 73 | 74 | int main() 75 | { 76 | authored a{ sql::load("tests/data/authored.tsv", '\t') }; 77 | books b{ sql::load("tests/data/books.tsv", '\t') }; 78 | 79 | for (query q{ b, a }; auto const& [book, author, year, pages] : q) 80 | { 81 | std::cout << book << '\t' << author << '\t' << year << '\t' << pages << '\n'; 82 | } 83 | 84 | return 0; 85 | } 86 | ``` 87 | 88 | [`sql::schema`](https://github.com/mkitzan/constexpr-sql/blob/master/include/sql/schema.hpp) defines a relation used in a query. [`sql::index`](https://github.com/mkitzan/constexpr-sql/blob/master/include/sql/index.hpp) defines how an `sql::schema` sorts its data (unsorted if unspecified). [`sql::column`](https://github.com/mkitzan/constexpr-sql/blob/master/include/sql/column.hpp) types are used to define the rows in an `sql::schema`. [`sql::query`](https://github.com/mkitzan/constexpr-sql/blob/master/include/sql/query.hpp) wraps a query statement and the `sql::schema` types the query will operate on. [`sql::load`](https://github.com/mkitzan/constexpr-sql/blob/master/include/sql/schema.hpp#L180) can be used to load data from a file into an `sql::schema`. 89 | 90 | The example is from [`example.cpp`](https://github.com/mkitzan/constexpr-sql/blob/master/example.cpp) in the root of the repository, and can be compiled and executed with the following command: 91 | 92 | ```shell 93 | g++ -std=c++2a -pedantic -Wall -Wextra -Werror -O3 -Isingle-header/ -o example example.cpp && ./example 94 | ``` 95 | 96 | It is strongly recommended to compile with optimizations enabled, otherwise expect template bloat. Use of multiple objects of the same `sql::query` type is considered **undefined behavior** (due to issues involving static members). Instantiating `sql::query` objects should be performed within a guarded scope, like in the example. However, there are no use restrictions to `sql::schema` types. `sql::schema` types may be used multiple times within a single query or in many queries at once. There are more examples and information in [`presentation.pdf`](https://github.com/mkitzan/constexpr-sql/blob/master/presentation.pdf) at the root of the repository. 97 | 98 | ## Correctness and Performance Testing 99 | 100 | The library has a significant testing system which is composed of two script pipelines. All tests use the data from another project of mine called [`Terminus`](https://github.com/mkitzan/terminus) which is a library database shell. The correctness testing pipeline generates nearly 1.5 million test queries, then Constexpr SQL's output is compared against the output of `SQLite3` performing the same queries. The performance testing pipeline executes six different SQL queries implemented using Constexpr SQL and hand coded SQL. The queries are executed over 65 thousand times (256 for `CROSS JOIN` due to computational complexity), and the execution timing is captured using the Linux `time` tool. 101 | 102 | The [`runner.sh`](https://github.com/mkitzan/constexpr-sql/blob/master/tests/runner.sh) script in the `tests` directory will execute correctness testing, and the [`runner.sh`](https://github.com/mkitzan/constexpr-sql/tree/master/tests/perf/runner.sh) script in `tests/perf` will execute performance testing. 103 | 104 | ## Important Class Templates and Implementation Details 105 | 106 | The following sections provide a high-level description about how the library is implemented. Hopefully, the sections will provide useful code and document references to others looking to write similar libraries. 107 | 108 | ### Class Template: `sql::schema` 109 | 110 | The `sql::schema` class template represents relational schemas and, when instantiated, SQL tables. The class template is parameterized on three template parameters: `Name`, `Index`, and `Col` template parameter pack. `Name` defines the SQL table name which is matched against table names in a query's `FROM` statement. The `Index` template argument is used to support `GROUP BY` statements by using [**SFINAE**](https://en.cppreference.com/w/cpp/language/sfinae) to select the [underlying column data container](https://github.com/mkitzan/constexpr-sql/blob/master/include/sql/schema.hpp#L25) (`std::vector` or `std::multiset`). The `Index` template argument, when fully specified, provides the [comparator functor](https://github.com/mkitzan/constexpr-sql/blob/master/include/sql/index.hpp#L15) used by the `std::multiset` container. The `Cols` template parameter pack is expanded into the `sql::row` type for the schema. `sql::schema` objects support [**structured binding declarations**](https://en.cppreference.com/w/cpp/language/structured_binding) which is facilitated partly through the `sql::schema` API and partly through [`std` namespace injections from `sql::row`](https://github.com/mkitzan/constexpr-sql/blob/master/include/sql/row.hpp#L131) helping to satisfy the [argument dependant lookup](https://en.cppreference.com/w/cpp/language/adl) of the [`get` function](https://github.com/mkitzan/constexpr-sql/blob/master/include/sql/row.hpp#L97). 111 | 112 | Reference the example [earlier](https://github.com/mkitzan/constexpr-sql#example) for proper usage of `sql::schema`. Notice in the example the string literal as a template argument. String literals are lvalue reference types which are passed as `const` pointers. Normally, pointers can not be used as template arguments. With the new C++20 feature mentioned [earlier](https://github.com/mkitzan/constexpr-sql#library-features-and-compiler-support), a [`cexpr::string`](https://github.com/mkitzan/constexpr-sql/blob/master/include/cexpr/string.hpp) constructor template can be [deduced](https://en.cppreference.com/w/cpp/language/class_template_argument_deduction) to turn the string literal into a `constexpr` object. The deduction is enabled through [`cexpr::string`'s class template argument deduction guide](https://github.com/mkitzan/constexpr-sql/blob/master/include/cexpr/string.hpp#L144) which provides a mapping of constructor arguments to template parameters. 113 | 114 | ### Class Template: `sql::query` 115 | 116 | The [`sql::query`](https://github.com/mkitzan/constexpr-sql/blob/master/include/sql/query.hpp) class template is the user interface to the SQL query parser. The class is templated on a `cexpr::string` object (the SQL query) and a template parameter pack of `sql::schema` types. At compile time, the SQL query string is parsed into the relational algebra expression tree representing the query's computation. The constructor to a fully specified `sql::query` class takes a variadic pack of `sql::schema` objects which it uses to seed the relational algebra expression tree with iterators to data. The `sql::query` object can then be used in a range loop with structured binding declarations like in the example. 117 | 118 | The relational algebra expression tree uses static members to hold data, so only one object of a single fully specified `sql::query` class can exist at once in the program. To ensure this the object should be constructed within a guarded scope like in the example. It's worth noting that even though this class template's source file is the largest among the code base, nearly all of it is only live during compilation to parse the SQL query. In fact, the [runtime interface](https://github.com/mkitzan/constexpr-sql/blob/master/include/sql/query.hpp#L666) is deliberately insubstantial, merely providing an wrapper to support range loops and structured binding declarations. 119 | 120 | In compliance with range loop syntax, `sql::query` has an associated iterator class [`sql::query_iterator`](https://github.com/mkitzan/constexpr-sql/blob/master/include/sql/query.hpp#L189). `sql::query_iterator` wraps the type representing the relational algebra expression and handles all of the idiosyncrasies of its usage in favor of the familiar [`forward iterator`](https://en.cppreference.com/w/cpp/named_req/ForwardIterator) interface. When an [`sql::query_iterator` is dereferenced](https://github.com/mkitzan/constexpr-sql/blob/master/include/sql/query.hpp#L211), it returns a constant reference to an `sql::row` object representing the current row of output from the query stream. 121 | 122 | ### Class Template: `sql::row` 123 | 124 | The [`sql::row`](https://github.com/mkitzan/constexpr-sql/blob/master/include/sql/row.hpp) class template is a template recursive linked-list (similar to [`std::tuple`](https://en.cppreference.com/w/cpp/utility/tuple)). A template recursive linked-list is a template metaprogramming pattern which expresses a type analogous to a traditional linked-list. `sql::row` implements this pattern with two template parameters `Col` and `Next`. `Col` represents the [`sql::column`](https://github.com/mkitzan/constexpr-sql/blob/master/include/sql/column.hpp) which the node in list holds a data element from. `Next` represents the type of the next node in the list, which is either another `sql::row` type or [`sql::void_row`](https://github.com/mkitzan/constexpr-sql/blob/master/include/sql/row.hpp#L12). Because the next node is expressed as a type the template linked-list does not incur the overhead of holding a next pointer nor the run time cost of dereferencing a pointer to iterate (also makes better use of the cache). A quirk to this pattern is that the node data type need not be homogenous across the list, instead the list may be composed of heterogenous data types. Also, template linked-list access is computed at compile time, so the run time cost is constant. 125 | 126 | The example does not demonstrate the [`sql::get`](https://github.com/mkitzan/constexpr-sql/blob/master/include/sql/row.hpp#L81) helper function. This helper function allows the user to query a specific element from an `sql::row` object by column name. Additionally, `sql::row` has [**ML**-like](https://github.com/mkitzan/constexpr-sql/blob/master/include/sql/row.hpp#L81) functions for getting the `head` and `tail` of the object. 127 | 128 | ### Relational Algebra Expression Nodes 129 | 130 | At the moment, [`ra::projection`](https://github.com/mkitzan/constexpr-sql/blob/master/include/ra/projection.hpp), [`ra::rename`](https://github.com/mkitzan/constexpr-sql/blob/master/include/ra/rename.hpp), [`ra::cross`](https://github.com/mkitzan/constexpr-sql/blob/master/include/ra/cross.hpp), [`ra::natural`](https://github.com/mkitzan/constexpr-sql/blob/master/include/ra/natural.hpp), [`ra::selection`](https://github.com/mkitzan/constexpr-sql/blob/master/include/ra/selection.hpp), and [`ra::relation`](https://github.com/mkitzan/constexpr-sql/blob/master/include/ra/relation.hpp) are the only relational algebra nodes implemented. `ra::projection` and `ra::rename` are unary operators which take a single `sql::row` from their `Input` relational algebra operator and fold their operation over the row before propagating the transformed row to their `Output`. The `fold` is implemented as a template recursive function. `ra::cross` outputs the cross product of two relations. `ra::natural` implements a natural join between two relations using a hash table buffer of the right relation for performance. `ra::selection` uses a predicate function constructed from a `WHERE` clause to filter rows in a query. `ra::relation` is the only terminal node in the expression tree which is used for retrieving the next input in the stream. These operators are composable types and are used to serialize the relational algebra expression tree. Individual objects of each type are not instantiated to compose the expression tree. Instead to ensure the expression tree is a zero overhead abstraction, the types implement a `static` member function `next` used to request data from its input type. The actual `constexpr` template recursive recursive descent SQL parser will serialize these individual nodes together into the appropriate expression tree. 131 | 132 | ### Constexpr Parsing 133 | 134 | As a proof of concept for `constexpr` parsing, two math expression parsers were implemented in old repository: [`cexpr::prefix`](https://github.com/mkitzan/metaprogramming-optimization/blob/master/include/cexpr/prefix.hpp) and [`cexpr::infix`](https://github.com/mkitzan/metaprogramming-optimization/blob/master/include/cexpr/infix.hpp). `cexpr::prefix` demonstrates the fundamental method of `constexpr` parsing an expression tree into a class template. `cexpr::infix` extends this to perform `constepxr` recursive descent parsing. `cexpr::infix` and the SQL query parser are a whole order of magnitude more complex, because there's recursive function template instantiations to many different function templates. The explanation of `constexpr` parsing is illustrated through `cexpr::prefix` for simplicity. 135 | 136 | The expression tree created while parsing is a template recursive tree which shares similar properties to the template linked-list (discussed [earlier](https://github.com/mkitzan/constexpr-sql#class-template-sqlrow)). A notable benefit to this data structure is that because the tree is composed of types rather than data values, the tree can be used to express computation models (expression trees) rather than just a tree based container. 137 | 138 | Fundamentally, the parsing is accomplished by calling a template recursive `static constexpr` parsing function member parameterized on the token position which the parser's "cursor" is standing on ([`Pos`](https://github.com/mkitzan/metaprogramming-optimization/blob/master/include/cexpr/prefix.hpp#L39) template parameter). At each "cursor" position, the function uses the token to decide the how to proceed. If the token indicates the start of an operation, the parser recurses the immediate left subexpression ("cursor" + 1). On return, the left subexpression will report the depth in the token stream it recursed at which point the right subexpression will pick up at this position. This control flow is expressed in [this line](https://github.com/mkitzan/metaprogramming-optimization/blob/master/include/cexpr/prefix.hpp#L47) of [`cexpr::prefix::parse`](https://github.com/mkitzan/metaprogramming-optimization/blob/master/include/cexpr/prefix.hpp#L40). Once both left and right subexpressions are parsed, the new node's type is formed ([`decltype`](https://en.cppreference.com/w/cpp/language/decltype) left and right subexpressions) which is then propagated to the caller. Otherwise, if the token indicates a terminal, then an appropriate terminal node is constructed. It is necessary that the "cursor" position is unique across template instantiations, otherwise template memoization will lead to "infinite" recursion. 139 | 140 | The few ancillary class templates used to support this parsing and the math node `struct` templates can be found in the [`templ` namespace](https://github.com/mkitzan/metaprogramming-optimization/tree/master/include/templ) of the old repository. There is also a [driver program](https://github.com/mkitzan/metaprogramming-optimization/blob/master/resources/parser/equation.cpp) using the parsers in the old repository. In the Constexpr SQL parser, all of the entities in the `templ` namespace were replaced for more template metaprogramming idiomatic structures. 141 | -------------------------------------------------------------------------------- /example.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include "sql.hpp" 5 | 6 | using books = 7 | sql::schema< 8 | "books", sql::index<"title">, 9 | sql::column<"title", std::string>, 10 | sql::column<"genre", std::string>, 11 | sql::column<"year", unsigned>, 12 | sql::column<"pages", unsigned> 13 | >; 14 | 15 | using authored = 16 | sql::schema< 17 | "authored", sql::index<>, 18 | sql::column<"title", std::string>, 19 | sql::column<"name", std::string> 20 | >; 21 | 22 | using query = 23 | sql::query< 24 | "SELECT title AS book, name AS author, year, pages " 25 | "FROM books NATURAL JOIN (SELECT * FROM authored WHERE name = \"Harlan Ellison\") " 26 | "WHERE year = 1967 OR year >= 1972 AND genre = \"science fiction\"", 27 | books, authored 28 | >; 29 | 30 | int main() 31 | { 32 | authored a{ sql::load("tests/data/authored.tsv", '\t') }; 33 | books b{ sql::load("tests/data/books.tsv", '\t') }; 34 | 35 | for (query q{ b, a }; auto const& [book, author, year, pages] : q) 36 | { 37 | std::cout << book << '\t' << author << '\t' << year << '\t' << pages << '\n'; 38 | } 39 | 40 | return 0; 41 | } 42 | -------------------------------------------------------------------------------- /generator.py: -------------------------------------------------------------------------------- 1 | import os 2 | 3 | def include(header, incs, root, included): 4 | file = open("include/" + root, "r") 5 | 6 | for line in file: 7 | if line == "#pragma once\n" or line == "\n": 8 | pass 9 | elif line[:10] == "#include \"": 10 | if not line in included: 11 | included += [line] 12 | include(header, incs, line[10:-2], included) 13 | elif line[:10] == "#include <": 14 | incs += [line] 15 | else: 16 | header.write(line) 17 | break 18 | 19 | for line in file: 20 | header.write(line) 21 | header.write("\n") 22 | 23 | return included, incs 24 | 25 | def main(): 26 | header = open("temp", "w") 27 | included, incs = include(header, [], "sql/schema.hpp", []) 28 | included, incs = include(header, incs, "sql/query.hpp", included) 29 | header.close() 30 | header = open("single-header/sql.hpp", "w") 31 | header.write("#pragma once\n\n") 32 | 33 | for line in sorted(set(incs)): 34 | header.write(line) 35 | header.write("\n") 36 | 37 | for line in open("temp"): 38 | header.write(line) 39 | 40 | os.remove("temp") 41 | 42 | if __name__ == "__main__": 43 | main() 44 | -------------------------------------------------------------------------------- /include/cexpr/string.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | namespace cexpr 8 | { 9 | 10 | template 11 | class string 12 | { 13 | public: 14 | using char_type = Char; 15 | 16 | constexpr string() noexcept : size_{ 0 }, string_{ 0 } 17 | {} 18 | 19 | constexpr string(const Char(&s)[N]) noexcept : string{} 20 | { 21 | for(; s[size_]; ++size_) 22 | { 23 | string_[size_] = s[size_]; 24 | } 25 | } 26 | 27 | constexpr string(cexpr::string const& s) noexcept : string{} 28 | { 29 | for (; s[size_]; ++size_) 30 | { 31 | string_[size_] = s[size_]; 32 | } 33 | } 34 | 35 | constexpr string(std::basic_string_view const& s) noexcept : string{} 36 | { 37 | if (s.length() < N) 38 | { 39 | for (; size_ < s.length(); ++size_) 40 | { 41 | string_[size_] = s[size_]; 42 | } 43 | } 44 | } 45 | 46 | constexpr void fill(const Char* begin, const Char* end) noexcept 47 | { 48 | fill_from(begin, end, begin()); 49 | } 50 | 51 | constexpr void fill_from(const Char* begin, const Char* end, Char* start) noexcept 52 | { 53 | if (end - begin < N) 54 | { 55 | for (auto curr{ start }; begin != end; ++begin, ++curr) 56 | { 57 | *curr = *begin; 58 | } 59 | } 60 | } 61 | 62 | inline constexpr std::size_t capacity() const noexcept 63 | { 64 | return N - 1; 65 | } 66 | 67 | inline constexpr std::size_t size() const noexcept 68 | { 69 | return size_; 70 | } 71 | 72 | inline constexpr Char* begin() noexcept 73 | { 74 | return string_; 75 | } 76 | inline constexpr const Char* cbegin() const noexcept 77 | { 78 | return string_; 79 | } 80 | 81 | inline constexpr Char* end() noexcept 82 | { 83 | return &string_[size_]; 84 | } 85 | inline constexpr const Char* cend() const noexcept 86 | { 87 | return &string_[size_]; 88 | } 89 | 90 | inline constexpr Char& operator[](std::size_t i) 91 | { 92 | return string_[i]; 93 | } 94 | inline constexpr Char const& operator[](std::size_t i) const 95 | { 96 | return string_[i]; 97 | } 98 | 99 | template 100 | constexpr bool operator==(string const& other) const noexcept 101 | { 102 | if constexpr (N != OtherN) 103 | { 104 | return false; 105 | } 106 | 107 | std::size_t i{}; 108 | for (; i < N && string_[i] == other[i]; ++i); 109 | 110 | return i == N; 111 | } 112 | 113 | template 114 | constexpr bool operator==(const OtherChar(&other)[OtherN]) const noexcept 115 | { 116 | if constexpr (N != OtherN) 117 | { 118 | return false; 119 | } 120 | 121 | std::size_t i{}; 122 | for (; i < N && string_[i] == other[i]; ++i); 123 | 124 | return i == N; 125 | } 126 | 127 | template 128 | inline bool operator==(std::basic_string const& other) const noexcept 129 | { 130 | return other == string_; 131 | } 132 | 133 | template 134 | inline bool operator!=(std::basic_string const& other) const noexcept 135 | { 136 | return !(other == string_); 137 | } 138 | 139 | private: 140 | std::size_t size_; 141 | Char string_[N]; 142 | }; 143 | 144 | template 145 | string(const Char[N]) -> string; 146 | 147 | template 148 | inline bool operator==(std::basic_string const& str, string const& cstr) noexcept 149 | { 150 | return cstr == str; 151 | } 152 | 153 | template 154 | inline bool operator!=(std::basic_string const& str, string const& cstr) noexcept 155 | { 156 | return cstr != str; 157 | } 158 | 159 | } // namespace cexpr 160 | -------------------------------------------------------------------------------- /include/ra/cross.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "ra/join.hpp" 4 | #include "ra/relation.hpp" 5 | 6 | namespace ra 7 | { 8 | 9 | template 10 | class cross : public ra::join 11 | { 12 | using join_type = ra::join; 13 | public: 14 | using output_type = join_type::output_type; 15 | 16 | static auto&& next() 17 | { 18 | try 19 | { 20 | copy(join_type::output_row, RightInput::next()); 21 | } 22 | catch(ra::data_end const& e) 23 | { 24 | copy(join_type::output_row, LeftInput::next()); 25 | RightInput::reset(); 26 | copy(join_type::output_row, RightInput::next()); 27 | } 28 | 29 | return std::move(join_type::output_row); 30 | } 31 | }; 32 | 33 | } // namespace ra 34 | -------------------------------------------------------------------------------- /include/ra/join.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include "ra/operation.hpp" 6 | 7 | #include "sql/row.hpp" 8 | 9 | namespace ra 10 | { 11 | 12 | namespace 13 | { 14 | 15 | template 16 | constexpr auto recr_merge() 17 | { 18 | if constexpr (std::is_same_v) 19 | { 20 | return Right{}; 21 | } 22 | else 23 | { 24 | using next = decltype(recr_merge()); 25 | 26 | return sql::row{}; 27 | } 28 | } 29 | 30 | template 31 | inline constexpr auto merge() 32 | { 33 | if constexpr (Left::column::name == Right::column::name) 34 | { 35 | return recr_merge(); 36 | } 37 | else 38 | { 39 | return recr_merge(); 40 | } 41 | } 42 | 43 | template 44 | constexpr void recr_copy(Dest& dest, Row const& src) 45 | { 46 | if constexpr (std::is_same_v) 47 | { 48 | return; 49 | } 50 | else 51 | { 52 | dest.head() = src.head(); 53 | recr_copy(dest.tail(), src.tail()); 54 | } 55 | } 56 | 57 | template 58 | inline constexpr void copy(Dest& dest, Row const& src) 59 | { 60 | if constexpr (Dest::column::name == Row::column::name) 61 | { 62 | recr_copy(dest, src); 63 | } 64 | else 65 | { 66 | copy(dest.tail(), src); 67 | } 68 | } 69 | 70 | } // namespace 71 | 72 | template 73 | class join : public ra::binary 74 | { 75 | using binary_type = ra::binary; 76 | using left_type = typename binary_type::left_type; 77 | using right_type = typename binary_type::right_type; 78 | public: 79 | using output_type = decltype(merge()); 80 | 81 | template 82 | static inline void seed(Inputs const&... rs) 83 | { 84 | binary_type::seed(rs...); 85 | copy(output_row, LeftInput::next()); 86 | } 87 | 88 | static inline void reset() 89 | { 90 | binary_type::reset(); 91 | copy(output_row, LeftInput::next()); 92 | } 93 | 94 | static output_type output_row; 95 | }; 96 | 97 | template 98 | typename join::output_type join::output_row{}; 99 | 100 | } // namespace ra 101 | -------------------------------------------------------------------------------- /include/ra/natural.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | #include "ra/join.hpp" 8 | #include "ra/relation.hpp" 9 | 10 | namespace ra 11 | { 12 | 13 | template 14 | class natural : public ra::join 15 | { 16 | using join_type = ra::join; 17 | using key_type = std::remove_cvref_t; 18 | using value_type = std::vector>; 19 | using map_type = std::unordered_map; 20 | public: 21 | using output_type = join_type::output_type; 22 | 23 | template 24 | static void seed(Inputs const&... rs) 25 | { 26 | join_type::seed(rs...); 27 | 28 | if (row_cache.empty()) 29 | { 30 | try 31 | { 32 | for (;;) 33 | { 34 | auto const& row{ RightInput::next() }; 35 | row_cache[row.head()].push_back(row.tail()); 36 | } 37 | } 38 | catch(ra::data_end const& e) 39 | { 40 | RightInput::reset(); 41 | } 42 | } 43 | 44 | auto const& active{ row_cache[join_type::output_row.head()] }; 45 | curr = active.cbegin(); 46 | end = active.cend(); 47 | } 48 | 49 | static auto&& next() 50 | { 51 | while (curr == end) 52 | { 53 | copy(join_type::output_row, LeftInput::next()); 54 | auto const& active{ row_cache[join_type::output_row.head()] }; 55 | curr = active.cbegin(); 56 | end = active.cend(); 57 | } 58 | 59 | copy(join_type::output_row, *curr++); 60 | 61 | return std::move(join_type::output_row); 62 | } 63 | 64 | private: 65 | static map_type row_cache; 66 | static value_type::const_iterator curr; 67 | static value_type::const_iterator end; 68 | }; 69 | 70 | template 71 | typename natural::map_type natural::row_cache{}; 72 | 73 | template 74 | typename natural::value_type::const_iterator natural::curr; 75 | 76 | template 77 | typename natural::value_type::const_iterator natural::end; 78 | 79 | } // namespace ra 80 | -------------------------------------------------------------------------------- /include/ra/operation.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | namespace ra 6 | { 7 | 8 | template 9 | class unary 10 | { 11 | public: 12 | using input_type = std::remove_cvref_t; 13 | 14 | template 15 | static inline void seed(Inputs const&... rs) 16 | { 17 | Input::seed(rs...); 18 | } 19 | 20 | static inline void reset() 21 | { 22 | Input::reset(); 23 | } 24 | }; 25 | 26 | template 27 | class binary 28 | { 29 | public: 30 | using left_type = std::remove_cvref_t; 31 | using right_type = std::remove_cvref_t; 32 | 33 | template 34 | static inline void seed(Inputs const&... rs) 35 | { 36 | LeftInput::seed(rs...); 37 | RightInput::seed(rs...); 38 | } 39 | 40 | static inline void reset() 41 | { 42 | LeftInput::reset(); 43 | RightInput::reset(); 44 | } 45 | }; 46 | 47 | } // namespace ra 48 | -------------------------------------------------------------------------------- /include/ra/projection.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "ra/operation.hpp" 4 | 5 | #include "sql/row.hpp" 6 | 7 | namespace ra 8 | { 9 | 10 | template 11 | class projection : public ra::unary 12 | { 13 | using input_type = typename ra::unary::input_type; 14 | public: 15 | using output_type = Output; 16 | 17 | static auto&& next() 18 | { 19 | fold(output_row, Input::next()); 20 | 21 | return std::move(output_row); 22 | } 23 | 24 | private: 25 | template 26 | static inline constexpr void fold(Dest& dest, input_type const& src) 27 | { 28 | if constexpr (Dest::depth == 0) 29 | { 30 | return; 31 | } 32 | else 33 | { 34 | dest.head() = sql::get(src); 35 | fold(dest.tail(), src); 36 | } 37 | } 38 | 39 | static output_type output_row; 40 | }; 41 | 42 | template 43 | typename projection::output_type projection::output_row{}; 44 | 45 | } // namespace ra 46 | -------------------------------------------------------------------------------- /include/ra/relation.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | namespace ra 7 | { 8 | 9 | struct data_end : std::exception 10 | {}; 11 | 12 | // Id template parameter allows unique ra::relation types to be instantiated from 13 | // a single sql::schema type (for queries referencing a schema multiple times). 14 | template 15 | class relation 16 | { 17 | public: 18 | using output_type = Schema::row_type&; 19 | 20 | static auto& next() 21 | { 22 | if (curr != end) 23 | { 24 | return *curr++; 25 | } 26 | else 27 | { 28 | throw ra::data_end{}; 29 | } 30 | } 31 | 32 | template 33 | static void seed(Input const& r, Inputs const&... rs) noexcept 34 | { 35 | if constexpr (std::is_same_v) 36 | { 37 | curr = r.begin(); 38 | begin = r.begin(); 39 | end = r.end(); 40 | } 41 | else 42 | { 43 | seed(rs...); 44 | } 45 | } 46 | 47 | static inline void reset() noexcept 48 | { 49 | curr = begin; 50 | } 51 | 52 | private: 53 | static Schema::const_iterator curr; 54 | static Schema::const_iterator begin; 55 | static Schema::const_iterator end; 56 | }; 57 | 58 | template 59 | Schema::const_iterator relation::curr{}; 60 | 61 | template 62 | Schema::const_iterator relation::begin{}; 63 | 64 | template 65 | Schema::const_iterator relation::end{}; 66 | 67 | } // namespace ra 68 | -------------------------------------------------------------------------------- /include/ra/rename.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "ra/operation.hpp" 4 | 5 | #include "sql/row.hpp" 6 | 7 | namespace ra 8 | { 9 | 10 | template 11 | class rename : public ra::unary 12 | { 13 | using input_type = typename ra::unary::input_type; 14 | public: 15 | using output_type = Output; 16 | 17 | static auto&& next() 18 | { 19 | fold(output_row, Input::next()); 20 | 21 | return std::move(output_row); 22 | } 23 | 24 | private: 25 | template 26 | static inline constexpr void fold(Dest& dest, Src const& src) 27 | { 28 | if constexpr (Dest::depth == 0) 29 | { 30 | return; 31 | } 32 | else 33 | { 34 | dest.head() = src.head(); 35 | fold(dest.tail(), src.tail()); 36 | } 37 | } 38 | 39 | static output_type output_row; 40 | }; 41 | 42 | template 43 | typename rename::output_type rename::output_row{}; 44 | 45 | } // namespace ra 46 | -------------------------------------------------------------------------------- /include/ra/selection.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "ra/operation.hpp" 4 | 5 | namespace ra 6 | { 7 | 8 | template 9 | class selection : public ra::unary 10 | { 11 | using input_type = typename ra::unary::input_type; 12 | public: 13 | using output_type = input_type; 14 | 15 | static auto&& next() 16 | { 17 | output_row = Input::next(); 18 | 19 | while(!Predicate::eval(output_row)) 20 | { 21 | output_row = Input::next(); 22 | } 23 | 24 | return std::move(output_row); 25 | } 26 | 27 | private: 28 | static output_type output_row; 29 | }; 30 | 31 | template 32 | typename selection::output_type selection::output_row{}; 33 | 34 | } // namespace ra 35 | -------------------------------------------------------------------------------- /include/sql/column.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "cexpr/string.hpp" 4 | 5 | namespace sql 6 | { 7 | 8 | template 9 | struct column 10 | { 11 | static constexpr auto name{ Name }; 12 | 13 | using type = Type; 14 | }; 15 | 16 | } // namespace sql 17 | -------------------------------------------------------------------------------- /include/sql/index.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include "cexpr/string.hpp" 6 | 7 | #include "sql/row.hpp" 8 | 9 | namespace sql 10 | { 11 | 12 | template 13 | struct index 14 | { 15 | template 16 | struct comparator 17 | { 18 | bool operator()(Row const& left, Row const& right) const noexcept 19 | { 20 | return compare(left, right); 21 | } 22 | 23 | private: 24 | template 25 | bool compare(Row const& left, Row const& right) const noexcept 26 | { 27 | auto const& l{ sql::get(left) }; 28 | auto const& r{ sql::get(right) }; 29 | 30 | if constexpr (sizeof...(Cols) != 0) 31 | { 32 | if (l == r) 33 | { 34 | return compare(left, right); 35 | } 36 | } 37 | 38 | return l < r; 39 | } 40 | }; 41 | }; 42 | 43 | } // namespace sql 44 | -------------------------------------------------------------------------------- /include/sql/predicate.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include "cexpr/string.hpp" 6 | 7 | namespace sql 8 | { 9 | 10 | namespace 11 | { 12 | 13 | // shim to allow all value types like double or float to be used as non-type template parameters. 14 | template 15 | struct value 16 | { 17 | constexpr value(Type v) : val{ v } 18 | {} 19 | 20 | Type val; 21 | }; 22 | 23 | } // namespace 24 | 25 | template 26 | struct operation 27 | { 28 | static constexpr bool eval(Row const& row) noexcept 29 | { 30 | if constexpr (Op == "=") 31 | { 32 | return Left::eval(row) == Right::eval(row); 33 | } 34 | else if constexpr (Op == ">") 35 | { 36 | return Left::eval(row) > Right::eval(row); 37 | } 38 | else if constexpr(Op == "<") 39 | { 40 | return Left::eval(row) < Right::eval(row); 41 | } 42 | else if constexpr(Op == ">=") 43 | { 44 | return Left::eval(row) >= Right::eval(row); 45 | } 46 | else if constexpr(Op == "<=") 47 | { 48 | return Left::eval(row) <= Right::eval(row); 49 | } 50 | else if constexpr(Op == "!=" || Op == "<>") 51 | { 52 | return Left::eval(row) != Right::eval(row); 53 | } 54 | else if constexpr(Op == "AND") 55 | { 56 | return Left::eval(row) && Right::eval(row); 57 | } 58 | else if constexpr(Op == "OR") 59 | { 60 | return Left::eval(row) || Right::eval(row); 61 | } 62 | else if constexpr(Op == "NOT") 63 | { 64 | return !Left::eval(row); 65 | } 66 | } 67 | }; 68 | 69 | template 70 | struct variable 71 | { 72 | static constexpr auto eval(Row const& row) noexcept 73 | { 74 | return sql::get(row); 75 | } 76 | }; 77 | 78 | template 79 | struct constant 80 | { 81 | static constexpr auto eval([[maybe_unused]] Row const& row) noexcept 82 | { 83 | return Const.val; 84 | } 85 | }; 86 | 87 | } // namespace sql 88 | -------------------------------------------------------------------------------- /include/sql/query.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | #include "cexpr/string.hpp" 9 | 10 | #include "ra/cross.hpp" 11 | #include "ra/join.hpp" 12 | #include "ra/natural.hpp" 13 | #include "ra/projection.hpp" 14 | #include "ra/relation.hpp" 15 | #include "ra/rename.hpp" 16 | #include "ra/selection.hpp" 17 | 18 | #include "sql/column.hpp" 19 | #include "sql/tokens.hpp" 20 | #include "sql/predicate.hpp" 21 | #include "sql/row.hpp" 22 | 23 | namespace sql 24 | { 25 | 26 | // anonymous namespace to hold helper data structures and functions 27 | namespace 28 | { 29 | 30 | template 31 | struct context 32 | { 33 | using node = Node; 34 | static constexpr std::size_t pos = Pos; 35 | }; 36 | 37 | template 38 | struct colinfo 39 | { 40 | using type = Type; 41 | static constexpr std::size_t name = Name; 42 | static constexpr std::size_t next = Next; 43 | }; 44 | 45 | template 46 | constexpr bool exists() noexcept 47 | { 48 | if constexpr (std::is_same_v) 49 | { 50 | return false; 51 | } 52 | else 53 | { 54 | if constexpr (Row::column::name == Name) 55 | { 56 | return true; 57 | } 58 | else 59 | { 60 | return exists(); 61 | } 62 | } 63 | } 64 | 65 | template 66 | constexpr value convert(cexpr::string const& str) noexcept 67 | { 68 | auto curr{ str.cbegin() }, end{ str.cend() }; 69 | constexpr Char dot{ '.' }, zro{ '0' }, min{ '-' }; 70 | Type acc{}, sign{ 1 }, scalar{ 10 }; 71 | 72 | if (*curr == min) 73 | { 74 | sign = -1; 75 | ++curr; 76 | } 77 | 78 | while (curr != end && *curr != dot) 79 | { 80 | acc = (acc * scalar) + (*curr - zro); 81 | ++curr; 82 | } 83 | 84 | if (curr != end && *curr == dot) 85 | { 86 | scalar = 1; 87 | ++curr; 88 | 89 | while(curr != end) 90 | { 91 | acc += (*curr - zro) * (scalar /= Type{ 10 }); 92 | ++curr; 93 | } 94 | } 95 | 96 | return value{ acc * sign }; 97 | } 98 | 99 | inline constexpr bool isquote(std::string_view const& tv) noexcept 100 | { 101 | return tv == "\"" || tv == "'"; 102 | } 103 | 104 | inline constexpr bool isor(std::string_view const& tv) noexcept 105 | { 106 | return tv == "OR" || tv == "or"; 107 | } 108 | 109 | inline constexpr bool isand(std::string_view const& tv) noexcept 110 | { 111 | return tv == "AND" || tv == "and"; 112 | } 113 | 114 | inline constexpr bool isnot(std::string_view const& tv) noexcept 115 | { 116 | return tv == "NOT" || tv == "not"; 117 | } 118 | 119 | inline constexpr bool isnatural(std::string_view const& tv) noexcept 120 | { 121 | return tv == "NATURAL" || tv == "natural"; 122 | } 123 | 124 | inline constexpr bool isjoin(std::string_view const& tv) noexcept 125 | { 126 | return tv == "JOIN" || tv == "join"; 127 | } 128 | 129 | inline constexpr bool iswhere(std::string_view const& tv) noexcept 130 | { 131 | return tv == "WHERE" || tv == "where"; 132 | } 133 | 134 | inline constexpr bool isfrom(std::string_view const& tv) noexcept 135 | { 136 | return tv == "FROM" || tv == "from"; 137 | } 138 | 139 | inline constexpr bool isas(std::string_view const& tv) noexcept 140 | { 141 | return tv == "AS" || tv == "as"; 142 | } 143 | 144 | inline constexpr bool isselect(std::string_view const& tv) noexcept 145 | { 146 | return tv == "SELECT" || tv == "select"; 147 | } 148 | 149 | inline constexpr bool iscomma(std::string_view const& tv) noexcept 150 | { 151 | return tv == ","; 152 | } 153 | 154 | constexpr bool isintegral(std::string_view const& tv) noexcept 155 | { 156 | bool result{ false }; 157 | 158 | for (auto c : tv) 159 | { 160 | result |= (c == '.'); 161 | } 162 | 163 | return !result; 164 | } 165 | 166 | constexpr bool isdigit(char c) noexcept 167 | { 168 | return (c >= '0' && c <= '9') || c == '-' || c == '.'; 169 | } 170 | 171 | constexpr bool iscomp(char c) noexcept 172 | { 173 | return c == '=' || c == '!' || c == '<' || c == '>'; 174 | } 175 | 176 | constexpr bool iscolumn(std::string_view const& tv) noexcept 177 | { 178 | return !iscomma(tv) && !isas(tv) && !isfrom(tv); 179 | } 180 | 181 | constexpr bool isseparator(std::string_view const& tv) noexcept 182 | { 183 | return iscomma(tv) || isfrom(tv); 184 | } 185 | 186 | } // namespace 187 | 188 | // structured binding compliant iterator for query objects 189 | template 190 | class query_iterator 191 | { 192 | public: 193 | using row_type = std::remove_cvref_t; 194 | 195 | // seeds row datamember for first dereference 196 | query_iterator(bool end) : end_{ end }, row_{} 197 | { 198 | operator++(); 199 | } 200 | 201 | inline bool operator==(query_iterator const& it) const noexcept 202 | { 203 | return end_ == it.end_; 204 | } 205 | 206 | inline bool operator!=(query_iterator const& it) const noexcept 207 | { 208 | return !(*this == it); 209 | } 210 | 211 | inline row_type const& operator*() const noexcept 212 | { 213 | return row_; 214 | } 215 | 216 | query_iterator& operator++() 217 | { 218 | if (!end_) 219 | { 220 | try 221 | { 222 | row_ = Expr::next(); 223 | } 224 | catch (ra::data_end const& e) 225 | { 226 | end_ = true; 227 | } 228 | } 229 | 230 | return *this; 231 | } 232 | 233 | private: 234 | bool end_{}; 235 | row_type row_{}; 236 | }; 237 | 238 | template 239 | class query 240 | { 241 | private: 242 | // where predicate terminal parsing 243 | template 244 | static constexpr auto parse_terms() 245 | { 246 | if constexpr (tokens_[Pos] == "(") 247 | { 248 | constexpr auto next{ parse_or() }; 249 | 250 | using node = typename decltype(next)::node; 251 | 252 | static_assert(tokens_[next.pos] == ")", "No closing paranthesis found."); 253 | 254 | return context{}; 255 | } 256 | else if constexpr (isquote(tokens_[Pos])) 257 | { 258 | constexpr cexpr::string name{ tokens_[Pos + 1] }; 259 | 260 | using str = decltype(name); 261 | using node = sql::constant{ name }, Row>; 262 | 263 | static_assert(isquote(tokens_[Pos + 2]), "No closing quote found."); 264 | 265 | return context{}; 266 | } 267 | else if constexpr (isdigit(tokens_[Pos][0])) 268 | { 269 | constexpr cexpr::string name{ tokens_[Pos] }; 270 | 271 | using val = decltype(isintegral(tokens_[Pos]) ? std::int64_t{} : double{}); 272 | using node = sql::constant(name), Row>; 273 | 274 | return context{}; 275 | } 276 | else 277 | { 278 | constexpr cexpr::string name{ tokens_[Pos] }; 279 | 280 | using node = sql::variable; 281 | 282 | return context{}; 283 | } 284 | } 285 | 286 | // parses a single compare operation 287 | template 288 | static constexpr auto recurse_comparison() 289 | { 290 | if constexpr (!iscomp(tokens_[Left::pos][0])) 291 | { 292 | return Left{}; 293 | } 294 | else 295 | { 296 | constexpr auto next{ parse_terms() }; 297 | constexpr cexpr::string name{ tokens_[Left::pos] }; 298 | 299 | using ranode = typename decltype(next)::node; 300 | using node = sql::operation; 301 | 302 | return context{}; 303 | } 304 | } 305 | 306 | // descend further and attempt to parse a compare operation 307 | template 308 | static constexpr auto parse_comparison() 309 | { 310 | using left = decltype(parse_terms()); 311 | 312 | return recurse_comparison(); 313 | } 314 | 315 | // attempt to parse a negation operation then descend further 316 | template 317 | static constexpr auto parse_negation() 318 | { 319 | if constexpr (isnot(tokens_[Pos])) 320 | { 321 | constexpr auto next{ parse_comparison() }; 322 | 323 | using ranode = typename decltype(next)::node; 324 | using node = sql::operation<"NOT", Row, ranode>; 325 | 326 | return context{}; 327 | } 328 | else 329 | { 330 | return parse_comparison(); 331 | } 332 | } 333 | 334 | // recursively parse chained AND operations 335 | template 336 | static constexpr auto recurse_and() 337 | { 338 | if constexpr (!isand(tokens_[Left::pos])) 339 | { 340 | return Left{}; 341 | } 342 | else 343 | { 344 | constexpr auto next{ parse_negation() }; 345 | 346 | using ranode = typename decltype(next)::node; 347 | using node = sql::operation<"AND", Row, typename Left::node, ranode>; 348 | 349 | return recurse_and, Row>(); 350 | } 351 | } 352 | 353 | // descend further then attempt to parse AND operations 354 | template 355 | static constexpr auto parse_and() 356 | { 357 | using left = decltype(parse_negation()); 358 | 359 | return recurse_and(); 360 | } 361 | 362 | // recursively parse chained OR operations 363 | template 364 | static constexpr auto recurse_or() 365 | { 366 | if constexpr (!isor(tokens_[Left::pos])) 367 | { 368 | return Left{}; 369 | } 370 | else 371 | { 372 | constexpr auto next{ parse_and() }; 373 | 374 | using ranode = typename decltype(next)::node; 375 | using node = sql::operation<"OR", Row, typename Left::node, ranode>; 376 | 377 | return recurse_or, Row>(); 378 | } 379 | } 380 | 381 | // descend further then attempt to parse OR operations 382 | template 383 | static constexpr auto parse_or() 384 | { 385 | using left = decltype(parse_and()); 386 | 387 | return recurse_or(); 388 | } 389 | 390 | // find correct schema for terminal relation 391 | template 392 | static constexpr auto recurse_schemas() 393 | { 394 | if constexpr (Name == Schema::name) 395 | { 396 | return ra::relation{}; 397 | } 398 | else 399 | { 400 | static_assert(sizeof...(Others) != 0, "Schema name used in JOIN was not provided."); 401 | 402 | return recurse_schemas(); 403 | } 404 | } 405 | 406 | // wrapper function to determine terminal relation 407 | template 408 | static constexpr auto parse_schema() 409 | { 410 | if constexpr (tokens_[Pos] == "(") 411 | { 412 | constexpr auto next{ parse_root() }; 413 | 414 | using node = typename decltype(next)::node; 415 | 416 | static_assert(tokens_[next.pos] == ")", "No closing paranthesis found."); 417 | 418 | return context{}; 419 | } 420 | else 421 | { 422 | constexpr cexpr::string name{ tokens_[Pos] }; 423 | 424 | using node = decltype(recurse_schemas()); 425 | 426 | return context{}; 427 | } 428 | } 429 | 430 | // stub which will choose the specific join RA node 431 | template 432 | static constexpr auto choose_join() 433 | { 434 | if constexpr (isnatural(tokens_[Pos])) 435 | { 436 | return ra::natural{}; 437 | } 438 | else 439 | { 440 | return ra::cross{}; 441 | } 442 | } 443 | 444 | // parses join colinfo if a join is present else returns the single relation terminal 445 | template 446 | static constexpr auto parse_join() 447 | { 448 | constexpr auto lnext{ parse_schema() }; 449 | 450 | using lnode = typename decltype(lnext)::node; 451 | 452 | if constexpr (lnext.pos + 2 < tokens_.count() && isjoin(tokens_[lnext.pos + 1])) 453 | { 454 | constexpr auto rnext{ parse_schema() }; 455 | 456 | using rnode = typename decltype(rnext)::node; 457 | using join = decltype(choose_join()); 458 | 459 | return context{}; 460 | } 461 | else 462 | { 463 | return context{}; 464 | } 465 | } 466 | 467 | // starting point to parse everything after the from keyword 468 | template 469 | static constexpr auto parse_from() 470 | { 471 | static_assert(isfrom(tokens_[Pos]), "Expected 'FROM' token not found."); 472 | 473 | constexpr auto next{ parse_join() }; 474 | 475 | using node = typename decltype(next)::node; 476 | 477 | if constexpr (next.pos < tokens_.count() && iswhere(tokens_[next.pos])) 478 | { 479 | using output = std::remove_cvref_t; 480 | 481 | constexpr auto predicate{ parse_or() }; 482 | 483 | using pnext = typename decltype(predicate)::node; 484 | using snode = ra::selection; 485 | 486 | return context{}; 487 | } 488 | else 489 | { 490 | return context{}; 491 | } 492 | } 493 | 494 | // recursively searches all schemas for the a matching column 495 | template 496 | static constexpr auto recurse_types() 497 | { 498 | if constexpr (sql::exists()) 499 | { 500 | return decltype(sql::get(typename Schema::row_type{})){}; 501 | } 502 | else 503 | { 504 | static_assert(sizeof...(Others) != 0, "Column name was not present in any schema."); 505 | 506 | return recurse_types(); 507 | } 508 | } 509 | 510 | // wrapper to determine the type for the the column 511 | template 512 | static constexpr auto column_type() 513 | { 514 | constexpr cexpr::string name{ tokens_[Pos] }; 515 | 516 | return recurse_types(); 517 | } 518 | 519 | // asserts token is column separator, and if comma returns one past the comma else start position 520 | template 521 | static constexpr std::size_t next_column() 522 | { 523 | static_assert(isseparator(tokens_[Pos]), "Expected ',' or 'FROM' token following column."); 524 | 525 | if constexpr (iscomma(tokens_[Pos])) 526 | { 527 | return Pos + 1; 528 | } 529 | else 530 | { 531 | return Pos; 532 | } 533 | } 534 | 535 | template 536 | static constexpr auto parse_colinfo() 537 | { 538 | static_assert(iscolumn(tokens_[Pos]), "Invalid token starting column delcaration."); 539 | 540 | constexpr bool rename{ isas(tokens_[Pos + 1]) && iscolumn(tokens_[Pos + 2]) }; 541 | 542 | using col = decltype(column_type()); 543 | 544 | if constexpr (Rename && rename) 545 | { 546 | constexpr auto next{ next_column() }; 547 | 548 | return colinfo{}; 549 | } 550 | else if constexpr (rename) 551 | { 552 | constexpr auto next{ next_column() }; 553 | 554 | return colinfo{}; 555 | } 556 | else 557 | { 558 | constexpr auto next{ next_column() }; 559 | 560 | return colinfo{}; 561 | } 562 | } 563 | 564 | // recursively parse all columns projected/renamed in the query 565 | template 566 | static constexpr auto recurse_columns() 567 | { 568 | if constexpr (isfrom(tokens_[Pos])) 569 | { 570 | return context{}; 571 | } 572 | else 573 | { 574 | constexpr auto info{ parse_colinfo() }; 575 | constexpr cexpr::string name{ tokens_[info.name] }; 576 | constexpr auto child{ recurse_columns() }; 577 | 578 | using next = std::remove_const_t; 579 | using col = std::remove_const_t{})>; 580 | using node = sql::row; 581 | 582 | return context{}; 583 | } 584 | } 585 | 586 | // wrapper to parse columns as a projection RA node 587 | template 588 | static constexpr auto parse_projection() 589 | { 590 | constexpr auto proj{ recurse_columns() }; 591 | constexpr auto next{ parse_from() }; 592 | 593 | using ranode = typename decltype(proj)::node; 594 | using node = ra::projection; 595 | 596 | return context{}; 597 | } 598 | 599 | // wrapper to parse columns as a rename RA node 600 | template 601 | static constexpr auto parse_rename() 602 | { 603 | constexpr auto next = parse_projection(); 604 | 605 | using ranode = typename decltype(recurse_columns())::node; 606 | using node = ra::rename; 607 | 608 | return context{}; 609 | } 610 | 611 | // attempts to match column rename operation pattern on a column 612 | template 613 | static constexpr bool has_rename() 614 | { 615 | if constexpr (isfrom(tokens_[Pos]) || isfrom(tokens_[Pos + 2])) 616 | { 617 | return false; 618 | } 619 | else if constexpr (iscolumn(tokens_[Pos]) && isas(tokens_[Pos + 1]) && iscolumn(tokens_[Pos + 2])) 620 | { 621 | return true; 622 | } 623 | else 624 | { 625 | constexpr bool comma{ iscomma(tokens_[Pos + 1]) }; 626 | 627 | static_assert(comma || isfrom(tokens_[Pos + 1]), "Expected ',' or 'FROM' token following column."); 628 | 629 | if constexpr (comma) 630 | { 631 | return has_rename(); 632 | } 633 | else 634 | { 635 | return has_rename(); 636 | } 637 | } 638 | } 639 | 640 | // decide RA node to root the expression tree 641 | template 642 | static constexpr auto parse_root() 643 | { 644 | static_assert(isselect(tokens_[Pos]), "Expected 'SELECT' token not found."); 645 | 646 | if constexpr (tokens_[Pos + 1] == "*") 647 | { 648 | return parse_from(); 649 | } 650 | else if constexpr (has_rename()) 651 | { 652 | return parse_rename(); 653 | } 654 | else 655 | { 656 | return parse_projection(); 657 | } 658 | } 659 | 660 | static constexpr sql::tokens tokens_{ Str }; 661 | 662 | using expression = typename decltype(parse_root<0>())::node; 663 | 664 | bool empty_; 665 | 666 | public: 667 | using iterator = query_iterator; 668 | using row_type = expression::output_type; 669 | 670 | query(Schemas const&... tables) 671 | { 672 | try 673 | { 674 | expression::seed(tables...); 675 | empty_ = false; 676 | } 677 | catch(ra::data_end const& e) 678 | { 679 | empty_ = true; 680 | } 681 | } 682 | 683 | ~query() 684 | { 685 | expression::reset(); 686 | } 687 | 688 | inline iterator begin() const 689 | { 690 | return iterator{ empty_ }; 691 | } 692 | 693 | inline iterator end() const 694 | { 695 | return iterator{ true }; 696 | } 697 | }; 698 | 699 | } // namespace sql 700 | -------------------------------------------------------------------------------- /include/sql/row.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | #include "cexpr/string.hpp" 8 | 9 | namespace sql 10 | { 11 | 12 | struct void_row 13 | { 14 | static constexpr std::size_t depth{ 0 }; 15 | }; 16 | 17 | template 18 | class row 19 | { 20 | public: 21 | using column = Col; 22 | using next = Next; 23 | 24 | static constexpr std::size_t depth{ 1 + next::depth }; 25 | 26 | row() = default; 27 | 28 | template 29 | row(column::type const& val, ColTs const&... vals) : value_{ val }, next_{ vals... } 30 | {} 31 | 32 | template 33 | row(column::type&& val, ColTs&&... vals) : value_{ std::forward(val) }, next_{ std::forward(vals)... } 34 | {} 35 | 36 | inline constexpr next const& tail() const noexcept 37 | { 38 | return next_; 39 | } 40 | 41 | inline constexpr next& tail() noexcept 42 | { 43 | return next_; 44 | } 45 | 46 | inline constexpr column::type const& head() const noexcept 47 | { 48 | return value_; 49 | } 50 | 51 | inline constexpr column::type& head() noexcept 52 | { 53 | return value_; 54 | } 55 | 56 | private: 57 | column::type value_; 58 | next next_; 59 | }; 60 | 61 | template 62 | struct variadic_row 63 | { 64 | private: 65 | static inline constexpr auto resolve() noexcept 66 | { 67 | if constexpr (sizeof...(Cols) != 0) 68 | { 69 | return typename variadic_row::row_type{}; 70 | } 71 | else 72 | { 73 | return void_row{}; 74 | } 75 | } 76 | 77 | public: 78 | using row_type = row; 79 | }; 80 | 81 | // user function to query row elements by column name 82 | template 83 | constexpr auto const& get(Row const& r) noexcept 84 | { 85 | static_assert(!std::is_same_v, "Name does not match a column name."); 86 | 87 | if constexpr (Row::column::name == Name) 88 | { 89 | return r.head(); 90 | } 91 | else 92 | { 93 | return get(r.tail()); 94 | } 95 | } 96 | 97 | // compiler function used by structured binding declaration 98 | template 99 | constexpr auto const& get(Row const& r) noexcept 100 | { 101 | static_assert(Pos < Row::depth, "Position is larger than number of row columns."); 102 | 103 | if constexpr (Pos == 0) 104 | { 105 | return r.head(); 106 | } 107 | else 108 | { 109 | return get(r.tail()); 110 | } 111 | } 112 | 113 | // function to assign a value to a column's value in a row 114 | template 115 | constexpr void set(Row& r, Type const& value) 116 | { 117 | static_assert(!std::is_same_v, "Name does not match a column name."); 118 | 119 | if constexpr (Row::column::name == Name) 120 | { 121 | r.head() = value; 122 | } 123 | else 124 | { 125 | set(r.tail(), value); 126 | } 127 | } 128 | 129 | } // namespace sql 130 | 131 | // STL injections to allow row to be used in structured binding declarations 132 | namespace std 133 | { 134 | 135 | template 136 | class tuple_size> : public integral_constant::depth> 137 | {}; 138 | 139 | template 140 | struct tuple_element> 141 | { 142 | using type = decltype(sql::get(sql::row{})); 143 | }; 144 | 145 | } // namespace std 146 | -------------------------------------------------------------------------------- /include/sql/schema.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #include "cexpr/string.hpp" 10 | 11 | #include "sql/column.hpp" 12 | #include "sql/index.hpp" 13 | #include "sql/row.hpp" 14 | 15 | namespace sql 16 | { 17 | 18 | template 19 | class schema 20 | { 21 | public: 22 | static constexpr auto name{ Name }; 23 | 24 | using row_type = sql::variadic_row::row_type; 25 | using container = typename 26 | std::conditional_t< 27 | std::is_same_v>, 28 | std::vector, 29 | std::multiset> 30 | >; 31 | using const_iterator = typename container::const_iterator; 32 | 33 | schema() = default; 34 | 35 | template 36 | schema(std::vector const& col, Types const&... cols) : schema{} 37 | { 38 | insert(col, cols...); 39 | } 40 | 41 | template 42 | schema(std::vector&& col, Types&&... cols) : schema{} 43 | { 44 | insert(std::forward(col), std::forward(cols)...); 45 | } 46 | 47 | template 48 | inline void emplace(Types const&... vals) 49 | { 50 | if constexpr (std::is_same_v>) 51 | { 52 | table_.emplace_back(vals...); 53 | } 54 | else 55 | { 56 | table_.emplace(vals...); 57 | } 58 | } 59 | 60 | template 61 | inline void emplace(Types&&... vals) 62 | { 63 | if constexpr (std::is_same_v>) 64 | { 65 | table_.emplace_back(vals...); 66 | } 67 | else 68 | { 69 | table_.emplace(vals...); 70 | } 71 | } 72 | 73 | template 74 | void insert(std::vector const& col, Types const&... cols) 75 | { 76 | for (std::size_t i{}; i < col.size(); ++i) 77 | { 78 | emplace(col[i], cols[i]...); 79 | } 80 | } 81 | 82 | template 83 | void insert(std::vector&& col, Types&&... cols) 84 | { 85 | for (std::size_t i{}; i < col.size(); ++i) 86 | { 87 | emplace(std::forward(col[i]), std::forward(cols[i])...); 88 | } 89 | } 90 | 91 | void insert(row_type const& row) 92 | { 93 | if constexpr (std::is_same_v>) 94 | { 95 | table_.push_back(row); 96 | } 97 | else 98 | { 99 | table_.insert(row); 100 | } 101 | } 102 | 103 | void insert(row_type&& row) 104 | { 105 | if constexpr (std::is_same_v>) 106 | { 107 | table_.push_back(std::forward(row)); 108 | } 109 | else 110 | { 111 | table_.insert(std::forward(row)); 112 | } 113 | } 114 | 115 | inline const_iterator begin() const noexcept 116 | { 117 | return table_.begin(); 118 | } 119 | 120 | inline const_iterator end() const noexcept 121 | { 122 | return table_.end(); 123 | } 124 | 125 | private: 126 | container table_; 127 | }; 128 | 129 | namespace 130 | { 131 | 132 | template 133 | void fill(std::fstream& fstr, Row& row, [[maybe_unused]] char delim) 134 | { 135 | if constexpr (!std::is_same_v) 136 | { 137 | if constexpr (std::is_same_v) 138 | { 139 | if constexpr (std::is_same_v) 140 | { 141 | std::getline(fstr, row.head()); 142 | } 143 | else 144 | { 145 | std::getline(fstr, row.head(), delim); 146 | } 147 | } 148 | else 149 | { 150 | fstr >> row.head(); 151 | } 152 | 153 | fill(fstr, row.tail(), delim); 154 | } 155 | } 156 | 157 | template 158 | void fill(std::fstream& fstr, Row const& row, char delim) 159 | { 160 | if constexpr (!std::is_same_v) 161 | { 162 | fstr << row.head(); 163 | 164 | if constexpr (std::is_same_v) 165 | { 166 | fstr << '\n'; 167 | } 168 | else 169 | { 170 | fstr << delim; 171 | } 172 | 173 | fill(fstr, row.tail(), delim); 174 | } 175 | } 176 | 177 | } // namespace 178 | 179 | // helper function for users to load a data into a schema from a file 180 | template 181 | Schema load(std::string const& file, char delim) 182 | { 183 | auto fstr{ std::fstream(file, fstr.in) }; 184 | Schema table{}; 185 | typename Schema::row_type row{}; 186 | 187 | while (fstr) 188 | { 189 | fill(fstr, row, delim); 190 | table.insert(std::move(row)); 191 | 192 | // in case last stream extraction did not remove newline 193 | if (fstr.get() != '\n') 194 | { 195 | fstr.unget(); 196 | } 197 | } 198 | 199 | return table; 200 | } 201 | 202 | // for compat with previous versions 203 | template 204 | inline Schema load(std::string const& file) 205 | { 206 | return load(file, Delim); 207 | } 208 | 209 | // will work with schema and query objects 210 | template 211 | void store(Type const& data, std::string const& file, char delim) 212 | { 213 | auto fstr{ std::fstream(file, fstr.out) }; 214 | 215 | for (auto const& row : data) 216 | { 217 | fill(fstr, row, delim); 218 | } 219 | } 220 | 221 | // for devs who want to use the previous format 222 | template 223 | inline void store(Type const& data, std::string const& file) 224 | { 225 | store(data, file, Delim); 226 | } 227 | 228 | } // namespace sql 229 | -------------------------------------------------------------------------------- /include/sql/tokens.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | #include "cexpr/string.hpp" 9 | 10 | namespace sql 11 | { 12 | namespace 13 | { 14 | 15 | template 16 | constexpr bool whitespace(Char curr) 17 | { 18 | return curr == Char{ ' ' } || curr == Char{ '\t' } || curr == Char{ '\n' }; 19 | } 20 | 21 | template 22 | constexpr bool syntax(Char curr) 23 | { 24 | return curr == Char{ ',' } || curr == Char{ '(' } || curr == Char{ ')' } || 25 | curr == Char{ '\'' } || curr == Char{ '\"' } || curr == Char{ '=' }; 26 | } 27 | 28 | template 29 | constexpr const Char* skip(const Char *curr, const Char *end) 30 | { 31 | for (; curr != end && whitespace(*curr); ++curr); 32 | return curr; 33 | } 34 | 35 | template 36 | constexpr const Char* next(const Char *curr, const Char *end) 37 | { 38 | Char c{ *curr }; 39 | 40 | if (c == Char{ '>' } || c == Char{ '<' } || c == Char{ '!' }) 41 | { 42 | ++curr; 43 | 44 | if (*curr == Char{ '=' } || (c == Char{ '<' } && *curr == Char{ '>' })) 45 | { 46 | ++curr; 47 | } 48 | } 49 | else if (syntax(c)) 50 | { 51 | ++curr; 52 | } 53 | else 54 | { 55 | for (; curr != end && !whitespace(*curr) && !syntax(*curr); ++curr); 56 | } 57 | 58 | return curr; 59 | } 60 | 61 | } // namespace 62 | 63 | template 64 | class tokens 65 | { 66 | public: 67 | using token_view = std::basic_string_view; 68 | 69 | constexpr tokens() = default; 70 | 71 | template 72 | constexpr tokens(cexpr::string const& cs) : tokens_{} 73 | { 74 | auto curr{ cs.cbegin() }, last{ cs.cbegin() }; 75 | const auto end{ cs.cend() }; 76 | std::size_t i{}; 77 | 78 | while (curr < end) 79 | { 80 | curr = skip(curr, end); 81 | last = curr; 82 | last = next(last, end); 83 | 84 | if (*curr == Char{ '\"' } || *curr == Char{ '\'' }) 85 | { 86 | tokens_[i++] = token_view{ curr, 1 }; 87 | for (char c{ *curr++ }; last != end && *last != c; ++last); 88 | } 89 | 90 | auto len{ reinterpret_cast(last) - reinterpret_cast(curr) }; 91 | tokens_[i++] = token_view{ curr, len }; 92 | 93 | if (*last == Char{ '\"' } || *last == Char{ '\'' }) 94 | { 95 | tokens_[i++] = token_view{ last, 1 }; 96 | ++last; 97 | } 98 | 99 | curr = last; 100 | } 101 | } 102 | 103 | constexpr std::size_t count() const noexcept 104 | { 105 | return Count; 106 | } 107 | 108 | constexpr token_view* begin() noexcept 109 | { 110 | return tokens_.begin(); 111 | } 112 | constexpr const token_view* cbegin() const noexcept 113 | { 114 | return tokens_.cbegin(); 115 | } 116 | 117 | constexpr token_view* end() noexcept 118 | { 119 | return tokens_.end(); 120 | } 121 | constexpr const token_view* cend() const noexcept 122 | { 123 | return tokens_.cend(); 124 | } 125 | 126 | constexpr token_view& operator[](std::size_t i) 127 | { 128 | return tokens_[i]; 129 | } 130 | constexpr token_view const& operator[](std::size_t i) const 131 | { 132 | return tokens_[i]; 133 | } 134 | 135 | private: 136 | std::array tokens_; 137 | }; 138 | 139 | template 140 | constexpr std::size_t preprocess(cexpr::string const& cs) noexcept 141 | { 142 | auto begin{ cs.cbegin() }; 143 | const auto end{ cs.cend() }; 144 | std::size_t count{ 1 }; 145 | 146 | while (begin < end) 147 | { 148 | begin = skip(begin, end); 149 | begin = next(begin, end); 150 | ++count; 151 | } 152 | 153 | return count; 154 | } 155 | 156 | } // namespace sql 157 | -------------------------------------------------------------------------------- /presentation.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mkitzan/constexpr-sql/ba98a31224ce160b6e8bc92aca3b079c5cf0f56d/presentation.pdf -------------------------------------------------------------------------------- /tests/data.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | #include "sql.hpp" 7 | 8 | using books = 9 | sql::schema< 10 | "books", sql::index<>, 11 | #ifdef CROSS 12 | sql::column<"book", std::string>, 13 | #else 14 | sql::column<"title", std::string>, 15 | #endif 16 | sql::column<"genre", std::string>, 17 | sql::column<"year", unsigned>, 18 | sql::column<"pages", unsigned> 19 | >; 20 | 21 | using stories = 22 | sql::schema< 23 | "stories", sql::index<>, 24 | #ifdef CROSS 25 | sql::column<"story", std::string>, 26 | #else 27 | sql::column<"title", std::string>, 28 | #endif 29 | sql::column<"genre", std::string>, 30 | sql::column<"year", unsigned> 31 | >; 32 | 33 | using authored = 34 | sql::schema< 35 | "authored", sql::index<>, 36 | sql::column<"title", std::string>, 37 | sql::column<"name", std::string> 38 | >; 39 | 40 | using collected = 41 | sql::schema< 42 | "collected", sql::index<>, 43 | sql::column<"title", std::string>, 44 | sql::column<"collection", std::string>, 45 | sql::column<"pages", unsigned> 46 | >; 47 | 48 | const std::string data_folder{ "./data/" }; 49 | const std::string perf_folder{ "../data/" }; 50 | const std::string books_data{ "books.tsv" }; 51 | const std::string stories_data{ "stories.tsv" }; 52 | const std::string authored_data{ "authored.tsv" }; 53 | const std::string collected_data{ "collected.tsv" }; 54 | 55 | using books_row = std::tuple; 56 | using books_type = std::vector; 57 | using stories_row = std::tuple; 58 | using stories_type = std::vector; 59 | using authored_row = std::tuple; 60 | using authored_type = std::vector; 61 | using collected_row = std::tuple; 62 | using collected_type = std::vector; 63 | 64 | constexpr std::size_t iters{ 65536 }; 65 | constexpr std::size_t offset{ 512 }; 66 | 67 | template 68 | books_type books_load() 69 | { 70 | auto file{ std::fstream(perf_folder + books_data) }; 71 | books_type table{}; 72 | 73 | while (file) 74 | { 75 | books_row row{}; 76 | std::getline(file, std::get<0>(row), Delim); 77 | std::getline(file, std::get<1>(row), Delim); 78 | file >> std::get<2>(row); 79 | file >> std::get<3>(row); 80 | 81 | table.push_back(std::move(row)); 82 | 83 | if (file.get() != '\n') 84 | { 85 | file.unget(); 86 | } 87 | } 88 | 89 | return table; 90 | } 91 | 92 | template 93 | stories_type stories_load() 94 | { 95 | auto file{ std::fstream(perf_folder + stories_data) }; 96 | stories_type table{}; 97 | 98 | while (file) 99 | { 100 | stories_row row{}; 101 | std::getline(file, std::get<0>(row), Delim); 102 | std::getline(file, std::get<1>(row), Delim); 103 | file >> std::get<2>(row); 104 | 105 | table.push_back(std::move(row)); 106 | 107 | if (file.get() != '\n') 108 | { 109 | file.unget(); 110 | } 111 | } 112 | 113 | return table; 114 | } 115 | 116 | template 117 | authored_type authored_load() 118 | { 119 | auto file{ std::fstream(perf_folder + authored_data) }; 120 | authored_type table{}; 121 | 122 | while (file) 123 | { 124 | authored_row row{}; 125 | std::getline(file, std::get<0>(row), Delim); 126 | std::getline(file, std::get<1>(row), Delim); 127 | 128 | table.push_back(std::move(row)); 129 | 130 | if (file.get() != '\n') 131 | { 132 | file.unget(); 133 | } 134 | } 135 | 136 | return table; 137 | } 138 | 139 | template 140 | collected_type collected_load() 141 | { 142 | auto file{ std::fstream(perf_folder + collected_data) }; 143 | collected_type table{}; 144 | 145 | while (file) 146 | { 147 | collected_row row{}; 148 | std::getline(file, std::get<0>(row), Delim); 149 | std::getline(file, std::get<1>(row), Delim); 150 | file >> std::get<2>(row); 151 | 152 | table.push_back(std::move(row)); 153 | 154 | if (file.get() != '\n') 155 | { 156 | file.unget(); 157 | } 158 | } 159 | 160 | return table; 161 | } 162 | -------------------------------------------------------------------------------- /tests/data/authored.tsv: -------------------------------------------------------------------------------- 1 | 1984 George Orwell 2 | !!!The!!Teddy!Crazy!!Show!!! Harlan Ellison 3 | (Learning About) Machine Sex Candas Jane Dorsey 4 | ...the World, as we Know 't Howard Waldrop 5 | 2001: A Space Odyssey Arthur C. Clarke 6 | 2004, or Thereabouts David R. Bunch 7 | 20th Century Boys vol.1 Naoki Urasawa 8 | 20th Century Boys vol.2 Naoki Urasawa 9 | 20th Century Boys vol.3 Naoki Urasawa 10 | 20th Century Boys vol.4 Naoki Urasawa 11 | 20th Century Boys vol.5 Naoki Urasawa 12 | 20th Century Boys vol.6 Naoki Urasawa 13 | A Biography of Tadeo Isidoro Cruz (1829-1874) Jorge Luis Borges 14 | A Brief History of the Trans-Pacific Tunnel Ken Liu 15 | A Canticle for Leibowitz Walter M. Miller, Jr. 16 | A Case of Conscience James Blish 17 | A Case of Identity Arthur Conan Doyle 18 | A Clash of Cymbals James Blish 19 | A Clockwork Orange Anthony Burgess 20 | A Day at Harmenz Tadeusz Borowski 21 | A Deskful of Girls Fritz Leiber 22 | A Dialog About A Dialog Jorge Luis Borges 23 | A Dialog Between Dead Men Jorge Luis Borges 24 | A Farewell to Arms Ernest Hemingway 25 | A Feast of Demons William Morrison 26 | A Few Things I Know About While Away Joanna Russ 27 | A Hundred Ghosts Parade Tonight Xia Jia 28 | A is for Automation Kate Wilhelm 29 | A Life for the Stars James Blish 30 | A Midwinter's Tale Michael Swanwick 31 | A Momentary Taste of Being James Tiptree, Jr. 32 | A Mouse in the Walls of the Global Village Dean R. Koontz 33 | A New Refutation of Time Jorge Luis Borges 34 | A Note on (toward) Bernard Shaw Jorge Luis Borges 35 | A Path Through the Darkness Harlan Ellison 36 | A Prayer for No One's Enemies Harlan Ellison 37 | A Problem Jorge Luis Borges 38 | A Scandal in Bohemia Arthur Conan Doyle 39 | A Scanner Darkly Philip K. Dick 40 | A Time of Changes Robert Silverberg 41 | A Tour of C++ 2nd Bjarne Stroustrup 42 | A Toy for Juliette Robert Bloch 43 | A True Story Tadeusz Borowski 44 | A Visit Tadeusz Borowski 45 | A Way of Thinking Theodore Sturgeon 46 | Absalom, Absalom! William Faulkner 47 | Adrift Just Off the Islets of Langerhans: Latitude 38o54'N, Longitude 77o00'13W Harlan Ellison 48 | Adrift on the Policy Level Chandler Davis 49 | Aesop Clifford D. Simak 50 | After the Days of Dead-Eye 'Dee Pat Cadigan 51 | Again, Dangerous Visions Harlan Ellison 52 | Akira vol.1 Katsuhiro Otomo 53 | Akira vol.2 Katsuhiro Otomo 54 | Akira vol.3 Katsuhiro Otomo 55 | Akira vol.4 Katsuhiro Otomo 56 | Akira vol.5 Katsuhiro Otomo 57 | Akira vol.6 Katsuhiro Otomo 58 | Algorithms 4th Kevin Wayne 59 | Algorithms 4th Robert Sedgewick 60 | All in Good Time Miram Allen deFord 61 | All the Birds Come Home to Roost Harlan Ellison 62 | All the Flavors Ken Liu 63 | All the Lies Lies That Are My Life Harlan Ellison 64 | All The People R. A. Lafferty 65 | All the Sound of Fear Harlan Ellison 66 | All Tomorrow's Parties William Gibson 67 | Along the Scenic Route Harlan Ellison 68 | Alpha Ralpha Boulevard Cordwainer Smith 69 | Amateur in Chancery George O. Smith 70 | America Orson Scott Card 71 | An Advanced Readers' Picture Book of Comparative Cognition Ken Liu 72 | An Examination of the Work of Herbert Quain Jorge Luis Borges 73 | And Chaos Died Joanna Russ 74 | And the Angels Sing Kate Wilhelm 75 | And the Moon be Still as Bright Ray Bradbury 76 | And the Sea Like Mirrors Gregory Benford 77 | Andover and the Android Kate Wilhelm 78 | Angry Candy Harlan Ellison 79 | Animal Farm George Orwell 80 | Anybody Else Like Me? Walter M. Miller, Jr. 81 | Anywhere But Here, With Anybody But You Harlan Ellison 82 | Approaching Oblivion Harlan Ellison 83 | April Fools' Day Forever Kate Wilhelm 84 | Argumentum Ornithologicum Jorge Luis Borges 85 | Army of None Paul Scharre 86 | As Simple As That Zenna Henderson 87 | At the End of the Orbit Arthur C. Clarke 88 | At the Mouse Circus Harlan Ellison 89 | Aunt Parnetta's Electric Blisters Diane Glancy 90 | Auschwitz, Our Home (A Letter) Tadeusz Borowski 91 | Auto-De-Fe Roger Zelazny 92 | Avatars of the Tortoise Jorge Luis Borges 93 | Averroes' Search Jorge Luis Borges 94 | Aye, and Gomorrah... Samuel R. Delany 95 | Balanced Ecology James H. Schmitz 96 | Basilisk Harlan Ellison 97 | Battle for the Mind William Sargant 98 | Battle Without Banners Harlan Ellison 99 | Battlefield Harlan Ellison 100 | Beachhead Clifford D. Simak 101 | Beauty's Beast Robert Bloch 102 | Bed Sheets are White Evelyn Lief 103 | Beowulf Anonymous 104 | Bettyann Kris Neville 105 | Beyond the Blue Event Horizon Frederik Pohl 106 | Bianca's Hands Theodore Sturgeon 107 | Bible and Sword Barbara W. Tuchman 108 | Big Joe and the Nth Generation Walter M. Miller, Jr. 109 | Blabbermouth Theodore Sturgeon 110 | Black Bargain Robert Bloch 111 | Blame! vol.1 Tsumotu Nihei 112 | Blame! vol.2 Tsumotu Nihei 113 | Blame! vol.3 Tsumotu Nihei 114 | Blame! vol.4 Tsumotu Nihei 115 | Blame! vol.5 Tsumotu Nihei 116 | Blame! vol.6 Tsumotu Nihei 117 | Blank? Harlan Ellison 118 | Bleeding Stones Harlan Ellison 119 | Blind Bird, Blind Bird, Go Away From Me! Harlan Ellison 120 | Blood Bank Walter M. Miller, Jr. 121 | Blot Gahan Wilson 122 | Blowups Happen Robert A. Heilein 123 | Blue Spring Taiyo Matsumoto 124 | Borges and I Jorge Luis Borges 125 | Bounty T. L. Sherred 126 | Brain Wave Poul Anderson 127 | Brass and Gold (or Horse and Zeppelin in Beverly Hills) Philip Jose Farmer 128 | Brave New World Aldous Huxley 129 | Bright Eyes Harlan Ellison 130 | Bright Segment Theodore Sturgeon 131 | Broken Glass Harlan Ellison 132 | Brownshoes Theodore Sturgeon 133 | Burning Chrome William Gibson 134 | By His Bootstraps Robert A. Heinlein 135 | C Primer Plus 5th Stephen Prata 136 | C++ Primer 5th Barbara E. Moo 137 | C++ Primer 5th Josee Lajoie 138 | C++ Primer 5th Stanley B. Lippman 139 | Call Girl Tang Fei 140 | Camps Jack Dann 141 | Capitalism Without Capital Jonathan Haskel 142 | Capitalism Without Capital Stian Westlake 143 | Captain Harlock: The Classic Collection vol.1 Leiji Matsumoto 144 | Captain Harlock: The Classic Collection vol.2 Leiji Matsumoto 145 | Captain Harlock: The Classic Collection vol.3 Leiji Matusmoto 146 | Carcinoma Angels Norman Spinard 147 | Catch That Rabbit Isaac Asimov 148 | Catch-22 Joseph Heller 149 | Catman Harlan Ellison 150 | Caviar Theodore Sturgeon 151 | Census Clifford D. Simak 152 | Chain Reaction Boyd Ellanby 153 | Chained to the Fast Lane in the Red Queen's Race Harlan Ellison 154 | Changewar Fritz Leiber 155 | Chapterhouse: Dune Frank Herbert 156 | Chatting with Anubis Harlan Ellison 157 | Childhood's End Arthur C. Clarke 158 | Children of Dune Frank Herbert 159 | Children of the Sea vol.1 Daisuke Igarashi 160 | Children of the Sea vol.2 Daisuke Igarashi 161 | Children of the Sea vol.3 Daisuke Igarashi 162 | Children of the Sea vol.4 Daisuke Igarashi 163 | Children of the Sea vol.5 Daisuke Igarashi 164 | Ching Witch! Ross Rocklynne 165 | Christ, Old Student in a New School Ray Bradbury 166 | Chuck Berry, Won't You Please Come Home Ken McCullough 167 | City Clifford D. Simak 168 | Cold Friend Harlan Ellison 169 | Collecting Team Robert Silverberg 170 | Colossus B. Jack Copeland 171 | Columbus Was a Dope Robert A. Heinlein 172 | Come to the Party F. M. Busby 173 | Comes Now the Power Roger Zelazny 174 | Commuter's Problem Harlan Ellison 175 | Conversations With Jorge Luis Borges Richard Burgin 176 | Corpse Harlan Ellison 177 | Count the Clock That Tells the Time Harlan Ellison 178 | Count Zero William Gibson 179 | Covered Mirrors Jorge Luis Borges 180 | Crate Theodore Sturgeon 181 | Crazy as a Soup Sandwich Harlan Ellison 182 | Croatoan Harlan Ellison 183 | Crome Yellow Aldous Huxley 184 | Crucifixus Etiam Walter M. Miller, Jr. 185 | Curse 5.0 Liu Cixin 186 | Damnation Morning Fritz Leiber 187 | Dandelion Wine Ray Bradbury 188 | Dangerous Visions Harlan Ellison 189 | Danger-Human! Gordon R. Dickson 190 | Daniel White for the Greater Good Harlan Ellison 191 | Darkness Upon the Face of the Deep Harlan Ellison 192 | Day Million Frederik Pohl 193 | Deal From the Bottom Harlan Ellison 194 | Death and the Compass Jorge Luis Borges 195 | Death and the Penguin Andrey Kurkov 196 | Deathbird Stories Harlan Ellison 197 | Death's End Liu Cixin 198 | Deeper than the Darkness Harlan Ellison 199 | Delia Elena San Marco Jorge Luis Borges 200 | Delusion for a Dragon Slayer Harlan Ellison 201 | Design Patterns Erich Gamma 202 | Design Patterns John Vlissides 203 | Design Patterns Ralph Johnson 204 | Design Patterns Richard Helm 205 | Destined for War Graham Allison 206 | Deutsches Requiem Jorge Luis Borges 207 | Devourer Liu Cixin 208 | Dirk Gently's Holistic Detective Agency Douglas Adams 209 | Distant Signals Andrew Weiner 210 | Distrust That Particular Flavor William Gibson 211 | Division by Zero Ted Chiang 212 | Django Harlan Ellison 213 | Djinn, No Chaser Harlan Ellison 214 | Do Androids Dream of Electric Sheep? Philip K. Dick 215 | Doctor Zhivago Boris Pasternak 216 | Dogfight Michael Swanwick 217 | Dogfight William Gibson 218 | Do-It-Yourself Harlan Ellison 219 | Don Quixote Miguel de Cervantes Saavedra 220 | Double Star Robert A. Heinlein 221 | Downward to the Earth Robert Silverberg 222 | Dr. Bloodmoney Philip K. Dick 223 | Dreamtigers Jorge Luis Borges 224 | Dumb Waiter Walter M. Miller, Jr. 225 | Dune Frank Herbert 226 | Dune Messiah Frank Herbert 227 | Dying Inside Robert Silverberg 228 | Each an Explorer Isaac Asimov 229 | Earthman, Come Home James Blish 230 | Earthman, Go Home! Harlan Ellison 231 | Ecowarewness Harlan Ellison 232 | Eidolons Harlan Ellison 233 | Elbow Room Marion Zimmer Bradley 234 | Elegy Jorge Luis Borges 235 | Elouise and the Doctors of the Planet Pergamon Josephine Saxton 236 | Emanon vol.1: Memories of Emanon Kenji Tsuruta 237 | Emanon vol.2: Emanon Wanderer pt.1 Kenji Tsuruta 238 | Emanon vol.3: Emanon Wanderer pt.2 Kenji Tsuruta 239 | Emissary from Hamelin Harlan Ellison 240 | Emma Zunz Jorge Luis Borges 241 | Empire of the Sun Andrew Weiner 242 | Empire Star Samuel R. Delany 243 | Encounter With A Hick Jonathan Brand 244 | Ender's Game Orson Scott Card 245 | Endless Frontier G. Pascal Zachary 246 | Endymion Dan Simmons 247 | Enemy Mine Barry B. Longyear 248 | Eniac Scott McCartney 249 | Epilogue Clifford D. Simak 250 | Epiphany for Aliens David Kerr 251 | Ernest and the Machine God Harlan Ellison 252 | Erotophobia Harlan Ellison 253 | Ersatz Henry Slesar 254 | Escape! Isaac Asimov 255 | Escapegoat Harlan Ellison 256 | Eutopia Poul Anderson 257 | Evensong Lester del Rey 258 | Everything and Nothing Jorge Luis Borges 259 | Evidence Isaac Asimov 260 | Exploration Team Murray Leinster 261 | Explorers of Space Robert Silverberg 262 | Exposures Gregory Benford 263 | Eye of the Beholder Burt K. Filer 264 | Fahrenheit 451 Ray Bradbury 265 | Faith of our Fathers Philip K. Dick 266 | Fault-Tolerant Computer System Designs Dhiraj K. Pradhan 267 | Fear is a Cold Black Kate Wilhelm 268 | Feather Tigers Gene Wolfe 269 | Featherbed on Chlyntha Miram Allen deFord 270 | Fiasco Stanislaw Lem 271 | Ficciones Jorge Luis Borges 272 | Final Trophy Harlan Ellison 273 | Flies Robert Silverberg 274 | Flop Sweat Harlan Ellison 275 | Flow My Tears, the Policeman Said Philip K. Dick 276 | Flowers for Algernon Daniel Keyes 277 | Folding Beijing Hao Jingfang 278 | Footsteps Harlan Ellison 279 | For the Sake of Grace Suzette Haden Elgin 280 | For Value Received Andrew J. Ouffutt 281 | For Whom the Bell Tolls Ernest Hemingway 282 | Forward the Foundation Isaac Asimov 283 | Foundation Isaac Asimov 284 | Foundation and Earth Isaac Asimov 285 | Foundation and Empire Isaac Asimov 286 | Foundation's Edge Isaac Asimov 287 | Fragments of a Hologram Rose William Gibson 288 | Frank Herbert Nebula Winners Fifteen 289 | Frederik Pohl The Expert Dreamers 290 | From A to Z, In The Chocolate Alphabet Harlan Ellison 291 | From the Government Printing Office Kris Neville 292 | Frozen Journey Philip K. Dick 293 | Funes the Memorious Jorge Luis Borges 294 | G. B. K.-A Many-Flavored Bird Harlan Ellison 295 | Gateway Frederik Pohl 296 | Gather Blue Roses Pamela Sargent 297 | Gathi Miram Allen deFord 298 | Getting Along James Blish 299 | Ghost in the Shell Shirow Masamune 300 | Ghost in the Shell vol.1.5: Human-Error Processor Shirow Masamune 301 | Ghost in the Shell vol.2: Man-Machine Interface Shirow Masamune 302 | Ghost of a Chance Theodore Sturgeon 303 | giANTS Edward Bryant 304 | Gift from the Stars Kate Wilhelm 305 | Giganto Maxia Kentaro Miura 306 | Gnomebody Harlan Ellison 307 | Go Toward the Light Harlan Ellison 308 | Go, Go, Go, Said the Bird Sonya Dorman 309 | God Emperor of Dune Frank Herbert 310 | Goldfish Bowl Robert A. Heinlein 311 | Gonna Roll the Bones Fritz Leiber 312 | Good Hunting Ken Liu 313 | Good News from the Vatican Robert Silverberg 314 | Gopher in the Gilly Harlan Ellison 315 | Grail Harlan Ellison 316 | Grave of the Fireflies Cheng Jingbo 317 | Gutter Gang Harlan Ellison 318 | Hadj Harlan Ellison 319 | Half-Life Paul Preuss 320 | Hamlet William Shakespeare 321 | Harry the Hare James B. Hemesath 322 | Hawksbill Station Robert Silverberg 323 | Heart of Darkness Joseph Conrad 324 | Heavyplanet Lee Gregor 325 | Heechee Rendezvous Frederik Pohl 326 | Heechee Treasures Frederik Pohl 327 | Hell Is the Absence of God Ted Chiang 328 | Heretics of Dune Frank Herbert 329 | High Weir Samuel R. Delany 330 | Hindsight: 480 Seconds Harlan Ellison 331 | Hinterlands William Gibson 332 | His Vegetable Pat Murphy 333 | Hitler Painted Roses Harlan Ellison 334 | Hobbies Clifford D. Simak 335 | Homecoming Ray Bradbury 336 | Homelanding Margaret Atwood 337 | Houston, Houston, Do You Read? James Tiptree, Jr. 338 | How Beautiful with Banners James Blish 339 | How's the Night Life on Cassalda? Harlan Ellison 340 | Huddling Place Clifford D. Simak 341 | Humpty Dumpty had a Great Fall Frank Belknap 342 | Hyperion Dan Simmons 343 | I Curse the Lesson and Bless the Knowledge Harlan Ellison 344 | I Will Fear No Evil Robert A. Heinlein 345 | I, Dreamer Walter M. Miller, Jr. 346 | I, Robot Isaac Asimov 347 | Ibn-Hakam al-Bokhari, Murdered in His Labyrinth Jorge Luis Borges 348 | Ichi-F Kazuto Tatsuta 349 | Idoru William Gibson 350 | If All Men Were Brothers, Would You Let One Marry Your Sister? Theodore Sturgeon 351 | I'm Looking for Kadak Harlan Ellison 352 | In Fear of K Harlan Ellison 353 | In Lonely Islands Harlan Ellison 354 | In Memoriam, J. F. K. Jorge Luis Borges 355 | In re Glover Leonard Tushnet 356 | In the Barn Piers Anthony 357 | In the Core Frederik Pohl 358 | In the Fourth Year of the War Harlan Ellison 359 | Incident in Moderan David R. Bunch 360 | Inferno, I, 32 Jorge Luis Borges 361 | Inferno: The World at War, 1939-1945 Max Hastings 362 | Interim Ray Bradbury 363 | Interlocking Pieces Molly Gloss 364 | Into the Wild Jon Krakauer 365 | Into Thin Air Jon Krakauer 366 | Invaders John Kessel 367 | Invasion Footnote Harlan Ellison 368 | Invisible Man Ralph Ellison 369 | Invisible Planets Hao Jingfang 370 | It Theodore Sturgeon 371 | It was Nothing-Really Theodore Sturgeon 372 | It's You! Theodore Sturgeon 373 | J. C. on the Dude Ranch Philip Jose Farmer 374 | Jack-in-the-Box Ray Bradbury 375 | Jane Doe #112 Harlan Ellison 376 | Jeffty is Five Harlan Ellison 377 | Jenny with Wings Kate Wilhelm 378 | Johnny Mnemonic William Gibson 379 | Jorry's Gap Theodore Sturgeon 380 | Judas John Brunner 381 | Julius Caesar William Shakespeare 382 | Jupiter Five Arthur C. Clarke 383 | Jurassic Park Michael Crichton 384 | Kafka and His Precursors Jorge Luis Borges 385 | Invisible Planets Ken Liu 386 | Keyboard Harlan Ellison 387 | Killdozer! Theodore Sturgeon 388 | Killing Bernstein Harlan Ellison 389 | King of the Hill Chad Oliver 390 | Kirinyaga Mike Resnick 391 | Kiss of Fire Harlan Ellison 392 | Knights to Move Fritz Leiber 393 | Knox Harlan Ellison 394 | Kyrie Poul Anderson 395 | Labyrinths Jorge Luis Borges 396 | Ladies and Gentlemen, This Is Your Crisis Kate Wilhelm 397 | Lamia Mutable M. John Harrison 398 | Land of the Great Horses R. A. Lafferty 399 | Last Train to Kankakee Robin Scott 400 | Laugh Track Harlan Ellison 401 | Leadership in Turbulent Times Doris Kearns Goodwin 402 | Lenny Isaac Asimov 403 | Let There Be Light Robert A. Heilein 404 | Liar! Isaac Asimov 405 | Life in Our Time Robert Bloch 406 | Life, the Universe and Everything Douglas Adams 407 | Life-Line Robert A. Heilein 408 | Liking What You See: A Documentary Ted Chiang 409 | Little Lost Robot Isaac Asimov 410 | Lollipop and the Tar Baby John Varley 411 | Lonley Women Are the Vessels of Time Harlan Ellison 412 | Looking for Company Frederik Pohl 413 | Lord of Light Roger Zelazny 414 | Lord of the Flies William Golding 415 | Lord Randy, My Son Joe L. Hensley 416 | Love Ain't Nothing but Sex Misspelled Harlan Ellison 417 | Lucy Comes To Stay Robert Bloch 418 | Madame Curie Eve Curie 419 | Making It All the Way into the Future on Gaxton Falls of the Red Planet Barry N. Malzberg 420 | Man of Letters Kate Wilhelm 421 | Man Plus Frederik Pohl 422 | Martin Fierro Jorge Luis Borges 423 | Martin the Warrior Brian Jacques 424 | Master and Commander Patrick O'Brian 425 | Mathoms from the Time Closet Gene Wolfe 426 | Mattimeo Brian Jacques 427 | Mealtime Harlan Ellison 428 | Medusa Theodore Sturgeon 429 | Mefisto in Onyx Harlan Ellison 430 | Microcosmic God Theodore Sturgeon 431 | Midnight in the Sunken Cathedral Harlan Ellison 432 | Midnight News Lisa Goldstein 433 | Mom Harlan Ellison 434 | Mona at Her Windows Harlan Ellison 435 | Mona Lisa Overdrive William Gibson 436 | Monitored Dreams & Strategic Cremations Bernard Wolfe 437 | Mono no Aware Ken Liu 438 | Monolog Philip Jose Farmer 439 | Monster vol.1 Naoki Urasawa 440 | Monster vol.2 Naoki Urasawa 441 | Monster vol.3 Naoki Urasawa 442 | Monster vol.4 Naoki Urasawa 443 | Monster vol.5 Naoki Urasawa 444 | Monster vol.6 Naoki Urasawa 445 | Monster vol.7 Naoki Urasawa 446 | Monster vol.8 Naoki Urasawa 447 | Monster vol.9 Naoki Urasawa 448 | More Than Human Theodore Sturgeon 449 | Moth Race Richard Hill 450 | Mountain Liu Cixin 451 | Mr. Costello, Hero Theodore Sturgeon 452 | Mrs. Bagley Goes to Mars Kate Wilhelm 453 | Mutations Jorge Luis Borges 454 | Nackles vr.1 Donald E. Westlake 455 | Nackles vr.2 Donald E. Westlake 456 | Nackles vr.2 Harlan Ellison 457 | Nausicaa of the Valley of the Wind vol.1 Hayao Miyazaki 458 | Nausicaa of the Valley of the Wind vol.2 Hayao Miyazaki 459 | Neither Your Jenny Nor Mine Harlan Ellison 460 | Neon Harlan Ellison 461 | Neuromancer William Gibson 462 | New Rose Hotel William Gibson 463 | Night Journey of the Dragon-Horse Xia Jia 464 | Night Meeting Ray Bradbury 465 | Night of Black Glass Harlan Ellison 466 | Nightfall Isaac Asimov 467 | Nightfall Robert Silverberg 468 | Night-Rise Katherine MacLean 469 | Nijigagara Holograph Inio Asano 470 | Nine Hundred Grandmothers R. A. Lafferty 471 | No Game for Children Harlan Ellison 472 | No Great Magic Fritz Leiber 473 | No Light in the Windows Kate Wilhelm 474 | Nothing for My Noon Meal Harlan Ellison 475 | Nova Samuel R. Delany 476 | O Ye of Little Faith Harlan Ellison 477 | Oddy and Id Alfred Bester 478 | Of Ants and Dinosaurs Liu Cixin 479 | On Exactitude and Science Jorge Luis Borges 480 | On the Downhill Slide Harlan Ellison 481 | On the Feasibility of Coal-Driven Power Stations O. R. Frisch 482 | On the Slab Harlan Ellison 483 | One Day in the Life of Ivan Denisovich Aleksandr Solzhenitsyn 484 | One for the Road Kate Wilhelm 485 | One Life, Furnished in Early Poverty Harlan Ellison 486 | One-Way Journey Miram Allen deFord 487 | Operating Systems in Depth Thomas W. Doeppner 488 | Operation Cassandra Miram Allen deFord 489 | Opium Harlan Ellison 490 | Other Worlds Frederik Pohl 491 | Out of All Them Bright Stars Nancy Kress 492 | Over the River and Through the Woods Clifford D. Simak 493 | Overlord Max Hastings 494 | Ozymandias Terry Car 495 | Paingod Harlan Ellison 496 | Paingod and Other Delusions Harlan Ellison 497 | Paladin of the Last Hour Harlan Ellison 498 | Parable of Cervantes and the Quixote Jorge Luis Borges 499 | Parable of the Palace Jorge Luis Borges 500 | Paradise Clifford D. Simak 501 | Paradiso, XXXI, 108 Jorge Luis Borges 502 | Partial Magic in the Quixote Jorge Luis Borges 503 | Pattern Recognition William Gibson 504 | Paulie Charmed the Sleeping Woman Harlan Ellison 505 | Permanent Record Edward Snowden 506 | Persona 3: Official Design Works Shigenori Soejima 507 | Persona 4 Arena: Official Design Works Shigenori Soejima 508 | Persona 4: Official Design Works Shigenori Soejima 509 | Philtre Tip Robert Bloch 510 | Picnic on Paradise Joanna Russ 511 | Pierre Menrad, Author of Don Quixote Jorge Luis Borges 512 | Planet Story Kate Wilhelm 513 | Planetes vol.1 Makoto Yukimura 514 | Planetes vol.2 Makoto Yukimura 515 | Player Piano Kurt Vonnegut 516 | Precession Edward Bryant 517 | Prelude to Foundation Isaac Asimov 518 | Presidents of War Michael Beschloss 519 | Pretty Maggie Moneyeyes Harlan Ellison 520 | Prince Myshkin, and Hold the Relish Harlan Ellison 521 | Prodigy Theodore Sturgeon 522 | Project Nightmare Robert A. Heinlein 523 | Pulling Hard Time Harlan Ellison 524 | Punky & The Yale Men Harlan Ellison 525 | Queen Emeraldas vol.1 Leiji Matsumoto 526 | Queen Emeraldas vol.2 Leiji Matsumoto 527 | Quick to Haste Miram Allen deFord 528 | Quicktime Harlan Ellison 529 | Radio Free Albemuth Philip K. Dick 530 | Ragnarok Jorge Luis Borges 531 | Rain, Rain, Go Away Harlan Ellison 532 | Rat James Patrick Kelly 533 | Reason Isaac Asimov 534 | Red Star, Winter Orbit Bruce Sterling 535 | Red Star, Winter Orbit William Gibson 536 | Redwall Brian Jacques 537 | Rendezvous with Rama Arthur C. Clarke 538 | Repent, Harlequin! Said the Ticktockman Harlan Ellison 539 | Requiem Robert A. Heilein 540 | Riders of the Purple Wage Philip Jose Farmer 541 | Riding the Dark Train Out Harlan Ellison 542 | Ringworld Larry Niven 543 | Riverworld Philip Jose Farmer 544 | Riverworld and Other Stories Philip Jose Farmer 545 | Roadside Picnic Arkady Strugatsky 546 | Roadside Picnic Boris Strugatsky 547 | Robbie Isaac Asimov 548 | Rock God Harlan Ellison 549 | Rocket Summer Ray Bradbury 550 | Runaround Isaac Asimov 551 | Sandkings George R. R. Martin 552 | Saturn, November 11th Harlan Ellison 553 | Scartaris, June 28th Harlan Ellison 554 | Schrodinger's Plague Greg Bear 555 | Schwarzschild Radius Connie Willis 556 | Second Foundation Isaac Asimov 557 | Seeing Harlan Ellison 558 | Selected Poems T. S. Eliot 559 | Selected Stories Theodore Sturgeon 560 | Sensible City Harlan Ellison 561 | Seraphim: 266613336 Wings Satoshi Kon 562 | Seventy-Two Letters Ted Chiang 563 | Sex and/or Mr. Morrison Carol Emshwiller 564 | Shadow, Shadow on the Wall Theodore Sturgeon 565 | Shall the Dust Praise Thee? Damon Knight 566 | Shatterday Harlan Ellison 567 | Shattered Like a Glass Goblin Harlan Ellison 568 | She's a Young Thing and Cannot Leaver Her Mother Harlan Ellison 569 | Shin Megami Tensei 4: Official Artworks Masayuki Doi 570 | Shoppe Keeper Harlan Ellison 571 | Silence Tadeusz Borowski 572 | Silent in Gehenna Harlan Ellison 573 | Silhouette Gene Wolfe 574 | Simulacrum Ken Liu 575 | Sir Gawain and the Green Knight J. R. R. Tolkien 576 | Skeleton Ray Bradbury 577 | Skunk Works Ben R. Rich 578 | Skunk Works Leo Janos 579 | Sky Lift Robert A. Heinlein 580 | Slippage Harlan Ellison 581 | Slow Sculpture Theodore Sturgeon 582 | Snow John Crowley 583 | So Long, and Thanks for All the Fish Douglas Adams 584 | Soft Monkey Harlan Ellison 585 | Solanin Inio Asano 586 | Solaris Stanislaw Lem 587 | Some Assembly Required Timothy S. Margush 588 | Somehow, I Don't Think We're in Kansas, Toto Harlan Ellison 589 | Somerset Dreams Kate Wilhelm 590 | Somerset Dreams and Other Fictions Kate Wilhelm 591 | Souls Joanna Russ 592 | Soundless Evening Lee Hoffman 593 | Speech Sound Octavia E. Butler 594 | Spook Country William Gibson 595 | Stable Strategies for Middle Management Eileen Gunn 596 | Stalingrad Antony Beevor 597 | Stalking the Nightmare Harlan Ellison 598 | Stand Still and Die Harlan Ellison 599 | Starship Troopers Robert A. Heinlein 600 | State Change Ken Liu 601 | State of Grace Kate Wilhelm 602 | Still-Life K. M. O'Donnell 603 | Stillwell and the American Experience in China 1911-1945 Barbara W. Tuchman 604 | Stoned Counsel H. H. Hollis 605 | Stories of Your Life and Others Ted Chiang 606 | Story of the Warrior and the Captive Maiden Jorge Luis Borges 607 | Story of Your Life Ted Chiang 608 | Strange Gifts Robert Silverberg 609 | Strange Wine Harlan Ellison 610 | Stranger in a Strange Land Robert A. Heinlein 611 | Stuffing Harlan Ellison 612 | Sturgeon is Alive and Well... Theodore Sturgeon 613 | Suicide Theodore Sturgeon 614 | Sun of China Liu Cixin 615 | Symbiosis Kate Wilhelm 616 | Take Care of Joey Theodore Sturgeon 617 | Taking Care of God Liu Cixin 618 | Tandy's Story Theodore Sturgeon 619 | Tauf Aleph Physillis Gotlieb 620 | Team of Rivals Doris Kearns Goodwin 621 | Tekkonkinkreet: Black and White Taiyo Matsumoto 622 | Tell Your Fortune Robert Bloch 623 | Test to Destruction Keith Laummer 624 | That Girl Who Knew What They Meant Theodore Sturgeon 625 | The [Widget], the [Wadget], and Boff Theodore Sturgeon 626 | The 10:00 Report is Brought to You By... Edward Bryant 627 | The 3 Most Important Things in Life Harlan Ellison 628 | The Absolutely Perfect Murder Miram Allen deFord 629 | The Adventure of Black Peter Arthur Conan Doyle 630 | The Adventure of Charles Augustus Milverton Arthur Conan Doyle 631 | The Adventure of the Gloria Scott Arthur Conan Doyle 632 | The Adventure of the Abbey Grange Arthur Conan Doyle 633 | The Adventure of the Beryl Coronet Arthur Conan Doyle 634 | The Adventure of the Blue Carbuncle Arthur Conan Doyle 635 | The Adventure of the Cardboard Box Arthur Conan Doyle 636 | The Adventure of the Copper Beeches Arthur Conan Doyle 637 | The Adventure of the Crooked Man Arthur Conan Doyle 638 | The Adventure of the Dancing Men Arthur Conan Doyle 639 | The Adventure of the Empty House Arthur Conan Doyle 640 | The Adventure of the Engineer's Thumb Arthur Conan Doyle 641 | The Adventure of the Final Problem Arthur Conan Doyle 642 | The Adventure of the Golden Pince-Nez Arthur Conan Doyle 643 | The Adventure of the Greek Interpreter Arthur Conan Doyle 644 | The Adventure of the Missing Three-Quarter Arthur Conan Doyle 645 | The Adventure of the Musgrave Ritual Arthur Conan Doyle 646 | The Adventure of the Naval Treaty Arthur Conan Doyle 647 | The Adventure of the Noble Bachelor Arthur Conan Doyle 648 | The Adventure of the Norwood Builder Arthur Conan Doyle 649 | The Adventure of the Priory School Arthur Conan Doyle 650 | The Adventure of the Reigate Squires Arthur Conan Doyle 651 | The Adventure of the Resident Patient Arthur Conan Doyle 652 | The Adventure of the Second Stain Arthur Conan Doyle 653 | The Adventure of the Silver Blaze Arthur Conan Doyle 654 | The Adventure of the Six Napoleons Arthur Conan Doyle 655 | The Adventure of the Solitary Cyclist Arthur Conan Doyle 656 | The Adventure of the Speckled Band Arthur Conan Doyle 657 | The Adventure of the Stockbroker's Clerk Arthur Conan Doyle 658 | The Adventure of the Yellow Face Arthur Conan Doyle 659 | The Age of Gold Frederik Pohl 660 | The Ajeri Diary Miram Allen deFord 661 | The Aleph Jorge Luis Borges 662 | The Aleph and Other Stories Jorge Luis Borges 663 | The Annals of the Heechee Frederik Pohl 664 | The Approach to Al-Mu'tasim Jorge Luis Borges 665 | The Argentine Writer and Tradition Jorge Luis Borges 666 | The Art of Computer Programming vol.1 Donald E. Knuth 667 | The Art of Nausicaa of the Valley of the Wind Hayao Miyazaki 668 | The Art of Persona 5 Shigenori Soejima 669 | The Art of Space Ron Miller 670 | The Avenger of Death Harlan Ellison 671 | The Babylon Lottery Jorge Luis Borges 672 | The Beast of Barsac Robert Bloch 673 | The Belonging Kind John Shirley 674 | The Belonging Kind William Gibson 675 | The Big Hunger Walter M. Miller, Jr. 676 | The Big Space Fuck Kurt Vonnegut, Jr. 677 | The Big Time Fritz Leiber 678 | The Black Cloud Fred Hoyle 679 | The Bob Dylan Tambourine Software & Satori Support Services Consortium, Ltd. Michael Bishop 680 | The Book of Skulls Robert Silverberg 681 | The Bookmaking Habits of Select Species Ken Liu 682 | The Boscombe Valley Mystery Arthur Conan Doyle 683 | The Boulevard of Broken Dreams Harlan Ellison 684 | The Boy Who Would Live Forever Frederik Pohl 685 | The Brains of Rats Michael Blumlein 686 | The Byrds Michael G. Coney 687 | The Captive Jorge Luis Borges 688 | The Cat Who Walks Through Walls Robert A. Heinlein 689 | The Catcher in the Rye J. D. Salinger 690 | The Cheese Stands Alone Harlan Ellison 691 | The Children Miram Allen deFord 692 | The Chrysalids John Wyndham 693 | The Circle Liu Cixin 694 | The Circular Ruins Jorge Luis Borges 695 | The Cistern Ray Bradbury 696 | The City of Silence Ma Boyong 697 | The Classic Horror Stories H. P. Lovecraft 698 | The Crackpots Harlan Ellison 699 | The Crowd Ray Bradbury 700 | The Dark Design Philip Jose Farmer 701 | The Dark Forest Liu Cixin 702 | The Daughter of the Tree Miram Allen deFord 703 | The Day After the Day the Martians Came Frederik Pohl 704 | The Day I Died Harlan Ellison 705 | The Day of the Triffids John Wyndham 706 | The Dead Man Jorge Luis Borges 707 | The Death of Schillinger Tadeusz Borowski 708 | The Deathbird Harlan Ellison 709 | The Demolished Man Alfred Bester 710 | The Diagnosis of Dr. Darqueangel Harlan Ellison 711 | The Difference Engine Bruce Sterling 712 | The Difference Engine William Gibson 713 | The Discarded Harlan Ellison 714 | The Dispossessed Ursula K. Le Guin 715 | The Divine Invasion Philip K. Dick 716 | The Doll-House James Cross 717 | The Dragon on the Bookshelf Harlan Ellison 718 | The Dragon on the Bookshelf Robert Silverberg 719 | The Dreaming Jewels Theodore Sturgeon 720 | The Dreams a Nightmare Dreams Harlan Ellison 721 | The Dune Encyclopedia Dr. Willis E. McNelly 722 | The Dwarf Ray Bradbury 723 | The Earth Men Ray Bradbury 724 | The Electric Kool-Aid Acid Test Tom Wolfe 725 | The Emissary Ray Bradbury 726 | The Encounter Kate Wilhelm 727 | The End Jorge Luis Borges 728 | The Evitable Conflict Isaac Asimov 729 | The Evolution of Human Science Ted Chiang 730 | The Executioner of the Malformed Children Harlan Ellison 731 | The Extraordinary Voyages of Amelie Bertrand Joanna Russ 732 | The Eyes of Heisenberg Frank Herbert 733 | The Face of Helene Bournouw Harlan Ellison 734 | The Fall of Hyperion Dan Simmons 735 | The Fearful Sphere of Pascal Jorge Luis Borges 736 | The Fellowship of the Ring J. R. R. Tolkien 737 | The Few, the Proud Harlan Ellison 738 | The Fish of Lijiang Chen Qiufan 739 | The Five Orange Pips Arthur Conan Doyle 740 | The Flower of Shazui Chen Qiufan 741 | The Forces that Crush Harlan Ellison 742 | The Forever War Joe Haldeman 743 | The Form of the Sword Jorge Luis Borges 744 | The Fountains of Paradise Arthur C. Clarke 745 | The Function of Dream Sleep Harlan Ellison 746 | The Funeral Kate Wilhelm 747 | The Fusion Bomb Kate Wilhelm 748 | The Garden of Forking Paths Jorge Luis Borges 749 | The Gateway Asteroid Frederik Pohl 750 | The Gateway Trip Frederik Pohl 751 | The Gernsback Continum William Gibson 752 | The Girl From Mars Robert Bloch 753 | The Goddess in the Ice Harlan Ellison 754 | The Godmakers Frank Herbert 755 | The Gods Lie. Kaori Ozaki 756 | The God's Script Jorge Luis Borges 757 | The Gods Themselves Isaac Asimov 758 | The Golden Helix Theodore Sturgeon 759 | The Golden Man Philip K. Dick 760 | The Great Gatsby F. Scott Fitzgerald 761 | The Green Morning Ray Bradbury 762 | The Guns of August Barbara W. Tuchman 763 | The Handler Damon Knight 764 | The Happy Breed John T. Sladek 765 | The Heart of the Other Side George Gamow 766 | The Henry Miller Dawn Patrol Philip Jose Farmer 767 | The Hitchhiker's Guide to the Galaxy Douglas Adams 768 | The Hobbit J. R. R. Tolkien 769 | The Home Planet Frederik Pohl 770 | The Hounds Kate Wilhelm 771 | The Hour That Stretches Harlan Ellison 772 | The House of Asterion Jorge Luis Borges 773 | The House the Blakeneys Built Avram Davidson 774 | The Immortal Jorge Luis Borges 775 | The Incredible Voyage Tristan Jones 776 | The Indian Spirit Guide Robert Bloch 777 | The Infinity Box Kate Wilhelm 778 | The Invasion Robert Willey 779 | The January Offensive Tadeusz Borowski 780 | The Jar Ray Bradbury 781 | The Jigsaw Man Larry Niven 782 | The Jungle Rot Kid on the Nod Philip Jose Farmer 783 | The Korean War Max Hastings 784 | The Lake Ray Bradbury 785 | The Lake Was Full of Artificial Things Karen Joy Fowler 786 | The Last Days of the Captain Kate Wilhelm 787 | The Last Generation? Miram Allen deFord 788 | The Lathe of Heaven Ursula K. Le Guin 789 | The Leaser of Two Evils Philip Jose Farmer 790 | The Library of Babel Jorge Luis Borges 791 | The Life of Anybody Robert Sheckley 792 | The Lingering Scent of Woodsmoke Harlan Ellison 793 | The Literomancer Ken Liu 794 | The Litigation Master and the Monkey King Ken Liu 795 | The Living Demons Robert Bloch 796 | The Locusts Ray Bradbury 797 | The Long Dark Tea-Time of the Soul Douglas Adams 798 | The Long Space Age Alexander MacDonald 799 | The Long Years Ray Bradbury 800 | The Longest Fall Liu Cixin 801 | The Lost World Michael Crichton 802 | The Lottery in Babylon Jorge Luis Borges 803 | The Lucky Strike Kim Stanley Robinson 804 | The Luggage Store Ray Bradbury 805 | The Maker Jorge Luis Borges 806 | The Malley System Miriam Allen deFord 807 | The Man in the High Castle Philip K. Dick 808 | The Man on the Threshold Jorge Luis Borges 809 | The Man Upstairs Ray Bradbury 810 | The Man Who Ended History: A Documentary Ken Liu 811 | The Man Who Lost the Sea Theodore Sturgeon 812 | The Man Who Rowed Christopher Columbus Ashore Harlan Ellison 813 | The Man Who Sold the Moon Robert A. Heinlein 814 | The Man Who Was Heavily into Revenge Harlan Ellison 815 | The Man Who Went to the Moon-Twice Howard Rodman 816 | The Man With English Horace L. Gold 817 | The Man with the Package Tadeusz Borowski 818 | The Man With the Twisted Lips Arthur Conan Doyle 819 | The Man without a Planet Kate Wilhelm 820 | The Manhattan Project Al Cimino 821 | The March of Folly Barbara W. Tuchman 822 | The Mark Gable Foundation Leo Szilard 823 | The Martian Ray Bradbury 824 | The Martian Chronicles Ray Bradbury 825 | The Menace from Earth Robert A. Heinlein 826 | The Merchants of Venus Frederik Pohl 827 | The Micro-Age Liu Cixin 828 | The Mile-Long Spaceship Kate Wilhelm 829 | The Milk of Paradise James Tiptree, Jr. 830 | The Million-Year Picnic Ray Bradbury 831 | The Miracle of the Broom Closet W. Norbert 832 | The Mirrors of Enigmas Jorge Luis Borges 833 | The Moon is a Harsh Mistress Robert A. Heinlein 834 | The Mountains of Sunset, the Mountains of Dawn Vonda N. McIntyre 835 | The Mountebank Jorge Luis Borges 836 | The Museum on Cyclops Avenue Harlan Ellison 837 | The Musicians Ray Bradbury 838 | The Naming of Names Ray Bradbury 839 | The New Atlantis Robert Silverberg 840 | The New Atlantis Ursula K. Le Guin 841 | The New York Review of Bird Harlan Ellison 842 | The Next in Line Ray Bradbury 843 | The Night That All Time Broke Out Brian W. Aldiss 844 | The Norton Book of Science Fiction Brian Attebery 845 | The Norton Book of Science Fiction Ursula K. Le Guin 846 | The October Country Ray Bradbury 847 | The Off Season Ray Bradbury 848 | The Old Man and the Sea Ernest Hemingway 849 | The Old Ones Ray Bradbury 850 | The Oldest Soldier Fritz Leiber 851 | The Original Hitchhiker Radio Scripts Douglas Adams 852 | The Original Illustrated Sherlock Holmes Arthur Conan Doyle 853 | The Other Death Jorge Luis Borges 854 | The Other Eye of Polyphemus Harlan Ellison 855 | The Outcast of Redwall Brian Jacques 856 | The Outpost Undiscovered by Tourists Harlan Ellison 857 | The Oxford Book of English Verse Christopher Ricks 858 | The Pale Silver Dollar of the Moon Pays Its Way and Makes Change vr.1 Harlan Ellison 859 | The Pale Silver Dollar of the Moon Pays Its Way and Makes Change vr.2 Harlan Ellison 860 | The Paper Menagerie Ken Liu 861 | The Patterns of Drone Theodore Sturgeon 862 | The People Who Walked On Tadeusz Borowski 863 | The Perfect Match Ken Liu 864 | The Peripheral William Gibson 865 | The Phantom of the Sewers Philip Jose Farmer 866 | The Place with No Name Harlan Ellison 867 | The Plot Jorge Luis Borges 868 | The Plot Is the Thing Robert Bloch 869 | The Private War of Private Jacob Joe Haldeman 870 | The Problem of the Sore Bridge-Among Others Philip Jose Farmer 871 | The Proud Tower Barbara W. Tuchman 872 | The Prowler in the City on the Edge of Forever Harlan Ellison 873 | The Recognition J. G. Ballard 874 | The Red Canary Kate Wilhelm 875 | The Red-Headed League Arthur Conan Doyle 876 | The Region Between Harlan Ellison 877 | The Regular Ken Liu 878 | The Resurgence of Miss Ankle-Strap Wedgie Harlan Ellison 879 | The Return of the King J. R. R. Tolkien 880 | The Right Stuff Tom Wolfe 881 | The Rise of Endymion Dan Simmons 882 | The Road Cormac McCarthy 883 | The Roads Must Roll Robert A. Heilein 884 | The Salmon of Doubt Douglas Adams 885 | The Season of Babies Miram Allen deFord 886 | The Secret Miracle Jorge Luis Borges 887 | The Sect of Phoenix Jorge Luis Borges 888 | The Settlers Ray Bradbury 889 | The Sex Opposite Theodore Sturgeon 890 | The Shape of the Sword Jorge Luis Borges 891 | The Shore Ray Bradbury 892 | The Silent Towns Ray Bradbury 893 | The Silver Corridor Harlan Ellison 894 | The Simple Way Clifford D. Simak 895 | The Singers W. Grey Walter 896 | The Sirens of Titan Kurt Vonnegut 897 | The Skills of Xanadu Theodore Sturgeon 898 | The Sky is Burning Harlan Ellison 899 | The Small Assaassin Ray Bradbury 900 | The Smiling Future Miram Allen deFord 901 | The Sound and the Fury William Faulkner 902 | The South Jorge Luis Borges 903 | The Space Merchants C. M. Kornbluth 904 | The Space Merchants Frederik Pohl 905 | The Stars My Destination Alfred Bester 906 | The Starseekers Frederik Pohl 907 | The Start of the End of It All Carol Emshwiller 908 | The Stochastic Man Robert Silverberg 909 | The Summer Night Ray Bradbury 910 | The Sun also Rises Ernest Hemingway 911 | The Superior Sex Miram Allen deFord 912 | The Supper Tadeusz Borowski 913 | The Sycthe Ray Bradbury 914 | The Taxpayer Ray Bradbury 915 | The Tell-Tale Heart and Other Writings Edgar Allan Poe 916 | The Tempest William Shakespeare 917 | The Test Stand Lee Corey 918 | The Test-Tube Creature, Afterward Joan Bernott 919 | The Theologians Jorge Luis Borges 920 | The Third Ear Curt Siodmak 921 | The Third Expedition Ray Bradbury 922 | The Three Stigmata of Palmer Eldritch Philip K. Dick 923 | The Three-Body Problem Liu Cixin 924 | The Tides of the Mind David Gelernter 925 | The Time Piece Kate Wilhelm 926 | The Transit of Venus Miram Allen deFord 927 | The Transmigration of Timothy Archer Philip K. Dick 928 | The Tree Lord of Imeten Tom Purdom 929 | The Trial Franz Kafka 930 | The Two Kings and the Two Labyrinths Jorge Luis Borges 931 | The Two Towers J. R. R. Tolkien 932 | The Ultimate Hitchhiker's Guide Douglas Adams 933 | The Universe of Robert Blake Harlan Ellison 934 | The Unspeakable Betrothal Robert Bloch 935 | The Very Last Day of a Good Woman Harlan Ellison 936 | The View from the Stars Walter M. Miller, Jr. 937 | The Village Kate Wilhelm 938 | The Visit Frederik Pohl 939 | The Voice of the Sonar in My Veriform Appendix Philip Jose Farmer 940 | The Volcano Philip Jose Farmer 941 | The Wages of Humanity Liu Cixin 942 | The Waiting Jorge Luis Borges 943 | The Wall and the Books Jorge Luis Borges 944 | The Wandering Earth Liu Cixin 945 | The War at Home Lewis Shiner 946 | The Warlord of Saturn's Moon Eleanor Aranason 947 | The Watchers Ray Bradbury 948 | The Watchful Poker Chip of H. Matisse Ray Bradbury 949 | The Waves Ken Liu 950 | The Westing Game Ellen Raskin 951 | The Whimper of Whipped Dogs Harlan Ellison 952 | The Will Walter M. Miller, Jr. 953 | The Wind Ray Bradbury 954 | The Wind Beyond the Mountains Harlan Ellison 955 | The Windup Girl Paolo Bacigalupi 956 | The Wine Has Been Left Open Too Long and the Memory Has Gone Flat Harlan Ellison 957 | The Winter Flies Fritz Leiber 958 | The Winter Market William Gibson 959 | The Witness Jorge Luis Borges 960 | The Women Men Don't See James Tiptree, Jr. 961 | The Wonderful Death of Dudley Stone Ray Bradbury 962 | The Word for World is Forrest Ursula K. Le Guin 963 | The World Inside Robert Silverberg 964 | The World of Professor Layton Jun Suzuki 965 | The World of Stone Tadeusz Borowski 966 | The Writing of the God Jorge Luis Borges 967 | The Year of the Jackpot Robert A. Heinlein 968 | The Year of the Rat Chen Qiufan 969 | The Yellow Rose Jorge Luis Borges 970 | The Zahir Jorge Luis Borges 971 | The Zimmermann Telegram Barbara W. Tuchman 972 | Theme of the Traitor and Hero Jorge Luis Borges 973 | There Was an Old Woman Ray Bradbury 974 | There Will Come Soft Rains Ray Bradbury 975 | They Shall Have Stars James Blish 976 | Things Lost Thomas M. Disch 977 | This Immortal Roger Zelazny 978 | This Way for the Gas, Ladies and Gentlemen Tadeusz Borowski 979 | Thorns Robert Silverberg 980 | Thousand Cranes Yasunari Kawabata 981 | Three Versions of Judas Jorge Luis Borges 982 | Throwback Miram Allen deFord 983 | Thunder and Roses Theodore Sturgeon 984 | Time Travel for Pedestrians Ray Nelson 985 | Tiny Ally Harlan Ellison 986 | Tissue James Sallis 987 | Tlon, Uqbar, Orbis Teritus Jorge Luis Borges 988 | To Be Continued Robert Silverberg 989 | To Explain to Mrs. Thompson Phillip Latham 990 | To Here and the Easel Theodore Sturgeon 991 | To Kill a Mockingbird Harper Lee 992 | To Open the Sky Robert Silverberg 993 | Toenails Jorge Luis Borges 994 | Tongtong's Summer Xia Jia 995 | Totenbuch A. Parra (y Figuerado) 996 | Touched With Fire Ray Bradbury 997 | Tower of Babylon Ted Chiang 998 | Tower of Glass Robert Silverberg 999 | Tracking Level Harlan Ellison 1000 | Transcending Destiny Harlan Ellison 1001 | Treasure Island Robert Lewis Stevenson 1002 | Trigun Omnibus Yasuhiro Nightow 1003 | Triss Brian Jacques 1004 | Trouble With Ants Clifford D. Simak 1005 | Try and Change the Past Fritz Leiber 1006 | Twink Theodore Sturgeon 1007 | Ubik Philip K. Dick 1008 | Unaccompanied Sonata Orson Scott Card 1009 | Uncle Einar Ray Bradbury 1010 | Uncle Fremmis Theodore Sturgeon 1011 | Underground Robert Bloch 1012 | Understand Ted Chiang 1013 | Unlocking the Air Ursula K. Le Guin 1014 | Usher II Ray Bradbury 1015 | Valerie Harlan Ellison 1016 | Valery as Symbol Jorge Luis Borges 1017 | VALIS Philip K. Dick 1018 | Vaster than Empires and More Slow Ursula K. Le Guin 1019 | Venus Plus X Theodore Sturgeon 1020 | Vietnam: An Epic Tragedy, 1945-1975 Max Hastings 1021 | Virtual Light William Gibson 1022 | Visionary Harlan Ellison 1023 | Walden; or, Life in the Woods Henry David Thoreau 1024 | Wandering Island vol.1 Kenji Tsuruta 1025 | Wandering Island vol.2 Kenji Tsuruta 1026 | Wanted in Surgery Harlan Ellison 1027 | Watchmen Alan Moore 1028 | Water Is for Washing Robert A. Heinlein 1029 | Watership Down Richard Adams 1030 | Way in the Middle of the Air Ray Bradbury 1031 | Way Station Clifford D. Simak 1032 | We Yevgeny Zamyatin 1033 | We See Things Differently Bruce Sterling 1034 | Web of the City Harlan Ellison 1035 | What Happened to Auguste Clarot? Larry Eisenberg 1036 | What I Did on My Vaction This Summer by Little Bobby Hirschhorn, Age 27 Harlan Ellison 1037 | What's It Like Out There? Edmond Hamilton 1038 | When Auld's Acquaintance is Forgot Harlan Ellison 1039 | When I was a Hired Gun Harlan Ellison 1040 | When I Was Miss Dow Sonya Dorman 1041 | When it Changed Joanna Russ 1042 | When the Bentfin Boomer Boys on Old New Alabama Richard A. Lupoff 1043 | When the Change-Winds Blow Fritz Leiber 1044 | Where Have You Been, Billy Boy, Billy Boy? Kate Wilhelm 1045 | Where I Shall Dwell in the Next World Harlan Ellison 1046 | Where Late the Sweet Birds Sang Kate Wilhelm 1047 | With a Finger in My I David Gerrold 1048 | With Her Eyes Liu Cixin 1049 | With Virgin Oddum at the East Pole Harlan Ellison 1050 | Working with the Little People Harlan Ellison 1051 | Would You Do It for a Penny Harlan Ellison 1052 | Xenogenesis Miriam Allen deFord 1053 | Yeager Chuck Yeager 1054 | Yeager Leo Janos 1055 | Ylla Ray Bradbury 1056 | You Triflin' Skunk Walter M. Miller, Jr. 1057 | Zero Gee Ben Bova 1058 | Zero History William Gibson -------------------------------------------------------------------------------- /tests/data/books.tsv: -------------------------------------------------------------------------------- 1 | 1984 science fiction 1950 328 2 | 2001: A Space Odyssey science fiction 1968 221 3 | 20th Century Boys vol.1 science fiction 2018 413 4 | 20th Century Boys vol.2 science fiction 2018 412 5 | 20th Century Boys vol.3 science fiction 2019 410 6 | 20th Century Boys vol.4 science fiction 2019 416 7 | 20th Century Boys vol.5 science fiction 2019 422 8 | 20th Century Boys vol.6 science fiction 2019 456 9 | A Canticle for Leibowitz science fiction 1959 338 10 | A Case of Conscience science fiction 1958 188 11 | A Clash of Cymbals science fiction 1959 199 12 | A Clockwork Orange science fiction 1962 139 13 | A Farewell to Arms american lit 1929 332 14 | A Life for the Stars science fiction 1962 147 15 | A Scanner Darkly science fiction 1977 217 16 | A Time of Changes science fiction 1975 205 17 | A Tour of C++ 2nd textbook 2018 238 18 | Absalom, Absalom! american lit 1936 303 19 | Again, Dangerous Visions science fiction 1972 830 20 | Akira vol.1 science fiction 2010 363 21 | Akira vol.2 science fiction 2010 301 22 | Akira vol.3 science fiction 2010 282 23 | Akira vol.4 science fiction 2010 394 24 | Akira vol.5 science fiction 2011 413 25 | Akira vol.6 science fiction 2011 434 26 | Algorithms 4th textbook 2011 959 27 | All Tomorrow's Parties science fiction 1999 339 28 | And Chaos Died science fiction 1970 189 29 | Angry Candy science fiction 1988 324 30 | Animal Farm british lit 1956 139 31 | Approaching Oblivion science fiction 1974 164 32 | Army of None history 2018 436 33 | Battle for the Mind informative 1954 350 34 | Beowulf fantasy 1994 92 35 | Beyond the Blue Event Horizon science fiction 1980 309 36 | Bible and Sword history 1984 346 37 | Blame! vol.1 science fiction 2016 348 38 | Blame! vol.2 science fiction 2016 374 39 | Blame! vol.3 science fiction 2017 352 40 | Blame! vol.4 science fiction 2017 367 41 | Blame! vol.5 science fiction 2017 334 42 | Blame! vol.6 science fiction 2017 326 43 | Blue Spring fiction 2004 213 44 | Brain Wave science fiction 1954 166 45 | Brave New World science fiction 1932 259 46 | Burning Chrome science fiction 1986 191 47 | C Primer Plus 5th textbook 2005 959 48 | C++ Primer 5th textbook 2013 938 49 | Capitalism Without Capital economics 2018 278 50 | Captain Harlock: The Classic Collection vol.1 science fiction 2018 396 51 | Captain Harlock: The Classic Collection vol.2 science fiction 2018 397 52 | Captain Harlock: The Classic Collection vol.3 science fiction 2019 392 53 | Catch-22 american lit 1955 453 54 | Caviar science fiction 1955 182 55 | Changewar science fiction 1983 198 56 | Chapterhouse: Dune science fiction 1985 436 57 | Childhood's End science fiction 1953 212 58 | Children of Dune science fiction 1976 408 59 | Children of the Sea vol.1 fiction 2013 316 60 | Children of the Sea vol.2 fiction 2013 315 61 | Children of the Sea vol.3 fiction 2013 334 62 | Children of the Sea vol.4 fiction 2013 324 63 | Children of the Sea vol.5 fiction 2013 329 64 | City science fiction 1952 267 65 | Colossus history 2006 462 66 | Conversations With Jorge Luis Borges interviews 1968 144 67 | Count Zero science fiction 1986 246 68 | Crome Yellow british lit 1921 174 69 | Dandelion Wine american lit 1957 239 70 | Dangerous Visions science fiction 1967 598 71 | Death and the Penguin mystery 1996 228 72 | Deathbird Stories science fiction 1975 347 73 | Death's End science fiction 2016 604 74 | Destined for War history 2017 364 75 | Dirk Gently's Holistic Detective Agency science fiction 1987 306 76 | Distrust That Particular Flavor essays 2012 255 77 | Do Androids Dream of Electric Sheep? science fiction 1968 244 78 | Doctor Zhivago east euro lit 1957 456 79 | Don Quixote adventure 1950 940 80 | Double Star science fiction 1956 243 81 | Downward to the Earth science fiction 1970 181 82 | Dr. Bloodmoney science fiction 1965 298 83 | Dune science fiction 1965 883 84 | Dune Messiah science fiction 1969 279 85 | Dying Inside science fiction 1972 200 86 | Earthman, Come Home science fiction 1955 256 87 | Earthman, Go Home! science fiction 1962 191 88 | Emanon vol.1: Memories of Emanon science fiction 2019 190 89 | Emanon vol.2: Emanon Wanderer pt.1 science fiction 2019 213 90 | Emanon vol.3: Emanon Wanderer pt.2 science fiction 2019 233 91 | Empire Star science fiction 1966 102 92 | Ender's Game science fiction 1977 324 93 | Endless Frontier history 1997 527 94 | Endymion science fiction 1995 563 95 | Eniac history 1999 262 96 | Explorers of Space science fiction 1975 253 97 | Fahrenheit 451 science fiction 1953 190 98 | Fault-Tolerant Computer System Designs textbook 1996 550 99 | Fiasco science fiction 1987 322 100 | Ficciones fiction 1956 174 101 | Flow My Tears, the Policeman Said science fiction 1974 231 102 | Flowers for Algernon science fiction 1966 216 103 | For Whom the Bell Tolls american lit 1940 507 104 | Forward the Foundation science fiction 1993 435 105 | Foundation science fiction 1951 296 106 | Foundation and Earth science fiction 1986 494 107 | Foundation and Empire science fiction 1952 282 108 | Foundation's Edge science fiction 1982 426 109 | Gateway science fiction 1977 313 110 | Ghost in the Shell science fiction 2009 348 111 | Ghost in the Shell vol.2: Man-Machine Interface science fiction 2010 306 112 | Ghost in the Shell vol.1.5: Human-Error Processor science fiction 2007 176 113 | Giganto Maxia fantasy 2016 232 114 | God Emperor of Dune science fiction 1981 423 115 | Hamlet tragedy 1599 287 116 | Hawksbill Station science fiction 1968 185 117 | Heart of Darkness east euro lit 1899 166 118 | Heechee Rendezvous science fiction 1984 331 119 | Heretics of Dune science fiction 1984 480 120 | Houston, Houston, Do You Read? science fiction 1976 92 121 | Hyperion science fiction 1989 482 122 | I Will Fear No Evil science fiction 1970 512 123 | I, Robot science fiction 1950 192 124 | Ichi-F nonfiction 2017 550 125 | Idoru science fiction 1996 383 126 | Inferno: The World at War, 1939-1945 informative 2012 729 127 | Into the Wild nonfiction 1996 207 128 | Into Thin Air nonfiction 1997 404 129 | Invisible Man american lit 1952 581 130 | Invisible Planets science fiction 2016 393 131 | Julius Caesar tragedy 1599 209 132 | Jurassic Park science fiction 1990 399 133 | Labyrinths fiction 2007 256 134 | Leadership in Turbulent Times history 2018 473 135 | Life, the Universe and Everything science fiction 1982 162 136 | Lord of Light science fiction 1967 296 137 | Lord of the Flies british lit 1954 208 138 | Love Ain't Nothing but Sex Misspelled science fiction 1968 380 139 | Madame Curie history 1939 390 140 | Man Plus science fiction 1976 277 141 | Martin the Warrior fantasy 1994 376 142 | Master and Commander adventure 1970 408 143 | Mattimeo fantasy 1990 432 144 | Mona Lisa Overdrive science fiction 1988 308 145 | Monster vol.1 thriller 2014 422 146 | Monster vol.2 thriller 2014 398 147 | Monster vol.3 thriller 2015 430 148 | Monster vol.4 thriller 2015 412 149 | Monster vol.5 thriller 2015 404 150 | Monster vol.6 thriller 2015 400 151 | Monster vol.7 thriller 2016 410 152 | Monster vol.8 thriller 2016 424 153 | Monster vol.9 thriller 2016 470 154 | More Than Human science fiction 1953 188 155 | Nausicaa of the Valley of the Wind vol.1 fantasy 2012 548 156 | Nausicaa of the Valley of the Wind vol.2 fantasy 2012 533 157 | Nebula Winners Fifteen science fiction 1981 223 158 | Neuromancer science fiction 1984 271 159 | Nightfall science fiction 1990 339 160 | Nijigagara Holograph fiction 2015 200 161 | Nova science fiction 1968 215 162 | One Day in the Life of Ivan Denisovich east euro lit 1962 210 163 | Operating Systems in Depth textbook 2011 444 164 | Overlord history 1984 462 165 | Paingod and Other Delusions science fiction 1965 157 166 | Pattern Recognition science fiction 2003 356 167 | Permanent Record history 2019 340 168 | Persona 3: Official Design Works art 2006 141 169 | Persona 4 Arena: Official Design Works art 2012 176 170 | Persona 4: Official Design Works art 2008 191 171 | Picnic on Paradise science fiction 1968 157 172 | Planetes vol.1 science fiction 2015 524 173 | Planetes vol.2 science fiction 2016 524 174 | Player Piano science fiction 1952 320 175 | Prelude to Foundation science fiction 1988 434 176 | Presidents of War history 2018 740 177 | Queen Emeraldas vol.1 science fiction 2016 415 178 | Queen Emeraldas vol.2 science fiction 2017 423 179 | Radio Free Albemuth science fiction 1985 214 180 | Redwall fantasy 1986 333 181 | Rendezvous with Rama science fiction 1973 243 182 | Riders of the Purple Wage science fiction 1992 216 183 | Ringworld science fiction 1970 288 184 | Riverworld and Other Stories science fiction 1979 264 185 | Roadside Picnic science fiction 1972 209 186 | Second Foundation science fiction 1953 279 187 | Selected Poems american lit 1954 114 188 | Selected Stories science fiction 2000 439 189 | Seraphim: 266613336 Wings science fiction 2015 268 190 | Shatterday science fiction 1980 332 191 | Shin Megami Tensei 4: Official Artworks art 2013 208 192 | Sir Gawain and the Green Knight fantasy 1975 212 193 | Skunk Works history 1994 372 194 | Slippage science fiction 1997 359 195 | So Long, and Thanks for All the Fish science fiction 1984 214 196 | Solanin fiction 2008 432 197 | Solaris science fiction 1961 223 198 | Some Assembly Required informative 2012 611 199 | Somerset Dreams and Other Fictions science fiction 1979 174 200 | Souls fantasy 1982 84 201 | Spook Country science fiction 2007 480 202 | Stalingrad history 1998 493 203 | Stalking the Nightmare science fiction 1982 301 204 | Starship Troopers science fiction 1959 335 205 | Stillwell and the American Experience in China 1911-1945 history 1971 794 206 | Stories of Your Life and Others science fiction 2002 281 207 | Strange Gifts science fiction 1975 191 208 | Strange Wine science fiction 1979 316 209 | Stranger in a Strange Land science fiction 1961 438 210 | Sturgeon is Alive and Well... science fiction 1971 207 211 | Team of Rivals history 2005 757 212 | Tekkonkinkreet: Black and White fiction 2007 614 213 | The Aleph and Other Stories fiction 1998 210 214 | The Annals of the Heechee science fiction 1987 341 215 | The Art of Computer Programming vol.1 textbook 1997 652 216 | The Art of Nausicaa of the Valley of the Wind art 2007 207 217 | The Art of Persona 5 art 2017 447 218 | The Art of Space art 2014 224 219 | The Big Time science fiction 1958 184 220 | The Book of Skulls science fiction 1972 222 221 | The Boy Who Would Live Forever science fiction 2004 452 222 | The Cat Who Walks Through Walls science fiction 1985 388 223 | The Catcher in the Rye american lit 1945 214 224 | The Chrysalids science fiction 1955 200 225 | The Classic Horror Stories horror 2013 487 226 | The Dark Forest science fiction 2015 512 227 | The Day of the Triffids science fiction 1951 191 228 | The Demolished Man science fiction 1954 175 229 | The Difference Engine science fiction 1991 429 230 | The Dispossessed science fiction 1974 311 231 | The Divine Invasion science fiction 1981 260 232 | The Dreaming Jewels science fiction 1950 174 233 | The Dune Encyclopedia encyclopedia 1985 526 234 | The Electric Kool-Aid Acid Test informative 1968 416 235 | The Expert Dreamers science fiction 1962 248 236 | The Eyes of Heisenberg science fiction 1966 158 237 | The Fall of Hyperion science fiction 1990 518 238 | The Fellowship of the Ring fantasy 1954 458 239 | The Forever War science fiction 1974 254 240 | The Fountains of Paradise science fiction 1980 305 241 | The Gateway Trip science fiction 1990 245 242 | The Godmakers science fiction 1972 221 243 | The Gods Lie. fiction 2016 216 244 | The Gods Themselves science fiction 1972 288 245 | The Great Gatsby american lit 1952 180 246 | The Guns of August history 1962 606 247 | The Hitchhiker's Guide to the Galaxy science fiction 1979 215 248 | The Hobbit fantasy 1937 305 249 | The Incredible Voyage nonfiction 1977 390 250 | The Infinity Box science fiction 1975 272 251 | The Korean War history 1987 389 252 | The Lathe of Heaven science fiction 1971 175 253 | The Living Demons horror 1967 156 254 | The Long Dark Tea-Time of the Soul science fiction 1988 307 255 | The Long Space Age history 2017 258 256 | The Lost World science fiction 1995 430 257 | The Man in the High Castle science fiction 1962 259 258 | The Man Who Sold the Moon science fiction 1951 267 259 | The Manhattan Project history 2016 187 260 | The March of Folly history 1984 447 261 | The Martian Chronicles science fiction 1950 181 262 | The Menace from Earth science fiction 1962 189 263 | The Mile-Long Spaceship science fiction 1963 160 264 | The Moon is a Harsh Mistress science fiction 1966 382 265 | The New Atlantis science fiction 1975 182 266 | The Norton Book of Science Fiction science fiction 1993 861 267 | The October Country science fiction 1956 306 268 | The Old Man and the Sea american lit 1952 127 269 | The Original Hitchhiker Radio Scripts science fiction 1985 248 270 | The Original Illustrated Sherlock Holmes mystery 1976 636 271 | The Outcast of Redwall fantasy 1995 367 272 | The Oxford Book of English Verse british lit 1999 668 273 | The Paper Menagerie science fiction 2016 450 274 | The Peripheral science fiction 2014 486 275 | The Proud Tower history 1966 615 276 | The Return of the King fantasy 1955 466 277 | The Right Stuff nonfiction 1970 352 278 | The Rise of Endymion science fiction 1997 709 279 | The Road thriller 2006 287 280 | The Salmon of Doubt fiction 2002 299 281 | The Sirens of Titan science fiction 1959 224 282 | The Sound and the Fury american lit 1929 326 283 | The Space Merchants science fiction 1953 216 284 | The Stars My Destination science fiction 1956 234 285 | The Stochastic Man science fiction 1976 240 286 | The Sun also Rises american lit 1926 251 287 | The Tell-Tale Heart and Other Writings horror 1982 419 288 | The Tempest tragedy 1599 177 289 | The Third Ear science fiction 1971 254 290 | The Three Stigmata of Palmer Eldritch science fiction 1964 230 291 | The Three-Body Problem science fiction 2014 399 292 | The Tides of the Mind nonfiction 2016 267 293 | The Transmigration of Timothy Archer science fiction 1991 255 294 | The Tree Lord of Imeten science fiction 1966 152 295 | The Trial east euro lit 1925 271 296 | The Two Towers fantasy 1954 398 297 | The Ultimate Hitchhiker's Guide science fiction 2005 815 298 | The View from the Stars science fiction 1965 192 299 | The Wandering Earth science fiction 2013 478 300 | The Westing Game mystery 1978 182 301 | The Windup Girl science fiction 2015 466 302 | The World Inside science fiction 1970 167 303 | The World of Professor Layton art 2015 191 304 | The Zimmermann Telegram history 1966 225 305 | They Shall Have Stars science fiction 1956 181 306 | This Immortal science fiction 1966 184 307 | This Way for the Gas, Ladies and Gentlemen east euro lit 1959 180 308 | Thorns science fiction 1967 222 309 | Thousand Cranes asian lit 1965 144 310 | To Kill a Mockingbird american lit 1960 376 311 | To Open the Sky science fiction 1967 222 312 | Tower of Glass science fiction 1971 184 313 | Treasure Island adventure 1882 202 314 | Trigun Omnibus science fiction 2013 691 315 | Triss fantasy 2002 389 316 | Ubik science fiction 1969 216 317 | VALIS science fiction 1991 241 318 | Venus Plus X science fiction 1960 160 319 | Vietnam: An Epic Tragedy, 1945-1975 history 2018 857 320 | Virtual Light science fiction 1993 352 321 | Walden; or, Life in the Woods essays 1854 216 322 | Wandering Island vol.1 fiction 2016 198 323 | Wandering Island vol.2 fiction 2018 190 324 | Watchmen science fiction 1986 414 325 | Watership Down fantasy 1973 478 326 | Way Station science fiction 1963 190 327 | We science fiction 1924 226 328 | Web of the City thriller 1958 284 329 | What's It Like Out There? science fiction 1974 320 330 | Where Late the Sweet Birds Sang science fiction 1976 207 331 | Xenogenesis science fiction 1969 231 332 | Yeager history 1985 331 333 | Zero History science fiction 2010 529 -------------------------------------------------------------------------------- /tests/data/collected.tsv: -------------------------------------------------------------------------------- 1 | !!!The!!Teddy!Crazy!!Show!!! Stalking the Nightmare 14 2 | (Learning About) Machine Sex The Norton Book of Science Fiction 16 3 | ...the World, as we Know 't The Norton Book of Science Fiction 16 4 | 2004, or Thereabouts The Norton Book of Science Fiction 5 5 | A Biography of Tadeo Isidoro Cruz (1829-1874) The Aleph and Other Stories 4 6 | A Brief History of the Trans-Pacific Tunnel The Paper Menagerie and Other Stories 19 7 | A Case of Identity The Original Illustrated Sherlock Holmes 12 8 | A Day at Harmenz This Way for the Gas, Ladies and Gentlemen 32 9 | A Deskful of Girls Changewar 44 10 | A Dialog About A Dialog The Aleph and Other Stories 1 11 | A Dialog Between Dead Men The Aleph and Other Stories 3 12 | A Feast of Demons The Expert Dreamers 26 13 | A Few Things I Know About While Away The Norton Book of Science Fiction 13 14 | A Hundred Ghosts Parade Tonight Invisible Planets 20 15 | A is for Automation The Mile-Long Spaceship 17 16 | A Midwinter's Tale The Norton Book of Science Fiction 13 17 | A Momentary Taste of Being The New Atlantis 174 18 | A Mouse in the Walls of the Global Village Again, Dangerous Visions 15 19 | A New Refutation of Time Labyrinths 20 20 | A Note on (toward) Bernard Shaw Labyrinths 4 21 | A Path Through the Darkness Love Ain't Nothing but Sex Misspelled 14 22 | A Prayer for No One's Enemies Love Ain't Nothing but Sex Misspelled 21 23 | A Problem Labyrinths 2 24 | A Problem The Aleph and Other Stories 2 25 | A Scandal in Bohemia The Original Illustrated Sherlock Holmes 15 26 | A Toy for Juliette Dangerous Visions 15 27 | A True Story This Way for the Gas, Ladies and Gentlemen 4 28 | A Visit This Way for the Gas, Ladies and Gentlemen 3 29 | A Way of Thinking Selected Stories 29 30 | Adrift Just Off the Islets of Langerhans: Latitude 38o54'N, Longitude 77o00'13W Deathbird Stories 40 31 | Adrift on the Policy Level The Expert Dreamers 24 32 | Aesop City 42 33 | After the Days of Dead-Eye 'Dee The Norton Book of Science Fiction 11 34 | All in Good Time Xenogensis 10 35 | All the Birds Come Home to Roost Shatterday 18 36 | All the Flavors The Paper Menagerie and Other Stories 89 37 | All the Lies Lies That Are My Life Shatterday 58 38 | All The People Strange Gifts 12 39 | All the Sound of Fear Earthman, Go Home! 12 40 | Along the Scenic Route Deathbird Stories 14 41 | Alpha Ralpha Boulevard The Norton Book of Science Fiction 25 42 | Amateur in Chancery The Expert Dreamers 18 43 | America The Norton Book of Science Fiction 24 44 | An Advanced Readers' Picture Book of Comparative Cognition The Paper Menagerie and Other Stories 15 45 | An Examination of the Work of Herbert Quain Ficciones 6 46 | And the Angels Sing The Norton Book of Science Fiction 17 47 | And the Sea Like Mirrors Again, Dangerous Visions 20 48 | Andover and the Android The Mile-Long Spaceship 13 49 | Anybody Else Like Me? The View from the Stars 17 50 | Anywhere But Here, With Anybody But You Slippage 8 51 | April Fools' Day Forever The Infinity Box 58 52 | Argumentum Ornithologicum The Aleph and Other Stories 1 53 | As Simple As That The Norton Book of Science Fiction 11 54 | At the End of the Orbit The Expert Dreamers 20 55 | At the Mouse Circus Deathbird Stories 10 56 | Aunt Parnetta's Electric Blisters The Norton Book of Science Fiction 5 57 | Auschwitz, Our Home (A Letter) This Way for the Gas, Ladies and Gentlemen 45 58 | Auto-De-Fe Dangerous Visions 10 59 | Avatars of the Tortoise Labyrinths 7 60 | Averroes' Search Labyrinths 8 61 | Averroes' Search The Aleph and Other Stories 10 62 | Aye, and Gomorrah... Dangerous Visions 14 63 | Balanced Ecology The Norton Book of Science Fiction 17 64 | Basilisk Deathbird Stories 22 65 | Battle Without Banners Love Ain't Nothing but Sex Misspelled 14 66 | Battlefield Earthman, Go Home! 12 67 | Beachhead Explorers of Space 25 68 | Beauty's Beast The Living Demons 17 69 | Bed Sheets are White Again, Dangerous Visions 8 70 | Bettyann Strange Gifts 44 71 | Bianca's Hands Selected Stories 9 72 | Big Joe and the Nth Generation The View from the Stars 19 73 | Blabbermouth Caviar 28 74 | Black Bargain The Living Demons 16 75 | Blank? Stalking the Nightmare 8 76 | Bleeding Stones Deathbird Stories 8 77 | Blind Bird, Blind Bird, Go Away From Me! Love Ain't Nothing but Sex Misspelled 22 78 | Blood Bank The View from the Stars 46 79 | Blot Again, Dangerous Visions 15 80 | Blowups Happen The Man Who Sold the Moon 54 81 | Borges and I Labyrinths 2 82 | Borges and I The Aleph and Other Stories 2 83 | Bounty Again, Dangerous Visions 7 84 | Brass and Gold (or Horse and Zeppelin in Beverly Hills) Riverworld and Other Stories 18 85 | Bright Eyes Paingod and Other Delusions 12 86 | Bright Segment Caviar 28 87 | Bright Segment Selected Stories 25 88 | Broken Glass Angry Candy 12 89 | Brownshoes Sturgeon is Alive and Well... 12 90 | Burning Chrome Burning Chrome 23 91 | By His Bootstraps The Menace from Earth 49 92 | Call Girl Invisible Planets 12 93 | Camps Nebula Winners Fifteen 29 94 | Carcinoma Angels Dangerous Visions 15 95 | Catch That Rabbit I, Robot 15 96 | Catman Approaching Oblivion 34 97 | Census City 35 98 | Chain Reaction The Expert Dreamers 16 99 | Chained to the Fast Lane in the Red Queen's Race Angry Candy 16 100 | Chatting with Anubis Slippage 8 101 | Ching Witch! Again, Dangerous Visions 24 102 | Christ, Old Student in a New School Again, Dangerous Visions 9 103 | Chuck Berry, Won't You Please Come Home Again, Dangerous Visions 12 104 | City City 34 105 | Cold Friend Approaching Oblivion 11 106 | Collecting Team Explorers of Space 18 107 | Columbus Was a Dope The Menace from Earth 4 108 | Come to the Party The Collected Stories of Frank Herbert 21 109 | Comes Now the Power The Norton Book of Science Fiction 5 110 | Commuter's Problem Earthman, Go Home! 22 111 | Corpse Deathbird Stories 12 112 | Count the Clock That Tells the Time Shatterday 22 113 | Covered Mirrors The Aleph and Other Stories 2 114 | Crate Sturgeon is Alive and Well... 14 115 | Crazy as a Soup Sandwich Slippage 48 116 | Croatoan Strange Wine 18 117 | Crucifixus Etiam The View from the Stars 18 118 | Curse 5.0 The Wandering Earth 23 119 | Damnation Morning Changewar 19 120 | Danger-Human! Strange Gifts 21 121 | Daniel White for the Greater Good Love Ain't Nothing but Sex Misspelled 13 122 | Darkness Upon the Face of the Deep Slippage 16 123 | Day Million The Norton Book of Science Fiction 5 124 | Deal From the Bottom Earthman, Go Home! 7 125 | Death and the Compass Ficciones 14 126 | Death and the Compass Labyrinths 12 127 | Deeper than the Darkness Paingod and Other Delusions 20 128 | Delia Elena San Marco The Aleph and Other Stories 1 129 | Delusion for a Dragon Slayer Deathbird Stories 18 130 | Deutsches Requiem Labyrinths 7 131 | Deutsches Requiem The Aleph and Other Stories 7 132 | Devourer The Wandering Earth 46 133 | Distant Signals The Norton Book of Science Fiction 13 134 | Division by Zero Stories of Your Life and Others 20 135 | Django Shatterday 12 136 | Djinn, No Chaser Stalking the Nightmare 22 137 | Dogfight Burning Chrome 24 138 | Do-It-Yourself Earthman, Go Home! 14 139 | Dreamtigers The Aleph and Other Stories 1 140 | Dumb Waiter The View from the Stars 34 141 | Each an Explorer Explorers of Space 18 142 | Ecowarewness Approaching Oblivion 2 143 | Eidolons Angry Candy 18 144 | Elbow Room The Norton Book of Science Fiction 15 145 | Elegy Labyrinths 2 146 | Elouise and the Doctors of the Planet Pergamon Again, Dangerous Visions 19 147 | Emissary from Hamelin Strange Wine 13 148 | Emma Zunz Labyrinths 6 149 | Emma Zunz The Aleph and Other Stories 7 150 | Empire of the Sun Again, Dangerous Visions 8 151 | Encounter With A Hick Dangerous Visions 7 152 | Enemy Mine Nebula Winners Fifteen 64 153 | Epilogue City 13 154 | Epiphany for Aliens Again, Dangerous Visions 11 155 | Ernest and the Machine God Deathbird Stories 20 156 | Erotophobia Approaching Oblivion 7 157 | Ersatz Dangerous Visions 9 158 | Escape! I, Robot 21 159 | Escapegoat Angry Candy 4 160 | Eutopia Dangerous Visions 23 161 | Evensong Dangerous Visions 10 162 | Everything and Nothing Labyrinths 3 163 | Everything and Nothing The Aleph and Other Stories 3 164 | Evidence I, Robot 23 165 | Exploration Team Explorers of Space 58 166 | Exposures The Norton Book of Science Fiction 12 167 | Eye of the Beholder Again, Dangerous Visions 15 168 | Faith of our Fathers Dangerous Visions 38 169 | Fear is a Cold Black The Mile-Long Spaceship 25 170 | Feather Tigers The Norton Book of Science Fiction 7 171 | Featherbed on Chlyntha Xenogensis 17 172 | Final Trophy Stalking the Nightmare 12 173 | Flies Dangerous Visions 13 174 | Flop Sweat Shatterday 18 175 | Folding Beijing Invisible Planets 44 176 | Footsteps Angry Candy 14 177 | For the Sake of Grace The Norton Book of Science Fiction 20 178 | For Value Received Again, Dangerous Visions 18 179 | Fragments of a Hologram Rose Burning Chrome 7 180 | From A to Z, In The Chocolate Alphabet Strange Wine 24 181 | From the Government Printing Office Dangerous Visions 9 182 | Frozen Journey The Norton Book of Science Fiction 16 183 | Funes the Memorious Labyrinths 8 184 | Funes the Memorious Ficciones 10 185 | G. B. K.-A Many-Flavored Bird Love Ain't Nothing but Sex Misspelled 11 186 | Gather Blue Roses The Norton Book of Science Fiction 5 187 | Gathi Xenogensis 7 188 | Getting Along Again, Dangerous Visions 32 189 | Ghost of a Chance Caviar 20 190 | giANTS Nebula Winners Fifteen 20 191 | Gift from the Stars The Mile-Long Spaceship 17 192 | Gnomebody Earthman, Go Home! 7 193 | Go Toward the Light Slippage 10 194 | Go, Go, Go, Said the Bird Dangerous Visions 9 195 | Goldfish Bowl The Menace from Earth 29 196 | Gonna Roll the Bones Dangerous Visions 26 197 | Good Hunting The Paper Menagerie and Other Stories 23 198 | Good News from the Vatican The Norton Book of Science Fiction 8 199 | Gopher in the Gilly Stalking the Nightmare 6 200 | Grail Stalking the Nightmare 28 201 | Grave of the Fireflies Invisible Planets 18 202 | Gutter Gang Web of the City 25 203 | Hadj Earthman, Go Home! 5 204 | Half-Life The Norton Book of Science Fiction 14 205 | Harry the Hare Again, Dangerous Visions 5 206 | Heavyplanet The Expert Dreamers 13 207 | Heechee Treasures The Gateway Trip 19 208 | Hell Is the Absence of God Stories of Your Life and Others 32 209 | High Weir The Norton Book of Science Fiction 18 210 | Hindsight: 480 Seconds Approaching Oblivion 6 211 | Hinterlands Burning Chrome 22 212 | His Vegetable The Norton Book of Science Fiction 5 213 | Hitler Painted Roses Strange Wine 18 214 | Hobbies City 28 215 | Homecoming The October Country 17 216 | Homelanding The Norton Book of Science Fiction 3 217 | How Beautiful with Banners The Norton Book of Science Fiction 9 218 | How's the Night Life on Cassalda? Shatterday 18 219 | Huddling Place City 23 220 | Humpty Dumpty had a Great Fall Strange Gifts 27 221 | I Curse the Lesson and Bless the Knowledge Love Ain't Nothing but Sex Misspelled 14 222 | I, Dreamer The View from the Stars 12 223 | Ibn-Hakam al-Bokhari, Murdered in His Labyrinth The Aleph and Other Stories 10 224 | If All Men Were Brothers, Would You Let One Marry Your Sister? Dangerous Visions 49 225 | I'm Looking for Kadak Approaching Oblivion 27 226 | In Fear of K Strange Wine 16 227 | In Lonely Islands Earthman, Go Home! 5 228 | In Memoriam, J. F. K. The Aleph and Other Stories 1 229 | In re Glover Again, Dangerous Visions 13 230 | In the Barn Again, Dangerous Visions 37 231 | In the Core The Gateway Trip 9 232 | In the Fourth Year of the War Shatterday 14 233 | Incident in Moderan Dangerous Visions 6 234 | Inferno, I, 32 Labyrinths 1 235 | Inferno, I, 32 The Aleph and Other Stories 1 236 | Interim The Martian Chronicles 1 237 | Interlocking Pieces The Norton Book of Science Fiction 6 238 | Invaders The Norton Book of Science Fiction 20 239 | Invasion Footnote Stalking the Nightmare 8 240 | Invisible Planets Invisible Planets 20 241 | It Selected Stories 25 242 | It was Nothing-Really Sturgeon is Alive and Well... 15 243 | It's You! Sturgeon is Alive and Well... 10 244 | J. C. on the Dude Ranch Riverworld and Other Stories 16 245 | Jack-in-the-Box The October Country 20 246 | Jane Doe #112 Slippage 12 247 | Jeffty is Five Shatterday 28 248 | Jenny with Wings The Mile-Long Spaceship 13 249 | Johnny Mnemonic Burning Chrome 22 250 | Jorry's Gap Sturgeon is Alive and Well... 12 251 | Judas Dangerous Visions 12 252 | Jupiter Five Explorers of Space 38 253 | Kafka and His Precursors Labyrinths 3 254 | Keyboard Slippage 7 255 | Killdozer! Selected Stories 70 256 | Killing Bernstein Strange Wine 18 257 | King of the Hill Again, Dangerous Visions 20 258 | Kirinyaga The Norton Book of Science Fiction 17 259 | Kiss of Fire Approaching Oblivion 11 260 | Knights to Move Changewar 13 261 | Knox Approaching Oblivion 15 262 | Kyrie Explorers of Space 15 263 | Kyrie The Norton Book of Science Fiction 10 264 | Ladies and Gentlemen, This Is Your Crisis Somerset Dreams and Other Fictions 16 265 | Lamia Mutable Again, Dangerous Visions 10 266 | Land of the Great Horses Dangerous Visions 12 267 | Last Train to Kankakee Again, Dangerous Visions 11 268 | Laugh Track Angry Candy 22 269 | Lenny The Expert Dreamers 18 270 | Let There Be Light The Man Who Sold the Moon 19 271 | Liar! I, Robot 16 272 | Life in Our Time The Living Demons 9 273 | Life-Line The Man Who Sold the Moon 22 274 | Liking What You See: A Documentary Stories of Your Life and Others 38 275 | Little Lost Robot I, Robot 26 276 | Lollipop and the Tar Baby The Norton Book of Science Fiction 19 277 | Lonley Women Are the Vessels of Time Strange Wine 8 278 | Looking for Company The Gateway Trip 13 279 | Lord Randy, My Son Dangerous Visions 18 280 | Lucy Comes To Stay The Living Demons 6 281 | Making It All the Way into the Future on Gaxton Falls of the Red Planet The Norton Book of Science Fiction 4 282 | Man of Letters The Infinity Box 19 283 | Martin Fierro The Aleph and Other Stories 2 284 | Mathoms from the Time Closet Again, Dangerous Visions 12 285 | Mealtime Earthman, Go Home! 11 286 | Medusa Caviar 26 287 | Mefisto in Onyx Slippage 46 288 | Microcosmic God Caviar 34 289 | Midnight in the Sunken Cathedral Slippage 10 290 | Midnight News The Norton Book of Science Fiction 11 291 | Mom Strange Wine 22 292 | Mona at Her Windows Love Ain't Nothing but Sex Misspelled 5 293 | Monitored Dreams & Strategic Cremations Again, Dangerous Visions 67 294 | Mono no Aware The Paper Menagerie and Other Stories 21 295 | Monolog Riverworld and Other Stories 8 296 | Moth Race Again, Dangerous Visions 13 297 | Mountain The Wandering Earth 48 298 | Mr. Costello, Hero Selected Stories 26 299 | Mrs. Bagley Goes to Mars Somerset Dreams and Other Fictions 10 300 | Mutations The Aleph and Other Stories 1 301 | Nackles vr.1 Slippage 8 302 | Nackles vr.2 Slippage 31 303 | Neither Your Jenny Nor Mine Love Ain't Nothing but Sex Misspelled 44 304 | Neon Deathbird Stories 12 305 | New Rose Hotel Burning Chrome 14 306 | Night Journey of the Dragon-Horse Invisible Planets 20 307 | Night Meeting The Martian Chronicles 9 308 | Night of Black Glass Stalking the Nightmare 16 309 | Night-Rise The Norton Book of Science Fiction 10 310 | Nine Hundred Grandmothers The Norton Book of Science Fiction 9 311 | No Game for Children Web of the City 51 312 | No Great Magic Changewar 68 313 | No Light in the Windows The Mile-Long Spaceship 11 314 | Nothing for My Noon Meal Earthman, Go Home! 15 315 | O Ye of Little Faith Deathbird Stories 10 316 | Oddy and Id Strange Gifts 17 317 | Of Ants and Dinosaurs The Wandering Earth 57 318 | On Exactitude and Science The Aleph and Other Stories 1 319 | On the Downhill Slide Deathbird Stories 18 320 | On the Feasibility of Coal-Driven Power Stations The Expert Dreamers 4 321 | On the Slab Angry Candy 12 322 | One for the Road The Mile-Long Spaceship 16 323 | One Life, Furnished in Early Poverty Approaching Oblivion 14 324 | One-Way Journey Xenogensis 11 325 | Operation Cassandra Xenogensis 27 326 | Opium Shatterday 8 327 | Other Worlds The Gateway Trip 19 328 | Out of All Them Bright Stars The Norton Book of Science Fiction 7 329 | Over the River and Through the Woods The Norton Book of Science Fiction 8 330 | Ozymandias Again, Dangerous Visions 21 331 | Paingod Deathbird Stories 12 332 | Paingod Paingod and Other Delusions 12 333 | Paladin of the Last Hour Angry Candy 26 334 | Parable of Cervantes and the Quixote Labyrinths 1 335 | Parable of the Palace The Aleph and Other Stories 2 336 | Paradise City 16 337 | Paradiso, XXXI, 108 Labyrinths 2 338 | Paradiso, XXXI, 108 The Aleph and Other Stories 2 339 | Partial Magic in the Quixote Labyrinths 4 340 | Paulie Charmed the Sleeping Woman Approaching Oblivion 4 341 | Philtre Tip The Living Demons 5 342 | Pierre Menrad, Author of Don Quixote Ficciones 12 343 | Pierre Menrad, Author of Don Quixote Labyrinths 9 344 | Planet Story Somerset Dreams and Other Fictions 16 345 | Precession The Norton Book of Science Fiction 10 346 | Pretty Maggie Moneyeyes Deathbird Stories 24 347 | Prince Myshkin, and Hold the Relish Angry Candy 10 348 | Prodigy Caviar 14 349 | Project Nightmare The Menace from Earth 21 350 | Pulling Hard Time Slippage 6 351 | Punky & The Yale Men Love Ain't Nothing but Sex Misspelled 30 352 | Quick to Haste Xenogensis 12 353 | Quicktime Angry Candy 10 354 | Ragnarok Labyrinths 2 355 | Ragnarok The Aleph and Other Stories 2 356 | Rain, Rain, Go Away Earthman, Go Home! 9 357 | Rat The Norton Book of Science Fiction 11 358 | Reason I, Robot 18 359 | Red Star, Winter Orbit Burning Chrome 23 360 | Repent, Harlequin! Said the Ticktockman Paingod and Other Delusions 14 361 | Requiem The Man Who Sold the Moon 20 362 | Riders of the Purple Wage Dangerous Visions 80 363 | Riding the Dark Train Out Love Ain't Nothing but Sex Misspelled 10 364 | Riverworld Riverworld and Other Stories 86 365 | Robbie I, Robot 19 366 | Rock God Deathbird Stories 14 367 | Rocket Summer The Martian Chronicles 1 368 | Runaround I, Robot 17 369 | Sandkings Nebula Winners Fifteen 43 370 | Saturn, November 11th Stalking the Nightmare 16 371 | Scartaris, June 28th Slippage 22 372 | Schrodinger's Plague The Norton Book of Science Fiction 8 373 | Schwarzschild Radius The Norton Book of Science Fiction 16 374 | Seeing Strange Wine 34 375 | Sensible City Slippage 10 376 | Seventy-Two Letters Stories of Your Life and Others 54 377 | Sex and/or Mr. Morrison Dangerous Visions 14 378 | Shadow, Shadow on the Wall Caviar 12 379 | Shall the Dust Praise Thee? Dangerous Visions 7 380 | Shatterday Shatterday 17 381 | Shattered Like a Glass Goblin Deathbird Stories 14 382 | She's a Young Thing and Cannot Leaver Her Mother Slippage 16 383 | Shoppe Keeper Shatterday 24 384 | Silence This Way for the Gas, Ladies and Gentlemen 3 385 | Silent in Gehenna Approaching Oblivion 16 386 | Silhouette The New Atlantis 56 387 | Simulacrum The Paper Menagerie and Other Stories 11 388 | Skeleton The October Country 20 389 | Sky Lift The Menace from Earth 14 390 | Slow Sculpture Selected Stories 20 391 | Slow Sculpture Sturgeon is Alive and Well... 22 392 | Snow The Norton Book of Science Fiction 14 393 | Soft Monkey Angry Candy 16 394 | Somehow, I Don't Think We're in Kansas, Toto Stalking the Nightmare 10 395 | Somerset Dreams Somerset Dreams and Other Fictions 46 396 | Soundless Evening Again, Dangerous Visions 8 397 | Speech Sound The Norton Book of Science Fiction 12 398 | Stable Strategies for Middle Management The Norton Book of Science Fiction 11 399 | Stand Still and Die Web of the City 203 400 | State Change The Paper Menagerie and Other Stories 16 401 | State of Grace Somerset Dreams and Other Fictions 9 402 | Still-Life Again, Dangerous Visions 15 403 | Stoned Counsel Again, Dangerous Visions 16 404 | Story of the Warrior and the Captive Maiden Labyrinths 5 405 | Story of the Warrior and the Captive Maiden The Aleph and Other Stories 5 406 | Story of Your Life Stories of Your Life and Others 56 407 | Strange Wine Strange Wine 12 408 | Strange Wine The Norton Book of Science Fiction 7 409 | Stuffing Angry Candy 8 410 | Suicide Sturgeon is Alive and Well... 8 411 | Sun of China The Wandering Earth 49 412 | Symbiosis Somerset Dreams and Other Fictions 20 413 | Take Care of Joey Sturgeon is Alive and Well... 12 414 | Taking Care of God Invisible Planets 40 415 | Taking Care of God The Wandering Earth 41 416 | Tandy's Story The Norton Book of Science Fiction 19 417 | Tauf Aleph The Norton Book of Science Fiction 18 418 | Tell Your Fortune The Living Demons 25 419 | Test to Destruction Dangerous Visions 29 420 | That Girl Who Knew What They Meant Sturgeon is Alive and Well... 10 421 | The [Widget], the [Wadget], and Boff Selected Stories 84 422 | The 10:00 Report is Brought to You By... Again, Dangerous Visions 16 423 | The 3 Most Important Things in Life Stalking the Nightmare 20 424 | The Absolutely Perfect Murder Xenogensis 11 425 | The Adventure of Black Peter The Original Illustrated Sherlock Holmes 13 426 | The Adventure of Charles Augustus Milverton The Original Illustrated Sherlock Holmes 12 427 | The Adventure of the Gloria Scott The Original Illustrated Sherlock Holmes 12 428 | The Adventure of the Abbey Grange The Original Illustrated Sherlock Holmes 15 429 | The Adventure of the Beryl Coronet The Original Illustrated Sherlock Holmes 15 430 | The Adventure of the Blue Carbuncle The Original Illustrated Sherlock Holmes 13 431 | The Adventure of the Cardboard Box The Original Illustrated Sherlock Holmes 13 432 | The Adventure of the Copper Beeches The Original Illustrated Sherlock Holmes 17 433 | The Adventure of the Crooked Man The Original Illustrated Sherlock Holmes 11 434 | The Adventure of the Dancing Men The Original Illustrated Sherlock Holmes 16 435 | The Adventure of the Empty House The Original Illustrated Sherlock Holmes 15 436 | The Adventure of the Engineer's Thumb The Original Illustrated Sherlock Holmes 13 437 | The Adventure of the Final Problem The Original Illustrated Sherlock Holmes 14 438 | The Adventure of the Golden Pince-Nez The Original Illustrated Sherlock Holmes 15 439 | The Adventure of the Greek Interpreter The Original Illustrated Sherlock Holmes 12 440 | The Adventure of the Missing Three-Quarter The Original Illustrated Sherlock Holmes 14 441 | The Adventure of the Musgrave Ritual The Original Illustrated Sherlock Holmes 11 442 | The Adventure of the Naval Treaty The Original Illustrated Sherlock Holmes 22 443 | The Adventure of the Noble Bachelor The Original Illustrated Sherlock Holmes 14 444 | The Adventure of the Norwood Builder The Original Illustrated Sherlock Holmes 15 445 | The Adventure of the Priory School The Original Illustrated Sherlock Holmes 19 446 | The Adventure of the Reigate Squires The Original Illustrated Sherlock Holmes 12 447 | The Adventure of the Resident Patient The Original Illustrated Sherlock Holmes 11 448 | The Adventure of the Second Stain The Original Illustrated Sherlock Holmes 14 449 | The Adventure of the Silver Blaze The Original Illustrated Sherlock Holmes 16 450 | The Adventure of the Six Napoleons The Original Illustrated Sherlock Holmes 14 451 | The Adventure of the Solitary Cyclist The Original Illustrated Sherlock Holmes 13 452 | The Adventure of the Speckled Band The Original Illustrated Sherlock Holmes 16 453 | The Adventure of the Stockbroker's Clerk The Original Illustrated Sherlock Holmes 11 454 | The Adventure of the Yellow Face The Original Illustrated Sherlock Holmes 11 455 | The Age of Gold The Gateway Trip 16 456 | The Ajeri Diary Xenogensis 20 457 | The Aleph The Aleph and Other Stories 16 458 | The Approach to Al-Mu'tasim Ficciones 8 459 | The Argentine Writer and Tradition Labyrinths 9 460 | The Avenger of Death Angry Candy 14 461 | The Babylon Lottery Ficciones 8 462 | The Beast of Barsac The Living Demons 19 463 | The Belonging Kind Burning Chrome 15 464 | The Big Hunger The View from the Stars 14 465 | The Big Space Fuck Again, Dangerous Visions 11 466 | The Black Cloud The Expert Dreamers 18 467 | The Bob Dylan Tambourine Software & Satori Support Services Consortium, Ltd. The Norton Book of Science Fiction 12 468 | The Bookmaking Habits of Select Species The Paper Menagerie and Other Stories 9 469 | The Boscombe Valley Mystery The Original Illustrated Sherlock Holmes 16 470 | The Boulevard of Broken Dreams Strange Wine 6 471 | The Brains of Rats The Norton Book of Science Fiction 14 472 | The Byrds The Norton Book of Science Fiction 12 473 | The Captive The Aleph and Other Stories 2 474 | The Cheese Stands Alone Stalking the Nightmare 14 475 | The Children Xenogensis 29 476 | The Circle Invisible Planets 22 477 | The Circular Ruins Ficciones 8 478 | The Circular Ruins Labyrinths 6 479 | The Cistern The October Country 10 480 | The City of Silence Invisible Planets 44 481 | The Crackpots Paingod and Other Delusions 40 482 | The Crowd The October Country 12 483 | The Daughter of the Tree Xenogensis 12 484 | The Day After the Day the Martians Came Dangerous Visions 10 485 | The Day I Died Stalking the Nightmare 10 486 | The Dead Man The Aleph and Other Stories 6 487 | The Death of Schillinger This Way for the Gas, Ladies and Gentlemen 4 488 | The Deathbird Deathbird Stories 32 489 | The Diagnosis of Dr. Darqueangel Strange Wine 17 490 | The Discarded Paingod and Other Delusions 14 491 | The Doll-House Dangerous Visions 24 492 | The Dragon on the Bookshelf Slippage 12 493 | The Dreams a Nightmare Dreams Slippage 4 494 | The Dwarf The October Country 15 495 | The Earth Men The Martian Chronicles 15 496 | The Emissary The October Country 10 497 | The Encounter Somerset Dreams and Other Fictions 28 498 | The End Ficciones 4 499 | The Evitable Conflict I, Robot 22 500 | The Evolution of Human Science Stories of Your Life and Others 4 501 | The Executioner of the Malformed Children Shatterday 16 502 | The Extraordinary Voyages of Amelie Bertrand Nebula Winners Fifteen 15 503 | The Face of Helene Bournouw Deathbird Stories 12 504 | The Fearful Sphere of Pascal Labyrinths 4 505 | The Few, the Proud Slippage 10 506 | The Fish of Lijiang Invisible Planets 18 507 | The Five Orange Pips The Original Illustrated Sherlock Holmes 11 508 | The Flower of Shazui Invisible Planets 20 509 | The Forces that Crush Earthman, Go Home! 15 510 | The Form of the Sword Ficciones 6 511 | The Function of Dream Sleep Angry Candy 23 512 | The Funeral Again, Dangerous Visions 28 513 | The Funeral The Infinity Box 27 514 | The Fusion Bomb The Infinity Box 39 515 | The Garden of Forking Paths Ficciones 14 516 | The Garden of Forking Paths Labyrinths 11 517 | The Gateway Asteroid The Gateway Trip 9 518 | The Gernsback Continuum The Norton Book of Science Fiction 9 519 | The Gernsback Continuum Burning Chrome 13 520 | The Girl From Mars The Living Demons 7 521 | The Goddess in the Ice Stalking the Nightmare 6 522 | The God's Script Labyrinths 8 523 | The Golden Helix Selected Stories 56 524 | The Golden Man Strange Gifts 33 525 | The Green Morning The Martian Chronicles 5 526 | The Handler The Norton Book of Science Fiction 4 527 | The Happy Breed Dangerous Visions 22 528 | The Heart of the Other Side The Expert Dreamers 11 529 | The Henry Miller Dawn Patrol Riverworld and Other Stories 16 530 | The Home Planet The Gateway Trip 9 531 | The Hounds Somerset Dreams and Other Fictions 28 532 | The Hour That Stretches Stalking the Nightmare 22 533 | The House of Asterion Labyrinths 3 534 | The House of Asterion The Aleph and Other Stories 3 535 | The House the Blakeneys Built The Norton Book of Science Fiction 10 536 | The Immortal Labyrinths 14 537 | The Immortal The Aleph and Other Stories 17 538 | The Indian Spirit Guide The Living Demons 16 539 | The Infinity Box The Infinity Box 65 540 | The Invasion The Expert Dreamers 18 541 | The January Offensive This Way for the Gas, Ladies and Gentlemen 10 542 | The Jar The October Country 17 543 | The Jigsaw Man Dangerous Visions 17 544 | The Jungle Rot Kid on the Nod Riverworld and Other Stories 12 545 | The Lake The October Country 7 546 | The Lake Was Full of Artificial Things The Norton Book of Science Fiction 11 547 | The Last Days of the Captain The Mile-Long Spaceship 15 548 | The Last Generation? Xenogensis 12 549 | The Leaser of Two Evils Riverworld and Other Stories 16 550 | The Library of Babel Ficciones 10 551 | The Library of Babel Labyrinths 8 552 | The Life of Anybody The Norton Book of Science Fiction 2 553 | The Lingering Scent of Woodsmoke Slippage 4 554 | The Literomancer The Paper Menagerie and Other Stories 38 555 | The Litigation Master and the Monkey King The Paper Menagerie and Other Stories 26 556 | The Locusts The Martian Chronicles 1 557 | The Long Years The Martian Chronicles 11 558 | The Longest Fall The Wandering Earth 56 559 | The Lottery in Babylon Labyrinths 6 560 | The Lucky Strike The Norton Book of Science Fiction 31 561 | The Luggage Store The Martian Chronicles 1 562 | The Maker The Aleph and Other Stories 3 563 | The Malley System Dangerous Visions 11 564 | The Man on the Threshold The Aleph and Other Stories 6 565 | The Man Upstairs The October Country 16 566 | The Man Who Ended History: A Documentary The Paper Menagerie and Other Stories 61 567 | The Man Who Lost the Sea Selected Stories 12 568 | The Man Who Rowed Christopher Columbus Ashore Slippage 18 569 | The Man Who Sold the Moon The Man Who Sold the Moon 106 570 | The Man Who Was Heavily into Revenge Shatterday 8 571 | The Man Who Went to the Moon-Twice Dangerous Visions 13 572 | The Man With English Strange Gifts 10 573 | The Man with the Package This Way for the Gas, Ladies and Gentlemen 5 574 | The Man With the Twisted Lips The Original Illustrated Sherlock Holmes 15 575 | The Man without a Planet The Mile-Long Spaceship 7 576 | The Mark Gable Foundation The Expert Dreamers 13 577 | The Martian The Martian Chronicles 12 578 | The Menace from Earth The Menace from Earth 13 579 | The Merchants of Venus The Gateway Trip 122 580 | The Micro-Age The Wandering Earth 33 581 | The Mile-Long Spaceship The Mile-Long Spaceship 10 582 | The Milk of Paradise Again, Dangerous Visions 13 583 | The Million-Year Picnic The Martian Chronicles 9 584 | The Miracle of the Broom Closet The Expert Dreamers 7 585 | The Mirrors of Enigmas Labyrinths 4 586 | The Mountains of Sunset, the Mountains of Dawn The Norton Book of Science Fiction 13 587 | The Mountebank The Aleph and Other Stories 2 588 | The Museum on Cyclops Avenue Slippage 12 589 | The Musicians The Martian Chronicles 1 590 | The Naming of Names The Martian Chronicles 1 591 | The New Atlantis The New Atlantis 30 592 | The New Atlantis The Norton Book of Science Fiction 20 593 | The New York Review of Bird Strange Wine 44 594 | The Next in Line The October Country 41 595 | The Night That All Time Broke Out Dangerous Visions 16 596 | The Off Season The Martian Chronicles 12 597 | The Old Ones The Martian Chronicles 1 598 | The Oldest Soldier Changewar 27 599 | The Other Death The Aleph and Other Stories 8 600 | The Other Eye of Polyphemus Shatterday 14 601 | The Outpost Undiscovered by Tourists Stalking the Nightmare 8 602 | The Pale Silver Dollar of the Moon Pays Its Way and Makes Change vr.1 Slippage 6 603 | The Pale Silver Dollar of the Moon Pays Its Way and Makes Change vr.2 Slippage 8 604 | The Paper Menagerie The Paper Menagerie and Other Stories 15 605 | The Patterns of Drone Sturgeon is Alive and Well... 16 606 | The People Who Walked On This Way for the Gas, Ladies and Gentlemen 16 607 | The Perfect Match The Paper Menagerie and Other Stories 25 608 | The Phantom of the Sewers Riverworld and Other Stories 25 609 | The Place with No Name Deathbird Stories 16 610 | The Plot The Aleph and Other Stories 1 611 | The Plot Is the Thing The Living Demons 7 612 | The Private War of Private Jacob The Norton Book of Science Fiction 5 613 | The Problem of the Sore Bridge-Among Others Riverworld and Other Stories 32 614 | The Prowler in the City on the Edge of Forever Dangerous Visions 20 615 | The Recognition Dangerous Visions 14 616 | The Red Canary The Infinity Box 18 617 | The Red-Headed League The Original Illustrated Sherlock Holmes 15 618 | The Region Between Angry Candy 86 619 | The Regular The Paper Menagerie and Other Stories 25 620 | The Resurgence of Miss Ankle-Strap Wedgie Love Ain't Nothing but Sex Misspelled 91 621 | The Roads Must Roll The Man Who Sold the Moon 45 622 | The Season of Babies Xenogensis 14 623 | The Secret Miracle Ficciones 8 624 | The Secret Miracle Labyrinths 7 625 | The Sect of Phoenix Ficciones 4 626 | The Sect of Phoenix Labyrinths 4 627 | The Settlers The Martian Chronicles 1 628 | The Sex Opposite Selected Stories 28 629 | The Shape of the Sword Labyrinths 5 630 | The Shore The Martian Chronicles 1 631 | The Silent Towns The Martian Chronicles 10 632 | The Silver Corridor Earthman, Go Home! 20 633 | The Simple Way City 25 634 | The Singers The Expert Dreamers 4 635 | The Skills of Xanadu Selected Stories 28 636 | The Sky is Burning Earthman, Go Home! 9 637 | The Small Assaassin The October Country 21 638 | The Smiling Future Xenogensis 13 639 | The South Ficciones 7 640 | The Starseekers The Gateway Trip 19 641 | The Start of the End of It All The Norton Book of Science Fiction 11 642 | The Summer Night The Martian Chronicles 2 643 | The Superior Sex Xenogensis 11 644 | The Supper This Way for the Gas, Ladies and Gentlemen 5 645 | The Sycthe The October Country 8 646 | The Taxpayer The Martian Chronicles 1 647 | The Test Stand The Expert Dreamers 14 648 | The Test-Tube Creature, Afterward Again, Dangerous Visions 5 649 | The Theologians Labyrinths 8 650 | The Theologians The Aleph and Other Stories 9 651 | The Third Expedition The Martian Chronicles 16 652 | The Time Piece The Infinity Box 22 653 | The Transit of Venus Xenogensis 11 654 | The Two Kings and the Two Labyrinths The Aleph and Other Stories 2 655 | The Universe of Robert Blake Love Ain't Nothing but Sex Misspelled 5 656 | The Unspeakable Betrothal The Living Demons 14 657 | The Very Last Day of a Good Woman Earthman, Go Home! 9 658 | The Village The Infinity Box 10 659 | The Visit The Gateway Trip 9 660 | The Voice of the Sonar in My Veriform Appendix Riverworld and Other Stories 14 661 | The Volcano Riverworld and Other Stories 20 662 | The Wages of Humanity The Wandering Earth 44 663 | The Waiting Labyrinths 4 664 | The Wall and the Books Labyrinths 3 665 | The Wandering Earth The Wandering Earth 46 666 | The War at Home The Norton Book of Science Fiction 3 667 | The Warlord of Saturn's Moon The Norton Book of Science Fiction 8 668 | The Watchers The Martian Chronicles 1 669 | The Watchful Poker Chip of H. Matisse The October Country 12 670 | The Waves The Paper Menagerie and Other Stories 26 671 | The Whimper of Whipped Dogs Deathbird Stories 22 672 | The Will The View from the Stars 14 673 | The Wind The October Country 12 674 | The Wind Beyond the Mountains Earthman, Go Home! 10 675 | The Wine Has Been Left Open Too Long and the Memory Has Gone Flat Strange Wine 16 676 | The Winter Flies The Norton Book of Science Fiction 12 677 | The Winter Market Burning Chrome 25 678 | The Witness Labyrinths 1 679 | The Witness The Aleph and Other Stories 1 680 | The Women Men Don't See The Norton Book of Science Fiction 25 681 | The Wonderful Death of Dudley Stone The October Country 13 682 | The Word for World is Forrest Again, Dangerous Visions 96 683 | The World of Stone This Way for the Gas, Ladies and Gentlemen 3 684 | The Writing of the God The Aleph and Other Stories 6 685 | The Year of the Jackpot The Menace from Earth 32 686 | The Year of the Rat Invisible Planets 30 687 | The Yellow Rose The Aleph and Other Stories 1 688 | The Zahir Labyrinths 5 689 | The Zahir The Aleph and Other Stories 10 690 | Theme of the Traitor and Hero Ficciones 6 691 | Theme of the Traitor and Hero Labyrinths 4 692 | There Was an Old Woman The October Country 16 693 | There Will Come Soft Rains The Martian Chronicles 6 694 | Things Lost Again, Dangerous Visions 30 695 | This Way for the Gas, Ladies and Gentlemen This Way for the Gas, Ladies and Gentlemen 21 696 | Three Versions of Judas Ficciones 8 697 | Three Versions of Judas Labyrinths 6 698 | Throwback Xenogensis 13 699 | Thunder and Roses Selected Stories 24 700 | Time Travel for Pedestrians Again, Dangerous Visions 31 701 | Tiny Ally Stalking the Nightmare 6 702 | Tissue Again, Dangerous Visions 16 703 | Tlon, Uqbar, Orbis Teritus Ficciones 20 704 | Tlon, Uqbar, Orbis Teritus Labyrinths 16 705 | To Be Continued Strange Gifts 14 706 | To Explain to Mrs. Thompson The Expert Dreamers 23 707 | To Here and the Easel Sturgeon is Alive and Well... 56 708 | Toenails The Aleph and Other Stories 1 709 | Tongtong's Summer Invisible Planets 20 710 | Totenbuch Again, Dangerous Visions 10 711 | Touched With Fire The October Country 15 712 | Tower of Babylon Stories of Your Life and Others 28 713 | Tracking Level Stalking the Nightmare 12 714 | Transcending Destiny Stalking the Nightmare 26 715 | Trouble With Ants City 38 716 | Try and Change the Past Changewar 11 717 | Twink Caviar 19 718 | Unaccompanied Sonata Nebula Winners Fifteen 20 719 | Uncle Einar The October Country 10 720 | Uncle Fremmis Sturgeon is Alive and Well... 18 721 | Underground The Living Demons 6 722 | Understand Stories of Your Life and Others 42 723 | Unlocking the Air The Unreal and the Real 26 724 | Usher II The Martian Chronicles 15 725 | Valerie Love Ain't Nothing but Sex Misspelled 16 726 | Valery as Symbol Labyrinths 2 727 | Vaster than Empires and More Slow Explorers of Space 57 728 | Visionary Stalking the Nightmare 14 729 | Wanted in Surgery Paingod and Other Delusions 30 730 | Water Is for Washing The Menace from Earth 10 731 | Way in the Middle of the Air The Martian Chronicles 3 732 | We See Things Differently The Norton Book of Science Fiction 18 733 | What Happened to Auguste Clarot? Dangerous Visions 8 734 | What I Did on My Vaction This Summer by Little Bobby Hirschhorn, Age 27 Love Ain't Nothing but Sex Misspelled 19 735 | What's It Like Out There? Explorers of Space 27 736 | When Auld's Acquaintance is Forgot Angry Candy 10 737 | When I was a Hired Gun Love Ain't Nothing but Sex Misspelled 12 738 | When I Was Miss Dow The Norton Book of Science Fiction 10 739 | When it Changed Again, Dangerous Visions 16 740 | When the Bentfin Boomer Boys on Old New Alabama Again, Dangerous Visions 107 741 | When the Change-Winds Blow Changewar 15 742 | Where Have You Been, Billy Boy, Billy Boy? The Infinity Box 13 743 | Where I Shall Dwell in the Next World Slippage 12 744 | With a Finger in My I Again, Dangerous Visions 15 745 | With Her Eyes The Wandering Earth 19 746 | With Virgin Oddum at the East Pole Angry Candy 20 747 | Working with the Little People Strange Wine 18 748 | Would You Do It for a Penny Shatterday 22 749 | Ylla The Martian Chronicles 12 750 | You Triflin' Skunk The View from the Stars 11 751 | Zero Gee Again, Dangerous Visions 31 752 | And the Moon be Still as Bright The Martian Chronicles 24 -------------------------------------------------------------------------------- /tests/data/library-cross.db: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mkitzan/constexpr-sql/ba98a31224ce160b6e8bc92aca3b079c5cf0f56d/tests/data/library-cross.db -------------------------------------------------------------------------------- /tests/data/library.db: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mkitzan/constexpr-sql/ba98a31224ce160b6e8bc92aca3b079c5cf0f56d/tests/data/library.db -------------------------------------------------------------------------------- /tests/data/stories.tsv: -------------------------------------------------------------------------------- 1 | !!!The!!Teddy!Crazy!!Show!!! science fiction 1968 2 | (Learning About) Machine Sex science fiction 1988 3 | ...the World, as we Know 't science fiction 1982 4 | 2004, or Thereabouts science fiction 1964 5 | A Biography of Tadeo Isidoro Cruz (1829-1874) fiction 1944 6 | A Brief History of the Trans-Pacific Tunnel science fiction 2013 7 | A Case of Identity mystery 1891 8 | A Day at Harmenz east euro lit 1959 9 | A Deskful of Girls science fiction 1958 10 | A Dialog About A Dialog fiction 1936 11 | A Dialog Between Dead Men fiction 1957 12 | A Feast of Demons science fiction 1958 13 | A Few Things I Know About While Away science fiction 1975 14 | A Hundred Ghosts Parade Tonight science fiction 2010 15 | A is for Automation science fiction 1959 16 | A Midwinter's Tale science fiction 1988 17 | A Momentary Taste of Being science fiction 1975 18 | A Mouse in the Walls of the Global Village science fiction 1972 19 | A New Refutation of Time essay 1947 20 | A Note on (toward) Bernard Shaw essay 1962 21 | A Path Through the Darkness science fiction 1963 22 | A Prayer for No One's Enemies science fiction 1966 23 | A Problem fiction 1957 24 | A Scandal in Bohemia mystery 1891 25 | A Toy for Juliette science fiction 1967 26 | A True Story east euro lit 1959 27 | A Visit east euro lit 1959 28 | A Way of Thinking science fiction 1953 29 | Adrift Just Off the Islets of Langerhans: Latitude 38o54'N, Longitude 77o00'13W science fiction 1974 30 | Adrift on the Policy Level science fiction 1959 31 | Aesop science fiction 1947 32 | After the Days of Dead-Eye 'Dee science fiction 1985 33 | All in Good Time science fiction 1960 34 | All the Birds Come Home to Roost science fiction 1978 35 | All the Flavors science fiction 2012 36 | All the Lies Lies That Are My Life science fiction 1980 37 | All The People science fiction 1961 38 | All the Sound of Fear science fiction 1962 39 | Along the Scenic Route science fiction 1969 40 | Alpha Ralpha Boulevard science fiction 1961 41 | Amateur in Chancery science fiction 1961 42 | America science fiction 1987 43 | An Advanced Readers' Picture Book of Comparative Cognition science fiction 2016 44 | An Examination of the Work of Herbert Quain fiction 1941 45 | And the Angels Sing science fiction 1990 46 | And the Sea Like Mirrors science fiction 1972 47 | Andover and the Android science fiction 1963 48 | Anybody Else Like Me? science fiction 1952 49 | Anywhere But Here, With Anybody But You science fiction 1996 50 | April Fools' Day Forever science fiction 1970 51 | Argumentum Ornithologicum fiction 1952 52 | As Simple As That science fiction 1971 53 | At the End of the Orbit science fiction 1961 54 | At the Mouse Circus science fiction 1971 55 | Aunt Parnetta's Electric Blisters science fiction 1990 56 | Auschwitz, Our Home (A Letter) east euro lit 1959 57 | Auto-De-Fe science fiction 1967 58 | Avatars of the Tortoise essay 1939 59 | Averroes' Search fiction 1947 60 | Aye, and Gomorrah... science fiction 1967 61 | Balanced Ecology science fiction 1965 62 | Basilisk science fiction 1972 63 | Battle Without Banners science fiction 1964 64 | Battlefield science fiction 1958 65 | Beachhead science fiction 1951 66 | Beauty's Beast science fiction 1941 67 | Bed Sheets are White science fiction 1972 68 | Bettyann science fiction 1951 69 | Bianca's Hands science fiction 1947 70 | Big Joe and the Nth Generation science fiction 1952 71 | Blabbermouth science fiction 1945 72 | Black Bargain science fiction 1942 73 | Blank? science fiction 1957 74 | Bleeding Stones science fiction 1973 75 | Blind Bird, Blind Bird, Go Away From Me! science fiction 1963 76 | Blood Bank science fiction 1952 77 | Blot science fiction 1972 78 | Blowups Happen science fiction 1940 79 | Borges and I fiction 1957 80 | Bounty science fiction 1972 81 | Brass and Gold (or Horse and Zeppelin in Beverly Hills) science fiction 1971 82 | Bright Eyes science fiction 1965 83 | Bright Segment science fiction 1955 84 | Broken Glass science fiction 1981 85 | Brownshoes science fiction 1969 86 | Burning Chrome science fiction 1982 87 | By His Bootstraps science fiction 1941 88 | Call Girl science fiction 2014 89 | Camps science fiction 1979 90 | Carcinoma Angels science fiction 1967 91 | Catch That Rabbit science fiction 1944 92 | Catman science fiction 1974 93 | Census science fiction 1944 94 | Chain Reaction science fiction 1956 95 | Chained to the Fast Lane in the Red Queen's Race science fiction 1983 96 | Chatting with Anubis science fiction 1995 97 | Ching Witch! science fiction 1972 98 | Christ, Old Student in a New School science fiction 1972 99 | Chuck Berry, Won't You Please Come Home science fiction 1972 100 | City science fiction 1944 101 | Cold Friend science fiction 1973 102 | Collecting Team science fiction 1956 103 | Columbus Was a Dope science fiction 1947 104 | Come to the Party science fiction 1978 105 | Comes Now the Power science fiction 1966 106 | Commuter's Problem science fiction 1957 107 | Corpse science fiction 1972 108 | Count the Clock That Tells the Time science fiction 1978 109 | Covered Mirrors fiction 1936 110 | Crate science fiction 1970 111 | Crazy as a Soup Sandwich science fiction 1989 112 | Croatoan science fiction 1975 113 | Crucifixus Etiam science fiction 1953 114 | Curse 5.0 science fiction 2013 115 | Damnation Morning science fiction 1959 116 | Danger-Human! science fiction 1957 117 | Daniel White for the Greater Good science fiction 1961 118 | Darkness Upon the Face of the Deep science fiction 1991 119 | Day Million science fiction 1966 120 | Deal From the Bottom science fiction 1960 121 | Death and the Compass fiction 1942 122 | Deeper than the Darkness science fiction 1957 123 | Delia Elena San Marco fiction 1957 124 | Delusion for a Dragon Slayer science fiction 1966 125 | Deutsches Requiem fiction 1946 126 | Devourer science fiction 2013 127 | Distant Signals science fiction 1984 128 | Division by Zero science fiction 1991 129 | Django science fiction 1978 130 | Djinn, No Chaser science fiction 1982 131 | Dogfight science fiction 1985 132 | Do-It-Yourself science fiction 1961 133 | Dreamtigers fiction 1936 134 | Dumb Waiter science fiction 1952 135 | Each an Explorer science fiction 1956 136 | Ecowarewness science fiction 1974 137 | Eidolons science fiction 1986 138 | Elbow Room science fiction 1980 139 | Elegy poem 1962 140 | Elouise and the Doctors of the Planet Pergamon science fiction 1972 141 | Emissary from Hamelin science fiction 1977 142 | Emma Zunz fiction 1948 143 | Empire of the Sun science fiction 1972 144 | Encounter With A Hick science fiction 1967 145 | Enemy Mine science fiction 1979 146 | Epilogue science fiction 1952 147 | Epiphany for Aliens science fiction 1972 148 | Ernest and the Machine God science fiction 1968 149 | Erotophobia science fiction 1971 150 | Ersatz science fiction 1967 151 | Escape! science fiction 1945 152 | Escapegoat science fiction 1983 153 | Eutopia science fiction 1967 154 | Evensong science fiction 1967 155 | Everything and Nothing fiction 1958 156 | Evidence science fiction 1946 157 | Exploration Team science fiction 1956 158 | Exposures science fiction 1981 159 | Eye of the Beholder science fiction 1972 160 | Faith of our Fathers science fiction 1967 161 | Fear is a Cold Black science fiction 1963 162 | Feather Tigers science fiction 1973 163 | Featherbed on Chlyntha science fiction 1957 164 | Final Trophy science fiction 1957 165 | Flies science fiction 1967 166 | Flop Sweat science fiction 1977 167 | Folding Beijing science fiction 2014 168 | Footsteps science fiction 1980 169 | For the Sake of Grace science fiction 1969 170 | For Value Received science fiction 1972 171 | Fragments of a Hologram Rose science fiction 1977 172 | From A to Z, In The Chocolate Alphabet science fiction 1979 173 | From the Government Printing Office science fiction 1967 174 | Frozen Journey science fiction 1980 175 | Funes the Memorious fiction 1942 176 | G. B. K.-A Many-Flavored Bird science fiction 1962 177 | Gather Blue Roses science fiction 1972 178 | Gathi science fiction 1958 179 | Getting Along science fiction 1972 180 | Ghost of a Chance science fiction 1943 181 | giANTS science fiction 1979 182 | Gift from the Stars science fiction 1958 183 | Gnomebody science fiction 1956 184 | Go Toward the Light science fiction 1996 185 | Go, Go, Go, Said the Bird science fiction 1967 186 | Goldfish Bowl science fiction 1942 187 | Gonna Roll the Bones science fiction 1967 188 | Good Hunting science fiction 2012 189 | Good News from the Vatican science fiction 1971 190 | Gopher in the Gilly science fiction 1982 191 | Grail science fiction 1981 192 | Grave of the Fireflies science fiction 2005 193 | Gutter Gang thriller 1957 194 | Hadj science fiction 1956 195 | Half-Life science fiction 1989 196 | Harry the Hare science fiction 1972 197 | Heavyplanet science fiction 1958 198 | Heechee Treasures science fiction 1990 199 | Hell Is the Absence of God science fiction 2001 200 | High Weir science fiction 1968 201 | Hindsight: 480 Seconds science fiction 1973 202 | Hinterlands science fiction 1981 203 | His Vegetable science fiction 1986 204 | Hitler Painted Roses science fiction 1977 205 | Hobbies science fiction 1946 206 | Homecoming science fiction 1946 207 | Homelanding science fiction 1990 208 | How Beautiful with Banners science fiction 1966 209 | How's the Night Life on Cassalda? science fiction 1977 210 | Huddling Place science fiction 1944 211 | Humpty Dumpty had a Great Fall science fiction 1948 212 | I Curse the Lesson and Bless the Knowledge science fiction 1976 213 | I, Dreamer science fiction 1953 214 | Ibn-Hakam al-Bokhari, Murdered in His Labyrinth fiction 1951 215 | If All Men Were Brothers, Would You Let One Marry Your Sister? science fiction 1967 216 | I'm Looking for Kadak science fiction 1974 217 | In Fear of K science fiction 1975 218 | In Lonely Islands science fiction 1956 219 | In Memoriam, J. F. K. fiction 1967 220 | In re Glover science fiction 1972 221 | In the Barn science fiction 1972 222 | In the Core science fiction 1990 223 | In the Fourth Year of the War science fiction 1979 224 | Incident in Moderan science fiction 1967 225 | Inferno, I, 32 fiction 1955 226 | Interim science fiction 1950 227 | Interlocking Pieces science fiction 1984 228 | Invaders science fiction 1990 229 | Invasion Footnote science fiction 1957 230 | Invisible Planets science fiction 2010 231 | It science fiction 1940 232 | It was Nothing-Really science fiction 1969 233 | It's You! science fiction 1969 234 | J. C. on the Dude Ranch science fiction 1979 235 | Jack-in-the-Box science fiction 1947 236 | Jane Doe #112 science fiction 1990 237 | Jeffty is Five science fiction 1977 238 | Jenny with Wings science fiction 1963 239 | Johnny Mnemonic science fiction 1981 240 | Jorry's Gap science fiction 1969 241 | Judas science fiction 1967 242 | Jupiter Five science fiction 1953 243 | Kafka and His Precursors essay 1951 244 | Keyboard science fiction 1995 245 | Killdozer! science fiction 1944 246 | Killing Bernstein science fiction 1976 247 | King of the Hill science fiction 1972 248 | Kirinyaga science fiction 1988 249 | Kiss of Fire science fiction 1972 250 | Knights to Move science fiction 1965 251 | Knox science fiction 1974 252 | Kyrie science fiction 1968 253 | Ladies and Gentlemen, This Is Your Crisis science fiction 1976 254 | Lamia Mutable science fiction 1972 255 | Land of the Great Horses science fiction 1967 256 | Last Train to Kankakee science fiction 1972 257 | Laugh Track science fiction 1984 258 | Lenny science fiction 1957 259 | Let There Be Light science fiction 1940 260 | Liar! science fiction 1941 261 | Life in Our Time science fiction 1966 262 | Life-Line science fiction 1939 263 | Liking What You See: A Documentary science fiction 2002 264 | Little Lost Robot science fiction 1947 265 | Lollipop and the Tar Baby science fiction 1977 266 | Lonley Women Are the Vessels of Time science fiction 1976 267 | Looking for Company science fiction 1990 268 | Lord Randy, My Son science fiction 1967 269 | Lucy Comes To Stay science fiction 1952 270 | Making It All the Way into the Future on Gaxton Falls of the Red Planet science fiction 1974 271 | Man of Letters science fiction 1975 272 | Martin Fierro fiction 1957 273 | Mathoms from the Time Closet science fiction 1972 274 | Mealtime science fiction 1958 275 | Medusa science fiction 1942 276 | Mefisto in Onyx science fiction 1993 277 | Microcosmic God science fiction 1941 278 | Midnight in the Sunken Cathedral science fiction 1995 279 | Midnight News science fiction 1990 280 | Mom science fiction 1976 281 | Mona at Her Windows science fiction 1962 282 | Monitored Dreams & Strategic Cremations science fiction 1972 283 | Mono no Aware science fiction 2012 284 | Monolog science fiction 1973 285 | Moth Race science fiction 1972 286 | Mountain science fiction 2013 287 | Mr. Costello, Hero science fiction 1953 288 | Mrs. Bagley Goes to Mars science fiction 1975 289 | Mutations fiction 1960 290 | Nackles vr.1 science fiction 1963 291 | Nackles vr.2 science fiction 1987 292 | Neither Your Jenny Nor Mine science fiction 1964 293 | Neon science fiction 1973 294 | New Rose Hotel science fiction 1984 295 | Night Journey of the Dragon-Horse science fiction 2016 296 | Night Meeting science fiction 1950 297 | Night of Black Glass science fiction 1981 298 | Night-Rise science fiction 1978 299 | Nine Hundred Grandmothers science fiction 1966 300 | No Game for Children thriller 1959 301 | No Great Magic science fiction 1960 302 | No Light in the Windows science fiction 1963 303 | Nothing for My Noon Meal science fiction 1958 304 | O Ye of Little Faith science fiction 1968 305 | Oddy and Id science fiction 1950 306 | Of Ants and Dinosaurs science fiction 2013 307 | On Exactitude and Science fiction 1946 308 | On the Downhill Slide science fiction 1972 309 | On the Feasibility of Coal-Driven Power Stations science fiction 1956 310 | On the Slab science fiction 1981 311 | One for the Road science fiction 1959 312 | One Life, Furnished in Early Poverty science fiction 1970 313 | One-Way Journey science fiction 1955 314 | Operation Cassandra science fiction 1958 315 | Opium science fiction 1977 316 | Other Worlds science fiction 1990 317 | Out of All Them Bright Stars science fiction 1986 318 | Over the River and Through the Woods science fiction 1965 319 | Ozymandias science fiction 1972 320 | Paingod science fiction 1964 321 | Paladin of the Last Hour science fiction 1985 322 | Parable of Cervantes and the Quixote poem 1955 323 | Parable of the Palace fiction 1956 324 | Paradise science fiction 1946 325 | Paradiso, XXXI, 108 fiction 1954 326 | Partial Magic in the Quixote essay 1949 327 | Paulie Charmed the Sleeping Woman science fiction 1962 328 | Philtre Tip science fiction 1961 329 | Pierre Menrad, Author of Don Quixote fiction 1939 330 | Planet Story science fiction 1975 331 | Precession science fiction 1980 332 | Pretty Maggie Moneyeyes science fiction 1967 333 | Prince Myshkin, and Hold the Relish science fiction 1982 334 | Prodigy science fiction 1949 335 | Project Nightmare science fiction 1953 336 | Pulling Hard Time science fiction 1995 337 | Punky & The Yale Men science fiction 1966 338 | Quick to Haste science fiction 1969 339 | Quicktime science fiction 1985 340 | Ragnarok fiction 1959 341 | Rain, Rain, Go Away science fiction 1956 342 | Rat science fiction 1986 343 | Reason science fiction 1941 344 | Red Star, Winter Orbit science fiction 1983 345 | Repent, Harlequin! Said the Ticktockman science fiction 1965 346 | Requiem science fiction 1940 347 | Riders of the Purple Wage science fiction 1967 348 | Riding the Dark Train Out science fiction 1961 349 | Riverworld science fiction 1966 350 | Robbie science fiction 1940 351 | Rock God science fiction 1969 352 | Rocket Summer science fiction 1950 353 | Runaround science fiction 1942 354 | Sandkings science fiction 1979 355 | Saturn, November 11th science fiction 1981 356 | Scartaris, June 28th science fiction 1990 357 | Schrodinger's Plague science fiction 1982 358 | Schwarzschild Radius science fiction 1987 359 | Seeing science fiction 1976 360 | Sensible City science fiction 1994 361 | Seventy-Two Letters science fiction 2000 362 | Sex and/or Mr. Morrison science fiction 1967 363 | Shadow, Shadow on the Wall science fiction 1951 364 | Shall the Dust Praise Thee? science fiction 1967 365 | Shatterday science fiction 1975 366 | Shattered Like a Glass Goblin science fiction 1968 367 | She's a Young Thing and Cannot Leaver Her Mother science fiction 1988 368 | Shoppe Keeper science fiction 1977 369 | Silence east euro lit 1959 370 | Silent in Gehenna science fiction 1971 371 | Silhouette science fiction 1975 372 | Simulacrum science fiction 2011 373 | Skeleton science fiction 1977 374 | Sky Lift science fiction 1953 375 | Slow Sculpture science fiction 1970 376 | Snow science fiction 1985 377 | Soft Monkey science fiction 1987 378 | Somehow, I Don't Think We're in Kansas, Toto science fiction 1974 379 | Somerset Dreams science fiction 1969 380 | Soundless Evening science fiction 1972 381 | Speech Sound science fiction 1983 382 | Stable Strategies for Middle Management science fiction 1988 383 | Stand Still and Die thriller 1956 384 | State Change science fiction 2004 385 | State of Grace science fiction 1977 386 | Still-Life science fiction 1972 387 | Stoned Counsel science fiction 1972 388 | Story of the Warrior and the Captive Maiden fiction 1949 389 | Story of Your Life science fiction 1998 390 | Strange Wine science fiction 1976 391 | Stuffing science fiction 1982 392 | Suicide science fiction 1970 393 | Sun of China science fiction 2013 394 | Symbiosis science fiction 1972 395 | Take Care of Joey science fiction 1970 396 | Taking Care of God science fiction 2005 397 | Tandy's Story science fiction 1961 398 | Tauf Aleph science fiction 1981 399 | Tell Your Fortune science fiction 1967 400 | Test to Destruction science fiction 1967 401 | That Girl Who Knew What They Meant science fiction 1970 402 | The [Widget], the [Wadget], and Boff science fiction 1955 403 | The 10:00 Report is Brought to You By... science fiction 1972 404 | The 3 Most Important Things in Life science fiction 1978 405 | The Absolutely Perfect Murder science fiction 1965 406 | The Adventure of Black Peter mystery 1904 407 | The Adventure of Charles Augustus Milverton mystery 1904 408 | The Adventure of the Gloria Scott mystery 1893 409 | The Adventure of the Abbey Grange mystery 1904 410 | The Adventure of the Beryl Coronet mystery 1892 411 | The Adventure of the Blue Carbuncle mystery 1892 412 | The Adventure of the Cardboard Box mystery 1893 413 | The Adventure of the Copper Beeches mystery 1892 414 | The Adventure of the Crooked Man mystery 1893 415 | The Adventure of the Dancing Men mystery 1903 416 | The Adventure of the Empty House mystery 1903 417 | The Adventure of the Engineer's Thumb mystery 1892 418 | The Adventure of the Final Problem mystery 1893 419 | The Adventure of the Golden Pince-Nez mystery 1904 420 | The Adventure of the Greek Interpreter mystery 1893 421 | The Adventure of the Missing Three-Quarter mystery 1904 422 | The Adventure of the Musgrave Ritual mystery 1893 423 | The Adventure of the Naval Treaty mystery 1893 424 | The Adventure of the Noble Bachelor mystery 1892 425 | The Adventure of the Norwood Builder mystery 1903 426 | The Adventure of the Priory School mystery 1904 427 | The Adventure of the Reigate Squires mystery 1893 428 | The Adventure of the Resident Patient mystery 1893 429 | The Adventure of the Second Stain mystery 1904 430 | The Adventure of the Silver Blaze mystery 1892 431 | The Adventure of the Six Napoleons mystery 1904 432 | The Adventure of the Solitary Cyclist mystery 1903 433 | The Adventure of the Speckled Band mystery 1892 434 | The Adventure of the Stockbroker's Clerk mystery 1893 435 | The Adventure of the Yellow Face mystery 1893 436 | The Age of Gold science fiction 1990 437 | The Ajeri Diary science fiction 1968 438 | The Aleph fiction 1949 439 | The Approach to Al-Mu'tasim fiction 1936 440 | The Argentine Writer and Tradition essay 1951 441 | The Avenger of Death science fiction 1988 442 | The Babylon Lottery fiction 1941 443 | The Beast of Barsac science fiction 1944 444 | The Belonging Kind science fiction 1981 445 | The Big Hunger science fiction 1952 446 | The Big Space Fuck science fiction 1972 447 | The Black Cloud science fiction 1957 448 | The Bob Dylan Tambourine Software & Satori Support Services Consortium, Ltd. science fiction 1985 449 | The Bookmaking Habits of Select Species science fiction 2012 450 | The Boscombe Valley Mystery mystery 1891 451 | The Boulevard of Broken Dreams science fiction 1975 452 | The Brains of Rats science fiction 1986 453 | The Byrds science fiction 1982 454 | The Captive fiction 1957 455 | The Cheese Stands Alone science fiction 1981 456 | The Children science fiction 1952 457 | The Circle science fiction 2014 458 | The Circular Ruins fiction 1940 459 | The Cistern science fiction 1947 460 | The City of Silence science fiction 2005 461 | The Crackpots science fiction 1956 462 | The Crowd science fiction 1943 463 | The Daughter of the Tree science fiction 1951 464 | The Day After the Day the Martians Came science fiction 1967 465 | The Day I Died science fiction 1973 466 | The Dead Man fiction 1946 467 | The Death of Schillinger east euro lit 1959 468 | The Deathbird science fiction 1973 469 | The Diagnosis of Dr. Darqueangel science fiction 1977 470 | The Discarded science fiction 1959 471 | The Doll-House science fiction 1967 472 | The Dragon on the Bookshelf science fiction 1995 473 | The Dreams a Nightmare Dreams science fiction 1997 474 | The Dwarf science fiction 1954 475 | The Earth Men science fiction 1948 476 | The Emissary science fiction 1947 477 | The Encounter science fiction 1970 478 | The End fiction 1953 479 | The Evitable Conflict science fiction 1950 480 | The Evolution of Human Science science fiction 2000 481 | The Executioner of the Malformed Children science fiction 1978 482 | The Extraordinary Voyages of Amelie Bertrand science fiction 1979 483 | The Face of Helene Bournouw science fiction 1960 484 | The Fearful Sphere of Pascal essay 1947 485 | The Few, the Proud science fiction 1987 486 | The Fish of Lijiang science fiction 2006 487 | The Five Orange Pips mystery 1891 488 | The Flower of Shazui science fiction 2012 489 | The Forces that Crush science fiction 1958 490 | The Form of the Sword fiction 1942 491 | The Funeral science fiction 1972 492 | The Fusion Bomb science fiction 1972 493 | The Garden of Forking Paths fiction 1941 494 | The Gateway Asteroid science fiction 1990 495 | The Gernsback Continuum science fiction 1981 496 | The Girl From Mars science fiction 1950 497 | The Goddess in the Ice science fiction 1967 498 | The God's Script fiction 1949 499 | The Golden Helix science fiction 1979 500 | The Golden Man science fiction 1954 501 | The Green Morning science fiction 1950 502 | The Handler science fiction 1960 503 | The Happy Breed science fiction 1967 504 | The Heart of the Other Side science fiction 1962 505 | The Henry Miller Dawn Patrol science fiction 1977 506 | The Home Planet science fiction 1990 507 | The Hounds science fiction 1974 508 | The Hour That Stretches science fiction 1982 509 | The House of Asterion fiction 1947 510 | The House the Blakeneys Built science fiction 1965 511 | The Immortal fiction 1947 512 | The Indian Spirit Guide science fiction 1948 513 | The Infinity Box science fiction 1971 514 | The Invasion science fiction 1940 515 | The January Offensive east euro lit 1959 516 | The Jar science fiction 1944 517 | The Jigsaw Man science fiction 1967 518 | The Jungle Rot Kid on the Nod science fiction 1968 519 | The Lake science fiction 1944 520 | The Lake Was Full of Artificial Things science fiction 1985 521 | The Last Days of the Captain science fiction 1962 522 | The Last Generation? science fiction 1946 523 | The Leaser of Two Evils science fiction 1979 524 | The Library of Babel fiction 1941 525 | The Life of Anybody science fiction 1984 526 | The Lingering Scent of Woodsmoke science fiction 1996 527 | The Literomancer science fiction 2010 528 | The Litigation Master and the Monkey King science fiction 2013 529 | The Locusts science fiction 1950 530 | The Long Years science fiction 1948 531 | The Longest Fall science fiction 2013 532 | The Lottery in Babylon fiction 1941 533 | The Lucky Strike science fiction 1984 534 | The Luggage Store science fiction 1950 535 | The Maker fiction 1958 536 | The Malley System science fiction 1967 537 | The Man on the Threshold fiction 1952 538 | The Man Upstairs science fiction 1947 539 | The Man Who Ended History: A Documentary science fiction 2011 540 | The Man Who Lost the Sea science fiction 1959 541 | The Man Who Rowed Christopher Columbus Ashore science fiction 1991 542 | The Man Who Sold the Moon science fiction 1950 543 | The Man Who Was Heavily into Revenge science fiction 1978 544 | The Man Who Went to the Moon-Twice science fiction 1967 545 | The Man With English science fiction 1953 546 | The Man with the Package east euro lit 1959 547 | The Man With the Twisted Lips mystery 1891 548 | The Man without a Planet science fiction 1962 549 | The Mark Gable Foundation science fiction 1961 550 | The Martian science fiction 1949 551 | The Menace from Earth science fiction 1957 552 | The Merchants of Venus science fiction 1972 553 | The Micro-Age science fiction 2013 554 | The Mile-Long Spaceship science fiction 1956 555 | The Milk of Paradise science fiction 1972 556 | The Million-Year Picnic science fiction 1946 557 | The Miracle of the Broom Closet science fiction 1952 558 | The Mirrors of Enigmas essay 1940 559 | The Mountains of Sunset, the Mountains of Dawn science fiction 1974 560 | The Mountebank fiction 1957 561 | The Museum on Cyclops Avenue science fiction 1995 562 | The Musicians science fiction 1950 563 | The Naming of Names science fiction 1950 564 | The New Atlantis science fiction 1975 565 | The New York Review of Bird science fiction 1975 566 | The Next in Line science fiction 1947 567 | The Night That All Time Broke Out science fiction 1967 568 | The Off Season science fiction 1948 569 | The Old Ones science fiction 1950 570 | The Oldest Soldier science fiction 1960 571 | The Other Death fiction 1949 572 | The Other Eye of Polyphemus science fiction 1977 573 | The Outpost Undiscovered by Tourists science fiction 1982 574 | The Pale Silver Dollar of the Moon Pays Its Way and Makes Change vr.1 science fiction 1994 575 | The Pale Silver Dollar of the Moon Pays Its Way and Makes Change vr.2 science fiction 1994 576 | The Paper Menagerie science fiction 2011 577 | The Patterns of Drone science fiction 1970 578 | The People Who Walked On east euro lit 1959 579 | The Perfect Match science fiction 2012 580 | The Phantom of the Sewers science fiction 1978 581 | The Place with No Name science fiction 1969 582 | The Plot fiction 1957 583 | The Plot Is the Thing science fiction 1966 584 | The Private War of Private Jacob science fiction 1973 585 | The Problem of the Sore Bridge-Among Others science fiction 1975 586 | The Prowler in the City on the Edge of Forever science fiction 1967 587 | The Recognition science fiction 1967 588 | The Red Canary science fiction 1973 589 | The Red-Headed League mystery 1891 590 | The Region Between science fiction 1970 591 | The Regular science fiction 2014 592 | The Resurgence of Miss Ankle-Strap Wedgie science fiction 1968 593 | The Roads Must Roll science fiction 1940 594 | The Season of Babies science fiction 1959 595 | The Secret Miracle fiction 1943 596 | The Sect of Phoenix fiction 1952 597 | The Settlers science fiction 1950 598 | The Sex Opposite science fiction 1952 599 | The Shape of the Sword fiction 1942 600 | The Shore science fiction 1950 601 | The Silent Towns science fiction 1949 602 | The Silver Corridor science fiction 1956 603 | The Simple Way science fiction 1951 604 | The Singers science fiction 1956 605 | The Skills of Xanadu science fiction 1956 606 | The Sky is Burning science fiction 1958 607 | The Small Assaassin science fiction 1962 608 | The Smiling Future science fiction 1965 609 | The South fiction 1953 610 | The Starseekers science fiction 1990 611 | The Start of the End of It All science fiction 1981 612 | The Summer Night science fiction 1949 613 | The Superior Sex science fiction 1968 614 | The Supper east euro lit 1959 615 | The Sycthe science fiction 1943 616 | The Taxpayer science fiction 1950 617 | The Test Stand science fiction 1955 618 | The Test-Tube Creature, Afterward science fiction 1972 619 | The Theologians fiction 1947 620 | The Third Expedition science fiction 1948 621 | The Time Piece science fiction 1975 622 | The Transit of Venus science fiction 1962 623 | The Two Kings and the Two Labyrinths fiction 1946 624 | The Universe of Robert Blake science fiction 1962 625 | The Unspeakable Betrothal science fiction 1949 626 | The Very Last Day of a Good Woman science fiction 1958 627 | The Village science fiction 1973 628 | The Visit science fiction 1990 629 | The Voice of the Sonar in My Veriform Appendix science fiction 1971 630 | The Volcano science fiction 1976 631 | The Wages of Humanity science fiction 2013 632 | The Waiting fiction 1950 633 | The Wall and the Books essay 1950 634 | The Wandering Earth science fiction 2013 635 | The War at Home science fiction 1985 636 | The Warlord of Saturn's Moon science fiction 1974 637 | The Watchers science fiction 1950 638 | The Watchful Poker Chip of H. Matisse science fiction 1954 639 | The Waves science fiction 2012 640 | The Whimper of Whipped Dogs science fiction 1973 641 | The Will science fiction 1953 642 | The Wind science fiction 1943 643 | The Wind Beyond the Mountains science fiction 1957 644 | The Wine Has Been Left Open Too Long and the Memory Has Gone Flat science fiction 1976 645 | The Winter Flies science fiction 1967 646 | The Winter Market science fiction 1985 647 | The Witness fiction 1957 648 | The Women Men Don't See science fiction 1973 649 | The Wonderful Death of Dudley Stone science fiction 1954 650 | The Word for World is Forrest science fiction 1972 651 | The World of Stone east euro lit 1959 652 | The Writing of the God fiction 1949 653 | The Year of the Jackpot science fiction 1952 654 | The Year of the Rat science fiction 2009 655 | The Yellow Rose fiction 1960 656 | The Zahir fiction 1947 657 | Theme of the Traitor and Hero fiction 1944 658 | There Was an Old Woman science fiction 1944 659 | There Will Come Soft Rains science fiction 1950 660 | Things Lost science fiction 1972 661 | This Way for the Gas, Ladies and Gentlemen east euro lit 1959 662 | Three Versions of Judas fiction 1944 663 | Throwback science fiction 1952 664 | Thunder and Roses science fiction 1957 665 | Time Travel for Pedestrians science fiction 1972 666 | Tiny Ally science fiction 1957 667 | Tissue science fiction 1972 668 | Tlon, Uqbar, Orbis Teritus fiction 1940 669 | To Be Continued science fiction 1956 670 | To Explain to Mrs. Thompson science fiction 1951 671 | To Here and the Easel science fiction 1954 672 | Toenails fiction 1936 673 | Tongtong's Summer science fiction 2014 674 | Totenbuch science fiction 1972 675 | Touched With Fire science fiction 1954 676 | Tower of Babylon science fiction 1990 677 | Tracking Level science fiction 1956 678 | Transcending Destiny science fiction 1957 679 | Trouble With Ants science fiction 1951 680 | Try and Change the Past science fiction 1958 681 | Twink science fiction 1955 682 | Unaccompanied Sonata science fiction 1979 683 | Uncle Einar science fiction 1947 684 | Uncle Fremmis science fiction 1970 685 | Underground science fiction 1967 686 | Understand science fiction 1991 687 | Unlocking the Air science fiction 1990 688 | Usher II science fiction 1950 689 | Valerie science fiction 1972 690 | Valery as Symbol essay 1962 691 | Vaster than Empires and More Slow science fiction 1971 692 | Visionary science fiction 1959 693 | Wanted in Surgery science fiction 1957 694 | Water Is for Washing science fiction 1947 695 | Way in the Middle of the Air science fiction 1950 696 | We See Things Differently science fiction 1989 697 | What Happened to Auguste Clarot? science fiction 1967 698 | What I Did on My Vaction This Summer by Little Bobby Hirschhorn, Age 27 science fiction 1964 699 | What's It Like Out There? science fiction 1952 700 | When Auld's Acquaintance is Forgot science fiction 1982 701 | When I was a Hired Gun science fiction 1973 702 | When I Was Miss Dow science fiction 1966 703 | When it Changed science fiction 1972 704 | When the Bentfin Boomer Boys on Old New Alabama science fiction 1972 705 | When the Change-Winds Blow science fiction 1964 706 | Where Have You Been, Billy Boy, Billy Boy? science fiction 1971 707 | Where I Shall Dwell in the Next World science fiction 1992 708 | With a Finger in My I science fiction 1972 709 | With Her Eyes science fiction 2013 710 | With Virgin Oddum at the East Pole science fiction 1985 711 | Working with the Little People science fiction 1979 712 | Would You Do It for a Penny science fiction 1967 713 | Ylla science fiction 1950 714 | You Triflin' Skunk science fiction 1954 715 | Zero Gee science fiction 1972 716 | And the Moon be Still as Bright science fiction 1948 -------------------------------------------------------------------------------- /tests/perf/data/lib-query0: -------------------------------------------------------------------------------- 1 | 6.81 user 2 | -------------------------------------------------------------------------------- /tests/perf/data/lib-query1: -------------------------------------------------------------------------------- 1 | 4.73 user 2 | -------------------------------------------------------------------------------- /tests/perf/data/lib-query2: -------------------------------------------------------------------------------- 1 | 3.70 user 2 | -------------------------------------------------------------------------------- /tests/perf/data/lib-query3: -------------------------------------------------------------------------------- 1 | 11.81 user 2 | -------------------------------------------------------------------------------- /tests/perf/data/lib-query4: -------------------------------------------------------------------------------- 1 | 1.54 user 2 | -------------------------------------------------------------------------------- /tests/perf/data/lib-query5: -------------------------------------------------------------------------------- 1 | 38.04 user 2 | -------------------------------------------------------------------------------- /tests/perf/data/query0: -------------------------------------------------------------------------------- 1 | 6.39 user 2 | -------------------------------------------------------------------------------- /tests/perf/data/query1: -------------------------------------------------------------------------------- 1 | 4.18 user 2 | -------------------------------------------------------------------------------- /tests/perf/data/query2: -------------------------------------------------------------------------------- 1 | 11.17 user 2 | -------------------------------------------------------------------------------- /tests/perf/data/query3: -------------------------------------------------------------------------------- 1 | 12.39 user 2 | -------------------------------------------------------------------------------- /tests/perf/data/query4: -------------------------------------------------------------------------------- 1 | 3.45 user 2 | -------------------------------------------------------------------------------- /tests/perf/data/query5: -------------------------------------------------------------------------------- 1 | 44.35 user 2 | -------------------------------------------------------------------------------- /tests/perf/queries/lib-query0.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "../../data.hpp" 3 | 4 | using query = 5 | sql::query< 6 | "SELECT title, genre AS type, year AS published " 7 | "FROM stories " 8 | "WHERE NOT genre <> \"science fiction\" AND NOT year <= 1970", 9 | stories 10 | >; 11 | 12 | int main() 13 | { 14 | stories s{ sql::load(perf_folder + stories_data, '\t') }; 15 | 16 | for (std::size_t i{}; i < iters; ++i) 17 | { 18 | for (query q{ s }; auto const& [t, g, y] : q) 19 | { 20 | std::cout << t << '\t' << g << '\t' << y << '\n'; 21 | } 22 | } 23 | 24 | return 0; 25 | } 26 | -------------------------------------------------------------------------------- /tests/perf/queries/lib-query1.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "../../data.hpp" 3 | 4 | using query = 5 | sql::query< 6 | "SELECT title, genre AS type, year AS published, pages " 7 | "FROM books " 8 | "WHERE NOT genre <> \"science fiction\" AND NOT year >= 1970 OR pages < 300", 9 | books 10 | >; 11 | 12 | int main() 13 | { 14 | books b{ sql::load(perf_folder + books_data), '\t' }; 15 | 16 | for (std::size_t i{}; i < iters; ++i) 17 | { 18 | for (query q{ b }; auto const& [t, g, y, p] : q) 19 | { 20 | std::cout << t << '\t' << g << '\t' << y << '\t' << p << '\n'; 21 | } 22 | } 23 | 24 | return 0; 25 | } 26 | -------------------------------------------------------------------------------- /tests/perf/queries/lib-query2.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "../../data.hpp" 3 | 4 | using query = 5 | sql::query< 6 | "SELECT genre AS type, name " 7 | "FROM books NATURAL JOIN authored " 8 | "WHERE NOT genre = \"science fiction\" AND name != \"Harlan Ellison\"", 9 | books, 10 | authored 11 | >; 12 | 13 | int main() 14 | { 15 | books b{ sql::load(perf_folder + books_data, '\t') }; 16 | authored a{ sql::load(perf_folder + authored_data, '\t') }; 17 | 18 | for (std::size_t i{}; i < iters; ++i) 19 | { 20 | for (query q{ b, a }; auto const& [g, n] : q) 21 | { 22 | std::cout << g << '\t' << n << '\n'; 23 | } 24 | } 25 | 26 | return 0; 27 | } 28 | -------------------------------------------------------------------------------- /tests/perf/queries/lib-query3.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "../../data.hpp" 3 | 4 | using query = 5 | sql::query< 6 | "SELECT genre AS type, year AS published, title, name " 7 | "FROM stories NATURAL JOIN authored " 8 | "WHERE genre = \"science fiction\" AND year > 1970 AND name != \"Harlan Elison\"", 9 | stories, 10 | authored 11 | >; 12 | 13 | int main() 14 | { 15 | stories s{ sql::load(perf_folder + stories_data, '\t') }; 16 | authored a{ sql::load(perf_folder + authored_data, '\t') }; 17 | 18 | for (std::size_t i{}; i < iters; ++i) 19 | { 20 | for (query q{ s, a }; auto const& [g, y, t, n] : q) 21 | { 22 | std::cout << g << '\t' << y << '\t' << t << '\t' << n << '\n'; 23 | } 24 | } 25 | 26 | return 0; 27 | } 28 | -------------------------------------------------------------------------------- /tests/perf/queries/lib-query4.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "../../data.hpp" 3 | 4 | using query = 5 | sql::query< 6 | "SELECT book, genre AS type, year As published " 7 | "FROM books CROSS JOIN authored " 8 | "WHERE NOT genre != \"science fiction\" AND year > 1970", 9 | books, 10 | authored 11 | >; 12 | 13 | int main() 14 | { 15 | books b{ sql::load(perf_folder + books_data '\t') }; 16 | authored a{ sql::load(perf_folder + authored_data, '\t') }; 17 | 18 | for (std::size_t i{}; i < iters / offset; ++i) 19 | { 20 | for (query q{ b, a }; auto const& [b, g, y] : q) 21 | { 22 | std::cout << b << '\t' << g << '\t' << y << '\n'; 23 | } 24 | } 25 | 26 | return 0; 27 | } 28 | -------------------------------------------------------------------------------- /tests/perf/queries/lib-query5.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "../../data.hpp" 3 | 4 | using query = 5 | sql::query< 6 | "SELECT story, genre AS type, year AS published, title, collection, pages " 7 | "FROM stories CROSS join collected " 8 | "WHERE genre != \"science fiction\" OR year >= 1970 OR NOT pages < 300", 9 | stories, 10 | collected 11 | >; 12 | 13 | int main() 14 | { 15 | stories s{ sql::load(perf_folder + stories_data, '\t') }; 16 | collected c{ sql::load(perf_folder + collected_data, '\t') }; 17 | 18 | for (std::size_t i{}; i < iters / offset; ++i) 19 | { 20 | for (query q{ s, c }; auto const& [s, g, y, t, c, p] : q) 21 | { 22 | std::cout << s << '\t' << g << '\t' << y << '\t' << t << '\t' << c << '\t' << p << '\n'; 23 | } 24 | } 25 | 26 | return 0; 27 | } 28 | -------------------------------------------------------------------------------- /tests/perf/queries/query0.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | #include "../../data.hpp" 9 | 10 | stories_type query(stories_type const& s) 11 | { 12 | using std::get; 13 | stories_type output{}; 14 | 15 | for (auto const& row : s) 16 | { 17 | if (!(get<1>(row) != "science fiction") && !(get<2>(row) <= 1970)) 18 | { 19 | output.push_back(row); 20 | } 21 | } 22 | 23 | return output; 24 | } 25 | 26 | int main() 27 | { 28 | stories_type s{ stories_load<'\t'>() }; 29 | 30 | for (std::size_t i{}; i < iters; ++i) 31 | { 32 | for (auto data{ query(s) }; auto const& [t, g, y] : data) 33 | { 34 | std::cout << t << '\t' << g << '\t' << y << '\n'; 35 | } 36 | } 37 | 38 | return 0; 39 | } 40 | -------------------------------------------------------------------------------- /tests/perf/queries/query1.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | #include "../../data.hpp" 9 | 10 | books_type query(books_type const& b) 11 | { 12 | using std::get; 13 | books_type output{}; 14 | 15 | for (auto const& row : b) 16 | { 17 | if (!(get<1>(row) != "science fiction") && !(get<2>(row) >= 1970) || get<3>(row) < 300) 18 | { 19 | output.push_back(row); 20 | } 21 | } 22 | 23 | return output; 24 | } 25 | 26 | int main() 27 | { 28 | books_type b{ books_load<'\t'>() }; 29 | 30 | for (std::size_t i{}; i < iters; ++i) 31 | { 32 | for (auto data{ query(b) }; auto const& [t, g, y, p] : data) 33 | { 34 | std::cout << t << '\t' << g << '\t' << y << '\t' << p << '\n'; 35 | } 36 | } 37 | 38 | return 0; 39 | } 40 | -------------------------------------------------------------------------------- /tests/perf/queries/query2.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | #include "../../data.hpp" 9 | 10 | authored_type query(books_type const& b, authored_type const& a) 11 | { 12 | using std::get; 13 | authored_type output{}; 14 | std::unordered_map cache{}; 15 | 16 | for (auto const& row : a) 17 | { 18 | cache[get<0>(row)] = row; 19 | } 20 | 21 | for (auto const& b_row : b) 22 | { 23 | auto it{ cache.find(get<0>(b_row)) }; 24 | 25 | if (it != cache.end()) 26 | { 27 | auto const& a_row{ get<1>(*it) }; 28 | 29 | if (!(get<1>(b_row) == "science fiction") && get<1>(a_row) != "Harlan Ellison") 30 | { 31 | output.emplace_back(get<1>(b_row), get<1>(a_row)); 32 | } 33 | } 34 | } 35 | 36 | return output; 37 | } 38 | 39 | int main() 40 | { 41 | books_type b{ books_load<'\t'>() }; 42 | authored_type a{ authored_load<'\t'>() }; 43 | 44 | for (std::size_t i{}; i < iters; ++i) 45 | { 46 | for (auto data{ query(b, a) }; auto const& [g, n] : data) 47 | { 48 | std::cout << g << '\t' << n << '\n'; 49 | } 50 | } 51 | 52 | return 0; 53 | } 54 | -------------------------------------------------------------------------------- /tests/perf/queries/query3.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | #include "../../data.hpp" 9 | 10 | using output_type = std::vector>; 11 | 12 | output_type query(stories_type const& s, authored_type const& a) 13 | { 14 | using std::get; 15 | output_type output{}; 16 | std::unordered_map cache{}; 17 | 18 | for (auto const& row : a) 19 | { 20 | cache[get<0>(row)] = row; 21 | } 22 | 23 | for (auto const& s_row : s) 24 | { 25 | auto it{ cache.find(get<0>(s_row)) }; 26 | 27 | if (it != cache.end()) 28 | { 29 | auto const& a_row{ get<1>(*it) }; 30 | 31 | if (get<1>(s_row) == "science fiction" && get<2>(s_row) > 1970 && get<1>(a_row) != "Harlan Ellison") 32 | { 33 | output.emplace_back(get<1>(s_row), get<2>(s_row), get<0>(a_row), get<1>(a_row)); 34 | } 35 | } 36 | } 37 | 38 | return output; 39 | } 40 | 41 | int main() 42 | { 43 | stories_type s{ stories_load<'\t'>() }; 44 | authored_type a{ authored_load<'\t'>() }; 45 | 46 | for (std::size_t i{}; i < iters; ++i) 47 | { 48 | for (auto data{ query(s, a) }; auto const& [g, y, t, n] : data) 49 | { 50 | std::cout << g << '\t' << y << '\t' << t << '\t' << n << '\n'; 51 | } 52 | } 53 | 54 | return 0; 55 | } 56 | -------------------------------------------------------------------------------- /tests/perf/queries/query4.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | #include "../../data.hpp" 9 | 10 | using output_type = std::vector>; 11 | 12 | output_type query(books_type const& b, authored_type const& a) 13 | { 14 | using std::get; 15 | output_type output{}; 16 | 17 | for (auto const& a_row : a) 18 | { 19 | for (auto const& b_row : b) 20 | { 21 | if (!(get<1>(b_row) != "science fiction") && get<2>(b_row) > 1970) 22 | { 23 | output.emplace_back(get<0>(b_row), get<1>(b_row), get<2>(b_row)); 24 | } 25 | } 26 | } 27 | 28 | return output; 29 | } 30 | 31 | int main() 32 | { 33 | books_type b{ books_load<'\t'>() }; 34 | authored_type a{ authored_load<'\t'>() }; 35 | 36 | for (std::size_t i{}; i < iters / offset; ++i) 37 | { 38 | for (auto data{ query(b, a) }; auto const& [b, g, y] : data) 39 | { 40 | std::cout << b << '\t' << g << '\t' << y << '\n'; 41 | } 42 | } 43 | 44 | return 0; 45 | } 46 | -------------------------------------------------------------------------------- /tests/perf/queries/query5.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | #include "../../data.hpp" 9 | 10 | using output_type = std::vector>; 11 | 12 | output_type query(stories_type const& s, collected_type const& c) 13 | { 14 | using std::get; 15 | output_type output{}; 16 | 17 | for (auto const& c_row : c) 18 | { 19 | for (auto const& s_row : s) 20 | { 21 | if (!(get<1>(s_row) != "science fiction") || get<2>(s_row) >= 1970 || !(get<2>(c_row) < 300)) 22 | { 23 | output.emplace_back(get<0>(s_row), get<1>(s_row), get<2>(s_row), get<0>(c_row), get<1>(c_row), get<2>(c_row)); 24 | } 25 | } 26 | } 27 | 28 | return output; 29 | } 30 | 31 | int main() 32 | { 33 | stories_type s{ stories_load<'\t'>() }; 34 | collected_type c{ collected_load<'\t'>() }; 35 | 36 | for (std::size_t i{}; i < iters / offset; ++i) 37 | { 38 | for (auto data{ query(s, c) }; auto const& [st, g, y, t, co, p] : data) 39 | { 40 | std::cout << st << '\t' << g << '\t' << y << '\t' << t << '\t' << co << '\t' << p << '\n'; 41 | } 42 | } 43 | 44 | return 0; 45 | } 46 | -------------------------------------------------------------------------------- /tests/perf/runner.sh: -------------------------------------------------------------------------------- 1 | python3 scripts/runner.py 2 | 3 | -------------------------------------------------------------------------------- /tests/perf/scripts/runner.py: -------------------------------------------------------------------------------- 1 | import os 2 | 3 | QUERIES = 6 4 | 5 | def exe(file, q): 6 | if int(q) >= 4: 7 | os.system("g++ -std=c++2a -DCROSS -O3 -I../../single-header -o test queries/" + file) 8 | else: 9 | os.system("g++ -std=c++2a -O3 -I../../single-header -o test queries/" + file) 10 | os.system("/usr/bin/time -f \"%U user\" -o data/" + file[:-4] + " ./test > /dev/null") 11 | os.remove("test") 12 | 13 | def main(): 14 | print("Benchmark Test Begin") 15 | for q in range(QUERIES): 16 | q = str(q) 17 | print("\tTest Query " + q) 18 | exe("lib-query" + q + ".cpp", q) 19 | exe("query" + q + ".cpp", q) 20 | print("Benchmark Test End") 21 | 22 | if __name__ == "__main__": 23 | main() 24 | -------------------------------------------------------------------------------- /tests/runner.sh: -------------------------------------------------------------------------------- 1 | mkdir queries 2 | python3 scripts/generate.py 3 | python3 scripts/runner.py 4 | -------------------------------------------------------------------------------- /tests/scripts/compose.py: -------------------------------------------------------------------------------- 1 | # Composes a test file 2 | 3 | begin = """#include 4 | 5 | #include "data.hpp" 6 | 7 | using query = 8 | sql::query< 9 | """ 10 | middle = """ 11 | >; 12 | 13 | int main() 14 | { 15 | """ 16 | end = """ 17 | return 0; 18 | } 19 | """ 20 | 21 | def data(tokens): 22 | f = False 23 | cs = 1 24 | ts = [] 25 | for tk in tokens: 26 | tk = tk.lower() 27 | if tk[-1] == ",": 28 | cs += 1 29 | if tk == "where": 30 | break 31 | if tk == "from": 32 | f = True 33 | elif f and tk != "cross" and tk != "natural" and tk != "join": 34 | ts += [tk] 35 | return cs, ts 36 | 37 | def templ(query, ts): 38 | templ_spec = "\t\t\"" + query + "\"" 39 | for t in ts: 40 | templ_spec += ",\n\t\t" + t 41 | return templ_spec 42 | 43 | def func(ts, cs): 44 | body = "" 45 | args = "" 46 | out = "\tstd::cout << " 47 | count = 0 48 | for t in ts: 49 | body += "\t" + t + " t" + str(count) + "{ sql::load<" + t + ">(data_folder + " + t + "_data, '\\t') };\n" 50 | args += "t" + str(count) + ", " 51 | count += 1 52 | body += "\n\tfor (query q{ " + args[:-2] + " }; auto const& [" 53 | for c in range(cs): 54 | body += "c" + str(c) + ", " 55 | out += "c" + str(c) + " << \'|\' << " 56 | body = body[:-2] + "] : q)\n\t{\n\t" + out[:-11] + " << \'\\n\';\n\t}\n" 57 | return body 58 | 59 | def main(): 60 | infile = open("queries/query", "r") 61 | query = infile.readline().strip() 62 | infile.close() 63 | tokens = query.split() 64 | cs, ts = data(tokens[1:]) 65 | spec = templ(query, ts) 66 | body = func(ts, cs) 67 | outfile = open("test.cpp", "w") 68 | outfile.write(begin + spec + middle + body + end) 69 | outfile.close() 70 | 71 | if __name__ == "__main__": 72 | main() 73 | -------------------------------------------------------------------------------- /tests/scripts/generate.py: -------------------------------------------------------------------------------- 1 | # SQL query generator for test queries 2 | # Generates over 1.4 million unique queries 3 | 4 | import itertools 5 | import random 6 | 7 | tables = ["books", "stories", "authored", "collected"] 8 | columns = { 9 | "books": ["book", "genre", "year", "pages"], 10 | "stories": ["story", "genre", "year"], 11 | "authored": ["title", "name"], 12 | "collected": ["title", "collection", "pages"] 13 | } 14 | joinable = { 15 | "books": ["authored"], 16 | "stories": ["authored", "collected"], 17 | "authored": [], 18 | "collected": [] 19 | } 20 | joins = ["cross"] 21 | renames = { 22 | "genre": "type", 23 | "year": "published" 24 | } 25 | integral = ["year", "pages"] 26 | all_comp = ["=", "!=", "<>"] 27 | integral_comp = [">", "<", ">=", "<="] 28 | bool_op = ["or", "and"] 29 | negate_op = ["", "not "] 30 | where_data = { 31 | "name": ["Harlan Ellison"], 32 | "year": [1970], 33 | "pages": [300], 34 | "genre": ["science fiction"] 35 | } 36 | outfiles = { 37 | "joinless": open("queries/joinless-queries.txt", "w"), 38 | "cross": open("queries/cross-queries.txt", "w") 39 | } 40 | 41 | def col_list(cs): 42 | cl = [] 43 | re = False 44 | cols = "" 45 | for c in cs: 46 | cols += c 47 | if c in renames.keys(): 48 | cols += " as " + renames[c] 49 | re = True 50 | cols += ", " 51 | cl += [cols[:-2]] 52 | if re: 53 | cols = "" 54 | for c in cs: 55 | cols += c 56 | cols += ", " 57 | cl += [cols[:-2]] 58 | return cl 59 | 60 | def froms(ts): 61 | f = [] 62 | output = outfiles["joinless"] 63 | if len(ts) == 1: 64 | f = [ts[0]] 65 | else: 66 | for j in joins: 67 | output = outfiles[j] 68 | if random.random() < 0.3333: 69 | j = j.upper() 70 | f += [ts[0] + " " + j + " join " + ts[1]] 71 | return f, output 72 | 73 | def compose(ts, cs, pred): 74 | if pred != "": 75 | pred = " where " + pred 76 | cols = col_list(cs) 77 | sel, output = froms(ts) 78 | for s in sel: 79 | for c in cols: 80 | output.write("select " + c + " from " + s + pred + "\n") 81 | 82 | def next(cs, ci): 83 | if ci >= len(cs): 84 | return -1 85 | else: 86 | while not cs[ci] in where_data.keys(): 87 | ci += 1 88 | if ci >= len(cs): 89 | return -1 90 | return ci 91 | 92 | def predicate(ts, cs, ci, pred): 93 | ci = next(cs, ci) 94 | if ci == -1: 95 | compose(ts, cs, pred) 96 | else: 97 | for op in bool_op: 98 | if random.random() < 0.3333: 99 | op = op.upper() 100 | p = pred + " " + op + " " 101 | operation(ts, cs, ci, p) 102 | 103 | def operation(ts, cs, ci, pred): 104 | c = cs[ci] 105 | ops = [] 106 | ops += all_comp 107 | if c in integral: 108 | ops += integral_comp 109 | for nop in negate_op: 110 | for op in ops: 111 | for data in where_data[c]: 112 | if random.random() < 0.3333: 113 | nop = nop.upper() 114 | p = pred 115 | p += nop + c + " " + op + " " 116 | if type(data) is str: 117 | p += "\\\"" + data + "\\\"" 118 | else: 119 | p += str(data) 120 | predicate(ts, cs, ci + 1, p) 121 | 122 | def select(ts): 123 | cols = [] 124 | for t in ts: 125 | cols += columns[t] 126 | for i in range(len(cols)): 127 | comb = list(itertools.combinations(cols, i + 1)) 128 | for cs in comb: 129 | ci = next(cs, 0) 130 | if ci == -1: 131 | compose(ts, cs, "") 132 | else: 133 | pred = operation(ts, cs, ci, "") 134 | 135 | def root_query(left): 136 | select([left]) 137 | for right in joinable[left]: 138 | select([left, right]) 139 | 140 | def main(): 141 | print("Test Generator") 142 | for table in tables: 143 | print("\tGenerating queries for \"" + table + "\" schema") 144 | root_query(table) 145 | 146 | if __name__ == "__main__": 147 | main() 148 | for file in outfiles.keys(): 149 | outfiles[file].close() 150 | joins = ["natural"] 151 | outfiles = { 152 | "joinless": open("queries/joinless-queries.txt", "w"), 153 | "natural": open("queries/natural-queries.txt", "w") 154 | } 155 | columns = { 156 | "books": ["title", "genre", "year", "pages"], 157 | "stories": ["title", "genre", "year"], 158 | "authored": ["title", "name"], 159 | "collected": ["title", "collection", "pages"] 160 | } 161 | main() 162 | for file in outfiles.keys(): 163 | outfiles[file].close() 164 | -------------------------------------------------------------------------------- /tests/scripts/runner.py: -------------------------------------------------------------------------------- 1 | import os 2 | 3 | def main(): 4 | print("Test Runner") 5 | os.system("python3 scripts/select.py") 6 | print("\tTest queries selected") 7 | num = 1 8 | token = "" 9 | db = "library.db" 10 | with open("queries/test-queries.txt", "r") as queries: 11 | for query in queries: 12 | query = query.strip() 13 | if query[0] != "s": 14 | token = query 15 | if query == "CROSS": 16 | db = "library-cross.db" 17 | continue 18 | q = open("queries/query", "w") 19 | q.write(query + "\n") 20 | q.close() 21 | os.system("python3 scripts/compose.py") 22 | os.system("g++ -std=c++2a " + "-D" + token + " -O3 -I../single-header -o test test.cpp") 23 | os.system("./test | sort > cpp-results.txt") 24 | os.system("sqlite3 data/" + db + " \"" + query + ";\" | sort > sql-results.txt") 25 | stream = os.popen("diff cpp-results.txt sql-results.txt") 26 | res = "Passed" 27 | for line in stream: 28 | res = "Failed" 29 | break 30 | print("\tTest " + str(num) + ":\t" + res + "\n\t\t" + query) 31 | if res == "Failed": 32 | exit() 33 | num += 1 34 | os.remove("cpp-results.txt") 35 | os.remove("sql-results.txt") 36 | os.remove("queries/test-queries.txt") 37 | os.remove("queries/query") 38 | 39 | if __name__ == "__main__": 40 | main() 41 | -------------------------------------------------------------------------------- /tests/scripts/select.py: -------------------------------------------------------------------------------- 1 | # Randomly selects ~500 queries to test from the 1.4mil query set 2 | 3 | import random 4 | 5 | def main(): 6 | outfile = open("queries/test-queries.txt", "w") 7 | #h = 100 / 23000 8 | #h = 0 9 | h = 1.0 10 | outfile.write("JOINLESS\n") 11 | with open("queries/joinless-queries.txt", "r") as infile: 12 | for line in infile: 13 | if random.random() < h: 14 | outfile.write(line) 15 | #h = 500 / 700000 16 | outfile.write("NATURAL\n") 17 | with open("queries/natural-queries.txt", "r") as infile: 18 | for line in infile: 19 | if random.random() < h: 20 | outfile.write(line) 21 | outfile.write("CROSS\n") 22 | with open("queries/cross-queries.txt", "r") as infile: 23 | for line in infile: 24 | if random.random() < h: 25 | outfile.write(line) 26 | outfile.close() 27 | 28 | if __name__ == "__main__": 29 | main() 30 | --------------------------------------------------------------------------------