Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

reduced preallocation of attributes on stack

  • Loading branch information...
commit c6d6539c71b3868f28a34c935b47a2a657268bdb 1 parent e4e18f2
@ohler55 authored
View
109 ext/ox/attr.h
@@ -0,0 +1,109 @@
+/* attr.h
+ * Copyright (c) 2011, Peter Ohler
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * - Neither the name of Peter Ohler nor the names of its contributors may be
+ * used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __OX_ATTR_H__
+#define __OX_ATTR_H__
+
+#include "ox.h"
+
+#define ATTR_STACK_INC 16
+
+typedef struct _Attr {
+ const char *name;
+ const char *value;
+} *Attr;
+
+typedef struct _AttrStack {
+ struct _Attr base[ATTR_STACK_INC];
+ Attr head; /* current stack */
+ Attr end; /* stack end */
+ Attr tail; /* pointer to one past last element name on stack */
+} *AttrStack;
+
+inline static void
+attr_stack_init(AttrStack stack) {
+ stack->head = stack->base;
+ stack->end = stack->base + sizeof(stack->base) / sizeof(struct _Attr);
+ stack->tail = stack->head;
+ stack->head->name = 0;
+}
+
+inline static int
+attr_stack_empty(AttrStack stack) {
+ return (stack->head == stack->base);
+}
+
+inline static void
+attr_stack_cleanup(AttrStack stack) {
+ if (stack->base != stack->head) {
+ xfree(stack->head);
+ stack->head = stack->base;
+ }
+}
+
+inline static void
+attr_stack_push(AttrStack stack, const char *name, const char *value) {
+ if (stack->end <= stack->tail + 1) {
+ size_t len = stack->end - stack->head;
+ size_t toff = stack->tail - stack->head;
+
+ if (stack->base == stack->head) {
+ stack->head = ALLOC_N(struct _Attr, len + ATTR_STACK_INC);
+ memcpy(stack->head, stack->base, sizeof(struct _Attr) * len);
+ } else {
+ REALLOC_N(stack->head, struct _Attr, len + ATTR_STACK_INC);
+ }
+ stack->tail = stack->head + toff;
+ stack->end = stack->head + len + ATTR_STACK_INC;
+ }
+ stack->tail->name = name;
+ stack->tail->value = value;
+ stack->tail++;
+ stack->tail->name = 0; // terminate
+}
+
+inline static Attr
+attr_stack_peek(AttrStack stack) {
+ if (stack->head < stack->tail) {
+ return stack->tail - 1;
+ }
+ return 0;
+}
+
+inline static Attr
+attr_stack_pop(AttrStack stack) {
+ if (stack->head < stack->tail) {
+ stack->tail--;
+ return stack->tail;
+ }
+ return 0;
+}
+
+#endif /* __OX_ATTR_H__ */
View
109 ext/ox/helper.h
@@ -0,0 +1,109 @@
+/* helper.h
+ * Copyright (c) 2011, Peter Ohler
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * - Neither the name of Peter Ohler nor the names of its contributors may be
+ * used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __OX_HELPER_H__
+#define __OX_HELPER_H__
+
+#include "type.h"
+
+#define HELPER_STACK_INC 16
+
+typedef struct _Helper {
+ ID var; /* Object var ID */
+ VALUE obj; /* object created or Qundef if not appropriate */
+ Type type; /* type of object in obj */
+} *Helper;
+
+typedef struct _HelperStack {
+ struct _Helper base[HELPER_STACK_INC];
+ Helper head; /* current stack */
+ Helper end; /* stack end */
+ Helper tail; /* pointer to one past last element name on stack */
+} *HelperStack;
+
+inline static void
+helper_stack_init(HelperStack stack) {
+ stack->head = stack->base;
+ stack->end = stack->base + sizeof(stack->base) / sizeof(struct _Helper);
+ stack->tail = stack->head;
+}
+
+inline static int
+helper_stack_empty(HelperStack stack) {
+ return (stack->head == stack->base);
+}
+
+inline static void
+helper_stack_cleanup(HelperStack stack) {
+ if (stack->base != stack->head) {
+ xfree(stack->head);
+ stack->head = stack->base;
+ }
+}
+
+inline static void
+helper_stack_push(HelperStack stack, ID var, VALUE obj, Type type) {
+ if (stack->end <= stack->tail) {
+ size_t len = stack->end - stack->head;
+ size_t toff = stack->tail - stack->head;
+
+ if (stack->base == stack->head) {
+ stack->head = ALLOC_N(struct _Helper, len + HELPER_STACK_INC);
+ memcpy(stack->head, stack->base, sizeof(struct _Helper) * len);
+ } else {
+ REALLOC_N(stack->head, struct _Helper, len + HELPER_STACK_INC);
+ }
+ stack->tail = stack->head + toff;
+ stack->end = stack->head + len + HELPER_STACK_INC;
+ }
+ stack->tail->var = var;
+ stack->tail->obj = obj;
+ stack->tail->type = type;
+ stack->tail++;
+}
+
+inline static Helper
+helper_stack_peek(HelperStack stack) {
+ if (stack->head < stack->tail) {
+ return stack->tail - 1;
+ }
+ return 0;
+}
+
+inline static Helper
+helper_stack_pop(HelperStack stack) {
+ if (stack->head < stack->tail) {
+ stack->tail--;
+ return stack->tail;
+ }
+ return 0;
+}
+
+#endif /* __OX_HELPER_H__ */
View
1  ext/ox/ox.c
@@ -39,7 +39,6 @@
/* maximum to allocate on the stack, arbitrary limit */
#define SMALL_XML 4096
-//#define SMALL_XML 65536
typedef struct _YesNoOpt {
VALUE sym;
View
45 ext/ox/ox.h
@@ -59,10 +59,13 @@ enum st_retval {ST_CONTINUE = 0, ST_STOP = 1, ST_DELETE = 2, ST_CHECK};
#include "cache.h"
+#include "type.h"
+#include "attr.h"
+#include "helper.h"
+
#define raise_error(msg, xml, current) _ox_raise_error(msg, xml, current, __FILE__, __LINE__)
#define MAX_TEXT_LEN 4096
-#define MAX_ATTRS 256
#define MAX_DEPTH 1024
#define SILENT 0
@@ -115,46 +118,6 @@ typedef enum {
NoMode = 0
} LoadMode;
-typedef enum {
- NoCode = 0,
- ArrayCode = 'a',
- String64Code = 'b', /* base64 encoded String */
- ClassCode = 'c',
- Symbol64Code = 'd', /* base64 encoded Symbol */
- DateCode = 'D',
- ExceptionCode = 'e',
- FloatCode = 'f',
- RegexpCode = 'g',
- HashCode = 'h',
- FixnumCode = 'i',
- BignumCode = 'j',
- KeyCode = 'k', /* indicates the value is a hash key, kind of a hack */
- RationalCode = 'l',
- SymbolCode = 'm',
- FalseClassCode = 'n',
- ObjectCode = 'o',
- RefCode = 'p',
- RangeCode = 'r',
- StringCode = 's',
- TimeCode = 't',
- StructCode = 'u',
- ComplexCode = 'v',
- RawCode = 'x',
- TrueClassCode = 'y',
- NilClassCode = 'z',
-} Type;
-
-typedef struct _Attr {
- const char *name;
- const char *value;
-} *Attr;
-
-typedef struct _Helper {
- ID var; /* Object var ID */
- VALUE obj; /* object created or Qundef if not appropriate */
- Type type; /* type of object in obj */
-} *Helper;
-
typedef struct _PInfo *PInfo;
typedef struct _ParseCallbacks {
View
78 ext/ox/parse.c
@@ -35,6 +35,8 @@
#include "ruby.h"
#include "ox.h"
+#include "attr.h"
+#include "helper.h"
static void read_instruction(PInfo pi);
static void read_doctype(PInfo pi);
@@ -191,16 +193,18 @@ gather_content(const char *src, char *content, size_t len) {
static void
read_instruction(PInfo pi) {
char content[1024];
- struct _Attr attrs[MAX_ATTRS + 1];
- Attr a = attrs;
+ struct _AttrStack attrs;
+ char *attr_name;
+ char *attr_value;
char *target;
char *end;
char c;
char *cend;
int attrs_ok = 1;
+
*content = '\0';
- memset(attrs, 0, sizeof(attrs));
+ attr_stack_init(&attrs);
target = read_name_token(pi);
end = pi->s;
if (0 == (cend = gather_content(pi->s, content, sizeof(content) - 1))) {
@@ -213,10 +217,11 @@ read_instruction(PInfo pi) {
while ('?' != c) {
pi->last = 0;
if ('\0' == *pi->s) {
+ attr_stack_cleanup(&attrs);
raise_error("invalid format, processing instruction not terminated", pi->str, pi->s);
}
next_non_white(pi);
- a->name = read_name_token(pi);
+ attr_name = read_name_token(pi);
end = pi->s;
next_non_white(pi);
if ('=' != *pi->s++) {
@@ -226,12 +231,8 @@ read_instruction(PInfo pi) {
*end = '\0'; /* terminate name */
/* read value */
next_non_white(pi);
- a->value = read_quoted_value(pi);
- a++;
- if (MAX_ATTRS <= (a - attrs)) {
- attrs_ok = 0;
- break;
- }
+ attr_value = read_quoted_value(pi);
+ attr_stack_push(&attrs, attr_name, attr_value);
next_non_white(pi);
if ('\0' == pi->last) {
c = *pi->s;
@@ -247,6 +248,7 @@ read_instruction(PInfo pi) {
}
if (attrs_ok) {
if ('>' != *pi->s++) {
+ attr_stack_cleanup(&attrs);
raise_error("invalid format, processing instruction not terminated", pi->str, pi->s);
}
} else {
@@ -254,11 +256,12 @@ read_instruction(PInfo pi) {
}
if (0 != pi->pcb->instruct) {
if (attrs_ok) {
- pi->pcb->instruct(pi, target, attrs, 0);
+ pi->pcb->instruct(pi, target, attrs.head, 0);
} else {
- pi->pcb->instruct(pi, target, attrs, content);
+ pi->pcb->instruct(pi, target, attrs.head, content);
}
}
+ attr_stack_cleanup(&attrs);
}
/* Entered after the "<!DOCTYPE" sequence plus the first character after
@@ -334,8 +337,9 @@ read_comment(PInfo pi) {
*/
static char*
read_element(PInfo pi) {
- struct _Attr attrs[MAX_ATTRS];
- Attr ap = attrs;
+ struct _AttrStack attrs;
+ const char *attr_name;
+ const char *attr_value;
char *name;
char *ename;
char *end;
@@ -344,6 +348,7 @@ read_element(PInfo pi) {
int hasChildren = 0;
int done = 0;
+ attr_stack_init(&attrs);
ename = read_name_token(pi);
end = pi->s;
elen = end - ename;
@@ -355,13 +360,14 @@ read_element(PInfo pi) {
pi->s++;
if ('>' != *pi->s) {
/*printf("*** '%s' ***\n", pi->s); */
+ attr_stack_cleanup(&attrs);
raise_error("invalid format, element not closed", pi->str, pi->s);
}
pi->s++; /* past > */
- ap->name = 0;
- pi->pcb->add_element(pi, ename, attrs, hasChildren);
+ pi->pcb->add_element(pi, ename, attrs.head, hasChildren);
pi->pcb->end_element(pi, ename);
+ attr_stack_cleanup(&attrs);
return 0;
}
/* read attribute names until the close (/ or >) is reached */
@@ -373,31 +379,32 @@ read_element(PInfo pi) {
pi->last = 0;
switch (c) {
case '\0':
+ attr_stack_cleanup(&attrs);
raise_error("invalid format, document not terminated", pi->str, pi->s);
case '/':
/* Element with just attributes. */
pi->s++;
if ('>' != *pi->s) {
+ attr_stack_cleanup(&attrs);
raise_error("invalid format, element not closed", pi->str, pi->s);
}
pi->s++;
- ap->name = 0;
- pi->pcb->add_element(pi, ename, attrs, hasChildren);
+ pi->pcb->add_element(pi, ename, attrs.head, hasChildren);
pi->pcb->end_element(pi, ename);
+ attr_stack_cleanup(&attrs);
return 0;
case '>':
/* has either children or a value */
pi->s++;
hasChildren = 1;
done = 1;
- ap->name = 0;
- pi->pcb->add_element(pi, ename, attrs, hasChildren);
+ pi->pcb->add_element(pi, ename, attrs.head, hasChildren);
break;
default:
/* Attribute name so it's an element and the attribute will be */
/* added to it. */
- ap->name = read_name_token(pi);
+ attr_name = read_name_token(pi);
end = pi->s;
next_non_white(pi);
if ('=' != *pi->s++) {
@@ -405,29 +412,25 @@ read_element(PInfo pi) {
pi->s--;
pi->last = *pi->s;
*end = '\0'; /* terminate name */
- ap->value = "";
- ap++;
- if (MAX_ATTRS <= (ap - attrs)) {
- raise_error("too many attributes", pi->str, pi->s);
- }
+ attr_value = "";
+ attr_stack_push(&attrs, attr_name, attr_value);
break;
} else {
+ attr_stack_cleanup(&attrs);
raise_error("invalid format, no attribute value", pi->str, pi->s);
}
}
*end = '\0'; /* terminate name */
/* read value */
next_non_white(pi);
- ap->value = read_quoted_value(pi);
- if (0 != strchr(ap->value, '&')) {
- if (0 != collapse_special(pi, (char*)ap->value)) {
+ attr_value = read_quoted_value(pi);
+ if (0 != strchr(attr_value, '&')) {
+ if (0 != collapse_special(pi, (char*)attr_value)) {
+ attr_stack_cleanup(&attrs);
raise_error("invalid format, special character does not end with a semicolon", pi->str, pi->s);
}
}
- ap++;
- if (MAX_ATTRS <= (ap - attrs)) {
- raise_error("too many attributes", pi->str, pi->s);
- }
+ attr_stack_push(&attrs, attr_name, attr_value);
break;
}
if ('\0' == pi->last) {
@@ -448,6 +451,7 @@ read_element(PInfo pi) {
next_non_white(pi);
c = *pi->s++;
if ('\0' == c) {
+ attr_stack_cleanup(&attrs);
raise_error("invalid format, document not terminated", pi->str, pi->s);
}
if ('<' == c) {
@@ -465,6 +469,7 @@ read_element(PInfo pi) {
pi->s += 7;
read_cdata(pi);
} else {
+ attr_stack_cleanup(&attrs);
raise_error("invalid format, invalid comment or CDATA format", pi->str, pi->s);
}
break;
@@ -481,6 +486,7 @@ read_element(PInfo pi) {
c = *pi->s;
*end = '\0';
if (0 != strcmp(name, ename)) {
+ attr_stack_cleanup(&attrs);
if (TolerantEffort == pi->options->effort) {
pi->pcb->end_element(pi, ename);
return name;
@@ -489,6 +495,7 @@ read_element(PInfo pi) {
}
}
if ('>' != c) {
+ attr_stack_cleanup(&attrs);
raise_error("invalid format, element not closed", pi->str, pi->s);
}
if (first && start != slash - 1) {
@@ -498,8 +505,10 @@ read_element(PInfo pi) {
}
pi->s++;
pi->pcb->end_element(pi, ename);
+ attr_stack_cleanup(&attrs);
return 0;
case '\0':
+ attr_stack_cleanup(&attrs);
if (TolerantEffort == pi->options->effort) {
return 0;
} else {
@@ -510,6 +519,7 @@ read_element(PInfo pi) {
/* a child element */
// Child closed with mismatched name.
if (0 != (name = read_element(pi))) {
+ attr_stack_cleanup(&attrs);
if (0 == strcmp(name, ename)) {
pi->s++;
pi->pcb->end_element(pi, ename);
@@ -534,11 +544,13 @@ read_element(PInfo pi) {
/* close tag after text so treat as a value */
pi->s += elen + 3;
pi->pcb->end_element(pi, ename);
+ attr_stack_cleanup(&attrs);
return 0;
}
}
}
}
+ attr_stack_cleanup(&attrs);
return 0;
}
View
63 ext/ox/type.h
@@ -0,0 +1,63 @@
+/* type.h
+ * Copyright (c) 2011, Peter Ohler
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * - Neither the name of Peter Ohler nor the names of its contributors may be
+ * used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __OX_TYPE_H__
+#define __OX_TYPE_H__
+
+typedef enum {
+ NoCode = 0,
+ ArrayCode = 'a',
+ String64Code = 'b', /* base64 encoded String */
+ ClassCode = 'c',
+ Symbol64Code = 'd', /* base64 encoded Symbol */
+ DateCode = 'D',
+ ExceptionCode = 'e',
+ FloatCode = 'f',
+ RegexpCode = 'g',
+ HashCode = 'h',
+ FixnumCode = 'i',
+ BignumCode = 'j',
+ KeyCode = 'k', /* indicates the value is a hash key, kind of a hack */
+ RationalCode = 'l',
+ SymbolCode = 'm',
+ FalseClassCode = 'n',
+ ObjectCode = 'o',
+ RefCode = 'p',
+ RangeCode = 'r',
+ StringCode = 's',
+ TimeCode = 't',
+ StructCode = 'u',
+ ComplexCode = 'v',
+ RawCode = 'x',
+ TrueClassCode = 'y',
+ NilClassCode = 'z',
+} Type;
+
+#endif /* __OX_TYPE_H__ */
View
6 notes
@@ -4,10 +4,8 @@
^c^s show subtree
- todo
- - max_stack
- - used for stack error
- - some fraction used for alloc up to a max
- - cut down on MAX_ATTRS and realloc when needed
+ - use helper stack in gen_load and obj_load
+
- continuous sax parser
- parse input stream and continue waiting for next one
Please sign in to comment.
Something went wrong with that request. Please try again.