Thread overview
'raii' for structs
Oct 27, 2006
Don Clugston
Oct 27, 2006
David Medlock
Oct 27, 2006
BCS
Oct 27, 2006
Sean Kelly
Oct 27, 2006
Brad Roberts
October 27, 2006
I'm trying to get an implementation of floating-point rounding modes.
Normally, you set the rounding mode at the start of a function, and restore it at exit.

void somefunc()
{
 RoundingMode oldmode = setRoundingMode(ROUNDTOZERO);
:
:
:
 setRoundingMode(oldmode);
}

It's a classic RAII situation.
In C++, you'd do it as:

struct TemporaryRoundingMode
{
  RoundingMode oldmode;
  TemporaryRoundingMode(RoundingMode newmode)
    { oldmode = setRoundingMode(newmode); }
~TemporaryRoundingMode() { setRoundingMode(oldmode); }
};

void somefunc()
{
  TemporaryRoundingMode tempMode(ROUNDTOZERO);
  :
  :
}

How can it be done in D? It's only 2 asm instructions, you definitely do not want memory allocation happening.

Unfortunately you can't do

template TempRoundingMode(int mode)
{
  int oldmode = setRoundingMode(mode);
  scope(exit) int junk = setRoundingMode(oldmode);
}

void somefunc()
{
  mixin TemporaryRoundingMode!(ROUNDTOZERO);
  :
  :
}

which doesn't require you to name a useless temporary variable; but it doesn't work, because you can't use scope(exit) in a mixin. And you couldn't do variables that way, anyway.

Any ideas?
October 27, 2006
Don Clugston wrote:
> I'm trying to get an implementation of floating-point rounding modes.
> Normally, you set the rounding mode at the start of a function, and restore it at exit.
> 
> void somefunc()
> {
>  RoundingMode oldmode = setRoundingMode(ROUNDTOZERO);
> :
> :
> :
>  setRoundingMode(oldmode);
> }
> 
> It's a classic RAII situation.
> In C++, you'd do it as:
> 
> struct TemporaryRoundingMode
> {
>   RoundingMode oldmode;
>   TemporaryRoundingMode(RoundingMode newmode)
>     { oldmode = setRoundingMode(newmode); }
> ~TemporaryRoundingMode() { setRoundingMode(oldmode); }
> };
> 
> void somefunc()
> {
>   TemporaryRoundingMode tempMode(ROUNDTOZERO);
>   :
>   :
> }
> 
> How can it be done in D? It's only 2 asm instructions, you definitely do not want memory allocation happening.
> 
> Unfortunately you can't do
> 
> template TempRoundingMode(int mode)
> {
>   int oldmode = setRoundingMode(mode);
>   scope(exit) int junk = setRoundingMode(oldmode);
> }
> 
> void somefunc()
> {
>   mixin TemporaryRoundingMode!(ROUNDTOZERO);
>   :
>   :
> }
> 
> which doesn't require you to name a useless temporary variable; but it doesn't work, because you can't use scope(exit) in a mixin. And you couldn't do variables that way, anyway.
> 
> Any ideas?

Using inner functions its just as clean IMO.

void withRounding( int mode, void delegate() dg )
{
  setRoundingMode( mode);
  dg();
  restoreRoundingMode();
}

Then to use it:

void foo()
{
  withRounding( ROUNDTOZERO, { ..do some stuff here } );
}

-David
October 27, 2006
Don Clugston wrote:
> 
> Any ideas?

It's not much of an answer, but how about classes constructed in place using alloca :-p  I'll admit I sometimes miss stack-based raii types as well.  An alternative would be:

struct TemporaryRoundingMode
{
    static TemporaryRoundingMode opCall( int mode ) {}
    void undo() {}
}

TemporaryRoundingMode m = TemporaryRoundingMode( x );
scope(exit) x.undo();

Still pretty messy though.


Sean
October 27, 2006
David Medlock wrote:
> 
> Using inner functions its just as clean IMO.
> 
> void withRounding( int mode, void delegate() dg )
> {
>   setRoundingMode( mode);
>   dg();
>   restoreRoundingMode();
> }
> 
> Then to use it:
> 
> void foo()
> {
>   withRounding( ROUNDTOZERO, { ..do some stuff here } );
> }
> 
> -David

T With_ROUNDTOZERO(T)( lazy T dg )
{
	RoundingMode oldmode = setRoundingMode(ROUNDTOZERO);
	T ret = dg();
 	setRoundingMode(oldmode);
	return ret;
}

void foo()
{
	real r = With_ROUNDTOZERO(1+76);
}


all of that should inline (I assume*) to

void foo()
{
	RoundingMode oldmode = setRoundingMode(ROUNDTOZERO);
	real r = (1+76);
 	setRoundingMode(oldmode);
}


* does DMD inline lazy arguments when it inlines the function? For that matter does this get inlined?

void foo()
{
	int i;
	(){
		i=1;
	}();
}
October 27, 2006
Don Clugston wrote:
> I'm trying to get an implementation of floating-point rounding modes.
> Normally, you set the rounding mode at the start of a function, and restore it at exit.
> 
> void somefunc()
> {
>  RoundingMode oldmode = setRoundingMode(ROUNDTOZERO);
> :
> :
> :
>  setRoundingMode(oldmode);
> }
> 
> It's a classic RAII situation.
> In C++, you'd do it as:
> 
> struct TemporaryRoundingMode
> {
>   RoundingMode oldmode;
>   TemporaryRoundingMode(RoundingMode newmode)
>     { oldmode = setRoundingMode(newmode); }
> ~TemporaryRoundingMode() { setRoundingMode(oldmode); }
> };
> 
> void somefunc()
> {
>   TemporaryRoundingMode tempMode(ROUNDTOZERO);
>   :
>   :
> }
> 
> How can it be done in D? It's only 2 asm instructions, you definitely do not want memory allocation happening.
> 
> Unfortunately you can't do
> 
> template TempRoundingMode(int mode)
> {
>   int oldmode = setRoundingMode(mode);
>   scope(exit) int junk = setRoundingMode(oldmode);
> }
> 
> void somefunc()
> {
>   mixin TemporaryRoundingMode!(ROUNDTOZERO);
>   :
>   :
> }
> 
> which doesn't require you to name a useless temporary variable; but it doesn't work, because you can't use scope(exit) in a mixin. And you couldn't do variables that way, anyway.
> 
> Any ideas?

Drop the variables all together.. no need for them here:

void somefunc()
{
    int oldmode = setRoundingMode(mode);
    scope(exit) setRoundingMode(oldMode);
    ...
}