<commit_before>/*
 * Redistribution and use in source and binary forms, with or
 * without modification, are permitted provided that the following
 * conditions are met:
 *
 * 1. Redistributions of source code must retain the above
 *    copyright notice, this list of conditions and the
 *    following disclaimer.
 *
 * 2. 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.
 *
 * THIS SOFTWARE IS PROVIDED BY <COPYRIGHT HOLDER> ``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
 * <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.
 */
#include "tree_index.h"
#include "tuple.h"
#include "space.h"
#include "exception.h"

/* {{{ Utilities. *************************************************/

struct sptree_index_node {
	struct tuple *tuple;
};

struct sptree_index_key_data
{
	const char *key;
	uint32_t part_count;
};

static inline struct tuple *
sptree_index_unfold(const void *node)
{
	if (node == NULL)
		return NULL;

	struct sptree_index_node *node_x = (struct sptree_index_node *) node;
	assert (node_x->tuple != NULL);
	return node_x->tuple;
}

static inline void
sptree_index_fold(void *node, struct tuple *tuple)
{
	assert (node != NULL);
	assert (tuple != NULL);

	struct sptree_index_node *node_x = (struct sptree_index_node *) node;
	node_x->tuple = tuple;
}

static int
sptree_index_node_compare(const void *node_a, const void *node_b, void *arg)
{
	TreeIndex *self = (TreeIndex *) arg;
	struct tuple *tuple_a = sptree_index_unfold(node_a);
	struct tuple *tuple_b = sptree_index_unfold(node_b);

	return tuple_compare(tuple_a, tuple_b, self->key_def);
}

static int
sptree_index_node_compare_dup(const void *node_a, const void *node_b, void *arg)
{
	TreeIndex *self = (TreeIndex *) arg;
	struct tuple *tuple_a = sptree_index_unfold(node_a);
	struct tuple *tuple_b = sptree_index_unfold(node_b);

	return tuple_compare_dup(tuple_a, tuple_b, self->key_def);
}

static int
sptree_index_node_compare_with_key(const void *key, const void *node, void *arg)
{
	TreeIndex *self = (TreeIndex *) arg;
	struct sptree_index_key_data *key_data =
			(struct sptree_index_key_data *) key;
	struct tuple *tuple = sptree_index_unfold(node);

	/* the result is inverted because arguments are swapped */
	return -tuple_compare_with_key(tuple, key_data->key,
				       key_data->part_count, self->key_def);
}

/* {{{ TreeIndex Iterators ****************************************/

struct tree_iterator {
	struct iterator base;
	const TreeIndex *index;
	struct sptree_index_iterator *iter;
	struct sptree_index_key_data key_data;
};

static void
tree_iterator_free(struct iterator *iterator);

static inline struct tree_iterator *
tree_iterator(struct iterator *it)
{
	assert(it->free == tree_iterator_free);
	return (struct tree_iterator *) it;
}

static void
tree_iterator_free(struct iterator *iterator)
{
	struct tree_iterator *it = tree_iterator(iterator);
	if (it->iter)
		sptree_index_iterator_free(it->iter);
	free(it);
}

static struct tuple *
tree_iterator_ge(struct iterator *iterator)
{
	struct tree_iterator *it = tree_iterator(iterator);
	void *node = sptree_index_iterator_next(it->iter);
	return sptree_index_unfold(node);
}

static struct tuple *
tree_iterator_le(struct iterator *iterator)
{
	struct tree_iterator *it = tree_iterator(iterator);
	void *node = sptree_index_iterator_reverse_next(it->iter);
	return sptree_index_unfold(node);
}

static struct tuple *
tree_iterator_eq(struct iterator *iterator)
{
	struct tree_iterator *it = tree_iterator(iterator);

	void *node = sptree_index_iterator_next(it->iter);
	if (node && it->index->tree.compare(&it->key_data, node,
					    (void *) it->index) == 0)
		return sptree_index_unfold(node);

	return NULL;
}

static struct tuple *
tree_iterator_req(struct iterator *iterator)
{
	struct tree_iterator *it = tree_iterator(iterator);

	void *node = sptree_index_iterator_reverse_next(it->iter);
	if (node != NULL
	    && it->index->tree.compare(&it->key_data, node,
				       (void *) it->index) == 0) {
		return sptree_index_unfold(node);
	}

	return NULL;
}

static struct tuple *
tree_iterator_lt(struct iterator *iterator)
{
	struct tree_iterator *it = tree_iterator(iterator);

	void *node ;
	while ((node = sptree_index_iterator_reverse_next(it->iter)) != NULL) {
		if (it->index->tree.compare(&it->key_data, node,
					    (void *) it->index) != 0) {
			it->base.next = tree_iterator_le;
			return sptree_index_unfold(node);
		}
	}

	return NULL;
}

static struct tuple *
tree_iterator_gt(struct iterator *iterator)
{
	struct tree_iterator *it = tree_iterator(iterator);

	void *node;
	while ((node = sptree_index_iterator_next(it->iter)) != NULL) {
		if (it->index->tree.compare(&it->key_data, node,
					    (void *) it->index) != 0) {
			it->base.next = tree_iterator_ge;
			return sptree_index_unfold(node);
		}
	}

	return NULL;
}

/* }}} */

/* {{{ TreeIndex  **********************************************************/

TreeIndex::TreeIndex(struct key_def *key_def, struct space *space)
	: Index(key_def, space)
{
	memset(&tree, 0, sizeof tree);
}

TreeIndex::~TreeIndex()
{
	sptree_index_destroy(&tree);
}

size_t
TreeIndex::size() const
{
	return tree.size;
}

struct tuple *
TreeIndex::min() const
{
	void *node = sptree_index_first(&tree);
	return sptree_index_unfold(node);
}

struct tuple *
TreeIndex::max() const
{
	void *node = sptree_index_last(&tree);
	return sptree_index_unfold(node);
}

struct tuple *
TreeIndex::random(uint32_t rnd) const
{
	void *node = sptree_index_random(&tree, rnd);
	return sptree_index_unfold(node);
}

struct tuple *
TreeIndex::findByKey(const char *key, uint32_t part_count) const
{
	assert(key_def->is_unique && part_count == key_def->part_count);

	struct sptree_index_key_data key_data;
	key_data.key = key;
	key_data.part_count = part_count;
	void *node = sptree_index_find(&tree, &key_data);
	return sptree_index_unfold(node);
}

struct tuple *
TreeIndex::replace(struct tuple *old_tuple, struct tuple *new_tuple,
		   enum dup_replace_mode mode)
{
	struct sptree_index_node new_node;
	struct sptree_index_node old_node;
	uint32_t errcode;

	if (new_tuple) {
		struct sptree_index_node *p_dup_node = &old_node;
		sptree_index_fold(&new_node, new_tuple);

		/* Try to optimistically replace the new_tuple. */
		sptree_index_replace(&tree, &new_node, (void **) &p_dup_node);

		struct tuple *dup_tuple = sptree_index_unfold(p_dup_node);
		errcode = replace_check_dup(old_tuple, dup_tuple, mode);

		if (errcode) {
			sptree_index_delete(&tree, &new_node);
			if (p_dup_node != NULL)
				sptree_index_replace(&tree, p_dup_node, NULL);
			tnt_raise(ClientError, errcode, index_n(this));
		}
		if (dup_tuple)
			return dup_tuple;
	}
	if (old_tuple) {
		sptree_index_fold(&old_node, old_tuple);
		sptree_index_delete(&tree, &old_node);
	}
	return old_tuple;
}

struct iterator *
TreeIndex::allocIterator() const
{
	struct tree_iterator *it = (struct tree_iterator *)
			calloc(1, sizeof(*it));
	if (it == NULL) {
		tnt_raise(ClientError, ER_MEMORY_ISSUE,
			  sizeof(struct tree_iterator),
			  "TreeIndex", "iterator");
	}

	it->index = this;
	it->base.free = tree_iterator_free;
	return (struct iterator *) it;
}

void
TreeIndex::initIterator(struct iterator *iterator, enum iterator_type type,
			const char *key, uint32_t part_count) const
{
	assert (key != NULL || part_count == 0);
	struct tree_iterator *it = tree_iterator(iterator);

	if (part_count == 0) {
		/*
		 * If no key is specified, downgrade equality
		 * iterators to a full range.
		 */
		type = iterator_type_is_reverse(type) ? ITER_LE : ITER_GE;
		key = NULL;
	}
	it->key_data.key = key;
	it->key_data.part_count = part_count;

	if (iterator_type_is_reverse(type))
		sptree_index_iterator_reverse_init_set(&tree, &it->iter,
						       &it->key_data);
	else
		sptree_index_iterator_init_set(&tree, &it->iter,
					       &it->key_data);

	switch (type) {
	case ITER_EQ:
		it->base.next = tree_iterator_eq;
		break;
	case ITER_REQ:
		it->base.next = tree_iterator_req;
		break;
	case ITER_ALL:
	case ITER_GE:
		it->base.next = tree_iterator_ge;
		break;
	case ITER_GT:
		it->base.next = tree_iterator_gt;
		break;
	case ITER_LE:
		it->base.next = tree_iterator_le;
		break;
	case ITER_LT:
		it->base.next = tree_iterator_lt;
		break;
	default:
		tnt_raise(ClientError, ER_UNSUPPORTED,
			  "Tree index", "requested iterator type");
	}
}

void
TreeIndex::beginBuild()
{
	assert(index_is_primary(this));

	tree.size = 0;
	tree.max_size = 64;

	size_t sz = tree.max_size * sizeof(struct sptree_index_node);
	tree.members = malloc(sz);
	if (tree.members == NULL) {
		panic("malloc(): failed to allocate %" PRI_SZ " bytes", sz);
	}
}

void
TreeIndex::buildNext(struct tuple *tuple)
{
	if (tree.size == tree.max_size) {
		tree.max_size *= 2;

		size_t sz = tree.max_size * sizeof(struct sptree_index_node);
		tree.members = realloc(tree.members, sz);
		if (tree.members == NULL) {
			panic("malloc(): failed to allocate %" PRI_SZ " bytes", sz);
		}
	}

	struct sptree_index_node *node = (struct sptree_index_node *)
			tree.members + tree.size;
	sptree_index_fold(node, tuple);
	tree.size++;
}

void
TreeIndex::endBuild()
{
	assert(index_is_primary(this));

	uint32_t n_tuples = tree.size;
	uint32_t estimated_tuples = tree.max_size;
	void *nodes = tree.members;

	sptree_index_init(&tree, sizeof(struct tuple *),
			  nodes, n_tuples, estimated_tuples,
			  sptree_index_node_compare_with_key,
			  sptree_index_node_compare,
			  this);
}

void
TreeIndex::build(Index *pk)
{
	uint32_t n_tuples = pk->size();
	uint32_t estimated_tuples = n_tuples * 1.2;

	void *nodes = NULL;
	if (n_tuples) {
		/*
		 * Allocate a little extra to avoid
		 * unnecessary realloc() when more data is
		 * inserted.
		*/
		size_t sz = estimated_tuples * sizeof(struct sptree_index_node);
		nodes = malloc(sz);
		if (nodes == NULL) {
			panic("malloc(): failed to allocate %" PRI_SZ " bytes", sz);
		}
	}

	struct iterator *it = pk->position();
	pk->initIterator(it, ITER_ALL, NULL, 0);

	struct tuple *tuple;

	for (uint32_t i = 0; (tuple = it->next(it)) != NULL; ++i) {
		struct sptree_index_node *node = (struct sptree_index_node *)
				nodes + i;
		sptree_index_fold(node, tuple);
	}

	if (n_tuples) {
		say_info("Sorting %" PRIu32 " keys in index %" PRIu32 "...", n_tuples,
			 index_n(this));
	}

	/* If n_tuples == 0 then estimated_tuples = 0, elem == NULL, tree is empty */
	sptree_index_init(&tree, sizeof(struct sptree_index_node),
			  nodes, n_tuples, estimated_tuples,
			  sptree_index_node_compare_with_key,
			  key_def->is_unique ? sptree_index_node_compare
					     : sptree_index_node_compare_dup,
			  this);
}
<commit_msg>Fix incorrect sizeof() in box/tree_index.cc<commit_after>/*
 * Redistribution and use in source and binary forms, with or
 * without modification, are permitted provided that the following
 * conditions are met:
 *
 * 1. Redistributions of source code must retain the above
 *    copyright notice, this list of conditions and the
 *    following disclaimer.
 *
 * 2. 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.
 *
 * THIS SOFTWARE IS PROVIDED BY <COPYRIGHT HOLDER> ``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
 * <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.
 */
#include "tree_index.h"
#include "tuple.h"
#include "space.h"
#include "exception.h"

/* {{{ Utilities. *************************************************/

struct sptree_index_node {
	struct tuple *tuple;
};

struct sptree_index_key_data
{
	const char *key;
	uint32_t part_count;
};

static inline struct tuple *
sptree_index_unfold(const void *node)
{
	if (node == NULL)
		return NULL;

	struct sptree_index_node *node_x = (struct sptree_index_node *) node;
	assert (node_x->tuple != NULL);
	return node_x->tuple;
}

static inline void
sptree_index_fold(void *node, struct tuple *tuple)
{
	assert (node != NULL);
	assert (tuple != NULL);

	struct sptree_index_node *node_x = (struct sptree_index_node *) node;
	node_x->tuple = tuple;
}

static int
sptree_index_node_compare(const void *node_a, const void *node_b, void *arg)
{
	TreeIndex *self = (TreeIndex *) arg;
	struct tuple *tuple_a = sptree_index_unfold(node_a);
	struct tuple *tuple_b = sptree_index_unfold(node_b);

	return tuple_compare(tuple_a, tuple_b, self->key_def);
}

static int
sptree_index_node_compare_dup(const void *node_a, const void *node_b, void *arg)
{
	TreeIndex *self = (TreeIndex *) arg;
	struct tuple *tuple_a = sptree_index_unfold(node_a);
	struct tuple *tuple_b = sptree_index_unfold(node_b);

	return tuple_compare_dup(tuple_a, tuple_b, self->key_def);
}

static int
sptree_index_node_compare_with_key(const void *key, const void *node, void *arg)
{
	TreeIndex *self = (TreeIndex *) arg;
	struct sptree_index_key_data *key_data =
			(struct sptree_index_key_data *) key;
	struct tuple *tuple = sptree_index_unfold(node);

	/* the result is inverted because arguments are swapped */
	return -tuple_compare_with_key(tuple, key_data->key,
				       key_data->part_count, self->key_def);
}

/* {{{ TreeIndex Iterators ****************************************/

struct tree_iterator {
	struct iterator base;
	const TreeIndex *index;
	struct sptree_index_iterator *iter;
	struct sptree_index_key_data key_data;
};

static void
tree_iterator_free(struct iterator *iterator);

static inline struct tree_iterator *
tree_iterator(struct iterator *it)
{
	assert(it->free == tree_iterator_free);
	return (struct tree_iterator *) it;
}

static void
tree_iterator_free(struct iterator *iterator)
{
	struct tree_iterator *it = tree_iterator(iterator);
	if (it->iter)
		sptree_index_iterator_free(it->iter);
	free(it);
}

static struct tuple *
tree_iterator_ge(struct iterator *iterator)
{
	struct tree_iterator *it = tree_iterator(iterator);
	void *node = sptree_index_iterator_next(it->iter);
	return sptree_index_unfold(node);
}

static struct tuple *
tree_iterator_le(struct iterator *iterator)
{
	struct tree_iterator *it = tree_iterator(iterator);
	void *node = sptree_index_iterator_reverse_next(it->iter);
	return sptree_index_unfold(node);
}

static struct tuple *
tree_iterator_eq(struct iterator *iterator)
{
	struct tree_iterator *it = tree_iterator(iterator);

	void *node = sptree_index_iterator_next(it->iter);
	if (node && it->index->tree.compare(&it->key_data, node,
					    (void *) it->index) == 0)
		return sptree_index_unfold(node);

	return NULL;
}

static struct tuple *
tree_iterator_req(struct iterator *iterator)
{
	struct tree_iterator *it = tree_iterator(iterator);

	void *node = sptree_index_iterator_reverse_next(it->iter);
	if (node != NULL
	    && it->index->tree.compare(&it->key_data, node,
				       (void *) it->index) == 0) {
		return sptree_index_unfold(node);
	}

	return NULL;
}

static struct tuple *
tree_iterator_lt(struct iterator *iterator)
{
	struct tree_iterator *it = tree_iterator(iterator);

	void *node ;
	while ((node = sptree_index_iterator_reverse_next(it->iter)) != NULL) {
		if (it->index->tree.compare(&it->key_data, node,
					    (void *) it->index) != 0) {
			it->base.next = tree_iterator_le;
			return sptree_index_unfold(node);
		}
	}

	return NULL;
}

static struct tuple *
tree_iterator_gt(struct iterator *iterator)
{
	struct tree_iterator *it = tree_iterator(iterator);

	void *node;
	while ((node = sptree_index_iterator_next(it->iter)) != NULL) {
		if (it->index->tree.compare(&it->key_data, node,
					    (void *) it->index) != 0) {
			it->base.next = tree_iterator_ge;
			return sptree_index_unfold(node);
		}
	}

	return NULL;
}

/* }}} */

/* {{{ TreeIndex  **********************************************************/

TreeIndex::TreeIndex(struct key_def *key_def, struct space *space)
	: Index(key_def, space)
{
	memset(&tree, 0, sizeof tree);
}

TreeIndex::~TreeIndex()
{
	sptree_index_destroy(&tree);
}

size_t
TreeIndex::size() const
{
	return tree.size;
}

struct tuple *
TreeIndex::min() const
{
	void *node = sptree_index_first(&tree);
	return sptree_index_unfold(node);
}

struct tuple *
TreeIndex::max() const
{
	void *node = sptree_index_last(&tree);
	return sptree_index_unfold(node);
}

struct tuple *
TreeIndex::random(uint32_t rnd) const
{
	void *node = sptree_index_random(&tree, rnd);
	return sptree_index_unfold(node);
}

struct tuple *
TreeIndex::findByKey(const char *key, uint32_t part_count) const
{
	assert(key_def->is_unique && part_count == key_def->part_count);

	struct sptree_index_key_data key_data;
	key_data.key = key;
	key_data.part_count = part_count;
	void *node = sptree_index_find(&tree, &key_data);
	return sptree_index_unfold(node);
}

struct tuple *
TreeIndex::replace(struct tuple *old_tuple, struct tuple *new_tuple,
		   enum dup_replace_mode mode)
{
	struct sptree_index_node new_node;
	struct sptree_index_node old_node;
	uint32_t errcode;

	if (new_tuple) {
		struct sptree_index_node *p_dup_node = &old_node;
		sptree_index_fold(&new_node, new_tuple);

		/* Try to optimistically replace the new_tuple. */
		sptree_index_replace(&tree, &new_node, (void **) &p_dup_node);

		struct tuple *dup_tuple = sptree_index_unfold(p_dup_node);
		errcode = replace_check_dup(old_tuple, dup_tuple, mode);

		if (errcode) {
			sptree_index_delete(&tree, &new_node);
			if (p_dup_node != NULL)
				sptree_index_replace(&tree, p_dup_node, NULL);
			tnt_raise(ClientError, errcode, index_n(this));
		}
		if (dup_tuple)
			return dup_tuple;
	}
	if (old_tuple) {
		sptree_index_fold(&old_node, old_tuple);
		sptree_index_delete(&tree, &old_node);
	}
	return old_tuple;
}

struct iterator *
TreeIndex::allocIterator() const
{
	struct tree_iterator *it = (struct tree_iterator *)
			calloc(1, sizeof(*it));
	if (it == NULL) {
		tnt_raise(ClientError, ER_MEMORY_ISSUE,
			  sizeof(struct tree_iterator),
			  "TreeIndex", "iterator");
	}

	it->index = this;
	it->base.free = tree_iterator_free;
	return (struct iterator *) it;
}

void
TreeIndex::initIterator(struct iterator *iterator, enum iterator_type type,
			const char *key, uint32_t part_count) const
{
	assert (key != NULL || part_count == 0);
	struct tree_iterator *it = tree_iterator(iterator);

	if (part_count == 0) {
		/*
		 * If no key is specified, downgrade equality
		 * iterators to a full range.
		 */
		type = iterator_type_is_reverse(type) ? ITER_LE : ITER_GE;
		key = NULL;
	}
	it->key_data.key = key;
	it->key_data.part_count = part_count;

	if (iterator_type_is_reverse(type))
		sptree_index_iterator_reverse_init_set(&tree, &it->iter,
						       &it->key_data);
	else
		sptree_index_iterator_init_set(&tree, &it->iter,
					       &it->key_data);

	switch (type) {
	case ITER_EQ:
		it->base.next = tree_iterator_eq;
		break;
	case ITER_REQ:
		it->base.next = tree_iterator_req;
		break;
	case ITER_ALL:
	case ITER_GE:
		it->base.next = tree_iterator_ge;
		break;
	case ITER_GT:
		it->base.next = tree_iterator_gt;
		break;
	case ITER_LE:
		it->base.next = tree_iterator_le;
		break;
	case ITER_LT:
		it->base.next = tree_iterator_lt;
		break;
	default:
		tnt_raise(ClientError, ER_UNSUPPORTED,
			  "Tree index", "requested iterator type");
	}
}

void
TreeIndex::beginBuild()
{
	assert(index_is_primary(this));

	tree.size = 0;
	tree.max_size = 64;

	size_t sz = tree.max_size * sizeof(struct sptree_index_node);
	tree.members = malloc(sz);
	if (tree.members == NULL) {
		panic("malloc(): failed to allocate %" PRI_SZ " bytes", sz);
	}
}

void
TreeIndex::buildNext(struct tuple *tuple)
{
	if (tree.size == tree.max_size) {
		tree.max_size *= 2;

		size_t sz = tree.max_size * sizeof(struct sptree_index_node);
		tree.members = realloc(tree.members, sz);
		if (tree.members == NULL) {
			panic("malloc(): failed to allocate %" PRI_SZ " bytes", sz);
		}
	}

	struct sptree_index_node *node = (struct sptree_index_node *)
			tree.members + tree.size;
	sptree_index_fold(node, tuple);
	tree.size++;
}

void
TreeIndex::endBuild()
{
	assert(index_is_primary(this));

	uint32_t n_tuples = tree.size;
	uint32_t estimated_tuples = tree.max_size;
	void *nodes = tree.members;

	sptree_index_init(&tree, sizeof(struct sptree_index_node),
			  nodes, n_tuples, estimated_tuples,
			  sptree_index_node_compare_with_key,
			  sptree_index_node_compare,
			  this);
}

void
TreeIndex::build(Index *pk)
{
	uint32_t n_tuples = pk->size();
	uint32_t estimated_tuples = n_tuples * 1.2;

	void *nodes = NULL;
	if (n_tuples) {
		/*
		 * Allocate a little extra to avoid
		 * unnecessary realloc() when more data is
		 * inserted.
		*/
		size_t sz = estimated_tuples * sizeof(struct sptree_index_node);
		nodes = malloc(sz);
		if (nodes == NULL) {
			panic("malloc(): failed to allocate %" PRI_SZ " bytes", sz);
		}
	}

	struct iterator *it = pk->position();
	pk->initIterator(it, ITER_ALL, NULL, 0);

	struct tuple *tuple;

	for (uint32_t i = 0; (tuple = it->next(it)) != NULL; ++i) {
		struct sptree_index_node *node = (struct sptree_index_node *)
				nodes + i;
		sptree_index_fold(node, tuple);
	}

	if (n_tuples) {
		say_info("Sorting %" PRIu32 " keys in index %" PRIu32 "...", n_tuples,
			 index_n(this));
	}

	/* If n_tuples == 0 then estimated_tuples = 0, elem == NULL, tree is empty */
	sptree_index_init(&tree, sizeof(struct sptree_index_node),
			  nodes, n_tuples, estimated_tuples,
			  sptree_index_node_compare_with_key,
			  key_def->is_unique ? sptree_index_node_compare
					     : sptree_index_node_compare_dup,
			  this);
}
<|endoftext|>


<commit_before>#ifdef WIN32
#pragma warning(4:4786)
#endif

#include <string>
#include <fstream>
#include <stdio.h>
#include "Bundle.h"

Bundle::Bundle(const Bundle *pBundle)
{
  if (pBundle == NULL)
    return;

  mappings = pBundle->mappings;
}

void Bundle::load(const std::string &path)
{
  std::string untranslated;
  std::string translated;
  char buffer[1024];

  std::ifstream poStrm(path.c_str());
  if (!poStrm.good())
    return;

  poStrm.getline(buffer,1024);
  while (poStrm.good()) {
    std::string line = buffer;
    std::string data;
    TLineType type = parseLine(line, data);
    if (type == tMSGID) {
      if (untranslated.length() > 0) {
        mappings.erase(untranslated);
        ensureNormalText(translated);
        mappings.insert(std::pair<std::string,std::string>(untranslated, translated));
      }
      untranslated = data;
      translated.resize(0);
    }
    else if (type == tMSGSTR) {
      if (untranslated.length() > 0)
        translated = data;
    }
    else if (type == tAPPEND) {
      if (untranslated.length() > 0)
        translated += data;
    }
    else if (type == tERROR) {

    }

    poStrm.getline(buffer,1024);
  }

  if ((untranslated.length() > 0) && (translated.length() > 0)) {
    mappings.erase(untranslated);
    ensureNormalText(translated);
    mappings.insert(std::pair<std::string,std::string>(untranslated, translated));
  }
}

Bundle::TLineType Bundle::parseLine(const std::string &line, std::string &data)
{
  int startPos, endPos;
  TLineType type;

  data.resize(0);
  startPos = line.find_first_not_of("\t \r\n");

  if ((startPos < 0) || (line.at(startPos) == '#'))
    return tCOMMENT;

  else if (line.at(startPos) == '"') {
    endPos = line.find_first_of('"', startPos+1);
    if (endPos < 0)
      endPos = line.length();
    data = line.substr(startPos+1, endPos-startPos-1);
    return tAPPEND;
  }

  endPos = line.find_first_of("\t \r\n\"");
  if (endPos < 0)
    endPos = line.length();
  std::string key = line.substr(startPos, endPos-startPos);
  if (key == "msgid")
    type = tMSGID;
  else if (key == "msgstr")
    type = tMSGSTR;
  else
    return tERROR;

  startPos = line.find_first_of('"', endPos + 1);
  if (startPos >= 0) {
    startPos++;
    endPos = line.find_first_of('"', startPos);
    if (endPos < 0)
      endPos = line.length();
    data = line.substr( startPos, endPos-startPos);
  }
  return type;
}

std::string Bundle::getLocalString(const std::string &key)
{
  BundleStringMap::iterator it = mappings.find(key);
  if (it != mappings.end())
    return it->second;
  else
    return key;
}

void Bundle::ensureNormalText(std::string &msg)
{
// This is an ugly hack. If you don't like it fix it.
// BZFlag's font bitmaps don't contain letters with accents, so strip them here
// Would be nice if some kind sole added them.

  for (std::string::size_type i = 0; i < msg.length(); i++) {
    char c = msg.at(i);
    switch (c) {
      case '':
      case '':
      case '':
      case '':
	msg[i] = 'a';
      break;
      case '':
      case '':
	msg[i] = 'a';
	i++;
	msg.insert(i, 1, 'a');
      break;
      case '':
	msg[i] = 'a';
	i++;
	msg.insert(i, 1, 'e');
      break;
      case '':
      case '':
	msg[i] = 'A';
	i++;
	msg.insert(i, 1, 'e');
      break;
      case '':
	msg[i] = 'A';
	i++;
	msg.insert(i, 1, 'a');
      break;
      case '':
	msg[i] = 'c';
      break;
      case '':
      case '':
      case '':
      case '':
	msg[i] = 'e';
      break;
      case '':
      case '':
	msg[i] = 'i';
      break;
      case '':
      case '':
      case '':
	msg[i] = 'o';
      break;
      case '':
      case '':
	msg[i] = 'o';
	i++;
	msg.insert(i, 1, 'e');
      break;
      case '':
      case '':
	msg[i] = 'O';
	i++;
	msg.insert(i, 1, 'e');
      break;
      case '':
      case '':
      case '':
	msg[i] = 'u';
      break;
      case '':
	msg[i] = 'u';
	i++;
        msg.insert(i, 1, 'e');
      case '':
	msg[i] = 'U';
	i++;
	msg.insert(i, 1, 'e');
      case '':
	msg[i] = 'n';
      break;
      case '':
      case '':
	msg[i] = ' ';
      break;

    }
  }

}

std::string Bundle::formatMessage(const std::string &key, int parmCnt, const std::string *parms)
{
  std::string messageIn = getLocalString(key);
  std::string messageOut;

  int startPos = 0;
  int lCurlyPos = messageIn.find_first_of("{");

  while (lCurlyPos >= 0) {
    messageOut += messageIn.substr( startPos, lCurlyPos - startPos);
    int rCurlyPos = messageIn.find_first_of("}", lCurlyPos++);
    if (rCurlyPos < 0) {
      messageOut += messageIn.substr(lCurlyPos);
      return messageOut;
    }
    std::string numStr = messageIn.substr(lCurlyPos, rCurlyPos-lCurlyPos);
    int num;
    if (sscanf(numStr.c_str(), "%d", &num) != 1)
      messageOut += messageIn.substr(lCurlyPos, rCurlyPos-lCurlyPos);
    else {
      num--;
      if ((num >= 0) && (num < parmCnt))
        messageOut += parms[num];
    }
    startPos = rCurlyPos+1;
    lCurlyPos = messageIn.find_first_of("{", startPos);
  }
  messageOut += messageIn.substr(startPos);
  return messageOut;
}
// ex: shiftwidth=2 tabstop=8
<commit_msg>Convert more accented chars<commit_after>#ifdef WIN32
#pragma warning(4:4786)
#endif

#include <string>
#include <fstream>
#include <stdio.h>
#include "Bundle.h"

Bundle::Bundle(const Bundle *pBundle)
{
  if (pBundle == NULL)
    return;

  mappings = pBundle->mappings;
}

void Bundle::load(const std::string &path)
{
  std::string untranslated;
  std::string translated;
  char buffer[1024];

  std::ifstream poStrm(path.c_str());
  if (!poStrm.good())
    return;

  poStrm.getline(buffer,1024);
  while (poStrm.good()) {
    std::string line = buffer;
    std::string data;
    TLineType type = parseLine(line, data);
    if (type == tMSGID) {
      if (untranslated.length() > 0) {
        mappings.erase(untranslated);
        ensureNormalText(translated);
        mappings.insert(std::pair<std::string,std::string>(untranslated, translated));
      }
      untranslated = data;
      translated.resize(0);
    }
    else if (type == tMSGSTR) {
      if (untranslated.length() > 0)
        translated = data;
    }
    else if (type == tAPPEND) {
      if (untranslated.length() > 0)
        translated += data;
    }
    else if (type == tERROR) {

    }

    poStrm.getline(buffer,1024);
  }

  if ((untranslated.length() > 0) && (translated.length() > 0)) {
    mappings.erase(untranslated);
    ensureNormalText(translated);
    mappings.insert(std::pair<std::string,std::string>(untranslated, translated));
  }
}

Bundle::TLineType Bundle::parseLine(const std::string &line, std::string &data)
{
  int startPos, endPos;
  TLineType type;

  data.resize(0);
  startPos = line.find_first_not_of("\t \r\n");

  if ((startPos < 0) || (line.at(startPos) == '#'))
    return tCOMMENT;

  else if (line.at(startPos) == '"') {
    endPos = line.find_first_of('"', startPos+1);
    if (endPos < 0)
      endPos = line.length();
    data = line.substr(startPos+1, endPos-startPos-1);
    return tAPPEND;
  }

  endPos = line.find_first_of("\t \r\n\"");
  if (endPos < 0)
    endPos = line.length();
  std::string key = line.substr(startPos, endPos-startPos);
  if (key == "msgid")
    type = tMSGID;
  else if (key == "msgstr")
    type = tMSGSTR;
  else
    return tERROR;

  startPos = line.find_first_of('"', endPos + 1);
  if (startPos >= 0) {
    startPos++;
    endPos = line.find_first_of('"', startPos);
    if (endPos < 0)
      endPos = line.length();
    data = line.substr( startPos, endPos-startPos);
  }
  return type;
}

std::string Bundle::getLocalString(const std::string &key)
{
  BundleStringMap::iterator it = mappings.find(key);
  if (it != mappings.end())
    return it->second;
  else
    return key;
}

void Bundle::ensureNormalText(std::string &msg)
{
// This is an ugly hack. If you don't like it fix it.
// BZFlag's font bitmaps don't contain letters with accents, so strip them here
// Would be nice if some kind sole added them.

  for (std::string::size_type i = 0; i < msg.length(); i++) {
    char c = msg.at(i);
    switch (c) {
      case '':
      case '':
      case '':
      case '':
	msg[i] = 'a';
      break;
      case '':
      case '':
	msg[i] = 'a';
	i++;
	msg.insert(i, 1, 'a');
      break;
      case '':
	msg[i] = 'a';
	i++;
	msg.insert(i, 1, 'e');
      break;
      case '':
	msg[i] = 'A';
      break;
      case '':
      case '':
	msg[i] = 'A';
	i++;
	msg.insert(i, 1, 'e');
      break;
      case '':
	msg[i] = 'A';
	i++;
	msg.insert(i, 1, 'a');
      break;
      case '':
	msg[i] = 'c';
      break;
      case '':
      case '':
      case '':
      case '':
	msg[i] = 'e';
      break;
      case '':
      case '':
      case '':
	msg[i] = 'i';
      break;
      case '':
      case '':
      case '':
	msg[i] = 'o';
      break;
      case '':
      case '':
	msg[i] = 'o';
	i++;
	msg.insert(i, 1, 'e');
      break;
      case '':
      case '':
	msg[i] = 'O';
	i++;
	msg.insert(i, 1, 'e');
      break;
      case '':
      case '':
      case '':
	msg[i] = 'u';
      break;
      case '':
	msg[i] = 'u';
	i++;
        msg.insert(i, 1, 'e');
      case '':
	msg[i] = 'U';
	i++;
	msg.insert(i, 1, 'e');
      case '':
	msg[i] = 'n';
      break;
      case '':
      case '':
	msg[i] = ' ';
      break;

      default: // A temporary patch, to catch untranslated chars.. To be removed eventually
        if (((c >= 'A') && (c <= 'Z'))
	    || ((c >= 'a') && (c <= 'z'))
            || ((c >= '0') && (c <= '9'))
            || (c == '}') || (c == '{') || (c == ' ')
            || (c == ':') || (c == '/') || (c == '-')
	    || (c == ',') || (c == '&') || (c == '?')
	    || (c == '<') || (c == '>') || (c == '.')
	    || (c == '(') || (c == ')') || (c == '%')
	    || (c == '!') || (c == '+') || (c == '-')
	    || (c == '$') || (c == ';'))
	;
	else {
		msg = std::string("unsupported char:") + c;
		return;
	}
      break;

    }
  }
}

std::string Bundle::formatMessage(const std::string &key, int parmCnt, const std::string *parms)
{
  std::string messageIn = getLocalString(key);
  std::string messageOut;

  int startPos = 0;
  int lCurlyPos = messageIn.find_first_of("{");

  while (lCurlyPos >= 0) {
    messageOut += messageIn.substr( startPos, lCurlyPos - startPos);
    int rCurlyPos = messageIn.find_first_of("}", lCurlyPos++);
    if (rCurlyPos < 0) {
      messageOut += messageIn.substr(lCurlyPos);
      return messageOut;
    }
    std::string numStr = messageIn.substr(lCurlyPos, rCurlyPos-lCurlyPos);
    int num;
    if (sscanf(numStr.c_str(), "%d", &num) != 1)
      messageOut += messageIn.substr(lCurlyPos, rCurlyPos-lCurlyPos);
    else {
      num--;
      if ((num >= 0) && (num < parmCnt))
        messageOut += parms[num];
    }
    startPos = rCurlyPos+1;
    lCurlyPos = messageIn.find_first_of("{", startPos);
  }
  messageOut += messageIn.substr(startPos);
  return messageOut;
}
// ex: shiftwidth=2 tabstop=8
<|endoftext|>


<commit_before>#include "catch.hpp"

#include "../include/vector.h"

TEST_CASE("construct a new vector", "[vector]") {
    jade::vector<int> v;
    REQUIRE(v.size() == 0);
    REQUIRE(v.capacity() == 0);
}

TEST_CASE("copy construct a new vector", "[vector]") {
    jade::vector<int> v1;
    v1.push_back(1);
    v1.push_back(2);
    v1.push_back(3);

    jade::vector<int> v2(v1);

    REQUIRE(v2.size() == 3);
    REQUIRE(v2.capacity() == 4);

    int k = 1;
    for (const auto& i : v2) {
        REQUIRE(k++ == i);
    }
}

TEST_CASE("a vector can be constructed using a pair of iterators") {
    int arr[5] = {1,2,3,4,5};
    jade::vector<int> v{arr, arr+5};
    REQUIRE(v.size() == 5);
    REQUIRE(v.capacity() == 5);
}

TEST_CASE("assignment operator", "[vector]") {
    jade::vector<int> v1;
    v1.push_back(1);
    v1.push_back(2);

    REQUIRE(v1.size() == 2);
    REQUIRE(v1.capacity() == 2);

    jade::vector<int> v2;
    v2.push_back(3);
    v2.push_back(4);
    v2.push_back(5);

    REQUIRE(v2.size() == 3);
    REQUIRE(v2.capacity() == 4);

    v2 = v1;

    REQUIRE(v2.size() == 2);
    REQUIRE(v2.capacity() == 2);

    int k = 1;
    for (const auto& i : v2) {
        REQUIRE(k++ == i);
    }
}

TEST_CASE("move assignment operator", "[vector]") {
    jade::vector<int> v1{1,2,3};
    REQUIRE(v1.size() == 3);
    REQUIRE(v1.capacity() == 3);

    jade::vector<int> v2{4,5,6,7,8};
    REQUIRE(v2.size() == 5);
    REQUIRE(v2.capacity() == 5);

    v1 = std::move(v2);
    REQUIRE(v1.size() == 5);
    REQUIRE(v1.capacity() == 5);
    REQUIRE(v2.size() == 0);
    REQUIRE(v2.capacity() == 0);
}

TEST_CASE("initializer list assginment operator") {
    jade::vector<int> v{1,2,3};
    REQUIRE(v.size() == 3);
    REQUIRE(v.capacity() == 3);
    REQUIRE(v[0] == 1);
    REQUIRE(v[1] == 2);
    REQUIRE(v[2] == 3);

    v = {4,5,6,7};
    REQUIRE(v.size() == 4);
    REQUIRE(v.capacity() == 4);
    REQUIRE(v[0] == 4);
    REQUIRE(v[1] == 5);
    REQUIRE(v[2] == 6);
    REQUIRE(v[3] == 7);

    v = {};
    REQUIRE(v.size() == 0);
    REQUIRE(v.capacity() == 0);
}

TEST_CASE("assign replaces contents with a number of values") {
    jade::vector<int> v{1,2,3};
    REQUIRE(v.size() == 3);
    REQUIRE(v.capacity() == 3);
    REQUIRE(v[0] == 1);
    REQUIRE(v[1] == 2);
    REQUIRE(v[2] == 3);

    v.assign(5, 123);
    REQUIRE(v.size() == 5);
    REQUIRE(v.capacity() == 5);
    for (const auto i : v) {
        REQUIRE(i == 123);
    }
}

TEST_CASE("a vector can be assigned using a pair of iterators") {
    jade::vector<int> v{1,2,3};
    REQUIRE(v.size() == 3);
    REQUIRE(v.capacity() == 3);
    REQUIRE(v[0] == 1);
    REQUIRE(v[1] == 2);
    REQUIRE(v[2] == 3);

    int arr[5] = {1,2,3,4,5};
    v.assign(arr, arr+5);
    REQUIRE(v.size() == 5);
    REQUIRE(v.capacity() == 5);
}

TEST_CASE("a vector can be assigned using an initializer list") {
    jade::vector<int> v{1,2,3};
    REQUIRE(v.size() == 3);
    REQUIRE(v.capacity() == 3);
    REQUIRE(v[0] == 1);
    REQUIRE(v[1] == 2);
    REQUIRE(v[2] == 3);

    v.assign({1,2,3,4,5});
    REQUIRE(v.size() == 5);
    REQUIRE(v.capacity() == 5);
}

TEST_CASE("at method checks bounds of vector", "[vector]") {
    jade::vector<int> v = { 1, 2, 3, 4, 5 };
    REQUIRE_THROWS_AS(v.at(-1), std::out_of_range);
    REQUIRE_NOTHROW(v.at(0));
    REQUIRE_NOTHROW(v.at(2));
    REQUIRE_NOTHROW(v.at(4));
    REQUIRE_THROWS_AS(v.at(5), std::out_of_range);
}

TEST_CASE("capacity doubles everytime the size increases to the current max. capacity", "[vector]") {
    jade::vector<int> v;
    v.push_back(1);
    REQUIRE(v.size() == 1);
    REQUIRE(v.capacity() == 1);
    v.push_back(2);
    REQUIRE(v.size() == 2);
    REQUIRE(v.capacity() == 2);
    v.push_back(3);
    REQUIRE(v.size() == 3);
    REQUIRE(v.capacity() == 4);
    v.push_back(4);
    REQUIRE(v.size() == 4);
    REQUIRE(v.capacity() == 4);
    v.push_back(5);
    REQUIRE(v.size() == 5);
    REQUIRE(v.capacity() == 8);
    v.push_back(6);
    v.push_back(7);
    v.push_back(8);
    REQUIRE(v.size() == 8);
    REQUIRE(v.capacity() == 8);
    v.push_back(9);
    REQUIRE(v.size() == 9);
    REQUIRE(v.capacity() == 16);
}

TEST_CASE("constructor with initializer list", "[vector]") {
    jade::vector<int> v = { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
    REQUIRE(v.capacity() == 9);
    REQUIRE(v.size() == 9);
    REQUIRE(v[0] == 1);
    REQUIRE(v[1] == 2);
    REQUIRE(v[2] == 3);
    REQUIRE(v[3] == 4);
    REQUIRE(v[4] == 5);
    REQUIRE(v[5] == 6);
    REQUIRE(v[6] == 7);
    REQUIRE(v[7] == 8);
    REQUIRE(v[8] == 9);
}

TEST_CASE("vector can be constructed with a number copies of elements with a certain value", "[vector]") {
    SECTION("default-inserted instances of T", "[vector]") {
        jade::vector<int> v1(50);
        REQUIRE(v1.capacity() == 50);
        REQUIRE(v1.size() == 50);
        for (const auto i : v1) {
            REQUIRE(i == 0);
        }
    }
    SECTION("copies of provided value", "[vector]") {
        jade::vector<int> v1(50, 123);
        REQUIRE(v1.capacity() == 50);
        REQUIRE(v1.size() == 50);
        for (const auto i : v1) {
            REQUIRE(i == 123);
        }
    }
}

TEST_CASE("move constructor", "[vector]") {
    jade::vector<int> v1 = { 1, 2, 3 };
    REQUIRE(v1.size() == 3);
    REQUIRE(v1.capacity() == 3);

    jade::vector<int> v2{std::move(v1)};
    REQUIRE(v1.size() == 0);
    REQUIRE(v1.capacity() == 0);
    REQUIRE(v2.size() == 3);
    REQUIRE(v2.capacity() == 3);
}

TEST_CASE("a vector is resizable", "[vector]") {
    jade::vector<int> v;
    v.resize(16);
    REQUIRE(v.capacity() == 16);
    REQUIRE(v.size() == 0);
}

TEST_CASE("a new vector is resizable to zero", "[vector]") {
    jade::vector<int> v;
    v.resize(0);
    REQUIRE(v.capacity() == 0);
    REQUIRE(v.size() == 0);
}

TEST_CASE("resizing a vector keeps it consistent", "[vector]") {
    jade::vector<int> v;
    REQUIRE(v.capacity() == 0);
    REQUIRE(v.size() == 0);

    v.push_back(1);
    v.push_back(2);
    v.push_back(3);
    REQUIRE(v.capacity() == 4);
    REQUIRE(v.size() == 3);

    v.resize(16);
    REQUIRE(v.capacity() == 16);
    REQUIRE(v.size() == 3);

    v.resize(0);
    REQUIRE(v.capacity() == 0);
    REQUIRE(v.size() == 0);

    v.push_back(1);
    v.push_back(2);
    v.push_back(3);
    REQUIRE(v.capacity() == 4);
    REQUIRE(v.size() == 3);

    v.resize(16);
    REQUIRE(v.capacity() == 16);
    REQUIRE(v.size() == 3);
}
<commit_msg>add test for index operator<commit_after>#include "catch.hpp"

#include "../include/vector.h"

TEST_CASE("construct a new vector", "[vector]") {
    jade::vector<int> v;
    REQUIRE(v.size() == 0);
    REQUIRE(v.capacity() == 0);
}

TEST_CASE("copy construct a new vector", "[vector]") {
    jade::vector<int> v1;
    v1.push_back(1);
    v1.push_back(2);
    v1.push_back(3);

    jade::vector<int> v2(v1);

    REQUIRE(v2.size() == 3);
    REQUIRE(v2.capacity() == 4);

    int k = 1;
    for (const auto& i : v2) {
        REQUIRE(k++ == i);
    }
}

TEST_CASE("a vector can be constructed using a pair of iterators") {
    int arr[5] = {1,2,3,4,5};
    jade::vector<int> v{arr, arr+5};
    REQUIRE(v.size() == 5);
    REQUIRE(v.capacity() == 5);
}

TEST_CASE("assignment operator", "[vector]") {
    jade::vector<int> v1;
    v1.push_back(1);
    v1.push_back(2);

    REQUIRE(v1.size() == 2);
    REQUIRE(v1.capacity() == 2);

    jade::vector<int> v2;
    v2.push_back(3);
    v2.push_back(4);
    v2.push_back(5);

    REQUIRE(v2.size() == 3);
    REQUIRE(v2.capacity() == 4);

    v2 = v1;

    REQUIRE(v2.size() == 2);
    REQUIRE(v2.capacity() == 2);

    int k = 1;
    for (const auto& i : v2) {
        REQUIRE(k++ == i);
    }
}

TEST_CASE("move assignment operator", "[vector]") {
    jade::vector<int> v1{1,2,3};
    REQUIRE(v1.size() == 3);
    REQUIRE(v1.capacity() == 3);

    jade::vector<int> v2{4,5,6,7,8};
    REQUIRE(v2.size() == 5);
    REQUIRE(v2.capacity() == 5);

    v1 = std::move(v2);
    REQUIRE(v1.size() == 5);
    REQUIRE(v1.capacity() == 5);
    REQUIRE(v2.size() == 0);
    REQUIRE(v2.capacity() == 0);
}

TEST_CASE("initializer list assginment operator") {
    jade::vector<int> v{1,2,3};
    REQUIRE(v.size() == 3);
    REQUIRE(v.capacity() == 3);
    REQUIRE(v[0] == 1);
    REQUIRE(v[1] == 2);
    REQUIRE(v[2] == 3);

    v = {4,5,6,7};
    REQUIRE(v.size() == 4);
    REQUIRE(v.capacity() == 4);
    REQUIRE(v[0] == 4);
    REQUIRE(v[1] == 5);
    REQUIRE(v[2] == 6);
    REQUIRE(v[3] == 7);

    v = {};
    REQUIRE(v.size() == 0);
    REQUIRE(v.capacity() == 0);
}

TEST_CASE("assign replaces contents with a number of values") {
    jade::vector<int> v{1,2,3};
    REQUIRE(v.size() == 3);
    REQUIRE(v.capacity() == 3);
    REQUIRE(v[0] == 1);
    REQUIRE(v[1] == 2);
    REQUIRE(v[2] == 3);

    v.assign(5, 123);
    REQUIRE(v.size() == 5);
    REQUIRE(v.capacity() == 5);
    for (const auto i : v) {
        REQUIRE(i == 123);
    }
}

TEST_CASE("a vector can be assigned using a pair of iterators") {
    jade::vector<int> v{1,2,3};
    REQUIRE(v.size() == 3);
    REQUIRE(v.capacity() == 3);
    REQUIRE(v[0] == 1);
    REQUIRE(v[1] == 2);
    REQUIRE(v[2] == 3);

    int arr[5] = {1,2,3,4,5};
    v.assign(arr, arr+5);
    REQUIRE(v.size() == 5);
    REQUIRE(v.capacity() == 5);
}

TEST_CASE("a vector can be assigned using an initializer list") {
    jade::vector<int> v{1,2,3};
    REQUIRE(v.size() == 3);
    REQUIRE(v.capacity() == 3);
    REQUIRE(v[0] == 1);
    REQUIRE(v[1] == 2);
    REQUIRE(v[2] == 3);

    v.assign({1,2,3,4,5});
    REQUIRE(v.size() == 5);
    REQUIRE(v.capacity() == 5);
}

TEST_CASE("at method checks bounds of vector", "[vector]") {
    jade::vector<int> v = { 1, 2, 3, 4, 5 };
    REQUIRE_THROWS_AS(v.at(-1), std::out_of_range);
    REQUIRE_NOTHROW(v.at(0));
    REQUIRE_NOTHROW(v.at(2));
    REQUIRE_NOTHROW(v.at(4));
    REQUIRE_THROWS_AS(v.at(5), std::out_of_range);
}

TEST_CASE("References to an element at a specified location is returned by the index operator", "[vector]") {
    jade::vector<int> v{0,1,2,3,4,5,6,7,8,9};
    REQUIRE(v.size() == 10);
    REQUIRE(v.capacity() == 10);
    jade::vector<int>::size_type i = 0;
    for (; i < v.size(); ++i) {
        REQUIRE(i == v[i]);
    }
}

TEST_CASE("capacity doubles everytime the size increases to the current max. capacity", "[vector]") {
    jade::vector<int> v;
    v.push_back(1);
    REQUIRE(v.size() == 1);
    REQUIRE(v.capacity() == 1);
    v.push_back(2);
    REQUIRE(v.size() == 2);
    REQUIRE(v.capacity() == 2);
    v.push_back(3);
    REQUIRE(v.size() == 3);
    REQUIRE(v.capacity() == 4);
    v.push_back(4);
    REQUIRE(v.size() == 4);
    REQUIRE(v.capacity() == 4);
    v.push_back(5);
    REQUIRE(v.size() == 5);
    REQUIRE(v.capacity() == 8);
    v.push_back(6);
    v.push_back(7);
    v.push_back(8);
    REQUIRE(v.size() == 8);
    REQUIRE(v.capacity() == 8);
    v.push_back(9);
    REQUIRE(v.size() == 9);
    REQUIRE(v.capacity() == 16);
}

TEST_CASE("constructor with initializer list", "[vector]") {
    jade::vector<int> v = { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
    REQUIRE(v.capacity() == 9);
    REQUIRE(v.size() == 9);
    REQUIRE(v[0] == 1);
    REQUIRE(v[1] == 2);
    REQUIRE(v[2] == 3);
    REQUIRE(v[3] == 4);
    REQUIRE(v[4] == 5);
    REQUIRE(v[5] == 6);
    REQUIRE(v[6] == 7);
    REQUIRE(v[7] == 8);
    REQUIRE(v[8] == 9);
}

TEST_CASE("vector can be constructed with a number copies of elements with a certain value", "[vector]") {
    SECTION("default-inserted instances of T", "[vector]") {
        jade::vector<int> v1(50);
        REQUIRE(v1.capacity() == 50);
        REQUIRE(v1.size() == 50);
        for (const auto i : v1) {
            REQUIRE(i == 0);
        }
    }
    SECTION("copies of provided value", "[vector]") {
        jade::vector<int> v1(50, 123);
        REQUIRE(v1.capacity() == 50);
        REQUIRE(v1.size() == 50);
        for (const auto i : v1) {
            REQUIRE(i == 123);
        }
    }
}

TEST_CASE("move constructor", "[vector]") {
    jade::vector<int> v1 = { 1, 2, 3 };
    REQUIRE(v1.size() == 3);
    REQUIRE(v1.capacity() == 3);

    jade::vector<int> v2{std::move(v1)};
    REQUIRE(v1.size() == 0);
    REQUIRE(v1.capacity() == 0);
    REQUIRE(v2.size() == 3);
    REQUIRE(v2.capacity() == 3);
}

TEST_CASE("a vector is resizable", "[vector]") {
    jade::vector<int> v;
    v.resize(16);
    REQUIRE(v.capacity() == 16);
    REQUIRE(v.size() == 0);
}

TEST_CASE("a new vector is resizable to zero", "[vector]") {
    jade::vector<int> v;
    v.resize(0);
    REQUIRE(v.capacity() == 0);
    REQUIRE(v.size() == 0);
}

TEST_CASE("resizing a vector keeps it consistent", "[vector]") {
    jade::vector<int> v;
    REQUIRE(v.capacity() == 0);
    REQUIRE(v.size() == 0);

    v.push_back(1);
    v.push_back(2);
    v.push_back(3);
    REQUIRE(v.capacity() == 4);
    REQUIRE(v.size() == 3);

    v.resize(16);
    REQUIRE(v.capacity() == 16);
    REQUIRE(v.size() == 3);

    v.resize(0);
    REQUIRE(v.capacity() == 0);
    REQUIRE(v.size() == 0);

    v.push_back(1);
    v.push_back(2);
    v.push_back(3);
    REQUIRE(v.capacity() == 4);
    REQUIRE(v.size() == 3);

    v.resize(16);
    REQUIRE(v.capacity() == 16);
    REQUIRE(v.size() == 3);
}
<|endoftext|>


<commit_before>// This file is part of the uSTL library, an STL implementation.
//
// Copyright (c) 2005 Mike Sharov <msharov@users.sourceforge.net>
// This file is free software, distributed under the MIT License.

#include "stdtest.h"
#include "../uqueue.h"
#include "../ustack.h"

void TestStackAndQueue (void)
{
    stack<int> s;
    cout << "Testing stack: ";
    for (size_t i = 0; i < 5; ++ i)
	s.push (1 + i);
    s.emplace (42);
    cout << "popping:";
    while (!s.empty()) {
	cout << ' ' << s.top();
	s.pop();
    }
    cout << endl;

    queue<int> q;
    cout << "Testing queue: ";
    for (size_t k = 0; k < 5; ++ k)
	q.push (1 + k);
    q.emplace (42);
    cout << "popping:";
    while (!q.empty()) {
	cout << ' ' << q.front();
	q.pop();
    }
    cout << endl;
}

StdBvtMain (TestStackAndQueue)
<commit_msg>Stack and queue test should have fallback for pre-c++11 builds. Fixes #61.<commit_after>// This file is part of the uSTL library, an STL implementation.
//
// Copyright (c) 2005 Mike Sharov <msharov@users.sourceforge.net>
// This file is free software, distributed under the MIT License.

#include "stdtest.h"
#include "../uqueue.h"
#include "../ustack.h"

void TestStackAndQueue (void)
{
    stack<int> s;
    cout << "Testing stack: ";
    for (size_t i = 0; i < 5; ++ i)
	s.push (1 + i);
#if HAVE_CPP11
    s.emplace (42);
#else
    s.push (42);
#endif
    cout << "popping:";
    while (!s.empty()) {
	cout << ' ' << s.top();
	s.pop();
    }
    cout << endl;

    queue<int> q;
    cout << "Testing queue: ";
    for (size_t k = 0; k < 5; ++ k)
	q.push (1 + k);
#if HAVE_CPP11
    q.emplace (42);
#else
    q.push (42);
#endif
    cout << "popping:";
    while (!q.empty()) {
	cout << ' ' << q.front();
	q.pop();
    }
    cout << endl;
}

StdBvtMain (TestStackAndQueue)
<|endoftext|>


<commit_before>#include <fcntl.h>
#include <google/protobuf/io/coded_stream.h>
#include <google/protobuf/io/zero_copy_stream_impl.h>
#include <google/protobuf/text_format.h>
#include <opencv2/core/core.hpp>
#ifdef USE_OPENCV
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/highgui/highgui_c.h>
#include <opencv2/imgproc/imgproc.hpp>
#endif  // USE_OPENCV
#include <stdint.h>

#include <algorithm>
#include <fstream>  // NOLINT(readability/streams)
#include <string>
#include <vector>

#include "caffe/common.hpp"
#include "caffe/proto/caffe.pb.h"
#include "caffe/util/io.hpp"

const int kProtoReadBytesLimit = INT_MAX;  // Max size of 2 GB minus 1 byte.

namespace caffe {

using google::protobuf::io::FileInputStream;
using google::protobuf::io::FileOutputStream;
using google::protobuf::io::ZeroCopyInputStream;
using google::protobuf::io::CodedInputStream;
using google::protobuf::io::ZeroCopyOutputStream;
using google::protobuf::io::CodedOutputStream;
using google::protobuf::Message;

bool ReadProtoFromTextFile(const char* filename, Message* proto) {
  int fd = open(filename, O_RDONLY);
  CHECK_NE(fd, -1) << "File not found: " << filename;
  FileInputStream* input = new FileInputStream(fd);
  bool success = google::protobuf::TextFormat::Parse(input, proto);
  delete input;
  close(fd);
  return success;
}

void WriteProtoToTextFile(const Message& proto, const char* filename) {
  int fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC, 0644);
  FileOutputStream* output = new FileOutputStream(fd);
  CHECK(google::protobuf::TextFormat::Print(proto, output));
  delete output;
  close(fd);
}

bool ReadProtoFromBinaryFile(const char* filename, Message* proto) {
  int fd = open(filename, O_RDONLY);
  CHECK_NE(fd, -1) << "File not found: " << filename;
  ZeroCopyInputStream* raw_input = new FileInputStream(fd);
  CodedInputStream* coded_input = new CodedInputStream(raw_input);
  coded_input->SetTotalBytesLimit(kProtoReadBytesLimit, 536870912);

  bool success = proto->ParseFromCodedStream(coded_input);

  delete coded_input;
  delete raw_input;
  close(fd);
  return success;
}

void WriteProtoToBinaryFile(const Message& proto, const char* filename) {
  fstream output(filename, ios::out | ios::trunc | ios::binary);
  CHECK(proto.SerializeToOstream(&output));
}

#ifdef USE_OPENCV
cv::Mat ReadImageToCVMat(const string& filename,
    const int height, const int width, const bool is_color) {
  cv::Mat cv_img;
  int cv_read_flag = (is_color ? CV_LOAD_IMAGE_COLOR :
    CV_LOAD_IMAGE_GRAYSCALE);
  cv::Mat cv_img_origin = cv::imread(filename, cv_read_flag);
  if (!cv_img_origin.data) {
    LOG(ERROR) << "Could not open or find file " << filename;
    return cv_img_origin;
  }
  if (height > 0 && width > 0) {
    cv::resize(cv_img_origin, cv_img, cv::Size(width, height));
  } else {
    cv_img = cv_img_origin;
  }
  return cv_img;
}

cv::Mat ReadImageToCVMat(const string& filename,
    const int height, const int width) {
  return ReadImageToCVMat(filename, height, width, true);
}

cv::Mat ReadImageToCVMat(const string& filename,
    const bool is_color) {
  return ReadImageToCVMat(filename, 0, 0, is_color);
}

cv::Mat ReadImageToCVMat(const string& filename) {
  return ReadImageToCVMat(filename, 0, 0, true);
}

// Do the file extension and encoding match?
static bool matchExt(const std::string & fn,
                     std::string en) {
  size_t p = fn.rfind('.');
  std::string ext = p != fn.npos ? fn.substr(p) : fn;
  std::transform(ext.begin(), ext.end(), ext.begin(), ::tolower);
  std::transform(en.begin(), en.end(), en.begin(), ::tolower);
  if ( ext == en )
    return true;
  if ( en == "jpg" && ext == "jpeg" )
    return true;
  return false;
}

bool ReadImageToDatum(const string& filename, const int label,
    const int height, const int width, const bool is_color,
    const std::string & encoding, Datum* datum) {
  cv::Mat cv_img = ReadImageToCVMat(filename, height, width, is_color);
  if (cv_img.data) {
    if (encoding.size()) {
      if ( (cv_img.channels() == 3) == is_color && !height && !width &&
          matchExt(filename, encoding) )
        return ReadFileToDatum(filename, label, datum);
      std::vector<uchar> buf;
      cv::imencode("."+encoding, cv_img, buf);
      datum->set_data(std::string(reinterpret_cast<char*>(&buf[0]),
                      buf.size()));
      datum->set_label(label);
      datum->set_encoded(true);
      return true;
    }
    CVMatToDatum(cv_img, datum);
    datum->set_label(label);
    return true;
  } else {
    return false;
  }
}
#endif  // USE_OPENCV

bool ReadFileToDatum(const string& filename, const int label,
    Datum* datum) {
  std::streampos size;

  fstream file(filename.c_str(), ios::in|ios::binary|ios::ate);
  if (file.is_open()) {
    size = file.tellg();
    std::string buffer(size, ' ');
    file.seekg(0, ios::beg);
    file.read(&buffer[0], size);
    file.close();
    datum->set_data(buffer);
    datum->set_label(label);
    datum->set_encoded(true);
    return true;
  } else {
    return false;
  }
}

#ifdef USE_OPENCV
cv::Mat DecodeDatumToCVMatNative(const Datum& datum) {
  cv::Mat cv_img;
  CHECK(datum.encoded()) << "Datum not encoded";
  const string& data = datum.data();
  std::vector<char> vec_data(data.c_str(), data.c_str() + data.size());
  cv_img = cv::imdecode(vec_data, -1);
  if (!cv_img.data) {
    LOG(ERROR) << "Could not decode datum ";
  }
  return cv_img;
}
cv::Mat DecodeDatumToCVMat(const Datum& datum, bool is_color) {
  cv::Mat cv_img;
  CHECK(datum.encoded()) << "Datum not encoded";
  const string& data = datum.data();
  std::vector<char> vec_data(data.c_str(), data.c_str() + data.size());
  int cv_read_flag = (is_color ? CV_LOAD_IMAGE_COLOR :
    CV_LOAD_IMAGE_GRAYSCALE);
  cv_img = cv::imdecode(vec_data, cv_read_flag);
  if (!cv_img.data) {
    LOG(ERROR) << "Could not decode datum ";
  }
  return cv_img;
}

// If Datum is encoded will decoded using DecodeDatumToCVMat and CVMatToDatum
// If Datum is not encoded will do nothing
bool DecodeDatumNative(Datum* datum) {
  if (datum->encoded()) {
    cv::Mat cv_img = DecodeDatumToCVMatNative((*datum));
    CVMatToDatum(cv_img, datum);
    return true;
  } else {
    return false;
  }
}
bool DecodeDatum(Datum* datum, bool is_color) {
  if (datum->encoded()) {
    cv::Mat cv_img = DecodeDatumToCVMat((*datum), is_color);
    CVMatToDatum(cv_img, datum);
    return true;
  } else {
    return false;
  }
}

void CVMatToDatum(const cv::Mat& cv_img, Datum* datum) {
  CHECK(cv_img.depth() == CV_8U) << "Image data type must be unsigned byte";
  datum->set_channels(cv_img.channels());
  datum->set_height(cv_img.rows);
  datum->set_width(cv_img.cols);
  datum->clear_data();
  datum->clear_float_data();
  datum->set_encoded(false);
  int datum_channels = datum->channels();
  int datum_height = datum->height();
  int datum_width = datum->width();
  int datum_size = datum_channels * datum_height * datum_width;
  std::string buffer(datum_size, ' ');
  for (int h = 0; h < datum_height; ++h) {
    const uchar* ptr = cv_img.ptr<uchar>(h);
    int img_index = 0;
    for (int w = 0; w < datum_width; ++w) {
      for (int c = 0; c < datum_channels; ++c) {
        int datum_index = (c * datum_height + h) * datum_width + w;
        buffer[datum_index] = static_cast<char>(ptr[img_index++]);
      }
    }
  }
  datum->set_data(buffer);
}
#endif  // USE_OPENCV
}  // namespace caffe
<commit_msg>Exclude core.hpp when building without OpenCV<commit_after>#include <fcntl.h>
#include <google/protobuf/io/coded_stream.h>
#include <google/protobuf/io/zero_copy_stream_impl.h>
#include <google/protobuf/text_format.h>
#ifdef USE_OPENCV
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/highgui/highgui_c.h>
#include <opencv2/imgproc/imgproc.hpp>
#endif  // USE_OPENCV
#include <stdint.h>

#include <algorithm>
#include <fstream>  // NOLINT(readability/streams)
#include <string>
#include <vector>

#include "caffe/common.hpp"
#include "caffe/proto/caffe.pb.h"
#include "caffe/util/io.hpp"

const int kProtoReadBytesLimit = INT_MAX;  // Max size of 2 GB minus 1 byte.

namespace caffe {

using google::protobuf::io::FileInputStream;
using google::protobuf::io::FileOutputStream;
using google::protobuf::io::ZeroCopyInputStream;
using google::protobuf::io::CodedInputStream;
using google::protobuf::io::ZeroCopyOutputStream;
using google::protobuf::io::CodedOutputStream;
using google::protobuf::Message;

bool ReadProtoFromTextFile(const char* filename, Message* proto) {
  int fd = open(filename, O_RDONLY);
  CHECK_NE(fd, -1) << "File not found: " << filename;
  FileInputStream* input = new FileInputStream(fd);
  bool success = google::protobuf::TextFormat::Parse(input, proto);
  delete input;
  close(fd);
  return success;
}

void WriteProtoToTextFile(const Message& proto, const char* filename) {
  int fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC, 0644);
  FileOutputStream* output = new FileOutputStream(fd);
  CHECK(google::protobuf::TextFormat::Print(proto, output));
  delete output;
  close(fd);
}

bool ReadProtoFromBinaryFile(const char* filename, Message* proto) {
  int fd = open(filename, O_RDONLY);
  CHECK_NE(fd, -1) << "File not found: " << filename;
  ZeroCopyInputStream* raw_input = new FileInputStream(fd);
  CodedInputStream* coded_input = new CodedInputStream(raw_input);
  coded_input->SetTotalBytesLimit(kProtoReadBytesLimit, 536870912);

  bool success = proto->ParseFromCodedStream(coded_input);

  delete coded_input;
  delete raw_input;
  close(fd);
  return success;
}

void WriteProtoToBinaryFile(const Message& proto, const char* filename) {
  fstream output(filename, ios::out | ios::trunc | ios::binary);
  CHECK(proto.SerializeToOstream(&output));
}

#ifdef USE_OPENCV
cv::Mat ReadImageToCVMat(const string& filename,
    const int height, const int width, const bool is_color) {
  cv::Mat cv_img;
  int cv_read_flag = (is_color ? CV_LOAD_IMAGE_COLOR :
    CV_LOAD_IMAGE_GRAYSCALE);
  cv::Mat cv_img_origin = cv::imread(filename, cv_read_flag);
  if (!cv_img_origin.data) {
    LOG(ERROR) << "Could not open or find file " << filename;
    return cv_img_origin;
  }
  if (height > 0 && width > 0) {
    cv::resize(cv_img_origin, cv_img, cv::Size(width, height));
  } else {
    cv_img = cv_img_origin;
  }
  return cv_img;
}

cv::Mat ReadImageToCVMat(const string& filename,
    const int height, const int width) {
  return ReadImageToCVMat(filename, height, width, true);
}

cv::Mat ReadImageToCVMat(const string& filename,
    const bool is_color) {
  return ReadImageToCVMat(filename, 0, 0, is_color);
}

cv::Mat ReadImageToCVMat(const string& filename) {
  return ReadImageToCVMat(filename, 0, 0, true);
}

// Do the file extension and encoding match?
static bool matchExt(const std::string & fn,
                     std::string en) {
  size_t p = fn.rfind('.');
  std::string ext = p != fn.npos ? fn.substr(p) : fn;
  std::transform(ext.begin(), ext.end(), ext.begin(), ::tolower);
  std::transform(en.begin(), en.end(), en.begin(), ::tolower);
  if ( ext == en )
    return true;
  if ( en == "jpg" && ext == "jpeg" )
    return true;
  return false;
}

bool ReadImageToDatum(const string& filename, const int label,
    const int height, const int width, const bool is_color,
    const std::string & encoding, Datum* datum) {
  cv::Mat cv_img = ReadImageToCVMat(filename, height, width, is_color);
  if (cv_img.data) {
    if (encoding.size()) {
      if ( (cv_img.channels() == 3) == is_color && !height && !width &&
          matchExt(filename, encoding) )
        return ReadFileToDatum(filename, label, datum);
      std::vector<uchar> buf;
      cv::imencode("."+encoding, cv_img, buf);
      datum->set_data(std::string(reinterpret_cast<char*>(&buf[0]),
                      buf.size()));
      datum->set_label(label);
      datum->set_encoded(true);
      return true;
    }
    CVMatToDatum(cv_img, datum);
    datum->set_label(label);
    return true;
  } else {
    return false;
  }
}
#endif  // USE_OPENCV

bool ReadFileToDatum(const string& filename, const int label,
    Datum* datum) {
  std::streampos size;

  fstream file(filename.c_str(), ios::in|ios::binary|ios::ate);
  if (file.is_open()) {
    size = file.tellg();
    std::string buffer(size, ' ');
    file.seekg(0, ios::beg);
    file.read(&buffer[0], size);
    file.close();
    datum->set_data(buffer);
    datum->set_label(label);
    datum->set_encoded(true);
    return true;
  } else {
    return false;
  }
}

#ifdef USE_OPENCV
cv::Mat DecodeDatumToCVMatNative(const Datum& datum) {
  cv::Mat cv_img;
  CHECK(datum.encoded()) << "Datum not encoded";
  const string& data = datum.data();
  std::vector<char> vec_data(data.c_str(), data.c_str() + data.size());
  cv_img = cv::imdecode(vec_data, -1);
  if (!cv_img.data) {
    LOG(ERROR) << "Could not decode datum ";
  }
  return cv_img;
}
cv::Mat DecodeDatumToCVMat(const Datum& datum, bool is_color) {
  cv::Mat cv_img;
  CHECK(datum.encoded()) << "Datum not encoded";
  const string& data = datum.data();
  std::vector<char> vec_data(data.c_str(), data.c_str() + data.size());
  int cv_read_flag = (is_color ? CV_LOAD_IMAGE_COLOR :
    CV_LOAD_IMAGE_GRAYSCALE);
  cv_img = cv::imdecode(vec_data, cv_read_flag);
  if (!cv_img.data) {
    LOG(ERROR) << "Could not decode datum ";
  }
  return cv_img;
}

// If Datum is encoded will decoded using DecodeDatumToCVMat and CVMatToDatum
// If Datum is not encoded will do nothing
bool DecodeDatumNative(Datum* datum) {
  if (datum->encoded()) {
    cv::Mat cv_img = DecodeDatumToCVMatNative((*datum));
    CVMatToDatum(cv_img, datum);
    return true;
  } else {
    return false;
  }
}
bool DecodeDatum(Datum* datum, bool is_color) {
  if (datum->encoded()) {
    cv::Mat cv_img = DecodeDatumToCVMat((*datum), is_color);
    CVMatToDatum(cv_img, datum);
    return true;
  } else {
    return false;
  }
}

void CVMatToDatum(const cv::Mat& cv_img, Datum* datum) {
  CHECK(cv_img.depth() == CV_8U) << "Image data type must be unsigned byte";
  datum->set_channels(cv_img.channels());
  datum->set_height(cv_img.rows);
  datum->set_width(cv_img.cols);
  datum->clear_data();
  datum->clear_float_data();
  datum->set_encoded(false);
  int datum_channels = datum->channels();
  int datum_height = datum->height();
  int datum_width = datum->width();
  int datum_size = datum_channels * datum_height * datum_width;
  std::string buffer(datum_size, ' ');
  for (int h = 0; h < datum_height; ++h) {
    const uchar* ptr = cv_img.ptr<uchar>(h);
    int img_index = 0;
    for (int w = 0; w < datum_width; ++w) {
      for (int c = 0; c < datum_channels; ++c) {
        int datum_index = (c * datum_height + h) * datum_width + w;
        buffer[datum_index] = static_cast<char>(ptr[img_index++]);
      }
    }
  }
  datum->set_data(buffer);
}
#endif  // USE_OPENCV
}  // namespace caffe
<|endoftext|>


<commit_before>#ifndef CAN_EMULATOR

#include "usbutil.h"
#include "canread.h"
#include "serialutil.h"
#include "signals.h"
#include "log.h"
#include "cJSON.h"
#include "listener.h"
#include <stdint.h>

extern SerialDevice SERIAL_DEVICE;
extern UsbDevice USB_DEVICE;
extern Listener listener;

/* Forward declarations */

void receiveCan(CanBus*);
void initializeAllCan();
bool receiveWriteRequest(uint8_t*);
bool receiveCANWriteRequest(uint8_t*);

void setup() {
    initializeLogging();
    initializeSerial(&SERIAL_DEVICE);
    initializeUsb(&USB_DEVICE);
    initializeAllCan();
}

void loop() {
    for(int i = 0; i < getCanBusCount(); i++) {
        receiveCan(&getCanBuses()[i]);
    }
    processListenerQueues(&listener);
#ifdef TRANSMITTER
    readFromHost(&USB_DEVICE, &receiveCANWriteRequest);
    readFromSerial(&SERIAL_DEVICE, &receiveCANWriteRequest);
#else
    readFromHost(&USB_DEVICE, &receiveWriteRequest);
    readFromSerial(&SERIAL_DEVICE, &receiveWriteRequest);
    for(int i = 0; i < getCanBusCount(); i++) {
        processCanWriteQueue(&getCanBuses()[i]);
    }
#endif
}

void initializeAllCan() {
    for(int i = 0; i < getCanBusCount(); i++) {
        initializeCan(&(getCanBuses()[i]));
    }
}
#ifdef TRANSMITTER
bool receiveCANWriteRequest(uint8_t* message) {
    int index=0;
    int packetLength = 15;

    //    while((message[index] != '!') && (index + packetLength < 64)) {
    while(true){
      if(message[index] == '!') {
	return true;
      }
      if  (index + packetLength >= 64)
	{
	  debug("!");
	}
        if((message[index] != '{') || (message[index+5] != '|') || (message[index+14] != '}'))
	{
	    debug("Received a corrupted CAN message.\r\n");
	    for(int i = 0; i < 16; i++) {
	        debug("%02x ", message[index+i] );
	    }
	    debug("\r\n");
	    return false;
	}

	CanMessage outGoing = {0, 0};

	memcpy((uint8_t*)&outGoing.id, &message[index+1], 4);

	for(int i = 0; i < 8; i++) {
	    ((uint8_t*)&(outGoing.data))[i] = message[index+i+6];
	}

	//    debug("Sending CAN message id = 0x%02x, data = 0x", outGoing.id);
	//for(int i = 0; i < 8; i++) {
	//    debug("%02x ", ((uint8_t*)&(outGoing.data))[i] );
	//}
	//debug("\r\n");

	sendCanMessage(&(getCanBuses()[0]), outGoing);

	index += packetLength;
    }

    return true;
}

#else    //ifdef TRANSMITTER

bool receiveRawWriteRequest(cJSON* idObject, cJSON* root) {
    int id = idObject->valueint;
    cJSON* dataObject = cJSON_GetObjectItem(root, "data");
    if(dataObject == NULL) {
        debug("Raw write request with id 0x%x missing data\r\n", id);
        return true;
    }
    int data = dataObject->valueint;
    CanMessage message = {id, data};
    debug("Writing raw CAN message 0x%x: 0x%x\r\n", id, data);
    // TODO specify bus by address in JSON
    sendCanMessage(&getCanBuses()[0], message);

    return true;
}

bool receiveWriteRequest(uint8_t* message) {

    cJSON *root = cJSON_Parse((char*)message);
    if(root != NULL) {
        cJSON* nameObject = cJSON_GetObjectItem(root, "name");
        if(nameObject == NULL) {
            cJSON* idObject = cJSON_GetObjectItem(root, "id");
            if(idObject == NULL) {
                debug("Write request is malformed, "
                        "missing name or id: %s\r\n", message);
                return true;
            } else {
                return receiveRawWriteRequest(idObject, root);
            }
        }

        char* name = nameObject->valuestring;
        cJSON* value = cJSON_GetObjectItem(root, "value");
        if(value == NULL) {
            debug("Write request for %s missing value\r\n", name);
            return true;
        }

        CanSignal* signal = lookupSignal(name, getSignals(),
                getSignalCount(), true);
        CanCommand* command = lookupCommand(name, getCommands(),
                getCommandCount());
        if(signal != NULL) {
            sendCanSignal(signal, value, getSignals(), getSignalCount());
        } else if(command != NULL) {
            command->handler(name, value, getSignals(), getSignalCount());
        } else {
            debug("Writing not allowed for signal with name %s\r\n", name);
        }
        cJSON_Delete(root);
        return true;
    }
    return false;
}
#endif
/*
 * Check to see if a packet has been received. If so, read the packet and print
 * the packet payload to the serial monitor.
 */
void receiveCan(CanBus* bus) {
    // TODO what happens if we process until the queue is empty?
    if(!QUEUE_EMPTY(CanMessage, &bus->receiveQueue)) {
        CanMessage message = QUEUE_POP(CanMessage, &bus->receiveQueue);
        decodeCanMessage(message.id, message.data);
    }
}

void reset() {
    initializeAllCan();
}

#endif // CAN_EMULATOR
<commit_msg>Enqueue raw write requests instead of sending manually.<commit_after>#ifndef CAN_EMULATOR

#include "usbutil.h"
#include "canread.h"
#include "serialutil.h"
#include "signals.h"
#include "log.h"
#include "cJSON.h"
#include "listener.h"
#include <stdint.h>

extern SerialDevice SERIAL_DEVICE;
extern UsbDevice USB_DEVICE;
extern Listener listener;

/* Forward declarations */

void receiveCan(CanBus*);
void initializeAllCan();
bool receiveWriteRequest(uint8_t*);
bool receiveCANWriteRequest(uint8_t*);

void setup() {
    initializeLogging();
    initializeSerial(&SERIAL_DEVICE);
    initializeUsb(&USB_DEVICE);
    initializeAllCan();
}

void loop() {
    for(int i = 0; i < getCanBusCount(); i++) {
        receiveCan(&getCanBuses()[i]);
    }
    processListenerQueues(&listener);
#ifdef TRANSMITTER
    readFromHost(&USB_DEVICE, &receiveCANWriteRequest);
    readFromSerial(&SERIAL_DEVICE, &receiveCANWriteRequest);
#else
    readFromHost(&USB_DEVICE, &receiveWriteRequest);
    readFromSerial(&SERIAL_DEVICE, &receiveWriteRequest);
    for(int i = 0; i < getCanBusCount(); i++) {
        processCanWriteQueue(&getCanBuses()[i]);
    }
#endif
}

void initializeAllCan() {
    for(int i = 0; i < getCanBusCount(); i++) {
        initializeCan(&(getCanBuses()[i]));
    }
}
#ifdef TRANSMITTER
bool receiveCANWriteRequest(uint8_t* message) {
    int index=0;
    int packetLength = 15;

    //    while((message[index] != '!') && (index + packetLength < 64)) {
    while(true){
      if(message[index] == '!') {
	return true;
      }
      if  (index + packetLength >= 64)
	{
	  debug("!");
	}
        if((message[index] != '{') || (message[index+5] != '|') || (message[index+14] != '}'))
	{
	    debug("Received a corrupted CAN message.\r\n");
	    for(int i = 0; i < 16; i++) {
	        debug("%02x ", message[index+i] );
	    }
	    debug("\r\n");
	    return false;
	}

	CanMessage outGoing = {0, 0};

	memcpy((uint8_t*)&outGoing.id, &message[index+1], 4);

	for(int i = 0; i < 8; i++) {
	    ((uint8_t*)&(outGoing.data))[i] = message[index+i+6];
	}

	//    debug("Sending CAN message id = 0x%02x, data = 0x", outGoing.id);
	//for(int i = 0; i < 8; i++) {
	//    debug("%02x ", ((uint8_t*)&(outGoing.data))[i] );
	//}
	//debug("\r\n");

	sendCanMessage(&(getCanBuses()[0]), outGoing);

	index += packetLength;
    }

    return true;
}

#else    //ifdef TRANSMITTER

bool receiveRawWriteRequest(cJSON* idObject, cJSON* root) {
    int id = idObject->valueint;
    cJSON* dataObject = cJSON_GetObjectItem(root, "data");
    if(dataObject == NULL) {
        debug("Raw write request missing data\r\n", id);
        return true;
    }
    int data = dataObject->valueint;
    CanMessage message = {id, data};
    QUEUE_PUSH(CanMessage, &getCanBuses()[0].sendQueue, message);
    return true;
}

bool receiveWriteRequest(uint8_t* message) {

    cJSON *root = cJSON_Parse((char*)message);
    if(root != NULL) {
        cJSON* nameObject = cJSON_GetObjectItem(root, "name");
        if(nameObject == NULL) {
            cJSON* idObject = cJSON_GetObjectItem(root, "id");
            if(idObject == NULL) {
                debug("Write request is malformed, "
                        "missing name or id: %s\r\n", message);
                return true;
            } else {
                return receiveRawWriteRequest(idObject, root);
            }
        }

        char* name = nameObject->valuestring;
        cJSON* value = cJSON_GetObjectItem(root, "value");
        if(value == NULL) {
            debug("Write request for %s missing value\r\n", name);
            return true;
        }

        CanSignal* signal = lookupSignal(name, getSignals(),
                getSignalCount(), true);
        CanCommand* command = lookupCommand(name, getCommands(),
                getCommandCount());
        if(signal != NULL) {
            sendCanSignal(signal, value, getSignals(), getSignalCount());
        } else if(command != NULL) {
            command->handler(name, value, getSignals(), getSignalCount());
        } else {
            debug("Writing not allowed for signal with name %s\r\n", name);
        }
        cJSON_Delete(root);
        return true;
    }
    return false;
}
#endif
/*
 * Check to see if a packet has been received. If so, read the packet and print
 * the packet payload to the serial monitor.
 */
void receiveCan(CanBus* bus) {
    // TODO what happens if we process until the queue is empty?
    if(!QUEUE_EMPTY(CanMessage, &bus->receiveQueue)) {
        CanMessage message = QUEUE_POP(CanMessage, &bus->receiveQueue);
        decodeCanMessage(message.id, message.data);
    }
}

void reset() {
    initializeAllCan();
}

#endif // CAN_EMULATOR
<|endoftext|>


<commit_before>/******************************************************************************
 *
 * File:         seam.cpp  (Formerly seam.c)
 * Author:       Mark Seaman, OCR Technology
 *
 * (c) Copyright 1987, Hewlett-Packard Company.
 ** Licensed under the Apache License, Version 2.0 (the "License");
 ** you may not use this file except in compliance with the License.
 ** You may obtain a copy of the License at
 ** http://www.apache.org/licenses/LICENSE-2.0
 ** Unless required by applicable law or agreed to in writing, software
 ** distributed under the License is distributed on an "AS IS" BASIS,
 ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 ** See the License for the specific language governing permissions and
 ** limitations under the License.
 *
 *****************************************************************************/
/*----------------------------------------------------------------------
              I n c l u d e s
----------------------------------------------------------------------*/
#include "seam.h"
#include "blobs.h"
#include "tprintf.h"

/*----------------------------------------------------------------------
        Public Function Code
----------------------------------------------------------------------*/

// Returns the bounding box of all the points in the seam.
TBOX SEAM::bounding_box() const {
  TBOX box(location_.x, location_.y, location_.x, location_.y);
  for (int s = 0; s < num_splits_; ++s) {
    box += splits_[s].bounding_box();
  }
  return box;
}

// Returns true if the splits in *this SEAM appear OK in the sense that they
// do not cross any outlines and do not chop off any ridiculously small
// pieces.
bool SEAM::IsHealthy(const TBLOB& blob, int min_points, int min_area) const {
  // TODO(rays) Try testing all the splits. Duplicating original code for now,
  // which tested only the first.
  return num_splits_ == 0 || splits_[0].IsHealthy(blob, min_points, min_area);
}

// Computes the widthp_/widthn_ range for all existing SEAMs and for *this
// seam, which is about to be inserted at insert_index. Returns false if
// any of the computations fails, as this indicates an invalid chop.
// widthn_/widthp_ are only changed if modify is true.
bool SEAM::PrepareToInsertSeam(const GenericVector<SEAM*>& seams,
                               const GenericVector<TBLOB*>& blobs,
                               int insert_index, bool modify) {
  for (int s = 0; s < insert_index; ++s) {
    if (!seams[s]->FindBlobWidth(blobs, s, modify)) return false;
  }
  if (!FindBlobWidth(blobs, insert_index, modify)) return false;
  for (int s = insert_index; s < seams.size(); ++s) {
    if (!seams[s]->FindBlobWidth(blobs, s + 1, modify)) return false;
  }
  return true;
}

// Computes the widthp_/widthn_ range. Returns false if not all the splits
// are accounted for. widthn_/widthp_ are only changed if modify is true.
bool SEAM::FindBlobWidth(const GenericVector<TBLOB*>& blobs, int index,
                         bool modify) {
  int num_found = 0;
  if (modify) {
    widthp_ = 0;
    widthn_ = 0;
  }
  for (int s = 0; s < num_splits_; ++s) {
    const SPLIT& split = splits_[s];
    bool found_split = split.ContainedByBlob(*blobs[index]);
    // Look right.
    for (int b = index + 1; !found_split && b < blobs.size(); ++b) {
      found_split = split.ContainedByBlob(*blobs[b]);
      if (found_split && b - index > widthp_ && modify) widthp_ = b - index;
    }
    // Look left.
    for (int b = index - 1; !found_split && b >= 0; --b) {
      found_split = split.ContainedByBlob(*blobs[b]);
      if (found_split && index - b > widthn_ && modify) widthn_ = index - b;
    }
    if (found_split) ++num_found;
  }
  return num_found == num_splits_;
}

// Splits this blob into two blobs by applying the splits included in
// *this SEAM
void SEAM::ApplySeam(bool italic_blob, TBLOB* blob, TBLOB* other_blob) const {
  for (int s = 0; s < num_splits_; ++s) {
    splits_[s].SplitOutlineList(blob->outlines);
  }
  blob->ComputeBoundingBoxes();

  divide_blobs(blob, other_blob, italic_blob, location_);

  blob->EliminateDuplicateOutlines();
  other_blob->EliminateDuplicateOutlines();

  blob->CorrectBlobOrder(other_blob);
}

// Undoes ApplySeam by removing the seam between these two blobs.
// Produces one blob as a result, and deletes other_blob.
void SEAM::UndoSeam(TBLOB* blob, TBLOB* other_blob) const {
  if (blob->outlines == nullptr) {
    blob->outlines = other_blob->outlines;
    other_blob->outlines = nullptr;
  }

  TESSLINE* outline = blob->outlines;
  while (outline->next) outline = outline->next;
  outline->next = other_blob->outlines;
  other_blob->outlines = nullptr;
  delete other_blob;

  for (int s = 0; s < num_splits_; ++s) {
    splits_[s].UnsplitOutlineList(blob);
  }
  blob->ComputeBoundingBoxes();
  blob->EliminateDuplicateOutlines();
}

// Prints everything in *this SEAM.
void SEAM::Print(const char* label) const {
  tprintf(label);
  tprintf(" %6.2f @ (%d,%d), p=%d, n=%d ", priority_, location_.x, location_.y,
          widthp_, widthn_);
  for (int s = 0; s < num_splits_; ++s) {
    splits_[s].Print();
    if (s + 1 < num_splits_) tprintf(",   ");
  }
  tprintf("\n");
}

// Prints a collection of SEAMs.
/* static */
void SEAM::PrintSeams(const char* label, const GenericVector<SEAM*>& seams) {
  if (!seams.empty()) {
    tprintf("%s\n", label);
    for (int x = 0; x < seams.size(); ++x) {
      tprintf("%2d:   ", x);
      seams[x]->Print("");
    }
    tprintf("\n");
  }
}

#ifndef GRAPHICS_DISABLED
// Draws the seam in the given window.
void SEAM::Mark(ScrollView* window) const {
  for (int s = 0; s < num_splits_; ++s) splits_[s].Mark(window);
}
#endif

// Break up the blobs in this chain so that they are all independent.
// This operation should undo the affect of join_pieces.
/* static */
void SEAM::BreakPieces(const GenericVector<SEAM*>& seams,
                       const GenericVector<TBLOB*>& blobs, int first,
                       int last) {
  for (int x = first; x < last; ++x) seams[x]->Reveal();

  TESSLINE* outline = blobs[first]->outlines;
  int next_blob = first + 1;

  while (outline != nullptr && next_blob <= last) {
    if (outline->next == blobs[next_blob]->outlines) {
      outline->next = nullptr;
      outline = blobs[next_blob]->outlines;
      ++next_blob;
    } else {
      outline = outline->next;
    }
  }
}

// Join a group of base level pieces into a single blob that can then
// be classified.
/* static */
void SEAM::JoinPieces(const GenericVector<SEAM*>& seams,
                      const GenericVector<TBLOB*>& blobs, int first, int last) {
  TESSLINE* outline = blobs[first]->outlines;
  if (!outline)
    return;

  for (int x = first; x < last; ++x) {
    SEAM *seam = seams[x];
    if (x - seam->widthn_ >= first && x + seam->widthp_ < last) seam->Hide();
    while (outline->next) outline = outline->next;
    outline->next = blobs[x + 1]->outlines;
  }
}

// Hides the seam so the outlines appear not to be cut by it.
void SEAM::Hide() const {
  for (int s = 0; s < num_splits_; ++s) {
    splits_[s].Hide();
  }
}

// Undoes hide, so the outlines are cut by the seam.
void SEAM::Reveal() const {
  for (int s = 0; s < num_splits_; ++s) {
    splits_[s].Reveal();
  }
}

// Computes and returns, but does not set, the full priority of *this SEAM.
float SEAM::FullPriority(int xmin, int xmax, double overlap_knob,
                         int centered_maxwidth, double center_knob,
                         double width_change_knob) const {
  if (num_splits_ == 0) return 0.0f;
  for (int s = 1; s < num_splits_; ++s) {
    splits_[s].SplitOutline();
  }
  float full_priority =
      priority_ +
      splits_[0].FullPriority(xmin, xmax, overlap_knob, centered_maxwidth,
                              center_knob, width_change_knob);
  for (int s = num_splits_ - 1; s >= 1; --s) {
    splits_[s].UnsplitOutlines();
  }
  return full_priority;
}

/**
 * @name start_seam_list
 *
 * Initialize a list of seams that match the original number of blobs
 * present in the starting segmentation.  Each of the seams created
 * by this routine have location information only.
 */
void start_seam_list(TWERD* word, GenericVector<SEAM*>* seam_array) {
  seam_array->truncate(0);
  TPOINT location;

  for (int b = 1; b < word->NumBlobs(); ++b) {
    TBOX bbox = word->blobs[b - 1]->bounding_box();
    TBOX nbox = word->blobs[b]->bounding_box();
    location.x = (bbox.right() + nbox.left()) / 2;
    location.y = (bbox.bottom() + bbox.top() + nbox.bottom() + nbox.top()) / 4;
    seam_array->push_back(new SEAM(0.0f, location));
  }
}
<commit_msg>Fix insecure call of tprintf<commit_after>/******************************************************************************
 *
 * File:         seam.cpp  (Formerly seam.c)
 * Author:       Mark Seaman, OCR Technology
 *
 * (c) Copyright 1987, Hewlett-Packard Company.
 ** Licensed under the Apache License, Version 2.0 (the "License");
 ** you may not use this file except in compliance with the License.
 ** You may obtain a copy of the License at
 ** http://www.apache.org/licenses/LICENSE-2.0
 ** Unless required by applicable law or agreed to in writing, software
 ** distributed under the License is distributed on an "AS IS" BASIS,
 ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 ** See the License for the specific language governing permissions and
 ** limitations under the License.
 *
 *****************************************************************************/
/*----------------------------------------------------------------------
              I n c l u d e s
----------------------------------------------------------------------*/
#include "seam.h"
#include "blobs.h"
#include "tprintf.h"

/*----------------------------------------------------------------------
        Public Function Code
----------------------------------------------------------------------*/

// Returns the bounding box of all the points in the seam.
TBOX SEAM::bounding_box() const {
  TBOX box(location_.x, location_.y, location_.x, location_.y);
  for (int s = 0; s < num_splits_; ++s) {
    box += splits_[s].bounding_box();
  }
  return box;
}

// Returns true if the splits in *this SEAM appear OK in the sense that they
// do not cross any outlines and do not chop off any ridiculously small
// pieces.
bool SEAM::IsHealthy(const TBLOB& blob, int min_points, int min_area) const {
  // TODO(rays) Try testing all the splits. Duplicating original code for now,
  // which tested only the first.
  return num_splits_ == 0 || splits_[0].IsHealthy(blob, min_points, min_area);
}

// Computes the widthp_/widthn_ range for all existing SEAMs and for *this
// seam, which is about to be inserted at insert_index. Returns false if
// any of the computations fails, as this indicates an invalid chop.
// widthn_/widthp_ are only changed if modify is true.
bool SEAM::PrepareToInsertSeam(const GenericVector<SEAM*>& seams,
                               const GenericVector<TBLOB*>& blobs,
                               int insert_index, bool modify) {
  for (int s = 0; s < insert_index; ++s) {
    if (!seams[s]->FindBlobWidth(blobs, s, modify)) return false;
  }
  if (!FindBlobWidth(blobs, insert_index, modify)) return false;
  for (int s = insert_index; s < seams.size(); ++s) {
    if (!seams[s]->FindBlobWidth(blobs, s + 1, modify)) return false;
  }
  return true;
}

// Computes the widthp_/widthn_ range. Returns false if not all the splits
// are accounted for. widthn_/widthp_ are only changed if modify is true.
bool SEAM::FindBlobWidth(const GenericVector<TBLOB*>& blobs, int index,
                         bool modify) {
  int num_found = 0;
  if (modify) {
    widthp_ = 0;
    widthn_ = 0;
  }
  for (int s = 0; s < num_splits_; ++s) {
    const SPLIT& split = splits_[s];
    bool found_split = split.ContainedByBlob(*blobs[index]);
    // Look right.
    for (int b = index + 1; !found_split && b < blobs.size(); ++b) {
      found_split = split.ContainedByBlob(*blobs[b]);
      if (found_split && b - index > widthp_ && modify) widthp_ = b - index;
    }
    // Look left.
    for (int b = index - 1; !found_split && b >= 0; --b) {
      found_split = split.ContainedByBlob(*blobs[b]);
      if (found_split && index - b > widthn_ && modify) widthn_ = index - b;
    }
    if (found_split) ++num_found;
  }
  return num_found == num_splits_;
}

// Splits this blob into two blobs by applying the splits included in
// *this SEAM
void SEAM::ApplySeam(bool italic_blob, TBLOB* blob, TBLOB* other_blob) const {
  for (int s = 0; s < num_splits_; ++s) {
    splits_[s].SplitOutlineList(blob->outlines);
  }
  blob->ComputeBoundingBoxes();

  divide_blobs(blob, other_blob, italic_blob, location_);

  blob->EliminateDuplicateOutlines();
  other_blob->EliminateDuplicateOutlines();

  blob->CorrectBlobOrder(other_blob);
}

// Undoes ApplySeam by removing the seam between these two blobs.
// Produces one blob as a result, and deletes other_blob.
void SEAM::UndoSeam(TBLOB* blob, TBLOB* other_blob) const {
  if (blob->outlines == nullptr) {
    blob->outlines = other_blob->outlines;
    other_blob->outlines = nullptr;
  }

  TESSLINE* outline = blob->outlines;
  while (outline->next) outline = outline->next;
  outline->next = other_blob->outlines;
  other_blob->outlines = nullptr;
  delete other_blob;

  for (int s = 0; s < num_splits_; ++s) {
    splits_[s].UnsplitOutlineList(blob);
  }
  blob->ComputeBoundingBoxes();
  blob->EliminateDuplicateOutlines();
}

// Prints everything in *this SEAM.
void SEAM::Print(const char* label) const {
  tprintf("%s", label);
  tprintf(" %6.2f @ (%d,%d), p=%d, n=%d ", priority_, location_.x, location_.y,
          widthp_, widthn_);
  for (int s = 0; s < num_splits_; ++s) {
    splits_[s].Print();
    if (s + 1 < num_splits_) tprintf(",   ");
  }
  tprintf("\n");
}

// Prints a collection of SEAMs.
/* static */
void SEAM::PrintSeams(const char* label, const GenericVector<SEAM*>& seams) {
  if (!seams.empty()) {
    tprintf("%s\n", label);
    for (int x = 0; x < seams.size(); ++x) {
      tprintf("%2d:   ", x);
      seams[x]->Print("");
    }
    tprintf("\n");
  }
}

#ifndef GRAPHICS_DISABLED
// Draws the seam in the given window.
void SEAM::Mark(ScrollView* window) const {
  for (int s = 0; s < num_splits_; ++s) splits_[s].Mark(window);
}
#endif

// Break up the blobs in this chain so that they are all independent.
// This operation should undo the affect of join_pieces.
/* static */
void SEAM::BreakPieces(const GenericVector<SEAM*>& seams,
                       const GenericVector<TBLOB*>& blobs, int first,
                       int last) {
  for (int x = first; x < last; ++x) seams[x]->Reveal();

  TESSLINE* outline = blobs[first]->outlines;
  int next_blob = first + 1;

  while (outline != nullptr && next_blob <= last) {
    if (outline->next == blobs[next_blob]->outlines) {
      outline->next = nullptr;
      outline = blobs[next_blob]->outlines;
      ++next_blob;
    } else {
      outline = outline->next;
    }
  }
}

// Join a group of base level pieces into a single blob that can then
// be classified.
/* static */
void SEAM::JoinPieces(const GenericVector<SEAM*>& seams,
                      const GenericVector<TBLOB*>& blobs, int first, int last) {
  TESSLINE* outline = blobs[first]->outlines;
  if (!outline)
    return;

  for (int x = first; x < last; ++x) {
    SEAM *seam = seams[x];
    if (x - seam->widthn_ >= first && x + seam->widthp_ < last) seam->Hide();
    while (outline->next) outline = outline->next;
    outline->next = blobs[x + 1]->outlines;
  }
}

// Hides the seam so the outlines appear not to be cut by it.
void SEAM::Hide() const {
  for (int s = 0; s < num_splits_; ++s) {
    splits_[s].Hide();
  }
}

// Undoes hide, so the outlines are cut by the seam.
void SEAM::Reveal() const {
  for (int s = 0; s < num_splits_; ++s) {
    splits_[s].Reveal();
  }
}

// Computes and returns, but does not set, the full priority of *this SEAM.
float SEAM::FullPriority(int xmin, int xmax, double overlap_knob,
                         int centered_maxwidth, double center_knob,
                         double width_change_knob) const {
  if (num_splits_ == 0) return 0.0f;
  for (int s = 1; s < num_splits_; ++s) {
    splits_[s].SplitOutline();
  }
  float full_priority =
      priority_ +
      splits_[0].FullPriority(xmin, xmax, overlap_knob, centered_maxwidth,
                              center_knob, width_change_knob);
  for (int s = num_splits_ - 1; s >= 1; --s) {
    splits_[s].UnsplitOutlines();
  }
  return full_priority;
}

/**
 * @name start_seam_list
 *
 * Initialize a list of seams that match the original number of blobs
 * present in the starting segmentation.  Each of the seams created
 * by this routine have location information only.
 */
void start_seam_list(TWERD* word, GenericVector<SEAM*>* seam_array) {
  seam_array->truncate(0);
  TPOINT location;

  for (int b = 1; b < word->NumBlobs(); ++b) {
    TBOX bbox = word->blobs[b - 1]->bounding_box();
    TBOX nbox = word->blobs[b]->bounding_box();
    location.x = (bbox.right() + nbox.left()) / 2;
    location.y = (bbox.bottom() + bbox.top() + nbox.bottom() + nbox.top()) / 4;
    seam_array->push_back(new SEAM(0.0f, location));
  }
}
<|endoftext|>