Atomic operations with double, OpenCL - double

I would like to know if there's a way to implement atomic operations (particularly atomic_add) with double type.
For floats this code works, but atomic_xchg doesn't support double:
while ((value = atomic_xchg(addr, atomic_xchg(addr, 0.0f)+value))!=0.0f);

I was looking for for the same in the past and I found this: https://github.com/ddemidov/vexcl-experiments/blob/master/sort-by-key-atomic.cpp.
At the end I figured out different approach to my problem so I did not use it. Here is the code:
"#pragma OPENCL EXTENSION cl_khr_fp64: enable\n"
"#pragma OPENCL EXTENSION cl_khr_int64_base_atomics: enable\n"
"void AtomicAdd(__global double *val, double delta) {\n"
" union {\n"
" double f;\n"
" ulong i;\n"
" } old;\n"
" union {\n"
" double f;\n"
" ulong i;\n"
" } new;\n"
" do {\n"
" old.f = *val;\n"
" new.f = old.f + delta;\n"
" } while (atom_cmpxchg ( (volatile __global ulong *)val, old.i, new.i) != old.i);\n"
"}\n"
"kernel void atomic_reduce(\n"
" ulong n,\n"
" global const int * key,\n"
" global const double * val,\n"
" global double * sum\n"
")\n"
"{\n"
" for(size_t idx = get_global_id(0); idx < n; idx += get_global_size(0))\n"
" AtomicAdd(sum + key[idx], val[idx]);\n"
"}\n",
"atomic_reduce"

Both approaches of initial post and the answer by doqtor work well. Basically there are two ways to implement them on doubles: using unions or using OpenCL as_type functions. OpenCL 1.0 code snippets are presented at the end of the answer (for OpenCL 2.x they can be shortened, but NVIDIA does not support it as of yet). As for performance, I personally have experience on AMD OpenCL realization on Tahiti chips that all these variants produce more or less the same execution time (as_ and union variants even produce the same optimized ISA code on most tested compilers). So using one variant or another is a matter of personal taste.
// define REALDOUBLES for double precision, undefine for single
#if REALDOUBLES
// extensions needed
#pragma OPENCL EXTENSION cl_khr_fp64 : enable
#ifdef cl_khr_int64_base_atomics
#pragma OPENCL EXTENSION cl_khr_int64_base_atomics : enable
#endif
// definitions
#define UINTVAR ulong
#define AS_INT as_ulong
#define AS_REAL as_double
#define ATOM_CMPXCHG atom_cmpxchg
#define ATOM_XCHG atom_xchg
#else
// extensions needed
#ifdef cl_khr_local_int32_base_atomics
#pragma OPENCL EXTENSION cl_khr_local_int32_base_atomics : enable
#endif
#ifdef cl_khr_global_int32_base_atomics
#pragma OPENCL EXTENSION cl_khr_global_int32_base_atomics : enable
#endif
// definitions
#define UINTVAR uint
#define AS_INT as_uint
#define AS_REAL as_float
#define ATOM_CMPXCHG atomic_cmpxchg
#define ATOM_XCHG atomic_xchg
#endif
// as_ variants
// variant from GROMACS - https://streamhpc.com/blog/2016-02-09/atomic-operations-for-floats-in-opencl-improved/
inline void atomic_add_local(volatile local REAL * const source, const REAL operand) {
UINTVAR expected, current;
current = AS_INT(*source);
do {
expected = current;
current = ATOM_CMPXCHG((volatile local UINTVAR *)source, expected, AS_INT(AS_REAL(expected) + operand));
} while (current != expected);
}
// NVIDIA variant
inline void atomic_add_local(local REAL * const source, const REAL operand) {
UINTVAR old = AS_INT(operand);
while ((old = ATOM_XCHG((local UINTVAR *)source, AS_INT(AS_REAL(ATOM_XCHG((local UINTVAR *)source, AS_INT((REAL)0))) + AS_REAL(old)))) != AS_INT((REAL)0));
}
// union variants
typedef union {
UINTVAR intVal;
REAL floatVal;
} uni;
// NVIDIA variant
inline void atomic_add_local(local REAL * const source, const REAL operand) {
uni old, t, zero;
old.floatVal = operand;
zero.floatVal = 0;
do {
t.intVal = ATOM_XCHG((local UINTVAR *)source, zero.intVal);
t.floatVal += old.floatVal;
} while ((old.intVal = ATOM_XCHG((local UINTVAR *)source, t.intVal)) != zero.intVal);
}
// shortened variant from GROMACS - https://streamhpc.com/blog/2016-02-09/atomic-operations-for-floats-in-opencl-improved/
inline void atomic_add_local(volatile local REAL * const source, const REAL operand) {
uni expected, current;
current.floatVal = *source;
do {
expected.floatVal = current.floatVal;
current.floatVal = expected.floatVal + operand;
current.intVal = ATOM_CMPXCHG((volatile local UINTVAR *)source, expected.intVal, current.intVal);
} while (current.intVal != expected.intVal);
}
And obvious replacement local<->global for global memory.

Related

Implicit conversion between c++11 clocks/time_points

Is it possible to do implicit/explicit conversion between time_points of two C++11 clocks?
Motivation: chrono::durations provide means of storing time intervals from epoch, conceptually is not equal to a time_point of a custom clock that has an epoch on its own.
Having an implicit conversion between clocks eases up the use Howard Hinnant's date library <date/date.h> which provides means to manipulate and print out time_points of system clocks.
Example:
#include <date/date.h>
using namespace date;
namespace ch = std::chrono;
//
#define EPOCH_OFFSET 100
template<class Duration> using PosixTimePoint =
ch::time_point<ch::system_clock, Duration>;
typedef PosixTimePoint<ch::duration<long,std::micro>> PosixTimePointType;
struct SomeClock{
typedef ch::duration<long,std::micro> duration;
typedef ch::time_point<SomeClock> time_point;
...
static time_point now() noexcept {
using namespace std::chrono;
return time_point (
duration_cast<duration>(
system_clock::now().time_since_epoch()) + date::years(EPOCH_OFFSET) );
}
static PosixTimePoint<duration> to_posix( const time_point& tp ){...}
}
auto tp = SomeClock::now(); //<time_point<SomeClock,ch::duration<long,std::micro>>;
Objective: to convert tp so the std::stream conversions of date.h works and prints out the current time, which in my case is: 2017-12-24 17:02:56.000000
// std::cout << tp; compile error
std::cout << SomeClock::to_posix( tp ); // OK
Explicit cast: this could ease up readability, support conversion feature of the language and facilitate access to date.h routines.
long time_value = static_cast<long>( tp );
auto st = static_cast<PosixTimePointType>( tp );
std::cout << static_cast<PosixTimePointType>( tp );
I recommend mimicking the implementations of either date::utc_clock or date::tai_clock found in tz.h. For example utc_clock implements two functions to convert to and from sys_time:
template<typename Duration>
static
std::chrono::time_point<std::chrono::system_clock, typename std::common_type<Duration, std::chrono::seconds>::type>
to_sys(const std::chrono::time_point<utc_clock, Duration>&);
template<typename Duration>
static
std::chrono::time_point<utc_clock, typename std::common_type<Duration, std::chrono::seconds>::type>
from_sys(const std::chrono::time_point<std::chrono::system_clock, Duration>&);
So you can think of std::chrono::system_clock as a "hub". Any clock that implements these conversions can convert to any other clock which implements these conversions by bouncing off of system_clock under the covers. And to facilitate that bounce, date::clock_cast is introduced.
Additionally, utc_time can be used as the hub, if that is more efficient for your type. For example tai_clock implements:
template<typename Duration>
static
std::chrono::time_point<utc_clock, typename std::common_type<Duration, std::chrono::seconds>::type>
to_utc(const std::chrono::time_point<tai_clock, Duration>&) NOEXCEPT;
template<typename Duration>
static
std::chrono::time_point<tai_clock, typename std::common_type<Duration, std::chrono::seconds>::type>
from_utc(const std::chrono::time_point<utc_clock, Duration>&) NOEXCEPT;
clock_cast is smart enough to deal with this "dual-hub" system, so one can convert a clock that converts to/from utc_time, to another clock that uses sys_time as its hub.
If you also implement to_stream for your clock, then you can directly use format to format your clock::time_point. And clock_cast is likely to be useful in the implementation of your to_stream function.
Also from_stream can be used to hook your clock::time_point up to date::parse.
Search https://howardhinnant.github.io/date/tz.html for "clock_cast" for example uses of it. For your use case the to_sys/from_sys API appears to be the most useful. Just these two functions will allow you to use clock_cast between your SomeClock and any other clock in tz.h (and any other custom clock that meets these requirements).
Full Demo
#include "date/tz.h"
#include <iostream>
#include <sstream>
struct SomeClock
{
using duration = std::chrono::microseconds;
using rep = duration::rep;
using period = duration::period;
using time_point = std::chrono::time_point<SomeClock>;
static constexpr bool is_steady = false;
static time_point now() noexcept
{
return from_sys(date::floor<duration>(std::chrono::system_clock::now()));
}
static constexpr auto offset = date::sys_days{} - date::sys_days{date::year{1870}/1/1};
template<typename Duration>
static
date::sys_time<Duration>
to_sys(const std::chrono::time_point<SomeClock, Duration>& t)
{
return date::sys_time<Duration>{(t - offset).time_since_epoch()};
}
template<typename Duration>
static
std::chrono::time_point<SomeClock, Duration>
from_sys(const date::sys_time<Duration>& t)
{
return std::chrono::time_point<SomeClock, Duration>{(t + offset).time_since_epoch()};
}
};
template <class Duration>
using SomeTime = std::chrono::time_point<SomeClock, Duration>;
constexpr date::days SomeClock::offset;
template <class CharT, class Traits, class Duration>
std::basic_ostream<CharT, Traits>&
to_stream(std::basic_ostream<CharT, Traits>& os, const CharT* fmt,
const SomeTime<Duration>& t)
{
return date::to_stream(os, fmt, date::clock_cast<std::chrono::system_clock>(t));
}
template <class CharT, class Traits, class Duration>
std::basic_ostream<CharT, Traits>&
operator<<(std::basic_ostream<CharT, Traits>& os, const SomeTime<Duration>& t)
{
const CharT fmt[] = {'%', 'F', ' ', '%', 'T', CharT{}};
return to_stream(os, fmt, t);
}
template <class Duration, class CharT, class Traits, class Alloc = std::allocator<CharT>>
std::basic_istream<CharT, Traits>&
from_stream(std::basic_istream<CharT, Traits>& is, const CharT* fmt,
SomeTime<Duration>& tp, std::basic_string<CharT, Traits, Alloc>* abbrev = nullptr,
std::chrono::minutes* offset = nullptr)
{
using namespace date;
sys_time<Duration> st;
date::from_stream(is, fmt, st, abbrev, offset);
if (!is.fail())
tp = clock_cast<SomeClock>(st);
return is;
}
int
main()
{
std::cout << SomeClock::now() << '\n';
std::cout << date::format("%a, %b %d, %Y\n", SomeClock::now());
std::istringstream in{"2017-12-24 19:52:30"};
SomeClock::time_point t;
in >> date::parse("%F %T", t);
std::cout << t << '\n';
}

Access to OS functions from CAPL

I'm doing a script using CAPL and am stuck for a solution to grep the login ID from Windows. Could some please help show how to get Windows user login ID from within a CAPL program code, if this is possible?
For example, if the Windows user login ID is 'kp21ml' , I want to read this ID from a CAPL function, as shown below.
byte UserIdCheck()
{
char uid[10];
byte CanMessageTrasmission;
strncpy(uid, xxxx(), 6); // where xxxx() is the unknown OS or system function that could return the login ID ?
if (strncmp(uid, "kp21ml") != 0)
{
write("Access denied!"); // Message to CANoe's Write window
CanMessageTrasmission = 0;
}
else
{
// Access ok
CanMessageTrasmission = 1;
}
return CanMessageTrasmission;
}
I use this CAPL book as my reference guide, which is very good:
http://docplayer.net/15013371-Programming-with-capl.html
But I couldn't find anything to do with system access. I would appreciate your help.
Thanks
Juno
I'm afraid you won't be able to do that directly from a CAPL script.
I generally create a CAPL-DLL and include that in my CANoe project when I need to access some OS level functionality. Though I use it mostly for accessing an external device (e.g. USB) or to interact with another program using sockets over local host, the principle is the same.
You can find more information in CANoe's documentation with examples but the CAPL-DLL source code provided in CANoe samples is a little difficult to understand.
I've attempted to strip some of the "unnecessary" parts in the following code sample; this example will create a CAPL-DLL which "exposes" the multiplyBy10 function and basically allows you to call multiplyBy10 from you CAPL script):
#define USECDLL_FEATURE
#define _BUILDNODELAYERDLL
#pragma warning( disable : 4786 )
#include "cdll.h"
#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <map>
char moduleName[_MAX_FNAME];
HINSTANCE moduleHandle;
unsigned int
CAPLEXPORT far CAPLPASCAL multiplyBy10 (unsigned char value)
{
unsigned int result = value * 10;
freopen("CONOUT$", "w", stdout);
std::cout << "multiplyBy10() - value: " << int(value) << ", result: " << result << std::endl;
return (result);
}
CAPL_DLL_INFO4 table[] =
{
{CDLL_VERSION_NAME, (CAPL_FARCALL)CDLL_VERSION, "", "", CAPL_DLL_CDECL, 0xABD, CDLL_EXPORT},
{"multiplyBy10", (CAPL_FARCALL)multiplyBy10, "CAPL_DLL", "This is a demo function", 'L', 1, "D", "", { "value"}},
{0, 0}
};
CAPLEXPORT CAPL_DLL_INFO4 far * caplDllTable4 = table;
bool
WINAPI DllMain(HINSTANCE handle, DWORD reason, void*)
{
static FILE * stream;
switch (reason)
{
case DLL_PROCESS_ATTACH:
{
moduleHandle = handle;
char path_buffer[_MAX_PATH];
DWORD result = GetModuleFileName(moduleHandle, path_buffer, _MAX_PATH);
char drive[_MAX_DRIVE];
char dir[_MAX_DIR];
char fname[_MAX_FNAME];
char ext[_MAX_EXT];
_splitpath_s(path_buffer, drive, dir, fname, ext);
strcpy_s(moduleName, fname);
AllocConsole();
freopen_s(&stream, "conout$", "w", stdout);
std::cout << "DLL_PROCESS_ATTACH" << std::endl;
return 1;
}
case DLL_PROCESS_DETACH:
{
std::cout << "DLL_PROCESS_DETACH" << std::endl;
FreeConsole();
fclose(stream);
return 1;
}
}
return 1;
}

print floats from audio input callback function

I'm working on a university project that involves a lot of programming in C, especially with Portaudio & ALSA. At the moment i'm trying to make a callback function to pass audio through, standard input/output job. I was wondering if anybody could tell me how to print the floats from my inputBuffer to display in real time in the terminal? Here is the internal structure of my callback function so far.
Thanks very much for your help in advance!
#define SAMPLE_RATE (44100)
#define PA_SAMPLE_TYPE paFloat32
#define FRAMES_PER_BUFFER (64)
typedef float SAMPLE;
static int audio_callback( const void *inputBuffer, void *outputBuffer,
unsigned long framesPerBuffer,
const PaStreamCallbackTimeInfo* timeInfo,
PaStreamCallbackFlags statusFlags,
void *userData )
{
SAMPLE *out = (SAMPLE*)outputBuffer;
const SAMPLE *in = (const SAMPLE*)inputBuffer;
unsigned int i;
(void) timeInfo; /* Prevent unused variable warnings. */
(void) statusFlags;
(void) userData;
if( inputBuffer == NULL )
{
for( i=0; i<framesPerBuffer; i++ )
{
*out++ = *in++; /* left - clean */
*out++ = *in++; /* right - clean */
}
}
return paContinue;
}

how to get the parameters from s-function block in legacy code tool

i am working on tunable parameters and with a manual s-function its pretty straight forward. but what to do when we want to make variables tunable (getting them as parameters from s-function parameter block ) and generating the s-function automatically using the legacy code tool.
is it even possible?
for example i have written a simple single track model. This is the single_track.h file
#ifndef _SINGLE_TRACK_FUNC_
#define _SINGLE_TRACK_FUNC_
typedef struct retvale
{
double a_y;
double psi_dot;
double beta;
} retvale;
extern struct retvale singletrack(double a,double b,double m,double cv,double ch,double lv,double lh,double theta,double I_s, double dt);
extern void initialization();
#endif
this is the single_track.c file
#include "single_track_func.h"
float a_1_1,a_1_2,a_2_1,a_2_2,b_1_1,b_2_1,psi_dot_prev,beta_prev;
int count;
retvale singletrack(double a,double b,double m,double cv,double ch,double lv,double lh,double theta,double I_s, double dt)
{
retvale my_obj;
static float beta_dot=0;
static float psi_double_dot=0;
static float beta_previous=0;
static float psi_dot_previous=0;
beta_previous = beta_prev;
psi_dot_previous = psi_dot_prev;
a_1_1 = ((-cv-ch)/((m)*(a)));
a_1_2 = ((m*(a)*(a))-((ch*lh)-(cv*lv)))/(m*(a)*(a));
a_2_1 = (-(ch*lh)+(cv*lv))/theta;
a_2_2 = ((-ch*lh*lh)-(cv*lv*lv))/(theta*(a));
b_1_1 = -cv/(m*(a));
b_2_1 = (cv*lv)/(theta);
beta_dot = a_1_1 * beta_previous + a_1_2 * psi_dot_previous - b_1_1*((b)/I_s);
psi_double_dot = a_2_1 * beta_previous + a_2_2 * psi_dot_previous + b_2_1*((b)/I_s);
my_obj.beta = beta_dot * dt + beta_previous;
my_obj.psi_dot = psi_double_dot * dt + psi_dot_previous;
my_obj.a_y = (a*((my_obj.psi_dot)-(beta_dot)));
beta_prev=my_obj.beta;
psi_dot_prev=my_obj.psi_dot;
return my_obj;
}
void initialization()
{
psi_dot_prev=0;
beta_prev=0;
}
the arguments from double m till double dt are the inputs which i expect as parameters from the s-function block while the 'double a' and 'double b' values i will get from inputs so i don't have to worry about them.
manually i introduced some global variables in my s-function in mdlInitializeSize
ssSetNumSFcnParams(S, 8);
m_s=mxGetPr(ssGetSFcnParam(S,0));
cv_s=(real_T*) mxGetPr(ssGetSFcnParam(S,1));
ch_s=(real_T*) mxGetPr(ssGetSFcnParam(S,2));
lv_s=(real_T*)mxGetPr(ssGetSFcnParam(S,3));
lh_s=(real_T*)mxGetPr(ssGetSFcnParam(S,4));
theta_s=(real_T*)mxGetPr(ssGetSFcnParam(S,5));
I_s_s=(real_T*)mxGetPr(ssGetSFcnParam(S,6));
dt_s=(real_T*)mxGetPr(ssGetSFcnParam(S,7));
ssSetSFcnParamTunable(S,0,SS_PRM_SIM_ONLY_TUNABLE);
ssSetSFcnParamTunable(S,1,SS_PRM_SIM_ONLY_TUNABLE);
ssSetSFcnParamTunable(S,2,SS_PRM_SIM_ONLY_TUNABLE);
ssSetSFcnParamTunable(S,3,SS_PRM_SIM_ONLY_TUNABLE);
ssSetSFcnParamTunable(S,4,SS_PRM_SIM_ONLY_TUNABLE);
ssSetSFcnParamTunable(S,5,SS_PRM_SIM_ONLY_TUNABLE);
ssSetSFcnParamTunable(S,6,SS_PRM_SIM_ONLY_TUNABLE);
ssSetSFcnParamTunable(S,7,SS_PRM_SIM_ONLY_TUNABLE);
this works manually but how to put it in legacy code such that it works automatically
i have written legacy code previously where I was using predefined values and it worked fine:
run('CreateBusObject_retvale');
def = legacy_code('initialize');
def.SourceFiles = {'single_track_func.c'};
def.HeaderFiles = {'single_track_func.h'};
def.SFunctionName = 'single_track_1';
def.StartFcnSpec ='void initialization()';
def.OutputFcnSpec ='retvale y1=singletrack(double u1,double u2, double u3,)';
def.SampleTime = [-1,0];
legacy_code('sfcn_cmex_generate', def);
legacy_code('compile', def);
legacy_code('sfcn_tlc_generate', def);
and CreateBusObject_retvale.m is
a_y=Simulink.BusElement;
a_y.Name='a_y';
a_y.DataType='double';
psi_dot=Simulink.BusElement;
psi_dot.Name='psi_dot';
psi_dot.DataType='double';
beta=Simulink.BusElement;
beta.Name='beta';
beta.DataType='double';
retvale = Simulink.Bus;
retvale.HeaderFile = 'single_track_func.h';
retvale.Elements = [a_y,psi_dot,beta];
outputBus = Simulink.BusElement;
outputBus.Name = 'outputBus';
outputBus.DataType = 'Bus: retvale';

Command line parser for Qt4

I am looking for a command line parser for Qt4.
I did a small google search, and found this: http://www.froglogic.com/pg?id=PublicationsFreeware&category=getopt however it lacks support for "--enable-foo" and "--disable-foo" switches. Besides that, it looks like a real winner.
EDIT:
It seems Frologic removed this. So the best options I see are using Boost (which is not API nor ABI stable) or forking the support for kdelibs. Yay...
QCoreApplication's constructors require (int &argc, char **argv) (and QApplication inherits from QCoreApplication). As the documentation states, it is highly recommended that
Since QApplication also deals with common command line arguments, it is usually a good idea to create it before any interpretation or modification of argv is done in the application itself.
And if you're letting Qt get the first pass at handling arguments anyways, it would also be a good idea to use QStringList QCoreApplication::arguments() instead of walking through argv; QApplication may remove some of the arguments that it has taken for its own use.
This doesn't lend itself to being very compatible with other argument-parsing libraries...
However, kdelibs does come with a nice argument parser, KCmdLineArgs. It is LGPL and can be used without KApplication if you really want (call KCmdLineArgs::init).
KCmdLineOptions options;
options.add("enable-foo", ki18n("enables foo"));
options.add("nodisable-foo", ki18n("disables foo"));
// double negatives are confusing, but this makes disable-foo enabled by default
KCmdLineArgs::addCmdLineOptions(options);
KApplication app;
KCmdLineArgs *args = KCmdLineArgs::parsedArgs();
if (args->isSet("enable-foo") && !args->isSet("disable-foo"))
cout << "foo enabled" << endl;
else
cout << "foo disabled" << endl;
Untested (who ever tests what they post on S.O.?).
Since Qt 5.2 you can finally find a solution in QtCore itself: I contributed QCommandLineParser there.
This is more or less the same answer as ephemient, but with a simple regexp to help parse the args. (This way could be useful if you only need a handful of args)
Run with this:
./QArgTest --pid=45 --enable-foo
And the code:
int main(int argc, char *argv[]) {
QApplication app(argc, argv, false);
qDebug() << "QApp arg test app";
QStringList args = app.arguments();
int pid = 0;
QRegExp rxArgPid("--pid=([0-9]{1,})");
QRegExp rxArgFooEna("--enable-foo");
QRegExp rxArgFooDis("--disable-foo");
for (int i = 1; i < args.size(); ++i) {
if (rxArgPid.indexIn(args.at(i)) != -1 ) {
pid = rxArgPid.cap(1).toInt();
qDebug() << i << ":" << args.at(i) << rxArgPid.cap(1) << pid;
}
else if (rxArgFooEna.indexIn(args.at(i)) != -1 ) {
qDebug() << i << ":" << args.at(i) << "Enable Foo";
}
else if (rxArgFooDis.indexIn(args.at(i)) != -1 ) {
qDebug() << i << ":" << args.at(i) << "Disable Foo";
}
else {
qDebug() << "Uknown arg:" << args.at(i);
}
}
return 0;
}
There is also QxtCommandOptions from http://www.libqxt.org/
That package does support --disable-foo and --enable-foo via opts.addSwitch("disable-foo", &foo_disabled); and opts.addSwitch("enable-foo", &foo_enabled);. You need handle checking both, and dealing with someone specifying both (oops).
What I don't understand is how this has anything to do with QT4...
Look at this: http://code.google.com/p/qtargparser/
A really simple method is to scan "key=value" args,
put them in a table say zz.map: QString -> QVariant,
and get their values with zz.map.value( key, default ).
An example:
#include "ztest.h"
Ztest zz;
int main( int argc, char* argv[] )
{
zz.eqargs( ++ argv ); // scan test=2 x=str ... to zz.map
QString xx = zz.map.value( "xx", "" );
if( Zint( Size, 10 )) // a #def -> zz.map.value( "Size", 10 )
...
ztest.h is < 1 page, below; same for Python ~ 10 lines.
(Everybody has his/her favorite options parser;
this one's about the simplest.
Worth repeating: however you specify options, echo them to output files --
"every scientist I know has trouble keeping track
of what parameters they used last time they ran a script".)
To make QPoints etc work one of course needs a QString -> QPoint parser.
Anyone know offhand why this doesn't work (in Qt 4.4.3) ?
QPoint pt(0,0);
QDataStream s( "QPoint(1,2)" );
s >> pt;
qDebug() << "pt:" << pt; // QPoint(1364225897,1853106225) ??
Added 25nov --
// ztest.h: scan args x=2 s=str ... to a key -> string table
// usage:
// Ztest ztest;
// int main( int argc, char* argv[] )
// {
// QApplication app( argc, argv );
// ztest.eqargs( ++ argv ); // scan leading args name=value ...
// int x = Zint( x, 10 ); // arg x= or default 10
// qreal ff = Zreal( ff, 3.14 );
// QString s = Zstr( s, "default" );
// care: int misspelled = Zint( misspellled ) -- you lose
//version: 2009-06-09 jun denis
#ifndef ztest_h
#define ztest_h
#include <QHash>
#include <QString>
#include <QVariant>
#include <QRegExp>
//------------------------------------------------------------------------------
class Ztest {
public:
QHash< QString, QVariant > map;
int test; // arg test=num, if( ztest.test )
Ztest() : test( 0 ) {}
QVariant val( const QString& key, const QVariant& default_ = 0 )
{
return map.value( key, default_ );
}
void setval( const QString& key, const QVariant& val )
{
map[key] = val;
if( key == "test" || key == "Test" )
test = val.toInt();
}
//------------------------------------------------------------------------------
// ztest.eqargs( ++ argv ) scans test=2 x=3 ... -> ztest table
void eqargs( char** argv )
{
char** argv0 = argv;
char *arg;
QRegExp re( "(\\w+)=(.*)" ); // name= anything, but not ./file=name
for( ; (arg = *argv) && re.exactMatch( arg ); argv ++ ){
setval( re.cap(1), re.cap(2) );
}
// change argv[0..] -> args after all name=values
while(( *argv0++ = *argv++) != 0 ) {}
}
};
extern Ztest ztest;
// macros: int x = Zint( x, 10 ): x= arg or default 10
#define Zstr( key, default ) ztest.val( #key, default ).toString()
#define Zint( key, default ) ztest.val( #key, default ).toInt()
#define Zreal( key, default ) ztest.val( #key, default ).toDouble()
#endif
It's 2013 and still no "1st party" arg parser. Anyways..if anyone finds themselves facing the same problem and would like to avoid the learning curves that come with cmd parser libs, here is a "quick & dirty" fix for you:-
QString QArgByKey(QString key, QChar sep = QChar('\0') ) //prototype usually in separate header
QString QArgByKey(QString key, QChar sep )
{
bool sepd=sep!=QChar('\0');
int pos=sepd?qApp->arguments().indexOf(QRegExp('^'+key+sep+"\\S*")):qApp->arguments().indexOf(QRegExp(key));
return pos==-1?QString::null:
(sepd?qApp->arguments().at(pos).split(sep).at(1):(++pos<qApp->arguments().size()?qApp->arguments().at(pos):QString::null));
}
Example:-
user#box:~$ ./myApp firstKey=Value1 --secondKey Value2 thirdKey=val3.1,val3.2,val3.3 --enable-foo
Usage:
QString param1 = QArgByKey("firstkey",'='); // Returns `Value1` from first pair
QString param2 = QArgByKey("--secondkey"); // Returns `Value2` from second pair
QString param3-1 = QArgByKey("thirdkey",'=').split(',').at(0); // Returns `val3.1`
bool fooEnabled = qApp->arguments().contains("--enable-foo"); //To check for `--enable-foo`
Params can be passed in any order
Edit: Updates to this snippet will be found here
Does it have to be Qt4 specific? If not, GNU Getopt is really nice, although licensing may be a problem if you are not doing open source software.
Also for some fancy options parsing you can try gperf.
IBM has a nice tutorial on it.
Another option I ran across while looking to do this, too:
http://code.google.com/p/qgetopts/
I haven't used it though.