From 171844dd905e3627c5725201cb269929c791b538 Mon Sep 17 00:00:00 2001 From: "Callum Chan ( Taota )" <64086092+callme-taota@users.noreply.github.com> Date: Sun, 3 Dec 2023 20:44:43 +0800 Subject: [PATCH] feat: Add string command bitop (#47) * feat:add string command bitop * feat:add string command bitop * feat : add string cmd bitop * feat: add string cmd bitop * feat: add string cmd bitop * feat: add stream cmd bitop bitop ops * feat : Add string command bitop * feat : Add string command bitop * feat : Add string command bitop * feat : Add string command bitop * feat : Add string command bitop * feat: add string command bitop * mearge branch * mearge branch * merge branch * merge brance * merge branch * merge branch * feat: string cmd bitop --- src/base_cmd.h | 1 + src/cmd_kv.cc | 113 ++++++++++++++++++++++++++++++++++++++- src/cmd_kv.h | 17 ++++++ src/cmd_table_manager.cc | 3 ++ src/command.cc | 2 +- 5 files changed, 134 insertions(+), 2 deletions(-) diff --git a/src/base_cmd.h b/src/base_cmd.h index f36f9079b..80c36c9e4 100644 --- a/src/base_cmd.h +++ b/src/base_cmd.h @@ -24,6 +24,7 @@ namespace pikiwidb { // string cmd const std::string kCmdNameSet = "set"; const std::string kCmdNameGet = "get"; +const std::string kCmdNameBitOp = "bitop"; const std::string kCmdNameIncrby = "incrby"; const std::string kCmdNameStrlen = "strlen"; const std::string kCmdNameSetex = "setex"; diff --git a/src/cmd_kv.cc b/src/cmd_kv.cc index da9249780..f04c378fc 100644 --- a/src/cmd_kv.cc +++ b/src/cmd_kv.cc @@ -6,7 +6,7 @@ */ #include "cmd_kv.h" -#include "pstd_string.h" +#include "pstd/pstd_string.h" #include "pstd_util.h" #include "store.h" @@ -216,6 +216,117 @@ void BitCountCmd::DoCmd(PClient* client) { client->AppendInteger(static_cast(count)); } +BitOpCmd::BitOpCmd(const std::string& name, int16_t arity) + : BaseCmd(name, arity, CmdFlagsWrite, AclCategoryWrite | AclCategoryString) {} + +bool BitOpCmd::DoInitial(PClient* client) { + if (!(pstd::StringEqualCaseInsensitive(client->argv_[1], "and") || + pstd::StringEqualCaseInsensitive(client->argv_[1], "or") || + pstd::StringEqualCaseInsensitive(client->argv_[1], "not") || + pstd::StringEqualCaseInsensitive(client->argv_[1], "xor"))) { + client->SetRes(CmdRes::kSyntaxErr, "operation error"); + return false; + } + return true; +} + +static std::string StringBitOp(const std::vector& keys, BitOpCmd::BitOp op) { + PString res; + + switch (op) { + case BitOpCmd::kBitOpAnd: + case BitOpCmd::kBitOpOr: + case BitOpCmd::kBitOpXor: + for (auto k : keys) { + PObject* val = nullptr; + if (PSTORE.GetValueByType(k, val, PType_string) != PError_ok) { + continue; + } + + auto str = GetDecodedString(val); + if (res.empty()) { + res = *str; + continue; + } + + if (str->size() > res.size()) { + res.resize(str->size()); + } + + for (size_t i = 0; i < str->size(); ++i) { + if (op == BitOpCmd::kBitOpAnd) { + res[i] &= (*str)[i]; + } else if (op == BitOpCmd::kBitOpOr) { + res[i] |= (*str)[i]; + } else if (op == BitOpCmd::kBitOpXor) { + res[i] ^= (*str)[i]; + } + } + } + break; + + case BitOpCmd::kBitOpNot: { + assert(keys.size() == 1); + PObject* val = nullptr; + if (PSTORE.GetValueByType(keys[0], val, PType_string) != PError_ok) { + break; + } + + auto str = GetDecodedString(val); + res.resize(str->size()); + + for (size_t i = 0; i < str->size(); ++i) { + res[i] = ~(*str)[i]; + } + + break; + } + + default: + break; + } + + return res; +} + +void BitOpCmd::DoCmd(PClient* client) { + std::vector keys; + for (size_t i = 3; i < client->argv_.size(); ++i) { + keys.push_back(client->argv_[i]); + } + + PError err = PError_param; + PString res; + + if (client->Key().size() == 2) { + if (pstd::StringEqualCaseInsensitive(client->argv_[1], "or")) { + err = PError_ok; + res = StringBitOp(keys, kBitOpOr); + } + } else if (client->Key().size() == 3) { + if (pstd::StringEqualCaseInsensitive(client->argv_[1], "xor")) { + err = PError_ok; + res = StringBitOp(keys, kBitOpXor); + } else if (pstd::StringEqualCaseInsensitive(client->argv_[1], "and")) { + err = PError_ok; + res = StringBitOp(keys, kBitOpAnd); + } else if (pstd::StringEqualCaseInsensitive(client->argv_[1], "not")) { + if (client->argv_.size() == 4) { + err = PError_ok; + res = StringBitOp(keys, kBitOpNot); + } + } + } + + if (err != PError_ok) { + client->SetRes(CmdRes::kSyntaxErr); + } else { + PSTORE.SetValue(client->argv_[2], PObject::CreateString(res)); + client->SetRes(CmdRes::kOk, std::to_string(static_cast(res.size()))); + } + client->SetRes(CmdRes::kOk, std::to_string(static_cast(res.size()))); +} + StrlenCmd::StrlenCmd(const std::string& name, int16_t arity) : BaseCmd(name, arity, CmdFlagsReadonly, AclCategoryRead | AclCategoryString) {} diff --git a/src/cmd_kv.h b/src/cmd_kv.h index 94114af42..b28ebbcff 100644 --- a/src/cmd_kv.h +++ b/src/cmd_kv.h @@ -33,6 +33,23 @@ class SetCmd : public BaseCmd { void DoCmd(PClient *client) override; }; +class BitOpCmd : public BaseCmd { + public: + enum BitOp { + kBitOpAnd, + kBitOpOr, + kBitOpNot, + kBitOpXor, + }; + BitOpCmd(const std::string &name, int16_t arity); + + protected: + bool DoInitial(PClient *client) override; + + private: + void DoCmd(PClient *client) override; +}; + class StrlenCmd : public BaseCmd { public: StrlenCmd(const std::string &name, int16_t arity); diff --git a/src/cmd_table_manager.cc b/src/cmd_table_manager.cc index 1b37ca780..1bc0dd8fa 100644 --- a/src/cmd_table_manager.cc +++ b/src/cmd_table_manager.cc @@ -32,6 +32,9 @@ void CmdTableManager::InitCmdTable() { cmds_->insert(std::make_pair(kCmdNameGet, std::move(getPtr))); std::unique_ptr setPtr = std::make_unique(kCmdNameSet, -3); cmds_->insert(std::make_pair(kCmdNameSet, std::move(setPtr))); + + std::unique_ptr bitOpPtr = std::make_unique(kCmdNameBitOp, -4); + cmds_->insert(std::make_pair(kCmdNameBitOp, std::move(bitOpPtr))); std::unique_ptr appendPtr = std::make_unique(kCmdNameAppend, 3); cmds_->insert(std::make_pair(kCmdNameAppend, std::move(appendPtr))); std::unique_ptr getsetPtr = std::make_unique(kCmdNameGetset, 3); diff --git a/src/command.cc b/src/command.cc index ad3d5100d..60d0afa49 100644 --- a/src/command.cc +++ b/src/command.cc @@ -62,7 +62,7 @@ const PCommandInfo PCommandTable::s_info[] = { {"mget", PAttr_read, -2, &mget}, {"append", PAttr_write, 3, &append}, {"bitcount", PAttr_read, -2, &bitcount}, - {"bitop", PAttr_write, -4, &bitop}, + // {"bitop", PAttr_write, -4, &bitop}, {"getbit", PAttr_read, 3, &getbit}, {"setbit", PAttr_write, 4, &setbit}, {"incr", PAttr_write, 2, &incr},