Merge tag 'upstream/11.3'

Upstream version 11.3
This commit is contained in:
Mario Fetka 2019-01-07 14:41:49 +01:00
commit 36b5ac9c36
31 changed files with 408 additions and 217 deletions

View File

@ -1 +1 @@
11.2 11.3

10
HISTORY
View File

@ -1,6 +1,16 @@
SnapRAID HISTORY SnapRAID HISTORY
================ ================
11.3 2018/11
============
* Fixed handing of Linux devices that have multiple slaves. This affects
the smart/list/devices/down commands [Valentin Hilbig].
* The 'list' command in verbose mode prints the full nanosecond
timestamp precision.
* After writing content files also sync their directory.
* Fix a invalid time computation that could result in future scrub dates.
Such dates are fixed automatically at the next scrub or sync.
11.2 2017/12 11.2 2017/12
============ ============
* Fixed recognition of NTFS hardlinks. They behave differently than * Fixed recognition of NTFS hardlinks. They behave differently than

16
TODO
View File

@ -17,6 +17,18 @@ Not checked disks should be allowed to be missing.
* Add an option to ignore subsecond timestamp. * Add an option to ignore subsecond timestamp.
Like when you copy data to a filesystem with less timestamp precision. Like when you copy data to a filesystem with less timestamp precision.
* Use threads to scan all the disks at the same time.
- After 7.0 Windows changes it seems fast enough even
with a mono thread implementation with 100.0000 files.
+ But if you have millions of files, it could take minutes.
* Support more parity levels
It can be done with a generic computation function, using
intrinsic for SSSE3 and AVX instructions.
It would be intersting to compare performance with the hand-written
assembler functions. Eventially we can convert them to use intrinsic also.
https://sourceforge.net/p/snapraid/discussion/1677233/thread/9dbd7581/
* Extend haspdeep to support the SnapRAID hash : * Extend haspdeep to support the SnapRAID hash :
https://github.com/jessek/hashdeep/ https://github.com/jessek/hashdeep/
https://sourceforge.net/p/snapraid/discussion/1677233/thread/90b0e9b2/?limit=25 https://sourceforge.net/p/snapraid/discussion/1677233/thread/90b0e9b2/?limit=25
@ -222,10 +234,6 @@ and if we manage to keep it in the cache, we should save time.
- We now hash first the faster disks, and this could - We now hash first the faster disks, and this could
reduce performance as we'll have to wait for all disks. reduce performance as we'll have to wait for all disks.
* Use threads to scan all the disks at the same time.
- After 7.0 Windows changes it seems fast enough even
with a mono thread implementation.
* Enable storing of creation time NTFS, crtime/birth time EXT4. * Enable storing of creation time NTFS, crtime/birth time EXT4.
But see: http://unix.stackexchange.com/questions/50177/birth-is-empty-on-ext4 But see: http://unix.stackexchange.com/questions/50177/birth-is-empty-on-ext4
coreutils stat has an example, but it doesn't work in Linux (see lib/stat-time.h) coreutils stat has an example, but it doesn't work in Linux (see lib/stat-time.h)

View File

@ -889,7 +889,7 @@ void io_init(struct snapraid_io* io, struct snapraid_state* state,
allocated += state->block_size * buffer_max; allocated += state->block_size * buffer_max;
} }
msg_progress("Using %u MiB of memory for %u blocks of IO cache.\n", (unsigned)(allocated / MEBI), io->io_max); msg_progress("Using %u MiB of memory for %u cached blocks.\n", (unsigned)(allocated / MEBI), io->io_max);
if (parity_writer) { if (parity_writer) {
io->reader_max = handle_max; io->reader_max = handle_max;

View File

@ -74,7 +74,7 @@ void state_list(struct snapraid_state* state)
if (tm) { if (tm) {
printf("%04u/%02u/%02u %02u:%02u", tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday, tm->tm_hour, tm->tm_min); printf("%04u/%02u/%02u %02u:%02u", tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday, tm->tm_hour, tm->tm_min);
if (msg_level >= MSG_VERBOSE) if (msg_level >= MSG_VERBOSE)
printf(":%02u.%03u", tm->tm_sec, file->mtime_nsec / 1000000); printf(":%02u.%09u", tm->tm_sec, file->mtime_nsec);
printf(" "); printf(" ");
} }
printf("%s\n", fmt_term(disk, file->sub, esc_buffer)); printf("%s\n", fmt_term(disk, file->sub, esc_buffer));
@ -105,7 +105,7 @@ void state_list(struct snapraid_state* state)
printf("%12s ", type); printf("%12s ", type);
printf(" "); printf(" ");
if (msg_level >= MSG_VERBOSE) if (msg_level >= MSG_VERBOSE)
printf(" "); printf(" ");
printf("%s -> %s\n", fmt_term(disk, slink->sub, esc_buffer), fmt_term(disk, slink->linkto, esc_buffer_alt)); printf("%s -> %s\n", fmt_term(disk, slink->sub, esc_buffer), fmt_term(disk, slink->linkto, esc_buffer_alt));
} }
} }

View File

@ -694,6 +694,7 @@ static void windows_errno(DWORD error)
errno = EPERM; errno = EPERM;
break; break;
case ERROR_IO_DEVICE : /* in ReadFile() and WriteFile() */ case ERROR_IO_DEVICE : /* in ReadFile() and WriteFile() */
case ERROR_CRC : /* in ReadFile() */
errno = EIO; errno = EIO;
break; break;
default : default :

View File

@ -41,6 +41,7 @@ void test(void)
s = sopen_multi_write(STREAM_MAX); s = sopen_multi_write(STREAM_MAX);
for (i = 0; i < STREAM_MAX; ++i) { for (i = 0; i < STREAM_MAX; ++i) {
snprintf(file, sizeof(file), "stream%u.bin", i); snprintf(file, sizeof(file), "stream%u.bin", i);
remove(file);
if (sopen_multi_file(s, i, file) != 0) { if (sopen_multi_file(s, i, file) != 0) {
/* LCOV_EXCL_START */ /* LCOV_EXCL_START */
exit(EXIT_FAILURE); exit(EXIT_FAILURE);

View File

@ -136,25 +136,29 @@ void MurmurHash3_x86_128(const void* data, size_t size, const uint8_t* seed, voi
uint32_t k4 = 0; uint32_t k4 = 0;
switch (size_remainder) { switch (size_remainder) {
case 15 : k4 ^= (uint32_t)tail[14] << 16; case 15 : k4 ^= (uint32_t)tail[14] << 16; /* fallthrough */
case 14 : k4 ^= (uint32_t)tail[13] << 8; case 14 : k4 ^= (uint32_t)tail[13] << 8; /* fallthrough */
case 13 : k4 ^= (uint32_t)tail[12] << 0; case 13 : k4 ^= (uint32_t)tail[12] << 0; /* fallthrough */
k4 *= c4; k4 = util_rotl32(k4, 18); k4 *= c1; h4 ^= k4; k4 *= c4; k4 = util_rotl32(k4, 18); k4 *= c1; h4 ^= k4;
case 12 : k3 ^= (uint32_t)tail[11] << 24; /* fallthrough */
case 11 : k3 ^= (uint32_t)tail[10] << 16; case 12 : k3 ^= (uint32_t)tail[11] << 24; /* fallthrough */
case 10 : k3 ^= (uint32_t)tail[ 9] << 8; case 11 : k3 ^= (uint32_t)tail[10] << 16; /* fallthrough */
case 9 : k3 ^= (uint32_t)tail[ 8] << 0; case 10 : k3 ^= (uint32_t)tail[ 9] << 8; /* fallthrough */
case 9 : k3 ^= (uint32_t)tail[ 8] << 0; /* fallthrough */
k3 *= c3; k3 = util_rotl32(k3, 17); k3 *= c4; h3 ^= k3; k3 *= c3; k3 = util_rotl32(k3, 17); k3 *= c4; h3 ^= k3;
case 8 : k2 ^= (uint32_t)tail[ 7] << 24; /* fallthrough */
case 7 : k2 ^= (uint32_t)tail[ 6] << 16; case 8 : k2 ^= (uint32_t)tail[ 7] << 24; /* fallthrough */
case 6 : k2 ^= (uint32_t)tail[ 5] << 8; case 7 : k2 ^= (uint32_t)tail[ 6] << 16; /* fallthrough */
case 5 : k2 ^= (uint32_t)tail[ 4] << 0; case 6 : k2 ^= (uint32_t)tail[ 5] << 8; /* fallthrough */
case 5 : k2 ^= (uint32_t)tail[ 4] << 0; /* fallthrough */
k2 *= c2; k2 = util_rotl32(k2, 16); k2 *= c3; h2 ^= k2; k2 *= c2; k2 = util_rotl32(k2, 16); k2 *= c3; h2 ^= k2;
case 4 : k1 ^= (uint32_t)tail[ 3] << 24; /* fallthrough */
case 3 : k1 ^= (uint32_t)tail[ 2] << 16; case 4 : k1 ^= (uint32_t)tail[ 3] << 24; /* fallthrough */
case 2 : k1 ^= (uint32_t)tail[ 1] << 8; case 3 : k1 ^= (uint32_t)tail[ 2] << 16; /* fallthrough */
case 1 : k1 ^= (uint32_t)tail[ 0] << 0; case 2 : k1 ^= (uint32_t)tail[ 1] << 8; /* fallthrough */
case 1 : k1 ^= (uint32_t)tail[ 0] << 0; /* fallthrough */
k1 *= c1; k1 = util_rotl32(k1, 15); k1 *= c2; h1 ^= k1; k1 *= c1; k1 = util_rotl32(k1, 15); k1 *= c2; h1 ^= k1;
/* fallthrough */
} }
} }

View File

@ -87,7 +87,7 @@ void memory(void)
log_tag("memory:link:%" PRIu64 "\n", (uint64_t)(sizeof(struct snapraid_link))); log_tag("memory:link:%" PRIu64 "\n", (uint64_t)(sizeof(struct snapraid_link)));
log_tag("memory:dir:%" PRIu64 "\n", (uint64_t)(sizeof(struct snapraid_dir))); log_tag("memory:dir:%" PRIu64 "\n", (uint64_t)(sizeof(struct snapraid_dir)));
msg_progress("Using %u MiB of memory for the FileSystem.\n", (unsigned)(malloc_counter_get() / MEBI)); msg_progress("Using %u MiB of memory for the file-system.\n", (unsigned)(malloc_counter_get() / MEBI));
} }
void test(int argc, char* argv[]) void test(int argc, char* argv[])
@ -1091,7 +1091,7 @@ int main(int argc, char* argv[])
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
/* LCOV_EXCL_STOP */ /* LCOV_EXCL_STOP */
} }
/* follow */ /* fallthrough */
case OPERATION_SPINUP : case OPERATION_SPINUP :
case OPERATION_SPINDOWN : case OPERATION_SPINDOWN :
if (!tommy_list_empty(&filterlist_file)) { if (!tommy_list_empty(&filterlist_file)) {

View File

@ -2872,6 +2872,7 @@ struct state_write_thread_context {
/* input */ /* input */
block_off_t blockmax; block_off_t blockmax;
time_t info_oldest; time_t info_oldest;
time_t info_now;
int info_has_rehash; int info_has_rehash;
STREAM* f; STREAM* f;
/* output */ /* output */
@ -2888,6 +2889,7 @@ static void* state_write_thread(void* arg)
struct snapraid_state* state = context->state; struct snapraid_state* state = context->state;
block_off_t blockmax = context->blockmax; block_off_t blockmax = context->blockmax;
time_t info_oldest = context->info_oldest; time_t info_oldest = context->info_oldest;
time_t info_now = context->info_now;
int info_has_rehash = context->info_has_rehash; int info_has_rehash = context->info_has_rehash;
STREAM* f = context->f; STREAM* f = context->f;
uint32_t crc; uint32_t crc;
@ -3278,7 +3280,18 @@ static void* state_write_thread(void* arg)
flag |= 8; flag |= 8;
sputb32(flag, f); sputb32(flag, f);
t = info_get_time(info) - info_oldest; t = info_get_time(info);
/* truncate any time that is in the future */
if (t > info_now)
t = info_now;
/* the oldest info is computed only on required blocks, so it may not be the absolute oldest */
if (t < info_oldest)
t = 0;
else
t -= info_oldest;
sputb32(t, f); sputb32(t, f);
} else { } else {
/* write a special 0 flag to mark missing info */ /* write a special 0 flag to mark missing info */
@ -3353,6 +3366,7 @@ static void state_write_content(struct snapraid_state* state, uint32_t* out_crc)
tommy_node* i; tommy_node* i;
block_off_t blockmax; block_off_t blockmax;
time_t info_oldest; time_t info_oldest;
time_t info_now;
int info_has_rehash; int info_has_rehash;
int mapping_idx; int mapping_idx;
block_off_t idx; block_off_t idx;
@ -3371,6 +3385,7 @@ static void state_write_content(struct snapraid_state* state, uint32_t* out_crc)
/* clear the info for unused blocks */ /* clear the info for unused blocks */
/* and get some other info */ /* and get some other info */
info_oldest = 0; /* oldest time in info */ info_oldest = 0; /* oldest time in info */
info_now = time(0); /* get the present time */
info_has_rehash = 0; /* if there is a rehash info */ info_has_rehash = 0; /* if there is a rehash info */
for (idx = 0; idx < blockmax; ++idx) { for (idx = 0; idx < blockmax; ++idx) {
/* if the position is used */ /* if the position is used */
@ -3434,10 +3449,21 @@ static void state_write_content(struct snapraid_state* state, uint32_t* out_crc)
msg_progress("Saving state to %s...\n", content->content); msg_progress("Saving state to %s...\n", content->content);
pathprint(tmp, sizeof(tmp), "%s.tmp", content->content); pathprint(tmp, sizeof(tmp), "%s.tmp", content->content);
/* ensure to delete a previous stale file */
if (remove(tmp) != 0) {
if (errno != ENOENT) {
/* LCOV_EXCL_START */
log_fatal("Error removing the stale content file '%s'. %s.\n", tmp, strerror(errno));
exit(EXIT_FAILURE);
/* LCOV_EXCL_STOP */
}
}
f = sopen_write(tmp); f = sopen_write(tmp);
if (f == 0) { if (f == 0) {
/* LCOV_EXCL_START */ /* LCOV_EXCL_START */
log_fatal("Error opening the content file '%s'. %s.\n", tmp, strerror(errno)); log_fatal("Error opening the temporary content file '%s'. %s.\n", tmp, strerror(errno));
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
/* LCOV_EXCL_STOP */ /* LCOV_EXCL_STOP */
} }
@ -3450,6 +3476,7 @@ static void state_write_content(struct snapraid_state* state, uint32_t* out_crc)
context->state = state; context->state = state;
context->blockmax = blockmax; context->blockmax = blockmax;
context->info_oldest = info_oldest; context->info_oldest = info_oldest;
context->info_now = info_now;
context->info_has_rehash = info_has_rehash; context->info_has_rehash = info_has_rehash;
context->f = f; context->f = f;
@ -3562,12 +3589,24 @@ static void state_write_content(struct snapraid_state* state, uint32_t* out_crc)
struct snapraid_content* content = i->data; struct snapraid_content* content = i->data;
char tmp[PATH_MAX]; char tmp[PATH_MAX];
pathprint(tmp, sizeof(tmp), "%s.tmp", content->content); pathprint(tmp, sizeof(tmp), "%s.tmp", content->content);
/* ensure to delete a previous stale file */
if (remove(tmp) != 0) {
if (errno != ENOENT) {
/* LCOV_EXCL_START */
log_fatal("Error removing the stale content file '%s'. %s.\n", tmp, strerror(errno));
exit(EXIT_FAILURE);
/* LCOV_EXCL_STOP */
}
}
if (sopen_multi_file(f, k, tmp) != 0) { if (sopen_multi_file(f, k, tmp) != 0) {
/* LCOV_EXCL_START */ /* LCOV_EXCL_START */
log_fatal("Error opening the content file '%s'. %s.\n", tmp, strerror(errno)); log_fatal("Error opening the temporary content file '%s'. %s.\n", tmp, strerror(errno));
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
/* LCOV_EXCL_STOP */ /* LCOV_EXCL_STOP */
} }
++k; ++k;
i = i->next; i = i->next;
} }
@ -3579,6 +3618,7 @@ static void state_write_content(struct snapraid_state* state, uint32_t* out_crc)
context->state = state; context->state = state;
context->blockmax = blockmax; context->blockmax = blockmax;
context->info_oldest = info_oldest; context->info_oldest = info_oldest;
context->info_now = info_now;
context->info_has_rehash = info_has_rehash; context->info_has_rehash = info_has_rehash;
context->f = f; context->f = f;
@ -3851,11 +3891,10 @@ static void state_verify_content(struct snapraid_state* state, uint32_t crc)
msg_progress("Verifying %s...\n", content->content); msg_progress("Verifying %s...\n", content->content);
pathprint(tmp, sizeof(tmp), "%s.tmp", content->content); pathprint(tmp, sizeof(tmp), "%s.tmp", content->content);
f = sopen_read(tmp); f = sopen_read(tmp);
if (f == 0) { if (f == 0) {
/* LCOV_EXCL_START */ /* LCOV_EXCL_START */
log_fatal("Error reopening the content file '%s'. %s.\n", tmp, strerror(errno)); log_fatal("Error reopening the temporary content file '%s'. %s.\n", tmp, strerror(errno));
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
/* LCOV_EXCL_STOP */ /* LCOV_EXCL_STOP */
} }
@ -3924,6 +3963,59 @@ static void state_rename_content(struct snapraid_state* state)
{ {
tommy_node* i; tommy_node* i;
#if defined(_linux) /* this sequence is linux specific */
i = tommy_list_head(&state->contentlist);
while (i) {
struct snapraid_content* content = i->data;
char tmp[PATH_MAX];
char dir[PATH_MAX];
char* slash;
int handle;
pathcpy(dir, sizeof(dir), content->content);
slash = strrchr(tmp, '/');
if (slash)
*slash = 0;
else
pathcpy(dir, sizeof(dir), ".");
/* open the directory to get the handle */
handle = open(dir, O_RDONLY | O_DIRECTORY);
if (handle < 0) {
/* LCOV_EXCL_START */
log_fatal("Error opening the directory '%s'. %s.\n", dir, strerror(errno));
exit(EXIT_FAILURE);
/* LCOV_EXCL_STOP */
}
/* now rename the just written copy with the correct name */
pathprint(tmp, sizeof(tmp), "%s.tmp", content->content);
if (rename(tmp, content->content) != 0) {
/* LCOV_EXCL_START */
log_fatal("Error renaming the content file '%s' to '%s'. %s.\n", tmp, content->content, strerror(errno));
exit(EXIT_FAILURE);
/* LCOV_EXCL_STOP */
}
/* sync the directory */
if (fsync(handle) != 0) {
/* LCOV_EXCL_START */
log_fatal("Error syncing the directory '%s'. %s.\n", dir, strerror(errno));
exit(EXIT_FAILURE);
/* LCOV_EXCL_STOP */
}
if (close(handle) != 0) {
/* LCOV_EXCL_START */
log_fatal("Error closing the directory '%s'. %s.\n", dir, strerror(errno));
exit(EXIT_FAILURE);
/* LCOV_EXCL_STOP */
}
i = i->next;
}
#else
i = tommy_list_head(&state->contentlist); i = tommy_list_head(&state->contentlist);
while (i) { while (i) {
struct snapraid_content* content = i->data; struct snapraid_content* content = i->data;
@ -3940,6 +4032,7 @@ static void state_rename_content(struct snapraid_state* state)
i = i->next; i = i->next;
} }
#endif
} }
void state_write(struct snapraid_state* state) void state_write(struct snapraid_state* state)

View File

@ -29,6 +29,10 @@
unsigned day_ago(time_t ref, time_t now) unsigned day_ago(time_t ref, time_t now)
{ {
/* in case some dates is in the future */
if (now < ref)
return 0;
return (now - ref) / (24 * 3600); return (now - ref) / (24 * 3600);
} }
@ -458,6 +462,10 @@ int state_status(struct snapraid_state* state)
printf("\n"); printf("\n");
if (newest > now) {
printf("WARNING! You have scrub dates in the future! The next sync/scrub will truncate them!\n");
}
if (unsynced_blocks) { if (unsynced_blocks) {
printf("WARNING! The array is NOT fully synced.\n"); printf("WARNING! The array is NOT fully synced.\n");
printf("You have a sync in progress at %u%%.\n", (blockmax - unsynced_blocks) * 100 / blockmax); printf("You have a sync in progress at %u%%.\n", (blockmax - unsynced_blocks) * 100 / blockmax);

View File

@ -112,7 +112,8 @@ int sopen_multi_file(STREAM* s, unsigned i, const char* file)
pathcpy(s->handle[i].path, sizeof(s->handle[i].path), file); pathcpy(s->handle[i].path, sizeof(s->handle[i].path), file);
f = open(file, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY | O_SEQUENTIAL, 0600); /* O_EXCL to be resilent ensure to always create a new file and not use a stale link to the original file */
f = open(file, O_WRONLY | O_CREAT | O_EXCL | O_BINARY | O_SEQUENTIAL, 0600);
if (f == -1) { if (f == -1) {
/* LCOV_EXCL_START */ /* LCOV_EXCL_START */
return -1; return -1;

View File

@ -299,6 +299,8 @@ void pathslash(char* dst, size_t size);
/** /**
* Cut everything after the latest slash. * Cut everything after the latest slash.
*
* If the string doesn't contain any slash, it returns the empty string.
*/ */
void pathcut(char* dst); void pathcut(char* dst);

View File

@ -1536,7 +1536,7 @@ int state_sync(struct snapraid_state* state, block_off_t blockstart, block_off_t
data_off_t out_size; data_off_t out_size;
parity_size(&parity_handle[l], &out_size); parity_size(&parity_handle[l], &out_size);
parity_overflow(state, out_size); parity_overflow(state, out_size);
log_fatal("WARNING! Without an unsable %s file, it isn't possible to sync.\n", lev_name(l)); log_fatal("WARNING! Without an usable %s file, it isn't possible to sync.\n", lev_name(l));
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
/* LCOV_EXCL_STOP */ /* LCOV_EXCL_STOP */
} }

View File

@ -917,18 +917,20 @@ static int devtree(const char* name, const char* custom, dev_t device, devinfo_t
while ((dd = readdir(d)) != 0) { while ((dd = readdir(d)) != 0) {
if (dd->d_name[0] != '.') { if (dd->d_name[0] != '.') {
dev_t subdev;
/* for each slave, expand the full potential tree */ /* for each slave, expand the full potential tree */
pathprint(path, sizeof(path), "/sys/dev/block/%u:%u/slaves/%s/dev", major(device), minor(device), dd->d_name); pathprint(path, sizeof(path), "/sys/dev/block/%u:%u/slaves/%s/dev", major(device), minor(device), dd->d_name);
device = devread(path); subdev = devread(path);
if (!device) { if (!subdev) {
/* LCOV_EXCL_START */ /* LCOV_EXCL_START */
closedir(d); closedir(d);
return -1; return -1;
/* LCOV_EXCL_STOP */ /* LCOV_EXCL_STOP */
} }
if (devtree(name, custom, device, parent, list) != 0) { if (devtree(name, custom, subdev, parent, list) != 0) {
/* LCOV_EXCL_START */ /* LCOV_EXCL_START */
closedir(d); closedir(d);
return -1; return -1;
@ -1072,8 +1074,8 @@ static int devscan(tommy_list* list)
#if HAVE_LINUX_DEVICE #if HAVE_LINUX_DEVICE
static int devsmart(dev_t device, const char* name, const char* custom, uint64_t* smart, char* serial, char* vendor, char* model) static int devsmart(dev_t device, const char* name, const char* custom, uint64_t* smart, char* serial, char* vendor, char* model)
{ {
char cmd[128]; char cmd[PATH_MAX + 64];
char file[128]; char file[PATH_MAX];
FILE* f; FILE* f;
int ret; int ret;
@ -1086,7 +1088,7 @@ static int devsmart(dev_t device, const char* name, const char* custom, uint64_t
/* if there is a custom command */ /* if there is a custom command */
if (custom[0]) { if (custom[0]) {
char option[128]; char option[PATH_MAX];
snprintf(option, sizeof(option), custom, file); snprintf(option, sizeof(option), custom, file);
snprintf(cmd, sizeof(cmd), "smartctl -a %s", option); snprintf(cmd, sizeof(cmd), "smartctl -a %s", option);
} else { } else {
@ -1140,8 +1142,8 @@ static int devsmart(dev_t device, const char* name, const char* custom, uint64_t
#if HAVE_LINUX_DEVICE #if HAVE_LINUX_DEVICE
static int devdown(dev_t device, const char* name, const char* custom) static int devdown(dev_t device, const char* name, const char* custom)
{ {
char cmd[128]; char cmd[PATH_MAX + 64];
char file[128]; char file[PATH_MAX];
FILE* f; FILE* f;
int ret; int ret;
@ -1154,7 +1156,7 @@ static int devdown(dev_t device, const char* name, const char* custom)
/* if there is a custom command */ /* if there is a custom command */
if (custom[0]) { if (custom[0]) {
char option[128]; char option[PATH_MAX];
snprintf(option, sizeof(option), custom, file); snprintf(option, sizeof(option), custom, file);
snprintf(cmd, sizeof(cmd), "smartctl -s standby,now %s", option); snprintf(cmd, sizeof(cmd), "smartctl -s standby,now %s", option);
} else { } else {

20
configure vendored
View File

@ -1,6 +1,6 @@
#! /bin/sh #! /bin/sh
# Guess values for system-dependent variables and create Makefiles. # Guess values for system-dependent variables and create Makefiles.
# Generated by GNU Autoconf 2.69 for snapraid 11.2. # Generated by GNU Autoconf 2.69 for snapraid 11.3.
# #
# #
# Copyright (C) 1992-1996, 1998-2012 Free Software Foundation, Inc. # Copyright (C) 1992-1996, 1998-2012 Free Software Foundation, Inc.
@ -577,8 +577,8 @@ MAKEFLAGS=
# Identity of this package. # Identity of this package.
PACKAGE_NAME='snapraid' PACKAGE_NAME='snapraid'
PACKAGE_TARNAME='snapraid' PACKAGE_TARNAME='snapraid'
PACKAGE_VERSION='11.2' PACKAGE_VERSION='11.3'
PACKAGE_STRING='snapraid 11.2' PACKAGE_STRING='snapraid 11.3'
PACKAGE_BUGREPORT='' PACKAGE_BUGREPORT=''
PACKAGE_URL='http://www.snapraid.it' PACKAGE_URL='http://www.snapraid.it'
@ -1304,7 +1304,7 @@ if test "$ac_init_help" = "long"; then
# Omit some internal or obsolete options to make the list less imposing. # Omit some internal or obsolete options to make the list less imposing.
# This message is too long to be a string in the A/UX 3.1 sh. # This message is too long to be a string in the A/UX 3.1 sh.
cat <<_ACEOF cat <<_ACEOF
\`configure' configures snapraid 11.2 to adapt to many kinds of systems. \`configure' configures snapraid 11.3 to adapt to many kinds of systems.
Usage: $0 [OPTION]... [VAR=VALUE]... Usage: $0 [OPTION]... [VAR=VALUE]...
@ -1374,7 +1374,7 @@ fi
if test -n "$ac_init_help"; then if test -n "$ac_init_help"; then
case $ac_init_help in case $ac_init_help in
short | recursive ) echo "Configuration of snapraid 11.2:";; short | recursive ) echo "Configuration of snapraid 11.3:";;
esac esac
cat <<\_ACEOF cat <<\_ACEOF
@ -1496,7 +1496,7 @@ fi
test -n "$ac_init_help" && exit $ac_status test -n "$ac_init_help" && exit $ac_status
if $ac_init_version; then if $ac_init_version; then
cat <<\_ACEOF cat <<\_ACEOF
snapraid configure 11.2 snapraid configure 11.3
generated by GNU Autoconf 2.69 generated by GNU Autoconf 2.69
Copyright (C) 2012 Free Software Foundation, Inc. Copyright (C) 2012 Free Software Foundation, Inc.
@ -2102,7 +2102,7 @@ cat >config.log <<_ACEOF
This file contains any messages produced by compilers while This file contains any messages produced by compilers while
running configure, to aid debugging if configure makes a mistake. running configure, to aid debugging if configure makes a mistake.
It was created by snapraid $as_me 11.2, which was It was created by snapraid $as_me 11.3, which was
generated by GNU Autoconf 2.69. Invocation command line was generated by GNU Autoconf 2.69. Invocation command line was
$ $0 $@ $ $0 $@
@ -2965,7 +2965,7 @@ fi
# Define the identity of the package. # Define the identity of the package.
PACKAGE='snapraid' PACKAGE='snapraid'
VERSION='11.2' VERSION='11.3'
cat >>confdefs.h <<_ACEOF cat >>confdefs.h <<_ACEOF
@ -7373,7 +7373,7 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
# report actual input values of CONFIG_FILES etc. instead of their # report actual input values of CONFIG_FILES etc. instead of their
# values after options handling. # values after options handling.
ac_log=" ac_log="
This file was extended by snapraid $as_me 11.2, which was This file was extended by snapraid $as_me 11.3, which was
generated by GNU Autoconf 2.69. Invocation command line was generated by GNU Autoconf 2.69. Invocation command line was
CONFIG_FILES = $CONFIG_FILES CONFIG_FILES = $CONFIG_FILES
@ -7436,7 +7436,7 @@ _ACEOF
cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`" ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`"
ac_cs_version="\\ ac_cs_version="\\
snapraid config.status 11.2 snapraid config.status 11.3
configured by $0, generated by GNU Autoconf 2.69, configured by $0, generated by GNU Autoconf 2.69,
with options \\"\$ac_cs_config\\" with options \\"\$ac_cs_config\\"

View File

@ -647,7 +647,7 @@ and ignore all the parity data.
This command will take a long time, but if you are not paranoid, This command will take a long time, but if you are not paranoid,
you can skip it. you can skip it.
.SS STEP 4 \-> Sync .SS STEP 4 \-> Sync
Run the \[dq]sync\[dq] command to resynchronize the array with the new disk. Run the \[dq]sync\[dq] command to re\-synchronize the array with the new disk.
.PP .PP
.RS 4 .RS 4
snapraid sync snapraid sync
@ -745,7 +745,7 @@ Spins up all the disks of the array.
.PP .PP
You can spin\-up only some specific disks using the \-d, \-\-filter\-disk option. You can spin\-up only some specific disks using the \-d, \-\-filter\-disk option.
.PP .PP
Take care that spinniup\-up all the disks at the same time needs a lot of power. Take care that spinning\-up all the disks at the same time needs a lot of power.
Ensure that your power\-supply can sustain that. Ensure that your power\-supply can sustain that.
.PP .PP
Nothing is modified. Nothing is modified.
@ -912,7 +912,7 @@ Verify all the files and the parity data.
It works like \[dq]fix\[dq], but it only simulates a recovery and no change It works like \[dq]fix\[dq], but it only simulates a recovery and no change
is written in the array. is written in the array.
.PP .PP
This command is mostly intended for manual verifications, This command is mostly intended for manual verification,
like after a recovery process or in other special conditions. like after a recovery process or in other special conditions.
For periodic and scheduled checks uses \[dq]scrub\[dq]. For periodic and scheduled checks uses \[dq]scrub\[dq].
.PP .PP
@ -931,7 +931,7 @@ Nothing is modified.
.SS dup .SS dup
Lists all the duplicate files. Two files are assumed equal if their Lists all the duplicate files. Two files are assumed equal if their
hashes are matching. The file data is not read, but only the hashes are matching. The file data is not read, but only the
precomputed hashes are used. pre\-computed hashes are used.
.PP .PP
Nothing is modified. Nothing is modified.
.SS pool .SS pool
@ -942,7 +942,7 @@ The files are not really copied here, but just linked using
symbolic links. symbolic links.
.PP .PP
When updating, all the present symbolic links and empty When updating, all the present symbolic links and empty
subdirectories are deleted and replaced with the new sub\-directories are deleted and replaced with the new
view of the array. Any other regular file is left in place. view of the array. Any other regular file is left in place.
.PP .PP
Nothing is modified outside the pool directory. Nothing is modified outside the pool directory.
@ -962,20 +962,20 @@ low level devices used by a single disk in the array.
.PP .PP
Nothing is modified. Nothing is modified.
.SS touch .SS touch
Sets arbitrarely the sub\-second timestamp of all the files Sets arbitrarily the sub\-second time\-stamp of all the files
that have it at zero. that have it at zero.
.PP .PP
This improves the SnapRAID capability to recognize moved This improves the SnapRAID capability to recognize moved
and copied files as it makes the timestamp almost unique, and copied files as it makes the time\-stamp almost unique,
removing possible duplicates. removing possible duplicates.
.PP .PP
More specifically, if the sub\-second timestamp is not zero, More specifically, if the sub\-second time\-stamp is not zero,
a moved or copied file is identified as such if it matches a moved or copied file is identified as such if it matches
the name, size and timestamp. If instead the sub\-second timestamp the name, size and time\-stamp. If instead the sub\-second time\-stamp
is zero, it\'s considered a copy only if it matches the full path, is zero, it\'s considered a copy only if it matches the full path,
size and timestamp. size and time\-stamp.
.PP .PP
Note that the second precision timestamp is not modified, Note that the second precision time\-stamp is not modified,
and all the dates and times of your files will be maintained. and all the dates and times of your files will be maintained.
.SS rehash .SS rehash
Schedules a rehash of the whole array. Schedules a rehash of the whole array.
@ -1090,7 +1090,7 @@ Imports from the specified directory any file that you deleted
from the array after the last \[dq]sync\[dq]. from the array after the last \[dq]sync\[dq].
If you still have such files, they could be used by \[dq]check\[dq] If you still have such files, they could be used by \[dq]check\[dq]
and \[dq]fix\[dq] to improve the recover process. and \[dq]fix\[dq] to improve the recover process.
The files are read also in subdirectories and they are The files are read also in sub\-directories and they are
identified regardless of their name. identified regardless of their name.
This option can be used only with \[dq]check\[dq] and \[dq]fix\[dq]. This option can be used only with \[dq]check\[dq] and \[dq]fix\[dq].
.TP .TP
@ -1146,7 +1146,7 @@ This allows to identify copied or moved files from one disk
to another, and to reuse the already computed hash information to another, and to reuse the already computed hash information
to detect silent errors or to recover missing files. to detect silent errors or to recover missing files.
This behavior, in some rare cases, may result in false positives, This behavior, in some rare cases, may result in false positives,
or in a slow process due the many hash verifications, and this or in a slow process due the many hash verification, and this
option allows to resolve them. option allows to resolve them.
This option can be used only with \[dq]sync\[dq], \[dq]check\[dq] and \[dq]fix\[dq]. This option can be used only with \[dq]sync\[dq], \[dq]check\[dq] and \[dq]fix\[dq].
.TP .TP
@ -1280,7 +1280,7 @@ is enabled:
6\-parity enables hexa (six) parity 6\-parity enables hexa (six) parity
.PD .PD
.PP .PP
Each parity level requires the precence of all the previous parity Each parity level requires the presence of all the previous parity
levels. levels.
.PP .PP
The same considerations of the \'parity\' option apply. The same considerations of the \'parity\' option apply.

View File

@ -391,7 +391,7 @@ This command will take a long time, but if you are not paranoid,
you can skip it. you can skip it.
---- 4.4.4 STEP 4 -> Sync ---- ---- 4.4.4 STEP 4 -> Sync ----
Run the "sync" command to resynchronize the array with the new disk. Run the "sync" command to re-synchronize the array with the new disk.
snapraid sync snapraid sync
@ -476,7 +476,7 @@ Spins up all the disks of the array.
You can spin-up only some specific disks using the -d, --filter-disk option. You can spin-up only some specific disks using the -d, --filter-disk option.
Take care that spinniup-up all the disks at the same time needs a lot of power. Take care that spinning-up all the disks at the same time needs a lot of power.
Ensure that your power-supply can sustain that. Ensure that your power-supply can sustain that.
Nothing is modified. Nothing is modified.
@ -643,7 +643,7 @@ Verify all the files and the parity data.
It works like "fix", but it only simulates a recovery and no change It works like "fix", but it only simulates a recovery and no change
is written in the array. is written in the array.
This command is mostly intended for manual verifications, This command is mostly intended for manual verification,
like after a recovery process or in other special conditions. like after a recovery process or in other special conditions.
For periodic and scheduled checks uses "scrub". For periodic and scheduled checks uses "scrub".
@ -668,7 +668,7 @@ Nothing is modified.
Lists all the duplicate files. Two files are assumed equal if their Lists all the duplicate files. Two files are assumed equal if their
hashes are matching. The file data is not read, but only the hashes are matching. The file data is not read, but only the
precomputed hashes are used. pre-computed hashes are used.
Nothing is modified. Nothing is modified.
@ -682,7 +682,7 @@ The files are not really copied here, but just linked using
symbolic links. symbolic links.
When updating, all the present symbolic links and empty When updating, all the present symbolic links and empty
subdirectories are deleted and replaced with the new sub-directories are deleted and replaced with the new
view of the array. Any other regular file is left in place. view of the array. Any other regular file is left in place.
Nothing is modified outside the pool directory. Nothing is modified outside the pool directory.
@ -708,20 +708,20 @@ Nothing is modified.
5.14 touch 5.14 touch
---------- ----------
Sets arbitrarely the sub-second timestamp of all the files Sets arbitrarily the sub-second time-stamp of all the files
that have it at zero. that have it at zero.
This improves the SnapRAID capability to recognize moved This improves the SnapRAID capability to recognize moved
and copied files as it makes the timestamp almost unique, and copied files as it makes the time-stamp almost unique,
removing possible duplicates. removing possible duplicates.
More specifically, if the sub-second timestamp is not zero, More specifically, if the sub-second time-stamp is not zero,
a moved or copied file is identified as such if it matches a moved or copied file is identified as such if it matches
the name, size and timestamp. If instead the sub-second timestamp the name, size and time-stamp. If instead the sub-second time-stamp
is zero, it's considered a copy only if it matches the full path, is zero, it's considered a copy only if it matches the full path,
size and timestamp. size and time-stamp.
Note that the second precision timestamp is not modified, Note that the second precision time-stamp is not modified,
and all the dates and times of your files will be maintained. and all the dates and times of your files will be maintained.
5.15 rehash 5.15 rehash
@ -843,7 +843,7 @@ SnapRAID provides the following options:
from the array after the last "sync". from the array after the last "sync".
If you still have such files, they could be used by "check" If you still have such files, they could be used by "check"
and "fix" to improve the recover process. and "fix" to improve the recover process.
The files are read also in subdirectories and they are The files are read also in sub-directories and they are
identified regardless of their name. identified regardless of their name.
This option can be used only with "check" and "fix". This option can be used only with "check" and "fix".
@ -899,7 +899,7 @@ SnapRAID provides the following options:
to another, and to reuse the already computed hash information to another, and to reuse the already computed hash information
to detect silent errors or to recover missing files. to detect silent errors or to recover missing files.
This behavior, in some rare cases, may result in false positives, This behavior, in some rare cases, may result in false positives,
or in a slow process due the many hash verifications, and this or in a slow process due the many hash verification, and this
option allows to resolve them. option allows to resolve them.
This option can be used only with "sync", "check" and "fix". This option can be used only with "sync", "check" and "fix".
@ -1037,7 +1037,7 @@ is enabled:
* 5-parity enables penta (five) parity * 5-parity enables penta (five) parity
* 6-parity enables hexa (six) parity * 6-parity enables hexa (six) parity
Each parity level requires the precence of all the previous parity Each parity level requires the presence of all the previous parity
levels. levels.
The same considerations of the 'parity' option apply. The same considerations of the 'parity' option apply.

View File

@ -36,7 +36,7 @@ void tommy_array_init(tommy_array* array)
/* fixed initial size */ /* fixed initial size */
array->bucket_bit = TOMMY_ARRAY_BIT; array->bucket_bit = TOMMY_ARRAY_BIT;
array->bucket_max = 1 << array->bucket_bit; array->bucket_max = (tommy_size_t)1 << array->bucket_bit;
array->bucket[0] = tommy_cast(void**, tommy_calloc(array->bucket_max, sizeof(void*))); array->bucket[0] = tommy_cast(void**, tommy_calloc(array->bucket_max, sizeof(void*)));
for (i = 1; i < TOMMY_ARRAY_BIT; ++i) for (i = 1; i < TOMMY_ARRAY_BIT; ++i)
array->bucket[i] = array->bucket[0]; array->bucket[i] = array->bucket[0];
@ -51,11 +51,11 @@ void tommy_array_done(tommy_array* array)
tommy_free(array->bucket[0]); tommy_free(array->bucket[0]);
for (i = TOMMY_ARRAY_BIT; i < array->bucket_bit; ++i) { for (i = TOMMY_ARRAY_BIT; i < array->bucket_bit; ++i) {
void** segment = array->bucket[i]; void** segment = array->bucket[i];
tommy_free(&segment[((tommy_ptrdiff_t)1) << i]); tommy_free(&segment[(tommy_ptrdiff_t)1 << i]);
} }
} }
void tommy_array_grow(tommy_array* array, tommy_count_t count) void tommy_array_grow(tommy_array* array, tommy_size_t count)
{ {
if (array->count >= count) if (array->count >= count)
return; return;
@ -72,7 +72,7 @@ void tommy_array_grow(tommy_array* array, tommy_count_t count)
array->bucket[array->bucket_bit] = &segment[-(tommy_ptrdiff_t)array->bucket_max]; array->bucket[array->bucket_bit] = &segment[-(tommy_ptrdiff_t)array->bucket_max];
++array->bucket_bit; ++array->bucket_bit;
array->bucket_max = 1 << array->bucket_bit; array->bucket_max = (tommy_size_t)1 << array->bucket_bit;
} }
} }

View File

@ -53,20 +53,15 @@
*/ */
#define TOMMY_ARRAY_BIT 6 #define TOMMY_ARRAY_BIT 6
/** \internal
* Max number of elements as a power of 2.
*/
#define TOMMY_ARRAY_BIT_MAX 32
/** /**
* Array container type. * Array container type.
* \note Don't use internal fields directly, but access the container only using functions. * \note Don't use internal fields directly, but access the container only using functions.
*/ */
typedef struct tommy_array_struct { typedef struct tommy_array_struct {
void** bucket[TOMMY_ARRAY_BIT_MAX]; /**< Dynamic array of buckets. */ void** bucket[TOMMY_SIZE_BIT]; /**< Dynamic array of buckets. */
tommy_size_t bucket_max; /**< Number of buckets. */
tommy_size_t count; /**< Number of initialized elements in the array. */
tommy_uint_t bucket_bit; /**< Bits used in the bit mask. */ tommy_uint_t bucket_bit; /**< Bits used in the bit mask. */
tommy_count_t bucket_max; /**< Number of buckets. */
tommy_count_t count; /**< Number of initialized elements in the array. */
} tommy_array; } tommy_array;
/** /**
@ -83,21 +78,21 @@ void tommy_array_done(tommy_array* array);
* Grows the size up to the specified value. * Grows the size up to the specified value.
* All the new elements in the array are initialized with the 0 value. * All the new elements in the array are initialized with the 0 value.
*/ */
void tommy_array_grow(tommy_array* array, tommy_count_t size); void tommy_array_grow(tommy_array* array, tommy_size_t size);
/** /**
* Gets a reference of the element at the specified position. * Gets a reference of the element at the specified position.
* You must be sure that space for this position is already * You must be sure that space for this position is already
* allocated calling tommy_array_grow(). * allocated calling tommy_array_grow().
*/ */
tommy_inline void** tommy_array_ref(tommy_array* array, tommy_count_t pos) tommy_inline void** tommy_array_ref(tommy_array* array, tommy_size_t pos)
{ {
tommy_uint_t bsr; tommy_uint_t bsr;
assert(pos < array->count); assert(pos < array->count);
/* get the highest bit set, in case of all 0, return 0 */ /* get the highest bit set, in case of all 0, return 0 */
bsr = tommy_ilog2_u32(pos | 1); bsr = tommy_ilog2(pos | 1);
return &array->bucket[bsr][pos]; return &array->bucket[bsr][pos];
} }
@ -107,7 +102,7 @@ tommy_inline void** tommy_array_ref(tommy_array* array, tommy_count_t pos)
* You must be sure that space for this position is already * You must be sure that space for this position is already
* allocated calling tommy_array_grow(). * allocated calling tommy_array_grow().
*/ */
tommy_inline void tommy_array_set(tommy_array* array, tommy_count_t pos, void* element) tommy_inline void tommy_array_set(tommy_array* array, tommy_size_t pos, void* element)
{ {
*tommy_array_ref(array, pos) = element; *tommy_array_ref(array, pos) = element;
} }
@ -117,7 +112,7 @@ tommy_inline void tommy_array_set(tommy_array* array, tommy_count_t pos, void* e
* You must be sure that space for this position is already * You must be sure that space for this position is already
* allocated calling tommy_array_grow(). * allocated calling tommy_array_grow().
*/ */
tommy_inline void* tommy_array_get(tommy_array* array, tommy_count_t pos) tommy_inline void* tommy_array_get(tommy_array* array, tommy_size_t pos)
{ {
return *tommy_array_ref(array, pos); return *tommy_array_ref(array, pos);
} }
@ -127,7 +122,7 @@ tommy_inline void* tommy_array_get(tommy_array* array, tommy_count_t pos)
*/ */
tommy_inline void tommy_array_insert(tommy_array* array, void* element) tommy_inline void tommy_array_insert(tommy_array* array, void* element)
{ {
tommy_count_t pos = array->count; tommy_size_t pos = array->count;
tommy_array_grow(array, pos + 1); tommy_array_grow(array, pos + 1);
@ -137,7 +132,7 @@ tommy_inline void tommy_array_insert(tommy_array* array, void* element)
/** /**
* Gets the initialized size of the array. * Gets the initialized size of the array.
*/ */
tommy_inline tommy_count_t tommy_array_size(tommy_array* array) tommy_inline tommy_size_t tommy_array_size(tommy_array* array)
{ {
return array->count; return array->count;
} }

View File

@ -40,7 +40,7 @@ void tommy_arrayblkof_init(tommy_arrayblkof* array, tommy_size_t element_size)
void tommy_arrayblkof_done(tommy_arrayblkof* array) void tommy_arrayblkof_done(tommy_arrayblkof* array)
{ {
tommy_count_t i; tommy_size_t i;
for (i = 0; i < tommy_array_size(&array->block); ++i) for (i = 0; i < tommy_array_size(&array->block); ++i)
tommy_free(tommy_array_get(&array->block, i)); tommy_free(tommy_array_get(&array->block, i));
@ -48,10 +48,10 @@ void tommy_arrayblkof_done(tommy_arrayblkof* array)
tommy_array_done(&array->block); tommy_array_done(&array->block);
} }
void tommy_arrayblkof_grow(tommy_arrayblkof* array, tommy_count_t count) void tommy_arrayblkof_grow(tommy_arrayblkof* array, tommy_size_t count)
{ {
tommy_count_t block_max; tommy_size_t block_max;
tommy_count_t block_mac; tommy_size_t block_mac;
if (array->count >= count) if (array->count >= count)
return; return;

View File

@ -61,7 +61,7 @@
typedef struct tommy_arrayblkof_struct { typedef struct tommy_arrayblkof_struct {
tommy_array block; /**< Array of blocks. */ tommy_array block; /**< Array of blocks. */
tommy_size_t element_size; /**< Size of the stored element in bytes. */ tommy_size_t element_size; /**< Size of the stored element in bytes. */
tommy_count_t count; /**< Number of initialized elements in the array. */ tommy_size_t count; /**< Number of initialized elements in the array. */
} tommy_arrayblkof; } tommy_arrayblkof;
/** /**
@ -79,14 +79,14 @@ void tommy_arrayblkof_done(tommy_arrayblkof* array);
* Grows the size up to the specified value. * Grows the size up to the specified value.
* All the new elements in the array are initialized with the 0 value. * All the new elements in the array are initialized with the 0 value.
*/ */
void tommy_arrayblkof_grow(tommy_arrayblkof* array, tommy_count_t size); void tommy_arrayblkof_grow(tommy_arrayblkof* array, tommy_size_t size);
/** /**
* Gets a reference of the element at the specified position. * Gets a reference of the element at the specified position.
* You must be sure that space for this position is already * You must be sure that space for this position is already
* allocated calling tommy_arrayblkof_grow(). * allocated calling tommy_arrayblkof_grow().
*/ */
tommy_inline void* tommy_arrayblkof_ref(tommy_arrayblkof* array, tommy_count_t pos) tommy_inline void* tommy_arrayblkof_ref(tommy_arrayblkof* array, tommy_size_t pos)
{ {
unsigned char* base; unsigned char* base;
@ -100,7 +100,7 @@ tommy_inline void* tommy_arrayblkof_ref(tommy_arrayblkof* array, tommy_count_t p
/** /**
* Gets the initialized size of the array. * Gets the initialized size of the array.
*/ */
tommy_inline tommy_count_t tommy_arrayblkof_size(tommy_arrayblkof* array) tommy_inline tommy_size_t tommy_arrayblkof_size(tommy_arrayblkof* array)
{ {
return array->count; return array->count;
} }

View File

@ -136,11 +136,6 @@ tommy_inline void tommy_chain_merge_degenerated(tommy_chain* first, tommy_chain*
tommy_chain_merge(first, second, cmp); tommy_chain_merge(first, second, cmp);
} }
/**
* Max number of elements as a power of 2.
*/
#define TOMMY_CHAIN_BIT_MAX 32
/** /**
* Sorts a chain. * Sorts a chain.
* It's a stable merge sort using power of 2 buckets, with O(N*log(N)) complexity, * It's a stable merge sort using power of 2 buckets, with O(N*log(N)) complexity,
@ -158,20 +153,20 @@ tommy_inline void tommy_chain_mergesort(tommy_chain* chain, tommy_compare_func*
/* /*
* Bit buckets of chains. * Bit buckets of chains.
* Each bucket contains 2^i nodes or it's empty. * Each bucket contains 2^i nodes or it's empty.
* The chain at address TOMMY_CHAIN_BIT_MAX is an independet variable operating as "carry". * The chain at address TOMMY_BIT_MAX is an independet variable operating as "carry".
* We keep it in the same "bit" vector to avoid reports from the valgrind tool sgcheck. * We keep it in the same "bit" vector to avoid reports from the valgrind tool sgcheck.
*/ */
tommy_chain bit[TOMMY_CHAIN_BIT_MAX + 1]; tommy_chain bit[TOMMY_SIZE_BIT + 1];
/** /**
* Value stored inside the bit bucket. * Value stored inside the bit bucket.
* It's used to know which bucket is empty of full. * It's used to know which bucket is empty of full.
*/ */
tommy_count_t counter; tommy_size_t counter;
tommy_node* node = chain->head; tommy_node* node = chain->head;
tommy_node* tail = chain->tail; tommy_node* tail = chain->tail;
tommy_count_t mask; tommy_size_t mask;
tommy_count_t i; tommy_size_t i;
counter = 0; counter = 0;
while (1) { while (1) {
@ -179,9 +174,9 @@ tommy_inline void tommy_chain_mergesort(tommy_chain* chain, tommy_compare_func*
tommy_chain* last; tommy_chain* last;
/* carry bit to add */ /* carry bit to add */
last = &bit[TOMMY_CHAIN_BIT_MAX]; last = &bit[TOMMY_SIZE_BIT];
bit[TOMMY_CHAIN_BIT_MAX].head = node; bit[TOMMY_SIZE_BIT].head = node;
bit[TOMMY_CHAIN_BIT_MAX].tail = node; bit[TOMMY_SIZE_BIT].tail = node;
next = node->next; next = node->next;
/* add the bit, propagating the carry */ /* add the bit, propagating the carry */
@ -206,7 +201,7 @@ tommy_inline void tommy_chain_mergesort(tommy_chain* chain, tommy_compare_func*
} }
/* merge the buckets */ /* merge the buckets */
i = tommy_ctz_u32(counter); i = tommy_ctz(counter);
mask = counter >> i; mask = counter >> i;
while (mask != 1) { while (mask != 1) {
mask >>= 1; mask >>= 1;

View File

@ -92,22 +92,22 @@ tommy_uint32_t tommy_hash_u32(tommy_uint32_t init_val, const void* void_key, tom
b += tommy_le_uint32_read(key + 4); b += tommy_le_uint32_read(key + 4);
a += tommy_le_uint32_read(key + 0); a += tommy_le_uint32_read(key + 0);
break; break;
case 11 : c += ((tommy_uint32_t)key[10]) << 16; case 11 : c += ((tommy_uint32_t)key[10]) << 16; /* fallthrough */
case 10 : c += ((tommy_uint32_t)key[9]) << 8; case 10 : c += ((tommy_uint32_t)key[9]) << 8; /* fallthrough */
case 9 : c += key[8]; case 9 : c += key[8]; /* fallthrough */
case 8 : case 8 :
b += tommy_le_uint32_read(key + 4); b += tommy_le_uint32_read(key + 4);
a += tommy_le_uint32_read(key + 0); a += tommy_le_uint32_read(key + 0);
break; break;
case 7 : b += ((tommy_uint32_t)key[6]) << 16; case 7 : b += ((tommy_uint32_t)key[6]) << 16; /* fallthrough */
case 6 : b += ((tommy_uint32_t)key[5]) << 8; case 6 : b += ((tommy_uint32_t)key[5]) << 8; /* fallthrough */
case 5 : b += key[4]; case 5 : b += key[4]; /* fallthrough */
case 4 : case 4 :
a += tommy_le_uint32_read(key + 0); a += tommy_le_uint32_read(key + 0);
break; break;
case 3 : a += ((tommy_uint32_t)key[2]) << 16; case 3 : a += ((tommy_uint32_t)key[2]) << 16; /* fallthrough */
case 2 : a += ((tommy_uint32_t)key[1]) << 8; case 2 : a += ((tommy_uint32_t)key[1]) << 8; /* fallthrough */
case 1 : a += key[0]; case 1 : a += key[0]; /* fallthrough */
} }
tommy_final(a, b, c); tommy_final(a, b, c);
@ -142,22 +142,22 @@ tommy_uint64_t tommy_hash_u64(tommy_uint64_t init_val, const void* void_key, tom
b += tommy_le_uint32_read(key + 4); b += tommy_le_uint32_read(key + 4);
a += tommy_le_uint32_read(key + 0); a += tommy_le_uint32_read(key + 0);
break; break;
case 11 : c += ((tommy_uint32_t)key[10]) << 16; case 11 : c += ((tommy_uint32_t)key[10]) << 16; /* fallthrough */
case 10 : c += ((tommy_uint32_t)key[9]) << 8; case 10 : c += ((tommy_uint32_t)key[9]) << 8; /* fallthrough */
case 9 : c += key[8]; case 9 : c += key[8]; /* fallthrough */
case 8 : case 8 :
b += tommy_le_uint32_read(key + 4); b += tommy_le_uint32_read(key + 4);
a += tommy_le_uint32_read(key + 0); a += tommy_le_uint32_read(key + 0);
break; break;
case 7 : b += ((tommy_uint32_t)key[6]) << 16; case 7 : b += ((tommy_uint32_t)key[6]) << 16; /* fallthrough */
case 6 : b += ((tommy_uint32_t)key[5]) << 8; case 6 : b += ((tommy_uint32_t)key[5]) << 8; /* fallthrough */
case 5 : b += key[4]; case 5 : b += key[4]; /* fallthrough */
case 4 : case 4 :
a += tommy_le_uint32_read(key + 0); a += tommy_le_uint32_read(key + 0);
break; break;
case 3 : a += ((tommy_uint32_t)key[2]) << 16; case 3 : a += ((tommy_uint32_t)key[2]) << 16; /* fallthrough */
case 2 : a += ((tommy_uint32_t)key[1]) << 8; case 2 : a += ((tommy_uint32_t)key[1]) << 8; /* fallthrough */
case 1 : a += key[0]; case 1 : a += key[0]; /* fallthrough */
} }
tommy_final(a, b, c); tommy_final(a, b, c);

View File

@ -37,11 +37,6 @@
/******************************************************************************/ /******************************************************************************/
/* hash */ /* hash */
/**
* Hash type used in hashtables.
*/
typedef tommy_key_t tommy_hash_t;
/** /**
* Hash function with a 32 bits result. * Hash function with a 32 bits result.
* Implementation of the Robert Jenkins "lookup3" hash 32 bits version, * Implementation of the Robert Jenkins "lookup3" hash 32 bits version,

View File

@ -35,7 +35,7 @@ void tommy_hashdyn_init(tommy_hashdyn* hashdyn)
{ {
/* fixed initial size */ /* fixed initial size */
hashdyn->bucket_bit = TOMMY_HASHDYN_BIT; hashdyn->bucket_bit = TOMMY_HASHDYN_BIT;
hashdyn->bucket_max = 1 << hashdyn->bucket_bit; hashdyn->bucket_max = (tommy_size_t)1 << hashdyn->bucket_bit;
hashdyn->bucket_mask = hashdyn->bucket_max - 1; hashdyn->bucket_mask = hashdyn->bucket_max - 1;
hashdyn->bucket = tommy_cast(tommy_hashdyn_node**, tommy_calloc(hashdyn->bucket_max, sizeof(tommy_hashdyn_node*))); hashdyn->bucket = tommy_cast(tommy_hashdyn_node**, tommy_calloc(hashdyn->bucket_max, sizeof(tommy_hashdyn_node*)));
@ -50,18 +50,18 @@ void tommy_hashdyn_done(tommy_hashdyn* hashdyn)
/** /**
* Resize the bucket vector. * Resize the bucket vector.
*/ */
static void tommy_hashdyn_resize(tommy_hashdyn* hashdyn, tommy_count_t new_bucket_bit) static void tommy_hashdyn_resize(tommy_hashdyn* hashdyn, tommy_size_t new_bucket_bit)
{ {
tommy_count_t bucket_bit; tommy_size_t bucket_bit;
tommy_count_t bucket_max; tommy_size_t bucket_max;
tommy_count_t new_bucket_max; tommy_size_t new_bucket_max;
tommy_count_t new_bucket_mask; tommy_size_t new_bucket_mask;
tommy_hashdyn_node** new_bucket; tommy_hashdyn_node** new_bucket;
bucket_bit = hashdyn->bucket_bit; bucket_bit = hashdyn->bucket_bit;
bucket_max = hashdyn->bucket_max; bucket_max = hashdyn->bucket_max;
new_bucket_max = 1 << new_bucket_bit; new_bucket_max = (tommy_size_t)1 << new_bucket_bit;
new_bucket_mask = new_bucket_max - 1; new_bucket_mask = new_bucket_max - 1;
/* allocate the new vector using malloc() and not calloc() */ /* allocate the new vector using malloc() and not calloc() */
@ -70,7 +70,7 @@ static void tommy_hashdyn_resize(tommy_hashdyn* hashdyn, tommy_count_t new_bucke
/* reinsert all the elements */ /* reinsert all the elements */
if (new_bucket_bit > bucket_bit) { if (new_bucket_bit > bucket_bit) {
tommy_count_t i; tommy_size_t i;
/* grow */ /* grow */
for (i = 0; i < bucket_max; ++i) { for (i = 0; i < bucket_max; ++i) {
@ -84,7 +84,7 @@ static void tommy_hashdyn_resize(tommy_hashdyn* hashdyn, tommy_count_t new_bucke
j = hashdyn->bucket[i]; j = hashdyn->bucket[i];
while (j) { while (j) {
tommy_hashdyn_node* j_next = j->next; tommy_hashdyn_node* j_next = j->next;
tommy_count_t pos = j->key & new_bucket_mask; tommy_size_t pos = j->index & new_bucket_mask;
if (new_bucket[pos]) if (new_bucket[pos])
tommy_list_insert_tail_not_empty(new_bucket[pos], j); tommy_list_insert_tail_not_empty(new_bucket[pos], j);
else else
@ -93,7 +93,7 @@ static void tommy_hashdyn_resize(tommy_hashdyn* hashdyn, tommy_count_t new_bucke
} }
} }
} else { } else {
tommy_count_t i; tommy_size_t i;
/* shrink */ /* shrink */
for (i = 0; i < new_bucket_max; ++i) { for (i = 0; i < new_bucket_max; ++i) {
@ -136,11 +136,11 @@ tommy_inline void hashdyn_shrink_step(tommy_hashdyn* hashdyn)
void tommy_hashdyn_insert(tommy_hashdyn* hashdyn, tommy_hashdyn_node* node, void* data, tommy_hash_t hash) void tommy_hashdyn_insert(tommy_hashdyn* hashdyn, tommy_hashdyn_node* node, void* data, tommy_hash_t hash)
{ {
tommy_count_t pos = hash & hashdyn->bucket_mask; tommy_size_t pos = hash & hashdyn->bucket_mask;
tommy_list_insert_tail(&hashdyn->bucket[pos], node, data); tommy_list_insert_tail(&hashdyn->bucket[pos], node, data);
node->key = hash; node->index = hash;
++hashdyn->count; ++hashdyn->count;
@ -149,7 +149,7 @@ void tommy_hashdyn_insert(tommy_hashdyn* hashdyn, tommy_hashdyn_node* node, void
void* tommy_hashdyn_remove_existing(tommy_hashdyn* hashdyn, tommy_hashdyn_node* node) void* tommy_hashdyn_remove_existing(tommy_hashdyn* hashdyn, tommy_hashdyn_node* node)
{ {
tommy_count_t pos = node->key & hashdyn->bucket_mask; tommy_size_t pos = node->index & hashdyn->bucket_mask;
tommy_list_remove_existing(&hashdyn->bucket[pos], node); tommy_list_remove_existing(&hashdyn->bucket[pos], node);
@ -162,12 +162,12 @@ void* tommy_hashdyn_remove_existing(tommy_hashdyn* hashdyn, tommy_hashdyn_node*
void* tommy_hashdyn_remove(tommy_hashdyn* hashdyn, tommy_search_func* cmp, const void* cmp_arg, tommy_hash_t hash) void* tommy_hashdyn_remove(tommy_hashdyn* hashdyn, tommy_search_func* cmp, const void* cmp_arg, tommy_hash_t hash)
{ {
tommy_count_t pos = hash & hashdyn->bucket_mask; tommy_size_t pos = hash & hashdyn->bucket_mask;
tommy_hashdyn_node* node = hashdyn->bucket[pos]; tommy_hashdyn_node* node = hashdyn->bucket[pos];
while (node) { while (node) {
/* we first check if the hash matches, as in the same bucket we may have multiples hash values */ /* we first check if the hash matches, as in the same bucket we may have multiples hash values */
if (node->key == hash && cmp(cmp_arg, node->data) == 0) { if (node->index == hash && cmp(cmp_arg, node->data) == 0) {
tommy_list_remove_existing(&hashdyn->bucket[pos], node); tommy_list_remove_existing(&hashdyn->bucket[pos], node);
--hashdyn->count; --hashdyn->count;
@ -184,9 +184,9 @@ void* tommy_hashdyn_remove(tommy_hashdyn* hashdyn, tommy_search_func* cmp, const
void tommy_hashdyn_foreach(tommy_hashdyn* hashdyn, tommy_foreach_func* func) void tommy_hashdyn_foreach(tommy_hashdyn* hashdyn, tommy_foreach_func* func)
{ {
tommy_count_t bucket_max = hashdyn->bucket_max; tommy_size_t bucket_max = hashdyn->bucket_max;
tommy_hashdyn_node** bucket = hashdyn->bucket; tommy_hashdyn_node** bucket = hashdyn->bucket;
tommy_count_t pos; tommy_size_t pos;
for (pos = 0; pos < bucket_max; ++pos) { for (pos = 0; pos < bucket_max; ++pos) {
tommy_hashdyn_node* node = bucket[pos]; tommy_hashdyn_node* node = bucket[pos];
@ -201,9 +201,9 @@ void tommy_hashdyn_foreach(tommy_hashdyn* hashdyn, tommy_foreach_func* func)
void tommy_hashdyn_foreach_arg(tommy_hashdyn* hashdyn, tommy_foreach_arg_func* func, void* arg) void tommy_hashdyn_foreach_arg(tommy_hashdyn* hashdyn, tommy_foreach_arg_func* func, void* arg)
{ {
tommy_count_t bucket_max = hashdyn->bucket_max; tommy_size_t bucket_max = hashdyn->bucket_max;
tommy_hashdyn_node** bucket = hashdyn->bucket; tommy_hashdyn_node** bucket = hashdyn->bucket;
tommy_count_t pos; tommy_size_t pos;
for (pos = 0; pos < bucket_max; ++pos) { for (pos = 0; pos < bucket_max; ++pos) {
tommy_hashdyn_node* node = bucket[pos]; tommy_hashdyn_node* node = bucket[pos];

View File

@ -160,10 +160,10 @@ typedef tommy_node tommy_hashdyn_node;
*/ */
typedef struct tommy_hashdyn_struct { typedef struct tommy_hashdyn_struct {
tommy_hashdyn_node** bucket; /**< Hash buckets. One list for each hash modulus. */ tommy_hashdyn_node** bucket; /**< Hash buckets. One list for each hash modulus. */
tommy_size_t bucket_max; /**< Number of buckets. */
tommy_size_t bucket_mask; /**< Bit mask to access the buckets. */
tommy_size_t count; /**< Number of elements. */
tommy_uint_t bucket_bit; /**< Bits used in the bit mask. */ tommy_uint_t bucket_bit; /**< Bits used in the bit mask. */
tommy_count_t bucket_max; /**< Number of buckets. */
tommy_count_t bucket_mask; /**< Bit mask to access the buckets. */
tommy_count_t count; /**< Number of elements. */
} tommy_hashdyn; } tommy_hashdyn;
/** /**
@ -226,7 +226,7 @@ tommy_inline void* tommy_hashdyn_search(tommy_hashdyn* hashdyn, tommy_search_fun
while (i) { while (i) {
/* we first check if the hash matches, as in the same bucket we may have multiples hash values */ /* we first check if the hash matches, as in the same bucket we may have multiples hash values */
if (i->key == hash && cmp(cmp_arg, i->data) == 0) if (i->index == hash && cmp(cmp_arg, i->data) == 0)
return i->data; return i->data;
i = i->next; i = i->next;
} }
@ -281,7 +281,7 @@ void tommy_hashdyn_foreach_arg(tommy_hashdyn* hashdyn, tommy_foreach_arg_func* f
/** /**
* Gets the number of elements. * Gets the number of elements.
*/ */
tommy_inline tommy_count_t tommy_hashdyn_count(tommy_hashdyn* hashdyn) tommy_inline tommy_size_t tommy_hashdyn_count(tommy_hashdyn* hashdyn)
{ {
return hashdyn->count; return hashdyn->count;
} }

View File

@ -226,24 +226,6 @@ tommy_inline void tommy_list_insert_tail(tommy_list* list, tommy_node* node, voi
node->data = data; node->data = data;
} }
/** \internal
* Removes an element from the head of a not empty list.
* \param list The list. The list cannot be empty.
* \return The node removed.
*/
tommy_inline tommy_node* tommy_list_remove_head_not_empty(tommy_list* list)
{
tommy_node* head = tommy_list_head(list);
/* remove from the "circular" prev list */
head->next->prev = head->prev;
/* remove from the "0 terminated" next list */
*list = head->next; /* the new head, in case 0 */
return head;
}
/** /**
* Removes an element from the list. * Removes an element from the list.
* You must already have the address of the element to remove. * You must already have the address of the element to remove.
@ -329,9 +311,9 @@ tommy_inline tommy_bool_t tommy_list_empty(tommy_list* list)
* Gets the number of elements. * Gets the number of elements.
* \note This operation is O(n). * \note This operation is O(n).
*/ */
tommy_inline tommy_count_t tommy_list_count(tommy_list* list) tommy_inline tommy_size_t tommy_list_count(tommy_list* list)
{ {
tommy_count_t count = 0; tommy_size_t count = 0;
tommy_node* i = tommy_list_head(list); tommy_node* i = tommy_list_head(list);
while (i) { while (i) {

View File

@ -39,10 +39,10 @@ void tommy_tree_init(tommy_tree* tree, tommy_compare_func* cmp)
tree->cmp = cmp; tree->cmp = cmp;
} }
static int tommy_tree_delta(tommy_tree_node* root) static tommy_ssize_t tommy_tree_delta(tommy_tree_node* root)
{ {
int left_height = root->prev ? root->prev->key : 0; tommy_ssize_t left_height = root->prev ? root->prev->index : 0;
int right_height = root->next ? root->next->key : 0; tommy_ssize_t right_height = root->next ? root->next->index : 0;
return left_height - right_height; return left_height - right_height;
} }
@ -84,7 +84,7 @@ static tommy_tree_node* tommy_tree_move_right(tommy_tree_node* root, tommy_tree_
static tommy_tree_node* tommy_tree_balance(tommy_tree_node* root) static tommy_tree_node* tommy_tree_balance(tommy_tree_node* root)
{ {
int delta = tommy_tree_delta(root); tommy_ssize_t delta = tommy_tree_delta(root);
if (delta < -1) { if (delta < -1) {
if (tommy_tree_delta(root->next) > 0) if (tommy_tree_delta(root->next) > 0)
@ -99,16 +99,16 @@ static tommy_tree_node* tommy_tree_balance(tommy_tree_node* root)
} }
/* recompute key */ /* recompute key */
root->key = 0; root->index = 0;
if (root->prev && root->prev->key > root->key) if (root->prev && root->prev->index > root->index)
root->key = root->prev->key; root->index = root->prev->index;
if (root->next && root->next->key > root->key) if (root->next && root->next->index > root->index)
root->key = root->next->key; root->index = root->next->index;
/* count itself */ /* count itself */
root->key += 1; root->index += 1;
return root; return root;
} }
@ -145,7 +145,7 @@ void* tommy_tree_insert(tommy_tree* tree, tommy_tree_node* node, void* data)
insert->data = data; insert->data = data;
insert->prev = 0; insert->prev = 0;
insert->next = 0; insert->next = 0;
insert->key = 0; insert->index = 0;
tree->root = tommy_tree_insert_node(tree->cmp, tree->root, &insert); tree->root = tommy_tree_insert_node(tree->cmp, tree->root, &insert);

View File

@ -117,8 +117,8 @@ typedef tommy_node tommy_tree_node;
*/ */
typedef struct tommy_tree_struct { typedef struct tommy_tree_struct {
tommy_tree_node* root; /**< Root node. */ tommy_tree_node* root; /**< Root node. */
tommy_count_t count; /**< Number of elements. */
tommy_compare_func* cmp; /**< Comparison function. */ tommy_compare_func* cmp; /**< Comparison function. */
tommy_size_t count; /**< Number of elements. */
} tommy_tree; } tommy_tree;
/** /**
@ -213,7 +213,7 @@ void tommy_tree_foreach_arg(tommy_tree* tree, tommy_foreach_arg_func* func, void
/** /**
* Gets the number of elements. * Gets the number of elements.
*/ */
tommy_inline tommy_count_t tommy_tree_count(tommy_tree* tree) tommy_inline tommy_size_t tommy_tree_count(tommy_tree* tree)
{ {
return tree->count; return tree->count;
} }

View File

@ -24,7 +24,6 @@
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE. * POSSIBILITY OF SUCH DAMAGE.
*/ */
/** \file /** \file
* Generic types. * Generic types.
*/ */
@ -37,17 +36,37 @@
#include <stddef.h> #include <stddef.h>
#if defined(_MSC_VER) #ifdef _MSC_VER
typedef unsigned tommy_uint32_t; /**< Generic uint32_t type. */ typedef unsigned tommy_uint32_t; /**< Generic uint32_t type. */
typedef unsigned _int64 tommy_uint64_t; /**< Generic uint64_t type. */ typedef unsigned _int64 tommy_uint64_t; /**< Generic uint64_t type. */
typedef size_t tommy_uintptr_t; /**< Generic uintptr_t type. */ typedef size_t tommy_uintptr_t; /**< Generic uintptr_t type. */
#ifdef _WIN64
#define TOMMY_SIZE_BIT 64
typedef unsigned _int64_t tommy_size_t; /**< Generic size_t type. */
typedef _int64_t tommy_ssize_t; /**< Generic ssize_t type. */
#else
#define TOMMY_SIZE_BIT 32
typedef unsigned tommy_size_t; /**< Generic size_t type. */
typedef int tommy_ssize_t; /**< Generic ssize_t type. */
#endif
#else #else
#include <stdint.h> #include <stdint.h>
typedef uint32_t tommy_uint32_t; /**< Generic uint32_t type. */ typedef uint32_t tommy_uint32_t; /**< Generic uint32_t type. */
typedef uint64_t tommy_uint64_t; /**< Generic uint64_t type. */ typedef uint64_t tommy_uint64_t; /**< Generic uint64_t type. */
typedef uintptr_t tommy_uintptr_t; /**< Generic uintptr_t type. */ typedef uintptr_t tommy_uintptr_t; /**< Generic uintptr_t type. */
#if SIZE_MAX == UINT64_MAX
#define TOMMY_SIZE_BIT 64
typedef uint64_t tommy_size_t; /**< Generic size_t type. */
typedef int64_t tommy_ssize_t; /**< Generic ssize_t type. */
#elif SIZE_MAX == UINT32_MAX
#define TOMMY_SIZE_BIT 32
typedef uint32_t tommy_size_t; /**< Generic size_t type. */
typedef int32_t tommy_ssize_t; /**< Generic ssize_t type. */
#else
#error Unsupported SIZE_MAX
#endif #endif
typedef size_t tommy_size_t; /**< Generic size_t type. */ #endif
typedef ptrdiff_t tommy_ptrdiff_t; /**< Generic ptrdiff_t type. */ typedef ptrdiff_t tommy_ptrdiff_t; /**< Generic ptrdiff_t type. */
typedef int tommy_bool_t; /**< Generic boolean type. */ typedef int tommy_bool_t; /**< Generic boolean type. */
@ -59,13 +78,6 @@ typedef int tommy_bool_t; /**< Generic boolean type. */
*/ */
typedef tommy_uint32_t tommy_uint_t; typedef tommy_uint32_t tommy_uint_t;
/**
* Generic unsigned integer for counting objects.
*
* TommyDS doesn't support more than 2^32-1 objects.
*/
typedef tommy_uint32_t tommy_count_t;
/** \internal /** \internal
* Type cast required for the C++ compilation. * Type cast required for the C++ compilation.
* When compiling in C++ we cannot convert a void* pointer to another pointer. * When compiling in C++ we cannot convert a void* pointer to another pointer.
@ -152,17 +164,17 @@ typedef tommy_uint32_t tommy_count_t;
#endif #endif
/******************************************************************************/ /******************************************************************************/
/* key */ /* key/hash */
/** /**
* Key type used in indexed data structures to store the key or the hash value. * Type used in indexed data structures to store the key of a object.
*/ */
typedef tommy_uint32_t tommy_key_t; typedef tommy_size_t tommy_key_t;
/** /**
* Bits into the ::tommy_key_t type. * Type used in hashtables to store the hash of a object.
*/ */
#define TOMMY_KEY_BIT (sizeof(tommy_key_t) * 8) typedef tommy_size_t tommy_hash_t;
/******************************************************************************/ /******************************************************************************/
/* node */ /* node */
@ -200,11 +212,12 @@ typedef struct tommy_node_struct {
void* data; void* data;
/** /**
* Key used to store the node. * Index of the node.
* With tries this field is used to store the key.
* With hashtables this field is used to store the hash value. * With hashtables this field is used to store the hash value.
* With lists this field is not used. * With lists this field is not used.
*/ */
tommy_key_t key; tommy_size_t index;
} tommy_node; } tommy_node;
/******************************************************************************/ /******************************************************************************/
@ -302,6 +315,10 @@ typedef void tommy_foreach_arg_func(void* arg, void* obj);
#include <intrin.h> #include <intrin.h>
#pragma intrinsic(_BitScanReverse) #pragma intrinsic(_BitScanReverse)
#pragma intrinsic(_BitScanForward) #pragma intrinsic(_BitScanForward)
#if TOMMY_SIZE_BIT == 64
#pragma intrinsic(_BitScanReverse64)
#pragma intrinsic(_BitScanForward64)
#endif
#endif #endif
/** \internal /** \internal
@ -363,6 +380,29 @@ tommy_inline tommy_uint_t tommy_ilog2_u32(tommy_uint32_t value)
#endif #endif
} }
#if TOMMY_SIZE_BIT == 64
/**
* Bit scan reverse or integer log2 for 64 bits.
*/
tommy_inline tommy_uint_t tommy_ilog2_u64(tommy_uint64_t value)
{
#if defined(_MSC_VER)
unsigned long count;
_BitScanReverse64(&count, value);
return count;
#elif defined(__GNUC__)
return __builtin_clzll(value) ^ 63;
#else
uint32_t l = value & 0xFFFFFFFFU;
uint32_t h = value >> 32;
if (h)
return tommy_ilog2_u32(h) + 32;
else
return tommy_ilog2_u32(l);
#endif
}
#endif
/** /**
* Bit scan forward or trailing zero count. * Bit scan forward or trailing zero count.
* Return the bit index of the least significant 1 bit. * Return the bit index of the least significant 1 bit.
@ -391,6 +431,29 @@ tommy_inline tommy_uint_t tommy_ctz_u32(tommy_uint32_t value)
#endif #endif
} }
#if TOMMY_SIZE_BIT == 64
/**
* Bit scan forward or trailing zero count for 64 bits.
*/
tommy_inline tommy_uint_t tommy_ctz_u64(tommy_uint64_t value)
{
#if defined(_MSC_VER)
unsigned long count;
_BitScanForward64(&count, value);
return count;
#elif defined(__GNUC__)
return __builtin_ctzll(value);
#else
uint32_t l = value & 0xFFFFFFFFU;
uint32_t h = value >> 32;
if (l)
return tommy_ctz_u32(l);
else
return tommy_ctz_u32(h) + 32;
#endif
}
#endif
/** /**
* Rounds up to the next power of 2. * Rounds up to the next power of 2.
* For the value 0, the result is undefined. * For the value 0, the result is undefined.
@ -412,6 +475,23 @@ tommy_inline tommy_uint32_t tommy_roundup_pow2_u32(tommy_uint32_t value)
return value; return value;
} }
/**
* Rounds up to the next power of 2 for 64 bits.
*/
tommy_inline tommy_uint64_t tommy_roundup_pow2_u64(tommy_uint64_t value)
{
--value;
value |= value >> 1;
value |= value >> 2;
value |= value >> 4;
value |= value >> 8;
value |= value >> 16;
value |= value >> 32;
++value;
return value;
}
/** /**
* Check if the specified word has a byte at 0. * Check if the specified word has a byte at 0.
* \return 0 or 1. * \return 0 or 1.
@ -420,5 +500,19 @@ tommy_inline int tommy_haszero_u32(tommy_uint32_t value)
{ {
return ((value - 0x01010101) & ~value & 0x80808080) != 0; return ((value - 0x01010101) & ~value & 0x80808080) != 0;
} }
/*
* Bit depth mapping.
*/
#if TOMMY_SIZE_BIT == 64
#define tommy_ilog2 tommy_ilog2_u64
#define tommy_ctz tommy_ctz_u64
#define tommy_roundup_pow2 tommy_roundup_pow2_u64
#else
#define tommy_ilog2 tommy_ilog2_u32
#define tommy_ctz tommy_ctz_u32
#define tommy_roundup_pow2 tommy_roundup_pow2_u32
#endif
#endif #endif