void ethash_calculate_dag_item( node* const ret, uint32_t node_index, ethash_light_t const light ) { uint32_t num_parent_nodes = (uint32_t) (light->cache_size / sizeof(node)); node const* cache_nodes = (node const *) light->cache; node const* init = &cache_nodes[node_index % num_parent_nodes]; memcpy(ret, init, sizeof(node)); ret->words[0] ^= node_index; SHA3_512(ret->bytes, ret->bytes, sizeof(node)); #if defined(_M_X64) && ENABLE_SSE __m128i const fnv_prime = _mm_set1_epi32(FNV_PRIME); __m128i xmm0 = ret->xmm[0]; __m128i xmm1 = ret->xmm[1]; __m128i xmm2 = ret->xmm[2]; __m128i xmm3 = ret->xmm[3]; #endif for (uint32_t i = 0; i != ETHASH_DATASET_PARENTS; ++i) { uint32_t parent_index = fnv_hash(node_index ^ i, ret->words[i % NODE_WORDS]) % num_parent_nodes; node const *parent = &cache_nodes[parent_index]; #if defined(_M_X64) && ENABLE_SSE { xmm0 = _mm_mullo_epi32(xmm0, fnv_prime); xmm1 = _mm_mullo_epi32(xmm1, fnv_prime); xmm2 = _mm_mullo_epi32(xmm2, fnv_prime); xmm3 = _mm_mullo_epi32(xmm3, fnv_prime); xmm0 = _mm_xor_si128(xmm0, parent->xmm[0]); xmm1 = _mm_xor_si128(xmm1, parent->xmm[1]); xmm2 = _mm_xor_si128(xmm2, parent->xmm[2]); xmm3 = _mm_xor_si128(xmm3, parent->xmm[3]); // have to write to ret as values are used to compute index ret->xmm[0] = xmm0; ret->xmm[1] = xmm1; ret->xmm[2] = xmm2; ret->xmm[3] = xmm3; } #else { for (unsigned w = 0; w != NODE_WORDS; ++w) { ret->words[w] = fnv_hash(ret->words[w], parent->words[w]); } } #endif } SHA3_512(ret->bytes, ret->bytes, sizeof(node)); }
HashT *add(HashT &h, bool &found) { int b = fnv_hash(HASHT_PTR(h), HASHT_SZ) % HASHB; for (int i = buckets[b]; i >= 0; i = next[i]) if (data[i] == h) { found = true; return &data[i]; } found = false, next[n] = buckets[b], buckets[b] = n, data[n] = h; return &data[n++]; }
// Test int NoVoHT::append(string k, string aval) { //while(map_lock) { /* Wait for it... */ } sem_wait(&map_lock); int ret = 0; int loc = fnv_hash(k) % size; kvpair* cur = kvpairs[loc]; while (cur != NULL) { if (k.compare(cur->key) == 0) { cur->val += ":" + aval; sem_post(&map_lock); return writeAppend(cur, aval) + ret; } cur = cur->next; } kvpair* add = new kvpair; add->key = k; add->val = aval; add->next = kvpairs[loc]; add->positions = NULL; kvpairs[loc] = add; numEl++; //map_lock = false; sem_post(&map_lock); return write(add); }
/* We want all the fields to be const (not that it really matters since any instance is almost certainly going to be const itself), so we create the table in the following function which returns a tuple, we can use this to initialize the fields in the member initializiter list allowing the fields to be const. */ static constexpr std::tuple<std::array<hentry,N>,std::array<uint8_t,N>, size_t, size_t, size_t> build_table(const std::initializer_list<std::pair<Key,Value>> ls) { std::array<hentry, N> table = {{}}; std::array<uint8_t, N> entries_used = {{}}; size_t nentries = 0; size_t first_entry = 0; size_t last_entry = (N-1); assert(nentries <= Max_Entries); for(const auto kv : ls){ const Key key = kv.first; const Value value = kv.second; const size_t hv = fnv_hash(key); size_t idx = hv % N; while(entries_used[idx]){ assert(hv != table[idx].hv); //"Error, duplicate hash code, either dupliate key or hash collision"); ++idx; } table[idx] = hentry(key,value,hv); entries_used[idx] = 1; } while(!entries_used[first_entry]){ first_entry++; } while(!entries_used[last_entry]){ last_entry--; } return std::make_tuple(table, entries_used, nentries, first_entry, last_entry); }
world_write::~world_write() { for (auto& cnk : cnks_) { trace("Write commit chunk %1%, fingerprint %2%", cnk.first, fnv_hash((const uint8_t*)&*cnk.second.begin(), chunk_volume * 2)); w_.commit_write(cnk.first); } }
constexpr iterator find(const Key &k) const { const size_t hv = fnv_hash(k); size_t idx = hv % N; while(table[idx].hv != hv && entries_used[idx]){ ++idx; } if(entries_used[idx]){ return iterator(this, idx); } else { return end(); } }
//0 success, -1 no insert, -2 no write int NoVoHT::put(string k, string v) { //while(resizing || map_lock){ /* Wait till done */} //while (map_lock) {} //map_lock = true; // //int semv; //sem_getvalue(&map_lock, &semv); //printf("semv = %d\n", semv); sem_wait(&map_lock); if (numEl >= size * resizeNum) { if (resizeNum != 0) { resize(size * 2); } } int slot; slot = fnv_hash(k) % size; kvpair *cur = kvpairs[slot]; kvpair *add = new kvpair; add->key = k; add->val = v; add->next = NULL; add->positions = NULL; if (cur == NULL) { kvpairs[slot] = add; numEl++; //map_lock = false; sem_post(&map_lock); return write(add); } while (cur->next != NULL) { if (k.compare(cur->key) == 0) { cur->val = v; mark(cur->positions); delete add; //map_lock = false; sem_post(&map_lock); return write(cur); } cur = cur->next; } if (k.compare(cur->key) == 0) { cur->val = v; mark(cur->positions); delete add; //map_lock = false; sem_post(&map_lock); return write(cur); } cur->next = add; numEl++; //map_lock = false; sem_post(&map_lock); return write(add); }
static ERL_NIF_TERM hash(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) { ErlNifBinary bin; long seed; int hash; if (enif_inspect_binary(env, argv[0], &bin)) { int res = enif_get_long(env, argv[1], &seed); hash = fnv_hash(bin.data, bin.size, seed); return enif_make_int(env, hash); } return enif_make_atom(env, "badarg"); }
// Fix void NoVoHT::merge() { //while(write_lock){} //write_lock=true; sem_wait(&map_lock); sem_wait(&write_lock); char buf[300]; char sec[300]; rewind(dbfile); while (readTabString(dbfile, buf) != NULL) { if (buf[0] == '~') { readTabString(dbfile, sec); char * pos; pos = strtok(sec, ","); while (pos != NULL) { fseek(swapFile, (off_t) atoi(pos), SEEK_SET); char test[300]; readTabString(swapFile, test); if (strcmp(test, (buf + 1)) == 0) { fseek(swapFile, (off_t) atoi(pos), SEEK_SET); fputc('~', swapFile); } pos = strtok(NULL, ","); } } else { //while (map_lock) {} //map_lock = true; //sem_wait(&map_lock); fseek(swapFile, 0, SEEK_END); string s(buf); kvpair* p = kvpairs[fnv_hash(s) % size]; while (p != NULL) { if (p->key.compare(s) == 0) { destroyFposList(p->positions); p->positions = new fpos_list; p->positions->next = NULL; fgetpos(swapFile, &(p->positions->pos)); fprintf(swapFile, "%s\t%s\t", p->key.c_str(), p->val.c_str()); p->diff = false; break; } else p = p->next; } //map_lock = false; //sem_post(&map_lock); } } fclose(dbfile); dbfile = swapFile; rewriting = false; sem_post(&map_lock); sem_post(&write_lock); }
ListNode *MapGetChain(ListNode *Map, const char *Key) { unsigned int i; ListNode *Node; if (Map->Flags & LIST_FLAG_MAP_HEAD) { i=fnv_hash(Key, Map->ItemType); Node=(ListNode *) Map->Item; return(Node + i); } return(NULL); }
string* NoVoHT::get(string k) { //while (map_lock) { /* Wait till done */ sem_wait(&map_lock); sem_post(&map_lock); int loc = fnv_hash(k) % size; kvpair *cur = kvpairs[loc]; while (cur != NULL && !k.empty()) { if (k.compare(cur->key) == 0) return &(cur->val); cur = cur->next; } return NULL; }
//return 0 for success, -1 fail to remove, -2+ write failure int NoVoHT::remove(string k) { //while(map_lock){ /* Wait till done */} sem_wait(&map_lock); int ret = 0; int loc = fnv_hash(k) % size; kvpair *cur = kvpairs[loc]; if (cur == NULL) { sem_post(&map_lock); return ret - 1; //not found } if (k.compare(cur->key) == 0) { //fpos_t toRem = kvpairs[loc]->pos; fpos_list * toRem = kvpairs[loc]->positions; kvpairs[loc] = cur->next; numEl--; ret = rewriting ? logrm(k, toRem) + ret : ret + mark(toRem); delete cur; nRem++; if (nRem == magicNumber) ret += writeFile(); //write and save write success sem_post(&map_lock); return ret; } while (cur != NULL) { if (cur->next == NULL) { sem_post(&map_lock); return ret - 1; } else if (k.compare(cur->next->key) == 0) { kvpair *r = cur->next; cur->next = r->next; // fpos_t toRem = r->pos; struct fpos_list * toRem = kvpairs[loc]->positions; ret = rewriting ? logrm(k, toRem) + ret : ret + mark(toRem); delete r; numEl--; nRem++; if (nRem == magicNumber) ret += writeFile(); //mark and sace status code sem_post(&map_lock); return ret; } cur = cur->next; } sem_post(&map_lock); return ret - 1; //not found }
static int atomic_hash_table_update_one_file(english_word *word){ uint64_t hashv=fnv_hash(word->str,word->len); uint64_t index=hashv%global_hash_table_size; //this next line results in a lot of cache misses //for obvious reasons if(!global_hash_table[index]){//word isn't in the hash table, add it uint8_t *mem=xmalloc(word->len); word->str=(char*)my_strcpy(mem,(uint8_t*)word->str,word->len); void *prev=global_hash_table[index]; int test=atomic_compare_exchange_n(global_hash_table+index,&prev,word); if(test){ //we added the word //this needs to be atomic to prevent two threads writing different //values to the same index of indices uint64_t old_indices_index=atomic_fetch_add(&indices_index,1); //this doesn't need to be atomic, since indices_index will never be //decremented, so no one else will change this hash_table_indices[old_indices_index]=index; goto end1; } //else, someone else changed the value of global_hash_table[index] before us } while(1){ do { //see if the value in the table is the same as our value //if so update the value already in the table if(string_compare(global_hash_table[index],word)){ //atomically increment word count atomic_add(&global_hash_table[index]->count,1); goto end0; } } while(global_hash_table[++index]); //not in the table use next free index (if we can) void *prev=global_hash_table[index]; int test=atomic_compare_exchange_n(global_hash_table+index,&prev,word); if(test){ uint64_t old_indices_index=atomic_fetch_add(&indices_index,1); hash_table_indices[old_indices_index]=index; goto end1; } //if !test the compare exchange failed and we need to keep looping } end0: return 0; end1: return 1; }
void debug_filter_remove(const char* tag) { const u32 hash = fnv_hash(tag, strlen(tag)*sizeof(tag[0])); for(size_t i = 0; i < MAX_TAGS; i++) { if(tags[i] == hash) // found it { // replace with last element (avoid holes) tags[i] = tags[MAX_TAGS-1]; num_tags--; // can only happen once, so we're done. return; } } }
unsigned novenaRF_hashFpga(const std::string &fpgaImage) { //open the specified FPGA image FILE *fpga_fp = fopen(fpgaImage.c_str(), "rb"); if (fpga_fp == NULL) { throw std::runtime_error("Failed to open "+fpgaImage+": " + std::string(strerror(errno))); } //just read enough to make a hash that can differentiate images unsigned char buff[4096]; int r = fread(buff, 1, sizeof(buff), fpga_fp); fclose(fpga_fp); if (r <= 0) throw std::runtime_error("Failed to read "+fpgaImage+": " + std::string(strerror(errno))); return fnv_hash(buff, r); }
void debug_filter_add(const char* tag) { const u32 hash = fnv_hash(tag, strlen(tag)*sizeof(tag[0])); // make sure it isn't already in the list for(size_t i = 0; i < MAX_TAGS; i++) if(tags[i] == hash) return; // too many already? if(num_tags == MAX_TAGS) { DEBUG_WARN_ERR(ERR::LOGIC); // increase MAX_TAGS return; } tags[num_tags++] = hash; }
int main(int argc, char * argv[]) { line_t line; int i, j, col_index; int first_line = 1; if (argc < 5) showusage(); if (strcmp(argv[1], "-") != 0) line.pin = try_open(argv[1], "rb"); else line.pin = stdin; col_index = atoi(argv[2]); int pouts_len = atoi(argv[3]); const char* output_format = argv[4]; FILE ** pouts = (FILE **) malloc( pouts_len * sizeof(FILE *) ); char out_path[256]; for (i = 0; i != pouts_len; ++i) { sprintf(out_path, output_format, i); pouts[i] = try_open(out_path, "wb"); } while (fgets(line.buf, sizeof(line.buf), line.pin)) { if (first_line) { for (j = 0; j != pouts_len; ++j) { fputs(line.buf, pouts[j]); // write header to all the files first_line = 0; } } else if ( find_col(col_index, &line) ) // if this string has the requisite number of columns fputs(line.buf, pouts[fnv_hash(line.col_beg, line.col_end) % pouts_len]); // write it to the correct file } if (line.pin != stdin) fclose(line.pin); for (i = 0; i != pouts_len; ++i) fclose(pouts[i]); return 0; }
int test_btree(string **values, int n){ int i; btree *tree = make_btree(); uint64_t *hashes = xmalloc(n*sizeof(uint64_t)); uint64_t *indices = xmalloc(n*sizeof(uint64_t)); //nfor now I'm just using sequential ints for keys DEBUG_PRINTF("Testing btree insertion\n"); for(i=0;i<n;i++){ assert(check_tree(tree) >= 0); indices[i] = i; hashes[i] = fnv_hash(values[i]->mem, values[i]->len); btree_insert(tree, hashes[indices[i]], values[i]); } assert(check_tree(tree) >= 0); shuffle_array((void**)indices, n); DEBUG_PRINTF("Testing btree lookup\n"); for(i=0;i<n;i++){ string *str = btree_lookup(tree, hashes[indices[i]]); WARN_ON_ONCE(!string_ptr_eq(str, values[indices[i]])); } DEBUG_PRINTF("Testing btree deletion\n"); for(i=0;i<n;i++){ uint64_t num_keys = count_num_keys(tree->root); if(num_keys != (n-i)){ DEBUG_PRINTF("Tree has %lu keys, expected %lu\n", num_keys, n-i); exit(1); } assert(check_tree(tree) >= 0); if(btree_lookup(tree, hashes[indices[i]])){ if(!btree_delete(tree, hashes[indices[i]])){ exit(1); } } else { DEBUG_PRINTF("Couldn't find key %lu\n",indices[i]); } } WARN_ON(check_tree(tree) < 0); WARN_ON(tree->root->n_keys != 0); return 0; }
bool debug_filter_allows(const char* text) { size_t i; for(i = 0; ; i++) { // no | found => no tag => should always be displayed if(text[i] == ' ' || text[i] == '\0') return true; if(text[i] == '|' && i != 0) break; } const u32 hash = fnv_hash(text, i*sizeof(text[0])); // check if entry allowing this tag is found for(i = 0; i < MAX_TAGS; i++) if(tags[i] == hash) return true; return false; }
// any further params are passed to type's init routine Handle h_alloc(H_Type type, const PIVFS& vfs, const VfsPath& pathname, size_t flags, ...) { H_ScopedLock s; RETURN_STATUS_IF_ERR(type_validate(type)); const uintptr_t key = fnv_hash(pathname.string().c_str(), pathname.string().length()*sizeof(pathname.string()[0])); // see if we can reuse an existing handle Handle h = reuse_existing_handle(key, type, flags); RETURN_STATUS_IF_ERR(h); // .. successfully reused the handle; refcount increased if(h > 0) return h; // .. need to allocate a new one: va_list args; va_start(args, flags); h = alloc_new_handle(type, vfs, pathname, key, flags, &args); va_end(args); return h; // alloc_new_handle already does WARN_RETURN_STATUS_IF_ERR }
// TODO: what if iterating through all handles is too slow? Status h_reload(const PIVFS& vfs, const VfsPath& pathname) { H_ScopedLock s; const u32 key = fnv_hash(pathname.string().c_str(), pathname.string().length()*sizeof(pathname.string()[0])); // destroy (note: not free!) all handles backed by this file. // do this before reloading any of them, because we don't specify reload // order (the parent resource may be reloaded first, and load the child, // whose original data would leak). for(HDATA* hd = (HDATA*)hpool.da.base; hd < (HDATA*)(hpool.da.base + hpool.da.pos); hd = (HDATA*)(uintptr_t(hd)+hpool.el_size)) { if(hd->key == 0 || hd->key != key || hd->disallow_reload) continue; hd->type->dtor(hd->user); } Status ret = INFO::OK; // now reload all affected handles size_t i = 0; for(HDATA* hd = (HDATA*)hpool.da.base; hd < (HDATA*)(hpool.da.base + hpool.da.pos); hd = (HDATA*)(uintptr_t(hd)+hpool.el_size), i++) { if(hd->key == 0 || hd->key != key || hd->disallow_reload) continue; Status err = hd->type->reload(hd->user, vfs, hd->pathname, hd->h); // don't stop if an error is encountered - try to reload them all. if(err < 0) { h_free(hd->h, hd->type); if(ret == 0) // don't overwrite first error ret = err; } else warn_if_invalid(hd); } return ret; }
//success 0 fail -2 //resize the hashmap's base size void NoVoHT::resize(int ns) { resizing = true; int olds = size; size = ns; oldpairs = kvpairs; kvpairs = new kvpair*[ns]; for (int z = 0; z < ns; z++) { kvpairs[z] = NULL; } numEl = 0; for (int i = 0; i < olds; i++) { kvpair *cur = oldpairs[i]; while (cur != NULL) { int pos = fnv_hash(cur->key) % size; kvpair * tmp = kvpairs[pos]; kvpairs[pos] = cur; cur = cur->next; kvpairs[pos]->next = tmp; } } delete[] oldpairs; resizing = false; }
/** @brief Driver. ** ** @param nount number of output arguments. ** @param out output arguments. ** @param nin number of input arguments. ** @param in input arguments. **/ void mexFunction(int nout, mxArray *out[], int nin, const mxArray *in[]) { enum { IN_ID, IN_NEXT, IN_K, IN_X } ; enum { OUT_SEL } ; vl_uint32 const * next ; vl_uint32 * sel ; vl_uint8 const * id ; vl_uint8 const * x ; unsigned int K, i, N, res, last, ndims ; /* ----------------------------------------------------------------- * Check arguments * -------------------------------------------------------------- */ if( nin != 4 ) { mexErrMsgTxt("Four arguments required") ; } else if (nout > 1) { mexErrMsgTxt("At most one output argument.") ; } if(! mxIsNumeric(in[IN_NEXT])|| mxGetClassID(in[IN_NEXT])!= mxUINT32_CLASS) { mexErrMsgTxt("NEXT must be UINT32.") ; } if(! mxIsNumeric(in[IN_X]) || mxGetClassID(in[IN_X])!= mxUINT8_CLASS) { mexErrMsgTxt("X must be UINT8") ; } if (mxGetM(in[IN_NEXT]) != 1) { mexErrMsgTxt("NEXT must be a row vector") ; } if(! mxIsNumeric(in[IN_ID]) || mxGetClassID(in[IN_ID])!= mxUINT8_CLASS) { mexErrMsgTxt("ID must be UINT8.") ; } ndims = mxGetM(in[IN_ID]) ; res = mxGetN(in[IN_ID]) ; if(res != mxGetN(in[IN_NEXT])) { mexErrMsgTxt("ID, NEXT must have the same number of columns") ; } if(ndims != mxGetM(in[IN_X])) { mexErrMsgTxt("ID and X must havethe same number of rows") ; } if(! vlmxIsPlainScalar(in[IN_K])) { mexErrMsgTxt("K must be a scalar") ; } K = (unsigned int) *mxGetPr(in[IN_K]) ; N = mxGetN(in[IN_X]) ; id = mxGetData(in[IN_ID]) ; next = mxGetData(in[IN_NEXT]) ; x = mxGetData(in[IN_X]) ; out[OUT_SEL] = mxCreateNumericMatrix (1, N, mxUINT32_CLASS, mxREAL) ; sel = mxGetData (out[OUT_SEL]) ; /* search for last occupied slot */ last = res ; for (i = 0 ; i < res ; ++i) last = VL_MAX(last, next [i]) ; /* REMARK: last and next are 1 based */ if (K > res) { mexErrMsgTxt("K cannot be larger then the size of H") ; } if (last > res) { mexErrMsgTxt("An element of NEXT is greater than the size of the table") ; } /* ----------------------------------------------------------------- * Do job * -------------------------------------------------------------- */ for (i = 0 ; i < N ; ++i) { /* hash */ unsigned int h1, h2 ; unsigned int j, p = 0 ; if (is_null (x + i * ndims, ndims)) { *sel++ = 0 ; continue ; } h1 = fnv_hash(x + i * ndims, ndims) % K ; h2 = h1 | 0x1 ; /* this needs to be odd */ /* search first free or matching position */ p = h1 % K ; for (j = 0 ; j < K ; ++j) { if (is_null (id + p * ndims, ndims) || is_equal(id + p * ndims, x + i * ndims, ndims)) break ; h1 += h2 ; p = h1 % K ; } /* handle extended table */ while (! is_null (id + p * ndims, ndims) && ! is_equal(id + p * ndims, x + i * ndims, ndims)) { if (next[p] == 0) break ; p = next [p] - 1 ; } /* found or not ? */ if (is_equal(id + p * ndims, x + i * ndims, ndims)) { /* found */ *sel++ = p + 1 ; } else { /* not found */ *sel++ = 0 ; } } /* next guy to search for */ }
size_t CStr::GetHashCode() const { return (size_t)fnv_hash(data(), length()*sizeof(value_type)); // janwas 2005-03-18: now use 32-bit version; 64 is slower and // the result was truncated down to 32 anyway. }
int cloakhost(char *host, char *dest) { char virt[HOSTLEN + 1], ip6buffer[INET6_ADDRSTRLEN], *p; unsigned int dotCount, colCount; int32_t csum; host_type_t htype; htype = host_type(host, &dotCount, &colCount); memset(virt, 0x0, HOSTLEN+1); switch (htype) { case HT_INVALID: return 0; case HT_FQDN: csum = fnv_hash(sha1_hash(host, strlen(host)), SHABUFLEN); if (dotCount == 1) { snprintf(virt, HOSTLEN, "%s%c%X.%s", cloak_host, (csum < 0 ? '=' : '-'), (csum < 0 ? -csum : csum), host); } else if (dotCount > 1) { int chlen = strlen(cloak_host) + 10; /* -12345678. */ p = (char *) strchr((char *)host, '.'); while((strlen(p) + chlen) > HOSTLEN) { /* controllare i return value non sarebbe una cattiva idea... */ if ((p = (char *) strchr((char *) ++p, '.')) == NULL) return 0; } snprintf(virt, HOSTLEN, "%s%c%X.%s", cloak_host, (csum < 0 ? '=' : '-'), (csum < 0 ? -csum : csum), p + 1); } else return 0; break; case HT_IPv4: { char ipmask[16]; csum = fnv_hash(sha1_hash(host, strlen(host)), SHABUFLEN); strncpy(ipmask, host, sizeof(ipmask)); ipmask[sizeof(ipmask) - 1] = '\0'; if ((p = strchr(ipmask, '.')) != NULL) if ((p = strchr(p + 1, '.')) != NULL) *p = '\0'; if (p == NULL) snprintf(virt, HOSTLEN, "%s%c%X", cloak_host, csum < 0 ? '=' : '-', csum < 0 ? -csum : csum); else snprintf(virt, HOSTLEN, "%s.%s%c%X", ipmask, cloak_host, csum < 0 ? '=' : '-', csum < 0 ? -csum : csum); break; } case HT_IPv6: { /* FFFFFFFUUUUUUUU */ int rv; struct in6_addr ip6addr; /* Expand address before hashing */ expand_ipv6(host, colCount, ip6buffer); Debug((DEBUG_INFO, "%s expanded to %s (%u columns)", host, ip6buffer, colCount)); csum = fnv_hash(sha1_hash(ip6buffer, strlen(ip6buffer)), SHABUFLEN); /* Clear the buffer */ memset(ip6buffer, 0, sizeof(ip6buffer)); /* Get raw bytes... */ rv = inet_pton(AF_INET6, host, &ip6addr); if (rv <= 0) { Debug((DEBUG_ERROR, "inet_pton failed: rv = %d, errno = %d", rv, errno)); return 0; } /* ...blank out the lowest 80 bits... */ memset(&(ip6addr.s6_addr[6]), 0, 10); /* ...and get back the "presentation format" */ if (inet_ntop(AF_INET6, &ip6addr, ip6buffer, INET6_ADDRSTRLEN) == NULL) { Debug((DEBUG_ERROR, "inet_ntop failed: errno = %d", errno)); return 0; } /* Now append the checksum (eg. "2001:db8::Azzurra-12345678") */ snprintf(virt, HOSTLEN, "%s%s%c%X", ip6buffer, cloak_host, csum < 0 ? '=' : '-', csum < 0 ? -csum : csum); break; } } memcpy(dest, virt, HOSTLEN); return 1; }
VfsPath CColladaManager::GetLoadableFilename(const VfsPath& pathnameNoExtension, FileType type) { std::wstring extn; switch (type) { case PMD: extn = L".pmd"; break; case PSA: extn = L".psa"; break; // no other alternatives } /* If there is a .dae file: * Calculate a hash to identify it. * Look for a cached .pmd file matching that hash. * If it exists, load it. Else, convert the .dae into .pmd and load it. Otherwise, if there is a (non-cache) .pmd file: * Load it. Else, fail. The hash calculation ought to be fast, since normally (during development) the .dae file will exist but won't have changed recently and so the cache would be used. Hence, just hash the file's size, mtime, and the converter version number (so updates of the converter can cause regeneration of .pmds) instead of the file's actual contents. TODO (maybe): The .dae -> .pmd conversion may fail (e.g. if the .dae is invalid or unsupported), but it may take a long time to start the conversion then realise it's not going to work. That will delay the loading of the game every time, which is annoying, so maybe it should cache the error message until the .dae is updated and fixed. (Alternatively, avoid having that many broken .daes in the game.) */ // (TODO: the comments and variable names say "pmd" but actually they can // be "psa" too.) VfsPath dae(pathnameNoExtension.ChangeExtension(L".dae")); if (! VfsFileExists(dae)) { // No .dae - got to use the .pmd, assuming there is one return pathnameNoExtension.ChangeExtension(extn); } // There is a .dae - see if there's an up-to-date cached copy FileInfo fileInfo; if (g_VFS->GetFileInfo(dae, &fileInfo) < 0) { // This shouldn't occur for any sensible reasons LOGERROR(L"Failed to stat DAE file '%ls'", dae.string().c_str()); return VfsPath(); } // Build a struct of all the data we want to hash. // (Use ints and not time_t/off_t because we don't care about overflow // but do care about the fields not being 64-bit aligned) // (Remove the lowest bit of mtime because some things round it to a // resolution of 2 seconds) #pragma pack(push, 1) struct { int version; int mtime; int size; } hashSource = { COLLADA_CONVERTER_VERSION, (int)fileInfo.MTime() & ~1, (int)fileInfo.Size() }; cassert(sizeof(hashSource) == sizeof(int) * 3); // no padding, because that would be bad #pragma pack(pop) // Calculate the hash, convert to hex u32 hash = fnv_hash(static_cast<void*>(&hashSource), sizeof(hashSource)); wchar_t hashString[9]; swprintf_s(hashString, ARRAY_SIZE(hashString), L"%08x", hash); std::wstring extension(L"_"); extension += hashString; extension += extn; // realDaePath_ is "[..]/mods/whatever/art/meshes/whatever.dae" OsPath realDaePath_; Status ret = g_VFS->GetRealPath(dae, realDaePath_); ENSURE(ret == INFO::OK); wchar_t realDaeBuf[PATH_MAX]; wcscpy_s(realDaeBuf, ARRAY_SIZE(realDaeBuf), realDaePath_.string().c_str()); std::replace(realDaeBuf, realDaeBuf+ARRAY_SIZE(realDaeBuf), '\\', '/'); const wchar_t* realDaePath = wcsstr(realDaeBuf, L"mods/"); // cachedPmdVfsPath is "cache/mods/whatever/art/meshes/whatever_{hash}.pmd" VfsPath cachedPmdVfsPath = VfsPath("cache") / realDaePath; cachedPmdVfsPath = cachedPmdVfsPath.ChangeExtension(extension); // If it's not in the cache, we'll have to create it first if (! VfsFileExists(cachedPmdVfsPath)) { if (! m->Convert(dae, cachedPmdVfsPath, type)) return L""; // failed to convert } return cachedPmdVfsPath; }
static constexpr uint64_t fnv_hash(const T arr[N]){ return fnv_hash(static_cast<const void*>(arr), sizeof(T)*N); }
//string_views static constexpr uint64_t fnv_hash(const std::string_view sv){ return fnv_hash(static_cast<const void*>(sv.data()), sv.size()); }
static constexpr uint64_t fnv_hash(const T x){ //Mix in unique type value here. return fnv_hash(static_cast<const void*>(&x), sizeof(x)); }
//Caling with a key that's not in the table invokes undefined behavior, //in practice it usually will go into an infinite loop. constexpr Value operator[](const Key &k) const { const size_t hv = fnv_hash(k); const size_t idx = find_hv_idx(hv, hv % N); return table[idx].value; }