plugins_manager.cpp 11.8 KB
Newer Older
1
#include "plugins_manager.h"
2 3
#include "rational_function.h"
#include "vertical_segment.h"
4

5
/*
6
#include <QCoreApplication>
7
#include <QDir>
8
*/
9 10

#ifdef WIN32
11
    #include <windows.h>
12 13 14
#else
    #include <dlfcn.h>
#endif
15
#include <stdio.h>
16 17 18 19 20 21 22

//! \brief Open a dynamic library file (.so or .dll) and extract the associated
//! provide function. The template argument is used to cast the library to a
//! specific type.
template<typename T> T open_library(const std::string& filename, const char* function)
{
#ifdef WIN32
23
    HINSTANCE handle = LoadLibraryA(filename.c_str());
24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43
    if(handle != NULL)
    {
        T res = (T)GetProcAddress(handle, function);

        if(res == NULL)
        {
            std::cerr << "<<ERROR>> unable to load the symbol \"" << function << "\" from " << filename << std::endl;
            return NULL;
        }
#ifdef DEBUG_CORE
        std::cout << "<<DEBUG>> will provide a " << function << " for library \"" << filename << "\"" << std::endl;
#endif
        return res;
    }
    else
    {
        std::cerr << "<<ERROR>> unable to load the dynamic library file \"" << filename << "\"" << std::endl;
        std::cerr << "          cause: \"" << GetLastError() << "\"" << std::endl;
        return NULL;
    }
44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62
#else
    void* handle = dlopen(filename.c_str(), RTLD_LAZY);
    if(handle != NULL)
    {
        void* res = dlsym(handle, function);

        if(dlerror() != NULL)
        {
            std::cerr << "<<ERROR>> unable to load the symbol \"" << function << "\" from " << filename << std::endl;
            return NULL;
        }
#ifdef DEBUG_CORE
        std::cout << "<<DEBUG>> will provide a " << function << " for library \"" << filename << "\"" << std::endl;
#endif
        return (T)res;
    }
    else
    {
        std::cerr << "<<ERROR>> unable to load the dynamic library file \"" << filename << "\"" << std::endl;
63
		  std::cerr << "          cause: \"" << dlerror() << "\"" << std::endl;
64 65 66 67 68 69 70
        return NULL;
    }
#endif
}


// Create the object, parse the argument and load all the plugins
71 72
plugins_manager::plugins_manager(const arguments& args) 
{
73
/*
74 75 76 77 78 79 80 81 82
	QDir pluginsDir;
	if(args.is_defined("plugins"))
	{
		pluginsDir = QDir(args["plugins"].c_str()) ;
	}
	else if(QCoreApplication::instance() != NULL)
	{
		pluginsDir = QDir(QCoreApplication::instance()->applicationDirPath());
	}
83
	*/
84

85
	/*
86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138
	foreach (QString fileName, pluginsDir.entryList(QDir::Files)) 
	{
		QPluginLoader loader ;
		loader.setLoadHints(QLibrary::ExportExternalSymbolsHint) ;
		loader.setFileName(pluginsDir.absoluteFilePath(fileName));
		
		// Convert filename for outputing		
		std::string filename(fileName.toStdString()) ;

		if(!loader.load())
		{
#ifdef DEBUG
			std::cout << "<<DEBUG>> " << loader.errorString().toStdString() << std::endl ;
#endif
			continue ;
		}

		QObject *plugin = loader.instance();
		if (plugin != NULL) 
		{
#ifdef DEBUG
			std::cout << "<<DEBUG>> loading plugin " << filename << std::endl ;
#endif
			if(dynamic_cast<function*>(plugin) != NULL)
			{
#ifdef DEBUG
				std::cout << "<<DEBUG>>  -> it is a function" << std::endl ;
#endif
				_functions.insert(std::pair<std::string, function*>(filename, dynamic_cast<function*>(plugin))) ;
			}
			
			if(dynamic_cast<data*>(plugin) != NULL)
			{
#ifdef DEBUG
				std::cout << "<<DEBUG>>  -> it is a data loader" << std::endl ;
#endif
				_datas.insert(std::pair<std::string, data*>(filename, dynamic_cast<data*>(plugin))) ;
			}
			if(dynamic_cast<fitter*>(plugin) != NULL)
			{
#ifdef DEBUG
				std::cout << "<<DEBUG>>  -> it is a fitter" << std::endl ;
#endif
				_fitters.insert(std::pair<std::string, fitter*>(filename, dynamic_cast<fitter*>(plugin))) ;
			}
		}
		else
		{
#ifdef DEBUG
			std::cout << "<<DEBUG>> " << loader.errorString().toStdString() << std::endl ;
#endif
		}
	}
139
	*/
140 141 142 143 144
}

// Get instances of the function, the data and the
// fitter
//
145
function* plugins_manager::get_function()
146
{
147 148 149 150
#ifdef USING_STATIC
    return new rational_function() ;
#else
    if(_functions.empty())
151
	{
152
		return new rational_function() ;
153 154 155 156 157
	}
	else
	{
		return _functions.begin()->second ;
	}
158 159
#endif

160
}
161
data* plugins_manager::get_data()
162
{
Laurent Belcour's avatar
Laurent Belcour committed
163
	//if(_datas.empty())
164
	{
165 166 167
#ifdef DEBUG
        std::cout << "<<DEBUG>>  using vertical segment data loader" << std::endl ;
#endif
168
		return new vertical_segment() ;
Laurent Belcour's avatar
Laurent Belcour committed
169
	}/*
170 171
	else
	{
172
#ifdef DEBUG
173
		std::cout << "<<DEBUG>>  using \"" << _datas.begin()->first << "\" data loader" << std::endl ;
174
#endif
175
		return _datas.begin()->second ;
Laurent Belcour's avatar
Laurent Belcour committed
176
	}*/
177
}
178
fitter* plugins_manager::get_fitter()
179
{
180 181 182
#ifdef USING_STATIC
    return NULL;
#else
183 184 185 186 187 188
	if(_fitters.empty())
	{
		return NULL ;
	}
	else
	{
189
#ifdef DEBUG
190
		std::cout << "<<DEBUG>>  using \"" <<  _fitters.begin()->first << "\"" << std::endl ;
191
#endif
192 193
		return _fitters.begin()->second ;
	}
194
#endif
195 196
}

197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254

		
//! \brief load a function from the ALTA input file.
function* plugins_manager::get_function(const std::string& filename)
{
	std::ifstream file;
	file.open(filename.c_str()) ;
	if(!file.is_open())
	{
		std::cerr << "<<ERROR>> unable to open file \"" << filename << "\"" << std::endl ;
		throw ;
	}

	// Parameters of the function object
	int nX, nY;
	arguments args;

	// Test for the first line of the file. Should be a ALTA FUNC HEADER
	std::string line ;
	std::getline(file, line) ;
	if(line != "#ALTA FUNC HEADER")
	{
		std::cerr << "<<ERROR>> this is not a function file" << std::endl;
	}

	// Parse the header for the function command line and the dimension
	// of the function
	while(line != "#ALTA HEADER END")
	{
		std::getline(file, line) ;
		std::stringstream linestream(line) ;

		linestream.ignore(1) ;

		std::string comment ;
		linestream >> comment ;

		if(comment == std::string("DIM"))
		{
			linestream >> nX >> nY ;
		}
		else if(comment == std::string("CMD"))
		{
			args = arguments::create_arguments(line.substr(4, std::string::npos));
		}
	}

	// Create the function from the command line
	function* f = get_function(args);
	f->setDimX(nX);
	f->setDimY(nY);

	// Load the function part from the file object
	//f->load(file);

	return f;
}

255 256 257
//! Get an instance of the function selected based on the name <em>n</em>.
//! Return NULL if no one exist.
function* plugins_manager::get_function(const arguments& args)
258
{
259
    if(!args.is_defined("func"))
260 261 262 263 264 265 266
    {
#ifdef DEBUG
        std::cout << "<<DEBUG>> no function plugin specified, returning a rational function" << std::endl;
#endif
        return new rational_function();
    }

267 268
    // The function to be returned.
    function* func = NULL;
Laurent Belcour's avatar
Laurent Belcour committed
269

270
    if(args.is_vec("func"))
271
    {
272 273 274 275 276 277 278 279
        std::vector<std::string> args_vec = args.get_vec("func");

        // Treating the case []
        if(args_vec.size() == 0)
        {
            return NULL;
        }

280
        //! create a <em>compound</em> class to store multiple
281
        //! functions in it.
282 283
		  compound_function* compound = new compound_function();
	
284 285
        //! For each args_vec element, create a function object and add
        //! it to the compound one.
286 287 288 289
		  for(int i=0; i<args_vec.size(); ++i)
		  {
	        std::string n("--func ");
	        n.append(args_vec[i]);
290

291 292 293 294 295 296 297 298 299 300
			  function* f = get_function(arguments::create_arguments(n));
			  if(dynamic_cast<nonlinear_function*>(f) == NULL)
			  {
				  std::cerr << "<<ERROR>> only non-linear function care compatible with a compound" << std::endl;
			  }
			  else
			  {
				  compound->push_back(dynamic_cast<nonlinear_function*>(f));
			  }
		  }
301

302 303
		  //! return the compound class
		  func = compound;
304 305 306
    }
    else
    {
307 308 309 310 311 312
        std::string filename = args["func"];
        FunctionPrototype myFunction = open_library<FunctionPrototype>(filename, "provide_function");
        if(myFunction != NULL)
        {
#ifdef DEBUG
            std::cout << "<<DEBUG>> using function provider in file \"" << filename << "\"" << std::endl;
313
#endif
314
            func =  myFunction();
315 316 317 318 319 320
        }
        else
        {
            std::cerr << "<<ERROR>> no function provider found in file \"" << filename << "\"" << std::endl;
            return new rational_function() ;
        }
321 322
    }

323 324 325
    // Treat the case of the Fresnel
    if(args.is_defined("fresnel"))
    {
326 327 328 329 330 331 332 333
		 // Cast into a non linear function, only those are permitted to use
		 // a Fresnel term.
		 nonlinear_function* nl_func = dynamic_cast<nonlinear_function*>(func);
		 if(nl_func == NULL)
		 {
			 std::cerr << "<<ERROR>> only non-linear function are permitted to use Fresnel" << std::endl;
			 return func;
		 }
334

335
		 std::cout << "<<DEBUG>> multiplying by a Fresnel term" << std::endl;
336

337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357
		 std::string n("--func ");
		 if(args.is_vec("fresnel"))
		 {
			 std::string temp = args["fresnel"];
			 n.append(temp.substr(1, temp.size()-2));
		 }
		 else
		 {
			 std::string fname = args["fresnel"];
			 if(fname.empty()) // Nothing to do except print error, no plugin defined
			 {
				 std::cerr << "<<ERROR>> Fresnel plugin not defined" << std::endl;
				 std::cerr << "<<ERROR>> using --fresnel alone is not permitted" << std::endl;
				 return func;
			 }
			 else // Case where the fresnel parameters is only the plugin filename
			 {
				 n.append(fname);
			 }
		 }

358
		 fresnel* func_fres = dynamic_cast<fresnel*>(get_function(arguments::create_arguments(n)));
359
		 func_fres->setBase(nl_func);
360 361
		 return func_fres;

362
	 }
363 364

    return func;
365
}
366
data* plugins_manager::get_data(const std::string& n)
367
{
368 369
    if(n.empty())
    {
370
#ifdef DEBUG
371
        std::cout << "<<DEBUG>> no data plugin specified, returning a vertial_segment loader" << std::endl;
372
#endif
373 374 375
        return new vertical_segment();
    }

376
	 DataPrototype myData = open_library<DataPrototype>(n, "provide_data");
377 378
    if(myData != NULL)
    {
379
#ifdef DEBUG
380 381 382 383 384 385 386 387 388
        std::cout << "<<DEBUG>> using function provider in file \"" << n << "\"" << std::endl;
#endif
        return myData();
    }
    else
    {
        std::cerr << "<<ERROR>> no data provider found in file \"" << n << "\"" << std::endl;
        return new vertical_segment() ;
    }
389
}
390
fitter* plugins_manager::get_fitter(const std::string& n)
391
{
Laurent Belcour's avatar
Laurent Belcour committed
392 393 394 395 396 397 398 399
    if(n.empty())
    {
#ifdef DEBUG
        std::cout << "<<DEBUG>> no fitter plugin specified, returning null" << std::endl;
#endif
        return NULL;
    }

400
    FitterPrototype myFitter = open_library<FitterPrototype>(n, "provide_fitter");
Laurent Belcour's avatar
Laurent Belcour committed
401 402 403 404 405 406 407 408 409
    if(myFitter != NULL)
    {
#ifdef DEBUG
        std::cout << "<<DEBUG>> using function provider in file \"" << n << "\"" << std::endl;
#endif
        return myFitter();
    }
    else
    {
410 411
        std::cerr << "<<ERROR>> no fitter provider found in file \"" << n << "\"" << std::endl;
        return NULL ;
Laurent Belcour's avatar
Laurent Belcour committed
412
    }
413
}
414

Laurent Belcour's avatar
Laurent Belcour committed
415 416 417
void plugins_manager::check_compatibility(data*& d, function*& f,
                                          const arguments& args)
{
418
	if(d->input_parametrization() == params::UNKNOWN_INPUT)
Laurent Belcour's avatar
Laurent Belcour committed
419 420 421 422
	{
		std::cout << "<<WARNING>> unknown parametrization for data" << std::endl;
	}

423
	if(f->input_parametrization() == params::UNKNOWN_INPUT)
Laurent Belcour's avatar
Laurent Belcour committed
424 425
	{
		std::cout << "<<DEBUG>> function will take the parametrization of the data" << std::endl;
426
		f->setParametrization(d->input_parametrization());
Laurent Belcour's avatar
Laurent Belcour committed
427
	}
428
	else if(d->input_parametrization() != f->input_parametrization())
Laurent Belcour's avatar
Laurent Belcour committed
429 430
	{
		std::cout << "<<INFO>> has to change the parametrization of the input data" << std::endl;
431
		data_params* dd = new data_params(d, f->input_parametrization());
Laurent Belcour's avatar
Laurent Belcour committed
432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452
		d = dd ;
	}
	else
	{
		std::cout << "<<DEBUG>> no change was made to the parametrization" << std::endl;
	}

	if(f->dimY() != d->dimY())
	{
		std::cout << "<<WARNING>> the data and the function have different Y dimensions" << std::endl;
	}

	/*
	// Check is the data has to be clusterized
	if(args.is_defined("cluster-dim"))
	{
	clustering* cluster = new clustering(d, args);
	d = cluster;
	}
	*/
}
453 454 455 456
		
// \todo implement the Darwin (MACOS) version.
#ifdef WIN32
#include <windows.h>
457
size_t plugins_manager::get_system_memory()
458 459 460 461 462 463 464 465
{
	MEMORYSTATUSEX status;
	status.dwLength = sizeof(status);
	GlobalMemoryStatusEx(&status);
	return status.ullTotalPhys;
}
#else
#include <unistd.h>
466
size_t plugins_manager::get_system_memory()
467 468 469 470 471 472
{
	long pages = sysconf(_SC_PHYS_PAGES);
	long page_size = sysconf(_SC_PAGE_SIZE);
	return pages * page_size;
}
#endif