Browse Source

Couple of optimisations to text rendering. Removed various printfs from the codebase.

tags/2021-05-28
Julian Storer 15 years ago
parent
commit
d84e47353c
22 changed files with 142 additions and 217 deletions
  1. +10
    -3
      extras/audio plugins/demo/src/DemoEditorComponent.cpp
  2. +11
    -36
      extras/juce demo/Source/ApplicationStartup.cpp
  3. +0
    -7
      src/core/juce_Logger.h
  4. +1
    -10
      src/core/juce_PlatformDefs.h
  5. +1
    -1
      src/core/juce_StandardHeader.h
  6. +20
    -0
      src/core/juce_SystemStats.cpp
  7. +10
    -2
      src/core/juce_SystemStats.h
  8. +8
    -2
      src/gui/components/code_editor/juce_CodeDocument.cpp
  9. +24
    -23
      src/gui/graphics/fonts/juce_GlyphArrangement.cpp
  10. +2
    -1
      src/gui/graphics/fonts/juce_GlyphArrangement.h
  11. +1
    -1
      src/native/linux/juce_linux_Network.cpp
  12. +1
    -11
      src/native/linux/juce_linux_SystemStats.cpp
  13. +2
    -1
      src/native/mac/juce_mac_CoreGraphicsContext.mm
  14. +1
    -10
      src/native/mac/juce_mac_Debugging.mm
  15. +3
    -3
      src/native/mac/juce_mac_Fonts.mm
  16. +1
    -1
      src/native/mac/juce_mac_Network.mm
  17. +1
    -1
      src/native/windows/juce_win32_Network.cpp
  18. +0
    -9
      src/native/windows/juce_win32_SystemStats.cpp
  19. +0
    -14
      src/text/juce_CharacterFunctions.cpp
  20. +0
    -3
      src/text/juce_CharacterFunctions.h
  21. +45
    -65
      src/text/juce_String.cpp
  22. +0
    -13
      src/text/juce_String.h

+ 10
- 3
extras/audio plugins/demo/src/DemoEditorComponent.cpp View File

@@ -37,9 +37,16 @@ static const String timeToTimecodeString (const double seconds)
const int mins = ((int) (absSecs / 60.0)) % 60;
const int secs = ((int) absSecs) % 60;
return String::formatted (T("%s%02d:%02d:%02d:%03d"),
sign, hours, mins, secs,
roundToInt (absSecs * 1000) % 1000);
String t;
if (seconds < 0)
t = T("-");
t << String (hours).paddedLeft ('0', 2) << ":"
<< String (mins).paddedLeft ('0', 2) << ":"
<< String (secs).paddedLeft ('0', 2) << ":"
<< String (roundToInt (absSecs * 1000) % 1000).paddedLeft ('0', 3);
return t;
}
// quick-and-dirty function to format a bars/beats string


+ 11
- 36
extras/juce demo/Source/ApplicationStartup.cpp View File

@@ -124,47 +124,22 @@ private:
<< "\nFull user name: " << SystemStats::getFullUserName()
<< "\nOperating system: " << SystemStats::getOperatingSystemName()
<< "\nCPU vendor: " << SystemStats::getCpuVendor()
<< "\nCPU speed: " << SystemStats::getCpuSpeedInMegaherz() << "MHz\n"
<< "\nCPU speed: " << SystemStats::getCpuSpeedInMegaherz() << "MHz"
<< "\nNumber of CPUs: " << SystemStats::getNumCpus()
<< "\nCPU has MMX: " << (SystemStats::hasMMX() ? "yes" : "no")
<< "\nCPU has SSE: " << (SystemStats::hasSSE() ? "yes" : "no")
<< "\nCPU has SSE2: " << (SystemStats::hasSSE2() ? "yes" : "no")
<< "\nCPU has 3DNOW: " << (SystemStats::has3DNow() ? "yes" : "no")
<< "\nMemory size: " << SystemStats::getMemorySizeInMegabytes() << "MB\n";
int64 macAddresses[8];
const int numAddresses = SystemStats::getMACAddresses (macAddresses, 8, false);
for (int i = 0; i < numAddresses; ++i)
{
systemInfo
<< "Found network card MAC address: "
<< String::formatted (T("%02x-%02x-%02x-%02x-%02x-%02x\n"),
0xff & (int) (macAddresses [i] >> 40),
0xff & (int) (macAddresses [i] >> 32),
0xff & (int) (macAddresses [i] >> 24),
0xff & (int) (macAddresses [i] >> 16),
0xff & (int) (macAddresses [i] >> 8),
0xff & (int) macAddresses [i]);
}
systemInfo
<< "Current executable file: "
<< File::getSpecialLocation (File::currentExecutableFile).getFullPathName()
<< "\nCurrent application file: "
<< File::getSpecialLocation (File::currentApplicationFile).getFullPathName()
<< "\nCurrent working directory: "
<< File::getCurrentWorkingDirectory().getFullPathName()
<< "\nUser home directory: "
<< File::getSpecialLocation (File::userHomeDirectory).getFullPathName()
<< "\nUser documents directory: "
<< File::getSpecialLocation (File::userDocumentsDirectory).getFullPathName()
<< "\nUser application data directory: "
<< File::getSpecialLocation (File::userApplicationDataDirectory).getFullPathName()
<< "\nCommon application data directory: "
<< File::getSpecialLocation (File::commonApplicationDataDirectory).getFullPathName()
<< "\nTemp directory: "
<< File::getSpecialLocation (File::tempDirectory).getFullPathName()
<< "\nMemory size: " << SystemStats::getMemorySizeInMegabytes() << "MB"
<< "\nFound network card MAC addresses: " << SystemStats::getMACAddressStrings().joinIntoString (T(", "))
<< "\nCurrent executable file: " << File::getSpecialLocation (File::currentExecutableFile).getFullPathName()
<< "\nCurrent application file: " << File::getSpecialLocation (File::currentApplicationFile).getFullPathName()
<< "\nCurrent working directory: " << File::getCurrentWorkingDirectory().getFullPathName()
<< "\nUser home directory: " << File::getSpecialLocation (File::userHomeDirectory).getFullPathName()
<< "\nUser documents directory: " << File::getSpecialLocation (File::userDocumentsDirectory).getFullPathName()
<< "\nUser application data directory: " << File::getSpecialLocation (File::userApplicationDataDirectory).getFullPathName()
<< "\nCommon application data directory: " << File::getSpecialLocation (File::commonApplicationDataDirectory).getFullPathName()
<< "\nTemp directory: " << File::getSpecialLocation (File::tempDirectory).getFullPathName()
<< "\n\n";
return systemInfo;


+ 0
- 7
src/core/juce_Logger.h View File

@@ -78,13 +78,6 @@ public:
*/
static void JUCE_CALLTYPE outputDebugString (const String& text) throw();
/** Writes a message to the standard error stream.
This can be called directly, or by using the DBG_PRINTF() macro in
juce_PlatformDefs.h (which will avoid calling the method in non-debug builds).
*/
static void JUCE_CALLTYPE outputDebugPrintf (const tchar* format, ...) throw();
protected:
//==============================================================================


+ 1
- 10
src/core/juce_PlatformDefs.h View File

@@ -53,7 +53,7 @@
#if JUCE_LOG_ASSERTIONS
#define juce_LogCurrentAssertion juce_LogAssertion (__FILE__, __LINE__);
#elif defined (JUCE_DEBUG)
#define juce_LogCurrentAssertion fprintf (stderr, "JUCE Assertion failure in %s, line %d\n", __FILE__, __LINE__);
#define juce_LogCurrentAssertion std::cerr << "JUCE Assertion failure in " << __FILE__ << ", line " << __LINE__ << std::endl;
#else
#define juce_LogCurrentAssertion
#endif
@@ -70,14 +70,6 @@
*/
#define DBG(dbgtext) Logger::outputDebugString (dbgtext);
/** Printf's a string to the standard error stream.
This is only compiled in a debug build.
@see Logger::outputDebugString
*/
#define DBG_PRINTF(dbgprintf) Logger::outputDebugPrintf dbgprintf;
//==============================================================================
// Assertions..
@@ -138,7 +130,6 @@
// If debugging is disabled, these dummy debug and assertion macros are used..
#define DBG(dbgtext)
#define DBG_PRINTF(dbgprintf)
#define jassertfalse { juce_LogCurrentAssertion }


+ 1
- 1
src/core/juce_StandardHeader.h View File

@@ -33,7 +33,7 @@
*/
#define JUCE_MAJOR_VERSION 1
#define JUCE_MINOR_VERSION 51
#define JUCE_BUILDNUMBER 9
#define JUCE_BUILDNUMBER 10
/** Current Juce version number.


+ 20
- 0
src/core/juce_SystemStats.cpp View File

@@ -48,6 +48,26 @@ const String SystemStats::getJUCEVersion() throw()
+ "." + String (JUCE_BUILDNUMBER);
}
const StringArray SystemStats::getMACAddressStrings()
{
int64 macAddresses [16];
const int numAddresses = getMACAddresses (macAddresses, numElementsInArray (macAddresses), false);
StringArray s;
for (int i = 0; i < numAddresses; ++i)
{
s.add (String::toHexString (0xff & (int) (macAddresses [i] >> 40)).paddedLeft ('0', 2)
+ "-" + String::toHexString (0xff & (int) (macAddresses [i] >> 32)).paddedLeft ('0', 2)
+ "-" + String::toHexString (0xff & (int) (macAddresses [i] >> 24)).paddedLeft ('0', 2)
+ "-" + String::toHexString (0xff & (int) (macAddresses [i] >> 16)).paddedLeft ('0', 2)
+ "-" + String::toHexString (0xff & (int) (macAddresses [i] >> 8)).paddedLeft ('0', 2)
+ "-" + String::toHexString (0xff & (int) (macAddresses [i] >> 0)).paddedLeft ('0', 2));
}
return s;
}
//==============================================================================
static bool juceInitialisedNonGUI = false;


+ 10
- 2
src/core/juce_SystemStats.h View File

@@ -26,6 +26,8 @@
#ifndef __JUCE_SYSTEMSTATS_JUCEHEADER__
#define __JUCE_SYSTEMSTATS_JUCEHEADER__
#include "../text/juce_StringArray.h"
//==============================================================================
/**
@@ -172,11 +174,17 @@ public:
*/
static int getMACAddresses (int64* addresses, int maxNum,
#if JUCE_MAC
const bool littleEndian = true) throw();
const bool littleEndian = true);
#else
const bool littleEndian = false) throw();
const bool littleEndian = false);
#endif
/** Returns a list of MAC addresses found on this machine.
@returns an array of strings containing the MAC addresses that were found
*/
static const StringArray getMACAddressStrings();
//==============================================================================
// not-for-public-use platform-specific method gets called at startup to initialise things.


+ 8
- 2
src/gui/components/code_editor/juce_CodeDocument.cpp View File

@@ -151,7 +151,13 @@ juce_wchar CodeDocument::Iterator::nextChar()
jassert (currentLine == document->lines.getUnchecked (line));
const juce_wchar result = currentLine->line [position - currentLine->lineStartInFile];
skip();
if (++position >= currentLine->lineStartInFile + currentLine->lineLength)
{
++line;
currentLine = document->lines [line];
}
return result;
}
@@ -191,7 +197,7 @@ juce_wchar CodeDocument::Iterator::peekNextChar() const
return 0;
jassert (currentLine == document->lines.getUnchecked (line));
return currentLine->line [position - currentLine->lineStartInFile];
return const_cast <const String&> (currentLine->line) [position - currentLine->lineStartInFile];
}
void CodeDocument::Iterator::skipWhitespace()


+ 24
- 23
src/gui/graphics/fonts/juce_GlyphArrangement.cpp View File

@@ -34,7 +34,24 @@ BEGIN_JUCE_NAMESPACE
//==============================================================================
PositionedGlyph::PositionedGlyph()
PositionedGlyph::PositionedGlyph (const float x_, const float y_, const float w_, const Font& font_,
const juce_wchar character_, const int glyph_)
: x (x_),
y (y_),
w (w_),
font (font_),
character (character_),
glyph (glyph_)
{
}
PositionedGlyph::PositionedGlyph (const PositionedGlyph& other)
: x (other.x),
y (other.y),
w (other.w),
font (other.font),
character (other.character),
glyph (other.glyph)
{
}
@@ -178,16 +195,14 @@ void GlyphArrangement::addCurtailedLineOfText (const Font& font,
const float maxWidthPixels,
const bool useEllipsis)
{
int textLen = text.length();
if (textLen > 0)
if (text.isNotEmpty())
{
Array <int> newGlyphs;
Array <float> xOffsets;
font.getGlyphPositions (text, newGlyphs, xOffsets);
const int textLen = newGlyphs.size();
const juce_wchar* const unicodeText = (const juce_wchar*) text;
textLen = jmin (textLen, newGlyphs.size());
for (int i = 0; i < textLen; ++i)
{
@@ -204,15 +219,8 @@ void GlyphArrangement::addCurtailedLineOfText (const Font& font,
}
else
{
PositionedGlyph* const pg = new PositionedGlyph();
pg->x = xOffset + thisX;
pg->y = yOffset;
pg->w = nextX - thisX;
pg->font = font;
pg->glyph = newGlyphs.getUnchecked(i);
pg->character = unicodeText[i];
glyphs.add (pg);
glyphs.add (new PositionedGlyph (xOffset + thisX, yOffset, nextX - thisX,
font, unicodeText[i], newGlyphs.getUnchecked(i)));
}
}
}
@@ -247,16 +255,9 @@ int GlyphArrangement::insertEllipsis (const Font& font, const float maxXPos,
for (int i = 3; --i >= 0;)
{
PositionedGlyph* const pg = new PositionedGlyph();
pg->x = xOffset;
pg->y = yOffset;
pg->w = dx;
pg->font = font;
pg->character = '.';
pg->glyph = dotGlyphs.getFirst();
glyphs.insert (endIndex++, pg);
glyphs.insert (endIndex++, new PositionedGlyph (xOffset, yOffset, dx,
font, '.', dotGlyphs.getFirst()));
--numDeleted;
xOffset += dx;
if (xOffset > maxXPos)


+ 2
- 1
src/gui/graphics/fonts/juce_GlyphArrangement.h View File

@@ -89,7 +89,8 @@ private:
juce_wchar character;
int glyph;
PositionedGlyph();
PositionedGlyph (float x, float y, float w, const Font& font, juce_wchar character, int glyph);
PositionedGlyph (const PositionedGlyph& other);
};


+ 1
- 1
src/native/linux/juce_linux_Network.cpp View File

@@ -29,7 +29,7 @@
//==============================================================================
int SystemStats::getMACAddresses (int64* addresses, int maxNum, const bool littleEndian) throw()
int SystemStats::getMACAddresses (int64* addresses, int maxNum, const bool littleEndian)
{
int numResults = 0;


+ 1
- 11
src/native/linux/juce_linux_SystemStats.cpp View File

@@ -31,17 +31,7 @@
//==============================================================================
void Logger::outputDebugString (const String& text) throw()
{
fputs (text.toUTF8(), stdout);
fputs ("\n", stdout);
}
void Logger::outputDebugPrintf (const tchar* format, ...) throw()
{
String text;
va_list args;
va_start (args, format);
text.vprintf(format, args);
outputDebugString(text);
std::cerr << text << std::endl;
}
SystemStats::OperatingSystemType SystemStats::getOperatingSystemType() throw()


+ 2
- 1
src/native/mac/juce_mac_CoreGraphicsContext.mm View File

@@ -132,6 +132,7 @@ public:
CoreGraphicsContext (CGContextRef context_, const float flipHeight_)
: context (context_),
flipHeight (flipHeight_),
state (new SavedState()),
numGradientLookupEntries (0)
{
CGContextRetain (context);
@@ -144,7 +145,7 @@ public:
gradientCallbacks.version = 0;
gradientCallbacks.evaluate = gradientCallback;
gradientCallbacks.releaseInfo = 0;
state = new SavedState();
setFont (Font());
}
~CoreGraphicsContext()


+ 1
- 10
src/native/mac/juce_mac_Debugging.mm View File

@@ -30,16 +30,7 @@
//==============================================================================
void Logger::outputDebugString (const String& text) throw()
{
std::cerr << (const char*) text.toUTF8() << std::endl;
}
void Logger::outputDebugPrintf (const tchar* format, ...) throw()
{
String text;
va_list args;
va_start (args, format);
text.vprintf (format, args);
outputDebugString (text);
std::cerr << text << std::endl;
}
bool JUCE_PUBLIC_FUNCTION juce_isRunningUnderDebugger()


+ 3
- 3
src/native/mac/juce_mac_Fonts.mm View File

@@ -201,7 +201,7 @@ public:
#if SUPPORT_ONLY_10_4_FONTS
HeapBlock <NSSize> advances (length);
[nsFont getAdvancements: advances forGlyphs: (NSGlyph*) glyphs count: length];
[nsFont getAdvancements: advances forGlyphs: reinterpret_cast <NSGlyph*> (glyphs.getData()) count: length];
for (int i = 0; i < length; ++i)
x += advances[i].width;
@@ -242,14 +242,14 @@ public:
#if SUPPORT_ONLY_10_4_FONTS
HeapBlock <NSSize> advances (length);
[nsFont getAdvancements: advances forGlyphs: (NSGlyph*) glyphs count: length];
[nsFont getAdvancements: advances forGlyphs: reinterpret_cast <NSGlyph*> (glyphs.getData()) count: length];
int x = 0;
for (int i = 0; i < length; ++i)
{
x += advances[i].width;
xOffsets.add (x * unitsToHeightScaleFactor);
resultGlyphs.add (((NSGlyph*) glyphs)[i]);
resultGlyphs.add (reinterpret_cast <NSGlyph*> (glyphs.getData())[i]);
}
#else


+ 1
- 1
src/native/mac/juce_mac_Network.mm View File

@@ -28,7 +28,7 @@
#if JUCE_INCLUDED_FILE
//==============================================================================
int SystemStats::getMACAddresses (int64* addresses, int maxNum, const bool littleEndian) throw()
int SystemStats::getMACAddresses (int64* addresses, int maxNum, const bool littleEndian)
{
#ifndef IFT_ETHER
#define IFT_ETHER 6


+ 1
- 1
src/native/windows/juce_win32_Network.cpp View File

@@ -417,7 +417,7 @@ static int getMACAddressesViaNetBios (int64* addresses, int maxNum, const bool l
return numFound;
}
int SystemStats::getMACAddresses (int64* addresses, int maxNum, const bool littleEndian) throw()
int SystemStats::getMACAddresses (int64* addresses, int maxNum, const bool littleEndian)
{
int numFound = getMACAddressViaGetAdaptersInfo (addresses, maxNum, littleEndian);


+ 0
- 9
src/native/windows/juce_win32_SystemStats.cpp View File

@@ -36,15 +36,6 @@ void Logger::outputDebugString (const String& text) throw()
OutputDebugString (text + T("\n"));
}
void Logger::outputDebugPrintf (const tchar* format, ...) throw()
{
String text;
va_list args;
va_start (args, format);
text.vprintf(format, args);
outputDebugString (text);
}
//==============================================================================
static int64 hiResTicksPerSecond;
static double hiResTicksScaleFactor;


+ 0
- 14
src/text/juce_CharacterFunctions.cpp View File

@@ -772,20 +772,6 @@ int CharacterFunctions::getHexDigitValue (const juce_wchar digit) throw()
}
//==============================================================================
int CharacterFunctions::printf (char* const dest, const int maxLength, const char* const format, ...) throw()
{
va_list list;
va_start (list, format);
return vprintf (dest, maxLength, format, list);
}
int CharacterFunctions::printf (juce_wchar* const dest, const int maxLength, const juce_wchar* const format, ...) throw()
{
va_list list;
va_start (list, format);
return vprintf (dest, maxLength, format, list);
}
int CharacterFunctions::vprintf (char* const dest, const int maxLength, const char* const format, va_list& args) throw()
{
#if JUCE_WIN32


+ 0
- 3
src/text/juce_CharacterFunctions.h View File

@@ -148,9 +148,6 @@ public:
static int getHexDigitValue (const juce_wchar digit) throw();
//==============================================================================
static int printf (char* const dest, const int maxLength, const char* const format, ...) throw();
static int printf (juce_wchar* const dest, const int maxLength, const juce_wchar* const format, ...) throw();
static int vprintf (char* const dest, const int maxLength, const char* const format, va_list& args) throw();
static int vprintf (juce_wchar* const dest, const int maxLength, const juce_wchar* const format, va_list& args) throw();
};


+ 45
- 65
src/text/juce_String.cpp View File

@@ -322,6 +322,43 @@ namespace IntToCharConverters
return t;
}
static tchar* doubleToString (tchar* buffer, int numChars, double n, int numDecPlaces, int& len) throw()
{
if (numDecPlaces > 0 && n > -1.0e20 && n < 1.0e20)
{
tchar* const end = buffer + numChars;
tchar* t = end;
int64 v = (int64) (pow (10.0, numDecPlaces) * fabs (n) + 0.5);
*--t = (tchar) 0;
while (numDecPlaces >= 0 || v > 0)
{
if (numDecPlaces == 0)
*--t = decimalPoint;
*--t = (tchar) (T('0') + (v % 10));
v /= 10;
--numDecPlaces;
}
if (n < 0)
*--t = T('-');
len = end - t;
return t;
}
else
{
#if JUCE_WIN32
len = (int) _snwprintf_s (buffer, numChars, _TRUNCATE, L"%.9g", n) + 1;
#else
len = (int) swprintf (buffer, numChars, L"%.9g", n) + 1;
#endif
return buffer;
}
}
}
String::String (const int number) throw()
@@ -372,71 +409,22 @@ String::String (const uint64 number) throw()
createInternal (IntToCharConverters::uint64ToString (end, number), end);
}
// a double-to-string routine that actually uses the number of dec. places you asked for
// without resorting to exponent notation if the number's too big or small (which is what printf does).
void String::doubleToStringWithDecPlaces (double n, int numDecPlaces) throw()
{
const int bufSize = 80;
tchar buffer [bufSize];
int len;
tchar* t;
if (numDecPlaces > 0 && n > -1.0e20 && n < 1.0e20)
{
int64 v = (int64) (pow (10.0, numDecPlaces) * fabs (n) + 0.5);
t = buffer + bufSize;
*--t = (tchar) 0;
while (numDecPlaces >= 0 || v > 0)
{
if (numDecPlaces == 0)
*--t = decimalPoint;
*--t = (tchar) (T('0') + (v % 10));
v /= 10;
--numDecPlaces;
}
if (n < 0)
*--t = T('-');
len = (int) ((buffer + bufSize) - t);
}
else
{
len = CharacterFunctions::printf (buffer, bufSize, T("%.9g"), n) + 1;
t = buffer;
}
if (len > 1)
{
jassert (len < numElementsInArray (buffer));
createInternal (len - 1);
memcpy (text->text, t, len * sizeof (tchar));
}
else
{
jassert (*t == 0);
text = &emptyString;
emptyString.refCount = safeEmptyStringRefCount;
}
}
String::String (const float number,
const int numberOfDecimalPlaces) throw()
{
doubleToStringWithDecPlaces ((double) number,
numberOfDecimalPlaces);
tchar buffer [48];
int len;
tchar* start = IntToCharConverters::doubleToString (buffer, numElementsInArray (buffer), (double) number, numberOfDecimalPlaces, len);
createInternal (start, start + len);
}
String::String (const double number,
const int numberOfDecimalPlaces) throw()
{
doubleToStringWithDecPlaces (number,
numberOfDecimalPlaces);
tchar buffer [48];
int len;
tchar* start = IntToCharConverters::doubleToString (buffer, numElementsInArray (buffer), number, numberOfDecimalPlaces, len);
createInternal (start, start + len);
}
String::~String() throw()
@@ -1102,14 +1090,6 @@ bool String::matchesWildcard (const tchar* wildcard, const bool ignoreCase) cons
}
//==============================================================================
void String::printf (const tchar* const pf, ...) throw()
{
va_list list;
va_start (list, pf);
vprintf (pf, list);
}
const String String::formatted (const tchar* const pf, ...) throw()
{
va_list list;


+ 0
- 13
src/text/juce_String.h View File

@@ -706,18 +706,6 @@ public:
//==============================================================================
/** Writes text into this string, using printf style-arguments.
This will replace the contents of the string with the output of this
formatted printf.
Note that using the %s token with a juce string is probably a bad idea, as
this may expect differect encodings on different platforms.
@see formatted
*/
void printf (const tchar* const format, ...) throw();
/** Returns a string, created using arguments in the style of printf.
This will return a string which is the result of a sprintf using the
@@ -1076,7 +1064,6 @@ private:
void createInternal (const int numChars) throw();
void createInternal (const tchar* const text, const tchar* const textEnd) throw();
void appendInternal (const tchar* const text, const int numExtraChars) throw();
void doubleToStringWithDecPlaces (double n, int numDecPlaces) throw();
void dupeInternalIfMultiplyReferenced() throw();
};


Loading…
Cancel
Save