From e8ae0c8caa560bdd5dcac14ff82ba27e999fa670 Mon Sep 17 00:00:00 2001 From: rubicon0501 Date: Fri, 25 Nov 2022 20:46:50 +0800 Subject: [PATCH] add bitfield api --- src/sw/redis++/command.h | 13 +++++++ src/sw/redis++/queued_redis.h | 12 +++++++ src/sw/redis++/redis.h | 44 ++++++++++++++++++++++++ src/sw/redis++/redis.hpp | 9 +++++ src/sw/redis++/redis_cluster.h | 8 +++++ src/sw/redis++/redis_cluster.hpp | 9 +++++ test/src/sw/redis++/string_cmds_test.hpp | 20 +++++++++++ 7 files changed, 115 insertions(+) diff --git a/src/sw/redis++/command.h b/src/sw/redis++/command.h index 4fc83c5e..a21a9080 100644 --- a/src/sw/redis++/command.h +++ b/src/sw/redis++/command.h @@ -319,6 +319,19 @@ inline void bitpos(Connection &connection, end); } +template +inline void bitfield(Connection &connection, + const StringView &key, + Input first, + Input last) { + assert(first != last); + + CmdArgs args; + args << "BITFIELD" << key << std::make_pair(first, last); + + connection.send(args); +} + inline void decr(Connection &connection, const StringView &key) { connection.send("DECR %b", key.data(), key.size()); } diff --git a/src/sw/redis++/queued_redis.h b/src/sw/redis++/queued_redis.h index 342a1979..bf7ed62a 100644 --- a/src/sw/redis++/queued_redis.h +++ b/src/sw/redis++/queued_redis.h @@ -356,6 +356,18 @@ class QueuedRedis { return command(cmd::bitop_range, op, destination, first, last); } + template + QueuedRedis& bitfield(const StringView &key, Input first, Input last) { + range_check("BITFIELD", first, last); + + return command(cmd::bitfield, key, first, last); + } + + template + QueuedRedis& bitfield(const StringView &key, std::initializer_list il) { + return bitfield(key, il.begin(), il.end()); + } + template QueuedRedis& bitop(BitOp op, const StringView &destination, diff --git a/src/sw/redis++/redis.h b/src/sw/redis++/redis.h index 64dc1bfa..d6475bde 100644 --- a/src/sw/redis++/redis.h +++ b/src/sw/redis++/redis.h @@ -721,6 +721,50 @@ class Redis { /// @see https://redis.io/commands/getbit long long getbit(const StringView &key, long long offset); + /// @brief Batch operations on multiple bits of a string. + /// + /// Example: + /// @code{.cpp} + /// std::vector ops = {"SET", "u1", "1", "1","SET", "u1", "3", "0","SET", "u1", "6", "1"}; + /// std::vector vals; + /// redis.bitfield("bitfieldkey", ops.begin(), ops.end(), std::back_inserter(vals)); + /// for (int i = 0; i < vals.size(); i++) { + /// std::cout << vals[i] << std::endl; + /// } + /// @endcode + /// @param key Key where the string is stored. + /// @param first Iterator to the first sub command. + /// @param last Off-the-end iterator to the given sub commands range. + /// @param output Output iterator to the destination where the result is saved. + /// @note The destination should be a container of `long long` type, + /// the value of the corresponding is only `1` or `0`. + /// @see https://redis.io/commands/bitfield + template + void bitfield(const StringView &key, Input first, Input last, Output output); + + /// @brief Batch operations on multiple bits of a string. + /// Example: + /// @code{.cpp} + /// std::vector vals; + /// redis.bitfield("bitfieldkey", + /// {"SET", "u1", "1", "1","SET", "u1", "3", "0","SET", "u1", "6", "1"}, + /// std::back_inserter(vals)); + /// for (int i = 0; i < vals.size(); i++) { + /// std::cout << vals[i] << std::endl; + /// } + /// @endcode + /// @param key Key where the string is stored. + /// @param first Iterator to the first sub command. + /// @param last Off-the-end iterator to the given sub commands range. + /// @param output Output iterator to the destination where the result is saved. + /// @note The destination should be a container of `long long` type, + /// the value of the corresponding is only `1` or `0`. + /// @see https://redis.io/commands/bitfield + template + void bitfield(const StringView &key, std::initializer_list il, Output output) { + bitfield(key, il.begin(), il.end(), output); + } + /// @brief Get the substring of the string stored at key. /// @param key Key. /// @param start Start index (inclusive) of the range. 0 means the beginning of the string. diff --git a/src/sw/redis++/redis.hpp b/src/sw/redis++/redis.hpp index e5d8db6d..80367563 100644 --- a/src/sw/redis++/redis.hpp +++ b/src/sw/redis++/redis.hpp @@ -235,6 +235,15 @@ long long Redis::bitop(BitOp op, const StringView &destination, Input first, Inp return reply::parse(*reply); } +template +inline void Redis::bitfield(const StringView &key, Input first, Input last, Output output) { + range_check("BITFIELD", first, last); + + auto reply = command(cmd::bitfield, key, first, last); + + reply::to_array(*reply, output); +} + template void Redis::mget(Input first, Input last, Output output) { range_check("MGET", first, last); diff --git a/src/sw/redis++/redis_cluster.h b/src/sw/redis++/redis_cluster.h index b8d8c5f5..ce40538a 100644 --- a/src/sw/redis++/redis_cluster.h +++ b/src/sw/redis++/redis_cluster.h @@ -204,6 +204,14 @@ class RedisCluster { return bitop(op, destination, il.begin(), il.end()); } + template + void bitfield(const StringView &key, Input first, Input last, Output output); + + template + void bitfield(const StringView &key, std::initializer_list il, Output output) { + bitfield(key, il.begin(), il.end(), output); + } + long long bitpos(const StringView &key, long long bit, long long start = 0, diff --git a/src/sw/redis++/redis_cluster.hpp b/src/sw/redis++/redis_cluster.hpp index de6c2278..48b5099c 100644 --- a/src/sw/redis++/redis_cluster.hpp +++ b/src/sw/redis++/redis_cluster.hpp @@ -192,6 +192,15 @@ long long RedisCluster::bitop(BitOp op, const StringView &destination, Input fir return reply::parse(*reply); } +template +inline void RedisCluster::bitfield(const StringView &key, Input first, Input last, Output output) { + range_check("BITFIELD", first, last); + + auto reply = command(cmd::bitfield, key, first, last); + + reply::to_array(*reply, output); +} + template void RedisCluster::mget(Input first, Input last, Output output) { range_check("MGET", first, last); diff --git a/test/src/sw/redis++/string_cmds_test.hpp b/test/src/sw/redis++/string_cmds_test.hpp index cf702e43..ad7ad205 100644 --- a/test/src/sw/redis++/string_cmds_test.hpp +++ b/test/src/sw/redis++/string_cmds_test.hpp @@ -149,6 +149,26 @@ void StringCmdTest::_test_bit() { // dest_key -> 11101111 v = _redis.get(dest_key); REDIS_ASSERT(v && *v == std::string(1, '\xEF'), "failed to test bitop"); + + + auto bitfield_key = test_key("bitfield_src"); + // bitfield_key -> 01000010 + std::vector ops = {"SET", "u1", "1", "1","SET", "u1", "3", "0","SET", "u1", "6", "1"}; + std::vector vals; + _redis.bitfield(bitfield_key, ops.begin(), ops.end(), std::back_inserter(vals)); + REDIS_ASSERT(_redis.getbit(bitfield_key, 1) == 1, "failed to test bitfield"); + REDIS_ASSERT(_redis.getbit(bitfield_key, 3) == 0, "failed to test bitfield"); + REDIS_ASSERT(_redis.getbit(bitfield_key, 6) == 1, "failed to test bitfield"); + REDIS_ASSERT(_redis.bitcount(bitfield_key) == 2, "failed to test bitfield"); + + // bitfield_key -> 10011001 + vals.clear(); + _redis.bitfield(bitfield_key, {"SET", "u1", "0", "1","SET", "u1", "1", "0","SET", "u1", "4", "1", "SET", "u1", "7", "1"}, + std::back_inserter(vals)); + REDIS_ASSERT(_redis.getbit(bitfield_key, 0) == 1, "failed to test bitfield"); + REDIS_ASSERT(_redis.getbit(bitfield_key, 4) == 1, "failed to test bitfield"); + REDIS_ASSERT(_redis.getbit(bitfield_key, 7) == 1, "failed to test bitfield"); + REDIS_ASSERT(_redis.bitcount(bitfield_key) == 4, "failed to test bitfield"); } template