summaryrefslogtreecommitdiff
path: root/indra/llcommon
diff options
context:
space:
mode:
Diffstat (limited to 'indra/llcommon')
-rw-r--r--indra/llcommon/imageids.cpp3
-rw-r--r--indra/llcommon/imageids.h1
-rw-r--r--indra/llcommon/llassettype.cpp1
-rw-r--r--indra/llcommon/llassettype.h3
-rw-r--r--indra/llcommon/llavatarname.cpp131
-rw-r--r--indra/llcommon/llavatarname.h60
-rw-r--r--indra/llcommon/lldictionary.h2
-rw-r--r--indra/llcommon/llfasttimer.cpp6
-rw-r--r--indra/llcommon/llfasttimer.h2
-rw-r--r--indra/llcommon/llfile.cpp709
-rw-r--r--indra/llcommon/llfile.h423
-rwxr-xr-x[-rw-r--r--]indra/llcommon/llfoldertype.h0
-rw-r--r--indra/llcommon/llhandle.h13
-rw-r--r--indra/llcommon/llinitparam.cpp82
-rw-r--r--indra/llcommon/llinitparam.h1657
-rw-r--r--indra/llcommon/llinstancetracker.h5
-rw-r--r--indra/llcommon/llmetricperformancetester.cpp2
-rw-r--r--indra/llcommon/llrefcount.h19
-rw-r--r--indra/llcommon/llregistry.h4
-rw-r--r--indra/llcommon/llsdparam.cpp51
-rw-r--r--indra/llcommon/llsdserialize.cpp4
-rw-r--r--indra/llcommon/llsdserialize.h16
-rw-r--r--indra/llcommon/llsdserialize_xml.cpp18
-rw-r--r--indra/llcommon/llthread.h17
-rw-r--r--indra/llcommon/llversionserver.h2
-rw-r--r--indra/llcommon/llversionviewer.h6
-rw-r--r--indra/llcommon/stdenums.h3
-rw-r--r--indra/llcommon/tests/bitpack_test.cpp16
-rw-r--r--indra/llcommon/tests/llinstancetracker_test.cpp3
29 files changed, 2315 insertions, 944 deletions
diff --git a/indra/llcommon/imageids.cpp b/indra/llcommon/imageids.cpp
index fe11465221..7d647e5c36 100644
--- a/indra/llcommon/imageids.cpp
+++ b/indra/llcommon/imageids.cpp
@@ -68,3 +68,6 @@ const LLUUID TERRAIN_MOUNTAIN_DETAIL ("303cd381-8560-7579-23f1-f0a880799740"); /
const LLUUID TERRAIN_ROCK_DETAIL ("53a2f406-4895-1d13-d541-d2e3b86bc19c"); // VIEWER
const LLUUID DEFAULT_WATER_NORMAL ("822ded49-9a6c-f61c-cb89-6df54f42cdf4"); // VIEWER
+
+const LLUUID IMG_CHECKERBOARD_RGBA ("2585a0f3-4163-6dd1-0f34-ad48cb909e25"); // dataserver
+
diff --git a/indra/llcommon/imageids.h b/indra/llcommon/imageids.h
index e0c2683fdc..18c8ecb074 100644
--- a/indra/llcommon/imageids.h
+++ b/indra/llcommon/imageids.h
@@ -66,4 +66,5 @@ LL_COMMON_API extern const LLUUID TERRAIN_ROCK_DETAIL;
LL_COMMON_API extern const LLUUID DEFAULT_WATER_NORMAL;
+LL_COMMON_API extern const LLUUID IMG_CHECKERBOARD_RGBA;
#endif
diff --git a/indra/llcommon/llassettype.cpp b/indra/llcommon/llassettype.cpp
index 5e566d6c7c..5ae2df3994 100644
--- a/indra/llcommon/llassettype.cpp
+++ b/indra/llcommon/llassettype.cpp
@@ -95,6 +95,7 @@ LLAssetDictionary::LLAssetDictionary()
addEntry(LLAssetType::AT_LINK_FOLDER, new AssetEntry("FOLDER_LINK", "link_f", "sym folder link", false, false, true));
addEntry(LLAssetType::AT_MESH, new AssetEntry("MESH", "mesh", "mesh", false, false, false));
addEntry(LLAssetType::AT_WIDGET, new AssetEntry("WIDGET", "widget", "widget", false, false, false));
+ addEntry(LLAssetType::AT_PERSON, new AssetEntry("PERSON", "person", "person", false, false, false));
addEntry(LLAssetType::AT_NONE, new AssetEntry("NONE", "-1", NULL, FALSE, FALSE, FALSE));
};
diff --git a/indra/llcommon/llassettype.h b/indra/llcommon/llassettype.h
index d538accbf7..69b01731e5 100644
--- a/indra/llcommon/llassettype.h
+++ b/indra/llcommon/llassettype.h
@@ -112,6 +112,9 @@ public:
AT_WIDGET = 40,
// UI Widget: this is *not* an inventory asset type, only a viewer side asset (e.g. button, other ui items...)
+ AT_PERSON = 45,
+ // A user uuid which is not an inventory asset type, used in viewer only for adding a person to a chat via drag and drop.
+
AT_MESH = 49,
// Mesh data in our proprietary SLM format
diff --git a/indra/llcommon/llavatarname.cpp b/indra/llcommon/llavatarname.cpp
index 3206843bf4..642bd82e90 100644
--- a/indra/llcommon/llavatarname.cpp
+++ b/indra/llcommon/llavatarname.cpp
@@ -30,6 +30,7 @@
#include "llavatarname.h"
#include "lldate.h"
+#include "llframetimer.h"
#include "llsd.h"
// Store these in pre-built std::strings to avoid memory allocations in
@@ -42,6 +43,14 @@ static const std::string IS_DISPLAY_NAME_DEFAULT("is_display_name_default");
static const std::string DISPLAY_NAME_EXPIRES("display_name_expires");
static const std::string DISPLAY_NAME_NEXT_UPDATE("display_name_next_update");
+bool LLAvatarName::sUseDisplayNames = true;
+
+// Minimum time-to-live (in seconds) for a name entry.
+// Avatar name should always guarantee to expire reasonably soon by default
+// so if the failure to get a valid expiration time was due to something temporary
+// we will eventually request and get the right data.
+const F64 MIN_ENTRY_LIFETIME = 60.0;
+
LLAvatarName::LLAvatarName()
: mUsername(),
mDisplayName(),
@@ -61,6 +70,17 @@ bool LLAvatarName::operator<(const LLAvatarName& rhs) const
return mUsername < rhs.mUsername;
}
+//static
+void LLAvatarName::setUseDisplayNames(bool use)
+{
+ sUseDisplayNames = use;
+}
+//static
+bool LLAvatarName::useDisplayNames()
+{
+ return sUseDisplayNames;
+}
+
LLSD LLAvatarName::asLLSD() const
{
LLSD sd;
@@ -85,21 +105,75 @@ void LLAvatarName::fromLLSD(const LLSD& sd)
mExpires = expires.secondsSinceEpoch();
LLDate next_update = sd[DISPLAY_NAME_NEXT_UPDATE];
mNextUpdate = next_update.secondsSinceEpoch();
+
+ // Some avatars don't have explicit display names set. Force a legible display name here.
+ if (mDisplayName.empty())
+ {
+ mDisplayName = mUsername;
+ }
+}
+
+// Transform a string (typically provided by the legacy service) into a decent
+// avatar name instance.
+void LLAvatarName::fromString(const std::string& full_name)
+{
+ mDisplayName = full_name;
+ std::string::size_type index = full_name.find(' ');
+ if (index != std::string::npos)
+ {
+ // The name is in 2 parts (first last)
+ mLegacyFirstName = full_name.substr(0, index);
+ mLegacyLastName = full_name.substr(index+1);
+ if (mLegacyLastName != "Resident")
+ {
+ mUsername = mLegacyFirstName + "." + mLegacyLastName;
+ mDisplayName = full_name;
+ LLStringUtil::toLower(mUsername);
+ }
+ else
+ {
+ // Very old names do have a dummy "Resident" last name
+ // that we choose to hide from users.
+ mUsername = mLegacyFirstName;
+ mDisplayName = mLegacyFirstName;
+ }
+ }
+ else
+ {
+ mLegacyFirstName = full_name;
+ mLegacyLastName = "";
+ mUsername = full_name;
+ mDisplayName = full_name;
+ }
+ mIsDisplayNameDefault = true;
+ mIsTemporaryName = true;
+ setExpires(MIN_ENTRY_LIFETIME);
+}
+
+void LLAvatarName::setExpires(F64 expires)
+{
+ mExpires = LLFrameTimer::getTotalSeconds() + expires;
}
std::string LLAvatarName::getCompleteName() const
{
std::string name;
- if (mUsername.empty() || mIsDisplayNameDefault)
- // If the display name feature is off
- // OR this particular display name is defaulted (i.e. based on user name),
- // then display only the easier to read instance of the person's name.
+ if (sUseDisplayNames)
{
- name = mDisplayName;
+ if (mUsername.empty() || mIsDisplayNameDefault)
+ {
+ // If this particular display name is defaulted (i.e. based on user name),
+ // then display only the easier to read instance of the person's name.
+ name = mDisplayName;
+ }
+ else
+ {
+ name = mDisplayName + " (" + mUsername + ")";
+ }
}
else
{
- name = mDisplayName + " (" + mUsername + ")";
+ name = getUserName();
}
return name;
}
@@ -118,3 +192,48 @@ std::string LLAvatarName::getLegacyName() const
name += mLegacyLastName;
return name;
}
+
+std::string LLAvatarName::getDisplayName() const
+{
+ if (sUseDisplayNames)
+ {
+ return mDisplayName;
+ }
+ else
+ {
+ return getUserName();
+ }
+}
+
+std::string LLAvatarName::getUserName() const
+{
+ std::string name;
+ if (mLegacyLastName.empty() || (mLegacyLastName == "Resident"))
+ {
+ if (mLegacyFirstName.empty())
+ {
+ // If we cannot create a user name from the legacy strings, use the display name
+ name = mDisplayName;
+ }
+ else
+ {
+ // The last name might be empty if it defaulted to "Resident"
+ name = mLegacyFirstName;
+ }
+ }
+ else
+ {
+ name = mLegacyFirstName + " " + mLegacyLastName;
+ }
+ return name;
+}
+
+void LLAvatarName::dump() const
+{
+ LL_DEBUGS("AvNameCache") << "LLAvatarName: "
+ << "user '" << mUsername << "' "
+ << "display '" << mDisplayName << "' "
+ << "expires in " << mExpires - LLFrameTimer::getTotalSeconds() << " seconds"
+ << LL_ENDL;
+}
+
diff --git a/indra/llcommon/llavatarname.h b/indra/llcommon/llavatarname.h
index ba258d6d52..7542a8dece 100644
--- a/indra/llcommon/llavatarname.h
+++ b/indra/llcommon/llavatarname.h
@@ -39,10 +39,27 @@ public:
bool operator<(const LLAvatarName& rhs) const;
+ // Conversion to and from LLSD (cache file or server response)
LLSD asLLSD() const;
-
void fromLLSD(const LLSD& sd);
+ // Used only in legacy mode when the display name capability is not provided server side
+ // or to otherwise create a temporary valid item.
+ void fromString(const std::string& full_name);
+
+ // Set the name object to become invalid in "expires" seconds from now
+ void setExpires(F64 expires);
+
+ // Set and get the display name flag set by the user in preferences.
+ static void setUseDisplayNames(bool use);
+ static bool useDisplayNames();
+
+ // A name object is valid if not temporary and not yet expired (default is expiration not checked)
+ bool isValidName(F64 max_unrefreshed = 0.0f) const { return !mIsTemporaryName && (mExpires >= max_unrefreshed); }
+
+ // Return true if the name is made up from legacy or temporary data
+ bool isDisplayNameDefault() const { return mIsDisplayNameDefault; }
+
// For normal names, returns "James Linden (james.linden)"
// When display names are disabled returns just "James Linden"
std::string getCompleteName() const;
@@ -51,11 +68,38 @@ public:
// compatibility with systems like voice and muting
// *TODO: Eliminate this in favor of username only
std::string getLegacyName() const;
+
+ // "José Sanchez" or "James Linden", UTF-8 encoded Unicode
+ // Takes the display name preference into account. This is truly the name that should
+ // be used for all UI where an avatar name has to be used unless we truly want something else (rare)
+ std::string getDisplayName() const;
+
+ // Returns "James Linden" or "bobsmith123 Resident"
+ // Used where we explicitely prefer or need a non UTF-8 legacy (ASCII) name
+ // Also used for backwards compatibility with systems like voice and muting
+ std::string getUserName() const;
+
+ // Returns "james.linden" or the legacy name for very old names
+ std::string getAccountName() const { return mUsername; }
+ // Debug print of the object
+ void dump() const;
+
+ // Names can change, so need to keep track of when name was
+ // last checked.
+ // Unix time-from-epoch seconds for efficiency
+ F64 mExpires;
+
+ // You can only change your name every N hours, so record
+ // when the next update is allowed
+ // Unix time-from-epoch seconds
+ F64 mNextUpdate;
+
+private:
// "bobsmith123" or "james.linden", US-ASCII only
std::string mUsername;
- // "Jose' Sanchez" or "James Linden", UTF-8 encoded Unicode
+ // "José Sanchez" or "James Linden", UTF-8 encoded Unicode
// Contains data whether or not user has explicitly set
// a display name; may duplicate their username.
std::string mDisplayName;
@@ -81,15 +125,9 @@ public:
// shown in UI, but are not serialized.
bool mIsTemporaryName;
- // Names can change, so need to keep track of when name was
- // last checked.
- // Unix time-from-epoch seconds for efficiency
- F64 mExpires;
-
- // You can only change your name every N hours, so record
- // when the next update is allowed
- // Unix time-from-epoch seconds
- F64 mNextUpdate;
+ // Global flag indicating if display name should be used or not
+ // This will affect the output of the high level "get" methods
+ static bool sUseDisplayNames;
};
#endif
diff --git a/indra/llcommon/lldictionary.h b/indra/llcommon/lldictionary.h
index bc3bc3e74a..c752859a36 100644
--- a/indra/llcommon/lldictionary.h
+++ b/indra/llcommon/lldictionary.h
@@ -30,6 +30,8 @@
#include <map>
#include <string>
+#include "llerror.h"
+
struct LL_COMMON_API LLDictionaryEntry
{
LLDictionaryEntry(const std::string &name);
diff --git a/indra/llcommon/llfasttimer.cpp b/indra/llcommon/llfasttimer.cpp
index 6970c29092..9b15804e97 100644
--- a/indra/llcommon/llfasttimer.cpp
+++ b/indra/llcommon/llfasttimer.cpp
@@ -561,6 +561,12 @@ std::vector<LLFastTimer::NamedTimer*>& LLFastTimer::NamedTimer::getChildren()
return mChildren;
}
+// static
+LLFastTimer::NamedTimer& LLFastTimer::NamedTimer::getRootNamedTimer()
+{
+ return *NamedTimerFactory::instance().getRootTimer();
+}
+
//static
void LLFastTimer::nextFrame()
{
diff --git a/indra/llcommon/llfasttimer.h b/indra/llcommon/llfasttimer.h
index e42e549df5..81c4b78775 100644
--- a/indra/llcommon/llfasttimer.h
+++ b/indra/llcommon/llfasttimer.h
@@ -91,6 +91,8 @@ public:
U32 getHistoricalCount(S32 history_index = 0) const;
U32 getHistoricalCalls(S32 history_index = 0) const;
+ static NamedTimer& getRootNamedTimer();
+
void setFrameState(FrameState* state) { mFrameState = state; state->setNamedTimer(this); }
FrameState& getFrameState() const;
diff --git a/indra/llcommon/llfile.cpp b/indra/llcommon/llfile.cpp
index c51d042a3d..bc615ed39e 100644
--- a/indra/llcommon/llfile.cpp
+++ b/indra/llcommon/llfile.cpp
@@ -56,6 +56,8 @@ std::string strerr(int errn)
return buffer;
}
+typedef std::basic_ios<char,std::char_traits < char > > _Myios;
+
#else
// On Posix we want to call strerror_r(), but alarmingly, there are two
// different variants. The one that returns int always populates the passed
@@ -324,9 +326,10 @@ const char *LLFile::tmpdir()
/***************** Modified file stream created to overcome the incorrect behaviour of posix fopen in windows *******************/
-#if USE_LLFILESTREAMS
+#if LL_WINDOWS
-LLFILE * LLFile::_Fiopen(const std::string& filename, std::ios::openmode mode,int) // protection currently unused
+LLFILE * LLFile::_Fiopen(const std::string& filename,
+ std::ios::openmode mode)
{ // open a file
static const char *mods[] =
{ // fopen mode strings corresponding to valid[i]
@@ -385,117 +388,681 @@ LLFILE * LLFile::_Fiopen(const std::string& filename, std::ios::openmode mode,in
return (0);
}
-/************** input file stream ********************************/
+#endif /* LL_WINDOWS */
-void llifstream::close()
-{ // close the C stream
- if (_Filebuffer && _Filebuffer->close() == 0)
+/************** llstdio file buffer ********************************/
+
+
+//llstdio_filebuf* llstdio_filebuf::open(const char *_Filename,
+// ios_base::openmode _Mode)
+//{
+//#if LL_WINDOWS
+// _Filet *_File;
+// if (is_open() || (_File = LLFILE::_Fiopen(_Filename, _Mode)) == 0)
+// return (0); // open failed
+//
+// _Init(_File, _Openfl);
+// _Initcvt(&_USE(_Mysb::getloc(), _Cvt));
+// return (this); // open succeeded
+//#else
+// std::filebuf* _file = std::filebuf::open(_Filename, _Mode);
+// if (NULL == _file) return NULL;
+// return this;
+//#endif
+//}
+
+
+// *TODO: Seek the underlying c stream for better cross-platform compatibility?
+#if !LL_WINDOWS
+llstdio_filebuf::int_type llstdio_filebuf::overflow(llstdio_filebuf::int_type __c)
+{
+ int_type __ret = traits_type::eof();
+ const bool __testeof = traits_type::eq_int_type(__c, __ret);
+ const bool __testout = _M_mode & ios_base::out;
+ if (__testout && !_M_reading)
{
- _Myios::setstate(ios_base::failbit); /*Flawfinder: ignore*/
+ if (this->pbase() < this->pptr())
+ {
+ // If appropriate, append the overflow char.
+ if (!__testeof)
+ {
+ *this->pptr() = traits_type::to_char_type(__c);
+ this->pbump(1);
+ }
+
+ // Convert pending sequence to external representation,
+ // and output.
+ if (_convert_to_external(this->pbase(),
+ this->pptr() - this->pbase()))
+ {
+ _M_set_buffer(0);
+ __ret = traits_type::not_eof(__c);
+ }
+ }
+ else if (_M_buf_size > 1)
+ {
+ // Overflow in 'uncommitted' mode: set _M_writing, set
+ // the buffer to the initial 'write' mode, and put __c
+ // into the buffer.
+ _M_set_buffer(0);
+ _M_writing = true;
+ if (!__testeof)
+ {
+ *this->pptr() = traits_type::to_char_type(__c);
+ this->pbump(1);
+ }
+ __ret = traits_type::not_eof(__c);
+ }
+ else
+ {
+ // Unbuffered.
+ char_type __conv = traits_type::to_char_type(__c);
+ if (__testeof || _convert_to_external(&__conv, 1))
+ {
+ _M_writing = true;
+ __ret = traits_type::not_eof(__c);
+ }
+ }
}
+ return __ret;
}
-void llifstream::open(const std::string& _Filename, /* Flawfinder: ignore */
- ios_base::openmode _Mode,
- int _Prot)
-{ // open a C stream with specified mode
+bool llstdio_filebuf::_convert_to_external(char_type* __ibuf,
+ std::streamsize __ilen)
+{
+ // Sizes of external and pending output.
+ streamsize __elen;
+ streamsize __plen;
+ if (__check_facet(_M_codecvt).always_noconv())
+ {
+ //__elen = _M_file.xsputn(reinterpret_cast<char*>(__ibuf), __ilen);
+ __elen = fwrite(reinterpret_cast<void*>(__ibuf), 1,
+ __ilen, _M_file.file());
+ __plen = __ilen;
+ }
+ else
+ {
+ // Worst-case number of external bytes needed.
+ // XXX Not done encoding() == -1.
+ streamsize __blen = __ilen * _M_codecvt->max_length();
+ char* __buf = static_cast<char*>(__builtin_alloca(__blen));
- LLFILE* filep = LLFile::_Fiopen(_Filename,_Mode | ios_base::in, _Prot);
- if(filep == NULL)
+ char* __bend;
+ const char_type* __iend;
+ codecvt_base::result __r;
+ __r = _M_codecvt->out(_M_state_cur, __ibuf, __ibuf + __ilen,
+ __iend, __buf, __buf + __blen, __bend);
+
+ if (__r == codecvt_base::ok || __r == codecvt_base::partial)
+ __blen = __bend - __buf;
+ else if (__r == codecvt_base::noconv)
+ {
+ // Same as the always_noconv case above.
+ __buf = reinterpret_cast<char*>(__ibuf);
+ __blen = __ilen;
+ }
+ else
+ __throw_ios_failure(__N("llstdio_filebuf::_convert_to_external "
+ "conversion error"));
+
+ //__elen = _M_file.xsputn(__buf, __blen);
+ __elen = fwrite(__buf, 1, __blen, _M_file.file());
+ __plen = __blen;
+
+ // Try once more for partial conversions.
+ if (__r == codecvt_base::partial && __elen == __plen)
+ {
+ const char_type* __iresume = __iend;
+ streamsize __rlen = this->pptr() - __iend;
+ __r = _M_codecvt->out(_M_state_cur, __iresume,
+ __iresume + __rlen, __iend, __buf,
+ __buf + __blen, __bend);
+ if (__r != codecvt_base::error)
+ {
+ __rlen = __bend - __buf;
+ //__elen = _M_file.xsputn(__buf, __rlen);
+ __elen = fwrite(__buf, 1, __rlen, _M_file.file());
+ __plen = __rlen;
+ }
+ else
+ {
+ __throw_ios_failure(__N("llstdio_filebuf::_convert_to_external "
+ "conversion error"));
+ }
+ }
+ }
+ return __elen == __plen;
+}
+
+llstdio_filebuf::int_type llstdio_filebuf::underflow()
+{
+ int_type __ret = traits_type::eof();
+ const bool __testin = _M_mode & ios_base::in;
+ if (__testin)
{
- _Myios::setstate(ios_base::failbit); /*Flawfinder: ignore*/
- return;
+ if (_M_writing)
+ {
+ if (overflow() == traits_type::eof())
+ return __ret;
+ //_M_set_buffer(-1);
+ //_M_writing = false;
+ }
+ // Check for pback madness, and if so switch back to the
+ // normal buffers and jet outta here before expensive
+ // fileops happen...
+ _M_destroy_pback();
+
+ if (this->gptr() < this->egptr())
+ return traits_type::to_int_type(*this->gptr());
+
+ // Get and convert input sequence.
+ const size_t __buflen = _M_buf_size > 1 ? _M_buf_size - 1 : 1;
+
+ // Will be set to true if ::fread() returns 0 indicating EOF.
+ bool __got_eof = false;
+ // Number of internal characters produced.
+ streamsize __ilen = 0;
+ codecvt_base::result __r = codecvt_base::ok;
+ if (__check_facet(_M_codecvt).always_noconv())
+ {
+ //__ilen = _M_file.xsgetn(reinterpret_cast<char*>(this->eback()),
+ // __buflen);
+ __ilen = fread(reinterpret_cast<void*>(this->eback()), 1,
+ __buflen, _M_file.file());
+ if (__ilen == 0)
+ __got_eof = true;
+ }
+ else
+ {
+ // Worst-case number of external bytes.
+ // XXX Not done encoding() == -1.
+ const int __enc = _M_codecvt->encoding();
+ streamsize __blen; // Minimum buffer size.
+ streamsize __rlen; // Number of chars to read.
+ if (__enc > 0)
+ __blen = __rlen = __buflen * __enc;
+ else
+ {
+ __blen = __buflen + _M_codecvt->max_length() - 1;
+ __rlen = __buflen;
+ }
+ const streamsize __remainder = _M_ext_end - _M_ext_next;
+ __rlen = __rlen > __remainder ? __rlen - __remainder : 0;
+
+ // An imbue in 'read' mode implies first converting the external
+ // chars already present.
+ if (_M_reading && this->egptr() == this->eback() && __remainder)
+ __rlen = 0;
+
+ // Allocate buffer if necessary and move unconverted
+ // bytes to front.
+ if (_M_ext_buf_size < __blen)
+ {
+ char* __buf = new char[__blen];
+ if (__remainder)
+ __builtin_memcpy(__buf, _M_ext_next, __remainder);
+
+ delete [] _M_ext_buf;
+ _M_ext_buf = __buf;
+ _M_ext_buf_size = __blen;
+ }
+ else if (__remainder)
+ __builtin_memmove(_M_ext_buf, _M_ext_next, __remainder);
+
+ _M_ext_next = _M_ext_buf;
+ _M_ext_end = _M_ext_buf + __remainder;
+ _M_state_last = _M_state_cur;
+
+ do
+ {
+ if (__rlen > 0)
+ {
+ // Sanity check!
+ // This may fail if the return value of
+ // codecvt::max_length() is bogus.
+ if (_M_ext_end - _M_ext_buf + __rlen > _M_ext_buf_size)
+ {
+ __throw_ios_failure(__N("llstdio_filebuf::underflow "
+ "codecvt::max_length() "
+ "is not valid"));
+ }
+ //streamsize __elen = _M_file.xsgetn(_M_ext_end, __rlen);
+ streamsize __elen = fread(_M_ext_end, 1,
+ __rlen, _M_file.file());
+ if (__elen == 0)
+ __got_eof = true;
+ else if (__elen == -1)
+ break;
+ //_M_ext_end += __elen;
+ }
+
+ char_type* __iend = this->eback();
+ if (_M_ext_next < _M_ext_end)
+ {
+ __r = _M_codecvt->in(_M_state_cur, _M_ext_next,
+ _M_ext_end, _M_ext_next,
+ this->eback(),
+ this->eback() + __buflen, __iend);
+ }
+ if (__r == codecvt_base::noconv)
+ {
+ size_t __avail = _M_ext_end - _M_ext_buf;
+ __ilen = std::min(__avail, __buflen);
+ traits_type::copy(this->eback(),
+ reinterpret_cast<char_type*>
+ (_M_ext_buf), __ilen);
+ _M_ext_next = _M_ext_buf + __ilen;
+ }
+ else
+ __ilen = __iend - this->eback();
+
+ // _M_codecvt->in may return error while __ilen > 0: this is
+ // ok, and actually occurs in case of mixed encodings (e.g.,
+ // XML files).
+ if (__r == codecvt_base::error)
+ break;
+
+ __rlen = 1;
+ } while (__ilen == 0 && !__got_eof);
+ }
+
+ if (__ilen > 0)
+ {
+ _M_set_buffer(__ilen);
+ _M_reading = true;
+ __ret = traits_type::to_int_type(*this->gptr());
+ }
+ else if (__got_eof)
+ {
+ // If the actual end of file is reached, set 'uncommitted'
+ // mode, thus allowing an immediate write without an
+ // intervening seek.
+ _M_set_buffer(-1);
+ _M_reading = false;
+ // However, reaching it while looping on partial means that
+ // the file has got an incomplete character.
+ if (__r == codecvt_base::partial)
+ __throw_ios_failure(__N("llstdio_filebuf::underflow "
+ "incomplete character in file"));
+ }
+ else if (__r == codecvt_base::error)
+ __throw_ios_failure(__N("llstdio_filebuf::underflow "
+ "invalid byte sequence in file"));
+ else
+ __throw_ios_failure(__N("llstdio_filebuf::underflow "
+ "error reading the file"));
}
- llassert(_Filebuffer == NULL);
- _Filebuffer = new _Myfb(filep);
- _ShouldClose = true;
- _Myios::init(_Filebuffer);
+ return __ret;
}
-bool llifstream::is_open() const
-{ // test if C stream has been opened
- if(_Filebuffer)
- return (_Filebuffer->is_open());
- return false;
+std::streamsize llstdio_filebuf::xsgetn(char_type* __s, std::streamsize __n)
+{
+ // Clear out pback buffer before going on to the real deal...
+ streamsize __ret = 0;
+ if (_M_pback_init)
+ {
+ if (__n > 0 && this->gptr() == this->eback())
+ {
+ *__s++ = *this->gptr();
+ this->gbump(1);
+ __ret = 1;
+ --__n;
+ }
+ _M_destroy_pback();
+ }
+
+ // Optimization in the always_noconv() case, to be generalized in the
+ // future: when __n > __buflen we read directly instead of using the
+ // buffer repeatedly.
+ const bool __testin = _M_mode & ios_base::in;
+ const streamsize __buflen = _M_buf_size > 1 ? _M_buf_size - 1 : 1;
+
+ if (__n > __buflen && __check_facet(_M_codecvt).always_noconv()
+ && __testin && !_M_writing)
+ {
+ // First, copy the chars already present in the buffer.
+ const streamsize __avail = this->egptr() - this->gptr();
+ if (__avail != 0)
+ {
+ if (__avail == 1)
+ *__s = *this->gptr();
+ else
+ traits_type::copy(__s, this->gptr(), __avail);
+ __s += __avail;
+ this->gbump(__avail);
+ __ret += __avail;
+ __n -= __avail;
+ }
+
+ // Need to loop in case of short reads (relatively common
+ // with pipes).
+ streamsize __len;
+ for (;;)
+ {
+ //__len = _M_file.xsgetn(reinterpret_cast<char*>(__s), __n);
+ __len = fread(reinterpret_cast<void*>(__s), 1,
+ __n, _M_file.file());
+ if (__len == -1)
+ __throw_ios_failure(__N("llstdio_filebuf::xsgetn "
+ "error reading the file"));
+ if (__len == 0)
+ break;
+
+ __n -= __len;
+ __ret += __len;
+ if (__n == 0)
+ break;
+
+ __s += __len;
+ }
+
+ if (__n == 0)
+ {
+ _M_set_buffer(0);
+ _M_reading = true;
+ }
+ else if (__len == 0)
+ {
+ // If end of file is reached, set 'uncommitted'
+ // mode, thus allowing an immediate write without
+ // an intervening seek.
+ _M_set_buffer(-1);
+ _M_reading = false;
+ }
+ }
+ else
+ __ret += __streambuf_type::xsgetn(__s, __n);
+
+ return __ret;
}
-llifstream::~llifstream()
+
+std::streamsize llstdio_filebuf::xsputn(char_type* __s, std::streamsize __n)
{
- if (_ShouldClose)
+ // Optimization in the always_noconv() case, to be generalized in the
+ // future: when __n is sufficiently large we write directly instead of
+ // using the buffer.
+ streamsize __ret = 0;
+ const bool __testout = _M_mode & ios_base::out;
+ if (__check_facet(_M_codecvt).always_noconv()
+ && __testout && !_M_reading)
{
- close();
+ // Measurement would reveal the best choice.
+ const streamsize __chunk = 1ul << 10;
+ streamsize __bufavail = this->epptr() - this->pptr();
+
+ // Don't mistake 'uncommitted' mode buffered with unbuffered.
+ if (!_M_writing && _M_buf_size > 1)
+ __bufavail = _M_buf_size - 1;
+
+ const streamsize __limit = std::min(__chunk, __bufavail);
+ if (__n >= __limit)
+ {
+ const streamsize __buffill = this->pptr() - this->pbase();
+ const char* __buf = reinterpret_cast<const char*>(this->pbase());
+ //__ret = _M_file.xsputn_2(__buf, __buffill,
+ // reinterpret_cast<const char*>(__s), __n);
+ if (__buffill)
+ {
+ __ret = fwrite(__buf, 1, __buffill, _M_file.file());
+ }
+ if (__ret == __buffill)
+ {
+ __ret += fwrite(reinterpret_cast<const char*>(__s), 1,
+ __n, _M_file.file());
+ }
+ if (__ret == __buffill + __n)
+ {
+ _M_set_buffer(0);
+ _M_writing = true;
+ }
+ if (__ret > __buffill)
+ __ret -= __buffill;
+ else
+ __ret = 0;
+ }
+ else
+ __ret = __streambuf_type::xsputn(__s, __n);
}
- delete _Filebuffer;
+ else
+ __ret = __streambuf_type::xsputn(__s, __n);
+ return __ret;
}
-llifstream::llifstream(const std::string& _Filename,
- ios_base::openmode _Mode,
- int _Prot)
- : std::basic_istream< char , std::char_traits< char > >(NULL,true),_Filebuffer(NULL),_ShouldClose(false)
+int llstdio_filebuf::sync()
+{
+ return (_M_file.sync() == 0 ? 0 : -1);
+}
+#endif
+
+/************** input file stream ********************************/
-{ // construct with named file and specified mode
- open(_Filename, _Mode | ios_base::in, _Prot); /* Flawfinder: ignore */
+
+llifstream::llifstream() : _M_filebuf(),
+#if LL_WINDOWS
+ std::istream(&_M_filebuf) {}
+#else
+ std::istream()
+{
+ this->init(&_M_filebuf);
+}
+#endif
+
+// explicit
+llifstream::llifstream(const std::string& _Filename,
+ ios_base::openmode _Mode) : _M_filebuf(),
+#if LL_WINDOWS
+ std::istream(&_M_filebuf)
+{
+ if (_M_filebuf.open(_Filename.c_str(), _Mode | ios_base::in) == 0)
+ {
+ _Myios::setstate(ios_base::failbit);
+ }
}
+#else
+ std::istream()
+{
+ this->init(&_M_filebuf);
+ this->open(_Filename.c_str(), _Mode | ios_base::in);
+}
+#endif
+// explicit
+llifstream::llifstream(const char* _Filename,
+ ios_base::openmode _Mode) : _M_filebuf(),
+#if LL_WINDOWS
+ std::istream(&_M_filebuf)
+{
+ if (_M_filebuf.open(_Filename, _Mode | ios_base::in) == 0)
+ {
+ _Myios::setstate(ios_base::failbit);
+ }
+}
+#else
+ std::istream()
+{
+ this->init(&_M_filebuf);
+ this->open(_Filename, _Mode | ios_base::in);
+}
+#endif
-/************** output file stream ********************************/
-bool llofstream::is_open() const
+// explicit
+llifstream::llifstream(_Filet *_File,
+ ios_base::openmode _Mode, size_t _Size) :
+ _M_filebuf(_File, _Mode, _Size),
+#if LL_WINDOWS
+ std::istream(&_M_filebuf) {}
+#else
+ std::istream()
+{
+ this->init(&_M_filebuf);
+}
+#endif
+
+#if !LL_WINDOWS
+// explicit
+llifstream::llifstream(int __fd,
+ ios_base::openmode _Mode, size_t _Size) :
+ _M_filebuf(__fd, _Mode, _Size),
+ std::istream()
+{
+ this->init(&_M_filebuf);
+}
+#endif
+
+bool llifstream::is_open() const
{ // test if C stream has been opened
- if(_Filebuffer)
- return (_Filebuffer->is_open());
- return false;
+ return _M_filebuf.is_open();
}
-void llofstream::open(const std::string& _Filename, /* Flawfinder: ignore */
- ios_base::openmode _Mode,
- int _Prot)
+void llifstream::open(const char* _Filename, ios_base::openmode _Mode)
{ // open a C stream with specified mode
-
- LLFILE* filep = LLFile::_Fiopen(_Filename,_Mode | ios_base::out, _Prot);
- if(filep == NULL)
+ if (_M_filebuf.open(_Filename, _Mode | ios_base::in) == 0)
+#if LL_WINDOWS
+ {
+ _Myios::setstate(ios_base::failbit);
+ }
+ else
{
- _Myios::setstate(ios_base::failbit); /*Flawfinder: ignore*/
- return;
+ _Myios::clear();
}
- llassert(_Filebuffer==NULL);
- _Filebuffer = new _Myfb(filep);
- _ShouldClose = true;
- _Myios::init(_Filebuffer);
+#else
+ {
+ this->setstate(ios_base::failbit);
+ }
+ else
+ {
+ this->clear();
+ }
+#endif
}
-void llofstream::close()
+void llifstream::close()
{ // close the C stream
- if(is_open())
+ if (_M_filebuf.close() == 0)
{
- if (_Filebuffer->close() == 0)
- {
- _Myios::setstate(ios_base::failbit); /*Flawfinder: ignore*/
- }
- delete _Filebuffer;
- _Filebuffer = NULL;
- _ShouldClose = false;
+#if LL_WINDOWS
+ _Myios::setstate(ios_base::failbit);
+#else
+ this->setstate(ios_base::failbit);
+#endif
}
}
+
+/************** output file stream ********************************/
+
+
+llofstream::llofstream() : _M_filebuf(),
+#if LL_WINDOWS
+ std::ostream(&_M_filebuf) {}
+#else
+ std::ostream()
+{
+ this->init(&_M_filebuf);
+}
+#endif
+
+// explicit
llofstream::llofstream(const std::string& _Filename,
- std::ios_base::openmode _Mode,
- int _Prot)
- : std::basic_ostream<char,std::char_traits < char > >(NULL,true),_Filebuffer(NULL),_ShouldClose(false)
-{ // construct with named file and specified mode
- open(_Filename, _Mode , _Prot); /* Flawfinder: ignore */
+ ios_base::openmode _Mode) : _M_filebuf(),
+#if LL_WINDOWS
+ std::ostream(&_M_filebuf)
+{
+ if (_M_filebuf.open(_Filename.c_str(), _Mode | ios_base::out) == 0)
+ {
+ _Myios::setstate(ios_base::failbit);
+ }
+}
+#else
+ std::ostream()
+{
+ this->init(&_M_filebuf);
+ this->open(_Filename.c_str(), _Mode | ios_base::out);
+}
+#endif
+
+// explicit
+llofstream::llofstream(const char* _Filename,
+ ios_base::openmode _Mode) : _M_filebuf(),
+#if LL_WINDOWS
+ std::ostream(&_M_filebuf)
+{
+ if (_M_filebuf.open(_Filename, _Mode | ios_base::out) == 0)
+ {
+ _Myios::setstate(ios_base::failbit);
+ }
+}
+#else
+ std::ostream()
+{
+ this->init(&_M_filebuf);
+ this->open(_Filename, _Mode | ios_base::out);
+}
+#endif
+
+// explicit
+llofstream::llofstream(_Filet *_File,
+ ios_base::openmode _Mode, size_t _Size) :
+ _M_filebuf(_File, _Mode, _Size),
+#if LL_WINDOWS
+ std::ostream(&_M_filebuf) {}
+#else
+ std::ostream()
+{
+ this->init(&_M_filebuf);
}
+#endif
-llofstream::~llofstream()
+#if !LL_WINDOWS
+// explicit
+llofstream::llofstream(int __fd,
+ ios_base::openmode _Mode, size_t _Size) :
+ _M_filebuf(__fd, _Mode, _Size),
+ std::ostream()
{
- // destroy the object
- if (_ShouldClose)
+ this->init(&_M_filebuf);
+}
+#endif
+
+bool llofstream::is_open() const
+{ // test if C stream has been opened
+ return _M_filebuf.is_open();
+}
+
+void llofstream::open(const char* _Filename, ios_base::openmode _Mode)
+{ // open a C stream with specified mode
+ if (_M_filebuf.open(_Filename, _Mode | ios_base::out) == 0)
+#if LL_WINDOWS
+ {
+ _Myios::setstate(ios_base::failbit);
+ }
+ else
{
- close();
+ _Myios::clear();
}
- delete _Filebuffer;
+#else
+ {
+ this->setstate(ios_base::failbit);
+ }
+ else
+ {
+ this->clear();
+ }
+#endif
}
-#endif // #if USE_LLFILESTREAMS
+void llofstream::close()
+{ // close the C stream
+ if (_M_filebuf.close() == 0)
+ {
+#if LL_WINDOWS
+ _Myios::setstate(ios_base::failbit);
+#else
+ this->setstate(ios_base::failbit);
+#endif
+ }
+}
/************** helper functions ********************************/
diff --git a/indra/llcommon/llfile.h b/indra/llcommon/llfile.h
index dd7d36513a..9d70db96ea 100644
--- a/indra/llcommon/llfile.h
+++ b/indra/llcommon/llfile.h
@@ -35,16 +35,9 @@
* Attempts to mostly mirror the POSIX style IO functions.
*/
-typedef FILE LLFILE;
+typedef FILE LLFILE;
#include <fstream>
-
-#ifdef LL_WINDOWS
-#define USE_LLFILESTREAMS 1
-#else
-#define USE_LLFILESTREAMS 0
-#endif
-
#include <sys/stat.h>
#if LL_WINDOWS
@@ -52,6 +45,8 @@ typedef FILE LLFILE;
typedef struct _stat llstat;
#else
typedef struct stat llstat;
+#include <ext/stdio_filebuf.h>
+#include <bits/postypes.h>
#endif
#ifndef S_ISREG
@@ -83,142 +78,342 @@ public:
static int stat(const std::string& filename,llstat* file_status);
static bool isdir(const std::string& filename);
static bool isfile(const std::string& filename);
- static LLFILE * _Fiopen(const std::string& filename, std::ios::openmode mode,int); // protection currently unused
+ static LLFILE * _Fiopen(const std::string& filename,
+ std::ios::openmode mode);
static const char * tmpdir();
};
+/**
+ * @brief Provides a layer of compatibility for C/POSIX.
+ *
+ * This is taken from both the GNU __gnu_cxx::stdio_filebuf extension and
+ * VC's basic_filebuf implementation.
+ * This file buffer provides extensions for working with standard C FILE*'s
+ * and POSIX file descriptors for platforms that support this.
+*/
+namespace
+{
+#if LL_WINDOWS
+typedef std::filebuf _Myfb;
+#else
+typedef __gnu_cxx::stdio_filebuf< char > _Myfb;
+typedef std::__c_file _Filet;
+#endif /* LL_WINDOWS */
+}
-#if USE_LLFILESTREAMS
-
-class LL_COMMON_API llifstream : public std::basic_istream < char , std::char_traits < char > >
+class LL_COMMON_API llstdio_filebuf : public _Myfb
{
- // input stream associated with a C stream
public:
- typedef std::basic_ifstream<char,std::char_traits < char > > _Myt;
- typedef std::basic_filebuf<char,std::char_traits< char > > _Myfb;
- typedef std::basic_ios<char,std::char_traits< char > > _Myios;
-
- llifstream()
- : std::basic_istream<char,std::char_traits< char > >(NULL,true),_Filebuffer(NULL),_ShouldClose(false)
- { // construct unopened
- }
+ /**
+ * deferred initialization / destruction
+ */
+ llstdio_filebuf() : _Myfb() {}
+ virtual ~llstdio_filebuf() {}
+
+ /**
+ * @param f An open @c FILE*.
+ * @param mode Same meaning as in a standard filebuf.
+ * @param size Optimal or preferred size of internal buffer, in chars.
+ * Defaults to system's @c BUFSIZ.
+ *
+ * This constructor associates a file stream buffer with an open
+ * C @c FILE*. The @c FILE* will not be automatically closed when the
+ * stdio_filebuf is closed/destroyed.
+ */
+ llstdio_filebuf(_Filet* __f, std::ios_base::openmode __mode,
+ //size_t __size = static_cast<size_t>(BUFSIZ)) :
+ size_t __size = static_cast<size_t>(1)) :
+#if LL_WINDOWS
+ _Myfb(__f) {}
+#else
+ _Myfb(__f, __mode, __size) {}
+#endif
- explicit llifstream(const std::string& _Filename,
- ios_base::openmode _Mode = ios_base::in,
- int _Prot = (int)ios_base::_Openprot);
-
- explicit llifstream(_Filet *_File)
- : std::basic_istream<char,std::char_traits< char > >(NULL,true),
- _Filebuffer(new _Myfb(_File)),
- _ShouldClose(false)
- { // construct with specified C stream
- }
- virtual ~llifstream();
-
- _Myfb *rdbuf() const
- { // return pointer to file buffer
- return _Filebuffer;
- }
- bool is_open() const;
- void open(const std::string& _Filename, /* Flawfinder: ignore */
- ios_base::openmode _Mode = ios_base::in,
- int _Prot = (int)ios_base::_Openprot);
- void close();
+ /**
+ * @brief Opens an external file.
+ * @param s The name of the file.
+ * @param mode The open mode flags.
+ * @return @c this on success, NULL on failure
+ *
+ * If a file is already open, this function immediately fails.
+ * Otherwise it tries to open the file named @a s using the flags
+ * given in @a mode.
+ */
+ //llstdio_filebuf* open(const char *_Filename,
+ // std::ios_base::openmode _Mode);
+
+ /**
+ * @param fd An open file descriptor.
+ * @param mode Same meaning as in a standard filebuf.
+ * @param size Optimal or preferred size of internal buffer, in chars.
+ *
+ * This constructor associates a file stream buffer with an open
+ * POSIX file descriptor. The file descriptor will be automatically
+ * closed when the stdio_filebuf is closed/destroyed.
+ */
+#if !LL_WINDOWS
+ llstdio_filebuf(int __fd, std::ios_base::openmode __mode,
+ //size_t __size = static_cast<size_t>(BUFSIZ)) :
+ size_t __size = static_cast<size_t>(1)) :
+ _Myfb(__fd, __mode, __size) {}
+#endif
-private:
- _Myfb* _Filebuffer; // the file buffer
- bool _ShouldClose;
+// *TODO: Seek the underlying c stream for better cross-platform compatibility?
+#if !LL_WINDOWS
+protected:
+ /** underflow() and uflow() functions are called to get the next
+ * character from the real input source when the buffer is empty.
+ * Buffered input uses underflow()
+ */
+ /*virtual*/ int_type underflow();
+
+ /* Convert internal byte sequence to external, char-based
+ * sequence via codecvt.
+ */
+ bool _convert_to_external(char_type*, std::streamsize);
+
+ /** The overflow() function is called to transfer characters to the
+ * real output destination when the buffer is full. A call to
+ * overflow(c) outputs the contents of the buffer plus the
+ * character c.
+ * Consume some sequence of the characters in the pending sequence.
+ */
+ /*virtual*/ int_type overflow(int_type __c = traits_type::eof());
+
+ /** sync() flushes the underlying @c FILE* stream.
+ */
+ /*virtual*/ int sync();
+
+ std::streamsize xsgetn(char_type*, std::streamsize);
+ std::streamsize xsputn(char_type*, std::streamsize);
+#endif
};
-class LL_COMMON_API llofstream : public std::basic_ostream< char , std::char_traits < char > >
+/**
+ * @brief Controlling input for files.
+ *
+ * This class supports reading from named files, using the inherited
+ * functions from std::basic_istream. To control the associated
+ * sequence, an instance of std::basic_filebuf (or a platform-specific derivative)
+ * which allows construction using a pre-exisintg file stream buffer.
+ * We refer to this std::basic_filebuf (or derivative) as @c sb.
+*/
+class LL_COMMON_API llifstream : public std::istream
{
+ // input stream associated with a C stream
public:
- typedef std::basic_ostream< char , std::char_traits < char > > _Myt;
- typedef std::basic_filebuf< char , std::char_traits < char > > _Myfb;
- typedef std::basic_ios<char,std::char_traits < char > > _Myios;
-
- llofstream()
- : std::basic_ostream<char,std::char_traits < char > >(NULL,true),_Filebuffer(NULL),_ShouldClose(false)
- { // construct unopened
- }
-
- explicit llofstream(const std::string& _Filename,
- std::ios_base::openmode _Mode = ios_base::out,
- int _Prot = (int)std::ios_base::_Openprot);
-
-
- explicit llofstream(_Filet *_File)
- : std::basic_ostream<char,std::char_traits < char > >(NULL,true),
- _Filebuffer(new _Myfb(_File)),//_File)
- _ShouldClose(false)
- { // construct with specified C stream
- }
-
- virtual ~llofstream();
-
- _Myfb *rdbuf() const
- { // return pointer to file buffer
- return _Filebuffer;
- }
+ // Constructors:
+ /**
+ * @brief Default constructor.
+ *
+ * Initializes @c sb using its default constructor, and passes
+ * @c &sb to the base class initializer. Does not open any files
+ * (you haven't given it a filename to open).
+ */
+ llifstream();
+
+ /**
+ * @brief Create an input file stream.
+ * @param Filename String specifying the filename.
+ * @param Mode Open file in specified mode (see std::ios_base).
+ *
+ * @c ios_base::in is automatically included in @a mode.
+ */
+ explicit llifstream(const std::string& _Filename,
+ ios_base::openmode _Mode = ios_base::in);
+ explicit llifstream(const char* _Filename,
+ ios_base::openmode _Mode = ios_base::in);
+
+ /**
+ * @brief Create a stream using an open c file stream.
+ * @param File An open @c FILE*.
+ @param Mode Same meaning as in a standard filebuf.
+ @param Size Optimal or preferred size of internal buffer, in chars.
+ Defaults to system's @c BUFSIZ.
+ */
+ explicit llifstream(_Filet *_File,
+ ios_base::openmode _Mode = ios_base::in,
+ //size_t _Size = static_cast<size_t>(BUFSIZ));
+ size_t _Size = static_cast<size_t>(1));
+
+ /**
+ * @brief Create a stream using an open file descriptor.
+ * @param fd An open file descriptor.
+ @param Mode Same meaning as in a standard filebuf.
+ @param Size Optimal or preferred size of internal buffer, in chars.
+ Defaults to system's @c BUFSIZ.
+ */
+#if !LL_WINDOWS
+ explicit llifstream(int __fd,
+ ios_base::openmode _Mode = ios_base::in,
+ //size_t _Size = static_cast<size_t>(BUFSIZ));
+ size_t _Size = static_cast<size_t>(1));
+#endif
+ /**
+ * @brief The destructor does nothing.
+ *
+ * The file is closed by the filebuf object, not the formatting
+ * stream.
+ */
+ virtual ~llifstream() {}
+
+ // Members:
+ /**
+ * @brief Accessing the underlying buffer.
+ * @return The current basic_filebuf buffer.
+ *
+ * This hides both signatures of std::basic_ios::rdbuf().
+ */
+ llstdio_filebuf* rdbuf() const
+ { return const_cast<llstdio_filebuf*>(&_M_filebuf); }
+
+ /**
+ * @brief Wrapper to test for an open file.
+ * @return @c rdbuf()->is_open()
+ */
bool is_open() const;
- void open(const std::string& _Filename,ios_base::openmode _Mode = ios_base::out,int _Prot = (int)ios_base::_Openprot); /* Flawfinder: ignore */
-
+ /**
+ * @brief Opens an external file.
+ * @param Filename The name of the file.
+ * @param Node The open mode flags.
+ *
+ * Calls @c llstdio_filebuf::open(s,mode|in). If that function
+ * fails, @c failbit is set in the stream's error state.
+ */
+ void open(const std::string& _Filename,
+ ios_base::openmode _Mode = ios_base::in)
+ { open(_Filename.c_str(), _Mode); }
+ void open(const char* _Filename,
+ ios_base::openmode _Mode = ios_base::in);
+
+ /**
+ * @brief Close the file.
+ *
+ * Calls @c llstdio_filebuf::close(). If that function
+ * fails, @c failbit is set in the stream's error state.
+ */
void close();
private:
- _Myfb *_Filebuffer; // the file buffer
- bool _ShouldClose;
-};
-
-
-
-#else
-//Use standard file streams on non windows platforms
-//#define llifstream std::ifstream
-//#define llofstream std::ofstream
-
-class LL_COMMON_API llifstream : public std::ifstream
-{
-public:
- llifstream() : std::ifstream()
- {
- }
-
- explicit llifstream(const std::string& _Filename, std::_Ios_Openmode _Mode = in)
- : std::ifstream(_Filename.c_str(), _Mode)
- {
- }
- void open(const std::string& _Filename, std::_Ios_Openmode _Mode = in) /* Flawfinder: ignore */
- {
- std::ifstream::open(_Filename.c_str(), _Mode);
- }
+ llstdio_filebuf _M_filebuf;
};
-class LL_COMMON_API llofstream : public std::ofstream
+/**
+ * @brief Controlling output for files.
+ *
+ * This class supports writing to named files, using the inherited
+ * functions from std::basic_ostream. To control the associated
+ * sequence, an instance of std::basic_filebuf (or a platform-specific derivative)
+ * which allows construction using a pre-exisintg file stream buffer.
+ * We refer to this std::basic_filebuf (or derivative) as @c sb.
+*/
+class LL_COMMON_API llofstream : public std::ostream
{
public:
- llofstream() : std::ofstream()
- {
- }
+ // Constructors:
+ /**
+ * @brief Default constructor.
+ *
+ * Initializes @c sb using its default constructor, and passes
+ * @c &sb to the base class initializer. Does not open any files
+ * (you haven't given it a filename to open).
+ */
+ llofstream();
+
+ /**
+ * @brief Create an output file stream.
+ * @param Filename String specifying the filename.
+ * @param Mode Open file in specified mode (see std::ios_base).
+ *
+ * @c ios_base::out|ios_base::trunc is automatically included in
+ * @a mode.
+ */
+ explicit llofstream(const std::string& _Filename,
+ ios_base::openmode _Mode = ios_base::out|ios_base::trunc);
+ explicit llofstream(const char* _Filename,
+ ios_base::openmode _Mode = ios_base::out|ios_base::trunc);
+
+ /**
+ * @brief Create a stream using an open c file stream.
+ * @param File An open @c FILE*.
+ @param Mode Same meaning as in a standard filebuf.
+ @param Size Optimal or preferred size of internal buffer, in chars.
+ Defaults to system's @c BUFSIZ.
+ */
+ explicit llofstream(_Filet *_File,
+ ios_base::openmode _Mode = ios_base::out,
+ //size_t _Size = static_cast<size_t>(BUFSIZ));
+ size_t _Size = static_cast<size_t>(1));
+
+ /**
+ * @brief Create a stream using an open file descriptor.
+ * @param fd An open file descriptor.
+ @param Mode Same meaning as in a standard filebuf.
+ @param Size Optimal or preferred size of internal buffer, in chars.
+ Defaults to system's @c BUFSIZ.
+ */
+#if !LL_WINDOWS
+ explicit llofstream(int __fd,
+ ios_base::openmode _Mode = ios_base::out,
+ //size_t _Size = static_cast<size_t>(BUFSIZ));
+ size_t _Size = static_cast<size_t>(1));
+#endif
- explicit llofstream(const std::string& _Filename, std::_Ios_Openmode _Mode = out)
- : std::ofstream(_Filename.c_str(), _Mode)
- {
- }
+ /**
+ * @brief The destructor does nothing.
+ *
+ * The file is closed by the filebuf object, not the formatting
+ * stream.
+ */
+ virtual ~llofstream() {}
+
+ // Members:
+ /**
+ * @brief Accessing the underlying buffer.
+ * @return The current basic_filebuf buffer.
+ *
+ * This hides both signatures of std::basic_ios::rdbuf().
+ */
+ llstdio_filebuf* rdbuf() const
+ { return const_cast<llstdio_filebuf*>(&_M_filebuf); }
+
+ /**
+ * @brief Wrapper to test for an open file.
+ * @return @c rdbuf()->is_open()
+ */
+ bool is_open() const;
- void open(const std::string& _Filename, std::_Ios_Openmode _Mode = out) /* Flawfinder: ignore */
- {
- std::ofstream::open(_Filename.c_str(), _Mode);
- }
+ /**
+ * @brief Opens an external file.
+ * @param Filename The name of the file.
+ * @param Node The open mode flags.
+ *
+ * Calls @c llstdio_filebuf::open(s,mode|out). If that function
+ * fails, @c failbit is set in the stream's error state.
+ */
+ void open(const std::string& _Filename,
+ ios_base::openmode _Mode = ios_base::out|ios_base::trunc)
+ { open(_Filename.c_str(), _Mode); }
+ void open(const char* _Filename,
+ ios_base::openmode _Mode = ios_base::out|ios_base::trunc);
+
+ /**
+ * @brief Close the file.
+ *
+ * Calls @c llstdio_filebuf::close(). If that function
+ * fails, @c failbit is set in the stream's error state.
+ */
+ void close();
+private:
+ llstdio_filebuf _M_filebuf;
};
-#endif
/**
* @breif filesize helpers.
diff --git a/indra/llcommon/llfoldertype.h b/indra/llcommon/llfoldertype.h
index a0c847914f..a0c847914f 100644..100755
--- a/indra/llcommon/llfoldertype.h
+++ b/indra/llcommon/llfoldertype.h
diff --git a/indra/llcommon/llhandle.h b/indra/llcommon/llhandle.h
index 6af5e198d6..401e4d759a 100644
--- a/indra/llcommon/llhandle.h
+++ b/indra/llcommon/llhandle.h
@@ -194,13 +194,6 @@ public:
return mHandle;
}
-protected:
- typedef LLHandle<T> handle_type_t;
- LLHandleProvider()
- {
- // provided here to enforce T deriving from LLHandleProvider<T>
- }
-
template <typename U>
LLHandle<U> getDerivedHandle(typename boost::enable_if< typename boost::is_convertible<U*, T*> >::type* dummy = 0) const
{
@@ -209,6 +202,12 @@ protected:
return downcast_handle;
}
+protected:
+ typedef LLHandle<T> handle_type_t;
+ LLHandleProvider()
+ {
+ // provided here to enforce T deriving from LLHandleProvider<T>
+ }
private:
mutable LLRootHandle<T> mHandle;
diff --git a/indra/llcommon/llinitparam.cpp b/indra/llcommon/llinitparam.cpp
index db72aa19b9..89c831d296 100644
--- a/indra/llcommon/llinitparam.cpp
+++ b/indra/llcommon/llinitparam.cpp
@@ -40,7 +40,9 @@ namespace LLInitParam
{
const U8* my_addr = reinterpret_cast<const U8*>(this);
const U8* block_addr = reinterpret_cast<const U8*>(enclosing_block);
- mEnclosingBlockOffset = 0x7FFFffff & (U32)(my_addr - block_addr);
+ U32 enclosing_block_offset = 0x7FFFffff & (U32)(my_addr - block_addr);
+ mEnclosingBlockOffsetLow = enclosing_block_offset & 0x0000ffff;
+ mEnclosingBlockOffsetHigh = (enclosing_block_offset & 0x007f0000) >> 16;
}
//
@@ -112,6 +114,35 @@ namespace LLInitParam
std::copy(src_block_data.mAllParams.begin(), src_block_data.mAllParams.end(), std::back_inserter(mAllParams));
}
+ void BlockDescriptor::addParam(const ParamDescriptorPtr in_param, const char* char_name)
+ {
+ // create a copy of the param descriptor in mAllParams
+ // so other data structures can store a pointer to it
+ mAllParams.push_back(in_param);
+ ParamDescriptorPtr param(mAllParams.back());
+
+ std::string name(char_name);
+ if ((size_t)param->mParamHandle > mMaxParamOffset)
+ {
+ llerrs << "Attempted to register param with block defined for parent class, make sure to derive from LLInitParam::Block<YOUR_CLASS, PARAM_BLOCK_BASE_CLASS>" << llendl;
+ }
+
+ if (name.empty())
+ {
+ mUnnamedParams.push_back(param);
+ }
+ else
+ {
+ // don't use insert, since we want to overwrite existing entries
+ mNamedParams[name] = param;
+ }
+
+ if (param->mValidationFunc)
+ {
+ mValidationList.push_back(std::make_pair(param->mParamHandle, param->mValidationFunc));
+ }
+ }
+
BlockDescriptor::BlockDescriptor()
: mMaxParamOffset(0),
mInitializationState(UNINITIALIZED),
@@ -150,7 +181,8 @@ namespace LLInitParam
bool BaseBlock::submitValue(Parser::name_stack_t& name_stack, Parser& p, bool silent)
{
- if (!deserializeBlock(p, std::make_pair(name_stack.begin(), name_stack.end()), true))
+ Parser::name_stack_range_t range = std::make_pair(name_stack.begin(), name_stack.end());
+ if (!deserializeBlock(p, range, true))
{
if (!silent)
{
@@ -196,12 +228,7 @@ namespace LLInitParam
if (serialize_func)
{
const Param* diff_param = diff_block ? diff_block->getParamFromHandle(param_handle) : NULL;
- // each param descriptor remembers its serial number
- // so we can inspect the same param under different names
- // and see that it has the same number
- name_stack.push_back(std::make_pair("", true));
serialize_func(*param, parser, name_stack, diff_param);
- name_stack.pop_back();
}
}
@@ -295,7 +322,7 @@ namespace LLInitParam
return true;
}
- bool BaseBlock::deserializeBlock(Parser& p, Parser::name_stack_range_t name_stack_range, bool ignored)
+ bool BaseBlock::deserializeBlock(Parser& p, Parser::name_stack_range_t& name_stack_range, bool ignored)
{
BlockDescriptor& block_data = mostDerivedBlockDescriptor();
bool names_left = name_stack_range.first != name_stack_range.second;
@@ -308,15 +335,12 @@ namespace LLInitParam
{
const std::string& top_name = name_stack_range.first->first;
- ParamDescriptor::deserialize_func_t deserialize_func = NULL;
- Param* paramp = NULL;
-
BlockDescriptor::param_map_t::iterator found_it = block_data.mNamedParams.find(top_name);
if (found_it != block_data.mNamedParams.end())
{
// find pointer to member parameter from offset table
- paramp = getParamFromHandle(found_it->second->mParamHandle);
- deserialize_func = found_it->second->mDeserializeFunc;
+ Param* paramp = getParamFromHandle(found_it->second->mParamHandle);
+ ParamDescriptor::deserialize_func_t deserialize_func = found_it->second->mDeserializeFunc;
Parser::name_stack_range_t new_name_stack(name_stack_range.first, name_stack_range.second);
++new_name_stack.first;
@@ -358,36 +382,6 @@ namespace LLInitParam
return false;
}
- //static
- void BaseBlock::addParam(BlockDescriptor& block_data, const ParamDescriptorPtr in_param, const char* char_name)
- {
- // create a copy of the param descriptor in mAllParams
- // so other data structures can store a pointer to it
- block_data.mAllParams.push_back(in_param);
- ParamDescriptorPtr param(block_data.mAllParams.back());
-
- std::string name(char_name);
- if ((size_t)param->mParamHandle > block_data.mMaxParamOffset)
- {
- llerrs << "Attempted to register param with block defined for parent class, make sure to derive from LLInitParam::Block<YOUR_CLASS, PARAM_BLOCK_BASE_CLASS>" << llendl;
- }
-
- if (name.empty())
- {
- block_data.mUnnamedParams.push_back(param);
- }
- else
- {
- // don't use insert, since we want to overwrite existing entries
- block_data.mNamedParams[name] = param;
- }
-
- if (param->mValidationFunc)
- {
- block_data.mValidationList.push_back(std::make_pair(param->mParamHandle, param->mValidationFunc));
- }
- }
-
void BaseBlock::addSynonym(Param& param, const std::string& synonym)
{
BlockDescriptor& block_data = mostDerivedBlockDescriptor();
@@ -460,7 +454,7 @@ namespace LLInitParam
if (merge_func)
{
Param* paramp = getParamFromHandle((*it)->mParamHandle);
- llassert(paramp->mEnclosingBlockOffset == (*it)->mParamHandle);
+ llassert(paramp->getEnclosingBlockOffset() == (*it)->mParamHandle);
some_param_changed |= merge_func(*paramp, *other_paramp, overwrite);
}
}
diff --git a/indra/llcommon/llinitparam.h b/indra/llcommon/llinitparam.h
index 0dd6030fa2..ae836645b9 100644
--- a/indra/llcommon/llinitparam.h
+++ b/indra/llcommon/llinitparam.h
@@ -38,6 +38,71 @@
#include "llerror.h"
#include "llstl.h"
+namespace LLTypeTags
+{
+ template <typename INNER_TYPE, int _SORT_ORDER>
+ struct TypeTagBase
+ {
+ typedef void is_tag_t;
+ typedef INNER_TYPE inner_t;
+ static const int SORT_ORDER=_SORT_ORDER;
+ };
+
+ template <int VAL1, int VAL2>
+ struct GreaterThan
+ {
+ static const bool value = VAL1 > VAL2;
+ };
+
+ template<typename ITEM, typename REST, bool NEEDS_SWAP = GreaterThan<ITEM::SORT_ORDER, REST::SORT_ORDER>::value >
+ struct Swap
+ {
+ typedef typename ITEM::template Cons<REST>::value_t value_t;
+ };
+
+ template<typename ITEM, typename REST>
+ struct Swap<ITEM, REST, true>
+ {
+ typedef typename REST::template Cons<Swap<ITEM, typename REST::inner_t>::value_t>::value_t value_t;
+ };
+
+ template<typename T, typename SORTABLE = void>
+ struct IsSortable
+ {
+ static const bool value = false;
+ };
+
+ template<typename T>
+ struct IsSortable<T, typename T::is_tag_t>
+ {
+ static const bool value = true;
+ };
+
+ template<typename ITEM, typename REST, bool IS_REST_SORTABLE = IsSortable<REST>::value>
+ struct InsertInto
+ {
+ typedef typename ITEM::template Cons<REST>::value_t value_t;
+ };
+
+ template<typename ITEM, typename REST>
+ struct InsertInto <ITEM, REST, true>
+ {
+ typedef typename Swap<ITEM, REST>::value_t value_t;
+ };
+
+ template<typename T, bool SORTABLE = IsSortable<T>::value>
+ struct Sorted
+ {
+ typedef T value_t;
+ };
+
+ template<typename T>
+ struct Sorted <T, true>
+ {
+ typedef typename InsertInto<T, typename Sorted<typename T::inner_t>::value_t>::value_t value_t;
+ };
+}
+
namespace LLInitParam
{
// used to indicate no matching value to a given name when parsing
@@ -45,6 +110,8 @@ namespace LLInitParam
template<typename T> const T& defaultValue() { static T value; return value; }
+ // wraps comparison operator between any 2 values of the same type
+ // specialize to handle cases where equality isn't defined well, or at all
template <typename T, bool IS_BOOST_FUNCTION = boost::is_convertible<T, boost::function_base>::value >
struct ParamCompare
{
@@ -79,24 +146,123 @@ namespace LLInitParam
// helper functions and classes
typedef ptrdiff_t param_handle_t;
+ struct IS_A_BLOCK {};
+ struct NOT_BLOCK {};
+
+ // these templates allow us to distinguish between template parameters
+ // that derive from BaseBlock and those that don't
+ template<typename T, typename BLOCK_IDENTIFIER = void>
+ struct IsBlock
+ {
+ typedef NOT_BLOCK value_t;
+ };
+
+ template<typename T>
+ struct IsBlock<T, typename T::baseblock_base_class_t>
+ {
+ typedef IS_A_BLOCK value_t;
+ };
+
+ // ParamValue class directly manages the wrapped value
+ // by holding on to a copy (scalar params)
+ // or deriving from it (blocks)
+ // has specializations for custom value behavior
+ // and "tag" values like Lazy and Atomic
+ template<typename T, typename VALUE_IS_BLOCK = typename IsBlock<T>::value_t>
+ class ParamValue
+ {
+ typedef ParamValue<T, VALUE_IS_BLOCK> self_t;
+
+ public:
+ typedef T default_value_t;
+ typedef T value_t;
+
+ ParamValue(): mValue() {}
+ ParamValue(const default_value_t& other) : mValue(other) {}
+
+ void setValue(const value_t& val)
+ {
+ mValue = val;
+ }
+
+ const value_t& getValue() const
+ {
+ return mValue;
+ }
+
+ T& getValue()
+ {
+ return mValue;
+ }
+
+ protected:
+ T mValue;
+ };
+
+ template<typename T>
+ class ParamValue<T, IS_A_BLOCK>
+ : public T
+ {
+ typedef ParamValue<T, IS_A_BLOCK> self_t;
+ public:
+ typedef T default_value_t;
+ typedef T value_t;
+
+ ParamValue()
+ : T(),
+ mValidated(false)
+ {}
+
+ ParamValue(const default_value_t& other)
+ : T(other),
+ mValidated(false)
+ {}
+
+ void setValue(const value_t& val)
+ {
+ *this = val;
+ }
+
+ const value_t& getValue() const
+ {
+ return *this;
+ }
+
+ T& getValue()
+ {
+ return *this;
+ }
+
+ protected:
+ mutable bool mValidated; // lazy validation flag
+ };
+
// empty default implementation of key cache
// leverages empty base class optimization
template <typename T>
class TypeValues
+ : public ParamValue<typename LLTypeTags::Sorted<T>::value_t>
{
private:
struct Inaccessable{};
public:
typedef std::map<std::string, T> value_name_map_t;
typedef Inaccessable name_t;
+ typedef TypeValues<T> type_value_t;
+ typedef ParamValue<typename LLTypeTags::Sorted<T>::value_t> param_value_t;
+ typedef typename param_value_t::value_t value_t;
+
+ TypeValues(const typename param_value_t::value_t& val)
+ : param_value_t(val)
+ {}
void setValueName(const std::string& key) {}
std::string getValueName() const { return ""; }
- std::string calcValueName(const T& value) const { return ""; }
+ std::string calcValueName(const value_t& value) const { return ""; }
void clearValueName() const {}
- static bool getValueFromName(const std::string& name, T& value)
+ static bool getValueFromName(const std::string& name, value_t& value)
{
return false;
}
@@ -111,15 +277,39 @@ namespace LLInitParam
return NULL;
}
+ void assignNamedValue(const Inaccessable& name)
+ {}
+
+ operator const value_t&() const
+ {
+ return param_value_t::getValue();
+ }
+
+ const value_t& operator()() const
+ {
+ return param_value_t::getValue();
+ }
+
static value_name_map_t* getValueNames() {return NULL;}
};
- template <typename T, typename DERIVED_TYPE = TypeValues<T> >
+ // helper class to implement name value lookups
+ // and caching of last used name
+ template <typename T, typename DERIVED_TYPE = TypeValues<T>, bool IS_SPECIALIZED = true >
class TypeValuesHelper
+ : public ParamValue<typename LLTypeTags::Sorted<T>::value_t>
{
+ typedef TypeValuesHelper<T, DERIVED_TYPE, IS_SPECIALIZED> self_t;
public:
typedef typename std::map<std::string, T> value_name_map_t;
typedef std::string name_t;
+ typedef self_t type_value_t;
+ typedef ParamValue<typename LLTypeTags::Sorted<T>::value_t> param_value_t;
+ typedef typename param_value_t::value_t value_t;
+
+ TypeValuesHelper(const typename param_value_t::value_t& val)
+ : param_value_t(val)
+ {}
//TODO: cache key by index to save on param block size
void setValueName(const std::string& value_name)
@@ -132,7 +322,7 @@ namespace LLInitParam
return mValueName;
}
- std::string calcValueName(const T& value) const
+ std::string calcValueName(const value_t& value) const
{
value_name_map_t* map = getValueNames();
for (typename value_name_map_t::iterator it = map->begin(), end_it = map->end();
@@ -153,7 +343,7 @@ namespace LLInitParam
mValueName.clear();
}
- static bool getValueFromName(const std::string& name, T& value)
+ static bool getValueFromName(const std::string& name, value_t& value)
{
value_name_map_t* map = getValueNames();
typename value_name_map_t::iterator found_it = map->find(name);
@@ -195,18 +385,90 @@ namespace LLInitParam
return &sValues;
}
- static void declare(const std::string& name, const T& value)
+ static void declare(const std::string& name, const value_t& value)
{
(*getValueNames())[name] = value;
}
+ void operator ()(const std::string& name)
+ {
+ *this = name;
+ }
+
+ void assignNamedValue(const std::string& name)
+ {
+ if (getValueFromName(name, param_value_t::getValue()))
+ {
+ setValueName(name);
+ }
+ }
+
+ operator const value_t&() const
+ {
+ return param_value_t::getValue();
+ }
+
+ const value_t& operator()() const
+ {
+ return param_value_t::getValue();
+ }
+
protected:
- static void getName(const std::string& name, const T& value)
+ static void getName(const std::string& name, const value_t& value)
{}
mutable std::string mValueName;
};
+ // string types can support custom named values, but need
+ // to disambiguate in code between a string that is a named value
+ // and a string that is a name
+ template <typename DERIVED_TYPE>
+ class TypeValuesHelper<std::string, DERIVED_TYPE, true>
+ : public TypeValuesHelper<std::string, DERIVED_TYPE, false>
+ {
+ public:
+ typedef TypeValuesHelper<std::string, DERIVED_TYPE, true> self_t;
+ typedef TypeValuesHelper<std::string, DERIVED_TYPE, false> base_t;
+ typedef std::string value_t;
+ typedef std::string name_t;
+ typedef self_t type_value_t;
+
+ TypeValuesHelper(const std::string& val)
+ : TypeValuesHelper(val)
+ {}
+
+ void operator ()(const std::string& name)
+ {
+ *this = name;
+ }
+
+ self_t& operator =(const std::string& name)
+ {
+ if (base_t::getValueFromName(name, ParamValue<std::string>::getValue()))
+ {
+ base_t::setValueName(name);
+ }
+ else
+ {
+ ParamValue<std::string>::setValue(name);
+ }
+ return *this;
+ }
+
+ operator const value_t&() const
+ {
+ return ParamValue<std::string>::getValue();
+ }
+
+ const value_t& operator()() const
+ {
+ return ParamValue<std::string>::getValue();
+ }
+
+ };
+
+ // parser base class with mechanisms for registering readers/writers/inspectors of different types
class LL_COMMON_API Parser
{
LOG_CLASS(Parser);
@@ -223,82 +485,58 @@ namespace LLInitParam
typedef std::map<const std::type_info*, parser_write_func_t> parser_write_func_map_t;
typedef std::map<const std::type_info*, parser_inspect_func_t> parser_inspect_func_map_t;
- private:
- template<typename T, bool is_enum = boost::is_enum<T>::value>
- struct ReaderWriter
- {
- static bool read(T& param, Parser* parser)
+ public:
+
+ Parser(parser_read_func_map_t& read_map, parser_write_func_map_t& write_map, parser_inspect_func_map_t& inspect_map)
+ : mParseSilently(false),
+ mParserReadFuncs(&read_map),
+ mParserWriteFuncs(&write_map),
+ mParserInspectFuncs(&inspect_map)
+ {}
+
+ virtual ~Parser();
+
+ template <typename T> bool readValue(T& param, typename boost::disable_if<boost::is_enum<T> >::type* dummy = 0)
{
- parser_read_func_map_t::iterator found_it = parser->mParserReadFuncs->find(&typeid(T));
- if (found_it != parser->mParserReadFuncs->end())
+ parser_read_func_map_t::iterator found_it = mParserReadFuncs->find(&typeid(T));
+ if (found_it != mParserReadFuncs->end())
{
- return found_it->second(*parser, (void*)&param);
+ return found_it->second(*this, (void*)&param);
}
+
return false;
}
- static bool write(const T& param, Parser* parser, name_stack_t& name_stack)
+ template <typename T> bool readValue(T& param, typename boost::enable_if<boost::is_enum<T> >::type* dummy = 0)
{
- parser_write_func_map_t::iterator found_it = parser->mParserWriteFuncs->find(&typeid(T));
- if (found_it != parser->mParserWriteFuncs->end())
+ parser_read_func_map_t::iterator found_it = mParserReadFuncs->find(&typeid(T));
+ if (found_it != mParserReadFuncs->end())
{
- return found_it->second(*parser, (const void*)&param, name_stack);
+ return found_it->second(*this, (void*)&param);
}
- return false;
- }
- };
-
- // read enums as ints
- template<typename T>
- struct ReaderWriter<T, true>
+ else
{
- static bool read(T& param, Parser* parser)
- {
- // read all enums as ints
- parser_read_func_map_t::iterator found_it = parser->mParserReadFuncs->find(&typeid(S32));
- if (found_it != parser->mParserReadFuncs->end())
+ found_it = mParserReadFuncs->find(&typeid(S32));
+ if (found_it != mParserReadFuncs->end())
{
- S32 value;
- if (found_it->second(*parser, (void*)&value))
- {
- param = (T)value;
- return true;
+ S32 int_value;
+ bool parsed = found_it->second(*this, (void*)&int_value);
+ param = (T)int_value;
+ return parsed;
}
}
return false;
}
- static bool write(const T& param, Parser* parser, name_stack_t& name_stack)
+ template <typename T> bool writeValue(const T& param, name_stack_t& name_stack)
{
- parser_write_func_map_t::iterator found_it = parser->mParserWriteFuncs->find(&typeid(S32));
- if (found_it != parser->mParserWriteFuncs->end())
+ parser_write_func_map_t::iterator found_it = mParserWriteFuncs->find(&typeid(T));
+ if (found_it != mParserWriteFuncs->end())
{
- return found_it->second(*parser, (const void*)&param, name_stack);
+ return found_it->second(*this, (const void*)&param, name_stack);
}
return false;
}
- };
-
- public:
-
- Parser(parser_read_func_map_t& read_map, parser_write_func_map_t& write_map, parser_inspect_func_map_t& inspect_map)
- : mParseSilently(false),
- mParserReadFuncs(&read_map),
- mParserWriteFuncs(&write_map),
- mParserInspectFuncs(&inspect_map)
- {}
-
- virtual ~Parser();
-
- template <typename T> bool readValue(T& param)
- {
- return ReaderWriter<T>::read(param, this);
- }
-
- template <typename T> bool writeValue(const T& param, name_stack_t& name_stack)
- {
- return ReaderWriter<T>::write(param, this, name_stack);
- }
// dispatch inspection to registered inspection functions, for each parameter in a param block
template <typename T> bool inspectValue(name_stack_t& name_stack, S32 min_count, S32 max_count, const possible_values_t* possible_values)
@@ -350,7 +588,7 @@ namespace LLInitParam
};
typedef bool(*merge_func_t)(Param&, const Param&, bool);
- typedef bool(*deserialize_func_t)(Param&, Parser&, const Parser::name_stack_range_t&, bool);
+ typedef bool(*deserialize_func_t)(Param&, Parser&, Parser::name_stack_range_t&, bool);
typedef void(*serialize_func_t)(const Param&, Parser&, Parser::name_stack_t&, const Param* diff_param);
typedef void(*inspect_func_t)(const Param&, Parser&, Parser::name_stack_t&, S32 min_count, S32 max_count);
typedef bool(*validation_func_t)(const Param*);
@@ -395,6 +633,7 @@ namespace LLInitParam
} EInitializationState;
void aggregateBlockData(BlockDescriptor& src_block_data);
+ void addParam(ParamDescriptorPtr param, const char* name);
typedef boost::unordered_map<const std::string, ParamDescriptorPtr> param_map_t;
typedef std::vector<ParamDescriptorPtr> param_list_t;
@@ -410,48 +649,58 @@ namespace LLInitParam
class BaseBlock* mCurrentBlockPtr; // pointer to block currently being constructed
};
- class LL_COMMON_API BaseBlock
- {
- public:
//TODO: implement in terms of owned_ptr
template<typename T>
- class Lazy
+ class LazyValue
{
public:
- Lazy()
+ LazyValue()
: mPtr(NULL)
{}
- ~Lazy()
+ ~LazyValue()
{
delete mPtr;
}
- Lazy(const Lazy& other)
+ LazyValue(const T& value)
{
- if (other.mPtr)
+ mPtr = new T(value);
+ }
+
+ LazyValue(const LazyValue& other)
+ : mPtr(NULL)
{
- mPtr = new T(*other.mPtr);
+ *this = other;
}
- else
+
+ LazyValue& operator = (const LazyValue& other)
{
+ if (!other.mPtr)
+ {
+ delete mPtr;
mPtr = NULL;
}
- }
-
- Lazy<T>& operator = (const Lazy<T>& other)
+ else
{
- if (other.mPtr)
+ if (!mPtr)
{
mPtr = new T(*other.mPtr);
}
else
{
- mPtr = NULL;
+ *mPtr = *(other.mPtr);
+ }
}
return *this;
}
+ bool operator==(const LazyValue& other) const
+ {
+ if (empty() || other.empty()) return false;
+ return *mPtr == *other.mPtr;
+ }
+
bool empty() const
{
return mPtr == NULL;
@@ -459,18 +708,29 @@ namespace LLInitParam
void set(const T& other)
{
- delete mPtr;
+ if (!mPtr)
+ {
mPtr = new T(other);
}
+ else
+ {
+ *mPtr = other;
+ }
+ }
const T& get() const
{
- return ensureInstance();
+ return *ensureInstance();
}
T& get()
{
- return ensureInstance();
+ return *ensureInstance();
+ }
+
+ operator const T&() const
+ {
+ return get();
}
private:
@@ -485,13 +745,50 @@ namespace LLInitParam
}
private:
- // if you get a compilation error with this, that means you are using a forward declared struct for T
- // unfortunately, the type traits we rely on don't work with forward declared typed
- //static const int dummy = sizeof(T);
mutable T* mPtr;
};
+ // root class of all parameter blocks
+
+ class LL_COMMON_API BaseBlock
+ {
+ public:
+ // lift block tags into baseblock namespace so derived classes do not need to qualify them
+ typedef LLInitParam::IS_A_BLOCK IS_A_BLOCK;
+ typedef LLInitParam::NOT_BLOCK NOT_A_BLOCK;
+
+ template<typename T>
+ struct Sequential : public LLTypeTags::TypeTagBase<T, 2>
+ {
+ template <typename S> struct Cons { typedef Sequential<ParamValue<S> > value_t; };
+ template <typename S> struct Cons<Sequential<S> > { typedef Sequential<S> value_t; };
+ };
+
+ template<typename T>
+ struct Atomic : public LLTypeTags::TypeTagBase<T, 1>
+ {
+ template <typename S> struct Cons { typedef Atomic<ParamValue<S> > value_t; };
+ template <typename S> struct Cons<Atomic<S> > { typedef Atomic<S> value_t; };
+ };
+
+ template<typename T, typename BLOCK_T = typename IsBlock<T>::value_t >
+ struct Lazy : public LLTypeTags::TypeTagBase<T, 0>
+ {
+ template <typename S> struct Cons
+ {
+ typedef Lazy<ParamValue<S, BLOCK_T>, BLOCK_T> value_t;
+ };
+ template <typename S> struct Cons<Lazy<S, IS_A_BLOCK> >
+ {
+ typedef Lazy<S, IS_A_BLOCK> value_t;
+ };
+ template <typename S> struct Cons<Lazy<S, NOT_A_BLOCK> >
+ {
+ typedef Lazy<S, BLOCK_T> value_t;
+ };
+ };
+
// "Multiple" constraint types, put here in root class to avoid ambiguity during use
struct AnyAmount
{
@@ -557,12 +854,12 @@ namespace LLInitParam
// Blocks can override this to do custom tracking of changes
virtual void paramChanged(const Param& changed_param, bool user_provided) {}
- bool deserializeBlock(Parser& p, Parser::name_stack_range_t name_stack_range, bool new_name);
+ bool deserializeBlock(Parser& p, Parser::name_stack_range_t& name_stack_range, bool new_name);
void serializeBlock(Parser& p, Parser::name_stack_t& name_stack, const BaseBlock* diff_block = NULL) const;
bool inspectBlock(Parser& p, Parser::name_stack_t name_stack = Parser::name_stack_t(), S32 min_count = 0, S32 max_count = S32_MAX) const;
- virtual const BlockDescriptor& mostDerivedBlockDescriptor() const { return selfBlockDescriptor(); }
- virtual BlockDescriptor& mostDerivedBlockDescriptor() { return selfBlockDescriptor(); }
+ virtual const BlockDescriptor& mostDerivedBlockDescriptor() const { return getBlockDescriptor(); }
+ virtual BlockDescriptor& mostDerivedBlockDescriptor() { return getBlockDescriptor(); }
// take all provided params from other and apply to self
bool overwriteFrom(const BaseBlock& other)
@@ -576,10 +873,17 @@ namespace LLInitParam
return false;
}
- static void addParam(BlockDescriptor& block_data, ParamDescriptorPtr param, const char* name);
-
ParamDescriptorPtr findParamDescriptor(const Param& param);
+ // take all provided params from other and apply to self
+ bool mergeBlock(BlockDescriptor& block_data, const BaseBlock& other, bool overwrite);
+
+ static BlockDescriptor& getBlockDescriptor()
+ {
+ static BlockDescriptor sBlockDescriptor;
+ return sBlockDescriptor;
+ }
+
protected:
void init(BlockDescriptor& descriptor, BlockDescriptor& base_descriptor, size_t block_size);
@@ -588,25 +892,11 @@ namespace LLInitParam
{
return mergeBlock(block_data, source, overwrite);
}
- // take all provided params from other and apply to self
- bool mergeBlock(BlockDescriptor& block_data, const BaseBlock& other, bool overwrite);
-
- static BlockDescriptor& selfBlockDescriptor()
- {
- static BlockDescriptor sBlockDescriptor;
- return sBlockDescriptor;
- }
private:
const std::string& getParamName(const BlockDescriptor& block_data, const Param* paramp) const;
};
- template<typename T>
- struct ParamCompare<BaseBlock::Lazy<T>, false >
- {
- static bool equals(const BaseBlock::Lazy<T>& a, const BaseBlock::Lazy<T>& b) { return !a.empty() || !b.empty(); }
- };
-
class LL_COMMON_API Param
{
public:
@@ -635,256 +925,68 @@ namespace LLInitParam
// get address of enclosing BLOCK class using stored offset to enclosing BaseBlock class
return *const_cast<BaseBlock*>
(reinterpret_cast<const BaseBlock*>
- (my_addr - (ptrdiff_t)(S32)mEnclosingBlockOffset));
- }
-
- private:
- friend class BaseBlock;
-
- U32 mEnclosingBlockOffset:31;
- U32 mIsProvided:1;
-
- };
-
- // these templates allow us to distinguish between template parameters
- // that derive from BaseBlock and those that don't
- template<typename T, typename Void = void>
- struct IsBlock
- {
- static const bool value = false;
- struct EmptyBase {};
- typedef EmptyBase base_class_t;
- };
-
- template<typename T>
- struct IsBlock<T, typename T::baseblock_base_class_t>
- {
- static const bool value = true;
- typedef BaseBlock base_class_t;
- };
-
- template<typename T>
- struct IsBlock<BaseBlock::Lazy<T>, typename T::baseblock_base_class_t >
- {
- static const bool value = true;
- typedef BaseBlock base_class_t;
- };
-
- template<typename T, typename NAME_VALUE_LOOKUP, bool VALUE_IS_BLOCK = IsBlock<T>::value>
- class ParamValue : public NAME_VALUE_LOOKUP
- {
- public:
- typedef const T& value_assignment_t;
- typedef T value_t;
- typedef ParamValue<T, NAME_VALUE_LOOKUP, VALUE_IS_BLOCK> self_t;
-
- ParamValue(): mValue() {}
- ParamValue(value_assignment_t other) : mValue(other) {}
-
- void setValue(value_assignment_t val)
- {
- mValue = val;
- }
-
- value_assignment_t getValue() const
- {
- return mValue;
- }
-
- T& getValue()
- {
- return mValue;
- }
-
- operator value_assignment_t() const
- {
- return mValue;
- }
-
- value_assignment_t operator()() const
- {
- return mValue;
- }
-
- void operator ()(const typename NAME_VALUE_LOOKUP::name_t& name)
- {
- *this = name;
- }
-
- self_t& operator =(const typename NAME_VALUE_LOOKUP::name_t& name)
- {
- if (NAME_VALUE_LOOKUP::getValueFromName(name, mValue))
- {
- setValueName(name);
- }
-
- return *this;
- }
-
- protected:
- T mValue;
- };
-
- template<typename T, typename NAME_VALUE_LOOKUP>
- class ParamValue<T, NAME_VALUE_LOOKUP, true>
- : public T,
- public NAME_VALUE_LOOKUP
- {
- public:
- typedef const T& value_assignment_t;
- typedef T value_t;
- typedef ParamValue<T, NAME_VALUE_LOOKUP, true> self_t;
-
- ParamValue()
- : T(),
- mValidated(false)
- {}
-
- ParamValue(value_assignment_t other)
- : T(other),
- mValidated(false)
- {}
-
- void setValue(value_assignment_t val)
- {
- *this = val;
- }
-
- value_assignment_t getValue() const
- {
- return *this;
- }
-
- T& getValue()
- {
- return *this;
- }
-
- operator value_assignment_t() const
- {
- return *this;
- }
-
- value_assignment_t operator()() const
- {
- return *this;
- }
-
- void operator ()(const typename NAME_VALUE_LOOKUP::name_t& name)
- {
- *this = name;
- }
-
- self_t& operator =(const typename NAME_VALUE_LOOKUP::name_t& name)
- {
- if (NAME_VALUE_LOOKUP::getValueFromName(name, *this))
- {
- setValueName(name);
- }
-
- return *this;
+ (my_addr - (ptrdiff_t)getEnclosingBlockOffset()));
}
- protected:
- mutable bool mValidated; // lazy validation flag
- };
-
- template<typename NAME_VALUE_LOOKUP>
- class ParamValue<std::string, NAME_VALUE_LOOKUP, false>
- : public NAME_VALUE_LOOKUP
+ U32 getEnclosingBlockOffset() const
{
- public:
- typedef const std::string& value_assignment_t;
- typedef std::string value_t;
- typedef ParamValue<std::string, NAME_VALUE_LOOKUP, false> self_t;
-
- ParamValue(): mValue() {}
- ParamValue(value_assignment_t other) : mValue(other) {}
-
- void setValue(value_assignment_t val)
- {
- if (NAME_VALUE_LOOKUP::getValueFromName(val, mValue))
- {
- NAME_VALUE_LOOKUP::setValueName(val);
- }
- else
- {
- mValue = val;
- }
- }
-
- value_assignment_t getValue() const
- {
- return mValue;
- }
-
- std::string& getValue()
- {
- return mValue;
+ return ((U32)mEnclosingBlockOffsetHigh << 16) | (U32)mEnclosingBlockOffsetLow;
}
- operator value_assignment_t() const
- {
- return mValue;
- }
+ private:
+ friend class BaseBlock;
- value_assignment_t operator()() const
- {
- return mValue;
- }
+ //24 bits for member offset field and 1 bit for provided flag
+ U16 mEnclosingBlockOffsetLow;
+ U8 mEnclosingBlockOffsetHigh:7;
+ U8 mIsProvided:1;
- protected:
- std::string mValue;
};
-
template<typename T, typename NAME_VALUE_LOOKUP = TypeValues<T> >
struct ParamIterator
{
- typedef typename std::vector<ParamValue<T, NAME_VALUE_LOOKUP> >::const_iterator const_iterator;
- typedef typename std::vector<ParamValue<T, NAME_VALUE_LOOKUP> >::iterator iterator;
+ typedef typename std::vector<typename NAME_VALUE_LOOKUP::type_value_t >::const_iterator const_iterator;
+ typedef typename std::vector<typename NAME_VALUE_LOOKUP::type_value_t >::iterator iterator;
};
- // specialize for custom parsing/decomposition of specific classes
- // e.g. TypedParam<LLRect> has left, top, right, bottom, etc...
+ // wrapper for parameter with a known type
+ // specialized to handle 4 cases:
+ // simple "scalar" value
+ // parameter that is itself a block
+ // multiple scalar values, stored in a vector
+ // multiple blocks, stored in a vector
template<typename T,
typename NAME_VALUE_LOOKUP = TypeValues<T>,
bool HAS_MULTIPLE_VALUES = false,
- bool VALUE_IS_BLOCK = IsBlock<ParamValue<T, NAME_VALUE_LOOKUP> >::value>
+ typename VALUE_IS_BLOCK = typename IsBlock<ParamValue<typename LLTypeTags::Sorted<T>::value_t> >::value_t>
class TypedParam
: public Param,
- public ParamValue<T, NAME_VALUE_LOOKUP>
+ public NAME_VALUE_LOOKUP::type_value_t
{
+ protected:
+ typedef TypedParam<T, NAME_VALUE_LOOKUP, HAS_MULTIPLE_VALUES, VALUE_IS_BLOCK> self_t;
+ typedef ParamValue<typename LLTypeTags::Sorted<T>::value_t> param_value_t;
+ typedef typename param_value_t::default_value_t default_value_t;
+ typedef typename NAME_VALUE_LOOKUP::type_value_t named_value_t;
public:
- typedef TypedParam<T, NAME_VALUE_LOOKUP, HAS_MULTIPLE_VALUES, VALUE_IS_BLOCK> self_t;
- typedef ParamValue<T, NAME_VALUE_LOOKUP> param_value_t;
- typedef typename param_value_t::value_assignment_t value_assignment_t;
- typedef NAME_VALUE_LOOKUP name_value_lookup_t;
+ typedef typename param_value_t::value_t value_t;
- using param_value_t::operator();
+ using named_value_t::operator();
- TypedParam(BlockDescriptor& block_descriptor, const char* name, value_assignment_t value, ParamDescriptor::validation_func_t validate_func, S32 min_count, S32 max_count)
- : Param(block_descriptor.mCurrentBlockPtr)
+ TypedParam(BlockDescriptor& block_descriptor, const char* name, const default_value_t& value, ParamDescriptor::validation_func_t validate_func, S32 min_count, S32 max_count)
+ : Param(block_descriptor.mCurrentBlockPtr),
+ named_value_t(value)
{
if (LL_UNLIKELY(block_descriptor.mInitializationState == BlockDescriptor::INITIALIZING))
{
- ParamDescriptorPtr param_descriptor = ParamDescriptorPtr(new ParamDescriptor(
- block_descriptor.mCurrentBlockPtr->getHandleFromParam(this),
- &mergeWith,
- &deserializeParam,
- &serializeParam,
- validate_func,
- &inspectParam,
- min_count, max_count));
- BaseBlock::addParam(block_descriptor, param_descriptor, name);
+ init(block_descriptor, validate_func, min_count, max_count, name);
}
-
- setValue(value);
}
bool isProvided() const { return Param::anyProvided(); }
- static bool deserializeParam(Param& param, Parser& parser, const Parser::name_stack_range_t& name_stack_range, bool new_name)
+ static bool deserializeParam(Param& param, Parser& parser, Parser::name_stack_range_t& name_stack_range, bool new_name)
{
self_t& typed_param = static_cast<self_t&>(param);
// no further names in stack, attempt to parse value now
@@ -893,9 +995,9 @@ namespace LLInitParam
std::string name;
// try to parse a known named value
- if(name_value_lookup_t::valueNamesExist()
+ if(named_value_t::valueNamesExist()
&& parser.readValue(name)
- && name_value_lookup_t::getValueFromName(name, typed_param.getValue()))
+ && named_value_t::getValueFromName(name, typed_param.getValue()))
{
typed_param.setValueName(name);
typed_param.setProvided();
@@ -939,7 +1041,9 @@ namespace LLInitParam
if (!parser.writeValue(typed_param.getValue(), name_stack))
{
std::string calculated_key = typed_param.calcValueName(typed_param.getValue());
- if (!diff_param || !ParamCompare<std::string>::equals(static_cast<const self_t*>(diff_param)->getValueName(), calculated_key))
+ if (calculated_key.size()
+ && (!diff_param
+ || !ParamCompare<std::string>::equals(static_cast<const self_t*>(diff_param)->getValueName(), calculated_key)))
{
parser.writeValue(calculated_key, name_stack);
}
@@ -952,22 +1056,23 @@ namespace LLInitParam
// tell parser about our actual type
parser.inspectValue<T>(name_stack, min_count, max_count, NULL);
// then tell it about string-based alternatives ("red", "blue", etc. for LLColor4)
- if (name_value_lookup_t::getPossibleValues())
+ if (named_value_t::getPossibleValues())
{
- parser.inspectValue<std::string>(name_stack, min_count, max_count, name_value_lookup_t::getPossibleValues());
+ parser.inspectValue<std::string>(name_stack, min_count, max_count, named_value_t::getPossibleValues());
}
}
- void set(value_assignment_t val, bool flag_as_provided = true)
+ void set(const value_t& val, bool flag_as_provided = true)
{
- param_value_t::clearValueName();
+ named_value_t::clearValueName();
setValue(val);
setProvided(flag_as_provided);
}
- self_t& operator =(const typename NAME_VALUE_LOOKUP::name_t& name)
+ self_t& operator =(const typename named_value_t::name_t& name)
{
- return static_cast<self_t&>(param_value_t::operator =(name));
+ named_value_t::assignNamedValue(name);
+ return *this;
}
protected:
@@ -992,41 +1097,47 @@ namespace LLInitParam
}
return false;
}
+ private:
+ void init( BlockDescriptor &block_descriptor, ParamDescriptor::validation_func_t validate_func, S32 min_count, S32 max_count, const char* name )
+ {
+ ParamDescriptorPtr param_descriptor = ParamDescriptorPtr(new ParamDescriptor(
+ block_descriptor.mCurrentBlockPtr->getHandleFromParam(this),
+ &mergeWith,
+ &deserializeParam,
+ &serializeParam,
+ validate_func,
+ &inspectParam,
+ min_count, max_count));
+ block_descriptor.addParam(param_descriptor, name);
+ }
};
// parameter that is a block
template <typename T, typename NAME_VALUE_LOOKUP>
- class TypedParam<T, NAME_VALUE_LOOKUP, false, true>
+ class TypedParam<T, NAME_VALUE_LOOKUP, false, IS_A_BLOCK>
: public Param,
- public ParamValue<T, NAME_VALUE_LOOKUP>
+ public NAME_VALUE_LOOKUP::type_value_t
{
+ protected:
+ typedef ParamValue<typename LLTypeTags::Sorted<T>::value_t> param_value_t;
+ typedef typename param_value_t::default_value_t default_value_t;
+ typedef TypedParam<T, NAME_VALUE_LOOKUP, false, IS_A_BLOCK> self_t;
+ typedef typename NAME_VALUE_LOOKUP::type_value_t named_value_t;
public:
- typedef ParamValue<T, NAME_VALUE_LOOKUP> param_value_t;
- typedef typename param_value_t::value_assignment_t value_assignment_t;
- typedef TypedParam<T, NAME_VALUE_LOOKUP, false, true> self_t;
- typedef NAME_VALUE_LOOKUP name_value_lookup_t;
-
- using param_value_t::operator();
+ using named_value_t::operator();
+ typedef typename param_value_t::value_t value_t;
- TypedParam(BlockDescriptor& block_descriptor, const char* name, value_assignment_t value, ParamDescriptor::validation_func_t validate_func, S32 min_count, S32 max_count)
+ TypedParam(BlockDescriptor& block_descriptor, const char* name, const default_value_t& value, ParamDescriptor::validation_func_t validate_func, S32 min_count, S32 max_count)
: Param(block_descriptor.mCurrentBlockPtr),
- param_value_t(value)
+ named_value_t(value)
{
if (LL_UNLIKELY(block_descriptor.mInitializationState == BlockDescriptor::INITIALIZING))
{
- ParamDescriptorPtr param_descriptor = ParamDescriptorPtr(new ParamDescriptor(
- block_descriptor.mCurrentBlockPtr->getHandleFromParam(this),
- &mergeWith,
- &deserializeParam,
- &serializeParam,
- validate_func,
- &inspectParam,
- min_count, max_count));
- BaseBlock::addParam(block_descriptor, param_descriptor, name);
+ init(block_descriptor, validate_func, min_count, max_count, name);
}
}
- static bool deserializeParam(Param& param, Parser& parser, const Parser::name_stack_range_t& name_stack_range, bool new_name)
+ static bool deserializeParam(Param& param, Parser& parser, Parser::name_stack_range_t& name_stack_range, bool new_name)
{
self_t& typed_param = static_cast<self_t&>(param);
@@ -1034,9 +1145,9 @@ namespace LLInitParam
{ // try to parse a known named value
std::string name;
- if(name_value_lookup_t::valueNamesExist()
+ if(named_value_t::valueNamesExist()
&& parser.readValue(name)
- && name_value_lookup_t::getValueFromName(name, typed_param.getValue()))
+ && named_value_t::getValueFromName(name, typed_param.getValue()))
{
typed_param.setValueName(name);
typed_param.setProvided();
@@ -1068,9 +1179,9 @@ namespace LLInitParam
std::string key = typed_param.getValueName();
if (!key.empty())
{
- if (!parser.writeValue(key, name_stack))
+ if (!diff_param || !ParamCompare<std::string>::equals(static_cast<const self_t*>(diff_param)->getValueName(), key))
{
- return;
+ parser.writeValue(key, name_stack);
}
}
else
@@ -1081,8 +1192,16 @@ namespace LLInitParam
static void inspectParam(const Param& param, Parser& parser, Parser::name_stack_t& name_stack, S32 min_count, S32 max_count)
{
- // I am a param that is also a block, so just recurse into my contents
const self_t& typed_param = static_cast<const self_t&>(param);
+
+ // tell parser about our actual type
+ parser.inspectValue<value_t>(name_stack, min_count, max_count, NULL);
+ // then tell it about string-based alternatives ("red", "blue", etc. for LLColor4)
+ if (named_value_t::getPossibleValues())
+ {
+ parser.inspectValue<std::string>(name_stack, min_count, max_count, named_value_t::getPossibleValues());
+ }
+
typed_param.inspectBlock(parser, name_stack, min_count, max_count);
}
@@ -1100,32 +1219,34 @@ namespace LLInitParam
}
// assign block contents to this param-that-is-a-block
- void set(value_assignment_t val, bool flag_as_provided = true)
+ void set(const value_t& val, bool flag_as_provided = true)
{
setValue(val);
- param_value_t::clearValueName();
+ named_value_t::clearValueName();
// force revalidation of block
// next call to isProvided() will update provision status based on validity
param_value_t::mValidated = false;
setProvided(flag_as_provided);
}
- self_t& operator =(const typename NAME_VALUE_LOOKUP::name_t& name)
+ self_t& operator =(const typename named_value_t::name_t& name)
{
- return static_cast<self_t&>(param_value_t::operator =(name));
+ named_value_t::assignNamedValue(name);
+ return *this;
}
// propagate changed status up to enclosing block
/*virtual*/ void paramChanged(const Param& changed_param, bool user_provided)
{
param_value_t::paramChanged(changed_param, user_provided);
+
if (user_provided)
{
// a child param has been explicitly changed
// so *some* aspect of this block is now provided
param_value_t::mValidated = false;
setProvided();
- param_value_t::clearValueName();
+ named_value_t::clearValueName();
}
else
{
@@ -1149,7 +1270,7 @@ namespace LLInitParam
if (src_typed_param.anyProvided())
{
- if (dst_typed_param.mergeBlockParam(src_typed_param.isProvided(), dst_typed_param.isProvided(), param_value_t::selfBlockDescriptor(), src_typed_param, overwrite))
+ if (dst_typed_param.mergeBlockParam(src_typed_param.isProvided(), dst_typed_param.isProvided(), param_value_t::getBlockDescriptor(), src_typed_param, overwrite))
{
dst_typed_param.clearValueName();
dst_typed_param.setProvided(true);
@@ -1158,56 +1279,72 @@ namespace LLInitParam
}
return false;
}
+
+ private:
+ void init( BlockDescriptor &block_descriptor, ParamDescriptor::validation_func_t validate_func, S32 min_count, S32 max_count, const char* name )
+ {
+ ParamDescriptorPtr param_descriptor = ParamDescriptorPtr(new ParamDescriptor(
+ block_descriptor.mCurrentBlockPtr->getHandleFromParam(this),
+ &mergeWith,
+ &deserializeParam,
+ &serializeParam,
+ validate_func,
+ &inspectParam,
+ min_count, max_count));
+ block_descriptor.addParam(param_descriptor, name);
+ }
};
- // container of non-block parameters
+ // list of non-block parameters
template <typename VALUE_TYPE, typename NAME_VALUE_LOOKUP>
- class TypedParam<VALUE_TYPE, NAME_VALUE_LOOKUP, true, false>
+ class TypedParam<VALUE_TYPE, NAME_VALUE_LOOKUP, true, NOT_BLOCK>
: public Param
{
+ protected:
+ typedef TypedParam<VALUE_TYPE, NAME_VALUE_LOOKUP, true, NOT_BLOCK> self_t;
+ typedef ParamValue<typename LLTypeTags::Sorted<VALUE_TYPE>::value_t> param_value_t;
+ typedef typename std::vector<typename NAME_VALUE_LOOKUP::type_value_t> container_t;
+ typedef container_t default_value_t;
+ typedef typename NAME_VALUE_LOOKUP::type_value_t named_value_t;
+
public:
- typedef TypedParam<VALUE_TYPE, NAME_VALUE_LOOKUP, true, false> self_t;
- typedef ParamValue<VALUE_TYPE, NAME_VALUE_LOOKUP> param_value_t;
- typedef typename std::vector<param_value_t> container_t;
- typedef const container_t& value_assignment_t;
-
typedef typename param_value_t::value_t value_t;
- typedef NAME_VALUE_LOOKUP name_value_lookup_t;
- TypedParam(BlockDescriptor& block_descriptor, const char* name, value_assignment_t value, ParamDescriptor::validation_func_t validate_func, S32 min_count, S32 max_count)
+ TypedParam(BlockDescriptor& block_descriptor, const char* name, const default_value_t& value, ParamDescriptor::validation_func_t validate_func, S32 min_count, S32 max_count)
: Param(block_descriptor.mCurrentBlockPtr)
{
std::copy(value.begin(), value.end(), std::back_inserter(mValues));
if (LL_UNLIKELY(block_descriptor.mInitializationState == BlockDescriptor::INITIALIZING))
{
- ParamDescriptorPtr param_descriptor = ParamDescriptorPtr(new ParamDescriptor(
- block_descriptor.mCurrentBlockPtr->getHandleFromParam(this),
- &mergeWith,
- &deserializeParam,
- &serializeParam,
- validate_func,
- &inspectParam,
- min_count, max_count));
- BaseBlock::addParam(block_descriptor, param_descriptor, name);
+ init(block_descriptor, validate_func, min_count, max_count, name);
+
}
}
bool isProvided() const { return Param::anyProvided(); }
- static bool deserializeParam(Param& param, Parser& parser, const Parser::name_stack_range_t& name_stack_range, bool new_name)
+ static bool deserializeParam(Param& param, Parser& parser, Parser::name_stack_range_t& name_stack_range, bool new_name)
{
+ Parser::name_stack_range_t new_name_stack_range(name_stack_range);
self_t& typed_param = static_cast<self_t&>(param);
value_t value;
+
+ // pop first element if empty string
+ if (new_name_stack_range.first != new_name_stack_range.second && new_name_stack_range.first->first.empty())
+ {
+ ++new_name_stack_range.first;
+ }
+
// no further names in stack, attempt to parse value now
if (name_stack_range.first == name_stack_range.second)
{
std::string name;
// try to parse a known named value
- if(name_value_lookup_t::valueNamesExist()
+ if(named_value_t::valueNamesExist()
&& parser.readValue(name)
- && name_value_lookup_t::getValueFromName(name, value))
+ && named_value_t::getValueFromName(name, value))
{
typed_param.add(value);
typed_param.mValues.back().setValueName(name);
@@ -1225,14 +1362,14 @@ namespace LLInitParam
static void serializeParam(const Param& param, Parser& parser, Parser::name_stack_t& name_stack, const Param* diff_param)
{
const self_t& typed_param = static_cast<const self_t&>(param);
- if (!typed_param.isProvided() || name_stack.empty()) return;
+ if (!typed_param.isProvided()) return;
for (const_iterator it = typed_param.mValues.begin(), end_it = typed_param.mValues.end();
it != end_it;
++it)
{
std::string key = it->getValueName();
- name_stack.back().second = true;
+ name_stack.push_back(std::make_pair(std::string(), true));
if(key.empty())
// not parsed via name values, write out value directly
@@ -1254,19 +1391,21 @@ namespace LLInitParam
break;
}
}
+
+ name_stack.pop_back();
}
}
static void inspectParam(const Param& param, Parser& parser, Parser::name_stack_t& name_stack, S32 min_count, S32 max_count)
{
parser.inspectValue<VALUE_TYPE>(name_stack, min_count, max_count, NULL);
- if (name_value_lookup_t::getPossibleValues())
+ if (named_value_t::getPossibleValues())
{
- parser.inspectValue<std::string>(name_stack, min_count, max_count, name_value_lookup_t::getPossibleValues());
+ parser.inspectValue<std::string>(name_stack, min_count, max_count, named_value_t::getPossibleValues());
}
}
- void set(value_assignment_t val, bool flag_as_provided = true)
+ void set(const container_t& val, bool flag_as_provided = true)
{
mValues = val;
setProvided(flag_as_provided);
@@ -1274,26 +1413,24 @@ namespace LLInitParam
param_value_t& add()
{
- mValues.push_back(param_value_t(value_t()));
+ mValues.push_back(value_t());
Param::setProvided();
return mValues.back();
}
self_t& add(const value_t& item)
{
- param_value_t param_value;
- param_value.setValue(item);
- mValues.push_back(param_value);
+ mValues.push_back(item);
setProvided();
return *this;
}
- self_t& add(const typename name_value_lookup_t::name_t& name)
+ self_t& add(const typename named_value_t::name_t& name)
{
value_t value;
// try to parse a per type named value
- if (name_value_lookup_t::getValueFromName(name, value))
+ if (named_value_t::getValueFromName(name, value))
{
add(value);
mValues.back().setValueName(name);
@@ -1303,9 +1440,9 @@ namespace LLInitParam
}
// implicit conversion
- operator value_assignment_t() const { return mValues; }
+ operator const container_t&() const { return mValues; }
// explicit conversion
- value_assignment_t operator()() const { return mValues; }
+ const container_t& operator()() const { return mValues; }
typedef typename container_t::iterator iterator;
typedef typename container_t::const_iterator const_iterator;
@@ -1346,62 +1483,79 @@ namespace LLInitParam
}
container_t mValues;
+
+ private:
+ void init( BlockDescriptor &block_descriptor, ParamDescriptor::validation_func_t validate_func, S32 min_count, S32 max_count, const char* name )
+ {
+ ParamDescriptorPtr param_descriptor = ParamDescriptorPtr(new ParamDescriptor(
+ block_descriptor.mCurrentBlockPtr->getHandleFromParam(this),
+ &mergeWith,
+ &deserializeParam,
+ &serializeParam,
+ validate_func,
+ &inspectParam,
+ min_count, max_count));
+ block_descriptor.addParam(param_descriptor, name);
+ }
};
- // container of block parameters
+ // list of block parameters
template <typename VALUE_TYPE, typename NAME_VALUE_LOOKUP>
- class TypedParam<VALUE_TYPE, NAME_VALUE_LOOKUP, true, true>
+ class TypedParam<VALUE_TYPE, NAME_VALUE_LOOKUP, true, IS_A_BLOCK>
: public Param
{
+ protected:
+ typedef TypedParam<VALUE_TYPE, NAME_VALUE_LOOKUP, true, IS_A_BLOCK> self_t;
+ typedef ParamValue<typename LLTypeTags::Sorted<VALUE_TYPE>::value_t> param_value_t;
+ typedef typename std::vector<typename NAME_VALUE_LOOKUP::type_value_t> container_t;
+ typedef typename NAME_VALUE_LOOKUP::type_value_t named_value_t;
+ typedef container_t default_value_t;
+ typedef typename container_t::iterator iterator;
+ typedef typename container_t::const_iterator const_iterator;
public:
- typedef TypedParam<VALUE_TYPE, NAME_VALUE_LOOKUP, true, true> self_t;
- typedef ParamValue<VALUE_TYPE, NAME_VALUE_LOOKUP> param_value_t;
- typedef typename std::vector<param_value_t> container_t;
- typedef const container_t& value_assignment_t;
typedef typename param_value_t::value_t value_t;
- typedef NAME_VALUE_LOOKUP name_value_lookup_t;
- TypedParam(BlockDescriptor& block_descriptor, const char* name, value_assignment_t value, ParamDescriptor::validation_func_t validate_func, S32 min_count, S32 max_count)
+ TypedParam(BlockDescriptor& block_descriptor, const char* name, const default_value_t& value, ParamDescriptor::validation_func_t validate_func, S32 min_count, S32 max_count)
: Param(block_descriptor.mCurrentBlockPtr)
{
std::copy(value.begin(), value.end(), back_inserter(mValues));
if (LL_UNLIKELY(block_descriptor.mInitializationState == BlockDescriptor::INITIALIZING))
{
- ParamDescriptorPtr param_descriptor = ParamDescriptorPtr(new ParamDescriptor(
- block_descriptor.mCurrentBlockPtr->getHandleFromParam(this),
- &mergeWith,
- &deserializeParam,
- &serializeParam,
- validate_func,
- &inspectParam,
- min_count, max_count));
- BaseBlock::addParam(block_descriptor, param_descriptor, name);
+ init(block_descriptor, validate_func, min_count, max_count, name);
}
}
bool isProvided() const { return Param::anyProvided(); }
- static bool deserializeParam(Param& param, Parser& parser, const Parser::name_stack_range_t& name_stack_range, bool new_name)
+ static bool deserializeParam(Param& param, Parser& parser, Parser::name_stack_range_t& name_stack_range, bool new_name)
{
+ Parser::name_stack_range_t new_name_stack_range(name_stack_range);
self_t& typed_param = static_cast<self_t&>(param);
bool new_value = false;
+ bool new_array_value = false;
- if (new_name || typed_param.mValues.empty())
+ // pop first element if empty string
+ if (new_name_stack_range.first != new_name_stack_range.second && new_name_stack_range.first->first.empty())
+ {
+ new_array_value = new_name_stack_range.first->second;
+ ++new_name_stack_range.first;
+ }
+
+ if (new_name || new_array_value || typed_param.mValues.empty())
{
new_value = true;
typed_param.mValues.push_back(value_t());
}
-
param_value_t& value = typed_param.mValues.back();
if (name_stack_range.first == name_stack_range.second)
{ // try to parse a known named value
std::string name;
- if(name_value_lookup_t::valueNamesExist()
+ if(named_value_t::valueNamesExist()
&& parser.readValue(name)
- && name_value_lookup_t::getValueFromName(name, value.getValue()))
+ && named_value_t::getValueFromName(name, value.getValue()))
{
typed_param.mValues.back().setValueName(name);
typed_param.setProvided();
@@ -1410,9 +1564,13 @@ namespace LLInitParam
}
// attempt to parse block...
- if(value.deserializeBlock(parser, name_stack_range, new_name))
+ if(value.deserializeBlock(parser, new_name_stack_range, new_name))
{
typed_param.setProvided();
+ if (new_array_value)
+ {
+ name_stack_range.first->second = false;
+ }
return true;
}
@@ -1428,13 +1586,13 @@ namespace LLInitParam
static void serializeParam(const Param& param, Parser& parser, Parser::name_stack_t& name_stack, const Param* diff_param)
{
const self_t& typed_param = static_cast<const self_t&>(param);
- if (!typed_param.isProvided() || name_stack.empty()) return;
+ if (!typed_param.isProvided()) return;
for (const_iterator it = typed_param.mValues.begin(), end_it = typed_param.mValues.end();
it != end_it;
++it)
{
- name_stack.back().second = true;
+ name_stack.push_back(std::make_pair(std::string(), true));
std::string key = it->getValueName();
if (!key.empty())
@@ -1447,16 +1605,27 @@ namespace LLInitParam
{
it->serializeBlock(parser, name_stack, NULL);
}
+
+ name_stack.pop_back();
}
}
static void inspectParam(const Param& param, Parser& parser, Parser::name_stack_t& name_stack, S32 min_count, S32 max_count)
{
- // I am a vector of blocks, so describe my contents recursively
- param_value_t(value_t()).inspectBlock(parser, name_stack, min_count, max_count);
+ const param_value_t& value_param = param_value_t(value_t());
+
+ // tell parser about our actual type
+ parser.inspectValue<value_t>(name_stack, min_count, max_count, NULL);
+ // then tell it about string-based alternatives ("red", "blue", etc. for LLColor4)
+ if (named_value_t::getPossibleValues())
+ {
+ parser.inspectValue<std::string>(name_stack, min_count, max_count, named_value_t::getPossibleValues());
}
- void set(value_assignment_t val, bool flag_as_provided = true)
+ value_param.inspectBlock(parser, name_stack, min_count, max_count);
+ }
+
+ void set(const container_t& val, bool flag_as_provided = true)
{
mValues = val;
setProvided(flag_as_provided);
@@ -1476,12 +1645,12 @@ namespace LLInitParam
return *this;
}
- self_t& add(const typename name_value_lookup_t::name_t& name)
+ self_t& add(const typename named_value_t::name_t& name)
{
value_t value;
// try to parse a per type named value
- if (name_value_lookup_t::getValueFromName(name, value))
+ if (named_value_t::getValueFromName(name, value))
{
add(value);
mValues.back().setValueName(name);
@@ -1490,12 +1659,10 @@ namespace LLInitParam
}
// implicit conversion
- operator value_assignment_t() const { return mValues; }
+ operator const container_t&() const { return mValues; }
// explicit conversion
- value_assignment_t operator()() const { return mValues; }
+ const container_t& operator()() const { return mValues; }
- typedef typename container_t::iterator iterator;
- typedef typename container_t::const_iterator const_iterator;
iterator begin() { return mValues.begin(); }
iterator end() { return mValues.end(); }
const_iterator begin() const { return mValues.begin(); }
@@ -1542,6 +1709,20 @@ namespace LLInitParam
}
container_t mValues;
+
+ private:
+ void init( BlockDescriptor &block_descriptor, ParamDescriptor::validation_func_t validate_func, S32 min_count, S32 max_count, const char* name )
+ {
+ ParamDescriptorPtr param_descriptor = ParamDescriptorPtr(new ParamDescriptor(
+ block_descriptor.mCurrentBlockPtr->getHandleFromParam(this),
+ &mergeWith,
+ &deserializeParam,
+ &serializeParam,
+ validate_func,
+ &inspectParam,
+ min_count, max_count));
+ block_descriptor.addParam(param_descriptor, name);
+ }
};
template <typename DERIVED_BLOCK, typename BASE_BLOCK = BaseBlock>
@@ -1556,13 +1737,13 @@ namespace LLInitParam
// take all provided params from other and apply to self
bool overwriteFrom(const self_t& other)
{
- return static_cast<DERIVED_BLOCK*>(this)->mergeBlock(selfBlockDescriptor(), other, true);
+ return static_cast<DERIVED_BLOCK*>(this)->mergeBlock(getBlockDescriptor(), other, true);
}
// take all provided params that are not already provided, and apply to self
bool fillFrom(const self_t& other)
{
- return static_cast<DERIVED_BLOCK*>(this)->mergeBlock(selfBlockDescriptor(), other, false);
+ return static_cast<DERIVED_BLOCK*>(this)->mergeBlock(getBlockDescriptor(), other, false);
}
bool mergeBlockParam(bool source_provided, bool dest_provided, BlockDescriptor& block_data, const self_t& source, bool overwrite)
@@ -1580,7 +1761,7 @@ namespace LLInitParam
bool mergeBlock(BlockDescriptor& block_data, const self_t& other, bool overwrite)
{
mCurChoice = other.mCurChoice;
- return base_block_t::mergeBlock(selfBlockDescriptor(), other, overwrite);
+ return base_block_t::mergeBlock(getBlockDescriptor(), other, overwrite);
}
// clear out old choice when param has changed
@@ -1601,38 +1782,38 @@ namespace LLInitParam
base_block_t::paramChanged(changed_param, user_provided);
}
- virtual const BlockDescriptor& mostDerivedBlockDescriptor() const { return selfBlockDescriptor(); }
- virtual BlockDescriptor& mostDerivedBlockDescriptor() { return selfBlockDescriptor(); }
+ virtual const BlockDescriptor& mostDerivedBlockDescriptor() const { return getBlockDescriptor(); }
+ virtual BlockDescriptor& mostDerivedBlockDescriptor() { return getBlockDescriptor(); }
protected:
ChoiceBlock()
: mCurChoice(0)
{
- BaseBlock::init(selfBlockDescriptor(), base_block_t::selfBlockDescriptor(), sizeof(DERIVED_BLOCK));
+ BaseBlock::init(getBlockDescriptor(), base_block_t::getBlockDescriptor(), sizeof(DERIVED_BLOCK));
}
// Alternatives are mutually exclusive wrt other Alternatives in the same block.
// One alternative in a block will always have isChosen() == true.
// At most one alternative in a block will have isProvided() == true.
- template <typename T, typename NAME_VALUE_LOOKUP = TypeValues<T> >
+ template <typename T, typename NAME_VALUE_LOOKUP = typename TypeValues<T>::type_value_t >
class Alternative : public TypedParam<T, NAME_VALUE_LOOKUP, false>
{
+ typedef TypedParam<T, NAME_VALUE_LOOKUP, false> super_t;
+ typedef typename super_t::value_t value_t;
+ typedef typename super_t::default_value_t default_value_t;
+
public:
friend class ChoiceBlock<DERIVED_BLOCK>;
- typedef Alternative<T, NAME_VALUE_LOOKUP> self_t;
- typedef TypedParam<T, NAME_VALUE_LOOKUP, false, IsBlock<ParamValue<T, NAME_VALUE_LOOKUP> >::value> super_t;
- typedef typename super_t::value_assignment_t value_assignment_t;
-
using super_t::operator =;
- explicit Alternative(const char* name = "", value_assignment_t val = defaultValue<T>())
- : super_t(DERIVED_BLOCK::selfBlockDescriptor(), name, val, NULL, 0, 1),
+ explicit Alternative(const char* name = "", const default_value_t& val = defaultValue<default_value_t>())
+ : super_t(DERIVED_BLOCK::getBlockDescriptor(), name, val, NULL, 0, 1),
mOriginalValue(val)
{
// assign initial choice to first declared option
- DERIVED_BLOCK* blockp = ((DERIVED_BLOCK*)DERIVED_BLOCK::selfBlockDescriptor().mCurrentBlockPtr);
- if (LL_UNLIKELY(DERIVED_BLOCK::selfBlockDescriptor().mInitializationState == BlockDescriptor::INITIALIZING))
+ DERIVED_BLOCK* blockp = ((DERIVED_BLOCK*)DERIVED_BLOCK::getBlockDescriptor().mCurrentBlockPtr);
+ if (LL_UNLIKELY(DERIVED_BLOCK::getBlockDescriptor().mInitializationState == BlockDescriptor::INITIALIZING))
{
if(blockp->mCurChoice == 0)
{
@@ -1646,27 +1827,27 @@ namespace LLInitParam
static_cast<enclosing_block_t&>(Param::enclosingBlock()).paramChanged(*this, true);
}
- void chooseAs(value_assignment_t val)
+ void chooseAs(const value_t& val)
{
super_t::set(val);
}
- void operator =(value_assignment_t val)
+ void operator =(const value_t& val)
{
super_t::set(val);
}
- void operator()(typename super_t::value_assignment_t val)
+ void operator()(const value_t& val)
{
super_t::set(val);
}
- operator value_assignment_t() const
+ operator const value_t&() const
{
return (*this)();
}
- value_assignment_t operator()() const
+ const value_t& operator()() const
{
if (static_cast<enclosing_block_t&>(Param::enclosingBlock()).getCurrentChoice() == this)
{
@@ -1681,11 +1862,11 @@ namespace LLInitParam
}
private:
- T mOriginalValue;
+ default_value_t mOriginalValue;
};
- protected:
- static BlockDescriptor& selfBlockDescriptor()
+ public:
+ static BlockDescriptor& getBlockDescriptor()
{
static BlockDescriptor sBlockDescriptor;
return sBlockDescriptor;
@@ -1705,6 +1886,8 @@ namespace LLInitParam
: public BASE_BLOCK
{
typedef Block<DERIVED_BLOCK, BASE_BLOCK> self_t;
+
+ protected:
typedef Block<DERIVED_BLOCK, BASE_BLOCK> block_t;
public:
@@ -1713,80 +1896,82 @@ namespace LLInitParam
// take all provided params from other and apply to self
bool overwriteFrom(const self_t& other)
{
- return static_cast<DERIVED_BLOCK*>(this)->mergeBlock(selfBlockDescriptor(), other, true);
+ return static_cast<DERIVED_BLOCK*>(this)->mergeBlock(getBlockDescriptor(), other, true);
}
// take all provided params that are not already provided, and apply to self
bool fillFrom(const self_t& other)
{
- return static_cast<DERIVED_BLOCK*>(this)->mergeBlock(selfBlockDescriptor(), other, false);
+ return static_cast<DERIVED_BLOCK*>(this)->mergeBlock(getBlockDescriptor(), other, false);
}
- virtual const BlockDescriptor& mostDerivedBlockDescriptor() const { return selfBlockDescriptor(); }
- virtual BlockDescriptor& mostDerivedBlockDescriptor() { return selfBlockDescriptor(); }
+ virtual const BlockDescriptor& mostDerivedBlockDescriptor() const { return getBlockDescriptor(); }
+ virtual BlockDescriptor& mostDerivedBlockDescriptor() { return getBlockDescriptor(); }
protected:
Block()
{
//#pragma message("Parsing LLInitParam::Block")
- BaseBlock::init(selfBlockDescriptor(), BASE_BLOCK::selfBlockDescriptor(), sizeof(DERIVED_BLOCK));
+ BaseBlock::init(getBlockDescriptor(), BASE_BLOCK::getBlockDescriptor(), sizeof(DERIVED_BLOCK));
}
//
// Nested classes for declaring parameters
//
- template <typename T, typename NAME_VALUE_LOOKUP = TypeValues<T> >
+ template <typename T, typename NAME_VALUE_LOOKUP = typename TypeValues<T>::type_value_t >
class Optional : public TypedParam<T, NAME_VALUE_LOOKUP, false>
{
- public:
- typedef TypedParam<T, NAME_VALUE_LOOKUP, false, IsBlock<ParamValue<T, NAME_VALUE_LOOKUP> >::value> super_t;
- typedef typename super_t::value_assignment_t value_assignment_t;
+ typedef TypedParam<T, NAME_VALUE_LOOKUP, false> super_t;
+ typedef typename super_t::value_t value_t;
+ typedef typename super_t::default_value_t default_value_t;
+ public:
using super_t::operator();
using super_t::operator =;
- explicit Optional(const char* name = "", value_assignment_t val = defaultValue<T>())
- : super_t(DERIVED_BLOCK::selfBlockDescriptor(), name, val, NULL, 0, 1)
+ explicit Optional(const char* name = "", const default_value_t& val = defaultValue<default_value_t>())
+ : super_t(DERIVED_BLOCK::getBlockDescriptor(), name, val, NULL, 0, 1)
{
//#pragma message("Parsing LLInitParam::Block::Optional")
}
- Optional& operator =(value_assignment_t val)
+ Optional& operator =(const value_t& val)
{
set(val);
return *this;
}
- DERIVED_BLOCK& operator()(value_assignment_t val)
+ DERIVED_BLOCK& operator()(const value_t& val)
{
super_t::set(val);
return static_cast<DERIVED_BLOCK&>(Param::enclosingBlock());
}
};
- template <typename T, typename NAME_VALUE_LOOKUP = TypeValues<T> >
+ template <typename T, typename NAME_VALUE_LOOKUP = typename TypeValues<T>::type_value_t >
class Mandatory : public TypedParam<T, NAME_VALUE_LOOKUP, false>
{
- public:
- typedef TypedParam<T, NAME_VALUE_LOOKUP, false, IsBlock<ParamValue<T, NAME_VALUE_LOOKUP> >::value> super_t;
+ typedef TypedParam<T, NAME_VALUE_LOOKUP, false> super_t;
typedef Mandatory<T, NAME_VALUE_LOOKUP> self_t;
- typedef typename super_t::value_assignment_t value_assignment_t;
+ typedef typename super_t::value_t value_t;
+ typedef typename super_t::default_value_t default_value_t;
+ public:
using super_t::operator();
using super_t::operator =;
// mandatory parameters require a name to be parseable
- explicit Mandatory(const char* name = "", value_assignment_t val = defaultValue<T>())
- : super_t(DERIVED_BLOCK::selfBlockDescriptor(), name, val, &validate, 1, 1)
+ explicit Mandatory(const char* name = "", const default_value_t& val = defaultValue<default_value_t>())
+ : super_t(DERIVED_BLOCK::getBlockDescriptor(), name, val, &validate, 1, 1)
{}
- Mandatory& operator =(value_assignment_t val)
+ Mandatory& operator =(const value_t& val)
{
set(val);
return *this;
}
- DERIVED_BLOCK& operator()(typename super_t::value_assignment_t val)
+ DERIVED_BLOCK& operator()(const value_t& val)
{
super_t::set(val);
return static_cast<DERIVED_BLOCK&>(Param::enclosingBlock());
@@ -1800,28 +1985,29 @@ namespace LLInitParam
};
- template <typename T, typename RANGE = BaseBlock::AnyAmount, typename NAME_VALUE_LOOKUP = TypeValues<T> >
+ template <typename T, typename RANGE = BaseBlock::AnyAmount, typename NAME_VALUE_LOOKUP = typename TypeValues<T>::type_value_t >
class Multiple : public TypedParam<T, NAME_VALUE_LOOKUP, true>
{
- public:
- typedef TypedParam<T, NAME_VALUE_LOOKUP, true, IsBlock<ParamValue<T, NAME_VALUE_LOOKUP> >::value> super_t;
+ typedef TypedParam<T, NAME_VALUE_LOOKUP, true> super_t;
typedef Multiple<T, RANGE, NAME_VALUE_LOOKUP> self_t;
typedef typename super_t::container_t container_t;
- typedef typename super_t::value_assignment_t value_assignment_t;
+ typedef typename super_t::value_t value_t;
+
+ public:
typedef typename super_t::iterator iterator;
typedef typename super_t::const_iterator const_iterator;
explicit Multiple(const char* name = "")
- : super_t(DERIVED_BLOCK::selfBlockDescriptor(), name, container_t(), &validate, RANGE::minCount, RANGE::maxCount)
+ : super_t(DERIVED_BLOCK::getBlockDescriptor(), name, container_t(), &validate, RANGE::minCount, RANGE::maxCount)
{}
- Multiple& operator =(value_assignment_t val)
+ Multiple& operator =(const container_t& val)
{
set(val);
return *this;
}
- DERIVED_BLOCK& operator()(typename super_t::value_assignment_t val)
+ DERIVED_BLOCK& operator()(const container_t& val)
{
super_t::set(val);
return static_cast<DERIVED_BLOCK&>(Param::enclosingBlock());
@@ -1834,13 +2020,15 @@ namespace LLInitParam
}
};
- class Deprecated : public Param
+ // can appear in data files, but will ignored during parsing
+ // cannot read or write in code
+ class Ignored : public Param
{
public:
- explicit Deprecated(const char* name)
- : Param(DERIVED_BLOCK::selfBlockDescriptor().mCurrentBlockPtr)
+ explicit Ignored(const char* name)
+ : Param(DERIVED_BLOCK::getBlockDescriptor().mCurrentBlockPtr)
{
- BlockDescriptor& block_descriptor = DERIVED_BLOCK::selfBlockDescriptor();
+ BlockDescriptor& block_descriptor = DERIVED_BLOCK::getBlockDescriptor();
if (LL_UNLIKELY(block_descriptor.mInitializationState == BlockDescriptor::INITIALIZING))
{
ParamDescriptorPtr param_descriptor = ParamDescriptorPtr(new ParamDescriptor(
@@ -1851,11 +2039,11 @@ namespace LLInitParam
NULL,
NULL,
0, S32_MAX));
- BaseBlock::addParam(block_descriptor, param_descriptor, name);
+ block_descriptor.addParam(param_descriptor, name);
}
}
- static bool deserializeParam(Param& param, Parser& parser, const Parser::name_stack_range_t& name_stack_range, bool new_name)
+ static bool deserializeParam(Param& param, Parser& parser, Parser::name_stack_range_t& name_stack_range, bool new_name)
{
if (name_stack_range.first == name_stack_range.second)
{
@@ -1868,19 +2056,46 @@ namespace LLInitParam
}
};
- // different semantics for documentation purposes, but functionally identical
- typedef Deprecated Ignored;
+ // can appear in data files, or be written to in code, but data will be ignored
+ // cannot be read in code
+ class Deprecated : public Ignored
+ {
+ public:
+ explicit Deprecated(const char* name) : Ignored(name) {}
- protected:
- static BlockDescriptor& selfBlockDescriptor()
+ // dummy writer interfaces
+ template<typename T>
+ Deprecated& operator =(const T& val)
+ {
+ // do nothing
+ return *this;
+ }
+
+ template<typename T>
+ DERIVED_BLOCK& operator()(const T& val)
+ {
+ // do nothing
+ return static_cast<DERIVED_BLOCK&>(Param::enclosingBlock());
+ }
+
+ template<typename T>
+ void set(const T& val, bool flag_as_provided = true)
+ {
+ // do nothing
+ }
+ };
+
+ public:
+ static BlockDescriptor& getBlockDescriptor()
{
static BlockDescriptor sBlockDescriptor;
return sBlockDescriptor;
}
- template <typename T, typename NAME_VALUE_LOOKUP, bool multiple, bool is_block>
+ protected:
+ template <typename T, typename NAME_VALUE_LOOKUP, bool multiple, typename is_block>
void changeDefault(TypedParam<T, NAME_VALUE_LOOKUP, multiple, is_block>& param,
- typename TypedParam<T, NAME_VALUE_LOOKUP, multiple, is_block>::value_assignment_t value)
+ const typename TypedParam<T, NAME_VALUE_LOOKUP, multiple, is_block>::value_t& value)
{
if (!param.isProvided())
{
@@ -1890,204 +2105,420 @@ namespace LLInitParam
};
- template <typename DERIVED_BLOCK, typename BASE_BLOCK = BaseBlock>
- class BatchBlock
- : public Block<DERIVED_BLOCK, BASE_BLOCK>
+ template<typename T, typename BLOCK_T>
+ struct IsBlock<ParamValue<BaseBlock::Lazy<T, BaseBlock::IS_A_BLOCK>, BLOCK_T >, void>
+ {
+ typedef IS_A_BLOCK value_t;
+ };
+
+ template<typename T, typename BLOCK_T>
+ struct IsBlock<ParamValue<BaseBlock::Lazy<T, BaseBlock::NOT_A_BLOCK>, BLOCK_T >, void>
+ {
+ typedef NOT_BLOCK value_t;
+ };
+
+ template<typename T, typename BLOCK_IDENTIFIER>
+ struct IsBlock<ParamValue<BaseBlock::Atomic<T>, typename IsBlock<BaseBlock::Atomic<T> >::value_t >, BLOCK_IDENTIFIER>
+ {
+ typedef typename IsBlock<T>::value_t value_t;
+ };
+
+ template<typename T, typename BLOCK_IDENTIFIER>
+ struct IsBlock<ParamValue<BaseBlock::Sequential<T>, typename IsBlock<BaseBlock::Sequential<T> >::value_t >, BLOCK_IDENTIFIER>
{
+ typedef typename IsBlock<T>::value_t value_t;
+ };
+
+
+ template<typename T>
+ struct InnerMostType
+ {
+ typedef T value_t;
+ };
+
+ template<typename T>
+ struct InnerMostType<ParamValue<T, NOT_BLOCK> >
+ {
+ typedef typename InnerMostType<T>::value_t value_t;
+ };
+
+ template<typename T>
+ struct InnerMostType<ParamValue<T, IS_A_BLOCK> >
+ {
+ typedef typename InnerMostType<T>::value_t value_t;
+ };
+
+ template<typename T, typename BLOCK_T>
+ class ParamValue <BaseBlock::Atomic<T>, BLOCK_T>
+ {
+ typedef ParamValue <BaseBlock::Atomic<T>, BLOCK_T> self_t;
+
public:
- typedef BatchBlock<DERIVED_BLOCK, BASE_BLOCK> self_t;
- typedef Block<DERIVED_BLOCK, BASE_BLOCK> super_t;
+ typedef typename InnerMostType<T>::value_t value_t;
+ typedef T default_value_t;
- BatchBlock()
+ ParamValue()
+ : mValue(),
+ mValidated(false)
{}
- bool deserializeBlock(Parser& p, Parser::name_stack_range_t name_stack_range, bool new_name)
+ ParamValue(const default_value_t& value)
+ : mValue(value),
+ mValidated(false)
+ {}
+
+ void setValue(const value_t& val)
+ {
+ mValue.setValue(val);
+ }
+
+ const value_t& getValue() const
+ {
+ return mValue.getValue();
+ }
+
+ value_t& getValue()
+ {
+ return mValue.getValue();
+ }
+
+ bool deserializeBlock(Parser& p, Parser::name_stack_range_t& name_stack_range, bool new_name)
{
if (new_name)
{
- // reset block
- *static_cast<DERIVED_BLOCK*>(this) = defaultBatchValue();
+ resetToDefault();
}
- return super_t::deserializeBlock(p, name_stack_range, new_name);
+ return mValue.deserializeBlock(p, name_stack_range, new_name);
}
- bool mergeBlock(BlockDescriptor& block_data, const BaseBlock& other, bool overwrite)
+ void serializeBlock(Parser& p, Parser::name_stack_t& name_stack, const self_t* diff_block = NULL) const
{
- if (overwrite)
+ const BaseBlock* base_block = diff_block
+ ? &(diff_block->mValue)
+ : NULL;
+ mValue.serializeBlock(p, name_stack, base_block);
+ }
+
+ bool inspectBlock(Parser& p, Parser::name_stack_t name_stack = Parser::name_stack_t(), S32 min_count = 0, S32 max_count = S32_MAX) const
{
- *static_cast<DERIVED_BLOCK*>(this) = defaultBatchValue();
- // merge individual parameters into destination
- return super_t::mergeBlock(super_t::selfBlockDescriptor(), other, overwrite);
+ return mValue.inspectBlock(p, name_stack, min_count, max_count);
}
- return false;
+
+ bool mergeBlockParam(bool source_provided, bool dst_provided, BlockDescriptor& block_data, const self_t& source, bool overwrite)
+ {
+ if ((overwrite && source_provided) // new values coming in on top or...
+ || (!overwrite && !dst_provided)) // values being pushed under with nothing already there
+ {
+ // clear away what is there and take the new stuff as a whole
+ resetToDefault();
+ return mValue.mergeBlock(block_data, source.getValue(), overwrite);
}
- protected:
- static const DERIVED_BLOCK& defaultBatchValue()
+
+
+ return mValue.mergeBlock(block_data, source.getValue(), overwrite);
+ }
+
+ bool validateBlock(bool emit_errors = true) const
+ {
+ return mValue.validateBlock(emit_errors);
+ }
+
+ static BlockDescriptor& getBlockDescriptor()
+ {
+ return value_t::getBlockDescriptor();
+ }
+
+
+ mutable bool mValidated; // lazy validation flag
+
+ private:
+ void resetToDefault()
{
- static DERIVED_BLOCK default_value;
- return default_value;
+ static T default_value;
+ mValue = default_value;
}
+
+ T mValue;
};
- // FIXME: this specialization is not currently used, as it only matches against the BatchBlock base class
- // and not the derived class with the actual params
- template<typename DERIVED_BLOCK,
- typename BASE_BLOCK,
- typename NAME_VALUE_LOOKUP>
- class ParamValue <BatchBlock<DERIVED_BLOCK, BASE_BLOCK>,
- NAME_VALUE_LOOKUP,
- true>
- : public NAME_VALUE_LOOKUP,
- protected BatchBlock<DERIVED_BLOCK, BASE_BLOCK>
+ template<typename T>
+ class ParamValue <BaseBlock::Sequential<T>, IS_A_BLOCK>
{
+ typedef ParamValue <BaseBlock::Sequential<T>, IS_A_BLOCK> self_t;
+
public:
- typedef BatchBlock<DERIVED_BLOCK, BASE_BLOCK> block_t;
- typedef const BatchBlock<DERIVED_BLOCK, BASE_BLOCK>& value_assignment_t;
- typedef block_t value_t;
+ typedef typename InnerMostType<T>::value_t value_t;
+ typedef T default_value_t;
ParamValue()
- : block_t(),
+ : mValue(),
mValidated(false)
- {}
+ {
+ mCurParam = getBlockDescriptor().mAllParams.begin();
+ }
- ParamValue(value_assignment_t other)
- : block_t(other),
+ ParamValue(const default_value_t& value)
+ : mValue(value),
mValidated(false)
{
+ mCurParam = getBlockDescriptor().mAllParams.begin();
}
- void setValue(value_assignment_t val)
+ void setValue(const value_t& val)
{
- *this = val;
+ mValue.setValue(val);
}
- value_assignment_t getValue() const
+ const value_t& getValue() const
{
- return *this;
+ return mValue.getValue();
}
- BatchBlock<DERIVED_BLOCK, BASE_BLOCK>& getValue()
+ value_t& getValue()
{
- return *this;
+ return mValue.getValue();
}
- operator value_assignment_t() const
+ bool deserializeBlock(Parser& p, Parser::name_stack_range_t& name_stack_range, bool new_name)
{
- return *this;
+ if (new_name)
+ {
+ mCurParam = getBlockDescriptor().mAllParams.begin();
}
+ if (name_stack_range.first == name_stack_range.second
+ && mCurParam != getBlockDescriptor().mAllParams.end())
+ {
+ // deserialize to mCurParam
+ ParamDescriptor& pd = *(*mCurParam);
+ ParamDescriptor::deserialize_func_t deserialize_func = pd.mDeserializeFunc;
+ Param* paramp = mValue.getParamFromHandle(pd.mParamHandle);
- value_assignment_t operator()() const
+ if (deserialize_func
+ && paramp
+ && deserialize_func(*paramp, p, name_stack_range, new_name))
{
- return *this;
+ ++mCurParam;
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+ }
+ else
+ {
+ return mValue.deserializeBlock(p, name_stack_range, new_name);
+ }
+ }
+
+ void serializeBlock(Parser& p, Parser::name_stack_t& name_stack, const self_t* diff_block = NULL) const
+ {
+ const BaseBlock* base_block = diff_block
+ ? &(diff_block->mValue)
+ : NULL;
+ mValue.serializeBlock(p, name_stack, base_block);
+ }
+
+ bool inspectBlock(Parser& p, Parser::name_stack_t name_stack = Parser::name_stack_t(), S32 min_count = 0, S32 max_count = S32_MAX) const
+ {
+ return mValue.inspectBlock(p, name_stack, min_count, max_count);
+ }
+
+ bool mergeBlockParam(bool source_provided, bool dst_provided, BlockDescriptor& block_data, const self_t& source, bool overwrite)
+ {
+ return mValue.mergeBlock(block_data, source.getValue(), overwrite);
+ }
+
+ bool validateBlock(bool emit_errors = true) const
+ {
+ return mValue.validateBlock(emit_errors);
+ }
+
+ static BlockDescriptor& getBlockDescriptor()
+ {
+ return value_t::getBlockDescriptor();
}
- protected:
mutable bool mValidated; // lazy validation flag
+
+ private:
+
+ BlockDescriptor::all_params_list_t::iterator mCurParam;
+ T mValue;
};
- template<typename T, bool IS_BLOCK>
- class ParamValue <BaseBlock::Lazy<T>,
- TypeValues<T>,
- IS_BLOCK>
- : public IsBlock<T>::base_class_t
+ template<typename T>
+ class ParamValue <BaseBlock::Sequential<T>, NOT_BLOCK>
+ : public T
{
+ typedef ParamValue <BaseBlock::Sequential<T>, NOT_BLOCK> self_t;
+
public:
- typedef ParamValue <BaseBlock::Lazy<T>, TypeValues<T>, false> self_t;
- typedef const T& value_assignment_t;
- typedef T value_t;
+ typedef typename InnerMostType<T>::value_t value_t;
+ typedef T default_value_t;
+
+ ParamValue()
+ : T(),
+ mValidated(false)
+ {}
+
+ ParamValue(const default_value_t& value)
+ : T(value.getValue()),
+ mValidated(false)
+ {}
+
+ mutable bool mValidated; // lazy validation flag
+ };
+
+ template<typename T, typename BLOCK_T>
+ class ParamValue <BaseBlock::Lazy<T, IS_A_BLOCK>, BLOCK_T>
+ {
+ typedef ParamValue <BaseBlock::Lazy<T, IS_A_BLOCK>, BLOCK_T> self_t;
+
+ public:
+ typedef typename InnerMostType<T>::value_t value_t;
+ typedef LazyValue<T> default_value_t;
ParamValue()
: mValue(),
mValidated(false)
{}
- ParamValue(value_assignment_t other)
+ ParamValue(const default_value_t& other)
: mValue(other),
mValidated(false)
{}
- void setValue(value_assignment_t val)
+ ParamValue(const T& value)
+ : mValue(value),
+ mValidated(false)
+ {}
+
+ void setValue(const value_t& val)
{
mValue.set(val);
}
- value_assignment_t getValue() const
+ const value_t& getValue() const
{
- return mValue.get();
+ return mValue.get().getValue();
}
- T& getValue()
+ value_t& getValue()
{
- return mValue.get();
+ return mValue.get().getValue();
}
- operator value_assignment_t() const
+ bool deserializeBlock(Parser& p, Parser::name_stack_range_t& name_stack_range, bool new_name)
{
- return mValue.get();
+ return mValue.get().deserializeBlock(p, name_stack_range, new_name);
}
- value_assignment_t operator()() const
+ void serializeBlock(Parser& p, Parser::name_stack_t& name_stack, const self_t* diff_block = NULL) const
{
- return mValue.get();
+ if (mValue.empty()) return;
+
+ const BaseBlock* base_block = (diff_block && !diff_block->mValue.empty())
+ ? &(diff_block->mValue.get().getValue())
+ : NULL;
+ mValue.get().serializeBlock(p, name_stack, base_block);
}
- bool deserializeBlock(Parser& p, Parser::name_stack_range_t name_stack_range, bool new_name)
+ bool inspectBlock(Parser& p, Parser::name_stack_t name_stack = Parser::name_stack_t(), S32 min_count = 0, S32 max_count = S32_MAX) const
{
- return mValue.get().deserializeBlock(p, name_stack_range, new_name);
+ return mValue.get().inspectBlock(p, name_stack, min_count, max_count);
}
- void serializeBlock(Parser& p, Parser::name_stack_t& name_stack, const BaseBlock* diff_block = NULL) const
+ bool mergeBlockParam(bool source_provided, bool dst_provided, BlockDescriptor& block_data, const self_t& source, bool overwrite)
{
- if (mValue.empty()) return;
+ return source.mValue.empty() || mValue.get().mergeBlock(block_data, source.getValue(), overwrite);
+ }
- mValue.get().serializeBlock(p, name_stack, diff_block);
+ bool validateBlock(bool emit_errors = true) const
+ {
+ return mValue.empty() || mValue.get().validateBlock(emit_errors);
}
- bool inspectBlock(Parser& p, Parser::name_stack_t name_stack = Parser::name_stack_t(), S32 min_count = 0, S32 max_count = S32_MAX) const
+ static BlockDescriptor& getBlockDescriptor()
{
- if (mValue.empty()) return false;
+ return value_t::getBlockDescriptor();
+ }
- return mValue.get().inspectBlock(p, name_stack, min_count, max_count);
+ mutable bool mValidated; // lazy validation flag
+
+ private:
+ LazyValue<T> mValue;
+ };
+
+ template<typename T, typename BLOCK_T>
+ class ParamValue <BaseBlock::Lazy<T, NOT_BLOCK>, BLOCK_T>
+ {
+ typedef ParamValue <BaseBlock::Lazy<T, NOT_BLOCK>, BLOCK_T> self_t;
+
+ public:
+ typedef typename InnerMostType<T>::value_t value_t;
+ typedef LazyValue<T> default_value_t;
+
+ ParamValue()
+ : mValue(),
+ mValidated(false)
+ {}
+
+ ParamValue(const default_value_t& other)
+ : mValue(other),
+ mValidated(false)
+ {}
+
+ ParamValue(const T& value)
+ : mValue(value),
+ mValidated(false)
+ {}
+
+ void setValue(const value_t& val)
+ {
+ mValue.set(val);
+ }
+
+ const value_t& getValue() const
+ {
+ return mValue.get().getValue();
+ }
+
+ value_t& getValue()
+ {
+ return mValue.get().getValue();
}
- protected:
mutable bool mValidated; // lazy validation flag
private:
- BaseBlock::Lazy<T> mValue;
+ LazyValue<T> mValue;
};
template <>
- class ParamValue <LLSD,
- TypeValues<LLSD>,
- false>
- : public TypeValues<LLSD>,
- public BaseBlock
+ class ParamValue <LLSD, NOT_BLOCK>
+ : public BaseBlock
{
public:
- typedef ParamValue<LLSD, TypeValues<LLSD>, false> self_t;
- typedef const LLSD& value_assignment_t;
+ typedef LLSD value_t;
+ typedef LLSD default_value_t;
ParamValue()
: mValidated(false)
{}
- ParamValue(value_assignment_t other)
+ ParamValue(const default_value_t& other)
: mValue(other),
mValidated(false)
{}
- void setValue(value_assignment_t val) { mValue = val; }
+ void setValue(const value_t& val) { mValue = val; }
- value_assignment_t getValue() const { return mValue; }
+ const value_t& getValue() const { return mValue; }
LLSD& getValue() { return mValue; }
- operator value_assignment_t() const { return mValue; }
- value_assignment_t operator()() const { return mValue; }
-
-
// block param interface
- LL_COMMON_API bool deserializeBlock(Parser& p, Parser::name_stack_range_t name_stack_range, bool new_name);
+ LL_COMMON_API bool deserializeBlock(Parser& p, Parser::name_stack_range_t& name_stack_range, bool new_name);
LL_COMMON_API void serializeBlock(Parser& p, Parser::name_stack_t& name_stack, const BaseBlock* diff_block = NULL) const;
bool inspectBlock(Parser& p, Parser::name_stack_t name_stack = Parser::name_stack_t(), S32 min_count = 0, S32 max_count = S32_MAX) const
{
@@ -2106,8 +2537,7 @@ namespace LLInitParam
template<typename T>
class CustomParamValue
- : public Block<ParamValue<T, TypeValues<T> > >,
- public TypeValues<T>
+ : public Block<ParamValue<T> >
{
public:
typedef enum e_value_age
@@ -2117,20 +2547,21 @@ namespace LLInitParam
BLOCK_AUTHORITATIVE // mValue is derived from the block parameters, which are authoritative
} EValueAge;
- typedef ParamValue<T, TypeValues<T> > derived_t;
+ typedef ParamValue<T> derived_t;
typedef CustomParamValue<T> self_t;
typedef Block<derived_t> block_t;
- typedef const T& value_assignment_t;
+ typedef T default_value_t;
typedef T value_t;
+ typedef void baseblock_base_class_t;
- CustomParamValue(const T& value = T())
+ CustomParamValue(const default_value_t& value = T())
: mValue(value),
mValueAge(VALUE_AUTHORITATIVE),
mValidated(false)
{}
- bool deserializeBlock(Parser& parser, Parser::name_stack_range_t name_stack_range, bool new_name)
+ bool deserializeBlock(Parser& parser, Parser::name_stack_range_t& name_stack_range, bool new_name)
{
derived_t& typed_param = static_cast<derived_t&>(*this);
// try to parse direct value T
@@ -2141,8 +2572,6 @@ namespace LLInitParam
typed_param.mValueAge = VALUE_AUTHORITATIVE;
typed_param.updateBlockFromValue(false);
- typed_param.clearValueName();
-
return true;
}
}
@@ -2156,18 +2585,8 @@ namespace LLInitParam
const derived_t& typed_param = static_cast<const derived_t&>(*this);
const derived_t* diff_param = static_cast<const derived_t*>(diff_block);
- std::string key = typed_param.getValueName();
-
- // first try to write out name of name/value pair
- if (!key.empty())
- {
- if (!diff_param || !ParamCompare<std::string>::equals(diff_param->getValueName(), key))
- {
- parser.writeValue(key, name_stack);
- }
- }
// then try to serialize value directly
- else if (!diff_param || !ParamCompare<T>::equals(typed_param.getValue(), diff_param->getValue()))
+ if (!diff_param || !ParamCompare<T>::equals(typed_param.getValue(), diff_param->getValue()))
{
if (!parser.writeValue(typed_param.getValue(), name_stack))
@@ -2197,19 +2616,6 @@ namespace LLInitParam
}
}
- bool inspectBlock(Parser& parser, Parser::name_stack_t name_stack = Parser::name_stack_t(), S32 min_count = 0, S32 max_count = S32_MAX) const
- {
- // first, inspect with actual type...
- parser.inspectValue<T>(name_stack, min_count, max_count, NULL);
- if (TypeValues<T>::getPossibleValues())
- {
- //...then inspect with possible string values...
- parser.inspectValue<std::string>(name_stack, min_count, max_count, TypeValues<T>::getPossibleValues());
- }
- // then recursively inspect contents...
- return block_t::inspectBlock(parser, name_stack, min_count, max_count);
- }
-
bool validateBlock(bool emit_errors = true) const
{
if (mValueAge == VALUE_NEEDS_UPDATE)
@@ -2217,7 +2623,6 @@ namespace LLInitParam
if (block_t::validateBlock(emit_errors))
{
// clear stale keyword associated with old value
- TypeValues<T>::clearValueName();
mValueAge = BLOCK_AUTHORITATIVE;
static_cast<derived_t*>(const_cast<self_t*>(this))->updateValueFromBlock();
return true;
@@ -2247,17 +2652,15 @@ namespace LLInitParam
}
}
- void setValue(value_assignment_t val)
+ void setValue(const value_t& val)
{
- derived_t& typed_param = static_cast<derived_t&>(*this);
// set param version number to be up to date, so we ignore block contents
mValueAge = VALUE_AUTHORITATIVE;
mValue = val;
- typed_param.clearValueName();
static_cast<derived_t*>(this)->updateBlockFromValue(false);
}
- value_assignment_t getValue() const
+ const value_t& getValue() const
{
validateBlock(true);
return mValue;
@@ -2269,20 +2672,10 @@ namespace LLInitParam
return mValue;
}
- operator value_assignment_t() const
- {
- return getValue();
- }
-
- value_assignment_t operator()() const
- {
- return getValue();
- }
-
protected:
// use this from within updateValueFromBlock() to set the value without making it authoritative
- void updateValue(value_assignment_t value)
+ void updateValue(const value_t& value)
{
mValue = value;
}
diff --git a/indra/llcommon/llinstancetracker.h b/indra/llcommon/llinstancetracker.h
index 403df08990..1eab270e3c 100644
--- a/indra/llcommon/llinstancetracker.h
+++ b/indra/llcommon/llinstancetracker.h
@@ -43,7 +43,7 @@
* semantics: one instance per process, rather than one instance per module as
* sometimes happens with data simply declared static.
*/
-class LL_COMMON_API LLInstanceTrackerBase : public boost::noncopyable
+class LL_COMMON_API LLInstanceTrackerBase
{
protected:
/// Get a process-unique void* pointer slot for the specified type_info
@@ -210,6 +210,9 @@ protected:
virtual const KEY& getKey() const { return mInstanceKey; }
private:
+ LLInstanceTracker( const LLInstanceTracker& );
+ const LLInstanceTracker& operator=( const LLInstanceTracker& );
+
void add_(KEY key)
{
mInstanceKey = key;
diff --git a/indra/llcommon/llmetricperformancetester.cpp b/indra/llcommon/llmetricperformancetester.cpp
index 41d3eb0bf3..731e58bd20 100644
--- a/indra/llcommon/llmetricperformancetester.cpp
+++ b/indra/llcommon/llmetricperformancetester.cpp
@@ -100,7 +100,7 @@ LLSD LLMetricPerformanceTesterBasic::analyzeMetricPerformanceLog(std::istream& i
LLSD ret;
LLSD cur;
- while (!is.eof() && LLSDSerialize::fromXML(cur, is))
+ while (!is.eof() && LLSDParser::PARSE_FAILURE != LLSDSerialize::fromXML(cur, is))
{
for (LLSD::map_iterator iter = cur.beginMap(); iter != cur.endMap(); ++iter)
{
diff --git a/indra/llcommon/llrefcount.h b/indra/llcommon/llrefcount.h
index 8eb5d53f3f..32ae15435a 100644
--- a/indra/llcommon/llrefcount.h
+++ b/indra/llcommon/llrefcount.h
@@ -27,6 +27,7 @@
#define LLREFCOUNT_H
#include <boost/noncopyable.hpp>
+#include <boost/intrusive_ptr.hpp>
#define LL_REF_COUNT_DEBUG 0
#if LL_REF_COUNT_DEBUG
@@ -86,4 +87,22 @@ private:
#endif
};
+/**
+ * intrusive pointer support
+ * this allows you to use boost::intrusive_ptr with any LLRefCount-derived type
+ */
+namespace boost
+{
+ inline void intrusive_ptr_add_ref(LLRefCount* p)
+ {
+ p->ref();
+ }
+
+ inline void intrusive_ptr_release(LLRefCount* p)
+ {
+ p->unref();
+ }
+};
+
+
#endif
diff --git a/indra/llcommon/llregistry.h b/indra/llcommon/llregistry.h
index 853c427a13..bb0d60247e 100644
--- a/indra/llcommon/llregistry.h
+++ b/indra/llcommon/llregistry.h
@@ -307,6 +307,10 @@ public:
virtual ~StaticRegistrar() {}
StaticRegistrar(ref_const_key_t key, ref_const_value_t value)
{
+ if (singleton_t::instance().exists(key))
+ {
+ llerrs << "Duplicate registry entry under key \"" << key << "\"" << llendl;
+ }
singleton_t::instance().mStaticScope->add(key, value);
}
};
diff --git a/indra/llcommon/llsdparam.cpp b/indra/llcommon/llsdparam.cpp
index 0e29873bb0..9f4460a988 100644
--- a/indra/llcommon/llsdparam.cpp
+++ b/indra/llcommon/llsdparam.cpp
@@ -223,10 +223,14 @@ LLSD& LLParamSDParserUtilities::getSDWriteNode(LLSD& input, LLInitParam::Parser:
{
bool new_traversal = it->second;
- LLSD* child_sd = it->first.empty() ? sd_to_write : &(*sd_to_write)[it->first];
-
- if (child_sd->isArray())
+ LLSD* child_sd;
+ if (it->first.empty())
{
+ child_sd = sd_to_write;
+ if (child_sd->isUndefined())
+ {
+ *child_sd = LLSD::emptyArray();
+ }
if (new_traversal)
{
// write to new element at end
@@ -240,22 +244,7 @@ LLSD& LLParamSDParserUtilities::getSDWriteNode(LLSD& input, LLInitParam::Parser:
}
else
{
- if (new_traversal
- && child_sd->isDefined()
- && !child_sd->isArray())
- {
- // copy child contents into first element of an array
- LLSD new_array = LLSD::emptyArray();
- new_array.append(*child_sd);
- // assign array to slot that previously held the single value
- *child_sd = new_array;
- // return next element in that array
- sd_to_write = &((*child_sd)[1]);
- }
- else
- {
- sd_to_write = child_sd;
- }
+ sd_to_write = &(*sd_to_write)[it->first];
}
it->second = false;
}
@@ -283,8 +272,9 @@ void LLParamSDParserUtilities::readSDValues(read_sd_cb_t cb, const LLSD& sd, LLI
it != sd.endArray();
++it)
{
- stack.back().second = true;
+ stack.push_back(make_pair(std::string(), true));
readSDValues(cb, *it, stack);
+ stack.pop_back();
}
}
else if (sd.isUndefined())
@@ -313,8 +303,14 @@ namespace LLInitParam
{
// LLSD specialization
// block param interface
- bool ParamValue<LLSD, TypeValues<LLSD>, false>::deserializeBlock(Parser& p, Parser::name_stack_range_t name_stack, bool new_name)
+ bool ParamValue<LLSD, NOT_BLOCK>::deserializeBlock(Parser& p, Parser::name_stack_range_t& name_stack, bool new_name)
{
+ if (name_stack.first == name_stack.second
+ && p.readValue<LLSD>(mValue))
+ {
+ return true;
+ }
+
LLSD& sd = LLParamSDParserUtilities::getSDWriteNode(mValue, name_stack);
LLSD::String string;
@@ -328,15 +324,18 @@ namespace LLInitParam
}
//static
- void ParamValue<LLSD, TypeValues<LLSD>, false>::serializeElement(Parser& p, const LLSD& sd, Parser::name_stack_t& name_stack)
+ void ParamValue<LLSD, NOT_BLOCK>::serializeElement(Parser& p, const LLSD& sd, Parser::name_stack_t& name_stack)
{
p.writeValue<LLSD::String>(sd.asString(), name_stack);
}
- void ParamValue<LLSD, TypeValues<LLSD>, false>::serializeBlock(Parser& p, Parser::name_stack_t& name_stack, const BaseBlock* diff_block) const
+ void ParamValue<LLSD, NOT_BLOCK>::serializeBlock(Parser& p, Parser::name_stack_t& name_stack, const BaseBlock* diff_block) const
{
- // read from LLSD value and serialize out to parser (which could be LLSD, XUI, etc)
- Parser::name_stack_t stack;
- LLParamSDParserUtilities::readSDValues(boost::bind(&serializeElement, boost::ref(p), _1, _2), mValue, stack);
+ // attempt to write LLSD out directly
+ if (!p.writeValue<LLSD>(mValue, name_stack))
+ {
+ // otherwise read from LLSD value and serialize out to parser (which could be LLSD, XUI, etc)
+ LLParamSDParserUtilities::readSDValues(boost::bind(&serializeElement, boost::ref(p), _1, _2), mValue, name_stack);
+ }
}
}
diff --git a/indra/llcommon/llsdserialize.cpp b/indra/llcommon/llsdserialize.cpp
index 6b549e4b6f..ad4fce6f35 100644
--- a/indra/llcommon/llsdserialize.cpp
+++ b/indra/llcommon/llsdserialize.cpp
@@ -1453,8 +1453,8 @@ S32 LLSDBinaryFormatter::format(const LLSD& data, std::ostream& ostr, U32 option
case LLSD::TypeUUID:
{
ostr.put('u');
- LLSD::UUID value = data.asUUID();
- ostr.write((const char*)(&value.mData), UUID_BYTES);
+ LLUUID temp = data.asUUID();
+ ostr.write((const char*)(&(temp.mData)), UUID_BYTES);
break;
}
diff --git a/indra/llcommon/llsdserialize.h b/indra/llcommon/llsdserialize.h
index 86e3fc864c..e7a5507385 100644
--- a/indra/llcommon/llsdserialize.h
+++ b/indra/llcommon/llsdserialize.h
@@ -300,7 +300,7 @@ public:
/**
* @brief Constructor
*/
- LLSDXMLParser();
+ LLSDXMLParser(bool emit_errors=true);
protected:
/**
@@ -747,25 +747,25 @@ public:
return f->format(sd, str, LLSDFormatter::OPTIONS_PRETTY);
}
- static S32 fromXMLEmbedded(LLSD& sd, std::istream& str)
+ static S32 fromXMLEmbedded(LLSD& sd, std::istream& str, bool emit_errors=true)
{
// no need for max_bytes since xml formatting is not
// subvertable by bad sizes.
- LLPointer<LLSDXMLParser> p = new LLSDXMLParser;
+ LLPointer<LLSDXMLParser> p = new LLSDXMLParser(emit_errors);
return p->parse(str, sd, LLSDSerialize::SIZE_UNLIMITED);
}
// Line oriented parser, 30% faster than fromXML(), but can
// only be used when you know you have the complete XML
// document available in the stream.
- static S32 fromXMLDocument(LLSD& sd, std::istream& str)
+ static S32 fromXMLDocument(LLSD& sd, std::istream& str, bool emit_errors=true)
{
- LLPointer<LLSDXMLParser> p = new LLSDXMLParser();
+ LLPointer<LLSDXMLParser> p = new LLSDXMLParser(emit_errors);
return p->parseLines(str, sd);
}
- static S32 fromXML(LLSD& sd, std::istream& str)
+ static S32 fromXML(LLSD& sd, std::istream& str, bool emit_errors=true)
{
- return fromXMLEmbedded(sd, str);
-// return fromXMLDocument(sd, str);
+ return fromXMLEmbedded(sd, str, emit_errors);
+// return fromXMLDocument(sd, str, emit_errors);
}
/*
diff --git a/indra/llcommon/llsdserialize_xml.cpp b/indra/llcommon/llsdserialize_xml.cpp
index 34b3dbb99a..cef743a7be 100644
--- a/indra/llcommon/llsdserialize_xml.cpp
+++ b/indra/llcommon/llsdserialize_xml.cpp
@@ -250,7 +250,7 @@ std::string LLSDXMLFormatter::escapeString(const std::string& in)
class LLSDXMLParser::Impl
{
public:
- Impl();
+ Impl(bool emit_errors);
~Impl();
S32 parse(std::istream& input, LLSD& data);
@@ -294,6 +294,7 @@ private:
static const XML_Char* findAttribute(const XML_Char* name, const XML_Char** pairs);
+ bool mEmitErrors;
XML_Parser mParser;
@@ -315,7 +316,8 @@ private:
};
-LLSDXMLParser::Impl::Impl()
+LLSDXMLParser::Impl::Impl(bool emit_errors)
+ : mEmitErrors(emit_errors)
{
mParser = XML_ParserCreate(NULL);
reset();
@@ -402,7 +404,10 @@ S32 LLSDXMLParser::Impl::parse(std::istream& input, LLSD& data)
{
((char*) buffer)[count ? count - 1 : 0] = '\0';
}
- llinfos << "LLSDXMLParser::Impl::parse: XML_STATUS_ERROR parsing:" << (char*) buffer << llendl;
+ if (mEmitErrors)
+ {
+ llinfos << "LLSDXMLParser::Impl::parse: XML_STATUS_ERROR parsing:" << (char*) buffer << llendl;
+ }
data = LLSD();
return LLSDParser::PARSE_FAILURE;
}
@@ -480,7 +485,10 @@ S32 LLSDXMLParser::Impl::parseLines(std::istream& input, LLSD& data)
if (status == XML_STATUS_ERROR
&& !mGracefullStop)
{
- llinfos << "LLSDXMLParser::Impl::parseLines: XML_STATUS_ERROR" << llendl;
+ if (mEmitErrors)
+ {
+ llinfos << "LLSDXMLParser::Impl::parseLines: XML_STATUS_ERROR" << llendl;
+ }
return LLSDParser::PARSE_FAILURE;
}
@@ -897,7 +905,7 @@ LLSDXMLParser::Impl::Element LLSDXMLParser::Impl::readElement(const XML_Char* na
/**
* LLSDXMLParser
*/
-LLSDXMLParser::LLSDXMLParser() : impl(* new Impl)
+LLSDXMLParser::LLSDXMLParser(bool emit_errors /* = true */) : impl(* new Impl(emit_errors))
{
}
diff --git a/indra/llcommon/llthread.h b/indra/llcommon/llthread.h
index 5c8bbca2ca..0fb89c5613 100644
--- a/indra/llcommon/llthread.h
+++ b/indra/llcommon/llthread.h
@@ -30,6 +30,7 @@
#include "llapp.h"
#include "llapr.h"
#include "apr_thread_cond.h"
+#include "boost/intrusive_ptr.hpp"
class LLThread;
class LLMutex;
@@ -284,6 +285,22 @@ private:
S32 mRef;
};
+/**
+ * intrusive pointer support for LLThreadSafeRefCount
+ * this allows you to use boost::intrusive_ptr with any LLThreadSafeRefCount-derived type
+ */
+namespace boost
+{
+ inline void intrusive_ptr_add_ref(LLThreadSafeRefCount* p)
+ {
+ p->ref();
+ }
+
+ inline void intrusive_ptr_release(LLThreadSafeRefCount* p)
+ {
+ p->unref();
+ }
+};
//============================================================================
// Simple responder for self destructing callbacks
diff --git a/indra/llcommon/llversionserver.h b/indra/llcommon/llversionserver.h
index b19ba3bf74..ef68a0eaf5 100644
--- a/indra/llcommon/llversionserver.h
+++ b/indra/llcommon/llversionserver.h
@@ -30,7 +30,7 @@
const S32 LL_VERSION_MAJOR = 2;
const S32 LL_VERSION_MINOR = 1;
const S32 LL_VERSION_PATCH = 0;
-const S32 LL_VERSION_BUILD = 13828;
+const S32 LL_VERSION_BUILD = 264760;
const char * const LL_CHANNEL = "Second Life Server";
diff --git a/indra/llcommon/llversionviewer.h b/indra/llcommon/llversionviewer.h
index 6a5ff314e4..0ea130e86b 100644
--- a/indra/llcommon/llversionviewer.h
+++ b/indra/llcommon/llversionviewer.h
@@ -28,9 +28,9 @@
#define LL_LLVERSIONVIEWER_H
const S32 LL_VERSION_MAJOR = 3;
-const S32 LL_VERSION_MINOR = 4;
-const S32 LL_VERSION_PATCH = 6;
-const S32 LL_VERSION_BUILD = 0;
+const S32 LL_VERSION_MINOR = 5;
+const S32 LL_VERSION_PATCH = 2;
+const S32 LL_VERSION_BUILD = 264760;
const char * const LL_CHANNEL = "Second Life Developer";
diff --git a/indra/llcommon/stdenums.h b/indra/llcommon/stdenums.h
index 40b3364b36..efcbe76795 100644
--- a/indra/llcommon/stdenums.h
+++ b/indra/llcommon/stdenums.h
@@ -51,7 +51,8 @@ enum EDragAndDropType
DAD_LINK = 14,
DAD_MESH = 15,
DAD_WIDGET = 16,
- DAD_COUNT = 17, // number of types in this enum
+ DAD_PERSON = 17,
+ DAD_COUNT = 18, // number of types in this enum
};
// Reasons for drags to be denied.
diff --git a/indra/llcommon/tests/bitpack_test.cpp b/indra/llcommon/tests/bitpack_test.cpp
index 4c3bc674af..afc0c18cd0 100644
--- a/indra/llcommon/tests/bitpack_test.cpp
+++ b/indra/llcommon/tests/bitpack_test.cpp
@@ -71,7 +71,6 @@ namespace tut
U8 packbuffer[255];
U8 unpackbuffer[255];
int pack_bufsize = 0;
- int unpack_bufsize = 0;
LLBitPack bitpack(packbuffer, 255);
@@ -81,21 +80,20 @@ namespace tut
pack_bufsize = bitpack.flushBitPack();
LLBitPack bitunpack(packbuffer, pack_bufsize*8);
- unpack_bufsize = bitunpack.bitUnpack(&unpackbuffer[0], 8);
+ bitunpack.bitUnpack(&unpackbuffer[0], 8);
ensure("bitPack: individual unpack: 0", unpackbuffer[0] == (U8) str[0]);
- unpack_bufsize = bitunpack.bitUnpack(&unpackbuffer[0], 8);
+ bitunpack.bitUnpack(&unpackbuffer[0], 8);
ensure("bitPack: individual unpack: 1", unpackbuffer[0] == (U8) str[1]);
- unpack_bufsize = bitunpack.bitUnpack(&unpackbuffer[0], 8);
+ bitunpack.bitUnpack(&unpackbuffer[0], 8);
ensure("bitPack: individual unpack: 2", unpackbuffer[0] == (U8) str[2]);
- unpack_bufsize = bitunpack.bitUnpack(&unpackbuffer[0], 8);
+ bitunpack.bitUnpack(&unpackbuffer[0], 8);
ensure("bitPack: individual unpack: 3", unpackbuffer[0] == (U8) str[3]);
- unpack_bufsize = bitunpack.bitUnpack(&unpackbuffer[0], 8);
+ bitunpack.bitUnpack(&unpackbuffer[0], 8);
ensure("bitPack: individual unpack: 4", unpackbuffer[0] == (U8) str[4]);
- unpack_bufsize = bitunpack.bitUnpack(&unpackbuffer[0], 8);
+ bitunpack.bitUnpack(&unpackbuffer[0], 8);
ensure("bitPack: individual unpack: 5", unpackbuffer[0] == (U8) str[5]);
- unpack_bufsize = bitunpack.bitUnpack(unpackbuffer, 8*4); // Life
+ bitunpack.bitUnpack(unpackbuffer, 8*4); // Life
ensure_memory_matches("bitPack: 4 bytes unpack:", unpackbuffer, 4, str+6, 4);
- ensure("keep compiler quiet", unpack_bufsize == unpack_bufsize);
}
// U32 packing
diff --git a/indra/llcommon/tests/llinstancetracker_test.cpp b/indra/llcommon/tests/llinstancetracker_test.cpp
index 454695ff9f..e769c3e22c 100644
--- a/indra/llcommon/tests/llinstancetracker_test.cpp
+++ b/indra/llcommon/tests/llinstancetracker_test.cpp
@@ -267,7 +267,6 @@ namespace tut
{
existing.insert(&*uki);
}
- Unkeyed* puk = NULL;
try
{
// We don't expect the assignment to take place because we expect
@@ -280,7 +279,7 @@ namespace tut
// realize we're testing the C++ implementation more than
// Unkeyed's implementation, but this seems an important point to
// nail down.
- puk = new Unkeyed("throw");
+ new Unkeyed("throw");
}
catch (const Badness&)
{