Improvement in my ability to compile code.

One of my practices on this blog has been, to compile certain programs for use either under Linux or Windows, depending on which compiled binary gets used by my reader, to sign any Windows .EXE Files, but only to be able to generate such Windows executables, if they did not have a GUI – i.e., if they were meant to be used in text-mode only, from a Windows command-prompt.

One reason for this has been, the fact that I was teaching myself the Qt5 GUI library, which is cross-platform, but which requires software beyond Visual Studio to compile on the Windows platform I’ve been using, just for such projects.

Ideally, I’d be able to write a Qt5 application once, and then compile it separately, for use under Linux or Windows, and on top of that, to put my code signature on the Windows executable.

Well, I’ve gotten closer to this objective, by means of brute force. I’ve installed the Qt SDK for Windows, in a way that parallels my installation of Qt development packages under Linux. I am able to transfer the source code, and then compile it on the other platform.

Once again, the URL at which my list of potential binaries resides, is:

https://dirkmittler.homeip.net/binaries/

And the 4 new additions, which did not previously have Windows executables within, are:

  • ‘Creator_Test3.tar.gz’
  • ‘Creator_Test3.zip’
  • ‘Dirk_Roots_GUI_1.tar.gz’
  • ‘Dirk_Roots_GUI_1.zip’

 

Enjoy,

Dirk

 

Creating a C++ Hash-Table quickly, that has a QString as its Key-Type.

This posting will assume that the reader has a rough idea, what a hash table is. In case this is not so, this WiKiPedia Article explains that as a generality. Just by reading that article, especially if the reader is of a slightly older generation like me, he or she could get the impression that, putting a hash-table into a practical C++ program is arduous and complex. In reality, the most efficient implementation possible for a hash table, requires some attention to such ideas as, whether the hashes will generally tend to be coprime with the modulus of the hash table, or at least, have the lowest GCDs possible. Often, bucket-arrays with sizes that are powers of (2), and hashes that contain higher prime factors help. But, when writing practical code in C++, one will find that the “Standard Template Library” (‘STL’) already provides one, that has been implemented by experts. It can be put into almost any C++ program, as an ‘unordered_map’. (:1)

But there is a caveat. Any valid data-type meant to act as a key needs to have a hashing function defined, as a template specialization, and not all data-types have one by far. And of course, this hashing function should be as close to unique as possible, for unique key-values, while never changing, if there could be more than one possible representation of the same key-value. Conveniently, C-strings, which are denoted in C or C++ as the old-fashioned ‘char *’ data-type, happen to have this template specialization. But, because C-strings are a very old type of data-structure, and, because the reader may be in the process of writing code that uses the Qt GUI library, the reader may want to use ‘QString’ as his key-data-type, only to find, that a template specialization has not been provided…

For such cases, C++ allows the programmer to define his own hashing function, for QStrings if so chosen. In fact, Qt even allows a quick-and-dirty way to do it, via the ‘qHash()’ function. But there is something I do not like about ‘qHash()’ and its relatives. They tend to produce 32-bit hash-codes! While this does not directly cause an error – only the least-significant 32 bits within a modern 64-bit data-field will contain non-zero values – I think it’s very weak to be using 32-bit hash-codes anyway.

Further, I read somewhere that the latest versions of Qt – as of 5.14? – do, in fact, define such a specialization, so that the programmer does not need to worry about it anymore. But, IF the programmer is still using an older version of Qt, like me, THEN he or she might want to define their own 64-bit hash-function. And so, the following is the result which I arrived at this afternoon. I’ve tested that it will not generate any warnings when compiled under Qt 5.7.1, and that a trivial ‘main()’ function that uses it, will only generate warnings, about the fact that the trivial ‘main()’ function also received the standard ‘argc’ and ‘argv’ parameters, but made no use of them. Otherwise, the resulting executable also produced no messages at run-time, while having put one key-value pair into a sample hash table… (:2)

 

/*  File 'Hash_QStr.h'
 * 
 *  Regular use of a QString in an unordered_map doesn't
 * work, because in earlier versons of Qt, there was no
 * std::hash<QString>() specialization.
 * Thus, one could be included everywhere the unordered_map
 * is to be used...
 */

#ifndef HASH_QSTR_H
#define HASH_QSTR_H


#include <unordered_map>
#include <QString>
//#include <QHash>
#include <QChar>

#define PRIME 5351


/*
namespace cust {
	template<typename T>
	struct hash32 {};

  template<> struct hash32<QString> {
    std::size_t operator()(const QString& s) const noexcept {
      return (size_t) qHash(s);
    }
  };
}

*/


namespace cust
{
	inline size_t QStr_Orther(const QChar & mychar) noexcept {
		return ((mychar.row() << 8) | mychar.cell());
	}
	
	template<typename T>
	struct hash64 {};
	
    template<> struct hash64<QString>
    {
        size_t operator()(const QString& s) const noexcept
        {
            size_t hash = 0;

            for (int i = 0; i < s.size(); i++)
				hash = (hash << 4) + hash + QStr_Orther(s.at(i));

            return hash * PRIME;
        }
    };
}


#endif  //  HASH_QSTR_H

 

(Updated 4/12/2021, 8h00… )

Continue reading Creating a C++ Hash-Table quickly, that has a QString as its Key-Type.

Using Factory Functions to Export C++ Objects from Shared Libraries / DLLs, but also applying Factory Class Design Pattern.

(Edited 3/15/2021, 22h45: )

The main reason for which factory functions are sometimes used is the fact that, while object-oriented code can in fact be compiled into shared libraries, situations exist in which the application programmer is not aware of specific libraries that will need to be loaded at run-time. As a result, this developer cannot specify them during the linking stage of his or her application.

(End of Edit, 3/15/2021, 22h45.)

What one does in practical cases is, to define “factory functions” in the shared library, such as the function “maker()” in the example below, and to give the compiler directive ‘extern “C”‘ when doing so:

https://www.linuxjournal.com/article/3687

I think that the example I’ve just linked to suffers from some seriously bad typesetting. But to my mind, it gets the point across. The methods that belong to C++ classes have mangled names, which are difficult to load from shared libraries directly (using the ‘dlsym()’ function). In principle, one could try to predict the name mangling in the client program, but in practice, this is avoided. Instead, a factory function is exported from the shared library to the client program, the name of which is explicitly not mangled, due to this compiler directive, and what that function does when called is, to create an object of the specified type. The client program’s C++ ‘knows’ what methods of the object it can call because of header files…

When I was studying System Software at Concordia University, an exercise the whole class was required to carry out was, to define a function that was declared with ‘extern “C”‘, to store that in a shared library, and, to write a client program which loaded that function. We were never required to load C++ objects from that shared library. But, the article which I just linked to above, explains how to do that, at least well enough so that I can follow it.

(…)

If you’re one of those people like me, who have seen C++ with many ‘Create…()’ function-names, even though we know that in general, in C++, the constructors of class-objects have the same name as the class, what is written above is likely the reason, for which so many Creator functions have been defined.

I think, though, that there is one way in which I must second-guess the author of the article I just linked to. He ended up using the ‘extern “C”‘ directive in more places than he needed to. If it was something his project set out to do from the beginning, for the source, shared libraries to register their factory functions in an array of function-pointers automatically, then there is really no longer any reason, why their names should not be mangled. In fact, in certain cases conflicts could result, as soon as two functions have the same name, such as “proxy()”. And so, in such cases, there is really only one object in the whole process, the name of which must not be mangled, and in the case cited above, that would be the associative array.

Another fact which the cited article does not mention is simply, that it might result in tedious code, if the factory function was defined separately, for every class of objects that a shared library can export. It might simplify things, if a template Creator class could be defined, which has a factory method as one of its methods, which can be applied to a series of classes that have default constructors… The following article describes a slightly different use:

https://refactoring.guru/design-patterns/factory-method/cpp/example

Of course, the cited function ‘SomeOperation()’ could not be used…

 

//  The following lines should probably go into some header file.

#include <map>
#include <string>
#include <stdlib.h>
#include <stdio.h>
#include <dlfcn.h>

using std::string;

//  If the library existed, either IMPORT or WINDLL would be defined...

typedef std::map<string, void *> function_array;

function_array *reg_factories_p = NULL;

#ifdef WIN32
#define DLL_EXPORT extern "C" __declspec(dllexport)
#define DLL_IMPORT extern "C" __declspec(dllimport)
#else
#define DLL_EXPORT extern "C"
#define DLL_IMPORT extern "C"
#endif

#ifdef WINDLL
DLL_EXPORT function_array reg_factories;
function_array reg_factories;
#else
#ifndef IMPORT
function_array reg_factories;
#endif
#endif

//  What comes below this line, goes into the shared library / DLL.

class Obj_1 {
public:
	Obj_1() {}
};

class Obj_2 {
public:
	Obj_2() {}
};

class Obj_3 {
public:
	Obj_3() {}
};

 
//  Template definition (can't be compiled).
 
template<class T>
class Creator {
public:

	typedef T * (Creator<T>::*method)() const;
	method m_ptr;
	
    Creator(string object_name) {
		m_ptr = &Creator<T>::FactoryMethod;
#ifndef IMPORT
		if (! reg_factories_p) {
			reg_factories_p = &reg_factories;
		}
		reg_factories[object_name] = (void *) this->m_ptr;
#endif
	}
 
    T *FactoryMethod() const {
        return new T;
    }
 
};
 
 
//  Template instantiations (can be compiled).

Creator<Obj_1>  mk1("Object1");
Creator<Obj_2>  mk2("Object2");
Creator<Obj_3>  mk3("Object3");

//  Static objects will be constructed, if the shared library
//  has been opened with 'RTLD_NOW'.
//  This will cause the constructor within 'Creator' to be
//  called, and therefore, the associative array to be populated.


//  Code below this line is meant to go into the client program...

//  The following template class will serve to cast void pointers back
//  to Maker objects, each with a method that makes the object...

#ifndef WINDLL

#define LIB_NAME "./libfunnylib.so"

template<class T>
class Maker {

public:
	typedef T * (*obj_maker) ();
	
	obj_maker m_fptr;

	Maker(void *fptr) {
		m_fptr = reinterpret_cast<obj_maker> (fptr);
	}
	
	T * Make() {
		return (*m_fptr) ();
	}
	
};


int main(int argc, char* argv[]) {

	void *hndl = dlopen(LIB_NAME, RTLD_NOW);
	if(hndl == NULL) {
		printf("%s\n\n", dlerror());
	} else {
		void *symbol = dlsym(hndl, "reg_factories");
		if (symbol) {
			reg_factories_p = (function_array *) symbol;
		} else {
			printf("%s Did not export symbol reg_factories.\n\n", LIB_NAME);
			return -1;
		}
	}
	
    char *buffer;
    size_t bufsize = 32;

	printf("The purpose here is, to find out whether\n");
	printf("I was able to store non-trivial adresses in the\n");
	printf("associative array.\n");
	printf("\n");
	printf("Object1 factory address: %p\n", (*reg_factories_p)["Object1"]);
	printf("Object2 factory address: %p\n", (*reg_factories_p)["Object2"]);
	printf("Object3 factory address: %p\n", (*reg_factories_p)["Object3"]);
	printf("\n");
	printf("Now attempting to execute those factories...\n");
	
	//  Exploiting the compiler's willingness to create temporary
	//  objects, invoked directly by their class-name...
	try {
		Maker<Obj_1>((*reg_factories_p)["Object1"]).Make();
		Maker<Obj_2>((*reg_factories_p)["Object2"]).Make();
		Maker<Obj_3>((*reg_factories_p)["Object3"]).Make();
	} catch (...) {
		printf("Some type of error took place!\n");
		return -1;
	}
	
	printf("All pointer casts executed.\n\n");
	
	printf("Press Enter to quit program.\n");
	
    buffer = (char *) malloc(bufsize * sizeof(char));
    if( buffer == NULL)
    {
        perror("Unable to allocate buffer");
        exit(-1);
    }
	
	getline(&buffer,&bufsize,stdin);
	

	//  We're done. Cleaning up.
	
	free(buffer);
	
	return 0;
}
#endif

 

One fact which must be kept in mind, if this code is ever to be used ‘in the real world’, is, that The associative array should be declared as ‘extern “C”‘ in a header file, but additionally allocated wherever it’s going to be used.  This results in two similar-looking C++ statements, when building the shared library.

Also, compiling this code will generate one warning per factory method, unless, under ‘g++’, the flag ‘-Wno-pmf-conversions‘ is set. Additionally, on Linux computers, linking requires that the flag ‘-ldl‘ be set.

Now, an astute reader will ask, ‘Mainstream code can be compiled without requiring special flags. Why does this guy’s code require that special flags be set?‘ And the answer to that question is, ‘Because this code cheats. The warning which up-to-date compilers will generate – at best – exists, because on some platforms, a pointer-to-method cannot be cast to a pointer-to free function, in the form of a single address, and always work. Therefore, this practice is actually shunned.’

At the end of this posting, I will show compatible code, that does not cheat…

(Updated 3/22/2021, 3h55… )

Continue reading Using Factory Functions to Export C++ Objects from Shared Libraries / DLLs, but also applying Factory Class Design Pattern.

Polynomials: I’ve just made a text-based UI, slightly user-friendlier.

One of the facts which I’ve written about before was, that I had written a C++ program which finds numerical approximations to the roots of polynomials, preferably difficult polynomials to which there can be no exact solution. And one of the facts about my program, which I was never completely satisfied with, had less to do with the actual algorithm that gets closer and closer to each root, but has more to do with how my code could be inaccessible to those readers, who do not already know how to use a compiler.

Specifically, I had written a version of the program which somebody executes from ‘the Command Prompt’, as it’s called under Windows, because under Linux, power-users access features with one-line commands often. Yet, if a user was not such a power-user, then what they might do under Windows could be, just to double-click on the .EXE-File (the Application icon), observe that a console window briefly appears, and then watch it disappear again. There could be users who do not know how to navigate their Command Prompt windows to the folder into which they unzipped the program, and then execute that program from within their Command Prompt / Terminal Window.

And so, even though I kept the code roughly the same – it’s still text-based – I changed it subtly, to help out potential readers who may have had that problem. You may try it and see if you like it. The compressed files can be found at the following location:

https://dirkmittler.homeip.net/binaries/

And, within the table of contents which gets displayed there, the reader would either be interested in the file ‘Roots_Dirk_Mittler.tar.gz‘, or the file ‘Roots_Dirk_Mittler.zip‘ – in either case, the file-name that begins with a single ‘R’.

Enjoy,

Dirk