Memory¶
Memory test source.
/******************************************************************************
* Copyright (c) Intel Corporation - All rights reserved. *
* This file is part of the LIBXS library. *
* *
* For information on the license, see the LICENSE file. *
* Further information: https://github.com/hfp/libxs/ *
* SPDX-License-Identifier: BSD-3-Clause *
******************************************************************************/
#include <libxs_source.h>
#if !defined(PRINT) && (defined(_DEBUG) || 0)
# define PRINT
#endif
#if defined(PRINT)
# define FPRINTF(STREAM, ...) do { fprintf(STREAM, __VA_ARGS__); } while(0)
#else
# define FPRINTF(STREAM, ...) do {} while(0)
#endif
int main(int argc, char* argv[])
{
char item[LIBXS_DESCRIPTOR_MAXSIZE];
const size_t elemsize = sizeof(item);
const int ndiffs = 1000, ntests = 1000;
const char init[] = "The quick brown fox jumps over the lazy dog", *delims = NULL;
int result = EXIT_SUCCESS, count = 0;
LIBXS_UNUSED(argc); LIBXS_UNUSED(argv);
/* check libxs_stristr */
if (EXIT_SUCCESS == result && NULL != libxs_stristr("ends with b", "Begins with b")) result = EXIT_FAILURE;
if (EXIT_SUCCESS == result && NULL == libxs_stristr("in between of", "BeTwEEn")) result = EXIT_FAILURE;
if (EXIT_SUCCESS == result && NULL == libxs_stristr("spr", "SPR")) result = EXIT_FAILURE;
if (EXIT_SUCCESS == result && NULL != libxs_stristr(NULL, "bb")) result = EXIT_FAILURE;
if (EXIT_SUCCESS == result && NULL != libxs_stristr("aa", NULL)) result = EXIT_FAILURE;
if (EXIT_SUCCESS == result && NULL != libxs_stristr(NULL, NULL)) result = EXIT_FAILURE;
/* backtracking: partial match at start, real match later */
if (EXIT_SUCCESS == result && NULL == libxs_stristr("aab", "ab")) {
FPRINTF(stderr, "ERROR line #%i: stristr backtrack aab/ab\n", __LINE__);
result = EXIT_FAILURE;
}
if (EXIT_SUCCESS == result && NULL == libxs_stristr("aaab", "aab")) {
FPRINTF(stderr, "ERROR line #%i: stristr backtrack aaab/aab\n", __LINE__);
result = EXIT_FAILURE;
}
/* haystack shorter than needle: must NOT match */
if (EXIT_SUCCESS == result && NULL != libxs_stristr("abc", "abcd")) {
FPRINTF(stderr, "ERROR line #%i: stristr short haystack abc/abcd\n", __LINE__);
result = EXIT_FAILURE;
}
if (EXIT_SUCCESS == result && NULL != libxs_stristr("ab", "abc")) {
FPRINTF(stderr, "ERROR line #%i: stristr short haystack ab/abc\n", __LINE__);
result = EXIT_FAILURE;
}
/* repeated chars at tail of pattern (was a buggy special-case path) */
if (EXIT_SUCCESS == result && NULL != libxs_stristr("bo", "boo")) {
FPRINTF(stderr, "ERROR line #%i: stristr partial bo/boo\n", __LINE__);
result = EXIT_FAILURE;
}
/* check libxs_strimatch */
if (EXIT_SUCCESS == result && (2 != libxs_strimatch("Co Product A", "Corp Prod B",
delims, &count) || 3 != count)) result = EXIT_FAILURE;
if (EXIT_SUCCESS == result && (2 != libxs_strimatch("Corp Prod B", "Co Product A",
delims, &count) || 3 != count)) result = EXIT_FAILURE;
if (EXIT_SUCCESS == result && (3 != libxs_strimatch("Co Product A", "Corp Prod AA",
delims, &count) || 3 != count)) result = EXIT_FAILURE;
if (EXIT_SUCCESS == result && (3 != libxs_strimatch("Corp Prod AA", "Co Product A",
delims, &count) || 3 != count)) result = EXIT_FAILURE;
if (EXIT_SUCCESS == result && (3 != libxs_strimatch("Corp Prod AA", "Co Product A",
delims, &count) || 3 != count)) result = EXIT_FAILURE;
if (EXIT_SUCCESS == result && (3 != libxs_strimatch("Co Product A", "Corp Prod AA",
delims, &count) || 3 != count)) result = EXIT_FAILURE;
if (EXIT_SUCCESS == result && (3 != libxs_strimatch("Corp Prod A", "Co Product A",
delims, &count) || 3 != count)) result = EXIT_FAILURE;
if (EXIT_SUCCESS == result && (3 != libxs_strimatch("Co Product A", "Corp Prod A",
delims, &count) || 3 != count)) result = EXIT_FAILURE;
if (EXIT_SUCCESS == result && (3 != libxs_strimatch("C Product A", "Cor Prod AA",
delims, &count) || 3 != count)) result = EXIT_FAILURE;
if (EXIT_SUCCESS == result && (3 != libxs_strimatch("Cor Prod AA", "C Product A",
delims, &count) || 3 != count)) result = EXIT_FAILURE;
if (EXIT_SUCCESS == result && (1 != libxs_strimatch("aaaa", "A A A A",
delims, &count) || 4 != count)) result = EXIT_FAILURE;
if (EXIT_SUCCESS == result && (1 != libxs_strimatch("A A A A", "aaaa",
delims, &count) || 4 != count)) result = EXIT_FAILURE;
if (EXIT_SUCCESS == result) {
const char *const sample[] = {
"The quick red squirrel jumps over the low fence",
"The slow green frog jumps over the lazy dog",
"The lazy brown dog jumps over the quick fox", /* match */
"The hazy fog crawls over the lazy crocodile"
};
int match = 0, i = 0;
#if defined(PRINT)
int j = 0;
#endif
for (; i < ((int)sizeof(sample) / (int)sizeof(*sample)); ++i) {
const int score = libxs_strimatch(init, sample[i], delims, &count);
if (match < score) {
match = score;
#if defined(PRINT)
j = i;
#endif
}
else if (0 > score) result = EXIT_FAILURE;
}
if (EXIT_SUCCESS == result) {
int self = 0;
if (0 < match) {
self = libxs_strimatch(init, init, delims, &count);
FPRINTF(stdout, "orig (%i): %s\n", self, init);
FPRINTF(stdout, "best (%i): %s\n", match, sample[j]);
}
if (9 != self || 9 != match) result = EXIT_FAILURE; /* test */
}
}
/* check libxs_offset */
if (EXIT_SUCCESS == result) {
const size_t shape[] = { 17, 13, 64, 4 }, ndims = sizeof(shape) / sizeof(*shape);
size_t size1 = 0, n;
for (n = 0; n < ndims && EXIT_SUCCESS == result; ++n) {
if (0 != libxs_offset(n, NULL, shape, NULL)) result = EXIT_FAILURE;
}
for (n = 0; n < ndims && EXIT_SUCCESS == result; ++n) {
const size_t offset1 = libxs_offset(n, shape, shape, &size1);
if (offset1 != size1) result = EXIT_FAILURE;
}
}
/* check LIBXS_MEMCPY127 and libxs_diff_n */
if (EXIT_SUCCESS == result) {
char *const data = (char*)malloc(elemsize * ndiffs);
if (NULL != data) { /* check if buffer was allocated */
int i = 0;
libxs_rng_seq(data, elemsize * ndiffs);
for (; i < ntests; ++i) {
const size_t j = libxs_rng_u32((unsigned int)ndiffs);
const size_t s = libxs_rng_u32((unsigned int)elemsize) + 1;
size_t k = s;
libxs_rng_seq(item, s);
for (; k < elemsize; ++k) item[k] = 0;
LIBXS_MEMCPY(data + elemsize * j, item, elemsize);
k = libxs_diff_n(item, data,
(unsigned char)s, (unsigned char)elemsize,
0, ndiffs);
while (k < j) {
k = libxs_diff_n(item, data,
(unsigned char)s, (unsigned char)elemsize,
LIBXS_CAST_UINT(k + 1), ndiffs);
}
if (k == j) continue;
else {
result = EXIT_FAILURE;
break;
}
}
free(data);
}
else result = EXIT_FAILURE;
}
/* check LIBXS_MEMSWP127 */
if (EXIT_SUCCESS == result) {
char a[sizeof(init)] = { 0 };
const size_t size = sizeof(init);
size_t i, j, k;
memcpy(a, init, size);
for (k = 1; k <= 8; ++k) {
const size_t s = (size - 1) / k;
for (j = 0; j < s; ++j) {
for (i = 0; i < (s - 1); ++i) {
LIBXS_MEMSWP(a + k * i, a + k * i + k, k);
}
}
if (0 != strcmp(a, init)) {
FPRINTF(stderr, "LIBXS_MEMSWP127: incorrect result!\n");
result = EXIT_FAILURE;
break;
}
}
}
if (EXIT_SUCCESS == result) { /* check libxs_shuffle */
char a[sizeof(init)] = { 0 }, b[sizeof(init)] = { 0 };
const size_t size = sizeof(init);
size_t i = 1, j;
memcpy(a, init, size);
for (; i < size; ++i) {
LIBXS_EXPECT(EXIT_SUCCESS == libxs_shuffle(a, 1, size - i, NULL, 0, NULL));
LIBXS_EXPECT(EXIT_SUCCESS == libxs_shuffle2(b, init, 1, size - i, NULL, 0, NULL));
if (0 == strncmp(a, b, size - i)) {
const size_t r = libxs_unshuffle(size - i, NULL);
for (j = 1; j < r; ++j) {
libxs_shuffle(a, 1, size - i, NULL, 0, NULL);
}
if (0 != strcmp(a, init)) {
FPRINTF(stderr, "libxs_shuffle: data not restored!\n");
result = EXIT_FAILURE; break;
}
}
else {
FPRINTF(stderr, "libxs_shuffle: result does not match libxs_shuffle2!\n");
result = EXIT_FAILURE; break;
}
}
}
if (EXIT_SUCCESS == result) { /* check libxs_shuffle2 */
char a[sizeof(init)], b[sizeof(init)];
const size_t size = sizeof(init);
size_t s = 0, i;
for (; s < size; ++s) {
const size_t shuffle = libxs_coprime2(s);
const size_t gcd = libxs_gcd(shuffle, s);
if (1 == gcd) {
const size_t r = libxs_unshuffle(s, &shuffle);
int cmp;
memset(a, 0, size); /* clear */
LIBXS_EXPECT(EXIT_SUCCESS == libxs_shuffle2(a, init, 1, s, &shuffle, 0, NULL));
cmp = memcmp(a, init, s);
if ((1 >= s || 0 == cmp) && (1 < s || 0 != cmp)) {
FPRINTF(stderr, "ERROR line #%i: data not shuffled or copy failed!\n", __LINE__);
result = EXIT_FAILURE; break;
}
/* shuffle restores initial input */
for (i = 0; i < r; ++i) {
memset(b, 0, size); /* clear */
LIBXS_EXPECT(EXIT_SUCCESS == libxs_shuffle2(b, a, 1, s, &shuffle, 0, NULL));
/* every shuffle is different from input */
if (1 < s && 0 == memcmp(a, b, s)) {
FPRINTF(stderr, "ERROR line #%i: data not shuffled!\n", __LINE__);
result = EXIT_FAILURE; break;
}
if (0 == memcmp(b, init, s)) break; /* restored */
else if (r == (i + 1)) {
FPRINTF(stderr, "ERROR line #%i: data not restored!\n", __LINE__);
result = EXIT_FAILURE;
}
memcpy(a, b, s);
}
if (EXIT_SUCCESS == result) {
const size_t rm1 = r - 1;
memset(a, 0, size); /* clear */
LIBXS_EXPECT(EXIT_SUCCESS == libxs_shuffle2(a, init, 1, s, &shuffle, 0, NULL));
memset(b, 0, size); /* clear */
LIBXS_EXPECT(EXIT_SUCCESS == libxs_shuffle2(b, a, 1, s, &shuffle, 0, &rm1));
if (0 != memcmp(b, init, s)) {
FPRINTF(stderr, "ERROR line #%i: data not restored via nrepeat!\n", __LINE__);
result = EXIT_FAILURE;
break;
}
}
else break; /* previous error */
}
else {
FPRINTF(stderr, "ERROR line #%i: shuffle argument not coprime!\n", __LINE__);
result = EXIT_FAILURE;
break;
}
}
}
if (EXIT_SUCCESS == result) { /* unshuffle cycle length: R applications restore original */
unsigned int data[256], ref[256];
size_t s;
for (s = 2; s <= 256 && EXIT_SUCCESS == result; ++s) {
const size_t shuffle = libxs_coprime2(s);
const size_t r = libxs_unshuffle(s, &shuffle);
size_t i;
for (i = 0; i < s; ++i) ref[i] = (unsigned int)i;
memcpy(data, ref, s * sizeof(unsigned int));
for (i = 0; i < r; ++i) {
unsigned int tmp[256];
LIBXS_EXPECT(EXIT_SUCCESS == libxs_shuffle2(tmp, data, sizeof(unsigned int), s, &shuffle, 0, NULL));
memcpy(data, tmp, s * sizeof(unsigned int));
}
if (0 != memcmp(data, ref, s * sizeof(unsigned int))) {
FPRINTF(stderr, "ERROR line #%i: unshuffle(s=%i) R=%i does not restore!\n",
__LINE__, (int)s, (int)r);
result = EXIT_FAILURE;
}
}
}
if (EXIT_SUCCESS == result) { /* DS1 and DS2 produce the same permutation */
unsigned int ds1[256], ds2[256], ref[256];
size_t s;
for (s = 2; s <= 256 && EXIT_SUCCESS == result; ++s) {
size_t i, one = 1;
for (i = 0; i < s; ++i) ref[i] = (unsigned int)i;
memcpy(ds1, ref, s * sizeof(unsigned int));
libxs_shuffle(ds1, sizeof(unsigned int), s, NULL, 0, &one);
libxs_shuffle2(ds2, ref, sizeof(unsigned int), s, NULL, 0, &one);
if (0 != memcmp(ds1, ds2, s * sizeof(unsigned int))) {
FPRINTF(stderr, "ERROR line #%i: DS1 != DS2 for s=%i!\n", __LINE__, (int)s);
result = EXIT_FAILURE;
}
}
}
if (EXIT_SUCCESS == result) { /* coprime_bias: bias=0 matches coprime2 */
size_t sizes[] = {7, 100, 10000, 1000000};
int si;
for (si = 0; si < 4; ++si) {
const size_t n = sizes[si];
if (libxs_coprime_bias(n, 0.0) != libxs_coprime2(n)) {
FPRINTF(stderr, "ERROR line #%i: coprime_bias(n=%i,0) != coprime2!\n", __LINE__, (int)n);
result = EXIT_FAILURE; break;
}
}
}
if (EXIT_SUCCESS == result) { /* coprime_bias: monotonicity along bias */
size_t sizes[] = {1000, 100000, 10000000};
int si;
for (si = 0; si < 3 && EXIT_SUCCESS == result; ++si) {
const size_t n = sizes[si];
double b;
size_t prev = 0;
for (b = -1.0; b <= 1.01; b += 0.25) {
const size_t c = libxs_coprime_bias(n, b);
if (c < prev) {
FPRINTF(stderr, "ERROR line #%i: coprime_bias not monotone at n=%i b=%.2f!\n",
__LINE__, (int)n, b);
result = EXIT_FAILURE; break;
}
prev = c;
}
}
}
if (EXIT_SUCCESS == result) { /* shuffle2: nrepeat=R-1 from shuffled state restores original */
unsigned int ref[128], a[128], b[128];
size_t s;
for (s = 2; s <= 128 && EXIT_SUCCESS == result; ++s) {
const size_t shuffle = libxs_coprime2(s);
const size_t r = libxs_unshuffle(s, &shuffle);
const size_t rm1 = r - 1;
size_t i;
for (i = 0; i < s; ++i) ref[i] = (unsigned int)i;
LIBXS_EXPECT(EXIT_SUCCESS == libxs_shuffle2(a, ref, sizeof(unsigned int), s, &shuffle, 0, NULL));
LIBXS_EXPECT(EXIT_SUCCESS == libxs_shuffle2(b, a, sizeof(unsigned int), s, &shuffle, 0, &rm1));
if (0 != memcmp(b, ref, s * sizeof(unsigned int))) {
FPRINTF(stderr, "ERROR line #%i: nrepeat=R-1 restore failed for s=%i!\n", __LINE__, (int)s);
result = EXIT_FAILURE;
}
}
}
/* check libxs_aligned */
if (EXIT_SUCCESS == result) {
LIBXS_ALIGNED(char aligned_buf[64], LIBXS_CACHELINE);
int alignment = 0;
/* An aligned buffer should be reported as aligned */
libxs_aligned(aligned_buf, NULL, &alignment);
if (0 >= alignment) {
FPRINTF(stderr, "ERROR line #%i: aligned buf has alignment=%i\n", __LINE__, alignment);
result = EXIT_FAILURE;
}
/* NULL increment should not affect the result */
if (EXIT_SUCCESS == result && 0 == libxs_aligned(aligned_buf, NULL, NULL)) {
/* may fail if cache line != vlen, not necessarily an error */
}
/* Misaligned pointer: offset by 1 byte */
if (EXIT_SUCCESS == result) {
int misalign = 0;
libxs_aligned(aligned_buf + 1, NULL, &misalign);
/* alignment of (base+1) should be exactly 1 */
if (1 != misalign) {
FPRINTF(stderr, "ERROR line #%i: misaligned ptr alignment=%i expected 1\n", __LINE__, misalign);
result = EXIT_FAILURE;
}
}
}
/* check libxs_diff */
if (EXIT_SUCCESS == result) {
const char buf_a[] = "ABCDEFGHIJKLMNOP";
const char buf_b[] = "ABCDEFGHIJKLMNOP";
const char buf_c[] = "ABCDEFGHIJKLMNOx";
/* identical buffers */
if (0 != libxs_diff(buf_a, buf_b, (unsigned char)sizeof(buf_a))) {
FPRINTF(stderr, "ERROR line #%i: diff reports mismatch for equal buffers\n", __LINE__);
result = EXIT_FAILURE;
}
/* different buffers */
if (EXIT_SUCCESS == result && 0 == libxs_diff(buf_a, buf_c, (unsigned char)sizeof(buf_a))) {
FPRINTF(stderr, "ERROR line #%i: diff reports match for different buffers\n", __LINE__);
result = EXIT_FAILURE;
}
/* zero-size comparison should report no difference */
if (EXIT_SUCCESS == result && 0 != libxs_diff(buf_a, buf_c, 0)) {
FPRINTF(stderr, "ERROR line #%i: diff with size=0 reports mismatch\n", __LINE__);
result = EXIT_FAILURE;
}
/* single-byte comparison */
if (EXIT_SUCCESS == result && 0 != libxs_diff(buf_a, buf_b, 1)) {
FPRINTF(stderr, "ERROR line #%i: diff single byte mismatch\n", __LINE__);
result = EXIT_FAILURE;
}
if (EXIT_SUCCESS == result) { /* diff at various sizes */
char x[64], y[64];
unsigned char s;
for (s = 1; s <= 64 && EXIT_SUCCESS == result; ++s) {
memset(x, 0x55, s); memset(y, 0x55, s);
if (0 != libxs_diff(x, y, s)) {
FPRINTF(stderr, "ERROR line #%i: diff size=%i false positive\n", __LINE__, (int)s);
result = EXIT_FAILURE;
}
y[s - 1] ^= 0xFF; /* flip last byte */
if (0 == libxs_diff(x, y, s)) {
FPRINTF(stderr, "ERROR line #%i: diff size=%i false negative\n", __LINE__, (int)s);
result = EXIT_FAILURE;
}
}
}
}
/* check libxs_memcmp */
if (EXIT_SUCCESS == result) {
const char buf_a[] = "The quick brown fox";
const char buf_b[] = "The quick brown fox";
const char buf_c[] = "The quick brown foX";
if (0 != libxs_memcmp(buf_a, buf_b, sizeof(buf_a))) {
FPRINTF(stderr, "ERROR line #%i: memcmp identical\n", __LINE__);
result = EXIT_FAILURE;
}
if (EXIT_SUCCESS == result && 0 == libxs_memcmp(buf_a, buf_c, sizeof(buf_a))) {
FPRINTF(stderr, "ERROR line #%i: memcmp different\n", __LINE__);
result = EXIT_FAILURE;
}
if (EXIT_SUCCESS == result && 0 != libxs_memcmp(buf_a, buf_c, 0)) {
FPRINTF(stderr, "ERROR line #%i: memcmp size=0\n", __LINE__);
result = EXIT_FAILURE;
}
/* test with larger buffers to exercise SIMD paths (>= 64 bytes) */
if (EXIT_SUCCESS == result) {
char big_a[256], big_b[256];
memset(big_a, 0xAA, sizeof(big_a));
memset(big_b, 0xAA, sizeof(big_b));
if (0 != libxs_memcmp(big_a, big_b, sizeof(big_a))) {
FPRINTF(stderr, "ERROR line #%i: memcmp large identical\n", __LINE__);
result = EXIT_FAILURE;
}
big_b[255] = 0x55;
if (EXIT_SUCCESS == result && 0 == libxs_memcmp(big_a, big_b, sizeof(big_a))) {
FPRINTF(stderr, "ERROR line #%i: memcmp large different\n", __LINE__);
result = EXIT_FAILURE;
}
}
}
/* check libxs_stristrn (length-limited case-insensitive search) */
if (EXIT_SUCCESS == result) {
/* basic match within length limit */
if (NULL == libxs_stristrn("Hello World", "WORLD", 5)) {
FPRINTF(stderr, "ERROR line #%i: stristrn basic match\n", __LINE__);
result = EXIT_FAILURE;
}
/* truncated needle: only first 3 chars of "WORLD" considered */
if (EXIT_SUCCESS == result && NULL == libxs_stristrn("Hello World", "WORxx", 3)) {
FPRINTF(stderr, "ERROR line #%i: stristrn truncated match\n", __LINE__);
result = EXIT_FAILURE;
}
/* no match */
if (EXIT_SUCCESS == result && NULL != libxs_stristrn("Hello", "xyz", 3)) {
FPRINTF(stderr, "ERROR line #%i: stristrn false match\n", __LINE__);
result = EXIT_FAILURE;
}
/* empty / NULL */
if (EXIT_SUCCESS == result && NULL != libxs_stristrn(NULL, "x", 1)) {
FPRINTF(stderr, "ERROR line #%i: stristrn NULL a\n", __LINE__);
result = EXIT_FAILURE;
}
if (EXIT_SUCCESS == result && NULL != libxs_stristrn("x", NULL, 1)) {
FPRINTF(stderr, "ERROR line #%i: stristrn NULL b\n", __LINE__);
result = EXIT_FAILURE;
}
if (EXIT_SUCCESS == result && NULL != libxs_stristrn("abc", "d", 0)) {
FPRINTF(stderr, "ERROR line #%i: stristrn maxlen=0\n", __LINE__);
result = EXIT_FAILURE;
}
}
/* check libxs_stridist */
if (EXIT_SUCCESS == result) {
if (3 != libxs_stridist("kitten", "sitting")) { /* classic Levenshtein example */
FPRINTF(stderr, "ERROR line #%i: stridist kitten/sitting\n", __LINE__);
result = EXIT_FAILURE;
}
if (EXIT_SUCCESS == result && 3 != libxs_stridist("Saturday", "Sunday")) {
FPRINTF(stderr, "ERROR line #%i: stridist Saturday/Sunday\n", __LINE__);
result = EXIT_FAILURE;
}
if (EXIT_SUCCESS == result && 1 != libxs_stridist("color", "colour")) {
FPRINTF(stderr, "ERROR line #%i: stridist color/colour\n", __LINE__);
result = EXIT_FAILURE;
}
if (EXIT_SUCCESS == result && 0 != libxs_stridist("abc", "ABC")) { /* case-insensitive */
FPRINTF(stderr, "ERROR line #%i: stridist case insensitive\n", __LINE__);
result = EXIT_FAILURE;
}
if (EXIT_SUCCESS == result && 0 != libxs_stridist("same", "same")) {
FPRINTF(stderr, "ERROR line #%i: stridist identical\n", __LINE__);
result = EXIT_FAILURE;
}
if (EXIT_SUCCESS == result && 5 != libxs_stridist("", "hello")) {
FPRINTF(stderr, "ERROR line #%i: stridist empty vs hello\n", __LINE__);
result = EXIT_FAILURE;
}
if (EXIT_SUCCESS == result && 0 > libxs_stridist(NULL, "x")) { /* NULL yields -1 */
FPRINTF(stdout, "stridist(NULL, x) = %d (expected -1)\n", libxs_stridist(NULL, "x"));
}
}
/* check libxs_strisimilar */
if (EXIT_SUCCESS == result) {
int order = -1, d;
/* identical strings: zero distance, zero inversions */
d = libxs_strisimilar("the quick fox", "the quick fox", NULL, LIBXS_STRISIMILAR_GREEDY, &order);
if (0 != d || 0 != order) {
FPRINTF(stderr, "ERROR line #%i: strisimilar identical d=%d order=%d\n", __LINE__, d, order);
result = EXIT_FAILURE;
}
/* case-insensitive: same words, different case */
if (EXIT_SUCCESS == result) {
d = libxs_strisimilar("Hello World", "HELLO WORLD", NULL, LIBXS_STRISIMILAR_GREEDY, &order);
if (0 != d || 0 != order) {
FPRINTF(stderr, "ERROR line #%i: strisimilar case d=%d order=%d\n", __LINE__, d, order);
result = EXIT_FAILURE;
}
}
/* reordered words: distance 0, inversions > 0 */
if (EXIT_SUCCESS == result) {
d = libxs_strisimilar("hello world", "world hello", NULL, LIBXS_STRISIMILAR_GREEDY, &order);
if (0 != d || 1 != order) {
FPRINTF(stderr, "ERROR line #%i: strisimilar swap d=%d order=%d\n", __LINE__, d, order);
result = EXIT_FAILURE;
}
}
/* typos: similar but not identical words */
if (EXIT_SUCCESS == result) {
d = libxs_strisimilar("Saturday morning", "Sunday evening", NULL, LIBXS_STRISIMILAR_TWOOPT, &order);
if (6 != d || 0 != order) {
FPRINTF(stderr, "ERROR line #%i: strisimilar typo d=%d order=%d\n", __LINE__, d, order);
result = EXIT_FAILURE;
}
}
/* extra words penalized by their length */
if (EXIT_SUCCESS == result) {
d = libxs_strisimilar("one two three", "one", NULL, LIBXS_STRISIMILAR_GREEDY, &order);
if (8 != d || 0 != order) { /* "two"(3) + "three"(5) = 8 */
FPRINTF(stderr, "ERROR line #%i: strisimilar extra d=%d order=%d\n", __LINE__, d, order);
result = EXIT_FAILURE;
}
}
/* completely different single words */
if (EXIT_SUCCESS == result) {
d = libxs_strisimilar("abc", "xyz", NULL, LIBXS_STRISIMILAR_GREEDY, &order);
if (3 != d || 0 != order) {
FPRINTF(stderr, "ERROR line #%i: strisimilar disjoint d=%d order=%d\n", __LINE__, d, order);
result = EXIT_FAILURE;
}
}
/* pangram vs reordered pangram: same words, many inversions */
if (EXIT_SUCCESS == result) {
d = libxs_strisimilar(
"the quick brown fox jumps over the lazy dog",
"the lazy dog jumps over the quick brown fox",
NULL, LIBXS_STRISIMILAR_TWOOPT, &order);
if (0 != d || 0 >= order) {
FPRINTF(stderr, "ERROR line #%i: strisimilar pangram d=%d order=%d\n", __LINE__, d, order);
result = EXIT_FAILURE;
}
}
/* NULL input */
if (EXIT_SUCCESS == result) {
d = libxs_strisimilar(NULL, "x", NULL, LIBXS_STRISIMILAR_GREEDY, &order);
if (-1 != d || 0 != order) {
FPRINTF(stderr, "ERROR line #%i: strisimilar NULL d=%d order=%d\n", __LINE__, d, order);
result = EXIT_FAILURE;
}
}
/* greedy vs 2-opt should agree or 2-opt should improve */
if (EXIT_SUCCESS == result) {
int order_g, order_t;
const int dg = libxs_strisimilar("color fast", "colour slow", NULL, LIBXS_STRISIMILAR_GREEDY, &order_g);
const int dt = libxs_strisimilar("color fast", "colour slow", NULL, LIBXS_STRISIMILAR_TWOOPT, &order_t);
if (dt > dg) {
FPRINTF(stderr, "ERROR line #%i: 2-opt worse than greedy dg=%d dt=%d\n", __LINE__, dg, dt);
result = EXIT_FAILURE;
}
}
}
/* check libxs_format_value */
if (EXIT_SUCCESS == result) {
char buffer[32];
size_t val;
/* 1 KiB = 1024 B */
val = libxs_format_value(buffer, sizeof(buffer), 1024, "KMGT", "B", 10);
FPRINTF(stdout, "format_value(1024) = \"%s\" val=%lu\n", buffer, (unsigned long)val);
if (1 != val) {
FPRINTF(stderr, "ERROR line #%i: format_value 1KiB val=%lu\n", __LINE__, (unsigned long)val);
result = EXIT_FAILURE;
}
/* 0 bytes */
if (EXIT_SUCCESS == result) {
val = libxs_format_value(buffer, sizeof(buffer), 0, "KMGT", "B", 10);
if (0 != val) {
FPRINTF(stderr, "ERROR line #%i: format_value 0B val=%lu\n", __LINE__, (unsigned long)val);
result = EXIT_FAILURE;
}
}
/* 1 MiB = 1048576 */
if (EXIT_SUCCESS == result) {
val = libxs_format_value(buffer, sizeof(buffer), 1048576, "KMGT", "B", 10);
FPRINTF(stdout, "format_value(1048576) = \"%s\" val=%lu\n", buffer, (unsigned long)val);
if (1 != val) {
FPRINTF(stderr, "ERROR line #%i: format_value 1MiB val=%lu\n", __LINE__, (unsigned long)val);
result = EXIT_FAILURE;
}
}
/* sub-kilo: 512 bytes should stay as bytes */
if (EXIT_SUCCESS == result) {
val = libxs_format_value(buffer, sizeof(buffer), 512, "KMGT", "B", 10);
FPRINTF(stdout, "format_value(512) = \"%s\" val=%lu\n", buffer, (unsigned long)val);
if (512 != val) {
FPRINTF(stderr, "ERROR line #%i: format_value 512B val=%lu\n", __LINE__, (unsigned long)val);
result = EXIT_FAILURE;
}
}
}
/* check LIBXS_MEMSET / LIBXS_MEMZERO */
if (EXIT_SUCCESS == result) {
int vals[4];
LIBXS_MEMZERO(&vals);
if (0 != vals[0] || 0 != vals[1] || 0 != vals[2] || 0 != vals[3]) {
FPRINTF(stderr, "ERROR line #%i: MEMZERO\n", __LINE__);
result = EXIT_FAILURE;
}
LIBXS_MEMSET(&vals, 0, sizeof(vals)); /* set entire structure to 0 */
if (0 != vals[0] || 0 != vals[1] || 0 != vals[2] || 0 != vals[3]) {
FPRINTF(stderr, "ERROR line #%i: MEMSET\n", __LINE__);
result = EXIT_FAILURE;
}
}
/* check LIBXS_ASSIGN / LIBXS_VALUE_ASSIGN */
if (EXIT_SUCCESS == result) {
int src_val = 42, dst_val = 0;
LIBXS_ASSIGN(&dst_val, &src_val);
if (42 != dst_val) {
FPRINTF(stderr, "ERROR line #%i: ASSIGN\n", __LINE__);
result = EXIT_FAILURE;
}
if (EXIT_SUCCESS == result) {
const int cv = 99;
int nv = 0;
LIBXS_VALUE_ASSIGN(nv, cv);
if (99 != nv) {
FPRINTF(stderr, "ERROR line #%i: VALUE_ASSIGN\n", __LINE__);
result = EXIT_FAILURE;
}
}
}
/* check LIBXS_VALUE_SWAP */
if (EXIT_SUCCESS == result) {
int va = 10, vb = 20;
LIBXS_VALUE_SWAP(va, vb);
if (20 != va || 10 != vb) {
FPRINTF(stderr, "ERROR line #%i: VALUE_SWAP\n", __LINE__);
result = EXIT_FAILURE;
}
/* swap with larger types */
if (EXIT_SUCCESS == result) {
double da = 1.5, db = 2.5;
LIBXS_VALUE_SWAP(da, db);
if (LIBXS_NEQ(da, 2.5) || LIBXS_NEQ(db, 1.5)) {
FPRINTF(stderr, "ERROR line #%i: VALUE_SWAP double\n", __LINE__);
result = EXIT_FAILURE;
}
}
}
return result;
}