Last active
April 1, 2024 12:11
-
-
Save furfurylic/6eb00239e4ab0c2bd6005e0fa6dab0a3 to your computer and use it in GitHub Desktop.
commata - primer
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sample codes in Commata Primer |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/build* |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
cmake_minimum_required(VERSION 3.13) | |
project(commata_primer CXX) | |
enable_language(CXX) | |
set(CMAKE_CXX_STANDARD 17) | |
set(CMAKE_CXX_STANDARD_REQUIRED ON) | |
set(CMAKE_CXX_EXTENSIONS OFF) | |
set_property(GLOBAL PROPERTY USE_FOLDERS ON) | |
include(FetchContent) | |
FetchContent_Declare( | |
commata | |
GIT_REPOSITORY https://github.com/furfurylic/commata.git | |
GIT_TAG v0.2.9 | |
) | |
FetchContent_MakeAvailable(commata) | |
add_executable(commata_primer main.cpp) | |
target_compile_features(commata_primer PRIVATE cxx_std_14) | |
if(CMAKE_CXX_COMPILER_ID STREQUAL "MSVC") | |
target_compile_options(commata_primer PRIVATE | |
/MP /W4 /bigobj | |
$<$<CONFIG:MinSizeRel>:/wd4702> | |
$<$<CONFIG:Release>:/wd4702> | |
$<$<CONFIG:RelWithDebInfo>:/wd4702> | |
) | |
elseif(CMAKE_CXX_COMPILER_ID STREQUAL "GNU") | |
target_compile_definitions(commata_primer PRIVATE | |
$<$<NOT:$<CONFIG:Debug>>:NDEBUG> | |
) | |
target_compile_options(commata_primer PRIVATE | |
-Wall -Wextra -pedantic-errors -Werror=pedantic | |
$<$<CONFIG:Debug>:-O0 -g3> | |
$<$<CONFIG:RelWithDebInfo>:-O2 -g3> | |
) | |
elseif(CMAKE_CXX_COMPILER_ID STREQUAL "Clang") | |
target_compile_definitions(commata_primer PRIVATE | |
$<$<NOT:$<CONFIG:Debug>>:NDEBUG> | |
) | |
target_compile_options(commata_primer PRIVATE | |
-Wall -Wextra -pedantic-errors -Werror=pedantic | |
-Wno-gnu-zero-variadic-macro-arguments | |
$<$<CONFIG:Debug>:-O0 -g3> | |
$<$<CONFIG:RelWithDebInfo>:-O2 -g3> | |
) | |
endif() | |
target_link_libraries(commata_primer PRIVATE commata) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* These codes are licensed under the Unlicense. | |
* http://unlicense.org | |
*/ | |
#include <algorithm> | |
#include <cctype> | |
#include <cstring> | |
#include <deque> | |
#include <fstream> | |
#include <iostream> | |
#include <iterator> | |
#include <limits> | |
#include <set> | |
#include <stdexcept> | |
#include <string_view> | |
#include <vector> | |
#include <commata/field_scanners.hpp> | |
#include <commata/parse_csv.hpp> | |
#include <commata/stored_table.hpp> | |
#include <commata/table_pull.hpp> | |
#include <commata/table_scanner.hpp> | |
#include <commata/text_error.hpp> | |
#include <commata/wrapper_handlers.hpp> | |
using namespace std::literals; | |
using commata::make_stored_table_builder; | |
using commata::parse_csv; | |
using commata::stored_table; | |
using commata::wstored_table; | |
using commata::table_scanner; | |
using commata::make_empty_physical_line_aware; | |
using commata::make_field_translator; | |
using commata::text_error; | |
using commata::text_error_info; | |
using commata::replacement_ignore; | |
using commata::make_csv_source; | |
using commata::make_table_pull; | |
using commata::indirect; | |
void stored_table_sample() | |
{ | |
// Make an empty stored_table object | |
stored_table table; | |
// Open stars.csv and load its content into table | |
parse_csv(std::ifstream("stars.csv"), make_stored_table_builder(table)); | |
std::cout << table.size() << std::endl; // will print "9" (not "10") | |
std::cout << table[0][3] << std::endl; // will print "Distance, in parsec" | |
std::cout << table[1][1] << std::endl; // will print "Spica" | |
std::cout << table[5][1] << std::endl; // will print "Deneb" | |
std::cout << table[5][3] << std::endl; // will print "" (an empty string) | |
std::cout << std::strlen(table[6][1].c_str()) << std::endl; | |
// will print the length of "Albireo", which is 7 | |
for (char c : table[0][0]) { | |
std::cout << static_cast<char>(std::toupper(static_cast<unsigned char>(c))); | |
} // will print "CONSTELLATION" | |
std::cout << std::endl; | |
std::cout << (table[1][1] == "Spica") << std::endl; | |
// table[1][1] is "Spica", so will print "1" or "true" or something like that | |
std::cout << (table[1][3] < std::to_string(75)) << std::endl; | |
// table[1][3] is "77", so will print the result of the lexicographical | |
// comparison of "77" and "75" | |
table[5][2].erase(3); // table[5][2] will change from "1.25" to "1.2" | |
table[5][2][2] = '3'; // table[5][2] will change from "1.2" to "1.3" | |
table.rewrite_value(table[5][3], "430"); | |
// table[5][3] change from "" to "430" | |
table.content().pop_front(); // erases the first record | |
std::stable_sort(table.content().begin(), table.content().end(), | |
[](const auto& record1, const auto& record2) { | |
return record1[1] < record2[1]; | |
}); // sorts on the names of the stars | |
table.content().emplace_front(1, table.import_value("Constellation")); | |
// adds a new record which consists of one value "Constellation" | |
} | |
void stored_table_sample2() | |
{ | |
wstored_table table; | |
parse_csv(std::wifstream("stars.csv"), make_stored_table_builder(table)); | |
std::wcout << (table[1][0] == L"Virgo") << std::endl; | |
// will print "1" or "true" or something like that | |
} | |
void one_pass_scanning_sample() | |
{ | |
std::set<std::string> constellation_set; | |
std::vector<std::string> names; | |
std::deque<double> magnitudes; | |
table_scanner scanner(1 /* means that the first one record is a header */); | |
scanner.set_field_scanner(0, make_field_translator(constellation_set)); | |
// sets a body field scanner for field #0 (zero-based) | |
scanner.set_field_scanner(1, make_field_translator(names)); | |
// sets a body field scanner for field #1 (zero-based) | |
scanner.set_field_scanner(2, make_field_translator(magnitudes)); | |
// sets a body field scanner for field #2 (zero-based) | |
parse_csv(std::ifstream("stars.csv"), std::move(scanner)); | |
std::cout << constellation_set.size() << std::endl; | |
// will print "2" | |
std::copy(constellation_set.cbegin(), constellation_set.cend(), | |
std::ostream_iterator<std::string>(std::cout, " ")); | |
// will print "Cygnus Virgo " | |
// or something like that | |
std::cout << std::endl; | |
std::cout << names.size() << std::endl; // will print "8" | |
std::cout << names.back() << std::endl; // will print "Fawaris" | |
std::cout << magnitudes.size() << std::endl; // will print "8" | |
std::cout << magnitudes[2] << std::endl; // will print "2.74" | |
// or something like that | |
} | |
void one_pass_scanning_sample2() | |
{ | |
table_scanner scanner(1); | |
// The body field scanner for field #1 will print the name of stars to the | |
// standard output | |
scanner.set_field_scanner(1, | |
make_field_translator<std::string>( // <std::string> is required | |
std::ostream_iterator<std::string>(std::cout, "\n"))); | |
// The body field scanner for field #2 will make max_magnitude the magnitude | |
// of the brightest star (note that brighter stars have smaller magnitudes) | |
double max_magnitude = std::numeric_limits<double>::max(); | |
scanner.set_field_scanner(2, | |
make_field_translator<double>( // <double> is required | |
[&max_magnitude](double magnitude) { | |
max_magnitude = std::min(max_magnitude, magnitude); | |
})); | |
parse_csv(std::ifstream("stars.csv"), std::move(scanner)); | |
std::cout << max_magnitude << std::endl; // will print "0.97" | |
// or something like that | |
} | |
void one_pass_scanning_sample3() | |
{ | |
std::vector<std::string> names; | |
table_scanner scanner( | |
[&names, names_attached = false] | |
(std::size_t field_index, | |
std::optional<std::pair<const char*, const char*>> field_value, | |
table_scanner& scanner) mutable { | |
if (field_value) { | |
// The value of field_index-th (zero-based) header field is notified, | |
// whose value is [field_value.first, field_value.end), and | |
// field_value.end is dereferenceable and points the terminating zero | |
if (std::string_view(field_value->first, | |
field_value->second - field_value->first) | |
== "Name") { | |
scanner.set_field_scanner( | |
field_index, make_field_translator(names)); | |
names_attached = true; | |
} else { | |
return true; // true to instruct the table scanner to continue to | |
// report the header fields | |
} | |
} else { | |
// An end of a header record is notified | |
if (!names_attached) { | |
throw std::runtime_error( | |
"Cannot find a field of the names of the stars"); | |
} | |
} | |
return false; // false to tell the scanner to uninstall this header field | |
// scanner, and tell it that here the header records end | |
// and the next record will be the first body record | |
}); | |
parse_csv(std::ifstream("stars.csv"), std::move(scanner)); | |
std::cout << names.front() << std::endl; // will print "Spica" | |
std::cout << names[4] << std::endl; // will print "Deneb" | |
} | |
void stored_table_error_sample() | |
{ | |
stored_table table; | |
try { | |
parse_csv(std::ifstream("stars2.csv"), make_stored_table_builder(table)); | |
} catch (const text_error& e) { | |
std::cout << e.what() << std::endl; | |
//throw; | |
} | |
} | |
void stored_table_error_sample2() | |
{ | |
stored_table table; | |
try { | |
parse_csv(std::ifstream("stars2.csv"), make_stored_table_builder(table)); | |
} catch (const text_error& e) { | |
std::cout << text_error_info(e) << std::endl; | |
//throw; | |
} | |
} | |
void one_pass_scanning_error_sample() | |
{ | |
double distance_sum = 0.0; | |
std::size_t distance_num = 0; | |
table_scanner scanner(1); | |
scanner.set_field_scanner(3, | |
make_field_translator<double>( | |
[&distance_sum, &distance_num](double distance) { | |
distance_sum += distance; | |
++distance_num; | |
})); | |
try { | |
parse_csv(std::ifstream("stars.csv"), std::move(scanner)); | |
} catch (const commata::text_error& e) { | |
std::cout << text_error_info(e) << std::endl; | |
} | |
std::cout << distance_sum / distance_num << std::endl; | |
// will print the average distance | |
} | |
void one_pass_scanning_error_sample2() | |
{ | |
double distance_sum = 0.0; | |
std::size_t distance_num = 0; | |
table_scanner scanner(1); | |
scanner.set_field_scanner(3, | |
make_field_translator<double>( | |
[&distance_sum, &distance_num](double distance) { | |
distance_sum += distance; | |
++distance_num; | |
}, | |
replacement_ignore, /* added (1) */ | |
replacement_ignore)); /* added (2) */ | |
parse_csv(std::ifstream("stars.csv"), std::move(scanner)); | |
std::cout << distance_sum / distance_num << std::endl; | |
// will print the average distance | |
} | |
// A table handler type whose objects make a vector of vectors of field values | |
class vov_table_handler // vov means "vector of vector" | |
{ | |
std::vector<std::vector<std::string>>* records_; | |
std::string current_value_; | |
public: | |
using char_type = const char; | |
explicit vov_table_handler( | |
std::vector<std::vector<std::string>>& records) : | |
records_(&records) | |
{} | |
void start_record(const char*) | |
{ | |
records_->emplace_back(); | |
} | |
void update(const char* first, const char* last) | |
{ | |
// Append [first, last) to the current field value | |
current_value_.append(first, last); | |
} | |
void finalize(const char* first, const char* last) | |
{ | |
// Append [first, last) to the current field value | |
// as the final chunk of the value | |
current_value_.append(first, last); | |
records_->back().push_back(std::move(current_value_)); | |
current_value_.clear(); | |
} | |
void end_record(char*) | |
{} | |
}; | |
void vov_table_handler_sample() | |
{ | |
std::vector<std::vector<std::string>> records; | |
parse_csv(std::ifstream("stars.csv"), vov_table_handler(records)); | |
std::cout << records.size() << std::endl; // will print "9" | |
std::cout << records[3][1] << std::endl; // will print "Porrima" | |
} | |
void make_empty_physical_line_aware_sample() | |
{ | |
stored_table table; | |
parse_csv(std::ifstream("stars.csv"), | |
make_empty_physical_line_aware(make_stored_table_builder(table))); | |
std::cout << table.size() << std::endl; // will print "10" (not "9") | |
std::cout << table[5].size() << std::endl; // will print "0" | |
std::cout << table[6][1] << std::endl; // will print "Deneb" | |
} | |
void pull_parsing_sample() | |
{ | |
auto p = make_table_pull(make_csv_source(std::ifstream("stars.csv"))); | |
p.set_empty_physical_line_aware(true); | |
// Skip the first record | |
p.skip_record(); | |
// Skip one field and point the next field | |
p(1); | |
std::cout << *p << std::endl; // will print "Spica" | |
std::cout << p->size() << std::endl; // will print "Spica"'s | |
// length | |
std::cout << *p.skip_record(5)(1) << std::endl; // will print "Albireo" | |
} | |
void pull_parsing_sample2() | |
{ | |
auto p = make_table_pull(make_csv_source(std::ifstream("stars.csv"))); | |
std::vector<std::string> v; | |
while (p.skip_record(), p(1)) { // moves to the end of the record and | |
// skip the first field of the next record | |
v.emplace_back(*p); // *p is a reference to std::string_view | |
// object of the current field value | |
} | |
std::cout << v[0] << std::endl; // will print "Spica" | |
std::cout << v[1] << std::endl; // will print "Zavijava" | |
std::cout << v[7] << std::endl; // will print "Fawaris" | |
} | |
std::string slurp(const char* s) | |
{ | |
std::filebuf in; | |
in.open(s, std::ios::in | std::ios::binary); | |
if (!in.is_open()) { | |
throw std::runtime_error("Cannot open "s + s); | |
} | |
return std::string(std::istreambuf_iterator<char>(&in), | |
std::istreambuf_iterator<char>()); | |
} | |
void pull_parsing_sample3() | |
{ | |
const std::string contents = slurp("stars.csv"); | |
auto p = make_table_pull(make_csv_source(indirect, contents)); | |
static_assert(!std::is_const_v<decltype(p)::char_type>); | |
while (p.skip_record()(1)) { | |
std::puts(p.c_str()); // will print stars' names | |
} | |
} | |
int main() | |
{ | |
stored_table_sample(); | |
std::cout << "-----\n"; | |
stored_table_sample2(); | |
std::cout << "-----\n"; | |
one_pass_scanning_sample(); | |
std::cout << "-----\n"; | |
one_pass_scanning_sample2(); | |
std::cout << "-----\n"; | |
one_pass_scanning_sample3(); | |
std::cout << "-----\n"; | |
stored_table_error_sample(); | |
std::cout << "-----\n"; | |
stored_table_error_sample2(); | |
std::cout << "-----\n"; | |
one_pass_scanning_error_sample(); | |
std::cout << "-----\n"; | |
one_pass_scanning_error_sample2(); | |
std::cout << "-----\n"; | |
make_empty_physical_line_aware_sample(); | |
std::cout << "-----\n"; | |
pull_parsing_sample(); | |
std::cout << "-----\n"; | |
pull_parsing_sample2(); | |
std::cout << "-----\n"; | |
pull_parsing_sample3(); | |
std::cout << "-----\n"; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Constellation | Name | Apparent magnitude | Distance, in parsec | |
---|---|---|---|---|
Virgo | Spica | 0.97 | 77 | |
Virgo | Zavijava | 3.60 | 11 | |
Virgo | Porrima | 2.74 | 38 | |
Virgo | Minelauva | 3.38 | 71 | |
Cygnus | Deneb | 1.25 | ||
Cygnus | Albireo | 3.08 | 133 | |
Cygnus | Sadr | 2.23 | 560 | |
Cygnus | Fawaris | 2.89 | 51 |
We can make this file beautiful and searchable if this error is corrected: Illegal quoting in line 2.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Constellation,Name,Apparent magnitude,"Distance, in parsec" | |
Virgo,Spica,0.97,77" | |
Virgo,Zavijava,3.60,11 | |
Virgo,Porrima,2.74,38 | |
Virgo,Minelauva,3.38,71 | |
Cygnus,Deneb,1.25, | |
Cygnus,Albireo,3.08,133 | |
Cygnus,Sadr,2.23,560 | |
Cygnus,Fawaris,2.89,51 |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment