Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- -----------------------------------------------------------------------
- CMakeLists.txt
- -----------------------------------------------------------------------
- cmake_minimum_required(VERSION 3.10)
- project(PhoneBook CXX)
- set(CMAKE_CXX_STANDARD 17)
- find_package(Protobuf REQUIRED)
- find_package(Threads REQUIRED)
- protobuf_generate_cpp(PROTO_SRCS PROTO_HDRS contact.proto)
- set(PHONEBOOK_FILES iterator_range.h
- main.cpp
- phone_book.h
- phone_book.cpp
- contact.proto)
- add_executable(phonebook ${PROTO_SRCS}
- ${PROTO_HDRS}
- ${PHONEBOOK_FILES})
- target_include_directories(phonebook PUBLIC ${Protobuf_INCLUDE_DIRS})
- target_include_directories(phonebook PUBLIC ${CMAKE_CURRENT_BINARY_DIR})
- string(REPLACE "protobuf.lib" "protobufd.lib" "Protobuf_LIBRARY_DEBUG" "${Protobuf_LIBRARY_DEBUG}")
- string(REPLACE "protobuf.a" "protobufd.a" "Protobuf_LIBRARY_DEBUG" "${Protobuf_LIBRARY_DEBUG}")
- target_link_libraries(phonebook "$<IF:$<CONFIG:Debug>,${Protobuf_LIBRARY_DEBUG},${Protobuf_LIBRARY}>" Threads::Threads)
- -----------------------------------------------------------------------
- contact.proto
- -----------------------------------------------------------------------
- syntax = "proto3";
- package phone_book_serialize;
- message Date {
- uint32 year = 1;
- uint32 month = 2;
- uint32 day = 3;
- }
- message Contact {
- string name = 1;
- Date birthday = 2;
- repeated string phone_number = 3;
- }
- message ContactList {
- repeated Contact contact = 1;
- }
- -----------------------------------------------------------------------
- iterator_range.h
- -----------------------------------------------------------------------
- #pragma once
- #include <algorithm>
- template <typename It>
- class IteratorRange {
- public:
- IteratorRange(It first_, It last_) : first_(first_)
- , last_(last_) {}
- It begin() const {return first_;}
- It end() const {return last_;}
- size_t size() const {return last_ - first_;}
- private:
- It first_, last_;
- };
- template <typename Container>
- auto Head(Container& c, int top) {
- return IteratorRange(std::begin(c), std::begin(c) + std::min<size_t>(std::max(top, 0), c.size()));
- }
- -----------------------------------------------------------------------
- phone_book.h
- -----------------------------------------------------------------------
- #pragma once
- #include "iterator_range.h"
- #include <optional>
- #include <sstream>
- #pragma once
- #include "iterator_range.h"
- #include <string>
- #include <string_view>
- #include <vector>
- #include <contact.pb.h>
- struct Date {int year, month, day;};
- struct Contact {
- std::string name;
- std::optional<Date> birthday;
- std::vector<std::string> phones;
- };
- class PhoneBook {
- public:
- explicit PhoneBook(std::vector<Contact> contacts);
- using Iterator = std::vector<Contact>::iterator;;
- using ContactRange = IteratorRange<Iterator>;
- ContactRange FindByNamePrefix(std::string_view name_prefix) const;
- void SaveTo(std::ostream& output) const;
- private:
- mutable std::vector<Contact> contacts_;
- };
- PhoneBook DeserializePhoneBook(std::istream& input);
- -----------------------------------------------------------------------
- phone_book.cpp
- -----------------------------------------------------------------------
- #include "phone_book.h"
- using namespace std;
- PhoneBook::PhoneBook(std::vector<Contact> contacts) : contacts_(contacts) {};
- PhoneBook::ContactRange PhoneBook::FindByNamePrefix(std::string_view name_prefix) const {
- std::sort(contacts_.begin(),
- contacts_.end(), [](const Contact& lhs, const Contact& rhs) {
- return lhs.name < rhs.name;
- });
- if (name_prefix.size() == 0) {
- return {contacts_.begin(), contacts_.end()};
- } else {
- Iterator start = std::lower_bound(contacts_.begin(),
- contacts_.end(),
- name_prefix, [](const Contact& contact, std::string_view prefix) {
- return prefix > contact.name;
- });
- Iterator end = std::upper_bound(start,
- contacts_.end(),
- name_prefix, [](std::string_view prefix, const Contact& contact) {
- int helper = contact.name.compare(0, prefix.size(), prefix);
- if (helper == 0) {
- return false;
- } else {
- return prefix < contact.name;
- }
- });
- return {start, end};
- }
- };
- void PhoneBook::SaveTo(std::ostream& output) const {
- phone_book_serialize::ContactList contact_list;
- for (const Contact contact : contacts_) {
- phone_book_serialize::Contact contact_from_phone_book;
- contact_from_phone_book.set_name(contact.name);
- if (contact.birthday.has_value()) {
- contact_from_phone_book.mutable_birthday()->set_day(contact.birthday->day);
- contact_from_phone_book.mutable_birthday()->set_month(contact.birthday->month);
- contact_from_phone_book.mutable_birthday()->set_year(contact.birthday->year);
- } else {
- for (const std::string& phone_number : contact.phones) {
- contact_from_phone_book.add_phone_number(phone_number);
- }
- contact_list.mutable_contact()->Add(std::move(contact_from_phone_book));
- }
- }
- contact_list.SerializeToOstream(&output);
- }
- PhoneBook DeserializePhoneBook(std::istream& input) {
- phone_book_serialize::ContactList contact_list;
- if (contact_list.ParseFromIstream(&input)) {
- std::vector<Contact> contact_list_vect(contact_list.contact_size());
- for (size_t i = 0; i < contact_list.contact_size(); ++i) {
- contact_list_vect[i].name = contact_list.contact(i).name();
- if (contact_list.contact(i).has_birthday()) {
- Date birth_date = {contact_list.contact(i).birthday().year(),
- contact_list.contact(i).birthday().month(),
- contact_list.contact(i).birthday().day()};
- contact_list_vect[i].birthday.emplace(birth_date);
- } else {
- for (size_t j = 0; j < contact_list.contact(i).phone_number_size(); ++j) {
- contact_list_vect[i].phones.push_back(contact_list.contact(i).phone_number(j));
- }
- }
- }
- return PhoneBook(contact_list_vect);
- }
- return PhoneBook({});
- }
- -----------------------------------------------------------------------
- main.cpp
- -----------------------------------------------------------------------
- #include "phone_book.h"
- #include <cassert>
- #include <sstream>
- #include <string_view>
- #include <contact.pb.h>
- using namespace std;
- void TestSerialization() {
- const PhoneBook ab({
- {"Ivan Ivanov"s, Date{1980, 1, 13}, {"+79850685521"s}},
- {"Margarita Petrova"s, Date{1989, 4, 23}, {"+79998887766"s, "+71112223344"s}},
- {"Just Birthday"s, Date{1989, 4, 23}, {}},
- {"No Birthday"s, std::nullopt, {"+7-4862-77-25-64"s}},
- });
- ostringstream output(std::ios::binary);
- ab.SaveTo(output);
- istringstream input(output.str(), std::ios::binary);
- phone_book_serialize::ContactList list;
- assert(list.ParseFromIstream(&input));
- assert(list.contact_size() == 4);
- unordered_map<string, const phone_book_serialize::Contact*> persons;
- for (const auto& p : list.contact()) {
- persons[p.name()] = &p;
- }
- {
- auto it = persons.find("Ivan Ivanov"s);
- assert(it != persons.end());
- const auto& p = *it->second;
- assert(p.has_birthday());
- assert(p.birthday().year() == 1980);
- }
- {
- auto it = persons.find("Margarita Petrova"s);
- assert(it != persons.end());
- const auto& p = *it->second;
- assert(p.has_birthday());
- assert(p.birthday().year() == 1989);
- assert(p.phone_number_size() == 2);
- assert(p.phone_number(1) == "+71112223344"sv);
- }
- {
- auto it = persons.find("Just Birthday"s);
- assert(it != persons.end());
- const auto& p = *it->second;
- assert(p.has_birthday());
- assert(p.birthday().day() == 23);
- assert(p.phone_number_size() == 0);
- }
- {
- auto it = persons.find("No Birthday"s);
- assert(it != persons.end());
- const auto& p = *it->second;
- assert(!p.has_birthday());
- assert(p.phone_number_size() == 1);
- }
- }
- void TestDeserialization() {
- phone_book_serialize::ContactList list;
- phone_book_serialize::Contact p;
- p.set_name("Vanya"s);
- p.add_phone_number("+7-953-181-46-12"s);
- *list.add_contact() = p;
- p.Clear();
- p.set_name("Veronika"s);
- p.mutable_birthday()->set_year(2000);
- p.mutable_birthday()->set_month(3);
- p.mutable_birthday()->set_day(31);
- p.add_phone_number("325-87-16"s);
- *list.add_contact() = p;
- p.Clear();
- p.set_name("Vitya"s);
- *list.add_contact() = p;
- ostringstream output(std::ios::binary);
- list.SerializeToOstream(&output);
- istringstream input(output.str(), std::ios::binary);
- const PhoneBook book = DeserializePhoneBook(input);
- auto range = book.FindByNamePrefix(""sv);
- vector<Contact> contacts(range.begin(), range.end());
- assert(contacts.size() == 3);
- assert(contacts[0].name == "Vanya"sv);
- assert(contacts[0].phones == (vector<string>{"+7-953-181-46-12"s}));
- assert(!contacts[0].birthday);
- assert(contacts[1].name == "Veronika"sv);
- assert(contacts[1].birthday);
- assert(contacts[1].birthday->year == 2000);
- assert(contacts[1].birthday->month == 3);
- assert(contacts[1].birthday->day == 31);
- assert(contacts[1].phones == (vector<string>{"325-87-16"s}));
- assert(contacts[2].name == "Vitya"sv);
- assert(!contacts[2].birthday);
- assert(contacts[2].phones.empty());
- }
- void TestFindNameByPrefix() {
- PhoneBook book({
- {"Vasiliy Petrov"s, std::nullopt, {}},
- {"Ivan Ivanov"s, std::nullopt, {}},
- {"Vasiliy Ivanov"s, std::nullopt, {}},
- {"Vasilisa Kuznetsova"s, std::nullopt, {}},
- {"Ivan Petrov"s, std::nullopt, {}},
- {"Vassisualiy Lokhankin"s, std::nullopt, {}},
- {"Ivan Vasiliev"s, std::nullopt, {}},
- {""s, std::nullopt, {}},
- });
- auto get_names = [](PhoneBook::ContactRange range) {
- vector<string> result;
- for (const auto& record : range) {
- result.push_back(record.name);
- }
- return result;
- };
- assert(get_names(book.FindByNamePrefix("Ivan"sv)) == (vector<string>{"Ivan Ivanov"s, "Ivan Petrov"s, "Ivan Vasiliev"s}));
- assert(get_names(book.FindByNamePrefix("I"sv)) == (vector<string>{"Ivan Ivanov"s, "Ivan Petrov"s, "Ivan Vasiliev"s}));
- assert(get_names(book.FindByNamePrefix("Iv"sv)) == (vector<string>{"Ivan Ivanov"s, "Ivan Petrov"s, "Ivan Vasiliev"s}));
- assert(get_names(book.FindByNamePrefix("Ivan Ivan"sv)) == (vector<string>{"Ivan Ivanov"s}));
- assert(get_names(book.FindByNamePrefix("Vas"sv))
- == (vector<string>{"Vasilisa Kuznetsova"s, "Vasiliy Ivanov"s, "Vasiliy Petrov"s, "Vassisualiy Lokhankin"s}));
- assert(get_names(book.FindByNamePrefix("Vasili"sv))
- == (vector<string>{"Vasilisa Kuznetsova"s, "Vasiliy Ivanov"s, "Vasiliy Petrov"s}));
- assert(get_names(book.FindByNamePrefix("Vasiliy"sv)) == (vector<string>{"Vasiliy Ivanov"s, "Vasiliy Petrov"s}));
- assert(get_names(book.FindByNamePrefix("Vasilis"sv)) == (vector<string>{"Vasilisa Kuznetsova"s}));
- assert(get_names(book.FindByNamePrefix(""sv))
- == (vector<string>{""s, "Ivan Ivanov"s, "Ivan Petrov"s, "Ivan Vasiliev"s, "Vasilisa Kuznetsova"s,
- "Vasiliy Ivanov"s, "Vasiliy Petrov"s, "Vassisualiy Lokhankin"s}));
- }
- void TestFindNameByPrefix2() {
- PhoneBook book({
- {"a"s, std::nullopt, {}},
- {"aaaa"s, std::nullopt, {}},
- {"aabc"s, std::nullopt, {}},
- {"aabccc"s, std::nullopt, {}},
- {"aabcbc"s, std::nullopt, {}},
- {"aeca"s, std::nullopt, {}},
- {"aeca"s, std::nullopt, {}},
- {"aefg"s, std::nullopt, {}},
- {"aq"s, std::nullopt, {}},
- });
- auto get_names = [](PhoneBook::ContactRange range) {
- vector<string> result;
- for (const auto& record : range) {
- result.push_back(record.name);
- }
- return result;
- };
- assert(book.FindByNamePrefix("a"sv).size() == 9u);
- assert(get_names(book.FindByNamePrefix("aa"sv)) == (vector<string>{"aaaa"s, "aabc"s, "aabcbc"s, "aabccc"s}));
- assert(book.FindByNamePrefix("ab"sv).size() == 0u);
- assert(book.FindByNamePrefix("b"sv).size() == 0u);
- assert(book.FindByNamePrefix("aaaaa"sv).size() == 0u);
- assert(book.FindByNamePrefix("aeb"sv).size() == 0u);
- assert(book.FindByNamePrefix("aed"sv).size() == 0u);
- assert(book.FindByNamePrefix("aeg"sv).size() == 0u);
- assert(get_names(book.FindByNamePrefix("aaa"sv)) == (vector<string>{"aaaa"s}));
- assert(get_names(book.FindByNamePrefix("ae"sv)) == (vector<string>{"aeca"s, "aeca"s, "aefg"s}));
- }
- int main() {
- TestFindNameByPrefix();
- TestFindNameByPrefix2();
- TestSerialization();
- TestDeserialization();
- }
Advertisement
Add Comment
Please, Sign In to add comment