mirror of
https://github.com/ruby/ruby.git
synced 2022-11-09 12:17:21 -05:00
Removed sdbm and it tests
This commit is contained in:
parent
adbdf11f94
commit
343ad9eff5
Notes:
git
2020-06-19 08:27:13 +09:00
7 changed files with 0 additions and 3006 deletions
952
ext/sdbm/_sdbm.c
952
ext/sdbm/_sdbm.c
|
@ -1,952 +0,0 @@
|
|||
/*
|
||||
* sdbm - ndbm work-alike hashed database library
|
||||
* based on Per-Aake Larson's Dynamic Hashing algorithms. BIT 18 (1978).
|
||||
* author: oz@nexus.yorku.ca
|
||||
* status: public domain.
|
||||
*
|
||||
* core routines
|
||||
*/
|
||||
|
||||
#include "ruby/ruby.h"
|
||||
|
||||
#ifdef HAVE_UNISTD_H
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
#include "sdbm.h"
|
||||
|
||||
/*
|
||||
* sdbm - ndbm work-alike hashed database library
|
||||
* tuning and portability constructs [not nearly enough]
|
||||
* author: oz@nexus.yorku.ca
|
||||
*/
|
||||
|
||||
#define BYTESIZ 8
|
||||
|
||||
#ifdef BSD42
|
||||
#define SEEK_SET L_SET
|
||||
#define memset(s,c,n) bzero((s), (n)) /* only when c is zero */
|
||||
#define memcpy(s1,s2,n) bcopy((s2), (s1), (n))
|
||||
#define memcmp(s1,s2,n) bcmp((s1),(s2),(n))
|
||||
#endif
|
||||
|
||||
/*
|
||||
* important tuning parms (hah)
|
||||
*/
|
||||
|
||||
#ifndef SEEDUPS
|
||||
#define SEEDUPS 1 /* always detect duplicates */
|
||||
#endif
|
||||
#ifndef BADMESS
|
||||
#define BADMESS 1 /* generate a message for worst case:
|
||||
cannot make room after SPLTMAX splits */
|
||||
#endif
|
||||
|
||||
/*
|
||||
* misc
|
||||
*/
|
||||
#ifdef DEBUG
|
||||
#define debug(x) printf x
|
||||
#else
|
||||
#define debug(x)
|
||||
#endif
|
||||
|
||||
#ifdef BIG_E
|
||||
#define GET_SHORT(p, i) (((unsigned)((unsigned char *)(p))[(i)*2] << 8) + (((unsigned char *)(p))[(i)*2 + 1]))
|
||||
#define PUT_SHORT(p, i, s) (((unsigned char *)(p))[(i)*2] = (unsigned char)((s) >> 8), ((unsigned char *)(p))[(i)*2 + 1] = (unsigned char)(s))
|
||||
#else
|
||||
#define GET_SHORT(p, i) ((p)[(i)])
|
||||
#define PUT_SHORT(p, i, s) ((p)[(i)] = (s))
|
||||
#endif
|
||||
|
||||
/*#include "pair.h"*/
|
||||
static int fitpair proto((char *, int));
|
||||
static void putpair proto((char *, datum, datum));
|
||||
static datum getpair proto((char *, datum));
|
||||
static int delpair proto((char *, datum));
|
||||
static int chkpage proto((char *));
|
||||
static datum getnkey proto((char *, int));
|
||||
static void splpage proto((char *, char *, long));
|
||||
#if SEEDUPS
|
||||
static int duppair proto((char *, datum));
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#ifdef DOSISH
|
||||
#include <io.h>
|
||||
#endif
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#ifdef BSD42
|
||||
#include <sys/file.h>
|
||||
#else
|
||||
#include <fcntl.h>
|
||||
/*#include <memory.h>*/
|
||||
#endif
|
||||
#ifndef O_BINARY
|
||||
#define O_BINARY 0
|
||||
#endif
|
||||
|
||||
#include <errno.h>
|
||||
#ifndef EPERM
|
||||
#define EPERM EACCES
|
||||
#endif
|
||||
#include <string.h>
|
||||
|
||||
#ifdef __STDC__
|
||||
#include <stddef.h>
|
||||
#endif
|
||||
|
||||
#ifndef NULL
|
||||
#define NULL 0
|
||||
#endif
|
||||
|
||||
/*
|
||||
* externals
|
||||
*/
|
||||
#if !defined(__sun) && !defined(_WIN32) && !defined(__CYGWIN__) && !defined(errno)
|
||||
extern int errno;
|
||||
#endif
|
||||
|
||||
/*
|
||||
* forward
|
||||
*/
|
||||
static int getdbit proto((DBM *, long));
|
||||
static int setdbit proto((DBM *, long));
|
||||
static int getpage proto((DBM *, long));
|
||||
static datum getnext proto((DBM *));
|
||||
static int makroom proto((DBM *, long, int));
|
||||
|
||||
/*
|
||||
* useful macros
|
||||
*/
|
||||
#define bad(x) ((x).dptr == NULL || (x).dsize < 0)
|
||||
#define exhash(item) sdbm_hash((item).dptr, (item).dsize)
|
||||
#define ioerr(db) ((db)->flags |= DBM_IOERR)
|
||||
|
||||
#define OFF_PAG(off) (long) (off) * PBLKSIZ
|
||||
#define OFF_DIR(off) (long) (off) * DBLKSIZ
|
||||
|
||||
static long masks[] = {
|
||||
000000000000L, 000000000001L, 000000000003L,
|
||||
000000000007L, 000000000017L, 000000000037L,
|
||||
000000000077L, 000000000177L, 000000000377L,
|
||||
000000000777L, 000000001777L, 000000003777L,
|
||||
000000007777L, 000000017777L, 000000037777L,
|
||||
000000077777L, 000000177777L, 000000377777L,
|
||||
000000777777L, 000001777777L, 000003777777L,
|
||||
000007777777L, 000017777777L, 000037777777L,
|
||||
000077777777L, 000177777777L, 000377777777L,
|
||||
000777777777L, 001777777777L, 003777777777L,
|
||||
007777777777L, 017777777777L
|
||||
};
|
||||
|
||||
datum nullitem = {NULL, 0};
|
||||
|
||||
DBM *
|
||||
sdbm_open(register char *file, register int flags, register int mode)
|
||||
{
|
||||
register DBM *db;
|
||||
register char *dirname;
|
||||
register char *pagname;
|
||||
register size_t n;
|
||||
|
||||
if (file == NULL || !*file)
|
||||
return errno = EINVAL, (DBM *) NULL;
|
||||
/*
|
||||
* need space for two separate filenames
|
||||
*/
|
||||
n = strlen(file) * 2 + strlen(DIRFEXT) + strlen(PAGFEXT) + 2;
|
||||
|
||||
if ((dirname = malloc(n)) == NULL)
|
||||
return errno = ENOMEM, (DBM *) NULL;
|
||||
/*
|
||||
* build the file names
|
||||
*/
|
||||
dirname = strcat(strcpy(dirname, file), DIRFEXT);
|
||||
pagname = strcpy(dirname + strlen(dirname) + 1, file);
|
||||
pagname = strcat(pagname, PAGFEXT);
|
||||
|
||||
db = sdbm_prep(dirname, pagname, flags, mode);
|
||||
free((char *) dirname);
|
||||
return db;
|
||||
}
|
||||
|
||||
static int
|
||||
fd_set_cloexec(int fd)
|
||||
{
|
||||
/* MinGW don't have F_GETFD and FD_CLOEXEC. [ruby-core:40281] */
|
||||
#ifdef F_GETFD
|
||||
int flags, ret;
|
||||
flags = fcntl(fd, F_GETFD); /* should not fail except EBADF. */
|
||||
if (flags == -1) {
|
||||
return -1;
|
||||
}
|
||||
if (2 < fd) {
|
||||
if (!(flags & FD_CLOEXEC)) {
|
||||
flags |= FD_CLOEXEC;
|
||||
ret = fcntl(fd, F_SETFD, flags);
|
||||
if (ret == -1) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
DBM *
|
||||
sdbm_prep(char *dirname, char *pagname, int flags, int mode)
|
||||
{
|
||||
register DBM *db;
|
||||
struct stat dstat;
|
||||
|
||||
if ((db = (DBM *) malloc(sizeof(DBM))) == NULL)
|
||||
return errno = ENOMEM, (DBM *) NULL;
|
||||
|
||||
db->pagf = -1;
|
||||
db->dirf = -1;
|
||||
db->flags = 0;
|
||||
db->hmask = 0;
|
||||
db->blkptr = 0;
|
||||
db->keyptr = 0;
|
||||
/*
|
||||
* adjust user flags so that WRONLY becomes RDWR,
|
||||
* as required by this package. Also set our internal
|
||||
* flag for RDONLY.
|
||||
*/
|
||||
if (flags & O_WRONLY)
|
||||
flags = (flags & ~O_WRONLY) | O_RDWR;
|
||||
if (flags & O_RDONLY)
|
||||
db->flags = DBM_RDONLY;
|
||||
/*
|
||||
* open the files in sequence, and stat the dirfile.
|
||||
* If we fail anywhere, undo everything, return NULL.
|
||||
*/
|
||||
flags |= O_BINARY;
|
||||
#ifdef O_CLOEXEC
|
||||
flags |= O_CLOEXEC;
|
||||
#endif
|
||||
|
||||
if ((db->pagf = open(pagname, flags, mode)) == -1) goto err;
|
||||
if (fd_set_cloexec(db->pagf) == -1) goto err;
|
||||
if ((db->dirf = open(dirname, flags, mode)) == -1) goto err;
|
||||
if (fd_set_cloexec(db->dirf) == -1) goto err;
|
||||
/*
|
||||
* need the dirfile size to establish max bit number.
|
||||
*/
|
||||
if (fstat(db->dirf, &dstat) == -1) goto err;
|
||||
/*
|
||||
* zero size: either a fresh database, or one with a single,
|
||||
* unsplit data page: dirpage is all zeros.
|
||||
*/
|
||||
db->dirbno = (!dstat.st_size) ? 0 : -1;
|
||||
db->pagbno = -1;
|
||||
db->maxbno = dstat.st_size * (long) BYTESIZ;
|
||||
|
||||
(void) memset(db->pagbuf, 0, PBLKSIZ);
|
||||
(void) memset(db->dirbuf, 0, DBLKSIZ);
|
||||
/*
|
||||
* success
|
||||
*/
|
||||
return db;
|
||||
|
||||
err:
|
||||
if (db->pagf != -1)
|
||||
(void) close(db->pagf);
|
||||
if (db->dirf != -1)
|
||||
(void) close(db->dirf);
|
||||
free((char *) db);
|
||||
return (DBM *) NULL;
|
||||
}
|
||||
|
||||
void
|
||||
sdbm_close(register DBM *db)
|
||||
{
|
||||
if (db == NULL)
|
||||
errno = EINVAL;
|
||||
else {
|
||||
(void) close(db->dirf);
|
||||
(void) close(db->pagf);
|
||||
free((char *) db);
|
||||
}
|
||||
}
|
||||
|
||||
datum
|
||||
sdbm_fetch(register DBM *db, datum key)
|
||||
{
|
||||
if (db == NULL || bad(key))
|
||||
return errno = EINVAL, nullitem;
|
||||
|
||||
if (getpage(db, exhash(key)))
|
||||
return getpair(db->pagbuf, key);
|
||||
|
||||
return ioerr(db), nullitem;
|
||||
}
|
||||
|
||||
int
|
||||
sdbm_delete(register DBM *db, datum key)
|
||||
{
|
||||
if (db == NULL || bad(key))
|
||||
return errno = EINVAL, -1;
|
||||
if (sdbm_rdonly(db))
|
||||
return errno = EPERM, -1;
|
||||
|
||||
if (getpage(db, exhash(key))) {
|
||||
if (!delpair(db->pagbuf, key))
|
||||
return -1;
|
||||
/*
|
||||
* update the page file
|
||||
*/
|
||||
if (lseek(db->pagf, OFF_PAG(db->pagbno), SEEK_SET) < 0
|
||||
|| write(db->pagf, db->pagbuf, PBLKSIZ) < 0)
|
||||
return ioerr(db), -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
return ioerr(db), -1;
|
||||
}
|
||||
|
||||
int
|
||||
sdbm_store(register DBM *db, datum key, datum val, int flags)
|
||||
{
|
||||
int need;
|
||||
register long hash;
|
||||
|
||||
if (db == NULL || bad(key))
|
||||
return errno = EINVAL, -1;
|
||||
if (sdbm_rdonly(db))
|
||||
return errno = EPERM, -1;
|
||||
|
||||
need = key.dsize + val.dsize;
|
||||
/*
|
||||
* is the pair too big (or too small) for this database ??
|
||||
*/
|
||||
if (need < 0 || need > PAIRMAX)
|
||||
return errno = EINVAL, -1;
|
||||
|
||||
if (getpage(db, (hash = exhash(key)))) {
|
||||
/*
|
||||
* if we need to replace, delete the key/data pair
|
||||
* first. If it is not there, ignore.
|
||||
*/
|
||||
if (flags == DBM_REPLACE)
|
||||
(void) delpair(db->pagbuf, key);
|
||||
#if SEEDUPS
|
||||
else if (duppair(db->pagbuf, key))
|
||||
return 1;
|
||||
#endif
|
||||
/*
|
||||
* if we do not have enough room, we have to split.
|
||||
*/
|
||||
if (!fitpair(db->pagbuf, need))
|
||||
if (!makroom(db, hash, need))
|
||||
return ioerr(db), -1;
|
||||
/*
|
||||
* we have enough room or split is successful. insert the key,
|
||||
* and update the page file.
|
||||
*/
|
||||
(void) putpair(db->pagbuf, key, val);
|
||||
|
||||
if (lseek(db->pagf, OFF_PAG(db->pagbno), SEEK_SET) < 0
|
||||
|| write(db->pagf, db->pagbuf, PBLKSIZ) < 0)
|
||||
return ioerr(db), -1;
|
||||
/*
|
||||
* success
|
||||
*/
|
||||
return 0;
|
||||
}
|
||||
|
||||
return ioerr(db), -1;
|
||||
}
|
||||
|
||||
/*
|
||||
* makroom - make room by splitting the overfull page
|
||||
* this routine will attempt to make room for SPLTMAX times before
|
||||
* giving up.
|
||||
*/
|
||||
static int
|
||||
makroom(register DBM *db, long int hash, int need)
|
||||
{
|
||||
long newp;
|
||||
char twin[PBLKSIZ];
|
||||
#if defined _WIN32
|
||||
char zer[PBLKSIZ];
|
||||
long oldtail;
|
||||
#endif
|
||||
char *pag = db->pagbuf;
|
||||
char *new = twin;
|
||||
register int smax = SPLTMAX;
|
||||
|
||||
do {
|
||||
/*
|
||||
* split the current page
|
||||
*/
|
||||
(void) splpage(pag, new, db->hmask + 1);
|
||||
/*
|
||||
* address of the new page
|
||||
*/
|
||||
newp = (hash & db->hmask) | (db->hmask + 1);
|
||||
debug(("newp: %ld\n", newp));
|
||||
/*
|
||||
* write delay, read avoidance/cache shuffle:
|
||||
* select the page for incoming pair: if key is to go to the new page,
|
||||
* write out the previous one, and copy the new one over, thus making
|
||||
* it the current page. If not, simply write the new page, and we are
|
||||
* still looking at the page of interest. current page is not updated
|
||||
* here, as sdbm_store will do so, after it inserts the incoming pair.
|
||||
*/
|
||||
|
||||
#if defined _WIN32
|
||||
/*
|
||||
* Fill hole with 0 if made it.
|
||||
* (hole is NOT read as 0)
|
||||
*/
|
||||
oldtail = lseek(db->pagf, 0L, SEEK_END);
|
||||
memset(zer, 0, PBLKSIZ);
|
||||
while (OFF_PAG(newp) > oldtail) {
|
||||
if (lseek(db->pagf, 0L, SEEK_END) < 0 ||
|
||||
write(db->pagf, zer, PBLKSIZ) < 0) {
|
||||
|
||||
return 0;
|
||||
}
|
||||
oldtail += PBLKSIZ;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (hash & (db->hmask + 1)) {
|
||||
if (lseek(db->pagf, OFF_PAG(db->pagbno), SEEK_SET) < 0
|
||||
|| write(db->pagf, db->pagbuf, PBLKSIZ) < 0)
|
||||
return 0;
|
||||
db->pagbno = newp;
|
||||
(void) memcpy(pag, new, PBLKSIZ);
|
||||
}
|
||||
else if (lseek(db->pagf, OFF_PAG(newp), SEEK_SET) < 0
|
||||
|| write(db->pagf, new, PBLKSIZ) < 0)
|
||||
return 0;
|
||||
|
||||
if (!setdbit(db, db->curbit))
|
||||
return 0;
|
||||
/*
|
||||
* see if we have enough room now
|
||||
*/
|
||||
if (fitpair(pag, need))
|
||||
return 1;
|
||||
/*
|
||||
* try again... update curbit and hmask as getpage would have
|
||||
* done. because of our update of the current page, we do not
|
||||
* need to read in anything. BUT we have to write the current
|
||||
* [deferred] page out, as the window of failure is too great.
|
||||
*/
|
||||
db->curbit = 2 * db->curbit +
|
||||
((hash & (db->hmask + 1)) ? 2 : 1);
|
||||
db->hmask |= (db->hmask + 1);
|
||||
|
||||
if (lseek(db->pagf, OFF_PAG(db->pagbno), SEEK_SET) < 0
|
||||
|| write(db->pagf, db->pagbuf, PBLKSIZ) < 0)
|
||||
return 0;
|
||||
|
||||
} while (--smax);
|
||||
/*
|
||||
* if we are here, this is real bad news. After SPLTMAX splits,
|
||||
* we still cannot fit the key. say goodnight.
|
||||
*/
|
||||
#if BADMESS
|
||||
(void) (write(2, "sdbm: cannot insert after SPLTMAX attempts.\n", 44) < 0);
|
||||
#endif
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* the following two routines will break if
|
||||
* deletions aren't taken into account. (ndbm bug)
|
||||
*/
|
||||
datum
|
||||
sdbm_firstkey(register DBM *db)
|
||||
{
|
||||
if (db == NULL)
|
||||
return errno = EINVAL, nullitem;
|
||||
/*
|
||||
* start at page 0
|
||||
*/
|
||||
(void) memset(db->pagbuf, 0, PBLKSIZ);
|
||||
if (lseek(db->pagf, OFF_PAG(0), SEEK_SET) < 0
|
||||
|| read(db->pagf, db->pagbuf, PBLKSIZ) < 0)
|
||||
return ioerr(db), nullitem;
|
||||
db->pagbno = 0;
|
||||
db->blkptr = 0;
|
||||
db->keyptr = 0;
|
||||
|
||||
return getnext(db);
|
||||
}
|
||||
|
||||
datum
|
||||
sdbm_nextkey(register DBM *db)
|
||||
{
|
||||
if (db == NULL)
|
||||
return errno = EINVAL, nullitem;
|
||||
return getnext(db);
|
||||
}
|
||||
|
||||
/*
|
||||
* all important binary trie traversal
|
||||
*/
|
||||
static int
|
||||
getpage(register DBM *db, register long int hash)
|
||||
{
|
||||
register int hbit;
|
||||
register long dbit;
|
||||
register long pagb;
|
||||
|
||||
dbit = 0;
|
||||
hbit = 0;
|
||||
while (dbit < db->maxbno && getdbit(db, dbit))
|
||||
dbit = 2 * dbit + ((hash & ((long) 1 << hbit++)) ? 2 : 1);
|
||||
|
||||
debug(("dbit: %ld...", dbit));
|
||||
|
||||
db->curbit = dbit;
|
||||
db->hmask = masks[hbit];
|
||||
|
||||
pagb = hash & db->hmask;
|
||||
/*
|
||||
* see if the block we need is already in memory.
|
||||
* note: this lookaside cache has about 10% hit rate.
|
||||
*/
|
||||
if (pagb != db->pagbno) {
|
||||
/*
|
||||
* note: here, we assume a "hole" is read as 0s.
|
||||
* if not, must zero pagbuf first.
|
||||
*/
|
||||
(void) memset(db->pagbuf, 0, PBLKSIZ);
|
||||
|
||||
if (lseek(db->pagf, OFF_PAG(pagb), SEEK_SET) < 0
|
||||
|| read(db->pagf, db->pagbuf, PBLKSIZ) < 0)
|
||||
return 0;
|
||||
if (!chkpage(db->pagbuf)) {
|
||||
return 0;
|
||||
}
|
||||
db->pagbno = pagb;
|
||||
|
||||
debug(("pag read: %ld\n", pagb));
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int
|
||||
getdbit(register DBM *db, register long int dbit)
|
||||
{
|
||||
register long c;
|
||||
register long dirb;
|
||||
|
||||
c = dbit / BYTESIZ;
|
||||
dirb = c / DBLKSIZ;
|
||||
|
||||
if (dirb != db->dirbno) {
|
||||
if (lseek(db->dirf, OFF_DIR(dirb), SEEK_SET) < 0
|
||||
|| read(db->dirf, db->dirbuf, DBLKSIZ) < 0)
|
||||
return 0;
|
||||
db->dirbno = dirb;
|
||||
|
||||
debug(("dir read: %ld\n", dirb));
|
||||
}
|
||||
|
||||
return db->dirbuf[c % DBLKSIZ] & (1 << (dbit % BYTESIZ));
|
||||
}
|
||||
|
||||
static int
|
||||
setdbit(register DBM *db, register long int dbit)
|
||||
{
|
||||
register long c;
|
||||
register long dirb;
|
||||
|
||||
c = dbit / BYTESIZ;
|
||||
dirb = c / DBLKSIZ;
|
||||
|
||||
if (dirb != db->dirbno) {
|
||||
if (lseek(db->dirf, OFF_DIR(dirb), SEEK_SET) < 0
|
||||
|| read(db->dirf, db->dirbuf, DBLKSIZ) < 0)
|
||||
return 0;
|
||||
db->dirbno = dirb;
|
||||
|
||||
debug(("dir read: %ld\n", dirb));
|
||||
}
|
||||
|
||||
db->dirbuf[c % DBLKSIZ] |= (1 << (dbit % BYTESIZ));
|
||||
|
||||
if (dbit >= db->maxbno)
|
||||
db->maxbno += (long) DBLKSIZ * BYTESIZ;
|
||||
|
||||
if (lseek(db->dirf, OFF_DIR(dirb), SEEK_SET) < 0
|
||||
|| write(db->dirf, db->dirbuf, DBLKSIZ) < 0)
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* getnext - get the next key in the page, and if done with
|
||||
* the page, try the next page in sequence
|
||||
*/
|
||||
static datum
|
||||
getnext(register DBM *db)
|
||||
{
|
||||
datum key;
|
||||
|
||||
for (;;) {
|
||||
db->keyptr++;
|
||||
key = getnkey(db->pagbuf, db->keyptr);
|
||||
if (key.dptr != NULL)
|
||||
return key;
|
||||
/*
|
||||
* we either run out, or there is nothing on this page..
|
||||
* try the next one... If we lost our position on the
|
||||
* file, we will have to seek.
|
||||
*/
|
||||
db->keyptr = 0;
|
||||
if (db->pagbno != db->blkptr++)
|
||||
if (lseek(db->pagf, OFF_PAG(db->blkptr), SEEK_SET) < 0)
|
||||
break;
|
||||
db->pagbno = db->blkptr;
|
||||
if (read(db->pagf, db->pagbuf, PBLKSIZ) <= 0)
|
||||
break;
|
||||
if (!chkpage(db->pagbuf)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return ioerr(db), nullitem;
|
||||
}
|
||||
|
||||
/* pair.c */
|
||||
/*
|
||||
* sdbm - ndbm work-alike hashed database library
|
||||
* based on Per-Aake Larson's Dynamic Hashing algorithms. BIT 18 (1978).
|
||||
* author: oz@nexus.yorku.ca
|
||||
* status: public domain.
|
||||
*
|
||||
* page-level routines
|
||||
*/
|
||||
|
||||
#ifndef BSD42
|
||||
/*#include <memory.h>*/
|
||||
#endif
|
||||
|
||||
#define exhash(item) sdbm_hash((item).dptr, (item).dsize)
|
||||
|
||||
/*
|
||||
* forward
|
||||
*/
|
||||
static int seepair proto((char *, int, char *, int));
|
||||
|
||||
/*
|
||||
* page format:
|
||||
* +------------------------------+
|
||||
* ino | n | keyoff | datoff | keyoff |
|
||||
* +------------+--------+--------+
|
||||
* | datoff | - - - ----> |
|
||||
* +--------+---------------------+
|
||||
* | F R E E A R E A |
|
||||
* +--------------+---------------+
|
||||
* | <---- - - - | data |
|
||||
* +--------+-----+----+----------+
|
||||
* | key | data | key |
|
||||
* +--------+----------+----------+
|
||||
*
|
||||
* calculating the offsets for free area: if the number
|
||||
* of entries (ino[0]) is zero, the offset to the END of
|
||||
* the free area is the block size. Otherwise, it is the
|
||||
* nth (ino[ino[0]]) entry's offset.
|
||||
*/
|
||||
|
||||
static int
|
||||
fitpair(char *pag, int need)
|
||||
{
|
||||
register int n;
|
||||
register int off;
|
||||
register int free;
|
||||
register short *ino = (short *) pag;
|
||||
|
||||
off = ((n = GET_SHORT(ino,0)) > 0) ? GET_SHORT(ino,n) : PBLKSIZ;
|
||||
free = off - (n + 1) * (int)sizeof(short);
|
||||
need += 2 * (int)sizeof(short);
|
||||
|
||||
debug(("free %d need %d\n", free, need));
|
||||
|
||||
return need <= free;
|
||||
}
|
||||
|
||||
static void
|
||||
putpair(char *pag, datum key, datum val)
|
||||
{
|
||||
register int n;
|
||||
register int off;
|
||||
register short *ino = (short *) pag;
|
||||
|
||||
off = ((n = GET_SHORT(ino,0)) > 0) ? GET_SHORT(ino,n) : PBLKSIZ;
|
||||
/*
|
||||
* enter the key first
|
||||
*/
|
||||
off -= key.dsize;
|
||||
if (key.dsize)
|
||||
(void) memcpy(pag + off, key.dptr, key.dsize);
|
||||
PUT_SHORT(ino,n + 1,off);
|
||||
/*
|
||||
* now the data
|
||||
*/
|
||||
off -= val.dsize;
|
||||
if (val.dsize)
|
||||
(void) memcpy(pag + off, val.dptr, val.dsize);
|
||||
PUT_SHORT(ino,n + 2,off);
|
||||
/*
|
||||
* adjust item count
|
||||
*/
|
||||
PUT_SHORT(ino,0,GET_SHORT(ino,0) + 2);
|
||||
}
|
||||
|
||||
static datum
|
||||
getpair(char *pag, datum key)
|
||||
{
|
||||
register int i;
|
||||
register int n;
|
||||
datum val;
|
||||
register short *ino = (short *) pag;
|
||||
|
||||
if ((n = GET_SHORT(ino,0)) == 0)
|
||||
return nullitem;
|
||||
|
||||
if ((i = seepair(pag, n, key.dptr, key.dsize)) == 0)
|
||||
return nullitem;
|
||||
|
||||
val.dptr = pag + GET_SHORT(ino,i + 1);
|
||||
val.dsize = GET_SHORT(ino,i) - GET_SHORT(ino,i + 1);
|
||||
return val;
|
||||
}
|
||||
|
||||
#if SEEDUPS
|
||||
static int
|
||||
duppair(char *pag, datum key)
|
||||
{
|
||||
register short *ino = (short *) pag;
|
||||
return GET_SHORT(ino,0) > 0 &&
|
||||
seepair(pag, GET_SHORT(ino,0), key.dptr, key.dsize) > 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
static datum
|
||||
getnkey(char *pag, int num)
|
||||
{
|
||||
datum key;
|
||||
register int off;
|
||||
register short *ino = (short *) pag;
|
||||
|
||||
num = num * 2 - 1;
|
||||
if (GET_SHORT(ino,0) == 0 || num > GET_SHORT(ino,0))
|
||||
return nullitem;
|
||||
|
||||
off = (num > 1) ? GET_SHORT(ino,num - 1) : PBLKSIZ;
|
||||
|
||||
key.dptr = pag + GET_SHORT(ino,num);
|
||||
key.dsize = off - GET_SHORT(ino,num);
|
||||
|
||||
return key;
|
||||
}
|
||||
|
||||
static int
|
||||
delpair(char *pag, datum key)
|
||||
{
|
||||
register int n;
|
||||
register int i;
|
||||
register short *ino = (short *) pag;
|
||||
|
||||
if ((n = GET_SHORT(ino,0)) == 0)
|
||||
return 0;
|
||||
|
||||
if ((i = seepair(pag, n, key.dptr, key.dsize)) == 0)
|
||||
return 0;
|
||||
/*
|
||||
* found the key. if it is the last entry
|
||||
* [i.e. i == n - 1] we just adjust the entry count.
|
||||
* hard case: move all data down onto the deleted pair,
|
||||
* shift offsets onto deleted offsets, and adjust them.
|
||||
* [note: 0 < i < n]
|
||||
*/
|
||||
if (i < n - 1) {
|
||||
register int m;
|
||||
register char *dst = pag + (i == 1 ? PBLKSIZ : GET_SHORT(ino,i - 1));
|
||||
register char *src = pag + GET_SHORT(ino,i + 1);
|
||||
register ptrdiff_t zoo = dst - src;
|
||||
|
||||
debug(("free-up %"PRIdPTRDIFF" ", zoo));
|
||||
/*
|
||||
* shift data/keys down
|
||||
*/
|
||||
m = GET_SHORT(ino,i + 1) - GET_SHORT(ino,n);
|
||||
#ifdef DUFF
|
||||
#define MOVB *--dst = *--src
|
||||
|
||||
if (m > 0) {
|
||||
register int loop = (m + 8 - 1) >> 3;
|
||||
|
||||
switch (m & (8 - 1)) {
|
||||
case 0: do {
|
||||
MOVB; case 7: MOVB;
|
||||
case 6: MOVB; case 5: MOVB;
|
||||
case 4: MOVB; case 3: MOVB;
|
||||
case 2: MOVB; case 1: MOVB;
|
||||
} while (--loop);
|
||||
}
|
||||
}
|
||||
#else
|
||||
#ifdef MEMMOVE
|
||||
memmove(dst-m, src-m, m);
|
||||
#else
|
||||
while (m--)
|
||||
*--dst = *--src;
|
||||
#endif
|
||||
#endif
|
||||
/*
|
||||
* adjust offset index up
|
||||
*/
|
||||
while (i < n - 1) {
|
||||
PUT_SHORT(ino,i, GET_SHORT(ino,i + 2) + zoo);
|
||||
i++;
|
||||
}
|
||||
}
|
||||
PUT_SHORT(ino, 0, GET_SHORT(ino, 0) - 2);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* search for the key in the page.
|
||||
* return offset index in the range 0 < i < n.
|
||||
* return 0 if not found.
|
||||
*/
|
||||
static int
|
||||
seepair(char *pag, register int n, register char *key, register int siz)
|
||||
{
|
||||
register int i;
|
||||
register int off = PBLKSIZ;
|
||||
register short *ino = (short *) pag;
|
||||
|
||||
for (i = 1; i < n; i += 2) {
|
||||
if (siz == off - GET_SHORT(ino,i) &&
|
||||
memcmp(key, pag + GET_SHORT(ino,i), siz) == 0)
|
||||
return i;
|
||||
off = GET_SHORT(ino,i + 1);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
splpage(char *pag, char *new, long int sbit)
|
||||
{
|
||||
datum key;
|
||||
datum val;
|
||||
|
||||
register int n;
|
||||
register int off = PBLKSIZ;
|
||||
char cur[PBLKSIZ];
|
||||
register short *ino = (short *) cur;
|
||||
|
||||
(void) memcpy(cur, pag, PBLKSIZ);
|
||||
(void) memset(pag, 0, PBLKSIZ);
|
||||
(void) memset(new, 0, PBLKSIZ);
|
||||
|
||||
n = GET_SHORT(ino,0);
|
||||
for (ino++; n > 0; ino += 2) {
|
||||
key.dptr = cur + GET_SHORT(ino,0);
|
||||
key.dsize = off - GET_SHORT(ino,0);
|
||||
val.dptr = cur + GET_SHORT(ino,1);
|
||||
val.dsize = GET_SHORT(ino,0) - GET_SHORT(ino,1);
|
||||
/*
|
||||
* select the page pointer (by looking at sbit) and insert
|
||||
*/
|
||||
(void) putpair((exhash(key) & sbit) ? new : pag, key, val);
|
||||
|
||||
off = GET_SHORT(ino,1);
|
||||
n -= 2;
|
||||
}
|
||||
|
||||
debug(("%d split %d/%d\n", ((short *) cur)[0] / 2,
|
||||
((short *) new)[0] / 2,
|
||||
((short *) pag)[0] / 2));
|
||||
}
|
||||
|
||||
/*
|
||||
* check page sanity:
|
||||
* number of entries should be something
|
||||
* reasonable, and all offsets in the index should be in order.
|
||||
* this could be made more rigorous.
|
||||
*/
|
||||
static int
|
||||
chkpage(char *pag)
|
||||
{
|
||||
register int n;
|
||||
register int off;
|
||||
register short *ino = (short *) pag;
|
||||
|
||||
if ((n = GET_SHORT(ino,0)) < 0 || n > PBLKSIZ / (int)sizeof(short))
|
||||
return 0;
|
||||
|
||||
if (n > 0) {
|
||||
off = PBLKSIZ;
|
||||
for (ino++; n > 0; ino += 2) {
|
||||
if (GET_SHORT(ino,0) > off || GET_SHORT(ino,1) > off ||
|
||||
GET_SHORT(ino,1) > GET_SHORT(ino,0))
|
||||
return 0;
|
||||
off = GET_SHORT(ino,1);
|
||||
n -= 2;
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* hash.c */
|
||||
/*
|
||||
* sdbm - ndbm work-alike hashed database library
|
||||
* based on Per-Aake Larson's Dynamic Hashing algorithms. BIT 18 (1978).
|
||||
* author: oz@nexus.yorku.ca
|
||||
* status: public domain. keep it that way.
|
||||
*
|
||||
* hashing routine
|
||||
*/
|
||||
|
||||
/*
|
||||
* polynomial conversion ignoring overflows
|
||||
* [this seems to work remarkably well, in fact better
|
||||
* then the ndbm hash function. Replace at your own risk]
|
||||
* use: 65599 nice.
|
||||
* 65587 even better.
|
||||
*/
|
||||
long
|
||||
sdbm_hash(register char *str, register int len)
|
||||
{
|
||||
register unsigned long n = 0;
|
||||
|
||||
#ifdef DUFF
|
||||
|
||||
#define HASHC n = *str++ + 65599 * n
|
||||
|
||||
if (len > 0) {
|
||||
register int loop = (len + 8 - 1) >> 3;
|
||||
|
||||
switch(len & (8 - 1)) {
|
||||
case 0: do {
|
||||
HASHC; case 7: HASHC;
|
||||
case 6: HASHC; case 5: HASHC;
|
||||
case 4: HASHC; case 3: HASHC;
|
||||
case 2: HASHC; case 1: HASHC;
|
||||
} while (--loop);
|
||||
}
|
||||
|
||||
}
|
||||
#else
|
||||
while (len--)
|
||||
n = ((*str++) & 255) + 65587L * n;
|
||||
#endif
|
||||
return n;
|
||||
}
|
331
ext/sdbm/depend
331
ext/sdbm/depend
|
@ -1,331 +0,0 @@
|
|||
# AUTOGENERATED DEPENDENCIES START
|
||||
_sdbm.o: $(RUBY_EXTCONF_H)
|
||||
_sdbm.o: $(arch_hdrdir)/ruby/config.h
|
||||
_sdbm.o: $(hdrdir)/ruby/internal/anyargs.h
|
||||
_sdbm.o: $(hdrdir)/ruby/internal/arithmetic.h
|
||||
_sdbm.o: $(hdrdir)/ruby/internal/arithmetic/char.h
|
||||
_sdbm.o: $(hdrdir)/ruby/internal/arithmetic/double.h
|
||||
_sdbm.o: $(hdrdir)/ruby/internal/arithmetic/fixnum.h
|
||||
_sdbm.o: $(hdrdir)/ruby/internal/arithmetic/gid_t.h
|
||||
_sdbm.o: $(hdrdir)/ruby/internal/arithmetic/int.h
|
||||
_sdbm.o: $(hdrdir)/ruby/internal/arithmetic/intptr_t.h
|
||||
_sdbm.o: $(hdrdir)/ruby/internal/arithmetic/long.h
|
||||
_sdbm.o: $(hdrdir)/ruby/internal/arithmetic/long_long.h
|
||||
_sdbm.o: $(hdrdir)/ruby/internal/arithmetic/mode_t.h
|
||||
_sdbm.o: $(hdrdir)/ruby/internal/arithmetic/off_t.h
|
||||
_sdbm.o: $(hdrdir)/ruby/internal/arithmetic/pid_t.h
|
||||
_sdbm.o: $(hdrdir)/ruby/internal/arithmetic/short.h
|
||||
_sdbm.o: $(hdrdir)/ruby/internal/arithmetic/size_t.h
|
||||
_sdbm.o: $(hdrdir)/ruby/internal/arithmetic/st_data_t.h
|
||||
_sdbm.o: $(hdrdir)/ruby/internal/arithmetic/uid_t.h
|
||||
_sdbm.o: $(hdrdir)/ruby/internal/assume.h
|
||||
_sdbm.o: $(hdrdir)/ruby/internal/attr/alloc_size.h
|
||||
_sdbm.o: $(hdrdir)/ruby/internal/attr/artificial.h
|
||||
_sdbm.o: $(hdrdir)/ruby/internal/attr/cold.h
|
||||
_sdbm.o: $(hdrdir)/ruby/internal/attr/const.h
|
||||
_sdbm.o: $(hdrdir)/ruby/internal/attr/constexpr.h
|
||||
_sdbm.o: $(hdrdir)/ruby/internal/attr/deprecated.h
|
||||
_sdbm.o: $(hdrdir)/ruby/internal/attr/diagnose_if.h
|
||||
_sdbm.o: $(hdrdir)/ruby/internal/attr/enum_extensibility.h
|
||||
_sdbm.o: $(hdrdir)/ruby/internal/attr/error.h
|
||||
_sdbm.o: $(hdrdir)/ruby/internal/attr/flag_enum.h
|
||||
_sdbm.o: $(hdrdir)/ruby/internal/attr/forceinline.h
|
||||
_sdbm.o: $(hdrdir)/ruby/internal/attr/format.h
|
||||
_sdbm.o: $(hdrdir)/ruby/internal/attr/maybe_unused.h
|
||||
_sdbm.o: $(hdrdir)/ruby/internal/attr/noalias.h
|
||||
_sdbm.o: $(hdrdir)/ruby/internal/attr/nodiscard.h
|
||||
_sdbm.o: $(hdrdir)/ruby/internal/attr/noexcept.h
|
||||
_sdbm.o: $(hdrdir)/ruby/internal/attr/noinline.h
|
||||
_sdbm.o: $(hdrdir)/ruby/internal/attr/nonnull.h
|
||||
_sdbm.o: $(hdrdir)/ruby/internal/attr/noreturn.h
|
||||
_sdbm.o: $(hdrdir)/ruby/internal/attr/pure.h
|
||||
_sdbm.o: $(hdrdir)/ruby/internal/attr/restrict.h
|
||||
_sdbm.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
|
||||
_sdbm.o: $(hdrdir)/ruby/internal/attr/warning.h
|
||||
_sdbm.o: $(hdrdir)/ruby/internal/attr/weakref.h
|
||||
_sdbm.o: $(hdrdir)/ruby/internal/cast.h
|
||||
_sdbm.o: $(hdrdir)/ruby/internal/compiler_is.h
|
||||
_sdbm.o: $(hdrdir)/ruby/internal/compiler_is/apple.h
|
||||
_sdbm.o: $(hdrdir)/ruby/internal/compiler_is/clang.h
|
||||
_sdbm.o: $(hdrdir)/ruby/internal/compiler_is/gcc.h
|
||||
_sdbm.o: $(hdrdir)/ruby/internal/compiler_is/intel.h
|
||||
_sdbm.o: $(hdrdir)/ruby/internal/compiler_is/msvc.h
|
||||
_sdbm.o: $(hdrdir)/ruby/internal/compiler_is/sunpro.h
|
||||
_sdbm.o: $(hdrdir)/ruby/internal/compiler_since.h
|
||||
_sdbm.o: $(hdrdir)/ruby/internal/config.h
|
||||
_sdbm.o: $(hdrdir)/ruby/internal/constant_p.h
|
||||
_sdbm.o: $(hdrdir)/ruby/internal/core.h
|
||||
_sdbm.o: $(hdrdir)/ruby/internal/core/rarray.h
|
||||
_sdbm.o: $(hdrdir)/ruby/internal/core/rbasic.h
|
||||
_sdbm.o: $(hdrdir)/ruby/internal/core/rbignum.h
|
||||
_sdbm.o: $(hdrdir)/ruby/internal/core/rclass.h
|
||||
_sdbm.o: $(hdrdir)/ruby/internal/core/rdata.h
|
||||
_sdbm.o: $(hdrdir)/ruby/internal/core/rfile.h
|
||||
_sdbm.o: $(hdrdir)/ruby/internal/core/rhash.h
|
||||
_sdbm.o: $(hdrdir)/ruby/internal/core/robject.h
|
||||
_sdbm.o: $(hdrdir)/ruby/internal/core/rregexp.h
|
||||
_sdbm.o: $(hdrdir)/ruby/internal/core/rstring.h
|
||||
_sdbm.o: $(hdrdir)/ruby/internal/core/rstruct.h
|
||||
_sdbm.o: $(hdrdir)/ruby/internal/core/rtypeddata.h
|
||||
_sdbm.o: $(hdrdir)/ruby/internal/ctype.h
|
||||
_sdbm.o: $(hdrdir)/ruby/internal/dllexport.h
|
||||
_sdbm.o: $(hdrdir)/ruby/internal/dosish.h
|
||||
_sdbm.o: $(hdrdir)/ruby/internal/error.h
|
||||
_sdbm.o: $(hdrdir)/ruby/internal/eval.h
|
||||
_sdbm.o: $(hdrdir)/ruby/internal/event.h
|
||||
_sdbm.o: $(hdrdir)/ruby/internal/fl_type.h
|
||||
_sdbm.o: $(hdrdir)/ruby/internal/gc.h
|
||||
_sdbm.o: $(hdrdir)/ruby/internal/glob.h
|
||||
_sdbm.o: $(hdrdir)/ruby/internal/globals.h
|
||||
_sdbm.o: $(hdrdir)/ruby/internal/has/attribute.h
|
||||
_sdbm.o: $(hdrdir)/ruby/internal/has/builtin.h
|
||||
_sdbm.o: $(hdrdir)/ruby/internal/has/c_attribute.h
|
||||
_sdbm.o: $(hdrdir)/ruby/internal/has/cpp_attribute.h
|
||||
_sdbm.o: $(hdrdir)/ruby/internal/has/declspec_attribute.h
|
||||
_sdbm.o: $(hdrdir)/ruby/internal/has/extension.h
|
||||
_sdbm.o: $(hdrdir)/ruby/internal/has/feature.h
|
||||
_sdbm.o: $(hdrdir)/ruby/internal/has/warning.h
|
||||
_sdbm.o: $(hdrdir)/ruby/internal/intern/array.h
|
||||
_sdbm.o: $(hdrdir)/ruby/internal/intern/bignum.h
|
||||
_sdbm.o: $(hdrdir)/ruby/internal/intern/class.h
|
||||
_sdbm.o: $(hdrdir)/ruby/internal/intern/compar.h
|
||||
_sdbm.o: $(hdrdir)/ruby/internal/intern/complex.h
|
||||
_sdbm.o: $(hdrdir)/ruby/internal/intern/cont.h
|
||||
_sdbm.o: $(hdrdir)/ruby/internal/intern/dir.h
|
||||
_sdbm.o: $(hdrdir)/ruby/internal/intern/enum.h
|
||||
_sdbm.o: $(hdrdir)/ruby/internal/intern/enumerator.h
|
||||
_sdbm.o: $(hdrdir)/ruby/internal/intern/error.h
|
||||
_sdbm.o: $(hdrdir)/ruby/internal/intern/eval.h
|
||||
_sdbm.o: $(hdrdir)/ruby/internal/intern/file.h
|
||||
_sdbm.o: $(hdrdir)/ruby/internal/intern/gc.h
|
||||
_sdbm.o: $(hdrdir)/ruby/internal/intern/hash.h
|
||||
_sdbm.o: $(hdrdir)/ruby/internal/intern/io.h
|
||||
_sdbm.o: $(hdrdir)/ruby/internal/intern/load.h
|
||||
_sdbm.o: $(hdrdir)/ruby/internal/intern/marshal.h
|
||||
_sdbm.o: $(hdrdir)/ruby/internal/intern/numeric.h
|
||||
_sdbm.o: $(hdrdir)/ruby/internal/intern/object.h
|
||||
_sdbm.o: $(hdrdir)/ruby/internal/intern/parse.h
|
||||
_sdbm.o: $(hdrdir)/ruby/internal/intern/proc.h
|
||||
_sdbm.o: $(hdrdir)/ruby/internal/intern/process.h
|
||||
_sdbm.o: $(hdrdir)/ruby/internal/intern/random.h
|
||||
_sdbm.o: $(hdrdir)/ruby/internal/intern/range.h
|
||||
_sdbm.o: $(hdrdir)/ruby/internal/intern/rational.h
|
||||
_sdbm.o: $(hdrdir)/ruby/internal/intern/re.h
|
||||
_sdbm.o: $(hdrdir)/ruby/internal/intern/ruby.h
|
||||
_sdbm.o: $(hdrdir)/ruby/internal/intern/select.h
|
||||
_sdbm.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
|
||||
_sdbm.o: $(hdrdir)/ruby/internal/intern/signal.h
|
||||
_sdbm.o: $(hdrdir)/ruby/internal/intern/sprintf.h
|
||||
_sdbm.o: $(hdrdir)/ruby/internal/intern/string.h
|
||||
_sdbm.o: $(hdrdir)/ruby/internal/intern/struct.h
|
||||
_sdbm.o: $(hdrdir)/ruby/internal/intern/thread.h
|
||||
_sdbm.o: $(hdrdir)/ruby/internal/intern/time.h
|
||||
_sdbm.o: $(hdrdir)/ruby/internal/intern/variable.h
|
||||
_sdbm.o: $(hdrdir)/ruby/internal/intern/vm.h
|
||||
_sdbm.o: $(hdrdir)/ruby/internal/interpreter.h
|
||||
_sdbm.o: $(hdrdir)/ruby/internal/iterator.h
|
||||
_sdbm.o: $(hdrdir)/ruby/internal/memory.h
|
||||
_sdbm.o: $(hdrdir)/ruby/internal/method.h
|
||||
_sdbm.o: $(hdrdir)/ruby/internal/module.h
|
||||
_sdbm.o: $(hdrdir)/ruby/internal/newobj.h
|
||||
_sdbm.o: $(hdrdir)/ruby/internal/rgengc.h
|
||||
_sdbm.o: $(hdrdir)/ruby/internal/scan_args.h
|
||||
_sdbm.o: $(hdrdir)/ruby/internal/special_consts.h
|
||||
_sdbm.o: $(hdrdir)/ruby/internal/static_assert.h
|
||||
_sdbm.o: $(hdrdir)/ruby/internal/stdalign.h
|
||||
_sdbm.o: $(hdrdir)/ruby/internal/stdbool.h
|
||||
_sdbm.o: $(hdrdir)/ruby/internal/symbol.h
|
||||
_sdbm.o: $(hdrdir)/ruby/internal/token_paste.h
|
||||
_sdbm.o: $(hdrdir)/ruby/internal/value.h
|
||||
_sdbm.o: $(hdrdir)/ruby/internal/value_type.h
|
||||
_sdbm.o: $(hdrdir)/ruby/internal/variable.h
|
||||
_sdbm.o: $(hdrdir)/ruby/internal/warning_push.h
|
||||
_sdbm.o: $(hdrdir)/ruby/internal/xmalloc.h
|
||||
_sdbm.o: $(hdrdir)/ruby/assert.h
|
||||
_sdbm.o: $(hdrdir)/ruby/backward.h
|
||||
_sdbm.o: $(hdrdir)/ruby/backward/2/assume.h
|
||||
_sdbm.o: $(hdrdir)/ruby/backward/2/attributes.h
|
||||
_sdbm.o: $(hdrdir)/ruby/backward/2/bool.h
|
||||
_sdbm.o: $(hdrdir)/ruby/backward/2/extern.h
|
||||
_sdbm.o: $(hdrdir)/ruby/backward/2/gcc_version_since.h
|
||||
_sdbm.o: $(hdrdir)/ruby/backward/2/inttypes.h
|
||||
_sdbm.o: $(hdrdir)/ruby/backward/2/limits.h
|
||||
_sdbm.o: $(hdrdir)/ruby/backward/2/long_long.h
|
||||
_sdbm.o: $(hdrdir)/ruby/backward/2/r_cast.h
|
||||
_sdbm.o: $(hdrdir)/ruby/backward/2/rmodule.h
|
||||
_sdbm.o: $(hdrdir)/ruby/backward/2/stdalign.h
|
||||
_sdbm.o: $(hdrdir)/ruby/backward/2/stdarg.h
|
||||
_sdbm.o: $(hdrdir)/ruby/defines.h
|
||||
_sdbm.o: $(hdrdir)/ruby/intern.h
|
||||
_sdbm.o: $(hdrdir)/ruby/missing.h
|
||||
_sdbm.o: $(hdrdir)/ruby/ruby.h
|
||||
_sdbm.o: $(hdrdir)/ruby/st.h
|
||||
_sdbm.o: $(hdrdir)/ruby/subst.h
|
||||
_sdbm.o: _sdbm.c
|
||||
_sdbm.o: sdbm.h
|
||||
init.o: $(RUBY_EXTCONF_H)
|
||||
init.o: $(arch_hdrdir)/ruby/config.h
|
||||
init.o: $(hdrdir)/ruby.h
|
||||
init.o: $(hdrdir)/ruby/internal/anyargs.h
|
||||
init.o: $(hdrdir)/ruby/internal/arithmetic.h
|
||||
init.o: $(hdrdir)/ruby/internal/arithmetic/char.h
|
||||
init.o: $(hdrdir)/ruby/internal/arithmetic/double.h
|
||||
init.o: $(hdrdir)/ruby/internal/arithmetic/fixnum.h
|
||||
init.o: $(hdrdir)/ruby/internal/arithmetic/gid_t.h
|
||||
init.o: $(hdrdir)/ruby/internal/arithmetic/int.h
|
||||
init.o: $(hdrdir)/ruby/internal/arithmetic/intptr_t.h
|
||||
init.o: $(hdrdir)/ruby/internal/arithmetic/long.h
|
||||
init.o: $(hdrdir)/ruby/internal/arithmetic/long_long.h
|
||||
init.o: $(hdrdir)/ruby/internal/arithmetic/mode_t.h
|
||||
init.o: $(hdrdir)/ruby/internal/arithmetic/off_t.h
|
||||
init.o: $(hdrdir)/ruby/internal/arithmetic/pid_t.h
|
||||
init.o: $(hdrdir)/ruby/internal/arithmetic/short.h
|
||||
init.o: $(hdrdir)/ruby/internal/arithmetic/size_t.h
|
||||
init.o: $(hdrdir)/ruby/internal/arithmetic/st_data_t.h
|
||||
init.o: $(hdrdir)/ruby/internal/arithmetic/uid_t.h
|
||||
init.o: $(hdrdir)/ruby/internal/assume.h
|
||||
init.o: $(hdrdir)/ruby/internal/attr/alloc_size.h
|
||||
init.o: $(hdrdir)/ruby/internal/attr/artificial.h
|
||||
init.o: $(hdrdir)/ruby/internal/attr/cold.h
|
||||
init.o: $(hdrdir)/ruby/internal/attr/const.h
|
||||
init.o: $(hdrdir)/ruby/internal/attr/constexpr.h
|
||||
init.o: $(hdrdir)/ruby/internal/attr/deprecated.h
|
||||
init.o: $(hdrdir)/ruby/internal/attr/diagnose_if.h
|
||||
init.o: $(hdrdir)/ruby/internal/attr/enum_extensibility.h
|
||||
init.o: $(hdrdir)/ruby/internal/attr/error.h
|
||||
init.o: $(hdrdir)/ruby/internal/attr/flag_enum.h
|
||||
init.o: $(hdrdir)/ruby/internal/attr/forceinline.h
|
||||
init.o: $(hdrdir)/ruby/internal/attr/format.h
|
||||
init.o: $(hdrdir)/ruby/internal/attr/maybe_unused.h
|
||||
init.o: $(hdrdir)/ruby/internal/attr/noalias.h
|
||||
init.o: $(hdrdir)/ruby/internal/attr/nodiscard.h
|
||||
init.o: $(hdrdir)/ruby/internal/attr/noexcept.h
|
||||
init.o: $(hdrdir)/ruby/internal/attr/noinline.h
|
||||
init.o: $(hdrdir)/ruby/internal/attr/nonnull.h
|
||||
init.o: $(hdrdir)/ruby/internal/attr/noreturn.h
|
||||
init.o: $(hdrdir)/ruby/internal/attr/pure.h
|
||||
init.o: $(hdrdir)/ruby/internal/attr/restrict.h
|
||||
init.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
|
||||
init.o: $(hdrdir)/ruby/internal/attr/warning.h
|
||||
init.o: $(hdrdir)/ruby/internal/attr/weakref.h
|
||||
init.o: $(hdrdir)/ruby/internal/cast.h
|
||||
init.o: $(hdrdir)/ruby/internal/compiler_is.h
|
||||
init.o: $(hdrdir)/ruby/internal/compiler_is/apple.h
|
||||
init.o: $(hdrdir)/ruby/internal/compiler_is/clang.h
|
||||
init.o: $(hdrdir)/ruby/internal/compiler_is/gcc.h
|
||||
init.o: $(hdrdir)/ruby/internal/compiler_is/intel.h
|
||||
init.o: $(hdrdir)/ruby/internal/compiler_is/msvc.h
|
||||
init.o: $(hdrdir)/ruby/internal/compiler_is/sunpro.h
|
||||
init.o: $(hdrdir)/ruby/internal/compiler_since.h
|
||||
init.o: $(hdrdir)/ruby/internal/config.h
|
||||
init.o: $(hdrdir)/ruby/internal/constant_p.h
|
||||
init.o: $(hdrdir)/ruby/internal/core.h
|
||||
init.o: $(hdrdir)/ruby/internal/core/rarray.h
|
||||
init.o: $(hdrdir)/ruby/internal/core/rbasic.h
|
||||
init.o: $(hdrdir)/ruby/internal/core/rbignum.h
|
||||
init.o: $(hdrdir)/ruby/internal/core/rclass.h
|
||||
init.o: $(hdrdir)/ruby/internal/core/rdata.h
|
||||
init.o: $(hdrdir)/ruby/internal/core/rfile.h
|
||||
init.o: $(hdrdir)/ruby/internal/core/rhash.h
|
||||
init.o: $(hdrdir)/ruby/internal/core/robject.h
|
||||
init.o: $(hdrdir)/ruby/internal/core/rregexp.h
|
||||
init.o: $(hdrdir)/ruby/internal/core/rstring.h
|
||||
init.o: $(hdrdir)/ruby/internal/core/rstruct.h
|
||||
init.o: $(hdrdir)/ruby/internal/core/rtypeddata.h
|
||||
init.o: $(hdrdir)/ruby/internal/ctype.h
|
||||
init.o: $(hdrdir)/ruby/internal/dllexport.h
|
||||
init.o: $(hdrdir)/ruby/internal/dosish.h
|
||||
init.o: $(hdrdir)/ruby/internal/error.h
|
||||
init.o: $(hdrdir)/ruby/internal/eval.h
|
||||
init.o: $(hdrdir)/ruby/internal/event.h
|
||||
init.o: $(hdrdir)/ruby/internal/fl_type.h
|
||||
init.o: $(hdrdir)/ruby/internal/gc.h
|
||||
init.o: $(hdrdir)/ruby/internal/glob.h
|
||||
init.o: $(hdrdir)/ruby/internal/globals.h
|
||||
init.o: $(hdrdir)/ruby/internal/has/attribute.h
|
||||
init.o: $(hdrdir)/ruby/internal/has/builtin.h
|
||||
init.o: $(hdrdir)/ruby/internal/has/c_attribute.h
|
||||
init.o: $(hdrdir)/ruby/internal/has/cpp_attribute.h
|
||||
init.o: $(hdrdir)/ruby/internal/has/declspec_attribute.h
|
||||
init.o: $(hdrdir)/ruby/internal/has/extension.h
|
||||
init.o: $(hdrdir)/ruby/internal/has/feature.h
|
||||
init.o: $(hdrdir)/ruby/internal/has/warning.h
|
||||
init.o: $(hdrdir)/ruby/internal/intern/array.h
|
||||
init.o: $(hdrdir)/ruby/internal/intern/bignum.h
|
||||
init.o: $(hdrdir)/ruby/internal/intern/class.h
|
||||
init.o: $(hdrdir)/ruby/internal/intern/compar.h
|
||||
init.o: $(hdrdir)/ruby/internal/intern/complex.h
|
||||
init.o: $(hdrdir)/ruby/internal/intern/cont.h
|
||||
init.o: $(hdrdir)/ruby/internal/intern/dir.h
|
||||
init.o: $(hdrdir)/ruby/internal/intern/enum.h
|
||||
init.o: $(hdrdir)/ruby/internal/intern/enumerator.h
|
||||
init.o: $(hdrdir)/ruby/internal/intern/error.h
|
||||
init.o: $(hdrdir)/ruby/internal/intern/eval.h
|
||||
init.o: $(hdrdir)/ruby/internal/intern/file.h
|
||||
init.o: $(hdrdir)/ruby/internal/intern/gc.h
|
||||
init.o: $(hdrdir)/ruby/internal/intern/hash.h
|
||||
init.o: $(hdrdir)/ruby/internal/intern/io.h
|
||||
init.o: $(hdrdir)/ruby/internal/intern/load.h
|
||||
init.o: $(hdrdir)/ruby/internal/intern/marshal.h
|
||||
init.o: $(hdrdir)/ruby/internal/intern/numeric.h
|
||||
init.o: $(hdrdir)/ruby/internal/intern/object.h
|
||||
init.o: $(hdrdir)/ruby/internal/intern/parse.h
|
||||
init.o: $(hdrdir)/ruby/internal/intern/proc.h
|
||||
init.o: $(hdrdir)/ruby/internal/intern/process.h
|
||||
init.o: $(hdrdir)/ruby/internal/intern/random.h
|
||||
init.o: $(hdrdir)/ruby/internal/intern/range.h
|
||||
init.o: $(hdrdir)/ruby/internal/intern/rational.h
|
||||
init.o: $(hdrdir)/ruby/internal/intern/re.h
|
||||
init.o: $(hdrdir)/ruby/internal/intern/ruby.h
|
||||
init.o: $(hdrdir)/ruby/internal/intern/select.h
|
||||
init.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
|
||||
init.o: $(hdrdir)/ruby/internal/intern/signal.h
|
||||
init.o: $(hdrdir)/ruby/internal/intern/sprintf.h
|
||||
init.o: $(hdrdir)/ruby/internal/intern/string.h
|
||||
init.o: $(hdrdir)/ruby/internal/intern/struct.h
|
||||
init.o: $(hdrdir)/ruby/internal/intern/thread.h
|
||||
init.o: $(hdrdir)/ruby/internal/intern/time.h
|
||||
init.o: $(hdrdir)/ruby/internal/intern/variable.h
|
||||
init.o: $(hdrdir)/ruby/internal/intern/vm.h
|
||||
init.o: $(hdrdir)/ruby/internal/interpreter.h
|
||||
init.o: $(hdrdir)/ruby/internal/iterator.h
|
||||
init.o: $(hdrdir)/ruby/internal/memory.h
|
||||
init.o: $(hdrdir)/ruby/internal/method.h
|
||||
init.o: $(hdrdir)/ruby/internal/module.h
|
||||
init.o: $(hdrdir)/ruby/internal/newobj.h
|
||||
init.o: $(hdrdir)/ruby/internal/rgengc.h
|
||||
init.o: $(hdrdir)/ruby/internal/scan_args.h
|
||||
init.o: $(hdrdir)/ruby/internal/special_consts.h
|
||||
init.o: $(hdrdir)/ruby/internal/static_assert.h
|
||||
init.o: $(hdrdir)/ruby/internal/stdalign.h
|
||||
init.o: $(hdrdir)/ruby/internal/stdbool.h
|
||||
init.o: $(hdrdir)/ruby/internal/symbol.h
|
||||
init.o: $(hdrdir)/ruby/internal/token_paste.h
|
||||
init.o: $(hdrdir)/ruby/internal/value.h
|
||||
init.o: $(hdrdir)/ruby/internal/value_type.h
|
||||
init.o: $(hdrdir)/ruby/internal/variable.h
|
||||
init.o: $(hdrdir)/ruby/internal/warning_push.h
|
||||
init.o: $(hdrdir)/ruby/internal/xmalloc.h
|
||||
init.o: $(hdrdir)/ruby/assert.h
|
||||
init.o: $(hdrdir)/ruby/backward.h
|
||||
init.o: $(hdrdir)/ruby/backward/2/assume.h
|
||||
init.o: $(hdrdir)/ruby/backward/2/attributes.h
|
||||
init.o: $(hdrdir)/ruby/backward/2/bool.h
|
||||
init.o: $(hdrdir)/ruby/backward/2/extern.h
|
||||
init.o: $(hdrdir)/ruby/backward/2/gcc_version_since.h
|
||||
init.o: $(hdrdir)/ruby/backward/2/inttypes.h
|
||||
init.o: $(hdrdir)/ruby/backward/2/limits.h
|
||||
init.o: $(hdrdir)/ruby/backward/2/long_long.h
|
||||
init.o: $(hdrdir)/ruby/backward/2/r_cast.h
|
||||
init.o: $(hdrdir)/ruby/backward/2/rmodule.h
|
||||
init.o: $(hdrdir)/ruby/backward/2/stdalign.h
|
||||
init.o: $(hdrdir)/ruby/backward/2/stdarg.h
|
||||
init.o: $(hdrdir)/ruby/defines.h
|
||||
init.o: $(hdrdir)/ruby/intern.h
|
||||
init.o: $(hdrdir)/ruby/missing.h
|
||||
init.o: $(hdrdir)/ruby/ruby.h
|
||||
init.o: $(hdrdir)/ruby/st.h
|
||||
init.o: $(hdrdir)/ruby/subst.h
|
||||
init.o: init.c
|
||||
init.o: sdbm.h
|
||||
# AUTOGENERATED DEPENDENCIES END
|
|
@ -1,5 +0,0 @@
|
|||
# frozen_string_literal: false
|
||||
require 'mkmf'
|
||||
|
||||
$defs << "-D""BADMESS=0"
|
||||
create_makefile("sdbm")
|
1067
ext/sdbm/init.c
1067
ext/sdbm/init.c
File diff suppressed because it is too large
Load diff
|
@ -1,21 +0,0 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
Gem::Specification.new do |s|
|
||||
s.name = "sdbm"
|
||||
s.version = '1.0.0'
|
||||
s.summary = "Provides a simple file-based key-value store with String keys and values."
|
||||
s.description = "Provides a simple file-based key-value store with String keys and values."
|
||||
|
||||
s.require_path = %w{lib}
|
||||
s.files = %w{ext/sdbm/_sdbm.c ext/sdbm/extconf.rb ext/sdbm/init.c ext/sdbm/sdbm.h}
|
||||
s.extensions = ["ext/sdbm/extconf.rb"]
|
||||
s.required_ruby_version = ">= 2.3.0"
|
||||
|
||||
s.authors = ["Yukihiro Matsumoto"]
|
||||
s.email = ["matz@ruby-lang.org"]
|
||||
s.homepage = "https://github.com/ruby/sdbm"
|
||||
s.license = "BSD-2-Clause"
|
||||
|
||||
s.add_development_dependency "test-unit"
|
||||
s.add_development_dependency "rake-compiler"
|
||||
end
|
|
@ -1,86 +0,0 @@
|
|||
/*
|
||||
* sdbm - ndbm work-alike hashed database library
|
||||
* based on Per-Ake Larson's Dynamic Hashing algorithms. BIT 18 (1978).
|
||||
* author: oz@nexus.yorku.ca
|
||||
* status: public domain.
|
||||
*/
|
||||
#ifndef _SDBM_H_
|
||||
#define _SDBM_H_
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#define DBLKSIZ 4096
|
||||
#define PBLKSIZ 1024
|
||||
#define PAIRMAX 1008 /* arbitrary on PBLKSIZ-N */
|
||||
#define SPLTMAX 10 /* maximum allowed splits */
|
||||
/* for a single insertion */
|
||||
#define DIRFEXT ".dir"
|
||||
#define PAGFEXT ".pag"
|
||||
|
||||
typedef struct {
|
||||
int dirf; /* directory file descriptor */
|
||||
int pagf; /* page file descriptor */
|
||||
int flags; /* status/error flags, see below */
|
||||
int keyptr; /* current key for nextkey */
|
||||
off_t maxbno; /* size of dirfile in bits */
|
||||
long curbit; /* current bit number */
|
||||
long hmask; /* current hash mask */
|
||||
long blkptr; /* current block for nextkey */
|
||||
long blkno; /* current page to read/write */
|
||||
long pagbno; /* current page in pagbuf */
|
||||
char pagbuf[PBLKSIZ]; /* page file block buffer */
|
||||
long dirbno; /* current block in dirbuf */
|
||||
char dirbuf[DBLKSIZ]; /* directory file block buffer */
|
||||
} DBM;
|
||||
|
||||
#define DBM_RDONLY 0x1 /* data base open read-only */
|
||||
#define DBM_IOERR 0x2 /* data base I/O error */
|
||||
|
||||
/*
|
||||
* utility macros
|
||||
*/
|
||||
#define sdbm_rdonly(db) ((db)->flags & DBM_RDONLY)
|
||||
#define sdbm_error(db) ((db)->flags & DBM_IOERR)
|
||||
|
||||
#define sdbm_clearerr(db) ((db)->flags &= ~DBM_IOERR) /* ouch */
|
||||
|
||||
#define sdbm_dirfno(db) ((db)->dirf)
|
||||
#define sdbm_pagfno(db) ((db)->pagf)
|
||||
|
||||
typedef struct {
|
||||
char *dptr;
|
||||
int dsize;
|
||||
} datum;
|
||||
|
||||
extern datum nullitem;
|
||||
|
||||
#if defined(__STDC__)
|
||||
#define proto(p) p
|
||||
#else
|
||||
#define proto(p) ()
|
||||
#endif
|
||||
|
||||
/*
|
||||
* flags to sdbm_store
|
||||
*/
|
||||
#define DBM_INSERT 0
|
||||
#define DBM_REPLACE 1
|
||||
|
||||
/*
|
||||
* ndbm interface
|
||||
*/
|
||||
extern DBM *sdbm_open proto((char *, int, int));
|
||||
extern void sdbm_close proto((DBM *));
|
||||
extern datum sdbm_fetch proto((DBM *, datum));
|
||||
extern int sdbm_delete proto((DBM *, datum));
|
||||
extern int sdbm_store proto((DBM *, datum, datum, int));
|
||||
extern datum sdbm_firstkey proto((DBM *));
|
||||
extern datum sdbm_nextkey proto((DBM *));
|
||||
|
||||
/*
|
||||
* other
|
||||
*/
|
||||
extern DBM *sdbm_prep proto((char *, char *, int, int));
|
||||
extern long sdbm_hash proto((char *, int));
|
||||
|
||||
#endif /* _SDBM_H_ */
|
|
@ -1,544 +0,0 @@
|
|||
# frozen_string_literal: false
|
||||
require 'test/unit'
|
||||
require 'tmpdir'
|
||||
|
||||
begin
|
||||
require 'sdbm'
|
||||
rescue LoadError
|
||||
end
|
||||
|
||||
class TestSDBM < Test::Unit::TestCase
|
||||
def setup
|
||||
@tmpdir = Dir.mktmpdir("tmptest_sdbm")
|
||||
@prefix = "tmptest_sdbm_#{$$}"
|
||||
@path = "#{@tmpdir}/#{@prefix}_"
|
||||
assert_instance_of(SDBM, @sdbm = SDBM.new(@path))
|
||||
end
|
||||
def teardown
|
||||
assert_nil(@sdbm.close)
|
||||
ObjectSpace.each_object(SDBM) do |obj|
|
||||
obj.close unless obj.closed?
|
||||
end
|
||||
FileUtils.remove_entry_secure @tmpdir
|
||||
end
|
||||
|
||||
def check_size(expect, sdbm=@sdbm)
|
||||
assert_equal(expect, sdbm.size)
|
||||
n = 0
|
||||
sdbm.each { n+=1 }
|
||||
assert_equal(expect, n)
|
||||
if expect == 0
|
||||
assert_equal(true, sdbm.empty?)
|
||||
else
|
||||
assert_equal(false, sdbm.empty?)
|
||||
end
|
||||
end
|
||||
|
||||
def test_version
|
||||
assert(! SDBM.const_defined?(:VERSION))
|
||||
end
|
||||
|
||||
def test_s_new_has_no_block
|
||||
# SDBM.new ignore the block
|
||||
foo = true
|
||||
assert_instance_of(SDBM, sdbm = SDBM.new("#{@tmpdir}/#{@prefix}") { foo = false })
|
||||
assert_equal(foo, true)
|
||||
assert_nil(sdbm.close)
|
||||
end
|
||||
def test_s_open_no_create
|
||||
assert_nil(sdbm = SDBM.open("#{@tmpdir}/#{@prefix}", nil))
|
||||
ensure
|
||||
sdbm.close if sdbm
|
||||
end
|
||||
def test_s_open_with_block
|
||||
assert_equal(SDBM.open("#{@tmpdir}/#{@prefix}") { :foo }, :foo)
|
||||
end
|
||||
=begin
|
||||
# Is it guaranteed on many OS?
|
||||
def test_s_open_lock_one_process
|
||||
# locking on one process
|
||||
assert_instance_of(SDBM, sdbm = SDBM.open("#{@tmpdir}/#{@prefix}", 0644))
|
||||
assert_raise(Errno::EWOULDBLOCK) {
|
||||
begin
|
||||
SDBM.open("#{@tmpdir}/#{@prefix}", 0644)
|
||||
rescue Errno::EAGAIN
|
||||
raise Errno::EWOULDBLOCK
|
||||
end
|
||||
}
|
||||
end
|
||||
=end
|
||||
|
||||
def open_db_child(dbname, *opts)
|
||||
opts = [0644, *opts].map(&:inspect).join(', ')
|
||||
args = [EnvUtil.rubybin, "-rsdbm", <<-SRC, dbname]
|
||||
STDOUT.sync = true
|
||||
gdbm = SDBM.open(ARGV.shift, #{opts})
|
||||
puts sdbm.class
|
||||
gets
|
||||
SRC
|
||||
IO.popen(args, "r+") do |f|
|
||||
dbclass = f.gets
|
||||
assert_equal("SDBM", dbclass.chomp)
|
||||
yield
|
||||
end
|
||||
end
|
||||
|
||||
def test_s_open_nolock
|
||||
dbname = "#{@tmpdir}/#{@prefix}"
|
||||
|
||||
open_db_child(dbname, SDBM::NOLOCK) do
|
||||
assert_no_exception(Errno::EWOULDBLOCK, Errno::EAGAIN, Errno::EACCES) {
|
||||
SDBM.open(dbname, 0644) {|sdbm|
|
||||
assert_instance_of(SDBM, sdbm)
|
||||
}
|
||||
}
|
||||
end
|
||||
|
||||
p Dir.glob("#{@tmpdir}/#{@prefix}*") if $DEBUG
|
||||
|
||||
open_db_child(dbname) do
|
||||
assert_no_exception(Errno::EWOULDBLOCK, Errno::EAGAIN, Errno::EACCES) {
|
||||
# this test is failed on Cygwin98 (???)
|
||||
SDBM.open(dbname, 0644, SDBM::NOLOCK) {|sdbm|
|
||||
assert_instance_of(SDBM, sdbm)
|
||||
}
|
||||
}
|
||||
end
|
||||
end if defined? SDBM::NOLOCK # sdbm 1.8.0 specific
|
||||
|
||||
def test_s_open_error
|
||||
skip "doesn't support to avoid read access by owner on Windows" if /mswin|mingw/ =~ RUBY_PLATFORM
|
||||
skip "skipped because root can open anything" if Process.uid == 0
|
||||
assert_instance_of(SDBM, sdbm = SDBM.open("#{@tmpdir}/#{@prefix}", 0))
|
||||
assert_raise(Errno::EACCES) {
|
||||
SDBM.open("#{@tmpdir}/#{@prefix}", 0)
|
||||
}
|
||||
sdbm.close
|
||||
end
|
||||
|
||||
def test_close
|
||||
assert_instance_of(SDBM, sdbm = SDBM.open("#{@tmpdir}/#{@prefix}"))
|
||||
assert_nil(sdbm.close)
|
||||
|
||||
# closed SDBM file
|
||||
assert_raise(SDBMError) { sdbm.close }
|
||||
end
|
||||
|
||||
def test_aref
|
||||
assert_equal('bar', @sdbm['foo'] = 'bar')
|
||||
assert_equal('bar', @sdbm['foo'])
|
||||
|
||||
assert_nil(@sdbm['bar'])
|
||||
end
|
||||
|
||||
def test_fetch
|
||||
assert_equal('bar', @sdbm['foo']='bar')
|
||||
assert_equal('bar', @sdbm.fetch('foo'))
|
||||
|
||||
# key not found
|
||||
assert_raise(IndexError) {
|
||||
@sdbm.fetch('bar')
|
||||
}
|
||||
|
||||
# test for `ifnone' arg
|
||||
assert_equal('baz', @sdbm.fetch('bar', 'baz'))
|
||||
|
||||
# test for `ifnone' block
|
||||
assert_equal('foobar', @sdbm.fetch('bar') {|key| 'foo' + key })
|
||||
end
|
||||
|
||||
def test_aset
|
||||
num = 0
|
||||
2.times {|i|
|
||||
assert_equal('foo', @sdbm['foo'] = 'foo')
|
||||
assert_equal('foo', @sdbm['foo'])
|
||||
assert_equal('bar', @sdbm['foo'] = 'bar')
|
||||
assert_equal('bar', @sdbm['foo'])
|
||||
|
||||
num += 1 if i == 0
|
||||
assert_equal(num, @sdbm.size)
|
||||
|
||||
# assign nil
|
||||
assert_equal('', @sdbm['bar'] = '')
|
||||
assert_equal('', @sdbm['bar'])
|
||||
|
||||
num += 1 if i == 0
|
||||
assert_equal(num, @sdbm.size)
|
||||
|
||||
# empty string
|
||||
assert_equal('', @sdbm[''] = '')
|
||||
assert_equal('', @sdbm[''])
|
||||
|
||||
num += 1 if i == 0
|
||||
assert_equal(num, @sdbm.size)
|
||||
|
||||
# Integer
|
||||
assert_equal('200', @sdbm['100'] = '200')
|
||||
assert_equal('200', @sdbm['100'])
|
||||
|
||||
num += 1 if i == 0
|
||||
assert_equal(num, @sdbm.size)
|
||||
|
||||
# Big key and value
|
||||
assert_equal('y' * 100, @sdbm['x' * 100] = 'y' * 100)
|
||||
assert_equal('y' * 100, @sdbm['x' * 100])
|
||||
|
||||
num += 1 if i == 0
|
||||
assert_equal(num, @sdbm.size)
|
||||
}
|
||||
end
|
||||
|
||||
def test_key
|
||||
assert_equal('bar', @sdbm['foo'] = 'bar')
|
||||
assert_equal('foo', @sdbm.key('bar'))
|
||||
assert_nil(@sdbm['bar'])
|
||||
end
|
||||
|
||||
def test_values_at
|
||||
keys = %w(foo bar baz)
|
||||
values = %w(FOO BAR BAZ)
|
||||
@sdbm[keys[0]], @sdbm[keys[1]], @sdbm[keys[2]] = values
|
||||
assert_equal(values.reverse, @sdbm.values_at(*keys.reverse))
|
||||
end
|
||||
|
||||
def test_select_with_block
|
||||
keys = %w(foo bar baz)
|
||||
values = %w(FOO BAR BAZ)
|
||||
@sdbm[keys[0]], @sdbm[keys[1]], @sdbm[keys[2]] = values
|
||||
ret = @sdbm.select {|k,v|
|
||||
assert_equal(k.upcase, v)
|
||||
k != "bar"
|
||||
}
|
||||
assert_equal([['baz', 'BAZ'], ['foo', 'FOO']],
|
||||
ret.sort)
|
||||
end
|
||||
|
||||
def test_length
|
||||
num = 10
|
||||
assert_equal(0, @sdbm.size)
|
||||
num.times {|i|
|
||||
i = i.to_s
|
||||
@sdbm[i] = i
|
||||
}
|
||||
assert_equal(num, @sdbm.size)
|
||||
|
||||
@sdbm.shift
|
||||
|
||||
assert_equal(num - 1, @sdbm.size)
|
||||
end
|
||||
|
||||
def test_empty?
|
||||
assert_equal(true, @sdbm.empty?)
|
||||
@sdbm['foo'] = 'FOO'
|
||||
assert_equal(false, @sdbm.empty?)
|
||||
end
|
||||
|
||||
def test_each_pair
|
||||
n = 0
|
||||
@sdbm.each_pair { n += 1 }
|
||||
assert_equal(0, n)
|
||||
|
||||
keys = %w(foo bar baz)
|
||||
values = %w(FOO BAR BAZ)
|
||||
|
||||
@sdbm[keys[0]], @sdbm[keys[1]], @sdbm[keys[2]] = values
|
||||
|
||||
n = 0
|
||||
ret = @sdbm.each_pair {|key, val|
|
||||
assert_not_nil(i = keys.index(key))
|
||||
assert_equal(val, values[i])
|
||||
|
||||
n += 1
|
||||
}
|
||||
assert_equal(keys.size, n)
|
||||
assert_equal(@sdbm, ret)
|
||||
end
|
||||
|
||||
def test_each_value
|
||||
n = 0
|
||||
@sdbm.each_value { n += 1 }
|
||||
assert_equal(0, n)
|
||||
|
||||
keys = %w(foo bar baz)
|
||||
values = %w(FOO BAR BAZ)
|
||||
|
||||
@sdbm[keys[0]], @sdbm[keys[1]], @sdbm[keys[2]] = values
|
||||
|
||||
n = 0
|
||||
ret = @sdbm.each_value {|val|
|
||||
assert_not_nil(key = @sdbm.key(val))
|
||||
assert_not_nil(i = keys.index(key))
|
||||
assert_equal(val, values[i])
|
||||
|
||||
n += 1
|
||||
}
|
||||
assert_equal(keys.size, n)
|
||||
assert_equal(@sdbm, ret)
|
||||
end
|
||||
|
||||
def test_each_key
|
||||
n = 0
|
||||
@sdbm.each_key { n += 1 }
|
||||
assert_equal(0, n)
|
||||
|
||||
keys = %w(foo bar baz)
|
||||
values = %w(FOO BAR BAZ)
|
||||
|
||||
@sdbm[keys[0]], @sdbm[keys[1]], @sdbm[keys[2]] = values
|
||||
|
||||
n = 0
|
||||
ret = @sdbm.each_key {|key|
|
||||
assert_not_nil(i = keys.index(key))
|
||||
assert_equal(@sdbm[key], values[i])
|
||||
|
||||
n += 1
|
||||
}
|
||||
assert_equal(keys.size, n)
|
||||
assert_equal(@sdbm, ret)
|
||||
end
|
||||
|
||||
def test_keys
|
||||
assert_equal([], @sdbm.keys)
|
||||
|
||||
keys = %w(foo bar baz)
|
||||
values = %w(FOO BAR BAZ)
|
||||
|
||||
@sdbm[keys[0]], @sdbm[keys[1]], @sdbm[keys[2]] = values
|
||||
|
||||
assert_equal(keys.sort, @sdbm.keys.sort)
|
||||
assert_equal(values.sort, @sdbm.values.sort)
|
||||
end
|
||||
|
||||
def test_values
|
||||
test_keys
|
||||
end
|
||||
|
||||
def test_shift
|
||||
assert_nil(@sdbm.shift)
|
||||
assert_equal(0, @sdbm.size)
|
||||
|
||||
keys = %w(foo bar baz)
|
||||
values = %w(FOO BAR BAZ)
|
||||
|
||||
@sdbm[keys[0]], @sdbm[keys[1]], @sdbm[keys[2]] = values
|
||||
|
||||
ret_keys = []
|
||||
ret_values = []
|
||||
while ret = @sdbm.shift
|
||||
ret_keys.push ret[0]
|
||||
ret_values.push ret[1]
|
||||
|
||||
assert_equal(keys.size - ret_keys.size, @sdbm.size)
|
||||
end
|
||||
|
||||
assert_equal(keys.sort, ret_keys.sort)
|
||||
assert_equal(values.sort, ret_values.sort)
|
||||
end
|
||||
|
||||
def test_delete
|
||||
keys = %w(foo bar baz)
|
||||
values = %w(FOO BAR BAZ)
|
||||
key = keys[1]
|
||||
|
||||
assert_nil(@sdbm.delete(key))
|
||||
assert_equal(0, @sdbm.size)
|
||||
|
||||
@sdbm[keys[0]], @sdbm[keys[1]], @sdbm[keys[2]] = values
|
||||
|
||||
assert_equal('BAR', @sdbm.delete(key))
|
||||
assert_nil(@sdbm[key])
|
||||
assert_equal(2, @sdbm.size)
|
||||
|
||||
assert_nil(@sdbm.delete(key))
|
||||
end
|
||||
def test_delete_with_block
|
||||
key = 'no called block'
|
||||
@sdbm[key] = 'foo'
|
||||
assert_equal('foo', @sdbm.delete(key) {|k| k.replace 'called block'; :blockval})
|
||||
assert_equal(0, @sdbm.size)
|
||||
|
||||
key = 'no called block'
|
||||
assert_equal(:blockval, @sdbm.delete(key) {|k| k.replace 'called block'; :blockval})
|
||||
assert_equal(0, @sdbm.size)
|
||||
end
|
||||
|
||||
def test_delete_if
|
||||
v = "0"
|
||||
100.times {@sdbm[v] = v; v = v.next}
|
||||
|
||||
ret = @sdbm.delete_if {|key, val| key.to_i < 50}
|
||||
assert_equal(@sdbm, ret)
|
||||
check_size(50, @sdbm)
|
||||
|
||||
ret = @sdbm.delete_if {|key, val| key.to_i >= 50}
|
||||
assert_equal(@sdbm, ret)
|
||||
check_size(0, @sdbm)
|
||||
|
||||
# break
|
||||
v = "0"
|
||||
100.times {@sdbm[v] = v; v = v.next}
|
||||
check_size(100, @sdbm)
|
||||
n = 0;
|
||||
@sdbm.delete_if {|key, val|
|
||||
break if n > 50
|
||||
n+=1
|
||||
true
|
||||
}
|
||||
assert_equal(51, n)
|
||||
check_size(49, @sdbm)
|
||||
|
||||
@sdbm.clear
|
||||
|
||||
# raise
|
||||
v = "0"
|
||||
100.times {@sdbm[v] = v; v = v.next}
|
||||
check_size(100, @sdbm)
|
||||
n = 0;
|
||||
begin
|
||||
@sdbm.delete_if {|key, val|
|
||||
raise "runtime error" if n > 50
|
||||
n+=1
|
||||
true
|
||||
}
|
||||
rescue RuntimeError
|
||||
end
|
||||
assert_equal(51, n)
|
||||
check_size(49, @sdbm)
|
||||
end
|
||||
|
||||
def test_reject
|
||||
v = "0"
|
||||
100.times {@sdbm[v] = v; v = v.next}
|
||||
|
||||
hash = @sdbm.reject {|key, val| key.to_i < 50}
|
||||
assert_instance_of(Hash, hash)
|
||||
assert_equal(100, @sdbm.size)
|
||||
|
||||
assert_equal(50, hash.size)
|
||||
hash.each_pair {|key,val|
|
||||
assert_equal(false, key.to_i < 50)
|
||||
assert_equal(key, val)
|
||||
}
|
||||
|
||||
hash = @sdbm.reject {|key, val| key.to_i < 100}
|
||||
assert_instance_of(Hash, hash)
|
||||
assert_equal(true, hash.empty?)
|
||||
end
|
||||
|
||||
def test_clear
|
||||
v = "1"
|
||||
100.times {v = v.next; @sdbm[v] = v}
|
||||
|
||||
assert_equal(@sdbm, @sdbm.clear)
|
||||
|
||||
# validate SDBM#size
|
||||
i = 0
|
||||
@sdbm.each { i += 1 }
|
||||
assert_equal(@sdbm.size, i)
|
||||
assert_equal(0, i)
|
||||
end
|
||||
|
||||
def test_invert
|
||||
v = "0"
|
||||
100.times {@sdbm[v] = v; v = v.next}
|
||||
|
||||
hash = @sdbm.invert
|
||||
assert_instance_of(Hash, hash)
|
||||
assert_equal(100, hash.size)
|
||||
hash.each_pair {|key, val|
|
||||
assert_equal(key.to_i, val.to_i)
|
||||
}
|
||||
end
|
||||
|
||||
def test_update
|
||||
hash = {}
|
||||
v = "0"
|
||||
100.times {v = v.next; hash[v] = v}
|
||||
|
||||
@sdbm["101"] = "101"
|
||||
@sdbm.update hash
|
||||
assert_equal(101, @sdbm.size)
|
||||
@sdbm.each_pair {|key, val|
|
||||
assert_equal(key.to_i, val.to_i)
|
||||
}
|
||||
end
|
||||
|
||||
def test_replace
|
||||
hash = {}
|
||||
v = "0"
|
||||
100.times {v = v.next; hash[v] = v}
|
||||
|
||||
@sdbm["101"] = "101"
|
||||
@sdbm.replace hash
|
||||
assert_equal(100, @sdbm.size)
|
||||
@sdbm.each_pair {|key, val|
|
||||
assert_equal(key.to_i, val.to_i)
|
||||
}
|
||||
end
|
||||
|
||||
def test_haskey?
|
||||
assert_equal('bar', @sdbm['foo']='bar')
|
||||
assert_equal(true, @sdbm.has_key?('foo'))
|
||||
assert_equal(false, @sdbm.has_key?('bar'))
|
||||
end
|
||||
|
||||
def test_has_value?
|
||||
assert_equal('bar', @sdbm['foo']='bar')
|
||||
assert_equal(true, @sdbm.has_value?('bar'))
|
||||
assert_equal(false, @sdbm.has_value?('foo'))
|
||||
end
|
||||
|
||||
def test_to_a
|
||||
v = "0"
|
||||
100.times {v = v.next; @sdbm[v] = v}
|
||||
|
||||
ary = @sdbm.to_a
|
||||
assert_instance_of(Array, ary)
|
||||
assert_equal(100, ary.size)
|
||||
ary.each {|key,val|
|
||||
assert_equal(key.to_i, val.to_i)
|
||||
}
|
||||
end
|
||||
|
||||
def test_to_hash
|
||||
v = "0"
|
||||
100.times {v = v.next; @sdbm[v] = v}
|
||||
|
||||
hash = @sdbm.to_hash
|
||||
assert_instance_of(Hash, hash)
|
||||
assert_equal(100, hash.size)
|
||||
hash.each {|key,val|
|
||||
assert_equal(key.to_i, val.to_i)
|
||||
}
|
||||
end
|
||||
|
||||
def test_closed
|
||||
assert_equal(false, @sdbm.closed?)
|
||||
@sdbm.close
|
||||
assert_equal(true, @sdbm.closed?)
|
||||
@sdbm = SDBM.new(@path)
|
||||
end
|
||||
|
||||
def test_readonly
|
||||
skip "skipped because root can read anything" if /mswin|mingw/ !~ RUBY_PLATFORM && Process.uid == 0
|
||||
@sdbm["bar"] = "baz"
|
||||
@sdbm.close
|
||||
File.chmod(0444, @path + ".dir")
|
||||
File.chmod(0444, @path + ".pag")
|
||||
@sdbm = SDBM.new(@path)
|
||||
assert_raise(SDBMError) { @sdbm["bar"] = "foo" }
|
||||
assert_raise(SDBMError) { @sdbm.delete("bar") }
|
||||
assert_raise(SDBMError) { @sdbm.delete_if { true } }
|
||||
assert_raise(SDBMError) { @sdbm.clear }
|
||||
assert_nil(@sdbm.store("bar", nil))
|
||||
end
|
||||
|
||||
def test_update2
|
||||
obj = Object.new
|
||||
def obj.each_pair
|
||||
yield []
|
||||
end
|
||||
assert_raise(ArgumentError) { @sdbm.update(obj) }
|
||||
end
|
||||
end if defined? SDBM
|
||||
|
Loading…
Add table
Reference in a new issue