summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFuwn <[email protected]>2024-05-26 18:01:25 -0700
committerFuwn <[email protected]>2024-05-26 18:01:25 -0700
commitfa3595d69f817ad1a67b7189ed65dbde1ba9f77d (patch)
treeae85e0ba5f132ce89021cc1e4bcea4e642ffee6c
downloadcst_136_assignment_eight-fa3595d69f817ad1a67b7189ed65dbde1ba9f77d.tar.xz
cst_136_assignment_eight-fa3595d69f817ad1a67b7189ed65dbde1ba9f77d.zip
feat: initial commit
-rw-r--r--.gitignore11
-rw-r--r--Makefile35
-rw-r--r--Tupfile13
-rw-r--r--include/book_store/book.hh62
-rw-r--r--include/book_store/book_count.hh37
-rw-r--r--include/book_store/member.hh41
-rw-r--r--include/book_store/person.hh36
-rw-r--r--include/book_store/price.hh39
-rw-r--r--include/book_store/random.hh66
-rw-r--r--source/book.cc102
-rw-r--r--source/main.cc99
-rw-r--r--source/member.cc23
-rw-r--r--source/person.cc43
-rw-r--r--source/random.cc87
14 files changed, 694 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..c8f22de
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,11 @@
+# clangd
+.cache/
+
+# Tup
+.tup/
+
+# Build Artifacts
+build/
+
+# Compilation database
+compile_commands.json
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..a962a6f
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,35 @@
+SOURCE_DIRECTORY = source
+INCLUDE_DIRECTORY = include
+BUILD_DIRECTORY = build
+CC = clang++
+CC_EXTENSION = cc
+CC_FLAGS = -std=c++23 -I $(INCLUDE_DIRECTORY) -Weverything -Wno-padded -Wno-c++98-compat -MMD
+CLANG_TIDY_CHECKS = '-*,bugprone-*,clang-analyzer-*,concurrency-*,cppcoreguildelines-*,llvm-*,misc-*,modernize-*,performance-*,portability-*,readability-*,-readability-magic-numbers,-llvm-header-guard'
+CLANG_TIDY_FLAGS = -checks=$(CLANG_TIDY_CHECKS) -header-filter=.* -warnings-as-errors=* -system-headers=0
+SOURCES = $(wildcard $(SOURCE_DIRECTORY)/*.$(CC_EXTENSION))
+OBJECTS = $(SOURCES:$(SOURCE_DIRECTORY)/%.$(CC_EXTENSION)=$(BUILD_DIRECTORY)/%.o)
+DEPS = $(OBJECTS:.o=.d)
+
+all: $(BUILD_DIRECTORY)/book_store
+
+format:
+ clang-format -i $(SOURCES) $(wildcard $(INCLUDE_DIRECTORY)/*.hh)
+
+tidy:
+ clang-tidy $(SOURCES) $(CLANG_TIDY_FLAGS) -- $(CC_FLAGS)
+
+$(BUILD_DIRECTORY)/%.o: $(SOURCE_DIRECTORY)/%.$(CC_EXTENSION) | $(BUILD_DIRECTORY)
+ $(CC) $(CC_FLAGS) -MF $(@:.o=.d) -c $< -o $@
+
+$(BUILD_DIRECTORY)/book_store: $(OBJECTS)
+ $(CC) $^ -o $@
+
+$(BUILD_DIRECTORY):
+ mkdir -p $(BUILD_DIRECTORY)
+
+clean:
+ rm -rf $(BUILD_DIRECTORY)
+
+-include $(DEPS)
+
+.PHONY: all format tidy clean
diff --git a/Tupfile b/Tupfile
new file mode 100644
index 0000000..36f4be6
--- /dev/null
+++ b/Tupfile
@@ -0,0 +1,13 @@
+SOURCE_DIRECTORY = source
+INCLUDE_DIRECTORY = include
+BUILD_DIRECTORY = build
+CC = clang++
+CC_EXTENSION = cc
+CC_FLAGS = -std=c++23 -I $(INCLUDE_DIRECTORY) -Weverything -Wno-padded -Wno-c++98-compat -MMD
+CLANG_TIDY_CHECKS = '-*,bugprone-*,clang-analyzer-*,concurrency-*,cppcoreguildelines-*,llvm-*,misc-*,modernize-*,performance-*,portability-*,readability-*,-readability-magic-numbers,-llvm-header-guard'
+CLANG_TIDY_FLAGS = -checks=$(CLANG_TIDY_CHECKS) -header-filter=.* -warnings-as-errors=* -system-headers=0
+
+: foreach $(SOURCE_DIRECTORY)/*.$(CC_EXTENSION) $(INCLUDE_DIRECTORY)/*.hh |> clang-format -i %f |>
+: foreach $(SOURCE_DIRECTORY)/*.$(CC_EXTENSION) |> clang-tidy $(CLANG_TIDY_FLAGS) %f -- $(CC_FLAGS) |>
+: foreach $(SOURCE_DIRECTORY)/*.$(CC_EXTENSION) |> ^j^ $(CC) $(CC_FLAGS) -MF $(BUILD_DIRECTORY)/%B.d -c %f -o %o |> $(BUILD_DIRECTORY)/%B.o | $(BUILD_DIRECTORY)/%B.d
+: $(BUILD_DIRECTORY)/*.o |> $(CC) %f -o %o |> $(BUILD_DIRECTORY)/book_store
diff --git a/include/book_store/book.hh b/include/book_store/book.hh
new file mode 100644
index 0000000..23420da
--- /dev/null
+++ b/include/book_store/book.hh
@@ -0,0 +1,62 @@
+#ifndef BOOK_HH
+#define BOOK_HH
+
+#include <iostream>
+#include <ostream>
+#include <string>
+#include <vector>
+
+#include "book_count.hh"
+#include "person.hh"
+#include "price.hh"
+
+namespace book_store::product {
+class book {
+public:
+ using size_type = book_count;
+ using price_type = price::usd;
+
+private:
+ std::string _title;
+ std::vector<consumer::person> _authors;
+ std::string _publisher;
+ std::string _isbn;
+ price_type _price_usd;
+ size_type _copies;
+
+public:
+ book(std::string title, std::vector<consumer::person> authors,
+ std::string publisher, std::string isbn, price::usd price,
+ size_type copies)
+ : _title(std::move(title)), _authors(std::move(authors)),
+ _publisher(std::move(publisher)), _isbn(std::move(isbn)),
+ _price_usd(price), _copies(copies) {}
+ book() noexcept : _authors({}), _price_usd(0.0), _copies(0) {}
+ book(const book &) noexcept = default;
+ book(book &&) noexcept = default;
+
+ [[nodiscard]] auto title() const noexcept -> std::string_view;
+ [[nodiscard]] auto authors() const noexcept -> std::vector<consumer::person>;
+ [[nodiscard]] auto publisher() const noexcept -> std::string_view;
+ [[nodiscard]] auto isbn() const noexcept -> std::string_view;
+ [[nodiscard]] auto price_usd() const noexcept -> price_type;
+ [[nodiscard]] auto copies() const noexcept -> size_type;
+
+ auto title(std::string_view title) noexcept -> book &;
+ auto authors(std::vector<consumer::person> authors) -> book &;
+ auto author(const consumer::person &author) -> book &;
+ auto remove_author_by_id(std::size_t author_id) -> book &;
+ auto publisher(std::string_view publisher) noexcept -> book &;
+ auto isbn(std::string_view isbn) noexcept -> book &;
+ auto price_usd(price_type price) noexcept -> book &;
+ auto copies(size_type copies) noexcept -> book &;
+
+ auto operator=(const book &) -> book & = default;
+ auto operator=(book &&) -> book & = default;
+
+ friend auto operator<<(std::ostream &output_stream, const book &book)
+ -> std::ostream &;
+};
+} // namespace book_store::product
+
+#endif // BOOK_HH
diff --git a/include/book_store/book_count.hh b/include/book_store/book_count.hh
new file mode 100644
index 0000000..a9c68c1
--- /dev/null
+++ b/include/book_store/book_count.hh
@@ -0,0 +1,37 @@
+#ifndef BOOK_COUNT_HH
+#define BOOK_COUNT_HH
+
+#include <ostream>
+#include <string>
+
+namespace book_store::product {
+class book_count {
+public:
+ using book_count_type = std::size_t;
+
+private:
+ book_count_type _count;
+
+public:
+ book_count() = default;
+ book_count(book_count_type count) : _count(count) {}
+
+ friend auto operator<<(std::ostream &output_stream, const book_count &price)
+ -> std::ostream & {
+ output_stream << price._count;
+
+ return output_stream;
+ }
+
+ friend auto operator==(const book_count &lhs, const book_count &rhs) -> bool {
+ return lhs._count == rhs._count;
+ }
+
+ friend auto operator+(const book_count &lhs, const book_count &rhs)
+ -> book_count {
+ return {lhs._count + rhs._count};
+ }
+};
+} // namespace book_store::product
+
+#endif // BOOK_COUNT_HH
diff --git a/include/book_store/member.hh b/include/book_store/member.hh
new file mode 100644
index 0000000..0796a11
--- /dev/null
+++ b/include/book_store/member.hh
@@ -0,0 +1,41 @@
+#ifndef MEMBER_HH
+#define MEMBER_HH
+
+#include <cstddef>
+
+#include "book.hh"
+#include "person.hh"
+#include "price.hh"
+
+namespace book_store::consumer {
+class member : person {
+
+private:
+ product::book::book::size_type _books_bought;
+ product::price::usd _amount_spent;
+
+public:
+ member(std::string last_name, std::string first_name, std::size_t member_id)
+ : person(std::move(last_name), std::move(first_name), member_id),
+ _books_bought(0), _amount_spent(0) {}
+ member(std::string last_name, std::string first_name, std::size_t member_id,
+ product::book::size_type books_baught,
+ product::price::usd amount_spent)
+ : person(std::move(last_name), std::move(first_name), member_id),
+ _books_bought(books_baught), _amount_spent(amount_spent) {}
+ member() = default;
+ member(const member &) = default;
+ member(member &&) = default;
+
+ [[nodiscard]] auto books_bought() const noexcept -> product::book::size_type;
+ [[nodiscard]] auto amount_spent() const noexcept -> product::price::usd;
+
+ auto books_bought(product::book::size_type books_bought) noexcept -> void;
+ auto amount_spent(product::price::usd amount_spent) noexcept -> void;
+
+ auto operator=(const member &) -> member & = default;
+ auto operator=(member &&) -> member & = default;
+};
+} // namespace book_store::consumer
+
+#endif // MEMBER_HH
diff --git a/include/book_store/person.hh b/include/book_store/person.hh
new file mode 100644
index 0000000..46b9d59
--- /dev/null
+++ b/include/book_store/person.hh
@@ -0,0 +1,36 @@
+#ifndef PERSON_HH
+#define PERSON_HH
+
+#include <string>
+
+namespace book_store::consumer {
+class person {
+private:
+ std::string _last_name;
+ std::string _first_name;
+ std::size_t _id;
+
+public:
+ person(std::string last_name, std::string first_name, std::size_t person_id)
+ : _last_name(std::move(last_name)), _first_name(std::move(first_name)),
+ _id(person_id) {}
+ person() = default;
+ person(const person &) = default;
+ person(person &&) = default;
+
+ [[nodiscard]] auto last_name() const noexcept -> std::string_view;
+ [[nodiscard]] auto first_name() const noexcept -> std::string_view;
+ [[nodiscard]] auto full_name(bool last_first = false) const noexcept
+ -> std::string;
+ [[nodiscard]] auto id() const noexcept -> std::size_t;
+
+ auto last_name(std::string_view last_name) noexcept -> person &;
+ auto first_name(std::string_view first_name) noexcept -> person &;
+ auto id(std::size_t person_id) noexcept -> person &;
+
+ auto operator=(const person &) -> person & = default;
+ auto operator=(person &&) -> person & = default;
+};
+} // namespace book_store::consumer
+
+#endif // PERSON_HH
diff --git a/include/book_store/price.hh b/include/book_store/price.hh
new file mode 100644
index 0000000..39f14b8
--- /dev/null
+++ b/include/book_store/price.hh
@@ -0,0 +1,39 @@
+#ifndef PRICE_HH
+#define PRICE_HH
+
+#include <ostream>
+#include <string>
+
+namespace book_store::product::price {
+class usd {
+public:
+ using price_type = double;
+
+private:
+ price_type _price;
+
+public:
+ usd() = default;
+ usd(price_type price) : _price(price) {}
+ usd(const std::string &price) : _price(std::stod(price)) {}
+
+ auto operator=(const std::string &value) -> usd & {
+ _price = std::stod(value);
+
+ return *this;
+ }
+
+ friend auto operator<<(std::ostream &output_stream, const usd &price)
+ -> std::ostream & {
+ output_stream << price._price;
+
+ return output_stream;
+ }
+
+ friend auto operator==(const usd &lhs, const usd &rhs) -> bool {
+ return std::abs(lhs._price - rhs._price) < 0.0001;
+ }
+};
+} // namespace book_store::product::price
+
+#endif // PRICE_HH
diff --git a/include/book_store/random.hh b/include/book_store/random.hh
new file mode 100644
index 0000000..e279feb
--- /dev/null
+++ b/include/book_store/random.hh
@@ -0,0 +1,66 @@
+#ifndef RANDOM_HH
+#define RANDOM_HH
+
+#include <array>
+#include <cstddef>
+#include <random>
+#include <string>
+#include <string_view>
+#include <vector>
+
+#include "book.hh"
+#include "person.hh"
+
+namespace book_store::utility::random {
+constexpr std::array<std::string_view, 50> names = {
+ "James", "John", "Robert", "Michael", "William", "David",
+ "Richard", "Joseph", "Thomas", "Charles", "Daniel", "Matthew",
+ "Anthony", "Donald", "Mark", "Paul", "Steven", "Andrew",
+ "Kenneth", "Joshua", "George", "Kevin", "Brian", "Edward",
+ "Ronald", "Timothy", "Jason", "Jeffrey", "Ryan", "Jacob",
+ "Gary", "Nicholas", "Eric", "Stephen", "Jonathan", "Larry",
+ "Justin", "Scott", "Brandon", "Frank", "Benjamin", "Gregory",
+ "Samuel", "Raymond", "Patrick", "Alexander", "Jack", "Dennis",
+ "Jerry", "Tyler"};
+constexpr std::array<std::string_view, 50> book_title_parts = {
+ "The", "A", "An", "In", "Of", "And",
+ "To", "For", "With", "On", "At", "By",
+ "From", "Up", "About", "Into", "Over", "After",
+ "Between", "Out", "Against", "Under", "Without", "Within",
+ "Along", "Across", "Behind", "Beyond", "Through", "Around",
+ "Among", "Upon", "Beside", "Toward", "Against", "Upon",
+ "Amongst", "Between", "Within", "Without", "Underneath", "Under",
+ "Over", "Into", "About", "Up", "From", "By",
+ "At", "On"};
+constexpr std::array<std::string_view, 10> publishers = {
+ "Penguin", "Random House", "HarperCollins", "Simon & Schuster",
+ "Macmillan", "Hachette", "Harlequin", "Scholastic",
+ "Pearson", "Houghton Mifflin"};
+
+class book_random_engine {
+private:
+ std::mt19937 _random_number_generator;
+
+public:
+ book_random_engine() : _random_number_generator(std::random_device{}()) {}
+ explicit book_random_engine(std::mt19937 random_number_generator)
+ : _random_number_generator(random_number_generator) {}
+ book_random_engine(const book_random_engine &) = default;
+ book_random_engine(book_random_engine &&) = default;
+
+ auto title() -> std::string;
+ auto name() -> std::string;
+ auto author() -> consumer::person;
+ auto authors() -> std::vector<consumer::person>;
+ auto publisher() -> std::string;
+ auto isbn() -> std::string;
+ auto price_usd() -> double;
+ auto copy_count() -> product::book::size_type;
+ auto id() -> std::size_t;
+
+ auto operator=(const book_random_engine &) -> book_random_engine & = default;
+ auto operator=(book_random_engine &&) -> book_random_engine & = default;
+};
+} // namespace book_store::utility::random
+
+#endif // RANDOM_HH
diff --git a/source/book.cc b/source/book.cc
new file mode 100644
index 0000000..6b0bd6a
--- /dev/null
+++ b/source/book.cc
@@ -0,0 +1,102 @@
+#include <cstddef>
+#include <ostream>
+#include <string_view>
+#include <utility>
+#include <vector>
+
+#include <book_store/book.hh>
+#include <book_store/person.hh>
+#include <book_store/price.hh>
+
+namespace book_store::product {
+using namespace consumer;
+
+auto book::title() const noexcept -> std::string_view { return this->_title; }
+
+auto book::authors() const noexcept -> std::vector<class person> {
+ return this->_authors;
+}
+
+auto book::publisher() const noexcept -> std::string_view {
+ return this->_publisher;
+}
+
+auto book::isbn() const noexcept -> std::string_view { return this->_isbn; }
+
+auto book::price_usd() const noexcept -> price::usd { return this->_price_usd; }
+
+auto book::copies() const noexcept -> book::size_type { return this->_copies; }
+
+auto book::title(std::string_view title) noexcept -> book & {
+ this->_title = title;
+
+ return *this;
+}
+
+auto book::authors(std::vector<class person> authors) -> book & {
+ this->_authors = std::move(authors);
+
+ return *this;
+}
+
+auto book::author(const class person &author) -> book & {
+ while (this->_authors.size() < 4) {
+ this->_authors.emplace_back(author);
+
+ break;
+ }
+
+ return *this;
+}
+
+auto book::remove_author_by_id(std::size_t author_id) -> book & {
+ this->_authors.erase(
+ this->_authors.begin() +
+ static_cast<std::vector<class person>::difference_type>(author_id));
+
+ return *this;
+}
+
+auto book::publisher(std::string_view publisher) noexcept -> book & {
+ this->_publisher = publisher;
+
+ return *this;
+}
+
+auto book::isbn(std::string_view isbn) noexcept -> book & {
+ this->_isbn = isbn;
+
+ return *this;
+}
+
+auto book::price_usd(price::usd price) noexcept -> book & {
+ this->_price_usd = price;
+
+ return *this;
+}
+
+auto book::copies(book::size_type copies) noexcept -> book & {
+ this->_copies = copies;
+
+ return *this;
+}
+
+auto operator<<(std::ostream &output_stream, const book &book)
+ -> std::ostream & {
+ output_stream << "Title: " << book._title << '\n';
+ output_stream << "Authors: ";
+
+ for (const auto &author : book._authors) {
+ output_stream << author.full_name()
+ << ((&author == &book._authors.back()) ? "" : ", ");
+ }
+
+ output_stream << '\n';
+ output_stream << "Publisher: " << book._publisher << '\n';
+ output_stream << "ISBN: " << book._isbn << '\n';
+ output_stream << "Price: $" << book._price_usd << '\n';
+ output_stream << "Copies: " << book._copies << '\n';
+
+ return output_stream;
+}
+} // namespace book_store::product
diff --git a/source/main.cc b/source/main.cc
new file mode 100644
index 0000000..5d262f7
--- /dev/null
+++ b/source/main.cc
@@ -0,0 +1,99 @@
+#include <algorithm>
+#include <array>
+#include <cstdlib>
+#include <exception>
+#include <iostream>
+#include <random>
+#include <ranges>
+#include <string>
+#include <string_view>
+
+#include <book_store/book.hh>
+#include <book_store/member.hh>
+#include <book_store/random.hh>
+
+auto main() -> int {
+ using namespace book_store;
+
+ std::array<product::book, 100> books;
+ std::array<std::string, 100> book_titles;
+ std::array<consumer::member, 100> members;
+ std::array<std::size_t, 100> member_ids;
+ std::mt19937 random_number_generator(std::random_device{}());
+ utility::random::book_random_engine random(random_number_generator);
+ auto perform = [](std::string_view name, auto action) {
+ std::cout << name << " ...";
+
+ action();
+
+ std::cout << " ok.\n";
+ };
+ auto clear_cerr = []() {
+ if (!std::cerr.good()) {
+ std::cerr.clear();
+ }
+ };
+
+ perform("populating books and book_titles", [&]() {
+ for (auto [index, book] : std::ranges::views::enumerate(books)) {
+ auto random_title = random.title();
+
+ book_titles[static_cast<std::size_t>(index)] = random_title;
+ book =
+ product::book{random_title, random.authors(), random.publisher(),
+ random.isbn(), random.price_usd(), random.copy_count()};
+ }
+ });
+ perform("verifying all books are present", [&]() {
+ for (const auto &title : book_titles) {
+ if (std::ranges::find(book_titles, title) == book_titles.end()) {
+ clear_cerr();
+
+ std::cerr << "error: title not found" << '\n';
+
+ std::terminate();
+ }
+ }
+ });
+ perform("verifying book copy count increment", [&]() {
+ for (int i = 0; i < 100; ++i) {
+ auto &book = books[std::uniform_int_distribution<std::size_t>(
+ 0, books.size() - 1)(random_number_generator)];
+ auto copy_count = book.copies();
+ auto random_copy_count = static_cast<product::book::size_type>(
+ std::uniform_int_distribution<std::size_t>(0, 100)(
+ random_number_generator));
+
+ book.copies(copy_count + random_copy_count);
+
+ if (book.copies() != copy_count + random_copy_count) {
+ clear_cerr();
+
+ std::cerr << "error: invalid copy count after increment" << '\n';
+
+ std::terminate();
+ }
+ }
+ });
+ perform("populating members and member_ids", [&]() {
+ for (auto [index, member] : std::views::enumerate(members)) {
+ auto random_name = random.name();
+ auto random_surname = random.name();
+ auto random_id = random.id();
+
+ member_ids[static_cast<std::size_t>(index)] = random_id;
+ member = consumer::member{random_name, random_surname, random_id};
+ }
+ });
+ perform("verifying all members are present", [&]() {
+ for (auto member_id : member_ids) {
+ if (std::ranges::find(member_ids, member_id) == member_ids.end()) {
+ std::cerr << "error: id not found" << '\n';
+
+ std::terminate();
+ }
+ }
+ });
+
+ return 0;
+}
diff --git a/source/member.cc b/source/member.cc
new file mode 100644
index 0000000..0e8a41c
--- /dev/null
+++ b/source/member.cc
@@ -0,0 +1,23 @@
+#include <book_store/book.hh>
+#include <book_store/member.hh>
+#include <book_store/price.hh>
+
+namespace book_store::consumer {
+using namespace product;
+
+auto member::books_bought() const noexcept -> book::size_type {
+ return this->_books_bought;
+}
+
+auto member::amount_spent() const noexcept -> price::usd {
+ return this->_amount_spent;
+}
+
+auto member::books_bought(book::size_type books_bought) noexcept -> void {
+ this->_books_bought = books_bought;
+}
+
+auto member::amount_spent(price::usd amount_spent) noexcept -> void {
+ this->_amount_spent = amount_spent;
+}
+} // namespace book_store::consumer
diff --git a/source/person.cc b/source/person.cc
new file mode 100644
index 0000000..e80e6df
--- /dev/null
+++ b/source/person.cc
@@ -0,0 +1,43 @@
+#include <cstddef>
+#include <string>
+#include <string_view>
+
+#include <book_store/person.hh>
+
+namespace book_store::consumer {
+auto person::last_name() const noexcept -> std::string_view {
+ return this->_last_name;
+}
+
+auto person::first_name() const noexcept -> std::string_view {
+ return this->_first_name;
+}
+
+auto person::full_name(bool last_first) const noexcept -> std::string {
+ if (last_first) {
+ return this->_last_name + ", " + this->_first_name;
+ }
+
+ return this->_first_name + " " + this->_last_name;
+}
+
+auto person::id() const noexcept -> std::size_t { return this->_id; }
+
+auto person::last_name(std::string_view last_name) noexcept -> person & {
+ this->_last_name = last_name;
+
+ return *this;
+}
+
+auto person::first_name(std::string_view first_name) noexcept -> person & {
+ this->_first_name = first_name;
+
+ return *this;
+}
+
+auto person::id(std::size_t person_id) noexcept -> person & {
+ this->_id = person_id;
+
+ return *this;
+}
+} // namespace book_store::consumer
diff --git a/source/random.cc b/source/random.cc
new file mode 100644
index 0000000..d237b9f
--- /dev/null
+++ b/source/random.cc
@@ -0,0 +1,87 @@
+#include <cstddef>
+#include <random>
+#include <string>
+#include <vector>
+
+#include <book_store/book.hh>
+#include <book_store/person.hh>
+#include <book_store/random.hh>
+
+namespace book_store::utility::random {
+auto book_random_engine::title() -> std::string {
+ static std::uniform_int_distribution<> distrubtion{0, 49};
+ std::string book_name;
+
+ for (int i = 0; i < 3; ++i) {
+ book_name += book_title_parts[static_cast<std::size_t>(
+ distrubtion(this->_random_number_generator))];
+ book_name += ' ';
+ }
+
+ book_name.pop_back();
+
+ return book_name;
+}
+
+auto book_random_engine::name() -> std::string {
+ static std::uniform_int_distribution<> distrubtion{0, 49};
+
+ return std::string(names[static_cast<std::size_t>(
+ distrubtion(this->_random_number_generator))]);
+}
+
+auto book_random_engine::author() -> consumer::person {
+ return consumer::person{this->name(), this->name(), this->id()};
+}
+
+auto book_random_engine::authors() -> std::vector<consumer::person> {
+ std::vector<consumer::person> authors;
+ static std::uniform_int_distribution<> distrubtion{1, 4};
+ auto author_count = distrubtion(this->_random_number_generator);
+
+ authors.reserve(static_cast<std::size_t>(author_count));
+
+ for (int i = 0; i < author_count; ++i) {
+ authors.push_back(this->author());
+ }
+
+ return authors;
+}
+
+auto book_random_engine::publisher() -> std::string {
+ static std::uniform_int_distribution<> distrubtion{0, 9};
+
+ return std::string(publishers[static_cast<std::size_t>(
+ distrubtion(this->_random_number_generator))]);
+}
+
+auto book_random_engine::isbn() -> std::string {
+ static std::uniform_int_distribution<> distrubtion{0, 9};
+ std::string isbn;
+
+ for (int i = 0; i < 13; ++i) {
+ isbn += std::to_string(distrubtion(this->_random_number_generator));
+ }
+
+ return isbn;
+}
+
+auto book_random_engine::price_usd() -> double {
+ static std::uniform_real_distribution<> distrubtion{0.0, 100.0};
+
+ return distrubtion(this->_random_number_generator);
+}
+
+auto book_random_engine::copy_count() -> product::book::size_type {
+ static std::uniform_int_distribution<> distrubtion{0, 10000};
+
+ return static_cast<product::book::size_type::book_count_type>(
+ distrubtion(this->_random_number_generator));
+}
+
+auto book_random_engine::id() -> std::size_t {
+ static std::uniform_int_distribution<> distrubtion{0, 1000000};
+
+ return static_cast<std::size_t>(distrubtion(this->_random_number_generator));
+}
+} // namespace book_store::utility::random