<commit_before>#include "jsi.h"
#include "jsvalue.h"

#include <assert.h>

/*
	Use an AA-tree to quickly look up properties in objects:

	The level of every leaf node is one.
	The level of every left child is one less than its parent.
	The level of every right child is equal or one less than its parent.
	The level of every right grandchild is less than its grandparent.
	Every node of level greater than one has two children.

	A link where the child's level is equal to that of its parent is called a horizontal link.
	Individual right horizontal links are allowed, but consecutive ones are forbidden.
	Left horizontal links are forbidden.

	skew() fixes left horizontal links.
	split() fixes consecutive right horizontal links.
*/

static js_Property sentinel = {
	&sentinel, &sentinel,
	0, 0,
	{ {0}, {0}, JS_TUNDEFINED },
	NULL, NULL, ""
};

static js_Property *newproperty(js_State *J, js_Object *obj, const char *name)
{
	int n = strlen(name) + 1;
	js_Property *node = js_malloc(J, offsetof(js_Property, name) + n);
	node->left = node->right = &sentinel;
	node->level = 1;
	node->atts = 0;
	node->value.type = JS_TUNDEFINED;
	node->value.u.number = 0;
	node->getter = NULL;
	node->setter = NULL;
	memcpy(node->name, name, n);
	++obj->count;
	++J->gccounter;
	return node;
}

static js_Property *lookup(js_Property *node, const char *name)
{
	while (node != &sentinel) {
		int c = strcmp(name, node->name);
		if (c == 0)
			return node;
		else if (c < 0)
			node = node->left;
		else
			node = node->right;
	}
	return NULL;
}

static js_Property *skew(js_Property *node)
{
	if (node->left->level == node->level) {
		js_Property *temp = node;
		node = node->left;
		temp->left = node->right;
		node->right = temp;
	}
	return node;
}

static js_Property *split(js_Property *node)
{
	if (node->right->right->level == node->level) {
		js_Property *temp = node;
		node = node->right;
		temp->right = node->left;
		node->left = temp;
		++node->level;
	}
	return node;
}

static js_Property *insert(js_State *J, js_Object *obj, js_Property *node, const char *name, js_Property **result)
{
	if (node != &sentinel) {
		int c = strcmp(name, node->name);
		if (c < 0)
			node->left = insert(J, obj, node->left, name, result);
		else if (c > 0)
			node->right = insert(J, obj, node->right, name, result);
		else
			return *result = node;
		node = skew(node);
		node = split(node);
		return node;
	}
	return *result = newproperty(J, obj, name);
}

static void freeproperty(js_State *J, js_Object *obj, js_Property *node)
{
	js_free(J, node);
	--obj->count;
}

static js_Property *unlinkproperty(js_State *J, js_Object *obj, js_Property *node, const char *name, js_Property **garbage)
{
	js_Property *temp, *succ;

	if (node != &sentinel) {
		int c = strcmp(name, node->name);
		if (c < 0) {
			node->left = unlinkproperty(J, obj, node->left, name, garbage);
		} else if (c > 0) {
			node->right = unlinkproperty(J, obj, node->right, name, garbage);
		} else {
			if (node->left == &sentinel) {
				*garbage = node;
				node = node->right;
			} else if (node->right == &sentinel) {
				*garbage = node;
				node = node->left;
			} else {
				*garbage = node;
				succ = node->right;
				while (succ->left != &sentinel)
					succ = succ->left;
				succ->right = unlinkproperty(J, obj, node->right, succ->name, &temp);
				succ->left = node->left;
				node = succ;
			}
		}

		if (node->left->level < node->level - 1 ||
			node->right->level < node->level - 1)
		{
			if (node->right->level > --node->level)
				node->right->level = node->level;
			node = skew(node);
			node->right = skew(node->right);
			node->right->right = skew(node->right->right);
			node = split(node);
			node->right = split(node->right);
		}
	}
	return node;
}

static js_Property *deleteproperty(js_State *J, js_Object *obj, js_Property *tree, const char *name)
{
	js_Property *garbage = NULL;
	tree = unlinkproperty(J, obj, tree, name, &garbage);
	if (garbage != NULL)
		freeproperty(J, obj, garbage);
	return tree;
}

js_Object *jsV_newobject(js_State *J, enum js_Class type, js_Object *prototype)
{
	js_Object *obj = js_malloc(J, sizeof *obj);
	memset(obj, 0, sizeof *obj);
	obj->gcmark = 0;
	obj->gcnext = J->gcobj;
	J->gcobj = obj;
	++J->gccounter;

	obj->type = type;
	obj->properties = &sentinel;
	obj->prototype = prototype;<commit_msg>Bug 706075: Fix errors in property deletion.<commit_after>#include "jsi.h"
#include "jsvalue.h"

#include <assert.h>

/*
	Use an AA-tree to quickly look up properties in objects:

	The level of every leaf node is one.
	The level of every left child is one less than its parent.
	The level of every right child is equal or one less than its parent.
	The level of every right grandchild is less than its grandparent.
	Every node of level greater than one has two children.

	A link where the child's level is equal to that of its parent is called a horizontal link.
	Individual right horizontal links are allowed, but consecutive ones are forbidden.
	Left horizontal links are forbidden.

	skew() fixes left horizontal links.
	split() fixes consecutive right horizontal links.
*/

static js_Property sentinel = {
	&sentinel, &sentinel,
	0, 0,
	{ {0}, {0}, JS_TUNDEFINED },
	NULL, NULL, ""
};

static js_Property *newproperty(js_State *J, js_Object *obj, const char *name)
{
	int n = strlen(name) + 1;
	js_Property *node = js_malloc(J, offsetof(js_Property, name) + n);
	node->left = node->right = &sentinel;
	node->level = 1;
	node->atts = 0;
	node->value.type = JS_TUNDEFINED;
	node->value.u.number = 0;
	node->getter = NULL;
	node->setter = NULL;
	memcpy(node->name, name, n);
	++obj->count;
	++J->gccounter;
	return node;
}

static js_Property *lookup(js_Property *node, const char *name)
{
	while (node != &sentinel) {
		int c = strcmp(name, node->name);
		if (c == 0)
			return node;
		else if (c < 0)
			node = node->left;
		else
			node = node->right;
	}
	return NULL;
}

static js_Property *skew(js_Property *node)
{
	if (node->left->level == node->level) {
		js_Property *temp = node;
		node = node->left;
		temp->left = node->right;
		node->right = temp;
	}
	return node;
}

static js_Property *split(js_Property *node)
{
	if (node->right->right->level == node->level) {
		js_Property *temp = node;
		node = node->right;
		temp->right = node->left;
		node->left = temp;
		++node->level;
	}
	return node;
}

static js_Property *insert(js_State *J, js_Object *obj, js_Property *node, const char *name, js_Property **result)
{
	if (node != &sentinel) {
		int c = strcmp(name, node->name);
		if (c < 0)
			node->left = insert(J, obj, node->left, name, result);
		else if (c > 0)
			node->right = insert(J, obj, node->right, name, result);
		else
			return *result = node;
		node = skew(node);
		node = split(node);
		return node;
	}
	return *result = newproperty(J, obj, name);
}

static void freeproperty(js_State *J, js_Object *obj, js_Property *node)
{
	js_free(J, node);
	--obj->count;
}

static js_Property *unlinkproperty(js_Property *node, const char *name, js_Property **garbage)
{
	js_Property *temp, *a, *b;
	if (node != &sentinel) {
		int c = strcmp(name, node->name);
		if (c < 0) {
			node->left = unlinkproperty(node->left, name, garbage);
		} else if (c > 0) {
			node->right = unlinkproperty(node->right, name, garbage);
		} else {
			*garbage = node;
			if (node->left == &sentinel && node->right == &sentinel) {
				return &sentinel;
			}
			else if (node->left == &sentinel) {
				a = node->right;
				while (a->left != &sentinel)
					a = a->left;
				b = unlinkproperty(node->right, a->name, &temp);
				temp->level = node->level;
				temp->left = node->left;
				temp->right = b;
				node = temp;
			}
			else {
				a = node->left;
				while (a->right != &sentinel)
					a = a->right;
				b = unlinkproperty(node->left, a->name, &temp);
				temp->level = node->level;
				temp->left = b;
				temp->right = node->right;
				node = temp;
			}
		}

		if (node->left->level < node->level - 1 || node->right->level < node->level - 1)
		{
			if (node->right->level > --node->level)
				node->right->level = node->level;
			node = skew(node);
			node->right = skew(node->right);
			node->right->right = skew(node->right->right);
			node = split(node);
			node->right = split(node->right);
		}
	}
	return node;
}

static js_Property *deleteproperty(js_State *J, js_Object *obj, js_Property *tree, const char *name)
{
	js_Property *garbage = &sentinel;
	tree = unlinkproperty(tree, name, &garbage);
	if (garbage != &sentinel)
		freeproperty(J, obj, garbage);
	return tree;
}

js_Object *jsV_newobject(js_State *J, enum js_Class type, js_Object *prototype)
{
	js_Object *obj = js_malloc(J, sizeof *obj);
	memset(obj, 0, sizeof *obj);
	obj->gcmark = 0;
	obj->gcnext = J->gcobj;
	J->gcobj = obj;
	++J->gccounter;

	obj->type = type;
	obj->properties = &sentinel;
	obj->prototype = prototype;
{'fraction_non_alphanumeric': 0.15458772825224, 'fraction_numerical': 0.004763525008506295, 'mean_word_length': 3.5571059431524548, 'pattern_counts': {'":': 0, '<': 15, '<?xml version=': 0, '>': 184, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5722925', 'n_tokens_mistral': 3512, 'n_tokens_neox': 3175, 'n_words': 935}