Convert C++ to PBasic

Just starting out? Need help? Post your questions and find answers here.
zikitrake
Addict
Addict
Posts: 878
Joined: Thu Mar 25, 2004 2:15 pm
Location: Spain

Convert C++ to PBasic

Post 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!
PB 6.21 beta, PureVision User
User avatar
Demivec
Addict
Addict
Posts: 4281
Joined: Mon Jul 25, 2005 3:51 pm
Location: Utah, USA

Re: Convert C++ to PBasic

Post 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
Last edited by Demivec on Wed May 29, 2024 11:32 am, edited 2 times in total.
zikitrake
Addict
Addict
Posts: 878
Joined: Thu Mar 25, 2004 2:15 pm
Location: Spain

Re: Convert C++ to PBasic

Post 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 :!:
PB 6.21 beta, PureVision User
BarryG
Addict
Addict
Posts: 4219
Joined: Thu Apr 18, 2019 8:17 am

Re: Convert C++ to PBasic

Post by BarryG »

0xF0000000 has to be $F0000000 for starters. Don't know about the rest.
User avatar
NicTheQuick
Addict
Addict
Posts: 1527
Joined: Sun Jun 22, 2003 7:43 pm
Location: Germany, Saarbrücken
Contact:

Re: Convert C++ to PBasic

Post 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.
The english grammar is freeware, you can use it freely - But it's not Open Source, i.e. you can not change it or publish it in altered way.
Fred
Administrator
Administrator
Posts: 18351
Joined: Fri May 17, 2002 4:39 pm
Location: France
Contact:

Re: Convert C++ to PBasic

Post by Fred »

'unsigned long' in C is usually a 32-bit number
zikitrake
Addict
Addict
Posts: 878
Joined: Thu Mar 25, 2004 2:15 pm
Location: Spain

Re: Convert C++ to PBasic

Post 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!
PB 6.21 beta, PureVision User
wilbert
PureBasic Expert
PureBasic Expert
Posts: 3943
Joined: Sun Aug 08, 2004 5:21 am
Location: Netherlands

Re: Convert C++ to PBasic

Post 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)
Windows (x64)
Raspberry Pi OS (Arm64)
zikitrake
Addict
Addict
Posts: 878
Joined: Thu Mar 25, 2004 2:15 pm
Location: Spain

Re: Convert C++ to PBasic

Post by zikitrake »

Thank you @wilbert and @NicTheQuick

Your code works perfectly :!:
PB 6.21 beta, PureVision User
Post Reply