diff --git a/src/command_helpers.h b/src/command_helpers.h index d7668d09..47da30f4 100644 --- a/src/command_helpers.h +++ b/src/command_helpers.h @@ -37,7 +37,7 @@ #ifndef RTORRENT_UTILS_COMMAND_HELPERS_H #define RTORRENT_UTILS_COMMAND_HELPERS_H -#include "rpc/command_new_slot.h" +#include "rpc/command.h" #include "rpc/parse_commands.h" #include "rpc/object_storage.h" diff --git a/src/command_local.cc b/src/command_local.cc index 3b656e16..e8763808 100644 --- a/src/command_local.cc +++ b/src/command_local.cc @@ -249,14 +249,14 @@ initialize_command_local() { CMD2_ANY_STRING_V("log.xmlrpc", std::tr1::bind(&ThreadWorker::set_xmlrpc_log, worker_thread, std::tr1::placeholders::_2)); // TODO: Convert to new command types: - *rpc::Command::argument(0) = "placeholder.0"; - *rpc::Command::argument(1) = "placeholder.1"; - *rpc::Command::argument(2) = "placeholder.2"; - *rpc::Command::argument(3) = "placeholder.3"; - CMD2_ANY_P("argument.0", std::tr1::bind(&rpc::Command::argument_ref, 0)); - CMD2_ANY_P("argument.1", std::tr1::bind(&rpc::Command::argument_ref, 1)); - CMD2_ANY_P("argument.2", std::tr1::bind(&rpc::Command::argument_ref, 2)); - CMD2_ANY_P("argument.3", std::tr1::bind(&rpc::Command::argument_ref, 3)); + *rpc::command_base::argument(0) = "placeholder.0"; + *rpc::command_base::argument(1) = "placeholder.1"; + *rpc::command_base::argument(2) = "placeholder.2"; + *rpc::command_base::argument(3) = "placeholder.3"; + CMD2_ANY_P("argument.0", std::tr1::bind(&rpc::command_base::argument_ref, 0)); + CMD2_ANY_P("argument.1", std::tr1::bind(&rpc::command_base::argument_ref, 1)); + CMD2_ANY_P("argument.2", std::tr1::bind(&rpc::command_base::argument_ref, 2)); + CMD2_ANY_P("argument.3", std::tr1::bind(&rpc::command_base::argument_ref, 3)); CMD2_ANY_LIST ("group.insert", std::tr1::bind(&group_insert, std::tr1::placeholders::_2)); } diff --git a/src/command_network.cc b/src/command_network.cc index d429e2c8..ef046df4 100644 --- a/src/command_network.cc +++ b/src/command_network.cc @@ -204,7 +204,7 @@ apply_encryption(const torrent::Object::list_type& args) { torrent::Object apply_tos(const torrent::Object::string_type& arg) { - rpc::Command::value_type value; + rpc::command_base::value_type value; torrent::ConnectionManager* cm = torrent::connection_manager(); if (arg == "default") diff --git a/src/rpc/Makefile.am b/src/rpc/Makefile.am index 687ae8cd..60ebd5d0 100644 --- a/src/rpc/Makefile.am +++ b/src/rpc/Makefile.am @@ -2,6 +2,7 @@ noinst_LIBRARIES = libsub_rpc.a libsub_rpc_a_SOURCES = \ command.h \ + command.cc \ command_impl.h \ command_map.cc \ command_map.h \ @@ -9,8 +10,6 @@ libsub_rpc_a_SOURCES = \ command_scheduler.h \ command_scheduler_item.cc \ command_scheduler_item.h \ - command_new_slot.cc \ - command_new_slot.h \ exec_file.cc \ exec_file.h \ fixed_key.h \ diff --git a/src/rpc/command_new_slot.cc b/src/rpc/command.cc similarity index 75% rename from src/rpc/command_new_slot.cc rename to src/rpc/command.cc index 19d752b0..09940e64 100644 --- a/src/rpc/command_new_slot.cc +++ b/src/rpc/command.cc @@ -39,20 +39,20 @@ #include "core/download.h" #include "parse.h" -#include "command_new_slot.h" +#include "command.h" #define COMMAND_BASE_TEMPLATE_DEFINE(func_name) \ -template const torrent::Object func_name(Command* rawCommand, target_type target, const torrent::Object& args); \ -template const torrent::Object func_name(Command* rawCommand, target_type target, const torrent::Object& args); \ -template const torrent::Object func_name(Command* rawCommand, target_type target, const torrent::Object& args); \ -template const torrent::Object func_name(Command* rawCommand, target_type target, const torrent::Object& args); \ -template const torrent::Object func_name(Command* rawCommand, target_type target, const torrent::Object& args); \ -template const torrent::Object func_name(Command* rawCommand, target_type target, const torrent::Object& args); +template const torrent::Object func_name(command_base* rawCommand, target_type target, const torrent::Object& args); \ +template const torrent::Object func_name(command_base* rawCommand, target_type target, const torrent::Object& args); \ +template const torrent::Object func_name(command_base* rawCommand, target_type target, const torrent::Object& args); \ +template const torrent::Object func_name(command_base* rawCommand, target_type target, const torrent::Object& args); \ +template const torrent::Object func_name(command_base* rawCommand, target_type target, const torrent::Object& args); \ +template const torrent::Object func_name(command_base* rawCommand, target_type target, const torrent::Object& args); namespace rpc { template const torrent::Object -command_base_call(Command* rawCommand, target_type target, const torrent::Object& args) { +command_base_call(command_base* rawCommand, target_type target, const torrent::Object& args) { if (!is_target_compatible(target)) throw torrent::input_error("Target of wrong type."); @@ -62,7 +62,7 @@ command_base_call(Command* rawCommand, target_type target, const torrent::Object COMMAND_BASE_TEMPLATE_DEFINE(command_base_call); template const torrent::Object -command_base_call_value_base(Command* rawCommand, target_type target, const torrent::Object& rawArgs, int base, int unit) { +command_base_call_value_base(command_base* rawCommand, target_type target, const torrent::Object& rawArgs, int base, int unit) { if (!is_target_compatible(target)) throw torrent::input_error("Target of wrong type."); @@ -81,12 +81,12 @@ command_base_call_value_base(Command* rawCommand, target_type target, const torr } template const torrent::Object -command_base_call_value(Command* rawCommand, target_type target, const torrent::Object& rawArgs) { +command_base_call_value(command_base* rawCommand, target_type target, const torrent::Object& rawArgs) { return command_base_call_value_base(rawCommand, target, rawArgs, 0, 1); } template const torrent::Object -command_base_call_value_kb(Command* rawCommand, target_type target, const torrent::Object& rawArgs) { +command_base_call_value_kb(command_base* rawCommand, target_type target, const torrent::Object& rawArgs) { return command_base_call_value_base(rawCommand, target, rawArgs, 0, 1024); } @@ -94,7 +94,7 @@ COMMAND_BASE_TEMPLATE_DEFINE(command_base_call_value); COMMAND_BASE_TEMPLATE_DEFINE(command_base_call_value_kb); template const torrent::Object -command_base_call_string(Command* rawCommand, target_type target, const torrent::Object& rawArgs) { +command_base_call_string(command_base* rawCommand, target_type target, const torrent::Object& rawArgs) { if (!is_target_compatible(target)) throw torrent::input_error("Target of wrong type."); @@ -109,7 +109,7 @@ command_base_call_string(Command* rawCommand, target_type target, const torrent: COMMAND_BASE_TEMPLATE_DEFINE(command_base_call_string); template const torrent::Object -command_base_call_list(Command* rawCommand, target_type target, const torrent::Object& rawArgs) { +command_base_call_list(command_base* rawCommand, target_type target, const torrent::Object& rawArgs) { if (!is_target_compatible(target)) throw torrent::input_error("Target of wrong type."); diff --git a/src/rpc/command.h b/src/rpc/command.h index 9746b0ce..126564ee 100644 --- a/src/rpc/command.h +++ b/src/rpc/command.h @@ -37,6 +37,12 @@ #ifndef RTORRENT_RPC_COMMAND_H #define RTORRENT_RPC_COMMAND_H +#include +#include +#include +#include +#include + #include #include @@ -99,7 +105,15 @@ struct rt_triple : private std::pair { //typedef std::pair target_type; typedef rt_triple target_type; -class Command { +class command_base; + +typedef const torrent::Object (*command_base_call_type)(command_base*, target_type, const torrent::Object&); +typedef std::tr1::function base_function; + +template struct command_base_is_valid {}; +template struct command_base_is_type {}; + +class command_base { public: typedef torrent::Object::value_type value_type; typedef torrent::Object::string_type string_type; @@ -107,16 +121,16 @@ public: typedef torrent::Object::map_type map_type; typedef torrent::Object::key_type key_type; - typedef const torrent::Object (*generic_slot) (Command*, const torrent::Object&); - typedef const torrent::Object (*cleaned_slot) (Command*, target_wrapper::cleaned_type, const torrent::Object&); - typedef const torrent::Object (*any_slot) (Command*, target_type, const torrent::Object&); - typedef const torrent::Object (*download_slot) (Command*, core::Download*, const torrent::Object&); - typedef const torrent::Object (*file_slot) (Command*, torrent::File*, const torrent::Object&); - typedef const torrent::Object (*file_itr_slot) (Command*, torrent::FileListIterator*, const torrent::Object&); - typedef const torrent::Object (*peer_slot) (Command*, torrent::Peer*, const torrent::Object&); - typedef const torrent::Object (*tracker_slot) (Command*, torrent::Tracker*, const torrent::Object&); + typedef const torrent::Object (*generic_slot) (command_base*, const torrent::Object&); + typedef const torrent::Object (*cleaned_slot) (command_base*, target_wrapper::cleaned_type, const torrent::Object&); + typedef const torrent::Object (*any_slot) (command_base*, target_type, const torrent::Object&); + typedef const torrent::Object (*download_slot) (command_base*, core::Download*, const torrent::Object&); + typedef const torrent::Object (*file_slot) (command_base*, torrent::File*, const torrent::Object&); + typedef const torrent::Object (*file_itr_slot) (command_base*, torrent::FileListIterator*, const torrent::Object&); + typedef const torrent::Object (*peer_slot) (command_base*, torrent::Peer*, const torrent::Object&); + typedef const torrent::Object (*tracker_slot) (command_base*, torrent::Tracker*, const torrent::Object&); - typedef const torrent::Object (*download_pair_slot) (Command*, core::Download*, core::Download*, const torrent::Object&); + typedef const torrent::Object (*download_pair_slot) (command_base*, core::Download*, core::Download*, const torrent::Object&); static const int target_generic = 0; static const int target_any = 1; @@ -145,8 +159,8 @@ public: char buffer[sizeof(torrent::Object) * max_arguments]; }; - Command() {} - virtual ~Command() {} + command_base() { new (&_pod()) base_function(); } + virtual ~command_base() { _pod().~base_function(); } static torrent::Object* argument(unsigned int index) { return current_stack.begin() + index; } static torrent::Object& argument_ref(unsigned int index) { return *(current_stack.begin() + index); } @@ -160,13 +174,35 @@ public: static torrent::Object* push_stack(const torrent::Object* first_arg, const torrent::Object* last_arg, stack_type* stack); static void pop_stack(stack_type* stack, torrent::Object* last_stack); + template + void set_function(T s, int value = command_base_is_valid::value) { _pod() = s; } + + template + void set_function_2(typename command_base_is_type::type s, int value = command_base_is_valid::type>::value) { + _pod::type>() = s; + } + + // The std::function object in GCC is castable between types with a + // pointer to a struct of ctor/dtor/calls for non-POD slots. As such + // it should be safe to cast between different std::function + // template types, yet what the C++0x standard will say about this I + // have no idea atm. + template tmpl& _pod() { return reinterpret_cast(t_pod); } + + template + static const torrent::Object _call(command_base* cmd, target_type target, Args args); + protected: - Command(const Command&); - void operator = (const Command&); + command_base(const command_base&); + void operator = (const command_base&); // For use by functions that need to use placeholders to arguments // within commands. E.d. callable command strings where one of the // arguments within the command needs to be supplied by the caller. + + union { + char t_pod[sizeof(base_function)]; + }; }; template @@ -178,7 +214,7 @@ template inline bool is_target_compatible(const target_type& target) { return target.first == target_type_id::value; } // Splitting pairs into separate targets. -inline bool is_target_pair(const target_type& target) { return target.first >= Command::target_download_pair; } +inline bool is_target_pair(const target_type& target) { return target.first >= command_base::target_download_pair; } template inline T get_target_cast(target_type target, int type = target_type_id::value) { return (T)target.second; } @@ -190,4 +226,47 @@ inline target_type get_target_right(const target_type& target) { return target_t #include "command_impl.h" +namespace rpc { + +template +inline const torrent::Object +command_base::_call(command_base* cmd, target_type target, Args args) { + return static_cast(cmd)->_pod()(get_target_cast(target), args); +} + +#define COMMAND_BASE_TEMPLATE_TYPE(func_type, func_parm) \ + template ::proper_type> struct func_type { typedef std::tr1::function type; }; \ + \ + template <> struct command_base_is_valid::type> { static const int value = 1; }; \ + template <> struct command_base_is_valid::type> { static const int value = 1; }; \ + template <> struct command_base_is_valid::type> { static const int value = 1; }; \ + template <> struct command_base_is_valid::type> { static const int value = 1; }; \ + template <> struct command_base_is_valid::type> { static const int value = 1; }; \ + template <> struct command_base_is_valid::type> { static const int value = 1; }; + +// template struct command_base_is_valid::type > { static const int value = 1; }; + +COMMAND_BASE_TEMPLATE_TYPE(command_function, torrent::Object (T, const torrent::Object&)); +COMMAND_BASE_TEMPLATE_TYPE(command_value_function, torrent::Object (T, const torrent::Object::value_type&)); +COMMAND_BASE_TEMPLATE_TYPE(command_string_function, torrent::Object (T, const std::string&)); +COMMAND_BASE_TEMPLATE_TYPE(command_list_function, torrent::Object (T, const torrent::Object::list_type&)); + +#define COMMAND_BASE_TEMPLATE_CALL(func_name, func_type) \ + template const torrent::Object func_name(command_base* rawCommand, target_type target, const torrent::Object& args); \ + \ + template <> struct command_base_is_type > { static const int value = 1; typedef func_type::type type; }; \ + template <> struct command_base_is_type > { static const int value = 1; typedef func_type::type type; }; \ + template <> struct command_base_is_type > { static const int value = 1; typedef func_type::type type; }; \ + template <> struct command_base_is_type > { static const int value = 1; typedef func_type::type type; }; \ + template <> struct command_base_is_type > { static const int value = 1; typedef func_type::type type; }; \ + template <> struct command_base_is_type > { static const int value = 1; typedef func_type::type type; }; + +COMMAND_BASE_TEMPLATE_CALL(command_base_call, command_function); +COMMAND_BASE_TEMPLATE_CALL(command_base_call_value, command_value_function); +COMMAND_BASE_TEMPLATE_CALL(command_base_call_value_kb, command_value_function); +COMMAND_BASE_TEMPLATE_CALL(command_base_call_string, command_string_function); +COMMAND_BASE_TEMPLATE_CALL(command_base_call_list, command_list_function); + +} + #endif diff --git a/src/rpc/command_impl.h b/src/rpc/command_impl.h index b0c183d8..0482693a 100644 --- a/src/rpc/command_impl.h +++ b/src/rpc/command_impl.h @@ -39,50 +39,50 @@ namespace rpc { -//template <> struct target_type_id { static const int value = Command::target_generic; }; -template <> struct target_type_id { static const int value = Command::target_generic; }; -template <> struct target_type_id { static const int value = Command::target_any; }; -template <> struct target_type_id { static const int value = Command::target_download; }; -template <> struct target_type_id { static const int value = Command::target_peer; }; -template <> struct target_type_id { static const int value = Command::target_tracker; }; -template <> struct target_type_id { static const int value = Command::target_file; }; -template <> struct target_type_id { static const int value = Command::target_file_itr; }; +//template <> struct target_type_id { static const int value = command_base::target_generic; }; +template <> struct target_type_id { static const int value = command_base::target_generic; }; +template <> struct target_type_id { static const int value = command_base::target_any; }; +template <> struct target_type_id { static const int value = command_base::target_download; }; +template <> struct target_type_id { static const int value = command_base::target_peer; }; +template <> struct target_type_id { static const int value = command_base::target_tracker; }; +template <> struct target_type_id { static const int value = command_base::target_file; }; +template <> struct target_type_id { static const int value = command_base::target_file_itr; }; -template <> struct target_type_id { static const int value = Command::target_download_pair; }; +template <> struct target_type_id { static const int value = command_base::target_download_pair; }; -template <> struct target_type_id<> { static const int value = Command::target_generic; }; -template <> struct target_type_id { static const int value = Command::target_any; static const int proper_type = 1; }; -template <> struct target_type_id { static const int value = Command::target_download; static const int proper_type = 1; }; -template <> struct target_type_id { static const int value = Command::target_peer; static const int proper_type = 1; }; -template <> struct target_type_id { static const int value = Command::target_tracker; static const int proper_type = 1; }; -template <> struct target_type_id { static const int value = Command::target_file; static const int proper_type = 1; }; -template <> struct target_type_id { static const int value = Command::target_file_itr; static const int proper_type = 1; }; +template <> struct target_type_id<> { static const int value = command_base::target_generic; }; +template <> struct target_type_id { static const int value = command_base::target_any; static const int proper_type = 1; }; +template <> struct target_type_id { static const int value = command_base::target_download; static const int proper_type = 1; }; +template <> struct target_type_id { static const int value = command_base::target_peer; static const int proper_type = 1; }; +template <> struct target_type_id { static const int value = command_base::target_tracker; static const int proper_type = 1; }; +template <> struct target_type_id { static const int value = command_base::target_file; static const int proper_type = 1; }; +template <> struct target_type_id { static const int value = command_base::target_file_itr; static const int proper_type = 1; }; -template <> struct target_type_id { static const int value = Command::target_download_pair; }; +template <> struct target_type_id { static const int value = command_base::target_download_pair; }; template <> inline bool is_target_compatible(const target_type& target) { return true; } template <> inline bool -is_target_compatible(const target_type& target) { return target.first == Command::target_file || Command::target_file_itr; } +is_target_compatible(const target_type& target) { return target.first == command_base::target_file || command_base::target_file_itr; } template <> inline target_type get_target_cast(target_type target, int type) { return target; } template <> inline torrent::File* get_target_cast(target_type target, int type) { - if (target.first == Command::target_file_itr) + if (target.first == command_base::target_file_itr) return static_cast(target.second)->file(); else return static_cast(target.second); } inline torrent::Object* -Command::push_stack(const torrent::Object* first_arg, const torrent::Object* last_arg, stack_type* stack) { +command_base::push_stack(const torrent::Object* first_arg, const torrent::Object* last_arg, stack_type* stack) { unsigned int idx = 0; - while (first_arg != last_arg && idx < Command::max_arguments) { + while (first_arg != last_arg && idx < command_base::max_arguments) { new (&(*stack)[idx]) torrent::Object(*first_arg++); - (*stack)[idx].swap(*Command::argument(idx)); + (*stack)[idx].swap(*command_base::argument(idx)); idx++; } @@ -91,14 +91,14 @@ Command::push_stack(const torrent::Object* first_arg, const torrent::Object* las } inline torrent::Object* -Command::push_stack(const torrent::Object::list_type& args, stack_type* stack) { +command_base::push_stack(const torrent::Object::list_type& args, stack_type* stack) { return push_stack(args.data(), args.data() + args.size(), stack); } inline void -Command::pop_stack(stack_type* stack, torrent::Object* last_stack) { +command_base::pop_stack(stack_type* stack, torrent::Object* last_stack) { while (last_stack-- != stack->begin()) { - last_stack->swap(*Command::argument(std::distance(stack->begin(), last_stack))); + last_stack->swap(*command_base::argument(std::distance(stack->begin(), last_stack))); last_stack->~Object(); // To ensure we catch errors: diff --git a/src/rpc/command_map.cc b/src/rpc/command_map.cc index 22ee7bd1..a6e460c4 100644 --- a/src/rpc/command_map.cc +++ b/src/rpc/command_map.cc @@ -55,7 +55,7 @@ namespace rpc { -Command::stack_type Command::current_stack; +command_base::stack_type command_base::current_stack; CommandMap::~CommandMap() { std::vector keys; @@ -73,7 +73,7 @@ CommandMap::~CommandMap() { } CommandMap::iterator -CommandMap::insert(key_type key, Command* variable, int flags, const char* parm, const char* doc) { +CommandMap::insert(key_type key, command_base* variable, int flags, const char* parm, const char* doc) { iterator itr = base_type::find(key); if (itr != base_type::end()) diff --git a/src/rpc/command_map.h b/src/rpc/command_map.h index 28858e95..2d4dfd44 100644 --- a/src/rpc/command_map.h +++ b/src/rpc/command_map.h @@ -57,11 +57,11 @@ struct command_map_data_type { // // The any_slot should perhaps replace generic_slot? - command_map_data_type(Command* variable, int flags, const char* parm, const char* doc) : + command_map_data_type(command_base* variable, int flags, const char* parm, const char* doc) : m_variable(variable), m_flags(flags), m_parm(parm), m_doc(doc) {} - Command* m_variable; - Command::any_slot m_anySlot; + command_base* m_variable; + command_base::any_slot m_anySlot; int m_flags; @@ -104,10 +104,10 @@ public: bool is_modifiable(const_iterator itr) { return itr != end() && (itr->second.m_flags & flag_modifiable); } - iterator insert(key_type key, Command* variable, int flags, const char* parm, const char* doc); + iterator insert(key_type key, command_base* variable, int flags, const char* parm, const char* doc); // Make this a wrapper call to insert without extra fluff. - void insert_type(key_type key, Command* variable, Command::any_slot targetSlot, int flags, const char* parm, const char* doc) { + void insert_type(key_type key, command_base* variable, command_base::any_slot targetSlot, int flags, const char* parm, const char* doc) { iterator itr = insert(key, variable, flags, parm, doc); itr->second.m_anySlot = targetSlot; } @@ -121,20 +121,20 @@ public: const mapped_type call(key_type key, target_type target, const mapped_type& args = mapped_type()) { return call_command(key, args, target); } const mapped_type call_catch(key_type key, target_type target, const mapped_type& args = mapped_type(), const char* err = "Command failed: "); - const mapped_type call_command (key_type key, const mapped_type& arg, target_type target = target_type((int)Command::target_generic, NULL)); - const mapped_type call_command (const_iterator itr, const mapped_type& arg, target_type target = target_type((int)Command::target_generic, NULL)); + const mapped_type call_command (key_type key, const mapped_type& arg, target_type target = target_type((int)command_base::target_generic, NULL)); + const mapped_type call_command (const_iterator itr, const mapped_type& arg, target_type target = target_type((int)command_base::target_generic, NULL)); - const mapped_type call_command_d(key_type key, core::Download* download, const mapped_type& arg) { return call_command(key, arg, target_type((int)Command::target_download, download)); } - const mapped_type call_command_p(key_type key, torrent::Peer* peer, const mapped_type& arg) { return call_command(key, arg, target_type((int)Command::target_peer, peer)); } - const mapped_type call_command_t(key_type key, torrent::Tracker* tracker, const mapped_type& arg) { return call_command(key, arg, target_type((int)Command::target_tracker, tracker)); } - const mapped_type call_command_f(key_type key, torrent::File* file, const mapped_type& arg) { return call_command(key, arg, target_type((int)Command::target_file, file)); } + const mapped_type call_command_d(key_type key, core::Download* download, const mapped_type& arg) { return call_command(key, arg, target_type((int)command_base::target_download, download)); } + const mapped_type call_command_p(key_type key, torrent::Peer* peer, const mapped_type& arg) { return call_command(key, arg, target_type((int)command_base::target_peer, peer)); } + const mapped_type call_command_t(key_type key, torrent::Tracker* tracker, const mapped_type& arg) { return call_command(key, arg, target_type((int)command_base::target_tracker, tracker)); } + const mapped_type call_command_f(key_type key, torrent::File* file, const mapped_type& arg) { return call_command(key, arg, target_type((int)command_base::target_file, file)); } private: CommandMap(const CommandMap&); void operator = (const CommandMap&); }; -inline target_type make_target() { return target_type((int)Command::target_generic, NULL); } +inline target_type make_target() { return target_type((int)command_base::target_generic, NULL); } inline target_type make_target(int type, void* target) { return target_type(type, target); } inline target_type make_target(int type, void* target1, void* target2) { return target_type(type, target1, target2); } diff --git a/src/rpc/command_new_slot.h b/src/rpc/command_new_slot.h deleted file mode 100644 index dad293bf..00000000 --- a/src/rpc/command_new_slot.h +++ /dev/null @@ -1,133 +0,0 @@ -// rTorrent - BitTorrent client -// Copyright (C) 2005-2007, Jari Sundell -// -// This program is free software; you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation; either version 2 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -// -// In addition, as a special exception, the copyright holders give -// permission to link the code of portions of this program with the -// OpenSSL library under certain conditions as described in each -// individual source file, and distribute linked combinations -// including the two. -// -// You must obey the GNU General Public License in all respects for -// all of the code used other than OpenSSL. If you modify file(s) -// with this exception, you may extend this exception to your version -// of the file(s), but you are not obligated to do so. If you do not -// wish to do so, delete this exception statement from your version. -// If you delete this exception statement from all source files in the -// program, then also delete it here. -// -// Contact: Jari Sundell -// -// Skomakerveien 33 -// 3185 Skoppum, NORWAY - -// The command_new_slot object aims at replacing the current crop of -// Command* objects with a new type that is safe to cast from the base -// command type and thus allows for static initialization and fixed -// sized objects. -// -// All commands changed to this new class shall be safe to call with -// the raw object types. - -#ifndef RTORRENT_RPC_COMMAND_NEW_SLOT_H -#define RTORRENT_RPC_COMMAND_NEW_SLOT_H - -#include -#include -#include -#include -#include - -#include "command.h" - -namespace rpc { - -typedef const torrent::Object (*command_base_call_type)(Command*, target_type, const torrent::Object&); -typedef std::tr1::function base_function; - -template struct command_base_is_valid {}; -template struct command_base_is_type {}; - -class command_base : public Command { -public: - command_base() { new (&_pod()) base_function(); } - ~command_base() { _pod().~base_function(); } - - template - void set_function(T s, int value = command_base_is_valid::value) { _pod() = s; } - - template - void set_function_2(typename command_base_is_type::type s, int value = command_base_is_valid::type>::value) { - _pod::type>() = s; - } - - // The std::function object in GCC is castable between types with a - // pointer to a struct of ctor/dtor/calls for non-POD slots. As such - // it should be safe to cast between different std::function - // template types, yet what the C++0x standard will say about this I - // have no idea atm. - template tmpl& _pod() { return reinterpret_cast(t_pod); } - - template - static const torrent::Object _call(Command* cmd, target_type target, Args args) { - return static_cast(cmd)->_pod()(get_target_cast(target), args); - } - -protected: - - union { - char t_pod[sizeof(base_function)]; - }; -}; - -#define COMMAND_BASE_TEMPLATE_TYPE(func_type, func_parm) \ - template ::proper_type> struct func_type { typedef std::tr1::function type; }; \ - \ - template <> struct command_base_is_valid::type> { static const int value = 1; }; \ - template <> struct command_base_is_valid::type> { static const int value = 1; }; \ - template <> struct command_base_is_valid::type> { static const int value = 1; }; \ - template <> struct command_base_is_valid::type> { static const int value = 1; }; \ - template <> struct command_base_is_valid::type> { static const int value = 1; }; \ - template <> struct command_base_is_valid::type> { static const int value = 1; }; - -// template struct command_base_is_valid::type > { static const int value = 1; }; - -COMMAND_BASE_TEMPLATE_TYPE(command_function, torrent::Object (T, const torrent::Object&)); -COMMAND_BASE_TEMPLATE_TYPE(command_value_function, torrent::Object (T, const torrent::Object::value_type&)); -COMMAND_BASE_TEMPLATE_TYPE(command_string_function, torrent::Object (T, const std::string&)); -COMMAND_BASE_TEMPLATE_TYPE(command_list_function, torrent::Object (T, const torrent::Object::list_type&)); - -#define COMMAND_BASE_TEMPLATE_CALL(func_name, func_type) \ - template const torrent::Object func_name(Command* rawCommand, target_type target, const torrent::Object& args); \ - \ - template <> struct command_base_is_type > { static const int value = 1; typedef func_type::type type; }; \ - template <> struct command_base_is_type > { static const int value = 1; typedef func_type::type type; }; \ - template <> struct command_base_is_type > { static const int value = 1; typedef func_type::type type; }; \ - template <> struct command_base_is_type > { static const int value = 1; typedef func_type::type type; }; \ - template <> struct command_base_is_type > { static const int value = 1; typedef func_type::type type; }; \ - template <> struct command_base_is_type > { static const int value = 1; typedef func_type::type type; }; - -COMMAND_BASE_TEMPLATE_CALL(command_base_call, command_function); -COMMAND_BASE_TEMPLATE_CALL(command_base_call_value, command_value_function); -COMMAND_BASE_TEMPLATE_CALL(command_base_call_value_kb, command_value_function); -COMMAND_BASE_TEMPLATE_CALL(command_base_call_string, command_string_function); -COMMAND_BASE_TEMPLATE_CALL(command_base_call_list, command_list_function); - -} - -#endif - - diff --git a/src/rpc/fixed_key.h b/src/rpc/fixed_key.h new file mode 100644 index 00000000..31809b51 --- /dev/null +++ b/src/rpc/fixed_key.h @@ -0,0 +1,115 @@ +// rTorrent - BitTorrent client +// Copyright (C) 2005-2007, Jari Sundell +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// In addition, as a special exception, the copyright holders give +// permission to link the code of portions of this program with the +// OpenSSL library under certain conditions as described in each +// individual source file, and distribute linked combinations +// including the two. +// +// You must obey the GNU General Public License in all respects for +// all of the code used other than OpenSSL. If you modify file(s) +// with this exception, you may extend this exception to your version +// of the file(s), but you are not obligated to do so. If you do not +// wish to do so, delete this exception statement from your version. +// If you delete this exception statement from all source files in the +// program, then also delete it here. +// +// Contact: Jari Sundell +// +// Skomakerveien 33 +// 3185 Skoppum, NORWAY + +#ifndef RTORRENT_RPC_FIXED_KEY_H +#define RTORRENT_RPC_FIXED_KEY_H + +#include + +namespace rpc { + +// The key size should be such that the value type size which includes +// the next-pointer. + +template +class fixed_key_type { +public: + typedef char value_type; + typedef const char* iterator; + typedef const char* const_iterator; + typedef uint32_t size_type; + + static const size_type max_size = MaxSize - 1; + + fixed_key_type() : m_size(0) { m_data[0] = '\0'; } + fixed_key_type(const fixed_key_type& k) : m_size(k.m_size) { std::memcpy(m_data, k.m_data, k.m_size + 1); } + + fixed_key_type(const value_type* src_data, size_type src_size) { set_data(src_data, src_size); } + + static fixed_key_type from_c_str(const char* str) { fixed_key_type k; k.set_c_str(str); return k; } + static fixed_key_type from_string(const std::string& str) { fixed_key_type k; k.set_c_str(str.c_str(), str.size()); return k; } + static fixed_key_type from_raw_string(const torrent::raw_string& str) { fixed_key_type k; k.set_data(str.data(), str.size()); return k; } + + bool empty() const { return m_size == 0;; } + size_type size() const { return m_size; } + + iterator begin() const { return m_data; } + iterator end() const { return m_data + m_size; } + + value_type* data() { return m_data; } + const value_type* data() const { return m_data; } + const char* c_str() const { return m_data; } + + void set_data(const value_type* src_data, size_type src_size); + void set_c_str(const value_type* src_data); + void set_c_str(const value_type* src_data, size_type src_size); + + bool operator == (const fixed_key_type& rhs) const { return m_size == rhs.m_size && std::memcmp(m_data, rhs.m_data, m_size) == 0; } + bool operator != (const fixed_key_type& rhs) const { return m_size != rhs.m_size || std::memcmp(m_data, rhs.m_data, m_size) != 0; } + + bool operator == (const std::string& rhs) const { return m_size == rhs.size() && std::memcmp(m_data, rhs.data(), m_size) == 0; } + +private: + size_type m_size; + char m_data[max_size]; +}; + +struct hash_fixed_key_type { + template + inline std::size_t operator () (const fixed_key_type& p) const { return hash(p.data()); } + + static inline std::size_t hash(const char* data) { + std::size_t result = 0; + + while (*data != '\0') + result = (result * 131) + *data++; + + return result; + } + + static inline std::size_t hash(const char* data, uint32_t size) { + std::size_t result = 0; + + while (size--) + result = (result * 131) + *data++; + + return result; + } +}; + +} + +#endif diff --git a/src/rpc/parse_commands.cc b/src/rpc/parse_commands.cc index 9d1e6982..da253e4f 100644 --- a/src/rpc/parse_commands.cc +++ b/src/rpc/parse_commands.cc @@ -230,39 +230,39 @@ parse_command_name(const char* first, const char* last, std::string* dest) { // Temp until it can be moved somewhere better... const torrent::Object command_function_call(const torrent::raw_string& cmd, target_type target, const torrent::Object& args) { - rpc::Command::stack_type stack; + rpc::command_base::stack_type stack; torrent::Object* last_stack; if (args.is_list()) - last_stack = rpc::Command::push_stack(args.as_list(), &stack); + last_stack = rpc::command_base::push_stack(args.as_list(), &stack); else if (args.type() != torrent::Object::TYPE_NONE) - last_stack = rpc::Command::push_stack(&args, &args + 1, &stack); + last_stack = rpc::command_base::push_stack(&args, &args + 1, &stack); else - last_stack = rpc::Command::push_stack(NULL, NULL, &stack); + last_stack = rpc::command_base::push_stack(NULL, NULL, &stack); try { torrent::Object result = parse_command_multiple(target, cmd.begin(), cmd.end()); - rpc::Command::pop_stack(&stack, last_stack); + rpc::command_base::pop_stack(&stack, last_stack); return result; } catch (torrent::bencode_error& e) { - rpc::Command::pop_stack(&stack, last_stack); + rpc::command_base::pop_stack(&stack, last_stack); throw e; } } const torrent::Object command_function_multi_call(const torrent::Object::map_type& cmd, target_type target, const torrent::Object& args) { - rpc::Command::stack_type stack; + rpc::command_base::stack_type stack; torrent::Object* last_stack; if (args.is_list()) - last_stack = rpc::Command::push_stack(args.as_list(), &stack); + last_stack = rpc::command_base::push_stack(args.as_list(), &stack); else if (args.type() != torrent::Object::TYPE_NONE) - last_stack = rpc::Command::push_stack(&args, &args + 1, &stack); + last_stack = rpc::command_base::push_stack(&args, &args + 1, &stack); else - last_stack = rpc::Command::push_stack(NULL, NULL, &stack); + last_stack = rpc::command_base::push_stack(NULL, NULL, &stack); try { for (torrent::Object::map_const_iterator itr = cmd.begin(), last = cmd.end(); itr != last; itr++) { @@ -271,11 +271,11 @@ command_function_multi_call(const torrent::Object::map_type& cmd, target_type ta } } catch (torrent::bencode_error& e) { - rpc::Command::pop_stack(&stack, last_stack); + rpc::command_base::pop_stack(&stack, last_stack); throw e; } - rpc::Command::pop_stack(&stack, last_stack); + rpc::command_base::pop_stack(&stack, last_stack); return torrent::Object(); } diff --git a/test/rpc/command_map_test.h b/test/rpc/command_map_test.h index 5648e6a3..34ab2943 100644 --- a/test/rpc/command_map_test.h +++ b/test/rpc/command_map_test.h @@ -1,7 +1,6 @@ #include #include "rpc/command_map.h" -#include "rpc/command_new_slot.h" class CommandMapTest : public CppUnit::TestFixture { CPPUNIT_TEST_SUITE(CommandMapTest); diff --git a/test/rpc/command_slot_test.h b/test/rpc/command_slot_test.h index 3af4d4f6..d6910c99 100644 --- a/test/rpc/command_slot_test.h +++ b/test/rpc/command_slot_test.h @@ -1,6 +1,6 @@ #include -#include "rpc/command_new_slot.h" +#include "rpc/command.h" class CommandSlotTest : public CppUnit::TestFixture { CPPUNIT_TEST_SUITE(CommandSlotTest); diff --git a/test/rpc/command_test.cc b/test/rpc/command_test.cc index fd0a04b9..4d9348ab 100644 --- a/test/rpc/command_test.cc +++ b/test/rpc/command_test.cc @@ -6,33 +6,33 @@ CPPUNIT_TEST_SUITE_REGISTRATION(CommandTest); bool command_stack_all_empty() { - return std::find_if(rpc::Command::stack_begin(), rpc::Command::stack_end(), - std::mem_fun_ref(&torrent::Object::is_not_empty)) == rpc::Command::stack_end(); + return std::find_if(rpc::command_base::stack_begin(), rpc::command_base::stack_end(), + std::mem_fun_ref(&torrent::Object::is_not_empty)) == rpc::command_base::stack_end(); } void CommandTest::test_stack() { torrent::Object::list_type args; - rpc::Command::stack_type stack; + rpc::command_base::stack_type stack; torrent::Object* last_stack; // Test empty stack. CPPUNIT_ASSERT(command_stack_all_empty()); - last_stack = rpc::Command::push_stack(args, &stack); + last_stack = rpc::command_base::push_stack(args, &stack); CPPUNIT_ASSERT(command_stack_all_empty()); - rpc::Command::pop_stack(&stack, last_stack); + rpc::command_base::pop_stack(&stack, last_stack); CPPUNIT_ASSERT(command_stack_all_empty()); // Test stack with one. args.push_back(int64_t(1)); - last_stack = rpc::Command::push_stack(args, &stack); + last_stack = rpc::command_base::push_stack(args, &stack); CPPUNIT_ASSERT(!command_stack_all_empty()); - CPPUNIT_ASSERT(rpc::Command::stack_begin()->as_value() == 1); + CPPUNIT_ASSERT(rpc::command_base::stack_begin()->as_value() == 1); - rpc::Command::pop_stack(&stack, last_stack); + rpc::command_base::pop_stack(&stack, last_stack); CPPUNIT_ASSERT(command_stack_all_empty()); // Test stack with two @@ -40,44 +40,44 @@ CommandTest::test_stack() { args.push_back(int64_t(2)); args.push_back(int64_t(3)); - last_stack = rpc::Command::push_stack(args, &stack); + last_stack = rpc::command_base::push_stack(args, &stack); CPPUNIT_ASSERT(!command_stack_all_empty()); - CPPUNIT_ASSERT(rpc::Command::current_stack[0].as_value() == 2); - CPPUNIT_ASSERT(rpc::Command::current_stack[1].as_value() == 3); + CPPUNIT_ASSERT(rpc::command_base::current_stack[0].as_value() == 2); + CPPUNIT_ASSERT(rpc::command_base::current_stack[1].as_value() == 3); - rpc::Command::pop_stack(&stack, last_stack); + rpc::command_base::pop_stack(&stack, last_stack); CPPUNIT_ASSERT(command_stack_all_empty()); } void CommandTest::test_stack_double() { torrent::Object::list_type args; - rpc::Command::stack_type stack_first; - rpc::Command::stack_type stack_second; + rpc::command_base::stack_type stack_first; + rpc::command_base::stack_type stack_second; torrent::Object* last_stack_first; torrent::Object* last_stack_second; // Test double-stacked. args.push_back(int64_t(1)); - last_stack_first = rpc::Command::push_stack(args, &stack_first); + last_stack_first = rpc::command_base::push_stack(args, &stack_first); CPPUNIT_ASSERT(!command_stack_all_empty()); - CPPUNIT_ASSERT(rpc::Command::current_stack[0].as_value() == 1); + CPPUNIT_ASSERT(rpc::command_base::current_stack[0].as_value() == 1); args.clear(); args.push_back(int64_t(2)); args.push_back(int64_t(3)); - last_stack_second = rpc::Command::push_stack(args, &stack_second); + last_stack_second = rpc::command_base::push_stack(args, &stack_second); CPPUNIT_ASSERT(!command_stack_all_empty()); - CPPUNIT_ASSERT(rpc::Command::current_stack[0].as_value() == 2); - CPPUNIT_ASSERT(rpc::Command::current_stack[1].as_value() == 3); + CPPUNIT_ASSERT(rpc::command_base::current_stack[0].as_value() == 2); + CPPUNIT_ASSERT(rpc::command_base::current_stack[1].as_value() == 3); - rpc::Command::pop_stack(&stack_second, last_stack_second); + rpc::command_base::pop_stack(&stack_second, last_stack_second); CPPUNIT_ASSERT(!command_stack_all_empty()); - CPPUNIT_ASSERT(rpc::Command::current_stack[0].as_value() == 1); + CPPUNIT_ASSERT(rpc::command_base::current_stack[0].as_value() == 1); - rpc::Command::pop_stack(&stack_first, last_stack_first); + rpc::command_base::pop_stack(&stack_first, last_stack_first); CPPUNIT_ASSERT(command_stack_all_empty()); }