Full Code of mkitzan/constexpr-sql for AI

master ba98a31224ce cached
59 files
234.1 KB
70.0k tokens
370 symbols
1 requests
Download .txt
Showing preview only (250K chars total). Download the full file or copy to clipboard to get everything.
Repository: mkitzan/constexpr-sql
Branch: master
Commit: ba98a31224ce
Files: 59
Total size: 234.1 KB

Directory structure:
gitextract_sm4g9zum/

├── .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
├── single-header/
│   └── sql.hpp
└── tests/
    ├── data/
    │   ├── authored.tsv
    │   ├── books.tsv
    │   ├── collected.tsv
    │   └── stories.tsv
    ├── data.hpp
    ├── 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

================================================
FILE CONTENTS
================================================

================================================
FILE: .gitattributes
================================================
# Auto detect text files and perform LF normalization
* text=auto


================================================
FILE: .gitignore
================================================
tests/*.txt
tests/test.cpp
tests/test
tests/queries/*
.vscode/*
example
.DS_STORE


================================================
FILE: LICENSE
================================================
MIT License

Copyright (c) 2020 Michael Kitzan

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.


================================================
FILE: README.md
================================================
# Constexpr SQL

A light weight single header alternative to DBMS

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

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.

## Library Features and Compiler Support

Supported features:

- SQL query syntax for data processing
- `SELECT` data querying
- `AS` column renaming
- `CROSS JOIN` (note: all column names of each relation must be unique)
- `NATURAL JOIN` (note: natural join will attempt to join on the first column of each relation)
- `WHERE` clause predicates on numeric and `std::string` types
- Wildcard selection with `*`
- Nested queries
- Uppercase and lowercase SQL keywords
- Modern `!=` and legacy `<>` not-equal operator
- Standard SQL operator precedence in `WHERE` clause
- Schemas support all default constructable types
- Indexes for schemas (used for sorting the data)
- Range loop and structured binding declaration support
- [Loading data](https://github.com/mkitzan/constexpr-sql/blob/master/include/sql/schema.hpp#L180) from files (no header row)
- [Storing data](https://github.com/mkitzan/constexpr-sql/blob/master/include/sql/schema.hpp#L210) from `sql::schema` and `sql::query` objects to files
- Element querying from `sql::row` objects with [`sql::get<"column-name">`](https://github.com/mkitzan/constexpr-sql/blob/master/include/sql/row.hpp#L81)

Unsupported features (future work):

- `INNER JOIN`, `OUTER JOIN`, `LEFT JOIN`, and `RIGHT JOIN`
- `GROUP BY`, `HAVING`, and `ORDER BY` (using indexes can simulate some of these features)
- `IN` operation within `WHERE` clause
- Template argument error detection

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`.

## Example

The following example shows usage of all class templates a user is expected to define to use the library.

```c++
#include <iostream>
#include <string>

#include "sql.hpp"

using books =
	sql::schema<
		"books", sql::index<"title">,
		sql::column<"title", std::string>,
		sql::column<"genre", std::string>,
		sql::column<"year", unsigned>,
		sql::column<"pages", unsigned>
	>;

using authored =
	sql::schema<
		"authored", sql::index<>,
		sql::column<"title", std::string>,
		sql::column<"name", std::string>
	>;

using query =
	sql::query<
		"SELECT title AS book, name AS author, year, pages "
		"FROM books NATURAL JOIN (SELECT * FROM authored WHERE name = \"Harlan Ellison\") "
		"WHERE year = 1967 OR year >= 1972 AND genre = \"science fiction\"",
		books, authored
	>;

int main()
{
	authored a{ sql::load<authored>("tests/data/authored.tsv", '\t') };
	books b{ sql::load<books>("tests/data/books.tsv", '\t') };

	for (query q{ b, a }; auto const& [book, author, year, pages] : q)
	{
		std::cout << book << '\t' << author << '\t' << year << '\t' << pages << '\n';
	}

	return 0;
}
```

[`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`.

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:

```shell
g++ -std=c++2a -pedantic -Wall -Wextra -Werror -O3 -Isingle-header/ -o example example.cpp && ./example
```

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.

## Correctness and Performance Testing

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.

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.

## Important Class Templates and Implementation Details

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.

### Class Template: `sql::schema`

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<i>` function](https://github.com/mkitzan/constexpr-sql/blob/master/include/sql/row.hpp#L97).

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.

### Class Template: `sql::query`

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.

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.

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.

### Class Template: `sql::row`

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.

The example does not demonstrate the [`sql::get<cexpr::string>`](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.

### Relational Algebra Expression Nodes

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.

### Constexpr Parsing

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.

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.

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.

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.


================================================
FILE: example.cpp
================================================
#include <iostream>
#include <string>

#include "sql.hpp"

using books =
	sql::schema<
		"books", sql::index<"title">,
		sql::column<"title", std::string>,
		sql::column<"genre", std::string>,
		sql::column<"year", unsigned>,
		sql::column<"pages", unsigned>
	>;

using authored =
	sql::schema<
		"authored", sql::index<>,
		sql::column<"title", std::string>,
		sql::column<"name", std::string>
	>;

using query =
	sql::query<
		"SELECT title AS book, name AS author, year, pages "
		"FROM books NATURAL JOIN (SELECT * FROM authored WHERE name = \"Harlan Ellison\") "
		"WHERE year = 1967 OR year >= 1972 AND genre = \"science fiction\"",
		books, authored
	>;

int main()
{
	authored a{ sql::load<authored>("tests/data/authored.tsv", '\t') };
	books b{ sql::load<books>("tests/data/books.tsv", '\t') };

	for (query q{ b, a }; auto const& [book, author, year, pages] : q)
	{
		std::cout << book << '\t' << author << '\t' << year << '\t' << pages << '\n';
	}

	return 0;
}


================================================
FILE: generator.py
================================================
import os

def include(header, incs, root, included):
	file = open("include/" + root, "r")

	for line in file:
		if line == "#pragma once\n" or line == "\n":
			pass
		elif line[:10] == "#include \"":
			if not line in included:
				included += [line]
				include(header, incs, line[10:-2], included)
		elif line[:10] == "#include <":
			incs += [line]
		else:
			header.write(line)
			break
	
	for line in file:
		header.write(line)
	header.write("\n")

	return included, incs

def main():
	header = open("temp", "w")
	included, incs = include(header, [], "sql/schema.hpp", [])
	included, incs = include(header, incs, "sql/query.hpp", included)
	header.close()
	header = open("single-header/sql.hpp", "w")
	header.write("#pragma once\n\n")

	for line in sorted(set(incs)):
		header.write(line)
	header.write("\n")

	for line in open("temp"):
		header.write(line)

	os.remove("temp")

if __name__ == "__main__":
	main()


================================================
FILE: include/cexpr/string.hpp
================================================
#pragma once

#include <cstddef>
#include <string>
#include <string_view>

namespace cexpr
{

	template <typename Char, std::size_t N>
	class string
	{
	public:
		using char_type = Char;

		constexpr string() noexcept : size_{ 0 }, string_{ 0 }
		{}

		constexpr string(const Char(&s)[N]) noexcept : string{}
		{
			for(; s[size_]; ++size_)
			{
				string_[size_] = s[size_];
			}
		}

		constexpr string(cexpr::string<Char, N> const& s) noexcept : string{}
		{
			for (; s[size_]; ++size_)
			{
				string_[size_] = s[size_];
			}
		}

		constexpr string(std::basic_string_view<Char> const& s) noexcept : string{}
		{
			if (s.length() < N)
			{
				for (; size_ < s.length(); ++size_)
				{
					string_[size_] = s[size_];
				}
			}
		}

		constexpr void fill(const Char* begin, const Char* end) noexcept
		{
			fill_from(begin, end, begin());
		}

		constexpr void fill_from(const Char* begin, const Char* end, Char* start) noexcept
		{
			if (end - begin < N)
			{
				for (auto curr{ start }; begin != end; ++begin, ++curr)
				{
					*curr = *begin;
				}
			}
		}

		inline constexpr std::size_t capacity() const noexcept
		{ 
			return N - 1;
		}

		inline constexpr std::size_t size() const noexcept
		{
			return size_;
		}

		inline constexpr Char* begin() noexcept
		{
			return string_;
		}
		inline constexpr const Char* cbegin() const noexcept
		{
			return string_;
		}

		inline constexpr Char* end() noexcept
		{
			return &string_[size_];
		}
		inline constexpr const Char* cend() const noexcept
		{
			return &string_[size_];
		}

		inline constexpr Char& operator[](std::size_t i)
		{
			return string_[i];
		}
		inline constexpr Char const& operator[](std::size_t i) const
		{
			return string_[i];
		}

		template <typename OtherChar, std::size_t OtherN>
		constexpr bool operator==(string<OtherChar, OtherN> const& other) const noexcept
		{
			if constexpr (N != OtherN)
			{
				return false;
			}

			std::size_t i{};
			for (; i < N && string_[i] == other[i]; ++i);

			return i == N;
		}

		template <typename OtherChar, std::size_t OtherN>
		constexpr bool operator==(const OtherChar(&other)[OtherN]) const noexcept
		{
			if constexpr (N != OtherN)
			{
				return false;
			}

			std::size_t i{};
			for (; i < N && string_[i] == other[i]; ++i);

			return i == N;
		}

		template <typename OtherChar>
		inline bool operator==(std::basic_string<OtherChar> const& other) const noexcept
		{
			return other == string_;
		}

		template <typename OtherChar>
		inline bool operator!=(std::basic_string<OtherChar> const& other) const noexcept
		{
			return !(other == string_);
		}

	private:
		std::size_t size_;
		Char string_[N];
	};

	template <typename Char, std::size_t N>
	string(const Char[N]) -> string<Char, N>;

	template <typename Char, std::size_t N>
	inline bool operator==(std::basic_string<Char> const& str, string<Char, N> const& cstr) noexcept
	{
		return cstr == str;
	}

	template <typename Char, std::size_t N>
	inline bool operator!=(std::basic_string<Char> const& str, string<Char, N> const& cstr) noexcept
	{
		return cstr != str;
	}

} // namespace cexpr


================================================
FILE: include/ra/cross.hpp
================================================
#pragma once

#include "ra/join.hpp"
#include "ra/relation.hpp"

namespace ra
{

	template <typename LeftInput, typename RightInput>
	class cross : public ra::join<LeftInput, RightInput>
	{
		using join_type = ra::join<LeftInput, RightInput>;
	public:
		using output_type = join_type::output_type;

		static auto&& next()
		{
			try
			{
				copy(join_type::output_row, RightInput::next());
			}
			catch(ra::data_end const& e)
			{
				copy(join_type::output_row, LeftInput::next());
				RightInput::reset();
				copy(join_type::output_row, RightInput::next());
			}

			return std::move(join_type::output_row);
		}
	};

} // namespace ra


================================================
FILE: include/ra/join.hpp
================================================
#pragma once

#include <type_traits>

#include "ra/operation.hpp"

#include "sql/row.hpp"

namespace ra
{

	namespace
	{

		template <typename Left, typename Right>
		constexpr auto recr_merge()
		{
			if constexpr (std::is_same_v<Left, sql::void_row>)
			{
				return Right{};
			}
			else
			{
				using next = decltype(recr_merge<typename Left::next, Right>());

				return sql::row<typename Left::column, next>{};
			}
		}

		template <typename Left, typename Right>
		inline constexpr auto merge()
		{
			if constexpr (Left::column::name == Right::column::name)
			{
				return recr_merge<Left, typename Right::next>();
			}
			else
			{
				return recr_merge<Left, Right>();
			}
		}

		template <typename Dest, typename Row>
		constexpr void recr_copy(Dest& dest, Row const& src)
		{
			if constexpr (std::is_same_v<Row, sql::void_row>)
			{
				return;
			}
			else
			{
				dest.head() = src.head();
				recr_copy(dest.tail(), src.tail());
			}
		}

		template <typename Dest, typename Row>
		inline constexpr void copy(Dest& dest, Row const& src)
		{
			if constexpr (Dest::column::name == Row::column::name)
			{
				recr_copy(dest, src);
			}
			else
			{
				copy(dest.tail(), src);
			}
		}

	} // namespace

	template <typename LeftInput, typename RightInput>
	class join : public ra::binary<LeftInput, RightInput>
	{
		using binary_type = ra::binary<LeftInput, RightInput>;
		using left_type = typename binary_type::left_type;
		using right_type = typename binary_type::right_type;
	public:
		using output_type = decltype(merge<left_type, right_type>());

		template <typename... Inputs>
		static inline void seed(Inputs const&... rs)
		{
			binary_type::seed(rs...);
			copy(output_row, LeftInput::next());
		}

		static inline void reset()
		{
			binary_type::reset();
			copy(output_row, LeftInput::next());
		}

		static output_type output_row;
	};

	template <typename LeftInput, typename RightInput>
	typename join<LeftInput, RightInput>::output_type join<LeftInput, RightInput>::output_row{};

} // namespace ra


================================================
FILE: include/ra/natural.hpp
================================================
#pragma once

#include <type_traits>
#include <vector>
#include <unordered_map>

#include "ra/join.hpp"
#include "ra/relation.hpp"

namespace ra
{

	template <typename LeftInput, typename RightInput>
	class natural : public ra::join<LeftInput, RightInput>
	{
		using join_type = ra::join<LeftInput, RightInput>;
		using key_type = std::remove_cvref_t<decltype(LeftInput::next().head())>;
		using value_type = std::vector<std::remove_cvref_t<decltype(RightInput::next().tail())>>;
		using map_type = std::unordered_map<key_type, value_type>;
	public:
		using output_type = join_type::output_type;

		template <typename... Inputs>
		static void seed(Inputs const&... rs)
		{
			join_type::seed(rs...);
			
			if (row_cache.empty())
			{
				try
				{
					for (;;)
					{
						auto const& row{ RightInput::next() };
						row_cache[row.head()].push_back(row.tail());
					}
				}
				catch(ra::data_end const& e)
				{
					RightInput::reset();
				}
			}

			auto const& active{ row_cache[join_type::output_row.head()] };
			curr = active.cbegin();
			end = active.cend();
		}

		static auto&& next()
		{
			while (curr == end)
			{
				copy(join_type::output_row, LeftInput::next());
				auto const& active{ row_cache[join_type::output_row.head()] };
				curr = active.cbegin();
				end = active.cend();
			}

			copy(join_type::output_row, *curr++);
			
			return std::move(join_type::output_row);
		}

	private:
		static map_type row_cache;
		static value_type::const_iterator curr;
		static value_type::const_iterator end;
	};

	template <typename LeftInput, typename RightInput>
	typename natural<LeftInput, RightInput>::map_type natural<LeftInput, RightInput>::row_cache{};

	template <typename LeftInput, typename RightInput>
	typename natural<LeftInput, RightInput>::value_type::const_iterator natural<LeftInput, RightInput>::curr;

	template <typename LeftInput, typename RightInput>
	typename natural<LeftInput, RightInput>::value_type::const_iterator natural<LeftInput, RightInput>::end;

} // namespace ra


================================================
FILE: include/ra/operation.hpp
================================================
#pragma once

#include <type_traits>

namespace ra
{

	template <typename Input>
	class unary
	{
	public:
		using input_type = std::remove_cvref_t<decltype(Input::next())>;

		template <typename... Inputs>
		static inline void seed(Inputs const&... rs)
		{
			Input::seed(rs...);
		}

		static inline void reset()
		{
			Input::reset();
		}
	};

	template <typename LeftInput, typename RightInput>
	class binary
	{
	public:
		using left_type = std::remove_cvref_t<decltype(LeftInput::next())>;
		using right_type = std::remove_cvref_t<decltype(RightInput::next())>;

		template <typename... Inputs>
		static inline void seed(Inputs const&... rs)
		{
			LeftInput::seed(rs...);
			RightInput::seed(rs...);
		}

		static inline void reset()
		{
			LeftInput::reset();
			RightInput::reset();
		}
	};

} // namespace ra


================================================
FILE: include/ra/projection.hpp
================================================
#pragma once

#include "ra/operation.hpp"

#include "sql/row.hpp"

namespace ra
{

	template <typename Output, typename Input>
	class projection : public ra::unary<Input>
	{
		using input_type =  typename ra::unary<Input>::input_type;
	public:
		using output_type = Output;

		static auto&& next()
		{
			fold<output_type>(output_row, Input::next());
			
			return std::move(output_row);
		}

	private:
		template <typename Dest>
		static inline constexpr void fold(Dest& dest, input_type const& src)
		{
			if constexpr (Dest::depth == 0)
			{
				return;
			}
			else
			{
				dest.head() = sql::get<Dest::column::name>(src);
				fold<typename Dest::next>(dest.tail(), src);	
			}
		}

		static output_type output_row;
	};

	template <typename Output, typename Input>
	typename projection<Output, Input>::output_type projection<Output, Input>::output_row{};

} // namespace ra


================================================
FILE: include/ra/relation.hpp
================================================
#pragma once

#include <exception>
#include <type_traits>

namespace ra
{

	struct data_end : std::exception
	{};

	// Id template parameter allows unique ra::relation types to be instantiated from
	//	a single sql::schema type (for queries referencing a schema multiple times).
	template <typename Schema, std::size_t Id>
	class relation
	{
	public:
		using output_type = Schema::row_type&;

		static auto& next()
		{
			if (curr != end)
			{
				return *curr++;
			}
			else
			{
				throw ra::data_end{};
			}
		}
		
		template <typename Input, typename... Inputs>
		static void seed(Input const& r, Inputs const&... rs) noexcept
		{
			if constexpr (std::is_same_v<Input, Schema>)
			{
				curr = r.begin();
				begin = r.begin();
				end = r.end();
			}
			else
			{
				seed(rs...);
			}
		}

		static inline void reset() noexcept
		{
			curr = begin;
		}

	private:
		static Schema::const_iterator curr;
		static Schema::const_iterator begin;
		static Schema::const_iterator end;
	};

	template <typename Schema, std::size_t Id>
	Schema::const_iterator relation<Schema, Id>::curr{};

	template <typename Schema, std::size_t Id>
	Schema::const_iterator relation<Schema, Id>::begin{};

	template <typename Schema, std::size_t Id>
	Schema::const_iterator relation<Schema, Id>::end{};

} // namespace ra


================================================
FILE: include/ra/rename.hpp
================================================
#pragma once

#include "ra/operation.hpp"

#include "sql/row.hpp"

namespace ra
{

	template <typename Output, typename Input>
	class rename : public ra::unary<Input>
	{
		using input_type = typename ra::unary<Input>::input_type;
	public:
		using output_type = Output;

		static auto&& next()
		{
			fold<output_type, input_type>(output_row, Input::next());
			
			return std::move(output_row);
		}

	private:
		template <typename Dest, typename Src>
		static inline constexpr void fold(Dest& dest, Src const& src)
		{
			if constexpr (Dest::depth == 0)
			{
				return;
			}
			else
			{
				dest.head() = src.head();
				fold<typename Dest::next, typename Src::next>(dest.tail(), src.tail());
			}
		}

		static output_type output_row;
	};

	template <typename Output, typename Input>
	typename rename<Output, Input>::output_type rename<Output, Input>::output_row{};
	
} // namespace ra


================================================
FILE: include/ra/selection.hpp
================================================
#pragma once

#include "ra/operation.hpp"

namespace ra
{

	template <typename Predicate, typename Input>
	class selection : public ra::unary<Input>
	{
		using input_type = typename ra::unary<Input>::input_type;
	public:
		using output_type = input_type;		

		static auto&& next()
		{
			output_row = Input::next();

			while(!Predicate::eval(output_row))
			{
				output_row = Input::next();
			}

			return std::move(output_row);
		}

	private:
		static output_type output_row;
	};

	template <typename Output, typename Input>
	typename selection<Output, Input>::output_type selection<Output, Input>::output_row{};

} // namespace ra


================================================
FILE: include/sql/column.hpp
================================================
#pragma once

#include "cexpr/string.hpp"

namespace sql
{

	template <cexpr::string Name, typename Type>
	struct column
	{
		static constexpr auto name{ Name };
		
		using type = Type;
	};

} // namespace sql


================================================
FILE: include/sql/index.hpp
================================================
#pragma once

#include <type_traits>

#include "cexpr/string.hpp"

#include "sql/row.hpp"

namespace sql
{

	template <cexpr::string... Columns>
	struct index
	{
		template <typename Row>
		struct comparator
		{
			bool operator()(Row const& left, Row const& right) const noexcept
			{
				return compare<Columns...>(left, right);
			}
		
		private:
			template <cexpr::string Col, cexpr::string... Cols>
			bool compare(Row const& left, Row const& right) const noexcept
			{
				auto const& l{ sql::get<Col>(left) };
				auto const& r{ sql::get<Col>(right) };

				if constexpr (sizeof...(Cols) != 0)
				{
					if (l == r)
					{
						return compare<Cols...>(left, right);
					}					
				}
				
				return l < r;
			}
		};
	};

} // namespace sql


================================================
FILE: include/sql/predicate.hpp
================================================
#pragma once

#include <cstddef>

#include "cexpr/string.hpp"

namespace sql
{

	namespace
	{

		// shim to allow all value types like double or float to be used as non-type template parameters.
		template <typename Type>
		struct value
		{
			constexpr value(Type v) : val{ v }
			{}

			Type val;
		};

	} // namespace

	template <cexpr::string Op, typename Row, typename Left, typename Right=void>
	struct operation
	{
		static constexpr bool eval(Row const& row) noexcept
		{
			if constexpr (Op == "=")
			{
				return Left::eval(row) == Right::eval(row);
			}
			else if constexpr (Op == ">")
			{
				return Left::eval(row) > Right::eval(row);
			}
			else if constexpr(Op == "<")
			{
				return Left::eval(row) < Right::eval(row);
			}
			else if constexpr(Op == ">=")
			{
				return Left::eval(row) >= Right::eval(row);
			}
			else if constexpr(Op == "<=")
			{
				return Left::eval(row) <= Right::eval(row);
			}
			else if constexpr(Op == "!=" || Op == "<>")
			{
				return Left::eval(row) != Right::eval(row);
			}
			else if constexpr(Op == "AND")
			{
				return Left::eval(row) && Right::eval(row);
			}
			else if constexpr(Op == "OR")
			{
				return Left::eval(row) || Right::eval(row);
			}
			else if constexpr(Op == "NOT")
			{
				return !Left::eval(row);
			}
		}
	};

	template <cexpr::string Column, typename Row>
	struct variable
	{
		static constexpr auto eval(Row const& row) noexcept
		{
			return sql::get<Column>(row);
		}
	};

	template <auto Const, typename Row>
	struct constant
	{
		static constexpr auto eval([[maybe_unused]] Row const& row) noexcept
		{
			return Const.val;
		}
	};

} // namespace sql


================================================
FILE: include/sql/query.hpp
================================================
#pragma once

#include <array>
#include <string>
#include <string_view>
#include <type_traits>

#include "cexpr/string.hpp"

#include "ra/cross.hpp"
#include "ra/join.hpp"
#include "ra/natural.hpp"
#include "ra/projection.hpp"
#include "ra/relation.hpp"
#include "ra/rename.hpp"
#include "ra/selection.hpp"

#include "sql/column.hpp"
#include "sql/tokens.hpp"
#include "sql/predicate.hpp"
#include "sql/row.hpp"

namespace sql
{

	// anonymous namespace to hold helper data structures and functions
	namespace
	{

		template <std::size_t Pos, typename Node>
		struct context
		{
			using node = Node;
			static constexpr std::size_t pos = Pos;
		};

		template <typename Type, std::size_t Name, std::size_t Next>
		struct colinfo
		{
			using type = Type;
			static constexpr std::size_t name = Name;
			static constexpr std::size_t next = Next;
		};

		template <cexpr::string Name, typename Row>
		constexpr bool exists() noexcept
		{
			if constexpr (std::is_same_v<Row, sql::void_row>)
			{
				return false;
			}
			else
			{
				if constexpr (Row::column::name == Name)
				{
					return true;
				}
				else
				{
					return exists<Name, typename Row::next>();
				}
			}
		}

		template <typename Type, typename Char, std::size_t N>
		constexpr value<Type> convert(cexpr::string<Char, N> const& str) noexcept
		{
			auto curr{ str.cbegin() }, end{ str.cend() };
			constexpr Char dot{ '.' }, zro{ '0' }, min{ '-' };
			Type acc{}, sign{ 1 }, scalar{ 10 };

			if (*curr == min)
			{
				sign = -1;
				++curr;
			}

			while (curr != end && *curr != dot)
			{
				acc = (acc * scalar) + (*curr - zro);
				++curr;
			}

			if (curr != end && *curr == dot)
			{
				scalar = 1;
				++curr;

				while(curr != end)
				{
					acc += (*curr - zro) * (scalar /= Type{ 10 });
					++curr;
				}
			}

			return value<Type>{ acc * sign };
		}

		inline constexpr bool isquote(std::string_view const& tv) noexcept
		{
			return tv == "\"" || tv == "'";
		}

		inline constexpr bool isor(std::string_view const& tv) noexcept
		{
			return tv == "OR" || tv == "or";
		}

		inline constexpr bool isand(std::string_view const& tv) noexcept
		{
			return tv == "AND" || tv == "and";
		}

		inline constexpr bool isnot(std::string_view const& tv) noexcept
		{
			return tv == "NOT" || tv == "not";
		}

		inline constexpr bool isnatural(std::string_view const& tv) noexcept
		{
			return tv == "NATURAL" || tv == "natural";
		}

		inline constexpr bool isjoin(std::string_view const& tv) noexcept
		{
			return tv == "JOIN" || tv == "join";
		}

		inline constexpr bool iswhere(std::string_view const& tv) noexcept
		{
			return tv == "WHERE" || tv == "where";
		}

		inline constexpr bool isfrom(std::string_view const& tv) noexcept
		{
			return tv == "FROM" || tv == "from";
		}

		inline constexpr bool isas(std::string_view const& tv) noexcept
		{
			return tv == "AS" || tv == "as";
		}

		inline constexpr bool isselect(std::string_view const& tv) noexcept
		{
			return tv == "SELECT" || tv == "select";
		}

		inline constexpr bool iscomma(std::string_view const& tv) noexcept
		{
			return tv == ",";
		}

		constexpr bool isintegral(std::string_view const& tv) noexcept
		{
			bool result{ false };

			for (auto c : tv)
			{
				result |= (c == '.');
			}

			return !result;
		}

		constexpr bool isdigit(char c) noexcept
		{
			return (c >= '0' && c <= '9') || c == '-' || c == '.';
		}

		constexpr bool iscomp(char c) noexcept
		{
			return c == '=' || c == '!' || c == '<' || c == '>';
		}

		constexpr bool iscolumn(std::string_view const& tv) noexcept
		{
			return !iscomma(tv) && !isas(tv) && !isfrom(tv);
		}

		constexpr bool isseparator(std::string_view const& tv) noexcept
		{
			return iscomma(tv) || isfrom(tv);
		}

	} // namespace

	// structured binding compliant iterator for query objects
	template <typename Expr>
	class query_iterator
	{
	public:
		using row_type = std::remove_cvref_t<typename Expr::output_type>;

		// seeds row datamember for first dereference
		query_iterator(bool end) : end_{ end }, row_{}
		{
			operator++();
		}

		inline bool operator==(query_iterator const& it) const noexcept
		{
			return end_ == it.end_;
		}

		inline bool operator!=(query_iterator const& it) const noexcept
		{
			return !(*this == it);
		}

		inline row_type const& operator*() const noexcept
		{
			return row_;
		}

		query_iterator& operator++()
		{
			if (!end_)
			{
				try
				{
					row_ = Expr::next();
				}
				catch (ra::data_end const& e)
				{
					end_ = true;
				}
			}

			return *this;
		}

	private:
		bool end_{};
		row_type row_{};
	};

	template <cexpr::string Str, typename... Schemas>
	class query
	{
	private:
		// where predicate terminal parsing 
		template <std::size_t Pos, typename Row>
		static constexpr auto parse_terms()
		{
			if constexpr (tokens_[Pos] == "(")
			{
				constexpr auto next{ parse_or<Pos + 1, Row>() };

				using node = typename decltype(next)::node;

				static_assert(tokens_[next.pos] == ")", "No closing paranthesis found.");

				return context<next.pos + 1, node>{};
			}
			else if constexpr (isquote(tokens_[Pos]))
			{
				constexpr cexpr::string<char, tokens_[Pos + 1].length() + 1> name{ tokens_[Pos + 1] };

				using str = decltype(name);
				using node = sql::constant<value<str>{ name }, Row>;

				static_assert(isquote(tokens_[Pos + 2]), "No closing quote found.");

				return context<Pos + 3, node>{};
			}
			else if constexpr (isdigit(tokens_[Pos][0]))
			{
				constexpr cexpr::string<char, tokens_[Pos].length() + 1> name{ tokens_[Pos] };
				
				using val = decltype(isintegral(tokens_[Pos]) ? std::int64_t{} : double{});
				using node = sql::constant<sql::convert<val>(name), Row>;

				return context<Pos + 1, node>{};
			}
			else
			{
				constexpr cexpr::string<char, tokens_[Pos].length() + 1> name{ tokens_[Pos] };

				using node = sql::variable<name, Row>;

				return context<Pos + 1, node>{};
			}
		}

		// parses a single compare operation
		template <typename Left, typename Row>
		static constexpr auto recurse_comparison()
		{
			if constexpr (!iscomp(tokens_[Left::pos][0]))
			{
				return Left{};
			}
			else
			{
				constexpr auto next{ parse_terms<Left::pos + 1, Row>() };
				constexpr cexpr::string<char, tokens_[Left::pos].length() + 1> name{ tokens_[Left::pos] };

				using ranode = typename decltype(next)::node;
				using node = sql::operation<name, Row, typename Left::node, ranode>;

				return context<next.pos, node>{};
			}			
		}

		// descend further and attempt to parse a compare operation
		template <std::size_t Pos, typename Row>
		static constexpr auto parse_comparison()
		{
			using left = decltype(parse_terms<Pos, Row>());
			
			return recurse_comparison<left, Row>();
		}

		// attempt to parse a negation operation then descend further
		template <std::size_t Pos, typename Row>
		static constexpr auto parse_negation()
		{
			if constexpr (isnot(tokens_[Pos]))
			{
				constexpr auto next{ parse_comparison<Pos + 1, Row>() };

				using ranode = typename decltype(next)::node;
				using node = sql::operation<"NOT", Row, ranode>;

				return context<next.pos, node>{};
			}
			else
			{
				return parse_comparison<Pos, Row>();
			}
		}

		// recursively parse chained AND operations
		template <typename Left, typename Row>
		static constexpr auto recurse_and()
		{
			if constexpr (!isand(tokens_[Left::pos]))
			{
				return Left{};
			}
			else
			{
				constexpr auto next{ parse_negation<Left::pos + 1, Row>() };

				using ranode = typename decltype(next)::node;
				using node = sql::operation<"AND", Row, typename Left::node, ranode>;

				return recurse_and<context<next.pos, node>, Row>();
			}
		}

		// descend further then attempt to parse AND operations
		template <std::size_t Pos, typename Row>
		static constexpr auto parse_and()
		{
			using left = decltype(parse_negation<Pos, Row>());
			
			return recurse_and<left, Row>();
		}
		
		// recursively parse chained OR operations
		template <typename Left, typename Row>
		static constexpr auto recurse_or()
		{
			if constexpr (!isor(tokens_[Left::pos]))
			{
				return Left{};
			}
			else
			{
				constexpr auto next{ parse_and<Left::pos + 1, Row>() };
				
				using ranode = typename decltype(next)::node;
				using node = sql::operation<"OR", Row, typename Left::node, ranode>;

				return recurse_or<context<next.pos, node>, Row>();
			}
		}

		// descend further then attempt to parse OR operations
		template <std::size_t Pos, typename Row>
		static constexpr auto parse_or()
		{
			using left = decltype(parse_and<Pos, Row>());
			
			return recurse_or<left, Row>();
		}

		// find correct schema for terminal relation
		template <cexpr::string Name, std::size_t Id, typename Schema, typename... Others>
		static constexpr auto recurse_schemas()
		{
			if constexpr (Name == Schema::name)
			{
				return ra::relation<Schema, Id>{};
			}
			else
			{
				static_assert(sizeof...(Others) != 0, "Schema name used in JOIN was not provided.");

				return recurse_schemas<Name, Id, Others...>();
			}
		}

		// wrapper function to determine terminal relation
		template <std::size_t Pos>
		static constexpr auto parse_schema()
		{
			if constexpr (tokens_[Pos] == "(")
			{
				constexpr auto next{ parse_root<Pos + 1>() };
				
				using node = typename decltype(next)::node;

				static_assert(tokens_[next.pos] == ")", "No closing paranthesis found.");

				return context<next.pos + 1, node>{};
			}
			else
			{
				constexpr cexpr::string<char, tokens_[Pos].length() + 1> name{ tokens_[Pos] };

				using node = decltype(recurse_schemas<name, Pos, Schemas...>());

				return context<Pos + 1, node>{};
			}
		}

		// stub which will choose the specific join RA node
		template <std::size_t Pos, typename Left, typename Right>
		static constexpr auto choose_join()
		{
			if constexpr (isnatural(tokens_[Pos]))
			{
				return ra::natural<Left, Right>{};
			}
			else
			{
				return ra::cross<Left, Right>{};	
			}
		}

		// parses join colinfo if a join is present else returns the single relation terminal
		template <std::size_t Pos>
		static constexpr auto parse_join()
		{
			constexpr auto lnext{ parse_schema<Pos>() };

			using lnode = typename decltype(lnext)::node;

			if constexpr (lnext.pos + 2 < tokens_.count() && isjoin(tokens_[lnext.pos + 1]))
			{
				constexpr auto rnext{ parse_schema<lnext.pos + 2>() };

				using rnode = typename decltype(rnext)::node;
				using join = decltype(choose_join<lnext.pos, lnode, rnode>());

				return context<rnext.pos, join>{};
			}
			else
			{
				return context<lnext.pos, lnode>{};
			}
		}

		// starting point to parse everything after the from keyword
		template <std::size_t Pos>
		static constexpr auto parse_from()
		{
			static_assert(isfrom(tokens_[Pos]), "Expected 'FROM' token not found.");

			constexpr auto next{ parse_join<Pos + 1>() };

			using node = typename decltype(next)::node;

			if constexpr (next.pos < tokens_.count() && iswhere(tokens_[next.pos]))
			{
				using output = std::remove_cvref_t<typename node::output_type>;

				constexpr auto predicate{ parse_or<next.pos + 1, output>() };

				using pnext = typename decltype(predicate)::node;
				using snode = ra::selection<pnext, node>;

				return context<predicate.pos, snode>{};
			}
			else
			{
				return context<next.pos, node>{};	
			}
		}

		// recursively searches all schemas for the a matching column
		template <cexpr::string Name, typename Schema, typename... Others>
		static constexpr auto recurse_types()
		{
			if constexpr (sql::exists<Name, typename Schema::row_type>())
			{
				return decltype(sql::get<Name>(typename Schema::row_type{})){};
			}
			else
			{
				static_assert(sizeof...(Others) != 0, "Column name was not present in any schema.");

				return recurse_types<Name, Others...>();
			}
		}

		// wrapper to determine the type for the the column
		template <std::size_t Pos>
		static constexpr auto column_type()
		{
			constexpr cexpr::string<char, tokens_[Pos].length() + 1> name{ tokens_[Pos] };

			return recurse_types<name, Schemas...>();
		}

		// asserts token is column separator, and if comma returns one past the comma else start position
		template <std::size_t Pos>
		static constexpr std::size_t next_column()
		{
			static_assert(isseparator(tokens_[Pos]), "Expected ',' or 'FROM' token following column.");

			if constexpr (iscomma(tokens_[Pos]))
			{
				return Pos + 1;
			}
			else
			{
				return Pos;
			}
		}

		template <std::size_t Pos, bool Rename>
		static constexpr auto parse_colinfo()
		{
			static_assert(iscolumn(tokens_[Pos]), "Invalid token starting column delcaration.");

			constexpr bool rename{ isas(tokens_[Pos + 1]) && iscolumn(tokens_[Pos + 2]) };

			using col = decltype(column_type<Pos>());

			if constexpr (Rename && rename)
			{
				constexpr auto next{ next_column<Pos + 3>() };

				return colinfo<col, Pos + 2, next>{};
			}
			else if constexpr (rename)
			{
				constexpr auto next{ next_column<Pos + 3>() };

				return colinfo<col, Pos, next>{};
			}
			else
			{
				constexpr auto next{ next_column<Pos + 1>() };

				return colinfo<col, Pos, next>{};
			}
		}

		// recursively parse all columns projected/renamed in the query
		template <std::size_t Pos, bool Rename>
		static constexpr auto recurse_columns()
		{
			if constexpr (isfrom(tokens_[Pos]))
			{
				return context<Pos, sql::void_row>{};
			}
			else
			{
				constexpr auto info{ parse_colinfo<Pos, Rename>() };
				constexpr cexpr::string<char, tokens_[info.name].length() + 1> name{ tokens_[info.name] };
				constexpr auto child{ recurse_columns<info.next, Rename>() };

				using next = std::remove_const_t<typename decltype(child)::node>;
				using col = std::remove_const_t<decltype(sql::column<name, typename decltype(info)::type>{})>;
				using node = sql::row<col, next>;

				return context<child.pos, node>{};
			}
		}

		// wrapper to parse columns as a projection RA node
		template <std::size_t Pos>
		static constexpr auto parse_projection()
		{
			constexpr auto proj{ recurse_columns<Pos, false>() };
			constexpr auto next{ parse_from<proj.pos>() };

			using ranode = typename decltype(proj)::node;
			using node = ra::projection<ranode, typename decltype(next)::node>;

			return context<next.pos, node>{};
		}

		// wrapper to parse columns as a rename RA node
		template <std::size_t Pos>
		static constexpr auto parse_rename()
		{
			constexpr auto next = parse_projection<Pos>();

			using ranode = typename decltype(recurse_columns<Pos, true>())::node;
			using node = ra::rename<ranode, typename decltype(next)::node>;

			return context<next.pos, node>{};
		}

		// attempts to match column rename operation pattern on a column
		template <std::size_t Pos>
		static constexpr bool has_rename()
		{
			if constexpr (isfrom(tokens_[Pos]) || isfrom(tokens_[Pos + 2]))
			{
				return false;
			}
			else if constexpr (iscolumn(tokens_[Pos]) && isas(tokens_[Pos + 1]) && iscolumn(tokens_[Pos + 2]))
			{
				return true;
			}
			else
			{
				constexpr bool comma{ iscomma(tokens_[Pos + 1]) };

				static_assert(comma || isfrom(tokens_[Pos + 1]), "Expected ',' or 'FROM' token following column.");

				if constexpr (comma)
				{
					return has_rename<Pos + 2>();
				}
				else
				{
					return has_rename<Pos + 1>();
				}
			}
		}

		// decide RA node to root the expression tree
		template <std::size_t Pos>
		static constexpr auto parse_root()
		{
			static_assert(isselect(tokens_[Pos]), "Expected 'SELECT' token not found.");

			if constexpr (tokens_[Pos + 1] == "*")
			{
				return parse_from<Pos + 2>();
			}
			else if constexpr (has_rename<Pos + 1>())
			{
				return parse_rename<Pos + 1>();
			}
			else
			{
				return parse_projection<Pos + 1>();
			}
		}

		static constexpr sql::tokens<char, sql::preprocess(Str)> tokens_{ Str };

		using expression = typename decltype(parse_root<0>())::node;

		bool empty_;
	
	public:
		using iterator = query_iterator<expression>;
		using row_type = expression::output_type;

		query(Schemas const&... tables)
		{
			try 
			{
				expression::seed(tables...);
				empty_ = false;
			}
			catch(ra::data_end const& e)
			{
				empty_ = true;
			}
		}

		~query()
		{
			expression::reset();
		}

		inline iterator begin() const
		{
			return iterator{ empty_ };
		}

		inline iterator end() const
		{
			return iterator{ true };
		}
	};

} // namespace sql


================================================
FILE: include/sql/row.hpp
================================================
#pragma once

#include <type_traits>
#include <utility>
#include <vector>

#include "cexpr/string.hpp"

namespace sql
{

	struct void_row
	{
		static constexpr std::size_t depth{ 0 };
	};

	template <typename Col, typename Next>
	class row
	{
	public:
		using column = Col;
		using next = Next;

		static constexpr std::size_t depth{ 1 + next::depth };

		row() = default;

		template <typename... ColTs>
		row(column::type const& val, ColTs const&... vals) : value_{ val }, next_{ vals... }
		{}

		template <typename... ColTs>
		row(column::type&& val, ColTs&&... vals) : value_{ std::forward<column::type>(val) }, next_{ std::forward<ColTs>(vals)... }
		{}

		inline constexpr next const& tail() const noexcept
		{
			return next_;
		}

		inline constexpr next& tail() noexcept
		{
			return next_;
		}

		inline constexpr column::type const& head() const noexcept
		{
			return value_;
		}

		inline constexpr column::type& head() noexcept
		{
			return value_;
		}
	
	private:
		column::type value_;
		next next_;
	};

	template <typename Col, typename... Cols>
	struct variadic_row
	{
	private:
		static inline constexpr auto resolve() noexcept
		{
			if constexpr (sizeof...(Cols) != 0)
			{
				return typename variadic_row<Cols...>::row_type{};
			}
			else
			{
				return void_row{};
			}
		}

	public:
		using row_type = row<Col, decltype(resolve())>;
	};

	// user function to query row elements by column name
	template <cexpr::string Name, typename Row>
	constexpr auto const& get(Row const& r) noexcept
	{
		static_assert(!std::is_same_v<Row, sql::void_row>, "Name does not match a column name.");

		if constexpr (Row::column::name == Name)
		{
			return r.head();
		}
		else
		{
			return get<Name>(r.tail());
		}
	}

	// compiler function used by structured binding declaration
	template <std::size_t Pos, typename Row>
	constexpr auto const& get(Row const& r) noexcept
	{
		static_assert(Pos < Row::depth, "Position is larger than number of row columns.");

		if constexpr (Pos == 0)
		{
			return r.head();
		}
		else
		{
			return get<Pos - 1>(r.tail());
		}
	}

	// function to assign a value to a column's value in a row
	template <cexpr::string Name, typename Row, typename Type>
	constexpr void set(Row& r, Type const& value)
	{
		static_assert(!std::is_same_v<Row, sql::void_row>, "Name does not match a column name.");

		if constexpr (Row::column::name == Name)
		{
			r.head() = value;
		}
		else
		{
			set<Name>(r.tail(), value);
		}
	}

} // namespace sql

// STL injections to allow row to be used in structured binding declarations
namespace std
{

	template <typename Col, typename Next>
	class tuple_size<sql::row<Col, Next>> : public integral_constant<size_t, sql::row<Col, Next>::depth>
	{};

	template <size_t Index, typename Col, typename Next>
	struct tuple_element<Index, sql::row<Col, Next>>
	{
		using type = decltype(sql::get<Index>(sql::row<Col, Next>{}));
	};

} // namespace std


================================================
FILE: include/sql/schema.hpp
================================================
#pragma once

#include <fstream>
#include <set>
#include <type_traits>
#include <utility>
#include <vector>

#include "cexpr/string.hpp"

#include "sql/column.hpp"
#include "sql/index.hpp"
#include "sql/row.hpp"

namespace sql
{

	template <cexpr::string Name, typename Index, typename... Cols>
	class schema
	{
	public:
		static constexpr auto name{ Name };

		using row_type = sql::variadic_row<Cols...>::row_type;
		using container = typename
			std::conditional_t<
				std::is_same_v<Index, sql::index<>>,
				std::vector<row_type>,
				std::multiset<row_type, typename Index::template comparator<row_type>>
			>;
		using const_iterator = typename container::const_iterator;
		
		schema() = default;

		template <typename Type, typename... Types>
		schema(std::vector<Type> const& col, Types const&... cols) : schema{}
		{
			insert(col, cols...);
		}

		template <typename Type, typename... Types>
		schema(std::vector<Type>&& col, Types&&... cols) : schema{}
		{
			insert(std::forward<Type>(col), std::forward<Types>(cols)...);
		}

		template <typename... Types>
		inline void emplace(Types const&... vals)
		{
			if constexpr (std::is_same_v<Index, sql::index<>>)
			{
				table_.emplace_back(vals...);
			}
			else
			{
				table_.emplace(vals...);
			}
		}

		template <typename... Types>
		inline void emplace(Types&&... vals)
		{
			if constexpr (std::is_same_v<Index, sql::index<>>)
			{
				table_.emplace_back(vals...);
			}
			else
			{
				table_.emplace(vals...);
			}
		}

		template <typename Type, typename... Types>
		void insert(std::vector<Type> const& col, Types const&... cols)
		{
			for (std::size_t i{}; i < col.size(); ++i)
			{
				emplace(col[i], cols[i]...);
			}
		}

		template <typename Type, typename... Types>
		void insert(std::vector<Type>&& col, Types&&... cols)
		{
			for (std::size_t i{}; i < col.size(); ++i)
			{
				emplace(std::forward<Type>(col[i]), std::forward<Types>(cols[i])...);
			}
		}

		void insert(row_type const& row)
		{
			if constexpr (std::is_same_v<Index, sql::index<>>)
			{
				table_.push_back(row);
			}
			else
			{
				table_.insert(row);
			}
		}

		void insert(row_type&& row)
		{
			if constexpr (std::is_same_v<Index, sql::index<>>)
			{
				table_.push_back(std::forward<row_type>(row));
			}
			else
			{
				table_.insert(std::forward<row_type>(row));
			}
		}

		inline const_iterator begin() const noexcept
		{
			return table_.begin();
		}

		inline const_iterator end() const noexcept
		{
			return table_.end();
		}

	private:
		container table_;
	};

	namespace
	{

		template <typename Row>
		void fill(std::fstream& fstr, Row& row, [[maybe_unused]] char delim)
		{
			if constexpr (!std::is_same_v<Row, sql::void_row>)
			{
				if constexpr (std::is_same_v<typename Row::column::type, std::string>)
				{
					if constexpr (std::is_same_v<typename Row::next, sql::void_row>)
					{
						std::getline(fstr, row.head());
					}
					else
					{
						std::getline(fstr, row.head(), delim);
					}
				}
				else
				{
					fstr >> row.head();
				}

				fill<typename Row::next>(fstr, row.tail(), delim);
			}
		}

		template <typename Row>
		void fill(std::fstream& fstr, Row const& row, char delim)
		{
			if constexpr (!std::is_same_v<Row, sql::void_row>)
			{
				fstr << row.head();

				if constexpr (std::is_same_v<typename Row::next, sql::void_row>)
				{
					fstr << '\n';
				}
				else
				{
					fstr << delim;
				}
				
				fill<typename Row::next>(fstr, row.tail(), delim);
			}
		}

	} // namespace

	// helper function for users to load a data into a schema from a file
	template <typename Schema>
	Schema load(std::string const& file, char delim)
	{
		auto fstr{ std::fstream(file, fstr.in) };
		Schema table{};
		typename Schema::row_type row{};

		while (fstr)
		{
			fill<typename Schema::row_type>(fstr, row, delim);
			table.insert(std::move(row));

			// in case last stream extraction did not remove newline
			if (fstr.get() != '\n')
			{
				fstr.unget();
			}
		}

		return table;
	}

	// for compat with previous versions
	template <typename Schema, char Delim>
	inline Schema load(std::string const& file)
	{
		return load<Schema>(file, Delim);
	}

	// will work with schema and query objects
	template <typename Type>
	void store(Type const& data, std::string const& file, char delim)
	{
		auto fstr{ std::fstream(file, fstr.out) };

		for (auto const& row : data)
		{
			fill<typename Type::row_type>(fstr, row, delim);
		}
	}

	// for devs who want to use the previous format
	template <typename Type, char Delim>
	inline void store(Type const& data, std::string const& file)
	{
		store<Type>(data, file, Delim);
	}

} // namespace sql


================================================
FILE: include/sql/tokens.hpp
================================================
#pragma once

#include <array>
#include <cstddef>
#include <locale>
#include <string_view>

#include "cexpr/string.hpp"

namespace sql
{
	namespace
	{
		
		template <typename Char>
		constexpr bool whitespace(Char curr)
		{
			return curr == Char{ ' ' } || curr == Char{ '\t' } || curr == Char{ '\n' };
		}

		template <typename Char>
		constexpr bool syntax(Char curr)
		{
			return curr == Char{ ',' } || curr == Char{ '(' } || curr == Char{ ')' } ||
				curr == Char{ '\'' } || curr == Char{ '\"' } || curr == Char{ '=' };
		}

		template <typename Char>
		constexpr const Char* skip(const Char *curr, const Char *end)
		{
			for (; curr != end && whitespace(*curr); ++curr);
			return curr;
		}

		template <typename Char>
		constexpr const Char* next(const Char *curr, const Char *end)
		{
			Char c{ *curr };

			if (c == Char{ '>' } || c == Char{ '<' } || c == Char{ '!' })
			{
				++curr;

				if (*curr == Char{ '=' } || (c == Char{ '<' } && *curr == Char{ '>' }))
				{
					++curr;
				}
			}
			else if (syntax(c))
			{
				++curr;
			}
			else
			{
				for (; curr != end && !whitespace(*curr) && !syntax(*curr); ++curr);
			}
			
			return curr;
		}
	
	} // namespace

	template <typename Char, std::size_t Count>
	class tokens
	{
	public:
		using token_view = std::basic_string_view<Char>;

		constexpr tokens() = default;

		template<std::size_t N>
		constexpr tokens(cexpr::string<Char, N> const& cs) : tokens_{}
		{
			auto curr{ cs.cbegin() }, last{ cs.cbegin() };
			const auto end{ cs.cend() };
			std::size_t i{};

			while (curr < end)
			{
				curr = skip(curr, end);
				last = curr;
				last = next(last, end);

				if (*curr == Char{ '\"' } || *curr == Char{ '\'' })
				{
					tokens_[i++] = token_view{ curr, 1 };
					for (char c{ *curr++ }; last != end && *last != c; ++last);
				}

				auto len{ reinterpret_cast<std::size_t>(last) - reinterpret_cast<std::size_t>(curr) };
				tokens_[i++] = token_view{ curr, len };

				if (*last == Char{ '\"' } || *last == Char{ '\'' })
				{
					tokens_[i++] = token_view{ last, 1 };
					++last;
				}

				curr = last;
			}
		}

		constexpr std::size_t count() const noexcept
		{
			return Count;
		}

		constexpr token_view* begin() noexcept
		{
			return tokens_.begin();
		}
		constexpr const token_view* cbegin() const noexcept
		{
			return tokens_.cbegin();
		}

		constexpr token_view* end() noexcept
		{
			return tokens_.end();
		}
		constexpr const token_view* cend() const noexcept
		{
			return tokens_.cend();
		}

		constexpr token_view& operator[](std::size_t i)
		{
			return tokens_[i];
		}
		constexpr token_view const& operator[](std::size_t i) const
		{
			return tokens_[i];
		}

	private:
		std::array<token_view, Count> tokens_;
	};

	template<typename Char, std::size_t N>
	constexpr std::size_t preprocess(cexpr::string<Char, N> const& cs) noexcept
	{
		auto begin{ cs.cbegin() };
		const auto end{ cs.cend() };
		std::size_t count{ 1 };

		while (begin < end)
		{
			begin = skip(begin, end);
			begin = next(begin, end);
			++count;
		}

		return count;
	}

} // namespace sql


================================================
FILE: single-header/sql.hpp
================================================
#pragma once

#include <array>
#include <cstddef>
#include <exception>
#include <fstream>
#include <locale>
#include <set>
#include <string>
#include <string_view>
#include <type_traits>
#include <unordered_map>
#include <utility>
#include <vector>

namespace cexpr
{

	template <typename Char, std::size_t N>
	class string
	{
	public:
		using char_type = Char;

		constexpr string() noexcept : size_{ 0 }, string_{ 0 }
		{}

		constexpr string(const Char(&s)[N]) noexcept : string{}
		{
			for(; s[size_]; ++size_)
			{
				string_[size_] = s[size_];
			}
		}

		constexpr string(cexpr::string<Char, N> const& s) noexcept : string{}
		{
			for (; s[size_]; ++size_)
			{
				string_[size_] = s[size_];
			}
		}

		constexpr string(std::basic_string_view<Char> const& s) noexcept : string{}
		{
			if (s.length() < N)
			{
				for (; size_ < s.length(); ++size_)
				{
					string_[size_] = s[size_];
				}
			}
		}

		constexpr void fill(const Char* begin, const Char* end) noexcept
		{
			fill_from(begin, end, begin());
		}

		constexpr void fill_from(const Char* begin, const Char* end, Char* start) noexcept
		{
			if (end - begin < N)
			{
				for (auto curr{ start }; begin != end; ++begin, ++curr)
				{
					*curr = *begin;
				}
			}
		}

		inline constexpr std::size_t capacity() const noexcept
		{ 
			return N - 1;
		}

		inline constexpr std::size_t size() const noexcept
		{
			return size_;
		}

		inline constexpr Char* begin() noexcept
		{
			return string_;
		}
		inline constexpr const Char* cbegin() const noexcept
		{
			return string_;
		}

		inline constexpr Char* end() noexcept
		{
			return &string_[size_];
		}
		inline constexpr const Char* cend() const noexcept
		{
			return &string_[size_];
		}

		inline constexpr Char& operator[](std::size_t i)
		{
			return string_[i];
		}
		inline constexpr Char const& operator[](std::size_t i) const
		{
			return string_[i];
		}

		template <typename OtherChar, std::size_t OtherN>
		constexpr bool operator==(string<OtherChar, OtherN> const& other) const noexcept
		{
			if constexpr (N != OtherN)
			{
				return false;
			}

			std::size_t i{};
			for (; i < N && string_[i] == other[i]; ++i);

			return i == N;
		}

		template <typename OtherChar, std::size_t OtherN>
		constexpr bool operator==(const OtherChar(&other)[OtherN]) const noexcept
		{
			if constexpr (N != OtherN)
			{
				return false;
			}

			std::size_t i{};
			for (; i < N && string_[i] == other[i]; ++i);

			return i == N;
		}

		template <typename OtherChar>
		inline bool operator==(std::basic_string<OtherChar> const& other) const noexcept
		{
			return other == string_;
		}

		template <typename OtherChar>
		inline bool operator!=(std::basic_string<OtherChar> const& other) const noexcept
		{
			return !(other == string_);
		}

	private:
		std::size_t size_;
		Char string_[N];
	};

	template <typename Char, std::size_t N>
	string(const Char[N]) -> string<Char, N>;

	template <typename Char, std::size_t N>
	inline bool operator==(std::basic_string<Char> const& str, string<Char, N> const& cstr) noexcept
	{
		return cstr == str;
	}

	template <typename Char, std::size_t N>
	inline bool operator!=(std::basic_string<Char> const& str, string<Char, N> const& cstr) noexcept
	{
		return cstr != str;
	}

} // namespace cexpr

namespace sql
{

	template <cexpr::string Name, typename Type>
	struct column
	{
		static constexpr auto name{ Name };
		
		using type = Type;
	};

} // namespace sql

namespace sql
{

	struct void_row
	{
		static constexpr std::size_t depth{ 0 };
	};

	template <typename Col, typename Next>
	class row
	{
	public:
		using column = Col;
		using next = Next;

		static constexpr std::size_t depth{ 1 + next::depth };

		row() = default;

		template <typename... ColTs>
		row(column::type const& val, ColTs const&... vals) : value_{ val }, next_{ vals... }
		{}

		template <typename... ColTs>
		row(column::type&& val, ColTs&&... vals) : value_{ std::forward<column::type>(val) }, next_{ std::forward<ColTs>(vals)... }
		{}

		inline constexpr next const& tail() const noexcept
		{
			return next_;
		}

		inline constexpr next& tail() noexcept
		{
			return next_;
		}

		inline constexpr column::type const& head() const noexcept
		{
			return value_;
		}

		inline constexpr column::type& head() noexcept
		{
			return value_;
		}
	
	private:
		column::type value_;
		next next_;
	};

	template <typename Col, typename... Cols>
	struct variadic_row
	{
	private:
		static inline constexpr auto resolve() noexcept
		{
			if constexpr (sizeof...(Cols) != 0)
			{
				return typename variadic_row<Cols...>::row_type{};
			}
			else
			{
				return void_row{};
			}
		}

	public:
		using row_type = row<Col, decltype(resolve())>;
	};

	// user function to query row elements by column name
	template <cexpr::string Name, typename Row>
	constexpr auto const& get(Row const& r) noexcept
	{
		static_assert(!std::is_same_v<Row, sql::void_row>, "Name does not match a column name.");

		if constexpr (Row::column::name == Name)
		{
			return r.head();
		}
		else
		{
			return get<Name>(r.tail());
		}
	}

	// compiler function used by structured binding declaration
	template <std::size_t Pos, typename Row>
	constexpr auto const& get(Row const& r) noexcept
	{
		static_assert(Pos < Row::depth, "Position is larger than number of row columns.");

		if constexpr (Pos == 0)
		{
			return r.head();
		}
		else
		{
			return get<Pos - 1>(r.tail());
		}
	}

	// function to assign a value to a column's value in a row
	template <cexpr::string Name, typename Row, typename Type>
	constexpr void set(Row& r, Type const& value)
	{
		static_assert(!std::is_same_v<Row, sql::void_row>, "Name does not match a column name.");

		if constexpr (Row::column::name == Name)
		{
			r.head() = value;
		}
		else
		{
			set<Name>(r.tail(), value);
		}
	}

} // namespace sql

// STL injections to allow row to be used in structured binding declarations
namespace std
{

	template <typename Col, typename Next>
	class tuple_size<sql::row<Col, Next>> : public integral_constant<size_t, sql::row<Col, Next>::depth>
	{};

	template <size_t Index, typename Col, typename Next>
	struct tuple_element<Index, sql::row<Col, Next>>
	{
		using type = decltype(sql::get<Index>(sql::row<Col, Next>{}));
	};

} // namespace std

namespace sql
{

	template <cexpr::string... Columns>
	struct index
	{
		template <typename Row>
		struct comparator
		{
			bool operator()(Row const& left, Row const& right) const noexcept
			{
				return compare<Columns...>(left, right);
			}
		
		private:
			template <cexpr::string Col, cexpr::string... Cols>
			bool compare(Row const& left, Row const& right) const noexcept
			{
				auto const& l{ sql::get<Col>(left) };
				auto const& r{ sql::get<Col>(right) };

				if constexpr (sizeof...(Cols) != 0)
				{
					if (l == r)
					{
						return compare<Cols...>(left, right);
					}					
				}
				
				return l < r;
			}
		};
	};

} // namespace sql

namespace sql
{

	template <cexpr::string Name, typename Index, typename... Cols>
	class schema
	{
	public:
		static constexpr auto name{ Name };

		using row_type = sql::variadic_row<Cols...>::row_type;
		using container = typename
			std::conditional_t<
				std::is_same_v<Index, sql::index<>>,
				std::vector<row_type>,
				std::multiset<row_type, typename Index::template comparator<row_type>>
			>;
		using const_iterator = typename container::const_iterator;
		
		schema() = default;

		template <typename Type, typename... Types>
		schema(std::vector<Type> const& col, Types const&... cols) : schema{}
		{
			insert(col, cols...);
		}

		template <typename Type, typename... Types>
		schema(std::vector<Type>&& col, Types&&... cols) : schema{}
		{
			insert(std::forward<Type>(col), std::forward<Types>(cols)...);
		}

		template <typename... Types>
		inline void emplace(Types const&... vals)
		{
			if constexpr (std::is_same_v<Index, sql::index<>>)
			{
				table_.emplace_back(vals...);
			}
			else
			{
				table_.emplace(vals...);
			}
		}

		template <typename... Types>
		inline void emplace(Types&&... vals)
		{
			if constexpr (std::is_same_v<Index, sql::index<>>)
			{
				table_.emplace_back(vals...);
			}
			else
			{
				table_.emplace(vals...);
			}
		}

		template <typename Type, typename... Types>
		void insert(std::vector<Type> const& col, Types const&... cols)
		{
			for (std::size_t i{}; i < col.size(); ++i)
			{
				emplace(col[i], cols[i]...);
			}
		}

		template <typename Type, typename... Types>
		void insert(std::vector<Type>&& col, Types&&... cols)
		{
			for (std::size_t i{}; i < col.size(); ++i)
			{
				emplace(std::forward<Type>(col[i]), std::forward<Types>(cols[i])...);
			}
		}

		void insert(row_type const& row)
		{
			if constexpr (std::is_same_v<Index, sql::index<>>)
			{
				table_.push_back(row);
			}
			else
			{
				table_.insert(row);
			}
		}

		void insert(row_type&& row)
		{
			if constexpr (std::is_same_v<Index, sql::index<>>)
			{
				table_.push_back(std::forward<row_type>(row));
			}
			else
			{
				table_.insert(std::forward<row_type>(row));
			}
		}

		inline const_iterator begin() const noexcept
		{
			return table_.begin();
		}

		inline const_iterator end() const noexcept
		{
			return table_.end();
		}

	private:
		container table_;
	};

	namespace
	{

		template <typename Row>
		void fill(std::fstream& fstr, Row& row, [[maybe_unused]] char delim)
		{
			if constexpr (!std::is_same_v<Row, sql::void_row>)
			{
				if constexpr (std::is_same_v<typename Row::column::type, std::string>)
				{
					if constexpr (std::is_same_v<typename Row::next, sql::void_row>)
					{
						std::getline(fstr, row.head());
					}
					else
					{
						std::getline(fstr, row.head(), delim);
					}
				}
				else
				{
					fstr >> row.head();
				}

				fill<typename Row::next>(fstr, row.tail(), delim);
			}
		}

		template <typename Row>
		void fill(std::fstream& fstr, Row const& row, char delim)
		{
			if constexpr (!std::is_same_v<Row, sql::void_row>)
			{
				fstr << row.head();

				if constexpr (std::is_same_v<typename Row::next, sql::void_row>)
				{
					fstr << '\n';
				}
				else
				{
					fstr << delim;
				}
				
				fill<typename Row::next>(fstr, row.tail(), delim);
			}
		}

	} // namespace

	// helper function for users to load a data into a schema from a file
	template <typename Schema>
	Schema load(std::string const& file, char delim)
	{
		auto fstr{ std::fstream(file, fstr.in) };
		Schema table{};
		typename Schema::row_type row{};

		while (fstr)
		{
			fill<typename Schema::row_type>(fstr, row, delim);
			table.insert(std::move(row));

			// in case last stream extraction did not remove newline
			if (fstr.get() != '\n')
			{
				fstr.unget();
			}
		}

		return table;
	}

	// for compat with previous versions
	template <typename Schema, char Delim>
	inline Schema load(std::string const& file)
	{
		return load<Schema>(file, Delim);
	}

	// will work with schema and query objects
	template <typename Type>
	void store(Type const& data, std::string const& file, char delim)
	{
		auto fstr{ std::fstream(file, fstr.out) };

		for (auto const& row : data)
		{
			fill<typename Type::row_type>(fstr, row, delim);
		}
	}

	// for devs who want to use the previous format
	template <typename Type, char Delim>
	inline void store(Type const& data, std::string const& file)
	{
		store<Type>(data, file, Delim);
	}

} // namespace sql

namespace ra
{

	template <typename Input>
	class unary
	{
	public:
		using input_type = std::remove_cvref_t<decltype(Input::next())>;

		template <typename... Inputs>
		static inline void seed(Inputs const&... rs)
		{
			Input::seed(rs...);
		}

		static inline void reset()
		{
			Input::reset();
		}
	};

	template <typename LeftInput, typename RightInput>
	class binary
	{
	public:
		using left_type = std::remove_cvref_t<decltype(LeftInput::next())>;
		using right_type = std::remove_cvref_t<decltype(RightInput::next())>;

		template <typename... Inputs>
		static inline void seed(Inputs const&... rs)
		{
			LeftInput::seed(rs...);
			RightInput::seed(rs...);
		}

		static inline void reset()
		{
			LeftInput::reset();
			RightInput::reset();
		}
	};

} // namespace ra

namespace ra
{

	namespace
	{

		template <typename Left, typename Right>
		constexpr auto recr_merge()
		{
			if constexpr (std::is_same_v<Left, sql::void_row>)
			{
				return Right{};
			}
			else
			{
				using next = decltype(recr_merge<typename Left::next, Right>());

				return sql::row<typename Left::column, next>{};
			}
		}

		template <typename Left, typename Right>
		inline constexpr auto merge()
		{
			if constexpr (Left::column::name == Right::column::name)
			{
				return recr_merge<Left, typename Right::next>();
			}
			else
			{
				return recr_merge<Left, Right>();
			}
		}

		template <typename Dest, typename Row>
		constexpr void recr_copy(Dest& dest, Row const& src)
		{
			if constexpr (std::is_same_v<Row, sql::void_row>)
			{
				return;
			}
			else
			{
				dest.head() = src.head();
				recr_copy(dest.tail(), src.tail());
			}
		}

		template <typename Dest, typename Row>
		inline constexpr void copy(Dest& dest, Row const& src)
		{
			if constexpr (Dest::column::name == Row::column::name)
			{
				recr_copy(dest, src);
			}
			else
			{
				copy(dest.tail(), src);
			}
		}

	} // namespace

	template <typename LeftInput, typename RightInput>
	class join : public ra::binary<LeftInput, RightInput>
	{
		using binary_type = ra::binary<LeftInput, RightInput>;
		using left_type = typename binary_type::left_type;
		using right_type = typename binary_type::right_type;
	public:
		using output_type = decltype(merge<left_type, right_type>());

		template <typename... Inputs>
		static inline void seed(Inputs const&... rs)
		{
			binary_type::seed(rs...);
			copy(output_row, LeftInput::next());
		}

		static inline void reset()
		{
			binary_type::reset();
			copy(output_row, LeftInput::next());
		}

		static output_type output_row;
	};

	template <typename LeftInput, typename RightInput>
	typename join<LeftInput, RightInput>::output_type join<LeftInput, RightInput>::output_row{};

} // namespace ra

namespace ra
{

	struct data_end : std::exception
	{};

	// Id template parameter allows unique ra::relation types to be instantiated from
	//	a single sql::schema type (for queries referencing a schema multiple times).
	template <typename Schema, std::size_t Id>
	class relation
	{
	public:
		using output_type = Schema::row_type&;

		static auto& next()
		{
			if (curr != end)
			{
				return *curr++;
			}
			else
			{
				throw ra::data_end{};
			}
		}
		
		template <typename Input, typename... Inputs>
		static void seed(Input const& r, Inputs const&... rs) noexcept
		{
			if constexpr (std::is_same_v<Input, Schema>)
			{
				curr = r.begin();
				begin = r.begin();
				end = r.end();
			}
			else
			{
				seed(rs...);
			}
		}

		static inline void reset() noexcept
		{
			curr = begin;
		}

	private:
		static Schema::const_iterator curr;
		static Schema::const_iterator begin;
		static Schema::const_iterator end;
	};

	template <typename Schema, std::size_t Id>
	Schema::const_iterator relation<Schema, Id>::curr{};

	template <typename Schema, std::size_t Id>
	Schema::const_iterator relation<Schema, Id>::begin{};

	template <typename Schema, std::size_t Id>
	Schema::const_iterator relation<Schema, Id>::end{};

} // namespace ra

namespace ra
{

	template <typename LeftInput, typename RightInput>
	class cross : public ra::join<LeftInput, RightInput>
	{
		using join_type = ra::join<LeftInput, RightInput>;
	public:
		using output_type = join_type::output_type;

		static auto&& next()
		{
			try
			{
				copy(join_type::output_row, RightInput::next());
			}
			catch(ra::data_end const& e)
			{
				copy(join_type::output_row, LeftInput::next());
				RightInput::reset();
				copy(join_type::output_row, RightInput::next());
			}

			return std::move(join_type::output_row);
		}
	};

} // namespace ra

namespace ra
{

	template <typename LeftInput, typename RightInput>
	class natural : public ra::join<LeftInput, RightInput>
	{
		using join_type = ra::join<LeftInput, RightInput>;
		using key_type = std::remove_cvref_t<decltype(LeftInput::next().head())>;
		using value_type = std::vector<std::remove_cvref_t<decltype(RightInput::next().tail())>>;
		using map_type = std::unordered_map<key_type, value_type>;
	public:
		using output_type = join_type::output_type;

		template <typename... Inputs>
		static void seed(Inputs const&... rs)
		{
			join_type::seed(rs...);
			
			if (row_cache.empty())
			{
				try
				{
					for (;;)
					{
						auto const& row{ RightInput::next() };
						row_cache[row.head()].push_back(row.tail());
					}
				}
				catch(ra::data_end const& e)
				{
					RightInput::reset();
				}
			}

			auto const& active{ row_cache[join_type::output_row.head()] };
			curr = active.cbegin();
			end = active.cend();
		}

		static auto&& next()
		{
			while (curr == end)
			{
				copy(join_type::output_row, LeftInput::next());
				auto const& active{ row_cache[join_type::output_row.head()] };
				curr = active.cbegin();
				end = active.cend();
			}

			copy(join_type::output_row, *curr++);
			
			return std::move(join_type::output_row);
		}

	private:
		static map_type row_cache;
		static value_type::const_iterator curr;
		static value_type::const_iterator end;
	};

	template <typename LeftInput, typename RightInput>
	typename natural<LeftInput, RightInput>::map_type natural<LeftInput, RightInput>::row_cache{};

	template <typename LeftInput, typename RightInput>
	typename natural<LeftInput, RightInput>::value_type::const_iterator natural<LeftInput, RightInput>::curr;

	template <typename LeftInput, typename RightInput>
	typename natural<LeftInput, RightInput>::value_type::const_iterator natural<LeftInput, RightInput>::end;

} // namespace ra

namespace ra
{

	template <typename Output, typename Input>
	class projection : public ra::unary<Input>
	{
		using input_type =  typename ra::unary<Input>::input_type;
	public:
		using output_type = Output;

		static auto&& next()
		{
			fold<output_type>(output_row, Input::next());
			
			return std::move(output_row);
		}

	private:
		template <typename Dest>
		static inline constexpr void fold(Dest& dest, input_type const& src)
		{
			if constexpr (Dest::depth == 0)
			{
				return;
			}
			else
			{
				dest.head() = sql::get<Dest::column::name>(src);
				fold<typename Dest::next>(dest.tail(), src);	
			}
		}

		static output_type output_row;
	};

	template <typename Output, typename Input>
	typename projection<Output, Input>::output_type projection<Output, Input>::output_row{};

} // namespace ra

namespace ra
{

	template <typename Output, typename Input>
	class rename : public ra::unary<Input>
	{
		using input_type = typename ra::unary<Input>::input_type;
	public:
		using output_type = Output;

		static auto&& next()
		{
			fold<output_type, input_type>(output_row, Input::next());
			
			return std::move(output_row);
		}

	private:
		template <typename Dest, typename Src>
		static inline constexpr void fold(Dest& dest, Src const& src)
		{
			if constexpr (Dest::depth == 0)
			{
				return;
			}
			else
			{
				dest.head() = src.head();
				fold<typename Dest::next, typename Src::next>(dest.tail(), src.tail());
			}
		}

		static output_type output_row;
	};

	template <typename Output, typename Input>
	typename rename<Output, Input>::output_type rename<Output, Input>::output_row{};
	
} // namespace ra

namespace ra
{

	template <typename Predicate, typename Input>
	class selection : public ra::unary<Input>
	{
		using input_type = typename ra::unary<Input>::input_type;
	public:
		using output_type = input_type;		

		static auto&& next()
		{
			output_row = Input::next();

			while(!Predicate::eval(output_row))
			{
				output_row = Input::next();
			}

			return std::move(output_row);
		}

	private:
		static output_type output_row;
	};

	template <typename Output, typename Input>
	typename selection<Output, Input>::output_type selection<Output, Input>::output_row{};

} // namespace ra

namespace sql
{
	namespace
	{
		
		template <typename Char>
		constexpr bool whitespace(Char curr)
		{
			return curr == Char{ ' ' } || curr == Char{ '\t' } || curr == Char{ '\n' };
		}

		template <typename Char>
		constexpr bool syntax(Char curr)
		{
			return curr == Char{ ',' } || curr == Char{ '(' } || curr == Char{ ')' } ||
				curr == Char{ '\'' } || curr == Char{ '\"' } || curr == Char{ '=' };
		}

		template <typename Char>
		constexpr const Char* skip(const Char *curr, const Char *end)
		{
			for (; curr != end && whitespace(*curr); ++curr);
			return curr;
		}

		template <typename Char>
		constexpr const Char* next(const Char *curr, const Char *end)
		{
			Char c{ *curr };

			if (c == Char{ '>' } || c == Char{ '<' } || c == Char{ '!' })
			{
				++curr;

				if (*curr == Char{ '=' } || (c == Char{ '<' } && *curr == Char{ '>' }))
				{
					++curr;
				}
			}
			else if (syntax(c))
			{
				++curr;
			}
			else
			{
				for (; curr != end && !whitespace(*curr) && !syntax(*curr); ++curr);
			}
			
			return curr;
		}
	
	} // namespace

	template <typename Char, std::size_t Count>
	class tokens
	{
	public:
		using token_view = std::basic_string_view<Char>;

		constexpr tokens() = default;

		template<std::size_t N>
		constexpr tokens(cexpr::string<Char, N> const& cs) : tokens_{}
		{
			auto curr{ cs.cbegin() }, last{ cs.cbegin() };
			const auto end{ cs.cend() };
			std::size_t i{};

			while (curr < end)
			{
				curr = skip(curr, end);
				last = curr;
				last = next(last, end);

				if (*curr == Char{ '\"' } || *curr == Char{ '\'' })
				{
					tokens_[i++] = token_view{ curr, 1 };
					for (char c{ *curr++ }; last != end && *last != c; ++last);
				}

				auto len{ reinterpret_cast<std::size_t>(last) - reinterpret_cast<std::size_t>(curr) };
				tokens_[i++] = token_view{ curr, len };

				if (*last == Char{ '\"' } || *last == Char{ '\'' })
				{
					tokens_[i++] = token_view{ last, 1 };
					++last;
				}

				curr = last;
			}
		}

		constexpr std::size_t count() const noexcept
		{
			return Count;
		}

		constexpr token_view* begin() noexcept
		{
			return tokens_.begin();
		}
		constexpr const token_view* cbegin() const noexcept
		{
			return tokens_.cbegin();
		}

		constexpr token_view* end() noexcept
		{
			return tokens_.end();
		}
		constexpr const token_view* cend() const noexcept
		{
			return tokens_.cend();
		}

		constexpr token_view& operator[](std::size_t i)
		{
			return tokens_[i];
		}
		constexpr token_view const& operator[](std::size_t i) const
		{
			return tokens_[i];
		}

	private:
		std::array<token_view, Count> tokens_;
	};

	template<typename Char, std::size_t N>
	constexpr std::size_t preprocess(cexpr::string<Char, N> const& cs) noexcept
	{
		auto begin{ cs.cbegin() };
		const auto end{ cs.cend() };
		std::size_t count{ 1 };

		while (begin < end)
		{
			begin = skip(begin, end);
			begin = next(begin, end);
			++count;
		}

		return count;
	}

} // namespace sql

namespace sql
{

	namespace
	{

		// shim to allow all value types like double or float to be used as non-type template parameters.
		template <typename Type>
		struct value
		{
			constexpr value(Type v) : val{ v }
			{}

			Type val;
		};

	} // namespace

	template <cexpr::string Op, typename Row, typename Left, typename Right=void>
	struct operation
	{
		static constexpr bool eval(Row const& row) noexcept
		{
			if constexpr (Op == "=")
			{
				return Left::eval(row) == Right::eval(row);
			}
			else if constexpr (Op == ">")
			{
				return Left::eval(row) > Right::eval(row);
			}
			else if constexpr(Op == "<")
			{
				return Left::eval(row) < Right::eval(row);
			}
			else if constexpr(Op == ">=")
			{
				return Left::eval(row) >= Right::eval(row);
			}
			else if constexpr(Op == "<=")
			{
				return Left::eval(row) <= Right::eval(row);
			}
			else if constexpr(Op == "!=" || Op == "<>")
			{
				return Left::eval(row) != Right::eval(row);
			}
			else if constexpr(Op == "AND")
			{
				return Left::eval(row) && Right::eval(row);
			}
			else if constexpr(Op == "OR")
			{
				return Left::eval(row) || Right::eval(row);
			}
			else if constexpr(Op == "NOT")
			{
				return !Left::eval(row);
			}
		}
	};

	template <cexpr::string Column, typename Row>
	struct variable
	{
		static constexpr auto eval(Row const& row) noexcept
		{
			return sql::get<Column>(row);
		}
	};

	template <auto Const, typename Row>
	struct constant
	{
		static constexpr auto eval([[maybe_unused]] Row const& row) noexcept
		{
			return Const.val;
		}
	};

} // namespace sql

namespace sql
{

	// anonymous namespace to hold helper data structures and functions
	namespace
	{

		template <std::size_t Pos, typename Node>
		struct context
		{
			using node = Node;
			static constexpr std::size_t pos = Pos;
		};

		template <typename Type, std::size_t Name, std::size_t Next>
		struct colinfo
		{
			using type = Type;
			static constexpr std::size_t name = Name;
			static constexpr std::size_t next = Next;
		};

		template <cexpr::string Name, typename Row>
		constexpr bool exists() noexcept
		{
			if constexpr (std::is_same_v<Row, sql::void_row>)
			{
				return false;
			}
			else
			{
				if constexpr (Row::column::name == Name)
				{
					return true;
				}
				else
				{
					return exists<Name, typename Row::next>();
				}
			}
		}

		template <typename Type, typename Char, std::size_t N>
		constexpr value<Type> convert(cexpr::string<Char, N> const& str) noexcept
		{
			auto curr{ str.cbegin() }, end{ str.cend() };
			constexpr Char dot{ '.' }, zro{ '0' }, min{ '-' };
			Type acc{}, sign{ 1 }, scalar{ 10 };

			if (*curr == min)
			{
				sign = -1;
				++curr;
			}

			while (curr != end && *curr != dot)
			{
				acc = (acc * scalar) + (*curr - zro);
				++curr;
			}

			if (curr != end && *curr == dot)
			{
				scalar = 1;
				++curr;

				while(curr != end)
				{
					acc += (*curr - zro) * (scalar /= Type{ 10 });
					++curr;
				}
			}

			return value<Type>{ acc * sign };
		}

		inline constexpr bool isquote(std::string_view const& tv) noexcept
		{
			return tv == "\"" || tv == "'";
		}

		inline constexpr bool isor(std::string_view const& tv) noexcept
		{
			return tv == "OR" || tv == "or";
		}

		inline constexpr bool isand(std::string_view const& tv) noexcept
		{
			return tv == "AND" || tv == "and";
		}

		inline constexpr bool isnot(std::string_view const& tv) noexcept
		{
			return tv == "NOT" || tv == "not";
		}

		inline constexpr bool isnatural(std::string_view const& tv) noexcept
		{
			return tv == "NATURAL" || tv == "natural";
		}

		inline constexpr bool isjoin(std::string_view const& tv) noexcept
		{
			return tv == "JOIN" || tv == "join";
		}

		inline constexpr bool iswhere(std::string_view const& tv) noexcept
		{
			return tv == "WHERE" || tv == "where";
		}

		inline constexpr bool isfrom(std::string_view const& tv) noexcept
		{
			return tv == "FROM" || tv == "from";
		}

		inline constexpr bool isas(std::string_view const& tv) noexcept
		{
			return tv == "AS" || tv == "as";
		}

		inline constexpr bool isselect(std::string_view const& tv) noexcept
		{
			return tv == "SELECT" || tv == "select";
		}

		inline constexpr bool iscomma(std::string_view const& tv) noexcept
		{
			return tv == ",";
		}

		constexpr bool isintegral(std::string_view const& tv) noexcept
		{
			bool result{ false };

			for (auto c : tv)
			{
				result |= (c == '.');
			}

			return !result;
		}

		constexpr bool isdigit(char c) noexcept
		{
			return (c >= '0' && c <= '9') || c == '-' || c == '.';
		}

		constexpr bool iscomp(char c) noexcept
		{
			return c == '=' || c == '!' || c == '<' || c == '>';
		}

		constexpr bool iscolumn(std::string_view const& tv) noexcept
		{
			return !iscomma(tv) && !isas(tv) && !isfrom(tv);
		}

		constexpr bool isseparator(std::string_view const& tv) noexcept
		{
			return iscomma(tv) || isfrom(tv);
		}

	} // namespace

	// structured binding compliant iterator for query objects
	template <typename Expr>
	class query_iterator
	{
	public:
		using row_type = std::remove_cvref_t<typename Expr::output_type>;

		// seeds row datamember for first dereference
		query_iterator(bool end) : end_{ end }, row_{}
		{
			operator++();
		}

		inline bool operator==(query_iterator const& it) const noexcept
		{
			return end_ == it.end_;
		}

		inline bool operator!=(query_iterator const& it) const noexcept
		{
			return !(*this == it);
		}

		inline row_type const& operator*() const noexcept
		{
			return row_;
		}

		query_iterator& operator++()
		{
			if (!end_)
			{
				try
				{
					row_ = Expr::next();
				}
				catch (ra::data_end const& e)
				{
					end_ = true;
				}
			}

			return *this;
		}

	private:
		bool end_{};
		row_type row_{};
	};

	template <cexpr::string Str, typename... Schemas>
	class query
	{
	private:
		// where predicate terminal parsing 
		template <std::size_t Pos, typename Row>
		static constexpr auto parse_terms()
		{
			if constexpr (tokens_[Pos] == "(")
			{
				constexpr auto next{ parse_or<Pos + 1, Row>() };

				using node = typename decltype(next)::node;

				static_assert(tokens_[next.pos] == ")", "No closing paranthesis found.");

				return context<next.pos + 1, node>{};
			}
			else if constexpr (isquote(tokens_[Pos]))
			{
				constexpr cexpr::string<char, tokens_[Pos + 1].length() + 1> name{ tokens_[Pos + 1] };

				using str = decltype(name);
				using node = sql::constant<value<str>{ name }, Row>;

				static_assert(isquote(tokens_[Pos + 2]), "No closing quote found.");

				return context<Pos + 3, node>{};
			}
			else if constexpr (isdigit(tokens_[Pos][0]))
			{
				constexpr cexpr::string<char, tokens_[Pos].length() + 1> name{ tokens_[Pos] };
				
				using val = decltype(isintegral(tokens_[Pos]) ? std::int64_t{} : double{});
				using node = sql::constant<sql::convert<val>(name), Row>;

				return context<Pos + 1, node>{};
			}
			else
			{
				constexpr cexpr::string<char, tokens_[Pos].length() + 1> name{ tokens_[Pos] };

				using node = sql::variable<name, Row>;

				return context<Pos + 1, node>{};
			}
		}

		// parses a single compare operation
		template <typename Left, typename Row>
		static constexpr auto recurse_comparison()
		{
			if constexpr (!iscomp(tokens_[Left::pos][0]))
			{
				return Left{};
			}
			else
			{
				constexpr auto next{ parse_terms<Left::pos + 1, Row>() };
				constexpr cexpr::string<char, tokens_[Left::pos].length() + 1> name{ tokens_[Left::pos] };

				using ranode = typename decltype(next)::node;
				using node = sql::operation<name, Row, typename Left::node, ranode>;

				return context<next.pos, node>{};
			}			
		}

		// descend further and attempt to parse a compare operation
		template <std::size_t Pos, typename Row>
		static constexpr auto parse_comparison()
		{
			using left = decltype(parse_terms<Pos, Row>());
			
			return recurse_comparison<left, Row>();
		}

		// attempt to parse a negation operation then descend further
		template <std::size_t Pos, typename Row>
		static constexpr auto parse_negation()
		{
			if constexpr (isnot(tokens_[Pos]))
			{
				constexpr auto next{ parse_comparison<Pos + 1, Row>() };

				using ranode = typename decltype(next)::node;
				using node = sql::operation<"NOT", Row, ranode>;

				return context<next.pos, node>{};
			}
			else
			{
				return parse_comparison<Pos, Row>();
			}
		}

		// recursively parse chained AND operations
		template <typename Left, typename Row>
		static constexpr auto recurse_and()
		{
			if constexpr (!isand(tokens_[Left::pos]))
			{
				return Left{};
			}
			else
			{
				constexpr auto next{ parse_negation<Left::pos + 1, Row>() };

				using ranode = typename decltype(next)::node;
				using node = sql::operation<"AND", Row, typename Left::node, ranode>;

				return recurse_and<context<next.pos, node>, Row>();
			}
		}

		// descend further then attempt to parse AND operations
		template <std::size_t Pos, typename Row>
		static constexpr auto parse_and()
		{
			using left = decltype(parse_negation<Pos, Row>());
			
			return recurse_and<left, Row>();
		}
		
		// recursively parse chained OR operations
		template <typename Left, typename Row>
		static constexpr auto recurse_or()
		{
			if constexpr (!isor(tokens_[Left::pos]))
			{
				return Left{};
			}
			else
			{
				constexpr auto next{ parse_and<Left::pos + 1, Row>() };
				
				using ranode = typename decltype(next)::node;
				using node = sql::operation<"OR", Row, typename Left::node, ranode>;

				return recurse_or<context<next.pos, node>, Row>();
			}
		}

		// descend further then attempt to parse OR operations
		template <std::size_t Pos, typename Row>
		static constexpr auto parse_or()
		{
			using left = decltype(parse_and<Pos, Row>());
			
			return recurse_or<left, Row>();
		}

		// find correct schema for terminal relation
		template <cexpr::string Name, std::size_t Id, typename Schema, typename... Others>
		static constexpr auto recurse_schemas()
		{
			if constexpr (Name == Schema::name)
			{
				return ra::relation<Schema, Id>{};
			}
			else
			{
				static_assert(sizeof...(Others) != 0, "Schema name used in JOIN was not provided.");

				return recurse_schemas<Name, Id, Others...>();
			}
		}

		// wrapper function to determine terminal relation
		template <std::size_t Pos>
		static constexpr auto parse_schema()
		{
			if constexpr (tokens_[Pos] == "(")
			{
				constexpr auto next{ parse_root<Pos + 1>() };
				
				using node = typename decltype(next)::node;

				static_assert(tokens_[next.pos] == ")", "No closing paranthesis found.");

				return context<next.pos + 1, node>{};
			}
			else
			{
				constexpr cexpr::string<char, tokens_[Pos].length() + 1> name{ tokens_[Pos] };

				using node = decltype(recurse_schemas<name, Pos, Schemas...>());

				return context<Pos + 1, node>{};
			}
		}

		// stub which will choose the specific join RA node
		template <std::size_t Pos, typename Left, typename Right>
		static constexpr auto choose_join()
		{
			if constexpr (isnatural(tokens_[Pos]))
			{
				return ra::natural<Left, Right>{};
			}
			else
			{
				return ra::cross<Left, Right>{};	
			}
		}

		// parses join colinfo if a join is present else returns the single relation terminal
		template <std::size_t Pos>
		static constexpr auto parse_join()
		{
			constexpr auto lnext{ parse_schema<Pos>() };

			using lnode = typename decltype(lnext)::node;

			if constexpr (lnext.pos + 2 < tokens_.count() && isjoin(tokens_[lnext.pos + 1]))
			{
				constexpr auto rnext{ parse_schema<lnext.pos + 2>() };

				using rnode = typename decltype(rnext)::node;
				using join = decltype(choose_join<lnext.pos, lnode, rnode>());

				return context<rnext.pos, join>{};
			}
			else
			{
				return context<lnext.pos, lnode>{};
			}
		}

		// starting point to parse everything after the from keyword
		template <std::size_t Pos>
		static constexpr auto parse_from()
		{
			static_assert(isfrom(tokens_[Pos]), "Expected 'FROM' token not found.");

			constexpr auto next{ parse_join<Pos + 1>() };

			using node = typename decltype(next)::node;

			if constexpr (next.pos < tokens_.count() && iswhere(tokens_[next.pos]))
			{
				using output = std::remove_cvref_t<typename node::output_type>;

				constexpr auto predicate{ parse_or<next.pos + 1, output>() };

				using pnext = typename decltype(predicate)::node;
				using snode = ra::selection<pnext, node>;

				return context<predicate.pos, snode>{};
			}
			else
			{
				return context<next.pos, node>{};	
			}
		}

		// recursively searches all schemas for the a matching column
		template <cexpr::string Name, typename Schema, typename... Others>
		static constexpr auto recurse_types()
		{
			if constexpr (sql::exists<Name, typename Schema::row_type>())
			{
				return decltype(sql::get<Name>(typename Schema::row_type{})){};
			}
			else
			{
				static_assert(sizeof...(Others) != 0, "Column name was not present in any schema.");

				return recurse_types<Name, Others...>();
			}
		}

		// wrapper to determine the type for the the column
		template <std::size_t Pos>
		static constexpr auto column_type()
		{
			constexpr cexpr::string<char, tokens_[Pos].length() + 1> name{ tokens_[Pos] };

			return recurse_types<name, Schemas...>();
		}

		// asserts token is column separator, and if comma returns one past the comma else start position
		template <std::size_t Pos>
		static constexpr std::size_t next_column()
		{
			static_assert(isseparator(tokens_[Pos]), "Expected ',' or 'FROM' token following column.");

			if constexpr (iscomma(tokens_[Pos]))
			{
				return Pos + 1;
			}
			else
			{
				return Pos;
			}
		}

		template <std::size_t Pos, bool Rename>
		static constexpr auto parse_colinfo()
		{
			static_assert(iscolumn(tokens_[Pos]), "Invalid token starting column delcaration.");

			constexpr bool rename{ isas(tokens_[Pos + 1]) && iscolumn(tokens_[Pos + 2]) };

			using col = decltype(column_type<Pos>());

			if constexpr (Rename && rename)
			{
				constexpr auto next{ next_column<Pos + 3>() };

				return colinfo<col, Pos + 2, next>{};
			}
			else if constexpr (rename)
			{
				constexpr auto next{ next_column<Pos + 3>() };

				return colinfo<col, Pos, next>{};
			}
			else
			{
				constexpr auto next{ next_column<Pos + 1>() };

				return colinfo<col, Pos, next>{};
			}
		}

		// recursively parse all columns projected/renamed in the query
		template <std::size_t Pos, bool Rename>
		static constexpr auto recurse_columns()
		{
			if constexpr (isfrom(tokens_[Pos]))
			{
				return context<Pos, sql::void_row>{};
			}
			else
			{
				constexpr auto info{ parse_colinfo<Pos, Rename>() };
				constexpr cexpr::string<char, tokens_[info.name].length() + 1> name{ tokens_[info.name] };
				constexpr auto child{ recurse_columns<info.next, Rename>() };

				using next = std::remove_const_t<typename decltype(child)::node>;
				using col = std::remove_const_t<decltype(sql::column<name, typename decltype(info)::type>{})>;
				using node = sql::row<col, next>;

				return context<child.pos, node>{};
			}
		}

		// wrapper to parse columns as a projection RA node
		template <std::size_t Pos>
		static constexpr auto parse_projection()
		{
			constexpr auto proj{ recurse_columns<Pos, false>() };
			constexpr auto next{ parse_from<proj.pos>() };

			using ranode = typename decltype(proj)::node;
			using node = ra::projection<ranode, typename decltype(next)::node>;

			return context<next.pos, node>{};
		}

		// wrapper to parse columns as a rename RA node
		template <std::size_t Pos>
		static constexpr auto parse_rename()
		{
			constexpr auto next = parse_projection<Pos>();

			using ranode = typename decltype(recurse_columns<Pos, true>())::node;
			using node = ra::rename<ranode, typename decltype(next)::node>;

			return context<next.pos, node>{};
		}

		// attempts to match column rename operation pattern on a column
		template <std::size_t Pos>
		static constexpr bool has_rename()
		{
			if constexpr (isfrom(tokens_[Pos]) || isfrom(tokens_[Pos + 2]))
			{
				return false;
			}
			else if constexpr (iscolumn(tokens_[Pos]) && isas(tokens_[Pos + 1]) && iscolumn(tokens_[Pos + 2]))
			{
				return true;
			}
			else
			{
				constexpr bool comma{ iscomma(tokens_[Pos + 1]) };

				static_assert(comma || isfrom(tokens_[Pos + 1]), "Expected ',' or 'FROM' token following column.");

				if constexpr (comma)
				{
					return has_rename<Pos + 2>();
				}
				else
				{
					return has_rename<Pos + 1>();
				}
			}
		}

		// decide RA node to root the expression tree
		template <std::size_t Pos>
		static constexpr auto parse_root()
		{
			static_assert(isselect(tokens_[Pos]), "Expected 'SELECT' token not found.");

			if constexpr (tokens_[Pos + 1] == "*")
			{
				return parse_from<Pos + 2>();
			}
			else if constexpr (has_rename<Pos + 1>())
			{
				return parse_rename<Pos + 1>();
			}
			else
			{
				return parse_projection<Pos + 1>();
			}
		}

		static constexpr sql::tokens<char, sql::preprocess(Str)> tokens_{ Str };

		using expression = typename decltype(parse_root<0>())::node;

		bool empty_;
	
	public:
		using iterator = query_iterator<expression>;
		using row_type = expression::output_type;

		query(Schemas const&... tables)
		{
			try 
			{
				expression::seed(tables...);
				empty_ = false;
			}
			catch(ra::data_end const& e)
			{
				empty_ = true;
			}
		}

		~query()
		{
			expression::reset();
		}

		inline iterator begin() const
		{
			return iterator{ empty_ };
		}

		inline iterator end() const
		{
			return iterator{ true };
		}
	};

} // namespace sql



================================================
FILE: tests/data/authored.tsv
================================================
1984	George Orwell
!!!The!!Teddy!Crazy!!Show!!!	Harlan Ellison
(Learning About) Machine Sex	Candas Jane Dorsey
...the World, as we Know 't	Howard Waldrop
2001: A Space Odyssey	Arthur C. Clarke
2004, or Thereabouts	David R. Bunch
20th Century Boys vol.1	Naoki Urasawa
20th Century Boys vol.2	Naoki Urasawa
20th Century Boys vol.3	Naoki Urasawa
20th Century Boys vol.4	Naoki Urasawa
20th Century Boys vol.5	Naoki Urasawa
20th Century Boys vol.6	Naoki Urasawa
A Biography of Tadeo Isidoro Cruz (1829-1874)	Jorge Luis Borges
A Brief History of the Trans-Pacific Tunnel	Ken Liu
A Canticle for Leibowitz	Walter M. Miller, Jr.
A Case of Conscience	James Blish
A Case of Identity	Arthur Conan Doyle
A Clash of Cymbals	James Blish
A Clockwork Orange	Anthony Burgess
A Day at Harmenz	Tadeusz Borowski
A Deskful of Girls	Fritz Leiber
A Dialog About A Dialog	Jorge Luis Borges
A Dialog Between Dead Men	Jorge Luis Borges
A Farewell to Arms	Ernest Hemingway
A Feast of Demons	William Morrison
A Few Things I Know About While Away	Joanna Russ
A Hundred Ghosts Parade Tonight	Xia Jia
A is for Automation	Kate Wilhelm
A Life for the Stars	James Blish
A Midwinter's Tale	Michael Swanwick
A Momentary Taste of Being	James Tiptree, Jr.
A Mouse in the Walls of the Global Village	Dean R. Koontz
A New Refutation of Time	Jorge Luis Borges
A Note on (toward) Bernard Shaw	Jorge Luis Borges
A Path Through the Darkness	Harlan Ellison
A Prayer for No One's Enemies	Harlan Ellison
A Problem	Jorge Luis Borges
A Scandal in Bohemia	Arthur Conan Doyle
A Scanner Darkly	Philip K. Dick
A Time of Changes	Robert Silverberg
A Tour of C++ 2nd	Bjarne Stroustrup
A Toy for Juliette	Robert Bloch
A True Story	Tadeusz Borowski
A Visit	Tadeusz Borowski
A Way of Thinking	Theodore Sturgeon
Absalom, Absalom!	William Faulkner
Adrift Just Off the Islets of Langerhans: Latitude 38o54'N, Longitude 77o00'13W	Harlan Ellison
Adrift on the Policy Level	Chandler Davis
Aesop	Clifford D. Simak
After the Days of Dead-Eye 'Dee	Pat Cadigan
Again, Dangerous Visions	Harlan Ellison
Akira vol.1	Katsuhiro Otomo
Akira vol.2	Katsuhiro Otomo
Akira vol.3	Katsuhiro Otomo
Akira vol.4	Katsuhiro Otomo
Akira vol.5	Katsuhiro Otomo
Akira vol.6	Katsuhiro Otomo
Algorithms 4th	Kevin Wayne
Algorithms 4th	Robert Sedgewick
All in Good Time	Miram Allen deFord
All the Birds Come Home to Roost	Harlan Ellison
All the Flavors	Ken Liu
All the Lies Lies That Are My Life	Harlan Ellison
All The People	R. A. Lafferty
All the Sound of Fear	Harlan Ellison
All Tomorrow's Parties	William Gibson
Along the Scenic Route	Harlan Ellison
Alpha Ralpha Boulevard	Cordwainer Smith
Amateur in Chancery	George O. Smith
America	Orson Scott Card
An Advanced Readers' Picture Book of Comparative Cognition	Ken Liu
An Examination of the Work of Herbert Quain	Jorge Luis Borges
And Chaos Died	Joanna Russ
And the Angels Sing	Kate Wilhelm
And the Moon be Still as Bright	Ray Bradbury
And the Sea Like Mirrors	Gregory Benford
Andover and the Android	Kate Wilhelm
Angry Candy	Harlan Ellison
Animal Farm	George Orwell
Anybody Else Like Me?	Walter M. Miller, Jr.
Anywhere But Here, With Anybody But You	Harlan Ellison
Approaching Oblivion	Harlan Ellison
April Fools' Day Forever	Kate Wilhelm
Argumentum Ornithologicum	Jorge Luis Borges
Army of None	Paul Scharre
As Simple As That	Zenna Henderson
At the End of the Orbit	Arthur C. Clarke
At the Mouse Circus	Harlan Ellison
Aunt Parnetta's Electric Blisters	Diane Glancy
Auschwitz, Our Home (A Letter)	Tadeusz Borowski
Auto-De-Fe	Roger Zelazny
Avatars of the Tortoise	Jorge Luis Borges
Averroes' Search	Jorge Luis Borges
Aye, and Gomorrah...	Samuel R. Delany
Balanced Ecology	James H. Schmitz
Basilisk	Harlan Ellison
Battle for the Mind	William Sargant
Battle Without Banners	Harlan Ellison
Battlefield	Harlan Ellison
Beachhead	Clifford D. Simak
Beauty's Beast	Robert Bloch
Bed Sheets are White	Evelyn Lief
Beowulf	Anonymous
Bettyann	Kris Neville
Beyond the Blue Event Horizon	Frederik Pohl
Bianca's Hands	Theodore Sturgeon
Bible and Sword	Barbara W. Tuchman
Big Joe and the Nth Generation	Walter M. Miller, Jr.
Blabbermouth	Theodore Sturgeon
Black Bargain	Robert Bloch
Blame! vol.1	Tsumotu Nihei
Blame! vol.2	Tsumotu Nihei
Blame! vol.3	Tsumotu Nihei
Blame! vol.4	Tsumotu Nihei
Blame! vol.5	Tsumotu Nihei
Blame! vol.6	Tsumotu Nihei
Blank?	Harlan Ellison
Bleeding Stones	Harlan Ellison
Blind Bird, Blind Bird, Go Away From Me!	Harlan Ellison
Blood Bank	Walter M. Miller, Jr.
Blot	Gahan Wilson
Blowups Happen	Robert A. Heilein
Blue Spring	Taiyo Matsumoto
Borges and I	Jorge Luis Borges
Bounty	T. L. Sherred
Brain Wave	Poul Anderson
Brass and Gold (or Horse and Zeppelin in Beverly Hills)	Philip Jose Farmer
Brave New World	Aldous Huxley
Bright Eyes	Harlan Ellison
Bright Segment	Theodore Sturgeon
Broken Glass	Harlan Ellison
Brownshoes	Theodore Sturgeon
Burning Chrome	William Gibson
By His Bootstraps	Robert A. Heinlein
C Primer Plus 5th	Stephen Prata
C++ Primer 5th	Barbara E. Moo
C++ Primer 5th	Josee Lajoie
C++ Primer 5th	Stanley B. Lippman
Call Girl	Tang Fei
Camps	Jack Dann
Capitalism Without Capital	Jonathan Haskel
Capitalism Without Capital	Stian Westlake
Captain Harlock: The Classic Collection vol.1	Leiji Matsumoto
Captain Harlock: The Classic Collection vol.2	Leiji Matsumoto
Captain Harlock: The Classic Collection vol.3	Leiji Matusmoto
Carcinoma Angels	Norman Spinard
Catch That Rabbit	Isaac Asimov
Catch-22	Joseph Heller
Catman	Harlan Ellison
Caviar	Theodore Sturgeon
Census	Clifford D. Simak
Chain Reaction	Boyd Ellanby
Chained to the Fast Lane in the Red Queen's Race	Harlan Ellison
Changewar	Fritz Leiber
Chapterhouse: Dune	Frank Herbert
Chatting with Anubis	Harlan Ellison
Childhood's End	Arthur C. Clarke
Children of Dune	Frank Herbert
Children of the Sea vol.1	Daisuke Igarashi
Children of the Sea vol.2	Daisuke Igarashi
Children of the Sea vol.3	Daisuke Igarashi
Children of the Sea vol.4	Daisuke Igarashi
Children of the Sea vol.5	Daisuke Igarashi
Ching Witch!	Ross Rocklynne
Christ, Old Student in a New School	Ray Bradbury
Chuck Berry, Won't You Please Come Home	Ken McCullough
City	Clifford D. Simak
Cold Friend	Harlan Ellison
Collecting Team	Robert Silverberg
Colossus	B. Jack Copeland
Columbus Was a Dope	Robert A. Heinlein
Come to the Party	F. M. Busby
Comes Now the Power	Roger Zelazny
Commuter's Problem	Harlan Ellison
Conversations With Jorge Luis Borges	Richard Burgin
Corpse	Harlan Ellison
Count the Clock That Tells the Time	Harlan Ellison
Count Zero	William Gibson
Covered Mirrors	Jorge Luis Borges
Crate	Theodore Sturgeon
Crazy as a Soup Sandwich	Harlan Ellison
Croatoan	Harlan Ellison
Crome Yellow	Aldous Huxley
Crucifixus Etiam	Walter M. Miller, Jr.
Curse 5.0	Liu Cixin
Damnation Morning	Fritz Leiber
Dandelion Wine	Ray Bradbury
Dangerous Visions	Harlan Ellison
Danger-Human!	Gordon R. Dickson
Daniel White for the Greater Good	Harlan Ellison
Darkness Upon the Face of the Deep	Harlan Ellison
Day Million	Frederik Pohl
Deal From the Bottom	Harlan Ellison
Death and the Compass	Jorge Luis Borges
Death and the Penguin	Andrey Kurkov
Deathbird Stories	Harlan Ellison
Death's End	Liu Cixin
Deeper than the Darkness	Harlan Ellison
Delia Elena San Marco	Jorge Luis Borges
Delusion for a Dragon Slayer	Harlan Ellison
Design Patterns	Erich Gamma
Design Patterns	John Vlissides
Design Patterns	Ralph Johnson
Design Patterns	Richard Helm
Destined for War	Graham Allison
Deutsches Requiem	Jorge Luis Borges
Devourer	Liu Cixin
Dirk Gently's Holistic Detective Agency	Douglas Adams
Distant Signals	Andrew Weiner
Distrust That Particular Flavor	William Gibson
Division by Zero	Ted Chiang
Django	Harlan Ellison
Djinn, No Chaser	Harlan Ellison
Do Androids Dream of Electric Sheep?	Philip K. Dick
Doctor Zhivago	Boris Pasternak
Dogfight	Michael Swanwick
Dogfight	William Gibson
Do-It-Yourself	Harlan Ellison
Don Quixote	Miguel de Cervantes Saavedra
Double Star	Robert A. Heinlein
Downward to the Earth	Robert Silverberg
Dr. Bloodmoney	Philip K. Dick
Dreamtigers	Jorge Luis Borges
Dumb Waiter	Walter M. Miller, Jr.
Dune	Frank Herbert
Dune Messiah	Frank Herbert
Dying Inside	Robert Silverberg
Each an Explorer	Isaac Asimov
Earthman, Come Home	James Blish
Earthman, Go Home!	Harlan Ellison
Ecowarewness	Harlan Ellison
Eidolons	Harlan Ellison
Elbow Room	Marion Zimmer Bradley
Elegy	Jorge Luis Borges
Elouise and the Doctors of the Planet Pergamon	Josephine Saxton
Emanon vol.1: Memories of Emanon	Kenji Tsuruta
Emanon vol.2: Emanon Wanderer pt.1	Kenji Tsuruta
Emanon vol.3: Emanon Wanderer pt.2	Kenji Tsuruta
Emissary from Hamelin	Harlan Ellison
Emma Zunz	Jorge Luis Borges
Empire of the Sun	Andrew Weiner
Empire Star	Samuel R. Delany
Encounter With A Hick	Jonathan Brand
Ender's Game	Orson Scott Card
Endless Frontier	G. Pascal Zachary
Endymion	Dan Simmons
Enemy Mine	Barry B. Longyear
Eniac	Scott McCartney
Epilogue	Clifford D. Simak
Epiphany for Aliens	David Kerr
Ernest and the Machine God	Harlan Ellison
Erotophobia	Harlan Ellison
Ersatz	Henry Slesar
Escape!	Isaac Asimov
Escapegoat	Harlan Ellison
Eutopia	Poul Anderson
Evensong	Lester del Rey
Everything and Nothing	Jorge Luis Borges
Evidence	Isaac Asimov
Exploration Team	Murray Leinster
Explorers of Space	Robert Silverberg
Exposures	Gregory Benford
Eye of the Beholder	Burt K. Filer
Fahrenheit 451	Ray Bradbury
Faith of our Fathers	Philip K. Dick
Fault-Tolerant Computer System Designs	Dhiraj K. Pradhan
Fear is a Cold Black	Kate Wilhelm
Feather Tigers	Gene Wolfe
Featherbed on Chlyntha	Miram Allen deFord
Fiasco	Stanislaw Lem
Ficciones	Jorge Luis Borges
Final Trophy	Harlan Ellison
Flies	Robert Silverberg
Flop Sweat	Harlan Ellison
Flow My Tears, the Policeman Said	Philip K. Dick
Flowers for Algernon	Daniel Keyes
Folding Beijing	Hao Jingfang
Footsteps	Harlan Ellison
For the Sake of Grace	Suzette Haden Elgin
For Value Received	Andrew J. Ouffutt
For Whom the Bell Tolls	Ernest Hemingway
Forward the Foundation	Isaac Asimov
Foundation	Isaac Asimov
Foundation and Earth	Isaac Asimov
Foundation and Empire	Isaac Asimov
Foundation's Edge	Isaac Asimov
Fragments of a Hologram Rose	William Gibson
Frank Herbert	Nebula Winners Fifteen
Frederik Pohl	The Expert Dreamers
From A to Z, In The Chocolate Alphabet	Harlan Ellison
From the Government Printing Office	Kris Neville
Frozen Journey	Philip K. Dick
Funes the Memorious	Jorge Luis Borges
G. B. K.-A Many-Flavored Bird	Harlan Ellison
Gateway	Frederik Pohl
Gather Blue Roses	Pamela Sargent
Gathi	Miram Allen deFord
Getting Along	James Blish
Ghost in the Shell	Shirow Masamune
Ghost in the Shell vol.1.5: Human-Error Processor	Shirow Masamune
Ghost in the Shell vol.2: Man-Machine Interface	Shirow Masamune
Ghost of a Chance	Theodore Sturgeon
giANTS	Edward Bryant
Gift from the Stars	Kate Wilhelm
Giganto Maxia	Kentaro Miura
Gnomebody	Harlan Ellison
Go Toward the Light	Harlan Ellison
Go, Go, Go, Said the Bird	Sonya Dorman
God Emperor of Dune	Frank Herbert
Goldfish Bowl	Robert A. Heinlein
Gonna Roll the Bones	Fritz Leiber
Good Hunting	Ken Liu
Good News from the Vatican	Robert Silverberg
Gopher in the Gilly	Harlan Ellison
Grail	Harlan Ellison
Grave of the Fireflies	Cheng Jingbo
Gutter Gang	Harlan Ellison
Hadj	Harlan Ellison
Half-Life	Paul Preuss
Hamlet	William Shakespeare
Harry the Hare	James B. Hemesath
Hawksbill Station	Robert Silverberg
Heart of Darkness	Joseph Conrad
Heavyplanet	Lee Gregor
Heechee Rendezvous	Frederik Pohl
Heechee Treasures	Frederik Pohl
Hell Is the Absence of God	Ted Chiang
Heretics of Dune	Frank Herbert
High Weir	Samuel R. Delany
Hindsight: 480 Seconds	Harlan Ellison
Hinterlands	William Gibson
His Vegetable	Pat Murphy
Hitler Painted Roses	Harlan Ellison
Hobbies	Clifford D. Simak
Homecoming	Ray Bradbury
Homelanding	Margaret Atwood
Houston, Houston, Do You Read?	James Tiptree, Jr.
How Beautiful with Banners	James Blish
How's the Night Life on Cassalda?	Harlan Ellison
Huddling Place	Clifford D. Simak
Humpty Dumpty had a Great Fall	Frank Belknap
Hyperion	Dan Simmons
I Curse the Lesson and Bless the Knowledge	Harlan Ellison
I Will Fear No Evil	Robert A. Heinlein
I, Dreamer	Walter M. Miller, Jr.
I, Robot	Isaac Asimov
Ibn-Hakam al-Bokhari, Murdered in His Labyrinth	Jorge Luis Borges
Ichi-F	Kazuto Tatsuta
Idoru	William Gibson
If All Men Were Brothers, Would You Let One Marry Your Sister?	Theodore Sturgeon
I'm Looking for Kadak	Harlan Ellison
In Fear of K	Harlan Ellison
In Lonely Islands	Harlan Ellison
In Memoriam, J. F. K.	Jorge Luis Borges
In re Glover	Leonard Tushnet
In the Barn	Piers Anthony
In the Core	Frederik Pohl
In the Fourth Year of the War	Harlan Ellison
Incident in Moderan	David R. Bunch
Inferno, I, 32	Jorge Luis Borges
Inferno: The World at War, 1939-1945	Max Hastings
Interim	Ray Bradbury
Interlocking Pieces	Molly Gloss
Into the Wild	Jon Krakauer
Into Thin Air	Jon Krakauer
Invaders	John Kessel
Invasion Footnote	Harlan Ellison
Invisible Man	Ralph Ellison
Invisible Planets	Hao Jingfang
It	Theodore Sturgeon
It was Nothing-Really	Theodore Sturgeon
It's You!	Theodore Sturgeon
J. C. on the Dude Ranch	Philip Jose Farmer
Jack-in-the-Box	Ray Bradbury
Jane Doe #112	Harlan Ellison
Jeffty is Five	Harlan Ellison
Jenny with Wings	Kate Wilhelm
Johnny Mnemonic	William Gibson
Jorry's Gap	Theodore Sturgeon
Judas	John Brunner
Julius Caesar	William Shakespeare
Jupiter Five	Arthur C. Clarke
Jurassic Park	Michael Crichton
Kafka and His Precursors	Jorge Luis Borges
Invisible Planets	Ken Liu
Keyboard	Harlan Ellison
Killdozer!	Theodore Sturgeon
Killing Bernstein	Harlan Ellison
King of the Hill	Chad Oliver
Kirinyaga	Mike Resnick
Kiss of Fire	Harlan Ellison
Knights to Move	Fritz Leiber
Knox	Harlan Ellison
Kyrie	Poul Anderson
Labyrinths	Jorge Luis Borges
Ladies and Gentlemen, This Is Your Crisis	Kate Wilhelm
Lamia Mutable	M. John Harrison
Land of the Great Horses	R. A. Lafferty
Last Train to Kankakee	Robin Scott
Laugh Track	Harlan Ellison
Leadership in Turbulent Times	Doris Kearns Goodwin
Lenny	Isaac Asimov
Let There Be Light	Robert A. Heilein
Liar!	Isaac Asimov
Life in Our Time	Robert Bloch
Life, the Universe and Everything	Douglas Adams
Life-Line	Robert A. Heilein
Liking What You See: A Documentary	Ted Chiang
Little Lost Robot	Isaac Asimov
Lollipop and the Tar Baby	John Varley
Lonley Women Are the Vessels of Time	Harlan Ellison
Looking for Company	Frederik Pohl
Lord of Light	Roger Zelazny
Lord of the Flies	William Golding
Lord Randy, My Son	Joe L. Hensley
Love Ain't Nothing but Sex Misspelled	Harlan Ellison
Lucy Comes To Stay	Robert Bloch
Madame Curie	Eve Curie
Making It All the Way into the Future on Gaxton Falls of the Red Planet	Barry N. Malzberg
Man of Letters	Kate Wilhelm
Man Plus	Frederik Pohl
Martin Fierro	Jorge Luis Borges
Martin the Warrior	Brian Jacques
Master and Commander	Patrick O'Brian
Mathoms from the Time Closet	Gene Wolfe
Mattimeo	Brian Jacques
Mealtime	Harlan Ellison
Medusa	Theodore Sturgeon
Mefisto in Onyx	Harlan Ellison
Microcosmic God	Theodore Sturgeon
Midnight in the Sunken Cathedral	Harlan Ellison
Midnight News	Lisa Goldstein
Mom	Harlan Ellison
Mona at Her Windows	Harlan Ellison
Mona Lisa Overdrive	William Gibson
Monitored Dreams & Strategic Cremations	Bernard Wolfe
Mono no Aware	Ken Liu
Monolog	Philip Jose Farmer
Monster vol.1	Naoki Urasawa
Monster vol.2	Naoki Urasawa
Monster vol.3	Naoki Urasawa
Monster vol.4	Naoki Urasawa
Monster vol.5	Naoki Urasawa
Monster vol.6	Naoki Urasawa
Monster vol.7	Naoki Urasawa
Monster vol.8	Naoki Urasawa
Monster vol.9	Naoki Urasawa
More Than Human	Theodore Sturgeon
Moth Race	Richard Hill
Mountain	Liu Cixin
Mr. Costello, Hero	Theodore Sturgeon
Mrs. Bagley Goes to Mars	Kate Wilhelm
Mutations	Jorge Luis Borges
Nackles vr.1	Donald E. Westlake
Nackles vr.2	Donald E. Westlake
Nackles vr.2	Harlan Ellison
Nausicaa of the Valley of the Wind vol.1	Hayao Miyazaki
Nausicaa of the Valley of the Wind vol.2	Hayao Miyazaki
Neither Your Jenny Nor Mine	Harlan Ellison
Neon	Harlan Ellison
Neuromancer	William Gibson
New Rose Hotel	William Gibson
Night Journey of the Dragon-Horse	Xia Jia
Night Meeting	Ray Bradbury
Night of Black Glass	Harlan Ellison
Nightfall	Isaac Asimov
Nightfall	Robert Silverberg
Night-Rise	Katherine MacLean
Nijigagara Holograph	Inio Asano
Nine Hundred Grandmothers	R. A. Lafferty
No Game for Children	Harlan Ellison
No Great Magic	Fritz Leiber
No Light in the Windows	Kate Wilhelm
Nothing for My Noon Meal	Harlan Ellison
Nova	Samuel R. Delany
O Ye of Little Faith	Harlan Ellison
Oddy and Id	Alfred Bester
Of Ants and Dinosaurs	Liu Cixin
On Exactitude and Science	Jorge Luis Borges
On the Downhill Slide	Harlan Ellison
On the Feasibility of Coal-Driven Power Stations	O. R. Frisch
On the Slab	Harlan Ellison
One Day in the Life of Ivan Denisovich	Aleksandr Solzhenitsyn
One for the Road	Kate Wilhelm
One Life, Furnished in Early Poverty	Harlan Ellison
One-Way Journey	Miram Allen deFord
Operating Systems in Depth	Thomas W. Doeppner
Operation Cassandra	Miram Allen deFord
Opium	Harlan Ellison
Other Worlds	Frederik Pohl
Out of All Them Bright Stars	Nancy Kress
Over the River and Through the Woods	Clifford D. Simak
Overlord	Max Hastings
Ozymandias	Terry Car
Paingod	Harlan Ellison
Paingod and Other Delusions	Harlan Ellison
Paladin of the Last Hour	Harlan Ellison
Parable of Cervantes and the Quixote	Jorge Luis Borges
Parable of the Palace	Jorge Luis Borges
Paradise	Clifford D. Simak
Paradiso, XXXI, 108	Jorge Luis Borges
Partial Magic in the Quixote	Jorge Luis Borges
Pattern Recognition	William Gibson
Paulie Charmed the Sleeping Woman	Harlan Ellison
Permanent Record	Edward Snowden
Persona 3: Official Design Works	Shigenori Soejima
Persona 4 Arena: Official Design Works	Shigenori Soejima
Persona 4: Official Design Works	Shigenori Soejima
Philtre Tip	Robert Bloch
Picnic on Paradise	Joanna Russ
Pierre Menrad, Author of Don Quixote	Jorge Luis Borges
Planet Story	Kate Wilhelm
Planetes vol.1	Makoto Yukimura
Planetes vol.2	Makoto Yukimura
Player Piano	Kurt Vonnegut
Precession	Edward Bryant
Prelude to Foundation	Isaac Asimov
Presidents of War	Michael Beschloss
Pretty Maggie Moneyeyes	Harlan Ellison
Prince Myshkin, and Hold the Relish	Harlan Ellison
Prodigy	Theodore Sturgeon
Project Nightmare	Robert A. Heinlein
Pulling Hard Time	Harlan Ellison
Punky & The Yale Men	Harlan Ellison
Queen Emeraldas vol.1	Leiji Matsumoto
Queen Emeraldas vol.2	Leiji Matsumoto
Quick to Haste	Miram Allen deFord
Quicktime	Harlan Ellison
Radio Free Albemuth	Philip K. Dick
Ragnarok	Jorge Luis Borges
Rain, Rain, Go Away	Harlan Ellison
Rat	James Patrick Kelly
Reason	Isaac Asimov
Red Star, Winter Orbit	Bruce Sterling
Red Star, Winter Orbit	William Gibson
Redwall	Brian Jacques
Rendezvous with Rama	Arthur C. Clarke
Repent, Harlequin! Said the Ticktockman	Harlan Ellison
Requiem	Robert A. Heilein
Riders of the Purple Wage	Philip Jose Farmer
Riding the Dark Train Out	Harlan Ellison
Ringworld	Larry Niven
Riverworld	Philip Jose Farmer
Riverworld and Other Stories	Philip Jose Farmer
Roadside Picnic	Arkady Strugatsky
Roadside Picnic	Boris Strugatsky
Robbie	Isaac Asimov
Rock God	Harlan Ellison
Rocket Summer	Ray Bradbury
Runaround	Isaac Asimov
Sandkings	George R. R. Martin
Saturn, November 11th	Harlan Ellison
Scartaris, June 28th	Harlan Ellison
Schrodinger's Plague	Greg Bear
Schwarzschild Radius	Connie Willis
Second Foundation	Isaac Asimov
Seeing	Harlan Ellison
Selected Poems	T. S. Eliot
Selected Stories	Theodore Sturgeon
Sensible City	Harlan Ellison
Seraphim: 266613336 Wings	Satoshi Kon
Seventy-Two Letters	Ted Chiang
Sex and/or Mr. Morrison	Carol Emshwiller
Shadow, Shadow on the Wall	Theodore Sturgeon
Shall the Dust Praise Thee?	Damon Knight
Shatterday	Harlan Ellison
Shattered Like a Glass Goblin	Harlan Ellison
She's a Young Thing and Cannot Leaver Her Mother	Harlan Ellison
Shin Megami Tensei 4: Official Artworks	Masayuki Doi
Shoppe Keeper	Harlan Ellison
Silence	Tadeusz Borowski
Silent in Gehenna	Harlan Ellison
Silhouette	Gene Wolfe
Simulacrum	Ken Liu
Sir Gawain and the Green Knight	J. R. R. Tolkien
Skeleton	Ray Bradbury
Skunk Works	Ben R. Rich
Skunk Works	Leo Janos
Sky Lift	Robert A. Heinlein
Slippage	Harlan Ellison
Slow Sculpture	Theodore Sturgeon
Snow	John Crowley
So Long, and Thanks for All the Fish	Douglas Adams
Soft Monkey	Harlan Ellison
Solanin	Inio Asano
Solaris	Stanislaw Lem
Some Assembly Required	Timothy S. Margush
Somehow, I Don't Think We're in Kansas, Toto	Harlan Ellison
Somerset Dreams	Kate Wilhelm
Somerset Dreams and Other Fictions	Kate Wilhelm
Souls	Joanna Russ
Soundless Evening	Lee Hoffman
Speech Sound	Octavia E. Butler
Spook Country	William Gibson
Stable Strategies for Middle Management	Eileen Gunn
Stalingrad	Antony Beevor
Stalking the Nightmare	Harlan Ellison
Stand Still and Die	Harlan Ellison
Starship Troopers	Robert A. Heinlein
State Change	Ken Liu
State of Grace	Kate Wilhelm
Still-Life	K. M. O'Donnell
Stillwell and the American Experience in China 1911-1945	Barbara W. Tuchman
Stoned Counsel	H. H. Hollis
Stories of Your Life and Others	Ted Chiang
Story of the Warrior and the Captive Maiden	Jorge Luis Borges
Story of Your Life	Ted Chiang
Strange Gifts	Robert Silverberg
Strange Wine	Harlan Ellison
Stranger in a Strange Land	Robert A. Heinlein
Stuffing	Harlan Ellison
Sturgeon is Alive and Well...	Theodore Sturgeon
Suicide	Theodore Sturgeon
Sun of China	Liu Cixin
Symbiosis	Kate Wilhelm
Take Care of Joey	Theodore Sturgeon
Taking Care of God	Liu Cixin
Tandy's Story	Theodore Sturgeon
Tauf Aleph	Physillis Gotlieb
Team of Rivals	Doris Kearns Goodwin
Tekkonkinkreet: Black and White	Taiyo Matsumoto
Tell Your Fortune	Robert Bloch
Test to Destruction	Keith Laummer
That Girl Who Knew What They Meant	Theodore Sturgeon
The [Widget], the [Wadget], and Boff	Theodore Sturgeon
The 10:00 Report is Brought to You By...	Edward Bryant
The 3 Most Important Things in Life	Harlan Ellison
The Absolutely Perfect Murder	Miram Allen deFord
The Adventure of Black Peter	Arthur Conan Doyle
The Adventure of Charles Augustus Milverton	Arthur Conan Doyle
The Adventure of the Gloria Scott	Arthur Conan Doyle
The Adventure of the Abbey Grange	Arthur Conan Doyle
The Adventure of the Beryl Coronet	Arthur Conan Doyle
The Adventure of the Blue Carbuncle	Arthur Conan Doyle
The Adventure of the Cardboard Box	Arthur Conan Doyle
The Adventure of the Copper Beeches	Arthur Conan Doyle
The Adventure of the Crooked Man	Arthur Conan Doyle
The Adventure of the Dancing Men	Arthur Conan Doyle
The Adventure of the Empty House	Arthur Conan Doyle
The Adventure of the Engineer's Thumb	Arthur Conan Doyle
The Adventure of the Final Problem	Arthur Conan Doyle
The Adventure of the Golden Pince-Nez	Arthur Conan Doyle
The Adventure of the Greek Interpreter	Arthur Conan Doyle
The Adventure of the Missing Three-Quarter	Arthur Conan Doyle
The Adventure of the Musgrave Ritual	Arthur Conan Doyle
The Adventure of the Naval Treaty	Arthur Conan Doyle
The Adventure of the Noble Bachelor	Arthur Conan Doyle
The Adventure of the Norwood Builder	Arthur Conan Doyle
The Adventure of the Priory School	Arthur Conan Doyle
The Adventure of the Reigate Squires	Arthur Conan Doyle
The Adventure of the Resident Patient	Arthur Conan Doyle
The Adventure of the Second Stain	Arthur Conan Doyle
The Adventure of the Silver Blaze	Arthur Conan Doyle
The Adventure of the Six Napoleons	Arthur Conan Doyle
The Adventure of the Solitary Cyclist	Arthur Conan Doyle
The Adventure of the Speckled Band	Arthur Conan Doyle
The Adventure of the Stockbroker's Clerk	Arthur Conan Doyle
The Adventure of the Yellow Face	Arthur Conan Doyle
The Age of Gold	Frederik Pohl
The Ajeri Diary	Miram Allen deFord
The Aleph	Jorge Luis Borges
The Aleph and Other Stories	Jorge Luis Borges
The Annals of the Heechee	Frederik Pohl
The Approach to Al-Mu'tasim	Jorge Luis Borges
The Argentine Writer and Tradition	Jorge Luis Borges
The Art of Computer Programming vol.1	Donald E. Knuth
The Art of Nausicaa of the Valley of the Wind	Hayao Miyazaki
The Art of Persona 5	Shigenori Soejima
The Art of Space	Ron Miller
The Avenger of Death	Harlan Ellison
The Babylon Lottery	Jorge Luis Borges
The Beast of Barsac	Robert Bloch
The Belonging Kind	John Shirley
The Belonging Kind	William Gibson
The Big Hunger	Walter M. Miller, Jr.
The Big Space Fuck	Kurt Vonnegut, Jr.
The Big Time	Fritz Leiber
The Black Cloud	Fred Hoyle
The Bob Dylan Tambourine Software & Satori Support Services Consortium, Ltd.	Michael Bishop
The Book of Skulls	Robert Silverberg
The Bookmaking Habits of Select Species	Ken Liu
The Boscombe Valley Mystery	Arthur Conan Doyle
The Boulevard of Broken Dreams	Harlan Ellison
The Boy Who Would Live Forever	Frederik Pohl
The Brains of Rats	Michael Blumlein
The Byrds	Michael G. Coney
The Captive	Jorge Luis Borges
The Cat Who Walks Through Walls	Robert A. Heinlein
The Catcher in the Rye	J. D. Salinger
The Cheese Stands Alone	Harlan Ellison
The Children	Miram Allen deFord
The Chrysalids	John Wyndham
The Circle	Liu Cixin
The Circular Ruins	Jorge Luis Borges
The Cistern	Ray Bradbury
The City of Silence	Ma Boyong
The Classic Horror Stories	H. P. Lovecraft
The Crackpots	Harlan Ellison
The Crowd	Ray Bradbury
The Dark Design	Philip Jose Farmer
The Dark Forest	Liu Cixin
The Daughter of the Tree	Miram Allen deFord
The Day After the Day the Martians Came	Frederik Pohl
The Day I Died	Harlan Ellison
The Day of the Triffids	John Wyndham
The Dead Man	Jorge Luis Borges
The Death of Schillinger	Tadeusz Borowski
The Deathbird	Harlan Ellison
The Demolished Man	Alfred Bester
The Diagnosis of Dr. Darqueangel	Harlan Ellison
The Difference Engine	Bruce Sterling
The Difference Engine	William Gibson
The Discarded	Harlan Ellison
The Dispossessed	Ursula K. Le Guin
The Divine Invasion	Philip K. Dick
The Doll-House	James Cross
The Dragon on the Bookshelf	Harlan Ellison
The Dragon on the Bookshelf	Robert Silverberg
The Dreaming Jewels	Theodore Sturgeon
The Dreams a Nightmare Dreams	Harlan Ellison
The Dune Encyclopedia	Dr. Willis E. McNelly
The Dwarf	Ray Bradbury
The Earth Men	Ray Bradbury
The Electric Kool-Aid Acid Test	Tom Wolfe
The Emissary	Ray Bradbury
The Encounter	Kate Wilhelm
The End	Jorge Luis Borges
The Evitable Conflict	Isaac Asimov
The Evolution of Human Science	Ted Chiang
The Executioner of the Malformed Children	Harlan Ellison
The Extraordinary Voyages of Amelie Bertrand	Joanna Russ
The Eyes of Heisenberg	Frank Herbert
The Face of Helene Bournouw	Harlan Ellison
The Fall of Hyperion	Dan Simmons
The Fearful Sphere of Pascal	Jorge Luis Borges
The Fellowship of the Ring	J. R. R. Tolkien
The Few, the Proud	Harlan Ellison
The Fish of Lijiang	Chen Qiufan
The Five Orange Pips	Arthur Conan Doyle
The Flower of Shazui	Chen Qiufan
The Forces that Crush	Harlan Ellison
The Forever War	Joe Haldeman
The Form of the Sword	Jorge Luis Borges
The Fountains of Paradise	Arthur C. Clarke
The Function of Dream Sleep	Harlan Ellison
The Funeral	Kate Wilhelm
The Fusion Bomb	Kate Wilhelm
The Garden of Forking Paths	Jorge Luis Borges
The Gateway Asteroid	Frederik Pohl
The Gateway Trip	Frederik Pohl
The Gernsback Continum	William Gibson
The Girl From Mars	Robert Bloch
The Goddess in the Ice	Harlan Ellison
The Godmakers	Frank Herbert
The Gods Lie.	Kaori Ozaki
The God's Script	Jorge Luis Borges
The Gods Themselves	Isaac Asimov
The Golden Helix	Theodore Sturgeon
The Golden Man	Philip K. Dick
The Great Gatsby	F. Scott Fitzgerald
The Green Morning	Ray Bradbury
The Guns of August	Barbara W. Tuchman
The Handler	Damon Knight
The Happy Breed	John T. Sladek
The Heart of the Other Side	George Gamow
The Henry Miller Dawn Patrol	Philip Jose Farmer
The Hitchhiker's Guide to the Galaxy	Douglas Adams
The Hobbit	J. R. R. Tolkien
The Home Planet	Frederik Pohl
The Hounds	Kate Wilhelm
The Hour That Stretches	Harlan Ellison
The House of Asterion	Jorge Luis Borges
The House the Blakeneys Built	Avram Davidson
The Immortal	Jorge Luis Borges
The Incredible Voyage	Tristan Jones
The Indian Spirit Guide	Robert Bloch
The Infinity Box	Kate Wilhelm
The Invasion	Robert Willey
The January Offensive	Tadeusz Borowski
The Jar	Ray Bradbury
The Jigsaw Man	Larry Niven
The Jungle Rot Kid on the Nod	Philip Jose Farmer
The Korean War	Max Hastings
The Lake	Ray Bradbury
The Lake Was Full of Artificial Things	Karen Joy Fowler
The Last Days of the Captain	Kate Wilhelm
The Last Generation?	Miram Allen deFord
The Lathe of Heaven	Ursula K. Le Guin
The Leaser of Two Evils	Philip Jose Farmer
The Library of Babel	Jorge Luis Borges
The Life of Anybody	Robert Sheckley
The Lingering Scent of Woodsmoke	Harlan Ellison
The Literomancer	Ken Liu
The Litigation Master and the Monkey King	Ken Liu
The Living Demons	Robert Bloch
The Locusts	Ray Bradbury
The Long Dark Tea-Time of the Soul	Douglas Adams
The Long Space Age	Alexander MacDonald
The Long Years	Ray Bradbury
The Longest Fall	Liu Cixin
The Lost World	Michael Crichton
The Lottery in Babylon	Jorge Luis Borges
The Lucky Strike	Kim Stanley Robinson
The Luggage Store	Ray Bradbury
The Maker	Jorge Luis Borges
The Malley System	Miriam Allen deFord
The Man in the High Castle	Philip K. Dick
The Man on the Threshold	Jorge Luis Borges
The Man Upstairs	Ray Bradbury
The Man Who Ended History: A Documentary	Ken Liu
The Man Who Lost the Sea	Theodore Sturgeon
The Man Who Rowed Christopher Columbus Ashore	Harlan Ellison
The Man Who Sold the Moon	Robert A. Heinlein
The Man Who Was Heavily into Revenge	Harlan Ellison
The Man Who Went to the Moon-Twice	Howard Rodman
The Man With English	Horace L. Gold
The Man with the Package	Tadeusz Borowski
The Man With the Twisted Lips	Arthur Conan Doyle
The Man without a Planet	Kate Wilhelm
The Manhattan Project	Al Cimino
The March of Folly	Barbara W. Tuchman
The Mark Gable Foundation	Leo Szilard
The Martian	Ray Bradbury
The Martian Chronicles	Ray Bradbury
The Menace from Earth	Robert A. Heinlein
The Merchants of Venus	Frederik Pohl
The Micro-Age	Liu Cixin
The Mile-Long Spaceship	Kate Wilhelm
The Milk of Paradise	James Tiptree, Jr.
The Million-Year Picnic	Ray Bradbury
The Miracle of the Broom Closet	W. Norbert
The Mirrors of Enigmas	Jorge Luis Borges
The Moon is a Harsh Mistress	Robert A. Heinlein
The Mountains of Sunset, the Mountains of Dawn	Vonda N. McIntyre
The Mountebank	Jorge Luis Borges
The Museum on Cyclops Avenue	Harlan Ellison
The Musicians	Ray Bradbury
The Naming of Names	Ray Bradbury
The New Atlantis	Robert Silverberg
The New Atlantis	Ursula K. Le Guin
The New York Review of Bird	Harlan Ellison
The Next in Line	Ray Bradbury
The Night That All Time Broke Out	Brian W. Aldiss
The Norton Book of Science Fiction	Brian Attebery
The Norton Book of Science Fiction	Ursula K. Le Guin
The October Country	Ray Bradbury
The Off Season	Ray Bradbury
The Old Man and the Sea	Ernest Hemingway
The Old Ones	Ray Bradbury
The Oldest Soldier	Fritz Leiber
The Original Hitchhiker Radio Scripts	Douglas Adams
The Original Illustrated Sherlock Holmes	Arthur Conan Doyle
The Other Death	Jorge Luis Borges
The Other Eye of Polyphemus	Harlan Ellison
The Outcast of Redwall	Brian Jacques
The Outpost Undiscovered by Tourists	Harlan Ellison
The Oxford Book of English Verse	Christopher Ricks
The Pale Silver Dollar of the Moon Pays Its Way and Makes Change vr.1	Harlan Ellison
The Pale Silver Dollar of the Moon Pays Its Way and Makes Change vr.2	Harlan Ellison
The Paper Menagerie	Ken Liu
The Patterns of Drone	Theodore Sturgeon
The People Who Walked On	Tadeusz Borowski
The Perfect Match	Ken Liu
The Peripheral	William Gibson
The Phantom of the Sewers	Philip Jose Farmer
The Place with No Name	Harlan Ellison
The Plot	Jorge Luis Borges
The Plot Is the Thing	Robert Bloch
The Private War of Private Jacob	Joe Haldeman
The Problem of the Sore Bridge-Among Others	Philip Jose Farmer
The Proud Tower	Barbara W. Tuchman
The Prowler in the City on the Edge of Forever	Harlan Ellison
The Recognition	J. G. Ballard
The Red Canary	Kate Wilhelm
The Red-Headed League	Arthur Conan Doyle
The Region Between	Harlan Ellison
The Regular	Ken Liu
The Resurgence of Miss Ankle-Strap Wedgie	Harlan Ellison
The Return of the King	J. R. R. Tolkien
The Right Stuff	Tom Wolfe
The Rise of Endymion	Dan Simmons
The Road	Cormac McCarthy
The Roads Must Roll	Robert A. Heilein
The Salmon of Doubt	Douglas Adams
The Season of Babies	Miram Allen deFord
The Secret Miracle	Jorge Luis Borges
The Sect of Phoenix	Jorge Luis Borges
The Settlers	Ray Bradbury
The Sex Opposite	Theodore Sturgeon
The Shape of the Sword	Jorge Luis Borges
The Shore	Ray Bradbury
The Silent Towns	Ray Bradbury
The Silver Corridor	Harlan Ellison
The Simple Way	Clifford D. Simak
The Singers	W. Grey Walter
The Sirens of Titan	Kurt Vonnegut
The Skills of Xanadu	Theodore Sturgeon
The Sky is Burning	Harlan Ellison
The Small Assaassin	Ray Bradbury
The Smiling Future	Miram Allen deFord
The Sound and the Fury	William Faulkner
The South	Jorge Luis Borges
The Space Merchants	C. M. Kornbluth
The Space Merchants	Frederik Pohl
The Stars My Destination	Alfred Bester
The Starseekers	Frederik Pohl
The Start of the End of It All	Carol Emshwiller
The Stochastic Man	Robert Silverberg
The Summer Night	Ray Bradbury
The Sun also Rises	Ernest Hemingway
The Superior Sex	Miram Allen deFord
The Supper	Tadeusz Borowski
The Sycthe	Ray Bradbury
The Taxpayer	Ray Bradbury
The Tell-Tale Heart and Other Writings	Edgar Allan Poe
The Tempest	William Shakespeare
The Test Stand	Lee Corey
The Test-Tube Creature, Afterward	Joan Bernott
The Theologians	Jorge Luis Borges
The Third Ear	Curt Siodmak
The Third Expedition	Ray Bradbury
The Three Stigmata of Palmer Eldritch	Philip K. Dick
The Three-Body Problem	Liu Cixin
The Tides of the Mind	David Gelernter
The Time Piece	Kate Wilhelm
The Transit of Venus	Miram Allen deFord
The Transmigration of Timothy Archer	Philip K. Dick
The Tree Lord of Imeten	Tom Purdom
The Trial	Franz Kafka
The Two Kings and the Two Labyrinths	Jorge Luis Borges
The Two Towers	J. R. R. Tolkien
The Ultimate Hitchhiker's Guide	Douglas Adams
The Universe of Robert Blake	Harlan Ellison
The Unspeakable Betrothal	Robert Bloch
The Very Last Day of a Good Woman	Harlan Ellison
The View from the Stars	Walter M. Miller, Jr.
The Village	Kate Wilhelm
The Visit	Frederik Pohl
The Voice of the Sonar in My Veriform Appendix	Philip Jose Farmer
The Volcano	Philip Jose Farmer
The Wages of Humanity	Liu Cixin
The Waiting	Jorge Luis Borges
The Wall and the Books	Jorge Luis Borges
The Wandering Earth	Liu Cixin
The War at Home	Lewis Shiner
The Warlord of Saturn's Moon	Eleanor Aranason
The Watchers	Ray Bradbury
The Watchful Poker Chip of H. Matisse	Ray Bradbury
The Waves	Ken Liu
The Westing Game	Ellen Raskin
The Whimper of Whipped Dogs	Harlan Ellison
The Will	Walter M. Miller, Jr.
The Wind	Ray Bradbury
The Wind Beyond the Mountains	Harlan Ellison
The Windup Girl	Paolo Bacigalupi
The Wine Has Been Left Open Too Long and the Memory Has Gone Flat	Harlan Ellison
The Winter Flies	Fritz Leiber
The Winter Market	William Gibson
The Witness	Jorge Luis Borges
The Women Men Don't See	James Tiptree, Jr.
The Wonderful Death of Dudley Stone	Ray Bradbury
The Word for World is Forrest	Ursula K. Le Guin
The World Inside	Robert Silverberg
The World of Professor Layton	Jun Suzuki
The World of Stone	Tadeusz Borowski
The Writing of the God	Jorge Luis Borges
The Year of the Jackpot	Robert A. Heinlein
The Year of the Rat	Chen Qiufan
The Yellow Rose	Jorge Luis Borges
The Zahir	Jorge Luis Borges
The Zimmermann Telegram	Barbara W. Tuchman
Theme of the Traitor and Hero	Jorge Luis Borges
There Was an Old Woman	Ray Bradbury
There Will Come Soft Rains	Ray Bradbury
They Shall Have Stars	James Blish
Things Lost	Thomas M. Disch
This Immortal	Roger Zelazny
This Way for the Gas, Ladies and Gentlemen	Tadeusz Borowski
Thorns	Robert Silverberg
Thousand Cranes	Yasunari Kawabata
Three Versions of Judas	Jorge Luis Borges
Throwback	Miram Allen deFord
Thunder and Roses	Theodore Sturgeon
Time Travel for Pedestrians	Ray Nelson
Tiny Ally	Harlan Ellison
Tissue	James Sallis
Tlon, Uqbar, Orbis Teritus	Jorge Luis Borges
To Be Continued	Robert Silverberg
To Explain to Mrs. Thompson	Phillip Latham
To Here and the Easel	Theodore Sturgeon
To Kill a Mockingbird	Harper Lee
To Open the Sky	Robert Silverberg
Toenails	Jorge Luis Borges
Tongtong's Summer	Xia Jia
Totenbuch	A. Parra (y Figuerado)
Touched With Fire	Ray Bradbury
Tower of Babylon	Ted Chiang
Tower of Glass	Robert Silverberg
Tracking Level	Harlan Ellison
Transcending Destiny	Harlan Ellison
Treasure Island	Robert Lewis Stevenson
Trigun Omnibus	Yasuhiro Nightow
Triss	Brian Jacques
Trouble With Ants	Clifford D. Simak
Try and Change the Past	Fritz Leiber
Twink	Theodore Sturgeon
Ubik	Philip K. Dick
Unaccompanied Sonata	Orson Scott Card
Uncle Einar	Ray Bradbury
Uncle Fremmis	Theodore Sturgeon
Underground	Robert Bloch
Understand	Ted Chiang
Unlocking the Air	Ursula K. Le Guin
Usher II	Ray Bradbury
Valerie	Harlan Ellison
Valery as Symbol	Jorge Luis Borges
VALIS	Philip K. Dick
Vaster than Empires and More Slow	Ursula K. Le Guin
Venus Plus X	Theodore Sturgeon
Vietnam: An Epic Tragedy, 1945-1975	Max Hastings
Virtual Light	William Gibson
Visionary	Harlan Ellison
Walden; or, Life in the Woods	Henry David Thoreau
Wandering Island vol.1	Kenji Tsuruta
Wandering Island vol.2	Kenji Tsuruta
Wanted in Surgery	Harlan Ellison
Watchmen	Alan Moore
Water Is for Washing	Robert A. Heinlein
Watership Down	Richard Adams
Way in the Middle of the Air	Ray Bradbury
Way Station	Clifford D. Simak
We	Yevgeny Zamyatin
We See Things Differently	Bruce Sterling
Web of the City	Harlan Ellison
What Happened to Auguste Clarot?	Larry Eisenberg
What I Did on My Vaction This Summer by Little Bobby Hirschhorn, Age 27	Harlan Ellison
What's It Like Out There?	Edmond Hamilton
When Auld's Acquaintance is Forgot	Harlan Ellison
When I was a Hired Gun	Harlan Ellison
When I Was Miss Dow	Sonya Dorman
When it Changed	Joanna Russ
When the Bentfin Boomer Boys on Old New Alabama	Richard A. Lupoff
When the Change-Winds Blow	Fritz Leiber
Where Have You Been, Billy Boy, Billy Boy?	Kate Wilhelm
Where I Shall Dwell in the Next World	Harlan Ellison
Where Late the Sweet Birds Sang	Kate Wilhelm
With a Finger in My I	David Gerrold
With Her Eyes	Liu Cixin
With Virgin Oddum at the East Pole	Harlan Ellison
Working with the Little People	Harlan Ellison
Would You Do It for a Penny	Harlan Ellison
Xenogenesis	Miriam Allen deFord
Yeager	Chuck Yeager
Yeager	Leo Janos
Ylla	Ray Bradbury
You Triflin' Skunk	Walter M. Miller, Jr.
Zero Gee	Ben Bova
Zero History	William Gibson

================================================
FILE: tests/data/books.tsv
================================================
1984	science fiction	1950	328
2001: A Space Odyssey	science fiction	1968	221
20th Century Boys vol.1	science fiction	2018	413
20th Century Boys vol.2	science fiction	2018	412
20th Century Boys vol.3	science fiction	2019	410
20th Century Boys vol.4	science fiction	2019	416
20th Century Boys vol.5	science fiction	2019	422
20th Century Boys vol.6	science fiction	2019	456
A Canticle for Leibowitz	science fiction	1959	338
A Case of Conscience	science fiction	1958	188
A Clash of Cymbals	science fiction	1959	199
A Clockwork Orange	science fiction	1962	139
A Farewell to Arms	american lit	1929	332
A Life for the Stars	science fiction	1962	147
A Scanner Darkly	science fiction	1977	217
A Time of Changes	science fiction	1975	205
A Tour of C++ 2nd	textbook	2018	238
Absalom, Absalom!	american lit	1936	303
Again, Dangerous Visions	science fiction	1972	830
Akira vol.1	science fiction	2010	363
Akira vol.2	science fiction	2010	301
Akira vol.3	science fiction	2010	282
Akira vol.4	science fiction	2010	394
Akira vol.5	science fiction	2011	413
Akira vol.6	science fiction	2011	434
Algorithms 4th	textbook	2011	959
All Tomorrow's Parties	science fiction	1999	339
And Chaos Died	science fiction	1970	189
Angry Candy	science fiction	1988	324
Animal Farm	british lit	1956	139
Approaching Oblivion	science fiction	1974	164
Army of None	history	2018	436
Battle for the Mind	informative	1954	350
Beowulf	fantasy	1994	92
Beyond the Blue Event Horizon	science fiction	1980	309
Bible and Sword	history	1984	346
Blame! vol.1	science fiction	2016	348
Blame! vol.2	science fiction	2016	374
Blame! vol.3	science fiction	2017	352
Blame! vol.4	science fiction	2017	367
Blame! vol.5	science fiction	2017	334
Blame! vol.6	science fiction	2017	326
Blue Spring	fiction	2004	213
Brain Wave	science fiction	1954	166
Brave New World	science fiction	1932	259
Burning Chrome	science fiction	1986	191
C Primer Plus 5th	textbook	2005	959
C++ Primer 5th	textbook	2013	938
Capitalism Without Capital	economics	2018	278
Captain Harlock: The Classic Collection vol.1	science fiction	2018	396
Captain Harlock: The Classic Collection vol.2	science fiction	2018	397
Captain Harlock: The Classic Collection vol.3	science fiction	2019	392
Catch-22	american lit	1955	453
Caviar	science fiction	1955	182
Changewar	science fiction	1983	198
Chapterhouse: Dune	science fiction	1985	436
Childhood's End	science fiction	1953	212
Children of Dune	science fiction	1976	408
Children of the Sea vol.1	fiction	2013	316
Children of the Sea vol.2	fiction	2013	315
Children of the Sea vol.3	fiction	2013	334
Children of the Sea vol.4	fiction	2013	324
Children of the Sea vol.5	fiction	2013	329
City	science fiction	1952	267
Colossus	history	2006	462
Conversations With Jorge Luis Borges	interviews	1968	144
Count Zero	science fiction	1986	246
Crome Yellow	british lit	1921	174
Dandelion Wine	american lit	1957	239
Dangerous Visions	science fiction	1967	598
Death and the Penguin	mystery	1996	228
Deathbird Stories	science fiction	1975	347
Death's End	science fiction	2016	604
Destined for War	history	2017	364
Dirk Gently's Holistic Detective Agency	science fiction	1987	306
Distrust That Particular Flavor	essays	2012	255
Do Androids Dream of Electric Sheep?	science fiction	1968	244
Doctor Zhivago	east euro lit	1957	456
Don Quixote	adventure	1950	940
Double Star	science fiction	1956	243
Downward to the Earth	science fiction	1970	181
Dr. Bloodmoney	science fiction	1965	298
Dune	science fiction	1965	883
Dune Messiah	science fiction	1969	279
Dying Inside	science fiction	1972	200
Earthman, Come Home	science fiction	1955	256
Earthman, Go Home!	science fiction	1962	191
Emanon vol.1: Memories of Emanon	science fiction	2019	190
Emanon vol.2: Emanon Wanderer pt.1	science fiction	2019	213
Emanon vol.3: Emanon Wanderer pt.2	science fiction	2019	233
Empire Star	science fiction	1966	102
Ender's Game	science fiction	1977	324
Endless Frontier	history	1997	527
Endymion	science fiction	1995	563
Eniac	history	1999	262
Explorers of Space	science fiction	1975	253
Fahrenheit 451	science fiction	1953	190
Fault-Tolerant Computer System Designs	textbook	1996	550
Fiasco	science fiction	1987	322
Ficciones	fiction	1956	174
Flow My Tears, the Policeman Said	science fiction	1974	231
Flowers for Algernon	science fiction	1966	216
For Whom the Bell Tolls	american lit	1940	507
Forward the Foundation	science fiction	1993	435
Foundation	science fiction	1951	296
Foundation and Earth	science fiction	1986	494
Foundation and Empire	science fiction	1952	282
Foundation's Edge	science fiction	1982	426
Gateway	science fiction	1977	313
Ghost in the Shell	science fiction	2009	348
Ghost in the Shell vol.2: Man-Machine Interface	science fiction	2010	306
Ghost in the Shell vol.1.5: Human-Error Processor	science fiction	2007	176
Giganto Maxia	fantasy	2016	232
God Emperor of Dune	science fiction	1981	423
Hamlet	tragedy	1599	287
Hawksbill Station	science fiction	1968	185
Heart of Darkness	east euro lit	1899	166
Heechee Rendezvous	science fiction	1984	331
Heretics of Dune	science fiction	1984	480
Houston, Houston, Do You Read?	science fiction	1976	92
Hyperion	science fiction	1989	482
I Will Fear No Evil	science fiction	1970	512
I, Robot	science fiction	1950	192
Ichi-F	nonfiction	2017	550
Idoru	science fiction	1996	383
Inferno: The World at War, 1939-1945	informative	2012	729
Into the Wild	nonfiction	1996	207
Into Thin Air	nonfiction	1997	404
Invisible Man	american lit	1952	581
Invisible Planets	science fiction	2016	393
Julius Caesar	tragedy	1599	209
Jurassic Park	science fiction	1990	399
Labyrinths	fiction	2007	256
Leadership in Turbulent Times	history	2018	473
Life, the Universe and Everything	science fiction	1982	162
Lord of Light	science fiction	1967	296
Lord of the Flies	british lit	1954	208
Love Ain't Nothing but Sex Misspelled	science fiction	1968	380
Madame Curie	history	1939	390
Man Plus	science fiction	1976	277
Martin the Warrior	fantasy	1994	376
Master and Commander	adventure	1970	408
Mattimeo	fantasy	1990	432
Mona Lisa Overdrive	science fiction	1988	308
Monster vol.1	thriller	2014	422
Monster vol.2	thriller	2014	398
Monster vol.3	thriller	2015	430
Monster vol.4	thriller	2015	412
Monster vol.5	thriller	2015	404
Monster vol.6	thriller	2015	400
Monster vol.7	thriller	2016	410
Monster vol.8	thriller	2016	424
Monster vol.9	thriller	2016	470
More Than Human	science fiction	1953	188
Nausicaa of the Valley of the Wind vol.1	fantasy	2012	548
Nausicaa of the Valley of the Wind vol.2	fantasy	2012	533
Nebula Winners Fifteen	science fiction	1981	223
Neuromancer	science fiction	1984	271
Nightfall	science fiction	1990	339
Nijigagara Holograph	fiction	2015	200
Nova	science fiction	1968	215
One Day in the Life of Ivan Denisovich	east euro lit	1962	210
Operating Systems in Depth	textbook	2011	444
Overlord	history	1984	462
Paingod and Other Delusions	science fiction	1965	157
Pattern Recognition	science fiction	2003	356
Permanent Record	history	2019	340
Persona 3: Official Design Works	art	2006	141
Persona 4 Arena: Official Design Works	art	2012	176
Persona 4: Official Design Works	art	2008	191
Picnic on Paradise	science fiction	1968	157
Planetes vol.1	science fiction	2015	524
Planetes vol.2	science fiction	2016	524
Player Piano	science fiction	1952	320
Prelude to Foundation	science fiction	1988	434
Presidents of War	history	2018	740
Queen Emeraldas vol.1	science fiction	2016	415
Queen Emeraldas vol.2	science fiction	2017	423
Radio Free Albemuth	science fiction	1985	214
Redwall	fantasy	1986	333
Rendezvous with Rama	science fiction	1973	243
Riders of the Purple Wage	science fiction	1992	216
Ringworld	science fiction	1970	288
Riverworld and Other Stories	science fiction	1979	264
Roadside Picnic	science fiction	1972	209
Second Foundation	science fiction	1953	279
Selected Poems	american lit	1954	114
Selected Stories	science fiction	2000	439
Seraphim: 266613336 Wings	science fiction	2015	268
Shatterday	science fiction	1980	332
Shin Megami Tensei 4: Official Artworks	art	2013	208
Sir Gawain and the Green Knight	fantasy	1975	212
Skunk Works	history	1994	372
Slippage	science fiction	1997	359
So Long, and Thanks for All the Fish	science fiction	1984	214
Solanin	fiction	2008	432
Solaris	science fiction	1961	223
Some Assembly Required	informative	2012	611
Somerset Dreams and Other Fictions	science fiction	1979	174
Souls	fantasy	1982	84
Spook Country	science fiction	2007	480
Stalingrad	history	1998	493
Stalking the Nightmare	science fiction	1982	301
Starship Troopers	science fiction	1959	335
Stillwell and the American Experience in China 1911-1945	history	1971	794
Stories of Your Life and Others	science fiction	2002	281
Strange Gifts	science fiction	1975	191
Strange Wine	science fiction	1979	316
Stranger in a Strange Land	science fiction	1961	438
Sturgeon is Alive and Well...	science fiction	1971	207
Team of Rivals	history	2005	757
Tekkonkinkreet: Black and White	fiction	2007	614
The Aleph and Other Stories	fiction	1998	210
The Annals of the Heechee	science fiction	1987	341
The Art of Computer Programming vol.1	textbook	1997	652
The Art of Nausicaa of the Valley of the Wind	art	2007	207
The Art of Persona 5	art	2017	447
The Art of Space	art	2014	224
The Big Time	science fiction	1958	184
The Book of Skulls	science fiction	1972	222
The Boy Who Would Live Forever	science fiction	2004	452
The Cat Who Walks Through Walls	science fiction	1985	388
The Catcher in the Rye	american lit	1945	214
The Chrysalids	science fiction	1955	200
The Classic Horror Stories	horror	2013	487
The Dark Forest	science fiction	2015	512
The Day of the Triffids	science fiction	1951	191
The Demolished Man	science fiction	1954	175
The Difference Engine	science fiction	1991	429
The Dispossessed	science fiction	1974	311
The Divine Invasion	science fiction	1981	260
The Dreaming Jewels	science fiction	1950	174
The Dune Encyclopedia	encyclopedia	1985	526
The Electric Kool-Aid Acid Test	informative	1968	416
The Expert Dreamers	science fiction	1962	248
The Eyes of Heisenberg	science fiction	1966	158
The Fall of Hyperion	science fiction	1990	518
The Fellowship of the Ring	fantasy	1954	458
The Forever War	science fiction	1974	254
The Fountains of Paradise	science fiction	1980	305
The Gateway Trip	science fiction	1990	245
The Godmakers	science fiction	1972	221
The Gods Lie.	fiction	2016	216
The Gods Themselves	science fiction	1972	288
The Great Gatsby	american lit	1952	180
The Guns of August	history	1962	606
The Hitchhiker's Guide to the Galaxy	science fiction	1979	215
The Hobbit	fantasy	1937	305
The Incredible Voyage	nonfiction	1977	390
The Infinity Box	science fiction	1975	272
The Korean War	history	1987	389
The Lathe of Heaven	science fiction	1971	175
The Living Demons	horror	1967	156
The Long Dark Tea-Time of the Soul	science fiction	1988	307
The Long Space Age	history	2017	258
The Lost World	science fiction	1995	430
The Man in the High Castle	science fiction	1962	259
The Man Who Sold the Moon	science fiction	1951	267
The Manhattan Project	history	2016	187
The March of Folly	history	1984	447
The Martian Chronicles	science fiction	1950	181
The Menace from Earth	science fiction	1962	189
The Mile-Long Spaceship	science fiction	1963	160
The Moon is a Harsh Mistress	science fiction	1966	382
The New Atlantis	science fiction	1975	182
The Norton Book of Science Fiction	science fiction	1993	861
The October Country	science fiction	1956	306
The Old Man and the Sea	american lit	1952	127
The Original Hitchhiker Radio Scripts	science fiction	1985	248
The Original Illustrated Sherlock Holmes	mystery	1976	636
The Outcast of Redwall	fantasy	1995	367
The Oxford Book of English Verse	british lit	1999	668
The Paper Menagerie	science fiction	2016	450
The Peripheral	science fiction	2014	486
The Proud Tower	history	1966	615
The Return of the King	fantasy	1955	466
The Right Stuff	nonfiction	1970	352
The Rise of Endymion	science fiction	1997	709
The Road	thriller	2006	287
The Salmon of Doubt	fiction	2002	299
The Sirens of Titan	science fiction	1959	224
The Sound and the Fury	american lit	1929	326
The Space Merchants	science fiction	1953	216
The Stars My Destination	science fiction	1956	234
The Stochastic Man	science fiction	1976	240
The Sun also Rises	american lit	1926	251
The Tell-Tale Heart and Other Writings	horror	1982	419
The Tempest	tragedy	1599	177
The Third Ear	science fiction	1971	254
The Three Stigmata of Palmer Eldritch	science fiction	1964	230
The Three-Body Problem	science fiction	2014	399
The Tides of the Mind	nonfiction	2016	267
The Transmigration of Timothy Archer	science fiction	1991	255
The Tree Lord of Imeten	science fiction	1966	152
The Trial	east euro lit	1925	271
The Two Towers	fantasy	1954	398
The Ultimate Hitchhiker's Guide	science fiction	2005	815
The View from the Stars	science fiction	1965	192
The Wandering Earth	science fiction	2013	478
The Westing Game	mystery	1978	182
The Windup Girl	science fiction	2015	466
The World Inside	science fiction	1970	167
The World of Professor Layton	art	2015	191
The Zimmermann Telegram	history	1966	225
They Shall Have Stars	science fiction	1956	181
This Immortal	science fiction	1966	184
This Way for the Gas, Ladies and Gentlemen	east euro lit	1959	180
Thorns	science fiction	1967	222
Thousand Cranes	asian lit	1965	144
To Kill a Mockingbird	american lit	1960	376
To Open the Sky	science fiction	1967	222
Tower of Glass	science fiction	1971	184
Treasure Island	adventure	1882	202
Trigun Omnibus	science fiction	2013	691
Triss	fantasy	2002	389
Ubik	science fiction	1969	216
VALIS	science fiction	1991	241
Venus Plus X	science fiction	1960	160
Vietnam: An Epic Tragedy, 1945-1975	history	2018	857
Virtual Light	science fiction	1993	352
Walden; or, Life in the Woods	essays	1854	216
Wandering Island vol.1	fiction	2016	198
Wandering Island vol.2	fiction	2018	190
Watchmen	science fiction	1986	414
Watership Down	fantasy	1973	478
Way Station	science fiction	1963	190
We	science fiction	1924	226
Web of the City	thriller	1958	284
What's It Like Out There?	science fiction	1974	320
Where Late the Sweet Birds Sang	science fiction	1976	207
Xenogenesis	science fiction	1969	231
Yeager	history	1985	331
Zero History	science fiction	2010	529

================================================
FILE: tests/data/collected.tsv
================================================
!!!The!!Teddy!Crazy!!Show!!!	Stalking the Nightmare	14
(Learning About) Machine Sex	The Norton Book of Science Fiction	16
...the World, as we Know 't	The Norton Book of Science Fiction	16
2004, or Thereabouts	The Norton Book of Science Fiction	5
A Biography of Tadeo Isidoro Cruz (1829-1874)	The Aleph and Other Stories	4
A Brief History of the Trans-Pacific Tunnel	The Paper Menagerie and Other Stories	19
A Case of Identity	The Original Illustrated Sherlock Holmes	12
A Day at Harmenz	This Way for the Gas, Ladies and Gentlemen	32
A Deskful of Girls	Changewar	44
A Dialog About A Dialog	The Aleph and Other Stories	1
A Dialog Between Dead Men	The Aleph and Other Stories	3
A Feast of Demons	The Expert Dreamers	26
A Few Things I Know About While Away	The Norton Book of Science Fiction	13
A Hundred Ghosts Parade Tonight	Invisible Planets	20
A is for Automation	The Mile-Long Spaceship	17
A Midwinter's Tale	The Norton Book of Science Fiction	13
A Momentary Taste of Being	The New Atlantis	174
A Mouse in the Walls of the Global Village	Again, Dangerous Visions	15
A New Refutation of Time	Labyrinths	20
A Note on (toward) Bernard Shaw	Labyrinths	4
A Path Through the Darkness	Love Ain't Nothing but Sex Misspelled	14
A Prayer for No One's Enemies	Love Ain't Nothing but Sex Misspelled	21
A Problem	Labyrinths	2
A Problem	The Aleph and Other Stories	2
A Scandal in Bohemia	The Original Illustrated Sherlock Holmes	15
A Toy for Juliette	Dangerous Visions	15
A True Story	This Way for the Gas, Ladies and Gentlemen	4
A Visit	This Way for the Gas, Ladies and Gentlemen	3
A Way of Thinking	Selected Stories	29
Adrift Just Off the Islets of Langerhans: Latitude 38o54'N, Longitude 77o00'13W	Deathbird Stories	40
Adrift on the Policy Level	The Expert Dreamers	24
Aesop	City	42
After the Days of Dead-Eye 'Dee	The Norton Book of Science Fiction	11
All in Good Time	Xenogensis	10
All the Birds Come Home to Roost	Shatterday	18
All the Flavors	The Paper Menagerie and Other Stories	89
All the Lies Lies That Are My Life	Shatterday	58
All The People	Strange Gifts	12
All the Sound of Fear	Earthman, Go Home!	12
Along the Scenic Route	Deathbird Stories	14
Alpha Ralpha Boulevard	The Norton Book of Science Fiction	25
Amateur in Chancery	The Expert Dreamers	18
America	The Norton Book of Science Fiction	24
An Advanced Readers' Picture Book of Comparative Cognition	The Paper Menagerie and Other Stories	15
An Examination of the Work of Herbert Quain	Ficciones	6
And the Angels Sing	The Norton Book of Science Fiction	17
And the Sea Like Mirrors	Again, Dangerous Visions	20
Andover and the Android	The Mile-Long Spaceship	13
Anybody Else Like Me?	The View from the Stars	17
Anywhere But Here, With Anybody But You	Slippage	8
April Fools' Day Forever	The Infinity Box	58
Argumentum Ornithologicum	The Aleph and Other Stories	1
As Simple As That	The Norton Book of Science Fiction	11
At the End of the Orbit	The Expert Dreamers	20
At the Mouse Circus	Deathbird Stories	10
Aunt Parnetta's Electric Blisters	The Norton Book of Science Fiction	5
Auschwitz, Our Home (A Letter)	This Way for the Gas, Ladies and Gentlemen	45
Auto-De-Fe	Dangerous Visions	10
Avatars of the Tortoise	Labyrinths	7
Averroes' Search	Labyrinths	8
Averroes' Search	The Aleph and Other Stories	10
Aye, and Gomorrah...	Dangerous Visions	14
Balanced Ecology	The Norton Book of Science Fiction	17
Basilisk	Deathbird Stories	22
Battle Without Banners	Love Ain't Nothing but Sex Misspelled	14
Battlefield	Earthman, Go Home!	12
Beachhead	Explorers of Space	25
Beauty's Beast	The Living Demons	17
Bed Sheets are White	Again, Dangerous Visions	8
Bettyann	Strange Gifts	44
Bianca's Hands	Selected Stories	9
Big Joe and the Nth Generation	The View from the Stars	19
Blabbermouth	Caviar	28
Black Bargain	The Living Demons	16
Blank?	Stalking the Nightmare	8
Bleeding Stones	Deathbird Stories	8
Blind Bird, Blind Bird, Go Away From Me!	Love Ain't Nothing but Sex Misspelled	22
Blood Bank	The View from the Stars	46
Blot	Again, Dangerous Visions	15
Blowups Happen	The Man Who Sold the Moon	54
Borges and I	Labyrinths	2
Borges and I	The Aleph and Other Stories	2
Bounty	Again, Dangerous Visions	7
Brass and Gold (or Horse and Zeppelin in Beverly Hills)	Riverworld and Other Stories	18
Bright Eyes	Paingod and Other Delusions	12
Bright Segment	Caviar	28
Bright Segment	Selected Stories	25
Broken Glass	Angry Candy	12
Brownshoes	Sturgeon is Alive and Well...	12
Burning Chrome	Burning Chrome	23
By His Bootstraps	The Menace from Earth	49
Call Girl	Invisible Planets	12
Camps	Nebula Winners Fifteen	29
Carcinoma Angels	Dangerous Visions	15
Catch That Rabbit	I, Robot	15
Catman	Approaching Oblivion	34
Census	City	35
Chain Reaction	The Expert Dreamers	16
Chained to the Fast Lane in the Red Queen's Race	Angry Candy	16
Chatting with Anubis	Slippage	8
Ching Witch!	Again, Dangerous Visions	24
Christ, Old Student in a New School	Again, Dangerous Visions	9
Chuck Berry, Won't You Please Come Home	Again, Dangerous Visions	12
City	City	34
Cold Friend	Approaching Oblivion	11
Collecting Team	Explorers of Space	18
Columbus Was a Dope	The Menace from Earth	4
Come to the Party	The Collected Stories of Frank Herbert	21
Comes Now the Power	The Norton Book of Science Fiction	5
Commuter's Problem	Earthman, Go Home!	22
Corpse	Deathbird Stories	12
Count the Clock That Tells the Time	Shatterday	22
Covered Mirrors	The Aleph and Other Stories	2
Crate	Sturgeon is Alive and Well...	14
Crazy as a Soup Sandwich	Slippage	48
Croatoan	Strange Wine	18
Crucifixus Etiam	The View from the Stars	18
Curse 5.0	The Wandering Earth	23
Damnation Morning	Changewar	19
Danger-Human!	Strange Gifts	21
Daniel White for the Greater Good	Love Ain't Nothing but Sex Misspelled	13
Darkness Upon the Face of the Deep	Slippage	16
Day Million	The Norton Book of Science Fiction	5
Deal From the Bottom	Earthman, Go Home!	7
Death and the Compass	Ficciones	14
Death and the Compass	Labyrinths	12
Deeper than the Darkness	Paingod and Other Delusions	20
Delia Elena San Marco	The Aleph and Other Stories	1
Delusion for a Dragon Slayer	Deathbird Stories	18
Deutsches Requiem	Labyrinths	7
Deutsches Requiem	The Aleph and Other Stories	7
Devourer	The Wandering Earth	46
Distant Signals	The Norton Book of Science Fiction	13
Division by Zero	Stories of Your Life and Others	20
Django	Shatterday	12
Djinn, No Chaser	Stalking the Nightmare	22
Dogfight	Burning Chrome	24
Do-It-Yourself	Earthman, Go Home!	14
Dreamtigers	The Aleph and Other Stories	1
Dumb Waiter	The View from the Stars	34
Each an Explorer	Explorers of Space	18
Ecowarewness	Approaching Oblivion	2
Eidolons	Angry Candy	18
Elbow Room	The Norton Book of Science Fiction	15
Elegy	Labyrinths	2
Elouise and the Doctors of the Planet Pergamon	Again, Dangerous Visions	19
Emissary from Hamelin	Strange Wine	13
Emma Zunz	Labyrinths	6
Emma Zunz	The Aleph and Other Stories	7
Empire of the Sun	Again, Dangerous Visions	8
Encounter With A Hick	Dangerous Visions	7
Enemy Mine	Nebula Winners Fifteen	64
Epilogue	City	13
Epiphany for Aliens	Again, Dangerous Visions	11
Ernest and the Machine God	Deathbird Stories	20
Erotophobia	Approaching Oblivion	7
Ersatz	Dangerous Visions	9
Escape!	I, Robot	21
Escapegoat	Angry Candy	4
Eutopia	Dangerous Visions	23
Evensong	Dangerous Visions	10
Everything and Nothing	Labyrinths	3
Everything and Nothing	The Aleph and Other Stories	3
Evidence	I, Robot	23
Exploration Team	Explorers of Space	58
Exposures	The Norton Book of Science Fiction	12
Eye of the Beholder	Again, Dangerous Visions	15
Faith of our Fathers	Dangerous Visions	38
Fear is a Cold Black	The Mile-Long Spaceship	25
Feather Tigers	The Norton Book of Science Fiction	7
Featherbed on Chlyntha	Xenogensis	17
Final Trophy	Stalking the Nightmare	12
Flies	Dangerous Visions	13
Flop Sweat	Shatterday	18
Folding Beijing	Invisible Planets	44
Footsteps	Angry Candy	14
For the Sake of Grace	The Norton Book of Science Fiction	20
For Value Received	Again, Dangerous Visions	18
Fragments of a Hologram Rose	Burning Chrome	7
From A to Z, In The Chocolate Alphabet	Strange Wine	24
From the Government Printing Office	Dangerous Visions	9
Frozen Journey	The Norton Book of Science Fiction	16
Funes the Memorious	Labyrinths	8
Funes the Memorious	Ficciones	10
G. B. K.-A Many-Flavored Bird	Love Ain't Nothing but Sex Misspelled	11
Gather Blue Roses	The Norton Book of Science Fiction	5
Gathi	Xenogensis	7
Getting Along	Again, Dangerous Visions	32
Ghost of a Chance	Caviar	20
giANTS	Nebula Winners Fifteen	20
Gift from the Stars	The Mile-Long Spaceship	17
Gnomebody	Earthman, Go Home!	7
Go Toward the Light	Slippage	10
Go, Go, Go, Said the Bird	Dangerous Visions	9
Goldfish Bowl	The Menace from Earth	29
Gonna Roll the Bones	Dangerous Visions	26
Good Hunting	The Paper Menagerie and Other Stories	23
Good News from the Vatican	The Norton Book of Science Fiction	8
Gopher in the Gilly	Stalking the Nightmare	6
Grail	Stalking the Nightmare	28
Grave of the Fireflies	Invisible Planets	18
Gutter Gang	Web of the City	25
Hadj	Earthman, Go Home!	5
Half-Life	The Norton Book of Science Fiction	14
Harry the Hare	Again, Dangerous Visions	5
Heavyplanet	The Expert Dreamers	13
Heechee Treasures	The Gateway Trip	19
Hell Is the Absence of God	Stories of Your Life and Others	32
High Weir	The Norton Book of Science Fiction	18
Hindsight: 480 Seconds	Approaching Oblivion	6
Hinterlands	Burning Chrome	22
His Vegetable	The Norton Book of Science Fiction	5
Hitler Painted Roses	Strange Wine	18
Hobbies	City	28
Homecoming	The October Country	17
Homelanding	The Norton Book of Science Fiction	3
How Beautiful with Banners	The Norton Book of Science Fiction	9
How's the Night Life on Cassalda?	Shatterday	18
Huddling Place	City	23
Humpty Dumpty had a Great Fall	Strange Gifts	27
I Curse the Lesson and Bless the Knowledge	Love Ain't Nothing but Sex Misspelled	14
I, Dreamer	The View from the Stars	12
Ibn-Hakam al-Bokhari, Murdered in His Labyrinth	The Aleph and Other Stories	10
If All Men Were Brothers, Would You Let One Marry Your Sister?	Dangerous Visions	49
I'm Looking for Kadak	Approaching Oblivion	27
In Fear of K	Strange Wine	16
In Lonely Islands	Earthman, Go Home!	5
In Memoriam, J. F. K.	The Aleph and Other Stories	1
In re Glover	Again, Dangerous Visions	13
In the Barn	Again, Dangerous Visions	37
In the Core	The Gateway Trip	9
In the Fourth Year of the War	Shatterday	14
Incident in Moderan	Dangerous Visions	6
Inferno, I, 32	Labyrinths	1
Inferno, I, 32	The Aleph and Other Stories	1
Interim	The Martian Chronicles	1
Interlocking Pieces	The Norton Book of Science Fiction	6
Invaders	The Norton Book of Science Fiction	20
Invasion Footnote	Stalking the Nightmare	8
Invisible Planets	Invisible Planets	20
It	Selected Stories	25
It was Nothing-Really	Sturgeon is Alive and Well...	15
It's You!	Sturgeon is Alive and Well...	10
J. C. on the Dude Ranch	Riverworld and Other Stories	16
Jack-in-the-Box	The October Country	20
Jane Doe #112	Slippage	12
Jeffty is Five	Shatterday	28
Jenny with Wings	The Mile-Long Spaceship	13
Johnny Mnemonic	Burning Chrome	22
Jorry's Gap	Sturgeon is Alive and Well...	12
Judas	Dangerous Visions	12
Jupiter Five	Explorers of Space	38
Kafka and His Precursors	Labyrinths	3
Keyboard	Slippage	7
Killdozer!	Selected Stories	70
Killing Bernstein	Strange Wine	18
King of the Hill	Again, Dangerous Visions	20
Kirinyaga	The Norton Book of Science Fiction	17
Kiss of Fire	Approaching Oblivion	11
Knights to Move	Changewar	13
Knox	Approaching Oblivion	15
Kyrie	Explorers of Space	15
Kyrie	The Norton Book of Science Fiction	10
Ladies and Gentlemen, This Is Your Crisis	Somerset Dreams and Other Fictions	16
Lamia Mutable	Again, Dangerous Visions	10
Land of the Great Horses	Dangerous Visions	12
Last Train to Kankakee	Again, Dangerous Visions	11
Laugh Track	Angry Candy	22
Lenny	The Expert Dreamers	18
Let There Be Light	The Man Who Sold the Moon	19
Liar!	I, Robot	16
Life in Our Time	The Living Demons	9
Life-Line	The Man Who Sold the Moon	22
Liking What You See: A Documentary	Stories of Your Life and Others	38
Little Lost Robot	I, Robot	26
Lollipop and the Tar Baby	The Norton Book of Science Fiction	19
Lonley Women Are the Vessels of Time	Strange Wine	8
Looking for Company	The Gateway Trip	13
Lord Randy, My Son	Dangerous Visions	18
Lucy Comes To Stay	The Living Demons	6
Making It All the Way into the Future on Gaxton Falls of the Red Planet	The Norton Book of Science Fiction	4
Man of Letters	The Infinity Box	19
Martin Fierro	The Aleph and Other Stories	2
Mathoms from the Time Closet	Again, Dangerous Visions	12
Mealtime	Earthman, Go Home!	11
Medusa	Caviar	26
Mefisto in Onyx	Slippage	46
Microcosmic God	Caviar	34
Midnight in the Sunken Cathedral	Slippage	10
Midnight News	The Norton Book of Science Fiction	11
Mom	Strange Wine	22
Mona at Her Windows	Love Ain't Nothing but Sex Misspelled	5
Monitored Dreams & Strategic Cremations	Again, Dangerous Visions	67
Mono no Aware	The Paper Menagerie and Other Stories	21
Monolog	Riverworld and Other Stories	8
Moth Race	Again, Dangerous Visions	13
Mountain	The Wandering Earth	48
Mr. Costello, Hero	Selected Stories	26
Mrs. Bagley Goes to Mars	Somerset Dreams and Other Fictions	10
Mutations	The Aleph and Other Stories	1
Nackles vr.1	Slippage	8
Nackles vr.2	Slippage	31
Neither Your Jenny Nor Mine	Love Ain't Nothing but Sex Misspelled	44
Neon	Deathbird Stories	12
New Rose Hotel	Burning Chrome	14
Night Journey of the Dragon-Horse	Invisible Planets	20
Night Meeting	The Martian Chronicles	9
Night of Black Glass	Stalking the Nightmare	16
Night-Rise	The Norton Book of Science Fiction	10
Nine Hundred Grandmothers	The Norton Book of Science Fiction	9
No Game for Children	Web of the City	51
No Great Magic	Changewar	68
No Light in the Windows	The Mile-Long Spaceship	11
Nothing for My Noon Meal	Earthman, Go Home!	15
O Ye of Little Faith	Deathbird Stories	10
Oddy and Id	Strange Gifts	17
Of Ants and Dinosaurs	The Wandering Earth	57
On Exactitude and Science	The Aleph and Other Stories	1
On the Downhill Slide	Deathbird Stories	18
On the Feasibility of Coal-Driven Power Stations	The Expert Dreamers	4
On the Slab	Angry Candy	12
One for the Road	The Mile-Long Spaceship	16
One Life, Furnished in Early Poverty	Approaching Oblivion	14
One-Way Journey	Xenogensis	11
Operation Cassandra	Xenogensis	27
Opium	Shatterday	8
Other Worlds	The Gateway Trip	19
Out of All Them Bright Stars	The Norton Book of Science Fiction	7
Over the River and Through the Woods	The Norton Book of Science Fiction	8
Ozymandias	Again, Dangerous Visions	21
Paingod	Deathbird Stories	12
Paingod	Paingod and Other Delusions	12
Paladin of the Last Hour	Angry Candy	26
Parable of Cervantes and the Quixote	Labyrinths	1
Parable of the Palace	The Aleph and Other Stories	2
Paradise	City	16
Paradiso, XXXI, 108	Labyrinths	2
Paradiso, XXXI, 108	The Aleph and Other Stories	2
Partial Magic in the Quixote	Labyrinths	4
Paulie Charmed the Sleeping Woman	Approaching Oblivion	4
Philtre Tip	The Living Demons	5
Pierre Menrad, Author of Don Quixote	Ficciones	12
Pierre Menrad, Author of Don Quixote	Labyrinths	9
Planet Story	Somerset Dreams and Other Fictions	16
Precession	The Norton Book of Science Fiction	10
Pretty Maggie Moneyeyes	Deathbird Stories	24
Prince Myshkin, and Hold the Relish	Angry Candy	10
Prodigy	Caviar	14
Project Nightmare	The Menace from Earth	21
Pulling Hard Time	Slippage	6
Punky & The Yale Men	Love Ain't Nothing but Sex Misspelled	30
Quick to Haste	Xenogensis	12
Quicktime	Angry Candy	10
Ragnarok	Labyrinths	2
Ragnarok	The Aleph and Other Stories	2
Rain, Rain, Go Away	Earthman, Go Home!	9
Rat	The Norton Book of Science Fiction	11
Reason	I, Robot	18
Red Star, Winter Orbit	Burning Chrome	23
Repent, Harlequin! Said the Ticktockman	Paingod and Other Delusions	14
Requiem	The Man Who Sold the Moon	20
Riders of the Purple Wage	Dangerous Visions	80
Riding the Dark Train Out	Love Ain't Nothing but Sex Misspelled	10
Riverworld	Riverworld and Other Stories	86
Robbie	I, Robot	19
Rock God	Deathbird Stories	14
Rocket Summer	The Martian Chronicles	1
Runaround	I, Robot	17
Sandkings	Nebula Winners Fifteen	43
Saturn, November 11th	Stalking the Nightmare	16
Scartaris, June 28th	Slippage	22
Schrodinger's Plague	The Norton Book of Science Fiction	8
Schwarzschild Radius	The Norton Book of Science Fiction	16
Seeing	Strange Wine	34
Sensible City	Slippage	10
Seventy-Two Letters	Stories of Your Life and Others	54
Sex and/or Mr. Morrison	Dangerous Visions	14
Shadow, Shadow on the Wall	Caviar	12
Shall the Dust Praise Thee?	Dangerous Visions	7
Shatterday	Shatterday	17
Shattered Like a Glass Goblin	Deathbird Stories	14
She's a Young Thing and Cannot Leaver Her Mother	Slippage	16
Shoppe Keeper	Shatterday	24
Silence	This Way for the Gas, Ladies and Gentlemen	3
Silent in Gehenna	Approaching Oblivion	16
Silhouette	The New Atlantis	56
Simulacrum	The Paper Menagerie and Other Stories	11
Skeleton	The October Country	20
Sky Lift	The Menace from Earth	14
Slow Sculpture	Selected Stories	20
Slow Sculpture	Sturgeon is Alive and Well...	22
Snow	The Norton Book of Science Fiction	14
Soft Monkey	Angry Candy	16
Somehow, I Don't Think We're in Kansas, Toto	Stalking the Nightmare	10
Somerset Dreams	Somerset Dreams and Other Fictions	46
Soundless Evening	Again, Dangerous Visions	8
Speech Sound	The Norton Book of Science Fiction	12
Stable Strategies for Middle Management	The Norton Book of Science Fiction	11
Stand Still and Die	Web of the City	203
State Change	The Paper Menagerie and Other Stories	16
State of Grace	Somerset Dreams and Other Fictions	9
Still-Life	Again, Dangerous Visions	15
Stoned Counsel	Again, Dangerous Visions	16
Story of the Warrior and the Captive Maiden	Labyrinths	5
Story of the Warrior and the Captive Maiden	The Aleph and Other Stories	5
Story of Your Life	Stories of Your Life and Others	56
Strange Wine	Strange Wine	12
Strange Wine	The Norton Book of Science Fiction	7
Stuffing	Angry Candy	8
Suicide	Sturgeon is Alive and Well...	8
Sun of China	The Wandering Earth	49
Symbiosis	Somerset Dreams and Other Fictions	20
Take Care of Joey	Sturgeon is Alive and Well...	12
Taking Care of God	Invisible Planets	40
Taking Care of God	The Wandering Earth	41
Tandy's Story	The Norton Book of Science Fiction	19
Tauf Aleph	The Norton Book of Science Fiction	18
Tell Your Fortune	The Living Demons	25
Test to Destruction	Dangerous Visions	29
That Girl Who Knew What They Meant	Sturgeon is Alive and Well...	10
The [Widget], the [Wadget], and Boff	Selected Stories	84
The 10:00 Report is Brought to You By...	Again, Dangerous Visions	16
The 3 Most Important Things in Life	Stalking the Nightmare	20
The Absolutely Perfect Murder	Xenogensis	11
The Adventure of Black Peter	The Original Illustrated Sherlock Holmes	13
The Adventure of Charles Augustus Milverton	The Original Illustrated Sherlock Holmes	12
The Adventure of the Gloria Scott	The Original Illustrated Sherlock Holmes	12
The Adventure of the Abbey Grange	The Original Illustrated Sherlock Holmes	15
The Adventure of the Beryl Coronet	The Original Illustrated Sherlock Holmes	15
The Adventure of the Blue Carbuncle	The Original Illustrated Sherlock Holmes	13
The Adventure of the Cardboard Box	The Original Illustrated Sherlock Holmes	13
The Adventure of the Copper Beeches	The Original Illustrated Sherlock Holmes	17
The Adventure of the Crooked Man	The Original Illustrated Sherlock Holmes	11
The Adventure of the Dancing Men	The Original Illustrated Sherlock Holmes	16
The Adventure of the Empty House	The Original Illustrated Sherlock Holmes	15
The Adventure of the Engineer's Thumb	The Original Illustrated Sherlock Holmes	13
The Adventure of the Final Problem	The Original Illustrated Sherlock Holmes	14
The Adventure of the Golden Pince-Nez	The Original Illustrated Sherlock Holmes	15
The Adventure of the Greek Interpreter	The Original Illustrated Sherlock Holmes	12
The Adventure of the Missing Three-Quarter	The Original Illustrated Sherlock Holmes	14
The Adventure of the Musgrave Ritual	The Original Illustrated Sherlock Holmes	11
The Adventure of the Naval Treaty	The Original Illustrated Sherlock Holmes	22
The Adventure of the Noble Bachelor	The Original Illustrated Sherlock Holmes	14
The Adventure of the Norwood Builder	The Original Illustrated Sherlock Holmes	15
The Adventure of the Priory School	The Original Illustrated Sherlock Holmes	19
The Adventure of the Reigate Squires	The Original Illustrated Sherlock Holmes	12
The Adventure of the Resident Patient	The Original Illustrated Sherlock Holmes	11
The Adventure of the Second Stain	The Original Illustrated Sherlock Holmes	14
The Adventure of the Silver Blaze	The Original Illustrated Sherlock Holmes	16
The Adventure of the Six Napoleons	The Original Illustrated Sherlock Holmes	14
The Adventure of the Solitary Cyclist	The Original Illustrated Sherlock Holmes	13
The Adventure of the Speckled Band	The Original Illustrated Sherlock Holmes	16
The Adventure of the Stockbroker's Clerk	The Original Illustrated Sherlock Holmes	11
The Adventure of the Yellow Face	The Original Illustrated Sherlock Holmes	11
The Age of Gold	The Gateway Trip	16
The Ajeri Diary	Xenogensis	20
The Aleph	The Aleph and Other Stories	16
The Approach to Al-Mu'tasim	Ficciones	8
The Argentine Writer and Tradition	Labyrinths	9
The Avenger of Death	Angry Candy	14
The Babylon Lottery	Ficciones	8
The Beast of Barsac	The Living Demons	19
The Belonging Kind	Burning Chrome	15
The Big Hunger	The View from the Stars	14
The Big Space Fuck	Again, Dangerous Visions	11
The Black Cloud	The Expert Dreamers	18
The Bob Dylan Tambourine Software & Satori Support Services Consortium, Ltd.	The Norton Book of Science Fiction	12
The Bookmaking Habits of Select Species	The Paper Menagerie and Other Stories	9
The Boscombe Valley Mystery	The Original Illustrated Sherlock Holmes	16
The Boulevard of Broken Dreams	Strange Wine	6
The Brains of Rats	The Norton Book of Science Fiction	14
The Byrds	The Norton Book of Science Fiction	12
The Captive	The Aleph and Other Stories	2
The Cheese Stands Alone	Stalking the Nightmare	14
The Children	Xenogensis	29
The Circle	Invisible Planets	22
The Circular Ruins	Ficciones	8
The Circular Ruins	Labyrinths	6
The Cistern	The October Country	10
The City of Silence	Invisible Planets	44
The Crackpots	Paingod and Other Delusions	40
The Crowd	The October Country	12
The Daughter of the Tree	Xenogensis	12
The Day After the Day the Martians Came	Dangerous Visions	10
The Day I Died	Stalking the Nightmare	10
The Dead Man	The Aleph and Other Stories	6
The Death of Schillinger	This Way for the Gas, Ladies and Gentlemen	4
The Deathbird	Deathbird Stories	32
The Diagnosis of Dr. Darqueangel	Strange Wine	17
The Discarded	Paingod and Other Delusions	14
The Doll-House	Dangerous Visions	24
The Dragon on the Bookshelf	Slippage	12
The Dreams a Nightmare Dreams	Slippage	4
The Dwarf	The October Country	15
The Earth Men	The Martian Chronicles	15
The Emissary	The October Country	10
The Encounter	Somerset Dreams and Other Fictions	28
The End	Ficciones	4
The Evitable Conflict	I, Robot	22
The Evolution of Human Science	Stories of Your Life and Others	4
The Executioner of the Malformed Children	Shatterday	16
The Extraordinary Voyages of Amelie Bertrand	Nebula Winners Fifteen	15
The Face of Helene Bournouw	Deathbird Stories	12
The Fearful Sphere of Pascal	Labyrinths	4
The Few, the Proud	Slippage	10
The Fish of Lijiang	Invisible Planets	18
The Five Orange Pips	The Original Illustrated Sherlock Holmes	11
The Flower of Shazui	Invisible Planets	20
The Forces that Crush	Earthman, Go Home!	15
The Form of the Sword	Ficciones	6
The Function of Dream Sleep	Angry Candy	23
The Funeral	Again, Dangerous Visions	28
The Funeral	The Infinity Box	27
The Fusion Bomb	The Infinity Box	39
The Garden of Forking Paths	Ficciones	14
The Garden of Forking Paths	Labyrinths	11
The Gateway Asteroid	The Gateway Trip	9
The Gernsback Continuum	The Norton Book of Science Fiction	9
The Gernsback Continuum	Burning Chrome	13
The Girl From Mars	The Living Demons	7
The Goddess in the Ice	Stalking the Nightmare	6
The God's Script	Labyrinths	8
The Golden Helix	Selected Stories	56
The Golden Man	Strange Gifts	33
The Green Morning	The Martian Chronicles	5
The Handler	The Norton Book of Science Fiction	4
The Happy Breed	Dangerous Visions	22
The Heart of the Other Side	The Expert Dreamers	11
The Henry Miller Dawn Patrol	Riverworld and Other Stories	16
The Home Planet	The Gateway Trip	9
The Hounds	Somerset Dreams and Other Fictions	28
The Hour That Stretches	Stalking the Nightmare	22
The House of Asterion	Labyrinths	3
The House of Asterion	The Aleph and Other Stories	3
The House the Blakeneys Built	The Norton Book of Science Fiction	10
The Immortal	Labyrinths	14
The Immortal	The Aleph and Other Stories	17
The Indian Spirit Guide	The Living Demons	16
The Infinity Box	The Infinity Box	65
The Invasion	The Expert Dreamers	18
The January Offensive	This Way for the Gas, Ladies and Gentlemen	10
The Jar	The October Country	17
The Jigsaw Man	Dangerous Visions	17
The Jungle Rot Kid on the Nod	Riverworld and Other Stories	12
The Lake	The October Country	7
The Lake Was Full of Artificial Things	The Norton Book of Science Fiction	11
The Last Days of the Captain	The Mile-Long Spaceship	15
The Last Generation?	Xenogensis	12
The Leaser of Two Evils	Riverworld and Other Stories	16
The Library of Babel	Ficciones	10
The Library of Babel	Labyrinths	8
The Life of Anybody	The Norton Book of Science Fiction	2
The Lingering Scent of Woodsmoke	Slippage	4
The Literomancer	The Paper Menagerie and Other Stories	38
The Litigation Master and the Monkey King	The Paper Menagerie and Other Stories	26
The Locusts	The Martian Chronicles	1
The Long Years	The Martian Chronicles	11
The Longest Fall	The Wandering Earth	56
The Lottery in Babylon	Labyrinths	6
The Lucky Strike	The Norton Book of Science Fiction	31
The Luggage Store	The Martian Chronicles	1
The Maker	The Aleph and Other Stories	3
The Malley System	Dangerous Visions	11
The Man on the Threshold	The Aleph and Other Stories	6
The Man Upstairs	The October Country	16
The Man Who Ended History: A Documentary	The Paper Menagerie and Other Stories	61
The Man Who Lost the Sea	Selected Stories	12
The Man Who Rowed Christopher Columbus Ashore	Slippage	18
The Man Who Sold the Moon	The Man Who Sold the Moon	106
The Man Who Was Heavily into Revenge	Shatterday	8
The Man Who Went to the Moon-Twice	Dangerous Visions	13
The Man With English	Strange Gifts	10
The Man with the Package	This Way for the Gas, Ladies and Gentlemen	5
The Man With the Twisted Lips	The Original Illustrated Sherlock Holmes	15
The Man without a Planet	The Mile-Long Spaceship	7
The Mark Gable Foundation	The Expert Dreamers	13
The Martian	The Martian Chronicles	12
The Menace from Earth	The Menace from Earth	13
The Merchants of Venus	The Gateway Trip	122
The Micro-Age	The Wandering Earth	33
The Mile-Long Spaceship	The Mile-Long Spaceship	10
The Milk of Paradise	Again, Dangerous Visions	13
The Million-Year Picnic	The Martian Chronicles	9
The Miracle of the Broom Closet	The Expert Dreamers	7
The Mirrors of Enigmas	Labyrinths	4
The Mountains of Sunset, the Mountains of Dawn	The Norton Book of Science Fiction	13
The Mountebank	The Aleph and Other Stories	2
The Museum on Cyclops Avenue	Slippage	12
The Musicians	The Martian Chronicles	1
The Naming of Names	The Martian Chronicles	1
The New Atlantis	The New Atlantis	30
The New Atlantis	The Norton Book of Science Fiction	20
The New York Review of Bird	Strange Wine	44
The Next in Line	The October Country	41
The Night That All Time Broke Out	Dangerous Visions	16
The Off Season	The Martian Chronicles	12
The Old Ones	The Martian Chronicles	1
The Oldest Soldier	Changewar	27
The Other Death	The Aleph and Other Stories	8
The Other Eye of Polyphemus	Shatterday	14
The Outpost Undiscovered by Tourists	Stalking the Nightmare	8
The Pale Silver Dollar of the Moon Pays Its Way and Makes Change vr.1	Slippage	6
The Pale Silver Dollar of the Moon Pays Its Way and Makes Change vr.2	Slippage	8
The Paper Menagerie	The Paper Menagerie and Other Stories	15
The Patterns of Drone	Sturgeon is Alive and Well...	16
The People Who Walked On	This Way for the Gas, Ladies and Gentlemen	16
The Perfect Match	The Paper Menagerie and Other Stories	25
The Phantom of the Sewers	Riverworld and Other Stories	25
The Place with No Name	Deathbird Stories	16
The Plot	The Aleph and Other Stories	1
The Plot Is the Thing	The Living Demons	7
The Private War of Private Jacob	The Norton Book of Science Fiction	5
The Problem of the Sore Bridge-Among Others	Riverworld and Other Stories	32
The Prowler in the City on the Edge of Forever	Dangerous Visions	20
The Recognition	Dangerous Visions	14
The Red Canary	The Infinity Box	18
The Red-Headed League	The Original Illustrated Sherlock Holmes	15
The Region Between	Angry Candy	86
The Regular	The Paper Menagerie and Other Stories	25
The Resurgence of Miss Ankle-Strap Wedgie	Love Ain't Nothing but Sex Misspelled	91
The Roads Must Roll	The Man Who Sold the Moon	45
The Season of Babies	Xenogensis	14
The Secret Miracle	Ficciones	8
The Secret Miracle	Labyrinths	7
The Sect of Phoenix	Ficciones	4
The Sect of Phoenix	Labyrinths	4
The Settlers	The Martian Chronicles	1
The Sex Opposite	Selected Stories	28
The Shape of the Sword	Labyrinths	5
The Shore	The Martian Chronicles	1
The Silent Towns	The Martian Chronicles	10
The Silver Corridor	Earthman, Go Home!	20
The Simple Way	City	25
The Singers	The Expert Dreamers	4
The Skills of Xanadu	Selected Stories	28
The Sky is Burning	Earthman, Go Home!	9
The Small Assaassin	The October Country	21
The Smiling Future	Xenogensis	13
The South	Ficciones	7
The Starseekers	The Gateway Trip	19
The Start of the End of It All	The Norton Book of Science Fiction	11
The Summer Night	The Martian Chronicles	2
The Superior Sex	Xenogensis	11
The Supper	This Way for the Gas, Ladies and Gentlemen	5
The Sycthe	The October Country	8
The Taxpayer	The Martian Chronicles	1
The Test Stand	The Expert Dreamers	14
The Test-Tube Creature, Afterward	Again, Dangerous Visions	5
The Theologians	Labyrinths	8
The Theologians	The Aleph and Other Stories	9
The Third Expedition	The Martian Chronicles	16
The Time Piece	The Infinity Box	22
The Transit of Venus	Xenogensis	11
The Two Kings and the Two Labyrinths	The Aleph and Other Stories	2
The Universe of Robert Blake	Love Ain't Nothing but Sex Misspelled	5
The Unspeakable Betrothal	The Living Demons	14
The Very Last Day of a Good Woman	Earthman, Go Home!	9
The Village	The Infinity Box	10
The Visit	The Gateway Trip	9
The Voice of the Sonar in My Veriform Appendix	Riverworld and Other Stories	14
The Volcano	Riverworld and Other Stories	20
The Wages of Humanity	The Wandering Earth	44
The Waiting	Labyrinths	4
The Wall and the Books	Labyrinths	3
The Wandering Earth	The Wandering Earth	46
The War at Home	The Norton Book of Science Fiction	3
The Warlord of Saturn's Moon	The Norton Book of Science Fiction	8
The Watchers	The Martian Chronicles	1
The Watchful Poker Chip of H. Matisse	The October Country	12
The Waves	The Paper Menagerie and Other Stories	26
The Whimper of Whipped Dogs	Deathbird Stories	22
The Will	The View from the Stars	14
The Wind	The October Country	12
The Wind Beyond the Mountains	Earthman, Go Home!	10
The Wine Has Been Left Open Too Long and the Memory Has Gone Flat	Strange Wine	16
The Winter Flies	The Norton Book of Science Fiction	12
The Winter Market	Burning Chrome	25
The Witness	Labyrinths	1
The Witness	The Aleph and Other Stories	1
The Women Men Don't See	The Norton Book of Science Fiction	25
The Wonderful Death of Dudley Stone	The October Country	13
The Word for World is Forrest	Again, Dangerous Visions	96
The World of Stone	This Way for the Gas, Ladies and Gentlemen	3
The Writing of the God	The Aleph and Other Stories	6
The Year of the Jackpot	The Menace from Earth	32
The Year of the Rat	Invisible Planets	30
The Yellow Rose	The Aleph and Other Stories	1
The Zahir	Labyrinths	5
The Zahir	The Aleph and Other Stories	10
Theme of the Traitor and Hero	Ficciones	6
Theme of the Traitor and Hero	Labyrinths	4
There Was an Old Woman	The October Country	16
There Will Come Soft Rains	The Martian Chronicles	6
Things Lost	Again, Dangerous Visions	30
This Way for the Gas, Ladies and Gentlemen	This Way for the Gas, Ladies and Gentlemen	21
Three Versions of Judas	Ficciones	8
Three Versions of Judas	Labyrinths	6
Throwback	Xenogensis	13
Thunder and Roses	Selected Stories	24
Time Travel for Pedestrians	Again, Dangerous Visions	31
Tiny Ally	Stalking the Nightmare	6
Tissue	Again, Dangerous Visions	16
Tlon, Uqbar, Orbis Teritus	Ficciones	20
Tlon, Uqbar, Orbis Teritus	Labyrinths	16
To Be Continued	Strange Gifts	14
To Explain to Mrs. Thompson	The Expert Dreamers	23
To Here and the Easel	Sturgeon is Alive and Well...	56
Toenails	The Aleph and Other Stories	1
Tongtong's Summer	Invisible Planets	20
Totenbuch	Again, Dangerous Visions	10
Touched With Fire	The October Country	15
Tower of Babylon	Stories of Your Life and Others	28
Tracking Level	Stalking the Nightmare	12
Transcending Destiny	Stalking the Nightmare	26
Trouble With Ants	City	38
Try and Change the Past	Changewar	11
Twink	Caviar	19
Unaccompanied Sonata	Nebula Winners Fifteen	20
Uncle Einar	The October Country	10
Uncle Fremmis	Sturgeon is Alive and Well...	18
Underground	The Living Demons	6
Understand	Stories of Your Life and Others	42
Unlocking the Air	The Unreal and the Real	26
Usher II	The Martian Chronicles	15
Valerie	Love Ain't Nothing but Sex Misspelled	16
Valery as Symbol	Labyrinths	2
Vaster than Empires and More Slow	Explorers of Space	57
Visionary	Stalking the Nightmare	14
Wanted in Surgery	Paingod and Other Delusions	30
Water Is for Washing	The Menace from Earth	10
Way in the Middle of the Air	The Martian Chronicles	3
We See Things Differently	The Norton Book of Science Fiction	18
What Happened to Auguste Clarot?	Dangerous Visions	8
What I Did on My Vaction This Summer by Little Bobby Hirschhorn, Age 27	Love Ain't Nothing but Sex Misspelled	19
What's It Like Out There?	Explorers of Space	27
When Auld's Acquaintance is Forgot	Angry Candy	10
When I was a Hired Gun	Love Ain't Nothing but Sex Misspelled	12
When I Was Miss Dow	The Norton Book of Science Fiction	10
When it Changed	Again, Dangerous Visions	16
When the Bentfin Boomer Boys on Old New Alabama	Again, Dangerous Visions	107
When the Change-Winds Blow	Changewar	15
Where Have You Been, Billy Boy, Billy Boy?	The Infinity Box	13
Where I Shall Dwell in the Next World	Slippage	12
With a Finger in My I	Again, Dangerous Visions	15
With Her Eyes	The Wandering Earth	19
With Virgin Oddum at the East Pole	Angry Candy	20
Working with the Little People	Strange Wine	18
Would You Do It for a Penny	Shatterday	22
Ylla	The Martian Chronicles	12
You Triflin' Skunk	The View from the Stars	11
Zero Gee	Again, Dangerous Visions	31
And the Moon be Still as Bright	The Martian Chronicles	24

================================================
FILE: tests/data/stories.tsv
================================================
!!!The!!Teddy!Crazy!!Show!!!	science fiction	1968
(Learning About) Machine Sex	science fiction	1988
...the World, as we Know 't	science fiction	1982
2004, or Thereabouts	science fiction	1964
A Biography of Tadeo Isidoro Cruz (1829-1874)	fiction	1944
A Brief History of the Trans-Pacific Tunnel	science fiction	2013
A Case of Identity	mystery	1891
A Day at Harmenz	east euro lit	1959
A Deskful of Girls	science fiction	1958
A Dialog About A Dialog	fiction	1936
A Dialog Between Dead Men	fiction	1957
A Feast of Demons	science fiction	1958
A Few Things I Know About While Away	science fiction	1975
A Hundred Ghosts Parade Tonight	science fiction	2010
A is for Automation	science fiction	1959
A Midwinter's Tale	science fiction	1988
A Momentary Taste of Being	science fiction	1975
A Mouse in the Walls of the Global Village	science fiction	1972
A New Refutation of Time	essay	1947
A Note on (toward) Bernard Shaw	essay	1962
A Path Through the Darkness	science fiction	1963
A Prayer for No One's Enemies	science fiction	1966
A Problem	fiction	1957
A Scandal in Bohemia	mystery	1891
A Toy for Juliette	science fiction	1967
A True Story	east euro lit	1959
A Visit	east euro lit	1959
A Way of Thinking	science fiction	1953
Adrift Just Off the Islets of Langerhans: Latitude 38o54'N, Longitude 77o00'13W	science fiction	1974
Adrift on the Policy Level	science fiction	1959
Aesop	science fiction	1947
After the Days of Dead-Eye 'Dee	science fiction	1985
All in Good Time	science fiction	1960
All the Birds Come Home to Roost	science fiction	1978
All the Flavors	science fiction	2012
All the Lies Lies That Are My Life	science fiction	1980
All The People	science fiction	1961
All the Sound of Fear	science fiction	1962
Along the Scenic Route	science fiction	1969
Alpha Ralpha Boulevard	science fiction	1961
Amateur in Chancery	science fiction	1961
America	science fiction	1987
An Advanced Readers' Picture Book of Comparative Cognition	science fiction	2016
An Examination of the Work of Herbert Quain	fiction	1941
And the Angels Sing	science fiction	1990
And the Sea Like Mirrors	science fiction	1972
Andover and the Android	science fiction	1963
Anybody Else Like Me?	science fiction	1952
Anywhere But Here, With Anybody But You	science fiction	1996
April Fools' Day Forever	science fiction	1970
Argumentum Ornithologicum	fiction	1952
As Simple As That	science fiction	1971
At the End of the Orbit	science fiction	1961
At the Mouse Circus	science fiction	1971
Aunt Parnetta's Electric Blisters	science fiction	1990
Auschwitz, Our Home (A Letter)	east euro lit	1959
Auto-De-Fe	science fiction	1967
Avatars of the Tortoise	essay	1939
Averroes' Search	fiction	1947
Aye, and Gomorrah...	science fiction	1967
Balanced Ecology	science fiction	1965
Basilisk	science fiction	1972
Battle Without Banners	science fiction	1964
Battlefield	science fiction	1958
Beachhead	science fiction	1951
Beauty's Beast	science fiction	1941
Bed Sheets are White	science fiction	1972
Bettyann	science fiction	1951
Bianca's Hands	science fiction	1947
Big Joe and the Nth Generation	science fiction	1952
Blabbermouth	science fiction	1945
Black Bargain	science fiction	1942
Blank?	science fiction	1957
Bleeding Stones	science fiction	1973
Blind Bird, Blind Bird, Go Away From Me!	science fiction	1963
Blood Bank	science fiction	1952
Blot	science fiction	1972
Blowups Happen	science fiction	1940
Borges and I	fiction	1957
Bounty	science fiction	1972
Brass and Gold (or Horse and Zeppelin in Beverly Hills)	science fiction	1971
Bright Eyes	science fiction	1965
Bright Segment	science fiction	1955
Broken Glass	science fiction	1981
Brownshoes	science fiction	1969
Burning Chrome	science fiction	1982
By His Bootstraps	science fiction	1941
Call Girl	science fiction	2014
Camps	science fiction	1979
Carcinoma Angels	science fiction	1967
Catch That Rabbit	science fiction	1944
Catman	science fiction	1974
Census	science fiction	1944
Chain Reaction	science fiction	1956
Chained to the Fast Lane in the Red Queen's Race	science fiction	1983
Chatting with Anubis	science fiction	1995
Ching Witch!	science fiction	1972
Christ, Old Student in a New School	science fiction	1972
Chuck Berry, Won't You Please Come Home	science fiction	1972
City	science fiction	1944
Cold Friend	science fiction	1973
Collecting Team	science fiction	1956
Columbus Was a Dope	science fiction	1947
Come to the Party	science fiction	1978
Comes Now the Power	science fiction	1966
Commuter's Problem	science fiction	1957
Corpse	science fiction	1972
Count the Clock That Tells the Time	science fiction	1978
Covered Mirrors	fiction	1936
Crate	science fiction	1970
Crazy as a Soup Sandwich	science fiction	1989
Croatoan	science fiction	1975
Crucifixus Etiam	science fiction	1953
Curse 5.0	science fiction	2013
Damnation Morning	science fiction	1959
Danger-Human!	science fiction	1957
Daniel White for the Greater Good	science fiction	1961
Darkness Upon the Face of the Deep	science fiction	1991
Day Million	science fiction	1966
Deal From the Bottom	science fiction	1960
Death and the Compass	fiction	1942
Deeper than the Darkness	science fiction	1957
Delia Elena San Marco	fiction	1957
Delusion for a Dragon Slayer	science fiction	1966
Deutsches Requiem	fiction	1946
Devourer	science fiction	2013
Distant Signals	science fiction	1984
Division by Zero	science fiction	1991
Django	science fiction	1978
Djinn, No Chaser	science fiction	1982
Dogfight	science fiction	1985
Do-It-Yourself	science fiction	1961
Dreamtigers	fiction	1936
Dumb Waiter	science fiction	1952
Each an Explorer	science fiction	1956
E
Download .txt
gitextract_sm4g9zum/

├── .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
├── single-header/
│   └── sql.hpp
└── tests/
    ├── data/
    │   ├── authored.tsv
    │   ├── books.tsv
    │   ├── collected.tsv
    │   └── stories.tsv
    ├── data.hpp
    ├── 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
Download .txt
SYMBOL INDEX (370 symbols across 37 files)

FILE: example.cpp
  function main (line 30) | int main()

FILE: generator.py
  function include (line 3) | def include(header, incs, root, included):
  function main (line 25) | def main():

FILE: include/cexpr/string.hpp
  type cexpr (line 7) | namespace cexpr
    class string (line 11) | class string
      method string (line 16) | constexpr string() noexcept : size_{ 0 }, string_{ 0 }
      method string (line 19) | constexpr string(const Char(&s)[N]) noexcept : string{}
      method string (line 27) | constexpr string(cexpr::string<Char, N> const& s) noexcept : string{}
      method string (line 35) | constexpr string(std::basic_string_view<Char> const& s) noexcept : s...
      method fill (line 46) | constexpr void fill(const Char* begin, const Char* end) noexcept
      method fill_from (line 51) | constexpr void fill_from(const Char* begin, const Char* end, Char* s...
      method capacity (line 62) | inline constexpr std::size_t capacity() const noexcept
      method size (line 67) | inline constexpr std::size_t size() const noexcept
      method Char (line 72) | inline constexpr Char* begin() noexcept
      method Char (line 76) | inline constexpr const Char* cbegin() const noexcept
      method Char (line 81) | inline constexpr Char* end() noexcept
      method Char (line 85) | inline constexpr const Char* cend() const noexcept
      method Char (line 90) | inline constexpr Char& operator[](std::size_t i)
      method Char (line 94) | inline constexpr Char const& operator[](std::size_t i) const

FILE: include/ra/cross.hpp
  type ra (line 6) | namespace ra
    class cross (line 10) | class cross : public ra::join<LeftInput, RightInput>

FILE: include/ra/join.hpp
  type ra (line 9) | namespace ra
    function recr_merge (line 16) | constexpr auto recr_merge()
    function merge (line 31) | inline constexpr auto merge()
    function recr_copy (line 44) | constexpr void recr_copy(Dest& dest, Row const& src)
    function copy (line 58) | inline constexpr void copy(Dest& dest, Row const& src)
    class join (line 73) | class join : public ra::binary<LeftInput, RightInput>
      method seed (line 82) | static inline void seed(Inputs const&... rs)
      method reset (line 88) | static inline void reset()

FILE: include/ra/natural.hpp
  type ra (line 10) | namespace ra
    class natural (line 14) | class natural : public ra::join<LeftInput, RightInput>
      method seed (line 24) | static void seed(Inputs const&... rs)

FILE: include/ra/operation.hpp
  type ra (line 5) | namespace ra
    class unary (line 9) | class unary
      method seed (line 15) | static inline void seed(Inputs const&... rs)
      method reset (line 20) | static inline void reset()
    class binary (line 27) | class binary
      method seed (line 34) | static inline void seed(Inputs const&... rs)
      method reset (line 40) | static inline void reset()

FILE: include/ra/projection.hpp
  type ra (line 7) | namespace ra
    class projection (line 11) | class projection : public ra::unary<Input>
      method fold (line 26) | static inline constexpr void fold(Dest& dest, input_type const& src)

FILE: include/ra/relation.hpp
  type ra (line 6) | namespace ra
    type data_end (line 9) | struct data_end : std::exception
    class relation (line 15) | class relation
      method seed (line 33) | static void seed(Input const& r, Inputs const&... rs) noexcept
      method reset (line 47) | static inline void reset() noexcept

FILE: include/ra/rename.hpp
  type ra (line 7) | namespace ra
    class rename (line 11) | class rename : public ra::unary<Input>
      method fold (line 26) | static inline constexpr void fold(Dest& dest, Src const& src)

FILE: include/ra/selection.hpp
  type ra (line 5) | namespace ra
    class selection (line 9) | class selection : public ra::unary<Input>

FILE: include/sql/column.hpp
  type sql (line 5) | namespace sql
    type column (line 9) | struct column

FILE: include/sql/index.hpp
  type sql (line 9) | namespace sql
    type index (line 13) | struct index
      type comparator (line 16) | struct comparator
        method compare (line 25) | bool compare(Row const& left, Row const& right) const noexcept

FILE: include/sql/predicate.hpp
  type sql (line 7) | namespace sql
    type value (line 15) | struct value
      method value (line 17) | constexpr value(Type v) : val{ v }
    type operation (line 26) | struct operation
      method eval (line 28) | static constexpr bool eval(Row const& row) noexcept
    type variable (line 70) | struct variable
      method eval (line 72) | static constexpr auto eval(Row const& row) noexcept
    type constant (line 79) | struct constant
      method eval (line 81) | static constexpr auto eval([[maybe_unused]] Row const& row) noexcept

FILE: include/sql/query.hpp
  type sql (line 23) | namespace sql
    type context (line 31) | struct context
    type colinfo (line 38) | struct colinfo
    function exists (line 46) | constexpr bool exists() noexcept
    function convert (line 66) | constexpr value<Type> convert(cexpr::string<Char, N> const& str) noexcept
    function isquote (line 99) | inline constexpr bool isquote(std::string_view const& tv) noexcept
    function isor (line 104) | inline constexpr bool isor(std::string_view const& tv) noexcept
    function isand (line 109) | inline constexpr bool isand(std::string_view const& tv) noexcept
    function isnot (line 114) | inline constexpr bool isnot(std::string_view const& tv) noexcept
    function isnatural (line 119) | inline constexpr bool isnatural(std::string_view const& tv) noexcept
    function isjoin (line 124) | inline constexpr bool isjoin(std::string_view const& tv) noexcept
    function iswhere (line 129) | inline constexpr bool iswhere(std::string_view const& tv) noexcept
    function isfrom (line 134) | inline constexpr bool isfrom(std::string_view const& tv) noexcept
    function isas (line 139) | inline constexpr bool isas(std::string_view const& tv) noexcept
    function isselect (line 144) | inline constexpr bool isselect(std::string_view const& tv) noexcept
    function iscomma (line 149) | inline constexpr bool iscomma(std::string_view const& tv) noexcept
    function isintegral (line 154) | constexpr bool isintegral(std::string_view const& tv) noexcept
    function isdigit (line 166) | constexpr bool isdigit(char c) noexcept
    function iscomp (line 171) | constexpr bool iscomp(char c) noexcept
    function iscolumn (line 176) | constexpr bool iscolumn(std::string_view const& tv) noexcept
    function isseparator (line 181) | constexpr bool isseparator(std::string_view const& tv) noexcept
    class query_iterator (line 190) | class query_iterator
      method query_iterator (line 196) | query_iterator(bool end) : end_{ end }, row_{}
      method row_type (line 211) | inline row_type const& operator*() const noexcept
      method query_iterator (line 216) | query_iterator& operator++()
    class query (line 239) | class query
      method parse_terms (line 244) | static constexpr auto parse_terms()
      method recurse_comparison (line 288) | static constexpr auto recurse_comparison()
      method parse_comparison (line 308) | static constexpr auto parse_comparison()
      method parse_negation (line 317) | static constexpr auto parse_negation()
      method recurse_and (line 336) | static constexpr auto recurse_and()
      method parse_and (line 355) | static constexpr auto parse_and()
      method recurse_or (line 364) | static constexpr auto recurse_or()
      method parse_or (line 383) | static constexpr auto parse_or()
      method recurse_schemas (line 392) | static constexpr auto recurse_schemas()
      method parse_schema (line 408) | static constexpr auto parse_schema()
      method choose_join (line 432) | static constexpr auto choose_join()
      method parse_join (line 446) | static constexpr auto parse_join()
      method parse_from (line 469) | static constexpr auto parse_from()
      method recurse_types (line 496) | static constexpr auto recurse_types()
      method column_type (line 512) | static constexpr auto column_type()
      method next_column (line 521) | static constexpr std::size_t next_column()
      method parse_colinfo (line 536) | static constexpr auto parse_colinfo()
      method recurse_columns (line 566) | static constexpr auto recurse_columns()
      method parse_projection (line 588) | static constexpr auto parse_projection()
      method parse_rename (line 601) | static constexpr auto parse_rename()
      method has_rename (line 613) | static constexpr bool has_rename()
      method parse_root (line 642) | static constexpr auto parse_root()
      method query (line 670) | query(Schemas const&... tables)
      method iterator (line 688) | inline iterator begin() const
      method iterator (line 693) | inline iterator end() const

FILE: include/sql/row.hpp
  type sql (line 9) | namespace sql
    type void_row (line 12) | struct void_row
    class row (line 18) | class row
      method row (line 26) | row() = default;
      method row (line 29) | row(column::type const& val, ColTs const&... vals) : value_{ val }, ...
      method row (line 33) | row(column::type&& val, ColTs&&... vals) : value_{ std::forward<colu...
      method next (line 36) | inline constexpr next const& tail() const noexcept
      method next (line 41) | inline constexpr next& tail() noexcept
    type variadic_row (line 62) | struct variadic_row
      method resolve (line 65) | static inline constexpr auto resolve() noexcept
    function set (line 115) | constexpr void set(Row& r, Type const& value)
  type std (line 132) | namespace std
    class tuple_size<sql::row<Col, Next>> (line 136) | class tuple_size<sql::row<Col, Next>> : public integral_constant<size_...
    type tuple_element<Index, sql::row<Col, Next>> (line 140) | struct tuple_element<Index, sql::row<Col, Next>>

FILE: include/sql/schema.hpp
  type sql (line 15) | namespace sql
    class schema (line 19) | class schema
      method schema (line 33) | schema() = default;
      method schema (line 36) | schema(std::vector<Type> const& col, Types const&... cols) : schema{}
      method schema (line 42) | schema(std::vector<Type>&& col, Types&&... cols) : schema{}
      method emplace (line 48) | inline void emplace(Types const&... vals)
      method emplace (line 61) | inline void emplace(Types&&... vals)
      method insert (line 74) | void insert(std::vector<Type> const& col, Types const&... cols)
      method insert (line 83) | void insert(std::vector<Type>&& col, Types&&... cols)
      method insert (line 91) | void insert(row_type const& row)
      method insert (line 103) | void insert(row_type&& row)
      method const_iterator (line 115) | inline const_iterator begin() const noexcept
      method const_iterator (line 120) | inline const_iterator end() const noexcept
    function fill (line 133) | void fill(std::fstream& fstr, Row& row, [[maybe_unused]] char delim)
    function fill (line 158) | void fill(std::fstream& fstr, Row const& row, char delim)
    function Schema (line 181) | Schema load(std::string const& file, char delim)
    function Schema (line 204) | inline Schema load(std::string const& file)
    function store (line 211) | void store(Type const& data, std::string const& file, char delim)
    function store (line 223) | inline void store(Type const& data, std::string const& file)

FILE: include/sql/tokens.hpp
  type sql (line 10) | namespace sql
    function whitespace (line 16) | constexpr bool whitespace(Char curr)
    function syntax (line 22) | constexpr bool syntax(Char curr)
    function Char (line 29) | constexpr const Char* skip(const Char *curr, const Char *end)
    function Char (line 36) | constexpr const Char* next(const Char *curr, const Char *end)
    class tokens (line 64) | class tokens
      method tokens (line 69) | constexpr tokens() = default;
      method tokens (line 72) | constexpr tokens(cexpr::string<Char, N> const& cs) : tokens_{}
      method count (line 103) | constexpr std::size_t count() const noexcept
      method token_view (line 108) | constexpr token_view* begin() noexcept
      method token_view (line 112) | constexpr const token_view* cbegin() const noexcept
      method token_view (line 117) | constexpr token_view* end() noexcept
      method token_view (line 121) | constexpr const token_view* cend() const noexcept
      method token_view (line 126) | constexpr token_view& operator[](std::size_t i)
      method token_view (line 130) | constexpr token_view const& operator[](std::size_t i) const
    function preprocess (line 140) | constexpr std::size_t preprocess(cexpr::string<Char, N> const& cs) noe...

FILE: single-header/sql.hpp
  type cexpr (line 16) | namespace cexpr
    class string (line 20) | class string
      method string (line 25) | constexpr string() noexcept : size_{ 0 }, string_{ 0 }
      method string (line 28) | constexpr string(const Char(&s)[N]) noexcept : string{}
      method string (line 36) | constexpr string(cexpr::string<Char, N> const& s) noexcept : string{}
      method string (line 44) | constexpr string(std::basic_string_view<Char> const& s) noexcept : s...
      method fill (line 55) | constexpr void fill(const Char* begin, const Char* end) noexcept
      method fill_from (line 60) | constexpr void fill_from(const Char* begin, const Char* end, Char* s...
      method capacity (line 71) | inline constexpr std::size_t capacity() const noexcept
      method size (line 76) | inline constexpr std::size_t size() const noexcept
      method Char (line 81) | inline constexpr Char* begin() noexcept
      method Char (line 85) | inline constexpr const Char* cbegin() const noexcept
      method Char (line 90) | inline constexpr Char* end() noexcept
      method Char (line 94) | inline constexpr const Char* cend() const noexcept
      method Char (line 99) | inline constexpr Char& operator[](std::size_t i)
      method Char (line 103) | inline constexpr Char const& operator[](std::size_t i) const
  type sql (line 170) | namespace sql
    type column (line 174) | struct column
    type void_row (line 186) | struct void_row
    class row (line 192) | class row
      method row (line 200) | row() = default;
      method row (line 203) | row(column::type const& val, ColTs const&... vals) : value_{ val }, ...
      method row (line 207) | row(column::type&& val, ColTs&&... vals) : value_{ std::forward<colu...
      method next (line 210) | inline constexpr next const& tail() const noexcept
      method next (line 215) | inline constexpr next& tail() noexcept
    type variadic_row (line 236) | struct variadic_row
      method resolve (line 239) | static inline constexpr auto resolve() noexcept
    function set (line 289) | constexpr void set(Row& r, Type const& value)
    type index (line 325) | struct index
      type comparator (line 328) | struct comparator
        method compare (line 337) | bool compare(Row const& left, Row const& right) const noexcept
    class schema (line 361) | class schema
      method schema (line 375) | schema() = default;
      method schema (line 378) | schema(std::vector<Type> const& col, Types const&... cols) : schema{}
      method schema (line 384) | schema(std::vector<Type>&& col, Types&&... cols) : schema{}
      method emplace (line 390) | inline void emplace(Types const&... vals)
      method emplace (line 403) | inline void emplace(Types&&... vals)
      method insert (line 416) | void insert(std::vector<Type> const& col, Types const&... cols)
      method insert (line 425) | void insert(std::vector<Type>&& col, Types&&... cols)
      method insert (line 433) | void insert(row_type const& row)
      method insert (line 445) | void insert(row_type&& row)
      method const_iterator (line 457) | inline const_iterator begin() const noexcept
      method const_iterator (line 462) | inline const_iterator end() const noexcept
    function fill (line 475) | void fill(std::fstream& fstr, Row& row, [[maybe_unused]] char delim)
    function fill (line 500) | void fill(std::fstream& fstr, Row const& row, char delim)
    function Schema (line 523) | Schema load(std::string const& file, char delim)
    function Schema (line 546) | inline Schema load(std::string const& file)
    function store (line 553) | void store(Type const& data, std::string const& file, char delim)
    function store (line 565) | inline void store(Type const& data, std::string const& file)
    function whitespace (line 989) | constexpr bool whitespace(Char curr)
    function syntax (line 995) | constexpr bool syntax(Char curr)
    function Char (line 1002) | constexpr const Char* skip(const Char *curr, const Char *end)
    function Char (line 1009) | constexpr const Char* next(const Char *curr, const Char *end)
    class tokens (line 1037) | class tokens
      method tokens (line 1042) | constexpr tokens() = default;
      method tokens (line 1045) | constexpr tokens(cexpr::string<Char, N> const& cs) : tokens_{}
      method count (line 1076) | constexpr std::size_t count() const noexcept
      method token_view (line 1081) | constexpr token_view* begin() noexcept
      method token_view (line 1085) | constexpr const token_view* cbegin() const noexcept
      method token_view (line 1090) | constexpr token_view* end() noexcept
      method token_view (line 1094) | constexpr const token_view* cend() const noexcept
      method token_view (line 1099) | constexpr token_view& operator[](std::size_t i)
      method token_view (line 1103) | constexpr token_view const& operator[](std::size_t i) const
    function preprocess (line 1113) | constexpr std::size_t preprocess(cexpr::string<Char, N> const& cs) noe...
    type value (line 1139) | struct value
      method value (line 1141) | constexpr value(Type v) : val{ v }
    type operation (line 1150) | struct operation
      method eval (line 1152) | static constexpr bool eval(Row const& row) noexcept
    type variable (line 1194) | struct variable
      method eval (line 1196) | static constexpr auto eval(Row const& row) noexcept
    type constant (line 1203) | struct constant
      method eval (line 1205) | static constexpr auto eval([[maybe_unused]] Row const& row) noexcept
    type context (line 1221) | struct context
    type colinfo (line 1228) | struct colinfo
    function exists (line 1236) | constexpr bool exists() noexcept
    function convert (line 1256) | constexpr value<Type> convert(cexpr::string<Char, N> const& str) noexcept
    function isquote (line 1289) | inline constexpr bool isquote(std::string_view const& tv) noexcept
    function isor (line 1294) | inline constexpr bool isor(std::string_view const& tv) noexcept
    function isand (line 1299) | inline constexpr bool isand(std::string_view const& tv) noexcept
    function isnot (line 1304) | inline constexpr bool isnot(std::string_view const& tv) noexcept
    function isnatural (line 1309) | inline constexpr bool isnatural(std::string_view const& tv) noexcept
    function isjoin (line 1314) | inline constexpr bool isjoin(std::string_view const& tv) noexcept
    function iswhere (line 1319) | inline constexpr bool iswhere(std::string_view const& tv) noexcept
    function isfrom (line 1324) | inline constexpr bool isfrom(std::string_view const& tv) noexcept
    function isas (line 1329) | inline constexpr bool isas(std::string_view const& tv) noexcept
    function isselect (line 1334) | inline constexpr bool isselect(std::string_view const& tv) noexcept
    function iscomma (line 1339) | inline constexpr bool iscomma(std::string_view const& tv) noexcept
    function isintegral (line 1344) | constexpr bool isintegral(std::string_view const& tv) noexcept
    function isdigit (line 1356) | constexpr bool isdigit(char c) noexcept
    function iscomp (line 1361) | constexpr bool iscomp(char c) noexcept
    function iscolumn (line 1366) | constexpr bool iscolumn(std::string_view const& tv) noexcept
    function isseparator (line 1371) | constexpr bool isseparator(std::string_view const& tv) noexcept
    class query_iterator (line 1380) | class query_iterator
      method query_iterator (line 1386) | query_iterator(bool end) : end_{ end }, row_{}
      method row_type (line 1401) | inline row_type const& operator*() const noexcept
      method query_iterator (line 1406) | query_iterator& operator++()
    class query (line 1429) | class query
      method parse_terms (line 1434) | static constexpr auto parse_terms()
      method recurse_comparison (line 1478) | static constexpr auto recurse_comparison()
      method parse_comparison (line 1498) | static constexpr auto parse_comparison()
      method parse_negation (line 1507) | static constexpr auto parse_negation()
      method recurse_and (line 1526) | static constexpr auto recurse_and()
      method parse_and (line 1545) | static constexpr auto parse_and()
      method recurse_or (line 1554) | static constexpr auto recurse_or()
      method parse_or (line 1573) | static constexpr auto parse_or()
      method recurse_schemas (line 1582) | static constexpr auto recurse_schemas()
      method parse_schema (line 1598) | static constexpr auto parse_schema()
      method choose_join (line 1622) | static constexpr auto choose_join()
      method parse_join (line 1636) | static constexpr auto parse_join()
      method parse_from (line 1659) | static constexpr auto parse_from()
      method recurse_types (line 1686) | static constexpr auto recurse_types()
      method column_type (line 1702) | static constexpr auto column_type()
      method next_column (line 1711) | static constexpr std::size_t next_column()
      method parse_colinfo (line 1726) | static constexpr auto parse_colinfo()
      method recurse_columns (line 1756) | static constexpr auto recurse_columns()
      method parse_projection (line 1778) | static constexpr auto parse_projection()
      method parse_rename (line 1791) | static constexpr auto parse_rename()
      method has_rename (line 1803) | static constexpr bool has_rename()
      method parse_root (line 1832) | static constexpr auto parse_root()
      method query (line 1860) | query(Schemas const&... tables)
      method iterator (line 1878) | inline iterator begin() const
      method iterator (line 1883) | inline iterator end() const
  type sql (line 183) | namespace sql
    type column (line 174) | struct column
    type void_row (line 186) | struct void_row
    class row (line 192) | class row
      method row (line 200) | row() = default;
      method row (line 203) | row(column::type const& val, ColTs const&... vals) : value_{ val }, ...
      method row (line 207) | row(column::type&& val, ColTs&&... vals) : value_{ std::forward<colu...
      method next (line 210) | inline constexpr next const& tail() const noexcept
      method next (line 215) | inline constexpr next& tail() noexcept
    type variadic_row (line 236) | struct variadic_row
      method resolve (line 239) | static inline constexpr auto resolve() noexcept
    function set (line 289) | constexpr void set(Row& r, Type const& value)
    type index (line 325) | struct index
      type comparator (line 328) | struct comparator
        method compare (line 337) | bool compare(Row const& left, Row const& right) const noexcept
    class schema (line 361) | class schema
      method schema (line 375) | schema() = default;
      method schema (line 378) | schema(std::vector<Type> const& col, Types const&... cols) : schema{}
      method schema (line 384) | schema(std::vector<Type>&& col, Types&&... cols) : schema{}
      method emplace (line 390) | inline void emplace(Types const&... vals)
      method emplace (line 403) | inline void emplace(Types&&... vals)
      method insert (line 416) | void insert(std::vector<Type> const& col, Types const&... cols)
      method insert (line 425) | void insert(std::vector<Type>&& col, Types&&... cols)
      method insert (line 433) | void insert(row_type const& row)
      method insert (line 445) | void insert(row_type&& row)
      method const_iterator (line 457) | inline const_iterator begin() const noexcept
      method const_iterator (line 462) | inline const_iterator end() const noexcept
    function fill (line 475) | void fill(std::fstream& fstr, Row& row, [[maybe_unused]] char delim)
    function fill (line 500) | void fill(std::fstream& fstr, Row const& row, char delim)
    function Schema (line 523) | Schema load(std::string const& file, char delim)
    function Schema (line 546) | inline Schema load(std::string const& file)
    function store (line 553) | void store(Type const& data, std::string const& file, char delim)
    function store (line 565) | inline void store(Type const& data, std::string const& file)
    function whitespace (line 989) | constexpr bool whitespace(Char curr)
    function syntax (line 995) | constexpr bool syntax(Char curr)
    function Char (line 1002) | constexpr const Char* skip(const Char *curr, const Char *end)
    function Char (line 1009) | constexpr const Char* next(const Char *curr, const Char *end)
    class tokens (line 1037) | class tokens
      method tokens (line 1042) | constexpr tokens() = default;
      method tokens (line 1045) | constexpr tokens(cexpr::string<Char, N> const& cs) : tokens_{}
      method count (line 1076) | constexpr std::size_t count() const noexcept
      method token_view (line 1081) | constexpr token_view* begin() noexcept
      method token_view (line 1085) | constexpr const token_view* cbegin() const noexcept
      method token_view (line 1090) | constexpr token_view* end() noexcept
      method token_view (line 1094) | constexpr const token_view* cend() const noexcept
      method token_view (line 1099) | constexpr token_view& operator[](std::size_t i)
      method token_view (line 1103) | constexpr token_view const& operator[](std::size_t i) const
    function preprocess (line 1113) | constexpr std::size_t preprocess(cexpr::string<Char, N> const& cs) noe...
    type value (line 1139) | struct value
      method value (line 1141) | constexpr value(Type v) : val{ v }
    type operation (line 1150) | struct operation
      method eval (line 1152) | static constexpr bool eval(Row const& row) noexcept
    type variable (line 1194) | struct variable
      method eval (line 1196) | static constexpr auto eval(Row const& row) noexcept
    type constant (line 1203) | struct constant
      method eval (line 1205) | static constexpr auto eval([[maybe_unused]] Row const& row) noexcept
    type context (line 1221) | struct context
    type colinfo (line 1228) | struct colinfo
    function exists (line 1236) | constexpr bool exists() noexcept
    function convert (line 1256) | constexpr value<Type> convert(cexpr::string<Char, N> const& str) noexcept
    function isquote (line 1289) | inline constexpr bool isquote(std::string_view const& tv) noexcept
    function isor (line 1294) | inline constexpr bool isor(std::string_view const& tv) noexcept
    function isand (line 1299) | inline constexpr bool isand(std::string_view const& tv) noexcept
    function isnot (line 1304) | inline constexpr bool isnot(std::string_view const& tv) noexcept
    function isnatural (line 1309) | inline constexpr bool isnatural(std::string_view const& tv) noexcept
    function isjoin (line 1314) | inline constexpr bool isjoin(std::string_view const& tv) noexcept
    function iswhere (line 1319) | inline constexpr bool iswhere(std::string_view const& tv) noexcept
    function isfrom (line 1324) | inline constexpr bool isfrom(std::string_view const& tv) noexcept
    function isas (line 1329) | inline constexpr bool isas(std::string_view const& tv) noexcept
    function isselect (line 1334) | inline constexpr bool isselect(std::string_view const& tv) noexcept
    function iscomma (line 1339) | inline constexpr bool iscomma(std::string_view const& tv) noexcept
    function isintegral (line 1344) | constexpr bool isintegral(std::string_view const& tv) noexcept
    function isdigit (line 1356) | constexpr bool isdigit(char c) noexcept
    function iscomp (line 1361) | constexpr bool iscomp(char c) noexcept
    function iscolumn (line 1366) | constexpr bool iscolumn(std::string_view const& tv) noexcept
    function isseparator (line 1371) | constexpr bool isseparator(std::string_view const& tv) noexcept
    class query_iterator (line 1380) | class query_iterator
      method query_iterator (line 1386) | query_iterator(bool end) : end_{ end }, row_{}
      method row_type (line 1401) | inline row_type const& operator*() const noexcept
      method query_iterator (line 1406) | query_iterator& operator++()
    class query (line 1429) | class query
      method parse_terms (line 1434) | static constexpr auto parse_terms()
      method recurse_comparison (line 1478) | static constexpr auto recurse_comparison()
      method parse_comparison (line 1498) | static constexpr auto parse_comparison()
      method parse_negation (line 1507) | static constexpr auto parse_negation()
      method recurse_and (line 1526) | static constexpr auto recurse_and()
      method parse_and (line 1545) | static constexpr auto parse_and()
      method recurse_or (line 1554) | static constexpr auto recurse_or()
      method parse_or (line 1573) | static constexpr auto parse_or()
      method recurse_schemas (line 1582) | static constexpr auto recurse_schemas()
      method parse_schema (line 1598) | static constexpr auto parse_schema()
      method choose_join (line 1622) | static constexpr auto choose_join()
      method parse_join (line 1636) | static constexpr auto parse_join()
      method parse_from (line 1659) | static constexpr auto parse_from()
      method recurse_types (line 1686) | static constexpr auto recurse_types()
      method column_type (line 1702) | static constexpr auto column_type()
      method next_column (line 1711) | static constexpr std::size_t next_column()
      method parse_colinfo (line 1726) | static constexpr auto parse_colinfo()
      method recurse_columns (line 1756) | static constexpr auto recurse_columns()
      method parse_projection (line 1778) | static constexpr auto parse_projection()
      method parse_rename (line 1791) | static constexpr auto parse_rename()
      method has_rename (line 1803) | static constexpr bool has_rename()
      method parse_root (line 1832) | static constexpr auto parse_root()
      method query (line 1860) | query(Schemas const&... tables)
      method iterator (line 1878) | inline iterator begin() const
      method iterator (line 1883) | inline iterator end() const
  type std (line 306) | namespace std
    class tuple_size<sql::row<Col, Next>> (line 310) | class tuple_size<sql::row<Col, Next>> : public integral_constant<size_...
    type tuple_element<Index, sql::row<Col, Next>> (line 314) | struct tuple_element<Index, sql::row<Col, Next>>
  type sql (line 321) | namespace sql
    type column (line 174) | struct column
    type void_row (line 186) | struct void_row
    class row (line 192) | class row
      method row (line 200) | row() = default;
      method row (line 203) | row(column::type const& val, ColTs const&... vals) : value_{ val }, ...
      method row (line 207) | row(column::type&& val, ColTs&&... vals) : value_{ std::forward<colu...
      method next (line 210) | inline constexpr next const& tail() const noexcept
      method next (line 215) | inline constexpr next& tail() noexcept
    type variadic_row (line 236) | struct variadic_row
      method resolve (line 239) | static inline constexpr auto resolve() noexcept
    function set (line 289) | constexpr void set(Row& r, Type const& value)
    type index (line 325) | struct index
      type comparator (line 328) | struct comparator
        method compare (line 337) | bool compare(Row const& left, Row const& right) const noexcept
    class schema (line 361) | class schema
      method schema (line 375) | schema() = default;
      method schema (line 378) | schema(std::vector<Type> const& col, Types const&... cols) : schema{}
      method schema (line 384) | schema(std::vector<Type>&& col, Types&&... cols) : schema{}
      method emplace (line 390) | inline void emplace(Types const&... vals)
      method emplace (line 403) | inline void emplace(Types&&... vals)
      method insert (line 416) | void insert(std::vector<Type> const& col, Types const&... cols)
      method insert (line 425) | void insert(std::vector<Type>&& col, Types&&... cols)
      method insert (line 433) | void insert(row_type const& row)
      method insert (line 445) | void insert(row_type&& row)
      method const_iterator (line 457) | inline const_iterator begin() const noexcept
      method const_iterator (line 462) | inline const_iterator end() const noexcept
    function fill (line 475) | void fill(std::fstream& fstr, Row& row, [[maybe_unused]] char delim)
    function fill (line 500) | void fill(std::fstream& fstr, Row const& row, char delim)
    function Schema (line 523) | Schema load(std::string const& file, char delim)
    function Schema (line 546) | inline Schema load(std::string const& file)
    function store (line 553) | void store(Type const& data, std::string const& file, char delim)
    function store (line 565) | inline void store(Type const& data, std::string const& file)
    function whitespace (line 989) | constexpr bool whitespace(Char curr)
    function syntax (line 995) | constexpr bool syntax(Char curr)
    function Char (line 1002) | constexpr const Char* skip(const Char *curr, const Char *end)
    function Char (line 1009) | constexpr const Char* next(const Char *curr, const Char *end)
    class tokens (line 1037) | class tokens
      method tokens (line 1042) | constexpr tokens() = default;
      method tokens (line 1045) | constexpr tokens(cexpr::string<Char, N> const& cs) : tokens_{}
      method count (line 1076) | constexpr std::size_t count() const noexcept
      method token_view (line 1081) | constexpr token_view* begin() noexcept
      method token_view (line 1085) | constexpr const token_view* cbegin() const noexcept
      method token_view (line 1090) | constexpr token_view* end() noexcept
      method token_view (line 1094) | constexpr const token_view* cend() const noexcept
      method token_view (line 1099) | constexpr token_view& operator[](std::size_t i)
      method token_view (line 1103) | constexpr token_view const& operator[](std::size_t i) const
    function preprocess (line 1113) | constexpr std::size_t preprocess(cexpr::string<Char, N> const& cs) noe...
    type value (line 1139) | struct value
      method value (line 1141) | constexpr value(Type v) : val{ v }
    type operation (line 1150) | struct operation
      method eval (line 1152) | static constexpr bool eval(Row const& row) noexcept
    type variable (line 1194) | struct variable
      method eval (line 1196) | static constexpr auto eval(Row const& row) noexcept
    type constant (line 1203) | struct constant
      method eval (line 1205) | static constexpr auto eval([[maybe_unused]] Row const& row) noexcept
    type context (line 1221) | struct context
    type colinfo (line 1228) | struct colinfo
    function exists (line 1236) | constexpr bool exists() noexcept
    function convert (line 1256) | constexpr value<Type> convert(cexpr::string<Char, N> const& str) noexcept
    function isquote (line 1289) | inline constexpr bool isquote(std::string_view const& tv) noexcept
    function isor (line 1294) | inline constexpr bool isor(std::string_view const& tv) noexcept
    function isand (line 1299) | inline constexpr bool isand(std::string_view const& tv) noexcept
    function isnot (line 1304) | inline constexpr bool isnot(std::string_view const& tv) noexcept
    function isnatural (line 1309) | inline constexpr bool isnatural(std::string_view const& tv) noexcept
    function isjoin (line 1314) | inline constexpr bool isjoin(std::string_view const& tv) noexcept
    function iswhere (line 1319) | inline constexpr bool iswhere(std::string_view const& tv) noexcept
    function isfrom (line 1324) | inline constexpr bool isfrom(std::string_view const& tv) noexcept
    function isas (line 1329) | inline constexpr bool isas(std::string_view const& tv) noexcept
    function isselect (line 1334) | inline constexpr bool isselect(std::string_view const& tv) noexcept
    function iscomma (line 1339) | inline constexpr bool iscomma(std::string_view const& tv) noexcept
    function isintegral (line 1344) | constexpr bool isintegral(std::string_view const& tv) noexcept
    function isdigit (line 1356) | constexpr bool isdigit(char c) noexcept
    function iscomp (line 1361) | constexpr bool iscomp(char c) noexcept
    function iscolumn (line 1366) | constexpr bool iscolumn(std::string_view const& tv) noexcept
    function isseparator (line 1371) | constexpr bool isseparator(std::string_view const& tv) noexcept
    class query_iterator (line 1380) | class query_iterator
      method query_iterator (line 1386) | query_iterator(bool end) : end_{ end }, row_{}
      method row_type (line 1401) | inline row_type const& operator*() const noexcept
      method query_iterator (line 1406) | query_iterator& operator++()
    class query (line 1429) | class query
      method parse_terms (line 1434) | static constexpr auto parse_terms()
      method recurse_comparison (line 1478) | static constexpr auto recurse_comparison()
      method parse_comparison (line 1498) | static constexpr auto parse_comparison()
      method parse_negation (line 1507) | static constexpr auto parse_negation()
      method recurse_and (line 1526) | static constexpr auto recurse_and()
      method parse_and (line 1545) | static constexpr auto parse_and()
      method recurse_or (line 1554) | static constexpr auto recurse_or()
      method parse_or (line 1573) | static constexpr auto parse_or()
      method recurse_schemas (line 1582) | static constexpr auto recurse_schemas()
      method parse_schema (line 1598) | static constexpr auto parse_schema()
      method choose_join (line 1622) | static constexpr auto choose_join()
      method parse_join (line 1636) | static constexpr auto parse_join()
      method parse_from (line 1659) | static constexpr auto parse_from()
      method recurse_types (line 1686) | static constexpr auto recurse_types()
      method column_type (line 1702) | static constexpr auto column_type()
      method next_column (line 1711) | static constexpr std::size_t next_column()
      method parse_colinfo (line 1726) | static constexpr auto parse_colinfo()
      method recurse_columns (line 1756) | static constexpr auto recurse_columns()
      method parse_projection (line 1778) | static constexpr auto parse_projection()
      method parse_rename (line 1791) | static constexpr auto parse_rename()
      method has_rename (line 1803) | static constexpr bool has_rename()
      method parse_root (line 1832) | static constexpr auto parse_root()
      method query (line 1860) | query(Schemas const&... tables)
      method iterator (line 1878) | inline iterator begin() const
      method iterator (line 1883) | inline iterator end() const
  type sql (line 357) | namespace sql
    type column (line 174) | struct column
    type void_row (line 186) | struct void_row
    class row (line 192) | class row
      method row (line 200) | row() = default;
      method row (line 203) | row(column::type const& val, ColTs const&... vals) : value_{ val }, ...
      method row (line 207) | row(column::type&& val, ColTs&&... vals) : value_{ std::forward<colu...
      method next (line 210) | inline constexpr next const& tail() const noexcept
      method next (line 215) | inline constexpr next& tail() noexcept
    type variadic_row (line 236) | struct variadic_row
      method resolve (line 239) | static inline constexpr auto resolve() noexcept
    function set (line 289) | constexpr void set(Row& r, Type const& value)
    type index (line 325) | struct index
      type comparator (line 328) | struct comparator
        method compare (line 337) | bool compare(Row const& left, Row const& right) const noexcept
    class schema (line 361) | class schema
      method schema (line 375) | schema() = default;
      method schema (line 378) | schema(std::vector<Type> const& col, Types const&... cols) : schema{}
      method schema (line 384) | schema(std::vector<Type>&& col, Types&&... cols) : schema{}
      method emplace (line 390) | inline void emplace(Types const&... vals)
      method emplace (line 403) | inline void emplace(Types&&... vals)
      method insert (line 416) | void insert(std::vector<Type> const& col, Types const&... cols)
      method insert (line 425) | void insert(std::vector<Type>&& col, Types&&... cols)
      method insert (line 433) | void insert(row_type const& row)
      method insert (line 445) | void insert(row_type&& row)
      method const_iterator (line 457) | inline const_iterator begin() const noexcept
      method const_iterator (line 462) | inline const_iterator end() const noexcept
    function fill (line 475) | void fill(std::fstream& fstr, Row& row, [[maybe_unused]] char delim)
    function fill (line 500) | void fill(std::fstream& fstr, Row const& row, char delim)
    function Schema (line 523) | Schema load(std::string const& file, char delim)
    function Schema (line 546) | inline Schema load(std::string const& file)
    function store (line 553) | void store(Type const& data, std::string const& file, char delim)
    function store (line 565) | inline void store(Type const& data, std::string const& file)
    function whitespace (line 989) | constexpr bool whitespace(Char curr)
    function syntax (line 995) | constexpr bool syntax(Char curr)
    function Char (line 1002) | constexpr const Char* skip(const Char *curr, const Char *end)
    function Char (line 1009) | constexpr const Char* next(const Char *curr, const Char *end)
    class tokens (line 1037) | class tokens
      method tokens (line 1042) | constexpr tokens() = default;
      method tokens (line 1045) | constexpr tokens(cexpr::string<Char, N> const& cs) : tokens_{}
      method count (line 1076) | constexpr std::size_t count() const noexcept
      method token_view (line 1081) | constexpr token_view* begin() noexcept
      method token_view (line 1085) | constexpr const token_view* cbegin() const noexcept
      method token_view (line 1090) | constexpr token_view* end() noexcept
      method token_view (line 1094) | constexpr const token_view* cend() const noexcept
      method token_view (line 1099) | constexpr token_view& operator[](std::size_t i)
      method token_view (line 1103) | constexpr token_view const& operator[](std::size_t i) const
    function preprocess (line 1113) | constexpr std::size_t preprocess(cexpr::string<Char, N> const& cs) noe...
    type value (line 1139) | struct value
      method value (line 1141) | constexpr value(Type v) : val{ v }
    type operation (line 1150) | struct operation
      method eval (line 1152) | static constexpr bool eval(Row const& row) noexcept
    type variable (line 1194) | struct variable
      method eval (line 1196) | static constexpr auto eval(Row const& row) noexcept
    type constant (line 1203) | struct constant
      method eval (line 1205) | static constexpr auto eval([[maybe_unused]] Row const& row) noexcept
    type context (line 1221) | struct context
    type colinfo (line 1228) | struct colinfo
    function exists (line 1236) | constexpr bool exists() noexcept
    function convert (line 1256) | constexpr value<Type> convert(cexpr::string<Char, N> const& str) noexcept
    function isquote (line 1289) | inline constexpr bool isquote(std::string_view const& tv) noexcept
    function isor (line 1294) | inline constexpr bool isor(std::string_view const& tv) noexcept
    function isand (line 1299) | inline constexpr bool isand(std::string_view const& tv) noexcept
    function isnot (line 1304) | inline constexpr bool isnot(std::string_view const& tv) noexcept
    function isnatural (line 1309) | inline constexpr bool isnatural(std::string_view const& tv) noexcept
    function isjoin (line 1314) | inline constexpr bool isjoin(std::string_view const& tv) noexcept
    function iswhere (line 1319) | inline constexpr bool iswhere(std::string_view const& tv) noexcept
    function isfrom (line 1324) | inline constexpr bool isfrom(std::string_view const& tv) noexcept
    function isas (line 1329) | inline constexpr bool isas(std::string_view const& tv) noexcept
    function isselect (line 1334) | inline constexpr bool isselect(std::string_view const& tv) noexcept
    function iscomma (line 1339) | inline constexpr bool iscomma(std::string_view const& tv) noexcept
    function isintegral (line 1344) | constexpr bool isintegral(std::string_view const& tv) noexcept
    function isdigit (line 1356) | constexpr bool isdigit(char c) noexcept
    function iscomp (line 1361) | constexpr bool iscomp(char c) noexcept
    function iscolumn (line 1366) | constexpr bool iscolumn(std::string_view const& tv) noexcept
    function isseparator (line 1371) | constexpr bool isseparator(std::string_view const& tv) noexcept
    class query_iterator (line 1380) | class query_iterator
      method query_iterator (line 1386) | query_iterator(bool end) : end_{ end }, row_{}
      method row_type (line 1401) | inline row_type const& operator*() const noexcept
      method query_iterator (line 1406) | query_iterator& operator++()
    class query (line 1429) | class query
      method parse_terms (line 1434) | static constexpr auto parse_terms()
      method recurse_comparison (line 1478) | static constexpr auto recurse_comparison()
      method parse_comparison (line 1498) | static constexpr auto parse_comparison()
      method parse_negation (line 1507) | static constexpr auto parse_negation()
      method recurse_and (line 1526) | static constexpr auto recurse_and()
      method parse_and (line 1545) | static constexpr auto parse_and()
      method recurse_or (line 1554) | static constexpr auto recurse_or()
      method parse_or (line 1573) | static constexpr auto parse_or()
      method recurse_schemas (line 1582) | static constexpr auto recurse_schemas()
      method parse_schema (line 1598) | static constexpr auto parse_schema()
      method choose_join (line 1622) | static constexpr auto choose_join()
      method parse_join (line 1636) | static constexpr auto parse_join()
      method parse_from (line 1659) | static constexpr auto parse_from()
      method recurse_types (line 1686) | static constexpr auto recurse_types()
      method column_type (line 1702) | static constexpr auto column_type()
      method next_column (line 1711) | static constexpr std::size_t next_column()
      method parse_colinfo (line 1726) | static constexpr auto parse_colinfo()
      method recurse_columns (line 1756) | static constexpr auto recurse_columns()
      method parse_projection (line 1778) | static constexpr auto parse_projection()
      method parse_rename (line 1791) | static constexpr auto parse_rename()
      method has_rename (line 1803) | static constexpr bool has_rename()
      method parse_root (line 1832) | static constexpr auto parse_root()
      method query (line 1860) | query(Schemas const&... tables)
      method iterator (line 1878) | inline iterator begin() const
      method iterator (line 1883) | inline iterator end() const
  type ra (line 572) | namespace ra
    class unary (line 576) | class unary
      method seed (line 582) | static inline void seed(Inputs const&... rs)
      method reset (line 587) | static inline void reset()
    class binary (line 594) | class binary
      method seed (line 601) | static inline void seed(Inputs const&... rs)
      method reset (line 607) | static inline void reset()
    function recr_merge (line 623) | constexpr auto recr_merge()
    function merge (line 638) | inline constexpr auto merge()
    function recr_copy (line 651) | constexpr void recr_copy(Dest& dest, Row const& src)
    function copy (line 665) | inline constexpr void copy(Dest& dest, Row const& src)
    class join (line 680) | class join : public ra::binary<LeftInput, RightInput>
      method seed (line 689) | static inline void seed(Inputs const&... rs)
      method reset (line 695) | static inline void reset()
    type data_end (line 712) | struct data_end : std::exception
    class relation (line 718) | class relation
      method seed (line 736) | static void seed(Input const& r, Inputs const&... rs) noexcept
      method reset (line 750) | static inline void reset() noexcept
    class cross (line 776) | class cross : public ra::join<LeftInput, RightInput>
    class natural (line 805) | class natural : public ra::join<LeftInput, RightInput>
      method seed (line 815) | static void seed(Inputs const&... rs)
    class projection (line 876) | class projection : public ra::unary<Input>
      method fold (line 891) | static inline constexpr void fold(Dest& dest, input_type const& src)
    class rename (line 916) | class rename : public ra::unary<Input>
      method fold (line 931) | static inline constexpr void fold(Dest& dest, Src const& src)
    class selection (line 956) | class selection : public ra::unary<Input>
  type ra (line 616) | namespace ra
    class unary (line 576) | class unary
      method seed (line 582) | static inline void seed(Inputs const&... rs)
      method reset (line 587) | static inline void reset()
    class binary (line 594) | class binary
      method seed (line 601) | static inline void seed(Inputs const&... rs)
      method reset (line 607) | static inline void reset()
    function recr_merge (line 623) | constexpr auto recr_merge()
    function merge (line 638) | inline constexpr auto merge()
    function recr_copy (line 651) | constexpr void recr_copy(Dest& dest, Row const& src)
    function copy (line 665) | inline constexpr void copy(Dest& dest, Row const& src)
    class join (line 680) | class join : public ra::binary<LeftInput, RightInput>
      method seed (line 689) | static inline void seed(Inputs const&... rs)
      method reset (line 695) | static inline void reset()
    type data_end (line 712) | struct data_end : std::exception
    class relation (line 718) | class relation
      method seed (line 736) | static void seed(Input const& r, Inputs const&... rs) noexcept
      method reset (line 750) | static inline void reset() noexcept
    class cross (line 776) | class cross : public ra::join<LeftInput, RightInput>
    class natural (line 805) | class natural : public ra::join<LeftInput, RightInput>
      method seed (line 815) | static void seed(Inputs const&... rs)
    class projection (line 876) | class projection : public ra::unary<Input>
      method fold (line 891) | static inline constexpr void fold(Dest& dest, input_type const& src)
    class rename (line 916) | class rename : public ra::unary<Input>
      method fold (line 931) | static inline constexpr void fold(Dest& dest, Src const& src)
    class selection (line 956) | class selection : public ra::unary<Input>
  type ra (line 709) | namespace ra
    class unary (line 576) | class unary
      method seed (line 582) | static inline void seed(Inputs const&... rs)
      method reset (line 587) | static inline void reset()
    class binary (line 594) | class binary
      method seed (line 601) | static inline void seed(Inputs const&... rs)
      method reset (line 607) | static inline void reset()
    function recr_merge (line 623) | constexpr auto recr_merge()
    function merge (line 638) | inline constexpr auto merge()
    function recr_copy (line 651) | constexpr void recr_copy(Dest& dest, Row const& src)
    function copy (line 665) | inline constexpr void copy(Dest& dest, Row const& src)
    class join (line 680) | class join : public ra::binary<LeftInput, RightInput>
      method seed (line 689) | static inline void seed(Inputs const&... rs)
      method reset (line 695) | static inline void reset()
    type data_end (line 712) | struct data_end : std::exception
    class relation (line 718) | class relation
      method seed (line 736) | static void seed(Input const& r, Inputs const&... rs) noexcept
      method reset (line 750) | static inline void reset() noexcept
    class cross (line 776) | class cross : public ra::join<LeftInput, RightInput>
    class natural (line 805) | class natural : public ra::join<LeftInput, RightInput>
      method seed (line 815) | static void seed(Inputs const&... rs)
    class projection (line 876) | class projection : public ra::unary<Input>
      method fold (line 891) | static inline constexpr void fold(Dest& dest, input_type const& src)
    class rename (line 916) | class rename : public ra::unary<Input>
      method fold (line 931) | static inline constexpr void fold(Dest& dest, Src const& src)
    class selection (line 956) | class selection : public ra::unary<Input>
  type ra (line 772) | namespace ra
    class unary (line 576) | class unary
      method seed (line 582) | static inline void seed(Inputs const&... rs)
      method reset (line 587) | static inline void reset()
    class binary (line 594) | class binary
      method seed (line 601) | static inline void seed(Inputs const&... rs)
      method reset (line 607) | static inline void reset()
    function recr_merge (line 623) | constexpr auto recr_merge()
    function merge (line 638) | inline constexpr auto merge()
    function recr_copy (line 651) | constexpr void recr_copy(Dest& dest, Row const& src)
    function copy (line 665) | inline constexpr void copy(Dest& dest, Row const& src)
    class join (line 680) | class join : public ra::binary<LeftInput, RightInput>
      method seed (line 689) | static inline void seed(Inputs const&... rs)
      method reset (line 695) | static inline void reset()
    type data_end (line 712) | struct data_end : std::exception
    class relation (line 718) | class relation
      method seed (line 736) | static void seed(Input const& r, Inputs const&... rs) noexcept
      method reset (line 750) | static inline void reset() noexcept
    class cross (line 776) | class cross : public ra::join<LeftInput, RightInput>
    class natural (line 805) | class natural : public ra::join<LeftInput, RightInput>
      method seed (line 815) | static void seed(Inputs const&... rs)
    class projection (line 876) | class projection : public ra::unary<Input>
      method fold (line 891) | static inline constexpr void fold(Dest& dest, input_type const& src)
    class rename (line 916) | class rename : public ra::unary<Input>
      method fold (line 931) | static inline constexpr void fold(Dest& dest, Src const& src)
    class selection (line 956) | class selection : public ra::unary<Input>
  type ra (line 801) | namespace ra
    class unary (line 576) | class unary
      method seed (line 582) | static inline void seed(Inputs const&... rs)
      method reset (line 587) | static inline void reset()
    class binary (line 594) | class binary
      method seed (line 601) | static inline void seed(Inputs const&... rs)
      method reset (line 607) | static inline void reset()
    function recr_merge (line 623) | constexpr auto recr_merge()
    function merge (line 638) | inline constexpr auto merge()
    function recr_copy (line 651) | constexpr void recr_copy(Dest& dest, Row const& src)
    function copy (line 665) | inline constexpr void copy(Dest& dest, Row const& src)
    class join (line 680) | class join : public ra::binary<LeftInput, RightInput>
      method seed (line 689) | static inline void seed(Inputs const&... rs)
      method reset (line 695) | static inline void reset()
    type data_end (line 712) | struct data_end : std::exception
    class relation (line 718) | class relation
      method seed (line 736) | static void seed(Input const& r, Inputs const&... rs) noexcept
      method reset (line 750) | static inline void reset() noexcept
    class cross (line 776) | class cross : public ra::join<LeftInput, RightInput>
    class natural (line 805) | class natural : public ra::join<LeftInput, RightInput>
      method seed (line 815) | static void seed(Inputs const&... rs)
    class projection (line 876) | class projection : public ra::unary<Input>
      method fold (line 891) | static inline constexpr void fold(Dest& dest, input_type const& src)
    class rename (line 916) | class rename : public ra::unary<Input>
      method fold (line 931) | static inline constexpr void fold(Dest& dest, Src const& src)
    class selection (line 956) | class selection : public ra::unary<Input>
  type ra (line 872) | namespace ra
    class unary (line 576) | class unary
      method seed (line 582) | static inline void seed(Inputs const&... rs)
      method reset (line 587) | static inline void reset()
    class binary (line 594) | class binary
      method seed (line 601) | static inline void seed(Inputs const&... rs)
      method reset (line 607) | static inline void reset()
    function recr_merge (line 623) | constexpr auto recr_merge()
    function merge (line 638) | inline constexpr auto merge()
    function recr_copy (line 651) | constexpr void recr_copy(Dest& dest, Row const& src)
    function copy (line 665) | inline constexpr void copy(Dest& dest, Row const& src)
    class join (line 680) | class join : public ra::binary<LeftInput, RightInput>
      method seed (line 689) | static inline void seed(Inputs const&... rs)
      method reset (line 695) | static inline void reset()
    type data_end (line 712) | struct data_end : std::exception
    class relation (line 718) | class relation
      method seed (line 736) | static void seed(Input const& r, Inputs const&... rs) noexcept
      method reset (line 750) | static inline void reset() noexcept
    class cross (line 776) | class cross : public ra::join<LeftInput, RightInput>
    class natural (line 805) | class natural : public ra::join<LeftInput, RightInput>
      method seed (line 815) | static void seed(Inputs const&... rs)
    class projection (line 876) | class projection : public ra::unary<Input>
      method fold (line 891) | static inline constexpr void fold(Dest& dest, input_type const& src)
    class rename (line 916) | class rename : public ra::unary<Input>
      method fold (line 931) | static inline constexpr void fold(Dest& dest, Src const& src)
    class selection (line 956) | class selection : public ra::unary<Input>
  type ra (line 912) | namespace ra
    class unary (line 576) | class unary
      method seed (line 582) | static inline void seed(Inputs const&... rs)
      method reset (line 587) | static inline void reset()
    class binary (line 594) | class binary
      method seed (line 601) | static inline void seed(Inputs const&... rs)
      method reset (line 607) | static inline void reset()
    function recr_merge (line 623) | constexpr auto recr_merge()
    function merge (line 638) | inline constexpr auto merge()
    function recr_copy (line 651) | constexpr void recr_copy(Dest& dest, Row const& src)
    function copy (line 665) | inline constexpr void copy(Dest& dest, Row const& src)
    class join (line 680) | class join : public ra::binary<LeftInput, RightInput>
      method seed (line 689) | static inline void seed(Inputs const&... rs)
      method reset (line 695) | static inline void reset()
    type data_end (line 712) | struct data_end : std::exception
    class relation (line 718) | class relation
      method seed (line 736) | static void seed(Input const& r, Inputs const&... rs) noexcept
      method reset (line 750) | static inline void reset() noexcept
    class cross (line 776) | class cross : public ra::join<LeftInput, RightInput>
    class natural (line 805) | class natural : public ra::join<LeftInput, RightInput>
      method seed (line 815) | static void seed(Inputs const&... rs)
    class projection (line 876) | class projection : public ra::unary<Input>
      method fold (line 891) | static inline constexpr void fold(Dest& dest, input_type const& src)
    class rename (line 916) | class rename : public ra::unary<Input>
      method fold (line 931) | static inline constexpr void fold(Dest& dest, Src const& src)
    class selection (line 956) | class selection : public ra::unary<Input>
  type ra (line 952) | namespace ra
    class unary (line 576) | class unary
      method seed (line 582) | static inline void seed(Inputs const&... rs)
      method reset (line 587) | static inline void reset()
    class binary (line 594) | class binary
      method seed (line 601) | static inline void seed(Inputs const&... rs)
      method reset (line 607) | static inline void reset()
    function recr_merge (line 623) | constexpr auto recr_merge()
    function merge (line 638) | inline constexpr auto merge()
    function recr_copy (line 651) | constexpr void recr_copy(Dest& dest, Row const& src)
    function copy (line 665) | inline constexpr void copy(Dest& dest, Row const& src)
    class join (line 680) | class join : public ra::binary<LeftInput, RightInput>
      method seed (line 689) | static inline void seed(Inputs const&... rs)
      method reset (line 695) | static inline void reset()
    type data_end (line 712) | struct data_end : std::exception
    class relation (line 718) | class relation
      method seed (line 736) | static void seed(Input const& r, Inputs const&... rs) noexcept
      method reset (line 750) | static inline void reset() noexcept
    class cross (line 776) | class cross : public ra::join<LeftInput, RightInput>
    class natural (line 805) | class natural : public ra::join<LeftInput, RightInput>
      method seed (line 815) | static void seed(Inputs const&... rs)
    class projection (line 876) | class projection : public ra::unary<Input>
      method fold (line 891) | static inline constexpr void fold(Dest& dest, input_type const& src)
    class rename (line 916) | class rename : public ra::unary<Input>
      method fold (line 931) | static inline constexpr void fold(Dest& dest, Src const& src)
    class selection (line 956) | class selection : public ra::unary<Input>
  type sql (line 983) | namespace sql
    type column (line 174) | struct column
    type void_row (line 186) | struct void_row
    class row (line 192) | class row
      method row (line 200) | row() = default;
      method row (line 203) | row(column::type const& val, ColTs const&... vals) : value_{ val }, ...
      method row (line 207) | row(column::type&& val, ColTs&&... vals) : value_{ std::forward<colu...
      method next (line 210) | inline constexpr next const& tail() const noexcept
      method next (line 215) | inline constexpr next& tail() noexcept
    type variadic_row (line 236) | struct variadic_row
      method resolve (line 239) | static inline constexpr auto resolve() noexcept
    function set (line 289) | constexpr void set(Row& r, Type const& value)
    type index (line 325) | struct index
      type comparator (line 328) | struct comparator
        method compare (line 337) | bool compare(Row const& left, Row const& right) const noexcept
    class schema (line 361) | class schema
      method schema (line 375) | schema() = default;
      method schema (line 378) | schema(std::vector<Type> const& col, Types const&... cols) : schema{}
      method schema (line 384) | schema(std::vector<Type>&& col, Types&&... cols) : schema{}
      method emplace (line 390) | inline void emplace(Types const&... vals)
      method emplace (line 403) | inline void emplace(Types&&... vals)
      method insert (line 416) | void insert(std::vector<Type> const& col, Types const&... cols)
      method insert (line 425) | void insert(std::vector<Type>&& col, Types&&... cols)
      method insert (line 433) | void insert(row_type const& row)
      method insert (line 445) | void insert(row_type&& row)
      method const_iterator (line 457) | inline const_iterator begin() const noexcept
      method const_iterator (line 462) | inline const_iterator end() const noexcept
    function fill (line 475) | void fill(std::fstream& fstr, Row& row, [[maybe_unused]] char delim)
    function fill (line 500) | void fill(std::fstream& fstr, Row const& row, char delim)
    function Schema (line 523) | Schema load(std::string const& file, char delim)
    function Schema (line 546) | inline Schema load(std::string const& file)
    function store (line 553) | void store(Type const& data, std::string const& file, char delim)
    function store (line 565) | inline void store(Type const& data, std::string const& file)
    function whitespace (line 989) | constexpr bool whitespace(Char curr)
    function syntax (line 995) | constexpr bool syntax(Char curr)
    function Char (line 1002) | constexpr const Char* skip(const Char *curr, const Char *end)
    function Char (line 1009) | constexpr const Char* next(const Char *curr, const Char *end)
    class tokens (line 1037) | class tokens
      method tokens (line 1042) | constexpr tokens() = default;
      method tokens (line 1045) | constexpr tokens(cexpr::string<Char, N> const& cs) : tokens_{}
      method count (line 1076) | constexpr std::size_t count() const noexcept
      method token_view (line 1081) | constexpr token_view* begin() noexcept
      method token_view (line 1085) | constexpr const token_view* cbegin() const noexcept
      method token_view (line 1090) | constexpr token_view* end() noexcept
      method token_view (line 1094) | constexpr const token_view* cend() const noexcept
      method token_view (line 1099) | constexpr token_view& operator[](std::size_t i)
      method token_view (line 1103) | constexpr token_view const& operator[](std::size_t i) const
    function preprocess (line 1113) | constexpr std::size_t preprocess(cexpr::string<Char, N> const& cs) noe...
    type value (line 1139) | struct value
      method value (line 1141) | constexpr value(Type v) : val{ v }
    type operation (line 1150) | struct operation
      method eval (line 1152) | static constexpr bool eval(Row const& row) noexcept
    type variable (line 1194) | struct variable
      method eval (line 1196) | static constexpr auto eval(Row const& row) noexcept
    type constant (line 1203) | struct constant
      method eval (line 1205) | static constexpr auto eval([[maybe_unused]] Row const& row) noexcept
    type context (line 1221) | struct context
    type colinfo (line 1228) | struct colinfo
    function exists (line 1236) | constexpr bool exists() noexcept
    function convert (line 1256) | constexpr value<Type> convert(cexpr::string<Char, N> const& str) noexcept
    function isquote (line 1289) | inline constexpr bool isquote(std::string_view const& tv) noexcept
    function isor (line 1294) | inline constexpr bool isor(std::string_view const& tv) noexcept
    function isand (line 1299) | inline constexpr bool isand(std::string_view const& tv) noexcept
    function isnot (line 1304) | inline constexpr bool isnot(std::string_view const& tv) noexcept
    function isnatural (line 1309) | inline constexpr bool isnatural(std::string_view const& tv) noexcept
    function isjoin (line 1314) | inline constexpr bool isjoin(std::string_view const& tv) noexcept
    function iswhere (line 1319) | inline constexpr bool iswhere(std::string_view const& tv) noexcept
    function isfrom (line 1324) | inline constexpr bool isfrom(std::string_view const& tv) noexcept
    function isas (line 1329) | inline constexpr bool isas(std::string_view const& tv) noexcept
    function isselect (line 1334) | inline constexpr bool isselect(std::string_view const& tv) noexcept
    function iscomma (line 1339) | inline constexpr bool iscomma(std::string_view const& tv) noexcept
    function isintegral (line 1344) | constexpr bool isintegral(std::string_view const& tv) noexcept
    function isdigit (line 1356) | constexpr bool isdigit(char c) noexcept
    function iscomp (line 1361) | constexpr bool iscomp(char c) noexcept
    function iscolumn (line 1366) | constexpr bool iscolumn(std::string_view const& tv) noexcept
    function isseparator (line 1371) | constexpr bool isseparator(std::string_view const& tv) noexcept
    class query_iterator (line 1380) | class query_iterator
      method query_iterator (line 1386) | query_iterator(bool end) : end_{ end }, row_{}
      method row_type (line 1401) | inline row_type const& operator*() const noexcept
      method query_iterator (line 1406) | query_iterator& operator++()
    class query (line 1429) | class query
      method parse_terms (line 1434) | static constexpr auto parse_terms()
      method recurse_comparison (line 1478) | static constexpr auto recurse_comparison()
      method parse_comparison (line 1498) | static constexpr auto parse_comparison()
      method parse_negation (line 1507) | static constexpr auto parse_negation()
      method recurse_and (line 1526) | static constexpr auto recurse_and()
      method parse_and (line 1545) | static constexpr auto parse_and()
      method recurse_or (line 1554) | static constexpr auto recurse_or()
      method parse_or (line 1573) | static constexpr auto parse_or()
      method recurse_schemas (line 1582) | static constexpr auto recurse_schemas()
      method parse_schema (line 1598) | static constexpr auto parse_schema()
      method choose_join (line 1622) | static constexpr auto choose_join()
      method parse_join (line 1636) | static constexpr auto parse_join()
      method parse_from (line 1659) | static constexpr auto parse_from()
      method recurse_types (line 1686) | static constexpr auto recurse_types()
      method column_type (line 1702) | static constexpr auto column_type()
      method next_column (line 1711) | static constexpr std::size_t next_column()
      method parse_colinfo (line 1726) | static constexpr auto parse_colinfo()
      method recurse_columns (line 1756) | static constexpr auto recurse_columns()
      method parse_projection (line 1778) | static constexpr auto parse_projection()
      method parse_rename (line 1791) | static constexpr auto parse_rename()
      method has_rename (line 1803) | static constexpr bool has_rename()
      method parse_root (line 1832) | static constexpr auto parse_root()
      method query (line 1860) | query(Schemas const&... tables)
      method iterator (line 1878) | inline iterator begin() const
      method iterator (line 1883) | inline iterator end() const
  type sql (line 1131) | namespace sql
    type column (line 174) | struct column
    type void_row (line 186) | struct void_row
    class row (line 192) | class row
      method row (line 200) | row() = default;
      method row (line 203) | row(column::type const& val, ColTs const&... vals) : value_{ val }, ...
      method row (line 207) | row(column::type&& val, ColTs&&... vals) : value_{ std::forward<colu...
      method next (line 210) | inline constexpr next const& tail() const noexcept
      method next (line 215) | inline constexpr next& tail() noexcept
    type variadic_row (line 236) | struct variadic_row
      method resolve (line 239) | static inline constexpr auto resolve() noexcept
    function set (line 289) | constexpr void set(Row& r, Type const& value)
    type index (line 325) | struct index
      type comparator (line 328) | struct comparator
        method compare (line 337) | bool compare(Row const& left, Row const& right) const noexcept
    class schema (line 361) | class schema
      method schema (line 375) | schema() = default;
      method schema (line 378) | schema(std::vector<Type> const& col, Types const&... cols) : schema{}
      method schema (line 384) | schema(std::vector<Type>&& col, Types&&... cols) : schema{}
      method emplace (line 390) | inline void emplace(Types const&... vals)
      method emplace (line 403) | inline void emplace(Types&&... vals)
      method insert (line 416) | void insert(std::vector<Type> const& col, Types const&... cols)
      method insert (line 425) | void insert(std::vector<Type>&& col, Types&&... cols)
      method insert (line 433) | void insert(row_type const& row)
      method insert (line 445) | void insert(row_type&& row)
      method const_iterator (line 457) | inline const_iterator begin() const noexcept
      method const_iterator (line 462) | inline const_iterator end() const noexcept
    function fill (line 475) | void fill(std::fstream& fstr, Row& row, [[maybe_unused]] char delim)
    function fill (line 500) | void fill(std::fstream& fstr, Row const& row, char delim)
    function Schema (line 523) | Schema load(std::string const& file, char delim)
    function Schema (line 546) | inline Schema load(std::string const& file)
    function store (line 553) | void store(Type const& data, std::string const& file, char delim)
    function store (line 565) | inline void store(Type const& data, std::string const& file)
    function whitespace (line 989) | constexpr bool whitespace(Char curr)
    function syntax (line 995) | constexpr bool syntax(Char curr)
    function Char (line 1002) | constexpr const Char* skip(const Char *curr, const Char *end)
    function Char (line 1009) | constexpr const Char* next(const Char *curr, const Char *end)
    class tokens (line 1037) | class tokens
      method tokens (line 1042) | constexpr tokens() = default;
      method tokens (line 1045) | constexpr tokens(cexpr::string<Char, N> const& cs) : tokens_{}
      method count (line 1076) | constexpr std::size_t count() const noexcept
      method token_view (line 1081) | constexpr token_view* begin() noexcept
      method token_view (line 1085) | constexpr const token_view* cbegin() const noexcept
      method token_view (line 1090) | constexpr token_view* end() noexcept
      method token_view (line 1094) | constexpr const token_view* cend() const noexcept
      method token_view (line 1099) | constexpr token_view& operator[](std::size_t i)
      method token_view (line 1103) | constexpr token_view const& operator[](std::size_t i) const
    function preprocess (line 1113) | constexpr std::size_t preprocess(cexpr::string<Char, N> const& cs) noe...
    type value (line 1139) | struct value
      method value (line 1141) | constexpr value(Type v) : val{ v }
    type operation (line 1150) | struct operation
      method eval (line 1152) | static constexpr bool eval(Row const& row) noexcept
    type variable (line 1194) | struct variable
      method eval (line 1196) | static constexpr auto eval(Row const& row) noexcept
    type constant (line 1203) | struct constant
      method eval (line 1205) | static constexpr auto eval([[maybe_unused]] Row const& row) noexcept
    type context (line 1221) | struct context
    type colinfo (line 1228) | struct colinfo
    function exists (line 1236) | constexpr bool exists() noexcept
    function convert (line 1256) | constexpr value<Type> convert(cexpr::string<Char, N> const& str) noexcept
    function isquote (line 1289) | inline constexpr bool isquote(std::string_view const& tv) noexcept
    function isor (line 1294) | inline constexpr bool isor(std::string_view const& tv) noexcept
    function isand (line 1299) | inline constexpr bool isand(std::string_view const& tv) noexcept
    function isnot (line 1304) | inline constexpr bool isnot(std::string_view const& tv) noexcept
    function isnatural (line 1309) | inline constexpr bool isnatural(std::string_view const& tv) noexcept
    function isjoin (line 1314) | inline constexpr bool isjoin(std::string_view const& tv) noexcept
    function iswhere (line 1319) | inline constexpr bool iswhere(std::string_view const& tv) noexcept
    function isfrom (line 1324) | inline constexpr bool isfrom(std::string_view const& tv) noexcept
    function isas (line 1329) | inline constexpr bool isas(std::string_view const& tv) noexcept
    function isselect (line 1334) | inline constexpr bool isselect(std::string_view const& tv) noexcept
    function iscomma (line 1339) | inline constexpr bool iscomma(std::string_view const& tv) noexcept
    function isintegral (line 1344) | constexpr bool isintegral(std::string_view const& tv) noexcept
    function isdigit (line 1356) | constexpr bool isdigit(char c) noexcept
    function iscomp (line 1361) | constexpr bool iscomp(char c) noexcept
    function iscolumn (line 1366) | constexpr bool iscolumn(std::string_view const& tv) noexcept
    function isseparator (line 1371) | constexpr bool isseparator(std::string_view const& tv) noexcept
    class query_iterator (line 1380) | class query_iterator
      method query_iterator (line 1386) | query_iterator(bool end) : end_{ end }, row_{}
      method row_type (line 1401) | inline row_type const& operator*() const noexcept
      method query_iterator (line 1406) | query_iterator& operator++()
    class query (line 1429) | class query
      method parse_terms (line 1434) | static constexpr auto parse_terms()
      method recurse_comparison (line 1478) | static constexpr auto recurse_comparison()
      method parse_comparison (line 1498) | static constexpr auto parse_comparison()
      method parse_negation (line 1507) | static constexpr auto parse_negation()
      method recurse_and (line 1526) | static constexpr auto recurse_and()
      method parse_and (line 1545) | static constexpr auto parse_and()
      method recurse_or (line 1554) | static constexpr auto recurse_or()
      method parse_or (line 1573) | static constexpr auto parse_or()
      method recurse_schemas (line 1582) | static constexpr auto recurse_schemas()
      method parse_schema (line 1598) | static constexpr auto parse_schema()
      method choose_join (line 1622) | static constexpr auto choose_join()
      method parse_join (line 1636) | static constexpr auto parse_join()
      method parse_from (line 1659) | static constexpr auto parse_from()
      method recurse_types (line 1686) | static constexpr auto recurse_types()
      method column_type (line 1702) | static constexpr auto column_type()
      method next_column (line 1711) | static constexpr std::size_t next_column()
      method parse_colinfo (line 1726) | static constexpr auto parse_colinfo()
      method recurse_columns (line 1756) | static constexpr auto recurse_columns()
      method parse_projection (line 1778) | static constexpr auto parse_projection()
      method parse_rename (line 1791) | static constexpr auto parse_rename()
      method has_rename (line 1803) | static constexpr bool has_rename()
      method parse_root (line 1832) | static constexpr auto parse_root()
      method query (line 1860) | query(Schemas const&... tables)
      method iterator (line 1878) | inline iterator begin() const
      method iterator (line 1883) | inline iterator end() const
  type sql (line 1213) | namespace sql
    type column (line 174) | struct column
    type void_row (line 186) | struct void_row
    class row (line 192) | class row
      method row (line 200) | row() = default;
      method row (line 203) | row(column::type const& val, ColTs const&... vals) : value_{ val }, ...
      method row (line 207) | row(column::type&& val, ColTs&&... vals) : value_{ std::forward<colu...
      method next (line 210) | inline constexpr next const& tail() const noexcept
      method next (line 215) | inline constexpr next& tail() noexcept
    type variadic_row (line 236) | struct variadic_row
      method resolve (line 239) | static inline constexpr auto resolve() noexcept
    function set (line 289) | constexpr void set(Row& r, Type const& value)
    type index (line 325) | struct index
      type comparator (line 328) | struct comparator
        method compare (line 337) | bool compare(Row const& left, Row const& right) const noexcept
    class schema (line 361) | class schema
      method schema (line 375) | schema() = default;
      method schema (line 378) | schema(std::vector<Type> const& col, Types const&... cols) : schema{}
      method schema (line 384) | schema(std::vector<Type>&& col, Types&&... cols) : schema{}
      method emplace (line 390) | inline void emplace(Types const&... vals)
      method emplace (line 403) | inline void emplace(Types&&... vals)
      method insert (line 416) | void insert(std::vector<Type> const& col, Types const&... cols)
      method insert (line 425) | void insert(std::vector<Type>&& col, Types&&... cols)
      method insert (line 433) | void insert(row_type const& row)
      method insert (line 445) | void insert(row_type&& row)
      method const_iterator (line 457) | inline const_iterator begin() const noexcept
      method const_iterator (line 462) | inline const_iterator end() const noexcept
    function fill (line 475) | void fill(std::fstream& fstr, Row& row, [[maybe_unused]] char delim)
    function fill (line 500) | void fill(std::fstream& fstr, Row const& row, char delim)
    function Schema (line 523) | Schema load(std::string const& file, char delim)
    function Schema (line 546) | inline Schema load(std::string const& file)
    function store (line 553) | void store(Type const& data, std::string const& file, char delim)
    function store (line 565) | inline void store(Type const& data, std::string const& file)
    function whitespace (line 989) | constexpr bool whitespace(Char curr)
    function syntax (line 995) | constexpr bool syntax(Char curr)
    function Char (line 1002) | constexpr const Char* skip(const Char *curr, const Char *end)
    function Char (line 1009) | constexpr const Char* next(const Char *curr, const Char *end)
    class tokens (line 1037) | class tokens
      method tokens (line 1042) | constexpr tokens() = default;
      method tokens (line 1045) | constexpr tokens(cexpr::string<Char, N> const& cs) : tokens_{}
      method count (line 1076) | constexpr std::size_t count() const noexcept
      method token_view (line 1081) | constexpr token_view* begin() noexcept
      method token_view (line 1085) | constexpr const token_view* cbegin() const noexcept
      method token_view (line 1090) | constexpr token_view* end() noexcept
      method token_view (line 1094) | constexpr const token_view* cend() const noexcept
      method token_view (line 1099) | constexpr token_view& operator[](std::size_t i)
      method token_view (line 1103) | constexpr token_view const& operator[](std::size_t i) const
    function preprocess (line 1113) | constexpr std::size_t preprocess(cexpr::string<Char, N> const& cs) noe...
    type value (line 1139) | struct value
      method value (line 1141) | constexpr value(Type v) : val{ v }
    type operation (line 1150) | struct operation
      method eval (line 1152) | static constexpr bool eval(Row const& row) noexcept
    type variable (line 1194) | struct variable
      method eval (line 1196) | static constexpr auto eval(Row const& row) noexcept
    type constant (line 1203) | struct constant
      method eval (line 1205) | static constexpr auto eval([[maybe_unused]] Row const& row) noexcept
    type context (line 1221) | struct context
    type colinfo (line 1228) | struct colinfo
    function exists (line 1236) | constexpr bool exists() noexcept
    function convert (line 1256) | constexpr value<Type> convert(cexpr::string<Char, N> const& str) noexcept
    function isquote (line 1289) | inline constexpr bool isquote(std::string_view const& tv) noexcept
    function isor (line 1294) | inline constexpr bool isor(std::string_view const& tv) noexcept
    function isand (line 1299) | inline constexpr bool isand(std::string_view const& tv) noexcept
    function isnot (line 1304) | inline constexpr bool isnot(std::string_view const& tv) noexcept
    function isnatural (line 1309) | inline constexpr bool isnatural(std::string_view const& tv) noexcept
    function isjoin (line 1314) | inline constexpr bool isjoin(std::string_view const& tv) noexcept
    function iswhere (line 1319) | inline constexpr bool iswhere(std::string_view const& tv) noexcept
    function isfrom (line 1324) | inline constexpr bool isfrom(std::string_view const& tv) noexcept
    function isas (line 1329) | inline constexpr bool isas(std::string_view const& tv) noexcept
    function isselect (line 1334) | inline constexpr bool isselect(std::string_view const& tv) noexcept
    function iscomma (line 1339) | inline constexpr bool iscomma(std::string_view const& tv) noexcept
    function isintegral (line 1344) | constexpr bool isintegral(std::string_view const& tv) noexcept
    function isdigit (line 1356) | constexpr bool isdigit(char c) noexcept
    function iscomp (line 1361) | constexpr bool iscomp(char c) noexcept
    function iscolumn (line 1366) | constexpr bool iscolumn(std::string_view const& tv) noexcept
    function isseparator (line 1371) | constexpr bool isseparator(std::string_view const& tv) noexcept
    class query_iterator (line 1380) | class query_iterator
      method query_iterator (line 1386) | query_iterator(bool end) : end_{ end }, row_{}
      method row_type (line 1401) | inline row_type const& operator*() const noexcept
      method query_iterator (line 1406) | query_iterator& operator++()
    class query (line 1429) | class query
      method parse_terms (line 1434) | static constexpr auto parse_terms()
      method recurse_comparison (line 1478) | static constexpr auto recurse_comparison()
      method parse_comparison (line 1498) | static constexpr auto parse_comparison()
      method parse_negation (line 1507) | static constexpr auto parse_negation()
      method recurse_and (line 1526) | static constexpr auto recurse_and()
      method parse_and (line 1545) | static constexpr auto parse_and()
      method recurse_or (line 1554) | static constexpr auto recurse_or()
      method parse_or (line 1573) | static constexpr auto parse_or()
      method recurse_schemas (line 1582) | static constexpr auto recurse_schemas()
      method parse_schema (line 1598) | static constexpr auto parse_schema()
      method choose_join (line 1622) | static constexpr auto choose_join()
      method parse_join (line 1636) | static constexpr auto parse_join()
      method parse_from (line 1659) | static constexpr auto parse_from()
      method recurse_types (line 1686) | static constexpr auto recurse_types()
      method column_type (line 1702) | static constexpr auto column_type()
      method next_column (line 1711) | static constexpr std::size_t next_column()
      method parse_colinfo (line 1726) | static constexpr auto parse_colinfo()
      method recurse_columns (line 1756) | static constexpr auto recurse_columns()
      method parse_projection (line 1778) | static constexpr auto parse_projection()
      method parse_rename (line 1791) | static constexpr auto parse_rename()
      method has_rename (line 1803) | static constexpr bool has_rename()
      method parse_root (line 1832) | static constexpr auto parse_root()
      method query (line 1860) | query(Schemas const&... tables)
      method iterator (line 1878) | inline iterator begin() const
      method iterator (line 1883) | inline iterator end() const

FILE: tests/data.hpp
  function books_type (line 68) | books_type books_load()
  function stories_type (line 93) | stories_type stories_load()
  function authored_type (line 117) | authored_type authored_load()
  function collected_type (line 140) | collected_type collected_load()

FILE: tests/perf/queries/lib-query0.cpp
  function main (line 12) | int main()

FILE: tests/perf/queries/lib-query1.cpp
  function main (line 12) | int main()

FILE: tests/perf/queries/lib-query2.cpp
  function main (line 13) | int main()

FILE: tests/perf/queries/lib-query3.cpp
  function main (line 13) | int main()

FILE: tests/perf/queries/lib-query4.cpp
  function main (line 13) | int main()

FILE: tests/perf/queries/lib-query5.cpp
  function main (line 13) | int main()

FILE: tests/perf/queries/query0.cpp
  function stories_type (line 10) | stories_type query(stories_type const& s)
  function main (line 26) | int main()

FILE: tests/perf/queries/query1.cpp
  function books_type (line 10) | books_type query(books_type const& b)
  function main (line 26) | int main()

FILE: tests/perf/queries/query2.cpp
  function authored_type (line 10) | authored_type query(books_type const& b, authored_type const& a)
  function main (line 39) | int main()

FILE: tests/perf/queries/query3.cpp
  function output_type (line 12) | output_type query(stories_type const& s, authored_type const& a)
  function main (line 41) | int main()

FILE: tests/perf/queries/query4.cpp
  function output_type (line 12) | output_type query(books_type const& b, authored_type const& a)
  function main (line 31) | int main()

FILE: tests/perf/queries/query5.cpp
  function output_type (line 12) | output_type query(stories_type const& s, collected_type const& c)
  function main (line 31) | int main()

FILE: tests/perf/scripts/runner.py
  function exe (line 5) | def exe(file, q):
  function main (line 13) | def main():

FILE: tests/scripts/compose.py
  function data (line 21) | def data(tokens):
  function templ (line 37) | def templ(query, ts):
  function func (line 43) | def func(ts, cs):
  function main (line 59) | def main():

FILE: tests/scripts/generate.py
  function col_list (line 41) | def col_list(cs):
  function froms (line 60) | def froms(ts):
  function compose (line 73) | def compose(ts, cs, pred):
  function next (line 82) | def next(cs, ci):
  function predicate (line 92) | def predicate(ts, cs, ci, pred):
  function operation (line 103) | def operation(ts, cs, ci, pred):
  function select (line 122) | def select(ts):
  function root_query (line 135) | def root_query(left):
  function main (line 140) | def main():

FILE: tests/scripts/runner.py
  function main (line 3) | def main():

FILE: tests/scripts/select.py
  function main (line 5) | def main():
Condensed preview — 59 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (266K chars).
[
  {
    "path": ".gitattributes",
    "chars": 66,
    "preview": "# Auto detect text files and perform LF normalization\n* text=auto\n"
  },
  {
    "path": ".gitignore",
    "chars": 82,
    "preview": "tests/*.txt\ntests/test.cpp\ntests/test\ntests/queries/*\n.vscode/*\nexample\n.DS_STORE\n"
  },
  {
    "path": "LICENSE",
    "chars": 1071,
    "preview": "MIT License\n\nCopyright (c) 2020 Michael Kitzan\n\nPermission is hereby granted, free of charge, to any person obtaining a "
  },
  {
    "path": "README.md",
    "chars": 18437,
    "preview": "# Constexpr SQL\n\nA light weight single header alternative to DBMS\n\nThis library was developed during my honors project a"
  },
  {
    "path": "example.cpp",
    "chars": 973,
    "preview": "#include <iostream>\n#include <string>\n\n#include \"sql.hpp\"\n\nusing books =\n\tsql::schema<\n\t\t\"books\", sql::index<\"title\">,\n\t"
  },
  {
    "path": "generator.py",
    "chars": 920,
    "preview": "import os\n\ndef include(header, incs, root, included):\n\tfile = open(\"include/\" + root, \"r\")\n\n\tfor line in file:\n\t\tif line"
  },
  {
    "path": "include/cexpr/string.hpp",
    "chars": 3107,
    "preview": "#pragma once\n\n#include <cstddef>\n#include <string>\n#include <string_view>\n\nnamespace cexpr\n{\n\n\ttemplate <typename Char, "
  },
  {
    "path": "include/ra/cross.hpp",
    "chars": 640,
    "preview": "#pragma once\n\n#include \"ra/join.hpp\"\n#include \"ra/relation.hpp\"\n\nnamespace ra\n{\n\n\ttemplate <typename LeftInput, typename"
  },
  {
    "path": "include/ra/join.hpp",
    "chars": 2035,
    "preview": "#pragma once\n\n#include <type_traits>\n\n#include \"ra/operation.hpp\"\n\n#include \"sql/row.hpp\"\n\nnamespace ra\n{\n\n\tnamespace\n\t{"
  },
  {
    "path": "include/ra/natural.hpp",
    "chars": 2018,
    "preview": "#pragma once\n\n#include <type_traits>\n#include <vector>\n#include <unordered_map>\n\n#include \"ra/join.hpp\"\n#include \"ra/rel"
  },
  {
    "path": "include/ra/operation.hpp",
    "chars": 817,
    "preview": "#pragma once\n\n#include <type_traits>\n\nnamespace ra\n{\n\n\ttemplate <typename Input>\n\tclass unary\n\t{\n\tpublic:\n\t\tusing input_"
  },
  {
    "path": "include/ra/projection.hpp",
    "chars": 879,
    "preview": "#pragma once\n\n#include \"ra/operation.hpp\"\n\n#include \"sql/row.hpp\"\n\nnamespace ra\n{\n\n\ttemplate <typename Output, typename "
  },
  {
    "path": "include/ra/relation.hpp",
    "chars": 1307,
    "preview": "#pragma once\n\n#include <exception>\n#include <type_traits>\n\nnamespace ra\n{\n\n\tstruct data_end : std::exception\n\t{};\n\n\t// I"
  },
  {
    "path": "include/ra/rename.hpp",
    "chars": 889,
    "preview": "#pragma once\n\n#include \"ra/operation.hpp\"\n\n#include \"sql/row.hpp\"\n\nnamespace ra\n{\n\n\ttemplate <typename Output, typename "
  },
  {
    "path": "include/ra/selection.hpp",
    "chars": 636,
    "preview": "#pragma once\n\n#include \"ra/operation.hpp\"\n\nnamespace ra\n{\n\n\ttemplate <typename Predicate, typename Input>\n\tclass selecti"
  },
  {
    "path": "include/sql/column.hpp",
    "chars": 210,
    "preview": "#pragma once\n\n#include \"cexpr/string.hpp\"\n\nnamespace sql\n{\n\n\ttemplate <cexpr::string Name, typename Type>\n\tstruct column"
  },
  {
    "path": "include/sql/index.hpp",
    "chars": 751,
    "preview": "#pragma once\n\n#include <type_traits>\n\n#include \"cexpr/string.hpp\"\n\n#include \"sql/row.hpp\"\n\nnamespace sql\n{\n\n\ttemplate <c"
  },
  {
    "path": "include/sql/predicate.hpp",
    "chars": 1645,
    "preview": "#pragma once\n\n#include <cstddef>\n\n#include \"cexpr/string.hpp\"\n\nnamespace sql\n{\n\n\tnamespace\n\t{\n\n\t\t// shim to allow all va"
  },
  {
    "path": "include/sql/query.hpp",
    "chars": 16378,
    "preview": "#pragma once\n\n#include <array>\n#include <string>\n#include <string_view>\n#include <type_traits>\n\n#include \"cexpr/string.h"
  },
  {
    "path": "include/sql/row.hpp",
    "chars": 2928,
    "preview": "#pragma once\n\n#include <type_traits>\n#include <utility>\n#include <vector>\n\n#include \"cexpr/string.hpp\"\n\nnamespace sql\n{\n"
  },
  {
    "path": "include/sql/schema.hpp",
    "chars": 4656,
    "preview": "#pragma once\n\n#include <fstream>\n#include <set>\n#include <type_traits>\n#include <utility>\n#include <vector>\n\n#include \"c"
  },
  {
    "path": "include/sql/tokens.hpp",
    "chars": 3079,
    "preview": "#pragma once\n\n#include <array>\n#include <cstddef>\n#include <locale>\n#include <string_view>\n\n#include \"cexpr/string.hpp\"\n"
  },
  {
    "path": "single-header/sql.hpp",
    "chars": 40556,
    "preview": "#pragma once\n\n#include <array>\n#include <cstddef>\n#include <exception>\n#include <fstream>\n#include <locale>\n#include <se"
  },
  {
    "path": "tests/data/authored.tsv",
    "chars": 38172,
    "preview": "1984\tGeorge Orwell\n!!!The!!Teddy!Crazy!!Show!!!\tHarlan Ellison\n(Learning About) Machine Sex\tCandas Jane Dorsey\n...the Wo"
  },
  {
    "path": "tests/data/books.tsv",
    "chars": 14092,
    "preview": "1984\tscience fiction\t1950\t328\n2001: A Space Odyssey\tscience fiction\t1968\t221\n20th Century Boys vol.1\tscience fiction\t201"
  },
  {
    "path": "tests/data/collected.tsv",
    "chars": 34720,
    "preview": "!!!The!!Teddy!Crazy!!Show!!!\tStalking the Nightmare\t14\n(Learning About) Machine Sex\tThe Norton Book of Science Fiction\t1"
  },
  {
    "path": "tests/data/stories.tsv",
    "chars": 29242,
    "preview": "!!!The!!Teddy!Crazy!!Show!!!\tscience fiction\t1968\n(Learning About) Machine Sex\tscience fiction\t1988\n...the World, as we "
  },
  {
    "path": "tests/data.hpp",
    "chars": 3314,
    "preview": "#pragma once\n\n#include <string>\n#include <type_traits>\n\n#include \"sql.hpp\"\n\nusing books =\n\tsql::schema<\n\t\t\"books\", sql::"
  },
  {
    "path": "tests/perf/data/lib-query0",
    "chars": 10,
    "preview": "6.81 user\n"
  },
  {
    "path": "tests/perf/data/lib-query1",
    "chars": 10,
    "preview": "4.73 user\n"
  },
  {
    "path": "tests/perf/data/lib-query2",
    "chars": 10,
    "preview": "3.70 user\n"
  },
  {
    "path": "tests/perf/data/lib-query3",
    "chars": 11,
    "preview": "11.81 user\n"
  },
  {
    "path": "tests/perf/data/lib-query4",
    "chars": 10,
    "preview": "1.54 user\n"
  },
  {
    "path": "tests/perf/data/lib-query5",
    "chars": 11,
    "preview": "38.04 user\n"
  },
  {
    "path": "tests/perf/data/query0",
    "chars": 10,
    "preview": "6.39 user\n"
  },
  {
    "path": "tests/perf/data/query1",
    "chars": 10,
    "preview": "4.18 user\n"
  },
  {
    "path": "tests/perf/data/query2",
    "chars": 11,
    "preview": "11.17 user\n"
  },
  {
    "path": "tests/perf/data/query3",
    "chars": 11,
    "preview": "12.39 user\n"
  },
  {
    "path": "tests/perf/data/query4",
    "chars": 10,
    "preview": "3.45 user\n"
  },
  {
    "path": "tests/perf/data/query5",
    "chars": 11,
    "preview": "44.35 user\n"
  },
  {
    "path": "tests/perf/queries/lib-query0.cpp",
    "chars": 474,
    "preview": "#include <iostream>\n#include \"../../data.hpp\"\n\nusing query =\n\tsql::query<\n\t\t\"SELECT title, genre AS type, year AS publis"
  },
  {
    "path": "tests/perf/queries/lib-query1.cpp",
    "chars": 502,
    "preview": "#include <iostream>\n#include \"../../data.hpp\"\n\nusing query =\n\tsql::query<\n\t\t\"SELECT title, genre AS type, year AS publis"
  },
  {
    "path": "tests/perf/queries/lib-query2.cpp",
    "chars": 545,
    "preview": "#include <iostream>\n#include \"../../data.hpp\"\n\nusing query =\n\tsql::query<\n\t\t\"SELECT genre AS type, name \"\n\t\t\"FROM books "
  },
  {
    "path": "tests/perf/queries/lib-query3.cpp",
    "chars": 624,
    "preview": "#include <iostream>\n#include \"../../data.hpp\"\n\nusing query =\n\tsql::query<\n\t\t\"SELECT genre AS type, year AS published, ti"
  },
  {
    "path": "tests/perf/queries/lib-query4.cpp",
    "chars": 573,
    "preview": "#include <iostream>\n#include \"../../data.hpp\"\n\nusing query =\n\tsql::query<\n\t\t\"SELECT book, genre AS type, year As publish"
  },
  {
    "path": "tests/perf/queries/lib-query5.cpp",
    "chars": 678,
    "preview": "#include <iostream>\n#include \"../../data.hpp\"\n\nusing query =\n\tsql::query<\n\t\t\"SELECT story, genre AS type, year AS publis"
  },
  {
    "path": "tests/perf/queries/query0.cpp",
    "chars": 622,
    "preview": "#include <iostream>\n#include <fstream>\n#include <string>\n#include <tuple>\n#include <vector>\n#include <unordered_map>\n\n#i"
  },
  {
    "path": "tests/perf/queries/query1.cpp",
    "chars": 649,
    "preview": "#include <iostream>\n#include <fstream>\n#include <string>\n#include <tuple>\n#include <vector>\n#include <unordered_map>\n\n#i"
  },
  {
    "path": "tests/perf/queries/query2.cpp",
    "chars": 949,
    "preview": "#include <iostream>\n#include <fstream>\n#include <string>\n#include <tuple>\n#include <vector>\n#include <unordered_map>\n\n#i"
  },
  {
    "path": "tests/perf/queries/query3.cpp",
    "chars": 1124,
    "preview": "#include <iostream>\n#include <fstream>\n#include <string>\n#include <tuple>\n#include <vector>\n#include <unordered_map>\n\n#i"
  },
  {
    "path": "tests/perf/queries/query4.cpp",
    "chars": 858,
    "preview": "#include <iostream>\n#include <fstream>\n#include <string>\n#include <tuple>\n#include <vector>\n#include <unordered_map>\n\n#i"
  },
  {
    "path": "tests/perf/queries/query5.cpp",
    "chars": 1022,
    "preview": "#include <iostream>\n#include <fstream>\n#include <string>\n#include <tuple>\n#include <vector>\n#include <unordered_map>\n\n#i"
  },
  {
    "path": "tests/perf/runner.sh",
    "chars": 27,
    "preview": "python3 scripts/runner.py\n\n"
  },
  {
    "path": "tests/perf/scripts/runner.py",
    "chars": 585,
    "preview": "import os\n\nQUERIES = 6\n\ndef exe(file, q):\n\tif int(q) >= 4:\n\t\tos.system(\"g++ -std=c++2a -DCROSS -O3 -I../../single-header"
  },
  {
    "path": "tests/runner.sh",
    "chars": 68,
    "preview": "mkdir queries\npython3 scripts/generate.py\npython3 scripts/runner.py\n"
  },
  {
    "path": "tests/scripts/compose.py",
    "chars": 1386,
    "preview": "# Composes a test file\n\nbegin = \"\"\"#include <iostream>\n\n#include \"data.hpp\"\n\nusing query =\n\tsql::query<\n\"\"\"\nmiddle = \"\"\""
  },
  {
    "path": "tests/scripts/generate.py",
    "chars": 3428,
    "preview": "# SQL query generator for test queries\n# Generates over 1.4 million unique queries\n\nimport itertools\nimport random\n\ntabl"
  },
  {
    "path": "tests/scripts/runner.py",
    "chars": 1115,
    "preview": "import os\n\ndef main():\n\tprint(\"Test Runner\")\n\tos.system(\"python3 scripts/select.py\")\n\tprint(\"\\tTest queries selected\")\n\t"
  },
  {
    "path": "tests/scripts/select.py",
    "chars": 725,
    "preview": "# Randomly selects ~500 queries to test from the 1.4mil query set\n\nimport random\n\ndef main():\n\toutfile = open(\"queries/t"
  }
]

About this extraction

This page contains the full source code of the mkitzan/constexpr-sql GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 59 files (234.1 KB), approximately 70.0k tokens, and a symbol index with 370 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!