www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - 'raii' for structs

reply Don Clugston <dac nospam.com.au> writes:
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?
Oct 27 2006
next sibling parent reply David Medlock <noone nowhere.com> writes:
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
Oct 27 2006
parent BCS <BCS pathlink.com> writes:
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; }(); }
Oct 27 2006
prev sibling next sibling parent Sean Kelly <sean f4.ca> writes:
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
Oct 27 2006
prev sibling parent Brad Roberts <braddr puremagic.com> writes:
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); ... }
Oct 27 2006