posix/glibc: implement ffs(), ffsl(), ffsll() and add tests for them
This commit is contained in:
parent
2feb3c63ed
commit
38bc4f96ea
|
@ -57,6 +57,8 @@ char *stpcpy(char *__restrict, const char *__restrict);
|
|||
|
||||
// GNU extensions.
|
||||
int strverscmp(const char *l0, const char *r0);
|
||||
int ffsl(long i);
|
||||
int ffsll(long long i);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
|
|
@ -13,9 +13,61 @@ char *rindex(const char *s, int c) {
|
|||
return strrchr(s, c);
|
||||
}
|
||||
|
||||
int ffs(int) {
|
||||
__ensure(!"Not implemented");
|
||||
__builtin_unreachable();
|
||||
namespace {
|
||||
|
||||
template<typename T>
|
||||
int ffs_generic(T i) {
|
||||
//Non-portably assume a byte has 8 bits; fine in all plausible cases.
|
||||
for(int b = 0; b < sizeof(T) * 8;)
|
||||
if(i & (static_cast<T>(0x1) << b++))
|
||||
return b;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#ifdef __has_builtin
|
||||
# if __has_builtin(__builtin_ffs)
|
||||
# define __mlibc_ffs __builtin_ffs
|
||||
# endif
|
||||
# if __has_builtin(__builtin_ffsl)
|
||||
# define __mlibc_ffsl __builtin_ffsl
|
||||
# endif
|
||||
# if __has_builtin(__builtin_ffsll)
|
||||
# define __mlibc_ffsll __builtin_ffsll
|
||||
# endif
|
||||
#endif
|
||||
|
||||
int ffs(int i) {
|
||||
#ifdef __mlibc_ffs
|
||||
return __mlibc_ffs(i);
|
||||
#else
|
||||
return ffs_generic<int>(i);
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
Both ffsl() and ffsll() are glibc extensions
|
||||
defined in string.h. They are however implemented
|
||||
here because of similarity in logic and
|
||||
shared code.
|
||||
*/
|
||||
|
||||
int ffsl(long i) {
|
||||
#ifdef __mlibc_ffsl
|
||||
return __mlibc_ffsl(i);
|
||||
#else
|
||||
return ffs_generic<long>(i);
|
||||
#endif
|
||||
}
|
||||
|
||||
int ffsll(long long i) {
|
||||
#ifdef __mlibc_ffsll
|
||||
return __mlibc_ffsll(i);
|
||||
#else
|
||||
return ffs_generic<long long>(i);
|
||||
#endif
|
||||
}
|
||||
|
||||
int strcasecmp(const char *a, const char *b) {
|
||||
|
|
20
tests/glibc/ffsl-ffsll.c
Normal file
20
tests/glibc/ffsl-ffsll.c
Normal file
|
@ -0,0 +1,20 @@
|
|||
#include <assert.h>
|
||||
#include <string.h>
|
||||
|
||||
int main(void){
|
||||
long test1 = 1L << (sizeof(long) * 8 - 1);
|
||||
long long test2 = 1LL << (sizeof(long long) * 8 - 1);
|
||||
|
||||
assert(ffsl(test1) == sizeof(long) * 8);
|
||||
assert(ffsll(test2) == sizeof(long long) * 8);
|
||||
assert(ffsl(0) == 0);
|
||||
assert(ffsll(0) == 0);
|
||||
assert(ffsl(test1) == ffsll(test1));
|
||||
if(sizeof(long) < sizeof(long long)){
|
||||
assert(ffsl(test1) < ffsll(test2));
|
||||
} else {
|
||||
assert(ffsl(test2) == ffsll(test2));
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -39,7 +39,8 @@ posix_test_cases = [
|
|||
'system', # This test should be in the ANSI tests, but it depends on sys/wait.h
|
||||
'sigsuspend',
|
||||
'sigaltstack',
|
||||
'realpath'
|
||||
'realpath',
|
||||
'ffs'
|
||||
]
|
||||
|
||||
posix_fail_test_cases = [
|
||||
|
@ -47,7 +48,8 @@ posix_fail_test_cases = [
|
|||
]
|
||||
|
||||
glibc_test_cases = [
|
||||
'getopt'
|
||||
'getopt',
|
||||
'ffsl-ffsll'
|
||||
]
|
||||
|
||||
test_sources = [
|
||||
|
|
10
tests/posix/ffs.c
Normal file
10
tests/posix/ffs.c
Normal file
|
@ -0,0 +1,10 @@
|
|||
#include <assert.h>
|
||||
#include <strings.h>
|
||||
|
||||
int main(void){
|
||||
assert(ffs(0x8000) == 16);
|
||||
assert(ffs(0x0) == 0);
|
||||
assert(ffs(0x8000000000000000) == 0);
|
||||
|
||||
return 0;
|
||||
}
|
Loading…
Reference in a new issue