aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorcrupest <crupest@outlook.com>2020-12-30 15:37:39 +0800
committercrupest <crupest@outlook.com>2020-12-30 15:37:39 +0800
commite0964bbc4f66e7d193abd249213c9cf762fd0294 (patch)
treeee4f5307fc555ef66a3752e20388dca8f386c2f1
parent7e9e803b33a9380d2ff3111c8d11f25f5d2b98ec (diff)
downloadcrupest-e0964bbc4f66e7d193abd249213c9cf762fd0294.tar.gz
crupest-e0964bbc4f66e7d193abd249213c9cf762fd0294.tar.bz2
crupest-e0964bbc4f66e7d193abd249213c9cf762fd0294.zip
import(life): ...
-rw-r--r--works/life/cpp-practicum/Base.hpp37
-rw-r--r--works/life/cpp-practicum/Book.cpp36
-rw-r--r--works/life/cpp-practicum/Book.hpp51
-rw-r--r--works/life/cpp-practicum/CMakeLists.txt21
-rw-r--r--works/life/cpp-practicum/Record.cpp38
-rw-r--r--works/life/cpp-practicum/Record.hpp36
-rw-r--r--works/life/cpp-practicum/StringUtil.cpp305
-rw-r--r--works/life/cpp-practicum/StringUtil.hpp148
-rw-r--r--works/life/cpp-practicum/Vendor.cpp33
-rw-r--r--works/life/cpp-practicum/Vendor.hpp45
-rw-r--r--works/life/cpp-practicum/main.cpp297
11 files changed, 286 insertions, 761 deletions
diff --git a/works/life/cpp-practicum/Base.hpp b/works/life/cpp-practicum/Base.hpp
index f26b81f..bdf87dd 100644
--- a/works/life/cpp-practicum/Base.hpp
+++ b/works/life/cpp-practicum/Base.hpp
@@ -1,15 +1,8 @@
#pragma once
-#include <cstddef>
#include <exception>
-// #include <gsl/gsl>
#include <stdexcept>
-// Now we have no gsl but we need gsl::index
-namespace gsl {
-using index = std::ptrdiff_t;
-}
-
#define CRU_UNUSED(entity) static_cast<void>(entity);
#define CRU__CONCAT(a, b) a##b
@@ -31,33 +24,7 @@ using index = std::ptrdiff_t;
classname(classname &&) = delete; \
classname &operator=(classname &&) = delete;
-namespace cru {
-class Object {
+class SerializationException : public std::runtime_error {
public:
- Object() = default;
- CRU_DEFAULT_COPY(Object)
- CRU_DEFAULT_MOVE(Object)
- virtual ~Object() = default;
-};
-
-struct Interface {
- Interface() = default;
- CRU_DELETE_COPY(Interface)
- CRU_DELETE_MOVE(Interface)
- virtual ~Interface() = default;
+ using runtime_error::runtime_error;
};
-
-[[noreturn]] inline void UnreachableCode() { std::terminate(); }
-
-using Index = gsl::index;
-
-// https://www.boost.org/doc/libs/1_54_0/doc/html/hash/reference.html#boost.hash_combine
-template <class T> inline void hash_combine(std::size_t &s, const T &v) {
- std::hash<T> h;
- s ^= h(v) + 0x9e3779b9 + (s << 6) + (s >> 2);
-}
-
-#define CRU_DEFINE_CLASS_LOG_TAG(tag) \
-private: \
- constexpr static std::u16string_view log_tag = tag;
-} // namespace cru
diff --git a/works/life/cpp-practicum/Book.cpp b/works/life/cpp-practicum/Book.cpp
new file mode 100644
index 0000000..bf67d7c
--- /dev/null
+++ b/works/life/cpp-practicum/Book.cpp
@@ -0,0 +1,36 @@
+#include "Book.hpp"
+
+#include <QString>
+
+QTextStream &operator>>(QTextStream &left, Book &right) {
+ auto line = left.readLine();
+
+ auto fields = line.split(QChar('|'));
+
+ if (fields.size() != 6) {
+ throw SerializationException("The line has not 6 parts.");
+ }
+
+ right.SetIsbn(fields[0].toStdU16String());
+ right.SetTitle(fields[1].toStdU16String());
+ right.SetType(fields[2].toStdU16String());
+ right.SetAuthor(fields[3].toStdU16String());
+ right.SetPress(fields[4].toStdU16String());
+
+ bool ok;
+ auto stock_count = fields[5].toInt(&ok);
+ if (!ok) {
+ throw SerializationException("Part 6 is not a number.");
+ }
+
+ right.SetStockCount(stock_count);
+
+ return left;
+}
+
+QTextStream &operator<<(QTextStream &left, const Book &right) {
+ left << right.GetIsbn() << '|' << right.GetTitle() << '|' << right.GetType()
+ << '|' << right.GetAuthor() << '|' << right.GetPress() << '|'
+ << right.GetStockCount();
+ return left;
+}
diff --git a/works/life/cpp-practicum/Book.hpp b/works/life/cpp-practicum/Book.hpp
new file mode 100644
index 0000000..2fb1123
--- /dev/null
+++ b/works/life/cpp-practicum/Book.hpp
@@ -0,0 +1,51 @@
+#pragma once
+#include "Base.hpp"
+
+#include <QTextStream>
+#include <string>
+
+class Book final {
+public:
+ Book() = default;
+
+ Book(std::u16string isbn, std::u16string title, std::u16string type,
+ std::u16string author, std::u16string press, int stock_count)
+ : isbn_(std::move(isbn)), title_(std::move(title)),
+ type_(std::move(type)), author_(std::move(author)),
+ press_(std::move(press)), stock_count_(stock_count) {}
+
+ CRU_DEFAULT_COPY(Book)
+ CRU_DEFAULT_MOVE(Book)
+
+ ~Book() = default;
+
+public:
+ std::u16string GetIsbn() const { return isbn_; }
+ void SetIsbn(std::u16string isbn) { isbn_ = std::move(isbn); }
+
+ std::u16string GetTitle() const { return title_; }
+ void SetTitle(std::u16string title) { title_ = std::move(title); }
+
+ std::u16string GetType() const { return type_; }
+ void SetType(std::u16string type) { type_ = std::move(type); }
+
+ std::u16string GetAuthor() const { return author_; }
+ void SetAuthor(std::u16string author) { author_ = std::move(author); }
+
+ std::u16string GetPress() const { return press_; }
+ void SetPress(std::u16string press) { press_ = std::move(press); }
+
+ int GetStockCount() const { return stock_count_; }
+ void SetStockCount(int stock_count) { stock_count_ = stock_count; }
+
+private:
+ std::u16string isbn_;
+ std::u16string title_;
+ std::u16string type_;
+ std::u16string author_;
+ std::u16string press_;
+ int stock_count_;
+};
+
+QTextStream &operator>>(QTextStream &left, Book &right);
+QTextStream &operator<<(QTextStream &left, const Book &right);
diff --git a/works/life/cpp-practicum/CMakeLists.txt b/works/life/cpp-practicum/CMakeLists.txt
index fbf1c13..7958850 100644
--- a/works/life/cpp-practicum/CMakeLists.txt
+++ b/works/life/cpp-practicum/CMakeLists.txt
@@ -1,3 +1,6 @@
+set(CMAKE_TOOLCHAIN_FILE ${CMAKE_CURRENT_SOURCE_DIR}/../vcpkg/scripts/buildsystems/vcpkg.cmake
+ CACHE STRING "Vcpkg toolchain file")
+
cmake_minimum_required(VERSION 3.14)
project(CppPraticum)
@@ -11,4 +14,20 @@ if (MSVC)
add_compile_options(/utf-8 /W4 /WX)
endif()
-add_executable(main main.cpp Base.hpp StringUtil.hpp StringUtil.cpp)
+find_package(Qt5Core CONFIG REQUIRED)
+find_package(Qt5Gui CONFIG REQUIRED)
+find_package(Qt5Widgets CONFIG REQUIRED)
+
+add_executable(main
+ Base.hpp
+
+ Book.hpp
+ Book.cpp
+ Vendor.hpp
+ Vendor.cpp
+ Record.hpp
+ Record.cpp
+
+ main.cpp
+)
+target_link_libraries(main PRIVATE Qt5::Core Qt5::Widgets Qt5::Gui)
diff --git a/works/life/cpp-practicum/Record.cpp b/works/life/cpp-practicum/Record.cpp
new file mode 100644
index 0000000..1041b23
--- /dev/null
+++ b/works/life/cpp-practicum/Record.cpp
@@ -0,0 +1,38 @@
+#include "Record.hpp"
+
+void Record::WriteTo(QFile file) {
+ file.open(QFile::ReadWrite | QFile::Text | QFile::Truncate);
+ QTextStream stream(&file);
+ stream.setCodec("UTF-8");
+
+ stream << books_.size() << ' ' << vendors_.size() << '\n';
+ for (const auto &book : books_) {
+ stream << book << '\n';
+ }
+ for (const auto &vendor : vendors_) {
+ stream << vendor << '\n';
+ }
+}
+
+void Record::ReadFrom(QFile file) {
+ file.open(QFile::ReadOnly | QFile::Text);
+ QTextStream stream(&file);
+ stream.setCodec("UTF-8");
+
+ books_.clear();
+ vendors_.clear();
+
+ int book_count, vendor_count;
+ stream >> book_count >> vendor_count;
+ stream.skipWhiteSpace();
+ for (int i = 0; i < book_count; i++) {
+ Book book;
+ stream >> book;
+ books_.push_back(std::move(book));
+ }
+ for (int i = 0; i < vendor_count; i++) {
+ Vendor vendor;
+ stream >> vendor;
+ vendors_.push_back(std::move(vendor));
+ }
+}
diff --git a/works/life/cpp-practicum/Record.hpp b/works/life/cpp-practicum/Record.hpp
new file mode 100644
index 0000000..e39e626
--- /dev/null
+++ b/works/life/cpp-practicum/Record.hpp
@@ -0,0 +1,36 @@
+#pragma once
+#include "Base.hpp"
+
+#include "Book.hpp"
+#include "Vendor.hpp"
+
+#include <QFile>
+#include <optional>
+#include <vector>
+
+class Record final {
+public:
+ Record();
+
+ CRU_DEFAULT_COPY(Record);
+ CRU_DEFAULT_MOVE(Record);
+
+ ~Record() = default;
+
+public:
+ void WriteTo(QFile file);
+ void ReadFrom(QFile file);
+
+ const std::vector<Book> &GetBooks() const { return books_; }
+ const std::vector<Vendor> &GetVendors() const { return vendors_; }
+
+ // TODO: Implementation
+ std::optional<Book> FindBookByIsbn(std::u16string_view isbn);
+
+ // TODO: Implementation
+ void RemoveBookByIsbn(std::u16string_view isbn);
+
+private:
+ std::vector<Book> books_;
+ std::vector<Vendor> vendors_;
+};
diff --git a/works/life/cpp-practicum/StringUtil.cpp b/works/life/cpp-practicum/StringUtil.cpp
deleted file mode 100644
index e6cd377..0000000
--- a/works/life/cpp-practicum/StringUtil.cpp
+++ /dev/null
@@ -1,305 +0,0 @@
-#include "StringUtil.hpp"
-#include "Base.hpp"
-
-namespace cru {
-namespace {
-template <typename UInt, int number_of_bit, typename ReturnType>
-inline std::enable_if_t<std::is_unsigned_v<UInt>, ReturnType>
-ExtractBits(UInt n) {
- return static_cast<ReturnType>(n & ((1u << number_of_bit) - 1));
-}
-} // namespace
-
-CodePoint Utf8NextCodePoint(std::string_view str, Index current,
- Index *next_position) {
- CodePoint result;
-
- if (current >= static_cast<Index>(str.length())) {
- result = k_invalid_code_point;
- } else {
- const auto cu0 = static_cast<std::uint8_t>(str[current++]);
-
- auto read_next_folowing_code = [&str, &current]() -> CodePoint {
- if (current == static_cast<Index>(str.length()))
- throw TextEncodeException(
- "Unexpected end when read continuing byte of multi-byte code "
- "point.");
-
- const auto u = static_cast<std::uint8_t>(str[current]);
- if (!(u & (1u << 7)) || (u & (1u << 6))) {
- throw TextEncodeException(
- "Unexpected bad-format (not 0b10xxxxxx) continuing byte of "
- "multi-byte code point.");
- }
-
- return ExtractBits<std::uint8_t, 6, CodePoint>(str[current++]);
- };
-
- if ((1u << 7) & cu0) {
- if ((1u << 6) & cu0) { // 2~4-length code point
- if ((1u << 5) & cu0) { // 3~4-length code point
- if ((1u << 4) & cu0) { // 4-length code point
- if (cu0 & (1u << 3)) {
- throw TextEncodeException(
- "Unexpected bad-format begin byte (not 0b11110xxx) of 4-byte"
- "code point.");
- }
-
- const CodePoint s0 = ExtractBits<std::uint8_t, 3, CodePoint>(cu0)
- << (6 * 3);
- const CodePoint s1 = read_next_folowing_code() << (6 * 2);
- const CodePoint s2 = read_next_folowing_code() << 6;
- const CodePoint s3 = read_next_folowing_code();
- result = s0 + s1 + s2 + s3;
- } else { // 3-length code point
- const CodePoint s0 = ExtractBits<std::uint8_t, 4, CodePoint>(cu0)
- << (6 * 2);
- const CodePoint s1 = read_next_folowing_code() << 6;
- const CodePoint s2 = read_next_folowing_code();
- result = s0 + s1 + s2;
- }
- } else { // 2-length code point
- const CodePoint s0 = ExtractBits<std::uint8_t, 5, CodePoint>(cu0)
- << 6;
- const CodePoint s1 = read_next_folowing_code();
- result = s0 + s1;
- }
- } else {
- throw TextEncodeException(
- "Unexpected bad-format (0b10xxxxxx) begin byte of a code point.");
- }
- } else {
- result = static_cast<CodePoint>(cu0);
- }
- }
-
- if (next_position != nullptr)
- *next_position = current;
- return result;
-}
-
-CodePoint Utf16NextCodePoint(std::u16string_view str, Index current,
- Index *next_position) {
- CodePoint result;
-
- if (current >= static_cast<Index>(str.length())) {
- result = k_invalid_code_point;
- } else {
- const auto cu0 = str[current++];
-
- if (!IsUtf16SurrogatePairCodeUnit(cu0)) { // 1-length code point
- result = static_cast<CodePoint>(cu0);
- } else if (IsUtf16SurrogatePairLeading(cu0)) { // 2-length code point
- if (current >= static_cast<Index>(str.length())) {
- throw TextEncodeException(
- "Unexpected end when reading second code unit of surrogate pair.");
- }
- const auto cu1 = str[current++];
-
- if (!IsUtf16SurrogatePairTrailing(cu1)) {
- throw TextEncodeException(
- "Unexpected bad-range second code unit of surrogate pair.");
- }
-
- const auto s0 = ExtractBits<std::uint16_t, 10, CodePoint>(cu0) << 10;
- const auto s1 = ExtractBits<std::uint16_t, 10, CodePoint>(cu1);
-
- result = s0 + s1 + 0x10000;
-
- } else {
- throw TextEncodeException(
- "Unexpected bad-range first code unit of surrogate pair.");
- }
- }
-
- if (next_position != nullptr)
- *next_position = current;
- return result;
-}
-
-CodePoint Utf16PreviousCodePoint(std::u16string_view str, Index current,
- Index *previous_position) {
- CodePoint result;
- if (current <= 0) {
- result = k_invalid_code_point;
- } else {
- const auto cu0 = str[--current];
-
- if (!IsUtf16SurrogatePairCodeUnit(cu0)) { // 1-length code point
- result = static_cast<CodePoint>(cu0);
- } else if (IsUtf16SurrogatePairTrailing(cu0)) { // 2-length code point
- if (current <= 0) {
- throw TextEncodeException(
- "Unexpected end when reading first code unit of surrogate pair.");
- }
- const auto cu1 = str[--current];
-
- if (!IsUtf16SurrogatePairLeading(cu1)) {
- throw TextEncodeException(
- "Unexpected bad-range first code unit of surrogate pair.");
- }
-
- const auto s0 = ExtractBits<std::uint16_t, 10, CodePoint>(cu1) << 10;
- const auto s1 = ExtractBits<std::uint16_t, 10, CodePoint>(cu0);
-
- result = s0 + s1 + 0x10000;
-
- } else {
- throw TextEncodeException(
- "Unexpected bad-range second code unit of surrogate pair.");
- }
- }
-
- if (previous_position != nullptr)
- *previous_position = current;
- return result;
-}
-
-void Utf8EncodeCodePointAppend(CodePoint code_point, std::string &str) {
- auto write_continue_byte = [&str](std::uint8_t byte6) {
- str.push_back((1u << 7) + (((1u << 6) - 1) & byte6));
- };
-
- if (code_point >= 0 && code_point <= 0x007F) {
- str.push_back(static_cast<char>(code_point));
- } else if (code_point >= 0x0080 && code_point <= 0x07FF) {
- std::uint32_t unsigned_code_point = code_point;
- str.push_back(static_cast<char>(ExtractBits<std::uint32_t, 5, std::uint8_t>(
- (unsigned_code_point >> 6)) +
- 0b11000000));
- write_continue_byte(
- ExtractBits<std::uint32_t, 6, std::uint8_t>(unsigned_code_point));
- } else if (code_point >= 0x0800 && code_point <= 0xFFFF) {
- std::uint32_t unsigned_code_point = code_point;
- str.push_back(static_cast<char>(ExtractBits<std::uint32_t, 4, std::uint8_t>(
- (unsigned_code_point >> (6 * 2))) +
- 0b11100000));
- write_continue_byte(
- ExtractBits<std::uint32_t, 6, std::uint8_t>(unsigned_code_point >> 6));
- write_continue_byte(
- ExtractBits<std::uint32_t, 6, std::uint8_t>(unsigned_code_point));
- } else if (code_point >= 0x10000 && code_point <= 0x10FFFF) {
- std::uint32_t unsigned_code_point = code_point;
- str.push_back(static_cast<char>(ExtractBits<std::uint32_t, 3, std::uint8_t>(
- (unsigned_code_point >> (6 * 3))) +
- 0b11110000));
- write_continue_byte(ExtractBits<std::uint32_t, 6, std::uint8_t>(
- unsigned_code_point >> (6 * 2)));
- write_continue_byte(
- ExtractBits<std::uint32_t, 6, std::uint8_t>(unsigned_code_point >> 6));
- write_continue_byte(
- ExtractBits<std::uint32_t, 6, std::uint8_t>(unsigned_code_point));
- } else {
- throw TextEncodeException("Code point out of range.");
- }
-}
-
-void Utf16EncodeCodePointAppend(CodePoint code_point, std::u16string &str) {
- if ((code_point >= 0 && code_point <= 0xD7FF) ||
- (code_point >= 0xE000 && code_point <= 0xFFFF)) {
- str.push_back(static_cast<char16_t>(code_point));
- } else if (code_point >= 0x10000 && code_point <= 0x10FFFF) {
- std::uint32_t u = code_point - 0x10000;
- str.push_back(static_cast<char16_t>(
- ExtractBits<std::uint32_t, 10, std::uint32_t>(u >> 10) + 0xD800u));
- str.push_back(static_cast<char16_t>(
- ExtractBits<std::uint32_t, 10, std::uint32_t>(u) + 0xDC00u));
- } else {
- throw TextEncodeException("Code point out of range.");
- }
-}
-
-std::string ToUtf8(std::u16string_view s) {
- std::string result;
- for (CodePoint cp : Utf16CodePointIterator{s}) {
- Utf8EncodeCodePointAppend(cp, result);
- }
- return result;
-}
-
-std::u16string ToUtf16(std::string_view s) {
- std::u16string result;
- for (CodePoint cp : Utf8CodePointIterator{s}) {
- Utf16EncodeCodePointAppend(cp, result);
- }
- return result;
-}
-
-bool Utf16IsValidInsertPosition(std::u16string_view s, gsl::index position) {
- if (position < 0)
- return false;
- if (position > static_cast<gsl::index>(s.size()))
- return false;
- if (position == 0)
- return true;
- if (position == static_cast<gsl::index>(s.size()))
- return true;
- return !IsUtf16SurrogatePairTrailing(s[position]);
-}
-
-gsl::index Utf16BackwardUntil(std::u16string_view str, gsl::index position,
- const std::function<bool(CodePoint)> &predicate) {
- if (position <= 0)
- return position;
- while (true) {
- gsl::index p = position;
- auto c = Utf16PreviousCodePoint(str, p, &position);
- if (predicate(c))
- return p;
- if (c == k_invalid_code_point)
- return p;
- }
- UnreachableCode();
-}
-
-gsl::index Utf16ForwardUntil(std::u16string_view str, gsl::index position,
- const std::function<bool(CodePoint)> &predicate) {
- if (position >= static_cast<gsl::index>(str.size()))
- return position;
- while (true) {
- gsl::index p = position;
- auto c = Utf16NextCodePoint(str, p, &position);
- if (predicate(c))
- return p;
- if (c == k_invalid_code_point)
- return p;
- }
- UnreachableCode();
-}
-
-inline bool IsSpace(CodePoint c) { return c == 0x20 || c == 0xA; }
-
-gsl::index Utf16PreviousWord(std::u16string_view str, gsl::index position,
- bool *is_space) {
- if (position <= 0)
- return position;
- auto c = Utf16PreviousCodePoint(str, position, nullptr);
- if (IsSpace(c)) { // TODO: Currently only test against 0x20(space).
- if (is_space)
- *is_space = true;
- return Utf16BackwardUntil(str, position,
- [](CodePoint c) { return !IsSpace(c); });
- } else {
- if (is_space)
- *is_space = false;
- return Utf16BackwardUntil(str, position, IsSpace);
- }
-}
-
-gsl::index Utf16NextWord(std::u16string_view str, gsl::index position,
- bool *is_space) {
- if (position >= static_cast<gsl::index>(str.size()))
- return position;
- auto c = Utf16NextCodePoint(str, position, nullptr);
- if (IsSpace(c)) { // TODO: Currently only test against 0x20(space).
- if (is_space)
- *is_space = true;
- return Utf16ForwardUntil(str, position,
- [](CodePoint c) { return !IsSpace(c); });
- } else {
- if (is_space)
- *is_space = false;
- return Utf16ForwardUntil(str, position, IsSpace);
- }
-}
-} // namespace cru
diff --git a/works/life/cpp-practicum/StringUtil.hpp b/works/life/cpp-practicum/StringUtil.hpp
deleted file mode 100644
index d7b6cc9..0000000
--- a/works/life/cpp-practicum/StringUtil.hpp
+++ /dev/null
@@ -1,148 +0,0 @@
-#pragma once
-#include "Base.hpp"
-
-#include <functional>
-#include <string>
-#include <string_view>
-
-namespace cru {
-using CodePoint = std::int32_t;
-constexpr CodePoint k_invalid_code_point = -1;
-
-class TextEncodeException : public std::runtime_error {
-public:
- using runtime_error::runtime_error;
-};
-
-inline bool IsUtf16SurrogatePairCodeUnit(char16_t c) {
- return c >= 0xD800 && c <= 0xDFFF;
-}
-
-inline bool IsUtf16SurrogatePairLeading(char16_t c) {
- return c >= 0xD800 && c <= 0xDBFF;
-}
-
-inline bool IsUtf16SurrogatePairTrailing(char16_t c) {
- return c >= 0xDC00 && c <= 0xDFFF;
-}
-
-CodePoint Utf8NextCodePoint(std::string_view str, Index current,
- Index *next_position);
-
-CodePoint Utf16NextCodePoint(std::u16string_view str, Index current,
- Index *next_position);
-CodePoint Utf16PreviousCodePoint(std::u16string_view str, Index current,
- Index *previous_position);
-
-template <typename StringType>
-using NextCodePointFunctionType = CodePoint (*)(StringType, Index, Index *);
-
-template <typename StringType,
- NextCodePointFunctionType<StringType> NextCodePointFunction>
-class CodePointIterator {
-public:
- using difference_type = Index;
- using value_type = CodePoint;
- using pointer = void;
- using reference = value_type;
- using iterator_category = std::forward_iterator_tag;
-
-public:
- struct past_end_tag_t {};
-
- explicit CodePointIterator(StringType string)
- : string_(std::move(string)), position_(0) {}
- explicit CodePointIterator(StringType string, past_end_tag_t)
- : string_(std::move(string)), position_(string_.size()) {}
-
- CRU_DEFAULT_COPY(CodePointIterator)
- CRU_DEFAULT_MOVE(CodePointIterator)
-
- ~CodePointIterator() = default;
-
-public:
- StringType GetString() const { return string_; }
- Index GetPosition() const { return position_; }
-
- bool IsPastEnd() const {
- return position_ == static_cast<Index>(string_.size());
- }
-
-public:
- CodePointIterator begin() const { return *this; }
- CodePointIterator end() const {
- return CodePointIterator{string_, past_end_tag_t{}};
- }
-
-public:
- bool operator==(const CodePointIterator &other) const {
- // You should compare iterator that iterate on the same string.
- Expects(this->string_.data() == other.string_.data() &&
- this->string_.size() == other.string_.size());
- return this->position_ == other.position_;
- }
- bool operator!=(const CodePointIterator &other) const {
- return !this->operator==(other);
- }
-
- CodePointIterator &operator++() {
- Expects(!IsPastEnd());
- Forward();
- return *this;
- }
-
- CodePointIterator operator++(int) {
- Expects(!IsPastEnd());
- CodePointIterator old = *this;
- Forward();
- return old;
- }
-
- CodePoint operator*() const {
- return NextCodePointFunction(string_, position_, &next_position_cache_);
- }
-
-private:
- void Forward() {
- if (next_position_cache_ > position_) {
- position_ = next_position_cache_;
- } else {
- NextCodePointFunction(string_, position_, &position_);
- }
- }
-
-private:
- StringType string_;
- Index position_;
- mutable Index next_position_cache_;
-};
-
-using Utf8CodePointIterator =
- CodePointIterator<std::string_view, &Utf8NextCodePoint>;
-
-using Utf16CodePointIterator =
- CodePointIterator<std::u16string_view, &Utf16NextCodePoint>;
-
-void Utf8EncodeCodePointAppend(CodePoint code_point, std::string &str);
-void Utf16EncodeCodePointAppend(CodePoint code_point, std::u16string &str);
-
-std::string ToUtf8(std::u16string_view s);
-std::u16string ToUtf16(std::string_view s);
-
-// If given s is not a valid utf16 string, return value is UD.
-bool Utf16IsValidInsertPosition(std::u16string_view s, gsl::index position);
-
-// Return position after the character making predicate returns true or 0 if no
-// character doing so.
-gsl::index Utf16BackwardUntil(std::u16string_view str, gsl::index position,
- const std::function<bool(CodePoint)> &predicate);
-// Return position before the character making predicate returns true or
-// str.size() if no character doing so.
-gsl::index Utf16ForwardUntil(std::u16string_view str, gsl::index position,
- const std::function<bool(CodePoint)> &predicate);
-
-gsl::index Utf16PreviousWord(std::u16string_view str, gsl::index position,
- bool *is_space = nullptr);
-gsl::index Utf16NextWord(std::u16string_view str, gsl::index position,
- bool *is_space = nullptr);
-} // namespace cru
diff --git a/works/life/cpp-practicum/Vendor.cpp b/works/life/cpp-practicum/Vendor.cpp
new file mode 100644
index 0000000..7544451
--- /dev/null
+++ b/works/life/cpp-practicum/Vendor.cpp
@@ -0,0 +1,33 @@
+#include "Vendor.hpp"
+
+#include <QString>
+
+QTextStream &operator>>(QTextStream &left, Vendor &right) {
+ auto line = left.readLine();
+
+ auto fields = line.split(QChar('|'));
+
+ if (fields.size() != 5) {
+ throw SerializationException("Line has not 5 parts.");
+ }
+
+ bool ok;
+ auto id = fields[0].toInt(&ok);
+ if (!ok) {
+ throw SerializationException("Part 1 is not a number.");
+ }
+
+ right.SetId(id);
+ right.SetName(fields[1].toStdU16String());
+ right.SetType(fields[2].toStdU16String());
+ right.SetAddress(fields[3].toStdU16String());
+ right.SetPhone(fields[4].toStdU16String());
+
+ return left;
+}
+
+QTextStream &operator<<(QTextStream &left, const Vendor &right) {
+ left << right.GetId() << '|' << right.GetName() << '|' << right.GetType()
+ << '|' << right.GetAddress() << '|' << right.GetPhone();
+ return left;
+}
diff --git a/works/life/cpp-practicum/Vendor.hpp b/works/life/cpp-practicum/Vendor.hpp
new file mode 100644
index 0000000..24c22ee
--- /dev/null
+++ b/works/life/cpp-practicum/Vendor.hpp
@@ -0,0 +1,45 @@
+#pragma once
+#include "Base.hpp"
+
+#include <QTextStream>
+#include <string>
+
+class Vendor final {
+public:
+ Vendor() = default;
+ Vendor(int id, std::u16string name, std::u16string type,
+ std::u16string address, std::u16string phone)
+ : id_(id), name_(std::move(name)), type_(std::move(type)),
+ address_(std::move(address)), phone_(std::move(phone)) {}
+
+ CRU_DEFAULT_COPY(Vendor)
+ CRU_DEFAULT_MOVE(Vendor)
+
+ ~Vendor() = default;
+
+public:
+ int GetId() const { return id_; }
+ void SetId(int id) { id_ = id; }
+
+ std::u16string GetName() const { return name_; }
+ void SetName(std::u16string name) { name_ = std::move(name); }
+
+ std::u16string GetType() const { return type_; }
+ void SetType(std::u16string type) { type_ = std::move(type); }
+
+ std::u16string GetAddress() const { return address_; }
+ void SetAddress(std::u16string address) { address_ = std::move(address); }
+
+ std::u16string GetPhone() const { return phone_; }
+ void SetPhone(std::u16string phone) { phone_ = std::move(phone); }
+
+private:
+ int id_;
+ std::u16string name_;
+ std::u16string type_;
+ std::u16string address_;
+ std::u16string phone_;
+};
+
+QTextStream &operator>>(QTextStream &left, Vendor &right);
+QTextStream &operator<<(QTextStream &left, const Vendor &right);
diff --git a/works/life/cpp-practicum/main.cpp b/works/life/cpp-practicum/main.cpp
index 0f90b74..a6c92e5 100644
--- a/works/life/cpp-practicum/main.cpp
+++ b/works/life/cpp-practicum/main.cpp
@@ -1,281 +1,34 @@
-#include "Base.hpp"
-#include "StringUtil.hpp"
+#include "qboxlayout.h"
+#include "qnamespace.h"
+#include <QApplication>
+#include <QHBoxLayout>
+#include <QMainWindow>
+#include <QPushButton>
+#include <QVBoxLayout>
+#include <QWidget>
-#include <fstream>
-#include <iostream>
-#include <optional>
-#include <ostream>
-#include <stdexcept>
-#include <string>
-#include <string_view>
-#include <type_traits>
+int main(int argc, char *argv[]) {
+ QApplication application(argc, argv);
-inline std::u16string_view ToUtf16View(const std::wstring &str) {
- return std::u16string_view(reinterpret_cast<const char16_t *>(str.c_str()),
- str.size());
-}
-
-inline std::wstring_view ToWStringView(std::u16string_view str) {
- return std::wstring_view(reinterpret_cast<const wchar_t *>(str.data()),
- str.size());
-}
-
-class SerializationException : public std::runtime_error {
-public:
- using runtime_error::runtime_error;
-};
-
-std::vector<std::string_view> SplitByVerticalLine(std::string_view str,
- int field_count) {
- std::vector<std::string_view> fields;
- gsl::index current_position = 0;
-
- for (int i = 0; i < field_count - 1; i++) {
- auto pos = str.find('|', current_position);
- if (pos == std::string::npos) {
- throw SerializationException("Failed to find next splitter('|').");
- }
- fields.push_back(str.substr(current_position, pos - current_position));
- current_position = pos + 1;
- }
- fields.push_back(str.substr(current_position));
-
- return fields;
-}
-
-class Book final {
-public:
- Book() = default;
-
- Book(std::u16string isbn, std::u16string title, std::u16string type,
- std::u16string author, std::u16string press, int stock_count)
- : isbn_(std::move(isbn)), title_(std::move(title)),
- type_(std::move(type)), author_(std::move(author)),
- press_(std::move(press)), stock_count_(stock_count) {}
-
- CRU_DEFAULT_COPY(Book)
- CRU_DEFAULT_MOVE(Book)
-
- ~Book() = default;
-
-public:
- std::u16string GetIsbn() const { return isbn_; }
- void SetIsbn(std::u16string isbn) { isbn_ = std::move(isbn); }
-
- std::u16string GetTitle() const { return title_; }
- void SetTitle(std::u16string title) { title_ = std::move(title); }
-
- std::u16string GetType() const { return type_; }
- void SetType(std::u16string type) { type_ = std::move(type); }
-
- std::u16string GetAuthor() const { return author_; }
- void SetAuthor(std::u16string author) { author_ = std::move(author); }
-
- std::u16string GetPress() const { return press_; }
- void SetPress(std::u16string press) { press_ = std::move(press); }
-
- int GetStockCount() const { return stock_count_; }
- void SetStockCount(int stock_count) { stock_count_ = stock_count; }
-
-private:
- std::u16string isbn_;
- std::u16string title_;
- std::u16string type_;
- std::u16string author_;
- std::u16string press_;
- int stock_count_;
-};
-
-std::istream &operator>>(std::istream &left, Book &right) {
- std::string line;
- std::getline(left, line);
-
- std::vector<std::string_view> fields = SplitByVerticalLine(line, 6);
-
- right.SetIsbn(cru::ToUtf16(fields[0]));
- right.SetTitle(cru::ToUtf16(fields[1]));
- right.SetType(cru::ToUtf16(fields[2]));
- right.SetAuthor(cru::ToUtf16(fields[3]));
- right.SetPress(cru::ToUtf16(fields[4]));
- right.SetStockCount(std::stoi(std::string(fields[5])));
-
- return left;
-}
-
-std::ostream &operator<<(std::ostream &left, const Book &right) {
- left << cru::ToUtf8(right.GetIsbn()) << '|' << cru::ToUtf8(right.GetTitle())
- << '|' << cru::ToUtf8(right.GetType()) << '|'
- << cru::ToUtf8(right.GetAuthor()) << '|' << cru::ToUtf8(right.GetPress())
- << '|' << right.GetStockCount();
- return left;
-}
-
-void PrettyPrint(std::wostream &stream, const Book &book) {
- stream << L"ISBN: " << ToWStringView(book.GetIsbn()) << L"\n";
- stream << L"标题: " << ToWStringView(book.GetTitle()) << L"\n";
- stream << L"类型: " << ToWStringView(book.GetType()) << L"\n";
- stream << L"作者: " << ToWStringView(book.GetAuthor()) << L"\n";
- stream << L"出版社: " << ToWStringView(book.GetPress()) << L"\n";
- stream << L"库存: " << book.GetStockCount() << L"\n";
-}
-
-class Vendor final {
-public:
- Vendor() = default;
- Vendor(int id, std::u16string name, std::u16string type,
- std::u16string address, std::u16string phone)
- : id_(id), name_(std::move(name)), type_(std::move(type)),
- address_(std::move(address)), phone_(std::move(phone)) {}
-
- CRU_DEFAULT_COPY(Vendor)
- CRU_DEFAULT_MOVE(Vendor)
-
- ~Vendor() = default;
-
-public:
- int GetId() const { return id_; }
- void SetId(int id) { id_ = id; }
-
- std::u16string GetName() const { return name_; }
- void SetName(std::u16string name) { name_ = std::move(name); }
-
- std::u16string GetType() const { return type_; }
- void SetType(std::u16string type) { type_ = std::move(type); }
-
- std::u16string GetAddress() const { return address_; }
- void SetAddress(std::u16string address) { address_ = std::move(address); }
-
- std::u16string GetPhone() const { return phone_; }
- void SetPhone(std::u16string phone) { phone_ = std::move(phone); }
-
-private:
- int id_;
- std::u16string name_;
- std::u16string type_;
- std::u16string address_;
- std::u16string phone_;
-};
-
-std::istream &operator>>(std::istream &left, Vendor &right) {
- std::string line;
- std::getline(left, line);
-
- std::vector<std::string_view> fields = SplitByVerticalLine(line, 5);
-
- right.SetId(std::stoi(std::string(fields[0])));
- right.SetName(cru::ToUtf16(fields[1]));
- right.SetType(cru::ToUtf16(fields[2]));
- right.SetAddress(cru::ToUtf16(fields[3]));
- right.SetPhone(cru::ToUtf16(fields[4]));
-
- return left;
-}
-
-std::ostream &operator<<(std::ostream &left, const Vendor &right) {
- left << right.GetId() << '|' << cru::ToUtf8(right.GetName()) << '|'
- << cru::ToUtf8(right.GetType()) << '|' << cru::ToUtf8(right.GetAddress())
- << '|' << cru::ToUtf8(right.GetPhone());
- return left;
-}
-
-class Record final {
-public:
- Record();
-
- CRU_DEFAULT_COPY(Record);
- CRU_DEFAULT_MOVE(Record);
-
- ~Record() = default;
-
-public:
- void WriteTo(std::ostream &stream);
- void ReadFrom(std::istream &stream);
-
- const std::vector<Book> &GetBooks() const { return books_; }
- const std::vector<Vendor> &GetVendors() const { return vendors_; }
-
- // TODO: Implementation
- std::optional<Book> FindBookByIsbn(std::u16string_view isbn);
-
- // TODO: Implementation
- void RemoveBookByIsbn(std::u16string_view isbn);
-
-private:
- std::vector<Book> books_;
- std::vector<Vendor> vendors_;
-};
-
-void Record::WriteTo(std::ostream &stream) {
- stream << books_.size() << ' ' << vendors_.size() << '\n';
- for (const auto &book : books_) {
- stream << book << '\n';
- }
- for (const auto &vendor : vendors_) {
- stream << vendor << '\n';
- }
-}
-
-void Record::ReadFrom(std::istream &stream) {
- books_.clear();
- vendors_.clear();
- int book_count, vendor_count;
- stream >> book_count >> vendor_count;
- stream >> std::ws;
- for (int i = 0; i < book_count; i++) {
- Book book;
- stream >> book;
- books_.push_back(std::move(book));
- }
- for (int i = 0; i < vendor_count; i++) {
- Vendor vendor;
- stream >> vendor;
- vendors_.push_back(std::move(vendor));
- }
-}
+ QMainWindow main_window;
-int main() {
- Record record;
+ QWidget centeral_area;
+ QVBoxLayout central_area_layout;
+ centeral_area.setLayout(&central_area_layout);
- while (true) {
- std::wcout << L"1. 查询 2. 添加 0. 退出\n";
- int choice = 0;
- std::wcin >> choice;
- if (choice == 1) {
- std::wcout
- << L"1. 图书 2. 供应商\n输入数字选择操作,其他任意字符将退出程序。\n";
- choice = 0;
- std::wcin >> choice;
- if (choice == 1) {
- std::wcout << L"请输入图书编号:\n";
- std::wstring isbn;
- std::wcin >> isbn;
- auto find_result = record.FindBookByIsbn(ToUtf16View(isbn));
- if (find_result) {
- PrettyPrint(std::wcout, *find_result);
- std::wcout << L"0. 返回主菜单 1. 修改 2. 删除\n";
- choice = 0;
- std::wcin >> choice;
- if (choice == 1) {
- // TODO:
- } else if (choice == 2) {
- record.RemoveBookByIsbn(ToUtf16View(isbn));
- std::wcout << L"删除成功。\n";
- }
- } else {
- std::wcout << L"该书不存在。\n";
- }
- } else if (choice == 2) {
+ main_window.setCentralWidget(&centeral_area);
- } else {
- return 0;
- }
+ QWidget top_bar;
+ QHBoxLayout top_bar_layout;
+ top_bar.setLayout(&top_bar_layout);
+ central_area_layout.addWidget(&top_bar);
- } else if (choice == 2) {
+ QPushButton import_button(QStringLiteral("导入"));
+ QPushButton export_button(QStringLiteral("导出"));
+ top_bar_layout.addWidget(&import_button);
+ top_bar_layout.addWidget(&export_button);
- } else {
- return 0;
- }
- }
+ main_window.show();
- return 0;
+ return application.exec();
}