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 :!: