Page 1 of 1
Convert C++ to PBasic
Posted: Wed May 29, 2024 11:05 am
by zikitrake
Can someone give me a hand with the conversion of this code?
Code: Select all
unsigned long h = 0, high; // Directory Hash
// Calc hash
for (int i = 0; i < fname.length(); i++) {
h = (h << 4) + fname[i];
if (high = h & 0xF0000000)
h ^= high >> 24;
h &= ~high;
}
My (fault) PB code:
Code: Select all
Define h.i, high.i
; Calc hash
ForEach(fname())
h = (h << 4) + Len(fname())
If (high = h & 0xF0000000)
h ^= high >> 24
h &= ~high;
Next
Thank you in advance!
Re: Convert C++ to PBasic
Posted: Wed May 29, 2024 11:15 am
by Demivec
If fname is a list then perhaps this:
Code: Select all
Define h.i, high.i , fnl.i, i.i
; Calc hash
ForEach fname()
fnl = Len(fname())
For i = 1 To fnl
h = (h << 4) + Asc(Mid(fname(), i, 1))
If high = h & $F0000000
h ^= high >> 24
EndIf
h &= ~high
Next
Next
Re: Convert C++ to PBasic
Posted: Wed May 29, 2024 11:19 am
by zikitrake
Demivec wrote: Wed May 29, 2024 11:15 am
If fname is a list then perhaps this:...
Thank you! Yes, fname is a filename list
In some hours I'll test it and comment

Re: Convert C++ to PBasic
Posted: Wed May 29, 2024 11:28 am
by BarryG
0xF0000000 has to be $F0000000 for starters. Don't know about the rest.
Re: Convert C++ to PBasic
Posted: Wed May 29, 2024 11:52 am
by NicTheQuick
All solutions are wrong. This should be right:
Code: Select all
Procedure.q hash(name.s)
Protected h.q, high.q, *c.Character = @name
While *c\c
h = (h << 4) + *c\c
high = h & $F0000000
If high
h ! (high >> 24)
EndIf
h & (~high)
*c + SizeOf(Character)
Wend
ProcedureReturn h
EndProcedure
Debug hash("Purebasic.exe")
Why?
- We are not talking about a list but an array, and I am pretty sure it is an array of characters, so basically a simple string.
- The line "if (high = h & 0xF0000000)" does two things. It assigns the value of "h & 0xF0000000" to the variable "high" and then checks if it is non-zero.
- Also the operator "^=" is a XOR which is "!" in Purebasic.
Re: Convert C++ to PBasic
Posted: Wed May 29, 2024 3:42 pm
by Fred
'unsigned long' in C is usually a 32-bit number
Re: Convert C++ to PBasic
Posted: Wed May 29, 2024 4:18 pm
by zikitrake
NicTheQuick wrote: Wed May 29, 2024 11:52 am
All solutions are wrong. This should be right:...
Sorry, my error; this is a more complete code:
Code: Select all
unsigned long h = 0, high; // Directory Hash
OSD::elements = 0;
OSD::ndirs = 0;
while ((de = readdir(dir)) != nullptr) {
string fname = de->d_name;
// if (fname[0] == 'A') printf("Fname: %s\n",fname.c_str());
if (de->d_type == DT_REG || de->d_type == DT_DIR) {
if (fname.compare(0,1,".") != 0) {
// if (fname[0] == 'A') printf("Fname2: %s\n",fname.c_str());
// if ((de->d_type == DT_DIR) || (std::find(filexts.begin(),filexts.end(),fname.substr(fname.size()-4)) != filexts.end())) {
// if ((de->d_type == DT_DIR) || ((fname.size() > 3) && (std::find(filexts.begin(),filexts.end(),fname.substr(fname.size()-4)) != filexts.end()))) {
size_t fpos = fname.find_last_of(".");
if ((de->d_type == DT_DIR) || ((fpos != string::npos) && (std::find(filexts.begin(),filexts.end(),fname.substr(fpos)) != filexts.end()))) {
// if (fname[0] == 'A') printf("Fname3: %s\n",fname.c_str());
if (de->d_type == DT_DIR) {
filenames.push_back((char(32) + fname).c_str());
OSD::ndirs++;
} else {
filenames.push_back(fname.c_str());
OSD::elements++;
}
// Calc hash
for (int i = 0; i < fname.length(); i++) {
h = (h << 4) + fname[i];
if (high = h & 0xF0000000)
h ^= high >> 24;
h &= ~high;
}
cnt++;
if (cnt == MAX_FNAMES_PER_CHUNK) {
// Dump current chunk
sort(filenames.begin(),filenames.end()); // Sort vector
sprintf(fileName, "%d", chunk_cnt);
FILE *f = fopen((fpath + fileTypes[ftype].indexFilename + fileName).c_str(), "w");
if (f==NULL) {
printf("Error opening filelist chunk\n");
// Close progress dialog
OSD::progressDialog("","",0,2);
return;
}
for (int n=0; n < MAX_FNAMES_PER_CHUNK; n++) fputs((filenames[n] + std::string(63 - filenames[n].size(), ' ') + "\n").c_str(),f);
fclose(f);
filenames.clear();
cnt = 0;
chunk_cnt++;
items_processed--;
}
}
}
items_processed++;
OSD::progressDialog("","",(float) 100 / ((float) item_count / (float) items_processed),1);
}
}
Sorry to all, until at night I can't test any of your code.
Thank you again!
Re: Convert C++ to PBasic
Posted: Wed May 29, 2024 7:23 pm
by wilbert
The hash function you are asking about is the ELF hash; a variant of the PJW hash function.
https://en.wikipedia.org/wiki/PJW_hash_function
The output is supposed to be 32 bits but h and high are unsigned so if you convert the code from NicTheQuick to 32 bit you need to add a mask to the shift right.
Code: Select all
Procedure.l hash(name.s)
Protected h.l, high.l, *c.Character = @name
While *c\c
h = (h << 4) + *c\c
high = h & $F0000000
If high
h ! (high >> 24 & $FF)
EndIf
h & (~high)
*c + SizeOf(Character)
Wend
ProcedureReturn h
EndProcedure
Debug Hex(hash("Purebasic.exe"), #PB_Long)
Re: Convert C++ to PBasic
Posted: Fri May 31, 2024 9:36 am
by zikitrake
Thank you @wilbert and @NicTheQuick
Your code works perfectly
