/* * Test mf_hash_*() functions. */ static void test_mf_hash() { mf_hashtab_T ht; mf_hashitem_T *item; blocknr_T key; long_u i; long_u num_buckets; mf_hash_init(&ht); /* insert some items and check invariants */ for (i = 0; i < TEST_COUNT; i++) { assert(ht.mht_count == i); /* check that number of buckets is a power of 2 */ num_buckets = ht.mht_mask + 1; assert(num_buckets > 0 && (num_buckets & (num_buckets - 1)) == 0); /* check load factor */ assert(ht.mht_count <= (num_buckets << MHT_LOG_LOAD_FACTOR)); if (i < (MHT_INIT_SIZE << MHT_LOG_LOAD_FACTOR)) { /* first expansion shouldn't have occurred yet */ assert(num_buckets == MHT_INIT_SIZE); assert(ht.mht_buckets == ht.mht_small_buckets); } else { assert(num_buckets > MHT_INIT_SIZE); assert(ht.mht_buckets != ht.mht_small_buckets); } key = index_to_key(i); assert(mf_hash_find(&ht, key) == NULL); /* allocate and add new item */ item = (mf_hashitem_T *)lalloc_clear(sizeof(mf_hashtab_T), FALSE); assert(item != NULL); item->mhi_key = key; mf_hash_add_item(&ht, item); assert(mf_hash_find(&ht, key) == item); if (ht.mht_mask + 1 != num_buckets) { /* hash table was expanded */ assert(ht.mht_mask + 1 == num_buckets * MHT_GROWTH_FACTOR); assert(i + 1 == (num_buckets << MHT_LOG_LOAD_FACTOR)); } } /* check presence of inserted items */ for (i = 0; i < TEST_COUNT; i++) { key = index_to_key(i); item = mf_hash_find(&ht, key); assert(item != NULL); assert(item->mhi_key == key); } /* delete some items */ for (i = 0; i < TEST_COUNT; i++) { if (i % 100 < 70) { key = index_to_key(i); item = mf_hash_find(&ht, key); assert(item != NULL); assert(item->mhi_key == key); mf_hash_rem_item(&ht, item); assert(mf_hash_find(&ht, key) == NULL); mf_hash_add_item(&ht, item); assert(mf_hash_find(&ht, key) == item); mf_hash_rem_item(&ht, item); assert(mf_hash_find(&ht, key) == NULL); vim_free(item); } } /* check again */ for (i = 0; i < TEST_COUNT; i++) { key = index_to_key(i); item = mf_hash_find(&ht, key); if (i % 100 < 70) { assert(item == NULL); } else { assert(item != NULL); assert(item->mhi_key == key); } } /* free hash table and all remaining items */ mf_hash_free_all(&ht); }
/* * Open an existing or new memory block file. * * fname: name of file to use (NULL means no file at all) * Note: fname must have been allocated, it is not copied! * If opening the file fails, fname is freed. * flags: flags for open() call * * If fname != NULL and file cannot be opened, fail. * * return value: identifier for this memory block file. */ memfile_T * mf_open(char_u *fname, int flags) { memfile_T *mfp; off_T size; #if defined(STATFS) && defined(UNIX) && !defined(__QNX__) && !defined(__minix) # define USE_FSTATFS struct STATFS stf; #endif if ((mfp = (memfile_T *)alloc((unsigned)sizeof(memfile_T))) == NULL) return NULL; if (fname == NULL) /* no file for this memfile, use memory only */ { mfp->mf_fname = NULL; mfp->mf_ffname = NULL; mfp->mf_fd = -1; } else { mf_do_open(mfp, fname, flags); /* try to open the file */ /* if the file cannot be opened, return here */ if (mfp->mf_fd < 0) { vim_free(mfp); return NULL; } } mfp->mf_free_first = NULL; /* free list is empty */ mfp->mf_used_first = NULL; /* used list is empty */ mfp->mf_used_last = NULL; mfp->mf_dirty = FALSE; mfp->mf_used_count = 0; mf_hash_init(&mfp->mf_hash); mf_hash_init(&mfp->mf_trans); mfp->mf_page_size = MEMFILE_PAGE_SIZE; #ifdef FEAT_CRYPT mfp->mf_old_key = NULL; #endif #ifdef USE_FSTATFS /* * Try to set the page size equal to the block size of the device. * Speeds up I/O a lot. * When recovering, the actual block size will be retrieved from block 0 * in ml_recover(). The size used here may be wrong, therefore * mf_blocknr_max must be rounded up. */ if (mfp->mf_fd >= 0 && fstatfs(mfp->mf_fd, &stf, sizeof(struct statfs), 0) == 0 && stf.F_BSIZE >= MIN_SWAP_PAGE_SIZE && stf.F_BSIZE <= MAX_SWAP_PAGE_SIZE) mfp->mf_page_size = stf.F_BSIZE; #endif if (mfp->mf_fd < 0 || (flags & (O_TRUNC|O_EXCL)) || (size = vim_lseek(mfp->mf_fd, (off_T)0L, SEEK_END)) <= 0) mfp->mf_blocknr_max = 0; /* no file or empty file */ else mfp->mf_blocknr_max = (blocknr_T)((size + mfp->mf_page_size - 1) / mfp->mf_page_size); mfp->mf_blocknr_min = -1; mfp->mf_neg_count = 0; mfp->mf_infile_count = mfp->mf_blocknr_max; /* * Compute maximum number of pages ('maxmem' is in Kbyte): * 'mammem' * 1Kbyte / page-size-in-bytes. * Avoid overflow by first reducing page size as much as possible. */ { int shift = 10; unsigned page_size = mfp->mf_page_size; while (shift > 0 && (page_size & 1) == 0) { page_size = page_size >> 1; --shift; } mfp->mf_used_count_max = (p_mm << shift) / page_size; if (mfp->mf_used_count_max < 10) mfp->mf_used_count_max = 10; } return mfp; }