bhylu.com

Advertisements

C++ Delivery Manifest Project

Parse a complete two-field record into a typed result and commit output only after all checks succeed.

Your brief

Define a deliberately small manifest format: a nonempty stop token without commas, then one comma, then a parcel count from zero through one thousand. The numeric field uses exact decimal conversion with no whitespace. This is not general CSV: quoted fields, embedded separators and multiline records require a format-aware parser. Return an optional owned record so failed parsing cannot leave a partially updated caller object. Validate framing and the entire number before constructing the accepted result.

Run it locally

Use a C++20 compiler and matching standard library in a separate lab folder. The command uses c++; substitute g++, clang++ or zig c++ for your toolchain. C++ does not currently run in Bhylu’s browser playground. Apache, PHP and MySQL are not needed.

c++ -std=c++20 -Wall -Wextra -Wpedantic -Werror manifest-project.cpp -o lesson

On Windows use -o lesson.exe and run .\lesson.exe in PowerShell. On Unix-like systems run ./lesson. Thread examples may need -pthread on your platform.

Download the complete C++ source. Run file labs in a private empty directory, away from existing reports.

Worked solution

Show the worked solution
C++20 · manifest-project.cpp

#include <iostream>
#include <string>
#include <string_view>
#include <optional>
#include <charconv>
#include <system_error>

struct StopRecord { std::string name; int parcels; };
std::optional<StopRecord> parse_stop(std::string_view line) {
    auto comma = line.find(',');
    if (comma == std::string_view::npos || comma == 0 || comma + 1 == line.size()) { return std::nullopt; }
    auto text = line.substr(comma + 1);
    int count{};
    auto [end, error] = std::from_chars(text.data(), text.data() + text.size(), count);
    if (error != std::errc{} || end != text.data() + text.size() || count < 0 || count > 1000) { return std::nullopt; }
    return StopRecord{std::string{line.substr(0, comma)}, count};
}

int main() {
    auto record = parse_stop("Quay,12");
    if (!record) { return 1; }
    std::cout << record->name << ": " << record->parcels << '\n';
    std::cout << "Junk accepted: " << parse_stop("Quay,12x").has_value() << '\n';
}

Expected result

Quay: 12
Junk accepted: 0

The returned record owns its name instead of retaining a view into the caller input. A second comma in the numeric suffix fails complete conversion, while an empty name or missing count fails framing. For real files, impose an input-size limit before or during reading; this parser does not make an unbounded transport safe. Add a richer error result when a user needs to know which field was rejected.

Extend and test

Test missing separators, an empty name, missing count, negative and excessive counts, extra commas and oversized integer text. State the grammar before adding spaces or quoted names.

Consult the WG21 C++ working group and the C++ Core Guidelines for language references and design guidance. Check the selected standard version and your implementation’s library support.

Advertisements