From 48f6e4df05a0f38b6b7799113a48b20f5ec04105 Mon Sep 17 00:00:00 2001 From: Grant Limberg Date: Thu, 29 Jun 2023 19:51:03 +0000 Subject: [PATCH] redis-plus-plus for ubuntu 22.04 arm --- .../include/sw/redis++/cmd_formatter.h | 0 .../{ => amd64}/include/sw/redis++/command.h | 0 .../include/sw/redis++/command_args.h | 0 .../include/sw/redis++/command_options.h | 0 .../include/sw/redis++/connection.h | 0 .../include/sw/redis++/connection_pool.h | 0 .../include/sw/redis++/cxx_utils.h | 0 .../{ => amd64}/include/sw/redis++/errors.h | 0 .../{ => amd64}/include/sw/redis++/pipeline.h | 0 .../include/sw/redis++/queued_redis.h | 0 .../include/sw/redis++/queued_redis.hpp | 0 .../{ => amd64}/include/sw/redis++/redis++.h | 0 .../{ => amd64}/include/sw/redis++/redis.h | 0 .../{ => amd64}/include/sw/redis++/redis.hpp | 0 .../include/sw/redis++/redis_cluster.h | 0 .../include/sw/redis++/redis_cluster.hpp | 0 .../{ => amd64}/include/sw/redis++/reply.h | 0 .../{ => amd64}/include/sw/redis++/sentinel.h | 0 .../{ => amd64}/include/sw/redis++/shards.h | 0 .../include/sw/redis++/shards_pool.h | 0 .../include/sw/redis++/subscriber.h | 0 .../{ => amd64}/include/sw/redis++/tls.h | 0 .../include/sw/redis++/transaction.h | 0 .../{ => amd64}/include/sw/redis++/utils.h | 0 .../{ => amd64}/lib/pkgconfig/redis++.pc | 0 .../redis++/redis++-config-version.cmake | 0 .../share/cmake/redis++/redis++-config.cmake | 0 .../redis++/redis++-targets-release.cmake | 0 .../share/cmake/redis++/redis++-targets.cmake | 0 .../arm64/include/sw/redis++/cmd_formatter.h | 775 ++++ .../arm64/include/sw/redis++/command.h | 2271 +++++++++++ .../arm64/include/sw/redis++/command_args.h | 180 + .../include/sw/redis++/command_options.h | 211 + .../arm64/include/sw/redis++/connection.h | 237 ++ .../include/sw/redis++/connection_pool.h | 182 + .../arm64/include/sw/redis++/cxx_utils.h | 46 + .../arm64/include/sw/redis++/errors.h | 166 + .../arm64/include/sw/redis++/pipeline.h | 49 + .../arm64/include/sw/redis++/queued_redis.h | 2013 +++++++++ .../arm64/include/sw/redis++/queued_redis.hpp | 275 ++ .../arm64/include/sw/redis++/redis++.h | 25 + .../arm64/include/sw/redis++/redis.h | 3631 +++++++++++++++++ .../arm64/include/sw/redis++/redis.hpp | 1342 ++++++ .../arm64/include/sw/redis++/redis_cluster.h | 1439 +++++++ .../include/sw/redis++/redis_cluster.hpp | 1403 +++++++ .../arm64/include/sw/redis++/reply.h | 435 ++ .../arm64/include/sw/redis++/sentinel.h | 141 + .../arm64/include/sw/redis++/shards.h | 115 + .../arm64/include/sw/redis++/shards_pool.h | 121 + .../arm64/include/sw/redis++/subscriber.h | 231 ++ .../arm64/include/sw/redis++/tls.h | 47 + .../arm64/include/sw/redis++/transaction.h | 77 + .../arm64/include/sw/redis++/utils.h | 193 + .../arm64/lib/pkgconfig/redis++.pc | 12 + .../redis++/redis++-config-version.cmake | 48 + .../share/cmake/redis++/redis++-config.cmake | 36 + .../redis++/redis++-targets-release.cmake | 19 + .../share/cmake/redis++/redis++-targets.cmake | 94 + .../install/ubuntu22.04/lib/libredis++.a | Bin 1399538 -> 0 bytes 59 files changed, 15814 insertions(+) rename ext/redis-plus-plus-1.3.3/install/ubuntu22.04/{ => amd64}/include/sw/redis++/cmd_formatter.h (100%) rename ext/redis-plus-plus-1.3.3/install/ubuntu22.04/{ => amd64}/include/sw/redis++/command.h (100%) rename ext/redis-plus-plus-1.3.3/install/ubuntu22.04/{ => amd64}/include/sw/redis++/command_args.h (100%) rename ext/redis-plus-plus-1.3.3/install/ubuntu22.04/{ => amd64}/include/sw/redis++/command_options.h (100%) rename ext/redis-plus-plus-1.3.3/install/ubuntu22.04/{ => amd64}/include/sw/redis++/connection.h (100%) rename ext/redis-plus-plus-1.3.3/install/ubuntu22.04/{ => amd64}/include/sw/redis++/connection_pool.h (100%) rename ext/redis-plus-plus-1.3.3/install/ubuntu22.04/{ => amd64}/include/sw/redis++/cxx_utils.h (100%) rename ext/redis-plus-plus-1.3.3/install/ubuntu22.04/{ => amd64}/include/sw/redis++/errors.h (100%) rename ext/redis-plus-plus-1.3.3/install/ubuntu22.04/{ => amd64}/include/sw/redis++/pipeline.h (100%) rename ext/redis-plus-plus-1.3.3/install/ubuntu22.04/{ => amd64}/include/sw/redis++/queued_redis.h (100%) rename ext/redis-plus-plus-1.3.3/install/ubuntu22.04/{ => amd64}/include/sw/redis++/queued_redis.hpp (100%) rename ext/redis-plus-plus-1.3.3/install/ubuntu22.04/{ => amd64}/include/sw/redis++/redis++.h (100%) rename ext/redis-plus-plus-1.3.3/install/ubuntu22.04/{ => amd64}/include/sw/redis++/redis.h (100%) rename ext/redis-plus-plus-1.3.3/install/ubuntu22.04/{ => amd64}/include/sw/redis++/redis.hpp (100%) rename ext/redis-plus-plus-1.3.3/install/ubuntu22.04/{ => amd64}/include/sw/redis++/redis_cluster.h (100%) rename ext/redis-plus-plus-1.3.3/install/ubuntu22.04/{ => amd64}/include/sw/redis++/redis_cluster.hpp (100%) rename ext/redis-plus-plus-1.3.3/install/ubuntu22.04/{ => amd64}/include/sw/redis++/reply.h (100%) rename ext/redis-plus-plus-1.3.3/install/ubuntu22.04/{ => amd64}/include/sw/redis++/sentinel.h (100%) rename ext/redis-plus-plus-1.3.3/install/ubuntu22.04/{ => amd64}/include/sw/redis++/shards.h (100%) rename ext/redis-plus-plus-1.3.3/install/ubuntu22.04/{ => amd64}/include/sw/redis++/shards_pool.h (100%) rename ext/redis-plus-plus-1.3.3/install/ubuntu22.04/{ => amd64}/include/sw/redis++/subscriber.h (100%) rename ext/redis-plus-plus-1.3.3/install/ubuntu22.04/{ => amd64}/include/sw/redis++/tls.h (100%) rename ext/redis-plus-plus-1.3.3/install/ubuntu22.04/{ => amd64}/include/sw/redis++/transaction.h (100%) rename ext/redis-plus-plus-1.3.3/install/ubuntu22.04/{ => amd64}/include/sw/redis++/utils.h (100%) rename ext/redis-plus-plus-1.3.3/install/ubuntu22.04/{ => amd64}/lib/pkgconfig/redis++.pc (100%) rename ext/redis-plus-plus-1.3.3/install/ubuntu22.04/{ => amd64}/share/cmake/redis++/redis++-config-version.cmake (100%) rename ext/redis-plus-plus-1.3.3/install/ubuntu22.04/{ => amd64}/share/cmake/redis++/redis++-config.cmake (100%) rename ext/redis-plus-plus-1.3.3/install/ubuntu22.04/{ => amd64}/share/cmake/redis++/redis++-targets-release.cmake (100%) rename ext/redis-plus-plus-1.3.3/install/ubuntu22.04/{ => amd64}/share/cmake/redis++/redis++-targets.cmake (100%) create mode 100644 ext/redis-plus-plus-1.3.3/install/ubuntu22.04/arm64/include/sw/redis++/cmd_formatter.h create mode 100644 ext/redis-plus-plus-1.3.3/install/ubuntu22.04/arm64/include/sw/redis++/command.h create mode 100644 ext/redis-plus-plus-1.3.3/install/ubuntu22.04/arm64/include/sw/redis++/command_args.h create mode 100644 ext/redis-plus-plus-1.3.3/install/ubuntu22.04/arm64/include/sw/redis++/command_options.h create mode 100644 ext/redis-plus-plus-1.3.3/install/ubuntu22.04/arm64/include/sw/redis++/connection.h create mode 100644 ext/redis-plus-plus-1.3.3/install/ubuntu22.04/arm64/include/sw/redis++/connection_pool.h create mode 100644 ext/redis-plus-plus-1.3.3/install/ubuntu22.04/arm64/include/sw/redis++/cxx_utils.h create mode 100644 ext/redis-plus-plus-1.3.3/install/ubuntu22.04/arm64/include/sw/redis++/errors.h create mode 100644 ext/redis-plus-plus-1.3.3/install/ubuntu22.04/arm64/include/sw/redis++/pipeline.h create mode 100644 ext/redis-plus-plus-1.3.3/install/ubuntu22.04/arm64/include/sw/redis++/queued_redis.h create mode 100644 ext/redis-plus-plus-1.3.3/install/ubuntu22.04/arm64/include/sw/redis++/queued_redis.hpp create mode 100644 ext/redis-plus-plus-1.3.3/install/ubuntu22.04/arm64/include/sw/redis++/redis++.h create mode 100644 ext/redis-plus-plus-1.3.3/install/ubuntu22.04/arm64/include/sw/redis++/redis.h create mode 100644 ext/redis-plus-plus-1.3.3/install/ubuntu22.04/arm64/include/sw/redis++/redis.hpp create mode 100644 ext/redis-plus-plus-1.3.3/install/ubuntu22.04/arm64/include/sw/redis++/redis_cluster.h create mode 100644 ext/redis-plus-plus-1.3.3/install/ubuntu22.04/arm64/include/sw/redis++/redis_cluster.hpp create mode 100644 ext/redis-plus-plus-1.3.3/install/ubuntu22.04/arm64/include/sw/redis++/reply.h create mode 100644 ext/redis-plus-plus-1.3.3/install/ubuntu22.04/arm64/include/sw/redis++/sentinel.h create mode 100644 ext/redis-plus-plus-1.3.3/install/ubuntu22.04/arm64/include/sw/redis++/shards.h create mode 100644 ext/redis-plus-plus-1.3.3/install/ubuntu22.04/arm64/include/sw/redis++/shards_pool.h create mode 100644 ext/redis-plus-plus-1.3.3/install/ubuntu22.04/arm64/include/sw/redis++/subscriber.h create mode 100644 ext/redis-plus-plus-1.3.3/install/ubuntu22.04/arm64/include/sw/redis++/tls.h create mode 100644 ext/redis-plus-plus-1.3.3/install/ubuntu22.04/arm64/include/sw/redis++/transaction.h create mode 100644 ext/redis-plus-plus-1.3.3/install/ubuntu22.04/arm64/include/sw/redis++/utils.h create mode 100644 ext/redis-plus-plus-1.3.3/install/ubuntu22.04/arm64/lib/pkgconfig/redis++.pc create mode 100644 ext/redis-plus-plus-1.3.3/install/ubuntu22.04/arm64/share/cmake/redis++/redis++-config-version.cmake create mode 100644 ext/redis-plus-plus-1.3.3/install/ubuntu22.04/arm64/share/cmake/redis++/redis++-config.cmake create mode 100644 ext/redis-plus-plus-1.3.3/install/ubuntu22.04/arm64/share/cmake/redis++/redis++-targets-release.cmake create mode 100644 ext/redis-plus-plus-1.3.3/install/ubuntu22.04/arm64/share/cmake/redis++/redis++-targets.cmake delete mode 100644 ext/redis-plus-plus-1.3.3/install/ubuntu22.04/lib/libredis++.a diff --git a/ext/redis-plus-plus-1.3.3/install/ubuntu22.04/include/sw/redis++/cmd_formatter.h b/ext/redis-plus-plus-1.3.3/install/ubuntu22.04/amd64/include/sw/redis++/cmd_formatter.h similarity index 100% rename from ext/redis-plus-plus-1.3.3/install/ubuntu22.04/include/sw/redis++/cmd_formatter.h rename to ext/redis-plus-plus-1.3.3/install/ubuntu22.04/amd64/include/sw/redis++/cmd_formatter.h diff --git a/ext/redis-plus-plus-1.3.3/install/ubuntu22.04/include/sw/redis++/command.h b/ext/redis-plus-plus-1.3.3/install/ubuntu22.04/amd64/include/sw/redis++/command.h similarity index 100% rename from ext/redis-plus-plus-1.3.3/install/ubuntu22.04/include/sw/redis++/command.h rename to ext/redis-plus-plus-1.3.3/install/ubuntu22.04/amd64/include/sw/redis++/command.h diff --git a/ext/redis-plus-plus-1.3.3/install/ubuntu22.04/include/sw/redis++/command_args.h b/ext/redis-plus-plus-1.3.3/install/ubuntu22.04/amd64/include/sw/redis++/command_args.h similarity index 100% rename from ext/redis-plus-plus-1.3.3/install/ubuntu22.04/include/sw/redis++/command_args.h rename to ext/redis-plus-plus-1.3.3/install/ubuntu22.04/amd64/include/sw/redis++/command_args.h diff --git a/ext/redis-plus-plus-1.3.3/install/ubuntu22.04/include/sw/redis++/command_options.h b/ext/redis-plus-plus-1.3.3/install/ubuntu22.04/amd64/include/sw/redis++/command_options.h similarity index 100% rename from ext/redis-plus-plus-1.3.3/install/ubuntu22.04/include/sw/redis++/command_options.h rename to ext/redis-plus-plus-1.3.3/install/ubuntu22.04/amd64/include/sw/redis++/command_options.h diff --git a/ext/redis-plus-plus-1.3.3/install/ubuntu22.04/include/sw/redis++/connection.h b/ext/redis-plus-plus-1.3.3/install/ubuntu22.04/amd64/include/sw/redis++/connection.h similarity index 100% rename from ext/redis-plus-plus-1.3.3/install/ubuntu22.04/include/sw/redis++/connection.h rename to ext/redis-plus-plus-1.3.3/install/ubuntu22.04/amd64/include/sw/redis++/connection.h diff --git a/ext/redis-plus-plus-1.3.3/install/ubuntu22.04/include/sw/redis++/connection_pool.h b/ext/redis-plus-plus-1.3.3/install/ubuntu22.04/amd64/include/sw/redis++/connection_pool.h similarity index 100% rename from ext/redis-plus-plus-1.3.3/install/ubuntu22.04/include/sw/redis++/connection_pool.h rename to ext/redis-plus-plus-1.3.3/install/ubuntu22.04/amd64/include/sw/redis++/connection_pool.h diff --git a/ext/redis-plus-plus-1.3.3/install/ubuntu22.04/include/sw/redis++/cxx_utils.h b/ext/redis-plus-plus-1.3.3/install/ubuntu22.04/amd64/include/sw/redis++/cxx_utils.h similarity index 100% rename from ext/redis-plus-plus-1.3.3/install/ubuntu22.04/include/sw/redis++/cxx_utils.h rename to ext/redis-plus-plus-1.3.3/install/ubuntu22.04/amd64/include/sw/redis++/cxx_utils.h diff --git a/ext/redis-plus-plus-1.3.3/install/ubuntu22.04/include/sw/redis++/errors.h b/ext/redis-plus-plus-1.3.3/install/ubuntu22.04/amd64/include/sw/redis++/errors.h similarity index 100% rename from ext/redis-plus-plus-1.3.3/install/ubuntu22.04/include/sw/redis++/errors.h rename to ext/redis-plus-plus-1.3.3/install/ubuntu22.04/amd64/include/sw/redis++/errors.h diff --git a/ext/redis-plus-plus-1.3.3/install/ubuntu22.04/include/sw/redis++/pipeline.h b/ext/redis-plus-plus-1.3.3/install/ubuntu22.04/amd64/include/sw/redis++/pipeline.h similarity index 100% rename from ext/redis-plus-plus-1.3.3/install/ubuntu22.04/include/sw/redis++/pipeline.h rename to ext/redis-plus-plus-1.3.3/install/ubuntu22.04/amd64/include/sw/redis++/pipeline.h diff --git a/ext/redis-plus-plus-1.3.3/install/ubuntu22.04/include/sw/redis++/queued_redis.h b/ext/redis-plus-plus-1.3.3/install/ubuntu22.04/amd64/include/sw/redis++/queued_redis.h similarity index 100% rename from ext/redis-plus-plus-1.3.3/install/ubuntu22.04/include/sw/redis++/queued_redis.h rename to ext/redis-plus-plus-1.3.3/install/ubuntu22.04/amd64/include/sw/redis++/queued_redis.h diff --git a/ext/redis-plus-plus-1.3.3/install/ubuntu22.04/include/sw/redis++/queued_redis.hpp b/ext/redis-plus-plus-1.3.3/install/ubuntu22.04/amd64/include/sw/redis++/queued_redis.hpp similarity index 100% rename from ext/redis-plus-plus-1.3.3/install/ubuntu22.04/include/sw/redis++/queued_redis.hpp rename to ext/redis-plus-plus-1.3.3/install/ubuntu22.04/amd64/include/sw/redis++/queued_redis.hpp diff --git a/ext/redis-plus-plus-1.3.3/install/ubuntu22.04/include/sw/redis++/redis++.h b/ext/redis-plus-plus-1.3.3/install/ubuntu22.04/amd64/include/sw/redis++/redis++.h similarity index 100% rename from ext/redis-plus-plus-1.3.3/install/ubuntu22.04/include/sw/redis++/redis++.h rename to ext/redis-plus-plus-1.3.3/install/ubuntu22.04/amd64/include/sw/redis++/redis++.h diff --git a/ext/redis-plus-plus-1.3.3/install/ubuntu22.04/include/sw/redis++/redis.h b/ext/redis-plus-plus-1.3.3/install/ubuntu22.04/amd64/include/sw/redis++/redis.h similarity index 100% rename from ext/redis-plus-plus-1.3.3/install/ubuntu22.04/include/sw/redis++/redis.h rename to ext/redis-plus-plus-1.3.3/install/ubuntu22.04/amd64/include/sw/redis++/redis.h diff --git a/ext/redis-plus-plus-1.3.3/install/ubuntu22.04/include/sw/redis++/redis.hpp b/ext/redis-plus-plus-1.3.3/install/ubuntu22.04/amd64/include/sw/redis++/redis.hpp similarity index 100% rename from ext/redis-plus-plus-1.3.3/install/ubuntu22.04/include/sw/redis++/redis.hpp rename to ext/redis-plus-plus-1.3.3/install/ubuntu22.04/amd64/include/sw/redis++/redis.hpp diff --git a/ext/redis-plus-plus-1.3.3/install/ubuntu22.04/include/sw/redis++/redis_cluster.h b/ext/redis-plus-plus-1.3.3/install/ubuntu22.04/amd64/include/sw/redis++/redis_cluster.h similarity index 100% rename from ext/redis-plus-plus-1.3.3/install/ubuntu22.04/include/sw/redis++/redis_cluster.h rename to ext/redis-plus-plus-1.3.3/install/ubuntu22.04/amd64/include/sw/redis++/redis_cluster.h diff --git a/ext/redis-plus-plus-1.3.3/install/ubuntu22.04/include/sw/redis++/redis_cluster.hpp b/ext/redis-plus-plus-1.3.3/install/ubuntu22.04/amd64/include/sw/redis++/redis_cluster.hpp similarity index 100% rename from ext/redis-plus-plus-1.3.3/install/ubuntu22.04/include/sw/redis++/redis_cluster.hpp rename to ext/redis-plus-plus-1.3.3/install/ubuntu22.04/amd64/include/sw/redis++/redis_cluster.hpp diff --git a/ext/redis-plus-plus-1.3.3/install/ubuntu22.04/include/sw/redis++/reply.h b/ext/redis-plus-plus-1.3.3/install/ubuntu22.04/amd64/include/sw/redis++/reply.h similarity index 100% rename from ext/redis-plus-plus-1.3.3/install/ubuntu22.04/include/sw/redis++/reply.h rename to ext/redis-plus-plus-1.3.3/install/ubuntu22.04/amd64/include/sw/redis++/reply.h diff --git a/ext/redis-plus-plus-1.3.3/install/ubuntu22.04/include/sw/redis++/sentinel.h b/ext/redis-plus-plus-1.3.3/install/ubuntu22.04/amd64/include/sw/redis++/sentinel.h similarity index 100% rename from ext/redis-plus-plus-1.3.3/install/ubuntu22.04/include/sw/redis++/sentinel.h rename to ext/redis-plus-plus-1.3.3/install/ubuntu22.04/amd64/include/sw/redis++/sentinel.h diff --git a/ext/redis-plus-plus-1.3.3/install/ubuntu22.04/include/sw/redis++/shards.h b/ext/redis-plus-plus-1.3.3/install/ubuntu22.04/amd64/include/sw/redis++/shards.h similarity index 100% rename from ext/redis-plus-plus-1.3.3/install/ubuntu22.04/include/sw/redis++/shards.h rename to ext/redis-plus-plus-1.3.3/install/ubuntu22.04/amd64/include/sw/redis++/shards.h diff --git a/ext/redis-plus-plus-1.3.3/install/ubuntu22.04/include/sw/redis++/shards_pool.h b/ext/redis-plus-plus-1.3.3/install/ubuntu22.04/amd64/include/sw/redis++/shards_pool.h similarity index 100% rename from ext/redis-plus-plus-1.3.3/install/ubuntu22.04/include/sw/redis++/shards_pool.h rename to ext/redis-plus-plus-1.3.3/install/ubuntu22.04/amd64/include/sw/redis++/shards_pool.h diff --git a/ext/redis-plus-plus-1.3.3/install/ubuntu22.04/include/sw/redis++/subscriber.h b/ext/redis-plus-plus-1.3.3/install/ubuntu22.04/amd64/include/sw/redis++/subscriber.h similarity index 100% rename from ext/redis-plus-plus-1.3.3/install/ubuntu22.04/include/sw/redis++/subscriber.h rename to ext/redis-plus-plus-1.3.3/install/ubuntu22.04/amd64/include/sw/redis++/subscriber.h diff --git a/ext/redis-plus-plus-1.3.3/install/ubuntu22.04/include/sw/redis++/tls.h b/ext/redis-plus-plus-1.3.3/install/ubuntu22.04/amd64/include/sw/redis++/tls.h similarity index 100% rename from ext/redis-plus-plus-1.3.3/install/ubuntu22.04/include/sw/redis++/tls.h rename to ext/redis-plus-plus-1.3.3/install/ubuntu22.04/amd64/include/sw/redis++/tls.h diff --git a/ext/redis-plus-plus-1.3.3/install/ubuntu22.04/include/sw/redis++/transaction.h b/ext/redis-plus-plus-1.3.3/install/ubuntu22.04/amd64/include/sw/redis++/transaction.h similarity index 100% rename from ext/redis-plus-plus-1.3.3/install/ubuntu22.04/include/sw/redis++/transaction.h rename to ext/redis-plus-plus-1.3.3/install/ubuntu22.04/amd64/include/sw/redis++/transaction.h diff --git a/ext/redis-plus-plus-1.3.3/install/ubuntu22.04/include/sw/redis++/utils.h b/ext/redis-plus-plus-1.3.3/install/ubuntu22.04/amd64/include/sw/redis++/utils.h similarity index 100% rename from ext/redis-plus-plus-1.3.3/install/ubuntu22.04/include/sw/redis++/utils.h rename to ext/redis-plus-plus-1.3.3/install/ubuntu22.04/amd64/include/sw/redis++/utils.h diff --git a/ext/redis-plus-plus-1.3.3/install/ubuntu22.04/lib/pkgconfig/redis++.pc b/ext/redis-plus-plus-1.3.3/install/ubuntu22.04/amd64/lib/pkgconfig/redis++.pc similarity index 100% rename from ext/redis-plus-plus-1.3.3/install/ubuntu22.04/lib/pkgconfig/redis++.pc rename to ext/redis-plus-plus-1.3.3/install/ubuntu22.04/amd64/lib/pkgconfig/redis++.pc diff --git a/ext/redis-plus-plus-1.3.3/install/ubuntu22.04/share/cmake/redis++/redis++-config-version.cmake b/ext/redis-plus-plus-1.3.3/install/ubuntu22.04/amd64/share/cmake/redis++/redis++-config-version.cmake similarity index 100% rename from ext/redis-plus-plus-1.3.3/install/ubuntu22.04/share/cmake/redis++/redis++-config-version.cmake rename to ext/redis-plus-plus-1.3.3/install/ubuntu22.04/amd64/share/cmake/redis++/redis++-config-version.cmake diff --git a/ext/redis-plus-plus-1.3.3/install/ubuntu22.04/share/cmake/redis++/redis++-config.cmake b/ext/redis-plus-plus-1.3.3/install/ubuntu22.04/amd64/share/cmake/redis++/redis++-config.cmake similarity index 100% rename from ext/redis-plus-plus-1.3.3/install/ubuntu22.04/share/cmake/redis++/redis++-config.cmake rename to ext/redis-plus-plus-1.3.3/install/ubuntu22.04/amd64/share/cmake/redis++/redis++-config.cmake diff --git a/ext/redis-plus-plus-1.3.3/install/ubuntu22.04/share/cmake/redis++/redis++-targets-release.cmake b/ext/redis-plus-plus-1.3.3/install/ubuntu22.04/amd64/share/cmake/redis++/redis++-targets-release.cmake similarity index 100% rename from ext/redis-plus-plus-1.3.3/install/ubuntu22.04/share/cmake/redis++/redis++-targets-release.cmake rename to ext/redis-plus-plus-1.3.3/install/ubuntu22.04/amd64/share/cmake/redis++/redis++-targets-release.cmake diff --git a/ext/redis-plus-plus-1.3.3/install/ubuntu22.04/share/cmake/redis++/redis++-targets.cmake b/ext/redis-plus-plus-1.3.3/install/ubuntu22.04/amd64/share/cmake/redis++/redis++-targets.cmake similarity index 100% rename from ext/redis-plus-plus-1.3.3/install/ubuntu22.04/share/cmake/redis++/redis++-targets.cmake rename to ext/redis-plus-plus-1.3.3/install/ubuntu22.04/amd64/share/cmake/redis++/redis++-targets.cmake diff --git a/ext/redis-plus-plus-1.3.3/install/ubuntu22.04/arm64/include/sw/redis++/cmd_formatter.h b/ext/redis-plus-plus-1.3.3/install/ubuntu22.04/arm64/include/sw/redis++/cmd_formatter.h new file mode 100644 index 000000000..85efdf347 --- /dev/null +++ b/ext/redis-plus-plus-1.3.3/install/ubuntu22.04/arm64/include/sw/redis++/cmd_formatter.h @@ -0,0 +1,775 @@ +/************************************************************************** + Copyright (c) 2021 sewenew + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + *************************************************************************/ + +#ifndef SEWENEW_REDISPLUSPLUS_CMD_FORMATTER_H +#define SEWENEW_REDISPLUSPLUS_CMD_FORMATTER_H + +#include +#include "command_options.h" +#include "command_args.h" +#include "command.h" +#include "errors.h" + +namespace sw { + +namespace redis { + +class FormattedCommand { +public: + FormattedCommand(char *data, int len) : _data(data), _size(len) { + if (data == nullptr || len < 0) { + throw Error("failed to format command"); + } + } + + FormattedCommand(const FormattedCommand &) = delete; + FormattedCommand& operator=(const FormattedCommand &) = delete; + + FormattedCommand(FormattedCommand &&that) noexcept { + _move(std::move(that)); + } + + FormattedCommand& operator=(FormattedCommand &&that) noexcept { + if (this != &that) { + _move(std::move(that)); + } + + return *this; + } + + ~FormattedCommand() noexcept { + if (_data != nullptr) { + redisFreeCommand(_data); + } + } + + const char* data() const noexcept { + return _data; + } + + int size() const noexcept { + return _size; + } + +private: + void _move(FormattedCommand &&that) noexcept { + _data = that._data; + _size = that._size; + that._data = nullptr; + that._size = 0; + } + + char *_data = nullptr; + int _size = 0; +}; + +namespace fmt { + +template +FormattedCommand format_cmd(const char *format, Args &&...args) { + char *data = nullptr; + auto len = redisFormatCommand(&data, format, std::forward(args)...); + + return FormattedCommand(data, len); +} + +inline FormattedCommand format_cmd(int argc, const char **argv, const std::size_t *argv_len) { + char *data = nullptr; + auto len = redisFormatCommandArgv(&data, argc, argv, argv_len); + + return FormattedCommand(data, len); +} + +inline FormattedCommand format_cmd(CmdArgs &args) { + char *data = nullptr; + auto len = redisFormatCommandArgv(&data, args.size(), args.argv(), args.argv_len()); + + return FormattedCommand(data, len); +} + +struct SetResultParser { + bool operator()(redisReply &reply) const { + sw::redis::reply::rewrite_set_reply(reply); + return sw::redis::reply::parse(reply); + } +}; + +// CONNECTION commands. + +inline FormattedCommand echo(const StringView &msg) { + return format_cmd("ECHO %b", msg.data(), msg.size()); +} + +inline FormattedCommand ping() { + return format_cmd("PING"); +} + +inline FormattedCommand ping(const StringView &msg) { + return format_cmd("PING %b", msg.data(), msg.size()); +} + +inline FormattedCommand del(const StringView &key) { + return format_cmd("DEL %b", key.data(), key.size()); +} + +template +FormattedCommand del_range(Input first, Input last) { + assert(first != last); + + CmdArgs args; + args << "DEL" << std::make_pair(first, last); + + return format_cmd(args); +} + +inline FormattedCommand exists(const StringView &key) { + return format_cmd("EXISTS %b", key.data(), key.size()); +} + +template +FormattedCommand exists_range(Input first, Input last) { + assert(first != last); + + CmdArgs args; + args << "EXISTS" << std::make_pair(first, last); + + return format_cmd(args); +} + +inline FormattedCommand expire(const StringView &key, const std::chrono::seconds &timeout) { + return format_cmd("EXPIRE %b %lld", key.data(), key.size(), timeout.count()); +} + +inline FormattedCommand expireat(const StringView &key, + const std::chrono::time_point &tp) { + return format_cmd("EXPIREAT %b %lld", key.data(), key.size(), tp.time_since_epoch().count()); +} + +inline FormattedCommand pexpire(const StringView &key, + const std::chrono::milliseconds &timeout) { + return format_cmd("PEXPIRE %b %lld", key.data(), key.size(), timeout.count()); +} + +inline FormattedCommand pexpireat(const StringView &key, + const std::chrono::time_point &tp) { + return format_cmd("PEXPIREAT %b %lld", key.data(), key.size(), tp.time_since_epoch().count()); +} + +inline FormattedCommand pttl(const StringView &key) { + return format_cmd("PTTL %b", key.data(), key.size()); +} + +inline FormattedCommand rename(const StringView &key, const StringView &newkey) { + return format_cmd("RENAME %b %b", key.data(), key.size(), newkey.data(), newkey.size()); +} + +inline FormattedCommand renamenx(const StringView &key, const StringView &newkey) { + return format_cmd("RENAMENX %b %b", key.data(), key.size(), newkey.data(), newkey.size()); +} + +inline FormattedCommand ttl(const StringView &key) { + return format_cmd("TTL %b", key.data(), key.size()); +} + +inline FormattedCommand unlink(const StringView &key) { + return format_cmd("UNLINK %b", key.data(), key.size()); +} + +template +FormattedCommand unlink_range(Input first, Input last) { + CmdArgs args; + args << "UNLINK" << std::make_pair(first, last); + + return format_cmd(args); +} + +// STRING commands. + +inline FormattedCommand get(const StringView &key) { + return format_cmd("GET %b", key.data(), key.size()); +} + +inline FormattedCommand incr(const StringView &key) { + return format_cmd("INCR %b", key.data(), key.size()); +} + +inline FormattedCommand incrby(const StringView &key, long long increment) { + return format_cmd("INCRBY %b %lld", key.data(), key.size(), increment); +} + +inline FormattedCommand incrbyfloat(const StringView &key, double increment) { + return format_cmd("INCRBYFLOAT %b %f", key.data(), key.size(), increment); +} + +template +FormattedCommand mget(Input first, Input last) { + CmdArgs args; + args << "MGET" << std::make_pair(first, last); + + return format_cmd(args); +} + +template +FormattedCommand mset(Input first, Input last) { + CmdArgs args; + args << "MSET" << std::make_pair(first, last); + + return format_cmd(args); +} + +template +FormattedCommand msetnx(Input first, Input last) { + CmdArgs args; + args << "MSETNX" << std::make_pair(first, last); + + return format_cmd(args); +} + +inline FormattedCommand set(const StringView &key, + const StringView &val, + const std::chrono::milliseconds &ttl, + UpdateType type) { + CmdArgs args; + args << "SET" << key << val; + + if (ttl > std::chrono::milliseconds(0)) { + args << "PX" << ttl.count(); + } + + cmd::detail::set_update_type(args, type); + + return format_cmd(args); +} + +inline FormattedCommand strlen(const StringView &key) { + return format_cmd("STRLEN %b", key.data(), key.size()); +} + +inline FormattedCommand blpop(const StringView &key, const std::chrono::seconds &timeout) { + return format_cmd("BLPOP %b %lld", key.data(), key.size(), timeout.count()); +} + +template +FormattedCommand blpop_range(Input first, Input last, const std::chrono::seconds &timeout) { + assert(first != last); + + CmdArgs args; + args << "BLPOP" << std::make_pair(first, last) << timeout.count(); + + return format_cmd(args); +} + +inline FormattedCommand brpop(const StringView &key, const std::chrono::seconds &timeout) { + return format_cmd("BRPOP %b %lld", key.data(), key.size(), timeout.count()); +} + + +template +FormattedCommand brpop_range(Input first, Input last, const std::chrono::seconds &timeout) { + assert(first != last); + + CmdArgs args; + args << "BRPOP" << std::make_pair(first, last) << timeout.count(); + + return format_cmd(args); +} + +inline FormattedCommand brpoplpush(const StringView &source, + const StringView &destination, + const std::chrono::seconds &timeout) { + return format_cmd("BRPOPLPUSH %b %b %lld", + source.data(), source.size(), + destination.data(), destination.size(), + timeout.count()); +} + +inline FormattedCommand llen(const StringView &key) { + return format_cmd("LLEN %b", key.data(), key.size()); +} + +inline FormattedCommand lpop(const StringView &key) { + return format_cmd("LPOP %b", key.data(), key.size()); +} + +inline FormattedCommand lpush(const StringView &key, const StringView &val) { + return format_cmd("LPUSH %b %b", key.data(), key.size(), val.data(), val.size()); +} + +template +FormattedCommand lpush_range(const StringView &key, Input first, Input last) { + assert(first != last); + + CmdArgs args; + args << "LPUSH" << key << std::make_pair(first, last); + + return format_cmd(args); +} + +inline FormattedCommand lrange(const StringView &key, long long start, long long stop) { + return format_cmd("LRANGE %b %lld %lld", key.data(), key.size(), start, stop); +} + +inline FormattedCommand lrem(const StringView &key, long long count, const StringView &val) { + return format_cmd("LREM %b %lld %b", key.data(), key.size(), count, val.data(), val.size()); +} + +inline FormattedCommand ltrim(const StringView &key, long long start, long long stop) { + return format_cmd("LTRIM %b %lld %lld", key.data(), key.size(), start, stop); +} + +inline FormattedCommand rpop(const StringView &key) { + return format_cmd("RPOP %b", key.data(), key.size()); +} + +inline FormattedCommand rpoplpush(const StringView &source, const StringView &destination) { + return format_cmd("RPOPLPUSH %b %b", + source.data(), source.size(), + destination.data(), destination.size()); +} + +inline FormattedCommand rpush(const StringView &key, const StringView &val) { + return format_cmd("RPUSH %b %b", key.data(), key.size(), val.data(), val.size()); +} + +template +FormattedCommand rpush_range(const StringView &key, Input first, Input last) { + assert(first != last); + + CmdArgs args; + args << "RPUSH" << key << std::make_pair(first, last); + + return format_cmd(args); +} + +// HASH commands. + +inline FormattedCommand hdel(const StringView &key, const StringView &field) { + return format_cmd("HDEL %b %b", key.data(), key.size(), field.data(), field.size()); +} + +template +FormattedCommand hdel_range(const StringView &key, Input first, Input last) { + assert(first != last); + + CmdArgs args; + args << "HDEL" << key << std::make_pair(first, last); + + return format_cmd(args); +} + +inline FormattedCommand hexists(const StringView &key, const StringView &field) { + return format_cmd("HEXISTS %b %b", key.data(), key.size(), field.data(), field.size()); +} + +inline FormattedCommand hget(const StringView &key, const StringView &field) { + return format_cmd("HGET %b %b", key.data(), key.size(), field.data(), field.size()); +} + +inline FormattedCommand hgetall(const StringView &key) { + return format_cmd("HGETALL %b", key.data(), key.size()); +} + +inline FormattedCommand hincrby(const StringView &key, + const StringView &field, + long long increment) { + return format_cmd("HINCRBY %b %b %lld", + key.data(), key.size(), + field.data(), field.size(), + increment); +} + +inline FormattedCommand hincrbyfloat(const StringView &key, + const StringView &field, + double increment) { + return format_cmd("HINCRBYFLOAT %b %b %f", + key.data(), key.size(), + field.data(), field.size(), + increment); +} + +inline FormattedCommand hkeys(const StringView &key) { + return format_cmd("HKEYS %b", key.data(), key.size()); +} + +inline FormattedCommand hlen(const StringView &key) { + return format_cmd("HLEN %b", key.data(), key.size()); +} + +template +FormattedCommand hmget(const StringView &key, Input first, Input last) { + assert(first != last); + + CmdArgs args; + args << "HMGET" << key << std::make_pair(first, last); + + return format_cmd(args); +} + +template +FormattedCommand hmset(const StringView &key, Input first, Input last) { + assert(first != last); + + CmdArgs args; + args << "HMSET" << key << std::make_pair(first, last); + + return format_cmd(args); +} + +inline FormattedCommand hset(const StringView &key, + const StringView &field, + const StringView &val) { + return format_cmd("HSET %b %b %b", + key.data(), key.size(), + field.data(), field.size(), + val.data(), val.size()); +} + +template +auto hset_range(const StringView &key, + Input first, + Input last) + -> typename std::enable_if::value, + FormattedCommand>::type { + assert(first != last); + + CmdArgs args; + args << "HSET" << key << std::make_pair(first, last); + + return format_cmd(args); +} + +inline FormattedCommand hvals(const StringView &key) { + return format_cmd("HVALS %b", key.data(), key.size()); +} + +// SET commands. + +inline FormattedCommand sadd(const StringView &key, const StringView &member) { + return format_cmd("SADD %b %b", key.data(), key.size(), member.data(), member.size()); +} + +template +FormattedCommand sadd_range(const StringView &key, Input first, Input last) { + assert(first != last); + + CmdArgs args; + args << "SADD" << key << std::make_pair(first, last); + + return format_cmd(args); +} + +inline FormattedCommand scard(const StringView &key) { + return format_cmd("SCARD %b", key.data(), key.size()); +} + +inline FormattedCommand sismember(const StringView &key, const StringView &member) { + return format_cmd("SISMEMBER %b %b", key.data(), key.size(), member.data(), member.size()); +} + +inline FormattedCommand smembers(const StringView &key) { + return format_cmd("SMEMBERS %b", key.data(), key.size()); +} + +inline FormattedCommand spop(const StringView &key) { + return format_cmd("SPOP %b", key.data(), key.size()); +} + +inline FormattedCommand spop(const StringView &key, long long count) { + return format_cmd("SPOP %b %lld", key.data(), key.size(), count); +} + +inline FormattedCommand srem(const StringView &key, const StringView &member) { + return format_cmd("SREM %b %b", key.data(), key.size(), member.data(), member.size()); +} + +template +FormattedCommand srem_range(const StringView &key, Input first, Input last) { + assert(first != last); + + CmdArgs args; + args << "SREM" << key << std::make_pair(first, last); + + return format_cmd(args); +} + +// SORTED SET commands. + +inline FormattedCommand bzpopmax(const StringView &key, const std::chrono::seconds &timeout) { + return format_cmd("BZPOPMAX %b %lld", key.data(), key.size(), timeout.count()); +} + +template +FormattedCommand bzpopmax_range(Input first, + Input last, + const std::chrono::seconds &timeout) { + assert(first != last); + + CmdArgs args; + args << "BZPOPMAX" << std::make_pair(first, last) << timeout.count(); + + return format_cmd(args); +} + +inline FormattedCommand bzpopmin(const StringView &key, const std::chrono::seconds &timeout) { + return format_cmd("BZPOPMIN %b %lld", key.data(), key.size(), timeout.count()); +} + +template +FormattedCommand bzpopmin_range(Input first, Input last, const std::chrono::seconds &timeout) { + assert(first != last); + + CmdArgs args; + args << "BZPOPMIN" << std::make_pair(first, last) << timeout.count(); + + return format_cmd(args); +} + +inline FormattedCommand zadd(const StringView &key, + const StringView &member, + double score, + UpdateType type, + bool changed) { + CmdArgs args; + args << "ZADD" << key; + + cmd::detail::set_update_type(args, type); + + if (changed) { + args << "CH"; + } + + args << score << member; + + return format_cmd(args); +} + +template +FormattedCommand zadd_range(const StringView &key, + Input first, + Input last, + UpdateType type, + bool changed) { + CmdArgs args; + args << "ZADD" << key; + + cmd::detail::set_update_type(args, type); + + if (changed) { + args << "CH"; + } + + while (first != last) { + // Swap the pair to pair. + args << first->second << first->first; + ++first; + } + + return format_cmd(args); +} + +inline FormattedCommand zcard(const StringView &key) { + return format_cmd("ZCARD %b", key.data(), key.size()); +} + +template +FormattedCommand zcount(const StringView &key, const Interval &interval) { + return format_cmd("ZCOUNT %b %s %s", + key.data(), key.size(), + interval.min().c_str(), + interval.max().c_str()); +} + +inline FormattedCommand zincrby(const StringView &key, + double increment, + const StringView &member) { + return format_cmd("ZINCRBY %b %f %b", + key.data(), key.size(), + increment, + member.data(), member.size()); +} + +template +FormattedCommand zlexcount(const StringView &key, + const Interval &interval) { + const auto &min = interval.min(); + const auto &max = interval.max(); + + return format_cmd("ZLEXCOUNT %b %b %b", + key.data(), key.size(), + min.data(), min.size(), + max.data(), max.size()); +} + +inline FormattedCommand zpopmax(const StringView &key) { + return format_cmd("ZPOPMAX %b", key.data(), key.size()); +} + +inline FormattedCommand zpopmax(const StringView &key, long long count) { + return format_cmd("ZPOPMAX %b %lld", key.data(), key.size(), count); +} + +inline FormattedCommand zpopmin(const StringView &key) { + return format_cmd("ZPOPMIN %b", key.data(), key.size()); +} + +inline FormattedCommand zpopmin_count(const StringView &key, long long count) { + return format_cmd("ZPOPMIN %b %lld", key.data(), key.size(), count); +} + +inline FormattedCommand zrange(const StringView &key, long long start, long long stop) { + return format_cmd("ZRANGE %b %lld %lld", key.data(), key.size(), start, stop); +} + +template +FormattedCommand zrangebylex(const StringView &key, + const Interval &interval, + const LimitOptions &opts) { + const auto &min = interval.min(); + const auto &max = interval.max(); + + return format_cmd("ZRANGEBYLEX %b %b %b LIMIT %lld %lld", + key.data(), key.size(), + min.data(), min.size(), + max.data(), max.size(), + opts.offset, + opts.count); +} + +template +FormattedCommand zrangebyscore(const StringView &key, + const Interval &interval, + const LimitOptions &opts) { + const auto &min = interval.min(); + const auto &max = interval.max(); + + return format_cmd("ZRANGEBYSCORE %b %b %b LIMIT %lld %lld", + key.data(), key.size(), + min.data(), min.size(), + max.data(), max.size(), + opts.offset, + opts.count); +} + +inline FormattedCommand zrank(const StringView &key, const StringView &member) { + return format_cmd("ZRANK %b %b", key.data(), key.size(), member.data(), member.size()); +} + +inline FormattedCommand zrem(const StringView &key, const StringView &member) { + return format_cmd("ZREM %b %b", key.data(), key.size(), member.data(), member.size()); +} + +template +FormattedCommand zrem_range(const StringView &key, Input first, Input last) { + assert(first != last); + + CmdArgs args; + args << "ZREM" << key << std::make_pair(first, last); + + return format_cmd(args); +} + +template +FormattedCommand zremrangebylex(const StringView &key, const Interval &interval) { + const auto &min = interval.min(); + const auto &max = interval.max(); + + return format_cmd("ZREMRANGEBYLEX %b %b %b", + key.data(), key.size(), + min.data(), min.size(), + max.data(), max.size()); +} + +inline FormattedCommand zremrangebyrank(const StringView &key, long long start, long long stop) { + return format_cmd("ZREMRANGEBYRANK %b %lld %lld", key.data(), key.size(), start, stop); +} + +template +FormattedCommand zremrangebyscore(const StringView &key, + const Interval &interval) { + const auto &min = interval.min(); + const auto &max = interval.max(); + + return format_cmd("ZREMRANGEBYSCORE %b %b %b", + key.data(), key.size(), + min.data(), min.size(), + max.data(), max.size()); +} + +template +FormattedCommand zrevrangebylex(const StringView &key, + const Interval &interval, + const LimitOptions &opts) { + const auto &min = interval.min(); + const auto &max = interval.max(); + + return format_cmd("ZREVRANGEBYLEX %b %b %b LIMIT %lld %lld", + key.data(), key.size(), + max.data(), max.size(), + min.data(), min.size(), + opts.offset, + opts.count); +} + +inline FormattedCommand zrevrank(const StringView &key, const StringView &member) { + return format_cmd("ZREVRANK %b %b", key.data(), key.size(), member.data(), member.size()); +} + +inline FormattedCommand zscore(const StringView &key, const StringView &member) { + return format_cmd("ZSCORE %b %b", key.data(), key.size(), member.data(), member.size()); +} + +// SCRIPTING commands. +template +FormattedCommand eval(const StringView &script, + Keys keys_first, + Keys keys_last, + Args args_first, + Args args_last) { + CmdArgs args; + auto keys_num = std::distance(keys_first, keys_last); + + args << "EVAL" << script << keys_num + << std::make_pair(keys_first, keys_last) + << std::make_pair(args_first, args_last); + + return format_cmd(args); +} + +template +FormattedCommand evalsha(const StringView &script, + Keys keys_first, + Keys keys_last, + Args args_first, + Args args_last) { + CmdArgs args; + auto keys_num = std::distance(keys_first, keys_last); + + args << "EVALSHA" << script << keys_num + << std::make_pair(keys_first, keys_last) + << std::make_pair(args_first, args_last); + + return format_cmd(args); +} + +} + +} + +} + +#endif // end SEWENEW_REDISPLUSPLUS_CMD_FORMATTER_H diff --git a/ext/redis-plus-plus-1.3.3/install/ubuntu22.04/arm64/include/sw/redis++/command.h b/ext/redis-plus-plus-1.3.3/install/ubuntu22.04/arm64/include/sw/redis++/command.h new file mode 100644 index 000000000..81857dd9b --- /dev/null +++ b/ext/redis-plus-plus-1.3.3/install/ubuntu22.04/arm64/include/sw/redis++/command.h @@ -0,0 +1,2271 @@ +/************************************************************************** + Copyright (c) 2017 sewenew + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + *************************************************************************/ + +#ifndef SEWENEW_REDISPLUSPLUS_COMMAND_H +#define SEWENEW_REDISPLUSPLUS_COMMAND_H + +#include +#include +#include +#include +#include "connection.h" +#include "command_options.h" +#include "command_args.h" +#include "utils.h" + +namespace sw { + +namespace redis { + +namespace cmd { + +// CONNECTION command. +inline void auth(Connection &connection, const StringView &password) { + connection.send("AUTH %b", password.data(), password.size()); +} + +inline void auth(Connection &connection, const StringView &user, const StringView &password) { + connection.send("AUTH %b %b", + user.data(), user.size(), + password.data(), password.size()); +} + +inline void echo(Connection &connection, const StringView &msg) { + connection.send("ECHO %b", msg.data(), msg.size()); +} + +inline void ping(Connection &connection) { + connection.send("PING"); +} + +inline void quit(Connection &connection) { + connection.send("QUIT"); +} + +inline void ping(Connection &connection, const StringView &msg) { + // If *msg* is empty, Redis returns am empty reply of REDIS_REPLY_STRING type. + connection.send("PING %b", msg.data(), msg.size()); +} + +inline void select(Connection &connection, long long idx) { + connection.send("SELECT %lld", idx); +} + +inline void swapdb(Connection &connection, long long idx1, long long idx2) { + connection.send("SWAPDB %lld %lld", idx1, idx2); +} + +// SERVER commands. + +inline void bgrewriteaof(Connection &connection) { + connection.send("BGREWRITEAOF"); +} + +inline void bgsave(Connection &connection) { + connection.send("BGSAVE"); +} + +inline void dbsize(Connection &connection) { + connection.send("DBSIZE"); +} + +inline void flushall(Connection &connection, bool async) { + if (async) { + connection.send("FLUSHALL ASYNC"); + } else { + connection.send("FLUSHALL"); + } +} + +inline void flushdb(Connection &connection, bool async) { + if (async) { + connection.send("FLUSHDB ASYNC"); + } else { + connection.send("FLUSHDB"); + } +} + +inline void info(Connection &connection) { + connection.send("INFO"); +} + +inline void info(Connection &connection, const StringView §ion) { + connection.send("INFO %b", section.data(), section.size()); +} + +inline void lastsave(Connection &connection) { + connection.send("LASTSAVE"); +} + +inline void save(Connection &connection) { + connection.send("SAVE"); +} + +// KEY commands. + +inline void del(Connection &connection, const StringView &key) { + connection.send("DEL %b", key.data(), key.size()); +} + +template +inline void del_range(Connection &connection, Input first, Input last) { + assert(first != last); + + CmdArgs args; + args << "DEL" << std::make_pair(first, last); + + connection.send(args); +} + +inline void dump(Connection &connection, const StringView &key) { + connection.send("DUMP %b", key.data(), key.size()); +} + +inline void exists(Connection &connection, const StringView &key) { + connection.send("EXISTS %b", key.data(), key.size()); +} + +template +inline void exists_range(Connection &connection, Input first, Input last) { + assert(first != last); + + CmdArgs args; + args << "EXISTS" << std::make_pair(first, last); + + connection.send(args); +} + +inline void expire(Connection &connection, + const StringView &key, + long long timeout) { + connection.send("EXPIRE %b %lld", + key.data(), key.size(), + timeout); +} + +inline void expireat(Connection &connection, + const StringView &key, + long long timestamp) { + connection.send("EXPIREAT %b %lld", + key.data(), key.size(), + timestamp); +} + +inline void keys(Connection &connection, const StringView &pattern) { + connection.send("KEYS %b", pattern.data(), pattern.size()); +} + +inline void move(Connection &connection, const StringView &key, long long db) { + connection.send("MOVE %b %lld", + key.data(), key.size(), + db); +} + +inline void persist(Connection &connection, const StringView &key) { + connection.send("PERSIST %b", key.data(), key.size()); +} + +inline void pexpire(Connection &connection, + const StringView &key, + long long timeout) { + connection.send("PEXPIRE %b %lld", + key.data(), key.size(), + timeout); +} + +inline void pexpireat(Connection &connection, + const StringView &key, + long long timestamp) { + connection.send("PEXPIREAT %b %lld", + key.data(), key.size(), + timestamp); +} + +inline void pttl(Connection &connection, const StringView &key) { + connection.send("PTTL %b", key.data(), key.size()); +} + +inline void randomkey(Connection &connection) { + connection.send("RANDOMKEY"); +} + +inline void rename(Connection &connection, + const StringView &key, + const StringView &newkey) { + connection.send("RENAME %b %b", + key.data(), key.size(), + newkey.data(), newkey.size()); +} + +inline void renamenx(Connection &connection, + const StringView &key, + const StringView &newkey) { + connection.send("RENAMENX %b %b", + key.data(), key.size(), + newkey.data(), newkey.size()); +} + +void restore(Connection &connection, + const StringView &key, + const StringView &val, + long long ttl, + bool replace); + +inline void scan(Connection &connection, + long long cursor, + const StringView &pattern, + long long count) { + connection.send("SCAN %lld MATCH %b COUNT %lld", + cursor, + pattern.data(), pattern.size(), + count); +} + +inline void touch(Connection &connection, const StringView &key) { + connection.send("TOUCH %b", key.data(), key.size()); +} + +template +inline void touch_range(Connection &connection, Input first, Input last) { + assert(first != last); + + CmdArgs args; + args << "TOUCH" << std::make_pair(first, last); + + connection.send(args); +} + +inline void ttl(Connection &connection, const StringView &key) { + connection.send("TTL %b", key.data(), key.size()); +} + +inline void type(Connection &connection, const StringView &key) { + connection.send("TYPE %b", key.data(), key.size()); +} + +inline void unlink(Connection &connection, const StringView &key) { + connection.send("UNLINK %b", key.data(), key.size()); +} + +template +inline void unlink_range(Connection &connection, Input first, Input last) { + assert(first != last); + + CmdArgs args; + args << "UNLINK" << std::make_pair(first, last); + + connection.send(args); +} + +inline void wait(Connection &connection, long long numslave, long long timeout) { + connection.send("WAIT %lld %lld", numslave, timeout); +} + +// STRING commands. + +inline void append(Connection &connection, const StringView &key, const StringView &str) { + connection.send("APPEND %b %b", + key.data(), key.size(), + str.data(), str.size()); +} + +inline void bitcount(Connection &connection, + const StringView &key, + long long start, + long long end) { + connection.send("BITCOUNT %b %lld %lld", + key.data(), key.size(), + start, end); +} + +void bitop(Connection &connection, + BitOp op, + const StringView &destination, + const StringView &key); + +template +void bitop_range(Connection &connection, + BitOp op, + const StringView &destination, + Input first, + Input last); + +inline void bitpos(Connection &connection, + const StringView &key, + long long bit, + long long start, + long long end) { + connection.send("BITPOS %b %lld %lld %lld", + key.data(), key.size(), + bit, + start, + end); +} + +inline void decr(Connection &connection, const StringView &key) { + connection.send("DECR %b", key.data(), key.size()); +} + +inline void decrby(Connection &connection, const StringView &key, long long decrement) { + connection.send("DECRBY %b %lld", + key.data(), key.size(), + decrement); +} + +inline void get(Connection &connection, const StringView &key) { + connection.send("GET %b", + key.data(), key.size()); +} + +inline void getbit(Connection &connection, const StringView &key, long long offset) { + connection.send("GETBIT %b %lld", + key.data(), key.size(), + offset); +} + +inline void getrange(Connection &connection, + const StringView &key, + long long start, + long long end) { + connection.send("GETRANGE %b %lld %lld", + key.data(), key.size(), + start, + end); +} + +inline void getset(Connection &connection, + const StringView &key, + const StringView &val) { + connection.send("GETSET %b %b", + key.data(), key.size(), + val.data(), val.size()); +} + +inline void incr(Connection &connection, const StringView &key) { + connection.send("INCR %b", key.data(), key.size()); +} + +inline void incrby(Connection &connection, const StringView &key, long long increment) { + connection.send("INCRBY %b %lld", + key.data(), key.size(), + increment); +} + +inline void incrbyfloat(Connection &connection, const StringView &key, double increment) { + connection.send("INCRBYFLOAT %b %f", + key.data(), key.size(), + increment); +} + +template +inline void mget(Connection &connection, Input first, Input last) { + assert(first != last); + + CmdArgs args; + args << "MGET" << std::make_pair(first, last); + + connection.send(args); +} + +template +inline void mset(Connection &connection, Input first, Input last) { + assert(first != last); + + CmdArgs args; + args << "MSET" << std::make_pair(first, last); + + connection.send(args); +} + +template +inline void msetnx(Connection &connection, Input first, Input last) { + assert(first != last); + + CmdArgs args; + args << "MSETNX" << std::make_pair(first, last); + + connection.send(args); +} + +inline void psetex(Connection &connection, + const StringView &key, + long long ttl, + const StringView &val) { + connection.send("PSETEX %b %lld %b", + key.data(), key.size(), + ttl, + val.data(), val.size()); +} + +void set(Connection &connection, + const StringView &key, + const StringView &val, + long long ttl, + UpdateType type); + +inline void setex(Connection &connection, + const StringView &key, + long long ttl, + const StringView &val) { + connection.send("SETEX %b %lld %b", + key.data(), key.size(), + ttl, + val.data(), val.size()); +} + +inline void setnx(Connection &connection, + const StringView &key, + const StringView &val) { + connection.send("SETNX %b %b", + key.data(), key.size(), + val.data(), val.size()); +} + +inline void setrange(Connection &connection, + const StringView &key, + long long offset, + const StringView &val) { + connection.send("SETRANGE %b %lld %b", + key.data(), key.size(), + offset, + val.data(), val.size()); +} + +inline void strlen(Connection &connection, const StringView &key) { + connection.send("STRLEN %b", key.data(), key.size()); +} + +// LIST commands. + +inline void blpop(Connection &connection, const StringView &key, long long timeout) { + connection.send("BLPOP %b %lld", + key.data(), key.size(), + timeout); +} + +template +inline void blpop_range(Connection &connection, + Input first, + Input last, + long long timeout) { + assert(first != last); + + CmdArgs args; + args << "BLPOP" << std::make_pair(first, last) << timeout; + + connection.send(args); +} + +inline void brpop(Connection &connection, const StringView &key, long long timeout) { + connection.send("BRPOP %b %lld", + key.data(), key.size(), + timeout); +} + +template +inline void brpop_range(Connection &connection, + Input first, + Input last, + long long timeout) { + assert(first != last); + + CmdArgs args; + args << "BRPOP" << std::make_pair(first, last) << timeout; + + connection.send(args); +} + +inline void brpoplpush(Connection &connection, + const StringView &source, + const StringView &destination, + long long timeout) { + connection.send("BRPOPLPUSH %b %b %lld", + source.data(), source.size(), + destination.data(), destination.size(), + timeout); +} + +inline void lindex(Connection &connection, const StringView &key, long long index) { + connection.send("LINDEX %b %lld", + key.data(), key.size(), + index); +} + +void linsert(Connection &connection, + const StringView &key, + InsertPosition position, + const StringView &pivot, + const StringView &val); + +inline void llen(Connection &connection, + const StringView &key) { + connection.send("LLEN %b", key.data(), key.size()); +} + +inline void lpop(Connection &connection, const StringView &key) { + connection.send("LPOP %b", + key.data(), key.size()); +} + +inline void lpush(Connection &connection, const StringView &key, const StringView &val) { + connection.send("LPUSH %b %b", + key.data(), key.size(), + val.data(), val.size()); +} + +template +inline void lpush_range(Connection &connection, + const StringView &key, + Input first, + Input last) { + assert(first != last); + + CmdArgs args; + args << "LPUSH" << key << std::make_pair(first, last); + + connection.send(args); +} + +inline void lpushx(Connection &connection, const StringView &key, const StringView &val) { + connection.send("LPUSHX %b %b", + key.data(), key.size(), + val.data(), val.size()); +} + +inline void lrange(Connection &connection, + const StringView &key, + long long start, + long long stop) { + connection.send("LRANGE %b %lld %lld", + key.data(), key.size(), + start, + stop); +} + +inline void lrem(Connection &connection, + const StringView &key, + long long count, + const StringView &val) { + connection.send("LREM %b %lld %b", + key.data(), key.size(), + count, + val.data(), val.size()); +} + +inline void lset(Connection &connection, + const StringView &key, + long long index, + const StringView &val) { + connection.send("LSET %b %lld %b", + key.data(), key.size(), + index, + val.data(), val.size()); +} + +inline void ltrim(Connection &connection, + const StringView &key, + long long start, + long long stop) { + connection.send("LTRIM %b %lld %lld", + key.data(), key.size(), + start, + stop); +} + +inline void rpop(Connection &connection, const StringView &key) { + connection.send("RPOP %b", key.data(), key.size()); +} + +inline void rpoplpush(Connection &connection, + const StringView &source, + const StringView &destination) { + connection.send("RPOPLPUSH %b %b", + source.data(), source.size(), + destination.data(), destination.size()); +} + +inline void rpush(Connection &connection, const StringView &key, const StringView &val) { + connection.send("RPUSH %b %b", + key.data(), key.size(), + val.data(), val.size()); +} + +template +inline void rpush_range(Connection &connection, + const StringView &key, + Input first, + Input last) { + assert(first != last); + + CmdArgs args; + args << "RPUSH" << key << std::make_pair(first, last); + + connection.send(args); +} + +inline void rpushx(Connection &connection, const StringView &key, const StringView &val) { + connection.send("RPUSHX %b %b", + key.data(), key.size(), + val.data(), val.size()); +} + +// HASH commands. + +inline void hdel(Connection &connection, const StringView &key, const StringView &field) { + connection.send("HDEL %b %b", + key.data(), key.size(), + field.data(), field.size()); +} + +template +inline void hdel_range(Connection &connection, + const StringView &key, + Input first, + Input last) { + assert(first != last); + + CmdArgs args; + args << "HDEL" << key << std::make_pair(first, last); + + connection.send(args); +} + +inline void hexists(Connection &connection, const StringView &key, const StringView &field) { + connection.send("HEXISTS %b %b", + key.data(), key.size(), + field.data(), field.size()); +} + +inline void hget(Connection &connection, const StringView &key, const StringView &field) { + connection.send("HGET %b %b", + key.data(), key.size(), + field.data(), field.size()); +} + +inline void hgetall(Connection &connection, const StringView &key) { + connection.send("HGETALL %b", key.data(), key.size()); +} + +inline void hincrby(Connection &connection, + const StringView &key, + const StringView &field, + long long increment) { + connection.send("HINCRBY %b %b %lld", + key.data(), key.size(), + field.data(), field.size(), + increment); +} + +inline void hincrbyfloat(Connection &connection, + const StringView &key, + const StringView &field, + double increment) { + connection.send("HINCRBYFLOAT %b %b %f", + key.data(), key.size(), + field.data(), field.size(), + increment); +} + +inline void hkeys(Connection &connection, const StringView &key) { + connection.send("HKEYS %b", key.data(), key.size()); +} + +inline void hlen(Connection &connection, const StringView &key) { + connection.send("HLEN %b", key.data(), key.size()); +} + +template +inline void hmget(Connection &connection, + const StringView &key, + Input first, + Input last) { + assert(first != last); + + CmdArgs args; + args << "HMGET" << key << std::make_pair(first, last); + + connection.send(args); +} + +template +inline void hmset(Connection &connection, + const StringView &key, + Input first, + Input last) { + assert(first != last); + + CmdArgs args; + args << "HMSET" << key << std::make_pair(first, last); + + connection.send(args); +} + +inline void hscan(Connection &connection, + const StringView &key, + long long cursor, + const StringView &pattern, + long long count) { + connection.send("HSCAN %b %lld MATCH %b COUNT %lld", + key.data(), key.size(), + cursor, + pattern.data(), pattern.size(), + count); +} + +inline void hset(Connection &connection, + const StringView &key, + const StringView &field, + const StringView &val) { + connection.send("HSET %b %b %b", + key.data(), key.size(), + field.data(), field.size(), + val.data(), val.size()); +} + +template +void hset_range(Connection &connection, const StringView &key, Input first, Input last) { + assert(first != last); + + CmdArgs args; + args << "HSET" << key << std::make_pair(first, last); + + connection.send(args); +} + +inline void hsetnx(Connection &connection, + const StringView &key, + const StringView &field, + const StringView &val) { + connection.send("HSETNX %b %b %b", + key.data(), key.size(), + field.data(), field.size(), + val.data(), val.size()); +} + +inline void hstrlen(Connection &connection, + const StringView &key, + const StringView &field) { + connection.send("HSTRLEN %b %b", + key.data(), key.size(), + field.data(), field.size()); +} + +inline void hvals(Connection &connection, const StringView &key) { + connection.send("HVALS %b", key.data(), key.size()); +} + +// SET commands + +inline void sadd(Connection &connection, + const StringView &key, + const StringView &member) { + connection.send("SADD %b %b", + key.data(), key.size(), + member.data(), member.size()); +} + +template +inline void sadd_range(Connection &connection, + const StringView &key, + Input first, + Input last) { + assert(first != last); + + CmdArgs args; + args << "SADD" << key << std::make_pair(first, last); + + connection.send(args); +} + +inline void scard(Connection &connection, const StringView &key) { + connection.send("SCARD %b", key.data(), key.size()); +} + +template +inline void sdiff(Connection &connection, Input first, Input last) { + assert(first != last); + + CmdArgs args; + args << "SDIFF" << std::make_pair(first, last); + + connection.send(args); +} + +inline void sdiffstore(Connection &connection, + const StringView &destination, + const StringView &key) { + connection.send("SDIFFSTORE %b %b", + destination.data(), destination.size(), + key.data(), key.size()); +} + +template +inline void sdiffstore_range(Connection &connection, + const StringView &destination, + Input first, + Input last) { + assert(first != last); + + CmdArgs args; + args << "SDIFFSTORE" << destination << std::make_pair(first, last); + + connection.send(args); +} + +template +inline void sinter(Connection &connection, Input first, Input last) { + assert(first != last); + + CmdArgs args; + args << "SINTER" << std::make_pair(first, last); + + connection.send(args); +} + +inline void sinterstore(Connection &connection, + const StringView &destination, + const StringView &key) { + connection.send("SINTERSTORE %b %b", + destination.data(), destination.size(), + key.data(), key.size()); +} + +template +inline void sinterstore_range(Connection &connection, + const StringView &destination, + Input first, + Input last) { + assert(first != last); + + CmdArgs args; + args << "SINTERSTORE" << destination << std::make_pair(first, last); + + connection.send(args); +} + +inline void sismember(Connection &connection, + const StringView &key, + const StringView &member) { + connection.send("SISMEMBER %b %b", + key.data(), key.size(), + member.data(), member.size()); +} + +inline void smembers(Connection &connection, const StringView &key) { + connection.send("SMEMBERS %b", key.data(), key.size()); +} + +inline void smove(Connection &connection, + const StringView &source, + const StringView &destination, + const StringView &member) { + connection.send("SMOVE %b %b %b", + source.data(), source.size(), + destination.data(), destination.size(), + member.data(), member.size()); +} + +inline void spop(Connection &connection, const StringView &key) { + connection.send("SPOP %b", key.data(), key.size()); +} + +inline void spop_range(Connection &connection, const StringView &key, long long count) { + connection.send("SPOP %b %lld", + key.data(), key.size(), + count); +} + +inline void srandmember(Connection &connection, const StringView &key) { + connection.send("SRANDMEMBER %b", key.data(), key.size()); +} + +inline void srandmember_range(Connection &connection, + const StringView &key, + long long count) { + connection.send("SRANDMEMBER %b %lld", + key.data(), key.size(), + count); +} + +inline void srem(Connection &connection, + const StringView &key, + const StringView &member) { + connection.send("SREM %b %b", + key.data(), key.size(), + member.data(), member.size()); +} + +template +inline void srem_range(Connection &connection, + const StringView &key, + Input first, + Input last) { + assert(first != last); + + CmdArgs args; + args << "SREM" << key << std::make_pair(first, last); + + connection.send(args); +} + +inline void sscan(Connection &connection, + const StringView &key, + long long cursor, + const StringView &pattern, + long long count) { + connection.send("SSCAN %b %lld MATCH %b COUNT %lld", + key.data(), key.size(), + cursor, + pattern.data(), pattern.size(), + count); +} + +template +inline void sunion(Connection &connection, Input first, Input last) { + assert(first != last); + + CmdArgs args; + args << "SUNION" << std::make_pair(first, last); + + connection.send(args); +} + +inline void sunionstore(Connection &connection, + const StringView &destination, + const StringView &key) { + connection.send("SUNIONSTORE %b %b", + destination.data(), destination.size(), + key.data(), key.size()); +} + +template +inline void sunionstore_range(Connection &connection, + const StringView &destination, + Input first, + Input last) { + assert(first != last); + + CmdArgs args; + args << "SUNIONSTORE" << destination << std::make_pair(first, last); + + connection.send(args); +} + +// Sorted Set commands. + +inline void bzpopmax(Connection &connection, const StringView &key, long long timeout) { + connection.send("BZPOPMAX %b %lld", key.data(), key.size(), timeout); +} + +template +void bzpopmax_range(Connection &connection, + Input first, + Input last, + long long timeout) { + assert(first != last); + + CmdArgs args; + args << "BZPOPMAX" << std::make_pair(first, last) << timeout; + + connection.send(args); +} + +inline void bzpopmin(Connection &connection, const StringView &key, long long timeout) { + connection.send("BZPOPMIN %b %lld", key.data(), key.size(), timeout); +} + +template +void bzpopmin_range(Connection &connection, + Input first, + Input last, + long long timeout) { + assert(first != last); + + CmdArgs args; + args << "BZPOPMIN" << std::make_pair(first, last) << timeout; + + connection.send(args); +} + +template +void zadd_range(Connection &connection, + const StringView &key, + Input first, + Input last, + UpdateType type, + bool changed); + +inline void zadd(Connection &connection, + const StringView &key, + const StringView &member, + double score, + UpdateType type, + bool changed) { + auto tmp = {std::make_pair(member, score)}; + + zadd_range(connection, key, tmp.begin(), tmp.end(), type, changed); +} + +inline void zcard(Connection &connection, const StringView &key) { + connection.send("ZCARD %b", key.data(), key.size()); +} + +template +inline void zcount(Connection &connection, + const StringView &key, + const Interval &interval) { + connection.send("ZCOUNT %b %s %s", + key.data(), key.size(), + interval.min().c_str(), + interval.max().c_str()); +} + +inline void zincrby(Connection &connection, + const StringView &key, + double increment, + const StringView &member) { + connection.send("ZINCRBY %b %f %b", + key.data(), key.size(), + increment, + member.data(), member.size()); +} + +inline void zinterstore(Connection &connection, + const StringView &destination, + const StringView &key, + double weight) { + connection.send("ZINTERSTORE %b 1 %b WEIGHTS %f", + destination.data(), destination.size(), + key.data(), key.size(), + weight); +} + +template +void zinterstore_range(Connection &connection, + const StringView &destination, + Input first, + Input last, + Aggregation aggr); + +template +inline void zlexcount(Connection &connection, + const StringView &key, + const Interval &interval) { + const auto &min = interval.min(); + const auto &max = interval.max(); + + connection.send("ZLEXCOUNT %b %b %b", + key.data(), key.size(), + min.data(), min.size(), + max.data(), max.size()); +} + +inline void zpopmax(Connection &connection, const StringView &key, long long count) { + connection.send("ZPOPMAX %b %lld", + key.data(), key.size(), + count); +} + +inline void zpopmin(Connection &connection, const StringView &key, long long count) { + connection.send("ZPOPMIN %b %lld", + key.data(), key.size(), + count); +} + +inline void zrange(Connection &connection, + const StringView &key, + long long start, + long long stop, + bool with_scores) { + if (with_scores) { + connection.send("ZRANGE %b %lld %lld WITHSCORES", + key.data(), key.size(), + start, + stop); + } else { + connection.send("ZRANGE %b %lld %lld", + key.data(), key.size(), + start, + stop); + } +} + +template +inline void zrangebylex(Connection &connection, + const StringView &key, + const Interval &interval, + const LimitOptions &opts) { + const auto &min = interval.min(); + const auto &max = interval.max(); + + connection.send("ZRANGEBYLEX %b %b %b LIMIT %lld %lld", + key.data(), key.size(), + min.data(), min.size(), + max.data(), max.size(), + opts.offset, + opts.count); +} + +template +void zrangebyscore(Connection &connection, + const StringView &key, + const Interval &interval, + const LimitOptions &opts, + bool with_scores) { + const auto &min = interval.min(); + const auto &max = interval.max(); + + if (with_scores) { + connection.send("ZRANGEBYSCORE %b %b %b WITHSCORES LIMIT %lld %lld", + key.data(), key.size(), + min.data(), min.size(), + max.data(), max.size(), + opts.offset, + opts.count); + } else { + connection.send("ZRANGEBYSCORE %b %b %b LIMIT %lld %lld", + key.data(), key.size(), + min.data(), min.size(), + max.data(), max.size(), + opts.offset, + opts.count); + } +} + +inline void zrank(Connection &connection, + const StringView &key, + const StringView &member) { + connection.send("ZRANK %b %b", + key.data(), key.size(), + member.data(), member.size()); +} + +inline void zrem(Connection &connection, + const StringView &key, + const StringView &member) { + connection.send("ZREM %b %b", + key.data(), key.size(), + member.data(), member.size()); +} + +template +inline void zrem_range(Connection &connection, + const StringView &key, + Input first, + Input last) { + assert(first != last); + + CmdArgs args; + args << "ZREM" << key << std::make_pair(first, last); + + connection.send(args); +} + +template +inline void zremrangebylex(Connection &connection, + const StringView &key, + const Interval &interval) { + const auto &min = interval.min(); + const auto &max = interval.max(); + + connection.send("ZREMRANGEBYLEX %b %b %b", + key.data(), key.size(), + min.data(), min.size(), + max.data(), max.size()); +} + +inline void zremrangebyrank(Connection &connection, + const StringView &key, + long long start, + long long stop) { + connection.send("zremrangebyrank %b %lld %lld", + key.data(), key.size(), + start, + stop); +} + +template +inline void zremrangebyscore(Connection &connection, + const StringView &key, + const Interval &interval) { + const auto &min = interval.min(); + const auto &max = interval.max(); + + connection.send("ZREMRANGEBYSCORE %b %b %b", + key.data(), key.size(), + min.data(), min.size(), + max.data(), max.size()); +} + +inline void zrevrange(Connection &connection, + const StringView &key, + long long start, + long long stop, + bool with_scores) { + if (with_scores) { + connection.send("ZREVRANGE %b %lld %lld WITHSCORES", + key.data(), key.size(), + start, + stop); + } else { + connection.send("ZREVRANGE %b %lld %lld", + key.data(), key.size(), + start, + stop); + } +} + +template +inline void zrevrangebylex(Connection &connection, + const StringView &key, + const Interval &interval, + const LimitOptions &opts) { + const auto &min = interval.min(); + const auto &max = interval.max(); + + connection.send("ZREVRANGEBYLEX %b %b %b LIMIT %lld %lld", + key.data(), key.size(), + max.data(), max.size(), + min.data(), min.size(), + opts.offset, + opts.count); +} + +template +void zrevrangebyscore(Connection &connection, + const StringView &key, + const Interval &interval, + const LimitOptions &opts, + bool with_scores) { + const auto &min = interval.min(); + const auto &max = interval.max(); + + if (with_scores) { + connection.send("ZREVRANGEBYSCORE %b %b %b WITHSCORES LIMIT %lld %lld", + key.data(), key.size(), + max.data(), max.size(), + min.data(), min.size(), + opts.offset, + opts.count); + } else { + connection.send("ZREVRANGEBYSCORE %b %b %b LIMIT %lld %lld", + key.data(), key.size(), + max.data(), max.size(), + min.data(), min.size(), + opts.offset, + opts.count); + } +} + +inline void zrevrank(Connection &connection, + const StringView &key, + const StringView &member) { + connection.send("ZREVRANK %b %b", + key.data(), key.size(), + member.data(), member.size()); +} + +inline void zscan(Connection &connection, + const StringView &key, + long long cursor, + const StringView &pattern, + long long count) { + connection.send("ZSCAN %b %lld MATCH %b COUNT %lld", + key.data(), key.size(), + cursor, + pattern.data(), pattern.size(), + count); +} + +inline void zscore(Connection &connection, + const StringView &key, + const StringView &member) { + connection.send("ZSCORE %b %b", + key.data(), key.size(), + member.data(), member.size()); +} + +inline void zunionstore(Connection &connection, + const StringView &destination, + const StringView &key, + double weight) { + connection.send("ZUNIONSTORE %b 1 %b WEIGHTS %f", + destination.data(), destination.size(), + key.data(), key.size(), + weight); +} + +template +void zunionstore_range(Connection &connection, + const StringView &destination, + Input first, + Input last, + Aggregation aggr); + +// HYPERLOGLOG commands. + +inline void pfadd(Connection &connection, + const StringView &key, + const StringView &element) { + connection.send("PFADD %b %b", + key.data(), key.size(), + element.data(), element.size()); +} + +template +inline void pfadd_range(Connection &connection, + const StringView &key, + Input first, + Input last) { + assert(first != last); + + CmdArgs args; + args << "PFADD" << key << std::make_pair(first, last); + + connection.send(args); +} + +inline void pfcount(Connection &connection, const StringView &key) { + connection.send("PFCOUNT %b", key.data(), key.size()); +} + +template +inline void pfcount_range(Connection &connection, + Input first, + Input last) { + assert(first != last); + + CmdArgs args; + args << "PFCOUNT" << std::make_pair(first, last); + + connection.send(args); +} + +inline void pfmerge(Connection &connection, const StringView &destination, const StringView &key) { + connection.send("PFMERGE %b %b", + destination.data(), destination.size(), + key.data(), key.size()); +} + +template +inline void pfmerge_range(Connection &connection, + const StringView &destination, + Input first, + Input last) { + assert(first != last); + + CmdArgs args; + args << "PFMERGE" << destination << std::make_pair(first, last); + + connection.send(args); +} + +// GEO commands. + +inline void geoadd(Connection &connection, + const StringView &key, + const std::tuple &member) { + const auto &mem = std::get<0>(member); + + connection.send("GEOADD %b %f %f %b", + key.data(), key.size(), + std::get<1>(member), + std::get<2>(member), + mem.data(), mem.size()); +} + +template +inline void geoadd_range(Connection &connection, + const StringView &key, + Input first, + Input last) { + assert(first != last); + + CmdArgs args; + args << "GEOADD" << key; + + while (first != last) { + const auto &member = *first; + args << std::get<1>(member) << std::get<2>(member) << std::get<0>(member); + ++first; + } + + connection.send(args); +} + +void geodist(Connection &connection, + const StringView &key, + const StringView &member1, + const StringView &member2, + GeoUnit unit); + +inline void geohash(Connection &connection, const StringView &key, const StringView &member) { + connection.send("GEOHASH %b %b", + key.data(), key.size(), + member.data(), member.size()); +} + +template +inline void geohash_range(Connection &connection, + const StringView &key, + Input first, + Input last) { + assert(first != last); + + CmdArgs args; + args << "GEOHASH" << key << std::make_pair(first, last); + + connection.send(args); +} + +inline void geopos(Connection &connection, const StringView &key, const StringView &member) { + connection.send("GEOPOS %b %b", + key.data(), key.size(), + member.data(), member.size()); +} + +template +inline void geopos_range(Connection &connection, + const StringView &key, + Input first, + Input last) { + assert(first != last); + + CmdArgs args; + args << "GEOPOS" << key << std::make_pair(first, last); + + connection.send(args); +} + +void georadius(Connection &connection, + const StringView &key, + const std::pair &loc, + double radius, + GeoUnit unit, + long long count, + bool asc, + bool with_coord, + bool with_dist, + bool with_hash); + +void georadius_store(Connection &connection, + const StringView &key, + const std::pair &loc, + double radius, + GeoUnit unit, + const StringView &destination, + bool store_dist, + long long count); + +void georadiusbymember(Connection &connection, + const StringView &key, + const StringView &member, + double radius, + GeoUnit unit, + long long count, + bool asc, + bool with_coord, + bool with_dist, + bool with_hash); + +void georadiusbymember_store(Connection &connection, + const StringView &key, + const StringView &member, + double radius, + GeoUnit unit, + const StringView &destination, + bool store_dist, + long long count); + +// SCRIPTING commands. + +template +inline void eval(Connection &connection, + const StringView &script, + Keys keys_first, + Keys keys_last, + Args args_first, + Args args_last) { + CmdArgs cmd_args; + + auto keys_num = std::distance(keys_first, keys_last); + + cmd_args << "EVAL" << script << keys_num + << std::make_pair(keys_first, keys_last) + << std::make_pair(args_first, args_last); + + connection.send(cmd_args); +} + +template +inline void evalsha(Connection &connection, + const StringView &script, + Keys keys_first, + Keys keys_last, + Args args_first, + Args args_last) { + CmdArgs cmd_args; + + auto keys_num = std::distance(keys_first, keys_last); + + cmd_args << "EVALSHA" << script << keys_num + << std::make_pair(keys_first, keys_last) + << std::make_pair(args_first, args_last); + + connection.send(cmd_args); +} + +inline void script_exists(Connection &connection, const StringView &sha) { + connection.send("SCRIPT EXISTS %b", sha.data(), sha.size()); +} + +template +inline void script_exists_range(Connection &connection, Input first, Input last) { + assert(first != last); + + CmdArgs args; + args << "SCRIPT" << "EXISTS" << std::make_pair(first, last); + + connection.send(args); +} + +inline void script_flush(Connection &connection) { + connection.send("SCRIPT FLUSH"); +} + +inline void script_kill(Connection &connection) { + connection.send("SCRIPT KILL"); +} + +inline void script_load(Connection &connection, const StringView &script) { + connection.send("SCRIPT LOAD %b", script.data(), script.size()); +} + +// PUBSUB commands. + +inline void psubscribe(Connection &connection, const StringView &pattern) { + connection.send("PSUBSCRIBE %b", pattern.data(), pattern.size()); +} + +template +inline void psubscribe_range(Connection &connection, Input first, Input last) { + if (first == last) { + throw Error("PSUBSCRIBE: no key specified"); + } + + CmdArgs args; + args << "PSUBSCRIBE" << std::make_pair(first, last); + + connection.send(args); +} + +inline void publish(Connection &connection, + const StringView &channel, + const StringView &message) { + connection.send("PUBLISH %b %b", + channel.data(), channel.size(), + message.data(), message.size()); +} + +inline void punsubscribe(Connection &connection) { + connection.send("PUNSUBSCRIBE"); +} + +inline void punsubscribe(Connection &connection, const StringView &pattern) { + connection.send("PUNSUBSCRIBE %b", pattern.data(), pattern.size()); +} + +template +inline void punsubscribe_range(Connection &connection, Input first, Input last) { + if (first == last) { + throw Error("PUNSUBSCRIBE: no key specified"); + } + + CmdArgs args; + args << "PUNSUBSCRIBE" << std::make_pair(first, last); + + connection.send(args); +} + +inline void subscribe(Connection &connection, const StringView &channel) { + connection.send("SUBSCRIBE %b", channel.data(), channel.size()); +} + +template +inline void subscribe_range(Connection &connection, Input first, Input last) { + if (first == last) { + throw Error("SUBSCRIBE: no key specified"); + } + + CmdArgs args; + args << "SUBSCRIBE" << std::make_pair(first, last); + + connection.send(args); +} + +inline void unsubscribe(Connection &connection) { + connection.send("UNSUBSCRIBE"); +} + +inline void unsubscribe(Connection &connection, const StringView &channel) { + connection.send("UNSUBSCRIBE %b", channel.data(), channel.size()); +} + +template +inline void unsubscribe_range(Connection &connection, Input first, Input last) { + if (first == last) { + throw Error("UNSUBSCRIBE: no key specified"); + } + + CmdArgs args; + args << "UNSUBSCRIBE" << std::make_pair(first, last); + + connection.send(args); +} + +// Transaction commands. + +inline void discard(Connection &connection) { + connection.send("DISCARD"); +} + +inline void exec(Connection &connection) { + connection.send("EXEC"); +} + +inline void multi(Connection &connection) { + connection.send("MULTI"); +} + +inline void unwatch(Connection &connection) { + connection.send("UNWATCH"); +} + +template +inline void unwatch_range(Connection &connection, Input first, Input last) { + if (first == last) { + throw Error("UNWATCH: no key specified"); + } + + CmdArgs args; + args << "UNWATCH" << std::make_pair(first, last); + + connection.send(args); +} + +inline void watch(Connection &connection, const StringView &key) { + connection.send("WATCH %b", key.data(), key.size()); +} + +template +inline void watch_range(Connection &connection, Input first, Input last) { + if (first == last) { + throw Error("WATCH: no key specified"); + } + + CmdArgs args; + args << "WATCH" << std::make_pair(first, last); + + connection.send(args); +} + +// Stream commands. + +inline void xack(Connection &connection, + const StringView &key, + const StringView &group, + const StringView &id) { + connection.send("XACK %b %b %b", + key.data(), key.size(), + group.data(), group.size(), + id.data(), id.size()); +} + +template +void xack_range(Connection &connection, + const StringView &key, + const StringView &group, + Input first, + Input last) { + CmdArgs args; + args << "XACK" << key << group << std::make_pair(first, last); + + connection.send(args); +} + +template +void xadd_range(Connection &connection, + const StringView &key, + const StringView &id, + Input first, + Input last) { + CmdArgs args; + args << "XADD" << key << id << std::make_pair(first, last); + + connection.send(args); +} + +template +void xadd_maxlen_range(Connection &connection, + const StringView &key, + const StringView &id, + Input first, + Input last, + long long count, + bool approx) { + CmdArgs args; + args << "XADD" << key << "MAXLEN"; + + if (approx) { + args << "~"; + } + + args << count << id << std::make_pair(first, last); + + connection.send(args); +} + +inline void xclaim(Connection &connection, + const StringView &key, + const StringView &group, + const StringView &consumer, + long long min_idle_time, + const StringView &id) { + connection.send("XCLAIM %b %b %b %lld %b", + key.data(), key.size(), + group.data(), group.size(), + consumer.data(), consumer.size(), + min_idle_time, + id.data(), id.size()); +} + +template +void xclaim_range(Connection &connection, + const StringView &key, + const StringView &group, + const StringView &consumer, + long long min_idle_time, + Input first, + Input last) { + CmdArgs args; + args << "XCLAIM" << key << group << consumer << min_idle_time << std::make_pair(first, last); + + connection.send(args); +} + +inline void xdel(Connection &connection, const StringView &key, const StringView &id) { + connection.send("XDEL %b %b", key.data(), key.size(), id.data(), id.size()); +} + +template +void xdel_range(Connection &connection, const StringView &key, Input first, Input last) { + CmdArgs args; + args << "XDEL" << key << std::make_pair(first, last); + + connection.send(args); +} + +inline void xgroup_create(Connection &connection, + const StringView &key, + const StringView &group, + const StringView &id, + bool mkstream) { + CmdArgs args; + args << "XGROUP" << "CREATE" << key << group << id; + + if (mkstream) { + args << "MKSTREAM"; + } + + connection.send(args); +} + +inline void xgroup_setid(Connection &connection, + const StringView &key, + const StringView &group, + const StringView &id) { + connection.send("XGROUP SETID %b %b %b", + key.data(), key.size(), + group.data(), group.size(), + id.data(), id.size()); +} + +inline void xgroup_destroy(Connection &connection, + const StringView &key, + const StringView &group) { + connection.send("XGROUP DESTROY %b %b", + key.data(), key.size(), + group.data(), group.size()); +} + +inline void xgroup_delconsumer(Connection &connection, + const StringView &key, + const StringView &group, + const StringView &consumer) { + connection.send("XGROUP DELCONSUMER %b %b %b", + key.data(), key.size(), + group.data(), group.size(), + consumer.data(), consumer.size()); +} + +inline void xlen(Connection &connection, const StringView &key) { + connection.send("XLEN %b", key.data(), key.size()); +} + +inline void xpending(Connection &connection, const StringView &key, const StringView &group) { + connection.send("XPENDING %b %b", + key.data(), key.size(), + group.data(), group.size()); +} + +inline void xpending_detail(Connection &connection, + const StringView &key, + const StringView &group, + const StringView &start, + const StringView &end, + long long count) { + connection.send("XPENDING %b %b %b %b %lld", + key.data(), key.size(), + group.data(), group.size(), + start.data(), start.size(), + end.data(), end.size(), + count); +} + +inline void xpending_per_consumer(Connection &connection, + const StringView &key, + const StringView &group, + const StringView &start, + const StringView &end, + long long count, + const StringView &consumer) { + connection.send("XPENDING %b %b %b %b %lld %b", + key.data(), key.size(), + group.data(), group.size(), + start.data(), start.size(), + end.data(), end.size(), + count, + consumer.data(), consumer.size()); +} + +inline void xrange(Connection &connection, + const StringView &key, + const StringView &start, + const StringView &end) { + connection.send("XRANGE %b %b %b", + key.data(), key.size(), + start.data(), start.size(), + end.data(), end.size()); +} + +inline void xrange_count(Connection &connection, + const StringView &key, + const StringView &start, + const StringView &end, + long long count) { + connection.send("XRANGE %b %b %b COUNT %lld", + key.data(), key.size(), + start.data(), start.size(), + end.data(), end.size(), + count); +} + +inline void xread(Connection &connection, + const StringView &key, + const StringView &id, + long long count) { + connection.send("XREAD COUNT %lld STREAMS %b %b", + count, + key.data(), key.size(), + id.data(), id.size()); +} + +template +void xread_range(Connection &connection, Input first, Input last, long long count) { + CmdArgs args; + args << "XREAD" << "COUNT" << count << "STREAMS"; + + for (auto iter = first; iter != last; ++iter) { + args << iter->first; + } + + for (auto iter = first; iter != last; ++iter) { + args << iter->second; + } + + connection.send(args); +} + +inline void xread_block(Connection &connection, + const StringView &key, + const StringView &id, + long long timeout, + long long count) { + connection.send("XREAD COUNT %lld BLOCK %lld STREAMS %b %b", + count, + timeout, + key.data(), key.size(), + id.data(), id.size()); +} + +template +void xread_block_range(Connection &connection, + Input first, + Input last, + long long timeout, + long long count) { + CmdArgs args; + args << "XREAD" << "COUNT" << count << "BLOCK" << timeout << "STREAMS"; + + for (auto iter = first; iter != last; ++iter) { + args << iter->first; + } + + for (auto iter = first; iter != last; ++iter) { + args << iter->second; + } + + connection.send(args); +} + +inline void xreadgroup(Connection &connection, + const StringView &group, + const StringView &consumer, + const StringView &key, + const StringView &id, + long long count, + bool noack) { + CmdArgs args; + args << "XREADGROUP" << "GROUP" << group << consumer << "COUNT" << count; + + if (noack) { + args << "NOACK"; + } + + args << "STREAMS" << key << id; + + connection.send(args); +} + +template +void xreadgroup_range(Connection &connection, + const StringView &group, + const StringView &consumer, + Input first, + Input last, + long long count, + bool noack) { + CmdArgs args; + args << "XREADGROUP" << "GROUP" << group << consumer << "COUNT" << count; + + if (noack) { + args << "NOACK"; + } + + args << "STREAMS"; + + for (auto iter = first; iter != last; ++iter) { + args << iter->first; + } + + for (auto iter = first; iter != last; ++iter) { + args << iter->second; + } + + connection.send(args); +} + +inline void xreadgroup_block(Connection &connection, + const StringView &group, + const StringView &consumer, + const StringView &key, + const StringView &id, + long long timeout, + long long count, + bool noack) { + CmdArgs args; + args << "XREADGROUP" << "GROUP" << group << consumer + << "COUNT" << count << "BLOCK" << timeout; + + if (noack) { + args << "NOACK"; + } + + args << "STREAMS" << key << id; + + connection.send(args); +} + +template +void xreadgroup_block_range(Connection &connection, + const StringView &group, + const StringView &consumer, + Input first, + Input last, + long long timeout, + long long count, + bool noack) { + CmdArgs args; + args << "XREADGROUP" << "GROUP" << group << consumer + << "COUNT" << count << "BLOCK" << timeout; + + if (noack) { + args << "NOACK"; + } + + args << "STREAMS"; + + for (auto iter = first; iter != last; ++iter) { + args << iter->first; + } + + for (auto iter = first; iter != last; ++iter) { + args << iter->second; + } + + connection.send(args); +} + +inline void xrevrange(Connection &connection, + const StringView &key, + const StringView &end, + const StringView &start) { + connection.send("XREVRANGE %b %b %b", + key.data(), key.size(), + end.data(), end.size(), + start.data(), start.size()); +} + +inline void xrevrange_count(Connection &connection, + const StringView &key, + const StringView &end, + const StringView &start, + long long count) { + connection.send("XREVRANGE %b %b %b COUNT %lld", + key.data(), key.size(), + end.data(), end.size(), + start.data(), start.size(), + count); +} + +void xtrim(Connection &connection, const StringView &key, long long count, bool approx); + +namespace detail { + +void set_bitop(CmdArgs &args, BitOp op); + +void set_update_type(CmdArgs &args, UpdateType type); + +void set_aggregation_type(CmdArgs &args, Aggregation type); + +template +void zinterstore(std::false_type, + Connection &connection, + const StringView &destination, + Input first, + Input last, + Aggregation aggr) { + CmdArgs args; + args << "ZINTERSTORE" << destination << std::distance(first, last) + << std::make_pair(first, last); + + set_aggregation_type(args, aggr); + + connection.send(args); +} + +template +void zinterstore(std::true_type, + Connection &connection, + const StringView &destination, + Input first, + Input last, + Aggregation aggr) { + CmdArgs args; + args << "ZINTERSTORE" << destination << std::distance(first, last); + + for (auto iter = first; iter != last; ++iter) { + args << iter->first; + } + + args << "WEIGHTS"; + + for (auto iter = first; iter != last; ++iter) { + args << iter->second; + } + + set_aggregation_type(args, aggr); + + connection.send(args); +} + +template +void zunionstore(std::false_type, + Connection &connection, + const StringView &destination, + Input first, + Input last, + Aggregation aggr) { + CmdArgs args; + args << "ZUNIONSTORE" << destination << std::distance(first, last) + << std::make_pair(first, last); + + set_aggregation_type(args, aggr); + + connection.send(args); +} + +template +void zunionstore(std::true_type, + Connection &connection, + const StringView &destination, + Input first, + Input last, + Aggregation aggr) { + CmdArgs args; + args << "ZUNIONSTORE" << destination << std::distance(first, last); + + for (auto iter = first; iter != last; ++iter) { + args << iter->first; + } + + args << "WEIGHTS"; + + for (auto iter = first; iter != last; ++iter) { + args << iter->second; + } + + set_aggregation_type(args, aggr); + + connection.send(args); +} + +void set_geo_unit(CmdArgs &args, GeoUnit unit); + +void set_georadius_store_parameters(CmdArgs &args, + double radius, + GeoUnit unit, + const StringView &destination, + bool store_dist, + long long count); + +void set_georadius_parameters(CmdArgs &args, + double radius, + GeoUnit unit, + long long count, + bool asc, + bool with_coord, + bool with_dist, + bool with_hash); + +} + +} + +} + +} + +namespace sw { + +namespace redis { + +namespace cmd { + +template +void bitop_range(Connection &connection, + BitOp op, + const StringView &destination, + Input first, + Input last) { + assert(first != last); + + CmdArgs args; + + detail::set_bitop(args, op); + + args << destination << std::make_pair(first, last); + + connection.send(args); +} + +template +void zadd_range(Connection &connection, + const StringView &key, + Input first, + Input last, + UpdateType type, + bool changed) { + assert(first != last); + + CmdArgs args; + + args << "ZADD" << key; + + detail::set_update_type(args, type); + + if (changed) { + args << "CH"; + } + + while (first != last) { + // Swap the pair to pair. + args << first->second << first->first; + ++first; + } + + connection.send(args); +} + +template +void zinterstore_range(Connection &connection, + const StringView &destination, + Input first, + Input last, + Aggregation aggr) { + assert(first != last); + + detail::zinterstore(typename IsKvPairIter::type(), + connection, + destination, + first, + last, + aggr); +} + +template +void zunionstore_range(Connection &connection, + const StringView &destination, + Input first, + Input last, + Aggregation aggr) { + assert(first != last); + + detail::zunionstore(typename IsKvPairIter::type(), + connection, + destination, + first, + last, + aggr); +} + +} + +} + +} + +#endif // end SEWENEW_REDISPLUSPLUS_COMMAND_H diff --git a/ext/redis-plus-plus-1.3.3/install/ubuntu22.04/arm64/include/sw/redis++/command_args.h b/ext/redis-plus-plus-1.3.3/install/ubuntu22.04/arm64/include/sw/redis++/command_args.h new file mode 100644 index 000000000..0beb71e5c --- /dev/null +++ b/ext/redis-plus-plus-1.3.3/install/ubuntu22.04/arm64/include/sw/redis++/command_args.h @@ -0,0 +1,180 @@ +/************************************************************************** + Copyright (c) 2017 sewenew + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + *************************************************************************/ + +#ifndef SEWENEW_REDISPLUSPLUS_COMMAND_ARGS_H +#define SEWENEW_REDISPLUSPLUS_COMMAND_ARGS_H + +#include +#include +#include +#include +#include "utils.h" + +namespace sw { + +namespace redis { + +class CmdArgs { +public: + template + CmdArgs& append(Arg &&arg); + + template + CmdArgs& append(Arg &&arg, Args &&...args); + + // All overloads of operator<< are for internal use only. + CmdArgs& operator<<(const StringView &arg); + + template ::type>::value, + int>::type = 0> + CmdArgs& operator<<(T &&arg); + + template + CmdArgs& operator<<(const std::pair &range); + + template + auto operator<<(const std::tuple &) -> + typename std::enable_if::type { + return *this; + } + + template + auto operator<<(const std::tuple &arg) -> + typename std::enable_if::type; + + const char** argv() { + return _argv.data(); + } + + const std::size_t* argv_len() { + return _argv_len.data(); + } + + std::size_t size() const { + return _argv.size(); + } + +private: + // Deep copy. + CmdArgs& _append(std::string arg); + + // Shallow copy. + CmdArgs& _append(const StringView &arg); + + // Shallow copy. + CmdArgs& _append(const char *arg); + + template ::type>::value, + int>::type = 0> + CmdArgs& _append(T &&arg) { + return operator<<(std::forward(arg)); + } + + template + CmdArgs& _append(std::true_type, const std::pair &range); + + template + CmdArgs& _append(std::false_type, const std::pair &range); + + std::vector _argv; + std::vector _argv_len; + + std::list _args; +}; + +template +inline CmdArgs& CmdArgs::append(Arg &&arg) { + return _append(std::forward(arg)); +} + +template +inline CmdArgs& CmdArgs::append(Arg &&arg, Args &&...args) { + _append(std::forward(arg)); + + return append(std::forward(args)...); +} + +inline CmdArgs& CmdArgs::operator<<(const StringView &arg) { + _argv.push_back(arg.data()); + _argv_len.push_back(arg.size()); + + return *this; +} + +template +inline CmdArgs& CmdArgs::operator<<(const std::pair &range) { + return _append(IsKvPair())>::type>(), range); +} + +template ::type>::value, + int>::type> +inline CmdArgs& CmdArgs::operator<<(T &&arg) { + return _append(std::to_string(std::forward(arg))); +} + +template +auto CmdArgs::operator<<(const std::tuple &arg) -> + typename std::enable_if::type { + operator<<(std::get(arg)); + + return operator<<(arg); +} + +inline CmdArgs& CmdArgs::_append(std::string arg) { + _args.push_back(std::move(arg)); + return operator<<(_args.back()); +} + +inline CmdArgs& CmdArgs::_append(const StringView &arg) { + return operator<<(arg); +} + +inline CmdArgs& CmdArgs::_append(const char *arg) { + return operator<<(arg); +} + +template +CmdArgs& CmdArgs::_append(std::false_type, const std::pair &range) { + auto first = range.first; + auto last = range.second; + while (first != last) { + *this << *first; + ++first; + } + + return *this; +} + +template +CmdArgs& CmdArgs::_append(std::true_type, const std::pair &range) { + auto first = range.first; + auto last = range.second; + while (first != last) { + *this << first->first << first->second; + ++first; + } + + return *this; +} + +} + +} + +#endif // end SEWENEW_REDISPLUSPLUS_COMMAND_ARGS_H diff --git a/ext/redis-plus-plus-1.3.3/install/ubuntu22.04/arm64/include/sw/redis++/command_options.h b/ext/redis-plus-plus-1.3.3/install/ubuntu22.04/arm64/include/sw/redis++/command_options.h new file mode 100644 index 000000000..ca766c086 --- /dev/null +++ b/ext/redis-plus-plus-1.3.3/install/ubuntu22.04/arm64/include/sw/redis++/command_options.h @@ -0,0 +1,211 @@ +/************************************************************************** + Copyright (c) 2017 sewenew + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + *************************************************************************/ + +#ifndef SEWENEW_REDISPLUSPLUS_COMMAND_OPTIONS_H +#define SEWENEW_REDISPLUSPLUS_COMMAND_OPTIONS_H + +#include +#include "utils.h" + +namespace sw { + +namespace redis { + +enum class UpdateType { + EXIST, + NOT_EXIST, + ALWAYS +}; + +enum class InsertPosition { + BEFORE, + AFTER +}; + +enum class BoundType { + CLOSED, + OPEN, + LEFT_OPEN, + RIGHT_OPEN +}; + +// (-inf, +inf) +template +class UnboundedInterval; + +// [min, max], (min, max), (min, max], [min, max) +template +class BoundedInterval; + +// [min, +inf), (min, +inf) +template +class LeftBoundedInterval; + +// (-inf, max], (-inf, max) +template +class RightBoundedInterval; + +template <> +class UnboundedInterval { +public: + const std::string& min() const; + + const std::string& max() const; +}; + +template <> +class BoundedInterval { +public: + BoundedInterval(double min, double max, BoundType type); + + const std::string& min() const { + return _min; + } + + const std::string& max() const { + return _max; + } + +private: + std::string _min; + std::string _max; +}; + +template <> +class LeftBoundedInterval { +public: + LeftBoundedInterval(double min, BoundType type); + + const std::string& min() const { + return _min; + } + + const std::string& max() const; + +private: + std::string _min; +}; + +template <> +class RightBoundedInterval { +public: + RightBoundedInterval(double max, BoundType type); + + const std::string& min() const; + + const std::string& max() const { + return _max; + } + +private: + std::string _max; +}; + +template <> +class UnboundedInterval { +public: + const std::string& min() const; + + const std::string& max() const; +}; + +template <> +class BoundedInterval { +public: + BoundedInterval(const std::string &min, const std::string &max, BoundType type); + + const std::string& min() const { + return _min; + } + + const std::string& max() const { + return _max; + } + +private: + std::string _min; + std::string _max; +}; + +template <> +class LeftBoundedInterval { +public: + LeftBoundedInterval(const std::string &min, BoundType type); + + const std::string& min() const { + return _min; + } + + const std::string& max() const; + +private: + std::string _min; +}; + +template <> +class RightBoundedInterval { +public: + RightBoundedInterval(const std::string &max, BoundType type); + + const std::string& min() const; + + const std::string& max() const { + return _max; + } + +private: + std::string _max; +}; + +struct LimitOptions { + long long offset = 0; + long long count = -1; +}; + +enum class Aggregation { + SUM, + MIN, + MAX +}; + +enum class BitOp { + AND, + OR, + XOR, + NOT +}; + +enum class GeoUnit { + M, + KM, + MI, + FT +}; + +template +struct WithCoord : TupleWithType, T> {}; + +template +struct WithDist : TupleWithType {}; + +template +struct WithHash : TupleWithType {}; + +} + +} + +#endif // end SEWENEW_REDISPLUSPLUS_COMMAND_OPTIONS_H diff --git a/ext/redis-plus-plus-1.3.3/install/ubuntu22.04/arm64/include/sw/redis++/connection.h b/ext/redis-plus-plus-1.3.3/install/ubuntu22.04/arm64/include/sw/redis++/connection.h new file mode 100644 index 000000000..340375561 --- /dev/null +++ b/ext/redis-plus-plus-1.3.3/install/ubuntu22.04/arm64/include/sw/redis++/connection.h @@ -0,0 +1,237 @@ +/************************************************************************** + Copyright (c) 2017 sewenew + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + *************************************************************************/ + +#ifndef SEWENEW_REDISPLUSPLUS_CONNECTION_H +#define SEWENEW_REDISPLUSPLUS_CONNECTION_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include "errors.h" +#include "reply.h" +#include "utils.h" +#include "tls.h" + +namespace sw { + +namespace redis { + +enum class ConnectionType { + TCP = 0, + UNIX +}; + +struct ConnectionOptions { +public: + ConnectionOptions() = default; + + explicit ConnectionOptions(const std::string &uri); + + ConnectionOptions(const ConnectionOptions &) = default; + ConnectionOptions& operator=(const ConnectionOptions &) = default; + + ConnectionOptions(ConnectionOptions &&) = default; + ConnectionOptions& operator=(ConnectionOptions &&) = default; + + ~ConnectionOptions() = default; + + ConnectionType type = ConnectionType::TCP; + + std::string host; + + int port = 6379; + + std::string path; + + std::string user = "default"; + + std::string password; + + int db = 0; + + bool keep_alive = false; + + std::chrono::milliseconds connect_timeout{0}; + + std::chrono::milliseconds socket_timeout{0}; + + tls::TlsOptions tls; + + // `readonly` is only used for reading from a slave node in Redis Cluster mode. + // Client code should never manually set/get it. This member might be removed in the future. + bool readonly = false; + +private: + ConnectionOptions _parse_uri(const std::string &uri) const; + + auto _split_uri(const std::string &uri) const + -> std::tuple; + + auto _split_path(const std::string &path) const + -> std::tuple; + + void _parse_parameters(const std::string ¶meter_string, + ConnectionOptions &opts) const; + + void _set_option(const std::string &key, const std::string &val, ConnectionOptions &opts) const; + + bool _parse_bool_option(const std::string &str) const; + + std::chrono::milliseconds _parse_timeout_option(const std::string &str) const; + + std::vector _split(const std::string &str, const std::string &delimiter) const; + + void _set_auth_opts(const std::string &auth, ConnectionOptions &opts) const; + + void _set_tcp_opts(const std::string &path, ConnectionOptions &opts) const; + + void _set_unix_opts(const std::string &path, ConnectionOptions &opts) const; +}; + +class CmdArgs; + +class Connection { +public: + explicit Connection(const ConnectionOptions &opts); + + Connection(const Connection &) = delete; + Connection& operator=(const Connection &) = delete; + + Connection(Connection &&) = default; + Connection& operator=(Connection &&) = default; + + ~Connection() = default; + + // Check if the connection is broken. Client needs to do this check + // before sending some command to the connection. If it's broken, + // client needs to reconnect it. + bool broken() const noexcept { + return _ctx->err != REDIS_OK; + } + + void reset() noexcept { + _ctx->err = 0; + } + + void invalidate() noexcept { + _ctx->err = REDIS_ERR; + } + + void reconnect(); + + auto create_time() const + -> std::chrono::time_point { + return _create_time; + } + + auto last_active() const + -> std::chrono::time_point { + return _last_active; + } + + template + void send(const char *format, Args &&...args); + + void send(int argc, const char **argv, const std::size_t *argv_len); + + void send(CmdArgs &args); + + ReplyUPtr recv(bool handle_error_reply = true); + + const ConnectionOptions& options() const { + return _opts; + } + + friend void swap(Connection &lhs, Connection &rhs) noexcept; + +private: + class Connector; + + struct ContextDeleter { + void operator()(redisContext *context) const { + if (context != nullptr) { + redisFree(context); + } + }; + }; + + using ContextUPtr = std::unique_ptr; + + void _set_options(); + + void _auth(); + + void _select_db(); + + void _enable_readonly(); + + redisContext* _context(); + + ContextUPtr _ctx; + + // The time that the connection is created. + std::chrono::time_point _create_time{}; + + // The time that the connection is created or the time that + // the connection is recently used, i.e. `_context()` is called. + std::chrono::time_point _last_active{}; + + ConnectionOptions _opts; + + // TODO: define _tls_ctx before _ctx + tls::TlsContextUPtr _tls_ctx; +}; + +using ConnectionSPtr = std::shared_ptr; + +enum class Role { + MASTER, + SLAVE +}; + +// Inline implementaions. + +template +inline void Connection::send(const char *format, Args &&...args) { + auto ctx = _context(); + + assert(ctx != nullptr); + + if (redisAppendCommand(ctx, + format, + std::forward(args)...) != REDIS_OK) { + throw_error(*ctx, "Failed to send command"); + } + + assert(!broken()); +} + +inline redisContext* Connection::_context() { + _last_active = std::chrono::steady_clock::now(); + + return _ctx.get(); +} + +} + +} + +#endif // end SEWENEW_REDISPLUSPLUS_CONNECTION_H diff --git a/ext/redis-plus-plus-1.3.3/install/ubuntu22.04/arm64/include/sw/redis++/connection_pool.h b/ext/redis-plus-plus-1.3.3/install/ubuntu22.04/arm64/include/sw/redis++/connection_pool.h new file mode 100644 index 000000000..30ba5daa2 --- /dev/null +++ b/ext/redis-plus-plus-1.3.3/install/ubuntu22.04/arm64/include/sw/redis++/connection_pool.h @@ -0,0 +1,182 @@ +/************************************************************************** + Copyright (c) 2017 sewenew + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + *************************************************************************/ + +#ifndef SEWENEW_REDISPLUSPLUS_CONNECTION_POOL_H +#define SEWENEW_REDISPLUSPLUS_CONNECTION_POOL_H + +#include +#include +#include +#include +#include +#include +#include "connection.h" +#include "sentinel.h" + +namespace sw { + +namespace redis { + +struct ConnectionPoolOptions { + // Max number of connections, including both in-use and idle ones. + std::size_t size = 1; + + // Max time to wait for a connection. 0ms means client waits forever. + std::chrono::milliseconds wait_timeout{0}; + + // Max lifetime of a connection. 0ms means we never expire the connection. + std::chrono::milliseconds connection_lifetime{0}; + + // Max idle time of a connection. 0ms means we never expire the connection. + std::chrono::milliseconds connection_idle_time{0}; +}; + +class ConnectionPool { +public: + ConnectionPool(const ConnectionPoolOptions &pool_opts, + const ConnectionOptions &connection_opts); + + ConnectionPool(SimpleSentinel sentinel, + const ConnectionPoolOptions &pool_opts, + const ConnectionOptions &connection_opts); + + ConnectionPool() = default; + + ConnectionPool(ConnectionPool &&that); + ConnectionPool& operator=(ConnectionPool &&that); + + ConnectionPool(const ConnectionPool &) = delete; + ConnectionPool& operator=(const ConnectionPool &) = delete; + + ~ConnectionPool() = default; + + // Fetch a connection from pool. + Connection fetch(); + + ConnectionOptions connection_options(); + + void release(Connection connection); + + // Create a new connection. + Connection create(); + + ConnectionPool clone(); + +private: + void _move(ConnectionPool &&that); + + // NOT thread-safe + Connection _create(); + + Connection _create(SimpleSentinel &sentinel, const ConnectionOptions &opts, bool locked); + + Connection _fetch(); + + void _wait_for_connection(std::unique_lock &lock); + + bool _need_reconnect(const Connection &connection, + const std::chrono::milliseconds &connection_lifetime, + const std::chrono::milliseconds &connection_idle_time) const; + + void _update_connection_opts(const std::string &host, int port) { + _opts.host = host; + _opts.port = port; + } + + bool _role_changed(const ConnectionOptions &opts) const { + return opts.port != _opts.port || opts.host != _opts.host; + } + + ConnectionOptions _opts; + + ConnectionPoolOptions _pool_opts; + + std::deque _pool; + + std::size_t _used_connections = 0; + + std::mutex _mutex; + + std::condition_variable _cv; + + SimpleSentinel _sentinel; +}; + +using ConnectionPoolSPtr = std::shared_ptr; + +class SafeConnection { +public: + explicit SafeConnection(ConnectionPool &pool) : _pool(pool), _connection(_pool.fetch()) { + assert(!_connection.broken()); + } + + SafeConnection(const SafeConnection &) = delete; + SafeConnection& operator=(const SafeConnection &) = delete; + + SafeConnection(SafeConnection &&) = delete; + SafeConnection& operator=(SafeConnection &&) = delete; + + ~SafeConnection() { + _pool.release(std::move(_connection)); + } + + Connection& connection() { + return _connection; + } + +private: + ConnectionPool &_pool; + Connection _connection; +}; + +// NOTE: This class is similar to `SafeConnection`. +// The difference is that `SafeConnection` tries to avoid copying a std::shared_ptr. +class GuardedConnection { +public: + explicit GuardedConnection(const ConnectionPoolSPtr &pool) : _pool(pool), + _connection(_pool->fetch()) { + assert(!_connection.broken()); + } + + GuardedConnection(const GuardedConnection &) = delete; + GuardedConnection& operator=(const GuardedConnection &) = delete; + + GuardedConnection(GuardedConnection &&) = default; + GuardedConnection& operator=(GuardedConnection &&) = default; + + ~GuardedConnection() { + // If `GuardedConnection` has been moved, `_pool` will be nullptr. + if (_pool) { + _pool->release(std::move(_connection)); + } + } + + Connection& connection() { + return _connection; + } + +private: + ConnectionPoolSPtr _pool; + Connection _connection; +}; + +using GuardedConnectionSPtr = std::shared_ptr; + +} + +} + +#endif // end SEWENEW_REDISPLUSPLUS_CONNECTION_POOL_H diff --git a/ext/redis-plus-plus-1.3.3/install/ubuntu22.04/arm64/include/sw/redis++/cxx_utils.h b/ext/redis-plus-plus-1.3.3/install/ubuntu22.04/arm64/include/sw/redis++/cxx_utils.h new file mode 100644 index 000000000..dce51abe9 --- /dev/null +++ b/ext/redis-plus-plus-1.3.3/install/ubuntu22.04/arm64/include/sw/redis++/cxx_utils.h @@ -0,0 +1,46 @@ +/************************************************************************** + Copyright (c) 2021 sewenew + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + *************************************************************************/ + +#ifndef SEWENEW_REDISPLUSPLUS_CXX_UTILS_H +#define SEWENEW_REDISPLUSPLUS_CXX_UTILS_H + +#include +#include +#include + +#define REDIS_PLUS_PLUS_HAS_OPTIONAL + +#define REDIS_PLUS_PLUS_HAS_VARIANT + +namespace sw { + +namespace redis { + +using StringView = std::string_view; + +template +using Optional = std::optional; + +template +using Variant = std::variant; + +using Monostate = std::monostate; + +} + +} + +#endif // end SEWENEW_REDISPLUSPLUS_CXX_UTILS_H diff --git a/ext/redis-plus-plus-1.3.3/install/ubuntu22.04/arm64/include/sw/redis++/errors.h b/ext/redis-plus-plus-1.3.3/install/ubuntu22.04/arm64/include/sw/redis++/errors.h new file mode 100644 index 000000000..7cc19d2f1 --- /dev/null +++ b/ext/redis-plus-plus-1.3.3/install/ubuntu22.04/arm64/include/sw/redis++/errors.h @@ -0,0 +1,166 @@ +/************************************************************************** + Copyright (c) 2017 sewenew + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + *************************************************************************/ + +#ifndef SEWENEW_REDISPLUSPLUS_ERRORS_H +#define SEWENEW_REDISPLUSPLUS_ERRORS_H + +#include +#include +#include + +namespace sw { + +namespace redis { + +enum ReplyErrorType { + ERR, + MOVED, + ASK +}; + +class Error : public std::exception { +public: + explicit Error(const std::string &msg) : _msg(msg) {} + + Error(const Error &) = default; + Error& operator=(const Error &) = default; + + Error(Error &&) = default; + Error& operator=(Error &&) = default; + + virtual ~Error() override = default; + + virtual const char* what() const noexcept override { + return _msg.data(); + } + +private: + std::string _msg; +}; + +class IoError : public Error { +public: + explicit IoError(const std::string &msg) : Error(msg) {} + + IoError(const IoError &) = default; + IoError& operator=(const IoError &) = default; + + IoError(IoError &&) = default; + IoError& operator=(IoError &&) = default; + + virtual ~IoError() override = default; +}; + +class TimeoutError : public IoError { +public: + explicit TimeoutError(const std::string &msg) : IoError(msg) {} + + TimeoutError(const TimeoutError &) = default; + TimeoutError& operator=(const TimeoutError &) = default; + + TimeoutError(TimeoutError &&) = default; + TimeoutError& operator=(TimeoutError &&) = default; + + virtual ~TimeoutError() override = default; +}; + +class ClosedError : public Error { +public: + explicit ClosedError(const std::string &msg) : Error(msg) {} + + ClosedError(const ClosedError &) = default; + ClosedError& operator=(const ClosedError &) = default; + + ClosedError(ClosedError &&) = default; + ClosedError& operator=(ClosedError &&) = default; + + virtual ~ClosedError() override = default; +}; + +class ProtoError : public Error { +public: + explicit ProtoError(const std::string &msg) : Error(msg) {} + + ProtoError(const ProtoError &) = default; + ProtoError& operator=(const ProtoError &) = default; + + ProtoError(ProtoError &&) = default; + ProtoError& operator=(ProtoError &&) = default; + + virtual ~ProtoError() override = default; +}; + +class OomError : public Error { +public: + explicit OomError(const std::string &msg) : Error(msg) {} + + OomError(const OomError &) = default; + OomError& operator=(const OomError &) = default; + + OomError(OomError &&) = default; + OomError& operator=(OomError &&) = default; + + virtual ~OomError() override = default; +}; + +class ReplyError : public Error { +public: + explicit ReplyError(const std::string &msg) : Error(msg) {} + + ReplyError(const ReplyError &) = default; + ReplyError& operator=(const ReplyError &) = default; + + ReplyError(ReplyError &&) = default; + ReplyError& operator=(ReplyError &&) = default; + + virtual ~ReplyError() override = default; +}; + +class WatchError : public Error { +public: + explicit WatchError() : Error("Watched key has been modified") {} + + WatchError(const WatchError &) = default; + WatchError& operator=(const WatchError &) = default; + + WatchError(WatchError &&) = default; + WatchError& operator=(WatchError &&) = default; + + virtual ~WatchError() override = default; +}; + + +// MovedError and AskError are defined in shards.h +class MovedError; + +class AskError; + +void throw_error(const redisContext &context, const std::string &err_info); + +void throw_error(const redisReply &reply); + +template +inline void range_check(const char *cmd, Input first, Input last) { + if (first == last) { + throw Error(std::string(cmd) + ": no key specified"); + } +} + +} + +} + +#endif // end SEWENEW_REDISPLUSPLUS_ERRORS_H diff --git a/ext/redis-plus-plus-1.3.3/install/ubuntu22.04/arm64/include/sw/redis++/pipeline.h b/ext/redis-plus-plus-1.3.3/install/ubuntu22.04/arm64/include/sw/redis++/pipeline.h new file mode 100644 index 000000000..52b01253f --- /dev/null +++ b/ext/redis-plus-plus-1.3.3/install/ubuntu22.04/arm64/include/sw/redis++/pipeline.h @@ -0,0 +1,49 @@ +/************************************************************************** + Copyright (c) 2017 sewenew + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + *************************************************************************/ + +#ifndef SEWENEW_REDISPLUSPLUS_PIPELINE_H +#define SEWENEW_REDISPLUSPLUS_PIPELINE_H + +#include +#include +#include "connection.h" + +namespace sw { + +namespace redis { + +class PipelineImpl { +public: + template + void command(Connection &connection, Cmd cmd, Args &&...args) { + assert(!connection.broken()); + + cmd(connection, std::forward(args)...); + } + + std::vector exec(Connection &connection, std::size_t cmd_num); + + void discard(Connection &connection, std::size_t /*cmd_num*/) { + // Reconnect to Redis to discard all commands. + connection.reconnect(); + } +}; + +} + +} + +#endif // end SEWENEW_REDISPLUSPLUS_PIPELINE_H diff --git a/ext/redis-plus-plus-1.3.3/install/ubuntu22.04/arm64/include/sw/redis++/queued_redis.h b/ext/redis-plus-plus-1.3.3/install/ubuntu22.04/arm64/include/sw/redis++/queued_redis.h new file mode 100644 index 000000000..e663c7423 --- /dev/null +++ b/ext/redis-plus-plus-1.3.3/install/ubuntu22.04/arm64/include/sw/redis++/queued_redis.h @@ -0,0 +1,2013 @@ +/************************************************************************** + Copyright (c) 2017 sewenew + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + *************************************************************************/ + +#ifndef SEWENEW_REDISPLUSPLUS_QUEUED_REDIS_H +#define SEWENEW_REDISPLUSPLUS_QUEUED_REDIS_H + +#include +#include +#include +#include +#include +#include "connection.h" +#include "connection_pool.h" +#include "utils.h" +#include "reply.h" +#include "command.h" +#include "redis.h" +#include "errors.h" + +namespace sw { + +namespace redis { + +class QueuedReplies; + +// If any command throws, QueuedRedis resets the connection, and becomes invalid. +// In this case, the only thing we can do is to destory the QueuedRedis object. +template +class QueuedRedis { +public: + QueuedRedis(QueuedRedis &&) = default; + QueuedRedis& operator=(QueuedRedis &&) = default; + + // When it destructs, the underlying *Connection* will be closed or return to pool, + // and any command that has NOT been executed will be ignored. + ~QueuedRedis(); + + Redis redis(); + + template + auto command(Cmd cmd, Args &&...args) + -> typename std::enable_if::value, + QueuedRedis&>::type; + + template + QueuedRedis& command(const StringView &cmd_name, Args &&...args); + + template + auto command(Input first, Input last) + -> typename std::enable_if::value, QueuedRedis&>::type; + + QueuedReplies exec(); + + void discard(); + + // CONNECTION commands. + + QueuedRedis& auth(const StringView &password) { + return command(cmd::auth, password); + } + + QueuedRedis& auth(const StringView &user, const StringView &password) { + return command( + cmd::auth, user, password); + } + + QueuedRedis& echo(const StringView &msg) { + return command(cmd::echo, msg); + } + + QueuedRedis& ping() { + return command(cmd::ping); + } + + QueuedRedis& ping(const StringView &msg) { + return command(cmd::ping, msg); + } + + // We DO NOT support the QUIT command. See *Redis::quit* doc for details. + // + // QueuedRedis& quit(); + + QueuedRedis& select(long long idx) { + return command(cmd::select, idx); + } + + QueuedRedis& swapdb(long long idx1, long long idx2) { + return command(cmd::swapdb, idx1, idx2); + } + + // SERVER commands. + + QueuedRedis& bgrewriteaof() { + return command(cmd::bgrewriteaof); + } + + QueuedRedis& bgsave() { + return command(cmd::bgsave); + } + + QueuedRedis& dbsize() { + return command(cmd::dbsize); + } + + QueuedRedis& flushall(bool async = false) { + return command(cmd::flushall, async); + } + + QueuedRedis& flushdb(bool async = false) { + return command(cmd::flushdb, async); + } + + QueuedRedis& info() { + return command(cmd::info); + } + + QueuedRedis& info(const StringView §ion) { + return command(cmd::info, section); + } + + QueuedRedis& lastsave() { + return command(cmd::lastsave); + } + + QueuedRedis& save() { + return command(cmd::save); + } + + // KEY commands. + + QueuedRedis& del(const StringView &key) { + return command(cmd::del, key); + } + + template + QueuedRedis& del(Input first, Input last) { + range_check("DEL", first, last); + + return command(cmd::del_range, first, last); + } + + template + QueuedRedis& del(std::initializer_list il) { + return del(il.begin(), il.end()); + } + + QueuedRedis& dump(const StringView &key) { + return command(cmd::dump, key); + } + + QueuedRedis& exists(const StringView &key) { + return command(cmd::exists, key); + } + + template + QueuedRedis& exists(Input first, Input last) { + range_check("EXISTS", first, last); + + return command(cmd::exists_range, first, last); + } + + template + QueuedRedis& exists(std::initializer_list il) { + return exists(il.begin(), il.end()); + } + + QueuedRedis& expire(const StringView &key, long long timeout) { + return command(cmd::expire, key, timeout); + } + + QueuedRedis& expire(const StringView &key, + const std::chrono::seconds &timeout) { + return expire(key, timeout.count()); + } + + QueuedRedis& expireat(const StringView &key, long long timestamp) { + return command(cmd::expireat, key, timestamp); + } + + QueuedRedis& expireat(const StringView &key, + const std::chrono::time_point &tp) { + return expireat(key, tp.time_since_epoch().count()); + } + + QueuedRedis& keys(const StringView &pattern) { + return command(cmd::keys, pattern); + } + + QueuedRedis& move(const StringView &key, long long db) { + return command(cmd::move, key, db); + } + + QueuedRedis& persist(const StringView &key) { + return command(cmd::persist, key); + } + + QueuedRedis& pexpire(const StringView &key, long long timeout) { + return command(cmd::pexpire, key, timeout); + } + + QueuedRedis& pexpire(const StringView &key, + const std::chrono::milliseconds &timeout) { + return pexpire(key, timeout.count()); + } + + QueuedRedis& pexpireat(const StringView &key, long long timestamp) { + return command(cmd::pexpireat, key, timestamp); + } + + QueuedRedis& pexpireat(const StringView &key, + const std::chrono::time_point &tp) { + return pexpireat(key, tp.time_since_epoch().count()); + } + + QueuedRedis& pttl(const StringView &key) { + return command(cmd::pttl, key); + } + + QueuedRedis& randomkey() { + return command(cmd::randomkey); + } + + QueuedRedis& rename(const StringView &key, const StringView &newkey) { + return command(cmd::rename, key, newkey); + } + + QueuedRedis& renamenx(const StringView &key, const StringView &newkey) { + return command(cmd::renamenx, key, newkey); + } + + QueuedRedis& restore(const StringView &key, + const StringView &val, + long long ttl, + bool replace = false) { + return command(cmd::restore, key, val, ttl, replace); + } + + QueuedRedis& restore(const StringView &key, + const StringView &val, + const std::chrono::milliseconds &ttl = std::chrono::milliseconds{0}, + bool replace = false) { + return restore(key, val, ttl.count(), replace); + } + + // TODO: sort + + QueuedRedis& scan(long long cursor, + const StringView &pattern, + long long count) { + return command(cmd::scan, cursor, pattern, count); + } + + QueuedRedis& scan(long long cursor) { + return scan(cursor, "*", 10); + } + + QueuedRedis& scan(long long cursor, + const StringView &pattern) { + return scan(cursor, pattern, 10); + } + + QueuedRedis& scan(long long cursor, + long long count) { + return scan(cursor, "*", count); + } + + QueuedRedis& touch(const StringView &key) { + return command(cmd::touch, key); + } + + template + QueuedRedis& touch(Input first, Input last) { + range_check("TOUCH", first, last); + + return command(cmd::touch_range, first, last); + } + + template + QueuedRedis& touch(std::initializer_list il) { + return touch(il.begin(), il.end()); + } + + QueuedRedis& ttl(const StringView &key) { + return command(cmd::ttl, key); + } + + QueuedRedis& type(const StringView &key) { + return command(cmd::type, key); + } + + QueuedRedis& unlink(const StringView &key) { + return command(cmd::unlink, key); + } + + template + QueuedRedis& unlink(Input first, Input last) { + range_check("UNLINK", first, last); + + return command(cmd::unlink_range, first, last); + } + + template + QueuedRedis& unlink(std::initializer_list il) { + return unlink(il.begin(), il.end()); + } + + QueuedRedis& wait(long long numslaves, long long timeout) { + return command(cmd::wait, numslaves, timeout); + } + + QueuedRedis& wait(long long numslaves, const std::chrono::milliseconds &timeout) { + return wait(numslaves, timeout.count()); + } + + // STRING commands. + + QueuedRedis& append(const StringView &key, const StringView &str) { + return command(cmd::append, key, str); + } + + QueuedRedis& bitcount(const StringView &key, + long long start = 0, + long long end = -1) { + return command(cmd::bitcount, key, start, end); + } + + QueuedRedis& bitop(BitOp op, + const StringView &destination, + const StringView &key) { + return command(cmd::bitop, op, destination, key); + } + + template + QueuedRedis& bitop(BitOp op, + const StringView &destination, + Input first, + Input last) { + range_check("BITOP", first, last); + + return command(cmd::bitop_range, op, destination, first, last); + } + + template + QueuedRedis& bitop(BitOp op, + const StringView &destination, + std::initializer_list il) { + return bitop(op, destination, il.begin(), il.end()); + } + + QueuedRedis& bitpos(const StringView &key, + long long bit, + long long start = 0, + long long end = -1) { + return command(cmd::bitpos, key, bit, start, end); + } + + QueuedRedis& decr(const StringView &key) { + return command(cmd::decr, key); + } + + QueuedRedis& decrby(const StringView &key, long long decrement) { + return command(cmd::decrby, key, decrement); + } + + QueuedRedis& get(const StringView &key) { + return command(cmd::get, key); + } + + QueuedRedis& getbit(const StringView &key, long long offset) { + return command(cmd::getbit, key, offset); + } + + QueuedRedis& getrange(const StringView &key, long long start, long long end) { + return command(cmd::getrange, key, start, end); + } + + QueuedRedis& getset(const StringView &key, const StringView &val) { + return command(cmd::getset, key, val); + } + + QueuedRedis& incr(const StringView &key) { + return command(cmd::incr, key); + } + + QueuedRedis& incrby(const StringView &key, long long increment) { + return command(cmd::incrby, key, increment); + } + + QueuedRedis& incrbyfloat(const StringView &key, double increment) { + return command(cmd::incrbyfloat, key, increment); + } + + template + QueuedRedis& mget(Input first, Input last) { + range_check("MGET", first, last); + + return command(cmd::mget, first, last); + } + + template + QueuedRedis& mget(std::initializer_list il) { + return mget(il.begin(), il.end()); + } + + template + QueuedRedis& mset(Input first, Input last) { + range_check("MSET", first, last); + + return command(cmd::mset, first, last); + } + + template + QueuedRedis& mset(std::initializer_list il) { + return mset(il.begin(), il.end()); + } + + template + QueuedRedis& msetnx(Input first, Input last) { + range_check("MSETNX", first, last); + + return command(cmd::msetnx, first, last); + } + + template + QueuedRedis& msetnx(std::initializer_list il) { + return msetnx(il.begin(), il.end()); + } + + QueuedRedis& psetex(const StringView &key, + long long ttl, + const StringView &val) { + return command(cmd::psetex, key, ttl, val); + } + + QueuedRedis& psetex(const StringView &key, + const std::chrono::milliseconds &ttl, + const StringView &val) { + return psetex(key, ttl.count(), val); + } + + QueuedRedis& set(const StringView &key, + const StringView &val, + const std::chrono::milliseconds &ttl = std::chrono::milliseconds(0), + UpdateType type = UpdateType::ALWAYS) { + _set_cmd_indexes.push_back(_cmd_num); + + return command(cmd::set, key, val, ttl.count(), type); + } + + QueuedRedis& setex(const StringView &key, + long long ttl, + const StringView &val) { + return command(cmd::setex, key, ttl, val); + } + + QueuedRedis& setex(const StringView &key, + const std::chrono::seconds &ttl, + const StringView &val) { + return setex(key, ttl.count(), val); + } + + QueuedRedis& setnx(const StringView &key, const StringView &val) { + return command(cmd::setnx, key, val); + } + + QueuedRedis& setrange(const StringView &key, + long long offset, + const StringView &val) { + return command(cmd::setrange, key, offset, val); + } + + QueuedRedis& strlen(const StringView &key) { + return command(cmd::strlen, key); + } + + // LIST commands. + + QueuedRedis& blpop(const StringView &key, long long timeout) { + return command(cmd::blpop, key, timeout); + } + + QueuedRedis& blpop(const StringView &key, + const std::chrono::seconds &timeout = std::chrono::seconds{0}) { + return blpop(key, timeout.count()); + } + + template + QueuedRedis& blpop(Input first, Input last, long long timeout) { + range_check("BLPOP", first, last); + + return command(cmd::blpop_range, first, last, timeout); + } + + template + QueuedRedis& blpop(std::initializer_list il, long long timeout) { + return blpop(il.begin(), il.end(), timeout); + } + + template + QueuedRedis& blpop(Input first, + Input last, + const std::chrono::seconds &timeout = std::chrono::seconds{0}) { + return blpop(first, last, timeout.count()); + } + + template + QueuedRedis& blpop(std::initializer_list il, + const std::chrono::seconds &timeout = std::chrono::seconds{0}) { + return blpop(il.begin(), il.end(), timeout); + } + + QueuedRedis& brpop(const StringView &key, long long timeout) { + return command(cmd::brpop, key, timeout); + } + + QueuedRedis& brpop(const StringView &key, + const std::chrono::seconds &timeout = std::chrono::seconds{0}) { + return brpop(key, timeout.count()); + } + + template + QueuedRedis& brpop(Input first, Input last, long long timeout) { + range_check("BRPOP", first, last); + + return command(cmd::brpop_range, first, last, timeout); + } + + template + QueuedRedis& brpop(std::initializer_list il, long long timeout) { + return brpop(il.begin(), il.end(), timeout); + } + + template + QueuedRedis& brpop(Input first, + Input last, + const std::chrono::seconds &timeout = std::chrono::seconds{0}) { + return brpop(first, last, timeout.count()); + } + + template + QueuedRedis& brpop(std::initializer_list il, + const std::chrono::seconds &timeout = std::chrono::seconds{0}) { + return brpop(il.begin(), il.end(), timeout); + } + + QueuedRedis& brpoplpush(const StringView &source, + const StringView &destination, + long long timeout) { + return command(cmd::brpoplpush, source, destination, timeout); + } + + QueuedRedis& brpoplpush(const StringView &source, + const StringView &destination, + const std::chrono::seconds &timeout = std::chrono::seconds{0}) { + return brpoplpush(source, destination, timeout.count()); + } + + QueuedRedis& lindex(const StringView &key, long long index) { + return command(cmd::lindex, key, index); + } + + QueuedRedis& linsert(const StringView &key, + InsertPosition position, + const StringView &pivot, + const StringView &val) { + return command(cmd::linsert, key, position, pivot, val); + } + + QueuedRedis& llen(const StringView &key) { + return command(cmd::llen, key); + } + + QueuedRedis& lpop(const StringView &key) { + return command(cmd::lpop, key); + } + + QueuedRedis& lpush(const StringView &key, const StringView &val) { + return command(cmd::lpush, key, val); + } + + template + QueuedRedis& lpush(const StringView &key, Input first, Input last) { + range_check("LPUSH", first, last); + + return command(cmd::lpush_range, key, first, last); + } + + template + QueuedRedis& lpush(const StringView &key, std::initializer_list il) { + return lpush(key, il.begin(), il.end()); + } + + QueuedRedis& lpushx(const StringView &key, const StringView &val) { + return command(cmd::lpushx, key, val); + } + + QueuedRedis& lrange(const StringView &key, + long long start, + long long stop) { + return command(cmd::lrange, key, start, stop); + } + + QueuedRedis& lrem(const StringView &key, long long count, const StringView &val) { + return command(cmd::lrem, key, count, val); + } + + QueuedRedis& lset(const StringView &key, long long index, const StringView &val) { + return command(cmd::lset, key, index, val); + } + + QueuedRedis& ltrim(const StringView &key, long long start, long long stop) { + return command(cmd::ltrim, key, start, stop); + } + + QueuedRedis& rpop(const StringView &key) { + return command(cmd::rpop, key); + } + + QueuedRedis& rpoplpush(const StringView &source, const StringView &destination) { + return command(cmd::rpoplpush, source, destination); + } + + QueuedRedis& rpush(const StringView &key, const StringView &val) { + return command(cmd::rpush, key, val); + } + + template + QueuedRedis& rpush(const StringView &key, Input first, Input last) { + range_check("RPUSH", first, last); + + return command(cmd::rpush_range, key, first, last); + } + + template + QueuedRedis& rpush(const StringView &key, std::initializer_list il) { + return rpush(key, il.begin(), il.end()); + } + + QueuedRedis& rpushx(const StringView &key, const StringView &val) { + return command(cmd::rpushx, key, val); + } + + // HASH commands. + + QueuedRedis& hdel(const StringView &key, const StringView &field) { + return command(cmd::hdel, key, field); + } + + template + QueuedRedis& hdel(const StringView &key, Input first, Input last) { + range_check("HDEL", first, last); + + return command(cmd::hdel_range, key, first, last); + } + + template + QueuedRedis& hdel(const StringView &key, std::initializer_list il) { + return hdel(key, il.begin(), il.end()); + } + + QueuedRedis& hexists(const StringView &key, const StringView &field) { + return command(cmd::hexists, key, field); + } + + QueuedRedis& hget(const StringView &key, const StringView &field) { + return command(cmd::hget, key, field); + } + + QueuedRedis& hgetall(const StringView &key) { + return command(cmd::hgetall, key); + } + + QueuedRedis& hincrby(const StringView &key, + const StringView &field, + long long increment) { + return command(cmd::hincrby, key, field, increment); + } + + QueuedRedis& hincrbyfloat(const StringView &key, + const StringView &field, + double increment) { + return command(cmd::hincrbyfloat, key, field, increment); + } + + QueuedRedis& hkeys(const StringView &key) { + return command(cmd::hkeys, key); + } + + QueuedRedis& hlen(const StringView &key) { + return command(cmd::hlen, key); + } + + template + QueuedRedis& hmget(const StringView &key, Input first, Input last) { + range_check("HMGET", first, last); + + return command(cmd::hmget, key, first, last); + } + + template + QueuedRedis& hmget(const StringView &key, std::initializer_list il) { + return hmget(key, il.begin(), il.end()); + } + + template + QueuedRedis& hmset(const StringView &key, Input first, Input last) { + range_check("HMSET", first, last); + + return command(cmd::hmset, key, first, last); + } + + template + QueuedRedis& hmset(const StringView &key, std::initializer_list il) { + return hmset(key, il.begin(), il.end()); + } + + QueuedRedis& hscan(const StringView &key, + long long cursor, + const StringView &pattern, + long long count) { + return command(cmd::hscan, key, cursor, pattern, count); + } + + QueuedRedis& hscan(const StringView &key, + long long cursor, + const StringView &pattern) { + return hscan(key, cursor, pattern, 10); + } + + QueuedRedis& hscan(const StringView &key, + long long cursor, + long long count) { + return hscan(key, cursor, "*", count); + } + + QueuedRedis& hscan(const StringView &key, + long long cursor) { + return hscan(key, cursor, "*", 10); + } + + QueuedRedis& hset(const StringView &key, const StringView &field, const StringView &val) { + return command(cmd::hset, key, field, val); + } + + QueuedRedis& hset(const StringView &key, const std::pair &item) { + return hset(key, item.first, item.second); + } + + template + auto hset(const StringView &key, Input first, Input last) + -> typename std::enable_if::value, + QueuedRedis&>::type { + range_check("HSET", first, last); + + return command(cmd::hset_range, key, first, last); + } + + template + QueuedRedis& hset(const StringView &key, std::initializer_list il) { + return hset(key, il.begin(), il.end()); + } + + QueuedRedis& hsetnx(const StringView &key, const StringView &field, const StringView &val) { + return command(cmd::hsetnx, key, field, val); + } + + QueuedRedis& hsetnx(const StringView &key, const std::pair &item) { + return hsetnx(key, item.first, item.second); + } + + QueuedRedis& hstrlen(const StringView &key, const StringView &field) { + return command(cmd::hstrlen, key, field); + } + + QueuedRedis& hvals(const StringView &key) { + return command(cmd::hvals, key); + } + + // SET commands. + + QueuedRedis& sadd(const StringView &key, const StringView &member) { + return command(cmd::sadd, key, member); + } + + template + QueuedRedis& sadd(const StringView &key, Input first, Input last) { + range_check("SADD", first, last); + + return command(cmd::sadd_range, key, first, last); + } + + template + QueuedRedis& sadd(const StringView &key, std::initializer_list il) { + return sadd(key, il.begin(), il.end()); + } + + QueuedRedis& scard(const StringView &key) { + return command(cmd::scard, key); + } + + template + QueuedRedis& sdiff(Input first, Input last) { + range_check("SDIFF", first, last); + + return command(cmd::sdiff, first, last); + } + + template + QueuedRedis& sdiff(std::initializer_list il) { + return sdiff(il.begin(), il.end()); + } + + QueuedRedis& sdiffstore(const StringView &destination, const StringView &key) { + return command(cmd::sdiffstore, destination, key); + } + + template + QueuedRedis& sdiffstore(const StringView &destination, + Input first, + Input last) { + range_check("SDIFFSTORE", first, last); + + return command(cmd::sdiffstore_range, destination, first, last); + } + + template + QueuedRedis& sdiffstore(const StringView &destination, std::initializer_list il) { + return sdiffstore(destination, il.begin(), il.end()); + } + + template + QueuedRedis& sinter(Input first, Input last) { + range_check("SINTER", first, last); + + return command(cmd::sinter, first, last); + } + + template + QueuedRedis& sinter(std::initializer_list il) { + return sinter(il.begin(), il.end()); + } + + QueuedRedis& sinterstore(const StringView &destination, const StringView &key) { + return command(cmd::sinterstore, destination, key); + } + + template + QueuedRedis& sinterstore(const StringView &destination, + Input first, + Input last) { + range_check("SINTERSTORE", first, last); + + return command(cmd::sinterstore_range, destination, first, last); + } + + template + QueuedRedis& sinterstore(const StringView &destination, std::initializer_list il) { + return sinterstore(destination, il.begin(), il.end()); + } + + QueuedRedis& sismember(const StringView &key, const StringView &member) { + return command(cmd::sismember, key, member); + } + + QueuedRedis& smembers(const StringView &key) { + return command(cmd::smembers, key); + } + + QueuedRedis& smove(const StringView &source, + const StringView &destination, + const StringView &member) { + return command(cmd::smove, source, destination, member); + } + + QueuedRedis& spop(const StringView &key) { + return command(cmd::spop, key); + } + + QueuedRedis& spop(const StringView &key, long long count) { + return command(cmd::spop_range, key, count); + } + + QueuedRedis& srandmember(const StringView &key) { + return command(cmd::srandmember, key); + } + + QueuedRedis& srandmember(const StringView &key, long long count) { + return command(cmd::srandmember_range, key, count); + } + + QueuedRedis& srem(const StringView &key, const StringView &member) { + return command(cmd::srem, key, member); + } + + template + QueuedRedis& srem(const StringView &key, Input first, Input last) { + range_check("SREM", first, last); + + return command(cmd::srem_range, key, first, last); + } + + template + QueuedRedis& srem(const StringView &key, std::initializer_list il) { + return srem(key, il.begin(), il.end()); + } + + QueuedRedis& sscan(const StringView &key, + long long cursor, + const StringView &pattern, + long long count) { + return command(cmd::sscan, key, cursor, pattern, count); + } + + QueuedRedis& sscan(const StringView &key, + long long cursor, + const StringView &pattern) { + return sscan(key, cursor, pattern, 10); + } + + QueuedRedis& sscan(const StringView &key, + long long cursor, + long long count) { + return sscan(key, cursor, "*", count); + } + + QueuedRedis& sscan(const StringView &key, + long long cursor) { + return sscan(key, cursor, "*", 10); + } + + template + QueuedRedis& sunion(Input first, Input last) { + range_check("SUNION", first, last); + + return command(cmd::sunion, first, last); + } + + template + QueuedRedis& sunion(std::initializer_list il) { + return sunion(il.begin(), il.end()); + } + + QueuedRedis& sunionstore(const StringView &destination, const StringView &key) { + return command(cmd::sunionstore, destination, key); + } + + template + QueuedRedis& sunionstore(const StringView &destination, Input first, Input last) { + range_check("SUNIONSTORE", first, last); + + return command(cmd::sunionstore_range, destination, first, last); + } + + template + QueuedRedis& sunionstore(const StringView &destination, std::initializer_list il) { + return sunionstore(destination, il.begin(), il.end()); + } + + // SORTED SET commands. + + QueuedRedis& bzpopmax(const StringView &key, long long timeout) { + return command(cmd::bzpopmax, key, timeout); + } + + QueuedRedis& bzpopmax(const StringView &key, + const std::chrono::seconds &timeout = std::chrono::seconds{0}) { + return bzpopmax(key, timeout.count()); + } + + template + QueuedRedis& bzpopmax(Input first, Input last, long long timeout) { + range_check("BZPOPMAX", first, last); + + return command(cmd::bzpopmax_range, first, last, timeout); + } + + template + QueuedRedis& bzpopmax(Input first, + Input last, + const std::chrono::seconds &timeout = std::chrono::seconds{0}) { + return bzpopmax(first, last, timeout.count()); + } + + template + QueuedRedis& bzpopmax(std::initializer_list il, long long timeout) { + return bzpopmax(il.begin(), il.end(), timeout); + } + + template + QueuedRedis& bzpopmax(std::initializer_list il, + const std::chrono::seconds &timeout = std::chrono::seconds{0}) { + return bzpopmax(il.begin(), il.end(), timeout); + } + + QueuedRedis& bzpopmin(const StringView &key, long long timeout) { + return command(cmd::bzpopmin, key, timeout); + } + + QueuedRedis& bzpopmin(const StringView &key, + const std::chrono::seconds &timeout = std::chrono::seconds{0}) { + return bzpopmin(key, timeout.count()); + } + + template + QueuedRedis& bzpopmin(Input first, Input last, long long timeout) { + range_check("BZPOPMIN", first, last); + + return command(cmd::bzpopmin_range, first, last, timeout); + } + + template + QueuedRedis& bzpopmin(Input first, + Input last, + const std::chrono::seconds &timeout = std::chrono::seconds{0}) { + return bzpopmin(first, last, timeout.count()); + } + + template + QueuedRedis& bzpopmin(std::initializer_list il, long long timeout) { + return bzpopmin(il.begin(), il.end(), timeout); + } + + template + QueuedRedis& bzpopmin(std::initializer_list il, + const std::chrono::seconds &timeout = std::chrono::seconds{0}) { + return bzpopmin(il.begin(), il.end(), timeout); + } + + // We don't support the INCR option, since you can always use ZINCRBY instead. + QueuedRedis& zadd(const StringView &key, + const StringView &member, + double score, + UpdateType type = UpdateType::ALWAYS, + bool changed = false) { + return command(cmd::zadd, key, member, score, type, changed); + } + + template + QueuedRedis& zadd(const StringView &key, + Input first, + Input last, + UpdateType type = UpdateType::ALWAYS, + bool changed = false) { + range_check("ZADD", first, last); + + return command(cmd::zadd_range, key, first, last, type, changed); + } + + QueuedRedis& zcard(const StringView &key) { + return command(cmd::zcard, key); + } + + template + QueuedRedis& zcount(const StringView &key, const Interval &interval) { + return command(cmd::zcount, key, interval); + } + + QueuedRedis& zincrby(const StringView &key, double increment, const StringView &member) { + return command(cmd::zincrby, key, increment, member); + } + + QueuedRedis& zinterstore(const StringView &destination, + const StringView &key, + double weight) { + return command(cmd::zinterstore, destination, key, weight); + } + + template + QueuedRedis& zinterstore(const StringView &destination, + Input first, + Input last, + Aggregation type = Aggregation::SUM) { + range_check("ZINTERSTORE", first, last); + + return command(cmd::zinterstore_range, destination, first, last, type); + } + + template + QueuedRedis& zinterstore(const StringView &destination, + std::initializer_list il, + Aggregation type = Aggregation::SUM) { + return zinterstore(destination, il.begin(), il.end(), type); + } + + template + QueuedRedis& zlexcount(const StringView &key, const Interval &interval) { + return command(cmd::zlexcount, key, interval); + } + + QueuedRedis& zpopmax(const StringView &key) { + _empty_array_cmd_indexes.push_back(_cmd_num); + + return command(cmd::zpopmax, key, 1); + } + + QueuedRedis& zpopmax(const StringView &key, long long count) { + return command(cmd::zpopmax, key, count); + } + + QueuedRedis& zpopmin(const StringView &key) { + _empty_array_cmd_indexes.push_back(_cmd_num); + + return command(cmd::zpopmin, key, 1); + } + + QueuedRedis& zpopmin(const StringView &key, long long count) { + return command(cmd::zpopmin, key, count); + } + + // NOTE: *QueuedRedis::zrange*'s parameters are different from *Redis::zrange*. + // *Redis::zrange* is overloaded by the output iterator, however, there's no such + // iterator in *QueuedRedis::zrange*. So we have to use an extra parameter: *with_scores*, + // to decide whether we should send *WITHSCORES* option to Redis. This also applies to + // other commands with the *WITHSCORES* option, e.g. *ZRANGEBYSCORE*, *ZREVRANGE*, + // *ZREVRANGEBYSCORE*. + QueuedRedis& zrange(const StringView &key, + long long start, + long long stop, + bool with_scores = false) { + return command(cmd::zrange, key, start, stop, with_scores); + } + + template + QueuedRedis& zrangebylex(const StringView &key, + const Interval &interval, + const LimitOptions &opts) { + return command(cmd::zrangebylex, key, interval, opts); + } + + template + QueuedRedis& zrangebylex(const StringView &key, const Interval &interval) { + return zrangebylex(key, interval, {}); + } + + // See comments on *ZRANGE*. + template + QueuedRedis& zrangebyscore(const StringView &key, + const Interval &interval, + const LimitOptions &opts, + bool with_scores = false) { + return command(cmd::zrangebyscore, key, interval, opts, with_scores); + } + + // See comments on *ZRANGE*. + template + QueuedRedis& zrangebyscore(const StringView &key, + const Interval &interval, + bool with_scores = false) { + return zrangebyscore(key, interval, {}, with_scores); + } + + QueuedRedis& zrank(const StringView &key, const StringView &member) { + return command(cmd::zrank, key, member); + } + + QueuedRedis& zrem(const StringView &key, const StringView &member) { + return command(cmd::zrem, key, member); + } + + template + QueuedRedis& zrem(const StringView &key, Input first, Input last) { + range_check("ZREM", first, last); + + return command(cmd::zrem_range, key, first, last); + } + + template + QueuedRedis& zrem(const StringView &key, std::initializer_list il) { + return zrem(key, il.begin(), il.end()); + } + + template + QueuedRedis& zremrangebylex(const StringView &key, const Interval &interval) { + return command(cmd::zremrangebylex, key, interval); + } + + QueuedRedis& zremrangebyrank(const StringView &key, long long start, long long stop) { + return command(cmd::zremrangebyrank, key, start, stop); + } + + template + QueuedRedis& zremrangebyscore(const StringView &key, const Interval &interval) { + return command(cmd::zremrangebyscore, key, interval); + } + + // See comments on *ZRANGE*. + QueuedRedis& zrevrange(const StringView &key, + long long start, + long long stop, + bool with_scores = false) { + return command(cmd::zrevrange, key, start, stop, with_scores); + } + + template + QueuedRedis& zrevrangebylex(const StringView &key, + const Interval &interval, + const LimitOptions &opts) { + return command(cmd::zrevrangebylex, key, interval, opts); + } + + template + QueuedRedis& zrevrangebylex(const StringView &key, const Interval &interval) { + return zrevrangebylex(key, interval, {}); + } + + // See comments on *ZRANGE*. + template + QueuedRedis& zrevrangebyscore(const StringView &key, + const Interval &interval, + const LimitOptions &opts, + bool with_scores = false) { + return command(cmd::zrevrangebyscore, key, interval, opts, with_scores); + } + + // See comments on *ZRANGE*. + template + QueuedRedis& zrevrangebyscore(const StringView &key, + const Interval &interval, + bool with_scores = false) { + return zrevrangebyscore(key, interval, {}, with_scores); + } + + QueuedRedis& zrevrank(const StringView &key, const StringView &member) { + return command(cmd::zrevrank, key, member); + } + + QueuedRedis& zscan(const StringView &key, + long long cursor, + const StringView &pattern, + long long count) { + return command(cmd::zscan, key, cursor, pattern, count); + } + + QueuedRedis& zscan(const StringView &key, + long long cursor, + const StringView &pattern) { + return zscan(key, cursor, pattern, 10); + } + + QueuedRedis& zscan(const StringView &key, + long long cursor, + long long count) { + return zscan(key, cursor, "*", count); + } + + QueuedRedis& zscan(const StringView &key, + long long cursor) { + return zscan(key, cursor, "*", 10); + } + + QueuedRedis& zscore(const StringView &key, const StringView &member) { + return command(cmd::zscore, key, member); + } + + QueuedRedis& zunionstore(const StringView &destination, + const StringView &key, + double weight) { + return command(cmd::zunionstore, destination, key, weight); + } + + template + QueuedRedis& zunionstore(const StringView &destination, + Input first, + Input last, + Aggregation type = Aggregation::SUM) { + range_check("ZUNIONSTORE", first, last); + + return command(cmd::zunionstore_range, destination, first, last, type); + } + + template + QueuedRedis& zunionstore(const StringView &destination, + std::initializer_list il, + Aggregation type = Aggregation::SUM) { + return zunionstore(destination, il.begin(), il.end(), type); + } + + // HYPERLOGLOG commands. + + QueuedRedis& pfadd(const StringView &key, const StringView &element) { + return command(cmd::pfadd, key, element); + } + + template + QueuedRedis& pfadd(const StringView &key, Input first, Input last) { + range_check("PFADD", first, last); + + return command(cmd::pfadd_range, key, first, last); + } + + template + QueuedRedis& pfadd(const StringView &key, std::initializer_list il) { + return pfadd(key, il.begin(), il.end()); + } + + QueuedRedis& pfcount(const StringView &key) { + return command(cmd::pfcount, key); + } + + template + QueuedRedis& pfcount(Input first, Input last) { + range_check("PFCOUNT", first, last); + + return command(cmd::pfcount_range, first, last); + } + + template + QueuedRedis& pfcount(std::initializer_list il) { + return pfcount(il.begin(), il.end()); + } + + QueuedRedis& pfmerge(const StringView &destination, const StringView &key) { + return command(cmd::pfmerge, destination, key); + } + + template + QueuedRedis& pfmerge(const StringView &destination, Input first, Input last) { + range_check("PFMERGE", first, last); + + return command(cmd::pfmerge_range, destination, first, last); + } + + template + QueuedRedis& pfmerge(const StringView &destination, std::initializer_list il) { + return pfmerge(destination, il.begin(), il.end()); + } + + // GEO commands. + + QueuedRedis& geoadd(const StringView &key, + const std::tuple &member) { + return command(cmd::geoadd, key, member); + } + + template + QueuedRedis& geoadd(const StringView &key, + Input first, + Input last) { + range_check("GEOADD", first, last); + + return command(cmd::geoadd_range, key, first, last); + } + + template + QueuedRedis& geoadd(const StringView &key, std::initializer_list il) { + return geoadd(key, il.begin(), il.end()); + } + + QueuedRedis& geodist(const StringView &key, + const StringView &member1, + const StringView &member2, + GeoUnit unit = GeoUnit::M) { + return command(cmd::geodist, key, member1, member2, unit); + } + + // Call reply::parse_leniently to parse the reply. + QueuedRedis& geohash(const StringView &key, const StringView &member) { + return command(cmd::geohash, key, member); + } + + template + QueuedRedis& geohash(const StringView &key, Input first, Input last) { + range_check("GEOHASH", first, last); + + return command(cmd::geohash_range, key, first, last); + } + + template + QueuedRedis& geohash(const StringView &key, std::initializer_list il) { + return geohash(key, il.begin(), il.end()); + } + + // Call reply::parse_leniently to parse the reply. + QueuedRedis& geopos(const StringView &key, const StringView &member) { + return command(cmd::geopos, key, member); + } + + template + QueuedRedis& geopos(const StringView &key, Input first, Input last) { + range_check("GEOPOS", first, last); + + return command(cmd::geopos_range, key, first, last); + } + + template + QueuedRedis& geopos(const StringView &key, std::initializer_list il) { + return geopos(key, il.begin(), il.end()); + } + + // TODO: + // 1. since we have different overloads for georadius and georadius-store, + // we might use the GEORADIUS_RO command in the future. + // 2. there're too many parameters for this method, we might refactor it. + QueuedRedis& georadius(const StringView &key, + const std::pair &loc, + double radius, + GeoUnit unit, + const StringView &destination, + bool store_dist, + long long count) { + _empty_array_cmd_indexes.push_back(_cmd_num); + + return command(cmd::georadius_store, + key, + loc, + radius, + unit, + destination, + store_dist, + count); + } + + // NOTE: *QueuedRedis::georadius*'s parameters are different from *Redis::georadius*. + // *Redis::georadius* is overloaded by the output iterator, however, there's no such + // iterator in *QueuedRedis::georadius*. So we have to use extra parameters to decide + // whether we should send options to Redis. This also applies to *GEORADIUSBYMEMBER*. + QueuedRedis& georadius(const StringView &key, + const std::pair &loc, + double radius, + GeoUnit unit, + long long count, + bool asc, + bool with_coord, + bool with_dist, + bool with_hash) { + return command(cmd::georadius, + key, + loc, + radius, + unit, + count, + asc, + with_coord, + with_dist, + with_hash); + } + + QueuedRedis& georadiusbymember(const StringView &key, + const StringView &member, + double radius, + GeoUnit unit, + const StringView &destination, + bool store_dist, + long long count) { + _empty_array_cmd_indexes.push_back(_cmd_num); + + return command(cmd::georadiusbymember, + key, + member, + radius, + unit, + destination, + store_dist, + count); + } + + // See the comments on *GEORADIUS*. + QueuedRedis& georadiusbymember(const StringView &key, + const StringView &member, + double radius, + GeoUnit unit, + long long count, + bool asc, + bool with_coord, + bool with_dist, + bool with_hash) { + return command(cmd::georadiusbymember, + key, + member, + radius, + unit, + count, + asc, + with_coord, + with_dist, + with_hash); + } + + // SCRIPTING commands. + + template + QueuedRedis& eval(const StringView &script, + Keys keys_first, + Keys keys_last, + Args args_first, + Args args_last) { + return command(cmd::eval, script, keys_first, keys_last, args_first, args_last); + } + + QueuedRedis& eval(const StringView &script, + std::initializer_list keys, + std::initializer_list args) { + return eval(script, keys.begin(), keys.end(), args.begin(), args.end()); + } + + template + QueuedRedis& evalsha(const StringView &script, + Keys keys_first, + Keys keys_last, + Args args_first, + Args args_last) { + return command(cmd::evalsha, script, keys_first, keys_last, args_first, args_last); + } + + QueuedRedis& evalsha(const StringView &script, + std::initializer_list keys, + std::initializer_list args) { + return evalsha(script, keys.begin(), keys.end(), args.begin(), args.end()); + } + + // Call reply::parse_leniently to parse the reply. + QueuedRedis& script_exists(const StringView &sha1) { + return command(cmd::script_exists, sha1); + } + + template + QueuedRedis& script_exists(Input first, Input last) { + range_check("SCRIPT EXISTS", first, last); + + return command(cmd::script_exists_range, first, last); + } + + template + QueuedRedis& script_exists(std::initializer_list il) { + return script_exists(il.begin(), il.end()); + } + + QueuedRedis& script_flush() { + return command(cmd::script_flush); + } + + QueuedRedis& script_kill() { + return command(cmd::script_kill); + } + + QueuedRedis& script_load(const StringView &script) { + return command(cmd::script_load, script); + } + + // PUBSUB commands. + + QueuedRedis& publish(const StringView &channel, const StringView &message) { + return command(cmd::publish, channel, message); + } + + // Stream commands. + + QueuedRedis& xack(const StringView &key, const StringView &group, const StringView &id) { + return command(cmd::xack, key, group, id); + } + + template + QueuedRedis& xack(const StringView &key, const StringView &group, Input first, Input last) { + range_check("XACK", first, last); + + return command(cmd::xack_range, key, group, first, last); + } + + template + QueuedRedis& xack(const StringView &key, const StringView &group, std::initializer_list il) { + return xack(key, group, il.begin(), il.end()); + } + + template + QueuedRedis& xadd(const StringView &key, const StringView &id, Input first, Input last) { + range_check("XADD", first, last); + + return command(cmd::xadd_range, key, id, first, last); + } + + template + QueuedRedis& xadd(const StringView &key, const StringView &id, std::initializer_list il) { + return xadd(key, id, il.begin(), il.end()); + } + + template + QueuedRedis& xadd(const StringView &key, + const StringView &id, + Input first, + Input last, + long long count, + bool approx = true) { + range_check("XADD", first, last); + + return command(cmd::xadd_maxlen_range, key, id, first, last, count, approx); + } + + template + QueuedRedis& xadd(const StringView &key, + const StringView &id, + std::initializer_list il, + long long count, + bool approx = true) { + return xadd(key, id, il.begin(), il.end(), count, approx); + } + + QueuedRedis& xclaim(const StringView &key, + const StringView &group, + const StringView &consumer, + const std::chrono::milliseconds &min_idle_time, + const StringView &id) { + return command(cmd::xclaim, key, group, consumer, min_idle_time.count(), id); + } + + template + QueuedRedis& xclaim(const StringView &key, + const StringView &group, + const StringView &consumer, + const std::chrono::milliseconds &min_idle_time, + Input first, + Input last) { + range_check("XCLAIM", first, last); + + return command(cmd::xclaim_range, + key, + group, + consumer, + min_idle_time.count(), + first, + last); + } + + template + QueuedRedis& xclaim(const StringView &key, + const StringView &group, + const StringView &consumer, + const std::chrono::milliseconds &min_idle_time, + std::initializer_list il) { + return xclaim(key, group, consumer, min_idle_time, il.begin(), il.end()); + } + + QueuedRedis& xdel(const StringView &key, const StringView &id) { + return command(cmd::xdel, key, id); + } + + template + QueuedRedis& xdel(const StringView &key, Input first, Input last) { + range_check("XDEL", first, last); + + return command(cmd::xdel_range, key, first, last); + } + + template + QueuedRedis& xdel(const StringView &key, std::initializer_list il) { + return xdel(key, il.begin(), il.end()); + } + + QueuedRedis& xgroup_create(const StringView &key, + const StringView &group, + const StringView &id, + bool mkstream = false) { + return command(cmd::xgroup_create, key, group, id, mkstream); + } + + QueuedRedis& xgroup_setid(const StringView &key, + const StringView &group, + const StringView &id) { + return command(cmd::xgroup_setid, key, group, id); + } + + QueuedRedis& xgroup_destroy(const StringView &key, const StringView &group) { + return command(cmd::xgroup_destroy, key, group); + } + + QueuedRedis& xgroup_delconsumer(const StringView &key, + const StringView &group, + const StringView &consumer) { + return command(cmd::xgroup_delconsumer, key, group, consumer); + } + + QueuedRedis& xlen(const StringView &key) { + return command(cmd::xlen, key); + } + + QueuedRedis& xpending(const StringView &key, const StringView &group) { + return command(cmd::xpending, key, group); + } + + QueuedRedis& xpending(const StringView &key, + const StringView &group, + const StringView &start, + const StringView &end, + long long count) { + return command(cmd::xpending_detail, key, group, start, end, count); + } + + QueuedRedis& xpending(const StringView &key, + const StringView &group, + const StringView &start, + const StringView &end, + long long count, + const StringView &consumer) { + return command(cmd::xpending_per_consumer, key, group, start, end, count, consumer); + } + + QueuedRedis& xrange(const StringView &key, + const StringView &start, + const StringView &end) { + return command(cmd::xrange, key, start, end); + } + + QueuedRedis& xrange(const StringView &key, + const StringView &start, + const StringView &end, + long long count) { + return command(cmd::xrange_count, key, start, end, count); + } + + QueuedRedis& xread(const StringView &key, const StringView &id, long long count) { + return command(cmd::xread, key, id, count); + } + + QueuedRedis& xread(const StringView &key, const StringView &id) { + return xread(key, id, 0); + } + + template + auto xread(Input first, Input last, long long count) + -> typename std::enable_if::value, + QueuedRedis&>::type { + range_check("XREAD", first, last); + + return command(cmd::xread_range, first, last, count); + } + + template + auto xread(Input first, Input last) + -> typename std::enable_if::value, + QueuedRedis&>::type { + return xread(first, last, 0); + } + + QueuedRedis& xread(const StringView &key, + const StringView &id, + const std::chrono::milliseconds &timeout, + long long count) { + return command(cmd::xread_block, key, id, timeout.count(), count); + } + + QueuedRedis& xread(const StringView &key, + const StringView &id, + const std::chrono::milliseconds &timeout) { + return xread(key, id, timeout, 0); + } + + template + auto xread(Input first, + Input last, + const std::chrono::milliseconds &timeout, + long long count) + -> typename std::enable_if::value, + QueuedRedis&>::type { + range_check("XREAD", first, last); + + return command(cmd::xread_block_range, first, last, timeout.count(), count); + } + + template + auto xread(Input first, + Input last, + const std::chrono::milliseconds &timeout) + -> typename std::enable_if::value, + QueuedRedis&>::type { + return xread(first, last, timeout, 0); + } + + QueuedRedis& xreadgroup(const StringView &group, + const StringView &consumer, + const StringView &key, + const StringView &id, + long long count, + bool noack) { + return command(cmd::xreadgroup, group, consumer, key, id, count, noack); + } + + QueuedRedis& xreadgroup(const StringView &group, + const StringView &consumer, + const StringView &key, + const StringView &id, + long long count) { + return xreadgroup(group, consumer, key, id, count, false); + } + + template + auto xreadgroup(const StringView &group, + const StringView &consumer, + Input first, + Input last, + long long count, + bool noack) + -> typename std::enable_if::value, + QueuedRedis&>::type { + range_check("XREADGROUP", first, last); + + return command(cmd::xreadgroup_range, group, consumer, first, last, count, noack); + } + + template + auto xreadgroup(const StringView &group, + const StringView &consumer, + Input first, + Input last, + long long count) + -> typename std::enable_if::value, + QueuedRedis&>::type { + return xreadgroup(group, consumer, first ,last, count, false); + } + + template + auto xreadgroup(const StringView &group, + const StringView &consumer, + Input first, + Input last) + -> typename std::enable_if::value, + QueuedRedis&>::type { + return xreadgroup(group, consumer, first ,last, 0, false); + } + + QueuedRedis& xreadgroup(const StringView &group, + const StringView &consumer, + const StringView &key, + const StringView &id, + const std::chrono::milliseconds &timeout, + long long count, + bool noack) { + return command(cmd::xreadgroup_block, + group, + consumer, + key, + id, + timeout.count(), + count, + noack); + } + + QueuedRedis& xreadgroup(const StringView &group, + const StringView &consumer, + const StringView &key, + const StringView &id, + const std::chrono::milliseconds &timeout, + long long count) { + return xreadgroup(group, consumer, key, id, timeout, count, false); + } + + QueuedRedis& xreadgroup(const StringView &group, + const StringView &consumer, + const StringView &key, + const StringView &id, + const std::chrono::milliseconds &timeout) { + return xreadgroup(group, consumer, key, id, timeout, 0, false); + } + + template + auto xreadgroup(const StringView &group, + const StringView &consumer, + Input first, + Input last, + const std::chrono::milliseconds &timeout, + long long count, + bool noack) + -> typename std::enable_if::value, + QueuedRedis&>::type { + range_check("XREADGROUP", first, last); + + return command(cmd::xreadgroup_block_range, + group, + consumer, + first, + last, + timeout.count(), + count, + noack); + } + + template + auto xreadgroup(const StringView &group, + const StringView &consumer, + Input first, + Input last, + const std::chrono::milliseconds &timeout, + long long count) + -> typename std::enable_if::value, + QueuedRedis&>::type { + return xreadgroup(group, consumer, first, last, timeout, count, false); + } + + template + auto xreadgroup(const StringView &group, + const StringView &consumer, + Input first, + Input last, + const std::chrono::milliseconds &timeout) + -> typename std::enable_if::value, + QueuedRedis&>::type { + return xreadgroup(group, consumer, first, last, timeout, 0, false); + } + + QueuedRedis& xrevrange(const StringView &key, + const StringView &end, + const StringView &start) { + return command(cmd::xrevrange, key, end, start); + } + + QueuedRedis& xrevrange(const StringView &key, + const StringView &end, + const StringView &start, + long long count) { + return command(cmd::xrevrange_count, key, end, start, count); + } + + QueuedRedis& xtrim(const StringView &key, long long count, bool approx = true) { + return command(cmd::xtrim, key, count, approx); + } + +private: + friend class Redis; + + friend class RedisCluster; + + template + QueuedRedis(const ConnectionPoolSPtr &pool, bool new_connection, Args &&...args); + + Connection& _connection(); + + void _sanity_check(); + + void _reset(bool reset_connection = true); + + void _return_connection(); + + void _invalidate(); + + void _clean_up(); + + void _rewrite_replies(std::vector &replies) const; + + template + void _rewrite_replies(const std::vector &indexes, + Func rewriter, + std::vector &replies) const; + + GuardedConnectionSPtr _guarded_connection; + + ConnectionPoolSPtr _connection_pool; + + bool _new_connection = true; + + Impl _impl; + + std::size_t _cmd_num = 0; + + std::vector _set_cmd_indexes; + + std::vector _empty_array_cmd_indexes; + + bool _valid = true; +}; + +class QueuedReplies { +public: + QueuedReplies() = default; + + QueuedReplies(const QueuedReplies &) = delete; + QueuedReplies& operator=(const QueuedReplies &) = delete; + + QueuedReplies(QueuedReplies &&) = default; + QueuedReplies& operator=(QueuedReplies &&) = default; + + ~QueuedReplies() = default; + + std::size_t size() const; + + redisReply& get(std::size_t idx); + + template + Result get(std::size_t idx); + + template + void get(std::size_t idx, Output output); + +private: + template + friend class QueuedRedis; + + explicit QueuedReplies(std::vector replies) : _replies(std::move(replies)) {} + + void _index_check(std::size_t idx) const; + + std::vector _replies; +}; + +} + +} + +#include "queued_redis.hpp" + +#endif // end SEWENEW_REDISPLUSPLUS_QUEUED_REDIS_H diff --git a/ext/redis-plus-plus-1.3.3/install/ubuntu22.04/arm64/include/sw/redis++/queued_redis.hpp b/ext/redis-plus-plus-1.3.3/install/ubuntu22.04/arm64/include/sw/redis++/queued_redis.hpp new file mode 100644 index 000000000..d2865e46e --- /dev/null +++ b/ext/redis-plus-plus-1.3.3/install/ubuntu22.04/arm64/include/sw/redis++/queued_redis.hpp @@ -0,0 +1,275 @@ +/************************************************************************** + Copyright (c) 2017 sewenew + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + *************************************************************************/ + +#ifndef SEWENEW_REDISPLUSPLUS_QUEUED_REDIS_HPP +#define SEWENEW_REDISPLUSPLUS_QUEUED_REDIS_HPP + +namespace sw { + +namespace redis { + +template +template +QueuedRedis::QueuedRedis(const ConnectionPoolSPtr &pool, + bool new_connection, + Args &&...args) : + _new_connection(new_connection), + _impl(std::forward(args)...) { + assert(pool); + + if (_new_connection) { + _connection_pool = std::make_shared(pool->clone()); + } else { + // Create a connection from the origin pool. + _connection_pool = pool; + } +} + +template +QueuedRedis::~QueuedRedis() { + try { + _clean_up(); + } catch (const Error &e) { + // Ensure the destructor does not throw + } +} + +template +Redis QueuedRedis::redis() { + _sanity_check(); + + assert(_guarded_connection); + + return Redis(_guarded_connection); +} + +template +template +auto QueuedRedis::command(Cmd cmd, Args &&...args) + -> typename std::enable_if::value, + QueuedRedis&>::type { + try { + _sanity_check(); + + _impl.command(_connection(), cmd, std::forward(args)...); + + ++_cmd_num; + } catch (const Error &e) { + _invalidate(); + throw; + } + + return *this; +} + +template +template +QueuedRedis& QueuedRedis::command(const StringView &cmd_name, Args &&...args) { + auto cmd = [](Connection &connection, const StringView &cmd_name, Args &&...args) { + CmdArgs cmd_args; + cmd_args.append(cmd_name, std::forward(args)...); + connection.send(cmd_args); + }; + + return command(cmd, cmd_name, std::forward(args)...); +} + +template +template +auto QueuedRedis::command(Input first, Input last) + -> typename std::enable_if::value, QueuedRedis&>::type { + if (first == last) { + throw Error("command: empty range"); + } + + auto cmd = [](Connection &connection, Input first, Input last) { + CmdArgs cmd_args; + while (first != last) { + cmd_args.append(*first); + ++first; + } + connection.send(cmd_args); + }; + + return command(cmd, first, last); +} + +template +QueuedReplies QueuedRedis::exec() { + try { + _sanity_check(); + + auto replies = _impl.exec(_connection(), _cmd_num); + + _rewrite_replies(replies); + + _reset(); + + return QueuedReplies(std::move(replies)); + } catch (const WatchError &e) { + // In this case, we only clear some states and keep the connection, + // so that user can retry the transaction. + _reset(false); + throw; + } catch (const Error &e) { + _invalidate(); + throw; + } +} + +template +void QueuedRedis::discard() { + try { + _sanity_check(); + + _impl.discard(_connection(), _cmd_num); + + _reset(); + } catch (const Error &e) { + _invalidate(); + throw; + } +} + +template +Connection& QueuedRedis::_connection() { + assert(_valid); + + if (!_guarded_connection) { + _guarded_connection = std::make_shared(_connection_pool); + } + + return _guarded_connection->connection(); +} + +template +void QueuedRedis::_sanity_check() { + if (!_valid) { + throw Error("Not in valid state"); + } + + if (_connection().broken()) { + throw Error("Connection is broken"); + } +} + +template +inline void QueuedRedis::_reset(bool reset_connection) { + if (reset_connection && !_new_connection) { + _return_connection(); + } + + _cmd_num = 0; + + _set_cmd_indexes.clear(); + + _empty_array_cmd_indexes.clear(); +} + +template +inline void QueuedRedis::_return_connection() { + if (_guarded_connection.use_count() == 1) { + // If no one else holding the connection, return it back to pool. + // Instead, if some other `Redis` object holds the connection, + // e.g. `auto redis = transaction.redis();`, we cannot return the connection. + _guarded_connection.reset(); + } +} + +template +void QueuedRedis::_invalidate() { + _valid = false; + + _clean_up(); + + _reset(); +} + +template +void QueuedRedis::_clean_up() { + if (_guarded_connection && !_new_connection) { + // Something bad happened, we need to close the current connection + // before returning it back to pool. + _guarded_connection->connection().invalidate(); + } +} + +template +void QueuedRedis::_rewrite_replies(std::vector &replies) const { + _rewrite_replies(_set_cmd_indexes, reply::rewrite_set_reply, replies); + + _rewrite_replies(_empty_array_cmd_indexes, reply::rewrite_empty_array_reply, replies); +} + +template +template +void QueuedRedis::_rewrite_replies(const std::vector &indexes, + Func rewriter, + std::vector &replies) const { + for (auto idx : indexes) { + assert(idx < replies.size()); + + auto &reply = replies[idx]; + + assert(reply); + + rewriter(*reply); + } +} + +inline std::size_t QueuedReplies::size() const { + return _replies.size(); +} + +inline redisReply& QueuedReplies::get(std::size_t idx) { + _index_check(idx); + + auto &reply = _replies[idx]; + + assert(reply); + + if (reply::is_error(*reply)) { + throw_error(*reply); + } + + return *reply; +} + +template +inline Result QueuedReplies::get(std::size_t idx) { + auto &reply = get(idx); + + return reply::parse(reply); +} + +template +inline void QueuedReplies::get(std::size_t idx, Output output) { + auto &reply = get(idx); + + reply::to_array(reply, output); +} + +inline void QueuedReplies::_index_check(std::size_t idx) const { + if (idx >= size()) { + throw Error("Out of range"); + } +} + +} + +} + +#endif // end SEWENEW_REDISPLUSPLUS_QUEUED_REDIS_HPP diff --git a/ext/redis-plus-plus-1.3.3/install/ubuntu22.04/arm64/include/sw/redis++/redis++.h b/ext/redis-plus-plus-1.3.3/install/ubuntu22.04/arm64/include/sw/redis++/redis++.h new file mode 100644 index 000000000..0da0ebb16 --- /dev/null +++ b/ext/redis-plus-plus-1.3.3/install/ubuntu22.04/arm64/include/sw/redis++/redis++.h @@ -0,0 +1,25 @@ +/************************************************************************** + Copyright (c) 2017 sewenew + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + *************************************************************************/ + +#ifndef SEWENEW_REDISPLUSPLUS_REDISPLUSPLUS_H +#define SEWENEW_REDISPLUSPLUS_REDISPLUSPLUS_H + +#include "redis.h" +#include "redis_cluster.h" +#include "queued_redis.h" +#include "sentinel.h" + +#endif // end SEWENEW_REDISPLUSPLUS_REDISPLUSPLUS_H diff --git a/ext/redis-plus-plus-1.3.3/install/ubuntu22.04/arm64/include/sw/redis++/redis.h b/ext/redis-plus-plus-1.3.3/install/ubuntu22.04/arm64/include/sw/redis++/redis.h new file mode 100644 index 000000000..1333e6b68 --- /dev/null +++ b/ext/redis-plus-plus-1.3.3/install/ubuntu22.04/arm64/include/sw/redis++/redis.h @@ -0,0 +1,3631 @@ +/************************************************************************** + Copyright (c) 2017 sewenew + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + *************************************************************************/ + +#ifndef SEWENEW_REDISPLUSPLUS_REDIS_H +#define SEWENEW_REDISPLUSPLUS_REDIS_H + +#include +#include +#include +#include +#include +#include "connection_pool.h" +#include "reply.h" +#include "command_options.h" +#include "utils.h" +#include "subscriber.h" +#include "pipeline.h" +#include "transaction.h" +#include "sentinel.h" + +namespace sw { + +namespace redis { + +template +class QueuedRedis; + +using Transaction = QueuedRedis; + +using Pipeline = QueuedRedis; + +class Redis { +public: + /// @brief Construct `Redis` instance with connection options and connection pool options. + /// @param connection_opts Connection options. + /// @param pool_opts Connection pool options. + /// @see `ConnectionOptions` + /// @see `ConnectionPoolOptions` + /// @see https://github.com/sewenew/redis-plus-plus#connection + explicit Redis(const ConnectionOptions &connection_opts, + const ConnectionPoolOptions &pool_opts = {}) : + _pool(std::make_shared(pool_opts, connection_opts)) {} + + /// @brief Construct `Redis` instance with URI. + /// @param uri URI, e.g. 'tcp://127.0.0.1', 'tcp://127.0.0.1:6379', or 'unix://path/to/socket'. + /// Full URI scheme: 'tcp://[[username:]password@]host[:port][/db]' or + /// unix://[[username:]password@]path-to-unix-domain-socket[/db] + /// @see https://github.com/sewenew/redis-plus-plus/issues/37 + /// @see https://github.com/sewenew/redis-plus-plus#connection + explicit Redis(const std::string &uri); + + /// @brief Construct `Redis` instance with Redis sentinel, i.e. get node info from sentinel. + /// @param sentinel `Sentinel` instance. + /// @param master_name Name of master node. + /// @param role Connect to master node or slave node. + /// - Role::MASTER: Connect to master node. + /// - Role::SLAVE: Connect to slave node. + /// @param connection_opts Connection options. + /// @param pool_opts Connection pool options. + /// @see `Sentinel` + /// @see `Role` + /// @see https://github.com/sewenew/redis-plus-plus#redis-sentinel + Redis(const std::shared_ptr &sentinel, + const std::string &master_name, + Role role, + const ConnectionOptions &connection_opts, + const ConnectionPoolOptions &pool_opts = {}) : + _pool(std::make_shared(SimpleSentinel(sentinel, master_name, role), + pool_opts, + connection_opts)) {} + + /// @brief `Redis` is not copyable. + Redis(const Redis &) = delete; + + /// @brief `Redis` is not copyable. + Redis& operator=(const Redis &) = delete; + + /// @brief `Redis` is movable. + Redis(Redis &&) = default; + + /// @brief `Redis` is movable. + Redis& operator=(Redis &&) = default; + + /// @brief Create a pipeline. + /// @param new_connection Whether creating a `Pipeline` object in a new connection. + /// @return The created pipeline. + /// @note Instead of picking a connection from the underlying connection pool, + /// this method will create a new connection to Redis. So it's not a cheap operation, + /// and you'd better reuse the returned object as much as possible. + /// @see https://github.com/sewenew/redis-plus-plus#pipeline + Pipeline pipeline(bool new_connection = true); + + /// @brief Create a transaction. + /// @param piped Whether commands in a transaction should be sent in a pipeline to reduce RTT. + /// @param new_connection Whether creating a `Pipeline` object in a new connection. + /// @return The created transaction. + /// @note Instead of picking a connection from the underlying connection pool, + /// this method will create a new connection to Redis. So it's not a cheap operation, + /// and you'd better reuse the returned object as much as possible. + /// @see https://github.com/sewenew/redis-plus-plus#transaction + Transaction transaction(bool piped = false, bool new_connection = true); + + /// @brief Create a subscriber. + /// @return The created subscriber. + /// @note Instead of picking a connection from the underlying connection pool, + /// this method will create a new connection to Redis. So it's not a cheap operation, + /// and you'd better reuse the returned object as much as possible. + /// @see https://github.com/sewenew/redis-plus-plus#publishsubscribe + Subscriber subscriber(); + + template + auto command(Cmd cmd, Args &&...args) + -> typename std::enable_if::value, ReplyUPtr>::type; + + template + auto command(const StringView &cmd_name, Args &&...args) + -> typename std::enable_if::type>::value, + ReplyUPtr>::type; + + template + auto command(const StringView &cmd_name, Args &&...args) + -> typename std::enable_if::type>::value, void>::type; + + template + Result command(const StringView &cmd_name, Args &&...args); + + template + auto command(Input first, Input last) + -> typename std::enable_if::value, ReplyUPtr>::type; + + template + auto command(Input first, Input last) + -> typename std::enable_if::value, Result>::type; + + template + auto command(Input first, Input last, Output output) + -> typename std::enable_if::value, void>::type; + + // CONNECTION commands. + + /// @brief Send password to Redis. + /// @param password Password. + /// @note Normally, you should not call this method. + /// Instead, you should set password with `ConnectionOptions` or URI. + /// @see https://redis.io/commands/auth + void auth(const StringView &password); + + /// @brief Send user and password to Redis. + /// @param user User name. + /// @param password Password. + /// @note Normally, you should not call this method. + /// Instead, you should set password with `ConnectionOptions` or URI. + /// Also this overload only works with Redis 6.0 or later. + /// @see https://redis.io/commands/auth + void auth(const StringView &user, const StringView &password); + + /// @brief Ask Redis to return the given message. + /// @param msg Message to be sent. + /// @return Return the given message. + /// @see https://redis.io/commands/echo + std::string echo(const StringView &msg); + + /// @brief Test if the connection is alive. + /// @return Always return *PONG*. + /// @see https://redis.io/commands/ping + std::string ping(); + + /// @brief Test if the connection is alive. + /// @param msg Message sent to Redis. + /// @return Return the given message. + /// @see https://redis.io/commands/ping + std::string ping(const StringView &msg); + + // After sending QUIT, only the current connection will be close, while + // other connections in the pool is still open. This is a strange behavior. + // So we DO NOT support the QUIT command. If you want to quit connection to + // server, just destroy the Redis object. + // + // void quit(); + + // We get a connection from the pool, and send the SELECT command to switch + // to a specified DB. However, when we try to send other commands to the + // given DB, we might get a different connection from the pool, and these + // commands, in fact, work on other DB. e.g. + // + // redis.select(1); // get a connection from the pool and switch to the 1th DB + // redis.get("key"); // might get another connection from the pool, + // // and try to get 'key' on the default DB + // + // Obviously, this is NOT what we expect. So we DO NOT support SELECT command. + // In order to select a DB, we can specify the DB index with the ConnectionOptions. + // + // However, since Pipeline and Transaction always send multiple commands on a + // single connection, these two classes have a *select* method. + // + // void select(long long idx); + + /// @brief Swap two Redis databases. + /// @param idx1 The index of the first database. + /// @param idx2 The index of the second database. + /// @see https://redis.io/commands/swapdb + void swapdb(long long idx1, long long idx2); + + // SERVER commands. + + /// @brief Rewrite AOF in the background. + /// @see https://redis.io/commands/bgrewriteaof + void bgrewriteaof(); + + /// @brief Save database in the background. + /// @see https://redis.io/commands/bgsave + void bgsave(); + + /// @brief Get the size of the currently selected database. + /// @return Number of keys in currently selected database. + /// @see https://redis.io/commands/dbsize + long long dbsize(); + + /// @brief Remove keys of all databases. + /// @param async Whether flushing databases asynchronously, i.e. without blocking the server. + /// @see https://redis.io/commands/flushall + void flushall(bool async = false); + + /// @brief Remove keys of current databases. + /// @param async Whether flushing databases asynchronously, i.e. without blocking the server. + /// @see https://redis.io/commands/flushdb + void flushdb(bool async = false); + + /// @brief Get the info about the server. + /// @return Server info. + /// @see https://redis.io/commands/info + std::string info(); + + /// @brief Get the info about the server on the given section. + /// @param section Section. + /// @return Server info. + /// @see https://redis.io/commands/info + std::string info(const StringView §ion); + + /// @brief Get the UNIX timestamp in seconds, at which the database was saved successfully. + /// @return The last saving time. + /// @see https://redis.io/commands/lastsave + long long lastsave(); + + /// @brief Save databases into RDB file **synchronously**, i.e. block the server during saving. + /// @see https://redis.io/commands/save + void save(); + + // KEY commands. + + /// @brief Delete the given key. + /// @param key Key. + /// @return Number of keys removed. + /// @retval 1 If the key exists, and has been removed. + /// @retval 0 If the key does not exist. + /// @see https://redis.io/commands/del + long long del(const StringView &key); + + /// @brief Delete the given list of keys. + /// @param first Iterator to the first key in the range. + /// @param last Off-the-end iterator to the given range. + /// @return Number of keys removed. + /// @see https://redis.io/commands/del + template + long long del(Input first, Input last); + + /// @brief Delete the given list of keys. + /// @param il Initializer list of keys to be deleted. + /// @return Number of keys removed. + /// @see https://redis.io/commands/del + template + long long del(std::initializer_list il) { + return del(il.begin(), il.end()); + } + + /// @brief Get the serialized valued stored at key. + /// @param key Key. + /// @return The serialized value. + /// @note If key does not exist, `dump` returns `OptionalString{}` (`std::nullopt`). + /// @see https://redis.io/commands/dump + OptionalString dump(const StringView &key); + + /// @brief Check if the given key exists. + /// @param key Key. + /// @return Whether the given key exists. + /// @retval 1 If key exists. + /// @retval 0 If key does not exist. + /// @see https://redis.io/commands/exists + long long exists(const StringView &key); + + /// @brief Check if the given keys exist. + /// @param first Iterator to the first key. + /// @param last Off-the-end iterator to the given range. + /// @return Number of keys existing. + /// @see https://redis.io/commands/exists + template + long long exists(Input first, Input last); + + /// @brief Check if the given keys exist. + /// @param il Initializer list of keys to be checked. + /// @return Number of keys existing. + /// @see https://redis.io/commands/exists + template + long long exists(std::initializer_list il) { + return exists(il.begin(), il.end()); + } + + /// @brief Set a timeout on key. + /// @param key Key. + /// @param timeout Timeout in seconds. + /// @return Whether timeout has been set. + /// @retval true If timeout has been set. + /// @retval false If key does not exist. + /// @see https://redis.io/commands/expire + bool expire(const StringView &key, long long timeout); + + /// @brief Set a timeout on key. + /// @param key Key. + /// @param timeout Timeout in seconds. + /// @return Whether timeout has been set. + /// @retval true If timeout has been set. + /// @retval false If key does not exist. + /// @see https://redis.io/commands/expire + bool expire(const StringView &key, const std::chrono::seconds &timeout); + + /// @brief Set a timeout on key, i.e. expire the key at a future time point. + /// @param key Key. + /// @param timestamp Time in seconds since UNIX epoch. + /// @return Whether timeout has been set. + /// @retval true If timeout has been set. + /// @retval false If key does not exist. + /// @see https://redis.io/commands/expireat + bool expireat(const StringView &key, long long timestamp); + + /// @brief Set a timeout on key, i.e. expire the key at a future time point. + /// @param key Key. + /// @param timestamp Time in seconds since UNIX epoch. + /// @return Whether timeout has been set. + /// @retval true If timeout has been set. + /// @retval false If key does not exist. + /// @see https://redis.io/commands/expireat + bool expireat(const StringView &key, + const std::chrono::time_point &tp); + + /// @brief Get keys matching the given pattern. + /// @param pattern Pattern. + /// @param output Output iterator to the destination where the returned keys are stored. + /// @note It's always a bad idea to call `keys`, since it might block Redis for a long time, + /// especially when the data set is very big. + /// @see `Redis::scan` + /// @see https://redis.io/commands/keys + template + void keys(const StringView &pattern, Output output); + + /// @brief Move a key to the given database. + /// @param key Key. + /// @param db The destination database. + /// @return Whether key has been moved. + /// @retval true If key has been moved. + /// @retval false If key was not moved. + /// @see https://redis.io/commands/move + bool move(const StringView &key, long long db); + + /// @brief Remove timeout on key. + /// @param key Key. + /// @return Whether timeout has been removed. + /// @retval true If timeout has been removed. + /// @retval false If key does not exist, or does not have an associated timeout. + /// @see https://redis.io/commands/persist + bool persist(const StringView &key); + + /// @brief Set a timeout on key. + /// @param key Key. + /// @param timeout Timeout in milliseconds. + /// @return Whether timeout has been set. + /// @retval true If timeout has been set. + /// @retval false If key does not exist. + /// @see https://redis.io/commands/pexpire + bool pexpire(const StringView &key, long long timeout); + + /// @brief Set a timeout on key. + /// @param key Key. + /// @param timeout Timeout in milliseconds. + /// @return Whether timeout has been set. + /// @retval true If timeout has been set. + /// @retval false If key does not exist. + /// @see https://redis.io/commands/pexpire + bool pexpire(const StringView &key, const std::chrono::milliseconds &timeout); + + /// @brief Set a timeout on key, i.e. expire the key at a future time point. + /// @param key Key. + /// @param timestamp Time in milliseconds since UNIX epoch. + /// @return Whether timeout has been set. + /// @retval true If timeout has been set. + /// @retval false If key does not exist. + /// @see https://redis.io/commands/pexpireat + bool pexpireat(const StringView &key, long long timestamp); + + /// @brief Set a timeout on key, i.e. expire the key at a future time point. + /// @param key Key. + /// @param timestamp Time in milliseconds since UNIX epoch. + /// @return Whether timeout has been set. + /// @retval true If timeout has been set. + /// @retval false If key does not exist. + /// @see https://redis.io/commands/pexpireat + bool pexpireat(const StringView &key, + const std::chrono::time_point &tp); + + /// @brief Get the TTL of a key in milliseconds. + /// @param key Key. + /// @return TTL of the key in milliseconds. + /// @see https://redis.io/commands/pttl + long long pttl(const StringView &key); + + /// @brief Get a random key from current database. + /// @return A random key. + /// @note If the database is empty, `randomkey` returns `OptionalString{}` (`std::nullopt`). + /// @see https://redis.io/commands/randomkey + OptionalString randomkey(); + + /// @brief Rename `key` to `newkey`. + /// @param key Key to be renamed. + /// @param newkey The new name of the key. + /// @see https://redis.io/commands/rename + void rename(const StringView &key, const StringView &newkey); + + /// @brief Rename `key` to `newkey` if `newkey` does not exist. + /// @param key Key to be renamed. + /// @param newkey The new name of the key. + /// @return Whether key has been renamed. + /// @retval true If key has been renamed. + /// @retval false If newkey already exists. + /// @see https://redis.io/commands/renamenx + bool renamenx(const StringView &key, const StringView &newkey); + + /// @brief Create a key with the value obtained by `Redis::dump`. + /// @param key Key. + /// @param val Value obtained by `Redis::dump`. + /// @param ttl Timeout of the created key in milliseconds. If `ttl` is 0, set no timeout. + /// @param replace Whether to overwrite an existing key. + /// If `replace` is `true` and key already exists, throw an exception. + /// @see https://redis.io/commands/restore + void restore(const StringView &key, + const StringView &val, + long long ttl, + bool replace = false); + + /// @brief Create a key with the value obtained by `Redis::dump`. + /// @param key Key. + /// @param val Value obtained by `Redis::dump`. + /// @param ttl Timeout of the created key in milliseconds. If `ttl` is 0, set no timeout. + /// @param replace Whether to overwrite an existing key. + /// If `replace` is `true` and key already exists, throw an exception. + /// @see https://redis.io/commands/restore + void restore(const StringView &key, + const StringView &val, + const std::chrono::milliseconds &ttl = std::chrono::milliseconds{0}, + bool replace = false); + + // TODO: sort + + /// @brief Scan keys of the database matching the given pattern. + /// + /// Example: + /// @code{.cpp} + /// auto cursor = 0LL; + /// std::unordered_set keys; + /// while (true) { + /// cursor = redis.scan(cursor, "pattern:*", 10, std::inserter(keys, keys.begin())); + /// if (cursor == 0) { + /// break; + /// } + /// } + /// @endcode + /// @param cursor Cursor. + /// @param pattern Pattern of the keys to be scanned. + /// @param count A hint for how many keys to be scanned. + /// @param output Output iterator to the destination where the returned keys are stored. + /// @return The cursor to be used for the next scan operation. + /// @see https://redis.io/commands/scan + /// TODO: support the TYPE option for Redis 6.0. + template + long long scan(long long cursor, + const StringView &pattern, + long long count, + Output output); + + /// @brief Scan all keys of the database. + /// @param cursor Cursor. + /// @param output Output iterator to the destination where the returned keys are stored. + /// @return The cursor to be used for the next scan operation. + /// @see https://redis.io/commands/scan + template + long long scan(long long cursor, + Output output); + + /// @brief Scan keys of the database matching the given pattern. + /// @param cursor Cursor. + /// @param pattern Pattern of the keys to be scanned. + /// @param output Output iterator to the destination where the returned keys are stored. + /// @return The cursor to be used for the next scan operation. + /// @see https://redis.io/commands/scan + template + long long scan(long long cursor, + const StringView &pattern, + Output output); + + /// @brief Scan keys of the database matching the given pattern. + /// @param cursor Cursor. + /// @param count A hint for how many keys to be scanned. + /// @param output Output iterator to the destination where the returned keys are stored. + /// @return The cursor to be used for the next scan operation. + /// @see https://redis.io/commands/scan + template + long long scan(long long cursor, + long long count, + Output output); + + /// @brief Update the last access time of the given key. + /// @param key Key. + /// @return Whether last access time of the key has been updated. + /// @retval 1 If key exists, and last access time has been updated. + /// @retval 0 If key does not exist. + /// @see https://redis.io/commands/touch + long long touch(const StringView &key); + + /// @brief Update the last access time of the given key. + /// @param first Iterator to the first key to be touched. + /// @param last Off-the-end iterator to the given range. + /// @return Whether last access time of the key has been updated. + /// @retval 1 If key exists, and last access time has been updated. + /// @retval 0 If key does not exist. + /// @see https://redis.io/commands/touch + template + long long touch(Input first, Input last); + + /// @brief Update the last access time of the given key. + /// @param il Initializer list of keys to be touched. + /// @return Whether last access time of the key has been updated. + /// @retval 1 If key exists, and last access time has been updated. + /// @retval 0 If key does not exist. + /// @see https://redis.io/commands/touch + template + long long touch(std::initializer_list il) { + return touch(il.begin(), il.end()); + } + + /// @brief Get the remaining Time-To-Live of a key. + /// @param key Key. + /// @return TTL in seconds. + /// @retval TTL If the key has a timeout. + /// @retval -1 If the key exists but does not have a timeout. + /// @retval -2 If the key does not exist. + /// @note In Redis 2.6 or older, `ttl` returns -1 if the key does not exist, + /// or if the key exists but does not have a timeout. + /// @see https://redis.io/commands/ttl + long long ttl(const StringView &key); + + /// @brief Get the type of the value stored at key. + /// @param key Key. + /// @return The type of the value. + /// @see https://redis.io/commands/type + std::string type(const StringView &key); + + /// @brief Remove the given key asynchronously, i.e. without blocking Redis. + /// @param key Key. + /// @return Whether the key has been removed. + /// @retval 1 If key exists, and has been removed. + /// @retval 0 If key does not exist. + /// @see https://redis.io/commands/unlink + long long unlink(const StringView &key); + + /// @brief Remove the given keys asynchronously, i.e. without blocking Redis. + /// @param first Iterator to the first key in the given range. + /// @param last Off-the-end iterator to the given range. + /// @return Number of keys that have been removed. + /// @see https://redis.io/commands/unlink + template + long long unlink(Input first, Input last); + + /// @brief Remove the given keys asynchronously, i.e. without blocking Redis. + /// @param il Initializer list of keys to be unlinked. + /// @return Number of keys that have been removed. + /// @see https://redis.io/commands/unlink + template + long long unlink(std::initializer_list il) { + return unlink(il.begin(), il.end()); + } + + /// @brief Wait until previous write commands are successfully replicated to at + /// least the specified number of replicas or the given timeout has been reached. + /// @param numslaves Number of replicas. + /// @param timeout Timeout in milliseconds. If timeout is 0ms, wait forever. + /// @return Number of replicas that have been successfully replicated these write commands. + /// @note The return value might be less than `numslaves`, because timeout has been reached. + /// @see https://redis.io/commands/wait + long long wait(long long numslaves, long long timeout); + + /// @brief Wait until previous write commands are successfully replicated to at + /// least the specified number of replicas or the given timeout has been reached. + /// @param numslaves Number of replicas. + /// @param timeout Timeout in milliseconds. If timeout is 0ms, wait forever. + /// @return Number of replicas that have been successfully replicated these write commands. + /// @note The return value might be less than `numslaves`, because timeout has been reached. + /// @see https://redis.io/commands/wait + /// TODO: Support default parameter for `timeout` to wait forever. + long long wait(long long numslaves, const std::chrono::milliseconds &timeout); + + // STRING commands. + + /// @brief Append the given string to the string stored at key. + /// @param key Key. + /// @param str String to be appended. + /// @return The length of the string after the append operation. + /// @see https://redis.io/commands/append + long long append(const StringView &key, const StringView &str); + + /// @brief Get the number of bits that have been set for the given range of the string. + /// @param key Key. + /// @param start Start index (inclusive) of the range. 0 means the beginning of the string. + /// @param end End index (inclusive) of the range. -1 means the end of the string. + /// @return Number of bits that have been set. + /// @note The index can be negative to index from the end of the string. + /// @see https://redis.io/commands/bitcount + long long bitcount(const StringView &key, long long start = 0, long long end = -1); + + /// @brief Do bit operation on the string stored at `key`, and save the result to `destination`. + /// @param op Bit operations. + /// @param destination The destination key where the result is saved. + /// @param key The key where the string to be operated is stored. + /// @return The length of the string saved at `destination`. + /// @see https://redis.io/commands/bitop + /// @see `BitOp` + long long bitop(BitOp op, const StringView &destination, const StringView &key); + + /// @brief Do bit operations on the strings stored at the given keys, + /// and save the result to `destination`. + /// @param op Bit operations. + /// @param destination The destination key where the result is saved. + /// @param first Iterator to the first key where the string to be operated is stored. + /// @param last Off-the-end iterator to the given range of keys. + /// @return The length of the string saved at `destination`. + /// @see https://redis.io/commands/bitop + /// @see `BitOp` + template + long long bitop(BitOp op, const StringView &destination, Input first, Input last); + + /// @brief Do bit operations on the strings stored at the given keys, + /// and save the result to `destination`. + /// @param op Bit operations. + /// @param destination The destination key where the result is saved. + /// @param il Initializer list of keys where the strings are operated. + /// @return The length of the string saved at `destination`. + /// @see https://redis.io/commands/bitop + /// @see `BitOp` + template + long long bitop(BitOp op, const StringView &destination, std::initializer_list il) { + return bitop(op, destination, il.begin(), il.end()); + } + + /// @brief Get the position of the first bit set to 0 or 1 in the given range of the string. + /// @param key Key. + /// @param bit 0 or 1. + /// @param start Start index (inclusive) of the range. 0 means the beginning of the string. + /// @param end End index (inclusive) of the range. -1 means the end of the string. + /// @return The position of the first bit set to 0 or 1. + /// @see https://redis.io/commands/bitpos + long long bitpos(const StringView &key, + long long bit, + long long start = 0, + long long end = -1); + + /// @brief Decrement the integer stored at key by 1. + /// @param key Key. + /// @return The value after the decrement. + /// @see https://redis.io/commands/decr + long long decr(const StringView &key); + + /// @brief Decrement the integer stored at key by `decrement`. + /// @param key Key. + /// @param decrement Decrement. + /// @return The value after the decrement. + /// @see https://redis.io/commands/decrby + long long decrby(const StringView &key, long long decrement); + + /// @brief Get the string value stored at key. + /// + /// Example: + /// @code{.cpp} + /// auto val = redis.get("key"); + /// if (val) + /// std::cout << *val << std::endl; + /// else + /// std::cout << "key not exist" << std::endl; + /// @endcode + /// @param key Key. + /// @return The value stored at key. + /// @note If key does not exist, `get` returns `OptionalString{}` (`std::nullopt`). + /// @see https://redis.io/commands/get + OptionalString get(const StringView &key); + + /// @brief Get the bit value at offset in the string. + /// @param key Key. + /// @param offset Offset. + /// @return The bit value. + /// @see https://redis.io/commands/getbit + long long getbit(const StringView &key, long long offset); + + /// @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. + /// @param end End index (inclusive) of the range. -1 means the end of the string. + /// @return The substring in range [start, end]. If key does not exist, return an empty string. + /// @see https://redis.io/commands/getrange + std::string getrange(const StringView &key, long long start, long long end); + + /// @brief Atomically set the string stored at `key` to `val`, and return the old value. + /// @param key Key. + /// @param val Value to be set. + /// @return The old value stored at key. + /// @note If key does not exist, `getset` returns `OptionalString{}` (`std::nullopt`). + /// @see https://redis.io/commands/getset + /// @see `OptionalString` + OptionalString getset(const StringView &key, const StringView &val); + + /// @brief Increment the integer stored at key by 1. + /// @param key Key. + /// @return The value after the increment. + /// @see https://redis.io/commands/incr + long long incr(const StringView &key); + + /// @brief Increment the integer stored at key by `increment`. + /// @param key Key. + /// @param increment Increment. + /// @return The value after the increment. + /// @see https://redis.io/commands/incrby + long long incrby(const StringView &key, long long increment); + + /// @brief Increment the floating point number stored at key by `increment`. + /// @param key Key. + /// @param increment Increment. + /// @return The value after the increment. + /// @see https://redis.io/commands/incrbyfloat + double incrbyfloat(const StringView &key, double increment); + + /// @brief Get the values of multiple keys atomically. + /// + /// Example: + /// @code{.cpp} + /// std::vector keys = {"k1", "k2", "k3"}; + /// std::vector vals; + /// redis.mget(keys.begin(), keys.end(), std::back_inserter(vals)); + /// for (const auto &val : vals) { + /// if (val) + /// std::cout << *val << std::endl; + /// else + /// std::cout << "key does not exist" << std::endl; + /// } + /// @endcode + /// @param first Iterator to the first key of the given range. + /// @param last Off-the-end iterator to the given range. + /// @param output Output iterator to the destination where the values are stored. + /// @note The destination should be a container of `OptionalString` type, + /// since the given key might not exist (in this case, the value of the corresponding + /// key is `OptionalString{}` (`std::nullopt`)). + /// @see https://redis.io/commands/mget + template + void mget(Input first, Input last, Output output); + + /// @brief Get the values of multiple keys atomically. + /// + /// Example: + /// @code{.cpp} + /// std::vector vals; + /// redis.mget({"k1", "k2", "k3"}, std::back_inserter(vals)); + /// for (const auto &val : vals) { + /// if (val) + /// std::cout << *val << std::endl; + /// else + /// std::cout << "key does not exist" << std::endl; + /// } + /// @endcode + /// @param il Initializer list of keys. + /// @param output Output iterator to the destination where the values are stored. + /// @note The destination should be a container of `OptionalString` type, + /// since the given key might not exist (in this case, the value of the corresponding + /// key is `OptionalString{}` (`std::nullopt`)). + /// @see https://redis.io/commands/mget + template + void mget(std::initializer_list il, Output output) { + mget(il.begin(), il.end(), output); + } + + /// @brief Set multiple key-value pairs. + /// + /// Example: + /// @code{.cpp} + /// std::vector> kvs1 = {{"k1", "v1"}, {"k2", "v2"}}; + /// redis.mset(kvs1.begin(), kvs1.end()); + /// std::unordered_map kvs2 = {{"k3", "v3"}, {"k4", "v4"}}; + /// redis.mset(kvs2.begin(), kvs2.end()); + /// @endcode + /// @param first Iterator to the first key-value pair. + /// @param last Off-the-end iterator to the given range. + /// @see https://redis.io/commands/mset + template + void mset(Input first, Input last); + + /// @brief Set multiple key-value pairs. + /// + /// Example: + /// @code{.cpp} + /// redis.mset({std::make_pair("k1", "v1"), std::make_pair("k2", "v2")}); + /// @endcode + /// @param il Initializer list of key-value pairs. + /// @see https://redis.io/commands/mset + template + void mset(std::initializer_list il) { + mset(il.begin(), il.end()); + } + + /// @brief Set the given key-value pairs if all specified keys do not exist. + /// + /// Example: + /// @code{.cpp} + /// std::vector> kvs1; + /// redis.msetnx(kvs1.begin(), kvs1.end()); + /// std::unordered_map kvs2; + /// redis.msetnx(kvs2.begin(), kvs2.end()); + /// @endcode + /// @param first Iterator to the first key-value pair. + /// @param last Off-the-end iterator of the given range. + /// @return Whether all keys have been set. + /// @retval true If all keys have been set. + /// @retval false If no key was set, i.e. at least one key already exist. + /// @see https://redis.io/commands/msetnx + template + bool msetnx(Input first, Input last); + + /// @brief Set the given key-value pairs if all specified keys do not exist. + /// + /// Example: + /// @code{.cpp} + /// redis.msetnx({make_pair("k1", "v1"), make_pair("k2", "v2")}); + /// @endcode + /// @param il Initializer list of key-value pairs. + /// @return Whether all keys have been set. + /// @retval true If all keys have been set. + /// @retval false If no key was set, i.e. at least one key already exist. + /// @see https://redis.io/commands/msetnx + template + bool msetnx(std::initializer_list il) { + return msetnx(il.begin(), il.end()); + } + + /// @brief Set key-value pair with the given timeout in milliseconds. + /// @param key Key. + /// @param ttl Time-To-Live in milliseconds. + /// @param val Value. + /// @see https://redis.io/commands/psetex + void psetex(const StringView &key, + long long ttl, + const StringView &val); + + /// @brief Set key-value pair with the given timeout in milliseconds. + /// @param key Key. + /// @param ttl Time-To-Live in milliseconds. + /// @param val Value. + /// @see https://redis.io/commands/psetex + void psetex(const StringView &key, + const std::chrono::milliseconds &ttl, + const StringView &val); + + /// @brief Set a key-value pair. + /// + /// Example: + /// @code{.cpp} + /// // Set a key-value pair. + /// redis.set("key", "value"); + /// // Set a key-value pair, and expire it after 10 seconds. + /// redis.set("key", "value", std::chrono::seconds(10)); + /// // Set a key-value pair with a timeout, only if the key already exists. + /// if (redis.set("key", "value", std::chrono::seconds(10), UpdateType::EXIST)) + /// std::cout << "OK" << std::endl; + /// else + /// std::cout << "key does not exist" << std::endl; + /// @endcode + /// @param key Key. + /// @param val Value. + /// @param ttl Timeout on the key. If `ttl` is 0ms, do not set timeout. + /// @param type Options for set command: + /// - UpdateType::EXIST: Set the key only if it already exists. + /// - UpdateType::NOT_EXIST: Set the key only if it does not exist. + /// - UpdateType::ALWAYS: Always set the key no matter whether it exists. + /// @return Whether the key has been set. + /// @retval true If the key has been set. + /// @retval false If the key was not set, because of the given option. + /// @see https://redis.io/commands/set + // TODO: Support KEEPTTL option for Redis 6.0 + bool set(const StringView &key, + const StringView &val, + const std::chrono::milliseconds &ttl = std::chrono::milliseconds(0), + UpdateType type = UpdateType::ALWAYS); + + // TODO: add SETBIT command. + + /// @brief Set key-value pair with the given timeout in seconds. + /// @param key Key. + /// @param ttl Time-To-Live in seconds. + /// @param val Value. + /// @see https://redis.io/commands/setex + void setex(const StringView &key, + long long ttl, + const StringView &val); + + /// @brief Set key-value pair with the given timeout in seconds. + /// @param key Key. + /// @param ttl Time-To-Live in seconds. + /// @param val Value. + /// @see https://redis.io/commands/setex + void setex(const StringView &key, + const std::chrono::seconds &ttl, + const StringView &val); + + /// @brief Set the key if it does not exist. + /// @param key Key. + /// @param val Value. + /// @return Whether the key has been set. + /// @retval true If the key has been set. + /// @retval false If the key was not set, i.e. the key already exists. + /// @see https://redis.io/commands/setnx + bool setnx(const StringView &key, const StringView &val); + + /// @brief Set the substring starting from `offset` to the given value. + /// @param key Key. + /// @param offset Offset. + /// @param val Value. + /// @return The length of the string after this operation. + /// @see https://redis.io/commands/setrange + long long setrange(const StringView &key, long long offset, const StringView &val); + + /// @brief Get the length of the string stored at key. + /// @param key Key. + /// @return The length of the string. + /// @note If key does not exist, `strlen` returns 0. + /// @see https://redis.io/commands/strlen + long long strlen(const StringView &key); + + // LIST commands. + + /// @brief Pop the first element of the list in a blocking way. + /// @param key Key where the list is stored. + /// @param timeout Timeout in seconds. 0 means block forever. + /// @return Key-element pair. + /// @note If list is empty and timeout reaches, return `OptionalStringPair{}` (`std::nullopt`). + /// @see `Redis::lpop` + /// @see https://redis.io/commands/blpop + OptionalStringPair blpop(const StringView &key, long long timeout); + + /// @brief Pop the first element of the list in a blocking way. + /// @param key Key where the list is stored. + /// @param timeout Timeout in seconds. 0 means block forever. + /// @return Key-element pair. + /// @note If list is empty and timeout reaches, return `OptionalStringPair{}` (`std::nullopt`). + /// @see `Redis::lpop` + /// @see https://redis.io/commands/blpop + OptionalStringPair blpop(const StringView &key, + const std::chrono::seconds &timeout = std::chrono::seconds{0}); + + /// @brief Pop the first element of multiple lists in a blocking way. + /// @param first Iterator to the first key. + /// @param last Off-the-end iterator to the key range. + /// @param timeout Timeout in seconds. 0 means block forever. + /// @return Key-element pair. + /// @note If all lists are empty and timeout reaches, return `OptionalStringPair{}` (`std::nullopt`). + /// @see `Redis::lpop` + /// @see https://redis.io/commands/blpop + template + OptionalStringPair blpop(Input first, Input last, long long timeout); + + /// @brief Pop the first element of multiple lists in a blocking way. + /// @param il Initializer list of keys. + /// @param timeout Timeout in seconds. 0 means block forever. + /// @return Key-element pair. + /// @note If all lists are empty and timeout reaches, return `OptionalStringPair{}` (`std::nullopt`). + /// @see `Redis::lpop` + /// @see https://redis.io/commands/blpop + template + OptionalStringPair blpop(std::initializer_list il, long long timeout) { + return blpop(il.begin(), il.end(), timeout); + } + + /// @brief Pop the first element of multiple lists in a blocking way. + /// @param first Iterator to the first key. + /// @param last Off-the-end iterator to the key range. + /// @param timeout Timeout in seconds. 0 means block forever. + /// @return Key-element pair. + /// @note If all lists are empty and timeout reaches, return `OptionalStringPair{}` (`std::nullopt`). + /// @see `Redis::lpop` + /// @see https://redis.io/commands/blpop + template + OptionalStringPair blpop(Input first, + Input last, + const std::chrono::seconds &timeout = std::chrono::seconds{0}); + + /// @brief Pop the first element of multiple lists in a blocking way. + /// @param il Initializer list of keys. + /// @param timeout Timeout in seconds. 0 means block forever. + /// @return Key-element pair. + /// @note If all lists are empty and timeout reaches, return `OptionalStringPair{}` (`std::nullopt`). + /// @see `Redis::lpop` + /// @see https://redis.io/commands/blpop + template + OptionalStringPair blpop(std::initializer_list il, + const std::chrono::seconds &timeout = std::chrono::seconds{0}) { + return blpop(il.begin(), il.end(), timeout); + } + + /// @brief Pop the last element of the list in a blocking way. + /// @param key Key where the list is stored. + /// @param timeout Timeout in seconds. 0 means block forever. + /// @return Key-element pair. + /// @note If list is empty and timeout reaches, return `OptionalStringPair{}` (`std::nullopt`). + /// @see `Redis::rpop` + /// @see https://redis.io/commands/brpop + OptionalStringPair brpop(const StringView &key, long long timeout); + + /// @brief Pop the last element of the list in a blocking way. + /// @param key Key where the list is stored. + /// @param timeout Timeout in seconds. 0 means block forever. + /// @return Key-element pair. + /// @note If list is empty and timeout reaches, return `OptionalStringPair{}` (`std::nullopt`). + /// @see `Redis::rpop` + /// @see https://redis.io/commands/brpop + OptionalStringPair brpop(const StringView &key, + const std::chrono::seconds &timeout = std::chrono::seconds{0}); + + /// @brief Pop the last element of multiple lists in a blocking way. + /// @param first Iterator to the first key. + /// @param last Off-the-end iterator to the key range. + /// @param timeout Timeout in seconds. 0 means block forever. + /// @return Key-element pair. + /// @note If all lists are empty and timeout reaches, return `OptionalStringPair{}` (`std::nullopt`). + /// @see `Redis::rpop` + /// @see https://redis.io/commands/brpop + template + OptionalStringPair brpop(Input first, Input last, long long timeout); + + /// @brief Pop the last element of multiple lists in a blocking way. + /// @param il Initializer list of lists. + /// @param timeout Timeout in seconds. 0 means block forever. + /// @return Key-element pair. + /// @note If all lists are empty and timeout reaches, return `OptionalStringPair{}` (`std::nullopt`). + /// @see `Redis::rpop` + /// @see https://redis.io/commands/brpop + template + OptionalStringPair brpop(std::initializer_list il, long long timeout) { + return brpop(il.begin(), il.end(), timeout); + } + + /// @brief Pop the last element of multiple lists in a blocking way. + /// @param first Iterator to the first list. + /// @param last Off-the-end iterator to the list range. + /// @param timeout Timeout in seconds. 0 means block forever. + /// @return Key-element pair. + /// @note If all lists are empty and timeout reaches, return `OptionalStringPair{}` (`std::nullopt`). + /// @see `Redis::rpop` + /// @see https://redis.io/commands/brpop + template + OptionalStringPair brpop(Input first, + Input last, + const std::chrono::seconds &timeout = std::chrono::seconds{0}); + + /// @brief Pop the last element of multiple lists in a blocking way. + /// @param il Initializer list of list keys. + /// @param timeout Timeout in seconds. 0 means block forever. + /// @return Key-element pair. + /// @note If all lists are empty and timeout reaches, return `OptionalStringPair{}` (`std::nullopt`). + /// @see `Redis::rpop` + /// @see https://redis.io/commands/brpop + template + OptionalStringPair brpop(std::initializer_list il, + const std::chrono::seconds &timeout = std::chrono::seconds{0}) { + return brpop(il.begin(), il.end(), timeout); + } + + /// @brief Pop last element of one list and push it to the left of another list in blocking way. + /// @param source Key of the source list. + /// @param destination Key of the destination list. + /// @param timeout Timeout. 0 means block forever. + /// @return The popped element. + /// @note If the source list does not exist, `brpoplpush` returns `OptionalString{}` (`std::nullopt`). + /// @see `Redis::rpoplpush` + /// @see https://redis.io/commands/brpoplpush + OptionalString brpoplpush(const StringView &source, + const StringView &destination, + long long timeout); + + /// @brief Pop last element of one list and push it to the left of another list in blocking way. + /// @param source Key of the source list. + /// @param destination Key of the destination list. + /// @param timeout Timeout. 0 means block forever. + /// @return The popped element. + /// @note If the source list does not exist, `brpoplpush` returns `OptionalString{}` (`std::nullopt`). + /// @see `Redis::rpoplpush` + /// @see https://redis.io/commands/brpoplpush + OptionalString brpoplpush(const StringView &source, + const StringView &destination, + const std::chrono::seconds &timeout = std::chrono::seconds{0}); + + /// @brief Get the element at the given index of the list. + /// @param key Key where the list is stored. + /// @param index Zero-base index, and -1 means the last element. + /// @return The element at the given index. + /// @see https://redis.io/commands/lindex + OptionalString lindex(const StringView &key, long long index); + + /// @brief Insert an element to a list before or after the pivot element. + /// + /// Example: + /// @code{.cpp} + /// // Insert 'hello' before 'world' + /// auto len = redis.linsert("list", InsertPosition::BEFORE, "world", "hello"); + /// if (len == -1) + /// std::cout << "there's no 'world' in the list" << std::endl; + /// else + /// std::cout << "after the operation, the length of the list is " << len << std::endl; + /// @endcode + /// @param key Key where the list is stored. + /// @param position Before or after the pivot element. + /// @param pivot The pivot value. The `pivot` is the value of the element, not the index. + /// @param val Element to be inserted. + /// @return The length of the list after the operation. + /// @note If the pivot value is not found, `linsert` returns -1. + /// @see `InsertPosition` + /// @see https://redis.io/commands/linsert + long long linsert(const StringView &key, + InsertPosition position, + const StringView &pivot, + const StringView &val); + + /// @brief Get the length of the list. + /// @param key Key where the list is stored. + /// @return The length of the list. + /// @see https://redis.io/commands/llen + long long llen(const StringView &key); + + /// @brief Pop the first element of the list. + /// + /// Example: + /// @code{.cpp} + /// auto element = redis.lpop("list"); + /// if (element) + /// std::cout << *element << std::endl; + /// else + /// std::cout << "list is empty, i.e. list does not exist" << std::endl; + /// @endcode + /// @param key Key where the list is stored. + /// @return The popped element. + /// @note If list is empty, i.e. key does not exist, return `OptionalString{}` (`std::nullopt`). + /// @see https://redis.io/commands/lpop + OptionalString lpop(const StringView &key); + + /// @brief Push an element to the beginning of the list. + /// @param key Key where the list is stored. + /// @param val Element to be pushed. + /// @return The length of the list after the operation. + /// @see https://redis.io/commands/lpush + long long lpush(const StringView &key, const StringView &val); + + /// @brief Push multiple elements to the beginning of the list. + /// + /// Example: + /// @code{.cpp} + /// std::vector elements = {"e1", "e2", "e3"}; + /// redis.lpush("list", elements.begin(), elements.end()); + /// @endcode + /// @param key Key where the list is stored. + /// @param first Iterator to the first element to be pushed. + /// @param last Off-the-end iterator to the given element range. + /// @return The length of the list after the operation. + /// @see https://redis.io/commands/lpush + template + long long lpush(const StringView &key, Input first, Input last); + + /// @brief Push multiple elements to the beginning of the list. + /// + /// Example: + /// @code{.cpp} + /// redis.lpush("list", {"e1", "e2", "e3"}); + /// @endcode + /// @param key Key where the list is stored. + /// @param il Initializer list of elements. + /// @return The length of the list after the operation. + /// @see https://redis.io/commands/lpush + template + long long lpush(const StringView &key, std::initializer_list il) { + return lpush(key, il.begin(), il.end()); + } + + /// @brief Push an element to the beginning of the list, only if the list already exists. + /// @param key Key where the list is stored. + /// @param val Element to be pushed. + /// @return The length of the list after the operation. + /// @see https://redis.io/commands/lpushx + // TODO: add a multiple elements overload. + long long lpushx(const StringView &key, const StringView &val); + + /// @brief Get elements in the given range of the given list. + /// + /// Example: + /// @code{.cpp} + /// std::vector elements; + /// // Save all elements of a Redis list to a vector of string. + /// redis.lrange("list", 0, -1, std::back_inserter(elements)); + /// @endcode + /// @param key Key where the list is stored. + /// @param start Start index of the range. Index can be negative, which mean index from the end. + /// @param stop End index of the range. + /// @param output Output iterator to the destination where the results are saved. + /// @see https://redis.io/commands/lrange + template + void lrange(const StringView &key, long long start, long long stop, Output output); + + /// @brief Remove the first `count` occurrences of elements equal to `val`. + /// @param key Key where the list is stored. + /// @param count Number of occurrences to be removed. + /// @param val Value. + /// @return Number of elements removed. + /// @note `count` can be positive, negative and 0. Check the reference for detail. + /// @see https://redis.io/commands/lrem + long long lrem(const StringView &key, long long count, const StringView &val); + + /// @brief Set the element at the given index to the specified value. + /// @param key Key where the list is stored. + /// @param index Index of the element to be set. + /// @param val Value. + /// @see https://redis.io/commands/lset + void lset(const StringView &key, long long index, const StringView &val); + + /// @brief Trim a list to keep only element in the given range. + /// @param key Key where the key is stored. + /// @param start Start of the index. + /// @param stop End of the index. + /// @see https://redis.io/commands/ltrim + void ltrim(const StringView &key, long long start, long long stop); + + /// @brief Pop the last element of a list. + /// @param key Key where the list is stored. + /// @return The popped element. + /// @note If the list is empty, i.e. key does not exist, `rpop` returns `OptionalString{}` (`std::nullopt`). + /// @see https://redis.io/commands/rpop + OptionalString rpop(const StringView &key); + + /// @brief Pop last element of one list and push it to the left of another list. + /// @param source Key of the source list. + /// @param destination Key of the destination list. + /// @return The popped element. + /// @note If the source list does not exist, `rpoplpush` returns `OptionalString{}` (`std::nullopt`). + /// @see https://redis.io/commands/brpoplpush + OptionalString rpoplpush(const StringView &source, const StringView &destination); + + /// @brief Push an element to the end of the list. + /// @param key Key where the list is stored. + /// @param val Element to be pushed. + /// @return The length of the list after the operation. + /// @see https://redis.io/commands/rpush + long long rpush(const StringView &key, const StringView &val); + + /// @brief Push multiple elements to the end of the list. + /// @param key Key where the list is stored. + /// @param first Iterator to the first element to be pushed. + /// @param last Off-the-end iterator to the given element range. + /// @return The length of the list after the operation. + /// @see https://redis.io/commands/rpush + template + long long rpush(const StringView &key, Input first, Input last); + + /// @brief Push multiple elements to the end of the list. + /// @param key Key where the list is stored. + /// @param il Initializer list of elements to be pushed. + /// @return The length of the list after the operation. + /// @see https://redis.io/commands/rpush + template + long long rpush(const StringView &key, std::initializer_list il) { + return rpush(key, il.begin(), il.end()); + } + + /// @brief Push an element to the end of the list, only if the list already exists. + /// @param key Key where the list is stored. + /// @param val Element to be pushed. + /// @return The length of the list after the operation. + /// @see https://redis.io/commands/rpushx + long long rpushx(const StringView &key, const StringView &val); + + // HASH commands. + + /// @brief Remove the given field from hash. + /// @param key Key where the hash is stored. + /// @param field Field to be removed. + /// @return Whether the field has been removed. + /// @retval 1 If the field exists, and has been removed. + /// @retval 0 If the field does not exist. + /// @see https://redis.io/commands/hdel + long long hdel(const StringView &key, const StringView &field); + + /// @brief Remove multiple fields from hash. + /// @param key Key where the hash is stored. + /// @param first Iterator to the first field to be removed. + /// @param last Off-the-end iterator to the given field range. + /// @return Number of fields that has been removed. + /// @see https://redis.io/commands/hdel + template + long long hdel(const StringView &key, Input first, Input last); + + /// @brief Remove multiple fields from hash. + /// @param key Key where the hash is stored. + /// @param il Initializer list of fields. + /// @return Number of fields that has been removed. + /// @see https://redis.io/commands/hdel + template + long long hdel(const StringView &key, std::initializer_list il) { + return hdel(key, il.begin(), il.end()); + } + + /// @brief Check if the given field exists in hash. + /// @param key Key where the hash is stored. + /// @param field Field. + /// @return Whether the field exists. + /// @retval true If the field exists in hash. + /// @retval false If the field does not exist. + /// @see https://redis.io/commands/hexists + bool hexists(const StringView &key, const StringView &field); + + /// @brief Get the value of the given field. + /// @param key Key where the hash is stored. + /// @param field Field. + /// @return Value of the given field. + /// @note If field does not exist, `hget` returns `OptionalString{}` (`std::nullopt`). + /// @see https://redis.io/commands/hget + OptionalString hget(const StringView &key, const StringView &field); + + /// @brief Get all field-value pairs of the given hash. + /// + /// Example: + /// @code{.cpp} + /// std::unordered_map results; + /// // Save all field-value pairs of a Redis hash to an unordered_map. + /// redis.hgetall("hash", std::inserter(results, results.begin())); + /// @endcode + /// @param key Key where the hash is stored. + /// @param output Output iterator to the destination where the result is saved. + /// @note It's always a bad idea to call `hgetall` on a large hash, since it will block Redis. + /// @see `Redis::hscan` + /// @see https://redis.io/commands/hgetall + template + void hgetall(const StringView &key, Output output); + + /// @brief Increment the integer stored at the given field. + /// @param key Key where the hash is stored. + /// @param field Field. + /// @param increment Increment. + /// @return The value of the field after the increment. + /// @see https://redis.io/commands/hincrby + long long hincrby(const StringView &key, const StringView &field, long long increment); + + /// @brief Increment the floating point number stored at the given field. + /// @param key Key where the hash is stored. + /// @param field Field. + /// @param increment Increment. + /// @return The value of the field after the increment. + /// @see https://redis.io/commands/hincrbyfloat + double hincrbyfloat(const StringView &key, const StringView &field, double increment); + + /// @brief Get all fields of the given hash. + /// @param key Key where the hash is stored. + /// @param output Output iterator to the destination where the result is saved. + /// @note It's always a bad idea to call `hkeys` on a large hash, since it will block Redis. + /// @see `Redis::hscan` + /// @see https://redis.io/commands/hkeys + template + void hkeys(const StringView &key, Output output); + + /// @brief Get the number of fields of the given hash. + /// @param key Key where the hash is stored. + /// @return Number of fields. + /// @see https://redis.io/commands/hlen + long long hlen(const StringView &key); + + /// @brief Get values of multiple fields. + /// + /// Example: + /// @code{.cpp} + /// std::vector fields = {"f1", "f2"}; + /// std::vector vals; + /// redis.hmget("hash", fields.begin(), fields.end(), std::back_inserter(vals)); + /// for (const auto &val : vals) { + /// if (val) + /// std::cout << *val << std::endl; + /// else + /// std::cout << "field not exist" << std::endl; + /// } + /// @endcode + /// @param key Key where the hash is stored. + /// @param first Iterator to the first field. + /// @param last Off-the-end iterator to the given field range. + /// @param output Output iterator to the destination where the result is saved. + /// @note The destination should be a container of `OptionalString` type, + /// since the given field might not exist (in this case, the value of the corresponding + /// field is `OptionalString{}` (`std::nullopt`)). + /// @see https://redis.io/commands/hmget + template + void hmget(const StringView &key, Input first, Input last, Output output); + + /// @brief Get values of multiple fields. + /// + /// Example: + /// @code{.cpp} + /// std::vector vals; + /// redis.hmget("hash", {"f1", "f2"}, std::back_inserter(vals)); + /// for (const auto &val : vals) { + /// if (val) + /// std::cout << *val << std::endl; + /// else + /// std::cout << "field not exist" << std::endl; + /// } + /// @endcode + /// @param key Key where the hash is stored. + /// @param il Initializer list of fields. + /// @param output Output iterator to the destination where the result is saved. + /// @note The destination should be a container of `OptionalString` type, + /// since the given field might not exist (in this case, the value of the corresponding + /// field is `OptionalString{}` (`std::nullopt`)). + /// @see https://redis.io/commands/hmget + template + void hmget(const StringView &key, std::initializer_list il, Output output) { + hmget(key, il.begin(), il.end(), output); + } + + /// @brief Set multiple field-value pairs of the given hash. + /// + /// Example: + /// @code{.cpp} + /// std::unordered_map m = {{"f1", "v1"}, {"f2", "v2"}}; + /// redis.hmset("hash", m.begin(), m.end()); + /// @endcode + /// @param key Key where the hash is stored. + /// @param first Iterator to the first field-value pair. + /// @param last Off-the-end iterator to the range. + /// @see https://redis.io/commands/hmset + template + void hmset(const StringView &key, Input first, Input last); + + /// @brief Set multiple field-value pairs of the given hash. + /// + /// Example: + /// @code{.cpp} + /// redis.hmset("hash", {std::make_pair("f1", "v1"), std::make_pair("f2", "v2")}); + /// @endcode + /// @param key Key where the hash is stored. + /// @param il Initializer list of field-value pairs. + /// @see https://redis.io/commands/hmset + template + void hmset(const StringView &key, std::initializer_list il) { + hmset(key, il.begin(), il.end()); + } + + /// @brief Scan fields of the given hash matching the given pattern. + /// + /// Example: + /// @code{.cpp} + /// auto cursor = 0LL; + /// std::unordered_map kvs; + /// while (true) { + /// cursor = redis.hscan("hash", cursor, "pattern:*", 10, std::inserter(kvs, kvs.begin())); + /// if (cursor == 0) { + /// break; + /// } + /// } + /// @endcode + /// @param key Key where the hash is stored. + /// @param cursor Cursor. + /// @param pattern Pattern of fields to be scanned. + /// @param count A hint for how many fields to be scanned. + /// @param output Output iterator to the destination where the result is saved. + /// @return The cursor to be used for the next scan operation. + /// @see https://redis.io/commands/hscan + template + long long hscan(const StringView &key, + long long cursor, + const StringView &pattern, + long long count, + Output output); + + /// @brief Scan fields of the given hash matching the given pattern. + /// @param key Key where the hash is stored. + /// @param cursor Cursor. + /// @param pattern Pattern of fields to be scanned. + /// @param output Output iterator to the destination where the result is saved. + /// @return The cursor to be used for the next scan operation. + /// @see https://redis.io/commands/hscan + template + long long hscan(const StringView &key, + long long cursor, + const StringView &pattern, + Output output); + + /// @brief Scan all fields of the given hash. + /// @param key Key where the hash is stored. + /// @param cursor Cursor. + /// @param count A hint for how many fields to be scanned. + /// @param output Output iterator to the destination where the result is saved. + /// @return The cursor to be used for the next scan operation. + /// @see https://redis.io/commands/hscan + template + long long hscan(const StringView &key, + long long cursor, + long long count, + Output output); + + /// @brief Scan all fields of the given hash. + /// @param key Key where the hash is stored. + /// @param cursor Cursor. + /// @param output Output iterator to the destination where the result is saved. + /// @return The cursor to be used for the next scan operation. + /// @see https://redis.io/commands/hscan + template + long long hscan(const StringView &key, + long long cursor, + Output output); + + /// @brief Set hash field to value. + /// @param key Key where the hash is stored. + /// @param field Field. + /// @param val Value. + /// @return Whether the given field is a new field. + /// @retval true If the given field didn't exist, and a new field has been added. + /// @retval false If the given field already exists, and its value has been overwritten. + /// @note When `hset` returns false, it does not mean that the method failed to set the field. + /// Instead, it means that the field already exists, and we've overwritten its value. + /// If `hset` fails, it will throw an exception of `Exception` type. + /// @see https://github.com/sewenew/redis-plus-plus/issues/9 + /// @see https://redis.io/commands/hset + bool hset(const StringView &key, const StringView &field, const StringView &val); + + /// @brief Set hash field to value. + /// @param key Key where the hash is stored. + /// @param item The field-value pair to be set. + /// @return Whether the given field is a new field. + /// @retval true If the given field didn't exist, and a new field has been added. + /// @retval false If the given field already exists, and its value has been overwritten. + /// @note When `hset` returns false, it does not mean that the method failed to set the field. + /// Instead, it means that the field already exists, and we've overwritten its value. + /// If `hset` fails, it will throw an exception of `Exception` type. + /// @see https://github.com/sewenew/redis-plus-plus/issues/9 + /// @see https://redis.io/commands/hset + bool hset(const StringView &key, const std::pair &item); + + /// @brief Set multiple fields of the given hash. + /// + /// Example: + /// @code{.cpp} + /// std::unordered_map m = {{"f1", "v1"}, {"f2", "v2"}}; + /// redis.hset("hash", m.begin(), m.end()); + /// @endcode + /// @param key Key where the hash is stored. + /// @param first Iterator to the first field to be set. + /// @param last Off-the-end iterator to the given range. + /// @return Number of fields that have been added, i.e. fields that not existed before. + /// @see https://redis.io/commands/hset + template + auto hset(const StringView &key, Input first, Input last) + -> typename std::enable_if::value, long long>::type; + + /// @brief Set multiple fields of the given hash. + /// + /// Example: + /// @code{.cpp} + /// redis.hset("hash", {std::make_pair("f1", "v1"), std::make_pair("f2", "v2")}); + /// @endcode + /// @param key Key where the hash is stored. + /// @param il Initializer list of field-value pairs. + /// @return Number of fields that have been added, i.e. fields that not existed before. + /// @see https://redis.io/commands/hset + template + long long hset(const StringView &key, std::initializer_list il) { + return hset(key, il.begin(), il.end()); + } + + /// @brief Set hash field to value, only if the given field does not exist. + /// @param key Key where the hash is stored. + /// @param field Field. + /// @param val Value. + /// @return Whether the field has been set. + /// @retval true If the field has been set. + /// @retval false If failed to set the field, i.e. the field already exists. + /// @see https://redis.io/commands/hsetnx + bool hsetnx(const StringView &key, const StringView &field, const StringView &val); + + /// @brief Set hash field to value, only if the given field does not exist. + /// @param key Key where the hash is stored. + /// @param item The field-value pair to be set. + /// @return Whether the field has been set. + /// @retval true If the field has been set. + /// @retval false If failed to set the field, i.e. the field already exists. + /// @see https://redis.io/commands/hsetnx + bool hsetnx(const StringView &key, const std::pair &item); + + /// @brief Get the length of the string stored at the given field. + /// @param key Key where the hash is stored. + /// @param field Field. + /// @return Length of the string. + /// @see https://redis.io/commands/hstrlen + long long hstrlen(const StringView &key, const StringView &field); + + /// @brief Get values of all fields stored at the given hash. + /// @param key Key where the hash is stored. + /// @param output Output iterator to the destination where the result is saved. + /// @note It's always a bad idea to call `hvals` on a large hash, since it might block Redis. + /// @see `Redis::hscan` + /// @see https://redis.io/commands/hvals + template + void hvals(const StringView &key, Output output); + + // SET commands. + + /// @brief Add a member to the given set. + /// @param key Key where the set is stored. + /// @param member Member to be added. + /// @return Whether the given member is a new member. + /// @retval 1 The member did not exist before, and it has been added now. + /// @retval 0 The member already exists before this operation. + /// @see https://redis.io/commands/sadd + long long sadd(const StringView &key, const StringView &member); + + /// @brief Add multiple members to the given set. + /// @param key Key where the set is stored. + /// @param first Iterator to the first member to be added. + /// @param last Off-the-end iterator to the member range. + /// @return Number of new members that have been added, i.e. members did not exist before. + /// @see https://redis.io/commands/sadd + template + long long sadd(const StringView &key, Input first, Input last); + + /// @brief Add multiple members to the given set. + /// @param key Key where the set is stored. + /// @param il Initializer list of members to be added. + /// @return Number of new members that have been added, i.e. members did not exist before. + /// @see https://redis.io/commands/sadd + template + long long sadd(const StringView &key, std::initializer_list il) { + return sadd(key, il.begin(), il.end()); + } + + /// @brief Get the number of members in the set. + /// @param key Key where the set is stored. + /// @return Number of members. + /// @see https://redis.io/commands/scard + long long scard(const StringView &key); + + /// @brief Get the difference between the first set and all successive sets. + /// @param first Iterator to the first set. + /// @param last Off-the-end iterator to the range. + /// @param output Output iterator to the destination where the result is saved. + /// @see https://redis.io/commands/sdiff + // TODO: `void sdiff(const StringView &key, Input first, Input last, Output output)` is better. + template + void sdiff(Input first, Input last, Output output); + + /// @brief Get the difference between the first set and all successive sets. + /// @param il Initializer list of sets. + /// @param output Output iterator to the destination where the result is saved. + /// @see https://redis.io/commands/sdiff + template + void sdiff(std::initializer_list il, Output output) { + sdiff(il.begin(), il.end(), output); + } + + /// @brief Copy set stored at `key` to `destination`. + /// @param destination Key of the destination set. + /// @param key Key of the source set. + /// @return Number of members of the set. + /// @see https://redis.io/commands/sdiffstore + long long sdiffstore(const StringView &destination, const StringView &key); + + /// @brief Same as `sdiff`, except that it stores the result to another set. + /// @param destination Key of the destination set. + /// @param first Iterator to the first set. + /// @param last Off-the-end iterator to set range. + /// @return Number of members in the resulting set. + /// @see https://redis.io/commands/sdiffstore + template + long long sdiffstore(const StringView &destination, + Input first, + Input last); + + /// @brief Same as `sdiff`, except that it stores the result to another set. + /// @param destination Key of the destination set. + /// @param il Initializer list of sets. + /// @return Number of members in the resulting set. + /// @see https://redis.io/commands/sdiffstore + template + long long sdiffstore(const StringView &destination, + std::initializer_list il) { + return sdiffstore(destination, il.begin(), il.end()); + } + + /// @brief Get the intersection between the first set and all successive sets. + /// @param first Iterator to the first set. + /// @param last Off-the-end iterator to the range. + /// @param output Output iterator to the destination where the result is saved. + /// @see https://redis.io/commands/sinter + // TODO: `void sinter(const StringView &key, Input first, Input last, Output output)` is better. + template + void sinter(Input first, Input last, Output output); + + /// @brief Get the intersection between the first set and all successive sets. + /// @param il Initializer list of sets. + /// @param output Output iterator to the destination where the result is saved. + /// @see https://redis.io/commands/sinter + template + void sinter(std::initializer_list il, Output output) { + sinter(il.begin(), il.end(), output); + } + + /// @brief Copy set stored at `key` to `destination`. + /// @param destination Key of the destination set. + /// @param key Key of the source set. + /// @return Number of members of the set. + /// @see https://redis.io/commands/sinter + long long sinterstore(const StringView &destination, const StringView &key); + + /// @brief Same as `sinter`, except that it stores the result to another set. + /// @param destination Key of the destination set. + /// @param first Iterator to the first set. + /// @param last Off-the-end iterator to set range. + /// @return Number of members in the resulting set. + /// @see https://redis.io/commands/sinter + template + long long sinterstore(const StringView &destination, + Input first, + Input last); + + /// @brief Same as `sinter`, except that it stores the result to another set. + /// @param destination Key of the destination set. + /// @param il Initializer list of sets. + /// @return Number of members in the resulting set. + /// @see https://redis.io/commands/sinter + template + long long sinterstore(const StringView &destination, + std::initializer_list il) { + return sinterstore(destination, il.begin(), il.end()); + } + + /// @brief Test if `member` exists in the set stored at key. + /// @param key Key where the set is stored. + /// @param member Member to be checked. + /// @return Whether `member` exists in the set. + /// @retval true If it exists in the set. + /// @retval false If it does not exist in the set, or the given key does not exist. + /// @see https://redis.io/commands/sismember + bool sismember(const StringView &key, const StringView &member); + + /// @brief Get all members in the given set. + /// + /// Example: + /// @code{.cpp} + /// std::unordered_set members1; + /// redis.smembers("set", std::inserter(members1, members1.begin())); + /// std::vector members2; + /// redis.smembers("set", std::back_inserter(members2)); + /// @endcode + /// @param key Key where the set is stored. + /// @param output Iterator to the destination where the result is saved. + /// @see https://redis.io/commands/smembers + template + void smembers(const StringView &key, Output output); + + /// @brief Move `member` from one set to another. + /// @param source Key of the set in which the member currently exists. + /// @param destination Key of the destination set. + /// @return Whether the member has been moved. + /// @retval true If the member has been moved. + /// @retval false If `member` does not exist in `source`. + /// @see https://redis.io/commands/smove + bool smove(const StringView &source, + const StringView &destination, + const StringView &member); + + /// @brief Remove a random member from the set. + /// @param key Key where the set is stored. + /// @return The popped member. + /// @note If the set is empty, `spop` returns `OptionalString{}` (`std::nullopt`). + /// @see `Redis::srandmember` + /// @see https://redis.io/commands/spop + OptionalString spop(const StringView &key); + + /// @brief Remove multiple random members from the set. + /// + /// Example: + /// @code{.cpp} + /// std::vector members; + /// redis.spop("set", 10, std::back_inserter(members)); + /// @endcode + /// @param key Key where the set is stored. + /// @param count Number of members to be popped. + /// @param output Output iterator to the destination where the result is saved. + /// @note The number of popped members might be less than `count`. + /// @see `Redis::srandmember` + /// @see https://redis.io/commands/spop + template + void spop(const StringView &key, long long count, Output output); + + /// @brief Get a random member of the given set. + /// @param key Key where the set is stored. + /// @return A random member. + /// @note If the set is empty, `srandmember` returns `OptionalString{}` (`std::nullopt`). + /// @note This method won't remove the member from the set. + /// @see `Redis::spop` + /// @see https://redis.io/commands/srandmember + OptionalString srandmember(const StringView &key); + + /// @brief Get multiple random members of the given set. + /// @param key Key where the set is stored. + /// @param count Number of members to be returned. + /// @param output Output iterator to the destination where the result is saved. + /// @note This method won't remove members from the set. + /// @see `Redis::spop` + /// @see https://redis.io/commands/srandmember + template + void srandmember(const StringView &key, long long count, Output output); + + /// @brief Remove a member from set. + /// @param key Key where the set is stored. + /// @param member Member to be removed. + /// @return Whether the member has been removed. + /// @retval 1 If the given member exists, and has been removed. + /// @retval 0 If the given member does not exist. + /// @see https://redis.io/commands/srem + long long srem(const StringView &key, const StringView &member); + + /// @brief Remove multiple members from set. + /// @param key Key where the set is stored. + /// @param first Iterator to the first member to be removed. + /// @param last Off-the-end iterator to the range. + /// @return Number of members that have been removed. + /// @see https://redis.io/commands/srem + template + long long srem(const StringView &key, Input first, Input last); + + /// @brief Remove multiple members from set. + /// @param key Key where the set is stored. + /// @param il Initializer list of members to be removed. + /// @return Number of members that have been removed. + /// @see https://redis.io/commands/srem + template + long long srem(const StringView &key, std::initializer_list il) { + return srem(key, il.begin(), il.end()); + } + + /// @brief Scan members of the set matching the given pattern. + /// + /// Example: + /// @code{.cpp} + /// auto cursor = 0LL; + /// std::unordered_set members; + /// while (true) { + /// cursor = redis.sscan("set", cursor, "pattern:*", + /// 10, std::inserter(members, members.begin())); + /// if (cursor == 0) { + /// break; + /// } + /// } + /// @endcode + /// @param key Key where the set is stored. + /// @param cursor Cursor. + /// @param pattern Pattern of fields to be scanned. + /// @param count A hint for how many fields to be scanned. + /// @param output Output iterator to the destination where the result is saved. + /// @return The cursor to be used for the next scan operation. + /// @see https://redis.io/commands/sscan + template + long long sscan(const StringView &key, + long long cursor, + const StringView &pattern, + long long count, + Output output); + + /// @brief Scan members of the set matching the given pattern. + /// @param key Key where the set is stored. + /// @param cursor Cursor. + /// @param pattern Pattern of fields to be scanned. + /// @param output Output iterator to the destination where the result is saved. + /// @return The cursor to be used for the next scan operation. + /// @see https://redis.io/commands/sscan + template + long long sscan(const StringView &key, + long long cursor, + const StringView &pattern, + Output output); + + /// @brief Scan all members of the given set. + /// @param key Key where the set is stored. + /// @param cursor Cursor. + /// @param count A hint for how many fields to be scanned. + /// @param output Output iterator to the destination where the result is saved. + /// @return The cursor to be used for the next scan operation. + /// @see https://redis.io/commands/sscan + template + long long sscan(const StringView &key, + long long cursor, + long long count, + Output output); + + /// @brief Scan all members of the given set. + /// @param key Key where the set is stored. + /// @param cursor Cursor. + /// @param output Output iterator to the destination where the result is saved. + /// @return The cursor to be used for the next scan operation. + /// @see https://redis.io/commands/sscan + template + long long sscan(const StringView &key, + long long cursor, + Output output); + + /// @brief Get the union between the first set and all successive sets. + /// @param first Iterator to the first set. + /// @param last Off-the-end iterator to the range. + /// @param output Output iterator to the destination where the result is saved. + /// @see https://redis.io/commands/sunion + // TODO: `void sunion(const StringView &key, Input first, Input last, Output output)` is better. + template + void sunion(Input first, Input last, Output output); + + /// @brief Get the union between the first set and all successive sets. + /// @param il Initializer list of sets. + /// @param output Output iterator to the destination where the result is saved. + /// @see https://redis.io/commands/sunion + template + void sunion(std::initializer_list il, Output output) { + sunion(il.begin(), il.end(), output); + } + + /// @brief Copy set stored at `key` to `destination`. + /// @param destination Key of the destination set. + /// @param key Key of the source set. + /// @return Number of members of the set. + /// @see https://redis.io/commands/sunionstore + long long sunionstore(const StringView &destination, const StringView &key); + + /// @brief Same as `sunion`, except that it stores the result to another set. + /// @param destination Key of the destination set. + /// @param first Iterator to the first set. + /// @param last Off-the-end iterator to set range. + /// @return Number of members in the resulting set. + /// @see https://redis.io/commands/sunionstore + template + long long sunionstore(const StringView &destination, Input first, Input last); + + /// @brief Same as `sunion`, except that it stores the result to another set. + /// @param destination Key of the destination set. + /// @param il Initializer list of sets. + /// @return Number of members in the resulting set. + /// @see https://redis.io/commands/sunionstore + template + long long sunionstore(const StringView &destination, std::initializer_list il) { + return sunionstore(destination, il.begin(), il.end()); + } + + // SORTED SET commands. + + /// @brief Pop the member with highest score from sorted set in a blocking way. + /// @param key Key where the sorted set is stored. + /// @param timeout Timeout in seconds. 0 means block forever. + /// @return Key-member-score tuple with the highest score. + /// @note If sorted set is empty and timeout reaches, `bzpopmax` returns + /// `Optional>{}` (`std::nullopt`). + /// @see `Redis::zpopmax` + /// @see https://redis.io/commands/bzpopmax + auto bzpopmax(const StringView &key, long long timeout) + -> Optional>; + + /// @brief Pop the member with highest score from sorted set in a blocking way. + /// @param key Key where the sorted set is stored. + /// @param timeout Timeout in seconds. 0 means block forever. + /// @return Key-member-score tuple with the highest score. + /// @note If sorted set is empty and timeout reaches, `bzpopmax` returns + /// `Optional>{}` (`std::nullopt`). + /// @see `Redis::zpopmax` + /// @see https://redis.io/commands/bzpopmax + auto bzpopmax(const StringView &key, + const std::chrono::seconds &timeout = std::chrono::seconds{0}) + -> Optional>; + + /// @brief Pop the member with highest score from multiple sorted set in a blocking way. + /// @param first Iterator to the first key. + /// @param last Off-the-end iterator to the key range. + /// @param timeout Timeout in seconds. 0 means block forever. + /// @return Key-member-score tuple with the higest score. + /// @note If all lists are empty and timeout reaches, `bzpopmax` returns + /// `Optional>{}` (`std::nullopt`). + /// @see `Redis::zpopmax` + /// @see https://redis.io/commands/bzpopmax + template + auto bzpopmax(Input first, Input last, long long timeout) + -> Optional>; + + /// @brief Pop the member with highest score from multiple sorted set in a blocking way. + /// @param first Iterator to the first key. + /// @param last Off-the-end iterator to the key range. + /// @param timeout Timeout in seconds. 0 means block forever. + /// @return Key-member-score tuple with the higest score. + /// @note If all lists are empty and timeout reaches, `bzpopmax` returns + /// `Optional>{}` (`std::nullopt`). + /// @see `Redis::zpopmax` + /// @see https://redis.io/commands/bzpopmax + template + auto bzpopmax(Input first, + Input last, + const std::chrono::seconds &timeout = std::chrono::seconds{0}) + -> Optional>; + + /// @brief Pop the member with highest score from multiple sorted set in a blocking way. + /// @param il Initializer list of sorted sets. + /// @param timeout Timeout in seconds. 0 means block forever. + /// @return Key-member-score tuple with the higest score. + /// @note If all lists are empty and timeout reaches, `bzpopmax` returns + /// `Optional>{}` (`std::nullopt`). + /// @see `Redis::zpopmax` + /// @see https://redis.io/commands/bzpopmax + template + auto bzpopmax(std::initializer_list il, long long timeout) + -> Optional> { + return bzpopmax(il.begin(), il.end(), timeout); + } + + /// @brief Pop the member with highest score from multiple sorted set in a blocking way. + /// @param il Initializer list of sorted sets. + /// @param timeout Timeout in seconds. 0 means block forever. + /// @return Key-member-score tuple with the higest score. + /// @note If all lists are empty and timeout reaches, `bzpopmax` returns + /// `Optional>{}` (`std::nullopt`). + /// @see `Redis::zpopmax` + /// @see https://redis.io/commands/bzpopmax + template + auto bzpopmax(std::initializer_list il, + const std::chrono::seconds &timeout = std::chrono::seconds{0}) + -> Optional> { + return bzpopmax(il.begin(), il.end(), timeout); + } + + /// @brief Pop the member with lowest score from sorted set in a blocking way. + /// @param key Key where the sorted set is stored. + /// @param timeout Timeout in seconds. 0 means block forever. + /// @return Key-member-score tuple with the lowest score. + /// @note If sorted set is empty and timeout reaches, `bzpopmin` returns + /// `Optional>{}` (`std::nullopt`). + /// @see `Redis::zpopmin` + /// @see https://redis.io/commands/bzpopmin + auto bzpopmin(const StringView &key, long long timeout) + -> Optional>; + + /// @brief Pop the member with lowest score from sorted set in a blocking way. + /// @param key Key where the sorted set is stored. + /// @param timeout Timeout in seconds. 0 means block forever. + /// @return Key-member-score tuple with the lowest score. + /// @note If sorted set is empty and timeout reaches, `bzpopmin` returns + /// `Optional>{}` (`std::nullopt`). + /// @see `Redis::zpopmin` + /// @see https://redis.io/commands/bzpopmin + auto bzpopmin(const StringView &key, + const std::chrono::seconds &timeout = std::chrono::seconds{0}) + -> Optional>; + + /// @brief Pop the member with lowest score from multiple sorted set in a blocking way. + /// @param first Iterator to the first key. + /// @param last Off-the-end iterator to the key range. + /// @param timeout Timeout in seconds. 0 means block forever. + /// @return Key-member-score tuple with the lowest score. + /// @note If all lists are empty and timeout reaches, `bzpopmin` returns + /// `Optional>{}` (`std::nullopt`). + /// @see `Redis::zpopmin` + /// @see https://redis.io/commands/bzpopmin + template + auto bzpopmin(Input first, Input last, long long timeout) + -> Optional>; + + /// @brief Pop the member with lowest score from multiple sorted set in a blocking way. + /// @param first Iterator to the first key. + /// @param last Off-the-end iterator to the key range. + /// @param timeout Timeout in seconds. 0 means block forever. + /// @return Key-member-score tuple with the lowest score. + /// @note If all lists are empty and timeout reaches, `bzpopmin` returns + /// `Optional>{}` (`std::nullopt`). + /// @see `Redis::zpopmin` + /// @see https://redis.io/commands/bzpopmin + template + auto bzpopmin(Input first, + Input last, + const std::chrono::seconds &timeout = std::chrono::seconds{0}) + -> Optional>; + + /// @brief Pop the member with lowest score from multiple sorted set in a blocking way. + /// @param il Initializer list of sorted sets. + /// @param timeout Timeout in seconds. 0 means block forever. + /// @return Key-member-score tuple with the lowest score. + /// @note If all lists are empty and timeout reaches, `bzpopmin` returns + /// `Optional>{}` (`std::nullopt`). + /// @see `Redis::zpopmin` + /// @see https://redis.io/commands/bzpopmin + template + auto bzpopmin(std::initializer_list il, long long timeout) + -> Optional> { + return bzpopmin(il.begin(), il.end(), timeout); + } + + /// @brief Pop the member with lowest score from multiple sorted set in a blocking way. + /// @param il Initializer list of sorted sets. + /// @param timeout Timeout in seconds. 0 means block forever. + /// @return Key-member-score tuple with the lowest score. + /// @note If all lists are empty and timeout reaches, `bzpopmin` returns + /// `Optional>{}` (`std::nullopt`). + /// @see `Redis::zpopmin` + /// @see https://redis.io/commands/bzpopmin + template + auto bzpopmin(std::initializer_list il, + const std::chrono::seconds &timeout = std::chrono::seconds{0}) + -> Optional> { + return bzpopmin(il.begin(), il.end(), timeout); + } + + /// @brief Add or update a member with score to sorted set. + /// @param key Key where the sorted set is stored. + /// @param member Member to be added. + /// @param score Score of the member. + /// @param type Options for zadd command: + /// - UpdateType::EXIST: Add the member only if it already exists. + /// - UpdateType::NOT_EXIST: Add the member only if it does not exist. + /// - UpdateType::ALWAYS: Always add the member no matter whether it exists. + /// @param changed Whether change the return value from number of newly added member to + /// number of members changed (i.e. added and updated). + /// @return Number of added members or number of added and updated members depends on `changed`. + /// @note We don't support the INCR option, because in this case, the return value of zadd + /// command is NOT of type long long. However, you can always use the generic interface + /// to send zadd command with INCR option: + /// `auto score = redis.command("ZADD", "key", "XX", "INCR", 10, "mem");` + /// @see `UpdateType` + /// @see https://redis.io/commands/zadd + long long zadd(const StringView &key, + const StringView &member, + double score, + UpdateType type = UpdateType::ALWAYS, + bool changed = false); + + /// @brief Add or update multiple members with score to sorted set. + /// + /// Example: + /// @code{.cpp} + /// std::unordered_map m = {{"m1", 1.2}, {"m2", 2.3}}; + /// redis.zadd("zset", m.begin(), m.end()); + /// @endcode + /// @param key Key where the sorted set is stored. + /// @param first Iterator to the first member-score pair. + /// @param last Off-the-end iterator to the member-score pairs range. + /// @param type Options for zadd command: + /// - UpdateType::EXIST: Add the member only if it already exists. + /// - UpdateType::NOT_EXIST: Add the member only if it does not exist. + /// - UpdateType::ALWAYS: Always add the member no matter whether it exists. + /// @param changed Whether change the return value from number of newly added member to + /// number of members changed (i.e. added and updated). + /// @return Number of added members or number of added and updated members depends on `changed`. + /// @note We don't support the INCR option, because in this case, the return value of zadd + /// command is NOT of type long long. However, you can always use the generic interface + /// to send zadd command with INCR option: + /// `auto score = redis.command("ZADD", "key", "XX", "INCR", 10, "mem");` + /// @see `UpdateType` + /// @see https://redis.io/commands/zadd + template + long long zadd(const StringView &key, + Input first, + Input last, + UpdateType type = UpdateType::ALWAYS, + bool changed = false); + + /// @brief Add or update multiple members with score to sorted set. + /// + /// Example: + /// @code{.cpp} + /// redis.zadd("zset", {std::make_pair("m1", 1.4), std::make_pair("m2", 2.3)}); + /// @endcode + /// @param key Key where the sorted set is stored. + /// @param first Iterator to the first member-score pair. + /// @param last Off-the-end iterator to the member-score pairs range. + /// @param type Options for zadd command: + /// - UpdateType::EXIST: Add the member only if it already exists. + /// - UpdateType::NOT_EXIST: Add the member only if it does not exist. + /// - UpdateType::ALWAYS: Always add the member no matter whether it exists. + /// @param changed Whether change the return value from number of newly added member to + /// number of members changed (i.e. added and updated). + /// @return Number of added members or number of added and updated members depends on `changed`. + /// @note We don't support the INCR option, because in this case, the return value of zadd + /// command is NOT of type long long. However, you can always use the generic interface + /// to send zadd command with INCR option: + /// `auto score = redis.command("ZADD", "key", "XX", "INCR", 10, "mem");` + /// @see `UpdateType` + /// @see https://redis.io/commands/zadd + template + long long zadd(const StringView &key, + std::initializer_list il, + UpdateType type = UpdateType::ALWAYS, + bool changed = false) { + return zadd(key, il.begin(), il.end(), type, changed); + } + + /// @brief Get the number of members in the sorted set. + /// @param key Key where the sorted set is stored. + /// @return Number of members in the sorted set. + /// @see https://redis.io/commands/zcard + long long zcard(const StringView &key); + + /// @brief Get the number of members with score between a min-max score range. + /// + /// Example: + /// @code{.cpp} + /// // Count members with score between (2.3, 5] + /// redis.zcount("zset", BoundedInterval(2.3, 5, BoundType::LEFT_OPEN)); + /// // Count members with score between [2.3, 5) + /// redis.zcount("zset", BoundedInterval(2.3, 5, BoundType::RIGHT_OPEN)); + /// // Count members with score between (2.3, 5) + /// redis.zcount("zset", BoundedInterval(2.3, 5, BoundType::OPEN)); + /// // Count members with score between [2.3, 5] + /// redis.zcount("zset", BoundedInterval(2.3, 5, BoundType::CLOSED)); + /// // Count members with score between [2.3, +inf) + /// redis.zcount("zset", LeftBoundedInterval(2.3, BoundType::RIGHT_OPEN)); + /// // Count members with score between (2.3, +inf) + /// redis.zcount("zset", LeftBoundedInterval(2.3, BoundType::OPEN)); + /// // Count members with score between (-inf, 5] + /// redis.zcount("zset", RightBoundedInterval(5, BoundType::LEFT_OPEN)); + /// // Count members with score between (-inf, 5) + /// redis.zcount("zset", RightBoundedInterval(5, BoundType::OPEN)); + /// // Count members with score between (-inf, +inf) + /// redis.zcount("zset", UnboundedInterval{}); + /// @endcode + /// @param key Key where the sorted set is stored. + /// @param interval The min-max score range. + /// @return Number of members with score between a min-max score range. + /// @see `BoundedInterval` + /// @see `LeftBoundedInterval` + /// @see `RightBoundedInterval` + /// @see `UnboundedInterval` + /// @see `BoundType` + /// @see https://redis.io/commands/zcount + // TODO: add a string version of Interval: zcount("key", "(2.3", "5"). + template + long long zcount(const StringView &key, const Interval &interval); + + /// @brief Increment the score of given member. + /// @param key Key where the sorted set is stored. + /// @param increment Increment. + /// @param member Member. + /// @return The score of the member after the operation. + /// @see https://redis.io/commands/zincrby + double zincrby(const StringView &key, double increment, const StringView &member); + + /// @brief Copy a sorted set to another one with the scores being multiplied by a factor. + /// @param destination Key of the destination sorted set. + /// @param key Key of the source sorted set. + /// @param weight Weight to be multiplied to the score of each member. + /// @return The number of members in the sorted set. + /// @note There's no aggregation type parameter for single key overload, since these 3 types + /// have the same effect. + /// @see `Redis::zunionstore` + /// @see https://redis.io/commands/zinterstore + long long zinterstore(const StringView &destination, const StringView &key, double weight); + + /// @brief Get intersection of multiple sorted sets, and store the result to another one. + /// + /// Example: + /// @code{.cpp} + /// // Use the default weight, i.e. 1, + /// // and use the sum of the all scores as the score of the result: + /// std::vector keys = {"k1", "k2", "k3"}; + /// redis.zinterstore("destination", keys.begin(), keys.end()); + /// // Each sorted set has a different weight, + /// // and the score of the result is the min of all scores. + /// std::vector> keys_with_weights = {{"k1", 1}, {"k2", 2}}; + /// redis.zinterstore("destination", keys_with_weights.begin(), + /// keys_with_weights.end(), Aggregation::MIN); + /// // NOTE: `keys_with_weights` can also be of type `std::unordered_map`. + /// // However, it will be slower than std::vector>, since we use + /// // `std::distance(first, last)` to calculate the *numkeys* parameter. + /// @endcode + /// @param destination Key of the destination sorted set. + /// @param first Iterator to the first sorted set (might with weight). + /// @param last Off-the-end iterator to the sorted set range. + /// @param type How the scores are aggregated. + /// - Aggregation::SUM: Score of a member is the sum of all scores. + /// - Aggregation::MIN: Score of a member is the min of all scores. + /// - Aggregation::MAX: Score of a member is the max of all scores. + /// @return The number of members in the resulting sorted set. + /// @note The score of each member can be multiplied by a factor, i.e. weight. If `Input` is an + /// iterator to a container of `std::string`, we use the default weight, i.e. 1, and send + /// *ZINTERSTORE dest numkeys key [key ...] [AGGREGATE SUM|MIN|MAX]* command. + /// If `Input` is an iterator to a container of `std::pair`, + /// i.e. key-weight pair, we send the command with the given weights: + /// *ZINTERSTORE dest numkeys key [key ...] [WEIGHTS weight [weight ...]] [AGGREGATE SUM|MIN|MAX]*. + /// See the *Example* part for examples on how to use this command. + /// @see `Redis::zunionstore` + /// @see https://redis.io/commands/zinterstore + template + long long zinterstore(const StringView &destination, + Input first, + Input last, + Aggregation type = Aggregation::SUM); + + /// @brief Get intersection of multiple sorted sets, and store the result to another one. + /// + /// Example: + /// @code{.cpp} + /// // Use the default weight, i.e. 1, + /// // and use the sum of the all scores as the score of the result: + /// redis.zinterstore("destination", {"k1", "k2"}); + /// // Each sorted set has a different weight, + /// // and the score of the result is the min of all scores. + /// redis.zinterstore("destination", + /// {std::make_pair("k1", 1), std::make_pair("k2", 2)}, Aggregation::MIN); + /// @endcode + /// @param destination Key of the destination sorted set. + /// @param il Initializer list of sorted set. + /// @param type How the scores are aggregated. + /// - Aggregation::SUM: Score of a member is the sum of all scores. + /// - Aggregation::MIN: Score of a member is the min of all scores. + /// - Aggregation::MAX: Score of a member is the max of all scores. + /// @return The number of members in the resulting sorted set. + /// @note The score of each member can be multiplied by a factor, i.e. weight. If `T` is + /// of type `std::string`, we use the default weight, i.e. 1, and send + /// *ZINTERSTORE dest numkeys key [key ...] [AGGREGATE SUM|MIN|MAX]* command. + /// If `T` is of type `std::pair`, i.e. key-weight pair, + /// we send the command with the given weights: + /// *ZINTERSTORE dest numkeys key [key ...] [WEIGHTS weight [weight ...]] [AGGREGATE SUM|MIN|MAX]*. + /// See the *Example* part for examples on how to use this command. + /// @see `Redis::zunionstore` + /// @see https://redis.io/commands/zinterstore + template + long long zinterstore(const StringView &destination, + std::initializer_list il, + Aggregation type = Aggregation::SUM) { + return zinterstore(destination, il.begin(), il.end(), type); + } + + /// @brief Get the number of members between a min-max range in lexicographical order. + /// + /// Example: + /// @code{.cpp} + /// // Count members between (abc, abd] + /// redis.zlexcount("zset", BoundedInterval("abc", "abd", BoundType::LEFT_OPEN)); + /// // Count members between [abc, abd) + /// redis.zlexcount("zset", BoundedInterval("abc", "abd", BoundType::RIGHT_OPEN)); + /// // Count members between (abc, abd) + /// redis.zlexcount("zset", BoundedInterval("abc", "abd", BoundType::OPEN)); + /// // Count members between [abc, abd] + /// redis.zlexcount("zset", BoundedInterval("abc", "abd", BoundType::CLOSED)); + /// // Count members between [abc, +inf) + /// redis.zlexcount("zset", LeftBoundedInterval("abc", BoundType::RIGHT_OPEN)); + /// // Count members between (abc, +inf) + /// redis.zlexcount("zset", LeftBoundedInterval("abc", BoundType::OPEN)); + /// // Count members between (-inf, "abd"] + /// redis.zlexcount("zset", RightBoundedInterval("abd", BoundType::LEFT_OPEN)); + /// // Count members between (-inf, "abd") + /// redis.zlexcount("zset", RightBoundedInterval("abd", BoundType::OPEN)); + /// // Count members between (-inf, +inf) + /// redis.zlexcount("zset", UnboundedInterval{}); + /// @endcode + /// @param key Key where the sorted set is stored. + /// @param interval The min-max range in lexicographical order. + /// @return Number of members between a min-max range in lexicographical order. + /// @see `BoundedInterval` + /// @see `LeftBoundedInterval` + /// @see `RightBoundedInterval` + /// @see `UnboundedInterval` + /// @see `BoundType` + /// @see https://redis.io/commands/zlexcount + // TODO: add a string version of Interval: zlexcount("key", "(abc", "abd"). + template + long long zlexcount(const StringView &key, const Interval &interval); + + /// @brief Pop the member with highest score from sorted set. + /// @param key Key where the sorted set is stored. + /// @return Member-score pair with the highest score. + /// @note If sorted set is empty `zpopmax` returns + /// `Optional>{}` (`std::nullopt`). + /// @see `Redis::bzpopmax` + /// @see https://redis.io/commands/zpopmax + Optional> zpopmax(const StringView &key); + + /// @brief Pop multiple members with highest score from sorted set. + /// @param key Key where the sorted set is stored. + /// @param count Number of members to be popped. + /// @param output Output iterator to the destination where the result is saved. + /// @note The number of returned members might be less than `count`. + /// @see `Redis::bzpopmax` + /// @see https://redis.io/commands/zpopmax + template + void zpopmax(const StringView &key, long long count, Output output); + + /// @brief Pop the member with lowest score from sorted set. + /// @param key Key where the sorted set is stored. + /// @return Member-score pair with the lowest score. + /// @note If sorted set is empty `zpopmin` returns + /// `Optional>{}` (`std::nullopt`). + /// @see `Redis::bzpopmin` + /// @see https://redis.io/commands/zpopmin + Optional> zpopmin(const StringView &key); + + /// @brief Pop multiple members with lowest score from sorted set. + /// @param key Key where the sorted set is stored. + /// @param count Number of members to be popped. + /// @param output Output iterator to the destination where the result is saved. + /// @note The number of returned members might be less than `count`. + /// @see `Redis::bzpopmin` + /// @see https://redis.io/commands/zpopmin + template + void zpopmin(const StringView &key, long long count, Output output); + + /// @brief Get a range of members by rank (ordered from lowest to highest). + /// + /// Example: + /// @code{.cpp} + /// // send *ZRANGE* command without the *WITHSCORES* option: + /// std::vector result; + /// redis.zrange("zset", 0, -1, std::back_inserter(result)); + /// // send command with *WITHSCORES* option: + /// std::vector> with_score; + /// redis.zrange("zset", 0, -1, std::back_inserter(with_score)); + /// @endcode + /// @param key Key where the sorted set is stored. + /// @param start Start rank. Inclusive and can be negative. + /// @param stop Stop rank. Inclusive and can be negative. + /// @param output Output iterator to the destination where the result is saved. + /// @note This method can also return the score of each member. If `output` is an iterator + /// to a container of `std::string`, we send *ZRANGE key start stop* command. + /// If it's an iterator to a container of `std::pair`, + /// we send *ZRANGE key start stop WITHSCORES* command. See the *Example* part on + /// how to use this method. + /// @see `Redis::zrevrange` + /// @see https://redis.io/commands/zrange + template + void zrange(const StringView &key, long long start, long long stop, Output output); + + /// @brief Get a range of members by lexicographical order (from lowest to highest). + /// + /// Example: + /// @code{.cpp} + /// std::vector result; + /// // Get members between [abc, abd]. + /// redis.zrangebylex("zset", BoundedInterval("abc", "abd", BoundType::CLOSED), + /// std::back_inserter(result)); + /// @endcode + /// @param key Key where the sorted set is stored. + /// @param interval the min-max range by lexicographical order. + /// @param output Output iterator to the destination where the result is saved. + /// @note See `Redis::zlexcount`'s *Example* part for how to set `interval` parameter. + /// @see `Redis::zlexcount` + /// @see `BoundedInterval` + /// @see `LeftBoundedInterval` + /// @see `RightBoundedInterval` + /// @see `UnboundedInterval` + /// @see `BoundType` + /// @see `Redis::zrevrangebylex` + /// @see https://redis.io/commands/zrangebylex + template + void zrangebylex(const StringView &key, const Interval &interval, Output output); + + /// @brief Get a range of members by lexicographical order (from lowest to highest). + /// + /// Example: + /// @code{.cpp} + /// std::vector result; + /// // Limit the result to at most 5 members starting from 10. + /// LimitOptions opts; + /// opts.offset = 10; + /// opts.count = 5; + /// // Get members between [abc, abd]. + /// redis.zrangebylex("zset", BoundedInterval("abc", "abd", BoundType::CLOSED), + /// opts, std::back_inserter(result)); + /// @endcode + /// @param key Key where the sorted set is stored. + /// @param interval the min-max range by lexicographical order. + /// @param opts Options to do pagination, i.e. *LIMIT offset count*. + /// @param output Output iterator to the destination where the result is saved. + /// @note See `Redis::zlexcount`'s *Example* part for how to set `interval` parameter. + /// @see `Redis::zlexcount` + /// @see `BoundedInterval` + /// @see `LeftBoundedInterval` + /// @see `RightBoundedInterval` + /// @see `UnboundedInterval` + /// @see `BoundType` + /// @see `LimitOptions` + /// @see `Redis::zrevrangebylex` + /// @see https://redis.io/commands/zrangebylex + template + void zrangebylex(const StringView &key, + const Interval &interval, + const LimitOptions &opts, + Output output); + + /// @brief Get a range of members by score (ordered from lowest to highest). + /// + /// Example: + /// @code{.cpp} + /// // Send *ZRANGEBYSCORE* command without the *WITHSCORES* option: + /// std::vector result; + /// // Get members whose score between (3, 6). + /// redis.zrangebyscore("zset", BoundedInterval(3, 6, BoundType::OPEN), + /// std::back_inserter(result)); + /// // Send command with *WITHSCORES* option: + /// std::vector> with_score; + /// // Get members whose score between [3, +inf). + /// redis.zrangebyscore("zset", LeftBoundedInterval(3, BoundType::RIGHT_OPEN), + /// std::back_inserter(with_score)); + /// @endcode + /// @param key Key where the sorted set is stored. + /// @param interval the min-max range by score. + /// @param output Output iterator to the destination where the result is saved. + /// @note This method can also return the score of each member. If `output` is an iterator + /// to a container of `std::string`, we send *ZRANGEBYSCORE key min max* command. + /// If it's an iterator to a container of `std::pair`, + /// we send *ZRANGEBYSCORE key min max WITHSCORES* command. See the *Example* part on + /// how to use this method. + /// @note See `Redis::zcount`'s *Example* part for how to set the `interval` parameter. + /// @see `Redis::zrevrangebyscore` + /// @see https://redis.io/commands/zrangebyscore + template + void zrangebyscore(const StringView &key, const Interval &interval, Output output); + + /// @brief Get a range of members by score (ordered from lowest to highest). + /// + /// Example: + /// @code{.cpp} + /// // Send *ZRANGEBYSCORE* command without the *WITHSCORES* option: + /// std::vector result; + /// // Only return at most 5 members starting from 10. + /// LimitOptions opts; + /// opts.offset = 10; + /// opts.count = 5; + /// // Get members whose score between (3, 6). + /// redis.zrangebyscore("zset", BoundedInterval(3, 6, BoundType::OPEN), + /// opts, std::back_inserter(result)); + /// // Send command with *WITHSCORES* option: + /// std::vector> with_score; + /// // Get members whose score between [3, +inf). + /// redis.zrangebyscore("zset", LeftBoundedInterval(3, BoundType::RIGHT_OPEN), + /// opts, std::back_inserter(with_score)); + /// @endcode + /// @param key Key where the sorted set is stored. + /// @param interval the min-max range by score. + /// @param opts Options to do pagination, i.e. *LIMIT offset count*. + /// @param output Output iterator to the destination where the result is saved. + /// @note This method can also return the score of each member. If `output` is an iterator + /// to a container of `std::string`, we send *ZRANGEBYSCORE key min max* command. + /// If it's an iterator to a container of `std::pair`, + /// we send *ZRANGEBYSCORE key min max WITHSCORES* command. See the *Example* part on + /// how to use this method. + /// @note See `Redis::zcount`'s *Example* part for how to set the `interval` parameter. + /// @see `Redis::zrevrangebyscore` + /// @see https://redis.io/commands/zrangebyscore + template + void zrangebyscore(const StringView &key, + const Interval &interval, + const LimitOptions &opts, + Output output); + + /// @brief Get the rank (from low to high) of the given member in the sorted set. + /// @param key Key where the sorted set is stored. + /// @param member Member. + /// @return The rank of the given member. + /// @note If the member does not exist, `zrank` returns `OptionalLongLong{}` (`std::nullopt`). + /// @see https://redis.io/commands/zrank + OptionalLongLong zrank(const StringView &key, const StringView &member); + + /// @brief Remove the given member from sorted set. + /// @param key Key where the sorted set is stored. + /// @param member Member to be removed. + /// @return Whether the member has been removed. + /// @retval 1 If the member exists, and has been removed. + /// @retval 0 If the member does not exist. + /// @see https://redis.io/commands/zrem + long long zrem(const StringView &key, const StringView &member); + + /// @brief Remove multiple members from sorted set. + /// @param key Key where the sorted set is stored. + /// @param first Iterator to the first member. + /// @param last Off-the-end iterator to the given range. + /// @return Number of members that have been removed. + /// @see https://redis.io/commands/zrem + template + long long zrem(const StringView &key, Input first, Input last); + + /// @brief Remove multiple members from sorted set. + /// @param key Key where the sorted set is stored. + /// @param il Initializer list of members to be removed. + /// @return Number of members that have been removed. + /// @see https://redis.io/commands/zrem + template + long long zrem(const StringView &key, std::initializer_list il) { + return zrem(key, il.begin(), il.end()); + } + + /// @brief Remove members in the given range of lexicographical order. + /// @param key Key where the sorted set is stored. + /// @param interval the min-max range by lexicographical order. + /// @note See `Redis::zlexcount`'s *Example* part for how to set `interval` parameter. + /// @return Number of members removed. + /// @see `Redis::zlexcount` + /// @see `BoundedInterval` + /// @see `LeftBoundedInterval` + /// @see `RightBoundedInterval` + /// @see `UnboundedInterval` + /// @see `BoundType` + /// @see https://redis.io/commands/zremrangebylex + template + long long zremrangebylex(const StringView &key, const Interval &interval); + + /// @brief Remove members in the given range ordered by rank. + /// @param key Key where the sorted set is stored. + /// @param start Start rank. + /// @param stop Stop rank. + /// @return Number of members removed. + /// @see https://redis.io/commands/zremrangebyrank + long long zremrangebyrank(const StringView &key, long long start, long long stop); + + /// @brief Remove members in the given range ordered by score. + /// @param key Key where the sorted set is stored. + /// @param interval the min-max range by score. + /// @return Number of members removed. + /// @note See `Redis::zcount`'s *Example* part for how to set the `interval` parameter. + /// @see https://redis.io/commands/zremrangebyscore + template + long long zremrangebyscore(const StringView &key, const Interval &interval); + + /// @brief Get a range of members by rank (ordered from highest to lowest). + /// + /// Example: + /// @code{.cpp} + /// // send *ZREVRANGE* command without the *WITHSCORES* option: + /// std::vector result; + /// redis.zrevrange("key", 0, -1, std::back_inserter(result)); + /// // send command with *WITHSCORES* option: + /// std::vector> with_score; + /// redis.zrevrange("key", 0, -1, std::back_inserter(with_score)); + /// @endcode + /// @param key Key where the sorted set is stored. + /// @param start Start rank. Inclusive and can be negative. + /// @param stop Stop rank. Inclusive and can be negative. + /// @param output Output iterator to the destination where the result is saved. + /// @note This method can also return the score of each member. If `output` is an iterator + /// to a container of `std::string`, we send *ZREVRANGE key start stop* command. + /// If it's an iterator to a container of `std::pair`, + /// we send *ZREVRANGE key start stop WITHSCORES* command. See the *Example* part on + /// how to use this method. + /// @see `Redis::zrange` + /// @see https://redis.io/commands/zrevrange + template + void zrevrange(const StringView &key, long long start, long long stop, Output output); + + /// @brief Get a range of members by lexicographical order (from highest to lowest). + /// + /// Example: + /// @code{.cpp} + /// std::vector result; + /// // Get members between [abc, abd] in reverse order. + /// redis.zrevrangebylex("zset", BoundedInterval("abc", "abd", BoundType::CLOSED), + /// std::back_inserter(result)); + /// @endcode + /// @param key Key where the sorted set is stored. + /// @param interval the min-max range by lexicographical order. + /// @param output Output iterator to the destination where the result is saved. + /// @note See `Redis::zlexcount`'s *Example* part for how to set `interval` parameter. + /// @see `Redis::zlexcount` + /// @see `BoundedInterval` + /// @see `LeftBoundedInterval` + /// @see `RightBoundedInterval` + /// @see `UnboundedInterval` + /// @see `BoundType` + /// @see `Redis::zrangebylex` + /// @see https://redis.io/commands/zrevrangebylex + template + void zrevrangebylex(const StringView &key, const Interval &interval, Output output); + + /// @brief Get a range of members by lexicographical order (from highest to lowest). + /// + /// Example: + /// @code{.cpp} + /// std::vector result; + /// // Limit the result to at most 5 members starting from 10. + /// LimitOptions opts; + /// opts.offset = 10; + /// opts.count = 5; + /// // Get members between [abc, abd] in reverse order. + /// redis.zrevrangebylex("zset", BoundedInterval("abc", "abd", BoundType::CLOSED), + /// opts, std::back_inserter(result)); + /// @endcode + /// @param key Key where the sorted set is stored. + /// @param interval the min-max range by lexicographical order. + /// @param opts Options to do pagination, i.e. *LIMIT offset count*. + /// @param output Output iterator to the destination where the result is saved. + /// @note See `Redis::zlexcount`'s *Example* part for how to set `interval` parameter. + /// @see `Redis::zlexcount` + /// @see `BoundedInterval` + /// @see `LeftBoundedInterval` + /// @see `RightBoundedInterval` + /// @see `UnboundedInterval` + /// @see `BoundType` + /// @see `LimitOptions` + /// @see `Redis::zrangebylex` + /// @see https://redis.io/commands/zrevrangebylex + template + void zrevrangebylex(const StringView &key, + const Interval &interval, + const LimitOptions &opts, + Output output); + + /// @brief Get a range of members by score (ordered from highest to lowest). + /// + /// Example: + /// @code{.cpp} + /// // Send *ZREVRANGEBYSCORE* command without the *WITHSCORES* option: + /// std::vector result; + /// // Get members whose score between (3, 6) in reverse order. + /// redis.zrevrangebyscore("zset", BoundedInterval(3, 6, BoundType::OPEN), + /// std::back_inserter(result)); + /// // Send command with *WITHSCORES* option: + /// std::vector> with_score; + /// // Get members whose score between [3, +inf) in reverse order. + /// redis.zrevrangebyscore("zset", LeftBoundedInterval(3, BoundType::RIGHT_OPEN), + /// std::back_inserter(with_score)); + /// @endcode + /// @param key Key where the sorted set is stored. + /// @param interval the min-max range by score. + /// @param output Output iterator to the destination where the result is saved. + /// @note This method can also return the score of each member. If `output` is an iterator + /// to a container of `std::string`, we send *ZREVRANGEBYSCORE key min max* command. + /// If it's an iterator to a container of `std::pair`, + /// we send *ZREVRANGEBYSCORE key min max WITHSCORES* command. See the *Example* part on + /// how to use this method. + /// @note See `Redis::zcount`'s *Example* part for how to set the `interval` parameter. + /// @see `Redis::zrangebyscore` + /// @see https://redis.io/commands/zrevrangebyscore + template + void zrevrangebyscore(const StringView &key, const Interval &interval, Output output); + + /// @brief Get a range of members by score (ordered from highest to lowest). + /// + /// Example: + /// @code{.cpp} + /// // Send *ZREVRANGEBYSCORE* command without the *WITHSCORES* option: + /// std::vector result; + /// // Only return at most 5 members starting from 10. + /// LimitOptions opts; + /// opts.offset = 10; + /// opts.count = 5; + /// // Get members whose score between (3, 6) in reverse order. + /// redis.zrevrangebyscore("zset", BoundedInterval(3, 6, BoundType::OPEN), + /// opts, std::back_inserter(result)); + /// // Send command with *WITHSCORES* option: + /// std::vector> with_score; + /// // Get members whose score between [3, +inf) in reverse order. + /// redis.zrevrangebyscore("zset", LeftBoundedInterval(3, BoundType::RIGHT_OPEN), + /// opts, std::back_inserter(with_score)); + /// @endcode + /// @param key Key where the sorted set is stored. + /// @param interval the min-max range by score. + /// @param opts Options to do pagination, i.e. *LIMIT offset count*. + /// @param output Output iterator to the destination where the result is saved. + /// @note This method can also return the score of each member. If `output` is an iterator + /// to a container of `std::string`, we send *ZREVRANGEBYSCORE key min max* command. + /// If it's an iterator to a container of `std::pair`, + /// we send *ZREVRANGEBYSCORE key min max WITHSCORES* command. See the *Example* part on + /// how to use this method. + /// @note See `Redis::zcount`'s *Example* part for how to set the `interval` parameter. + /// @see `Redis::zrangebyscore` + /// @see https://redis.io/commands/zrevrangebyscore + template + void zrevrangebyscore(const StringView &key, + const Interval &interval, + const LimitOptions &opts, + Output output); + + /// @brief Get the rank (from high to low) of the given member in the sorted set. + /// @param key Key where the sorted set is stored. + /// @param member Member. + /// @return The rank of the given member. + /// @note If the member does not exist, `zrevrank` returns `OptionalLongLong{}` (`std::nullopt`). + /// @see https://redis.io/commands/zrevrank + OptionalLongLong zrevrank(const StringView &key, const StringView &member); + + /// @brief Scan members of the given sorted set matching the given pattern. + /// + /// Example: + /// @code{.cpp} + /// auto cursor = 0LL; + /// std::vector> members; + /// while (true) { + /// cursor = redis.zscan("zset", cursor, "pattern:*", + /// 10, std::back_inserter(members)); + /// if (cursor == 0) { + /// break; + /// } + /// } + /// @endcode + /// @param key Key where the sorted set is stored. + /// @param cursor Cursor. + /// @param pattern Pattern of members to be scanned. + /// @param count A hint for how many members to be scanned. + /// @param output Output iterator to the destination where the result is saved. + /// @return The cursor to be used for the next scan operation. + /// @see https://redis.io/commands/zscan + template + long long zscan(const StringView &key, + long long cursor, + const StringView &pattern, + long long count, + Output output); + + /// @brief Scan members of the given sorted set matching the given pattern. + /// @param key Key where the sorted set is stored. + /// @param cursor Cursor. + /// @param pattern Pattern of members to be scanned. + /// @param output Output iterator to the destination where the result is saved. + /// @return The cursor to be used for the next scan operation. + /// @see https://redis.io/commands/zscan + template + long long zscan(const StringView &key, + long long cursor, + const StringView &pattern, + Output output); + + /// @brief Scan all members of the given sorted set. + /// @param key Key where the sorted set is stored. + /// @param cursor Cursor. + /// @param count A hint for how many members to be scanned. + /// @param output Output iterator to the destination where the result is saved. + /// @return The cursor to be used for the next scan operation. + /// @see https://redis.io/commands/zscan + template + long long zscan(const StringView &key, + long long cursor, + long long count, + Output output); + + /// @brief Scan all members of the given sorted set. + /// @param key Key where the sorted set is stored. + /// @param cursor Cursor. + /// @param output Output iterator to the destination where the result is saved. + /// @return The cursor to be used for the next scan operation. + /// @see https://redis.io/commands/zscan + template + long long zscan(const StringView &key, + long long cursor, + Output output); + + /// @brief Get the score of the given member. + /// @param key Key where the sorted set is stored. + /// @param member Member. + /// @return The score of the member. + /// @note If member does not exist, `zscore` returns `OptionalDouble{}` (`std::nullopt`). + /// @see https://redis.io/commands/zscore + OptionalDouble zscore(const StringView &key, const StringView &member); + + /// @brief Copy a sorted set to another one with the scores being multiplied by a factor. + /// @param destination Key of the destination sorted set. + /// @param key Key of the source sorted set. + /// @param weight Weight to be multiplied to the score of each member. + /// @return The number of members in the sorted set. + /// @note There's no aggregation type parameter for single key overload, since these 3 types + /// have the same effect. + /// @see `Redis::zinterstore` + /// @see https://redis.io/commands/zinterstore + long long zunionstore(const StringView &destination, const StringView &key, double weight); + + /// @brief Get union of multiple sorted sets, and store the result to another one. + /// + /// Example: + /// @code{.cpp} + /// // Use the default weight, i.e. 1, + /// // and use the sum of the all scores as the score of the result: + /// std::vector keys = {"k1", "k2", "k3"}; + /// redis.zunionstore("destination", keys.begin(), keys.end()); + /// // Each sorted set has a different weight, + /// // and the score of the result is the min of all scores. + /// std::vector> keys_with_weights = {{"k1", 1}, {"k2", 2}}; + /// redis.zunionstore("destination", keys_with_weights.begin(), + /// keys_with_weights.end(), Aggregation::MIN); + /// // NOTE: `keys_with_weights` can also be of type `std::unordered_map`. + /// // However, it will be slower than std::vector>, since we use + /// // `std::distance(first, last)` to calculate the *numkeys* parameter. + /// @endcode + /// @param destination Key of the destination sorted set. + /// @param first Iterator to the first sorted set (might with weight). + /// @param last Off-the-end iterator to the sorted set range. + /// @param type How the scores are aggregated. + /// - Aggregation::SUM: Score of a member is the sum of all scores. + /// - Aggregation::MIN: Score of a member is the min of all scores. + /// - Aggregation::MAX: Score of a member is the max of all scores. + /// @return The number of members in the resulting sorted set. + /// @note The score of each member can be multiplied by a factor, i.e. weight. If `Input` is an + /// iterator to a container of `std::string`, we use the default weight, i.e. 1, and send + /// *ZUNIONSTORE dest numkeys key [key ...] [AGGREGATE SUM|MIN|MAX]* command. + /// If `Input` is an iterator to a container of `std::pair`, + /// i.e. key-weight pair, we send the command with the given weights: + /// *ZUNIONSTORE dest numkeys key [key ...] [WEIGHTS weight [weight ...]] [AGGREGATE SUM|MIN|MAX]*. + /// See the *Example* part for examples on how to use this command. + /// @see `Redis::zinterstore` + /// @see https://redis.io/commands/zunionstore + template + long long zunionstore(const StringView &destination, + Input first, + Input last, + Aggregation type = Aggregation::SUM); + + /// @brief Get union of multiple sorted sets, and store the result to another one. + /// + /// Example: + /// @code{.cpp} + /// // Use the default weight, i.e. 1, + /// // and use the sum of the all scores as the score of the result: + /// redis.zunionstore("destination", {"k1", "k2"}); + /// // Each sorted set has a different weight, + /// // and the score of the result is the min of all scores. + /// redis.zunionstore("destination", + /// {std::make_pair("k1", 1), std::make_pair("k2", 2)}, Aggregation::MIN); + /// @endcode + /// @param destination Key of the destination sorted set. + /// @param il Initializer list of sorted set. + /// @param type How the scores are aggregated. + /// - Aggregation::SUM: Score of a member is the sum of all scores. + /// - Aggregation::MIN: Score of a member is the min of all scores. + /// - Aggregation::MAX: Score of a member is the max of all scores. + /// @return The number of members in the resulting sorted set. + /// @note The score of each member can be multiplied by a factor, i.e. weight. If `T` is + /// of type `std::string`, we use the default weight, i.e. 1, and send + /// *ZUNIONSTORE dest numkeys key [key ...] [AGGREGATE SUM|MIN|MAX]* command. + /// If `T` is of type `std::pair`, i.e. key-weight pair, + /// we send the command with the given weights: + /// *ZUNIONSTORE dest numkeys key [key ...] [WEIGHTS weight [weight ...]] [AGGREGATE SUM|MIN|MAX]*. + /// See the *Example* part for examples on how to use this command. + /// @see `Redis::zinterstore` + /// @see https://redis.io/commands/zunionstore + template + long long zunionstore(const StringView &destination, + std::initializer_list il, + Aggregation type = Aggregation::SUM) { + return zunionstore(destination, il.begin(), il.end(), type); + } + + // HYPERLOGLOG commands. + + /// @brief Add the given element to a hyperloglog. + /// @param key Key of the hyperloglog. + /// @param element Element to be added. + /// @return Whether any of hyperloglog's internal register has been altered. + /// @retval true If at least one internal register has been altered. + /// @retval false If none of internal registers has been altered. + /// @note When `pfadd` returns false, it does not mean that this method failed to add + /// an element to the hyperloglog. Instead it means that the internal registers + /// were not altered. If `pfadd` fails, it will throw an exception of `Exception` type. + /// @see https://redis.io/commands/pfadd + bool pfadd(const StringView &key, const StringView &element); + + /// @brief Add the given elements to a hyperloglog. + /// @param key Key of the hyperloglog. + /// @param first Iterator to the first element. + /// @param last Off-the-end iterator to the given range. + /// @return Whether any of hyperloglog's internal register has been altered. + /// @retval true If at least one internal register has been altered. + /// @retval false If none of internal registers has been altered. + /// @note When `pfadd` returns false, it does not mean that this method failed to add + /// an element to the hyperloglog. Instead it means that the internal registers + /// were not altered. If `pfadd` fails, it will throw an exception of `Exception` type. + /// @see https://redis.io/commands/pfadd + template + bool pfadd(const StringView &key, Input first, Input last); + + /// @brief Add the given elements to a hyperloglog. + /// @param key Key of the hyperloglog. + /// @param il Initializer list of elements to be added. + /// @return Whether any of hyperloglog's internal register has been altered. + /// @retval true If at least one internal register has been altered. + /// @retval false If none of internal registers has been altered. + /// @note When `pfadd` returns false, it does not mean that this method failed to add + /// an element to the hyperloglog. Instead it means that the internal registers + /// were not altered. If `pfadd` fails, it will throw an exception of `Exception` type. + /// @see https://redis.io/commands/pfadd + template + bool pfadd(const StringView &key, std::initializer_list il) { + return pfadd(key, il.begin(), il.end()); + } + + long long pfcount(const StringView &key); + + template + long long pfcount(Input first, Input last); + + template + long long pfcount(std::initializer_list il) { + return pfcount(il.begin(), il.end()); + } + + void pfmerge(const StringView &destination, const StringView &key); + + template + void pfmerge(const StringView &destination, Input first, Input last); + + template + void pfmerge(const StringView &destination, std::initializer_list il) { + pfmerge(destination, il.begin(), il.end()); + } + + // GEO commands. + + long long geoadd(const StringView &key, + const std::tuple &member); + + template + long long geoadd(const StringView &key, + Input first, + Input last); + + template + long long geoadd(const StringView &key, + std::initializer_list il) { + return geoadd(key, il.begin(), il.end()); + } + + OptionalDouble geodist(const StringView &key, + const StringView &member1, + const StringView &member2, + GeoUnit unit = GeoUnit::M); + + OptionalString geohash(const StringView &key, const StringView &member); + + template + void geohash(const StringView &key, Input first, Input last, Output output); + + template + void geohash(const StringView &key, std::initializer_list il, Output output) { + geohash(key, il.begin(), il.end(), output); + } + + Optional> geopos(const StringView &key, const StringView &member); + + template + void geopos(const StringView &key, Input first, Input last, Output output); + + template + void geopos(const StringView &key, std::initializer_list il, Output output) { + geopos(key, il.begin(), il.end(), output); + } + + // TODO: + // 1. since we have different overloads for georadius and georadius-store, + // we might use the GEORADIUS_RO command in the future. + // 2. there're too many parameters for this method, we might refactor it. + + /// @brief Get members in geo range, i.e. a circle, and store them in a sorted set. + /// @param key Key of the GEO set. + /// @param loc Location encoded with pair. + /// @param radius Radius of the range. + /// @param unit Radius unit. + /// @param destination Key of the destination sorted set. + /// @param store_dist Whether store distance info instead of geo info to destination. + /// @param count Limit the first N members. + /// @return Number of members stored in destination. + /// @note Before Redis 6.2.6, if key does not exist, returns `OptionalLongLong{}` (`std::nullopt`). + /// Since Redis 6.2.6, if key does not exist, returns 0. + /// @see `GeoUnit` + /// @see `Redis::georadiusbymember` + /// @see https://redis.io/commands/georadius + OptionalLongLong georadius(const StringView &key, + const std::pair &loc, + double radius, + GeoUnit unit, + const StringView &destination, + bool store_dist, + long long count); + + // If *output* is an iterator of a container of string, we send *GEORADIUS* command + // without any options and only get the members in the specified geo range. + // If *output* is an iterator of a container of a tuple, the type of the tuple decides + // options we send with the *GEORADIUS* command. If the tuple has an element of type + // double, we send the *WITHDIST* option. If it has an element of type string, we send + // the *WITHHASH* option. If it has an element of type pair, we send + // the *WITHCOORD* option. For example: + // + // The following code only gets the members in range, i.e. without any option. + // + // vector members; + // redis.georadius("key", make_pair(10.1, 10.2), 10, GeoUnit::KM, 10, true, + // back_inserter(members)) + // + // The following code sends the command with *WITHDIST* option. + // + // vector> with_dist; + // redis.georadius("key", make_pair(10.1, 10.2), 10, GeoUnit::KM, 10, true, + // back_inserter(with_dist)) + // + // The following code sends the command with *WITHDIST* and *WITHHASH* options. + // + // vector> with_dist_hash; + // redis.georadius("key", make_pair(10.1, 10.2), 10, GeoUnit::KM, 10, true, + // back_inserter(with_dist_hash)) + // + // The following code sends the command with *WITHDIST*, *WITHCOORD* and *WITHHASH* options. + // + // vector, string>> with_dist_coord_hash; + // redis.georadius("key", make_pair(10.1, 10.2), 10, GeoUnit::KM, 10, true, + // back_inserter(with_dist_coord_hash)) + // + // This also applies to *GEORADIUSBYMEMBER*. + template + void georadius(const StringView &key, + const std::pair &loc, + double radius, + GeoUnit unit, + long long count, + bool asc, + Output output); + + /// @brief Get members in geo range, i.e. a circle, and store them in a sorted set. + /// @param key Key of the GEO set. + /// @param member Member which is the center of the circle. + /// @param radius Radius of the range. + /// @param unit Radius unit. + /// @param destination Key of the destination sorted set. + /// @param store_dist Whether store distance info instead of geo info to destination. + /// @param count Limit the first N members. + /// @return Number of members stored in destination. + /// @note Before Redis 6.2.6, if key does not exist, returns `OptionalLongLong{}` (`std::nullopt`). + /// Since Redis 6.2.6, if key does not exist, returns 0. + /// @note If member does not exist, throw an `ReplyError`. + /// @see `GeoUnit` + /// @see `Redis::georadius` + /// @see https://redis.io/commands/georadiusbymember + OptionalLongLong georadiusbymember(const StringView &key, + const StringView &member, + double radius, + GeoUnit unit, + const StringView &destination, + bool store_dist, + long long count); + + // See comments on *GEORADIUS*. + template + void georadiusbymember(const StringView &key, + const StringView &member, + double radius, + GeoUnit unit, + long long count, + bool asc, + Output output); + + // SCRIPTING commands. + + template + Result eval(const StringView &script, + Keys keys_first, + Keys keys_last, + Args args_first, + Args args_last); + + template + Result eval(const StringView &script, + std::initializer_list keys, + std::initializer_list args); + + template + void eval(const StringView &script, + Keys keys_first, + Keys keys_last, + Args args_first, + Args args_last, + Output output); + + template + void eval(const StringView &script, + std::initializer_list keys, + std::initializer_list args, + Output output); + + template + Result evalsha(const StringView &script, + Keys keys_first, + Keys keys_last, + Args args_first, + Args args_last); + + template + Result evalsha(const StringView &script, + std::initializer_list keys, + std::initializer_list args); + + template + void evalsha(const StringView &script, + Keys keys_first, + Keys keys_last, + Args args_first, + Args args_last, + Output output); + + template + void evalsha(const StringView &script, + std::initializer_list keys, + std::initializer_list args, + Output output); + + /// @brief Check if the given script exists. + /// @param sha1 SHA1 digest of the script. + /// @return Whether the script exists. + /// @retval true If the script exists. + /// @retval false If the script does not exist. + /// @see https://redis.io/commands/script-exists + bool script_exists(const StringView &sha1); + + template + void script_exists(Input first, Input last, Output output); + + template + void script_exists(std::initializer_list il, Output output) { + script_exists(il.begin(), il.end(), output); + } + + void script_flush(); + + void script_kill(); + + std::string script_load(const StringView &script); + + // PUBSUB commands. + + long long publish(const StringView &channel, const StringView &message); + + // Transaction commands. + void watch(const StringView &key); + + template + void watch(Input first, Input last); + + template + void watch(std::initializer_list il) { + watch(il.begin(), il.end()); + } + + void unwatch(); + + // Stream commands. + + long long xack(const StringView &key, const StringView &group, const StringView &id); + + template + long long xack(const StringView &key, const StringView &group, Input first, Input last); + + template + long long xack(const StringView &key, const StringView &group, std::initializer_list il) { + return xack(key, group, il.begin(), il.end()); + } + + template + std::string xadd(const StringView &key, const StringView &id, Input first, Input last); + + template + std::string xadd(const StringView &key, const StringView &id, std::initializer_list il) { + return xadd(key, id, il.begin(), il.end()); + } + + template + std::string xadd(const StringView &key, + const StringView &id, + Input first, + Input last, + long long count, + bool approx = true); + + template + std::string xadd(const StringView &key, + const StringView &id, + std::initializer_list il, + long long count, + bool approx = true) { + return xadd(key, id, il.begin(), il.end(), count, approx); + } + + template + void xclaim(const StringView &key, + const StringView &group, + const StringView &consumer, + const std::chrono::milliseconds &min_idle_time, + const StringView &id, + Output output); + + template + void xclaim(const StringView &key, + const StringView &group, + const StringView &consumer, + const std::chrono::milliseconds &min_idle_time, + Input first, + Input last, + Output output); + + template + void xclaim(const StringView &key, + const StringView &group, + const StringView &consumer, + const std::chrono::milliseconds &min_idle_time, + std::initializer_list il, + Output output) { + xclaim(key, group, consumer, min_idle_time, il.begin(), il.end(), output); + } + + long long xdel(const StringView &key, const StringView &id); + + template + long long xdel(const StringView &key, Input first, Input last); + + template + long long xdel(const StringView &key, std::initializer_list il) { + return xdel(key, il.begin(), il.end()); + } + + void xgroup_create(const StringView &key, + const StringView &group, + const StringView &id, + bool mkstream = false); + + void xgroup_setid(const StringView &key, const StringView &group, const StringView &id); + + long long xgroup_destroy(const StringView &key, const StringView &group); + + long long xgroup_delconsumer(const StringView &key, + const StringView &group, + const StringView &consumer); + + long long xlen(const StringView &key); + + template + auto xpending(const StringView &key, const StringView &group, Output output) + -> std::tuple; + + template + void xpending(const StringView &key, + const StringView &group, + const StringView &start, + const StringView &end, + long long count, + Output output); + + template + void xpending(const StringView &key, + const StringView &group, + const StringView &start, + const StringView &end, + long long count, + const StringView &consumer, + Output output); + + template + void xrange(const StringView &key, + const StringView &start, + const StringView &end, + Output output); + + template + void xrange(const StringView &key, + const StringView &start, + const StringView &end, + long long count, + Output output); + + template + void xread(const StringView &key, + const StringView &id, + long long count, + Output output); + + template + void xread(const StringView &key, + const StringView &id, + Output output) { + xread(key, id, 0, output); + } + + template + auto xread(Input first, Input last, long long count, Output output) + -> typename std::enable_if::value>::type; + + template + auto xread(Input first, Input last, Output output) + -> typename std::enable_if::value>::type { + xread(first ,last, 0, output); + } + + template + void xread(const StringView &key, + const StringView &id, + const std::chrono::milliseconds &timeout, + long long count, + Output output); + + template + void xread(const StringView &key, + const StringView &id, + const std::chrono::milliseconds &timeout, + Output output) { + xread(key, id, timeout, 0, output); + } + + template + auto xread(Input first, + Input last, + const std::chrono::milliseconds &timeout, + long long count, + Output output) + -> typename std::enable_if::value>::type; + + template + auto xread(Input first, + Input last, + const std::chrono::milliseconds &timeout, + Output output) + -> typename std::enable_if::value>::type { + xread(first, last, timeout, 0, output); + } + + template + void xreadgroup(const StringView &group, + const StringView &consumer, + const StringView &key, + const StringView &id, + long long count, + bool noack, + Output output); + + template + void xreadgroup(const StringView &group, + const StringView &consumer, + const StringView &key, + const StringView &id, + long long count, + Output output) { + xreadgroup(group, consumer, key, id, count, false, output); + } + + template + void xreadgroup(const StringView &group, + const StringView &consumer, + const StringView &key, + const StringView &id, + Output output) { + xreadgroup(group, consumer, key, id, 0, false, output); + } + + template + auto xreadgroup(const StringView &group, + const StringView &consumer, + Input first, + Input last, + long long count, + bool noack, + Output output) + -> typename std::enable_if::value>::type; + + template + auto xreadgroup(const StringView &group, + const StringView &consumer, + Input first, + Input last, + long long count, + Output output) + -> typename std::enable_if::value>::type { + xreadgroup(group, consumer, first ,last, count, false, output); + } + + template + auto xreadgroup(const StringView &group, + const StringView &consumer, + Input first, + Input last, + Output output) + -> typename std::enable_if::value>::type { + xreadgroup(group, consumer, first ,last, 0, false, output); + } + + template + void xreadgroup(const StringView &group, + const StringView &consumer, + const StringView &key, + const StringView &id, + const std::chrono::milliseconds &timeout, + long long count, + bool noack, + Output output); + + template + void xreadgroup(const StringView &group, + const StringView &consumer, + const StringView &key, + const StringView &id, + const std::chrono::milliseconds &timeout, + long long count, + Output output) { + xreadgroup(group, consumer, key, id, timeout, count, false, output); + } + + template + void xreadgroup(const StringView &group, + const StringView &consumer, + const StringView &key, + const StringView &id, + const std::chrono::milliseconds &timeout, + Output output) { + xreadgroup(group, consumer, key, id, timeout, 0, false, output); + } + + template + auto xreadgroup(const StringView &group, + const StringView &consumer, + Input first, + Input last, + const std::chrono::milliseconds &timeout, + long long count, + bool noack, + Output output) + -> typename std::enable_if::value>::type; + + template + auto xreadgroup(const StringView &group, + const StringView &consumer, + Input first, + Input last, + const std::chrono::milliseconds &timeout, + long long count, + Output output) + -> typename std::enable_if::value>::type { + xreadgroup(group, consumer, first, last, timeout, count, false, output); + } + + template + auto xreadgroup(const StringView &group, + const StringView &consumer, + Input first, + Input last, + const std::chrono::milliseconds &timeout, + Output output) + -> typename std::enable_if::value>::type { + xreadgroup(group, consumer, first, last, timeout, 0, false, output); + } + + template + void xrevrange(const StringView &key, + const StringView &end, + const StringView &start, + Output output); + + template + void xrevrange(const StringView &key, + const StringView &end, + const StringView &start, + long long count, + Output output); + + long long xtrim(const StringView &key, long long count, bool approx = true); + +private: + template + friend class QueuedRedis; + + friend class RedisCluster; + + // For internal use. + explicit Redis(const GuardedConnectionSPtr &connection); + + template + ReplyUPtr _command(const StringView &cmd_name, const IndexSequence &, Args &&...args) { + return command(cmd_name, NthValue(std::forward(args)...)...); + } + + template + ReplyUPtr _command(Connection &connection, Cmd cmd, Args &&...args); + + template + ReplyUPtr _score_command(std::true_type, Cmd cmd, Args &&... args); + + template + ReplyUPtr _score_command(std::false_type, Cmd cmd, Args &&... args); + + template + ReplyUPtr _score_command(Cmd cmd, Args &&... args); + + // Pool Mode. + // Public constructors create a *Redis* instance with a pool. + // In this case, *_connection* is a null pointer, and is never used. + ConnectionPoolSPtr _pool; + + // Single Connection Mode. + // Private constructor creates a *Redis* instance with a single connection. + // This is used when we create Transaction, Pipeline and Subscriber. + // In this case, *_pool* is empty, and is never used. + GuardedConnectionSPtr _connection; +}; + +} + +} + +#include "redis.hpp" + +#endif // end SEWENEW_REDISPLUSPLUS_REDIS_H diff --git a/ext/redis-plus-plus-1.3.3/install/ubuntu22.04/arm64/include/sw/redis++/redis.hpp b/ext/redis-plus-plus-1.3.3/install/ubuntu22.04/arm64/include/sw/redis++/redis.hpp new file mode 100644 index 000000000..c560ce111 --- /dev/null +++ b/ext/redis-plus-plus-1.3.3/install/ubuntu22.04/arm64/include/sw/redis++/redis.hpp @@ -0,0 +1,1342 @@ +/************************************************************************** + Copyright (c) 2017 sewenew + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + *************************************************************************/ + +#ifndef SEWENEW_REDISPLUSPLUS_REDIS_HPP +#define SEWENEW_REDISPLUSPLUS_REDIS_HPP + +#include "command.h" +#include "reply.h" +#include "utils.h" +#include "errors.h" + +namespace sw { + +namespace redis { + +template +auto Redis::command(Cmd cmd, Args &&...args) + -> typename std::enable_if::value, ReplyUPtr>::type { + if (_connection) { + // Single Connection Mode. + // TODO: In this case, should we reconnect? + auto &connection = _connection->connection(); + if (connection.broken()) { + throw Error("Connection is broken"); + } + + return _command(connection, cmd, std::forward(args)...); + } else { + assert(_pool); + + // Pool Mode, i.e. get connection from pool. + SafeConnection connection(*_pool); + + return _command(connection.connection(), cmd, std::forward(args)...); + } +} + +template +auto Redis::command(const StringView &cmd_name, Args &&...args) + -> typename std::enable_if::type>::value, ReplyUPtr>::type { + auto cmd = [](Connection &connection, const StringView &cmd_name, Args &&...args) { + CmdArgs cmd_args; + cmd_args.append(cmd_name, std::forward(args)...); + connection.send(cmd_args); + }; + + return command(cmd, cmd_name, std::forward(args)...); +} + +template +auto Redis::command(Input first, Input last) + -> typename std::enable_if::value, ReplyUPtr>::type { + range_check("command", first, last); + + auto cmd = [](Connection &connection, Input first, Input last) { + CmdArgs cmd_args; + while (first != last) { + cmd_args.append(*first); + ++first; + } + connection.send(cmd_args); + }; + + return command(cmd, first, last); +} + +template +Result Redis::command(const StringView &cmd_name, Args &&...args) { + auto r = command(cmd_name, std::forward(args)...); + + assert(r); + + return reply::parse(*r); +} + +template +auto Redis::command(const StringView &cmd_name, Args &&...args) + -> typename std::enable_if::type>::value, void>::type { + auto r = _command(cmd_name, + MakeIndexSequence(), + std::forward(args)...); + + assert(r); + + reply::to_array(*r, LastValue(std::forward(args)...)); +} + +template +auto Redis::command(Input first, Input last) + -> typename std::enable_if::value, Result>::type { + auto r = command(first, last); + + assert(r); + + return reply::parse(*r); +} + +template +auto Redis::command(Input first, Input last, Output output) + -> typename std::enable_if::value, void>::type { + auto r = command(first, last); + + assert(r); + + reply::to_array(*r, output); +} + +// KEY commands. + +template +long long Redis::del(Input first, Input last) { + range_check("DEL", first, last); + + auto reply = command(cmd::del_range, first, last); + + return reply::parse(*reply); +} + +template +long long Redis::exists(Input first, Input last) { + range_check("EXISTS", first, last); + + auto reply = command(cmd::exists_range, first, last); + + return reply::parse(*reply); +} + +inline bool Redis::expire(const StringView &key, const std::chrono::seconds &timeout) { + return expire(key, timeout.count()); +} + +inline bool Redis::expireat(const StringView &key, + const std::chrono::time_point &tp) { + return expireat(key, tp.time_since_epoch().count()); +} + +template +void Redis::keys(const StringView &pattern, Output output) { + auto reply = command(cmd::keys, pattern); + + reply::to_array(*reply, output); +} + +inline bool Redis::pexpire(const StringView &key, const std::chrono::milliseconds &timeout) { + return pexpire(key, timeout.count()); +} + +inline bool Redis::pexpireat(const StringView &key, + const std::chrono::time_point &tp) { + return pexpireat(key, tp.time_since_epoch().count()); +} + +inline void Redis::restore(const StringView &key, + const StringView &val, + const std::chrono::milliseconds &ttl, + bool replace) { + return restore(key, val, ttl.count(), replace); +} + +template +long long Redis::scan(long long cursor, + const StringView &pattern, + long long count, + Output output) { + auto reply = command(cmd::scan, cursor, pattern, count); + + return reply::parse_scan_reply(*reply, output); +} + +template +inline long long Redis::scan(long long cursor, + const StringView &pattern, + Output output) { + return scan(cursor, pattern, 10, output); +} + +template +inline long long Redis::scan(long long cursor, + long long count, + Output output) { + return scan(cursor, "*", count, output); +} + +template +inline long long Redis::scan(long long cursor, + Output output) { + return scan(cursor, "*", 10, output); +} + +template +long long Redis::touch(Input first, Input last) { + range_check("TOUCH", first, last); + + auto reply = command(cmd::touch_range, first, last); + + return reply::parse(*reply); +} + +template +long long Redis::unlink(Input first, Input last) { + range_check("UNLINK", first, last); + + auto reply = command(cmd::unlink_range, first, last); + + return reply::parse(*reply); +} + +inline long long Redis::wait(long long numslaves, const std::chrono::milliseconds &timeout) { + return wait(numslaves, timeout.count()); +} + +// STRING commands. + +template +long long Redis::bitop(BitOp op, const StringView &destination, Input first, Input last) { + range_check("BITOP", first, last); + + auto reply = command(cmd::bitop_range, op, destination, first, last); + + return reply::parse(*reply); +} + +template +void Redis::mget(Input first, Input last, Output output) { + range_check("MGET", first, last); + + auto reply = command(cmd::mget, first, last); + + reply::to_array(*reply, output); +} + +template +void Redis::mset(Input first, Input last) { + range_check("MSET", first, last); + + auto reply = command(cmd::mset, first, last); + + reply::parse(*reply); +} + +template +bool Redis::msetnx(Input first, Input last) { + range_check("MSETNX", first, last); + + auto reply = command(cmd::msetnx, first, last); + + return reply::parse(*reply); +} + +inline void Redis::psetex(const StringView &key, + const std::chrono::milliseconds &ttl, + const StringView &val) { + return psetex(key, ttl.count(), val); +} + +inline void Redis::setex(const StringView &key, + const std::chrono::seconds &ttl, + const StringView &val) { + setex(key, ttl.count(), val); +} + +// LIST commands. + +template +OptionalStringPair Redis::blpop(Input first, Input last, long long timeout) { + range_check("BLPOP", first, last); + + auto reply = command(cmd::blpop_range, first, last, timeout); + + return reply::parse(*reply); +} + +template +OptionalStringPair Redis::blpop(Input first, + Input last, + const std::chrono::seconds &timeout) { + return blpop(first, last, timeout.count()); +} + +template +OptionalStringPair Redis::brpop(Input first, Input last, long long timeout) { + range_check("BRPOP", first, last); + + auto reply = command(cmd::brpop_range, first, last, timeout); + + return reply::parse(*reply); +} + +template +OptionalStringPair Redis::brpop(Input first, + Input last, + const std::chrono::seconds &timeout) { + return brpop(first, last, timeout.count()); +} + +inline OptionalString Redis::brpoplpush(const StringView &source, + const StringView &destination, + const std::chrono::seconds &timeout) { + return brpoplpush(source, destination, timeout.count()); +} + +template +inline long long Redis::lpush(const StringView &key, Input first, Input last) { + range_check("LPUSH", first, last); + + auto reply = command(cmd::lpush_range, key, first, last); + + return reply::parse(*reply); +} + +template +inline void Redis::lrange(const StringView &key, long long start, long long stop, Output output) { + auto reply = command(cmd::lrange, key, start, stop); + + reply::to_array(*reply, output); +} + +template +inline long long Redis::rpush(const StringView &key, Input first, Input last) { + range_check("RPUSH", first, last); + + auto reply = command(cmd::rpush_range, key, first, last); + + return reply::parse(*reply); +} + +// HASH commands. + +template +inline long long Redis::hdel(const StringView &key, Input first, Input last) { + range_check("HDEL", first, last); + + auto reply = command(cmd::hdel_range, key, first, last); + + return reply::parse(*reply); +} + +template +inline void Redis::hgetall(const StringView &key, Output output) { + auto reply = command(cmd::hgetall, key); + + reply::to_array(*reply, output); +} + +template +inline void Redis::hkeys(const StringView &key, Output output) { + auto reply = command(cmd::hkeys, key); + + reply::to_array(*reply, output); +} + +template +inline void Redis::hmget(const StringView &key, Input first, Input last, Output output) { + range_check("HMGET", first, last); + + auto reply = command(cmd::hmget, key, first, last); + + reply::to_array(*reply, output); +} + +template +inline void Redis::hmset(const StringView &key, Input first, Input last) { + range_check("HMSET", first, last); + + auto reply = command(cmd::hmset, key, first, last); + + reply::parse(*reply); +} + +template +long long Redis::hscan(const StringView &key, + long long cursor, + const StringView &pattern, + long long count, + Output output) { + auto reply = command(cmd::hscan, key, cursor, pattern, count); + + return reply::parse_scan_reply(*reply, output); +} + +template +inline long long Redis::hscan(const StringView &key, + long long cursor, + const StringView &pattern, + Output output) { + return hscan(key, cursor, pattern, 10, output); +} + +template +inline long long Redis::hscan(const StringView &key, + long long cursor, + long long count, + Output output) { + return hscan(key, cursor, "*", count, output); +} + +template +inline long long Redis::hscan(const StringView &key, + long long cursor, + Output output) { + return hscan(key, cursor, "*", 10, output); +} + +template +auto Redis::hset(const StringView &key, Input first, Input last) + -> typename std::enable_if::value, + long long>::type { + range_check("HSET", first, last); + + auto reply = command(cmd::hset_range, key, first, last); + + return reply::parse(*reply); +} + +template +inline void Redis::hvals(const StringView &key, Output output) { + auto reply = command(cmd::hvals, key); + + reply::to_array(*reply, output); +} + +// SET commands. + +template +long long Redis::sadd(const StringView &key, Input first, Input last) { + range_check("SADD", first, last); + + auto reply = command(cmd::sadd_range, key, first, last); + + return reply::parse(*reply); +} + +template +void Redis::sdiff(Input first, Input last, Output output) { + range_check("SDIFF", first, last); + + auto reply = command(cmd::sdiff, first, last); + + reply::to_array(*reply, output); +} + +template +long long Redis::sdiffstore(const StringView &destination, + Input first, + Input last) { + range_check("SDIFFSTORE", first, last); + + auto reply = command(cmd::sdiffstore_range, destination, first, last); + + return reply::parse(*reply); +} + +template +void Redis::sinter(Input first, Input last, Output output) { + range_check("SINTER", first, last); + + auto reply = command(cmd::sinter, first, last); + + reply::to_array(*reply, output); +} + +template +long long Redis::sinterstore(const StringView &destination, + Input first, + Input last) { + range_check("SINTERSTORE", first, last); + + auto reply = command(cmd::sinterstore_range, destination, first, last); + + return reply::parse(*reply); +} + +template +void Redis::smembers(const StringView &key, Output output) { + auto reply = command(cmd::smembers, key); + + reply::to_array(*reply, output); +} + +template +void Redis::spop(const StringView &key, long long count, Output output) { + auto reply = command(cmd::spop_range, key, count); + + reply::to_array(*reply, output); +} + +template +void Redis::srandmember(const StringView &key, long long count, Output output) { + auto reply = command(cmd::srandmember_range, key, count); + + reply::to_array(*reply, output); +} + +template +long long Redis::srem(const StringView &key, Input first, Input last) { + range_check("SREM", first, last); + + auto reply = command(cmd::srem_range, key, first, last); + + return reply::parse(*reply); +} + +template +long long Redis::sscan(const StringView &key, + long long cursor, + const StringView &pattern, + long long count, + Output output) { + auto reply = command(cmd::sscan, key, cursor, pattern, count); + + return reply::parse_scan_reply(*reply, output); +} + +template +inline long long Redis::sscan(const StringView &key, + long long cursor, + const StringView &pattern, + Output output) { + return sscan(key, cursor, pattern, 10, output); +} + +template +inline long long Redis::sscan(const StringView &key, + long long cursor, + long long count, + Output output) { + return sscan(key, cursor, "*", count, output); +} + +template +inline long long Redis::sscan(const StringView &key, + long long cursor, + Output output) { + return sscan(key, cursor, "*", 10, output); +} + +template +void Redis::sunion(Input first, Input last, Output output) { + range_check("SUNION", first, last); + + auto reply = command(cmd::sunion, first, last); + + reply::to_array(*reply, output); +} + +template +long long Redis::sunionstore(const StringView &destination, Input first, Input last) { + range_check("SUNIONSTORE", first, last); + + auto reply = command(cmd::sunionstore_range, destination, first, last); + + return reply::parse(*reply); +} + +// SORTED SET commands. + +inline auto Redis::bzpopmax(const StringView &key, const std::chrono::seconds &timeout) + -> Optional> { + return bzpopmax(key, timeout.count()); +} + +template +auto Redis::bzpopmax(Input first, Input last, long long timeout) + -> Optional> { + auto reply = command(cmd::bzpopmax_range, first, last, timeout); + + return reply::parse>>(*reply); +} + +template +inline auto Redis::bzpopmax(Input first, + Input last, + const std::chrono::seconds &timeout) + -> Optional> { + return bzpopmax(first, last, timeout.count()); +} + +inline auto Redis::bzpopmin(const StringView &key, const std::chrono::seconds &timeout) + -> Optional> { + return bzpopmin(key, timeout.count()); +} + +template +auto Redis::bzpopmin(Input first, Input last, long long timeout) + -> Optional> { + auto reply = command(cmd::bzpopmin_range, first, last, timeout); + + return reply::parse>>(*reply); +} + +template +inline auto Redis::bzpopmin(Input first, + Input last, + const std::chrono::seconds &timeout) + -> Optional> { + return bzpopmin(first, last, timeout.count()); +} + +template +long long Redis::zadd(const StringView &key, + Input first, + Input last, + UpdateType type, + bool changed) { + range_check("ZADD", first, last); + + auto reply = command(cmd::zadd_range, key, first, last, type, changed); + + return reply::parse(*reply); +} + +template +long long Redis::zcount(const StringView &key, const Interval &interval) { + auto reply = command(cmd::zcount, key, interval); + + return reply::parse(*reply); +} + +template +long long Redis::zinterstore(const StringView &destination, + Input first, + Input last, + Aggregation type) { + range_check("ZINTERSTORE", first, last); + + auto reply = command(cmd::zinterstore_range, + destination, + first, + last, + type); + + return reply::parse(*reply); +} + +template +long long Redis::zlexcount(const StringView &key, const Interval &interval) { + auto reply = command(cmd::zlexcount, key, interval); + + return reply::parse(*reply); +} + +template +void Redis::zpopmax(const StringView &key, long long count, Output output) { + auto reply = command(cmd::zpopmax, key, count); + + reply::to_array(*reply, output); +} + +template +void Redis::zpopmin(const StringView &key, long long count, Output output) { + auto reply = command(cmd::zpopmin, key, count); + + reply::to_array(*reply, output); +} + +template +void Redis::zrange(const StringView &key, long long start, long long stop, Output output) { + auto reply = _score_command(cmd::zrange, key, start, stop); + + reply::to_array(*reply, output); +} + +template +void Redis::zrangebylex(const StringView &key, const Interval &interval, Output output) { + zrangebylex(key, interval, {}, output); +} + +template +void Redis::zrangebylex(const StringView &key, + const Interval &interval, + const LimitOptions &opts, + Output output) { + auto reply = command(cmd::zrangebylex, key, interval, opts); + + reply::to_array(*reply, output); +} + +template +void Redis::zrangebyscore(const StringView &key, + const Interval &interval, + Output output) { + zrangebyscore(key, interval, {}, output); +} + +template +void Redis::zrangebyscore(const StringView &key, + const Interval &interval, + const LimitOptions &opts, + Output output) { + auto reply = _score_command(cmd::zrangebyscore, + key, + interval, + opts); + + reply::to_array(*reply, output); +} + +template +long long Redis::zrem(const StringView &key, Input first, Input last) { + range_check("ZREM", first, last); + + auto reply = command(cmd::zrem_range, key, first, last); + + return reply::parse(*reply); +} + +template +long long Redis::zremrangebylex(const StringView &key, const Interval &interval) { + auto reply = command(cmd::zremrangebylex, key, interval); + + return reply::parse(*reply); +} + +template +long long Redis::zremrangebyscore(const StringView &key, const Interval &interval) { + auto reply = command(cmd::zremrangebyscore, key, interval); + + return reply::parse(*reply); +} + +template +void Redis::zrevrange(const StringView &key, long long start, long long stop, Output output) { + auto reply = _score_command(cmd::zrevrange, key, start, stop); + + reply::to_array(*reply, output); +} + +template +inline void Redis::zrevrangebylex(const StringView &key, + const Interval &interval, + Output output) { + zrevrangebylex(key, interval, {}, output); +} + +template +void Redis::zrevrangebylex(const StringView &key, + const Interval &interval, + const LimitOptions &opts, + Output output) { + auto reply = command(cmd::zrevrangebylex, key, interval, opts); + + reply::to_array(*reply, output); +} + +template +void Redis::zrevrangebyscore(const StringView &key, const Interval &interval, Output output) { + zrevrangebyscore(key, interval, {}, output); +} + +template +void Redis::zrevrangebyscore(const StringView &key, + const Interval &interval, + const LimitOptions &opts, + Output output) { + auto reply = _score_command(cmd::zrevrangebyscore, key, interval, opts); + + reply::to_array(*reply, output); +} + +template +long long Redis::zscan(const StringView &key, + long long cursor, + const StringView &pattern, + long long count, + Output output) { + auto reply = command(cmd::zscan, key, cursor, pattern, count); + + return reply::parse_scan_reply(*reply, output); +} + +template +inline long long Redis::zscan(const StringView &key, + long long cursor, + const StringView &pattern, + Output output) { + return zscan(key, cursor, pattern, 10, output); +} + +template +inline long long Redis::zscan(const StringView &key, + long long cursor, + long long count, + Output output) { + return zscan(key, cursor, "*", count, output); +} + +template +inline long long Redis::zscan(const StringView &key, + long long cursor, + Output output) { + return zscan(key, cursor, "*", 10, output); +} + +template +long long Redis::zunionstore(const StringView &destination, + Input first, + Input last, + Aggregation type) { + range_check("ZUNIONSTORE", first, last); + + auto reply = command(cmd::zunionstore_range, + destination, + first, + last, + type); + + return reply::parse(*reply); +} + +// HYPERLOGLOG commands. + +template +bool Redis::pfadd(const StringView &key, Input first, Input last) { + range_check("PFADD", first, last); + + auto reply = command(cmd::pfadd_range, key, first, last); + + return reply::parse(*reply); +} + +template +long long Redis::pfcount(Input first, Input last) { + range_check("PFCOUNT", first, last); + + auto reply = command(cmd::pfcount_range, first, last); + + return reply::parse(*reply); +} + +template +void Redis::pfmerge(const StringView &destination, + Input first, + Input last) { + range_check("PFMERGE", first, last); + + auto reply = command(cmd::pfmerge_range, destination, first, last); + + reply::parse(*reply); +} + +// GEO commands. + +template +inline long long Redis::geoadd(const StringView &key, + Input first, + Input last) { + range_check("GEOADD", first, last); + + auto reply = command(cmd::geoadd_range, key, first, last); + + return reply::parse(*reply); +} + +template +void Redis::geohash(const StringView &key, Input first, Input last, Output output) { + range_check("GEOHASH", first, last); + + auto reply = command(cmd::geohash_range, key, first, last); + + reply::to_array(*reply, output); +} + +template +void Redis::geopos(const StringView &key, Input first, Input last, Output output) { + range_check("GEOPOS", first, last); + + auto reply = command(cmd::geopos_range, key, first, last); + + reply::to_array(*reply, output); +} + +template +void Redis::georadius(const StringView &key, + const std::pair &loc, + double radius, + GeoUnit unit, + long long count, + bool asc, + Output output) { + auto reply = command(cmd::georadius, + key, + loc, + radius, + unit, + count, + asc, + WithCoord::type>::value, + WithDist::type>::value, + WithHash::type>::value); + + reply::to_array(*reply, output); +} + +template +void Redis::georadiusbymember(const StringView &key, + const StringView &member, + double radius, + GeoUnit unit, + long long count, + bool asc, + Output output) { + auto reply = command(cmd::georadiusbymember, + key, + member, + radius, + unit, + count, + asc, + WithCoord::type>::value, + WithDist::type>::value, + WithHash::type>::value); + + reply::to_array(*reply, output); +} + +// SCRIPTING commands. + +template +Result Redis::eval(const StringView &script, + Keys keys_first, + Keys keys_last, + Args args_first, + Args args_last) { + auto reply = command(cmd::eval, script, keys_first, keys_last, args_first, args_last); + + return reply::parse(*reply); +} + +template +Result Redis::eval(const StringView &script, + std::initializer_list keys, + std::initializer_list args) { + return eval(script, keys.begin(), keys.end(), args.begin(), args.end()); +} + +template +void Redis::eval(const StringView &script, + Keys keys_first, + Keys keys_last, + Args args_first, + Args args_last, + Output output) { + auto reply = command(cmd::eval, + script, + keys_first, keys_last, + args_first, args_last); + + reply::to_array(*reply, output); +} + +template +void Redis::eval(const StringView &script, + std::initializer_list keys, + std::initializer_list args, + Output output) { + eval(script, keys.begin(), keys.end(), args.begin(), args.end(), output); +} + +template +Result Redis::evalsha(const StringView &script, + Keys keys_first, + Keys keys_last, + Args args_first, + Args args_last) { + auto reply = command(cmd::evalsha, script, + keys_first, keys_last, args_first, args_last); + + return reply::parse(*reply); +} + +template +Result Redis::evalsha(const StringView &script, + std::initializer_list keys, + std::initializer_list args) { + return evalsha(script, keys.begin(), keys.end(), args.begin(), args.end()); +} + +template +void Redis::evalsha(const StringView &script, + Keys keys_first, + Keys keys_last, + Args args_first, + Args args_last, + Output output) { + auto reply = command(cmd::evalsha, + script, + keys_first, keys_last, + args_first, args_last); + + reply::to_array(*reply, output); +} + +template +void Redis::evalsha(const StringView &script, + std::initializer_list keys, + std::initializer_list args, + Output output) { + evalsha(script, keys.begin(), keys.end(), args.begin(), args.end(), output); +} + +template +void Redis::script_exists(Input first, Input last, Output output) { + range_check("SCRIPT EXISTS", first, last); + + auto reply = command(cmd::script_exists_range, first, last); + + reply::to_array(*reply, output); +} + +// Transaction commands. + +template +void Redis::watch(Input first, Input last) { + auto reply = command(cmd::watch_range, first, last); + + reply::parse(*reply); +} + +// Stream commands. + +template +long long Redis::xack(const StringView &key, const StringView &group, Input first, Input last) { + auto reply = command(cmd::xack_range, key, group, first, last); + + return reply::parse(*reply); +} + +template +std::string Redis::xadd(const StringView &key, const StringView &id, Input first, Input last) { + auto reply = command(cmd::xadd_range, key, id, first, last); + + return reply::parse(*reply); +} + +template +std::string Redis::xadd(const StringView &key, + const StringView &id, + Input first, + Input last, + long long count, + bool approx) { + auto reply = command(cmd::xadd_maxlen_range, key, id, first, last, count, approx); + + return reply::parse(*reply); +} + +template +void Redis::xclaim(const StringView &key, + const StringView &group, + const StringView &consumer, + const std::chrono::milliseconds &min_idle_time, + const StringView &id, + Output output) { + auto reply = command(cmd::xclaim, key, group, consumer, min_idle_time.count(), id); + + reply::to_array(*reply, output); +} + +template +void Redis::xclaim(const StringView &key, + const StringView &group, + const StringView &consumer, + const std::chrono::milliseconds &min_idle_time, + Input first, + Input last, + Output output) { + auto reply = command(cmd::xclaim_range, + key, + group, + consumer, + min_idle_time.count(), + first, + last); + + reply::to_array(*reply, output); +} + +template +long long Redis::xdel(const StringView &key, Input first, Input last) { + auto reply = command(cmd::xdel_range, key, first, last); + + return reply::parse(*reply); +} + +template +auto Redis::xpending(const StringView &key, const StringView &group, Output output) + -> std::tuple { + auto reply = command(cmd::xpending, key, group); + + return reply::parse_xpending_reply(*reply, output); +} + +template +void Redis::xpending(const StringView &key, + const StringView &group, + const StringView &start, + const StringView &end, + long long count, + Output output) { + auto reply = command(cmd::xpending_detail, key, group, start, end, count); + + reply::to_array(*reply, output); +} + +template +void Redis::xpending(const StringView &key, + const StringView &group, + const StringView &start, + const StringView &end, + long long count, + const StringView &consumer, + Output output) { + auto reply = command(cmd::xpending_per_consumer, key, group, start, end, count, consumer); + + reply::to_array(*reply, output); +} + +template +void Redis::xrange(const StringView &key, + const StringView &start, + const StringView &end, + Output output) { + auto reply = command(cmd::xrange, key, start, end); + + reply::to_array(*reply, output); +} + +template +void Redis::xrange(const StringView &key, + const StringView &start, + const StringView &end, + long long count, + Output output) { + auto reply = command(cmd::xrange_count, key, start, end, count); + + reply::to_array(*reply, output); +} + +template +void Redis::xread(const StringView &key, + const StringView &id, + long long count, + Output output) { + auto reply = command(cmd::xread, key, id, count); + + if (!reply::is_nil(*reply)) { + reply::to_array(*reply, output); + } +} + +template +auto Redis::xread(Input first, Input last, long long count, Output output) + -> typename std::enable_if::value>::type { + range_check("XREAD", first, last); + + auto reply = command(cmd::xread_range, first, last, count); + + if (!reply::is_nil(*reply)) { + reply::to_array(*reply, output); + } +} + +template +void Redis::xread(const StringView &key, + const StringView &id, + const std::chrono::milliseconds &timeout, + long long count, + Output output) { + auto reply = command(cmd::xread_block, key, id, timeout.count(), count); + + if (!reply::is_nil(*reply)) { + reply::to_array(*reply, output); + } +} + +template +auto Redis::xread(Input first, + Input last, + const std::chrono::milliseconds &timeout, + long long count, + Output output) + -> typename std::enable_if::value>::type { + range_check("XREAD", first, last); + + auto reply = command(cmd::xread_block_range, first, last, timeout.count(), count); + + if (!reply::is_nil(*reply)) { + reply::to_array(*reply, output); + } +} + +template +void Redis::xreadgroup(const StringView &group, + const StringView &consumer, + const StringView &key, + const StringView &id, + long long count, + bool noack, + Output output) { + auto reply = command(cmd::xreadgroup, group, consumer, key, id, count, noack); + + if (!reply::is_nil(*reply)) { + reply::to_array(*reply, output); + } +} + +template +auto Redis::xreadgroup(const StringView &group, + const StringView &consumer, + Input first, + Input last, + long long count, + bool noack, + Output output) + -> typename std::enable_if::value>::type { + range_check("XREADGROUP", first, last); + + auto reply = command(cmd::xreadgroup_range, group, consumer, first, last, count, noack); + + if (!reply::is_nil(*reply)) { + reply::to_array(*reply, output); + } +} + +template +void Redis::xreadgroup(const StringView &group, + const StringView &consumer, + const StringView &key, + const StringView &id, + const std::chrono::milliseconds &timeout, + long long count, + bool noack, + Output output) { + auto reply = command(cmd::xreadgroup_block, + group, + consumer, + key, + id, + timeout.count(), + count, + noack); + + if (!reply::is_nil(*reply)) { + reply::to_array(*reply, output); + } +} + +template +auto Redis::xreadgroup(const StringView &group, + const StringView &consumer, + Input first, + Input last, + const std::chrono::milliseconds &timeout, + long long count, + bool noack, + Output output) + -> typename std::enable_if::value>::type { + range_check("XREADGROUP", first, last); + + auto reply = command(cmd::xreadgroup_block_range, + group, + consumer, + first, + last, + timeout.count(), + count, + noack); + + if (!reply::is_nil(*reply)) { + reply::to_array(*reply, output); + } +} + +template +void Redis::xrevrange(const StringView &key, + const StringView &end, + const StringView &start, + Output output) { + auto reply = command(cmd::xrevrange, key, end, start); + + reply::to_array(*reply, output); +} + +template +void Redis::xrevrange(const StringView &key, + const StringView &end, + const StringView &start, + long long count, + Output output) { + auto reply = command(cmd::xrevrange_count, key, end, start, count); + + reply::to_array(*reply, output); +} + +template +ReplyUPtr Redis::_command(Connection &connection, Cmd cmd, Args &&...args) { + assert(!connection.broken()); + + cmd(connection, std::forward(args)...); + + auto reply = connection.recv(); + + return reply; +} + +template +inline ReplyUPtr Redis::_score_command(std::true_type, Cmd cmd, Args &&... args) { + return command(cmd, std::forward(args)..., true); +} + +template +inline ReplyUPtr Redis::_score_command(std::false_type, Cmd cmd, Args &&... args) { + return command(cmd, std::forward(args)..., false); +} + +template +inline ReplyUPtr Redis::_score_command(Cmd cmd, Args &&... args) { + return _score_command(typename IsKvPairIter::type(), + cmd, + std::forward(args)...); +} + +} + +} + +#endif // end SEWENEW_REDISPLUSPLUS_REDIS_HPP diff --git a/ext/redis-plus-plus-1.3.3/install/ubuntu22.04/arm64/include/sw/redis++/redis_cluster.h b/ext/redis-plus-plus-1.3.3/install/ubuntu22.04/arm64/include/sw/redis++/redis_cluster.h new file mode 100644 index 000000000..63c6131c1 --- /dev/null +++ b/ext/redis-plus-plus-1.3.3/install/ubuntu22.04/arm64/include/sw/redis++/redis_cluster.h @@ -0,0 +1,1439 @@ +/************************************************************************** + Copyright (c) 2017 sewenew + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + *************************************************************************/ + +#ifndef SEWENEW_REDISPLUSPLUS_REDIS_CLUSTER_H +#define SEWENEW_REDISPLUSPLUS_REDIS_CLUSTER_H + +#include +#include +#include +#include +#include "shards_pool.h" +#include "reply.h" +#include "command_options.h" +#include "utils.h" +#include "subscriber.h" +#include "pipeline.h" +#include "transaction.h" +#include "redis.h" +#include "connection.h" + +namespace sw { + +namespace redis { + +template +class QueuedRedis; + +using Transaction = QueuedRedis; + +using Pipeline = QueuedRedis; + +class RedisCluster { +public: + RedisCluster(const ConnectionOptions &connection_opts, + const ConnectionPoolOptions &pool_opts = {}, + Role role = Role::MASTER) : _pool(pool_opts, connection_opts, role) {} + + // Construct RedisCluster with URI: + // "tcp://127.0.0.1" or "tcp://127.0.0.1:6379" + // Only need to specify one URI. + explicit RedisCluster(const std::string &uri); + + RedisCluster(const RedisCluster &) = delete; + RedisCluster& operator=(const RedisCluster &) = delete; + + RedisCluster(RedisCluster &&) = default; + RedisCluster& operator=(RedisCluster &&) = default; + + Redis redis(const StringView &hash_tag, bool new_connection = true); + + Pipeline pipeline(const StringView &hash_tag, bool new_connection = true); + + Transaction transaction(const StringView &hash_tag, bool piped = false, bool new_connection = true); + + Subscriber subscriber(); + + template + auto command(Cmd cmd, Key &&key, Args &&...args) + -> typename std::enable_if::value, ReplyUPtr>::type; + + template + auto command(const StringView &cmd_name, Key &&key, Args &&...args) + -> typename std::enable_if<(std::is_convertible::value + || std::is_arithmetic::type>::value) + && !IsIter::type>::value, ReplyUPtr>::type; + + template + auto command(const StringView &cmd_name, Key &&key, Args &&...args) + -> typename std::enable_if<(std::is_convertible::value + || std::is_arithmetic::type>::value) + && IsIter::type>::value, void>::type; + + template + auto command(const StringView &cmd_name, Key &&key, Args &&...args) + -> typename std::enable_if::value + || std::is_arithmetic::type>::value, Result>::type; + + template + auto command(Input first, Input last) + -> typename std::enable_if::value, ReplyUPtr>::type; + + template + auto command(Input first, Input last) + -> typename std::enable_if::value, Result>::type; + + template + auto command(Input first, Input last, Output output) + -> typename std::enable_if::value, void>::type; + + // KEY commands. + + long long del(const StringView &key); + + template + long long del(Input first, Input last); + + template + long long del(std::initializer_list il) { + return del(il.begin(), il.end()); + } + + OptionalString dump(const StringView &key); + + long long exists(const StringView &key); + + template + long long exists(Input first, Input last); + + template + long long exists(std::initializer_list il) { + return exists(il.begin(), il.end()); + } + + bool expire(const StringView &key, long long timeout); + + bool expire(const StringView &key, const std::chrono::seconds &timeout); + + bool expireat(const StringView &key, long long timestamp); + + bool expireat(const StringView &key, + const std::chrono::time_point &tp); + + bool persist(const StringView &key); + + bool pexpire(const StringView &key, long long timeout); + + bool pexpire(const StringView &key, const std::chrono::milliseconds &timeout); + + bool pexpireat(const StringView &key, long long timestamp); + + bool pexpireat(const StringView &key, + const std::chrono::time_point &tp); + + long long pttl(const StringView &key); + + void rename(const StringView &key, const StringView &newkey); + + bool renamenx(const StringView &key, const StringView &newkey); + + void restore(const StringView &key, + const StringView &val, + long long ttl, + bool replace = false); + + void restore(const StringView &key, + const StringView &val, + const std::chrono::milliseconds &ttl = std::chrono::milliseconds{0}, + bool replace = false); + + // TODO: sort + + long long touch(const StringView &key); + + template + long long touch(Input first, Input last); + + template + long long touch(std::initializer_list il) { + return touch(il.begin(), il.end()); + } + + long long ttl(const StringView &key); + + std::string type(const StringView &key); + + long long unlink(const StringView &key); + + template + long long unlink(Input first, Input last); + + template + long long unlink(std::initializer_list il) { + return unlink(il.begin(), il.end()); + } + + // STRING commands. + + long long append(const StringView &key, const StringView &str); + + long long bitcount(const StringView &key, long long start = 0, long long end = -1); + + long long bitop(BitOp op, const StringView &destination, const StringView &key); + + template + long long bitop(BitOp op, const StringView &destination, Input first, Input last); + + template + long long bitop(BitOp op, const StringView &destination, std::initializer_list il) { + return bitop(op, destination, il.begin(), il.end()); + } + + long long bitpos(const StringView &key, + long long bit, + long long start = 0, + long long end = -1); + + long long decr(const StringView &key); + + long long decrby(const StringView &key, long long decrement); + + OptionalString get(const StringView &key); + + long long getbit(const StringView &key, long long offset); + + std::string getrange(const StringView &key, long long start, long long end); + + OptionalString getset(const StringView &key, const StringView &val); + + long long incr(const StringView &key); + + long long incrby(const StringView &key, long long increment); + + double incrbyfloat(const StringView &key, double increment); + + template + void mget(Input first, Input last, Output output); + + template + void mget(std::initializer_list il, Output output) { + mget(il.begin(), il.end(), output); + } + + template + void mset(Input first, Input last); + + template + void mset(std::initializer_list il) { + mset(il.begin(), il.end()); + } + + template + bool msetnx(Input first, Input last); + + template + bool msetnx(std::initializer_list il) { + return msetnx(il.begin(), il.end()); + } + + void psetex(const StringView &key, + long long ttl, + const StringView &val); + + void psetex(const StringView &key, + const std::chrono::milliseconds &ttl, + const StringView &val); + + bool set(const StringView &key, + const StringView &val, + const std::chrono::milliseconds &ttl = std::chrono::milliseconds(0), + UpdateType type = UpdateType::ALWAYS); + + void setex(const StringView &key, + long long ttl, + const StringView &val); + + void setex(const StringView &key, + const std::chrono::seconds &ttl, + const StringView &val); + + bool setnx(const StringView &key, const StringView &val); + + long long setrange(const StringView &key, long long offset, const StringView &val); + + long long strlen(const StringView &key); + + // LIST commands. + + OptionalStringPair blpop(const StringView &key, long long timeout); + + OptionalStringPair blpop(const StringView &key, + const std::chrono::seconds &timeout = std::chrono::seconds{0}); + + template + OptionalStringPair blpop(Input first, Input last, long long timeout); + + template + OptionalStringPair blpop(std::initializer_list il, long long timeout) { + return blpop(il.begin(), il.end(), timeout); + } + + template + OptionalStringPair blpop(Input first, + Input last, + const std::chrono::seconds &timeout = std::chrono::seconds{0}); + + template + OptionalStringPair blpop(std::initializer_list il, + const std::chrono::seconds &timeout = std::chrono::seconds{0}) { + return blpop(il.begin(), il.end(), timeout); + } + + OptionalStringPair brpop(const StringView &key, long long timeout); + + OptionalStringPair brpop(const StringView &key, + const std::chrono::seconds &timeout = std::chrono::seconds{0}); + + template + OptionalStringPair brpop(Input first, Input last, long long timeout); + + template + OptionalStringPair brpop(std::initializer_list il, long long timeout) { + return brpop(il.begin(), il.end(), timeout); + } + + template + OptionalStringPair brpop(Input first, + Input last, + const std::chrono::seconds &timeout = std::chrono::seconds{0}); + + template + OptionalStringPair brpop(std::initializer_list il, + const std::chrono::seconds &timeout = std::chrono::seconds{0}) { + return brpop(il.begin(), il.end(), timeout); + } + + OptionalString brpoplpush(const StringView &source, + const StringView &destination, + long long timeout); + + OptionalString brpoplpush(const StringView &source, + const StringView &destination, + const std::chrono::seconds &timeout = std::chrono::seconds{0}); + + OptionalString lindex(const StringView &key, long long index); + + long long linsert(const StringView &key, + InsertPosition position, + const StringView &pivot, + const StringView &val); + + long long llen(const StringView &key); + + OptionalString lpop(const StringView &key); + + long long lpush(const StringView &key, const StringView &val); + + template + long long lpush(const StringView &key, Input first, Input last); + + template + long long lpush(const StringView &key, std::initializer_list il) { + return lpush(key, il.begin(), il.end()); + } + + long long lpushx(const StringView &key, const StringView &val); + + template + void lrange(const StringView &key, long long start, long long stop, Output output); + + long long lrem(const StringView &key, long long count, const StringView &val); + + void lset(const StringView &key, long long index, const StringView &val); + + void ltrim(const StringView &key, long long start, long long stop); + + OptionalString rpop(const StringView &key); + + OptionalString rpoplpush(const StringView &source, const StringView &destination); + + long long rpush(const StringView &key, const StringView &val); + + template + long long rpush(const StringView &key, Input first, Input last); + + template + long long rpush(const StringView &key, std::initializer_list il) { + return rpush(key, il.begin(), il.end()); + } + + long long rpushx(const StringView &key, const StringView &val); + + // HASH commands. + + long long hdel(const StringView &key, const StringView &field); + + template + long long hdel(const StringView &key, Input first, Input last); + + template + long long hdel(const StringView &key, std::initializer_list il) { + return hdel(key, il.begin(), il.end()); + } + + bool hexists(const StringView &key, const StringView &field); + + OptionalString hget(const StringView &key, const StringView &field); + + template + void hgetall(const StringView &key, Output output); + + long long hincrby(const StringView &key, const StringView &field, long long increment); + + double hincrbyfloat(const StringView &key, const StringView &field, double increment); + + template + void hkeys(const StringView &key, Output output); + + long long hlen(const StringView &key); + + template + void hmget(const StringView &key, Input first, Input last, Output output); + + template + void hmget(const StringView &key, std::initializer_list il, Output output) { + hmget(key, il.begin(), il.end(), output); + } + + template + void hmset(const StringView &key, Input first, Input last); + + template + void hmset(const StringView &key, std::initializer_list il) { + hmset(key, il.begin(), il.end()); + } + + template + long long hscan(const StringView &key, + long long cursor, + const StringView &pattern, + long long count, + Output output); + + template + long long hscan(const StringView &key, + long long cursor, + const StringView &pattern, + Output output); + + template + long long hscan(const StringView &key, + long long cursor, + long long count, + Output output); + + template + long long hscan(const StringView &key, + long long cursor, + Output output); + + bool hset(const StringView &key, const StringView &field, const StringView &val); + + bool hset(const StringView &key, const std::pair &item); + + template + auto hset(const StringView &key, Input first, Input last) + -> typename std::enable_if::value, long long>::type; + + template + long long hset(const StringView &key, std::initializer_list il) { + return hset(key, il.begin(), il.end()); + } + + bool hsetnx(const StringView &key, const StringView &field, const StringView &val); + + bool hsetnx(const StringView &key, const std::pair &item); + + long long hstrlen(const StringView &key, const StringView &field); + + template + void hvals(const StringView &key, Output output); + + // SET commands. + + long long sadd(const StringView &key, const StringView &member); + + template + long long sadd(const StringView &key, Input first, Input last); + + template + long long sadd(const StringView &key, std::initializer_list il) { + return sadd(key, il.begin(), il.end()); + } + + long long scard(const StringView &key); + + template + void sdiff(Input first, Input last, Output output); + + template + void sdiff(std::initializer_list il, Output output) { + sdiff(il.begin(), il.end(), output); + } + + long long sdiffstore(const StringView &destination, const StringView &key); + + template + long long sdiffstore(const StringView &destination, + Input first, + Input last); + + template + long long sdiffstore(const StringView &destination, + std::initializer_list il) { + return sdiffstore(destination, il.begin(), il.end()); + } + + template + void sinter(Input first, Input last, Output output); + + template + void sinter(std::initializer_list il, Output output) { + sinter(il.begin(), il.end(), output); + } + + long long sinterstore(const StringView &destination, const StringView &key); + + template + long long sinterstore(const StringView &destination, + Input first, + Input last); + + template + long long sinterstore(const StringView &destination, + std::initializer_list il) { + return sinterstore(destination, il.begin(), il.end()); + } + + bool sismember(const StringView &key, const StringView &member); + + template + void smembers(const StringView &key, Output output); + + bool smove(const StringView &source, + const StringView &destination, + const StringView &member); + + OptionalString spop(const StringView &key); + + template + void spop(const StringView &key, long long count, Output output); + + OptionalString srandmember(const StringView &key); + + template + void srandmember(const StringView &key, long long count, Output output); + + long long srem(const StringView &key, const StringView &member); + + template + long long srem(const StringView &key, Input first, Input last); + + template + long long srem(const StringView &key, std::initializer_list il) { + return srem(key, il.begin(), il.end()); + } + + template + long long sscan(const StringView &key, + long long cursor, + const StringView &pattern, + long long count, + Output output); + + template + long long sscan(const StringView &key, + long long cursor, + const StringView &pattern, + Output output); + + template + long long sscan(const StringView &key, + long long cursor, + long long count, + Output output); + + template + long long sscan(const StringView &key, + long long cursor, + Output output); + + template + void sunion(Input first, Input last, Output output); + + template + void sunion(std::initializer_list il, Output output) { + sunion(il.begin(), il.end(), output); + } + + long long sunionstore(const StringView &destination, const StringView &key); + + template + long long sunionstore(const StringView &destination, Input first, Input last); + + template + long long sunionstore(const StringView &destination, std::initializer_list il) { + return sunionstore(destination, il.begin(), il.end()); + } + + // SORTED SET commands. + + auto bzpopmax(const StringView &key, long long timeout) + -> Optional>; + + auto bzpopmax(const StringView &key, + const std::chrono::seconds &timeout = std::chrono::seconds{0}) + -> Optional>; + + template + auto bzpopmax(Input first, Input last, long long timeout) + -> Optional>; + + template + auto bzpopmax(Input first, + Input last, + const std::chrono::seconds &timeout = std::chrono::seconds{0}) + -> Optional>; + + template + auto bzpopmax(std::initializer_list il, long long timeout) + -> Optional> { + return bzpopmax(il.begin(), il.end(), timeout); + } + + template + auto bzpopmax(std::initializer_list il, + const std::chrono::seconds &timeout = std::chrono::seconds{0}) + -> Optional> { + return bzpopmax(il.begin(), il.end(), timeout); + } + + auto bzpopmin(const StringView &key, long long timeout) + -> Optional>; + + auto bzpopmin(const StringView &key, + const std::chrono::seconds &timeout = std::chrono::seconds{0}) + -> Optional>; + + template + auto bzpopmin(Input first, Input last, long long timeout) + -> Optional>; + + template + auto bzpopmin(Input first, + Input last, + const std::chrono::seconds &timeout = std::chrono::seconds{0}) + -> Optional>; + + template + auto bzpopmin(std::initializer_list il, long long timeout) + -> Optional> { + return bzpopmin(il.begin(), il.end(), timeout); + } + + template + auto bzpopmin(std::initializer_list il, + const std::chrono::seconds &timeout = std::chrono::seconds{0}) + -> Optional> { + return bzpopmin(il.begin(), il.end(), timeout); + } + + // We don't support the INCR option, since you can always use ZINCRBY instead. + long long zadd(const StringView &key, + const StringView &member, + double score, + UpdateType type = UpdateType::ALWAYS, + bool changed = false); + + template + long long zadd(const StringView &key, + Input first, + Input last, + UpdateType type = UpdateType::ALWAYS, + bool changed = false); + + template + long long zadd(const StringView &key, + std::initializer_list il, + UpdateType type = UpdateType::ALWAYS, + bool changed = false) { + return zadd(key, il.begin(), il.end(), type, changed); + } + + long long zcard(const StringView &key); + + template + long long zcount(const StringView &key, const Interval &interval); + + double zincrby(const StringView &key, double increment, const StringView &member); + + long long zinterstore(const StringView &destination, const StringView &key, double weight); + + template + long long zinterstore(const StringView &destination, + Input first, + Input last, + Aggregation type = Aggregation::SUM); + + template + long long zinterstore(const StringView &destination, + std::initializer_list il, + Aggregation type = Aggregation::SUM) { + return zinterstore(destination, il.begin(), il.end(), type); + } + + template + long long zlexcount(const StringView &key, const Interval &interval); + + Optional> zpopmax(const StringView &key); + + template + void zpopmax(const StringView &key, long long count, Output output); + + Optional> zpopmin(const StringView &key); + + template + void zpopmin(const StringView &key, long long count, Output output); + + // If *output* is an iterator of a container of string, + // we send *ZRANGE key start stop* command. + // If it's an iterator of a container of pair, + // we send *ZRANGE key start stop WITHSCORES* command. + // + // The following code sends *ZRANGE* without the *WITHSCORES* option: + // + // vector result; + // redis.zrange("key", 0, -1, back_inserter(result)); + // + // On the other hand, the following code sends command with *WITHSCORES* option: + // + // unordered_map with_score; + // redis.zrange("key", 0, -1, inserter(with_score, with_score.end())); + // + // This also applies to other commands with the *WITHSCORES* option, + // e.g. *ZRANGEBYSCORE*, *ZREVRANGE*, *ZREVRANGEBYSCORE*. + template + void zrange(const StringView &key, long long start, long long stop, Output output); + + template + void zrangebylex(const StringView &key, const Interval &interval, Output output); + + template + void zrangebylex(const StringView &key, + const Interval &interval, + const LimitOptions &opts, + Output output); + + // See *zrange* comment on how to send command with *WITHSCORES* option. + template + void zrangebyscore(const StringView &key, const Interval &interval, Output output); + + // See *zrange* comment on how to send command with *WITHSCORES* option. + template + void zrangebyscore(const StringView &key, + const Interval &interval, + const LimitOptions &opts, + Output output); + + OptionalLongLong zrank(const StringView &key, const StringView &member); + + long long zrem(const StringView &key, const StringView &member); + + template + long long zrem(const StringView &key, Input first, Input last); + + template + long long zrem(const StringView &key, std::initializer_list il) { + return zrem(key, il.begin(), il.end()); + } + + template + long long zremrangebylex(const StringView &key, const Interval &interval); + + long long zremrangebyrank(const StringView &key, long long start, long long stop); + + template + long long zremrangebyscore(const StringView &key, const Interval &interval); + + // See *zrange* comment on how to send command with *WITHSCORES* option. + template + void zrevrange(const StringView &key, long long start, long long stop, Output output); + + template + void zrevrangebylex(const StringView &key, const Interval &interval, Output output); + + template + void zrevrangebylex(const StringView &key, + const Interval &interval, + const LimitOptions &opts, + Output output); + + // See *zrange* comment on how to send command with *WITHSCORES* option. + template + void zrevrangebyscore(const StringView &key, const Interval &interval, Output output); + + // See *zrange* comment on how to send command with *WITHSCORES* option. + template + void zrevrangebyscore(const StringView &key, + const Interval &interval, + const LimitOptions &opts, + Output output); + + OptionalLongLong zrevrank(const StringView &key, const StringView &member); + + template + long long zscan(const StringView &key, + long long cursor, + const StringView &pattern, + long long count, + Output output); + + template + long long zscan(const StringView &key, + long long cursor, + const StringView &pattern, + Output output); + + template + long long zscan(const StringView &key, + long long cursor, + long long count, + Output output); + + template + long long zscan(const StringView &key, + long long cursor, + Output output); + + OptionalDouble zscore(const StringView &key, const StringView &member); + + long long zunionstore(const StringView &destination, const StringView &key, double weight); + + template + long long zunionstore(const StringView &destination, + Input first, + Input last, + Aggregation type = Aggregation::SUM); + + template + long long zunionstore(const StringView &destination, + std::initializer_list il, + Aggregation type = Aggregation::SUM) { + return zunionstore(destination, il.begin(), il.end(), type); + } + + // HYPERLOGLOG commands. + + bool pfadd(const StringView &key, const StringView &element); + + template + bool pfadd(const StringView &key, Input first, Input last); + + template + bool pfadd(const StringView &key, std::initializer_list il) { + return pfadd(key, il.begin(), il.end()); + } + + long long pfcount(const StringView &key); + + template + long long pfcount(Input first, Input last); + + template + long long pfcount(std::initializer_list il) { + return pfcount(il.begin(), il.end()); + } + + void pfmerge(const StringView &destination, const StringView &key); + + template + void pfmerge(const StringView &destination, Input first, Input last); + + template + void pfmerge(const StringView &destination, std::initializer_list il) { + pfmerge(destination, il.begin(), il.end()); + } + + // GEO commands. + + long long geoadd(const StringView &key, + const std::tuple &member); + + template + long long geoadd(const StringView &key, + Input first, + Input last); + + template + long long geoadd(const StringView &key, + std::initializer_list il) { + return geoadd(key, il.begin(), il.end()); + } + + OptionalDouble geodist(const StringView &key, + const StringView &member1, + const StringView &member2, + GeoUnit unit = GeoUnit::M); + + OptionalString geohash(const StringView &key, const StringView &member); + + template + void geohash(const StringView &key, Input first, Input last, Output output); + + template + void geohash(const StringView &key, std::initializer_list il, Output output) { + geohash(key, il.begin(), il.end(), output); + } + + Optional> geopos(const StringView &key, const StringView &member); + + template + void geopos(const StringView &key, Input first, Input last, Output output); + + template + void geopos(const StringView &key, std::initializer_list il, Output output) { + geopos(key, il.begin(), il.end(), output); + } + + // TODO: + // 1. since we have different overloads for georadius and georadius-store, + // we might use the GEORADIUS_RO command in the future. + // 2. there're too many parameters for this method, we might refactor it. + OptionalLongLong georadius(const StringView &key, + const std::pair &loc, + double radius, + GeoUnit unit, + const StringView &destination, + bool store_dist, + long long count); + + // If *output* is an iterator of a container of string, we send *GEORADIUS* command + // without any options and only get the members in the specified geo range. + // If *output* is an iterator of a container of a tuple, the type of the tuple decides + // options we send with the *GEORADIUS* command. If the tuple has an element of type + // double, we send the *WITHDIST* option. If it has an element of type string, we send + // the *WITHHASH* option. If it has an element of type pair, we send + // the *WITHCOORD* option. For example: + // + // The following code only gets the members in range, i.e. without any option. + // + // vector members; + // redis.georadius("key", make_pair(10.1, 10.2), 10, GeoUnit::KM, 10, true, + // back_inserter(members)) + // + // The following code sends the command with *WITHDIST* option. + // + // vector> with_dist; + // redis.georadius("key", make_pair(10.1, 10.2), 10, GeoUnit::KM, 10, true, + // back_inserter(with_dist)) + // + // The following code sends the command with *WITHDIST* and *WITHHASH* options. + // + // vector> with_dist_hash; + // redis.georadius("key", make_pair(10.1, 10.2), 10, GeoUnit::KM, 10, true, + // back_inserter(with_dist_hash)) + // + // The following code sends the command with *WITHDIST*, *WITHCOORD* and *WITHHASH* options. + // + // vector, string>> with_dist_coord_hash; + // redis.georadius("key", make_pair(10.1, 10.2), 10, GeoUnit::KM, 10, true, + // back_inserter(with_dist_coord_hash)) + // + // This also applies to *GEORADIUSBYMEMBER*. + template + void georadius(const StringView &key, + const std::pair &loc, + double radius, + GeoUnit unit, + long long count, + bool asc, + Output output); + + OptionalLongLong georadiusbymember(const StringView &key, + const StringView &member, + double radius, + GeoUnit unit, + const StringView &destination, + bool store_dist, + long long count); + + // See comments on *GEORADIUS*. + template + void georadiusbymember(const StringView &key, + const StringView &member, + double radius, + GeoUnit unit, + long long count, + bool asc, + Output output); + + // SCRIPTING commands. + + template + Result eval(const StringView &script, + Keys keys_first, + Keys keys_last, + Args args_first, + Args args_last); + + template + Result eval(const StringView &script, + std::initializer_list keys, + std::initializer_list args); + + template + void eval(const StringView &script, + Keys keys_first, + Keys keys_last, + Args args_first, + Args args_last, + Output output); + + template + void eval(const StringView &script, + std::initializer_list keys, + std::initializer_list args, + Output output); + + template + Result evalsha(const StringView &script, + Keys keys_first, + Keys keys_last, + Args args_first, + Args args_last); + + template + Result evalsha(const StringView &script, + std::initializer_list keys, + std::initializer_list args); + + template + void evalsha(const StringView &script, + Keys keys_first, + Keys keys_last, + Args args_first, + Args args_last, + Output output); + + template + void evalsha(const StringView &script, + std::initializer_list keys, + std::initializer_list args, + Output output); + + // PUBSUB commands. + + long long publish(const StringView &channel, const StringView &message); + + // Stream commands. + + long long xack(const StringView &key, const StringView &group, const StringView &id); + + template + long long xack(const StringView &key, const StringView &group, Input first, Input last); + + template + long long xack(const StringView &key, const StringView &group, std::initializer_list il) { + return xack(key, group, il.begin(), il.end()); + } + + template + std::string xadd(const StringView &key, const StringView &id, Input first, Input last); + + template + std::string xadd(const StringView &key, const StringView &id, std::initializer_list il) { + return xadd(key, id, il.begin(), il.end()); + } + + template + std::string xadd(const StringView &key, + const StringView &id, + Input first, + Input last, + long long count, + bool approx = true); + + template + std::string xadd(const StringView &key, + const StringView &id, + std::initializer_list il, + long long count, + bool approx = true) { + return xadd(key, id, il.begin(), il.end(), count, approx); + } + + template + void xclaim(const StringView &key, + const StringView &group, + const StringView &consumer, + const std::chrono::milliseconds &min_idle_time, + const StringView &id, + Output output); + + template + void xclaim(const StringView &key, + const StringView &group, + const StringView &consumer, + const std::chrono::milliseconds &min_idle_time, + Input first, + Input last, + Output output); + + template + void xclaim(const StringView &key, + const StringView &group, + const StringView &consumer, + const std::chrono::milliseconds &min_idle_time, + std::initializer_list il, + Output output) { + xclaim(key, group, consumer, min_idle_time, il.begin(), il.end(), output); + } + + long long xdel(const StringView &key, const StringView &id); + + template + long long xdel(const StringView &key, Input first, Input last); + + template + long long xdel(const StringView &key, std::initializer_list il) { + return xdel(key, il.begin(), il.end()); + } + + void xgroup_create(const StringView &key, + const StringView &group, + const StringView &id, + bool mkstream = false); + + void xgroup_setid(const StringView &key, const StringView &group, const StringView &id); + + long long xgroup_destroy(const StringView &key, const StringView &group); + + long long xgroup_delconsumer(const StringView &key, + const StringView &group, + const StringView &consumer); + + long long xlen(const StringView &key); + + template + auto xpending(const StringView &key, const StringView &group, Output output) + -> std::tuple; + + template + void xpending(const StringView &key, + const StringView &group, + const StringView &start, + const StringView &end, + long long count, + Output output); + + template + void xpending(const StringView &key, + const StringView &group, + const StringView &start, + const StringView &end, + long long count, + const StringView &consumer, + Output output); + + template + void xrange(const StringView &key, + const StringView &start, + const StringView &end, + Output output); + + template + void xrange(const StringView &key, + const StringView &start, + const StringView &end, + long long count, + Output output); + + template + void xread(const StringView &key, + const StringView &id, + long long count, + Output output); + + template + void xread(const StringView &key, + const StringView &id, + Output output) { + xread(key, id, 0, output); + } + + template + auto xread(Input first, Input last, long long count, Output output) + -> typename std::enable_if::value>::type; + + template + auto xread(Input first, Input last, Output output) + -> typename std::enable_if::value>::type { + xread(first, last, 0, output); + } + + template + void xread(const StringView &key, + const StringView &id, + const std::chrono::milliseconds &timeout, + long long count, + Output output); + + template + void xread(const StringView &key, + const StringView &id, + const std::chrono::milliseconds &timeout, + Output output) { + xread(key, id, timeout, 0, output); + } + + template + auto xread(Input first, + Input last, + const std::chrono::milliseconds &timeout, + long long count, + Output output) + -> typename std::enable_if::value>::type; + + template + auto xread(Input first, + Input last, + const std::chrono::milliseconds &timeout, + Output output) + -> typename std::enable_if::value>::type { + xread(first, last, timeout, 0, output); + } + + template + void xreadgroup(const StringView &group, + const StringView &consumer, + const StringView &key, + const StringView &id, + long long count, + bool noack, + Output output); + + template + void xreadgroup(const StringView &group, + const StringView &consumer, + const StringView &key, + const StringView &id, + long long count, + Output output) { + xreadgroup(group, consumer, key, id, count, false, output); + } + + template + void xreadgroup(const StringView &group, + const StringView &consumer, + const StringView &key, + const StringView &id, + Output output) { + xreadgroup(group, consumer, key, id, 0, false, output); + } + + template + auto xreadgroup(const StringView &group, + const StringView &consumer, + Input first, + Input last, + long long count, + bool noack, + Output output) + -> typename std::enable_if::value>::type; + + template + auto xreadgroup(const StringView &group, + const StringView &consumer, + Input first, + Input last, + long long count, + Output output) + -> typename std::enable_if::value>::type { + xreadgroup(group, consumer, first ,last, count, false, output); + } + + template + auto xreadgroup(const StringView &group, + const StringView &consumer, + Input first, + Input last, + Output output) + -> typename std::enable_if::value>::type { + xreadgroup(group, consumer, first ,last, 0, false, output); + } + + template + void xreadgroup(const StringView &group, + const StringView &consumer, + const StringView &key, + const StringView &id, + const std::chrono::milliseconds &timeout, + long long count, + bool noack, + Output output); + + template + void xreadgroup(const StringView &group, + const StringView &consumer, + const StringView &key, + const StringView &id, + const std::chrono::milliseconds &timeout, + long long count, + Output output) { + return xreadgroup(group, consumer, key, id, timeout, count, false, output); + } + + template + void xreadgroup(const StringView &group, + const StringView &consumer, + const StringView &key, + const StringView &id, + const std::chrono::milliseconds &timeout, + Output output) { + return xreadgroup(group, consumer, key, id, timeout, 0, false, output); + } + + template + auto xreadgroup(const StringView &group, + const StringView &consumer, + Input first, + Input last, + const std::chrono::milliseconds &timeout, + long long count, + bool noack, + Output output) + -> typename std::enable_if::value>::type; + + template + auto xreadgroup(const StringView &group, + const StringView &consumer, + Input first, + Input last, + const std::chrono::milliseconds &timeout, + long long count, + Output output) + -> typename std::enable_if::value>::type { + xreadgroup(group, consumer, first, last, timeout, count, false, output); + } + + template + auto xreadgroup(const StringView &group, + const StringView &consumer, + Input first, + Input last, + const std::chrono::milliseconds &timeout, + Output output) + -> typename std::enable_if::value>::type { + xreadgroup(group, consumer, first, last, timeout, 0, false, output); + } + + template + void xrevrange(const StringView &key, + const StringView &end, + const StringView &start, + Output output); + + template + void xrevrange(const StringView &key, + const StringView &end, + const StringView &start, + long long count, + Output output); + + long long xtrim(const StringView &key, long long count, bool approx = true); + +private: + class Command { + public: + explicit Command(const StringView &cmd_name) : _cmd_name(cmd_name) {} + + template + void operator()(Connection &connection, Args &&...args) const { + CmdArgs cmd_args; + cmd_args.append(_cmd_name, std::forward(args)...); + connection.send(cmd_args); + } + + private: + StringView _cmd_name; + }; + + template + auto _generic_command(Cmd cmd, Key &&key, Args &&...args) + -> typename std::enable_if::value, + ReplyUPtr>::type; + + template + auto _generic_command(Cmd cmd, Key &&key, Args &&...args) + -> typename std::enable_if::type>::value, + ReplyUPtr>::type; + + template + ReplyUPtr _command(Cmd cmd, Connection &connection, Args &&...args); + + template + ReplyUPtr _command(Cmd cmd, const StringView &key, Args &&...args); + + template + ReplyUPtr _command(Cmd cmd, std::true_type, const StringView &key, Args &&...args); + + template + ReplyUPtr _command(Cmd cmd, std::false_type, Input &&first, Args &&...args); + + template + ReplyUPtr _command(const StringView &cmd_name, const IndexSequence &, Args &&...args) { + return command(cmd_name, NthValue(std::forward(args)...)...); + } + + template + ReplyUPtr _range_command(Cmd cmd, std::true_type, Input input, Args &&...args); + + template + ReplyUPtr _range_command(Cmd cmd, std::false_type, Input input, Args &&...args); + + void _asking(Connection &connection); + + template + ReplyUPtr _score_command(std::true_type, Cmd cmd, Args &&... args); + + template + ReplyUPtr _score_command(std::false_type, Cmd cmd, Args &&... args); + + template + ReplyUPtr _score_command(Cmd cmd, Args &&... args); + + ShardsPool _pool; +}; + +} + +} + +#include "redis_cluster.hpp" + +#endif // end SEWENEW_REDISPLUSPLUS_REDIS_CLUSTER_H diff --git a/ext/redis-plus-plus-1.3.3/install/ubuntu22.04/arm64/include/sw/redis++/redis_cluster.hpp b/ext/redis-plus-plus-1.3.3/install/ubuntu22.04/arm64/include/sw/redis++/redis_cluster.hpp new file mode 100644 index 000000000..2153d181b --- /dev/null +++ b/ext/redis-plus-plus-1.3.3/install/ubuntu22.04/arm64/include/sw/redis++/redis_cluster.hpp @@ -0,0 +1,1403 @@ +/************************************************************************** + Copyright (c) 2017 sewenew + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + *************************************************************************/ + +#ifndef SEWENEW_REDISPLUSPLUS_REDIS_CLUSTER_HPP +#define SEWENEW_REDISPLUSPLUS_REDIS_CLUSTER_HPP + +#include +#include "command.h" +#include "reply.h" +#include "utils.h" +#include "errors.h" +#include "shards_pool.h" + +namespace sw { + +namespace redis { + +template +auto RedisCluster::command(Cmd cmd, Key &&key, Args &&...args) + -> typename std::enable_if::value, ReplyUPtr>::type { + return _command(cmd, + std::is_convertible::type, StringView>(), + std::forward(key), + std::forward(args)...); +} + +template +auto RedisCluster::command(const StringView &cmd_name, Key &&key, Args &&...args) + -> typename std::enable_if<(std::is_convertible::value + || std::is_arithmetic::type>::value) + && !IsIter::type>::value, ReplyUPtr>::type { + auto cmd = Command(cmd_name); + + return _generic_command(cmd, std::forward(key), std::forward(args)...); +} + +template +auto RedisCluster::command(const StringView &cmd_name, Key &&key, Args &&...args) + -> typename std::enable_if::value + || std::is_arithmetic::type>::value, Result>::type { + auto r = command(cmd_name, std::forward(key), std::forward(args)...); + + assert(r); + + return reply::parse(*r); +} + +template +auto RedisCluster::command(const StringView &cmd_name, Key &&key, Args &&...args) + -> typename std::enable_if<(std::is_convertible::value + || std::is_arithmetic::type>::value) + && IsIter::type>::value, void>::type { + auto r = _command(cmd_name, + MakeIndexSequence(), + std::forward(key), + std::forward(args)...); + + assert(r); + + reply::to_array(*r, LastValue(std::forward(args)...)); +} + +template +auto RedisCluster::command(Input first, Input last) + -> typename std::enable_if::value, ReplyUPtr>::type { + if (first == last || std::next(first) == last) { + throw Error("command: invalid range"); + } + + const auto &key = *first; + ++first; + + auto cmd = [&key](Connection &connection, Input first, Input last) { + CmdArgs cmd_args; + cmd_args.append(key); + while (first != last) { + cmd_args.append(*first); + ++first; + } + connection.send(cmd_args); + }; + + return command(cmd, first, last); +} + +template +auto RedisCluster::command(Input first, Input last) + -> typename std::enable_if::value, Result>::type { + auto r = command(first, last); + + assert(r); + + return reply::parse(*r); +} + +template +auto RedisCluster::command(Input first, Input last, Output output) + -> typename std::enable_if::value, void>::type { + auto r = command(first, last); + + assert(r); + + reply::to_array(*r, output); +} + +// KEY commands. + +template +long long RedisCluster::del(Input first, Input last) { + range_check("DEL", first, last); + + auto reply = command(cmd::del_range, first, last); + + return reply::parse(*reply); +} + +template +long long RedisCluster::exists(Input first, Input last) { + range_check("EXISTS", first, last); + + auto reply = command(cmd::exists_range, first, last); + + return reply::parse(*reply); +} + +inline bool RedisCluster::expire(const StringView &key, const std::chrono::seconds &timeout) { + return expire(key, timeout.count()); +} + +inline bool RedisCluster::expireat(const StringView &key, + const std::chrono::time_point &tp) { + return expireat(key, tp.time_since_epoch().count()); +} + +inline bool RedisCluster::pexpire(const StringView &key, const std::chrono::milliseconds &timeout) { + return pexpire(key, timeout.count()); +} + +inline bool RedisCluster::pexpireat(const StringView &key, + const std::chrono::time_point &tp) { + return pexpireat(key, tp.time_since_epoch().count()); +} + +inline void RedisCluster::restore(const StringView &key, + const StringView &val, + const std::chrono::milliseconds &ttl, + bool replace) { + return restore(key, val, ttl.count(), replace); +} + +template +long long RedisCluster::touch(Input first, Input last) { + range_check("TOUCH", first, last); + + auto reply = command(cmd::touch_range, first, last); + + return reply::parse(*reply); +} + +template +long long RedisCluster::unlink(Input first, Input last) { + range_check("UNLINK", first, last); + + auto reply = command(cmd::unlink_range, first, last); + + return reply::parse(*reply); +} + +// STRING commands. + +template +long long RedisCluster::bitop(BitOp op, const StringView &destination, Input first, Input last) { + range_check("BITOP", first, last); + + auto reply = _command(cmd::bitop_range, destination, op, destination, first, last); + + return reply::parse(*reply); +} + +template +void RedisCluster::mget(Input first, Input last, Output output) { + range_check("MGET", first, last); + + auto reply = command(cmd::mget, first, last); + + reply::to_array(*reply, output); +} + +template +void RedisCluster::mset(Input first, Input last) { + range_check("MSET", first, last); + + auto reply = command(cmd::mset, first, last); + + reply::parse(*reply); +} + +template +bool RedisCluster::msetnx(Input first, Input last) { + range_check("MSETNX", first, last); + + auto reply = command(cmd::msetnx, first, last); + + return reply::parse(*reply); +} + +inline void RedisCluster::psetex(const StringView &key, + const std::chrono::milliseconds &ttl, + const StringView &val) { + return psetex(key, ttl.count(), val); +} + +inline void RedisCluster::setex(const StringView &key, + const std::chrono::seconds &ttl, + const StringView &val) { + setex(key, ttl.count(), val); +} + +// LIST commands. + +template +OptionalStringPair RedisCluster::blpop(Input first, Input last, long long timeout) { + range_check("BLPOP", first, last); + + auto reply = command(cmd::blpop_range, first, last, timeout); + + return reply::parse(*reply); +} + +template +OptionalStringPair RedisCluster::blpop(Input first, + Input last, + const std::chrono::seconds &timeout) { + return blpop(first, last, timeout.count()); +} + +template +OptionalStringPair RedisCluster::brpop(Input first, Input last, long long timeout) { + range_check("BRPOP", first, last); + + auto reply = command(cmd::brpop_range, first, last, timeout); + + return reply::parse(*reply); +} + +template +OptionalStringPair RedisCluster::brpop(Input first, + Input last, + const std::chrono::seconds &timeout) { + return brpop(first, last, timeout.count()); +} + +inline OptionalString RedisCluster::brpoplpush(const StringView &source, + const StringView &destination, + const std::chrono::seconds &timeout) { + return brpoplpush(source, destination, timeout.count()); +} + +template +inline long long RedisCluster::lpush(const StringView &key, Input first, Input last) { + range_check("LPUSH", first, last); + + auto reply = command(cmd::lpush_range, key, first, last); + + return reply::parse(*reply); +} + +template +inline void RedisCluster::lrange(const StringView &key, long long start, long long stop, Output output) { + auto reply = command(cmd::lrange, key, start, stop); + + reply::to_array(*reply, output); +} + +template +inline long long RedisCluster::rpush(const StringView &key, Input first, Input last) { + range_check("RPUSH", first, last); + + auto reply = command(cmd::rpush_range, key, first, last); + + return reply::parse(*reply); +} + +// HASH commands. + +template +inline long long RedisCluster::hdel(const StringView &key, Input first, Input last) { + range_check("HDEL", first, last); + + auto reply = command(cmd::hdel_range, key, first, last); + + return reply::parse(*reply); +} + +template +inline void RedisCluster::hgetall(const StringView &key, Output output) { + auto reply = command(cmd::hgetall, key); + + reply::to_array(*reply, output); +} + +template +inline void RedisCluster::hkeys(const StringView &key, Output output) { + auto reply = command(cmd::hkeys, key); + + reply::to_array(*reply, output); +} + +template +inline void RedisCluster::hmget(const StringView &key, Input first, Input last, Output output) { + range_check("HMGET", first, last); + + auto reply = command(cmd::hmget, key, first, last); + + reply::to_array(*reply, output); +} + +template +inline void RedisCluster::hmset(const StringView &key, Input first, Input last) { + range_check("HMSET", first, last); + + auto reply = command(cmd::hmset, key, first, last); + + reply::parse(*reply); +} + +template +long long RedisCluster::hscan(const StringView &key, + long long cursor, + const StringView &pattern, + long long count, + Output output) { + auto reply = command(cmd::hscan, key, cursor, pattern, count); + + return reply::parse_scan_reply(*reply, output); +} + +template +inline long long RedisCluster::hscan(const StringView &key, + long long cursor, + const StringView &pattern, + Output output) { + return hscan(key, cursor, pattern, 10, output); +} + +template +inline long long RedisCluster::hscan(const StringView &key, + long long cursor, + long long count, + Output output) { + return hscan(key, cursor, "*", count, output); +} + +template +inline long long RedisCluster::hscan(const StringView &key, + long long cursor, + Output output) { + return hscan(key, cursor, "*", 10, output); +} + +template +auto RedisCluster::hset(const StringView &key, Input first, Input last) + -> typename std::enable_if::value, + long long>::type { + range_check("HSET", first, last); + + auto reply = command(cmd::hset_range, key, first, last); + + return reply::parse(*reply); +} + +template +inline void RedisCluster::hvals(const StringView &key, Output output) { + auto reply = command(cmd::hvals, key); + + reply::to_array(*reply, output); +} + +// SET commands. + +template +long long RedisCluster::sadd(const StringView &key, Input first, Input last) { + range_check("SADD", first, last); + + auto reply = command(cmd::sadd_range, key, first, last); + + return reply::parse(*reply); +} + +template +void RedisCluster::sdiff(Input first, Input last, Output output) { + range_check("SDIFF", first, last); + + auto reply = command(cmd::sdiff, first, last); + + reply::to_array(*reply, output); +} + +template +long long RedisCluster::sdiffstore(const StringView &destination, + Input first, + Input last) { + range_check("SDIFFSTORE", first, last); + + auto reply = command(cmd::sdiffstore_range, destination, first, last); + + return reply::parse(*reply); +} + +template +void RedisCluster::sinter(Input first, Input last, Output output) { + range_check("SINTER", first, last); + + auto reply = command(cmd::sinter, first, last); + + reply::to_array(*reply, output); +} + +template +long long RedisCluster::sinterstore(const StringView &destination, + Input first, + Input last) { + range_check("SINTERSTORE", first, last); + + auto reply = command(cmd::sinterstore_range, destination, first, last); + + return reply::parse(*reply); +} + +template +void RedisCluster::smembers(const StringView &key, Output output) { + auto reply = command(cmd::smembers, key); + + reply::to_array(*reply, output); +} + +template +void RedisCluster::spop(const StringView &key, long long count, Output output) { + auto reply = command(cmd::spop_range, key, count); + + reply::to_array(*reply, output); +} + +template +void RedisCluster::srandmember(const StringView &key, long long count, Output output) { + auto reply = command(cmd::srandmember_range, key, count); + + reply::to_array(*reply, output); +} + +template +long long RedisCluster::srem(const StringView &key, Input first, Input last) { + range_check("SREM", first, last); + + auto reply = command(cmd::srem_range, key, first, last); + + return reply::parse(*reply); +} + +template +long long RedisCluster::sscan(const StringView &key, + long long cursor, + const StringView &pattern, + long long count, + Output output) { + auto reply = command(cmd::sscan, key, cursor, pattern, count); + + return reply::parse_scan_reply(*reply, output); +} + +template +inline long long RedisCluster::sscan(const StringView &key, + long long cursor, + const StringView &pattern, + Output output) { + return sscan(key, cursor, pattern, 10, output); +} + +template +inline long long RedisCluster::sscan(const StringView &key, + long long cursor, + long long count, + Output output) { + return sscan(key, cursor, "*", count, output); +} + +template +inline long long RedisCluster::sscan(const StringView &key, + long long cursor, + Output output) { + return sscan(key, cursor, "*", 10, output); +} + +template +void RedisCluster::sunion(Input first, Input last, Output output) { + range_check("SUNION", first, last); + + auto reply = command(cmd::sunion, first, last); + + reply::to_array(*reply, output); +} + +template +long long RedisCluster::sunionstore(const StringView &destination, Input first, Input last) { + range_check("SUNIONSTORE", first, last); + + auto reply = command(cmd::sunionstore_range, destination, first, last); + + return reply::parse(*reply); +} + +// SORTED SET commands. + +inline auto RedisCluster::bzpopmax(const StringView &key, const std::chrono::seconds &timeout) + -> Optional> { + return bzpopmax(key, timeout.count()); +} + +template +auto RedisCluster::bzpopmax(Input first, Input last, long long timeout) + -> Optional> { + auto reply = command(cmd::bzpopmax_range, first, last, timeout); + + return reply::parse>>(*reply); +} + +template +inline auto RedisCluster::bzpopmax(Input first, + Input last, + const std::chrono::seconds &timeout) + -> Optional> { + return bzpopmax(first, last, timeout.count()); +} + +inline auto RedisCluster::bzpopmin(const StringView &key, const std::chrono::seconds &timeout) + -> Optional> { + return bzpopmin(key, timeout.count()); +} + +template +auto RedisCluster::bzpopmin(Input first, Input last, long long timeout) + -> Optional> { + auto reply = command(cmd::bzpopmin_range, first, last, timeout); + + return reply::parse>>(*reply); +} + +template +inline auto RedisCluster::bzpopmin(Input first, + Input last, + const std::chrono::seconds &timeout) + -> Optional> { + return bzpopmin(first, last, timeout.count()); +} + +template +long long RedisCluster::zadd(const StringView &key, + Input first, + Input last, + UpdateType type, + bool changed) { + range_check("ZADD", first, last); + + auto reply = command(cmd::zadd_range, key, first, last, type, changed); + + return reply::parse(*reply); +} + +template +long long RedisCluster::zcount(const StringView &key, const Interval &interval) { + auto reply = command(cmd::zcount, key, interval); + + return reply::parse(*reply); +} + +template +long long RedisCluster::zinterstore(const StringView &destination, + Input first, + Input last, + Aggregation type) { + range_check("ZINTERSTORE", first, last); + + auto reply = command(cmd::zinterstore_range, + destination, + first, + last, + type); + + return reply::parse(*reply); +} + +template +long long RedisCluster::zlexcount(const StringView &key, const Interval &interval) { + auto reply = command(cmd::zlexcount, key, interval); + + return reply::parse(*reply); +} + +template +void RedisCluster::zpopmax(const StringView &key, long long count, Output output) { + auto reply = command(cmd::zpopmax, key, count); + + reply::to_array(*reply, output); +} + +template +void RedisCluster::zpopmin(const StringView &key, long long count, Output output) { + auto reply = command(cmd::zpopmin, key, count); + + reply::to_array(*reply, output); +} + +template +void RedisCluster::zrange(const StringView &key, long long start, long long stop, Output output) { + auto reply = _score_command(cmd::zrange, key, start, stop); + + reply::to_array(*reply, output); +} + +template +void RedisCluster::zrangebylex(const StringView &key, const Interval &interval, Output output) { + zrangebylex(key, interval, {}, output); +} + +template +void RedisCluster::zrangebylex(const StringView &key, + const Interval &interval, + const LimitOptions &opts, + Output output) { + auto reply = command(cmd::zrangebylex, key, interval, opts); + + reply::to_array(*reply, output); +} + +template +void RedisCluster::zrangebyscore(const StringView &key, + const Interval &interval, + Output output) { + zrangebyscore(key, interval, {}, output); +} + +template +void RedisCluster::zrangebyscore(const StringView &key, + const Interval &interval, + const LimitOptions &opts, + Output output) { + auto reply = _score_command(cmd::zrangebyscore, + key, + interval, + opts); + + reply::to_array(*reply, output); +} + +template +long long RedisCluster::zrem(const StringView &key, Input first, Input last) { + range_check("ZREM", first, last); + + auto reply = command(cmd::zrem_range, key, first, last); + + return reply::parse(*reply); +} + +template +long long RedisCluster::zremrangebylex(const StringView &key, const Interval &interval) { + auto reply = command(cmd::zremrangebylex, key, interval); + + return reply::parse(*reply); +} + +template +long long RedisCluster::zremrangebyscore(const StringView &key, const Interval &interval) { + auto reply = command(cmd::zremrangebyscore, key, interval); + + return reply::parse(*reply); +} + +template +void RedisCluster::zrevrange(const StringView &key, long long start, long long stop, Output output) { + auto reply = _score_command(cmd::zrevrange, key, start, stop); + + reply::to_array(*reply, output); +} + +template +inline void RedisCluster::zrevrangebylex(const StringView &key, + const Interval &interval, + Output output) { + zrevrangebylex(key, interval, {}, output); +} + +template +void RedisCluster::zrevrangebylex(const StringView &key, + const Interval &interval, + const LimitOptions &opts, + Output output) { + auto reply = command(cmd::zrevrangebylex, key, interval, opts); + + reply::to_array(*reply, output); +} + +template +void RedisCluster::zrevrangebyscore(const StringView &key, const Interval &interval, Output output) { + zrevrangebyscore(key, interval, {}, output); +} + +template +void RedisCluster::zrevrangebyscore(const StringView &key, + const Interval &interval, + const LimitOptions &opts, + Output output) { + auto reply = _score_command(cmd::zrevrangebyscore, key, interval, opts); + + reply::to_array(*reply, output); +} + +template +long long RedisCluster::zscan(const StringView &key, + long long cursor, + const StringView &pattern, + long long count, + Output output) { + auto reply = command(cmd::zscan, key, cursor, pattern, count); + + return reply::parse_scan_reply(*reply, output); +} + +template +inline long long RedisCluster::zscan(const StringView &key, + long long cursor, + const StringView &pattern, + Output output) { + return zscan(key, cursor, pattern, 10, output); +} + +template +inline long long RedisCluster::zscan(const StringView &key, + long long cursor, + long long count, + Output output) { + return zscan(key, cursor, "*", count, output); +} + +template +inline long long RedisCluster::zscan(const StringView &key, + long long cursor, + Output output) { + return zscan(key, cursor, "*", 10, output); +} + +template +long long RedisCluster::zunionstore(const StringView &destination, + Input first, + Input last, + Aggregation type) { + range_check("ZUNIONSTORE", first, last); + + auto reply = command(cmd::zunionstore_range, + destination, + first, + last, + type); + + return reply::parse(*reply); +} + +// HYPERLOGLOG commands. + +template +bool RedisCluster::pfadd(const StringView &key, Input first, Input last) { + range_check("PFADD", first, last); + + auto reply = command(cmd::pfadd_range, key, first, last); + + return reply::parse(*reply); +} + +template +long long RedisCluster::pfcount(Input first, Input last) { + range_check("PFCOUNT", first, last); + + auto reply = command(cmd::pfcount_range, first, last); + + return reply::parse(*reply); +} + +template +void RedisCluster::pfmerge(const StringView &destination, + Input first, + Input last) { + range_check("PFMERGE", first, last); + + auto reply = command(cmd::pfmerge_range, destination, first, last); + + reply::parse(*reply); +} + +// GEO commands. + +template +inline long long RedisCluster::geoadd(const StringView &key, + Input first, + Input last) { + range_check("GEOADD", first, last); + + auto reply = command(cmd::geoadd_range, key, first, last); + + return reply::parse(*reply); +} + +template +void RedisCluster::geohash(const StringView &key, Input first, Input last, Output output) { + range_check("GEOHASH", first, last); + + auto reply = command(cmd::geohash_range, key, first, last); + + reply::to_array(*reply, output); +} + +template +void RedisCluster::geopos(const StringView &key, Input first, Input last, Output output) { + range_check("GEOPOS", first, last); + + auto reply = command(cmd::geopos_range, key, first, last); + + reply::to_array(*reply, output); +} + +template +void RedisCluster::georadius(const StringView &key, + const std::pair &loc, + double radius, + GeoUnit unit, + long long count, + bool asc, + Output output) { + auto reply = command(cmd::georadius, + key, + loc, + radius, + unit, + count, + asc, + WithCoord::type>::value, + WithDist::type>::value, + WithHash::type>::value); + + reply::to_array(*reply, output); +} + +template +void RedisCluster::georadiusbymember(const StringView &key, + const StringView &member, + double radius, + GeoUnit unit, + long long count, + bool asc, + Output output) { + auto reply = command(cmd::georadiusbymember, + key, + member, + radius, + unit, + count, + asc, + WithCoord::type>::value, + WithDist::type>::value, + WithHash::type>::value); + + reply::to_array(*reply, output); +} + +// SCRIPTING commands. + +template +Result RedisCluster::eval(const StringView &script, + Keys keys_first, + Keys keys_last, + Args args_first, + Args args_last) { + if (keys_first == keys_last) { + throw Error("DO NOT support Lua script without key"); + } + + auto reply = _command(cmd::eval, *keys_first, script, keys_first, keys_last, args_first, args_last); + + return reply::parse(*reply); +} + +template +Result RedisCluster::eval(const StringView &script, + std::initializer_list keys, + std::initializer_list args) { + return eval(script, keys.begin(), keys.end(), args.begin(), args.end()); +} + +template +void RedisCluster::eval(const StringView &script, + Keys keys_first, + Keys keys_last, + Args args_first, + Args args_last, + Output output) { + if (keys_first == keys_last) { + throw Error("DO NOT support Lua script without key"); + } + + auto reply = _command(cmd::eval, + *keys_first, + script, + keys_first, keys_last, + args_first, args_last); + + reply::to_array(*reply, output); +} + +template +void RedisCluster::eval(const StringView &script, + std::initializer_list keys, + std::initializer_list args, + Output output) { + eval(script, keys.begin(), keys.end(), args.begin(), args.end(), output); +} + +template +Result RedisCluster::evalsha(const StringView &script, + Keys keys_first, + Keys keys_last, + Args args_first, + Args args_last) { + if (keys_first == keys_last) { + throw Error("DO NOT support Lua script without key"); + } + + auto reply = _command(cmd::evalsha, *keys_first, script, + keys_first, keys_last, args_first, args_last); + + return reply::parse(*reply); +} + +template +Result RedisCluster::evalsha(const StringView &script, + std::initializer_list keys, + std::initializer_list args) { + return evalsha(script, keys.begin(), keys.end(), args.begin(), args.end()); +} + +template +void RedisCluster::evalsha(const StringView &script, + Keys keys_first, + Keys keys_last, + Args args_first, + Args args_last, + Output output) { + if (keys_first == keys_last) { + throw Error("DO NOT support Lua script without key"); + } + + auto reply = _command(cmd::evalsha, + *keys_first, + script, + keys_first, keys_last, + args_first, args_last); + + reply::to_array(*reply, output); +} + +template +void RedisCluster::evalsha(const StringView &script, + std::initializer_list keys, + std::initializer_list args, + Output output) { + evalsha(script, keys.begin(), keys.end(), args.begin(), args.end(), output); +} + +// Stream commands. + +template +long long RedisCluster::xack(const StringView &key, + const StringView &group, + Input first, + Input last) { + auto reply = command(cmd::xack_range, key, group, first, last); + + return reply::parse(*reply); +} + +template +std::string RedisCluster::xadd(const StringView &key, + const StringView &id, + Input first, + Input last) { + auto reply = command(cmd::xadd_range, key, id, first, last); + + return reply::parse(*reply); +} + +template +std::string RedisCluster::xadd(const StringView &key, + const StringView &id, + Input first, + Input last, + long long count, + bool approx) { + auto reply = command(cmd::xadd_maxlen_range, key, id, first, last, count, approx); + + return reply::parse(*reply); +} + +template +void RedisCluster::xclaim(const StringView &key, + const StringView &group, + const StringView &consumer, + const std::chrono::milliseconds &min_idle_time, + const StringView &id, + Output output) { + auto reply = command(cmd::xclaim, key, group, consumer, min_idle_time.count(), id); + + reply::to_array(*reply, output); +} + +template +void RedisCluster::xclaim(const StringView &key, + const StringView &group, + const StringView &consumer, + const std::chrono::milliseconds &min_idle_time, + Input first, + Input last, + Output output) { + auto reply = command(cmd::xclaim_range, + key, + group, + consumer, + min_idle_time.count(), + first, + last); + + reply::to_array(*reply, output); +} + +template +long long RedisCluster::xdel(const StringView &key, Input first, Input last) { + auto reply = command(cmd::xdel_range, key, first, last); + + return reply::parse(*reply); +} + +template +auto RedisCluster::xpending(const StringView &key, const StringView &group, Output output) + -> std::tuple { + auto reply = command(cmd::xpending, key, group); + + return reply::parse_xpending_reply(*reply, output); +} + +template +void RedisCluster::xpending(const StringView &key, + const StringView &group, + const StringView &start, + const StringView &end, + long long count, + Output output) { + auto reply = command(cmd::xpending_detail, key, group, start, end, count); + + reply::to_array(*reply, output); +} + +template +void RedisCluster::xpending(const StringView &key, + const StringView &group, + const StringView &start, + const StringView &end, + long long count, + const StringView &consumer, + Output output) { + auto reply = command(cmd::xpending_per_consumer, key, group, start, end, count, consumer); + + reply::to_array(*reply, output); +} + +template +void RedisCluster::xrange(const StringView &key, + const StringView &start, + const StringView &end, + Output output) { + auto reply = command(cmd::xrange, key, start, end); + + reply::to_array(*reply, output); +} + +template +void RedisCluster::xrange(const StringView &key, + const StringView &start, + const StringView &end, + long long count, + Output output) { + auto reply = command(cmd::xrange_count, key, start, end, count); + + reply::to_array(*reply, output); +} + +template +void RedisCluster::xread(const StringView &key, + const StringView &id, + long long count, + Output output) { + auto reply = command(cmd::xread, key, id, count); + + if (!reply::is_nil(*reply)) { + reply::to_array(*reply, output); + } +} + +template +auto RedisCluster::xread(Input first, Input last, long long count, Output output) + -> typename std::enable_if::value>::type { + range_check("XREAD", first, last); + + auto reply = command(cmd::xread_range, first, last, count); + + if (!reply::is_nil(*reply)) { + reply::to_array(*reply, output); + } +} + +template +void RedisCluster::xread(const StringView &key, + const StringView &id, + const std::chrono::milliseconds &timeout, + long long count, + Output output) { + auto reply = command(cmd::xread_block, key, id, timeout.count(), count); + + if (!reply::is_nil(*reply)) { + reply::to_array(*reply, output); + } +} + +template +auto RedisCluster::xread(Input first, + Input last, + const std::chrono::milliseconds &timeout, + long long count, + Output output) + -> typename std::enable_if::value>::type { + range_check("XREAD", first, last); + + auto reply = command(cmd::xread_block_range, first, last, timeout.count(), count); + + if (!reply::is_nil(*reply)) { + reply::to_array(*reply, output); + } +} + +template +void RedisCluster::xreadgroup(const StringView &group, + const StringView &consumer, + const StringView &key, + const StringView &id, + long long count, + bool noack, + Output output) { + auto reply = _command(cmd::xreadgroup, key, group, consumer, key, id, count, noack); + + if (!reply::is_nil(*reply)) { + reply::to_array(*reply, output); + } +} + +template +auto RedisCluster::xreadgroup(const StringView &group, + const StringView &consumer, + Input first, + Input last, + long long count, + bool noack, + Output output) + -> typename std::enable_if::value>::type { + range_check("XREADGROUP", first, last); + + auto reply = _command(cmd::xreadgroup_range, + first->first, + group, + consumer, + first, + last, + count, + noack); + + if (!reply::is_nil(*reply)) { + reply::to_array(*reply, output); + } +} + +template +void RedisCluster::xreadgroup(const StringView &group, + const StringView &consumer, + const StringView &key, + const StringView &id, + const std::chrono::milliseconds &timeout, + long long count, + bool noack, + Output output) { + auto reply = _command(cmd::xreadgroup_block, + key, + group, + consumer, + key, + id, + timeout.count(), + count, + noack); + + if (!reply::is_nil(*reply)) { + reply::to_array(*reply, output); + } +} + +template +auto RedisCluster::xreadgroup(const StringView &group, + const StringView &consumer, + Input first, + Input last, + const std::chrono::milliseconds &timeout, + long long count, + bool noack, + Output output) + -> typename std::enable_if::value>::type { + range_check("XREADGROUP", first, last); + + auto reply = _command(cmd::xreadgroup_block_range, + first->first, + group, + consumer, + first, + last, + timeout.count(), + count, + noack); + + if (!reply::is_nil(*reply)) { + reply::to_array(*reply, output); + } +} + +template +void RedisCluster::xrevrange(const StringView &key, + const StringView &end, + const StringView &start, + Output output) { + auto reply = command(cmd::xrevrange, key, end, start); + + reply::to_array(*reply, output); +} + +template +void RedisCluster::xrevrange(const StringView &key, + const StringView &end, + const StringView &start, + long long count, + Output output) { + auto reply = command(cmd::xrevrange_count, key, end, start, count); + + reply::to_array(*reply, output); +} + +template +auto RedisCluster::_generic_command(Cmd cmd, Key &&key, Args &&...args) + -> typename std::enable_if::value, + ReplyUPtr>::type { + return command(cmd, std::forward(key), std::forward(args)...); +} + +template +auto RedisCluster::_generic_command(Cmd cmd, Key &&key, Args &&...args) + -> typename std::enable_if::type>::value, + ReplyUPtr>::type { + auto k = std::to_string(std::forward(key)); + return command(cmd, k, std::forward(args)...); +} + +template +ReplyUPtr RedisCluster::_command(Cmd cmd, std::true_type, const StringView &key, Args &&...args) { + return _command(cmd, key, key, std::forward(args)...); +} + +template +ReplyUPtr RedisCluster::_command(Cmd cmd, std::false_type, Input &&first, Args &&...args) { + return _range_command(cmd, + std::is_convertible< + typename std::decay< + decltype(*std::declval())>::type, StringView>(), + std::forward(first), + std::forward(args)...); +} + +template +ReplyUPtr RedisCluster::_range_command(Cmd cmd, std::true_type, Input input, Args &&...args) { + return _command(cmd, *input, input, std::forward(args)...); +} + +template +ReplyUPtr RedisCluster::_range_command(Cmd cmd, std::false_type, Input input, Args &&...args) { + return _command(cmd, std::get<0>(*input), input, std::forward(args)...); +} + +template +ReplyUPtr RedisCluster::_command(Cmd cmd, Connection &connection, Args &&...args) { + assert(!connection.broken()); + + cmd(connection, std::forward(args)...); + + return connection.recv(); +} + +template +ReplyUPtr RedisCluster::_command(Cmd cmd, const StringView &key, Args &&...args) { + for (auto idx = 0; idx < 2; ++idx) { + try { + auto pool = _pool.fetch(key); + assert(pool); + SafeConnection safe_connection(*pool); + + return _command(cmd, safe_connection.connection(), std::forward(args)...); + } catch (const IoError &err) { + // When master is down, one of its replicas will be promoted to be the new master. + // If we try to send command to the old master, we'll get an *IoError*. + // In this case, we need to update the slots mapping. + _pool.update(); + } catch (const ClosedError &err) { + // Node might be removed. + // 1. Get up-to-date slot mapping to check if the node still exists. + _pool.update(); + + // TODO: + // 2. If it's NOT exist, update slot mapping, and retry. + // 3. If it's still exist, that means the node is down, NOT removed, throw exception. + } catch (const MovedError &err) { + // Slot mapping has been changed, update it and try again. + _pool.update(); + } catch (const AskError &err) { + auto pool = _pool.fetch(err.node()); + assert(pool); + SafeConnection safe_connection(*pool); + auto &connection = safe_connection.connection(); + + // 1. send ASKING command. + _asking(connection); + + // 2. resend last command. + try { + return _command(cmd, connection, std::forward(args)...); + } catch (const MovedError &err) { + throw Error("Slot migrating... ASKING node hasn't been set to IMPORTING state"); + } + } // For other exceptions, just throw it. + } + + // Possible failures: + // 1. Source node has already run 'CLUSTER SETSLOT xxx NODE xxx', + // while the destination node has NOT run it. + // In this case, client will be redirected by both nodes with MovedError. + // 2. Other failures... + throw Error("Failed to send command with key: " + std::string(key.data(), key.size())); +} + +template +inline ReplyUPtr RedisCluster::_score_command(std::true_type, Cmd cmd, Args &&... args) { + return command(cmd, std::forward(args)..., true); +} + +template +inline ReplyUPtr RedisCluster::_score_command(std::false_type, Cmd cmd, Args &&... args) { + return command(cmd, std::forward(args)..., false); +} + +template +inline ReplyUPtr RedisCluster::_score_command(Cmd cmd, Args &&... args) { + return _score_command(typename IsKvPairIter::type(), + cmd, + std::forward(args)...); +} + +} + +} + +#endif // end SEWENEW_REDISPLUSPLUS_REDIS_CLUSTER_HPP diff --git a/ext/redis-plus-plus-1.3.3/install/ubuntu22.04/arm64/include/sw/redis++/reply.h b/ext/redis-plus-plus-1.3.3/install/ubuntu22.04/arm64/include/sw/redis++/reply.h new file mode 100644 index 000000000..d89174329 --- /dev/null +++ b/ext/redis-plus-plus-1.3.3/install/ubuntu22.04/arm64/include/sw/redis++/reply.h @@ -0,0 +1,435 @@ +/************************************************************************** + Copyright (c) 2017 sewenew + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + *************************************************************************/ + +#ifndef SEWENEW_REDISPLUSPLUS_REPLY_H +#define SEWENEW_REDISPLUSPLUS_REPLY_H + +#include +#include +#include +#include +#include +#include +#include +#include "errors.h" +#include "utils.h" + +namespace sw { + +namespace redis { + +struct ReplyDeleter { + void operator()(redisReply *reply) const { + if (reply != nullptr) { + freeReplyObject(reply); + } + } +}; + +using ReplyUPtr = std::unique_ptr; + +namespace reply { + +template +struct ParseTag {}; + +template +inline T parse(redisReply &reply) { + return parse(ParseTag(), reply); +} + +template +T parse_leniently(redisReply &reply); + +void parse(ParseTag, redisReply &reply); + +std::string parse(ParseTag, redisReply &reply); + +long long parse(ParseTag, redisReply &reply); + +double parse(ParseTag, redisReply &reply); + +bool parse(ParseTag, redisReply &reply); + +template +Optional parse(ParseTag>, redisReply &reply); + +template +std::pair parse(ParseTag>, redisReply &reply); + +template +std::tuple parse(ParseTag>, redisReply &reply); + +#ifdef REDIS_PLUS_PLUS_HAS_VARIANT + +inline Monostate parse(ParseTag, redisReply &) { + // Just ignore the reply + return {}; +} + +template +Variant parse(ParseTag>, redisReply &reply); + +#endif + +template ::value, int>::type = 0> +T parse(ParseTag, redisReply &reply); + +template ::value, int>::type = 0> +T parse(ParseTag, redisReply &reply); + +template +long long parse_scan_reply(redisReply &reply, Output output); + +inline bool is_error(redisReply &reply) { + return reply.type == REDIS_REPLY_ERROR; +} + +inline bool is_nil(redisReply &reply) { + return reply.type == REDIS_REPLY_NIL; +} + +inline bool is_string(redisReply &reply) { + return reply.type == REDIS_REPLY_STRING; +} + +inline bool is_status(redisReply &reply) { + return reply.type == REDIS_REPLY_STATUS; +} + +inline bool is_integer(redisReply &reply) { + return reply.type == REDIS_REPLY_INTEGER; +} + +inline bool is_array(redisReply &reply) { + return reply.type == REDIS_REPLY_ARRAY; +} + +std::string to_status(redisReply &reply); + +template +void to_array(redisReply &reply, Output output); + +// Rewrite set reply to bool type +void rewrite_set_reply(redisReply &reply); + +// Some command might return an empty array reply as a nil reply, +// e.g. georadius, zpopmin, zpopmax. In this case, we rewrite the +// reply to a nil reply. +void rewrite_empty_array_reply(redisReply &reply); + +template +auto parse_xpending_reply(redisReply &reply, Output output) + -> std::tuple; + +} + +// Inline implementations. + +namespace reply { + +namespace detail { + +template +void to_array(redisReply &reply, Output output) { + if (!is_array(reply)) { + throw ProtoError("Expect ARRAY reply"); + } + + if (reply.element == nullptr) { + // Empty array. + return; + } + + for (std::size_t idx = 0; idx != reply.elements; ++idx) { + auto *sub_reply = reply.element[idx]; + if (sub_reply == nullptr) { + throw ProtoError("Null array element reply"); + } + + *output = parse::type>(*sub_reply); + + ++output; + } +} + +bool is_flat_array(redisReply &reply); + +template +void to_flat_array(redisReply &reply, Output output) { + if (reply.element == nullptr) { + // Empty array. + return; + } + + if (reply.elements % 2 != 0) { + throw ProtoError("Not string pair array reply"); + } + + for (std::size_t idx = 0; idx != reply.elements; idx += 2) { + auto *key_reply = reply.element[idx]; + auto *val_reply = reply.element[idx + 1]; + if (key_reply == nullptr || val_reply == nullptr) { + throw ProtoError("Null string array reply"); + } + + using Pair = typename IterType::type; + using FirstType = typename std::decay::type; + using SecondType = typename std::decay::type; + *output = std::make_pair(parse(*key_reply), + parse(*val_reply)); + + ++output; + } +} + +template +void to_array(std::true_type, redisReply &reply, Output output) { + if (is_flat_array(reply)) { + to_flat_array(reply, output); + } else { + to_array(reply, output); + } +} + +template +void to_array(std::false_type, redisReply &reply, Output output) { + to_array(reply, output); +} + +template +std::tuple parse_tuple(redisReply **reply, std::size_t idx) { + assert(reply != nullptr); + + auto *sub_reply = reply[idx]; + if (sub_reply == nullptr) { + throw ProtoError("Null reply"); + } + + return std::make_tuple(parse(*sub_reply)); +} + +template +auto parse_tuple(redisReply **reply, std::size_t idx) -> + typename std::enable_if>::type { + assert(reply != nullptr); + + return std::tuple_cat(parse_tuple(reply, idx), + parse_tuple(reply, idx + 1)); +} + +#ifdef REDIS_PLUS_PLUS_HAS_VARIANT + +template +Variant parse_variant(redisReply &reply) { + return parse(reply); +} + +template +auto parse_variant(redisReply &reply) -> + typename std::enable_if>::type { + auto return_var = [](auto &&arg) { + return Variant(std::move(arg)); + }; + + try { + return std::visit(return_var, parse_variant(reply)); + } catch (const ProtoError &) { + return std::visit(return_var, parse_variant(reply)); + } +} + +#endif + +} + +template +T parse_leniently(redisReply &reply) { + if (is_array(reply) && reply.elements == 1) { + if (reply.element == nullptr) { + throw ProtoError("null array reply"); + } + + auto *ele = reply.element[0]; + if (ele != nullptr) { + return parse(*ele); + } // else fall through + } + + return parse(reply); +} + +template +Optional parse(ParseTag>, redisReply &reply) { + if (reply::is_nil(reply)) { + // Because of a GCC bug, we cannot return {} for -std=c++17 + // Refer to https://gcc.gnu.org/bugzilla/show_bug.cgi?id=86465 +#if defined REDIS_PLUS_PLUS_HAS_OPTIONAL + return std::nullopt; +#else + return {}; +#endif + } + + return Optional(parse(reply)); +} + +template +std::pair parse(ParseTag>, redisReply &reply) { + if (!is_array(reply)) { + throw ProtoError("Expect ARRAY reply"); + } + + if (reply.elements != 2) { + throw ProtoError("NOT key-value PAIR reply"); + } + + if (reply.element == nullptr) { + throw ProtoError("Null PAIR reply"); + } + + auto *first = reply.element[0]; + auto *second = reply.element[1]; + if (first == nullptr || second == nullptr) { + throw ProtoError("Null pair reply"); + } + + return std::make_pair(parse::type>(*first), + parse::type>(*second)); +} + +template +std::tuple parse(ParseTag>, redisReply &reply) { + constexpr auto size = sizeof...(Args); + + static_assert(size > 0, "DO NOT support parsing tuple with 0 element"); + + if (!is_array(reply)) { + throw ProtoError("Expect ARRAY reply"); + } + + if (reply.elements != size) { + throw ProtoError("Expect tuple reply with " + std::to_string(size) + "elements"); + } + + if (reply.element == nullptr) { + throw ProtoError("Null TUPLE reply"); + } + + return detail::parse_tuple(reply.element, 0); +} + +#ifdef REDIS_PLUS_PLUS_HAS_VARIANT + +template +Variant parse(ParseTag>, redisReply &reply) { + return detail::parse_variant(reply); +} + +#endif + +template ::value, int>::type> +T parse(ParseTag, redisReply &reply) { + if (!is_array(reply)) { + throw ProtoError("Expect ARRAY reply"); + } + + T container; + + to_array(reply, std::back_inserter(container)); + + return container; +} + +template ::value, int>::type> +T parse(ParseTag, redisReply &reply) { + if (!is_array(reply)) { + throw ProtoError("Expect ARRAY reply"); + } + + T container; + + to_array(reply, std::inserter(container, container.end())); + + return container; +} + +template +long long parse_scan_reply(redisReply &reply, Output output) { + if (reply.elements != 2 || reply.element == nullptr) { + throw ProtoError("Invalid scan reply"); + } + + auto *cursor_reply = reply.element[0]; + auto *data_reply = reply.element[1]; + if (cursor_reply == nullptr || data_reply == nullptr) { + throw ProtoError("Invalid cursor reply or data reply"); + } + + auto cursor_str = reply::parse(*cursor_reply); + long long new_cursor = 0; + try { + new_cursor = std::stoll(cursor_str); + } catch (const std::exception &e) { + throw ProtoError("Invalid cursor reply: " + cursor_str); + } + + reply::to_array(*data_reply, output); + + return new_cursor; +} + +template +void to_array(redisReply &reply, Output output) { + if (!is_array(reply)) { + throw ProtoError("Expect ARRAY reply"); + } + + detail::to_array(typename IsKvPairIter::type(), reply, output); +} + +template +auto parse_xpending_reply(redisReply &reply, Output output) + -> std::tuple { + if (!is_array(reply) || reply.elements != 4) { + throw ProtoError("expect array reply with 4 elements"); + } + + for (std::size_t idx = 0; idx != reply.elements; ++idx) { + if (reply.element[idx] == nullptr) { + throw ProtoError("null array reply"); + } + } + + auto num = parse(*(reply.element[0])); + auto start = parse(*(reply.element[1])); + auto end = parse(*(reply.element[2])); + + auto &entry_reply = *(reply.element[3]); + if (!is_nil(entry_reply)) { + to_array(entry_reply, output); + } + + return std::make_tuple(num, std::move(start), std::move(end)); +} + +} + +} + +} + +#endif // end SEWENEW_REDISPLUSPLUS_REPLY_H diff --git a/ext/redis-plus-plus-1.3.3/install/ubuntu22.04/arm64/include/sw/redis++/sentinel.h b/ext/redis-plus-plus-1.3.3/install/ubuntu22.04/arm64/include/sw/redis++/sentinel.h new file mode 100644 index 000000000..6f998791e --- /dev/null +++ b/ext/redis-plus-plus-1.3.3/install/ubuntu22.04/arm64/include/sw/redis++/sentinel.h @@ -0,0 +1,141 @@ +/************************************************************************** + Copyright (c) 2017 sewenew + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + *************************************************************************/ + +#ifndef SEWENEW_REDISPLUSPLUS_SENTINEL_H +#define SEWENEW_REDISPLUSPLUS_SENTINEL_H + +#include +#include +#include +#include +#include +#include "connection.h" +#include "shards.h" +#include "reply.h" +#include "tls.h" + +namespace sw { + +namespace redis { + +struct SentinelOptions { + std::vector> nodes; + + std::string password; + + bool keep_alive = true; + + std::chrono::milliseconds connect_timeout{100}; + + std::chrono::milliseconds socket_timeout{100}; + + std::chrono::milliseconds retry_interval{100}; + + std::size_t max_retry = 2; + + tls::TlsOptions tls; +}; + +class Sentinel { +public: + explicit Sentinel(const SentinelOptions &sentinel_opts); + + Sentinel(const Sentinel &) = delete; + Sentinel& operator=(const Sentinel &) = delete; + + Sentinel(Sentinel &&) = delete; + Sentinel& operator=(Sentinel &&) = delete; + + ~Sentinel() = default; + +private: + Connection master(const std::string &master_name, const ConnectionOptions &opts); + + Connection slave(const std::string &master_name, const ConnectionOptions &opts); + + class Iterator; + + friend class SimpleSentinel; + + std::list _parse_options(const SentinelOptions &opts) const; + + Optional _get_master_addr_by_name(Connection &connection, const StringView &name); + + std::vector _get_slave_addr_by_name(Connection &connection, const StringView &name); + + Connection _connect_redis(const Node &node, ConnectionOptions opts); + + Role _get_role(Connection &connection); + + std::vector _parse_slave_info(redisReply &reply) const; + + std::list _healthy_sentinels; + + std::list _broken_sentinels; + + SentinelOptions _sentinel_opts; + + std::mutex _mutex; +}; + +class SimpleSentinel { +public: + SimpleSentinel(const std::shared_ptr &sentinel, + const std::string &master_name, + Role role); + + SimpleSentinel() = default; + + SimpleSentinel(const SimpleSentinel &) = default; + SimpleSentinel& operator=(const SimpleSentinel &) = default; + + SimpleSentinel(SimpleSentinel &&) = default; + SimpleSentinel& operator=(SimpleSentinel &&) = default; + + ~SimpleSentinel() = default; + + explicit operator bool() const { + return bool(_sentinel); + } + + Connection create(const ConnectionOptions &opts); + +private: + std::shared_ptr _sentinel; + + std::string _master_name; + + Role _role = Role::MASTER; +}; + +class StopIterError : public Error { +public: + StopIterError() : Error("StopIterError") {} + + StopIterError(const StopIterError &) = default; + StopIterError& operator=(const StopIterError &) = default; + + StopIterError(StopIterError &&) = default; + StopIterError& operator=(StopIterError &&) = default; + + virtual ~StopIterError() override = default; +}; + +} + +} + +#endif // end SEWENEW_REDISPLUSPLUS_SENTINEL_H diff --git a/ext/redis-plus-plus-1.3.3/install/ubuntu22.04/arm64/include/sw/redis++/shards.h b/ext/redis-plus-plus-1.3.3/install/ubuntu22.04/arm64/include/sw/redis++/shards.h new file mode 100644 index 000000000..0d4cd97b3 --- /dev/null +++ b/ext/redis-plus-plus-1.3.3/install/ubuntu22.04/arm64/include/sw/redis++/shards.h @@ -0,0 +1,115 @@ +/************************************************************************** + Copyright (c) 2017 sewenew + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + *************************************************************************/ + +#ifndef SEWENEW_REDISPLUSPLUS_SHARDS_H +#define SEWENEW_REDISPLUSPLUS_SHARDS_H + +#include +#include +#include "errors.h" + +namespace sw { + +namespace redis { + +using Slot = std::size_t; + +struct SlotRange { + Slot min; + Slot max; +}; + +inline bool operator<(const SlotRange &lhs, const SlotRange &rhs) { + return lhs.max < rhs.max; +} + +struct Node { + std::string host; + int port; +}; + +inline bool operator==(const Node &lhs, const Node &rhs) { + return lhs.host == rhs.host && lhs.port == rhs.port; +} + +struct NodeHash { + std::size_t operator()(const Node &node) const noexcept { + auto host_hash = std::hash{}(node.host); + auto port_hash = std::hash{}(node.port); + return host_hash ^ (port_hash << 1); + } +}; + +using Shards = std::map; + +class RedirectionError : public ReplyError { +public: + RedirectionError(const std::string &msg); + + RedirectionError(const RedirectionError &) = default; + RedirectionError& operator=(const RedirectionError &) = default; + + RedirectionError(RedirectionError &&) = default; + RedirectionError& operator=(RedirectionError &&) = default; + + virtual ~RedirectionError() override = default; + + Slot slot() const { + return _slot; + } + + const Node& node() const { + return _node; + } + +private: + std::pair _parse_error(const std::string &msg) const; + + Slot _slot = 0; + Node _node; +}; + +class MovedError : public RedirectionError { +public: + explicit MovedError(const std::string &msg) : RedirectionError(msg) {} + + MovedError(const MovedError &) = default; + MovedError& operator=(const MovedError &) = default; + + MovedError(MovedError &&) = default; + MovedError& operator=(MovedError &&) = default; + + virtual ~MovedError() override = default; +}; + +class AskError : public RedirectionError { +public: + explicit AskError(const std::string &msg) : RedirectionError(msg) {} + + AskError(const AskError &) = default; + AskError& operator=(const AskError &) = default; + + AskError(AskError &&) = default; + AskError& operator=(AskError &&) = default; + + virtual ~AskError() override = default; +}; + +} + +} + +#endif // end SEWENEW_REDISPLUSPLUS_SHARDS_H diff --git a/ext/redis-plus-plus-1.3.3/install/ubuntu22.04/arm64/include/sw/redis++/shards_pool.h b/ext/redis-plus-plus-1.3.3/install/ubuntu22.04/arm64/include/sw/redis++/shards_pool.h new file mode 100644 index 000000000..e6e9e4a52 --- /dev/null +++ b/ext/redis-plus-plus-1.3.3/install/ubuntu22.04/arm64/include/sw/redis++/shards_pool.h @@ -0,0 +1,121 @@ +/************************************************************************** + Copyright (c) 2017 sewenew + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + *************************************************************************/ + +#ifndef SEWENEW_REDISPLUSPLUS_SHARDS_POOL_H +#define SEWENEW_REDISPLUSPLUS_SHARDS_POOL_H + +#include +#include +#include +#include +#include +#include "reply.h" +#include "connection_pool.h" +#include "shards.h" + +namespace sw { + +namespace redis { + +class ShardsPool { +public: + ShardsPool() = default; + + ShardsPool(const ShardsPool &that) = delete; + ShardsPool& operator=(const ShardsPool &that) = delete; + + ShardsPool(ShardsPool &&that); + ShardsPool& operator=(ShardsPool &&that); + + ~ShardsPool() = default; + + ShardsPool(const ConnectionPoolOptions &pool_opts, + const ConnectionOptions &connection_opts, + Role role); + + // Fetch a connection by key. + ConnectionPoolSPtr fetch(const StringView &key); + + // Randomly pick a connection. + ConnectionPoolSPtr fetch(); + + // Fetch a connection by node. + ConnectionPoolSPtr fetch(const Node &node); + + void update(); + + ConnectionOptions connection_options(const StringView &key); + + ConnectionOptions connection_options(); + + Shards shards(); + +private: + void _move(ShardsPool &&that); + + void _init_pool(const Shards &shards); + + Shards _cluster_slots(Connection &connection) const; + + ReplyUPtr _cluster_slots_command(Connection &connection) const; + + Shards _parse_reply(redisReply &reply) const; + + Slot _parse_slot(redisReply *reply) const; + + Node _parse_node(redisReply *reply) const; + + std::pair _parse_slot_info(redisReply &reply) const; + + // Get slot by key. + std::size_t _slot(const StringView &key) const; + + // Randomly pick a slot. + std::size_t _slot() const; + + // Get a random number between [min, max] + std::size_t _random(std::size_t min, std::size_t max) const; + + ConnectionPoolSPtr& _get_pool(Slot slot); + + ConnectionPoolSPtr _fetch(Slot slot); + + ConnectionOptions _connection_options(Slot slot); + + using NodeMap = std::unordered_map; + + NodeMap::iterator _add_node(const Node &node); + + ConnectionPoolOptions _pool_opts; + + ConnectionOptions _connection_opts; + + Shards _shards; + + NodeMap _pools; + + std::mutex _mutex; + + Role _role = Role::MASTER; + + static const std::size_t SHARDS = 16383; +}; + +} + +} + +#endif // end SEWENEW_REDISPLUSPLUS_SHARDS_POOL_H diff --git a/ext/redis-plus-plus-1.3.3/install/ubuntu22.04/arm64/include/sw/redis++/subscriber.h b/ext/redis-plus-plus-1.3.3/install/ubuntu22.04/arm64/include/sw/redis++/subscriber.h new file mode 100644 index 000000000..8b7c5cfb4 --- /dev/null +++ b/ext/redis-plus-plus-1.3.3/install/ubuntu22.04/arm64/include/sw/redis++/subscriber.h @@ -0,0 +1,231 @@ +/************************************************************************** + Copyright (c) 2017 sewenew + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + *************************************************************************/ + +#ifndef SEWENEW_REDISPLUSPLUS_SUBSCRIBER_H +#define SEWENEW_REDISPLUSPLUS_SUBSCRIBER_H + +#include +#include +#include +#include "connection.h" +#include "reply.h" +#include "command.h" +#include "utils.h" + +namespace sw { + +namespace redis { + +// @NOTE: Subscriber is NOT thread-safe. +// Subscriber uses callbacks to handle messages. There are 6 kinds of messages: +// 1) MESSAGE: message sent to a channel. +// 2) PMESSAGE: message sent to channels of a given pattern. +// 3) SUBSCRIBE: meta message sent when we successfully subscribe to a channel. +// 4) UNSUBSCRIBE: meta message sent when we successfully unsubscribe to a channel. +// 5) PSUBSCRIBE: meta message sent when we successfully subscribe to a channel pattern. +// 6) PUNSUBSCRIBE: meta message sent when we successfully unsubscribe to a channel pattern. +// +// Use Subscriber::on_message(MsgCallback) to set the callback function for message of +// *MESSAGE* type, and the callback interface is: +// void (std::string channel, std::string msg) +// +// Use Subscriber::on_pmessage(PatternMsgCallback) to set the callback function for message of +// *PMESSAGE* type, and the callback interface is: +// void (std::string pattern, std::string channel, std::string msg) +// +// Messages of other types are called *META MESSAGE*, they have the same callback interface. +// Use Subscriber::on_meta(MetaCallback) to set the callback function: +// void (Subscriber::MsgType type, OptionalString channel, long long num) +// +// NOTE: If we haven't subscribe/psubscribe to any channel/pattern, and try to +// unsubscribe/punsubscribe without any parameter, i.e. unsubscribe/punsubscribe all +// channels/patterns, *channel* will be null. So the second parameter of meta callback +// is of type *OptionalString*. +// +// All these callback interfaces pass std::string by value, and you can take their ownership +// (i.e. std::move) safely. +// +// If you don't set callback for a specific kind of message, Subscriber::consume() will +// receive the message, and ignore it, i.e. no callback will be called. +class Subscriber { +public: + Subscriber(const Subscriber &) = delete; + Subscriber& operator=(const Subscriber &) = delete; + + Subscriber(Subscriber &&) = default; + Subscriber& operator=(Subscriber &&) = default; + + ~Subscriber() = default; + + enum class MsgType { + SUBSCRIBE, + UNSUBSCRIBE, + PSUBSCRIBE, + PUNSUBSCRIBE, + MESSAGE, + PMESSAGE + }; + + template + void on_message(MsgCb msg_callback); + + template + void on_pmessage(PMsgCb pmsg_callback); + + template + void on_meta(MetaCb meta_callback); + + void subscribe(const StringView &channel); + + template + void subscribe(Input first, Input last); + + template + void subscribe(std::initializer_list channels) { + subscribe(channels.begin(), channels.end()); + } + + void unsubscribe(); + + void unsubscribe(const StringView &channel); + + template + void unsubscribe(Input first, Input last); + + template + void unsubscribe(std::initializer_list channels) { + unsubscribe(channels.begin(), channels.end()); + } + + void psubscribe(const StringView &pattern); + + template + void psubscribe(Input first, Input last); + + template + void psubscribe(std::initializer_list channels) { + psubscribe(channels.begin(), channels.end()); + } + + void punsubscribe(); + + void punsubscribe(const StringView &channel); + + template + void punsubscribe(Input first, Input last); + + template + void punsubscribe(std::initializer_list channels) { + punsubscribe(channels.begin(), channels.end()); + } + + void consume(); + +private: + friend class Redis; + + friend class RedisCluster; + + explicit Subscriber(Connection connection); + + MsgType _msg_type(redisReply *reply) const; + + void _check_connection(); + + void _handle_message(redisReply &reply); + + void _handle_pmessage(redisReply &reply); + + void _handle_meta(MsgType type, redisReply &reply); + + using MsgCallback = std::function; + + using PatternMsgCallback = std::function; + + using MetaCallback = std::function; + + using TypeIndex = std::unordered_map; + static const TypeIndex _msg_type_index; + + Connection _connection; + + MsgCallback _msg_callback = nullptr; + + PatternMsgCallback _pmsg_callback = nullptr; + + MetaCallback _meta_callback = nullptr; +}; + +template +void Subscriber::on_message(MsgCb msg_callback) { + _msg_callback = msg_callback; +} + +template +void Subscriber::on_pmessage(PMsgCb pmsg_callback) { + _pmsg_callback = pmsg_callback; +} + +template +void Subscriber::on_meta(MetaCb meta_callback) { + _meta_callback = meta_callback; +} + +template +void Subscriber::subscribe(Input first, Input last) { + if (first == last) { + return; + } + + _check_connection(); + + cmd::subscribe_range(_connection, first, last); +} + +template +void Subscriber::unsubscribe(Input first, Input last) { + _check_connection(); + + cmd::unsubscribe_range(_connection, first, last); +} + +template +void Subscriber::psubscribe(Input first, Input last) { + if (first == last) { + return; + } + + _check_connection(); + + cmd::psubscribe_range(_connection, first, last); +} + +template +void Subscriber::punsubscribe(Input first, Input last) { + _check_connection(); + + cmd::punsubscribe_range(_connection, first, last); +} + +} + +} + +#endif // end SEWENEW_REDISPLUSPLUS_SUBSCRIBER_H diff --git a/ext/redis-plus-plus-1.3.3/install/ubuntu22.04/arm64/include/sw/redis++/tls.h b/ext/redis-plus-plus-1.3.3/install/ubuntu22.04/arm64/include/sw/redis++/tls.h new file mode 100644 index 000000000..0f2303db7 --- /dev/null +++ b/ext/redis-plus-plus-1.3.3/install/ubuntu22.04/arm64/include/sw/redis++/tls.h @@ -0,0 +1,47 @@ +/************************************************************************** + Copyright (c) 2020 sewenew + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + *************************************************************************/ + +#ifndef SEWENEW_REDISPLUSPLUS_NO_TLS_H +#define SEWENEW_REDISPLUSPLUS_NO_TLS_H + +#include + +namespace sw { + +namespace redis { + +namespace tls { + +struct TlsOptions {}; + +struct TlsContextUPtr {}; + +inline TlsContextUPtr secure_connection(redisContext &/*ctx*/, const TlsOptions &/*opts*/) { + // Do nothing + return {}; +} + +inline bool enabled(const TlsOptions &/*opts*/) { + return false; +} + +} + +} + +} + +#endif // end SEWENEW_REDISPLUSPLUS_NO_TLS_H diff --git a/ext/redis-plus-plus-1.3.3/install/ubuntu22.04/arm64/include/sw/redis++/transaction.h b/ext/redis-plus-plus-1.3.3/install/ubuntu22.04/arm64/include/sw/redis++/transaction.h new file mode 100644 index 000000000..f19f24889 --- /dev/null +++ b/ext/redis-plus-plus-1.3.3/install/ubuntu22.04/arm64/include/sw/redis++/transaction.h @@ -0,0 +1,77 @@ +/************************************************************************** + Copyright (c) 2017 sewenew + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + *************************************************************************/ + +#ifndef SEWENEW_REDISPLUSPLUS_TRANSACTION_H +#define SEWENEW_REDISPLUSPLUS_TRANSACTION_H + +#include +#include +#include "connection.h" +#include "errors.h" + +namespace sw { + +namespace redis { + +class TransactionImpl { +public: + explicit TransactionImpl(bool piped) : _piped(piped) {} + + template + void command(Connection &connection, Cmd cmd, Args &&...args); + + std::vector exec(Connection &connection, std::size_t cmd_num); + + void discard(Connection &connection, std::size_t cmd_num); + +private: + void _open_transaction(Connection &connection); + + void _close_transaction(); + + void _get_queued_reply(Connection &connection); + + void _get_queued_replies(Connection &connection, std::size_t cmd_num); + + std::vector _exec(Connection &connection); + + void _discard(Connection &connection); + + bool _in_transaction = false; + + bool _piped; +}; + +template +void TransactionImpl::command(Connection &connection, Cmd cmd, Args &&...args) { + assert(!connection.broken()); + + if (!_in_transaction) { + _open_transaction(connection); + } + + cmd(connection, std::forward(args)...); + + if (!_piped) { + _get_queued_reply(connection); + } +} + +} + +} + +#endif // end SEWENEW_REDISPLUSPLUS_TRANSACTION_H diff --git a/ext/redis-plus-plus-1.3.3/install/ubuntu22.04/arm64/include/sw/redis++/utils.h b/ext/redis-plus-plus-1.3.3/install/ubuntu22.04/arm64/include/sw/redis++/utils.h new file mode 100644 index 000000000..f77f796d6 --- /dev/null +++ b/ext/redis-plus-plus-1.3.3/install/ubuntu22.04/arm64/include/sw/redis++/utils.h @@ -0,0 +1,193 @@ +/************************************************************************** + Copyright (c) 2017 sewenew + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + *************************************************************************/ + +#ifndef SEWENEW_REDISPLUSPLUS_UTILS_H +#define SEWENEW_REDISPLUSPLUS_UTILS_H + +#include +#include +#include +#include "cxx_utils.h" + +namespace sw { + +namespace redis { + +using OptionalString = Optional; + +using OptionalLongLong = Optional; + +using OptionalDouble = Optional; + +using OptionalStringPair = Optional>; + +template +struct IsKvPair : std::false_type {}; + +template +struct IsKvPair> : std::true_type {}; + +template +using Void = void; + +template > +struct IsInserter : std::false_type {}; + +template +//struct IsInserter> : std::true_type {}; +struct IsInserter::value>::type> + : std::true_type {}; + +template > +struct IterType { + using type = typename std::iterator_traits::value_type; +}; + +template +//struct IterType> { +struct IterType::value>::type> { + typename std::enable_if::value>::type> { + using type = typename std::decay::type; +}; + +template > +struct IsIter : std::false_type {}; + +template +struct IsIter::value>::type> : std::true_type {}; + +template +//struct IsIter::iterator_category>> +struct IsIter::value_type>::value>::type> + : std::integral_constant::value> {}; + +template +struct IsKvPairIter : IsKvPair::type> {}; + +template +struct TupleWithType : std::false_type {}; + +template +struct TupleWithType> : std::false_type {}; + +template +struct TupleWithType> : TupleWithType> {}; + +template +struct TupleWithType> : std::true_type {}; + +template +struct IndexSequence {}; + +template +struct MakeIndexSequence : MakeIndexSequence {}; + +template +struct MakeIndexSequence<0, Is...> : IndexSequence {}; + +// NthType and NthValue are taken from +// https://stackoverflow.com/questions/14261183 +template +struct NthType {}; + +template +struct NthType<0, Arg, Args...> { + using type = Arg; +}; + +template +struct NthType { + using type = typename NthType::type; +}; + +template +struct LastType { + using type = typename NthType::type; +}; + +struct InvalidLastType {}; + +template <> +struct LastType<> { + using type = InvalidLastType; +}; + +template +auto NthValue(Arg &&arg, Args &&...) + -> typename std::enable_if<(I == 0), decltype(std::forward(arg))>::type { + return std::forward(arg); +} + +template +auto NthValue(Arg &&, Args &&...args) + -> typename std::enable_if<(I > 0), + decltype(std::forward::type>( + std::declval::type>()))>::type { + return std::forward::type>( + NthValue(std::forward(args)...)); +} + +template +auto LastValue(Args &&...args) + -> decltype(std::forward::type>( + std::declval::type>())) { + return std::forward::type>( + NthValue(std::forward(args)...)); +} + +template > +struct HasPushBack : std::false_type {}; + +template +struct HasPushBack().push_back(std::declval()) + )>::value>::type> : std::true_type {}; + +template > +struct HasInsert : std::false_type {}; + +template +struct HasInsert().insert(std::declval(), + std::declval())), + typename T::iterator>::value>::type> : std::true_type {}; + +template +struct IsSequenceContainer + : std::integral_constant::value + && !std::is_same::type, std::string>::value> {}; + +template +struct IsAssociativeContainer + : std::integral_constant::value && !HasPushBack::value> {}; + +uint16_t crc16(const char *buf, int len); + +} + +} + +#endif // end SEWENEW_REDISPLUSPLUS_UTILS_H diff --git a/ext/redis-plus-plus-1.3.3/install/ubuntu22.04/arm64/lib/pkgconfig/redis++.pc b/ext/redis-plus-plus-1.3.3/install/ubuntu22.04/arm64/lib/pkgconfig/redis++.pc new file mode 100644 index 000000000..7bf203b35 --- /dev/null +++ b/ext/redis-plus-plus-1.3.3/install/ubuntu22.04/arm64/lib/pkgconfig/redis++.pc @@ -0,0 +1,12 @@ +prefix=/home/grant/dev/ZeroTierOne/ext/redis-plus-plus-1.3.3/install/ubuntu22.04/arm64 +exec_prefix=${prefix} +libdir=${exec_prefix}/lib +includedir=${prefix}/include + +Name: redis++ +Description: This is a Redis client, based on hiredis and written in C++11. It supports scritpting, pub/sub, pipeline, transaction, Redis Cluster, Redis Sentinel, connection pool, ACL, SSL and thread safety. +Version: 1.3.3 +URL: https://github.com/sewenew/redis-plus-plus +Requires: hiredis +Cflags: -I${includedir} +Libs: -L${libdir} -lredis++ diff --git a/ext/redis-plus-plus-1.3.3/install/ubuntu22.04/arm64/share/cmake/redis++/redis++-config-version.cmake b/ext/redis-plus-plus-1.3.3/install/ubuntu22.04/arm64/share/cmake/redis++/redis++-config-version.cmake new file mode 100644 index 000000000..ef4be219f --- /dev/null +++ b/ext/redis-plus-plus-1.3.3/install/ubuntu22.04/arm64/share/cmake/redis++/redis++-config-version.cmake @@ -0,0 +1,48 @@ +# This is a basic version file for the Config-mode of find_package(). +# It is used by write_basic_package_version_file() as input file for configure_file() +# to create a version-file which can be installed along a config.cmake file. +# +# The created file sets PACKAGE_VERSION_EXACT if the current version string and +# the requested version string are exactly the same and it sets +# PACKAGE_VERSION_COMPATIBLE if the current version is >= requested version. +# The variable CVF_VERSION must be set before calling configure_file(). + +set(PACKAGE_VERSION "1.3.3") + +if (PACKAGE_FIND_VERSION_RANGE) + # Package version must be in the requested version range + if ((PACKAGE_FIND_VERSION_RANGE_MIN STREQUAL "INCLUDE" AND PACKAGE_VERSION VERSION_LESS PACKAGE_FIND_VERSION_MIN) + OR ((PACKAGE_FIND_VERSION_RANGE_MAX STREQUAL "INCLUDE" AND PACKAGE_VERSION VERSION_GREATER PACKAGE_FIND_VERSION_MAX) + OR (PACKAGE_FIND_VERSION_RANGE_MAX STREQUAL "EXCLUDE" AND PACKAGE_VERSION VERSION_GREATER_EQUAL PACKAGE_FIND_VERSION_MAX))) + set(PACKAGE_VERSION_COMPATIBLE FALSE) + else() + set(PACKAGE_VERSION_COMPATIBLE TRUE) + endif() +else() + if(PACKAGE_VERSION VERSION_LESS PACKAGE_FIND_VERSION) + set(PACKAGE_VERSION_COMPATIBLE FALSE) + else() + set(PACKAGE_VERSION_COMPATIBLE TRUE) + if(PACKAGE_FIND_VERSION STREQUAL PACKAGE_VERSION) + set(PACKAGE_VERSION_EXACT TRUE) + endif() + endif() +endif() + + +# if the installed project requested no architecture check, don't perform the check +if("FALSE") + return() +endif() + +# if the installed or the using project don't have CMAKE_SIZEOF_VOID_P set, ignore it: +if("${CMAKE_SIZEOF_VOID_P}" STREQUAL "" OR "8" STREQUAL "") + return() +endif() + +# check that the installed version has the same 32/64bit-ness as the one which is currently searching: +if(NOT CMAKE_SIZEOF_VOID_P STREQUAL "8") + math(EXPR installedBits "8 * 8") + set(PACKAGE_VERSION "${PACKAGE_VERSION} (${installedBits}bit)") + set(PACKAGE_VERSION_UNSUITABLE TRUE) +endif() diff --git a/ext/redis-plus-plus-1.3.3/install/ubuntu22.04/arm64/share/cmake/redis++/redis++-config.cmake b/ext/redis-plus-plus-1.3.3/install/ubuntu22.04/arm64/share/cmake/redis++/redis++-config.cmake new file mode 100644 index 000000000..580d98613 --- /dev/null +++ b/ext/redis-plus-plus-1.3.3/install/ubuntu22.04/arm64/share/cmake/redis++/redis++-config.cmake @@ -0,0 +1,36 @@ + +####### Expanded from @PACKAGE_INIT@ by configure_package_config_file() ####### +####### Any changes to this file will be overwritten by the next CMake run #### +####### The input file was redis++-config.cmake.in ######## + +get_filename_component(PACKAGE_PREFIX_DIR "${CMAKE_CURRENT_LIST_DIR}/../../../" ABSOLUTE) + +macro(set_and_check _var _file) + set(${_var} "${_file}") + if(NOT EXISTS "${_file}") + message(FATAL_ERROR "File or directory ${_file} referenced by variable ${_var} does not exist !") + endif() +endmacro() + +macro(check_required_components _NAME) + foreach(comp ${${_NAME}_FIND_COMPONENTS}) + if(NOT ${_NAME}_${comp}_FOUND) + if(${_NAME}_FIND_REQUIRED_${comp}) + set(${_NAME}_FOUND FALSE) + endif() + endif() + endforeach() +endmacro() + +#################################################################################### + +include(CMakeFindDependencyMacro) + +string(REPLACE "," ";" REDIS_PLUS_PLUS_DEPENDS_LIST hiredis) +foreach(REDIS_PLUS_PLUS_DEP ${REDIS_PLUS_PLUS_DEPENDS_LIST}) + find_dependency(${REDIS_PLUS_PLUS_DEP} REQUIRED) +endforeach() + +include("${CMAKE_CURRENT_LIST_DIR}/redis++-targets.cmake") + +check_required_components(redis++) diff --git a/ext/redis-plus-plus-1.3.3/install/ubuntu22.04/arm64/share/cmake/redis++/redis++-targets-release.cmake b/ext/redis-plus-plus-1.3.3/install/ubuntu22.04/arm64/share/cmake/redis++/redis++-targets-release.cmake new file mode 100644 index 000000000..b790b539f --- /dev/null +++ b/ext/redis-plus-plus-1.3.3/install/ubuntu22.04/arm64/share/cmake/redis++/redis++-targets-release.cmake @@ -0,0 +1,19 @@ +#---------------------------------------------------------------- +# Generated CMake target import file for configuration "Release". +#---------------------------------------------------------------- + +# Commands may need to know the format version. +set(CMAKE_IMPORT_FILE_VERSION 1) + +# Import target "redis++::redis++_static" for configuration "Release" +set_property(TARGET redis++::redis++_static APPEND PROPERTY IMPORTED_CONFIGURATIONS RELEASE) +set_target_properties(redis++::redis++_static PROPERTIES + IMPORTED_LINK_INTERFACE_LANGUAGES_RELEASE "CXX" + IMPORTED_LOCATION_RELEASE "${_IMPORT_PREFIX}/lib/libredis++.a" + ) + +list(APPEND _IMPORT_CHECK_TARGETS redis++::redis++_static ) +list(APPEND _IMPORT_CHECK_FILES_FOR_redis++::redis++_static "${_IMPORT_PREFIX}/lib/libredis++.a" ) + +# Commands beyond this point should not need to know the version. +set(CMAKE_IMPORT_FILE_VERSION) diff --git a/ext/redis-plus-plus-1.3.3/install/ubuntu22.04/arm64/share/cmake/redis++/redis++-targets.cmake b/ext/redis-plus-plus-1.3.3/install/ubuntu22.04/arm64/share/cmake/redis++/redis++-targets.cmake new file mode 100644 index 000000000..9e87d927e --- /dev/null +++ b/ext/redis-plus-plus-1.3.3/install/ubuntu22.04/arm64/share/cmake/redis++/redis++-targets.cmake @@ -0,0 +1,94 @@ +# Generated by CMake + +if("${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION}" LESS 2.6) + message(FATAL_ERROR "CMake >= 2.6.0 required") +endif() +cmake_policy(PUSH) +cmake_policy(VERSION 2.6...3.20) +#---------------------------------------------------------------- +# Generated CMake target import file. +#---------------------------------------------------------------- + +# Commands may need to know the format version. +set(CMAKE_IMPORT_FILE_VERSION 1) + +# Protect against multiple inclusion, which would fail when already imported targets are added once more. +set(_targetsDefined) +set(_targetsNotDefined) +set(_expectedTargets) +foreach(_expectedTarget redis++::redis++_static) + list(APPEND _expectedTargets ${_expectedTarget}) + if(NOT TARGET ${_expectedTarget}) + list(APPEND _targetsNotDefined ${_expectedTarget}) + endif() + if(TARGET ${_expectedTarget}) + list(APPEND _targetsDefined ${_expectedTarget}) + endif() +endforeach() +if("${_targetsDefined}" STREQUAL "${_expectedTargets}") + unset(_targetsDefined) + unset(_targetsNotDefined) + unset(_expectedTargets) + set(CMAKE_IMPORT_FILE_VERSION) + cmake_policy(POP) + return() +endif() +if(NOT "${_targetsDefined}" STREQUAL "") + message(FATAL_ERROR "Some (but not all) targets in this export set were already defined.\nTargets Defined: ${_targetsDefined}\nTargets not yet defined: ${_targetsNotDefined}\n") +endif() +unset(_targetsDefined) +unset(_targetsNotDefined) +unset(_expectedTargets) + + +# Compute the installation prefix relative to this file. +get_filename_component(_IMPORT_PREFIX "${CMAKE_CURRENT_LIST_FILE}" PATH) +get_filename_component(_IMPORT_PREFIX "${_IMPORT_PREFIX}" PATH) +get_filename_component(_IMPORT_PREFIX "${_IMPORT_PREFIX}" PATH) +get_filename_component(_IMPORT_PREFIX "${_IMPORT_PREFIX}" PATH) +if(_IMPORT_PREFIX STREQUAL "/") + set(_IMPORT_PREFIX "") +endif() + +# Create imported target redis++::redis++_static +add_library(redis++::redis++_static STATIC IMPORTED) + +set_target_properties(redis++::redis++_static PROPERTIES + INTERFACE_INCLUDE_DIRECTORIES "${_IMPORT_PREFIX}/include;${_IMPORT_PREFIX}/include" +) + +# Load information for each installed configuration. +get_filename_component(_DIR "${CMAKE_CURRENT_LIST_FILE}" PATH) +file(GLOB CONFIG_FILES "${_DIR}/redis++-targets-*.cmake") +foreach(f ${CONFIG_FILES}) + include(${f}) +endforeach() + +# Cleanup temporary variables. +set(_IMPORT_PREFIX) + +# Loop over all imported files and verify that they actually exist +foreach(target ${_IMPORT_CHECK_TARGETS} ) + foreach(file ${_IMPORT_CHECK_FILES_FOR_${target}} ) + if(NOT EXISTS "${file}" ) + message(FATAL_ERROR "The imported target \"${target}\" references the file + \"${file}\" +but this file does not exist. Possible reasons include: +* The file was deleted, renamed, or moved to another location. +* An install or uninstall procedure did not complete successfully. +* The installation package was faulty and contained + \"${CMAKE_CURRENT_LIST_FILE}\" +but not all the files it references. +") + endif() + endforeach() + unset(_IMPORT_CHECK_FILES_FOR_${target}) +endforeach() +unset(_IMPORT_CHECK_TARGETS) + +# This file does not depend on other imported targets which have +# been exported from the same project but in a separate export set. + +# Commands beyond this point should not need to know the version. +set(CMAKE_IMPORT_FILE_VERSION) +cmake_policy(POP) diff --git a/ext/redis-plus-plus-1.3.3/install/ubuntu22.04/lib/libredis++.a b/ext/redis-plus-plus-1.3.3/install/ubuntu22.04/lib/libredis++.a deleted file mode 100644 index 3f398e48dfda90206cd0ad95d4f11faba86c2aba..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1399538 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≷@IH$jl!8v}3!8!h4GdRcp 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

pt#FMSW-Opnc85;*t5@T7(hHmGOLjW9Hx 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Π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

IgA1ytTN=Ik3x^A1?fiDK=l1!atXy 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
HAuXrkj=~-Nr0(#cB!khj&zuzXzsuo|d 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 fDeYj#Umy?Ae97xSy!-Rx-w9(WodD;m