| /************************************************************************ |
| * |
| * valcmp.cpp - definitions of the rw_valcmp() family of helper functions |
| * |
| * $Id$ |
| * |
| ************************************************************************ |
| * |
| * Licensed to the Apache Software Foundation (ASF) under one or more |
| * contributor license agreements. See the NOTICE file distributed |
| * with this work for additional information regarding copyright |
| * ownership. The ASF licenses this file to you 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. |
| * |
| **************************************************************************/ |
| |
| // expand _TEST_EXPORT macros |
| #define _RWSTD_TEST_SRC |
| |
| #include <rw_valcmp.h> |
| |
| #include <stdio.h> // for fprintf, stderr |
| #include <stdlib.h> // for abort |
| #include <string.h> // for memcmp |
| |
| /**************************************************************************/ |
| |
| typedef unsigned char UChar; |
| |
| |
| static const UChar |
| _rw_upper [] = { |
| |
| #if 'A' == 0x41 |
| |
| // basic ASCII: |
| // .0 .1 .2 .3 .4 .5 .6 .7 .8 .9 .a .b .c .d .e .f |
| // --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- |
| // NUL SOH STX ETX EOT ENQ ACK BEL BS TAB LF VT FF CR SO SI |
| /* 0. */ "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f" |
| // DLE DC1 DC2 DC3 DC4 NAK SYN ETB CAN EM SUB ESC FS GS RS US |
| /* 1. */ "\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f" |
| // SPC ! " # $ % ' ' ( ) * + , - . / |
| /* 2. */ "\x20\x21\x22\x23\x24\x25\x26\x27\x28\x29\x2a\x2b\x2c\x2d\x2e\x2f" |
| // 0 1 2 3 4 5 6 7 8 9 : ; < = > ? |
| /* 3. */ "\x30\x31\x32\x33\x34\x35\x36\x37\x38\x39\x3a\x3b\x3c\x3d\x3e\x3f" |
| // A B C D E F G H I J K L M N O |
| /* 4. */ "\x40\x41\x42\x43\x44\x45\x46\x47\x48\x49\x4a\x4b\x4c\x4d\x4e\x4f" |
| // P Q R S T U V W X Y Z [ \ ] ^ _ |
| /* 5. */ "\x50\x51\x52\x53\x54\x55\x56\x57\x58\x59\x5a\x5b\x5c\x5d\x5e\x5f" |
| // ` a b c d e f g h i j k l m n o |
| /* 6. */ "\x60\x41\x42\x43\x44\x45\x46\x47\x48\x49\x4a\x4b\x4c\x4d\x4e\x4f" |
| // p q r s t u v w x y z { | } ~ DEL |
| /* 7. */ "\x50\x51\x52\x53\x54\x55\x56\x57\x58\x59\x5a\x7b\x7c\x7d\x7e\x7f" |
| |
| // extended ASCII: |
| /* 8. */ "\x80\x81\x82\x83\x84\x85\x86\x87\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f" |
| /* 9. */ "\x90\x91\x92\x93\x94\x95\x96\x97\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f" |
| /* a. */ "\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7\xa8\xa9\xaa\xab\xac\xad\xae\xaf" |
| /* b. */ "\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf" |
| /* c. */ "\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf" |
| /* d. */ "\xd0\xd1\xd2\xd3\xd4\xd5\xd6\xd7\xd8\xd9\xda\xdb\xdc\xdd\xde\xdf" |
| /* e. */ "\xe0\xe1\xe2\xe3\xe4\xe5\xe6\xe7\xe8\xe9\xea\xeb\xec\xed\xee\xef" |
| /* f. */ "\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff" |
| |
| #elif 'A' == 0xc1 |
| |
| // EBCDIC: |
| // .0 .1 .2 .3 .4 .5 .6 .7 .8 .9 .a .b .c .d .e .f |
| // --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- |
| // NUL SOH STX ETX PF HT LC DEL SMM VT FF CR SO SI |
| /* 0. */ "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f" |
| // DLE DC1 DC2 TM RES NL BS IL CAN EM CC CU1 IFS IGS IRS IUS |
| /* 1. */ "\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f" |
| // DS SOS FS BYP LF ETB ESC SM CU2 ENQ ACK BEL |
| /* 2. */ "\x20\x21\x22\x23\x24\x25\x26\x27\x28\x29\x2a\x2b\x2c\x2d\x2e\x2f" |
| // SYN PN RS UC EOT CU3 DC4 NAK SUB |
| /* 3. */ "\x30\x31\x32\x33\x34\x35\x36\x37\x38\x39\x3a\x3b\x3c\x3d\x3e\x3f" |
| // SP ct. . < ( + | |
| /* 4. */ "\x40\x41\x42\x43\x44\x45\x46\x47\x48\x49\x4a\x4b\x4c\x4d\x4e\x4f" |
| // & ! $ * ) ; ~ |
| /* 5. */ "\x50\x51\x52\x53\x54\x55\x56\x57\x58\x59\x5a\x5b\x5c\x5d\x5e\x5f" |
| // - / , % _ > ? |
| /* 6. */ "\x60\x41\x42\x43\x44\x45\x46\x47\x48\x49\x4a\x4b\x4c\x4d\x4e\x4f" |
| // : # @ ' = " |
| /* 7. */ "\x70\x71\x72\x73\x74\x75\x76\x77\x78\x79\x7a\x7b\x7c\x7d\x7e\x7f" |
| // a b c d e f g h i |
| /* 8. */ "\x80\xc1\xc2\xc3\xc4\xc5\xc6\xc7\xc8\xc9\x8a\x8b\x8c\x8d\x8e\x8f" |
| // j k l m n o p q r |
| /* 9. */ "\x90\xd1\xd2\xd3\xd4\xd5\xd6\xd7\xd8\xd9\x9a\x9b\x9c\x9d\x9e\x9f" |
| // s t u v w x y z |
| /* a. */ "\xa0\xa1\xe2\xe3\xe4\xe5\xe6\xe7\xe8\xe9\xaa\xab\xac\xad\xae\xaf" |
| // ` |
| /* b. */ "\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf" |
| // A B C D E F G H I |
| /* c. */ "\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf" |
| // J K L M N O P Q R |
| /* d. */ "\xd0\xd1\xd2\xd3\xd4\xd5\xd6\xd7\xd8\xd9\xda\xdb\xdc\xdd\xde\xdf" |
| // S T U V W X Y Z |
| /* e. */ "\xe0\xe1\xe2\xe3\xe4\xe5\xe6\xe7\xe8\xe9\xea\xeb\xec\xed\xee\xef" |
| // 0 1 2 3 4 5 6 7 8 9 |
| /* f. */ "\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff" |
| |
| #else // 'A' != 0x41 && 'A' != 0xc1 |
| # error unknown character set (neither ASCII nor EBCDIC) |
| #endif // ASCII or EBCDIC |
| |
| }; |
| |
| |
| // returns 1 iff all size bytes of the object pointed to by buf are 0 |
| static int |
| _rw_iszero (const void *buf, size_t size) |
| { |
| for (size_t i = 0; i != size; ++i) |
| if (_RWSTD_STATIC_CAST (const UChar*, buf)[i]) |
| return 0; |
| |
| return 1; |
| } |
| |
| |
| // compares two objects of equal size |
| static int |
| _rw_cmpx (const void *buf1, |
| const void *buf2, |
| size_t nelems, |
| size_t size, |
| int flags = 0) |
| { |
| const UChar *p1 = _RWSTD_STATIC_CAST (const UChar*, buf1); |
| const UChar *p2 = _RWSTD_STATIC_CAST (const UChar*, buf2); |
| |
| int ret = 0; |
| |
| for ( ; nelems; p1 += size, p2 += size, --nelems) { |
| |
| ret = memcmp (p1, p2, size); |
| |
| if (flags & CMP_NULTERM) { |
| |
| const int zero1 = _rw_iszero (p1, size); |
| const int zero2 = _rw_iszero (p2, size); |
| |
| if (zero1 || zero2) { |
| ret = zero1 - zero2; |
| break; |
| } |
| } |
| |
| if (ret && (flags & CMP_NOCASE)) { |
| // FIXME: implement |
| fprintf (stderr, |
| "%s:%d: case insensitive comparison not implemented\n", |
| __FILE__, __LINE__); |
| abort (); |
| } |
| } |
| |
| if (flags & CMP_RETOFF) { |
| // FIXME: implement |
| fprintf (stderr, |
| "%s:%d: returning offset not implemented\n", |
| __FILE__, __LINE__); |
| abort (); |
| } |
| |
| return ret < 0 ? -1 : ret ? +1 : 0; |
| } |
| |
| |
| // compares two byte arrays |
| static int |
| _rw_cmp1 (const void *buf1, |
| const void *buf2, |
| size_t nelems, |
| int flags = 0) |
| { |
| #ifdef _RWSTD_UINT8_T |
| |
| typedef _RWSTD_UINT8_T UI8T; |
| |
| if (0 == flags) { |
| const int ret = memcmp (buf1, buf2, nelems); |
| return ret < 0 ? -1 : ret ? +1 : 0; |
| } |
| |
| if (CMP_NULTERM == flags) { |
| const int ret = |
| strncmp (_RWSTD_STATIC_CAST (const char*, buf1), |
| _RWSTD_STATIC_CAST (const char*, buf2), |
| nelems); |
| return ret < 0 ? -1 : ret ? +1 : 0; |
| } |
| |
| size_t inx = 0; |
| int ret = 0; |
| |
| const UI8T *pi1 = _RWSTD_STATIC_CAST (const UI8T*, buf1); |
| const UI8T *pi2 = _RWSTD_STATIC_CAST (const UI8T*, buf2); |
| |
| for (; inx < nelems; ++pi1, ++pi2, ++inx) { |
| |
| const UI8T ui1 = *pi1; |
| const UI8T ui2 = *pi2; |
| |
| if (flags & CMP_NULTERM) { |
| |
| if (0 == ui1) { |
| ret = ui2 ? -1 : 0; |
| break; |
| } |
| |
| if (0 == ui2) { |
| ret = +1; |
| break; |
| } |
| } |
| |
| if (ui1 != ui2) { |
| if (flags & CMP_NOCASE) { |
| if (_rw_upper [ui1] != _rw_upper [ui2]) { |
| ret = _rw_upper [ui1] < _rw_upper [ui2] ? -1 : +1; |
| break; |
| } |
| } |
| else { |
| ret = ui1 < ui2 ? -1 : +1; |
| break; |
| } |
| } |
| } |
| |
| if (CMP_RETOFF & flags) { |
| ret = ret ? int (inx) : -1; |
| } |
| |
| return ret; |
| |
| #else // if !defined (_RWSTD_UINT8_T) |
| # error _RWSTD_UINT8_T not #defined (configuration problem?) |
| #endif // _RWSTD_UINT8_T |
| |
| } |
| |
| |
| // compares two arrays of objects each 16 bits in size |
| static int |
| _rw_cmp2 (const void *buf1, |
| const void *buf2, |
| size_t nelems, |
| int flags = 0) |
| { |
| #ifdef _RWSTD_UINT16_T |
| |
| typedef _RWSTD_UINT16_T UI16T; |
| |
| size_t inx = 0; |
| int ret = 0; |
| |
| const UI16T *pi1 = _RWSTD_STATIC_CAST (const UI16T*, buf1); |
| const UI16T *pi2 = _RWSTD_STATIC_CAST (const UI16T*, buf2); |
| |
| for (; inx < nelems; ++pi1, ++pi2, ++inx) { |
| |
| const UI16T ui1 = *pi1; |
| const UI16T ui2 = *pi2; |
| |
| if (flags & CMP_NULTERM) { |
| |
| if (0 == ui1) { |
| ret = ui2 ? -1 : 0; |
| break; |
| } |
| |
| if (0 == ui2) { |
| ret = +1; |
| break; |
| } |
| } |
| |
| if (ui1 != ui2) { |
| if (flags & CMP_NOCASE) { |
| if (_RWSTD_UCHAR_MAX < ui1 || _RWSTD_UCHAR_MAX < ui2) { |
| ret = ui1 < ui2 ? -1 : +1; |
| break; |
| } |
| else if (_rw_upper [ui1] != _rw_upper [ui2]) { |
| ret = _rw_upper [ui1] < _rw_upper [ui2] ? -1 : +1; |
| break; |
| } |
| } |
| else { |
| ret = ui1 < ui2 ? -1 : +1; |
| break; |
| } |
| } |
| } |
| |
| if (CMP_RETOFF & flags) { |
| ret = ret ? int (inx) : -1; |
| } |
| |
| return ret; |
| |
| #else // if !defined (_RWSTD_UINT16_T) |
| |
| return _rw_cmpx (buf1, buf2, nelems, 2, flags); |
| |
| #endif // _RWSTD_UINT16_T |
| } |
| |
| |
| // compares two arrays of objects each 32 bits in size |
| static int |
| _rw_cmp4 (const void *buf1, |
| const void *buf2, |
| size_t nelems, |
| int flags = 0) |
| { |
| #ifdef _RWSTD_UINT32_T |
| |
| typedef _RWSTD_UINT32_T UI32T; |
| |
| size_t inx = 0; |
| int ret = 0; |
| |
| const UI32T *pi1 = _RWSTD_STATIC_CAST (const UI32T*, buf1); |
| const UI32T *pi2 = _RWSTD_STATIC_CAST (const UI32T*, buf2); |
| |
| for (; inx < nelems; ++pi1, ++pi2, ++inx) { |
| |
| const UI32T ui1 = *pi1; |
| const UI32T ui2 = *pi2; |
| |
| if (flags & CMP_NULTERM) { |
| |
| if (0 == ui1) { |
| ret = ui2 ? -1 : 0; |
| break; |
| } |
| |
| if (0 == ui2) { |
| ret = +1; |
| break; |
| } |
| } |
| |
| if (ui1 != ui2) { |
| if (flags & CMP_NOCASE) { |
| if (_RWSTD_UCHAR_MAX < ui1 || _RWSTD_UCHAR_MAX < ui2) { |
| ret = ui1 < ui2 ? -1 : +1; |
| break; |
| } |
| else if (_rw_upper [ui1] != _rw_upper [ui2]) { |
| ret = _rw_upper [ui1] < _rw_upper [ui2] ? -1 : +1; |
| break; |
| } |
| } |
| else { |
| ret = ui1 < ui2 ? -1 : +1; |
| break; |
| } |
| } |
| } |
| |
| if (CMP_RETOFF & flags) { |
| ret = ret ? int (inx) : -1; |
| } |
| |
| return ret; |
| |
| #else // if !defined (_RWSTD_UINT32_T) |
| |
| return _rw_cmpx (buf1, buf2, nelems, 4, flags); |
| |
| #endif // _RWSTD_UINT32_T |
| } |
| |
| |
| // compares two arrays of objects each 64 bits in size |
| static int |
| _rw_cmp8 (const void *buf1, |
| const void *buf2, |
| size_t nelems, |
| int flags = 0) |
| { |
| #ifdef _RWSTD_UINT64_T |
| |
| typedef _RWSTD_UINT64_T UI64T; |
| |
| size_t inx = 0; |
| int ret = 0; |
| |
| const UI64T *pi1 = _RWSTD_STATIC_CAST (const UI64T*, buf1); |
| const UI64T *pi2 = _RWSTD_STATIC_CAST (const UI64T*, buf2); |
| |
| for (; nelems; ++pi1, ++pi2, ++inx) { |
| |
| const UI64T ui1 = *pi1; |
| const UI64T ui2 = *pi2; |
| |
| if (flags & CMP_NULTERM) { |
| |
| if (0 == ui1) { |
| ret = ui2 ? -1 : 0; |
| break; |
| } |
| |
| if (0 == ui2) { |
| ret = +1; |
| break; |
| } |
| } |
| |
| if (ui1 != ui2) { |
| if (flags & CMP_NOCASE) { |
| if (_RWSTD_UCHAR_MAX < ui1 || _RWSTD_UCHAR_MAX < ui2) { |
| ret = ui1 < ui2 ? -1 : +1; |
| break; |
| } |
| else if (_rw_upper [ui1] != _rw_upper [ui2]) { |
| ret = _rw_upper [ui1] < _rw_upper [ui2] ? -1 : +1; |
| break; |
| } |
| } |
| else { |
| ret = ui1 < ui2 ? -1 : +1; |
| break; |
| } |
| } |
| } |
| |
| if (CMP_RETOFF & flags) { |
| ret = ret ? int (inx) : -1; |
| } |
| |
| return ret; |
| |
| #else // if !defined (_RWSTD_UINT64_T) |
| |
| return _rw_cmpx (buf1, buf2, nelems, 8, flags); |
| |
| #endif // _RWSTD_UINT64_T |
| } |
| |
| |
| // compares two arrays of objects of unequal size |
| static int |
| _rw_cmpxx (const void* buf1, |
| const void* buf2, |
| size_t nelems, |
| size_t size1, |
| size_t size2, |
| int flags) |
| { |
| size_t inx = 0; |
| int ret = 0; |
| |
| for (; inx < nelems; ++inx) { |
| |
| #ifdef _RWSTD_UINT64_T |
| |
| _RWSTD_UINT64_T ui1; |
| _RWSTD_UINT64_T ui2; |
| |
| #else // if !defined (_RWSTD_UINT64_T) |
| |
| size_t ui1; |
| size_t ui2; |
| |
| #endif // _RWSTD_UINT64_T |
| |
| switch (size1) { |
| |
| #ifdef _RWSTD_UINT8_T |
| |
| case 1: { |
| const _RWSTD_UINT8_T* ptr = |
| _RWSTD_STATIC_CAST (const _RWSTD_UINT8_T*, buf1); |
| ui1 = *ptr++; |
| buf1 = ptr; |
| break; |
| } |
| |
| #endif // _RWSTD_UINT8_T |
| |
| #ifdef _RWSTD_UINT16_T |
| |
| case 2: { |
| const _RWSTD_UINT16_T* ptr = |
| _RWSTD_STATIC_CAST (const _RWSTD_UINT16_T*, buf1); |
| ui1 = *ptr++; |
| buf1 = ptr; |
| break; |
| } |
| |
| #endif // _RWSTD_UINT16_T |
| |
| #ifdef _RWSTD_UINT32_T |
| |
| case 4: { |
| const _RWSTD_UINT32_T* ptr = |
| _RWSTD_STATIC_CAST (const _RWSTD_UINT32_T*, buf1); |
| ui1 = *ptr++; |
| buf1 = ptr; |
| break; |
| } |
| |
| #endif // _RWSTD_UINT32_T |
| |
| #ifdef _RWSTD_UINT64_T |
| |
| case 8: { |
| const _RWSTD_UINT64_T* ptr = |
| _RWSTD_STATIC_CAST (const _RWSTD_UINT64_T*, buf1); |
| ui1 = *ptr++; |
| buf1 = ptr; |
| break; |
| } |
| |
| #endif // _RWSTD_UINT64_T |
| |
| default: |
| fprintf (stderr, |
| "%s:%d: comparison of objects %u and %u bytes in size " |
| "not implemented\n", __FILE__, __LINE__, |
| unsigned (size1), unsigned (size2)); |
| abort (); |
| } |
| |
| switch (size2) { |
| |
| #ifdef _RWSTD_UINT8_T |
| |
| case 1: { |
| const _RWSTD_UINT8_T* ptr = |
| _RWSTD_STATIC_CAST (const _RWSTD_UINT8_T*, buf2); |
| ui2 = *ptr++; |
| buf2 = ptr; |
| break; |
| } |
| |
| #endif // _RWSTD_UINT8_T |
| |
| #ifdef _RWSTD_UINT16_T |
| |
| case 2: { |
| const _RWSTD_UINT16_T* ptr = |
| _RWSTD_STATIC_CAST (const _RWSTD_UINT16_T*, buf2); |
| ui2 = *ptr++; |
| buf2 = ptr; |
| break; |
| } |
| |
| #endif // _RWSTD_UINT16_T |
| |
| #ifdef _RWSTD_UINT32_T |
| |
| case 4: { |
| const _RWSTD_UINT32_T* ptr = |
| _RWSTD_STATIC_CAST (const _RWSTD_UINT32_T*, buf2); |
| ui2 = *ptr++; |
| buf2 = ptr; |
| break; |
| } |
| |
| #endif // _RWSTD_UINT32_T |
| |
| #ifdef _RWSTD_UINT64_T |
| |
| case 8: { |
| const _RWSTD_UINT64_T* ptr = |
| _RWSTD_STATIC_CAST (const _RWSTD_UINT64_T*, buf2); |
| ui2 = *ptr++; |
| buf2 = ptr; |
| break; |
| } |
| |
| #endif // _RWSTD_UINT64_T |
| |
| default: |
| fprintf (stderr, |
| "%s:%d: comparison of objects %u and %u bytes in size " |
| "not implemented\n", __FILE__, __LINE__, |
| unsigned (size1), unsigned (size2)); |
| abort (); |
| } |
| |
| if (flags & CMP_NULTERM) { |
| |
| if (0 == ui1) { |
| ret = ui2 ? -1 : 0; |
| break; |
| } |
| |
| if (0 == ui2) { |
| ret = +1; |
| break; |
| } |
| } |
| |
| if (ui1 != ui2) { |
| if (flags & CMP_NOCASE) { |
| if (_RWSTD_UCHAR_MAX < ui1 || _RWSTD_UCHAR_MAX < ui2) { |
| ret = ui1 < ui2 ? -1 : +1; |
| break; |
| } |
| else if (_rw_upper [ui1] != _rw_upper [ui2]) { |
| ret = _rw_upper [ui1] < _rw_upper [ui2] ? -1 : +1; |
| break; |
| } |
| } |
| else { |
| ret = ui1 < ui2 ? -1 : +1; |
| break; |
| } |
| } |
| } |
| |
| if (CMP_RETOFF & flags) { |
| ret = ret ? int (inx) : -1; |
| } |
| |
| return ret; |
| } |
| |
| |
| _TEST_EXPORT int |
| rw_valcmp (const void* buf1, |
| const void* buf2, |
| size_t nelems, |
| size_t size1, |
| size_t size2, |
| int flags /* = 0 */) |
| { |
| if (size1 == size2) { |
| |
| switch (size1) { |
| case 1: return _rw_cmp1 (buf1, buf2, nelems, flags); |
| case 2: return _rw_cmp2 (buf1, buf2, nelems, flags); |
| case 4: return _rw_cmp4 (buf1, buf2, nelems, flags); |
| case 8: return _rw_cmp8 (buf1, buf2, nelems, flags); |
| } |
| |
| return _rw_cmpx (buf1, buf2, nelems, size1, flags); |
| } |
| |
| return _rw_cmpxx (buf1, buf2, nelems, size1, size2, flags); |
| } |
| |
| |
| _TEST_EXPORT int |
| rw_strncmp (const char* str1, |
| const char* str2, |
| size_t nelems /* = _RWSTD_SIZE_MAX */, |
| int flags /* = CMP_NULTERM */) |
| { |
| return rw_valcmp (str1, str2, nelems, 1, 1, flags); |
| } |
| |
| |
| #ifndef _RWSTD_NO_WCHAR_T |
| |
| _TEST_EXPORT int |
| rw_strncmp (const char* str1, |
| const wchar_t* str2, |
| size_t nelems /* = _RWSTD_SIZE_MAX */, |
| int flags /* = CMP_NULTERM */) |
| { |
| return rw_valcmp (str1, str2, nelems, 1, sizeof (wchar_t), flags); |
| } |
| |
| |
| _TEST_EXPORT int |
| rw_strncmp (const wchar_t* str1, |
| const char* str2, |
| size_t nelems /* = _RWSTD_SIZE_MAX */, |
| int flags /* = CMP_NULTERM */) |
| { |
| return rw_valcmp (str1, str2, nelems, sizeof (wchar_t), 1, flags); |
| } |
| |
| |
| _TEST_EXPORT int |
| rw_strncmp (const wchar_t* str1, |
| const wchar_t* str2, |
| size_t nelems /* = _RWSTD_SIZE_MAX */, |
| int flags /* = CMP_NULTERM */) |
| { |
| return rw_valcmp (str1, str2, nelems, |
| sizeof (wchar_t), sizeof (wchar_t), flags); |
| } |
| |
| #endif // _RWSTD_NO_WCHAR_T |
| |
| |
| // floating point comparison helpers based on |
| // http://www.cygnus-software.com/papers/comparingfloats/comparingfloats.htm |
| |
| _TEST_EXPORT int |
| rw_fltcmp (float x, float y) |
| { |
| #if _RWSTD_FLT_SIZE == _RWSTD_SHRT_SIZE |
| typedef short IntT; |
| const IntT imin = _RWSTD_SHRT_MIN; |
| #elif _RWSTD_FLT_SIZE == _RWSTD_INT_SIZE |
| typedef int IntT; |
| const IntT imin = _RWSTD_INT_MIN; |
| #elif _RWSTD_FLT_SIZE == _RWSTD_LONG_SIZE |
| typedef long IntT; |
| const IntT imin = _RWSTD_LONG_MIN; |
| #elif _RWSTD_FLT_SIZE == _RWSTD_LLONG_SIZE |
| typedef _RWSTD_LONG_LONG IntT; |
| const IntT imin = _RWSTD_LLONG_MIN; |
| #else |
| // ??? |
| # error no integral type of the same size as float exists |
| #endif |
| |
| if (x == y) |
| return 0; |
| |
| // make both arguments lexicographically ordered as twos-complement ints |
| IntT x_int = *(IntT*)&x; |
| if (x_int < 0) |
| x_int = imin - x_int; |
| |
| IntT y_int = *(IntT*)&y; |
| if (y_int < 0) |
| y_int = imin - y_int; |
| |
| const IntT int_diff = x_int - y_int; |
| |
| return int_diff; |
| } |
| |
| |
| #define Abs(x) ((x) < 0 ? -(x) : (x)) |
| |
| |
| _TEST_EXPORT int |
| rw_dblcmp (double x, double y) |
| { |
| #if _RWSTD_DBL_SIZE == _RWSTD_INT_SIZE |
| typedef int IntT; |
| const IntT imin = _RWSTD_INT_MIN; |
| #elif _RWSTD_DBL_SIZE == _RWSTD_LONG_SIZE |
| typedef long IntT; |
| const IntT imin = _RWSTD_LONG_MIN; |
| #elif _RWSTD_DBL_SIZE == _RWSTD_LLONG_SIZE |
| typedef _RWSTD_LONG_LONG IntT; |
| const IntT imin = _RWSTD_LLONG_MIN; |
| #endif |
| |
| #if _RWSTD_LLONG_SIZE < _RWSTD_DBL_SIZE |
| |
| if (x == y) |
| return 0; |
| |
| // FIXME: use integer math as in the functions above |
| |
| const double diff = x - y; |
| |
| // check absolute error |
| if (Abs (diff) < _RWSTD_DBL_EPSILON) |
| return 0; |
| |
| // check relative error |
| const double relerr = |
| Abs (x) < Abs (y) ? Abs (diff / y) : Abs (diff / x); |
| |
| if (relerr <= 0.0000001) |
| return 0; |
| |
| return x < y ? -1 : +1; |
| |
| #else // if !(_RWSTD_LLONG_SIZE < _RWSTD_DBL_SIZE) |
| |
| if (x == y) |
| return 0; |
| |
| IntT x_int = *(IntT*)&x; |
| if (x_int < 0) |
| x_int = imin - x_int; |
| |
| IntT y_int = *(IntT*)&y; |
| if (y_int < 0) |
| y_int = imin - y_int; |
| |
| const IntT int_diff = x_int - y_int; |
| |
| // cast a possibly wider type to int to avoid compiler warnings |
| // this should be safe since the function should not be used to |
| // compare numbers that are that far apart |
| return int (int_diff); |
| |
| #endif // _RWSTD_LLONG_SIZE < _RWSTD_DBL_SIZE |
| |
| } |
| |
| |
| #ifndef _RWSTD_NO_LONG_DOUBLE |
| |
| _TEST_EXPORT int |
| rw_ldblcmp (long double x, long double y) |
| { |
| if (sizeof (long double) == sizeof (double)) |
| return rw_dblcmp (double (x), double (y)); |
| |
| if (x == y) |
| return 0; |
| |
| // FIXME: use integer math as in the functions above |
| |
| const long double diff = x - y; |
| |
| // check absolute error |
| if (Abs (diff) < _RWSTD_LDBL_EPSILON) |
| return 0; |
| |
| // check relative error |
| const long double relerr = |
| Abs (x) < Abs (y) ? Abs (diff / y) : Abs (diff / x); |
| |
| if (relerr <= 0.0000001L) |
| return 0; |
| |
| return x < y ? -1 : +1; |
| } |
| |
| #endif // _RWSTD_NO_LONG_DOUBLE |