LLCommon cleanup and updating to V2 (V3 now, I guess.)

This commit is contained in:
Shyotl
2011-08-27 01:57:10 -05:00
parent 863ab7fa6b
commit 1f187b09ee
63 changed files with 1750 additions and 190 deletions

View File

@@ -19,3 +19,8 @@ set(LLCOMMON_INCLUDE_DIRS
)
set(LLCOMMON_LIBRARIES llcommon)
set(LLCOMMON_LINK_SHARED ON CACHE BOOL "Build the llcommon target as a shared library.")
if(LLCOMMON_LINK_SHARED)
add_definitions(-DLL_COMMON_LINK_SHARED=1)
endif(LLCOMMON_LINK_SHARED)

View File

@@ -89,7 +89,7 @@ S32 check_for_invalid_wav_formats(const std::string& in_fname, std::string& erro
//********************************
LLAPRFile infile ;
infile.open(in_fname,LL_APR_RB, LLAPRFile::global);
infile.open(in_fname,LL_APR_RB);
//********************************
if (!infile.getFileHandle())
{
@@ -240,7 +240,7 @@ S32 encode_vorbis_file(const std::string& in_fname, const std::string& out_fname
S32 data_left = 0;
LLAPRFile infile ;
infile.open(in_fname,LL_APR_RB, LLAPRFile::global);
infile.open(in_fname,LL_APR_RB);
if (!infile.getFileHandle())
{
llwarns << "Couldn't open temporary ogg file for writing: " << in_fname
@@ -249,7 +249,7 @@ S32 encode_vorbis_file(const std::string& in_fname, const std::string& out_fname
}
LLAPRFile outfile ;
outfile.open(out_fname,LL_APR_WPB, LLAPRFile::global);
outfile.open(out_fname,LL_APR_WPB);
if (!outfile.getFileHandle())
{
llwarns << "Couldn't open upload sound file for reading: " << in_fname

View File

@@ -226,7 +226,7 @@ ELoadStatus LLBVHLoader::loadTranslationTable(const char *fileName)
std::string path = gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS,fileName);
LLAPRFile infile ;
infile.open(path, LL_APR_R, LLAPRFile::global);
infile.open(path, LL_APR_R);
apr_file_t *fp = infile.getFileHandle();
if (!fp)
return E_ST_NO_XLT_FILE;

View File

@@ -42,7 +42,7 @@
#include "llmotioncontroller.h"
#include "llvisualparam.h"
#include "string_table.h"
#include "llmemory.h"
#include "llpointer.h"
#include "llthread.h"
class LLPolyMesh;

View File

@@ -37,7 +37,7 @@
// Header Files
//-----------------------------------------------------------------------------
#include "lljoint.h"
#include "llmemory.h"
#include "llrefcount.h"
//-----------------------------------------------------------------------------
// class LLJointState

View File

@@ -163,8 +163,6 @@ void LLPose::setWeight(F32 weight)
// there was a crash here
// </edit>
llassert_always(iter->second.notNull());
if(!iter->second) //uhoh...
continue;
iter->second->setWeight(weight);
}
mWeight = weight;

View File

@@ -40,6 +40,8 @@
#include "lljointstate.h"
#include "lljoint.h"
#include "llmap.h"
#include "llpointer.h"
#include <map>
#include <string>

View File

@@ -211,7 +211,7 @@ LLFSMState* LLStateDiagram::getState(U32 state_id)
BOOL LLStateDiagram::saveDotFile(const std::string& filename)
{
LLAPRFile outfile ;
outfile.open(filename, LL_APR_W, LLAPRFile::global);
outfile.open(filename, LL_APR_W);
apr_file_t* dot_file = outfile.getFileHandle() ;
if (!dot_file)

View File

@@ -196,6 +196,7 @@ set(llcommon_HEADER_FILES
llsys.h
llthread.h
lltimer.h
lltreeiterators.h
lluri.h
lluuid.h
lluuidhashmap.h
@@ -232,6 +233,7 @@ target_link_libraries(
${EXPAT_LIBRARIES}
${ZLIB_LIBRARIES}
${WINDOWS_LIBRARIES}
${BOOST_REGEX_LIBRARY}
${CWDEBUG_LIBRARIES}
${CORESERVICES_LIBRARY}
)

View File

@@ -191,6 +191,10 @@ apr_status_t LLAPRFile::open(std::string const& filename, apr_int32_t flags, acc
return status;
}
apr_status_t LLAPRFile::open(const std::string& filename, apr_int32_t flags, BOOL use_global_pool)
{
return open(filename, flags, use_global_pool ? LLAPRFile::global : LLAPRFile::local);
}
// File I/O
S32 LLAPRFile::read(void *buf, S32 nbytes)
{

View File

@@ -150,10 +150,11 @@ public:
};
LLAPRFile() ;
LLAPRFile(const std::string& filename, apr_int32_t flags, access_t access_type);
LLAPRFile(const std::string& filename, apr_int32_t flags, access_t access_type = LLAPRFile::global);
~LLAPRFile() ;
apr_status_t open(const std::string& filename, apr_int32_t flags, access_t access_type, S32* sizep = NULL);
apr_status_t open(const std::string& filename, apr_int32_t flags, access_t access_type = LLAPRFile::global, S32* sizep = NULL);
apr_status_t open(const std::string& filename, apr_int32_t flags, BOOL use_global_pool); //use global pool.
apr_status_t close() ;
// Returns actual offset, -1 if seek fails

View File

@@ -35,6 +35,7 @@
#include "llassettype.h"
#include "lldictionary.h"
#include "llmemory.h"
#include "llsingleton.h"
///----------------------------------------------------------------------------
/// Class LLAssetType

View File

@@ -36,6 +36,7 @@
#include "llfoldertype.h"
#include "lldictionary.h"
#include "llmemory.h"
#include "llsingleton.h"
///----------------------------------------------------------------------------
/// Class LLFolderType
@@ -95,7 +96,12 @@ LLFolderDictionary::LLFolderDictionary()
addEntry(LLFolderType::FT_CURRENT_OUTFIT, new FolderEntry("current", TRUE));
addEntry(LLFolderType::FT_OUTFIT, new FolderEntry("outfit", FALSE));
addEntry(LLFolderType::FT_MY_OUTFITS, new FolderEntry("my_otfts", TRUE));
addEntry(LLFolderType::FT_MESH, new FolderEntry("mesh", TRUE));
addEntry(LLFolderType::FT_INBOX, new FolderEntry("inbox", TRUE));
addEntry(LLFolderType::FT_OUTBOX, new FolderEntry("outbox", TRUE));
addEntry(LLFolderType::FT_BASIC_ROOT, new FolderEntry("basic_rt", TRUE));
addEntry(LLFolderType::FT_NONE, new FolderEntry("-1", FALSE));
};

View File

@@ -87,9 +87,14 @@ public:
FT_OUTFIT = 47,
FT_MY_OUTFITS = 48,
FT_INBOX = 49,
FT_MESH = 49,
FT_COUNT = 50,
FT_INBOX = 50,
FT_OUTBOX = 51,
FT_BASIC_ROOT = 52,
FT_COUNT,
FT_NONE = -1
};

View File

@@ -99,7 +99,7 @@ public:
public:
typedef boost::iterator_facade<key_iter, KEY, boost::forward_traversal_tag> super_t;
key_iter(typename InstanceMap::iterator& it)
key_iter(typename InstanceMap::iterator it)
: mIterator(it)
{
++sIterationNestDepth;

View File

@@ -118,6 +118,62 @@ public:
THROTTLE_BLOCKED, // rate exceed, block key
};
F64 getActionCount(const T& id)
{
U64 now = 0;
if ( mIsRealtime )
{
now = LLKeyThrottleImpl<T>::getTime();
}
else
{
now = LLKeyThrottleImpl<T>::getFrame();
}
if (now >= (m.startTime + m.intervalLength))
{
if (now < (m.startTime + 2 * m.intervalLength))
{
// prune old data
delete m.prevMap;
m.prevMap = m.currMap;
m.currMap = new typename LLKeyThrottleImpl<T>::EntryMap;
m.startTime += m.intervalLength;
}
else
{
// lots of time has passed, all data is stale
delete m.prevMap;
delete m.currMap;
m.prevMap = new typename LLKeyThrottleImpl<T>::EntryMap;
m.currMap = new typename LLKeyThrottleImpl<T>::EntryMap;
m.startTime = now;
}
}
U32 prevCount = 0;
typename LLKeyThrottleImpl<T>::EntryMap::const_iterator prev = m.prevMap->find(id);
if (prev != m.prevMap->end())
{
prevCount = prev->second.count;
}
typename LLKeyThrottleImpl<T>::Entry& curr = (*m.currMap)[id];
// curr.count is the number of keys in
// this current 'time slice' from the beginning of it until now
// prevCount is the number of keys in the previous
// time slice scaled to be one full time slice back from the current
// (now) time.
// compute current, windowed rate
F64 timeInCurrent = ((F64)(now - m.startTime) / m.intervalLength);
F64 averageCount = curr.count + prevCount * (1.0 - timeInCurrent);
return averageCount;
}
// call each time the key wants use
State noteAction(const T& id, S32 weight = 1)
{

View File

@@ -74,9 +74,3 @@ void LLMortician::setZealous(BOOL b)
{
sDestroyImmediate = b;
}
// static
BOOL LLMortician::getZealous()
{
return sDestroyImmediate;
}

View File

@@ -46,7 +46,6 @@ public:
// sets destroy immediate true
static void setZealous(BOOL b);
static BOOL getZealous();
private:
static BOOL sDestroyImmediate;

View File

@@ -107,7 +107,17 @@
#endif
// Deal with the differences on Windows
// Static linking with apr on windows needs to be declared.
#if LL_WINDOWS && !LL_COMMON_LINK_SHARED
#ifndef APR_DECLARE_STATIC
#define APR_DECLARE_STATIC // For APR on Windows
#endif
#ifndef APU_DECLARE_STATIC
#define APU_DECLARE_STATIC // For APR util on Windows
#endif
#endif
#if defined(LL_WINDOWS)
#define BOOST_REGEX_NO_LIB 1
#define CURL_STATICLIB 1
@@ -159,12 +169,19 @@
#define LL_DLLIMPORT
#endif // LL_WINDOWS
#ifdef llcommon_EXPORTS
// Compiling llcommon (shared)
#define LL_COMMON_API LL_DLLEXPORT
#else // llcommon_EXPORTS
// Using llcommon (shared)
#define LL_COMMON_API LL_DLLIMPORT
#endif // llcommon_EXPORTS
#if LL_COMMON_LINK_SHARED
// CMake automagically defines llcommon_EXPORTS only when building llcommon
// sources, and only when llcommon is a shared library (i.e. when
// LL_COMMON_LINK_SHARED). We must still test LL_COMMON_LINK_SHARED because
// otherwise we can't distinguish between (non-llcommon source) and (llcommon
// not shared).
# if defined(llcommon_EXPORTS)
# define LL_COMMON_API LL_DLLEXPORT
# else //llcommon_EXPORTS
# define LL_COMMON_API LL_DLLIMPORT
# endif //llcommon_EXPORTS
#else // LL_COMMON_LINK_SHARED
# define LL_COMMON_API
#endif // LL_COMMON_LINK_SHARED
#endif // not LL_LINDEN_PREPROCESSOR_H

View File

@@ -31,8 +31,9 @@
#include "linden_common.h"
#include "llqueuedthread.h"
#include "llstl.h"
#include "lltimer.h"
#include "lltimer.h" // ms_sleep()
//============================================================================

View File

@@ -754,11 +754,7 @@ void LLSD::insert(const String& k, const LLSD& v) { makeMap(impl).insert(k, v);
LLSD& LLSD::with(const String& k, const LLSD& v)
{
makeMap(impl).insert(k, v);
#ifdef LL_MSVC7
return *dynamic_cast<LLSD*>(this);
#else
return *this;
#endif
return *this;
}
void LLSD::erase(const String& k) { makeMap(impl).erase(k); }
@@ -784,11 +780,7 @@ void LLSD::insert(Integer i, const LLSD& v) { makeArray(impl).insert(i, v); }
LLSD& LLSD::with(Integer i, const LLSD& v)
{
makeArray(impl).insert(i, v);
#ifdef LL_MSVC7
return *dynamic_cast<LLSD*>(this);
#else
return *this;
#endif
return *this;
}
void LLSD::append(const LLSD& v) { makeArray(impl).append(v); }
void LLSD::erase(Integer i) { makeArray(impl).erase(i); }

View File

@@ -34,7 +34,7 @@
#include "linden_common.h"
#include "llsdserialize.h"
#include "llmemory.h"
#include "llpointer.h"
#include "llstreamtools.h" // for fullread
#include <iostream>

View File

@@ -36,8 +36,9 @@
#define LL_LLSDSERIALIZE_H
#include <iosfwd>
#include "llpointer.h"
#include "llrefcount.h"
#include "llsd.h"
#include "llmemory.h"
/**
* @class LLSDParser

View File

@@ -37,6 +37,7 @@
#include <deque>
#include "apr_base64.h"
#include <boost/regex.hpp>
extern "C"
{
@@ -734,6 +735,7 @@ void LLSDXMLParser::Impl::endElementHandler(const XML_Char* name)
case ELEMENT_INTEGER:
{
S32 i;
// sscanf okay here with different locales - ints don't change for different locale settings like floats do.
if ( sscanf(mCurrentContent.c_str(), "%d", &i ) == 1 )
{ // See if sscanf works - it's faster
value = i;
@@ -747,15 +749,19 @@ void LLSDXMLParser::Impl::endElementHandler(const XML_Char* name)
case ELEMENT_REAL:
{
F64 r;
if ( sscanf(mCurrentContent.c_str(), "%lf", &r ) == 1 )
{ // See if sscanf works - it's faster
value = r;
}
else
{
value = LLSD(mCurrentContent).asReal();
}
value = LLSD(mCurrentContent).asReal();
// removed since this breaks when locale has decimal separator that isn't '.'
// investigated changing local to something compatible each time but deemed higher
// risk that just using LLSD.asReal() each time.
//F64 r;
//if ( sscanf(mCurrentContent.c_str(), "%lf", &r ) == 1 )
//{ // See if sscanf works - it's faster
// value = r;
//}
//else
//{
// value = LLSD(mCurrentContent).asReal();
//}
}
break;
@@ -777,10 +783,17 @@ void LLSDXMLParser::Impl::endElementHandler(const XML_Char* name)
case ELEMENT_BINARY:
{
S32 len = apr_base64_decode_len(mCurrentContent.c_str());
// Regex is expensive, but only fix for whitespace in base64,
// created by python and other non-linden systems - DEV-39358
// Fortunately we have very little binary passing now,
// so performance impact shold be negligible. + poppy 2009-09-04
boost::regex r;
r.assign("\\s");
std::string stripped = boost::regex_replace(mCurrentContent, r, "");
S32 len = apr_base64_decode_len(stripped.c_str());
std::vector<U8> data;
data.resize(len);
len = apr_base64_decode_binary(&data[0], mCurrentContent.c_str());
len = apr_base64_decode_binary(&data[0], stripped.c_str());
data.resize(len);
value = data;
break;

View File

@@ -46,6 +46,12 @@
#endif
#include "llsdserialize.h"
#include "stringize.h"
#include "is_approx_equal_fraction.h"
#include <map>
#include <set>
#include <boost/range.hpp>
// U32
LLSD ll_sd_from_U32(const U32 val)
@@ -171,6 +177,15 @@ char* ll_print_sd(const LLSD& sd)
return buffer;
}
char* ll_pretty_print_sd_ptr(const LLSD* sd)
{
if (sd)
{
return ll_pretty_print_sd(*sd);
}
return NULL;
}
char* ll_pretty_print_sd(const LLSD& sd)
{
const U32 bufferSize = 10 * 1024;
@@ -304,3 +319,363 @@ BOOL compare_llsd_with_template(
return TRUE;
}
/*****************************************************************************
* Helpers for llsd_matches()
*****************************************************************************/
// raw data used for LLSD::Type lookup
struct Data
{
LLSD::Type type;
const char* name;
} typedata[] =
{
#define def(type) { LLSD::type, #type + 4 }
def(TypeUndefined),
def(TypeBoolean),
def(TypeInteger),
def(TypeReal),
def(TypeString),
def(TypeUUID),
def(TypeDate),
def(TypeURI),
def(TypeBinary),
def(TypeMap),
def(TypeArray)
#undef def
};
// LLSD::Type lookup class into which we load the above static data
class TypeLookup
{
typedef std::map<LLSD::Type, std::string> MapType;
public:
TypeLookup()
{
for (const Data *di(boost::begin(typedata)), *dend(boost::end(typedata)); di != dend; ++di)
{
mMap[di->type] = di->name;
}
}
std::string lookup(LLSD::Type type) const
{
MapType::const_iterator found = mMap.find(type);
if (found != mMap.end())
{
return found->second;
}
return STRINGIZE("<unknown LLSD type " << type << ">");
}
private:
MapType mMap;
};
// static instance of the lookup class
static const TypeLookup sTypes;
// describe a mismatch; phrasing may want tweaking
const std::string op(" required instead of ");
// llsd_matches() wants to identify specifically where in a complex prototype
// structure the mismatch occurred. This entails passing a prefix string,
// empty for the top-level call. If the prototype contains an array of maps,
// and the mismatch occurs in the second map in a key 'foo', we want to
// decorate the returned string with: "[1]['foo']: etc." On the other hand, we
// want to omit the entire prefix -- including colon -- if the mismatch is at
// top level. This helper accepts the (possibly empty) recursively-accumulated
// prefix string, returning either empty or the original string with colon
// appended.
static std::string colon(const std::string& pfx)
{
if (pfx.empty())
return pfx;
return pfx + ": ";
}
// param type for match_types
typedef std::vector<LLSD::Type> TypeVector;
// The scalar cases in llsd_matches() use this helper. In most cases, we can
// accept not only the exact type specified in the prototype, but also other
// types convertible to the expected type. That implies looping over an array
// of such types. If the actual type doesn't match any of them, we want to
// provide a list of acceptable conversions as well as the exact type, e.g.:
// "Integer (or Boolean, Real, String) required instead of UUID". Both the
// implementation and the calling logic are simplified by separating out the
// expected type from the convertible types.
static std::string match_types(LLSD::Type expect, // prototype.type()
const TypeVector& accept, // types convertible to that type
LLSD::Type actual, // type we're checking
const std::string& pfx) // as for llsd_matches
{
// Trivial case: if the actual type is exactly what we expect, we're good.
if (actual == expect)
return "";
// For the rest of the logic, build up a suitable error string as we go so
// we only have to make a single pass over the list of acceptable types.
// If we detect success along the way, we'll simply discard the partial
// error string.
std::ostringstream out;
out << colon(pfx) << sTypes.lookup(expect);
// If there are any convertible types, append that list.
if (! accept.empty())
{
out << " (";
const char* sep = "or ";
for (TypeVector::const_iterator ai(accept.begin()), aend(accept.end());
ai != aend; ++ai, sep = ", ")
{
// Don't forget to return success if we match any of those types...
if (actual == *ai)
return "";
out << sep << sTypes.lookup(*ai);
}
out << ')';
}
// If we got this far, it's because 'actual' was not one of the acceptable
// types, so we must return an error. 'out' already contains colon(pfx)
// and the formatted list of acceptable types, so just append the mismatch
// phrase and the actual type.
out << op << sTypes.lookup(actual);
return out.str();
}
// see docstring in .h file
std::string llsd_matches(const LLSD& prototype, const LLSD& data, const std::string& pfx)
{
// An undefined prototype means that any data is valid.
// An undefined slot in an array or map prototype means that any data
// may fill that slot.
if (prototype.isUndefined())
return "";
// A prototype array must match a data array with at least as many
// entries. Moreover, every prototype entry must match the
// corresponding data entry.
if (prototype.isArray())
{
if (! data.isArray())
{
return STRINGIZE(colon(pfx) << "Array" << op << sTypes.lookup(data.type()));
}
if (data.size() < prototype.size())
{
return STRINGIZE(colon(pfx) << "Array size " << prototype.size() << op
<< "Array size " << data.size());
}
for (LLSD::Integer i = 0; i < prototype.size(); ++i)
{
std::string match(llsd_matches(prototype[i], data[i], STRINGIZE('[' << i << ']')));
if (! match.empty())
{
return match;
}
}
return "";
}
// A prototype map must match a data map. Every key in the prototype
// must have a corresponding key in the data map; every value in the
// prototype must match the corresponding key's value in the data.
if (prototype.isMap())
{
if (! data.isMap())
{
return STRINGIZE(colon(pfx) << "Map" << op << sTypes.lookup(data.type()));
}
// If there are a number of keys missing from the data, it would be
// frustrating to a coder to discover them one at a time, with a big
// build each time. Enumerate all missing keys.
std::ostringstream out;
out << colon(pfx);
const char* init = "Map missing keys: ";
const char* sep = init;
for (LLSD::map_const_iterator mi = prototype.beginMap(); mi != prototype.endMap(); ++mi)
{
if (! data.has(mi->first))
{
out << sep << mi->first;
sep = ", ";
}
}
// So... are we missing any keys?
if (sep != init)
{
return out.str();
}
// Good, the data block contains all the keys required by the
// prototype. Now match the prototype entries.
for (LLSD::map_const_iterator mi2 = prototype.beginMap(); mi2 != prototype.endMap(); ++mi2)
{
std::string match(llsd_matches(mi2->second, data[mi2->first],
STRINGIZE("['" << mi2->first << "']")));
if (! match.empty())
{
return match;
}
}
return "";
}
// A String prototype can match String, Boolean, Integer, Real, UUID,
// Date and URI, because any of these can be converted to String.
if (prototype.isString())
{
static LLSD::Type accept[] =
{
LLSD::TypeBoolean,
LLSD::TypeInteger,
LLSD::TypeReal,
LLSD::TypeUUID,
LLSD::TypeDate,
LLSD::TypeURI
};
return match_types(prototype.type(),
TypeVector(boost::begin(accept), boost::end(accept)),
data.type(),
pfx);
}
// Boolean, Integer, Real match each other or String. TBD: ensure that
// a String value is numeric.
if (prototype.isBoolean() || prototype.isInteger() || prototype.isReal())
{
static LLSD::Type all[] =
{
LLSD::TypeBoolean,
LLSD::TypeInteger,
LLSD::TypeReal,
LLSD::TypeString
};
// Funny business: shuffle the set of acceptable types to include all
// but the prototype's type. Get the acceptable types in a set.
std::set<LLSD::Type> rest(boost::begin(all), boost::end(all));
// Remove the prototype's type because we pass that separately.
rest.erase(prototype.type());
return match_types(prototype.type(),
TypeVector(rest.begin(), rest.end()),
data.type(),
pfx);
}
// UUID, Date and URI match themselves or String.
if (prototype.isUUID() || prototype.isDate() || prototype.isURI())
{
static LLSD::Type accept[] =
{
LLSD::TypeString
};
return match_types(prototype.type(),
TypeVector(boost::begin(accept), boost::end(accept)),
data.type(),
pfx);
}
// We don't yet know the conversion semantics associated with any new LLSD
// data type that might be added, so until we've been extended to handle
// them, assume it's strict: the new type matches only itself. (This is
// true of Binary, which is why we don't handle that case separately.) Too
// bad LLSD doesn't define isConvertible(Type to, Type from).
return match_types(prototype.type(), TypeVector(), data.type(), pfx);
}
bool llsd_equals(const LLSD& lhs, const LLSD& rhs, unsigned bits)
{
// We're comparing strict equality of LLSD representation rather than
// performing any conversions. So if the types aren't equal, the LLSD
// values aren't equal.
if (lhs.type() != rhs.type())
{
return false;
}
// Here we know both types are equal. Now compare values.
switch (lhs.type())
{
case LLSD::TypeUndefined:
// Both are TypeUndefined. There's nothing more to know.
return true;
case LLSD::TypeReal:
// This is where the 'bits' argument comes in handy. If passed
// explicitly, it means to use is_approx_equal_fraction() to compare.
if (bits >= 0)
{
return is_approx_equal_fraction(lhs.asReal(), rhs.asReal(), bits);
}
// Otherwise we compare bit representations, and the usual caveats
// about comparing floating-point numbers apply. Omitting 'bits' when
// comparing Real values is only useful when we expect identical bit
// representation for a given Real value, e.g. for integer-valued
// Reals.
return (lhs.asReal() == rhs.asReal());
#define COMPARE_SCALAR(type) \
case LLSD::Type##type: \
/* LLSD::URI has operator!=() but not operator==() */ \
/* rely on the optimizer for all others */ \
return (! (lhs.as##type() != rhs.as##type()))
COMPARE_SCALAR(Boolean);
COMPARE_SCALAR(Integer);
COMPARE_SCALAR(String);
COMPARE_SCALAR(UUID);
COMPARE_SCALAR(Date);
COMPARE_SCALAR(URI);
COMPARE_SCALAR(Binary);
#undef COMPARE_SCALAR
case LLSD::TypeArray:
{
LLSD::array_const_iterator
lai(lhs.beginArray()), laend(lhs.endArray()),
rai(rhs.beginArray()), raend(rhs.endArray());
// Compare array elements, walking the two arrays in parallel.
for ( ; lai != laend && rai != raend; ++lai, ++rai)
{
// If any one array element is unequal, the arrays are unequal.
if (! llsd_equals(*lai, *rai, bits))
return false;
}
// Here we've reached the end of one or the other array. They're equal
// only if they're BOTH at end: that is, if they have equal length too.
return (lai == laend && rai == raend);
}
case LLSD::TypeMap:
{
// Build a set of all rhs keys.
std::set<LLSD::String> rhskeys;
for (LLSD::map_const_iterator rmi(rhs.beginMap()), rmend(rhs.endMap());
rmi != rmend; ++rmi)
{
rhskeys.insert(rmi->first);
}
// Now walk all the lhs keys.
for (LLSD::map_const_iterator lmi(lhs.beginMap()), lmend(lhs.endMap());
lmi != lmend; ++lmi)
{
// Try to erase this lhs key from the set of rhs keys. If rhs has
// no such key, the maps are unequal. erase(key) returns count of
// items erased.
if (rhskeys.erase(lmi->first) != 1)
return false;
// Both maps have the current key. Compare values.
if (! llsd_equals(lmi->second, rhs[lmi->first], bits))
return false;
}
// We've now established that all the lhs keys have equal values in
// both maps. The maps are equal unless rhs contains a superset of
// those keys.
return rhskeys.empty();
}
default:
// We expect that every possible type() value is specifically handled
// above. Failing to extend this switch to support a new LLSD type is
// an error that must be brought to the coder's attention.
LL_ERRS("llsd_equals") << "llsd_equals(" << lhs << ", " << rhs << ", " << bits << "): "
"unknown type " << lhs.type() << LL_ENDL;
return false; // pacify the compiler
}
}

View File

@@ -35,7 +35,7 @@
#ifndef LL_LLSDUTIL_H
#define LL_LLSDUTIL_H
#include "llsd.h"
class LLSD;
// U32
LL_COMMON_API LLSD ll_sd_from_U32(const U32);
@@ -59,6 +59,7 @@ LL_COMMON_API LLSD ll_binary_from_string(const LLSD& sd);
LL_COMMON_API char* ll_print_sd(const LLSD& sd);
// Serializes sd to static buffer and returns pointer, using "pretty printing" mode.
LL_COMMON_API char* ll_pretty_print_sd_ptr(const LLSD* sd);
LL_COMMON_API char* ll_pretty_print_sd(const LLSD& sd);
//compares the structure of an LLSD to a template LLSD and stores the
@@ -73,6 +74,66 @@ LL_COMMON_API BOOL compare_llsd_with_template(
const LLSD& template_llsd,
LLSD& resultant_llsd);
/**
* Recursively determine whether a given LLSD data block "matches" another
* LLSD prototype. The returned string is empty() on success, non-empty() on
* mismatch.
*
* This function tests structure (types) rather than data values. It is
* intended for when a consumer expects an LLSD block with a particular
* structure, and must succinctly detect whether the arriving block is
* well-formed. For instance, a test of the form:
* @code
* if (! (data.has("request") && data.has("target") && data.has("modifier") ...))
* @endcode
* could instead be expressed by initializing a prototype LLSD map with the
* required keys and writing:
* @code
* if (! llsd_matches(prototype, data).empty())
* @endcode
*
* A non-empty return value is an error-message fragment intended to indicate
* to (English-speaking) developers where in the prototype structure the
* mismatch occurred.
*
* * If a slot in the prototype isUndefined(), then anything is valid at that
* place in the real object. (Passing prototype == LLSD() matches anything
* at all.)
* * An array in the prototype must match a data array at least that large.
* (Additional entries in the data array are ignored.) Every isDefined()
* entry in the prototype array must match the corresponding entry in the
* data array.
* * A map in the prototype must match a map in the data. Every key in the
* prototype map must match a corresponding key in the data map. (Additional
* keys in the data map are ignored.) Every isDefined() value in the
* prototype map must match the corresponding key's value in the data map.
* * Scalar values in the prototype are tested for @em type rather than value.
* For instance, a String in the prototype matches any String at all. In
* effect, storing an Integer at a particular place in the prototype asserts
* that the caller intends to apply asInteger() to the corresponding slot in
* the data.
* * A String in the prototype matches String, Boolean, Integer, Real, UUID,
* Date and URI, because asString() applied to any of these produces a
* meaningful result.
* * Similarly, a Boolean, Integer or Real in the prototype can match any of
* Boolean, Integer or Real in the data -- or even String.
* * UUID matches UUID or String.
* * Date matches Date or String.
* * URI matches URI or String.
* * Binary in the prototype matches only Binary in the data.
*
* @TODO: when a Boolean, Integer or Real in the prototype matches a String in
* the data, we should examine the String @em value to ensure it can be
* meaningfully converted to the requested type. The same goes for UUID, Date
* and URI.
*/
LL_COMMON_API std::string llsd_matches(const LLSD& prototype, const LLSD& data, const std::string& pfx="");
/// Deep equality. If you want to compare LLSD::Real values for approximate
/// equality rather than bitwise equality, pass @a bits as for
/// is_approx_equal_fraction().
LL_COMMON_API bool llsd_equals(const LLSD& lhs, const LLSD& rhs, unsigned bits=-1);
// Simple function to copy data out of input & output iterators if
// there is no need for casting.
template<typename Input> LLSD llsd_copy_array(Input iter, Input end)
@@ -85,4 +146,283 @@ template<typename Input> LLSD llsd_copy_array(Input iter, Input end)
return dest;
}
/*****************************************************************************
* LLSDArray
*****************************************************************************/
/**
* Construct an LLSD::Array inline, with implicit conversion to LLSD. Usage:
*
* @code
* void somefunc(const LLSD&);
* ...
* somefunc(LLSDArray("text")(17)(3.14));
* @endcode
*
* For completeness, LLSDArray() with no args constructs an empty array, so
* <tt>LLSDArray()("text")(17)(3.14)</tt> produces an array equivalent to the
* above. But for most purposes, LLSD() is already equivalent to an empty
* array, and if you explicitly want an empty isArray(), there's
* LLSD::emptyArray(). However, supporting a no-args LLSDArray() constructor
* follows the principle of least astonishment.
*/
class LLSDArray
{
public:
LLSDArray():
_data(LLSD::emptyArray())
{}
/**
* Need an explicit copy constructor. Consider the following:
*
* @code
* LLSD array_of_arrays(LLSDArray(LLSDArray(17)(34))
* (LLSDArray("x")("y")));
* @endcode
*
* The coder intends to construct [[17, 34], ["x", "y"]].
*
* With the compiler's implicit copy constructor, s/he gets instead
* [17, 34, ["x", "y"]].
*
* The expression LLSDArray(17)(34) constructs an LLSDArray with those two
* values. The reader assumes it should be converted to LLSD, as we always
* want with LLSDArray, before passing it to the @em outer LLSDArray
* constructor! This copy constructor makes that happen.
*/
LLSDArray(const LLSDArray& inner):
_data(LLSD::emptyArray())
{
_data.append(inner);
}
LLSDArray(const LLSD& value):
_data(LLSD::emptyArray())
{
_data.append(value);
}
LLSDArray& operator()(const LLSD& value)
{
_data.append(value);
return *this;
}
operator LLSD() const { return _data; }
LLSD get() const { return _data; }
private:
LLSD _data;
};
/*****************************************************************************
* LLSDMap
*****************************************************************************/
/**
* Construct an LLSD::Map inline, with implicit conversion to LLSD. Usage:
*
* @code
* void somefunc(const LLSD&);
* ...
* somefunc(LLSDMap("alpha", "abc")("number", 17)("pi", 3.14));
* @endcode
*
* For completeness, LLSDMap() with no args constructs an empty map, so
* <tt>LLSDMap()("alpha", "abc")("number", 17)("pi", 3.14)</tt> produces a map
* equivalent to the above. But for most purposes, LLSD() is already
* equivalent to an empty map, and if you explicitly want an empty isMap(),
* there's LLSD::emptyMap(). However, supporting a no-args LLSDMap()
* constructor follows the principle of least astonishment.
*/
class LLSDMap
{
public:
LLSDMap():
_data(LLSD::emptyMap())
{}
LLSDMap(const LLSD::String& key, const LLSD& value):
_data(LLSD::emptyMap())
{
_data[key] = value;
}
LLSDMap& operator()(const LLSD::String& key, const LLSD& value)
{
_data[key] = value;
return *this;
}
operator LLSD() const { return _data; }
LLSD get() const { return _data; }
private:
LLSD _data;
};
/*****************************************************************************
* LLSDParam
*****************************************************************************/
/**
* LLSDParam is a customization point for passing LLSD values to function
* parameters of more or less arbitrary type. LLSD provides a small set of
* native conversions; but if a generic algorithm explicitly constructs an
* LLSDParam object in the function's argument list, a consumer can provide
* LLSDParam specializations to support more different parameter types than
* LLSD's native conversions.
*
* Usage:
*
* @code
* void somefunc(const paramtype&);
* ...
* somefunc(..., LLSDParam<paramtype>(someLLSD), ...);
* @endcode
*/
template <typename T>
class LLSDParam
{
public:
/**
* Default implementation converts to T on construction, saves converted
* value for later retrieval
*/
LLSDParam(const LLSD& value):
_value(value)
{}
operator T() const { return _value; }
private:
T _value;
};
/**
* Turns out that several target types could accept an LLSD param using any of
* a few different conversions, e.g. LLUUID's constructor can accept LLUUID or
* std::string. Therefore, the compiler can't decide which LLSD conversion
* operator to choose, even though to us it seems obvious. But that's okay, we
* can specialize LLSDParam for such target types, explicitly specifying the
* desired conversion -- that's part of what LLSDParam is all about. Turns out
* we have to do that enough to make it worthwhile generalizing. Use a macro
* because I need to specify one of the asReal, etc., explicit conversion
* methods as well as a type. If I'm overlooking a clever way to implement
* that using a template instead, feel free to reimplement.
*/
#define LLSDParam_for(T, AS) \
template <> \
class LLSDParam<T> \
{ \
public: \
LLSDParam(const LLSD& value): \
_value(value.AS()) \
{} \
\
operator T() const { return _value; } \
\
private: \
T _value; \
}
LLSDParam_for(float, asReal);
LLSDParam_for(LLUUID, asUUID);
LLSDParam_for(LLDate, asDate);
LLSDParam_for(LLURI, asURI);
LLSDParam_for(LLSD::Binary, asBinary);
/**
* LLSDParam<const char*> is an example of the kind of conversion you can
* support with LLSDParam beyond native LLSD conversions. Normally you can't
* pass an LLSD object to a function accepting const char* -- but you can
* safely pass an LLSDParam<const char*>(yourLLSD).
*/
template <>
class LLSDParam<const char*>
{
private:
// The difference here is that we store a std::string rather than a const
// char*. It's important that the LLSDParam object own the std::string.
std::string _value;
// We don't bother storing the incoming LLSD object, but we do have to
// distinguish whether _value is an empty string because the LLSD object
// contains an empty string or because it's isUndefined().
bool _undefined;
public:
LLSDParam(const LLSD& value):
_value(value),
_undefined(value.isUndefined())
{}
// The const char* we retrieve is for storage owned by our _value member.
// That's how we guarantee that the const char* is valid for the lifetime
// of this LLSDParam object. Constructing your LLSDParam in the argument
// list should ensure that the LLSDParam object will persist for the
// duration of the function call.
operator const char*() const
{
if (_undefined)
{
// By default, an isUndefined() LLSD object's asString() method
// will produce an empty string. But for a function accepting
// const char*, it's often important to be able to pass NULL, and
// isUndefined() seems like the best way. If you want to pass an
// empty string, you can still pass LLSD(""). Without this special
// case, though, no LLSD value could pass NULL.
return NULL;
}
return _value.c_str();
}
};
namespace llsd
{
/*****************************************************************************
* BOOST_FOREACH() helpers for LLSD
*****************************************************************************/
/// Usage: BOOST_FOREACH(LLSD item, inArray(someLLSDarray)) { ... }
class inArray
{
public:
inArray(const LLSD& array):
_array(array)
{}
typedef LLSD::array_const_iterator const_iterator;
typedef LLSD::array_iterator iterator;
iterator begin() { return _array.beginArray(); }
iterator end() { return _array.endArray(); }
const_iterator begin() const { return _array.beginArray(); }
const_iterator end() const { return _array.endArray(); }
private:
LLSD _array;
};
/// MapEntry is what you get from dereferencing an LLSD::map_[const_]iterator.
typedef std::map<LLSD::String, LLSD>::value_type MapEntry;
/// Usage: BOOST_FOREACH([const] MapEntry& e, inMap(someLLSDmap)) { ... }
class inMap
{
public:
inMap(const LLSD& map):
_map(map)
{}
typedef LLSD::map_const_iterator const_iterator;
typedef LLSD::map_iterator iterator;
iterator begin() { return _map.beginMap(); }
iterator end() { return _map.endMap(); }
const_iterator begin() const { return _map.beginMap(); }
const_iterator end() const { return _map.endMap(); }
private:
LLSD _map;
};
} // namespace llsd
#endif // LL_LLSDUTIL_H

View File

@@ -100,12 +100,6 @@ private:
DELETED
} EInitState;
static void deleteSingleton()
{
delete getData().mSingletonInstance;
getData().mSingletonInstance = NULL;
}
// stores pointer to singleton instance
// and tracks initialization state of singleton
struct SingletonInstanceData
@@ -120,7 +114,11 @@ private:
~SingletonInstanceData()
{
deleteSingleton();
SingletonInstanceData& data = getData();
if (data.mInitState != DELETED)
{
deleteSingleton();
}
}
};
@@ -132,6 +130,14 @@ public:
data.mInitState = DELETED;
}
// Can be used to control when the singleton is deleted. Not normally needed.
static void deleteSingleton()
{
delete getData().mSingletonInstance;
getData().mSingletonInstance = NULL;
getData().mInitState = DELETED;
}
static SingletonInstanceData& getData()
{
// this is static to cache the lookup results

View File

@@ -43,9 +43,10 @@
// statics
BOOL LLPerfBlock::sStatsEnabled = FALSE; // Flag for detailed information
S32 LLPerfBlock::sStatsFlags = LLPerfBlock::LLSTATS_NO_OPTIONAL_STATS; // Control what is being recorded
LLPerfBlock::stat_map_t LLPerfBlock::sStatMap; // Map full path string to LLStatTime objects, tracks all active objects
std::string LLPerfBlock::sCurrentStatPath = ""; // Something like "/total_time/physics/physics step"
LLStat::stat_map_t LLStat::sStatList;
//------------------------------------------------------------------------
// Live config file to trigger stats logging
@@ -129,6 +130,7 @@ bool LLStatsConfigFile::loadFile()
F32 duration = 0.f;
F32 interval = 0.f;
S32 flags = LLPerfBlock::LLSTATS_BASIC_STATS;
const char * w = "duration";
if (stats_config.has(w))
@@ -140,8 +142,18 @@ bool LLStatsConfigFile::loadFile()
{
interval = (F32)stats_config[w].asReal();
}
w = "flags";
if (stats_config.has(w))
{
flags = (S32)stats_config[w].asInteger();
if (flags == LLPerfBlock::LLSTATS_NO_OPTIONAL_STATS &&
duration > 0)
{ // No flags passed in, but have a duration, so reset to basic stats
flags = LLPerfBlock::LLSTATS_BASIC_STATS;
}
}
mStatsp->setReportPerformanceDuration( duration );
mStatsp->setReportPerformanceDuration( duration, flags );
mStatsp->setReportPerformanceInterval( interval );
if ( duration > 0 )
@@ -253,13 +265,14 @@ void LLPerfStats::dumpIntervalPerformanceStats()
}
}
// Set length of performance stat recording
void LLPerfStats::setReportPerformanceDuration( F32 seconds )
// Set length of performance stat recording.
// If turning stats on, caller must provide flags
void LLPerfStats::setReportPerformanceDuration( F32 seconds, S32 flags /* = LLSTATS_NO_OPTIONAL_STATS */ )
{
if ( seconds <= 0.f )
{
mReportPerformanceStatEnd = 0.0;
LLPerfBlock::setStatsEnabled( FALSE );
LLPerfBlock::setStatsFlags(LLPerfBlock::LLSTATS_NO_OPTIONAL_STATS); // Make sure all recording is off
mFrameStatsFile.close();
LLPerfBlock::clearDynamicStats();
}
@@ -268,8 +281,8 @@ void LLPerfStats::setReportPerformanceDuration( F32 seconds )
mReportPerformanceStatEnd = LLFrameTimer::getElapsedSeconds() + ((F64) seconds);
// Clear failure flag to try and create the log file once
mFrameStatsFileFailure = FALSE;
LLPerfBlock::setStatsEnabled( TRUE );
mSkipFirstFrameStats = TRUE; // Skip the first report (at the end of this frame)
LLPerfBlock::setStatsFlags(flags);
}
}
@@ -611,11 +624,26 @@ LLPerfBlock::LLPerfBlock(LLStatTime* stat ) : mPredefinedStat(stat), mDynamicSta
}
}
// Use this constructor for dynamically created LLStatTime objects (not pre-defined) with a multi-part key.
// These are also turned on or off via the switch passed in
LLPerfBlock::LLPerfBlock( const char* key1, const char* key2 ) : mPredefinedStat(NULL), mDynamicStat(NULL)
// Use this constructor for normal, optional LLPerfBlock time slices
LLPerfBlock::LLPerfBlock( const char* key ) : mPredefinedStat(NULL), mDynamicStat(NULL)
{
if (!sStatsEnabled) return;
if ((sStatsFlags & LLSTATS_BASIC_STATS) == 0)
{ // These are off unless the base set is enabled
return;
}
initDynamicStat(key);
}
// Use this constructor for dynamically created LLPerfBlock time slices
// that are only enabled by specific control flags
LLPerfBlock::LLPerfBlock( const char* key1, const char* key2, S32 flags ) : mPredefinedStat(NULL), mDynamicStat(NULL)
{
if ((sStatsFlags & flags) == 0)
{
return;
}
if (NULL == key2 || strlen(key2) == 0)
{
@@ -629,10 +657,12 @@ LLPerfBlock::LLPerfBlock( const char* key1, const char* key2 ) : mPredefinedStat
}
}
// Set up the result data map if dynamic stats are enabled
void LLPerfBlock::initDynamicStat(const std::string& key)
{
// Early exit if dynamic stats aren't enabled.
if (!sStatsEnabled) return;
if (sStatsFlags == LLSTATS_NO_OPTIONAL_STATS)
return;
mLastPath = sCurrentStatPath; // Save and restore current path
sCurrentStatPath += "/" + key; // Add key to current path
@@ -713,7 +743,7 @@ void LLPerfBlock::addStatsToLLSDandReset( LLSD & stats,
}
}
else
{ // WTF? Shouldn't have a NULL pointer in the map.
{ // Shouldn't have a NULL pointer in the map.
llwarns << "Unexpected NULL dynamic stat at '" << stats_full_path << "'" << llendl;
}
}
@@ -725,14 +755,12 @@ void LLPerfBlock::addStatsToLLSDandReset( LLSD & stats,
LLTimer LLStat::sTimer;
LLFrameTimer LLStat::sFrameTimer;
LLStat::LLStat(const U32 num_bins, const BOOL use_frame_timer)
void LLStat::init()
{
llassert(num_bins > 0);
mUseFrameTimer = use_frame_timer;
llassert(mNumBins > 0);
mNumValues = 0;
mLastValue = 0.f;
mLastTime = 0.f;
mNumBins = num_bins;
mCurBin = (mNumBins-1);
mNextBin = 0;
mBins = new F32[mNumBins];
@@ -746,6 +774,29 @@ LLStat::LLStat(const U32 num_bins, const BOOL use_frame_timer)
mTime[i] = 0.0;
mDT[i] = 0.f;
}
if (!mName.empty())
{
stat_map_t::iterator iter = sStatList.find(mName);
if (iter != sStatList.end())
llwarns << "LLStat with duplicate name: " << mName << llendl;
sStatList.insert(std::make_pair(mName, this));
}
}
LLStat::LLStat(const U32 num_bins, const BOOL use_frame_timer)
: mUseFrameTimer(use_frame_timer),
mNumBins(num_bins)
{
init();
}
LLStat::LLStat(std::string name, U32 num_bins, BOOL use_frame_timer)
: mUseFrameTimer(use_frame_timer),
mNumBins(num_bins),
mName(name)
{
init();
}
LLStat::~LLStat()
@@ -754,6 +805,15 @@ LLStat::~LLStat()
delete[] mBeginTime;
delete[] mTime;
delete[] mDT;
if (!mName.empty())
{
// handle multiple entries with the same name
stat_map_t::iterator iter = sStatList.find(mName);
while (iter != sStatList.end() && iter->second != this)
++iter;
sStatList.erase(iter);
}
}
void LLStat::reset()

View File

@@ -192,14 +192,23 @@ public:
// Use this constructor for pre-defined LLStatTime objects
LLPerfBlock(LLStatTime* stat);
// Use this constructor for dynamically created LLStatTime objects (not pre-defined) with a multi-part key
LLPerfBlock( const char* key1, const char* key2 = NULL);
// Use this constructor for normal, optional LLPerfBlock time slices
LLPerfBlock( const char* key );
// Use this constructor for dynamically created LLPerfBlock time slices
// that are only enabled by specific control flags
LLPerfBlock( const char* key1, const char* key2, S32 flags = LLSTATS_BASIC_STATS );
~LLPerfBlock();
static void setStatsEnabled( BOOL enable ) { sStatsEnabled = enable; };
static S32 getStatsEnabled() { return sStatsEnabled; };
enum
{ // Stats bitfield flags
LLSTATS_NO_OPTIONAL_STATS = 0x00, // No optional stats gathering, just pre-defined LLStatTime objects
LLSTATS_BASIC_STATS = 0x01, // Gather basic optional runtime stats
LLSTATS_SCRIPT_FUNCTIONS = 0x02, // Include LSL function calls
};
static void setStatsFlags( S32 flags ) { sStatsFlags = flags; };
static S32 getStatsFlags() { return sStatsFlags; };
static void clearDynamicStats(); // Reset maps to clear out dynamic objects
static void addStatsToLLSDandReset( LLSD & stats, // Get current information and clear time bin
@@ -213,7 +222,7 @@ private:
LLStatTime * mPredefinedStat; // LLStatTime object to get data
StatEntry * mDynamicStat; // StatEntryobject to get data
static BOOL sStatsEnabled; // Normally FALSE
static S32 sStatsFlags; // Control what is being recorded
static stat_map_t sStatMap; // Map full path string to LLStatTime objects
static std::string sCurrentStatPath; // Something like "frame/physics/physics step"
};
@@ -236,7 +245,7 @@ public:
BOOL frameStatsIsRunning() { return (mReportPerformanceStatEnd > 0.); };
F32 getReportPerformanceInterval() const { return mReportPerformanceStatInterval; };
void setReportPerformanceInterval( F32 interval ) { mReportPerformanceStatInterval = interval; };
void setReportPerformanceDuration( F32 seconds );
void setReportPerformanceDuration( F32 seconds, S32 flags = LLPerfBlock::LLSTATS_NO_OPTIONAL_STATS );
void setProcessName(const std::string& process_name) { mProcessName = process_name; }
void setProcessPID(S32 process_pid) { mProcessPID = process_pid; }
@@ -258,8 +267,15 @@ private:
// ----------------------------------------------------------------------------
class LL_COMMON_API LLStat
{
private:
typedef std::multimap<std::string, LLStat*> stat_map_t;
static stat_map_t sStatList;
void init();
public:
LLStat(const U32 num_bins = 32, BOOL use_frame_timer = FALSE);
LLStat(U32 num_bins = 32, BOOL use_frame_timer = FALSE);
LLStat(std::string name, U32 num_bins = 32, BOOL use_frame_timer = FALSE);
~LLStat();
void reset();
@@ -322,8 +338,22 @@ private:
F32 *mDT;
S32 mCurBin;
S32 mNextBin;
std::string mName;
static LLTimer sTimer;
static LLFrameTimer sFrameTimer;
public:
static LLStat* getStat(const std::string& name)
{
// return the first stat that matches 'name'
stat_map_t::iterator iter = sStatList.find(name);
if (iter != sStatList.end())
return iter->second;
else
return NULL;
}
};
#endif // LL_STAT_

View File

@@ -45,7 +45,7 @@
// skips spaces and tabs
bool skip_whitespace(std::istream& input_stream)
{
char c = input_stream.peek();
int c = input_stream.peek();
while (('\t' == c || ' ' == c) && input_stream.good())
{
input_stream.get();
@@ -57,7 +57,7 @@ bool skip_whitespace(std::istream& input_stream)
// skips whitespace, newlines, and carriage returns
bool skip_emptyspace(std::istream& input_stream)
{
char c = input_stream.peek();
int c = input_stream.peek();
while ( input_stream.good()
&& ('\t' == c || ' ' == c || '\n' == c || '\r' == c) )
{
@@ -72,7 +72,7 @@ bool skip_comments_and_emptyspace(std::istream& input_stream)
{
while (skip_emptyspace(input_stream))
{
char c = input_stream.peek();
int c = input_stream.peek();
if ('#' == c )
{
while ('\n' != c && input_stream.good())
@@ -90,7 +90,7 @@ bool skip_comments_and_emptyspace(std::istream& input_stream)
bool skip_line(std::istream& input_stream)
{
char c;
int c;
do
{
c = input_stream.get();
@@ -100,7 +100,7 @@ bool skip_line(std::istream& input_stream)
bool skip_to_next_word(std::istream& input_stream)
{
char c = input_stream.peek();
int c = input_stream.peek();
while ( input_stream.good()
&& ( (c >= 'a' && c <= 'z')
|| (c >= 'A' && c <= 'Z')
@@ -132,7 +132,7 @@ bool skip_to_end_of_next_keyword(const char* keyword, std::istream& input_stream
while (input_stream.good())
{
skip_emptyspace(input_stream);
char c = input_stream.get();
int c = input_stream.get();
if (keyword[0] != c)
{
skip_line(input_stream);
@@ -181,7 +181,7 @@ bool skip_to_start_of_next_keyword(const char* keyword, std::istream& input_stre
while (input_stream.good())
{
skip_emptyspace(input_stream);
char c = input_stream.get();
int c = input_stream.get();
if (keyword[0] != c)
{
skip_line(input_stream);
@@ -229,7 +229,7 @@ bool skip_to_start_of_next_keyword(const char* keyword, std::istream& input_stre
bool get_word(std::string& output_string, std::istream& input_stream)
{
skip_emptyspace(input_stream);
char c = input_stream.peek();
int c = input_stream.peek();
while ( !isspace(c)
&& '\n' != c
&& '\r' != c
@@ -246,7 +246,7 @@ bool get_word(std::string& output_string, std::istream& input_stream, int n)
{
skip_emptyspace(input_stream);
int char_count = 0;
char c = input_stream.peek();
int c = input_stream.peek();
while (!isspace(c)
&& '\n' != c
&& '\r' != c
@@ -265,7 +265,7 @@ bool get_word(std::string& output_string, std::istream& input_stream, int n)
bool get_line(std::string& output_string, std::istream& input_stream)
{
output_string.clear();
char c = input_stream.get();
int c = input_stream.get();
while (input_stream.good())
{
output_string += c;
@@ -285,7 +285,7 @@ bool get_line(std::string& output_string, std::istream& input_stream, int n)
{
output_string.clear();
int char_count = 0;
char c = input_stream.get();
int c = input_stream.get();
while (input_stream.good() && char_count < n)
{
char_count++;

View File

@@ -36,6 +36,8 @@
#include "u64.h"
#include "lldate.h"
#if LL_WINDOWS
# define WIN32_LEAN_AND_MEAN
# include <winsock2.h>

View File

@@ -39,8 +39,6 @@
#include <limits.h>
#include "stdtypes.h"
#include "llpreprocessor.h"
#include "lldate.h"
#include <string>
#include <list>
@@ -55,8 +53,6 @@ const U32 USEC_PER_HOUR = USEC_PER_MIN * MIN_PER_HOUR;
const U32 SEC_PER_HOUR = SEC_PER_MIN * MIN_PER_HOUR;
const F64 SEC_PER_USEC = 1.0 / (F64) USEC_PER_SEC;
LL_COMMON_API U64 totalTime(); // Returns current system time in microseconds
class LL_COMMON_API LLTimer
{
public:
@@ -175,4 +171,5 @@ LL_COMMON_API void secondsToTimecodeString(F32 current_time, std::string& tcstri
LL_COMMON_API void timeToFormattedString(time_t time, std::string format, std::string &timestr);
LL_COMMON_API void timeStructToFormattedString(struct tm * time, std::string format, std::string &timestr);
U64 LL_COMMON_API totalTime(); // Returns current system time in microseconds
#endif

View File

@@ -0,0 +1,705 @@
/**
* @file lltreeiterators.h
* @author Nat Goodspeed
* @date 2008-08-19
* @brief This file defines iterators useful for traversing arbitrary node
* classes, potentially polymorphic, linked into strict tree
* structures.
*
* Dereferencing any one of these iterators actually yields a @em
* pointer to the node in question. For example, given an
* LLLinkedIter<MyNode> <tt>li</tt>, <tt>*li</tt> gets you a pointer
* to MyNode, and <tt>**li</tt> gets you the MyNode instance itself.
* More commonly, instead of writing <tt>li->member</tt>, you write
* <tt>(*li)->member</tt> -- as you would if you were traversing an
* STL container of MyNode pointers.
*
* It would certainly be possible to build these iterators so that
* <tt>*iterator</tt> would return a reference to the node itself
* rather than a pointer to the node, and for many purposes it would
* even be more convenient. However, that would be insufficiently
* flexible. If you want to use an iterator range to (e.g.) initialize
* a std::vector collecting results -- you rarely want to actually @em
* copy the nodes in question. You're much more likely to want to copy
* <i>pointers to</i> the traversed nodes. Hence these iterators
* produce pointers.
*
* Though you specify the actual NODE class as the template parameter,
* these iterators internally use LLPtrTo<> to discover whether to
* store and return an LLPointer<NODE> or a simple NODE*.
*
* By strict tree structures, we mean that each child must have
* exactly one parent. This forbids a child claiming any ancestor as a
* child of its own. Child nodes with multiple parents will be visited
* once for each parent. Cycles in the graph will result in either an
* infinite loop or an out-of-memory crash. You Have Been Warned.
*
* $LicenseInfo:firstyear=2008&license=viewerlgpl$
* Second Life Viewer Source Code
* Copyright (C) 2010, Linden Research, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation;
* version 2.1 of the License only.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
* $/LicenseInfo$
*/
#if ! defined(LL_LLTREEITERATORS_H)
#define LL_LLTREEITERATORS_H
#include "llptrto.h"
#include <vector>
#include <deque>
#include <boost/iterator/iterator_facade.hpp>
#include <boost/function.hpp>
#include <boost/static_assert.hpp>
namespace LLTreeIter
{
/// Discriminator between LLTreeUpIter and LLTreeDownIter
enum RootIter { UP, DOWN };
/// Discriminator between LLTreeDFSIter, LLTreeDFSPostIter and LLTreeBFSIter
enum WalkIter { DFS_PRE, DFS_POST, BFS };
}
/**
* LLBaseIter defines some machinery common to all these iterators. We use
* boost::iterator_facade to define the iterator boilerplate: the conventional
* operators and methods necessary to implement a standards-conforming
* iterator. That allows us to specify the actual iterator semantics in terms
* of equal(), dereference() and increment() methods.
*/
template <class SELFTYPE, class NODE>
class LLBaseIter: public boost::iterator_facade<SELFTYPE,
// use pointer type as the
// reference type
typename LLPtrTo<NODE>::type,
boost::forward_traversal_tag>
{
protected:
/// LLPtrTo<NODE>::type is either NODE* or LLPointer<NODE>, as appropriate
typedef typename LLPtrTo<NODE>::type ptr_type;
/// function that advances from this node to next accepts a node pointer
/// and returns another
typedef boost::function<ptr_type(const ptr_type&)> func_type;
typedef SELFTYPE self_type;
};
/// Functor returning NULL, suitable for an end-iterator's 'next' functor
template <class NODE>
typename LLPtrTo<NODE>::type LLNullNextFunctor(const typename LLPtrTo<NODE>::type&)
{
return typename LLPtrTo<NODE>::type();
}
/**
* LLLinkedIter is an iterator over an intrusive singly-linked list. The
* beginning of the list is represented by LLLinkedIter(list head); the end is
* represented by LLLinkedIter().
*
* The begin LLLinkedIter must be instantiated with a functor to extract the
* 'next' pointer from the current node. Supposing that the link pointer is @c
* public, something like:
*
* @code
* NODE* mNext;
* @endcode
*
* you can use (e.g.) <tt>boost::bind(&NODE::mNext, _1)</tt> for the purpose.
* Alternatively, you can bind whatever accessor method is normally used to
* advance to the next node, e.g. for:
*
* @code
* NODE* next() const;
* @endcode
*
* you can use <tt>boost::bind(&NODE::next, _1)</tt>.
*/
template <class NODE>
class LLLinkedIter: public LLBaseIter<LLLinkedIter<NODE>, NODE>
{
typedef LLBaseIter<LLLinkedIter<NODE>, NODE> super;
protected:
/// some methods need to return a reference to self
typedef typename super::self_type self_type;
typedef typename super::ptr_type ptr_type;
typedef typename super::func_type func_type;
public:
/// Instantiate an LLLinkedIter to start a range, or to end a range before
/// a particular list entry. Pass a functor to extract the 'next' pointer
/// from the current node.
LLLinkedIter(const ptr_type& entry, const func_type& nextfunc):
mCurrent(entry),
mNextFunc(nextfunc)
{}
/// Instantiate an LLLinkedIter to end a range at the end of the list
LLLinkedIter():
mCurrent(),
mNextFunc(LLNullNextFunctor<NODE>)
{}
private:
/// leverage boost::iterator_facade
friend class boost::iterator_core_access;
/// advance
void increment()
{
mCurrent = mNextFunc(mCurrent);
}
/// equality
bool equal(const self_type& that) const { return this->mCurrent == that.mCurrent; }
/// dereference
ptr_type& dereference() const { return const_cast<ptr_type&>(mCurrent); }
ptr_type mCurrent;
func_type mNextFunc;
};
/**
* LLTreeUpIter walks from the node in hand to the root of the tree. The term
* "up" is applied to a tree visualized with the root at the top.
*
* LLTreeUpIter is an alias for LLLinkedIter, since any linked tree that you
* can navigate that way at all contains parent pointers.
*/
template <class NODE>
class LLTreeUpIter: public LLLinkedIter<NODE>
{
typedef LLLinkedIter<NODE> super;
public:
/// Instantiate an LLTreeUpIter to start from a particular tree node, or
/// to end a parent traversal before reaching a particular ancestor. Pass
/// a functor to extract the 'parent' pointer from the current node.
LLTreeUpIter(const typename super::ptr_type& node,
const typename super::func_type& parentfunc):
super(node, parentfunc)
{}
/// Instantiate an LLTreeUpIter to end a range at the root of the tree
LLTreeUpIter():
super()
{}
};
/**
* LLTreeDownIter walks from the root of the tree to the node in hand. The
* term "down" is applied to a tree visualized with the root at the top.
*
* Though you instantiate the begin() LLTreeDownIter with a pointer to some
* node at an arbitrary location in the tree, the root will be the first node
* you dereference and the passed node will be the last node you dereference.
*
* On construction, LLTreeDownIter walks from the current node to the root,
* capturing the path. Then in use, it replays that walk in reverse. As with
* all traversals of interesting data structures, it is actively dangerous to
* modify the tree during an LLTreeDownIter walk.
*/
template <class NODE>
class LLTreeDownIter: public LLBaseIter<LLTreeDownIter<NODE>, NODE>
{
typedef LLBaseIter<LLTreeDownIter<NODE>, NODE> super;
typedef typename super::self_type self_type;
protected:
typedef typename super::ptr_type ptr_type;
typedef typename super::func_type func_type;
private:
typedef std::vector<ptr_type> list_type;
public:
/// Instantiate an LLTreeDownIter to end at a particular tree node. Pass a
/// functor to extract the 'parent' pointer from the current node.
LLTreeDownIter(const ptr_type& node,
const func_type& parentfunc)
{
for (ptr_type n = node; n; n = parentfunc(n))
mParents.push_back(n);
}
/// Instantiate an LLTreeDownIter representing "here", the end of the loop
LLTreeDownIter() {}
private:
/// leverage boost::iterator_facade
friend class boost::iterator_core_access;
/// advance
void increment()
{
mParents.pop_back();
}
/// equality
bool equal(const self_type& that) const { return this->mParents == that.mParents; }
/// implement dereference/indirection operators
ptr_type& dereference() const { return const_cast<ptr_type&>(mParents.back()); }
list_type mParents;
};
/**
* When you want to select between LLTreeUpIter and LLTreeDownIter with a
* compile-time discriminator, use LLTreeRootIter with an LLTreeIter::RootIter
* template arg.
*/
template <LLTreeIter::RootIter DISCRIM, class NODE>
class LLTreeRootIter
{
enum { use_a_valid_LLTreeIter_RootIter_value = false };
public:
/// Bogus constructors for default (unrecognized discriminator) case
template <typename TYPE1, typename TYPE2>
LLTreeRootIter(TYPE1, TYPE2)
{
BOOST_STATIC_ASSERT(use_a_valid_LLTreeIter_RootIter_value);
}
LLTreeRootIter()
{
BOOST_STATIC_ASSERT(use_a_valid_LLTreeIter_RootIter_value);
}
};
/// Specialize for LLTreeIter::UP
template <class NODE>
class LLTreeRootIter<LLTreeIter::UP, NODE>: public LLTreeUpIter<NODE>
{
typedef LLTreeUpIter<NODE> super;
public:
/// forward begin ctor
LLTreeRootIter(const typename super::ptr_type& node,
const typename super::func_type& parentfunc):
super(node, parentfunc)
{}
/// forward end ctor
LLTreeRootIter():
super()
{}
};
/// Specialize for LLTreeIter::DOWN
template <class NODE>
class LLTreeRootIter<LLTreeIter::DOWN, NODE>: public LLTreeDownIter<NODE>
{
typedef LLTreeDownIter<NODE> super;
public:
/// forward begin ctor
LLTreeRootIter(const typename super::ptr_type& node,
const typename super::func_type& parentfunc):
super(node, parentfunc)
{}
/// forward end ctor
LLTreeRootIter():
super()
{}
};
/**
* Instantiated with a tree node, typically the root, LLTreeDFSIter "flattens"
* a depth-first tree walk through that node and all its descendants.
*
* The begin() LLTreeDFSIter must be instantiated with functors to obtain from
* a given node begin() and end() iterators for that node's children. For this
* reason, you must specify the type of the node's child iterator as an
* additional template parameter.
*
* Specifically, the begin functor must return an iterator whose dereferenced
* value is a @em pointer to a child tree node. For instance, if each node
* tracks its children in an STL container of node* pointers, you can simply
* return that container's begin() iterator.
*
* Alternatively, if a node tracks its children with a classic linked list,
* write a functor returning LLLinkedIter<NODE>.
*
* The end() LLTreeDFSIter must, of course, match the begin() iterator's
* template parameters, but is constructed without runtime parameters.
*/
template <class NODE, typename CHILDITER>
class LLTreeDFSIter: public LLBaseIter<LLTreeDFSIter<NODE, CHILDITER>, NODE>
{
typedef LLBaseIter<LLTreeDFSIter<NODE, CHILDITER>, NODE> super;
typedef typename super::self_type self_type;
protected:
typedef typename super::ptr_type ptr_type;
// The func_type is different for this: from a NODE pointer, we must
// obtain a CHILDITER.
typedef boost::function<CHILDITER(const ptr_type&)> func_type;
private:
typedef std::vector<ptr_type> list_type;
public:
/// Instantiate an LLTreeDFSIter to start a depth-first walk. Pass
/// functors to extract the 'child begin' and 'child end' iterators from
/// each node.
LLTreeDFSIter(const ptr_type& node, const func_type& beginfunc, const func_type& endfunc)
: mBeginFunc(beginfunc),
mEndFunc(endfunc),
mSkipChildren(false)
{
// Only push back this node if it's non-NULL!
if (node)
mPending.push_back(node);
}
/// Instantiate an LLTreeDFSIter to mark the end of the walk
LLTreeDFSIter() : mSkipChildren(false) {}
/// flags iterator logic to skip traversing children of current node on next increment
void skipDescendants(bool skip = true) { mSkipChildren = skip; }
private:
/// leverage boost::iterator_facade
friend class boost::iterator_core_access;
/// advance
/// This implementation is due to http://en.wikipedia.org/wiki/Depth-first_search
void increment()
{
// Capture the node we were just looking at
ptr_type current = mPending.back();
// Remove it from mPending so we don't process it again later
mPending.pop_back();
if (!mSkipChildren)
{
// Add all its children to mPending
addChildren(current);
}
// reset flag after each step
mSkipChildren = false;
}
/// equality
bool equal(const self_type& that) const { return this->mPending == that.mPending; }
/// implement dereference/indirection operators
ptr_type& dereference() const { return const_cast<ptr_type&>(mPending.back()); }
/// Add the direct children of the specified node to mPending
void addChildren(const ptr_type& node)
{
// If we just use push_back() for each child in turn, we'll end up
// processing children in reverse order. We don't want to assume
// CHILDITER is reversible: some of the linked trees we'll be
// processing manage their children using singly-linked lists. So
// figure out how many children there are, grow mPending by that size
// and reverse-copy the children into the new space.
CHILDITER chi = mBeginFunc(node), chend = mEndFunc(node);
// grow mPending by the number of children
mPending.resize(mPending.size() + std::distance(chi, chend));
// reverse-copy the children into the newly-expanded space
std::copy(chi, chend, mPending.rbegin());
}
/// list of the nodes yet to be processed
list_type mPending;
/// functor to extract begin() child iterator
func_type mBeginFunc;
/// functor to extract end() child iterator
func_type mEndFunc;
/// flag which controls traversal of children (skip children of current node if true)
bool mSkipChildren;
};
/**
* Instantiated with a tree node, typically the root, LLTreeDFSPostIter
* "flattens" a depth-first tree walk through that node and all its
* descendants. Whereas LLTreeDFSIter visits each node before visiting any of
* its children, LLTreeDFSPostIter visits all of a node's children before
* visiting the node itself.
*
* The begin() LLTreeDFSPostIter must be instantiated with functors to obtain
* from a given node begin() and end() iterators for that node's children. For
* this reason, you must specify the type of the node's child iterator as an
* additional template parameter.
*
* Specifically, the begin functor must return an iterator whose dereferenced
* value is a @em pointer to a child tree node. For instance, if each node
* tracks its children in an STL container of node* pointers, you can simply
* return that container's begin() iterator.
*
* Alternatively, if a node tracks its children with a classic linked list,
* write a functor returning LLLinkedIter<NODE>.
*
* The end() LLTreeDFSPostIter must, of course, match the begin() iterator's
* template parameters, but is constructed without runtime parameters.
*/
template <class NODE, typename CHILDITER>
class LLTreeDFSPostIter: public LLBaseIter<LLTreeDFSPostIter<NODE, CHILDITER>, NODE>
{
typedef LLBaseIter<LLTreeDFSPostIter<NODE, CHILDITER>, NODE> super;
typedef typename super::self_type self_type;
protected:
typedef typename super::ptr_type ptr_type;
// The func_type is different for this: from a NODE pointer, we must
// obtain a CHILDITER.
typedef boost::function<CHILDITER(const ptr_type&)> func_type;
private:
// Upon reaching a given node in our pending list, we need to know whether
// we've already pushed that node's children, so we must associate a bool
// with each node pointer.
typedef std::vector< std::pair<ptr_type, bool> > list_type;
public:
/// Instantiate an LLTreeDFSPostIter to start a depth-first walk. Pass
/// functors to extract the 'child begin' and 'child end' iterators from
/// each node.
LLTreeDFSPostIter(const ptr_type& node, const func_type& beginfunc, const func_type& endfunc)
: mBeginFunc(beginfunc),
mEndFunc(endfunc),
mSkipAncestors(false)
{
if (! node)
return;
mPending.push_back(typename list_type::value_type(node, false));
makeCurrent();
}
/// Instantiate an LLTreeDFSPostIter to mark the end of the walk
LLTreeDFSPostIter() : mSkipAncestors(false) {}
/// flags iterator logic to skip traversing ancestors of current node on next increment
void skipAncestors(bool skip = true) { mSkipAncestors = skip; }
private:
/// leverage boost::iterator_facade
friend class boost::iterator_core_access;
/// advance
/// This implementation is due to http://en.wikipedia.org/wiki/Depth-first_search
void increment()
{
// Pop the previous current node
mPending.pop_back();
makeCurrent();
}
/// equality
bool equal(const self_type& that) const { return this->mPending == that.mPending; }
/// implement dereference/indirection operators
ptr_type& dereference() const { return const_cast<ptr_type&>(mPending.back().first); }
struct isOpen
{
bool operator()(const typename list_type::value_type& item)
{
return item.second;
}
};
/// Call this each time we change mPending.back() -- that is, every time
/// we're about to change the value returned by dereference(). If we
/// haven't yet pushed the new node's children, do so now.
void makeCurrent()
{
if (mSkipAncestors)
{
mPending.erase(std::remove_if(mPending.begin(), mPending.end(), isOpen()), mPending.end());
mSkipAncestors = false;
}
// Once we've popped the last node, this becomes a no-op.
if (mPending.empty())
return;
// Here mPending.back() holds the node pointer we're proposing to
// dereference next. Have we pushed that node's children yet?
if (mPending.back().second)
return; // if so, it's okay to visit this node now
// We haven't yet pushed this node's children. Do so now. Remember
// that we did -- while the node in question is still back().
mPending.back().second = true;
addChildren(mPending.back().first);
// Now, because we've just changed mPending.back(), make that new node
// current.
makeCurrent();
}
/// Add the direct children of the specified node to mPending
void addChildren(const ptr_type& node)
{
// If we just use push_back() for each child in turn, we'll end up
// processing children in reverse order. We don't want to assume
// CHILDITER is reversible: some of the linked trees we'll be
// processing manage their children using singly-linked lists. So
// figure out how many children there are, grow mPending by that size
// and reverse-copy the children into the new space.
CHILDITER chi = mBeginFunc(node), chend = mEndFunc(node);
// grow mPending by the number of children
mPending.resize(mPending.size() + std::distance(chi, chend));
// Reverse-copy the children into the newly-expanded space. We can't
// just use std::copy() because the source is a ptr_type, whereas the
// dest is a pair of (ptr_type, bool).
for (typename list_type::reverse_iterator pi = mPending.rbegin(); chi != chend; ++chi, ++pi)
{
pi->first = *chi; // copy the child pointer
pi->second = false; // we haven't yet pushed this child's chldren
}
}
/// list of the nodes yet to be processed
list_type mPending;
/// functor to extract begin() child iterator
func_type mBeginFunc;
/// functor to extract end() child iterator
func_type mEndFunc;
/// flags logic to skip traversal of ancestors of current node
bool mSkipAncestors;
};
/**
* Instantiated with a tree node, typically the root, LLTreeBFSIter "flattens"
* a breadth-first tree walk through that node and all its descendants.
*
* The begin() LLTreeBFSIter must be instantiated with functors to obtain from
* a given node the begin() and end() iterators of that node's children. For
* this reason, you must specify the type of the node's child iterator as an
* additional template parameter.
*
* Specifically, the begin functor must return an iterator whose dereferenced
* value is a @em pointer to a child tree node. For instance, if each node
* tracks its children in an STL container of node* pointers, you can simply
* return that container's begin() iterator.
*
* Alternatively, if a node tracks its children with a classic linked list,
* write a functor returning LLLinkedIter<NODE>.
*
* The end() LLTreeBFSIter must, of course, match the begin() iterator's
* template parameters, but is constructed without runtime parameters.
*/
template <class NODE, typename CHILDITER>
class LLTreeBFSIter: public LLBaseIter<LLTreeBFSIter<NODE, CHILDITER>, NODE>
{
typedef LLBaseIter<LLTreeBFSIter<NODE, CHILDITER>, NODE> super;
typedef typename super::self_type self_type;
protected:
typedef typename super::ptr_type ptr_type;
// The func_type is different for this: from a NODE pointer, we must
// obtain a CHILDITER.
typedef boost::function<CHILDITER(const ptr_type&)> func_type;
private:
// We need a FIFO queue rather than a LIFO stack. Use a deque rather than
// a vector, since vector can't implement pop_front() efficiently.
typedef std::deque<ptr_type> list_type;
public:
/// Instantiate an LLTreeBFSIter to start a depth-first walk. Pass
/// functors to extract the 'child begin' and 'child end' iterators from
/// each node.
LLTreeBFSIter(const ptr_type& node, const func_type& beginfunc, const func_type& endfunc):
mBeginFunc(beginfunc),
mEndFunc(endfunc)
{
if (node)
mPending.push_back(node);
}
/// Instantiate an LLTreeBFSIter to mark the end of the walk
LLTreeBFSIter() {}
private:
/// leverage boost::iterator_facade
friend class boost::iterator_core_access;
/// advance
/// This implementation is due to http://en.wikipedia.org/wiki/Breadth-first_search
void increment()
{
// Capture the node we were just looking at
ptr_type current = mPending.front();
// Remove it from mPending so we don't process it again later
mPending.pop_front();
// Add all its children to mPending
CHILDITER chend = mEndFunc(current);
for (CHILDITER chi = mBeginFunc(current); chi != chend; ++chi)
mPending.push_back(*chi);
}
/// equality
bool equal(const self_type& that) const { return this->mPending == that.mPending; }
/// implement dereference/indirection operators
ptr_type& dereference() const { return const_cast<ptr_type&>(mPending.front()); }
/// list of the nodes yet to be processed
list_type mPending;
/// functor to extract begin() child iterator
func_type mBeginFunc;
/// functor to extract end() child iterator
func_type mEndFunc;
};
/**
* When you want to select between LLTreeDFSIter, LLTreeDFSPostIter and
* LLTreeBFSIter with a compile-time discriminator, use LLTreeWalkIter with an
* LLTreeIter::WalkIter template arg.
*/
template <LLTreeIter::WalkIter DISCRIM, class NODE, typename CHILDITER>
class LLTreeWalkIter
{
enum { use_a_valid_LLTreeIter_WalkIter_value = false };
public:
/// Bogus constructors for default (unrecognized discriminator) case
template <typename TYPE1, typename TYPE2>
LLTreeWalkIter(TYPE1, TYPE2)
{
BOOST_STATIC_ASSERT(use_a_valid_LLTreeIter_WalkIter_value);
}
LLTreeWalkIter()
{
BOOST_STATIC_ASSERT(use_a_valid_LLTreeIter_WalkIter_value);
}
};
/// Specialize for LLTreeIter::DFS_PRE
template <class NODE, typename CHILDITER>
class LLTreeWalkIter<LLTreeIter::DFS_PRE, NODE, CHILDITER>:
public LLTreeDFSIter<NODE, CHILDITER>
{
typedef LLTreeDFSIter<NODE, CHILDITER> super;
public:
/// forward begin ctor
LLTreeWalkIter(const typename super::ptr_type& node,
const typename super::func_type& beginfunc,
const typename super::func_type& endfunc):
super(node, beginfunc, endfunc)
{}
/// forward end ctor
LLTreeWalkIter():
super()
{}
};
/// Specialize for LLTreeIter::DFS_POST
template <class NODE, typename CHILDITER>
class LLTreeWalkIter<LLTreeIter::DFS_POST, NODE, CHILDITER>:
public LLTreeDFSPostIter<NODE, CHILDITER>
{
typedef LLTreeDFSPostIter<NODE, CHILDITER> super;
public:
/// forward begin ctor
LLTreeWalkIter(const typename super::ptr_type& node,
const typename super::func_type& beginfunc,
const typename super::func_type& endfunc):
super(node, beginfunc, endfunc)
{}
/// forward end ctor
LLTreeWalkIter():
super()
{}
};
/// Specialize for LLTreeIter::BFS
template <class NODE, typename CHILDITER>
class LLTreeWalkIter<LLTreeIter::BFS, NODE, CHILDITER>:
public LLTreeBFSIter<NODE, CHILDITER>
{
typedef LLTreeBFSIter<NODE, CHILDITER> super;
public:
/// forward begin ctor
LLTreeWalkIter(const typename super::ptr_type& node,
const typename super::func_type& beginfunc,
const typename super::func_type& endfunc):
super(node, beginfunc, endfunc)
{}
/// forward end ctor
LLTreeWalkIter():
super()
{}
};
#endif /* ! defined(LL_LLTREEITERATORS_H) */

View File

@@ -32,7 +32,7 @@
#ifndef LL_LLECONOMY_H
#define LL_LLECONOMY_H
#include "llmemory.h"
#include "llsingleton.h"
class LLMessageSystem;
class LLVector3;

View File

@@ -36,10 +36,9 @@
#include "lldarray.h"
#include "llfoldertype.h"
#include "llinventorytype.h"
#include "llinventorydefines.h"
#include "llmemtype.h"
#include "llpermissions.h"
#include "llmemory.h"
#include "llrefcount.h"
#include "llsaleinfo.h"
#include "llsd.h"
#include "lluuid.h"
@@ -304,84 +303,11 @@ protected:
//-----------------------------------------------------------------------------
// Useful bits
// Convertors
//
// These functions convert between structured data and an inventory
// item, appropriate for serialization.
//-----------------------------------------------------------------------------
// This functor tests if an item is transferrable and returns true if
// it is. Derived from unary_function<> so that the object can be used
// in stl-compliant adaptable predicates (eg, not1<>). You might want
// to use this in std::partition() or similar logic.
struct IsItemTransferable : public std::unary_function<LLInventoryItem*, bool>
{
LLUUID mDestID;
IsItemTransferable(const LLUUID& dest_id) : mDestID(dest_id) {}
bool operator()(const LLInventoryItem* item) const
{
return (item->getPermissions().allowTransferTo(mDestID)) ? true:false;
}
};
// This functor is used to set the owner and group of inventory items,
// for example, in a simple std::for_each() loop. Note that the call
// to setOwnerAndGroup can fail if authority_id != LLUUID::null.
struct SetItemOwnerAndGroup
{
LLUUID mAuthorityID;
LLUUID mOwnerID;
LLUUID mGroupID;
SetItemOwnerAndGroup(const LLUUID& authority_id,
const LLUUID& owner_id,
const LLUUID& group_id) :
mAuthorityID(authority_id), mOwnerID(owner_id), mGroupID(group_id) {}
void operator()(LLInventoryItem* item) const
{
LLPermissions perm = item->getPermissions();
bool is_atomic = (LLAssetType::AT_OBJECT == item->getType()) ? false : true;
perm.setOwnerAndGroup(mAuthorityID, mOwnerID, mGroupID, is_atomic);
// If no owner id is set, this is equivalent to a deed action.
// Clear 'share with group'.
if (mOwnerID.isNull())
{
perm.setMaskGroup(PERM_NONE);
}
item->setPermissions(perm);
}
};
// This functor is used to unset the share with group, everyone perms, and
// for sale info for objects being sold through contents.
struct SetNotForSale
{
LLUUID mAgentID;
LLUUID mGroupID;
SetNotForSale(const LLUUID& agent_id,
const LLUUID& group_id) :
mAgentID(agent_id), mGroupID(group_id) {}
void operator()(LLInventoryItem* item) const
{
// Clear group & everyone permissions.
LLPermissions perm = item->getPermissions();
perm.setGroupBits(mAgentID, mGroupID, FALSE, PERM_MODIFY | PERM_MOVE | PERM_COPY);
perm.setEveryoneBits(mAgentID, mGroupID, FALSE, PERM_MOVE | PERM_COPY);
item->setPermissions(perm);
// Mark group & everyone permissions for overwrite on the next
// rez if it is an object.
if(LLAssetType::AT_OBJECT == item->getType())
{
U32 flags = item->getFlags();
flags |= LLInventoryItemFlags::II_FLAGS_OBJECT_PERM_OVERWRITE_GROUP;
flags |= LLInventoryItemFlags::II_FLAGS_OBJECT_PERM_OVERWRITE_EVERYONE;
item->setFlags(flags);
}
// Clear for sale info.
item->setSaleInfo(LLSaleInfo::DEFAULT);
}
};
// These functions convert between structured data and an inventroy
// item, appropriate for serialization.
LLSD ll_create_sd_from_inventory_item(LLPointer<LLInventoryItem> item);
LLPointer<LLInventoryItem> ll_create_item_from_sd(const LLSD& sd_item);
LLSD ll_create_sd_from_inventory_category(LLPointer<LLInventoryCategory> cat);

View File

@@ -35,6 +35,7 @@
#include "llinventorytype.h"
#include "lldictionary.h"
#include "llmemory.h"
#include "llsingleton.h"
static const std::string empty_string;

View File

@@ -33,7 +33,7 @@
#ifndef LL_NOTECARD_H
#define LL_NOTECARD_H
#include "llmemory.h"
#include "llpointer.h"
#include "llinventory.h"
class LLNotecard

View File

@@ -177,7 +177,7 @@ void LLParcel::init(const LLUUID &owner_id,
mSaleTimerExpires.stop();
mGraceExtension = 0;
//mExpireAction = STEA_REVERT;
mRecordTransaction = FALSE;
//mRecordTransaction = FALSE;
mAuctionID = 0;
mInEscrow = false;

View File

@@ -432,13 +432,10 @@ public:
void completeSale(U32& type, U8& flags, LLUUID& to_id);
void clearSale();
// this function returns TRUE if the parcel needs conversion to a
// lease from a non-owned-status state.
BOOL getRecordTransaction() const { return mRecordTransaction; }
void setRecordTransaction(BOOL record) { mRecordTransaction = record; }
BOOL isMediaResetTimerExpired(const U64& time);
// more accessors
U32 getParcelFlags() const { return mParcelFlags; }
@@ -473,7 +470,9 @@ public:
{ return (mParcelFlags & PF_ALLOW_FLY) ? TRUE : FALSE; }
BOOL getAllowLandmark() const
{ return (mParcelFlags & PF_ALLOW_LANDMARK) ? TRUE : FALSE; }
{ return TRUE; }
//Perhaps revert for opensim?
//{ return (mParcelFlags & PF_ALLOW_LANDMARK) ? TRUE : FALSE; }
BOOL getAllowGroupScripts() const
{ return (mParcelFlags & PF_ALLOW_GROUP_SCRIPTS) ? TRUE : FALSE; }
@@ -619,8 +618,6 @@ protected:
LLTimer mMediaResetTimer;
S32 mGraceExtension;
BOOL mRecordTransaction;
// This value is non-zero if there is an auction associated with
// the parcel.

View File

@@ -132,5 +132,7 @@ const S32 PARCEL_DETAILS_DESC = 1;
const S32 PARCEL_DETAILS_OWNER = 2;
const S32 PARCEL_DETAILS_GROUP = 3;
const S32 PARCEL_DETAILS_AREA = 4;
const S32 PARCEL_DETAILS_ID = 5;
const S32 PARCEL_DETAILS_SEE_AVATARS = 6;
#endif

View File

@@ -30,8 +30,8 @@
* $/LicenseInfo$
*/
#include "linden_common.h"
#include <iostream>
#include "linden_common.h"
#include "llsaleinfo.h"

View File

@@ -39,6 +39,7 @@
#include "llcompilequeue.h"
#include "llfloaterbuycurrency.h"
#include "llnotify.h"
#include "llinventorydefines.h"
#include "llinventorymodel.h"
#include "llinventoryview.h"
#include "llpermissionsflags.h"

View File

@@ -35,6 +35,7 @@
#include "llviewerprecompiledheaders.h"
#include "llfloaterbulkpermission.h"
#include "llfloaterperms.h" // for utilities
#include "llinventorydefines.h"
#include "llagent.h"
#include "llchat.h"
#include "llviewerwindow.h"

View File

@@ -43,6 +43,7 @@
#include "llagent.h" // for agent id
#include "llalertdialog.h"
#include "llinventorymodel.h" // for gInventory
#include "llinventorydefines.h"
#include "llinventoryview.h" // for get_item_icon
#include "llselectmgr.h"
#include "llscrolllistctrl.h"

View File

@@ -46,6 +46,7 @@
#include "llalertdialog.h"
#include "llcheckboxctrl.h"
#include "llinventorymodel.h" // for gInventory
#include "llinventorydefines.h"
#include "llinventoryview.h" // for get_item_icon
#include "llselectmgr.h"
#include "llscrolllistctrl.h"

View File

@@ -38,6 +38,7 @@
#include "llcachename.h"
#include "lldbstrings.h"
#include "llinventory.h"
#include "llinventorydefines.h"
#include "llagent.h"
#include "llbutton.h"

View File

@@ -36,6 +36,7 @@
#include "llinventoryview.h"
#include "llinventorybridge.h"
#include "llinventorydefines.h"
#include "message.h"

View File

@@ -36,6 +36,7 @@
#include "llinventoryview.h"
#include "llinventorybridge.h"
#include "llinventorydefines.h"
#include "message.h"

View File

@@ -45,6 +45,7 @@
#include "llpermissionsflags.h"
#include "lleconomy.h"
#include "material_codes.h"
#include "llinventorydefines.h"
// project includes
#include "llui.h"

View File

@@ -39,6 +39,7 @@
#include "llinventory.h"
#include "llviewerinventory.h"
#include "llinventorymodel.h"
#include "llinventorydefines.h"
#include "llinventoryview.h"
#include "llagent.h"
#include "lltooldraganddrop.h"

View File

@@ -50,6 +50,7 @@
#include "llfontgl.h"
#include "llassetstorage.h"
#include "llinventory.h"
#include "llinventorydefines.h"
#include "llagent.h"
#include "llcallbacklist.h"

View File

@@ -36,6 +36,7 @@
#include "llpreview.h"
#include "lllineeditor.h"
#include "llinventory.h"
#include "llinventorydefines.h"
#include "llinventorymodel.h"
#include "llresmgr.h"
#include "lltextbox.h"

View File

@@ -39,6 +39,7 @@
// libraries
#include "lldatapacker.h"
#include "lldarray.h"
#include "llinventorydefines.h"
#include "llstring.h"
#include "lldir.h"
#include "llmultigesture.h"

View File

@@ -35,6 +35,7 @@
#include "llpreviewnotecard.h"
#include "llinventory.h"
#include "llinventorydefines.h"
#include "llagent.h"
#include "llagentcamera.h"

View File

@@ -40,6 +40,7 @@
#include "llcheckboxctrl.h"
#include "llcombobox.h"
#include "lldir.h"
#include "llinventorydefines.h"
#include "llinventorymodel.h"
#include "llkeyboard.h"
#include "lllineeditor.h"

View File

@@ -49,6 +49,7 @@
#include "llhudeffecttrail.h"
#include "llhudmanager.h"
#include "llinventorybridge.h"
#include "llinventorydefines.h"
#include "llinventorymodel.h"
#include "llinventoryview.h"
#include "llmutelist.h"

View File

@@ -56,6 +56,7 @@
#include "llfloaterworldmap.h"
#include "llhudtext.h"
#include "llhudview.h"
#include "llinventorydefines.h"
#include "llinventorymodel.h"
#include "lllandmarklist.h"
#include "llsky.h"

View File

@@ -46,6 +46,7 @@
#include "llgesturemgr.h"
#include "llinventorybridge.h"
#include "llinventorydefines.h"
#include "llinventoryview.h"
#include "llviewerregion.h"

View File

@@ -167,6 +167,7 @@
#include "llimagebmp.h"
#include "llimagej2c.h"
#include "llimagetga.h"
#include "llinventorydefines.h"
#include "llinventorymodel.h"
#include "llinventoryview.h"
#include "llkeyboard.h"

View File

@@ -95,6 +95,7 @@
#include "llhudeffecttrail.h"
#include "llhudmanager.h"
#include "llimpanel.h"
#include "llinventorydefines.h"
#include "llinventorymodel.h"
#include "llinventoryview.h"
#include "llmenugl.h"

View File

@@ -45,6 +45,7 @@
#include "llfontgl.h"
#include "llframetimer.h"
#include "llinventory.h"
#include "llinventorydefines.h"
#include "llmaterialtable.h"
#include "llmutelist.h"
#include "llnamevalue.h"

View File

@@ -49,6 +49,7 @@
#include "llsdutil.h"
#include "llsdutil_math.h"
#include "lltransactiontypes.h"
#include "llinventorydefines.h"
// newview includes
#include "llagent.h"

View File

@@ -36,6 +36,7 @@
#include "llaudioengine.h"
#include "llagent.h"
#include "llinventory.h"
#include "llinventorydefines.h"
#include "llinventorymodel.h"
#include "llinventoryview.h"
#include "llinventorybridge.h" // for landmark prefix string