/* Copyright 2016 Samsung Electronics Co., Ltd.
 *
 * 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.
 */

int memcmp_scl_std_functions = 0;

#define SCL_STD_FUNCTIONS memcmp_scl_std_functions

#include "scl/memory.h"

/* TODO check timings */

static int cmp(char unsigned const *u1, char unsigned const *u2, size_t size) {
	size_t i;
	int ret;

	SCL_ASSERT(size > 0);

	i = 0;
	while ((i < size - 1) && (u1[i] == u2[i])) {
		++i;
	}
	if (u1[i] < u2[i]) {
		ret = -1;
	} else if(u1[i] == u2[i]) {
		ret = 0;
	} else {
		ret = 1;
	}
	return ret;
}

static void init(char unsigned *b1, char unsigned *b2, int size, int equal_count) {
	int i;
	char unsigned c, d;
	c = (equal_count + size) % UCHAR_MAX;
	for (i = 0; i < equal_count; ++i) {
		b1[i] = c;
		b2[i] = c;
	}
	d = SCHAR_MAX + (c + 1) % 3 - 1;
	c = SCHAR_MAX + c % 3 - 1;
	while (i < size) {
		b1[i] = c;
		b2[i] = d;
		++i;
	}
}

static void do_tests(void) {
#	define count 133
	unsigned char buf[count];
	int i, j, k, l, m, di, dj;
	int ret;

	di = 1;
	dj = 3;

	i = 0;
	while (i < count - 1) {
		j = 0;
		while (j < count - 1) {
			if (i > j) {
				l = count - i;
			} else {
				l = count - j;
			}
			for (k = 1; k <= l; ++k) {
				for (m = 0; m <= k; ++m) {
					init(buf + i, buf + j, k, m);

					ret = scl_memcmp(buf + i, buf + j, k);

					SCL_ASSERT(cmp(buf + i, buf + j, k) == ret);
				}
			}

			j += dj;
			dj = dj % 7 + 1;
		}

		i += di;
		di = di % 8 + 1;
	}
#	undef count
}

#if defined(START_FUNC) && (START_FUNC == 1)
#	undef START_FUNC
#	define START_FUNC test_memcmp
#endif

#if defined(START_FUNC)
	extern void START_FUNC(void) {
		do_tests();
		memcmp_scl_std_functions = 1 - memcmp_scl_std_functions;
		do_tests();
	}
#else
	extern int main(int argc, char const **argv) {
		do_tests();
		memcmp_scl_std_functions = 1 - memcmp_scl_std_functions;
		do_tests();
		return 0;
	}
#endif
