switch to a vtable approach for the reader

This commit is contained in:
Havoc Pennington 2004-12-29 22:22:41 +00:00
parent 8645ee5251
commit 9b0fc4e482
2 changed files with 397 additions and 338 deletions

View file

@ -29,6 +29,16 @@
* @{
*/
struct DBusTypeReaderClass
{
const char *name;
void (* recurse) (DBusTypeReader *sub,
DBusTypeReader *parent);
int (* get_current_type) (DBusTypeReader *reader);
void (* next) (DBusTypeReader *reader,
int current_type);
};
static int
first_type_in_signature (const DBusString *str,
int pos)
@ -50,233 +60,137 @@ element_type_get_alignment (const DBusString *str,
return _dbus_type_get_alignment (first_type_in_signature (str, pos));
}
void
_dbus_type_reader_init (DBusTypeReader *reader,
int byte_order,
const DBusString *type_str,
int type_pos,
const DBusString *value_str,
int value_pos)
static void
reader_init (DBusTypeReader *reader,
int byte_order,
const DBusString *type_str,
int type_pos,
const DBusString *value_str,
int value_pos)
{
reader->byte_order = byte_order;
reader->type_str = type_str;
reader->type_pos = type_pos;
reader->value_str = value_str;
reader->value_pos = value_pos;
reader->container_type = DBUS_TYPE_INVALID;
_dbus_verbose (" type reader %p init type_pos = %d value_pos = %d remaining sig '%s'\n",
reader, reader->type_pos, reader->value_pos,
_dbus_string_get_const_data_len (reader->type_str, reader->type_pos, 0));
}
int
_dbus_type_reader_get_current_type (DBusTypeReader *reader)
static void
base_reader_recurse (DBusTypeReader *sub,
DBusTypeReader *parent)
{
/* point subreader at the same place as parent */
reader_init (sub,
parent->byte_order,
parent->type_str,
parent->type_pos,
parent->value_str,
parent->value_pos);
}
static void
struct_reader_recurse (DBusTypeReader *sub,
DBusTypeReader *parent)
{
base_reader_recurse (sub, parent);
_dbus_assert (_dbus_string_get_byte (sub->type_str,
sub->type_pos) == DBUS_STRUCT_BEGIN_CHAR);
sub->type_pos += 1;
/* struct has 8 byte alignment */
sub->value_pos = _DBUS_ALIGN_VALUE (sub->value_pos, 8);
sub->u.strct.finished = FALSE;
}
static void
array_reader_recurse (DBusTypeReader *sub,
DBusTypeReader *parent)
{
dbus_uint32_t array_len;
int alignment;
_dbus_assert (!_dbus_type_reader_array_is_empty (parent));
base_reader_recurse (sub, parent);
/* point type_pos at the array element type */
sub->type_pos += 1;
sub->value_pos = _DBUS_ALIGN_VALUE (sub->value_pos, 4);
_dbus_demarshal_basic_type (sub->value_str,
DBUS_TYPE_UINT32,
&array_len,
sub->byte_order,
&sub->value_pos);
sub->u.array.len = array_len;
alignment = element_type_get_alignment (sub->type_str,
sub->type_pos);
sub->value_pos = _DBUS_ALIGN_VALUE (sub->value_pos, alignment);
sub->u.array.element_type = first_type_in_signature (sub->type_str,
sub->type_pos);
sub->u.array.start_pos = sub->value_pos;
_dbus_verbose (" type reader %p array start = %d array len = %d array element type = %s\n",
sub,
sub->u.array.start_pos,
sub->u.array.len,
_dbus_type_to_string (sub->u.array.element_type));
}
static int
body_reader_get_current_type (DBusTypeReader *reader)
{
int t;
/* for INVALID t will == DBUS_TYPE_INVALID when we
* reach the end of type_str, for STRUCT we have to
* check the finished flag
*/
if (reader->container_type == DBUS_TYPE_INVALID)
{
t = first_type_in_signature (reader->type_str,
reader->type_pos);
}
else if (reader->container_type == DBUS_TYPE_STRUCT)
{
if (reader->u.strct.finished)
t = DBUS_TYPE_INVALID;
else
t = first_type_in_signature (reader->type_str,
reader->type_pos);
}
else if (reader->container_type == DBUS_TYPE_ARRAY)
{
/* return the array element type if elements remain, and
* TYPE_INVALID otherwise
*/
int end_pos;
t = first_type_in_signature (reader->type_str,
reader->type_pos);
end_pos = reader->u.array.start_pos + reader->u.array.len;
_dbus_assert (reader->value_pos <= end_pos);
_dbus_assert (reader->value_pos >= reader->u.array.start_pos);
if (reader->value_pos < end_pos)
t = reader->u.array.element_type;
else
t = DBUS_TYPE_INVALID;
}
else
{
_dbus_assert_not_reached ("reader->container_type should not be set to this");
t = DBUS_TYPE_INVALID; /* quiet gcc */
}
_dbus_assert (t != DBUS_STRUCT_END_CHAR);
_dbus_assert (t != DBUS_STRUCT_BEGIN_CHAR);
#if 0
_dbus_verbose (" type reader %p current type_pos = %d type = %s\n",
reader, reader->type_pos,
_dbus_type_to_string (t));
#endif
return t;
}
dbus_bool_t
_dbus_type_reader_array_is_empty (DBusTypeReader *reader)
{
dbus_uint32_t array_len;
int len_pos;
_dbus_return_val_if_fail (_dbus_type_reader_get_current_type (reader) == DBUS_TYPE_ARRAY,
TRUE);
len_pos = _DBUS_ALIGN_VALUE (reader->value_pos, 4);
_dbus_demarshal_basic_type (reader->value_str,
DBUS_TYPE_UINT32,
&array_len,
reader->byte_order,
&len_pos);
return array_len == 0;
}
void
_dbus_type_reader_read_basic (DBusTypeReader *reader,
void *value)
{
if (reader->container_type == DBUS_TYPE_INVALID ||
reader->container_type == DBUS_TYPE_STRUCT ||
reader->container_type == DBUS_TYPE_ARRAY)
{
int t;
int next;
t = _dbus_type_reader_get_current_type (reader);
next = reader->value_pos;
_dbus_demarshal_basic_type (reader->value_str,
t, value,
reader->byte_order,
&next);
_dbus_verbose (" type reader %p read basic type_pos = %d value_pos = %d next = %d remaining sig '%s'\n",
reader, reader->type_pos, reader->value_pos, next,
_dbus_string_get_const_data_len (reader->type_str, reader->type_pos, 0));
}
else
{
_dbus_assert_not_reached ("reader->container_type should not be set to this");
}
}
dbus_bool_t
_dbus_type_reader_read_array_of_basic (DBusTypeReader *reader,
int type,
void **array,
int *array_len)
{
}
/**
* Initialize a new reader pointing to the first type and
* corresponding value that's a child of the current container. It's
* an error to call this if the current type is a non-container.
*
* Note that DBusTypeReader traverses values, not types. So if you
* have an empty array of array of int, you can't recurse into it. You
* can only recurse into each element.
*
* @param reader the reader
* @param sub a reader to init pointing to the first child
*/
void
_dbus_type_reader_recurse (DBusTypeReader *reader,
DBusTypeReader *sub)
static int
struct_reader_get_current_type (DBusTypeReader *reader)
{
int t;
t = first_type_in_signature (reader->type_str, reader->type_pos);
/* point subreader at the same place as reader */
_dbus_type_reader_init (sub,
reader->byte_order,
reader->type_str,
reader->type_pos,
reader->value_str,
reader->value_pos);
if (t == DBUS_TYPE_STRUCT)
{
sub->container_type = DBUS_TYPE_STRUCT;
sub->type_pos += 1;
/* struct has 8 byte alignment */
sub->value_pos = _DBUS_ALIGN_VALUE (sub->value_pos, 8);
sub->u.strct.finished = FALSE;
}
else if (t == DBUS_TYPE_ARRAY)
{
dbus_uint32_t array_len;
int alignment;
_dbus_return_if_fail (!_dbus_type_reader_array_is_empty (reader));
sub->container_type = DBUS_TYPE_ARRAY;
/* point type_pos at the array element type */
sub->type_pos += 1;
sub->value_pos = _DBUS_ALIGN_VALUE (sub->value_pos, 4);
_dbus_demarshal_basic_type (sub->value_str,
DBUS_TYPE_UINT32,
&array_len,
sub->byte_order,
&sub->value_pos);
sub->u.array.len = array_len;
alignment = element_type_get_alignment (sub->type_str,
sub->type_pos);
sub->value_pos = _DBUS_ALIGN_VALUE (sub->value_pos, alignment);
sub->u.array.element_type = first_type_in_signature (sub->type_str,
sub->type_pos);
sub->u.array.start_pos = sub->value_pos;
_dbus_verbose (" type reader %p array start = %d array len = %d array element type = %s\n",
reader,
sub->u.array.start_pos,
sub->u.array.len,
_dbus_type_to_string (sub->u.array.element_type));
}
if (reader->u.strct.finished)
t = DBUS_TYPE_INVALID;
else
{
_dbus_verbose ("recursing into type %s\n", _dbus_type_to_string (t));
#ifndef DBUS_DISABLE_CHECKS
if (t == DBUS_TYPE_INVALID)
_dbus_warn ("You can't recurse into an empty array or off the end of a message body\n");
#endif /* DBUS_DISABLE_CHECKS */
_dbus_assert_not_reached ("don't yet handle recursing into this type");
}
t = first_type_in_signature (reader->type_str,
reader->type_pos);
_dbus_verbose (" type reader %p RECURSED type_pos = %d value_pos = %d remaining sig '%s'\n",
sub, sub->type_pos, sub->value_pos,
_dbus_string_get_const_data_len (sub->type_str, sub->type_pos, 0));
return t;
}
static int
array_reader_get_current_type (DBusTypeReader *reader)
{
int t;
int end_pos;
/* return the array element type if elements remain, and
* TYPE_INVALID otherwise
*/
end_pos = reader->u.array.start_pos + reader->u.array.len;
_dbus_assert (reader->value_pos <= end_pos);
_dbus_assert (reader->value_pos >= reader->u.array.start_pos);
if (reader->value_pos < end_pos)
t = reader->u.array.element_type;
else
t = DBUS_TYPE_INVALID;
return t;
}
static void
@ -337,6 +251,275 @@ skip_array_values (int element_type,
*value_pos = pos + array_len;
}
static void
base_reader_next (DBusTypeReader *reader,
int current_type)
{
switch (current_type)
{
case DBUS_TYPE_STRUCT:
/* Scan forward over the entire container contents */
{
DBusTypeReader sub;
/* Recurse into the struct */
_dbus_type_reader_recurse (reader, &sub);
/* Skip everything in this subreader */
while (_dbus_type_reader_next (&sub))
{
/* nothing */;
}
/* Now we are at the end of this container */
reader->type_pos = sub.type_pos;
reader->value_pos = sub.value_pos;
}
break;
case DBUS_TYPE_ARRAY:
{
skip_array_values (first_type_in_signature (reader->type_str,
reader->type_pos + 1),
reader->value_str, &reader->value_pos, reader->byte_order);
skip_one_complete_type (reader->type_str, &reader->type_pos);
}
break;
default:
_dbus_marshal_skip_basic_type (reader->value_str,
current_type, reader->byte_order,
&reader->value_pos);
reader->type_pos += 1;
break;
}
}
static void
struct_reader_next (DBusTypeReader *reader,
int current_type)
{
int t;
base_reader_next (reader, current_type);
/* for STRUCT containers we return FALSE at the end of the struct,
* for INVALID we return FALSE at the end of the signature.
* In both cases we arrange for get_current_type() to return INVALID
* which is defined to happen iff we're at the end (no more next())
*/
t = _dbus_string_get_byte (reader->type_str, reader->type_pos);
if (t == DBUS_STRUCT_END_CHAR)
{
reader->type_pos += 1;
reader->u.strct.finished = TRUE;
}
}
static void
array_reader_next (DBusTypeReader *reader,
int current_type)
{
/* Skip one array element */
int end_pos;
end_pos = reader->u.array.start_pos + reader->u.array.len;
_dbus_assert (reader->value_pos < end_pos);
_dbus_assert (reader->value_pos >= reader->u.array.start_pos);
if (reader->u.array.element_type == DBUS_TYPE_STRUCT)
{
DBusTypeReader sub;
/* Recurse into the struct */
_dbus_type_reader_recurse (reader, &sub);
/* Skip everything in this element */
while (_dbus_type_reader_next (&sub))
{
/* nothing */;
}
/* Now we are at the end of this element */
reader->value_pos = sub.value_pos;
}
else if (reader->u.array.element_type == DBUS_TYPE_ARRAY)
{
skip_array_values (first_type_in_signature (reader->type_str,
reader->type_pos + 1),
reader->value_str, &reader->value_pos, reader->byte_order);
}
else
{
_dbus_marshal_skip_basic_type (reader->value_str,
current_type, reader->byte_order,
&reader->value_pos);
}
_dbus_assert (reader->value_pos <= end_pos);
if (reader->value_pos == end_pos)
{
skip_one_complete_type (reader->type_str,
&reader->type_pos);
}
}
static const DBusTypeReaderClass body_reader_class = {
"body",
NULL, /* body is always toplevel, so doesn't get recursed into */
body_reader_get_current_type,
base_reader_next
};
static const DBusTypeReaderClass struct_reader_class = {
"struct",
struct_reader_recurse,
struct_reader_get_current_type,
struct_reader_next
};
static const DBusTypeReaderClass array_reader_class = {
"array",
array_reader_recurse,
array_reader_get_current_type,
array_reader_next
};
void
_dbus_type_reader_init (DBusTypeReader *reader,
int byte_order,
const DBusString *type_str,
int type_pos,
const DBusString *value_str,
int value_pos)
{
reader->klass = &body_reader_class;
reader_init (reader, byte_order, type_str, type_pos,
value_str, value_pos);
_dbus_verbose (" type reader %p init type_pos = %d value_pos = %d remaining sig '%s'\n",
reader, reader->type_pos, reader->value_pos,
_dbus_string_get_const_data_len (reader->type_str, reader->type_pos, 0));
}
int
_dbus_type_reader_get_current_type (DBusTypeReader *reader)
{
int t;
t = (* reader->klass->get_current_type) (reader);
_dbus_assert (t != DBUS_STRUCT_END_CHAR);
_dbus_assert (t != DBUS_STRUCT_BEGIN_CHAR);
#if 0
_dbus_verbose (" type reader %p current type_pos = %d type = %s\n",
reader, reader->type_pos,
_dbus_type_to_string (t));
#endif
return t;
}
dbus_bool_t
_dbus_type_reader_array_is_empty (DBusTypeReader *reader)
{
dbus_uint32_t array_len;
int len_pos;
_dbus_return_val_if_fail (_dbus_type_reader_get_current_type (reader) == DBUS_TYPE_ARRAY,
TRUE);
len_pos = _DBUS_ALIGN_VALUE (reader->value_pos, 4);
_dbus_demarshal_basic_type (reader->value_str,
DBUS_TYPE_UINT32,
&array_len,
reader->byte_order,
&len_pos);
return array_len == 0;
}
void
_dbus_type_reader_read_basic (DBusTypeReader *reader,
void *value)
{
int t;
int next;
t = _dbus_type_reader_get_current_type (reader);
next = reader->value_pos;
_dbus_demarshal_basic_type (reader->value_str,
t, value,
reader->byte_order,
&next);
_dbus_verbose (" type reader %p read basic type_pos = %d value_pos = %d next = %d remaining sig '%s'\n",
reader, reader->type_pos, reader->value_pos, next,
_dbus_string_get_const_data_len (reader->type_str, reader->type_pos, 0));
}
dbus_bool_t
_dbus_type_reader_read_array_of_basic (DBusTypeReader *reader,
int type,
void **array,
int *array_len)
{
}
/**
* Initialize a new reader pointing to the first type and
* corresponding value that's a child of the current container. It's
* an error to call this if the current type is a non-container.
*
* Note that DBusTypeReader traverses values, not types. So if you
* have an empty array of array of int, you can't recurse into it. You
* can only recurse into each element.
*
* @param reader the reader
* @param sub a reader to init pointing to the first child
*/
void
_dbus_type_reader_recurse (DBusTypeReader *reader,
DBusTypeReader *sub)
{
int t;
t = first_type_in_signature (reader->type_str, reader->type_pos);
switch (t)
{
case DBUS_TYPE_STRUCT:
sub->klass = &struct_reader_class;
break;
case DBUS_TYPE_ARRAY:
sub->klass = &array_reader_class;
break;
default:
_dbus_verbose ("recursing into type %s\n", _dbus_type_to_string (t));
#ifndef DBUS_DISABLE_CHECKS
if (t == DBUS_TYPE_INVALID)
_dbus_warn ("You can't recurse into an empty array or off the end of a message body\n");
#endif /* DBUS_DISABLE_CHECKS */
_dbus_assert_not_reached ("don't yet handle recursing into this type");
}
(* sub->klass->recurse) (sub, reader);
_dbus_verbose (" type reader %p RECURSED type_pos = %d value_pos = %d remaining sig '%s'\n",
sub, sub->type_pos, sub->value_pos,
_dbus_string_get_const_data_len (sub->type_str, sub->type_pos, 0));
}
/**
* Skip to the next value on this "level". e.g. the next field in a
* struct, the next value in an array, the next key or value in a
@ -359,115 +542,8 @@ _dbus_type_reader_next (DBusTypeReader *reader)
if (t == DBUS_TYPE_INVALID)
return FALSE;
if (reader->container_type == DBUS_TYPE_INVALID ||
reader->container_type == DBUS_TYPE_STRUCT)
{
switch (t)
{
case DBUS_TYPE_STRUCT:
/* Scan forward over the entire container contents */
{
DBusTypeReader sub;
/* Recurse into the struct */
_dbus_type_reader_recurse (reader, &sub);
/* Skip everything in this subreader */
while (_dbus_type_reader_next (&sub))
{
/* nothing */;
}
/* Now we are at the end of this container */
reader->type_pos = sub.type_pos;
reader->value_pos = sub.value_pos;
}
break;
case DBUS_TYPE_ARRAY:
{
skip_array_values (first_type_in_signature (reader->type_str,
reader->type_pos + 1),
reader->value_str, &reader->value_pos, reader->byte_order);
skip_one_complete_type (reader->type_str, &reader->type_pos);
}
break;
default:
_dbus_marshal_skip_basic_type (reader->value_str,
t, reader->byte_order,
&reader->value_pos);
reader->type_pos += 1;
break;
}
/* for STRUCT containers we return FALSE at the end of the struct,
* for INVALID we return FALSE at the end of the signature.
* In both cases we arrange for get_current_type() to return INVALID
* which is defined to happen iff we're at the end (no more next())
*/
if (reader->container_type == DBUS_TYPE_STRUCT)
{
t = _dbus_string_get_byte (reader->type_str, reader->type_pos);
if (t == DBUS_STRUCT_END_CHAR)
{
reader->type_pos += 1;
reader->u.strct.finished = TRUE;
}
}
}
else if (reader->container_type == DBUS_TYPE_ARRAY)
{
/* Skip one array element */
int end_pos;
end_pos = reader->u.array.start_pos + reader->u.array.len;
_dbus_assert (reader->value_pos < end_pos);
_dbus_assert (reader->value_pos >= reader->u.array.start_pos);
if (reader->u.array.element_type == DBUS_TYPE_STRUCT)
{
DBusTypeReader sub;
/* Recurse into the struct */
_dbus_type_reader_recurse (reader, &sub);
/* Skip everything in this element */
while (_dbus_type_reader_next (&sub))
{
/* nothing */;
}
/* Now we are at the end of this element */
reader->value_pos = sub.value_pos;
}
else if (reader->u.array.element_type == DBUS_TYPE_ARRAY)
{
skip_array_values (first_type_in_signature (reader->type_str,
reader->type_pos + 1),
reader->value_str, &reader->value_pos, reader->byte_order);
}
else
{
_dbus_marshal_skip_basic_type (reader->value_str,
t, reader->byte_order,
&reader->value_pos);
}
_dbus_assert (reader->value_pos <= end_pos);
if (reader->value_pos == end_pos)
{
skip_one_complete_type (reader->type_str,
&reader->type_pos);
}
}
else
{
_dbus_assert_not_reached ("reader->container_type should not be set to this");
}
(* reader->klass->next) (reader, t);
_dbus_verbose (" type reader %p END next() type_pos = %d value_pos = %d remaining sig '%s' current_type = %s\n",
reader, reader->type_pos, reader->value_pos,

View file

@ -31,23 +31,10 @@
#error "config.h not included here"
#endif
/* Notes on my plan to implement this:
* - also have DBusTypeWriter (heh)
* - TypeReader has accessors for:
* . basic type
* . array of basic type (efficiency hack)
* . another type reader
* - a dict will appear to be a list of string, whatever, string, whatever
* - a variant will contain another TypeReader
* - a struct will be a list of whatever, whatever, whatever
*
* So the basic API usage is to go next, next, next; if the
* item is a basic type or basic array then read the item;
* if it's another type reader then process it; if it's
* a container type (struct, array, variant, dict) then
* recurse.
*
*/
typedef struct DBusTypeReader DBusTypeReader;
typedef struct DBusTypeWriter DBusTypeWriter;
typedef struct DBusTypeReaderClass DBusTypeReaderClass;
typedef struct DBusTypeWriterClass DBusTypeWriterClass;
struct DBusTypeReader
{
@ -57,8 +44,7 @@ struct DBusTypeReader
const DBusString *value_str;
int value_pos;
/* Hmm - it might be cleaner to do TypeReaderClass *vtable for container type */
int container_type;
const DBusTypeReaderClass *klass;
union
{
struct {
@ -78,8 +64,6 @@ struct DBusTypeReader
} u;
};
typedef struct DBusTypeReader DBusTypeReader;
struct DBusTypeWriter
{
int byte_order;
@ -90,6 +74,7 @@ struct DBusTypeWriter
dbus_uint32_t inside_array : 1;
/* const DBusTypeWriterClass *klass; */
int container_type;
union
{
@ -107,8 +92,6 @@ struct DBusTypeWriter
} u;
};
typedef struct DBusTypeWriter DBusTypeWriter;
void _dbus_type_reader_init (DBusTypeReader *reader,
int byte_order,
const DBusString *type_str,