static char *array_to_string_internal __P((ARRAY_ELEMENT *, ARRAY_ELEMENT *, char *, int));
+/* lastref should be moved into the array structure so each array can be
+ optimized separately */
+
+static ARRAY *lastarray = 0;
+static ARRAY_ELEMENT *lastref = 0;
+
+#define IS_LASTREF(a) (lastarray && (a) == lastarray)
+
+#define LASTREF_START(a, i) \
+ (IS_LASTREF(a) && i >= element_index(lastref)) ? lastref \
+ : element_forw(a->head)
+
+#define INVALIDATE_LASTREF(a) \
+do { \
+ if ((a) == lastarray) { \
+ lastarray = 0; \
+ lastref = 0; \
+ } \
+} while (0)
+
+#define SET_LASTREF(a, e) \
+do { \
+ lastarray = (a); \
+ lastref = (e); \
+} while (0)
+
+#define UNSET_LASTREF() \
+do { \
+ lastarray = 0; \
+ lastref = 0; \
+} while (0)
+
ARRAY *
array_create()
{
a->head->next = a->head->prev = a->head;
a->max_index = -1;
a->num_elements = 0;
+ INVALIDATE_LASTREF(a);
}
void
if (a == 0 || array_empty(a) || n <= 0)
return ((ARRAY_ELEMENT *)NULL);
+ INVALIDATE_LASTREF(a);
for (i = 0, ret = ae = element_forw(a->head); ae != a->head && i < n; ae = element_forw(ae), i++)
;
if (ae == a->head) {
element_index(ae) -= n; /* renumber retained indices */
a->num_elements -= n; /* modify bookkeeping information */
- a->max_index -= n;
+ a->max_index = element_index(a->head->prev);
if (flags & AS_DISPOSE) {
for (ae = ret; ae; ) {
new = array_create_element(0, s);
ADD_BEFORE(ae, new);
a->num_elements++;
- if (array_num_elements(a) == 1) /* array was empty */
+ if (array_num_elements(a) == 1) { /* array was empty */
+ a->max_index = 0;
return 1;
+ }
}
/*
a->max_index = element_index(a->head->prev);
+ INVALIDATE_LASTREF(a);
return (a->num_elements);
}
arrayind_t i;
char *v;
{
- register ARRAY_ELEMENT *new, *ae;
+ register ARRAY_ELEMENT *new, *ae, *start;
if (a == 0)
return(-1);
ADD_BEFORE(a->head, new);
a->max_index = i;
a->num_elements++;
+ SET_LASTREF(a, new);
return(0);
}
+#if OPTIMIZE_SEQUENTIAL_ARRAY_ASSIGNMENT
/*
- * Otherwise we search for the spot to insert it.
+ * Otherwise we search for the spot to insert it. The lastref
+ * handle optimizes the case of sequential or almost-sequential
+ * assignments that are not at the end of the array.
*/
- for (ae = element_forw(a->head); ae != a->head; ae = element_forw(ae)) {
+ start = LASTREF_START(a, i);
+#else
+ start = element_forw(ae->head);
+#endif
+ for (ae = start; ae != a->head; ae = element_forw(ae)) {
if (element_index(ae) == i) {
/*
* Replacing an existing element.
array_dispose_element(new);
free(element_value(ae));
ae->value = v ? savestring(v) : (char *)NULL;
+ SET_LASTREF(a, ae);
return(0);
} else if (element_index(ae) > i) {
ADD_BEFORE(ae, new);
a->num_elements++;
+ SET_LASTREF(a, new);
return(0);
}
}
+ array_dispose_element(new);
+ INVALIDATE_LASTREF(a);
return (-1); /* problem */
}
ARRAY *a;
arrayind_t i;
{
- register ARRAY_ELEMENT *ae;
+ register ARRAY_ELEMENT *ae, *start;
if (a == 0 || array_empty(a))
return((ARRAY_ELEMENT *) NULL);
- for (ae = element_forw(a->head); ae != a->head; ae = element_forw(ae))
+ start = LASTREF_START(a, i);
+ for (ae = start; ae != a->head; ae = element_forw(ae))
if (element_index(ae) == i) {
ae->next->prev = ae->prev;
ae->prev->next = ae->next;
a->num_elements--;
if (i == array_max_index(a))
a->max_index = element_index(ae->prev);
+#if 0
+ INVALIDATE_LASTREF(a);
+#else
+ if (ae->next != a->head)
+ SET_LASTREF(a, ae->next);
+ else if (ae->prev != a->head)
+ SET_LASTREF(a, ae->prev);
+ else
+ INVALIDATE_LASTREF(a);
+#endif
return(ae);
}
return((ARRAY_ELEMENT *) NULL);
ARRAY *a;
arrayind_t i;
{
- register ARRAY_ELEMENT *ae;
+ register ARRAY_ELEMENT *ae, *start;
if (a == 0 || array_empty(a))
return((char *) NULL);
- for (ae = element_forw(a->head); ae != a->head; ae = element_forw(ae))
- if (element_index(ae) == i)
+ if (i > array_max_index(a))
+ return((char *)NULL); /* Keep roving pointer into array to optimize sequential access */
+ start = LASTREF_START(a, i);
+ for (ae = start; ae != a->head; ae = element_forw(ae))
+ if (element_index(ae) == i) {
+ SET_LASTREF(a, ae);
return(element_value(ae));
+ }
+ UNSET_LASTREF(); /* XXX SET_LASTREF(a, start) ? */
return((char *) NULL);
}
rsize, rsize);
strcpy(result + rlen, t);
rlen += reg;
- if (quoted && t)
+ if (quoted)
free(t);
/*
* Add a separator only after non-null elements.
for (ae = element_forw(a->head); ae != a->head; ae = element_forw(ae)) {
is = inttostr (element_index(ae), indstr, sizeof(indstr));
- valstr = element_value (ae) ? sh_double_quote (element_value(ae))
+ valstr = element_value (ae) ?
+ (ansic_shouldquote (element_value (ae)) ?
+ ansic_quote (element_value(ae), 0, (int *)0) :
+ sh_double_quote (element_value (ae)))
: (char *)NULL;
elen = STRLEN (is) + 8 + STRLEN (valstr);
RESIZE_MALLOCED_BUFFER (result, rlen, (elen + 1), rsize, rsize);