* Added 'rpc/fixed_key.h' header.

* Replaced Command with command_base.


git-svn-id: svn://rakshasa.no/libtorrent/trunk/rtorrent@1168 e378c898-3ddf-0310-93e7-cc216c733640
This commit is contained in:
rakshasa
2010-04-30 04:36:02 +00:00
parent 7dad6d34f3
commit 8b03988612
15 changed files with 307 additions and 248 deletions
+1 -1
View File
@@ -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"
+8 -8
View File
@@ -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));
}
+1 -1
View File
@@ -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")
+1 -2
View File
@@ -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 \
@@ -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<target_type>(Command* rawCommand, target_type target, const torrent::Object& args); \
template const torrent::Object func_name<core::Download*>(Command* rawCommand, target_type target, const torrent::Object& args); \
template const torrent::Object func_name<torrent::Peer*>(Command* rawCommand, target_type target, const torrent::Object& args); \
template const torrent::Object func_name<torrent::Tracker*>(Command* rawCommand, target_type target, const torrent::Object& args); \
template const torrent::Object func_name<torrent::File*>(Command* rawCommand, target_type target, const torrent::Object& args); \
template const torrent::Object func_name<torrent::FileListIterator*>(Command* rawCommand, target_type target, const torrent::Object& args);
template const torrent::Object func_name<target_type>(command_base* rawCommand, target_type target, const torrent::Object& args); \
template const torrent::Object func_name<core::Download*>(command_base* rawCommand, target_type target, const torrent::Object& args); \
template const torrent::Object func_name<torrent::Peer*>(command_base* rawCommand, target_type target, const torrent::Object& args); \
template const torrent::Object func_name<torrent::Tracker*>(command_base* rawCommand, target_type target, const torrent::Object& args); \
template const torrent::Object func_name<torrent::File*>(command_base* rawCommand, target_type target, const torrent::Object& args); \
template const torrent::Object func_name<torrent::FileListIterator*>(command_base* rawCommand, target_type target, const torrent::Object& args);
namespace rpc {
template <typename T> 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<T>(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 <typename T> 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<T>(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 <typename T> 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<T>(rawCommand, target, rawArgs, 0, 1);
}
template <typename T> 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<T>(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 <typename T> 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<T>(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 <typename T> 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<T>(target))
throw torrent::input_error("Target of wrong type.");
+94 -15
View File
@@ -37,6 +37,12 @@
#ifndef RTORRENT_RPC_COMMAND_H
#define RTORRENT_RPC_COMMAND_H
#include <functional>
#include <limits>
#include <inttypes.h>
#include <torrent/object.h>
#include <tr1/functional>
#include <torrent/object.h>
#include <torrent/data/file_list_iterator.h>
@@ -99,7 +105,15 @@ struct rt_triple : private std::pair<T1, T2> {
//typedef std::pair<int, void*> target_type;
typedef rt_triple<int, void*, void*> 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<torrent::Object (target_type, const torrent::Object&)> base_function;
template <typename tmpl> struct command_base_is_valid {};
template <command_base_call_type tmpl_func> 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<void>::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<void>::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>()) base_function(); }
virtual ~command_base() { _pod<base_function>().~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 <typename T>
void set_function(T s, int value = command_base_is_valid<T>::value) { _pod<T>() = s; }
template <command_base_call_type T>
void set_function_2(typename command_base_is_type<T>::type s, int value = command_base_is_valid<typename command_base_is_type<T>::type>::value) {
_pod<typename command_base_is_type<T>::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 <typename tmpl> tmpl& _pod() { return reinterpret_cast<tmpl&>(t_pod); }
template <typename Func, typename T, typename Args>
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 <typename T1 = void, typename T2 = void>
@@ -178,7 +214,7 @@ template <typename T> inline bool
is_target_compatible(const target_type& target) { return target.first == target_type_id<T>::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 <typename T> inline T
get_target_cast(target_type target, int type = target_type_id<T>::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 <typename Func, typename T, typename Args>
inline const torrent::Object
command_base::_call(command_base* cmd, target_type target, Args args) {
return static_cast<command_base*>(cmd)->_pod<Func>()(get_target_cast<T>(target), args);
}
#define COMMAND_BASE_TEMPLATE_TYPE(func_type, func_parm) \
template <typename T, int proper = target_type_id<T>::proper_type> struct func_type { typedef std::tr1::function<func_parm> type; }; \
\
template <> struct command_base_is_valid<func_type<target_type>::type> { static const int value = 1; }; \
template <> struct command_base_is_valid<func_type<core::Download*>::type> { static const int value = 1; }; \
template <> struct command_base_is_valid<func_type<torrent::Peer*>::type> { static const int value = 1; }; \
template <> struct command_base_is_valid<func_type<torrent::Tracker*>::type> { static const int value = 1; }; \
template <> struct command_base_is_valid<func_type<torrent::File*>::type> { static const int value = 1; }; \
template <> struct command_base_is_valid<func_type<torrent::FileListIterator*>::type> { static const int value = 1; };
// template <typename Q> struct command_base_is_valid<typename func_type<Q>::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 <typename T> const torrent::Object func_name(command_base* rawCommand, target_type target, const torrent::Object& args); \
\
template <> struct command_base_is_type<func_name<target_type> > { static const int value = 1; typedef func_type<target_type>::type type; }; \
template <> struct command_base_is_type<func_name<core::Download*> > { static const int value = 1; typedef func_type<core::Download*>::type type; }; \
template <> struct command_base_is_type<func_name<torrent::Peer*> > { static const int value = 1; typedef func_type<torrent::Peer*>::type type; }; \
template <> struct command_base_is_type<func_name<torrent::Tracker*> > { static const int value = 1; typedef func_type<torrent::Tracker*>::type type; }; \
template <> struct command_base_is_type<func_name<torrent::File*> > { static const int value = 1; typedef func_type<torrent::File*>::type type; }; \
template <> struct command_base_is_type<func_name<torrent::FileListIterator*> > { static const int value = 1; typedef func_type<torrent::FileListIterator*>::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
+25 -25
View File
@@ -39,50 +39,50 @@
namespace rpc {
//template <> struct target_type_id<Command::generic_slot> { static const int value = Command::target_generic; };
template <> struct target_type_id<Command::cleaned_slot> { static const int value = Command::target_generic; };
template <> struct target_type_id<Command::any_slot> { static const int value = Command::target_any; };
template <> struct target_type_id<Command::download_slot> { static const int value = Command::target_download; };
template <> struct target_type_id<Command::peer_slot> { static const int value = Command::target_peer; };
template <> struct target_type_id<Command::tracker_slot> { static const int value = Command::target_tracker; };
template <> struct target_type_id<Command::file_slot> { static const int value = Command::target_file; };
template <> struct target_type_id<Command::file_itr_slot> { static const int value = Command::target_file_itr; };
//template <> struct target_type_id<command_base::generic_slot> { static const int value = command_base::target_generic; };
template <> struct target_type_id<command_base::cleaned_slot> { static const int value = command_base::target_generic; };
template <> struct target_type_id<command_base::any_slot> { static const int value = command_base::target_any; };
template <> struct target_type_id<command_base::download_slot> { static const int value = command_base::target_download; };
template <> struct target_type_id<command_base::peer_slot> { static const int value = command_base::target_peer; };
template <> struct target_type_id<command_base::tracker_slot> { static const int value = command_base::target_tracker; };
template <> struct target_type_id<command_base::file_slot> { static const int value = command_base::target_file; };
template <> struct target_type_id<command_base::file_itr_slot> { static const int value = command_base::target_file_itr; };
template <> struct target_type_id<Command::download_pair_slot> { static const int value = Command::target_download_pair; };
template <> struct target_type_id<command_base::download_pair_slot> { 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<target_type> { static const int value = Command::target_any; static const int proper_type = 1; };
template <> struct target_type_id<core::Download*> { static const int value = Command::target_download; static const int proper_type = 1; };
template <> struct target_type_id<torrent::Peer*> { static const int value = Command::target_peer; static const int proper_type = 1; };
template <> struct target_type_id<torrent::Tracker*> { static const int value = Command::target_tracker; static const int proper_type = 1; };
template <> struct target_type_id<torrent::File*> { static const int value = Command::target_file; static const int proper_type = 1; };
template <> struct target_type_id<torrent::FileListIterator*> { 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<target_type> { static const int value = command_base::target_any; static const int proper_type = 1; };
template <> struct target_type_id<core::Download*> { static const int value = command_base::target_download; static const int proper_type = 1; };
template <> struct target_type_id<torrent::Peer*> { static const int value = command_base::target_peer; static const int proper_type = 1; };
template <> struct target_type_id<torrent::Tracker*> { static const int value = command_base::target_tracker; static const int proper_type = 1; };
template <> struct target_type_id<torrent::File*> { static const int value = command_base::target_file; static const int proper_type = 1; };
template <> struct target_type_id<torrent::FileListIterator*> { static const int value = command_base::target_file_itr; static const int proper_type = 1; };
template <> struct target_type_id<core::Download*, core::Download*> { static const int value = Command::target_download_pair; };
template <> struct target_type_id<core::Download*, core::Download*> { static const int value = command_base::target_download_pair; };
template <> inline bool
is_target_compatible<target_type>(const target_type& target) { return true; }
template <> inline bool
is_target_compatible<torrent::File*>(const target_type& target) { return target.first == Command::target_file || Command::target_file_itr; }
is_target_compatible<torrent::File*>(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_type target, int type) { return target; }
template <> inline torrent::File*
get_target_cast<torrent::File*>(target_type target, int type) {
if (target.first == Command::target_file_itr)
if (target.first == command_base::target_file_itr)
return static_cast<torrent::FileListIterator*>(target.second)->file();
else
return static_cast<torrent::File*>(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:
+2 -2
View File
@@ -55,7 +55,7 @@
namespace rpc {
Command::stack_type Command::current_stack;
command_base::stack_type command_base::current_stack;
CommandMap::~CommandMap() {
std::vector<const char*> 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())
+12 -12
View File
@@ -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); }
-133
View File
@@ -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 <jaris@ifi.uio.no>
//
// 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 <functional>
#include <limits>
#include <inttypes.h>
#include <torrent/object.h>
#include <tr1/functional>
#include "command.h"
namespace rpc {
typedef const torrent::Object (*command_base_call_type)(Command*, target_type, const torrent::Object&);
typedef std::tr1::function<torrent::Object (target_type, const torrent::Object&)> base_function;
template <typename tmpl> struct command_base_is_valid {};
template <command_base_call_type tmpl_func> struct command_base_is_type {};
class command_base : public Command {
public:
command_base() { new (&_pod<base_function>()) base_function(); }
~command_base() { _pod<base_function>().~base_function(); }
template <typename T>
void set_function(T s, int value = command_base_is_valid<T>::value) { _pod<T>() = s; }
template <command_base_call_type T>
void set_function_2(typename command_base_is_type<T>::type s, int value = command_base_is_valid<typename command_base_is_type<T>::type>::value) {
_pod<typename command_base_is_type<T>::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 <typename tmpl> tmpl& _pod() { return reinterpret_cast<tmpl&>(t_pod); }
template <typename Func, typename T, typename Args>
static const torrent::Object _call(Command* cmd, target_type target, Args args) {
return static_cast<command_base*>(cmd)->_pod<Func>()(get_target_cast<T>(target), args);
}
protected:
union {
char t_pod[sizeof(base_function)];
};
};
#define COMMAND_BASE_TEMPLATE_TYPE(func_type, func_parm) \
template <typename T, int proper = target_type_id<T>::proper_type> struct func_type { typedef std::tr1::function<func_parm> type; }; \
\
template <> struct command_base_is_valid<func_type<target_type>::type> { static const int value = 1; }; \
template <> struct command_base_is_valid<func_type<core::Download*>::type> { static const int value = 1; }; \
template <> struct command_base_is_valid<func_type<torrent::Peer*>::type> { static const int value = 1; }; \
template <> struct command_base_is_valid<func_type<torrent::Tracker*>::type> { static const int value = 1; }; \
template <> struct command_base_is_valid<func_type<torrent::File*>::type> { static const int value = 1; }; \
template <> struct command_base_is_valid<func_type<torrent::FileListIterator*>::type> { static const int value = 1; };
// template <typename Q> struct command_base_is_valid<typename func_type<Q>::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 <typename T> const torrent::Object func_name(Command* rawCommand, target_type target, const torrent::Object& args); \
\
template <> struct command_base_is_type<func_name<target_type> > { static const int value = 1; typedef func_type<target_type>::type type; }; \
template <> struct command_base_is_type<func_name<core::Download*> > { static const int value = 1; typedef func_type<core::Download*>::type type; }; \
template <> struct command_base_is_type<func_name<torrent::Peer*> > { static const int value = 1; typedef func_type<torrent::Peer*>::type type; }; \
template <> struct command_base_is_type<func_name<torrent::Tracker*> > { static const int value = 1; typedef func_type<torrent::Tracker*>::type type; }; \
template <> struct command_base_is_type<func_name<torrent::File*> > { static const int value = 1; typedef func_type<torrent::File*>::type type; }; \
template <> struct command_base_is_type<func_name<torrent::FileListIterator*> > { static const int value = 1; typedef func_type<torrent::FileListIterator*>::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
+115
View File
@@ -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 <jaris@ifi.uio.no>
//
// Skomakerveien 33
// 3185 Skoppum, NORWAY
#ifndef RTORRENT_RPC_FIXED_KEY_H
#define RTORRENT_RPC_FIXED_KEY_H
#include <torrent/object_raw_bencode.h>
namespace rpc {
// The key size should be such that the value type size which includes
// the next-pointer.
template <size_t MaxSize>
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 <size_t MaxSize>
inline std::size_t operator () (const fixed_key_type<MaxSize>& 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
+12 -12
View File
@@ -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();
}
-1
View File
@@ -1,7 +1,6 @@
#include <cppunit/extensions/HelperMacros.h>
#include "rpc/command_map.h"
#include "rpc/command_new_slot.h"
class CommandMapTest : public CppUnit::TestFixture {
CPPUNIT_TEST_SUITE(CommandMapTest);
+1 -1
View File
@@ -1,6 +1,6 @@
#include <cppunit/extensions/HelperMacros.h>
#include "rpc/command_new_slot.h"
#include "rpc/command.h"
class CommandSlotTest : public CppUnit::TestFixture {
CPPUNIT_TEST_SUITE(CommandSlotTest);
+22 -22
View File
@@ -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());
}