Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add bitfield api #423

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions src/sw/redis++/command.h
Original file line number Diff line number Diff line change
Expand Up @@ -319,6 +319,19 @@ inline void bitpos(Connection &connection,
end);
}

template <typename Input>
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());
}
Expand Down
12 changes: 12 additions & 0 deletions src/sw/redis++/queued_redis.h
Original file line number Diff line number Diff line change
Expand Up @@ -356,6 +356,18 @@ class QueuedRedis {
return command(cmd::bitop_range<Input>, op, destination, first, last);
}

template <typename Input>
QueuedRedis& bitfield(const StringView &key, Input first, Input last) {
range_check("BITFIELD", first, last);

return command(cmd::bitfield<Input>, key, first, last);
}

template <typename T>
QueuedRedis& bitfield(const StringView &key, std::initializer_list<T> il) {
return bitfield(key, il.begin(), il.end());
}

template <typename T>
QueuedRedis& bitop(BitOp op,
const StringView &destination,
Expand Down
44 changes: 44 additions & 0 deletions src/sw/redis++/redis.h
Original file line number Diff line number Diff line change
Expand Up @@ -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<std::string> ops = {"SET", "u1", "1", "1","SET", "u1", "3", "0","SET", "u1", "6", "1"};
/// std::vector<long long> 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 <typename Input, typename Output>
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<long long> 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 <typename T, typename Output>
void bitfield(const StringView &key, std::initializer_list<T> 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.
Expand Down
9 changes: 9 additions & 0 deletions src/sw/redis++/redis.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -235,6 +235,15 @@ long long Redis::bitop(BitOp op, const StringView &destination, Input first, Inp
return reply::parse<long long>(*reply);
}

template <typename Input, typename Output>
inline void Redis::bitfield(const StringView &key, Input first, Input last, Output output) {
range_check("BITFIELD", first, last);

auto reply = command(cmd::bitfield<Input>, key, first, last);

reply::to_array(*reply, output);
}

template <typename Input, typename Output>
void Redis::mget(Input first, Input last, Output output) {
range_check("MGET", first, last);
Expand Down
8 changes: 8 additions & 0 deletions src/sw/redis++/redis_cluster.h
Original file line number Diff line number Diff line change
Expand Up @@ -204,6 +204,14 @@ class RedisCluster {
return bitop(op, destination, il.begin(), il.end());
}

template <typename Input, typename Output>
void bitfield(const StringView &key, Input first, Input last, Output output);

template <typename T, typename Output>
void bitfield(const StringView &key, std::initializer_list<T> il, Output output) {
bitfield(key, il.begin(), il.end(), output);
}

long long bitpos(const StringView &key,
long long bit,
long long start = 0,
Expand Down
9 changes: 9 additions & 0 deletions src/sw/redis++/redis_cluster.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -192,6 +192,15 @@ long long RedisCluster::bitop(BitOp op, const StringView &destination, Input fir
return reply::parse<long long>(*reply);
}

template <typename Input, typename Output>
inline void RedisCluster::bitfield(const StringView &key, Input first, Input last, Output output) {
range_check("BITFIELD", first, last);

auto reply = command(cmd::bitfield<Input>, key, first, last);

reply::to_array(*reply, output);
}

template <typename Input, typename Output>
void RedisCluster::mget(Input first, Input last, Output output) {
range_check("MGET", first, last);
Expand Down
20 changes: 20 additions & 0 deletions test/src/sw/redis++/string_cmds_test.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,26 @@ void StringCmdTest<RedisInstance>::_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<std::string> ops = {"SET", "u1", "1", "1","SET", "u1", "3", "0","SET", "u1", "6", "1"};
std::vector<long long> 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 <typename RedisInstance>
Expand Down