Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #include "test_runner.h"
- #include <iostream>
- #include <map>
- #include <string>
- #include <unordered_map>
- #include <unordered_set>
- using namespace std;
- struct Record {
- string id;
- string title;
- string user;
- int timestamp;
- int karma;
- };
- struct RecordHasher {
- size_t operator()(const Record &record) const {
- const size_t c = 514'229;
- const hash<int> int_hasher;
- const hash<string> string_hasher;
- // return int_hasher(record.karma) + c * int_hasher(record.timestamp) + c * c * string_hasher(record.user) +
- // c * c * c * string_hasher(record.title) + c * c * c * c * string_hasher(record.id);
- return c * c * c * c * string_hasher(record.id);
- }
- };
- bool operator==(const Record &lhs, const Record &rhs) {
- return lhs.id == rhs.id;
- }
- // Реализуйте этот класс
- class Database {
- using BulkWarehouse = unordered_set<Record, RecordHasher>;
- using RecordPointer = BulkWarehouse::iterator;
- using IdWarehouse = unordered_map<string, RecordPointer>;
- using UserIndex = multimap<string, RecordPointer>;
- using IntegerIndex = multimap<int, RecordPointer>;
- public:
- bool Put(const Record &record) {
- auto result = bulkWarehouse.insert(record);
- bool success = result.second;
- if (success) {
- idWarehouse[record.id] = result.first;
- auto user_result = userIndex.insert({record.user, result.first});
- auto karma_result = karmaIndex.insert({record.karma, result.first});
- auto timestamp_result = timestampIndex.insert({record.timestamp, result.first});
- invertedIndex.insert({record.id, make_tuple(user_result, karma_result, timestamp_result)});
- }
- return success;
- };
- const Record *GetById(const string &id) const {
- if (idWarehouse.count(id) == 0) {
- return nullptr;
- }
- return &(*idWarehouse.at(id));
- };
- bool Erase(const string &id) {
- if (idWarehouse.count(id) == 0) {
- return false;
- }
- auto p = idWarehouse[id];
- bulkWarehouse.erase(p);
- idWarehouse.erase(id);
- auto ip = invertedIndex[id];
- userIndex.erase(get<0>(ip));
- karmaIndex.erase(get<1>(ip));
- timestampIndex.erase(get<2>(ip));
- invertedIndex.erase(id);
- return true;
- };
- template<typename Callback>
- void RangeByTimestamp(int low, int high, Callback callback) const {
- auto lower = timestampIndex.lower_bound(low);
- auto upper = timestampIndex.upper_bound(high);
- for (auto it = lower; it != upper; it++) {
- if (!callback(*it->second)) {
- break;
- }
- }
- };
- template<typename Callback>
- void RangeByKarma(int low, int high, Callback callback) const {
- auto lower = karmaIndex.lower_bound(low);
- auto upper = karmaIndex.upper_bound(high);
- for (auto it = lower; it != upper; it++) {
- if (!callback(*it->second)) {
- break;
- }
- }
- };
- template<typename Callback>
- void AllByUser(const string &user, Callback callback) const {
- auto range = userIndex.equal_range(user);
- for (auto it = range.first; it != range.second; it++) {
- if (!callback(*it->second)) {
- break;
- }
- }
- };
- private:
- BulkWarehouse bulkWarehouse;
- IdWarehouse idWarehouse;
- UserIndex userIndex;
- IntegerIndex karmaIndex;
- IntegerIndex timestampIndex;
- unordered_map<string, tuple<UserIndex::iterator, IntegerIndex::iterator, IntegerIndex::iterator>> invertedIndex;
- };
- void TestBoundariesSinglePoint() {
- Database db;
- db.Put({"id1", "Hello there", "master", 1536107260, 1});
- db.Put({"id23", "Hello there", "master", 1536107260, 1});
- db.Put({"id2", "O>>-<", "general2", 1536107260, 2});
- db.Put({"id3", "O>>-<", "general2", 1536107260, 3});
- db.Put({"id4", "O>>-<", "general2", 1536107260, 4});
- int counter_whole = 0;
- db.RangeByKarma(0, 1, [&counter_whole](const Record &) {
- ++counter_whole;
- return true;
- });
- ASSERT_EQUAL(2, counter_whole);
- }
- void TestRangeBoundaries() {
- Database db;
- db.Put({"id1", "Hello there", "master", 1536107260, 1});
- db.Put({"id2", "O>>-<", "general2", 1536107260, 2});
- db.Put({"id3", "O>>-<", "general2", 1536107260, 3});
- db.Put({"id4", "O>>-<", "general2", 1536107260, 4});
- // testing whole range
- int counter_whole = 0;
- db.RangeByKarma(1, 4, [&counter_whole](const Record &) {
- ++counter_whole;
- return true;
- });
- ASSERT_EQUAL(4, counter_whole);
- int counter_nolast = 0;
- db.RangeByKarma(1, 3, [&counter_nolast](const Record &) {
- ++counter_nolast;
- return true;
- });
- ASSERT_EQUAL(3, counter_nolast);
- int counter_nofirst = 0;
- db.RangeByKarma(2, 4, [&counter_nofirst](const Record &) {
- ++counter_nofirst;
- return true;
- });
- ASSERT_EQUAL(3, counter_nofirst);
- int ct_no = 0;
- db.RangeByKarma(100, 101, [&ct_no](const Record &) {
- ++ct_no;
- return true;
- });
- ASSERT_EQUAL(0, ct_no);
- }
- void TestRangeBoundariesInclusive() {
- const int good_karma = 1000;
- const int bad_karma = -10;
- Database db;
- db.Put({"id1", "Hello there", "master", 1536107260, good_karma});
- db.Put({"id2", "O>>-<", "general2", 1536107260, bad_karma});
- int count = 0;
- db.RangeByKarma(bad_karma, good_karma, [&count](const Record &) {
- ++count;
- return true;
- });
- ASSERT_EQUAL(2, count);
- }
- void TestRangeBoundariesErase() {
- const int good_karma = 1000;
- const int bad_karma = -10;
- Database db;
- db.Put({"id1", "Hello there", "master", 1536107260, good_karma});
- db.Put({"id2", "O>>-<", "general2", 1536107260, bad_karma});
- db.Erase("id2");
- int count = 0;
- db.RangeByKarma(bad_karma, good_karma, [&count](const Record &) {
- ++count;
- return true;
- });
- ASSERT_EQUAL(1, count);
- }
- ostream &operator<<(ostream &os, const Record &r) {
- os << r.id << " " << r.title << " " << r.user << " " << r.timestamp << " " << r.karma;
- return os;
- }
- void TestPutUser() {
- Database db;
- bool done = db.Put({"id1", "Hello there", "master", 1536107260, 1});
- ASSERT_EQUAL(done, true)
- bool notdone = db.Put({"id1", "Hello111 there", "master", 1536107260, 1});
- ASSERT_EQUAL(notdone, false)
- }
- void TestPutRetrieveUser() {
- Database db;
- Record testRecord{"id1", "Hello there", "master", 1536107260, 1};
- bool done = db.Put(testRecord);
- const Record *r = db.GetById(testRecord.id);
- ASSERT_EQUAL(*r, testRecord)
- }
- void TestPutRetrieveUserNonExist() {
- Database db;
- Record testRecord{"id1", "Hello there", "master", 1536107260, 1};
- bool done = db.Put(testRecord);
- const Record *r = db.GetById("id2");
- ASSERT(!r)
- }
- void TestEraseExist() {
- Database db;
- Record testRecord{"id1", "Hello there", "master", 1536107260, 1};
- db.Put(testRecord);
- bool done = db.Erase(testRecord.id);
- ASSERT_EQUAL(done, true)
- ASSERT(!db.GetById(testRecord.id))
- }
- void TestEraseNonExist() {
- Database db;
- Record testRecord{"id1", "Hello there", "master", 1536107260, 1};
- bool done = db.Erase("NO SUCH ID");
- ASSERT_EQUAL(done, false)
- }
- void TestSameUser() {
- Database db;
- db.Put({"id1", "Don't sell", "master", 1536107260, 1000});
- db.Put({"id2", "Rethink life", "master", 1536107260, 2000});
- int count = 0;
- db.AllByUser("master", [&count](const Record &) {
- ++count;
- return true;
- });
- ASSERT_EQUAL(2, count)
- }
- void TestSameUserWithDelete() {
- Database db;
- db.Put({"id1", "Don't sell", "master", 1536107260, 1000});
- db.Put({"id2", "Rethink life", "master", 1536107260, 2000});
- db.Erase("id2");
- int count = 0;
- db.AllByUser("master1", [&count](const Record &) {
- ++count;
- return true;
- });
- ASSERT_EQUAL(0, count)
- }
- //
- void TestReplacement() {
- const string final_body = "Feeling sad";
- Database db;
- db.Put({"id", "Have a hand", "not-master", 1536107260, 10});
- db.Erase("id");
- db.Put({"id", final_body, "not-master", 1536107260, -10});
- auto record = db.GetById("id");
- ASSERT(record != nullptr);
- ASSERT_EQUAL(final_body, record->title);
- }
- int main() {
- TestRunner tr;
- RUN_TEST(tr, TestPutUser);
- RUN_TEST(tr, TestPutRetrieveUser);
- RUN_TEST(tr, TestPutRetrieveUserNonExist);
- RUN_TEST(tr, TestEraseExist);
- RUN_TEST(tr, TestEraseNonExist);
- RUN_TEST(tr, TestRangeBoundariesInclusive);
- RUN_TEST(tr, TestRangeBoundariesErase);
- RUN_TEST(tr, TestSameUser);
- RUN_TEST(tr, TestSameUserWithDelete);
- RUN_TEST(tr, TestReplacement);
- RUN_TEST(tr, TestRangeBoundaries);
- RUN_TEST(tr, TestBoundariesSinglePoint);
- return 0;
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement