posix/glibc: implement ffs(), ffsl(), ffsll() and add tests for them

This commit is contained in:
ikbenlike 2021-10-08 02:04:49 +02:00
parent 2feb3c63ed
commit 38bc4f96ea
5 changed files with 91 additions and 5 deletions

View file

@ -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
}

View file

@ -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
View 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;
}

View file

@ -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
View 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;
}