Kvstore
#include <string>
#include <unordered_map>
#include <iostream>
#include <sstream>
using namespace std;
// Class for Parsed operation from STDIN.
class Operation {
public:
string op;
string k;
string version;
Operation(string operation, string key) : k(key), op(operation), version("") {}
Operation(string operation, string key, string ver) : k(key), op(operation), version(ver) {}
};
// Class for VersionedValue entity.
class Value {
public:
int val;
int version;
Value(int v, int ver): val(v), version(ver) {}
};
// Class for Key Value Store.
class KVStore {
public:
int put(string k, int v) {
m[k] = v;
// store in version map
int ver = version++;
if (!versioned_m.count(k)) {
versioned_m[k] = {Value(v, ver)};
} else {
versioned_m[k].push_back(Value(v, ver));
}
// Print line to STDOUT for put().
cout << PUT << "(#" << to_string(ver) << ") " << k << " = " << to_string(v) << endl;
return ver;
}
// Get latest value for key k.
// Return <NULL> if not found.
string get(string k) {
string res = "";
if (!m.count(k)) {
res = NULL_STR;
} else {
res = to_string(m[k]);
}
// Print line to STDOUT for get().
cout << GET << " " << k << " = " << res << endl;
return res;
}
// Get versioned value for key k.
// Return <NULL> if not found.
string get(string k, int version) {
string res = "";
if (!versioned_m.count(k)) {
res = NULL_STR;
} else {
int idx = search(versioned_m[k], version);
if (idx == -1) {
res = NULL_STR;
} else {
Value v = versioned_m[k][idx];
res = to_string(v.val);
}
}
// Print line to STDOUT for get() with version.
cout << GET << " " << k << "(#" << to_string(version) << ") = " << res << endl;
return res;
}
// Search value in the value list from versioned_m using binary search.
// Input: value list, version number
// Output: idx of the found value in the list.
// Time complexity: O(logn) for n number of values in the list.
int search(vector<Value> vals, int version) {
int n = vals.size();
int l = 0, r = n-1;
int res = -1;
while (l <= r) {
int m = l + (r-l) / 2;
if (vals[m].version == version) {
return m;
} else if (vals[m].version < version) {
res = m;
l = m+1;
} else {
r = m-1;
}
}
return res;
}
private:
// Hash table keeping track of regular kv entries.
unordered_map<string, int> m;
// Hash table keeping track of versioned kv entries.
unordered_map<string, vector<Value>> versioned_m;
// Monotonically increasing version number.
int version = 1;
// Constants
const string GET = "GET";
const string PUT = "PUT";
const string NULL_STR = "<NULL>";
};
vector<Operation> parseStdin() {
string line = "";
vector<Operation> res;
while (getline(cin, line)) {
string op = "";
string k = "";
string ver = "";
istringstream iss(line);
iss >> op >> k >> ver;
// cout << "operator: " << op << " key: " << k << " v:" << ver << endl;
Operation operation = Operation(op, k, ver);
res.push_back(operation);
}
return res;
}
void execute(vector<Operation>& operations) {
int n = operations.size();
KVStore kv = KVStore();
for (int i = 0; i < n; i++) {
Operation operation = operations[i];
string op = operation.op;
string k = operation.k;
string ver = operation.version;
if (op == "PUT") {
kv.put(k, stoi(ver));
} else if (op == "GET") {
// regular get
if (ver.empty()) {
kv.get(k);
} else {
kv.get(k, stoi(ver));
}
}
}
}
void testOperations() {
vector<Operation> ops;
ops.push_back(Operation("PUT", "key1", "5"));
ops.push_back(Operation("PUT", "key2", "6"));
ops.push_back(Operation("GET", "key1", ""));
ops.push_back(Operation("GET", "key1", "1"));
execute(ops);
}
void testFinal() {
KVStore kv = KVStore();
// PUT key1 5
kv.put("key1", 5);
// PUT key2 6
kv.put("key2", 6);
// GET key1
kv.get("key1");
// GET key1 1
kv.get("key1", 1);
// GET key2 2
kv.get("key2", 2); // 6
// PUT key1 7
kv.put("key1", 7);
// GET key1 1
kv.get("key1", 1);
// GET key1 2
kv.get("key1", 2);
// GET key1 3
kv.get("key1", 3);
// GET key4
kv.get("key4");
// GET key1 4
kv.get("key1", 4);
// GET key2 1
kv.get("key2", 1);
return;
}
void testVersionedMap() {
KVStore kv = KVStore();
kv.put("key1", 5); // 1, 5
kv.put("key2", 6); // 2, 6
kv.get("key2", 2); // 6
kv.get("key2", 1); // NULL
return;
}
void testMap() {
KVStore kv = KVStore();
kv.put("key1", 5);
cout << kv.get("key1") << endl; // 5
cout << kv.get("key2") << endl; // NULL
kv.put("key1", 7);
cout << kv.get("key1") << endl; // 7
return;
}
// key2: 6 version: 2
void testParseAndExecute() {
vector<Operation> operations = parseStdin();
execute(operations);
}
int main() {
// testVersionedMap();
// testMap();
// testFinal();
// testOperations();
testParseAndExecute();
return 0;
}```
Last updated