Changeset 1313 in 3DVCSoftware for trunk/source/App/utils/BitrateTargeting
- Timestamp:
- 13 Aug 2015, 17:38:13 (9 years ago)
- Location:
- trunk/source/App/utils/BitrateTargeting
- Files:
-
- 7 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/source/App/utils/BitrateTargeting/ExtractBitrates.cpp
r872 r1313 2 2 * License, included below. This software may be subject to other third party 3 3 * and contributor rights, including patent rights, and no such rights are 4 * granted under this license. 5 * 6 * Copyright (c) 2010-201 4, ITU/ISO/IEC4 * granted under this license. 5 * 6 * Copyright (c) 2010-2015, ITU/ISO/IEC 7 7 * All rights reserved. 8 8 * … … 45 45 { 46 46 public: 47 47 48 48 /// Contructs a new zeroed tally 49 49 Tally( ): m_sum( 0.0 ), m_numSlices( 0 ) { } 50 50 51 51 /// Adds to the sum and increments the sample-count 52 52 void add( double in ) { ++m_numSlices; m_sum += in; } 53 53 54 54 /// \return The calculated average 55 55 double average( ) const { return m_sum / ( double )m_numSlices; } 56 56 57 57 private: 58 58 double m_sum; 59 59 unsigned long m_numSlices; 60 60 }; 61 61 62 62 /// Ignores all of the the characters up to and including a given character 63 63 /// \param line The line being read from … … 69 69 while( iLine.good( ) && character != iLine.get( ) ) 70 70 ; 71 if( !iLine.good( ) ) throw POCParseException( line ); 71 if( !iLine.good( ) ) 72 { 73 throw POCParseException( line ); 74 } 72 75 } 73 76 74 77 /// Extracts the average bitrates for each of the temporal layers from the given log 75 78 /// \param i The input stream that represents the log … … 79 82 { 80 83 std::map< unsigned char, Tally > tallyMap; 81 84 82 85 while( i.good( ) ) 83 86 { … … 86 89 std::getline( i, line ); 87 90 std::istringstream iLine( line ); 88 if( !iLine.good( ) ) continue; 89 91 if( !iLine.good( ) ) 92 { 93 continue; 94 } 95 90 96 // Ignore the "POC" 91 if( iLine.get( ) != 'P' ) continue; 92 if( !iLine.good( ) ) continue; 93 if( iLine.get( ) != 'O' ) continue; 94 if( !iLine.good( ) ) continue; 95 if( iLine.get( ) != 'C' ) continue; 96 if( !iLine.good( ) ) throw POCParseException( line ); 97 97 if( iLine.get( ) != 'P' ) 98 { 99 continue; 100 } 101 if( !iLine.good( ) ) 102 { 103 continue; 104 } 105 if( iLine.get( ) != 'O' ) 106 { 107 continue; 108 } 109 if( !iLine.good( ) ) 110 { 111 continue; 112 } 113 if( iLine.get( ) != 'C' ) 114 { 115 continue; 116 } 117 if( !iLine.good( ) ) 118 { 119 throw POCParseException( line ); 120 } 121 98 122 ignoreUpTo( line, iLine, '(' ); 99 100 if( iLine.get( ) != ' ' ) throw POCParseException( line ); 101 if( !iLine.good( ) ) throw POCParseException( line ); 102 103 if( 'I' == iLine.get( ) ) continue; 104 if( !iLine.good( ) ) throw POCParseException( line ); 105 123 124 if( iLine.get( ) != ' ' ) 125 { 126 throw POCParseException( line ); 127 } 128 if( !iLine.good( ) ) 129 { 130 throw POCParseException( line ); 131 } 132 133 if( 'I' == iLine.get( ) ) 134 { 135 continue; 136 } 137 if( !iLine.good( ) ) 138 { 139 throw POCParseException( line ); 140 } 141 106 142 ignoreUpTo( line, iLine, ' ' ); 107 143 ignoreUpTo( line, iLine, ' ' ); 108 144 109 145 // Parse the qpIndex 110 146 long qpIndexLong; 111 147 iLine >> qpIndexLong; 112 if( ( long )std::numeric_limits< unsigned char >::max( ) < qpIndexLong ) throw POCParseException( line ); 148 if( ( long )std::numeric_limits< unsigned char >::max( ) < qpIndexLong ) 149 { 150 throw POCParseException( line ); 151 } 113 152 unsigned char qpIndex( ( unsigned char )qpIndexLong ); 114 if( !iLine.good( ) ) throw POCParseException( line ); 115 153 if( !iLine.good( ) ) 154 { 155 throw POCParseException( line ); 156 } 157 116 158 ignoreUpTo( line, iLine, ')' ); 117 159 ignoreUpTo( line, iLine, ' ' ); 118 160 119 161 // Parse the number of bits 120 162 unsigned long bitsULong; 121 163 iLine >> bitsULong; 122 if( !iLine.good( ) ) throw POCParseException( line ); 123 164 if( !iLine.good( ) ) 165 { 166 throw POCParseException( line ); 167 } 168 124 169 // Find the tally that corresponds to our QP. If there is no such tally yet, then add a new one to the map. 125 170 std::map< unsigned char, Tally >::iterator iter( tallyMap.find( qpIndex ) ); … … 130 175 } 131 176 assert( iter != tallyMap.end( ) ); 132 177 133 178 iter->second.add( ( double )bitsULong ); 134 179 } 135 180 136 181 // Populate and return the result based on all of the tallies 137 182 std::map< unsigned char, double > result; … … 147 192 { 148 193 std::vector< double > result; 149 194 150 195 std::map< unsigned char, double > bitratesForQPsMap( extractBitratesForQPs( i ) ); 151 196 if( !bitratesForQPsMap.empty( ) ) 152 197 { 153 198 unsigned char expectedNextQPIndex( bitratesForQPsMap.begin( )->first ); 154 199 155 200 for( std::map< unsigned char, double >::const_iterator i( bitratesForQPsMap.begin( ) ); i != bitratesForQPsMap.end( ); ++i ) 156 201 { 157 if( i->first != expectedNextQPIndex ) throw NonContiguousQPSetException( ); 202 if( i->first != expectedNextQPIndex ) 203 { 204 throw NonContiguousQPSetException( ); 205 } 158 206 ++expectedNextQPIndex; 159 207 result.push_back( i->second ); 160 208 } 161 209 } 162 210 163 211 return result; 164 212 } -
trunk/source/App/utils/BitrateTargeting/ExtractBitrates.h
r872 r1313 2 2 * License, included below. This software may be subject to other third party 3 3 * and contributor rights, including patent rights, and no such rights are 4 * granted under this license. 4 * granted under this license. 5 5 * 6 * Copyright (c) 2010-201 4, ITU/ISO/IEC6 * Copyright (c) 2010-2015, ITU/ISO/IEC 7 7 * All rights reserved. 8 8 * … … 32 32 */ 33 33 34 #ifndef EXTRACT_BITRATES_H35 #define EXTRACT_BITRATES_H34 #ifndef __EXTRACTBITRATES__ 35 #define __EXTRACTBITRATES__ 36 36 37 37 #include "RuntimeError.h" … … 44 44 POCParseException( const std::string& pocLine ): m_pocLine( pocLine ) { } 45 45 virtual ~POCParseException( ) throw ( ) { } 46 46 47 47 protected: 48 48 void outputWhat( std::ostream& o ) const { o << "POC parse exception: " << m_pocLine; } 49 49 50 50 private: 51 51 std::string m_pocLine; … … 57 57 public: 58 58 virtual ~NonContiguousQPSetException( ) throw( ) { } 59 59 60 60 protected: 61 61 void outputWhat( std::ostream& o ) const { o << "Non-contiguous QP set exception"; } -
trunk/source/App/utils/BitrateTargeting/ExtractBitratesMain.cpp
r872 r1313 2 2 * License, included below. This software may be subject to other third party 3 3 * and contributor rights, including patent rights, and no such rights are 4 * granted under this license. 4 * granted under this license. 5 5 * 6 * Copyright (c) 2010-201 4, ITU/ISO/IEC6 * Copyright (c) 2010-2015, ITU/ISO/IEC 7 7 * All rights reserved. 8 8 * … … 44 44 assert( 2 == toFind.size( ) ); 45 45 assert( 'e' == toFind[ 0 ] ); 46 46 47 47 std::string::size_type pos( out.find( toFind ) ); 48 48 assert( pos != std::string::npos ); … … 57 57 oss << std::scientific << right; 58 58 std::string s( oss.str( ) ); 59 59 60 60 replaceWithE( s, "e+" ); 61 61 replaceWithE( s, "e0" ); 62 62 63 63 left << s; 64 64 } … … 69 69 { 70 70 std::vector< double > result( extractBitratesForTemporalLayers( std::cin ) ); // Extract the bitrate vector 71 71 72 72 // Output the bitrate vector 73 73 if( 0 < result.size( ) ) … … 89 89 } 90 90 } 91 91 92 92 return 0; 93 93 } -
trunk/source/App/utils/BitrateTargeting/GuessLambdaModifiers.cpp
r872 r1313 2 2 * License, included below. This software may be subject to other third party 3 3 * and contributor rights, including patent rights, and no such rights are 4 * granted under this license. 4 * granted under this license. 5 5 * 6 * Copyright (c) 2010-201 4, ITU/ISO/IEC6 * Copyright (c) 2010-2015, ITU/ISO/IEC 7 7 * All rights reserved. 8 8 * … … 46 46 { 47 47 assert( right.empty( ) ); 48 48 49 49 for( ; ; ) 50 50 { 51 51 assert( left.good( ) ); 52 52 53 53 double bitrate; 54 54 left >> bitrate; 55 if( left.fail( ) ) break; 55 if( left.fail( ) ) 56 { 57 break; 58 } 56 59 if( bitrate <= ( double )0.0 ) 57 60 { … … 62 65 right.push_back( bitrate ); 63 66 } 64 if( !left.good( ) ) break; 65 67 if( !left.good( ) ) 68 { 69 break; 70 } 71 66 72 if( left.peek( ) == ' ' ) 67 73 { … … 74 80 } 75 81 } 76 82 77 83 /// Makes a next guess for a single Lambda-modifier based on only one previous guess 78 84 /// \param initialAdjustmentParameter The proportionality to use between the target bitrate and the previous guess … … 88 94 assert( ( double )0.0 < previousPoint.lambdaModifier ); 89 95 assert( ( double )0.0 < previousPoint.bitrate ); 90 96 91 97 double extrapolated( previousPoint.lambdaModifier * targetBitrate / previousPoint.bitrate ); 92 98 return previousPoint.lambdaModifier + initialAdjustmentParameter * ( extrapolated - previousPoint.lambdaModifier ); … … 102 108 assert( point1.lambdaModifier != point2.lambdaModifier ); 103 109 assert( point1.bitrate != point2.bitrate ); 104 110 105 111 // Calculate and return the result 106 112 double denominator( point1.bitrate - point2.bitrate ); … … 119 125 assert( interDampeningFactor <= ( double )1.0 ); 120 126 assert( !pointList.empty( ) ); 121 127 122 128 double preliminaryResult; 123 129 124 130 if( 1 == pointList.size( ) ) // If there is only one prevous point, then we cannot interpolate, so we call incrementLambdaModifier 125 131 { … … 132 138 ++i; 133 139 Point point2 = *i; 134 140 135 141 // If the slope is either horizontal or vertical, we cannot interpolate 136 142 if( point1.lambdaModifier == point2.lambdaModifier || point1.bitrate == point2.bitrate ) … … 143 149 } 144 150 } 145 151 146 152 double previousResult( pointList.back( ).lambdaModifier ); 147 153 148 154 // Apply "intra dampening" 149 155 { … … 159 165 } 160 166 } 161 167 162 168 // Apply "inter dampening factor". If necessary, reduce the factor until a positive result is acheived. 163 169 double result; … … 180 186 return result; 181 187 } 182 188 183 189 /// Calculates the inter dampening factor based 184 190 /// \param parameter The inter dampening parameter which determines how severely the inter dampening factor is affected by Lambda-modifier changes at previous temporal layers … … 202 208 assert( !targetBitrateVector.empty( ) ); 203 209 assert( !metaLogEntryList.empty( ) ); 204 210 205 211 double cumulativeDelta( 0.0 ); 206 212 std::vector< double > resultVector; … … 212 218 pointList.push_front( pointFromFullMetaLogEntry( i, *j ) ); 213 219 ++j; 214 if( j != metaLogEntryList.rend( ) ) pointList.push_front( pointFromFullMetaLogEntry( i, *j ) ); 215 220 if( j != metaLogEntryList.rend( ) ) 221 { 222 pointList.push_front( pointFromFullMetaLogEntry( i, *j ) ); 223 } 224 216 225 // Calculate the new Lambda-modifier guess and add it to the result vector 217 226 const double newLambdaModifier( guessLambdaModifier( … … 221 230 interDampeningFactor( 50.0, cumulativeDelta ) ) ); 222 231 resultVector.push_back( newLambdaModifier ); 223 232 224 233 // Increment the cumulativeDelta 225 234 const double oldLambdaModifier( pointList.back( ).lambdaModifier ); 226 235 cumulativeDelta += std::abs( newLambdaModifier - oldLambdaModifier ) / oldLambdaModifier; 227 236 } 228 237 229 238 return resultVector; 230 239 } … … 240 249 while( i.good( ) && character != i.get( ) ) 241 250 ; 242 if( !i.good( ) ) throw MetaLogParseException( ); 243 } 244 251 if( !i.good( ) ) 252 { 253 throw MetaLogParseException( ); 254 } 255 } 256 245 257 /// Parses a Lambda-modifier map 246 258 /// \param right The map to write the output to … … 250 262 { 251 263 assert( left.good( ) ); 252 264 253 265 // Ignore the "-LM" 254 if( '-' != left.get( ) ) left.setstate( std::istream::failbit ); 255 if( !left.good( ) ) break; 256 if( 'L' != left.get( ) ) left.setstate( std::istream::failbit ); 257 if( !left.good( ) ) break; 258 if( 'M' != left.get( ) ) left.setstate( std::istream::failbit ); 259 if( !left.good( ) ) break; 260 266 if( '-' != left.get( ) ) 267 { 268 left.setstate( std::istream::failbit ); 269 } 270 if( !left.good( ) ) 271 { 272 break; 273 } 274 if( 'L' != left.get( ) ) 275 { 276 left.setstate( std::istream::failbit ); 277 } 278 if( !left.good( ) ) 279 { 280 break; 281 } 282 if( 'M' != left.get( ) ) 283 { 284 left.setstate( std::istream::failbit ); 285 } 286 if( !left.good( ) ) 287 { 288 break; 289 } 290 261 291 // Parse the index 262 292 long indexLong; 263 293 left >> indexLong; 264 if( !left.good( ) ) break; 265 if( indexLong < std::numeric_limits< unsigned char >::min( ) ) left.setstate( std::istream::failbit ); 266 if( std::numeric_limits< unsigned char >::max( ) < indexLong ) left.setstate( std::istream::failbit ); 267 if( !left.good( ) ) break; 294 if( !left.good( ) ) 295 { 296 break; 297 } 298 if( indexLong < std::numeric_limits< unsigned char >::min( ) ) 299 { 300 left.setstate( std::istream::failbit ); 301 } 302 if( std::numeric_limits< unsigned char >::max( ) < indexLong ) 303 { 304 left.setstate( std::istream::failbit ); 305 } 306 if( !left.good( ) ) 307 { 308 break; 309 } 268 310 unsigned char index( ( unsigned char )indexLong ); 269 270 if( ' ' != left.get( ) ) left.setstate( std::istream::failbit ); 271 if( !left.good( ) ) break; 272 311 312 if( ' ' != left.get( ) ) 313 { 314 left.setstate( std::istream::failbit ); 315 } 316 if( !left.good( ) ) 317 { 318 break; 319 } 320 273 321 // Parse the Lambda-modifier 274 322 double lambdaModifier; … … 282 330 right[ index ] = lambdaModifier; 283 331 } 284 if( !left.good( ) ) break; 285 332 if( !left.good( ) ) 333 { 334 break; 335 } 336 286 337 // If we peek and see a space, then there should be more Lambda-modifiers to parse. Otherwise, we are finished. 287 338 if( left.peek( ) == ' ' ) … … 295 346 } 296 347 } 297 348 298 349 /// Extracts the indexes from the given maps 299 350 /// \return The set of indexes … … 322 373 throw InitialAdjustmentParameterParseException( ); 323 374 } 324 375 325 376 // Parse the targets 326 377 std::vector< double > targetVector; 327 378 parseBitrateVector( targetsIstream, targetVector ); 328 if( targetVector.empty( ) || targetsIstream.fail( ) || targetsIstream.good( ) ) throw TargetsParseException( ); 329 379 if( targetVector.empty( ) || targetsIstream.fail( ) || targetsIstream.good( ) ) 380 { 381 throw TargetsParseException( ); 382 } 383 330 384 // Parse the metalog 331 385 std::list< MetaLogEntry< std::map< unsigned char, double > > > metaLogEntryList; … … 335 389 MetaLogEntry< std::map< unsigned char, double > > entry; 336 390 parseLambdaModifierMap( metaLogIstream, entry.lambdaModifiers ); 337 if( !metaLogIstream.good( ) ) throw MetaLogParseException( ); 338 391 if( !metaLogIstream.good( ) ) 392 { 393 throw MetaLogParseException( ); 394 } 395 339 396 // Skip the ';' 340 if( ';' != metaLogIstream.get( ) ) throw MetaLogParseException( ); 341 if( !metaLogIstream.good( ) ) throw MetaLogParseException( ); 342 397 if( ';' != metaLogIstream.get( ) ) 398 { 399 throw MetaLogParseException( ); 400 } 401 if( !metaLogIstream.good( ) ) 402 { 403 throw MetaLogParseException( ); 404 } 405 343 406 // Parse the bitrates 344 407 parseBitrateVector( metaLogIstream, entry.bitrateVector ); 345 if( metaLogIstream.fail( ) ) throw MetaLogParseException( ); 408 if( metaLogIstream.fail( ) ) 409 { 410 throw MetaLogParseException( ); 411 } 346 412 metaLogEntryList.push_back( entry ); 347 348 if( !metaLogIstream.good( ) ) break; 349 if( metaLogIstream.get( ) != '\n' ) throw MetaLogParseException( ); 413 414 if( !metaLogIstream.good( ) ) 415 { 416 break; 417 } 418 if( metaLogIstream.get( ) != '\n' ) 419 { 420 throw MetaLogParseException( ); 421 } 350 422 metaLogIstream.peek( ); 351 423 } while( metaLogIstream.good( ) ); 352 if( metaLogEntryList.empty( ) ) throw MetaLogParseException( ); // The meta-log should not be empty 353 424 if( metaLogEntryList.empty( ) ) 425 { 426 throw MetaLogParseException( ); // The meta-log should not be empty 427 } 428 354 429 // Initialize firstIndexVector and check that the sizes and indexes match 355 430 std::set< unsigned char > firstIndexSet( indexSetFromMap( metaLogEntryList.front( ).lambdaModifiers ) ); 356 if( firstIndexSet.size( ) != targetVector.size( ) ) throw MismatchedIndexesException( ); 431 if( firstIndexSet.size( ) != targetVector.size( ) ) 432 { 433 throw MismatchedIndexesException( ); 434 } 357 435 for( std::list< MetaLogEntry< std::map< unsigned char, double > > >::const_iterator i( metaLogEntryList.begin( ) ); 358 436 i != metaLogEntryList.end( ); 359 437 ++i ) 360 438 { 361 if( indexSetFromMap( i->lambdaModifiers ) != firstIndexSet ) throw MismatchedIndexesException( ); 362 if( i->bitrateVector.size( ) != targetVector.size( ) ) throw MismatchedIndexesException( ); 363 } 364 439 if( indexSetFromMap( i->lambdaModifiers ) != firstIndexSet ) 440 { 441 throw MismatchedIndexesException( ); 442 } 443 if( i->bitrateVector.size( ) != targetVector.size( ) ) 444 { 445 throw MismatchedIndexesException( ); 446 } 447 } 448 365 449 // Initialize simplifiedMetaLogEntryList 366 450 std::list< MetaLogEntry< std::vector< double > > > simplifiedMetaLogEntryList; … … 376 460 simplifiedMetaLogEntryList.back( ).bitrateVector = i->bitrateVector; 377 461 } 378 462 379 463 // Run the calculations 380 464 std::vector< double > resultVector( guessLambdaModifiers( initialAdjustmentParameter, targetVector, simplifiedMetaLogEntryList ) ); 381 465 382 466 // Output the results 383 467 std::set< unsigned char >::const_iterator indexIter( firstIndexSet.begin( ) ); … … 385 469 do 386 470 { 387 if( indexIter != firstIndexSet.begin( ) ) o << " "; 471 if( indexIter != firstIndexSet.begin( ) ) 472 { 473 o << " "; 474 } 388 475 o << "-LM" << ( long )( *indexIter ) << " "; 389 476 o.setf( std::ostream::fixed, std::ostream::floatfield ); 390 477 o.precision( 7 ); 391 478 o << ( *resultIter ); 392 479 393 480 ++indexIter; 394 481 ++resultIter; -
trunk/source/App/utils/BitrateTargeting/GuessLambdaModifiers.h
r872 r1313 2 2 * License, included below. This software may be subject to other third party 3 3 * and contributor rights, including patent rights, and no such rights are 4 * granted under this license. 4 * granted under this license. 5 5 * 6 * Copyright (c) 2010-201 4, ITU/ISO/IEC6 * Copyright (c) 2010-2015, ITU/ISO/IEC 7 7 * All rights reserved. 8 8 * … … 32 32 */ 33 33 34 #ifndef CALCULATE_LAMBDA_MODIFIER_H35 #define CALCULATE_LAMBDA_MODIFIER_H34 #ifndef __GUESSLAMBDAMODIFIERS__ 35 #define __GUESSLAMBDAMODIFIERS__ 36 36 37 37 #include "RuntimeError.h" … … 94 94 95 95 /// Performs interpolation/extrapolation to guess a single Lambda-modifier 96 /// \param target The target bitrate value that this Lambda-modifier is trying to reach96 /// \param targetBitrate The target bitrate value that this Lambda-modifier is trying to reach 97 97 /// \param point1 One of the two previously tried points where first is the Lambda-modifier and second is the obtained bitrate 98 98 /// \param point2 One of the two previously tried points where first is the Lambda-modifier and second is the obtained bitrate … … 134 134 /// \param o The output stream to write the guessed Lambda-modifiers to 135 135 /// \param initialAdjustmentParameterIstream The input stream that contains the initial adjustment parameter 136 /// \param target Istream The input stream that contains the target bitrates136 /// \param targetsIstream The input stream that contains the target bitrates 137 137 /// \param metaLogIstream The input stream that contains the meta-log 138 138 /// \throw InitialAdjustmentParameterParseException if there is an error parsing the initial adjustment parameter -
trunk/source/App/utils/BitrateTargeting/GuessLambdaModifiersMain.cpp
r872 r1313 2 2 * License, included below. This software may be subject to other third party 3 3 * and contributor rights, including patent rights, and no such rights are 4 * granted under this license. 4 * granted under this license. 5 5 * 6 * Copyright (c) 2010-201 4, ITU/ISO/IEC6 * Copyright (c) 2010-2015, ITU/ISO/IEC 7 7 * All rights reserved. 8 8 * … … 49 49 try 50 50 { 51 if( argc != 3 ) throw WrongNumberOfArgumentsException( ); 52 51 if( argc != 3 ) 52 { 53 throw WrongNumberOfArgumentsException( ); 54 } 55 53 56 std::string initialAdjustmentParameterString( ppArgv[ 1 ] ); 54 57 std::istringstream initialAdjustmentParameterIstream( initialAdjustmentParameterString ); 55 58 56 59 std::string targetBitratesString( ppArgv[ 2 ] ); 57 60 std::istringstream targetBitratesIstream( targetBitratesString ); 58 61 59 62 guessLambdaModifiers( std::cout, initialAdjustmentParameterIstream, targetBitratesIstream, std::cin ); 60 63 return 0; 61 64 62 65 } 63 66 catch( std::exception& e ) -
trunk/source/App/utils/BitrateTargeting/RuntimeError.h
r872 r1313 2 2 * License, included below. This software may be subject to other third party 3 3 * and contributor rights, including patent rights, and no such rights are 4 * granted under this license. 4 * granted under this license. 5 5 * 6 * Copyright (c) 2010-201 4, ITU/ISO/IEC6 * Copyright (c) 2010-2015, ITU/ISO/IEC 7 7 * All rights reserved. 8 8 * … … 32 32 */ 33 33 34 #ifndef DIRECTORY_LIB_RUNTIME_ERROR_H35 #define DIRECTORY_LIB_RUNTIME_ERROR_H34 #ifndef __RUNTIMEERROR__ 35 #define __RUNTIMEERROR__ 36 36 37 37 #include <sstream> … … 44 44 RuntimeError( ): std::runtime_error( "" ), m_firstWhat( true ) { } 45 45 virtual ~RuntimeError( ) throw ( ) { } 46 46 47 47 /// Implementation of the std::exception::what method 48 48 const char * what( ) const throw( ) … … 57 57 return m_what.c_str( ); 58 58 } 59 59 60 60 protected: 61 61 /// The implementing class implements this method to customize the what output 62 62 /// \param o The what stream is outputted to this parameter 63 63 virtual void outputWhat( std::ostream & o ) const =0; 64 64 65 65 private: 66 66 mutable bool m_firstWhat; ///< True i.f.f. the what method has not yet been called
Note: See TracChangeset for help on using the changeset viewer.