Commit 3b431e0e10c632ccd2aea1b82183531bea524ef1
1 parent
a2138a65
Add set and unordered_set reply type templates
Useful based on what kind of data you need.
Showing
4 changed files
with
112 additions
and
32 deletions
examples/data_types.cpp
| 1 | /** | 1 | /** |
| 2 | -* Basic use of Redox to set and get a Redis key. | 2 | +* Test special data type templates for multi-element replies using Redox. |
| 3 | */ | 3 | */ |
| 4 | 4 | ||
| 5 | #include <iostream> | 5 | #include <iostream> |
| 6 | #include "../src/redox.hpp" | 6 | #include "../src/redox.hpp" |
| 7 | +#include <set> | ||
| 8 | +#include <unordered_set> | ||
| 9 | +#include <vector> | ||
| 7 | 10 | ||
| 8 | using namespace std; | 11 | using namespace std; |
| 9 | 12 | ||
| @@ -16,15 +19,40 @@ int main(int argc, char* argv[]) { | @@ -16,15 +19,40 @@ int main(int argc, char* argv[]) { | ||
| 16 | 19 | ||
| 17 | rdx.command_blocking("LPUSH mylist 1 2 3 4 5 6 7 8 9 10"); | 20 | rdx.command_blocking("LPUSH mylist 1 2 3 4 5 6 7 8 9 10"); |
| 18 | 21 | ||
| 19 | - auto c = rdx.command_blocking<vector<string>>("LRANGE mylist -3 -1"); | ||
| 20 | - if(!c->ok()) cerr << "Error with LRANGE: " << c->status() << endl; | ||
| 21 | - for(const string& s : c->reply()) cout << s << endl; | ||
| 22 | - c->free(); | ||
| 23 | - | ||
| 24 | -// if(!rdx.set("apples", "are great!")) // Set a key, check if succeeded | ||
| 25 | -// cerr << "Failed to set key!" << endl; | ||
| 26 | -// | ||
| 27 | -// cout << "key = alaska, value = \"" << rdx.get("apples") << "\"" << endl; | ||
| 28 | - | ||
| 29 | - rdx.stop(); // Shut down the event loop | 22 | + rdx.command<vector<string>>("LRANGE mylist 0 4", |
| 23 | + [](const string& cmd, const vector<string>& reply){ | ||
| 24 | + cout << "Last 5 elements as a vector: "; | ||
| 25 | + for(const string& s : reply) cout << s << " "; | ||
| 26 | + cout << endl; | ||
| 27 | + }, | ||
| 28 | + [](const string& cmd, int status) { | ||
| 29 | + cerr << "Error with LRANGE: " << status << endl; | ||
| 30 | + } | ||
| 31 | + ); | ||
| 32 | + | ||
| 33 | + rdx.command<unordered_set<string>>("LRANGE mylist 0 4", | ||
| 34 | + [](const string& cmd, const unordered_set<string>& reply){ | ||
| 35 | + cout << "Last 5 elements as an unordered set: "; | ||
| 36 | + for(const string& s : reply) cout << s << " "; | ||
| 37 | + cout << endl; | ||
| 38 | + }, | ||
| 39 | + [](const string& cmd, int status) { | ||
| 40 | + cerr << "Error with LRANGE: " << status << endl; | ||
| 41 | + } | ||
| 42 | + ); | ||
| 43 | + | ||
| 44 | + rdx.command<set<string>>("LRANGE mylist 0 4", | ||
| 45 | + [&rdx](const string& cmd, const set<string>& reply){ | ||
| 46 | + cout << "Last 5 elements as a set: "; | ||
| 47 | + for(const string& s : reply) cout << s << " "; | ||
| 48 | + cout << endl; | ||
| 49 | + rdx.stop_signal(); | ||
| 50 | + }, | ||
| 51 | + [&rdx](const string& cmd, int status) { | ||
| 52 | + cerr << "Error with LRANGE: " << status << endl; | ||
| 53 | + rdx.stop_signal(); | ||
| 54 | + } | ||
| 55 | + ); | ||
| 56 | + | ||
| 57 | + rdx.block(); // Shut down the event loop | ||
| 30 | } | 58 | } |
src/command.cpp
| @@ -3,7 +3,8 @@ | @@ -3,7 +3,8 @@ | ||
| 3 | */ | 3 | */ |
| 4 | 4 | ||
| 5 | #include <vector> | 5 | #include <vector> |
| 6 | -#include <assert.h> | 6 | +#include <set> |
| 7 | +#include <unordered_set> | ||
| 7 | 8 | ||
| 8 | #include "command.hpp" | 9 | #include "command.hpp" |
| 9 | 10 | ||
| @@ -134,4 +135,52 @@ void Command<std::vector<std::string>>::invoke_callback() { | @@ -134,4 +135,52 @@ void Command<std::vector<std::string>>::invoke_callback() { | ||
| 134 | } | 135 | } |
| 135 | } | 136 | } |
| 136 | 137 | ||
| 138 | +template<> | ||
| 139 | +void Command<std::unordered_set<std::string>>::invoke_callback() { | ||
| 140 | + | ||
| 141 | + if(is_error_reply()) invoke_error(REDOX_ERROR_REPLY); | ||
| 142 | + | ||
| 143 | + else if(reply_obj->type != REDIS_REPLY_ARRAY) { | ||
| 144 | + std::cerr << "[ERROR] " << cmd << ": Received non-array reply." << std::endl; | ||
| 145 | + invoke_error(REDOX_WRONG_TYPE); | ||
| 146 | + | ||
| 147 | + } else { | ||
| 148 | + std::unordered_set<std::string> v; | ||
| 149 | + size_t count = reply_obj->elements; | ||
| 150 | + for(size_t i = 0; i < count; i++) { | ||
| 151 | + redisReply* r = *(reply_obj->element + i); | ||
| 152 | + if(r->type != REDIS_REPLY_STRING) { | ||
| 153 | + std::cerr << "[ERROR] " << cmd << ": Received non-array reply." << std::endl; | ||
| 154 | + invoke_error(REDOX_WRONG_TYPE); | ||
| 155 | + } | ||
| 156 | + v.insert(r->str); | ||
| 157 | + } | ||
| 158 | + invoke(v); | ||
| 159 | + } | ||
| 160 | +} | ||
| 161 | + | ||
| 162 | +template<> | ||
| 163 | +void Command<std::set<std::string>>::invoke_callback() { | ||
| 164 | + | ||
| 165 | + if(is_error_reply()) invoke_error(REDOX_ERROR_REPLY); | ||
| 166 | + | ||
| 167 | + else if(reply_obj->type != REDIS_REPLY_ARRAY) { | ||
| 168 | + std::cerr << "[ERROR] " << cmd << ": Received non-array reply." << std::endl; | ||
| 169 | + invoke_error(REDOX_WRONG_TYPE); | ||
| 170 | + | ||
| 171 | + } else { | ||
| 172 | + std::set<std::string> v; | ||
| 173 | + size_t count = reply_obj->elements; | ||
| 174 | + for(size_t i = 0; i < count; i++) { | ||
| 175 | + redisReply* r = *(reply_obj->element + i); | ||
| 176 | + if(r->type != REDIS_REPLY_STRING) { | ||
| 177 | + std::cerr << "[ERROR] " << cmd << ": Received non-array reply." << std::endl; | ||
| 178 | + invoke_error(REDOX_WRONG_TYPE); | ||
| 179 | + } | ||
| 180 | + v.insert(r->str); | ||
| 181 | + } | ||
| 182 | + invoke(v); | ||
| 183 | + } | ||
| 184 | +} | ||
| 185 | + | ||
| 137 | } // End namespace redox | 186 | } // End namespace redox |
src/redox.cpp
| @@ -308,42 +308,36 @@ void Redox::process_queued_commands(struct ev_loop* loop, ev_async* async, int r | @@ -308,42 +308,36 @@ void Redox::process_queued_commands(struct ev_loop* loop, ev_async* async, int r | ||
| 308 | rdx->command_queue.pop(); | 308 | rdx->command_queue.pop(); |
| 309 | 309 | ||
| 310 | if(rdx->process_queued_command<redisReply*>(id)) {} | 310 | if(rdx->process_queued_command<redisReply*>(id)) {} |
| 311 | - else if(rdx->process_queued_command<string>(id)) {} | 311 | + else if(rdx->process_queued_command<std::string>(id)) {} |
| 312 | else if(rdx->process_queued_command<char*>(id)) {} | 312 | else if(rdx->process_queued_command<char*>(id)) {} |
| 313 | else if(rdx->process_queued_command<int>(id)) {} | 313 | else if(rdx->process_queued_command<int>(id)) {} |
| 314 | else if(rdx->process_queued_command<long long int>(id)) {} | 314 | else if(rdx->process_queued_command<long long int>(id)) {} |
| 315 | - else if(rdx->process_queued_command<nullptr_t>(id)) {} | ||
| 316 | - else if(rdx->process_queued_command<vector<string>>(id)) {} | 315 | + else if(rdx->process_queued_command<std::nullptr_t>(id)) {} |
| 316 | + else if(rdx->process_queued_command<std::vector<std::string>>(id)) {} | ||
| 317 | + else if(rdx->process_queued_command<std::set<std::string>>(id)) {} | ||
| 318 | + else if(rdx->process_queued_command<std::unordered_set<std::string>>(id)) {} | ||
| 317 | else throw runtime_error("[FATAL] Command pointer not found in any queue!"); | 319 | else throw runtime_error("[FATAL] Command pointer not found in any queue!"); |
| 318 | } | 320 | } |
| 319 | } | 321 | } |
| 320 | 322 | ||
| 321 | -// ---------------------------- | 323 | +// --------------------------------- |
| 324 | +// get_command_map specializations | ||
| 325 | +// --------------------------------- | ||
| 322 | 326 | ||
| 323 | template<> unordered_map<long, Command<redisReply*>*>& | 327 | template<> unordered_map<long, Command<redisReply*>*>& |
| 324 | -Redox::get_command_map<redisReply*>() { | ||
| 325 | -// cout << "redis reply command map at " << &commands_redis_reply << endl; | ||
| 326 | - return commands_redis_reply; } | 328 | +Redox::get_command_map<redisReply*>() { return commands_redis_reply; } |
| 327 | 329 | ||
| 328 | template<> unordered_map<long, Command<string>*>& | 330 | template<> unordered_map<long, Command<string>*>& |
| 329 | -Redox::get_command_map<string>() { | ||
| 330 | -// cout << "string command map at " << &commands_string_r << endl; | ||
| 331 | - return commands_string_r; } | 331 | +Redox::get_command_map<string>() { return commands_string_r; } |
| 332 | 332 | ||
| 333 | template<> unordered_map<long, Command<char*>*>& | 333 | template<> unordered_map<long, Command<char*>*>& |
| 334 | -Redox::get_command_map<char*>() { | ||
| 335 | -// cout << "char* command map at " << &commands_char_p << endl; | ||
| 336 | - return commands_char_p; } | 334 | +Redox::get_command_map<char*>() { return commands_char_p; } |
| 337 | 335 | ||
| 338 | template<> unordered_map<long, Command<int>*>& | 336 | template<> unordered_map<long, Command<int>*>& |
| 339 | -Redox::get_command_map<int>() { | ||
| 340 | -// cout << "int command map at " << &commands_int << " has size: " << commands_int.size() << endl; | ||
| 341 | - return commands_int; } | 337 | +Redox::get_command_map<int>() { return commands_int; } |
| 342 | 338 | ||
| 343 | template<> unordered_map<long, Command<long long int>*>& | 339 | template<> unordered_map<long, Command<long long int>*>& |
| 344 | -Redox::get_command_map<long long int>() { | ||
| 345 | -// cout << "long long int command map at " << &commands_long_long_int << endl; | ||
| 346 | - return commands_long_long_int; } | 340 | +Redox::get_command_map<long long int>() { return commands_long_long_int; } |
| 347 | 341 | ||
| 348 | template<> unordered_map<long, Command<nullptr_t>*>& | 342 | template<> unordered_map<long, Command<nullptr_t>*>& |
| 349 | Redox::get_command_map<nullptr_t>() { return commands_null; } | 343 | Redox::get_command_map<nullptr_t>() { return commands_null; } |
| @@ -351,6 +345,12 @@ Redox::get_command_map<nullptr_t>() { return commands_null; } | @@ -351,6 +345,12 @@ Redox::get_command_map<nullptr_t>() { return commands_null; } | ||
| 351 | template<> unordered_map<long, Command<vector<string>>*>& | 345 | template<> unordered_map<long, Command<vector<string>>*>& |
| 352 | Redox::get_command_map<vector<string>>() { return commands_vector_string; } | 346 | Redox::get_command_map<vector<string>>() { return commands_vector_string; } |
| 353 | 347 | ||
| 348 | +template<> unordered_map<long, Command<set<string>>*>& | ||
| 349 | +Redox::get_command_map<set<string>>() { return commands_set_string; } | ||
| 350 | + | ||
| 351 | +template<> unordered_map<long, Command<unordered_set<string>>*>& | ||
| 352 | +Redox::get_command_map<unordered_set<string>>() { return commands_unordered_set_string; } | ||
| 353 | + | ||
| 354 | // ---------------------------- | 354 | // ---------------------------- |
| 355 | // Helpers | 355 | // Helpers |
| 356 | // ---------------------------- | 356 | // ---------------------------- |
src/redox.hpp
| @@ -14,6 +14,7 @@ | @@ -14,6 +14,7 @@ | ||
| 14 | 14 | ||
| 15 | #include <string> | 15 | #include <string> |
| 16 | #include <queue> | 16 | #include <queue> |
| 17 | +#include <set> | ||
| 17 | #include <unordered_map> | 18 | #include <unordered_map> |
| 18 | #include <unordered_set> | 19 | #include <unordered_set> |
| 19 | 20 | ||
| @@ -235,6 +236,8 @@ private: | @@ -235,6 +236,8 @@ private: | ||
| 235 | std::unordered_map<long, Command<long long int>*> commands_long_long_int; | 236 | std::unordered_map<long, Command<long long int>*> commands_long_long_int; |
| 236 | std::unordered_map<long, Command<std::nullptr_t>*> commands_null; | 237 | std::unordered_map<long, Command<std::nullptr_t>*> commands_null; |
| 237 | std::unordered_map<long, Command<std::vector<std::string>>*> commands_vector_string; | 238 | std::unordered_map<long, Command<std::vector<std::string>>*> commands_vector_string; |
| 239 | + std::unordered_map<long, Command<std::set<std::string>>*> commands_set_string; | ||
| 240 | + std::unordered_map<long, Command<std::unordered_set<std::string>>*> commands_unordered_set_string; | ||
| 238 | std::mutex command_map_guard; // Guards access to all of the above | 241 | std::mutex command_map_guard; // Guards access to all of the above |
| 239 | 242 | ||
| 240 | // Return the correct map from the above, based on the template specialization | 243 | // Return the correct map from the above, based on the template specialization |