// C++20 syntax reference. Each named region is displayed from this file.
// Compile the complete file; main calls every example in page order.
#include <algorithm>
#include <array>
#include <cstddef>
#include <iostream>
#include <memory>
#include <span>
#include <stdexcept>
#include <string>
#include <string_view>
#include <utility>
#include <vector>

// textbook:begin declaration
void syntax_declaration() {
    int a{7};
    int b = 7;
    int c(7);
    int d = {7};
    int zero{};
    a = 9;
    std::cout << a << ' ' << b << ' ' << c << ' ' << d << ' ' << zero << '\n';
}
// textbook:end declaration

// textbook:begin const-auto
void syntax_const_auto() {
    const int x{7};
    int const y{7};
    auto copy{x};
    auto& edit{copy};
    const auto& read{copy};
    edit = 10;
    std::cout << x << ' ' << y << ' ' << copy << ' ' << read << '\n';
}
// textbook:end const-auto

// textbook:begin arithmetic
void syntax_arithmetic() {
    int n{5};
    std::cout << n / 2 << ' ' << n % 2 << ' ' << -n / 2 << '\n';
    std::cout << static_cast<double>(n) / 2 << ' '
              << static_cast<double>(n / 2) << '\n';
    std::cout << 2 + 3 * 4 << ' ' << (2 + 3) * 4 << '\n';
}
// textbook:end arithmetic

// textbook:begin selection
void syntax_selection() {
    int n{4};
    if (n > 0 && n % 2 == 0) {
        std::cout << "positive even\n";
    } else {
        std::cout << "other\n";
    }
    switch (n) {
        case 4: std::cout << "four\n"; break;
        default: std::cout << "not four\n"; break;
    }
}
// textbook:end selection

// textbook:begin while-do
void syntax_while_do() {
    int a{0};
    while (a < 0) {
        ++a;
    }
    int b{0};
    do {
        ++b;
    } while (b < 0);
    std::cout << a << ' ' << b << '\n';
}
// textbook:end while-do

// textbook:begin index-for
void syntax_index_for() {
    std::array<int, 3> values{2, 4, 6};
    int total{0};
    for (std::size_t i{0}; i < values.size(); ++i) {
        total += values[i];
    }
    std::cout << total << '\n';
}
// textbook:end index-for

// textbook:begin range-for
void syntax_range_for() {
    std::array<int, 3> values{2, 4, 6};
    int copied_total{0};
    for (auto value : values) {
        value += 1;
        copied_total += value;
    }
    for (auto& value : values) {
        value *= 2;
    }
    int stored_total{0};
    for (const auto& value : values) {
        stored_total += value;
    }
    std::cout << copied_total << ' ' << stored_total << '\n';
}
// textbook:end range-for

// textbook:begin loop-jumps
void syntax_loop_jumps() {
    int total{0};
    for (int i{0}; i < 6; ++i) {
        if (i == 2) { continue; }
        if (i == 4) { break; }
        total += i;
    }
    std::cout << total << '\n';
}
// textbook:end loop-jumps

// textbook:begin functions
int next_value(int value) { return value + 1; }
void add_one(int& value) { value += 1; }
int read_value(const int& value) { return value; }
void syntax_functions() {
    int x{4};
    int result{next_value(x)};
    std::cout << x << ' ' << result << '\n';
    add_one(x);
    std::cout << x << ' ' << read_value(x) << '\n';
}
// textbook:end functions

// textbook:begin pointer-const
void syntax_pointer_const() {
    int x{4};
    int y{9};
    const int* read{&x};
    int* const fixed{&x};
    const int* const both{&x};
    *fixed = 7;
    read = &y;
    std::cout << *read << ' ' << *fixed << ' ' << *both << '\n';
    const int* missing{nullptr};
    if (missing == nullptr) { std::cout << "missing\n"; }
}
// textbook:end pointer-const

// textbook:begin containers
void syntax_containers() {
    std::array<int, 3> fixed{2, 4, 6};
    std::vector<int> values{2, 4};
    values.push_back(6);
    std::string text{"hi"};
    text += '!';
    std::cout << fixed[0] << ' ' << values.size() << ' ' << text << '\n';
    values.reserve(10);
    std::cout << values.size() << '\n';
}
// textbook:end containers

// textbook:begin borrowed-views
void syntax_borrowed_views() {
    std::array<int, 3> values{2, 4, 6};
    std::span<const int> view{values};
    std::string text{"cat"};
    std::string_view word{text};
    values[1] = 9;
    text[0] = 'b';
    std::cout << view[1] << ' ' << word << '\n';
}
// textbook:end borrowed-views

// textbook:begin classes
void syntax_classes() {
    class Reading {
        int value_;
    public:
        explicit Reading(int initial) : value_{initial} {}
        int value() const { return value_; }
        void set(int next) { this->value_ = next; }
    };
    Reading r{4};
    Reading* p{&r};
    p->set(7);
    std::cout << r.value() << '\n';
}
// textbook:end classes

// textbook:begin destruction
void syntax_destruction() {
    struct Trace {
        int id;
        explicit Trace(int value) : id{value} { std::cout << "build " << id << '\n'; }
        ~Trace() { std::cout << "destroy " << id << '\n'; }
    };
    Trace outer{1};
    {
        Trace inner{2};
    }
}
// textbook:end destruction

// textbook:begin lambda-algorithms
void syntax_lambda_algorithms() {
    std::vector<int> values{3, 1, 2};
    std::sort(values.begin(), values.end());
    int limit{1};
    auto above = [limit](int value) { return value > limit; };
    auto count = std::count_if(values.begin(), values.end(), above);
    std::cout << values[0] << ' ' << values[1] << ' ' << values[2] << '\n';
    std::cout << count << '\n';
}
// textbook:end lambda-algorithms

// textbook:begin ownership-move
void syntax_ownership_move() {
    auto first = std::make_unique<int>(7);
    auto second = std::move(first);
    std::cout << (first == nullptr) << ' ' << *second << '\n';
    auto owner = std::make_shared<int>(9);
    std::weak_ptr<int> observer{owner};
    {
        auto held = observer.lock();
        if (held) { std::cout << *held << '\n'; }
    }
    owner.reset();
    std::cout << observer.expired() << '\n';
}
// textbook:end ownership-move

// textbook:begin templates
template<class T>
T twice(T value) { return value + value; }
void syntax_templates() {
    std::cout << twice<int>(3) << ' ' << twice(0.5) << '\n';
}
// textbook:end templates

// textbook:begin exceptions
int nonnegative(int value) {
    if (value < 0) { throw std::runtime_error("negative"); }
    return value;
}
void syntax_exceptions() {
    try {
        std::cout << nonnegative(3) << '\n';
        nonnegative(-1);
    } catch (const std::runtime_error& error) {
        std::cout << error.what() << '\n';
    }
}
// textbook:end exceptions

// textbook:begin bits
void syntax_bits() {
    unsigned int a{5u};  // Low three bits: 101.
    unsigned int b{3u};  // Low three bits: 011.
    std::cout << (a & b) << ' ' << (a | b) << ' ' << (a ^ b) << '\n';
    std::cout << ((~a) & 7u) << ' ' << (a << 1) << ' ' << (a >> 1) << '\n';
}
// textbook:end bits

int main() {
    std::cout << "[declaration]\n"; syntax_declaration();
    std::cout << "[const-auto]\n"; syntax_const_auto();
    std::cout << "[arithmetic]\n"; syntax_arithmetic();
    std::cout << "[selection]\n"; syntax_selection();
    std::cout << "[while-do]\n"; syntax_while_do();
    std::cout << "[index-for]\n"; syntax_index_for();
    std::cout << "[range-for]\n"; syntax_range_for();
    std::cout << "[loop-jumps]\n"; syntax_loop_jumps();
    std::cout << "[functions]\n"; syntax_functions();
    std::cout << "[pointer-const]\n"; syntax_pointer_const();
    std::cout << "[containers]\n"; syntax_containers();
    std::cout << "[borrowed-views]\n"; syntax_borrowed_views();
    std::cout << "[classes]\n"; syntax_classes();
    std::cout << "[destruction]\n"; syntax_destruction();
    std::cout << "[lambda-algorithms]\n"; syntax_lambda_algorithms();
    std::cout << "[ownership-move]\n"; syntax_ownership_move();
    std::cout << "[templates]\n"; syntax_templates();
    std::cout << "[exceptions]\n"; syntax_exceptions();
    std::cout << "[bits]\n"; syntax_bits();
    return 0;
}
