diff --git a/src/base_cmd.h b/src/base_cmd.h index 65c5352a9..39687765e 100644 --- a/src/base_cmd.h +++ b/src/base_cmd.h @@ -34,6 +34,7 @@ const std::string kCmdNameStrlen = "strlen"; const std::string kCmdNameSetex = "setex"; const std::string kCmdNamePsetex = "psetex"; const std::string kCmdNameSetnx = "setnx"; +const std::string kCmdNameGetBit = "getbit"; // multi const std::string kCmdNameMulti = "multi"; diff --git a/src/cmd_kv.cc b/src/cmd_kv.cc index 724e55525..ed9e67b84 100644 --- a/src/cmd_kv.cc +++ b/src/cmd_kv.cc @@ -456,4 +456,47 @@ void SetnxCmd::DoCmd(PClient* client) { } } +GetBitCmd::GetBitCmd(const std::string& name, int16_t arity) + : BaseCmd(name, arity, CmdFlagsWrite, AclCategoryWrite | AclCategoryString) {} + +bool GetBitCmd::DoInitial(PClient* client) { + client->SetKey(client->argv_[1]); + return true; +} + +void GetBitCmd::DoCmd(PClient* client) { + PObject* value = nullptr; + PError err = PSTORE.GetValueByType(client->Key(), value, PType_string); + if (err != PError_ok) { + client->SetRes(CmdRes::kErrOther); + return; + } + + long offset = 0; + if (!Strtol(client->argv_[2].c_str(), client->argv_[2].size(), &offset)) { + client->SetRes(CmdRes::kInvalidInt); + return; + } + + auto str = GetDecodedString(value); + const uint8_t* buf = (const uint8_t*)str->c_str(); + size_t size = 8 * str->size(); + + if (offset < 0 || offset >= static_cast(size)) { + client->AppendInteger(0); + return; + } + + size_t bytesOffset = offset / 8; + size_t bitsOffset = offset % 8; + uint8_t byte = buf[bytesOffset]; + if (byte & (0x1 << bitsOffset)) { + client->AppendInteger(1); + } else { + client->AppendInteger(0); + } + + return; +} + } // namespace pikiwidb \ No newline at end of file diff --git a/src/cmd_kv.h b/src/cmd_kv.h index b28ebbcff..4c4244b32 100644 --- a/src/cmd_kv.h +++ b/src/cmd_kv.h @@ -160,4 +160,15 @@ class IncrbyCmd : public BaseCmd { void DoCmd(PClient *client) override; }; +class GetBitCmd : public BaseCmd { + public: + GetBitCmd(const std::string &name, int16_t arity); + + protected: + bool DoInitial(PClient *client) override; + + private: + void DoCmd(PClient *client) override; +}; + } // namespace pikiwidb diff --git a/src/cmd_table_manager.cc b/src/cmd_table_manager.cc index 32277a9b2..85728a08b 100644 --- a/src/cmd_table_manager.cc +++ b/src/cmd_table_manager.cc @@ -62,6 +62,8 @@ void CmdTableManager::InitCmdTable() { cmds_->insert(std::make_pair(kCmdNamePsetex, std::move(psetexPtr))); std::unique_ptr setnxPtr = std::make_unique(kCmdNameSetnx, 3); cmds_->insert(std::make_pair(kCmdNameSetnx, std::move(setnxPtr))); + std::unique_ptr getbitPtr = std::make_unique(kCmdNameGetBit, 3); + cmds_->insert(std::make_pair(kCmdNameGetBit, std::move(getbitPtr))); } std::pair CmdTableManager::GetCommand(const std::string& cmdName, PClient* client) {