summaryrefslogtreecommitdiff
path: root/indra/llcommon
diff options
context:
space:
mode:
Diffstat (limited to 'indra/llcommon')
-rw-r--r--indra/llcommon/CMakeLists.txt317
-rw-r--r--indra/llcommon/bitpack.cpp30
-rw-r--r--indra/llcommon/bitpack.h35
-rw-r--r--indra/llcommon/ctype_workaround.h35
-rw-r--r--indra/llcommon/doublelinkedlist.h35
-rw-r--r--indra/llcommon/imageids.cpp70
-rw-r--r--indra/llcommon/imageids.h115
-rw-r--r--indra/llcommon/indra_constants.cpp40
-rw-r--r--indra/llcommon/indra_constants.h111
-rw-r--r--indra/llcommon/is_approx_equal_fraction.h79
-rw-r--r--indra/llcommon/linden_common.h77
-rw-r--r--indra/llcommon/linked_lists.h35
-rw-r--r--indra/llcommon/ll_template_cast.h177
-rw-r--r--indra/llcommon/llagentconstants.h109
-rw-r--r--indra/llcommon/llallocator.cpp134
-rw-r--r--indra/llcommon/llallocator.h57
-rw-r--r--indra/llcommon/llallocator_heap_profile.cpp147
-rw-r--r--indra/llcommon/llallocator_heap_profile.h71
-rw-r--r--indra/llcommon/llapp.cpp469
-rw-r--r--indra/llcommon/llapp.h126
-rw-r--r--indra/llcommon/llapr.cpp631
-rw-r--r--indra/llcommon/llapr.h208
-rw-r--r--indra/llcommon/llassettype.cpp361
-rw-r--r--indra/llcommon/llassettype.h186
-rw-r--r--indra/llcommon/llassoclist.h35
-rw-r--r--indra/llcommon/llavatarconstants.h35
-rw-r--r--indra/llcommon/llavatarname.cpp113
-rw-r--r--indra/llcommon/llavatarname.h95
-rw-r--r--indra/llcommon/llbase32.cpp43
-rw-r--r--indra/llcommon/llbase32.h39
-rw-r--r--indra/llcommon/llbase64.cpp37
-rw-r--r--indra/llcommon/llbase64.h39
-rw-r--r--indra/llcommon/llboost.h50
-rw-r--r--indra/llcommon/llchat.h66
-rw-r--r--indra/llcommon/llclickaction.h40
-rw-r--r--indra/llcommon/llcommon.cpp41
-rw-r--r--indra/llcommon/llcommon.h41
-rw-r--r--indra/llcommon/llcommonutils.cpp56
-rw-r--r--indra/llcommon/llcommonutils.h51
-rw-r--r--indra/llcommon/llcoros.cpp154
-rw-r--r--indra/llcommon/llcoros.h166
-rw-r--r--indra/llcommon/llcrc.cpp223
-rw-r--r--indra/llcommon/llcrc.h68
-rw-r--r--indra/llcommon/llcriticaldamp.cpp35
-rw-r--r--indra/llcommon/llcriticaldamp.h37
-rw-r--r--indra/llcommon/llcursortypes.cpp85
-rw-r--r--indra/llcommon/llcursortypes.h73
-rw-r--r--indra/llcommon/lldarray.h41
-rw-r--r--indra/llcommon/lldarrayptr.h35
-rw-r--r--indra/llcommon/lldate.cpp205
-rw-r--r--indra/llcommon/lldate.h87
-rw-r--r--indra/llcommon/lldefs.h46
-rw-r--r--indra/llcommon/lldeleteutils.h47
-rw-r--r--indra/llcommon/lldependencies.cpp103
-rw-r--r--indra/llcommon/lldependencies.h799
-rw-r--r--indra/llcommon/lldepthstack.h35
-rw-r--r--indra/llcommon/lldictionary.cpp47
-rw-r--r--indra/llcommon/lldictionary.h94
-rw-r--r--indra/llcommon/lldlinked.h35
-rw-r--r--indra/llcommon/lldoubledispatch.h326
-rw-r--r--indra/llcommon/lldqueueptr.h43
-rw-r--r--indra/llcommon/llendianswizzle.h35
-rw-r--r--indra/llcommon/llenum.h35
-rw-r--r--indra/llcommon/llerror.cpp439
-rw-r--r--indra/llcommon/llerror.h165
-rw-r--r--indra/llcommon/llerrorcontrol.h123
-rw-r--r--indra/llcommon/llerrorlegacy.h55
-rw-r--r--indra/llcommon/llerrorthread.cpp37
-rw-r--r--indra/llcommon/llerrorthread.h37
-rw-r--r--indra/llcommon/llevent.cpp39
-rw-r--r--indra/llcommon/llevent.h52
-rw-r--r--indra/llcommon/lleventapi.cpp47
-rw-r--r--indra/llcommon/lleventapi.h83
-rw-r--r--indra/llcommon/lleventcoro.cpp146
-rw-r--r--indra/llcommon/lleventcoro.h569
-rw-r--r--indra/llcommon/lleventdispatcher.cpp166
-rw-r--r--indra/llcommon/lleventdispatcher.h210
-rw-r--r--indra/llcommon/lleventemitter.h35
-rw-r--r--indra/llcommon/lleventfilter.cpp166
-rw-r--r--indra/llcommon/lleventfilter.h203
-rw-r--r--indra/llcommon/llevents.cpp588
-rw-r--r--indra/llcommon/llevents.h1035
-rw-r--r--indra/llcommon/lleventtimer.cpp89
-rw-r--r--indra/llcommon/lleventtimer.h54
-rw-r--r--indra/llcommon/llextendedstatus.h35
-rw-r--r--indra/llcommon/llfasttimer.h366
-rw-r--r--indra/llcommon/llfasttimer_class.cpp764
-rw-r--r--indra/llcommon/llfasttimer_class.h266
-rw-r--r--indra/llcommon/llfile.cpp137
-rw-r--r--indra/llcommon/llfile.h134
-rw-r--r--indra/llcommon/llfindlocale.cpp518
-rw-r--r--indra/llcommon/llfindlocale.h60
-rw-r--r--indra/llcommon/llfixedbuffer.cpp55
-rw-r--r--indra/llcommon/llfixedbuffer.h61
-rw-r--r--indra/llcommon/llfoldertype.cpp163
-rw-r--r--indra/llcommon/llfoldertype.h106
-rw-r--r--indra/llcommon/llformat.cpp67
-rw-r--r--indra/llcommon/llformat.h41
-rw-r--r--indra/llcommon/llframetimer.cpp51
-rw-r--r--indra/llcommon/llframetimer.h51
-rw-r--r--indra/llcommon/llhash.h54
-rw-r--r--indra/llcommon/llheartbeat.cpp165
-rw-r--r--indra/llcommon/llheartbeat.h68
-rw-r--r--indra/llcommon/llhttpstatuscodes.h89
-rw-r--r--indra/llcommon/llindexedqueue.h35
-rw-r--r--indra/llcommon/llinstancetracker.cpp37
-rw-r--r--indra/llcommon/llinstancetracker.h190
-rw-r--r--indra/llcommon/llkeythrottle.h202
-rw-r--r--indra/llcommon/llkeyusetracker.h215
-rw-r--r--indra/llcommon/lllazy.cpp40
-rw-r--r--indra/llcommon/lllazy.h399
-rw-r--r--indra/llcommon/lllinkedqueue.h35
-rw-r--r--indra/llcommon/lllistenerwrapper.h198
-rw-r--r--indra/llcommon/llliveappconfig.cpp69
-rw-r--r--indra/llcommon/llliveappconfig.h71
-rw-r--r--indra/llcommon/lllivefile.cpp83
-rw-r--r--indra/llcommon/lllivefile.h89
-rw-r--r--indra/llcommon/lllocalidhashmap.h35
-rw-r--r--indra/llcommon/lllog.cpp47
-rw-r--r--indra/llcommon/lllog.h41
-rw-r--r--indra/llcommon/lllslconstants.h69
-rw-r--r--indra/llcommon/llmap.h35
-rw-r--r--indra/llcommon/llmd5.cpp538
-rw-r--r--indra/llcommon/llmd5.h131
-rw-r--r--indra/llcommon/llmemory.cpp375
-rw-r--r--indra/llcommon/llmemory.h434
-rw-r--r--indra/llcommon/llmemorystream.cpp35
-rw-r--r--indra/llcommon/llmemorystream.h39
-rw-r--r--indra/llcommon/llmemtype.cpp231
-rw-r--r--indra/llcommon/llmemtype.h333
-rw-r--r--indra/llcommon/llmetrics.cpp37
-rw-r--r--indra/llcommon/llmetrics.h37
-rw-r--r--indra/llcommon/llmortician.cpp35
-rw-r--r--indra/llcommon/llmortician.h37
-rw-r--r--indra/llcommon/llnametable.h35
-rw-r--r--indra/llcommon/lloptioninterface.cpp33
-rw-r--r--indra/llcommon/lloptioninterface.h40
-rw-r--r--indra/llcommon/llpointer.h170
-rw-r--r--indra/llcommon/llpreprocessor.h122
-rw-r--r--indra/llcommon/llpriqueuemap.h35
-rw-r--r--indra/llcommon/llprocesslauncher.cpp339
-rw-r--r--indra/llcommon/llprocesslauncher.h88
-rw-r--r--indra/llcommon/llprocessor.cpp2802
-rw-r--r--indra/llcommon/llprocessor.h204
-rw-r--r--indra/llcommon/llptrskiplist.h37
-rw-r--r--indra/llcommon/llptrskipmap.h41
-rw-r--r--indra/llcommon/llptrto.cpp102
-rw-r--r--indra/llcommon/llptrto.h87
-rw-r--r--indra/llcommon/llqueuedthread.cpp124
-rw-r--r--indra/llcommon/llqueuedthread.h44
-rw-r--r--indra/llcommon/llrand.cpp171
-rw-r--r--indra/llcommon/llrand.h127
-rw-r--r--indra/llcommon/llrefcount.cpp54
-rw-r--r--indra/llcommon/llrefcount.h73
-rw-r--r--indra/llcommon/llrun.cpp35
-rw-r--r--indra/llcommon/llrun.h39
-rw-r--r--indra/llcommon/llsafehandle.h162
-rw-r--r--indra/llcommon/llsd.cpp103
-rw-r--r--indra/llcommon/llsd.h45
-rw-r--r--indra/llcommon/llsdserialize.cpp77
-rw-r--r--indra/llcommon/llsdserialize.h112
-rw-r--r--indra/llcommon/llsdserialize_xml.cpp370
-rw-r--r--indra/llcommon/llsdserialize_xml.h35
-rw-r--r--indra/llcommon/llsdutil.cpp529
-rw-r--r--indra/llcommon/llsdutil.h165
-rw-r--r--indra/llcommon/llsecondlifeurls.cpp113
-rw-r--r--indra/llcommon/llsecondlifeurls.h78
-rw-r--r--indra/llcommon/llsimplehash.h37
-rw-r--r--indra/llcommon/llsingleton.cpp32
-rw-r--r--indra/llcommon/llsingleton.h201
-rw-r--r--indra/llcommon/llskiplist.h36
-rw-r--r--indra/llcommon/llskipmap.h35
-rw-r--r--indra/llcommon/llsmoothstep.h35
-rw-r--r--indra/llcommon/llstack.h35
-rw-r--r--indra/llcommon/llstacktrace.cpp136
-rw-r--r--indra/llcommon/llstacktrace.h38
-rw-r--r--indra/llcommon/llstat.cpp679
-rw-r--r--indra/llcommon/llstat.h236
-rw-r--r--indra/llcommon/llstatenums.h57
-rw-r--r--indra/llcommon/llstl.h45
-rw-r--r--indra/llcommon/llstreamtools.cpp142
-rw-r--r--indra/llcommon/llstreamtools.h76
-rw-r--r--indra/llcommon/llstrider.h37
-rw-r--r--indra/llcommon/llstring.cpp976
-rw-r--r--indra/llcommon/llstring.h713
-rw-r--r--indra/llcommon/llstringtable.cpp52
-rw-r--r--indra/llcommon/llstringtable.h71
-rw-r--r--indra/llcommon/llsys.cpp367
-rw-r--r--indra/llcommon/llsys.h57
-rw-r--r--indra/llcommon/llthread.cpp79
-rw-r--r--indra/llcommon/llthread.h70
-rw-r--r--indra/llcommon/lltimer.cpp229
-rw-r--r--indra/llcommon/lltimer.h123
-rw-r--r--indra/llcommon/lltreeiterators.h705
-rw-r--r--indra/llcommon/lluri.cpp65
-rw-r--r--indra/llcommon/lluri.h57
-rw-r--r--indra/llcommon/lluuid.cpp924
-rw-r--r--indra/llcommon/lluuid.h331
-rw-r--r--indra/llcommon/lluuidhashmap.h35
-rw-r--r--indra/llcommon/llversionserver.h43
-rw-r--r--indra/llcommon/llversionviewer.h41
-rw-r--r--indra/llcommon/llworkerthread.cpp90
-rw-r--r--indra/llcommon/llworkerthread.h54
-rw-r--r--indra/llcommon/metaclass.cpp35
-rw-r--r--indra/llcommon/metaclass.h37
-rw-r--r--indra/llcommon/metaclasst.h35
-rw-r--r--indra/llcommon/metaproperty.cpp35
-rw-r--r--indra/llcommon/metaproperty.h37
-rw-r--r--indra/llcommon/metapropertyt.h43
-rw-r--r--indra/llcommon/reflective.cpp35
-rw-r--r--indra/llcommon/reflective.h37
-rw-r--r--indra/llcommon/reflectivet.h35
-rw-r--r--indra/llcommon/roles_constants.h56
-rw-r--r--indra/llcommon/stdenums.h42
-rw-r--r--indra/llcommon/stdtypes.h40
-rw-r--r--indra/llcommon/string_table.h35
-rw-r--r--indra/llcommon/stringize.h107
-rw-r--r--indra/llcommon/tests/bitpack_test.cpp119
-rw-r--r--indra/llcommon/tests/commonmisc_test.cpp671
-rw-r--r--indra/llcommon/tests/listener.h156
-rw-r--r--indra/llcommon/tests/llallocator_heap_profile_test.cpp144
-rw-r--r--indra/llcommon/tests/llallocator_test.cpp80
-rw-r--r--indra/llcommon/tests/llbase64_test.cpp77
-rw-r--r--indra/llcommon/tests/lldate_test.cpp213
-rw-r--r--indra/llcommon/tests/lldependencies_test.cpp292
-rw-r--r--indra/llcommon/tests/llerror_test.cpp762
-rw-r--r--indra/llcommon/tests/lleventcoro_test.cpp799
-rw-r--r--indra/llcommon/tests/lleventfilter_test.cpp293
-rw-r--r--indra/llcommon/tests/llframetimer_test.cpp112
-rw-r--r--indra/llcommon/tests/llinstancetracker_test.cpp183
-rw-r--r--indra/llcommon/tests/lllazy_test.cpp244
-rw-r--r--indra/llcommon/tests/llmemtype_test.cpp117
-rw-r--r--indra/llcommon/tests/llprocessor_test.cpp61
-rw-r--r--indra/llcommon/tests/llrand_test.cpp127
-rw-r--r--indra/llcommon/tests/llsdserialize_test.cpp1498
-rw-r--r--indra/llcommon/tests/llstring_test.cpp745
-rw-r--r--indra/llcommon/tests/lltreeiterators_test.cpp1213
-rw-r--r--indra/llcommon/tests/lluri_test.cpp364
-rw-r--r--indra/llcommon/tests/reflection_test.cpp220
-rw-r--r--indra/llcommon/tests/stringize_test.cpp104
-rw-r--r--indra/llcommon/tests/wrapllerrs.h73
-rw-r--r--indra/llcommon/timer.h35
-rw-r--r--indra/llcommon/timing.cpp35
-rw-r--r--indra/llcommon/timing.h38
-rw-r--r--indra/llcommon/u64.cpp71
-rw-r--r--indra/llcommon/u64.h50
246 files changed, 33328 insertions, 8738 deletions
diff --git a/indra/llcommon/CMakeLists.txt b/indra/llcommon/CMakeLists.txt
new file mode 100644
index 0000000000..7bad780dd8
--- /dev/null
+++ b/indra/llcommon/CMakeLists.txt
@@ -0,0 +1,317 @@
+
+# -*- cmake -*-
+
+project(llcommon)
+
+include(00-Common)
+include(LLCommon)
+include(Linking)
+include(Boost)
+include(Pth)
+include(LLSharedLibs)
+include(GoogleBreakpad)
+include(GooglePerfTools)
+include(Copy3rdPartyLibs)
+
+include_directories(
+ ${EXPAT_INCLUDE_DIRS}
+ ${LLCOMMON_INCLUDE_DIRS}
+ ${ZLIB_INCLUDE_DIRS}
+ ${PTH_INCLUDE_DIRS}
+ )
+
+# add_executable(lltreeiterators lltreeiterators.cpp)
+#
+# target_link_libraries(lltreeiterators
+# ${LLCOMMON_LIBRARIES})
+
+set(llcommon_SOURCE_FILES
+ imageids.cpp
+ indra_constants.cpp
+ llallocator.cpp
+ llallocator_heap_profile.cpp
+ llapp.cpp
+ llapr.cpp
+ llassettype.cpp
+ llavatarname.cpp
+ llbase32.cpp
+ llbase64.cpp
+ llcommon.cpp
+ llcommonutils.cpp
+ llcoros.cpp
+ llcrc.cpp
+ llcriticaldamp.cpp
+ llcursortypes.cpp
+ lldate.cpp
+ lldependencies.cpp
+ lldictionary.cpp
+ llerror.cpp
+ llerrorthread.cpp
+ llevent.cpp
+ lleventapi.cpp
+ lleventcoro.cpp
+ lleventdispatcher.cpp
+ lleventfilter.cpp
+ llevents.cpp
+ lleventtimer.cpp
+ llfasttimer_class.cpp
+ llfile.cpp
+ llfindlocale.cpp
+ llfixedbuffer.cpp
+ llfoldertype.cpp
+ llformat.cpp
+ llframetimer.cpp
+ llheartbeat.cpp
+ llliveappconfig.cpp
+ lllivefile.cpp
+ lllog.cpp
+ llmd5.cpp
+ llmemory.cpp
+ llmemorystream.cpp
+ llmemtype.cpp
+ llmetrics.cpp
+ llmortician.cpp
+ lloptioninterface.cpp
+ llptrto.cpp
+ llprocesslauncher.cpp
+ llprocessor.cpp
+ llqueuedthread.cpp
+ llrand.cpp
+ llrefcount.cpp
+ llrun.cpp
+ llsd.cpp
+ llsdserialize.cpp
+ llsdserialize_xml.cpp
+ llsdutil.cpp
+ llsecondlifeurls.cpp
+ llsingleton.cpp
+ llstat.cpp
+ llstacktrace.cpp
+ llstreamtools.cpp
+ llstring.cpp
+ llstringtable.cpp
+ llsys.cpp
+ llthread.cpp
+ lltimer.cpp
+ lluri.cpp
+ lluuid.cpp
+ llworkerthread.cpp
+ metaclass.cpp
+ metaproperty.cpp
+ reflective.cpp
+ timing.cpp
+ u64.cpp
+ )
+
+set(llcommon_HEADER_FILES
+ CMakeLists.txt
+
+ bitpack.h
+ ctype_workaround.h
+ doublelinkedlist.h
+ imageids.h
+ indra_constants.h
+ linden_common.h
+ linked_lists.h
+ llallocator.h
+ llallocator_heap_profile.h
+ llagentconstants.h
+ llavatarname.h
+ llapp.h
+ llapr.h
+ llassettype.h
+ llassoclist.h
+ llavatarconstants.h
+ llbase32.h
+ llbase64.h
+ llboost.h
+ llchat.h
+ llclickaction.h
+ llcommon.h
+ llcommonutils.h
+ llcoros.h
+ llcrc.h
+ llcriticaldamp.h
+ llcursortypes.h
+ lldarray.h
+ lldarrayptr.h
+ lldate.h
+ lldefs.h
+ lldependencies.h
+ lldeleteutils.h
+ lldepthstack.h
+ lldictionary.h
+ lldlinked.h
+ lldoubledispatch.h
+ lldqueueptr.h
+ llendianswizzle.h
+ llenum.h
+ llerror.h
+ llerrorcontrol.h
+ llerrorlegacy.h
+ llerrorthread.h
+ llevent.h
+ lleventapi.h
+ lleventcoro.h
+ lleventdispatcher.h
+ lleventfilter.h
+ llevents.h
+ lleventemitter.h
+ llextendedstatus.h
+ llfasttimer.h
+ llfasttimer_class.h
+ llfile.h
+ llfindlocale.h
+ llfixedbuffer.h
+ llfoldertype.h
+ llformat.h
+ llframetimer.h
+ llhash.h
+ llheartbeat.h
+ llhttpstatuscodes.h
+ llindexedqueue.h
+ llinstancetracker.h
+ llkeythrottle.h
+ lllazy.h
+ lllistenerwrapper.h
+ lllinkedqueue.h
+ llliveappconfig.h
+ lllivefile.h
+ lllocalidhashmap.h
+ lllog.h
+ lllslconstants.h
+ llmap.h
+ llmd5.h
+ llmemory.h
+ llmemorystream.h
+ llmemtype.h
+ llmetrics.h
+ llmortician.h
+ llnametable.h
+ lloptioninterface.h
+ llpointer.h
+ llpreprocessor.h
+ llpriqueuemap.h
+ llprocesslauncher.h
+ llprocessor.h
+ llptrskiplist.h
+ llptrskipmap.h
+ llptrto.h
+ llqueuedthread.h
+ llrand.h
+ llrefcount.h
+ llrun.h
+ llrefcount.h
+ llsafehandle.h
+ llsd.h
+ llsdserialize.h
+ llsdserialize_xml.h
+ llsdutil.h
+ llsecondlifeurls.h
+ llsimplehash.h
+ llsingleton.h
+ llskiplist.h
+ llskipmap.h
+ llstack.h
+ llstacktrace.h
+ llstat.h
+ llstatenums.h
+ llstl.h
+ llstreamtools.h
+ llstrider.h
+ llstring.h
+ llstringtable.h
+ llsys.h
+ llthread.h
+ lltimer.h
+ lltreeiterators.h
+ lluri.h
+ lluuid.h
+ lluuidhashmap.h
+ llversionserver.h
+ llversionviewer.h
+ llworkerthread.h
+ ll_template_cast.h
+ metaclass.h
+ metaclasst.h
+ metaproperty.h
+ metapropertyt.h
+ reflective.h
+ reflectivet.h
+ roles_constants.h
+ stdenums.h
+ stdtypes.h
+ string_table.h
+ stringize.h
+ timer.h
+ timing.h
+ u64.h
+ )
+
+set_source_files_properties(${llcommon_HEADER_FILES}
+ PROPERTIES HEADER_FILE_ONLY TRUE)
+
+list(APPEND llcommon_SOURCE_FILES ${llcommon_HEADER_FILES})
+
+if(LLCOMMON_LINK_SHARED)
+ add_library (llcommon SHARED ${llcommon_SOURCE_FILES})
+ if(NOT WORD_SIZE EQUAL 32)
+ if(WINDOWS)
+ add_definitions(/FIXED:NO)
+ else(WINDOWS) # not windows therefore gcc LINUX and DARWIN
+ add_definitions(-fPIC)
+ endif(WINDOWS)
+ endif(NOT WORD_SIZE EQUAL 32)
+ ll_stage_sharedlib(llcommon)
+else(LLCOMMON_LINK_SHARED)
+ add_library (llcommon ${llcommon_SOURCE_FILES})
+endif(LLCOMMON_LINK_SHARED)
+
+target_link_libraries(
+ llcommon
+ ${BREAKPAD_EXCEPTION_HANDLER_LIBRARIES}
+ ${APRUTIL_LIBRARIES}
+ ${APR_LIBRARIES}
+ ${EXPAT_LIBRARIES}
+ ${ZLIB_LIBRARIES}
+ ${WINDOWS_LIBRARIES}
+ ${BOOST_PROGRAM_OPTIONS_LIBRARY}
+ ${BOOST_REGEX_LIBRARY}
+ ${PTH_LIBRARIES}
+ ${GOOGLE_PERFTOOLS_LIBRARIES}
+ )
+
+add_dependencies(llcommon stage_third_party_libs)
+
+if (LL_TESTS)
+ include(LLAddBuildTest)
+ SET(llcommon_TEST_SOURCE_FILES
+ # unit-testing llcommon is not possible right now as the test-harness *itself* depends upon llcommon, causing a circular dependency. Add your 'unit' tests as integration tests for now.
+ )
+ LL_ADD_PROJECT_UNIT_TESTS(llcommon "${llcommon_TEST_SOURCE_FILES}")
+
+ #set(TEST_DEBUG on)
+ set(test_libs llcommon ${LLCOMMON_LIBRARIES} ${WINDOWS_LIBRARIES} ${GOOGLEMOCK_LIBRARIES})
+ LL_ADD_INTEGRATION_TEST(commonmisc "" "${test_libs}")
+ LL_ADD_INTEGRATION_TEST(bitpack "" "${test_libs}")
+ LL_ADD_INTEGRATION_TEST(llbase64 "" "${test_libs}")
+ LL_ADD_INTEGRATION_TEST(lldate "" "${test_libs}")
+ LL_ADD_INTEGRATION_TEST(lldependencies "" "${test_libs}")
+ LL_ADD_INTEGRATION_TEST(llerror "" "${test_libs}")
+ LL_ADD_INTEGRATION_TEST(llframetimer "" "${test_libs}")
+ LL_ADD_INTEGRATION_TEST(llinstancetracker "" "${test_libs}")
+ LL_ADD_INTEGRATION_TEST(lllazy "" "${test_libs}")
+ LL_ADD_INTEGRATION_TEST(llprocessor "" "${test_libs}")
+ LL_ADD_INTEGRATION_TEST(llrand "" "${test_libs}")
+ LL_ADD_INTEGRATION_TEST(llsdserialize "" "${test_libs}")
+ LL_ADD_INTEGRATION_TEST(llstring "" "${test_libs}")
+ LL_ADD_INTEGRATION_TEST(lltreeiterators "" "${test_libs}")
+ LL_ADD_INTEGRATION_TEST(lluri "" "${test_libs}")
+ LL_ADD_INTEGRATION_TEST(reflection "" "${test_libs}")
+ LL_ADD_INTEGRATION_TEST(stringize "" "${test_libs}")
+
+ # *TODO - reenable these once tcmalloc libs no longer break the build.
+ #ADD_BUILD_TEST(llallocator llcommon)
+ #ADD_BUILD_TEST(llallocator_heap_profile llcommon)
+ #ADD_BUILD_TEST(llmemtype llcommon)
+endif (LL_TESTS)
diff --git a/indra/llcommon/bitpack.cpp b/indra/llcommon/bitpack.cpp
new file mode 100644
index 0000000000..cdcaba0765
--- /dev/null
+++ b/indra/llcommon/bitpack.cpp
@@ -0,0 +1,30 @@
+/**
+ * @file bitpack.cpp
+ * @brief LLBitPack class implementation
+ *
+ * $LicenseInfo:firstyear=2001&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$
+ */
+
+#include "linden_common.h"
+
+// implementation is all in the header, this include dep ensures the unit test is rerun if the implementation changes.
+#include "bitpack.h"
diff --git a/indra/llcommon/bitpack.h b/indra/llcommon/bitpack.h
index 1a382ff53f..037300dd14 100644
--- a/indra/llcommon/bitpack.h
+++ b/indra/llcommon/bitpack.h
@@ -2,30 +2,25 @@
* @file bitpack.h
* @brief Convert data to packed bit stream
*
- * $LicenseInfo:firstyear=2000&license=viewergpl$
- *
- * Copyright (c) 2000-2007, Linden Research, Inc.
- *
+ * $LicenseInfo:firstyear=2000&license=viewerlgpl$
* Second Life Viewer Source Code
- * The source code in this file ("Source Code") is provided by Linden Lab
- * to you under the terms of the GNU General Public License, version 2.0
- * ("GPL"), unless you have obtained a separate licensing agreement
- * ("Other License"), formally executed by you and Linden Lab. Terms of
- * the GPL can be found in doc/GPL-license.txt in this distribution, or
- * online at http://secondlife.com/developers/opensource/gplv2
+ * 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.
*
- * There are special exceptions to the terms and conditions of the GPL as
- * it is applied to this Source Code. View the full text of the exception
- * in the file doc/FLOSS-exception.txt in this software distribution, or
- * online at http://secondlife.com/developers/opensource/flossexception
+ * 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.
*
- * By copying, modifying or distributing this software, you acknowledge
- * that you have read and understood your obligations described above,
- * and agree to abide by those obligations.
+ * 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
*
- * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
- * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
- * COMPLETENESS OR PERFORMANCE.
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
* $/LicenseInfo$
*/
diff --git a/indra/llcommon/ctype_workaround.h b/indra/llcommon/ctype_workaround.h
index 7c730d9d18..552be9fb90 100644
--- a/indra/llcommon/ctype_workaround.h
+++ b/indra/llcommon/ctype_workaround.h
@@ -3,30 +3,25 @@
* @brief The workaround is to create some legacy symbols that point
* to the correct symbols, which avoids link errors.
*
- * $LicenseInfo:firstyear=2006&license=viewergpl$
- *
- * Copyright (c) 2006-2007, Linden Research, Inc.
- *
+ * $LicenseInfo:firstyear=2006&license=viewerlgpl$
* Second Life Viewer Source Code
- * The source code in this file ("Source Code") is provided by Linden Lab
- * to you under the terms of the GNU General Public License, version 2.0
- * ("GPL"), unless you have obtained a separate licensing agreement
- * ("Other License"), formally executed by you and Linden Lab. Terms of
- * the GPL can be found in doc/GPL-license.txt in this distribution, or
- * online at http://secondlife.com/developers/opensource/gplv2
+ * 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.
*
- * There are special exceptions to the terms and conditions of the GPL as
- * it is applied to this Source Code. View the full text of the exception
- * in the file doc/FLOSS-exception.txt in this software distribution, or
- * online at http://secondlife.com/developers/opensource/flossexception
+ * 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.
*
- * By copying, modifying or distributing this software, you acknowledge
- * that you have read and understood your obligations described above,
- * and agree to abide by those obligations.
+ * 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
*
- * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
- * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
- * COMPLETENESS OR PERFORMANCE.
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
* $/LicenseInfo$
*/
diff --git a/indra/llcommon/doublelinkedlist.h b/indra/llcommon/doublelinkedlist.h
index 11cfb48a74..0aeaa69df3 100644
--- a/indra/llcommon/doublelinkedlist.h
+++ b/indra/llcommon/doublelinkedlist.h
@@ -2,30 +2,25 @@
* @file doublelinkedlist.h
* @brief Provides a standard doubly linked list for fun and profit.
*
- * $LicenseInfo:firstyear=2001&license=viewergpl$
- *
- * Copyright (c) 2001-2007, Linden Research, Inc.
- *
+ * $LicenseInfo:firstyear=2001&license=viewerlgpl$
* Second Life Viewer Source Code
- * The source code in this file ("Source Code") is provided by Linden Lab
- * to you under the terms of the GNU General Public License, version 2.0
- * ("GPL"), unless you have obtained a separate licensing agreement
- * ("Other License"), formally executed by you and Linden Lab. Terms of
- * the GPL can be found in doc/GPL-license.txt in this distribution, or
- * online at http://secondlife.com/developers/opensource/gplv2
+ * 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.
*
- * There are special exceptions to the terms and conditions of the GPL as
- * it is applied to this Source Code. View the full text of the exception
- * in the file doc/FLOSS-exception.txt in this software distribution, or
- * online at http://secondlife.com/developers/opensource/flossexception
+ * 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.
*
- * By copying, modifying or distributing this software, you acknowledge
- * that you have read and understood your obligations described above,
- * and agree to abide by those obligations.
+ * 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
*
- * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
- * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
- * COMPLETENESS OR PERFORMANCE.
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
* $/LicenseInfo$
*/
diff --git a/indra/llcommon/imageids.cpp b/indra/llcommon/imageids.cpp
new file mode 100644
index 0000000000..fe11465221
--- /dev/null
+++ b/indra/llcommon/imageids.cpp
@@ -0,0 +1,70 @@
+/**
+ * @file imageids.cpp
+ *
+ * $LicenseInfo:firstyear=2001&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$
+ */
+
+#include "linden_common.h"
+
+#include "imageids.h"
+
+#include "lluuid.h"
+
+//
+// USE OF THIS FILE IS DEPRECATED
+//
+// Please use viewerart.ini and the standard
+// art import path. // indicates if file is only
+ // on dataserver, or also
+ // pre-cached on viewer
+
+// Grass Images
+const LLUUID IMG_SMOKE ("b4ba225c-373f-446d-9f7e-6cb7b5cf9b3d"); // VIEWER
+
+const LLUUID IMG_DEFAULT ("d2114404-dd59-4a4d-8e6c-49359e91bbf0"); // VIEWER
+
+const LLUUID IMG_SUN ("cce0f112-878f-4586-a2e2-a8f104bba271"); // dataserver
+const LLUUID IMG_MOON ("d07f6eed-b96a-47cd-b51d-400ad4a1c428"); // dataserver
+const LLUUID IMG_CLOUD_POOF ("fc4b9f0b-d008-45c6-96a4-01dd947ac621"); // dataserver
+const LLUUID IMG_SHOT ("35f217a3-f618-49cf-bbca-c86d486551a9"); // dataserver
+const LLUUID IMG_SPARK ("d2e75ac1-d0fb-4532-820e-a20034ac814d"); // dataserver
+const LLUUID IMG_FIRE ("aca40aa8-44cf-44ca-a0fa-93e1a2986f82"); // dataserver
+const LLUUID IMG_FACE_SELECT ("a85ac674-cb75-4af6-9499-df7c5aaf7a28"); // face selector
+const LLUUID IMG_DEFAULT_AVATAR ("c228d1cf-4b5d-4ba8-84f4-899a0796aa97"); // dataserver
+const LLUUID IMG_INVISIBLE ("3a367d1c-bef1-6d43-7595-e88c1e3aadb3"); // dataserver
+
+const LLUUID IMG_EXPLOSION ("68edcf47-ccd7-45b8-9f90-1649d7f12806"); // On dataserver
+const LLUUID IMG_EXPLOSION_2 ("21ce046c-83fe-430a-b629-c7660ac78d7c"); // On dataserver
+const LLUUID IMG_EXPLOSION_3 ("fedea30a-1be8-47a6-bc06-337a04a39c4b"); // On dataserver
+const LLUUID IMG_EXPLOSION_4 ("abf0d56b-82e5-47a2-a8ad-74741bb2c29e"); // On dataserver
+const LLUUID IMG_SMOKE_POOF ("1e63e323-5fe0-452e-92f8-b98bd0f764e3"); // On dataserver
+
+const LLUUID IMG_BIG_EXPLOSION_1 ("5e47a0dc-97bf-44e0-8b40-de06718cee9d"); // On dataserver
+const LLUUID IMG_BIG_EXPLOSION_2 ("9c8eca51-53d5-42a7-bb58-cef070395db8"); // On dataserver
+
+const LLUUID IMG_BLOOM1 ("3c59f7fe-9dc8-47f9-8aaf-a9dd1fbc3bef"); // VIEWER
+const LLUUID TERRAIN_DIRT_DETAIL ("0bc58228-74a0-7e83-89bc-5c23464bcec5"); // VIEWER
+const LLUUID TERRAIN_GRASS_DETAIL ("63338ede-0037-c4fd-855b-015d77112fc8"); // VIEWER
+const LLUUID TERRAIN_MOUNTAIN_DETAIL ("303cd381-8560-7579-23f1-f0a880799740"); // VIEWER
+const LLUUID TERRAIN_ROCK_DETAIL ("53a2f406-4895-1d13-d541-d2e3b86bc19c"); // VIEWER
+
+const LLUUID DEFAULT_WATER_NORMAL ("822ded49-9a6c-f61c-cb89-6df54f42cdf4"); // VIEWER
diff --git a/indra/llcommon/imageids.h b/indra/llcommon/imageids.h
index cc7c70e29f..e0c2683fdc 100644
--- a/indra/llcommon/imageids.h
+++ b/indra/llcommon/imageids.h
@@ -2,101 +2,68 @@
* @file imageids.h
* @brief Temporary holder for image IDs
*
- * $LicenseInfo:firstyear=2001&license=viewergpl$
- *
- * Copyright (c) 2001-2007, Linden Research, Inc.
- *
+ * $LicenseInfo:firstyear=2001&license=viewerlgpl$
* Second Life Viewer Source Code
- * The source code in this file ("Source Code") is provided by Linden Lab
- * to you under the terms of the GNU General Public License, version 2.0
- * ("GPL"), unless you have obtained a separate licensing agreement
- * ("Other License"), formally executed by you and Linden Lab. Terms of
- * the GPL can be found in doc/GPL-license.txt in this distribution, or
- * online at http://secondlife.com/developers/opensource/gplv2
+ * 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.
*
- * There are special exceptions to the terms and conditions of the GPL as
- * it is applied to this Source Code. View the full text of the exception
- * in the file doc/FLOSS-exception.txt in this software distribution, or
- * online at http://secondlife.com/developers/opensource/flossexception
+ * 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.
*
- * By copying, modifying or distributing this software, you acknowledge
- * that you have read and understood your obligations described above,
- * and agree to abide by those obligations.
+ * 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
*
- * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
- * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
- * COMPLETENESS OR PERFORMANCE.
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
* $/LicenseInfo$
*/
#ifndef LL_IMAGEIDS_H
#define LL_IMAGEIDS_H
-#include "lluuid.h"
-
//
// USE OF THIS FILE IS DEPRECATED
//
// Please use viewerart.ini and the standard
-// art import path. // indicates if file is only
- // on dataserver, or also
- // pre-cached on viewer
-
-// Grass Images
-//const LLUUID IMG_GRASS1 ("990c4086-46ce-49bd-8cae-afcc23a08f4e"); // dataserver
-//const LLUUID IMG_GRASS2 ("869e2dcf-21b9-402d-a36d-9a23365cf723"); // dataserver
-//const LLUUID IMG_GRASS3 ("8f97e7a7-f664-4967-9e8f-8d9e8039c1b7"); // dataserver
-
-//const LLUUID IMG_GRASS4 ("8a05131d-35b7-4812-bcfc-a989b0f954ef"); // dataserver
-
-//const LLUUID IMG_GRASS5 ("7d092acb-c69a-4122-b09b-f285e009b185"); // dataserver
-
-const LLUUID IMG_CLEAR ("11ee27f5-43c0-414e-afd5-d7f5688c351f"); // VIEWER
-const LLUUID IMG_SMOKE ("b4ba225c-373f-446d-9f7e-6cb7b5cf9b3d"); // VIEWER
-
-const LLUUID IMG_DEFAULT ("d2114404-dd59-4a4d-8e6c-49359e91bbf0"); // VIEWER
+// art import path.
-//const LLUUID IMG_SAND ("0ff70ead-4562-45f9-9e8a-52b1a3286868"); // VIEWER 1.5k
-//const LLUUID IMG_GRASS ("5ab48dd5-05d0-4f1a-ace6-efd4e2fb3508"); // VIEWER 1.2k
-//const LLUUID IMG_ROCK ("402f8b24-5f9d-4905-b5f8-37baff603e88"); // VIEWER 1.2k
-//const LLUUID IMG_ROCKFACE ("9c88539c-fd04-46b8-bea2-ddf1bcffe3bd"); // VIEWER 1.2k
-const LLUUID IMG_SUN ("cce0f112-878f-4586-a2e2-a8f104bba271"); // dataserver
-const LLUUID IMG_MOON ("d07f6eed-b96a-47cd-b51d-400ad4a1c428"); // dataserver
-const LLUUID IMG_CLOUD_POOF ("fc4b9f0b-d008-45c6-96a4-01dd947ac621"); // dataserver
-const LLUUID IMG_SHOT ("35f217a3-f618-49cf-bbca-c86d486551a9"); // dataserver
-const LLUUID IMG_SPARK ("d2e75ac1-d0fb-4532-820e-a20034ac814d"); // dataserver
-const LLUUID IMG_FIRE ("aca40aa8-44cf-44ca-a0fa-93e1a2986f82"); // dataserver
-//const LLUUID IMG_WATER ("e510b068-d20d-4612-a08d-fde4d5c15789"); // VIEWER
-const LLUUID IMG_FACE_SELECT ("a85ac674-cb75-4af6-9499-df7c5aaf7a28"); // face selector
+class LLUUID;
-//const LLUUID IMG_SHADOW ("5e1de0a8-f9f8-4237-9396-d221126a7c4a"); // dataserver
-//const LLUUID IMG_AVATARSHADOW ("c7d8bbf3-21ee-4f6e-9b20-3cf18425af1d"); // dataserver
-//const LLUUID IMG_BOXSHADOW ("8d86b8cc-4889-408a-8b72-c1961bae53d7"); // dataserver
-//const LLUUID IMG_EYE ("5e3551ae-9971-4814-af99-5117591e937b"); // dataserver
-//const LLUUID IMG_BLUE_FLAME ("d8b62059-7b31-4511-a479-1fe45117948f"); // dataserver
+LL_COMMON_API extern const LLUUID IMG_SMOKE;
-const LLUUID IMG_DEFAULT_AVATAR ("c228d1cf-4b5d-4ba8-84f4-899a0796aa97"); // dataserver
-//const LLUUID IMG_ENERGY_BEAM ("09e7bc54-11b9-442a-ae3d-f52e599e466a"); // dataserver
-//const LLUUID IMG_ENERGY_BEAM2 ("de651394-f926-48db-b666-e49d83af1bbc"); // dataserver
+LL_COMMON_API extern const LLUUID IMG_DEFAULT;
-//const LLUUID IMG_BRICK_PATH ("a9d0019b-3783-4c7f-959c-322d301918bc"); // dataserver
+LL_COMMON_API extern const LLUUID IMG_SUN;
+LL_COMMON_API extern const LLUUID IMG_MOON;
+LL_COMMON_API extern const LLUUID IMG_CLOUD_POOF;
+LL_COMMON_API extern const LLUUID IMG_SHOT;
+LL_COMMON_API extern const LLUUID IMG_SPARK;
+LL_COMMON_API extern const LLUUID IMG_FIRE;
+LL_COMMON_API extern const LLUUID IMG_FACE_SELECT;
+LL_COMMON_API extern const LLUUID IMG_DEFAULT_AVATAR;
+LL_COMMON_API extern const LLUUID IMG_INVISIBLE;
-const LLUUID IMG_EXPLOSION ("68edcf47-ccd7-45b8-9f90-1649d7f12806"); // On dataserver
-const LLUUID IMG_EXPLOSION_2 ("21ce046c-83fe-430a-b629-c7660ac78d7c"); // On dataserver
-const LLUUID IMG_EXPLOSION_3 ("fedea30a-1be8-47a6-bc06-337a04a39c4b"); // On dataserver
-const LLUUID IMG_EXPLOSION_4 ("abf0d56b-82e5-47a2-a8ad-74741bb2c29e"); // On dataserver
-//const LLUUID IMG_EXPLOSION_5 ("60f2dec7-675b-4950-b614-85b907d552ea"); // On dataserver
-//const LLUUID IMG_SPLASH_SPRITE ("8a101f63-fe45-49e7-9f8a-e64817daa475"); // On dataserver
-const LLUUID IMG_SMOKE_POOF ("1e63e323-5fe0-452e-92f8-b98bd0f764e3"); // On dataserver
+LL_COMMON_API extern const LLUUID IMG_EXPLOSION;
+LL_COMMON_API extern const LLUUID IMG_EXPLOSION_2;
+LL_COMMON_API extern const LLUUID IMG_EXPLOSION_3;
+LL_COMMON_API extern const LLUUID IMG_EXPLOSION_4;
+LL_COMMON_API extern const LLUUID IMG_SMOKE_POOF;
-const LLUUID IMG_BIG_EXPLOSION_1 ("5e47a0dc-97bf-44e0-8b40-de06718cee9d"); // On dataserver
-const LLUUID IMG_BIG_EXPLOSION_2 ("9c8eca51-53d5-42a7-bb58-cef070395db8"); // On dataserver
-//const LLUUID IMG_BLUE_BLOOD ("8bc2e3f8-097e-4c87-b417-b0d699d07189"); // On dataserver
+LL_COMMON_API extern const LLUUID IMG_BIG_EXPLOSION_1;
+LL_COMMON_API extern const LLUUID IMG_BIG_EXPLOSION_2;
-const LLUUID IMG_BLOOM1 ("3c59f7fe-9dc8-47f9-8aaf-a9dd1fbc3bef");
-//const LLUUID IMG_BLOOM2 ("9fb76e81-eca0-4b6a-96e1-a6c5a685150b");
-//const LLUUID IMG_BLOOM3 ("fb1fecba-9585-415b-ad15-6e6e3d6c5479");
+LL_COMMON_API extern const LLUUID IMG_BLOOM1;
+LL_COMMON_API extern const LLUUID TERRAIN_DIRT_DETAIL;
+LL_COMMON_API extern const LLUUID TERRAIN_GRASS_DETAIL;
+LL_COMMON_API extern const LLUUID TERRAIN_MOUNTAIN_DETAIL;
+LL_COMMON_API extern const LLUUID TERRAIN_ROCK_DETAIL;
-const LLUUID IMG_PTT_SPEAKER ("89e9fc7c-0b16-457d-be4f-136270759c4d"); // On cache
+LL_COMMON_API extern const LLUUID DEFAULT_WATER_NORMAL;
#endif
diff --git a/indra/llcommon/indra_constants.cpp b/indra/llcommon/indra_constants.cpp
new file mode 100644
index 0000000000..d32ae6c041
--- /dev/null
+++ b/indra/llcommon/indra_constants.cpp
@@ -0,0 +1,40 @@
+/**
+ * @file indra_constants.cpp
+ * @brief some useful short term constants for Indra
+ *
+ * $LicenseInfo:firstyear=2001&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$
+ */
+#include "linden_common.h"
+
+#include "indra_constants.h"
+
+#include "lluuid.h"
+
+// "agent id" for things that should be done to ALL agents
+const LLUUID LL_UUID_ALL_AGENTS("44e87126-e794-4ded-05b3-7c42da3d5cdb");
+
+// Governor Linden's agent id.
+const LLUUID ALEXANDRIA_LINDEN_ID("ba2a564a-f0f1-4b82-9c61-b7520bfcd09f");
+const LLUUID GOVERNOR_LINDEN_ID("3d6181b0-6a4b-97ef-18d8-722652995cf1");
+const LLUUID REALESTATE_LINDEN_ID("3d6181b0-6a4b-97ef-18d8-722652995cf1");
+// Maintenance's group id.
+const LLUUID MAINTENANCE_GROUP_ID("dc7b21cd-3c89-fcaa-31c8-25f9ffd224cd");
diff --git a/indra/llcommon/indra_constants.h b/indra/llcommon/indra_constants.h
index 89b276e3b3..b0618bfe59 100644
--- a/indra/llcommon/indra_constants.h
+++ b/indra/llcommon/indra_constants.h
@@ -2,30 +2,25 @@
* @file indra_constants.h
* @brief some useful short term constants for Indra
*
- * $LicenseInfo:firstyear=2001&license=viewergpl$
- *
- * Copyright (c) 2001-2007, Linden Research, Inc.
- *
+ * $LicenseInfo:firstyear=2001&license=viewerlgpl$
* Second Life Viewer Source Code
- * The source code in this file ("Source Code") is provided by Linden Lab
- * to you under the terms of the GNU General Public License, version 2.0
- * ("GPL"), unless you have obtained a separate licensing agreement
- * ("Other License"), formally executed by you and Linden Lab. Terms of
- * the GPL can be found in doc/GPL-license.txt in this distribution, or
- * online at http://secondlife.com/developers/opensource/gplv2
+ * 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.
*
- * There are special exceptions to the terms and conditions of the GPL as
- * it is applied to this Source Code. View the full text of the exception
- * in the file doc/FLOSS-exception.txt in this software distribution, or
- * online at http://secondlife.com/developers/opensource/flossexception
+ * 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.
*
- * By copying, modifying or distributing this software, you acknowledge
- * that you have read and understood your obligations described above,
- * and agree to abide by those obligations.
+ * 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
*
- * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
- * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
- * COMPLETENESS OR PERFORMANCE.
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
* $/LicenseInfo$
*/
@@ -33,14 +28,20 @@
#define LL_INDRA_CONSTANTS_H
#include "stdtypes.h"
-#include "lluuid.h"
+
+class LLUUID;
// At 45 Hz collisions seem stable and objects seem
// to settle down at a reasonable rate.
// JC 3/18/2003
-const F32 HAVOK_TIMESTEP = 1.f / 45.f;
+
+// const F32 PHYSICS_TIMESTEP = 1.f / 45.f;
+// This must be a #define due to anal retentive restrictions on const expressions
+// CG 2008-06-05
+#define PHYSICS_TIMESTEP (1.f / 45.f)
const F32 COLLISION_TOLERANCE = 0.1f;
+const F32 HALF_COLLISION_TOLERANCE = 0.05f;
// Time constants
const U32 HOURS_PER_LINDEN_DAY = 4;
@@ -49,9 +50,11 @@ const U32 DAYS_PER_LINDEN_YEAR = 11;
const U32 SEC_PER_LINDEN_DAY = HOURS_PER_LINDEN_DAY * 60 * 60;
const U32 SEC_PER_LINDEN_YEAR = DAYS_PER_LINDEN_YEAR * SEC_PER_LINDEN_DAY;
-const F32 REGION_WIDTH_METERS = 256.f;
-const S32 REGION_WIDTH_UNITS = 256;
-const U32 REGION_WIDTH_U32 = 256;
+static const F32 REGION_WIDTH_METERS = 256.f;
+static const S32 REGION_WIDTH_UNITS = 256;
+static const U32 REGION_WIDTH_U32 = 256;
+
+const F32 REGION_HEIGHT_METERS = 4096.f;
// Bits for simulator performance query flags
enum LAND_STAT_FLAGS
@@ -70,8 +73,16 @@ enum LAND_STAT_REPORT_TYPE
const U32 STAT_FILTER_MASK = 0x1FFFFFFF;
+// Region absolute limits
+static const S32 REGION_AGENT_COUNT_MIN = 1;
+static const S32 REGION_AGENT_COUNT_MAX = 200; // Must fit in U8 for the moment (RegionInfo msg)
+static const S32 REGION_PRIM_COUNT_MIN = 0;
+static const S32 REGION_PRIM_COUNT_MAX = 40000;
+static const F32 REGION_PRIM_BONUS_MIN = 1.0;
+static const F32 REGION_PRIM_BONUS_MAX = 10.0;
+
// Default maximum number of tasks/prims per region.
-const U32 MAX_TASKS_PER_REGION = 15000;
+const U32 DEFAULT_MAX_REGION_WIDE_PRIM_COUNT = 15000;
const F32 MIN_AGENT_DEPTH = 0.30f;
const F32 DEFAULT_AGENT_DEPTH = 0.45f;
@@ -81,13 +92,13 @@ const F32 MIN_AGENT_WIDTH = 0.40f;
const F32 DEFAULT_AGENT_WIDTH = 0.60f;
const F32 MAX_AGENT_WIDTH = 0.80f;
-const F32 MIN_AGENT_HEIGHT = 1.3f - 2.0f * COLLISION_TOLERANCE;
+const F32 MIN_AGENT_HEIGHT = 1.1f;
const F32 DEFAULT_AGENT_HEIGHT = 1.9f;
-const F32 MAX_AGENT_HEIGHT = 2.65f - 2.0f * COLLISION_TOLERANCE;
+const F32 MAX_AGENT_HEIGHT = 2.45f;
// For linked sets
const S32 MAX_CHILDREN_PER_TASK = 255;
-const S32 MAX_CHILDREN_PER_PHYSICAL_TASK = 31;
+const S32 MAX_CHILDREN_PER_PHYSICAL_TASK = 32;
const S32 MAX_JOINTS_PER_OBJECT = 1; // limiting to 1 until Havok 2.x
@@ -102,6 +113,7 @@ const char* const DEFAULT_AGNI_DATA_SERVER = "63.211.139.100";
const char* const DEFAULT_AGNI_ASSET_SERVER = "http://asset.agni.lindenlab.com:80";
// Information about what ports are for what services is in the wiki Name Space Ports page
+// https://wiki.lindenlab.com/wiki/Name_Space_Ports
const char* const DEFAULT_LOCAL_ASSET_SERVER = "http://localhost:12041/asset/tmp";
const char* const LOCAL_ASSET_URL_FORMAT = "http://%s:12041/asset";
@@ -122,6 +134,10 @@ const U32 DEFAULT_CAP_PROXY_PORT = 12043;
const U32 DEFAULT_INV_DATA_SERVER_PORT = 12044;
const U32 DEFAULT_CGI_SERVICES_PORT = 12045;
+// Mapserver uses ports 12124 - 12139 to allow multiple mapservers to run
+// on a single host for map tile generation. JC
+const U32 DEFAULT_MAPSERVER_PORT = 12124;
+
// For automatic port discovery when running multiple viewers on one host
const U32 PORT_DISCOVERY_RANGE_MIN = 13000;
const U32 PORT_DISCOVERY_RANGE_MAX = PORT_DISCOVERY_RANGE_MIN + 50;
@@ -222,16 +238,20 @@ const S32 KEY_COUNT = 256;
const F32 DEFAULT_WATER_HEIGHT = 20.0f;
// Maturity ratings for simulators
-const U8 SIM_ACCESS_MIN = 0;
-const U8 SIM_ACCESS_TRIAL = 7;
+const U8 SIM_ACCESS_MIN = 0; // Treated as 'unknown', usually ends up being SIM_ACCESS_PG
const U8 SIM_ACCESS_PG = 13;
const U8 SIM_ACCESS_MATURE = 21;
+const U8 SIM_ACCESS_ADULT = 42; // Seriously Adult Only
const U8 SIM_ACCESS_DOWN = 254;
-const U8 SIM_ACCESS_MAX = SIM_ACCESS_MATURE;
+const U8 SIM_ACCESS_MAX = SIM_ACCESS_ADULT;
// group constants
const S32 MAX_AGENT_GROUPS = 25;
+// attachment constants
+const S32 MAX_AGENT_ATTACHMENTS = 38;
+const U8 ATTACHMENT_ADD = 0x80;
+
// god levels
const U8 GOD_MAINTENANCE = 250;
const U8 GOD_FULL = 200;
@@ -241,13 +261,15 @@ const U8 GOD_LIKE = 1;
const U8 GOD_NOT = 0;
// "agent id" for things that should be done to ALL agents
-const LLUUID LL_UUID_ALL_AGENTS("44e87126-e794-4ded-05b3-7c42da3d5cdb");
+LL_COMMON_API extern const LLUUID LL_UUID_ALL_AGENTS;
+
+// inventory library owner
+LL_COMMON_API extern const LLUUID ALEXANDRIA_LINDEN_ID;
-// Governor Linden's agent id.
-const LLUUID GOVERNOR_LINDEN_ID("3d6181b0-6a4b-97ef-18d8-722652995cf1");
-const LLUUID REALESTATE_LINDEN_ID("3d6181b0-6a4b-97ef-18d8-722652995cf1");
+LL_COMMON_API extern const LLUUID GOVERNOR_LINDEN_ID;
+LL_COMMON_API extern const LLUUID REALESTATE_LINDEN_ID;
// Maintenance's group id.
-const LLUUID MAINTENANCE_GROUP_ID("dc7b21cd-3c89-fcaa-31c8-25f9ffd224cd");
+LL_COMMON_API extern const LLUUID MAINTENANCE_GROUP_ID;
// Flags for kick message
const U32 KICK_FLAGS_DEFAULT = 0x0;
@@ -264,6 +286,7 @@ const U8 UPD_UNIFORM = 0x10; // used with UPD_SCALE
// Agent Update Flags (U8)
const U8 AU_FLAGS_NONE = 0x00;
const U8 AU_FLAGS_HIDETITLE = 0x01;
+const U8 AU_FLAGS_CLIENT_AUTOPILOT = 0x02;
// start location constants
const U32 START_LOCATION_ID_LAST = 0;
@@ -332,11 +355,23 @@ const U32 PARCEL_MEDIA_COMMAND_LOOP_SET = 13;
const U32 MAP_ITEM_TELEHUB = 0x01;
const U32 MAP_ITEM_PG_EVENT = 0x02;
const U32 MAP_ITEM_MATURE_EVENT = 0x03;
-const U32 MAP_ITEM_POPULAR = 0x04;
+//const U32 MAP_ITEM_POPULAR = 0x04; // No longer supported, 2009-03-02 KLW
//const U32 MAP_ITEM_AGENT_COUNT = 0x05;
const U32 MAP_ITEM_AGENT_LOCATIONS = 0x06;
const U32 MAP_ITEM_LAND_FOR_SALE = 0x07;
const U32 MAP_ITEM_CLASSIFIED = 0x08;
+const U32 MAP_ITEM_ADULT_EVENT = 0x09;
+const U32 MAP_ITEM_LAND_FOR_SALE_ADULT = 0x0a;
+
+// Region map layer numbers
+const S32 MAP_SIM_OBJECTS = 0;
+const S32 MAP_SIM_TERRAIN = 1;
+const S32 MAP_SIM_LAND_FOR_SALE = 2; // Transparent alpha overlay of land for sale
+const S32 MAP_SIM_IMAGE_TYPES = 3; // Number of map layers
+const S32 MAP_SIM_INFO_MASK = 0x00FFFFFF; // Agent access may be stuffed into upper byte
+const S32 MAP_SIM_LAYER_MASK = 0x0000FFFF; // Layer info is in lower 16 bits
+const S32 MAP_SIM_RETURN_NULL_SIMS = 0x00010000;
+const S32 MAP_SIM_PRELUDE = 0x00020000;
// Crash reporter behavior
const char* const CRASH_SETTINGS_FILE = "settings_crash_behavior.xml";
diff --git a/indra/llcommon/is_approx_equal_fraction.h b/indra/llcommon/is_approx_equal_fraction.h
new file mode 100644
index 0000000000..4a9b2e2725
--- /dev/null
+++ b/indra/llcommon/is_approx_equal_fraction.h
@@ -0,0 +1,79 @@
+/**
+ * @file is_approx_equal_fraction.h
+ * @author Nat Goodspeed
+ * @date 2009-01-28
+ * @brief lltut.h uses is_approx_equal_fraction(). Moved to this header
+ * file in llcommon so we can use lltut.h for llcommon tests without
+ * making llcommon depend on llmath.
+ *
+ * $LicenseInfo:firstyear=2009&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_IS_APPROX_EQUAL_FRACTION_H)
+#define LL_IS_APPROX_EQUAL_FRACTION_H
+
+#include "lldefs.h"
+#include <cmath>
+
+/**
+ * Originally llmath.h contained two complete implementations of
+ * is_approx_equal_fraction(), with signatures as below, bodies identical save
+ * where they specifically mentioned F32/F64. Unifying these into a template
+ * makes sense -- but to preserve the compiler's overload-selection behavior,
+ * we still wrap the template implementation with the specific overloaded
+ * signatures.
+ */
+template <typename FTYPE>
+inline BOOL is_approx_equal_fraction_impl(FTYPE x, FTYPE y, U32 frac_bits)
+{
+ BOOL ret = TRUE;
+ FTYPE diff = (FTYPE) fabs(x - y);
+
+ S32 diffInt = (S32) diff;
+ S32 diffFracTolerance = (S32) ((diff - (FTYPE) diffInt) * (1 << frac_bits));
+
+ // if integer portion is not equal, not enough bits were used for packing
+ // so error out since either the use case is not correct OR there is
+ // an issue with pack/unpack. should fail in either case.
+ // for decimal portion, make sure that the delta is no more than 1
+ // based on the number of bits used for packing decimal portion.
+ if (diffInt != 0 || diffFracTolerance > 1)
+ {
+ ret = FALSE;
+ }
+
+ return ret;
+}
+
+/// F32 flavor
+inline BOOL is_approx_equal_fraction(F32 x, F32 y, U32 frac_bits)
+{
+ return is_approx_equal_fraction_impl<F32>(x, y, frac_bits);
+}
+
+/// F64 flavor
+inline BOOL is_approx_equal_fraction(F64 x, F64 y, U32 frac_bits)
+{
+ return is_approx_equal_fraction_impl<F64>(x, y, frac_bits);
+}
+
+#endif /* ! defined(LL_IS_APPROX_EQUAL_FRACTION_H) */
diff --git a/indra/llcommon/linden_common.h b/indra/llcommon/linden_common.h
index 9ee4d1159e..bdcc98e402 100644
--- a/indra/llcommon/linden_common.h
+++ b/indra/llcommon/linden_common.h
@@ -2,36 +2,44 @@
* @file linden_common.h
* @brief Includes common headers that are always safe to include
*
- * $LicenseInfo:firstyear=2001&license=viewergpl$
- *
- * Copyright (c) 2001-2007, Linden Research, Inc.
- *
+ * $LicenseInfo:firstyear=2001&license=viewerlgpl$
* Second Life Viewer Source Code
- * The source code in this file ("Source Code") is provided by Linden Lab
- * to you under the terms of the GNU General Public License, version 2.0
- * ("GPL"), unless you have obtained a separate licensing agreement
- * ("Other License"), formally executed by you and Linden Lab. Terms of
- * the GPL can be found in doc/GPL-license.txt in this distribution, or
- * online at http://secondlife.com/developers/opensource/gplv2
+ * 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.
*
- * There are special exceptions to the terms and conditions of the GPL as
- * it is applied to this Source Code. View the full text of the exception
- * in the file doc/FLOSS-exception.txt in this software distribution, or
- * online at http://secondlife.com/developers/opensource/flossexception
+ * 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.
*
- * By copying, modifying or distributing this software, you acknowledge
- * that you have read and understood your obligations described above,
- * and agree to abide by those obligations.
+ * 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
*
- * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
- * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
- * COMPLETENESS OR PERFORMANCE.
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
* $/LicenseInfo$
*/
#ifndef LL_LINDEN_COMMON_H
#define LL_LINDEN_COMMON_H
+// *NOTE: Please keep includes here to a minimum!
+//
+// Files included here are included in every library .cpp file and
+// are not precompiled.
+
+#if defined(LL_WINDOWS) && defined(_DEBUG)
+# if _MSC_VER >= 1400 // Visual C++ 2005 or later
+# define _CRTDBG_MAP_ALLOC
+# include <stdlib.h>
+# include <crtdbg.h>
+# endif
+#endif
+
#include "llpreprocessor.h"
#include <cstring>
@@ -42,41 +50,36 @@
#include <cstdio>
#include <cstdlib>
#include <ctime>
-#include <iostream>
-#include <fstream>
+#include <iosfwd>
-// Work around stupid Microsoft STL warning
+// Work around Microsoft compiler warnings in STL headers
#ifdef LL_WINDOWS
-#pragma warning (disable : 4702) // warning C4702: unreachable code
+#pragma warning (disable : 4702) // unreachable code
+#pragma warning (disable : 4244) // conversion from time_t to S32
#endif // LL_WINDOWS
-#include <algorithm>
+// *TODO: Eliminate these, most library .cpp files don't need them.
+// Add them to llviewerprecompiledheaders.h if necessary.
#include <list>
#include <map>
#include <vector>
#include <string>
#ifdef LL_WINDOWS
-#pragma warning (3 : 4702) // we like level 3, not 4
-// level 4 warnings that we need to disable:
-#pragma warning (disable : 4100) // unreferenced formal parameter
-#pragma warning (disable : 4127) // conditional expression is constant (e.g. while(1) )
-#pragma warning (disable : 4244) // possible loss of data on conversions
-#pragma warning (disable : 4396) // the inline specifier cannot be used when a friend declaration refers to a specialization of a function template
-#pragma warning (disable : 4512) // assignment operator could not be generated
-#pragma warning (disable : 4706) // assignment within conditional (even if((x = y)) )
+// Reenable warnings we disabled above
+#pragma warning (3 : 4702) // unreachable code, we like level 3, not 4
+// moved msvc warnings to llpreprocessor.h *TODO - delete this comment after merge conflicts are unlikely -brad
#endif // LL_WINDOWS
// Linden only libs in alpha-order other than stdtypes.h
+// *NOTE: Please keep includes here to a minimum, see above.
#include "stdtypes.h"
#include "lldefs.h"
#include "llerror.h"
#include "llextendedstatus.h"
-#include "llfasttimer.h"
+// Don't do this, adds 15K lines of header code to every library file.
+//#include "llfasttimer.h"
#include "llfile.h"
#include "llformat.h"
-#include "llstring.h"
-#include "llsys.h"
-#include "lltimer.h"
#endif
diff --git a/indra/llcommon/linked_lists.h b/indra/llcommon/linked_lists.h
index 0162a077a2..6b25295b7b 100644
--- a/indra/llcommon/linked_lists.h
+++ b/indra/llcommon/linked_lists.h
@@ -2,30 +2,25 @@
* @file linked_lists.h
* @brief LLLinkedList class header amd implementation file.
*
- * $LicenseInfo:firstyear=2001&license=viewergpl$
- *
- * Copyright (c) 2001-2007, Linden Research, Inc.
- *
+ * $LicenseInfo:firstyear=2001&license=viewerlgpl$
* Second Life Viewer Source Code
- * The source code in this file ("Source Code") is provided by Linden Lab
- * to you under the terms of the GNU General Public License, version 2.0
- * ("GPL"), unless you have obtained a separate licensing agreement
- * ("Other License"), formally executed by you and Linden Lab. Terms of
- * the GPL can be found in doc/GPL-license.txt in this distribution, or
- * online at http://secondlife.com/developers/opensource/gplv2
+ * 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.
*
- * There are special exceptions to the terms and conditions of the GPL as
- * it is applied to this Source Code. View the full text of the exception
- * in the file doc/FLOSS-exception.txt in this software distribution, or
- * online at http://secondlife.com/developers/opensource/flossexception
+ * 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.
*
- * By copying, modifying or distributing this software, you acknowledge
- * that you have read and understood your obligations described above,
- * and agree to abide by those obligations.
+ * 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
*
- * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
- * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
- * COMPLETENESS OR PERFORMANCE.
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
* $/LicenseInfo$
*/
diff --git a/indra/llcommon/ll_template_cast.h b/indra/llcommon/ll_template_cast.h
new file mode 100644
index 0000000000..c8f9a2f7eb
--- /dev/null
+++ b/indra/llcommon/ll_template_cast.h
@@ -0,0 +1,177 @@
+/**
+ * @file ll_template_cast.h
+ * @author Nat Goodspeed
+ * @date 2009-11-21
+ * @brief Define ll_template_cast function
+ *
+ * $LicenseInfo:firstyear=2009&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_LL_TEMPLATE_CAST_H)
+#define LL_LL_TEMPLATE_CAST_H
+
+/**
+ * Implementation for ll_template_cast() (q.v.).
+ *
+ * Default implementation: trying to cast two completely unrelated types
+ * returns 0. Typically you'd specify T and U as pointer types, but in fact T
+ * can be any type that can be initialized with 0.
+ */
+template <typename T, typename U>
+struct ll_template_cast_impl
+{
+ T operator()(U)
+ {
+ return 0;
+ }
+};
+
+/**
+ * ll_template_cast<T>(some_value) is for use in a template function when
+ * some_value might be of arbitrary type, but you want to recognize type T
+ * specially.
+ *
+ * It's designed for use with pointer types. Example:
+ * @code
+ * struct SpecialClass
+ * {
+ * void someMethod(const std::string&) const;
+ * };
+ *
+ * template <class REALCLASS>
+ * void somefunc(const REALCLASS& instance)
+ * {
+ * const SpecialClass* ptr = ll_template_cast<const SpecialClass*>(&instance);
+ * if (ptr)
+ * {
+ * ptr->someMethod("Call method only available on SpecialClass");
+ * }
+ * }
+ * @endcode
+ *
+ * Why is this better than dynamic_cast<>? Because unless OtherClass is
+ * polymorphic, the following won't even compile (gcc 4.0.1):
+ * @code
+ * OtherClass other;
+ * SpecialClass* ptr = dynamic_cast<SpecialClass*>(&other);
+ * @endcode
+ * to say nothing of this:
+ * @code
+ * void function(int);
+ * SpecialClass* ptr = dynamic_cast<SpecialClass*>(&function);
+ * @endcode
+ * ll_template_cast handles these kinds of cases by returning 0.
+ */
+template <typename T, typename U>
+T ll_template_cast(U value)
+{
+ return ll_template_cast_impl<T, U>()(value);
+}
+
+/**
+ * Implementation for ll_template_cast() (q.v.).
+ *
+ * Implementation for identical types: return same value.
+ */
+template <typename T>
+struct ll_template_cast_impl<T, T>
+{
+ T operator()(T value)
+ {
+ return value;
+ }
+};
+
+/**
+ * LL_TEMPLATE_CONVERTIBLE(dest, source) asserts that, for a value @c s of
+ * type @c source, <tt>ll_template_cast<dest>(s)</tt> will return @c s --
+ * presuming that @c source can be converted to @c dest by the normal rules of
+ * C++.
+ *
+ * By default, <tt>ll_template_cast<dest>(s)</tt> will return 0 unless @c s's
+ * type is literally identical to @c dest. (This is because of the
+ * straightforward application of template specialization rules.) That can
+ * lead to surprising results, e.g.:
+ *
+ * @code
+ * Foo myFoo;
+ * const Foo* fooptr = ll_template_cast<const Foo*>(&myFoo);
+ * @endcode
+ *
+ * Here @c fooptr will be 0 because <tt>&myFoo</tt> is of type <tt>Foo*</tt>
+ * -- @em not <tt>const Foo*</tt>. (Declaring <tt>const Foo myFoo;</tt> would
+ * force the compiler to do the right thing.)
+ *
+ * More disappointingly:
+ * @code
+ * struct Base {};
+ * struct Subclass: public Base {};
+ * Subclass object;
+ * Base* ptr = ll_template_cast<Base*>(&object);
+ * @endcode
+ *
+ * Here @c ptr will be 0 because <tt>&object</tt> is of type
+ * <tt>Subclass*</tt> rather than <tt>Base*</tt>. We @em want this cast to
+ * succeed, but without our help ll_template_cast can't recognize it.
+ *
+ * The following would suffice:
+ * @code
+ * LL_TEMPLATE_CONVERTIBLE(Base*, Subclass*);
+ * ...
+ * Base* ptr = ll_template_cast<Base*>(&object);
+ * @endcode
+ *
+ * However, as noted earlier, this is easily fooled:
+ * @code
+ * const Base* ptr = ll_template_cast<const Base*>(&object);
+ * @endcode
+ * would still produce 0 because we haven't yet seen:
+ * @code
+ * LL_TEMPLATE_CONVERTIBLE(const Base*, Subclass*);
+ * @endcode
+ *
+ * @TODO
+ * This macro should use Boost type_traits facilities for stripping and
+ * re-adding @c const and @c volatile qualifiers so that invoking
+ * LL_TEMPLATE_CONVERTIBLE(dest, source) will automatically generate all
+ * permitted permutations. It's really not fair to the coder to require
+ * separate:
+ * @code
+ * LL_TEMPLATE_CONVERTIBLE(Base*, Subclass*);
+ * LL_TEMPLATE_CONVERTIBLE(const Base*, Subclass*);
+ * LL_TEMPLATE_CONVERTIBLE(const Base*, const Subclass*);
+ * @endcode
+ *
+ * (Naturally we omit <tt>LL_TEMPLATE_CONVERTIBLE(Base*, const Subclass*)</tt>
+ * because that's not permitted by normal C++ assignment anyway.)
+ */
+#define LL_TEMPLATE_CONVERTIBLE(DEST, SOURCE) \
+template <> \
+struct ll_template_cast_impl<DEST, SOURCE> \
+{ \
+ DEST operator()(SOURCE wrapper) \
+ { \
+ return wrapper; \
+ } \
+}
+
+#endif /* ! defined(LL_LL_TEMPLATE_CAST_H) */
diff --git a/indra/llcommon/llagentconstants.h b/indra/llcommon/llagentconstants.h
index 2989d6d7d4..cd237da4eb 100644
--- a/indra/llcommon/llagentconstants.h
+++ b/indra/llcommon/llagentconstants.h
@@ -3,30 +3,25 @@
* @author James Cook, Andrew Meadows, Richard Nelson
* @brief Shared constants through the system for agents.
*
- * $LicenseInfo:firstyear=2006&license=viewergpl$
- *
- * Copyright (c) 2006-2007, Linden Research, Inc.
- *
+ * $LicenseInfo:firstyear=2006&license=viewerlgpl$
* Second Life Viewer Source Code
- * The source code in this file ("Source Code") is provided by Linden Lab
- * to you under the terms of the GNU General Public License, version 2.0
- * ("GPL"), unless you have obtained a separate licensing agreement
- * ("Other License"), formally executed by you and Linden Lab. Terms of
- * the GPL can be found in doc/GPL-license.txt in this distribution, or
- * online at http://secondlife.com/developers/opensource/gplv2
+ * 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.
*
- * There are special exceptions to the terms and conditions of the GPL as
- * it is applied to this Source Code. View the full text of the exception
- * in the file doc/FLOSS-exception.txt in this software distribution, or
- * online at http://secondlife.com/developers/opensource/flossexception
+ * 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.
*
- * By copying, modifying or distributing this software, you acknowledge
- * that you have read and understood your obligations described above,
- * and agree to abide by those obligations.
+ * 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
*
- * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
- * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
- * COMPLETENESS OR PERFORMANCE.
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
* $/LicenseInfo$
*/
@@ -67,43 +62,43 @@ const U32 CONTROL_ML_LBUTTON_DOWN_INDEX = 30;
const U32 CONTROL_ML_LBUTTON_UP_INDEX = 31;
const U32 TOTAL_CONTROLS = 32;
-const U32 AGENT_CONTROL_AT_POS = 0x1 << CONTROL_AT_POS_INDEX;
-const U32 AGENT_CONTROL_AT_NEG = 0x1 << CONTROL_AT_NEG_INDEX;
-const U32 AGENT_CONTROL_LEFT_POS = 0x1 << CONTROL_LEFT_POS_INDEX;
-const U32 AGENT_CONTROL_LEFT_NEG = 0x1 << CONTROL_LEFT_NEG_INDEX;
-const U32 AGENT_CONTROL_UP_POS = 0x1 << CONTROL_UP_POS_INDEX;
-const U32 AGENT_CONTROL_UP_NEG = 0x1 << CONTROL_UP_NEG_INDEX;
-const U32 AGENT_CONTROL_PITCH_POS = 0x1 << CONTROL_PITCH_POS_INDEX;
-const U32 AGENT_CONTROL_PITCH_NEG = 0x1 << CONTROL_PITCH_NEG_INDEX;
-const U32 AGENT_CONTROL_YAW_POS = 0x1 << CONTROL_YAW_POS_INDEX;
-const U32 AGENT_CONTROL_YAW_NEG = 0x1 << CONTROL_YAW_NEG_INDEX;
-
-const U32 AGENT_CONTROL_FAST_AT = 0x1 << CONTROL_FAST_AT_INDEX;
-const U32 AGENT_CONTROL_FAST_LEFT = 0x1 << CONTROL_FAST_LEFT_INDEX;
-const U32 AGENT_CONTROL_FAST_UP = 0x1 << CONTROL_FAST_UP_INDEX;
-
-const U32 AGENT_CONTROL_FLY = 0x1 << CONTROL_FLY_INDEX;
-const U32 AGENT_CONTROL_STOP = 0x1 << CONTROL_STOP_INDEX;
-const U32 AGENT_CONTROL_FINISH_ANIM = 0x1 << CONTROL_FINISH_ANIM_INDEX;
-const U32 AGENT_CONTROL_STAND_UP = 0x1 << CONTROL_STAND_UP_INDEX;
-const U32 AGENT_CONTROL_SIT_ON_GROUND = 0x1 << CONTROL_SIT_ON_GROUND_INDEX;
-const U32 AGENT_CONTROL_MOUSELOOK = 0x1 << CONTROL_MOUSELOOK_INDEX;
-
-const U32 AGENT_CONTROL_NUDGE_AT_POS = 0x1 << CONTROL_NUDGE_AT_POS_INDEX;
-const U32 AGENT_CONTROL_NUDGE_AT_NEG = 0x1 << CONTROL_NUDGE_AT_NEG_INDEX;
-const U32 AGENT_CONTROL_NUDGE_LEFT_POS = 0x1 << CONTROL_NUDGE_LEFT_POS_INDEX;
-const U32 AGENT_CONTROL_NUDGE_LEFT_NEG = 0x1 << CONTROL_NUDGE_LEFT_NEG_INDEX;
-const U32 AGENT_CONTROL_NUDGE_UP_POS = 0x1 << CONTROL_NUDGE_UP_POS_INDEX;
-const U32 AGENT_CONTROL_NUDGE_UP_NEG = 0x1 << CONTROL_NUDGE_UP_NEG_INDEX;
-const U32 AGENT_CONTROL_TURN_LEFT = 0x1 << CONTROL_TURN_LEFT_INDEX;
-const U32 AGENT_CONTROL_TURN_RIGHT = 0x1 << CONTROL_TURN_RIGHT_INDEX;
-
-const U32 AGENT_CONTROL_AWAY = 0x1 << CONTROL_AWAY_INDEX;
-
-const U32 AGENT_CONTROL_LBUTTON_DOWN = 0x1 << CONTROL_LBUTTON_DOWN_INDEX;
-const U32 AGENT_CONTROL_LBUTTON_UP = 0x1 << CONTROL_LBUTTON_UP_INDEX;
-const U32 AGENT_CONTROL_ML_LBUTTON_DOWN = 0x1 << CONTROL_ML_LBUTTON_DOWN_INDEX;
-const U32 AGENT_CONTROL_ML_LBUTTON_UP = ((U32)0x1) << CONTROL_ML_LBUTTON_UP_INDEX;
+const U32 AGENT_CONTROL_AT_POS = 0x1 << CONTROL_AT_POS_INDEX; // 0x00000001
+const U32 AGENT_CONTROL_AT_NEG = 0x1 << CONTROL_AT_NEG_INDEX; // 0x00000002
+const U32 AGENT_CONTROL_LEFT_POS = 0x1 << CONTROL_LEFT_POS_INDEX; // 0x00000004
+const U32 AGENT_CONTROL_LEFT_NEG = 0x1 << CONTROL_LEFT_NEG_INDEX; // 0x00000008
+const U32 AGENT_CONTROL_UP_POS = 0x1 << CONTROL_UP_POS_INDEX; // 0x00000010
+const U32 AGENT_CONTROL_UP_NEG = 0x1 << CONTROL_UP_NEG_INDEX; // 0x00000020
+const U32 AGENT_CONTROL_PITCH_POS = 0x1 << CONTROL_PITCH_POS_INDEX; // 0x00000040
+const U32 AGENT_CONTROL_PITCH_NEG = 0x1 << CONTROL_PITCH_NEG_INDEX; // 0x00000080
+const U32 AGENT_CONTROL_YAW_POS = 0x1 << CONTROL_YAW_POS_INDEX; // 0x00000100
+const U32 AGENT_CONTROL_YAW_NEG = 0x1 << CONTROL_YAW_NEG_INDEX; // 0x00000200
+
+const U32 AGENT_CONTROL_FAST_AT = 0x1 << CONTROL_FAST_AT_INDEX; // 0x00000400
+const U32 AGENT_CONTROL_FAST_LEFT = 0x1 << CONTROL_FAST_LEFT_INDEX; // 0x00000800
+const U32 AGENT_CONTROL_FAST_UP = 0x1 << CONTROL_FAST_UP_INDEX; // 0x00001000
+
+const U32 AGENT_CONTROL_FLY = 0x1 << CONTROL_FLY_INDEX; // 0x00002000
+const U32 AGENT_CONTROL_STOP = 0x1 << CONTROL_STOP_INDEX; // 0x00004000
+const U32 AGENT_CONTROL_FINISH_ANIM = 0x1 << CONTROL_FINISH_ANIM_INDEX; // 0x00008000
+const U32 AGENT_CONTROL_STAND_UP = 0x1 << CONTROL_STAND_UP_INDEX; // 0x00010000
+const U32 AGENT_CONTROL_SIT_ON_GROUND = 0x1 << CONTROL_SIT_ON_GROUND_INDEX; // 0x00020000
+const U32 AGENT_CONTROL_MOUSELOOK = 0x1 << CONTROL_MOUSELOOK_INDEX; // 0x00040000
+
+const U32 AGENT_CONTROL_NUDGE_AT_POS = 0x1 << CONTROL_NUDGE_AT_POS_INDEX; // 0x00080000
+const U32 AGENT_CONTROL_NUDGE_AT_NEG = 0x1 << CONTROL_NUDGE_AT_NEG_INDEX; // 0x00100000
+const U32 AGENT_CONTROL_NUDGE_LEFT_POS = 0x1 << CONTROL_NUDGE_LEFT_POS_INDEX; // 0x00200000
+const U32 AGENT_CONTROL_NUDGE_LEFT_NEG = 0x1 << CONTROL_NUDGE_LEFT_NEG_INDEX; // 0x00400000
+const U32 AGENT_CONTROL_NUDGE_UP_POS = 0x1 << CONTROL_NUDGE_UP_POS_INDEX; // 0x00800000
+const U32 AGENT_CONTROL_NUDGE_UP_NEG = 0x1 << CONTROL_NUDGE_UP_NEG_INDEX; // 0x01000000
+const U32 AGENT_CONTROL_TURN_LEFT = 0x1 << CONTROL_TURN_LEFT_INDEX; // 0x02000000
+const U32 AGENT_CONTROL_TURN_RIGHT = 0x1 << CONTROL_TURN_RIGHT_INDEX; // 0x04000000
+
+const U32 AGENT_CONTROL_AWAY = 0x1 << CONTROL_AWAY_INDEX; // 0x08000000
+
+const U32 AGENT_CONTROL_LBUTTON_DOWN = 0x1 << CONTROL_LBUTTON_DOWN_INDEX; // 0x10000000
+const U32 AGENT_CONTROL_LBUTTON_UP = 0x1 << CONTROL_LBUTTON_UP_INDEX; // 0x20000000
+const U32 AGENT_CONTROL_ML_LBUTTON_DOWN = 0x1 << CONTROL_ML_LBUTTON_DOWN_INDEX; // 0x40000000
+const U32 AGENT_CONTROL_ML_LBUTTON_UP = ((U32)0x1) << CONTROL_ML_LBUTTON_UP_INDEX; // 0x80000000
const U32 AGENT_CONTROL_AT = AGENT_CONTROL_AT_POS
| AGENT_CONTROL_AT_NEG
diff --git a/indra/llcommon/llallocator.cpp b/indra/llcommon/llallocator.cpp
new file mode 100644
index 0000000000..6f6abefc67
--- /dev/null
+++ b/indra/llcommon/llallocator.cpp
@@ -0,0 +1,134 @@
+/**
+ * @file llallocator.cpp
+ * @brief Implementation of the LLAllocator class.
+ *
+ * $LicenseInfo:firstyear=2009&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$
+ */
+
+#include "linden_common.h"
+#include "llallocator.h"
+
+#if LL_USE_TCMALLOC
+
+#include "google/heap-profiler.h"
+#include "google/commandlineflags_public.h"
+
+DECLARE_bool(heap_profile_use_stack_trace);
+//DECLARE_double(tcmalloc_release_rate);
+
+// static
+void LLAllocator::pushMemType(S32 type)
+{
+ if(isProfiling())
+ {
+ PushMemType(type);
+ }
+}
+
+// static
+S32 LLAllocator::popMemType()
+{
+ if (isProfiling())
+ {
+ return PopMemType();
+ }
+ else
+ {
+ return -1;
+ }
+}
+
+void LLAllocator::setProfilingEnabled(bool should_enable)
+{
+ // NULL disables dumping to disk
+ static char const * const PREFIX = NULL;
+ if(should_enable)
+ {
+ HeapProfilerSetUseStackTrace(false);
+ HeapProfilerStart(PREFIX);
+ }
+ else
+ {
+ HeapProfilerStop();
+ }
+}
+
+// static
+bool LLAllocator::isProfiling()
+{
+ return IsHeapProfilerRunning();
+}
+
+std::string LLAllocator::getRawProfile()
+{
+ // *TODO - fix google-perftools to accept an buffer to avoid this
+ // malloc-copy-free cycle.
+ char * buffer = GetHeapProfile();
+ std::string ret = buffer;
+ free(buffer);
+ return ret;
+}
+
+#else // LL_USE_TCMALLOC
+
+//
+// stub implementations for when tcmalloc is disabled
+//
+
+// static
+void LLAllocator::pushMemType(S32 type)
+{
+}
+
+// static
+S32 LLAllocator::popMemType()
+{
+ return -1;
+}
+
+void LLAllocator::setProfilingEnabled(bool should_enable)
+{
+}
+
+// static
+bool LLAllocator::isProfiling()
+{
+ return false;
+}
+
+std::string LLAllocator::getRawProfile()
+{
+ return std::string();
+}
+
+#endif // LL_USE_TCMALLOC
+
+LLAllocatorHeapProfile const & LLAllocator::getProfile()
+{
+ mProf.mLines.clear();
+
+ // *TODO - avoid making all these extra copies of things...
+ std::string prof_text = getRawProfile();
+ //std::cout << prof_text << std::endl;
+ mProf.parse(prof_text);
+ return mProf;
+}
diff --git a/indra/llcommon/llallocator.h b/indra/llcommon/llallocator.h
new file mode 100644
index 0000000000..a91dd57d14
--- /dev/null
+++ b/indra/llcommon/llallocator.h
@@ -0,0 +1,57 @@
+/**
+ * @file llallocator.h
+ * @brief Declaration of the LLAllocator class.
+ *
+ * $LicenseInfo:firstyear=2009&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$
+ */
+
+#ifndef LL_LLALLOCATOR_H
+#define LL_LLALLOCATOR_H
+
+#include <string>
+
+#include "llmemtype.h"
+#include "llallocator_heap_profile.h"
+
+class LL_COMMON_API LLAllocator {
+ friend class LLMemoryView;
+ friend class LLMemType;
+
+private:
+ static void pushMemType(S32 type);
+ static S32 popMemType();
+
+public:
+ void setProfilingEnabled(bool should_enable);
+
+ static bool isProfiling();
+
+ LLAllocatorHeapProfile const & getProfile();
+
+private:
+ std::string getRawProfile();
+
+private:
+ LLAllocatorHeapProfile mProf;
+};
+
+#endif // LL_LLALLOCATOR_H
diff --git a/indra/llcommon/llallocator_heap_profile.cpp b/indra/llcommon/llallocator_heap_profile.cpp
new file mode 100644
index 0000000000..b574ef668b
--- /dev/null
+++ b/indra/llcommon/llallocator_heap_profile.cpp
@@ -0,0 +1,147 @@
+/**
+ * @file llallocator_heap_profile.cpp
+ * @brief Implementation of the parser for tcmalloc heap profile data.
+ * @author Brad Kittenbrink
+ *
+ * $LicenseInfo:firstyear=2009&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$
+ */
+
+#include "linden_common.h"
+#include "llallocator_heap_profile.h"
+
+#if LL_MSVC
+// disable warning about boost::lexical_cast returning uninitialized data
+// when it fails to parse the string
+#pragma warning (disable:4701)
+#pragma warning (disable:4702)
+#endif
+
+#include <boost/algorithm/string/split.hpp>
+#include <boost/bind.hpp>
+#include <boost/lexical_cast.hpp>
+#include <boost/range/iterator_range.hpp>
+
+static const std::string HEAP_PROFILE_MAGIC_STR = "heap profile:";
+
+static bool is_separator(char c)
+{
+ return isspace(c) || c == '[' || c == ']' || c == ':';
+}
+
+void LLAllocatorHeapProfile::parse(std::string const & prof_text)
+{
+ // a typedef for handling a token in the string buffer
+ // it's a begin/end pair of string::const_iterators
+ typedef boost::iterator_range<std::string::const_iterator> range_t;
+
+ mLines.clear();
+
+ if(prof_text.compare(0, HEAP_PROFILE_MAGIC_STR.length(), HEAP_PROFILE_MAGIC_STR) != 0)
+ {
+ // *TODO - determine if there should be some better error state than
+ // mLines being empty. -brad
+ llwarns << "invalid heap profile data passed into parser." << llendl;
+ return;
+ }
+
+ std::vector< range_t > prof_lines;
+
+ std::string::const_iterator prof_begin = prof_text.begin() + HEAP_PROFILE_MAGIC_STR.length();
+
+ range_t prof_range(prof_begin, prof_text.end());
+ boost::algorithm::split(prof_lines,
+ prof_range,
+ boost::bind(std::equal_to<llwchar>(), '\n', _1));
+
+ std::vector< range_t >::const_iterator i;
+ for(i = prof_lines.begin(); i != prof_lines.end() && !i->empty(); ++i)
+ {
+ range_t const & line_text = *i;
+
+ std::vector<range_t> line_elems;
+
+ boost::algorithm::split(line_elems,
+ line_text,
+ is_separator);
+
+ std::vector< range_t >::iterator j;
+ j = line_elems.begin();
+
+ while(j != line_elems.end() && j->empty()) { ++j; } // skip any separator tokens
+ llassert_always(j != line_elems.end());
+ U32 live_count = boost::lexical_cast<U32>(*j);
+ ++j;
+
+ while(j != line_elems.end() && j->empty()) { ++j; } // skip any separator tokens
+ llassert_always(j != line_elems.end());
+ U64 live_size = boost::lexical_cast<U64>(*j);
+ ++j;
+
+ while(j != line_elems.end() && j->empty()) { ++j; } // skip any separator tokens
+ llassert_always(j != line_elems.end());
+ U32 tot_count = boost::lexical_cast<U32>(*j);
+ ++j;
+
+ while(j != line_elems.end() && j->empty()) { ++j; } // skip any separator tokens
+ llassert_always(j != line_elems.end());
+ U64 tot_size = boost::lexical_cast<U64>(*j);
+ ++j;
+
+ while(j != line_elems.end() && j->empty()) { ++j; } // skip any separator tokens
+ llassert(j != line_elems.end());
+ if (j != line_elems.end())
+ {
+ ++j; // skip the '@'
+
+ mLines.push_back(line(live_count, live_size, tot_count, tot_size));
+ line & current_line = mLines.back();
+
+ for(; j != line_elems.end(); ++j)
+ {
+ if(!j->empty())
+ {
+ U32 marker = boost::lexical_cast<U32>(*j);
+ current_line.mTrace.push_back(marker);
+ }
+ }
+ }
+ }
+ // *TODO - parse MAPPED_LIBRARIES section here if we're ever interested in it
+}
+
+void LLAllocatorHeapProfile::dump(std::ostream & out) const
+{
+ lines_t::const_iterator i;
+ for(i = mLines.begin(); i != mLines.end(); ++i)
+ {
+ out << i->mLiveCount << ": " << i->mLiveSize << '[' << i->mTotalCount << ": " << i->mTotalSize << "] @";
+
+ stack_trace::const_iterator j;
+ for(j = i->mTrace.begin(); j != i->mTrace.end(); ++j)
+ {
+ out << ' ' << *j;
+ }
+ out << '\n';
+ }
+ out.flush();
+}
+
diff --git a/indra/llcommon/llallocator_heap_profile.h b/indra/llcommon/llallocator_heap_profile.h
new file mode 100644
index 0000000000..69300b829b
--- /dev/null
+++ b/indra/llcommon/llallocator_heap_profile.h
@@ -0,0 +1,71 @@
+/**
+ * @file llallocator_heap_profile.h
+ * @brief Declaration of the parser for tcmalloc heap profile data.
+ * @author Brad Kittenbrink
+ *
+ * $LicenseInfo:firstyear=2009&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$
+ */
+
+#ifndef LL_LLALLOCATOR_HEAP_PROFILE_H
+#define LL_LLALLOCATOR_HEAP_PROFILE_H
+
+#include "stdtypes.h"
+
+#include <map>
+#include <vector>
+
+class LLAllocatorHeapProfile
+{
+public:
+ typedef int stack_marker;
+
+ typedef std::vector<stack_marker> stack_trace;
+
+ struct line {
+ line(U32 live_count, U64 live_size, U32 tot_count, U64 tot_size) :
+ mLiveSize(live_size),
+ mTotalSize(tot_size),
+ mLiveCount(live_count),
+ mTotalCount(tot_count)
+ {
+ }
+ U64 mLiveSize, mTotalSize;
+ U32 mLiveCount, mTotalCount;
+ stack_trace mTrace;
+ };
+
+ typedef std::vector<line> lines_t;
+
+ LLAllocatorHeapProfile()
+ {
+ }
+
+ void parse(std::string const & prof_text);
+
+ void dump(std::ostream & out) const;
+
+public:
+ lines_t mLines;
+};
+
+
+#endif // LL_LLALLOCATOR_HEAP_PROFILE_H
diff --git a/indra/llcommon/llapp.cpp b/indra/llcommon/llapp.cpp
index 6591bbc070..eebd5ed0a6 100644
--- a/indra/llcommon/llapp.cpp
+++ b/indra/llcommon/llapp.cpp
@@ -2,33 +2,36 @@
* @file llapp.cpp
* @brief Implementation of the LLApp class.
*
- * $LicenseInfo:firstyear=2003&license=viewergpl$
- *
- * Copyright (c) 2003-2007, Linden Research, Inc.
- *
+ * $LicenseInfo:firstyear=2003&license=viewerlgpl$
* Second Life Viewer Source Code
- * The source code in this file ("Source Code") is provided by Linden Lab
- * to you under the terms of the GNU General Public License, version 2.0
- * ("GPL"), unless you have obtained a separate licensing agreement
- * ("Other License"), formally executed by you and Linden Lab. Terms of
- * the GPL can be found in doc/GPL-license.txt in this distribution, or
- * online at http://secondlife.com/developers/opensource/gplv2
+ * 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.
*
- * There are special exceptions to the terms and conditions of the GPL as
- * it is applied to this Source Code. View the full text of the exception
- * in the file doc/FLOSS-exception.txt in this software distribution, or
- * online at http://secondlife.com/developers/opensource/flossexception
+ * 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.
*
- * By copying, modifying or distributing this software, you acknowledge
- * that you have read and understood your obligations described above,
- * and agree to abide by those obligations.
+ * 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
*
- * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
- * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
- * COMPLETENESS OR PERFORMANCE.
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
* $/LicenseInfo$
*/
+#include <cstdlib>
+
+#ifdef LL_DARWIN
+#include <sys/types.h>
+#include <unistd.h>
+#include <sys/sysctl.h>
+#endif
+
#include "linden_common.h"
#include "llapp.h"
@@ -37,8 +40,13 @@
#include "llerrorcontrol.h"
#include "llerrorthread.h"
#include "llframetimer.h"
+#include "lllivefile.h"
#include "llmemory.h"
-#include "lltimer.h"
+#include "llstl.h" // for DeletePointer()
+#include "llstring.h"
+#include "lleventtimer.h"
+
+#include "google_breakpad/exception_handler.h"
//
// Signal handling
@@ -48,12 +56,36 @@
#if LL_WINDOWS
LONG WINAPI default_windows_exception_handler(struct _EXCEPTION_POINTERS *exception_infop);
BOOL ConsoleCtrlHandler(DWORD fdwCtrlType);
+bool windows_post_minidump_callback(const wchar_t* dump_path,
+ const wchar_t* minidump_id,
+ void* context,
+ EXCEPTION_POINTERS* exinfo,
+ MDRawAssertionInfo* assertion,
+ bool succeeded);
#else
-#include <unistd.h> // for fork()
+# include <signal.h>
+# include <unistd.h> // for fork()
void setup_signals();
void default_unix_signal_handler(int signum, siginfo_t *info, void *);
-const S32 LL_SMACKDOWN_SIGNAL = SIGUSR1;
-#endif
+
+// Called by breakpad exception handler after the minidump has been generated.
+bool unix_post_minidump_callback(const char *dump_dir,
+ const char *minidump_id,
+ void *context, bool succeeded);
+# if LL_DARWIN
+/* OSX doesn't support SIGRT* */
+S32 LL_SMACKDOWN_SIGNAL = SIGUSR1;
+S32 LL_HEARTBEAT_SIGNAL = SIGUSR2;
+# else // linux or (assumed) other similar unixoid
+/* We want reliable delivery of our signals - SIGRT* is it. */
+/* Old LinuxThreads versions eat SIGRTMIN+0 to SIGRTMIN+2, avoid those. */
+/* Note that SIGRTMIN/SIGRTMAX may expand to a glibc function call with a
+ nonconstant result so these are not consts and cannot be used in constant-
+ expressions. SIGRTMAX may return -1 on rare broken setups. */
+S32 LL_SMACKDOWN_SIGNAL = (SIGRTMAX >= 0) ? (SIGRTMAX-1) : SIGUSR1;
+S32 LL_HEARTBEAT_SIGNAL = (SIGRTMAX >= 0) ? (SIGRTMAX-0) : SIGUSR2;
+# endif // LL_DARWIN
+#endif // LL_WINDOWS
// the static application instance
LLApp* LLApp::sApplication = NULL;
@@ -75,6 +107,11 @@ LLAppChildCallback LLApp::sDefaultChildCallback = NULL;
LLApp::LLApp() : mThreadErrorp(NULL)
{
+ commonCtor();
+}
+
+void LLApp::commonCtor()
+{
// Set our status to running
setStatus(APP_STATUS_RUNNING);
@@ -82,11 +119,8 @@ LLApp::LLApp() : mThreadErrorp(NULL)
#if !LL_WINDOWS
// This must be initialized before the error handler.
- sSigChildCount = new LLAtomicU32(0);
+ sSigChildCount = new LLAtomicU32(0);
#endif
-
- // Setup error handling
- setupErrorHandling();
// initialize the options structure. We need to make this an array
// because the structured data will not auto-allocate if we
@@ -104,6 +138,18 @@ LLApp::LLApp() : mThreadErrorp(NULL)
// Set the application to this instance.
sApplication = this;
+
+ mExceptionHandler = 0;
+
+ // initialize the buffer to write the minidump filename to
+ // (this is used to avoid allocating memory in the crash handler)
+ memset(minidump_path, 0, MAX_MINDUMP_PATH_LENGTH);
+}
+
+LLApp::LLApp(LLErrorThread *error_thread) :
+ mThreadErrorp(error_thread)
+{
+ commonCtor();
}
@@ -113,6 +159,11 @@ LLApp::~LLApp()
delete sSigChildCount;
sSigChildCount = NULL;
#endif
+
+ // reclaim live file memory
+ std::for_each(mLiveFiles.begin(), mLiveFiles.end(), DeletePointer());
+ mLiveFiles.clear();
+
setStopped();
// HACK: wait for the error thread to clean itself
ms_sleep(20);
@@ -121,6 +172,8 @@ LLApp::~LLApp()
delete mThreadErrorp;
mThreadErrorp = NULL;
}
+
+ if(mExceptionHandler != 0) delete mExceptionHandler;
LLCommon::cleanupClass();
}
@@ -186,6 +239,15 @@ bool LLApp::parseCommandOptions(int argc, char** argv)
return true;
}
+
+void LLApp::manageLiveFile(LLLiveFile* livefile)
+{
+ if(!livefile) return;
+ livefile->checkAndReload();
+ livefile->addToEventTimer();
+ mLiveFiles.push_back(livefile);
+}
+
bool LLApp::setOptionData(OptionPriority level, LLSD data)
{
if((level < 0)
@@ -210,6 +272,7 @@ LLSD LLApp::getOptionData(OptionPriority level)
void LLApp::stepFrame()
{
LLFrameTimer::updateFrameTime();
+ LLFrameTimer::updateFrameCount();
LLEventTimer::updateClass();
mRunner.run();
}
@@ -221,19 +284,18 @@ void LLApp::setupErrorHandling()
// occasionally checks to see if the app is in an error state, and sees if it needs to be run.
#if LL_WINDOWS
- // Windows doesn't have the same signal handling mechanisms as UNIX, thus APR doesn't provide
- // a signal handling thread implementation.
- // What we do is install an unhandled exception handler, which will try to do the right thing
- // in the case of an error (generate a minidump)
-
- // Disable this until the viewer gets ported so server crashes can be JIT debugged.
- //LPTOP_LEVEL_EXCEPTION_FILTER prev_filter;
- //prev_filter = SetUnhandledExceptionFilter(default_windows_exception_handler);
-
// This sets a callback to handle w32 signals to the console window.
// The viewer shouldn't be affected, sicne its a windowed app.
SetConsoleCtrlHandler( (PHANDLER_ROUTINE) ConsoleCtrlHandler, TRUE);
+ // Install the Google Breakpad crash handler for Windows
+ if(mExceptionHandler == 0)
+ {
+ llwarns << "adding breakpad exception handler" << llendl;
+ mExceptionHandler = new google_breakpad::ExceptionHandler(
+ L"C:\\Temp\\", 0, windows_post_minidump_callback, 0, google_breakpad::ExceptionHandler::HANDLER_ALL);
+ }
+
#else
//
// Start up signal handling.
@@ -241,22 +303,69 @@ void LLApp::setupErrorHandling()
// There are two different classes of signals. Synchronous signals are delivered to a specific
// thread, asynchronous signals can be delivered to any thread (in theory)
//
-
setup_signals();
-
+
+ // Add google breakpad exception handler configured for Darwin/Linux.
+ bool installHandler = true;
+#ifdef LL_DARWIN
+ // For the special case of Darwin, we do not want to install the handler if
+ // the process is being debugged as the app will exit with value ABRT (6) if
+ // we do. Unfortunately, the code below which performs that test relies on
+ // the structure kinfo_proc which has been tagged by apple as an unstable
+ // API. We disable this test for shipping versions to avoid conflicts with
+ // future releases of Darwin. This test is really only needed for developers
+ // starting the app from a debugger anyway.
+ #ifndef LL_RELEASE_FOR_DOWNLOAD
+ int mib[4];
+ mib[0] = CTL_KERN;
+ mib[1] = KERN_PROC;
+ mib[2] = KERN_PROC_PID;
+ mib[3] = getpid();
+
+ struct kinfo_proc info;
+ memset(&info, 0, sizeof(info));
+
+ size_t size = sizeof(info);
+ int result = sysctl(mib, sizeof(mib) / sizeof(*mib), &info, &size, NULL, 0);
+ if((result == 0) || (errno == ENOMEM))
+ {
+ // P_TRACED flag is set, so this process is being debugged; do not install
+ // the handler
+ if(info.kp_proc.p_flag & P_TRACED) installHandler = false;
+ }
+ else
+ {
+ // Failed to discover if the process is being debugged; default to
+ // installing the handler.
+ installHandler = true;
+ }
+ #endif
+#endif
+ if(installHandler && (mExceptionHandler == 0))
+ {
+ std::string dumpPath = "/tmp/";
+ mExceptionHandler = new google_breakpad::ExceptionHandler(dumpPath, 0, &unix_post_minidump_callback, 0, true);
+ }
#endif
+ startErrorThread();
+}
+
+void LLApp::startErrorThread()
+{
//
// Start the error handling thread, which is responsible for taking action
// when the app goes into the APP_STATUS_ERROR state
//
- llinfos << "LLApp::setupErrorHandling - Starting error thread" << llendl;
- mThreadErrorp = new LLErrorThread();
- mThreadErrorp->setUserData((void *) this);
- mThreadErrorp->start();
+ if(!mThreadErrorp)
+ {
+ llinfos << "Starting error thread" << llendl;
+ mThreadErrorp = new LLErrorThread();
+ mThreadErrorp->setUserData((void *) this);
+ mThreadErrorp->start();
+ }
}
-
void LLApp::setErrorHandler(LLAppErrorHandler handler)
{
LLApp::sErrorHandler = handler;
@@ -274,7 +383,6 @@ void LLApp::runErrorHandler()
LLApp::setStopped();
}
-
// static
void LLApp::setStatus(EAppStatus status)
{
@@ -285,9 +393,27 @@ void LLApp::setStatus(EAppStatus status)
// static
void LLApp::setError()
{
+ // set app status to ERROR so that the LLErrorThread notices
setStatus(APP_STATUS_ERROR);
}
+void LLApp::setMiniDumpDir(const std::string &path)
+{
+ if(mExceptionHandler == 0) return;
+#ifdef LL_WINDOWS
+ wchar_t buffer[MAX_MINDUMP_PATH_LENGTH];
+ mbstowcs(buffer, path.c_str(), MAX_MINDUMP_PATH_LENGTH);
+ mExceptionHandler->set_dump_path(std::wstring(buffer));
+#else
+ mExceptionHandler->set_dump_path(path);
+#endif
+}
+
+void LLApp::writeMiniDump()
+{
+ if(mExceptionHandler == 0) return;
+ mExceptionHandler->WriteMinidump();
+}
// static
void LLApp::setQuitting()
@@ -457,6 +583,7 @@ void LLApp::setDefaultChildCallback(LLAppChildCallback callback)
pid_t LLApp::fork()
{
+ fflush(NULL); // flush all buffers before the child inherits them
pid_t pid = ::fork();
if( pid < 0 )
{
@@ -501,8 +628,13 @@ void setup_signals()
sigaction(SIGSEGV, &act, NULL);
sigaction(SIGSYS, &act, NULL);
+ sigaction(LL_HEARTBEAT_SIGNAL, &act, NULL);
+ sigaction(LL_SMACKDOWN_SIGNAL, &act, NULL);
+
// Asynchronous signals that are normally ignored
+#ifndef LL_IGNORE_SIGCHLD
sigaction(SIGCHLD, &act, NULL);
+#endif // LL_IGNORE_SIGCHLD
sigaction(SIGUSR2, &act, NULL);
// Asynchronous signals that result in attempted graceful exit
@@ -511,8 +643,8 @@ void setup_signals()
sigaction(SIGINT, &act, NULL);
// Asynchronous signals that result in core
- sigaction(LL_SMACKDOWN_SIGNAL, &act, NULL);
sigaction(SIGQUIT, &act, NULL);
+
}
void clear_signals()
@@ -533,8 +665,13 @@ void clear_signals()
sigaction(SIGSEGV, &act, NULL);
sigaction(SIGSYS, &act, NULL);
+ sigaction(LL_HEARTBEAT_SIGNAL, &act, NULL);
+ sigaction(LL_SMACKDOWN_SIGNAL, &act, NULL);
+
// Asynchronous signals that are normally ignored
+#ifndef LL_IGNORE_SIGCHLD
sigaction(SIGCHLD, &act, NULL);
+#endif // LL_IGNORE_SIGCHLD
// Asynchronous signals that result in attempted graceful exit
sigaction(SIGHUP, &act, NULL);
@@ -543,7 +680,6 @@ void clear_signals()
// Asynchronous signals that result in core
sigaction(SIGUSR2, &act, NULL);
- sigaction(LL_SMACKDOWN_SIGNAL, &act, NULL);
sigaction(SIGQUIT, &act, NULL);
}
@@ -564,16 +700,7 @@ void default_unix_signal_handler(int signum, siginfo_t *info, void *)
switch (signum)
{
- case SIGALRM:
- case SIGPIPE:
- case SIGUSR2:
- // We don't care about these signals, ignore them
- if (LLApp::sLogInSignal)
- {
- llinfos << "Signal handler - Ignoring this signal" << llendl;
- }
- return;
- case SIGCHLD:
+ case SIGCHLD:
if (LLApp::sLogInSignal)
{
llinfos << "Signal handler - Got SIGCHLD from " << info->si_pid << llendl;
@@ -602,59 +729,6 @@ void default_unix_signal_handler(int signum, siginfo_t *info, void *)
clear_signals();
raise(signum);
return;
- case LL_SMACKDOWN_SIGNAL: // Smackdown treated just like any other app termination, for now
- if (LLApp::sLogInSignal)
- {
- llwarns << "Signal handler - Handling smackdown signal!" << llendl;
- }
- else
- {
- // Don't log anything, even errors - this is because this signal could happen anywhere.
- LLError::setDefaultLevel(LLError::LEVEL_NONE);
- }
-
- // Change the signal that we reraise to SIGABRT, so we generate a core dump.
- signum = SIGABRT;
- case SIGBUS:
- case SIGSEGV:
- case SIGQUIT:
- if (LLApp::sLogInSignal)
- {
- llwarns << "Signal handler - Handling fatal signal!" << llendl;
- }
- if (LLApp::isError())
- {
- // Received second fatal signal while handling first, just die right now
- // Set the signal handlers back to default before handling the signal - this makes the next signal wipe out the app.
- clear_signals();
-
- if (LLApp::sLogInSignal)
- {
- llwarns << "Signal handler - Got another fatal signal while in the error handler, die now!" << llendl;
- }
- raise(signum);
- return;
- }
-
- if (LLApp::sLogInSignal)
- {
- llwarns << "Signal handler - Flagging error status and waiting for shutdown" << llendl;
- }
- // Flag status to ERROR, so thread_error does its work.
- LLApp::setError();
- // Block in the signal handler until somebody says that we're done.
- while (LLApp::sErrorThreadRunning && !LLApp::isStopped())
- {
- ms_sleep(10);
- }
-
- if (LLApp::sLogInSignal)
- {
- llwarns << "Signal handler - App is stopped, reraising signal" << llendl;
- }
- clear_signals();
- raise(signum);
- return;
case SIGINT:
case SIGHUP:
case SIGTERM:
@@ -675,12 +749,181 @@ void default_unix_signal_handler(int signum, siginfo_t *info, void *)
}
LLApp::setQuitting();
return;
+ case SIGALRM:
+ case SIGPIPE:
+ case SIGUSR2:
default:
- if (LLApp::sLogInSignal)
- {
- llwarns << "Signal handler - Unhandled signal, ignoring!" << llendl;
+ if (signum == LL_SMACKDOWN_SIGNAL ||
+ signum == SIGBUS ||
+ signum == SIGILL ||
+ signum == SIGFPE ||
+ signum == SIGSEGV ||
+ signum == SIGQUIT)
+ {
+ if (signum == LL_SMACKDOWN_SIGNAL)
+ {
+ // Smackdown treated just like any other app termination, for now
+ if (LLApp::sLogInSignal)
+ {
+ llwarns << "Signal handler - Handling smackdown signal!" << llendl;
+ }
+ else
+ {
+ // Don't log anything, even errors - this is because this signal could happen anywhere.
+ LLError::setDefaultLevel(LLError::LEVEL_NONE);
+ }
+
+ // Change the signal that we reraise to SIGABRT, so we generate a core dump.
+ signum = SIGABRT;
+ }
+
+ if (LLApp::sLogInSignal)
+ {
+ llwarns << "Signal handler - Handling fatal signal!" << llendl;
+ }
+ if (LLApp::isError())
+ {
+ // Received second fatal signal while handling first, just die right now
+ // Set the signal handlers back to default before handling the signal - this makes the next signal wipe out the app.
+ clear_signals();
+
+ if (LLApp::sLogInSignal)
+ {
+ llwarns << "Signal handler - Got another fatal signal while in the error handler, die now!" << llendl;
+ }
+ raise(signum);
+ return;
+ }
+
+ if (LLApp::sLogInSignal)
+ {
+ llwarns << "Signal handler - Flagging error status and waiting for shutdown" << llendl;
+ }
+ // Flag status to ERROR, so thread_error does its work.
+ LLApp::setError();
+ // Block in the signal handler until somebody says that we're done.
+ while (LLApp::sErrorThreadRunning && !LLApp::isStopped())
+ {
+ ms_sleep(10);
+ }
+
+ if (LLApp::sLogInSignal)
+ {
+ llwarns << "Signal handler - App is stopped, reraising signal" << llendl;
+ }
+ clear_signals();
+ raise(signum);
+ return;
+ } else {
+ if (LLApp::sLogInSignal)
+ {
+ llinfos << "Signal handler - Unhandled signal " << signum << ", ignoring!" << llendl;
+ }
}
}
}
+bool unix_post_minidump_callback(const char *dump_dir,
+ const char *minidump_id,
+ void *context, bool succeeded)
+{
+ // Copy minidump file path into fixed buffer in the app instance to avoid
+ // heap allocations in a crash handler.
+
+ // path format: <dump_dir>/<minidump_id>.dmp
+ int dirPathLength = strlen(dump_dir);
+ int idLength = strlen(minidump_id);
+
+ // The path must not be truncated.
+ llassert((dirPathLength + idLength + 5) <= LLApp::MAX_MINDUMP_PATH_LENGTH);
+
+ char * path = LLApp::instance()->getMiniDumpFilename();
+ S32 remaining = LLApp::MAX_MINDUMP_PATH_LENGTH;
+ strncpy(path, dump_dir, remaining);
+ remaining -= dirPathLength;
+ path += dirPathLength;
+ if (remaining > 0 && dirPathLength > 0 && path[-1] != '/')
+ {
+ *path++ = '/';
+ --remaining;
+ }
+ if (remaining > 0)
+ {
+ strncpy(path, minidump_id, remaining);
+ remaining -= idLength;
+ path += idLength;
+ strncpy(path, ".dmp", remaining);
+ }
+
+ llinfos << "generated minidump: " << LLApp::instance()->getMiniDumpFilename() << llendl;
+ LLApp::runErrorHandler();
+
+#ifndef LL_RELEASE_FOR_DOWNLOAD
+ clear_signals();
+ return false;
+#else
+ return true;
+#endif
+}
#endif // !WINDOWS
+
+#ifdef LL_WINDOWS
+bool windows_post_minidump_callback(const wchar_t* dump_path,
+ const wchar_t* minidump_id,
+ void* context,
+ EXCEPTION_POINTERS* exinfo,
+ MDRawAssertionInfo* assertion,
+ bool succeeded)
+{
+ char * path = LLApp::instance()->getMiniDumpFilename();
+ S32 remaining = LLApp::MAX_MINDUMP_PATH_LENGTH;
+ size_t bytesUsed;
+
+ bytesUsed = wcstombs(path, dump_path, static_cast<size_t>(remaining));
+ remaining -= bytesUsed;
+ path += bytesUsed;
+ if(remaining > 0 && bytesUsed > 0 && path[-1] != '\\')
+ {
+ *path++ = '\\';
+ --remaining;
+ }
+ if(remaining > 0)
+ {
+ bytesUsed = wcstombs(path, minidump_id, static_cast<size_t>(remaining));
+ remaining -= bytesUsed;
+ path += bytesUsed;
+ }
+ if(remaining > 0)
+ {
+ strncpy(path, ".dmp", remaining);
+ }
+
+ llinfos << "generated minidump: " << LLApp::instance()->getMiniDumpFilename() << llendl;
+ // *NOTE:Mani - this code is stolen from LLApp, where its never actually used.
+ //OSMessageBox("Attach Debugger Now", "Error", OSMB_OK);
+ // *TODO: Translate the signals/exceptions into cross-platform stuff
+ // Windows implementation
+ llinfos << "Entering Windows Exception Handler..." << llendl;
+
+ if (LLApp::isError())
+ {
+ llwarns << "Got another fatal signal while in the error handler, die now!" << llendl;
+ }
+
+ // Flag status to error, so thread_error starts its work
+ LLApp::setError();
+
+ // Block in the exception handler until the app has stopped
+ // This is pretty sketchy, but appears to work just fine
+ while (!LLApp::isStopped())
+ {
+ ms_sleep(10);
+ }
+
+#ifndef LL_RELEASE_FOR_DOWNLOAD
+ return false;
+#else
+ return true;
+#endif
+}
+#endif
diff --git a/indra/llcommon/llapp.h b/indra/llcommon/llapp.h
index d64af62538..ee1d696829 100644
--- a/indra/llcommon/llapp.h
+++ b/indra/llcommon/llapp.h
@@ -2,30 +2,25 @@
* @file llapp.h
* @brief Declaration of the LLApp class.
*
- * $LicenseInfo:firstyear=2003&license=viewergpl$
- *
- * Copyright (c) 2003-2007, Linden Research, Inc.
- *
+ * $LicenseInfo:firstyear=2003&license=viewerlgpl$
* Second Life Viewer Source Code
- * The source code in this file ("Source Code") is provided by Linden Lab
- * to you under the terms of the GNU General Public License, version 2.0
- * ("GPL"), unless you have obtained a separate licensing agreement
- * ("Other License"), formally executed by you and Linden Lab. Terms of
- * the GPL can be found in doc/GPL-license.txt in this distribution, or
- * online at http://secondlife.com/developers/opensource/gplv2
+ * Copyright (C) 2010, Linden Research, Inc.
*
- * There are special exceptions to the terms and conditions of the GPL as
- * it is applied to this Source Code. View the full text of the exception
- * in the file doc/FLOSS-exception.txt in this software distribution, or
- * online at http://secondlife.com/developers/opensource/flossexception
+ * 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.
*
- * By copying, modifying or distributing this software, you acknowledge
- * that you have read and understood your obligations described above,
- * and agree to abide by those obligations.
+ * 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.
*
- * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
- * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
- * COMPLETENESS OR PERFORMANCE.
+ * 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$
*/
@@ -33,20 +28,25 @@
#define LL_LLAPP_H
#include <map>
-#include "llapr.h"
#include "llrun.h"
#include "llsd.h"
+#include "lloptioninterface.h"
// Forward declarations
+template <typename Type> class LLAtomic32;
+typedef LLAtomic32<U32> LLAtomicU32;
class LLErrorThread;
-class LLApp;
-
+class LLLiveFile;
+#if LL_LINUX
+typedef struct siginfo siginfo_t;
+#endif
typedef void (*LLAppErrorHandler)();
typedef void (*LLAppChildCallback)(int pid, bool exited, int status);
#if !LL_WINDOWS
-extern const S32 LL_SMACKDOWN_SIGNAL;
+extern S32 LL_SMACKDOWN_SIGNAL;
+extern S32 LL_HEARTBEAT_SIGNAL;
// Clear all of the signal handlers (which we want to do for the child process when we fork
void clear_signals();
@@ -60,7 +60,11 @@ public:
};
#endif
-class LLApp
+namespace google_breakpad {
+ class ExceptionHandler; // See exception_handler.h
+}
+
+class LL_COMMON_API LLApp : public LLOptionInterface
{
friend class LLErrorThread;
public:
@@ -76,6 +80,11 @@ public:
LLApp();
virtual ~LLApp();
+protected:
+ LLApp(LLErrorThread* error_thread);
+ void commonCtor();
+public:
+
/**
* @brief Return the static app instance if one was created.
*/
@@ -104,7 +113,7 @@ public:
* @param name The name of the option.
* @return Returns the option data.
*/
- LLSD getOption(const std::string& name) const;
+ virtual LLSD getOption(const std::string& name) const;
/**
* @brief Parse command line options and insert them into
@@ -121,6 +130,19 @@ public:
bool parseCommandOptions(int argc, char** argv);
/**
+ * @brief Keep track of live files automatically.
+ *
+ * *TODO: it currently uses the <code>addToEventTimer()</code> API
+ * instead of the runner. I should probalby use the runner.
+ *
+ * *NOTE: DO NOT add the livefile instance to any kind of check loop.
+ *
+ * @param livefile A valid instance of an LLLiveFile. This LLApp
+ * instance will delete the livefile instance.
+ */
+ void manageLiveFile(LLLiveFile* livefile);
+
+ /**
* @brief Set the options at the specified priority.
*
* This function completely replaces the options at the priority
@@ -185,17 +207,45 @@ public:
#endif
static int getPid();
- //
- // Error handling methods
- //
+ /** @name Error handling methods */
+ //@{
+ /**
+ * @brief Do our generic platform-specific error-handling setup --
+ * signals on unix, structured exceptions on windows.
+ *
+ * DO call this method if your app will either spawn children or be
+ * spawned by a launcher.
+ * Call just after app object construction.
+ * (Otherwise your app will crash when getting signals,
+ * and will not core dump.)
+ *
+ * DO NOT call this method if your application has specialized
+ * error handling code.
+ */
+ void setupErrorHandling();
+
void setErrorHandler(LLAppErrorHandler handler);
+ static void runErrorHandler(); // run shortly after we detect an error, ran in the relatively robust context of the LLErrorThread - preferred.
+ //@}
+
+ // the maximum length of the minidump filename returned by getMiniDumpFilename()
+ static const U32 MAX_MINDUMP_PATH_LENGTH = 256;
+
+ // change the directory where Breakpad minidump files are written to
+ void setMiniDumpDir(const std::string &path);
+
+ // Return the Google Breakpad minidump filename after a crash.
+ char *getMiniDumpFilename() { return minidump_path; }
+
+ // Write out a Google Breakpad minidump file.
+ void writeMiniDump();
#if !LL_WINDOWS
//
// Child process handling (Unix only for now)
//
// Set a callback to be run on exit of a child process
- // WARNING! This callback is run from the signal handler due to the extreme crappiness of
+ // WARNING! This callback is run from the signal handler due to
// Linux threading requiring waitpid() to be called from the thread that spawned the process.
// At some point I will make this more behaved, but I'm not going to fix this right now - djs
void setChildCallback(pid_t pid, LLAppChildCallback callback);
@@ -204,8 +254,9 @@ public:
void setDefaultChildCallback(LLAppChildCallback callback);
// Fork and do the proper signal handling/error handling mojo
- // WARNING: You need to make sure your signal handling callback is correct after
- // you fork, because not all threads are duplicated when you fork!
+ // *NOTE: You need to make sure your signal handling callback is
+ // correct after you fork, because not all threads are duplicated
+ // when you fork!
pid_t fork();
#endif
@@ -243,9 +294,10 @@ protected:
void stepFrame();
private:
- void setupErrorHandling(); // Do platform-specific error-handling setup (signals, structured exceptions)
-
- static void runErrorHandler();
+ void startErrorThread();
+
+ // Contains the filename of the minidump file after a crash.
+ char minidump_path[MAX_MINDUMP_PATH_LENGTH];
// *NOTE: On Windows, we need a routine to reset the structured
// exception handler when some evil driver has taken it over for
@@ -265,11 +317,15 @@ private:
// The application options.
LLSD mOptions;
+ // The live files for this application
+ std::vector<LLLiveFile*> mLiveFiles;
//@}
private:
// the static application instance if it was created.
static LLApp* sApplication;
+
+ google_breakpad::ExceptionHandler * mExceptionHandler;
#if !LL_WINDOWS
diff --git a/indra/llcommon/llapr.cpp b/indra/llcommon/llapr.cpp
index 3512f2fb17..66ec5bad2c 100644
--- a/indra/llcommon/llapr.cpp
+++ b/indra/llcommon/llapr.cpp
@@ -4,30 +4,25 @@
* @date 2004-11-28
* @brief Helper functions for using the apache portable runtime library.
*
- * $LicenseInfo:firstyear=2004&license=viewergpl$
- *
- * Copyright (c) 2004-2007, Linden Research, Inc.
- *
+ * $LicenseInfo:firstyear=2004&license=viewerlgpl$
* Second Life Viewer Source Code
- * The source code in this file ("Source Code") is provided by Linden Lab
- * to you under the terms of the GNU General Public License, version 2.0
- * ("GPL"), unless you have obtained a separate licensing agreement
- * ("Other License"), formally executed by you and Linden Lab. Terms of
- * the GPL can be found in doc/GPL-license.txt in this distribution, or
- * online at http://secondlife.com/developers/opensource/gplv2
+ * Copyright (C) 2010, Linden Research, Inc.
*
- * There are special exceptions to the terms and conditions of the GPL as
- * it is applied to this Source Code. View the full text of the exception
- * in the file doc/FLOSS-exception.txt in this software distribution, or
- * online at http://secondlife.com/developers/opensource/flossexception
+ * 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.
*
- * By copying, modifying or distributing this software, you acknowledge
- * that you have read and understood your obligations described above,
- * and agree to abide by those obligations.
+ * 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.
*
- * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
- * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
- * COMPLETENESS OR PERFORMANCE.
+ * 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$
*/
@@ -35,8 +30,11 @@
#include "llapr.h"
apr_pool_t *gAPRPoolp = NULL; // Global APR memory pool
+LLVolatileAPRPool *LLAPRFile::sAPRFilePoolp = NULL ; //global volatile APR memory pool.
apr_thread_mutex_t *gLogMutexp = NULL;
+apr_thread_mutex_t *gCallStacksLogMutexp = NULL;
+const S32 FULL_VOLATILE_APR_POOL = 1024 ; //number of references to LLVolatileAPRPool
void ll_init_apr()
{
@@ -45,16 +43,22 @@ void ll_init_apr()
// Initialize APR and create the global pool
apr_initialize();
apr_pool_create(&gAPRPoolp, NULL);
-
+
// Initialize the logging mutex
apr_thread_mutex_create(&gLogMutexp, APR_THREAD_MUTEX_UNNESTED, gAPRPoolp);
+ apr_thread_mutex_create(&gCallStacksLogMutexp, APR_THREAD_MUTEX_UNNESTED, gAPRPoolp);
+ }
+
+ if(!LLAPRFile::sAPRFilePoolp)
+ {
+ LLAPRFile::sAPRFilePoolp = new LLVolatileAPRPool(FALSE) ;
}
}
void ll_cleanup_apr()
{
- llinfos << "Cleaning up APR" << llendl;
+ LL_INFOS("APR") << "Cleaning up APR" << LL_ENDL;
if (gLogMutexp)
{
@@ -64,15 +68,174 @@ void ll_cleanup_apr()
apr_thread_mutex_destroy(gLogMutexp);
gLogMutexp = NULL;
}
+ if (gCallStacksLogMutexp)
+ {
+ // Clean up the logging mutex
+
+ // All other threads NEED to be done before we clean up APR, so this is okay.
+ apr_thread_mutex_destroy(gCallStacksLogMutexp);
+ gCallStacksLogMutexp = NULL;
+ }
if (gAPRPoolp)
{
apr_pool_destroy(gAPRPoolp);
gAPRPoolp = NULL;
}
+ if (LLAPRFile::sAPRFilePoolp)
+ {
+ delete LLAPRFile::sAPRFilePoolp ;
+ LLAPRFile::sAPRFilePoolp = NULL ;
+ }
apr_terminate();
}
//
+//
+//LLAPRPool
+//
+LLAPRPool::LLAPRPool(apr_pool_t *parent, apr_size_t size, BOOL releasePoolFlag)
+ : mParent(parent),
+ mReleasePoolFlag(releasePoolFlag),
+ mMaxSize(size),
+ mPool(NULL)
+{
+ createAPRPool() ;
+}
+
+LLAPRPool::~LLAPRPool()
+{
+ releaseAPRPool() ;
+}
+
+void LLAPRPool::createAPRPool()
+{
+ if(mPool)
+ {
+ return ;
+ }
+
+ mStatus = apr_pool_create(&mPool, mParent);
+ ll_apr_warn_status(mStatus) ;
+
+ if(mMaxSize > 0) //size is the number of blocks (which is usually 4K), NOT bytes.
+ {
+ apr_allocator_t *allocator = apr_pool_allocator_get(mPool);
+ if (allocator)
+ {
+ apr_allocator_max_free_set(allocator, mMaxSize) ;
+ }
+ }
+}
+
+void LLAPRPool::releaseAPRPool()
+{
+ if(!mPool)
+ {
+ return ;
+ }
+
+ if(!mParent || mReleasePoolFlag)
+ {
+ apr_pool_destroy(mPool) ;
+ mPool = NULL ;
+ }
+}
+
+//virtual
+apr_pool_t* LLAPRPool::getAPRPool()
+{
+ return mPool ;
+}
+
+LLVolatileAPRPool::LLVolatileAPRPool(BOOL is_local, apr_pool_t *parent, apr_size_t size, BOOL releasePoolFlag)
+ : LLAPRPool(parent, size, releasePoolFlag),
+ mNumActiveRef(0),
+ mNumTotalRef(0),
+ mMutexPool(NULL),
+ mMutexp(NULL)
+{
+ //create mutex
+ if(!is_local) //not a local apr_pool, that is: shared by multiple threads.
+ {
+ apr_pool_create(&mMutexPool, NULL); // Create a pool for mutex
+ apr_thread_mutex_create(&mMutexp, APR_THREAD_MUTEX_UNNESTED, mMutexPool);
+ }
+}
+
+LLVolatileAPRPool::~LLVolatileAPRPool()
+{
+ //delete mutex
+ if(mMutexp)
+ {
+ apr_thread_mutex_destroy(mMutexp);
+ apr_pool_destroy(mMutexPool);
+ }
+}
+
+//
+//define this virtual function to avoid any mistakenly calling LLAPRPool::getAPRPool().
+//
+//virtual
+apr_pool_t* LLVolatileAPRPool::getAPRPool()
+{
+ return LLVolatileAPRPool::getVolatileAPRPool() ;
+}
+
+apr_pool_t* LLVolatileAPRPool::getVolatileAPRPool()
+{
+ LLScopedLock lock(mMutexp) ;
+
+ mNumTotalRef++ ;
+ mNumActiveRef++ ;
+
+ if(!mPool)
+ {
+ createAPRPool() ;
+ }
+
+ return mPool ;
+}
+
+void LLVolatileAPRPool::clearVolatileAPRPool()
+{
+ LLScopedLock lock(mMutexp) ;
+
+ if(mNumActiveRef > 0)
+ {
+ mNumActiveRef--;
+ if(mNumActiveRef < 1)
+ {
+ if(isFull())
+ {
+ mNumTotalRef = 0 ;
+
+ //destroy the apr_pool.
+ releaseAPRPool() ;
+ }
+ else
+ {
+ //This does not actually free the memory,
+ //it just allows the pool to re-use this memory for the next allocation.
+ apr_pool_clear(mPool) ;
+ }
+ }
+ }
+ else
+ {
+ llassert_always(mNumActiveRef > 0) ;
+ }
+
+ //paranoia check if the pool is jammed.
+ //will remove the check before going to release.
+ llassert_always(mNumTotalRef < (FULL_VOLATILE_APR_POOL << 2)) ;
+}
+
+BOOL LLVolatileAPRPool::isFull()
+{
+ return mNumTotalRef > FULL_VOLATILE_APR_POOL ;
+}
+//---------------------------------------------------------------------
+//
// LLScopedLock
//
LLScopedLock::LLScopedLock(apr_thread_mutex_t* mutex) : mMutex(mutex)
@@ -110,14 +273,14 @@ void LLScopedLock::unlock()
}
}
-//
-// Misc functions
-//
+//---------------------------------------------------------------------
+
bool ll_apr_warn_status(apr_status_t status)
{
if(APR_SUCCESS == status) return false;
char buf[MAX_STRING]; /* Flawfinder: ignore */
- llwarns << "APR: " << apr_strerror(status, buf, MAX_STRING) << llendl;
+ apr_strerror(status, buf, MAX_STRING);
+ LL_WARNS("APR") << "APR: " << buf << LL_ENDL;
return true;
}
@@ -126,57 +289,139 @@ void ll_apr_assert_status(apr_status_t status)
llassert(ll_apr_warn_status(status) == false);
}
-// File I/O
-apr_file_t* ll_apr_file_open(const LLString& filename, apr_int32_t flags, S32* sizep, apr_pool_t* pool)
+//---------------------------------------------------------------------
+//
+// LLAPRFile functions
+//
+LLAPRFile::LLAPRFile()
+ : mFile(NULL),
+ mCurrentFilePoolp(NULL)
{
- apr_file_t* apr_file;
- apr_status_t s;
- if (pool == NULL) pool = gAPRPoolp;
- s = apr_file_open(&apr_file, filename.c_str(), flags, APR_OS_DEFAULT, pool);
- if (s != APR_SUCCESS)
+}
+
+LLAPRFile::LLAPRFile(const std::string& filename, apr_int32_t flags, LLVolatileAPRPool* pool)
+ : mFile(NULL),
+ mCurrentFilePoolp(NULL)
+{
+ open(filename, flags, pool);
+}
+
+LLAPRFile::~LLAPRFile()
+{
+ close() ;
+}
+
+apr_status_t LLAPRFile::close()
+{
+ apr_status_t ret = APR_SUCCESS ;
+ if(mFile)
+ {
+ ret = apr_file_close(mFile);
+ mFile = NULL ;
+ }
+
+ if(mCurrentFilePoolp)
+ {
+ mCurrentFilePoolp->clearVolatileAPRPool() ;
+ mCurrentFilePoolp = NULL ;
+ }
+
+ return ret ;
+}
+
+apr_status_t LLAPRFile::open(const std::string& filename, apr_int32_t flags, LLVolatileAPRPool* pool, S32* sizep)
+{
+ apr_status_t s ;
+
+ //check if already open some file
+ llassert_always(!mFile) ;
+ llassert_always(!mCurrentFilePoolp) ;
+
+ apr_pool_t* apr_pool = pool ? pool->getVolatileAPRPool() : NULL ;
+ s = apr_file_open(&mFile, filename.c_str(), flags, APR_OS_DEFAULT, getAPRFilePool(apr_pool));
+
+ if (s != APR_SUCCESS || !mFile)
{
+ mFile = NULL ;
+
if (sizep)
{
*sizep = 0;
}
- return NULL;
}
-
- if (sizep)
+ else if (sizep)
{
S32 file_size = 0;
apr_off_t offset = 0;
- if (apr_file_seek(apr_file, APR_END, &offset) == APR_SUCCESS)
+ if (apr_file_seek(mFile, APR_END, &offset) == APR_SUCCESS)
{
llassert_always(offset <= 0x7fffffff);
file_size = (S32)offset;
offset = 0;
- apr_file_seek(apr_file, APR_SET, &offset);
+ apr_file_seek(mFile, APR_SET, &offset);
}
*sizep = file_size;
}
- return apr_file;
-}
-apr_file_t* ll_apr_file_open(const LLString& filename, apr_int32_t flags, S32* sizep)
-{
- return ll_apr_file_open(filename, flags, sizep, NULL);
+ if(!mCurrentFilePoolp)
+ {
+ mCurrentFilePoolp = pool ;
+
+ if(!mFile)
+ {
+ close() ;
+ }
+ }
+
+ return s ;
}
-apr_file_t* ll_apr_file_open(const LLString& filename, apr_int32_t flags, apr_pool_t* pool)
+
+//use gAPRPoolp.
+apr_status_t LLAPRFile::open(const std::string& filename, apr_int32_t flags, BOOL use_global_pool)
{
- return ll_apr_file_open(filename, flags, NULL, pool);
+ apr_status_t s;
+
+ //check if already open some file
+ llassert_always(!mFile) ;
+ llassert_always(!mCurrentFilePoolp) ;
+ llassert_always(use_global_pool) ; //be aware of using gAPRPoolp.
+
+ s = apr_file_open(&mFile, filename.c_str(), flags, APR_OS_DEFAULT, gAPRPoolp);
+ if (s != APR_SUCCESS || !mFile)
+ {
+ mFile = NULL ;
+ close() ;
+ return s;
+ }
+
+ return s;
}
-apr_file_t* ll_apr_file_open(const LLString& filename, apr_int32_t flags)
-{
- return ll_apr_file_open(filename, flags, NULL, NULL);
+
+apr_pool_t* LLAPRFile::getAPRFilePool(apr_pool_t* pool)
+{
+ if(!pool)
+ {
+ mCurrentFilePoolp = sAPRFilePoolp ;
+ return mCurrentFilePoolp->getVolatileAPRPool() ;
+ }
+
+ return pool ;
}
-S32 ll_apr_file_read(apr_file_t* apr_file, void *buf, S32 nbytes)
+// File I/O
+S32 LLAPRFile::read(void *buf, S32 nbytes)
{
+ if(!mFile)
+ {
+ llwarns << "apr mFile is removed by somebody else. Can not read." << llendl ;
+ return 0;
+ }
+
apr_size_t sz = nbytes;
- apr_status_t s = apr_file_read(apr_file, buf, &sz);
+ apr_status_t s = apr_file_read(mFile, buf, &sz);
if (s != APR_SUCCESS)
{
+ ll_apr_warn_status(s);
return 0;
}
else
@@ -186,39 +431,19 @@ S32 ll_apr_file_read(apr_file_t* apr_file, void *buf, S32 nbytes)
}
}
-S32 ll_apr_file_read_ex(const LLString& filename, apr_pool_t* pool, void *buf, S32 offset, S32 nbytes)
+S32 LLAPRFile::write(const void *buf, S32 nbytes)
{
- if (pool == NULL) pool = gAPRPoolp;
- apr_file_t* filep = ll_apr_file_open(filename, APR_READ|APR_BINARY, pool);
- if (!filep)
+ if(!mFile)
{
+ llwarns << "apr mFile is removed by somebody else. Can not write." << llendl ;
return 0;
}
- S32 off;
- if (offset < 0)
- off = ll_apr_file_seek(filep, APR_END, 0);
- else
- off = ll_apr_file_seek(filep, APR_SET, offset);
- S32 bytes_read;
- if (off < 0)
- {
- bytes_read = 0;
- }
- else
- {
- bytes_read = ll_apr_file_read(filep, buf, nbytes );
- }
- apr_file_close(filep);
-
- return bytes_read;
-}
-
-S32 ll_apr_file_write(apr_file_t* apr_file, const void *buf, S32 nbytes)
-{
+
apr_size_t sz = nbytes;
- apr_status_t s = apr_file_write(apr_file, buf, &sz);
+ apr_status_t s = apr_file_write(mFile, buf, &sz);
if (s != APR_SUCCESS)
{
+ ll_apr_warn_status(s);
return 0;
}
else
@@ -228,54 +453,78 @@ S32 ll_apr_file_write(apr_file_t* apr_file, const void *buf, S32 nbytes)
}
}
-S32 ll_apr_file_write_ex(const LLString& filename, apr_pool_t* pool, void *buf, S32 offset, S32 nbytes)
+S32 LLAPRFile::seek(apr_seek_where_t where, S32 offset)
{
- if (pool == NULL) pool = gAPRPoolp;
- apr_int32_t flags = APR_CREATE|APR_WRITE|APR_BINARY;
- if (offset < 0)
- {
- flags |= APR_APPEND;
- offset = 0;
- }
- apr_file_t* filep = ll_apr_file_open(filename, flags, pool);
- if (!filep)
- {
- return 0;
- }
- if (offset > 0)
+ return LLAPRFile::seek(mFile, where, offset) ;
+}
+
+//
+//*******************************************************************************************************************************
+//static components of LLAPRFile
+//
+
+//static
+apr_status_t LLAPRFile::close(apr_file_t* file_handle, LLVolatileAPRPool* pool)
+{
+ apr_status_t ret = APR_SUCCESS ;
+ if(file_handle)
{
- offset = ll_apr_file_seek(filep, APR_SET, offset);
+ ret = apr_file_close(file_handle);
+ file_handle = NULL ;
}
- S32 bytes_written;
- if (offset < 0)
+
+ if(pool)
{
- bytes_written = 0;
+ pool->clearVolatileAPRPool() ;
}
- else
+
+ return ret ;
+}
+
+//static
+apr_file_t* LLAPRFile::open(const std::string& filename, LLVolatileAPRPool* pool, apr_int32_t flags)
+{
+ apr_status_t s;
+ apr_file_t* file_handle ;
+
+ pool = pool ? pool : LLAPRFile::sAPRFilePoolp ;
+
+ s = apr_file_open(&file_handle, filename.c_str(), flags, APR_OS_DEFAULT, pool->getVolatileAPRPool());
+ if (s != APR_SUCCESS || !file_handle)
{
- bytes_written = ll_apr_file_write(filep, buf, nbytes );
+ ll_apr_warn_status(s);
+ LL_WARNS("APR") << " Attempting to open filename: " << filename << LL_ENDL;
+ file_handle = NULL ;
+ close(file_handle, pool) ;
+ return NULL;
}
- apr_file_close(filep);
- return bytes_written;
+ return file_handle ;
}
-S32 ll_apr_file_seek(apr_file_t* apr_file, apr_seek_where_t where, S32 offset)
+//static
+S32 LLAPRFile::seek(apr_file_t* file_handle, apr_seek_where_t where, S32 offset)
{
+ if(!file_handle)
+ {
+ return -1 ;
+ }
+
apr_status_t s;
apr_off_t apr_offset;
if (offset >= 0)
{
apr_offset = (apr_off_t)offset;
- s = apr_file_seek(apr_file, where, &apr_offset);
+ s = apr_file_seek(file_handle, where, &apr_offset);
}
else
{
apr_offset = 0;
- s = apr_file_seek(apr_file, APR_END, &apr_offset);
+ s = apr_file_seek(file_handle, APR_END, &apr_offset);
}
if (s != APR_SUCCESS)
{
+ ll_apr_warn_status(s);
return -1;
}
else
@@ -285,66 +534,181 @@ S32 ll_apr_file_seek(apr_file_t* apr_file, apr_seek_where_t where, S32 offset)
}
}
-bool ll_apr_file_remove(const LLString& filename, apr_pool_t* pool)
+//static
+S32 LLAPRFile::readEx(const std::string& filename, void *buf, S32 offset, S32 nbytes, LLVolatileAPRPool* pool)
+{
+ //*****************************************
+ apr_file_t* file_handle = open(filename, pool, APR_READ|APR_BINARY);
+ //*****************************************
+ if (!file_handle)
+ {
+ return 0;
+ }
+
+ llassert(offset >= 0);
+
+ if (offset > 0)
+ offset = LLAPRFile::seek(file_handle, APR_SET, offset);
+
+ apr_size_t bytes_read;
+ if (offset < 0)
+ {
+ bytes_read = 0;
+ }
+ else
+ {
+ bytes_read = nbytes ;
+ apr_status_t s = apr_file_read(file_handle, buf, &bytes_read);
+ if (s != APR_SUCCESS)
+ {
+ LL_WARNS("APR") << " Attempting to read filename: " << filename << LL_ENDL;
+ ll_apr_warn_status(s);
+ bytes_read = 0;
+ }
+ else
+ {
+ llassert_always(bytes_read <= 0x7fffffff);
+ }
+ }
+
+ //*****************************************
+ close(file_handle, pool) ;
+ //*****************************************
+ return (S32)bytes_read;
+}
+
+//static
+S32 LLAPRFile::writeEx(const std::string& filename, void *buf, S32 offset, S32 nbytes, LLVolatileAPRPool* pool)
+{
+ apr_int32_t flags = APR_CREATE|APR_WRITE|APR_BINARY;
+ if (offset < 0)
+ {
+ flags |= APR_APPEND;
+ offset = 0;
+ }
+
+ //*****************************************
+ apr_file_t* file_handle = open(filename, pool, flags);
+ //*****************************************
+ if (!file_handle)
+ {
+ return 0;
+ }
+
+ if (offset > 0)
+ {
+ offset = LLAPRFile::seek(file_handle, APR_SET, offset);
+ }
+
+ apr_size_t bytes_written;
+ if (offset < 0)
+ {
+ bytes_written = 0;
+ }
+ else
+ {
+ bytes_written = nbytes ;
+ apr_status_t s = apr_file_write(file_handle, buf, &bytes_written);
+ if (s != APR_SUCCESS)
+ {
+ LL_WARNS("APR") << " Attempting to write filename: " << filename << LL_ENDL;
+ ll_apr_warn_status(s);
+ bytes_written = 0;
+ }
+ else
+ {
+ llassert_always(bytes_written <= 0x7fffffff);
+ }
+ }
+
+ //*****************************************
+ LLAPRFile::close(file_handle, pool);
+ //*****************************************
+
+ return (S32)bytes_written;
+}
+
+//static
+bool LLAPRFile::remove(const std::string& filename, LLVolatileAPRPool* pool)
{
apr_status_t s;
- if (pool == NULL) pool = gAPRPoolp;
- s = apr_file_remove(filename.c_str(), pool);
+
+ pool = pool ? pool : LLAPRFile::sAPRFilePoolp ;
+ s = apr_file_remove(filename.c_str(), pool->getVolatileAPRPool());
+ pool->clearVolatileAPRPool() ;
+
if (s != APR_SUCCESS)
{
- lldebugs << "ll_apr_file_remove failed on file: " << filename << llendl;
ll_apr_warn_status(s);
+ LL_WARNS("APR") << " Attempting to remove filename: " << filename << LL_ENDL;
return false;
}
return true;
}
-bool ll_apr_file_rename(const LLString& filename, const LLString& newname, apr_pool_t* pool)
+//static
+bool LLAPRFile::rename(const std::string& filename, const std::string& newname, LLVolatileAPRPool* pool)
{
apr_status_t s;
- if (pool == NULL) pool = gAPRPoolp;
- s = apr_file_rename(filename.c_str(), newname.c_str(), pool);
+
+ pool = pool ? pool : LLAPRFile::sAPRFilePoolp ;
+ s = apr_file_rename(filename.c_str(), newname.c_str(), pool->getVolatileAPRPool());
+ pool->clearVolatileAPRPool() ;
+
if (s != APR_SUCCESS)
{
- lldebugs << "ll_apr_file_rename failed on file: " << filename << llendl;
ll_apr_warn_status(s);
+ LL_WARNS("APR") << " Attempting to rename filename: " << filename << LL_ENDL;
return false;
}
return true;
}
-bool ll_apr_file_exists(const LLString& filename, apr_pool_t* pool)
+//static
+bool LLAPRFile::isExist(const std::string& filename, LLVolatileAPRPool* pool, apr_int32_t flags)
{
apr_file_t* apr_file;
apr_status_t s;
- if (pool == NULL) pool = gAPRPoolp;
- s = apr_file_open(&apr_file, filename.c_str(), APR_READ, APR_OS_DEFAULT, pool);
+
+ pool = pool ? pool : LLAPRFile::sAPRFilePoolp ;
+ s = apr_file_open(&apr_file, filename.c_str(), flags, APR_OS_DEFAULT, pool->getVolatileAPRPool());
+
if (s != APR_SUCCESS || !apr_file)
{
+ pool->clearVolatileAPRPool() ;
return false;
}
else
{
- apr_file_close(apr_file);
+ apr_file_close(apr_file) ;
+ pool->clearVolatileAPRPool() ;
return true;
}
}
-S32 ll_apr_file_size(const LLString& filename, apr_pool_t* pool)
+//static
+S32 LLAPRFile::size(const std::string& filename, LLVolatileAPRPool* pool)
{
apr_file_t* apr_file;
apr_finfo_t info;
apr_status_t s;
- if (pool == NULL) pool = gAPRPoolp;
- s = apr_file_open(&apr_file, filename.c_str(), APR_READ, APR_OS_DEFAULT, pool);
+
+ pool = pool ? pool : LLAPRFile::sAPRFilePoolp ;
+ s = apr_file_open(&apr_file, filename.c_str(), APR_READ, APR_OS_DEFAULT, pool->getVolatileAPRPool());
+
if (s != APR_SUCCESS || !apr_file)
- {
+ {
+ pool->clearVolatileAPRPool() ;
+
return 0;
}
else
{
- apr_status_t s = apr_file_info_get(&info, APR_FINFO_SIZE, apr_file);
- apr_file_close(apr_file);
+ apr_status_t s = apr_file_info_get(&info, APR_FINFO_SIZE, apr_file);
+
+ apr_file_close(apr_file) ;
+ pool->clearVolatileAPRPool() ;
+
if (s == APR_SUCCESS)
{
return (S32)info.size;
@@ -356,31 +720,42 @@ S32 ll_apr_file_size(const LLString& filename, apr_pool_t* pool)
}
}
-bool ll_apr_dir_make(const LLString& dirname, apr_pool_t* pool)
+//static
+bool LLAPRFile::makeDir(const std::string& dirname, LLVolatileAPRPool* pool)
{
apr_status_t s;
- if (pool == NULL) pool = gAPRPoolp;
- s = apr_dir_make(dirname.c_str(), APR_FPROT_OS_DEFAULT, pool);
+
+ pool = pool ? pool : LLAPRFile::sAPRFilePoolp ;
+ s = apr_dir_make(dirname.c_str(), APR_FPROT_OS_DEFAULT, pool->getVolatileAPRPool());
+ pool->clearVolatileAPRPool() ;
+
if (s != APR_SUCCESS)
{
- lldebugs << "ll_apr_dir_make failed on file: " << dirname << llendl;
ll_apr_warn_status(s);
+ LL_WARNS("APR") << " Attempting to make directory: " << dirname << LL_ENDL;
return false;
}
return true;
}
-bool ll_apr_dir_remove(const LLString& dirname, apr_pool_t* pool)
+//static
+bool LLAPRFile::removeDir(const std::string& dirname, LLVolatileAPRPool* pool)
{
apr_status_t s;
- if (pool == NULL) pool = gAPRPoolp;
- s = apr_file_remove(dirname.c_str(), pool);
+
+ pool = pool ? pool : LLAPRFile::sAPRFilePoolp ;
+ s = apr_file_remove(dirname.c_str(), pool->getVolatileAPRPool());
+ pool->clearVolatileAPRPool() ;
+
if (s != APR_SUCCESS)
{
- lldebugs << "ll_apr_dir_remove failed on file: " << dirname << llendl;
ll_apr_warn_status(s);
+ LL_WARNS("APR") << " Attempting to remove directory: " << dirname << LL_ENDL;
return false;
}
return true;
}
-
+//
+//end of static components of LLAPRFile
+//*******************************************************************************************************************************
+//
diff --git a/indra/llcommon/llapr.h b/indra/llcommon/llapr.h
index b6c363886c..4930270af8 100644
--- a/indra/llcommon/llapr.h
+++ b/indra/llcommon/llapr.h
@@ -4,30 +4,25 @@
* @date 2004-11-28
* @brief Helper functions for using the apache portable runtime library.
*
- * $LicenseInfo:firstyear=2004&license=viewergpl$
- *
- * Copyright (c) 2004-2007, Linden Research, Inc.
- *
+ * $LicenseInfo:firstyear=2004&license=viewerlgpl$
* Second Life Viewer Source Code
- * The source code in this file ("Source Code") is provided by Linden Lab
- * to you under the terms of the GNU General Public License, version 2.0
- * ("GPL"), unless you have obtained a separate licensing agreement
- * ("Other License"), formally executed by you and Linden Lab. Terms of
- * the GPL can be found in doc/GPL-license.txt in this distribution, or
- * online at http://secondlife.com/developers/opensource/gplv2
+ * 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.
*
- * There are special exceptions to the terms and conditions of the GPL as
- * it is applied to this Source Code. View the full text of the exception
- * in the file doc/FLOSS-exception.txt in this software distribution, or
- * online at http://secondlife.com/developers/opensource/flossexception
+ * 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.
*
- * By copying, modifying or distributing this software, you acknowledge
- * that you have read and understood your obligations described above,
- * and agree to abide by those obligations.
+ * 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
*
- * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
- * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
- * COMPLETENESS OR PERFORMANCE.
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
* $/LicenseInfo$
*/
@@ -37,28 +32,87 @@
#if LL_LINUX || LL_SOLARIS
#include <sys/param.h> // Need PATH_MAX in APR headers...
#endif
+#if LL_WINDOWS
+ // Limit Windows API to small and manageable set.
+ // If you get undefined symbols, find the appropriate
+ // Windows header file and include that in your .cpp file.
+ #define WIN32_LEAN_AND_MEAN
+ #include <winsock2.h>
+ #include <windows.h>
+#endif
#include <boost/noncopyable.hpp>
-#include "apr-1/apr_thread_proc.h"
-#include "apr-1/apr_thread_mutex.h"
-#include "apr-1/apr_getopt.h"
-#include "apr-1/apr_signal.h"
-#include "apr-1/apr_atomic.h"
+#include "apr_thread_proc.h"
+#include "apr_thread_mutex.h"
+#include "apr_getopt.h"
+#include "apr_signal.h"
+#include "apr_atomic.h"
#include "llstring.h"
-extern apr_thread_mutex_t* gLogMutexp;
+extern LL_COMMON_API apr_thread_mutex_t* gLogMutexp;
+extern apr_thread_mutex_t* gCallStacksLogMutexp;
/**
* @brief initialize the common apr constructs -- apr itself, the
* global pool, and a mutex.
*/
-void ll_init_apr();
+void LL_COMMON_API ll_init_apr();
/**
* @brief Cleanup those common apr constructs.
*/
-void ll_cleanup_apr();
+void LL_COMMON_API ll_cleanup_apr();
+
+//
+//LL apr_pool
+//manage apr_pool_t, destroy allocated apr_pool in the destruction function.
+//
+class LL_COMMON_API LLAPRPool
+{
+public:
+ LLAPRPool(apr_pool_t *parent = NULL, apr_size_t size = 0, BOOL releasePoolFlag = TRUE) ;
+ virtual ~LLAPRPool() ;
+
+ virtual apr_pool_t* getAPRPool() ;
+ apr_status_t getStatus() {return mStatus ; }
+
+protected:
+ void releaseAPRPool() ;
+ void createAPRPool() ;
+
+protected:
+ apr_pool_t* mPool ; //pointing to an apr_pool
+ apr_pool_t* mParent ; //parent pool
+ apr_size_t mMaxSize ; //max size of mPool, mPool should return memory to system if allocated memory beyond this limit. However it seems not to work.
+ apr_status_t mStatus ; //status when creating the pool
+ BOOL mReleasePoolFlag ; //if set, mPool is destroyed when LLAPRPool is deleted. default value is true.
+};
+
+//
+//volatile LL apr_pool
+//which clears memory automatically.
+//so it can not hold static data or data after memory is cleared
+//
+class LL_COMMON_API LLVolatileAPRPool : public LLAPRPool
+{
+public:
+ LLVolatileAPRPool(BOOL is_local = TRUE, apr_pool_t *parent = NULL, apr_size_t size = 0, BOOL releasePoolFlag = TRUE);
+ virtual ~LLVolatileAPRPool();
+
+ /*virtual*/ apr_pool_t* getAPRPool() ; //define this virtual function to avoid any mistakenly calling LLAPRPool::getAPRPool().
+ apr_pool_t* getVolatileAPRPool() ;
+ void clearVolatileAPRPool() ;
+
+ BOOL isFull() ;
+
+private:
+ S32 mNumActiveRef ; //number of active pointers pointing to the apr_pool.
+ S32 mNumTotalRef ; //number of total pointers pointing to the apr_pool since last creating.
+
+ apr_thread_mutex_t *mMutexp;
+ apr_pool_t *mMutexPool;
+} ;
/**
* @class LLScopedLock
@@ -69,7 +123,7 @@ void ll_cleanup_apr();
* destructor handles the unlock. Instances of this class are
* <b>not</b> thread safe.
*/
-class LLScopedLock : private boost::noncopyable
+class LL_COMMON_API LLScopedLock : private boost::noncopyable
{
public:
/**
@@ -122,7 +176,7 @@ typedef LLAtomic32<U32> LLAtomicU32;
typedef LLAtomic32<S32> LLAtomicS32;
// File IO convenience functions.
-// Returns NULL if the file fails to openm sets *sizep to file size of not NULL
+// Returns NULL if the file fails to open, sets *sizep to file size if not NULL
// abbreviated flags
#define LL_APR_R (APR_READ) // "r"
#define LL_APR_W (APR_CREATE|APR_TRUNCATE|APR_WRITE) // "w"
@@ -130,34 +184,84 @@ typedef LLAtomic32<S32> LLAtomicS32;
#define LL_APR_WB (APR_CREATE|APR_TRUNCATE|APR_WRITE|APR_BINARY) // "wb"
#define LL_APR_RPB (APR_READ|APR_WRITE|APR_BINARY) // "r+b"
#define LL_APR_WPB (APR_CREATE|APR_TRUNCATE|APR_READ|APR_WRITE|APR_BINARY) // "w+b"
-apr_file_t* ll_apr_file_open(const LLString& filename, apr_int32_t flags, S32* sizep, apr_pool_t* pool);
-apr_file_t* ll_apr_file_open(const LLString& filename, apr_int32_t flags, S32* sizep);
-apr_file_t* ll_apr_file_open(const LLString& filename, apr_int32_t flags, apr_pool_t* pool);
-apr_file_t* ll_apr_file_open(const LLString& filename, apr_int32_t flags);
-// Returns actual offset, -1 if seek fails
-S32 ll_apr_file_seek(apr_file_t* apr_file, apr_seek_where_t where, S32 offset);
-// Returns bytes read/written, 0 if read/write fails:
-S32 ll_apr_file_read(apr_file_t* apr_file, void* buf, S32 nbytes);
-S32 ll_apr_file_read_ex(const LLString& filename, apr_pool_t* pool, void *buf, S32 offset, S32 nbytes);
-S32 ll_apr_file_write(apr_file_t* apr_file, const void* buf, S32 nbytes);
-S32 ll_apr_file_write_ex(const LLString& filename, apr_pool_t* pool, void *buf, S32 offset, S32 nbytes);
-// returns false if failure:
-bool ll_apr_file_remove(const LLString& filename, apr_pool_t* pool = NULL);
-bool ll_apr_file_rename(const LLString& filename, const LLString& newname, apr_pool_t* pool = NULL);
-bool ll_apr_file_exists(const LLString& filename, apr_pool_t* pool = NULL);
-S32 ll_apr_file_size(const LLString& filename, apr_pool_t* pool = NULL);
-bool ll_apr_dir_make(const LLString& dirname, apr_pool_t* pool = NULL);
-bool ll_apr_dir_remove(const LLString& dirname, apr_pool_t* pool = NULL);
+
+//
+//apr_file manager
+//which: 1)only keeps one file open;
+// 2)closes the open file in the destruction function
+// 3)informs the apr_pool to clean the memory when the file is closed.
+//Note: please close an open file at the earliest convenience.
+// especially do not put some time-costly operations between open() and close().
+// otherwise it might lock the APRFilePool.
+//there are two different apr_pools the APRFile can use:
+// 1, a temporary pool passed to an APRFile function, which is used within this function and only once.
+// 2, a global pool.
+//
+
+class LL_COMMON_API LLAPRFile : boost::noncopyable
+{
+ // make this non copyable since a copy closes the file
+private:
+ apr_file_t* mFile ;
+ LLVolatileAPRPool *mCurrentFilePoolp ; //currently in use apr_pool, could be one of them: sAPRFilePoolp, or a temp pool.
+
+public:
+ LLAPRFile() ;
+ LLAPRFile(const std::string& filename, apr_int32_t flags, LLVolatileAPRPool* pool = NULL);
+ ~LLAPRFile() ;
+
+ apr_status_t open(const std::string& filename, apr_int32_t flags, LLVolatileAPRPool* pool = NULL, S32* sizep = NULL);
+ apr_status_t open(const std::string& filename, apr_int32_t flags, BOOL use_global_pool); //use gAPRPoolp.
+ apr_status_t close() ;
+
+ // Returns actual offset, -1 if seek fails
+ S32 seek(apr_seek_where_t where, S32 offset);
+ apr_status_t eof() { return apr_file_eof(mFile);}
+
+ // Returns bytes read/written, 0 if read/write fails:
+ S32 read(void* buf, S32 nbytes);
+ S32 write(const void* buf, S32 nbytes);
+
+ apr_file_t* getFileHandle() {return mFile;}
+
+private:
+ apr_pool_t* getAPRFilePool(apr_pool_t* pool) ;
+
+//
+//*******************************************************************************************************************************
+//static components
+//
+public:
+ static LLVolatileAPRPool *sAPRFilePoolp ; //a global apr_pool for APRFile, which is used only when local pool does not exist.
+
+private:
+ static apr_file_t* open(const std::string& filename, LLVolatileAPRPool* pool, apr_int32_t flags);
+ static apr_status_t close(apr_file_t* file, LLVolatileAPRPool* pool) ;
+ static S32 seek(apr_file_t* file, apr_seek_where_t where, S32 offset);
+public:
+ // returns false if failure:
+ static bool remove(const std::string& filename, LLVolatileAPRPool* pool = NULL);
+ static bool rename(const std::string& filename, const std::string& newname, LLVolatileAPRPool* pool = NULL);
+ static bool isExist(const std::string& filename, LLVolatileAPRPool* pool = NULL, apr_int32_t flags = APR_READ);
+ static S32 size(const std::string& filename, LLVolatileAPRPool* pool = NULL);
+ static bool makeDir(const std::string& dirname, LLVolatileAPRPool* pool = NULL);
+ static bool removeDir(const std::string& dirname, LLVolatileAPRPool* pool = NULL);
+
+ // Returns bytes read/written, 0 if read/write fails:
+ static S32 readEx(const std::string& filename, void *buf, S32 offset, S32 nbytes, LLVolatileAPRPool* pool = NULL);
+ static S32 writeEx(const std::string& filename, void *buf, S32 offset, S32 nbytes, LLVolatileAPRPool* pool = NULL); // offset<0 means append
+//*******************************************************************************************************************************
+};
/**
- * @brief Function which approprately logs error or remains quiet on
+ * @brief Function which appropriately logs error or remains quiet on
* APR_SUCCESS.
* @return Returns <code>true</code> if status is an error condition.
*/
-bool ll_apr_warn_status(apr_status_t status);
+bool LL_COMMON_API ll_apr_warn_status(apr_status_t status);
-void ll_apr_assert_status(apr_status_t status);
+void LL_COMMON_API ll_apr_assert_status(apr_status_t status);
-extern "C" apr_pool_t* gAPRPoolp; // Global APR memory pool
+extern "C" LL_COMMON_API apr_pool_t* gAPRPoolp; // Global APR memory pool
#endif // LL_LLAPR_H
diff --git a/indra/llcommon/llassettype.cpp b/indra/llcommon/llassettype.cpp
index 06504b53fd..eb610f625a 100644
--- a/indra/llcommon/llassettype.cpp
+++ b/indra/llcommon/llassettype.cpp
@@ -2,255 +2,250 @@
* @file llassettype.cpp
* @brief Implementatino of LLAssetType functionality.
*
- * $LicenseInfo:firstyear=2001&license=viewergpl$
- *
- * Copyright (c) 2001-2007, Linden Research, Inc.
- *
+ * $LicenseInfo:firstyear=2001&license=viewerlgpl$
* Second Life Viewer Source Code
- * The source code in this file ("Source Code") is provided by Linden Lab
- * to you under the terms of the GNU General Public License, version 2.0
- * ("GPL"), unless you have obtained a separate licensing agreement
- * ("Other License"), formally executed by you and Linden Lab. Terms of
- * the GPL can be found in doc/GPL-license.txt in this distribution, or
- * online at http://secondlife.com/developers/opensource/gplv2
+ * Copyright (C) 2010, Linden Research, Inc.
*
- * There are special exceptions to the terms and conditions of the GPL as
- * it is applied to this Source Code. View the full text of the exception
- * in the file doc/FLOSS-exception.txt in this software distribution, or
- * online at http://secondlife.com/developers/opensource/flossexception
+ * 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.
*
- * By copying, modifying or distributing this software, you acknowledge
- * that you have read and understood your obligations described above,
- * and agree to abide by those obligations.
+ * 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.
*
- * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
- * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
- * COMPLETENESS OR PERFORMANCE.
+ * 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$
*/
#include "linden_common.h"
#include "llassettype.h"
+#include "lldictionary.h"
+#include "llmemory.h"
+#include "llsingleton.h"
-#include "llstring.h"
-#include "lltimer.h"
+///----------------------------------------------------------------------------
+/// Class LLAssetType
+///----------------------------------------------------------------------------
+struct AssetEntry : public LLDictionaryEntry
+{
+ AssetEntry(const char *desc_name,
+ const char *type_name, // 8 character limit!
+ const char *human_name, // for decoding to human readable form; put any and as many printable characters you want in each one
+ bool can_link, // can you create a link to this type?
+ bool can_fetch, // can you fetch this asset by ID?
+ bool can_know) // can you see this asset's ID?
+ :
+ LLDictionaryEntry(desc_name),
+ mTypeName(type_name),
+ mHumanName(human_name),
+ mCanLink(can_link),
+ mCanFetch(can_fetch),
+ mCanKnow(can_know)
+ {
+ llassert(strlen(mTypeName) <= 8);
+ }
-// I added lookups for exact text of asset type enums in addition to the ones below, so shoot me. -Steve
+ const char *mTypeName;
+ const char *mHumanName;
+ bool mCanLink;
+ bool mCanFetch;
+ bool mCanKnow;
+};
-struct asset_info_t
+class LLAssetDictionary : public LLSingleton<LLAssetDictionary>,
+ public LLDictionary<LLAssetType::EType, AssetEntry>
{
- LLAssetType::EType type;
- const char* desc;
+public:
+ LLAssetDictionary();
};
-asset_info_t asset_types[] =
+LLAssetDictionary::LLAssetDictionary()
{
- { LLAssetType::AT_TEXTURE, "TEXTURE" },
- { LLAssetType::AT_SOUND, "SOUND" },
- { LLAssetType::AT_CALLINGCARD, "CALLINGCARD" },
- { LLAssetType::AT_LANDMARK, "LANDMARK" },
- { LLAssetType::AT_SCRIPT, "SCRIPT" },
- { LLAssetType::AT_CLOTHING, "CLOTHING" },
- { LLAssetType::AT_OBJECT, "OBJECT" },
- { LLAssetType::AT_NOTECARD, "NOTECARD" },
- { LLAssetType::AT_CATEGORY, "CATEGORY" },
- { LLAssetType::AT_ROOT_CATEGORY, "ROOT_CATEGORY" },
- { LLAssetType::AT_LSL_TEXT, "LSL_TEXT" },
- { LLAssetType::AT_LSL_BYTECODE, "LSL_BYTECODE" },
- { LLAssetType::AT_TEXTURE_TGA, "TEXTURE_TGA" },
- { LLAssetType::AT_BODYPART, "BODYPART" },
- { LLAssetType::AT_TRASH, "TRASH" },
- { LLAssetType::AT_SNAPSHOT_CATEGORY, "SNAPSHOT_CATEGORY" },
- { LLAssetType::AT_LOST_AND_FOUND, "LOST_AND_FOUND" },
- { LLAssetType::AT_SOUND_WAV, "SOUND_WAV" },
- { LLAssetType::AT_IMAGE_TGA, "IMAGE_TGA" },
- { LLAssetType::AT_IMAGE_JPEG, "IMAGE_JPEG" },
- { LLAssetType::AT_ANIMATION, "ANIMATION" },
- { LLAssetType::AT_GESTURE, "GESTURE" },
- { LLAssetType::AT_SIMSTATE, "SIMSTATE" },
- { LLAssetType::AT_NONE, "NONE" },
+ // DESCRIPTION TYPE NAME HUMAN NAME CAN LINK? CAN FETCH? CAN KNOW?
+ // |--------------------|-----------|-------------------|-----------|-----------|---------|
+ addEntry(LLAssetType::AT_TEXTURE, new AssetEntry("TEXTURE", "texture", "texture", true, false, true));
+ addEntry(LLAssetType::AT_SOUND, new AssetEntry("SOUND", "sound", "sound", true, true, true));
+ addEntry(LLAssetType::AT_CALLINGCARD, new AssetEntry("CALLINGCARD", "callcard", "calling card", true, false, false));
+ addEntry(LLAssetType::AT_LANDMARK, new AssetEntry("LANDMARK", "landmark", "landmark", true, true, true));
+ addEntry(LLAssetType::AT_SCRIPT, new AssetEntry("SCRIPT", "script", "legacy script", true, false, false));
+ addEntry(LLAssetType::AT_CLOTHING, new AssetEntry("CLOTHING", "clothing", "clothing", true, true, true));
+ addEntry(LLAssetType::AT_OBJECT, new AssetEntry("OBJECT", "object", "object", true, false, false));
+ addEntry(LLAssetType::AT_NOTECARD, new AssetEntry("NOTECARD", "notecard", "note card", true, false, true));
+ addEntry(LLAssetType::AT_CATEGORY, new AssetEntry("CATEGORY", "category", "folder", true, false, false));
+ addEntry(LLAssetType::AT_LSL_TEXT, new AssetEntry("LSL_TEXT", "lsltext", "lsl2 script", true, false, false));
+ addEntry(LLAssetType::AT_LSL_BYTECODE, new AssetEntry("LSL_BYTECODE", "lslbyte", "lsl bytecode", true, false, false));
+ addEntry(LLAssetType::AT_TEXTURE_TGA, new AssetEntry("TEXTURE_TGA", "txtr_tga", "tga texture", true, false, false));
+ addEntry(LLAssetType::AT_BODYPART, new AssetEntry("BODYPART", "bodypart", "body part", true, true, true));
+ addEntry(LLAssetType::AT_SOUND_WAV, new AssetEntry("SOUND_WAV", "snd_wav", "sound", true, false, false));
+ addEntry(LLAssetType::AT_IMAGE_TGA, new AssetEntry("IMAGE_TGA", "img_tga", "targa image", true, false, false));
+ addEntry(LLAssetType::AT_IMAGE_JPEG, new AssetEntry("IMAGE_JPEG", "jpeg", "jpeg image", true, false, false));
+ addEntry(LLAssetType::AT_ANIMATION, new AssetEntry("ANIMATION", "animatn", "animation", true, true, true));
+ addEntry(LLAssetType::AT_GESTURE, new AssetEntry("GESTURE", "gesture", "gesture", true, true, true));
+ addEntry(LLAssetType::AT_SIMSTATE, new AssetEntry("SIMSTATE", "simstate", "simstate", false, false, false));
+
+ addEntry(LLAssetType::AT_LINK, new AssetEntry("LINK", "link", "sym link", false, false, true));
+ addEntry(LLAssetType::AT_LINK_FOLDER, new AssetEntry("FOLDER_LINK", "link_f", "sym folder link", false, false, true));
+
+ addEntry(LLAssetType::AT_NONE, new AssetEntry("NONE", "-1", NULL, false, false, false));
};
-LLAssetType::EType LLAssetType::getType(const std::string& sin)
+// static
+LLAssetType::EType LLAssetType::getType(const std::string& desc_name)
{
- std::string s = sin;
- LLString::toUpper(s);
- for (S32 idx = 0; ;idx++)
- {
- asset_info_t* info = asset_types + idx;
- if (info->type == LLAssetType::AT_NONE)
- break;
- if (s == info->desc)
- return info->type;
- }
- return LLAssetType::AT_NONE;
+ std::string s = desc_name;
+ LLStringUtil::toUpper(s);
+ return LLAssetDictionary::getInstance()->lookup(s);
}
-std::string LLAssetType::getDesc(LLAssetType::EType type)
+// static
+const std::string &LLAssetType::getDesc(LLAssetType::EType asset_type)
{
- for (S32 idx = 0; ;idx++)
+ const AssetEntry *entry = LLAssetDictionary::getInstance()->lookup(asset_type);
+ if (entry)
+ {
+ return entry->mName;
+ }
+ else
{
- asset_info_t* info = asset_types + idx;
- if (type == info->type)
- return info->desc;
- if (info->type == LLAssetType::AT_NONE)
- break;
+ return badLookup();
}
- return "BAD TYPE";
}
-//============================================================================
-
-// The asset type names are limited to 8 characters.
-// static
-const char* LLAssetType::mAssetTypeNames[LLAssetType::AT_COUNT] =
-{
- "texture",
- "sound",
- "callcard",
- "landmark",
- "script",
- "clothing",
- "object",
- "notecard",
- "category",
- "root",
- "lsltext",
- "lslbyte",
- "txtr_tga",// Intentionally spelled this way. Limited to eight characters.
- "bodypart",
- "trash",
- "snapshot",
- "lstndfnd",
- "snd_wav",
- "img_tga",
- "jpeg",
- "animatn",
- "gesture",
- "simstate",
-};
-
-// This table is meant for decoding to human readable form. Put any
-// and as many printable characters you want in each one.
-// See also llinventory.cpp INVENTORY_TYPE_HUMAN_NAMES
-const char* LLAssetType::mAssetTypeHumanNames[LLAssetType::AT_COUNT] =
-{
- "texture",
- "sound",
- "calling card",
- "landmark",
- "legacy script",
- "clothing",
- "object",
- "note card",
- "folder",
- "root",
- "lsl2 script",
- "lsl bytecode",
- "tga texture",
- "body part",
- "trash",
- "snapshot",
- "lost and found",
- "sound",
- "targa image",
- "jpeg image",
- "animation",
- "gesture",
- "simstate",
-};
-
-///----------------------------------------------------------------------------
-/// class LLAssetType
-///----------------------------------------------------------------------------
-
// static
-const char* LLAssetType::lookup( LLAssetType::EType type )
+const char *LLAssetType::lookup(LLAssetType::EType asset_type)
{
- if( (type >= 0) && (type < AT_COUNT ))
+ const LLAssetDictionary *dict = LLAssetDictionary::getInstance();
+ const AssetEntry *entry = dict->lookup(asset_type);
+ if (entry)
{
- return mAssetTypeNames[ S32( type ) ];
+ return entry->mTypeName;
}
else
{
- return "-1";
+ return badLookup().c_str();
}
}
// static
-LLAssetType::EType LLAssetType::lookup( const char* name )
+LLAssetType::EType LLAssetType::lookup(const char* name)
{
- for( S32 i = 0; i < AT_COUNT; i++ )
+ return lookup(ll_safe_string(name));
+}
+
+// static
+LLAssetType::EType LLAssetType::lookup(const std::string& type_name)
+{
+ const LLAssetDictionary *dict = LLAssetDictionary::getInstance();
+ for (LLAssetDictionary::const_iterator iter = dict->begin();
+ iter != dict->end();
+ iter++)
{
- if( 0 == strcmp(name, mAssetTypeNames[i]) )
+ const AssetEntry *entry = iter->second;
+ if (type_name == entry->mTypeName)
{
- // match
- return (EType)i;
+ return iter->first;
}
}
return AT_NONE;
}
// static
-const char* LLAssetType::lookupHumanReadable(LLAssetType::EType type)
+const char *LLAssetType::lookupHumanReadable(LLAssetType::EType asset_type)
{
- if( (type >= 0) && (type < AT_COUNT ))
+ const LLAssetDictionary *dict = LLAssetDictionary::getInstance();
+ const AssetEntry *entry = dict->lookup(asset_type);
+ if (entry)
{
- return mAssetTypeHumanNames[S32(type)];
+ return entry->mHumanName;
}
else
{
- return NULL;
+ return badLookup().c_str();
}
}
// static
-LLAssetType::EType LLAssetType::lookupHumanReadable( const char* name )
+LLAssetType::EType LLAssetType::lookupHumanReadable(const char* name)
{
- for( S32 i = 0; i < AT_COUNT; i++ )
+ return lookupHumanReadable(ll_safe_string(name));
+}
+
+// static
+LLAssetType::EType LLAssetType::lookupHumanReadable(const std::string& readable_name)
+{
+ const LLAssetDictionary *dict = LLAssetDictionary::getInstance();
+ for (LLAssetDictionary::const_iterator iter = dict->begin();
+ iter != dict->end();
+ iter++)
{
- if( 0 == strcmp(name, mAssetTypeHumanNames[i]) )
+ const AssetEntry *entry = iter->second;
+ if (entry->mHumanName && (readable_name == entry->mHumanName))
{
- // match
- return (EType)i;
+ return iter->first;
}
}
return AT_NONE;
}
-EDragAndDropType LLAssetType::lookupDragAndDropType( EType asset )
+// static
+bool LLAssetType::lookupCanLink(EType asset_type)
+{
+ const LLAssetDictionary *dict = LLAssetDictionary::getInstance();
+ const AssetEntry *entry = dict->lookup(asset_type);
+ if (entry)
+ {
+ return entry->mCanLink;
+ }
+ return false;
+}
+
+// static
+// Not adding this to dictionary since we probably will only have these two types
+bool LLAssetType::lookupIsLinkType(EType asset_type)
{
- switch( asset )
+ if (asset_type == AT_LINK || asset_type == AT_LINK_FOLDER)
{
- case AT_TEXTURE: return DAD_TEXTURE;
- case AT_SOUND: return DAD_SOUND;
- case AT_CALLINGCARD: return DAD_CALLINGCARD;
- case AT_LANDMARK: return DAD_LANDMARK;
- case AT_SCRIPT: return DAD_NONE;
- case AT_CLOTHING: return DAD_CLOTHING;
- case AT_OBJECT: return DAD_OBJECT;
- case AT_NOTECARD: return DAD_NOTECARD;
- case AT_CATEGORY: return DAD_CATEGORY;
- case AT_ROOT_CATEGORY: return DAD_ROOT_CATEGORY;
- case AT_LSL_TEXT: return DAD_SCRIPT;
- case AT_BODYPART: return DAD_BODYPART;
- case AT_ANIMATION: return DAD_ANIMATION;
- case AT_GESTURE: return DAD_GESTURE;
- default: return DAD_NONE;
- };
+ return true;
+ }
+ return false;
}
-// static. Generate a good default description
-void LLAssetType::generateDescriptionFor(LLAssetType::EType type,
- std::string& desc)
+// static
+const std::string &LLAssetType::badLookup()
{
- const S32 BUF_SIZE = 30;
- char time_str[BUF_SIZE]; /* Flawfinder: ignore */
- time_t now;
- time(&now);
- memset(time_str, '\0', BUF_SIZE);
- strftime(time_str, BUF_SIZE - 1, "%Y-%m-%d %H:%M:%S ", localtime(&now));
- desc.assign(time_str);
- desc.append(LLAssetType::lookupHumanReadable(type));
+ static const std::string sBadLookup = "llassettype_bad_lookup";
+ return sBadLookup;
+
+}
+
+// static
+bool LLAssetType::lookupIsAssetFetchByIDAllowed(EType asset_type)
+{
+ const LLAssetDictionary *dict = LLAssetDictionary::getInstance();
+ const AssetEntry *entry = dict->lookup(asset_type);
+ if (entry)
+ {
+ return entry->mCanFetch;
+ }
+ return false;
+}
+
+// static
+bool LLAssetType::lookupIsAssetIDKnowable(EType asset_type)
+{
+ const LLAssetDictionary *dict = LLAssetDictionary::getInstance();
+ const AssetEntry *entry = dict->lookup(asset_type);
+ if (entry)
+ {
+ return entry->mCanKnow;
+ }
+ return false;
}
diff --git a/indra/llcommon/llassettype.h b/indra/llcommon/llassettype.h
index f71e0b98cd..c5ff2364cc 100644
--- a/indra/llcommon/llassettype.h
+++ b/indra/llcommon/llassettype.h
@@ -2,174 +2,152 @@
* @file llassettype.h
* @brief Declaration of LLAssetType.
*
- * $LicenseInfo:firstyear=2001&license=viewergpl$
- *
- * Copyright (c) 2001-2007, Linden Research, Inc.
- *
+ * $LicenseInfo:firstyear=2001&license=viewerlgpl$
* Second Life Viewer Source Code
- * The source code in this file ("Source Code") is provided by Linden Lab
- * to you under the terms of the GNU General Public License, version 2.0
- * ("GPL"), unless you have obtained a separate licensing agreement
- * ("Other License"), formally executed by you and Linden Lab. Terms of
- * the GPL can be found in doc/GPL-license.txt in this distribution, or
- * online at http://secondlife.com/developers/opensource/gplv2
+ * 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.
*
- * There are special exceptions to the terms and conditions of the GPL as
- * it is applied to this Source Code. View the full text of the exception
- * in the file doc/FLOSS-exception.txt in this software distribution, or
- * online at http://secondlife.com/developers/opensource/flossexception
+ * 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.
*
- * By copying, modifying or distributing this software, you acknowledge
- * that you have read and understood your obligations described above,
- * and agree to abide by those obligations.
+ * 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
*
- * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
- * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
- * COMPLETENESS OR PERFORMANCE.
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
* $/LicenseInfo$
*/
-#ifndef LL_LLASSETTYPE
-#define LL_LLASSETTYPE
+#ifndef LL_LLASSETTYPE_H
+#define LL_LLASSETTYPE_H
#include <string>
#include "stdenums.h" // for EDragAndDropType
-class LLAssetType
+class LL_COMMON_API LLAssetType
{
public:
enum EType
{
- // Used for painting the faces of geometry.
- // Stored in typical j2c stream format
AT_TEXTURE = 0,
+ // Used for painting the faces of geometry.
+ // Stored in typical j2c stream format.
- // Used to fill the aural spectrum.
AT_SOUND = 1,
+ // Used to fill the aural spectrum.
- // Links instant message access to the user on the card. eg, a
- // card for yourself, a card for linden support, a card for
- // the guy you were talking to in the coliseum.
AT_CALLINGCARD = 2,
+ // Links instant message access to the user on the card.
+ // : E.G. A card for yourself, for linden support, for
+ // : the guy you were talking to in the coliseum.
- // Links to places in the world with location and a screen
- // shot or image saved. eg, home, linden headquarters, the
- // coliseum, or destinations where we want to increase
- // traffic.
AT_LANDMARK = 3,
+ // Links to places in the world with location and a screen shot or image saved.
+ // : E.G. Home, linden headquarters, the coliseum, destinations where
+ // : we want to increase traffic.
- // Valid scripts that can be attached to an object. eg. open a
- // door, jump into the air.
AT_SCRIPT = 4,
+ // Valid scripts that can be attached to an object.
+ // : E.G. Open a door, jump into the air.
- // A collection of textures and parameters that can be worn
- // by an avatar.
AT_CLOTHING = 5,
+ // A collection of textures and parameters that can be worn by an avatar.
- // Any combination of textures, sounds, and scripts that are
- // associated with a fixed piece of geometry. eg, a hot tub, a
- // house with working door.
AT_OBJECT = 6,
+ // Any combination of textures, sounds, and scripts that are
+ // associated with a fixed piece of geometry.
+ // : E.G. A hot tub, a house with working door.
- // Just text
AT_NOTECARD = 7,
+ // Just text.
- // A category holds a collection of inventory items. It's
- // treated as an item in the inventory, and therefore needs a
- // type.
AT_CATEGORY = 8,
+ // Holds a collection of inventory items.
+ // It's treated as an item in the inventory and therefore needs a type.
- // A root category is a user's root inventory category. We
- // decided to expose it visually, so it seems logical to fold
- // it into the asset types.
- AT_ROOT_CATEGORY = 9,
-
- // The LSL is the brand spanking new scripting language. We've
- // split it into a text and bytecode representation.
AT_LSL_TEXT = 10,
AT_LSL_BYTECODE = 11,
+ // The LSL is the scripting language.
+ // We've split it into a text and bytecode representation.
- // uncompressed TGA texture
AT_TEXTURE_TGA = 12,
+ // Uncompressed TGA texture.
- // A collection of textures and parameters that can be worn
- // by an avatar.
AT_BODYPART = 13,
+ // A collection of textures and parameters that can be worn by an avatar.
- // This asset type is meant to only be used as a marker for a
- // category preferred type. Using this, we can throw things in
- // the trash before completely deleting.
- AT_TRASH = 14,
-
- // This is a marker for a folder meant for snapshots. No
- // actual assets will be snapshots, though if there were, you
- // could interpret them as textures.
- AT_SNAPSHOT_CATEGORY = 15,
-
- // This is used to stuff lost&found items into
- AT_LOST_AND_FOUND = 16,
-
- // uncompressed sound
AT_SOUND_WAV = 17,
+ // Uncompressed sound.
- // uncompressed image, non-square, and not appropriate for use
- // as a texture.
AT_IMAGE_TGA = 18,
+ // Uncompressed image, non-square.
+ // Not appropriate for use as a texture.
- // compressed image, non-square, and not appropriate for use
- // as a texture.
AT_IMAGE_JPEG = 19,
+ // Compressed image, non-square.
+ // Not appropriate for use as a texture.
- // animation
AT_ANIMATION = 20,
+ // Animation.
- // gesture, sequence of animations, sounds, chat, wait steps
AT_GESTURE = 21,
+ // Gesture, sequence of animations, sounds, chat, wait steps.
- // simstate file
AT_SIMSTATE = 22,
+ // Simstate file.
- // +*********************************************+
- // | TO ADD AN ELEMENT TO THIS ENUM: |
- // +*********************************************+
- // | 1. INSERT BEFORE AT_COUNT |
- // | 2. INCREMENT AT_COUNT BY 1 |
- // | 3. ADD TO LLAssetType::mAssetTypeNames |
- // | 4. ADD TO LLAssetType::mAssetTypeHumanNames |
- // +*********************************************+
+ AT_LINK = 24,
+ // Inventory symbolic link
- AT_COUNT = 23,
+ AT_LINK_FOLDER = 25,
+ // Inventory folder link
+
+ AT_COUNT = 26,
+
+ // +*********************************************************+
+ // | TO ADD AN ELEMENT TO THIS ENUM: |
+ // +*********************************************************+
+ // | 1. INSERT BEFORE AT_COUNT |
+ // | 2. INCREMENT AT_COUNT BY 1 |
+ // | 3. ADD TO LLAssetType.cpp |
+ // | 4. ADD TO LLViewerAssetType.cpp |
+ // | 5. ADD TO DEFAULT_ASSET_FOR_INV in LLInventoryType.cpp |
+ // +*********************************************************+
AT_NONE = -1
};
// machine transation between type and strings
- static EType lookup(const char* name);
- static const char* lookup(EType type);
+ static EType lookup(const char* name); // safe conversion to std::string, *TODO: deprecate
+ static EType lookup(const std::string& type_name);
+ static const char* lookup(EType asset_type);
// translation from a type to a human readable form.
- static EType lookupHumanReadable( const char* name );
- static const char* lookupHumanReadable(EType type);
+ static EType lookupHumanReadable(const char* desc_name); // safe conversion to std::string, *TODO: deprecate
+ static EType lookupHumanReadable(const std::string& readable_name);
+ static const char* lookupHumanReadable(EType asset_type);
- static EDragAndDropType lookupDragAndDropType( EType );
+ static EType getType(const std::string& desc_name);
+ static const std::string& getDesc(EType asset_type);
- // Generate a good default description. You may want to add a verb
- // or agent name after this depending on your application.
- static void generateDescriptionFor(LLAssetType::EType type,
- std::string& desc);
+ static bool lookupCanLink(EType asset_type);
+ static bool lookupIsLinkType(EType asset_type);
- static EType getType(const std::string& sin);
- static std::string getDesc(EType type);
+ static bool lookupIsAssetFetchByIDAllowed(EType asset_type); // the asset allows direct download
+ static bool lookupIsAssetIDKnowable(EType asset_type); // asset data can be known by the viewer
-private:
- // don't instantiate or derive one of these objects
- LLAssetType( void ) {}
- ~LLAssetType( void ) {}
-
-private:
- static const char* mAssetTypeNames[];
- static const char* mAssetTypeHumanNames[];
+ static const std::string& badLookup(); // error string when a lookup fails
+
+protected:
+ LLAssetType() {}
+ ~LLAssetType() {}
};
-#endif // LL_LLASSETTYPE
+#endif // LL_LLASSETTYPE_H
diff --git a/indra/llcommon/llassoclist.h b/indra/llcommon/llassoclist.h
index 974bc1ec41..2950504155 100644
--- a/indra/llcommon/llassoclist.h
+++ b/indra/llcommon/llassoclist.h
@@ -2,30 +2,25 @@
* @file llassoclist.h
* @brief LLAssocList class header file
*
- * $LicenseInfo:firstyear=2001&license=viewergpl$
- *
- * Copyright (c) 2001-2007, Linden Research, Inc.
- *
+ * $LicenseInfo:firstyear=2001&license=viewerlgpl$
* Second Life Viewer Source Code
- * The source code in this file ("Source Code") is provided by Linden Lab
- * to you under the terms of the GNU General Public License, version 2.0
- * ("GPL"), unless you have obtained a separate licensing agreement
- * ("Other License"), formally executed by you and Linden Lab. Terms of
- * the GPL can be found in doc/GPL-license.txt in this distribution, or
- * online at http://secondlife.com/developers/opensource/gplv2
+ * 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.
*
- * There are special exceptions to the terms and conditions of the GPL as
- * it is applied to this Source Code. View the full text of the exception
- * in the file doc/FLOSS-exception.txt in this software distribution, or
- * online at http://secondlife.com/developers/opensource/flossexception
+ * 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.
*
- * By copying, modifying or distributing this software, you acknowledge
- * that you have read and understood your obligations described above,
- * and agree to abide by those obligations.
+ * 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
*
- * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
- * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
- * COMPLETENESS OR PERFORMANCE.
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
* $/LicenseInfo$
*/
diff --git a/indra/llcommon/llavatarconstants.h b/indra/llcommon/llavatarconstants.h
index 4ba664287d..596b0643ef 100644
--- a/indra/llcommon/llavatarconstants.h
+++ b/indra/llcommon/llavatarconstants.h
@@ -2,30 +2,25 @@
* @file llavatarconstants.h
* @brief some useful short term constants for Indra
*
- * $LicenseInfo:firstyear=2001&license=viewergpl$
- *
- * Copyright (c) 2001-2007, Linden Research, Inc.
- *
+ * $LicenseInfo:firstyear=2001&license=viewerlgpl$
* Second Life Viewer Source Code
- * The source code in this file ("Source Code") is provided by Linden Lab
- * to you under the terms of the GNU General Public License, version 2.0
- * ("GPL"), unless you have obtained a separate licensing agreement
- * ("Other License"), formally executed by you and Linden Lab. Terms of
- * the GPL can be found in doc/GPL-license.txt in this distribution, or
- * online at http://secondlife.com/developers/opensource/gplv2
+ * 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.
*
- * There are special exceptions to the terms and conditions of the GPL as
- * it is applied to this Source Code. View the full text of the exception
- * in the file doc/FLOSS-exception.txt in this software distribution, or
- * online at http://secondlife.com/developers/opensource/flossexception
+ * 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.
*
- * By copying, modifying or distributing this software, you acknowledge
- * that you have read and understood your obligations described above,
- * and agree to abide by those obligations.
+ * 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
*
- * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
- * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
- * COMPLETENESS OR PERFORMANCE.
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
* $/LicenseInfo$
*/
diff --git a/indra/llcommon/llavatarname.cpp b/indra/llcommon/llavatarname.cpp
new file mode 100644
index 0000000000..b1ec9e9875
--- /dev/null
+++ b/indra/llcommon/llavatarname.cpp
@@ -0,0 +1,113 @@
+/**
+ * @file llavatarname.cpp
+ * @brief Represents name-related data for an avatar, such as the
+ * username/SLID ("bobsmith123" or "james.linden") and the display
+ * name ("James Cook")
+ *
+ * $LicenseInfo:firstyear=2010&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$
+ */
+#include "linden_common.h"
+
+#include "llavatarname.h"
+
+#include "lldate.h"
+#include "llsd.h"
+
+// Store these in pre-built std::strings to avoid memory allocations in
+// LLSD map lookups
+static const std::string USERNAME("username");
+static const std::string DISPLAY_NAME("display_name");
+static const std::string LEGACY_FIRST_NAME("legacy_first_name");
+static const std::string LEGACY_LAST_NAME("legacy_last_name");
+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");
+
+LLAvatarName::LLAvatarName()
+: mUsername(),
+ mDisplayName(),
+ mLegacyFirstName(),
+ mLegacyLastName(),
+ mIsDisplayNameDefault(false),
+ mIsDummy(false),
+ mExpires(F64_MAX),
+ mNextUpdate(0.0)
+{ }
+
+bool LLAvatarName::operator<(const LLAvatarName& rhs) const
+{
+ if (mUsername == rhs.mUsername)
+ return mDisplayName < rhs.mDisplayName;
+ else
+ return mUsername < rhs.mUsername;
+}
+
+LLSD LLAvatarName::asLLSD() const
+{
+ LLSD sd;
+ sd[USERNAME] = mUsername;
+ sd[DISPLAY_NAME] = mDisplayName;
+ sd[LEGACY_FIRST_NAME] = mLegacyFirstName;
+ sd[LEGACY_LAST_NAME] = mLegacyLastName;
+ sd[IS_DISPLAY_NAME_DEFAULT] = mIsDisplayNameDefault;
+ sd[DISPLAY_NAME_EXPIRES] = LLDate(mExpires);
+ sd[DISPLAY_NAME_NEXT_UPDATE] = LLDate(mNextUpdate);
+ return sd;
+}
+
+void LLAvatarName::fromLLSD(const LLSD& sd)
+{
+ mUsername = sd[USERNAME].asString();
+ mDisplayName = sd[DISPLAY_NAME].asString();
+ mLegacyFirstName = sd[LEGACY_FIRST_NAME].asString();
+ mLegacyLastName = sd[LEGACY_LAST_NAME].asString();
+ mIsDisplayNameDefault = sd[IS_DISPLAY_NAME_DEFAULT].asBoolean();
+ LLDate expires = sd[DISPLAY_NAME_EXPIRES];
+ mExpires = expires.secondsSinceEpoch();
+ LLDate next_update = sd[DISPLAY_NAME_NEXT_UPDATE];
+ mNextUpdate = next_update.secondsSinceEpoch();
+}
+
+std::string LLAvatarName::getCompleteName() const
+{
+ std::string name;
+ if (!mUsername.empty())
+ {
+ name = mDisplayName + " (" + mUsername + ")";
+ }
+ else
+ {
+ // ...display names are off, legacy name is in mDisplayName
+ name = mDisplayName;
+ }
+ return name;
+}
+
+std::string LLAvatarName::getLegacyName() const
+{
+ std::string name;
+ name.reserve( mLegacyFirstName.size() + 1 + mLegacyLastName.size() );
+ name = mLegacyFirstName;
+ name += " ";
+ name += mLegacyLastName;
+ return name;
+}
diff --git a/indra/llcommon/llavatarname.h b/indra/llcommon/llavatarname.h
new file mode 100644
index 0000000000..145aeccd35
--- /dev/null
+++ b/indra/llcommon/llavatarname.h
@@ -0,0 +1,95 @@
+/**
+ * @file llavatarname.h
+ * @brief Represents name-related data for an avatar, such as the
+ * username/SLID ("bobsmith123" or "james.linden") and the display
+ * name ("James Cook")
+ *
+ * $LicenseInfo:firstyear=2010&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$
+ */
+#ifndef LLAVATARNAME_H
+#define LLAVATARNAME_H
+
+#include <string>
+
+class LLSD;
+
+class LL_COMMON_API LLAvatarName
+{
+public:
+ LLAvatarName();
+
+ bool operator<(const LLAvatarName& rhs) const;
+
+ LLSD asLLSD() const;
+
+ void fromLLSD(const LLSD& sd);
+
+ // For normal names, returns "James Linden (james.linden)"
+ // When display names are disabled returns just "James Linden"
+ std::string getCompleteName() const;
+
+ // Returns "James Linden" or "bobsmith123 Resident" for backwards
+ // compatibility with systems like voice and muting
+ // *TODO: Eliminate this in favor of username only
+ std::string getLegacyName() const;
+
+ // "bobsmith123" or "james.linden", US-ASCII only
+ std::string mUsername;
+
+ // "Jose' 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;
+
+ // For "James Linden", "James"
+ // For "bobsmith123", "bobsmith123"
+ // Used to communicate with legacy systems like voice and muting which
+ // rely on old-style names.
+ // *TODO: Eliminate this in favor of username only
+ std::string mLegacyFirstName;
+
+ // For "James Linden", "Linden"
+ // For "bobsmith123", "Resident"
+ // see above for rationale
+ std::string mLegacyLastName;
+
+ // If true, both display name and SLID were generated from
+ // a legacy first and last name, like "James Linden (james.linden)"
+ bool mIsDisplayNameDefault;
+
+ // Under error conditions, we may insert "dummy" records with
+ // names like "???" into caches as placeholders. These can be
+ // shown in UI, but are not serialized.
+ bool mIsDummy;
+
+ // 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;
+};
+
+#endif
diff --git a/indra/llcommon/llbase32.cpp b/indra/llcommon/llbase32.cpp
index 50f789e249..053ac0d32f 100644
--- a/indra/llcommon/llbase32.cpp
+++ b/indra/llcommon/llbase32.cpp
@@ -7,30 +7,25 @@
* http://ghostwhitecrab.com/bitter/
*
* Some parts of this file are:
- * $LicenseInfo:firstyear=2007&license=viewergpl$
- *
- * Copyright (c) 2007, Linden Research, Inc.
- *
+ * $LicenseInfo:firstyear=2007&license=viewerlgpl$
* Second Life Viewer Source Code
- * The source code in this file ("Source Code") is provided by Linden Lab
- * to you under the terms of the GNU General Public License, version 2.0
- * ("GPL"), unless you have obtained a separate licensing agreement
- * ("Other License"), formally executed by you and Linden Lab. Terms of
- * the GPL can be found in doc/GPL-license.txt in this distribution, or
- * online at http://secondlife.com/developers/opensource/gplv2
+ * Copyright (C) 2010, Linden Research, Inc.
*
- * There are special exceptions to the terms and conditions of the GPL as
- * it is applied to this Source Code. View the full text of the exception
- * in the file doc/FLOSS-exception.txt in this software distribution, or
- * online at http://secondlife.com/developers/opensource/flossexception
+ * 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.
*
- * By copying, modifying or distributing this software, you acknowledge
- * that you have read and understood your obligations described above,
- * and agree to abide by those obligations.
+ * 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.
*
- * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
- * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
- * COMPLETENESS OR PERFORMANCE.
+ * 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$
*/
@@ -145,8 +140,6 @@ base32_encode(char *dst, size_t size, const void *data, size_t len)
/* *TODO: Implement base32 encode.
-#define ARRAY_LEN(a) (sizeof (a) / sizeof((a)[0]))
-
static inline int
ascii_toupper(int c)
{
@@ -172,7 +165,7 @@ base32_decode(char *dst, size_t size, const void *data, size_t len)
unsigned max_pad = 3;
if (0 == base32_map[0]) {
- for (i = 0; i < ARRAY_LEN(base32_map); i++) {
+ for (i = 0; i < LL_ARRAY_SIZE(base32_map); i++) {
const char *x;
x = memchr(base32_alphabet, ascii_toupper(i), sizeof base32_alphabet);
@@ -196,7 +189,7 @@ base32_decode(char *dst, size_t size, const void *data, size_t len)
}
}
- j = i % ARRAY_LEN(s);
+ j = i % LL_ARRAY_SIZE(s);
s[j] = c;
if (7 == j) {
@@ -208,7 +201,7 @@ base32_decode(char *dst, size_t size, const void *data, size_t len)
b[3] = ((s[4] & 1) << 7) | ((s[5] & 0x1f) << 2) | ((s[6] >> 3) & 0x03);
b[4] = ((s[6] & 0x07) << 5) | (s[7] & 0x1f);
- for (j = 0; j < ARRAY_LEN(b); j++) {
+ for (j = 0; j < LL_ARRAY_SIZE(b); j++) {
if (q != end)
*q = b[j];
q++;
diff --git a/indra/llcommon/llbase32.h b/indra/llcommon/llbase32.h
index 5254d0ab7c..eeb96d789d 100644
--- a/indra/llcommon/llbase32.h
+++ b/indra/llcommon/llbase32.h
@@ -3,37 +3,32 @@
* @brief base32 encoding that returns a std::string
* @author James Cook
*
- * $LicenseInfo:firstyear=2007&license=viewergpl$
- *
- * Copyright (c) 2007, Linden Research, Inc.
- *
+ * $LicenseInfo:firstyear=2007&license=viewerlgpl$
* Second Life Viewer Source Code
- * The source code in this file ("Source Code") is provided by Linden Lab
- * to you under the terms of the GNU General Public License, version 2.0
- * ("GPL"), unless you have obtained a separate licensing agreement
- * ("Other License"), formally executed by you and Linden Lab. Terms of
- * the GPL can be found in doc/GPL-license.txt in this distribution, or
- * online at http://secondlife.com/developers/opensource/gplv2
+ * 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.
*
- * There are special exceptions to the terms and conditions of the GPL as
- * it is applied to this Source Code. View the full text of the exception
- * in the file doc/FLOSS-exception.txt in this software distribution, or
- * online at http://secondlife.com/developers/opensource/flossexception
+ * 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.
*
- * By copying, modifying or distributing this software, you acknowledge
- * that you have read and understood your obligations described above,
- * and agree to abide by those obligations.
+ * 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
*
- * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
- * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
- * COMPLETENESS OR PERFORMANCE.
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
* $/LicenseInfo$
*/
#ifndef LLBASE32_H
-#define LLBASE32_h
+#define LLBASE32_H
-class LLBase32
+class LL_COMMON_API LLBase32
{
public:
static std::string encode(const U8* input, size_t input_size);
diff --git a/indra/llcommon/llbase64.cpp b/indra/llcommon/llbase64.cpp
index 207b367f6d..4e82cf7f20 100644
--- a/indra/llcommon/llbase64.cpp
+++ b/indra/llcommon/llbase64.cpp
@@ -3,30 +3,25 @@
* @brief Wrapper for apr base64 encoding that returns a std::string
* @author James Cook
*
- * $LicenseInfo:firstyear=2007&license=viewergpl$
- *
- * Copyright (c) 2007, Linden Research, Inc.
- *
+ * $LicenseInfo:firstyear=2007&license=viewerlgpl$
* Second Life Viewer Source Code
- * The source code in this file ("Source Code") is provided by Linden Lab
- * to you under the terms of the GNU General Public License, version 2.0
- * ("GPL"), unless you have obtained a separate licensing agreement
- * ("Other License"), formally executed by you and Linden Lab. Terms of
- * the GPL can be found in doc/GPL-license.txt in this distribution, or
- * online at http://secondlife.com/developers/opensource/gplv2
+ * 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.
*
- * There are special exceptions to the terms and conditions of the GPL as
- * it is applied to this Source Code. View the full text of the exception
- * in the file doc/FLOSS-exception.txt in this software distribution, or
- * online at http://secondlife.com/developers/opensource/flossexception
+ * 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.
*
- * By copying, modifying or distributing this software, you acknowledge
- * that you have read and understood your obligations described above,
- * and agree to abide by those obligations.
+ * 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
*
- * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
- * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
- * COMPLETENESS OR PERFORMANCE.
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
* $/LicenseInfo$
*/
@@ -36,7 +31,7 @@
#include <string>
-#include "apr-1/apr_base64.h"
+#include "apr_base64.h"
// static
diff --git a/indra/llcommon/llbase64.h b/indra/llcommon/llbase64.h
index c3d1a11f58..16d2c217d0 100644
--- a/indra/llcommon/llbase64.h
+++ b/indra/llcommon/llbase64.h
@@ -3,37 +3,32 @@
* @brief Wrapper for apr base64 encoding that returns a std::string
* @author James Cook
*
- * $LicenseInfo:firstyear=2007&license=viewergpl$
- *
- * Copyright (c) 2007, Linden Research, Inc.
- *
+ * $LicenseInfo:firstyear=2007&license=viewerlgpl$
* Second Life Viewer Source Code
- * The source code in this file ("Source Code") is provided by Linden Lab
- * to you under the terms of the GNU General Public License, version 2.0
- * ("GPL"), unless you have obtained a separate licensing agreement
- * ("Other License"), formally executed by you and Linden Lab. Terms of
- * the GPL can be found in doc/GPL-license.txt in this distribution, or
- * online at http://secondlife.com/developers/opensource/gplv2
+ * 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.
*
- * There are special exceptions to the terms and conditions of the GPL as
- * it is applied to this Source Code. View the full text of the exception
- * in the file doc/FLOSS-exception.txt in this software distribution, or
- * online at http://secondlife.com/developers/opensource/flossexception
+ * 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.
*
- * By copying, modifying or distributing this software, you acknowledge
- * that you have read and understood your obligations described above,
- * and agree to abide by those obligations.
+ * 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
*
- * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
- * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
- * COMPLETENESS OR PERFORMANCE.
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
* $/LicenseInfo$
*/
#ifndef LLBASE64_H
-#define LLBASE64_h
+#define LLBASE64_H
-class LLBase64
+class LL_COMMON_API LLBase64
{
public:
static std::string encode(const U8* input, size_t input_size);
diff --git a/indra/llcommon/llboost.h b/indra/llcommon/llboost.h
index 14cc97c568..57d958a51a 100644
--- a/indra/llcommon/llboost.h
+++ b/indra/llcommon/llboost.h
@@ -2,30 +2,25 @@
* @file llboost.h
* @brief helper object & functions for use with boost
*
- * $LicenseInfo:firstyear=2005&license=viewergpl$
- *
- * Copyright (c) 2005-2007, Linden Research, Inc.
- *
+ * $LicenseInfo:firstyear=2005&license=viewerlgpl$
* Second Life Viewer Source Code
- * The source code in this file ("Source Code") is provided by Linden Lab
- * to you under the terms of the GNU General Public License, version 2.0
- * ("GPL"), unless you have obtained a separate licensing agreement
- * ("Other License"), formally executed by you and Linden Lab. Terms of
- * the GPL can be found in doc/GPL-license.txt in this distribution, or
- * online at http://secondlife.com/developers/opensource/gplv2
+ * 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.
*
- * There are special exceptions to the terms and conditions of the GPL as
- * it is applied to this Source Code. View the full text of the exception
- * in the file doc/FLOSS-exception.txt in this software distribution, or
- * online at http://secondlife.com/developers/opensource/flossexception
+ * 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.
*
- * By copying, modifying or distributing this software, you acknowledge
- * that you have read and understood your obligations described above,
- * and agree to abide by those obligations.
+ * 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
*
- * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
- * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
- * COMPLETENESS OR PERFORMANCE.
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
* $/LicenseInfo$
*/
@@ -45,4 +40,19 @@
*/
typedef boost::tokenizer<boost::char_separator<char> > boost_tokenizer;
+// Useful combiner for boost signals that return a bool (e.g. validation)
+// returns false if any of the callbacks return false
+struct boost_boolean_combiner
+{
+ typedef bool result_type;
+ template<typename InputIterator>
+ bool operator()(InputIterator first, InputIterator last) const
+ {
+ bool res = true;
+ while (first != last)
+ res &= *first++;
+ return res;
+ }
+};
+
#endif // LL_LLBOOST_H
diff --git a/indra/llcommon/llchat.h b/indra/llcommon/llchat.h
index 0ae16380b4..87c2d6775b 100644
--- a/indra/llcommon/llchat.h
+++ b/indra/llcommon/llchat.h
@@ -3,37 +3,31 @@
* @author James Cook
* @brief Chat constants and data structures.
*
- * $LicenseInfo:firstyear=2006&license=viewergpl$
- *
- * Copyright (c) 2006-2007, Linden Research, Inc.
- *
+ * $LicenseInfo:firstyear=2006&license=viewerlgpl$
* Second Life Viewer Source Code
- * The source code in this file ("Source Code") is provided by Linden Lab
- * to you under the terms of the GNU General Public License, version 2.0
- * ("GPL"), unless you have obtained a separate licensing agreement
- * ("Other License"), formally executed by you and Linden Lab. Terms of
- * the GPL can be found in doc/GPL-license.txt in this distribution, or
- * online at http://secondlife.com/developers/opensource/gplv2
+ * 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.
*
- * There are special exceptions to the terms and conditions of the GPL as
- * it is applied to this Source Code. View the full text of the exception
- * in the file doc/FLOSS-exception.txt in this software distribution, or
- * online at http://secondlife.com/developers/opensource/flossexception
+ * 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.
*
- * By copying, modifying or distributing this software, you acknowledge
- * that you have read and understood your obligations described above,
- * and agree to abide by those obligations.
+ * 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
*
- * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
- * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
- * COMPLETENESS OR PERFORMANCE.
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
* $/LicenseInfo$
*/
#ifndef LL_LLCHAT_H
#define LL_LLCHAT_H
-#include "llstring.h"
#include "lluuid.h"
#include "v3math.h"
@@ -42,7 +36,8 @@ typedef enum e_chat_source_type
{
CHAT_SOURCE_SYSTEM = 0,
CHAT_SOURCE_AGENT = 1,
- CHAT_SOURCE_OBJECT = 2
+ CHAT_SOURCE_OBJECT = 2,
+ CHAT_SOURCE_UNKNOWN = 3
} EChatSourceType;
typedef enum e_chat_type
@@ -64,31 +59,50 @@ typedef enum e_chat_audible_level
CHAT_AUDIBLE_FULLY = 1
} EChatAudible;
+typedef enum e_chat_style
+{
+ CHAT_STYLE_NORMAL,
+ CHAT_STYLE_IRC,
+ CHAT_STYLE_HISTORY
+}EChatStyle;
+
// A piece of chat
class LLChat
{
public:
- LLChat(const LLString& text = LLString::null)
+ LLChat(const std::string& text = std::string())
: mText(text),
mFromName(),
mFromID(),
+ mNotifId(),
+ mOwnerID(),
mSourceType(CHAT_SOURCE_AGENT),
mChatType(CHAT_TYPE_NORMAL),
mAudible(CHAT_AUDIBLE_FULLY),
mMuted(FALSE),
mTime(0.0),
- mPosAgent()
+ mTimeStr(),
+ mPosAgent(),
+ mURL(),
+ mChatStyle(CHAT_STYLE_NORMAL),
+ mSessionID()
{ }
- LLString mText; // UTF-8 line of text
- LLString mFromName; // agent or object name
+ std::string mText; // UTF-8 line of text
+ std::string mFromName; // agent or object name
LLUUID mFromID; // agent id or object id
+ LLUUID mNotifId;
+ LLUUID mOwnerID;
EChatSourceType mSourceType;
EChatType mChatType;
EChatAudible mAudible;
BOOL mMuted; // pass muted chat to maintain list of chatters
F64 mTime; // viewer only, seconds from viewer start
+ std::string mTimeStr;
LLVector3 mPosAgent;
+ std::string mURL;
+ EChatStyle mChatStyle;
+ LLUUID mSessionID;
};
#endif
diff --git a/indra/llcommon/llclickaction.h b/indra/llcommon/llclickaction.h
index e2ba02465d..1f87d8eec3 100644
--- a/indra/llcommon/llclickaction.h
+++ b/indra/llcommon/llclickaction.h
@@ -3,36 +3,31 @@
* @author James Cook
* @brief Constants for single-click actions on objects
*
- * $LicenseInfo:firstyear=2006&license=viewergpl$
- *
- * Copyright (c) 2006-2007, Linden Research, Inc.
- *
+ * $LicenseInfo:firstyear=2006&license=viewerlgpl$
* Second Life Viewer Source Code
- * The source code in this file ("Source Code") is provided by Linden Lab
- * to you under the terms of the GNU General Public License, version 2.0
- * ("GPL"), unless you have obtained a separate licensing agreement
- * ("Other License"), formally executed by you and Linden Lab. Terms of
- * the GPL can be found in doc/GPL-license.txt in this distribution, or
- * online at http://secondlife.com/developers/opensource/gplv2
+ * 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.
*
- * There are special exceptions to the terms and conditions of the GPL as
- * it is applied to this Source Code. View the full text of the exception
- * in the file doc/FLOSS-exception.txt in this software distribution, or
- * online at http://secondlife.com/developers/opensource/flossexception
+ * 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.
*
- * By copying, modifying or distributing this software, you acknowledge
- * that you have read and understood your obligations described above,
- * and agree to abide by those obligations.
+ * 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
*
- * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
- * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
- * COMPLETENESS OR PERFORMANCE.
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
* $/LicenseInfo$
*/
#ifndef LL_LLCLICKACTION_H
#define LL_LLCLICKACTION_H
-
+// DO NOT CHANGE THE SEQUENCE OF THIS LIST!!
const U8 CLICK_ACTION_NONE = 0;
const U8 CLICK_ACTION_TOUCH = 0;
const U8 CLICK_ACTION_SIT = 1;
@@ -41,5 +36,6 @@ const U8 CLICK_ACTION_PAY = 3;
const U8 CLICK_ACTION_OPEN = 4;
const U8 CLICK_ACTION_PLAY = 5;
const U8 CLICK_ACTION_OPEN_MEDIA = 6;
-
+const U8 CLICK_ACTION_ZOOM = 7;
+// DO NOT CHANGE THE SEQUENCE OF THIS LIST!!
#endif
diff --git a/indra/llcommon/llcommon.cpp b/indra/llcommon/llcommon.cpp
index 0069d03de0..8be9e4f4de 100644
--- a/indra/llcommon/llcommon.cpp
+++ b/indra/llcommon/llcommon.cpp
@@ -1,36 +1,33 @@
/**
* @file llcommon.cpp
*
- * $LicenseInfo:firstyear=2006&license=viewergpl$
- *
- * Copyright (c) 2006-2007, Linden Research, Inc.
- *
+ * $LicenseInfo:firstyear=2006&license=viewerlgpl$
* Second Life Viewer Source Code
- * The source code in this file ("Source Code") is provided by Linden Lab
- * to you under the terms of the GNU General Public License, version 2.0
- * ("GPL"), unless you have obtained a separate licensing agreement
- * ("Other License"), formally executed by you and Linden Lab. Terms of
- * the GPL can be found in doc/GPL-license.txt in this distribution, or
- * online at http://secondlife.com/developers/opensource/gplv2
+ * Copyright (C) 2010, Linden Research, Inc.
*
- * There are special exceptions to the terms and conditions of the GPL as
- * it is applied to this Source Code. View the full text of the exception
- * in the file doc/FLOSS-exception.txt in this software distribution, or
- * online at http://secondlife.com/developers/opensource/flossexception
+ * 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.
*
- * By copying, modifying or distributing this software, you acknowledge
- * that you have read and understood your obligations described above,
- * and agree to abide by those obligations.
+ * 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.
*
- * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
- * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
- * COMPLETENESS OR PERFORMANCE.
+ * 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$
*/
#include "linden_common.h"
#include "llcommon.h"
+
+#include "llmemory.h"
#include "llthread.h"
//static
@@ -46,7 +43,7 @@ void LLCommon::initClass()
sAprInitialized = TRUE;
}
LLTimer::initClass();
- LLThreadSafeRefCount::initClass();
+ LLThreadSafeRefCount::initThreadSafeRefCount();
// LLWorkerThread::initClass();
// LLFrameCallbackManager::initClass();
}
@@ -56,7 +53,7 @@ void LLCommon::cleanupClass()
{
// LLFrameCallbackManager::cleanupClass();
// LLWorkerThread::cleanupClass();
- LLThreadSafeRefCount::cleanupClass();
+ LLThreadSafeRefCount::cleanupThreadSafeRefCount();
LLTimer::cleanupClass();
if (sAprInitialized)
{
diff --git a/indra/llcommon/llcommon.h b/indra/llcommon/llcommon.h
index 3f48763318..ca9cad5d05 100644
--- a/indra/llcommon/llcommon.h
+++ b/indra/llcommon/llcommon.h
@@ -1,43 +1,36 @@
/**
* @file llcommon.h
*
- * $LicenseInfo:firstyear=2006&license=viewergpl$
- *
- * Copyright (c) 2006-2007, Linden Research, Inc.
- *
+ * $LicenseInfo:firstyear=2006&license=viewerlgpl$
* Second Life Viewer Source Code
- * The source code in this file ("Source Code") is provided by Linden Lab
- * to you under the terms of the GNU General Public License, version 2.0
- * ("GPL"), unless you have obtained a separate licensing agreement
- * ("Other License"), formally executed by you and Linden Lab. Terms of
- * the GPL can be found in doc/GPL-license.txt in this distribution, or
- * online at http://secondlife.com/developers/opensource/gplv2
+ * 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.
*
- * There are special exceptions to the terms and conditions of the GPL as
- * it is applied to this Source Code. View the full text of the exception
- * in the file doc/FLOSS-exception.txt in this software distribution, or
- * online at http://secondlife.com/developers/opensource/flossexception
+ * 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.
*
- * By copying, modifying or distributing this software, you acknowledge
- * that you have read and understood your obligations described above,
- * and agree to abide by those obligations.
+ * 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
*
- * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
- * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
- * COMPLETENESS OR PERFORMANCE.
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
* $/LicenseInfo$
*/
#ifndef LL_COMMON_H
#define LL_COMMON_H
-#include "llmemory.h"
-#include "llapr.h"
-// #include "llframecallbackmanager.h"
+// *TODO: remove these?
#include "lltimer.h"
#include "llfile.h"
-class LLCommon
+class LL_COMMON_API LLCommon
{
public:
static void initClass();
diff --git a/indra/llcommon/llcommonutils.cpp b/indra/llcommon/llcommonutils.cpp
new file mode 100644
index 0000000000..d82554c202
--- /dev/null
+++ b/indra/llcommon/llcommonutils.cpp
@@ -0,0 +1,56 @@
+/**
+ * @file llcommonutils.h
+ * @brief Commin utils
+ *
+ * $LicenseInfo:firstyear=2010&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$
+ */
+
+#include "linden_common.h"
+#include "llcommonutils.h"
+
+void LLCommonUtils::computeDifference(
+ const uuid_vec_t& vnew,
+ const uuid_vec_t& vcur,
+ uuid_vec_t& vadded,
+ uuid_vec_t& vremoved)
+{
+ uuid_vec_t vnew_copy(vnew);
+ uuid_vec_t vcur_copy(vcur);
+
+ std::sort(vnew_copy.begin(), vnew_copy.end());
+ std::sort(vcur_copy.begin(), vcur_copy.end());
+
+ size_t maxsize = llmax(vnew_copy.size(), vcur_copy.size());
+ vadded.resize(maxsize);
+ vremoved.resize(maxsize);
+
+ uuid_vec_t::iterator it;
+ // what was removed
+ it = set_difference(vcur_copy.begin(), vcur_copy.end(), vnew_copy.begin(), vnew_copy.end(), vremoved.begin());
+ vremoved.erase(it, vremoved.end());
+
+ // what was added
+ it = set_difference(vnew_copy.begin(), vnew_copy.end(), vcur_copy.begin(), vcur_copy.end(), vadded.begin());
+ vadded.erase(it, vadded.end());
+}
+
+// EOF
diff --git a/indra/llcommon/llcommonutils.h b/indra/llcommon/llcommonutils.h
new file mode 100644
index 0000000000..755dc41fb4
--- /dev/null
+++ b/indra/llcommon/llcommonutils.h
@@ -0,0 +1,51 @@
+/**
+ * @file llcommonutils.h
+ * @brief Common utils
+ *
+ * $LicenseInfo:firstyear=2010&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$
+ */
+
+#ifndef LL_LLCOMMONUTILS_H
+#define LL_LLCOMMONUTILS_H
+
+namespace LLCommonUtils
+{
+ /**
+ * Computes difference between 'vnew' and 'vcur' vectors.
+ * Items present in 'vnew' and missing in 'vcur' are treated as added and are copied into 'vadded'
+ * Items missing in 'vnew' and present in 'vcur' are treated as removed and are copied into 'vremoved'
+ *
+ * @param vnew[in] - incoming IDs
+ * @param vcur[in] - current IDs
+ * @param vadded[out] - difference between incoming and current IDS - added IDs
+ * @param vremoved[out] - difference between incoming and current IDS - removed IDs
+ */
+ LL_COMMON_API void computeDifference(
+ const uuid_vec_t& vnew,
+ const uuid_vec_t& vcur,
+ uuid_vec_t& vadded,
+ uuid_vec_t& vremoved);
+};
+
+#endif //LL_LLCOMMONUTILS_H
+
+// EOF
diff --git a/indra/llcommon/llcoros.cpp b/indra/llcommon/llcoros.cpp
new file mode 100644
index 0000000000..0b5829eb7e
--- /dev/null
+++ b/indra/llcommon/llcoros.cpp
@@ -0,0 +1,154 @@
+/**
+ * @file llcoros.cpp
+ * @author Nat Goodspeed
+ * @date 2009-06-03
+ * @brief Implementation for llcoros.
+ *
+ * $LicenseInfo:firstyear=2009&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$
+ */
+
+// Precompiled header
+#include "linden_common.h"
+// associated header
+#include "llcoros.h"
+// STL headers
+// std headers
+// external library headers
+#include <boost/bind.hpp>
+// other Linden headers
+#include "llevents.h"
+#include "llerror.h"
+#include "stringize.h"
+
+LLCoros::LLCoros()
+{
+ // Register our cleanup() method for "mainloop" ticks
+ LLEventPumps::instance().obtain("mainloop").listen(
+ "LLCoros", boost::bind(&LLCoros::cleanup, this, _1));
+}
+
+bool LLCoros::cleanup(const LLSD&)
+{
+ // Walk the mCoros map, checking and removing completed coroutines.
+ for (CoroMap::iterator mi(mCoros.begin()), mend(mCoros.end()); mi != mend; )
+ {
+ // Has this coroutine exited (normal return, exception, exit() call)
+ // since last tick?
+ if (mi->second->exited())
+ {
+ LL_INFOS("LLCoros") << "LLCoros: cleaning up coroutine " << mi->first << LL_ENDL;
+ // The erase() call will invalidate its passed iterator value --
+ // so increment mi FIRST -- but pass its original value to
+ // erase(). This is what postincrement is all about.
+ mCoros.erase(mi++);
+ }
+ else
+ {
+ // Still live, just skip this entry as if incrementing at the top
+ // of the loop as usual.
+ ++mi;
+ }
+ }
+ return false;
+}
+
+std::string LLCoros::generateDistinctName(const std::string& prefix) const
+{
+ // Allowing empty name would make getName()'s not-found return ambiguous.
+ if (prefix.empty())
+ {
+ LL_ERRS("LLCoros") << "LLCoros::launch(): pass non-empty name string" << LL_ENDL;
+ }
+
+ // If the specified name isn't already in the map, just use that.
+ std::string name(prefix);
+
+ // Find the lowest numeric suffix that doesn't collide with an existing
+ // entry. Start with 2 just to make it more intuitive for any interested
+ // parties: e.g. "joe", "joe2", "joe3"...
+ for (int i = 2; ; name = STRINGIZE(prefix << i++))
+ {
+ if (mCoros.find(name) == mCoros.end())
+ {
+ LL_INFOS("LLCoros") << "LLCoros: launching coroutine " << name << LL_ENDL;
+ return name;
+ }
+ }
+}
+
+bool LLCoros::kill(const std::string& name)
+{
+ CoroMap::iterator found = mCoros.find(name);
+ if (found == mCoros.end())
+ {
+ return false;
+ }
+ // Because this is a boost::ptr_map, erasing the map entry also destroys
+ // the referenced heap object, in this case the boost::coroutine object,
+ // which will terminate the coroutine.
+ mCoros.erase(found);
+ return true;
+}
+
+std::string LLCoros::getNameByID(const void* self_id) const
+{
+ // Walk the existing coroutines, looking for one from which the 'self_id'
+ // passed to us comes.
+ for (CoroMap::const_iterator mi(mCoros.begin()), mend(mCoros.end()); mi != mend; ++mi)
+ {
+ namespace coro_private = boost::coroutines::detail;
+ if (static_cast<void*>(coro_private::coroutine_accessor::get_impl(const_cast<coro&>(*mi->second)).get())
+ == self_id)
+ {
+ return mi->first;
+ }
+ }
+ return "";
+}
+
+/*****************************************************************************
+* MUST BE LAST
+*****************************************************************************/
+// Turn off MSVC optimizations for just LLCoros::launchImpl() -- see
+// DEV-32777. But MSVC doesn't support push/pop for optimization flags as it
+// does for warning suppression, and we really don't want to force
+// optimization ON for other code even in Debug or RelWithDebInfo builds.
+
+#if LL_MSVC
+// work around broken optimizations
+#pragma warning(disable: 4748)
+#pragma optimize("", off)
+#endif // LL_MSVC
+
+std::string LLCoros::launchImpl(const std::string& prefix, coro* newCoro)
+{
+ std::string name(generateDistinctName(prefix));
+ mCoros.insert(name, newCoro);
+ /* Run the coroutine until its first wait, then return here */
+ (*newCoro)(std::nothrow);
+ return name;
+}
+
+#if LL_MSVC
+// reenable optimizations
+#pragma optimize("", on)
+#endif // LL_MSVC
diff --git a/indra/llcommon/llcoros.h b/indra/llcommon/llcoros.h
new file mode 100644
index 0000000000..d75f28ec1a
--- /dev/null
+++ b/indra/llcommon/llcoros.h
@@ -0,0 +1,166 @@
+/**
+ * @file llcoros.h
+ * @author Nat Goodspeed
+ * @date 2009-06-02
+ * @brief Manage running boost::coroutine instances
+ *
+ * $LicenseInfo:firstyear=2009&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_LLCOROS_H)
+#define LL_LLCOROS_H
+
+#include <boost/coroutine/coroutine.hpp>
+#include "llsingleton.h"
+#include <boost/ptr_container/ptr_map.hpp>
+#include <string>
+#include <boost/preprocessor/repetition/enum_params.hpp>
+#include <boost/preprocessor/repetition/enum_binary_params.hpp>
+#include <boost/preprocessor/iteration/local.hpp>
+#include <stdexcept>
+
+/**
+ * Registry of named Boost.Coroutine instances
+ *
+ * The Boost.Coroutine library supports the general case of a coroutine
+ * accepting arbitrary parameters and yielding multiple (sets of) results. For
+ * such use cases, it's natural for the invoking code to retain the coroutine
+ * instance: the consumer repeatedly calls into the coroutine, perhaps passing
+ * new parameter values, prompting it to yield its next result.
+ *
+ * Our typical coroutine usage is different, though. For us, coroutines
+ * provide an alternative to the @c Responder pattern. Our typical coroutine
+ * has @c void return, invoked in fire-and-forget mode: the handler for some
+ * user gesture launches the coroutine and promptly returns to the main loop.
+ * The coroutine initiates some action that will take multiple frames (e.g. a
+ * capability request), waits for its result, processes it and silently steals
+ * away.
+ *
+ * This usage poses two (related) problems:
+ *
+ * # Who should own the coroutine instance? If it's simply local to the
+ * handler code that launches it, return from the handler will destroy the
+ * coroutine object, terminating the coroutine.
+ * # Once the coroutine terminates, in whatever way, who's responsible for
+ * cleaning up the coroutine object?
+ *
+ * LLCoros is a Singleton collection of currently-active coroutine instances.
+ * Each has a name. You ask LLCoros to launch a new coroutine with a suggested
+ * name prefix; from your prefix it generates a distinct name, registers the
+ * new coroutine and returns the actual name.
+ *
+ * The name can be used to kill off the coroutine prematurely, if needed. It
+ * can also provide diagnostic info: we can look up the name of the
+ * currently-running coroutine.
+ *
+ * Finally, the next frame ("mainloop" event) after the coroutine terminates,
+ * LLCoros will notice its demise and destroy it.
+ */
+class LL_COMMON_API LLCoros: public LLSingleton<LLCoros>
+{
+public:
+ /// Canonical boost::coroutines::coroutine signature we use
+ typedef boost::coroutines::coroutine<void()> coro;
+ /// Canonical 'self' type
+ typedef coro::self self;
+
+ /**
+ * Create and start running a new coroutine with specified name. The name
+ * string you pass is a suggestion; it will be tweaked for uniqueness. The
+ * actual name is returned to you.
+ *
+ * Usage looks like this, for (e.g.) two coroutine parameters:
+ * @code
+ * class MyClass
+ * {
+ * public:
+ * ...
+ * // Do NOT NOT NOT accept reference params other than 'self'!
+ * // Pass by value only!
+ * void myCoroutineMethod(LLCoros::self& self, std::string, LLSD);
+ * ...
+ * };
+ * ...
+ * std::string name = LLCoros::instance().launch(
+ * "mycoro", boost::bind(&MyClass::myCoroutineMethod, this, _1,
+ * "somestring", LLSD(17));
+ * @endcode
+ *
+ * Your function/method must accept LLCoros::self& as its first parameter.
+ * It can accept any other parameters you want -- but ONLY BY VALUE!
+ * Other reference parameters are a BAD IDEA! You Have Been Warned. See
+ * DEV-32777 comments for an explanation.
+ *
+ * Pass a callable that accepts the single LLCoros::self& parameter. It
+ * may work to pass a free function whose only parameter is 'self'; for
+ * all other cases use boost::bind(). Of course, for a non-static class
+ * method, the first parameter must be the class instance. Use the
+ * placeholder _1 for the 'self' parameter. Any other parameters should be
+ * passed via the bind() expression.
+ *
+ * launch() tweaks the suggested name so it won't collide with any
+ * existing coroutine instance, creates the coroutine instance, registers
+ * it with the tweaked name and runs it until its first wait. At that
+ * point it returns the tweaked name.
+ */
+ template <typename CALLABLE>
+ std::string launch(const std::string& prefix, const CALLABLE& callable)
+ {
+ return launchImpl(prefix, new coro(callable));
+ }
+
+ /**
+ * Abort a running coroutine by name. Normally, when a coroutine either
+ * runs to completion or terminates with an exception, LLCoros quietly
+ * cleans it up. This is for use only when you must explicitly interrupt
+ * one prematurely. Returns @c true if the specified name was found and
+ * still running at the time.
+ */
+ bool kill(const std::string& name);
+
+ /**
+ * From within a coroutine, pass its @c self object to look up the
+ * (tweaked) name string by which this coroutine is registered. Returns
+ * the empty string if not found (e.g. if the coroutine was launched by
+ * hand rather than using LLCoros::launch()).
+ */
+ template <typename COROUTINE_SELF>
+ std::string getName(const COROUTINE_SELF& self) const
+ {
+ return getNameByID(self.get_id());
+ }
+
+ /// getName() by self.get_id()
+ std::string getNameByID(const void* self_id) const;
+
+private:
+ friend class LLSingleton<LLCoros>;
+ LLCoros();
+ std::string launchImpl(const std::string& prefix, coro* newCoro);
+ std::string generateDistinctName(const std::string& prefix) const;
+ bool cleanup(const LLSD&);
+
+ typedef boost::ptr_map<std::string, coro> CoroMap;
+ CoroMap mCoros;
+};
+
+#endif /* ! defined(LL_LLCOROS_H) */
diff --git a/indra/llcommon/llcrc.cpp b/indra/llcommon/llcrc.cpp
new file mode 100644
index 0000000000..e80da0bb0d
--- /dev/null
+++ b/indra/llcommon/llcrc.cpp
@@ -0,0 +1,223 @@
+/**
+ * @file llcrc.cpp
+ * @brief implementation of the crc class.
+ *
+ * $LicenseInfo:firstyear=2002&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$
+ */
+
+#include "linden_common.h"
+
+#include "llcrc.h"
+#include "llerror.h"
+
+/* Copyright (C) 1986 Gary S. Brown. You may use this program, or
+ code or tables extracted from it, as desired without restriction.*/
+
+/* First, the polynomial itself and its table of feedback terms. The */
+/* polynomial is */
+/* X^32+X^26+X^23+X^22+X^16+X^12+X^11+X^10+X^8+X^7+X^5+X^4+X^2+X^1+X^0 */
+/* Note that we take it "backwards" and put the highest-order term in */
+/* the lowest-order bit. The X^32 term is "implied"; the LSB is the */
+/* X^31 term, etc. The X^0 term (usually shown as "+1") results in */
+/* the MSB being 1. */
+
+/* Note that the usual hardware shift register implementation, which */
+/* is what we're using (we're merely optimizing it by doing eight-bit */
+/* chunks at a time) shifts bits into the lowest-order term. In our */
+/* implementation, that means shifting towards the right. Why do we */
+/* do it this way? Because the calculated CRC must be transmitted in */
+/* order from highest-order term to lowest-order term. UARTs transmit */
+/* characters in order from LSB to MSB. By storing the CRC this way, */
+/* we hand it to the UART in the order low-byte to high-byte; the UART */
+/* sends each low-bit to hight-bit; and the result is transmission bit */
+/* by bit from highest- to lowest-order term without requiring any bit */
+/* shuffling on our part. Reception works similarly. */
+
+/* The feedback terms table consists of 256, 32-bit entries. Notes: */
+/* */
+/* 1. The table can be generated at runtime if desired; code to do so */
+/* is shown later. It might not be obvious, but the feedback */
+/* terms simply represent the results of eight shift/xor opera- */
+/* tions for all combinations of data and CRC register values. */
+/* */
+/* 2. The CRC accumulation logic is the same for all CRC polynomials, */
+/* be they sixteen or thirty-two bits wide. You simply choose the */
+/* appropriate table. Alternatively, because the table can be */
+/* generated at runtime, you can start by generating the table for */
+/* the polynomial in question and use exactly the same "updcrc", */
+/* if your application needn't simultaneously handle two CRC */
+/* polynomials. (Note, however, that XMODEM is strange.) */
+/* */
+/* 3. For 16-bit CRCs, the table entries need be only 16 bits wide; */
+/* of course, 32-bit entries work OK if the high 16 bits are zero. */
+/* */
+/* 4. The values must be right-shifted by eight bits by the "updcrc" */
+/* logic; the shift must be unsigned (bring in zeroes). On some */
+/* hardware you could probably optimize the shift in assembler by */
+/* using byte-swap instructions. */
+
+///----------------------------------------------------------------------------
+/// Local function declarations, constants, enums, and typedefs
+///----------------------------------------------------------------------------
+
+#define UPDC32(octet,crc) (crc_32_tab[((crc) \
+ ^ ((U8)octet)) & 0xff] ^ ((crc) >> 8))
+
+
+static U32 crc_32_tab[] = { /* CRC polynomial 0xedb88320 */
+0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f,
+0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,
+0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2,
+0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
+0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9,
+0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172,
+0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c,
+0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
+0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423,
+0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
+0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, 0x01db7106,
+0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
+0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d,
+0x91646c97, 0xe6635c01, 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e,
+0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950,
+0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
+0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7,
+0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0,
+0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa,
+0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
+0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81,
+0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a,
+0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 0xe3630b12, 0x94643b84,
+0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
+0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb,
+0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc,
+0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8, 0xa1d1937e,
+0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
+0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55,
+0x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
+0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28,
+0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
+0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f,
+0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38,
+0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242,
+0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
+0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69,
+0x616bffd3, 0x166ccf45, 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2,
+0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc,
+0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
+0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693,
+0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,
+0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d
+};
+
+
+///----------------------------------------------------------------------------
+/// Class llcrc
+///----------------------------------------------------------------------------
+
+// Default constructor
+LLCRC::LLCRC() : mCurrent(0xffffffff)
+{
+}
+
+
+U32 LLCRC::getCRC() const
+{
+ return ~mCurrent;
+}
+
+void LLCRC::update(U8 next_byte)
+{
+ mCurrent = UPDC32(next_byte, mCurrent);
+}
+
+void LLCRC::update(const U8* buffer, size_t buffer_size)
+{
+ for (size_t i = 0; i < buffer_size; i++)
+ {
+ mCurrent = UPDC32(buffer[i], mCurrent);
+ }
+}
+
+void LLCRC::update(const std::string& filename)
+{
+ if (filename.empty())
+ {
+ llerrs << "No filename specified" << llendl;
+ return;
+ }
+
+ FILE* fp = LLFile::fopen(filename, "rb"); /* Flawfinder: ignore */
+
+ if (fp)
+ {
+ fseek(fp, 0, SEEK_END);
+ long size = ftell(fp);
+
+ fseek(fp, 0, SEEK_SET);
+
+ if (size > 0)
+ {
+ U8* data = new U8[size];
+ size_t nread;
+
+ nread = fread(data, 1, size, fp);
+ fclose(fp);
+
+ if (nread < (size_t) size)
+ {
+ llwarns << "Short read on " << filename << llendl;
+ }
+
+ update(data, nread);
+ delete[] data;
+ }
+ else
+ {
+ fclose(fp);
+ }
+ }
+}
+
+
+#ifdef _DEBUG
+BOOL LLCRC::testHarness()
+{
+ const S32 TEST_BUFFER_SIZE = 16;
+ const char TEST_BUFFER[TEST_BUFFER_SIZE] = "hello &#$)$&Nd0"; /* Flawfinder: ignore */
+ LLCRC c1, c2;
+ c1.update((U8*)TEST_BUFFER, TEST_BUFFER_SIZE - 1);
+ char* rh = (char*)TEST_BUFFER;
+ while(*rh != '\0')
+ {
+ c2.update(*rh);
+ ++rh;
+ }
+ return(c1.getCRC() == c2.getCRC());
+}
+#endif
+
+
+
+///----------------------------------------------------------------------------
+/// Local function definitions
+///----------------------------------------------------------------------------
diff --git a/indra/llcommon/llcrc.h b/indra/llcommon/llcrc.h
new file mode 100644
index 0000000000..2d291d92a1
--- /dev/null
+++ b/indra/llcommon/llcrc.h
@@ -0,0 +1,68 @@
+/**
+ * @file llcrc.h
+ * @brief LLCRC class header file.
+ *
+ * $LicenseInfo:firstyear=2002&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$
+ */
+
+#ifndef LL_LLCRC_H
+#define LL_LLCRC_H
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// Class llcrc
+//
+// Simple 32 bit crc. To use, instantiate an LLCRC instance and feed
+// it the bytes you want to check. It will update the internal crc as
+// you go, and you can qery it at the end. As a horribly inefficient
+// example (don't try this at work kids):
+//
+// LLCRC crc;
+// FILE* fp = LLFile::fopen(filename,"rb");
+// while(!feof(fp)) {
+// crc.update(fgetc(fp));
+// }
+// fclose(fp);
+// llinfos << "File crc: " << crc.getCRC() << llendl;
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+class LL_COMMON_API LLCRC
+{
+protected:
+ U32 mCurrent;
+
+public:
+ LLCRC();
+
+ U32 getCRC() const;
+ void update(U8 next_byte);
+ void update(const U8* buffer, size_t buffer_size);
+ void update(const std::string& filename);
+
+#ifdef _DEBUG
+ // This function runs tests to make sure the crc is
+ // working. Returns TRUE if it is.
+ static BOOL testHarness();
+#endif
+};
+
+
+#endif // LL_LLCRC_H
diff --git a/indra/llcommon/llcriticaldamp.cpp b/indra/llcommon/llcriticaldamp.cpp
index 9522573dd0..87d79b1ee0 100644
--- a/indra/llcommon/llcriticaldamp.cpp
+++ b/indra/llcommon/llcriticaldamp.cpp
@@ -2,30 +2,25 @@
* @file llcriticaldamp.cpp
* @brief Implementation of the critical damping functionality.
*
- * $LicenseInfo:firstyear=2002&license=viewergpl$
- *
- * Copyright (c) 2002-2007, Linden Research, Inc.
- *
+ * $LicenseInfo:firstyear=2002&license=viewerlgpl$
* Second Life Viewer Source Code
- * The source code in this file ("Source Code") is provided by Linden Lab
- * to you under the terms of the GNU General Public License, version 2.0
- * ("GPL"), unless you have obtained a separate licensing agreement
- * ("Other License"), formally executed by you and Linden Lab. Terms of
- * the GPL can be found in doc/GPL-license.txt in this distribution, or
- * online at http://secondlife.com/developers/opensource/gplv2
+ * 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.
*
- * There are special exceptions to the terms and conditions of the GPL as
- * it is applied to this Source Code. View the full text of the exception
- * in the file doc/FLOSS-exception.txt in this software distribution, or
- * online at http://secondlife.com/developers/opensource/flossexception
+ * 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.
*
- * By copying, modifying or distributing this software, you acknowledge
- * that you have read and understood your obligations described above,
- * and agree to abide by those obligations.
+ * 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
*
- * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
- * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
- * COMPLETENESS OR PERFORMANCE.
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
* $/LicenseInfo$
*/
diff --git a/indra/llcommon/llcriticaldamp.h b/indra/llcommon/llcriticaldamp.h
index e0b3df98ee..52f052ae25 100644
--- a/indra/llcommon/llcriticaldamp.h
+++ b/indra/llcommon/llcriticaldamp.h
@@ -3,30 +3,25 @@
* @brief A lightweight class that calculates critical damping constants once
* per frame.
*
- * $LicenseInfo:firstyear=2002&license=viewergpl$
- *
- * Copyright (c) 2002-2007, Linden Research, Inc.
- *
+ * $LicenseInfo:firstyear=2002&license=viewerlgpl$
* Second Life Viewer Source Code
- * The source code in this file ("Source Code") is provided by Linden Lab
- * to you under the terms of the GNU General Public License, version 2.0
- * ("GPL"), unless you have obtained a separate licensing agreement
- * ("Other License"), formally executed by you and Linden Lab. Terms of
- * the GPL can be found in doc/GPL-license.txt in this distribution, or
- * online at http://secondlife.com/developers/opensource/gplv2
+ * 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.
*
- * There are special exceptions to the terms and conditions of the GPL as
- * it is applied to this Source Code. View the full text of the exception
- * in the file doc/FLOSS-exception.txt in this software distribution, or
- * online at http://secondlife.com/developers/opensource/flossexception
+ * 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.
*
- * By copying, modifying or distributing this software, you acknowledge
- * that you have read and understood your obligations described above,
- * and agree to abide by those obligations.
+ * 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
*
- * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
- * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
- * COMPLETENESS OR PERFORMANCE.
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
* $/LicenseInfo$
*/
@@ -37,7 +32,7 @@
#include "llframetimer.h"
-class LLCriticalDamp
+class LL_COMMON_API LLCriticalDamp
{
public:
LLCriticalDamp();
diff --git a/indra/llcommon/llcursortypes.cpp b/indra/llcommon/llcursortypes.cpp
new file mode 100644
index 0000000000..e987c397bd
--- /dev/null
+++ b/indra/llcommon/llcursortypes.cpp
@@ -0,0 +1,85 @@
+/**
+ * @file llcursortypes.cpp
+ * @brief Cursor types and lookup of types from a string
+ *
+ * $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$
+ */
+
+#include "linden_common.h"
+
+#include "llcursortypes.h"
+
+ECursorType getCursorFromString(const std::string& cursor_string)
+{
+ static std::map<std::string,U32> cursor_string_table;
+ if (cursor_string_table.empty())
+ {
+ cursor_string_table["UI_CURSOR_ARROW"] = UI_CURSOR_ARROW;
+ cursor_string_table["UI_CURSOR_WAIT"] = UI_CURSOR_WAIT;
+ cursor_string_table["UI_CURSOR_HAND"] = UI_CURSOR_HAND;
+ cursor_string_table["UI_CURSOR_IBEAM"] = UI_CURSOR_IBEAM;
+ cursor_string_table["UI_CURSOR_CROSS"] = UI_CURSOR_CROSS;
+ cursor_string_table["UI_CURSOR_SIZENWSE"] = UI_CURSOR_SIZENWSE;
+ cursor_string_table["UI_CURSOR_SIZENESW"] = UI_CURSOR_SIZENESW;
+ cursor_string_table["UI_CURSOR_SIZEWE"] = UI_CURSOR_SIZEWE;
+ cursor_string_table["UI_CURSOR_SIZENS"] = UI_CURSOR_SIZENS;
+ cursor_string_table["UI_CURSOR_NO"] = UI_CURSOR_NO;
+ cursor_string_table["UI_CURSOR_WORKING"] = UI_CURSOR_WORKING;
+ cursor_string_table["UI_CURSOR_TOOLGRAB"] = UI_CURSOR_TOOLGRAB;
+ cursor_string_table["UI_CURSOR_TOOLLAND"] = UI_CURSOR_TOOLLAND;
+ cursor_string_table["UI_CURSOR_TOOLFOCUS"] = UI_CURSOR_TOOLFOCUS;
+ cursor_string_table["UI_CURSOR_TOOLCREATE"] = UI_CURSOR_TOOLCREATE;
+ cursor_string_table["UI_CURSOR_ARROWDRAG"] = UI_CURSOR_ARROWDRAG;
+ cursor_string_table["UI_CURSOR_ARROWCOPY"] = UI_CURSOR_ARROWCOPY;
+ cursor_string_table["UI_CURSOR_ARROWDRAGMULTI"] = UI_CURSOR_ARROWDRAGMULTI;
+ cursor_string_table["UI_CURSOR_ARROWCOPYMULTI"] = UI_CURSOR_ARROWCOPYMULTI;
+ cursor_string_table["UI_CURSOR_NOLOCKED"] = UI_CURSOR_NOLOCKED;
+ cursor_string_table["UI_CURSOR_ARROWLOCKED"] = UI_CURSOR_ARROWLOCKED;
+ cursor_string_table["UI_CURSOR_GRABLOCKED"] = UI_CURSOR_GRABLOCKED;
+ cursor_string_table["UI_CURSOR_TOOLTRANSLATE"] = UI_CURSOR_TOOLTRANSLATE;
+ cursor_string_table["UI_CURSOR_TOOLROTATE"] = UI_CURSOR_TOOLROTATE;
+ cursor_string_table["UI_CURSOR_TOOLSCALE"] = UI_CURSOR_TOOLSCALE;
+ cursor_string_table["UI_CURSOR_TOOLCAMERA"] = UI_CURSOR_TOOLCAMERA;
+ cursor_string_table["UI_CURSOR_TOOLPAN"] = UI_CURSOR_TOOLPAN;
+ cursor_string_table["UI_CURSOR_TOOLZOOMIN"] = UI_CURSOR_TOOLZOOMIN;
+ cursor_string_table["UI_CURSOR_TOOLPICKOBJECT3"] = UI_CURSOR_TOOLPICKOBJECT3;
+ cursor_string_table["UI_CURSOR_TOOLPLAY"] = UI_CURSOR_TOOLPLAY;
+ cursor_string_table["UI_CURSOR_TOOLPAUSE"] = UI_CURSOR_TOOLPAUSE;
+ cursor_string_table["UI_CURSOR_TOOLMEDIAOPEN"] = UI_CURSOR_TOOLMEDIAOPEN;
+ cursor_string_table["UI_CURSOR_PIPETTE"] = UI_CURSOR_PIPETTE;
+ cursor_string_table["UI_CURSOR_TOOLSIT"] = UI_CURSOR_TOOLSIT;
+ cursor_string_table["UI_CURSOR_TOOLBUY"] = UI_CURSOR_TOOLBUY;
+ cursor_string_table["UI_CURSOR_TOOLOPEN"] = UI_CURSOR_TOOLOPEN;
+ }
+
+ std::map<std::string,U32>::const_iterator iter = cursor_string_table.find(cursor_string);
+
+ if (iter != cursor_string_table.end())
+ {
+ return (ECursorType)iter->second;
+ }
+
+ return UI_CURSOR_ARROW;
+}
+
+
+
diff --git a/indra/llcommon/llcursortypes.h b/indra/llcommon/llcursortypes.h
new file mode 100644
index 0000000000..bacb0a80ba
--- /dev/null
+++ b/indra/llcommon/llcursortypes.h
@@ -0,0 +1,73 @@
+/**
+ * @file llcursortypes.h
+ * @brief Cursor types
+ *
+ * $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$
+ */
+
+#ifndef LL_LLCURSORTYPES_H
+#define LL_LLCURSORTYPES_H
+
+// If you add types here, add them in LLCursor::getCursorFromString
+enum ECursorType {
+ UI_CURSOR_ARROW,
+ UI_CURSOR_WAIT,
+ UI_CURSOR_HAND,
+ UI_CURSOR_IBEAM,
+ UI_CURSOR_CROSS,
+ UI_CURSOR_SIZENWSE,
+ UI_CURSOR_SIZENESW,
+ UI_CURSOR_SIZEWE,
+ UI_CURSOR_SIZENS,
+ UI_CURSOR_NO,
+ UI_CURSOR_WORKING,
+ UI_CURSOR_TOOLGRAB,
+ UI_CURSOR_TOOLLAND,
+ UI_CURSOR_TOOLFOCUS,
+ UI_CURSOR_TOOLCREATE,
+ UI_CURSOR_ARROWDRAG,
+ UI_CURSOR_ARROWCOPY, // drag with copy
+ UI_CURSOR_ARROWDRAGMULTI,
+ UI_CURSOR_ARROWCOPYMULTI, // drag with copy
+ UI_CURSOR_NOLOCKED,
+ UI_CURSOR_ARROWLOCKED,
+ UI_CURSOR_GRABLOCKED,
+ UI_CURSOR_TOOLTRANSLATE,
+ UI_CURSOR_TOOLROTATE,
+ UI_CURSOR_TOOLSCALE,
+ UI_CURSOR_TOOLCAMERA,
+ UI_CURSOR_TOOLPAN,
+ UI_CURSOR_TOOLZOOMIN,
+ UI_CURSOR_TOOLPICKOBJECT3,
+ UI_CURSOR_TOOLPLAY,
+ UI_CURSOR_TOOLPAUSE,
+ UI_CURSOR_TOOLMEDIAOPEN,
+ UI_CURSOR_PIPETTE,
+ UI_CURSOR_TOOLSIT,
+ UI_CURSOR_TOOLBUY,
+ UI_CURSOR_TOOLOPEN,
+ UI_CURSOR_COUNT // Number of elements in this enum (NOT a cursor)
+};
+
+LL_COMMON_API ECursorType getCursorFromString(const std::string& cursor_string);
+
+#endif // LL_LLCURSORTYPES_H
diff --git a/indra/llcommon/lldarray.h b/indra/llcommon/lldarray.h
index 3b46706d42..a8cd03b42a 100644
--- a/indra/llcommon/lldarray.h
+++ b/indra/llcommon/lldarray.h
@@ -2,37 +2,31 @@
* @file lldarray.h
* @brief Wrapped std::vector for backward compatibility.
*
- * $LicenseInfo:firstyear=2001&license=viewergpl$
- *
- * Copyright (c) 2001-2007, Linden Research, Inc.
- *
+ * $LicenseInfo:firstyear=2001&license=viewerlgpl$
* Second Life Viewer Source Code
- * The source code in this file ("Source Code") is provided by Linden Lab
- * to you under the terms of the GNU General Public License, version 2.0
- * ("GPL"), unless you have obtained a separate licensing agreement
- * ("Other License"), formally executed by you and Linden Lab. Terms of
- * the GPL can be found in doc/GPL-license.txt in this distribution, or
- * online at http://secondlife.com/developers/opensource/gplv2
+ * Copyright (C) 2010, Linden Research, Inc.
*
- * There are special exceptions to the terms and conditions of the GPL as
- * it is applied to this Source Code. View the full text of the exception
- * in the file doc/FLOSS-exception.txt in this software distribution, or
- * online at http://secondlife.com/developers/opensource/flossexception
+ * 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.
*
- * By copying, modifying or distributing this software, you acknowledge
- * that you have read and understood your obligations described above,
- * and agree to abide by those obligations.
+ * 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.
*
- * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
- * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
- * COMPLETENESS OR PERFORMANCE.
+ * 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$
*/
#ifndef LL_LLDARRAY_H
#define LL_LLDARRAY_H
-#include "llmath.h"
#include "llerror.h"
#include <vector>
@@ -119,11 +113,12 @@ inline S32 LLDynamicArray<Type,BlockSize>::removeObj(const Type& obj)
typename std::vector<Type>::iterator iter = std::find(this->begin(), this->end(), obj);
if (iter != this->end())
{
+ S32 res = iter - this->begin();
typename std::vector<Type>::iterator last = this->end();
--last;
*iter = *last;
this->pop_back();
- return iter - this->begin();
+ return res;
}
return FAIL;
}
@@ -201,7 +196,7 @@ public:
{
U32 n = mVector.size();
mIndexMap[k] = n;
- mVector.resize(n+1);
+ mVector.push_back(Type());
llassert(mVector.size() == mIndexMap.size());
return mVector[n];
}
diff --git a/indra/llcommon/lldarrayptr.h b/indra/llcommon/lldarrayptr.h
index d04bffe8a1..c9a0b204d1 100644
--- a/indra/llcommon/lldarrayptr.h
+++ b/indra/llcommon/lldarrayptr.h
@@ -2,30 +2,25 @@
* @file lldarrayptr.h
* @brief Wrapped std::vector for backward compatibility.
*
- * $LicenseInfo:firstyear=2001&license=viewergpl$
- *
- * Copyright (c) 2001-2007, Linden Research, Inc.
- *
+ * $LicenseInfo:firstyear=2001&license=viewerlgpl$
* Second Life Viewer Source Code
- * The source code in this file ("Source Code") is provided by Linden Lab
- * to you under the terms of the GNU General Public License, version 2.0
- * ("GPL"), unless you have obtained a separate licensing agreement
- * ("Other License"), formally executed by you and Linden Lab. Terms of
- * the GPL can be found in doc/GPL-license.txt in this distribution, or
- * online at http://secondlife.com/developers/opensource/gplv2
+ * 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.
*
- * There are special exceptions to the terms and conditions of the GPL as
- * it is applied to this Source Code. View the full text of the exception
- * in the file doc/FLOSS-exception.txt in this software distribution, or
- * online at http://secondlife.com/developers/opensource/flossexception
+ * 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.
*
- * By copying, modifying or distributing this software, you acknowledge
- * that you have read and understood your obligations described above,
- * and agree to abide by those obligations.
+ * 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
*
- * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
- * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
- * COMPLETENESS OR PERFORMANCE.
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
* $/LicenseInfo$
*/
#ifndef LL_LLDARRAYPTR_H
diff --git a/indra/llcommon/lldate.cpp b/indra/llcommon/lldate.cpp
index 37b912df3d..030ef6a3c7 100644
--- a/indra/llcommon/lldate.cpp
+++ b/indra/llcommon/lldate.cpp
@@ -4,41 +4,42 @@
* @date 2006-02-05
* @brief Implementation of the date class
*
- * $LicenseInfo:firstyear=2006&license=viewergpl$
- *
- * Copyright (c) 2006-2007, Linden Research, Inc.
- *
+ * $LicenseInfo:firstyear=2006&license=viewerlgpl$
* Second Life Viewer Source Code
- * The source code in this file ("Source Code") is provided by Linden Lab
- * to you under the terms of the GNU General Public License, version 2.0
- * ("GPL"), unless you have obtained a separate licensing agreement
- * ("Other License"), formally executed by you and Linden Lab. Terms of
- * the GPL can be found in doc/GPL-license.txt in this distribution, or
- * online at http://secondlife.com/developers/opensource/gplv2
+ * 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.
*
- * There are special exceptions to the terms and conditions of the GPL as
- * it is applied to this Source Code. View the full text of the exception
- * in the file doc/FLOSS-exception.txt in this software distribution, or
- * online at http://secondlife.com/developers/opensource/flossexception
+ * 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.
*
- * By copying, modifying or distributing this software, you acknowledge
- * that you have read and understood your obligations described above,
- * and agree to abide by those obligations.
+ * 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
*
- * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
- * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
- * COMPLETENESS OR PERFORMANCE.
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
* $/LicenseInfo$
*/
#include "linden_common.h"
#include "lldate.h"
-#include "apr-1/apr_time.h"
+#include "apr_time.h"
+#include <time.h>
+#include <locale.h>
+#include <string>
#include <iomanip>
#include <sstream>
+#include "lltimer.h"
+#include "llstring.h"
+
static const F64 DATE_EPOCH = 0.0;
static const F64 LL_APR_USEC_PER_SEC = 1000000.0;
@@ -84,45 +85,42 @@ std::string LLDate::asString() const
// is one of the standards used and the prefered format
std::string LLDate::asRFC1123() const
{
- std::ostringstream stream;
- toHTTPDateStream(stream);
- return stream.str();
+ return toHTTPDateString (std::string ("%A, %d %b %Y %H:%M:%S GMT"));
}
-void LLDate::toHTTPDateStream(std::ostream& s) const
-{
- // http://apr.apache.org/docs/apr/0.9/group__apr__time.html
- apr_time_t time = (apr_time_t)(mSecondsSinceEpoch * LL_APR_USEC_PER_SEC);
+LLFastTimer::DeclareTimer FT_DATE_FORMAT("Date Format");
- apr_time_exp_t exp_time ; //Apache time module
+std::string LLDate::toHTTPDateString (std::string fmt) const
+{
+ LLFastTimer ft1(FT_DATE_FORMAT);
+
+ time_t locSeconds = (time_t) mSecondsSinceEpoch;
+ struct tm * gmt = gmtime (&locSeconds);
+ return toHTTPDateString(gmt, fmt);
+}
- if (apr_time_exp_gmt(&exp_time, time) != APR_SUCCESS)
- {
- // Return Epoch UTC date
- s << "Thursday, 01 Jan 1970 00:00:00 GMT" ;
- return;
- }
+std::string LLDate::toHTTPDateString (tm * gmt, std::string fmt)
+{
+ LLFastTimer ft1(FT_DATE_FORMAT);
- s << std::dec << std::setfill('0');
-#if( LL_WINDOWS || __GNUC__ > 2)
- s << std::right ;
-#else
- s.setf(ios::right);
-#endif
- std::string day = weekdays[exp_time.tm_wday];
- std::string month = months[exp_time.tm_mon];
-
- s << std::setw(day.length()) << (day)
- << ", " << std::setw(2) << (exp_time.tm_mday)
- << ' ' << std::setw(month.length()) << (month)
- << ' ' << std::setw(4) << (exp_time.tm_year + 1900)
- << ' ' << std::setw(2) << (exp_time.tm_hour)
- << ':' << std::setw(2) << (exp_time.tm_min)
- << ':' << std::setw(2) << (exp_time.tm_sec)
- << " GMT";
+ // avoid calling setlocale() unnecessarily - it's expensive.
+ static std::string prev_locale = "";
+ std::string this_locale = LLStringUtil::getLocale();
+ if (this_locale != prev_locale)
+ {
+ setlocale(LC_TIME, this_locale.c_str());
+ prev_locale = this_locale;
+ }
- // RFC 1123 date does not use microseconds
- llinfos << "Date in RFC 1123 format is " << s << llendl;
+ // use strftime() as it appears to be faster than std::time_put
+ char buffer[128];
+ strftime(buffer, 128, fmt.c_str(), gmt);
+ std::string res(buffer);
+#if LL_WINDOWS
+ // Convert from locale-dependant charset to UTF-8 (EXT-8524).
+ res = ll_convert_string_to_utf8_string(res);
+#endif
+ return res;
}
void LLDate::toStream(std::ostream& s) const
@@ -153,7 +151,39 @@ void LLDate::toStream(std::ostream& s) const
s << '.' << std::setw(2)
<< (int)(exp_time.tm_usec / (LL_APR_USEC_PER_SEC / 100));
}
- s << 'Z';
+ s << 'Z'
+ << std::setfill(' ');
+}
+
+bool LLDate::split(S32 *year, S32 *month, S32 *day, S32 *hour, S32 *min, S32 *sec) const
+{
+ apr_time_t time = (apr_time_t)(mSecondsSinceEpoch * LL_APR_USEC_PER_SEC);
+
+ apr_time_exp_t exp_time;
+ if (apr_time_exp_gmt(&exp_time, time) != APR_SUCCESS)
+ {
+ return false;
+ }
+
+ if (year)
+ *year = exp_time.tm_year + 1900;
+
+ if (month)
+ *month = exp_time.tm_mon + 1;
+
+ if (day)
+ *day = exp_time.tm_mday;
+
+ if (hour)
+ *hour = exp_time.tm_hour;
+
+ if (min)
+ *min = exp_time.tm_min;
+
+ if (sec)
+ *sec = exp_time.tm_sec;
+
+ return true;
}
bool LLDate::fromString(const std::string& iso8601_date)
@@ -217,13 +247,62 @@ bool LLDate::fromStream(std::istream& s)
s >> fractional;
seconds_since_epoch += fractional;
}
- c = s.get(); // skip the Z
- if (c != 'Z') { return false; }
+
+ c = s.peek(); // check for offset
+ if (c == '+' || c == '-')
+ {
+ S32 offset_sign = (c == '+') ? 1 : -1;
+ S32 offset_hours = 0;
+ S32 offset_minutes = 0;
+ S32 offset_in_seconds = 0;
+
+ s >> offset_hours;
+
+ c = s.get(); // skip the colon a get the minutes if there are any
+ if (c == ':')
+ {
+ s >> offset_minutes;
+ }
+
+ offset_in_seconds = (offset_hours * 60 + offset_sign * offset_minutes) * 60;
+ seconds_since_epoch -= offset_in_seconds;
+ }
+ else if (c != 'Z') { return false; } // skip the Z
mSecondsSinceEpoch = seconds_since_epoch;
return true;
}
+bool LLDate::fromYMDHMS(S32 year, S32 month, S32 day, S32 hour, S32 min, S32 sec)
+{
+ struct apr_time_exp_t exp_time;
+
+ exp_time.tm_year = year - 1900;
+ exp_time.tm_mon = month - 1;
+ exp_time.tm_mday = day;
+ exp_time.tm_hour = hour;
+ exp_time.tm_min = min;
+ exp_time.tm_sec = sec;
+
+ // zero out the unused fields
+ exp_time.tm_usec = 0;
+ exp_time.tm_wday = 0;
+ exp_time.tm_yday = 0;
+ exp_time.tm_isdst = 0;
+ exp_time.tm_gmtoff = 0;
+
+ // generate a time_t from that
+ apr_time_t time;
+ if (apr_time_exp_gmt_get(&time, &exp_time) != APR_SUCCESS)
+ {
+ return false;
+ }
+
+ mSecondsSinceEpoch = time / LL_APR_USEC_PER_SEC;
+
+ return true;
+}
+
F64 LLDate::secondsSinceEpoch() const
{
return mSecondsSinceEpoch;
@@ -234,6 +313,17 @@ void LLDate::secondsSinceEpoch(F64 seconds)
mSecondsSinceEpoch = seconds;
}
+/* static */ LLDate LLDate::now()
+{
+ // time() returns seconds, we want fractions of a second, which LLTimer provides --RN
+ return LLDate(LLTimer::getTotalSeconds());
+}
+
+bool LLDate::operator<(const LLDate& rhs) const
+{
+ return mSecondsSinceEpoch < rhs.mSecondsSinceEpoch;
+}
+
std::ostream& operator<<(std::ostream& s, const LLDate& date)
{
date.toStream(s);
@@ -245,3 +335,4 @@ std::istream& operator>>(std::istream& s, LLDate& date)
date.fromStream(s);
return s;
}
+
diff --git a/indra/llcommon/lldate.h b/indra/llcommon/lldate.h
index 7bff18d927..7ff8b550ad 100644
--- a/indra/llcommon/lldate.h
+++ b/indra/llcommon/lldate.h
@@ -4,30 +4,25 @@
* @date 2006-02-05
* @brief Declaration of a simple date class.
*
- * $LicenseInfo:firstyear=2006&license=viewergpl$
- *
- * Copyright (c) 2006-2007, Linden Research, Inc.
- *
+ * $LicenseInfo:firstyear=2006&license=viewerlgpl$
* Second Life Viewer Source Code
- * The source code in this file ("Source Code") is provided by Linden Lab
- * to you under the terms of the GNU General Public License, version 2.0
- * ("GPL"), unless you have obtained a separate licensing agreement
- * ("Other License"), formally executed by you and Linden Lab. Terms of
- * the GPL can be found in doc/GPL-license.txt in this distribution, or
- * online at http://secondlife.com/developers/opensource/gplv2
+ * 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.
*
- * There are special exceptions to the terms and conditions of the GPL as
- * it is applied to this Source Code. View the full text of the exception
- * in the file doc/FLOSS-exception.txt in this software distribution, or
- * online at http://secondlife.com/developers/opensource/flossexception
+ * 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.
*
- * By copying, modifying or distributing this software, you acknowledge
- * that you have read and understood your obligations described above,
- * and agree to abide by those obligations.
+ * 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
*
- * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
- * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
- * COMPLETENESS OR PERFORMANCE.
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
* $/LicenseInfo$
*/
@@ -35,6 +30,7 @@
#define LL_LLDATE_H
#include <iosfwd>
+#include <string>
#include "stdtypes.h"
@@ -44,7 +40,7 @@
*
* The date class represents a point in time after epoch - 1970-01-01.
*/
-class LLDate
+class LL_COMMON_API LLDate
{
public:
/**
@@ -53,7 +49,7 @@ public:
LLDate();
/**
- * @brief Construct a date equal to epoch.
+ * @brief Construct a date equal to the source date.
*/
LLDate(const LLDate& date);
@@ -82,7 +78,9 @@ public:
std::string asString() const;
std::string asRFC1123() const;
void toStream(std::ostream&) const;
- void toHTTPDateStream(std::ostream&) const;
+ bool split(S32 *year, S32 *month = NULL, S32 *day = NULL, S32 *hour = NULL, S32 *min = NULL, S32 *sec = NULL) const;
+ std::string toHTTPDateString (std::string fmt) const;
+ static std::string toHTTPDateString (tm * gmt, std::string fmt);
/**
* @brief Set the date from an ISO-8601 string.
*
@@ -97,6 +95,7 @@ public:
*/
bool fromString(const std::string& iso8601_date);
bool fromStream(std::istream&);
+ bool fromYMDHMS(S32 year, S32 month = 1, S32 day = 0, S32 hour = 0, S32 min = 0, S32 sec = 0);
/**
* @brief Return the date in seconds since epoch.
@@ -111,21 +110,51 @@ public:
* @param seconds The number of seconds since epoch UTC.
*/
void secondsSinceEpoch(F64 seconds);
+
+ /**
+ * @brief Create an LLDate object set to the current time.
+ *
+ * @return The number of seconds since epoch UTC.
+ */
+ static LLDate now();
+
+ /**
+ * @brief Compare dates using operator< so we can order them using STL.
+ *
+ * @param rhs -- the right hand side of the comparison operator
+ */
+ bool operator<(const LLDate& rhs) const;
+
+ /**
+ * @brief Remaining comparison operators in terms of operator<
+ * This conforms to the expectation of STL.
+ *
+ * @param rhs -- the right hand side of the comparison operator
+ */
+ bool operator>(const LLDate& rhs) const { return rhs < *this; }
+ bool operator<=(const LLDate& rhs) const { return !(rhs < *this); }
+ bool operator>=(const LLDate& rhs) const { return !(*this < rhs); }
+ bool operator!=(const LLDate& rhs) const { return (*this < rhs) || (rhs < *this); }
+ bool operator==(const LLDate& rhs) const { return !(*this != rhs); }
+
+ /**
+ * @brief Compare to epoch UTC.
+ */
+
+ bool isNull() const { return mSecondsSinceEpoch == 0.0; }
+ bool notNull() const { return mSecondsSinceEpoch != 0.0; }
+
private:
F64 mSecondsSinceEpoch;
};
-
// Helper function to stream out a date
-std::ostream& operator<<(std::ostream& s, const LLDate& date);
+LL_COMMON_API std::ostream& operator<<(std::ostream& s, const LLDate& date);
// Helper function to stream in a date
-std::istream& operator>>(std::istream& s, LLDate& date);
-
+LL_COMMON_API std::istream& operator>>(std::istream& s, LLDate& date);
-const static std::string weekdays[] = {"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"};
-const static std::string months[] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};
#endif // LL_LLDATE_H
diff --git a/indra/llcommon/lldefs.h b/indra/llcommon/lldefs.h
index 96b2ab169b..6b38de6500 100644
--- a/indra/llcommon/lldefs.h
+++ b/indra/llcommon/lldefs.h
@@ -2,30 +2,25 @@
* @file lldefs.h
* @brief Various generic constant definitions.
*
- * $LicenseInfo:firstyear=2001&license=viewergpl$
- *
- * Copyright (c) 2001-2007, Linden Research, Inc.
- *
+ * $LicenseInfo:firstyear=2001&license=viewerlgpl$
* Second Life Viewer Source Code
- * The source code in this file ("Source Code") is provided by Linden Lab
- * to you under the terms of the GNU General Public License, version 2.0
- * ("GPL"), unless you have obtained a separate licensing agreement
- * ("Other License"), formally executed by you and Linden Lab. Terms of
- * the GPL can be found in doc/GPL-license.txt in this distribution, or
- * online at http://secondlife.com/developers/opensource/gplv2
+ * Copyright (C) 2010, Linden Research, Inc.
*
- * There are special exceptions to the terms and conditions of the GPL as
- * it is applied to this Source Code. View the full text of the exception
- * in the file doc/FLOSS-exception.txt in this software distribution, or
- * online at http://secondlife.com/developers/opensource/flossexception
+ * 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.
*
- * By copying, modifying or distributing this software, you acknowledge
- * that you have read and understood your obligations described above,
- * and agree to abide by those obligations.
+ * 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.
*
- * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
- * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
- * COMPLETENESS OR PERFORMANCE.
+ * 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$
*/
@@ -218,7 +213,15 @@ inline LLDATATYPE llmin(const LLDATATYPE& d1, const LLDATATYPE& d2, const LLDATA
template <class LLDATATYPE>
inline LLDATATYPE llclamp(const LLDATATYPE& a, const LLDATATYPE& minval, const LLDATATYPE& maxval)
{
- return llmin(llmax(a, minval), maxval);
+ if ( a < minval )
+ {
+ return minval;
+ }
+ else if ( a > maxval )
+ {
+ return maxval;
+ }
+ return a;
}
template <class LLDATATYPE>
@@ -234,3 +237,4 @@ inline LLDATATYPE llclampb(const LLDATATYPE& a)
}
#endif // LL_LLDEFS_H
+
diff --git a/indra/llcommon/lldeleteutils.h b/indra/llcommon/lldeleteutils.h
new file mode 100644
index 0000000000..f250dc3028
--- /dev/null
+++ b/indra/llcommon/lldeleteutils.h
@@ -0,0 +1,47 @@
+/**
+ * @file lldeleteutils.h
+ * @brief Utility functions to simplify some common pointer-munging idioms.
+ *
+ * $LicenseInfo:firstyear=2009&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$
+ */
+#ifndef LL_DELETE_UTILS_H
+#define LL_DELETE_UTILS_H
+
+// Simple utility functions to eventually replace the common 2-line
+// idiom scattered throughout the viewer codebase. Note that where
+// possible we would rather be using smart pointers of some sort.
+
+template <class T>
+inline void deleteAndClear(T*& ptr)
+{
+ delete ptr;
+ ptr = NULL;
+}
+
+template <class T>
+inline void deleteAndClearArray(T*& array_ptr)
+{
+ delete[] array_ptr;
+ array_ptr = NULL;
+}
+
+#endif
diff --git a/indra/llcommon/lldependencies.cpp b/indra/llcommon/lldependencies.cpp
new file mode 100644
index 0000000000..0e72c175cb
--- /dev/null
+++ b/indra/llcommon/lldependencies.cpp
@@ -0,0 +1,103 @@
+/**
+ * @file lldependencies.cpp
+ * @author Nat Goodspeed
+ * @date 2008-09-17
+ * @brief Implementation for lldependencies.
+ *
+ * $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$
+ */
+
+// Precompiled header
+#include "linden_common.h"
+// associated header
+#include "lldependencies.h"
+// STL headers
+#include <map>
+#include <sstream>
+// std headers
+// external library headers
+#include <boost/graph/graph_traits.hpp> // for boost::graph_traits
+#include <boost/graph/adjacency_list.hpp>
+#include <boost/graph/topological_sort.hpp>
+#include <boost/graph/exception.hpp>
+// other Linden headers
+
+LLDependenciesBase::VertexList LLDependenciesBase::topo_sort(int vertices, const EdgeList& edges) const
+{
+ // Construct a Boost Graph Library graph according to the constraints
+ // we've collected. It seems as though we ought to be able to capture
+ // the uniqueness of vertex keys using a setS of vertices with a
+ // string property -- but I don't yet understand adjacency_list well
+ // enough to get there. All the examples I've seen so far use integers
+ // for vertices.
+ // Define the Graph type. Use a vector for vertices so we can use the
+ // default topological_sort vertex lookup by int index. Use a set for
+ // edges because the same dependency may be stated twice: Node "a" may
+ // specify that it must precede "b", while "b" may also state that it
+ // must follow "a".
+ typedef boost::adjacency_list<boost::setS, boost::vecS, boost::directedS,
+ boost::no_property> Graph;
+ // Instantiate the graph. Without vertex properties, we need say no
+ // more about vertices than the total number.
+ Graph g(edges.begin(), edges.end(), vertices);
+ // topo sort
+ typedef boost::graph_traits<Graph>::vertex_descriptor VertexDesc;
+ typedef std::vector<VertexDesc> SortedList;
+ SortedList sorted;
+ // note that it throws not_a_dag if it finds a cycle
+ try
+ {
+ boost::topological_sort(g, std::back_inserter(sorted));
+ }
+ catch (const boost::not_a_dag& e)
+ {
+ // translate to the exception we define
+ std::ostringstream out;
+ out << "LLDependencies cycle: " << e.what() << '\n';
+ // Omit independent nodes: display only those that might contribute to
+ // the cycle.
+ describe(out, false);
+ throw Cycle(out.str());
+ }
+ // A peculiarity of boost::topological_sort() is that it emits results in
+ // REVERSE topological order: to get the result you want, you must
+ // traverse the SortedList using reverse iterators.
+ return VertexList(sorted.rbegin(), sorted.rend());
+}
+
+std::ostream& LLDependenciesBase::describe(std::ostream& out, bool full) const
+{
+ // Should never encounter this base-class implementation; may mean that
+ // the KEY type doesn't have a suitable ostream operator<<().
+ out << "<no description available>";
+ return out;
+}
+
+std::string LLDependenciesBase::describe(bool full) const
+{
+ // Just use the ostream-based describe() on a std::ostringstream. The
+ // implementation is here mostly so that we can avoid #include <sstream>
+ // in the header file.
+ std::ostringstream out;
+ describe(out, full);
+ return out.str();
+}
diff --git a/indra/llcommon/lldependencies.h b/indra/llcommon/lldependencies.h
new file mode 100644
index 0000000000..e0294e271b
--- /dev/null
+++ b/indra/llcommon/lldependencies.h
@@ -0,0 +1,799 @@
+/**
+ * @file lldependencies.h
+ * @author Nat Goodspeed
+ * @date 2008-09-17
+ * @brief LLDependencies: a generic mechanism for expressing "b must follow a,
+ * but precede c"
+ *
+ * $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_LLDEPENDENCIES_H)
+#define LL_LLDEPENDENCIES_H
+
+#include <string>
+#include <vector>
+#include <set>
+#include <map>
+#include <stdexcept>
+#include <iosfwd>
+#include <boost/iterator/transform_iterator.hpp>
+#include <boost/iterator/indirect_iterator.hpp>
+#include <boost/range/iterator_range.hpp>
+#include <boost/function.hpp>
+#include <boost/bind.hpp>
+
+/*****************************************************************************
+* Utilities
+*****************************************************************************/
+/**
+ * generic range transformer: given a range acceptable to Boost.Range (e.g. a
+ * standard container, an iterator pair, ...) and a unary function to apply to
+ * each element of the range, make a corresponding range that lazily applies
+ * that function to each element on dereferencing.
+ */
+template<typename FUNCTION, typename RANGE>
+inline
+boost::iterator_range<boost::transform_iterator<FUNCTION,
+ typename boost::range_const_iterator<RANGE>::type> >
+make_transform_range(const RANGE& range, FUNCTION function)
+{
+ // shorthand for the iterator type embedded in our return type
+ typedef boost::transform_iterator<FUNCTION, typename boost::range_const_iterator<RANGE>::type>
+ transform_iterator;
+ return boost::make_iterator_range(transform_iterator(boost::begin(range), function),
+ transform_iterator(boost::end(range), function));
+}
+
+/// non-const version of make_transform_range()
+template<typename FUNCTION, typename RANGE>
+inline
+boost::iterator_range<boost::transform_iterator<FUNCTION,
+ typename boost::range_iterator<RANGE>::type> >
+make_transform_range(RANGE& range, FUNCTION function)
+{
+ // shorthand for the iterator type embedded in our return type
+ typedef boost::transform_iterator<FUNCTION, typename boost::range_iterator<RANGE>::type>
+ transform_iterator;
+ return boost::make_iterator_range(transform_iterator(boost::begin(range), function),
+ transform_iterator(boost::end(range), function));
+}
+
+/**
+ * From any range compatible with Boost.Range, instantiate any class capable
+ * of accepting an iterator pair.
+ */
+template<class TYPE>
+struct instance_from_range: public TYPE
+{
+ template<typename RANGE>
+ instance_from_range(RANGE range):
+ TYPE(boost::begin(range), boost::end(range))
+ {}
+};
+
+/*****************************************************************************
+* LLDependencies
+*****************************************************************************/
+/**
+ * LLDependencies components that should not be reinstantiated for each KEY,
+ * NODE specialization
+ */
+class LL_COMMON_API LLDependenciesBase
+{
+public:
+ virtual ~LLDependenciesBase() {}
+
+ /**
+ * Exception thrown by sort() if there's a cycle
+ */
+ struct Cycle: public std::runtime_error
+ {
+ Cycle(const std::string& what): std::runtime_error(what) {}
+ };
+
+ /**
+ * Provide a short description of this LLDependencies instance on the
+ * specified output stream, assuming that its KEY type has an operator<<()
+ * that works with std::ostream.
+ *
+ * Pass @a full as @c false to omit any keys without dependency constraints.
+ */
+ virtual std::ostream& describe(std::ostream& out, bool full=true) const;
+
+ /// describe() to a string
+ virtual std::string describe(bool full=true) const;
+
+protected:
+ typedef std::vector< std::pair<int, int> > EdgeList;
+ typedef std::vector<int> VertexList;
+ VertexList topo_sort(int vertices, const EdgeList& edges) const;
+
+ /**
+ * refpair is specifically intended to capture a pair of references. This
+ * is better than std::pair<T1&, T2&> because some implementations of
+ * std::pair's ctor accept const references to the two types. If the
+ * types are themselves references, this results in an illegal reference-
+ * to-reference.
+ */
+ template<typename T1, typename T2>
+ struct refpair
+ {
+ refpair(T1 value1, T2 value2):
+ first(value1),
+ second(value2)
+ {}
+ T1 first;
+ T2 second;
+ };
+};
+
+/// describe() helper: for most types, report the type as usual
+template<typename T>
+inline
+std::ostream& LLDependencies_describe(std::ostream& out, const T& key)
+{
+ out << key;
+ return out;
+}
+
+/// specialize LLDependencies_describe() for std::string
+template<>
+inline
+std::ostream& LLDependencies_describe(std::ostream& out, const std::string& key)
+{
+ out << '"' << key << '"';
+ return out;
+}
+
+/**
+ * It's reasonable to use LLDependencies in a keys-only way, more or less like
+ * std::set. For that case, the default NODE type is an empty struct.
+ */
+struct LLDependenciesEmpty
+{
+ LLDependenciesEmpty() {}
+ /**
+ * Give it a constructor accepting void* so caller can pass placeholder
+ * values such as NULL or 0 rather than having to write
+ * LLDependenciesEmpty().
+ */
+ LLDependenciesEmpty(void*) {}
+};
+
+/**
+ * This class manages abstract dependencies between node types of your
+ * choosing. As with a std::map, nodes are copied when add()ed, so the node
+ * type should be relatively lightweight; to manipulate dependencies between
+ * expensive objects, use a pointer type.
+ *
+ * For a given node, you may state the keys of nodes that must precede it
+ * and/or nodes that must follow it. The sort() method will produce an order
+ * that should work, or throw an exception if the constraints are impossible.
+ * We cache results to minimize the cost of repeated sort() calls.
+ */
+template<typename KEY = std::string,
+ typename NODE = LLDependenciesEmpty>
+class LLDependencies: public LLDependenciesBase
+{
+ typedef LLDependencies<KEY, NODE> self_type;
+
+ /**
+ * Internally, we bundle the client's NODE with its before/after keys.
+ */
+ struct DepNode
+ {
+ typedef std::set<KEY> dep_set;
+ DepNode(const NODE& node_, const dep_set& after_, const dep_set& before_):
+ node(node_),
+ after(after_),
+ before(before_)
+ {}
+ NODE node;
+ dep_set after, before;
+ };
+ typedef std::map<KEY, DepNode> DepNodeMap;
+ typedef typename DepNodeMap::value_type DepNodeMapEntry;
+
+ /// We have various ways to get the dependencies for a given DepNode.
+ /// Rather than having to restate each one for 'after' and 'before'
+ /// separately, pass a dep_selector so we can apply each to either.
+ typedef boost::function<const typename DepNode::dep_set&(const DepNode&)> dep_selector;
+
+public:
+ LLDependencies() {}
+
+ typedef KEY key_type;
+ typedef NODE node_type;
+
+ /// param type used to express lists of other node keys -- note that such
+ /// lists can be initialized with boost::assign::list_of()
+ typedef std::vector<KEY> KeyList;
+
+ /**
+ * Add a new node. State its dependencies on other nodes (which may not
+ * yet have been added) by listing the keys of nodes this new one must
+ * follow, and separately the keys of nodes this new one must precede.
+ *
+ * The node you pass is @em copied into an internal data structure. If you
+ * want to modify the node value after add()ing it, capture the returned
+ * NODE& reference.
+ *
+ * @note
+ * Actual dependency analysis is deferred to the sort() method, so
+ * you can add an arbitrary number of nodes without incurring analysis
+ * overhead for each. The flip side of this is that add()ing nodes that
+ * define a cycle leaves this object in a state in which sort() will
+ * always throw the Cycle exception.
+ *
+ * Two distinct use cases are anticipated:
+ * * The data used to load this object are completely known at compile
+ * time (e.g. LLEventPump listener names). A Cycle exception represents a
+ * bug which can be corrected by the coder. The program need neither catch
+ * Cycle nor attempt to salvage the state of this object.
+ * * The data are loaded at runtime, therefore the universe of
+ * dependencies cannot be known at compile time. The client code should
+ * catch Cycle.
+ * ** If a Cycle exception indicates fatally-flawed input data, this
+ * object can simply be discarded, possibly with the entire program run.
+ * ** If it is essential to restore this object to a working state, the
+ * simplest workaround is to remove() nodes in LIFO order.
+ * *** It may be useful to add functionality to this class to track the
+ * add() chronology, providing a pop() method to remove the most recently
+ * added node.
+ * *** It may further be useful to add a restore() method which would
+ * pop() until sort() no longer throws Cycle. This method would be
+ * expensive -- but it's not clear that client code could resolve the
+ * problem more cheaply.
+ */
+ NODE& add(const KEY& key, const NODE& node = NODE(),
+ const KeyList& after = KeyList(),
+ const KeyList& before = KeyList())
+ {
+ // Get the passed-in lists as sets for equality comparison
+ typename DepNode::dep_set
+ after_set(after.begin(), after.end()),
+ before_set(before.begin(), before.end());
+ // Try to insert the new node; if it already exists, find the old
+ // node instead.
+ std::pair<typename DepNodeMap::iterator, bool> inserted =
+ mNodes.insert(typename DepNodeMap::value_type(key,
+ DepNode(node, after_set, before_set)));
+ if (! inserted.second) // bool indicating success of insert()
+ {
+ // We already have a node by this name. Have its dependencies
+ // changed? If the existing node's dependencies are identical, the
+ // result will be unchanged, so we can leave the cache intact.
+ // Regardless of inserted.second, inserted.first is the iterator
+ // to the newly-inserted (or existing) map entry. Of course, that
+ // entry's second is the DepNode of interest.
+ if (inserted.first->second.after != after_set ||
+ inserted.first->second.before != before_set)
+ {
+ // Dependencies have changed: clear the cached result.
+ mCache.clear();
+ // save the new dependencies
+ inserted.first->second.after = after_set;
+ inserted.first->second.before = before_set;
+ }
+ }
+ else // this node is new
+ {
+ // This will change results.
+ mCache.clear();
+ }
+ return inserted.first->second.node;
+ }
+
+ /// the value of an iterator, showing both KEY and its NODE
+ typedef refpair<const KEY&, NODE&> value_type;
+ /// the value of a const_iterator
+ typedef refpair<const KEY&, const NODE&> const_value_type;
+
+private:
+ // Extract functors
+ static value_type value_extract(DepNodeMapEntry& entry)
+ {
+ return value_type(entry.first, entry.second.node);
+ }
+
+ static const_value_type const_value_extract(const DepNodeMapEntry& entry)
+ {
+ return const_value_type(entry.first, entry.second.node);
+ }
+
+ // All the iterator access methods return iterator ranges just to cut down
+ // on the friggin' boilerplate!!
+
+ /// generic mNodes range method
+ template<typename ITERATOR, typename FUNCTION>
+ boost::iterator_range<ITERATOR> generic_range(FUNCTION function)
+ {
+ return make_transform_range(mNodes, function);
+ }
+
+ /// generic mNodes const range method
+ template<typename ITERATOR, typename FUNCTION>
+ boost::iterator_range<ITERATOR> generic_range(FUNCTION function) const
+ {
+ return make_transform_range(mNodes, function);
+ }
+
+public:
+ /// iterator over value_type entries
+ typedef boost::transform_iterator<boost::function<value_type(DepNodeMapEntry&)>,
+ typename DepNodeMap::iterator> iterator;
+ /// range over value_type entries
+ typedef boost::iterator_range<iterator> range;
+
+ /// iterate over value_type <i>in @c KEY order</i> rather than dependency order
+ range get_range()
+ {
+ return generic_range<iterator>(value_extract);
+ }
+
+ /// iterator over const_value_type entries
+ typedef boost::transform_iterator<boost::function<const_value_type(const DepNodeMapEntry&)>,
+ typename DepNodeMap::const_iterator> const_iterator;
+ /// range over const_value_type entries
+ typedef boost::iterator_range<const_iterator> const_range;
+
+ /// iterate over const_value_type <i>in @c KEY order</i> rather than dependency order
+ const_range get_range() const
+ {
+ return generic_range<const_iterator>(const_value_extract);
+ }
+
+ /// iterator over stored NODEs
+ typedef boost::transform_iterator<boost::function<NODE&(DepNodeMapEntry&)>,
+ typename DepNodeMap::iterator> node_iterator;
+ /// range over stored NODEs
+ typedef boost::iterator_range<node_iterator> node_range;
+
+ /// iterate over NODE <i>in @c KEY order</i> rather than dependency order
+ node_range get_node_range()
+ {
+ // First take a DepNodeMapEntry and extract a reference to its
+ // DepNode, then from that extract a reference to its NODE.
+ return generic_range<node_iterator>(
+ boost::bind<NODE&>(&DepNode::node,
+ boost::bind<DepNode&>(&DepNodeMapEntry::second, _1)));
+ }
+
+ /// const iterator over stored NODEs
+ typedef boost::transform_iterator<boost::function<const NODE&(const DepNodeMapEntry&)>,
+ typename DepNodeMap::const_iterator> const_node_iterator;
+ /// const range over stored NODEs
+ typedef boost::iterator_range<const_node_iterator> const_node_range;
+
+ /// iterate over const NODE <i>in @c KEY order</i> rather than dependency order
+ const_node_range get_node_range() const
+ {
+ // First take a DepNodeMapEntry and extract a reference to its
+ // DepNode, then from that extract a reference to its NODE.
+ return generic_range<const_node_iterator>(
+ boost::bind<const NODE&>(&DepNode::node,
+ boost::bind<const DepNode&>(&DepNodeMapEntry::second, _1)));
+ }
+
+ /// const iterator over stored KEYs
+ typedef boost::transform_iterator<boost::function<const KEY&(const DepNodeMapEntry&)>,
+ typename DepNodeMap::const_iterator> const_key_iterator;
+ /// const range over stored KEYs
+ typedef boost::iterator_range<const_key_iterator> const_key_range;
+ // We don't provide a non-const iterator over KEYs because they should be
+ // immutable, and in fact our underlying std::map won't give us non-const
+ // references.
+
+ /// iterate over const KEY <i>in @c KEY order</i> rather than dependency order
+ const_key_range get_key_range() const
+ {
+ // From a DepNodeMapEntry, extract a reference to its KEY.
+ return generic_range<const_key_iterator>(
+ boost::bind<const KEY&>(&DepNodeMapEntry::first, _1));
+ }
+
+ /**
+ * Find an existing NODE, or return NULL. We decided to avoid providing a
+ * method analogous to std::map::find(), for a couple of reasons:
+ *
+ * * For a find-by-key, getting back an iterator to the (key, value) pair
+ * is less than useful, since you already have the key in hand.
+ * * For a failed request, comparing to end() is problematic. First, we
+ * provide range accessors, so it's more code to get end(). Second, we
+ * provide a number of different ranges -- quick, to which one's end()
+ * should we compare the iterator returned by find()?
+ *
+ * The returned pointer is solely to allow expressing the not-found
+ * condition. LLDependencies still owns the found NODE.
+ */
+ const NODE* get(const KEY& key) const
+ {
+ typename DepNodeMap::const_iterator found = mNodes.find(key);
+ if (found != mNodes.end())
+ {
+ return &found->second.node;
+ }
+ return NULL;
+ }
+
+ /**
+ * non-const get()
+ */
+ NODE* get(const KEY& key)
+ {
+ // Use const implementation, then cast away const-ness of return
+ return const_cast<NODE*>(const_cast<const self_type*>(this)->get(key));
+ }
+
+ /**
+ * Remove a node with specified key. This operation is the major reason
+ * we rebuild the graph on the fly instead of storing it.
+ */
+ bool remove(const KEY& key)
+ {
+ typename DepNodeMap::iterator found = mNodes.find(key);
+ if (found != mNodes.end())
+ {
+ mNodes.erase(found);
+ return true;
+ }
+ return false;
+ }
+
+private:
+ /// cached list of iterators
+ typedef std::vector<iterator> iterator_list;
+ typedef typename iterator_list::iterator iterator_list_iterator;
+
+public:
+ /**
+ * The return type of the sort() method needs some explanation. Provide a
+ * public typedef to facilitate storing the result.
+ *
+ * * We will prepare mCache by looking up DepNodeMap iterators.
+ * * We want to return a range containing iterators that will walk mCache.
+ * * If we simply stored DepNodeMap iterators and returned
+ * (mCache.begin(), mCache.end()), dereferencing each iterator would
+ * obtain a DepNodeMap iterator.
+ * * We want the caller to loop over @c value_type: pair<KEY, NODE>.
+ * * This requires two transformations:
+ * ** mCache must contain @c LLDependencies::iterator so that
+ * dereferencing each entry will obtain an @c LLDependencies::value_type
+ * rather than a DepNodeMapEntry.
+ * ** We must wrap mCache's iterators in boost::indirect_iterator so that
+ * dereferencing one of our returned iterators will also dereference the
+ * iterator contained in mCache.
+ */
+ typedef boost::iterator_range<boost::indirect_iterator<iterator_list_iterator> > sorted_range;
+ /// for convenience in looping over a sorted_range
+ typedef typename sorted_range::iterator sorted_iterator;
+
+ /**
+ * Once we've loaded in the dependencies of interest, arrange them into an
+ * order that works -- or throw Cycle exception.
+ *
+ * Return an iterator range over (key, node) pairs that traverses them in
+ * the desired order.
+ */
+ sorted_range sort() const
+ {
+ // Changes to mNodes cause us to clear our cache, so empty mCache
+ // means it's invalid and should be recomputed. However, if mNodes is
+ // also empty, then an empty mCache represents a valid order, so don't
+ // bother sorting.
+ if (mCache.empty() && ! mNodes.empty())
+ {
+ // Construct a map of node keys to distinct vertex numbers -- even for
+ // nodes mentioned only in before/after constraints, that haven't yet
+ // been explicitly added. Rely on std::map rejecting a second attempt
+ // to insert the same key. Use the map's size() as the vertex number
+ // to get a distinct value for each successful insertion.
+ typedef std::map<KEY, int> VertexMap;
+ VertexMap vmap;
+ // Nest each of these loops because !@#$%? MSVC warns us that its
+ // former broken behavior has finally been fixed -- and our builds
+ // treat warnings as errors.
+ {
+ for (typename DepNodeMap::const_iterator nmi = mNodes.begin(), nmend = mNodes.end();
+ nmi != nmend; ++nmi)
+ {
+ vmap.insert(typename VertexMap::value_type(nmi->first, vmap.size()));
+ for (typename DepNode::dep_set::const_iterator ai = nmi->second.after.begin(),
+ aend = nmi->second.after.end();
+ ai != aend; ++ai)
+ {
+ vmap.insert(typename VertexMap::value_type(*ai, vmap.size()));
+ }
+ for (typename DepNode::dep_set::const_iterator bi = nmi->second.before.begin(),
+ bend = nmi->second.before.end();
+ bi != bend; ++bi)
+ {
+ vmap.insert(typename VertexMap::value_type(*bi, vmap.size()));
+ }
+ }
+ }
+ // Define the edges. For this we must traverse mNodes again, mapping
+ // all the known key dependencies to integer pairs.
+ EdgeList edges;
+ {
+ for (typename DepNodeMap::const_iterator nmi = mNodes.begin(), nmend = mNodes.end();
+ nmi != nmend; ++nmi)
+ {
+ int thisnode = vmap[nmi->first];
+ // after dependencies: build edges from the named node to this one
+ for (typename DepNode::dep_set::const_iterator ai = nmi->second.after.begin(),
+ aend = nmi->second.after.end();
+ ai != aend; ++ai)
+ {
+ edges.push_back(EdgeList::value_type(vmap[*ai], thisnode));
+ }
+ // before dependencies: build edges from this node to the
+ // named one
+ for (typename DepNode::dep_set::const_iterator bi = nmi->second.before.begin(),
+ bend = nmi->second.before.end();
+ bi != bend; ++bi)
+ {
+ edges.push_back(EdgeList::value_type(thisnode, vmap[*bi]));
+ }
+ }
+ }
+ // Hide the gory details of our topological sort, since they shouldn't
+ // get reinstantiated for each distinct NODE type.
+ VertexList sorted(topo_sort(vmap.size(), edges));
+ // Build the reverse of vmap to look up the key for each vertex
+ // descriptor. vmap contains exactly one entry for each distinct key,
+ // and we're certain that the associated int values are distinct
+ // indexes. The fact that they're not in order is irrelevant.
+ KeyList vkeys(vmap.size());
+ for (typename VertexMap::const_iterator vmi = vmap.begin(), vmend = vmap.end();
+ vmi != vmend; ++vmi)
+ {
+ vkeys[vmi->second] = vmi->first;
+ }
+ // Walk the sorted output list, building the result into mCache so
+ // we'll have it next time someone asks.
+ mCache.clear();
+ for (VertexList::const_iterator svi = sorted.begin(), svend = sorted.end();
+ svi != svend; ++svi)
+ {
+ // We're certain that vkeys[*svi] exists. However, there might not
+ // yet be a corresponding entry in mNodes.
+ self_type* non_const_this(const_cast<self_type*>(this));
+ typename DepNodeMap::iterator found = non_const_this->mNodes.find(vkeys[*svi]);
+ if (found != non_const_this->mNodes.end())
+ {
+ // Make an iterator of appropriate type.
+ mCache.push_back(iterator(found, value_extract));
+ }
+ }
+ }
+ // Whether or not we've just recomputed mCache, it should now contain
+ // the results we want. Return a range of indirect_iterators over it
+ // so that dereferencing a returned iterator will dereference the
+ // iterator stored in mCache and directly reference the (key, node)
+ // pair.
+ boost::indirect_iterator<iterator_list_iterator>
+ begin(mCache.begin()),
+ end(mCache.end());
+ return sorted_range(begin, end);
+ }
+
+ using LLDependenciesBase::describe; // unhide virtual std::string describe(bool full=true) const;
+
+ /// Override base-class describe() with actual implementation
+ virtual std::ostream& describe(std::ostream& out, bool full=true) const
+ {
+ typename DepNodeMap::const_iterator dmi(mNodes.begin()), dmend(mNodes.end());
+ if (dmi != dmend)
+ {
+ std::string sep;
+ describe(out, sep, *dmi, full);
+ while (++dmi != dmend)
+ {
+ describe(out, sep, *dmi, full);
+ }
+ }
+ return out;
+ }
+
+
+ /// describe() helper: report a DepNodeEntry
+ static std::ostream& describe(std::ostream& out, std::string& sep,
+ const DepNodeMapEntry& entry, bool full)
+ {
+ // If we were asked for a full report, describe every node regardless
+ // of whether it has dependencies. If we were asked to suppress
+ // independent nodes, describe this one if either after or before is
+ // non-empty.
+ if (full || (! entry.second.after.empty()) || (! entry.second.before.empty()))
+ {
+ out << sep;
+ sep = "\n";
+ if (! entry.second.after.empty())
+ {
+ out << "after ";
+ describe(out, entry.second.after);
+ out << " -> ";
+ }
+ LLDependencies_describe(out, entry.first);
+ if (! entry.second.before.empty())
+ {
+ out << " -> before ";
+ describe(out, entry.second.before);
+ }
+ }
+ return out;
+ }
+
+ /// describe() helper: report a dep_set
+ static std::ostream& describe(std::ostream& out, const typename DepNode::dep_set& keys)
+ {
+ out << '(';
+ typename DepNode::dep_set::const_iterator ki(keys.begin()), kend(keys.end());
+ if (ki != kend)
+ {
+ LLDependencies_describe(out, *ki);
+ while (++ki != kend)
+ {
+ out << ", ";
+ LLDependencies_describe(out, *ki);
+ }
+ }
+ out << ')';
+ return out;
+ }
+
+ /// Iterator over the before/after KEYs on which a given NODE depends
+ typedef typename DepNode::dep_set::const_iterator dep_iterator;
+ /// range over the before/after KEYs on which a given NODE depends
+ typedef boost::iterator_range<dep_iterator> dep_range;
+
+ /// dependencies access from key
+ dep_range get_dep_range_from_key(const KEY& key, const dep_selector& selector) const
+ {
+ typename DepNodeMap::const_iterator found = mNodes.find(key);
+ if (found != mNodes.end())
+ {
+ return dep_range(selector(found->second));
+ }
+ // We want to return an empty range. On some platforms a default-
+ // constructed range (e.g. dep_range()) does NOT suffice! The client
+ // is likely to try to iterate from boost::begin(range) to
+ // boost::end(range); yet these iterators might not be valid. Instead
+ // return a range over a valid, empty container.
+ static const typename DepNode::dep_set empty_deps;
+ return dep_range(empty_deps.begin(), empty_deps.end());
+ }
+
+ /// dependencies access from any one of our key-order iterators
+ template<typename ITERATOR>
+ dep_range get_dep_range_from_xform(const ITERATOR& iterator, const dep_selector& selector) const
+ {
+ return dep_range(selector(iterator.base()->second));
+ }
+
+ /// dependencies access from sorted_iterator
+ dep_range get_dep_range_from_sorted(const sorted_iterator& sortiter,
+ const dep_selector& selector) const
+ {
+ // sorted_iterator is a boost::indirect_iterator wrapping an mCache
+ // iterator, which we can obtain by sortiter.base(). Deferencing that
+ // gets us an mCache entry, an 'iterator' -- one of our traversal
+ // iterators -- on which we can use get_dep_range_from_xform().
+ return get_dep_range_from_xform(*sortiter.base(), selector);
+ }
+
+ /**
+ * Get a range over the after KEYs stored for the passed KEY or iterator,
+ * in <i>arbitrary order.</i> If you pass a nonexistent KEY, returns empty
+ * range -- same as a KEY with no after KEYs. Detect existence of a KEY
+ * using get() instead.
+ */
+ template<typename KEY_OR_ITER>
+ dep_range get_after_range(const KEY_OR_ITER& key) const;
+
+ /**
+ * Get a range over the before KEYs stored for the passed KEY or iterator,
+ * in <i>arbitrary order.</i> If you pass a nonexistent KEY, returns empty
+ * range -- same as a KEY with no before KEYs. Detect existence of a KEY
+ * using get() instead.
+ */
+ template<typename KEY_OR_ITER>
+ dep_range get_before_range(const KEY_OR_ITER& key) const;
+
+private:
+ DepNodeMap mNodes;
+ mutable iterator_list mCache;
+};
+
+/**
+ * Functor to get a dep_range from a KEY or iterator -- generic case. If the
+ * passed value isn't one of our iterator specializations, assume it's
+ * convertible to the KEY type.
+ */
+template<typename KEY_ITER>
+struct LLDependencies_dep_range_from
+{
+ template<typename KEY, typename NODE, typename SELECTOR>
+ typename LLDependencies<KEY, NODE>::dep_range
+ operator()(const LLDependencies<KEY, NODE>& deps,
+ const KEY_ITER& key,
+ const SELECTOR& selector)
+ {
+ return deps.get_dep_range_from_key(key, selector);
+ }
+};
+
+/// Specialize LLDependencies_dep_range_from for our key-order iterators
+template<typename FUNCTION, typename ITERATOR>
+struct LLDependencies_dep_range_from< boost::transform_iterator<FUNCTION, ITERATOR> >
+{
+ template<typename KEY, typename NODE, typename SELECTOR>
+ typename LLDependencies<KEY, NODE>::dep_range
+ operator()(const LLDependencies<KEY, NODE>& deps,
+ const boost::transform_iterator<FUNCTION, ITERATOR>& iter,
+ const SELECTOR& selector)
+ {
+ return deps.get_dep_range_from_xform(iter, selector);
+ }
+};
+
+/// Specialize LLDependencies_dep_range_from for sorted_iterator
+template<typename BASEITER>
+struct LLDependencies_dep_range_from< boost::indirect_iterator<BASEITER> >
+{
+ template<typename KEY, typename NODE, typename SELECTOR>
+ typename LLDependencies<KEY, NODE>::dep_range
+ operator()(const LLDependencies<KEY, NODE>& deps,
+ const boost::indirect_iterator<BASEITER>& iter,
+ const SELECTOR& selector)
+ {
+ return deps.get_dep_range_from_sorted(iter, selector);
+ }
+};
+
+/// generic get_after_range() implementation
+template<typename KEY, typename NODE>
+template<typename KEY_OR_ITER>
+typename LLDependencies<KEY, NODE>::dep_range
+LLDependencies<KEY, NODE>::get_after_range(const KEY_OR_ITER& key_iter) const
+{
+ return LLDependencies_dep_range_from<KEY_OR_ITER>()(
+ *this,
+ key_iter,
+ boost::bind<const typename DepNode::dep_set&>(&DepNode::after, _1));
+}
+
+/// generic get_before_range() implementation
+template<typename KEY, typename NODE>
+template<typename KEY_OR_ITER>
+typename LLDependencies<KEY, NODE>::dep_range
+LLDependencies<KEY, NODE>::get_before_range(const KEY_OR_ITER& key_iter) const
+{
+ return LLDependencies_dep_range_from<KEY_OR_ITER>()(
+ *this,
+ key_iter,
+ boost::bind<const typename DepNode::dep_set&>(&DepNode::before, _1));
+}
+
+#endif /* ! defined(LL_LLDEPENDENCIES_H) */
diff --git a/indra/llcommon/lldepthstack.h b/indra/llcommon/lldepthstack.h
index dbde29542a..d9db54efc7 100644
--- a/indra/llcommon/lldepthstack.h
+++ b/indra/llcommon/lldepthstack.h
@@ -2,30 +2,25 @@
* @file lldepthstack.h
* @brief Declaration of the LLDepthStack class
*
- * $LicenseInfo:firstyear=2001&license=viewergpl$
- *
- * Copyright (c) 2001-2007, Linden Research, Inc.
- *
+ * $LicenseInfo:firstyear=2001&license=viewerlgpl$
* Second Life Viewer Source Code
- * The source code in this file ("Source Code") is provided by Linden Lab
- * to you under the terms of the GNU General Public License, version 2.0
- * ("GPL"), unless you have obtained a separate licensing agreement
- * ("Other License"), formally executed by you and Linden Lab. Terms of
- * the GPL can be found in doc/GPL-license.txt in this distribution, or
- * online at http://secondlife.com/developers/opensource/gplv2
+ * 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.
*
- * There are special exceptions to the terms and conditions of the GPL as
- * it is applied to this Source Code. View the full text of the exception
- * in the file doc/FLOSS-exception.txt in this software distribution, or
- * online at http://secondlife.com/developers/opensource/flossexception
+ * 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.
*
- * By copying, modifying or distributing this software, you acknowledge
- * that you have read and understood your obligations described above,
- * and agree to abide by those obligations.
+ * 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
*
- * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
- * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
- * COMPLETENESS OR PERFORMANCE.
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
* $/LicenseInfo$
*/
diff --git a/indra/llcommon/lldictionary.cpp b/indra/llcommon/lldictionary.cpp
new file mode 100644
index 0000000000..e16c35ed6a
--- /dev/null
+++ b/indra/llcommon/lldictionary.cpp
@@ -0,0 +1,47 @@
+/**
+ * @file lldictionary.cpp
+ * @brief Lldictionary class header file
+ *
+ * $LicenseInfo:firstyear=2002&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$
+ */
+
+#include "linden_common.h"
+
+#include "lldictionary.h"
+
+#include "llstring.h"
+
+// Define in .cpp file to prevent header include of llstring.h
+LLDictionaryEntry::LLDictionaryEntry(const std::string &name)
+: mName(name)
+{
+ mNameCapitalized = mName;
+ LLStringUtil::replaceChar(mNameCapitalized, '-', ' ');
+ LLStringUtil::replaceChar(mNameCapitalized, '_', ' ');
+ for (U32 i=0; i < mNameCapitalized.size(); i++)
+ {
+ if (i == 0 || mNameCapitalized[i-1] == ' ') // don't change ordering of this statement or crash
+ {
+ mNameCapitalized[i] = toupper(mNameCapitalized[i]);
+ }
+ }
+}
diff --git a/indra/llcommon/lldictionary.h b/indra/llcommon/lldictionary.h
new file mode 100644
index 0000000000..552a805b70
--- /dev/null
+++ b/indra/llcommon/lldictionary.h
@@ -0,0 +1,94 @@
+/**
+ * @file lldictionary.h
+ * @brief Lldictionary class header file
+ *
+ * $LicenseInfo:firstyear=2002&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$
+ */
+
+#ifndef LL_LLDICTIONARY_H
+#define LL_LLDICTIONARY_H
+
+#include <map>
+#include <string>
+
+struct LL_COMMON_API LLDictionaryEntry
+{
+ LLDictionaryEntry(const std::string &name);
+ virtual ~LLDictionaryEntry() {}
+ const std::string mName;
+ std::string mNameCapitalized;
+};
+
+template <class Index, class Entry>
+class LLDictionary : public std::map<Index, Entry *>
+{
+public:
+ typedef std::map<Index, Entry *> map_t;
+ typedef typename map_t::iterator iterator_t;
+ typedef typename map_t::const_iterator const_iterator_t;
+
+ LLDictionary() {}
+ virtual ~LLDictionary()
+ {
+ for (iterator_t iter = map_t::begin(); iter != map_t::end(); ++iter)
+ delete (iter->second);
+ }
+
+ const Entry *lookup(Index index) const
+ {
+ const_iterator_t dictionary_iter = map_t::find(index);
+ if (dictionary_iter == map_t::end()) return NULL;
+ return dictionary_iter->second;
+ }
+ const Index lookup(const std::string &name) const
+ {
+ for (const_iterator_t dictionary_iter = map_t::begin();
+ dictionary_iter != map_t::end();
+ dictionary_iter++)
+ {
+ const Entry *entry = dictionary_iter->second;
+ if (entry->mName == name)
+ {
+ return dictionary_iter->first;
+ }
+ }
+ return notFound();
+ }
+
+protected:
+ virtual Index notFound() const
+ {
+ // default is to assert
+ llassert(false);
+ return Index(-1);
+ }
+ void addEntry(Index index, Entry *entry)
+ {
+ if (lookup(index))
+ {
+ llerrs << "Dictionary entry already added (attempted to add duplicate entry)" << llendl;
+ }
+ (*this)[index] = entry;
+ }
+};
+
+#endif // LL_LLDICTIONARY_H
diff --git a/indra/llcommon/lldlinked.h b/indra/llcommon/lldlinked.h
index d37d11e9f4..3f7c197be7 100644
--- a/indra/llcommon/lldlinked.h
+++ b/indra/llcommon/lldlinked.h
@@ -2,30 +2,25 @@
* @file lldlinked.h
* @brief Declaration of the LLDLinked class.
*
- * $LicenseInfo:firstyear=2001&license=viewergpl$
- *
- * Copyright (c) 2001-2007, Linden Research, Inc.
- *
+ * $LicenseInfo:firstyear=2001&license=viewerlgpl$
* Second Life Viewer Source Code
- * The source code in this file ("Source Code") is provided by Linden Lab
- * to you under the terms of the GNU General Public License, version 2.0
- * ("GPL"), unless you have obtained a separate licensing agreement
- * ("Other License"), formally executed by you and Linden Lab. Terms of
- * the GPL can be found in doc/GPL-license.txt in this distribution, or
- * online at http://secondlife.com/developers/opensource/gplv2
+ * 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.
*
- * There are special exceptions to the terms and conditions of the GPL as
- * it is applied to this Source Code. View the full text of the exception
- * in the file doc/FLOSS-exception.txt in this software distribution, or
- * online at http://secondlife.com/developers/opensource/flossexception
+ * 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.
*
- * By copying, modifying or distributing this software, you acknowledge
- * that you have read and understood your obligations described above,
- * and agree to abide by those obligations.
+ * 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
*
- * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
- * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
- * COMPLETENESS OR PERFORMANCE.
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
* $/LicenseInfo$
*/
#ifndef LL_LLDLINKED_H
diff --git a/indra/llcommon/lldoubledispatch.h b/indra/llcommon/lldoubledispatch.h
new file mode 100644
index 0000000000..8ed295b6f1
--- /dev/null
+++ b/indra/llcommon/lldoubledispatch.h
@@ -0,0 +1,326 @@
+/**
+ * @file lldoubledispatch.h
+ * @author Nat Goodspeed
+ * @date 2008-11-11
+ * @brief function calls virtual on more than one parameter
+ *
+ * $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_LLDOUBLEDISPATCH_H)
+#define LL_LLDOUBLEDISPATCH_H
+
+#include <list>
+#include <boost/shared_ptr.hpp>
+#include <boost/function.hpp>
+#include <boost/bind.hpp>
+#include <boost/ref.hpp>
+
+/**
+ * This class supports function calls which are virtual on the dynamic type of
+ * more than one parameter. Specifically, we address a limited but useful
+ * subset of that problem: function calls which accept two parameters, and
+ * select which particular function to call depending on the dynamic type of
+ * both.
+ *
+ * Scott Meyers, in More Effective C++ (Item 31), talks about some of the perils
+ * and pitfalls lurking down this pathway. He discusses and dismisses the
+ * straightforward approaches of using single-dispatch virtual functions twice,
+ * and of using a family of single-dispatch virtual functions which each examine
+ * RTTI for their other parameter. He advocates using a registry in which you
+ * look up the actual types of both parameters (he uses the classes' string names,
+ * via typeid(param).name()) to obtain a pointer to a free (non-member) function
+ * that will accept this pair of parameters.
+ *
+ * He does point out that his approach doesn't handle inheritance. If you have a
+ * registry entry for SpaceShip, and you have in hand a MilitaryShip (subclass of
+ * SpaceShip) and an Asteroid, you'd like to call the function appropriate for
+ * SpaceShips and Asteroids -- but alas, his lookup fails because the class name
+ * for your MilitaryShip subclass isn't in the registry.
+ *
+ * This class extends his idea to build a registry whose entries can examine the
+ * dynamic type of the parameter in a more flexible way -- using dynamic_cast<>
+ * -- thereby supporting inheritance relationships.
+ *
+ * Of course we must allow for the ambiguity this permits. We choose to use a
+ * sequence container rather than a map, and require that the client code
+ * specify the order in which dispatch-table entries should be searched. The
+ * result resembles the semantics of the catch clauses for a try/catch block:
+ * you must code catch clauses in decreasing order of specificity, because if
+ * you catch ErrorBaseClass before you catch ErrorSubclass, then any
+ * ErrorSubclass exceptions thrown by the protected code will always match
+ * ErrorBaseClass, and you will never reach your catch(ErrorSubclass) clause.
+ *
+ * So, in a similar way, if you have a specific routine to process
+ * MilitaryShip and Asteroid, you'd better place that in the table @em before
+ * your more general routine that processes SpaceShip and Asteroid, or else
+ * the MilitaryShip variant will never be called.
+ *
+ * @todo This implementation doesn't attempt to deal with
+ * <tt>const</tt>-correctness of arguments. Our container stores templated
+ * objects into which the specific parameter types have been "frozen." But to
+ * store all these in the same container, they are all instances of a base
+ * class with a virtual invocation method. Naturally the base-class virtual
+ * method definition cannot know the <tt>const</tt>-ness of the particular
+ * types with which its template subclass is instantiated.
+ *
+ * One is tempted to suggest four different virtual methods, one for each
+ * combination of @c const and non-<tt>const</tt> arguments. Then the client
+ * will select the particular virtual method that best fits the
+ * <tt>const</tt>-ness of the arguments in hand. The trouble with that idea is
+ * that in order to instantiate the subclass instance, we must compile all
+ * four of its virtual method overrides, which means we must be prepared to
+ * pass all four combinations of @c const and non-<tt>const</tt> arguments to
+ * the registered callable. That only works when the registered callable
+ * accepts both parameters as @c const.
+ *
+ * Of course the virtual method overrides could use @c const_cast to force
+ * them to compile correctly regardless of the <tt>const</tt>-ness of the
+ * registered callable's parameter declarations. But if we're going to force
+ * the issue with @c const_cast anyway, why bother with the four different
+ * virtual methods? Why not just require canonical parameter
+ * <tt>const</tt>-ness for any callables used with this mechanism?
+ *
+ * We therefore require that your callable accept both params as
+ * non-<tt>const</tt>. (This is more general than @c const: you can perform @c
+ * const operations on a non-<tt>const</tt> parameter, but you can't perform
+ * non-<tt>const</tt> operations on a @c const parameter.)
+ *
+ * For ease of use, though, our invocation method accepts both params as @c
+ * const. Again, you can pass a non-<tt>const</tt> object to a @c const param,
+ * but not the other way around. We take care of the @c const_cast for you.
+ */
+// LLDoubleDispatch is a template because we have to assume that all parameter
+// types are subclasses of some common base class -- but we don't have to
+// impose that base class on client code. Instead, we let IT tell US the
+// common parameter base class.
+template<class ReturnType, class ParamBaseType>
+class LLDoubleDispatch
+{
+ typedef LLDoubleDispatch<ReturnType, ParamBaseType> self_type;
+
+public:
+ LLDoubleDispatch() {}
+
+ /**
+ * Call the first matching entry. If there's no registered Functor
+ * appropriate for this pair of parameter types, this call will do
+ * @em nothing! (If you want notification in this case, simply add a new
+ * Functor for (ParamBaseType&, ParamBaseType&) at the end of the table.
+ * The two base-class entries should match anything that isn't matched by
+ * any more specific entry.)
+ *
+ * See note in class documentation about <tt>const</tt>-correctness.
+ */
+ inline
+ ReturnType operator()(const ParamBaseType& param1, const ParamBaseType& param2) const;
+
+ // Borrow a trick from Alexandrescu: use a Type class to "wrap" a type
+ // for purposes of passing the type itself into a template method.
+ template<typename T>
+ struct Type {};
+
+ /**
+ * Add a new Entry for a given @a Functor. As mentioned above, the order
+ * in which you add these entries is very important.
+ *
+ * If you want symmetrical entries -- that is, if a B and an A can call
+ * the same Functor as an A and a B -- then pass @c true for the last
+ * parameter, and we'll add a (B, A) entry as well as an (A, B) entry. But
+ * your @a Functor can still be written to expect exactly the pair of types
+ * you've explicitly specified, because the Entry with the reversed params
+ * will call a special thunk that swaps params before calling your @a
+ * Functor.
+ */
+ template<typename Type1, typename Type2, class Functor>
+ void add(const Type<Type1>& t1, const Type<Type2>& t2, Functor func, bool symmetrical=false)
+ {
+ insert(t1, t2, func);
+ if (symmetrical)
+ {
+ // Use boost::bind() to construct a param-swapping thunk. Don't
+ // forget to reverse the parameters too.
+ insert(t2, t1, boost::bind(func, _2, _1));
+ }
+ }
+
+ /**
+ * Add a new Entry for a given @a Functor, explicitly passing instances of
+ * the Functor's leaf param types to help us figure out where to insert.
+ * Because it can use RTTI, this add() method isn't order-sensitive like
+ * the other one.
+ *
+ * If you want symmetrical entries -- that is, if a B and an A can call
+ * the same Functor as an A and a B -- then pass @c true for the last
+ * parameter, and we'll add a (B, A) entry as well as an (A, B) entry. But
+ * your @a Functor can still be written to expect exactly the pair of types
+ * you've explicitly specified, because the Entry with the reversed params
+ * will call a special thunk that swaps params before calling your @a
+ * Functor.
+ */
+ template <typename Type1, typename Type2, class Functor>
+ void add(const Type1& prototype1, const Type2& prototype2, Functor func, bool symmetrical=false)
+ {
+ // Because we expect our caller to pass leaf param types, we can just
+ // perform an ordinary search to find the first matching iterator. If
+ // we find an existing Entry that matches both params, either the
+ // param types are the same, or the existing Entry uses the base class
+ // for one or both params, and the new Entry must precede that. Assume
+ // our client won't register two callables with exactly the SAME set
+ // of types; in that case we'll insert the new one before any earlier
+ // ones, meaning the last one registered will "win." Note that if
+ // find() doesn't find any matching Entry, it will return end(),
+ // meaning the new Entry will be last, which is fine.
+ typename DispatchTable::iterator insertion = find(prototype1, prototype2);
+ insert(Type<Type1>(), Type<Type2>(), func, insertion);
+ if (symmetrical)
+ {
+ insert(Type<Type2>(), Type<Type1>(), boost::bind(func, _2, _1), insertion);
+ }
+ }
+
+ /**
+ * Add a new Entry for a given @a Functor, specifying the Functor's leaf
+ * param types as explicit template arguments. This will instantiate
+ * temporary objects of each of these types, which requires that they have
+ * a lightweight default constructor.
+ *
+ * If you want symmetrical entries -- that is, if a B and an A can call
+ * the same Functor as an A and a B -- then pass @c true for the last
+ * parameter, and we'll add a (B, A) entry as well as an (A, B) entry. But
+ * your @a Functor can still be written to expect exactly the pair of types
+ * you've explicitly specified, because the Entry with the reversed params
+ * will call a special thunk that swaps params before calling your @a
+ * Functor.
+ */
+ template <typename Type1, typename Type2, class Functor>
+ void add(Functor func, bool symmetrical=false)
+ {
+ // This is a convenience wrapper for the add() variant taking explicit
+ // instances.
+ add(Type1(), Type2(), func, symmetrical);
+ }
+
+private:
+ /// This is the base class for each entry in our dispatch table.
+ struct EntryBase
+ {
+ virtual ~EntryBase() {}
+ virtual bool matches(const ParamBaseType& param1, const ParamBaseType& param2) const = 0;
+ virtual ReturnType operator()(ParamBaseType& param1, ParamBaseType& param2) const = 0;
+ };
+
+ /// Here's the template subclass that actually creates each entry.
+ template<typename Type1, typename Type2, class Functor>
+ class Entry: public EntryBase
+ {
+ public:
+ Entry(Functor func): mFunc(func) {}
+ /// Is this entry appropriate for these arguments?
+ virtual bool matches(const ParamBaseType& param1, const ParamBaseType& param2) const
+ {
+ return (dynamic_cast<const Type1*>(&param1) &&
+ dynamic_cast<const Type2*>(&param2));
+ }
+ /// invocation
+ virtual ReturnType operator()(ParamBaseType& param1, ParamBaseType& param2) const
+ {
+ // We perform the downcast so callable can accept leaf param
+ // types, instead of accepting ParamBaseType and downcasting
+ // explicitly.
+ return mFunc(dynamic_cast<Type1&>(param1), dynamic_cast<Type2&>(param2));
+ }
+ private:
+ /// Bind whatever function or function object the instantiator passed.
+ Functor mFunc;
+ };
+
+ /// shared_ptr manages Entry lifespan for us
+ typedef boost::shared_ptr<EntryBase> EntryPtr;
+ /// use a @c list to make it easy to insert
+ typedef std::list<EntryPtr> DispatchTable;
+ DispatchTable mDispatch;
+
+ /// Look up the location of the first matching entry.
+ typename DispatchTable::const_iterator find(const ParamBaseType& param1, const ParamBaseType& param2) const
+ {
+ // We assert that it's safe to call the non-const find() method on a
+ // const LLDoubleDispatch instance. Cast away the const-ness of 'this'.
+ return const_cast<self_type*>(this)->find(param1, param2);
+ }
+
+ /// Look up the location of the first matching entry.
+ typename DispatchTable::iterator find(const ParamBaseType& param1, const ParamBaseType& param2)
+ {
+ return std::find_if(mDispatch.begin(), mDispatch.end(),
+ boost::bind(&EntryBase::matches, _1,
+ boost::ref(param1), boost::ref(param2)));
+ }
+
+ /// Look up the first matching entry.
+ EntryPtr lookup(const ParamBaseType& param1, const ParamBaseType& param2) const
+ {
+ typename DispatchTable::const_iterator found = find(param1, param2);
+ if (found != mDispatch.end())
+ {
+ // Dereferencing the list iterator gets us an EntryPtr
+ return *found;
+ }
+ // not found
+ return EntryPtr();
+ }
+
+ // Break out the actual insert operation so the public add() template
+ // function can avoid calling itself recursively. See add() comments.
+ template<typename Type1, typename Type2, class Functor>
+ void insert(const Type<Type1>& param1, const Type<Type2>& param2, Functor func)
+ {
+ insert(param1, param2, func, mDispatch.end());
+ }
+
+ // Break out the actual insert operation so the public add() template
+ // function can avoid calling itself recursively. See add() comments.
+ template<typename Type1, typename Type2, class Functor>
+ void insert(const Type<Type1>&, const Type<Type2>&, Functor func,
+ typename DispatchTable::iterator where)
+ {
+ mDispatch.insert(where, EntryPtr(new Entry<Type1, Type2, Functor>(func)));
+ }
+
+ /// Don't implement the copy ctor. Everyone will be happier if the
+ /// LLDoubleDispatch object isn't copied.
+ LLDoubleDispatch(const LLDoubleDispatch& src);
+};
+
+template <class ReturnType, class ParamBaseType>
+ReturnType LLDoubleDispatch<ReturnType, ParamBaseType>::operator()(const ParamBaseType& param1,
+ const ParamBaseType& param2) const
+{
+ EntryPtr found = lookup(param1, param2);
+ if (found.get() == 0)
+ return ReturnType(); // bogus return value
+
+ // otherwise, call the Functor we found
+ return (*found)(const_cast<ParamBaseType&>(param1), const_cast<ParamBaseType&>(param2));
+}
+
+#endif /* ! defined(LL_LLDOUBLEDISPATCH_H) */
diff --git a/indra/llcommon/lldqueueptr.h b/indra/llcommon/lldqueueptr.h
index 06eee34cbc..9fe08191e1 100644
--- a/indra/llcommon/lldqueueptr.h
+++ b/indra/llcommon/lldqueueptr.h
@@ -2,30 +2,25 @@
* @file lldqueueptr.h
* @brief LLDynamicQueuePtr declaration
*
- * $LicenseInfo:firstyear=2001&license=viewergpl$
- *
- * Copyright (c) 2001-2007, Linden Research, Inc.
- *
+ * $LicenseInfo:firstyear=2001&license=viewerlgpl$
* Second Life Viewer Source Code
- * The source code in this file ("Source Code") is provided by Linden Lab
- * to you under the terms of the GNU General Public License, version 2.0
- * ("GPL"), unless you have obtained a separate licensing agreement
- * ("Other License"), formally executed by you and Linden Lab. Terms of
- * the GPL can be found in doc/GPL-license.txt in this distribution, or
- * online at http://secondlife.com/developers/opensource/gplv2
+ * 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.
*
- * There are special exceptions to the terms and conditions of the GPL as
- * it is applied to this Source Code. View the full text of the exception
- * in the file doc/FLOSS-exception.txt in this software distribution, or
- * online at http://secondlife.com/developers/opensource/flossexception
+ * 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.
*
- * By copying, modifying or distributing this software, you acknowledge
- * that you have read and understood your obligations described above,
- * and agree to abide by those obligations.
+ * 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
*
- * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
- * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
- * COMPLETENESS OR PERFORMANCE.
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
* $/LicenseInfo$
*/
#ifndef LL_LLDQUEUEPTR_H
@@ -47,7 +42,7 @@ public:
void init();
void destroy();
void reset();
- void realloc(U32 newsize);
+ void reallocate(U32 newsize);
// ACCESSORS
const Type& get(const S32 index) const; // no bounds checking
@@ -115,7 +110,7 @@ template <class Type>
inline LLDynamicQueuePtr<Type>::LLDynamicQueuePtr(const S32 size)
{
init();
- realloc(size);
+ reallocate(size);
}
template <class Type>
@@ -134,7 +129,7 @@ inline void LLDynamicQueuePtr<Type>::init()
}
template <class Type>
-inline void LLDynamicQueuePtr<Type>::realloc(U32 newsize)
+inline void LLDynamicQueuePtr<Type>::reallocate(U32 newsize)
{
if (newsize)
{
@@ -308,7 +303,7 @@ inline S32 LLDynamicQueuePtr<Type>::push(const Type &obj)
{
if (mMaxObj - count() <= 1)
{
- realloc(mMaxObj * 2);
+ reallocate(mMaxObj * 2);
}
mMemory[mLastObj++] = obj;
diff --git a/indra/llcommon/llendianswizzle.h b/indra/llcommon/llendianswizzle.h
index d2a9e401f4..4c08074a9c 100644
--- a/indra/llcommon/llendianswizzle.h
+++ b/indra/llcommon/llendianswizzle.h
@@ -2,30 +2,25 @@
* @file llendianswizzle.h
* @brief Functions for in-place bit swizzling
*
- * $LicenseInfo:firstyear=2002&license=viewergpl$
- *
- * Copyright (c) 2002-2007, Linden Research, Inc.
- *
+ * $LicenseInfo:firstyear=2002&license=viewerlgpl$
* Second Life Viewer Source Code
- * The source code in this file ("Source Code") is provided by Linden Lab
- * to you under the terms of the GNU General Public License, version 2.0
- * ("GPL"), unless you have obtained a separate licensing agreement
- * ("Other License"), formally executed by you and Linden Lab. Terms of
- * the GPL can be found in doc/GPL-license.txt in this distribution, or
- * online at http://secondlife.com/developers/opensource/gplv2
+ * 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.
*
- * There are special exceptions to the terms and conditions of the GPL as
- * it is applied to this Source Code. View the full text of the exception
- * in the file doc/FLOSS-exception.txt in this software distribution, or
- * online at http://secondlife.com/developers/opensource/flossexception
+ * 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.
*
- * By copying, modifying or distributing this software, you acknowledge
- * that you have read and understood your obligations described above,
- * and agree to abide by those obligations.
+ * 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
*
- * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
- * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
- * COMPLETENESS OR PERFORMANCE.
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
* $/LicenseInfo$
*/
diff --git a/indra/llcommon/llenum.h b/indra/llcommon/llenum.h
index 53db01d5f1..f57b2bc0b5 100644
--- a/indra/llcommon/llenum.h
+++ b/indra/llcommon/llenum.h
@@ -3,30 +3,25 @@
* @author Tom Yedwab
* @brief Utility class for storing enum value <-> string lookup.
*
- * $LicenseInfo:firstyear=2006&license=viewergpl$
- *
- * Copyright (c) 2006-2007, Linden Research, Inc.
- *
+ * $LicenseInfo:firstyear=2006&license=viewerlgpl$
* Second Life Viewer Source Code
- * The source code in this file ("Source Code") is provided by Linden Lab
- * to you under the terms of the GNU General Public License, version 2.0
- * ("GPL"), unless you have obtained a separate licensing agreement
- * ("Other License"), formally executed by you and Linden Lab. Terms of
- * the GPL can be found in doc/GPL-license.txt in this distribution, or
- * online at http://secondlife.com/developers/opensource/gplv2
+ * 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.
*
- * There are special exceptions to the terms and conditions of the GPL as
- * it is applied to this Source Code. View the full text of the exception
- * in the file doc/FLOSS-exception.txt in this software distribution, or
- * online at http://secondlife.com/developers/opensource/flossexception
+ * 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.
*
- * By copying, modifying or distributing this software, you acknowledge
- * that you have read and understood your obligations described above,
- * and agree to abide by those obligations.
+ * 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
*
- * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
- * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
- * COMPLETENESS OR PERFORMANCE.
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
* $/LicenseInfo$
*/
diff --git a/indra/llcommon/llerror.cpp b/indra/llcommon/llerror.cpp
index 22b2c9db82..bb64152407 100644
--- a/indra/llcommon/llerror.cpp
+++ b/indra/llcommon/llerror.cpp
@@ -3,30 +3,25 @@
* @date December 2006
* @brief error message system
*
- * $LicenseInfo:firstyear=2006&license=viewergpl$
- *
- * Copyright (c) 2006-2007, Linden Research, Inc.
- *
+ * $LicenseInfo:firstyear=2006&license=viewerlgpl$
* Second Life Viewer Source Code
- * The source code in this file ("Source Code") is provided by Linden Lab
- * to you under the terms of the GNU General Public License, version 2.0
- * ("GPL"), unless you have obtained a separate licensing agreement
- * ("Other License"), formally executed by you and Linden Lab. Terms of
- * the GPL can be found in doc/GPL-license.txt in this distribution, or
- * online at http://secondlife.com/developers/opensource/gplv2
+ * Copyright (C) 2010, Linden Research, Inc.
*
- * There are special exceptions to the terms and conditions of the GPL as
- * it is applied to this Source Code. View the full text of the exception
- * in the file doc/FLOSS-exception.txt in this software distribution, or
- * online at http://secondlife.com/developers/opensource/flossexception
+ * 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.
*
- * By copying, modifying or distributing this software, you acknowledge
- * that you have read and understood your obligations described above,
- * and agree to abide by those obligations.
+ * 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.
*
- * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
- * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
- * COMPLETENESS OR PERFORMANCE.
+ * 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$
*/
@@ -37,26 +32,23 @@
#include <cctype>
#ifdef __GNUC__
-#include <cxxabi.h>
-#endif
+# include <cxxabi.h>
+#endif // __GNUC__
#include <sstream>
#if !LL_WINDOWS
-#include <syslog.h>
-#endif
-#if LL_WINDOWS
-#include <windows.h>
-#endif
+# include <syslog.h>
+# include <unistd.h>
+#endif // !LL_WINDOWS
#include <vector>
#include "llapp.h"
#include "llapr.h"
#include "llfile.h"
-#include "llfixedbuffer.h"
#include "lllivefile.h"
#include "llsd.h"
#include "llsdserialize.h"
#include "llstl.h"
-
+#include "lltimer.h"
namespace {
#if !LL_WINDOWS
@@ -101,7 +93,7 @@ namespace {
public:
RecordToFile(const std::string& filename)
{
- mFile.open(filename.c_str(), llofstream::out | llofstream::app);
+ mFile.open(filename, llofstream::out | llofstream::app);
if (!mFile)
{
llinfos << "Error setting log file to " << filename << llendl;
@@ -133,33 +125,73 @@ namespace {
class RecordToStderr : public LLError::Recorder
{
public:
- RecordToStderr(bool timestamp) : mTimestamp(timestamp) { }
+ RecordToStderr(bool timestamp) : mTimestamp(timestamp), mUseANSI(ANSI_PROBE) { }
virtual bool wantsTime() { return mTimestamp; }
virtual void recordMessage(LLError::ELevel level,
- const std::string& message)
+ const std::string& message)
{
+ if (ANSI_PROBE == mUseANSI)
+ mUseANSI = (checkANSI() ? ANSI_YES : ANSI_NO);
+
+ if (ANSI_YES == mUseANSI)
+ {
+ // Default all message levels to bold so we can distinguish our own messages from those dumped by subprocesses and libraries.
+ colorANSI("1"); // bold
+ switch (level) {
+ case LLError::LEVEL_ERROR:
+ colorANSI("31"); // red
+ break;
+ case LLError::LEVEL_WARN:
+ colorANSI("34"); // blue
+ break;
+ case LLError::LEVEL_DEBUG:
+ colorANSI("35"); // magenta
+ break;
+ default:
+ break;
+ }
+ }
fprintf(stderr, "%s\n", message.c_str());
+ if (ANSI_YES == mUseANSI) colorANSI("0"); // reset
}
private:
bool mTimestamp;
+ enum ANSIState {ANSI_PROBE, ANSI_YES, ANSI_NO};
+ ANSIState mUseANSI;
+ void colorANSI(const std::string color)
+ {
+ // ANSI color code escape sequence
+ fprintf(stderr, "\033[%sm", color.c_str() );
+ };
+ bool checkANSI(void)
+ {
+#if LL_LINUX || LL_DARWIN
+ // Check whether it's okay to use ANSI; if stderr is
+ // a tty then we assume yes. Can be turned off with
+ // the LL_NO_ANSI_COLOR env var.
+ return (0 != isatty(2)) &&
+ (NULL == getenv("LL_NO_ANSI_COLOR"));
+#endif // LL_LINUX
+ return false;
+ };
};
class RecordToFixedBuffer : public LLError::Recorder
{
public:
- RecordToFixedBuffer(LLFixedBuffer& buffer) : mBuffer(buffer) { }
+ RecordToFixedBuffer(LLLineBuffer* buffer) : mBuffer(buffer) { }
virtual void recordMessage(LLError::ELevel level,
- const std::string& message)
+ const std::string& message)
{
- mBuffer.addLine(message.c_str());
+ mBuffer->addLine(message);
}
private:
- LLFixedBuffer& mBuffer;
+ LLLineBuffer* mBuffer;
};
#if LL_WINDOWS
@@ -167,7 +199,7 @@ namespace {
{
public:
virtual void recordMessage(LLError::ELevel level,
- const std::string& message)
+ const std::string& message)
{
llutf16string utf16str =
wstring_to_utf16str(utf8str_to_wstring(message));
@@ -247,7 +279,7 @@ namespace
public:
static LogControlFile& fromDirectory(const std::string& dir);
- virtual void loadFile();
+ virtual bool loadFile();
private:
LogControlFile(const std::string &filename)
@@ -264,7 +296,7 @@ namespace
std::string file = dirBase + "logcontrol-dev.xml";
llstat stat_info;
- if (LLFile::stat(file.c_str(), &stat_info)) {
+ if (LLFile::stat(file, &stat_info)) {
// NB: stat returns non-zero if it can't read the file, for example
// if it doesn't exist. LLFile has no better abstraction for
// testing for file existence.
@@ -275,12 +307,12 @@ namespace
// NB: This instance is never freed
}
- void LogControlFile::loadFile()
+ bool LogControlFile::loadFile()
{
LLSD configuration;
{
- llifstream file(filename().c_str());
+ llifstream file(filename());
if (file.is_open())
{
LLSDSerialize::fromXML(configuration, file);
@@ -291,12 +323,13 @@ namespace
llwarns << filename() << " missing, ill-formed,"
" or simply undefined; not changing configuration"
<< llendl;
- return;
+ return false;
}
}
LLError::configure(configuration);
llinfos << "logging reconfigured from " << filename() << llendl;
+ return true;
}
@@ -367,6 +400,8 @@ namespace LLError
LevelMap functionLevelMap;
LevelMap classLevelMap;
LevelMap fileLevelMap;
+ LevelMap tagLevelMap;
+ std::map<std::string, unsigned int> uniqueLogMessages;
LLError::FatalFunction crashFunction;
LLError::TimeFunction timeFunction;
@@ -388,7 +423,7 @@ namespace LLError
Settings()
: printLocation(false),
defaultLevel(LLError::LEVEL_DEBUG),
- crashFunction(NULL),
+ crashFunction(),
timeFunction(NULL),
fileRecorder(NULL),
fixedBufferRecorder(NULL),
@@ -453,11 +488,17 @@ namespace LLError
namespace LLError
{
CallSite::CallSite(ELevel level,
- const char* file, int line,
- const std::type_info& class_info, const char* function)
+ const char* file,
+ int line,
+ const std::type_info& class_info,
+ const char* function,
+ const char* broadTag,
+ const char* narrowTag,
+ bool printOnce)
: mLevel(level), mFile(file), mLine(line),
mClassInfo(class_info), mFunction(function),
- mCached(false), mShouldLog(false)
+ mCached(false), mShouldLog(false),
+ mBroadTag(broadTag), mNarrowTag(narrowTag), mPrintOnce(printOnce)
{ }
@@ -511,6 +552,15 @@ namespace
#endif
LogControlFile& e = LogControlFile::fromDirectory(dir);
+
+ // NOTE: We want to explicitly load the file before we add it to the event timer
+ // that checks for changes to the file. Else, we're not actually loading the file yet,
+ // and most of the initialization happens without any attention being paid to the
+ // log control file. Not to mention that when it finally gets checked later,
+ // all log statements that have been evaluated already become dirty and need to be
+ // evaluated for printing again. So, make sure to call checkAndReload()
+ // before addToEventTimer().
+ e.checkAndReload();
e.addToEventTimer();
}
}
@@ -541,12 +591,18 @@ namespace LLError
s.printLocation = print;
}
- void setFatalFunction(FatalFunction f)
+ void setFatalFunction(const FatalFunction& f)
{
Settings& s = Settings::get();
s.crashFunction = f;
}
+ FatalFunction getFatalFunction()
+ {
+ Settings& s = Settings::get();
+ return s.crashFunction;
+ }
+
void setTimeFunction(TimeFunction f)
{
Settings& s = Settings::get();
@@ -584,6 +640,14 @@ namespace LLError
g.invalidateCallSites();
s.fileLevelMap[file_name] = level;
}
+
+ void setTagLevel(const std::string& tag_name, ELevel level)
+ {
+ Globals& g = Globals::get();
+ Settings& s = Settings::get();
+ g.invalidateCallSites();
+ s.tagLevelMap[tag_name] = level;
+ }
}
namespace {
@@ -633,6 +697,8 @@ namespace LLError
s.functionLevelMap.clear();
s.classLevelMap.clear();
s.fileLevelMap.clear();
+ s.tagLevelMap.clear();
+ s.uniqueLogMessages.clear();
setPrintLocation(config["print-location"]);
setDefaultLevel(decodeLevel(config["default-level"]));
@@ -648,6 +714,7 @@ namespace LLError
setLevels(s.functionLevelMap, entry["functions"], level);
setLevels(s.classLevelMap, entry["classes"], level);
setLevels(s.fileLevelMap, entry["files"], level);
+ setLevels(s.tagLevelMap, entry["tags"], level);
}
}
}
@@ -715,7 +782,7 @@ namespace LLError
addRecorder(f);
}
- void logToFixedBuffer(LLFixedBuffer* fixedBuffer)
+ void logToFixedBuffer(LLLineBuffer* fixedBuffer)
{
LLError::Settings& s = LLError::Settings::get();
@@ -728,7 +795,7 @@ namespace LLError
return;
}
- s.fixedBufferRecorder = new RecordToFixedBuffer(*fixedBuffer);
+ s.fixedBufferRecorder = new RecordToFixedBuffer(fixedBuffer);
addRecorder(s.fixedBufferRecorder);
}
@@ -809,7 +876,7 @@ namespace {
return false;
}
- level = i->second;
+ level = i->second;
return true;
}
@@ -881,16 +948,27 @@ namespace LLError
std::string class_name = className(site.mClassInfo);
std::string function_name = functionName(site.mFunction);
+#if LL_LINUX
+ // gross, but typeid comparison seems to always fail here with gcc4.1
+ if (0 != strcmp(site.mClassInfo.name(), typeid(NoClassInfo).name()))
+#else
if (site.mClassInfo != typeid(NoClassInfo))
+#endif // LL_LINUX
{
function_name = class_name + "::" + function_name;
}
ELevel compareLevel = s.defaultLevel;
- checkLevelMap(s.functionLevelMap, function_name, compareLevel)
+ // The most specific match found will be used as the log level,
+ // since the computation short circuits.
+ // So, in increasing order of importance:
+ // Default < Broad Tag < File < Class < Function < Narrow Tag
+ ((site.mNarrowTag != NULL) ? checkLevelMap(s.tagLevelMap, site.mNarrowTag, compareLevel) : false)
+ || checkLevelMap(s.functionLevelMap, function_name, compareLevel)
|| checkLevelMap(s.classLevelMap, class_name, compareLevel)
- || checkLevelMap(s.fileLevelMap, abbreviateFile(site.mFile), compareLevel);
+ || checkLevelMap(s.fileLevelMap, abbreviateFile(site.mFile), compareLevel)
+ || ((site.mBroadTag != NULL) ? checkLevelMap(s.tagLevelMap, site.mBroadTag, compareLevel) : false);
site.mCached = true;
g.addCallSite(site);
@@ -914,6 +992,38 @@ namespace LLError
return new std::ostringstream;
}
+
+ void Log::flush(std::ostringstream* out, char* message)
+ {
+ LogLock lock;
+ if (!lock.ok())
+ {
+ return;
+ }
+
+ if(strlen(out->str().c_str()) < 128)
+ {
+ strcpy(message, out->str().c_str());
+ }
+ else
+ {
+ strncpy(message, out->str().c_str(), 127);
+ message[127] = '\0' ;
+ }
+
+ Globals& g = Globals::get();
+ if (out == &g.messageStream)
+ {
+ g.messageStream.clear();
+ g.messageStream.str("");
+ g.messageStreamInUse = false;
+ }
+ else
+ {
+ delete out;
+ }
+ return ;
+ }
void Log::flush(std::ostringstream* out, const CallSite& site)
{
@@ -965,17 +1075,42 @@ namespace LLError
<< "(" << site.mLine << ") : ";
}
- if (message.find(functionName(site.mFunction)) == std::string::npos)
- {
#if LL_WINDOWS
- // DevStudio: __FUNCTION__ already includes the full class name
+ // DevStudio: __FUNCTION__ already includes the full class name
#else
- if (site.mClassInfo != typeid(NoClassInfo))
+ #if LL_LINUX
+ // gross, but typeid comparison seems to always fail here with gcc4.1
+ if (0 != strcmp(site.mClassInfo.name(), typeid(NoClassInfo).name()))
+ #else
+ if (site.mClassInfo != typeid(NoClassInfo))
+ #endif // LL_LINUX
+ {
+ prefix << className(site.mClassInfo) << "::";
+ }
+ #endif
+ prefix << site.mFunction << ": ";
+
+ if (site.mPrintOnce)
+ {
+ std::map<std::string, unsigned int>::iterator messageIter = s.uniqueLogMessages.find(message);
+ if (messageIter != s.uniqueLogMessages.end())
{
- prefix << className(site.mClassInfo) << "::";
+ messageIter->second++;
+ unsigned int num_messages = messageIter->second;
+ if (num_messages == 10 || num_messages == 50 || (num_messages % 100) == 0)
+ {
+ prefix << "ONCE (" << num_messages << "th time seen): ";
+ }
+ else
+ {
+ return;
+ }
+ }
+ else
+ {
+ prefix << "ONCE: ";
+ s.uniqueLogMessages[message] = 1;
}
- #endif
- prefix << site.mFunction << ": ";
}
prefix << message;
@@ -1052,18 +1187,28 @@ namespace LLError
return s.shouldLogCallCounter;
}
+#if LL_WINDOWS
+ // VC80 was optimizing the error away.
+ #pragma optimize("", off)
+#endif
void crashAndLoop(const std::string& message)
{
// Now, we go kaboom!
- int* crash = NULL;
+ int* make_me_crash = NULL;
- *crash = 0;
+ *make_me_crash = 0;
while(true)
{
// Loop forever, in case the crash didn't work?
}
+
+ // this is an attempt to let Coverity and other semantic scanners know that this function won't be returning ever.
+ exit(EXIT_FAILURE);
}
+#if LL_WINDOWS
+ #pragma optimize("", on)
+#endif
std::string utcTime()
{
@@ -1079,3 +1224,175 @@ namespace LLError
}
}
+namespace LLError
+{
+ char** LLCallStacks::sBuffer = NULL ;
+ S32 LLCallStacks::sIndex = 0 ;
+
+#define SINGLE_THREADED 1
+
+ class CallStacksLogLock
+ {
+ public:
+ CallStacksLogLock();
+ ~CallStacksLogLock();
+
+#if SINGLE_THREADED
+ bool ok() const { return true; }
+#else
+ bool ok() const { return mOK; }
+ private:
+ bool mLocked;
+ bool mOK;
+#endif
+ };
+
+#if SINGLE_THREADED
+ CallStacksLogLock::CallStacksLogLock()
+ {
+ }
+ CallStacksLogLock::~CallStacksLogLock()
+ {
+ }
+#else
+ CallStacksLogLock::CallStacksLogLock()
+ : mLocked(false), mOK(false)
+ {
+ if (!gCallStacksLogMutexp)
+ {
+ mOK = true;
+ return;
+ }
+
+ const int MAX_RETRIES = 5;
+ for (int attempts = 0; attempts < MAX_RETRIES; ++attempts)
+ {
+ apr_status_t s = apr_thread_mutex_trylock(gCallStacksLogMutexp);
+ if (!APR_STATUS_IS_EBUSY(s))
+ {
+ mLocked = true;
+ mOK = true;
+ return;
+ }
+
+ ms_sleep(1);
+ }
+
+ // We're hosed, we can't get the mutex. Blah.
+ std::cerr << "CallStacksLogLock::CallStacksLogLock: failed to get mutex for log"
+ << std::endl;
+ }
+
+ CallStacksLogLock::~CallStacksLogLock()
+ {
+ if (mLocked)
+ {
+ apr_thread_mutex_unlock(gCallStacksLogMutexp);
+ }
+ }
+#endif
+
+ //static
+ void LLCallStacks::push(const char* function, const int line)
+ {
+ CallStacksLogLock lock;
+ if (!lock.ok())
+ {
+ return;
+ }
+
+ if(!sBuffer)
+ {
+ sBuffer = new char*[512] ;
+ sBuffer[0] = new char[512 * 128] ;
+ for(S32 i = 1 ; i < 512 ; i++)
+ {
+ sBuffer[i] = sBuffer[i-1] + 128 ;
+ }
+ sIndex = 0 ;
+ }
+
+ if(sIndex > 511)
+ {
+ clear() ;
+ }
+
+ strcpy(sBuffer[sIndex], function) ;
+ sprintf(sBuffer[sIndex] + strlen(function), " line: %d ", line) ;
+ sIndex++ ;
+
+ return ;
+ }
+
+ //static
+ std::ostringstream* LLCallStacks::insert(const char* function, const int line)
+ {
+ std::ostringstream* _out = LLError::Log::out();
+ *_out << function << " line " << line << " " ;
+
+ return _out ;
+ }
+
+ //static
+ void LLCallStacks::end(std::ostringstream* _out)
+ {
+ CallStacksLogLock lock;
+ if (!lock.ok())
+ {
+ return;
+ }
+
+ if(!sBuffer)
+ {
+ sBuffer = new char*[512] ;
+ sBuffer[0] = new char[512 * 128] ;
+ for(S32 i = 1 ; i < 512 ; i++)
+ {
+ sBuffer[i] = sBuffer[i-1] + 128 ;
+ }
+ sIndex = 0 ;
+ }
+
+ if(sIndex > 511)
+ {
+ clear() ;
+ }
+
+ LLError::Log::flush(_out, sBuffer[sIndex++]) ;
+ }
+
+ //static
+ void LLCallStacks::print()
+ {
+ CallStacksLogLock lock;
+ if (!lock.ok())
+ {
+ return;
+ }
+
+ if(sIndex > 0)
+ {
+ llinfos << " ************* PRINT OUT LL CALL STACKS ************* " << llendl ;
+ while(sIndex > 0)
+ {
+ sIndex-- ;
+ llinfos << sBuffer[sIndex] << llendl ;
+ }
+ llinfos << " *************** END OF LL CALL STACKS *************** " << llendl ;
+ }
+
+ if(sBuffer)
+ {
+ delete[] sBuffer[0] ;
+ delete[] sBuffer ;
+ sBuffer = NULL ;
+ }
+ }
+
+ //static
+ void LLCallStacks::clear()
+ {
+ sIndex = 0 ;
+ }
+}
+
diff --git a/indra/llcommon/llerror.h b/indra/llcommon/llerror.h
index ae41cd5244..4a42241c4f 100644
--- a/indra/llcommon/llerror.h
+++ b/indra/llcommon/llerror.h
@@ -3,30 +3,25 @@
* @date December 2006
* @brief error message system
*
- * $LicenseInfo:firstyear=2006&license=viewergpl$
- *
- * Copyright (c) 2006-2007, Linden Research, Inc.
- *
+ * $LicenseInfo:firstyear=2006&license=viewerlgpl$
* Second Life Viewer Source Code
- * The source code in this file ("Source Code") is provided by Linden Lab
- * to you under the terms of the GNU General Public License, version 2.0
- * ("GPL"), unless you have obtained a separate licensing agreement
- * ("Other License"), formally executed by you and Linden Lab. Terms of
- * the GPL can be found in doc/GPL-license.txt in this distribution, or
- * online at http://secondlife.com/developers/opensource/gplv2
+ * Copyright (C) 2010, Linden Research, Inc.
*
- * There are special exceptions to the terms and conditions of the GPL as
- * it is applied to this Source Code. View the full text of the exception
- * in the file doc/FLOSS-exception.txt in this software distribution, or
- * online at http://secondlife.com/developers/opensource/flossexception
+ * 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.
*
- * By copying, modifying or distributing this software, you acknowledge
- * that you have read and understood your obligations described above,
- * and agree to abide by those obligations.
+ * 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.
*
- * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
- * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
- * COMPLETENESS OR PERFORMANCE.
+ * 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$
*/
@@ -37,6 +32,7 @@
#include <typeinfo>
#include "llerrorlegacy.h"
+#include "stdtypes.h"
/* Error Logging Facility
@@ -45,23 +41,23 @@
Code can log messages with constuctions like this:
- llinfos << "request to fizzbip agent " << agent_id
- << " denied due to timeout" << llendl;
+ LL_INFOS("StringTag") << "request to fizzbip agent " << agent_id
+ << " denied due to timeout" << LL_ENDL;
Messages can be logged to one of four increasing levels of concern,
using one of four "streams":
- lldebugs - debug messages that are normally supressed
- llinfos - informational messages that are normall shown
- llwarns - warning messages that singal a problem
- llerrs - error messages that are major, unrecoverable failures
+ LL_DEBUGS("StringTag") - debug messages that are normally supressed
+ LL_INFOS("StringTag") - informational messages that are normall shown
+ LL_WARNS("StringTag") - warning messages that singal a problem
+ LL_ERRS("StringTag") - error messages that are major, unrecoverable failures
- The later (llerrs) automatically crashes the process after the message
+ The later (LL_ERRS("StringTag")) automatically crashes the process after the message
is logged.
Note that these "streams" are actually #define magic. Rules for use:
* they cannot be used as normal streams, only to start a message
- * messages written to them MUST be terminated with llendl
+ * messages written to them MUST be terminated with LL_ENDL
* between the opening and closing, the << operator is indeed
writing onto a std::ostream, so all conversions and stream
formating are available
@@ -85,7 +81,7 @@
{
if (i > 100)
{
- llwanrs << "called with a big value for i: " << i << llendl;
+ LL_WARNS("FooBarTag") << "called with a big value for i: " << i << LL_ENDL;
}
...
}
@@ -100,7 +96,7 @@
Lastly, logging is now very efficient in both compiled code and execution
when skipped. There is no need to wrap messages, even debugging ones, in
- #ifdef _DEBUG constructs. lldebugs messages are compiled into all builds,
+ #ifdef _DEBUG constructs. LL_DEBUGS("StringTag") messages are compiled into all builds,
even release. Which means you can use them to help debug even when deployed
to a real grid.
*/
@@ -129,22 +125,23 @@ namespace LLError
class CallSite;
- class Log
+ class LL_COMMON_API Log
{
public:
static bool shouldLog(CallSite&);
static std::ostringstream* out();
+ static void flush(std::ostringstream* out, char* message) ;
static void flush(std::ostringstream*, const CallSite&);
};
- class CallSite
+ class LL_COMMON_API CallSite
{
// Represents a specific place in the code where a message is logged
// This is public because it is used by the macros below. It is not
// intended for public use.
public:
CallSite(ELevel, const char* file, int line,
- const std::type_info& class_info, const char* function);
+ const std::type_info& class_info, const char* function, const char* broadTag, const char* narrowTag, bool printOnce);
bool shouldLog()
{ return mCached ? mShouldLog : Log::shouldLog(*this); }
@@ -156,9 +153,12 @@ namespace LLError
// these describe the call site and never change
const ELevel mLevel;
const char* const mFile;
- const int mLine;
- const std::type_info& mClassInfo;
+ const int mLine;
+ const std::type_info& mClassInfo;
const char* const mFunction;
+ const char* const mBroadTag;
+ const char* const mNarrowTag;
+ const bool mPrintOnce;
// these implement a cache of the call to shouldLog()
bool mCached;
@@ -173,11 +173,43 @@ namespace LLError
{ return s; }
// used to indicate the end of a message
- class NoClassInfo { };
+ class LL_COMMON_API NoClassInfo { };
// used to indicate no class info known for logging
-}
+ //LLCallStacks keeps track of call stacks and output the call stacks to log file
+ //when LLAppViewer::handleViewerCrash() is triggered.
+ //
+ //Note: to be simple, efficient and necessary to keep track of correct call stacks,
+ //LLCallStacks is designed not to be thread-safe.
+ //so try not to use it in multiple parallel threads at same time.
+ //Used in a single thread at a time is fine.
+ class LL_COMMON_API LLCallStacks
+ {
+ private:
+ static char** sBuffer ;
+ static S32 sIndex ;
+
+ public:
+ static void push(const char* function, const int line) ;
+ static std::ostringstream* insert(const char* function, const int line) ;
+ static void print() ;
+ static void clear() ;
+ static void end(std::ostringstream* _out) ;
+ };
+}
+//this is cheaper than llcallstacks if no need to output other variables to call stacks.
+#define llpushcallstacks LLError::LLCallStacks::push(__FUNCTION__, __LINE__)
+#define llcallstacks \
+ {\
+ std::ostringstream* _out = LLError::LLCallStacks::insert(__FUNCTION__, __LINE__) ; \
+ (*_out)
+#define llcallstacksendl \
+ LLError::End(); \
+ LLError::LLCallStacks::end(_out) ; \
+ }
+#define llclearcallstacks LLError::LLCallStacks::clear()
+#define llprintcallstacks LLError::LLCallStacks::print()
/*
Class type information for logging
@@ -200,39 +232,66 @@ typedef LLError::NoClassInfo _LL_CLASS_TO_LOG;
See top of file for common usage.
*/
-#define lllog(level) \
- { \
+#define lllog(level, broadTag, narrowTag, once) \
+ do { \
static LLError::CallSite _site( \
- level, __FILE__, __LINE__, typeid(_LL_CLASS_TO_LOG), __FUNCTION__);\
- if (_site.shouldLog()) \
+ level, __FILE__, __LINE__, typeid(_LL_CLASS_TO_LOG), __FUNCTION__, broadTag, narrowTag, once);\
+ if (LL_UNLIKELY(_site.shouldLog())) \
{ \
std::ostringstream* _out = LLError::Log::out(); \
(*_out)
-
+
+// DEPRECATED: Don't call directly, use LL_ENDL instead, which actually looks like a macro
#define llendl \
LLError::End(); \
LLError::Log::flush(_out, _site); \
} \
- }
-
-#define llinfos lllog(LLError::LEVEL_INFO)
-#define lldebugs lllog(LLError::LEVEL_DEBUG)
-#define llwarns lllog(LLError::LEVEL_WARN)
-#define llerrs lllog(LLError::LEVEL_ERROR)
+ } while(0)
+// DEPRECATED: Use the new macros that allow tags and *look* like macros.
+#define lldebugs lllog(LLError::LEVEL_DEBUG, NULL, NULL, false)
+#define llinfos lllog(LLError::LEVEL_INFO, NULL, NULL, false)
+#define llwarns lllog(LLError::LEVEL_WARN, NULL, NULL, false)
+#define llerrs lllog(LLError::LEVEL_ERROR, NULL, NULL, false)
#define llcont (*_out)
+
+// NEW Macros for debugging, allow the passing of a string tag
+
+// One Tag
+#define LL_DEBUGS(broadTag) lllog(LLError::LEVEL_DEBUG, broadTag, NULL, false)
+#define LL_INFOS(broadTag) lllog(LLError::LEVEL_INFO, broadTag, NULL, false)
+#define LL_WARNS(broadTag) lllog(LLError::LEVEL_WARN, broadTag, NULL, false)
+#define LL_ERRS(broadTag) lllog(LLError::LEVEL_ERROR, broadTag, NULL, false)
+// Two Tags
+#define LL_DEBUGS2(broadTag, narrowTag) lllog(LLError::LEVEL_DEBUG, broadTag, narrowTag, false)
+#define LL_INFOS2(broadTag, narrowTag) lllog(LLError::LEVEL_INFO, broadTag, narrowTag, false)
+#define LL_WARNS2(broadTag, narrowTag) lllog(LLError::LEVEL_WARN, broadTag, narrowTag, false)
+#define LL_ERRS2(broadTag, narrowTag) lllog(LLError::LEVEL_ERROR, broadTag, narrowTag, false)
+
+// Only print the log message once (good for warnings or infos that would otherwise
+// spam the log file over and over, such as tighter loops).
+#define LL_DEBUGS_ONCE(broadTag) lllog(LLError::LEVEL_DEBUG, broadTag, NULL, true)
+#define LL_INFOS_ONCE(broadTag) lllog(LLError::LEVEL_INFO, broadTag, NULL, true)
+#define LL_WARNS_ONCE(broadTag) lllog(LLError::LEVEL_WARN, broadTag, NULL, true)
+#define LL_DEBUGS2_ONCE(broadTag, narrowTag) lllog(LLError::LEVEL_DEBUG, broadTag, narrowTag, true)
+#define LL_INFOS2_ONCE(broadTag, narrowTag) lllog(LLError::LEVEL_INFO, broadTag, narrowTag, true)
+#define LL_WARNS2_ONCE(broadTag, narrowTag) lllog(LLError::LEVEL_WARN, broadTag, narrowTag, true)
+
+#define LL_ENDL llendl
+#define LL_CONT (*_out)
+
/*
Use this construct if you need to do computation in the middle of a
message:
- llinfos << "the agent " << agend_id;
+ LL_INFOS("AgentGesture") << "the agent " << agend_id;
switch (f)
{
- case FOP_SHRUGS: llcont << "shrugs"; break;
- case FOP_TAPS: llcont << "points at " << who; break;
- case FOP_SAYS: llcont << "says " << message; break;
+ case FOP_SHRUGS: LL_CONT << "shrugs"; break;
+ case FOP_TAPS: LL_CONT << "points at " << who; break;
+ case FOP_SAYS: LL_CONT << "says " << message; break;
}
- llcont << " for " << t << " seconds" << llendl;
+ LL_CONT << " for " << t << " seconds" << LL_ENDL;
Such computation is done iff the message will be logged.
*/
diff --git a/indra/llcommon/llerrorcontrol.h b/indra/llcommon/llerrorcontrol.h
index 528704d064..fb75d45e2c 100644
--- a/indra/llcommon/llerrorcontrol.h
+++ b/indra/llcommon/llerrorcontrol.h
@@ -3,30 +3,25 @@
* @date December 2006
* @brief error message system control
*
- * $LicenseInfo:firstyear=2007&license=viewergpl$
- *
- * Copyright (c) 2007, Linden Research, Inc.
- *
+ * $LicenseInfo:firstyear=2007&license=viewerlgpl$
* Second Life Viewer Source Code
- * The source code in this file ("Source Code") is provided by Linden Lab
- * to you under the terms of the GNU General Public License, version 2.0
- * ("GPL"), unless you have obtained a separate licensing agreement
- * ("Other License"), formally executed by you and Linden Lab. Terms of
- * the GPL can be found in doc/GPL-license.txt in this distribution, or
- * online at http://secondlife.com/developers/opensource/gplv2
+ * 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.
*
- * There are special exceptions to the terms and conditions of the GPL as
- * it is applied to this Source Code. View the full text of the exception
- * in the file doc/FLOSS-exception.txt in this software distribution, or
- * online at http://secondlife.com/developers/opensource/flossexception
+ * 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.
*
- * By copying, modifying or distributing this software, you acknowledge
- * that you have read and understood your obligations described above,
- * and agree to abide by those obligations.
+ * 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
*
- * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
- * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
- * COMPLETENESS OR PERFORMANCE.
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
* $/LicenseInfo$
*/
@@ -34,10 +29,9 @@
#define LL_LLERRORCONTROL_H
#include "llerror.h"
-
+#include "boost/function.hpp"
#include <string>
-class LLFixedBuffer;
class LLSD;
/*
@@ -48,15 +42,27 @@ class LLSD;
These implementations are in llerror.cpp.
*/
+// Line buffer interface
+class LLLineBuffer
+{
+public:
+ LLLineBuffer() {};
+ virtual ~LLLineBuffer() {};
+
+ virtual void clear() = 0; // Clear the buffer, and reset it.
+
+ virtual void addLine(const std::string& utf8line) = 0;
+};
+
namespace LLError
{
- void initForServer(const std::string& identity);
+ LL_COMMON_API void initForServer(const std::string& identity);
// resets all logging settings to defaults needed by server processes
// logs to stderr, syslog, and windows debug log
// the identity string is used for in the syslog
- void initForApplication(const std::string& dir);
+ LL_COMMON_API void initForApplication(const std::string& dir);
// resets all logging settings to defaults needed by applicaitons
// logs to stderr and windows debug log
// sets up log configuration from the file logcontrol.xml in dir
@@ -67,13 +73,14 @@ namespace LLError
Setting a level means log messages at that level or above.
*/
- void setPrintLocation(bool);
- void setDefaultLevel(LLError::ELevel);
- void setFunctionLevel(const std::string& function_name, LLError::ELevel);
- void setClassLevel(const std::string& class_name, LLError::ELevel);
- void setFileLevel(const std::string& file_name, LLError::ELevel);
+ LL_COMMON_API void setPrintLocation(bool);
+ LL_COMMON_API void setDefaultLevel(LLError::ELevel);
+ LL_COMMON_API void setFunctionLevel(const std::string& function_name, LLError::ELevel);
+ LL_COMMON_API void setClassLevel(const std::string& class_name, LLError::ELevel);
+ LL_COMMON_API void setFileLevel(const std::string& file_name, LLError::ELevel);
+ LL_COMMON_API void setTagLevel(const std::string& file_name, LLError::ELevel);
- void configure(const LLSD&);
+ LL_COMMON_API void configure(const LLSD&);
// the LLSD can configure all of the settings
// usually read automatically from the live errorlog.xml file
@@ -82,26 +89,48 @@ namespace LLError
Control functions.
*/
- typedef void (*FatalFunction)(const std::string& message);
- void crashAndLoop(const std::string& message);
- // Default fatal funtion: divides by zero and loops forever
+ typedef boost::function<void(const std::string&)> FatalFunction;
+ LL_COMMON_API void crashAndLoop(const std::string& message);
+ // Default fatal function: access null pointer and loops forever
- void setFatalFunction(FatalFunction);
+ LL_COMMON_API void setFatalFunction(const FatalFunction&);
// The fatal function will be called when an message of LEVEL_ERROR
// is logged. Note: supressing a LEVEL_ERROR message from being logged
// (by, for example, setting a class level to LEVEL_NONE), will keep
// the that message from causing the fatal funciton to be invoked.
-
+
+ LL_COMMON_API FatalFunction getFatalFunction();
+ // Retrieve the previously-set FatalFunction
+
+ /// temporarily override the FatalFunction for the duration of a
+ /// particular scope, e.g. for unit tests
+ class LL_COMMON_API OverrideFatalFunction
+ {
+ public:
+ OverrideFatalFunction(const FatalFunction& func):
+ mPrev(getFatalFunction())
+ {
+ setFatalFunction(func);
+ }
+ ~OverrideFatalFunction()
+ {
+ setFatalFunction(mPrev);
+ }
+
+ private:
+ FatalFunction mPrev;
+ };
+
typedef std::string (*TimeFunction)();
- std::string utcTime();
+ LL_COMMON_API std::string utcTime();
- void setTimeFunction(TimeFunction);
+ LL_COMMON_API void setTimeFunction(TimeFunction);
// The function is use to return the current time, formatted for
// display by those error recorders that want the time included.
- class Recorder
+ class LL_COMMON_API Recorder
{
// An object that handles the actual output or error messages.
public:
@@ -115,17 +144,17 @@ namespace LLError
// included in the text of the message
};
- void addRecorder(Recorder*);
- void removeRecorder(Recorder*);
+ LL_COMMON_API void addRecorder(Recorder*);
+ LL_COMMON_API void removeRecorder(Recorder*);
// each error message is passed to each recorder via recordMessage()
- void logToFile(const std::string& filename);
- void logToFixedBuffer(LLFixedBuffer*);
+ LL_COMMON_API void logToFile(const std::string& filename);
+ LL_COMMON_API void logToFixedBuffer(LLLineBuffer*);
// Utilities to add recorders for logging to a file or a fixed buffer
// A second call to the same function will remove the logger added
// with the first.
// Passing the empty string or NULL to just removes any prior.
- std::string logFileName();
+ LL_COMMON_API std::string logFileName();
// returns name of current logging file, empty string if none
@@ -134,11 +163,11 @@ namespace LLError
*/
class Settings;
- Settings* saveAndResetSettings();
- void restoreSettings(Settings *);
+ LL_COMMON_API Settings* saveAndResetSettings();
+ LL_COMMON_API void restoreSettings(Settings *);
- std::string abbreviateFile(const std::string& filePath);
- int shouldLogCallCount();
+ LL_COMMON_API std::string abbreviateFile(const std::string& filePath);
+ LL_COMMON_API int shouldLogCallCount();
};
diff --git a/indra/llcommon/llerrorlegacy.h b/indra/llcommon/llerrorlegacy.h
index cef34559cc..37cee579cd 100644
--- a/indra/llcommon/llerrorlegacy.h
+++ b/indra/llcommon/llerrorlegacy.h
@@ -3,37 +3,32 @@
* @date January 2007
* @brief old things from the older error system
*
- * $LicenseInfo:firstyear=2007&license=viewergpl$
- *
- * Copyright (c) 2007, Linden Research, Inc.
- *
+ * $LicenseInfo:firstyear=2007&license=viewerlgpl$
* Second Life Viewer Source Code
- * The source code in this file ("Source Code") is provided by Linden Lab
- * to you under the terms of the GNU General Public License, version 2.0
- * ("GPL"), unless you have obtained a separate licensing agreement
- * ("Other License"), formally executed by you and Linden Lab. Terms of
- * the GPL can be found in doc/GPL-license.txt in this distribution, or
- * online at http://secondlife.com/developers/opensource/gplv2
+ * 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.
*
- * There are special exceptions to the terms and conditions of the GPL as
- * it is applied to this Source Code. View the full text of the exception
- * in the file doc/FLOSS-exception.txt in this software distribution, or
- * online at http://secondlife.com/developers/opensource/flossexception
+ * 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.
*
- * By copying, modifying or distributing this software, you acknowledge
- * that you have read and understood your obligations described above,
- * and agree to abide by those obligations.
+ * 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
*
- * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
- * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
- * COMPLETENESS OR PERFORMANCE.
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
* $/LicenseInfo$
*/
#ifndef LL_LLERRORLEGACY_H
#define LL_LLERRORLEGACY_H
-
+#include "llpreprocessor.h"
/*
LEGACY -- DO NOT USE THIS STUFF ANYMORE
@@ -52,6 +47,7 @@ const int LL_ERR_FILE_NOT_FOUND = -43;
const int LL_ERR_FILE_EMPTY = -44;
const int LL_ERR_TCP_TIMEOUT = -23016;
const int LL_ERR_CIRCUIT_GONE = -23017;
+const int LL_ERR_PRICE_MISMATCH = -23018;
@@ -73,6 +69,10 @@ const int LL_ERR_CIRCUIT_GONE = -23017;
#define SHOW_ASSERT
#else // _DEBUG
+#ifdef LL_RELEASE_WITH_DEBUG_INFO
+#define SHOW_ASSERT
+#endif // LL_RELEASE_WITH_DEBUG_INFO
+
#ifdef RELEASE_SHOW_DEBUG
#define SHOW_DEBUG
#endif
@@ -101,17 +101,14 @@ const int LL_ERR_CIRCUIT_GONE = -23017;
#define llwarning(msg, num) llwarns << "Warning # " << num << ": " << msg << llendl;
-#ifdef SHOW_ASSERT
-#define llassert(func) if (!(func)) llerrs << "ASSERT (" << #func << ")" << llendl;
-#else
-#define llassert(func)
-#endif
-#define llassert_always(func) if (!(func)) llerrs << "ASSERT (" << #func << ")" << llendl;
+#define llassert_always(func) if (LL_UNLIKELY(!(func))) llerrs << "ASSERT (" << #func << ")" << llendl;
#ifdef SHOW_ASSERT
-#define llverify(func) if (!(func)) llerrs << "ASSERT (" << #func << ")" << llendl;
+#define llassert(func) llassert_always(func)
+#define llverify(func) llassert_always(func)
#else
-#define llverify(func) (func); // get rid of warning C4189
+#define llassert(func)
+#define llverify(func) do {if (func) {}} while(0)
#endif
// handy compile-time assert - enforce those template parameters!
diff --git a/indra/llcommon/llerrorthread.cpp b/indra/llcommon/llerrorthread.cpp
index 66806b41fd..902eaa3b72 100644
--- a/indra/llcommon/llerrorthread.cpp
+++ b/indra/llcommon/llerrorthread.cpp
@@ -1,36 +1,33 @@
/**
* @file llerrorthread.cpp
*
- * $LicenseInfo:firstyear=2004&license=viewergpl$
- *
- * Copyright (c) 2004-2007, Linden Research, Inc.
- *
+ * $LicenseInfo:firstyear=2004&license=viewerlgpl$
* Second Life Viewer Source Code
- * The source code in this file ("Source Code") is provided by Linden Lab
- * to you under the terms of the GNU General Public License, version 2.0
- * ("GPL"), unless you have obtained a separate licensing agreement
- * ("Other License"), formally executed by you and Linden Lab. Terms of
- * the GPL can be found in doc/GPL-license.txt in this distribution, or
- * online at http://secondlife.com/developers/opensource/gplv2
+ * Copyright (C) 2010, Linden Research, Inc.
*
- * There are special exceptions to the terms and conditions of the GPL as
- * it is applied to this Source Code. View the full text of the exception
- * in the file doc/FLOSS-exception.txt in this software distribution, or
- * online at http://secondlife.com/developers/opensource/flossexception
+ * 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.
*
- * By copying, modifying or distributing this software, you acknowledge
- * that you have read and understood your obligations described above,
- * and agree to abide by those obligations.
+ * 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.
*
- * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
- * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
- * COMPLETENESS OR PERFORMANCE.
+ * 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$
*/
#include "linden_common.h"
#include "llerrorthread.h"
+
#include "llapp.h"
+#include "lltimer.h" // ms_sleep()
LLErrorThread::LLErrorThread()
: LLThread("Error"),
diff --git a/indra/llcommon/llerrorthread.h b/indra/llcommon/llerrorthread.h
index 714f014fc2..474cef3a50 100644
--- a/indra/llcommon/llerrorthread.h
+++ b/indra/llcommon/llerrorthread.h
@@ -2,30 +2,25 @@
* @file llerrorthread.h
* @brief Specialized thread to handle runtime errors.
*
- * $LicenseInfo:firstyear=2004&license=viewergpl$
- *
- * Copyright (c) 2004-2007, Linden Research, Inc.
- *
+ * $LicenseInfo:firstyear=2004&license=viewerlgpl$
* Second Life Viewer Source Code
- * The source code in this file ("Source Code") is provided by Linden Lab
- * to you under the terms of the GNU General Public License, version 2.0
- * ("GPL"), unless you have obtained a separate licensing agreement
- * ("Other License"), formally executed by you and Linden Lab. Terms of
- * the GPL can be found in doc/GPL-license.txt in this distribution, or
- * online at http://secondlife.com/developers/opensource/gplv2
+ * 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.
*
- * There are special exceptions to the terms and conditions of the GPL as
- * it is applied to this Source Code. View the full text of the exception
- * in the file doc/FLOSS-exception.txt in this software distribution, or
- * online at http://secondlife.com/developers/opensource/flossexception
+ * 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.
*
- * By copying, modifying or distributing this software, you acknowledge
- * that you have read and understood your obligations described above,
- * and agree to abide by those obligations.
+ * 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
*
- * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
- * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
- * COMPLETENESS OR PERFORMANCE.
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
* $/LicenseInfo$
*/
@@ -34,7 +29,7 @@
#include "llthread.h"
-class LLErrorThread : public LLThread
+class LL_COMMON_API LLErrorThread : public LLThread
{
public:
LLErrorThread();
diff --git a/indra/llcommon/llevent.cpp b/indra/llcommon/llevent.cpp
index 292d0909a4..633df01588 100644
--- a/indra/llcommon/llevent.cpp
+++ b/indra/llcommon/llevent.cpp
@@ -2,30 +2,25 @@
* @file llevent.cpp
* @brief LLEvent and LLEventListener base classes.
*
- * $LicenseInfo:firstyear=2006&license=viewergpl$
- *
- * Copyright (c) 2006-2007, Linden Research, Inc.
- *
+ * $LicenseInfo:firstyear=2006&license=viewerlgpl$
* Second Life Viewer Source Code
- * The source code in this file ("Source Code") is provided by Linden Lab
- * to you under the terms of the GNU General Public License, version 2.0
- * ("GPL"), unless you have obtained a separate licensing agreement
- * ("Other License"), formally executed by you and Linden Lab. Terms of
- * the GPL can be found in doc/GPL-license.txt in this distribution, or
- * online at http://secondlife.com/developers/opensource/gplv2
+ * Copyright (C) 2010, Linden Research, Inc.
*
- * There are special exceptions to the terms and conditions of the GPL as
- * it is applied to this Source Code. View the full text of the exception
- * in the file doc/FLOSS-exception.txt in this software distribution, or
- * online at http://secondlife.com/developers/opensource/flossexception
+ * 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.
*
- * By copying, modifying or distributing this software, you acknowledge
- * that you have read and understood your obligations described above,
- * and agree to abide by those obligations.
+ * 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.
*
- * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
- * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
- * COMPLETENESS OR PERFORMANCE.
+ * 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$
*/
@@ -33,6 +28,8 @@
#include "llevent.h"
+using namespace LLOldEvents;
+
/************************************************
Events
************************************************/
@@ -219,7 +216,7 @@ std::vector<LLListenerEntry> LLSimpleDispatcher::getListeners() const
bool LLSimpleDispatcher::fireEvent(LLPointer<LLEvent> event, LLSD filter)
{
std::vector<LLListenerEntry>::iterator itor;
- LLString filter_string = filter.asString();
+ std::string filter_string = filter.asString();
for (itor=mListeners.begin(); itor!=mListeners.end(); ++itor)
{
LLListenerEntry& entry = *itor;
diff --git a/indra/llcommon/llevent.h b/indra/llcommon/llevent.h
index 741b40b787..8cd682b8bf 100644
--- a/indra/llcommon/llevent.h
+++ b/indra/llcommon/llevent.h
@@ -3,30 +3,25 @@
* @author Tom Yedwab
* @brief LLEvent and LLEventListener base classes.
*
- * $LicenseInfo:firstyear=2001&license=viewergpl$
- *
- * Copyright (c) 2001-2007, Linden Research, Inc.
- *
+ * $LicenseInfo:firstyear=2001&license=viewerlgpl$
* Second Life Viewer Source Code
- * The source code in this file ("Source Code") is provided by Linden Lab
- * to you under the terms of the GNU General Public License, version 2.0
- * ("GPL"), unless you have obtained a separate licensing agreement
- * ("Other License"), formally executed by you and Linden Lab. Terms of
- * the GPL can be found in doc/GPL-license.txt in this distribution, or
- * online at http://secondlife.com/developers/opensource/gplv2
+ * 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.
*
- * There are special exceptions to the terms and conditions of the GPL as
- * it is applied to this Source Code. View the full text of the exception
- * in the file doc/FLOSS-exception.txt in this software distribution, or
- * online at http://secondlife.com/developers/opensource/flossexception
+ * 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.
*
- * By copying, modifying or distributing this software, you acknowledge
- * that you have read and understood your obligations described above,
- * and agree to abide by those obligations.
+ * 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
*
- * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
- * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
- * COMPLETENESS OR PERFORMANCE.
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
* $/LicenseInfo$
*/
@@ -34,16 +29,19 @@
#define LL_EVENT_H
#include "llsd.h"
-#include "llmemory.h"
+#include "llpointer.h"
#include "llthread.h"
+namespace LLOldEvents
+{
+
class LLEventListener;
class LLEvent;
class LLEventDispatcher;
class LLObservable;
// Abstract event. All events derive from LLEvent
-class LLEvent : public LLThreadSafeRefCount
+class LL_COMMON_API LLEvent : public LLThreadSafeRefCount
{
protected:
virtual ~LLEvent();
@@ -71,7 +69,7 @@ private:
};
// Abstract listener. All listeners derive from LLEventListener
-class LLEventListener : public LLThreadSafeRefCount
+class LL_COMMON_API LLEventListener : public LLThreadSafeRefCount
{
protected:
virtual ~LLEventListener();
@@ -88,7 +86,7 @@ public:
};
// A listener which tracks references to it and cleans up when it's deallocated
-class LLSimpleListener : public LLEventListener
+class LL_COMMON_API LLSimpleListener : public LLEventListener
{
public:
void clearDispatchers();
@@ -113,7 +111,7 @@ struct LLListenerEntry
// Base class for a dispatcher - an object which listens
// to events being fired and relays them to their
// appropriate destinations.
-class LLEventDispatcher : public LLThreadSafeRefCount
+class LL_COMMON_API LLEventDispatcher : public LLThreadSafeRefCount
{
protected:
virtual ~LLEventDispatcher();
@@ -156,7 +154,7 @@ private:
// In order for this class to work properly, it needs
// an instance of an LLEventDispatcher to route events to their
// listeners.
-class LLObservable
+class LL_COMMON_API LLObservable
{
public:
// Initialize with the default Dispatcher
@@ -193,4 +191,6 @@ public:
LLSD mValue;
};
+} // LLOldEvents
+
#endif // LL_EVENT_H
diff --git a/indra/llcommon/lleventapi.cpp b/indra/llcommon/lleventapi.cpp
new file mode 100644
index 0000000000..4270c8b511
--- /dev/null
+++ b/indra/llcommon/lleventapi.cpp
@@ -0,0 +1,47 @@
+/**
+ * @file lleventapi.cpp
+ * @author Nat Goodspeed
+ * @date 2009-11-10
+ * @brief Implementation for lleventapi.
+ *
+ * $LicenseInfo:firstyear=2009&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$
+ */
+
+// Precompiled header
+#include "linden_common.h"
+// associated header
+#include "lleventapi.h"
+// STL headers
+// std headers
+// external library headers
+// other Linden headers
+
+LLEventAPI::LLEventAPI(const std::string& name, const std::string& desc, const std::string& field):
+ lbase(name, field),
+ ibase(name),
+ mDesc(desc)
+{
+}
+
+LLEventAPI::~LLEventAPI()
+{
+}
diff --git a/indra/llcommon/lleventapi.h b/indra/llcommon/lleventapi.h
new file mode 100644
index 0000000000..d75d521e8e
--- /dev/null
+++ b/indra/llcommon/lleventapi.h
@@ -0,0 +1,83 @@
+/**
+ * @file lleventapi.h
+ * @author Nat Goodspeed
+ * @date 2009-10-28
+ * @brief LLEventAPI is the base class for every class that wraps a C++ API
+ * in an event API
+ * (see https://wiki.lindenlab.com/wiki/Incremental_Viewer_Automation/Event_API).
+ *
+ * $LicenseInfo:firstyear=2009&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_LLEVENTAPI_H)
+#define LL_LLEVENTAPI_H
+
+#include "lleventdispatcher.h"
+#include "llinstancetracker.h"
+#include <string>
+
+/**
+ * LLEventAPI not only provides operation dispatch functionality, inherited
+ * from LLDispatchListener -- it also gives us event API introspection.
+ * Deriving from LLInstanceTracker lets us enumerate instances.
+ */
+class LL_COMMON_API LLEventAPI: public LLDispatchListener,
+ public LLInstanceTracker<LLEventAPI, std::string>
+{
+ typedef LLDispatchListener lbase;
+ typedef LLInstanceTracker<LLEventAPI, std::string> ibase;
+
+public:
+ /**
+ * @param name LLEventPump name on which this LLEventAPI will listen. This
+ * also serves as the LLInstanceTracker instance key.
+ * @param desc Documentation string shown to a client trying to discover
+ * available event APIs.
+ * @param field LLSD::Map key used by LLDispatchListener to look up the
+ * subclass method to invoke [default "op"].
+ */
+ LLEventAPI(const std::string& name, const std::string& desc, const std::string& field="op");
+ virtual ~LLEventAPI();
+
+ /// Get the string name of this LLEventAPI
+ std::string getName() const { return ibase::getKey(); }
+ /// Get the documentation string
+ std::string getDesc() const { return mDesc; }
+
+ /**
+ * Publish only selected add() methods from LLEventDispatcher.
+ * Every LLEventAPI add() @em must have a description string.
+ */
+ template <typename CALLABLE>
+ void add(const std::string& name,
+ const std::string& desc,
+ CALLABLE callable,
+ const LLSD& required=LLSD())
+ {
+ LLEventDispatcher::add(name, desc, callable, required);
+ }
+
+private:
+ std::string mDesc;
+};
+
+#endif /* ! defined(LL_LLEVENTAPI_H) */
diff --git a/indra/llcommon/lleventcoro.cpp b/indra/llcommon/lleventcoro.cpp
new file mode 100644
index 0000000000..81cc33fbba
--- /dev/null
+++ b/indra/llcommon/lleventcoro.cpp
@@ -0,0 +1,146 @@
+/**
+ * @file lleventcoro.cpp
+ * @author Nat Goodspeed
+ * @date 2009-04-29
+ * @brief Implementation for lleventcoro.
+ *
+ * $LicenseInfo:firstyear=2009&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$
+ */
+
+// Precompiled header
+#include "linden_common.h"
+// associated header
+#include "lleventcoro.h"
+// STL headers
+#include <map>
+// std headers
+// external library headers
+// other Linden headers
+#include "llsdserialize.h"
+#include "llerror.h"
+#include "llcoros.h"
+
+std::string LLEventDetail::listenerNameForCoroImpl(const void* self_id)
+{
+ // First, if this coroutine was launched by LLCoros::launch(), find that name.
+ std::string name(LLCoros::instance().getNameByID(self_id));
+ if (! name.empty())
+ {
+ return name;
+ }
+ // Apparently this coroutine wasn't launched by LLCoros::launch(). Check
+ // whether we have a memo for this self_id.
+ typedef std::map<const void*, std::string> MapType;
+ static MapType memo;
+ MapType::const_iterator found = memo.find(self_id);
+ if (found != memo.end())
+ {
+ // this coroutine instance has called us before, reuse same name
+ return found->second;
+ }
+ // this is the first time we've been called for this coroutine instance
+ name = LLEventPump::inventName("coro");
+ memo[self_id] = name;
+ LL_INFOS("LLEventCoro") << "listenerNameForCoroImpl(" << self_id << "): inventing coro name '"
+ << name << "'" << LL_ENDL;
+ return name;
+}
+
+void LLEventDetail::storeToLLSDPath(LLSD& dest, const LLSD& rawPath, const LLSD& value)
+{
+ if (rawPath.isUndefined())
+ {
+ // no-op case
+ return;
+ }
+
+ // Arrange to treat rawPath uniformly as an array. If it's not already an
+ // array, store it as the only entry in one.
+ LLSD path;
+ if (rawPath.isArray())
+ {
+ path = rawPath;
+ }
+ else
+ {
+ path.append(rawPath);
+ }
+
+ // Need to indicate a current destination -- but that current destination
+ // needs to change as we step through the path array. Where normally we'd
+ // use an LLSD& to capture a subscripted LLSD lvalue, this time we must
+ // instead use a pointer -- since it must be reassigned.
+ LLSD* pdest = &dest;
+
+ // Now loop through that array
+ for (LLSD::Integer i = 0; i < path.size(); ++i)
+ {
+ if (path[i].isString())
+ {
+ // *pdest is an LLSD map
+ pdest = &((*pdest)[path[i].asString()]);
+ }
+ else if (path[i].isInteger())
+ {
+ // *pdest is an LLSD array
+ pdest = &((*pdest)[path[i].asInteger()]);
+ }
+ else
+ {
+ // What do we do with Real or Array or Map or ...?
+ // As it's a coder error -- not a user error -- rub the coder's
+ // face in it so it gets fixed.
+ LL_ERRS("lleventcoro") << "storeToLLSDPath(" << dest << ", " << rawPath << ", " << value
+ << "): path[" << i << "] bad type " << path[i].type() << LL_ENDL;
+ }
+ }
+
+ // Here *pdest is where we should store value.
+ *pdest = value;
+}
+
+LLSD errorException(const LLEventWithID& result, const std::string& desc)
+{
+ // If the result arrived on the error pump (pump 1), instead of
+ // returning it, deliver it via exception.
+ if (result.second)
+ {
+ throw LLErrorEvent(desc, result.first);
+ }
+ // That way, our caller knows a simple return must be from the reply
+ // pump (pump 0).
+ return result.first;
+}
+
+LLSD errorLog(const LLEventWithID& result, const std::string& desc)
+{
+ // If the result arrived on the error pump (pump 1), log it as a fatal
+ // error.
+ if (result.second)
+ {
+ LL_ERRS("errorLog") << desc << ":" << std::endl;
+ LLSDSerialize::toPrettyXML(result.first, LL_CONT);
+ LL_CONT << LL_ENDL;
+ }
+ // A simple return must therefore be from the reply pump (pump 0).
+ return result.first;
+}
diff --git a/indra/llcommon/lleventcoro.h b/indra/llcommon/lleventcoro.h
new file mode 100644
index 0000000000..88a5e6ec74
--- /dev/null
+++ b/indra/llcommon/lleventcoro.h
@@ -0,0 +1,569 @@
+/**
+ * @file lleventcoro.h
+ * @author Nat Goodspeed
+ * @date 2009-04-29
+ * @brief Utilities to interface between coroutines and events.
+ *
+ * $LicenseInfo:firstyear=2009&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_LLEVENTCORO_H)
+#define LL_LLEVENTCORO_H
+
+#include <boost/coroutine/coroutine.hpp>
+#include <boost/coroutine/future.hpp>
+#include <boost/optional.hpp>
+#include <string>
+#include <stdexcept>
+#include "llevents.h"
+#include "llerror.h"
+
+/**
+ * Like LLListenerOrPumpName, this is a class intended for parameter lists:
+ * accept a <tt>const LLEventPumpOrPumpName&</tt> and you can accept either an
+ * <tt>LLEventPump&</tt> or its string name. For a single parameter that could
+ * be either, it's not hard to overload the function -- but as soon as you
+ * want to accept two such parameters, this is cheaper than four overloads.
+ */
+class LLEventPumpOrPumpName
+{
+public:
+ /// Pass an actual LLEventPump&
+ LLEventPumpOrPumpName(LLEventPump& pump):
+ mPump(pump)
+ {}
+ /// Pass the string name of an LLEventPump
+ LLEventPumpOrPumpName(const std::string& pumpname):
+ mPump(LLEventPumps::instance().obtain(pumpname))
+ {}
+ /// Pass string constant name of an LLEventPump. This override must be
+ /// explicit, since otherwise passing <tt>const char*</tt> to a function
+ /// accepting <tt>const LLEventPumpOrPumpName&</tt> would require two
+ /// different implicit conversions: <tt>const char*</tt> -> <tt>const
+ /// std::string&</tt> -> <tt>const LLEventPumpOrPumpName&</tt>.
+ LLEventPumpOrPumpName(const char* pumpname):
+ mPump(LLEventPumps::instance().obtain(pumpname))
+ {}
+ /// Unspecified: "I choose not to identify an LLEventPump."
+ LLEventPumpOrPumpName() {}
+ operator LLEventPump& () const { return *mPump; }
+ LLEventPump& getPump() const { return *mPump; }
+ operator bool() const { return mPump; }
+ bool operator!() const { return ! mPump; }
+
+private:
+ boost::optional<LLEventPump&> mPump;
+};
+
+/// This is an adapter for a signature like void LISTENER(const LLSD&), which
+/// isn't a valid LLEventPump listener: such listeners should return bool.
+template <typename LISTENER>
+class LLVoidListener
+{
+public:
+ LLVoidListener(const LISTENER& listener):
+ mListener(listener)
+ {}
+ bool operator()(const LLSD& event)
+ {
+ mListener(event);
+ // don't swallow the event, let other listeners see it
+ return false;
+ }
+private:
+ LISTENER mListener;
+};
+
+/// LLVoidListener helper function to infer the type of the LISTENER
+template <typename LISTENER>
+LLVoidListener<LISTENER> voidlistener(const LISTENER& listener)
+{
+ return LLVoidListener<LISTENER>(listener);
+}
+
+namespace LLEventDetail
+{
+ /**
+ * waitForEventOn() permits a coroutine to temporarily listen on an
+ * LLEventPump any number of times. We don't really want to have to ask
+ * the caller to label each such call with a distinct string; the whole
+ * point of waitForEventOn() is to present a nice sequential interface to
+ * the underlying LLEventPump-with-named-listeners machinery. So we'll use
+ * LLEventPump::inventName() to generate a distinct name for each
+ * temporary listener. On the other hand, because a given coroutine might
+ * call waitForEventOn() any number of times, we don't really want to
+ * consume an arbitrary number of generated inventName()s: that namespace,
+ * though large, is nonetheless finite. So we memoize an invented name for
+ * each distinct coroutine instance (each different 'self' object). We
+ * can't know the type of 'self', because it depends on the coroutine
+ * body's signature. So we cast its address to void*, looking for distinct
+ * pointer values. Yes, that means that an early coroutine could cache a
+ * value here, then be destroyed, only to be supplanted by a later
+ * coroutine (of the same or different type), and we'll end up
+ * "recognizing" the second one and reusing the listener name -- but
+ * that's okay, since it won't collide with any listener name used by the
+ * earlier coroutine since that earlier coroutine no longer exists.
+ */
+ template <typename COROUTINE_SELF>
+ std::string listenerNameForCoro(COROUTINE_SELF& self)
+ {
+ return listenerNameForCoroImpl(self.get_id());
+ }
+
+ /// Implementation for listenerNameForCoro()
+ LL_COMMON_API std::string listenerNameForCoroImpl(const void* self_id);
+
+ /**
+ * Implement behavior described for postAndWait()'s @a replyPumpNamePath
+ * parameter:
+ *
+ * * If <tt>path.isUndefined()</tt>, do nothing.
+ * * If <tt>path.isString()</tt>, @a dest is an LLSD map: store @a value
+ * into <tt>dest[path.asString()]</tt>.
+ * * If <tt>path.isInteger()</tt>, @a dest is an LLSD array: store @a
+ * value into <tt>dest[path.asInteger()]</tt>.
+ * * If <tt>path.isArray()</tt>, iteratively apply the rules above to step
+ * down through the structure of @a dest. The last array entry in @a
+ * path specifies the entry in the lowest-level structure in @a dest
+ * into which to store @a value.
+ *
+ * @note
+ * In the degenerate case in which @a path is an empty array, @a dest will
+ * @em become @a value rather than @em containing it.
+ */
+ LL_COMMON_API void storeToLLSDPath(LLSD& dest, const LLSD& path, const LLSD& value);
+} // namespace LLEventDetail
+
+/**
+ * Post specified LLSD event on the specified LLEventPump, then wait for a
+ * response on specified other LLEventPump. This is more than mere
+ * convenience: the difference between this function and the sequence
+ * @code
+ * requestPump.post(myEvent);
+ * LLSD reply = waitForEventOn(self, replyPump);
+ * @endcode
+ * is that the sequence above fails if the reply is posted immediately on
+ * @a replyPump, that is, before <tt>requestPump.post()</tt> returns. In the
+ * sequence above, the running coroutine isn't even listening on @a replyPump
+ * until <tt>requestPump.post()</tt> returns and @c waitForEventOn() is
+ * entered. Therefore, the coroutine completely misses an immediate reply
+ * event, making it wait indefinitely.
+ *
+ * By contrast, postAndWait() listens on the @a replyPump @em before posting
+ * the specified LLSD event on the specified @a requestPump.
+ *
+ * @param self The @c self object passed into a coroutine
+ * @param event LLSD data to be posted on @a requestPump
+ * @param requestPump an LLEventPump on which to post @a event. Pass either
+ * the LLEventPump& or its string name. However, if you pass a
+ * default-constructed @c LLEventPumpOrPumpName, we skip the post() call.
+ * @param replyPump an LLEventPump on which postAndWait() will listen for a
+ * reply. Pass either the LLEventPump& or its string name. The calling
+ * coroutine will wait until that reply arrives. (If you're concerned about a
+ * reply that might not arrive, please see also LLEventTimeout.)
+ * @param replyPumpNamePath specifies the location within @a event in which to
+ * store <tt>replyPump.getName()</tt>. This is a strictly optional convenience
+ * feature; obviously you can store the name in @a event "by hand" if desired.
+ * @a replyPumpNamePath can be specified in any of four forms:
+ * * @c isUndefined() (default-constructed LLSD object): do nothing. This is
+ * the default behavior if you omit @a replyPumpNamePath.
+ * * @c isInteger(): @a event is an array. Store <tt>replyPump.getName()</tt>
+ * in <tt>event[replyPumpNamePath.asInteger()]</tt>.
+ * * @c isString(): @a event is a map. Store <tt>replyPump.getName()</tt> in
+ * <tt>event[replyPumpNamePath.asString()]</tt>.
+ * * @c isArray(): @a event has several levels of structure, e.g. map of
+ * maps, array of arrays, array of maps, map of arrays, ... Store
+ * <tt>replyPump.getName()</tt> in
+ * <tt>event[replyPumpNamePath[0]][replyPumpNamePath[1]]...</tt> In other
+ * words, examine each array entry in @a replyPumpNamePath in turn. If it's an
+ * <tt>LLSD::String</tt>, the current level of @a event is a map; step down to
+ * that map entry. If it's an <tt>LLSD::Integer</tt>, the current level of @a
+ * event is an array; step down to that array entry. The last array entry in
+ * @a replyPumpNamePath specifies the entry in the lowest-level structure in
+ * @a event into which to store <tt>replyPump.getName()</tt>.
+ */
+template <typename SELF>
+LLSD postAndWait(SELF& self, const LLSD& event, const LLEventPumpOrPumpName& requestPump,
+ const LLEventPumpOrPumpName& replyPump, const LLSD& replyPumpNamePath=LLSD())
+{
+ // declare the future
+ boost::coroutines::future<LLSD> future(self);
+ // make a callback that will assign a value to the future, and listen on
+ // the specified LLEventPump with that callback
+ std::string listenerName(LLEventDetail::listenerNameForCoro(self));
+ LLTempBoundListener connection(
+ replyPump.getPump().listen(listenerName,
+ voidlistener(boost::coroutines::make_callback(future))));
+ // skip the "post" part if requestPump is default-constructed
+ if (requestPump)
+ {
+ // If replyPumpNamePath is non-empty, store the replyPump name in the
+ // request event.
+ LLSD modevent(event);
+ LLEventDetail::storeToLLSDPath(modevent, replyPumpNamePath, replyPump.getPump().getName());
+ LL_DEBUGS("lleventcoro") << "postAndWait(): coroutine " << listenerName
+ << " posting to " << requestPump.getPump().getName()
+ << LL_ENDL;
+
+ // *NOTE:Mani - Removed because modevent could contain user's hashed passwd.
+ // << ": " << modevent << LL_ENDL;
+ requestPump.getPump().post(modevent);
+ }
+ LL_DEBUGS("lleventcoro") << "postAndWait(): coroutine " << listenerName
+ << " about to wait on LLEventPump " << replyPump.getPump().getName()
+ << LL_ENDL;
+ // trying to dereference ("resolve") the future makes us wait for it
+ LLSD value(*future);
+ LL_DEBUGS("lleventcoro") << "postAndWait(): coroutine " << listenerName
+ << " resuming with " << value << LL_ENDL;
+ // returning should disconnect the connection
+ return value;
+}
+
+/// Wait for the next event on the specified LLEventPump. Pass either the
+/// LLEventPump& or its string name.
+template <typename SELF>
+LLSD waitForEventOn(SELF& self, const LLEventPumpOrPumpName& pump)
+{
+ // This is now a convenience wrapper for postAndWait().
+ return postAndWait(self, LLSD(), LLEventPumpOrPumpName(), pump);
+}
+
+/// return type for two-pump variant of waitForEventOn()
+typedef std::pair<LLSD, int> LLEventWithID;
+
+namespace LLEventDetail
+{
+ /**
+ * This helper is specifically for the two-pump version of waitForEventOn().
+ * We use a single future object, but we want to listen on two pumps with it.
+ * Since we must still adapt from (the callable constructed by)
+ * boost::coroutines::make_callback() (void return) to provide an event
+ * listener (bool return), we've adapted LLVoidListener for the purpose. The
+ * basic idea is that we construct a distinct instance of WaitForEventOnHelper
+ * -- binding different instance data -- for each of the pumps. Then, when a
+ * pump delivers an LLSD value to either WaitForEventOnHelper, it can combine
+ * that LLSD with its discriminator to feed the future object.
+ */
+ template <typename LISTENER>
+ class WaitForEventOnHelper
+ {
+ public:
+ WaitForEventOnHelper(const LISTENER& listener, int discriminator):
+ mListener(listener),
+ mDiscrim(discriminator)
+ {}
+ // this signature is required for an LLEventPump listener
+ bool operator()(const LLSD& event)
+ {
+ // our future object is defined to accept LLEventWithID
+ mListener(LLEventWithID(event, mDiscrim));
+ // don't swallow the event, let other listeners see it
+ return false;
+ }
+ private:
+ LISTENER mListener;
+ const int mDiscrim;
+ };
+
+ /// WaitForEventOnHelper type-inference helper
+ template <typename LISTENER>
+ WaitForEventOnHelper<LISTENER> wfeoh(const LISTENER& listener, int discriminator)
+ {
+ return WaitForEventOnHelper<LISTENER>(listener, discriminator);
+ }
+} // namespace LLEventDetail
+
+/**
+ * This function waits for a reply on either of two specified LLEventPumps.
+ * Otherwise, it closely resembles postAndWait(); please see the documentation
+ * for that function for detailed parameter info.
+ *
+ * While we could have implemented the single-pump variant in terms of this
+ * one, there's enough added complexity here to make it worthwhile to give the
+ * single-pump variant its own straightforward implementation. Conversely,
+ * though we could use preprocessor logic to generate n-pump overloads up to
+ * BOOST_COROUTINE_WAIT_MAX, we don't foresee a use case. This two-pump
+ * overload exists because certain event APIs are defined in terms of a reply
+ * LLEventPump and an error LLEventPump.
+ *
+ * The LLEventWithID return value provides not only the received event, but
+ * the index of the pump on which it arrived (0 or 1).
+ *
+ * @note
+ * I'd have preferred to overload the name postAndWait() for both signatures.
+ * But consider the following ambiguous call:
+ * @code
+ * postAndWait(self, LLSD(), requestPump, replyPump, "someString");
+ * @endcode
+ * "someString" could be converted to either LLSD (@a replyPumpNamePath for
+ * the single-pump function) or LLEventOrPumpName (@a replyPump1 for two-pump
+ * function).
+ *
+ * It seems less burdensome to write postAndWait2() than to write either
+ * LLSD("someString") or LLEventOrPumpName("someString").
+ */
+template <typename SELF>
+LLEventWithID postAndWait2(SELF& self, const LLSD& event,
+ const LLEventPumpOrPumpName& requestPump,
+ const LLEventPumpOrPumpName& replyPump0,
+ const LLEventPumpOrPumpName& replyPump1,
+ const LLSD& replyPump0NamePath=LLSD(),
+ const LLSD& replyPump1NamePath=LLSD())
+{
+ // declare the future
+ boost::coroutines::future<LLEventWithID> future(self);
+ // either callback will assign a value to this future; listen on
+ // each specified LLEventPump with a callback
+ std::string name(LLEventDetail::listenerNameForCoro(self));
+ LLTempBoundListener connection0(
+ replyPump0.getPump().listen(name + "a",
+ LLEventDetail::wfeoh(boost::coroutines::make_callback(future), 0)));
+ LLTempBoundListener connection1(
+ replyPump1.getPump().listen(name + "b",
+ LLEventDetail::wfeoh(boost::coroutines::make_callback(future), 1)));
+ // skip the "post" part if requestPump is default-constructed
+ if (requestPump)
+ {
+ // If either replyPumpNamePath is non-empty, store the corresponding
+ // replyPump name in the request event.
+ LLSD modevent(event);
+ LLEventDetail::storeToLLSDPath(modevent, replyPump0NamePath,
+ replyPump0.getPump().getName());
+ LLEventDetail::storeToLLSDPath(modevent, replyPump1NamePath,
+ replyPump1.getPump().getName());
+ LL_DEBUGS("lleventcoro") << "postAndWait2(): coroutine " << name
+ << " posting to " << requestPump.getPump().getName()
+ << ": " << modevent << LL_ENDL;
+ requestPump.getPump().post(modevent);
+ }
+ LL_DEBUGS("lleventcoro") << "postAndWait2(): coroutine " << name
+ << " about to wait on LLEventPumps " << replyPump0.getPump().getName()
+ << ", " << replyPump1.getPump().getName() << LL_ENDL;
+ // trying to dereference ("resolve") the future makes us wait for it
+ LLEventWithID value(*future);
+ LL_DEBUGS("lleventcoro") << "postAndWait(): coroutine " << name
+ << " resuming with (" << value.first << ", " << value.second << ")"
+ << LL_ENDL;
+ // returning should disconnect both connections
+ return value;
+}
+
+/**
+ * Wait for the next event on either of two specified LLEventPumps.
+ */
+template <typename SELF>
+LLEventWithID
+waitForEventOn(SELF& self,
+ const LLEventPumpOrPumpName& pump0, const LLEventPumpOrPumpName& pump1)
+{
+ // This is now a convenience wrapper for postAndWait2().
+ return postAndWait2(self, LLSD(), LLEventPumpOrPumpName(), pump0, pump1);
+}
+
+/**
+ * Helper for the two-pump variant of waitForEventOn(), e.g.:
+ *
+ * @code
+ * LLSD reply = errorException(waitForEventOn(self, replyPump, errorPump),
+ * "error response from login.cgi");
+ * @endcode
+ *
+ * Examines an LLEventWithID, assuming that the second pump (pump 1) is
+ * listening for an error indication. If the incoming data arrived on pump 1,
+ * throw an LLErrorEvent exception. If the incoming data arrived on pump 0,
+ * just return it. Since a normal return can only be from pump 0, we no longer
+ * need the LLEventWithID's discriminator int; we can just return the LLSD.
+ *
+ * @note I'm not worried about introducing the (fairly generic) name
+ * errorException() into global namespace, because how many other overloads of
+ * the same name are going to accept an LLEventWithID parameter?
+ */
+LLSD errorException(const LLEventWithID& result, const std::string& desc);
+
+/**
+ * Exception thrown by errorException(). We don't call this LLEventError
+ * because it's not an error in event processing: rather, this exception
+ * announces an event that bears error information (for some other API).
+ */
+class LL_COMMON_API LLErrorEvent: public std::runtime_error
+{
+public:
+ LLErrorEvent(const std::string& what, const LLSD& data):
+ std::runtime_error(what),
+ mData(data)
+ {}
+ virtual ~LLErrorEvent() throw() {}
+
+ LLSD getData() const { return mData; }
+
+private:
+ LLSD mData;
+};
+
+/**
+ * Like errorException(), save that this trips a fatal error using LL_ERRS
+ * rather than throwing an exception.
+ */
+LL_COMMON_API LLSD errorLog(const LLEventWithID& result, const std::string& desc);
+
+/**
+ * Certain event APIs require the name of an LLEventPump on which they should
+ * post results. While it works to invent a distinct name and let
+ * LLEventPumps::obtain() instantiate the LLEventPump as a "named singleton,"
+ * in a certain sense it's more robust to instantiate a local LLEventPump and
+ * provide its name instead. This class packages the following idiom:
+ *
+ * 1. Instantiate a local LLCoroEventPump, with an optional name prefix.
+ * 2. Provide its actual name to the event API in question as the name of the
+ * reply LLEventPump.
+ * 3. Initiate the request to the event API.
+ * 4. Call your LLEventTempStream's wait() method to wait for the reply.
+ * 5. Let the LLCoroEventPump go out of scope.
+ */
+class LL_COMMON_API LLCoroEventPump
+{
+public:
+ LLCoroEventPump(const std::string& name="coro"):
+ mPump(name, true) // allow tweaking the pump instance name
+ {}
+ /// It's typical to request the LLEventPump name to direct an event API to
+ /// send its response to this pump.
+ std::string getName() const { return mPump.getName(); }
+ /// Less typically, we'd request the pump itself for some reason.
+ LLEventPump& getPump() { return mPump; }
+
+ /**
+ * Wait for an event on this LLEventPump.
+ *
+ * @note
+ * The other major usage pattern we considered was to bind @c self at
+ * LLCoroEventPump construction time, which would avoid passing the
+ * parameter to each wait() call. But if we were going to bind @c self as
+ * a class member, we'd need to specify a class template parameter
+ * indicating its type. The big advantage of passing it to the wait() call
+ * is that the type can be implicit.
+ */
+ template <typename SELF>
+ LLSD wait(SELF& self)
+ {
+ return waitForEventOn(self, mPump);
+ }
+
+ template <typename SELF>
+ LLSD postAndWait(SELF& self, const LLSD& event, const LLEventPumpOrPumpName& requestPump,
+ const LLSD& replyPumpNamePath=LLSD())
+ {
+ return ::postAndWait(self, event, requestPump, mPump, replyPumpNamePath);
+ }
+
+private:
+ LLEventStream mPump;
+};
+
+/**
+ * Other event APIs require the names of two different LLEventPumps: one for
+ * success response, the other for error response. Extend LLCoroEventPump
+ * for the two-pump use case.
+ */
+class LL_COMMON_API LLCoroEventPumps
+{
+public:
+ LLCoroEventPumps(const std::string& name="coro",
+ const std::string& suff0="Reply",
+ const std::string& suff1="Error"):
+ mPump0(name + suff0, true), // allow tweaking the pump instance name
+ mPump1(name + suff1, true)
+ {}
+ /// request pump 0's name
+ std::string getName0() const { return mPump0.getName(); }
+ /// request pump 1's name
+ std::string getName1() const { return mPump1.getName(); }
+ /// request both names
+ std::pair<std::string, std::string> getNames() const
+ {
+ return std::pair<std::string, std::string>(mPump0.getName(), mPump1.getName());
+ }
+
+ /// request pump 0
+ LLEventPump& getPump0() { return mPump0; }
+ /// request pump 1
+ LLEventPump& getPump1() { return mPump1; }
+
+ /// waitForEventOn(self, either of our two LLEventPumps)
+ template <typename SELF>
+ LLEventWithID wait(SELF& self)
+ {
+ return waitForEventOn(self, mPump0, mPump1);
+ }
+
+ /// errorException(wait(self))
+ template <typename SELF>
+ LLSD waitWithException(SELF& self)
+ {
+ return errorException(wait(self), std::string("Error event on ") + getName1());
+ }
+
+ /// errorLog(wait(self))
+ template <typename SELF>
+ LLSD waitWithLog(SELF& self)
+ {
+ return errorLog(wait(self), std::string("Error event on ") + getName1());
+ }
+
+ template <typename SELF>
+ LLEventWithID postAndWait(SELF& self, const LLSD& event,
+ const LLEventPumpOrPumpName& requestPump,
+ const LLSD& replyPump0NamePath=LLSD(),
+ const LLSD& replyPump1NamePath=LLSD())
+ {
+ return postAndWait2(self, event, requestPump, mPump0, mPump1,
+ replyPump0NamePath, replyPump1NamePath);
+ }
+
+ template <typename SELF>
+ LLSD postAndWaitWithException(SELF& self, const LLSD& event,
+ const LLEventPumpOrPumpName& requestPump,
+ const LLSD& replyPump0NamePath=LLSD(),
+ const LLSD& replyPump1NamePath=LLSD())
+ {
+ return errorException(postAndWait(self, event, requestPump,
+ replyPump0NamePath, replyPump1NamePath),
+ std::string("Error event on ") + getName1());
+ }
+
+ template <typename SELF>
+ LLSD postAndWaitWithLog(SELF& self, const LLSD& event,
+ const LLEventPumpOrPumpName& requestPump,
+ const LLSD& replyPump0NamePath=LLSD(),
+ const LLSD& replyPump1NamePath=LLSD())
+ {
+ return errorLog(postAndWait(self, event, requestPump,
+ replyPump0NamePath, replyPump1NamePath),
+ std::string("Error event on ") + getName1());
+ }
+
+private:
+ LLEventStream mPump0, mPump1;
+};
+
+#endif /* ! defined(LL_LLEVENTCORO_H) */
diff --git a/indra/llcommon/lleventdispatcher.cpp b/indra/llcommon/lleventdispatcher.cpp
new file mode 100644
index 0000000000..d6e820d793
--- /dev/null
+++ b/indra/llcommon/lleventdispatcher.cpp
@@ -0,0 +1,166 @@
+/**
+ * @file lleventdispatcher.cpp
+ * @author Nat Goodspeed
+ * @date 2009-06-18
+ * @brief Implementation for lleventdispatcher.
+ *
+ * $LicenseInfo:firstyear=2009&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 LL_WINDOWS
+#pragma warning (disable : 4355) // 'this' used in initializer list: yes, intentionally
+#endif
+
+// Precompiled header
+#include "linden_common.h"
+// associated header
+#include "lleventdispatcher.h"
+// STL headers
+// std headers
+// external library headers
+// other Linden headers
+#include "llevents.h"
+#include "llerror.h"
+#include "llsdutil.h"
+
+LLEventDispatcher::LLEventDispatcher(const std::string& desc, const std::string& key):
+ mDesc(desc),
+ mKey(key)
+{
+}
+
+LLEventDispatcher::~LLEventDispatcher()
+{
+}
+
+/// Register a callable by name
+void LLEventDispatcher::add(const std::string& name, const std::string& desc,
+ const Callable& callable, const LLSD& required)
+{
+ mDispatch.insert(DispatchMap::value_type(name,
+ DispatchMap::mapped_type(callable, desc, required)));
+}
+
+void LLEventDispatcher::addFail(const std::string& name, const std::string& classname) const
+{
+ LL_ERRS("LLEventDispatcher") << "LLEventDispatcher(" << mDesc << ")::add(" << name
+ << "): " << classname << " is not a subclass "
+ << "of LLEventDispatcher" << LL_ENDL;
+}
+
+/// Unregister a callable
+bool LLEventDispatcher::remove(const std::string& name)
+{
+ DispatchMap::iterator found = mDispatch.find(name);
+ if (found == mDispatch.end())
+ {
+ return false;
+ }
+ mDispatch.erase(found);
+ return true;
+}
+
+/// Call a registered callable with an explicitly-specified name. If no
+/// such callable exists, die with LL_ERRS.
+void LLEventDispatcher::operator()(const std::string& name, const LLSD& event) const
+{
+ if (! attemptCall(name, event))
+ {
+ LL_ERRS("LLEventDispatcher") << "LLEventDispatcher(" << mDesc << "): '" << name
+ << "' not found" << LL_ENDL;
+ }
+}
+
+/// Extract the @a key value from the incoming @a event, and call the
+/// callable whose name is specified by that map @a key. If no such
+/// callable exists, die with LL_ERRS.
+void LLEventDispatcher::operator()(const LLSD& event) const
+{
+ // This could/should be implemented in terms of the two-arg overload.
+ // However -- we can produce a more informative error message.
+ std::string name(event[mKey]);
+ if (! attemptCall(name, event))
+ {
+ LL_ERRS("LLEventDispatcher") << "LLEventDispatcher(" << mDesc << "): bad " << mKey
+ << " value '" << name << "'" << LL_ENDL;
+ }
+}
+
+bool LLEventDispatcher::attemptCall(const std::string& name, const LLSD& event) const
+{
+ DispatchMap::const_iterator found = mDispatch.find(name);
+ if (found == mDispatch.end())
+ {
+ // The reason we only return false, leaving it up to our caller to die
+ // with LL_ERRS, is that different callers have different amounts of
+ // available information.
+ return false;
+ }
+ // Found the name, so it's plausible to even attempt the call. But first,
+ // validate the syntax of the event itself.
+ std::string mismatch(llsd_matches(found->second.mRequired, event));
+ if (! mismatch.empty())
+ {
+ LL_ERRS("LLEventDispatcher") << "LLEventDispatcher(" << mDesc << ") calling '" << name
+ << "': bad request: " << mismatch << LL_ENDL;
+ }
+ // Event syntax looks good, go for it!
+ (found->second.mFunc)(event);
+ return true; // tell caller we were able to call
+}
+
+LLEventDispatcher::Callable LLEventDispatcher::get(const std::string& name) const
+{
+ DispatchMap::const_iterator found = mDispatch.find(name);
+ if (found == mDispatch.end())
+ {
+ return Callable();
+ }
+ return found->second.mFunc;
+}
+
+LLSD LLEventDispatcher::getMetadata(const std::string& name) const
+{
+ DispatchMap::const_iterator found = mDispatch.find(name);
+ if (found == mDispatch.end())
+ {
+ return LLSD();
+ }
+ LLSD meta;
+ meta["name"] = name;
+ meta["desc"] = found->second.mDesc;
+ meta["required"] = found->second.mRequired;
+ return meta;
+}
+
+LLDispatchListener::LLDispatchListener(const std::string& pumpname, const std::string& key):
+ LLEventDispatcher(pumpname, key),
+ mPump(pumpname, true), // allow tweaking for uniqueness
+ mBoundListener(mPump.listen("self", boost::bind(&LLDispatchListener::process, this, _1)))
+{
+}
+
+bool LLDispatchListener::process(const LLSD& event)
+{
+ (*this)(event);
+ return false;
+}
diff --git a/indra/llcommon/lleventdispatcher.h b/indra/llcommon/lleventdispatcher.h
new file mode 100644
index 0000000000..dfffd59eb6
--- /dev/null
+++ b/indra/llcommon/lleventdispatcher.h
@@ -0,0 +1,210 @@
+/**
+ * @file lleventdispatcher.h
+ * @author Nat Goodspeed
+ * @date 2009-06-18
+ * @brief Central mechanism for dispatching events by string name. This is
+ * useful when you have a single LLEventPump listener on which you can
+ * request different operations, vs. instantiating a different
+ * LLEventPump for each such operation.
+ *
+ * $LicenseInfo:firstyear=2009&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_LLEVENTDISPATCHER_H)
+#define LL_LLEVENTDISPATCHER_H
+
+#include <string>
+#include <map>
+#include <boost/function.hpp>
+#include <boost/bind.hpp>
+#include <boost/iterator/transform_iterator.hpp>
+#include <typeinfo>
+#include "llevents.h"
+
+class LLSD;
+
+/**
+ * Given an LLSD map, examine a string-valued key and call a corresponding
+ * callable. This class is designed to be contained by an LLEventPump
+ * listener class that will register some of its own methods, though any
+ * callable can be used.
+ */
+class LL_COMMON_API LLEventDispatcher
+{
+public:
+ LLEventDispatcher(const std::string& desc, const std::string& key);
+ virtual ~LLEventDispatcher();
+
+ /// Accept any C++ callable, typically a boost::bind() expression
+ typedef boost::function<void(const LLSD&)> Callable;
+
+ /**
+ * Register a @a callable by @a name. The optional @a required parameter
+ * is used to validate the structure of each incoming event (see
+ * llsd_matches()).
+ */
+ void add(const std::string& name,
+ const std::string& desc,
+ const Callable& callable,
+ const LLSD& required=LLSD());
+
+ /**
+ * Special case: a subclass of this class can pass an unbound member
+ * function pointer without explicitly specifying the
+ * <tt>boost::bind()</tt> expression.
+ */
+ template <class CLASS>
+ void add(const std::string& name,
+ const std::string& desc,
+ void (CLASS::*method)(const LLSD&),
+ const LLSD& required=LLSD())
+ {
+ addMethod<CLASS>(name, desc, method, required);
+ }
+
+ /// Overload for both const and non-const methods
+ template <class CLASS>
+ void add(const std::string& name,
+ const std::string& desc,
+ void (CLASS::*method)(const LLSD&) const,
+ const LLSD& required=LLSD())
+ {
+ addMethod<CLASS>(name, desc, method, required);
+ }
+
+ /// Convenience: for LLEventDispatcher, not every callable needs a
+ /// documentation string.
+ template <typename CALLABLE>
+ void add(const std::string& name,
+ CALLABLE callable,
+ const LLSD& required=LLSD())
+ {
+ add(name, "", callable, required);
+ }
+
+ /// Unregister a callable
+ bool remove(const std::string& name);
+
+ /// Call a registered callable with an explicitly-specified name. If no
+ /// such callable exists, die with LL_ERRS. If the @a event fails to match
+ /// the @a required prototype specified at add() time, die with LL_ERRS.
+ void operator()(const std::string& name, const LLSD& event) const;
+
+ /// Extract the @a key value from the incoming @a event, and call the
+ /// callable whose name is specified by that map @a key. If no such
+ /// callable exists, die with LL_ERRS. If the @a event fails to match the
+ /// @a required prototype specified at add() time, die with LL_ERRS.
+ void operator()(const LLSD& event) const;
+
+ /// @name Iterate over defined names
+ //@{
+ typedef std::pair<std::string, std::string> NameDesc;
+
+private:
+ struct DispatchEntry
+ {
+ DispatchEntry(const Callable& func, const std::string& desc, const LLSD& required):
+ mFunc(func),
+ mDesc(desc),
+ mRequired(required)
+ {}
+ Callable mFunc;
+ std::string mDesc;
+ LLSD mRequired;
+ };
+ typedef std::map<std::string, DispatchEntry> DispatchMap;
+
+public:
+ /// We want the flexibility to redefine what data we store per name,
+ /// therefore our public interface doesn't expose DispatchMap iterators,
+ /// or DispatchMap itself, or DispatchEntry. Instead we explicitly
+ /// transform each DispatchMap item to NameDesc on dereferencing.
+ typedef boost::transform_iterator<NameDesc(*)(const DispatchMap::value_type&), DispatchMap::const_iterator> const_iterator;
+ const_iterator begin() const
+ {
+ return boost::make_transform_iterator(mDispatch.begin(), makeNameDesc);
+ }
+ const_iterator end() const
+ {
+ return boost::make_transform_iterator(mDispatch.end(), makeNameDesc);
+ }
+ //@}
+
+ /// Fetch the Callable for the specified name. If no such name was
+ /// registered, return an empty() Callable.
+ Callable get(const std::string& name) const;
+
+ /// Get information about a specific Callable
+ LLSD getMetadata(const std::string& name) const;
+
+ /// Retrieve the LLSD key we use for one-arg <tt>operator()</tt> method
+ std::string getDispatchKey() const { return mKey; }
+
+private:
+ template <class CLASS, typename METHOD>
+ void addMethod(const std::string& name, const std::string& desc,
+ const METHOD& method, const LLSD& required)
+ {
+ CLASS* downcast = dynamic_cast<CLASS*>(this);
+ if (! downcast)
+ {
+ addFail(name, typeid(CLASS).name());
+ }
+ else
+ {
+ add(name, desc, boost::bind(method, downcast, _1), required);
+ }
+ }
+ void addFail(const std::string& name, const std::string& classname) const;
+ /// try to dispatch, return @c true if success
+ bool attemptCall(const std::string& name, const LLSD& event) const;
+
+ std::string mDesc, mKey;
+ DispatchMap mDispatch;
+
+ static NameDesc makeNameDesc(const DispatchMap::value_type& item)
+ {
+ return NameDesc(item.first, item.second.mDesc);
+ }
+};
+
+/**
+ * Bundle an LLEventPump and a listener with an LLEventDispatcher. A class
+ * that contains (or derives from) LLDispatchListener need only specify the
+ * LLEventPump name and dispatch key, and add() its methods. Incoming events
+ * will automatically be dispatched.
+ */
+class LL_COMMON_API LLDispatchListener: public LLEventDispatcher
+{
+public:
+ LLDispatchListener(const std::string& pumpname, const std::string& key);
+
+ std::string getPumpName() const { return mPump.getName(); }
+
+private:
+ bool process(const LLSD& event);
+
+ LLEventStream mPump;
+ LLTempBoundListener mBoundListener;
+};
+
+#endif /* ! defined(LL_LLEVENTDISPATCHER_H) */
diff --git a/indra/llcommon/lleventemitter.h b/indra/llcommon/lleventemitter.h
index 4129dab1a1..cd82fc56f9 100644
--- a/indra/llcommon/lleventemitter.h
+++ b/indra/llcommon/lleventemitter.h
@@ -2,30 +2,25 @@
* @file lleventemitter.h
* @brief General event emitter class
*
- * $LicenseInfo:firstyear=2005&license=viewergpl$
- *
- * Copyright (c) 2005-2007, Linden Research, Inc.
- *
+ * $LicenseInfo:firstyear=2005&license=viewerlgpl$
* Second Life Viewer Source Code
- * The source code in this file ("Source Code") is provided by Linden Lab
- * to you under the terms of the GNU General Public License, version 2.0
- * ("GPL"), unless you have obtained a separate licensing agreement
- * ("Other License"), formally executed by you and Linden Lab. Terms of
- * the GPL can be found in doc/GPL-license.txt in this distribution, or
- * online at http://secondlife.com/developers/opensource/gplv2
+ * 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.
*
- * There are special exceptions to the terms and conditions of the GPL as
- * it is applied to this Source Code. View the full text of the exception
- * in the file doc/FLOSS-exception.txt in this software distribution, or
- * online at http://secondlife.com/developers/opensource/flossexception
+ * 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.
*
- * By copying, modifying or distributing this software, you acknowledge
- * that you have read and understood your obligations described above,
- * and agree to abide by those obligations.
+ * 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
*
- * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
- * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
- * COMPLETENESS OR PERFORMANCE.
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
* $/LicenseInfo$
*/
diff --git a/indra/llcommon/lleventfilter.cpp b/indra/llcommon/lleventfilter.cpp
new file mode 100644
index 0000000000..d36a107254
--- /dev/null
+++ b/indra/llcommon/lleventfilter.cpp
@@ -0,0 +1,166 @@
+/**
+ * @file lleventfilter.cpp
+ * @author Nat Goodspeed
+ * @date 2009-03-05
+ * @brief Implementation for lleventfilter.
+ *
+ * $LicenseInfo:firstyear=2009&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$
+ */
+
+// Precompiled header
+#include "linden_common.h"
+// associated header
+#include "lleventfilter.h"
+// STL headers
+// std headers
+// external library headers
+#include <boost/bind.hpp>
+// other Linden headers
+#include "llerror.h" // LL_ERRS
+#include "llsdutil.h" // llsd_matches()
+
+LLEventFilter::LLEventFilter(LLEventPump& source, const std::string& name, bool tweak):
+ LLEventStream(name, tweak)
+{
+ source.listen(getName(), boost::bind(&LLEventFilter::post, this, _1));
+}
+
+LLEventMatching::LLEventMatching(const LLSD& pattern):
+ LLEventFilter("matching"),
+ mPattern(pattern)
+{
+}
+
+LLEventMatching::LLEventMatching(LLEventPump& source, const LLSD& pattern):
+ LLEventFilter(source, "matching"),
+ mPattern(pattern)
+{
+}
+
+bool LLEventMatching::post(const LLSD& event)
+{
+ if (! llsd_matches(mPattern, event).empty())
+ return false;
+
+ return LLEventStream::post(event);
+}
+
+LLEventTimeoutBase::LLEventTimeoutBase():
+ LLEventFilter("timeout")
+{
+}
+
+LLEventTimeoutBase::LLEventTimeoutBase(LLEventPump& source):
+ LLEventFilter(source, "timeout")
+{
+}
+
+void LLEventTimeoutBase::actionAfter(F32 seconds, const Action& action)
+{
+ setCountdown(seconds);
+ mAction = action;
+ if (! mMainloop.connected())
+ {
+ LLEventPump& mainloop(LLEventPumps::instance().obtain("mainloop"));
+ mMainloop = mainloop.listen(getName(), boost::bind(&LLEventTimeoutBase::tick, this, _1));
+ }
+}
+
+class ErrorAfter
+{
+public:
+ ErrorAfter(const std::string& message): mMessage(message) {}
+
+ void operator()()
+ {
+ LL_ERRS("LLEventTimeout") << mMessage << LL_ENDL;
+ }
+
+private:
+ std::string mMessage;
+};
+
+void LLEventTimeoutBase::errorAfter(F32 seconds, const std::string& message)
+{
+ actionAfter(seconds, ErrorAfter(message));
+}
+
+class EventAfter
+{
+public:
+ EventAfter(LLEventPump& pump, const LLSD& event):
+ mPump(pump),
+ mEvent(event)
+ {}
+
+ void operator()()
+ {
+ mPump.post(mEvent);
+ }
+
+private:
+ LLEventPump& mPump;
+ LLSD mEvent;
+};
+
+void LLEventTimeoutBase::eventAfter(F32 seconds, const LLSD& event)
+{
+ actionAfter(seconds, EventAfter(*this, event));
+}
+
+bool LLEventTimeoutBase::post(const LLSD& event)
+{
+ cancel();
+ return LLEventStream::post(event);
+}
+
+void LLEventTimeoutBase::cancel()
+{
+ mMainloop.disconnect();
+}
+
+bool LLEventTimeoutBase::tick(const LLSD&)
+{
+ if (countdownElapsed())
+ {
+ cancel();
+ mAction();
+ }
+ return false; // show event to other listeners
+}
+
+LLEventTimeout::LLEventTimeout() {}
+
+LLEventTimeout::LLEventTimeout(LLEventPump& source):
+ LLEventTimeoutBase(source)
+{
+}
+
+void LLEventTimeout::setCountdown(F32 seconds)
+{
+ mTimer.setTimerExpirySec(seconds);
+}
+
+bool LLEventTimeout::countdownElapsed() const
+{
+ return mTimer.hasExpired();
+}
diff --git a/indra/llcommon/lleventfilter.h b/indra/llcommon/lleventfilter.h
new file mode 100644
index 0000000000..e822a664f5
--- /dev/null
+++ b/indra/llcommon/lleventfilter.h
@@ -0,0 +1,203 @@
+/**
+ * @file lleventfilter.h
+ * @author Nat Goodspeed
+ * @date 2009-03-05
+ * @brief Define LLEventFilter: LLEventStream subclass with conditions
+ *
+ * $LicenseInfo:firstyear=2009&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_LLEVENTFILTER_H)
+#define LL_LLEVENTFILTER_H
+
+#include "llevents.h"
+#include "stdtypes.h"
+#include "lltimer.h"
+#include <boost/function.hpp>
+
+/**
+ * Generic base class
+ */
+class LL_COMMON_API LLEventFilter: public LLEventStream
+{
+public:
+ /// construct a standalone LLEventFilter
+ LLEventFilter(const std::string& name="filter", bool tweak=true):
+ LLEventStream(name, tweak)
+ {}
+ /// construct LLEventFilter and connect it to the specified LLEventPump
+ LLEventFilter(LLEventPump& source, const std::string& name="filter", bool tweak=true);
+
+ /// Post an event to all listeners
+ virtual bool post(const LLSD& event) = 0;
+};
+
+/**
+ * Pass through only events matching a specified pattern
+ */
+class LLEventMatching: public LLEventFilter
+{
+public:
+ /// Pass an LLSD map with keys and values the incoming event must match
+ LLEventMatching(const LLSD& pattern);
+ /// instantiate and connect
+ LLEventMatching(LLEventPump& source, const LLSD& pattern);
+
+ /// Only pass through events matching the pattern
+ virtual bool post(const LLSD& event);
+
+private:
+ LLSD mPattern;
+};
+
+/**
+ * Wait for an event to be posted. If no such event arrives within a specified
+ * time, take a specified action. See LLEventTimeout for production
+ * implementation.
+ *
+ * @NOTE This is an abstract base class so that, for testing, we can use an
+ * alternate "timer" that doesn't actually consume real time.
+ */
+class LL_COMMON_API LLEventTimeoutBase: public LLEventFilter
+{
+public:
+ /// construct standalone
+ LLEventTimeoutBase();
+ /// construct and connect
+ LLEventTimeoutBase(LLEventPump& source);
+
+ /// Callable, can be constructed with boost::bind()
+ typedef boost::function<void()> Action;
+
+ /**
+ * Start countdown timer for the specified number of @a seconds. Forward
+ * all events. If any event arrives before timer expires, cancel timer. If
+ * no event arrives before timer expires, take specified @a action.
+ *
+ * This is a one-shot timer. Once it has either expired or been canceled,
+ * it is inert until another call to actionAfter().
+ *
+ * Calling actionAfter() while an existing timer is running cheaply
+ * replaces that original timer. Thus, a valid use case is to detect
+ * idleness of some event source by calling actionAfter() on each new
+ * event. A rapid sequence of events will keep the timer from expiring;
+ * the first gap in events longer than the specified timer will fire the
+ * specified Action.
+ *
+ * Any post() call cancels the timer. To be satisfied with only a
+ * particular event, chain on an LLEventMatching that only passes such
+ * events:
+ *
+ * @code
+ * event ultimate
+ * source ---> LLEventMatching ---> LLEventTimeout ---> listener
+ * @endcode
+ *
+ * @NOTE
+ * The implementation relies on frequent events on the LLEventPump named
+ * "mainloop".
+ */
+ void actionAfter(F32 seconds, const Action& action);
+
+ /**
+ * Like actionAfter(), but where the desired Action is LL_ERRS
+ * termination. Pass the timeout time and the desired LL_ERRS @a message.
+ *
+ * This method is useful when, for instance, some async API guarantees an
+ * event, whether success or failure, within a stated time window.
+ * Instantiate an LLEventTimeout listening to that API and call
+ * errorAfter() on each async request with a timeout comfortably longer
+ * than the API's time guarantee (much longer than the anticipated
+ * "mainloop" granularity).
+ *
+ * Then if the async API breaks its promise, the program terminates with
+ * the specified LL_ERRS @a message. The client of the async API can
+ * therefore assume the guarantee is upheld.
+ *
+ * @NOTE
+ * errorAfter() is implemented in terms of actionAfter(), so all remarks
+ * about calling actionAfter() also apply to errorAfter().
+ */
+ void errorAfter(F32 seconds, const std::string& message);
+
+ /**
+ * Like actionAfter(), but where the desired Action is a particular event
+ * for all listeners. Pass the timeout time and the desired @a event data.
+ *
+ * Suppose the timeout should only be satisfied by a particular event, but
+ * the ultimate listener must see all other incoming events as well, plus
+ * the timeout @a event if any:
+ *
+ * @code
+ * some LLEventMatching LLEventMatching
+ * event ---> for particular ---> LLEventTimeout ---> for timeout
+ * source event event \
+ * \ \ ultimate
+ * `-----------------------------------------------------> listener
+ * @endcode
+ *
+ * Since a given listener can listen on more than one LLEventPump, we can
+ * set things up so it sees the set union of events from LLEventTimeout
+ * and the original event source. However, as LLEventTimeout passes
+ * through all incoming events, the "particular event" that satisfies the
+ * left LLEventMatching would reach the ultimate listener twice. So we add
+ * an LLEventMatching that only passes timeout events.
+ *
+ * @NOTE
+ * eventAfter() is implemented in terms of actionAfter(), so all remarks
+ * about calling actionAfter() also apply to eventAfter().
+ */
+ void eventAfter(F32 seconds, const LLSD& event);
+
+ /// Pass event through, canceling the countdown timer
+ virtual bool post(const LLSD& event);
+
+ /// Cancel timer without event
+ void cancel();
+
+protected:
+ virtual void setCountdown(F32 seconds) = 0;
+ virtual bool countdownElapsed() const = 0;
+
+private:
+ bool tick(const LLSD&);
+
+ LLBoundListener mMainloop;
+ Action mAction;
+};
+
+/// Production implementation of LLEventTimoutBase
+class LL_COMMON_API LLEventTimeout: public LLEventTimeoutBase
+{
+public:
+ LLEventTimeout();
+ LLEventTimeout(LLEventPump& source);
+
+protected:
+ virtual void setCountdown(F32 seconds);
+ virtual bool countdownElapsed() const;
+
+private:
+ LLTimer mTimer;
+};
+
+#endif /* ! defined(LL_LLEVENTFILTER_H) */
diff --git a/indra/llcommon/llevents.cpp b/indra/llcommon/llevents.cpp
new file mode 100644
index 0000000000..84a6620a77
--- /dev/null
+++ b/indra/llcommon/llevents.cpp
@@ -0,0 +1,588 @@
+/**
+ * @file llevents.cpp
+ * @author Nat Goodspeed
+ * @date 2008-09-12
+ * @brief Implementation for llevents.
+ *
+ * $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$
+ */
+
+// Precompiled header
+#include "linden_common.h"
+
+#if LL_WINDOWS
+#pragma warning (disable : 4675) // "resolved by ADL" -- just as I want!
+#endif
+
+// associated header
+#include "llevents.h"
+// STL headers
+#include <set>
+#include <sstream>
+#include <algorithm>
+// std headers
+#include <typeinfo>
+#include <cassert>
+#include <cmath>
+#include <cctype>
+// external library headers
+#include <boost/range/iterator_range.hpp>
+#if LL_WINDOWS
+#pragma warning (push)
+#pragma warning (disable : 4701) // compiler thinks might use uninitialized var, but no
+#endif
+#include <boost/lexical_cast.hpp>
+#if LL_WINDOWS
+#pragma warning (pop)
+#endif
+// other Linden headers
+#include "stringize.h"
+#include "llerror.h"
+#include "llsdutil.h"
+#if LL_MSVC
+#pragma warning (disable : 4702)
+#endif
+
+/*****************************************************************************
+* queue_names: specify LLEventPump names that should be instantiated as
+* LLEventQueue
+*****************************************************************************/
+/**
+ * At present, we recognize particular requested LLEventPump names as needing
+ * LLEventQueues. Later on we'll migrate this information to an external
+ * configuration file.
+ */
+const char* queue_names[] =
+{
+ "placeholder - replace with first real name string"
+};
+
+/*****************************************************************************
+* If there's a "mainloop" pump, listen on that to flush all LLEventQueues
+*****************************************************************************/
+struct RegisterFlush : public LLEventTrackable
+{
+ RegisterFlush():
+ pumps(LLEventPumps::instance())
+ {
+ pumps.obtain("mainloop").listen("flushLLEventQueues", boost::bind(&RegisterFlush::flush, this, _1));
+ }
+ bool flush(const LLSD&)
+ {
+ pumps.flush();
+ return false;
+ }
+ ~RegisterFlush()
+ {
+ // LLEventTrackable handles stopListening for us.
+ }
+ LLEventPumps& pumps;
+};
+static RegisterFlush registerFlush;
+
+/*****************************************************************************
+* LLEventPumps
+*****************************************************************************/
+LLEventPumps::LLEventPumps():
+ // Until we migrate this information to an external config file,
+ // initialize mQueueNames from the static queue_names array.
+ mQueueNames(boost::begin(queue_names), boost::end(queue_names))
+{
+}
+
+LLEventPump& LLEventPumps::obtain(const std::string& name)
+{
+ PumpMap::iterator found = mPumpMap.find(name);
+ if (found != mPumpMap.end())
+ {
+ // Here we already have an LLEventPump instance with the requested
+ // name.
+ return *found->second;
+ }
+ // Here we must instantiate an LLEventPump subclass.
+ LLEventPump* newInstance;
+ // Should this name be an LLEventQueue?
+ PumpNames::const_iterator nfound = mQueueNames.find(name);
+ if (nfound != mQueueNames.end())
+ newInstance = new LLEventQueue(name);
+ else
+ newInstance = new LLEventStream(name);
+ // LLEventPump's constructor implicitly registers each new instance in
+ // mPumpMap. But remember that we instantiated it (in mOurPumps) so we'll
+ // delete it later.
+ mOurPumps.insert(newInstance);
+ return *newInstance;
+}
+
+void LLEventPumps::flush()
+{
+ // Flush every known LLEventPump instance. Leave it up to each instance to
+ // decide what to do with the flush() call.
+ for (PumpMap::iterator pmi = mPumpMap.begin(), pmend = mPumpMap.end(); pmi != pmend; ++pmi)
+ {
+ pmi->second->flush();
+ }
+}
+
+void LLEventPumps::reset()
+{
+ // Reset every known LLEventPump instance. Leave it up to each instance to
+ // decide what to do with the reset() call.
+ for (PumpMap::iterator pmi = mPumpMap.begin(), pmend = mPumpMap.end(); pmi != pmend; ++pmi)
+ {
+ pmi->second->reset();
+ }
+}
+
+std::string LLEventPumps::registerNew(const LLEventPump& pump, const std::string& name, bool tweak)
+{
+ std::pair<PumpMap::iterator, bool> inserted =
+ mPumpMap.insert(PumpMap::value_type(name, const_cast<LLEventPump*>(&pump)));
+ // If the insert worked, then the name is unique; return that.
+ if (inserted.second)
+ return name;
+ // Here the new entry was NOT inserted, and therefore name isn't unique.
+ // Unless we're permitted to tweak it, that's Bad.
+ if (! tweak)
+ {
+ throw LLEventPump::DupPumpName(std::string("Duplicate LLEventPump name '") + name + "'");
+ }
+ // The passed name isn't unique, but we're permitted to tweak it. Find the
+ // first decimal-integer suffix not already taken. The insert() attempt
+ // above will have set inserted.first to the iterator of the existing
+ // entry by that name. Starting there, walk forward until we reach an
+ // entry that doesn't start with 'name'. For each entry consisting of name
+ // + integer suffix, capture the integer suffix in a set. Use a set
+ // because we're going to encounter string suffixes in the order: name1,
+ // name10, name11, name2, ... Walking those possibilities in that order
+ // isn't convenient to detect the first available "hole."
+ std::set<int> suffixes;
+ PumpMap::iterator pmi(inserted.first), pmend(mPumpMap.end());
+ // We already know inserted.first references the existing entry with
+ // 'name' as the key; skip that one and start with the next.
+ while (++pmi != pmend)
+ {
+ if (pmi->first.substr(0, name.length()) != name)
+ {
+ // Found the first entry beyond the entries starting with 'name':
+ // stop looping.
+ break;
+ }
+ // Here we're looking at an entry that starts with 'name'. Is the rest
+ // of it an integer?
+ // Dubious (?) assumption: in the local character set, decimal digits
+ // are in increasing order such that '9' is the last of them. This
+ // test deals with 'name' values such as 'a', where there might be a
+ // very large number of entries starting with 'a' whose suffixes
+ // aren't integers. A secondary assumption is that digit characters
+ // precede most common name characters (true in ASCII, false in
+ // EBCDIC). The test below is correct either way, but it's worth more
+ // if the assumption holds.
+ if (pmi->first[name.length()] > '9')
+ break;
+ // It should be cheaper to detect that we're not looking at a digit
+ // character -- and therefore the suffix can't possibly be an integer
+ // -- than to attempt the lexical_cast and catch the exception.
+ if (! std::isdigit(pmi->first[name.length()]))
+ continue;
+ // Okay, the first character of the suffix is a digit, it's worth at
+ // least attempting to convert to int.
+ try
+ {
+ suffixes.insert(boost::lexical_cast<int>(pmi->first.substr(name.length())));
+ }
+ catch (const boost::bad_lexical_cast&)
+ {
+ // If the rest of pmi->first isn't an int, just ignore it.
+ }
+ }
+ // Here we've accumulated in 'suffixes' all existing int suffixes of the
+ // entries starting with 'name'. Find the first unused one.
+ int suffix = 1;
+ for ( ; suffixes.find(suffix) != suffixes.end(); ++suffix)
+ ;
+ // Here 'suffix' is not in 'suffixes'. Construct a new name based on that
+ // suffix, insert it and return it.
+ std::ostringstream out;
+ out << name << suffix;
+ return registerNew(pump, out.str(), tweak);
+}
+
+void LLEventPumps::unregister(const LLEventPump& pump)
+{
+ // Remove this instance from mPumpMap
+ PumpMap::iterator found = mPumpMap.find(pump.getName());
+ if (found != mPumpMap.end())
+ {
+ mPumpMap.erase(found);
+ }
+ // If this instance is one we created, also remove it from mOurPumps so we
+ // won't try again to delete it later!
+ PumpSet::iterator psfound = mOurPumps.find(const_cast<LLEventPump*>(&pump));
+ if (psfound != mOurPumps.end())
+ {
+ mOurPumps.erase(psfound);
+ }
+}
+
+LLEventPumps::~LLEventPumps()
+{
+ // On destruction, delete every LLEventPump we instantiated (via
+ // obtain()). CAREFUL: deleting an LLEventPump calls its destructor, which
+ // calls unregister(), which removes that LLEventPump instance from
+ // mOurPumps. So an iterator loop over mOurPumps to delete contained
+ // LLEventPump instances is dangerous! Instead, delete them one at a time
+ // until mOurPumps is empty.
+ while (! mOurPumps.empty())
+ {
+ delete *mOurPumps.begin();
+ }
+}
+
+/*****************************************************************************
+* LLEventPump
+*****************************************************************************/
+#if LL_WINDOWS
+#pragma warning (push)
+#pragma warning (disable : 4355) // 'this' used in initializer list: yes, intentionally
+#endif
+
+LLEventPump::LLEventPump(const std::string& name, bool tweak):
+ // Register every new instance with LLEventPumps
+ mName(LLEventPumps::instance().registerNew(*this, name, tweak)),
+ mSignal(new LLStandardSignal()),
+ mEnabled(true)
+{}
+
+#if LL_WINDOWS
+#pragma warning (pop)
+#endif
+
+LLEventPump::~LLEventPump()
+{
+ // Unregister this doomed instance from LLEventPumps
+ LLEventPumps::instance().unregister(*this);
+}
+
+// static data member
+const LLEventPump::NameList LLEventPump::empty;
+
+std::string LLEventPump::inventName(const std::string& pfx)
+{
+ static long suffix = 0;
+ return STRINGIZE(pfx << suffix++);
+}
+
+void LLEventPump::reset()
+{
+ mSignal.reset();
+ mConnections.clear();
+ //mDeps.clear();
+}
+
+LLBoundListener LLEventPump::listen_impl(const std::string& name, const LLEventListener& listener,
+ const NameList& after,
+ const NameList& before)
+{
+ // Check for duplicate name before connecting listener to mSignal
+ ConnectionMap::const_iterator found = mConnections.find(name);
+ // In some cases the user might disconnect a connection explicitly -- or
+ // might use LLEventTrackable to disconnect implicitly. Either way, we can
+ // end up retaining in mConnections a zombie connection object that's
+ // already been disconnected. Such a connection object can't be
+ // reconnected -- nor, in the case of LLEventTrackable, would we want to
+ // try, since disconnection happens with the destruction of the listener
+ // object. That means it's safe to overwrite a disconnected connection
+ // object with the new one we're attempting. The case we want to prevent
+ // is only when the existing connection object is still connected.
+ if (found != mConnections.end() && found->second.connected())
+ {
+ throw DupListenerName(std::string("Attempt to register duplicate listener name '") + name +
+ "' on " + typeid(*this).name() + " '" + getName() + "'");
+ }
+ // Okay, name is unique, try to reconcile its dependencies. Specify a new
+ // "node" value that we never use for an mSignal placement; we'll fix it
+ // later.
+ DependencyMap::node_type& newNode = mDeps.add(name, -1.0, after, before);
+ // What if this listener has been added, removed and re-added? In that
+ // case newNode already has a non-negative value because we never remove a
+ // listener from mDeps. But keep processing uniformly anyway in case the
+ // listener was added back with different dependencies. Then mDeps.sort()
+ // would put it in a different position, and the old newNode placement
+ // value would be wrong, so we'd have to reassign it anyway. Trust that
+ // re-adding a listener with the same dependencies is the trivial case for
+ // mDeps.sort(): it can just replay its cache.
+ DependencyMap::sorted_range sorted_range;
+ try
+ {
+ // Can we pick an order that works including this new entry?
+ sorted_range = mDeps.sort();
+ }
+ catch (const DependencyMap::Cycle& e)
+ {
+ // No: the new node's after/before dependencies have made mDeps
+ // unsortable. If we leave the new node in mDeps, it will continue
+ // to screw up all future attempts to sort()! Pull it out.
+ mDeps.remove(name);
+ throw Cycle(std::string("New listener '") + name + "' on " + typeid(*this).name() +
+ " '" + getName() + "' would cause cycle: " + e.what());
+ }
+ // Walk the list to verify that we haven't changed the order.
+ float previous = 0.0, myprev = 0.0;
+ DependencyMap::sorted_iterator mydmi = sorted_range.end(); // need this visible after loop
+ for (DependencyMap::sorted_iterator dmi = sorted_range.begin();
+ dmi != sorted_range.end(); ++dmi)
+ {
+ // Since we've added the new entry with an invalid placement,
+ // recognize it and skip it.
+ if (dmi->first == name)
+ {
+ // Remember the iterator belonging to our new node, and which
+ // placement value was 'previous' at that point.
+ mydmi = dmi;
+ myprev = previous;
+ continue;
+ }
+ // If the new node has rearranged the existing nodes, we'll find
+ // that their placement values are no longer in increasing order.
+ if (dmi->second < previous)
+ {
+ // This is another scenario in which we'd better back out the
+ // newly-added node from mDeps -- but don't do it yet, we want to
+ // traverse the existing mDeps to report on it!
+ // Describe the change to the order of our listeners. Copy
+ // everything but the newest listener to a vector we can sort to
+ // obtain the old order.
+ typedef std::vector< std::pair<float, std::string> > SortNameList;
+ SortNameList sortnames;
+ for (DependencyMap::sorted_iterator cdmi(sorted_range.begin()), cdmend(sorted_range.end());
+ cdmi != cdmend; ++cdmi)
+ {
+ if (cdmi->first != name)
+ {
+ sortnames.push_back(SortNameList::value_type(cdmi->second, cdmi->first));
+ }
+ }
+ std::sort(sortnames.begin(), sortnames.end());
+ std::ostringstream out;
+ out << "New listener '" << name << "' on " << typeid(*this).name() << " '" << getName()
+ << "' would move previous listener '" << dmi->first << "'\nwas: ";
+ SortNameList::const_iterator sni(sortnames.begin()), snend(sortnames.end());
+ if (sni != snend)
+ {
+ out << sni->second;
+ while (++sni != snend)
+ {
+ out << ", " << sni->second;
+ }
+ }
+ out << "\nnow: ";
+ DependencyMap::sorted_iterator ddmi(sorted_range.begin()), ddmend(sorted_range.end());
+ if (ddmi != ddmend)
+ {
+ out << ddmi->first;
+ while (++ddmi != ddmend)
+ {
+ out << ", " << ddmi->first;
+ }
+ }
+ // NOW remove the offending listener node.
+ mDeps.remove(name);
+ // Having constructed a description of the order change, inform caller.
+ throw OrderChange(out.str());
+ }
+ // This node becomes the previous one.
+ previous = dmi->second;
+ }
+ // We just got done with a successful mDeps.add(name, ...) call. We'd
+ // better have found 'name' somewhere in that sorted list!
+ assert(mydmi != sorted_range.end());
+ // Four cases:
+ // 0. name is the only entry: placement 1.0
+ // 1. name is the first of several entries: placement (next placement)/2
+ // 2. name is between two other entries: placement (myprev + (next placement))/2
+ // 3. name is the last entry: placement ceil(myprev) + 1.0
+ // Since we've cleverly arranged for myprev to be 0.0 if name is the
+ // first entry, this folds down to two cases. Case 1 is subsumed by
+ // case 2, and case 0 is subsumed by case 3. So we need only handle
+ // cases 2 and 3, which means we need only detect whether name is the
+ // last entry. Increment mydmi to see if there's anything beyond.
+ if (++mydmi != sorted_range.end())
+ {
+ // The new node isn't last. Place it between the previous node and
+ // the successor.
+ newNode = (myprev + mydmi->second)/2.0;
+ }
+ else
+ {
+ // The new node is last. Bump myprev up to the next integer, add
+ // 1.0 and use that.
+ newNode = std::ceil(myprev) + 1.0;
+ }
+ // Now that newNode has a value that places it appropriately in mSignal,
+ // connect it.
+ LLBoundListener bound = mSignal->connect(newNode, listener);
+ mConnections[name] = bound;
+ return bound;
+}
+
+LLBoundListener LLEventPump::getListener(const std::string& name) const
+{
+ ConnectionMap::const_iterator found = mConnections.find(name);
+ if (found != mConnections.end())
+ {
+ return found->second;
+ }
+ // not found, return dummy LLBoundListener
+ return LLBoundListener();
+}
+
+void LLEventPump::stopListening(const std::string& name)
+{
+ ConnectionMap::iterator found = mConnections.find(name);
+ if (found != mConnections.end())
+ {
+ found->second.disconnect();
+ mConnections.erase(found);
+ }
+ // We intentionally do NOT remove this name from mDeps. It may happen that
+ // the same listener with the same name and dependencies will jump on and
+ // off this LLEventPump repeatedly. Keeping a cache of dependencies will
+ // avoid a new dependency sort in such cases.
+}
+
+/*****************************************************************************
+* LLEventStream
+*****************************************************************************/
+bool LLEventStream::post(const LLSD& event)
+{
+ if (! mEnabled)
+ {
+ return false;
+ }
+ // NOTE NOTE NOTE: Any new access to member data beyond this point should
+ // cause us to move our LLStandardSignal object to a pimpl class along
+ // with said member data. Then the local shared_ptr will preserve both.
+
+ // DEV-43463: capture a local copy of mSignal. We've turned up a
+ // cross-coroutine scenario (described in the Jira) in which this post()
+ // call could end up destroying 'this', the LLEventPump subclass instance
+ // containing mSignal, during the call through *mSignal. So -- capture a
+ // *stack* instance of the shared_ptr, ensuring that our heap
+ // LLStandardSignal object will live at least until post() returns, even
+ // if 'this' gets destroyed during the call.
+ boost::shared_ptr<LLStandardSignal> signal(mSignal);
+ // Let caller know if any one listener handled the event. This is mostly
+ // useful when using LLEventStream as a listener for an upstream
+ // LLEventPump.
+ return (*signal)(event);
+}
+
+/*****************************************************************************
+* LLEventQueue
+*****************************************************************************/
+bool LLEventQueue::post(const LLSD& event)
+{
+ if (mEnabled)
+ {
+ // Defer sending this event by queueing it until flush()
+ mEventQueue.push_back(event);
+ }
+ // Unconditionally return false. We won't know until flush() whether a
+ // listener claims to have handled the event -- meanwhile, don't block
+ // other listeners.
+ return false;
+}
+
+void LLEventQueue::flush()
+{
+ // Consider the case when a given listener on this LLEventQueue posts yet
+ // another event on the same queue. If we loop over mEventQueue directly,
+ // we'll end up processing all those events during the same flush() call
+ // -- rather like an EventStream. Instead, copy mEventQueue and clear it,
+ // so that any new events posted to this LLEventQueue during flush() will
+ // be processed in the *next* flush() call.
+ EventQueue queue(mEventQueue);
+ mEventQueue.clear();
+ // NOTE NOTE NOTE: Any new access to member data beyond this point should
+ // cause us to move our LLStandardSignal object to a pimpl class along
+ // with said member data. Then the local shared_ptr will preserve both.
+
+ // DEV-43463: capture a local copy of mSignal. See LLEventStream::post()
+ // for detailed comments.
+ boost::shared_ptr<LLStandardSignal> signal(mSignal);
+ for ( ; ! queue.empty(); queue.pop_front())
+ {
+ (*signal)(queue.front());
+ }
+}
+
+/*****************************************************************************
+* LLListenerOrPumpName
+*****************************************************************************/
+LLListenerOrPumpName::LLListenerOrPumpName(const std::string& pumpname):
+ // Look up the specified pumpname, and bind its post() method as our listener
+ mListener(boost::bind(&LLEventPump::post,
+ boost::ref(LLEventPumps::instance().obtain(pumpname)),
+ _1))
+{
+}
+
+LLListenerOrPumpName::LLListenerOrPumpName(const char* pumpname):
+ // Look up the specified pumpname, and bind its post() method as our listener
+ mListener(boost::bind(&LLEventPump::post,
+ boost::ref(LLEventPumps::instance().obtain(pumpname)),
+ _1))
+{
+}
+
+bool LLListenerOrPumpName::operator()(const LLSD& event) const
+{
+ if (! mListener)
+ {
+ throw Empty("attempting to call uninitialized");
+ }
+ return (*mListener)(event);
+}
+
+void LLReqID::stamp(LLSD& response) const
+{
+ if (! (response.isUndefined() || response.isMap()))
+ {
+ // If 'response' was previously completely empty, it's okay to
+ // turn it into a map. If it was already a map, then it should be
+ // okay to add a key. But if it was anything else (e.g. a scalar),
+ // assigning a ["reqid"] key will DISCARD the previous value,
+ // replacing it with a map. That would be Bad.
+ LL_INFOS("LLReqID") << "stamp(" << mReqid << ") leaving non-map response unmodified: "
+ << response << LL_ENDL;
+ return;
+ }
+ LLSD oldReqid(response["reqid"]);
+ if (! (oldReqid.isUndefined() || llsd_equals(oldReqid, mReqid)))
+ {
+ LL_INFOS("LLReqID") << "stamp(" << mReqid << ") preserving existing [\"reqid\"] value "
+ << oldReqid << " in response: " << response << LL_ENDL;
+ return;
+ }
+ response["reqid"] = mReqid;
+}
diff --git a/indra/llcommon/llevents.h b/indra/llcommon/llevents.h
new file mode 100644
index 0000000000..2491cf1371
--- /dev/null
+++ b/indra/llcommon/llevents.h
@@ -0,0 +1,1035 @@
+/**
+ * @file llevents.h
+ * @author Kent Quirk, Nat Goodspeed
+ * @date 2008-09-11
+ * @brief This is an implementation of the event system described at
+ * https://wiki.lindenlab.com/wiki/Viewer:Messaging/Event_System,
+ * originally introduced in llnotifications.h. It has nothing
+ * whatsoever to do with the older system in llevent.h.
+ *
+ * $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_LLEVENTS_H)
+#define LL_LLEVENTS_H
+
+#include <string>
+#include <map>
+#include <set>
+#include <vector>
+#include <deque>
+#include <stdexcept>
+#if LL_WINDOWS
+ #pragma warning (push)
+ #pragma warning (disable : 4263) // boost::signals2::expired_slot::what() has const mismatch
+ #pragma warning (disable : 4264)
+#endif
+#include <boost/signals2.hpp>
+#if LL_WINDOWS
+ #pragma warning (pop)
+#endif
+
+#include <boost/bind.hpp>
+#include <boost/shared_ptr.hpp>
+#include <boost/enable_shared_from_this.hpp>
+#include <boost/utility.hpp> // noncopyable
+#include <boost/optional/optional.hpp>
+#include <boost/visit_each.hpp>
+#include <boost/ref.hpp> // reference_wrapper
+#include <boost/type_traits/is_pointer.hpp>
+#include <boost/function.hpp>
+#include <boost/static_assert.hpp>
+#include "llsd.h"
+#include "llsingleton.h"
+#include "lldependencies.h"
+#include "ll_template_cast.h"
+
+/*==========================================================================*|
+// override this to allow binding free functions with more parameters
+#ifndef LLEVENTS_LISTENER_ARITY
+#define LLEVENTS_LISTENER_ARITY 10
+#endif
+|*==========================================================================*/
+
+// hack for testing
+#ifndef testable
+#define testable private
+#endif
+
+/*****************************************************************************
+* Signal and handler declarations
+* Using a single handler signature means that we can have a common handler
+* type, rather than needing a distinct one for each different handler.
+*****************************************************************************/
+
+/**
+ * A boost::signals Combiner that stops the first time a handler returns true
+ * We need this because we want to have our handlers return bool, so that
+ * we have the option to cause a handler to stop further processing. The
+ * default handler fails when the signal returns a value but has no slots.
+ */
+struct LLStopWhenHandled
+{
+ typedef bool result_type;
+
+ template<typename InputIterator>
+ result_type operator()(InputIterator first, InputIterator last) const
+ {
+ for (InputIterator si = first; si != last; ++si)
+ {
+ if (*si)
+ {
+ return true;
+ }
+ }
+ return false;
+ }
+};
+
+/**
+ * We want to have a standard signature for all signals; this way,
+ * we can easily document a protocol for communicating across
+ * dlls and into scripting languages someday.
+ *
+ * We want to return a bool to indicate whether the signal has been
+ * handled and should NOT be passed on to other listeners.
+ * Return true to stop further handling of the signal, and false
+ * to continue.
+ *
+ * We take an LLSD because this way the contents of the signal
+ * are independent of the API used to communicate it.
+ * It is const ref because then there's low cost to pass it;
+ * if you only need to inspect it, it's very cheap.
+ *
+ * @internal
+ * The @c float template parameter indicates that we will internally use @c
+ * float to indicate relative listener order on a given LLStandardSignal.
+ * Don't worry, the @c float values are strictly internal! They are not part
+ * of the interface, for the excellent reason that requiring the caller to
+ * specify a numeric key to establish order means that the caller must know
+ * the universe of possible values. We use LLDependencies for that instead.
+ */
+typedef boost::signals2::signal<bool(const LLSD&), LLStopWhenHandled, float> LLStandardSignal;
+/// Methods that forward listeners (e.g. constructed with
+/// <tt>boost::bind()</tt>) should accept (const LLEventListener&)
+typedef LLStandardSignal::slot_type LLEventListener;
+/// Result of registering a listener, supports <tt>connected()</tt>,
+/// <tt>disconnect()</tt> and <tt>blocked()</tt>
+typedef boost::signals2::connection LLBoundListener;
+/// Storing an LLBoundListener in LLTempBoundListener will disconnect the
+/// referenced listener when the LLTempBoundListener instance is destroyed.
+typedef boost::signals2::scoped_connection LLTempBoundListener;
+
+/**
+ * A common idiom for event-based code is to accept either a callable --
+ * directly called on completion -- or the string name of an LLEventPump on
+ * which to post the completion event. Specifying a parameter as <tt>const
+ * LLListenerOrPumpName&</tt> allows either.
+ *
+ * Calling a validly-constructed LLListenerOrPumpName, passing the LLSD
+ * 'event' object, either calls the callable or posts the event to the named
+ * LLEventPump.
+ *
+ * A default-constructed LLListenerOrPumpName is 'empty'. (This is useful as
+ * the default value of an optional method parameter.) Calling it throws
+ * LLListenerOrPumpName::Empty. Test for this condition beforehand using
+ * either <tt>if (param)</tt> or <tt>if (! param)</tt>.
+ */
+class LL_COMMON_API LLListenerOrPumpName
+{
+public:
+ /// passing string name of LLEventPump
+ LLListenerOrPumpName(const std::string& pumpname);
+ /// passing string literal (overload so compiler isn't forced to infer
+ /// double conversion)
+ LLListenerOrPumpName(const char* pumpname);
+ /// passing listener -- the "anything else" catch-all case. The type of an
+ /// object constructed by boost::bind() isn't intended to be written out.
+ /// Normally we'd just accept 'const LLEventListener&', but that would
+ /// require double implicit conversion: boost::bind() object to
+ /// LLEventListener, LLEventListener to LLListenerOrPumpName. So use a
+ /// template to forward anything.
+ template<typename T>
+ LLListenerOrPumpName(const T& listener): mListener(listener) {}
+
+ /// for omitted method parameter: uninitialized mListener
+ LLListenerOrPumpName() {}
+
+ /// test for validity
+ operator bool() const { return bool(mListener); }
+ bool operator! () const { return ! mListener; }
+
+ /// explicit accessor
+ const LLEventListener& getListener() const { return *mListener; }
+
+ /// implicit conversion to LLEventListener
+ operator LLEventListener() const { return *mListener; }
+
+ /// allow calling directly
+ bool operator()(const LLSD& event) const;
+
+ /// exception if you try to call when empty
+ struct Empty: public std::runtime_error
+ {
+ Empty(const std::string& what):
+ std::runtime_error(std::string("LLListenerOrPumpName::Empty: ") + what) {}
+ };
+
+private:
+ boost::optional<LLEventListener> mListener;
+};
+
+/*****************************************************************************
+* LLEventPumps
+*****************************************************************************/
+class LLEventPump;
+
+/**
+ * LLEventPumps is a Singleton manager through which one typically accesses
+ * this subsystem.
+ */
+class LL_COMMON_API LLEventPumps: public LLSingleton<LLEventPumps>
+{
+ friend class LLSingleton<LLEventPumps>;
+public:
+ /**
+ * Find or create an LLEventPump instance with a specific name. We return
+ * a reference so there's no question about ownership. obtain() @em finds
+ * an instance without conferring @em ownership.
+ */
+ LLEventPump& obtain(const std::string& name);
+ /**
+ * Flush all known LLEventPump instances
+ */
+ void flush();
+
+ /**
+ * Reset all known LLEventPump instances
+ * workaround for DEV-35406 crash on shutdown
+ */
+ void reset();
+
+private:
+ friend class LLEventPump;
+ /**
+ * Register a new LLEventPump instance (internal)
+ */
+ std::string registerNew(const LLEventPump&, const std::string& name, bool tweak);
+ /**
+ * Unregister a doomed LLEventPump instance (internal)
+ */
+ void unregister(const LLEventPump&);
+
+private:
+ LLEventPumps();
+ ~LLEventPumps();
+
+testable:
+ // Map of all known LLEventPump instances, whether or not we instantiated
+ // them. We store a plain old LLEventPump* because this map doesn't claim
+ // ownership of the instances. Though the common usage pattern is to
+ // request an instance using obtain(), it's fair to instantiate an
+ // LLEventPump subclass statically, as a class member, on the stack or on
+ // the heap. In such cases, the instantiating party is responsible for its
+ // lifespan.
+ typedef std::map<std::string, LLEventPump*> PumpMap;
+ PumpMap mPumpMap;
+ // Set of all LLEventPumps we instantiated. Membership in this set means
+ // we claim ownership, and will delete them when this LLEventPumps is
+ // destroyed.
+ typedef std::set<LLEventPump*> PumpSet;
+ PumpSet mOurPumps;
+ // LLEventPump names that should be instantiated as LLEventQueue rather
+ // than as LLEventStream
+ typedef std::set<std::string> PumpNames;
+ PumpNames mQueueNames;
+};
+
+/*****************************************************************************
+* details
+*****************************************************************************/
+namespace LLEventDetail
+{
+ /// Any callable capable of connecting an LLEventListener to an
+ /// LLStandardSignal to produce an LLBoundListener can be mapped to this
+ /// signature.
+ typedef boost::function<LLBoundListener(const LLEventListener&)> ConnectFunc;
+
+ /// overload of visit_and_connect() when we have a string identifier available
+ template <typename LISTENER>
+ LLBoundListener visit_and_connect(const std::string& name,
+ const LISTENER& listener,
+ const ConnectFunc& connect_func);
+ /**
+ * Utility template function to use Visitor appropriately
+ *
+ * @param listener Callable to connect, typically a boost::bind()
+ * expression. This will be visited by Visitor using boost::visit_each().
+ * @param connect_func Callable that will connect() @a listener to an
+ * LLStandardSignal, returning LLBoundListener.
+ */
+ template <typename LISTENER>
+ LLBoundListener visit_and_connect(const LISTENER& listener,
+ const ConnectFunc& connect_func)
+ {
+ return visit_and_connect("", listener, connect_func);
+ }
+} // namespace LLEventDetail
+
+/*****************************************************************************
+* LLEventTrackable
+*****************************************************************************/
+/**
+ * LLEventTrackable wraps boost::signals2::trackable, which resembles
+ * boost::trackable. Derive your listener class from LLEventTrackable instead,
+ * and use something like
+ * <tt>LLEventPump::listen(boost::bind(&YourTrackableSubclass::method,
+ * instance, _1))</tt>. This will implicitly disconnect when the object
+ * referenced by @c instance is destroyed.
+ *
+ * @note
+ * LLEventTrackable doesn't address a couple of cases:
+ * * Object destroyed during call
+ * - You enter a slot call in thread A.
+ * - Thread B destroys the object, which of course disconnects it from any
+ * future slot calls.
+ * - Thread A's call uses 'this', which now refers to a defunct object.
+ * Undefined behavior results.
+ * * Call during destruction
+ * - @c MySubclass is derived from LLEventTrackable.
+ * - @c MySubclass registers one of its own methods using
+ * <tt>LLEventPump::listen()</tt>.
+ * - The @c MySubclass object begins destruction. <tt>~MySubclass()</tt>
+ * runs, destroying state specific to the subclass. (For instance, a
+ * <tt>Foo*</tt> data member is <tt>delete</tt>d but not zeroed.)
+ * - The listening method will not be disconnected until
+ * <tt>~LLEventTrackable()</tt> runs.
+ * - Before we get there, another thread posts data to the @c LLEventPump
+ * instance, calling the @c MySubclass method.
+ * - The method in question relies on valid @c MySubclass state. (For
+ * instance, it attempts to dereference the <tt>Foo*</tt> pointer that was
+ * <tt>delete</tt>d but not zeroed.)
+ * - Undefined behavior results.
+ * If you suspect you may encounter any such scenario, you're better off
+ * managing the lifespan of your object with <tt>boost::shared_ptr</tt>.
+ * Passing <tt>LLEventPump::listen()</tt> a <tt>boost::bind()</tt> expression
+ * involving a <tt>boost::weak_ptr<Foo></tt> is recognized specially, engaging
+ * thread-safe Boost.Signals2 machinery.
+ */
+typedef boost::signals2::trackable LLEventTrackable;
+
+/*****************************************************************************
+* LLEventPump
+*****************************************************************************/
+/**
+ * LLEventPump is the base class interface through which we access the
+ * concrete subclasses LLEventStream and LLEventQueue.
+ *
+ * @NOTE
+ * LLEventPump derives from LLEventTrackable so that when you "chain"
+ * LLEventPump instances together, they will automatically disconnect on
+ * destruction. Please see LLEventTrackable documentation for situations in
+ * which this may be perilous across threads.
+ */
+class LL_COMMON_API LLEventPump: public LLEventTrackable
+{
+public:
+ /**
+ * Exception thrown by LLEventPump(). You are trying to instantiate an
+ * LLEventPump (subclass) using the same name as some other instance, and
+ * you didn't pass <tt>tweak=true</tt> to permit it to generate a unique
+ * variant.
+ */
+ struct DupPumpName: public std::runtime_error
+ {
+ DupPumpName(const std::string& what):
+ std::runtime_error(std::string("DupPumpName: ") + what) {}
+ };
+
+ /**
+ * Instantiate an LLEventPump (subclass) with the string name by which it
+ * can be found using LLEventPumps::obtain().
+ *
+ * If you pass (or default) @a tweak to @c false, then a duplicate name
+ * will throw DupPumpName. This won't happen if LLEventPumps::obtain()
+ * instantiates the LLEventPump, because obtain() uses find-or-create
+ * logic. It can only happen if you instantiate an LLEventPump in your own
+ * code -- and a collision with the name of some other LLEventPump is
+ * likely to cause much more subtle problems!
+ *
+ * When you hand-instantiate an LLEventPump, consider passing @a tweak as
+ * @c true. This directs LLEventPump() to append a suffix to the passed @a
+ * name to make it unique. You can retrieve the adjusted name by calling
+ * getName() on your new instance.
+ */
+ LLEventPump(const std::string& name, bool tweak=false);
+ virtual ~LLEventPump();
+
+ /// group exceptions thrown by listen(). We use exceptions because these
+ /// particular errors are likely to be coding errors, found and fixed by
+ /// the developer even before preliminary checkin.
+ struct ListenError: public std::runtime_error
+ {
+ ListenError(const std::string& what): std::runtime_error(what) {}
+ };
+ /**
+ * exception thrown by listen(). You are attempting to register a
+ * listener on this LLEventPump using the same listener name as an
+ * already-registered listener.
+ */
+ struct DupListenerName: public ListenError
+ {
+ DupListenerName(const std::string& what):
+ ListenError(std::string("DupListenerName: ") + what)
+ {}
+ };
+ /**
+ * exception thrown by listen(). The order dependencies specified for your
+ * listener are incompatible with existing listeners.
+ *
+ * Consider listener "a" which specifies before "b" and "b" which
+ * specifies before "c". You are now attempting to register "c" before
+ * "a". There is no order that can satisfy all constraints.
+ */
+ struct Cycle: public ListenError
+ {
+ Cycle(const std::string& what): ListenError(std::string("Cycle: ") + what) {}
+ };
+ /**
+ * exception thrown by listen(). This one means that your new listener
+ * would force a change to the order of previously-registered listeners,
+ * and we don't have a good way to implement that.
+ *
+ * Consider listeners "some", "other" and "third". "some" and "other" are
+ * registered earlier without specifying relative order, so "other"
+ * happens to be first. Now you attempt to register "third" after "some"
+ * and before "other". Whoops, that would require swapping "some" and
+ * "other", which we can't do. Instead we throw this exception.
+ *
+ * It may not be possible to change the registration order so we already
+ * know "third"s order requirement by the time we register the second of
+ * "some" and "other". A solution would be to specify that "some" must
+ * come before "other", or equivalently that "other" must come after
+ * "some".
+ */
+ struct OrderChange: public ListenError
+ {
+ OrderChange(const std::string& what): ListenError(std::string("OrderChange: ") + what) {}
+ };
+
+ /// used by listen()
+ typedef std::vector<std::string> NameList;
+ /// convenience placeholder for when you explicitly want to pass an empty
+ /// NameList
+ const static NameList empty;
+
+ /// Get this LLEventPump's name
+ std::string getName() const { return mName; }
+
+ /**
+ * Register a new listener with a unique name. Specify an optional list
+ * of other listener names after which this one must be called, likewise
+ * an optional list of other listener names before which this one must be
+ * called. The other listeners mentioned need not yet be registered
+ * themselves. listen() can throw any ListenError; see ListenError
+ * subclasses.
+ *
+ * The listener name must be unique among active listeners for this
+ * LLEventPump, else you get DupListenerName. If you don't care to invent
+ * a name yourself, use inventName(). (I was tempted to recognize e.g. ""
+ * and internally generate a distinct name for that case. But that would
+ * handle badly the scenario in which you want to add, remove, re-add,
+ * etc. the same listener: each new listen() call would necessarily
+ * perform a new dependency sort. Assuming you specify the same
+ * after/before lists each time, using inventName() when you first
+ * instantiate your listener, then passing the same name on each listen()
+ * call, allows us to optimize away the second and subsequent dependency
+ * sorts.
+ *
+ * If (as is typical) you pass a <tt>boost::bind()</tt> expression as @a
+ * listener, listen() will inspect the components of that expression. If a
+ * bound object matches any of several cases, the connection will
+ * automatically be disconnected when that object is destroyed.
+ *
+ * * You bind a <tt>boost::weak_ptr</tt>.
+ * * Binding a <tt>boost::shared_ptr</tt> that way would ensure that the
+ * referenced object would @em never be destroyed, since the @c
+ * shared_ptr stored in the LLEventPump would remain an outstanding
+ * reference. Use the weaken() function to convert your @c shared_ptr to
+ * @c weak_ptr. Because this is easy to forget, binding a @c shared_ptr
+ * will produce a compile error (@c BOOST_STATIC_ASSERT failure).
+ * * You bind a simple pointer or reference to an object derived from
+ * <tt>boost::enable_shared_from_this</tt>. (UNDER CONSTRUCTION)
+ * * You bind a simple pointer or reference to an object derived from
+ * LLEventTrackable. Unlike the cases described above, though, this is
+ * vulnerable to a couple of cross-thread race conditions, as described
+ * in the LLEventTrackable documentation.
+ */
+ template <typename LISTENER>
+ LLBoundListener listen(const std::string& name, const LISTENER& listener,
+ const NameList& after=NameList(),
+ const NameList& before=NameList())
+ {
+ // Examine listener, using our listen_impl() method to make the
+ // actual connection.
+ // This is why listen() is a template. Conversion from boost::bind()
+ // to LLEventListener performs type erasure, so it's important to look
+ // at the boost::bind object itself before that happens.
+ return LLEventDetail::visit_and_connect(name,
+ listener,
+ boost::bind(&LLEventPump::listen_impl,
+ this,
+ name,
+ _1,
+ after,
+ before));
+ }
+
+ /// Get the LLBoundListener associated with the passed name (dummy
+ /// LLBoundListener if not found)
+ virtual LLBoundListener getListener(const std::string& name) const;
+ /**
+ * Instantiate one of these to block an existing connection:
+ * @code
+ * { // in some local scope
+ * LLEventPump::Blocker block(someLLBoundListener);
+ * // code that needs the connection blocked
+ * } // unblock the connection again
+ * @endcode
+ */
+ typedef boost::signals2::shared_connection_block Blocker;
+ /// Unregister a listener by name. Prefer this to
+ /// <tt>getListener(name).disconnect()</tt> because stopListening() also
+ /// forgets this name.
+ virtual void stopListening(const std::string& name);
+ /// Post an event to all listeners. The @c bool return is only meaningful
+ /// if the underlying leaf class is LLEventStream -- beware of relying on
+ /// it too much! Truthfully, we return @c bool mostly to permit chaining
+ /// one LLEventPump as a listener on another.
+ virtual bool post(const LLSD&) = 0;
+ /// Enable/disable: while disabled, silently ignore all post() calls
+ virtual void enable(bool enabled=true) { mEnabled = enabled; }
+ /// query
+ virtual bool enabled() const { return mEnabled; }
+
+ /// Generate a distinct name for a listener -- see listen()
+ static std::string inventName(const std::string& pfx="listener");
+
+private:
+ friend class LLEventPumps;
+ /// flush queued events
+ virtual void flush() {}
+
+ virtual void reset();
+
+private:
+ virtual LLBoundListener listen_impl(const std::string& name, const LLEventListener&,
+ const NameList& after,
+ const NameList& before);
+ std::string mName;
+
+protected:
+ /// implement the dispatching
+ boost::shared_ptr<LLStandardSignal> mSignal;
+
+ /// valve open?
+ bool mEnabled;
+ /// Map of named listeners. This tracks the listeners that actually exist
+ /// at this moment. When we stopListening(), we discard the entry from
+ /// this map.
+ typedef std::map<std::string, boost::signals2::connection> ConnectionMap;
+ ConnectionMap mConnections;
+ typedef LLDependencies<std::string, float> DependencyMap;
+ /// Dependencies between listeners. For each listener, track the float
+ /// used to establish its place in mSignal's order. This caches all the
+ /// listeners that have ever registered; stopListening() does not discard
+ /// the entry from this map. This is to avoid a new dependency sort if the
+ /// same listener with the same dependencies keeps hopping on and off this
+ /// LLEventPump.
+ DependencyMap mDeps;
+};
+
+/*****************************************************************************
+* LLEventStream
+*****************************************************************************/
+/**
+ * LLEventStream is a thin wrapper around LLStandardSignal. Posting an
+ * event immediately calls all registered listeners.
+ */
+class LL_COMMON_API LLEventStream: public LLEventPump
+{
+public:
+ LLEventStream(const std::string& name, bool tweak=false): LLEventPump(name, tweak) {}
+ virtual ~LLEventStream() {}
+
+ /// Post an event to all listeners
+ virtual bool post(const LLSD& event);
+};
+
+/*****************************************************************************
+* LLEventQueue
+*****************************************************************************/
+/**
+ * LLEventQueue isa LLEventPump whose post() method defers calling registered
+ * listeners until flush() is called.
+ */
+class LL_COMMON_API LLEventQueue: public LLEventPump
+{
+public:
+ LLEventQueue(const std::string& name, bool tweak=false): LLEventPump(name, tweak) {}
+ virtual ~LLEventQueue() {}
+
+ /// Post an event to all listeners
+ virtual bool post(const LLSD& event);
+
+private:
+ /// flush queued events
+ virtual void flush();
+
+private:
+ typedef std::deque<LLSD> EventQueue;
+ EventQueue mEventQueue;
+};
+
+/*****************************************************************************
+* LLReqID
+*****************************************************************************/
+/**
+ * This class helps the implementer of a given event API to honor the
+ * ["reqid"] convention. By this convention, each event API stamps into its
+ * response LLSD a ["reqid"] key whose value echoes the ["reqid"] value, if
+ * any, from the corresponding request.
+ *
+ * This supports an (atypical, but occasionally necessary) use case in which
+ * two or more asynchronous requests are multiplexed onto the same ["reply"]
+ * LLEventPump. Since the response events could arrive in arbitrary order, the
+ * caller must be able to demux them. It does so by matching the ["reqid"]
+ * value in each response with the ["reqid"] value in the corresponding
+ * request.
+ *
+ * It is the caller's responsibility to ensure distinct ["reqid"] values for
+ * that case. Though LLSD::UUID is guaranteed to work, it might be overkill:
+ * the "namespace" of unique ["reqid"] values is simply the set of requests
+ * specifying the same ["reply"] LLEventPump name.
+ *
+ * Making a given event API echo the request's ["reqid"] into the response is
+ * nearly trivial. This helper is mostly for mnemonic purposes, to serve as a
+ * place to put these comments. We hope that each time a coder implements a
+ * new event API based on some existing one, s/he will say, "Huh, what's an
+ * LLReqID?" and look up this material.
+ *
+ * The hardest part about the convention is deciding where to store the
+ * ["reqid"] value. Ironically, LLReqID can't help with that: you must store
+ * an LLReqID instance in whatever storage will persist until the reply is
+ * sent. For example, if the request ultimately ends up using a Responder
+ * subclass, storing an LLReqID instance in the Responder works.
+ *
+ * @note
+ * The @em implementer of an event API must honor the ["reqid"] convention.
+ * However, the @em caller of an event API need only use it if s/he is sharing
+ * the same ["reply"] LLEventPump for two or more asynchronous event API
+ * requests.
+ *
+ * In most cases, it's far easier for the caller to instantiate a local
+ * LLEventStream and pass its name to the event API in question. Then it's
+ * perfectly reasonable not to set a ["reqid"] key in the request, ignoring
+ * the @c isUndefined() ["reqid"] value in the response.
+ */
+class LL_COMMON_API LLReqID
+{
+public:
+ /**
+ * If you have the request in hand at the time you instantiate the
+ * LLReqID, pass that request to extract its ["reqid"].
+ */
+ LLReqID(const LLSD& request):
+ mReqid(request["reqid"])
+ {}
+ /// If you don't yet have the request, use setFrom() later.
+ LLReqID() {}
+
+ /// Extract and store the ["reqid"] value from an incoming request.
+ void setFrom(const LLSD& request)
+ {
+ mReqid = request["reqid"];
+ }
+
+ /// Set ["reqid"] key into a pending response LLSD object.
+ void stamp(LLSD& response) const;
+
+ /// Make a whole new response LLSD object with our ["reqid"].
+ LLSD makeResponse() const
+ {
+ LLSD response;
+ stamp(response);
+ return response;
+ }
+
+ /// Not really sure of a use case for this accessor...
+ LLSD getReqID() const { return mReqid; }
+
+private:
+ LLSD mReqid;
+};
+
+/**
+ * Base class for LLListenerWrapper. See visit_and_connect() and llwrap(). We
+ * provide virtual @c accept_xxx() methods, customization points allowing a
+ * subclass access to certain data visible at LLEventPump::listen() time.
+ * Example subclass usage:
+ *
+ * @code
+ * myEventPump.listen("somename",
+ * llwrap<MyListenerWrapper>(boost::bind(&MyClass::method, instance, _1)));
+ * @endcode
+ *
+ * Because of the anticipated usage (note the anonymous temporary
+ * MyListenerWrapper instance in the example above), the @c accept_xxx()
+ * methods must be @c const.
+ */
+class LL_COMMON_API LLListenerWrapperBase
+{
+public:
+ /// New instance. The accept_xxx() machinery makes it important to use
+ /// shared_ptrs for our data. Many copies of this object are made before
+ /// the instance that actually ends up in the signal, yet accept_xxx()
+ /// will later be called on the @em original instance. All copies of the
+ /// same original instance must share the same data.
+ LLListenerWrapperBase():
+ mName(new std::string),
+ mConnection(new LLBoundListener)
+ {
+ }
+
+ /// Copy constructor. Copy shared_ptrs to original instance data.
+ LLListenerWrapperBase(const LLListenerWrapperBase& that):
+ mName(that.mName),
+ mConnection(that.mConnection)
+ {
+ }
+ virtual ~LLListenerWrapperBase() {}
+
+ /// Ask LLEventPump::listen() for the listener name
+ virtual void accept_name(const std::string& name) const
+ {
+ *mName = name;
+ }
+
+ /// Ask LLEventPump::listen() for the new connection
+ virtual void accept_connection(const LLBoundListener& connection) const
+ {
+ *mConnection = connection;
+ }
+
+protected:
+ /// Listener name.
+ boost::shared_ptr<std::string> mName;
+ /// Connection.
+ boost::shared_ptr<LLBoundListener> mConnection;
+};
+
+/*****************************************************************************
+* Underpinnings
+*****************************************************************************/
+/**
+ * We originally provided a suite of overloaded
+ * LLEventTrackable::listenTo(LLEventPump&, ...) methods that would call
+ * LLEventPump::listen(...) and then pass the returned LLBoundListener to
+ * LLEventTrackable::track(). This was workable but error-prone: the coder
+ * must remember to call listenTo() rather than the more straightforward
+ * listen() method.
+ *
+ * Now we publish only the single canonical listen() method, so there's a
+ * uniform mechanism. Having a single way to do this is good, in that there's
+ * no question in the coder's mind which of several alternatives to choose.
+ *
+ * To support automatic connection management, we use boost::visit_each
+ * (http://www.boost.org/doc/libs/1_37_0/doc/html/boost/visit_each.html) to
+ * inspect each argument of a boost::bind expression. (Although the visit_each
+ * mechanism was first introduced with the original Boost.Signals library, it
+ * was only later documented.)
+ *
+ * Cases:
+ * * At least one of the function's arguments is a boost::weak_ptr<T>. Pass
+ * the corresponding shared_ptr to slot_type::track(). Ideally that would be
+ * the object whose method we want to call, but in fact we do the same for
+ * any weak_ptr we might find among the bound arguments. If we're passing
+ * our bound method a weak_ptr to some object, wouldn't the destruction of
+ * that object invalidate the call? So we disconnect automatically when any
+ * such object is destroyed. This is the mechanism preferred by boost::
+ * signals2.
+ * * One of the functions's arguments is a boost::shared_ptr<T>. This produces
+ * a compile error: the bound copy of the shared_ptr stored in the
+ * boost_bind object stored in the signal object would make the referenced
+ * T object immortal. We provide a weaken() function. Pass
+ * weaken(your_shared_ptr) instead. (We can inspect, but not modify, the
+ * boost::bind object. Otherwise we'd replace the shared_ptr with weak_ptr
+ * implicitly and just proceed.)
+ * * One of the function's arguments is a plain pointer/reference to an object
+ * derived from boost::enable_shared_from_this. We assume that this object
+ * is managed using boost::shared_ptr, so we implicitly extract a shared_ptr
+ * and track that. (UNDER CONSTRUCTION)
+ * * One of the function's arguments is derived from LLEventTrackable. Pass
+ * the LLBoundListener to its LLEventTrackable::track(). This is vulnerable
+ * to a couple different race conditions, as described in LLEventTrackable
+ * documentation. (NOTE: Now that LLEventTrackable is a typedef for
+ * boost::signals2::trackable, the Signals2 library handles this itself, so
+ * our visitor needs no special logic for this case.)
+ * * Any other argument type is irrelevant to automatic connection management.
+ */
+
+namespace LLEventDetail
+{
+ template <typename F>
+ const F& unwrap(const F& f) { return f; }
+
+ template <typename F>
+ const F& unwrap(const boost::reference_wrapper<F>& f) { return f.get(); }
+
+ // Most of the following is lifted from the Boost.Signals use of
+ // visit_each.
+ template<bool Cond> struct truth {};
+
+ /**
+ * boost::visit_each() Visitor, used on a template argument <tt>const F&
+ * f</tt> as follows (see visit_and_connect()):
+ * @code
+ * LLEventListener listener(f);
+ * Visitor visitor(listener); // bind listener so it can track() shared_ptrs
+ * using boost::visit_each; // allow unqualified visit_each() call for ADL
+ * visit_each(visitor, unwrap(f));
+ * @endcode
+ */
+ class Visitor
+ {
+ public:
+ /**
+ * Visitor binds a reference to LLEventListener so we can track() any
+ * shared_ptrs we find in the argument list.
+ */
+ Visitor(LLEventListener& listener):
+ mListener(listener)
+ {
+ }
+
+ /**
+ * boost::visit_each() calls this method for each component of a
+ * boost::bind() expression.
+ */
+ template <typename T>
+ void operator()(const T& t) const
+ {
+ decode(t, 0);
+ }
+
+ private:
+ // decode() decides between a reference wrapper and anything else
+ // boost::ref() variant
+ template<typename T>
+ void decode(const boost::reference_wrapper<T>& t, int) const
+ {
+// add_if_trackable(t.get_pointer());
+ }
+
+ // decode() anything else
+ template<typename T>
+ void decode(const T& t, long) const
+ {
+ typedef truth<(boost::is_pointer<T>::value)> is_a_pointer;
+ maybe_get_pointer(t, is_a_pointer());
+ }
+
+ // maybe_get_pointer() decides between a pointer and a non-pointer
+ // plain pointer variant
+ template<typename T>
+ void maybe_get_pointer(const T& t, truth<true>) const
+ {
+// add_if_trackable(t);
+ }
+
+ // shared_ptr variant
+ template<typename T>
+ void maybe_get_pointer(const boost::shared_ptr<T>& t, truth<false>) const
+ {
+ // If we have a shared_ptr to this object, it doesn't matter
+ // whether the object is derived from LLEventTrackable, so no
+ // further analysis of T is needed.
+// mListener.track(t);
+
+ // Make this case illegal. Passing a bound shared_ptr to
+ // slot_type::track() is useless, since the bound shared_ptr will
+ // keep the object alive anyway! Force the coder to cast to weak_ptr.
+
+ // Trivial as it is, make the BOOST_STATIC_ASSERT() condition
+ // dependent on template param so the macro is only evaluated if
+ // this method is in fact instantiated, as described here:
+ // http://www.boost.org/doc/libs/1_34_1/doc/html/boost_staticassert.html
+
+ // ATTENTION: Don't bind a shared_ptr<anything> using
+ // LLEventPump::listen(boost::bind()). Doing so captures a copy of
+ // the shared_ptr, making the referenced object effectively
+ // immortal. Use the weaken() function, e.g.:
+ // somepump.listen(boost::bind(...weaken(my_shared_ptr)...));
+ // This lets us automatically disconnect when the referenced
+ // object is destroyed.
+ BOOST_STATIC_ASSERT(sizeof(T) == 0);
+ }
+
+ // weak_ptr variant
+ template<typename T>
+ void maybe_get_pointer(const boost::weak_ptr<T>& t, truth<false>) const
+ {
+ // If we have a weak_ptr to this object, it doesn't matter
+ // whether the object is derived from LLEventTrackable, so no
+ // further analysis of T is needed.
+ mListener.track(t);
+// std::cout << "Found weak_ptr<" << typeid(T).name() << ">!\n";
+ }
+
+#if 0
+ // reference to anything derived from boost::enable_shared_from_this
+ template <typename T>
+ inline void maybe_get_pointer(const boost::enable_shared_from_this<T>& ct,
+ truth<false>) const
+ {
+ // Use the slot_type::track(shared_ptr) mechanism. Cast away
+ // const-ness because (in our code base anyway) it's unusual
+ // to find shared_ptr<const T>.
+ boost::enable_shared_from_this<T>&
+ t(const_cast<boost::enable_shared_from_this<T>&>(ct));
+ std::cout << "Capturing shared_from_this()" << std::endl;
+ boost::shared_ptr<T> sp(t.shared_from_this());
+/*==========================================================================*|
+ std::cout << "Capturing weak_ptr" << std::endl;
+ boost::weak_ptr<T> wp(sp);
+|*==========================================================================*/
+ std::cout << "Tracking shared__ptr" << std::endl;
+ mListener.track(sp);
+ }
+#endif
+
+ // non-pointer variant
+ template<typename T>
+ void maybe_get_pointer(const T& t, truth<false>) const
+ {
+ // Take the address of this object, because the object itself may be
+ // trackable
+// add_if_trackable(boost::addressof(t));
+ }
+
+/*==========================================================================*|
+ // add_if_trackable() adds LLEventTrackable objects to mTrackables
+ inline void add_if_trackable(const LLEventTrackable* t) const
+ {
+ if (t)
+ {
+ }
+ }
+
+ // pointer to anything not an LLEventTrackable subclass
+ inline void add_if_trackable(const void*) const
+ {
+ }
+
+ // pointer to free function
+ // The following construct uses the preprocessor to generate
+ // add_if_trackable() overloads accepting pointer-to-function taking
+ // 0, 1, ..., LLEVENTS_LISTENER_ARITY parameters of arbitrary type.
+#define BOOST_PP_LOCAL_MACRO(n) \
+ template <typename R \
+ BOOST_PP_COMMA_IF(n) \
+ BOOST_PP_ENUM_PARAMS(n, typename T)> \
+ inline void \
+ add_if_trackable(R (*)(BOOST_PP_ENUM_PARAMS(n, T))) const \
+ { \
+ }
+#define BOOST_PP_LOCAL_LIMITS (0, LLEVENTS_LISTENER_ARITY)
+#include BOOST_PP_LOCAL_ITERATE()
+#undef BOOST_PP_LOCAL_MACRO
+#undef BOOST_PP_LOCAL_LIMITS
+|*==========================================================================*/
+
+ /// Bind a reference to the LLEventListener to call its track() method.
+ LLEventListener& mListener;
+ };
+
+ /**
+ * Utility template function to use Visitor appropriately
+ *
+ * @param raw_listener Callable to connect, typically a boost::bind()
+ * expression. This will be visited by Visitor using boost::visit_each().
+ * @param connect_funct Callable that will connect() @a raw_listener to an
+ * LLStandardSignal, returning LLBoundListener.
+ */
+ template <typename LISTENER>
+ LLBoundListener visit_and_connect(const std::string& name,
+ const LISTENER& raw_listener,
+ const ConnectFunc& connect_func)
+ {
+ // Capture the listener
+ LLEventListener listener(raw_listener);
+ // Define our Visitor, binding the listener so we can call
+ // listener.track() if we discover any shared_ptr<Foo>.
+ LLEventDetail::Visitor visitor(listener);
+ // Allow unqualified visit_each() call for ADL
+ using boost::visit_each;
+ // Visit each component of a boost::bind() expression. Pass
+ // 'raw_listener', our template argument, rather than 'listener' from
+ // which type details have been erased. unwrap() comes from
+ // Boost.Signals, in case we were passed a boost::ref().
+ visit_each(visitor, LLEventDetail::unwrap(raw_listener));
+ // Make the connection using passed function.
+ LLBoundListener connection(connect_func(listener));
+ // If the LISTENER is an LLListenerWrapperBase subclass, pass it the
+ // desired information. It's important that we pass the raw_listener
+ // so the compiler can make decisions based on its original type.
+ const LLListenerWrapperBase* lwb =
+ ll_template_cast<const LLListenerWrapperBase*>(&raw_listener);
+ if (lwb)
+ {
+ lwb->accept_name(name);
+ lwb->accept_connection(connection);
+ }
+ // In any case, show new connection to caller.
+ return connection;
+ }
+} // namespace LLEventDetail
+
+// Somewhat to my surprise, passing boost::bind(...boost::weak_ptr<T>...) to
+// listen() fails in Boost code trying to instantiate LLEventListener (i.e.
+// LLStandardSignal::slot_type) because the boost::get_pointer() utility function isn't
+// specialized for boost::weak_ptr. This remedies that omission.
+namespace boost
+{
+ template <typename T>
+ T* get_pointer(const weak_ptr<T>& ptr) { return shared_ptr<T>(ptr).get(); }
+}
+
+/// Since we forbid use of listen(boost::bind(...shared_ptr<T>...)), provide an
+/// easy way to cast to the corresponding weak_ptr.
+template <typename T>
+boost::weak_ptr<T> weaken(const boost::shared_ptr<T>& ptr)
+{
+ return boost::weak_ptr<T>(ptr);
+}
+
+#endif /* ! defined(LL_LLEVENTS_H) */
diff --git a/indra/llcommon/lleventtimer.cpp b/indra/llcommon/lleventtimer.cpp
new file mode 100644
index 0000000000..7743826c60
--- /dev/null
+++ b/indra/llcommon/lleventtimer.cpp
@@ -0,0 +1,89 @@
+/**
+ * @file lleventtimer.cpp
+ * @brief Cross-platform objects for doing timing
+ *
+ * $LicenseInfo:firstyear=2000&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$
+ */
+
+#include "linden_common.h"
+
+#include "lleventtimer.h"
+
+#include "u64.h"
+
+
+//////////////////////////////////////////////////////////////////////////////
+//
+// LLEventTimer Implementation
+//
+//////////////////////////////////////////////////////////////////////////////
+
+LLEventTimer::LLEventTimer(F32 period)
+: mEventTimer()
+{
+ mPeriod = period;
+}
+
+LLEventTimer::LLEventTimer(const LLDate& time)
+: mEventTimer()
+{
+ mPeriod = (F32)(time.secondsSinceEpoch() - LLDate::now().secondsSinceEpoch());
+}
+
+
+LLEventTimer::~LLEventTimer()
+{
+}
+
+//static
+void LLEventTimer::updateClass()
+{
+ std::list<LLEventTimer*> completed_timers;
+
+ {
+ LLInstanceTrackerScopedGuard guard;
+ for (instance_iter iter = guard.beginInstances(); iter != guard.endInstances(); )
+ {
+ LLEventTimer& timer = *iter++;
+ F32 et = timer.mEventTimer.getElapsedTimeF32();
+ if (timer.mEventTimer.getStarted() && et > timer.mPeriod) {
+ timer.mEventTimer.reset();
+ if ( timer.tick() )
+ {
+ completed_timers.push_back( &timer );
+ }
+ }
+ }
+ }
+
+ if ( completed_timers.size() > 0 )
+ {
+ for (std::list<LLEventTimer*>::iterator completed_iter = completed_timers.begin();
+ completed_iter != completed_timers.end();
+ completed_iter++ )
+ {
+ delete *completed_iter;
+ }
+ }
+}
+
+
diff --git a/indra/llcommon/lleventtimer.h b/indra/llcommon/lleventtimer.h
new file mode 100644
index 0000000000..7f42623d01
--- /dev/null
+++ b/indra/llcommon/lleventtimer.h
@@ -0,0 +1,54 @@
+/**
+ * @file lleventtimer.h
+ * @brief Cross-platform objects for doing timing
+ *
+ * $LicenseInfo:firstyear=2000&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$
+ */
+
+#ifndef LL_EVENTTIMER_H
+#define LL_EVENTTIMER_H
+
+#include "stdtypes.h"
+#include "lldate.h"
+#include "llinstancetracker.h"
+#include "lltimer.h"
+
+// class for scheduling a function to be called at a given frequency (approximate, inprecise)
+class LL_COMMON_API LLEventTimer : public LLInstanceTracker<LLEventTimer>
+{
+public:
+ LLEventTimer(F32 period); // period is the amount of time between each call to tick() in seconds
+ LLEventTimer(const LLDate& time);
+ virtual ~LLEventTimer();
+
+ //function to be called at the supplied frequency
+ // Normally return FALSE; TRUE will delete the timer after the function returns.
+ virtual BOOL tick() = 0;
+
+ static void updateClass();
+
+protected:
+ LLTimer mEventTimer;
+ F32 mPeriod;
+};
+
+#endif //LL_EVENTTIMER_H
diff --git a/indra/llcommon/llextendedstatus.h b/indra/llcommon/llextendedstatus.h
index e4266f6af0..8ce173d1ff 100644
--- a/indra/llcommon/llextendedstatus.h
+++ b/indra/llcommon/llextendedstatus.h
@@ -3,30 +3,25 @@
* @date August 2007
* @brief extended status codes for curl/vfs/resident asset storage and delivery
*
- * $LicenseInfo:firstyear=2007&license=viewergpl$
- *
- * Copyright (c) 2007, Linden Research, Inc.
- *
+ * $LicenseInfo:firstyear=2007&license=viewerlgpl$
* Second Life Viewer Source Code
- * The source code in this file ("Source Code") is provided by Linden Lab
- * to you under the terms of the GNU General Public License, version 2.0
- * ("GPL"), unless you have obtained a separate licensing agreement
- * ("Other License"), formally executed by you and Linden Lab. Terms of
- * the GPL can be found in doc/GPL-license.txt in this distribution, or
- * online at http://secondlife.com/developers/opensource/gplv2
+ * 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.
*
- * There are special exceptions to the terms and conditions of the GPL as
- * it is applied to this Source Code. View the full text of the exception
- * in the file doc/FLOSS-exception.txt in this software distribution, or
- * online at http://secondlife.com/developers/opensource/flossexception
+ * 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.
*
- * By copying, modifying or distributing this software, you acknowledge
- * that you have read and understood your obligations described above,
- * and agree to abide by those obligations.
+ * 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
*
- * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
- * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
- * COMPLETENESS OR PERFORMANCE.
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
* $/LicenseInfo$
*/
diff --git a/indra/llcommon/llfasttimer.h b/indra/llcommon/llfasttimer.h
index e92f04441c..4ff93a553c 100644
--- a/indra/llcommon/llfasttimer.h
+++ b/indra/llcommon/llfasttimer.h
@@ -1,246 +1,166 @@
-/**
+/**
* @file llfasttimer.h
- * @brief Declaration of a fast timer.
+ * @brief Inline implementations of fast timers.
*
- * $LicenseInfo:firstyear=2004&license=viewergpl$
- *
- * Copyright (c) 2004-2007, Linden Research, Inc.
- *
+ * $LicenseInfo:firstyear=2004&license=viewerlgpl$
* Second Life Viewer Source Code
- * The source code in this file ("Source Code") is provided by Linden Lab
- * to you under the terms of the GNU General Public License, version 2.0
- * ("GPL"), unless you have obtained a separate licensing agreement
- * ("Other License"), formally executed by you and Linden Lab. Terms of
- * the GPL can be found in doc/GPL-license.txt in this distribution, or
- * online at http://secondlife.com/developers/opensource/gplv2
+ * Copyright (C) 2010, Linden Research, Inc.
*
- * There are special exceptions to the terms and conditions of the GPL as
- * it is applied to this Source Code. View the full text of the exception
- * in the file doc/FLOSS-exception.txt in this software distribution, or
- * online at http://secondlife.com/developers/opensource/flossexception
+ * 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.
*
- * By copying, modifying or distributing this software, you acknowledge
- * that you have read and understood your obligations described above,
- * and agree to abide by those obligations.
+ * 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.
*
- * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
- * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
- * COMPLETENESS OR PERFORMANCE.
+ * 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$
*/
-#ifndef LL_LLFASTTIMER_H
-#define LL_LLFASTTIMER_H
+#ifndef LL_FASTTIMER_H
+#define LL_FASTTIMER_H
+
+// pull in the actual class definition
+#include "llfasttimer_class.h"
-#define FAST_TIMER_ON 1
+//
+// Important note: These implementations must be FAST!
+//
-U64 get_cpu_clock_count();
+#if LL_WINDOWS
+//
+// Windows implementation of CPU clock
+//
-class LLFastTimer
+//
+// NOTE: put back in when we aren't using platform sdk anymore
+//
+// because MS has different signatures for these functions in winnt.h
+// need to rename them to avoid conflicts
+//#define _interlockedbittestandset _renamed_interlockedbittestandset
+//#define _interlockedbittestandreset _renamed_interlockedbittestandreset
+//#include <intrin.h>
+//#undef _interlockedbittestandset
+//#undef _interlockedbittestandreset
+
+//inline U32 LLFastTimer::getCPUClockCount32()
+//{
+// U64 time_stamp = __rdtsc();
+// return (U32)(time_stamp >> 8);
+//}
+//
+//// return full timer value, *not* shifted by 8 bits
+//inline U64 LLFastTimer::getCPUClockCount64()
+//{
+// return __rdtsc();
+//}
+
+// shift off lower 8 bits for lower resolution but longer term timing
+// on 1Ghz machine, a 32-bit word will hold ~1000 seconds of timing
+inline U32 LLFastTimer::getCPUClockCount32()
{
-public:
- enum EFastTimerType
- {
- // high level
- FTM_FRAME,
- FTM_UPDATE,
- FTM_RENDER,
- FTM_SWAP,
- FTM_CLIENT_COPY,
- FTM_IDLE,
- FTM_SLEEP,
-
- // common messaging components
- FTM_PUMP,
- FTM_CURL,
-
- // common simulation components
- FTM_UPDATE_ANIMATION,
- FTM_UPDATE_TERRAIN,
- FTM_UPDATE_PRIMITIVES,
- FTM_UPDATE_PARTICLES,
- FTM_SIMULATE_PARTICLES,
- FTM_UPDATE_SKY,
- FTM_UPDATE_TEXTURES,
- FTM_UPDATE_WLPARAM,
- FTM_UPDATE_WATER,
- FTM_UPDATE_CLOUDS,
- FTM_UPDATE_GRASS,
- FTM_UPDATE_TREE,
- FTM_UPDATE_AVATAR,
-
- // common render components
- FTM_RENDER_GEOMETRY,
- FTM_RENDER_TERRAIN,
- FTM_RENDER_SIMPLE,
- FTM_RENDER_FULLBRIGHT,
- FTM_RENDER_GLOW,
- FTM_RENDER_GRASS,
- FTM_RENDER_INVISIBLE,
- FTM_RENDER_SHINY,
- FTM_RENDER_BUMP,
- FTM_RENDER_TREES,
- FTM_RENDER_CHARACTERS,
- FTM_RENDER_OCCLUSION,
- FTM_RENDER_ALPHA,
- FTM_RENDER_CLOUDS,
- FTM_RENDER_HUD,
- FTM_RENDER_PARTICLES,
- FTM_RENDER_WATER,
- FTM_RENDER_WL_SKY,
- FTM_RENDER_FAKE_VBO_UPDATE,
- FTM_RENDER_TIMER,
- FTM_RENDER_UI,
- FTM_RENDER_BLOOM,
- FTM_RENDER_BLOOM_FBO,
- FTM_RENDER_FONTS,
-
- // newview specific
- FTM_MESSAGES,
- FTM_MOUSEHANDLER,
- FTM_KEYHANDLER,
- FTM_REBUILD,
- FTM_STATESORT,
- FTM_STATESORT_DRAWABLE,
- FTM_STATESORT_POSTSORT,
- FTM_REBUILD_VBO,
- FTM_REBUILD_VOLUME_VB,
- FTM_REBUILD_BRIDGE_VB,
- FTM_REBUILD_HUD_VB,
- FTM_REBUILD_TERRAIN_VB,
- FTM_REBUILD_WATER_VB,
- FTM_REBUILD_TREE_VB,
- FTM_REBUILD_PARTICLE_VB,
- FTM_REBUILD_CLOUD_VB,
- FTM_REBUILD_GRASS_VB,
- FTM_REBUILD_NONE_VB,
- FTM_REBUILD_OCCLUSION_VB,
- FTM_POOLS,
- FTM_POOLRENDER,
- FTM_IDLE_CB,
- FTM_WORLD_UPDATE,
- FTM_UPDATE_MOVE,
- FTM_OCTREE_BALANCE,
- FTM_UPDATE_LIGHTS,
- FTM_CULL,
- FTM_CULL_REBOUND,
- FTM_FRUSTUM_CULL,
- FTM_GEO_UPDATE,
- FTM_GEO_RESERVE,
- FTM_GEO_LIGHT,
- FTM_GEO_SHADOW,
- FTM_GEO_SKY,
- FTM_GEN_VOLUME,
- FTM_GEN_TRIANGLES,
- FTM_GEN_FLEX,
- FTM_AUDIO_UPDATE,
- FTM_RESET_DRAWORDER,
- FTM_OBJECTLIST_UPDATE,
- FTM_AVATAR_UPDATE,
- FTM_JOINT_UPDATE,
- FTM_ATTACHMENT_UPDATE,
- FTM_LOD_UPDATE,
- FTM_REGION_UPDATE,
- FTM_CLEANUP,
- FTM_NETWORK,
- FTM_IDLE_NETWORK,
- FTM_CREATE_OBJECT,
- FTM_LOAD_AVATAR,
- FTM_PROCESS_MESSAGES,
- FTM_PROCESS_OBJECTS,
- FTM_PROCESS_IMAGES,
- FTM_IMAGE_UPDATE,
- FTM_IMAGE_CREATE,
- FTM_IMAGE_DECODE,
- FTM_IMAGE_MARK_DIRTY,
- FTM_PIPELINE,
- FTM_VFILE_WAIT,
- FTM_FLEXIBLE_UPDATE,
- FTM_OCCLUSION_READBACK,
- FTM_HUD_EFFECTS,
- FTM_HUD_UPDATE,
- FTM_INVENTORY,
- FTM_AUTO_SELECT,
- FTM_ARRANGE,
- FTM_FILTER,
- FTM_REFRESH,
- FTM_SORT,
-
- // Temp
- FTM_TEMP1,
- FTM_TEMP2,
- FTM_TEMP3,
- FTM_TEMP4,
- FTM_TEMP5,
- FTM_TEMP6,
- FTM_TEMP7,
- FTM_TEMP8,
-
- FTM_OTHER, // Special, used by display code
-
- FTM_NUM_TYPES
- };
- enum { FTM_HISTORY_NUM = 60 };
- enum { FTM_MAX_DEPTH = 64 };
-
-public:
- LLFastTimer(EFastTimerType type)
+ U32 ret_val;
+ __asm
{
-#if FAST_TIMER_ON
- mType = type;
+ _emit 0x0f
+ _emit 0x31
+ shr eax,8
+ shl edx,24
+ or eax, edx
+ mov dword ptr [ret_val], eax
+ }
+ return ret_val;
+}
- // These don't get counted, because they use CPU clockticks
- //gTimerBins[gCurTimerBin]++;
- //LLTimer::sNumTimerCalls++;
+// return full timer value, *not* shifted by 8 bits
+inline U64 LLFastTimer::getCPUClockCount64()
+{
+ U64 ret_val;
+ __asm
+ {
+ _emit 0x0f
+ _emit 0x31
+ mov eax,eax
+ mov edx,edx
+ mov dword ptr [ret_val+4], edx
+ mov dword ptr [ret_val], eax
+ }
+ return ret_val;
+}
+#endif
- U64 cpu_clocks = get_cpu_clock_count();
- sStart[sCurDepth] = cpu_clocks;
- sCurDepth++;
+#if (LL_LINUX || LL_SOLARIS) && !(defined(__i386__) || defined(__amd64__))
+//
+// Linux and Solaris implementation of CPU clock - non-x86.
+// This is accurate but SLOW! Only use out of desperation.
+//
+// Try to use the MONOTONIC clock if available, this is a constant time counter
+// with nanosecond resolution (but not necessarily accuracy) and attempts are
+// made to synchronize this value between cores at kernel start. It should not
+// be affected by CPU frequency. If not available use the REALTIME clock, but
+// this may be affected by NTP adjustments or other user activity affecting
+// the system time.
+inline U64 LLFastTimer::getCPUClockCount64()
+{
+ struct timespec tp;
+
+#ifdef CLOCK_MONOTONIC // MONOTONIC supported at build-time?
+ if (-1 == clock_gettime(CLOCK_MONOTONIC,&tp)) // if MONOTONIC isn't supported at runtime then ouch, try REALTIME
#endif
- };
- ~LLFastTimer()
- {
-#if FAST_TIMER_ON
- U64 end,delta;
- int i;
-
- // These don't get counted, because they use CPU clockticks
- //gTimerBins[gCurTimerBin]++;
- //LLTimer::sNumTimerCalls++;
- end = get_cpu_clock_count();
-
- sCurDepth--;
- delta = end - sStart[sCurDepth];
- sCounter[mType] += delta;
- sCalls[mType]++;
- // Subtract delta from parents
- for (i=0; i<sCurDepth; i++)
- sStart[i] += delta;
+ clock_gettime(CLOCK_REALTIME,&tp);
+
+ return (tp.tv_sec*LLFastTimer::sClockResolution)+tp.tv_nsec;
+}
+
+inline U32 LLFastTimer::getCPUClockCount32()
+{
+ return (U32)(LLFastTimer::getCPUClockCount64() >> 8);
+}
+#endif // (LL_LINUX || LL_SOLARIS) && !(defined(__i386__) || defined(__amd64__))
+
+
+#if (LL_LINUX || LL_SOLARIS || LL_DARWIN) && (defined(__i386__) || defined(__amd64__))
+//
+// Mac+Linux+Solaris FAST x86 implementation of CPU clock
+inline U32 LLFastTimer::getCPUClockCount32()
+{
+ U64 x;
+ __asm__ volatile (".byte 0x0f, 0x31": "=A"(x));
+ return (U32)(x >> 8);
+}
+
+inline U64 LLFastTimer::getCPUClockCount64()
+{
+ U64 x;
+ __asm__ volatile (".byte 0x0f, 0x31": "=A"(x));
+ return x;
+}
#endif
- }
- static void reset();
- static U64 countsPerSecond();
-
-public:
- static int sCurDepth;
- static U64 sStart[FTM_MAX_DEPTH];
- static U64 sCounter[FTM_NUM_TYPES];
- static U64 sCalls[FTM_NUM_TYPES];
- static U64 sCountAverage[FTM_NUM_TYPES];
- static U64 sCallAverage[FTM_NUM_TYPES];
- static U64 sCountHistory[FTM_HISTORY_NUM][FTM_NUM_TYPES];
- static U64 sCallHistory[FTM_HISTORY_NUM][FTM_NUM_TYPES];
- static S32 sCurFrameIndex;
- static S32 sLastFrameIndex;
- static int sPauseHistory;
- static int sResetHistory;
- static F64 sCPUClockFrequency;
-
-private:
- EFastTimerType mType;
-};
+#if ( LL_DARWIN && !(defined(__i386__) || defined(__amd64__)))
+//
+// Mac PPC (deprecated) implementation of CPU clock
+//
+// Just use gettimeofday implementation for now
+
+inline U32 LLFastTimer::getCPUClockCount32()
+{
+ return (U32)(get_clock_count()>>8);
+}
+
+inline U64 LLFastTimer::getCPUClockCount64()
+{
+ return get_clock_count();
+}
+#endif
#endif // LL_LLFASTTIMER_H
diff --git a/indra/llcommon/llfasttimer_class.cpp b/indra/llcommon/llfasttimer_class.cpp
new file mode 100644
index 0000000000..c45921cdec
--- /dev/null
+++ b/indra/llcommon/llfasttimer_class.cpp
@@ -0,0 +1,764 @@
+/**
+ * @file llfasttimer_class.cpp
+ * @brief Implementation of the fast timer.
+ *
+ * $LicenseInfo:firstyear=2004&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$
+ */
+#include "linden_common.h"
+
+#include "llfasttimer.h"
+
+#include "llmemory.h"
+#include "llprocessor.h"
+#include "llsingleton.h"
+#include "lltreeiterators.h"
+#include "llsdserialize.h"
+
+#include <boost/bind.hpp>
+
+#if LL_WINDOWS
+#elif LL_LINUX || LL_SOLARIS
+#include <sys/time.h>
+#include <sched.h>
+#elif LL_DARWIN
+#include <sys/time.h>
+#include "lltimer.h" // get_clock_count()
+#else
+#error "architecture not supported"
+#endif
+
+//////////////////////////////////////////////////////////////////////////////
+// statics
+
+S32 LLFastTimer::sCurFrameIndex = -1;
+S32 LLFastTimer::sLastFrameIndex = -1;
+U64 LLFastTimer::sLastFrameTime = LLFastTimer::getCPUClockCount64();
+bool LLFastTimer::sPauseHistory = 0;
+bool LLFastTimer::sResetHistory = 0;
+LLFastTimer::CurTimerData LLFastTimer::sCurTimerData;
+BOOL LLFastTimer::sLog = FALSE;
+BOOL LLFastTimer::sMetricLog = FALSE;
+LLMutex* LLFastTimer::sLogLock = NULL;
+std::queue<LLSD> LLFastTimer::sLogQueue;
+
+#if LL_LINUX || LL_SOLARIS
+U64 LLFastTimer::sClockResolution = 1000000000; // Nanosecond resolution
+#else
+U64 LLFastTimer::sClockResolution = 1000000; // Microsecond resolution
+#endif
+
+std::vector<LLFastTimer::FrameState>* LLFastTimer::sTimerInfos = NULL;
+U64 LLFastTimer::sTimerCycles = 0;
+U32 LLFastTimer::sTimerCalls = 0;
+
+
+// FIXME: move these declarations to the relevant modules
+
+// helper functions
+typedef LLTreeDFSPostIter<LLFastTimer::NamedTimer, LLFastTimer::NamedTimer::child_const_iter> timer_tree_bottom_up_iterator_t;
+
+static timer_tree_bottom_up_iterator_t begin_timer_tree_bottom_up(LLFastTimer::NamedTimer& id)
+{
+ return timer_tree_bottom_up_iterator_t(&id,
+ boost::bind(boost::mem_fn(&LLFastTimer::NamedTimer::beginChildren), _1),
+ boost::bind(boost::mem_fn(&LLFastTimer::NamedTimer::endChildren), _1));
+}
+
+static timer_tree_bottom_up_iterator_t end_timer_tree_bottom_up()
+{
+ return timer_tree_bottom_up_iterator_t();
+}
+
+typedef LLTreeDFSIter<LLFastTimer::NamedTimer, LLFastTimer::NamedTimer::child_const_iter> timer_tree_dfs_iterator_t;
+
+
+static timer_tree_dfs_iterator_t begin_timer_tree(LLFastTimer::NamedTimer& id)
+{
+ return timer_tree_dfs_iterator_t(&id,
+ boost::bind(boost::mem_fn(&LLFastTimer::NamedTimer::beginChildren), _1),
+ boost::bind(boost::mem_fn(&LLFastTimer::NamedTimer::endChildren), _1));
+}
+
+static timer_tree_dfs_iterator_t end_timer_tree()
+{
+ return timer_tree_dfs_iterator_t();
+}
+
+
+
+// factory class that creates NamedTimers via static DeclareTimer objects
+class NamedTimerFactory : public LLSingleton<NamedTimerFactory>
+{
+public:
+ NamedTimerFactory()
+ : mActiveTimerRoot(NULL),
+ mTimerRoot(NULL),
+ mAppTimer(NULL),
+ mRootFrameState(NULL)
+ {}
+
+ /*virtual */ void initSingleton()
+ {
+ mTimerRoot = new LLFastTimer::NamedTimer("root");
+
+ mActiveTimerRoot = new LLFastTimer::NamedTimer("Frame");
+ mActiveTimerRoot->setCollapsed(false);
+
+ mRootFrameState = new LLFastTimer::FrameState(mActiveTimerRoot);
+ mRootFrameState->mParent = &mTimerRoot->getFrameState();
+ mActiveTimerRoot->setParent(mTimerRoot);
+
+ mAppTimer = new LLFastTimer(mRootFrameState);
+ }
+
+ ~NamedTimerFactory()
+ {
+ std::for_each(mTimers.begin(), mTimers.end(), DeletePairedPointer());
+
+ delete mAppTimer;
+ delete mActiveTimerRoot;
+ delete mTimerRoot;
+ delete mRootFrameState;
+ }
+
+ LLFastTimer::NamedTimer& createNamedTimer(const std::string& name)
+ {
+ timer_map_t::iterator found_it = mTimers.find(name);
+ if (found_it != mTimers.end())
+ {
+ return *found_it->second;
+ }
+
+ LLFastTimer::NamedTimer* timer = new LLFastTimer::NamedTimer(name);
+ timer->setParent(mTimerRoot);
+ mTimers.insert(std::make_pair(name, timer));
+
+ return *timer;
+ }
+
+ LLFastTimer::NamedTimer* getTimerByName(const std::string& name)
+ {
+ timer_map_t::iterator found_it = mTimers.find(name);
+ if (found_it != mTimers.end())
+ {
+ return found_it->second;
+ }
+ return NULL;
+ }
+
+ LLFastTimer::NamedTimer* getActiveRootTimer() { return mActiveTimerRoot; }
+ LLFastTimer::NamedTimer* getRootTimer() { return mTimerRoot; }
+ const LLFastTimer* getAppTimer() { return mAppTimer; }
+ LLFastTimer::FrameState& getRootFrameState() { return *mRootFrameState; }
+
+ typedef std::map<std::string, LLFastTimer::NamedTimer*> timer_map_t;
+ timer_map_t::iterator beginTimers() { return mTimers.begin(); }
+ timer_map_t::iterator endTimers() { return mTimers.end(); }
+ S32 timerCount() { return mTimers.size(); }
+
+private:
+ timer_map_t mTimers;
+
+ LLFastTimer::NamedTimer* mActiveTimerRoot;
+ LLFastTimer::NamedTimer* mTimerRoot;
+ LLFastTimer* mAppTimer;
+ LLFastTimer::FrameState* mRootFrameState;
+};
+
+void update_cached_pointers_if_changed()
+{
+ // detect when elements have moved and update cached pointers
+ static LLFastTimer::FrameState* sFirstTimerAddress = NULL;
+ if (&*(LLFastTimer::getFrameStateList().begin()) != sFirstTimerAddress)
+ {
+ LLFastTimer::DeclareTimer::updateCachedPointers();
+ }
+ sFirstTimerAddress = &*(LLFastTimer::getFrameStateList().begin());
+}
+
+LLFastTimer::DeclareTimer::DeclareTimer(const std::string& name, bool open )
+: mTimer(NamedTimerFactory::instance().createNamedTimer(name))
+{
+ mTimer.setCollapsed(!open);
+ mFrameState = &mTimer.getFrameState();
+ update_cached_pointers_if_changed();
+}
+
+LLFastTimer::DeclareTimer::DeclareTimer(const std::string& name)
+: mTimer(NamedTimerFactory::instance().createNamedTimer(name))
+{
+ mFrameState = &mTimer.getFrameState();
+ update_cached_pointers_if_changed();
+}
+
+// static
+void LLFastTimer::DeclareTimer::updateCachedPointers()
+{
+ DeclareTimer::LLInstanceTrackerScopedGuard guard;
+ // propagate frame state pointers to timer declarations
+ for (DeclareTimer::instance_iter it = guard.beginInstances();
+ it != guard.endInstances();
+ ++it)
+ {
+ // update cached pointer
+ it->mFrameState = &it->mTimer.getFrameState();
+ }
+}
+
+//static
+#if (LL_DARWIN || LL_LINUX || LL_SOLARIS) && !(defined(__i386__) || defined(__amd64__))
+U64 LLFastTimer::countsPerSecond() // counts per second for the *32-bit* timer
+{
+ return sClockResolution >> 8;
+}
+#else // windows or x86-mac or x86-linux or x86-solaris
+U64 LLFastTimer::countsPerSecond() // counts per second for the *32-bit* timer
+{
+ //getCPUFrequency returns MHz and sCPUClockFrequency wants to be in Hz
+ static U64 sCPUClockFrequency = U64(LLProcessorInfo().getCPUFrequency()*1000000.0);
+
+ // we drop the low-order byte in our timers, so report a lower frequency
+ return sCPUClockFrequency >> 8;
+}
+#endif
+
+LLFastTimer::FrameState::FrameState(LLFastTimer::NamedTimer* timerp)
+: mActiveCount(0),
+ mCalls(0),
+ mSelfTimeCounter(0),
+ mParent(NULL),
+ mLastCaller(NULL),
+ mMoveUpTree(false),
+ mTimer(timerp)
+{}
+
+
+LLFastTimer::NamedTimer::NamedTimer(const std::string& name)
+: mName(name),
+ mCollapsed(true),
+ mParent(NULL),
+ mTotalTimeCounter(0),
+ mCountAverage(0),
+ mCallAverage(0),
+ mNeedsSorting(false)
+{
+ info_list_t& frame_state_list = getFrameStateList();
+ mFrameStateIndex = frame_state_list.size();
+ getFrameStateList().push_back(FrameState(this));
+
+ mCountHistory = new U32[HISTORY_NUM];
+ memset(mCountHistory, 0, sizeof(U32) * HISTORY_NUM);
+ mCallHistory = new U32[HISTORY_NUM];
+ memset(mCallHistory, 0, sizeof(U32) * HISTORY_NUM);
+}
+
+LLFastTimer::NamedTimer::~NamedTimer()
+{
+ delete[] mCountHistory;
+ delete[] mCallHistory;
+}
+
+std::string LLFastTimer::NamedTimer::getToolTip(S32 history_idx)
+{
+ if (history_idx < 0)
+ {
+ // by default, show average number of calls
+ return llformat("%s (%d calls)", getName().c_str(), (S32)getCallAverage());
+ }
+ else
+ {
+ return llformat("%s (%d calls)", getName().c_str(), (S32)getHistoricalCalls(history_idx));
+ }
+}
+
+void LLFastTimer::NamedTimer::setParent(NamedTimer* parent)
+{
+ llassert_always(parent != this);
+ llassert_always(parent != NULL);
+
+ if (mParent)
+ {
+ // subtract our accumulated from previous parent
+ for (S32 i = 0; i < HISTORY_NUM; i++)
+ {
+ mParent->mCountHistory[i] -= mCountHistory[i];
+ }
+
+ // subtract average timing from previous parent
+ mParent->mCountAverage -= mCountAverage;
+
+ std::vector<NamedTimer*>& children = mParent->getChildren();
+ std::vector<NamedTimer*>::iterator found_it = std::find(children.begin(), children.end(), this);
+ if (found_it != children.end())
+ {
+ children.erase(found_it);
+ }
+ }
+
+ mParent = parent;
+ if (parent)
+ {
+ getFrameState().mParent = &parent->getFrameState();
+ parent->getChildren().push_back(this);
+ parent->mNeedsSorting = true;
+ }
+}
+
+S32 LLFastTimer::NamedTimer::getDepth()
+{
+ S32 depth = 0;
+ NamedTimer* timerp = mParent;
+ while(timerp)
+ {
+ depth++;
+ timerp = timerp->mParent;
+ }
+ return depth;
+}
+
+// static
+void LLFastTimer::NamedTimer::processTimes()
+{
+ if (sCurFrameIndex < 0) return;
+
+ buildHierarchy();
+ accumulateTimings();
+}
+
+// sort timer info structs by depth first traversal order
+struct SortTimersDFS
+{
+ bool operator()(const LLFastTimer::FrameState& i1, const LLFastTimer::FrameState& i2)
+ {
+ return i1.mTimer->getFrameStateIndex() < i2.mTimer->getFrameStateIndex();
+ }
+};
+
+// sort child timers by name
+struct SortTimerByName
+{
+ bool operator()(const LLFastTimer::NamedTimer* i1, const LLFastTimer::NamedTimer* i2)
+ {
+ return i1->getName() < i2->getName();
+ }
+};
+
+//static
+void LLFastTimer::NamedTimer::buildHierarchy()
+{
+ if (sCurFrameIndex < 0 ) return;
+
+ // set up initial tree
+ {
+ NamedTimer::LLInstanceTrackerScopedGuard guard;
+ for (instance_iter it = guard.beginInstances();
+ it != guard.endInstances();
+ ++it)
+ {
+ NamedTimer& timer = *it;
+ if (&timer == NamedTimerFactory::instance().getRootTimer()) continue;
+
+ // bootstrap tree construction by attaching to last timer to be on stack
+ // when this timer was called
+ if (timer.getFrameState().mLastCaller && timer.mParent == NamedTimerFactory::instance().getRootTimer())
+ {
+ timer.setParent(timer.getFrameState().mLastCaller->mTimer);
+ // no need to push up tree on first use, flag can be set spuriously
+ timer.getFrameState().mMoveUpTree = false;
+ }
+ }
+ }
+
+ // bump timers up tree if they've been flagged as being in the wrong place
+ // do this in a bottom up order to promote descendants first before promoting ancestors
+ // this preserves partial order derived from current frame's observations
+ for(timer_tree_bottom_up_iterator_t it = begin_timer_tree_bottom_up(*NamedTimerFactory::instance().getRootTimer());
+ it != end_timer_tree_bottom_up();
+ ++it)
+ {
+ NamedTimer* timerp = *it;
+ // skip root timer
+ if (timerp == NamedTimerFactory::instance().getRootTimer()) continue;
+
+ if (timerp->getFrameState().mMoveUpTree)
+ {
+ // since ancestors have already been visited, reparenting won't affect tree traversal
+ //step up tree, bringing our descendants with us
+ //llinfos << "Moving " << timerp->getName() << " from child of " << timerp->getParent()->getName() <<
+ // " to child of " << timerp->getParent()->getParent()->getName() << llendl;
+ timerp->setParent(timerp->getParent()->getParent());
+ timerp->getFrameState().mMoveUpTree = false;
+
+ // don't bubble up any ancestors until descendants are done bubbling up
+ it.skipAncestors();
+ }
+ }
+
+ // sort timers by time last called, so call graph makes sense
+ for(timer_tree_dfs_iterator_t it = begin_timer_tree(*NamedTimerFactory::instance().getRootTimer());
+ it != end_timer_tree();
+ ++it)
+ {
+ NamedTimer* timerp = (*it);
+ if (timerp->mNeedsSorting)
+ {
+ std::sort(timerp->getChildren().begin(), timerp->getChildren().end(), SortTimerByName());
+ }
+ timerp->mNeedsSorting = false;
+ }
+}
+
+//static
+void LLFastTimer::NamedTimer::accumulateTimings()
+{
+ U32 cur_time = getCPUClockCount32();
+
+ // walk up stack of active timers and accumulate current time while leaving timing structures active
+ LLFastTimer* cur_timer = sCurTimerData.mCurTimer;
+ // root defined by parent pointing to self
+ CurTimerData* cur_data = &sCurTimerData;
+ while(cur_timer->mLastTimerData.mCurTimer != cur_timer)
+ {
+ U32 cumulative_time_delta = cur_time - cur_timer->mStartTime;
+ U32 self_time_delta = cumulative_time_delta - cur_data->mChildTime;
+ cur_data->mChildTime = 0;
+ cur_timer->mFrameState->mSelfTimeCounter += self_time_delta;
+ cur_timer->mStartTime = cur_time;
+
+ cur_data = &cur_timer->mLastTimerData;
+ cur_data->mChildTime += cumulative_time_delta;
+
+ cur_timer = cur_timer->mLastTimerData.mCurTimer;
+ }
+
+ // traverse tree in DFS post order, or bottom up
+ for(timer_tree_bottom_up_iterator_t it = begin_timer_tree_bottom_up(*NamedTimerFactory::instance().getActiveRootTimer());
+ it != end_timer_tree_bottom_up();
+ ++it)
+ {
+ NamedTimer* timerp = (*it);
+ timerp->mTotalTimeCounter = timerp->getFrameState().mSelfTimeCounter;
+ for (child_const_iter child_it = timerp->beginChildren(); child_it != timerp->endChildren(); ++child_it)
+ {
+ timerp->mTotalTimeCounter += (*child_it)->mTotalTimeCounter;
+ }
+
+ S32 cur_frame = sCurFrameIndex;
+ if (cur_frame >= 0)
+ {
+ // update timer history
+ int hidx = cur_frame % HISTORY_NUM;
+
+ timerp->mCountHistory[hidx] = timerp->mTotalTimeCounter;
+ timerp->mCountAverage = ((U64)timerp->mCountAverage * cur_frame + timerp->mTotalTimeCounter) / (cur_frame+1);
+ timerp->mCallHistory[hidx] = timerp->getFrameState().mCalls;
+ timerp->mCallAverage = ((U64)timerp->mCallAverage * cur_frame + timerp->getFrameState().mCalls) / (cur_frame+1);
+ }
+ }
+}
+
+// static
+void LLFastTimer::NamedTimer::resetFrame()
+{
+ if (sLog)
+ { //output current frame counts to performance log
+ F64 iclock_freq = 1000.0 / countsPerSecond(); // good place to calculate clock frequency
+
+ F64 total_time = 0;
+ LLSD sd;
+
+ {
+ NamedTimer::LLInstanceTrackerScopedGuard guard;
+ for (NamedTimer::instance_iter it = guard.beginInstances();
+ it != guard.endInstances();
+ ++it)
+ {
+ NamedTimer& timer = *it;
+ FrameState& info = timer.getFrameState();
+ sd[timer.getName()]["Time"] = (LLSD::Real) (info.mSelfTimeCounter*iclock_freq);
+ sd[timer.getName()]["Calls"] = (LLSD::Integer) info.mCalls;
+
+ // computing total time here because getting the root timer's getCountHistory
+ // doesn't work correctly on the first frame
+ total_time = total_time + info.mSelfTimeCounter * iclock_freq;
+ }
+ }
+
+ sd["Total"]["Time"] = (LLSD::Real) total_time;
+ sd["Total"]["Calls"] = (LLSD::Integer) 1;
+
+ {
+ LLMutexLock lock(sLogLock);
+ sLogQueue.push(sd);
+ }
+ }
+
+
+ // tag timers by position in depth first traversal of tree
+ S32 index = 0;
+ for(timer_tree_dfs_iterator_t it = begin_timer_tree(*NamedTimerFactory::instance().getRootTimer());
+ it != end_timer_tree();
+ ++it)
+ {
+ NamedTimer* timerp = (*it);
+
+ timerp->mFrameStateIndex = index;
+ index++;
+
+ llassert_always(timerp->mFrameStateIndex < (S32)getFrameStateList().size());
+ }
+
+ // sort timers by dfs traversal order to improve cache coherency
+ std::sort(getFrameStateList().begin(), getFrameStateList().end(), SortTimersDFS());
+
+ // update pointers into framestatelist now that we've sorted it
+ DeclareTimer::updateCachedPointers();
+
+ // reset for next frame
+ {
+ NamedTimer::LLInstanceTrackerScopedGuard guard;
+ for (NamedTimer::instance_iter it = guard.beginInstances();
+ it != guard.endInstances();
+ ++it)
+ {
+ NamedTimer& timer = *it;
+
+ FrameState& info = timer.getFrameState();
+ info.mSelfTimeCounter = 0;
+ info.mCalls = 0;
+ info.mLastCaller = NULL;
+ info.mMoveUpTree = false;
+ // update parent pointer in timer state struct
+ if (timer.mParent)
+ {
+ info.mParent = &timer.mParent->getFrameState();
+ }
+ }
+ }
+
+ //sTimerCycles = 0;
+ //sTimerCalls = 0;
+}
+
+//static
+void LLFastTimer::NamedTimer::reset()
+{
+ resetFrame(); // reset frame data
+
+ // walk up stack of active timers and reset start times to current time
+ // effectively zeroing out any accumulated time
+ U32 cur_time = getCPUClockCount32();
+
+ // root defined by parent pointing to self
+ CurTimerData* cur_data = &sCurTimerData;
+ LLFastTimer* cur_timer = cur_data->mCurTimer;
+ while(cur_timer->mLastTimerData.mCurTimer != cur_timer)
+ {
+ cur_timer->mStartTime = cur_time;
+ cur_data->mChildTime = 0;
+
+ cur_data = &cur_timer->mLastTimerData;
+ cur_timer = cur_data->mCurTimer;
+ }
+
+ // reset all history
+ {
+ NamedTimer::LLInstanceTrackerScopedGuard guard;
+ for (NamedTimer::instance_iter it = guard.beginInstances();
+ it != guard.endInstances();
+ ++it)
+ {
+ NamedTimer& timer = *it;
+ if (&timer != NamedTimerFactory::instance().getRootTimer())
+ {
+ timer.setParent(NamedTimerFactory::instance().getRootTimer());
+ }
+
+ timer.mCountAverage = 0;
+ timer.mCallAverage = 0;
+ memset(timer.mCountHistory, 0, sizeof(U32) * HISTORY_NUM);
+ memset(timer.mCallHistory, 0, sizeof(U32) * HISTORY_NUM);
+ }
+ }
+
+ sLastFrameIndex = 0;
+ sCurFrameIndex = 0;
+}
+
+//static
+LLFastTimer::info_list_t& LLFastTimer::getFrameStateList()
+{
+ if (!sTimerInfos)
+ {
+ sTimerInfos = new info_list_t();
+ }
+ return *sTimerInfos;
+}
+
+
+U32 LLFastTimer::NamedTimer::getHistoricalCount(S32 history_index) const
+{
+ S32 history_idx = (getLastFrameIndex() + history_index) % LLFastTimer::NamedTimer::HISTORY_NUM;
+ return mCountHistory[history_idx];
+}
+
+U32 LLFastTimer::NamedTimer::getHistoricalCalls(S32 history_index ) const
+{
+ S32 history_idx = (getLastFrameIndex() + history_index) % LLFastTimer::NamedTimer::HISTORY_NUM;
+ return mCallHistory[history_idx];
+}
+
+LLFastTimer::FrameState& LLFastTimer::NamedTimer::getFrameState() const
+{
+ llassert_always(mFrameStateIndex >= 0);
+ if (this == NamedTimerFactory::instance().getActiveRootTimer())
+ {
+ return NamedTimerFactory::instance().getRootFrameState();
+ }
+ return getFrameStateList()[mFrameStateIndex];
+}
+
+// static
+LLFastTimer::NamedTimer& LLFastTimer::NamedTimer::getRootNamedTimer()
+{
+ return *NamedTimerFactory::instance().getActiveRootTimer();
+}
+
+std::vector<LLFastTimer::NamedTimer*>::const_iterator LLFastTimer::NamedTimer::beginChildren()
+{
+ return mChildren.begin();
+}
+
+std::vector<LLFastTimer::NamedTimer*>::const_iterator LLFastTimer::NamedTimer::endChildren()
+{
+ return mChildren.end();
+}
+
+std::vector<LLFastTimer::NamedTimer*>& LLFastTimer::NamedTimer::getChildren()
+{
+ return mChildren;
+}
+
+//static
+void LLFastTimer::nextFrame()
+{
+ countsPerSecond(); // good place to calculate clock frequency
+ U64 frame_time = getCPUClockCount64();
+ if ((frame_time - sLastFrameTime) >> 8 > 0xffffffff)
+ {
+ llinfos << "Slow frame, fast timers inaccurate" << llendl;
+ }
+
+ if (sPauseHistory)
+ {
+ sResetHistory = true;
+ }
+ else if (sResetHistory)
+ {
+ sLastFrameIndex = 0;
+ sCurFrameIndex = 0;
+ sResetHistory = false;
+ }
+ else // not paused
+ {
+ NamedTimer::processTimes();
+ sLastFrameIndex = sCurFrameIndex++;
+ }
+
+ // get ready for next frame
+ NamedTimer::resetFrame();
+ sLastFrameTime = frame_time;
+}
+
+//static
+void LLFastTimer::dumpCurTimes()
+{
+ // accumulate timings, etc.
+ NamedTimer::processTimes();
+
+ F64 clock_freq = (F64)countsPerSecond();
+ F64 iclock_freq = 1000.0 / clock_freq; // clock_ticks -> milliseconds
+
+ // walk over timers in depth order and output timings
+ for(timer_tree_dfs_iterator_t it = begin_timer_tree(*NamedTimerFactory::instance().getRootTimer());
+ it != end_timer_tree();
+ ++it)
+ {
+ NamedTimer* timerp = (*it);
+ F64 total_time_ms = ((F64)timerp->getHistoricalCount(0) * iclock_freq);
+ // Don't bother with really brief times, keep output concise
+ if (total_time_ms < 0.1) continue;
+
+ std::ostringstream out_str;
+ for (S32 i = 0; i < timerp->getDepth(); i++)
+ {
+ out_str << "\t";
+ }
+
+
+ out_str << timerp->getName() << " "
+ << std::setprecision(3) << total_time_ms << " ms, "
+ << timerp->getHistoricalCalls(0) << " calls";
+
+ llinfos << out_str.str() << llendl;
+ }
+}
+
+//static
+void LLFastTimer::reset()
+{
+ NamedTimer::reset();
+}
+
+
+//static
+void LLFastTimer::writeLog(std::ostream& os)
+{
+ while (!sLogQueue.empty())
+ {
+ LLSD& sd = sLogQueue.front();
+ LLSDSerialize::toXML(sd, os);
+ LLMutexLock lock(sLogLock);
+ sLogQueue.pop();
+ }
+}
+
+//static
+const LLFastTimer::NamedTimer* LLFastTimer::getTimerByName(const std::string& name)
+{
+ return NamedTimerFactory::instance().getTimerByName(name);
+}
+
+LLFastTimer::LLFastTimer(LLFastTimer::FrameState* state)
+: mFrameState(state)
+{
+ U32 start_time = getCPUClockCount32();
+ mStartTime = start_time;
+ mFrameState->mActiveCount++;
+ LLFastTimer::sCurTimerData.mCurTimer = this;
+ LLFastTimer::sCurTimerData.mFrameState = mFrameState;
+ LLFastTimer::sCurTimerData.mChildTime = 0;
+ mLastTimerData = LLFastTimer::sCurTimerData;
+}
+
+
+//////////////////////////////////////////////////////////////////////////////
diff --git a/indra/llcommon/llfasttimer_class.h b/indra/llcommon/llfasttimer_class.h
new file mode 100644
index 0000000000..1158ac5140
--- /dev/null
+++ b/indra/llcommon/llfasttimer_class.h
@@ -0,0 +1,266 @@
+/**
+ * @file llfasttimer_class.h
+ * @brief Declaration of a fast timer.
+ *
+ * $LicenseInfo:firstyear=2004&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$
+ */
+
+#ifndef LL_FASTTIMER_CLASS_H
+#define LL_FASTTIMER_CLASS_H
+
+#include "llinstancetracker.h"
+
+#define FAST_TIMER_ON 1
+#define TIME_FAST_TIMERS 0
+
+class LLMutex;
+
+#include <queue>
+#include "llsd.h"
+
+class LL_COMMON_API LLFastTimer
+{
+public:
+ class NamedTimer;
+
+ struct LL_COMMON_API FrameState
+ {
+ FrameState(NamedTimer* timerp);
+
+ U32 mSelfTimeCounter;
+ U32 mCalls;
+ FrameState* mParent; // info for caller timer
+ FrameState* mLastCaller; // used to bootstrap tree construction
+ NamedTimer* mTimer;
+ U16 mActiveCount; // number of timers with this ID active on stack
+ bool mMoveUpTree; // needs to be moved up the tree of timers at the end of frame
+ };
+
+ // stores a "named" timer instance to be reused via multiple LLFastTimer stack instances
+ class LL_COMMON_API NamedTimer
+ : public LLInstanceTracker<NamedTimer>
+ {
+ friend class DeclareTimer;
+ public:
+ ~NamedTimer();
+
+ enum { HISTORY_NUM = 60 };
+
+ const std::string& getName() const { return mName; }
+ NamedTimer* getParent() const { return mParent; }
+ void setParent(NamedTimer* parent);
+ S32 getDepth();
+ std::string getToolTip(S32 history_index = -1);
+
+ typedef std::vector<NamedTimer*>::const_iterator child_const_iter;
+ child_const_iter beginChildren();
+ child_const_iter endChildren();
+ std::vector<NamedTimer*>& getChildren();
+
+ void setCollapsed(bool collapsed) { mCollapsed = collapsed; }
+ bool getCollapsed() const { return mCollapsed; }
+
+ U32 getCountAverage() const { return mCountAverage; }
+ U32 getCallAverage() const { return mCallAverage; }
+
+ U32 getHistoricalCount(S32 history_index = 0) const;
+ U32 getHistoricalCalls(S32 history_index = 0) const;
+
+ static NamedTimer& getRootNamedTimer();
+
+ S32 getFrameStateIndex() const { return mFrameStateIndex; }
+
+ FrameState& getFrameState() const;
+
+ private:
+ friend class LLFastTimer;
+ friend class NamedTimerFactory;
+
+ //
+ // methods
+ //
+ NamedTimer(const std::string& name);
+ // recursive call to gather total time from children
+ static void accumulateTimings();
+
+ // updates cumulative times and hierarchy,
+ // can be called multiple times in a frame, at any point
+ static void processTimes();
+
+ static void buildHierarchy();
+ static void resetFrame();
+ static void reset();
+
+ //
+ // members
+ //
+ S32 mFrameStateIndex;
+
+ std::string mName;
+
+ U32 mTotalTimeCounter;
+
+ U32 mCountAverage;
+ U32 mCallAverage;
+
+ U32* mCountHistory;
+ U32* mCallHistory;
+
+ // tree structure
+ NamedTimer* mParent; // NamedTimer of caller(parent)
+ std::vector<NamedTimer*> mChildren;
+ bool mCollapsed; // don't show children
+ bool mNeedsSorting; // sort children whenever child added
+ };
+
+ // used to statically declare a new named timer
+ class LL_COMMON_API DeclareTimer
+ : public LLInstanceTracker<DeclareTimer>
+ {
+ friend class LLFastTimer;
+ public:
+ DeclareTimer(const std::string& name, bool open);
+ DeclareTimer(const std::string& name);
+
+ static void updateCachedPointers();
+
+ private:
+ NamedTimer& mTimer;
+ FrameState* mFrameState;
+ };
+
+public:
+ LLFastTimer(LLFastTimer::FrameState* state);
+
+ LL_FORCE_INLINE LLFastTimer(LLFastTimer::DeclareTimer& timer)
+ : mFrameState(timer.mFrameState)
+ {
+#if TIME_FAST_TIMERS
+ U64 timer_start = getCPUClockCount64();
+#endif
+#if FAST_TIMER_ON
+ LLFastTimer::FrameState* frame_state = mFrameState;
+ mStartTime = getCPUClockCount32();
+
+ frame_state->mActiveCount++;
+ frame_state->mCalls++;
+ // keep current parent as long as it is active when we are
+ frame_state->mMoveUpTree |= (frame_state->mParent->mActiveCount == 0);
+
+ LLFastTimer::CurTimerData* cur_timer_data = &LLFastTimer::sCurTimerData;
+ mLastTimerData = *cur_timer_data;
+ cur_timer_data->mCurTimer = this;
+ cur_timer_data->mFrameState = frame_state;
+ cur_timer_data->mChildTime = 0;
+#endif
+#if TIME_FAST_TIMERS
+ U64 timer_end = getCPUClockCount64();
+ sTimerCycles += timer_end - timer_start;
+#endif
+ }
+
+ LL_FORCE_INLINE ~LLFastTimer()
+ {
+#if TIME_FAST_TIMERS
+ U64 timer_start = getCPUClockCount64();
+#endif
+#if FAST_TIMER_ON
+ LLFastTimer::FrameState* frame_state = mFrameState;
+ U32 total_time = getCPUClockCount32() - mStartTime;
+
+ frame_state->mSelfTimeCounter += total_time - LLFastTimer::sCurTimerData.mChildTime;
+ frame_state->mActiveCount--;
+
+ // store last caller to bootstrap tree creation
+ // do this in the destructor in case of recursion to get topmost caller
+ frame_state->mLastCaller = mLastTimerData.mFrameState;
+
+ // we are only tracking self time, so subtract our total time delta from parents
+ mLastTimerData.mChildTime += total_time;
+
+ LLFastTimer::sCurTimerData = mLastTimerData;
+#endif
+#if TIME_FAST_TIMERS
+ U64 timer_end = getCPUClockCount64();
+ sTimerCycles += timer_end - timer_start;
+ sTimerCalls++;
+#endif
+ }
+
+public:
+ static LLMutex* sLogLock;
+ static std::queue<LLSD> sLogQueue;
+ static BOOL sLog;
+ static BOOL sMetricLog;
+ static bool sPauseHistory;
+ static bool sResetHistory;
+ static U64 sTimerCycles;
+ static U32 sTimerCalls;
+
+ typedef std::vector<FrameState> info_list_t;
+ static info_list_t& getFrameStateList();
+
+
+ // call this once a frame to reset timers
+ static void nextFrame();
+
+ // dumps current cumulative frame stats to log
+ // call nextFrame() to reset timers
+ static void dumpCurTimes();
+
+ // call this to reset timer hierarchy, averages, etc.
+ static void reset();
+
+ static U64 countsPerSecond();
+ static S32 getLastFrameIndex() { return sLastFrameIndex; }
+ static S32 getCurFrameIndex() { return sCurFrameIndex; }
+
+ static void writeLog(std::ostream& os);
+ static const NamedTimer* getTimerByName(const std::string& name);
+
+ struct CurTimerData
+ {
+ LLFastTimer* mCurTimer;
+ FrameState* mFrameState;
+ U32 mChildTime;
+ };
+ static CurTimerData sCurTimerData;
+
+private:
+ static U32 getCPUClockCount32();
+ static U64 getCPUClockCount64();
+ static U64 sClockResolution;
+
+ static S32 sCurFrameIndex;
+ static S32 sLastFrameIndex;
+ static U64 sLastFrameTime;
+ static info_list_t* sTimerInfos;
+
+ U32 mStartTime;
+ LLFastTimer::FrameState* mFrameState;
+ LLFastTimer::CurTimerData mLastTimerData;
+
+};
+
+typedef class LLFastTimer LLFastTimer;
+
+#endif // LL_LLFASTTIMER_CLASS_H
diff --git a/indra/llcommon/llfile.cpp b/indra/llcommon/llfile.cpp
index c44650009d..289ce0bc2c 100644
--- a/indra/llcommon/llfile.cpp
+++ b/indra/llcommon/llfile.cpp
@@ -5,33 +5,32 @@
* @brief Implementation of cross-platform POSIX file buffer and c++
* stream classes.
*
- * $LicenseInfo:firstyear=2006&license=viewergpl$
- *
- * Copyright (c) 2006-2007, Linden Research, Inc.
- *
+ * $LicenseInfo:firstyear=2006&license=viewerlgpl$
* Second Life Viewer Source Code
- * The source code in this file ("Source Code") is provided by Linden Lab
- * to you under the terms of the GNU General Public License, version 2.0
- * ("GPL"), unless you have obtained a separate licensing agreement
- * ("Other License"), formally executed by you and Linden Lab. Terms of
- * the GPL can be found in doc/GPL-license.txt in this distribution, or
- * online at http://secondlife.com/developers/opensource/gplv2
+ * Copyright (C) 2010, Linden Research, Inc.
*
- * There are special exceptions to the terms and conditions of the GPL as
- * it is applied to this Source Code. View the full text of the exception
- * in the file doc/FLOSS-exception.txt in this software distribution, or
- * online at http://secondlife.com/developers/opensource/flossexception
+ * 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.
*
- * By copying, modifying or distributing this software, you acknowledge
- * that you have read and understood your obligations described above,
- * and agree to abide by those obligations.
+ * 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.
*
- * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
- * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
- * COMPLETENESS OR PERFORMANCE.
+ * 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 LL_WINDOWS
+#include <windows.h>
+#endif
+
#include "linden_common.h"
#include "llfile.h"
#include "llstring.h"
@@ -40,7 +39,7 @@
using namespace std;
// static
-int LLFile::mkdir(const char* dirname, int perms)
+int LLFile::mkdir(const std::string& dirname, int perms)
{
#if LL_WINDOWS
// permissions are ignored on Windows
@@ -48,12 +47,12 @@ int LLFile::mkdir(const char* dirname, int perms)
llutf16string utf16dirname = utf8str_to_utf16str(utf8dirname);
return _wmkdir(utf16dirname.c_str());
#else
- return ::mkdir(dirname, (mode_t)perms);
+ return ::mkdir(dirname.c_str(), (mode_t)perms);
#endif
}
// static
-int LLFile::rmdir(const char* dirname)
+int LLFile::rmdir(const std::string& dirname)
{
#if LL_WINDOWS
// permissions are ignored on Windows
@@ -61,29 +60,29 @@ int LLFile::rmdir(const char* dirname)
llutf16string utf16dirname = utf8str_to_utf16str(utf8dirname);
return _wrmdir(utf16dirname.c_str());
#else
- return ::rmdir(dirname);
+ return ::rmdir(dirname.c_str());
#endif
}
// static
-LLFILE* LLFile::fopen(const char* filename, const char* mode) /* Flawfinder: ignore */
+LLFILE* LLFile::fopen(const std::string& filename, const char* mode) /* Flawfinder: ignore */
{
#if LL_WINDOWS
std::string utf8filename = filename;
- std::string utf8mode = mode;
+ std::string utf8mode = std::string(mode);
llutf16string utf16filename = utf8str_to_utf16str(utf8filename);
llutf16string utf16mode = utf8str_to_utf16str(utf8mode);
return _wfopen(utf16filename.c_str(),utf16mode.c_str());
#else
- return ::fopen(filename,mode); /* Flawfinder: ignore */
+ return ::fopen(filename.c_str(),mode); /* Flawfinder: ignore */
#endif
}
-LLFILE* LLFile::_fsopen(const char* filename, const char* mode, int sharingFlag)
+LLFILE* LLFile::_fsopen(const std::string& filename, const char* mode, int sharingFlag)
{
#if LL_WINDOWS
std::string utf8filename = filename;
- std::string utf8mode = mode;
+ std::string utf8mode = std::string(mode);
llutf16string utf16filename = utf8str_to_utf16str(utf8filename);
llutf16string utf16mode = utf8str_to_utf16str(utf8mode);
return _wfsopen(utf16filename.c_str(),utf16mode.c_str(),sharingFlag);
@@ -93,18 +92,18 @@ LLFILE* LLFile::_fsopen(const char* filename, const char* mode, int sharingFlag)
#endif
}
-int LLFile::remove(const char* filename)
+int LLFile::remove(const std::string& filename)
{
#if LL_WINDOWS
std::string utf8filename = filename;
llutf16string utf16filename = utf8str_to_utf16str(utf8filename);
return _wremove(utf16filename.c_str());
#else
- return ::remove(filename);
+ return ::remove(filename.c_str());
#endif
}
-int LLFile::rename(const char* filename, const char* newname)
+int LLFile::rename(const std::string& filename, const std::string& newname)
{
#if LL_WINDOWS
std::string utf8filename = filename;
@@ -113,19 +112,63 @@ int LLFile::rename(const char* filename, const char* newname)
llutf16string utf16newname = utf8str_to_utf16str(utf8newname);
return _wrename(utf16filename.c_str(),utf16newname.c_str());
#else
- return ::rename(filename,newname);
+ return ::rename(filename.c_str(),newname.c_str());
#endif
}
-int LLFile::stat(const char* filename, llstat* filestatus)
+int LLFile::stat(const std::string& filename, llstat* filestatus)
{
#if LL_WINDOWS
std::string utf8filename = filename;
llutf16string utf16filename = utf8str_to_utf16str(utf8filename);
return _wstat(utf16filename.c_str(),filestatus);
#else
- return ::stat(filename,filestatus);
+ return ::stat(filename.c_str(),filestatus);
+#endif
+}
+
+bool LLFile::isdir(const std::string& filename)
+{
+ llstat st;
+
+ return stat(filename, &st) == 0 && S_ISDIR(st.st_mode);
+}
+
+bool LLFile::isfile(const std::string& filename)
+{
+ llstat st;
+
+ return stat(filename, &st) == 0 && S_ISREG(st.st_mode);
+}
+
+const char *LLFile::tmpdir()
+{
+ static std::string utf8path;
+
+ if (utf8path.empty())
+ {
+ char sep;
+#if LL_WINDOWS
+ sep = '\\';
+
+ DWORD len = GetTempPathW(0, L"");
+ llutf16string utf16path;
+ utf16path.resize(len + 1);
+ len = GetTempPathW(static_cast<DWORD>(utf16path.size()), &utf16path[0]);
+ utf8path = utf16str_to_utf8str(utf16path);
+#else
+ sep = '/';
+
+ char *env = getenv("TMPDIR");
+
+ utf8path = env ? env : "/tmp/";
#endif
+ if (utf8path[utf8path.size() - 1] != sep)
+ {
+ utf8path += sep;
+ }
+ }
+ return utf8path.c_str();
}
@@ -133,7 +176,7 @@ int LLFile::stat(const char* filename, llstat* filestatus)
#if USE_LLFILESTREAMS
-LLFILE * LLFile::_Fiopen(const char *filename, std::ios::openmode mode,int) // protection currently unused
+LLFILE * LLFile::_Fiopen(const std::string& filename, std::ios::openmode mode,int) // protection currently unused
{ // open a file
static const char *mods[] =
{ // fopen mode strings corresponding to valid[i]
@@ -160,7 +203,7 @@ LLFILE * LLFile::_Fiopen(const char *filename, std::ios::openmode mode,int) // p
| ios_base::binary,
0};
- FILE *fp = 0;
+ LLFILE *fp = 0;
int n;
ios_base::openmode atendflag = mode & ios_base::ate;
ios_base::openmode norepflag = mode & ios_base::_Noreplace;
@@ -202,12 +245,12 @@ void llifstream::close()
}
}
-void llifstream::open(const char* _Filename, /* Flawfinder: ignore */
+void llifstream::open(const std::string& _Filename, /* Flawfinder: ignore */
ios_base::openmode _Mode,
int _Prot)
{ // open a C stream with specified mode
- FILE* filep = LLFile::_Fiopen(_Filename,_Mode | ios_base::in, _Prot);
+ LLFILE* filep = LLFile::_Fiopen(_Filename,_Mode | ios_base::in, _Prot);
if(filep == NULL)
{
_Myios::setstate(ios_base::failbit); /*Flawfinder: ignore*/
@@ -234,7 +277,7 @@ llifstream::~llifstream()
delete _Filebuffer;
}
-llifstream::llifstream(const char *_Filename,
+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)
@@ -253,12 +296,12 @@ bool llofstream::is_open() const
return false;
}
-void llofstream::open(const char* _Filename, /* Flawfinder: ignore */
+void llofstream::open(const std::string& _Filename, /* Flawfinder: ignore */
ios_base::openmode _Mode,
int _Prot)
{ // open a C stream with specified mode
- FILE* filep = LLFile::_Fiopen(_Filename,_Mode | ios_base::out, _Prot);
+ LLFILE* filep = LLFile::_Fiopen(_Filename,_Mode | ios_base::out, _Prot);
if(filep == NULL)
{
_Myios::setstate(ios_base::failbit); /*Flawfinder: ignore*/
@@ -266,6 +309,7 @@ void llofstream::open(const char* _Filename, /* Flawfinder: ignore */
}
llassert(_Filebuffer==NULL);
_Filebuffer = new _Myfb(filep);
+ _ShouldClose = true;
_Myios::init(_Filebuffer);
}
@@ -278,10 +322,10 @@ void llofstream::close()
}
}
-llofstream::llofstream(const char *_Filename,
+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)
+ : 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 */
}
@@ -289,7 +333,10 @@ llofstream::llofstream(const char *_Filename,
llofstream::~llofstream()
{
// destroy the object
- close();
+ if (_ShouldClose)
+ {
+ close();
+ }
delete _Filebuffer;
}
diff --git a/indra/llcommon/llfile.h b/indra/llcommon/llfile.h
index 7a1542a6fa..4913af7cb5 100644
--- a/indra/llcommon/llfile.h
+++ b/indra/llcommon/llfile.h
@@ -5,30 +5,25 @@
* @brief Declaration of cross-platform POSIX file buffer and c++
* stream classes.
*
- * $LicenseInfo:firstyear=2006&license=viewergpl$
- *
- * Copyright (c) 2006-2007, Linden Research, Inc.
- *
+ * $LicenseInfo:firstyear=2006&license=viewerlgpl$
* Second Life Viewer Source Code
- * The source code in this file ("Source Code") is provided by Linden Lab
- * to you under the terms of the GNU General Public License, version 2.0
- * ("GPL"), unless you have obtained a separate licensing agreement
- * ("Other License"), formally executed by you and Linden Lab. Terms of
- * the GPL can be found in doc/GPL-license.txt in this distribution, or
- * online at http://secondlife.com/developers/opensource/gplv2
+ * 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.
*
- * There are special exceptions to the terms and conditions of the GPL as
- * it is applied to this Source Code. View the full text of the exception
- * in the file doc/FLOSS-exception.txt in this software distribution, or
- * online at http://secondlife.com/developers/opensource/flossexception
+ * 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.
*
- * By copying, modifying or distributing this software, you acknowledge
- * that you have read and understood your obligations described above,
- * and agree to abide by those obligations.
+ * 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
*
- * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
- * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
- * COMPLETENESS OR PERFORMANCE.
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
* $/LicenseInfo$
*/
@@ -42,43 +37,59 @@
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
// windows version of stat function and stat data structure are called _stat
typedef struct _stat llstat;
#else
-#include <sys/stat.h>
typedef struct stat llstat;
#endif
-class LLFile
+#ifndef S_ISREG
+# define S_ISREG(x) (((x) & S_IFMT) == S_IFREG)
+#endif
+
+#ifndef S_ISDIR
+# define S_ISDIR(x) (((x) & S_IFMT) == S_IFDIR)
+#endif
+
+#include "llstring.h" // safe char* -> std::string conversion
+
+class LL_COMMON_API LLFile
{
public:
// All these functions take UTF8 path/filenames.
- static LLFILE* fopen(const char* filename,const char* accessmode); /* Flawfinder: ignore */
- static LLFILE* _fsopen(const char* filename,const char* accessmode,int sharingFlag);
+ static LLFILE* fopen(const std::string& filename,const char* accessmode); /* Flawfinder: ignore */
+ static LLFILE* _fsopen(const std::string& filename,const char* accessmode,int sharingFlag);
// perms is a permissions mask like 0777 or 0700. In most cases it will
// be overridden by the user's umask. It is ignored on Windows.
- static int mkdir(const char* filename, int perms = 0700);
+ static int mkdir(const std::string& filename, int perms = 0700);
- static int rmdir(const char* filename);
- static int remove(const char* filename);
- static int rename(const char* filename,const char* newname);
- static int stat(const char* filename,llstat* file_status);
- static LLFILE * _Fiopen(const char *filename, std::ios::openmode mode,int); // protection currently unused
+ static int rmdir(const std::string& filename);
+ static int remove(const std::string& filename);
+ static int rename(const std::string& filename,const std::string& newname);
+ 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 const char * tmpdir();
};
#if USE_LLFILESTREAMS
-class llifstream : public std::basic_istream < char , std::char_traits < char > >
+class LL_COMMON_API llifstream : public std::basic_istream < char , std::char_traits < char > >
{
// input stream associated with a C stream
public:
@@ -91,7 +102,7 @@ public:
{ // construct unopened
}
- explicit llifstream(const char *_Filename,
+ explicit llifstream(const std::string& _Filename,
ios_base::openmode _Mode = ios_base::in,
int _Prot = (int)ios_base::_Openprot);
@@ -108,7 +119,7 @@ public:
return _Filebuffer;
}
bool is_open() const;
- void open(const char* _Filename, /* Flawfinder: ignore */
+ void open(const std::string& _Filename, /* Flawfinder: ignore */
ios_base::openmode _Mode = ios_base::in,
int _Prot = (int)ios_base::_Openprot);
void close();
@@ -119,7 +130,7 @@ private:
};
-class llofstream : public std::basic_ostream< char , std::char_traits < char > >
+class LL_COMMON_API llofstream : public std::basic_ostream< char , std::char_traits < char > >
{
public:
typedef std::basic_ostream< char , std::char_traits < char > > _Myt;
@@ -127,18 +138,19 @@ public:
typedef std::basic_ios<char,std::char_traits < char > > _Myios;
llofstream()
- : std::basic_ostream<char,std::char_traits < char > >(NULL,true),_Filebuffer(NULL)
+ : std::basic_ostream<char,std::char_traits < char > >(NULL,true),_Filebuffer(NULL),_ShouldClose(false)
{ // construct unopened
}
- explicit llofstream(const char *_Filename,
+ 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)
+ _Filebuffer(new _Myfb(_File)),//_File)
+ _ShouldClose(false)
{ // construct with specified C stream
}
@@ -151,20 +163,58 @@ public:
bool is_open() const;
- void open(const char *_Filename,ios_base::openmode _Mode = ios_base::out,int _Prot = (int)ios_base::_Openprot); /* Flawfinder: ignore */
+ void open(const std::string& _Filename,ios_base::openmode _Mode = ios_base::out,int _Prot = (int)ios_base::_Openprot); /* Flawfinder: ignore */
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
+//#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);
+ }
+};
+
+
+class LL_COMMON_API llofstream : public std::ofstream
+{
+public:
+ llofstream() : std::ofstream()
+ {
+ }
+
+ explicit llofstream(const std::string& _Filename, std::_Ios_Openmode _Mode = out)
+ : std::ofstream(_Filename.c_str(), _Mode)
+ {
+ }
+
+ void open(const std::string& _Filename, std::_Ios_Openmode _Mode = out) /* Flawfinder: ignore */
+ {
+ std::ofstream::open(_Filename.c_str(), _Mode);
+ }
+
+};
#endif
@@ -175,7 +225,7 @@ private:
* and should only be used for config files and the like -- not in a
* loop.
*/
-std::streamsize llifstream_size(llifstream& fstr);
-std::streamsize llofstream_size(llofstream& fstr);
+std::streamsize LL_COMMON_API llifstream_size(llifstream& fstr);
+std::streamsize LL_COMMON_API llofstream_size(llofstream& fstr);
#endif // not LL_LLFILE_H
diff --git a/indra/llcommon/llfindlocale.cpp b/indra/llcommon/llfindlocale.cpp
new file mode 100644
index 0000000000..cd7c0c7c09
--- /dev/null
+++ b/indra/llcommon/llfindlocale.cpp
@@ -0,0 +1,518 @@
+/**
+ * @file llfindlocale.cpp
+ * @brief Detect system language setting
+ *
+ * $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$
+ */
+
+/* Yes, this was originally C code. */
+
+#include "linden_common.h"
+
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+
+#ifdef WIN32
+#include <windows.h>
+#include <winnt.h>
+#endif
+
+#include "llfindlocale.h"
+
+static int
+is_lcchar(const int c) {
+ return isalnum(c);
+}
+
+static void
+lang_country_variant_from_envstring(const char *str,
+ char **lang,
+ char **country,
+ char **variant) {
+ int end = 0;
+ int start;
+
+ /* get lang, if any */
+ start = end;
+ while (is_lcchar(str[end])) {
+ ++end;
+ }
+ if (start != end) {
+ int i;
+ int len = end - start;
+ char *s = (char*)malloc(len + 1);
+ for (i=0; i<len; ++i) {
+ s[i] = tolower(str[start + i]);
+ }
+ s[i] = '\0';
+ *lang = s;
+ } else {
+ *lang = NULL;
+ }
+
+ if (str[end] && str[end]!=':') { /* not at end of str */
+ ++end;
+ }
+
+ /* get country, if any */
+ start = end;
+ while (is_lcchar(str[end])) {
+ ++end;
+ }
+ if (start != end) {
+ int i;
+ int len = end - start;
+ char *s = (char*)malloc(len + 1);
+ for (i=0; i<len; ++i) {
+ s[i] = toupper(str[start + i]);
+ }
+ s[i] = '\0';
+ *country = s;
+ } else {
+ *country = NULL;
+ }
+
+ if (str[end] && str[end]!=':') { /* not at end of str */
+ ++end;
+ }
+
+ /* get variant, if any */
+ start = end;
+ while (str[end] && str[end]!=':') {
+ ++end;
+ }
+ if (start != end) {
+ int i;
+ int len = end - start;
+ char *s = (char*)malloc(len + 1);
+ for (i=0; i<len; ++i) {
+ s[i] = str[start + i];
+ }
+ s[i] = '\0';
+ *variant = s;
+ } else {
+ *variant = NULL;
+ }
+}
+
+
+static int
+accumulate_locstring(const char *str, FL_Locale *l) {
+ char *lang = NULL;
+ char *country = NULL;
+ char *variant = NULL;
+ if (str) {
+ lang_country_variant_from_envstring(str, &lang, &country, &variant);
+ if (lang) {
+ l->lang = lang;
+ l->country = country;
+ l->variant = variant;
+ return 1;
+ }
+ }
+ free(lang); free(country); free(variant);
+ return 0;
+}
+
+
+static int
+accumulate_env(const char *name, FL_Locale *l) {
+ char *env;
+ char *lang = NULL;
+ char *country = NULL;
+ char *variant = NULL;
+ env = getenv(name);
+ if (env) {
+ return accumulate_locstring(env, l);
+ }
+ free(lang); free(country); free(variant);
+ return 0;
+}
+
+
+static void
+canonise_fl(FL_Locale *l) {
+ /* this function fixes some common locale-specifying mistakes */
+ /* en_UK -> en_GB */
+ if (l->lang && 0 == strcmp(l->lang, "en")) {
+ if (l->country && 0 == strcmp(l->country, "UK")) {
+ free((void*)l->country);
+ l->country = strdup("GB");
+ }
+ }
+ /* ja_JA -> ja_JP */
+ if (l->lang && 0 == strcmp(l->lang, "ja")) {
+ if (l->country && 0 == strcmp(l->country, "JA")) {
+ free((void*)l->country);
+ l->country = strdup("JP");
+ }
+ }
+}
+
+
+#ifdef WIN32
+#include <stdio.h>
+#define ML(pn,sn) MAKELANGID(LANG_##pn, SUBLANG_##pn##_##sn)
+#define MLN(pn) MAKELANGID(LANG_##pn, SUBLANG_DEFAULT)
+#define RML(pn,sn) MAKELANGID(LANG_##pn, SUBLANG_##sn)
+struct IDToCode {
+ LANGID id;
+ char* code;
+};
+static const IDToCode both_to_code[] = {
+ {ML(ENGLISH,US), "en_US.ISO_8859-1"},
+ {ML(ENGLISH,CAN), "en_CA"}, /* english / canadian */
+ {ML(ENGLISH,UK), "en_GB"},
+ {ML(ENGLISH,EIRE), "en_IE"},
+ {ML(ENGLISH,AUS), "en_AU"},
+ {MLN(GERMAN), "de_DE"},
+ {MLN(SPANISH), "es_ES"},
+ {ML(SPANISH,MEXICAN), "es_MX"},
+ {MLN(FRENCH), "fr_FR"},
+ {ML(FRENCH,CANADIAN), "fr_CA"},
+ {ML(FRENCH,BELGIAN), "fr_BE"}, /* ? */
+ {ML(DUTCH,BELGIAN), "nl_BE"}, /* ? */
+ {ML(PORTUGUESE,BRAZILIAN), "pt_BR"},
+ {MLN(PORTUGUESE), "pt_PT"},
+ {MLN(SWEDISH), "sv_SE"},
+ {ML(CHINESE,HONGKONG), "zh_HK"},
+ /* these are machine-generated and not yet verified */
+ {RML(AFRIKAANS,DEFAULT), "af_ZA"},
+ {RML(ALBANIAN,DEFAULT), "sq_AL"},
+ {RML(ARABIC,ARABIC_ALGERIA), "ar_DZ"},
+ {RML(ARABIC,ARABIC_BAHRAIN), "ar_BH"},
+ {RML(ARABIC,ARABIC_EGYPT), "ar_EG"},
+ {RML(ARABIC,ARABIC_IRAQ), "ar_IQ"},
+ {RML(ARABIC,ARABIC_JORDAN), "ar_JO"},
+ {RML(ARABIC,ARABIC_KUWAIT), "ar_KW"},
+ {RML(ARABIC,ARABIC_LEBANON), "ar_LB"},
+ {RML(ARABIC,ARABIC_LIBYA), "ar_LY"},
+ {RML(ARABIC,ARABIC_MOROCCO), "ar_MA"},
+ {RML(ARABIC,ARABIC_OMAN), "ar_OM"},
+ {RML(ARABIC,ARABIC_QATAR), "ar_QA"},
+ {RML(ARABIC,ARABIC_SAUDI_ARABIA), "ar_SA"},
+ {RML(ARABIC,ARABIC_SYRIA), "ar_SY"},
+ {RML(ARABIC,ARABIC_TUNISIA), "ar_TN"},
+ {RML(ARABIC,ARABIC_UAE), "ar_AE"},
+ {RML(ARABIC,ARABIC_YEMEN), "ar_YE"},
+ {RML(ARMENIAN,DEFAULT), "hy_AM"},
+ {RML(AZERI,AZERI_CYRILLIC), "az_AZ"},
+ {RML(AZERI,AZERI_LATIN), "az_AZ"},
+ {RML(BASQUE,DEFAULT), "eu_ES"},
+ {RML(BELARUSIAN,DEFAULT), "be_BY"},
+/*{RML(BRETON,DEFAULT), "br_FR"},*/
+ {RML(BULGARIAN,DEFAULT), "bg_BG"},
+ {RML(CATALAN,DEFAULT), "ca_ES"},
+ {RML(CHINESE,CHINESE_HONGKONG), "zh_HK"},
+ {RML(CHINESE,CHINESE_MACAU), "zh_MO"},
+ {RML(CHINESE,CHINESE_SIMPLIFIED), "zh_CN"},
+ {RML(CHINESE,CHINESE_SINGAPORE), "zh_SG"},
+ {RML(CHINESE,CHINESE_TRADITIONAL), "zh_TW"},
+/*{RML(CORNISH,DEFAULT), "kw_GB"},*/
+ {RML(CZECH,DEFAULT), "cs_CZ"},
+ {RML(DANISH,DEFAULT), "da_DK"},
+ {RML(DUTCH,DUTCH), "nl_NL"},
+ {RML(DUTCH,DUTCH_BELGIAN), "nl_BE"},
+/*{RML(DUTCH,DUTCH_SURINAM), "nl_SR"},*/
+ {RML(ENGLISH,ENGLISH_AUS), "en_AU"},
+ {RML(ENGLISH,ENGLISH_BELIZE), "en_BZ"},
+ {RML(ENGLISH,ENGLISH_CAN), "en_CA"},
+ {RML(ENGLISH,ENGLISH_CARIBBEAN), "en_CB"},
+ {RML(ENGLISH,ENGLISH_EIRE), "en_IE"},
+ {RML(ENGLISH,ENGLISH_JAMAICA), "en_JM"},
+ {RML(ENGLISH,ENGLISH_NZ), "en_NZ"},
+ {RML(ENGLISH,ENGLISH_PHILIPPINES), "en_PH"},
+ {RML(ENGLISH,ENGLISH_SOUTH_AFRICA), "en_ZA"},
+ {RML(ENGLISH,ENGLISH_TRINIDAD), "en_TT"},
+ {RML(ENGLISH,ENGLISH_UK), "en_GB"},
+ {RML(ENGLISH,ENGLISH_US), "en_US"},
+ {RML(ENGLISH,ENGLISH_ZIMBABWE), "en_ZW"},
+/*{RML(ESPERANTO,DEFAULT), "eo_"},*/
+ {RML(ESTONIAN,DEFAULT), "et_EE"},
+ {RML(FAEROESE,DEFAULT), "fo_FO"},
+ {RML(FARSI,DEFAULT), "fa_IR"},
+ {RML(FINNISH,DEFAULT), "fi_FI"},
+ {RML(FRENCH,FRENCH), "fr_FR"},
+ {RML(FRENCH,FRENCH_BELGIAN), "fr_BE"},
+ {RML(FRENCH,FRENCH_CANADIAN), "fr_CA"},
+ {RML(FRENCH,FRENCH_LUXEMBOURG), "fr_LU"},
+ {RML(FRENCH,FRENCH_MONACO), "fr_MC"},
+ {RML(FRENCH,FRENCH_SWISS), "fr_CH"},
+/*{RML(GAELIC,GAELIC), "ga_IE"},*/
+/*{RML(GAELIC,GAELIC_MANX), "gv_GB"},*/
+/*{RML(GAELIC,GAELIC_SCOTTISH), "gd_GB"},*/
+/*{RML(GALICIAN,DEFAULT), "gl_ES"},*/
+ {RML(GEORGIAN,DEFAULT), "ka_GE"},
+ {RML(GERMAN,GERMAN), "de_DE"},
+ {RML(GERMAN,GERMAN_AUSTRIAN), "de_AT"},
+ {RML(GERMAN,GERMAN_LIECHTENSTEIN), "de_LI"},
+ {RML(GERMAN,GERMAN_LUXEMBOURG), "de_LU"},
+ {RML(GERMAN,GERMAN_SWISS), "de_CH"},
+ {RML(GREEK,DEFAULT), "el_GR"},
+ {RML(GUJARATI,DEFAULT), "gu_IN"},
+ {RML(HEBREW,DEFAULT), "he_IL"},
+ {RML(HINDI,DEFAULT), "hi_IN"},
+ {RML(HUNGARIAN,DEFAULT), "hu_HU"},
+ {RML(ICELANDIC,DEFAULT), "is_IS"},
+ {RML(INDONESIAN,DEFAULT), "id_ID"},
+ {RML(ITALIAN,ITALIAN), "it_IT"},
+ {RML(ITALIAN,ITALIAN_SWISS), "it_CH"},
+ {RML(JAPANESE,DEFAULT), "ja_JP"},
+ {RML(KANNADA,DEFAULT), "kn_IN"},
+ {RML(KAZAK,DEFAULT), "kk_KZ"},
+ {RML(KONKANI,DEFAULT), "kok_IN"},
+ {RML(KOREAN,KOREAN), "ko_KR"},
+/*{RML(KYRGYZ,DEFAULT), "ky_KG"},*/
+ {RML(LATVIAN,DEFAULT), "lv_LV"},
+ {RML(LITHUANIAN,LITHUANIAN), "lt_LT"},
+ {RML(MACEDONIAN,DEFAULT), "mk_MK"},
+ {RML(MALAY,MALAY_BRUNEI_DARUSSALAM), "ms_BN"},
+ {RML(MALAY,MALAY_MALAYSIA), "ms_MY"},
+ {RML(MARATHI,DEFAULT), "mr_IN"},
+/*{RML(MONGOLIAN,DEFAULT), "mn_MN"},*/
+ {RML(NORWEGIAN,NORWEGIAN_BOKMAL), "nb_NO"},
+ {RML(NORWEGIAN,NORWEGIAN_NYNORSK), "nn_NO"},
+ {RML(POLISH,DEFAULT), "pl_PL"},
+ {RML(PORTUGUESE,PORTUGUESE), "pt_PT"},
+ {RML(PORTUGUESE,PORTUGUESE_BRAZILIAN), "pt_BR"},
+ {RML(PUNJABI,DEFAULT), "pa_IN"},
+ {RML(ROMANIAN,DEFAULT), "ro_RO"},
+ {RML(RUSSIAN,DEFAULT), "ru_RU"},
+ {RML(SANSKRIT,DEFAULT), "sa_IN"},
+ {RML(SERBIAN,DEFAULT), "hr_HR"},
+ {RML(SERBIAN,SERBIAN_CYRILLIC), "sr_SP"},
+ {RML(SERBIAN,SERBIAN_LATIN), "sr_SP"},
+ {RML(SLOVAK,DEFAULT), "sk_SK"},
+ {RML(SLOVENIAN,DEFAULT), "sl_SI"},
+ {RML(SPANISH,SPANISH), "es_ES"},
+ {RML(SPANISH,SPANISH_ARGENTINA), "es_AR"},
+ {RML(SPANISH,SPANISH_BOLIVIA), "es_BO"},
+ {RML(SPANISH,SPANISH_CHILE), "es_CL"},
+ {RML(SPANISH,SPANISH_COLOMBIA), "es_CO"},
+ {RML(SPANISH,SPANISH_COSTA_RICA), "es_CR"},
+ {RML(SPANISH,SPANISH_DOMINICAN_REPUBLIC), "es_DO"},
+ {RML(SPANISH,SPANISH_ECUADOR), "es_EC"},
+ {RML(SPANISH,SPANISH_EL_SALVADOR), "es_SV"},
+ {RML(SPANISH,SPANISH_GUATEMALA), "es_GT"},
+ {RML(SPANISH,SPANISH_HONDURAS), "es_HN"},
+ {RML(SPANISH,SPANISH_MEXICAN), "es_MX"},
+ {RML(SPANISH,SPANISH_MODERN), "es_ES"},
+ {RML(SPANISH,SPANISH_NICARAGUA), "es_NI"},
+ {RML(SPANISH,SPANISH_PANAMA), "es_PA"},
+ {RML(SPANISH,SPANISH_PARAGUAY), "es_PY"},
+ {RML(SPANISH,SPANISH_PERU), "es_PE"},
+ {RML(SPANISH,SPANISH_PUERTO_RICO), "es_PR"},
+ {RML(SPANISH,SPANISH_URUGUAY), "es_UY"},
+ {RML(SPANISH,SPANISH_VENEZUELA), "es_VE"},
+ {RML(SWAHILI,DEFAULT), "sw_KE"},
+ {RML(SWEDISH,SWEDISH), "sv_SE"},
+ {RML(SWEDISH,SWEDISH_FINLAND), "sv_FI"},
+/*{RML(SYRIAC,DEFAULT), "syr_SY"},*/
+ {RML(TAMIL,DEFAULT), "ta_IN"},
+ {RML(TATAR,DEFAULT), "tt_TA"},
+ {RML(TELUGU,DEFAULT), "te_IN"},
+ {RML(THAI,DEFAULT), "th_TH"},
+ {RML(TURKISH,DEFAULT), "tr_TR"},
+ {RML(UKRAINIAN,DEFAULT), "uk_UA"},
+ {RML(URDU,URDU_PAKISTAN), "ur_PK"},
+ {RML(UZBEK,UZBEK_CYRILLIC), "uz_UZ"},
+ {RML(UZBEK,UZBEK_LATIN), "uz_UZ"},
+ {RML(VIETNAMESE,DEFAULT), "vi_VN"},
+/*{RML(WALON,DEFAULT), "wa_BE"},*/
+/*{RML(WELSH,DEFAULT), "cy_GB"},*/
+};
+static const IDToCode primary_to_code[] = {
+ {LANG_AFRIKAANS, "af"},
+ {LANG_ARABIC, "ar"},
+ {LANG_AZERI, "az"},
+ {LANG_BULGARIAN, "bg"},
+/*{LANG_BRETON, "br"},*/
+ {LANG_BELARUSIAN, "by"},
+ {LANG_CATALAN, "ca"},
+ {LANG_CZECH, "cs"},
+/*{LANG_WELSH, "cy"},*/
+ {LANG_DANISH, "da"},
+ {LANG_GERMAN, "de"},
+ {LANG_GREEK, "el"},
+ {LANG_ENGLISH, "en"},
+/*{LANG_ESPERANTO, "eo"},*/
+ {LANG_SPANISH, "es"},
+ {LANG_ESTONIAN, "et"},
+ {LANG_BASQUE, "eu"},
+ {LANG_FARSI, "fa"},
+ {LANG_FINNISH, "fi"},
+ {LANG_FAEROESE, "fo"},
+ {LANG_FRENCH, "fr"},
+/*{LANG_GAELIC, "ga"},*/
+/*{LANG_GALICIAN, "gl"},*/
+ {LANG_GUJARATI, "gu"},
+ {LANG_HEBREW, "he"},
+ {LANG_HINDI, "hi"},
+ {LANG_SERBIAN, "hr"},
+ {LANG_HUNGARIAN, "hu"},
+ {LANG_ARMENIAN, "hy"},
+ {LANG_INDONESIAN, "id"},
+ {LANG_ITALIAN, "it"},
+ {LANG_JAPANESE, "ja"},
+ {LANG_GEORGIAN, "ka"},
+ {LANG_KAZAK, "kk"},
+ {LANG_KANNADA, "kn"},
+ {LANG_KOREAN, "ko"},
+/*{LANG_KYRGYZ, "ky"},*/
+ {LANG_LITHUANIAN, "lt"},
+ {LANG_LATVIAN, "lv"},
+ {LANG_MACEDONIAN, "mk"},
+/*{LANG_MONGOLIAN, "mn"},*/
+ {LANG_MARATHI, "mr"},
+ {LANG_MALAY, "ms"},
+ {LANG_NORWEGIAN, "nb"},
+ {LANG_DUTCH, "nl"},
+ {LANG_NORWEGIAN, "nn"},
+ {LANG_NORWEGIAN, "no"},/* unofficial? */
+ {LANG_PUNJABI, "pa"},
+ {LANG_POLISH, "pl"},
+ {LANG_PORTUGUESE, "pt"},
+ {LANG_ROMANIAN, "ro"},
+ {LANG_RUSSIAN, "ru"},
+ {LANG_SLOVAK, "sk"},
+ {LANG_SLOVENIAN, "sl"},
+ {LANG_ALBANIAN, "sq"},
+ {LANG_SERBIAN, "sr"},
+ {LANG_SWEDISH, "sv"},
+ {LANG_SWAHILI, "sw"},
+ {LANG_TAMIL, "ta"},
+ {LANG_THAI, "th"},
+ {LANG_TURKISH, "tr"},
+ {LANG_TATAR, "tt"},
+ {LANG_UKRAINIAN, "uk"},
+ {LANG_URDU, "ur"},
+ {LANG_UZBEK, "uz"},
+ {LANG_VIETNAMESE, "vi"},
+/*{LANG_WALON, "wa"},*/
+ {LANG_CHINESE, "zh"},
+};
+static int num_primary_to_code = LL_ARRAY_SIZE(primary_to_code);
+static int num_both_to_code = LL_ARRAY_SIZE(both_to_code);
+
+static const int
+lcid_to_fl(LCID lcid,
+ FL_Locale *rtn) {
+ LANGID langid = LANGIDFROMLCID(lcid);
+ LANGID primary_lang = PRIMARYLANGID(langid);
+ /*LANGID sub_lang = SUBLANGID(langid);*/
+ int i;
+ /* try to find an exact primary/sublanguage combo that we know about */
+ for (i=0; i<num_both_to_code; ++i) {
+ if (both_to_code[i].id == langid) {
+ accumulate_locstring(both_to_code[i].code, rtn);
+ return 1;
+ }
+ }
+ /* fallback to just checking the primary language id */
+ for (i=0; i<num_primary_to_code; ++i) {
+ if (primary_to_code[i].id == primary_lang) {
+ accumulate_locstring(primary_to_code[i].code, rtn);
+ return 1;
+ }
+ }
+ return 0;
+}
+#endif
+
+
+FL_Success
+FL_FindLocale(FL_Locale **locale, FL_Domain domain) {
+ FL_Success success = FL_FAILED;
+ FL_Locale *rtn = (FL_Locale*)malloc(sizeof(FL_Locale));
+ rtn->lang = NULL;
+ rtn->country = NULL;
+ rtn->variant = NULL;
+
+#ifdef WIN32
+ /* win32 >= mswindows95 */
+ {
+ LCID lcid = GetThreadLocale();
+ if (lcid_to_fl(lcid, rtn)) {
+ success = FL_CONFIDENT;
+ }
+ if (success == FL_FAILED) {
+ /* assume US English on mswindows systems unless we know otherwise */
+ if (accumulate_locstring("en_US.ISO_8859-1", rtn)) {
+ success = FL_DEFAULT_GUESS;
+ }
+ }
+ }
+#else
+ /* assume unixoid */
+ {
+ /* examples: */
+ /* sv_SE.ISO_8859-1 */
+ /* fr_FR.ISO8859-1 */
+ /* no_NO_NB */
+ /* no_NO_NY */
+ /* no_NO */
+ /* de_DE */
+ /* try the various vars in decreasing order of authority */
+ if (accumulate_env("LC_ALL", rtn) ||
+ accumulate_env("LC_MESSAGES", rtn) ||
+ accumulate_env("LANG", rtn) ||
+ accumulate_env("LANGUAGE", rtn)) {
+ success = FL_CONFIDENT;
+ }
+ if (success == FL_FAILED) {
+ /* assume US English on unixoid systems unless we know otherwise */
+ if (accumulate_locstring("en_US.ISO_8859-1", rtn)) {
+ success = FL_DEFAULT_GUESS;
+ }
+ }
+ }
+#endif
+
+ if (success != FL_FAILED) {
+ canonise_fl(rtn);
+ }
+
+ *locale = rtn;
+ return success;
+}
+
+
+void
+FL_FreeLocale(FL_Locale **locale) {
+ if (locale) {
+ FL_Locale *l = *locale;
+ if (l) {
+ if (l->lang) {
+ free((void*)l->lang);
+ }
+ if (l->country) {
+ free((void*)l->country);
+ }
+ if (l->variant) {
+ free((void*)l->variant);
+ }
+ free(l);
+ *locale = NULL;
+ }
+ }
+}
diff --git a/indra/llcommon/llfindlocale.h b/indra/llcommon/llfindlocale.h
new file mode 100644
index 0000000000..6770db5774
--- /dev/null
+++ b/indra/llcommon/llfindlocale.h
@@ -0,0 +1,60 @@
+/**
+ * @file llfindlocale.h
+ * @brief Detect system language setting
+ *
+ * $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$
+ */
+
+#ifndef __findlocale_h_
+#define __findlocale_h_
+
+typedef const char* FL_Lang;
+typedef const char* FL_Country;
+typedef const char* FL_Variant;
+
+struct FL_Locale {
+ FL_Lang lang;
+ FL_Country country;
+ FL_Variant variant;
+};
+
+typedef enum {
+ /* for some reason we failed to even guess: this should never happen */
+ FL_FAILED = 0,
+ /* couldn't query locale -- returning a guess (almost always English) */
+ FL_DEFAULT_GUESS = 1,
+ /* the returned locale type was found by successfully asking the system */
+ FL_CONFIDENT = 2
+} FL_Success;
+
+typedef enum {
+ FL_MESSAGES = 0
+} FL_Domain;
+
+/* This allocates/fills in a FL_Locale structure with pointers to
+ strings (which should be treated as static), or NULL for inappropriate /
+ undetected fields. */
+LL_COMMON_API FL_Success FL_FindLocale(FL_Locale **locale, FL_Domain domain);
+/* This should be used to free the struct written by FL_FindLocale */
+LL_COMMON_API void FL_FreeLocale(FL_Locale **locale);
+
+#endif /*__findlocale_h_*/
diff --git a/indra/llcommon/llfixedbuffer.cpp b/indra/llcommon/llfixedbuffer.cpp
index 44bb953f80..d394f179fb 100644
--- a/indra/llcommon/llfixedbuffer.cpp
+++ b/indra/llcommon/llfixedbuffer.cpp
@@ -1,66 +1,65 @@
/**
* @file llfixedbuffer.cpp
*
- * $LicenseInfo:firstyear=2001&license=viewergpl$
- *
- * Copyright (c) 2001-2007, Linden Research, Inc.
- *
+ * $LicenseInfo:firstyear=2001&license=viewerlgpl$
* Second Life Viewer Source Code
- * The source code in this file ("Source Code") is provided by Linden Lab
- * to you under the terms of the GNU General Public License, version 2.0
- * ("GPL"), unless you have obtained a separate licensing agreement
- * ("Other License"), formally executed by you and Linden Lab. Terms of
- * the GPL can be found in doc/GPL-license.txt in this distribution, or
- * online at http://secondlife.com/developers/opensource/gplv2
+ * Copyright (C) 2010, Linden Research, Inc.
*
- * There are special exceptions to the terms and conditions of the GPL as
- * it is applied to this Source Code. View the full text of the exception
- * in the file doc/FLOSS-exception.txt in this software distribution, or
- * online at http://secondlife.com/developers/opensource/flossexception
+ * 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.
*
- * By copying, modifying or distributing this software, you acknowledge
- * that you have read and understood your obligations described above,
- * and agree to abide by those obligations.
+ * 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.
*
- * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
- * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
- * COMPLETENESS OR PERFORMANCE.
+ * 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$
*/
#include "linden_common.h"
#include "llfixedbuffer.h"
+////////////////////////////////////////////////////////////////////////////
+
LLFixedBuffer::LLFixedBuffer(const U32 max_lines)
+ : LLLineBuffer(),
+ mMaxLines(max_lines),
+ mMutex(NULL)
{
- mMaxLines = max_lines;
mTimer.reset();
}
-
LLFixedBuffer::~LLFixedBuffer()
{
clear();
}
-
void LLFixedBuffer::clear()
{
+ mMutex.lock() ;
mLines.clear();
mAddTimes.clear();
mLineLengths.clear();
+ mMutex.unlock() ;
mTimer.reset();
}
-void LLFixedBuffer::addLine(const LLString& utf8line)
+void LLFixedBuffer::addLine(const std::string& utf8line)
{
LLWString wstring = utf8str_to_wstring(utf8line);
- LLFixedBuffer::addLine(wstring);
+ addWLine(wstring);
}
-void LLFixedBuffer::addLine(const LLWString& line)
+void LLFixedBuffer::addWLine(const LLWString& line)
{
if (line.empty())
{
@@ -69,9 +68,11 @@ void LLFixedBuffer::addLine(const LLWString& line)
removeExtraLines();
+ mMutex.lock() ;
mLines.push_back(line);
mLineLengths.push_back((S32)line.length());
mAddTimes.push_back(mTimer.getElapsedTimeF32());
+ mMutex.unlock() ;
}
@@ -85,10 +86,12 @@ void LLFixedBuffer::setMaxLines(S32 max_lines)
void LLFixedBuffer::removeExtraLines()
{
+ mMutex.lock() ;
while ((S32)mLines.size() > llmax((S32)0, (S32)(mMaxLines - 1)))
{
mLines.pop_front();
mAddTimes.pop_front();
mLineLengths.pop_front();
}
+ mMutex.unlock() ;
}
diff --git a/indra/llcommon/llfixedbuffer.h b/indra/llcommon/llfixedbuffer.h
index 148c0e60db..554cf48a4c 100644
--- a/indra/llcommon/llfixedbuffer.h
+++ b/indra/llcommon/llfixedbuffer.h
@@ -2,30 +2,25 @@
* @file llfixedbuffer.h
* @brief A fixed size buffer of lines.
*
- * $LicenseInfo:firstyear=2001&license=viewergpl$
- *
- * Copyright (c) 2001-2007, Linden Research, Inc.
- *
+ * $LicenseInfo:firstyear=2001&license=viewerlgpl$
* Second Life Viewer Source Code
- * The source code in this file ("Source Code") is provided by Linden Lab
- * to you under the terms of the GNU General Public License, version 2.0
- * ("GPL"), unless you have obtained a separate licensing agreement
- * ("Other License"), formally executed by you and Linden Lab. Terms of
- * the GPL can be found in doc/GPL-license.txt in this distribution, or
- * online at http://secondlife.com/developers/opensource/gplv2
+ * Copyright (C) 2010, Linden Research, Inc.
*
- * There are special exceptions to the terms and conditions of the GPL as
- * it is applied to this Source Code. View the full text of the exception
- * in the file doc/FLOSS-exception.txt in this software distribution, or
- * online at http://secondlife.com/developers/opensource/flossexception
+ * 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.
*
- * By copying, modifying or distributing this software, you acknowledge
- * that you have read and understood your obligations described above,
- * and agree to abide by those obligations.
+ * 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.
*
- * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
- * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
- * COMPLETENESS OR PERFORMANCE.
+ * 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$
*/
@@ -36,14 +31,15 @@
#include <deque>
#include <string>
#include "llstring.h"
+#include "llthread.h"
+#include "llerrorcontrol.h"
-// Fixed size buffer for console output and other things.
-
-class LLFixedBuffer
+// fixed buffer implementation
+class LL_COMMON_API LLFixedBuffer : public LLLineBuffer
{
public:
LLFixedBuffer(const U32 max_lines = 20);
- virtual ~LLFixedBuffer();
+ ~LLFixedBuffer();
LLTimer mTimer;
U32 mMaxLines;
@@ -51,17 +47,18 @@ public:
std::deque<F32> mAddTimes;
std::deque<S32> mLineLengths;
- void clear(); // Clear the buffer, and reset it.
- virtual void addLine(const LLString& utf8line);
- virtual void addLine(const LLWString& line);
+ /*virtual*/ void clear(); // Clear the buffer, and reset it.
+
+ /*virtual*/ void addLine(const std::string& utf8line);
- // Get lines currently in the buffer, up to max_size chars, max_length lines
- char *getLines(U32 max_size = 0, U32 max_length = 0);
void setMaxLines(S32 max_lines);
+
protected:
- virtual void removeExtraLines();
-};
+ void removeExtraLines();
+ void addWLine(const LLWString& line);
-const U32 FIXED_BUF_MAX_LINE_LEN = 255; // Not including termnating 0
+protected:
+ LLMutex mMutex ;
+};
#endif //LL_FIXED_BUFFER_H
diff --git a/indra/llcommon/llfoldertype.cpp b/indra/llcommon/llfoldertype.cpp
new file mode 100644
index 0000000000..ebc79af412
--- /dev/null
+++ b/indra/llcommon/llfoldertype.cpp
@@ -0,0 +1,163 @@
+/**
+ * @file llfoldertype.cpp
+ * @brief Implementatino of LLFolderType functionality.
+ *
+ * $LicenseInfo:firstyear=2001&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$
+ */
+
+#include "linden_common.h"
+
+#include "llfoldertype.h"
+#include "lldictionary.h"
+#include "llmemory.h"
+#include "llsingleton.h"
+
+///----------------------------------------------------------------------------
+/// Class LLFolderType
+///----------------------------------------------------------------------------
+struct FolderEntry : public LLDictionaryEntry
+{
+ FolderEntry(const std::string &type_name, // 8 character limit!
+ bool is_protected) // can the viewer change categories of this type?
+ :
+ LLDictionaryEntry(type_name),
+ mIsProtected(is_protected)
+ {
+ llassert(type_name.length() <= 8);
+ }
+
+ const bool mIsProtected;
+};
+
+class LLFolderDictionary : public LLSingleton<LLFolderDictionary>,
+ public LLDictionary<LLFolderType::EType, FolderEntry>
+{
+public:
+ LLFolderDictionary();
+protected:
+ virtual LLFolderType::EType notFound() const
+ {
+ return LLFolderType::FT_NONE;
+ }
+};
+
+LLFolderDictionary::LLFolderDictionary()
+{
+ // TYPE NAME PROTECTED
+ // |-----------|---------|
+ addEntry(LLFolderType::FT_TEXTURE, new FolderEntry("texture", TRUE));
+ addEntry(LLFolderType::FT_SOUND, new FolderEntry("sound", TRUE));
+ addEntry(LLFolderType::FT_CALLINGCARD, new FolderEntry("callcard", TRUE));
+ addEntry(LLFolderType::FT_LANDMARK, new FolderEntry("landmark", TRUE));
+ addEntry(LLFolderType::FT_CLOTHING, new FolderEntry("clothing", TRUE));
+ addEntry(LLFolderType::FT_OBJECT, new FolderEntry("object", TRUE));
+ addEntry(LLFolderType::FT_NOTECARD, new FolderEntry("notecard", TRUE));
+ addEntry(LLFolderType::FT_ROOT_INVENTORY, new FolderEntry("root_inv", TRUE));
+ addEntry(LLFolderType::FT_LSL_TEXT, new FolderEntry("lsltext", TRUE));
+ addEntry(LLFolderType::FT_BODYPART, new FolderEntry("bodypart", TRUE));
+ addEntry(LLFolderType::FT_TRASH, new FolderEntry("trash", TRUE));
+ addEntry(LLFolderType::FT_SNAPSHOT_CATEGORY, new FolderEntry("snapshot", TRUE));
+ addEntry(LLFolderType::FT_LOST_AND_FOUND, new FolderEntry("lstndfnd", TRUE));
+ addEntry(LLFolderType::FT_ANIMATION, new FolderEntry("animatn", TRUE));
+ addEntry(LLFolderType::FT_GESTURE, new FolderEntry("gesture", TRUE));
+ addEntry(LLFolderType::FT_FAVORITE, new FolderEntry("favorite", TRUE));
+
+ for (S32 ensemble_num = S32(LLFolderType::FT_ENSEMBLE_START); ensemble_num <= S32(LLFolderType::FT_ENSEMBLE_END); ensemble_num++)
+ {
+ addEntry(LLFolderType::EType(ensemble_num), new FolderEntry("ensemble", FALSE));
+ }
+
+ 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_INBOX, new FolderEntry("inbox", TRUE));
+
+ addEntry(LLFolderType::FT_NONE, new FolderEntry("-1", FALSE));
+};
+
+// static
+LLFolderType::EType LLFolderType::lookup(const std::string& name)
+{
+ return LLFolderDictionary::getInstance()->lookup(name);
+}
+
+// static
+const std::string &LLFolderType::lookup(LLFolderType::EType folder_type)
+{
+ const FolderEntry *entry = LLFolderDictionary::getInstance()->lookup(folder_type);
+ if (entry)
+ {
+ return entry->mName;
+ }
+ else
+ {
+ return badLookup();
+ }
+}
+
+// static
+// Only ensembles and plain folders aren't protected. "Protected" means
+// you can't change certain properties such as their type.
+bool LLFolderType::lookupIsProtectedType(EType folder_type)
+{
+ const LLFolderDictionary *dict = LLFolderDictionary::getInstance();
+ const FolderEntry *entry = dict->lookup(folder_type);
+ if (entry)
+ {
+ return entry->mIsProtected;
+ }
+ return true;
+}
+
+// static
+bool LLFolderType::lookupIsEnsembleType(EType folder_type)
+{
+ return (folder_type >= FT_ENSEMBLE_START &&
+ folder_type <= FT_ENSEMBLE_END);
+}
+
+// static
+LLAssetType::EType LLFolderType::folderTypeToAssetType(LLFolderType::EType folder_type)
+{
+ if (LLAssetType::lookup(LLAssetType::EType(folder_type)) == LLAssetType::badLookup())
+ {
+ llwarns << "Converting to unknown asset type " << folder_type << llendl;
+ }
+ return (LLAssetType::EType)folder_type;
+}
+
+// static
+LLFolderType::EType LLFolderType::assetTypeToFolderType(LLAssetType::EType asset_type)
+{
+ if (LLFolderType::lookup(LLFolderType::EType(asset_type)) == LLFolderType::badLookup())
+ {
+ llwarns << "Converting to unknown folder type " << asset_type << llendl;
+ }
+ return (LLFolderType::EType)asset_type;
+}
+
+// static
+const std::string &LLFolderType::badLookup()
+{
+ static const std::string sBadLookup = "llfoldertype_bad_lookup";
+ return sBadLookup;
+}
diff --git a/indra/llcommon/llfoldertype.h b/indra/llcommon/llfoldertype.h
new file mode 100644
index 0000000000..936fbed17d
--- /dev/null
+++ b/indra/llcommon/llfoldertype.h
@@ -0,0 +1,106 @@
+/**
+ * @file llfoldertype.h
+ * @brief Declaration of LLFolderType.
+ *
+ * $LicenseInfo:firstyear=2001&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$
+ */
+
+#ifndef LL_LLFOLDERTYPE_H
+#define LL_LLFOLDERTYPE_H
+
+#include <string>
+#include "llassettype.h"
+
+// This class handles folder types (similar to assettype, except for folders)
+// and operations on those.
+class LL_COMMON_API LLFolderType
+{
+public:
+ // ! BACKWARDS COMPATIBILITY ! Folder type enums must match asset type enums.
+ enum EType
+ {
+ FT_TEXTURE = 0,
+
+ FT_SOUND = 1,
+
+ FT_CALLINGCARD = 2,
+
+ FT_LANDMARK = 3,
+
+ FT_CLOTHING = 5,
+
+ FT_OBJECT = 6,
+
+ FT_NOTECARD = 7,
+
+ FT_ROOT_INVENTORY = 8,
+ // We'd really like to change this to 9 since AT_CATEGORY is 8,
+ // but "My Inventory" has been type 8 for a long time.
+
+ FT_LSL_TEXT = 10,
+
+ FT_BODYPART = 13,
+
+ FT_TRASH = 14,
+
+ FT_SNAPSHOT_CATEGORY = 15,
+
+ FT_LOST_AND_FOUND = 16,
+
+ FT_ANIMATION = 20,
+
+ FT_GESTURE = 21,
+
+ FT_FAVORITE = 23,
+
+ FT_ENSEMBLE_START = 26,
+ FT_ENSEMBLE_END = 45,
+ // This range is reserved for special clothing folder types.
+
+ FT_CURRENT_OUTFIT = 46,
+ FT_OUTFIT = 47,
+ FT_MY_OUTFITS = 48,
+
+ FT_INBOX = 49,
+
+ FT_COUNT = 50,
+
+ FT_NONE = -1
+ };
+
+ static EType lookup(const std::string& type_name);
+ static const std::string& lookup(EType folder_type);
+
+ static bool lookupIsProtectedType(EType folder_type);
+ static bool lookupIsEnsembleType(EType folder_type);
+
+ static LLAssetType::EType folderTypeToAssetType(LLFolderType::EType folder_type);
+ static LLFolderType::EType assetTypeToFolderType(LLAssetType::EType asset_type);
+
+ static const std::string& badLookup(); // error string when a lookup fails
+
+protected:
+ LLFolderType() {}
+ ~LLFolderType() {}
+};
+
+#endif // LL_LLFOLDERTYPE_H
diff --git a/indra/llcommon/llformat.cpp b/indra/llcommon/llformat.cpp
index bb0f46739b..3b2b3038ea 100644
--- a/indra/llcommon/llformat.cpp
+++ b/indra/llcommon/llformat.cpp
@@ -3,30 +3,25 @@
* @date January 2007
* @brief string formatting utility
*
- * $LicenseInfo:firstyear=2007&license=viewergpl$
- *
- * Copyright (c) 2007, Linden Research, Inc.
- *
+ * $LicenseInfo:firstyear=2007&license=viewerlgpl$
* Second Life Viewer Source Code
- * The source code in this file ("Source Code") is provided by Linden Lab
- * to you under the terms of the GNU General Public License, version 2.0
- * ("GPL"), unless you have obtained a separate licensing agreement
- * ("Other License"), formally executed by you and Linden Lab. Terms of
- * the GPL can be found in doc/GPL-license.txt in this distribution, or
- * online at http://secondlife.com/developers/opensource/gplv2
+ * 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.
*
- * There are special exceptions to the terms and conditions of the GPL as
- * it is applied to this Source Code. View the full text of the exception
- * in the file doc/FLOSS-exception.txt in this software distribution, or
- * online at http://secondlife.com/developers/opensource/flossexception
+ * 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.
*
- * By copying, modifying or distributing this software, you acknowledge
- * that you have read and understood your obligations described above,
- * and agree to abide by those obligations.
+ * 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
*
- * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
- * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
- * COMPLETENESS OR PERFORMANCE.
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
* $/LicenseInfo$
*/
@@ -36,16 +31,40 @@
#include <cstdarg>
-std::string llformat(const char *fmt, ...)
+// common used function with va_list argument
+// wrapper for vsnprintf to be called from llformatXXX functions.
+static void va_format(std::string& out, const char *fmt, va_list va)
{
char tstr[1024]; /* Flawfinder: ignore */
- va_list va;
- va_start(va, fmt);
#if LL_WINDOWS
_vsnprintf(tstr, 1024, fmt, va);
#else
vsnprintf(tstr, 1024, fmt, va); /* Flawfinder: ignore */
#endif
+ out.assign(tstr);
+}
+
+std::string llformat(const char *fmt, ...)
+{
+ std::string res;
+ va_list va;
+ va_start(va, fmt);
+ va_format(res, fmt, va);
+ va_end(va);
+ return res;
+}
+
+std::string llformat_to_utf8(const char *fmt, ...)
+{
+ std::string res;
+ va_list va;
+ va_start(va, fmt);
+ va_format(res, fmt, va);
va_end(va);
- return std::string(tstr);
+
+#if LL_WINDOWS
+ // made converting to utf8. See EXT-8318.
+ res = ll_convert_string_to_utf8_string(res);
+#endif
+ return res;
}
diff --git a/indra/llcommon/llformat.h b/indra/llcommon/llformat.h
index 8b8c4a44fa..a4ec5e01de 100644
--- a/indra/llcommon/llformat.h
+++ b/indra/llcommon/llformat.h
@@ -3,30 +3,25 @@
* @date January 2007
* @brief string formatting utility
*
- * $LicenseInfo:firstyear=2007&license=viewergpl$
- *
- * Copyright (c) 2007, Linden Research, Inc.
- *
+ * $LicenseInfo:firstyear=2007&license=viewerlgpl$
* Second Life Viewer Source Code
- * The source code in this file ("Source Code") is provided by Linden Lab
- * to you under the terms of the GNU General Public License, version 2.0
- * ("GPL"), unless you have obtained a separate licensing agreement
- * ("Other License"), formally executed by you and Linden Lab. Terms of
- * the GPL can be found in doc/GPL-license.txt in this distribution, or
- * online at http://secondlife.com/developers/opensource/gplv2
+ * Copyright (C) 2010, Linden Research, Inc.
*
- * There are special exceptions to the terms and conditions of the GPL as
- * it is applied to this Source Code. View the full text of the exception
- * in the file doc/FLOSS-exception.txt in this software distribution, or
- * online at http://secondlife.com/developers/opensource/flossexception
+ * 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.
*
- * By copying, modifying or distributing this software, you acknowledge
- * that you have read and understood your obligations described above,
- * and agree to abide by those obligations.
+ * 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.
*
- * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
- * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
- * COMPLETENESS OR PERFORMANCE.
+ * 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$
*/
@@ -39,6 +34,10 @@
// *NOTE: buffer limited to 1024, (but vsnprintf prevents overrun)
// should perhaps be replaced with boost::format.
-std::string llformat(const char *fmt, ...);
+std::string LL_COMMON_API llformat(const char *fmt, ...);
+
+// the same version as above but ensures that returned string is in utf8 on windows
+// to enable correct converting utf8_to_wstring.
+std::string LL_COMMON_API llformat_to_utf8(const char *fmt, ...);
#endif // LL_LLFORMAT_H
diff --git a/indra/llcommon/llframetimer.cpp b/indra/llcommon/llframetimer.cpp
index 23d8775824..ec64195b21 100644
--- a/indra/llcommon/llframetimer.cpp
+++ b/indra/llcommon/llframetimer.cpp
@@ -1,30 +1,25 @@
/**
* @file llframetimer.cpp
*
- * $LicenseInfo:firstyear=2002&license=viewergpl$
- *
- * Copyright (c) 2002-2007, Linden Research, Inc.
- *
+ * $LicenseInfo:firstyear=2002&license=viewerlgpl$
* Second Life Viewer Source Code
- * The source code in this file ("Source Code") is provided by Linden Lab
- * to you under the terms of the GNU General Public License, version 2.0
- * ("GPL"), unless you have obtained a separate licensing agreement
- * ("Other License"), formally executed by you and Linden Lab. Terms of
- * the GPL can be found in doc/GPL-license.txt in this distribution, or
- * online at http://secondlife.com/developers/opensource/gplv2
+ * 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.
*
- * There are special exceptions to the terms and conditions of the GPL as
- * it is applied to this Source Code. View the full text of the exception
- * in the file doc/FLOSS-exception.txt in this software distribution, or
- * online at http://secondlife.com/developers/opensource/flossexception
+ * 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.
*
- * By copying, modifying or distributing this software, you acknowledge
- * that you have read and understood your obligations described above,
- * and agree to abide by those obligations.
+ * 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
*
- * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
- * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
- * COMPLETENESS OR PERFORMANCE.
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
* $/LicenseInfo$
*/
@@ -53,7 +48,6 @@ void LLFrameTimer::updateFrameTime()
sTotalTime = total_time;
sTotalSeconds = U64_to_F64(sTotalTime) * USEC_TO_SEC_F64;
sFrameTime = U64_to_F64(sTotalTime - sStartTotalTime) * USEC_TO_SEC_F64;
- sFrameCount++;
}
void LLFrameTimer::start()
@@ -140,3 +134,18 @@ F32 LLFrameTimer::getFrameDeltaTimeF32()
{
return (F32)(U64_to_F64(sFrameDeltaTime) * USEC_TO_SEC_F64);
}
+
+
+// static
+// Return seconds since the current frame started
+F32 LLFrameTimer::getCurrentFrameTime()
+{
+ U64 frame_time = totalTime() - sTotalTime;
+ return (F32)(U64_to_F64(frame_time) * USEC_TO_SEC_F64);
+}
+
+// Glue code to avoid full class .h file #includes
+F32 getCurrentFrameTime()
+{
+ return (F32)(LLFrameTimer::getCurrentFrameTime());
+}
diff --git a/indra/llcommon/llframetimer.h b/indra/llcommon/llframetimer.h
index 9d55fd1a0b..45754f3785 100644
--- a/indra/llcommon/llframetimer.h
+++ b/indra/llcommon/llframetimer.h
@@ -3,30 +3,25 @@
* @brief A lightweight timer that measures seconds and is only
* updated once per frame.
*
- * $LicenseInfo:firstyear=2002&license=viewergpl$
- *
- * Copyright (c) 2002-2007, Linden Research, Inc.
- *
+ * $LicenseInfo:firstyear=2002&license=viewerlgpl$
* Second Life Viewer Source Code
- * The source code in this file ("Source Code") is provided by Linden Lab
- * to you under the terms of the GNU General Public License, version 2.0
- * ("GPL"), unless you have obtained a separate licensing agreement
- * ("Other License"), formally executed by you and Linden Lab. Terms of
- * the GPL can be found in doc/GPL-license.txt in this distribution, or
- * online at http://secondlife.com/developers/opensource/gplv2
+ * 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.
*
- * There are special exceptions to the terms and conditions of the GPL as
- * it is applied to this Source Code. View the full text of the exception
- * in the file doc/FLOSS-exception.txt in this software distribution, or
- * online at http://secondlife.com/developers/opensource/flossexception
+ * 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.
*
- * By copying, modifying or distributing this software, you acknowledge
- * that you have read and understood your obligations described above,
- * and agree to abide by those obligations.
+ * 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
*
- * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
- * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
- * COMPLETENESS OR PERFORMANCE.
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
* $/LicenseInfo$
*/
@@ -42,7 +37,7 @@
#include "lltimer.h"
#include "timing.h"
-class LLFrameTimer
+class LL_COMMON_API LLFrameTimer
{
public:
LLFrameTimer() : mStartTime( sFrameTime ), mExpiry(0), mStarted(TRUE) {}
@@ -67,13 +62,20 @@ public:
return sTotalSeconds;
}
- // Call this method once per frame to update the current frame time.
+ // Call this method once per frame to update the current frame time. This is actually called
+ // at some other times as well
static void updateFrameTime();
- static S32 getFrameCount() { return sFrameCount; }
+ // Call this method once, and only once, per frame to update the current frame count.
+ static void updateFrameCount() { sFrameCount++; }
+
+ static U32 getFrameCount() { return sFrameCount; }
static F32 getFrameDeltaTimeF32();
+ // Return seconds since the current frame started
+ static F32 getCurrentFrameTime();
+
// MANIPULATORS
void start();
void stop();
@@ -144,4 +146,7 @@ protected:
BOOL mStarted;
};
+// Glue code for Havok (or anything else that doesn't want the full .h files)
+extern F32 getCurrentFrameTime();
+
#endif // LL_LLFRAMETIMER_H
diff --git a/indra/llcommon/llhash.h b/indra/llcommon/llhash.h
index f4b05869a4..c077ebe93f 100644
--- a/indra/llcommon/llhash.h
+++ b/indra/llcommon/llhash.h
@@ -2,30 +2,25 @@
* @file llhash.h
* @brief Wrapper for a hash function.
*
- * $LicenseInfo:firstyear=2004&license=viewergpl$
- *
- * Copyright (c) 2004-2007, Linden Research, Inc.
- *
+ * $LicenseInfo:firstyear=2004&license=viewerlgpl$
* Second Life Viewer Source Code
- * The source code in this file ("Source Code") is provided by Linden Lab
- * to you under the terms of the GNU General Public License, version 2.0
- * ("GPL"), unless you have obtained a separate licensing agreement
- * ("Other License"), formally executed by you and Linden Lab. Terms of
- * the GPL can be found in doc/GPL-license.txt in this distribution, or
- * online at http://secondlife.com/developers/opensource/gplv2
+ * Copyright (C) 2010, Linden Research, Inc.
*
- * There are special exceptions to the terms and conditions of the GPL as
- * it is applied to this Source Code. View the full text of the exception
- * in the file doc/FLOSS-exception.txt in this software distribution, or
- * online at http://secondlife.com/developers/opensource/flossexception
+ * 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.
*
- * By copying, modifying or distributing this software, you acknowledge
- * that you have read and understood your obligations described above,
- * and agree to abide by those obligations.
+ * 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.
*
- * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
- * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
- * COMPLETENESS OR PERFORMANCE.
+ * 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$
*/
@@ -38,7 +33,9 @@
#include <hash_map>
#include <algorithm>
#elif LL_DARWIN || LL_LINUX
-# if GCC_VERSION >= 30400 // gcc 3.4 and up
+# if GCC_VERSION >= 40300 // gcc 4.3 and up
+# include <backward/hashtable.h>
+# elif GCC_VERSION >= 30400 // gcc 3.4 and up
# include <ext/hashtable.h>
# elif __GNUC__ >= 3
# include <ext/stl_hashtable.h>
@@ -51,15 +48,20 @@
#error Please define your platform.
#endif
-template<class T> inline size_t llhash(T value)
-{
+// Warning - an earlier template-based version of this routine did not do
+// the correct thing on Windows. Since this is only used to get
+// a string hash, it was converted to a regular routine and
+// unit tests added.
+
+inline size_t llhash( const char * value )
+{
#if LL_WINDOWS
- return stdext::hash_value<T>(value);
+ return stdext::hash_value(value);
#elif ( (defined _STLPORT_VERSION) || ((LL_LINUX) && (__GNUC__ <= 2)) )
- std::hash<T> H;
+ std::hash<const char *> H;
return H(value);
#elif LL_DARWIN || LL_LINUX || LL_SOLARIS
- __gnu_cxx::hash<T> H;
+ __gnu_cxx::hash<const char *> H;
return H(value);
#else
#error Please define your platform.
diff --git a/indra/llcommon/llheartbeat.cpp b/indra/llcommon/llheartbeat.cpp
new file mode 100644
index 0000000000..18a0c489bd
--- /dev/null
+++ b/indra/llcommon/llheartbeat.cpp
@@ -0,0 +1,165 @@
+/**
+ * @file llheartbeat.cpp
+ * @brief Class encapsulating logic for telling a watchdog that we live.
+ *
+ * $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$
+ */
+
+#include <errno.h>
+#include <signal.h>
+
+#include "linden_common.h"
+#include "llapp.h"
+
+#include "llheartbeat.h"
+
+LLHeartbeat::LLHeartbeat(F32 secs_between_heartbeat,
+ F32 aggressive_heartbeat_panic_secs,
+ F32 aggressive_heartbeat_max_blocking_secs)
+ : mSecsBetweenHeartbeat(secs_between_heartbeat),
+ mAggressiveHeartbeatPanicSecs(aggressive_heartbeat_panic_secs),
+ mAggressiveHeartbeatMaxBlockingSecs(aggressive_heartbeat_max_blocking_secs),
+ mSuppressed(false)
+{
+ mBeatTimer.reset();
+ mBeatTimer.setTimerExpirySec(mSecsBetweenHeartbeat);
+ mPanicTimer.reset();
+ mPanicTimer.setTimerExpirySec(mAggressiveHeartbeatPanicSecs);
+}
+
+LLHeartbeat::~LLHeartbeat()
+{
+ // do nothing.
+}
+
+void
+LLHeartbeat::setSuppressed(bool is_suppressed)
+{
+ mSuppressed = is_suppressed;
+}
+
+// returns 0 on success, -1 on permanent failure, 1 on temporary failure
+int
+LLHeartbeat::rawSend()
+{
+#if LL_WINDOWS
+ return 0; // Pretend we succeeded.
+#else
+ if (mSuppressed)
+ return 0; // Pretend we succeeded.
+
+ int result;
+#ifndef LL_DARWIN
+ union sigval dummy;
+ result = sigqueue(getppid(), LL_HEARTBEAT_SIGNAL, dummy);
+#else
+ result = kill(getppid(), LL_HEARTBEAT_SIGNAL);
+#endif
+ if (result == 0)
+ return 0; // success
+
+ int err = errno;
+ if (err == EAGAIN)
+ return 1; // failed to queue, try again
+
+ return -1; // other failure.
+#endif
+}
+
+int
+LLHeartbeat::rawSendWithTimeout(F32 timeout_sec)
+{
+ int result = 0;
+
+ // Spin tightly until our heartbeat is digested by the watchdog
+ // or we time-out. We don't really want to sleep because our
+ // wake-up time might be undesirably synchronised to a hidden
+ // clock by the system's scheduler.
+ mTimeoutTimer.reset();
+ mTimeoutTimer.setTimerExpirySec(timeout_sec);
+ do {
+ result = rawSend();
+ //llinfos << " HEARTSENDc=" << result << llendl;
+ } while (result==1 && !mTimeoutTimer.hasExpired());
+
+ return result;
+}
+
+bool
+LLHeartbeat::send(F32 timeout_sec)
+{
+ bool total_success = false;
+ int result = 1;
+
+ if (timeout_sec > 0.f) {
+ // force a spin until success or timeout
+ result = rawSendWithTimeout(timeout_sec);
+ } else {
+ if (mBeatTimer.hasExpired()) {
+ // zero-timeout; we don't care too much whether our
+ // heartbeat was digested.
+ result = rawSend();
+ //llinfos << " HEARTSENDb=" << result << llendl;
+ }
+ }
+
+ if (result == -1) {
+ // big failure.
+ } else if (result == 0) {
+ total_success = true;
+ } else {
+ // need to retry at some point
+ }
+
+ if (total_success) {
+ mBeatTimer.reset();
+ mBeatTimer.setTimerExpirySec(mSecsBetweenHeartbeat);
+ // reset the time until we start panicking about lost
+ // heartbeats again.
+ mPanicTimer.reset();
+ mPanicTimer.setTimerExpirySec(mAggressiveHeartbeatPanicSecs);
+ } else {
+ // leave mBeatTimer as expired so we'll lazily poke the
+ // watchdog again next time through.
+ }
+
+ if (mPanicTimer.hasExpired()) {
+ // It's been ages since we successfully had a heartbeat
+ // digested by the watchdog. Sit here and spin a while
+ // in the hope that we can force it through.
+ llwarns << "Unable to deliver heartbeat to launcher for " << mPanicTimer.getElapsedTimeF32() << " seconds. Going to try very hard for up to " << mAggressiveHeartbeatMaxBlockingSecs << " seconds." << llendl;
+ result = rawSendWithTimeout(mAggressiveHeartbeatMaxBlockingSecs);
+ if (result == 0) {
+ total_success = true;
+ } else {
+ // we couldn't even force it through. That's bad,
+ // but we'll try again in a while.
+ llwarns << "Could not deliver heartbeat to launcher even after trying very hard for " << mAggressiveHeartbeatMaxBlockingSecs << " seconds." << llendl;
+ }
+
+ // in any case, reset the panic timer.
+ mPanicTimer.reset();
+ mPanicTimer.setTimerExpirySec(mAggressiveHeartbeatPanicSecs);
+ }
+
+ return total_success;
+}
diff --git a/indra/llcommon/llheartbeat.h b/indra/llcommon/llheartbeat.h
new file mode 100644
index 0000000000..4a75fcc103
--- /dev/null
+++ b/indra/llcommon/llheartbeat.h
@@ -0,0 +1,68 @@
+/**
+ * @file llheartbeat.h
+ * @brief Class encapsulating logic for telling a watchdog that we live.
+ *
+ * $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$
+ */
+
+#ifndef LL_LLHEARTBEAT_H
+#define LL_LLHEARTBEAT_H
+
+#include "linden_common.h"
+
+#include "lltimer.h"
+
+// Note: Win32 does not support the heartbeat/smackdown system;
+// heartbeat-delivery turns into a no-op there.
+
+class LL_COMMON_API LLHeartbeat
+{
+public:
+ // secs_between_heartbeat: after a heartbeat is successfully delivered,
+ // we suppress sending more for this length of time.
+ // aggressive_heartbeat_panic_secs: if we've been failing to
+ // successfully deliver heartbeats for this length of time then
+ // we block for a while until we're really sure we got one delivered.
+ // aggressive_heartbeat_max_blocking_secs: this is the length of
+ // time we block for when we're aggressively ensuring that a 'panic'
+ // heartbeat was delivered.
+ LLHeartbeat(F32 secs_between_heartbeat = 5.0f,
+ F32 aggressive_heartbeat_panic_secs = 10.0f,
+ F32 aggressive_heartbeat_max_blocking_secs = 4.0f);
+ ~LLHeartbeat();
+
+ bool send(F32 timeout_sec = 0.0f);
+ void setSuppressed(bool is_suppressed);
+
+private:
+ int rawSend();
+ int rawSendWithTimeout(F32 timeout_sec);
+ F32 mSecsBetweenHeartbeat;
+ F32 mAggressiveHeartbeatPanicSecs;
+ F32 mAggressiveHeartbeatMaxBlockingSecs;
+ bool mSuppressed;
+ LLTimer mBeatTimer;
+ LLTimer mPanicTimer;
+ LLTimer mTimeoutTimer;
+};
+
+#endif // LL_HEARTBEAT_H
diff --git a/indra/llcommon/llhttpstatuscodes.h b/indra/llcommon/llhttpstatuscodes.h
new file mode 100644
index 0000000000..0173461dad
--- /dev/null
+++ b/indra/llcommon/llhttpstatuscodes.h
@@ -0,0 +1,89 @@
+/**
+ * @file llhttpstatuscodes.h
+ * @brief Constants for HTTP status codes
+ *
+ * $LicenseInfo:firstyear=2001&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$
+ */
+
+#ifndef LL_HTTP_STATUS_CODES_H
+#define LL_HTTP_STATUS_CODES_H
+
+#include "stdtypes.h"
+
+// Standard errors from HTTP spec:
+// http://www.w3.org/Protocols/rfc2616/rfc2616-sec6.html#sec6.1
+const S32 HTTP_CONTINUE = 100;
+const S32 HTTP_SWITCHING_PROTOCOLS = 101;
+
+// Success
+const S32 HTTP_OK = 200;
+const S32 HTTP_CREATED = 201;
+const S32 HTTP_ACCEPTED = 202;
+const S32 HTTP_NON_AUTHORITATIVE_INFORMATION = 203;
+const S32 HTTP_NO_CONTENT = 204;
+const S32 HTTP_RESET_CONTENT = 205;
+const S32 HTTP_PARTIAL_CONTENT = 206;
+
+// Redirection
+const S32 HTTP_MULTIPLE_CHOICES = 300;
+const S32 HTTP_MOVED_PERMANENTLY = 301;
+const S32 HTTP_FOUND = 302;
+const S32 HTTP_SEE_OTHER = 303;
+const S32 HTTP_NOT_MODIFIED = 304;
+const S32 HTTP_USE_PROXY = 305;
+const S32 HTTP_TEMPORARY_REDIRECT = 307;
+
+// Client Error
+const S32 HTTP_BAD_REQUEST = 400;
+const S32 HTTP_UNAUTHORIZED = 401;
+const S32 HTTP_PAYMENT_REQUIRED = 402;
+const S32 HTTP_FORBIDDEN = 403;
+const S32 HTTP_NOT_FOUND = 404;
+const S32 HTTP_METHOD_NOT_ALLOWED = 405;
+const S32 HTTP_NOT_ACCEPTABLE = 406;
+const S32 HTTP_PROXY_AUTHENTICATION_REQUIRED = 407;
+const S32 HTTP_REQUEST_TIME_OUT = 408;
+const S32 HTTP_CONFLICT = 409;
+const S32 HTTP_GONE = 410;
+const S32 HTTP_LENGTH_REQUIRED = 411;
+const S32 HTTP_PRECONDITION_FAILED = 412;
+const S32 HTTP_REQUEST_ENTITY_TOO_LARGE = 413;
+const S32 HTTP_REQUEST_URI_TOO_LARGE = 414;
+const S32 HTTP_UNSUPPORTED_MEDIA_TYPE = 415;
+const S32 HTTP_REQUESTED_RANGE_NOT_SATISFIABLE = 416;
+const S32 HTTP_EXPECTATION_FAILED = 417;
+
+// Server Error
+const S32 HTTP_INTERNAL_SERVER_ERROR = 500;
+const S32 HTTP_NOT_IMPLEMENTED = 501;
+const S32 HTTP_BAD_GATEWAY = 502;
+const S32 HTTP_SERVICE_UNAVAILABLE = 503;
+const S32 HTTP_GATEWAY_TIME_OUT = 504;
+const S32 HTTP_VERSION_NOT_SUPPORTED = 505;
+
+// We combine internal process errors with status codes
+// These status codes should not be sent over the wire
+// and indicate something went wrong internally.
+// If you get these they are not normal.
+const S32 HTTP_INTERNAL_ERROR = 499;
+
+#endif
diff --git a/indra/llcommon/llindexedqueue.h b/indra/llcommon/llindexedqueue.h
index d689f1cab2..aa2675d87d 100644
--- a/indra/llcommon/llindexedqueue.h
+++ b/indra/llcommon/llindexedqueue.h
@@ -3,30 +3,25 @@
* @brief An indexed FIFO queue, where only one element with each key
* can be in the queue.
*
- * $LicenseInfo:firstyear=2003&license=viewergpl$
- *
- * Copyright (c) 2003-2007, Linden Research, Inc.
- *
+ * $LicenseInfo:firstyear=2003&license=viewerlgpl$
* Second Life Viewer Source Code
- * The source code in this file ("Source Code") is provided by Linden Lab
- * to you under the terms of the GNU General Public License, version 2.0
- * ("GPL"), unless you have obtained a separate licensing agreement
- * ("Other License"), formally executed by you and Linden Lab. Terms of
- * the GPL can be found in doc/GPL-license.txt in this distribution, or
- * online at http://secondlife.com/developers/opensource/gplv2
+ * 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.
*
- * There are special exceptions to the terms and conditions of the GPL as
- * it is applied to this Source Code. View the full text of the exception
- * in the file doc/FLOSS-exception.txt in this software distribution, or
- * online at http://secondlife.com/developers/opensource/flossexception
+ * 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.
*
- * By copying, modifying or distributing this software, you acknowledge
- * that you have read and understood your obligations described above,
- * and agree to abide by those obligations.
+ * 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
*
- * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
- * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
- * COMPLETENESS OR PERFORMANCE.
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
* $/LicenseInfo$
*/
diff --git a/indra/llcommon/llinstancetracker.cpp b/indra/llcommon/llinstancetracker.cpp
new file mode 100644
index 0000000000..89bc6cca39
--- /dev/null
+++ b/indra/llcommon/llinstancetracker.cpp
@@ -0,0 +1,37 @@
+/**
+ * @file lllinstancetracker.cpp
+ *
+ * $LicenseInfo:firstyear=2009&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$
+ */
+
+// Precompiled header
+#include "linden_common.h"
+// associated header
+#include "llinstancetracker.h"
+// STL headers
+// std headers
+// external library headers
+// other Linden headers
+
+// llinstancetracker.h is presently header-only. This file exists only because our CMake
+// test macro ADD_BUILD_TEST requires it.
+int dummy = 0;
diff --git a/indra/llcommon/llinstancetracker.h b/indra/llcommon/llinstancetracker.h
new file mode 100644
index 0000000000..4945461d62
--- /dev/null
+++ b/indra/llcommon/llinstancetracker.h
@@ -0,0 +1,190 @@
+/**
+ * @file llinstancetracker.h
+ * @brief LLInstanceTracker is a mixin class that automatically tracks object
+ * instances with or without an associated key
+ *
+ * $LicenseInfo:firstyear=2000&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$
+ */
+
+#ifndef LL_LLINSTANCETRACKER_H
+#define LL_LLINSTANCETRACKER_H
+
+#include <map>
+
+#include "string_table.h"
+#include <boost/utility.hpp>
+#include <boost/function.hpp>
+#include <boost/bind.hpp>
+#include <boost/iterator/transform_iterator.hpp>
+#include <boost/iterator/indirect_iterator.hpp>
+
+/// This mix-in class adds support for tracking all instances of the specified class parameter T
+/// The (optional) key associates a value of type KEY with a given instance of T, for quick lookup
+/// If KEY is not provided, then instances are stored in a simple set
+/// @NOTE: see explicit specialization below for default KEY==T* case
+template<typename T, typename KEY = T*>
+class LLInstanceTracker : boost::noncopyable
+{
+ typedef typename std::map<KEY, T*> InstanceMap;
+ typedef boost::function<const KEY&(typename InstanceMap::value_type&)> KeyGetter;
+ typedef boost::function<T*(typename InstanceMap::value_type&)> InstancePtrGetter;
+public:
+ /// Dereferencing key_iter gives you a const KEY&
+ typedef boost::transform_iterator<KeyGetter, typename InstanceMap::iterator> key_iter;
+ /// Dereferencing instance_iter gives you a T&
+ typedef boost::indirect_iterator< boost::transform_iterator<InstancePtrGetter, typename InstanceMap::iterator> > instance_iter;
+
+ static T* getInstance(const KEY& k)
+ {
+ typename InstanceMap::const_iterator found = getMap_().find(k);
+ return (found == getMap_().end()) ? NULL : found->second;
+ }
+
+ static key_iter beginKeys()
+ {
+ return boost::make_transform_iterator(getMap_().begin(),
+ boost::bind(&InstanceMap::value_type::first, _1));
+ }
+ static key_iter endKeys()
+ {
+ return boost::make_transform_iterator(getMap_().end(),
+ boost::bind(&InstanceMap::value_type::first, _1));
+ }
+ static instance_iter beginInstances()
+ {
+ return instance_iter(boost::make_transform_iterator(getMap_().begin(),
+ boost::bind(&InstanceMap::value_type::second, _1)));
+ }
+ static instance_iter endInstances()
+ {
+ return instance_iter(boost::make_transform_iterator(getMap_().end(),
+ boost::bind(&InstanceMap::value_type::second, _1)));
+ }
+ static S32 instanceCount() { return getMap_().size(); }
+protected:
+ LLInstanceTracker(KEY key) { add_(key); }
+ virtual ~LLInstanceTracker() { remove_(); }
+ virtual void setKey(KEY key) { remove_(); add_(key); }
+ virtual const KEY& getKey() const { return mKey; }
+
+private:
+ void add_(KEY key)
+ {
+ mKey = key;
+ getMap_()[key] = static_cast<T*>(this);
+ }
+ void remove_()
+ {
+ getMap_().erase(mKey);
+ }
+
+ static InstanceMap& getMap_()
+ {
+ if (! sInstances)
+ {
+ sInstances = new InstanceMap;
+ }
+ return *sInstances;
+ }
+
+private:
+
+ KEY mKey;
+ static InstanceMap* sInstances;
+};
+
+/// explicit specialization for default case where KEY is T*
+/// use a simple std::set<T*>
+template<typename T>
+class LLInstanceTracker<T, T*>
+{
+ typedef typename std::set<T*> InstanceSet;
+public:
+ /// Dereferencing key_iter gives you a T* (since T* is the key)
+ typedef typename InstanceSet::iterator key_iter;
+ /// Dereferencing instance_iter gives you a T&
+ typedef boost::indirect_iterator<key_iter> instance_iter;
+
+ /// for completeness of analogy with the generic implementation
+ static T* getInstance(T* k) { return k; }
+ static S32 instanceCount() { return getSet_().size(); }
+
+ // Instantiate this to get access to iterators for this type. It's a 'guard' in the sense
+ // that it treats deletes of this type as errors as long as there is an instance of
+ // this class alive in scope somewhere (i.e. deleting while iterating is bad).
+ class LLInstanceTrackerScopedGuard
+ {
+ public:
+ LLInstanceTrackerScopedGuard()
+ {
+ ++sIterationNestDepth;
+ }
+
+ ~LLInstanceTrackerScopedGuard()
+ {
+ --sIterationNestDepth;
+ }
+
+ static instance_iter beginInstances() { return instance_iter(getSet_().begin()); }
+ static instance_iter endInstances() { return instance_iter(getSet_().end()); }
+ static key_iter beginKeys() { return getSet_().begin(); }
+ static key_iter endKeys() { return getSet_().end(); }
+ };
+
+protected:
+ LLInstanceTracker()
+ {
+ // it's safe but unpredictable to create instances of this type while all instances are being iterated over. I hate unpredictable. This assert will probably be turned on early in the next development cycle.
+ //llassert(sIterationNestDepth == 0);
+ getSet_().insert(static_cast<T*>(this));
+ }
+ virtual ~LLInstanceTracker()
+ {
+ // it's unsafe to delete instances of this type while all instances are being iterated over.
+ llassert(sIterationNestDepth == 0);
+ getSet_().erase(static_cast<T*>(this));
+ }
+
+ LLInstanceTracker(const LLInstanceTracker& other)
+ {
+ //llassert(sIterationNestDepth == 0);
+ getSet_().insert(static_cast<T*>(this));
+ }
+
+ static InstanceSet& getSet_()
+ {
+ if (! sInstances)
+ {
+ sInstances = new InstanceSet;
+ }
+ return *sInstances;
+ }
+
+ static InstanceSet* sInstances;
+ static S32 sIterationNestDepth;
+};
+
+template <typename T, typename KEY> typename LLInstanceTracker<T, KEY>::InstanceMap* LLInstanceTracker<T, KEY>::sInstances = NULL;
+template <typename T> typename LLInstanceTracker<T, T*>::InstanceSet* LLInstanceTracker<T, T*>::sInstances = NULL;
+template <typename T> S32 LLInstanceTracker<T, T*>::sIterationNestDepth = 0;
+
+#endif
diff --git a/indra/llcommon/llkeythrottle.h b/indra/llcommon/llkeythrottle.h
index d831eadd59..1f576cc19e 100644
--- a/indra/llcommon/llkeythrottle.h
+++ b/indra/llcommon/llkeythrottle.h
@@ -1,30 +1,25 @@
/**
* @file llkeythrottle.h
*
- * $LicenseInfo:firstyear=2005&license=viewergpl$
- *
- * Copyright (c) 2005-2008, Linden Research, Inc.
- *
+ * $LicenseInfo:firstyear=2005&license=viewerlgpl$
* Second Life Viewer Source Code
- * The source code in this file ("Source Code") is provided by Linden Lab
- * to you under the terms of the GNU General Public License, version 2.0
- * ("GPL"), unless you have obtained a separate licensing agreement
- * ("Other License"), formally executed by you and Linden Lab. Terms of
- * the GPL can be found in doc/GPL-license.txt in this distribution, or
- * online at http://secondlife.com/developers/opensource/gplv2
+ * 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.
*
- * There are special exceptions to the terms and conditions of the GPL as
- * it is applied to this Source Code. View the full text of the exception
- * in the file doc/FLOSS-exception.txt in this software distribution, or
- * online at http://secondlife.com/developers/opensource/flossexception
+ * 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.
*
- * By copying, modifying or distributing this software, you acknowledge
- * that you have read and understood your obligations described above,
- * and agree to abide by those obligations.
+ * 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
*
- * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
- * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
- * COMPLETENESS OR PERFORMANCE.
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
* $/LicenseInfo$
*/
@@ -55,33 +50,40 @@ class LLKeyThrottleImpl
protected:
struct Entry {
U32 count;
- BOOL blocked;
+ bool blocked;
- Entry() : count(0), blocked(FALSE) { }
+ Entry() : count(0), blocked(false) { }
};
typedef std::map<T, Entry> EntryMap;
- EntryMap * prevMap;
- EntryMap * currMap;
+ EntryMap* prevMap;
+ EntryMap* currMap;
U32 countLimit;
// maximum number of keys allowed per interval
- U64 interval_usec;
- // each map covers this time period
- U64 start_usec;
+ U64 intervalLength; // each map covers this time period (usec or frame number)
+ U64 startTime; // start of the time period (usec or frame number)
// currMap started counting at this time
// prevMap covers the previous interval
- LLKeyThrottleImpl() : prevMap(0), currMap(0),
- countLimit(0), interval_usec(0),
- start_usec(0) { };
+ LLKeyThrottleImpl() :
+ prevMap(NULL),
+ currMap(NULL),
+ countLimit(0),
+ intervalLength(1),
+ startTime(0)
+ {}
static U64 getTime()
{
return LLFrameTimer::getTotalTime();
}
+ static U64 getFrame() // Return the current frame number
+ {
+ return (U64) LLFrameTimer::getFrameCount();
+ }
};
@@ -89,17 +91,12 @@ template< class T >
class LLKeyThrottle
{
public:
- LLKeyThrottle(U32 limit, F32 interval)
+ // @param realtime = FALSE for frame-based throttle, TRUE for usec
+ // real-time throttle
+ LLKeyThrottle(U32 limit, F32 interval, BOOL realtime = TRUE)
: m(* new LLKeyThrottleImpl<T>)
{
- // limit is the maximum number of keys
- // allowed per interval (in seconds)
- m.countLimit = limit;
- m.interval_usec = (U64)(interval * USEC_PER_SEC);
- m.start_usec = LLKeyThrottleImpl<T>::getTime();
-
- m.prevMap = new typename LLKeyThrottleImpl<T>::EntryMap;
- m.currMap = new typename LLKeyThrottleImpl<T>::EntryMap;
+ setParameters( limit, interval, realtime );
}
~LLKeyThrottle()
@@ -115,21 +112,86 @@ 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)
{
- U64 now = LLKeyThrottleImpl<T>::getTime();
+ U64 now = 0;
+ if ( mIsRealtime )
+ {
+ now = LLKeyThrottleImpl<T>::getTime();
+ }
+ else
+ {
+ now = LLKeyThrottleImpl<T>::getFrame();
+ }
- if (now >= (m.start_usec + m.interval_usec))
+ if (now >= (m.startTime + m.intervalLength))
{
- if (now < (m.start_usec + 2 * m.interval_usec))
+ 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.start_usec += m.interval_usec;
+ m.startTime += m.intervalLength;
}
else
{
@@ -139,12 +201,12 @@ public:
m.prevMap = new typename LLKeyThrottleImpl<T>::EntryMap;
m.currMap = new typename LLKeyThrottleImpl<T>::EntryMap;
- m.start_usec = now;
+ m.startTime = now;
}
}
U32 prevCount = 0;
- BOOL prevBlocked = FALSE;
+ bool prevBlocked = false;
typename LLKeyThrottleImpl<T>::EntryMap::const_iterator prev = m.prevMap->find(id);
if (prev != m.prevMap->end())
@@ -166,7 +228,7 @@ public:
// (now) time.
// compute current, windowed rate
- F64 timeInCurrent = ((F64)(now - m.start_usec) / m.interval_usec);
+ F64 timeInCurrent = ((F64)(now - m.startTime) / m.intervalLength);
F64 averageCount = curr.count + prevCount * (1.0 - timeInCurrent);
curr.blocked |= averageCount > m.countLimit;
@@ -193,17 +255,17 @@ public:
noteAction(id);
typename LLKeyThrottleImpl<T>::Entry& curr = (*m.currMap)[id];
curr.count = llmax(m.countLimit, curr.count);
- curr.blocked = TRUE;
+ curr.blocked = true;
}
- // returns TRUE if key is blocked
- BOOL isThrottled(const T& id) const
+ // returns true if key is blocked
+ bool isThrottled(const T& id) const
{
if (m.currMap->empty()
&& m.prevMap->empty())
{
// most of the time we'll fall in here
- return FALSE;
+ return false;
}
// NOTE, we ignore the case where id is in the map but the map is stale.
@@ -221,11 +283,49 @@ public:
{
return entry->second.blocked;
}
- return FALSE;
+ return false;
+ }
+
+ // Get the throttling parameters
+ void getParameters( U32 & out_limit, F32 & out_interval, BOOL & out_realtime )
+ {
+ out_limit = m.countLimit;
+ out_interval = m.intervalLength;
+ out_realtime = mIsRealtime;
+ }
+
+ // Set the throttling behavior
+ void setParameters( U32 limit, F32 interval, BOOL realtime = TRUE )
+ {
+ // limit is the maximum number of keys
+ // allowed per interval (in seconds or frames)
+ mIsRealtime = realtime;
+ m.countLimit = limit;
+ if ( mIsRealtime )
+ {
+ m.intervalLength = (U64)(interval * USEC_PER_SEC);
+ m.startTime = LLKeyThrottleImpl<T>::getTime();
+ }
+ else
+ {
+ m.intervalLength = (U64)interval;
+ m.startTime = LLKeyThrottleImpl<T>::getFrame();
+ }
+
+ if ( m.intervalLength == 0 )
+ { // Don't allow zero intervals
+ m.intervalLength = 1;
+ }
+
+ delete m.prevMap;
+ m.prevMap = new typename LLKeyThrottleImpl<T>::EntryMap;
+ delete m.currMap;
+ m.currMap = new typename LLKeyThrottleImpl<T>::EntryMap;
}
protected:
LLKeyThrottleImpl<T>& m;
+ BOOL mIsRealtime; // TRUE to be time based (default), FALSE for frame based
};
#endif
diff --git a/indra/llcommon/llkeyusetracker.h b/indra/llcommon/llkeyusetracker.h
new file mode 100644
index 0000000000..1fb222dd40
--- /dev/null
+++ b/indra/llcommon/llkeyusetracker.h
@@ -0,0 +1,215 @@
+/**
+ * @file llkeyusetracker.h
+ * @brief Declaration of the LLKeyUseTracker class.
+ *
+ * $LicenseInfo:firstyear=2003&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$
+ */
+
+#ifndef LL_KEYUSETRACKER_H
+#define LL_KEYUSETRACKER_H
+
+// This is a generic cache for an arbitrary data type indexed against an
+// arbitrary key type. The cache length is determined by expiration time
+// tince against last use and set size. The age of elements and the size
+// of the cache are queryable.
+//
+// This is implemented as a list, which makes search O(n). If you reuse this
+// for something with a large dataset, consider reimplementing with a Boost
+// multimap based on both a map(key) and priority queue(last_use).
+
+template <class TKey, class TData>
+class KeyUseTrackerNodeImpl
+{
+public:
+ U64 mLastUse;
+ U32 mUseCount;
+ TKey mKey;
+ TData mData;
+
+ KeyUseTrackerNodeImpl( TKey k, TData d ) :
+ mLastUse(0),
+ mUseCount(0),
+ mKey( k ),
+ mData( d )
+ {
+ }
+};
+
+
+template <class TKey, class TData>
+class LLKeyUseTracker
+{
+ typedef KeyUseTrackerNodeImpl<TKey,TData> TKeyUseTrackerNode;
+ typedef std::list<TKeyUseTrackerNode *> TKeyList;
+ TKeyList mKeyList;
+ U64 mMemUsecs;
+ U64 mLastExpire;
+ U32 mMaxCount;
+ U32 mCount;
+
+ static U64 getTime()
+ {
+ // This function operates on a frame basis, not instantaneous.
+ // We can rely on its output for determining first use in a
+ // frame.
+ return LLFrameTimer::getTotalTime();
+ }
+
+ void ageKeys()
+ {
+ U64 now = getTime();
+ if( now == mLastExpire )
+ {
+ return;
+ }
+ mLastExpire = now;
+
+ while( !mKeyList.empty() && (now - mKeyList.front()->mLastUse > mMemUsecs ) )
+ {
+ delete mKeyList.front();
+ mKeyList.pop_front();
+ mCount--;
+ }
+ }
+
+ TKeyUseTrackerNode *findNode( TKey key )
+ {
+ ageKeys();
+
+ typename TKeyList::iterator i;
+ for( i = mKeyList.begin(); i != mKeyList.end(); i++ )
+ {
+ if( (*i)->mKey == key )
+ return *i;
+ }
+
+ return NULL;
+ }
+
+ TKeyUseTrackerNode *removeNode( TKey key )
+ {
+ TKeyUseTrackerNode *i;
+ i = findNode( key );
+ if( i )
+ {
+ mKeyList.remove( i );
+ mCount--;
+ return i;
+ }
+
+ return NULL;
+ }
+
+public:
+ LLKeyUseTracker( U32 memory_seconds, U32 max_count ) :
+ mLastExpire(0),
+ mMaxCount( max_count ),
+ mCount(0)
+ {
+ mMemUsecs = ((U64)memory_seconds) * 1000000;
+ }
+
+ ~LLKeyUseTracker()
+ {
+ // Flush list
+ while( !mKeyList.empty() )
+ {
+ delete mKeyList.front();
+ mKeyList.pop_front();
+ mCount--;
+ }
+ }
+
+ void markUse( TKey key, TData data )
+ {
+ TKeyUseTrackerNode *node = removeNode( key );
+ if( !node )
+ {
+ node = new TKeyUseTrackerNode(key, data);
+ }
+ else
+ {
+ // Update data
+ node->mData = data;
+ }
+ node->mLastUse = getTime();
+ node->mUseCount++;
+ mKeyList.push_back( node );
+ mCount++;
+
+ // Too many items? Drop head
+ if( mCount > mMaxCount )
+ {
+ delete mKeyList.front();
+ mKeyList.pop_front();
+ mCount--;
+ }
+ }
+
+ void forgetKey( TKey key )
+ {
+ TKeyUseTrackerNode *node = removeNode( key );
+ if( node )
+ {
+ delete node;
+ }
+ }
+
+ U32 getUseCount( TKey key )
+ {
+ TKeyUseTrackerNode *node = findNode( key );
+ if( node )
+ {
+ return node->mUseCount;
+ }
+ return 0;
+ }
+
+ U64 getTimeSinceUse( TKey key )
+ {
+ TKeyUseTrackerNode *node = findNode( key );
+ if( node )
+ {
+ U64 now = getTime();
+ U64 delta = now - node->mLastUse;
+ return (U32)( delta / 1000000 );
+ }
+ return 0;
+ }
+
+ TData *getLastUseData( TKey key )
+ {
+ TKeyUseTrackerNode *node = findNode( key );
+ if( node )
+ {
+ return &node->mData;
+ }
+ return NULL;
+ }
+
+ U32 getKeyCount()
+ {
+ return mCount;
+ }
+};
+
+#endif
diff --git a/indra/llcommon/lllazy.cpp b/indra/llcommon/lllazy.cpp
new file mode 100644
index 0000000000..29fa040387
--- /dev/null
+++ b/indra/llcommon/lllazy.cpp
@@ -0,0 +1,40 @@
+/**
+ * @file lllazy.cpp
+ * @author Nat Goodspeed
+ * @date 2009-01-28
+ * @brief Implementation for lllazy.
+ *
+ * $LicenseInfo:firstyear=2009&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$
+ */
+
+// Precompiled header
+#include "linden_common.h"
+// associated header
+#include "lllazy.h"
+// STL headers
+// std headers
+// external library headers
+// other Linden headers
+
+// lllazy.h is presently header-only. This file exists only because our CMake
+// test macro ADD_BUILD_TEST requires it.
+int dummy = 0;
diff --git a/indra/llcommon/lllazy.h b/indra/llcommon/lllazy.h
new file mode 100644
index 0000000000..5f3bbce79e
--- /dev/null
+++ b/indra/llcommon/lllazy.h
@@ -0,0 +1,399 @@
+/**
+ * @file lllazy.h
+ * @author Nat Goodspeed
+ * @date 2009-01-22
+ * @brief Lazy instantiation of specified type. Useful in conjunction with
+ * Michael Feathers's "Extract and Override Getter" ("Working
+ * Effectively with Legacy Code", p. 352).
+ *
+ * Quoting his synopsis of steps on p.355:
+ *
+ * 1. Identify the object you need a getter for.
+ * 2. Extract all of the logic needed to create the object into a getter.
+ * 3. Replace all uses of the object with calls to the getter, and initialize
+ * the reference that holds the object to null in all constructors.
+ * 4. Add the first-time logic to the getter so that the object is constructed
+ * and assigned to the reference whenever the reference is null.
+ * 5. Subclass the class and override the getter to provide an alternative
+ * object for testing.
+ *
+ * It's the second half of bullet 3 (3b, as it were) that bothers me. I find
+ * it all too easy to imagine adding pointer initializers to all but one
+ * constructor... the one not exercised by my tests. That suggested using
+ * (e.g.) boost::scoped_ptr<MyObject> so you don't have to worry about
+ * destroying it either.
+ *
+ * However, introducing additional machinery allows us to encapsulate bullet 4
+ * as well.
+ *
+ * $LicenseInfo:firstyear=2009&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_LLLAZY_H)
+#define LL_LLLAZY_H
+
+#include <boost/function.hpp>
+#include <boost/scoped_ptr.hpp>
+#include <boost/lambda/construct.hpp>
+#include <stdexcept>
+
+/// LLLazyCommon simply factors out of LLLazy<T> things that don't depend on
+/// its template parameter.
+class LLLazyCommon
+{
+public:
+ /**
+ * This exception is thrown if you try to replace an LLLazy<T>'s factory
+ * (or T* instance) after it already has an instance in hand. Since T
+ * might well be stateful, we can't know the effect of silently discarding
+ * and replacing an existing instance, so we disallow it. This facility is
+ * intended for testing, and in a test scenario we can definitely control
+ * that.
+ */
+ struct InstanceChange: public std::runtime_error
+ {
+ InstanceChange(const std::string& what): std::runtime_error(what) {}
+ };
+
+protected:
+ /**
+ * InstanceChange might be appropriate in a couple of different LLLazy<T>
+ * methods. Factor out the common logic.
+ */
+ template <typename PTR>
+ static void ensureNoInstance(const PTR& ptr)
+ {
+ if (ptr)
+ {
+ // Too late: we've already instantiated the lazy object. We don't
+ // know whether it's stateful or not, so it's not safe to discard
+ // the existing instance in favor of a replacement.
+ throw InstanceChange("Too late to replace LLLazy instance");
+ }
+ }
+};
+
+/**
+ * LLLazy<T> is useful when you have an outer class Outer that you're trying
+ * to bring under unit test, that contains a data member difficult to
+ * instantiate in a test harness. Typically the data member's class Inner has
+ * many thorny dependencies. Feathers generally advocates "Extract and
+ * Override Factory Method" (p. 350). But in C++, you can't call a derived
+ * class override of a virtual method from the derived class constructor,
+ * which limits applicability of "Extract and Override Factory Method." For
+ * such cases Feathers presents "Extract and Override Getter" (p. 352).
+ *
+ * So we'll assume that your class Outer contains a member like this:
+ * @code
+ * Inner mInner;
+ * @endcode
+ *
+ * LLLazy<Inner> can be used to replace this member. You can directly declare:
+ * @code
+ * LLLazy<Inner> mInner;
+ * @endcode
+ * and change references to mInner accordingly.
+ *
+ * (Alternatively, you can add a base class of the form
+ * <tt>LLLazyBase<Inner></tt>. This is discussed further in the LLLazyBase<T>
+ * documentation.)
+ *
+ * LLLazy<T> binds a <tt>boost::scoped_ptr<T></tt> and a factory functor
+ * returning T*. You can either bind that functor explicitly or let it default
+ * to the expression <tt>new T()</tt>.
+ *
+ * As long as LLLazy<T> remains unreferenced, its T remains uninstantiated.
+ * The first time you use get(), <tt>operator*()</tt> or <tt>operator->()</tt>
+ * it will instantiate its T and thereafter behave like a pointer to it.
+ *
+ * Thus, any existing reference to <tt>mInner.member</tt> should be replaced
+ * with <tt>mInner->member</tt>. Any simple reference to @c mInner should be
+ * replaced by <tt>*mInner</tt>.
+ *
+ * (If the original declaration was a pointer initialized in Outer's
+ * constructor, e.g. <tt>Inner* mInner</tt>, so much the better. In that case
+ * you should be able to drop in <tt>LLLazy<Inner></tt> without much change.)
+ *
+ * The support for "Extract and Override Getter" lies in the fact that you can
+ * replace the factory functor -- or provide an explicit T*. Presumably this
+ * is most useful from a test subclass -- which suggests that your @c mInner
+ * member should be @c protected.
+ *
+ * Note that <tt>boost::lambda::new_ptr<T>()</tt> makes a dandy factory
+ * functor, for either the set() method or LLLazy<T>'s constructor. If your T
+ * requires constructor arguments, use an expression more like
+ * <tt>boost::lambda::bind(boost::lambda::new_ptr<T>(), arg1, arg2, ...)</tt>.
+ *
+ * Of course the point of replacing the functor is to substitute a class that,
+ * though referenced as Inner*, is not an Inner; presumably this is a testing
+ * subclass of Inner (e.g. TestInner). Thus your test subclass TestOuter for
+ * the containing class Outer will contain something like this:
+ * @code
+ * class TestOuter: public Outer
+ * {
+ * public:
+ * TestOuter()
+ * {
+ * // mInner must be 'protected' rather than 'private'
+ * mInner.set(boost::lambda::new_ptr<TestInner>());
+ * }
+ * ...
+ * };
+ * @endcode
+ */
+template <typename T>
+class LLLazy: public LLLazyCommon
+{
+public:
+ /// Any nullary functor returning T* will work as a Factory
+ typedef boost::function<T* ()> Factory;
+
+ /// The default LLLazy constructor uses <tt>new T()</tt> as its Factory
+ LLLazy():
+ mFactory(boost::lambda::new_ptr<T>())
+ {}
+
+ /// Bind an explicit Factory functor
+ LLLazy(const Factory& factory):
+ mFactory(factory)
+ {}
+
+ /// Reference T, instantiating it if this is the first access
+ const T& get() const
+ {
+ if (! mInstance)
+ {
+ // use the bound Factory functor
+ mInstance.reset(mFactory());
+ }
+ return *mInstance;
+ }
+
+ /// non-const get()
+ T& get()
+ {
+ return const_cast<T&>(const_cast<const LLLazy<T>*>(this)->get());
+ }
+
+ /// operator*() is equivalent to get()
+ const T& operator*() const { return get(); }
+ /// operator*() is equivalent to get()
+ T& operator*() { return get(); }
+
+ /**
+ * operator->() must return (something resembling) T*. It's tempting to
+ * return the underlying boost::scoped_ptr<T>, but that would require
+ * breaking out the lazy-instantiation logic from get() into a common
+ * private method. Assume the pointer used for operator->() access is very
+ * short-lived.
+ */
+ const T* operator->() const { return &get(); }
+ /// non-const operator->()
+ T* operator->() { return &get(); }
+
+ /// set(Factory). This will throw InstanceChange if mInstance has already
+ /// been set.
+ void set(const Factory& factory)
+ {
+ ensureNoInstance(mInstance);
+ mFactory = factory;
+ }
+
+ /// set(T*). This will throw InstanceChange if mInstance has already been
+ /// set.
+ void set(T* instance)
+ {
+ ensureNoInstance(mInstance);
+ mInstance.reset(instance);
+ }
+
+private:
+ Factory mFactory;
+ // Consider an LLLazy<T> member of a class we're accessing by const
+ // reference. We want to allow even const methods to touch the LLLazy<T>
+ // member. Hence the actual pointer must be mutable because such access
+ // might assign it.
+ mutable boost::scoped_ptr<T> mInstance;
+};
+
+#if (! defined(__GNUC__)) || (__GNUC__ > 3) || (__GNUC__ == 3 && __GNUC_MINOR__ > 3)
+// Not gcc at all, or a gcc more recent than gcc 3.3
+#define GCC33 0
+#else
+#define GCC33 1
+#endif
+
+/**
+ * LLLazyBase<T> wraps LLLazy<T>, giving you an alternative way to replace
+ * <tt>Inner mInner;</tt>. Instead of coding <tt>LLLazy<Inner> mInner</tt>,
+ * you can add LLLazyBase<Inner> to your Outer class's bases, e.g.:
+ * @code
+ * class Outer: public LLLazyBase<Inner>
+ * {
+ * ...
+ * };
+ * @endcode
+ *
+ * This gives you @c public get() and @c protected set() methods without
+ * having to make your LLLazy<Inner> member @c protected. The tradeoff is that
+ * you must access the wrapped LLLazy<Inner> using get() and set() rather than
+ * with <tt>operator*()</tt> or <tt>operator->()</tt>.
+ *
+ * This mechanism can be used for more than one member, but only if they're of
+ * different types. That is, you can replace:
+ * @code
+ * DifficultClass mDifficult;
+ * AwkwardType mAwkward;
+ * @endcode
+ * with:
+ * @code
+ * class Outer: public LLLazyBase<DifficultClass>, public LLLazyBase<AwkwardType>
+ * {
+ * ...
+ * };
+ * @endcode
+ * but for a situation like this:
+ * @code
+ * DifficultClass mMainDifficult, mAuxDifficult;
+ * @endcode
+ * you should directly embed LLLazy<DifficultClass> (q.v.).
+ *
+ * For multiple LLLazyBase bases, e.g. the <tt>LLLazyBase<DifficultClass>,
+ * LLLazyBase<AwkwardType></tt> example above, access the relevant get()/set()
+ * as (e.g.) <tt>LLLazyBase<DifficultClass>::get()</tt>. (This is why you
+ * can't have multiple LLLazyBase<T> of the same T.) For a bit of syntactic
+ * sugar, please see getLazy()/setLazy().
+ */
+template <typename T>
+class LLLazyBase
+{
+public:
+ /// invoke default LLLazy constructor
+ LLLazyBase() {}
+ /// make wrapped LLLazy bind an explicit Factory
+ LLLazyBase(const typename LLLazy<T>::Factory& factory):
+ mInstance(factory)
+ {}
+
+ /// access to LLLazy::get()
+ T& get() { return *mInstance; }
+ /// access to LLLazy::get()
+ const T& get() const { return *mInstance; }
+
+protected:
+ // see getLazy()/setLazy()
+ #if (! GCC33)
+ template <typename T2, class MYCLASS> friend T2& getLazy(MYCLASS* this_);
+ template <typename T2, class MYCLASS> friend const T2& getLazy(const MYCLASS* this_);
+ #else // gcc 3.3
+ template <typename T2, class MYCLASS> friend T2& getLazy(const MYCLASS* this_);
+ #endif // gcc 3.3
+ template <typename T2, class MYCLASS> friend void setLazy(MYCLASS* this_, T2* instance);
+ template <typename T2, class MYCLASS>
+ friend void setLazy(MYCLASS* this_, const typename LLLazy<T2>::Factory& factory);
+
+ /// access to LLLazy::set(Factory)
+ void set(const typename LLLazy<T>::Factory& factory)
+ {
+ mInstance.set(factory);
+ }
+
+ /// access to LLLazy::set(T*)
+ void set(T* instance)
+ {
+ mInstance.set(instance);
+ }
+
+private:
+ LLLazy<T> mInstance;
+};
+
+/**
+ * @name getLazy()/setLazy()
+ * Suppose you have something like the following:
+ * @code
+ * class Outer: public LLLazyBase<DifficultClass>, public LLLazyBase<AwkwardType>
+ * {
+ * ...
+ * };
+ * @endcode
+ *
+ * Your methods can reference the @c DifficultClass instance using
+ * <tt>LLLazyBase<DifficultClass>::get()</tt>, which is admittedly a bit ugly.
+ * Alternatively, you can write <tt>getLazy<DifficultClass>(this)</tt>, which
+ * is somewhat more straightforward to read.
+ *
+ * Similarly,
+ * @code
+ * LLLazyBase<DifficultClass>::set(new TestDifficultClass());
+ * @endcode
+ * could instead be written:
+ * @code
+ * setLazy<DifficultClass>(this, new TestDifficultClass());
+ * @endcode
+ *
+ * @note
+ * I wanted to provide getLazy() and setLazy() without explicitly passing @c
+ * this. That would imply making them methods on a base class rather than free
+ * functions. But if <tt>LLLazyBase<T></tt> derives normally from (say) @c
+ * LLLazyGrandBase providing those methods, then unqualified getLazy() would
+ * be ambiguous: you'd have to write <tt>LLLazyBase<T>::getLazy<T>()</tt>,
+ * which is even uglier than <tt>LLLazyBase<T>::get()</tt>, and therefore
+ * pointless. You can make the compiler not care which @c LLLazyGrandBase
+ * instance you're talking about by making @c LLLazyGrandBase a @c virtual
+ * base class of @c LLLazyBase. But in that case,
+ * <tt>LLLazyGrandBase::getLazy<T>()</tt> can't access
+ * <tt>LLLazyBase<T>::get()</tt>!
+ *
+ * We want <tt>getLazy<T>()</tt> to access <tt>LLLazyBase<T>::get()</tt> as if
+ * in the lexical context of some subclass method. Ironically, free functions
+ * let us do that better than methods on a @c virtual base class -- but that
+ * implies passing @c this explicitly. So be it.
+ */
+//@{
+#if (! GCC33)
+template <typename T, class MYCLASS>
+T& getLazy(MYCLASS* this_) { return this_->LLLazyBase<T>::get(); }
+template <typename T, class MYCLASS>
+const T& getLazy(const MYCLASS* this_) { return this_->LLLazyBase<T>::get(); }
+#else // gcc 3.3
+// For const-correctness, we really should have two getLazy() variants: one
+// accepting const MYCLASS* and returning const T&, the other accepting
+// non-const MYCLASS* and returning non-const T&. This works fine on the Mac
+// (gcc 4.0.1) and Windows (MSVC 8.0), but fails on our Linux 32-bit Debian
+// Sarge stations (gcc 3.3.5). Since I really don't know how to beat that aging
+// compiler over the head to make it do the right thing, I'm going to have to
+// move forward with the wrong thing: a single getLazy() function that accepts
+// const MYCLASS* and returns non-const T&.
+template <typename T, class MYCLASS>
+T& getLazy(const MYCLASS* this_) { return const_cast<MYCLASS*>(this_)->LLLazyBase<T>::get(); }
+#endif // gcc 3.3
+template <typename T, class MYCLASS>
+void setLazy(MYCLASS* this_, T* instance) { this_->LLLazyBase<T>::set(instance); }
+template <typename T, class MYCLASS>
+void setLazy(MYCLASS* this_, const typename LLLazy<T>::Factory& factory)
+{
+ this_->LLLazyBase<T>::set(factory);
+}
+//@}
+
+#endif /* ! defined(LL_LLLAZY_H) */
diff --git a/indra/llcommon/lllinkedqueue.h b/indra/llcommon/lllinkedqueue.h
index dcd13a21d6..8336608809 100644
--- a/indra/llcommon/lllinkedqueue.h
+++ b/indra/llcommon/lllinkedqueue.h
@@ -2,30 +2,25 @@
* @file lllinkedqueue.h
* @brief Declaration of linked queue classes.
*
- * $LicenseInfo:firstyear=2003&license=viewergpl$
- *
- * Copyright (c) 2003-2007, Linden Research, Inc.
- *
+ * $LicenseInfo:firstyear=2003&license=viewerlgpl$
* Second Life Viewer Source Code
- * The source code in this file ("Source Code") is provided by Linden Lab
- * to you under the terms of the GNU General Public License, version 2.0
- * ("GPL"), unless you have obtained a separate licensing agreement
- * ("Other License"), formally executed by you and Linden Lab. Terms of
- * the GPL can be found in doc/GPL-license.txt in this distribution, or
- * online at http://secondlife.com/developers/opensource/gplv2
+ * 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.
*
- * There are special exceptions to the terms and conditions of the GPL as
- * it is applied to this Source Code. View the full text of the exception
- * in the file doc/FLOSS-exception.txt in this software distribution, or
- * online at http://secondlife.com/developers/opensource/flossexception
+ * 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.
*
- * By copying, modifying or distributing this software, you acknowledge
- * that you have read and understood your obligations described above,
- * and agree to abide by those obligations.
+ * 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
*
- * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
- * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
- * COMPLETENESS OR PERFORMANCE.
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
* $/LicenseInfo$
*/
diff --git a/indra/llcommon/lllistenerwrapper.h b/indra/llcommon/lllistenerwrapper.h
new file mode 100644
index 0000000000..09d074abca
--- /dev/null
+++ b/indra/llcommon/lllistenerwrapper.h
@@ -0,0 +1,198 @@
+/**
+ * @file lllistenerwrapper.h
+ * @author Nat Goodspeed
+ * @date 2009-11-30
+ * @brief Introduce LLListenerWrapper template
+ *
+ * $LicenseInfo:firstyear=2009&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_LLLISTENERWRAPPER_H)
+#define LL_LLLISTENERWRAPPER_H
+
+#include "llevents.h" // LLListenerWrapperBase
+#include <boost/visit_each.hpp>
+
+/**
+ * Template base class for coding wrappers for LLEventPump listeners.
+ *
+ * Derive your listener wrapper from LLListenerWrapper. You must use
+ * LLLISTENER_WRAPPER_SUBCLASS() so your subclass will play nicely with
+ * boost::visit_each (q.v.). That way boost::signals2 can still detect
+ * derivation from LLEventTrackable, and so forth.
+ */
+template <typename LISTENER>
+class LLListenerWrapper: public LLListenerWrapperBase
+{
+public:
+ /// Wrap an arbitrary listener object
+ LLListenerWrapper(const LISTENER& listener):
+ mListener(listener)
+ {}
+
+ /// call
+ virtual bool operator()(const LLSD& event)
+ {
+ return mListener(event);
+ }
+
+ /// Allow boost::visit_each() to peek at our mListener.
+ template <class V>
+ void accept_visitor(V& visitor) const
+ {
+ using boost::visit_each;
+ visit_each(visitor, mListener, 0);
+ }
+
+private:
+ LISTENER mListener;
+};
+
+/**
+ * Specialize boost::visit_each() (leveraging ADL) to peek inside an
+ * LLListenerWrapper<T> to traverse its LISTENER. We borrow the
+ * accept_visitor() pattern from boost::bind(), avoiding the need to make
+ * mListener public.
+ */
+template <class V, typename T>
+void visit_each(V& visitor, const LLListenerWrapper<T>& wrapper, int)
+{
+ wrapper.accept_visitor(visitor);
+}
+
+/// use this (sigh!) for each subclass of LLListenerWrapper<T> you write
+#define LLLISTENER_WRAPPER_SUBCLASS(CLASS) \
+template <class V, typename T> \
+void visit_each(V& visitor, const CLASS<T>& wrapper, int) \
+{ \
+ visit_each(visitor, static_cast<const LLListenerWrapper<T>&>(wrapper), 0); \
+} \
+ \
+/* Have to state this explicitly, rather than using LL_TEMPLATE_CONVERTIBLE, */ \
+/* because the source type is itself a template. */ \
+template <typename T> \
+struct ll_template_cast_impl<const LLListenerWrapperBase*, const CLASS<T>*> \
+{ \
+ const LLListenerWrapperBase* operator()(const CLASS<T>* wrapper) \
+ { \
+ return wrapper; \
+ } \
+}
+
+/**
+ * Make an instance of a listener wrapper. Every wrapper class must be a
+ * template accepting a listener object of arbitrary type. In particular, the
+ * type of a boost::bind() expression is deliberately undocumented. So we
+ * can't just write Wrapper<CorrectType>(boost::bind(...)). Instead we must
+ * write llwrap<Wrapper>(boost::bind(...)).
+ */
+template <template<typename> class WRAPPER, typename T>
+WRAPPER<T> llwrap(const T& listener)
+{
+ return WRAPPER<T>(listener);
+}
+
+/**
+ * This LLListenerWrapper template subclass is used to report entry/exit to an
+ * event listener, by changing this:
+ * @code
+ * someEventPump.listen("MyClass",
+ * boost::bind(&MyClass::method, ptr, _1));
+ * @endcode
+ * to this:
+ * @code
+ * someEventPump.listen("MyClass",
+ * llwrap<LLCoutListener>(
+ * boost::bind(&MyClass::method, ptr, _1)));
+ * @endcode
+ */
+template <class LISTENER>
+class LLCoutListener: public LLListenerWrapper<LISTENER>
+{
+ typedef LLListenerWrapper<LISTENER> super;
+
+public:
+ /// Wrap an arbitrary listener object
+ LLCoutListener(const LISTENER& listener):
+ super(listener)
+ {}
+
+ /// call
+ virtual bool operator()(const LLSD& event)
+ {
+ std::cout << "Entering listener " << *super::mName << " with " << event << std::endl;
+ bool handled = super::operator()(event);
+ std::cout << "Leaving listener " << *super::mName;
+ if (handled)
+ {
+ std::cout << " (handled)";
+ }
+ std::cout << std::endl;
+ return handled;
+ }
+};
+
+LLLISTENER_WRAPPER_SUBCLASS(LLCoutListener);
+
+/**
+ * This LLListenerWrapper template subclass is used to log entry/exit to an
+ * event listener, by changing this:
+ * @code
+ * someEventPump.listen("MyClass",
+ * boost::bind(&MyClass::method, ptr, _1));
+ * @endcode
+ * to this:
+ * @code
+ * someEventPump.listen("MyClass",
+ * llwrap<LLLogListener>(
+ * boost::bind(&MyClass::method, ptr, _1)));
+ * @endcode
+ */
+template <class LISTENER>
+class LLLogListener: public LLListenerWrapper<LISTENER>
+{
+ typedef LLListenerWrapper<LISTENER> super;
+
+public:
+ /// Wrap an arbitrary listener object
+ LLLogListener(const LISTENER& listener):
+ super(listener)
+ {}
+
+ /// call
+ virtual bool operator()(const LLSD& event)
+ {
+ LL_DEBUGS("LLLogListener") << "Entering listener " << *super::mName << " with " << event << LL_ENDL;
+ bool handled = super::operator()(event);
+ LL_DEBUGS("LLLogListener") << "Leaving listener " << *super::mName;
+ if (handled)
+ {
+ LL_CONT << " (handled)";
+ }
+ LL_CONT << LL_ENDL;
+ return handled;
+ }
+};
+
+LLLISTENER_WRAPPER_SUBCLASS(LLLogListener);
+
+#endif /* ! defined(LL_LLLISTENERWRAPPER_H) */
diff --git a/indra/llcommon/llliveappconfig.cpp b/indra/llcommon/llliveappconfig.cpp
index 76432770a3..3a3dfa9f28 100644
--- a/indra/llcommon/llliveappconfig.cpp
+++ b/indra/llcommon/llliveappconfig.cpp
@@ -2,30 +2,25 @@
* @file llliveappconfig.cpp
* @brief Configuration information for an LLApp that overrides indra.xml
*
- * $LicenseInfo:firstyear=2003&license=viewergpl$
- *
- * Copyright (c) 2003-2007, Linden Research, Inc.
- *
+ * $LicenseInfo:firstyear=2003&license=viewerlgpl$
* Second Life Viewer Source Code
- * The source code in this file ("Source Code") is provided by Linden Lab
- * to you under the terms of the GNU General Public License, version 2.0
- * ("GPL"), unless you have obtained a separate licensing agreement
- * ("Other License"), formally executed by you and Linden Lab. Terms of
- * the GPL can be found in doc/GPL-license.txt in this distribution, or
- * online at http://secondlife.com/developers/opensource/gplv2
+ * Copyright (C) 2010, Linden Research, Inc.
*
- * There are special exceptions to the terms and conditions of the GPL as
- * it is applied to this Source Code. View the full text of the exception
- * in the file doc/FLOSS-exception.txt in this software distribution, or
- * online at http://secondlife.com/developers/opensource/flossexception
+ * 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.
*
- * By copying, modifying or distributing this software, you acknowledge
- * that you have read and understood your obligations described above,
- * and agree to abide by those obligations.
+ * 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.
*
- * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
- * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
- * COMPLETENESS OR PERFORMANCE.
+ * 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$
*/
@@ -37,9 +32,12 @@
#include "llsd.h"
#include "llsdserialize.h"
-LLLiveAppConfig::LLLiveAppConfig(LLApp* app, const std::string& filename, F32 refresh_period)
-: LLLiveFile(filename, refresh_period),
- mApp(app)
+LLLiveAppConfig::LLLiveAppConfig(
+ const std::string& filename,
+ F32 refresh_period,
+ LLApp::OptionPriority priority) :
+ LLLiveFile(filename, refresh_period),
+ mPriority(priority)
{ }
@@ -47,23 +45,36 @@ LLLiveAppConfig::~LLLiveAppConfig()
{ }
// virtual
-void LLLiveAppConfig::loadFile()
+bool LLLiveAppConfig::loadFile()
{
llinfos << "LLLiveAppConfig::loadFile(): reading from "
<< filename() << llendl;
- llifstream file(filename().c_str());
+ llifstream file(filename());
LLSD config;
if (file.is_open())
{
LLSDSerialize::fromXML(config, file);
if(!config.isMap())
{
- llinfos << "LLDataserverConfig::loadFile(): not an map!"
+ llwarns << "Live app config not an map in " << filename()
<< " Ignoring the data." << llendl;
- return;
+ return false;
}
file.close();
}
- mApp->setOptionData(
- LLApp::PRIORITY_SPECIFIC_CONFIGURATION, config);
+ else
+ {
+ llinfos << "Live file " << filename() << " does not exit." << llendl;
+ }
+ // *NOTE: we do not handle the else case here because we would not
+ // have attempted to load the file unless LLLiveFile had
+ // determined there was a reason to load it. This only happens
+ // when either the file has been updated or it is either suddenly
+ // in existence or has passed out of existence. Therefore, we want
+ // to set the config to an empty config, and return that it
+ // changed.
+
+ LLApp* app = LLApp::instance();
+ if(app) app->setOptionData(mPriority, config);
+ return true;
}
diff --git a/indra/llcommon/llliveappconfig.h b/indra/llcommon/llliveappconfig.h
index dd6dbfb5ad..4fd7c26a07 100644
--- a/indra/llcommon/llliveappconfig.h
+++ b/indra/llcommon/llliveappconfig.h
@@ -2,55 +2,68 @@
* @file llliveappconfig.h
* @brief Configuration information for an LLApp that overrides indra.xml
*
- * $LicenseInfo:firstyear=2003&license=viewergpl$
- *
- * Copyright (c) 2003-2007, Linden Research, Inc.
- *
+ * $LicenseInfo:firstyear=2003&license=viewerlgpl$
* Second Life Viewer Source Code
- * The source code in this file ("Source Code") is provided by Linden Lab
- * to you under the terms of the GNU General Public License, version 2.0
- * ("GPL"), unless you have obtained a separate licensing agreement
- * ("Other License"), formally executed by you and Linden Lab. Terms of
- * the GPL can be found in doc/GPL-license.txt in this distribution, or
- * online at http://secondlife.com/developers/opensource/gplv2
+ * 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.
*
- * There are special exceptions to the terms and conditions of the GPL as
- * it is applied to this Source Code. View the full text of the exception
- * in the file doc/FLOSS-exception.txt in this software distribution, or
- * online at http://secondlife.com/developers/opensource/flossexception
+ * 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.
*
- * By copying, modifying or distributing this software, you acknowledge
- * that you have read and understood your obligations described above,
- * and agree to abide by those obligations.
+ * 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
*
- * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
- * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
- * COMPLETENESS OR PERFORMANCE.
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
* $/LicenseInfo$
*/
#ifndef LLLIVEAPPCONFIG_H
#define LLLIVEAPPCONFIG_H
+#include "llapp.h"
#include "lllivefile.h"
-class LLApp;
-class LLLiveAppConfig : public LLLiveFile
+/**
+ * @class LLLiveAppConfig
+ * @see LLLiveFile
+ *
+ * To use this, instantiate a LLLiveAppConfig object inside your main
+ * loop. The traditional name for it is live_config. Be sure to call
+ * <code>live_config.checkAndReload()</code> periodically.
+ */
+class LL_COMMON_API LLLiveAppConfig : public LLLiveFile
{
public:
- // To use this, instantiate a LLLiveAppConfig object inside your main loop.
- // The traditional name for it is live_config.
- // Be sure to call live_config.checkAndReload() periodically.
- LLLiveAppConfig(LLApp* app, const std::string& filename, F32 refresh_period);
- ~LLLiveAppConfig();
+ /**
+ * @brief Constructor
+ *
+ * @param filename. The name of the file for periodically checking
+ * configuration.
+ * @param refresh_period How often the internal timer should
+ * bother checking the filesystem.
+ * @param The application priority level of that configuration file.
+ */
+ LLLiveAppConfig(
+ const std::string& filename,
+ F32 refresh_period,
+ LLApp::OptionPriority priority);
+
+ ~LLLiveAppConfig(); ///< Destructor
protected:
- /*virtual*/ void loadFile();
+ /*virtual*/ bool loadFile();
private:
- LLApp* mApp;
+ LLApp::OptionPriority mPriority;
};
#endif
diff --git a/indra/llcommon/lllivefile.cpp b/indra/llcommon/lllivefile.cpp
index cb3ce0f8d2..c1987baf55 100644
--- a/indra/llcommon/lllivefile.cpp
+++ b/indra/llcommon/lllivefile.cpp
@@ -1,30 +1,25 @@
/**
* @file lllivefile.cpp
*
- * $LicenseInfo:firstyear=2006&license=viewergpl$
- *
- * Copyright (c) 2006-2007, Linden Research, Inc.
- *
+ * $LicenseInfo:firstyear=2006&license=viewerlgpl$
* Second Life Viewer Source Code
- * The source code in this file ("Source Code") is provided by Linden Lab
- * to you under the terms of the GNU General Public License, version 2.0
- * ("GPL"), unless you have obtained a separate licensing agreement
- * ("Other License"), formally executed by you and Linden Lab. Terms of
- * the GPL can be found in doc/GPL-license.txt in this distribution, or
- * online at http://secondlife.com/developers/opensource/gplv2
+ * 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.
*
- * There are special exceptions to the terms and conditions of the GPL as
- * it is applied to this Source Code. View the full text of the exception
- * in the file doc/FLOSS-exception.txt in this software distribution, or
- * online at http://secondlife.com/developers/opensource/flossexception
+ * 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.
*
- * By copying, modifying or distributing this software, you acknowledge
- * that you have read and understood your obligations described above,
- * and agree to abide by those obligations.
+ * 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
*
- * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
- * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
- * COMPLETENESS OR PERFORMANCE.
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
* $/LicenseInfo$
*/
@@ -32,16 +27,19 @@
#include "lllivefile.h"
#include "llframetimer.h"
-#include "lltimer.h"
+#include "lleventtimer.h"
+
+const F32 DEFAULT_CONFIG_FILE_REFRESH = 5.0f;
+
class LLLiveFile::Impl
{
public:
- Impl(const std::string &filename, const F32 refresh_period);
+ Impl(const std::string& filename, const F32 refresh_period);
~Impl();
bool check();
-
+ void changed();
bool mForceCheck;
F32 mRefreshPeriod;
@@ -49,16 +47,19 @@ public:
std::string mFilename;
time_t mLastModTime;
+ time_t mLastStatTime;
bool mLastExists;
LLEventTimer* mEventTimer;
};
-LLLiveFile::Impl::Impl(const std::string &filename, const F32 refresh_period)
- : mForceCheck(true),
+LLLiveFile::Impl::Impl(const std::string& filename, const F32 refresh_period)
+ :
+ mForceCheck(true),
mRefreshPeriod(refresh_period),
mFilename(filename),
mLastModTime(0),
+ mLastStatTime(0),
mLastExists(false),
mEventTimer(NULL)
{
@@ -69,7 +70,7 @@ LLLiveFile::Impl::~Impl()
delete mEventTimer;
}
-LLLiveFile::LLLiveFile(const std::string &filename, const F32 refresh_period)
+LLLiveFile::LLLiveFile(const std::string& filename, const F32 refresh_period)
: impl(* new Impl(filename, refresh_period))
{
}
@@ -93,7 +94,7 @@ bool LLLiveFile::Impl::check()
// Stat the file to see if it exists and when it was last modified.
llstat stat_data;
- int res = LLFile::stat(mFilename.c_str(), &stat_data);
+ int res = LLFile::stat(mFilename, &stat_data);
if (res)
{
@@ -120,17 +121,30 @@ bool LLLiveFile::Impl::check()
// We want to read the file. Update status info for the file.
mLastExists = true;
- mLastModTime = stat_data.st_mtime;
-
+ mLastStatTime = stat_data.st_mtime;
return true;
}
+void LLLiveFile::Impl::changed()
+{
+ // we wanted to read this file, and we were successful.
+ mLastModTime = mLastStatTime;
+}
+
bool LLLiveFile::checkAndReload()
{
bool changed = impl.check();
if (changed)
{
- loadFile();
+ if(loadFile())
+ {
+ impl.changed();
+ this->changed();
+ }
+ else
+ {
+ changed = false;
+ }
}
return changed;
}
@@ -166,3 +180,12 @@ void LLLiveFile::addToEventTimer()
impl.mEventTimer = new LiveFileEventTimer(*this, impl.mRefreshPeriod);
}
+void LLLiveFile::setRefreshPeriod(F32 seconds)
+{
+ if (seconds < 0.f)
+ {
+ seconds = -seconds;
+ }
+ impl.mRefreshPeriod = seconds;
+}
+
diff --git a/indra/llcommon/lllivefile.h b/indra/llcommon/lllivefile.h
index 689590e324..320aa4bc3e 100644
--- a/indra/llcommon/lllivefile.h
+++ b/indra/llcommon/lllivefile.h
@@ -2,55 +2,90 @@
* @file lllivefile.h
* @brief Automatically reloads a file whenever it changes or is removed.
*
- * $LicenseInfo:firstyear=2006&license=viewergpl$
- *
- * Copyright (c) 2006-2007, Linden Research, Inc.
- *
+ * $LicenseInfo:firstyear=2006&license=viewerlgpl$
* Second Life Viewer Source Code
- * The source code in this file ("Source Code") is provided by Linden Lab
- * to you under the terms of the GNU General Public License, version 2.0
- * ("GPL"), unless you have obtained a separate licensing agreement
- * ("Other License"), formally executed by you and Linden Lab. Terms of
- * the GPL can be found in doc/GPL-license.txt in this distribution, or
- * online at http://secondlife.com/developers/opensource/gplv2
+ * 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.
*
- * There are special exceptions to the terms and conditions of the GPL as
- * it is applied to this Source Code. View the full text of the exception
- * in the file doc/FLOSS-exception.txt in this software distribution, or
- * online at http://secondlife.com/developers/opensource/flossexception
+ * 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.
*
- * By copying, modifying or distributing this software, you acknowledge
- * that you have read and understood your obligations described above,
- * and agree to abide by those obligations.
+ * 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
*
- * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
- * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
- * COMPLETENESS OR PERFORMANCE.
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
* $/LicenseInfo$
*/
#ifndef LL_LLLIVEFILE_H
#define LL_LLLIVEFILE_H
+extern const F32 DEFAULT_CONFIG_FILE_REFRESH;
-class LLLiveFile
+
+class LL_COMMON_API LLLiveFile
{
public:
- LLLiveFile(const std::string &filename, const F32 refresh_period = 5.f);
+ LLLiveFile(const std::string& filename, const F32 refresh_period = 5.f);
virtual ~LLLiveFile();
+ /**
+ * @brief Check to see if this live file should reload.
+ *
+ * Call this before using anything that was read & cached
+ * from the file.
+ *
+ * This method calls the <code>loadFile()</code> method if
+ * any of:
+ * file has a new modify time since the last check
+ * file used to exist and now does not
+ * file used to not exist but now does
+ * @return Returns true if the file was reloaded.
+ */
bool checkAndReload();
- // Returns true if the file changed in any way
- // Call this before using anything that was read & cached from the file
+
std::string filename() const;
+ /**
+ * @brief Add this live file to an automated recheck.
+ *
+ * Normally, just calling checkAndReload() is enough. In some
+ * cases though, you may need to let the live file periodically
+ * check itself.
+ */
void addToEventTimer();
- // Normally, just calling checkAndReload() is enough. In some cases
- // though, you may need to let the live file periodically check itself.
+
+ void setRefreshPeriod(F32 seconds);
protected:
- virtual void loadFile() = 0; // Implement this to load your file if it changed
+ /**
+ * @breif Implement this to load your file if it changed.
+ *
+ * This method is called automatically by <code>checkAndReload()</code>,
+ * so though you must implement this in derived classes, you do
+ * not need to call it manually.
+ * @return Returns true if the file was successfully loaded.
+ */
+ virtual bool loadFile() = 0;
+
+ /**
+ * @brief Implement this method if you want to get a change callback.
+ *
+ * This virtual function will be called automatically at the end
+ * of <code>checkAndReload()</code> if a new configuration was
+ * loaded. This does not track differences between the current and
+ * newly loaded file, so any successful load event will trigger a
+ * <code>changed()</code> callback. Default is to do nothing.
+ */
+ virtual void changed() {}
private:
class Impl;
diff --git a/indra/llcommon/lllocalidhashmap.h b/indra/llcommon/lllocalidhashmap.h
index 12df73d3b0..8f4f91a560 100644
--- a/indra/llcommon/lllocalidhashmap.h
+++ b/indra/llcommon/lllocalidhashmap.h
@@ -2,30 +2,25 @@
* @file lllocalidhashmap.h
* @brief Map specialized for dealing with local ids
*
- * $LicenseInfo:firstyear=2003&license=viewergpl$
- *
- * Copyright (c) 2003-2007, Linden Research, Inc.
- *
+ * $LicenseInfo:firstyear=2003&license=viewerlgpl$
* Second Life Viewer Source Code
- * The source code in this file ("Source Code") is provided by Linden Lab
- * to you under the terms of the GNU General Public License, version 2.0
- * ("GPL"), unless you have obtained a separate licensing agreement
- * ("Other License"), formally executed by you and Linden Lab. Terms of
- * the GPL can be found in doc/GPL-license.txt in this distribution, or
- * online at http://secondlife.com/developers/opensource/gplv2
+ * 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.
*
- * There are special exceptions to the terms and conditions of the GPL as
- * it is applied to this Source Code. View the full text of the exception
- * in the file doc/FLOSS-exception.txt in this software distribution, or
- * online at http://secondlife.com/developers/opensource/flossexception
+ * 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.
*
- * By copying, modifying or distributing this software, you acknowledge
- * that you have read and understood your obligations described above,
- * and agree to abide by those obligations.
+ * 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
*
- * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
- * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
- * COMPLETENESS OR PERFORMANCE.
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
* $/LicenseInfo$
*/
diff --git a/indra/llcommon/lllog.cpp b/indra/llcommon/lllog.cpp
index 178f02e215..fc4058b5c9 100644
--- a/indra/llcommon/lllog.cpp
+++ b/indra/llcommon/lllog.cpp
@@ -4,30 +4,25 @@
* @date 2007-11-27
* @brief Class to log messages to syslog for streambase to process.
*
- * $LicenseInfo:firstyear=2007&license=viewergpl$
- *
- * Copyright (c) 2007, Linden Research, Inc.
- *
+ * $LicenseInfo:firstyear=2007&license=viewerlgpl$
* Second Life Viewer Source Code
- * The source code in this file ("Source Code") is provided by Linden Lab
- * to you under the terms of the GNU General Public License, version 2.0
- * ("GPL"), unless you have obtained a separate licensing agreement
- * ("Other License"), formally executed by you and Linden Lab. Terms of
- * the GPL can be found in doc/GPL-license.txt in this distribution, or
- * online at http://secondlife.com/developers/opensource/gplv2
+ * 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.
*
- * There are special exceptions to the terms and conditions of the GPL as
- * it is applied to this Source Code. View the full text of the exception
- * in the file doc/FLOSS-exception.txt in this software distribution, or
- * online at http://secondlife.com/developers/opensource/flossexception
+ * 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.
*
- * By copying, modifying or distributing this software, you acknowledge
- * that you have read and understood your obligations described above,
- * and agree to abide by those obligations.
+ * 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
*
- * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
- * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
- * COMPLETENESS OR PERFORMANCE.
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
* $/LicenseInfo$
*/
@@ -45,8 +40,8 @@ public:
LLLogImpl(LLApp* app) : mApp(app) {}
~LLLogImpl() {}
- void log(const std::string message, LLSD& info);
- bool useLegacyLogMessage(const std::string message);
+ void log(const std::string &message, LLSD& info);
+ bool useLegacyLogMessage(const std::string &message);
private:
LLApp* mApp;
@@ -54,7 +49,7 @@ private:
//@brief Function to log a message to syslog for streambase to collect.
-void LLLogImpl::log(const std::string message, LLSD& info)
+void LLLogImpl::log(const std::string &message, LLSD& info)
{
static S32 sequence = 0;
LLSD log_config = mApp->getOption("log-messages");
@@ -74,7 +69,7 @@ void LLLogImpl::log(const std::string message, LLSD& info)
}
//@brief Function to check if specified legacy log message should be sent.
-bool LLLogImpl::useLegacyLogMessage(const std::string message)
+bool LLLogImpl::useLegacyLogMessage(const std::string &message)
{
LLSD log_config = mApp->getOption("log-messages");
if (log_config.has(message))
@@ -100,12 +95,12 @@ LLLog::~LLLog()
mImpl = NULL;
}
-void LLLog::log(const std::string message, LLSD& info)
+void LLLog::log(const std::string &message, LLSD& info)
{
if (mImpl) mImpl->log(message, info);
}
-bool LLLog::useLegacyLogMessage(const std::string message)
+bool LLLog::useLegacyLogMessage(const std::string &message)
{
if (mImpl)
{
diff --git a/indra/llcommon/lllog.h b/indra/llcommon/lllog.h
index ca71ca442c..7964412e83 100644
--- a/indra/llcommon/lllog.h
+++ b/indra/llcommon/lllog.h
@@ -4,30 +4,25 @@
* @date 2007-11-27
* @brief Class to log messages to syslog for streambase to process.
*
- * $LicenseInfo:firstyear=2007&license=viewergpl$
- *
- * Copyright (c) 2007, Linden Research, Inc.
- *
+ * $LicenseInfo:firstyear=2007&license=viewerlgpl$
* Second Life Viewer Source Code
- * The source code in this file ("Source Code") is provided by Linden Lab
- * to you under the terms of the GNU General Public License, version 2.0
- * ("GPL"), unless you have obtained a separate licensing agreement
- * ("Other License"), formally executed by you and Linden Lab. Terms of
- * the GPL can be found in doc/GPL-license.txt in this distribution, or
- * online at http://secondlife.com/developers/opensource/gplv2
+ * 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.
*
- * There are special exceptions to the terms and conditions of the GPL as
- * it is applied to this Source Code. View the full text of the exception
- * in the file doc/FLOSS-exception.txt in this software distribution, or
- * online at http://secondlife.com/developers/opensource/flossexception
+ * 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.
*
- * By copying, modifying or distributing this software, you acknowledge
- * that you have read and understood your obligations described above,
- * and agree to abide by those obligations.
+ * 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
*
- * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
- * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
- * COMPLETENESS OR PERFORMANCE.
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
* $/LicenseInfo$
*/
@@ -40,14 +35,14 @@ class LLLogImpl;
class LLApp;
class LLSD;
-class LLLog
+class LL_COMMON_API LLLog
{
public:
LLLog(LLApp* app);
virtual ~LLLog();
- virtual void log(const std::string message, LLSD& info);
- virtual bool useLegacyLogMessage(const std::string message);
+ virtual void log(const std::string &message, LLSD& info);
+ virtual bool useLegacyLogMessage(const std::string &message);
private:
LLLogImpl* mImpl;
diff --git a/indra/llcommon/lllslconstants.h b/indra/llcommon/lllslconstants.h
index e4c83582ce..539c807020 100644
--- a/indra/llcommon/lllslconstants.h
+++ b/indra/llcommon/lllslconstants.h
@@ -3,30 +3,25 @@
* @author James Cook
* @brief Constants used in lsl.
*
- * $LicenseInfo:firstyear=2006&license=viewergpl$
- *
- * Copyright (c) 2006-2007, Linden Research, Inc.
- *
+ * $LicenseInfo:firstyear=2006&license=viewerlgpl$
* Second Life Viewer Source Code
- * The source code in this file ("Source Code") is provided by Linden Lab
- * to you under the terms of the GNU General Public License, version 2.0
- * ("GPL"), unless you have obtained a separate licensing agreement
- * ("Other License"), formally executed by you and Linden Lab. Terms of
- * the GPL can be found in doc/GPL-license.txt in this distribution, or
- * online at http://secondlife.com/developers/opensource/gplv2
+ * Copyright (C) 2010, Linden Research, Inc.
*
- * There are special exceptions to the terms and conditions of the GPL as
- * it is applied to this Source Code. View the full text of the exception
- * in the file doc/FLOSS-exception.txt in this software distribution, or
- * online at http://secondlife.com/developers/opensource/flossexception
+ * 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.
*
- * By copying, modifying or distributing this software, you acknowledge
- * that you have read and understood your obligations described above,
- * and agree to abide by those obligations.
+ * 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.
*
- * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
- * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
- * COMPLETENESS OR PERFORMANCE.
+ * 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$
*/
@@ -47,6 +42,7 @@ const U32 AGENT_TYPING = 0x0200;
const U32 AGENT_CROUCHING = 0x0400;
const U32 AGENT_BUSY = 0x0800;
const U32 AGENT_ALWAYS_RUN = 0x1000;
+const U32 AGENT_AUTOPILOT = 0x2000;
const S32 LSL_REMOTE_DATA_CHANNEL = 1;
const S32 LSL_REMOTE_DATA_REQUEST = 2;
@@ -126,6 +122,9 @@ const S32 LSL_PRIM_SCULPT_TYPE_SPHERE = 1;
const S32 LSL_PRIM_SCULPT_TYPE_TORUS = 2;
const S32 LSL_PRIM_SCULPT_TYPE_PLANE = 3;
const S32 LSL_PRIM_SCULPT_TYPE_CYLINDER = 4;
+const S32 LSL_PRIM_SCULPT_TYPE_MASK = 7;
+const S32 LSL_PRIM_SCULPT_FLAG_INVERT = 64;
+const S32 LSL_PRIM_SCULPT_FLAG_MIRROR = 128;
const S32 LSL_ALL_SIDES = -1;
const S32 LSL_LINK_ROOT = 1;
@@ -181,4 +180,34 @@ const S32 OBJECT_OWNER = 6;
const S32 OBJECT_GROUP = 7;
const S32 OBJECT_CREATOR = 8;
+// llTextBox() magic token string - yes this is a hack. sue me.
+const std::string TEXTBOX_MAGIC_TOKEN = "!!llTextBox!!";
+
+// changed() event flags
+const U32 CHANGED_NONE = 0x0;
+const U32 CHANGED_INVENTORY = 0x1;
+const U32 CHANGED_COLOR = 0x2;
+const U32 CHANGED_SHAPE = 0x4;
+const U32 CHANGED_SCALE = 0x8;
+const U32 CHANGED_TEXTURE = 0x10;
+const U32 CHANGED_LINK = 0x20;
+const U32 CHANGED_ALLOWED_DROP = 0x40;
+const U32 CHANGED_OWNER = 0x80;
+const U32 CHANGED_REGION = 0x100;
+const U32 CHANGED_TELEPORT = 0x200;
+const U32 CHANGED_REGION_START = 0x400;
+const U32 CHANGED_MEDIA = 0x800;
+
+// Possible error results
+const U32 LSL_STATUS_OK = 0;
+const U32 LSL_STATUS_MALFORMED_PARAMS = 1000;
+const U32 LSL_STATUS_TYPE_MISMATCH = 1001;
+const U32 LSL_STATUS_BOUNDS_ERROR = 1002;
+const U32 LSL_STATUS_NOT_FOUND = 1003;
+const U32 LSL_STATUS_NOT_SUPPORTED = 1004;
+const U32 LSL_STATUS_INTERNAL_ERROR = 1999;
+
+// Start per-function errors below, starting at 2000:
+const U32 LSL_STATUS_WHITELIST_FAILED = 2001;
+
#endif
diff --git a/indra/llcommon/llmap.h b/indra/llcommon/llmap.h
index 9ad93b25b2..6294a15d3b 100644
--- a/indra/llcommon/llmap.h
+++ b/indra/llcommon/llmap.h
@@ -2,30 +2,25 @@
* @file llmap.h
* @brief LLMap class header file
*
- * $LicenseInfo:firstyear=2001&license=viewergpl$
- *
- * Copyright (c) 2001-2007, Linden Research, Inc.
- *
+ * $LicenseInfo:firstyear=2001&license=viewerlgpl$
* Second Life Viewer Source Code
- * The source code in this file ("Source Code") is provided by Linden Lab
- * to you under the terms of the GNU General Public License, version 2.0
- * ("GPL"), unless you have obtained a separate licensing agreement
- * ("Other License"), formally executed by you and Linden Lab. Terms of
- * the GPL can be found in doc/GPL-license.txt in this distribution, or
- * online at http://secondlife.com/developers/opensource/gplv2
+ * 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.
*
- * There are special exceptions to the terms and conditions of the GPL as
- * it is applied to this Source Code. View the full text of the exception
- * in the file doc/FLOSS-exception.txt in this software distribution, or
- * online at http://secondlife.com/developers/opensource/flossexception
+ * 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.
*
- * By copying, modifying or distributing this software, you acknowledge
- * that you have read and understood your obligations described above,
- * and agree to abide by those obligations.
+ * 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
*
- * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
- * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
- * COMPLETENESS OR PERFORMANCE.
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
* $/LicenseInfo$
*/
diff --git a/indra/llcommon/llmd5.cpp b/indra/llcommon/llmd5.cpp
new file mode 100644
index 0000000000..75fde8e5ba
--- /dev/null
+++ b/indra/llcommon/llmd5.cpp
@@ -0,0 +1,538 @@
+/**
+ * @file llmd5.cpp
+ *
+ * $LicenseInfo:firstyear=2001&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$
+ */
+
+// llMD5.CC - source code for the C++/object oriented translation and
+// modification of MD5.
+//
+// Adapted to Linden Lab by Frank Filipanits, 6/25/2002
+// Fixed potential memory leak, James Cook, 6/27/2002
+
+// Translation and modification (c) 1995 by Mordechai T. Abzug
+
+// This translation/ modification is provided "as is," without express or
+// implied warranty of any kind.
+
+// The translator/ modifier does not claim (1) that MD5 will do what you think
+// it does; (2) that this translation/ modification is accurate; or (3) that
+// this software is "merchantible." (Language for this disclaimer partially
+// copied from the disclaimer below).
+
+/* based on:
+
+ MD5C.C - RSA Data Security, Inc., MD5 message-digest algorithm
+ MDDRIVER.C - test driver for MD2, MD4 and MD5
+
+
+ Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All
+rights reserved.
+
+License to copy and use this software is granted provided that it
+is identified as the "RSA Data Security, Inc. MD5 Message-Digest
+Algorithm" in all material mentioning or referencing this software
+or this function.
+
+License is also granted to make and use derivative works provided
+that such works are identified as "derived from the RSA Data
+Security, Inc. MD5 Message-Digest Algorithm" in all material
+mentioning or referencing the derived work.
+
+RSA Data Security, Inc. makes no representations concerning either
+the merchantability of this software or the suitability of this
+software for any particular purpose. It is provided "as is"
+without express or implied warranty of any kind.
+
+These notices must be retained in any copies of any part of this
+documentation and/or software.
+
+ */
+
+
+
+
+
+#include "linden_common.h"
+
+#include "llmd5.h"
+
+#include <cassert>
+#include <iostream> // cerr
+
+// how many bytes to grab at a time when checking files
+const int LLMD5::BLOCK_LEN = 4096;
+
+
+// LLMD5 simple initialization method
+
+LLMD5::LLMD5()
+{
+ init();
+}
+
+
+
+
+// MD5 block update operation. Continues an MD5 message-digest
+// operation, processing another message block, and updating the
+// context.
+
+void LLMD5::update (const uint1 *input, const uint4 input_length) {
+
+ uint4 input_index, buffer_index;
+ uint4 buffer_space; // how much space is left in buffer
+
+ if (finalized){ // so we can't update!
+ std::cerr << "LLMD5::update: Can't update a finalized digest!" << std::endl;
+ return;
+ }
+
+ // Compute number of bytes mod 64
+ buffer_index = (unsigned int)((count[0] >> 3) & 0x3F);
+
+ // Update number of bits
+ if ( (count[0] += ((uint4) input_length << 3))<((uint4) input_length << 3) )
+ count[1]++;
+
+ count[1] += ((uint4)input_length >> 29);
+
+
+ buffer_space = 64 - buffer_index; // how much space is left in buffer
+
+ // Transform as many times as possible.
+ if (input_length >= buffer_space) { // ie. we have enough to fill the buffer
+ // fill the rest of the buffer and transform
+ memcpy( /* Flawfinder: ignore */
+ buffer + buffer_index,
+ input,
+ buffer_space);
+ transform (buffer);
+
+ // now, transform each 64-byte piece of the input, bypassing the buffer
+ if (input == NULL || input_length == 0){
+ std::cerr << "LLMD5::update: Invalid input!" << std::endl;
+ return;
+ }
+
+ for (input_index = buffer_space; input_index + 63 < input_length;
+ input_index += 64)
+ transform (input+input_index);
+
+ buffer_index = 0; // so we can buffer remaining
+ }
+ else
+ input_index=0; // so we can buffer the whole input
+
+
+ // and here we do the buffering:
+ memcpy(buffer+buffer_index, input+input_index, input_length-input_index); /* Flawfinder: ignore */
+}
+
+
+
+// MD5 update for files.
+// Like above, except that it works on files (and uses above as a primitive.)
+
+void LLMD5::update(FILE* file){
+
+ unsigned char buffer[BLOCK_LEN]; /* Flawfinder: ignore */
+ int len;
+
+ while ( (len=(int)fread(buffer, 1, BLOCK_LEN, file)) )
+ update(buffer, len);
+
+ fclose (file);
+
+}
+
+// MD5 update for istreams.
+// Like update for files; see above.
+
+void LLMD5::update(std::istream& stream){
+
+ unsigned char buffer[BLOCK_LEN]; /* Flawfinder: ignore */
+ int len;
+
+ while (stream.good()){
+ stream.read( (char*)buffer, BLOCK_LEN); /* Flawfinder: ignore */ // note that return value of read is unusable.
+ len=stream.gcount();
+ update(buffer, len);
+ }
+
+}
+
+void LLMD5::update(const std::string& s)
+{
+ update((unsigned char *)s.c_str(),s.length());
+}
+
+// MD5 finalization. Ends an MD5 message-digest operation, writing the
+// the message digest and zeroizing the context.
+
+
+void LLMD5::finalize (){
+
+ unsigned char bits[8]; /* Flawfinder: ignore */
+ unsigned int index, padLen;
+ static uint1 PADDING[64]={
+ 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+ };
+
+ if (finalized){
+ std::cerr << "LLMD5::finalize: Already finalized this digest!" << std::endl;
+ return;
+ }
+
+ // Save number of bits
+ encode (bits, count, 8);
+
+ // Pad out to 56 mod 64.
+ index = (uint4) ((count[0] >> 3) & 0x3f);
+ padLen = (index < 56) ? (56 - index) : (120 - index);
+ update (PADDING, padLen);
+
+ // Append length (before padding)
+ update (bits, 8);
+
+ // Store state in digest
+ encode (digest, state, 16);
+
+ // Zeroize sensitive information
+ memset (buffer, 0, sizeof(*buffer));
+
+ finalized=1;
+
+}
+
+
+
+
+LLMD5::LLMD5(FILE *file){
+
+ init(); // must be called be all constructors
+ update(file);
+ finalize ();
+}
+
+
+
+
+LLMD5::LLMD5(std::istream& stream){
+
+ init(); // must called by all constructors
+ update (stream);
+ finalize();
+}
+
+// Digest a string of the format ("%s:%i" % (s, number))
+LLMD5::LLMD5(const unsigned char *string, const unsigned int number)
+{
+ const char *colon = ":";
+ char tbuf[16]; /* Flawfinder: ignore */
+ init();
+ update(string, (U32)strlen((const char *) string)); /* Flawfinder: ignore */
+ update((const unsigned char *) colon, (U32)strlen(colon)); /* Flawfinder: ignore */
+ snprintf(tbuf, sizeof(tbuf), "%i", number); /* Flawfinder: ignore */
+ update((const unsigned char *) tbuf, (U32)strlen(tbuf)); /* Flawfinder: ignore */
+ finalize();
+}
+
+// Digest a string
+LLMD5::LLMD5(const unsigned char *s)
+{
+ init();
+ update(s, (U32)strlen((const char *) s)); /* Flawfinder: ignore */
+ finalize();
+}
+
+void LLMD5::raw_digest(unsigned char *s) const
+{
+ if (!finalized)
+ {
+ std::cerr << "LLMD5::raw_digest: Can't get digest if you haven't "<<
+ "finalized the digest!" << std::endl;
+ s[0] = '\0';
+ return;
+ }
+
+ memcpy(s, digest, 16); /* Flawfinder: ignore */
+ return;
+}
+
+
+
+void LLMD5::hex_digest(char *s) const
+{
+ int i;
+
+ if (!finalized)
+ {
+ std::cerr << "LLMD5::hex_digest: Can't get digest if you haven't "<<
+ "finalized the digest!" <<std::endl;
+ s[0] = '\0';
+ return;
+ }
+
+ for (i=0; i<16; i++)
+ {
+ sprintf(s+i*2, "%02x", digest[i]); /* Flawfinder: ignore */
+ }
+
+ s[32]='\0';
+
+ return;
+}
+
+
+
+
+
+
+std::ostream& operator<<(std::ostream &stream, LLMD5 context)
+{
+ char s[33]; /* Flawfinder: ignore */
+ context.hex_digest(s);
+ stream << s;
+ return stream;
+}
+
+bool operator==(const LLMD5& a, const LLMD5& b)
+{
+ unsigned char a_guts[16];
+ unsigned char b_guts[16];
+ a.raw_digest(a_guts);
+ b.raw_digest(b_guts);
+ if (memcmp(a_guts,b_guts,16)==0)
+ return true;
+ else
+ return false;
+}
+
+bool operator!=(const LLMD5& a, const LLMD5& b)
+{
+ return !(a==b);
+}
+
+// PRIVATE METHODS:
+
+void LLMD5::init(){
+ finalized=0; // we just started!
+
+ // Nothing counted, so count=0
+ count[0] = 0;
+ count[1] = 0;
+
+ // Load magic initialization constants.
+ state[0] = 0x67452301;
+ state[1] = 0xefcdab89;
+ state[2] = 0x98badcfe;
+ state[3] = 0x10325476;
+}
+
+
+
+// Constants for MD5Transform routine.
+// Although we could use C++ style constants, defines are actually better,
+// since they let us easily evade scope clashes.
+
+#define S11 7
+#define S12 12
+#define S13 17
+#define S14 22
+#define S21 5
+#define S22 9
+#define S23 14
+#define S24 20
+#define S31 4
+#define S32 11
+#define S33 16
+#define S34 23
+#define S41 6
+#define S42 10
+#define S43 15
+#define S44 21
+
+// #defines are faster then inline, etc because the compiler is not required to inline.
+// Timing tests prove that this works ~40% faster on win with msvc++2k3 over using static inline.
+
+/* F, G, H and I are basic MD5 functions.
+ */
+#define F(x, y, z) (((x) & (y)) | ((~x) & (z)))
+#define G(x, y, z) (((x) & (z)) | ((y) & (~z)))
+#define H(x, y, z) ((x) ^ (y) ^ (z))
+#define I(x, y, z) ((y) ^ ((x) | (~z)))
+
+/* ROTATE_LEFT rotates x left n bits.
+ */
+#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32-(n))))
+
+/* FF, GG, HH, and II transformations for rounds 1, 2, 3, and 4.
+Rotation is separate from addition to prevent recomputation.
+ */
+#define FF(a, b, c, d, x, s, ac) { \
+ (a) += F ((b), (c), (d)) + (x) + (U32)(ac); \
+ (a) = ROTATE_LEFT ((a), (s)); \
+ (a) += (b); \
+ }
+#define GG(a, b, c, d, x, s, ac) { \
+ (a) += G ((b), (c), (d)) + (x) + (U32)(ac); \
+ (a) = ROTATE_LEFT ((a), (s)); \
+ (a) += (b); \
+ }
+#define HH(a, b, c, d, x, s, ac) { \
+ (a) += H ((b), (c), (d)) + (x) + (U32)(ac); \
+ (a) = ROTATE_LEFT ((a), (s)); \
+ (a) += (b); \
+ }
+#define II(a, b, c, d, x, s, ac) { \
+ (a) += I ((b), (c), (d)) + (x) + (U32)(ac); \
+ (a) = ROTATE_LEFT ((a), (s)); \
+ (a) += (b); \
+ }
+
+
+
+// LLMD5 basic transformation. Transforms state based on block.
+void LLMD5::transform (const U8 block[64]){
+
+ uint4 a = state[0], b = state[1], c = state[2], d = state[3], x[16];
+
+ decode (x, block, 64);
+
+ assert(!finalized); // not just a user error, since the method is private
+
+ /* Round 1 */
+ FF (a, b, c, d, x[ 0], S11, 0xd76aa478); /* 1 */
+ FF (d, a, b, c, x[ 1], S12, 0xe8c7b756); /* 2 */
+ FF (c, d, a, b, x[ 2], S13, 0x242070db); /* 3 */
+ FF (b, c, d, a, x[ 3], S14, 0xc1bdceee); /* 4 */
+ FF (a, b, c, d, x[ 4], S11, 0xf57c0faf); /* 5 */
+ FF (d, a, b, c, x[ 5], S12, 0x4787c62a); /* 6 */
+ FF (c, d, a, b, x[ 6], S13, 0xa8304613); /* 7 */
+ FF (b, c, d, a, x[ 7], S14, 0xfd469501); /* 8 */
+ FF (a, b, c, d, x[ 8], S11, 0x698098d8); /* 9 */
+ FF (d, a, b, c, x[ 9], S12, 0x8b44f7af); /* 10 */
+ FF (c, d, a, b, x[10], S13, 0xffff5bb1); /* 11 */
+ FF (b, c, d, a, x[11], S14, 0x895cd7be); /* 12 */
+ FF (a, b, c, d, x[12], S11, 0x6b901122); /* 13 */
+ FF (d, a, b, c, x[13], S12, 0xfd987193); /* 14 */
+ FF (c, d, a, b, x[14], S13, 0xa679438e); /* 15 */
+ FF (b, c, d, a, x[15], S14, 0x49b40821); /* 16 */
+
+ /* Round 2 */
+ GG (a, b, c, d, x[ 1], S21, 0xf61e2562); /* 17 */
+ GG (d, a, b, c, x[ 6], S22, 0xc040b340); /* 18 */
+ GG (c, d, a, b, x[11], S23, 0x265e5a51); /* 19 */
+ GG (b, c, d, a, x[ 0], S24, 0xe9b6c7aa); /* 20 */
+ GG (a, b, c, d, x[ 5], S21, 0xd62f105d); /* 21 */
+ GG (d, a, b, c, x[10], S22, 0x2441453); /* 22 */
+ GG (c, d, a, b, x[15], S23, 0xd8a1e681); /* 23 */
+ GG (b, c, d, a, x[ 4], S24, 0xe7d3fbc8); /* 24 */
+ GG (a, b, c, d, x[ 9], S21, 0x21e1cde6); /* 25 */
+ GG (d, a, b, c, x[14], S22, 0xc33707d6); /* 26 */
+ GG (c, d, a, b, x[ 3], S23, 0xf4d50d87); /* 27 */
+ GG (b, c, d, a, x[ 8], S24, 0x455a14ed); /* 28 */
+ GG (a, b, c, d, x[13], S21, 0xa9e3e905); /* 29 */
+ GG (d, a, b, c, x[ 2], S22, 0xfcefa3f8); /* 30 */
+ GG (c, d, a, b, x[ 7], S23, 0x676f02d9); /* 31 */
+ GG (b, c, d, a, x[12], S24, 0x8d2a4c8a); /* 32 */
+
+ /* Round 3 */
+ HH (a, b, c, d, x[ 5], S31, 0xfffa3942); /* 33 */
+ HH (d, a, b, c, x[ 8], S32, 0x8771f681); /* 34 */
+ HH (c, d, a, b, x[11], S33, 0x6d9d6122); /* 35 */
+ HH (b, c, d, a, x[14], S34, 0xfde5380c); /* 36 */
+ HH (a, b, c, d, x[ 1], S31, 0xa4beea44); /* 37 */
+ HH (d, a, b, c, x[ 4], S32, 0x4bdecfa9); /* 38 */
+ HH (c, d, a, b, x[ 7], S33, 0xf6bb4b60); /* 39 */
+ HH (b, c, d, a, x[10], S34, 0xbebfbc70); /* 40 */
+ HH (a, b, c, d, x[13], S31, 0x289b7ec6); /* 41 */
+ HH (d, a, b, c, x[ 0], S32, 0xeaa127fa); /* 42 */
+ HH (c, d, a, b, x[ 3], S33, 0xd4ef3085); /* 43 */
+ HH (b, c, d, a, x[ 6], S34, 0x4881d05); /* 44 */
+ HH (a, b, c, d, x[ 9], S31, 0xd9d4d039); /* 45 */
+ HH (d, a, b, c, x[12], S32, 0xe6db99e5); /* 46 */
+ HH (c, d, a, b, x[15], S33, 0x1fa27cf8); /* 47 */
+ HH (b, c, d, a, x[ 2], S34, 0xc4ac5665); /* 48 */
+
+ /* Round 4 */
+ II (a, b, c, d, x[ 0], S41, 0xf4292244); /* 49 */
+ II (d, a, b, c, x[ 7], S42, 0x432aff97); /* 50 */
+ II (c, d, a, b, x[14], S43, 0xab9423a7); /* 51 */
+ II (b, c, d, a, x[ 5], S44, 0xfc93a039); /* 52 */
+ II (a, b, c, d, x[12], S41, 0x655b59c3); /* 53 */
+ II (d, a, b, c, x[ 3], S42, 0x8f0ccc92); /* 54 */
+ II (c, d, a, b, x[10], S43, 0xffeff47d); /* 55 */
+ II (b, c, d, a, x[ 1], S44, 0x85845dd1); /* 56 */
+ II (a, b, c, d, x[ 8], S41, 0x6fa87e4f); /* 57 */
+ II (d, a, b, c, x[15], S42, 0xfe2ce6e0); /* 58 */
+ II (c, d, a, b, x[ 6], S43, 0xa3014314); /* 59 */
+ II (b, c, d, a, x[13], S44, 0x4e0811a1); /* 60 */
+ II (a, b, c, d, x[ 4], S41, 0xf7537e82); /* 61 */
+ II (d, a, b, c, x[11], S42, 0xbd3af235); /* 62 */
+ II (c, d, a, b, x[ 2], S43, 0x2ad7d2bb); /* 63 */
+ II (b, c, d, a, x[ 9], S44, 0xeb86d391); /* 64 */
+
+ state[0] += a;
+ state[1] += b;
+ state[2] += c;
+ state[3] += d;
+
+ // Zeroize sensitive information.
+ memset ( (uint1 *) x, 0, sizeof(x));
+
+}
+
+
+
+// Encodes input (UINT4) into output (unsigned char). Assumes len is
+// a multiple of 4.
+void LLMD5::encode (uint1 *output, const uint4 *input, const uint4 len) {
+
+ unsigned int i, j;
+
+ for (i = 0, j = 0; j < len; i++, j += 4) {
+ output[j] = (uint1) (input[i] & 0xff);
+ output[j+1] = (uint1) ((input[i] >> 8) & 0xff);
+ output[j+2] = (uint1) ((input[i] >> 16) & 0xff);
+ output[j+3] = (uint1) ((input[i] >> 24) & 0xff);
+ }
+}
+
+
+
+
+// Decodes input (unsigned char) into output (UINT4). Assumes len is
+// a multiple of 4.
+void LLMD5::decode (uint4 *output, const uint1 *input, const uint4 len){
+
+ unsigned int i, j;
+
+ for (i = 0, j = 0; j < len; i++, j += 4)
+ output[i] = ((uint4)input[j]) | (((uint4)input[j+1]) << 8) |
+ (((uint4)input[j+2]) << 16) | (((uint4)input[j+3]) << 24);
+}
+
+
diff --git a/indra/llcommon/llmd5.h b/indra/llcommon/llmd5.h
new file mode 100644
index 0000000000..c8acbbe591
--- /dev/null
+++ b/indra/llcommon/llmd5.h
@@ -0,0 +1,131 @@
+/**
+ * @file llmd5.h
+ *
+ * $LicenseInfo:firstyear=2001&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$
+ */
+
+#ifndef LL_LLMD5_H
+#define LL_LLMD5_H
+
+// LLMD5.CC - source code for the C++/object oriented translation and
+// modification of MD5.
+
+// Translation and modification (c) 1995 by Mordechai T. Abzug
+
+// This translation/ modification is provided "as is," without express or
+// implied warranty of any kind.
+
+// The translator/ modifier does not claim (1) that MD5 will do what you think
+// it does; (2) that this translation/ modification is accurate; or (3) that
+// this software is "merchantible." (Language for this disclaimer partially
+// copied from the disclaimer below).
+
+/* based on:
+
+ MD5.H - header file for MD5C.C
+ MDDRIVER.C - test driver for MD2, MD4 and MD5
+
+ Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All
+rights reserved.
+
+License to copy and use this software is granted provided that it
+is identified as the "RSA Data Security, Inc. MD5 Message-Digest
+Algorithm" in all material mentioning or referencing this software
+or this function.
+
+License is also granted to make and use derivative works provided
+that such works are identified as "derived from the RSA Data
+Security, Inc. MD5 Message-Digest Algorithm" in all material
+mentioning or referencing the derived work.
+
+RSA Data Security, Inc. makes no representations concerning either
+the merchantability of this software or the suitability of this
+software for any particular purpose. It is provided "as is"
+without express or implied warranty of any kind.
+
+These notices must be retained in any copies of any part of this
+documentation and/or software.
+
+*/
+
+// use for the raw digest output
+const int MD5RAW_BYTES = 16;
+
+// use for outputting hex digests
+const int MD5HEX_STR_SIZE = 33; // char hex[MD5HEX_STR_SIZE]; with null
+const int MD5HEX_STR_BYTES = 32; // message system fixed size
+
+class LL_COMMON_API LLMD5 {
+// first, some types:
+ typedef unsigned int uint4; // assumes integer is 4 words long
+ typedef unsigned short int uint2; // assumes short integer is 2 words long
+ typedef unsigned char uint1; // assumes char is 1 word long
+
+// how many bytes to grab at a time when checking files
+ static const int BLOCK_LEN;
+
+public:
+// methods for controlled operation:
+ LLMD5 (); // simple initializer
+ void update (const uint1 *input, const uint4 input_length);
+ void update (std::istream& stream);
+ void update (FILE *file);
+ void update (const std::string& str);
+ void finalize ();
+
+// constructors for special circumstances. All these constructors finalize
+// the MD5 context.
+ LLMD5 (const unsigned char *string); // digest string, finalize
+ LLMD5 (std::istream& stream); // digest stream, finalize
+ LLMD5 (FILE *file); // digest file, close, finalize
+ LLMD5 (const unsigned char *string, const unsigned int number);
+
+// methods to acquire finalized result
+ void raw_digest(unsigned char *array) const; // provide 16-byte array for binary data
+ void hex_digest(char *string) const; // provide 33-byte array for ascii-hex string
+
+ friend std::ostream& operator<< (std::ostream&, LLMD5 context);
+
+private:
+
+
+// next, the private data:
+ uint4 state[4];
+ uint4 count[2]; // number of *bits*, mod 2^64
+ uint1 buffer[64]; // input buffer
+ uint1 digest[16];
+ uint1 finalized;
+
+// last, the private methods, mostly static:
+ void init (); // called by all constructors
+ void transform (const uint1 *buffer); // does the real update work. Note
+ // that length is implied to be 64.
+
+ static void encode (uint1 *dest, const uint4 *src, const uint4 length);
+ static void decode (uint4 *dest, const uint1 *src, const uint4 length);
+
+};
+
+LL_COMMON_API bool operator==(const LLMD5& a, const LLMD5& b);
+LL_COMMON_API bool operator!=(const LLMD5& a, const LLMD5& b);
+
+#endif // LL_LLMD5_H
diff --git a/indra/llcommon/llmemory.cpp b/indra/llcommon/llmemory.cpp
index e52a137254..a502d1a7eb 100644
--- a/indra/llcommon/llmemory.cpp
+++ b/indra/llcommon/llmemory.cpp
@@ -2,30 +2,25 @@
* @file llmemory.cpp
* @brief Very special memory allocation/deallocation stuff here
*
- * $LicenseInfo:firstyear=2002&license=viewergpl$
- *
- * Copyright (c) 2002-2007, Linden Research, Inc.
- *
+ * $LicenseInfo:firstyear=2002&license=viewerlgpl$
* Second Life Viewer Source Code
- * The source code in this file ("Source Code") is provided by Linden Lab
- * to you under the terms of the GNU General Public License, version 2.0
- * ("GPL"), unless you have obtained a separate licensing agreement
- * ("Other License"), formally executed by you and Linden Lab. Terms of
- * the GPL can be found in doc/GPL-license.txt in this distribution, or
- * online at http://secondlife.com/developers/opensource/gplv2
+ * Copyright (C) 2010, Linden Research, Inc.
*
- * There are special exceptions to the terms and conditions of the GPL as
- * it is applied to this Source Code. View the full text of the exception
- * in the file doc/FLOSS-exception.txt in this software distribution, or
- * online at http://secondlife.com/developers/opensource/flossexception
+ * 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.
*
- * By copying, modifying or distributing this software, you acknowledge
- * that you have read and understood your obligations described above,
- * and agree to abide by those obligations.
+ * 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.
*
- * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
- * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
- * COMPLETENESS OR PERFORMANCE.
+ * 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$
*/
@@ -36,18 +31,13 @@
# include <psapi.h>
#elif defined(LL_DARWIN)
# include <sys/types.h>
-# include <sys/sysctl.h>
# include <mach/task.h>
-# include <mach/vm_map.h>
# include <mach/mach_init.h>
-# include <mach/vm_region.h>
-# include <mach/mach_port.h>
-#elif defined(LL_LINUX)
+#elif LL_LINUX || LL_SOLARIS
# include <unistd.h>
#endif
#include "llmemory.h"
-#include "llmemtype.h"
//----------------------------------------------------------------------------
@@ -77,162 +67,6 @@ void LLMemory::freeReserve()
reserveMem = NULL;
}
-
-//----------------------------------------------------------------------------
-
-//static
-#if MEM_TRACK_TYPE
-S32 LLMemType::sCurDepth = 0;
-S32 LLMemType::sCurType = LLMemType::MTYPE_INIT;
-S32 LLMemType::sType[LLMemType::MTYPE_MAX_DEPTH];
-S32 LLMemType::sMemCount[LLMemType::MTYPE_NUM_TYPES] = { 0 };
-S32 LLMemType::sMaxMemCount[LLMemType::MTYPE_NUM_TYPES] = { 0 };
-S32 LLMemType::sNewCount[LLMemType::MTYPE_NUM_TYPES] = { 0 };
-S32 LLMemType::sOverheadMem = 0;
-
-const char* LLMemType::sTypeDesc[LLMemType::MTYPE_NUM_TYPES] =
-{
- "INIT",
- "STARTUP",
- "MAIN",
-
- "IMAGEBASE",
- "IMAGERAW",
- "IMAGEFORMATTED",
-
- "APPFMTIMAGE",
- "APPRAWIMAGE",
- "APPAUXRAWIMAGE",
-
- "DRAWABLE",
- "OBJECT",
- "PIPELINE",
- "AVATAR",
- "PARTICLES",
- "REGIONS",
- "INVENTORY",
- "ANIMATION",
- "NETWORK",
- "PHYSICS",
- "INTERESTLIST",
-
- "SCRIPT",
- "SCRIPT_RUN",
- "SCRIPT_BYTECODE",
-
- "IO_PUMP",
- "IO_TCP",
- "IO_BUFFER",
- "IO_HTTP_SERVER"
- "IO_SD_SERVER",
- "IO_SD_CLIENT",
- "IO_URL_REQUEST",
-
- "TEMP1",
- "TEMP2",
- "TEMP3",
- "TEMP4",
- "TEMP5",
- "TEMP6",
- "TEMP7",
- "TEMP8",
- "TEMP9"
-};
-
-#endif
-S32 LLMemType::sTotalMem = 0;
-S32 LLMemType::sMaxTotalMem = 0;
-
-//static
-void LLMemType::printMem()
-{
- S32 misc_mem = sTotalMem;
-#if MEM_TRACK_TYPE
- for (S32 i=0; i<MTYPE_NUM_TYPES; i++)
- {
- if (sMemCount[i])
- {
- llinfos << llformat("MEM: % 20s %03d MB (%03d MB) in %06d News",sTypeDesc[i],sMemCount[i]>>20,sMaxMemCount[i]>>20, sNewCount[i]) << llendl;
- }
- misc_mem -= sMemCount[i];
- }
-#endif
- llinfos << llformat("MEM: % 20s %03d MB","MISC",misc_mem>>20) << llendl;
- llinfos << llformat("MEM: % 20s %03d MB (Max=%d MB)","TOTAL",sTotalMem>>20,sMaxTotalMem>>20) << llendl;
-}
-
-#if MEM_TRACK_MEM
-
-void* ll_allocate (size_t size)
-{
- if (size == 0)
- {
- llwarns << "Null allocation" << llendl;
- }
-
- size = (size+3)&~3;
- S32 alloc_size = size + 4;
-#if MEM_TRACK_TYPE
- alloc_size += 4;
-#endif
- char* p = (char*)malloc(alloc_size);
- if (p == NULL)
- {
- LLMemory::freeReserve();
- llerrs << "Out of memory Error" << llendl;
- }
- LLMemType::sTotalMem += size;
- LLMemType::sMaxTotalMem = llmax(LLMemType::sTotalMem, LLMemType::sMaxTotalMem);
- LLMemType::sOverheadMem += 4;
- *(size_t*)p = size;
- p += 4;
-#if MEM_TRACK_TYPE
- if (LLMemType::sCurType < 0 || LLMemType::sCurType >= LLMemType::MTYPE_NUM_TYPES)
- {
- llerrs << "Memory Type Error: new" << llendl;
- }
- LLMemType::sOverheadMem += 4;
- *(S32*)p = LLMemType::sCurType;
- p += 4;
- LLMemType::sMemCount[LLMemType::sCurType] += size;
- if (LLMemType::sMemCount[LLMemType::sCurType] > LLMemType::sMaxMemCount[LLMemType::sCurType])
- {
- LLMemType::sMaxMemCount[LLMemType::sCurType] = LLMemType::sMemCount[LLMemType::sCurType];
- }
- LLMemType::sNewCount[LLMemType::sCurType]++;
-#endif
- return (void*)p;
-}
-
-void ll_release (void *pin)
-{
- if (!pin)
- {
- return;
- }
- char* p = (char*)pin;
-#if MEM_TRACK_TYPE
- p -= 4;
- S32 type = *(S32*)p;
- if (type < 0 || type >= LLMemType::MTYPE_NUM_TYPES)
- {
- llerrs << "Memory Type Error: delete" << llendl;
- }
-#endif
- p -= 4;
- S32 size = *(size_t*)p;
- LLMemType::sOverheadMem -= 4;
-#if MEM_TRACK_TYPE
- LLMemType::sMemCount[type] -= size;
- LLMemType::sOverheadMem -= 4;
- LLMemType::sNewCount[type]--;
-#endif
- LLMemType::sTotalMem -= size;
- free(p);
-}
-
-#else
-
void* ll_allocate (size_t size)
{
if (size == 0)
@@ -253,52 +87,11 @@ void ll_release (void *p)
free(p);
}
-#endif
-
-#if MEM_TRACK_MEM
-
-void* operator new (size_t size)
-{
- return ll_allocate(size);
-}
-
-void* operator new[] (size_t size)
-{
- return ll_allocate(size);
-}
-
-void operator delete (void *p)
-{
- ll_release(p);
-}
-
-void operator delete[] (void *p)
-{
- ll_release(p);
-}
-
-#endif
-
-//----------------------------------------------------------------------------
-
-LLRefCount::LLRefCount() :
- mRef(0)
-{
-}
-
-LLRefCount::~LLRefCount()
-{
- if (mRef != 0)
- {
- llerrs << "deleting non-zero reference" << llendl;
- }
-}
-
//----------------------------------------------------------------------------
#if defined(LL_WINDOWS)
-U64 getCurrentRSS()
+U64 LLMemory::getCurrentRSS()
{
HANDLE self = GetCurrentProcess();
PROCESS_MEMORY_COUNTERS counters;
@@ -314,80 +107,56 @@ U64 getCurrentRSS()
#elif defined(LL_DARWIN)
-static U32 getPageSize()
-{
- int ctl[2] = { CTL_HW, HW_PAGESIZE };
- int page_size;
- size_t size = sizeof(page_size);
-
- if (sysctl(ctl, 2, &page_size, &size, NULL, 0) == -1)
- {
- llwarns << "Couldn't get page size" << llendl;
- return 0;
- } else {
- return page_size;
+/*
+ The API used here is not capable of dealing with 64-bit memory sizes, but is available before 10.4.
+
+ Once we start requiring 10.4, we can use the updated API, which looks like this:
+
+ task_basic_info_64_data_t basicInfo;
+ mach_msg_type_number_t basicInfoCount = TASK_BASIC_INFO_64_COUNT;
+ if (task_info(mach_task_self(), TASK_BASIC_INFO_64, (task_info_t)&basicInfo, &basicInfoCount) == KERN_SUCCESS)
+
+ Of course, this doesn't gain us anything unless we start building the viewer as a 64-bit executable, since that's the only way
+ for our memory allocation to exceed 2^32.
+*/
+
+// if (sysctl(ctl, 2, &page_size, &size, NULL, 0) == -1)
+// {
+// llwarns << "Couldn't get page size" << llendl;
+// return 0;
+// } else {
+// return page_size;
+// }
+// }
+
+U64 LLMemory::getCurrentRSS()
+{
+ U64 residentSize = 0;
+ task_basic_info_data_t basicInfo;
+ mach_msg_type_number_t basicInfoCount = TASK_BASIC_INFO_COUNT;
+ if (task_info(mach_task_self(), TASK_BASIC_INFO, (task_info_t)&basicInfo, &basicInfoCount) == KERN_SUCCESS)
+ {
+ residentSize = basicInfo.resident_size;
+
+ // If we ever wanted it, the process virtual size is also available as:
+ // virtualSize = basicInfo.virtual_size;
+
+// llinfos << "resident size is " << residentSize << llendl;
}
-}
-
-U64 getCurrentRSS()
-{
- task_t task = mach_task_self();
- vm_address_t addr = VM_MIN_ADDRESS;
- vm_size_t size = 0;
- U64 residentPages = 0;
-
- while (true)
+ else
{
- mach_msg_type_number_t bcount = VM_REGION_BASIC_INFO_COUNT;
- vm_region_basic_info binfo;
- mach_port_t bobj;
- kern_return_t ret;
-
- addr += size;
-
- ret = vm_region(task, &addr, &size, VM_REGION_BASIC_INFO,
- (vm_region_info_t) &binfo, &bcount, &bobj);
-
- if (ret != KERN_SUCCESS)
- {
- break;
- }
-
- if (bobj != MACH_PORT_NULL)
- {
- mach_port_deallocate(task, bobj);
- }
-
- mach_msg_type_number_t ecount = VM_REGION_EXTENDED_INFO_COUNT;
- vm_region_extended_info einfo;
- mach_port_t eobj;
-
- ret = vm_region(task, &addr, &size, VM_REGION_EXTENDED_INFO,
- (vm_region_info_t) &einfo, &ecount, &eobj);
-
- if (ret != KERN_SUCCESS)
- {
- llwarns << "vm_region failed" << llendl;
- return 0;
- }
-
- if (eobj != MACH_PORT_NULL)
- {
- mach_port_deallocate(task, eobj);
- }
-
- residentPages += einfo.pages_resident;
+ llwarns << "task_info failed" << llendl;
}
- return residentPages * getPageSize();
+ return residentSize;
}
#elif defined(LL_LINUX)
-U64 getCurrentRSS()
+U64 LLMemory::getCurrentRSS()
{
static const char statPath[] = "/proc/self/stat";
- FILE *fp = fopen(statPath, "r");
+ LLFILE *fp = LLFile::fopen(statPath, "r");
U64 rss = 0;
if (fp == NULL)
@@ -416,9 +185,37 @@ bail:
return rss;
}
+#elif LL_SOLARIS
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#define _STRUCTURED_PROC 1
+#include <sys/procfs.h>
+
+U64 LLMemory::getCurrentRSS()
+{
+ char path [LL_MAX_PATH]; /* Flawfinder: ignore */
+
+ sprintf(path, "/proc/%d/psinfo", (int)getpid());
+ int proc_fd = -1;
+ if((proc_fd = open(path, O_RDONLY)) == -1){
+ llwarns << "LLmemory::getCurrentRSS() unable to open " << path << ". Returning 0 RSS!" << llendl;
+ return 0;
+ }
+ psinfo_t proc_psinfo;
+ if(read(proc_fd, &proc_psinfo, sizeof(psinfo_t)) != sizeof(psinfo_t)){
+ llwarns << "LLmemory::getCurrentRSS() Unable to read from " << path << ". Returning 0 RSS!" << llendl;
+ close(proc_fd);
+ return 0;
+ }
+
+ close(proc_fd);
+
+ return((U64)proc_psinfo.pr_rssize * 1024);
+}
#else
-U64 getCurrentRSS()
+U64 LLMemory::getCurrentRSS()
{
return 0;
}
diff --git a/indra/llcommon/llmemory.h b/indra/llcommon/llmemory.h
index b0a47b6820..9bf4248bb7 100644
--- a/indra/llcommon/llmemory.h
+++ b/indra/llcommon/llmemory.h
@@ -2,438 +2,58 @@
* @file llmemory.h
* @brief Memory allocation/deallocation header-stuff goes here.
*
- * $LicenseInfo:firstyear=2002&license=viewergpl$
- *
- * Copyright (c) 2002-2007, Linden Research, Inc.
- *
+ * $LicenseInfo:firstyear=2002&license=viewerlgpl$
* Second Life Viewer Source Code
- * The source code in this file ("Source Code") is provided by Linden Lab
- * to you under the terms of the GNU General Public License, version 2.0
- * ("GPL"), unless you have obtained a separate licensing agreement
- * ("Other License"), formally executed by you and Linden Lab. Terms of
- * the GPL can be found in doc/GPL-license.txt in this distribution, or
- * online at http://secondlife.com/developers/opensource/gplv2
+ * 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.
*
- * There are special exceptions to the terms and conditions of the GPL as
- * it is applied to this Source Code. View the full text of the exception
- * in the file doc/FLOSS-exception.txt in this software distribution, or
- * online at http://secondlife.com/developers/opensource/flossexception
+ * 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.
*
- * By copying, modifying or distributing this software, you acknowledge
- * that you have read and understood your obligations described above,
- * and agree to abide by those obligations.
+ * 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
*
- * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
- * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
- * COMPLETENESS OR PERFORMANCE.
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
* $/LicenseInfo$
*/
-#ifndef LL_MEMORY_H
-#define LL_MEMORY_H
+#ifndef LLMEMORY_H
+#define LLMEMORY_H
-#include <new>
-#include <cstdlib>
-#include "llerror.h"
extern S32 gTotalDAlloc;
extern S32 gTotalDAUse;
extern S32 gDACount;
-const U32 LLREFCOUNT_SENTINEL_VALUE = 0xAAAAAAAA;
+extern void* ll_allocate (size_t size);
+extern void ll_release (void *p);
-//----------------------------------------------------------------------------
-
-class LLMemory
+class LL_COMMON_API LLMemory
{
public:
static void initClass();
static void cleanupClass();
static void freeReserve();
+ // Return the resident set size of the current process, in bytes.
+ // Return value is zero if not known.
+ static U64 getCurrentRSS();
private:
static char* reserveMem;
};
-//----------------------------------------------------------------------------
-// RefCount objects should generally only be accessed by way of LLPointer<>'s
-// NOTE: LLPointer<LLFoo> x = new LLFoo(); MAY NOT BE THREAD SAFE
-// if LLFoo::LLFoo() does anything like put itself in an update queue.
-// The queue may get accessed before it gets assigned to x.
-// The correct implementation is:
-// LLPointer<LLFoo> x = new LLFoo; // constructor does not do anything interesting
-// x->instantiate(); // does stuff like place x into an update queue
-
-// see llthread.h for LLThreadSafeRefCount
-
-//----------------------------------------------------------------------------
-
-class LLRefCount
-{
-protected:
- LLRefCount(const LLRefCount&); // not implemented
-private:
- LLRefCount&operator=(const LLRefCount&); // not implemented
-
-protected:
- virtual ~LLRefCount(); // use unref()
-
-public:
- LLRefCount();
-
- void ref()
- {
- mRef++;
- }
-
- S32 unref()
- {
- llassert(mRef >= 1);
- if (0 == --mRef)
- {
- delete this;
- return 0;
- }
- return mRef;
- }
-
- S32 getNumRefs() const
- {
- return mRef;
- }
-
-private:
- S32 mRef;
-};
-
-//----------------------------------------------------------------------------
-
-// Note: relies on Type having ref() and unref() methods
-template <class Type> class LLPointer
-{
-public:
-
- LLPointer() :
- mPointer(NULL)
- {
- }
-
- LLPointer(Type* ptr) :
- mPointer(ptr)
- {
- ref();
- }
-
- LLPointer(const LLPointer<Type>& ptr) :
- mPointer(ptr.mPointer)
- {
- ref();
- }
-
- // support conversion up the type hierarchy. See Item 45 in Effective C++, 3rd Ed.
- template<typename Subclass>
- LLPointer(const LLPointer<Subclass>& ptr) :
- mPointer(ptr.get())
- {
- ref();
- }
-
- ~LLPointer()
- {
- unref();
- }
-
- Type* get() const { return mPointer; }
- const Type* operator->() const { return mPointer; }
- Type* operator->() { return mPointer; }
- const Type& operator*() const { return *mPointer; }
- Type& operator*() { return *mPointer; }
-
- operator BOOL() const { return (mPointer != NULL); }
- operator bool() const { return (mPointer != NULL); }
- bool operator!() const { return (mPointer == NULL); }
- bool isNull() const { return (mPointer == NULL); }
- bool notNull() const { return (mPointer != NULL); }
-
- operator Type*() const { return mPointer; }
- operator const Type*() const { return mPointer; }
- bool operator !=(Type* ptr) const { return (mPointer != ptr); }
- bool operator ==(Type* ptr) const { return (mPointer == ptr); }
- bool operator ==(const LLPointer<Type>& ptr) const { return (mPointer == ptr.mPointer); }
- bool operator < (const LLPointer<Type>& ptr) const { return (mPointer < ptr.mPointer); }
- bool operator > (const LLPointer<Type>& ptr) const { return (mPointer > ptr.mPointer); }
-
- LLPointer<Type>& operator =(Type* ptr)
- {
- if( mPointer != ptr )
- {
- unref();
- mPointer = ptr;
- ref();
- }
-
- return *this;
- }
-
- LLPointer<Type>& operator =(const LLPointer<Type>& ptr)
- {
- if( mPointer != ptr.mPointer )
- {
- unref();
- mPointer = ptr.mPointer;
- ref();
- }
- return *this;
- }
-
- // support assignment up the type hierarchy. See Item 45 in Effective C++, 3rd Ed.
- template<typename Subclass>
- LLPointer<Type>& operator =(const LLPointer<Subclass>& ptr)
- {
- if( mPointer != ptr.get() )
- {
- unref();
- mPointer = ptr.get();
- ref();
- }
- return *this;
- }
-
- // Just exchange the pointers, which will not change the reference counts.
- static void swap(LLPointer<Type>& a, LLPointer<Type>& b)
- {
- Type* temp = a.mPointer;
- a.mPointer = b.mPointer;
- b.mPointer = temp;
- }
-
-protected:
- void ref()
- {
- if (mPointer)
- {
- mPointer->ref();
- }
- }
-
- void unref()
- {
- if (mPointer)
- {
- Type *tempp = mPointer;
- mPointer = NULL;
- tempp->unref();
- if (mPointer != NULL)
- {
- llwarns << "Unreference did assignment to non-NULL because of destructor" << llendl;
- unref();
- }
- }
- }
-
-protected:
- Type* mPointer;
-};
-
-//template <class Type>
-//class LLPointerTraits
-//{
-// static Type* null();
-//};
-//
-// Expands LLPointer to return a pointer to a special instance of class Type instead of NULL.
-// This is useful in instances where operations on NULL pointers are semantically safe and/or
-// when error checking occurs at a different granularity or in a different part of the code
-// than when referencing an object via a LLSafeHandle.
-//
-
-template <class Type>
-class LLSafeHandle
-{
-public:
- LLSafeHandle() :
- mPointer(NULL)
- {
- }
-
- LLSafeHandle(Type* ptr) :
- mPointer(NULL)
- {
- assign(ptr);
- }
-
- LLSafeHandle(const LLSafeHandle<Type>& ptr) :
- mPointer(NULL)
- {
- assign(ptr.mPointer);
- }
-
- // support conversion up the type hierarchy. See Item 45 in Effective C++, 3rd Ed.
- template<typename Subclass>
- LLSafeHandle(const LLSafeHandle<Subclass>& ptr) :
- mPointer(NULL)
- {
- assign(ptr.get());
- }
-
- ~LLSafeHandle()
- {
- unref();
- }
-
- const Type* operator->() const { return nonNull(mPointer); }
- Type* operator->() { return nonNull(mPointer); }
-
- Type* get() const { return mPointer; }
- // we disallow these operations as they expose our null objects to direct manipulation
- // and bypass the reference counting semantics
- //const Type& operator*() const { return *nonNull(mPointer); }
- //Type& operator*() { return *nonNull(mPointer); }
-
- operator BOOL() const { return mPointer != NULL; }
- operator bool() const { return mPointer != NULL; }
- bool operator!() const { return mPointer == NULL; }
- bool isNull() const { return mPointer == NULL; }
- bool notNull() const { return mPointer != NULL; }
-
-
- operator Type*() const { return mPointer; }
- operator const Type*() const { return mPointer; }
- bool operator !=(Type* ptr) const { return (mPointer != ptr); }
- bool operator ==(Type* ptr) const { return (mPointer == ptr); }
- bool operator ==(const LLSafeHandle<Type>& ptr) const { return (mPointer == ptr.mPointer); }
- bool operator < (const LLSafeHandle<Type>& ptr) const { return (mPointer < ptr.mPointer); }
- bool operator > (const LLSafeHandle<Type>& ptr) const { return (mPointer > ptr.mPointer); }
-
- LLSafeHandle<Type>& operator =(Type* ptr)
- {
- assign(ptr);
- return *this;
- }
-
- LLSafeHandle<Type>& operator =(const LLSafeHandle<Type>& ptr)
- {
- assign(ptr.mPointer);
- return *this;
- }
-
- // support assignment up the type hierarchy. See Item 45 in Effective C++, 3rd Ed.
- template<typename Subclass>
- LLSafeHandle<Type>& operator =(const LLSafeHandle<Subclass>& ptr)
- {
- assign(ptr.get());
- return *this;
- }
-
-public:
- typedef Type* (*NullFunc)();
- static const NullFunc sNullFunc;
-
-protected:
- void ref()
- {
- if (mPointer)
- {
- mPointer->ref();
- }
- }
-
- void unref()
- {
- if (mPointer)
- {
- Type *tempp = mPointer;
- mPointer = NULL;
- tempp->unref();
- if (mPointer != NULL)
- {
- llwarns << "Unreference did assignment to non-NULL because of destructor" << llendl;
- unref();
- }
- }
- }
-
- void assign(Type* ptr)
- {
- if( mPointer != ptr )
- {
- unref();
- mPointer = ptr;
- ref();
- }
- }
-
- static Type* nonNull(Type* ptr)
- {
- return ptr == NULL ? sNullFunc() : ptr;
- }
-
-protected:
- Type* mPointer;
-};
-
-// LLInitializedPointer is just a pointer with a default constructor that initializes it to NULL
-// NOT a smart pointer like LLPointer<>
-// Useful for example in std::map<int,LLInitializedPointer<LLFoo> >
-// (std::map uses the default constructor for creating new entries)
-template <typename T> class LLInitializedPointer
-{
-public:
- LLInitializedPointer() : mPointer(NULL) {}
- ~LLInitializedPointer() { delete mPointer; }
-
- const T* operator->() const { return mPointer; }
- T* operator->() { return mPointer; }
- const T& operator*() const { return *mPointer; }
- T& operator*() { return *mPointer; }
- operator const T*() const { return mPointer; }
- operator T*() { return mPointer; }
- T* operator=(T* x) { return (mPointer = x); }
- operator bool() const { return mPointer != NULL; }
- bool operator!() const { return mPointer == NULL; }
- bool operator==(T* rhs) { return mPointer == rhs; }
- bool operator==(const LLInitializedPointer<T>* rhs) { return mPointer == rhs.mPointer; }
-
-protected:
- T* mPointer;
-};
+// LLRefCount moved to llrefcount.h
-//----------------------------------------------------------------------------
-
-// LLSingleton implements the getInstance() method part of the Singleton
-// pattern. It can't make the derived class constructors protected, though, so
-// you have to do that yourself.
-//
-// There are two ways to use LLSingleton. The first way is to inherit from it
-// while using the typename that you'd like to be static as the template
-// parameter, like so:
-//
-// class Foo: public LLSingleton<Foo>{};
-//
-// Foo* instance = Foo::getInstance();
-//
-// The second way is to define a seperate class that exposes the singleton
-// interface:
-//
-// class FooSingleton: public LLSingleton<Foo>{};
-//
-// Foo* instance = FooSingleton::getInstance();
-//
-// As currently written, it is not thread-safe.
-template <typename T>
-class LLSingleton
-{
-public:
- static T* getInstance()
- {
- static T instance;
- return &instance;
- }
-};
+// LLPointer moved to llpointer.h
-//----------------------------------------------------------------------------
+// LLSafeHandle moved to llsafehandle.h
-// Return the resident set size of the current process, in bytes.
-// Return value is zero if not known.
-U64 getCurrentRSS();
+// LLSingleton moved to llsingleton.h
#endif
diff --git a/indra/llcommon/llmemorystream.cpp b/indra/llcommon/llmemorystream.cpp
index e4872526aa..723d94f025 100644
--- a/indra/llcommon/llmemorystream.cpp
+++ b/indra/llcommon/llmemorystream.cpp
@@ -4,30 +4,25 @@
* @date 2005-06-03
* @brief Buffer and stream for a fixed linear memory segment.
*
- * $LicenseInfo:firstyear=2005&license=viewergpl$
- *
- * Copyright (c) 2005-2007, Linden Research, Inc.
- *
+ * $LicenseInfo:firstyear=2005&license=viewerlgpl$
* Second Life Viewer Source Code
- * The source code in this file ("Source Code") is provided by Linden Lab
- * to you under the terms of the GNU General Public License, version 2.0
- * ("GPL"), unless you have obtained a separate licensing agreement
- * ("Other License"), formally executed by you and Linden Lab. Terms of
- * the GPL can be found in doc/GPL-license.txt in this distribution, or
- * online at http://secondlife.com/developers/opensource/gplv2
+ * 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.
*
- * There are special exceptions to the terms and conditions of the GPL as
- * it is applied to this Source Code. View the full text of the exception
- * in the file doc/FLOSS-exception.txt in this software distribution, or
- * online at http://secondlife.com/developers/opensource/flossexception
+ * 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.
*
- * By copying, modifying or distributing this software, you acknowledge
- * that you have read and understood your obligations described above,
- * and agree to abide by those obligations.
+ * 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
*
- * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
- * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
- * COMPLETENESS OR PERFORMANCE.
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
* $/LicenseInfo$
*/
diff --git a/indra/llcommon/llmemorystream.h b/indra/llcommon/llmemorystream.h
index 317e86d29a..e28f012192 100644
--- a/indra/llcommon/llmemorystream.h
+++ b/indra/llcommon/llmemorystream.h
@@ -4,30 +4,25 @@
* @date 2005-06-03
* @brief Implementation of a simple fixed memory stream
*
- * $LicenseInfo:firstyear=2005&license=viewergpl$
- *
- * Copyright (c) 2005-2007, Linden Research, Inc.
- *
+ * $LicenseInfo:firstyear=2005&license=viewerlgpl$
* Second Life Viewer Source Code
- * The source code in this file ("Source Code") is provided by Linden Lab
- * to you under the terms of the GNU General Public License, version 2.0
- * ("GPL"), unless you have obtained a separate licensing agreement
- * ("Other License"), formally executed by you and Linden Lab. Terms of
- * the GPL can be found in doc/GPL-license.txt in this distribution, or
- * online at http://secondlife.com/developers/opensource/gplv2
+ * 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.
*
- * There are special exceptions to the terms and conditions of the GPL as
- * it is applied to this Source Code. View the full text of the exception
- * in the file doc/FLOSS-exception.txt in this software distribution, or
- * online at http://secondlife.com/developers/opensource/flossexception
+ * 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.
*
- * By copying, modifying or distributing this software, you acknowledge
- * that you have read and understood your obligations described above,
- * and agree to abide by those obligations.
+ * 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
*
- * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
- * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
- * COMPLETENESS OR PERFORMANCE.
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
* $/LicenseInfo$
*/
@@ -51,7 +46,7 @@
* be careful to always pass in a valid memory location that exists
* for at least as long as this streambuf.
*/
-class LLMemoryStreamBuf : public std::streambuf
+class LL_COMMON_API LLMemoryStreamBuf : public std::streambuf
{
public:
LLMemoryStreamBuf(const U8* start, S32 length);
@@ -73,7 +68,7 @@ protected:
* be careful to always pass in a valid memory location that exists
* for at least as long as this streambuf.
*/
-class LLMemoryStream : public std::istream
+class LL_COMMON_API LLMemoryStream : public std::istream
{
public:
LLMemoryStream(const U8* start, S32 length);
diff --git a/indra/llcommon/llmemtype.cpp b/indra/llcommon/llmemtype.cpp
new file mode 100644
index 0000000000..fe83f87d4b
--- /dev/null
+++ b/indra/llcommon/llmemtype.cpp
@@ -0,0 +1,231 @@
+/**
+ * @file llmemtype.cpp
+ * @brief Simple memory allocation/deallocation tracking stuff here
+ *
+ * $LicenseInfo:firstyear=2002&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$
+ */
+
+#include "llmemtype.h"
+#include "llallocator.h"
+
+std::vector<char const *> LLMemType::DeclareMemType::mNameList;
+
+LLMemType::DeclareMemType LLMemType::MTYPE_INIT("Init");
+LLMemType::DeclareMemType LLMemType::MTYPE_STARTUP("Startup");
+LLMemType::DeclareMemType LLMemType::MTYPE_MAIN("Main");
+LLMemType::DeclareMemType LLMemType::MTYPE_FRAME("Frame");
+
+LLMemType::DeclareMemType LLMemType::MTYPE_GATHER_INPUT("GatherInput");
+LLMemType::DeclareMemType LLMemType::MTYPE_JOY_KEY("JoyKey");
+
+LLMemType::DeclareMemType LLMemType::MTYPE_IDLE("Idle");
+LLMemType::DeclareMemType LLMemType::MTYPE_IDLE_PUMP("IdlePump");
+LLMemType::DeclareMemType LLMemType::MTYPE_IDLE_NETWORK("IdleNetwork");
+LLMemType::DeclareMemType LLMemType::MTYPE_IDLE_UPDATE_REGIONS("IdleUpdateRegions");
+LLMemType::DeclareMemType LLMemType::MTYPE_IDLE_UPDATE_VIEWER_REGION("IdleUpdateViewerRegion");
+LLMemType::DeclareMemType LLMemType::MTYPE_IDLE_UPDATE_SURFACE("IdleUpdateSurface");
+LLMemType::DeclareMemType LLMemType::MTYPE_IDLE_UPDATE_PARCEL_OVERLAY("IdleUpdateParcelOverlay");
+LLMemType::DeclareMemType LLMemType::MTYPE_IDLE_AUDIO("IdleAudio");
+
+LLMemType::DeclareMemType LLMemType::MTYPE_CACHE_PROCESS_PENDING("CacheProcessPending");
+LLMemType::DeclareMemType LLMemType::MTYPE_CACHE_PROCESS_PENDING_ASKS("CacheProcessPendingAsks");
+LLMemType::DeclareMemType LLMemType::MTYPE_CACHE_PROCESS_PENDING_REPLIES("CacheProcessPendingReplies");
+
+LLMemType::DeclareMemType LLMemType::MTYPE_MESSAGE_CHECK_ALL("MessageCheckAll");
+LLMemType::DeclareMemType LLMemType::MTYPE_MESSAGE_PROCESS_ACKS("MessageProcessAcks");
+
+LLMemType::DeclareMemType LLMemType::MTYPE_RENDER("Render");
+LLMemType::DeclareMemType LLMemType::MTYPE_SLEEP("Sleep");
+
+LLMemType::DeclareMemType LLMemType::MTYPE_NETWORK("Network");
+LLMemType::DeclareMemType LLMemType::MTYPE_PHYSICS("Physics");
+LLMemType::DeclareMemType LLMemType::MTYPE_INTERESTLIST("InterestList");
+
+LLMemType::DeclareMemType LLMemType::MTYPE_IMAGEBASE("ImageBase");
+LLMemType::DeclareMemType LLMemType::MTYPE_IMAGERAW("ImageRaw");
+LLMemType::DeclareMemType LLMemType::MTYPE_IMAGEFORMATTED("ImageFormatted");
+
+LLMemType::DeclareMemType LLMemType::MTYPE_APPFMTIMAGE("AppFmtImage");
+LLMemType::DeclareMemType LLMemType::MTYPE_APPRAWIMAGE("AppRawImage");
+LLMemType::DeclareMemType LLMemType::MTYPE_APPAUXRAWIMAGE("AppAuxRawImage");
+
+LLMemType::DeclareMemType LLMemType::MTYPE_DRAWABLE("Drawable");
+
+LLMemType::DeclareMemType LLMemType::MTYPE_OBJECT("Object");
+LLMemType::DeclareMemType LLMemType::MTYPE_OBJECT_PROCESS_UPDATE("ObjectProcessUpdate");
+LLMemType::DeclareMemType LLMemType::MTYPE_OBJECT_PROCESS_UPDATE_CORE("ObjectProcessUpdateCore");
+
+LLMemType::DeclareMemType LLMemType::MTYPE_DISPLAY("Display");
+LLMemType::DeclareMemType LLMemType::MTYPE_DISPLAY_UPDATE("DisplayUpdate");
+LLMemType::DeclareMemType LLMemType::MTYPE_DISPLAY_UPDATE_CAMERA("DisplayUpdateCam");
+LLMemType::DeclareMemType LLMemType::MTYPE_DISPLAY_UPDATE_GEOM("DisplayUpdateGeom");
+LLMemType::DeclareMemType LLMemType::MTYPE_DISPLAY_SWAP("DisplaySwap");
+LLMemType::DeclareMemType LLMemType::MTYPE_DISPLAY_UPDATE_HUD("DisplayUpdateHud");
+LLMemType::DeclareMemType LLMemType::MTYPE_DISPLAY_GEN_REFLECTION("DisplayGenRefl");
+LLMemType::DeclareMemType LLMemType::MTYPE_DISPLAY_IMAGE_UPDATE("DisplayImageUpdate");
+LLMemType::DeclareMemType LLMemType::MTYPE_DISPLAY_STATE_SORT("DisplayStateSort");
+LLMemType::DeclareMemType LLMemType::MTYPE_DISPLAY_SKY("DisplaySky");
+LLMemType::DeclareMemType LLMemType::MTYPE_DISPLAY_RENDER_GEOM("DisplayRenderGeom");
+LLMemType::DeclareMemType LLMemType::MTYPE_DISPLAY_RENDER_FLUSH("DisplayRenderFlush");
+LLMemType::DeclareMemType LLMemType::MTYPE_DISPLAY_RENDER_UI("DisplayRenderUI");
+LLMemType::DeclareMemType LLMemType::MTYPE_DISPLAY_RENDER_ATTACHMENTS("DisplayRenderAttach");
+
+LLMemType::DeclareMemType LLMemType::MTYPE_VERTEX_DATA("VertexData");
+LLMemType::DeclareMemType LLMemType::MTYPE_VERTEX_CONSTRUCTOR("VertexConstr");
+LLMemType::DeclareMemType LLMemType::MTYPE_VERTEX_DESTRUCTOR("VertexDestr");
+LLMemType::DeclareMemType LLMemType::MTYPE_VERTEX_CREATE_VERTICES("VertexCreateVerts");
+LLMemType::DeclareMemType LLMemType::MTYPE_VERTEX_CREATE_INDICES("VertexCreateIndices");
+LLMemType::DeclareMemType LLMemType::MTYPE_VERTEX_DESTROY_BUFFER("VertexDestroyBuff");
+LLMemType::DeclareMemType LLMemType::MTYPE_VERTEX_DESTROY_INDICES("VertexDestroyIndices");
+LLMemType::DeclareMemType LLMemType::MTYPE_VERTEX_UPDATE_VERTS("VertexUpdateVerts");
+LLMemType::DeclareMemType LLMemType::MTYPE_VERTEX_UPDATE_INDICES("VertexUpdateIndices");
+LLMemType::DeclareMemType LLMemType::MTYPE_VERTEX_ALLOCATE_BUFFER("VertexAllocateBuffer");
+LLMemType::DeclareMemType LLMemType::MTYPE_VERTEX_RESIZE_BUFFER("VertexResizeBuffer");
+LLMemType::DeclareMemType LLMemType::MTYPE_VERTEX_MAP_BUFFER("VertexMapBuffer");
+LLMemType::DeclareMemType LLMemType::MTYPE_VERTEX_MAP_BUFFER_VERTICES("VertexMapBufferVerts");
+LLMemType::DeclareMemType LLMemType::MTYPE_VERTEX_MAP_BUFFER_INDICES("VertexMapBufferIndices");
+LLMemType::DeclareMemType LLMemType::MTYPE_VERTEX_UNMAP_BUFFER("VertexUnmapBuffer");
+LLMemType::DeclareMemType LLMemType::MTYPE_VERTEX_SET_STRIDE("VertexSetStride");
+LLMemType::DeclareMemType LLMemType::MTYPE_VERTEX_SET_BUFFER("VertexSetBuffer");
+LLMemType::DeclareMemType LLMemType::MTYPE_VERTEX_SETUP_VERTEX_BUFFER("VertexSetupVertBuff");
+LLMemType::DeclareMemType LLMemType::MTYPE_VERTEX_CLEANUP_CLASS("VertexCleanupClass");
+
+LLMemType::DeclareMemType LLMemType::MTYPE_SPACE_PARTITION("SpacePartition");
+
+LLMemType::DeclareMemType LLMemType::MTYPE_PIPELINE("Pipeline");
+LLMemType::DeclareMemType LLMemType::MTYPE_PIPELINE_INIT("PipelineInit");
+LLMemType::DeclareMemType LLMemType::MTYPE_PIPELINE_CREATE_BUFFERS("PipelineCreateBuffs");
+LLMemType::DeclareMemType LLMemType::MTYPE_PIPELINE_RESTORE_GL("PipelineRestroGL");
+LLMemType::DeclareMemType LLMemType::MTYPE_PIPELINE_UNLOAD_SHADERS("PipelineUnloadShaders");
+LLMemType::DeclareMemType LLMemType::MTYPE_PIPELINE_LIGHTING_DETAIL("PipelineLightingDetail");
+LLMemType::DeclareMemType LLMemType::MTYPE_PIPELINE_GET_POOL_TYPE("PipelineGetPoolType");
+LLMemType::DeclareMemType LLMemType::MTYPE_PIPELINE_ADD_POOL("PipelineAddPool");
+LLMemType::DeclareMemType LLMemType::MTYPE_PIPELINE_ALLOCATE_DRAWABLE("PipelineAllocDrawable");
+LLMemType::DeclareMemType LLMemType::MTYPE_PIPELINE_ADD_OBJECT("PipelineAddObj");
+LLMemType::DeclareMemType LLMemType::MTYPE_PIPELINE_CREATE_OBJECTS("PipelineCreateObjs");
+LLMemType::DeclareMemType LLMemType::MTYPE_PIPELINE_UPDATE_MOVE("PipelineUpdateMove");
+LLMemType::DeclareMemType LLMemType::MTYPE_PIPELINE_UPDATE_GEOM("PipelineUpdateGeom");
+LLMemType::DeclareMemType LLMemType::MTYPE_PIPELINE_MARK_VISIBLE("PipelineMarkVisible");
+LLMemType::DeclareMemType LLMemType::MTYPE_PIPELINE_MARK_MOVED("PipelineMarkMoved");
+LLMemType::DeclareMemType LLMemType::MTYPE_PIPELINE_MARK_SHIFT("PipelineMarkShift");
+LLMemType::DeclareMemType LLMemType::MTYPE_PIPELINE_SHIFT_OBJECTS("PipelineShiftObjs");
+LLMemType::DeclareMemType LLMemType::MTYPE_PIPELINE_MARK_TEXTURED("PipelineMarkTextured");
+LLMemType::DeclareMemType LLMemType::MTYPE_PIPELINE_MARK_REBUILD("PipelineMarkRebuild");
+LLMemType::DeclareMemType LLMemType::MTYPE_PIPELINE_UPDATE_CULL("PipelineUpdateCull");
+LLMemType::DeclareMemType LLMemType::MTYPE_PIPELINE_STATE_SORT("PipelineStateSort");
+LLMemType::DeclareMemType LLMemType::MTYPE_PIPELINE_POST_SORT("PipelinePostSort");
+
+LLMemType::DeclareMemType LLMemType::MTYPE_PIPELINE_RENDER_HUD_ELS("PipelineHudEls");
+LLMemType::DeclareMemType LLMemType::MTYPE_PIPELINE_RENDER_HL("PipelineRenderHL");
+LLMemType::DeclareMemType LLMemType::MTYPE_PIPELINE_RENDER_GEOM("PipelineRenderGeom");
+LLMemType::DeclareMemType LLMemType::MTYPE_PIPELINE_RENDER_GEOM_DEFFERRED("PipelineRenderGeomDef");
+LLMemType::DeclareMemType LLMemType::MTYPE_PIPELINE_RENDER_GEOM_POST_DEF("PipelineRenderGeomPostDef");
+LLMemType::DeclareMemType LLMemType::MTYPE_PIPELINE_RENDER_GEOM_SHADOW("PipelineRenderGeomShadow");
+LLMemType::DeclareMemType LLMemType::MTYPE_PIPELINE_RENDER_SELECT("PipelineRenderSelect");
+LLMemType::DeclareMemType LLMemType::MTYPE_PIPELINE_REBUILD_POOLS("PipelineRebuildPools");
+LLMemType::DeclareMemType LLMemType::MTYPE_PIPELINE_QUICK_LOOKUP("PipelineQuickLookup");
+LLMemType::DeclareMemType LLMemType::MTYPE_PIPELINE_RENDER_OBJECTS("PipelineRenderObjs");
+LLMemType::DeclareMemType LLMemType::MTYPE_PIPELINE_GENERATE_IMPOSTOR("PipelineGenImpostors");
+LLMemType::DeclareMemType LLMemType::MTYPE_PIPELINE_RENDER_BLOOM("PipelineRenderBloom");
+
+LLMemType::DeclareMemType LLMemType::MTYPE_UPKEEP_POOLS("UpkeepPools");
+
+LLMemType::DeclareMemType LLMemType::MTYPE_AVATAR("Avatar");
+LLMemType::DeclareMemType LLMemType::MTYPE_AVATAR_MESH("AvatarMesh");
+LLMemType::DeclareMemType LLMemType::MTYPE_PARTICLES("Particles");
+LLMemType::DeclareMemType LLMemType::MTYPE_REGIONS("Regions");
+
+LLMemType::DeclareMemType LLMemType::MTYPE_INVENTORY("Inventory");
+LLMemType::DeclareMemType LLMemType::MTYPE_INVENTORY_DRAW("InventoryDraw");
+LLMemType::DeclareMemType LLMemType::MTYPE_INVENTORY_BUILD_NEW_VIEWS("InventoryBuildNewViews");
+LLMemType::DeclareMemType LLMemType::MTYPE_INVENTORY_DO_FOLDER("InventoryDoFolder");
+LLMemType::DeclareMemType LLMemType::MTYPE_INVENTORY_POST_BUILD("InventoryPostBuild");
+LLMemType::DeclareMemType LLMemType::MTYPE_INVENTORY_FROM_XML("InventoryFromXML");
+LLMemType::DeclareMemType LLMemType::MTYPE_INVENTORY_CREATE_NEW_ITEM("InventoryCreateNewItem");
+LLMemType::DeclareMemType LLMemType::MTYPE_INVENTORY_VIEW_INIT("InventoryViewInit");
+LLMemType::DeclareMemType LLMemType::MTYPE_INVENTORY_VIEW_SHOW("InventoryViewShow");
+LLMemType::DeclareMemType LLMemType::MTYPE_INVENTORY_VIEW_TOGGLE("InventoryViewToggle");
+
+LLMemType::DeclareMemType LLMemType::MTYPE_ANIMATION("Animation");
+LLMemType::DeclareMemType LLMemType::MTYPE_VOLUME("Volume");
+LLMemType::DeclareMemType LLMemType::MTYPE_PRIMITIVE("Primitive");
+
+LLMemType::DeclareMemType LLMemType::MTYPE_SCRIPT("Script");
+LLMemType::DeclareMemType LLMemType::MTYPE_SCRIPT_RUN("ScriptRun");
+LLMemType::DeclareMemType LLMemType::MTYPE_SCRIPT_BYTECODE("ScriptByteCode");
+
+LLMemType::DeclareMemType LLMemType::MTYPE_IO_PUMP("IoPump");
+LLMemType::DeclareMemType LLMemType::MTYPE_IO_TCP("IoTCP");
+LLMemType::DeclareMemType LLMemType::MTYPE_IO_BUFFER("IoBuffer");
+LLMemType::DeclareMemType LLMemType::MTYPE_IO_HTTP_SERVER("IoHttpServer");
+LLMemType::DeclareMemType LLMemType::MTYPE_IO_SD_SERVER("IoSDServer");
+LLMemType::DeclareMemType LLMemType::MTYPE_IO_SD_CLIENT("IoSDClient");
+LLMemType::DeclareMemType LLMemType::MTYPE_IO_URL_REQUEST("IOUrlRequest");
+
+LLMemType::DeclareMemType LLMemType::MTYPE_DIRECTX_INIT("DirectXInit");
+
+LLMemType::DeclareMemType LLMemType::MTYPE_TEMP1("Temp1");
+LLMemType::DeclareMemType LLMemType::MTYPE_TEMP2("Temp2");
+LLMemType::DeclareMemType LLMemType::MTYPE_TEMP3("Temp3");
+LLMemType::DeclareMemType LLMemType::MTYPE_TEMP4("Temp4");
+LLMemType::DeclareMemType LLMemType::MTYPE_TEMP5("Temp5");
+LLMemType::DeclareMemType LLMemType::MTYPE_TEMP6("Temp6");
+LLMemType::DeclareMemType LLMemType::MTYPE_TEMP7("Temp7");
+LLMemType::DeclareMemType LLMemType::MTYPE_TEMP8("Temp8");
+LLMemType::DeclareMemType LLMemType::MTYPE_TEMP9("Temp9");
+
+LLMemType::DeclareMemType LLMemType::MTYPE_OTHER("Other");
+
+
+LLMemType::DeclareMemType::DeclareMemType(char const * st)
+{
+ mID = (S32)mNameList.size();
+ mName = st;
+
+ mNameList.push_back(mName);
+}
+
+LLMemType::DeclareMemType::~DeclareMemType()
+{
+}
+
+LLMemType::LLMemType(LLMemType::DeclareMemType& dt)
+{
+ mTypeIndex = dt.mID;
+ LLAllocator::pushMemType(dt.mID);
+}
+
+LLMemType::~LLMemType()
+{
+ LLAllocator::popMemType();
+}
+
+char const * LLMemType::getNameFromID(S32 id)
+{
+ if (id < 0 || id >= (S32)DeclareMemType::mNameList.size())
+ {
+ return "INVALID";
+ }
+
+ return DeclareMemType::mNameList[id];
+}
+
diff --git a/indra/llcommon/llmemtype.h b/indra/llcommon/llmemtype.h
index 9bf6cad9f7..4945dbaf60 100644
--- a/indra/llcommon/llmemtype.h
+++ b/indra/llcommon/llmemtype.h
@@ -2,30 +2,25 @@
* @file llmemtype.h
* @brief Runtime memory usage debugging utilities.
*
- * $LicenseInfo:firstyear=2005&license=viewergpl$
- *
- * Copyright (c) 2005-2007, Linden Research, Inc.
- *
+ * $LicenseInfo:firstyear=2005&license=viewerlgpl$
* Second Life Viewer Source Code
- * The source code in this file ("Source Code") is provided by Linden Lab
- * to you under the terms of the GNU General Public License, version 2.0
- * ("GPL"), unless you have obtained a separate licensing agreement
- * ("Other License"), formally executed by you and Linden Lab. Terms of
- * the GPL can be found in doc/GPL-license.txt in this distribution, or
- * online at http://secondlife.com/developers/opensource/gplv2
+ * 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.
*
- * There are special exceptions to the terms and conditions of the GPL as
- * it is applied to this Source Code. View the full text of the exception
- * in the file doc/FLOSS-exception.txt in this software distribution, or
- * online at http://secondlife.com/developers/opensource/flossexception
+ * 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.
*
- * By copying, modifying or distributing this software, you acknowledge
- * that you have read and understood your obligations described above,
- * and agree to abide by those obligations.
+ * 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
*
- * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
- * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
- * COMPLETENESS OR PERFORMANCE.
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
* $/LicenseInfo$
*/
@@ -35,124 +30,210 @@
//----------------------------------------------------------------------------
//----------------------------------------------------------------------------
-class LLMemType;
-
-extern void* ll_allocate (size_t size);
-extern void ll_release (void *p);
+//----------------------------------------------------------------------------
-#define MEM_TRACK_MEM 0
-#define MEM_TRACK_TYPE (1 && MEM_TRACK_MEM)
+#include "linden_common.h"
+//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+// WARNING: Never commit with MEM_TRACK_MEM == 1
+//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+#define MEM_TRACK_MEM (0 && LL_WINDOWS)
-#if MEM_TRACK_TYPE
-#define MEM_DUMP_DATA 1
-#define MEM_TYPE_NEW(T) \
-static void* operator new(size_t s) { LLMemType mt(T); return ll_allocate(s); } \
-static void operator delete(void* p) { ll_release(p); }
+#include <vector>
-#else
#define MEM_TYPE_NEW(T)
-#endif // MEM_TRACK_TYPE
-
-//----------------------------------------------------------------------------
-
-class LLMemType
+class LL_COMMON_API LLMemType
{
public:
- // Also update sTypeDesc in llmemory.cpp
- enum EMemType
- {
- MTYPE_INIT,
- MTYPE_STARTUP,
- MTYPE_MAIN,
- MTYPE_IMAGEBASE,
- MTYPE_IMAGERAW,
- MTYPE_IMAGEFORMATTED,
-
- MTYPE_APPFMTIMAGE,
- MTYPE_APPRAWIMAGE,
- MTYPE_APPAUXRAWIMAGE,
-
- MTYPE_DRAWABLE,
- MTYPE_OBJECT,
- MTYPE_VERTEX_DATA,
- MTYPE_SPACE_PARTITION,
- MTYPE_PIPELINE,
- MTYPE_AVATAR,
- MTYPE_PARTICLES,
- MTYPE_REGIONS,
- MTYPE_INVENTORY,
- MTYPE_ANIMATION,
- MTYPE_NETWORK,
- MTYPE_PHYSICS,
- MTYPE_INTERESTLIST,
-
- MTYPE_SCRIPT,
- MTYPE_SCRIPT_RUN,
- MTYPE_SCRIPT_BYTECODE,
-
- MTYPE_IO_PUMP,
- MTYPE_IO_TCP,
- MTYPE_IO_BUFFER,
- MTYPE_IO_HTTP_SERVER,
- MTYPE_IO_SD_SERVER,
- MTYPE_IO_SD_CLIENT,
- MTYPE_IO_URL_REQUEST,
-
- MTYPE_TEMP1,
- MTYPE_TEMP2,
- MTYPE_TEMP3,
- MTYPE_TEMP4,
- MTYPE_TEMP5,
- MTYPE_TEMP6,
- MTYPE_TEMP7,
- MTYPE_TEMP8,
- MTYPE_TEMP9,
-
- MTYPE_OTHER, // Special, used by display code
+ // class we'll initialize all instances of as
+ // static members of MemType. Then use
+ // to construct any new mem type.
+ class LL_COMMON_API DeclareMemType
+ {
+ public:
+ DeclareMemType(char const * st);
+ ~DeclareMemType();
+
+ S32 mID;
+ char const * mName;
- MTYPE_NUM_TYPES
+ // array so we can map an index ID to Name
+ static std::vector<char const *> mNameList;
};
- enum { MTYPE_MAX_DEPTH = 64 };
-
-public:
- LLMemType(EMemType type)
- {
-#if MEM_TRACK_TYPE
- if (type < 0 || type >= MTYPE_NUM_TYPES)
- llerrs << "LLMemType error" << llendl;
- if (sCurDepth < 0 || sCurDepth >= MTYPE_MAX_DEPTH)
- llerrs << "LLMemType error" << llendl;
- sType[sCurDepth] = sCurType;
- sCurDepth++;
- sCurType = type;
-#endif
- }
- ~LLMemType()
- {
-#if MEM_TRACK_TYPE
- sCurDepth--;
- sCurType = sType[sCurDepth];
-#endif
- }
- static void reset();
- static void printMem();
+ LLMemType(DeclareMemType& dt);
+ ~LLMemType();
+
+ static char const * getNameFromID(S32 id);
+
+ static DeclareMemType MTYPE_INIT;
+ static DeclareMemType MTYPE_STARTUP;
+ static DeclareMemType MTYPE_MAIN;
+ static DeclareMemType MTYPE_FRAME;
+
+ static DeclareMemType MTYPE_GATHER_INPUT;
+ static DeclareMemType MTYPE_JOY_KEY;
+
+ static DeclareMemType MTYPE_IDLE;
+ static DeclareMemType MTYPE_IDLE_PUMP;
+ static DeclareMemType MTYPE_IDLE_NETWORK;
+ static DeclareMemType MTYPE_IDLE_UPDATE_REGIONS;
+ static DeclareMemType MTYPE_IDLE_UPDATE_VIEWER_REGION;
+ static DeclareMemType MTYPE_IDLE_UPDATE_SURFACE;
+ static DeclareMemType MTYPE_IDLE_UPDATE_PARCEL_OVERLAY;
+ static DeclareMemType MTYPE_IDLE_AUDIO;
+
+ static DeclareMemType MTYPE_CACHE_PROCESS_PENDING;
+ static DeclareMemType MTYPE_CACHE_PROCESS_PENDING_ASKS;
+ static DeclareMemType MTYPE_CACHE_PROCESS_PENDING_REPLIES;
+
+ static DeclareMemType MTYPE_MESSAGE_CHECK_ALL;
+ static DeclareMemType MTYPE_MESSAGE_PROCESS_ACKS;
+
+ static DeclareMemType MTYPE_RENDER;
+ static DeclareMemType MTYPE_SLEEP;
+
+ static DeclareMemType MTYPE_NETWORK;
+ static DeclareMemType MTYPE_PHYSICS;
+ static DeclareMemType MTYPE_INTERESTLIST;
+
+ static DeclareMemType MTYPE_IMAGEBASE;
+ static DeclareMemType MTYPE_IMAGERAW;
+ static DeclareMemType MTYPE_IMAGEFORMATTED;
-public:
-#if MEM_TRACK_TYPE
- static S32 sCurDepth;
- static S32 sCurType;
- static S32 sType[MTYPE_MAX_DEPTH];
- static S32 sMemCount[MTYPE_NUM_TYPES];
- static S32 sMaxMemCount[MTYPE_NUM_TYPES];
- static S32 sNewCount[MTYPE_NUM_TYPES];
- static S32 sOverheadMem;
- static const char* sTypeDesc[MTYPE_NUM_TYPES];
-#endif
- static S32 sTotalMem;
- static S32 sMaxTotalMem;
+ static DeclareMemType MTYPE_APPFMTIMAGE;
+ static DeclareMemType MTYPE_APPRAWIMAGE;
+ static DeclareMemType MTYPE_APPAUXRAWIMAGE;
+
+ static DeclareMemType MTYPE_DRAWABLE;
+
+ static DeclareMemType MTYPE_OBJECT;
+ static DeclareMemType MTYPE_OBJECT_PROCESS_UPDATE;
+ static DeclareMemType MTYPE_OBJECT_PROCESS_UPDATE_CORE;
+
+ static DeclareMemType MTYPE_DISPLAY;
+ static DeclareMemType MTYPE_DISPLAY_UPDATE;
+ static DeclareMemType MTYPE_DISPLAY_UPDATE_CAMERA;
+ static DeclareMemType MTYPE_DISPLAY_UPDATE_GEOM;
+ static DeclareMemType MTYPE_DISPLAY_SWAP;
+ static DeclareMemType MTYPE_DISPLAY_UPDATE_HUD;
+ static DeclareMemType MTYPE_DISPLAY_GEN_REFLECTION;
+ static DeclareMemType MTYPE_DISPLAY_IMAGE_UPDATE;
+ static DeclareMemType MTYPE_DISPLAY_STATE_SORT;
+ static DeclareMemType MTYPE_DISPLAY_SKY;
+ static DeclareMemType MTYPE_DISPLAY_RENDER_GEOM;
+ static DeclareMemType MTYPE_DISPLAY_RENDER_FLUSH;
+ static DeclareMemType MTYPE_DISPLAY_RENDER_UI;
+ static DeclareMemType MTYPE_DISPLAY_RENDER_ATTACHMENTS;
+
+ static DeclareMemType MTYPE_VERTEX_DATA;
+ static DeclareMemType MTYPE_VERTEX_CONSTRUCTOR;
+ static DeclareMemType MTYPE_VERTEX_DESTRUCTOR;
+ static DeclareMemType MTYPE_VERTEX_CREATE_VERTICES;
+ static DeclareMemType MTYPE_VERTEX_CREATE_INDICES;
+ static DeclareMemType MTYPE_VERTEX_DESTROY_BUFFER;
+ static DeclareMemType MTYPE_VERTEX_DESTROY_INDICES;
+ static DeclareMemType MTYPE_VERTEX_UPDATE_VERTS;
+ static DeclareMemType MTYPE_VERTEX_UPDATE_INDICES;
+ static DeclareMemType MTYPE_VERTEX_ALLOCATE_BUFFER;
+ static DeclareMemType MTYPE_VERTEX_RESIZE_BUFFER;
+ static DeclareMemType MTYPE_VERTEX_MAP_BUFFER;
+ static DeclareMemType MTYPE_VERTEX_MAP_BUFFER_VERTICES;
+ static DeclareMemType MTYPE_VERTEX_MAP_BUFFER_INDICES;
+ static DeclareMemType MTYPE_VERTEX_UNMAP_BUFFER;
+ static DeclareMemType MTYPE_VERTEX_SET_STRIDE;
+ static DeclareMemType MTYPE_VERTEX_SET_BUFFER;
+ static DeclareMemType MTYPE_VERTEX_SETUP_VERTEX_BUFFER;
+ static DeclareMemType MTYPE_VERTEX_CLEANUP_CLASS;
+
+ static DeclareMemType MTYPE_SPACE_PARTITION;
+
+ static DeclareMemType MTYPE_PIPELINE;
+ static DeclareMemType MTYPE_PIPELINE_INIT;
+ static DeclareMemType MTYPE_PIPELINE_CREATE_BUFFERS;
+ static DeclareMemType MTYPE_PIPELINE_RESTORE_GL;
+ static DeclareMemType MTYPE_PIPELINE_UNLOAD_SHADERS;
+ static DeclareMemType MTYPE_PIPELINE_LIGHTING_DETAIL;
+ static DeclareMemType MTYPE_PIPELINE_GET_POOL_TYPE;
+ static DeclareMemType MTYPE_PIPELINE_ADD_POOL;
+ static DeclareMemType MTYPE_PIPELINE_ALLOCATE_DRAWABLE;
+ static DeclareMemType MTYPE_PIPELINE_ADD_OBJECT;
+ static DeclareMemType MTYPE_PIPELINE_CREATE_OBJECTS;
+ static DeclareMemType MTYPE_PIPELINE_UPDATE_MOVE;
+ static DeclareMemType MTYPE_PIPELINE_UPDATE_GEOM;
+ static DeclareMemType MTYPE_PIPELINE_MARK_VISIBLE;
+ static DeclareMemType MTYPE_PIPELINE_MARK_MOVED;
+ static DeclareMemType MTYPE_PIPELINE_MARK_SHIFT;
+ static DeclareMemType MTYPE_PIPELINE_SHIFT_OBJECTS;
+ static DeclareMemType MTYPE_PIPELINE_MARK_TEXTURED;
+ static DeclareMemType MTYPE_PIPELINE_MARK_REBUILD;
+ static DeclareMemType MTYPE_PIPELINE_UPDATE_CULL;
+ static DeclareMemType MTYPE_PIPELINE_STATE_SORT;
+ static DeclareMemType MTYPE_PIPELINE_POST_SORT;
+
+ static DeclareMemType MTYPE_PIPELINE_RENDER_HUD_ELS;
+ static DeclareMemType MTYPE_PIPELINE_RENDER_HL;
+ static DeclareMemType MTYPE_PIPELINE_RENDER_GEOM;
+ static DeclareMemType MTYPE_PIPELINE_RENDER_GEOM_DEFFERRED;
+ static DeclareMemType MTYPE_PIPELINE_RENDER_GEOM_POST_DEF;
+ static DeclareMemType MTYPE_PIPELINE_RENDER_GEOM_SHADOW;
+ static DeclareMemType MTYPE_PIPELINE_RENDER_SELECT;
+ static DeclareMemType MTYPE_PIPELINE_REBUILD_POOLS;
+ static DeclareMemType MTYPE_PIPELINE_QUICK_LOOKUP;
+ static DeclareMemType MTYPE_PIPELINE_RENDER_OBJECTS;
+ static DeclareMemType MTYPE_PIPELINE_GENERATE_IMPOSTOR;
+ static DeclareMemType MTYPE_PIPELINE_RENDER_BLOOM;
+
+ static DeclareMemType MTYPE_UPKEEP_POOLS;
+
+ static DeclareMemType MTYPE_AVATAR;
+ static DeclareMemType MTYPE_AVATAR_MESH;
+ static DeclareMemType MTYPE_PARTICLES;
+ static DeclareMemType MTYPE_REGIONS;
+
+ static DeclareMemType MTYPE_INVENTORY;
+ static DeclareMemType MTYPE_INVENTORY_DRAW;
+ static DeclareMemType MTYPE_INVENTORY_BUILD_NEW_VIEWS;
+ static DeclareMemType MTYPE_INVENTORY_DO_FOLDER;
+ static DeclareMemType MTYPE_INVENTORY_POST_BUILD;
+ static DeclareMemType MTYPE_INVENTORY_FROM_XML;
+ static DeclareMemType MTYPE_INVENTORY_CREATE_NEW_ITEM;
+ static DeclareMemType MTYPE_INVENTORY_VIEW_INIT;
+ static DeclareMemType MTYPE_INVENTORY_VIEW_SHOW;
+ static DeclareMemType MTYPE_INVENTORY_VIEW_TOGGLE;
+
+ static DeclareMemType MTYPE_ANIMATION;
+ static DeclareMemType MTYPE_VOLUME;
+ static DeclareMemType MTYPE_PRIMITIVE;
+
+ static DeclareMemType MTYPE_SCRIPT;
+ static DeclareMemType MTYPE_SCRIPT_RUN;
+ static DeclareMemType MTYPE_SCRIPT_BYTECODE;
+
+ static DeclareMemType MTYPE_IO_PUMP;
+ static DeclareMemType MTYPE_IO_TCP;
+ static DeclareMemType MTYPE_IO_BUFFER;
+ static DeclareMemType MTYPE_IO_HTTP_SERVER;
+ static DeclareMemType MTYPE_IO_SD_SERVER;
+ static DeclareMemType MTYPE_IO_SD_CLIENT;
+ static DeclareMemType MTYPE_IO_URL_REQUEST;
+
+ static DeclareMemType MTYPE_DIRECTX_INIT;
+
+ static DeclareMemType MTYPE_TEMP1;
+ static DeclareMemType MTYPE_TEMP2;
+ static DeclareMemType MTYPE_TEMP3;
+ static DeclareMemType MTYPE_TEMP4;
+ static DeclareMemType MTYPE_TEMP5;
+ static DeclareMemType MTYPE_TEMP6;
+ static DeclareMemType MTYPE_TEMP7;
+ static DeclareMemType MTYPE_TEMP8;
+ static DeclareMemType MTYPE_TEMP9;
+
+ static DeclareMemType MTYPE_OTHER; // Special; used by display code
+
+ S32 mTypeIndex;
};
//----------------------------------------------------------------------------
diff --git a/indra/llcommon/llmetrics.cpp b/indra/llcommon/llmetrics.cpp
index 90a0517a5d..3078139f43 100644
--- a/indra/llcommon/llmetrics.cpp
+++ b/indra/llcommon/llmetrics.cpp
@@ -4,30 +4,25 @@
* @date 2007-05-25
* @brief Metrics accumulation and associated functions
*
- * $LicenseInfo:firstyear=2007&license=viewergpl$
- *
- * Copyright (c) 2007, Linden Research, Inc.
- *
+ * $LicenseInfo:firstyear=2007&license=viewerlgpl$
* Second Life Viewer Source Code
- * The source code in this file ("Source Code") is provided by Linden Lab
- * to you under the terms of the GNU General Public License, version 2.0
- * ("GPL"), unless you have obtained a separate licensing agreement
- * ("Other License"), formally executed by you and Linden Lab. Terms of
- * the GPL can be found in doc/GPL-license.txt in this distribution, or
- * online at http://secondlife.com/developers/opensource/gplv2
+ * 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.
*
- * There are special exceptions to the terms and conditions of the GPL as
- * it is applied to this Source Code. View the full text of the exception
- * in the file doc/FLOSS-exception.txt in this software distribution, or
- * online at http://secondlife.com/developers/opensource/flossexception
+ * 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.
*
- * By copying, modifying or distributing this software, you acknowledge
- * that you have read and understood your obligations described above,
- * and agree to abide by those obligations.
+ * 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
*
- * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
- * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
- * COMPLETENESS OR PERFORMANCE.
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
* $/LicenseInfo$
*/
@@ -70,7 +65,7 @@ void LLMetricsImpl::recordEventDetails(const std::string& location,
metrics["location"] = location;
metrics["stats"] = stats;
- llinfos << "LLMETRICS: " << LLSDNotationStreamer(metrics) << llendl;
+ llinfos << "LLMETRICS: " << (LLSDNotationStreamer(metrics)) << llendl;
}
// Store this:
diff --git a/indra/llcommon/llmetrics.h b/indra/llcommon/llmetrics.h
index f19bce5259..4f0ae56338 100644
--- a/indra/llcommon/llmetrics.h
+++ b/indra/llcommon/llmetrics.h
@@ -4,30 +4,25 @@
* @date 2007-05-25
* @brief Declaration of metrics accumulation and associated functions
*
- * $LicenseInfo:firstyear=2007&license=viewergpl$
- *
- * Copyright (c) 2007, Linden Research, Inc.
- *
+ * $LicenseInfo:firstyear=2007&license=viewerlgpl$
* Second Life Viewer Source Code
- * The source code in this file ("Source Code") is provided by Linden Lab
- * to you under the terms of the GNU General Public License, version 2.0
- * ("GPL"), unless you have obtained a separate licensing agreement
- * ("Other License"), formally executed by you and Linden Lab. Terms of
- * the GPL can be found in doc/GPL-license.txt in this distribution, or
- * online at http://secondlife.com/developers/opensource/gplv2
+ * 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.
*
- * There are special exceptions to the terms and conditions of the GPL as
- * it is applied to this Source Code. View the full text of the exception
- * in the file doc/FLOSS-exception.txt in this software distribution, or
- * online at http://secondlife.com/developers/opensource/flossexception
+ * 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.
*
- * By copying, modifying or distributing this software, you acknowledge
- * that you have read and understood your obligations described above,
- * and agree to abide by those obligations.
+ * 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
*
- * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
- * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
- * COMPLETENESS OR PERFORMANCE.
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
* $/LicenseInfo$
*/
@@ -37,7 +32,7 @@
class LLMetricsImpl;
class LLSD;
-class LLMetrics
+class LL_COMMON_API LLMetrics
{
public:
LLMetrics();
diff --git a/indra/llcommon/llmortician.cpp b/indra/llcommon/llmortician.cpp
index b3e25104cb..287f096eae 100644
--- a/indra/llcommon/llmortician.cpp
+++ b/indra/llcommon/llmortician.cpp
@@ -1,30 +1,25 @@
/**
* @file llmortician.cpp
*
- * $LicenseInfo:firstyear=2005&license=viewergpl$
- *
- * Copyright (c) 2005-2007, Linden Research, Inc.
- *
+ * $LicenseInfo:firstyear=2005&license=viewerlgpl$
* Second Life Viewer Source Code
- * The source code in this file ("Source Code") is provided by Linden Lab
- * to you under the terms of the GNU General Public License, version 2.0
- * ("GPL"), unless you have obtained a separate licensing agreement
- * ("Other License"), formally executed by you and Linden Lab. Terms of
- * the GPL can be found in doc/GPL-license.txt in this distribution, or
- * online at http://secondlife.com/developers/opensource/gplv2
+ * 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.
*
- * There are special exceptions to the terms and conditions of the GPL as
- * it is applied to this Source Code. View the full text of the exception
- * in the file doc/FLOSS-exception.txt in this software distribution, or
- * online at http://secondlife.com/developers/opensource/flossexception
+ * 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.
*
- * By copying, modifying or distributing this software, you acknowledge
- * that you have read and understood your obligations described above,
- * and agree to abide by those obligations.
+ * 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
*
- * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
- * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
- * COMPLETENESS OR PERFORMANCE.
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
* $/LicenseInfo$
*/
diff --git a/indra/llcommon/llmortician.h b/indra/llcommon/llmortician.h
index 606ac0dc39..319955ef93 100644
--- a/indra/llcommon/llmortician.h
+++ b/indra/llcommon/llmortician.h
@@ -2,30 +2,25 @@
* @file llmortician.h
* @brief Base class for delayed deletions.
*
- * $LicenseInfo:firstyear=2005&license=viewergpl$
- *
- * Copyright (c) 2005-2007, Linden Research, Inc.
- *
+ * $LicenseInfo:firstyear=2005&license=viewerlgpl$
* Second Life Viewer Source Code
- * The source code in this file ("Source Code") is provided by Linden Lab
- * to you under the terms of the GNU General Public License, version 2.0
- * ("GPL"), unless you have obtained a separate licensing agreement
- * ("Other License"), formally executed by you and Linden Lab. Terms of
- * the GPL can be found in doc/GPL-license.txt in this distribution, or
- * online at http://secondlife.com/developers/opensource/gplv2
+ * 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.
*
- * There are special exceptions to the terms and conditions of the GPL as
- * it is applied to this Source Code. View the full text of the exception
- * in the file doc/FLOSS-exception.txt in this software distribution, or
- * online at http://secondlife.com/developers/opensource/flossexception
+ * 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.
*
- * By copying, modifying or distributing this software, you acknowledge
- * that you have read and understood your obligations described above,
- * and agree to abide by those obligations.
+ * 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
*
- * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
- * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
- * COMPLETENESS OR PERFORMANCE.
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
* $/LicenseInfo$
*/
@@ -34,7 +29,7 @@
#include "stdtypes.h"
-class LLMortician
+class LL_COMMON_API LLMortician
{
public:
LLMortician() { mIsDead = FALSE; }
diff --git a/indra/llcommon/llnametable.h b/indra/llcommon/llnametable.h
index fd6f8796bd..d3283543f3 100644
--- a/indra/llcommon/llnametable.h
+++ b/indra/llcommon/llnametable.h
@@ -2,30 +2,25 @@
* @file llnametable.h
* @brief LLNameTable class is a table to associate pointers with string names
*
- * $LicenseInfo:firstyear=2000&license=viewergpl$
- *
- * Copyright (c) 2000-2007, Linden Research, Inc.
- *
+ * $LicenseInfo:firstyear=2000&license=viewerlgpl$
* Second Life Viewer Source Code
- * The source code in this file ("Source Code") is provided by Linden Lab
- * to you under the terms of the GNU General Public License, version 2.0
- * ("GPL"), unless you have obtained a separate licensing agreement
- * ("Other License"), formally executed by you and Linden Lab. Terms of
- * the GPL can be found in doc/GPL-license.txt in this distribution, or
- * online at http://secondlife.com/developers/opensource/gplv2
+ * 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.
*
- * There are special exceptions to the terms and conditions of the GPL as
- * it is applied to this Source Code. View the full text of the exception
- * in the file doc/FLOSS-exception.txt in this software distribution, or
- * online at http://secondlife.com/developers/opensource/flossexception
+ * 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.
*
- * By copying, modifying or distributing this software, you acknowledge
- * that you have read and understood your obligations described above,
- * and agree to abide by those obligations.
+ * 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
*
- * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
- * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
- * COMPLETENESS OR PERFORMANCE.
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
* $/LicenseInfo$
*/
diff --git a/indra/llcommon/lloptioninterface.cpp b/indra/llcommon/lloptioninterface.cpp
new file mode 100644
index 0000000000..23fae76dc0
--- /dev/null
+++ b/indra/llcommon/lloptioninterface.cpp
@@ -0,0 +1,33 @@
+/**
+ * @file lloptioninterface.cpp
+ * @brief
+ *
+ * $LicenseInfo:firstyear=2009&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$
+ */
+
+#include "lloptioninterface.h"
+
+
+LLOptionInterface::~LLOptionInterface()
+{
+
+}
diff --git a/indra/llcommon/lloptioninterface.h b/indra/llcommon/lloptioninterface.h
new file mode 100644
index 0000000000..93b465db32
--- /dev/null
+++ b/indra/llcommon/lloptioninterface.h
@@ -0,0 +1,40 @@
+/**
+ * @file lloptioninterface.h
+ * @brief
+ *
+ * $LicenseInfo:firstyear=2009&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$
+ */
+
+#ifndef LL_LLOPTIONINTERFACE_H
+#define LL_LLOPTIONINTERFACE_H
+
+#include "linden_common.h"
+
+class LLSD;
+class LLOptionInterface
+{
+public:
+ virtual ~LLOptionInterface() = 0;
+ virtual LLSD getOption(const std::string& name) const = 0;
+};
+
+#endif
diff --git a/indra/llcommon/llpointer.h b/indra/llcommon/llpointer.h
new file mode 100644
index 0000000000..affa040602
--- /dev/null
+++ b/indra/llcommon/llpointer.h
@@ -0,0 +1,170 @@
+/**
+ * @file llpointer.h
+ * @brief A reference-counted pointer for objects derived from LLRefCount
+ *
+ * $LicenseInfo:firstyear=2002&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$
+ */
+#ifndef LLPOINTER_H
+#define LLPOINTER_H
+
+#include "llerror.h" // *TODO: consider eliminating this
+
+//----------------------------------------------------------------------------
+// RefCount objects should generally only be accessed by way of LLPointer<>'s
+// NOTE: LLPointer<LLFoo> x = new LLFoo(); MAY NOT BE THREAD SAFE
+// if LLFoo::LLFoo() does anything like put itself in an update queue.
+// The queue may get accessed before it gets assigned to x.
+// The correct implementation is:
+// LLPointer<LLFoo> x = new LLFoo; // constructor does not do anything interesting
+// x->instantiate(); // does stuff like place x into an update queue
+
+// see llthread.h for LLThreadSafeRefCount
+
+//----------------------------------------------------------------------------
+
+// Note: relies on Type having ref() and unref() methods
+template <class Type> class LLPointer
+{
+public:
+
+ LLPointer() :
+ mPointer(NULL)
+ {
+ }
+
+ LLPointer(Type* ptr) :
+ mPointer(ptr)
+ {
+ ref();
+ }
+
+ LLPointer(const LLPointer<Type>& ptr) :
+ mPointer(ptr.mPointer)
+ {
+ ref();
+ }
+
+ // support conversion up the type hierarchy. See Item 45 in Effective C++, 3rd Ed.
+ template<typename Subclass>
+ LLPointer(const LLPointer<Subclass>& ptr) :
+ mPointer(ptr.get())
+ {
+ ref();
+ }
+
+ ~LLPointer()
+ {
+ unref();
+ }
+
+ Type* get() const { return mPointer; }
+ const Type* operator->() const { return mPointer; }
+ Type* operator->() { return mPointer; }
+ const Type& operator*() const { return *mPointer; }
+ Type& operator*() { return *mPointer; }
+
+ operator BOOL() const { return (mPointer != NULL); }
+ operator bool() const { return (mPointer != NULL); }
+ bool operator!() const { return (mPointer == NULL); }
+ bool isNull() const { return (mPointer == NULL); }
+ bool notNull() const { return (mPointer != NULL); }
+
+ operator Type*() const { return mPointer; }
+ bool operator !=(Type* ptr) const { return (mPointer != ptr); }
+ bool operator ==(Type* ptr) const { return (mPointer == ptr); }
+ bool operator ==(const LLPointer<Type>& ptr) const { return (mPointer == ptr.mPointer); }
+ bool operator < (const LLPointer<Type>& ptr) const { return (mPointer < ptr.mPointer); }
+ bool operator > (const LLPointer<Type>& ptr) const { return (mPointer > ptr.mPointer); }
+
+ LLPointer<Type>& operator =(Type* ptr)
+ {
+ if( mPointer != ptr )
+ {
+ unref();
+ mPointer = ptr;
+ ref();
+ }
+
+ return *this;
+ }
+
+ LLPointer<Type>& operator =(const LLPointer<Type>& ptr)
+ {
+ if( mPointer != ptr.mPointer )
+ {
+ unref();
+ mPointer = ptr.mPointer;
+ ref();
+ }
+ return *this;
+ }
+
+ // support assignment up the type hierarchy. See Item 45 in Effective C++, 3rd Ed.
+ template<typename Subclass>
+ LLPointer<Type>& operator =(const LLPointer<Subclass>& ptr)
+ {
+ if( mPointer != ptr.get() )
+ {
+ unref();
+ mPointer = ptr.get();
+ ref();
+ }
+ return *this;
+ }
+
+ // Just exchange the pointers, which will not change the reference counts.
+ static void swap(LLPointer<Type>& a, LLPointer<Type>& b)
+ {
+ Type* temp = a.mPointer;
+ a.mPointer = b.mPointer;
+ b.mPointer = temp;
+ }
+
+protected:
+ void ref()
+ {
+ if (mPointer)
+ {
+ mPointer->ref();
+ }
+ }
+
+ void unref()
+ {
+ if (mPointer)
+ {
+ Type *tempp = mPointer;
+ mPointer = NULL;
+ tempp->unref();
+ if (mPointer != NULL)
+ {
+ llwarns << "Unreference did assignment to non-NULL because of destructor" << llendl;
+ unref();
+ }
+ }
+ }
+
+protected:
+ Type* mPointer;
+};
+
+#endif
diff --git a/indra/llcommon/llpreprocessor.h b/indra/llcommon/llpreprocessor.h
index ac06b431c1..17a4287538 100644
--- a/indra/llcommon/llpreprocessor.h
+++ b/indra/llcommon/llpreprocessor.h
@@ -3,30 +3,25 @@
* @brief This file should be included in all Linden Lab files and
* should only contain special preprocessor directives
*
- * $LicenseInfo:firstyear=2001&license=viewergpl$
- *
- * Copyright (c) 2001-2007, Linden Research, Inc.
- *
+ * $LicenseInfo:firstyear=2001&license=viewerlgpl$
* Second Life Viewer Source Code
- * The source code in this file ("Source Code") is provided by Linden Lab
- * to you under the terms of the GNU General Public License, version 2.0
- * ("GPL"), unless you have obtained a separate licensing agreement
- * ("Other License"), formally executed by you and Linden Lab. Terms of
- * the GPL can be found in doc/GPL-license.txt in this distribution, or
- * online at http://secondlife.com/developers/opensource/gplv2
+ * 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.
*
- * There are special exceptions to the terms and conditions of the GPL as
- * it is applied to this Source Code. View the full text of the exception
- * in the file doc/FLOSS-exception.txt in this software distribution, or
- * online at http://secondlife.com/developers/opensource/flossexception
+ * 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.
*
- * By copying, modifying or distributing this software, you acknowledge
- * that you have read and understood your obligations described above,
- * and agree to abide by those obligations.
+ * 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
*
- * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
- * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
- * COMPLETENESS OR PERFORMANCE.
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
* $/LicenseInfo$
*/
@@ -39,19 +34,43 @@
#include <endian.h>
#endif // LL_LINUX
-#if (defined(LL_WINDOWS) || (defined(LL_LINUX) && (__BYTE_ORDER == __LITTLE_ENDIAN)) || (defined(LL_DARWIN) && defined(__LITTLE_ENDIAN__)))
+#if LL_SOLARIS
+# ifdef __sparc // Since we're talking Solaris 10 and up, only 64 bit is supported.
+# define LL_BIG_ENDIAN 1
+# define LL_SOLARIS_ALIGNED_CPU 1 // used to designate issues where SPARC alignment is addressed
+# define LL_SOLARIS_NON_MESA_GL 1 // The SPARC GL does not provide a MESA-based GL API
+# endif
+# include <sys/isa_defs.h> // ensure we know which end is up
+#endif // LL_SOLARIS
+
+#if (defined(LL_WINDOWS) || (defined(LL_LINUX) && (__BYTE_ORDER == __LITTLE_ENDIAN)) || (defined(LL_DARWIN) && defined(__LITTLE_ENDIAN__)) || (defined(LL_SOLARIS) && defined(__i386)))
#define LL_LITTLE_ENDIAN 1
#else
#define LL_BIG_ENDIAN 1
#endif
+
// Per-compiler switches
+
#ifdef __GNUC__
#define LL_FORCE_INLINE inline __attribute__((always_inline))
#else
#define LL_FORCE_INLINE __forceinline
#endif
+// Mark-up expressions with branch prediction hints. Do NOT use
+// this with reckless abandon - it's an obfuscating micro-optimization
+// outside of inner loops or other places where you are OVERWHELMINGLY
+// sure which way an expression almost-always evaluates.
+#if __GNUC__ >= 3
+# define LL_LIKELY(EXPR) __builtin_expect (!!(EXPR), true)
+# define LL_UNLIKELY(EXPR) __builtin_expect (!!(EXPR), false)
+#else
+# define LL_LIKELY(EXPR) (EXPR)
+# define LL_UNLIKELY(EXPR) (EXPR)
+#endif
+
+
// Figure out differences between compilers
#if defined(__GNUC__)
#define GCC_VERSION (__GNUC__ * 10000 \
@@ -64,6 +83,9 @@
#ifndef LL_MSVC
#define LL_MSVC 1
#endif
+ #if _MSC_VER < 1400
+ #define LL_MSVC7 //Visual C++ 2003 or earlier
+ #endif
#endif
// Deal with minor differences on Unixy OSes.
@@ -79,13 +101,9 @@
#endif
-// Deal with the differeneces on Windows
-#if LL_MSVC
-#define snprintf safe_snprintf /* Flawfinder: ignore */
-#endif // LL_MSVC
// Static linking with apr on windows needs to be declared.
-#ifdef LL_WINDOWS
+#if LL_WINDOWS && !LL_COMMON_LINK_SHARED
#ifndef APR_DECLARE_STATIC
#define APR_DECLARE_STATIC // For APR on Windows
#endif
@@ -97,9 +115,9 @@
#if defined(LL_WINDOWS)
#define BOOST_REGEX_NO_LIB 1
#define CURL_STATICLIB 1
-
-#define LL_LCD_COMPILE 1
-
+#ifndef XML_STATIC
+#define XML_STATIC
+#endif
#endif // LL_WINDOWS
@@ -109,12 +127,56 @@
#pragma warning( 3 : 4702 ) // "unreachable code" Treat this as level 3, not level 4.
#pragma warning( 3 : 4189 ) // "local variable initialized but not referenced" Treat this as level 3, not level 4.
//#pragma warning( 3 : 4018 ) // "signed/unsigned mismatch" Treat this as level 3, not level 4.
+#pragma warning( 3 : 4263 ) // 'function' : member function does not override any base class virtual member function
+#pragma warning( 3 : 4264 ) // "'virtual_function' : no override available for virtual member function from base 'class'; function is hidden"
#pragma warning( 3 : 4265 ) // "class has virtual functions, but destructor is not virtual"
-#pragma warning( disable : 4786 ) // silly MS warning deep inside their <map> include file
+#pragma warning( 3 : 4266 ) // 'function' : no override available for virtual member function from base 'type'; function is hidden
+#pragma warning (disable : 4180) // qualifier applied to function type has no meaning; ignored
#pragma warning( disable : 4284 ) // silly MS warning deep inside their <map> include file
#pragma warning( disable : 4503 ) // 'decorated name length exceeded, name was truncated'. Does not seem to affect compilation.
#pragma warning( disable : 4800 ) // 'BOOL' : forcing value to bool 'true' or 'false' (performance warning)
#pragma warning( disable : 4996 ) // warning: deprecated
+
+// Linker optimization with "extern template" generates these warnings
+#pragma warning( disable : 4231 ) // nonstandard extension used : 'extern' before template explicit instantiation
+#pragma warning( disable : 4506 ) // no definition for inline function
+
+// level 4 warnings that we need to disable:
+#pragma warning (disable : 4100) // unreferenced formal parameter
+#pragma warning (disable : 4127) // conditional expression is constant (e.g. while(1) )
+#pragma warning (disable : 4244) // possible loss of data on conversions
+#pragma warning (disable : 4396) // the inline specifier cannot be used when a friend declaration refers to a specialization of a function template
+#pragma warning (disable : 4512) // assignment operator could not be generated
+#pragma warning (disable : 4706) // assignment within conditional (even if((x = y)) )
+
+#pragma warning (disable : 4251) // member needs to have dll-interface to be used by clients of class
+#pragma warning (disable : 4275) // non dll-interface class used as base for dll-interface class
#endif // LL_MSVC
+#if LL_WINDOWS
+#define LL_DLLEXPORT __declspec(dllexport)
+#define LL_DLLIMPORT __declspec(dllimport)
+#elif LL_LINUX
+#define LL_DLLEXPORT __attribute__ ((visibility("default")))
+#define LL_DLLIMPORT
+#else
+#define LL_DLLEXPORT
+#define LL_DLLIMPORT
+#endif // LL_WINDOWS
+
+#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
diff --git a/indra/llcommon/llpriqueuemap.h b/indra/llcommon/llpriqueuemap.h
index 96da9351fe..da997c7b04 100644
--- a/indra/llcommon/llpriqueuemap.h
+++ b/indra/llcommon/llpriqueuemap.h
@@ -2,30 +2,25 @@
* @file llpriqueuemap.h
* @brief Priority queue implementation
*
- * $LicenseInfo:firstyear=2003&license=viewergpl$
- *
- * Copyright (c) 2003-2007, Linden Research, Inc.
- *
+ * $LicenseInfo:firstyear=2003&license=viewerlgpl$
* Second Life Viewer Source Code
- * The source code in this file ("Source Code") is provided by Linden Lab
- * to you under the terms of the GNU General Public License, version 2.0
- * ("GPL"), unless you have obtained a separate licensing agreement
- * ("Other License"), formally executed by you and Linden Lab. Terms of
- * the GPL can be found in doc/GPL-license.txt in this distribution, or
- * online at http://secondlife.com/developers/opensource/gplv2
+ * 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.
*
- * There are special exceptions to the terms and conditions of the GPL as
- * it is applied to this Source Code. View the full text of the exception
- * in the file doc/FLOSS-exception.txt in this software distribution, or
- * online at http://secondlife.com/developers/opensource/flossexception
+ * 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.
*
- * By copying, modifying or distributing this software, you acknowledge
- * that you have read and understood your obligations described above,
- * and agree to abide by those obligations.
+ * 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
*
- * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
- * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
- * COMPLETENESS OR PERFORMANCE.
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
* $/LicenseInfo$
*/
#ifndef LL_LLPRIQUEUEMAP_H
diff --git a/indra/llcommon/llprocesslauncher.cpp b/indra/llcommon/llprocesslauncher.cpp
new file mode 100644
index 0000000000..99308c94e7
--- /dev/null
+++ b/indra/llcommon/llprocesslauncher.cpp
@@ -0,0 +1,339 @@
+/**
+ * @file llprocesslauncher.cpp
+ * @brief Utility class for launching, terminating, and tracking the state of processes.
+ *
+ * $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$
+ */
+
+#include "linden_common.h"
+
+#include "llprocesslauncher.h"
+
+#include <iostream>
+#if LL_DARWIN || LL_LINUX
+// not required or present on Win32
+#include <sys/wait.h>
+#endif
+
+LLProcessLauncher::LLProcessLauncher()
+{
+#if LL_WINDOWS
+ mProcessHandle = 0;
+#else
+ mProcessID = 0;
+#endif
+}
+
+LLProcessLauncher::~LLProcessLauncher()
+{
+ kill();
+}
+
+void LLProcessLauncher::setExecutable(const std::string &executable)
+{
+ mExecutable = executable;
+}
+
+void LLProcessLauncher::setWorkingDirectory(const std::string &dir)
+{
+ mWorkingDir = dir;
+}
+
+void LLProcessLauncher::clearArguments()
+{
+ mLaunchArguments.clear();
+}
+
+void LLProcessLauncher::addArgument(const std::string &arg)
+{
+ mLaunchArguments.push_back(arg);
+}
+
+void LLProcessLauncher::addArgument(const char *arg)
+{
+ mLaunchArguments.push_back(std::string(arg));
+}
+
+#if LL_WINDOWS
+
+int LLProcessLauncher::launch(void)
+{
+ // If there was already a process associated with this object, kill it.
+ kill();
+ orphan();
+
+ int result = 0;
+
+ PROCESS_INFORMATION pinfo;
+ STARTUPINFOA sinfo;
+ memset(&sinfo, 0, sizeof(sinfo));
+
+ std::string args = mExecutable;
+ for(int i = 0; i < (int)mLaunchArguments.size(); i++)
+ {
+ args += " ";
+ args += mLaunchArguments[i];
+ }
+
+ // So retarded. Windows requires that the second parameter to CreateProcessA be a writable (non-const) string...
+ char *args2 = new char[args.size() + 1];
+ strcpy(args2, args.c_str());
+
+ if( ! CreateProcessA( NULL, args2, NULL, NULL, FALSE, 0, NULL, NULL, &sinfo, &pinfo ) )
+ {
+ // TODO: do better than returning the OS-specific error code on failure...
+ result = GetLastError();
+ if(result == 0)
+ {
+ // Make absolutely certain we return a non-zero value on failure.
+ result = -1;
+ }
+ }
+ else
+ {
+ // foo = pinfo.dwProcessId; // get your pid here if you want to use it later on
+ // CloseHandle(pinfo.hProcess); // stops leaks - nothing else
+ mProcessHandle = pinfo.hProcess;
+ CloseHandle(pinfo.hThread); // stops leaks - nothing else
+ }
+
+ delete[] args2;
+
+ return result;
+}
+
+bool LLProcessLauncher::isRunning(void)
+{
+ if(mProcessHandle != 0)
+ {
+ DWORD waitresult = WaitForSingleObject(mProcessHandle, 0);
+ if(waitresult == WAIT_OBJECT_0)
+ {
+ // the process has completed.
+ mProcessHandle = 0;
+ }
+ }
+
+ return (mProcessHandle != 0);
+}
+bool LLProcessLauncher::kill(void)
+{
+ bool result = true;
+
+ if(mProcessHandle != 0)
+ {
+ TerminateProcess(mProcessHandle,0);
+
+ if(isRunning())
+ {
+ result = false;
+ }
+ }
+
+ return result;
+}
+
+void LLProcessLauncher::orphan(void)
+{
+ // Forget about the process
+ mProcessHandle = 0;
+}
+
+// static
+void LLProcessLauncher::reap(void)
+{
+ // No actions necessary on Windows.
+}
+
+#else // Mac and linux
+
+#include <signal.h>
+#include <fcntl.h>
+#include <errno.h>
+
+static std::list<pid_t> sZombies;
+
+// Attempt to reap a process ID -- returns true if the process has exited and been reaped, false otherwise.
+static bool reap_pid(pid_t pid)
+{
+ bool result = false;
+
+ pid_t wait_result = ::waitpid(pid, NULL, WNOHANG);
+ if(wait_result == pid)
+ {
+ result = true;
+ }
+ else if(wait_result == -1)
+ {
+ if(errno == ECHILD)
+ {
+ // No such process -- this may mean we're ignoring SIGCHILD.
+ result = true;
+ }
+ }
+
+ return result;
+}
+
+int LLProcessLauncher::launch(void)
+{
+ // If there was already a process associated with this object, kill it.
+ kill();
+ orphan();
+
+ int result = 0;
+ int current_wd = -1;
+
+ // create an argv vector for the child process
+ const char ** fake_argv = new const char *[mLaunchArguments.size() + 2]; // 1 for the executable path, 1 for the NULL terminator
+
+ int i = 0;
+
+ // add the executable path
+ fake_argv[i++] = mExecutable.c_str();
+
+ // and any arguments
+ for(int j=0; j < mLaunchArguments.size(); j++)
+ fake_argv[i++] = mLaunchArguments[j].c_str();
+
+ // terminate with a null pointer
+ fake_argv[i] = NULL;
+
+ if(!mWorkingDir.empty())
+ {
+ // save the current working directory
+ current_wd = ::open(".", O_RDONLY);
+
+ // and change to the one the child will be executed in
+ if (::chdir(mWorkingDir.c_str()))
+ {
+ // chdir failed
+ }
+ }
+
+ // flush all buffers before the child inherits them
+ ::fflush(NULL);
+
+ pid_t id = vfork();
+ if(id == 0)
+ {
+ // child process
+
+ ::execv(mExecutable.c_str(), (char * const *)fake_argv);
+
+ // If we reach this point, the exec failed.
+ // Use _exit() instead of exit() per the vfork man page.
+ _exit(0);
+ }
+
+ // parent process
+
+ if(current_wd >= 0)
+ {
+ // restore the previous working directory
+ if (::fchdir(current_wd))
+ {
+ // chdir failed
+ }
+ ::close(current_wd);
+ }
+
+ delete[] fake_argv;
+
+ mProcessID = id;
+
+ // At this point, the child process will have been created (since that's how vfork works -- the child borrowed our execution context until it forked)
+ // If the process doesn't exist at this point, the exec failed.
+ if(!isRunning())
+ {
+ result = -1;
+ }
+
+ return result;
+}
+
+bool LLProcessLauncher::isRunning(void)
+{
+ if(mProcessID != 0)
+ {
+ // Check whether the process has exited, and reap it if it has.
+ if(reap_pid(mProcessID))
+ {
+ // the process has exited.
+ mProcessID = 0;
+ }
+ }
+
+ return (mProcessID != 0);
+}
+
+bool LLProcessLauncher::kill(void)
+{
+ bool result = true;
+
+ if(mProcessID != 0)
+ {
+ // Try to kill the process. We'll do approximately the same thing whether the kill returns an error or not, so we ignore the result.
+ (void)::kill(mProcessID, SIGTERM);
+
+ // This will have the side-effect of reaping the zombie if the process has exited.
+ if(isRunning())
+ {
+ result = false;
+ }
+ }
+
+ return result;
+}
+
+void LLProcessLauncher::orphan(void)
+{
+ // Disassociate the process from this object
+ if(mProcessID != 0)
+ {
+ // We may still need to reap the process's zombie eventually
+ sZombies.push_back(mProcessID);
+
+ mProcessID = 0;
+ }
+}
+
+// static
+void LLProcessLauncher::reap(void)
+{
+ // Attempt to real all saved process ID's.
+
+ std::list<pid_t>::iterator iter = sZombies.begin();
+ while(iter != sZombies.end())
+ {
+ if(reap_pid(*iter))
+ {
+ iter = sZombies.erase(iter);
+ }
+ else
+ {
+ iter++;
+ }
+ }
+}
+
+#endif
diff --git a/indra/llcommon/llprocesslauncher.h b/indra/llcommon/llprocesslauncher.h
new file mode 100644
index 0000000000..479aeb664a
--- /dev/null
+++ b/indra/llcommon/llprocesslauncher.h
@@ -0,0 +1,88 @@
+/**
+ * @file llprocesslauncher.h
+ * @brief Utility class for launching, terminating, and tracking the state of processes.
+ *
+ * $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$
+ */
+
+#ifndef LL_LLPROCESSLAUNCHER_H
+#define LL_LLPROCESSLAUNCHER_H
+
+#if LL_WINDOWS
+#include <windows.h>
+#endif
+
+
+/*
+ LLProcessLauncher handles launching external processes with specified command line arguments.
+ It also keeps track of whether the process is still running, and can kill it if required.
+*/
+
+class LL_COMMON_API LLProcessLauncher
+{
+ LOG_CLASS(LLProcessLauncher);
+public:
+ LLProcessLauncher();
+ virtual ~LLProcessLauncher();
+
+ void setExecutable(const std::string &executable);
+ void setWorkingDirectory(const std::string &dir);
+
+ void clearArguments();
+ void addArgument(const std::string &arg);
+ void addArgument(const char *arg);
+
+ int launch(void);
+ bool isRunning(void);
+
+ // Attempt to kill the process -- returns true if the process is no longer running when it returns.
+ // Note that even if this returns false, the process may exit some time after it's called.
+ bool kill(void);
+
+ // Use this if you want the external process to continue execution after the LLProcessLauncher instance controlling it is deleted.
+ // Normally, the destructor will attempt to kill the process and wait for termination.
+ // This should only be used if the viewer is about to exit -- otherwise, the child process will become a zombie after it exits.
+ void orphan(void);
+
+ // This needs to be called periodically on Mac/Linux to clean up zombie processes.
+ static void reap(void);
+
+ // Accessors for platform-specific process ID
+#if LL_WINDOWS
+ HANDLE getProcessHandle() { return mProcessHandle; };
+#else
+ pid_t getProcessID() { return mProcessID; };
+#endif
+
+private:
+ std::string mExecutable;
+ std::string mWorkingDir;
+ std::vector<std::string> mLaunchArguments;
+
+#if LL_WINDOWS
+ HANDLE mProcessHandle;
+#else
+ pid_t mProcessID;
+#endif
+};
+
+#endif // LL_LLPROCESSLAUNCHER_H
diff --git a/indra/llcommon/llprocessor.cpp b/indra/llcommon/llprocessor.cpp
index 4977ead91c..fd8f603d21 100644
--- a/indra/llcommon/llprocessor.cpp
+++ b/indra/llcommon/llprocessor.cpp
@@ -2,157 +2,411 @@
* @file llprocessor.cpp
* @brief Code to figure out the processor. Originally by Benjamin Jurke.
*
- * $LicenseInfo:firstyear=2002&license=viewergpl$
- *
- * Copyright (c) 2002-2007, Linden Research, Inc.
- *
+ * $LicenseInfo:firstyear=2002&license=viewerlgpl$
* Second Life Viewer Source Code
- * The source code in this file ("Source Code") is provided by Linden Lab
- * to you under the terms of the GNU General Public License, version 2.0
- * ("GPL"), unless you have obtained a separate licensing agreement
- * ("Other License"), formally executed by you and Linden Lab. Terms of
- * the GPL can be found in doc/GPL-license.txt in this distribution, or
- * online at http://secondlife.com/developers/opensource/gplv2
+ * Copyright (C) 2010, Linden Research, Inc.
*
- * There are special exceptions to the terms and conditions of the GPL as
- * it is applied to this Source Code. View the full text of the exception
- * in the file doc/FLOSS-exception.txt in this software distribution, or
- * online at http://secondlife.com/developers/opensource/flossexception
+ * 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.
*
- * By copying, modifying or distributing this software, you acknowledge
- * that you have read and understood your obligations described above,
- * and agree to abide by those obligations.
+ * 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.
*
- * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
- * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
- * COMPLETENESS OR PERFORMANCE.
+ * 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$
*/
-// Filename: Processor.cpp
-// =======================
-// Author: Benjamin Jurke
-// File history: 27.02.2002 - File created. Support for Intel and AMD processors
-// 05.03.2002 - Fixed the CPUID bug: On Pre-Pentium CPUs the CPUID
-// command is not available
-// - The CProcessor::WriteInfoTextFile function do not
-// longer use Win32 file functions (-> os independend)
-// - Optional include of the windows.h header which is
-// still need for CProcessor::GetCPUFrequency.
-// 06.03.2002 - My birthday (18th :-))
-// - Replaced the '\r\n' line endings in function
-// CProcessor::CPUInfoToText by '\n'
-// - Replaced unsigned __int64 by signed __int64 for
-// solving some compiler conversion problems
-// - Fixed a bug at family=6, model=6 (Celeron -> P2)
-//////////////////////////////////////////////////////////////////////////////////
-
#include "linden_common.h"
+#include "llprocessor.h"
-#include "processor.h"
+#include "llerror.h"
-#include <memory>
+//#include <memory>
#if LL_WINDOWS
# define WIN32_LEAN_AND_MEAN
# include <winsock2.h>
# include <windows.h>
+# define _interlockedbittestandset _renamed_interlockedbittestandset
+# define _interlockedbittestandreset _renamed_interlockedbittestandreset
+# include <intrin.h>
+# undef _interlockedbittestandset
+# undef _interlockedbittestandreset
#endif
-#if !LL_DARWIN && !LL_SOLARIS
-
-#ifdef PROCESSOR_FREQUENCY_MEASURE_AVAILABLE
-// We need the QueryPerformanceCounter and Sleep functions
-#define FORCEINLINE __forceinline
-#else
-#define FORCEINLINE
+#include "llsd.h"
+
+#if LL_MSVC && _M_X64
+# define LL_X86_64 1
+# define LL_X86 1
+#elif LL_MSVC && _M_IX86
+# define LL_X86 1
+#elif LL_GNUC && ( defined(__amd64__) || defined(__x86_64__) )
+# define LL_X86_64 1
+# define LL_X86 1
+#elif LL_GNUC && ( defined(__i386__) )
+# define LL_X86 1
+#elif LL_GNUC && ( defined(__powerpc__) || defined(__ppc__) )
+# define LL_PPC 1
#endif
+class LLProcessorInfoImpl; // foward declaration for the mImpl;
+
+namespace
+{
+ enum cpu_info
+ {
+ eBrandName = 0,
+ eFrequency,
+ eVendor,
+ eStepping,
+ eFamily,
+ eExtendedFamily,
+ eModel,
+ eExtendedModel,
+ eType,
+ eBrandID,
+ eFamilyName
+ };
+
+
+ const char* cpu_info_names[] =
+ {
+ "Processor Name",
+ "Frequency",
+ "Vendor",
+ "Stepping",
+ "Family",
+ "Extended Family",
+ "Model",
+ "Extended Model",
+ "Type",
+ "Brand ID",
+ "Family Name"
+ };
+
+ enum cpu_config
+ {
+ eMaxID,
+ eMaxExtID,
+ eCLFLUSHCacheLineSize,
+ eAPICPhysicalID,
+ eCacheLineSize,
+ eL2Associativity,
+ eCacheSizeK,
+ eFeatureBits,
+ eExtFeatureBits
+ };
+
+ const char* cpu_config_names[] =
+ {
+ "Max Supported CPUID level",
+ "Max Supported Ext. CPUID level",
+ "CLFLUSH cache line size",
+ "APIC Physical ID",
+ "Cache Line Size",
+ "L2 Associativity",
+ "Cache Size",
+ "Feature Bits",
+ "Ext. Feature Bits"
+ };
+
+
+
+ // *NOTE:Mani - this contains the elements we reference directly and extensions beyond the first 32.
+ // The rest of the names are referenced by bit maks returned from cpuid.
+ enum cpu_features
+ {
+ eSSE_Ext=25,
+ eSSE2_Ext=26,
+
+ eSSE3_Features=32,
+ eMONTIOR_MWAIT=33,
+ eCPLDebugStore=34,
+ eThermalMonitor2=35,
+ eAltivec=36
+ };
+
+ const char* cpu_feature_names[] =
+ {
+ "x87 FPU On Chip",
+ "Virtual-8086 Mode Enhancement",
+ "Debugging Extensions",
+ "Page Size Extensions",
+ "Time Stamp Counter",
+ "RDMSR and WRMSR Support",
+ "Physical Address Extensions",
+ "Machine Check Exception",
+ "CMPXCHG8B Instruction",
+ "APIC On Chip",
+ "Unknown1",
+ "SYSENTER and SYSEXIT",
+ "Memory Type Range Registers",
+ "PTE Global Bit",
+ "Machine Check Architecture",
+ "Conditional Move/Compare Instruction",
+ "Page Attribute Table",
+ "Page Size Extension",
+ "Processor Serial Number",
+ "CFLUSH Extension",
+ "Unknown2",
+ "Debug Store",
+ "Thermal Monitor and Clock Ctrl",
+ "MMX Technology",
+ "FXSAVE/FXRSTOR",
+ "SSE Extensions",
+ "SSE2 Extensions",
+ "Self Snoop",
+ "Hyper-threading Technology",
+ "Thermal Monitor",
+ "Unknown4",
+ "Pend. Brk. EN.", // 31 End of FeatureInfo bits
+
+ "SSE3 New Instructions", // 32
+ "MONITOR/MWAIT",
+ "CPL Qualified Debug Store",
+ "Thermal Monitor 2",
+
+ "Altivec"
+ };
+
+ std::string intel_CPUFamilyName(int composed_family)
+ {
+ switch(composed_family)
+ {
+ case 3: return "Intel i386";
+ case 4: return "Intel i486";
+ case 5: return "Intel Pentium";
+ case 6: return "Intel Pentium Pro/2/3, Core";
+ case 7: return "Intel Itanium (IA-64)";
+ case 0xF: return "Intel Pentium 4";
+ case 0x10: return "Intel Itanium 2 (IA-64)";
+ }
+ return "Unknown";
+ }
+
+ std::string amd_CPUFamilyName(int composed_family)
+ {
+ switch(composed_family)
+ {
+ case 4: return "AMD 80486/5x86";
+ case 5: return "AMD K5/K6";
+ case 6: return "AMD K7";
+ case 0xF: return "AMD K8";
+ case 0x10: return "AMD K8L";
+ }
+ return "Unknown";
+ }
+
+ std::string compute_CPUFamilyName(const char* cpu_vendor, int composed_family)
+ {
+ const char* intel_string = "GenuineIntel";
+ const char* amd_string = "AuthenticAMD";
+ if(!strncmp(cpu_vendor, intel_string, strlen(intel_string)))
+ {
+ return intel_CPUFamilyName(composed_family);
+ }
+ else if(!strncmp(cpu_vendor, amd_string, strlen(amd_string)))
+ {
+ return amd_CPUFamilyName(composed_family);
+ }
+ return "Unknown";
+ }
+
+ std::string compute_CPUFamilyName(const char* cpu_vendor, int family, int ext_family)
+ {
+ const char* intel_string = "GenuineIntel";
+ const char* amd_string = "AuthenticAMD";
+ if(!strncmp(cpu_vendor, intel_string, strlen(intel_string)))
+ {
+ U32 composed_family = family + ext_family;
+ return intel_CPUFamilyName(composed_family);
+ }
+ else if(!strncmp(cpu_vendor, amd_string, strlen(amd_string)))
+ {
+ U32 composed_family = (family == 0xF)
+ ? family + ext_family
+ : family;
+ return amd_CPUFamilyName(composed_family);
+ }
+ return "Unknown";
+ }
+
+} // end unnamed namespace
+
+// The base class for implementations.
+// Each platform should override this class.
+class LLProcessorInfoImpl
+{
+public:
+ LLProcessorInfoImpl()
+ {
+ mProcessorInfo["info"] = LLSD::emptyMap();
+ mProcessorInfo["config"] = LLSD::emptyMap();
+ mProcessorInfo["extension"] = LLSD::emptyMap();
+ }
+ virtual ~LLProcessorInfoImpl() {}
+
+ F64 getCPUFrequency() const
+ {
+ return getInfo(eFrequency, 0).asReal();
+ }
+
+ bool hasSSE() const
+ {
+ return hasExtension(cpu_feature_names[eSSE_Ext]);
+ }
+
+ bool hasSSE2() const
+ {
+ return hasExtension(cpu_feature_names[eSSE2_Ext]);
+ }
+
+ bool hasAltivec() const
+ {
+ return hasExtension("Altivec");
+ }
+
+ std::string getCPUFamilyName() const { return getInfo(eFamilyName, "Unknown").asString(); }
+ std::string getCPUBrandName() const { return getInfo(eBrandName, "Unknown").asString(); }
+
+ // This is virtual to support a different linux format.
+ // *NOTE:Mani - I didn't want to screw up server use of this data...
+ virtual std::string getCPUFeatureDescription() const
+ {
+ std::ostringstream out;
+ out << std::endl << std::endl;
+ out << "// CPU General Information" << std::endl;
+ out << "//////////////////////////" << std::endl;
+ out << "Processor Name: " << getCPUBrandName() << std::endl;
+ out << "Frequency: " << getCPUFrequency() << " MHz" << std::endl;
+ out << "Vendor: " << getInfo(eVendor, "Unknown").asString() << std::endl;
+ out << "Family: " << getCPUFamilyName() << " (" << getInfo(eFamily, 0) << ")" << std::endl;
+ out << "Extended family: " << getInfo(eExtendedFamily, 0) << std::endl;
+ out << "Model: " << getInfo(eModel, 0) << std::endl;
+ out << "Extended model: " << getInfo(eExtendedModel, 0) << std::endl;
+ out << "Type: " << getInfo(eType, 0) << std::endl;
+ out << "Brand ID: " << getInfo(eBrandID, 0) << std::endl;
+ out << std::endl;
+ out << "// CPU Configuration" << std::endl;
+ out << "//////////////////////////" << std::endl;
+
+ // Iterate through the dictionary of configuration options.
+ LLSD configs = mProcessorInfo["config"];
+ for(LLSD::map_const_iterator cfgItr = configs.beginMap(); cfgItr != configs.endMap(); ++cfgItr)
+ {
+ out << cfgItr->first << " = " << cfgItr->second << std::endl;
+ }
+ out << std::endl;
+
+ out << "// CPU Extensions" << std::endl;
+ out << "//////////////////////////" << std::endl;
+
+ for(LLSD::map_const_iterator itr = mProcessorInfo["extension"].beginMap(); itr != mProcessorInfo["extension"].endMap(); ++itr)
+ {
+ out << " " << itr->first << std::endl;
+ }
+ return out.str();
+ }
+
+protected:
+ void setInfo(cpu_info info_type, const LLSD& value)
+ {
+ setInfo(cpu_info_names[info_type], value);
+ }
+ LLSD getInfo(cpu_info info_type, const LLSD& defaultVal) const
+ {
+ return getInfo(cpu_info_names[info_type], defaultVal);
+ }
+
+ void setConfig(cpu_config config_type, const LLSD& value)
+ {
+ setConfig(cpu_config_names[config_type], value);
+ }
+ LLSD getConfig(cpu_config config_type, const LLSD& defaultVal) const
+ {
+ return getConfig(cpu_config_names[config_type], defaultVal);
+ }
+
+ void setExtension(const std::string& name) { mProcessorInfo["extension"][name] = "true"; }
+ bool hasExtension(const std::string& name) const
+ {
+ return mProcessorInfo["extension"].has(name);
+ }
+
+private:
+ void setInfo(const std::string& name, const LLSD& value) { mProcessorInfo["info"][name]=value; }
+ LLSD getInfo(const std::string& name, const LLSD& defaultVal) const
+ {
+ if(mProcessorInfo["info"].has(name))
+ {
+ return mProcessorInfo["info"][name];
+ }
+ return defaultVal;
+ }
+ void setConfig(const std::string& name, const LLSD& value) { mProcessorInfo["config"][name]=value; }
+ LLSD getConfig(const std::string& name, const LLSD& defaultVal) const
+ {
+ LLSD r = mProcessorInfo["config"].get(name);
+ return r.isDefined() ? r : defaultVal;
+ }
+
+private:
+
+ LLSD mProcessorInfo;
+};
+
-// Some macros we often need
-////////////////////////////
-#define CheckBit(var, bit) ((var & (1 << bit)) ? true : false)
+#ifdef LL_MSVC
+// LL_MSVC and not LLWINDOWS because some of the following code
+// uses the MSVC compiler intrinsics __cpuid() and __rdtsc().
-#ifdef PROCESSOR_FREQUENCY_MEASURE_AVAILABLE
// Delays for the specified amount of milliseconds
-static void _Delay(unsigned int ms)
+static void _Delay(unsigned int ms)
{
- LARGE_INTEGER freq, c1, c2;
- __int64 x;
+ LARGE_INTEGER freq, c1, c2;
+ __int64 x;
- // Get High-Res Timer frequency
+ // Get High-Res Timer frequency
if (!QueryPerformanceFrequency(&freq))
return;
-
+
// Convert ms to High-Res Timer value
x = freq.QuadPart/1000*ms;
- // Get first snapshot of High-Res Timer value
+ // Get first snapshot of High-Res Timer value
QueryPerformanceCounter(&c1);
do
{
- // Get second snapshot
- QueryPerformanceCounter(&c2);
+ // Get second snapshot
+ QueryPerformanceCounter(&c2);
}while(c2.QuadPart-c1.QuadPart < x);
// Loop while (second-first < x)
}
-#endif
-// CProcessor::CProcessor
-// ======================
-// Class constructor:
-/////////////////////////
-CProcessor::CProcessor()
+static F64 calculate_cpu_frequency(U32 measure_msecs)
{
- uqwFrequency = 0;
- strCPUName[0] = 0;
- memset(&CPUInfo, 0, sizeof(CPUInfo));
-}
-
-// unsigned __int64 CProcessor::GetCPUFrequency(unsigned int uiMeasureMSecs)
-// =========================================================================
-// Function to measure the current CPU frequency
-////////////////////////////////////////////////////////////////////////////
-F64 CProcessor::GetCPUFrequency(unsigned int uiMeasureMSecs)
-{
-#ifndef PROCESSOR_FREQUENCY_MEASURE_AVAILABLE
- return 0;
-#else
- // If there are invalid measure time parameters, zero msecs for example,
- // we've to exit the function
- if (uiMeasureMSecs < 1)
+ if(measure_msecs == 0)
{
- // If theres already a measured frequency available, we return it
- if (uqwFrequency > 0)
- return uqwFrequency;
- else
- return 0;
- }
-
- // Now we check if the CPUID command is available
- if (!CheckCPUIDPresence())
return 0;
-
- // First we get the CPUID standard level 0x00000001
- unsigned long reg;
- __asm
- {
- mov eax, 1
- cpuid
- mov reg, edx
}
- // Then we check, if the RDTSC (Real Date Time Stamp Counter) is available.
- // This function is necessary for our measure process.
- if (!(reg & (1 << 4)))
- return 0;
-
// After that we declare some vars and check the frequency of the high
// resolution timer for the measure process.
- // If there's no high-res timer, we exit.
- __int64 starttime, endtime, timedif, freq, start, end, dif;
+ // If there"s no high-res timer, we exit.
+ unsigned __int64 starttime, endtime, timedif, freq, start, end, dif;
if (!QueryPerformanceFrequency((LARGE_INTEGER *) &freq))
+ {
return 0;
+ }
// Now we can init the measure process. We set the process and thread priority
// to the highest available level (Realtime priority). Also we focus the
@@ -168,35 +422,27 @@ F64 CProcessor::GetCPUFrequency(unsigned int uiMeasureMSecs)
SetThreadPriority(hThread, THREAD_PRIORITY_TIME_CRITICAL);
SetProcessAffinityMask(hProcess, dwNewMask);
- // Now we call a CPUID to ensure, that all other prior called functions are
- // completed now (serialization)
- __asm cpuid
+ //// Now we call a CPUID to ensure, that all other prior called functions are
+ //// completed now (serialization)
+ //__asm cpuid
+ int cpu_info[4] = {-1};
+ __cpuid(cpu_info, 0);
// We ask the high-res timer for the start time
QueryPerformanceCounter((LARGE_INTEGER *) &starttime);
// Then we get the current cpu clock and store it
- __asm
- {
- rdtsc
- mov dword ptr [start+4], edx
- mov dword ptr [start], eax
- }
+ start = __rdtsc();
// Now we wart for some msecs
- _Delay(uiMeasureMSecs);
-// Sleep(uiMeasureMSecs);
+ _Delay(measure_msecs);
+ // Sleep(uiMeasureMSecs);
// We ask for the end time
QueryPerformanceCounter((LARGE_INTEGER *) &endtime);
// And also for the end cpu clock
- __asm
- {
- rdtsc
- mov dword ptr [end+4], edx
- mov dword ptr [end], eax
- }
+ end = __rdtsc();
// Now we can restore the default process and thread priorities
SetProcessAffinityMask(hProcess, dwProcessMask);
@@ -209,2039 +455,433 @@ F64 CProcessor::GetCPUFrequency(unsigned int uiMeasureMSecs)
// And finally the frequency is the clock difference divided by the time
// difference.
- uqwFrequency = (F64)dif / (((F64)timedif) / freq);
+ F64 frequency = (F64)dif / (((F64)timedif) / freq);
// At last we just return the frequency that is also stored in the call
- // member var uqwFrequency
- return uqwFrequency;
-#endif
+ // member var uqwFrequency - converted to MHz
+ return frequency / (F64)1000000;
}
-// bool CProcessor::AnalyzeIntelProcessor()
-// ========================================
-// Private class function for analyzing an Intel processor
-//////////////////////////////////////////////////////////
-bool CProcessor::AnalyzeIntelProcessor()
+// Windows implementation
+class LLProcessorInfoWindowsImpl : public LLProcessorInfoImpl
{
-#if LL_WINDOWS
- unsigned long eaxreg, ebxreg, edxreg;
-
- // First we check if the CPUID command is available
- if (!CheckCPUIDPresence())
- return false;
-
- // Now we get the CPUID standard level 0x00000001
- __asm
+public:
+ LLProcessorInfoWindowsImpl()
{
- mov eax, 1
- cpuid
- mov eaxreg, eax
- mov ebxreg, ebx
- mov edxreg, edx
+ getCPUIDInfo();
+ setInfo(eFrequency, calculate_cpu_frequency(50));
}
-
- // Then get the cpu model, family, type, stepping and brand id by masking
- // the eax and ebx register
- CPUInfo.uiStepping = eaxreg & 0xF;
- CPUInfo.uiModel = (eaxreg >> 4) & 0xF;
- CPUInfo.uiFamily = (eaxreg >> 8) & 0xF;
- CPUInfo.uiType = (eaxreg >> 12) & 0x3;
- CPUInfo.uiBrandID = ebxreg & 0xF;
-
- static const char* INTEL_BRAND[] =
- {
- /* 0x00 */ "",
- /* 0x01 */ "0.18 micron Intel Celeron",
- /* 0x02 */ "0.18 micron Intel Pentium III",
- /* 0x03 */ "0.13 micron Intel Celeron",
- /* 0x04 */ "0.13 micron Intel Pentium III",
- /* 0x05 */ "",
- /* 0x06 */ "0.13 micron Intel Pentium III Mobile",
- /* 0x07 */ "0.13 micron Intel Celeron Mobile",
- /* 0x08 */ "0.18 micron Intel Pentium 4",
- /* 0x09 */ "0.13 micron Intel Pentium 4",
- /* 0x0A */ "0.13 micron Intel Celeron",
- /* 0x0B */ "0.13 micron Intel Pentium 4 Xeon",
- /* 0x0C */ "Intel Xeon MP",
- /* 0x0D */ "",
- /* 0x0E */ "0.18 micron Intel Pentium 4 Xeon",
- /* 0x0F */ "Mobile Intel Celeron",
- /* 0x10 */ "",
- /* 0x11 */ "Mobile Genuine Intel",
- /* 0x12 */ "Intel Celeron M",
- /* 0x13 */ "Mobile Intel Celeron",
- /* 0x14 */ "Intel Celeron",
- /* 0x15 */ "Mobile Genuine Intel",
- /* 0x16 */ "Intel Pentium M",
- /* 0x17 */ "Mobile Intel Celeron",
- };
- // Only override the brand if we have it in the lookup table. We should
- // already have a string here from GetCPUInfo(). JC
- if (CPUInfo.uiBrandID < (sizeof(INTEL_BRAND)/sizeof(INTEL_BRAND[0])))
+private:
+ void getCPUIDInfo()
{
- strcpy(CPUInfo.strBrandID, INTEL_BRAND[CPUInfo.uiBrandID]);
+ // http://msdn.microsoft.com/en-us/library/hskdteyh(VS.80).aspx
+
+ // __cpuid with an InfoType argument of 0 returns the number of
+ // valid Ids in cpu_info[0] and the CPU identification string in
+ // the other three array elements. The CPU identification string is
+ // not in linear order. The code below arranges the information
+ // in a human readable form.
+ int cpu_info[4] = {-1};
+ __cpuid(cpu_info, 0);
+ unsigned int ids = (unsigned int)cpu_info[0];
+ setConfig(eMaxID, (S32)ids);
- if (CPUInfo.uiBrandID == 3 && CPUInfo.uiModel == 6)
+ char cpu_vendor[0x20];
+ memset(cpu_vendor, 0, sizeof(cpu_vendor));
+ *((int*)cpu_vendor) = cpu_info[1];
+ *((int*)(cpu_vendor+4)) = cpu_info[3];
+ *((int*)(cpu_vendor+8)) = cpu_info[2];
+ setInfo(eVendor, cpu_vendor);
+
+ // Get the information associated with each valid Id
+ for(unsigned int i=0; i<=ids; ++i)
{
- strcpy(CPUInfo.strBrandID, "0.18 micron Intel Pentium III Xeon");
- }
- }
+ __cpuid(cpu_info, i);
- // Then we translate the cpu family
- switch (CPUInfo.uiFamily)
- {
- case 3: // Family = 3: i386 (80386) processor family
- strcpy(CPUInfo.strFamily, "Intel i386"); /* Flawfinder: ignore */
- break;
- case 4: // Family = 4: i486 (80486) processor family
- strcpy(CPUInfo.strFamily, "Intel i486"); /* Flawfinder: ignore */
- break;
- case 5: // Family = 5: Pentium (80586) processor family
- strcpy(CPUInfo.strFamily, "Intel Pentium"); /* Flawfinder: ignore */
- break;
- case 6: // Family = 6: Pentium Pro (80686) processor family
- strcpy(CPUInfo.strFamily, "Intel Pentium Pro/2/3, Core"); /* Flawfinder: ignore */
- break;
- case 15: // Family = 15: Extended family specific
- // Masking the extended family
- CPUInfo.uiExtendedFamily = (eaxreg >> 20) & 0xFF;
- switch (CPUInfo.uiExtendedFamily)
+ // Interpret CPU feature information.
+ if (i == 1)
{
- case 0: // Family = 15, Ext. Family = 0: Pentium 4 (80786 ??) processor family
- strcpy(CPUInfo.strFamily, "Intel Pentium 4"); /* Flawfinder: ignore */
- break;
- case 1: // Family = 15, Ext. Family = 1: McKinley (64-bit) processor family
- strcpy(CPUInfo.strFamily, "Intel McKinley (IA-64)"); /* Flawfinder: ignore */
- break;
- default: // Sure is sure
- strcpy(CPUInfo.strFamily, "Unknown Intel Pentium 4+"); /* Flawfinder: ignore */
- break;
- }
- break;
- default: // Failsave
- strcpy(CPUInfo.strFamily, "Unknown"); /* Flawfinder: ignore */
- break;
- }
-
- // Now we come to the big deal, the exact model name
- switch (CPUInfo.uiFamily)
- {
- case 3: // i386 (80386) processor family
- strcpy(CPUInfo.strModel, "Unknown Intel i386"); /* Flawfinder: ignore */
- strncat(strCPUName, "Intel i386", sizeof(strCPUName)-strlen(strCPUName)-1); /* Flawfinder: ignore */
- break;
- case 4: // i486 (80486) processor family
- switch (CPUInfo.uiModel)
- {
- case 0: // Model = 0: i486 DX-25/33 processor model
- strcpy(CPUInfo.strModel, "Intel i486 DX-25/33"); /* Flawfinder: ignore */
- strncat(strCPUName, "Intel i486 DX-25/33", sizeof(strCPUName)-strlen(strCPUName)-1); /* Flawfinder: ignore */
- break;
- case 1: // Model = 1: i486 DX-50 processor model
- strcpy(CPUInfo.strModel, "Intel i486 DX-50"); /* Flawfinder: ignore */
- strncat(strCPUName, "Intel i486 DX-50", sizeof(strCPUName)-strlen(strCPUName)-1); /* Flawfinder: ignore */
- break;
- case 2: // Model = 2: i486 SX processor model
- strcpy(CPUInfo.strModel, "Intel i486 SX"); /* Flawfinder: ignore */
- strncat(strCPUName, "Intel i486 SX", sizeof(strCPUName)-strlen(strCPUName)-1); /* Flawfinder: ignore */
- break;
- case 3: // Model = 3: i486 DX2 (with i487 numeric coprocessor) processor model
- strcpy(CPUInfo.strModel, "Intel i486 487/DX2"); /* Flawfinder: ignore */
- strncat(strCPUName, "Intel i486 DX2 with i487 numeric coprocessor", sizeof(strCPUName)-strlen(strCPUName)-1); /* Flawfinder: ignore */
- break;
- case 4: // Model = 4: i486 SL processor model (never heard ?!?)
- strcpy(CPUInfo.strModel, "Intel i486 SL"); /* Flawfinder: ignore */
- strncat(strCPUName, "Intel i486 SL", sizeof(strCPUName)-strlen(strCPUName)-1); /* Flawfinder: ignore */
- break;
- case 5: // Model = 5: i486 SX2 processor model
- strcpy(CPUInfo.strModel, "Intel i486 SX2"); /* Flawfinder: ignore */
- strncat(strCPUName, "Intel i486 SX2", sizeof(strCPUName)-strlen(strCPUName)-1); /* Flawfinder: ignore */
- break;
- case 7: // Model = 7: i486 write-back enhanced DX2 processor model
- strcpy(CPUInfo.strModel, "Intel i486 write-back enhanced DX2"); /* Flawfinder: ignore */
- strncat(strCPUName, "Intel i486 write-back enhanced DX2", sizeof(strCPUName)-strlen(strCPUName)-1); /* Flawfinder: ignore */
- break;
- case 8: // Model = 8: i486 DX4 processor model
- strcpy(CPUInfo.strModel, "Intel i486 DX4"); /* Flawfinder: ignore */
- strncat(strCPUName, "Intel i486 DX4", sizeof(strCPUName)-strlen(strCPUName)-1); /* Flawfinder: ignore */
- break;
- case 9: // Model = 9: i486 write-back enhanced DX4 processor model
- strcpy(CPUInfo.strModel, "Intel i486 write-back enhanced DX4"); /* Flawfinder: ignore */
- strncat(strCPUName, "Intel i486 DX4", sizeof(strCPUName)-strlen(strCPUName)-1); /* Flawfinder: ignore */
- break;
- default: // ...
- strcpy(CPUInfo.strModel, "Unknown Intel i486"); /* Flawfinder: ignore */
- strncat(strCPUName, "Intel i486 (Unknown model)", sizeof(strCPUName)-strlen(strCPUName)-1); /* Flawfinder: ignore */
- break;
- }
- break;
- case 5: // Pentium (80586) processor family
- switch (CPUInfo.uiModel)
- {
- case 0: // Model = 0: Pentium (P5 A-Step) processor model
- strcpy(CPUInfo.strModel, "Intel Pentium (P5 A-Step)"); /* Flawfinder: ignore */
- strncat(strCPUName, "Intel Pentium (P5 A-Step core)", sizeof(strCPUName)-strlen(strCPUName)-1); /* Flawfinder: ignore */
- break; // Famous for the DIV bug, as far as I know
- case 1: // Model = 1: Pentium 60/66 processor model
- strcpy(CPUInfo.strModel, "Intel Pentium 60/66 (P5)"); /* Flawfinder: ignore */
- strncat(strCPUName, "Intel Pentium 60/66 (P5 core)", sizeof(strCPUName)-strlen(strCPUName)-1); /* Flawfinder: ignore */
- break;
- case 2: // Model = 2: Pentium 75-200 (P54C) processor model
- strcpy(CPUInfo.strModel, "Intel Pentium 75-200 (P54C)"); /* Flawfinder: ignore */
- strncat(strCPUName, "Intel Pentium 75-200 (P54C core)", sizeof(strCPUName)-strlen(strCPUName)-1); /* Flawfinder: ignore */
- break;
- case 3: // Model = 3: Pentium overdrive for 486 systems processor model
- strcpy(CPUInfo.strModel, "Intel Pentium for 486 system (P24T Overdrive)"); /* Flawfinder: ignore */
- strncat(strCPUName, "Intel Pentium for 486 (P24T overdrive core)", sizeof(strCPUName)-(strlen(strCPUName)-1)); /*Flawfinder: ignore*/
- break;
- case 4: // Model = 4: Pentium MMX processor model
- strcpy(CPUInfo.strModel, "Intel Pentium MMX (P55C)"); /*Flawfinder: ignore*/
- strncat(strCPUName, "Intel Pentium MMX (P55C core)", sizeof(strCPUName)-(strlen(strCPUName)-1)); /*Flawfinder: ignore*/
- break;
- case 7: // Model = 7: Pentium processor model (don't know difference to Model=2)
- strcpy(CPUInfo.strModel, "Intel Pentium (P54C)"); /*Flawfinder: ignore*/
- strncat(strCPUName, "Intel Pentium (P54C core)", sizeof(strCPUName)-(strlen(strCPUName)-1)); /*Flawfinder: ignore*/
- break;
- case 8: // Model = 8: Pentium MMX (0.25 micron) processor model
- strcpy(CPUInfo.strModel, "Intel Pentium MMX (P55C), 0.25 micron"); /*Flawfinder: ignore*/
- strncat(strCPUName, "Intel Pentium MMX (P55C core), 0.25 micron", sizeof(strCPUName)-(strlen(strCPUName)-1)); /*Flawfinder: ignore*/
- break;
- default: // ...
- strcpy(CPUInfo.strModel, "Unknown Intel Pentium"); /*Flawfinder: ignore*/
- strncat(strCPUName, "Intel Pentium (Unknown P5-model)", sizeof(strCPUName)-(strlen(strCPUName)-1)); /*Flawfinder: ignore*/
- break;
- }
- break;
- case 6: // Pentium Pro (80686) processor family
- switch (CPUInfo.uiModel)
- {
- case 0: // Model = 0: Pentium Pro (P6 A-Step) processor model
- strcpy(CPUInfo.strModel, "Intel Pentium Pro (P6 A-Step)"); /*Flawfinder: ignore*/
- strncat(strCPUName, "Intel Pentium Pro (P6 A-Step core)", sizeof(strCPUName)-(strlen(strCPUName)-1)); /*Flawfinder: ignore*/
- break;
- case 1: // Model = 1: Pentium Pro
- strcpy(CPUInfo.strModel, "Intel Pentium Pro (P6)"); /*Flawfinder: ignore*/
- strncat(strCPUName, "Intel Pentium Pro (P6 core)", sizeof(strCPUName)-(strlen(strCPUName)-1)); /*Flawfinder: ignore*/
- break;
- case 3: // Model = 3: Pentium II (66 MHz FSB, I think) processor model
- strcpy(CPUInfo.strModel, "Intel Pentium II Model 3, 0.28 micron"); /*Flawfinder: ignore*/
- strncat(strCPUName, "Intel Pentium II (Model 3 core, 0.28 micron process)", sizeof(strCPUName)-(strlen(strCPUName)-1)); /*Flawfinder: ignore*/
- break;
- case 5: // Model = 5: Pentium II/Xeon/Celeron (0.25 micron) processor model
- strcpy(CPUInfo.strModel, "Intel Pentium II Model 5/Xeon/Celeron, 0.25 micron"); /*Flawfinder: ignore*/
- strncat(strCPUName, "Intel Pentium II/Xeon/Celeron (Model 5 core, 0.25 micron process)", sizeof(strCPUName)-(strlen(strCPUName)-1)); /*Flawfinder: ignore*/
- break;
- case 6: // Model = 6: Pentium II with internal L2 cache
- strcpy(CPUInfo.strModel, "Intel Pentium II - internal L2 cache"); /*Flawfinder: ignore*/
- strncat(strCPUName, "Intel Pentium II with internal L2 cache", sizeof(strCPUName)-(strlen(strCPUName)-1)); /*Flawfinder: ignore*/
- break;
- case 7: // Model = 7: Pentium III/Xeon (extern L2 cache) processor model
- strcpy(CPUInfo.strModel, "Intel Pentium III/Pentium III Xeon - external L2 cache, 0.25 micron"); /*Flawfinder: ignore*/
- strncat(strCPUName, "Intel Pentium III/Pentium III Xeon (0.25 micron process) with external L2 cache", sizeof(strCPUName)-(strlen(strCPUName)-1)); /*Flawfinder: ignore*/
- break;
- case 8: // Model = 8: Pentium III/Xeon/Celeron (256 KB on-die L2 cache) processor model
- strcpy(CPUInfo.strModel, "Intel Pentium III/Celeron/Pentium III Xeon - internal L2 cache, 0.18 micron"); /*Flawfinder: ignore*/
- // We want to know it exactly:
- switch (CPUInfo.uiBrandID)
- {
- case 1: // Model = 8, Brand id = 1: Celeron (on-die L2 cache) processor model
- strncat(strCPUName, "Intel Celeron (0.18 micron process) with internal L2 cache", sizeof(strCPUName)-(strlen(strCPUName)-1)); /*Flawfinder: ignore*/
- break;
- case 2: // Model = 8, Brand id = 2: Pentium III (on-die L2 cache) processor model (my current cpu :-))
- strncat(strCPUName, "Intel Pentium III (0.18 micron process) with internal L2 cache", sizeof(strCPUName)-(strlen(strCPUName)-1)); /*Flawfinder: ignore*/
- break;
- case 3: // Model = 8, Brand id = 3: Pentium III Xeon (on-die L2 cache) processor model
- strncat(strCPUName, "Intel Pentium III Xeon (0.18 micron process) with internal L2 cache", sizeof(strCPUName)-(strlen(strCPUName)-1)); /*Flawfinder: ignore*/
- break;
- default: // ...
- strncat(strCPUName, "Intel Pentium III core (unknown model, 0.18 micron process) with internal L2 cache", sizeof(strCPUName)-(strlen(strCPUName)-1)); /*Flawfinder: ignore*/
- break;
- }
- break;
- case 9: // Model = 9: Intel Pentium M processor, Intel Celeron M processor, model 9
- strcpy(CPUInfo.strModel, "Intel Pentium M Series Processor"); /*Flawfinder: ignore*/
- strncat(strCPUName, "Intel Pentium M Series Processor", sizeof(strCPUName)-(strlen(strCPUName)-1)); /*Flawfinder: ignore*/
- break;
- case 0xA: // Model = 0xA: Pentium III/Xeon/Celeron (1 or 2 MB on-die L2 cache) processor model
- strcpy(CPUInfo.strModel, "Intel Pentium III/Celeron/Pentium III Xeon - internal L2 cache, 0.18 micron"); /*Flawfinder: ignore*/
- // Exact detection:
- switch (CPUInfo.uiBrandID)
- {
- case 1: // Model = 0xA, Brand id = 1: Celeron (1 or 2 MB on-die L2 cache (does it exist??)) processor model
- strncat(strCPUName, "Intel Celeron (0.18 micron process) with internal L2 cache", sizeof(strCPUName)-(strlen(strCPUName)-1)); /*Flawfinder: ignore*/
- break;
- case 2: // Model = 0xA, Brand id = 2: Pentium III (1 or 2 MB on-die L2 cache (never seen...)) processor model
- strncat(strCPUName, "Intel Pentium III (0.18 micron process) with internal L2 cache", sizeof(strCPUName)-(strlen(strCPUName)-1)); /*Flawfinder: ignore*/
- break;
- case 3: // Model = 0xA, Brand id = 3: Pentium III Xeon (1 or 2 MB on-die L2 cache) processor model
- strncat(strCPUName, "Intel Pentium III Xeon (0.18 micron process) with internal L2 cache", sizeof(strCPUName)-(strlen(strCPUName)-1)); /*Flawfinder: ignore*/
- break;
- default: // Getting bored of this............
- strncat(strCPUName, "Intel Pentium III core (unknown model, 0.18 micron process) with internal L2 cache", sizeof(strCPUName)-(strlen(strCPUName)-1)); /*Flawfinder: ignore*/
- break;
- }
- break;
- case 0xB: // Model = 0xB: Pentium III/Xeon/Celeron (Tualatin core, on-die cache) processor model
- strcpy(CPUInfo.strModel, "Intel Pentium III/Celeron/Pentium III Xeon - internal L2 cache, 0.13 micron"); /*Flawfinder: ignore*/
- // Omniscient: ;-)
- switch (CPUInfo.uiBrandID)
- {
- case 3: // Model = 0xB, Brand id = 3: Celeron (Tualatin core) processor model
- strncat(strCPUName, "Intel Celeron (Tualatin core, 0.13 micron process) with internal L2 cache", sizeof(strCPUName)-(strlen(strCPUName)-1)); /*Flawfinder: ignore*/
- break;
- case 4: // Model = 0xB, Brand id = 4: Pentium III (Tualatin core) processor model
- strncat(strCPUName, "Intel Pentium III (Tualatin core, 0.13 micron process) with internal L2 cache", sizeof(strCPUName)-(strlen(strCPUName)-1)); /*Flawfinder: ignore*/
- break;
- case 7: // Model = 0xB, Brand id = 7: Celeron mobile (Tualatin core) processor model
- strncat(strCPUName, "Intel Celeron mobile (Tualatin core, 0.13 micron process) with internal L2 cache", sizeof(strCPUName)-(strlen(strCPUName)-1)); /*Flawfinder: ignore*/
- break;
- default: // *bored*
- strncat(strCPUName, "Intel Pentium III Tualatin core (unknown model, 0.13 micron process) with internal L2 cache", sizeof(strCPUName)-(strlen(strCPUName)-1)); /*Flawfinder: ignore*/
- break;
- }
- break;
- case 0xD: // Model = 0xD: Intel Pentium M processor, Intel Celeron M processor, model D
- strcpy(CPUInfo.strModel, "Intel Pentium M Series Processor"); /*Flawfinder: ignore*/
- strncat(strCPUName, "Intel Pentium M Series Processor", sizeof(strCPUName)-(strlen(strCPUName)-1)); /*Flawfinder: ignore*/
- break;
- case 0xE: // Model = 0xE: Intel Core Duo processor, Intel Core Solo processor, model E
- strcpy(CPUInfo.strModel, "Intel Core Series Processor"); /*Flawfinder: ignore*/
- strncat(strCPUName, "Intel Core Series Processor", sizeof(strCPUName)-(strlen(strCPUName)-1)); /*Flawfinder: ignore*/
- break;
- case 0xF: // Model = 0xF: Intel Core 2 Duo processor, model F
- strcpy(CPUInfo.strModel, "Intel Core 2 Series Processor"); /*Flawfinder: ignore*/
- strncat(strCPUName, "Intel Core 2 Series Processor", sizeof(strCPUName)-(strlen(strCPUName)-1)); /*Flawfinder: ignore*/
- break;
- default: // *more bored*
- strcpy(CPUInfo.strModel, "Unknown Intel Pentium Pro/2/3, Core"); /*Flawfinder: ignore*/
- strncat(strCPUName, "Intel Pentium Pro/2/3, Core (Unknown model)", sizeof(strCPUName)-(strlen(strCPUName)-1)); /*Flawfinder: ignore*/
- break;
- }
- break;
- case 15: // Extended processor family
- // Masking the extended model
- CPUInfo.uiExtendedModel = (eaxreg >> 16) & 0xFF;
- switch (CPUInfo.uiModel)
- {
- case 0: // Model = 0: Pentium 4 Willamette (A-Step) core
- if ((CPUInfo.uiBrandID) == 8) // Brand id = 8: P4 Willamette
- {
- strcpy(CPUInfo.strModel, "Intel Pentium 4 Willamette (A-Step)"); /*Flawfinder: ignore*/
- strncat(strCPUName, "Intel Pentium 4 Willamette (A-Step)", sizeof(strCPUName)-(strlen(strCPUName)-1)); /*Flawfinder: ignore*/
- }
- else // else Xeon
- {
- strcpy(CPUInfo.strModel, "Intel Pentium 4 Willamette Xeon (A-Step)"); /* Flawfinder: ignore */
- strncat(strCPUName, "Intel Pentium 4 Willamette Xeon (A-Step)", sizeof(strCPUName) - strlen(strCPUName) - 1); /* Flawfinder: ignore */
- }
- break;
- case 1: // Model = 1: Pentium 4 Willamette core
- if ((CPUInfo.uiBrandID) == 8) // Brand id = 8: P4 Willamette
- {
- strcpy(CPUInfo.strModel, "Intel Pentium 4 Willamette"); /* Flawfinder: ignore */
- strncat(strCPUName, "Intel Pentium 4 Willamette", sizeof(strCPUName) - strlen(strCPUName) - 1); /* Flawfinder: ignore */
- }
- else // else Xeon
- {
- strcpy(CPUInfo.strModel, "Intel Pentium 4 Willamette Xeon"); /* Flawfinder: ignore */
- strncat(strCPUName, "Intel Pentium 4 Willamette Xeon", sizeof(strCPUName) - strlen(strCPUName) - 1); /* Flawfinder: ignore */
- }
- break;
- case 2: // Model = 2: Pentium 4 Northwood core
- if (((CPUInfo.uiBrandID) == 9) || ((CPUInfo.uiBrandID) == 0xA)) // P4 Willamette
+ setInfo(eStepping, cpu_info[0] & 0xf);
+ setInfo(eModel, (cpu_info[0] >> 4) & 0xf);
+ int family = (cpu_info[0] >> 8) & 0xf;
+ setInfo(eFamily, family);
+ setInfo(eType, (cpu_info[0] >> 12) & 0x3);
+ setInfo(eExtendedModel, (cpu_info[0] >> 16) & 0xf);
+ int ext_family = (cpu_info[0] >> 20) & 0xff;
+ setInfo(eExtendedFamily, ext_family);
+ setInfo(eBrandID, cpu_info[1] & 0xff);
+
+ setInfo(eFamilyName, compute_CPUFamilyName(cpu_vendor, family, ext_family));
+
+ setConfig(eCLFLUSHCacheLineSize, ((cpu_info[1] >> 8) & 0xff) * 8);
+ setConfig(eAPICPhysicalID, (cpu_info[1] >> 24) & 0xff);
+
+ if(cpu_info[2] & 0x1)
+ {
+ setExtension(cpu_feature_names[eSSE3_Features]);
+ }
+
+ if(cpu_info[2] & 0x8)
+ {
+ setExtension(cpu_feature_names[eMONTIOR_MWAIT]);
+ }
+
+ if(cpu_info[2] & 0x10)
+ {
+ setExtension(cpu_feature_names[eCPLDebugStore]);
+ }
+
+ if(cpu_info[2] & 0x100)
+ {
+ setExtension(cpu_feature_names[eThermalMonitor2]);
+ }
+
+ unsigned int feature_info = (unsigned int) cpu_info[3];
+ for(unsigned int index = 0, bit = 1; index < eSSE3_Features; ++index, bit <<= 1)
+ {
+ if(feature_info & bit)
{
- strcpy(CPUInfo.strModel, "Intel Pentium 4 Northwood"); /* Flawfinder: ignore */
- strncat(strCPUName, "Intel Pentium 4 Northwood", sizeof(strCPUName) - strlen(strCPUName) - 1); /* Flawfinder: ignore */
+ setExtension(cpu_feature_names[index]);
}
- else // Xeon
- {
- strcpy(CPUInfo.strModel, "Intel Pentium 4 Northwood Xeon"); /* Flawfinder: ignore */
- strncat(strCPUName, "Intel Pentium 4 Northwood Xeon", sizeof(strCPUName) - strlen(strCPUName) - 1); /* Flawfinder: ignore */
- }
- break;
- default: // Silly stupid never used failsave option
- strcpy(CPUInfo.strModel, "Unknown Intel Pentium 4"); /* Flawfinder: ignore */
- strncat(strCPUName, "Intel Pentium 4 (Unknown model)", sizeof(strCPUName) - strlen(strCPUName) - 1); /* Flawfinder: ignore */
- break;
+ }
}
- break;
- default: // *grmpf*
- strcpy(CPUInfo.strModel, "Unknown Intel model"); /* Flawfinder: ignore */
- strncat(strCPUName, "Intel (Unknown model)", sizeof(strCPUName) - strlen(strCPUName) - 1); /* Flawfinder: ignore */
- break;
- }
-
- // After the long processor model block we now come to the processors serial
- // number.
- // First of all we check if the processor supports the serial number
- if (CPUInfo.MaxSupportedLevel >= 3)
- {
- // If it supports the serial number CPUID level 0x00000003 we read the data
- unsigned long sig1, sig2, sig3;
- __asm
- {
- mov eax, 1
- cpuid
- mov sig1, eax
- mov eax, 3
- cpuid
- mov sig2, ecx
- mov sig3, edx
}
- // Then we convert the data to a readable string
- snprintf( /* Flawfinder: ignore */
- CPUInfo.strProcessorSerial,
- sizeof(CPUInfo.strProcessorSerial),
- "%04lX-%04lX-%04lX-%04lX-%04lX-%04lX",
- sig1 >> 16,
- sig1 & 0xFFFF,
- sig3 >> 16,
- sig3 & 0xFFFF,
- sig2 >> 16, sig2 & 0xFFFF);
- }
- else
- {
- // If there's no serial number support we just put "No serial number"
- snprintf( /* Flawfinder: ignore */
- CPUInfo.strProcessorSerial,
- sizeof(CPUInfo.strProcessorSerial),
- "No Processor Serial Number");
- }
- // Now we get the standard processor extensions
- GetStandardProcessorExtensions();
+ // Calling __cpuid with 0x80000000 as the InfoType argument
+ // gets the number of valid extended IDs.
+ __cpuid(cpu_info, 0x80000000);
+ unsigned int ext_ids = cpu_info[0];
+ setConfig(eMaxExtID, 0);
- // And finally the processor configuration (caches, TLBs, ...) and translate
- // the data to readable strings
- GetStandardProcessorConfiguration();
- TranslateProcessorConfiguration();
+ char cpu_brand_string[0x40];
+ memset(cpu_brand_string, 0, sizeof(cpu_brand_string));
- // At last...
- return true;
-#else
- return FALSE;
-#endif
-}
-
-// bool CProcessor::AnalyzeAMDProcessor()
-// ======================================
-// Private class function for analyzing an AMD processor
-////////////////////////////////////////////////////////
-bool CProcessor::AnalyzeAMDProcessor()
-{
-#if LL_WINDOWS
- unsigned long eaxreg, ebxreg, ecxreg, edxreg;
-
- // First of all we check if the CPUID command is available
- if (!CheckCPUIDPresence())
- return 0;
-
- // Now we get the CPUID standard level 0x00000001
- __asm
- {
- mov eax, 1
- cpuid
- mov eaxreg, eax
- mov ebxreg, ebx
- mov edxreg, edx
- }
-
- // Then we mask the model, family, stepping and type (AMD does not support brand id)
- CPUInfo.uiStepping = eaxreg & 0xF;
- CPUInfo.uiModel = (eaxreg >> 4) & 0xF;
- CPUInfo.uiFamily = (eaxreg >> 8) & 0xF;
- CPUInfo.uiType = (eaxreg >> 12) & 0x3;
-
- // Now we check if the processor supports the brand id string extended CPUID level
- if (CPUInfo.MaxSupportedExtendedLevel >= 0x80000004)
- {
- // If it supports the extended CPUID level 0x80000004 we read the data
- char tmp[52]; /* Flawfinder: ignore */
- memset(tmp, 0, sizeof(tmp));
- __asm
+ // Get the information associated with each extended ID.
+ for(unsigned int i=0x80000000; i<=ext_ids; ++i)
{
- mov eax, 0x80000002
- cpuid
- mov dword ptr [tmp], eax
- mov dword ptr [tmp+4], ebx
- mov dword ptr [tmp+8], ecx
- mov dword ptr [tmp+12], edx
- mov eax, 0x80000003
- cpuid
- mov dword ptr [tmp+16], eax
- mov dword ptr [tmp+20], ebx
- mov dword ptr [tmp+24], ecx
- mov dword ptr [tmp+28], edx
- mov eax, 0x80000004
- cpuid
- mov dword ptr [tmp+32], eax
- mov dword ptr [tmp+36], ebx
- mov dword ptr [tmp+40], ecx
- mov dword ptr [tmp+44], edx
- }
- // And copy it to the brand id string
- strncpy(CPUInfo.strBrandID, tmp,sizeof(CPUInfo.strBrandID)-1);
- CPUInfo.strBrandID[sizeof(CPUInfo.strBrandID)-1]='\0';
- }
- else
- {
- // Or just tell there is no brand id string support
- strcpy(CPUInfo.strBrandID, ""); /* Flawfinder: ignore */
- }
-
- // After that we translate the processor family
- switch(CPUInfo.uiFamily)
- {
- case 4: // Family = 4: 486 (80486) or 5x86 (80486) processor family
- switch (CPUInfo.uiModel)
+ __cpuid(cpu_info, i);
+
+ // Interpret CPU brand string and cache information.
+ if (i == 0x80000002)
+ memcpy(cpu_brand_string, cpu_info, sizeof(cpu_info));
+ else if (i == 0x80000003)
+ memcpy(cpu_brand_string + 16, cpu_info, sizeof(cpu_info));
+ else if (i == 0x80000004)
{
- case 3: // Thanks to AMD for this nice form of family
- case 7: // detection.... *grmpf*
- case 8:
- case 9:
- strcpy(CPUInfo.strFamily, "AMD 80486"); /* Flawfinder: ignore */
- break;
- case 0xE:
- case 0xF:
- strcpy(CPUInfo.strFamily, "AMD 5x86"); /* Flawfinder: ignore */
- break;
- default:
- strcpy(CPUInfo.strFamily, "Unknown family"); /* Flawfinder: ignore */
- break;
+ memcpy(cpu_brand_string + 32, cpu_info, sizeof(cpu_info));
+ setInfo(eBrandName, cpu_brand_string);
}
- break;
- case 5: // Family = 5: K5 or K6 processor family
- switch (CPUInfo.uiModel)
+ else if (i == 0x80000006)
{
- case 0:
- case 1:
- case 2:
- case 3:
- strcpy(CPUInfo.strFamily, "AMD K5"); /* Flawfinder: ignore */
- break;
- case 6:
- case 7:
- case 8:
- case 9:
- strcpy(CPUInfo.strFamily, "AMD K6"); /* Flawfinder: ignore */
- break;
- default:
- strcpy(CPUInfo.strFamily, "Unknown family"); /* Flawfinder: ignore */
- break;
+ setConfig(eCacheLineSize, cpu_info[2] & 0xff);
+ setConfig(eL2Associativity, (cpu_info[2] >> 12) & 0xf);
+ setConfig(eCacheSizeK, (cpu_info[2] >> 16) & 0xffff);
}
- break;
- case 6: // Family = 6: K7 (Athlon, ...) processor family
- strcpy(CPUInfo.strFamily, "AMD K7"); /* Flawfinder: ignore */
- break;
- default: // For security
- strcpy(CPUInfo.strFamily, "Unknown family"); /* Flawfinder: ignore */
- break;
+ }
}
+};
- // After the family detection we come to the specific processor model
- // detection
- switch (CPUInfo.uiFamily)
- {
- case 4: // Family = 4: 486 (80486) or 5x85 (80486) processor family
- switch (CPUInfo.uiModel)
- {
- case 3: // Model = 3: 80486 DX2
- strcpy(CPUInfo.strModel, "AMD 80486 DX2"); /* Flawfinder: ignore */
- strncat(strCPUName, "AMD 80486 DX2", sizeof(strCPUName) - strlen(strCPUName) -1); /* Flawfinder: ignore */
- break;
- case 7: // Model = 7: 80486 write-back enhanced DX2
- strcpy(CPUInfo.strModel, "AMD 80486 write-back enhanced DX2"); /* Flawfinder: ignore */
- strncat(strCPUName, "AMD 80486 write-back enhanced DX2", sizeof(strCPUName) - strlen(strCPUName) -1); /* Flawfinder: ignore */
- break;
- case 8: // Model = 8: 80486 DX4
- strcpy(CPUInfo.strModel, "AMD 80486 DX4"); /* Flawfinder: ignore */
- strncat(strCPUName, "AMD 80486 DX4", sizeof(strCPUName) - strlen(strCPUName) -1); /* Flawfinder: ignore */
- break;
- case 9: // Model = 9: 80486 write-back enhanced DX4
- strcpy(CPUInfo.strModel, "AMD 80486 write-back enhanced DX4"); /* Flawfinder: ignore */
- strncat(strCPUName, "AMD 80486 write-back enhanced DX4", sizeof(strCPUName) - strlen(strCPUName) -1); /* Flawfinder: ignore */
- break;
- case 0xE: // Model = 0xE: 5x86
- strcpy(CPUInfo.strModel, "AMD 5x86"); /* Flawfinder: ignore */
- strncat(strCPUName, "AMD 5x86", sizeof(strCPUName) - strlen(strCPUName) -1); /* Flawfinder: ignore */
- break;
- case 0xF: // Model = 0xF: 5x86 write-back enhanced (oh my god.....)
- strcpy(CPUInfo.strModel, "AMD 5x86 write-back enhanced"); /* Flawfinder: ignore */
- strncat(strCPUName, "AMD 5x86 write-back enhanced", sizeof(strCPUName) - strlen(strCPUName) -1); /* Flawfinder: ignore */
- break;
- default: // ...
- strcpy(CPUInfo.strModel, "Unknown AMD 80486 or 5x86 model"); /* Flawfinder: ignore */
- strncat(strCPUName, "AMD 80486 or 5x86 (Unknown model)", sizeof(strCPUName) - strlen(strCPUName) -1); /* Flawfinder: ignore */
- break;
- }
- break;
- case 5: // Family = 5: K5 / K6 processor family
- switch (CPUInfo.uiModel)
- {
- case 0: // Model = 0: K5 SSA 5 (Pentium Rating *ggg* 75, 90 and 100 Mhz)
- strcpy(CPUInfo.strModel, "AMD K5 SSA5 (PR75, PR90, PR100)"); /* Flawfinder: ignore */
- strncat(strCPUName, "AMD K5 SSA5 (PR75, PR90, PR100)", sizeof(strCPUName) - strlen(strCPUName) -1); /* Flawfinder: ignore */
- break;
- case 1: // Model = 1: K5 5k86 (PR 120 and 133 MHz)
- strcpy(CPUInfo.strModel, "AMD K5 5k86 (PR120, PR133)"); /* Flawfinder: ignore */
- strncat(strCPUName, "AMD K5 5k86 (PR120, PR133)", sizeof(strCPUName) - strlen(strCPUName) -1); /* Flawfinder: ignore */
- break;
- case 2: // Model = 2: K5 5k86 (PR 166 MHz)
- strcpy(CPUInfo.strModel, "AMD K5 5k86 (PR166)"); /* Flawfinder: ignore */
- strncat(strCPUName, "AMD K5 5k86 (PR166)", sizeof(strCPUName) - strlen(strCPUName) -1); /* Flawfinder: ignore */
- break;
- case 3: // Model = 3: K5 5k86 (PR 200 MHz)
- strcpy(CPUInfo.strModel, "AMD K5 5k86 (PR200)"); /* Flawfinder: ignore */
- strncat(strCPUName, "AMD K5 5k86 (PR200)", sizeof(strCPUName) - strlen(strCPUName) -1); /* Flawfinder: ignore */
- break;
- case 6: // Model = 6: K6
- strcpy(CPUInfo.strModel, "AMD K6 (0.30 micron)"); /* Flawfinder: ignore */
- strncat(strCPUName, "AMD K6 (0.30 micron)", sizeof(strCPUName) - strlen(strCPUName) -1); /* Flawfinder: ignore */
- break;
- case 7: // Model = 7: K6 (0.25 micron)
- strcpy(CPUInfo.strModel, "AMD K6 (0.25 micron)"); /* Flawfinder: ignore */
- strncat(strCPUName, "AMD K6 (0.25 micron)", sizeof(strCPUName) - strlen(strCPUName) -1); /* Flawfinder: ignore */
- break;
- case 8: // Model = 8: K6-2
- strcpy(CPUInfo.strModel, "AMD K6-2"); /* Flawfinder: ignore */
- strncat(strCPUName, "AMD K6-2", sizeof(strCPUName) - strlen(strCPUName) -1); /* Flawfinder: ignore */
- break;
- case 9: // Model = 9: K6-III
- strcpy(CPUInfo.strModel, "AMD K6-III"); /* Flawfinder: ignore */
- strncat(strCPUName, "AMD K6-III", sizeof(strCPUName) - strlen(strCPUName) -1); /* Flawfinder: ignore */
- break;
- case 0xD: // Model = 0xD: K6-2+ / K6-III+
- strcpy(CPUInfo.strModel, "AMD K6-2+ or K6-III+ (0.18 micron)"); /* Flawfinder: ignore */
- strncat(strCPUName, "AMD K6-2+ or K6-III+ (0.18 micron)", sizeof(strCPUName) - strlen(strCPUName) -1); /* Flawfinder: ignore */
- break;
- default: // ...
- strcpy(CPUInfo.strModel, "Unknown AMD K5 or K6 model"); /* Flawfinder: ignore */
- strncat(strCPUName, "AMD K5 or K6 (Unknown model)", sizeof(strCPUName) - strlen(strCPUName) -1); /* Flawfinder: ignore */
- break;
- }
- break;
- case 6: // Family = 6: K7 processor family (AMDs first good processors)
- switch (CPUInfo.uiModel)
+#elif LL_DARWIN
+
+#include <mach/machine.h>
+#include <sys/sysctl.h>
+
+class LLProcessorInfoDarwinImpl : public LLProcessorInfoImpl
+{
+public:
+ LLProcessorInfoDarwinImpl()
+ {
+ getCPUIDInfo();
+ uint64_t frequency = getSysctlInt64("hw.cpufrequency");
+ setInfo(eFrequency, (F64)frequency / (F64)1000000);
+ }
+
+ virtual ~LLProcessorInfoDarwinImpl() {}
+
+private:
+ int getSysctlInt(const char* name)
+ {
+ int result = 0;
+ size_t len = sizeof(int);
+ int error = sysctlbyname(name, (void*)&result, &len, NULL, 0);
+ return error == -1 ? 0 : result;
+ }
+
+ uint64_t getSysctlInt64(const char* name)
+ {
+ uint64_t value = 0;
+ size_t size = sizeof(value);
+ int result = sysctlbyname(name, (void*)&value, &size, NULL, 0);
+ if ( result == 0 )
+ {
+ if ( size == sizeof( uint64_t ) )
+ ;
+ else if ( size == sizeof( uint32_t ) )
+ value = (uint64_t)(( uint32_t *)&value);
+ else if ( size == sizeof( uint16_t ) )
+ value = (uint64_t)(( uint16_t *)&value);
+ else if ( size == sizeof( uint8_t ) )
+ value = (uint64_t)(( uint8_t *)&value);
+ else
{
- case 1: // Athlon
- strcpy(CPUInfo.strModel, "AMD Athlon (0.25 micron)"); /* Flawfinder: ignore */
- strncat(strCPUName, "AMD Athlon (0.25 micron)", sizeof(strCPUName) - strlen(strCPUName) -1); /* Flawfinder: ignore */
- break;
- case 2: // Athlon (0.18 micron)
- strcpy(CPUInfo.strModel, "AMD Athlon (0.18 micron)"); /* Flawfinder: ignore */
- strncat(strCPUName, "AMD Athlon (0.18 micron)", sizeof(strCPUName) - strlen(strCPUName) -1); /* Flawfinder: ignore */
- break;
- case 3: // Duron (Spitfire core)
- strcpy(CPUInfo.strModel, "AMD Duron (Spitfire)"); /* Flawfinder: ignore */
- strncat(strCPUName, "AMD Duron (Spitfire core)", sizeof(strCPUName) - strlen(strCPUName) -1); /* Flawfinder: ignore */
- break;
- case 4: // Athlon (Thunderbird core)
- strcpy(CPUInfo.strModel, "AMD Athlon (Thunderbird)"); /* Flawfinder: ignore */
- strncat(strCPUName, "AMD Athlon (Thunderbird core)", sizeof(strCPUName) - strlen(strCPUName) -1); /* Flawfinder: ignore */
- break;
- case 6: // Athlon MP / Mobile Athlon (Palomino core)
- strcpy(CPUInfo.strModel, "AMD Athlon MP/Mobile Athlon (Palomino)"); /* Flawfinder: ignore */
- strncat(strCPUName, "AMD Athlon MP/Mobile Athlon (Palomino core)", sizeof(strCPUName) - strlen(strCPUName) -1); /* Flawfinder: ignore */
- break;
- case 7: // Mobile Duron (Morgan core)
- strcpy(CPUInfo.strModel, "AMD Mobile Duron (Morgan)"); /* Flawfinder: ignore */
- strncat(strCPUName, "AMD Mobile Duron (Morgan core)", sizeof(strCPUName) - strlen(strCPUName) -1); /* Flawfinder: ignore */
- break;
- default: // ...
- strcpy(CPUInfo.strModel, "Unknown AMD K7 model"); /* Flawfinder: ignore */
- strncat(strCPUName, "AMD K7 (Unknown model)", sizeof(strCPUName) - strlen(strCPUName) -1); /* Flawfinder: ignore */
- break;
+ LL_WARNS("Unknown type returned from sysctl!") << LL_ENDL;
}
- break;
- default: // ...
- strcpy(CPUInfo.strModel, "Unknown AMD model"); /* Flawfinder: ignore */
- strncat(strCPUName, "AMD (Unknown model)", sizeof(strCPUName) - strlen(strCPUName) -1); /* Flawfinder: ignore */
- break;
- }
-
- // Now we read the standard processor extension that are stored in the same
- // way the Intel standard extensions are
- GetStandardProcessorExtensions();
-
- // Then we check if theres an extended CPUID level support
- if (CPUInfo.MaxSupportedExtendedLevel >= 0x80000001)
- {
- // If we can access the extended CPUID level 0x80000001 we get the
- // edx register
- __asm
- {
- mov eax, 0x80000001
- cpuid
- mov edxreg, edx
}
-
- // Now we can mask some AMD specific cpu extensions
- CPUInfo._Ext.EMMX_MultimediaExtensions = CheckBit(edxreg, 22);
- CPUInfo._Ext.AA64_AMD64BitArchitecture = CheckBit(edxreg, 29);
- CPUInfo._Ext._E3DNOW_InstructionExtensions = CheckBit(edxreg, 30);
- CPUInfo._Ext._3DNOW_InstructionExtensions = CheckBit(edxreg, 31);
- }
-
- // After that we check if the processor supports the ext. CPUID level
- // 0x80000006
- if (CPUInfo.MaxSupportedExtendedLevel >= 0x80000006)
+
+ return result == -1 ? 0 : value;
+ }
+
+ void getCPUIDInfo()
{
- // If it's present, we read it out
- __asm
- {
- mov eax, 0x80000005
- cpuid
- mov eaxreg, eax
- mov ebxreg, ebx
- mov ecxreg, ecx
- mov edxreg, edx
- }
+ size_t len = 0;
- // Then we mask the L1 Data TLB information
- if ((ebxreg >> 16) && (eaxreg >> 16))
- {
- CPUInfo._Data.bPresent = true;
- strcpy(CPUInfo._Data.strPageSize, "4 KB / 2 MB / 4MB"); /*Flawfinder: ignore*/
- CPUInfo._Data.uiAssociativeWays = (eaxreg >> 24) & 0xFF;
- CPUInfo._Data.uiEntries = (eaxreg >> 16) & 0xFF;
- }
- else if (eaxreg >> 16)
- {
- CPUInfo._Data.bPresent = true;
- strcpy(CPUInfo._Data.strPageSize, "2 MB / 4MB"); /*Flawfinder: ignore*/
- CPUInfo._Data.uiAssociativeWays = (eaxreg >> 24) & 0xFF;
- CPUInfo._Data.uiEntries = (eaxreg >> 16) & 0xFF;
- }
- else if (ebxreg >> 16)
- {
- CPUInfo._Data.bPresent = true;
- strcpy(CPUInfo._Data.strPageSize, "4 KB"); /*Flawfinder: ignore*/
- CPUInfo._Data.uiAssociativeWays = (ebxreg >> 24) & 0xFF;
- CPUInfo._Data.uiEntries = (ebxreg >> 16) & 0xFF;
- }
- if (CPUInfo._Data.uiAssociativeWays == 0xFF)
- CPUInfo._Data.uiAssociativeWays = (unsigned int) -1;
-
- // Now the L1 Instruction/Code TLB information
- if ((ebxreg & 0xFFFF) && (eaxreg & 0xFFFF))
- {
- CPUInfo._Instruction.bPresent = true;
- strcpy(CPUInfo._Instruction.strPageSize, "4 KB / 2 MB / 4MB"); /*Flawfinder: ignore*/
- CPUInfo._Instruction.uiAssociativeWays = (eaxreg >> 8) & 0xFF;
- CPUInfo._Instruction.uiEntries = eaxreg & 0xFF;
- }
- else if (eaxreg & 0xFFFF)
- {
- CPUInfo._Instruction.bPresent = true;
- strcpy(CPUInfo._Instruction.strPageSize, "2 MB / 4MB"); /*Flawfinder: ignore*/
- CPUInfo._Instruction.uiAssociativeWays = (eaxreg >> 8) & 0xFF;
- CPUInfo._Instruction.uiEntries = eaxreg & 0xFF;
- }
- else if (ebxreg & 0xFFFF)
- {
- CPUInfo._Instruction.bPresent = true;
- strcpy(CPUInfo._Instruction.strPageSize, "4 KB"); /*Flawfinder: ignore*/
- CPUInfo._Instruction.uiAssociativeWays = (ebxreg >> 8) & 0xFF;
- CPUInfo._Instruction.uiEntries = ebxreg & 0xFF;
- }
- if (CPUInfo._Instruction.uiAssociativeWays == 0xFF)
- CPUInfo._Instruction.uiAssociativeWays = (unsigned int) -1;
+ char cpu_brand_string[0x40];
+ len = sizeof(cpu_brand_string);
+ memset(cpu_brand_string, 0, len);
+ sysctlbyname("machdep.cpu.brand_string", (void*)cpu_brand_string, &len, NULL, 0);
+ cpu_brand_string[0x3f] = 0;
+ setInfo(eBrandName, cpu_brand_string);
- // Then we read the L1 data cache information
- if ((ecxreg >> 24) > 0)
- {
- CPUInfo._L1.Data.bPresent = true;
- snprintf(CPUInfo._L1.Data.strSize, sizeof(CPUInfo._L1.Data.strSize), "%d KB", ecxreg >> 24); /* Flawfinder: ignore */
- CPUInfo._L1.Data.uiAssociativeWays = (ecxreg >> 15) & 0xFF;
- CPUInfo._L1.Data.uiLineSize = ecxreg & 0xFF;
- }
- // After that we read the L2 instruction/code cache information
- if ((edxreg >> 24) > 0)
- {
- CPUInfo._L1.Instruction.bPresent = true;
- snprintf(CPUInfo._L1.Instruction.strSize, sizeof(CPUInfo._L1.Instruction.strSize), "%d KB", edxreg >> 24); /* Flawfinder: ignore */
- CPUInfo._L1.Instruction.uiAssociativeWays = (edxreg >> 15) & 0xFF;
- CPUInfo._L1.Instruction.uiLineSize = edxreg & 0xFF;
- }
-
- // Note: I'm not absolutely sure that the L1 page size code (the
- // 'if/else if/else if' structs above) really detects the real page
- // size for the TLB. Somebody should check it....
-
- // Now we read the ext. CPUID level 0x80000006
- __asm
- {
- mov eax, 0x80000006
- cpuid
- mov eaxreg, eax
- mov ebxreg, ebx
- mov ecxreg, ecx
- }
+ char cpu_vendor[0x20];
+ len = sizeof(cpu_vendor);
+ memset(cpu_vendor, 0, len);
+ sysctlbyname("machdep.cpu.vendor", (void*)cpu_vendor, &len, NULL, 0);
+ cpu_vendor[0x1f] = 0;
+ setInfo(eVendor, cpu_vendor);
+
+ setInfo(eStepping, getSysctlInt("machdep.cpu.stepping"));
+ setInfo(eModel, getSysctlInt("machdep.cpu.model"));
+ int family = getSysctlInt("machdep.cpu.family");
+ int ext_family = getSysctlInt("machdep.cpu.extfamily");
+ setInfo(eFamily, family);
+ setInfo(eExtendedFamily, ext_family);
+ setInfo(eFamilyName, compute_CPUFamilyName(cpu_vendor, family, ext_family));
+ setInfo(eExtendedModel, getSysctlInt("machdep.cpu.extmodel"));
+ setInfo(eBrandID, getSysctlInt("machdep.cpu.brand"));
+ setInfo(eType, 0); // ? where to find this?
+
+ //setConfig(eCLFLUSHCacheLineSize, ((cpu_info[1] >> 8) & 0xff) * 8);
+ //setConfig(eAPICPhysicalID, (cpu_info[1] >> 24) & 0xff);
+ setConfig(eCacheLineSize, getSysctlInt("machdep.cpu.cache.linesize"));
+ setConfig(eL2Associativity, getSysctlInt("machdep.cpu.cache.L2_associativity"));
+ setConfig(eCacheSizeK, getSysctlInt("machdep.cpu.cache.size"));
+
+ uint64_t feature_info = getSysctlInt64("machdep.cpu.feature_bits");
+ S32 *feature_infos = (S32*)(&feature_info);
+
+ setConfig(eFeatureBits, feature_infos[0]);
- // We only mask the unified L2 cache masks (never heard of an
- // L2 cache that is divided in data and code parts)
- if (((ecxreg >> 12) & 0xF) > 0)
+ for(unsigned int index = 0, bit = 1; index < eSSE3_Features; ++index, bit <<= 1)
{
- CPUInfo._L2.bPresent = true;
- snprintf(CPUInfo._L2.strSize, sizeof(CPUInfo._L2.strSize), "%d KB", ecxreg >> 16); /* Flawfinder: ignore */
- switch ((ecxreg >> 12) & 0xF)
+ if(feature_info & bit)
{
- case 1:
- CPUInfo._L2.uiAssociativeWays = 1;
- break;
- case 2:
- CPUInfo._L2.uiAssociativeWays = 2;
- break;
- case 4:
- CPUInfo._L2.uiAssociativeWays = 4;
- break;
- case 6:
- CPUInfo._L2.uiAssociativeWays = 8;
- break;
- case 8:
- CPUInfo._L2.uiAssociativeWays = 16;
- break;
- case 0xF:
- CPUInfo._L2.uiAssociativeWays = (unsigned int) -1;
- break;
- default:
- CPUInfo._L2.uiAssociativeWays = 0;
- break;
+ setExtension(cpu_feature_names[index]);
}
- CPUInfo._L2.uiLineSize = ecxreg & 0xFF;
}
- }
- else
- {
- // If we could not detect the ext. CPUID level 0x80000006 we
- // try to read the standard processor configuration.
- GetStandardProcessorConfiguration();
- }
- // After reading we translate the configuration to strings
- TranslateProcessorConfiguration();
-
- // And finally exit
- return true;
-#else
- return FALSE;
-#endif
-}
-
-// bool CProcessor::AnalyzeUnknownProcessor()
-// ==========================================
-// Private class function to analyze an unknown (No Intel or AMD) processor
-///////////////////////////////////////////////////////////////////////////
-bool CProcessor::AnalyzeUnknownProcessor()
-{
-#if LL_WINDOWS
- unsigned long eaxreg, ebxreg;
-
- // We check if the CPUID command is available
- if (!CheckCPUIDPresence())
- return false;
-
- // First of all we read the standard CPUID level 0x00000001
- // This level should be available on every x86-processor clone
- __asm
- {
- mov eax, 1
- cpuid
- mov eaxreg, eax
- mov ebxreg, ebx
- }
- // Then we mask the processor model, family, type and stepping
- CPUInfo.uiStepping = eaxreg & 0xF;
- CPUInfo.uiModel = (eaxreg >> 4) & 0xF;
- CPUInfo.uiFamily = (eaxreg >> 8) & 0xF;
- CPUInfo.uiType = (eaxreg >> 12) & 0x3;
-
- // To have complete information we also mask the brand id
- CPUInfo.uiBrandID = ebxreg & 0xF;
-
- // Then we get the standard processor extensions
- GetStandardProcessorExtensions();
-
- // Now we mark everything we do not know as unknown
- strcpy(strCPUName, "Unknown"); /*Flawfinder: ignore*/
-
- strcpy(CPUInfo._Data.strTLB, "Unknown"); /*Flawfinder: ignore*/
- strcpy(CPUInfo._Instruction.strTLB, "Unknown"); /*Flawfinder: ignore*/
-
- strcpy(CPUInfo._Trace.strCache, "Unknown"); /*Flawfinder: ignore*/
- strcpy(CPUInfo._L1.Data.strCache, "Unknown"); /*Flawfinder: ignore*/
- strcpy(CPUInfo._L1.Instruction.strCache, "Unknown"); /*Flawfinder: ignore*/
- strcpy(CPUInfo._L2.strCache, "Unknown"); /*Flawfinder: ignore*/
- strcpy(CPUInfo._L3.strCache, "Unknown"); /*Flawfinder: ignore*/
-
- strcpy(CPUInfo.strProcessorSerial, "Unknown / Not supported"); /*Flawfinder: ignore*/
- // For the family, model and brand id we can only print the numeric value
- snprintf(CPUInfo.strBrandID, sizeof(CPUInfo.strBrandID), "Brand-ID number %d", CPUInfo.uiBrandID); /* Flawfinder: ignore */
- snprintf(CPUInfo.strFamily, sizeof(CPUInfo.strFamily), "Family number %d", CPUInfo.uiFamily); /* Flawfinder: ignore */
- snprintf(CPUInfo.strModel, sizeof(CPUInfo.strModel), "Model number %d", CPUInfo.uiModel); /* Flawfinder: ignore */
+ // *NOTE:Mani - I didn't find any docs that assure me that machdep.cpu.feature_bits will always be
+ // The feature bits I think it is. Here's a test:
+#ifndef LL_RELEASE_FOR_DOWNLOAD
+ #if defined(__i386__) && defined(__PIC__)
+ /* %ebx may be the PIC register. */
+ #define __cpuid(level, a, b, c, d) \
+ __asm__ ("xchgl\t%%ebx, %1\n\t" \
+ "cpuid\n\t" \
+ "xchgl\t%%ebx, %1\n\t" \
+ : "=a" (a), "=r" (b), "=c" (c), "=d" (d) \
+ : "0" (level))
+ #else
+ #define __cpuid(level, a, b, c, d) \
+ __asm__ ("cpuid\n\t" \
+ : "=a" (a), "=b" (b), "=c" (c), "=d" (d) \
+ : "0" (level))
+ #endif
+
+ unsigned int eax, ebx, ecx, edx;
+ __cpuid(0x1, eax, ebx, ecx, edx);
+ if(feature_infos[0] != (S32)edx)
+ {
+ llerrs << "machdep.cpu.feature_bits doesn't match expected cpuid result!" << llendl;
+ }
+#endif // LL_RELEASE_FOR_DOWNLOAD
- // And thats it
- return true;
-#else
- return FALSE;
-#endif
-}
-// bool CProcessor::CheckCPUIDPresence()
-// =====================================
-// This function checks if the CPUID command is available on the current
-// processor
-////////////////////////////////////////////////////////////////////////
-bool CProcessor::CheckCPUIDPresence()
-{
-#if LL_WINDOWS
- unsigned long BitChanged;
-
- // We've to check if we can toggle the flag register bit 21
- // If we can't the processor does not support the CPUID command
- __asm
- {
- pushfd
- pop eax
- mov ebx, eax
- xor eax, 0x00200000
- push eax
- popfd
- pushfd
- pop eax
- xor eax,ebx
- mov BitChanged, eax
+ uint64_t ext_feature_info = getSysctlInt64("machdep.cpu.extfeature_bits");
+ S32 *ext_feature_infos = (S32*)(&ext_feature_info);
+ setConfig(eExtFeatureBits, ext_feature_infos[0]);
}
+};
- return ((BitChanged) ? true : false);
-#else
- return FALSE;
-#endif
-}
+#elif LL_LINUX
+const char CPUINFO_FILE[] = "/proc/cpuinfo";
-// void CProcessor::DecodeProcessorConfiguration(unsigned int cfg)
-// ===============================================================
-// This function (or switch ?!) just translates a one-byte processor configuration
-// byte to understandable values
-//////////////////////////////////////////////////////////////////////////////////
-void CProcessor::DecodeProcessorConfiguration(unsigned int cfg)
+class LLProcessorInfoLinuxImpl : public LLProcessorInfoImpl
{
- // First we ensure that there's only one single byte
- cfg &= 0xFF;
-
- // Then we do a big switch
- switch(cfg)
+public:
+ LLProcessorInfoLinuxImpl()
{
- case 0: // cfg = 0: Unused
- break;
- case 0x1: // cfg = 0x1: code TLB present, 4 KB pages, 4 ways, 32 entries
- CPUInfo._Instruction.bPresent = true;
- strcpy(CPUInfo._Instruction.strPageSize, "4 KB"); /*Flawfinder: ignore*/
- CPUInfo._Instruction.uiAssociativeWays = 4;
- CPUInfo._Instruction.uiEntries = 32;
- break;
- case 0x2: // cfg = 0x2: code TLB present, 4 MB pages, fully associative, 2 entries
- CPUInfo._Instruction.bPresent = true;
- strcpy(CPUInfo._Instruction.strPageSize, "4 MB"); /*Flawfinder: ignore*/
- CPUInfo._Instruction.uiAssociativeWays = 4;
- CPUInfo._Instruction.uiEntries = 2;
- break;
- case 0x3: // cfg = 0x3: data TLB present, 4 KB pages, 4 ways, 64 entries
- CPUInfo._Data.bPresent = true;
- strcpy(CPUInfo._Data.strPageSize, "4 KB"); /*Flawfinder: ignore*/
- CPUInfo._Data.uiAssociativeWays = 4;
- CPUInfo._Data.uiEntries = 64;
- break;
- case 0x4: // cfg = 0x4: data TLB present, 4 MB pages, 4 ways, 8 entries
- CPUInfo._Data.bPresent = true;
- strcpy(CPUInfo._Data.strPageSize, "4 MB"); /*Flawfinder: ignore*/
- CPUInfo._Data.uiAssociativeWays = 4;
- CPUInfo._Data.uiEntries = 8;
- break;
- case 0x6: // cfg = 0x6: code L1 cache present, 8 KB, 4 ways, 32 byte lines
- CPUInfo._L1.Instruction.bPresent = true;
- strcpy(CPUInfo._L1.Instruction.strSize, "8 KB"); /*Flawfinder: ignore*/
- CPUInfo._L1.Instruction.uiAssociativeWays = 4;
- CPUInfo._L1.Instruction.uiLineSize = 32;
- break;
- case 0x8: // cfg = 0x8: code L1 cache present, 16 KB, 4 ways, 32 byte lines
- CPUInfo._L1.Instruction.bPresent = true;
- strcpy(CPUInfo._L1.Instruction.strSize, "16 KB"); /*Flawfinder: ignore*/
- CPUInfo._L1.Instruction.uiAssociativeWays = 4;
- CPUInfo._L1.Instruction.uiLineSize = 32;
- break;
- case 0xA: // cfg = 0xA: data L1 cache present, 8 KB, 2 ways, 32 byte lines
- CPUInfo._L1.Data.bPresent = true;
- strcpy(CPUInfo._L1.Data.strSize, "8 KB"); /*Flawfinder: ignore*/
- CPUInfo._L1.Data.uiAssociativeWays = 2;
- CPUInfo._L1.Data.uiLineSize = 32;
- break;
- case 0xC: // cfg = 0xC: data L1 cache present, 16 KB, 4 ways, 32 byte lines
- CPUInfo._L1.Data.bPresent = true;
- strcpy(CPUInfo._L1.Data.strSize, "16 KB"); /*Flawfinder: ignore*/
- CPUInfo._L1.Data.uiAssociativeWays = 4;
- CPUInfo._L1.Data.uiLineSize = 32;
- break;
- case 0x22: // cfg = 0x22: code and data L3 cache present, 512 KB, 4 ways, 64 byte lines, sectored
- CPUInfo._L3.bPresent = true;
- strcpy(CPUInfo._L3.strSize, "512 KB"); /*Flawfinder: ignore*/
- CPUInfo._L3.uiAssociativeWays = 4;
- CPUInfo._L3.uiLineSize = 64;
- CPUInfo._L3.bSectored = true;
- break;
- case 0x23: // cfg = 0x23: code and data L3 cache present, 1024 KB, 8 ways, 64 byte lines, sectored
- CPUInfo._L3.bPresent = true;
- strcpy(CPUInfo._L3.strSize, "1024 KB"); /*Flawfinder: ignore*/
- CPUInfo._L3.uiAssociativeWays = 8;
- CPUInfo._L3.uiLineSize = 64;
- CPUInfo._L3.bSectored = true;
- break;
- case 0x25: // cfg = 0x25: code and data L3 cache present, 2048 KB, 8 ways, 64 byte lines, sectored
- CPUInfo._L3.bPresent = true;
- strcpy(CPUInfo._L3.strSize, "2048 KB"); /*Flawfinder: ignore*/
- CPUInfo._L3.uiAssociativeWays = 8;
- CPUInfo._L3.uiLineSize = 64;
- CPUInfo._L3.bSectored = true;
- break;
- case 0x29: // cfg = 0x29: code and data L3 cache present, 4096 KB, 8 ways, 64 byte lines, sectored
- CPUInfo._L3.bPresent = true;
- strcpy(CPUInfo._L3.strSize, "4096 KB"); /*Flawfinder: ignore*/
- CPUInfo._L3.uiAssociativeWays = 8;
- CPUInfo._L3.uiLineSize = 64;
- CPUInfo._L3.bSectored = true;
- break;
- case 0x40: // cfg = 0x40: no integrated L2 cache (P6 core) or L3 cache (P4 core)
- break;
- case 0x41: // cfg = 0x41: code and data L2 cache present, 128 KB, 4 ways, 32 byte lines
- CPUInfo._L2.bPresent = true;
- strcpy(CPUInfo._L2.strSize, "128 KB"); /*Flawfinder: ignore*/
- CPUInfo._L2.uiAssociativeWays = 4;
- CPUInfo._L2.uiLineSize = 32;
- break;
- case 0x42: // cfg = 0x42: code and data L2 cache present, 256 KB, 4 ways, 32 byte lines
- CPUInfo._L2.bPresent = true;
- strcpy(CPUInfo._L2.strSize, "256 KB"); /*Flawfinder: ignore*/
- CPUInfo._L2.uiAssociativeWays = 4;
- CPUInfo._L2.uiLineSize = 32;
- break;
- case 0x43: // cfg = 0x43: code and data L2 cache present, 512 KB, 4 ways, 32 byte lines
- CPUInfo._L2.bPresent = true;
- strcpy(CPUInfo._L2.strSize, "512 KB"); /* Flawfinder: ignore */
- CPUInfo._L2.uiAssociativeWays = 4;
- CPUInfo._L2.uiLineSize = 32;
- break;
- case 0x44: // cfg = 0x44: code and data L2 cache present, 1024 KB, 4 ways, 32 byte lines
- CPUInfo._L2.bPresent = true;
- strcpy(CPUInfo._L2.strSize, "1 MB"); /* Flawfinder: ignore */
- CPUInfo._L2.uiAssociativeWays = 4;
- CPUInfo._L2.uiLineSize = 32;
- break;
- case 0x45: // cfg = 0x45: code and data L2 cache present, 2048 KB, 4 ways, 32 byte lines
- CPUInfo._L2.bPresent = true;
- strcpy(CPUInfo._L2.strSize, "2 MB"); /* Flawfinder: ignore */
- CPUInfo._L2.uiAssociativeWays = 4;
- CPUInfo._L2.uiLineSize = 32;
- break;
- case 0x50: // cfg = 0x50: code TLB present, 4 KB / 4 MB / 2 MB pages, fully associative, 64 entries
- CPUInfo._Instruction.bPresent = true;
- strcpy(CPUInfo._Instruction.strPageSize, "4 KB / 2 MB / 4 MB"); /* Flawfinder: ignore */
- CPUInfo._Instruction.uiAssociativeWays = (unsigned int) -1;
- CPUInfo._Instruction.uiEntries = 64;
- break;
- case 0x51: // cfg = 0x51: code TLB present, 4 KB / 4 MB / 2 MB pages, fully associative, 128 entries
- CPUInfo._Instruction.bPresent = true;
- strcpy(CPUInfo._Instruction.strPageSize, "4 KB / 2 MB / 4 MB"); /* Flawfinder: ignore */
- CPUInfo._Instruction.uiAssociativeWays = (unsigned int) -1;
- CPUInfo._Instruction.uiEntries = 128;
- break;
- case 0x52: // cfg = 0x52: code TLB present, 4 KB / 4 MB / 2 MB pages, fully associative, 256 entries
- CPUInfo._Instruction.bPresent = true;
- strcpy(CPUInfo._Instruction.strPageSize, "4 KB / 2 MB / 4 MB"); /* Flawfinder: ignore */
- CPUInfo._Instruction.uiAssociativeWays = (unsigned int) -1;
- CPUInfo._Instruction.uiEntries = 256;
- break;
- case 0x5B: // cfg = 0x5B: data TLB present, 4 KB / 4 MB pages, fully associative, 64 entries
- CPUInfo._Data.bPresent = true;
- strcpy(CPUInfo._Data.strPageSize, "4 KB / 4 MB"); /* Flawfinder: ignore */
- CPUInfo._Data.uiAssociativeWays = (unsigned int) -1;
- CPUInfo._Data.uiEntries = 64;
- break;
- case 0x5C: // cfg = 0x5C: data TLB present, 4 KB / 4 MB pages, fully associative, 128 entries
- CPUInfo._Data.bPresent = true;
- strcpy(CPUInfo._Data.strPageSize, "4 KB / 4 MB"); /* Flawfinder: ignore */
- CPUInfo._Data.uiAssociativeWays = (unsigned int) -1;
- CPUInfo._Data.uiEntries = 128;
- break;
- case 0x5d: // cfg = 0x5D: data TLB present, 4 KB / 4 MB pages, fully associative, 256 entries
- CPUInfo._Data.bPresent = true;
- strcpy(CPUInfo._Data.strPageSize, "4 KB / 4 MB"); /* Flawfinder: ignore */
- CPUInfo._Data.uiAssociativeWays = (unsigned int) -1;
- CPUInfo._Data.uiEntries = 256;
- break;
- case 0x66: // cfg = 0x66: data L1 cache present, 8 KB, 4 ways, 64 byte lines, sectored
- CPUInfo._L1.Data.bPresent = true;
- strcpy(CPUInfo._L1.Data.strSize, "8 KB"); /* Flawfinder: ignore */
- CPUInfo._L1.Data.uiAssociativeWays = 4;
- CPUInfo._L1.Data.uiLineSize = 64;
- break;
- case 0x67: // cfg = 0x67: data L1 cache present, 16 KB, 4 ways, 64 byte lines, sectored
- CPUInfo._L1.Data.bPresent = true;
- strcpy(CPUInfo._L1.Data.strSize, "16 KB"); /* Flawfinder: ignore */
- CPUInfo._L1.Data.uiAssociativeWays = 4;
- CPUInfo._L1.Data.uiLineSize = 64;
- break;
- case 0x68: // cfg = 0x68: data L1 cache present, 32 KB, 4 ways, 64 byte lines, sectored
- CPUInfo._L1.Data.bPresent = true;
- strcpy(CPUInfo._L1.Data.strSize, "32 KB"); /* Flawfinder: ignore */
- CPUInfo._L1.Data.uiAssociativeWays = 4;
- CPUInfo._L1.Data.uiLineSize = 64;
- break;
- case 0x70: // cfg = 0x70: trace L1 cache present, 12 KuOPs, 4 ways
- CPUInfo._Trace.bPresent = true;
- strcpy(CPUInfo._Trace.strSize, "12 K-micro-ops"); /* Flawfinder: ignore */
- CPUInfo._Trace.uiAssociativeWays = 4;
- break;
- case 0x71: // cfg = 0x71: trace L1 cache present, 16 KuOPs, 4 ways
- CPUInfo._Trace.bPresent = true;
- strcpy(CPUInfo._Trace.strSize, "16 K-micro-ops"); /* Flawfinder: ignore */
- CPUInfo._Trace.uiAssociativeWays = 4;
- break;
- case 0x72: // cfg = 0x72: trace L1 cache present, 32 KuOPs, 4 ways
- CPUInfo._Trace.bPresent = true;
- strcpy(CPUInfo._Trace.strSize, "32 K-micro-ops"); /* Flawfinder: ignore */
- CPUInfo._Trace.uiAssociativeWays = 4;
- break;
- case 0x79: // cfg = 0x79: code and data L2 cache present, 128 KB, 8 ways, 64 byte lines, sectored
- CPUInfo._L2.bPresent = true;
- strcpy(CPUInfo._L2.strSize, "128 KB"); /* Flawfinder: ignore */
- CPUInfo._L2.uiAssociativeWays = 8;
- CPUInfo._L2.uiLineSize = 64;
- CPUInfo._L2.bSectored = true;
- break;
- case 0x7A: // cfg = 0x7A: code and data L2 cache present, 256 KB, 8 ways, 64 byte lines, sectored
- CPUInfo._L2.bPresent = true;
- strcpy(CPUInfo._L2.strSize, "256 KB"); /* Flawfinder: ignore */
- CPUInfo._L2.uiAssociativeWays = 8;
- CPUInfo._L2.uiLineSize = 64;
- CPUInfo._L2.bSectored = true;
- break;
- case 0x7B: // cfg = 0x7B: code and data L2 cache present, 512 KB, 8 ways, 64 byte lines, sectored
- CPUInfo._L2.bPresent = true;
- strcpy(CPUInfo._L2.strSize, "512 KB"); /* Flawfinder: ignore */
- CPUInfo._L2.uiAssociativeWays = 8;
- CPUInfo._L2.uiLineSize = 64;
- CPUInfo._L2.bSectored = true;
- break;
- case 0x7C: // cfg = 0x7C: code and data L2 cache present, 1024 KB, 8 ways, 64 byte lines, sectored
- CPUInfo._L2.bPresent = true;
- strcpy(CPUInfo._L2.strSize, "1 MB"); /* Flawfinder: ignore */
- CPUInfo._L2.uiAssociativeWays = 8;
- CPUInfo._L2.uiLineSize = 64;
- CPUInfo._L2.bSectored = true;
- break;
- case 0x81: // cfg = 0x81: code and data L2 cache present, 128 KB, 8 ways, 32 byte lines
- CPUInfo._L2.bPresent = true;
- strcpy(CPUInfo._L2.strSize, "128 KB"); /* Flawfinder: ignore */
- CPUInfo._L2.uiAssociativeWays = 8;
- CPUInfo._L2.uiLineSize = 32;
- break;
- case 0x82: // cfg = 0x82: code and data L2 cache present, 256 KB, 8 ways, 32 byte lines
- CPUInfo._L2.bPresent = true;
- strcpy(CPUInfo._L2.strSize, "256 KB"); /* Flawfinder: ignore */
- CPUInfo._L2.uiAssociativeWays = 8;
- CPUInfo._L2.uiLineSize = 32;
- break;
- case 0x83: // cfg = 0x83: code and data L2 cache present, 512 KB, 8 ways, 32 byte lines
- CPUInfo._L2.bPresent = true;
- strcpy(CPUInfo._L2.strSize, "512 KB"); /* Flawfinder: ignore */
- CPUInfo._L2.uiAssociativeWays = 8;
- CPUInfo._L2.uiLineSize = 32;
- break;
- case 0x84: // cfg = 0x84: code and data L2 cache present, 1024 KB, 8 ways, 32 byte lines
- CPUInfo._L2.bPresent = true;
- strcpy(CPUInfo._L2.strSize, "1 MB"); /* Flawfinder: ignore */
- CPUInfo._L2.uiAssociativeWays = 8;
- CPUInfo._L2.uiLineSize = 32;
- break;
- case 0x85: // cfg = 0x85: code and data L2 cache present, 2048 KB, 8 ways, 32 byte lines
- CPUInfo._L2.bPresent = true;
- strcpy(CPUInfo._L2.strSize, "2 MB"); /* Flawfinder: ignore */
- CPUInfo._L2.uiAssociativeWays = 8;
- CPUInfo._L2.uiLineSize = 32;
- break;
+ get_proc_cpuinfo();
}
-}
-
-FORCEINLINE static char *TranslateAssociativeWays(unsigned int uiWays, char *buf)
-{
- // We define 0xFFFFFFFF (= -1) as fully associative
- if (uiWays == ((unsigned int) -1))
- strcpy(buf, "fully associative"); /* Flawfinder: ignore */
- else
- {
- if (uiWays == 1) // A one way associative cache is just direct mapped
- strcpy(buf, "direct mapped"); /* Flawfinder: ignore */
- else if (uiWays == 0) // This should not happen...
- strcpy(buf, "unknown associative ways"); /* Flawfinder: ignore */
- else // The x-way associative cache
- sprintf(buf, "%d ways associative", uiWays); /* Flawfinder: ignore */
- }
- // To ease the function use we return the buffer
- return buf;
-}
-FORCEINLINE static void TranslateTLB(ProcessorTLB *tlb)
-{
- char buf[64]; /* Flawfinder: ignore */
-
- // We just check if the TLB is present
- if (tlb->bPresent)
- snprintf(tlb->strTLB,sizeof(tlb->strTLB), "%s page size, %s, %d entries", tlb->strPageSize, TranslateAssociativeWays(tlb->uiAssociativeWays, buf), tlb->uiEntries); /* Flawfinder: ignore */
- else
- strcpy(tlb->strTLB, "Not present"); /* Flawfinder: ignore */
-}
-FORCEINLINE static void TranslateCache(ProcessorCache *cache)
-{
- char buf[64]; /* Flawfinder: ignore */
-
- // We just check if the cache is present
- if (cache->bPresent)
- {
- // If present we construct the string
- snprintf(cache->strCache, sizeof(cache->strCache), "%s cache size, %s, %d bytes line size", cache->strSize, TranslateAssociativeWays(cache->uiAssociativeWays, buf), cache->uiLineSize); /* Flawfinder: ignore */
- if (cache->bSectored)
- strncat(cache->strCache, ", sectored", sizeof(cache->strCache)-strlen(cache->strCache)-1); /* Flawfinder: ignore */
- }
- else
- {
- // Else we just say "Not present"
- strcpy(cache->strCache, "Not present"); /* Flawfinder: ignore */
- }
-}
-
-// void CProcessor::TranslateProcessorConfiguration()
-// ==================================================
-// Private class function to translate the processor configuration values
-// to strings
-/////////////////////////////////////////////////////////////////////////
-void CProcessor::TranslateProcessorConfiguration()
-{
- // We just call the small functions defined above
- TranslateTLB(&CPUInfo._Data);
- TranslateTLB(&CPUInfo._Instruction);
-
- TranslateCache(&CPUInfo._Trace);
-
- TranslateCache(&CPUInfo._L1.Instruction);
- TranslateCache(&CPUInfo._L1.Data);
- TranslateCache(&CPUInfo._L2);
- TranslateCache(&CPUInfo._L3);
-}
-// void CProcessor::GetStandardProcessorConfiguration()
-// ====================================================
-// Private class function to read the standard processor configuration
-//////////////////////////////////////////////////////////////////////
-void CProcessor::GetStandardProcessorConfiguration()
-{
-#if LL_WINDOWS
- unsigned long eaxreg, ebxreg, ecxreg, edxreg;
-
- // We check if the CPUID function is available
- if (!CheckCPUIDPresence())
- return;
+ virtual ~LLProcessorInfoLinuxImpl() {}
+private:
- // First we check if the processor supports the standard
- // CPUID level 0x00000002
- if (CPUInfo.MaxSupportedLevel >= 2)
+ void get_proc_cpuinfo()
{
- // Now we go read the std. CPUID level 0x00000002 the first time
- unsigned long count, num = 255;
- for (count = 0; count < num; count++)
+ std::map< std::string, std::string > cpuinfo;
+ LLFILE* cpuinfo_fp = LLFile::fopen(CPUINFO_FILE, "rb");
+ if(cpuinfo_fp)
{
- __asm
+ char line[MAX_STRING];
+ memset(line, 0, MAX_STRING);
+ while(fgets(line, MAX_STRING, cpuinfo_fp))
{
- mov eax, 2
- cpuid
- mov eaxreg, eax
- mov ebxreg, ebx
- mov ecxreg, ecx
- mov edxreg, edx
- }
- // We have to repeat this reading for 'num' times
- num = eaxreg & 0xFF;
-
- // Then we call the big decode switch function
- DecodeProcessorConfiguration(eaxreg >> 8);
- DecodeProcessorConfiguration(eaxreg >> 16);
- DecodeProcessorConfiguration(eaxreg >> 24);
-
- // If ebx contains additional data we also decode it
- if ((ebxreg & 0x80000000) == 0)
- {
- DecodeProcessorConfiguration(ebxreg);
- DecodeProcessorConfiguration(ebxreg >> 8);
- DecodeProcessorConfiguration(ebxreg >> 16);
- DecodeProcessorConfiguration(ebxreg >> 24);
- }
- // And also the ecx register
- if ((ecxreg & 0x80000000) == 0)
- {
- DecodeProcessorConfiguration(ecxreg);
- DecodeProcessorConfiguration(ecxreg >> 8);
- DecodeProcessorConfiguration(ecxreg >> 16);
- DecodeProcessorConfiguration(ecxreg >> 24);
- }
- // At last the edx processor register
- if ((edxreg & 0x80000000) == 0)
- {
- DecodeProcessorConfiguration(edxreg);
- DecodeProcessorConfiguration(edxreg >> 8);
- DecodeProcessorConfiguration(edxreg >> 16);
- DecodeProcessorConfiguration(edxreg >> 24);
+ // /proc/cpuinfo on Linux looks like:
+ // name\t*: value\n
+ char* tabspot = strchr( line, '\t' );
+ if (tabspot == NULL)
+ continue;
+ char* colspot = strchr( tabspot, ':' );
+ if (colspot == NULL)
+ continue;
+ char* spacespot = strchr( colspot, ' ' );
+ if (spacespot == NULL)
+ continue;
+ char* nlspot = strchr( line, '\n' );
+ if (nlspot == NULL)
+ nlspot = line + strlen( line ); // Fallback to terminating NUL
+ std::string linename( line, tabspot );
+ std::string llinename(linename);
+ LLStringUtil::toLower(llinename);
+ std::string lineval( spacespot + 1, nlspot );
+ cpuinfo[ llinename ] = lineval;
}
+ fclose(cpuinfo_fp);
+ }
+# if LL_X86
+
+// *NOTE:Mani - eww, macros! srry.
+#define LLPI_SET_INFO_STRING(llpi_id, cpuinfo_id) \
+ if (!cpuinfo[cpuinfo_id].empty()) \
+ { setInfo(llpi_id, cpuinfo[cpuinfo_id]);}
+
+#define LLPI_SET_INFO_INT(llpi_id, cpuinfo_id) \
+ {\
+ S32 result; \
+ if (!cpuinfo[cpuinfo_id].empty() \
+ && LLStringUtil::convertToS32(cpuinfo[cpuinfo_id], result)) \
+ { setInfo(llpi_id, result);} \
+ }
+
+ F64 mhz;
+ if (LLStringUtil::convertToF64(cpuinfo["cpu mhz"], mhz)
+ && 200.0 < mhz && mhz < 10000.0)
+ {
+ setInfo(eFrequency,(F64)(mhz));
}
- }
-#endif
-}
-// void CProcessor::GetStandardProcessorExtensions()
-// =================================================
-// Private class function to read the standard processor extensions
-///////////////////////////////////////////////////////////////////
-void CProcessor::GetStandardProcessorExtensions()
-{
-#if LL_WINDOWS
- unsigned long ebxreg, edxreg;
+ LLPI_SET_INFO_STRING(eBrandName, "model name");
+ LLPI_SET_INFO_STRING(eVendor, "vendor_id");
- // We check if the CPUID command is available
- if (!CheckCPUIDPresence())
- return;
- // We just get the standard CPUID level 0x00000001 which should be
- // available on every x86 processor
- __asm
- {
- mov eax, 1
- cpuid
- mov ebxreg, ebx
- mov edxreg, edx
- }
-
- // Then we mask some bits
- CPUInfo._Ext.FPU_FloatingPointUnit = CheckBit(edxreg, 0);
- CPUInfo._Ext.VME_Virtual8086ModeEnhancements = CheckBit(edxreg, 1);
- CPUInfo._Ext.DE_DebuggingExtensions = CheckBit(edxreg, 2);
- CPUInfo._Ext.PSE_PageSizeExtensions = CheckBit(edxreg, 3);
- CPUInfo._Ext.TSC_TimeStampCounter = CheckBit(edxreg, 4);
- CPUInfo._Ext.MSR_ModelSpecificRegisters = CheckBit(edxreg, 5);
- CPUInfo._Ext.PAE_PhysicalAddressExtension = CheckBit(edxreg, 6);
- CPUInfo._Ext.MCE_MachineCheckException = CheckBit(edxreg, 7);
- CPUInfo._Ext.CX8_COMPXCHG8B_Instruction = CheckBit(edxreg, 8);
- CPUInfo._Ext.APIC_AdvancedProgrammableInterruptController = CheckBit(edxreg, 9);
- CPUInfo._Ext.APIC_ID = (ebxreg >> 24) & 0xFF;
- CPUInfo._Ext.SEP_FastSystemCall = CheckBit(edxreg, 11);
- CPUInfo._Ext.MTRR_MemoryTypeRangeRegisters = CheckBit(edxreg, 12);
- CPUInfo._Ext.PGE_PTE_GlobalFlag = CheckBit(edxreg, 13);
- CPUInfo._Ext.MCA_MachineCheckArchitecture = CheckBit(edxreg, 14);
- CPUInfo._Ext.CMOV_ConditionalMoveAndCompareInstructions = CheckBit(edxreg, 15);
- CPUInfo._Ext.FGPAT_PageAttributeTable = CheckBit(edxreg, 16);
- CPUInfo._Ext.PSE36_36bitPageSizeExtension = CheckBit(edxreg, 17);
- CPUInfo._Ext.PN_ProcessorSerialNumber = CheckBit(edxreg, 18);
- CPUInfo._Ext.CLFSH_CFLUSH_Instruction = CheckBit(edxreg, 19);
- CPUInfo._Ext.CLFLUSH_InstructionCacheLineSize = (ebxreg >> 8) & 0xFF;
- CPUInfo._Ext.DS_DebugStore = CheckBit(edxreg, 21);
- CPUInfo._Ext.ACPI_ThermalMonitorAndClockControl = CheckBit(edxreg, 22);
- CPUInfo._Ext.MMX_MultimediaExtensions = CheckBit(edxreg, 23);
- CPUInfo._Ext.FXSR_FastStreamingSIMD_ExtensionsSaveRestore = CheckBit(edxreg, 24);
- CPUInfo._Ext.SSE_StreamingSIMD_Extensions = CheckBit(edxreg, 25);
- CPUInfo._Ext.SSE2_StreamingSIMD2_Extensions = CheckBit(edxreg, 26);
- CPUInfo._Ext.Altivec_Extensions = false;
- CPUInfo._Ext.SS_SelfSnoop = CheckBit(edxreg, 27);
- CPUInfo._Ext.HT_HyperThreading = CheckBit(edxreg, 28);
- CPUInfo._Ext.HT_HyterThreadingSiblings = (ebxreg >> 16) & 0xFF;
- CPUInfo._Ext.TM_ThermalMonitor = CheckBit(edxreg, 29);
- CPUInfo._Ext.IA64_Intel64BitArchitecture = CheckBit(edxreg, 30);
-#endif
-}
+ LLPI_SET_INFO_INT(eStepping, "stepping");
+ LLPI_SET_INFO_INT(eModel, "model");
-// const ProcessorInfo *CProcessor::GetCPUInfo()
-// =============================================
-// Calls all the other detection function to create an detailed
-// processor information
-///////////////////////////////////////////////////////////////
-const ProcessorInfo *CProcessor::GetCPUInfo()
-{
-#if LL_WINDOWS
- unsigned long eaxreg, ebxreg, ecxreg, edxreg;
+
+ S32 family;
+ if (!cpuinfo["cpu family"].empty()
+ && LLStringUtil::convertToS32(cpuinfo["cpu family"], family))
+ {
+ setInfo(eFamily, family);
+ }
- // First of all we check if the CPUID command is available
- if (!CheckCPUIDPresence())
- return NULL;
-
- // We read the standard CPUID level 0x00000000 which should
- // be available on every x86 processor
- __asm
- {
- mov eax, 0
- cpuid
- mov eaxreg, eax
- mov ebxreg, ebx
- mov edxreg, edx
- mov ecxreg, ecx
- }
- // Then we connect the single register values to the vendor string
- *((unsigned long *) CPUInfo.strVendor) = ebxreg;
- *((unsigned long *) (CPUInfo.strVendor+4)) = edxreg;
- *((unsigned long *) (CPUInfo.strVendor+8)) = ecxreg;
- // Null terminate for string comparisons below.
- CPUInfo.strVendor[12] = 0;
-
- // We can also read the max. supported standard CPUID level
- CPUInfo.MaxSupportedLevel = eaxreg & 0xFFFF;
-
- // Then we read the ext. CPUID level 0x80000000
- __asm
- {
- mov eax, 0x80000000
- cpuid
- mov eaxreg, eax
- }
- // ...to check the max. supportted extended CPUID level
- CPUInfo.MaxSupportedExtendedLevel = eaxreg;
-
- // Then we switch to the specific processor vendors
- // See http://www.sandpile.org/ia32/cpuid.htm
- if (!strcmp(CPUInfo.strVendor, "GenuineIntel"))
- {
- AnalyzeIntelProcessor();
- }
- else if (!strcmp(CPUInfo.strVendor, "AuthenticAMD"))
- {
- AnalyzeAMDProcessor();
- }
- else if (!strcmp(CPUInfo.strVendor, "UMC UMC UMC"))
- {
- AnalyzeUnknownProcessor();
- }
- else if (!strcmp(CPUInfo.strVendor, "CyrixInstead"))
- {
- AnalyzeUnknownProcessor();
- }
- else if (!strcmp(CPUInfo.strVendor, "NexGenDriven"))
- {
- AnalyzeUnknownProcessor();
- }
- else if (!strcmp(CPUInfo.strVendor, "CentaurHauls"))
- {
- AnalyzeUnknownProcessor();
- }
- else if (!strcmp(CPUInfo.strVendor, "RiseRiseRise"))
- {
- AnalyzeUnknownProcessor();
- }
- else if (!strcmp(CPUInfo.strVendor, "SiS SiS SiS"))
- {
- AnalyzeUnknownProcessor();
- }
- else if (!strcmp(CPUInfo.strVendor, "GenuineTMx86"))
- {
- // Transmeta
- AnalyzeUnknownProcessor();
- }
- else if (!strcmp(CPUInfo.strVendor, "Geode by NSC"))
- {
- AnalyzeUnknownProcessor();
- }
- else
- {
- AnalyzeUnknownProcessor();
- }
-#endif
- // After all we return the class CPUInfo member var
- return (&CPUInfo);
-}
+ setInfo(eFamilyName, compute_CPUFamilyName(cpuinfo["vendor_id"].c_str(), family));
-#elif LL_SOLARIS
-#include <kstat.h>
+ // setInfo(eExtendedModel, getSysctlInt("machdep.cpu.extmodel"));
+ // setInfo(eBrandID, getSysctlInt("machdep.cpu.brand"));
+ // setInfo(eType, 0); // ? where to find this?
-// ======================
-// Class constructor:
-/////////////////////////
-CProcessor::CProcessor()
-{
- uqwFrequency = 0;
- strCPUName[0] = 0;
- memset(&CPUInfo, 0, sizeof(CPUInfo));
-}
-
-// unsigned __int64 CProcessor::GetCPUFrequency(unsigned int uiMeasureMSecs)
-// =========================================================================
-// Function to query the current CPU frequency
-////////////////////////////////////////////////////////////////////////////
-F64 CProcessor::GetCPUFrequency(unsigned int /*uiMeasureMSecs*/)
-{
- if(uqwFrequency == 0){
- GetCPUInfo();
- }
-
- return uqwFrequency;
-}
-
-// const ProcessorInfo *CProcessor::GetCPUInfo()
-// =============================================
-// Calls all the other detection function to create an detailed
-// processor information
-///////////////////////////////////////////////////////////////
-const ProcessorInfo *CProcessor::GetCPUInfo()
-{
- // In Solaris the CPU info is in the kstats
- // try "psrinfo" or "kstat cpu_info" to see all
- // that's available
- int ncpus=0, i;
- kstat_ctl_t *kc;
- kstat_t *ks;
- kstat_named_t *ksinfo, *ksi;
- kstat_t *CPU_stats_list;
-
- kc = kstat_open();
-
- if((int)kc == -1){
- llwarns << "kstat_open(0 failed!" << llendl;
- return (&CPUInfo);
- }
-
- for (ks = kc->kc_chain; ks != NULL; ks = ks->ks_next) {
- if (strncmp(ks->ks_module, "cpu_info", 8) == 0 &&
- strncmp(ks->ks_name, "cpu_info", 8) == 0)
- ncpus++;
- }
-
- if(ncpus < 1){
- llwarns << "No cpus found in kstats!" << llendl;
- return (&CPUInfo);
- }
-
- for (ks = kc->kc_chain; ks; ks = ks->ks_next) {
- if (strncmp(ks->ks_module, "cpu_info", 8) == 0
- && strncmp(ks->ks_name, "cpu_info", 8) == 0
- && kstat_read(kc, ks, NULL) != -1){
- CPU_stats_list = ks; // only looking at the first CPU
-
- break;
- }
- }
-
- if(ncpus > 1)
- snprintf(strCPUName, sizeof(strCPUName), "%d x ", ncpus);
-
- kstat_read(kc, CPU_stats_list, NULL);
- ksinfo = (kstat_named_t *)CPU_stats_list->ks_data;
- for(i=0; i < (int)(CPU_stats_list->ks_ndata); ++i){ // Walk the kstats for this cpu gathering what we need
- ksi = ksinfo++;
- if(!strcmp(ksi->name, "brand")){
- strncat(strCPUName, (char *)KSTAT_NAMED_STR_PTR(ksi),
- sizeof(strCPUName)-strlen(strCPUName)-1);
- strncat(CPUInfo.strFamily, (char *)KSTAT_NAMED_STR_PTR(ksi),
- sizeof(CPUInfo.strFamily)-strlen(CPUInfo.strFamily)-1);
- strncpy(CPUInfo.strBrandID, strCPUName,sizeof(CPUInfo.strBrandID)-1);
- CPUInfo.strBrandID[sizeof(CPUInfo.strBrandID)-1]='\0';
- // DEBUG llinfos << "CPU brand: " << strCPUName << llendl;
- continue;
- }
+ //setConfig(eCLFLUSHCacheLineSize, ((cpu_info[1] >> 8) & 0xff) * 8);
+ //setConfig(eAPICPhysicalID, (cpu_info[1] >> 24) & 0xff);
+ //setConfig(eCacheLineSize, getSysctlInt("machdep.cpu.cache.linesize"));
+ //setConfig(eL2Associativity, getSysctlInt("machdep.cpu.cache.L2_associativity"));
+ //setConfig(eCacheSizeK, getSysctlInt("machdep.cpu.cache.size"));
+
+ // Read extensions
+ std::string flags = " " + cpuinfo["flags"] + " ";
+ LLStringUtil::toLower(flags);
- if(!strcmp(ksi->name, "clock_MHz")){
-#if defined(__sparc)
- llinfos << "Raw kstat clock rate is: " << ksi->value.l << llendl;
- uqwFrequency = (F64)(ksi->value.l * 1000000);
-#else
- uqwFrequency = (F64)(ksi->value.i64 * 1000000);
-#endif
- //DEBUG llinfos << "CPU frequency: " << uqwFrequency << llendl;
- continue;
+ if( flags.find( " sse " ) != std::string::npos )
+ {
+ setExtension(cpu_feature_names[eSSE_Ext]);
}
-#if defined(__i386)
- if(!strcmp(ksi->name, "vendor_id")){
- strncpy(CPUInfo.strVendor, (char *)KSTAT_NAMED_STR_PTR(ksi), sizeof(CPUInfo.strVendor)-1);
- // DEBUG llinfos << "CPU vendor: " << CPUInfo.strVendor << llendl;
- continue;
+ if( flags.find( " sse2 " ) != std::string::npos )
+ {
+ setExtension(cpu_feature_names[eSSE2_Ext]);
}
-#endif
- }
-
- kstat_close(kc);
-
-#if defined(__sparc) // SPARC does not define a vendor string in kstat
- strncpy(CPUInfo.strVendor, "Sun Microsystems, Inc.", sizeof(CPUInfo.strVendor)-1);
-#endif
-
- // DEBUG llinfo << "The system has " << ncpus << " CPUs with a clock rate of " << uqwFrequency << "MHz." << llendl;
-
- return (&CPUInfo);
-}
-
-#else
-// LL_DARWIN
-
-#include <mach/machine.h>
-#include <sys/sysctl.h>
-
-static char *TranslateAssociativeWays(unsigned int uiWays, char *buf)
-{
- // We define 0xFFFFFFFF (= -1) as fully associative
- if (uiWays == ((unsigned int) -1))
- strcpy(buf, "fully associative"); /* Flawfinder: ignore */
- else
- {
- if (uiWays == 1) // A one way associative cache is just direct mapped
- strcpy(buf, "direct mapped"); /* Flawfinder: ignore */
- else if (uiWays == 0) // This should not happen...
- strcpy(buf, "unknown associative ways"); /* Flawfinder: ignore */
- else // The x-way associative cache
- sprintf(buf, "%d ways associative", uiWays); /* Flawfinder: ignore */
- }
- // To ease the function use we return the buffer
- return buf;
-}
-static void TranslateTLB(ProcessorTLB *tlb)
-{
- char buf[64]; /* Flawfinder: ignore */
-
- // We just check if the TLB is present
- if (tlb->bPresent)
- snprintf(tlb->strTLB, sizeof(tlb->strTLB), "%s page size, %s, %d entries", tlb->strPageSize, TranslateAssociativeWays(tlb->uiAssociativeWays, buf), tlb->uiEntries); /* Flawfinder: ignore */
- else
- strcpy(tlb->strTLB, "Not present"); /* Flawfinder: ignore */
-}
-static void TranslateCache(ProcessorCache *cache)
-{
- char buf[64]; /* Flawfinder: ignore */
-
- // We just check if the cache is present
- if (cache->bPresent)
- {
- // If present we construct the string
- snprintf(cache->strCache,sizeof(cache->strCache), "%s cache size, %s, %d bytes line size", cache->strSize, TranslateAssociativeWays(cache->uiAssociativeWays, buf), cache->uiLineSize); /* Flawfinder: ignore */
- if (cache->bSectored)
- strncat(cache->strCache, ", sectored", sizeof(cache->strCache)-strlen(cache->strCache)-1); /* Flawfinder: ignore */
- }
- else
- {
- // Else we just say "Not present"
- strcpy(cache->strCache, "Not present"); /* Flawfinder: ignore */
- }
-}
-
-// void CProcessor::TranslateProcessorConfiguration()
-// ==================================================
-// Private class function to translate the processor configuration values
-// to strings
-/////////////////////////////////////////////////////////////////////////
-void CProcessor::TranslateProcessorConfiguration()
-{
- // We just call the small functions defined above
- TranslateTLB(&CPUInfo._Data);
- TranslateTLB(&CPUInfo._Instruction);
-
- TranslateCache(&CPUInfo._Trace);
-
- TranslateCache(&CPUInfo._L1.Instruction);
- TranslateCache(&CPUInfo._L1.Data);
- TranslateCache(&CPUInfo._L2);
- TranslateCache(&CPUInfo._L3);
-}
-
-// CProcessor::CProcessor
-// ======================
-// Class constructor:
-/////////////////////////
-CProcessor::CProcessor()
-{
- uqwFrequency = 0;
- strCPUName[0] = 0;
- memset(&CPUInfo, 0, sizeof(CPUInfo));
-}
-
-// unsigned __int64 CProcessor::GetCPUFrequency(unsigned int uiMeasureMSecs)
-// =========================================================================
-// Function to query the current CPU frequency
-////////////////////////////////////////////////////////////////////////////
-F64 CProcessor::GetCPUFrequency(unsigned int /*uiMeasureMSecs*/)
-{
- U64 frequency = 0;
- size_t len = sizeof(frequency);
- if(sysctlbyname("hw.cpufrequency", &frequency, &len, NULL, 0) == 0)
- {
- uqwFrequency = (F64)frequency;
+# endif // LL_X86
}
-
- return uqwFrequency;
-}
-static bool hasFeature(const char *name)
-{
- bool result = false;
- int val = 0;
- size_t len = sizeof(val);
-
- if(sysctlbyname(name, &val, &len, NULL, 0) == 0)
+ std::string getCPUFeatureDescription() const
{
- if(val != 0)
- result = true;
- }
-
- return result;
-}
-
-// const ProcessorInfo *CProcessor::GetCPUInfo()
-// =============================================
-// Calls all the other detection function to create an detailed
-// processor information
-///////////////////////////////////////////////////////////////
-const ProcessorInfo *CProcessor::GetCPUInfo()
-{
- int pagesize = 0;
- int cachelinesize = 0;
- int l1icachesize = 0;
- int l1dcachesize = 0;
- int l2settings = 0;
- int l2cachesize = 0;
- int l3settings = 0;
- int l3cachesize = 0;
- int ncpu = 0;
- int cpusubtype = 0;
-
- // sysctl knows all.
- int mib[2];
- size_t len;
- mib[0] = CTL_HW;
-
- mib[1] = HW_PAGESIZE;
- len = sizeof(pagesize);
- sysctl(mib, 2, &pagesize, &len, NULL, 0);
+ std::ostringstream s;
- mib[1] = HW_CACHELINE;
- len = sizeof(cachelinesize);
- sysctl(mib, 2, &cachelinesize, &len, NULL, 0);
-
- mib[1] = HW_L1ICACHESIZE;
- len = sizeof(l1icachesize);
- sysctl(mib, 2, &l1icachesize, &len, NULL, 0);
-
- mib[1] = HW_L1DCACHESIZE;
- len = sizeof(l1dcachesize);
- sysctl(mib, 2, &l1dcachesize, &len, NULL, 0);
-
- mib[1] = HW_L2SETTINGS;
- len = sizeof(l2settings);
- sysctl(mib, 2, &l2settings, &len, NULL, 0);
-
- mib[1] = HW_L2CACHESIZE;
- len = sizeof(l2cachesize);
- sysctl(mib, 2, &l2cachesize, &len, NULL, 0);
-
- mib[1] = HW_L3SETTINGS;
- len = sizeof(l3settings);
- sysctl(mib, 2, &l3settings, &len, NULL, 0);
-
- mib[1] = HW_L3CACHESIZE;
- len = sizeof(l3cachesize);
- sysctl(mib, 2, &l3cachesize, &len, NULL, 0);
-
- mib[1] = HW_NCPU;
- len = sizeof(ncpu);
- sysctl(mib, 2, &ncpu, &len, NULL, 0);
-
- sysctlbyname("hw.cpusubtype", &cpusubtype, &len, NULL, 0);
-
- strCPUName[0] = 0;
-
- if((ncpu == 0) || (ncpu == 1))
- {
- // Uhhh...
- }
- else if(ncpu == 2)
- {
- strncat(strCPUName, "Dual ", sizeof(strCPUName)-strlen(strCPUName)-1); /* Flawfinder: ignore */
- }
- else
- {
- snprintf(strCPUName, sizeof(strCPUName), "%d x ", ncpu); /* Flawfinder: ignore */
- }
-
-#if __ppc__
- switch(cpusubtype)
- {
- case CPU_SUBTYPE_POWERPC_601:// ((cpu_subtype_t) 1)
- strncat(strCPUName, "PowerPC 601", sizeof(strCPUName)-strlen(strCPUName)-1); /* Flawfinder: ignore */
- strncat(CPUInfo.strFamily, "PowerPC", sizeof(CPUInfo.strFamily)-strlen(CPUInfo.strFamily)-1); /* Flawfinder: ignore */
-
- break;
- case CPU_SUBTYPE_POWERPC_602:// ((cpu_subtype_t) 2)
- strncat(strCPUName, "PowerPC 602", sizeof(strCPUName)-strlen(strCPUName)-1); /* Flawfinder: ignore */
- strncat(CPUInfo.strFamily, "PowerPC", sizeof(CPUInfo.strFamily)-strlen(CPUInfo.strFamily)-1); /* Flawfinder: ignore */
- break;
- case CPU_SUBTYPE_POWERPC_603:// ((cpu_subtype_t) 3)
- strncat(strCPUName, "PowerPC 603", sizeof(strCPUName)-strlen(strCPUName)-1); /* Flawfinder: ignore */
- strncat(CPUInfo.strFamily, "PowerPC", sizeof(CPUInfo.strFamily)-strlen(CPUInfo.strFamily)-1); /* Flawfinder: ignore */
- break;
- case CPU_SUBTYPE_POWERPC_603e:// ((cpu_subtype_t) 4)
- strncat(strCPUName, "PowerPC 603e", sizeof(strCPUName)-strlen(strCPUName)-1); /* Flawfinder: ignore */
- strncat(CPUInfo.strFamily, "PowerPC", sizeof(CPUInfo.strFamily)-strlen(CPUInfo.strFamily)-1); /* Flawfinder: ignore */
- break;
- case CPU_SUBTYPE_POWERPC_603ev:// ((cpu_subtype_t) 5)
- strncat(strCPUName, "PowerPC 603ev", sizeof(strCPUName)-strlen(strCPUName)-1); /* Flawfinder: ignore */
- strncat(CPUInfo.strFamily, "PowerPC", sizeof(CPUInfo.strFamily)-strlen(CPUInfo.strFamily)-1); /* Flawfinder: ignore */
- break;
- case CPU_SUBTYPE_POWERPC_604:// ((cpu_subtype_t) 6)
- strncat(strCPUName, "PowerPC 604", sizeof(strCPUName)-strlen(strCPUName)-1); /* Flawfinder: ignore */
- strncat(CPUInfo.strFamily, "PowerPC", sizeof(CPUInfo.strFamily)-strlen(CPUInfo.strFamily)-1); /* Flawfinder: ignore */
- break;
- case CPU_SUBTYPE_POWERPC_604e:// ((cpu_subtype_t) 7)
- strncat(strCPUName, "PowerPC 604e", sizeof(strCPUName)-strlen(strCPUName)-1); /* Flawfinder: ignore */
- strncat(CPUInfo.strFamily, "PowerPC", sizeof(CPUInfo.strFamily)-strlen(CPUInfo.strFamily)-1); /* Flawfinder: ignore */
- break;
- case CPU_SUBTYPE_POWERPC_620:// ((cpu_subtype_t) 8)
- strncat(strCPUName, "PowerPC 620", sizeof(strCPUName)-strlen(strCPUName)-1); /* Flawfinder: ignore */
- strncat(CPUInfo.strFamily, "PowerPC", sizeof(CPUInfo.strFamily)-strlen(CPUInfo.strFamily)-1); /* Flawfinder: ignore */
- break;
- case CPU_SUBTYPE_POWERPC_750:// ((cpu_subtype_t) 9)
- strncat(strCPUName, "PowerPC 750", sizeof(strCPUName)-strlen(strCPUName)-1); /* Flawfinder: ignore */
- strncat(CPUInfo.strFamily, "PowerPC G3", sizeof(CPUInfo.strFamily)-strlen(CPUInfo.strFamily)-1); /* Flawfinder: ignore */
- break;
- case CPU_SUBTYPE_POWERPC_7400:// ((cpu_subtype_t) 10)
- strncat(strCPUName, "PowerPC 7400", sizeof(strCPUName)-strlen(strCPUName)-1); /* Flawfinder: ignore */
- strncat(CPUInfo.strFamily, "PowerPC G4", sizeof(CPUInfo.strFamily)-strlen(CPUInfo.strFamily)-1); /* Flawfinder: ignore */
- break;
- case CPU_SUBTYPE_POWERPC_7450:// ((cpu_subtype_t) 11)
- strncat(strCPUName, "PowerPC 7450", sizeof(strCPUName)-strlen(strCPUName)-1); /* Flawfinder: ignore */
- strncat(CPUInfo.strFamily, "PowerPC G4", sizeof(CPUInfo.strFamily)-strlen(CPUInfo.strFamily)-1); /* Flawfinder: ignore */
- break;
- case CPU_SUBTYPE_POWERPC_970:// ((cpu_subtype_t) 100)
- strncat(strCPUName, "PowerPC 970", sizeof(strCPUName)-strlen(strCPUName)-1); /* Flawfinder: ignore */
- strncat(CPUInfo.strFamily, "PowerPC G5", sizeof(CPUInfo.strFamily)-strlen(CPUInfo.strFamily)-1); /* Flawfinder: ignore */
- break;
-
- default:
- strncat(strCPUName, "PowerPC (Unknown)", sizeof(strCPUName)-strlen(strCPUName)-1); /* Flawfinder: ignore */
- break;
- }
-
- CPUInfo._Ext.EMMX_MultimediaExtensions =
- CPUInfo._Ext.MMX_MultimediaExtensions =
- CPUInfo._Ext.SSE_StreamingSIMD_Extensions =
- CPUInfo._Ext.SSE2_StreamingSIMD2_Extensions = false;
-
- CPUInfo._Ext.Altivec_Extensions = hasFeature("hw.optional.altivec");
-
-#endif
-
-#if __i386__
- // MBW -- XXX -- TODO -- make this call AnalyzeIntelProcessor()?
- switch(cpusubtype)
- {
- default:
- strncat(strCPUName, "i386 (Unknown)", sizeof(strCPUName)-strlen(strCPUName)-1); /* Flawfinder: ignore */
- break;
- }
-
- CPUInfo._Ext.EMMX_MultimediaExtensions = hasFeature("hw.optional.mmx"); // MBW -- XXX -- this may be wrong...
- CPUInfo._Ext.MMX_MultimediaExtensions = hasFeature("hw.optional.mmx");
- CPUInfo._Ext.SSE_StreamingSIMD_Extensions = hasFeature("hw.optional.sse");
- CPUInfo._Ext.SSE2_StreamingSIMD2_Extensions = hasFeature("hw.optional.sse2");
- CPUInfo._Ext.Altivec_Extensions = false;
- CPUInfo._Ext.AA64_AMD64BitArchitecture = hasFeature("hw.optional.x86_64");
-
-#endif
-
- // Terse CPU info uses this string...
- strncpy(CPUInfo.strBrandID, strCPUName,sizeof(CPUInfo.strBrandID)-1); /* Flawfinder: ignore */
- CPUInfo.strBrandID[sizeof(CPUInfo.strBrandID)-1]='\0';
-
- // Fun cache config stuff...
-
- if(l1dcachesize != 0)
- {
- CPUInfo._L1.Data.bPresent = true;
- snprintf(CPUInfo._L1.Data.strSize, sizeof(CPUInfo._L1.Data.strSize), "%d KB", l1dcachesize / 1024); /* Flawfinder: ignore */
-// CPUInfo._L1.Data.uiAssociativeWays = ???;
- CPUInfo._L1.Data.uiLineSize = cachelinesize;
+ // *NOTE:Mani - This is for linux only.
+ LLFILE* cpuinfo = LLFile::fopen(CPUINFO_FILE, "rb");
+ if(cpuinfo)
+ {
+ char line[MAX_STRING];
+ memset(line, 0, MAX_STRING);
+ while(fgets(line, MAX_STRING, cpuinfo))
+ {
+ line[strlen(line)-1] = ' ';
+ s << line;
+ s << std::endl;
+ }
+ fclose(cpuinfo);
+ s << std::endl;
+ }
+ else
+ {
+ s << "Unable to collect processor information" << std::endl;
+ }
+ return s.str();
}
+
+};
- if(l1icachesize != 0)
- {
- CPUInfo._L1.Instruction.bPresent = true;
- snprintf(CPUInfo._L1.Instruction.strSize, sizeof(CPUInfo._L1.Instruction.strSize), "%d KB", l1icachesize / 1024); /* Flawfinder: ignore */
-// CPUInfo._L1.Instruction.uiAssociativeWays = ???;
- CPUInfo._L1.Instruction.uiLineSize = cachelinesize;
- }
- if(l2cachesize != 0)
- {
- CPUInfo._L2.bPresent = true;
- snprintf(CPUInfo._L2.strSize, sizeof(CPUInfo._L2.strSize), "%d KB", l2cachesize / 1024); /* Flawfinder: ignore */
-// CPUInfo._L2.uiAssociativeWays = ???;
- CPUInfo._L2.uiLineSize = cachelinesize;
- }
+#endif // LL_MSVC elif LL_DARWIN elif LL_LINUX
- if(l3cachesize != 0)
- {
- CPUInfo._L2.bPresent = true;
- snprintf(CPUInfo._L2.strSize, sizeof(CPUInfo._L2.strSize), "%d KB", l3cachesize / 1024); /* Flawfinder: ignore */
-// CPUInfo._L2.uiAssociativeWays = ???;
- CPUInfo._L2.uiLineSize = cachelinesize;
+//////////////////////////////////////////////////////
+// Interface definition
+LLProcessorInfo::LLProcessorInfo() : mImpl(NULL)
+{
+ // *NOTE:Mani - not thread safe.
+ if(!mImpl)
+ {
+#ifdef LL_MSVC
+ static LLProcessorInfoWindowsImpl the_impl;
+ mImpl = &the_impl;
+#elif LL_DARWIN
+ static LLProcessorInfoDarwinImpl the_impl;
+ mImpl = &the_impl;
+#else
+ static LLProcessorInfoLinuxImpl the_impl;
+ mImpl = &the_impl;
+#endif // LL_MSVC
}
-
- CPUInfo._Ext.FPU_FloatingPointUnit = hasFeature("hw.optional.floatingpoint");
-
-// printf("pagesize = 0x%x\n", pagesize);
-// printf("cachelinesize = 0x%x\n", cachelinesize);
-// printf("l1icachesize = 0x%x\n", l1icachesize);
-// printf("l1dcachesize = 0x%x\n", l1dcachesize);
-// printf("l2settings = 0x%x\n", l2settings);
-// printf("l2cachesize = 0x%x\n", l2cachesize);
-// printf("l3settings = 0x%x\n", l3settings);
-// printf("l3cachesize = 0x%x\n", l3cachesize);
-
- // After reading we translate the configuration to strings
- TranslateProcessorConfiguration();
-
- // After all we return the class CPUInfo member var
- return (&CPUInfo);
}
-#endif // LL_DARWIN
-// bool CProcessor::CPUInfoToText(char *strBuffer, unsigned int uiMaxLen)
-// ======================================================================
-// Gets the frequency and processor information and writes it to a string
-/////////////////////////////////////////////////////////////////////////
-bool CProcessor::CPUInfoToText(char *strBuffer, unsigned int uiMaxLen)
-{
-#define LENCHECK len = (unsigned int) strlen(buf); if (len >= uiMaxLen) return false; strcpy(strBuffer, buf); strBuffer += len; /*Flawfinder: ignore*/
-#define COPYADD(str) strcpy(buf, str); LENCHECK; /* Flawfinder: ignore */
-#define FORMATADD(format, var) sprintf(buf, format, var); LENCHECK; /* Flawfinder: ignore */
-#define BOOLADD(str, boolvar) COPYADD(str); if (boolvar) { COPYADD(" Yes\n"); } else { COPYADD(" No\n"); }
-
- char buf[1024]; /* Flawfinder: ignore */
- unsigned int len;
-
- // First we have to get the frequency
- GetCPUFrequency(50);
-
- // Then we get the processor information
- GetCPUInfo();
-
- // Now we construct the string (see the macros at function beginning)
- strBuffer[0] = 0;
-
- COPYADD("// CPU General Information\n//////////////////////////\n");
- FORMATADD("Processor name: %s\n", strCPUName);
- FORMATADD("Frequency: %.2f MHz\n\n", (float) uqwFrequency / 1000000.0f);
- FORMATADD("Vendor: %s\n", CPUInfo.strVendor);
- FORMATADD("Family: %s\n", CPUInfo.strFamily);
- FORMATADD("Extended family: %d\n", CPUInfo.uiExtendedFamily);
- FORMATADD("Model: %s\n", CPUInfo.strModel);
- FORMATADD("Extended model: %d\n", CPUInfo.uiExtendedModel);
- FORMATADD("Type: %s\n", CPUInfo.strType);
- FORMATADD("Brand ID: %s\n", CPUInfo.strBrandID);
- if (CPUInfo._Ext.PN_ProcessorSerialNumber)
- {
- FORMATADD("Processor Serial: %s\n", CPUInfo.strProcessorSerial);
- }
- else
- {
- COPYADD("Processor Serial: Disabled\n");
- }
-#if !LL_SOLARIS // NOTE: Why bother printing all this when it's irrelavent
-
- COPYADD("\n\n// CPU Configuration\n////////////////////\n");
- FORMATADD("L1 instruction cache: %s\n", CPUInfo._L1.Instruction.strCache);
- FORMATADD("L1 data cache: %s\n", CPUInfo._L1.Data.strCache);
- FORMATADD("L2 cache: %s\n", CPUInfo._L2.strCache);
- FORMATADD("L3 cache: %s\n", CPUInfo._L3.strCache);
- FORMATADD("Trace cache: %s\n", CPUInfo._Trace.strCache);
- FORMATADD("Instruction TLB: %s\n", CPUInfo._Instruction.strTLB);
- FORMATADD("Data TLB: %s\n", CPUInfo._Data.strTLB);
- FORMATADD("Max Supported CPUID-Level: 0x%08lX\n", CPUInfo.MaxSupportedLevel);
- FORMATADD("Max Supported Ext. CPUID-Level: 0x%08lX\n", CPUInfo.MaxSupportedExtendedLevel);
-
- COPYADD("\n\n// CPU Extensions\n/////////////////\n");
- BOOLADD("AA64 AMD 64-bit Architecture: ", CPUInfo._Ext.AA64_AMD64BitArchitecture);
- BOOLADD("ACPI Thermal Monitor And Clock Control: ", CPUInfo._Ext.ACPI_ThermalMonitorAndClockControl);
- BOOLADD("APIC Advanced Programmable Interrupt Controller: ", CPUInfo._Ext.APIC_AdvancedProgrammableInterruptController);
- FORMATADD(" APIC-ID: %d\n", CPUInfo._Ext.APIC_ID);
- BOOLADD("CLFSH CLFLUSH Instruction Presence: ", CPUInfo._Ext.CLFSH_CFLUSH_Instruction);
- FORMATADD(" CLFLUSH Instruction Cache Line Size: %d\n", CPUInfo._Ext.CLFLUSH_InstructionCacheLineSize);
- BOOLADD("CMOV Conditional Move And Compare Instructions: ", CPUInfo._Ext.CMOV_ConditionalMoveAndCompareInstructions);
- BOOLADD("CX8 COMPXCHG8B Instruction: ", CPUInfo._Ext.CX8_COMPXCHG8B_Instruction);
- BOOLADD("DE Debugging Extensions: ", CPUInfo._Ext.DE_DebuggingExtensions);
- BOOLADD("DS Debug Store: ", CPUInfo._Ext.DS_DebugStore);
- BOOLADD("FGPAT Page Attribute Table: ", CPUInfo._Ext.FGPAT_PageAttributeTable);
- BOOLADD("FPU Floating Point Unit: ", CPUInfo._Ext.FPU_FloatingPointUnit);
- BOOLADD("FXSR Fast Streaming SIMD Extensions Save/Restore:", CPUInfo._Ext.FXSR_FastStreamingSIMD_ExtensionsSaveRestore);
- BOOLADD("HT Hyper Threading: ", CPUInfo._Ext.HT_HyperThreading);
- BOOLADD("IA64 Intel 64-Bit Architecture: ", CPUInfo._Ext.IA64_Intel64BitArchitecture);
- BOOLADD("MCA Machine Check Architecture: ", CPUInfo._Ext.MCA_MachineCheckArchitecture);
- BOOLADD("MCE Machine Check Exception: ", CPUInfo._Ext.MCE_MachineCheckException);
- BOOLADD("MMX Multimedia Extensions: ", CPUInfo._Ext.MMX_MultimediaExtensions);
- BOOLADD("MMX+ Multimedia Extensions: ", CPUInfo._Ext.EMMX_MultimediaExtensions);
- BOOLADD("MSR Model Specific Registers: ", CPUInfo._Ext.MSR_ModelSpecificRegisters);
- BOOLADD("MTRR Memory Type Range Registers: ", CPUInfo._Ext.MTRR_MemoryTypeRangeRegisters);
- BOOLADD("PAE Physical Address Extension: ", CPUInfo._Ext.PAE_PhysicalAddressExtension);
- BOOLADD("PGE PTE Global Flag: ", CPUInfo._Ext.PGE_PTE_GlobalFlag);
- if (CPUInfo._Ext.PN_ProcessorSerialNumber)
- {
- FORMATADD("PN Processor Serial Number: %s\n", CPUInfo.strProcessorSerial);
- }
- else
- {
- COPYADD("PN Processor Serial Number: Disabled\n");
- }
- BOOLADD("PSE Page Size Extensions: ", CPUInfo._Ext.PSE_PageSizeExtensions);
- BOOLADD("PSE36 36-bit Page Size Extension: ", CPUInfo._Ext.PSE36_36bitPageSizeExtension);
- BOOLADD("SEP Fast System Call: ", CPUInfo._Ext.SEP_FastSystemCall);
- BOOLADD("SS Self Snoop: ", CPUInfo._Ext.SS_SelfSnoop);
- BOOLADD("SSE Streaming SIMD Extensions: ", CPUInfo._Ext.SSE_StreamingSIMD_Extensions);
- BOOLADD("SSE2 Streaming SIMD 2 Extensions: ", CPUInfo._Ext.SSE2_StreamingSIMD2_Extensions);
- BOOLADD("ALTVEC Altivec Extensions: ", CPUInfo._Ext.Altivec_Extensions);
- BOOLADD("TM Thermal Monitor: ", CPUInfo._Ext.TM_ThermalMonitor);
- BOOLADD("TSC Time Stamp Counter: ", CPUInfo._Ext.TSC_TimeStampCounter);
- BOOLADD("VME Virtual 8086 Mode Enhancements: ", CPUInfo._Ext.VME_Virtual8086ModeEnhancements);
- BOOLADD("3DNow! Instructions: ", CPUInfo._Ext._3DNOW_InstructionExtensions);
- BOOLADD("Enhanced 3DNow! Instructions: ", CPUInfo._Ext._E3DNOW_InstructionExtensions);
-#endif
- // Yippie!!!
- return true;
-}
+LLProcessorInfo::~LLProcessorInfo() {}
+F64 LLProcessorInfo::getCPUFrequency() const { return mImpl->getCPUFrequency(); }
+bool LLProcessorInfo::hasSSE() const { return mImpl->hasSSE(); }
+bool LLProcessorInfo::hasSSE2() const { return mImpl->hasSSE2(); }
+bool LLProcessorInfo::hasAltivec() const { return mImpl->hasAltivec(); }
+std::string LLProcessorInfo::getCPUFamilyName() const { return mImpl->getCPUFamilyName(); }
+std::string LLProcessorInfo::getCPUBrandName() const { return mImpl->getCPUBrandName(); }
+std::string LLProcessorInfo::getCPUFeatureDescription() const { return mImpl->getCPUFeatureDescription(); }
-// bool CProcessor::WriteInfoTextFile(const char *strFilename)
-// ===========================================================
-// Takes use of CProcessor::CPUInfoToText and saves the string to a
-// file
-///////////////////////////////////////////////////////////////////
-bool CProcessor::WriteInfoTextFile(const char *strFilename)
-{
- char buf[16384]; /* Flawfinder: ignore */
-
- // First we get the string
- if (!CPUInfoToText(buf, 16383))
- return false;
-
- // Then we create a new file (CREATE_ALWAYS)
- FILE *file = LLFile::fopen(strFilename, "w"); /* Flawfinder: ignore */
- if (!file)
- return false;
-
- // After that we write the string to the file
- unsigned long dwBytesToWrite, dwBytesWritten;
- dwBytesToWrite = (unsigned long) strlen(buf); /*Flawfinder: ignore*/
- dwBytesWritten = (unsigned long) fwrite(buf, 1, dwBytesToWrite, file);
- fclose(file);
- if (dwBytesToWrite != dwBytesWritten)
- return false;
-
- // Done
- return true;
-}
diff --git a/indra/llcommon/llprocessor.h b/indra/llcommon/llprocessor.h
index 6b966c5339..6364d3c8bb 100644
--- a/indra/llcommon/llprocessor.h
+++ b/indra/llcommon/llprocessor.h
@@ -2,194 +2,48 @@
* @file llprocessor.h
* @brief Code to figure out the processor. Originally by Benjamin Jurke.
*
- * $LicenseInfo:firstyear=2002&license=viewergpl$
- *
- * Copyright (c) 2002-2007, Linden Research, Inc.
- *
+ * $LicenseInfo:firstyear=2002&license=viewerlgpl$
* Second Life Viewer Source Code
- * The source code in this file ("Source Code") is provided by Linden Lab
- * to you under the terms of the GNU General Public License, version 2.0
- * ("GPL"), unless you have obtained a separate licensing agreement
- * ("Other License"), formally executed by you and Linden Lab. Terms of
- * the GPL can be found in doc/GPL-license.txt in this distribution, or
- * online at http://secondlife.com/developers/opensource/gplv2
+ * 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.
*
- * There are special exceptions to the terms and conditions of the GPL as
- * it is applied to this Source Code. View the full text of the exception
- * in the file doc/FLOSS-exception.txt in this software distribution, or
- * online at http://secondlife.com/developers/opensource/flossexception
+ * 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.
*
- * By copying, modifying or distributing this software, you acknowledge
- * that you have read and understood your obligations described above,
- * and agree to abide by those obligations.
+ * 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
*
- * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
- * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
- * COMPLETENESS OR PERFORMANCE.
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
* $/LicenseInfo$
*/
-// Author: Benjamin Jurke
-// File history: 27.02.2002 File created.
-///////////////////////////////////////////
-
#ifndef LLPROCESSOR_H
#define LLPROCESSOR_H
+class LLProcessorInfoImpl;
-// Options:
-///////////
-#if LL_WINDOWS
-#define PROCESSOR_FREQUENCY_MEASURE_AVAILABLE
-#endif
-
-#if LL_MSVC && _M_X64
-# define LL_X86_64 1
-# define LL_X86 1
-#elif LL_MSVC && _M_IX86
-# define LL_X86 1
-#elif LL_GNUC && ( defined(__amd64__) || defined(__x86_64__) )
-# define LL_X86_64 1
-# define LL_X86 1
-#elif LL_GNUC && ( defined(__i386__) )
-# define LL_X86 1
-#elif LL_GNUC && ( defined(__powerpc__) || defined(__ppc__) )
-# define LL_PPC 1
-#endif
-
-
-typedef struct ProcessorExtensions
-{
- bool FPU_FloatingPointUnit;
- bool VME_Virtual8086ModeEnhancements;
- bool DE_DebuggingExtensions;
- bool PSE_PageSizeExtensions;
- bool TSC_TimeStampCounter;
- bool MSR_ModelSpecificRegisters;
- bool PAE_PhysicalAddressExtension;
- bool MCE_MachineCheckException;
- bool CX8_COMPXCHG8B_Instruction;
- bool APIC_AdvancedProgrammableInterruptController;
- unsigned int APIC_ID;
- bool SEP_FastSystemCall;
- bool MTRR_MemoryTypeRangeRegisters;
- bool PGE_PTE_GlobalFlag;
- bool MCA_MachineCheckArchitecture;
- bool CMOV_ConditionalMoveAndCompareInstructions;
- bool FGPAT_PageAttributeTable;
- bool PSE36_36bitPageSizeExtension;
- bool PN_ProcessorSerialNumber;
- bool CLFSH_CFLUSH_Instruction;
- unsigned int CLFLUSH_InstructionCacheLineSize;
- bool DS_DebugStore;
- bool ACPI_ThermalMonitorAndClockControl;
- bool EMMX_MultimediaExtensions;
- bool MMX_MultimediaExtensions;
- bool FXSR_FastStreamingSIMD_ExtensionsSaveRestore;
- bool SSE_StreamingSIMD_Extensions;
- bool SSE2_StreamingSIMD2_Extensions;
- bool Altivec_Extensions;
- bool SS_SelfSnoop;
- bool HT_HyperThreading;
- unsigned int HT_HyterThreadingSiblings;
- bool TM_ThermalMonitor;
- bool IA64_Intel64BitArchitecture;
- bool _3DNOW_InstructionExtensions;
- bool _E3DNOW_InstructionExtensions;
- bool AA64_AMD64BitArchitecture;
-} ProcessorExtensions;
-
-typedef struct ProcessorCache
-{
- bool bPresent;
- char strSize[32]; /* Flawfinder: ignore */
- unsigned int uiAssociativeWays;
- unsigned int uiLineSize;
- bool bSectored;
- char strCache[128]; /* Flawfinder: ignore */
-} ProcessorCache;
-
-typedef struct ProcessorL1Cache
-{
- ProcessorCache Instruction;
- ProcessorCache Data;
-} ProcessorL1Cache;
-
-typedef struct ProcessorTLB
-{
- bool bPresent;
- char strPageSize[32]; /* Flawfinder: ignore */
- unsigned int uiAssociativeWays;
- unsigned int uiEntries;
- char strTLB[128]; /* Flawfinder: ignore */
-} ProcessorTLB;
-
-typedef struct ProcessorInfo
-{
- char strVendor[16]; /* Flawfinder: ignore */
- unsigned int uiFamily;
- unsigned int uiExtendedFamily;
- char strFamily[64]; /* Flawfinder: ignore */
- unsigned int uiModel;
- unsigned int uiExtendedModel;
- char strModel[128]; /* Flawfinder: ignore */
- unsigned int uiStepping;
- unsigned int uiType;
- char strType[64]; /* Flawfinder: ignore */
- unsigned int uiBrandID;
- char strBrandID[64]; /* Flawfinder: ignore */
- char strProcessorSerial[64]; /* Flawfinder: ignore */
- unsigned long MaxSupportedLevel;
- unsigned long MaxSupportedExtendedLevel;
- ProcessorExtensions _Ext;
- ProcessorL1Cache _L1;
- ProcessorCache _L2;
- ProcessorCache _L3;
- ProcessorCache _Trace;
- ProcessorTLB _Instruction;
- ProcessorTLB _Data;
-} ProcessorInfo;
-
-
-// CProcessor
-// ==========
-// Class for detecting the processor name, type and available
-// extensions as long as it's speed.
-/////////////////////////////////////////////////////////////
-class CProcessor
+class LL_COMMON_API LLProcessorInfo
{
-// Constructor / Destructor:
-////////////////////////////
public:
- CProcessor();
-
-// Private vars:
-////////////////
-public:
- F64 uqwFrequency;
- char strCPUName[128]; /* Flawfinder: ignore */
- ProcessorInfo CPUInfo;
-
-// Private functions:
-/////////////////////
+ LLProcessorInfo();
+ ~LLProcessorInfo();
+
+ F64 getCPUFrequency() const;
+ bool hasSSE() const;
+ bool hasSSE2() const;
+ bool hasAltivec() const;
+ std::string getCPUFamilyName() const;
+ std::string getCPUBrandName() const;
+ std::string getCPUFeatureDescription() const;
private:
- bool AnalyzeIntelProcessor();
- bool AnalyzeAMDProcessor();
- bool AnalyzeUnknownProcessor();
- bool CheckCPUIDPresence();
- void DecodeProcessorConfiguration(unsigned int cfg);
- void TranslateProcessorConfiguration();
- void GetStandardProcessorConfiguration();
- void GetStandardProcessorExtensions();
-
-// Public functions:
-////////////////////
-public:
- F64 GetCPUFrequency(unsigned int uiMeasureMSecs);
- const ProcessorInfo *GetCPUInfo();
- bool CPUInfoToText(char *strBuffer, unsigned int uiMaxLen);
- bool WriteInfoTextFile(const char *strFilename);
+ LLProcessorInfoImpl* mImpl;
};
-
-#endif
+#endif // LLPROCESSOR_H
diff --git a/indra/llcommon/llptrskiplist.h b/indra/llcommon/llptrskiplist.h
index 81c8ca3ef3..67c7cde352 100644
--- a/indra/llcommon/llptrskiplist.h
+++ b/indra/llcommon/llptrskiplist.h
@@ -2,30 +2,25 @@
* @file llptrskiplist.h
* @brief Skip list implementation.
*
- * $LicenseInfo:firstyear=2001&license=viewergpl$
- *
- * Copyright (c) 2001-2007, Linden Research, Inc.
- *
+ * $LicenseInfo:firstyear=2001&license=viewerlgpl$
* Second Life Viewer Source Code
- * The source code in this file ("Source Code") is provided by Linden Lab
- * to you under the terms of the GNU General Public License, version 2.0
- * ("GPL"), unless you have obtained a separate licensing agreement
- * ("Other License"), formally executed by you and Linden Lab. Terms of
- * the GPL can be found in doc/GPL-license.txt in this distribution, or
- * online at http://secondlife.com/developers/opensource/gplv2
+ * 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.
*
- * There are special exceptions to the terms and conditions of the GPL as
- * it is applied to this Source Code. View the full text of the exception
- * in the file doc/FLOSS-exception.txt in this software distribution, or
- * online at http://secondlife.com/developers/opensource/flossexception
+ * 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.
*
- * By copying, modifying or distributing this software, you acknowledge
- * that you have read and understood your obligations described above,
- * and agree to abide by those obligations.
+ * 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
*
- * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
- * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
- * COMPLETENESS OR PERFORMANCE.
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
* $/LicenseInfo$
*/
@@ -33,7 +28,9 @@
#define LL_LLPTRSKIPLIST_H
#include "llerror.h"
+#include "llrand.h"
//#include "vmath.h"
+#include "llrand.h"
/////////////////////////////////////////////
//
diff --git a/indra/llcommon/llptrskipmap.h b/indra/llcommon/llptrskipmap.h
index e505004b63..94bc71ec55 100644
--- a/indra/llcommon/llptrskipmap.h
+++ b/indra/llcommon/llptrskipmap.h
@@ -3,30 +3,25 @@
* @brief Just like a LLSkipMap, but since it's pointers, you can call
* deleteAllData
*
- * $LicenseInfo:firstyear=2003&license=viewergpl$
- *
- * Copyright (c) 2003-2007, Linden Research, Inc.
- *
+ * $LicenseInfo:firstyear=2003&license=viewerlgpl$
* Second Life Viewer Source Code
- * The source code in this file ("Source Code") is provided by Linden Lab
- * to you under the terms of the GNU General Public License, version 2.0
- * ("GPL"), unless you have obtained a separate licensing agreement
- * ("Other License"), formally executed by you and Linden Lab. Terms of
- * the GPL can be found in doc/GPL-license.txt in this distribution, or
- * online at http://secondlife.com/developers/opensource/gplv2
+ * 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.
*
- * There are special exceptions to the terms and conditions of the GPL as
- * it is applied to this Source Code. View the full text of the exception
- * in the file doc/FLOSS-exception.txt in this software distribution, or
- * online at http://secondlife.com/developers/opensource/flossexception
+ * 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.
*
- * By copying, modifying or distributing this software, you acknowledge
- * that you have read and understood your obligations described above,
- * and agree to abide by those obligations.
+ * 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
*
- * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
- * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
- * COMPLETENESS OR PERFORMANCE.
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
* $/LicenseInfo$
*/
#ifndef LL_LLPTRSKIPMAP_H
@@ -238,7 +233,8 @@ private:
template <class INDEX_T, class DATA_T, S32 BINARY_DEPTH>
inline LLPtrSkipMap<INDEX_T, DATA_T, BINARY_DEPTH>::LLPtrSkipMap()
: mInsertFirst(NULL),
- mEquals(defaultEquals)
+ mEquals(defaultEquals),
+ mNumberOfSteps(0)
{
if (BINARY_DEPTH < 2)
{
@@ -259,7 +255,8 @@ template <class INDEX_T, class DATA_T, S32 BINARY_DEPTH>
inline LLPtrSkipMap<INDEX_T, DATA_T, BINARY_DEPTH>::LLPtrSkipMap(insert_func insert_first,
equals_func equals)
: mInsertFirst(insert_first),
- mEquals(equals)
+ mEquals(equals),
+ mNumberOfSteps(0)
{
if (BINARY_DEPTH < 2)
{
diff --git a/indra/llcommon/llptrto.cpp b/indra/llcommon/llptrto.cpp
new file mode 100644
index 0000000000..b270291bd6
--- /dev/null
+++ b/indra/llcommon/llptrto.cpp
@@ -0,0 +1,102 @@
+/**
+ * @file llptrto.cpp
+ * @author Nat Goodspeed
+ * @date 2008-08-20
+ * @brief Test for llptrto.h
+ *
+ * $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$
+ */
+
+// Precompiled header
+#include "linden_common.h"
+// associated header
+#include "llptrto.h"
+// STL headers
+// std headers
+// external library headers
+#include <boost/type_traits/is_same.hpp>
+#include <boost/static_assert.hpp>
+// other Linden headers
+#include "llmemory.h"
+
+// a refcounted class
+class RCFoo: public LLRefCount
+{
+public:
+ RCFoo() {}
+};
+
+// a refcounted subclass
+class RCSubFoo: public RCFoo
+{
+public:
+ RCSubFoo() {}
+};
+
+// a refcounted class using the other refcount base class
+class TSRCFoo: public LLThreadSafeRefCount
+{
+public:
+ TSRCFoo() {}
+};
+
+// a non-refcounted class
+class Bar
+{
+public:
+ Bar() {}
+};
+
+// a non-refcounted subclass
+class SubBar: public Bar
+{
+public:
+ SubBar() {}
+};
+
+int main(int argc, char *argv[])
+{
+ // test LLPtrTo<>
+ BOOST_STATIC_ASSERT((boost::is_same<LLPtrTo<RCFoo>::type, LLPointer<RCFoo> >::value));
+ BOOST_STATIC_ASSERT((boost::is_same<LLPtrTo<RCSubFoo>::type, LLPointer<RCSubFoo> >::value));
+ BOOST_STATIC_ASSERT((boost::is_same<LLPtrTo<TSRCFoo>::type, LLPointer<TSRCFoo> >::value));
+ BOOST_STATIC_ASSERT((boost::is_same<LLPtrTo<Bar>::type, Bar*>::value));
+ BOOST_STATIC_ASSERT((boost::is_same<LLPtrTo<SubBar>::type, SubBar*>::value));
+ BOOST_STATIC_ASSERT((boost::is_same<LLPtrTo<int>::type, int*>::value));
+
+ // Test LLRemovePointer<>. Note that we remove both pointer variants from
+ // each kind of type, regardless of whether the variant makes sense.
+ BOOST_STATIC_ASSERT((boost::is_same<LLRemovePointer<RCFoo*>::type, RCFoo>::value));
+ BOOST_STATIC_ASSERT((boost::is_same<LLRemovePointer< LLPointer<RCFoo> >::type, RCFoo>::value));
+ BOOST_STATIC_ASSERT((boost::is_same<LLRemovePointer<RCSubFoo*>::type, RCSubFoo>::value));
+ BOOST_STATIC_ASSERT((boost::is_same<LLRemovePointer< LLPointer<RCSubFoo> >::type, RCSubFoo>::value));
+ BOOST_STATIC_ASSERT((boost::is_same<LLRemovePointer<TSRCFoo*>::type, TSRCFoo>::value));
+ BOOST_STATIC_ASSERT((boost::is_same<LLRemovePointer< LLPointer<TSRCFoo> >::type, TSRCFoo>::value));
+ BOOST_STATIC_ASSERT((boost::is_same<LLRemovePointer<Bar*>::type, Bar>::value));
+ BOOST_STATIC_ASSERT((boost::is_same<LLRemovePointer< LLPointer<Bar> >::type, Bar>::value));
+ BOOST_STATIC_ASSERT((boost::is_same<LLRemovePointer<SubBar*>::type, SubBar>::value));
+ BOOST_STATIC_ASSERT((boost::is_same<LLRemovePointer< LLPointer<SubBar> >::type, SubBar>::value));
+ BOOST_STATIC_ASSERT((boost::is_same<LLRemovePointer<int*>::type, int>::value));
+ BOOST_STATIC_ASSERT((boost::is_same<LLRemovePointer< LLPointer<int> >::type, int>::value));
+
+ return 0;
+}
diff --git a/indra/llcommon/llptrto.h b/indra/llcommon/llptrto.h
new file mode 100644
index 0000000000..7091d36f6b
--- /dev/null
+++ b/indra/llcommon/llptrto.h
@@ -0,0 +1,87 @@
+/**
+ * @file llptrto.h
+ * @author Nat Goodspeed
+ * @date 2008-08-19
+ * @brief LLPtrTo<TARGET> is a template helper to pick either TARGET* or -- when
+ * TARGET is a subclass of LLRefCount or LLThreadSafeRefCount --
+ * LLPointer<TARGET>. LLPtrTo<> chooses whichever pointer type is best.
+ *
+ * $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_LLPTRTO_H)
+#define LL_LLPTRTO_H
+
+#include "llpointer.h"
+#include "llrefcount.h" // LLRefCount
+#include "llthread.h" // LLThreadSafeRefCount
+#include <boost/type_traits/is_base_of.hpp>
+#include <boost/type_traits/remove_pointer.hpp>
+#include <boost/utility/enable_if.hpp>
+
+/**
+ * LLPtrTo<TARGET>::type is either of two things:
+ *
+ * * When TARGET is a subclass of either LLRefCount or LLThreadSafeRefCount,
+ * LLPtrTo<TARGET>::type is LLPointer<TARGET>.
+ * * Otherwise, LLPtrTo<TARGET>::type is TARGET*.
+ *
+ * This way, a class template can use LLPtrTo<TARGET>::type to select an
+ * appropriate pointer type to store.
+ */
+template <class T, class ENABLE=void>
+struct LLPtrTo
+{
+ typedef T* type;
+};
+
+/// specialize for subclasses of LLRefCount
+template <class T>
+struct LLPtrTo<T, typename boost::enable_if< boost::is_base_of<LLRefCount, T> >::type>
+{
+ typedef LLPointer<T> type;
+};
+
+/// specialize for subclasses of LLThreadSafeRefCount
+template <class T>
+struct LLPtrTo<T, typename boost::enable_if< boost::is_base_of<LLThreadSafeRefCount, T> >::type>
+{
+ typedef LLPointer<T> type;
+};
+
+/**
+ * LLRemovePointer<PTRTYPE>::type gets you the underlying (pointee) type.
+ */
+template <typename PTRTYPE>
+struct LLRemovePointer
+{
+ typedef typename boost::remove_pointer<PTRTYPE>::type type;
+};
+
+/// specialize for LLPointer<SOMECLASS>
+template <typename SOMECLASS>
+struct LLRemovePointer< LLPointer<SOMECLASS> >
+{
+ typedef SOMECLASS type;
+};
+
+#endif /* ! defined(LL_LLPTRTO_H) */
diff --git a/indra/llcommon/llqueuedthread.cpp b/indra/llcommon/llqueuedthread.cpp
index 8dfba0b6c5..efd9c4b68f 100644
--- a/indra/llcommon/llqueuedthread.cpp
+++ b/indra/llcommon/llqueuedthread.cpp
@@ -1,36 +1,33 @@
/**
* @file llqueuedthread.cpp
*
- * $LicenseInfo:firstyear=2004&license=viewergpl$
- *
- * Copyright (c) 2004-2007, Linden Research, Inc.
- *
+ * $LicenseInfo:firstyear=2004&license=viewerlgpl$
* Second Life Viewer Source Code
- * The source code in this file ("Source Code") is provided by Linden Lab
- * to you under the terms of the GNU General Public License, version 2.0
- * ("GPL"), unless you have obtained a separate licensing agreement
- * ("Other License"), formally executed by you and Linden Lab. Terms of
- * the GPL can be found in doc/GPL-license.txt in this distribution, or
- * online at http://secondlife.com/developers/opensource/gplv2
+ * Copyright (C) 2010, Linden Research, Inc.
*
- * There are special exceptions to the terms and conditions of the GPL as
- * it is applied to this Source Code. View the full text of the exception
- * in the file doc/FLOSS-exception.txt in this software distribution, or
- * online at http://secondlife.com/developers/opensource/flossexception
+ * 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.
*
- * By copying, modifying or distributing this software, you acknowledge
- * that you have read and understood your obligations described above,
- * and agree to abide by those obligations.
+ * 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.
*
- * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
- * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
- * COMPLETENESS OR PERFORMANCE.
+ * 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$
*/
#include "linden_common.h"
#include "llqueuedthread.h"
+
#include "llstl.h"
+#include "lltimer.h" // ms_sleep()
//============================================================================
@@ -39,7 +36,8 @@ LLQueuedThread::LLQueuedThread(const std::string& name, bool threaded) :
LLThread(name),
mThreaded(threaded),
mIdleThread(TRUE),
- mNextHandle(0)
+ mNextHandle(0),
+ mStarted(FALSE)
{
if (mThreaded)
{
@@ -50,6 +48,10 @@ LLQueuedThread::LLQueuedThread(const std::string& name, bool threaded) :
// MAIN THREAD
LLQueuedThread::~LLQueuedThread()
{
+ if (!mThreaded)
+ {
+ endThread();
+ }
shutdown();
// ~LLThread() will be called here
}
@@ -88,6 +90,7 @@ void LLQueuedThread::shutdown()
if (req->getStatus() == STATUS_QUEUED || req->getStatus() == STATUS_INPROGRESS)
{
++active_count;
+ req->setStatus(STATUS_ABORTED); // avoid assert in deleteRequest
}
req->deleteRequest();
}
@@ -103,6 +106,14 @@ void LLQueuedThread::shutdown()
// virtual
S32 LLQueuedThread::update(U32 max_time_ms)
{
+ if (!mStarted)
+ {
+ if (!mThreaded)
+ {
+ startThread();
+ mStarted = TRUE;
+ }
+ }
return updateQueue(max_time_ms);
}
@@ -116,8 +127,11 @@ S32 LLQueuedThread::updateQueue(U32 max_time_ms)
if (mThreaded)
{
pending = getPending();
+ if(pending > 0)
+ {
unpause();
}
+ }
else
{
while (pending > 0)
@@ -196,8 +210,9 @@ LLQueuedThread::handle_t LLQueuedThread::generateHandle()
{
mNextHandle++;
}
+ const LLQueuedThread::handle_t res = mNextHandle++;
unlockData();
- return mNextHandle++;
+ return res;
}
// MAIN thread
@@ -407,9 +422,11 @@ S32 LLQueuedThread::processNextRequest()
llassert_always(req->getStatus() == STATUS_QUEUED);
break;
}
+ U32 start_priority = 0 ;
if (req)
{
req->setStatus(STATUS_INPROGRESS);
+ start_priority = req->getPriority();
}
unlockData();
@@ -418,7 +435,7 @@ S32 LLQueuedThread::processNextRequest()
// safe to access req.
if (req)
{
- // process request
+ // process request
bool complete = req->processRequest();
if (complete)
@@ -439,35 +456,20 @@ S32 LLQueuedThread::processNextRequest()
lockData();
req->setStatus(STATUS_QUEUED);
mRequestQueue.insert(req);
- U32 priority = req->getPriority();
unlockData();
- if (priority < PRIORITY_NORMAL)
+ if (mThreaded && start_priority < PRIORITY_NORMAL)
{
ms_sleep(1); // sleep the thread a little
}
}
}
- S32 res;
S32 pending = getPending();
- if (pending == 0)
- {
- if (isQuitting())
- {
- res = -1; // exit thread
- }
- else
- {
- res = 0;
- }
- }
- else
- {
- res = pending;
- }
- return res;
+
+ return pending;
}
+// virtual
bool LLQueuedThread::runCondition()
{
// mRunCondition must be locked here
@@ -477,35 +479,53 @@ bool LLQueuedThread::runCondition()
return true;
}
+// virtual
void LLQueuedThread::run()
{
+ // call checPause() immediately so we don't try to do anything before the class is fully constructed
+ checkPause();
+ startThread();
+ mStarted = TRUE;
+
while (1)
{
// this will block on the condition until runCondition() returns true, the thread is unpaused, or the thread leaves the RUNNING state.
checkPause();
- if(isQuitting())
+ if (isQuitting())
+ {
+ endThread();
break;
-
- //llinfos << "QUEUED THREAD RUNNING, queue size = " << mRequestQueue.size() << llendl;
+ }
mIdleThread = FALSE;
+
+ threadedUpdate();
int res = processNextRequest();
if (res == 0)
{
mIdleThread = TRUE;
+ ms_sleep(1);
}
-
- if (res < 0) // finished working and want to exit
- {
- break;
- }
-
//LLThread::yield(); // thread should yield after each request
}
+ llinfos << "LLQueuedThread " << mName << " EXITING." << llendl;
+}
+
+// virtual
+void LLQueuedThread::startThread()
+{
+}
- llinfos << "QUEUED THREAD " << mName << " EXITING." << llendl;
+// virtual
+void LLQueuedThread::endThread()
+{
+}
+
+// virtual
+void LLQueuedThread::threadedUpdate()
+{
}
//============================================================================
diff --git a/indra/llcommon/llqueuedthread.h b/indra/llcommon/llqueuedthread.h
index a5919c8315..c75e0e2bbf 100644
--- a/indra/llcommon/llqueuedthread.h
+++ b/indra/llcommon/llqueuedthread.h
@@ -2,30 +2,25 @@
* @file llqueuedthread.h
* @brief
*
- * $LicenseInfo:firstyear=2004&license=viewergpl$
- *
- * Copyright (c) 2004-2007, Linden Research, Inc.
- *
+ * $LicenseInfo:firstyear=2004&license=viewerlgpl$
* Second Life Viewer Source Code
- * The source code in this file ("Source Code") is provided by Linden Lab
- * to you under the terms of the GNU General Public License, version 2.0
- * ("GPL"), unless you have obtained a separate licensing agreement
- * ("Other License"), formally executed by you and Linden Lab. Terms of
- * the GPL can be found in doc/GPL-license.txt in this distribution, or
- * online at http://secondlife.com/developers/opensource/gplv2
+ * Copyright (C) 2010, Linden Research, Inc.
*
- * There are special exceptions to the terms and conditions of the GPL as
- * it is applied to this Source Code. View the full text of the exception
- * in the file doc/FLOSS-exception.txt in this software distribution, or
- * online at http://secondlife.com/developers/opensource/flossexception
+ * 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.
*
- * By copying, modifying or distributing this software, you acknowledge
- * that you have read and understood your obligations described above,
- * and agree to abide by those obligations.
+ * 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.
*
- * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
- * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
- * COMPLETENESS OR PERFORMANCE.
+ * 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$
*/
@@ -46,7 +41,7 @@
// Note: ~LLQueuedThread is O(N) N=# of queued threads, assumed to be small
// It is assumed that LLQueuedThreads are rarely created/destroyed.
-class LLQueuedThread : public LLThread
+class LL_COMMON_API LLQueuedThread : public LLThread
{
//------------------------------------------------------------------------
public:
@@ -79,7 +74,7 @@ public:
//------------------------------------------------------------------------
public:
- class QueuedRequest : public LLSimpleHashEntry<handle_t>
+ class LL_COMMON_API QueuedRequest : public LLSimpleHashEntry<handle_t>
{
friend class LLQueuedThread;
@@ -147,6 +142,7 @@ protected:
}
};
+
//------------------------------------------------------------------------
public:
@@ -164,6 +160,9 @@ private:
virtual bool runCondition(void);
virtual void run(void);
+ virtual void startThread(void);
+ virtual void endThread(void);
+ virtual void threadedUpdate(void);
protected:
handle_t generateHandle();
@@ -198,6 +197,7 @@ public:
protected:
BOOL mThreaded; // if false, run on main thread and do updates during update()
+ BOOL mStarted; // required when mThreaded is false to call startThread() from update()
LLAtomic32<BOOL> mIdleThread; // request queue is empty (or we are quitting) and the thread is idle
typedef std::set<QueuedRequest*, queued_request_less> request_queue_t;
diff --git a/indra/llcommon/llrand.cpp b/indra/llcommon/llrand.cpp
new file mode 100644
index 0000000000..cb28a8f5c3
--- /dev/null
+++ b/indra/llcommon/llrand.cpp
@@ -0,0 +1,171 @@
+/**
+ * @file llrand.cpp
+ * @brief Global random generator.
+ *
+ * $LicenseInfo:firstyear=2000&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$
+ */
+
+#include "linden_common.h"
+
+#include "llrand.h"
+#include "lluuid.h"
+
+/**
+ * Through analysis, we have decided that we want to take values which
+ * are close enough to 1.0 to map back to 0.0. We came to this
+ * conclusion from noting that:
+ *
+ * [0.0, 1.0)
+ *
+ * when scaled to the integer set:
+ *
+ * [0, 4)
+ *
+ * there is some value close enough to 1.0 that when multiplying by 4,
+ * gets truncated to 4. Therefore:
+ *
+ * [0,1-eps] => 0
+ * [1,2-eps] => 1
+ * [2,3-eps] => 2
+ * [3,4-eps] => 3
+ *
+ * So 0 gets uneven distribution if we simply clamp. The actual
+ * clamp utilized in this file is to map values out of range back
+ * to 0 to restore uniform distribution.
+ *
+ * Also, for clamping floats when asking for a distribution from
+ * [0.0,g) we have determined that for values of g < 0.5, then
+ * rand*g=g, which is not the desired result. As above, we clamp to 0
+ * to restore uniform distribution.
+ */
+
+// *NOTE: The system rand implementation is probably not correct.
+#define LL_USE_SYSTEM_RAND 0
+
+#if LL_USE_SYSTEM_RAND
+#include <cstdlib>
+#endif
+
+#if LL_USE_SYSTEM_RAND
+class LLSeedRand
+{
+public:
+ LLSeedRand()
+ {
+#if LL_WINDOWS
+ srand(LLUUID::getRandomSeed());
+#else
+ srand48(LLUUID::getRandomSeed());
+#endif
+ }
+};
+static LLSeedRand sRandomSeeder;
+inline F64 ll_internal_random_double()
+{
+#if LL_WINDOWS
+ return (F64)rand() / (F64)RAND_MAX;
+#else
+ return drand48();
+#endif
+}
+inline F32 ll_internal_random_float()
+{
+#if LL_WINDOWS
+ return (F32)rand() / (F32)RAND_MAX;
+#else
+ return (F32)drand48();
+#endif
+}
+#else
+static LLRandLagFib2281 gRandomGenerator(LLUUID::getRandomSeed());
+inline F64 ll_internal_random_double()
+{
+ // *HACK: Through experimentation, we have found that dual core
+ // CPUs (or at least multi-threaded processes) seem to
+ // occasionally give an obviously incorrect random number -- like
+ // 5^15 or something. Sooooo, clamp it as described above.
+ F64 rv = gRandomGenerator();
+ if(!((rv >= 0.0) && (rv < 1.0))) return fmod(rv, 1.0);
+ return rv;
+}
+
+inline F32 ll_internal_random_float()
+{
+ // The clamping rules are described above.
+ F32 rv = (F32)gRandomGenerator();
+ if(!((rv >= 0.0f) && (rv < 1.0f))) return fmod(rv, 1.f);
+ return rv;
+}
+#endif
+
+S32 ll_rand()
+{
+ return ll_rand(RAND_MAX);
+}
+
+S32 ll_rand(S32 val)
+{
+ // The clamping rules are described above.
+ S32 rv = (S32)(ll_internal_random_double() * val);
+ if(rv == val) return 0;
+ return rv;
+}
+
+F32 ll_frand()
+{
+ return ll_internal_random_float();
+}
+
+F32 ll_frand(F32 val)
+{
+ // The clamping rules are described above.
+ F32 rv = ll_internal_random_float() * val;
+ if(val > 0)
+ {
+ if(rv >= val) return 0.0f;
+ }
+ else
+ {
+ if(rv <= val) return 0.0f;
+ }
+ return rv;
+}
+
+F64 ll_drand()
+{
+ return ll_internal_random_double();
+}
+
+F64 ll_drand(F64 val)
+{
+ // The clamping rules are described above.
+ F64 rv = ll_internal_random_double() * val;
+ if(val > 0)
+ {
+ if(rv >= val) return 0.0;
+ }
+ else
+ {
+ if(rv <= val) return 0.0;
+ }
+ return rv;
+}
diff --git a/indra/llcommon/llrand.h b/indra/llcommon/llrand.h
new file mode 100644
index 0000000000..ad317d5bf7
--- /dev/null
+++ b/indra/llcommon/llrand.h
@@ -0,0 +1,127 @@
+/**
+ * @file llrand.h
+ * @brief Information, functions, and typedefs for randomness.
+ *
+ * $LicenseInfo:firstyear=2000&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$
+ */
+
+#ifndef LL_LLRAND_H
+#define LL_LLRAND_H
+
+#include <boost/random/lagged_fibonacci.hpp>
+#include <boost/random/mersenne_twister.hpp>
+
+/**
+ * Use the boost random number generators if you want a stateful
+ * random numbers. If you want more random numbers, use the
+ * c-functions since they will generate faster/better randomness
+ * across the process.
+ *
+ * I tested some of the boost random engines, and picked a good double
+ * generator and a good integer generator. I also took some timings
+ * for them on linux using gcc 3.3.5. The harness also did some other
+ * fairly trivial operations to try to limit compiler optimizations,
+ * so these numbers are only good for relative comparisons.
+ *
+ * usec/inter algorithm
+ * 0.21 boost::minstd_rand0
+ * 0.039 boost:lagged_fibonacci19937
+ * 0.036 boost:lagged_fibonacci607
+ * 0.44 boost::hellekalek1995
+ * 0.44 boost::ecuyer1988
+ * 0.042 boost::rand48
+ * 0.043 boost::mt11213b
+ * 0.028 stdlib random()
+ * 0.05 stdlib lrand48()
+ * 0.034 stdlib rand()
+ * 0.020 the old & lame LLRand
+ */
+
+/**
+ *@brief Generate a float from [0, RAND_MAX).
+ */
+S32 LL_COMMON_API ll_rand();
+
+/**
+ *@brief Generate a float from [0, val) or (val, 0].
+ */
+S32 LL_COMMON_API ll_rand(S32 val);
+
+/**
+ *@brief Generate a float from [0, 1.0).
+ */
+F32 LL_COMMON_API ll_frand();
+
+/**
+ *@brief Generate a float from [0, val) or (val, 0].
+ */
+F32 LL_COMMON_API ll_frand(F32 val);
+
+/**
+ *@brief Generate a double from [0, 1.0).
+ */
+F64 LL_COMMON_API ll_drand();
+
+/**
+ *@brief Generate a double from [0, val) or (val, 0].
+ */
+F64 LL_COMMON_API ll_drand(F64 val);
+
+/**
+ * @brief typedefs for good boost lagged fibonacci.
+ * @see boost::lagged_fibonacci
+ *
+ * These generators will quickly generate doubles. Note the memory
+ * requirements, because they are somewhat high. I chose the smallest
+ * one, and one comparable in speed but higher periodicity without
+ * outrageous memory requirements.
+ * To use:
+ * LLRandLagFib607 foo((U32)time(NULL));
+ * double bar = foo();
+ */
+
+typedef boost::lagged_fibonacci607 LLRandLagFib607;
+/**<
+ * lengh of cycle: 2^32,000
+ * memory: 607*sizeof(double) (about 5K)
+ */
+
+typedef boost::lagged_fibonacci2281 LLRandLagFib2281;
+/**<
+ * lengh of cycle: 2^120,000
+ * memory: 2281*sizeof(double) (about 17K)
+ */
+
+/**
+ * @breif typedefs for a good boost mersenne twister implementation.
+ * @see boost::mersenne_twister
+ *
+ * This fairly quickly generates U32 values
+ * To use:
+ * LLRandMT19937 foo((U32)time(NULL));
+ * U32 bar = foo();
+ *
+ * lengh of cycle: 2^19,937-1
+ * memory: about 2496 bytes
+ */
+typedef boost::mt11213b LLRandMT19937;
+#endif
diff --git a/indra/llcommon/llrefcount.cpp b/indra/llcommon/llrefcount.cpp
new file mode 100644
index 0000000000..55d0c85cbd
--- /dev/null
+++ b/indra/llcommon/llrefcount.cpp
@@ -0,0 +1,54 @@
+/**
+ * @file llrefcount.cpp
+ * @brief Base class for reference counted objects for use with LLPointer
+ *
+ * $LicenseInfo:firstyear=2002&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$
+ */
+#include "linden_common.h"
+
+#include "llrefcount.h"
+
+#include "llerror.h"
+
+LLRefCount::LLRefCount(const LLRefCount& other)
+: mRef(0)
+{
+}
+
+LLRefCount& LLRefCount::operator=(const LLRefCount&)
+{
+ // do nothing, since ref count is specific to *this* reference
+ return *this;
+}
+
+LLRefCount::LLRefCount() :
+ mRef(0)
+{
+}
+
+LLRefCount::~LLRefCount()
+{
+ if (mRef != 0)
+ {
+ llerrs << "deleting non-zero reference" << llendl;
+ }
+}
diff --git a/indra/llcommon/llrefcount.h b/indra/llcommon/llrefcount.h
new file mode 100644
index 0000000000..19f008b15c
--- /dev/null
+++ b/indra/llcommon/llrefcount.h
@@ -0,0 +1,73 @@
+/**
+ * @file llrefcount.h
+ * @brief Base class for reference counted objects for use with LLPointer
+ *
+ * $LicenseInfo:firstyear=2002&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$
+ */
+#ifndef LLREFCOUNT_H
+#define LLREFCOUNT_H
+
+#include <boost/noncopyable.hpp>
+
+//----------------------------------------------------------------------------
+// RefCount objects should generally only be accessed by way of LLPointer<>'s
+// see llthread.h for LLThreadSafeRefCount
+//----------------------------------------------------------------------------
+
+class LL_COMMON_API LLRefCount
+{
+protected:
+ LLRefCount(const LLRefCount& other);
+ LLRefCount& operator=(const LLRefCount&);
+ virtual ~LLRefCount(); // use unref()
+
+public:
+ LLRefCount();
+
+ void ref() const
+ {
+ mRef++;
+ }
+
+ S32 unref() const
+ {
+ llassert(mRef >= 1);
+ if (0 == --mRef)
+ {
+ delete this;
+ return 0;
+ }
+ return mRef;
+ }
+
+ //NOTE: when passing around a const LLRefCount object, this can return different results
+ // at different types, since mRef is mutable
+ S32 getNumRefs() const
+ {
+ return mRef;
+ }
+
+private:
+ mutable S32 mRef;
+};
+
+#endif
diff --git a/indra/llcommon/llrun.cpp b/indra/llcommon/llrun.cpp
index 5d0e98ae2d..f5d3f302fa 100644
--- a/indra/llcommon/llrun.cpp
+++ b/indra/llcommon/llrun.cpp
@@ -4,30 +4,25 @@
* @date 2006-02-16
* @brief Implementation of the LLRunner and related classes
*
- * $LicenseInfo:firstyear=2006&license=viewergpl$
- *
- * Copyright (c) 2006-2007, Linden Research, Inc.
- *
+ * $LicenseInfo:firstyear=2006&license=viewerlgpl$
* Second Life Viewer Source Code
- * The source code in this file ("Source Code") is provided by Linden Lab
- * to you under the terms of the GNU General Public License, version 2.0
- * ("GPL"), unless you have obtained a separate licensing agreement
- * ("Other License"), formally executed by you and Linden Lab. Terms of
- * the GPL can be found in doc/GPL-license.txt in this distribution, or
- * online at http://secondlife.com/developers/opensource/gplv2
+ * 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.
*
- * There are special exceptions to the terms and conditions of the GPL as
- * it is applied to this Source Code. View the full text of the exception
- * in the file doc/FLOSS-exception.txt in this software distribution, or
- * online at http://secondlife.com/developers/opensource/flossexception
+ * 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.
*
- * By copying, modifying or distributing this software, you acknowledge
- * that you have read and understood your obligations described above,
- * and agree to abide by those obligations.
+ * 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
*
- * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
- * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
- * COMPLETENESS OR PERFORMANCE.
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
* $/LicenseInfo$
*/
diff --git a/indra/llcommon/llrun.h b/indra/llcommon/llrun.h
index 1c9f6c18ac..a117405366 100644
--- a/indra/llcommon/llrun.h
+++ b/indra/llcommon/llrun.h
@@ -4,30 +4,25 @@
* @date 2006-02-16
* @brief Declaration of LLRunner and LLRunnable classes.
*
- * $LicenseInfo:firstyear=2006&license=viewergpl$
- *
- * Copyright (c) 2006-2007, Linden Research, Inc.
- *
+ * $LicenseInfo:firstyear=2006&license=viewerlgpl$
* Second Life Viewer Source Code
- * The source code in this file ("Source Code") is provided by Linden Lab
- * to you under the terms of the GNU General Public License, version 2.0
- * ("GPL"), unless you have obtained a separate licensing agreement
- * ("Other License"), formally executed by you and Linden Lab. Terms of
- * the GPL can be found in doc/GPL-license.txt in this distribution, or
- * online at http://secondlife.com/developers/opensource/gplv2
+ * 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.
*
- * There are special exceptions to the terms and conditions of the GPL as
- * it is applied to this Source Code. View the full text of the exception
- * in the file doc/FLOSS-exception.txt in this software distribution, or
- * online at http://secondlife.com/developers/opensource/flossexception
+ * 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.
*
- * By copying, modifying or distributing this software, you acknowledge
- * that you have read and understood your obligations described above,
- * and agree to abide by those obligations.
+ * 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
*
- * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
- * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
- * COMPLETENESS OR PERFORMANCE.
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
* $/LicenseInfo$
*/
@@ -47,7 +42,7 @@ class LLRunnable;
* which are scheduled to run on a repeating or one time basis.
* @see LLRunnable
*/
-class LLRunner
+class LL_COMMON_API LLRunner
{
public:
/**
@@ -148,7 +143,7 @@ protected:
* something useful.
* @see LLRunner
*/
-class LLRunnable
+class LL_COMMON_API LLRunnable
{
public:
LLRunnable();
diff --git a/indra/llcommon/llsafehandle.h b/indra/llcommon/llsafehandle.h
new file mode 100644
index 0000000000..8d52d9bb15
--- /dev/null
+++ b/indra/llcommon/llsafehandle.h
@@ -0,0 +1,162 @@
+/**
+ * @file llsafehandle.h
+ * @brief Reference-counted object where Object() is valid, not NULL.
+ *
+ * $LicenseInfo:firstyear=2002&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$
+ */
+#ifndef LLSAFEHANDLE_H
+#define LLSAFEHANDLE_H
+
+#include "llerror.h" // *TODO: consider eliminating this
+
+// Expands LLPointer to return a pointer to a special instance of class Type instead of NULL.
+// This is useful in instances where operations on NULL pointers are semantically safe and/or
+// when error checking occurs at a different granularity or in a different part of the code
+// than when referencing an object via a LLSafeHandle.
+
+template <class Type>
+class LLSafeHandle
+{
+public:
+ LLSafeHandle() :
+ mPointer(NULL)
+ {
+ }
+
+ LLSafeHandle(Type* ptr) :
+ mPointer(NULL)
+ {
+ assign(ptr);
+ }
+
+ LLSafeHandle(const LLSafeHandle<Type>& ptr) :
+ mPointer(NULL)
+ {
+ assign(ptr.mPointer);
+ }
+
+ // support conversion up the type hierarchy. See Item 45 in Effective C++, 3rd Ed.
+ template<typename Subclass>
+ LLSafeHandle(const LLSafeHandle<Subclass>& ptr) :
+ mPointer(NULL)
+ {
+ assign(ptr.get());
+ }
+
+ ~LLSafeHandle()
+ {
+ unref();
+ }
+
+ const Type* operator->() const { return nonNull(mPointer); }
+ Type* operator->() { return nonNull(mPointer); }
+
+ Type* get() const { return mPointer; }
+ void clear() { assign(NULL); }
+ // we disallow these operations as they expose our null objects to direct manipulation
+ // and bypass the reference counting semantics
+ //const Type& operator*() const { return *nonNull(mPointer); }
+ //Type& operator*() { return *nonNull(mPointer); }
+
+ operator BOOL() const { return mPointer != NULL; }
+ operator bool() const { return mPointer != NULL; }
+ bool operator!() const { return mPointer == NULL; }
+ bool isNull() const { return mPointer == NULL; }
+ bool notNull() const { return mPointer != NULL; }
+
+
+ operator Type*() const { return mPointer; }
+ operator const Type*() const { return mPointer; }
+ bool operator !=(Type* ptr) const { return (mPointer != ptr); }
+ bool operator ==(Type* ptr) const { return (mPointer == ptr); }
+ bool operator ==(const LLSafeHandle<Type>& ptr) const { return (mPointer == ptr.mPointer); }
+ bool operator < (const LLSafeHandle<Type>& ptr) const { return (mPointer < ptr.mPointer); }
+ bool operator > (const LLSafeHandle<Type>& ptr) const { return (mPointer > ptr.mPointer); }
+
+ LLSafeHandle<Type>& operator =(Type* ptr)
+ {
+ assign(ptr);
+ return *this;
+ }
+
+ LLSafeHandle<Type>& operator =(const LLSafeHandle<Type>& ptr)
+ {
+ assign(ptr.mPointer);
+ return *this;
+ }
+
+ // support assignment up the type hierarchy. See Item 45 in Effective C++, 3rd Ed.
+ template<typename Subclass>
+ LLSafeHandle<Type>& operator =(const LLSafeHandle<Subclass>& ptr)
+ {
+ assign(ptr.get());
+ return *this;
+ }
+
+public:
+ typedef Type* (*NullFunc)();
+ static const NullFunc sNullFunc;
+
+protected:
+ void ref()
+ {
+ if (mPointer)
+ {
+ mPointer->ref();
+ }
+ }
+
+ void unref()
+ {
+ if (mPointer)
+ {
+ Type *tempp = mPointer;
+ mPointer = NULL;
+ tempp->unref();
+ if (mPointer != NULL)
+ {
+ llwarns << "Unreference did assignment to non-NULL because of destructor" << llendl;
+ unref();
+ }
+ }
+ }
+
+ void assign(Type* ptr)
+ {
+ if( mPointer != ptr )
+ {
+ unref();
+ mPointer = ptr;
+ ref();
+ }
+ }
+
+ static Type* nonNull(Type* ptr)
+ {
+ return ptr == NULL ? sNullFunc() : ptr;
+ }
+
+protected:
+ Type* mPointer;
+};
+
+#endif
diff --git a/indra/llcommon/llsd.cpp b/indra/llcommon/llsd.cpp
index ecca4c9b71..6ca0737445 100644
--- a/indra/llcommon/llsd.cpp
+++ b/indra/llcommon/llsd.cpp
@@ -2,30 +2,25 @@
* @file llsd.cpp
* @brief LLSD flexible data system
*
- * $LicenseInfo:firstyear=2005&license=viewergpl$
- *
- * Copyright (c) 2005-2007, Linden Research, Inc.
- *
+ * $LicenseInfo:firstyear=2005&license=viewerlgpl$
* Second Life Viewer Source Code
- * The source code in this file ("Source Code") is provided by Linden Lab
- * to you under the terms of the GNU General Public License, version 2.0
- * ("GPL"), unless you have obtained a separate licensing agreement
- * ("Other License"), formally executed by you and Linden Lab. Terms of
- * the GPL can be found in doc/GPL-license.txt in this distribution, or
- * online at http://secondlife.com/developers/opensource/gplv2
+ * Copyright (C) 2010, Linden Research, Inc.
*
- * There are special exceptions to the terms and conditions of the GPL as
- * it is applied to this Source Code. View the full text of the exception
- * in the file doc/FLOSS-exception.txt in this software distribution, or
- * online at http://secondlife.com/developers/opensource/flossexception
+ * 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.
*
- * By copying, modifying or distributing this software, you acknowledge
- * that you have read and understood your obligations described above,
- * and agree to abide by those obligations.
+ * 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.
*
- * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
- * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
- * COMPLETENESS OR PERFORMANCE.
+ * 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$
*/
@@ -42,10 +37,11 @@
#endif
#ifdef NAME_UNNAMED_NAMESPACE
-namespace LLSDUnnamedNamespace {
+namespace LLSDUnnamedNamespace
#else
-namespace {
+namespace
#endif
+{
class ImplMap;
class ImplArray;
}
@@ -127,10 +123,10 @@ public:
virtual void erase(Integer) { }
virtual const LLSD& ref(Integer) const { return undef(); }
- virtual LLSD::map_const_iterator beginMap() const { return LLSD::map_const_iterator(); }
- virtual LLSD::map_const_iterator endMap() const { return LLSD::map_const_iterator(); }
- virtual LLSD::array_const_iterator beginArray() const { return LLSD::array_const_iterator(); }
- virtual LLSD::array_const_iterator endArray() const { return LLSD::array_const_iterator(); }
+ virtual LLSD::map_const_iterator beginMap() const { return endMap(); }
+ virtual LLSD::map_const_iterator endMap() const { static const std::map<String, LLSD> empty; return empty.end(); }
+ virtual LLSD::array_const_iterator beginArray() const { return endArray(); }
+ virtual LLSD::array_const_iterator endArray() const { static const std::vector<LLSD> empty; return empty.end(); }
static const LLSD& undef();
@@ -139,10 +135,11 @@ public:
};
#ifdef NAME_UNNAMED_NAMESPACE
-namespace LLSDUnnamedNamespace {
+namespace LLSDUnnamedNamespace
#else
-namespace {
+namespace
#endif
+{
template<LLSD::Type T, class Data, class DataRef = Data>
class ImplBase : public LLSD::Impl
///< This class handles most of the work for a subclass of Impl
@@ -159,6 +156,7 @@ namespace {
virtual LLSD::Type type() const { return T; }
+ using LLSD::Impl::assign; // Unhiding base class virtuals...
virtual void assign(LLSD::Impl*& var, DataRef value) {
if (shared())
{
@@ -185,6 +183,11 @@ namespace {
};
LLSD::String ImplBoolean::asString() const
+ // *NOTE: The reason that false is not converted to "false" is
+ // because that would break roundtripping,
+ // e.g. LLSD(false).asString().asBoolean(). There are many
+ // reasons for wanting LLSD("false").asBoolean() == true, such
+ // as "everything else seems to work that way".
{ return mValue ? "true" : ""; }
@@ -341,8 +344,12 @@ namespace {
virtual LLSD::Boolean asBoolean() const { return !mData.empty(); }
virtual bool has(const LLSD::String&) const;
+
+ using LLSD::Impl::get; // Unhiding get(LLSD::Integer)
+ using LLSD::Impl::erase; // Unhiding erase(LLSD::Integer)
+ using LLSD::Impl::ref; // Unhiding ref(LLSD::Integer)
virtual LLSD get(const LLSD::String&) const;
- void insert(const LLSD::String& k, const LLSD& v);
+ void insert(const LLSD::String& k, const LLSD& v);
virtual void erase(const LLSD::String&);
LLSD& ref(const LLSD::String&);
virtual const LLSD& ref(const LLSD::String&) const;
@@ -426,6 +433,9 @@ namespace {
virtual LLSD::Boolean asBoolean() const { return !mData.empty(); }
+ using LLSD::Impl::get; // Unhiding get(LLSD::String)
+ using LLSD::Impl::erase; // Unhiding erase(LLSD::String)
+ using LLSD::Impl::ref; // Unhiding ref(LLSD::String)
virtual int size() const;
virtual LLSD get(LLSD::Integer) const;
void set(LLSD::Integer, const LLSD&);
@@ -480,7 +490,9 @@ namespace {
void ImplArray::insert(LLSD::Integer i, const LLSD& v)
{
- if (i < 0) { return; }
+ if (i < 0) {
+ return;
+ }
DataVector::size_type index = i;
if (index >= mData.size())
@@ -650,10 +662,11 @@ U32 LLSD::Impl::sOutstandingCount = 0;
#ifdef NAME_UNNAMED_NAMESPACE
-namespace LLSDUnnamedNamespace {
+namespace LLSDUnnamedNamespace
#else
-namespace {
+namespace
#endif
+{
inline LLSD::Impl& safe(LLSD::Impl* impl)
{ return LLSD::Impl::safe(impl); }
@@ -730,9 +743,13 @@ LLSD LLSD::emptyMap()
bool LLSD::has(const String& k) const { return safe(impl).has(k); }
LLSD LLSD::get(const String& k) const { return safe(impl).get(k); }
+void LLSD::insert(const String& k, const LLSD& v) { makeMap(impl).insert(k, v); }
-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);
+ return *this;
+ }
void LLSD::erase(const String& k) { makeMap(impl).erase(k); }
LLSD& LLSD::operator[](const String& k)
@@ -752,9 +769,13 @@ int LLSD::size() const { return safe(impl).size(); }
LLSD LLSD::get(Integer i) const { return safe(impl).get(i); }
void LLSD::set(Integer i, const LLSD& v){ makeArray(impl).set(i, v); }
+void LLSD::insert(Integer i, const LLSD& v) { makeArray(impl).insert(i, v); }
-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);
+ return *this;
+ }
void LLSD::append(const LLSD& v) { makeArray(impl).append(v); }
void LLSD::erase(Integer i) { makeArray(impl).erase(i); }
@@ -780,9 +801,15 @@ static const char *llsd_dump(const LLSD &llsd, bool useXMLFormat)
{
std::ostringstream out;
if (useXMLFormat)
- out << LLSDXMLStreamer(llsd);
+ {
+ LLSDXMLStreamer xml_streamer(llsd);
+ out << xml_streamer;
+ }
else
- out << LLSDNotationStreamer(llsd);
+ {
+ LLSDNotationStreamer notation_streamer(llsd);
+ out << notation_streamer;
+ }
out_string = out.str();
}
int len = out_string.length();
diff --git a/indra/llcommon/llsd.h b/indra/llcommon/llsd.h
index 1ba57b1e95..90d0f97873 100644
--- a/indra/llcommon/llsd.h
+++ b/indra/llcommon/llsd.h
@@ -2,30 +2,25 @@
* @file llsd.h
* @brief LLSD flexible data system.
*
- * $LicenseInfo:firstyear=2005&license=viewergpl$
- *
- * Copyright (c) 2005-2007, Linden Research, Inc.
- *
+ * $LicenseInfo:firstyear=2005&license=viewerlgpl$
* Second Life Viewer Source Code
- * The source code in this file ("Source Code") is provided by Linden Lab
- * to you under the terms of the GNU General Public License, version 2.0
- * ("GPL"), unless you have obtained a separate licensing agreement
- * ("Other License"), formally executed by you and Linden Lab. Terms of
- * the GPL can be found in doc/GPL-license.txt in this distribution, or
- * online at http://secondlife.com/developers/opensource/gplv2
+ * 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.
*
- * There are special exceptions to the terms and conditions of the GPL as
- * it is applied to this Source Code. View the full text of the exception
- * in the file doc/FLOSS-exception.txt in this software distribution, or
- * online at http://secondlife.com/developers/opensource/flossexception
+ * 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.
*
- * By copying, modifying or distributing this software, you acknowledge
- * that you have read and understood your obligations described above,
- * and agree to abide by those obligations.
+ * 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
*
- * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
- * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
- * COMPLETENESS OR PERFORMANCE.
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
* $/LicenseInfo$
*/
@@ -40,7 +35,7 @@
#include "lldate.h"
#include "lluri.h"
-#include "../llmath/lluuid.h"
+#include "lluuid.h"
/**
LLSD provides a flexible data system similar to the data facilities of
@@ -88,7 +83,7 @@
@nosubgrouping
*/
-class LLSD
+class LL_COMMON_API LLSD
{
public:
LLSD(); ///< initially Undefined
@@ -224,6 +219,7 @@ public:
LLSD get(const String&) const;
void insert(const String&, const LLSD&);
void erase(const String&);
+ LLSD& with(const String&, const LLSD&);
LLSD& operator[](const String&);
LLSD& operator[](const char* c) { return (*this)[String(c)]; }
@@ -240,6 +236,7 @@ public:
void insert(Integer, const LLSD&);
void append(const LLSD&);
void erase(Integer);
+ LLSD& with(Integer, const LLSD&);
const LLSD& operator[](Integer) const;
LLSD& operator[](Integer);
@@ -386,7 +383,7 @@ struct llsd_select_string : public std::unary_function<LLSD, LLSD::String>
}
};
-std::ostream& operator<<(std::ostream& s, const LLSD& llsd);
+LL_COMMON_API std::ostream& operator<<(std::ostream& s, const LLSD& llsd);
/** QUESTIONS & TO DOS
- Would Binary be more convenient as usigned char* buffer semantics?
@@ -394,7 +391,7 @@ std::ostream& operator<<(std::ostream& s, const LLSD& llsd);
- as UTF8 encoded strings (making not like UUID<->String)
- as Base64 or Base96 encoded (making like UUID<->String)
- Conversions to std::string and LLUUID do not result in easy assignment
- to std::string, LLString or LLUUID due to non-unique conversion paths
+ to std::string, std::string or LLUUID due to non-unique conversion paths
*/
#endif // LL_LLSD_NEW_H
diff --git a/indra/llcommon/llsdserialize.cpp b/indra/llcommon/llsdserialize.cpp
index 6f4a49180d..10f460e8a6 100644
--- a/indra/llcommon/llsdserialize.cpp
+++ b/indra/llcommon/llsdserialize.cpp
@@ -4,40 +4,35 @@
* @date 2006-03-05
* @brief Implementation of LLSD parsers and formatters
*
- * $LicenseInfo:firstyear=2006&license=viewergpl$
- *
- * Copyright (c) 2006-2007, Linden Research, Inc.
- *
+ * $LicenseInfo:firstyear=2006&license=viewerlgpl$
* Second Life Viewer Source Code
- * The source code in this file ("Source Code") is provided by Linden Lab
- * to you under the terms of the GNU General Public License, version 2.0
- * ("GPL"), unless you have obtained a separate licensing agreement
- * ("Other License"), formally executed by you and Linden Lab. Terms of
- * the GPL can be found in doc/GPL-license.txt in this distribution, or
- * online at http://secondlife.com/developers/opensource/gplv2
+ * 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.
*
- * There are special exceptions to the terms and conditions of the GPL as
- * it is applied to this Source Code. View the full text of the exception
- * in the file doc/FLOSS-exception.txt in this software distribution, or
- * online at http://secondlife.com/developers/opensource/flossexception
+ * 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.
*
- * By copying, modifying or distributing this software, you acknowledge
- * that you have read and understood your obligations described above,
- * and agree to abide by those obligations.
+ * 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
*
- * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
- * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
- * COMPLETENESS OR PERFORMANCE.
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
* $/LicenseInfo$
*/
#include "linden_common.h"
#include "llsdserialize.h"
-#include "llmemory.h"
+#include "llpointer.h"
#include "llstreamtools.h" // for fullread
#include <iostream>
-#include "apr-1/apr_base64.h"
+#include "apr_base64.h"
#if !LL_WINDOWS
#include <netinet/in.h> // htonl & ntohl
@@ -76,7 +71,7 @@ void LLSDSerialize::serialize(const LLSD& sd, std::ostream& str, ELLSD_Serialize
break;
default:
- llwarns << "serialize request for unkown ELLSD_Serialize" << llendl;
+ llwarns << "serialize request for unknown ELLSD_Serialize" << llendl;
}
if (f.notNull())
@@ -146,12 +141,15 @@ bool LLSDSerialize::deserialize(LLSD& sd, std::istream& str, S32 max_bytes)
* Create the parser as appropriate
*/
if (legacy_no_header)
- {
- LLSDXMLParser* x = new LLSDXMLParser;
- x->parsePart(hdr_buf, inbuf);
- p = x;
+ { // Create a LLSD XML parser, and parse the first chunk read above
+ LLSDXMLParser* x = new LLSDXMLParser();
+ x->parsePart(hdr_buf, inbuf); // Parse the first part that was already read
+ x->parseLines(str, sd); // Parse the rest of it
+ delete x;
+ return true;
}
- else if (header == LLSD_BINARY_HEADER)
+
+ if (header == LLSD_BINARY_HEADER)
{
p = new LLSDBinaryParser;
}
@@ -300,7 +298,8 @@ static const char BINARY_FALSE_SERIAL = '0';
/**
* LLSDParser
*/
-LLSDParser::LLSDParser() : mCheckLimits(true), mMaxBytesLeft(0)
+LLSDParser::LLSDParser()
+ : mCheckLimits(true), mMaxBytesLeft(0), mParseLines(false)
{
}
@@ -316,6 +315,15 @@ S32 LLSDParser::parse(std::istream& istr, LLSD& data, S32 max_bytes)
}
+// Parse using routine to get() lines, faster than parse()
+S32 LLSDParser::parseLines(std::istream& istr, LLSD& data)
+{
+ mCheckLimits = false;
+ mParseLines = true;
+ return doParse(istr, data);
+}
+
+
int LLSDParser::get(std::istream& istr) const
{
if(mCheckLimits) --mMaxBytesLeft;
@@ -1217,8 +1225,7 @@ void LLSDFormatter::realFormat(const std::string& format)
void LLSDFormatter::formatReal(LLSD::Real real, std::ostream& ostr) const
{
- char buffer[MAX_STRING]; /* Flawfinder: ignore */
- snprintf(buffer, MAX_STRING, mRealFormat.c_str(), real); /* Flawfinder: ignore */
+ std::string buffer = llformat(mRealFormat.c_str(), real);
ostr << buffer;
}
@@ -1489,7 +1496,7 @@ void LLSDBinaryFormatter::formatString(
*/
int deserialize_string(std::istream& istr, std::string& value, S32 max_bytes)
{
- char c = istr.get();
+ int c = istr.get();
if(istr.fail())
{
// No data in stream, bail out but mention the character we
@@ -1531,7 +1538,7 @@ int deserialize_string_delim(
while (true)
{
- char next_char = istr.get();
+ int next_byte = istr.get();
++count;
if(istr.fail())
@@ -1540,6 +1547,8 @@ int deserialize_string_delim(
value = write_buffer.str();
return LLSDParser::PARSE_FAILURE;
}
+
+ char next_char = (char)next_byte; // Now that we know it's not EOF
if(found_escape)
{
@@ -1628,7 +1637,7 @@ int deserialize_string_raw(
char buf[BUF_LEN]; /* Flawfinder: ignore */
istr.get(buf, BUF_LEN - 1, ')');
count += istr.gcount();
- char c = istr.get();
+ int c = istr.get();
c = istr.get();
count += 2;
if(((c == '"') || (c == '\'')) && (buf[0] == '('))
diff --git a/indra/llcommon/llsdserialize.h b/indra/llcommon/llsdserialize.h
index 26ce1dc993..1f096b5254 100644
--- a/indra/llcommon/llsdserialize.h
+++ b/indra/llcommon/llsdserialize.h
@@ -4,30 +4,25 @@
* @date 2006-02-26
* @brief Declaration of parsers and formatters for LLSD
*
- * $LicenseInfo:firstyear=2006&license=viewergpl$
- *
- * Copyright (c) 2006-2007, Linden Research, Inc.
- *
+ * $LicenseInfo:firstyear=2006&license=viewerlgpl$
* Second Life Viewer Source Code
- * The source code in this file ("Source Code") is provided by Linden Lab
- * to you under the terms of the GNU General Public License, version 2.0
- * ("GPL"), unless you have obtained a separate licensing agreement
- * ("Other License"), formally executed by you and Linden Lab. Terms of
- * the GPL can be found in doc/GPL-license.txt in this distribution, or
- * online at http://secondlife.com/developers/opensource/gplv2
+ * Copyright (C) 2010, Linden Research, Inc.
*
- * There are special exceptions to the terms and conditions of the GPL as
- * it is applied to this Source Code. View the full text of the exception
- * in the file doc/FLOSS-exception.txt in this software distribution, or
- * online at http://secondlife.com/developers/opensource/flossexception
+ * 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.
*
- * By copying, modifying or distributing this software, you acknowledge
- * that you have read and understood your obligations described above,
- * and agree to abide by those obligations.
+ * 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.
*
- * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
- * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
- * COMPLETENESS OR PERFORMANCE.
+ * 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$
*/
@@ -35,14 +30,15 @@
#define LL_LLSDSERIALIZE_H
#include <iosfwd>
+#include "llpointer.h"
+#include "llrefcount.h"
#include "llsd.h"
-#include "llmemory.h"
/**
* @class LLSDParser
* @brief Abstract base class for LLSD parsers.
*/
-class LLSDParser : public LLRefCount
+class LL_COMMON_API LLSDParser : public LLRefCount
{
protected:
/**
@@ -83,6 +79,18 @@ public:
*/
S32 parse(std::istream& istr, LLSD& data, S32 max_bytes);
+ /** Like parse(), but uses a different call (istream.getline()) to read by lines
+ * This API is better suited for XML, where the parse cannot tell
+ * where the document actually ends.
+ */
+ S32 parseLines(std::istream& istr, LLSD& data);
+
+ /**
+ * @brief Resets the parser so parse() or parseLines() can be called again for another <llsd> chunk.
+ */
+ void reset() { doReset(); };
+
+
protected:
/**
* @brief Pure virtual base for doing the parse.
@@ -100,6 +108,11 @@ protected:
*/
virtual S32 doParse(std::istream& istr, LLSD& data) const = 0;
+ /**
+ * @brief Virtual default function for resetting the parser
+ */
+ virtual void doReset() {};
+
/* @name Simple istream helper methods
*
* These helper methods exist to help correctly use the
@@ -191,13 +204,18 @@ protected:
* @brief The maximum number of bytes left to be parsed.
*/
mutable S32 mMaxBytesLeft;
+
+ /**
+ * @brief Use line-based reading to get text
+ */
+ bool mParseLines;
};
/**
* @class LLSDNotationParser
* @brief Parser which handles the original notation format for LLSD.
*/
-class LLSDNotationParser : public LLSDParser
+class LL_COMMON_API LLSDNotationParser : public LLSDParser
{
protected:
/**
@@ -270,7 +288,7 @@ private:
* @class LLSDXMLParser
* @brief Parser which handles XML format LLSD.
*/
-class LLSDXMLParser : public LLSDParser
+class LL_COMMON_API LLSDXMLParser : public LLSDParser
{
protected:
/**
@@ -301,6 +319,11 @@ protected:
*/
virtual S32 doParse(std::istream& istr, LLSD& data) const;
+ /**
+ * @brief Virtual default function for resetting the parser
+ */
+ virtual void doReset();
+
private:
class Impl;
Impl& impl;
@@ -313,7 +336,7 @@ private:
* @class LLSDBinaryParser
* @brief Parser which handles binary formatted LLSD.
*/
-class LLSDBinaryParser : public LLSDParser
+class LL_COMMON_API LLSDBinaryParser : public LLSDParser
{
protected:
/**
@@ -378,7 +401,7 @@ private:
* @class LLSDFormatter
* @brief Abstract base class for formatting LLSD.
*/
-class LLSDFormatter : public LLRefCount
+class LL_COMMON_API LLSDFormatter : public LLRefCount
{
protected:
/**
@@ -390,7 +413,7 @@ public:
/**
* Options for output
*/
- enum e_formatter_options_type
+ typedef enum e_formatter_options_type
{
OPTIONS_NONE = 0,
OPTIONS_PRETTY = 1
@@ -450,7 +473,7 @@ protected:
* @class LLSDNotationFormatter
* @brief Formatter which outputs the original notation format for LLSD.
*/
-class LLSDNotationFormatter : public LLSDFormatter
+class LL_COMMON_API LLSDNotationFormatter : public LLSDFormatter
{
protected:
/**
@@ -491,7 +514,7 @@ public:
* @class LLSDXMLFormatter
* @brief Formatter which outputs the LLSD as XML.
*/
-class LLSDXMLFormatter : public LLSDFormatter
+class LL_COMMON_API LLSDXMLFormatter : public LLSDFormatter
{
protected:
/**
@@ -559,7 +582,7 @@ protected:
* Map: '{' + 4 byte integer size every(key + value) + '}'<br>
* map keys are serialized as 'k' + 4 byte integer size + string
*/
-class LLSDBinaryFormatter : public LLSDFormatter
+class LL_COMMON_API LLSDBinaryFormatter : public LLSDFormatter
{
protected:
/**
@@ -609,9 +632,14 @@ protected:
* params << "[{'version':i1}," << LLSDOStreamer<LLSDNotationFormatter>(sd)
* << "]";
* </code>
+ *
+ * *NOTE - formerly this class inherited from its template parameter Formatter,
+ * but all insnatiations passed in LLRefCount subclasses. This conflicted with
+ * the auto allocation intended for this class template (demonstrated in the
+ * example above). -brad
*/
template <class Formatter>
-class LLSDOStreamer : public Formatter
+class LLSDOStreamer
{
public:
/**
@@ -632,7 +660,8 @@ public:
std::ostream& str,
const LLSDOStreamer<Formatter>& formatter)
{
- formatter.format(formatter.mSD, str, formatter.mOptions);
+ LLPointer<Formatter> f = new Formatter;
+ f->format(formatter.mSD, str, formatter.mOptions);
return str;
}
@@ -648,7 +677,7 @@ typedef LLSDOStreamer<LLSDXMLFormatter> LLSDXMLStreamer;
* @class LLSDSerialize
* @brief Serializer / deserializer for the various LLSD formats
*/
-class LLSDSerialize
+class LL_COMMON_API LLSDSerialize
{
public:
enum ELLSD_Serialize
@@ -674,7 +703,7 @@ public:
U32 options = LLSDFormatter::OPTIONS_NONE);
/**
- * @breif Examine a stream, and parse 1 sd object out based on contents.
+ * @brief Examine a stream, and parse 1 sd object out based on contents.
*
* @param sd [out] The data found on the stream
* @param str The incoming stream
@@ -718,13 +747,26 @@ public:
return f->format(sd, str, LLSDFormatter::OPTIONS_PRETTY);
}
- static S32 fromXML(LLSD& sd, std::istream& str)
+ static S32 fromXMLEmbedded(LLSD& sd, std::istream& str)
{
// no need for max_bytes since xml formatting is not
// subvertable by bad sizes.
LLPointer<LLSDXMLParser> p = new LLSDXMLParser;
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)
+ {
+ LLPointer<LLSDXMLParser> p = new LLSDXMLParser();
+ return p->parseLines(str, sd);
+ }
+ static S32 fromXML(LLSD& sd, std::istream& str)
+ {
+ return fromXMLEmbedded(sd, str);
+// return fromXMLDocument(sd, str);
+ }
/*
* Binary Methods
diff --git a/indra/llcommon/llsdserialize_xml.cpp b/indra/llcommon/llsdserialize_xml.cpp
index b3596e8705..c5a7c6fc15 100644
--- a/indra/llcommon/llsdserialize_xml.cpp
+++ b/indra/llcommon/llsdserialize_xml.cpp
@@ -2,30 +2,25 @@
* @file llsdserialize_xml.cpp
* @brief XML parsers and formatters for LLSD
*
- * $LicenseInfo:firstyear=2006&license=viewergpl$
- *
- * Copyright (c) 2006-2007, Linden Research, Inc.
- *
+ * $LicenseInfo:firstyear=2006&license=viewerlgpl$
* Second Life Viewer Source Code
- * The source code in this file ("Source Code") is provided by Linden Lab
- * to you under the terms of the GNU General Public License, version 2.0
- * ("GPL"), unless you have obtained a separate licensing agreement
- * ("Other License"), formally executed by you and Linden Lab. Terms of
- * the GPL can be found in doc/GPL-license.txt in this distribution, or
- * online at http://secondlife.com/developers/opensource/gplv2
+ * Copyright (C) 2010, Linden Research, Inc.
*
- * There are special exceptions to the terms and conditions of the GPL as
- * it is applied to this Source Code. View the full text of the exception
- * in the file doc/FLOSS-exception.txt in this software distribution, or
- * online at http://secondlife.com/developers/opensource/flossexception
+ * 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.
*
- * By copying, modifying or distributing this software, you acknowledge
- * that you have read and understood your obligations described above,
- * and agree to abide by those obligations.
+ * 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.
*
- * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
- * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
- * COMPLETENESS OR PERFORMANCE.
+ * 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$
*/
@@ -35,7 +30,8 @@
#include <iostream>
#include <deque>
-#include "apr-1/apr_base64.h"
+#include "apr_base64.h"
+#include <boost/regex.hpp>
extern "C"
{
@@ -63,7 +59,7 @@ S32 LLSDXMLFormatter::format(const LLSD& data, std::ostream& ostr, U32 options)
{
std::streamsize old_precision = ostr.precision(25);
- LLString post = "";
+ std::string post;
if (options & LLSDFormatter::OPTIONS_PRETTY)
{
post = "\n";
@@ -79,8 +75,8 @@ S32 LLSDXMLFormatter::format(const LLSD& data, std::ostream& ostr, U32 options)
S32 LLSDXMLFormatter::format_impl(const LLSD& data, std::ostream& ostr, U32 options, U32 level) const
{
S32 format_count = 1;
- LLString pre = "";
- LLString post = "";
+ std::string pre;
+ std::string post;
if (options & LLSDFormatter::OPTIONS_PRETTY)
{
@@ -137,12 +133,8 @@ S32 LLSDXMLFormatter::format_impl(const LLSD& data, std::ostream& ostr, U32 opti
case LLSD::TypeBoolean:
ostr << pre << "<boolean>";
if(mBoolAlpha ||
-#if( LL_WINDOWS || __GNUC__ > 2)
(ostr.flags() & std::ios::boolalpha)
-#else
- (ostr.flags() & 0x0100)
-#endif
- )
+ )
{
ostr << (data.asBoolean() ? "true" : "false");
}
@@ -262,12 +254,13 @@ public:
~Impl();
S32 parse(std::istream& input, LLSD& data);
+ S32 parseLines(std::istream& input, LLSD& data);
void parsePart(const char *buf, int len);
-private:
void reset();
-
+
+private:
void startElementHandler(const XML_Char* name, const XML_Char** attributes);
void endElementHandler(const XML_Char* name);
void characterDataHandler(const XML_Char* data, int length);
@@ -307,8 +300,8 @@ private:
LLSD mResult;
S32 mParseCount;
- bool mInLLSDElement;
- bool mGracefullStop;
+ bool mInLLSDElement; // true if we're on LLSD
+ bool mGracefullStop; // true if we found the </llsd
typedef std::deque<LLSD*> LLSDRefStack;
LLSDRefStack mStack;
@@ -317,17 +310,14 @@ private:
bool mSkipping;
int mSkipThrough;
- std::string mCurrentKey;
- std::ostringstream mCurrentContent;
-
- bool mPreStaged;
+ std::string mCurrentKey; // Current XML <tag>
+ std::string mCurrentContent; // String data between <tag> and </tag>
};
LLSDXMLParser::Impl::Impl()
{
mParser = XML_ParserCreate(NULL);
- mPreStaged = false;
reset();
}
@@ -336,7 +326,7 @@ LLSDXMLParser::Impl::~Impl()
XML_ParserFree(mParser);
}
-bool is_eol(char c)
+inline bool is_eol(char c)
{
return (c == '\n' || c == '\r');
}
@@ -356,9 +346,9 @@ static unsigned get_till_eol(std::istream& input, char *buf, unsigned bufsize)
unsigned count = 0;
while (count < bufsize && input.good())
{
- input.get(buf[count]);
- count++;
- if (is_eol(buf[count - 1]))
+ char c = input.get();
+ buf[count++] = c;
+ if (is_eol(c))
break;
}
return count;
@@ -366,7 +356,6 @@ static unsigned get_till_eol(std::istream& input, char *buf, unsigned bufsize)
S32 LLSDXMLParser::Impl::parse(std::istream& input, LLSD& data)
{
- reset();
XML_Status status;
static const int BUFFER_SIZE = 1024;
@@ -420,14 +409,86 @@ S32 LLSDXMLParser::Impl::parse(std::istream& input, LLSD& data)
return mParseCount;
}
-void LLSDXMLParser::Impl::reset()
+
+S32 LLSDXMLParser::Impl::parseLines(std::istream& input, LLSD& data)
{
- if (mPreStaged)
+ XML_Status status = XML_STATUS_OK;
+
+ data = LLSD();
+
+ static const int BUFFER_SIZE = 1024;
+
+ //static char last_buffer[ BUFFER_SIZE ];
+ //std::streamsize last_num_read;
+
+ // Must get rid of any leading \n, otherwise the stream gets into an error/eof state
+ clear_eol(input);
+
+ while( !mGracefullStop
+ && input.good()
+ && !input.eof())
{
- mPreStaged = false;
- return;
+ void* buffer = XML_GetBuffer(mParser, BUFFER_SIZE);
+ /*
+ * If we happened to end our last buffer right at the end of the llsd, but the
+ * stream is still going we will get a null buffer here. Check for mGracefullStop.
+ * -- I don't think this is actually true - zero 2008-05-09
+ */
+ if (!buffer)
+ {
+ break;
+ }
+
+ // Get one line
+ input.getline((char*)buffer, BUFFER_SIZE);
+ std::streamsize num_read = input.gcount();
+
+ //memcpy( last_buffer, buffer, num_read );
+ //last_num_read = num_read;
+
+ if ( num_read > 0 )
+ {
+ if (!input.good() )
+ { // Clear state that's set when we run out of buffer
+ input.clear();
+ }
+
+ // Re-insert with the \n that was absorbed by getline()
+ char * text = (char *) buffer;
+ if ( text[num_read - 1] == 0)
+ {
+ text[num_read - 1] = '\n';
+ }
+ }
+
+ status = XML_ParseBuffer(mParser, num_read, false);
+ if (status == XML_STATUS_ERROR)
+ {
+ break;
+ }
+ }
+
+ if (status != XML_STATUS_ERROR
+ && !mGracefullStop)
+ { // Parse last bit
+ status = XML_ParseBuffer(mParser, 0, true);
+ }
+
+ if (status == XML_STATUS_ERROR
+ && !mGracefullStop)
+ {
+ llinfos << "LLSDXMLParser::Impl::parseLines: XML_STATUS_ERROR" << llendl;
+ return LLSDParser::PARSE_FAILURE;
}
+ clear_eol(input);
+ data = mResult;
+ return mParseCount;
+}
+
+
+void LLSDXMLParser::Impl::reset()
+{
mResult.clear();
mParseCount = 0;
@@ -440,12 +501,7 @@ void LLSDXMLParser::Impl::reset()
mSkipping = false;
-#if( LL_WINDOWS || __GNUC__ > 2)
mCurrentKey.clear();
-#else
- mCurrentKey = std::string();
-#endif
-
XML_ParserReset(mParser, "utf-8");
XML_SetUserData(mParser, this);
@@ -476,26 +532,61 @@ LLSDXMLParser::Impl::findAttribute(const XML_Char* name, const XML_Char** pairs)
void LLSDXMLParser::Impl::parsePart(const char* buf, int len)
{
- void * buffer = XML_GetBuffer(mParser, len);
- if (buffer != NULL && buf != NULL)
+ if ( buf != NULL
+ && len > 0 )
{
- memcpy(buffer, buf, len);
+ XML_Status status = XML_Parse(mParser, buf, len, false);
+ if (status == XML_STATUS_ERROR)
+ {
+ llinfos << "Unexpected XML parsing error at start" << llendl;
+ }
}
- XML_ParseBuffer(mParser, len, false);
-
- mPreStaged = true;
}
+// Performance testing code
+//#define XML_PARSER_PERFORMANCE_TESTS
+
+#ifdef XML_PARSER_PERFORMANCE_TESTS
+
+extern U64 totalTime();
+U64 readElementTime = 0;
+U64 startElementTime = 0;
+U64 endElementTime = 0;
+U64 charDataTime = 0;
+U64 parseTime = 0;
+
+class XML_Timer
+{
+public:
+ XML_Timer( U64 * sum ) : mSum( sum )
+ {
+ mStart = totalTime();
+ }
+ ~XML_Timer()
+ {
+ *mSum += (totalTime() - mStart);
+ }
+
+ U64 * mSum;
+ U64 mStart;
+};
+#endif // XML_PARSER_PERFORMANCE_TESTS
+
void LLSDXMLParser::Impl::startElementHandler(const XML_Char* name, const XML_Char** attributes)
{
+ #ifdef XML_PARSER_PERFORMANCE_TESTS
+ XML_Timer timer( &startElementTime );
+ #endif // XML_PARSER_PERFORMANCE_TESTS
+
++mDepth;
if (mSkipping)
{
return;
}
-
+
Element element = readElement(name);
- mCurrentContent.str("");
+
+ mCurrentContent.clear();
switch (element)
{
@@ -538,11 +629,7 @@ void LLSDXMLParser::Impl::startElementHandler(const XML_Char* name, const XML_Ch
LLSD& newElement = map[mCurrentKey];
mStack.push_back(&newElement);
-#if( LL_WINDOWS || __GNUC__ > 2)
mCurrentKey.clear();
-#else
- mCurrentKey = std::string();
-#endif
}
else if (mStack.back()->isArray())
{
@@ -575,6 +662,10 @@ void LLSDXMLParser::Impl::startElementHandler(const XML_Char* name, const XML_Ch
void LLSDXMLParser::Impl::endElementHandler(const XML_Char* name)
{
+ #ifdef XML_PARSER_PERFORMANCE_TESTS
+ XML_Timer timer( &endElementTime );
+ #endif // XML_PARSER_PERFORMANCE_TESTS
+
--mDepth;
if (mSkipping)
{
@@ -599,7 +690,7 @@ void LLSDXMLParser::Impl::endElementHandler(const XML_Char* name)
return;
case ELEMENT_KEY:
- mCurrentKey = mCurrentContent.str();
+ mCurrentKey = mCurrentContent;
return;
default:
@@ -612,9 +703,6 @@ void LLSDXMLParser::Impl::endElementHandler(const XML_Char* name)
LLSD& value = *mStack.back();
mStack.pop_back();
- std::string content = mCurrentContent.str();
- mCurrentContent.str("");
-
switch (element)
{
case ELEMENT_UNDEF:
@@ -622,39 +710,66 @@ void LLSDXMLParser::Impl::endElementHandler(const XML_Char* name)
break;
case ELEMENT_BOOL:
- value = content == "true" || content == "1";
+ value = (mCurrentContent == "true" || mCurrentContent == "1");
break;
case ELEMENT_INTEGER:
- value = LLSD(content).asInteger();
+ {
+ S32 i;
+ if ( sscanf(mCurrentContent.c_str(), "%d", &i ) == 1 )
+ { // See if sscanf works - it's faster
+ value = i;
+ }
+ else
+ {
+ value = LLSD(mCurrentContent).asInteger();
+ }
+ }
break;
case ELEMENT_REAL:
- value = LLSD(content).asReal();
+ {
+ 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;
case ELEMENT_STRING:
- value = content;
+ value = mCurrentContent;
break;
case ELEMENT_UUID:
- value = LLSD(content).asUUID();
+ value = LLSD(mCurrentContent).asUUID();
break;
case ELEMENT_DATE:
- value = LLSD(content).asDate();
+ value = LLSD(mCurrentContent).asDate();
break;
case ELEMENT_URI:
- value = LLSD(content).asURI();
+ value = LLSD(mCurrentContent).asURI();
break;
case ELEMENT_BINARY:
{
- S32 len = apr_base64_decode_len(content.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], content.c_str());
+ len = apr_base64_decode_binary(&data[0], stripped.c_str());
data.resize(len);
value = data;
break;
@@ -668,11 +783,17 @@ void LLSDXMLParser::Impl::endElementHandler(const XML_Char* name)
// other values, map and array, have already been set
break;
}
+
+ mCurrentContent.clear();
}
void LLSDXMLParser::Impl::characterDataHandler(const XML_Char* data, int length)
{
- mCurrentContent.write(data, length);
+ #ifdef XML_PARSER_PERFORMANCE_TESTS
+ XML_Timer timer( &charDataTime );
+ #endif // XML_PARSER_PERFORMANCE_TESTS
+
+ mCurrentContent.append(data, length);
}
@@ -695,22 +816,69 @@ void LLSDXMLParser::Impl::sCharacterDataHandler(
}
+/*
+ This code is time critical
+
+ This is a sample of tag occurances of text in simstate file with ~8000 objects.
+ A tag pair (<key>something</key>) counts is counted as two:
+
+ key - 2680178
+ real - 1818362
+ integer - 906078
+ array - 295682
+ map - 191818
+ uuid - 177903
+ binary - 175748
+ string - 53482
+ undef - 40353
+ boolean - 33874
+ llsd - 16332
+ uri - 38
+ date - 1
+*/
LLSDXMLParser::Impl::Element LLSDXMLParser::Impl::readElement(const XML_Char* name)
{
- if (strcmp(name, "llsd") == 0) { return ELEMENT_LLSD; }
- if (strcmp(name, "undef") == 0) { return ELEMENT_UNDEF; }
- if (strcmp(name, "boolean") == 0) { return ELEMENT_BOOL; }
- if (strcmp(name, "integer") == 0) { return ELEMENT_INTEGER; }
- if (strcmp(name, "real") == 0) { return ELEMENT_REAL; }
- if (strcmp(name, "string") == 0) { return ELEMENT_STRING; }
- if (strcmp(name, "uuid") == 0) { return ELEMENT_UUID; }
- if (strcmp(name, "date") == 0) { return ELEMENT_DATE; }
- if (strcmp(name, "uri") == 0) { return ELEMENT_URI; }
- if (strcmp(name, "binary") == 0) { return ELEMENT_BINARY; }
- if (strcmp(name, "map") == 0) { return ELEMENT_MAP; }
- if (strcmp(name, "array") == 0) { return ELEMENT_ARRAY; }
- if (strcmp(name, "key") == 0) { return ELEMENT_KEY; }
-
+ #ifdef XML_PARSER_PERFORMANCE_TESTS
+ XML_Timer timer( &readElementTime );
+ #endif // XML_PARSER_PERFORMANCE_TESTS
+
+ XML_Char c = *name;
+ switch (c)
+ {
+ case 'k':
+ if (strcmp(name, "key") == 0) { return ELEMENT_KEY; }
+ break;
+ case 'r':
+ if (strcmp(name, "real") == 0) { return ELEMENT_REAL; }
+ break;
+ case 'i':
+ if (strcmp(name, "integer") == 0) { return ELEMENT_INTEGER; }
+ break;
+ case 'a':
+ if (strcmp(name, "array") == 0) { return ELEMENT_ARRAY; }
+ break;
+ case 'm':
+ if (strcmp(name, "map") == 0) { return ELEMENT_MAP; }
+ break;
+ case 'u':
+ if (strcmp(name, "uuid") == 0) { return ELEMENT_UUID; }
+ if (strcmp(name, "undef") == 0) { return ELEMENT_UNDEF; }
+ if (strcmp(name, "uri") == 0) { return ELEMENT_URI; }
+ break;
+ case 'b':
+ if (strcmp(name, "binary") == 0) { return ELEMENT_BINARY; }
+ if (strcmp(name, "boolean") == 0) { return ELEMENT_BOOL; }
+ break;
+ case 's':
+ if (strcmp(name, "string") == 0) { return ELEMENT_STRING; }
+ break;
+ case 'l':
+ if (strcmp(name, "llsd") == 0) { return ELEMENT_LLSD; }
+ break;
+ case 'd':
+ if (strcmp(name, "date") == 0) { return ELEMENT_DATE; }
+ break;
+ }
return ELEMENT_UNKNOWN;
}
@@ -738,5 +906,21 @@ void LLSDXMLParser::parsePart(const char *buf, int len)
// virtual
S32 LLSDXMLParser::doParse(std::istream& input, LLSD& data) const
{
- return impl.parse(input, data);
+ #ifdef XML_PARSER_PERFORMANCE_TESTS
+ XML_Timer timer( &parseTime );
+ #endif // XML_PARSER_PERFORMANCE_TESTS
+
+ if (mParseLines)
+ {
+ // Use line-based reading (faster code)
+ return impl.parseLines(input, data);
+ }
+
+ return impl.parse(input, data);
+}
+
+// virtual
+void LLSDXMLParser::doReset()
+{
+ impl.reset();
}
diff --git a/indra/llcommon/llsdserialize_xml.h b/indra/llcommon/llsdserialize_xml.h
index bb55a465f0..dcc5f3d3c7 100644
--- a/indra/llcommon/llsdserialize_xml.h
+++ b/indra/llcommon/llsdserialize_xml.h
@@ -2,30 +2,25 @@
* @file llsdserialize_xml.h
* @brief XML parsers and formatters for LLSD
*
- * $LicenseInfo:firstyear=2006&license=viewergpl$
- *
- * Copyright (c) 2006-2007, Linden Research, Inc.
- *
+ * $LicenseInfo:firstyear=2006&license=viewerlgpl$
* Second Life Viewer Source Code
- * The source code in this file ("Source Code") is provided by Linden Lab
- * to you under the terms of the GNU General Public License, version 2.0
- * ("GPL"), unless you have obtained a separate licensing agreement
- * ("Other License"), formally executed by you and Linden Lab. Terms of
- * the GPL can be found in doc/GPL-license.txt in this distribution, or
- * online at http://secondlife.com/developers/opensource/gplv2
+ * 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.
*
- * There are special exceptions to the terms and conditions of the GPL as
- * it is applied to this Source Code. View the full text of the exception
- * in the file doc/FLOSS-exception.txt in this software distribution, or
- * online at http://secondlife.com/developers/opensource/flossexception
+ * 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.
*
- * By copying, modifying or distributing this software, you acknowledge
- * that you have read and understood your obligations described above,
- * and agree to abide by those obligations.
+ * 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
*
- * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
- * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
- * COMPLETENESS OR PERFORMANCE.
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
* $/LicenseInfo$
*/
diff --git a/indra/llcommon/llsdutil.cpp b/indra/llcommon/llsdutil.cpp
index 992c883a7e..f8f9ece058 100644
--- a/indra/llcommon/llsdutil.cpp
+++ b/indra/llcommon/llsdutil.cpp
@@ -4,30 +4,25 @@
* @date 2006-05-24
* @brief Implementation of classes, functions, etc, for using structured data.
*
- * $LicenseInfo:firstyear=2006&license=viewergpl$
- *
- * Copyright (c) 2006-2007, Linden Research, Inc.
- *
+ * $LicenseInfo:firstyear=2006&license=viewerlgpl$
* Second Life Viewer Source Code
- * The source code in this file ("Source Code") is provided by Linden Lab
- * to you under the terms of the GNU General Public License, version 2.0
- * ("GPL"), unless you have obtained a separate licensing agreement
- * ("Other License"), formally executed by you and Linden Lab. Terms of
- * the GPL can be found in doc/GPL-license.txt in this distribution, or
- * online at http://secondlife.com/developers/opensource/gplv2
+ * Copyright (C) 2010, Linden Research, Inc.
*
- * There are special exceptions to the terms and conditions of the GPL as
- * it is applied to this Source Code. View the full text of the exception
- * in the file doc/FLOSS-exception.txt in this software distribution, or
- * online at http://secondlife.com/developers/opensource/flossexception
+ * 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.
*
- * By copying, modifying or distributing this software, you acknowledge
- * that you have read and understood your obligations described above,
- * and agree to abide by those obligations.
+ * 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.
*
- * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
- * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
- * COMPLETENESS OR PERFORMANCE.
+ * 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$
*/
@@ -45,124 +40,11 @@
#endif
#include "llsdserialize.h"
+#include "stringize.h"
-// vector3
-LLSD ll_sd_from_vector3(const LLVector3& vec)
-{
- LLSD rv;
- rv.append((F64)vec.mV[VX]);
- rv.append((F64)vec.mV[VY]);
- rv.append((F64)vec.mV[VZ]);
- return rv;
-}
-
-LLVector3 ll_vector3_from_sd(const LLSD& sd, S32 start_index)
-{
- LLVector3 rv;
- rv.mV[VX] = (F32)sd[start_index].asReal();
- rv.mV[VY] = (F32)sd[++start_index].asReal();
- rv.mV[VZ] = (F32)sd[++start_index].asReal();
- return rv;
-}
-
-// vector4
-LLSD ll_sd_from_vector4(const LLVector4& vec)
-{
- LLSD rv;
- rv.append((F64)vec.mV[VX]);
- rv.append((F64)vec.mV[VY]);
- rv.append((F64)vec.mV[VZ]);
- rv.append((F64)vec.mV[VW]);
- return rv;
-}
-
-LLVector4 ll_vector4_from_sd(const LLSD& sd, S32 start_index)
-{
- LLVector4 rv;
- rv.mV[VX] = (F32)sd[start_index].asReal();
- rv.mV[VY] = (F32)sd[++start_index].asReal();
- rv.mV[VZ] = (F32)sd[++start_index].asReal();
- rv.mV[VW] = (F32)sd[++start_index].asReal();
- return rv;
-}
-
-// vector3d
-LLSD ll_sd_from_vector3d(const LLVector3d& vec)
-{
- LLSD rv;
- rv.append(vec.mdV[VX]);
- rv.append(vec.mdV[VY]);
- rv.append(vec.mdV[VZ]);
- return rv;
-}
-
-LLVector3d ll_vector3d_from_sd(const LLSD& sd, S32 start_index)
-{
- LLVector3d rv;
- rv.mdV[VX] = sd[start_index].asReal();
- rv.mdV[VY] = sd[++start_index].asReal();
- rv.mdV[VZ] = sd[++start_index].asReal();
- return rv;
-}
-
-//vector2
-LLSD ll_sd_from_vector2(const LLVector2& vec)
-{
- LLSD rv;
- rv.append((F64)vec.mV[VX]);
- rv.append((F64)vec.mV[VY]);
- return rv;
-}
-
-LLVector2 ll_vector2_from_sd(const LLSD& sd)
-{
- LLVector2 rv;
- rv.mV[VX] = (F32)sd[0].asReal();
- rv.mV[VY] = (F32)sd[1].asReal();
- return rv;
-}
-
-// Quaternion
-LLSD ll_sd_from_quaternion(const LLQuaternion& quat)
-{
- LLSD rv;
- rv.append((F64)quat.mQ[VX]);
- rv.append((F64)quat.mQ[VY]);
- rv.append((F64)quat.mQ[VZ]);
- rv.append((F64)quat.mQ[VW]);
- return rv;
-}
-
-LLQuaternion ll_quaternion_from_sd(const LLSD& sd)
-{
- LLQuaternion quat;
- quat.mQ[VX] = (F32)sd[0].asReal();
- quat.mQ[VY] = (F32)sd[1].asReal();
- quat.mQ[VZ] = (F32)sd[2].asReal();
- quat.mQ[VW] = (F32)sd[3].asReal();
- return quat;
-}
-
-// color4
-LLSD ll_sd_from_color4(const LLColor4& c)
-{
- LLSD rv;
- rv.append(c.mV[0]);
- rv.append(c.mV[1]);
- rv.append(c.mV[2]);
- rv.append(c.mV[3]);
- return rv;
-}
-
-LLColor4 ll_color4_from_sd(const LLSD& sd)
-{
- LLColor4 c;
- c.mV[0] = (F32)sd[0].asReal();
- c.mV[1] = (F32)sd[1].asReal();
- c.mV[2] = (F32)sd[2].asReal();
- c.mV[3] = (F32)sd[3].asReal();
- return c;
-}
+#include <map>
+#include <set>
+#include <boost/range.hpp>
// U32
LLSD ll_sd_from_U32(const U32 val)
@@ -263,12 +145,11 @@ LLSD ll_binary_from_string(const LLSD& sd)
{
std::vector<U8> binary_value;
- LLString string_value = sd.asString();
- const char* string_p = string_value.c_str();
- while (*string_p)
+ std::string string_value = sd.asString();
+ for (std::string::iterator iter = string_value.begin();
+ iter != string_value.end(); ++iter)
{
- binary_value.push_back(*string_p);
- string_p++;
+ binary_value.push_back(*iter);
}
binary_value.push_back('\0');
@@ -289,6 +170,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;
@@ -303,8 +193,9 @@ char* ll_pretty_print_sd(const LLSD& sd)
}
//compares the structure of an LLSD to a template LLSD and stores the
-//"valid" values in a 3rd LLSD. Default values are stored in the template
-//
+//"valid" values in a 3rd LLSD. Default values pulled from the template
+//if the tested LLSD does not contain the key/value pair.
+//Excess values in the test LLSD are ignored in the resultant_llsd.
//If the llsd to test has a specific key to a map and the values
//are not of the same type, false is returned or if the LLSDs are not
//of the same value. Ordering of arrays matters
@@ -421,3 +312,353 @@ 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)
+{
+ // 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;
+
+#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);
+ // The usual caveats about comparing floating-point numbers apply. This is
+ // only useful when we expect identical bit representation for a given
+ // Real value, e.g. for integer-valued Reals.
+ COMPARE_SCALAR(Real);
+ 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))
+ 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]))
+ 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 << "): "
+ "unknown type " << lhs.type() << LL_ENDL;
+ return false; // pacify the compiler
+ }
+}
diff --git a/indra/llcommon/llsdutil.h b/indra/llcommon/llsdutil.h
index 17a881d9cb..bb8c0690b1 100644
--- a/indra/llcommon/llsdutil.h
+++ b/indra/llcommon/llsdutil.h
@@ -4,101 +4,138 @@
* @date 2006-05-24
* @brief Utility classes, functions, etc, for using structured data.
*
- * $LicenseInfo:firstyear=2006&license=viewergpl$
- *
- * Copyright (c) 2006-2007, Linden Research, Inc.
- *
+ * $LicenseInfo:firstyear=2006&license=viewerlgpl$
* Second Life Viewer Source Code
- * The source code in this file ("Source Code") is provided by Linden Lab
- * to you under the terms of the GNU General Public License, version 2.0
- * ("GPL"), unless you have obtained a separate licensing agreement
- * ("Other License"), formally executed by you and Linden Lab. Terms of
- * the GPL can be found in doc/GPL-license.txt in this distribution, or
- * online at http://secondlife.com/developers/opensource/gplv2
+ * Copyright (C) 2010, Linden Research, Inc.
*
- * There are special exceptions to the terms and conditions of the GPL as
- * it is applied to this Source Code. View the full text of the exception
- * in the file doc/FLOSS-exception.txt in this software distribution, or
- * online at http://secondlife.com/developers/opensource/flossexception
+ * 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.
*
- * By copying, modifying or distributing this software, you acknowledge
- * that you have read and understood your obligations described above,
- * and agree to abide by those obligations.
+ * 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.
*
- * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
- * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
- * COMPLETENESS OR PERFORMANCE.
+ * 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$
*/
#ifndef LL_LLSDUTIL_H
#define LL_LLSDUTIL_H
-#include "llsd.h"
-#include "../llmath/v3math.h"
-#include "../llmath/v4math.h"
-#include "../llmath/v3dmath.h"
-#include "../llmath/v2math.h"
-#include "../llmath/llquaternion.h"
-#include "../llmath/v4color.h"
-#include "../llprimitive/lltextureanim.h"
-
-// vector3
-LLSD ll_sd_from_vector3(const LLVector3& vec);
-LLVector3 ll_vector3_from_sd(const LLSD& sd, S32 start_index = 0);
-
-// vector4
-LLSD ll_sd_from_vector4(const LLVector4& vec);
-LLVector4 ll_vector4_from_sd(const LLSD& sd, S32 start_index = 0);
-
-// vector3d (double)
-LLSD ll_sd_from_vector3d(const LLVector3d& vec);
-LLVector3d ll_vector3d_from_sd(const LLSD& sd, S32 start_index = 0);
-
-// vector2
-LLSD ll_sd_from_vector2(const LLVector2& vec);
-LLVector2 ll_vector2_from_sd(const LLSD& sd);
-
-// Quaternion
-LLSD ll_sd_from_quaternion(const LLQuaternion& quat);
-LLQuaternion ll_quaternion_from_sd(const LLSD& sd);
-
-// color4
-LLSD ll_sd_from_color4(const LLColor4& c);
-LLColor4 ll_color4_from_sd(const LLSD& sd);
+class LLSD;
// U32
-LLSD ll_sd_from_U32(const U32);
-U32 ll_U32_from_sd(const LLSD& sd);
+LL_COMMON_API LLSD ll_sd_from_U32(const U32);
+LL_COMMON_API U32 ll_U32_from_sd(const LLSD& sd);
// U64
-LLSD ll_sd_from_U64(const U64);
-U64 ll_U64_from_sd(const LLSD& sd);
+LL_COMMON_API LLSD ll_sd_from_U64(const U64);
+LL_COMMON_API U64 ll_U64_from_sd(const LLSD& sd);
// IP Address
-LLSD ll_sd_from_ipaddr(const U32);
-U32 ll_ipaddr_from_sd(const LLSD& sd);
+LL_COMMON_API LLSD ll_sd_from_ipaddr(const U32);
+LL_COMMON_API U32 ll_ipaddr_from_sd(const LLSD& sd);
// Binary to string
-LLSD ll_string_from_binary(const LLSD& sd);
+LL_COMMON_API LLSD ll_string_from_binary(const LLSD& sd);
//String to binary
-LLSD ll_binary_from_string(const LLSD& sd);
+LL_COMMON_API LLSD ll_binary_from_string(const LLSD& sd);
// Serializes sd to static buffer and returns pointer, useful for gdb debugging.
-char* ll_print_sd(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.
-char* ll_pretty_print_sd(const LLSD& sd);
+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
//"valid" values in a 3rd LLSD. Default values
-//are pulled from the template. Ordering of arrays matters
+//are pulled from the template. Extra keys/values in the test
+//are ignored in the resultant LLSD. Ordering of arrays matters
//Returns false if the test is of same type but values differ in type
//Otherwise, returns true
-BOOL compare_llsd_with_template(
+
+LL_COMMON_API BOOL compare_llsd_with_template(
const LLSD& llsd_to_test,
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
+LL_COMMON_API bool llsd_equals(const LLSD& lhs, const LLSD& rhs);
+
+// 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)
+{
+ LLSD dest;
+ for (; iter != end; ++iter)
+ {
+ dest.append(*iter);
+ }
+ return dest;
+}
+
#endif // LL_LLSDUTIL_H
diff --git a/indra/llcommon/llsecondlifeurls.cpp b/indra/llcommon/llsecondlifeurls.cpp
index bf09453c16..9154e05e43 100644
--- a/indra/llcommon/llsecondlifeurls.cpp
+++ b/indra/llcommon/llsecondlifeurls.cpp
@@ -2,86 +2,83 @@
* @file llsecondlifeurls.cpp
* @brief Urls used in the product
*
- * $LicenseInfo:firstyear=2005&license=viewergpl$
- *
- * Copyright (c) 2005-2007, Linden Research, Inc.
- *
+ * $LicenseInfo:firstyear=2005&license=viewerlgpl$
* Second Life Viewer Source Code
- * The source code in this file ("Source Code") is provided by Linden Lab
- * to you under the terms of the GNU General Public License, version 2.0
- * ("GPL"), unless you have obtained a separate licensing agreement
- * ("Other License"), formally executed by you and Linden Lab. Terms of
- * the GPL can be found in doc/GPL-license.txt in this distribution, or
- * online at http://secondlife.com/developers/opensource/gplv2
+ * 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.
*
- * There are special exceptions to the terms and conditions of the GPL as
- * it is applied to this Source Code. View the full text of the exception
- * in the file doc/FLOSS-exception.txt in this software distribution, or
- * online at http://secondlife.com/developers/opensource/flossexception
+ * 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.
*
- * By copying, modifying or distributing this software, you acknowledge
- * that you have read and understood your obligations described above,
- * and agree to abide by those obligations.
+ * 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
*
- * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
- * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
- * COMPLETENESS OR PERFORMANCE.
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
* $/LicenseInfo$
*/
#include "linden_common.h"
#include "llsecondlifeurls.h"
+/*
+const std::string CREATE_ACCOUNT_URL (
+ "http://join.secondlife.com/");
-const char CREATE_ACCOUNT_URL[] =
- "http://secondlife.com/registration/";
-
-const char MANAGE_ACCOUNT[] =
- "http://secondlife.com/account/";
-
-const char AUCTION_URL[] =
- "http://secondlife.com/auctions/auction-detail.php?id=";
-
-const char EVENTS_URL[] =
- "http://secondlife.com/events/";
+const std::string MANAGE_ACCOUNT (
+ "http://secondlife.com/account/"); // *TODO: NOT USED
-const char TIER_UP_URL[] =
- "http://secondlife.com/app/landtier";
+const std::string AUCTION_URL (
+ "http://secondlife.com/auctions/auction-detail.php?id=");
-const char LAND_URL[] =
- "http://secondlife.com/app/landtier";
+const std::string EVENTS_URL (
+ "http://secondlife.com/events/");
+*/
+const std::string TIER_UP_URL (
+ "http://secondlife.com/app/landtier"); // *TODO: Translate (simulator)
-const char UPGRADE_TO_PREMIUM_URL[] =
- "http://secondlife.com/app/upgrade/";
+const std::string DIRECTX_9_URL (
+ "http://secondlife.com/support/"); // *TODO: NOT USED
+/*
+const std::string LAND_URL (
+ "http://secondlife.com/app/landtier"); // *TODO: NOT USED
-const char DIRECTX_9_URL[] =
- "http://secondlife.com/support/";
+const std::string UPGRADE_TO_PREMIUM_URL (
+ "http://secondlife.com/app/upgrade/"); // *TODO: NOT USED
-const char AMD_AGP_URL[] =
- "http://secondlife.com/support/";
+const std::string AMD_AGP_URL (
+ "http://secondlife.com/support/"); // *TODO: NOT USED
-const char VIA_URL[] =
- "http://secondlife.com/support/";
+const std::string VIA_URL (
+ "http://secondlife.com/support/"); // *TODO: NOT USED
-const char SUPPORT_URL[] =
- "http://secondlife.com/support/";
+const std::string SUPPORT_URL (
+ "http://secondlife.com/support/");
-const char INTEL_CHIPSET_URL[] =
- "http://secondlife.com/support/";
+const std::string INTEL_CHIPSET_URL (
+ "http://secondlife.com/support/"); // *TODO: NOT USED
-const char SIS_CHIPSET_URL[] =
- "http://secondlife.com/support/";
+const std::string SIS_CHIPSET_URL (
+ "http://secondlife.com/support/"); // *TODO: NOT USED
-const char BLOGS_URL[] =
- "http://blog.secondlife.com/";
+const std::string BLOGS_URL (
+ "http://blog.secondlife.com/"); // *TODO: NOT USED
-const char BUY_CURRENCY_URL[] =
- "http://secondlife.com/app/currency/";
+const std::string BUY_CURRENCY_URL (
+ "http://secondlife.com/app/currency/");
-const char LSL_DOC_URL[] =
- "http://secondlife.com/app/lsldoc/";
+const std::string LSL_DOC_URL (
+ "http://secondlife.com/app/lsldoc/"); // *TODO: NOT USED
-const char SL_KB_URL[] =
- "http://secondlife.com/knowledgebase/";
+const std::string SL_KB_URL (
+ "http://secondlife.com/knowledgebase/"); // *TODO: NOT USED
-const char RELEASE_NOTES[] = "releasenotes.txt";
+const std::string RELEASE_NOTES_BASE_URL (
+ "http://secondlife.com/app/releasenotes/");
+*/
diff --git a/indra/llcommon/llsecondlifeurls.h b/indra/llcommon/llsecondlifeurls.h
index b8d8aa2402..62f357ffed 100644
--- a/indra/llcommon/llsecondlifeurls.h
+++ b/indra/llcommon/llsecondlifeurls.h
@@ -2,77 +2,75 @@
* @file llsecondlifeurls.h
* @brief Global URLs to pages on our web site
*
- * $LicenseInfo:firstyear=2004&license=viewergpl$
- *
- * Copyright (c) 2004-2007, Linden Research, Inc.
- *
+ * $LicenseInfo:firstyear=2004&license=viewerlgpl$
* Second Life Viewer Source Code
- * The source code in this file ("Source Code") is provided by Linden Lab
- * to you under the terms of the GNU General Public License, version 2.0
- * ("GPL"), unless you have obtained a separate licensing agreement
- * ("Other License"), formally executed by you and Linden Lab. Terms of
- * the GPL can be found in doc/GPL-license.txt in this distribution, or
- * online at http://secondlife.com/developers/opensource/gplv2
+ * 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.
*
- * There are special exceptions to the terms and conditions of the GPL as
- * it is applied to this Source Code. View the full text of the exception
- * in the file doc/FLOSS-exception.txt in this software distribution, or
- * online at http://secondlife.com/developers/opensource/flossexception
+ * 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.
*
- * By copying, modifying or distributing this software, you acknowledge
- * that you have read and understood your obligations described above,
- * and agree to abide by those obligations.
+ * 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
*
- * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
- * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
- * COMPLETENESS OR PERFORMANCE.
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
* $/LicenseInfo$
*/
#ifndef LL_LLSECONDLIFEURLS_H
#define LL_LLSECONDLIFEURLS_H
-
+/*
// Account registration web page
-extern const char CREATE_ACCOUNT_URL[];
+LL_COMMON_API extern const std::string CREATE_ACCOUNT_URL;
// Manage Account
-extern const char MANAGE_ACCOUNT[];
-
-extern const char AUCTION_URL[];
+LL_COMMON_API extern const std::string MANAGE_ACCOUNT;
-extern const char EVENTS_URL[];
+LL_COMMON_API extern const std::string AUCTION_URL;
+LL_COMMON_API extern const std::string EVENTS_URL;
+*/
// Tier up to a new land level.
-extern const char TIER_UP_URL[];
+LL_COMMON_API extern const std::string TIER_UP_URL;
+
// Tier up to a new land level.
-extern const char LAND_URL[];
+LL_COMMON_API extern const std::string LAND_URL;
+
+// How to get DirectX 9
+LL_COMMON_API extern const std::string DIRECTX_9_URL;
+/*
// Upgrade from basic membership to premium membership
-extern const char UPGRADE_TO_PREMIUM_URL[];
+LL_COMMON_API extern const std::string UPGRADE_TO_PREMIUM_URL;
-// How to get DirectX 9
-extern const char DIRECTX_9_URL[];
// Out of date VIA chipset
-extern const char VIA_URL[];
+LL_COMMON_API extern const std::string VIA_URL;
// Support URL
-extern const char SUPPORT_URL[];
+LL_COMMON_API extern const std::string SUPPORT_URL;
// Linden Blogs page
-extern const char BLOGS_URL[];
+LL_COMMON_API extern const std::string BLOGS_URL;
// Currency page
-extern const char BUY_CURRENCY_URL[];
+LL_COMMON_API extern const std::string BUY_CURRENCY_URL;
// LSL script wiki
-extern const char LSL_DOC_URL[];
+LL_COMMON_API extern const std::string LSL_DOC_URL;
// SL KnowledgeBase page
-extern const char SL_KB_URL[];
-
-// Local Url Release Notes
-extern const char RELEASE_NOTES[];
+LL_COMMON_API extern const std::string SL_KB_URL;
+// Release Notes Redirect URL for Server and Viewer
+LL_COMMON_API extern const std::string RELEASE_NOTES_BASE_URL;
+*/
#endif
diff --git a/indra/llcommon/llsimplehash.h b/indra/llcommon/llsimplehash.h
index ae5a31e353..727b4568d8 100644
--- a/indra/llcommon/llsimplehash.h
+++ b/indra/llcommon/llsimplehash.h
@@ -1,30 +1,25 @@
/**
* @file llsimplehash.h
*
- * $LicenseInfo:firstyear=2003&license=viewergpl$
- *
- * Copyright (c) 2003-2007, Linden Research, Inc.
- *
+ * $LicenseInfo:firstyear=2003&license=viewerlgpl$
* Second Life Viewer Source Code
- * The source code in this file ("Source Code") is provided by Linden Lab
- * to you under the terms of the GNU General Public License, version 2.0
- * ("GPL"), unless you have obtained a separate licensing agreement
- * ("Other License"), formally executed by you and Linden Lab. Terms of
- * the GPL can be found in doc/GPL-license.txt in this distribution, or
- * online at http://secondlife.com/developers/opensource/gplv2
+ * 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.
*
- * There are special exceptions to the terms and conditions of the GPL as
- * it is applied to this Source Code. View the full text of the exception
- * in the file doc/FLOSS-exception.txt in this software distribution, or
- * online at http://secondlife.com/developers/opensource/flossexception
+ * 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.
*
- * By copying, modifying or distributing this software, you acknowledge
- * that you have read and understood your obligations described above,
- * and agree to abide by those obligations.
+ * 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
*
- * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
- * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
- * COMPLETENESS OR PERFORMANCE.
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
* $/LicenseInfo$
*/
@@ -63,7 +58,7 @@ public:
};
template <typename HASH_KEY_TYPE, int TABLE_SIZE>
-class LLSimpleHash
+class LL_COMMON_API LLSimpleHash
{
public:
LLSimpleHash()
diff --git a/indra/llcommon/llsingleton.cpp b/indra/llcommon/llsingleton.cpp
new file mode 100644
index 0000000000..eb8e2c9456
--- /dev/null
+++ b/indra/llcommon/llsingleton.cpp
@@ -0,0 +1,32 @@
+/**
+ * @file llsingleton.cpp
+ * @author Brad Kittenbrink
+ *
+ * $LicenseInfo:firstyear=2009&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$
+ */
+
+#include "linden_common.h"
+
+#include "llsingleton.h"
+
+std::map<std::string, void *> * LLSingletonRegistry::sSingletonMap = NULL;
+
diff --git a/indra/llcommon/llsingleton.h b/indra/llcommon/llsingleton.h
new file mode 100644
index 0000000000..7aee1bb85f
--- /dev/null
+++ b/indra/llcommon/llsingleton.h
@@ -0,0 +1,201 @@
+/**
+ * @file llsingleton.h
+ *
+ * $LicenseInfo:firstyear=2002&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$
+ */
+#ifndef LLSINGLETON_H
+#define LLSINGLETON_H
+
+#include "llerror.h" // *TODO: eliminate this
+
+#include <typeinfo>
+#include <boost/noncopyable.hpp>
+
+/// @brief A global registry of all singletons to prevent duplicate allocations
+/// across shared library boundaries
+class LL_COMMON_API LLSingletonRegistry {
+ private:
+ typedef std::map<std::string, void *> TypeMap;
+ static TypeMap * sSingletonMap;
+
+ static void checkInit()
+ {
+ if(sSingletonMap == NULL)
+ {
+ sSingletonMap = new TypeMap();
+ }
+ }
+
+ public:
+ template<typename T> static void * & get()
+ {
+ std::string name(typeid(T).name());
+
+ checkInit();
+
+ // the first entry of the pair returned by insert will be either the existing
+ // iterator matching our key, or the newly inserted NULL initialized entry
+ // see "Insert element" in http://www.sgi.com/tech/stl/UniqueAssociativeContainer.html
+ TypeMap::iterator result =
+ sSingletonMap->insert(std::make_pair(name, (void*)NULL)).first;
+
+ return result->second;
+ }
+};
+
+// LLSingleton implements the getInstance() method part of the Singleton
+// pattern. It can't make the derived class constructors protected, though, so
+// you have to do that yourself.
+//
+// There are two ways to use LLSingleton. The first way is to inherit from it
+// while using the typename that you'd like to be static as the template
+// parameter, like so:
+//
+// class Foo: public LLSingleton<Foo>{};
+//
+// Foo& instance = Foo::instance();
+//
+// The second way is to use the singleton class directly, without inheritance:
+//
+// typedef LLSingleton<Foo> FooSingleton;
+//
+// Foo& instance = FooSingleton::instance();
+//
+// In this case, the class being managed as a singleton needs to provide an
+// initSingleton() method since the LLSingleton virtual method won't be
+// available
+//
+// As currently written, it is not thread-safe.
+
+template <typename DERIVED_TYPE>
+class LLSingleton : private boost::noncopyable
+{
+
+private:
+ typedef enum e_init_state
+ {
+ UNINITIALIZED,
+ CONSTRUCTING,
+ INITIALIZING,
+ INITIALIZED,
+ DELETED
+ } EInitState;
+
+ static void deleteSingleton()
+ {
+ delete getData().mSingletonInstance;
+ getData().mSingletonInstance = NULL;
+ }
+
+ // stores pointer to singleton instance
+ // and tracks initialization state of singleton
+ struct SingletonInstanceData
+ {
+ EInitState mInitState;
+ DERIVED_TYPE* mSingletonInstance;
+
+ SingletonInstanceData()
+ : mSingletonInstance(NULL),
+ mInitState(UNINITIALIZED)
+ {}
+
+ ~SingletonInstanceData()
+ {
+ deleteSingleton();
+ }
+ };
+
+public:
+ virtual ~LLSingleton()
+ {
+ SingletonInstanceData& data = getData();
+ data.mSingletonInstance = NULL;
+ data.mInitState = DELETED;
+ }
+
+ static SingletonInstanceData& getData()
+ {
+ // this is static to cache the lookup results
+ static void * & registry = LLSingletonRegistry::get<DERIVED_TYPE>();
+
+ // *TODO - look into making this threadsafe
+ if(NULL == registry)
+ {
+ static SingletonInstanceData data;
+ registry = &data;
+ }
+
+ return *static_cast<SingletonInstanceData *>(registry);
+ }
+
+ static DERIVED_TYPE* getInstance()
+ {
+ SingletonInstanceData& data = getData();
+
+ if (data.mInitState == CONSTRUCTING)
+ {
+ llerrs << "Tried to access singleton " << typeid(DERIVED_TYPE).name() << " from singleton constructor!" << llendl;
+ }
+
+ if (data.mInitState == DELETED)
+ {
+ llwarns << "Trying to access deleted singleton " << typeid(DERIVED_TYPE).name() << " creating new instance" << llendl;
+ }
+
+ if (!data.mSingletonInstance)
+ {
+ data.mInitState = CONSTRUCTING;
+ data.mSingletonInstance = new DERIVED_TYPE();
+ data.mInitState = INITIALIZING;
+ data.mSingletonInstance->initSingleton();
+ data.mInitState = INITIALIZED;
+ }
+
+ return data.mSingletonInstance;
+ }
+
+ // Reference version of getInstance()
+ // Preferred over getInstance() as it disallows checking for NULL
+ static DERIVED_TYPE& instance()
+ {
+ return *getInstance();
+ }
+
+ // Has this singleton been created uet?
+ // Use this to avoid accessing singletons before the can safely be constructed
+ static bool instanceExists()
+ {
+ return getData().mInitState == INITIALIZED;
+ }
+
+ // Has this singleton already been deleted?
+ // Use this to avoid accessing singletons from a static object's destructor
+ static bool destroyed()
+ {
+ return getData().mInitState == DELETED;
+ }
+
+private:
+ virtual void initSingleton() {}
+};
+
+#endif
diff --git a/indra/llcommon/llskiplist.h b/indra/llcommon/llskiplist.h
index 314043ebac..ed132381f9 100644
--- a/indra/llcommon/llskiplist.h
+++ b/indra/llcommon/llskiplist.h
@@ -2,36 +2,32 @@
* @file llskiplist.h
* @brief skip list implementation
*
- * $LicenseInfo:firstyear=2001&license=viewergpl$
- *
- * Copyright (c) 2001-2007, Linden Research, Inc.
- *
+ * $LicenseInfo:firstyear=2001&license=viewerlgpl$
* Second Life Viewer Source Code
- * The source code in this file ("Source Code") is provided by Linden Lab
- * to you under the terms of the GNU General Public License, version 2.0
- * ("GPL"), unless you have obtained a separate licensing agreement
- * ("Other License"), formally executed by you and Linden Lab. Terms of
- * the GPL can be found in doc/GPL-license.txt in this distribution, or
- * online at http://secondlife.com/developers/opensource/gplv2
+ * Copyright (C) 2010, Linden Research, Inc.
*
- * There are special exceptions to the terms and conditions of the GPL as
- * it is applied to this Source Code. View the full text of the exception
- * in the file doc/FLOSS-exception.txt in this software distribution, or
- * online at http://secondlife.com/developers/opensource/flossexception
+ * 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.
*
- * By copying, modifying or distributing this software, you acknowledge
- * that you have read and understood your obligations described above,
- * and agree to abide by those obligations.
+ * 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.
*
- * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
- * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
- * COMPLETENESS OR PERFORMANCE.
+ * 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$
*/
#ifndef LL_LLSKIPLIST_H
#define LL_LLSKIPLIST_H
#include "llrand.h"
+#include "llrand.h"
// NOTA BENE: Insert first needs to be < NOT <=
// Binary depth must be >= 2
diff --git a/indra/llcommon/llskipmap.h b/indra/llcommon/llskipmap.h
index 65e1617bc5..49ff2928d1 100644
--- a/indra/llcommon/llskipmap.h
+++ b/indra/llcommon/llskipmap.h
@@ -2,30 +2,25 @@
* @file llskipmap.h
* @brief Associative container based on the skiplist algorithm.
*
- * $LicenseInfo:firstyear=2003&license=viewergpl$
- *
- * Copyright (c) 2003-2007, Linden Research, Inc.
- *
+ * $LicenseInfo:firstyear=2003&license=viewerlgpl$
* Second Life Viewer Source Code
- * The source code in this file ("Source Code") is provided by Linden Lab
- * to you under the terms of the GNU General Public License, version 2.0
- * ("GPL"), unless you have obtained a separate licensing agreement
- * ("Other License"), formally executed by you and Linden Lab. Terms of
- * the GPL can be found in doc/GPL-license.txt in this distribution, or
- * online at http://secondlife.com/developers/opensource/gplv2
+ * 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.
*
- * There are special exceptions to the terms and conditions of the GPL as
- * it is applied to this Source Code. View the full text of the exception
- * in the file doc/FLOSS-exception.txt in this software distribution, or
- * online at http://secondlife.com/developers/opensource/flossexception
+ * 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.
*
- * By copying, modifying or distributing this software, you acknowledge
- * that you have read and understood your obligations described above,
- * and agree to abide by those obligations.
+ * 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
*
- * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
- * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
- * COMPLETENESS OR PERFORMANCE.
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
* $/LicenseInfo$
*/
diff --git a/indra/llcommon/llsmoothstep.h b/indra/llcommon/llsmoothstep.h
index cac40c8f67..1f97a3ec89 100644
--- a/indra/llcommon/llsmoothstep.h
+++ b/indra/llcommon/llsmoothstep.h
@@ -2,30 +2,25 @@
* @file llsmoothstep.h
* @brief Smoothstep - transition from 0 to 1 - function, first and second derivatives all continuous (smooth)
*
- * $LicenseInfo:firstyear=2001&license=viewergpl$
- *
- * Copyright (c) 2001-2007, Linden Research, Inc.
- *
+ * $LicenseInfo:firstyear=2001&license=viewerlgpl$
* Second Life Viewer Source Code
- * The source code in this file ("Source Code") is provided by Linden Lab
- * to you under the terms of the GNU General Public License, version 2.0
- * ("GPL"), unless you have obtained a separate licensing agreement
- * ("Other License"), formally executed by you and Linden Lab. Terms of
- * the GPL can be found in doc/GPL-license.txt in this distribution, or
- * online at http://secondlife.com/developers/opensource/gplv2
+ * 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.
*
- * There are special exceptions to the terms and conditions of the GPL as
- * it is applied to this Source Code. View the full text of the exception
- * in the file doc/FLOSS-exception.txt in this software distribution, or
- * online at http://secondlife.com/developers/opensource/flossexception
+ * 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.
*
- * By copying, modifying or distributing this software, you acknowledge
- * that you have read and understood your obligations described above,
- * and agree to abide by those obligations.
+ * 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
*
- * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
- * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
- * COMPLETENESS OR PERFORMANCE.
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
* $/LicenseInfo$
*/
diff --git a/indra/llcommon/llstack.h b/indra/llcommon/llstack.h
index 5fb65f2ea6..315de6ba2d 100644
--- a/indra/llcommon/llstack.h
+++ b/indra/llcommon/llstack.h
@@ -2,30 +2,25 @@
* @file llstack.h
* @brief LLStack template class
*
- * $LicenseInfo:firstyear=2001&license=viewergpl$
- *
- * Copyright (c) 2001-2007, Linden Research, Inc.
- *
+ * $LicenseInfo:firstyear=2001&license=viewerlgpl$
* Second Life Viewer Source Code
- * The source code in this file ("Source Code") is provided by Linden Lab
- * to you under the terms of the GNU General Public License, version 2.0
- * ("GPL"), unless you have obtained a separate licensing agreement
- * ("Other License"), formally executed by you and Linden Lab. Terms of
- * the GPL can be found in doc/GPL-license.txt in this distribution, or
- * online at http://secondlife.com/developers/opensource/gplv2
+ * 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.
*
- * There are special exceptions to the terms and conditions of the GPL as
- * it is applied to this Source Code. View the full text of the exception
- * in the file doc/FLOSS-exception.txt in this software distribution, or
- * online at http://secondlife.com/developers/opensource/flossexception
+ * 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.
*
- * By copying, modifying or distributing this software, you acknowledge
- * that you have read and understood your obligations described above,
- * and agree to abide by those obligations.
+ * 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
*
- * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
- * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
- * COMPLETENESS OR PERFORMANCE.
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
* $/LicenseInfo$
*/
diff --git a/indra/llcommon/llstacktrace.cpp b/indra/llcommon/llstacktrace.cpp
new file mode 100644
index 0000000000..ccd7ef91c2
--- /dev/null
+++ b/indra/llcommon/llstacktrace.cpp
@@ -0,0 +1,136 @@
+/**
+ * @file llstacktrace.cpp
+ * @brief stack tracing functionality
+ *
+ * $LicenseInfo:firstyear=2001&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$
+ */
+
+#include "linden_common.h"
+#include "llstacktrace.h"
+
+#ifdef LL_WINDOWS
+
+#include <iostream>
+#include <sstream>
+
+#include "windows.h"
+#include "Dbghelp.h"
+
+typedef USHORT NTAPI RtlCaptureStackBackTrace_Function(
+ IN ULONG frames_to_skip,
+ IN ULONG frames_to_capture,
+ OUT PVOID *backtrace,
+ OUT PULONG backtrace_hash);
+
+static RtlCaptureStackBackTrace_Function* const RtlCaptureStackBackTrace_fn =
+ (RtlCaptureStackBackTrace_Function*)
+ GetProcAddress(GetModuleHandleA("ntdll.dll"), "RtlCaptureStackBackTrace");
+
+bool ll_get_stack_trace(std::vector<std::string>& lines)
+{
+ const S32 MAX_STACK_DEPTH = 32;
+ const S32 STRING_NAME_LENGTH = 200;
+ const S32 FRAME_SKIP = 2;
+ static BOOL symbolsLoaded = false;
+ static BOOL firstCall = true;
+
+ HANDLE hProc = GetCurrentProcess();
+
+ // load the symbols if they're not loaded
+ if(!symbolsLoaded && firstCall)
+ {
+ symbolsLoaded = SymInitialize(hProc, NULL, true);
+ firstCall = false;
+ }
+
+ // if loaded, get the call stack
+ if(symbolsLoaded)
+ {
+ // create the frames to hold the addresses
+ void* frames[MAX_STACK_DEPTH];
+ memset(frames, 0, sizeof(void*)*MAX_STACK_DEPTH);
+ S32 depth = 0;
+
+ // get the addresses
+ depth = RtlCaptureStackBackTrace_fn(FRAME_SKIP, MAX_STACK_DEPTH, frames, NULL);
+
+ IMAGEHLP_LINE64 line;
+ memset(&line, 0, sizeof(IMAGEHLP_LINE64));
+ line.SizeOfStruct = sizeof(IMAGEHLP_LINE64);
+
+ // create something to hold address info
+ PIMAGEHLP_SYMBOL64 pSym;
+ pSym = (PIMAGEHLP_SYMBOL64)malloc(sizeof(IMAGEHLP_SYMBOL64) + STRING_NAME_LENGTH);
+ memset(pSym, 0, sizeof(IMAGEHLP_SYMBOL64) + STRING_NAME_LENGTH);
+ pSym->MaxNameLength = STRING_NAME_LENGTH;
+ pSym->SizeOfStruct = sizeof(IMAGEHLP_SYMBOL64);
+
+ // get address info for each address frame
+ // and store
+ for(S32 i=0; i < depth; i++)
+ {
+ std::stringstream stack_line;
+ BOOL ret;
+
+ DWORD64 addr = (DWORD64)frames[i];
+ ret = SymGetSymFromAddr64(hProc, addr, 0, pSym);
+ if(ret)
+ {
+ stack_line << pSym->Name << " ";
+ }
+
+ DWORD dummy;
+ ret = SymGetLineFromAddr64(hProc, addr, &dummy, &line);
+ if(ret)
+ {
+ std::string file_name = line.FileName;
+ std::string::size_type index = file_name.rfind("\\");
+ stack_line << file_name.substr(index + 1, file_name.size()) << ":" << line.LineNumber;
+ }
+
+ lines.push_back(stack_line.str());
+ }
+
+ free(pSym);
+
+ // TODO: figure out a way to cleanup symbol loading
+ // Not hugely necessary, however.
+ //SymCleanup(hProc);
+ return true;
+ }
+ else
+ {
+ lines.push_back("Stack Trace Failed. PDB symbol info not loaded");
+ }
+
+ return false;
+}
+
+#else
+
+bool ll_get_stack_trace(std::vector<std::string>& lines)
+{
+ return false;
+}
+
+#endif
+
diff --git a/indra/llcommon/llstacktrace.h b/indra/llcommon/llstacktrace.h
new file mode 100644
index 0000000000..ca72c64c5d
--- /dev/null
+++ b/indra/llcommon/llstacktrace.h
@@ -0,0 +1,38 @@
+/**
+ * @file llstacktrace.h
+ * @brief stack trace functions
+ *
+ * $LicenseInfo:firstyear=2001&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$
+ */
+
+
+#ifndef LL_LLSTACKTRACE_H
+#define LL_LLSTACKTRACE_H
+
+#include "stdtypes.h"
+#include <vector>
+#include <string>
+
+LL_COMMON_API bool ll_get_stack_trace(std::vector<std::string>& lines);
+
+#endif
+
diff --git a/indra/llcommon/llstat.cpp b/indra/llcommon/llstat.cpp
index e999934b62..8ba97d7730 100644
--- a/indra/llcommon/llstat.cpp
+++ b/indra/llcommon/llstat.cpp
@@ -1,85 +1,328 @@
/**
* @file llstat.cpp
*
- * $LicenseInfo:firstyear=2001&license=viewergpl$
- *
- * Copyright (c) 2001-2007, Linden Research, Inc.
- *
+ * $LicenseInfo:firstyear=2001&license=viewerlgpl$
* Second Life Viewer Source Code
- * The source code in this file ("Source Code") is provided by Linden Lab
- * to you under the terms of the GNU General Public License, version 2.0
- * ("GPL"), unless you have obtained a separate licensing agreement
- * ("Other License"), formally executed by you and Linden Lab. Terms of
- * the GPL can be found in doc/GPL-license.txt in this distribution, or
- * online at http://secondlife.com/developers/opensource/gplv2
+ * 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.
*
- * There are special exceptions to the terms and conditions of the GPL as
- * it is applied to this Source Code. View the full text of the exception
- * in the file doc/FLOSS-exception.txt in this software distribution, or
- * online at http://secondlife.com/developers/opensource/flossexception
+ * 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.
*
- * By copying, modifying or distributing this software, you acknowledge
- * that you have read and understood your obligations described above,
- * and agree to abide by those obligations.
+ * 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
*
- * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
- * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
- * COMPLETENESS OR PERFORMANCE.
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
* $/LicenseInfo$
*/
#include "linden_common.h"
#include "llstat.h"
+#include "lllivefile.h"
+#include "llerrorcontrol.h"
#include "llframetimer.h"
#include "timing.h"
+#include "llsd.h"
+#include "llsdserialize.h"
+#include "llstl.h"
+#include "u64.h"
+
+
+// statics
+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
+static const char STATS_CONFIG_FILE_NAME[] = "/dev/shm/simperf/simperf_proc_config.llsd";
+static const F32 STATS_CONFIG_REFRESH_RATE = 5.0; // seconds
-class LLStatAccum::impl
+class LLStatsConfigFile : public LLLiveFile
{
public:
- static const TimeScale IMPL_NUM_SCALES = (TimeScale)(SCALE_TWO_MINUTE + 1);
- static U64 sScaleTimes[IMPL_NUM_SCALES];
+ LLStatsConfigFile()
+ : LLLiveFile(filename(), STATS_CONFIG_REFRESH_RATE),
+ mChanged(false), mStatsp(NULL) { }
- BOOL mUseFrameTimer;
+ static std::string filename();
+
+protected:
+ /* virtual */ bool loadFile();
- BOOL mRunning;
- U64 mLastTime;
-
- struct Bucket
- {
- F64 accum;
- U64 endTime;
+public:
+ void init(LLPerfStats* statsp);
+ static LLStatsConfigFile& instance();
+ // return the singleton stats config file
- BOOL lastValid;
- F64 lastAccum;
- };
+ bool mChanged;
- Bucket mBuckets[IMPL_NUM_SCALES];
+protected:
+ LLPerfStats* mStatsp;
+};
- BOOL mLastSampleValid;
- F64 mLastSampleValue;
+std::string LLStatsConfigFile::filename()
+{
+ return STATS_CONFIG_FILE_NAME;
+}
+void LLStatsConfigFile::init(LLPerfStats* statsp)
+{
+ mStatsp = statsp;
+}
- impl(bool useFrameTimer);
+LLStatsConfigFile& LLStatsConfigFile::instance()
+{
+ static LLStatsConfigFile the_file;
+ return the_file;
+}
- void reset(U64 when);
- void sum(F64 value);
- void sum(F64 value, U64 when);
+/* virtual */
+// Load and parse the stats configuration file
+bool LLStatsConfigFile::loadFile()
+{
+ if (!mStatsp)
+ {
+ llwarns << "Tries to load performance configure file without initializing LPerfStats" << llendl;
+ return false;
+ }
+ mChanged = true;
+
+ LLSD stats_config;
+ {
+ llifstream file(filename().c_str());
+ if (file.is_open())
+ {
+ LLSDSerialize::fromXML(stats_config, file);
+ if (stats_config.isUndefined())
+ {
+ llinfos << "Performance statistics configuration file ill-formed, not recording statistics" << llendl;
+ mStatsp->setReportPerformanceDuration( 0.f );
+ return false;
+ }
+ }
+ else
+ { // File went away, turn off stats if it was on
+ if ( mStatsp->frameStatsIsRunning() )
+ {
+ llinfos << "Performance statistics configuration file deleted, not recording statistics" << llendl;
+ mStatsp->setReportPerformanceDuration( 0.f );
+ }
+ return true;
+ }
+ }
+
+ F32 duration = 0.f;
+ F32 interval = 0.f;
+ S32 flags = LLPerfBlock::LLSTATS_BASIC_STATS;
+
+ const char * w = "duration";
+ if (stats_config.has(w))
+ {
+ duration = (F32)stats_config[w].asReal();
+ }
+ w = "interval";
+ if (stats_config.has(w))
+ {
+ 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, flags );
+ mStatsp->setReportPerformanceInterval( interval );
+
+ if ( duration > 0 )
+ {
+ if ( interval == 0.f )
+ {
+ llinfos << "Recording performance stats every frame for " << duration << " sec" << llendl;
+ }
+ else
+ {
+ llinfos << "Recording performance stats every " << interval << " seconds for " << duration << " seconds" << llendl;
+ }
+ }
+ else
+ {
+ llinfos << "Performance stats recording turned off" << llendl;
+ }
+ return true;
+}
- F32 meanValue(TimeScale scale) const;
- U64 getCurrentUsecs() const;
- // Get current microseconds based on timer type
-};
+//------------------------------------------------------------------------
+LLPerfStats::LLPerfStats(const std::string& process_name, S32 process_pid) :
+ mFrameStatsFileFailure(FALSE),
+ mSkipFirstFrameStats(FALSE),
+ mProcessName(process_name),
+ mProcessPID(process_pid),
+ mReportPerformanceStatInterval(1.f),
+ mReportPerformanceStatEnd(0.0)
+{ }
-U64 LLStatAccum::impl::sScaleTimes[IMPL_NUM_SCALES] =
+LLPerfStats::~LLPerfStats()
{
+ LLPerfBlock::clearDynamicStats();
+ mFrameStatsFile.close();
+}
+
+void LLPerfStats::init()
+{
+ // Initialize the stats config file instance.
+ (void) LLStatsConfigFile::instance().init(this);
+ (void) LLStatsConfigFile::instance().checkAndReload();
+}
+
+// Open file for statistics
+void LLPerfStats::openPerfStatsFile()
+{
+ if ( !mFrameStatsFile
+ && !mFrameStatsFileFailure )
+ {
+ std::string stats_file = llformat("/dev/shm/simperf/%s_proc.%d.llsd", mProcessName.c_str(), mProcessPID);
+ mFrameStatsFile.close();
+ mFrameStatsFile.clear();
+ mFrameStatsFile.open(stats_file, llofstream::out);
+ if ( mFrameStatsFile.fail() )
+ {
+ llinfos << "Error opening statistics log file " << stats_file << llendl;
+ mFrameStatsFileFailure = TRUE;
+ }
+ else
+ {
+ LLSD process_info = LLSD::emptyMap();
+ process_info["name"] = mProcessName;
+ process_info["pid"] = (LLSD::Integer) mProcessPID;
+ process_info["stat_rate"] = (LLSD::Integer) mReportPerformanceStatInterval;
+ // Add process-specific info.
+ addProcessHeaderInfo(process_info);
+
+ mFrameStatsFile << LLSDNotationStreamer(process_info) << std::endl;
+ }
+ }
+}
+
+// Dump out performance metrics over some time interval
+void LLPerfStats::dumpIntervalPerformanceStats()
+{
+ // Ensure output file is OK
+ openPerfStatsFile();
+
+ if ( mFrameStatsFile )
+ {
+ LLSD stats = LLSD::emptyMap();
+
+ LLStatAccum::TimeScale scale;
+ if ( getReportPerformanceInterval() == 0.f )
+ {
+ scale = LLStatAccum::SCALE_PER_FRAME;
+ }
+ else if ( getReportPerformanceInterval() < 0.5f )
+ {
+ scale = LLStatAccum::SCALE_100MS;
+ }
+ else
+ {
+ scale = LLStatAccum::SCALE_SECOND;
+ }
+
+ // Write LLSD into log
+ stats["utc_time"] = (LLSD::String) LLError::utcTime();
+ stats["timestamp"] = U64_to_str((totalTime() / 1000) + (gUTCOffset * 1000)); // milliseconds since epoch
+ stats["frame_number"] = (LLSD::Integer) LLFrameTimer::getFrameCount();
+
+ // Add process-specific frame info.
+ addProcessFrameInfo(stats, scale);
+ LLPerfBlock::addStatsToLLSDandReset( stats, scale );
+
+ mFrameStatsFile << LLSDNotationStreamer(stats) << std::endl;
+ }
+}
+
+// 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::setStatsFlags(LLPerfBlock::LLSTATS_NO_OPTIONAL_STATS); // Make sure all recording is off
+ mFrameStatsFile.close();
+ LLPerfBlock::clearDynamicStats();
+ }
+ else
+ {
+ mReportPerformanceStatEnd = LLFrameTimer::getElapsedSeconds() + ((F64) seconds);
+ // Clear failure flag to try and create the log file once
+ mFrameStatsFileFailure = FALSE;
+ mSkipFirstFrameStats = TRUE; // Skip the first report (at the end of this frame)
+ LLPerfBlock::setStatsFlags(flags);
+ }
+}
+
+void LLPerfStats::updatePerFrameStats()
+{
+ (void) LLStatsConfigFile::instance().checkAndReload();
+ static LLFrameTimer performance_stats_timer;
+ if ( frameStatsIsRunning() )
+ {
+ if ( mReportPerformanceStatInterval == 0 )
+ { // Record info every frame
+ if ( mSkipFirstFrameStats )
+ { // Skip the first time - was started this frame
+ mSkipFirstFrameStats = FALSE;
+ }
+ else
+ {
+ dumpIntervalPerformanceStats();
+ }
+ }
+ else
+ {
+ performance_stats_timer.setTimerExpirySec( getReportPerformanceInterval() );
+ if (performance_stats_timer.checkExpirationAndReset( mReportPerformanceStatInterval ))
+ {
+ dumpIntervalPerformanceStats();
+ }
+ }
+
+ if ( LLFrameTimer::getElapsedSeconds() > mReportPerformanceStatEnd )
+ { // Reached end of time, clear it to stop reporting
+ setReportPerformanceDuration(0.f); // Don't set mReportPerformanceStatEnd directly
+ llinfos << "Recording performance stats completed" << llendl;
+ }
+ }
+}
+
+
+//------------------------------------------------------------------------
+
+U64 LLStatAccum::sScaleTimes[NUM_SCALES] =
+{
+ USEC_PER_SEC / 10, // 100 millisec
USEC_PER_SEC * 1, // seconds
USEC_PER_SEC * 60, // minutes
- USEC_PER_SEC * 60 * 2 // minutes
-#if 0
+#if ENABLE_LONG_TIME_STATS
// enable these when more time scales are desired
USEC_PER_SEC * 60*60, // hours
USEC_PER_SEC * 24*60*60, // days
@@ -88,32 +331,41 @@ U64 LLStatAccum::impl::sScaleTimes[IMPL_NUM_SCALES] =
};
-LLStatAccum::impl::impl(bool useFrameTimer)
+
+LLStatAccum::LLStatAccum(bool useFrameTimer)
+ : mUseFrameTimer(useFrameTimer),
+ mRunning(FALSE),
+ mLastTime(0),
+ mLastSampleValue(0.0),
+ mLastSampleValid(FALSE)
+{
+}
+
+LLStatAccum::~LLStatAccum()
{
- mUseFrameTimer = useFrameTimer;
- mRunning = FALSE;
- mLastSampleValid = FALSE;
}
-void LLStatAccum::impl::reset(U64 when)
+
+
+void LLStatAccum::reset(U64 when)
{
mRunning = TRUE;
mLastTime = when;
- for (int i = 0; i < IMPL_NUM_SCALES; ++i)
+ for (int i = 0; i < NUM_SCALES; ++i)
{
mBuckets[i].accum = 0.0;
mBuckets[i].endTime = when + sScaleTimes[i];
- mBuckets[i].lastValid = FALSE;
+ mBuckets[i].lastValid = false;
}
}
-void LLStatAccum::impl::sum(F64 value)
+void LLStatAccum::sum(F64 value)
{
sum(value, getCurrentUsecs());
}
-void LLStatAccum::impl::sum(F64 value, U64 when)
+void LLStatAccum::sum(F64 value, U64 when)
{
if (!mRunning)
{
@@ -130,7 +382,10 @@ void LLStatAccum::impl::sum(F64 value, U64 when)
return;
}
- for (int i = 0; i < IMPL_NUM_SCALES; ++i)
+ // how long is this value for
+ U64 timeSpan = when - mLastTime;
+
+ for (int i = 0; i < NUM_SCALES; ++i)
{
Bucket& bucket = mBuckets[i];
@@ -142,8 +397,6 @@ void LLStatAccum::impl::sum(F64 value, U64 when)
{
U64 timeScale = sScaleTimes[i];
- U64 timeSpan = when - mLastTime;
- // how long is this value for
U64 timeLeft = when - bucket.endTime;
// how much time is left after filling this bucket
@@ -151,7 +404,7 @@ void LLStatAccum::impl::sum(F64 value, U64 when)
{
F64 valueLeft = value * timeLeft / timeSpan;
- bucket.lastValid = TRUE;
+ bucket.lastValid = true;
bucket.lastAccum = bucket.accum + (value - valueLeft);
bucket.accum = valueLeft;
bucket.endTime += timeScale;
@@ -160,7 +413,7 @@ void LLStatAccum::impl::sum(F64 value, U64 when)
{
U64 timeTail = timeLeft % timeScale;
- bucket.lastValid = TRUE;
+ bucket.lastValid = true;
bucket.lastAccum = value * timeScale / timeSpan;
bucket.accum = value * timeTail / timeSpan;
bucket.endTime += (timeLeft - timeTail) + timeScale;
@@ -172,13 +425,18 @@ void LLStatAccum::impl::sum(F64 value, U64 when)
}
-F32 LLStatAccum::impl::meanValue(TimeScale scale) const
+F32 LLStatAccum::meanValue(TimeScale scale) const
{
if (!mRunning)
{
return 0.0;
}
- if (scale < 0 || scale >= IMPL_NUM_SCALES)
+ if ( scale == SCALE_PER_FRAME )
+ { // Per-frame not supported here
+ scale = SCALE_100MS;
+ }
+
+ if (scale < 0 || scale >= NUM_SCALES)
{
llwarns << "llStatAccum::meanValue called for unsupported scale: "
<< scale << llendl;
@@ -208,7 +466,7 @@ F32 LLStatAccum::impl::meanValue(TimeScale scale) const
}
-U64 LLStatAccum::impl::getCurrentUsecs() const
+U64 LLStatAccum::getCurrentUsecs() const
{
if (mUseFrameTimer)
{
@@ -221,24 +479,43 @@ U64 LLStatAccum::impl::getCurrentUsecs() const
}
+// ------------------------------------------------------------------------
-
-
-LLStatAccum::LLStatAccum(bool useFrameTimer)
- : m(* new impl(useFrameTimer))
+LLStatRate::LLStatRate(bool use_frame_timer)
+ : LLStatAccum(use_frame_timer)
{
}
-LLStatAccum::~LLStatAccum()
+void LLStatRate::count(U32 value)
{
- delete &m;
+ sum((F64)value * sScaleTimes[SCALE_SECOND]);
}
-F32 LLStatAccum::meanValue(TimeScale scale) const
-{
- return m.meanValue(scale);
-}
+void LLStatRate::mark()
+ {
+ // Effectively the same as count(1), but sets mLastSampleValue
+ U64 when = getCurrentUsecs();
+
+ if ( mRunning
+ && (when > mLastTime) )
+ { // Set mLastSampleValue to the time from the last mark()
+ F64 duration = ((F64)(when - mLastTime)) / sScaleTimes[SCALE_SECOND];
+ if ( duration > 0.0 )
+ {
+ mLastSampleValue = 1.0 / duration;
+ }
+ else
+ {
+ mLastSampleValue = 0.0;
+ }
+ }
+
+ sum( (F64) sScaleTimes[SCALE_SECOND], when);
+ }
+
+
+// ------------------------------------------------------------------------
LLStatMeasure::LLStatMeasure(bool use_frame_timer)
@@ -248,79 +525,272 @@ LLStatMeasure::LLStatMeasure(bool use_frame_timer)
void LLStatMeasure::sample(F64 value)
{
- U64 when = m.getCurrentUsecs();
+ U64 when = getCurrentUsecs();
- if (m.mLastSampleValid)
+ if (mLastSampleValid)
{
- F64 avgValue = (value + m.mLastSampleValue) / 2.0;
- F64 interval = (F64)(when - m.mLastTime);
+ F64 avgValue = (value + mLastSampleValue) / 2.0;
+ F64 interval = (F64)(when - mLastTime);
- m.sum(avgValue * interval, when);
+ sum(avgValue * interval, when);
}
else
{
- m.reset(when);
+ reset(when);
}
- m.mLastSampleValid = TRUE;
- m.mLastSampleValue = value;
+ mLastSampleValid = TRUE;
+ mLastSampleValue = value;
}
-LLStatRate::LLStatRate(bool use_frame_timer)
- : LLStatAccum(use_frame_timer)
+// ------------------------------------------------------------------------
+
+LLStatTime::LLStatTime(const std::string & key)
+ : LLStatAccum(false),
+ mFrameNumber(LLFrameTimer::getFrameCount()),
+ mTotalTimeInFrame(0),
+ mKey(key)
+#if LL_DEBUG
+ , mRunning(FALSE)
+#endif
{
}
-void LLStatRate::count(U32 value)
+void LLStatTime::start()
{
- m.sum((F64)value * impl::sScaleTimes[SCALE_SECOND]);
+ // Reset frame accumluation if the frame number has changed
+ U32 frame_number = LLFrameTimer::getFrameCount();
+ if ( frame_number != mFrameNumber )
+ {
+ mFrameNumber = frame_number;
+ mTotalTimeInFrame = 0;
+ }
+
+ sum(0.0);
+
+#if LL_DEBUG
+ // Shouldn't be running already
+ llassert( !mRunning );
+ mRunning = TRUE;
+#endif
}
+void LLStatTime::stop()
+{
+ U64 end_time = getCurrentUsecs();
+ U64 duration = end_time - mLastTime;
+ sum(F64(duration), end_time);
+ //llinfos << "mTotalTimeInFrame incremented from " << mTotalTimeInFrame << " to " << (mTotalTimeInFrame + duration) << llendl;
+ mTotalTimeInFrame += duration;
-LLStatTime::LLStatTime(bool use_frame_timer)
- : LLStatAccum(use_frame_timer)
+#if LL_DEBUG
+ mRunning = FALSE;
+#endif
+}
+
+/* virtual */ F32 LLStatTime::meanValue(TimeScale scale) const
{
+ if ( LLStatAccum::SCALE_PER_FRAME == scale )
+ {
+ return mTotalTimeInFrame;
+ }
+ else
+ {
+ return LLStatAccum::meanValue(scale);
+ }
}
-void LLStatTime::start()
+
+// ------------------------------------------------------------------------
+
+
+// Use this constructor for pre-defined LLStatTime objects
+LLPerfBlock::LLPerfBlock(LLStatTime* stat ) : mPredefinedStat(stat), mDynamicStat(NULL)
{
- m.sum(0.0);
+ if (mPredefinedStat)
+ {
+ // If dynamic stats are turned on, this will create a separate entry in the stat map.
+ initDynamicStat(mPredefinedStat->mKey);
+
+ // Start predefined stats. These stats are not part of the stat map.
+ mPredefinedStat->start();
+ }
}
-void LLStatTime::stop()
+// Use this constructor for normal, optional LLPerfBlock time slices
+LLPerfBlock::LLPerfBlock( const char* key ) : mPredefinedStat(NULL), mDynamicStat(NULL)
{
- U64 endTime = m.getCurrentUsecs();
- m.sum((F64)(endTime - m.mLastTime), endTime);
+ 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)
+ {
+ initDynamicStat(key1);
+ }
+ else
+ {
+ std::ostringstream key;
+ key << key1 << "_" << key2;
+ initDynamicStat(key.str());
+ }
+}
+
+// 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 (sStatsFlags == LLSTATS_NO_OPTIONAL_STATS)
+ return;
+
+ mLastPath = sCurrentStatPath; // Save and restore current path
+ sCurrentStatPath += "/" + key; // Add key to current path
+
+ // See if the LLStatTime object already exists
+ stat_map_t::iterator iter = sStatMap.find(sCurrentStatPath);
+ if ( iter == sStatMap.end() )
+ {
+ // StatEntry object doesn't exist, so create it
+ mDynamicStat = new StatEntry( key );
+ sStatMap[ sCurrentStatPath ] = mDynamicStat; // Set the entry for this path
+ }
+ else
+ {
+ // Found this path in the map, use the object there
+ mDynamicStat = (*iter).second; // Get StatEntry for the current path
+ }
+
+ if (mDynamicStat)
+ {
+ mDynamicStat->mStat.start();
+ mDynamicStat->mCount++;
+ }
+ else
+ {
+ llwarns << "Initialized NULL dynamic stat at '" << sCurrentStatPath << "'" << llendl;
+ sCurrentStatPath = mLastPath;
+ }
+}
+
+
+// Destructor does the time accounting
+LLPerfBlock::~LLPerfBlock()
+{
+ if (mPredefinedStat) mPredefinedStat->stop();
+ if (mDynamicStat)
+ {
+ mDynamicStat->mStat.stop();
+ sCurrentStatPath = mLastPath; // Restore the path in case sStatsEnabled changed during this block
+ }
+}
+
+
+// Clear the map of any dynamic stats. Static routine
+void LLPerfBlock::clearDynamicStats()
+{
+ std::for_each(sStatMap.begin(), sStatMap.end(), DeletePairedPointer());
+ sStatMap.clear();
+}
+
+// static - Extract the stat info into LLSD
+void LLPerfBlock::addStatsToLLSDandReset( LLSD & stats,
+ LLStatAccum::TimeScale scale )
+{
+ // If we aren't in per-frame scale, we need to go from second to microsecond.
+ U32 scale_adjustment = 1;
+ if (LLStatAccum::SCALE_PER_FRAME != scale)
+ {
+ scale_adjustment = USEC_PER_SEC;
+ }
+ stat_map_t::iterator iter = sStatMap.begin();
+ for ( ; iter != sStatMap.end(); ++iter )
+ { // Put the entry into LLSD "/full/path/to/stat/" = microsecond total time
+ const std::string & stats_full_path = (*iter).first;
+
+ StatEntry * stat = (*iter).second;
+ if (stat)
+ {
+ if (stat->mCount > 0)
+ {
+ stats[stats_full_path] = LLSD::emptyMap();
+ stats[stats_full_path]["us"] = (LLSD::Integer) (scale_adjustment * stat->mStat.meanValue(scale));
+ if (stat->mCount > 1)
+ {
+ stats[stats_full_path]["count"] = (LLSD::Integer) stat->mCount;
+ }
+ stat->mCount = 0;
+ }
+ }
+ else
+ { // WTF? Shouldn't have a NULL pointer in the map.
+ llwarns << "Unexpected NULL dynamic stat at '" << stats_full_path << "'" << llendl;
+ }
+ }
+}
+// ------------------------------------------------------------------------
+
LLTimer LLStat::sTimer;
LLFrameTimer LLStat::sFrameTimer;
-LLStat::LLStat(const U32 num_bins, const BOOL use_frame_timer)
+void LLStat::init()
{
- llassert(num_bins > 0);
- U32 i;
- 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];
mBeginTime = new F64[mNumBins];
mTime = new F64[mNumBins];
mDT = new F32[mNumBins];
- for (i = 0; i < mNumBins; i++)
+ for (U32 i = 0; i < mNumBins; i++)
{
mBins[i] = 0.f;
mBeginTime[i] = 0.0;
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()
@@ -329,6 +799,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()
diff --git a/indra/llcommon/llstat.h b/indra/llcommon/llstat.h
index e20c01f67f..b877432e86 100644
--- a/indra/llcommon/llstat.h
+++ b/indra/llcommon/llstat.h
@@ -2,30 +2,25 @@
* @file llstat.h
* @brief Runtime statistics accumulation.
*
- * $LicenseInfo:firstyear=2001&license=viewergpl$
- *
- * Copyright (c) 2001-2007, Linden Research, Inc.
- *
+ * $LicenseInfo:firstyear=2001&license=viewerlgpl$
* Second Life Viewer Source Code
- * The source code in this file ("Source Code") is provided by Linden Lab
- * to you under the terms of the GNU General Public License, version 2.0
- * ("GPL"), unless you have obtained a separate licensing agreement
- * ("Other License"), formally executed by you and Linden Lab. Terms of
- * the GPL can be found in doc/GPL-license.txt in this distribution, or
- * online at http://secondlife.com/developers/opensource/gplv2
+ * 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.
*
- * There are special exceptions to the terms and conditions of the GPL as
- * it is applied to this Source Code. View the full text of the exception
- * in the file doc/FLOSS-exception.txt in this software distribution, or
- * online at http://secondlife.com/developers/opensource/flossexception
+ * 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.
*
- * By copying, modifying or distributing this software, you acknowledge
- * that you have read and understood your obligations described above,
- * and agree to abide by those obligations.
+ * 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
*
- * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
- * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
- * COMPLETENESS OR PERFORMANCE.
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
* $/LicenseInfo$
*/
@@ -33,9 +28,16 @@
#define LL_LLSTAT_H
#include <deque>
+#include <map>
#include "lltimer.h"
#include "llframetimer.h"
+#include "llfile.h"
+
+class LLSD;
+
+// Set this if longer stats are needed
+#define ENABLE_LONG_TIME_STATS 0
//
// Accumulates statistics for an arbitrary length of time.
@@ -44,7 +46,7 @@
// amounts of time with very low memory cost.
//
-class LLStatAccum
+class LL_COMMON_API LLStatAccum
{
protected:
LLStatAccum(bool use_frame_timer);
@@ -52,28 +54,63 @@ protected:
public:
enum TimeScale {
+ SCALE_100MS,
SCALE_SECOND,
SCALE_MINUTE,
- SCALE_TWO_MINUTE,
+#if ENABLE_LONG_TIME_STATS
SCALE_HOUR,
SCALE_DAY,
SCALE_WEEK,
-
- NUM_SCALES
+#endif
+ NUM_SCALES, // Use to size storage arrays
+ SCALE_PER_FRAME // For latest frame information - should be after NUM_SCALES since this doesn't go into the time buckets
};
- F32 meanValue(TimeScale scale) const;
+ static U64 sScaleTimes[NUM_SCALES];
+
+ virtual F32 meanValue(TimeScale scale) const;
// see the subclasses for the specific meaning of value
+ F32 meanValueOverLast100ms() const { return meanValue(SCALE_100MS); }
F32 meanValueOverLastSecond() const { return meanValue(SCALE_SECOND); }
F32 meanValueOverLastMinute() const { return meanValue(SCALE_MINUTE); }
-protected:
- class impl;
- impl& m;
+ void reset(U64 when);
+
+ void sum(F64 value);
+ void sum(F64 value, U64 when);
+
+ U64 getCurrentUsecs() const;
+ // Get current microseconds based on timer type
+
+ BOOL mUseFrameTimer;
+ BOOL mRunning;
+
+ U64 mLastTime;
+
+ struct Bucket
+ {
+ Bucket() :
+ accum(0.0),
+ endTime(0),
+ lastValid(false),
+ lastAccum(0.0)
+ {}
+
+ F64 accum;
+ U64 endTime;
+
+ bool lastValid;
+ F64 lastAccum;
+ };
+
+ Bucket mBuckets[NUM_SCALES];
+
+ BOOL mLastSampleValid;
+ F64 mLastSampleValue;
};
-class LLStatMeasure : public LLStatAccum
+class LL_COMMON_API LLStatMeasure : public LLStatAccum
// gathers statistics about things that are measured
// ex.: tempature, time dilation
{
@@ -88,7 +125,7 @@ public:
};
-class LLStatRate : public LLStatAccum
+class LL_COMMON_API LLStatRate : public LLStatAccum
// gathers statistics about things that can be counted over time
// ex.: LSL instructions executed, messages sent, simulator frames completed
// renders it in terms of rate of thing per second
@@ -99,43 +136,140 @@ public:
void count(U32);
// used to note that n items have occured
- void mark() { count(1); }
+ void mark();
// used for counting the rate thorugh a point in the code
};
-class LLTimeBlock;
-
-class LLStatTime : public LLStatAccum
+class LL_COMMON_API LLStatTime : public LLStatAccum
// gathers statistics about time spent in a block of code
// measure average duration per second in the block
{
public:
- LLStatTime(bool use_frame_timer = false);
+ LLStatTime( const std::string & key = "undefined" );
+
+ U32 mFrameNumber; // Current frame number
+ U64 mTotalTimeInFrame; // Total time (microseconds) accumulated during the last frame
+
+ void setKey( const std::string & key ) { mKey = key; };
+
+ virtual F32 meanValue(TimeScale scale) const;
private:
- void start();
+ void start(); // Start and stop measuring time block
void stop();
- friend class LLTimeBlock;
+
+ std::string mKey; // Tag representing this time block
+
+#if LL_DEBUG
+ BOOL mRunning; // TRUE if start() has been called
+#endif
+
+ friend class LLPerfBlock;
};
-class LLTimeBlock
+// ----------------------------------------------------------------------------
+
+
+// Use this class on the stack to record statistics about an area of code
+class LL_COMMON_API LLPerfBlock
{
public:
- LLTimeBlock(LLStatTime& stat) : mStat(stat) { mStat.start(); }
- ~LLTimeBlock() { mStat.stop(); }
+ struct StatEntry
+ {
+ StatEntry(const std::string& key) : mStat(LLStatTime(key)), mCount(0) {}
+ LLStatTime mStat;
+ U32 mCount;
+ };
+ typedef std::map<std::string, StatEntry*> stat_map_t;
+
+ // Use this constructor for pre-defined LLStatTime objects
+ LLPerfBlock(LLStatTime* stat);
+
+ // 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();
+
+ 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
+ LLStatAccum::TimeScale scale );
+
private:
- LLStatTime& mStat;
+ // Initialize dynamically created LLStatTime objects
+ void initDynamicStat(const std::string& key);
+
+ std::string mLastPath; // Save sCurrentStatPath when this is called
+ LLStatTime * mPredefinedStat; // LLStatTime object to get data
+ StatEntry * mDynamicStat; // StatEntryobject to get data
+
+ 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"
};
+// ----------------------------------------------------------------------------
+class LL_COMMON_API LLPerfStats
+{
+public:
+ LLPerfStats(const std::string& process_name = "unknown", S32 process_pid = 0);
+ virtual ~LLPerfStats();
+
+ virtual void init(); // Reset and start all stat timers
+ virtual void updatePerFrameStats();
+ // Override these function to add process-specific information to the performance log header and per-frame logging.
+ virtual void addProcessHeaderInfo(LLSD& info) { /* not implemented */ }
+ virtual void addProcessFrameInfo(LLSD& info, LLStatAccum::TimeScale scale) { /* not implemented */ }
+
+ // High-resolution frame stats
+ BOOL frameStatsIsRunning() { return (mReportPerformanceStatEnd > 0.); };
+ F32 getReportPerformanceInterval() const { return mReportPerformanceStatInterval; };
+ void setReportPerformanceInterval( F32 interval ) { mReportPerformanceStatInterval = interval; };
+ 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; }
+
+protected:
+ void openPerfStatsFile(); // Open file for high resolution metrics logging
+ void dumpIntervalPerformanceStats();
+ llofstream mFrameStatsFile; // File for per-frame stats
+ BOOL mFrameStatsFileFailure; // Flag to prevent repeat opening attempts
+ BOOL mSkipFirstFrameStats; // Flag to skip one (partial) frame report
+ std::string mProcessName;
+ S32 mProcessPID;
+private:
+ F32 mReportPerformanceStatInterval; // Seconds between performance stats
+ F64 mReportPerformanceStatEnd; // End time (seconds) for performance stats
+};
-class LLStat
+// ----------------------------------------------------------------------------
+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();
@@ -198,8 +332,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_
diff --git a/indra/llcommon/llstatenums.h b/indra/llcommon/llstatenums.h
index e9876f8061..9033d8eb43 100644
--- a/indra/llcommon/llstatenums.h
+++ b/indra/llcommon/llstatenums.h
@@ -1,30 +1,25 @@
/**
* @file llstatenums.h
*
- * $LicenseInfo:firstyear=2001&license=viewergpl$
- *
- * Copyright (c) 2001-2007, Linden Research, Inc.
- *
+ * $LicenseInfo:firstyear=2001&license=viewerlgpl$
* Second Life Viewer Source Code
- * The source code in this file ("Source Code") is provided by Linden Lab
- * to you under the terms of the GNU General Public License, version 2.0
- * ("GPL"), unless you have obtained a separate licensing agreement
- * ("Other License"), formally executed by you and Linden Lab. Terms of
- * the GPL can be found in doc/GPL-license.txt in this distribution, or
- * online at http://secondlife.com/developers/opensource/gplv2
+ * 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.
*
- * There are special exceptions to the terms and conditions of the GPL as
- * it is applied to this Source Code. View the full text of the exception
- * in the file doc/FLOSS-exception.txt in this software distribution, or
- * online at http://secondlife.com/developers/opensource/flossexception
+ * 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.
*
- * By copying, modifying or distributing this software, you acknowledge
- * that you have read and understood your obligations described above,
- * and agree to abide by those obligations.
+ * 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
*
- * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
- * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
- * COMPLETENESS OR PERFORMANCE.
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
* $/LicenseInfo$
*/
@@ -33,31 +28,41 @@
enum
{
- LL_SIM_STAT_TIME_DILATION,
+ LL_SIM_STAT_TIME_DILATION, // 0
LL_SIM_STAT_FPS,
LL_SIM_STAT_PHYSFPS,
LL_SIM_STAT_AGENTUPS,
LL_SIM_STAT_FRAMEMS,
- LL_SIM_STAT_NETMS,
+ LL_SIM_STAT_NETMS, // 5
LL_SIM_STAT_SIMOTHERMS,
LL_SIM_STAT_SIMPHYSICSMS,
LL_SIM_STAT_AGENTMS,
LL_SIM_STAT_IMAGESMS,
- LL_SIM_STAT_SCRIPTMS,
+ LL_SIM_STAT_SCRIPTMS, // 10
LL_SIM_STAT_NUMTASKS,
LL_SIM_STAT_NUMTASKSACTIVE,
LL_SIM_STAT_NUMAGENTMAIN,
LL_SIM_STAT_NUMAGENTCHILD,
- LL_SIM_STAT_NUMSCRIPTSACTIVE,
+ LL_SIM_STAT_NUMSCRIPTSACTIVE, // 15
LL_SIM_STAT_LSLIPS,
LL_SIM_STAT_INPPS,
LL_SIM_STAT_OUTPPS,
LL_SIM_STAT_PENDING_DOWNLOADS,
- LL_SIM_STAT_PENDING_UPLOADS,
+ LL_SIM_STAT_PENDING_UPLOADS, // 20
LL_SIM_STAT_VIRTUAL_SIZE_KB,
LL_SIM_STAT_RESIDENT_SIZE_KB,
LL_SIM_STAT_PENDING_LOCAL_UPLOADS,
- LL_SIM_STAT_TOTAL_UNACKED_BYTES
+ LL_SIM_STAT_TOTAL_UNACKED_BYTES,
+ LL_SIM_STAT_PHYSICS_PINNED_TASKS, // 25
+ LL_SIM_STAT_PHYSICS_LOD_TASKS,
+ LL_SIM_STAT_SIMPHYSICSSTEPMS,
+ LL_SIM_STAT_SIMPHYSICSSHAPEMS,
+ LL_SIM_STAT_SIMPHYSICSOTHERMS,
+ LL_SIM_STAT_SIMPHYSICSMEMORY, // 30
+ LL_SIM_STAT_SCRIPT_EPS,
+ LL_SIM_STAT_SIMSPARETIME,
+ LL_SIM_STAT_SIMSLEEPTIME,
+ LL_SIM_STAT_IOPUMPTIME,
};
#endif
diff --git a/indra/llcommon/llstl.h b/indra/llcommon/llstl.h
index b692daefd8..8ad12c9a03 100644
--- a/indra/llcommon/llstl.h
+++ b/indra/llcommon/llstl.h
@@ -2,30 +2,25 @@
* @file llstl.h
* @brief helper object & functions for use with the stl.
*
- * $LicenseInfo:firstyear=2003&license=viewergpl$
- *
- * Copyright (c) 2003-2007, Linden Research, Inc.
- *
+ * $LicenseInfo:firstyear=2003&license=viewerlgpl$
* Second Life Viewer Source Code
- * The source code in this file ("Source Code") is provided by Linden Lab
- * to you under the terms of the GNU General Public License, version 2.0
- * ("GPL"), unless you have obtained a separate licensing agreement
- * ("Other License"), formally executed by you and Linden Lab. Terms of
- * the GPL can be found in doc/GPL-license.txt in this distribution, or
- * online at http://secondlife.com/developers/opensource/gplv2
+ * Copyright (C) 2010, Linden Research, Inc.
*
- * There are special exceptions to the terms and conditions of the GPL as
- * it is applied to this Source Code. View the full text of the exception
- * in the file doc/FLOSS-exception.txt in this software distribution, or
- * online at http://secondlife.com/developers/opensource/flossexception
+ * 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.
*
- * By copying, modifying or distributing this software, you acknowledge
- * that you have read and understood your obligations described above,
- * and agree to abide by those obligations.
+ * 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.
*
- * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
- * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
- * COMPLETENESS OR PERFORMANCE.
+ * 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$
*/
@@ -33,6 +28,9 @@
#define LL_LLSTL_H
#include <functional>
+#include <algorithm>
+#include <map>
+#include <vector>
#include <set>
#include <deque>
@@ -76,6 +74,9 @@ struct compare_pointer_contents
// The general form is:
//
// std::for_each(cont.begin(), cont.end(), DeletePointer());
+// somemap.clear();
+//
+// Don't forget to clear()!
struct DeletePointer
{
@@ -92,7 +93,7 @@ struct DeletePointerArray
}
};
-// DeletePointer is a simple helper for deleting all pointers in a map.
+// DeletePairedPointer is a simple helper for deleting all pointers in a map.
// The general form is:
//
// std::for_each(somemap.begin(), somemap.end(), DeletePairedPointer());
@@ -102,6 +103,7 @@ struct DeletePairedPointer
template<typename T> void operator()(T &ptr) const
{
delete ptr.second;
+ ptr.second = NULL;
}
};
struct DeletePairedPointerArray
@@ -109,6 +111,7 @@ struct DeletePairedPointerArray
template<typename T> void operator()(T &ptr) const
{
delete[] ptr.second;
+ ptr.second = NULL;
}
};
diff --git a/indra/llcommon/llstreamtools.cpp b/indra/llcommon/llstreamtools.cpp
index 8d4a3ef6b8..d7a6f47932 100644
--- a/indra/llcommon/llstreamtools.cpp
+++ b/indra/llcommon/llstreamtools.cpp
@@ -2,30 +2,25 @@
* @file llstreamtools.cpp
* @brief some helper functions for parsing legacy simstate and asset files.
*
- * $LicenseInfo:firstyear=2005&license=viewergpl$
- *
- * Copyright (c) 2005-2007, Linden Research, Inc.
- *
+ * $LicenseInfo:firstyear=2005&license=viewerlgpl$
* Second Life Viewer Source Code
- * The source code in this file ("Source Code") is provided by Linden Lab
- * to you under the terms of the GNU General Public License, version 2.0
- * ("GPL"), unless you have obtained a separate licensing agreement
- * ("Other License"), formally executed by you and Linden Lab. Terms of
- * the GPL can be found in doc/GPL-license.txt in this distribution, or
- * online at http://secondlife.com/developers/opensource/gplv2
+ * 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.
*
- * There are special exceptions to the terms and conditions of the GPL as
- * it is applied to this Source Code. View the full text of the exception
- * in the file doc/FLOSS-exception.txt in this software distribution, or
- * online at http://secondlife.com/developers/opensource/flossexception
+ * 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.
*
- * By copying, modifying or distributing this software, you acknowledge
- * that you have read and understood your obligations described above,
- * and agree to abide by those obligations.
+ * 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
*
- * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
- * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
- * COMPLETENESS OR PERFORMANCE.
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
* $/LicenseInfo$
*/
@@ -44,7 +39,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();
@@ -56,7 +51,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) )
{
@@ -71,7 +66,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())
@@ -89,7 +84,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();
@@ -99,7 +94,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')
@@ -131,7 +126,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);
@@ -180,7 +175,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);
@@ -228,7 +223,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
@@ -245,7 +240,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
@@ -263,20 +258,14 @@ bool get_word(std::string& output_string, std::istream& input_stream, int n)
// get everything up to and including the next newline
bool get_line(std::string& output_string, std::istream& input_stream)
{
- char c = input_stream.get();
+ output_string.clear();
+ int c = input_stream.get();
while (input_stream.good())
{
- if ('\r' == c)
- {
- // skip carriage returns
- }
- else
+ output_string += c;
+ if ('\n' == c)
{
- output_string += c;
- if ('\n' == c)
- {
- break;
- }
+ break;
}
c = input_stream.get();
}
@@ -288,27 +277,21 @@ bool get_line(std::string& output_string, std::istream& input_stream)
// add a newline on the end if bail before actual line ending
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++;
output_string += c;
- if ('\r' == c)
+ if ('\n' == c)
{
- // skip carriage returns
+ break;
}
- else
+ if (char_count >= n)
{
- if ('\n' == c)
- {
- break;
- }
- if (char_count >= n)
- {
- output_string.append("\n");
- break;
- }
+ output_string.append("\n");
+ break;
}
c = input_stream.get();
}
@@ -408,49 +391,6 @@ void replace_newlines_with_whitespace(std::string& line)
}
}
-// returns 1 for solitary "{"
-// returns -1 for solitary "}"
-// otherwise returns 0
-int get_brace_count(const std::string& line)
-{
- int index = 0;
- int line_size = line.size();
- char c = 0;
- while (index < line_size)
- {
- c = line[index];
- index++;
- if (!isspace(c))
- {
- break;
- }
- }
- char brace = c;
- // make sure the rest of the line is whitespace
- while (index < line_size)
- {
- c = line[index];
- if (!isspace(c))
- {
- break;
- }
- index++;
- }
- if ('\n' != c)
- {
- return 0;
- }
- if ('{' == brace)
- {
- return 1;
- }
- else if ('}' == brace)
- {
- return -1;
- }
- return 0;
-}
-
// erases any double-quote characters in 'line'
void remove_double_quotes(std::string& line)
{
@@ -490,7 +430,7 @@ void get_keyword_and_value(std::string& keyword,
while (line_index < line_size)
{
c = line[line_index];
- if (!isspace(c))
+ if (!LLStringOps::isSpace(c))
{
break;
}
@@ -498,11 +438,11 @@ void get_keyword_and_value(std::string& keyword,
}
// get the keyword
- keyword.assign("");
+ keyword.clear();
while (line_index < line_size)
{
c = line[line_index];
- if (isspace(c) || '\r' == c || '\n' == c)
+ if (LLStringOps::isSpace(c) || '\r' == c || '\n' == c)
{
break;
}
@@ -510,6 +450,8 @@ void get_keyword_and_value(std::string& keyword,
line_index++;
}
+ // get the value
+ value.clear();
if (keyword.size() > 0
&& '\r' != line[line_index]
&& '\n' != line[line_index])
@@ -523,8 +465,6 @@ void get_keyword_and_value(std::string& keyword,
line_index++;
}
- // get the value
- value.assign("");
while (line_index < line_size)
{
c = line[line_index];
diff --git a/indra/llcommon/llstreamtools.h b/indra/llcommon/llstreamtools.h
index b024112f9f..1b04bf91d7 100644
--- a/indra/llcommon/llstreamtools.h
+++ b/indra/llcommon/llstreamtools.h
@@ -2,30 +2,25 @@
* @file llstreamtools.h
* @brief some helper functions for parsing legacy simstate and asset files.
*
- * $LicenseInfo:firstyear=2005&license=viewergpl$
- *
- * Copyright (c) 2005-2007, Linden Research, Inc.
- *
+ * $LicenseInfo:firstyear=2005&license=viewerlgpl$
* Second Life Viewer Source Code
- * The source code in this file ("Source Code") is provided by Linden Lab
- * to you under the terms of the GNU General Public License, version 2.0
- * ("GPL"), unless you have obtained a separate licensing agreement
- * ("Other License"), formally executed by you and Linden Lab. Terms of
- * the GPL can be found in doc/GPL-license.txt in this distribution, or
- * online at http://secondlife.com/developers/opensource/gplv2
+ * Copyright (C) 2010, Linden Research, Inc.
*
- * There are special exceptions to the terms and conditions of the GPL as
- * it is applied to this Source Code. View the full text of the exception
- * in the file doc/FLOSS-exception.txt in this software distribution, or
- * online at http://secondlife.com/developers/opensource/flossexception
+ * 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.
*
- * By copying, modifying or distributing this software, you acknowledge
- * that you have read and understood your obligations described above,
- * and agree to abide by those obligations.
+ * 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.
*
- * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
- * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
- * COMPLETENESS OR PERFORMANCE.
+ * 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$
*/
@@ -38,23 +33,23 @@
// unless specifed otherwise these all return input_stream.good()
// skips spaces and tabs
-bool skip_whitespace(std::istream& input_stream);
+LL_COMMON_API bool skip_whitespace(std::istream& input_stream);
// skips whitespace and newlines
-bool skip_emptyspace(std::istream& input_stream);
+LL_COMMON_API bool skip_emptyspace(std::istream& input_stream);
// skips emptyspace and lines that start with a #
-bool skip_comments_and_emptyspace(std::istream& input_stream);
+LL_COMMON_API bool skip_comments_and_emptyspace(std::istream& input_stream);
// skips to character after next newline
-bool skip_line(std::istream& input_stream);
+LL_COMMON_API bool skip_line(std::istream& input_stream);
// skips to beginning of next non-emptyspace
-bool skip_to_next_word(std::istream& input_stream);
+LL_COMMON_API bool skip_to_next_word(std::istream& input_stream);
// skips to character after the end of next keyword
// a 'keyword' is defined as the first word on a line
-bool skip_to_end_of_next_keyword(const char* keyword, std::istream& input_stream);
+LL_COMMON_API bool skip_to_end_of_next_keyword(const char* keyword, std::istream& input_stream);
// skip_to_start_of_next_keyword() is disabled -- might tickle corruption bug
// in windows iostream
@@ -64,14 +59,14 @@ bool skip_to_end_of_next_keyword(const char* keyword, std::istream& input_stream
// characters are pulled out of input_stream and appended to output_string
// returns result of input_stream.good() after characters are pulled
-bool get_word(std::string& output_string, std::istream& input_stream);
-bool get_line(std::string& output_string, std::istream& input_stream);
+LL_COMMON_API bool get_word(std::string& output_string, std::istream& input_stream);
+LL_COMMON_API bool get_line(std::string& output_string, std::istream& input_stream);
// characters are pulled out of input_stream (up to a max of 'n')
// and appended to output_string
// returns result of input_stream.good() after characters are pulled
-bool get_word(std::string& output_string, std::istream& input_stream, int n);
-bool get_line(std::string& output_string, std::istream& input_stream, int n);
+LL_COMMON_API bool get_word(std::string& output_string, std::istream& input_stream, int n);
+LL_COMMON_API bool get_line(std::string& output_string, std::istream& input_stream, int n);
// unget_line() is disabled -- might tickle corruption bug in windows iostream
//// backs up the input_stream by line_size + 1 characters
@@ -81,33 +76,28 @@ bool get_line(std::string& output_string, std::istream& input_stream, int n);
// removes the last char in 'line' if it matches 'c'
// returns true if removed last char
-bool remove_last_char(char c, std::string& line);
+LL_COMMON_API bool remove_last_char(char c, std::string& line);
// replaces escaped characters with the correct characters from left to right
// "\\" ---> '\\'
// "\n" ---> '\n'
-void unescape_string(std::string& line);
+LL_COMMON_API void unescape_string(std::string& line);
// replaces unescaped characters with expanded equivalents from left to right
// '\\' ---> "\\"
// '\n' ---> "\n"
-void escape_string(std::string& line);
+LL_COMMON_API void escape_string(std::string& line);
// replaces each '\n' character with ' '
-void replace_newlines_with_whitespace(std::string& line);
-
-// returns 1 for solitary "{"
-// returns -1 for solitary "}"
-// otherwise returns 0
-int get_brace_count(const std::string& line);
+LL_COMMON_API void replace_newlines_with_whitespace(std::string& line);
// erases any double-quote characters in line
-void remove_double_quotes(std::string& line);
+LL_COMMON_API void remove_double_quotes(std::string& line);
// the 'keyword' is defined as the first word on a line
// the 'value' is everything after the keyword on the same line
// starting at the first non-whitespace and ending right before the newline
-void get_keyword_and_value(std::string& keyword,
+LL_COMMON_API void get_keyword_and_value(std::string& keyword,
std::string& value,
const std::string& line);
@@ -115,13 +105,13 @@ void get_keyword_and_value(std::string& keyword,
// read anymore or until we hit the count. Some istream
// implimentations have a max that they will read.
// Returns the number of bytes read.
-std::streamsize fullread(
+LL_COMMON_API std::streamsize fullread(
std::istream& istr,
char* buf,
std::streamsize requested);
-std::istream& operator>>(std::istream& str, const char *tocheck);
+LL_COMMON_API std::istream& operator>>(std::istream& str, const char *tocheck);
#endif
diff --git a/indra/llcommon/llstrider.h b/indra/llcommon/llstrider.h
index e619ceb51d..f4c43bac61 100644
--- a/indra/llcommon/llstrider.h
+++ b/indra/llcommon/llstrider.h
@@ -1,30 +1,25 @@
/**
* @file llstrider.h
*
- * $LicenseInfo:firstyear=2001&license=viewergpl$
- *
- * Copyright (c) 2001-2007, Linden Research, Inc.
- *
+ * $LicenseInfo:firstyear=2001&license=viewerlgpl$
* Second Life Viewer Source Code
- * The source code in this file ("Source Code") is provided by Linden Lab
- * to you under the terms of the GNU General Public License, version 2.0
- * ("GPL"), unless you have obtained a separate licensing agreement
- * ("Other License"), formally executed by you and Linden Lab. Terms of
- * the GPL can be found in doc/GPL-license.txt in this distribution, or
- * online at http://secondlife.com/developers/opensource/gplv2
+ * Copyright (C) 2010, Linden Research, Inc.
*
- * There are special exceptions to the terms and conditions of the GPL as
- * it is applied to this Source Code. View the full text of the exception
- * in the file doc/FLOSS-exception.txt in this software distribution, or
- * online at http://secondlife.com/developers/opensource/flossexception
+ * 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.
*
- * By copying, modifying or distributing this software, you acknowledge
- * that you have read and understood your obligations described above,
- * and agree to abide by those obligations.
+ * 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.
*
- * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
- * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
- * COMPLETENESS OR PERFORMANCE.
+ * 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$
*/
@@ -50,7 +45,7 @@ public:
void setStride (S32 skipBytes) { mSkip = (skipBytes ? skipBytes : sizeof(Object));}
void skip(const U32 index) { mBytep += mSkip*index;}
-
+ U32 getSkip() const { return mSkip; }
Object* get() { return mObjectp; }
Object* operator->() { return mObjectp; }
Object& operator *() { return *mObjectp; }
diff --git a/indra/llcommon/llstring.cpp b/indra/llcommon/llstring.cpp
index a688bc1c6f..f3b48b0156 100644
--- a/indra/llcommon/llstring.cpp
+++ b/indra/llcommon/llstring.cpp
@@ -1,31 +1,26 @@
/**
* @file llstring.cpp
- * @brief String utility functions and the LLString class.
+ * @brief String utility functions and the std::string class.
*
- * $LicenseInfo:firstyear=2001&license=viewergpl$
- *
- * Copyright (c) 2001-2007, Linden Research, Inc.
- *
+ * $LicenseInfo:firstyear=2001&license=viewerlgpl$
* Second Life Viewer Source Code
- * The source code in this file ("Source Code") is provided by Linden Lab
- * to you under the terms of the GNU General Public License, version 2.0
- * ("GPL"), unless you have obtained a separate licensing agreement
- * ("Other License"), formally executed by you and Linden Lab. Terms of
- * the GPL can be found in doc/GPL-license.txt in this distribution, or
- * online at http://secondlife.com/developers/opensource/gplv2
+ * 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.
*
- * There are special exceptions to the terms and conditions of the GPL as
- * it is applied to this Source Code. View the full text of the exception
- * in the file doc/FLOSS-exception.txt in this software distribution, or
- * online at http://secondlife.com/developers/opensource/flossexception
+ * 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.
*
- * By copying, modifying or distributing this software, you acknowledge
- * that you have read and understood your obligations described above,
- * and agree to abide by those obligations.
+ * 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
*
- * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
- * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
- * COMPLETENESS OR PERFORMANCE.
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
* $/LicenseInfo$
*/
@@ -41,12 +36,21 @@
#include <winnls.h> // for WideCharToMultiByte
#endif
+LLFastTimer::DeclareTimer FT_STRING_FORMAT("String Format");
+
+
std::string ll_safe_string(const char* in)
{
if(in) return std::string(in);
return std::string();
}
+std::string ll_safe_string(const char* in, S32 maxlen)
+{
+ if(in) return std::string(in, maxlen);
+ return std::string();
+}
+
U8 hex_as_nybble(char hex)
{
if((hex >= '0') && (hex <= '9'))
@@ -64,13 +68,31 @@ U8 hex_as_nybble(char hex)
return 0; // uh - oh, not hex any more...
}
+bool iswindividual(llwchar elem)
+{
+ U32 cur_char = (U32)elem;
+ bool result = false;
+ if (0x2E80<= cur_char && cur_char <= 0x9FFF)
+ {
+ result = true;
+ }
+ else if (0xAC00<= cur_char && cur_char <= 0xD7A0 )
+ {
+ result = true;
+ }
+ else if (0xF900<= cur_char && cur_char <= 0xFA60 )
+ {
+ result = true;
+ }
+ return result;
+}
-bool _read_file_into_string(std::string& str, const char* filename)
+bool _read_file_into_string(std::string& str, const std::string& filename)
{
llifstream ifs(filename, llifstream::binary);
if (!ifs.is_open())
{
- llinfos << "Unable to open file" << filename << llendl;
+ llinfos << "Unable to open file " << filename << llendl;
return false;
}
@@ -127,7 +149,7 @@ S32 wchar_to_utf8chars(llwchar in_char, char* outchars)
*outchars++ = 0xF0 | (cur_char >> 18);
*outchars++ = 0x80 | ((cur_char >> 12) & 0x3F);
*outchars++ = 0x80 | ((cur_char >> 6) & 0x3F);
- *outchars++ = 0x80 | cur_char & 0x3F;
+ *outchars++ = 0x80 | (cur_char & 0x3F);
}
else if (cur_char < 0x4000000)
{
@@ -135,7 +157,7 @@ S32 wchar_to_utf8chars(llwchar in_char, char* outchars)
*outchars++ = 0x80 | ((cur_char >> 18) & 0x3F);
*outchars++ = 0x80 | ((cur_char >> 12) & 0x3F);
*outchars++ = 0x80 | ((cur_char >> 6) & 0x3F);
- *outchars++ = 0x80 | cur_char & 0x3F;
+ *outchars++ = 0x80 | (cur_char & 0x3F);
}
else if (cur_char < 0x80000000)
{
@@ -144,7 +166,7 @@ S32 wchar_to_utf8chars(llwchar in_char, char* outchars)
*outchars++ = 0x80 | ((cur_char >> 18) & 0x3F);
*outchars++ = 0x80 | ((cur_char >> 12) & 0x3F);
*outchars++ = 0x80 | ((cur_char >> 6) & 0x3F);
- *outchars++ = 0x80 | cur_char & 0x3F;
+ *outchars++ = 0x80 | (cur_char & 0x3F);
}
else
{
@@ -174,20 +196,6 @@ S32 utf16chars_to_wchar(const U16* inchars, llwchar* outchar)
return inchars - base;
}
-S32 utf16chars_to_utf8chars(const U16* inchars, char* outchars, S32* nchars8p)
-{
- // Get 32 bit char32
- llwchar char32;
- S32 nchars16 = utf16chars_to_wchar(inchars, &char32);
- // Convert to utf8
- S32 nchars8 = wchar_to_utf8chars(char32, outchars);
- if (nchars8p)
- {
- *nchars8p = nchars8;
- }
- return nchars16;
-}
-
llutf16string wstring_to_utf16str(const LLWString &utf32str, S32 len)
{
llutf16string out;
@@ -216,7 +224,7 @@ llutf16string wstring_to_utf16str(const LLWString &utf32str)
return wstring_to_utf16str(utf32str, len);
}
-llutf16string utf8str_to_utf16str ( const LLString& utf8str )
+llutf16string utf8str_to_utf16str ( const std::string& utf8str )
{
LLWString wstr = utf8str_to_wstring ( utf8str );
return wstring_to_utf16str ( wstr );
@@ -492,210 +500,10 @@ std::string utf16str_to_utf8str(const llutf16string& utf16str, S32 len)
return wstring_to_utf8str(utf16str_to_wstring(utf16str, len), len);
}
-
-//LLWString wstring_truncate(const LLWString &wstr, const S32 max_len)
-//{
-// return wstr.substr(0, llmin((S32)wstr.length(), max_len));
-//}
-//
-//
-//LLWString wstring_trim(const LLWString &wstr)
-//{
-// LLWString outstr;
-// outstr = wstring_trimhead(wstr);
-// outstr = wstring_trimtail(outstr);
-// return outstr;
-//}
-//
-//
-//LLWString wstring_trimhead(const LLWString &wstr)
-//{
-// if(wstr.empty())
-// {
-// return wstr;
-// }
-//
-// S32 i = 0;
-// while((i < (S32)wstr.length()) && iswspace(wstr[i]))
-// {
-// i++;
-// }
-// return wstr.substr(i, wstr.length() - i);
-//}
-//
-//
-//LLWString wstring_trimtail(const LLWString &wstr)
-//{
-// if(wstr.empty())
-// {
-// return wstr;
-// }
-//
-// S32 len = (S32)wstr.length();
-//
-// S32 i = len - 1;
-// while (i >= 0 && iswspace(wstr[i]))
-// {
-// i--;
-// }
-//
-// if (i >= 0)
-// {
-// return wstr.substr(0, i + 1);
-// }
-// return wstr;
-//}
-//
-//
-//LLWString wstring_copyinto(const LLWString &dest, const LLWString &src, const S32 insert_offset)
-//{
-// llassert( insert_offset <= (S32)dest.length() );
-//
-// LLWString out_str = dest.substr(0, insert_offset);
-// out_str += src;
-// LLWString tail = dest.substr(insert_offset);
-// out_str += tail;
-//
-// return out_str;
-//}
-
-
-//LLWString wstring_detabify(const LLWString &wstr, const S32 num_spaces)
-//{
-// LLWString out_str;
-// // Replace tabs with spaces
-// for (S32 i = 0; i < (S32)wstr.length(); i++)
-// {
-// if (wstr[i] == '\t')
-// {
-// for (S32 j = 0; j < num_spaces; j++)
-// out_str += ' ';
-// }
-// else
-// {
-// out_str += wstr[i];
-// }
-// }
-// return out_str;
-//}
-
-
-//LLWString wstring_makeASCII(const LLWString &wstr)
-//{
-// // Replace non-ASCII chars with replace_char
-// LLWString out_str = wstr;
-// for (S32 i = 0; i < (S32)out_str.length(); i++)
-// {
-// if (out_str[i] > 0x7f)
-// {
-// out_str[i] = LL_UNKNOWN_CHAR;
-// }
-// }
-// return out_str;
-//}
-
-
-//LLWString wstring_substChar(const LLWString &wstr, const llwchar target_char, const llwchar replace_char)
-//{
-// // Replace all occurences of target_char with replace_char
-// LLWString out_str = wstr;
-// for (S32 i = 0; i < (S32)out_str.length(); i++)
-// {
-// if (out_str[i] == target_char)
-// {
-// out_str[i] = replace_char;
-// }
-// }
-// return out_str;
-//}
-//
-//
-//LLWString wstring_tolower(const LLWString &wstr)
-//{
-// LLWString out_str = wstr;
-// for (S32 i = 0; i < (S32)out_str.length(); i++)
-// {
-// out_str[i] = towlower(out_str[i]);
-// }
-// return out_str;
-//}
-//
-//
-//LLWString wstring_convert_to_lf(const LLWString &wstr)
-//{
-// const llwchar CR = 13;
-// // Remove carriage returns from string with CRLF
-// LLWString out_str;
-//
-// for (S32 i = 0; i < (S32)wstr.length(); i++)
-// {
-// if (wstr[i] != CR)
-// {
-// out_str += wstr[i];
-// }
-// }
-// return out_str;
-//}
-//
-//
-//LLWString wstring_convert_to_crlf(const LLWString &wstr)
-//{
-// const llwchar LF = 10;
-// const llwchar CR = 13;
-// // Remove carriage returns from string with CRLF
-// LLWString out_str;
-//
-// for (S32 i = 0; i < (S32)wstr.length(); i++)
-// {
-// if (wstr[i] == LF)
-// {
-// out_str += CR;
-// }
-// out_str += wstr[i];
-// }
-// return out_str;
-//}
-
-
-//S32 wstring_compare_insensitive(const LLWString &lhs, const LLWString &rhs)
-//{
-//
-// if (lhs == rhs)
-// {
-// return 0;
-// }
-//
-// if (lhs.empty())
-// {
-// return rhs.empty() ? 0 : 1;
-// }
-//
-// if (rhs.empty())
-// {
-// return -1;
-// }
-//
-//#ifdef LL_LINUX
-// // doesn't work because gcc 2.95 doesn't correctly implement c_str(). Sigh...
-// llerrs << "wstring_compare_insensitive doesn't work on Linux!" << llendl;
-// return 0;
-//#else
-// LLWString lhs_lower = lhs;
-// LLWString::toLower(lhs_lower);
-// std::string lhs_lower = wstring_to_utf8str(lhs_lower);
-// LLWString rhs_lower = lhs;
-// LLWString::toLower(rhs_lower);
-// std::string rhs_lower = wstring_to_utf8str(rhs_lower);
-//
-// return strcmp(lhs_lower.c_str(), rhs_lower.c_str());
-//#endif
-//}
-
-
std::string utf8str_trim(const std::string& utf8str)
{
LLWString wstr = utf8str_to_wstring(utf8str);
- LLWString::trim(wstr);
+ LLWStringUtil::trim(wstr);
return wstring_to_utf8str(wstr);
}
@@ -703,7 +511,7 @@ std::string utf8str_trim(const std::string& utf8str)
std::string utf8str_tolower(const std::string& utf8str)
{
LLWString out_str = utf8str_to_wstring(utf8str);
- LLWString::toLower(out_str);
+ LLWStringUtil::toLower(out_str);
return wstring_to_utf8str(out_str);
}
@@ -712,7 +520,7 @@ S32 utf8str_compare_insensitive(const std::string& lhs, const std::string& rhs)
{
LLWString wlhs = utf8str_to_wstring(lhs);
LLWString wrhs = utf8str_to_wstring(rhs);
- return LLWString::compareInsensitive(wlhs.c_str(), wrhs.c_str());
+ return LLWStringUtil::compareInsensitive(wlhs, wrhs);
}
std::string utf8str_truncate(const std::string& utf8str, const S32 max_len)
@@ -756,7 +564,7 @@ std::string utf8str_substChar(
const llwchar replace_char)
{
LLWString wstr = utf8str_to_wstring(utf8str);
- LLWString::replaceChar(wstr, target_char, replace_char);
+ LLWStringUtil::replaceChar(wstr, target_char, replace_char);
//wstr = wstring_substChar(wstr, target_char, replace_char);
return wstring_to_utf8str(wstr);
}
@@ -764,7 +572,7 @@ std::string utf8str_substChar(
std::string utf8str_makeASCII(const std::string& utf8str)
{
LLWString wstr = utf8str_to_wstring(utf8str);
- LLWString::_makeASCII(wstr);
+ LLWStringUtil::_makeASCII(wstr);
return wstring_to_utf8str(wstr);
}
@@ -804,26 +612,29 @@ std::string utf8str_removeCRLF(const std::string& utf8str)
#if LL_WINDOWS
// documentation moved to header. Phoenix 2007-11-27
-int safe_snprintf(char *str, size_t size, const char *format, ...)
+namespace snprintf_hack
{
- va_list args;
- va_start(args, format);
-
- int num_written = _vsnprintf(str, size, format, args); /* Flawfinder: ignore */
- va_end(args);
-
- str[size-1] = '\0'; // always null terminate
- return num_written;
+ int snprintf(char *str, size_t size, const char *format, ...)
+ {
+ va_list args;
+ va_start(args, format);
+
+ int num_written = _vsnprintf(str, size, format, args); /* Flawfinder: ignore */
+ va_end(args);
+
+ str[size-1] = '\0'; // always null terminate
+ return num_written;
+ }
}
-std::string ll_convert_wide_to_string(const wchar_t* in)
+std::string ll_convert_wide_to_string(const wchar_t* in, unsigned int code_page)
{
std::string out;
if(in)
{
int len_in = wcslen(in);
int len_out = WideCharToMultiByte(
- CP_ACP,
+ code_page,
0,
in,
len_in,
@@ -838,7 +649,7 @@ std::string ll_convert_wide_to_string(const wchar_t* in)
if(pout)
{
WideCharToMultiByte(
- CP_ACP,
+ code_page,
0,
in,
len_in,
@@ -852,8 +663,56 @@ std::string ll_convert_wide_to_string(const wchar_t* in)
}
return out;
}
+
+wchar_t* ll_convert_string_to_wide(const std::string& in, unsigned int code_page)
+{
+ // From review:
+ // We can preallocate a wide char buffer that is the same length (in wchar_t elements) as the utf8 input,
+ // plus one for a null terminator, and be guaranteed to not overflow.
+
+ // Normally, I'd call that sort of thing premature optimization,
+ // but we *are* seeing string operations taking a bunch of time, especially when constructing widgets.
+// int output_str_len = MultiByteToWideChar(code_page, 0, in.c_str(), in.length(), NULL, 0);
+
+ // reserve place to NULL terminator
+ int output_str_len = in.length();
+ wchar_t* w_out = new wchar_t[output_str_len + 1];
+
+ memset(w_out, 0, output_str_len + 1);
+ int real_output_str_len = MultiByteToWideChar (code_page, 0, in.c_str(), in.length(), w_out, output_str_len);
+
+ //looks like MultiByteToWideChar didn't add null terminator to converted string, see EXT-4858.
+ w_out[real_output_str_len] = 0;
+
+ return w_out;
+}
+
+std::string ll_convert_string_to_utf8_string(const std::string& in)
+{
+ wchar_t* w_mesg = ll_convert_string_to_wide(in, CP_ACP);
+ std::string out_utf8(ll_convert_wide_to_string(w_mesg, CP_UTF8));
+ delete[] w_mesg;
+
+ return out_utf8;
+}
#endif // LL_WINDOWS
+long LLStringOps::sPacificTimeOffset = 0;
+long LLStringOps::sLocalTimeOffset = 0;
+bool LLStringOps::sPacificDaylightTime = 0;
+std::map<std::string, std::string> LLStringOps::datetimeToCodes;
+
+std::vector<std::string> LLStringOps::sWeekDayList;
+std::vector<std::string> LLStringOps::sWeekDayShortList;
+std::vector<std::string> LLStringOps::sMonthList;
+std::vector<std::string> LLStringOps::sMonthShortList;
+
+
+std::string LLStringOps::sDayFormat;
+std::string LLStringOps::sAM;
+std::string LLStringOps::sPM;
+
+
S32 LLStringOps::collate(const llwchar* a, const llwchar* b)
{
#if LL_WINDOWS
@@ -865,9 +724,111 @@ S32 LLStringOps::collate(const llwchar* a, const llwchar* b)
#endif
}
+void LLStringOps::setupDatetimeInfo (bool daylight)
+{
+ time_t nowT, localT, gmtT;
+ struct tm * tmpT;
+
+ nowT = time (NULL);
+
+ tmpT = gmtime (&nowT);
+ gmtT = mktime (tmpT);
+
+ tmpT = localtime (&nowT);
+ localT = mktime (tmpT);
+
+ sLocalTimeOffset = (long) (gmtT - localT);
+ if (tmpT->tm_isdst)
+ {
+ sLocalTimeOffset -= 60 * 60; // 1 hour
+ }
+
+ sPacificDaylightTime = daylight;
+ sPacificTimeOffset = (sPacificDaylightTime? 7 : 8 ) * 60 * 60;
+
+ datetimeToCodes["wkday"] = "%a"; // Thu
+ datetimeToCodes["weekday"] = "%A"; // Thursday
+ datetimeToCodes["year4"] = "%Y"; // 2009
+ datetimeToCodes["year"] = "%Y"; // 2009
+ datetimeToCodes["year2"] = "%y"; // 09
+ datetimeToCodes["mth"] = "%b"; // Aug
+ datetimeToCodes["month"] = "%B"; // August
+ datetimeToCodes["mthnum"] = "%m"; // 08
+ datetimeToCodes["day"] = "%d"; // 31
+ datetimeToCodes["sday"] = "%-d"; // 9
+ datetimeToCodes["hour24"] = "%H"; // 14
+ datetimeToCodes["hour"] = "%H"; // 14
+ datetimeToCodes["hour12"] = "%I"; // 02
+ datetimeToCodes["min"] = "%M"; // 59
+ datetimeToCodes["ampm"] = "%p"; // AM
+ datetimeToCodes["second"] = "%S"; // 59
+ datetimeToCodes["timezone"] = "%Z"; // PST
+}
+
+void tokenizeStringToArray(const std::string& data, std::vector<std::string>& output)
+{
+ output.clear();
+ size_t length = data.size();
+
+ // tokenize it and put it in the array
+ std::string cur_word;
+ for(size_t i = 0; i < length; ++i)
+ {
+ if(data[i] == ':')
+ {
+ output.push_back(cur_word);
+ cur_word.clear();
+ }
+ else
+ {
+ cur_word.append(1, data[i]);
+ }
+ }
+ output.push_back(cur_word);
+}
+
+void LLStringOps::setupWeekDaysNames(const std::string& data)
+{
+ tokenizeStringToArray(data,sWeekDayList);
+}
+void LLStringOps::setupWeekDaysShortNames(const std::string& data)
+{
+ tokenizeStringToArray(data,sWeekDayShortList);
+}
+void LLStringOps::setupMonthNames(const std::string& data)
+{
+ tokenizeStringToArray(data,sMonthList);
+}
+void LLStringOps::setupMonthShortNames(const std::string& data)
+{
+ tokenizeStringToArray(data,sMonthShortList);
+}
+void LLStringOps::setupDayFormat(const std::string& data)
+{
+ sDayFormat = data;
+}
+
+
+std::string LLStringOps::getDatetimeCode (std::string key)
+{
+ std::map<std::string, std::string>::iterator iter;
+
+ iter = datetimeToCodes.find (key);
+ if (iter != datetimeToCodes.end())
+ {
+ return iter->second;
+ }
+ else
+ {
+ return std::string("");
+ }
+}
+
+
namespace LLStringFn
{
- void replace_nonprintable(std::basic_string<char>& string, char replacement)
+ // NOTE - this restricts output to ascii
+ void replace_nonprintable_in_ascii(std::basic_string<char>& string, char replacement)
{
const char MIN = 0x20;
std::basic_string<char>::size_type len = string.size();
@@ -880,23 +841,9 @@ namespace LLStringFn
}
}
- void replace_nonprintable(
- std::basic_string<llwchar>& string,
- llwchar replacement)
- {
- const llwchar MIN = 0x20;
- const llwchar MAX = 0x7f;
- std::basic_string<llwchar>::size_type len = string.size();
- for(std::basic_string<llwchar>::size_type ii = 0; ii < len; ++ii)
- {
- if((string[ii] < MIN) || (string[ii] > MAX))
- {
- string[ii] = replacement;
- }
- }
- }
- void replace_nonprintable_and_pipe(std::basic_string<char>& str,
+ // NOTE - this restricts output to ascii
+ void replace_nonprintable_and_pipe_in_ascii(std::basic_string<char>& str,
char replacement)
{
const char MIN = 0x20;
@@ -911,23 +858,456 @@ namespace LLStringFn
}
}
- void replace_nonprintable_and_pipe(std::basic_string<llwchar>& str,
- llwchar replacement)
+ // https://wiki.lindenlab.com/wiki/Unicode_Guidelines has details on
+ // allowable code points for XML. Specifically, they are:
+ // 0x09, 0x0a, 0x0d, and 0x20 on up. JC
+ std::string strip_invalid_xml(const std::string& instr)
{
- const llwchar MIN = 0x20;
- const llwchar MAX = 0x7f;
- const llwchar PIPE = 0x7c;
- std::basic_string<llwchar>::size_type len = str.size();
- for(std::basic_string<llwchar>::size_type ii = 0; ii < len; ++ii)
+ std::string output;
+ output.reserve( instr.size() );
+ std::string::const_iterator it = instr.begin();
+ while (it != instr.end())
{
- if( (str[ii] < MIN) || (str[ii] > MAX) || (str[ii] == PIPE) )
+ // Must compare as unsigned for >=
+ // Test most likely match first
+ const unsigned char c = (unsigned char)*it;
+ if ( c >= (unsigned char)0x20 // SPACE
+ || c == (unsigned char)0x09 // TAB
+ || c == (unsigned char)0x0a // LINE_FEED
+ || c == (unsigned char)0x0d ) // CARRIAGE_RETURN
{
- str[ii] = replacement;
+ output.push_back(c);
+ }
+ ++it;
+ }
+ return output;
+ }
+
+ /**
+ * @brief Replace all control characters (c < 0x20) with replacement in
+ * string.
+ */
+ void replace_ascii_controlchars(std::basic_string<char>& string, char replacement)
+ {
+ const unsigned char MIN = 0x20;
+ std::basic_string<char>::size_type len = string.size();
+ for(std::basic_string<char>::size_type ii = 0; ii < len; ++ii)
+ {
+ const unsigned char c = (unsigned char) string[ii];
+ if(c < MIN)
+ {
+ string[ii] = replacement;
}
}
}
}
+////////////////////////////////////////////////////////////
+
+// Forward specialization of LLStringUtil::format before use in LLStringUtil::formatDatetime.
+template<>
+S32 LLStringUtil::format(std::string& s, const format_map_t& substitutions);
+
+//static
+template<>
+void LLStringUtil::getTokens(const std::string& instr, std::vector<std::string >& tokens, const std::string& delims)
+{
+ std::string currToken;
+ std::string::size_type begIdx, endIdx;
+
+ begIdx = instr.find_first_not_of (delims);
+ while (begIdx != std::string::npos)
+ {
+ endIdx = instr.find_first_of (delims, begIdx);
+ if (endIdx == std::string::npos)
+ {
+ endIdx = instr.length();
+ }
+
+ currToken = instr.substr(begIdx, endIdx - begIdx);
+ LLStringUtil::trim (currToken);
+ tokens.push_back(currToken);
+ begIdx = instr.find_first_not_of (delims, endIdx);
+ }
+}
+
+template<>
+LLStringUtil::size_type LLStringUtil::getSubstitution(const std::string& instr, size_type& start, std::vector<std::string>& tokens)
+{
+ const std::string delims (",");
+
+ // Find the first ]
+ size_type pos2 = instr.find(']', start);
+ if (pos2 == std::string::npos)
+ return std::string::npos;
+
+ // Find the last [ before ]
+ size_type pos1 = instr.find_last_of('[', pos2-1);
+ if (pos1 == std::string::npos || pos1 < start)
+ return std::string::npos;
+
+ getTokens(std::string(instr,pos1+1,pos2-pos1-1), tokens, delims);
+ start = pos2+1;
+
+ return pos1;
+}
+
+// static
+template<>
+bool LLStringUtil::simpleReplacement(std::string &replacement, std::string token, const format_map_t& substitutions)
+{
+ // see if we have a replacement for the bracketed string (without the brackets)
+ // test first using has() because if we just look up with operator[] we get back an
+ // empty string even if the value is missing. We want to distinguish between
+ // missing replacements and deliberately empty replacement strings.
+ format_map_t::const_iterator iter = substitutions.find(token);
+ if (iter != substitutions.end())
+ {
+ replacement = iter->second;
+ return true;
+ }
+ // if not, see if there's one WITH brackets
+ iter = substitutions.find(std::string("[" + token + "]"));
+ if (iter != substitutions.end())
+ {
+ replacement = iter->second;
+ return true;
+ }
+
+ return false;
+}
+
+// static
+template<>
+bool LLStringUtil::simpleReplacement(std::string &replacement, std::string token, const LLSD& substitutions)
+{
+ // see if we have a replacement for the bracketed string (without the brackets)
+ // test first using has() because if we just look up with operator[] we get back an
+ // empty string even if the value is missing. We want to distinguish between
+ // missing replacements and deliberately empty replacement strings.
+ if (substitutions.has(token))
+ {
+ replacement = substitutions[token].asString();
+ return true;
+ }
+ // if not, see if there's one WITH brackets
+ else if (substitutions.has(std::string("[" + token + "]")))
+ {
+ replacement = substitutions[std::string("[" + token + "]")].asString();
+ return true;
+ }
+
+ return false;
+}
+
+//static
+template<>
+void LLStringUtil::setLocale(std::string inLocale)
+{
+ sLocale = inLocale;
+};
+
+//static
+template<>
+std::string LLStringUtil::getLocale(void)
+{
+ return sLocale;
+};
+
+// static
+template<>
+void LLStringUtil::formatNumber(std::string& numStr, std::string decimals)
+{
+ std::stringstream strStream;
+ S32 intDecimals = 0;
+
+ convertToS32 (decimals, intDecimals);
+ if (!sLocale.empty())
+ {
+ // std::locale() throws if the locale is unknown! (EXT-7926)
+ try
+ {
+ strStream.imbue(std::locale(sLocale.c_str()));
+ } catch (const std::exception &)
+ {
+ LL_WARNS_ONCE("Locale") << "Cannot set locale to " << sLocale << LL_ENDL;
+ }
+ }
+
+ if (!intDecimals)
+ {
+ S32 intStr;
+
+ if (convertToS32(numStr, intStr))
+ {
+ strStream << intStr;
+ numStr = strStream.str();
+ }
+ }
+ else
+ {
+ F32 floatStr;
+
+ if (convertToF32(numStr, floatStr))
+ {
+ strStream << std::fixed << std::showpoint << std::setprecision(intDecimals) << floatStr;
+ numStr = strStream.str();
+ }
+ }
+}
+
+// static
+template<>
+bool LLStringUtil::formatDatetime(std::string& replacement, std::string token,
+ std::string param, S32 secFromEpoch)
+{
+ if (param == "local") // local
+ {
+ secFromEpoch -= LLStringOps::getLocalTimeOffset();
+ }
+ else if (param != "utc") // slt
+ {
+ secFromEpoch -= LLStringOps::getPacificTimeOffset();
+ }
+
+ // if never fell into those two ifs above, param must be utc
+ if (secFromEpoch < 0) secFromEpoch = 0;
+
+ LLDate datetime((F64)secFromEpoch);
+ std::string code = LLStringOps::getDatetimeCode (token);
+
+ // special case to handle timezone
+ if (code == "%Z") {
+ if (param == "utc")
+ {
+ replacement = "GMT";
+ }
+ else if (param == "local")
+ {
+ replacement = ""; // user knows their own timezone
+ }
+ else
+ {
+ // "slt" = Second Life Time, which is deprecated.
+ // If not utc or user local time, fallback to Pacific time
+ replacement = LLStringOps::getPacificDaylightTime() ? "PDT" : "PST";
+ }
+ return true;
+ }
+
+ //EXT-7013
+ //few codes are not suppotred by strtime function (example - weekdays for Japanise)
+ //so use predefined ones
+
+ //if sWeekDayList is not empty than current locale doesn't support
+ //weekday name.
+ time_t loc_seconds = (time_t) secFromEpoch;
+ if(LLStringOps::sWeekDayList.size() == 7 && code == "%A")
+ {
+ struct tm * gmt = gmtime (&loc_seconds);
+ replacement = LLStringOps::sWeekDayList[gmt->tm_wday];
+ }
+ else if(LLStringOps::sWeekDayShortList.size() == 7 && code == "%a")
+ {
+ struct tm * gmt = gmtime (&loc_seconds);
+ replacement = LLStringOps::sWeekDayShortList[gmt->tm_wday];
+ }
+ else if(LLStringOps::sMonthList.size() == 12 && code == "%B")
+ {
+ struct tm * gmt = gmtime (&loc_seconds);
+ replacement = LLStringOps::sMonthList[gmt->tm_mon];
+ }
+ else if( !LLStringOps::sDayFormat.empty() && code == "%d" )
+ {
+ struct tm * gmt = gmtime (&loc_seconds);
+ LLStringUtil::format_map_t args;
+ args["[MDAY]"] = llformat ("%d", gmt->tm_mday);
+ replacement = LLStringOps::sDayFormat;
+ LLStringUtil::format(replacement, args);
+ }
+ else if (code == "%-d")
+ {
+ struct tm * gmt = gmtime (&loc_seconds);
+ replacement = llformat ("%d", gmt->tm_mday); // day of the month without leading zero
+ }
+ else if( !LLStringOps::sAM.empty() && !LLStringOps::sPM.empty() && code == "%p" )
+ {
+ struct tm * gmt = gmtime (&loc_seconds);
+ if(gmt->tm_hour<12)
+ {
+ replacement = LLStringOps::sAM;
+ }
+ else
+ {
+ replacement = LLStringOps::sPM;
+ }
+ }
+ else
+ {
+ replacement = datetime.toHTTPDateString(code);
+ }
+
+ // *HACK: delete leading zero from hour string in case 'hour12' (code = %I) time format
+ // to show time without leading zero, e.g. 08:16 -> 8:16 (EXT-2738).
+ // We could have used '%l' format instead, but it's not supported by Windows.
+ if(code == "%I" && token == "hour12" && replacement.at(0) == '0')
+ {
+ replacement = replacement.at(1);
+ }
+
+ return !code.empty();
+}
+
+// LLStringUtil::format recogizes the following patterns.
+// All substitutions *must* be encased in []'s in the input string.
+// The []'s are optional in the substitution map.
+// [FOO_123]
+// [FOO,number,precision]
+// [FOO,datetime,format]
+
+
+// static
+template<>
+S32 LLStringUtil::format(std::string& s, const format_map_t& substitutions)
+{
+ LLFastTimer ft(FT_STRING_FORMAT);
+ S32 res = 0;
+
+ std::string output;
+ std::vector<std::string> tokens;
+
+ std::string::size_type start = 0;
+ std::string::size_type prev_start = 0;
+ std::string::size_type key_start = 0;
+ while ((key_start = getSubstitution(s, start, tokens)) != std::string::npos)
+ {
+ output += std::string(s, prev_start, key_start-prev_start);
+ prev_start = start;
+
+ bool found_replacement = false;
+ std::string replacement;
+
+ if (tokens.size() == 0)
+ {
+ found_replacement = false;
+ }
+ else if (tokens.size() == 1)
+ {
+ found_replacement = simpleReplacement (replacement, tokens[0], substitutions);
+ }
+ else if (tokens[1] == "number")
+ {
+ std::string param = "0";
+
+ if (tokens.size() > 2) param = tokens[2];
+ found_replacement = simpleReplacement (replacement, tokens[0], substitutions);
+ if (found_replacement) formatNumber (replacement, param);
+ }
+ else if (tokens[1] == "datetime")
+ {
+ std::string param;
+ if (tokens.size() > 2) param = tokens[2];
+
+ format_map_t::const_iterator iter = substitutions.find("datetime");
+ if (iter != substitutions.end())
+ {
+ S32 secFromEpoch = 0;
+ BOOL r = LLStringUtil::convertToS32(iter->second, secFromEpoch);
+ if (r)
+ {
+ found_replacement = formatDatetime(replacement, tokens[0], param, secFromEpoch);
+ }
+ }
+ }
+
+ if (found_replacement)
+ {
+ output += replacement;
+ res++;
+ }
+ else
+ {
+ // we had no replacement, use the string as is
+ // e.g. "hello [MISSING_REPLACEMENT]" or "-=[Stylized Name]=-"
+ output += std::string(s, key_start, start-key_start);
+ }
+ tokens.clear();
+ }
+ // send the remainder of the string (with no further matches for bracketed names)
+ output += std::string(s, start);
+ s = output;
+ return res;
+}
+
+//static
+template<>
+S32 LLStringUtil::format(std::string& s, const LLSD& substitutions)
+{
+ LLFastTimer ft(FT_STRING_FORMAT);
+ S32 res = 0;
+
+ if (!substitutions.isMap())
+ {
+ return res;
+ }
+
+ std::string output;
+ std::vector<std::string> tokens;
+
+ std::string::size_type start = 0;
+ std::string::size_type prev_start = 0;
+ std::string::size_type key_start = 0;
+ while ((key_start = getSubstitution(s, start, tokens)) != std::string::npos)
+ {
+ output += std::string(s, prev_start, key_start-prev_start);
+ prev_start = start;
+
+ bool found_replacement = false;
+ std::string replacement;
+
+ if (tokens.size() == 0)
+ {
+ found_replacement = false;
+ }
+ else if (tokens.size() == 1)
+ {
+ found_replacement = simpleReplacement (replacement, tokens[0], substitutions);
+ }
+ else if (tokens[1] == "number")
+ {
+ std::string param = "0";
+
+ if (tokens.size() > 2) param = tokens[2];
+ found_replacement = simpleReplacement (replacement, tokens[0], substitutions);
+ if (found_replacement) formatNumber (replacement, param);
+ }
+ else if (tokens[1] == "datetime")
+ {
+ std::string param;
+ if (tokens.size() > 2) param = tokens[2];
+
+ S32 secFromEpoch = (S32) substitutions["datetime"].asInteger();
+ found_replacement = formatDatetime (replacement, tokens[0], param, secFromEpoch);
+ }
+
+ if (found_replacement)
+ {
+ output += replacement;
+ res++;
+ }
+ else
+ {
+ // we had no replacement, use the string as is
+ // e.g. "hello [MISSING_REPLACEMENT]" or "-=[Stylized Name]=-"
+ output += std::string(s, key_start, start-key_start);
+ }
+ tokens.clear();
+ }
+ // send the remainder of the string (with no further matches for bracketed names)
+ output += std::string(s, start);
+ s = output;
+ return res;
+}
////////////////////////////////////////////////////////////
// Testing
@@ -935,19 +1315,19 @@ namespace LLStringFn
#ifdef _DEBUG
template<class T>
-void LLStringBase<T>::testHarness()
+void LLStringUtilBase<T>::testHarness()
{
- LLString s1;
+ std::string s1;
llassert( s1.c_str() == NULL );
llassert( s1.size() == 0 );
llassert( s1.empty() );
- LLString s2( "hello");
+ std::string s2( "hello");
llassert( !strcmp( s2.c_str(), "hello" ) );
llassert( s2.size() == 5 );
llassert( !s2.empty() );
- LLString s3( s2 );
+ std::string s3( s2 );
llassert( "hello" == s2 );
llassert( s2 == "hello" );
@@ -956,12 +1336,12 @@ void LLStringBase<T>::testHarness()
llassert( "gello" != s2 );
llassert( s2 != "gello" );
- LLString s4 = s2;
+ std::string s4 = s2;
llassert( !s4.empty() );
s4.empty();
llassert( s4.empty() );
- LLString s5("");
+ std::string s5("");
llassert( s5.empty() );
llassert( isValidIndex(s5, 0) );
@@ -975,8 +1355,8 @@ void LLStringBase<T>::testHarness()
llassert( s4 == "hello again!hello again!" );
- LLString s6 = s2 + " " + s2;
- LLString s7 = s6;
+ std::string s6 = s2 + " " + s2;
+ std::string s7 = s6;
llassert( s6 == s7 );
llassert( !( s6 != s7) );
llassert( !(s6 < s7) );
@@ -999,10 +1379,10 @@ void LLStringBase<T>::testHarness()
s2.insert( 1, "awn, don't yel");
llassert( s2 == "yawn, don't yell");
- LLString s8 = s2.substr( 6, 5 );
+ std::string s8 = s2.substr( 6, 5 );
llassert( s8 == "don't" );
- LLString s9 = " \t\ntest \t\t\n ";
+ std::string s9 = " \t\ntest \t\t\n ";
trim(s9);
llassert( s9 == "test" );
@@ -1017,17 +1397,17 @@ void LLStringBase<T>::testHarness()
llassert( s9 == "abc123&*(abc" );
- LLString s10( 10, 'x' );
+ std::string s10( 10, 'x' );
llassert( s10 == "xxxxxxxxxx" );
- LLString s11( "monkey in the middle", 7, 2 );
+ std::string s11( "monkey in the middle", 7, 2 );
llassert( s11 == "in" );
- LLString s12; //empty
+ std::string s12; //empty
s12 += "foo";
llassert( s12 == "foo" );
- LLString s13; //empty
+ std::string s13; //empty
s13 += 'f';
llassert( s13 == "f" );
}
diff --git a/indra/llcommon/llstring.h b/indra/llcommon/llstring.h
index 88d7e88edc..7e41e787b5 100644
--- a/indra/llcommon/llstring.h
+++ b/indra/llcommon/llstring.h
@@ -1,53 +1,58 @@
/**
* @file llstring.h
- * @brief String utility functions and LLString class.
+ * @brief String utility functions and std::string class.
*
- * $LicenseInfo:firstyear=2001&license=viewergpl$
- *
- * Copyright (c) 2001-2007, Linden Research, Inc.
- *
+ * $LicenseInfo:firstyear=2001&license=viewerlgpl$
* Second Life Viewer Source Code
- * The source code in this file ("Source Code") is provided by Linden Lab
- * to you under the terms of the GNU General Public License, version 2.0
- * ("GPL"), unless you have obtained a separate licensing agreement
- * ("Other License"), formally executed by you and Linden Lab. Terms of
- * the GPL can be found in doc/GPL-license.txt in this distribution, or
- * online at http://secondlife.com/developers/opensource/gplv2
+ * Copyright (C) 2010, Linden Research, Inc.
*
- * There are special exceptions to the terms and conditions of the GPL as
- * it is applied to this Source Code. View the full text of the exception
- * in the file doc/FLOSS-exception.txt in this software distribution, or
- * online at http://secondlife.com/developers/opensource/flossexception
+ * 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.
*
- * By copying, modifying or distributing this software, you acknowledge
- * that you have read and understood your obligations described above,
- * and agree to abide by those obligations.
+ * 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.
*
- * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
- * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
- * COMPLETENESS OR PERFORMANCE.
+ * 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$
*/
#ifndef LL_LLSTRING_H
#define LL_LLSTRING_H
+#include <string>
+#include <cstdio>
+#include <locale>
+#include <iomanip>
+#include "llsd.h"
+#include "llfasttimer.h"
+
#if LL_LINUX || LL_SOLARIS
#include <wctype.h>
#include <wchar.h>
#endif
+#include <string.h>
+
+#if LL_SOLARIS
+// stricmp and strnicmp do not exist on Solaris:
+#define stricmp strcasecmp
+#define strnicmp strncasecmp
+#endif
+
const char LL_UNKNOWN_CHAR = '?';
-class LLVector3;
-class LLVector3d;
-class LLQuaternion;
-class LLUUID;
-class LLColor4;
-class LLColor4U;
+#if LL_DARWIN || LL_LINUX || LL_SOLARIS
+// Template specialization of char_traits for U16s. Only necessary on Mac and Linux (exists on Windows already)
+#include <cstring>
-#if (LL_DARWIN || LL_SOLARIS || (LL_LINUX && __GNUC__ > 2))
-// Template specialization of char_traits for U16s. Only necessary on Mac for now (exists on Windows, unused/broken on Linux/gcc2.95)
namespace std
{
template<>
@@ -137,107 +142,121 @@ struct char_traits<U16>
};
#endif
-class LLStringOps
+class LL_COMMON_API LLStringOps
{
+private:
+ static long sPacificTimeOffset;
+ static long sLocalTimeOffset;
+ static bool sPacificDaylightTime;
+
+ static std::map<std::string, std::string> datetimeToCodes;
+
public:
- static char toUpper(char elem) { return toupper(elem); }
+ static std::vector<std::string> sWeekDayList;
+ static std::vector<std::string> sWeekDayShortList;
+ static std::vector<std::string> sMonthList;
+ static std::vector<std::string> sMonthShortList;
+ static std::string sDayFormat;
+
+ static std::string sAM;
+ static std::string sPM;
+
+ static char toUpper(char elem) { return toupper((unsigned char)elem); }
static llwchar toUpper(llwchar elem) { return towupper(elem); }
- static char toLower(char elem) { return tolower(elem); }
+ static char toLower(char elem) { return tolower((unsigned char)elem); }
static llwchar toLower(llwchar elem) { return towlower(elem); }
- static BOOL isSpace(char elem) { return isspace(elem) != 0; }
- static BOOL isSpace(llwchar elem) { return iswspace(elem) != 0; }
+ static bool isSpace(char elem) { return isspace((unsigned char)elem) != 0; }
+ static bool isSpace(llwchar elem) { return iswspace(elem) != 0; }
+
+ static bool isUpper(char elem) { return isupper((unsigned char)elem) != 0; }
+ static bool isUpper(llwchar elem) { return iswupper(elem) != 0; }
+
+ static bool isLower(char elem) { return islower((unsigned char)elem) != 0; }
+ static bool isLower(llwchar elem) { return iswlower(elem) != 0; }
- static BOOL isUpper(char elem) { return isupper(elem) != 0; }
- static BOOL isUpper(llwchar elem) { return iswupper(elem) != 0; }
+ static bool isDigit(char a) { return isdigit((unsigned char)a) != 0; }
+ static bool isDigit(llwchar a) { return iswdigit(a) != 0; }
- static BOOL isLower(char elem) { return islower(elem) != 0; }
- static BOOL isLower(llwchar elem) { return iswlower(elem) != 0; }
+ static bool isPunct(char a) { return ispunct((unsigned char)a) != 0; }
+ static bool isPunct(llwchar a) { return iswpunct(a) != 0; }
+
+ static bool isAlnum(char a) { return isalnum((unsigned char)a) != 0; }
+ static bool isAlnum(llwchar a) { return iswalnum(a) != 0; }
static S32 collate(const char* a, const char* b) { return strcoll(a, b); }
static S32 collate(const llwchar* a, const llwchar* b);
- static BOOL isDigit(char a) { return isdigit(a) != 0; }
- static BOOL isDigit(llwchar a) { return iswdigit(a) != 0; }
+ static void setupDatetimeInfo(bool pacific_daylight_time);
+
+ static void setupWeekDaysNames(const std::string& data);
+ static void setupWeekDaysShortNames(const std::string& data);
+ static void setupMonthNames(const std::string& data);
+ static void setupMonthShortNames(const std::string& data);
+ static void setupDayFormat(const std::string& data);
+
+
+ static long getPacificTimeOffset(void) { return sPacificTimeOffset;}
+ static long getLocalTimeOffset(void) { return sLocalTimeOffset;}
+ // Is the Pacific time zone (aka server time zone)
+ // currently in daylight savings time?
+ static bool getPacificDaylightTime(void) { return sPacificDaylightTime;}
+
+ static std::string getDatetimeCode (std::string key);
};
-//RN: I used a templated base class instead of a pure interface class to minimize code duplication
-// but it might be worthwhile to just go with two implementations (LLString and LLWString) of
-// an interface class, unless we can think of a good reason to have a std::basic_string polymorphic base
+/**
+ * @brief Return a string constructed from in without crashing if the
+ * pointer is NULL.
+ */
+LL_COMMON_API std::string ll_safe_string(const char* in);
+LL_COMMON_API std::string ll_safe_string(const char* in, S32 maxlen);
-//****************************************************************
-// NOTA BENE: do *NOT* dynamically allocate memory inside of LLStringBase as the {*()^#%*)#%W^*)#%*)STL implentation
-// of basic_string doesn't provide a virtual destructor. If we need to allocate resources specific to LLString
-// then we should either customize std::basic_string to linden::basic_string or change LLString to be a wrapper
-// that contains an instance of std::basic_string. Similarly, overriding methods defined in std::basic_string will *not*
-// be called in a polymorphic manner (passing an instance of basic_string to a particular function)
-//****************************************************************
-template <class T>
-class LLStringBase : public std::basic_string<T>
+// Allowing assignments from non-strings into format_map_t is apparently
+// *really* error-prone, so subclass std::string with just basic c'tors.
+class LLFormatMapString
{
public:
- typedef typename std::basic_string<T>::size_type size_type;
-
- // naming convention follows those set for LLUUID
-// static LLStringBase null; // deprecated for std::string compliance
-// static LLStringBase zero_length; // deprecated for std::string compliance
+ LLFormatMapString() {};
+ LLFormatMapString(const char* s) : mString(ll_safe_string(s)) {};
+ LLFormatMapString(const std::string& s) : mString(s) {};
+ operator std::string() const { return mString; }
+ bool operator<(const LLFormatMapString& rhs) const { return mString < rhs.mString; }
+ std::size_t length() const { return mString.length(); }
-
- // standard constructors
- LLStringBase() : std::basic_string<T>() {}
- LLStringBase(const LLStringBase& s): std::basic_string<T>(s) {}
- LLStringBase(const std::basic_string<T>& s) : std::basic_string<T>(s) {}
- LLStringBase(const std::basic_string<T>& s, size_type pos, size_type n = std::basic_string<T>::npos)
- : std::basic_string<T>(s, pos, n) {}
- LLStringBase(size_type count, const T& c) : std::basic_string<T>() { assign(count, c);}
- // custom constructors
- LLStringBase(const T* s);
- LLStringBase(const T* s, size_type n);
- LLStringBase(const T* s, size_type pos, size_type n );
-
-#if LL_LINUX || LL_SOLARIS
- void clear() { assign(null); }
-
- LLStringBase<T>& assign(const T* s);
- LLStringBase<T>& assign(const T* s, size_type n);
- LLStringBase<T>& assign(const LLStringBase& s);
- LLStringBase<T>& assign(size_type n, const T& c);
- LLStringBase<T>& assign(const T* a, const T* b);
- LLStringBase<T>& assign(typename LLStringBase<T>::iterator &it1, typename LLStringBase<T>::iterator &it2);
- LLStringBase<T>& assign(typename LLStringBase<T>::const_iterator &it1, typename LLStringBase<T>::const_iterator &it2);
-
- // workaround for bug in gcc2 STL headers.
- #if ((__GNUC__ <= 2) && (!defined _STLPORT_VERSION))
- const T* c_str () const
- {
- if (length () == 0)
- {
- static const T zero = 0;
- return &zero;
- }
-
- //terminate ();
- { string_char_traits<T>::assign(const_cast<T*>(data())[length()], string_char_traits<T>::eos()); }
-
- return data ();
- }
- #endif
-#endif
+private:
+ std::string mString;
+};
- bool operator==(const T* _Right) const { return _Right ? (std::basic_string<T>::compare(_Right) == 0) : this->empty(); }
+template <class T>
+class LLStringUtilBase
+{
+private:
+ static std::string sLocale;
+
+public:
+ typedef typename std::basic_string<T>::size_type size_type;
public:
/////////////////////////////////////////////////////////////////////////////////////////
// Static Utility functions that operate on std::strings
- static LLStringBase null;
+ static const std::basic_string<T> null;
- typedef std::map<std::string, std::string> format_map_t;
- static S32 format(std::basic_string<T>& s, const format_map_t& fmt_map);
+ typedef std::map<LLFormatMapString, LLFormatMapString> format_map_t;
+ LL_COMMON_API static void getTokens(const std::basic_string<T>& instr, std::vector<std::basic_string<T> >& tokens, const std::basic_string<T>& delims);
+ LL_COMMON_API static void formatNumber(std::basic_string<T>& numStr, std::basic_string<T> decimals);
+ LL_COMMON_API static bool formatDatetime(std::basic_string<T>& replacement, std::basic_string<T> token, std::basic_string<T> param, S32 secFromEpoch);
+ LL_COMMON_API static S32 format(std::basic_string<T>& s, const format_map_t& substitutions);
+ LL_COMMON_API static S32 format(std::basic_string<T>& s, const LLSD& substitutions);
+ LL_COMMON_API static bool simpleReplacement(std::basic_string<T>& replacement, std::basic_string<T> token, const format_map_t& substitutions);
+ LL_COMMON_API static bool simpleReplacement(std::basic_string<T>& replacement, std::basic_string<T> token, const LLSD& substitutions);
+ LL_COMMON_API static void setLocale (std::string inLocale);
+ LL_COMMON_API static std::string getLocale (void);
- static BOOL isValidIndex(const std::basic_string<T>& string, size_type i)
+ static bool isValidIndex(const std::basic_string<T>& string, size_type i)
{
return !string.empty() && (0 <= i) && (i <= string.size());
}
@@ -252,22 +271,41 @@ public:
// True if this is the head of s.
static BOOL isHead( const std::basic_string<T>& string, const T* s );
-
+
+ /**
+ * @brief Returns true if string starts with substr
+ *
+ * If etither string or substr are empty, this method returns false.
+ */
+ static bool startsWith(
+ const std::basic_string<T>& string,
+ const std::basic_string<T>& substr);
+
+ /**
+ * @brief Returns true if string ends in substr
+ *
+ * If etither string or substr are empty, this method returns false.
+ */
+ static bool endsWith(
+ const std::basic_string<T>& string,
+ const std::basic_string<T>& substr);
+
static void addCRLF(std::basic_string<T>& string);
static void removeCRLF(std::basic_string<T>& string);
static void replaceTabsWithSpaces( std::basic_string<T>& string, size_type spaces_per_tab );
static void replaceNonstandardASCII( std::basic_string<T>& string, T replacement );
static void replaceChar( std::basic_string<T>& string, T target, T replacement );
-
+ static void replaceString( std::basic_string<T>& string, std::basic_string<T> target, std::basic_string<T> replacement );
+
static BOOL containsNonprintable(const std::basic_string<T>& string);
static void stripNonprintable(std::basic_string<T>& string);
/**
* @brief Unsafe way to make ascii characters. You should probably
* only call this when interacting with the host operating system.
- * The 1 byte LLString does not work correctly.
- * The 2 and 4 byte LLString probably work, so LLWString::_makeASCII
+ * The 1 byte std::string does not work correctly.
+ * The 2 and 4 byte std::string probably work, so LLWStringUtil::_makeASCII
* should work.
*/
static void _makeASCII(std::basic_string<T>& string);
@@ -289,11 +327,13 @@ public:
// Like strcmp but also handles empty strings. Uses
// current locale.
static S32 compareStrings(const T* lhs, const T* rhs);
+ static S32 compareStrings(const std::basic_string<T>& lhs, const std::basic_string<T>& rhs);
// case insensitive version of above. Uses current locale on
// Win32, and falls back to a non-locale aware comparison on
// Linux.
static S32 compareInsensitive(const T* lhs, const T* rhs);
+ static S32 compareInsensitive(const std::basic_string<T>& lhs, const std::basic_string<T>& rhs);
// Case sensitive comparison with good handling of numbers. Does not use current locale.
// a.k.a. strdictcmp()
@@ -314,27 +354,33 @@ public:
// Copies src into dst at a given offset.
static void copyInto(std::basic_string<T>& dst, const std::basic_string<T>& src, size_type offset);
+ static bool isPartOfWord(T c) { return (c == (T)'_') || LLStringOps::isAlnum(c); }
+
+
#ifdef _DEBUG
- static void testHarness();
+ LL_COMMON_API static void testHarness();
#endif
+private:
+ LL_COMMON_API static size_type getSubstitution(const std::basic_string<T>& instr, size_type& start, std::vector<std::basic_string<T> >& tokens);
};
-template<class T> LLStringBase<T> LLStringBase<T>::null;
+template<class T> const std::basic_string<T> LLStringUtilBase<T>::null;
+template<class T> std::string LLStringUtilBase<T>::sLocale;
-typedef LLStringBase<char> LLString;
-typedef LLStringBase<llwchar> LLWString;
+typedef LLStringUtilBase<char> LLStringUtil;
+typedef LLStringUtilBase<llwchar> LLWStringUtil;
+typedef std::basic_string<llwchar> LLWString;
//@ Use this where we want to disallow input in the form of "foo"
// This is used to catch places where english text is embedded in the code
// instead of in a translatable XUI file.
-class LLStringExplicit : public LLString
+class LLStringExplicit : public std::string
{
public:
- explicit LLStringExplicit(const char* s) : LLString(s) {}
- LLStringExplicit(const LLString& s) : LLString(s) {}
- LLStringExplicit(const std::string& s) : LLString(s) {}
- LLStringExplicit(const std::string& s, size_type pos, size_type n = std::string::npos) : LLString(s, pos, n) {}
+ explicit LLStringExplicit(const char* s) : std::string(s) {}
+ LLStringExplicit(const std::string& s) : std::string(s) {}
+ LLStringExplicit(const std::string& s, size_type pos, size_type n = std::string::npos) : std::string(s, pos, n) {}
};
struct LLDictionaryLess
@@ -342,7 +388,7 @@ struct LLDictionaryLess
public:
bool operator()(const std::string& a, const std::string& b)
{
- return (LLString::precedesDict(a, b) ? true : false);
+ return (LLStringUtil::precedesDict(a, b) ? true : false);
}
};
@@ -357,7 +403,7 @@ public:
* This function works on bytes rather than glyphs, so this will
* incorrectly truncate non-single byte strings.
* Use utf8str_truncate() for utf8 strings
- * @return a copy of in string minus the trailing count characters.
+ * @return a copy of in string minus the trailing count bytes.
*/
inline std::string chop_tail_copy(
const std::string& in,
@@ -367,16 +413,10 @@ inline std::string chop_tail_copy(
}
/**
- * @brief Return a string constructed from in without crashing if the
- * pointer is NULL.
- */
-std::string ll_safe_string(const char* in);
-
-/**
* @brief This translates a nybble stored as a hex value from 0-f back
* to a nybble in the low order bits of the return byte.
*/
-U8 hex_as_nybble(char hex);
+LL_COMMON_API U8 hex_as_nybble(char hex);
/**
* @brief read the contents of a file into a string.
@@ -387,64 +427,62 @@ U8 hex_as_nybble(char hex);
* @param filename The full name of the file to read.
* @return Returns true on success. If false, str is unmodified.
*/
-bool _read_file_into_string(std::string& str, const char* filename);
+LL_COMMON_API bool _read_file_into_string(std::string& str, const std::string& filename);
+LL_COMMON_API bool iswindividual(llwchar elem);
/**
* Unicode support
*/
// Make the incoming string a utf8 string. Replaces any unknown glyph
-// with the UNKOWN_CHARACTER. Once any unknown glph is found, the rest
+// with the UNKNOWN_CHARACTER. Once any unknown glyph is found, the rest
// of the data may not be recovered.
-std::string rawstr_to_utf8(const std::string& raw);
+LL_COMMON_API std::string rawstr_to_utf8(const std::string& raw);
//
// We should never use UTF16 except when communicating with Win32!
//
typedef std::basic_string<U16> llutf16string;
-LLWString utf16str_to_wstring(const llutf16string &utf16str, S32 len);
-LLWString utf16str_to_wstring(const llutf16string &utf16str);
+LL_COMMON_API LLWString utf16str_to_wstring(const llutf16string &utf16str, S32 len);
+LL_COMMON_API LLWString utf16str_to_wstring(const llutf16string &utf16str);
-llutf16string wstring_to_utf16str(const LLWString &utf32str, S32 len);
-llutf16string wstring_to_utf16str(const LLWString &utf32str);
+LL_COMMON_API llutf16string wstring_to_utf16str(const LLWString &utf32str, S32 len);
+LL_COMMON_API llutf16string wstring_to_utf16str(const LLWString &utf32str);
-llutf16string utf8str_to_utf16str ( const LLString& utf8str, S32 len);
-llutf16string utf8str_to_utf16str ( const LLString& utf8str );
+LL_COMMON_API llutf16string utf8str_to_utf16str ( const std::string& utf8str, S32 len);
+LL_COMMON_API llutf16string utf8str_to_utf16str ( const std::string& utf8str );
-LLWString utf8str_to_wstring(const std::string &utf8str, S32 len);
-LLWString utf8str_to_wstring(const std::string &utf8str);
+LL_COMMON_API LLWString utf8str_to_wstring(const std::string &utf8str, S32 len);
+LL_COMMON_API LLWString utf8str_to_wstring(const std::string &utf8str);
// Same function, better name. JC
inline LLWString utf8string_to_wstring(const std::string& utf8_string) { return utf8str_to_wstring(utf8_string); }
-// Special hack for llfilepicker.cpp:
-S32 utf16chars_to_utf8chars(const U16* inchars, char* outchars, S32* nchars8 = 0);
-S32 utf16chars_to_wchar(const U16* inchars, llwchar* outchar);
-S32 wchar_to_utf8chars(llwchar inchar, char* outchars);
-
//
-std::string wstring_to_utf8str(const LLWString &utf32str, S32 len);
-std::string wstring_to_utf8str(const LLWString &utf32str);
+LL_COMMON_API S32 wchar_to_utf8chars(llwchar inchar, char* outchars);
+
+LL_COMMON_API std::string wstring_to_utf8str(const LLWString &utf32str, S32 len);
+LL_COMMON_API std::string wstring_to_utf8str(const LLWString &utf32str);
-std::string utf16str_to_utf8str(const llutf16string &utf16str, S32 len);
-std::string utf16str_to_utf8str(const llutf16string &utf16str);
+LL_COMMON_API std::string utf16str_to_utf8str(const llutf16string &utf16str, S32 len);
+LL_COMMON_API std::string utf16str_to_utf8str(const llutf16string &utf16str);
// Length of this UTF32 string in bytes when transformed to UTF8
-S32 wstring_utf8_length(const LLWString& wstr);
+LL_COMMON_API S32 wstring_utf8_length(const LLWString& wstr);
// Length in bytes of this wide char in a UTF8 string
-S32 wchar_utf8_length(const llwchar wc);
+LL_COMMON_API S32 wchar_utf8_length(const llwchar wc);
-std::string utf8str_tolower(const std::string& utf8str);
+LL_COMMON_API std::string utf8str_tolower(const std::string& utf8str);
// Length in llwchar (UTF-32) of the first len units (16 bits) of the given UTF-16 string.
-S32 utf16str_wstring_length(const llutf16string &utf16str, S32 len);
+LL_COMMON_API S32 utf16str_wstring_length(const llutf16string &utf16str, S32 len);
// Length in utf16string (UTF-16) of wlen wchars beginning at woffset.
-S32 wstring_utf16_length(const LLWString & wstr, S32 woffset, S32 wlen);
+LL_COMMON_API S32 wstring_utf16_length(const LLWString & wstr, S32 woffset, S32 wlen);
// Length in wstring (i.e., llwchar count) of a part of a wstring specified by utf16 length (i.e., utf16 units.)
-S32 wstring_wstring_length_from_utf16_length(const LLWString & wstr, S32 woffset, S32 utf16_length, BOOL *unaligned = NULL);
+LL_COMMON_API S32 wstring_wstring_length_from_utf16_length(const LLWString & wstr, S32 woffset, S32 utf16_length, BOOL *unaligned = NULL);
/**
* @brief Properly truncate a utf8 string to a maximum byte count.
@@ -456,11 +494,11 @@ S32 wstring_wstring_length_from_utf16_length(const LLWString & wstr, S32 woffset
* @param max_len The maximum number of bytes in the return value.
* @return Returns a valid utf8 string with byte count <= max_len.
*/
-std::string utf8str_truncate(const std::string& utf8str, const S32 max_len);
+LL_COMMON_API std::string utf8str_truncate(const std::string& utf8str, const S32 max_len);
-std::string utf8str_trim(const std::string& utf8str);
+LL_COMMON_API std::string utf8str_trim(const std::string& utf8str);
-S32 utf8str_compare_insensitive(
+LL_COMMON_API S32 utf8str_compare_insensitive(
const std::string& lhs,
const std::string& rhs);
@@ -471,28 +509,19 @@ S32 utf8str_compare_insensitive(
* @param target_char The wchar to be replaced
* @param replace_char The wchar which is written on replace
*/
-std::string utf8str_substChar(
+LL_COMMON_API std::string utf8str_substChar(
const std::string& utf8str,
const llwchar target_char,
const llwchar replace_char);
-std::string utf8str_makeASCII(const std::string& utf8str);
+LL_COMMON_API std::string utf8str_makeASCII(const std::string& utf8str);
// Hack - used for evil notecards.
-std::string mbcsstring_makeASCII(const std::string& str);
+LL_COMMON_API std::string mbcsstring_makeASCII(const std::string& str);
-std::string utf8str_removeCRLF(const std::string& utf8str);
+LL_COMMON_API std::string utf8str_removeCRLF(const std::string& utf8str);
-template <class T>
-std::ostream& operator<<(std::ostream &s, const LLStringBase<T> &str)
-{
- s << ((std::basic_string<T>)str);
- return s;
-}
-
-std::ostream& operator<<(std::ostream &s, const LLWString &wstr);
-
#if LL_WINDOWS
/* @name Windows string helpers
*/
@@ -515,20 +544,40 @@ std::ostream& operator<<(std::ostream &s, const LLWString &wstr);
* formatted string.
*
*/
-int safe_snprintf(char* str, size_t size, const char* format, ...);
+
+// Deal with the differeneces on Windows
+namespace snprintf_hack
+{
+ LL_COMMON_API int snprintf(char *str, size_t size, const char *format, ...);
+}
+
+using snprintf_hack::snprintf;
/**
* @brief Convert a wide string to std::string
*
* This replaces the unsafe W2A macro from ATL.
*/
-std::string ll_convert_wide_to_string(const wchar_t* in);
+LL_COMMON_API std::string ll_convert_wide_to_string(const wchar_t* in, unsigned int code_page);
+
+/**
+ * Converts a string to wide string.
+ *
+ * It will allocate memory for result string with "new []". Don't forget to release it with "delete []".
+ */
+LL_COMMON_API wchar_t* ll_convert_string_to_wide(const std::string& in, unsigned int code_page);
+
+/**
+ * Converts incoming string into urf8 string
+ *
+ */
+LL_COMMON_API std::string ll_convert_string_to_utf8_string(const std::string& in);
//@}
#endif // LL_WINDOWS
/**
- * Many of the 'strip' and 'replace' methods of LLStringBase need
+ * Many of the 'strip' and 'replace' methods of LLStringUtilBase need
* specialization to work with the signed char type.
* Sadly, it is not possible (AFAIK) to specialize a single method of
* a template class.
@@ -539,81 +588,62 @@ namespace LLStringFn
/**
* @brief Replace all non-printable characters with replacement in
* string.
+ * NOTE - this will zap non-ascii
*
* @param [in,out] string the to modify. out value is the string
* with zero non-printable characters.
* @param The replacement character. use LL_UNKNOWN_CHAR if unsure.
*/
- void replace_nonprintable(
+ LL_COMMON_API void replace_nonprintable_in_ascii(
std::basic_string<char>& string,
char replacement);
- /**
- * @brief Replace all non-printable characters with replacement in
- * a wide string.
- *
- * @param [in,out] string the to modify. out value is the string
- * with zero non-printable characters.
- * @param The replacement character. use LL_UNKNOWN_CHAR if unsure.
- */
- void replace_nonprintable(
- std::basic_string<llwchar>& string,
- llwchar replacement);
/**
* @brief Replace all non-printable characters and pipe characters
* with replacement in a string.
+ * NOTE - this will zap non-ascii
*
* @param [in,out] the string to modify. out value is the string
* with zero non-printable characters and zero pipe characters.
* @param The replacement character. use LL_UNKNOWN_CHAR if unsure.
*/
- void replace_nonprintable_and_pipe(std::basic_string<char>& str,
+ LL_COMMON_API void replace_nonprintable_and_pipe_in_ascii(std::basic_string<char>& str,
char replacement);
+
/**
- * @brief Replace all non-printable characters and pipe characters
- * with replacement in a wide string.
+ * @brief Remove all characters that are not allowed in XML 1.0.
+ * Returns a copy of the string with those characters removed.
+ * Works with US ASCII and UTF-8 encoded strings. JC
+ */
+ LL_COMMON_API std::string strip_invalid_xml(const std::string& input);
+
+
+ /**
+ * @brief Replace all control characters (0 <= c < 0x20) with replacement in
+ * string. This is safe for utf-8
*
- * @param [in,out] the string to modify. out value is the string
- * with zero non-printable characters and zero pipe characters.
- * @param The replacement wide character. use LL_UNKNOWN_CHAR if unsure.
+ * @param [in,out] string the to modify. out value is the string
+ * with zero non-printable characters.
+ * @param The replacement character. use LL_UNKNOWN_CHAR if unsure.
*/
- void replace_nonprintable_and_pipe(std::basic_string<llwchar>& str,
- llwchar replacement);
+ LL_COMMON_API void replace_ascii_controlchars(
+ std::basic_string<char>& string,
+ char replacement);
}
////////////////////////////////////////////////////////////
+// NOTE: LLStringUtil::format, getTokens, and support functions moved to llstring.cpp.
+// There is no LLWStringUtil::format implementation currently.
+// Calling thse for anything other than LLStringUtil will produce link errors.
+
+////////////////////////////////////////////////////////////
-// static
-template<class T>
-S32 LLStringBase<T>::format(std::basic_string<T>& s, const format_map_t& fmt_map)
-{
- typedef typename std::basic_string<T>::size_type string_size_type_t;
- S32 res = 0;
- for (format_map_t::const_iterator iter = fmt_map.begin(); iter != fmt_map.end(); ++iter)
- {
- U32 fmtlen = iter->first.size();
- string_size_type_t n = 0;
- while (1)
- {
- n = s.find(iter->first, n);
- if (n == std::basic_string<T>::npos)
- {
- break;
- }
- s.erase(n, fmtlen);
- s.insert(n, iter->second);
- n += fmtlen;
- ++res;
- }
- }
- return res;
-}
// static
template<class T>
-S32 LLStringBase<T>::compareStrings(const T* lhs, const T* rhs)
+S32 LLStringUtilBase<T>::compareStrings(const T* lhs, const T* rhs)
{
S32 result;
if( lhs == rhs )
@@ -637,9 +667,16 @@ S32 LLStringBase<T>::compareStrings(const T* lhs, const T* rhs)
return result;
}
+//static
+template<class T>
+S32 LLStringUtilBase<T>::compareStrings(const std::basic_string<T>& lhs, const std::basic_string<T>& rhs)
+{
+ return LLStringOps::collate(lhs.c_str(), rhs.c_str());
+}
+
// static
template<class T>
-S32 LLStringBase<T>::compareInsensitive(const T* lhs, const T* rhs )
+S32 LLStringUtilBase<T>::compareInsensitive(const T* lhs, const T* rhs )
{
S32 result;
if( lhs == rhs )
@@ -658,22 +695,32 @@ S32 LLStringBase<T>::compareInsensitive(const T* lhs, const T* rhs )
}
else
{
- LLStringBase<T> lhs_string(lhs);
- LLStringBase<T> rhs_string(rhs);
- LLStringBase<T>::toUpper(lhs_string);
- LLStringBase<T>::toUpper(rhs_string);
+ std::basic_string<T> lhs_string(lhs);
+ std::basic_string<T> rhs_string(rhs);
+ LLStringUtilBase<T>::toUpper(lhs_string);
+ LLStringUtilBase<T>::toUpper(rhs_string);
result = LLStringOps::collate(lhs_string.c_str(), rhs_string.c_str());
}
return result;
}
+//static
+template<class T>
+S32 LLStringUtilBase<T>::compareInsensitive(const std::basic_string<T>& lhs, const std::basic_string<T>& rhs)
+{
+ std::basic_string<T> lhs_string(lhs);
+ std::basic_string<T> rhs_string(rhs);
+ LLStringUtilBase<T>::toUpper(lhs_string);
+ LLStringUtilBase<T>::toUpper(rhs_string);
+ return LLStringOps::collate(lhs_string.c_str(), rhs_string.c_str());
+}
// Case sensitive comparison with good handling of numbers. Does not use current locale.
// a.k.a. strdictcmp()
//static
template<class T>
-S32 LLStringBase<T>::compareDict(const std::basic_string<T>& astr, const std::basic_string<T>& bstr)
+S32 LLStringUtilBase<T>::compareDict(const std::basic_string<T>& astr, const std::basic_string<T>& bstr)
{
const T* a = astr.c_str();
const T* b = bstr.c_str();
@@ -712,8 +759,9 @@ S32 LLStringBase<T>::compareDict(const std::basic_string<T>& astr, const std::ba
return ca-cb;
}
+// static
template<class T>
-S32 LLStringBase<T>::compareDictInsensitive(const std::basic_string<T>& astr, const std::basic_string<T>& bstr)
+S32 LLStringUtilBase<T>::compareDictInsensitive(const std::basic_string<T>& astr, const std::basic_string<T>& bstr)
{
const T* a = astr.c_str();
const T* b = bstr.c_str();
@@ -748,11 +796,11 @@ S32 LLStringBase<T>::compareDictInsensitive(const std::basic_string<T>& astr, co
// Puts compareDict() in a form appropriate for LL container classes to use for sorting.
// static
template<class T>
-BOOL LLStringBase<T>::precedesDict( const std::basic_string<T>& a, const std::basic_string<T>& b )
+BOOL LLStringUtilBase<T>::precedesDict( const std::basic_string<T>& a, const std::basic_string<T>& b )
{
if( a.size() && b.size() )
{
- return (LLStringBase<T>::compareDict(a.c_str(), b.c_str()) < 0);
+ return (LLStringUtilBase<T>::compareDict(a.c_str(), b.c_str()) < 0);
}
else
{
@@ -760,108 +808,9 @@ BOOL LLStringBase<T>::precedesDict( const std::basic_string<T>& a, const std::ba
}
}
-// Constructors
-template<class T>
-LLStringBase<T>::LLStringBase(const T* s ) : std::basic_string<T>()
-{
- if (s) assign(s);
-}
-
-template<class T>
-LLStringBase<T>::LLStringBase(const T* s, size_type n ) : std::basic_string<T>()
-{
- if (s) assign(s, n);
-}
-
-// Init from a substring
-template<class T>
-LLStringBase<T>::LLStringBase(const T* s, size_type pos, size_type n ) : std::basic_string<T>()
-{
- if( s )
- {
- assign(s + pos, n);
- }
- else
- {
- assign(LLStringBase<T>::null);
- }
-}
-
-#if LL_LINUX || LL_SOLARIS
-template<class T>
-LLStringBase<T>& LLStringBase<T>::assign(const T* s)
-{
- if (s)
- {
- std::basic_string<T>::assign(s);
- }
- else
- {
- assign(LLStringBase<T>::null);
- }
- return *this;
-}
-
-template<class T>
-LLStringBase<T>& LLStringBase<T>::assign(const T* s, size_type n)
-{
- if (s)
- {
- std::basic_string<T>::assign(s, n);
- }
- else
- {
- assign(LLStringBase<T>::null);
- }
- return *this;
-}
-
-template<class T>
-LLStringBase<T>& LLStringBase<T>::assign(const LLStringBase<T>& s)
-{
- std::basic_string<T>::assign(s);
- return *this;
-}
-
-template<class T>
-LLStringBase<T>& LLStringBase<T>::assign(size_type n, const T& c)
-{
- std::basic_string<T>::assign(n, c);
- return *this;
-}
-
-template<class T>
-LLStringBase<T>& LLStringBase<T>::assign(const T* a, const T* b)
-{
- if (a > b)
- assign(LLStringBase<T>::null);
- else
- assign(a, (size_type) (b-a));
- return *this;
-}
-
-template<class T>
-LLStringBase<T>& LLStringBase<T>::assign(typename LLStringBase<T>::iterator &it1, typename LLStringBase<T>::iterator &it2)
-{
- assign(LLStringBase<T>::null);
- while(it1 != it2)
- *this += *it1++;
- return *this;
-}
-
-template<class T>
-LLStringBase<T>& LLStringBase<T>::assign(typename LLStringBase<T>::const_iterator &it1, typename LLStringBase<T>::const_iterator &it2)
-{
- assign(LLStringBase<T>::null);
- while(it1 != it2)
- *this += *it1++;
- return *this;
-}
-#endif
-
//static
template<class T>
-void LLStringBase<T>::toUpper(std::basic_string<T>& string)
+void LLStringUtilBase<T>::toUpper(std::basic_string<T>& string)
{
if( !string.empty() )
{
@@ -875,7 +824,7 @@ void LLStringBase<T>::toUpper(std::basic_string<T>& string)
//static
template<class T>
-void LLStringBase<T>::toLower(std::basic_string<T>& string)
+void LLStringUtilBase<T>::toLower(std::basic_string<T>& string)
{
if( !string.empty() )
{
@@ -889,7 +838,7 @@ void LLStringBase<T>::toLower(std::basic_string<T>& string)
//static
template<class T>
-void LLStringBase<T>::trimHead(std::basic_string<T>& string)
+void LLStringUtilBase<T>::trimHead(std::basic_string<T>& string)
{
if( !string.empty() )
{
@@ -904,7 +853,7 @@ void LLStringBase<T>::trimHead(std::basic_string<T>& string)
//static
template<class T>
-void LLStringBase<T>::trimTail(std::basic_string<T>& string)
+void LLStringUtilBase<T>::trimTail(std::basic_string<T>& string)
{
if( string.size() )
{
@@ -923,7 +872,7 @@ void LLStringBase<T>::trimTail(std::basic_string<T>& string)
// Replace line feeds with carriage return-line feed pairs.
//static
template<class T>
-void LLStringBase<T>::addCRLF(std::basic_string<T>& string)
+void LLStringUtilBase<T>::addCRLF(std::basic_string<T>& string)
{
const T LF = 10;
const T CR = 13;
@@ -958,13 +907,14 @@ void LLStringBase<T>::addCRLF(std::basic_string<T>& string)
}
string.assign(t, size);
+ delete[] t;
}
}
// Remove all carriage returns
//static
template<class T>
-void LLStringBase<T>::removeCRLF(std::basic_string<T>& string)
+void LLStringUtilBase<T>::removeCRLF(std::basic_string<T>& string)
{
const T CR = 13;
@@ -985,20 +935,31 @@ void LLStringBase<T>::removeCRLF(std::basic_string<T>& string)
//static
template<class T>
-void LLStringBase<T>::replaceChar( std::basic_string<T>& string, T target, T replacement )
+void LLStringUtilBase<T>::replaceChar( std::basic_string<T>& string, T target, T replacement )
{
size_type found_pos = 0;
- for (found_pos = string.find(target, found_pos);
- found_pos != std::basic_string<T>::npos;
- found_pos = string.find(target, found_pos))
+ while( (found_pos = string.find(target, found_pos)) != std::basic_string<T>::npos )
{
string[found_pos] = replacement;
+ found_pos++; // avoid infinite defeat if target == replacement
}
}
//static
template<class T>
-void LLStringBase<T>::replaceNonstandardASCII( std::basic_string<T>& string, T replacement )
+void LLStringUtilBase<T>::replaceString( std::basic_string<T>& string, std::basic_string<T> target, std::basic_string<T> replacement )
+{
+ size_type found_pos = 0;
+ while( (found_pos = string.find(target, found_pos)) != std::basic_string<T>::npos )
+ {
+ string.replace( found_pos, target.length(), replacement );
+ found_pos += replacement.length(); // avoid infinite defeat if replacement contains target
+ }
+}
+
+//static
+template<class T>
+void LLStringUtilBase<T>::replaceNonstandardASCII( std::basic_string<T>& string, T replacement )
{
const char LF = 10;
const S8 MIN = 32;
@@ -1018,12 +979,12 @@ void LLStringBase<T>::replaceNonstandardASCII( std::basic_string<T>& string, T r
//static
template<class T>
-void LLStringBase<T>::replaceTabsWithSpaces( std::basic_string<T>& str, size_type spaces_per_tab )
+void LLStringUtilBase<T>::replaceTabsWithSpaces( std::basic_string<T>& str, size_type spaces_per_tab )
{
const T TAB = '\t';
const T SPACE = ' ';
- LLStringBase<T> out_str;
+ std::basic_string<T> out_str;
// Replace tabs with spaces
for (size_type i = 0; i < str.length(); i++)
{
@@ -1042,7 +1003,7 @@ void LLStringBase<T>::replaceTabsWithSpaces( std::basic_string<T>& str, size_typ
//static
template<class T>
-BOOL LLStringBase<T>::containsNonprintable(const std::basic_string<T>& string)
+BOOL LLStringUtilBase<T>::containsNonprintable(const std::basic_string<T>& string)
{
const char MIN = 32;
BOOL rv = FALSE;
@@ -1059,7 +1020,7 @@ BOOL LLStringBase<T>::containsNonprintable(const std::basic_string<T>& string)
//static
template<class T>
-void LLStringBase<T>::stripNonprintable(std::basic_string<T>& string)
+void LLStringUtilBase<T>::stripNonprintable(std::basic_string<T>& string)
{
const char MIN = 32;
size_type j = 0;
@@ -1067,14 +1028,15 @@ void LLStringBase<T>::stripNonprintable(std::basic_string<T>& string)
{
return;
}
- char* c_string = new char[string.size() + 1];
+ size_t src_size = string.size();
+ char* c_string = new char[src_size + 1];
if(c_string == NULL)
{
return;
}
- strcpy(c_string, string.c_str()); /*Flawfinder: ignore*/
+ copy(c_string, string.c_str(), src_size+1);
char* write_head = &c_string[0];
- for (size_type i = 0; i < string.size(); i++)
+ for (size_type i = 0; i < src_size; i++)
{
char* read_head = &string[i];
write_head = &c_string[j];
@@ -1090,7 +1052,7 @@ void LLStringBase<T>::stripNonprintable(std::basic_string<T>& string)
}
template<class T>
-void LLStringBase<T>::_makeASCII(std::basic_string<T>& string)
+void LLStringUtilBase<T>::_makeASCII(std::basic_string<T>& string)
{
// Replace non-ASCII chars with LL_UNKNOWN_CHAR
for (size_type i = 0; i < string.length(); i++)
@@ -1104,7 +1066,7 @@ void LLStringBase<T>::_makeASCII(std::basic_string<T>& string)
// static
template<class T>
-void LLStringBase<T>::copy( T* dst, const T* src, size_type dst_size )
+void LLStringUtilBase<T>::copy( T* dst, const T* src, size_type dst_size )
{
if( dst_size > 0 )
{
@@ -1120,7 +1082,7 @@ void LLStringBase<T>::copy( T* dst, const T* src, size_type dst_size )
// static
template<class T>
-void LLStringBase<T>::copyInto(std::basic_string<T>& dst, const std::basic_string<T>& src, size_type offset)
+void LLStringUtilBase<T>::copyInto(std::basic_string<T>& dst, const std::basic_string<T>& src, size_type offset)
{
if ( offset == dst.length() )
{
@@ -1141,7 +1103,7 @@ void LLStringBase<T>::copyInto(std::basic_string<T>& dst, const std::basic_strin
// True if this is the head of s.
//static
template<class T>
-BOOL LLStringBase<T>::isHead( const std::basic_string<T>& string, const T* s )
+BOOL LLStringUtilBase<T>::isHead( const std::basic_string<T>& string, const T* s )
{
if( string.empty() )
{
@@ -1154,15 +1116,39 @@ BOOL LLStringBase<T>::isHead( const std::basic_string<T>& string, const T* s )
}
}
+// static
+template<class T>
+bool LLStringUtilBase<T>::startsWith(
+ const std::basic_string<T>& string,
+ const std::basic_string<T>& substr)
+{
+ if(string.empty() || (substr.empty())) return false;
+ if(0 == string.find(substr)) return true;
+ return false;
+}
+
+// static
+template<class T>
+bool LLStringUtilBase<T>::endsWith(
+ const std::basic_string<T>& string,
+ const std::basic_string<T>& substr)
+{
+ if(string.empty() || (substr.empty())) return false;
+ std::string::size_type idx = string.rfind(substr);
+ if(std::string::npos == idx) return false;
+ return (idx == (string.size() - substr.size()));
+}
+
+
template<class T>
-BOOL LLStringBase<T>::convertToBOOL(const std::basic_string<T>& string, BOOL& value)
+BOOL LLStringUtilBase<T>::convertToBOOL(const std::basic_string<T>& string, BOOL& value)
{
if( string.empty() )
{
return FALSE;
}
- LLStringBase<T> temp( string );
+ std::basic_string<T> temp( string );
trim(temp);
if(
(temp == "1") ||
@@ -1192,7 +1178,7 @@ BOOL LLStringBase<T>::convertToBOOL(const std::basic_string<T>& string, BOOL& va
}
template<class T>
-BOOL LLStringBase<T>::convertToU8(const std::basic_string<T>& string, U8& value)
+BOOL LLStringUtilBase<T>::convertToU8(const std::basic_string<T>& string, U8& value)
{
S32 value32 = 0;
BOOL success = convertToS32(string, value32);
@@ -1205,7 +1191,7 @@ BOOL LLStringBase<T>::convertToU8(const std::basic_string<T>& string, U8& value)
}
template<class T>
-BOOL LLStringBase<T>::convertToS8(const std::basic_string<T>& string, S8& value)
+BOOL LLStringUtilBase<T>::convertToS8(const std::basic_string<T>& string, S8& value)
{
S32 value32 = 0;
BOOL success = convertToS32(string, value32);
@@ -1218,7 +1204,7 @@ BOOL LLStringBase<T>::convertToS8(const std::basic_string<T>& string, S8& value)
}
template<class T>
-BOOL LLStringBase<T>::convertToS16(const std::basic_string<T>& string, S16& value)
+BOOL LLStringUtilBase<T>::convertToS16(const std::basic_string<T>& string, S16& value)
{
S32 value32 = 0;
BOOL success = convertToS32(string, value32);
@@ -1231,7 +1217,7 @@ BOOL LLStringBase<T>::convertToS16(const std::basic_string<T>& string, S16& valu
}
template<class T>
-BOOL LLStringBase<T>::convertToU16(const std::basic_string<T>& string, U16& value)
+BOOL LLStringUtilBase<T>::convertToU16(const std::basic_string<T>& string, U16& value)
{
S32 value32 = 0;
BOOL success = convertToS32(string, value32);
@@ -1244,26 +1230,19 @@ BOOL LLStringBase<T>::convertToU16(const std::basic_string<T>& string, U16& valu
}
template<class T>
-BOOL LLStringBase<T>::convertToU32(const std::basic_string<T>& string, U32& value)
+BOOL LLStringUtilBase<T>::convertToU32(const std::basic_string<T>& string, U32& value)
{
if( string.empty() )
{
return FALSE;
}
- LLStringBase<T> temp( string );
+ std::basic_string<T> temp( string );
trim(temp);
U32 v;
std::basic_istringstream<T> i_stream((std::basic_string<T>)temp);
if(i_stream >> v)
{
- //TODO: figure out overflow reporting here
- //if( ULONG_MAX == v )
- //{
- // // Underflow or overflow
- // return FALSE;
- //}
-
value = v;
return TRUE;
}
@@ -1271,14 +1250,14 @@ BOOL LLStringBase<T>::convertToU32(const std::basic_string<T>& string, U32& valu
}
template<class T>
-BOOL LLStringBase<T>::convertToS32(const std::basic_string<T>& string, S32& value)
+BOOL LLStringUtilBase<T>::convertToS32(const std::basic_string<T>& string, S32& value)
{
if( string.empty() )
{
return FALSE;
}
- LLStringBase<T> temp( string );
+ std::basic_string<T> temp( string );
trim(temp);
S32 v;
std::basic_istringstream<T> i_stream((std::basic_string<T>)temp);
@@ -1298,7 +1277,7 @@ BOOL LLStringBase<T>::convertToS32(const std::basic_string<T>& string, S32& valu
}
template<class T>
-BOOL LLStringBase<T>::convertToF32(const std::basic_string<T>& string, F32& value)
+BOOL LLStringUtilBase<T>::convertToF32(const std::basic_string<T>& string, F32& value)
{
F64 value64 = 0.0;
BOOL success = convertToF64(string, value64);
@@ -1311,14 +1290,14 @@ BOOL LLStringBase<T>::convertToF32(const std::basic_string<T>& string, F32& valu
}
template<class T>
-BOOL LLStringBase<T>::convertToF64(const std::basic_string<T>& string, F64& value)
+BOOL LLStringUtilBase<T>::convertToF64(const std::basic_string<T>& string, F64& value)
{
if( string.empty() )
{
return FALSE;
}
- LLStringBase<T> temp( string );
+ std::basic_string<T> temp( string );
trim(temp);
F64 v;
std::basic_istringstream<T> i_stream((std::basic_string<T>)temp);
@@ -1338,7 +1317,7 @@ BOOL LLStringBase<T>::convertToF64(const std::basic_string<T>& string, F64& valu
}
template<class T>
-void LLStringBase<T>::truncate(std::basic_string<T>& string, size_type count)
+void LLStringUtilBase<T>::truncate(std::basic_string<T>& string, size_type count)
{
size_type cur_size = string.size();
string.resize(count < cur_size ? count : cur_size);
diff --git a/indra/llcommon/llstringtable.cpp b/indra/llcommon/llstringtable.cpp
index f6da802dc7..7ad3805351 100644
--- a/indra/llcommon/llstringtable.cpp
+++ b/indra/llcommon/llstringtable.cpp
@@ -3,30 +3,25 @@
* @brief The LLStringTable class provides a _fast_ method for finding
* unique copies of strings.
*
- * $LicenseInfo:firstyear=2001&license=viewergpl$
- *
- * Copyright (c) 2001-2007, Linden Research, Inc.
- *
+ * $LicenseInfo:firstyear=2001&license=viewerlgpl$
* Second Life Viewer Source Code
- * The source code in this file ("Source Code") is provided by Linden Lab
- * to you under the terms of the GNU General Public License, version 2.0
- * ("GPL"), unless you have obtained a separate licensing agreement
- * ("Other License"), formally executed by you and Linden Lab. Terms of
- * the GPL can be found in doc/GPL-license.txt in this distribution, or
- * online at http://secondlife.com/developers/opensource/gplv2
+ * 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.
*
- * There are special exceptions to the terms and conditions of the GPL as
- * it is applied to this Source Code. View the full text of the exception
- * in the file doc/FLOSS-exception.txt in this software distribution, or
- * online at http://secondlife.com/developers/opensource/flossexception
+ * 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.
*
- * By copying, modifying or distributing this software, you acknowledge
- * that you have read and understood your obligations described above,
- * and agree to abide by those obligations.
+ * 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
*
- * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
- * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
- * COMPLETENESS OR PERFORMANCE.
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
* $/LicenseInfo$
*/
@@ -37,6 +32,23 @@
LLStringTable gStringTable(32768);
+LLStringTableEntry::LLStringTableEntry(const char *str)
+: mString(NULL), mCount(1)
+{
+ // Copy string
+ U32 length = (U32)strlen(str) + 1; /*Flawfinder: ignore*/
+ length = llmin(length, MAX_STRINGS_LENGTH);
+ mString = new char[length];
+ strncpy(mString, str, length); /*Flawfinder: ignore*/
+ mString[length - 1] = 0;
+}
+
+LLStringTableEntry::~LLStringTableEntry()
+{
+ delete [] mString;
+ mCount = 0;
+}
+
LLStringTable::LLStringTable(int tablesize)
: mUniqueEntries(0)
{
diff --git a/indra/llcommon/llstringtable.h b/indra/llcommon/llstringtable.h
index f7206fe4f8..59d7372ed4 100644
--- a/indra/llcommon/llstringtable.h
+++ b/indra/llcommon/llstringtable.h
@@ -3,30 +3,25 @@
* @brief The LLStringTable class provides a _fast_ method for finding
* unique copies of strings.
*
- * $LicenseInfo:firstyear=2001&license=viewergpl$
- *
- * Copyright (c) 2001-2007, Linden Research, Inc.
- *
+ * $LicenseInfo:firstyear=2001&license=viewerlgpl$
* Second Life Viewer Source Code
- * The source code in this file ("Source Code") is provided by Linden Lab
- * to you under the terms of the GNU General Public License, version 2.0
- * ("GPL"), unless you have obtained a separate licensing agreement
- * ("Other License"), formally executed by you and Linden Lab. Terms of
- * the GPL can be found in doc/GPL-license.txt in this distribution, or
- * online at http://secondlife.com/developers/opensource/gplv2
+ * 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.
*
- * There are special exceptions to the terms and conditions of the GPL as
- * it is applied to this Source Code. View the full text of the exception
- * in the file doc/FLOSS-exception.txt in this software distribution, or
- * online at http://secondlife.com/developers/opensource/flossexception
+ * 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.
*
- * By copying, modifying or distributing this software, you acknowledge
- * that you have read and understood your obligations described above,
- * and agree to abide by those obligations.
+ * 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
*
- * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
- * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
- * COMPLETENESS OR PERFORMANCE.
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
* $/LicenseInfo$
*/
@@ -47,32 +42,22 @@
//# define STRING_TABLE_HASH_MAP 1
#endif
-#if LL_WINDOWS
-#include <hash_map>
-#else
-#include <ext/hash_map>
+#if STRING_TABLE_HASH_MAP
+# if LL_WINDOWS
+# include <hash_map>
+# else
+# include <ext/hash_map>
+# endif
#endif
const U32 MAX_STRINGS_LENGTH = 256;
-class LLStringTableEntry
+class LL_COMMON_API LLStringTableEntry
{
public:
- LLStringTableEntry(const char *str)
- : mString(NULL), mCount(1)
- {
- // Copy string
- U32 length = (U32)strlen(str) + 1; /*Flawfinder: ignore*/
- length = llmin(length, MAX_STRINGS_LENGTH);
- mString = new char[length];
- strncpy(mString, str, length); /*Flawfinder: ignore*/
- mString[length - 1] = 0;
- }
- ~LLStringTableEntry()
- {
- delete [] mString;
- mCount = 0;
- }
+ LLStringTableEntry(const char *str);
+ ~LLStringTableEntry();
+
void incCount() { mCount++; }
BOOL decCount() { return --mCount; }
@@ -80,7 +65,7 @@ public:
S32 mCount;
};
-class LLStringTable
+class LL_COMMON_API LLStringTable
{
public:
LLStringTable(int tablesize);
@@ -114,7 +99,7 @@ public:
#endif
};
-extern LLStringTable gStringTable;
+extern LL_COMMON_API LLStringTable gStringTable;
//============================================================================
@@ -124,7 +109,7 @@ extern LLStringTable gStringTable;
typedef const std::string* LLStdStringHandle;
-class LLStdStringTable
+class LL_COMMON_API LLStdStringTable
{
public:
LLStdStringTable(S32 tablesize = 0)
diff --git a/indra/llcommon/llsys.cpp b/indra/llcommon/llsys.cpp
index 98393dacd1..00c94404d4 100644
--- a/indra/llcommon/llsys.cpp
+++ b/indra/llcommon/llsys.cpp
@@ -2,30 +2,25 @@
* @file llsys.cpp
* @brief Impelementation of the basic system query functions.
*
- * $LicenseInfo:firstyear=2002&license=viewergpl$
- *
- * Copyright (c) 2002-2007, Linden Research, Inc.
- *
+ * $LicenseInfo:firstyear=2002&license=viewerlgpl$
* Second Life Viewer Source Code
- * The source code in this file ("Source Code") is provided by Linden Lab
- * to you under the terms of the GNU General Public License, version 2.0
- * ("GPL"), unless you have obtained a separate licensing agreement
- * ("Other License"), formally executed by you and Linden Lab. Terms of
- * the GPL can be found in doc/GPL-license.txt in this distribution, or
- * online at http://secondlife.com/developers/opensource/gplv2
+ * 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.
*
- * There are special exceptions to the terms and conditions of the GPL as
- * it is applied to this Source Code. View the full text of the exception
- * in the file doc/FLOSS-exception.txt in this software distribution, or
- * online at http://secondlife.com/developers/opensource/flossexception
+ * 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.
*
- * By copying, modifying or distributing this software, you acknowledge
- * that you have read and understood your obligations described above,
- * and agree to abide by those obligations.
+ * 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
*
- * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
- * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
- * COMPLETENESS OR PERFORMANCE.
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
* $/LicenseInfo$
*/
@@ -57,13 +52,92 @@
# include <unistd.h>
# include <sys/sysinfo.h>
const char MEMINFO_FILE[] = "/proc/meminfo";
-const char CPUINFO_FILE[] = "/proc/cpuinfo";
+#elif LL_SOLARIS
+# include <stdio.h>
+# include <unistd.h>
+# include <sys/utsname.h>
+# define _STRUCTURED_PROC 1
+# include <sys/procfs.h>
+# include <sys/types.h>
+# include <sys/stat.h>
+# include <fcntl.h>
+# include <errno.h>
+extern int errno;
#endif
static const S32 CPUINFO_BUFFER_SIZE = 16383;
LLCPUInfo gSysCPU;
+#if LL_WINDOWS
+#ifndef DLLVERSIONINFO
+typedef struct _DllVersionInfo
+{
+ DWORD cbSize;
+ DWORD dwMajorVersion;
+ DWORD dwMinorVersion;
+ DWORD dwBuildNumber;
+ DWORD dwPlatformID;
+}DLLVERSIONINFO;
+#endif
+
+#ifndef DLLGETVERSIONPROC
+typedef int (FAR WINAPI *DLLGETVERSIONPROC) (DLLVERSIONINFO *);
+#endif
+
+bool get_shell32_dll_version(DWORD& major, DWORD& minor, DWORD& build_number)
+{
+ bool result = false;
+ const U32 BUFF_SIZE = 32767;
+ WCHAR tempBuf[BUFF_SIZE];
+ if(GetSystemDirectory((LPWSTR)&tempBuf, BUFF_SIZE))
+ {
+
+ std::basic_string<WCHAR> shell32_path(tempBuf);
+
+ // Shell32.dll contains the DLLGetVersion function.
+ // according to msdn its not part of the API
+ // so you have to go in and get it.
+ // http://msdn.microsoft.com/en-us/library/bb776404(VS.85).aspx
+ shell32_path += TEXT("\\shell32.dll");
+
+ HMODULE hDllInst = LoadLibrary(shell32_path.c_str()); //load the DLL
+ if(hDllInst)
+ { // Could successfully load the DLL
+ DLLGETVERSIONPROC pDllGetVersion;
+ /*
+ You must get this function explicitly because earlier versions of the DLL
+ don't implement this function. That makes the lack of implementation of the
+ function a version marker in itself.
+ */
+ pDllGetVersion = (DLLGETVERSIONPROC) GetProcAddress(hDllInst,
+ "DllGetVersion");
+
+ if(pDllGetVersion)
+ {
+ // DLL supports version retrieval function
+ DLLVERSIONINFO dvi;
+
+ ZeroMemory(&dvi, sizeof(dvi));
+ dvi.cbSize = sizeof(dvi);
+ HRESULT hr = (*pDllGetVersion)(&dvi);
+
+ if(SUCCEEDED(hr))
+ { // Finally, the version is at our hands
+ major = dvi.dwMajorVersion;
+ minor = dvi.dwMinorVersion;
+ build_number = dvi.dwBuildNumber;
+ result = true;
+ }
+ }
+
+ FreeLibrary(hDllInst); // Release DLL
+ }
+ }
+ return result;
+}
+#endif // LL_WINDOWS
+
LLOSInfo::LLOSInfo() :
mMajorVer(0), mMinorVer(0), mBuild(0)
{
@@ -86,6 +160,11 @@ LLOSInfo::LLOSInfo() :
mMinorVer = osvi.dwMinorVersion;
mBuild = osvi.dwBuildNumber;
+ DWORD shell32_major, shell32_minor, shell32_build;
+ bool got_shell32_version = get_shell32_dll_version(shell32_major,
+ shell32_minor,
+ shell32_build);
+
switch(osvi.dwPlatformId)
{
case VER_PLATFORM_WIN32_NT:
@@ -110,14 +189,50 @@ LLOSInfo::LLOSInfo() :
else
mOSStringSimple = "Microsoft Windows Server 2003 ";
}
- else if(osvi.dwMajorVersion == 6 && osvi.dwMinorVersion == 0)
+ else if(osvi.dwMajorVersion == 6 && osvi.dwMinorVersion <= 1)
{
- if(osvi.wProductType == VER_NT_WORKSTATION)
+ if(osvi.dwMinorVersion == 0)
+ {
mOSStringSimple = "Microsoft Windows Vista ";
- else mOSStringSimple = "Microsoft Windows Vista Server ";
+ }
+ else if(osvi.dwMinorVersion == 1)
+ {
+ mOSStringSimple = "Microsoft Windows 7 ";
+ }
+
+ if(osvi.wProductType != VER_NT_WORKSTATION)
+ {
+ mOSStringSimple += "Server ";
+ }
+
+ ///get native system info if available..
+ typedef void (WINAPI *PGNSI)(LPSYSTEM_INFO); ///function pointer for loading GetNativeSystemInfo
+ SYSTEM_INFO si; //System Info object file contains architecture info
+ PGNSI pGNSI; //pointer object
+ ZeroMemory(&si, sizeof(SYSTEM_INFO)); //zero out the memory in information
+ pGNSI = (PGNSI) GetProcAddress(GetModuleHandle(TEXT("kernel32.dll")), "GetNativeSystemInfo"); //load kernel32 get function
+ if(NULL != pGNSI) //check if it has failed
+ pGNSI(&si); //success
+ else
+ GetSystemInfo(&si); //if it fails get regular system info
+ //(Warning: If GetSystemInfo it may result in incorrect information in a WOW64 machine, if the kernel fails to load)
+
+ //msdn microsoft finds 32 bit and 64 bit flavors this way..
+ //http://msdn.microsoft.com/en-us/library/ms724429(VS.85).aspx (example code that contains quite a few more flavors
+ //of windows than this code does (in case it is needed for the future)
+ if ( si.wProcessorArchitecture==PROCESSOR_ARCHITECTURE_AMD64 ) //check for 64 bit
+ {
+ mOSStringSimple += "64-bit ";
+ }
+ else if (si.wProcessorArchitecture==PROCESSOR_ARCHITECTURE_INTEL )
+ {
+ mOSStringSimple += "32-bit ";
+ }
}
else // Use the registry on early versions of Windows NT.
{
+ mOSStringSimple = "Microsoft Windows (unrecognized) ";
+
HKEY hKey;
WCHAR szProductType[80];
DWORD dwBufLen;
@@ -143,28 +258,23 @@ LLOSInfo::LLOSInfo() :
std::string csdversion = utf16str_to_utf8str(osvi.szCSDVersion);
// Display version, service pack (if any), and build number.
- char tmp[MAX_STRING]; /* Flawfinder: ignore */
+ std::string tmpstr;
if(osvi.dwMajorVersion <= 4)
{
- snprintf( /* Flawfinder: ignore */
- tmp,
- sizeof(tmp),
- "version %d.%d %s (Build %d)",
- osvi.dwMajorVersion,
- osvi.dwMinorVersion,
- csdversion.c_str(),
- (osvi.dwBuildNumber & 0xffff));
+ tmpstr = llformat("version %d.%d %s (Build %d)",
+ osvi.dwMajorVersion,
+ osvi.dwMinorVersion,
+ csdversion.c_str(),
+ (osvi.dwBuildNumber & 0xffff));
}
else
{
- snprintf( /* Flawfinder: ignore */
- tmp,
- sizeof(tmp),
- "%s (Build %d)",
- csdversion.c_str(),
- (osvi.dwBuildNumber & 0xffff));
+ tmpstr = llformat("%s (Build %d)",
+ csdversion.c_str(),
+ (osvi.dwBuildNumber & 0xffff));
}
- mOSString = mOSStringSimple + tmp;
+
+ mOSString = mOSStringSimple + tmpstr;
}
break;
@@ -193,6 +303,21 @@ LLOSInfo::LLOSInfo() :
mOSString = mOSStringSimple;
break;
}
+
+ std::string compatibility_mode;
+ if(got_shell32_version)
+ {
+ if(osvi.dwMajorVersion != shell32_major
+ || osvi.dwMinorVersion != shell32_minor)
+ {
+ compatibility_mode = llformat(" compatibility mode. real ver: %d.%d (Build %d)",
+ shell32_major,
+ shell32_minor,
+ shell32_build);
+ }
+ }
+ mOSString += compatibility_mode;
+
#else
struct utsname un;
if(uname(&un) != -1)
@@ -220,8 +345,8 @@ LLOSInfo::LLOSInfo() :
else if (ostype == "Linux")
{
// Only care about major and minor Linux versions, truncate at second '.'
- S32 idx1 = mOSStringSimple.find_first_of(".", 0);
- S32 idx2 = (idx1 != std::string::npos) ? mOSStringSimple.find_first_of(".", idx1+1) : std::string::npos;
+ std::string::size_type idx1 = mOSStringSimple.find_first_of(".", 0);
+ std::string::size_type idx2 = (idx1 != std::string::npos) ? mOSStringSimple.find_first_of(".", idx1+1) : std::string::npos;
std::string simple = mOSStringSimple.substr(0, idx2);
if (simple.length() > 0)
mOSStringSimple = simple;
@@ -293,20 +418,23 @@ U32 LLOSInfo::getProcessVirtualSizeKB()
#if LL_WINDOWS
#endif
#if LL_LINUX
- FILE* status_filep = LLFile::fopen("/proc/self/status", "rb");
- S32 numRead = 0;
- char buff[STATUS_SIZE]; /* Flawfinder: ignore */
+ LLFILE* status_filep = LLFile::fopen("/proc/self/status", "rb");
+ if (status_filep)
+ {
+ S32 numRead = 0;
+ char buff[STATUS_SIZE]; /* Flawfinder: ignore */
- size_t nbytes = fread(buff, 1, STATUS_SIZE-1, status_filep);
- buff[nbytes] = '\0';
+ size_t nbytes = fread(buff, 1, STATUS_SIZE-1, status_filep);
+ buff[nbytes] = '\0';
- // All these guys return numbers in KB
- char *memp = strstr(buff, "VmSize:");
- if (memp)
- {
- numRead += sscanf(memp, "%*s %u", &virtual_size);
+ // All these guys return numbers in KB
+ char *memp = strstr(buff, "VmSize:");
+ if (memp)
+ {
+ numRead += sscanf(memp, "%*s %u", &virtual_size);
+ }
+ fclose(status_filep);
}
- fclose(status_filep);
#elif LL_SOLARIS
char proc_ps[LL_MAX_PATH];
sprintf(proc_ps, "/proc/%d/psinfo", (int)getpid());
@@ -336,7 +464,7 @@ U32 LLOSInfo::getProcessResidentSizeKB()
#if LL_WINDOWS
#endif
#if LL_LINUX
- FILE* status_filep = LLFile::fopen("/proc/self/status", "rb");
+ LLFILE* status_filep = LLFile::fopen("/proc/self/status", "rb");
if (status_filep != NULL)
{
S32 numRead = 0;
@@ -378,71 +506,21 @@ U32 LLOSInfo::getProcessResidentSizeKB()
LLCPUInfo::LLCPUInfo()
{
std::ostringstream out;
- CProcessor proc;
- const ProcessorInfo* info = proc.GetCPUInfo();
+ LLProcessorInfo proc;
// proc.WriteInfoTextFile("procInfo.txt");
- mHasSSE = info->_Ext.SSE_StreamingSIMD_Extensions;
- mHasSSE2 = info->_Ext.SSE2_StreamingSIMD2_Extensions;
- mHasAltivec = info->_Ext.Altivec_Extensions;
- mCPUMhz = (S32)(proc.GetCPUFrequency(50)/1000000.0);
- mFamily.assign( info->strFamily );
+ mHasSSE = proc.hasSSE();
+ mHasSSE2 = proc.hasSSE2();
+ mHasAltivec = proc.hasAltivec();
+ mCPUMHz = (F64)proc.getCPUFrequency();
+ mFamily = proc.getCPUFamilyName();
mCPUString = "Unknown";
-#if LL_WINDOWS || LL_DARWIN || LL_SOLARIS
- out << proc.strCPUName;
- if (200 < mCPUMhz && mCPUMhz < 10000) // *NOTE: cpu speed is often way wrong, do a sanity check
+ out << proc.getCPUBrandName();
+ if (200 < mCPUMHz && mCPUMHz < 10000) // *NOTE: cpu speed is often way wrong, do a sanity check
{
- out << " (" << mCPUMhz << " MHz)";
+ out << " (" << mCPUMHz << " MHz)";
}
mCPUString = out.str();
-
-#elif LL_LINUX
- std::map< LLString, LLString > cpuinfo;
- FILE* cpuinfo_fp = LLFile::fopen(CPUINFO_FILE, "rb");
- if(cpuinfo_fp)
- {
- char line[MAX_STRING];
- memset(line, 0, MAX_STRING);
- while(fgets(line, MAX_STRING, cpuinfo_fp))
- {
- // /proc/cpuinfo on Linux looks like:
- // name\t*: value\n
- char* tabspot = strchr( line, '\t' );
- if (tabspot == NULL)
- continue;
- char* colspot = strchr( tabspot, ':' );
- if (colspot == NULL)
- continue;
- char* spacespot = strchr( colspot, ' ' );
- if (spacespot == NULL)
- continue;
- char* nlspot = strchr( line, '\n' );
- if (nlspot == NULL)
- nlspot = line + strlen( line ); // Fallback to terminating NUL
- std::string linename( line, tabspot );
- LLString llinename(linename);
- LLString::toLower(llinename);
- std::string lineval( spacespot + 1, nlspot );
- cpuinfo[ llinename ] = lineval;
- }
- fclose(cpuinfo_fp);
- }
-# if LL_X86
- LLString flags = " " + cpuinfo["flags"] + " ";
- LLString::toLower(flags);
- mHasSSE = ( flags.find( " sse " ) != std::string::npos );
- mHasSSE2 = ( flags.find( " sse2 " ) != std::string::npos );
-
- F64 mhz;
- if (LLString::convertToF64(cpuinfo["cpu mhz"], mhz)
- && 200.0 < mhz && mhz < 10000.0)
- {
- mCPUMhz = (S32)llrint(mhz);
- }
- if (!cpuinfo["model name"].empty())
- mCPUString = cpuinfo["model name"];
-# endif // LL_X86
-#endif // LL_LINUX
}
bool LLCPUInfo::hasAltivec() const
@@ -460,9 +538,9 @@ bool LLCPUInfo::hasSSE2() const
return mHasSSE2;
}
-S32 LLCPUInfo::getMhz() const
+F64 LLCPUInfo::getMHz() const
{
- return mCPUMhz;
+ return mCPUMHz;
}
std::string LLCPUInfo::getCPUString() const
@@ -472,44 +550,15 @@ std::string LLCPUInfo::getCPUString() const
void LLCPUInfo::stream(std::ostream& s) const
{
-#if LL_WINDOWS || LL_DARWIN || LL_SOLARIS
// gather machine information.
- char proc_buf[CPUINFO_BUFFER_SIZE]; /* Flawfinder: ignore */
- CProcessor proc;
- if(proc.CPUInfoToText(proc_buf, CPUINFO_BUFFER_SIZE))
- {
- s << proc_buf;
- }
- else
- {
- s << "Unable to collect processor information" << std::endl;
- }
-#else
- // *NOTE: This works on linux. What will it do on other systems?
- FILE* cpuinfo = LLFile::fopen(CPUINFO_FILE, "rb");
- if(cpuinfo)
- {
- char line[MAX_STRING];
- memset(line, 0, MAX_STRING);
- while(fgets(line, MAX_STRING, cpuinfo))
- {
- line[strlen(line)-1] = ' ';
- s << line;
- }
- fclose(cpuinfo);
- s << std::endl;
- }
- else
- {
- s << "Unable to collect processor information" << std::endl;
- }
-#endif
+ s << LLProcessorInfo().getCPUFeatureDescription();
+
// These are interesting as they reflect our internal view of the
// CPU's attributes regardless of platform
s << "->mHasSSE: " << (U32)mHasSSE << std::endl;
s << "->mHasSSE2: " << (U32)mHasSSE2 << std::endl;
s << "->mHasAltivec: " << (U32)mHasAltivec << std::endl;
- s << "->mCPUMhz: " << mCPUMhz << std::endl;
+ s << "->mCPUMHz: " << mCPUMHz << std::endl;
s << "->mCPUString: " << mCPUString << std::endl;
}
@@ -621,7 +670,7 @@ void LLMemoryInfo::stream(std::ostream& s) const
s << "Total Physical KB: " << phys << std::endl;
#else
// *NOTE: This works on linux. What will it do on other systems?
- FILE* meminfo = LLFile::fopen(MEMINFO_FILE,"rb");
+ LLFILE* meminfo = LLFile::fopen(MEMINFO_FILE,"rb");
if(meminfo)
{
char line[MAX_STRING]; /* Flawfinder: ignore */
@@ -658,18 +707,17 @@ std::ostream& operator<<(std::ostream& s, const LLMemoryInfo& info)
return s;
}
-BOOL gunzip_file(const char *srcfile, const char *dstfile)
+BOOL gunzip_file(const std::string& srcfile, const std::string& dstfile)
{
- char tmpfile[LL_MAX_PATH]; /* Flawfinder: ignore */
+ std::string tmpfile;
const S32 UNCOMPRESS_BUFFER_SIZE = 32768;
BOOL retval = FALSE;
gzFile src = NULL;
U8 buffer[UNCOMPRESS_BUFFER_SIZE];
- FILE *dst = NULL;
+ LLFILE *dst = NULL;
S32 bytes = 0;
- (void *) strcpy(tmpfile, dstfile); /* Flawfinder: ignore */
- (void *) strncat(tmpfile, ".t", sizeof(tmpfile) - strlen(tmpfile) -1); /* Flawfinder: ignore */
- src = gzopen(srcfile, "rb");
+ tmpfile = dstfile + ".t";
+ src = gzopen(srcfile.c_str(), "rb");
if (! src) goto err;
dst = LLFile::fopen(tmpfile, "wb"); /* Flawfinder: ignore */
if (! dst) goto err;
@@ -693,18 +741,17 @@ err:
return retval;
}
-BOOL gzip_file(const char *srcfile, const char *dstfile)
+BOOL gzip_file(const std::string& srcfile, const std::string& dstfile)
{
const S32 COMPRESS_BUFFER_SIZE = 32768;
- char tmpfile[LL_MAX_PATH]; /* Flawfinder: ignore */
+ std::string tmpfile;
BOOL retval = FALSE;
U8 buffer[COMPRESS_BUFFER_SIZE];
gzFile dst = NULL;
- FILE *src = NULL;
+ LLFILE *src = NULL;
S32 bytes = 0;
- (void *) strcpy(tmpfile, dstfile); /* Flawfinder: ignore */
- (void *) strncat(tmpfile, ".t", sizeof(tmpfile) - strlen(tmpfile) -1); /* Flawfinder: ignore */
- dst = gzopen(tmpfile, "wb"); /* Flawfinder: ignore */
+ tmpfile = dstfile + ".t";
+ dst = gzopen(tmpfile.c_str(), "wb"); /* Flawfinder: ignore */
if (! dst) goto err;
src = LLFile::fopen(srcfile, "rb"); /* Flawfinder: ignore */
if (! src) goto err;
diff --git a/indra/llcommon/llsys.h b/indra/llcommon/llsys.h
index 332d62c186..39af74e5c8 100644
--- a/indra/llcommon/llsys.h
+++ b/indra/llcommon/llsys.h
@@ -2,30 +2,25 @@
* @file llsys.h
* @brief System information debugging classes.
*
- * $LicenseInfo:firstyear=2001&license=viewergpl$
- *
- * Copyright (c) 2001-2007, Linden Research, Inc.
- *
+ * $LicenseInfo:firstyear=2001&license=viewerlgpl$
* Second Life Viewer Source Code
- * The source code in this file ("Source Code") is provided by Linden Lab
- * to you under the terms of the GNU General Public License, version 2.0
- * ("GPL"), unless you have obtained a separate licensing agreement
- * ("Other License"), formally executed by you and Linden Lab. Terms of
- * the GPL can be found in doc/GPL-license.txt in this distribution, or
- * online at http://secondlife.com/developers/opensource/gplv2
+ * 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.
*
- * There are special exceptions to the terms and conditions of the GPL as
- * it is applied to this Source Code. View the full text of the exception
- * in the file doc/FLOSS-exception.txt in this software distribution, or
- * online at http://secondlife.com/developers/opensource/flossexception
+ * 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.
*
- * By copying, modifying or distributing this software, you acknowledge
- * that you have read and understood your obligations described above,
- * and agree to abide by those obligations.
+ * 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
*
- * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
- * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
- * COMPLETENESS OR PERFORMANCE.
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
* $/LicenseInfo$
*/
@@ -44,7 +39,7 @@
#include <iosfwd>
#include <string>
-class LLOSInfo
+class LL_COMMON_API LLOSInfo
{
public:
LLOSInfo();
@@ -69,7 +64,7 @@ private:
};
-class LLCPUInfo
+class LL_COMMON_API LLCPUInfo
{
public:
LLCPUInfo();
@@ -80,7 +75,7 @@ public:
bool hasAltivec() const;
bool hasSSE() const;
bool hasSSE2() const;
- S32 getMhz() const;
+ F64 getMHz() const;
// Family is "AMD Duron" or "Intel Pentium Pro"
const std::string& getFamily() const { return mFamily; }
@@ -89,7 +84,7 @@ private:
bool mHasSSE;
bool mHasSSE2;
bool mHasAltivec;
- S32 mCPUMhz;
+ F64 mCPUMHz;
std::string mFamily;
std::string mCPUString;
};
@@ -98,7 +93,7 @@ private:
//
// CLASS LLMemoryInfo
-class LLMemoryInfo
+class LL_COMMON_API LLMemoryInfo
/*! @brief Class to query the memory subsystem
@@ -122,15 +117,15 @@ public:
};
-std::ostream& operator<<(std::ostream& s, const LLOSInfo& info);
-std::ostream& operator<<(std::ostream& s, const LLCPUInfo& info);
-std::ostream& operator<<(std::ostream& s, const LLMemoryInfo& info);
+LL_COMMON_API std::ostream& operator<<(std::ostream& s, const LLOSInfo& info);
+LL_COMMON_API std::ostream& operator<<(std::ostream& s, const LLCPUInfo& info);
+LL_COMMON_API std::ostream& operator<<(std::ostream& s, const LLMemoryInfo& info);
// gunzip srcfile into dstfile. Returns FALSE on error.
-BOOL gunzip_file(const char *srcfile, const char *dstfile);
+BOOL LL_COMMON_API gunzip_file(const std::string& srcfile, const std::string& dstfile);
// gzip srcfile into dstfile. Returns FALSE on error.
-BOOL gzip_file(const char *srcfile, const char *dstfile);
+BOOL LL_COMMON_API gzip_file(const std::string& srcfile, const std::string& dstfile);
-extern LLCPUInfo gSysCPU;
+extern LL_COMMON_API LLCPUInfo gSysCPU;
#endif // LL_LLSYS_H
diff --git a/indra/llcommon/llthread.cpp b/indra/llcommon/llthread.cpp
index 02ed0dcfc6..d7b7c3699c 100644
--- a/indra/llcommon/llthread.cpp
+++ b/indra/llcommon/llthread.cpp
@@ -1,37 +1,32 @@
/**
* @file llthread.cpp
*
- * $LicenseInfo:firstyear=2004&license=viewergpl$
- *
- * Copyright (c) 2004-2007, Linden Research, Inc.
- *
+ * $LicenseInfo:firstyear=2004&license=viewerlgpl$
* Second Life Viewer Source Code
- * The source code in this file ("Source Code") is provided by Linden Lab
- * to you under the terms of the GNU General Public License, version 2.0
- * ("GPL"), unless you have obtained a separate licensing agreement
- * ("Other License"), formally executed by you and Linden Lab. Terms of
- * the GPL can be found in doc/GPL-license.txt in this distribution, or
- * online at http://secondlife.com/developers/opensource/gplv2
+ * Copyright (C) 2010, Linden Research, Inc.
*
- * There are special exceptions to the terms and conditions of the GPL as
- * it is applied to this Source Code. View the full text of the exception
- * in the file doc/FLOSS-exception.txt in this software distribution, or
- * online at http://secondlife.com/developers/opensource/flossexception
+ * 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.
*
- * By copying, modifying or distributing this software, you acknowledge
- * that you have read and understood your obligations described above,
- * and agree to abide by those obligations.
+ * 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.
*
- * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
- * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
- * COMPLETENESS OR PERFORMANCE.
+ * 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$
*/
#include "linden_common.h"
#include "llapr.h"
-#include "apr-1/apr_portable.h"
+#include "apr_portable.h"
#include "llthread.h"
@@ -101,12 +96,20 @@ LLThread::LLThread(const std::string& name, apr_pool_t *poolp) :
apr_pool_create(&mAPRPoolp, NULL); // Create a subpool for this thread
}
mRunCondition = new LLCondition(mAPRPoolp);
+
+ mLocalAPRFilePoolp = NULL ;
}
LLThread::~LLThread()
{
shutdown();
+
+ if(mLocalAPRFilePoolp)
+ {
+ delete mLocalAPRFilePoolp ;
+ mLocalAPRFilePoolp = NULL ;
+ }
}
void LLThread::shutdown()
@@ -266,12 +269,12 @@ void LLThread::wakeLocked()
LLMutex::LLMutex(apr_pool_t *poolp) :
mAPRMutexp(NULL)
{
- if (poolp)
- {
- mIsLocalPool = FALSE;
- mAPRPoolp = poolp;
- }
- else
+ //if (poolp)
+ //{
+ // mIsLocalPool = FALSE;
+ // mAPRPoolp = poolp;
+ //}
+ //else
{
mIsLocalPool = TRUE;
apr_pool_create(&mAPRPoolp, NULL); // Create a subpool for this thread
@@ -282,8 +285,8 @@ LLMutex::LLMutex(apr_pool_t *poolp) :
LLMutex::~LLMutex()
{
-#if _DEBUG
- llassert(!isLocked()); // better not be locked!
+#if MUTEX_DEBUG
+ llassert_always(!isLocked()); // better not be locked!
#endif
apr_thread_mutex_destroy(mAPRMutexp);
mAPRMutexp = NULL;
@@ -297,10 +300,24 @@ LLMutex::~LLMutex()
void LLMutex::lock()
{
apr_thread_mutex_lock(mAPRMutexp);
+#if MUTEX_DEBUG
+ // Have to have the lock before we can access the debug info
+ U32 id = LLThread::currentID();
+ if (mIsLocked[id] != FALSE)
+ llerrs << "Already locked in Thread: " << id << llendl;
+ mIsLocked[id] = TRUE;
+#endif
}
void LLMutex::unlock()
{
+#if MUTEX_DEBUG
+ // Access the debug info while we have the lock
+ U32 id = LLThread::currentID();
+ if (mIsLocked[id] != TRUE)
+ llerrs << "Not locked in Thread: " << id << llendl;
+ mIsLocked[id] = FALSE;
+#endif
apr_thread_mutex_unlock(mAPRMutexp);
}
@@ -359,7 +376,7 @@ void LLCondition::broadcast()
LLMutex* LLThreadSafeRefCount::sMutex = 0;
//static
-void LLThreadSafeRefCount::initClass()
+void LLThreadSafeRefCount::initThreadSafeRefCount()
{
if (!sMutex)
{
@@ -368,7 +385,7 @@ void LLThreadSafeRefCount::initClass()
}
//static
-void LLThreadSafeRefCount::cleanupClass()
+void LLThreadSafeRefCount::cleanupThreadSafeRefCount()
{
delete sMutex;
sMutex = NULL;
diff --git a/indra/llcommon/llthread.h b/indra/llcommon/llthread.h
index a07c64b8fc..f1c6cd75af 100644
--- a/indra/llcommon/llthread.h
+++ b/indra/llcommon/llthread.h
@@ -2,47 +2,40 @@
* @file llthread.h
* @brief Base classes for thread, mutex and condition handling.
*
- * $LicenseInfo:firstyear=2004&license=viewergpl$
- *
- * Copyright (c) 2004-2007, Linden Research, Inc.
- *
+ * $LicenseInfo:firstyear=2004&license=viewerlgpl$
* Second Life Viewer Source Code
- * The source code in this file ("Source Code") is provided by Linden Lab
- * to you under the terms of the GNU General Public License, version 2.0
- * ("GPL"), unless you have obtained a separate licensing agreement
- * ("Other License"), formally executed by you and Linden Lab. Terms of
- * the GPL can be found in doc/GPL-license.txt in this distribution, or
- * online at http://secondlife.com/developers/opensource/gplv2
+ * 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.
*
- * There are special exceptions to the terms and conditions of the GPL as
- * it is applied to this Source Code. View the full text of the exception
- * in the file doc/FLOSS-exception.txt in this software distribution, or
- * online at http://secondlife.com/developers/opensource/flossexception
+ * 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.
*
- * By copying, modifying or distributing this software, you acknowledge
- * that you have read and understood your obligations described above,
- * and agree to abide by those obligations.
+ * 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
*
- * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
- * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
- * COMPLETENESS OR PERFORMANCE.
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
* $/LicenseInfo$
*/
#ifndef LL_LLTHREAD_H
#define LL_LLTHREAD_H
-#include "llapr.h"
#include "llapp.h"
-#include "llmemory.h"
-
-#include "apr-1/apr_thread_cond.h"
+#include "llapr.h"
+#include "apr_thread_cond.h"
class LLThread;
class LLMutex;
class LLCondition;
-class LLThread
+class LL_COMMON_API LLThread
{
public:
typedef enum e_thread_status
@@ -82,7 +75,8 @@ public:
void start(void);
apr_pool_t *getAPRPool() { return mAPRPoolp; }
-
+ LLVolatileAPRPool* getLocalAPRFilePool() { return mLocalAPRFilePoolp ; }
+
private:
BOOL mPaused;
@@ -98,6 +92,11 @@ protected:
BOOL mIsLocalPool;
EThreadStatus mStatus;
+ //a local apr_pool for APRFile operations in this thread. If it exists, LLAPRFile::sAPRFilePoolp should not be used.
+ //Note: this pool is used by APRFile ONLY, do NOT use it for any other purposes.
+ // otherwise it will cause severe memory leaking!!! --bao
+ LLVolatileAPRPool *mLocalAPRFilePoolp ;
+
void setQuitting();
// virtual function overridden by subclass -- this will be called when the thread runs
@@ -124,11 +123,13 @@ protected:
//============================================================================
-class LLMutex
+#define MUTEX_DEBUG (LL_DEBUG || LL_RELEASE_WITH_DEBUG_INFO)
+
+class LL_COMMON_API LLMutex
{
public:
LLMutex(apr_pool_t *apr_poolp); // NULL pool constructs a new pool for the mutex
- ~LLMutex();
+ virtual ~LLMutex();
void lock(); // blocks
void unlock();
@@ -138,10 +139,13 @@ protected:
apr_thread_mutex_t *mAPRMutexp;
apr_pool_t *mAPRPoolp;
BOOL mIsLocalPool;
+#if MUTEX_DEBUG
+ std::map<U32, BOOL> mIsLocked;
+#endif
};
// Actually a condition/mutex pair (since each condition needs to be associated with a mutex).
-class LLCondition : public LLMutex
+class LL_COMMON_API LLCondition : public LLMutex
{
public:
LLCondition(apr_pool_t *apr_poolp); // Defaults to global pool, could use the thread pool as well.
@@ -188,11 +192,11 @@ void LLThread::unlockData()
// see llmemory.h for LLPointer<> definition
-class LLThreadSafeRefCount
+class LL_COMMON_API LLThreadSafeRefCount
{
public:
- static void initClass(); // creates sMutex
- static void cleanupClass(); // destroys sMutex
+ static void initThreadSafeRefCount(); // creates sMutex
+ static void cleanupThreadSafeRefCount(); // destroys sMutex
private:
static LLMutex* sMutex;
@@ -240,7 +244,7 @@ private:
// Simple responder for self destructing callbacks
// Pure virtual class
-class LLResponder : public LLThreadSafeRefCount
+class LL_COMMON_API LLResponder : public LLThreadSafeRefCount
{
protected:
virtual ~LLResponder();
diff --git a/indra/llcommon/lltimer.cpp b/indra/llcommon/lltimer.cpp
index 9786d44899..38054b636e 100644
--- a/indra/llcommon/lltimer.cpp
+++ b/indra/llcommon/lltimer.cpp
@@ -2,30 +2,25 @@
* @file lltimer.cpp
* @brief Cross-platform objects for doing timing
*
- * $LicenseInfo:firstyear=2000&license=viewergpl$
- *
- * Copyright (c) 2000-2007, Linden Research, Inc.
- *
+ * $LicenseInfo:firstyear=2000&license=viewerlgpl$
* Second Life Viewer Source Code
- * The source code in this file ("Source Code") is provided by Linden Lab
- * to you under the terms of the GNU General Public License, version 2.0
- * ("GPL"), unless you have obtained a separate licensing agreement
- * ("Other License"), formally executed by you and Linden Lab. Terms of
- * the GPL can be found in doc/GPL-license.txt in this distribution, or
- * online at http://secondlife.com/developers/opensource/gplv2
+ * 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.
*
- * There are special exceptions to the terms and conditions of the GPL as
- * it is applied to this Source Code. View the full text of the exception
- * in the file doc/FLOSS-exception.txt in this software distribution, or
- * online at http://secondlife.com/developers/opensource/flossexception
+ * 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.
*
- * By copying, modifying or distributing this software, you acknowledge
- * that you have read and understood your obligations described above,
- * and agree to abide by those obligations.
+ * 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
*
- * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
- * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
- * COMPLETENESS OR PERFORMANCE.
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
* $/LicenseInfo$
*/
@@ -39,10 +34,8 @@
# define WIN32_LEAN_AND_MEAN
# include <winsock2.h>
# include <windows.h>
-#elif LL_LINUX || LL_SOLARIS
-# include <sys/time.h>
-# include <sched.h>
-#elif LL_DARWIN
+#elif LL_LINUX || LL_SOLARIS || LL_DARWIN
+# include <errno.h>
# include <sys/time.h>
#else
# error "architecture not supported"
@@ -81,42 +74,98 @@ U64 gLastTotalTimeClockCount = 0;
//---------------------------------------------------------------------------
#if LL_WINDOWS
-void ms_sleep(long ms)
+void ms_sleep(U32 ms)
{
- Sleep((U32)ms);
+ Sleep(ms);
}
-void llyield()
+U32 micro_sleep(U64 us, U32 max_yields)
{
- SleepEx(0, TRUE); // Relinquishes time slice to any thread of equal priority, can be woken up by extended IO functions
+ // max_yields is unused; just fiddle with it to avoid warnings.
+ max_yields = 0;
+ ms_sleep(us / 1000);
+ return 0;
}
-#elif LL_LINUX || LL_SOLARIS
-void ms_sleep(long ms)
+#elif LL_LINUX || LL_SOLARIS || LL_DARWIN
+static void _sleep_loop(struct timespec& thiswait)
{
- struct timespec t;
- t.tv_sec = ms / 1000;
- t.tv_nsec = (ms % 1000) * 1000000l;
- nanosleep(&t, NULL);
-}
+ struct timespec nextwait;
+ bool sleep_more = false;
-void llyield()
-{
- sched_yield();
-}
-#elif LL_DARWIN
-void ms_sleep(long ms)
-{
- struct timespec t;
- t.tv_sec = ms / 1000;
- t.tv_nsec = (ms % 1000) * 1000000l;
- nanosleep(&t, NULL);
-}
+ do {
+ int result = nanosleep(&thiswait, &nextwait);
-void llyield()
-{
-// sched_yield();
-}
-#else
+ // check if sleep was interrupted by a signal; unslept
+ // remainder was written back into 't' and we just nanosleep
+ // again.
+ sleep_more = (result == -1 && EINTR == errno);
+
+ if (sleep_more)
+ {
+ if ( nextwait.tv_sec > thiswait.tv_sec ||
+ (nextwait.tv_sec == thiswait.tv_sec &&
+ nextwait.tv_nsec >= thiswait.tv_nsec) )
+ {
+ // if the remaining time isn't actually going
+ // down then we're being shafted by low clock
+ // resolution - manually massage the sleep time
+ // downward.
+ if (nextwait.tv_nsec > 1000000) {
+ // lose 1ms
+ nextwait.tv_nsec -= 1000000;
+ } else {
+ if (nextwait.tv_sec == 0) {
+ // already so close to finished
+ sleep_more = false;
+ } else {
+ // lose up to 1ms
+ nextwait.tv_nsec = 0;
+ }
+ }
+ }
+ thiswait = nextwait;
+ }
+ } while (sleep_more);
+}
+
+U32 micro_sleep(U64 us, U32 max_yields)
+{
+ U64 start = get_clock_count();
+ // This is kernel dependent. Currently, our kernel generates software clock
+ // interrupts at 250 Hz (every 4,000 microseconds).
+ const U64 KERNEL_SLEEP_INTERVAL_US = 4000;
+
+ S32 num_sleep_intervals = (us - (KERNEL_SLEEP_INTERVAL_US >> 1)) / KERNEL_SLEEP_INTERVAL_US;
+ if (num_sleep_intervals > 0)
+ {
+ U64 sleep_time = (num_sleep_intervals * KERNEL_SLEEP_INTERVAL_US) - (KERNEL_SLEEP_INTERVAL_US >> 1);
+ struct timespec thiswait;
+ thiswait.tv_sec = sleep_time / 1000000;
+ thiswait.tv_nsec = (sleep_time % 1000000) * 1000l;
+ _sleep_loop(thiswait);
+ }
+
+ U64 current_clock = get_clock_count();
+ U32 yields = 0;
+ while ( (yields < max_yields)
+ && (current_clock - start < us) )
+ {
+ sched_yield();
+ ++yields;
+ current_clock = get_clock_count();
+ }
+ return yields;
+}
+
+void ms_sleep(U32 ms)
+{
+ long mslong = ms; // tv_nsec is a long
+ struct timespec thiswait;
+ thiswait.tv_sec = ms / 1000;
+ thiswait.tv_nsec = (mslong % 1000) * 1000000l;
+ _sleep_loop(thiswait);
+}
+#else
# error "architecture not supported"
#endif
@@ -154,7 +203,7 @@ F64 calc_clock_frequency(U32 uiMeasureMSecs)
// Both Linux and Mac use gettimeofday for accurate time
F64 calc_clock_frequency(unsigned int uiMeasureMSecs)
{
- return 1000000.0; // microseconds, so 1 Mhz.
+ return 1000000.0; // microseconds, so 1 MHz.
}
U64 get_clock_count()
@@ -323,7 +372,7 @@ void LLTimer::setTimerExpirySec(F32 expiration)
+ (U64)((F32)(expiration * gClockFrequency));
}
-F32 LLTimer::getRemainingTimeF32()
+F32 LLTimer::getRemainingTimeF32() const
{
U64 cur_ticks = get_clock_count();
if (cur_ticks > mExpirationTicks)
@@ -348,7 +397,7 @@ BOOL LLTimer::checkExpirationAndReset(F32 expiration)
}
-BOOL LLTimer::hasExpired()
+BOOL LLTimer::hasExpired() const
{
return (get_clock_count() >= mExpirationTicks)
? TRUE : FALSE;
@@ -418,10 +467,9 @@ BOOL LLTimer::knownBadTimer()
//
///////////////////////////////////////////////////////////////////////////////
-U32 time_corrected()
+time_t time_corrected()
{
- U32 corrected_time = (U32)time(NULL) + gUTCOffset;
- return corrected_time;
+ return time(NULL) + gUTCOffset;
}
@@ -441,27 +489,25 @@ BOOL is_daylight_savings()
}
-struct tm* utc_to_pacific_time(S32 utc_time, BOOL pacific_daylight_time)
+struct tm* utc_to_pacific_time(time_t utc_time, BOOL pacific_daylight_time)
{
- time_t unix_time = (time_t)utc_time;
-
S32 pacific_offset_hours;
if (pacific_daylight_time)
{
- pacific_offset_hours = -7;
+ pacific_offset_hours = 7;
}
else
{
- pacific_offset_hours = -8;
+ pacific_offset_hours = 8;
}
// We subtract off the PST/PDT offset _before_ getting
// "UTC" time, because this will handle wrapping around
// for 5 AM UTC -> 10 PM PDT of the previous day.
- unix_time += pacific_offset_hours * MIN_PER_HOUR * SEC_PER_MIN;
+ utc_time -= pacific_offset_hours * MIN_PER_HOUR * SEC_PER_MIN;
// Internal buffer to PST/PDT (see above)
- struct tm* internal_time = gmtime(&unix_time);
+ struct tm* internal_time = gmtime(&utc_time);
/*
// Don't do this, this won't correctly tell you if daylight savings is active in CA or not.
@@ -475,7 +521,7 @@ struct tm* utc_to_pacific_time(S32 utc_time, BOOL pacific_daylight_time)
}
-void microsecondsToTimecodeString(U64 current_time, char *tcstring)
+void microsecondsToTimecodeString(U64 current_time, std::string& tcstring)
{
U64 hours;
U64 minutes;
@@ -493,60 +539,13 @@ void microsecondsToTimecodeString(U64 current_time, char *tcstring)
subframes = current_time / (U64)42;
subframes %= 100;
- sprintf(tcstring,"%3.3d:%2.2d:%2.2d:%2.2d.%2.2d",(int)hours,(int)minutes,(int)seconds,(int)frames,(int)subframes); /* Flawfinder: ignore */
+ tcstring = llformat("%3.3d:%2.2d:%2.2d:%2.2d.%2.2d",(int)hours,(int)minutes,(int)seconds,(int)frames,(int)subframes);
}
-void secondsToTimecodeString(F32 current_time, char *tcstring)
+void secondsToTimecodeString(F32 current_time, std::string& tcstring)
{
microsecondsToTimecodeString((U64)((F64)(SEC_TO_MICROSEC*current_time)), tcstring);
}
-//////////////////////////////////////////////////////////////////////////////
-//
-// LLEventTimer Implementation
-//
-//////////////////////////////////////////////////////////////////////////////
-
-std::list<LLEventTimer*> LLEventTimer::sActiveList;
-
-LLEventTimer::LLEventTimer(F32 period)
-: mEventTimer()
-{
- mPeriod = period;
- sActiveList.push_back(this);
-}
-
-LLEventTimer::~LLEventTimer()
-{
- sActiveList.remove(this);
-}
-
-void LLEventTimer::updateClass()
-{
- std::list<LLEventTimer*> completed_timers;
- for (std::list<LLEventTimer*>::iterator iter = sActiveList.begin(); iter != sActiveList.end(); )
- {
- LLEventTimer* timer = *iter++;
- F32 et = timer->mEventTimer.getElapsedTimeF32();
- if (et > timer->mPeriod) {
- timer->mEventTimer.reset();
- if ( timer->tick() )
- {
- completed_timers.push_back( timer );
- }
- }
- }
-
- if ( completed_timers.size() > 0 )
- {
- for (std::list<LLEventTimer*>::iterator completed_iter = completed_timers.begin();
- completed_iter != completed_timers.end();
- completed_iter++ )
- {
- delete *completed_iter;
- }
- }
-}
-
diff --git a/indra/llcommon/lltimer.h b/indra/llcommon/lltimer.h
index 4ffb9c8eec..513de0605d 100644
--- a/indra/llcommon/lltimer.h
+++ b/indra/llcommon/lltimer.h
@@ -2,40 +2,40 @@
* @file lltimer.h
* @brief Cross-platform objects for doing timing
*
- * $LicenseInfo:firstyear=2000&license=viewergpl$
- *
- * Copyright (c) 2000-2007, Linden Research, Inc.
- *
+ * $LicenseInfo:firstyear=2000&license=viewerlgpl$
* Second Life Viewer Source Code
- * The source code in this file ("Source Code") is provided by Linden Lab
- * to you under the terms of the GNU General Public License, version 2.0
- * ("GPL"), unless you have obtained a separate licensing agreement
- * ("Other License"), formally executed by you and Linden Lab. Terms of
- * the GPL can be found in doc/GPL-license.txt in this distribution, or
- * online at http://secondlife.com/developers/opensource/gplv2
+ * 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.
*
- * There are special exceptions to the terms and conditions of the GPL as
- * it is applied to this Source Code. View the full text of the exception
- * in the file doc/FLOSS-exception.txt in this software distribution, or
- * online at http://secondlife.com/developers/opensource/flossexception
+ * 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.
*
- * By copying, modifying or distributing this software, you acknowledge
- * that you have read and understood your obligations described above,
- * and agree to abide by those obligations.
+ * 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
*
- * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
- * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
- * COMPLETENESS OR PERFORMANCE.
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
* $/LicenseInfo$
*/
#ifndef LL_TIMER_H
#define LL_TIMER_H
-#if LL_LINUX || LL_DARWIN
+#if LL_LINUX || LL_DARWIN || LL_SOLARIS
#include <sys/time.h>
#endif
+#include <limits.h>
+#include "stdtypes.h"
+
+#include <string>
+#include <list>
// units conversions
#ifndef USEC_PER_SEC
const U32 USEC_PER_SEC = 1000000;
@@ -47,7 +47,7 @@ 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;
-class LLTimer
+class LL_COMMON_API LLTimer
{
public:
static LLTimer *sTimer; // global timer
@@ -85,11 +85,11 @@ public:
void setLastClockCount(U64 current_count); // Sets the timer so that the next elapsed call will be relative to this time
void setTimerExpirySec(F32 expiration);
BOOL checkExpirationAndReset(F32 expiration);
- BOOL hasExpired();
+ BOOL hasExpired() const;
F32 getElapsedTimeAndResetF32(); // Returns elapsed time in seconds with reset
F64 getElapsedTimeAndResetF64();
- F32 getRemainingTimeF32();
+ F32 getRemainingTimeF32() const;
static BOOL knownBadTimer();
@@ -106,58 +106,63 @@ public:
//
// Various functions for initializing/accessing clock and timing stuff. Don't use these without REALLY knowing how they work.
//
-U64 get_clock_count();
-F64 calc_clock_frequency(U32 msecs);
-void update_clock_frequencies();
-
+LL_COMMON_API U64 get_clock_count();
+LL_COMMON_API F64 calc_clock_frequency(U32 msecs);
+LL_COMMON_API void update_clock_frequencies();
// Sleep for milliseconds
-void ms_sleep(long ms);
-
-// Yield
-//void llyield(); // Yield your timeslice - not implemented yet for Mac, so commented out.
+LL_COMMON_API void ms_sleep(U32 ms);
+LL_COMMON_API U32 micro_sleep(U64 us, U32 max_yields = 0xFFFFFFFF);
// Returns the correct UTC time in seconds, like time(NULL).
// Useful on the viewer, which may have its local clock set wrong.
-U32 time_corrected();
+LL_COMMON_API time_t time_corrected();
+
+static inline time_t time_min()
+{
+ if (sizeof(time_t) == 4)
+ {
+ return (time_t) INT_MIN;
+ } else {
+#ifdef LLONG_MIN
+ return (time_t) LLONG_MIN;
+#else
+ return (time_t) LONG_MIN;
+#endif
+ }
+}
+
+static inline time_t time_max()
+{
+ if (sizeof(time_t) == 4)
+ {
+ return (time_t) INT_MAX;
+ } else {
+#ifdef LLONG_MAX
+ return (time_t) LLONG_MAX;
+#else
+ return (time_t) LONG_MAX;
+#endif
+ }
+}
// Correction factor used by time_corrected() above.
-extern S32 gUTCOffset;
+extern LL_COMMON_API S32 gUTCOffset;
// Is the current computer (in its current time zone)
// observing daylight savings time?
-BOOL is_daylight_savings();
+LL_COMMON_API BOOL is_daylight_savings();
// Converts internal "struct tm" time buffer to Pacific Standard/Daylight Time
// Usage:
// S32 utc_time;
// utc_time = time_corrected();
// struct tm* internal_time = utc_to_pacific_time(utc_time, gDaylight);
-struct tm* utc_to_pacific_time(S32 utc_time, BOOL pacific_daylight_time);
+LL_COMMON_API struct tm* utc_to_pacific_time(time_t utc_time, BOOL pacific_daylight_time);
-void microsecondsToTimecodeString(U64 current_time, char *tcstring);
-void secondsToTimecodeString(F32 current_time, char *tcstring);
+LL_COMMON_API void microsecondsToTimecodeString(U64 current_time, std::string& tcstring);
+LL_COMMON_API void secondsToTimecodeString(F32 current_time, std::string& tcstring);
-// class for scheduling a function to be called at a given frequency (approximate, inprecise)
-class LLEventTimer
-{
-public:
- LLEventTimer(F32 period); // period is the amount of time between each call to tick() in seconds
- virtual ~LLEventTimer();
-
- //function to be called at the supplied frequency
- // Normally return FALSE; TRUE will delete the timer after the function returns.
- virtual BOOL tick() = 0;
-
- static void updateClass();
-
-protected:
- LLTimer mEventTimer;
- F32 mPeriod;
-
-private:
- //list of active timers
- static std::list<LLEventTimer*> sActiveList;
-};
+U64 LL_COMMON_API totalTime(); // Returns current system time in microseconds
#endif
diff --git a/indra/llcommon/lltreeiterators.h b/indra/llcommon/lltreeiterators.h
new file mode 100644
index 0000000000..ba861ae70b
--- /dev/null
+++ b/indra/llcommon/lltreeiterators.h
@@ -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) */
diff --git a/indra/llcommon/lluri.cpp b/indra/llcommon/lluri.cpp
index 022742660d..b39ea0c6f2 100644
--- a/indra/llcommon/lluri.cpp
+++ b/indra/llcommon/lluri.cpp
@@ -4,30 +4,25 @@
* @date 2006-02-08
* @brief Implementation of the LLURI class.
*
- * $LicenseInfo:firstyear=2006&license=viewergpl$
- *
- * Copyright (c) 2006-2007, Linden Research, Inc.
- *
+ * $LicenseInfo:firstyear=2006&license=viewerlgpl$
* Second Life Viewer Source Code
- * The source code in this file ("Source Code") is provided by Linden Lab
- * to you under the terms of the GNU General Public License, version 2.0
- * ("GPL"), unless you have obtained a separate licensing agreement
- * ("Other License"), formally executed by you and Linden Lab. Terms of
- * the GPL can be found in doc/GPL-license.txt in this distribution, or
- * online at http://secondlife.com/developers/opensource/gplv2
+ * 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.
*
- * There are special exceptions to the terms and conditions of the GPL as
- * it is applied to this Source Code. View the full text of the exception
- * in the file doc/FLOSS-exception.txt in this software distribution, or
- * online at http://secondlife.com/developers/opensource/flossexception
+ * 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.
*
- * By copying, modifying or distributing this software, you acknowledge
- * that you have read and understood your obligations described above,
- * and agree to abide by those obligations.
+ * 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
*
- * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
- * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
- * COMPLETENESS OR PERFORMANCE.
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
* $/LicenseInfo$
*/
@@ -38,17 +33,28 @@
#include "llsd.h"
#include <iomanip>
-#include "../llmath/lluuid.h"
+#include "lluuid.h"
// system includes
#include <boost/tokenizer.hpp>
void encode_character(std::ostream& ostr, std::string::value_type val)
{
- ostr << "%" << std::uppercase << std::hex << std::setw(2) << std::setfill('0')
+ ostr << "%"
+
+ << std::uppercase
+ << std::hex
+ << std::setw(2)
+ << std::setfill('0')
+
// VWR-4010 Cannot cast to U32 because sign-extension on
// chars > 128 will result in FFFFFFC3 instead of F3.
- << static_cast<S32>(static_cast<U8>(val));
+ << static_cast<S32>(static_cast<U8>(val))
+
+ // reset stream state
+ << std::nouppercase
+ << std::dec
+ << std::setfill(' ');
}
// static
@@ -161,11 +167,10 @@ namespace
{ return LLURI::escape(s, unreserved() + ":@!$'()*+,="); } // sub_delims - "&;" + ":@"
}
-// *TODO: Consider using curl. After http textures gets merged everywhere.
-// static
+//static
std::string LLURI::escape(const std::string& str)
{
- static std::string default_allowed(unreserved() + ":@!$'()*+,=/?&#;");
+ static std::string default_allowed = unreserved();
static bool initialized = false;
if(!initialized)
{
@@ -220,7 +225,8 @@ static BOOL isDefault(const std::string& scheme, U16 port)
void LLURI::parseAuthorityAndPathUsingOpaque()
{
if (mScheme == "http" || mScheme == "https" ||
- mScheme == "ftp" || mScheme == "secondlife" )
+ mScheme == "ftp" || mScheme == "secondlife" ||
+ mScheme == "x-grid-location-info")
{
if (mEscapedOpaque.substr(0,2) != "//")
{
@@ -599,3 +605,8 @@ std::string LLURI::mapToQueryString(const LLSD& queryMap)
}
return query_string;
}
+
+bool operator!=(const LLURI& first, const LLURI& second)
+{
+ return (first.asString() != second.asString());
+}
diff --git a/indra/llcommon/lluri.h b/indra/llcommon/lluri.h
index 953e652704..c82a666e48 100644
--- a/indra/llcommon/lluri.h
+++ b/indra/llcommon/lluri.h
@@ -4,30 +4,25 @@
* @date 2006-02-05
* @brief Declaration of the URI class.
*
- * $LicenseInfo:firstyear=2006&license=viewergpl$
- *
- * Copyright (c) 2006-2007, Linden Research, Inc.
- *
+ * $LicenseInfo:firstyear=2006&license=viewerlgpl$
* Second Life Viewer Source Code
- * The source code in this file ("Source Code") is provided by Linden Lab
- * to you under the terms of the GNU General Public License, version 2.0
- * ("GPL"), unless you have obtained a separate licensing agreement
- * ("Other License"), formally executed by you and Linden Lab. Terms of
- * the GPL can be found in doc/GPL-license.txt in this distribution, or
- * online at http://secondlife.com/developers/opensource/gplv2
+ * 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.
*
- * There are special exceptions to the terms and conditions of the GPL as
- * it is applied to this Source Code. View the full text of the exception
- * in the file doc/FLOSS-exception.txt in this software distribution, or
- * online at http://secondlife.com/developers/opensource/flossexception
+ * 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.
*
- * By copying, modifying or distributing this software, you acknowledge
- * that you have read and understood your obligations described above,
- * and agree to abide by those obligations.
+ * 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
*
- * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
- * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
- * COMPLETENESS OR PERFORMANCE.
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
* $/LicenseInfo$
*/
@@ -46,7 +41,7 @@ class LLApp;
* See: http://www.ietf.org/rfc/rfc3986.txt
*
*/
-class LLURI
+class LL_COMMON_API LLURI
{
public:
LLURI();
@@ -126,27 +121,16 @@ public:
/** @name Escaping Utilities */
//@{
/**
- * @brief Escape a raw url with a reasonable set of allowed characters.
- *
- * The default set was chosen to match HTTP urls and general
- * guidelines for naming resources. Passing in a raw url does not
- * produce well defined results because you really need to know
- * which segments are path parts because path parts are supposed
- * to be escaped individually. The default set chosen is:
+ * @brief Escape the string passed except for unreserved
*
* ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz
* 0123456789
* -._~
- * :@!$'()*+,=/?&#;
*
- * *NOTE: This API is basically broken because it does not
- * allow you to specify significant path characters. For example,
- * if the filename actually contained a /, then you cannot use
- * this function to generate the serialized url for that
- * resource.
+ * @see http://www.ietf.org/rfc/rfc1738.txt
*
* @param str The raw URI to escape.
- * @return Returns the escaped uri or an empty string.
+ * @return Returns the rfc 1738 escaped uri or an empty string.
*/
static std::string escape(const std::string& str);
@@ -187,4 +171,7 @@ private:
std::string mEscapedQuery;
};
+// this operator required for tut
+LL_COMMON_API bool operator!=(const LLURI& first, const LLURI& second);
+
#endif // LL_LLURI_H
diff --git a/indra/llcommon/lluuid.cpp b/indra/llcommon/lluuid.cpp
new file mode 100644
index 0000000000..5d452ac4e4
--- /dev/null
+++ b/indra/llcommon/lluuid.cpp
@@ -0,0 +1,924 @@
+/**
+ * @file lluuid.cpp
+ *
+ * $LicenseInfo:firstyear=2000&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$
+ */
+
+#include "linden_common.h"
+
+// We can't use WIN32_LEAN_AND_MEAN here, needs lots of includes.
+#if LL_WINDOWS
+#undef WIN32_LEAN_AND_MEAN
+#include <winsock2.h>
+#include <windows.h>
+// ugh, this is ugly. We need to straighten out our linking for this library
+#pragma comment(lib, "IPHLPAPI.lib")
+#include <iphlpapi.h>
+#endif
+
+#include "lldefs.h"
+#include "llerror.h"
+
+#include "lluuid.h"
+#include "llerror.h"
+#include "llrand.h"
+#include "llmd5.h"
+#include "llstring.h"
+#include "lltimer.h"
+
+const LLUUID LLUUID::null;
+const LLTransactionID LLTransactionID::tnull;
+
+/*
+
+NOT DONE YET!!!
+
+static char BASE85_TABLE[] = {
+ '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
+ 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J',
+ 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T',
+ 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd',
+ 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n',
+ 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x',
+ 'y', 'z', '!', '#', '$', '%', '&', '(', ')', '*',
+ '+', '-', ';', '[', '=', '>', '?', '@', '^', '_',
+ '`', '{', '|', '}', '~', '\0'
+};
+
+
+void encode( char * fiveChars, unsigned int word ) throw( )
+{
+for( int ix = 0; ix < 5; ++ix ) {
+fiveChars[4-ix] = encodeTable[ word % 85];
+word /= 85;
+}
+}
+
+To decode:
+unsigned int decode( char const * fiveChars ) throw( bad_input_data )
+{
+unsigned int ret = 0;
+for( int ix = 0; ix < 5; ++ix ) {
+char * s = strchr( encodeTable, fiveChars[ ix ] );
+if( s == 0 ) throw bad_input_data();
+ret = ret * 85 + (s-encodeTable);
+}
+return ret;
+}
+
+void LLUUID::toBase85(char* out)
+{
+ U32* me = (U32*)&(mData[0]);
+ for(S32 i = 0; i < 4; ++i)
+ {
+ char* o = &out[i*i];
+ for(S32 j = 0; j < 5; ++j)
+ {
+ o[4-j] = BASE85_TABLE[ me[i] % 85];
+ word /= 85;
+ }
+ }
+}
+
+unsigned int decode( char const * fiveChars ) throw( bad_input_data )
+{
+ unsigned int ret = 0;
+ for( S32 ix = 0; ix < 5; ++ix )
+ {
+ char * s = strchr( encodeTable, fiveChars[ ix ] );
+ ret = ret * 85 + (s-encodeTable);
+ }
+ return ret;
+}
+*/
+
+#define LL_USE_JANKY_RANDOM_NUMBER_GENERATOR 0
+#if LL_USE_JANKY_RANDOM_NUMBER_GENERATOR
+/**
+ * @brief a global for
+ */
+static U64 sJankyRandomSeed(LLUUID::getRandomSeed());
+
+/**
+ * @brief generate a random U32.
+ */
+U32 janky_fast_random_bytes()
+{
+ sJankyRandomSeed = U64L(1664525) * sJankyRandomSeed + U64L(1013904223);
+ return (U32)sJankyRandomSeed;
+}
+
+/**
+ * @brief generate a random U32 from [0, val)
+ */
+U32 janky_fast_random_byes_range(U32 val)
+{
+ sJankyRandomSeed = U64L(1664525) * sJankyRandomSeed + U64L(1013904223);
+ return (U32)(sJankyRandomSeed) % val;
+}
+
+/**
+ * @brief generate a random U32 from [0, val)
+ */
+U32 janky_fast_random_seeded_bytes(U32 seed, U32 val)
+{
+ seed = U64L(1664525) * (U64)(seed) + U64L(1013904223);
+ return (U32)(seed) % val;
+}
+#endif
+
+// Common to all UUID implementations
+void LLUUID::toString(std::string& out) const
+{
+ out = llformat(
+ "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x",
+ (U8)(mData[0]),
+ (U8)(mData[1]),
+ (U8)(mData[2]),
+ (U8)(mData[3]),
+ (U8)(mData[4]),
+ (U8)(mData[5]),
+ (U8)(mData[6]),
+ (U8)(mData[7]),
+ (U8)(mData[8]),
+ (U8)(mData[9]),
+ (U8)(mData[10]),
+ (U8)(mData[11]),
+ (U8)(mData[12]),
+ (U8)(mData[13]),
+ (U8)(mData[14]),
+ (U8)(mData[15]));
+}
+
+// *TODO: deprecate
+void LLUUID::toString(char *out) const
+{
+ std::string buffer;
+ toString(buffer);
+ strcpy(out,buffer.c_str()); /* Flawfinder: ignore */
+}
+
+void LLUUID::toCompressedString(std::string& out) const
+{
+ char bytes[UUID_BYTES+1];
+ memcpy(bytes, mData, UUID_BYTES); /* Flawfinder: ignore */
+ bytes[UUID_BYTES] = '\0';
+ out.assign(bytes, UUID_BYTES);
+}
+
+// *TODO: deprecate
+void LLUUID::toCompressedString(char *out) const
+{
+ memcpy(out, mData, UUID_BYTES); /* Flawfinder: ignore */
+ out[UUID_BYTES] = '\0';
+}
+
+std::string LLUUID::getString() const
+{
+ return asString();
+}
+
+std::string LLUUID::asString() const
+{
+ std::string str;
+ toString(str);
+ return str;
+}
+
+BOOL LLUUID::set(const char* in_string, BOOL emit)
+{
+ return set(ll_safe_string(in_string),emit);
+}
+
+BOOL LLUUID::set(const std::string& in_string, BOOL emit)
+{
+ BOOL broken_format = FALSE;
+
+ // empty strings should make NULL uuid
+ if (in_string.empty())
+ {
+ setNull();
+ return TRUE;
+ }
+
+ if (in_string.length() != (UUID_STR_LENGTH - 1)) /* Flawfinder: ignore */
+ {
+ // I'm a moron. First implementation didn't have the right UUID format.
+ // Shouldn't see any of these any more
+ if (in_string.length() == (UUID_STR_LENGTH - 2)) /* Flawfinder: ignore */
+ {
+ if(emit)
+ {
+ llwarns << "Warning! Using broken UUID string format" << llendl;
+ }
+ broken_format = TRUE;
+ }
+ else
+ {
+ // Bad UUID string. Spam as INFO, as most cases we don't care.
+ if(emit)
+ {
+ //don't spam the logs because a resident can't spell.
+ llwarns << "Bad UUID string: " << in_string << llendl;
+ }
+ setNull();
+ return FALSE;
+ }
+ }
+
+ U8 cur_pos = 0;
+ S32 i;
+ for (i = 0; i < UUID_BYTES; i++)
+ {
+ if ((i == 4) || (i == 6) || (i == 8) || (i == 10))
+ {
+ cur_pos++;
+ if (broken_format && (i==10))
+ {
+ // Missing - in the broken format
+ cur_pos--;
+ }
+ }
+
+ mData[i] = 0;
+
+ if ((in_string[cur_pos] >= '0') && (in_string[cur_pos] <= '9'))
+ {
+ mData[i] += (U8)(in_string[cur_pos] - '0');
+ }
+ else if ((in_string[cur_pos] >= 'a') && (in_string[cur_pos] <='f'))
+ {
+ mData[i] += (U8)(10 + in_string[cur_pos] - 'a');
+ }
+ else if ((in_string[cur_pos] >= 'A') && (in_string[cur_pos] <='F'))
+ {
+ mData[i] += (U8)(10 + in_string[cur_pos] - 'A');
+ }
+ else
+ {
+ if(emit)
+ {
+ llwarns << "Invalid UUID string character" << llendl;
+ }
+ setNull();
+ return FALSE;
+ }
+
+ mData[i] = mData[i] << 4;
+ cur_pos++;
+
+ if ((in_string[cur_pos] >= '0') && (in_string[cur_pos] <= '9'))
+ {
+ mData[i] += (U8)(in_string[cur_pos] - '0');
+ }
+ else if ((in_string[cur_pos] >= 'a') && (in_string[cur_pos] <='f'))
+ {
+ mData[i] += (U8)(10 + in_string[cur_pos] - 'a');
+ }
+ else if ((in_string[cur_pos] >= 'A') && (in_string[cur_pos] <='F'))
+ {
+ mData[i] += (U8)(10 + in_string[cur_pos] - 'A');
+ }
+ else
+ {
+ if(emit)
+ {
+ llwarns << "Invalid UUID string character" << llendl;
+ }
+ setNull();
+ return FALSE;
+ }
+ cur_pos++;
+ }
+
+ return TRUE;
+}
+
+BOOL LLUUID::validate(const std::string& in_string)
+{
+ BOOL broken_format = FALSE;
+ if (in_string.length() != (UUID_STR_LENGTH - 1)) /* Flawfinder: ignore */
+ {
+ // I'm a moron. First implementation didn't have the right UUID format.
+ if (in_string.length() == (UUID_STR_LENGTH - 2)) /* Flawfinder: ignore */
+ {
+ broken_format = TRUE;
+ }
+ else
+ {
+ return FALSE;
+ }
+ }
+
+ U8 cur_pos = 0;
+ for (U32 i = 0; i < 16; i++)
+ {
+ if ((i == 4) || (i == 6) || (i == 8) || (i == 10))
+ {
+ cur_pos++;
+ if (broken_format && (i==10))
+ {
+ // Missing - in the broken format
+ cur_pos--;
+ }
+ }
+
+ if ((in_string[cur_pos] >= '0') && (in_string[cur_pos] <= '9'))
+ {
+ }
+ else if ((in_string[cur_pos] >= 'a') && (in_string[cur_pos] <='f'))
+ {
+ }
+ else if ((in_string[cur_pos] >= 'A') && (in_string[cur_pos] <='F'))
+ {
+ }
+ else
+ {
+ return FALSE;
+ }
+
+ cur_pos++;
+
+ if ((in_string[cur_pos] >= '0') && (in_string[cur_pos] <= '9'))
+ {
+ }
+ else if ((in_string[cur_pos] >= 'a') && (in_string[cur_pos] <='f'))
+ {
+ }
+ else if ((in_string[cur_pos] >= 'A') && (in_string[cur_pos] <='F'))
+ {
+ }
+ else
+ {
+ return FALSE;
+ }
+ cur_pos++;
+ }
+ return TRUE;
+}
+
+const LLUUID& LLUUID::operator^=(const LLUUID& rhs)
+{
+ U32* me = (U32*)&(mData[0]);
+ const U32* other = (U32*)&(rhs.mData[0]);
+ for(S32 i = 0; i < 4; ++i)
+ {
+ me[i] = me[i] ^ other[i];
+ }
+ return *this;
+}
+
+LLUUID LLUUID::operator^(const LLUUID& rhs) const
+{
+ LLUUID id(*this);
+ id ^= rhs;
+ return id;
+}
+
+void LLUUID::combine(const LLUUID& other, LLUUID& result) const
+{
+ LLMD5 md5_uuid;
+ md5_uuid.update((unsigned char*)mData, 16);
+ md5_uuid.update((unsigned char*)other.mData, 16);
+ md5_uuid.finalize();
+ md5_uuid.raw_digest(result.mData);
+}
+
+LLUUID LLUUID::combine(const LLUUID &other) const
+{
+ LLUUID combination;
+ combine(other, combination);
+ return combination;
+}
+
+std::ostream& operator<<(std::ostream& s, const LLUUID &uuid)
+{
+ std::string uuid_str;
+ uuid.toString(uuid_str);
+ s << uuid_str;
+ return s;
+}
+
+std::istream& operator>>(std::istream &s, LLUUID &uuid)
+{
+ U32 i;
+ char uuid_str[UUID_STR_LENGTH]; /* Flawfinder: ignore */
+ for (i = 0; i < UUID_STR_LENGTH-1; i++)
+ {
+ s >> uuid_str[i];
+ }
+ uuid_str[i] = '\0';
+ uuid.set(std::string(uuid_str));
+ return s;
+}
+
+static void get_random_bytes(void *buf, int nbytes)
+{
+ int i;
+ char *cp = (char *) buf;
+
+ // *NOTE: If we are not using the janky generator ll_rand()
+ // generates at least 3 good bytes of data since it is 0 to
+ // RAND_MAX. This could be made more efficient by copying all the
+ // bytes.
+ for (i=0; i < nbytes; i++)
+#if LL_USE_JANKY_RANDOM_NUMBER_GENERATOR
+ *cp++ = janky_fast_random_bytes() & 0xFF;
+#else
+ *cp++ = ll_rand() & 0xFF;
+#endif
+ return;
+}
+
+#if LL_WINDOWS
+
+typedef struct _ASTAT_
+{
+ ADAPTER_STATUS adapt;
+ NAME_BUFFER NameBuff [30];
+}ASTAT, * PASTAT;
+
+// static
+S32 LLUUID::getNodeID(unsigned char *node_id)
+{
+ ASTAT Adapter;
+ NCB Ncb;
+ UCHAR uRetCode;
+ LANA_ENUM lenum;
+ int i;
+ int retval = 0;
+
+ memset( &Ncb, 0, sizeof(Ncb) );
+ Ncb.ncb_command = NCBENUM;
+ Ncb.ncb_buffer = (UCHAR *)&lenum;
+ Ncb.ncb_length = sizeof(lenum);
+ uRetCode = Netbios( &Ncb );
+
+ for(i=0; i < lenum.length ;i++)
+ {
+ memset( &Ncb, 0, sizeof(Ncb) );
+ Ncb.ncb_command = NCBRESET;
+ Ncb.ncb_lana_num = lenum.lana[i];
+
+ uRetCode = Netbios( &Ncb );
+
+ memset( &Ncb, 0, sizeof (Ncb) );
+ Ncb.ncb_command = NCBASTAT;
+ Ncb.ncb_lana_num = lenum.lana[i];
+
+ strcpy( (char *)Ncb.ncb_callname, "* " ); /* Flawfinder: ignore */
+ Ncb.ncb_buffer = (unsigned char *)&Adapter;
+ Ncb.ncb_length = sizeof(Adapter);
+
+ uRetCode = Netbios( &Ncb );
+ if ( uRetCode == 0 )
+ {
+ memcpy(node_id,Adapter.adapt.adapter_address,6); /* Flawfinder: ignore */
+ retval = 1;
+ }
+ }
+ return retval;
+}
+
+#elif LL_DARWIN
+// Mac OS X version of the UUID generation code...
+/*
+ * Get an ethernet hardware address, if we can find it...
+ */
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/socket.h>
+#include <sys/ioctl.h>
+#include <net/if.h>
+#include <net/if_types.h>
+#include <net/if_dl.h>
+#include <net/route.h>
+#include <ifaddrs.h>
+
+// static
+S32 LLUUID::getNodeID(unsigned char *node_id)
+{
+ int i;
+ unsigned char *a = NULL;
+ struct ifaddrs *ifap, *ifa;
+ int rv;
+ S32 result = 0;
+
+ if ((rv=getifaddrs(&ifap))==-1)
+ {
+ return -1;
+ }
+ if (ifap == NULL)
+ {
+ return -1;
+ }
+
+ for (ifa = ifap; ifa != NULL; ifa = ifa->ifa_next)
+ {
+// printf("Interface %s, address family %d, ", ifa->ifa_name, ifa->ifa_addr->sa_family);
+ for(i=0; i< ifa->ifa_addr->sa_len; i++)
+ {
+// printf("%02X ", (unsigned char)ifa->ifa_addr->sa_data[i]);
+ }
+// printf("\n");
+
+ if(ifa->ifa_addr->sa_family == AF_LINK)
+ {
+ // This is a link-level address
+ struct sockaddr_dl *lla = (struct sockaddr_dl *)ifa->ifa_addr;
+
+// printf("\tLink level address, type %02X\n", lla->sdl_type);
+
+ if(lla->sdl_type == IFT_ETHER)
+ {
+ // Use the first ethernet MAC in the list.
+ // For some reason, the macro LLADDR() defined in net/if_dl.h doesn't expand correctly. This is what it would do.
+ a = (unsigned char *)&((lla)->sdl_data);
+ a += (lla)->sdl_nlen;
+
+ if (!a[0] && !a[1] && !a[2] && !a[3] && !a[4] && !a[5])
+ {
+ continue;
+ }
+
+ if (node_id)
+ {
+ memcpy(node_id, a, 6);
+ result = 1;
+ }
+
+ // We found one.
+ break;
+ }
+ }
+ }
+ freeifaddrs(ifap);
+
+ return result;
+}
+
+#else
+
+// Linux version of the UUID generation code...
+/*
+ * Get the ethernet hardware address, if we can find it...
+ */
+#include <unistd.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/stat.h>
+#include <sys/file.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+#include <net/if.h>
+#define HAVE_NETINET_IN_H
+#ifdef HAVE_NETINET_IN_H
+#include <netinet/in.h>
+#if LL_SOLARIS
+#include <sys/sockio.h>
+#elif !LL_DARWIN
+#include <linux/sockios.h>
+#endif
+#endif
+
+// static
+S32 LLUUID::getNodeID(unsigned char *node_id)
+{
+ int sd;
+ struct ifreq ifr, *ifrp;
+ struct ifconf ifc;
+ char buf[1024];
+ int n, i;
+ unsigned char *a;
+
+/*
+ * BSD 4.4 defines the size of an ifreq to be
+ * max(sizeof(ifreq), sizeof(ifreq.ifr_name)+ifreq.ifr_addr.sa_len
+ * However, under earlier systems, sa_len isn't present, so the size is
+ * just sizeof(struct ifreq)
+ */
+#ifdef HAVE_SA_LEN
+#ifndef max
+#define max(a,b) ((a) > (b) ? (a) : (b))
+#endif
+#define ifreq_size(i) max(sizeof(struct ifreq),\
+ sizeof((i).ifr_name)+(i).ifr_addr.sa_len)
+#else
+#define ifreq_size(i) sizeof(struct ifreq)
+#endif /* HAVE_SA_LEN*/
+
+ sd = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP);
+ if (sd < 0) {
+ return -1;
+ }
+ memset(buf, 0, sizeof(buf));
+ ifc.ifc_len = sizeof(buf);
+ ifc.ifc_buf = buf;
+ if (ioctl (sd, SIOCGIFCONF, (char *)&ifc) < 0) {
+ close(sd);
+ return -1;
+ }
+ n = ifc.ifc_len;
+ for (i = 0; i < n; i+= ifreq_size(*ifr) ) {
+ ifrp = (struct ifreq *)((char *) ifc.ifc_buf+i);
+ strncpy(ifr.ifr_name, ifrp->ifr_name, IFNAMSIZ); /* Flawfinder: ignore */
+#ifdef SIOCGIFHWADDR
+ if (ioctl(sd, SIOCGIFHWADDR, &ifr) < 0)
+ continue;
+ a = (unsigned char *) &ifr.ifr_hwaddr.sa_data;
+#else
+#ifdef SIOCGENADDR
+ if (ioctl(sd, SIOCGENADDR, &ifr) < 0)
+ continue;
+ a = (unsigned char *) ifr.ifr_enaddr;
+#else
+ /*
+ * XXX we don't have a way of getting the hardware
+ * address
+ */
+ close(sd);
+ return 0;
+#endif /* SIOCGENADDR */
+#endif /* SIOCGIFHWADDR */
+ if (!a[0] && !a[1] && !a[2] && !a[3] && !a[4] && !a[5])
+ continue;
+ if (node_id) {
+ memcpy(node_id, a, 6); /* Flawfinder: ignore */
+ close(sd);
+ return 1;
+ }
+ }
+ close(sd);
+ return 0;
+}
+
+#endif
+
+S32 LLUUID::cmpTime(uuid_time_t *t1, uuid_time_t *t2)
+{
+ // Compare two time values.
+
+ if (t1->high < t2->high) return -1;
+ if (t1->high > t2->high) return 1;
+ if (t1->low < t2->low) return -1;
+ if (t1->low > t2->low) return 1;
+ return 0;
+}
+
+void LLUUID::getSystemTime(uuid_time_t *timestamp)
+{
+ // Get system time with 100ns precision. Time is since Oct 15, 1582.
+#if LL_WINDOWS
+ ULARGE_INTEGER time;
+ GetSystemTimeAsFileTime((FILETIME *)&time);
+ // NT keeps time in FILETIME format which is 100ns ticks since
+ // Jan 1, 1601. UUIDs use time in 100ns ticks since Oct 15, 1582.
+ // The difference is 17 Days in Oct + 30 (Nov) + 31 (Dec)
+ // + 18 years and 5 leap days.
+ time.QuadPart +=
+ (unsigned __int64) (1000*1000*10) // seconds
+ * (unsigned __int64) (60 * 60 * 24) // days
+ * (unsigned __int64) (17+30+31+365*18+5); // # of days
+
+ timestamp->high = time.HighPart;
+ timestamp->low = time.LowPart;
+#else
+ struct timeval tp;
+ gettimeofday(&tp, 0);
+
+ // Offset between UUID formatted times and Unix formatted times.
+ // UUID UTC base time is October 15, 1582.
+ // Unix base time is January 1, 1970.
+ U64 uuid_time = ((U64)tp.tv_sec * 10000000) + (tp.tv_usec * 10) +
+ U64L(0x01B21DD213814000);
+ timestamp->high = (U32) (uuid_time >> 32);
+ timestamp->low = (U32) (uuid_time & 0xFFFFFFFF);
+#endif
+}
+
+void LLUUID::getCurrentTime(uuid_time_t *timestamp)
+{
+ // Get current time as 60 bit 100ns ticks since whenever.
+ // Compensate for the fact that real clock resolution is less
+ // than 100ns.
+
+ const U32 uuids_per_tick = 1024;
+
+ static uuid_time_t time_last;
+ static U32 uuids_this_tick;
+ static BOOL init = FALSE;
+
+ if (!init) {
+ getSystemTime(&time_last);
+ uuids_this_tick = uuids_per_tick;
+ init = TRUE;
+ }
+
+ uuid_time_t time_now = {0,0};
+
+ while (1) {
+ getSystemTime(&time_now);
+
+ // if clock reading changed since last UUID generated
+ if (cmpTime(&time_last, &time_now)) {
+ // reset count of uuid's generated with this clock reading
+ uuids_this_tick = 0;
+ break;
+ }
+ if (uuids_this_tick < uuids_per_tick) {
+ uuids_this_tick++;
+ break;
+ }
+ // going too fast for our clock; spin
+ }
+
+ time_last = time_now;
+
+ if (uuids_this_tick != 0) {
+ if (time_now.low & 0x80000000) {
+ time_now.low += uuids_this_tick;
+ if (!(time_now.low & 0x80000000))
+ time_now.high++;
+ } else
+ time_now.low += uuids_this_tick;
+ }
+
+ timestamp->high = time_now.high;
+ timestamp->low = time_now.low;
+}
+
+void LLUUID::generate()
+{
+ // Create a UUID.
+ uuid_time_t timestamp;
+
+ static unsigned char node_id[6]; /* Flawfinder: ignore */
+ static int has_init = 0;
+
+ // Create a UUID.
+ static uuid_time_t time_last = {0,0};
+ static U16 clock_seq = 0;
+#if LL_USE_JANKY_RANDOM_NUMBER_GENERATOR
+ static U32 seed = 0L; // dummy seed. reset it below
+#endif
+ if (!has_init)
+ {
+ if (getNodeID(node_id) <= 0)
+ {
+ get_random_bytes(node_id, 6);
+ /*
+ * Set multicast bit, to prevent conflicts
+ * with IEEE 802 addresses obtained from
+ * network cards
+ */
+ node_id[0] |= 0x80;
+ }
+
+ getCurrentTime(&time_last);
+#if LL_USE_JANKY_RANDOM_NUMBER_GENERATOR
+ seed = time_last.low;
+#endif
+
+#if LL_USE_JANKY_RANDOM_NUMBER_GENERATOR
+ clock_seq = (U16)janky_fast_random_seeded_bytes(seed, 65536);
+#else
+ clock_seq = (U16)ll_rand(65536);
+#endif
+ has_init = 1;
+ }
+
+ // get current time
+ getCurrentTime(&timestamp);
+
+ // if clock went backward change clockseq
+ if (cmpTime(&timestamp, &time_last) == -1) {
+ clock_seq = (clock_seq + 1) & 0x3FFF;
+ if (clock_seq == 0) clock_seq++;
+ }
+
+ memcpy(mData+10, node_id, 6); /* Flawfinder: ignore */
+ U32 tmp;
+ tmp = timestamp.low;
+ mData[3] = (unsigned char) tmp;
+ tmp >>= 8;
+ mData[2] = (unsigned char) tmp;
+ tmp >>= 8;
+ mData[1] = (unsigned char) tmp;
+ tmp >>= 8;
+ mData[0] = (unsigned char) tmp;
+
+ tmp = (U16) timestamp.high;
+ mData[5] = (unsigned char) tmp;
+ tmp >>= 8;
+ mData[4] = (unsigned char) tmp;
+
+ tmp = (timestamp.high >> 16) | 0x1000;
+ mData[7] = (unsigned char) tmp;
+ tmp >>= 8;
+ mData[6] = (unsigned char) tmp;
+
+ tmp = clock_seq;
+ mData[9] = (unsigned char) tmp;
+ tmp >>= 8;
+ mData[8] = (unsigned char) tmp;
+
+ LLMD5 md5_uuid;
+
+ md5_uuid.update(mData,16);
+ md5_uuid.finalize();
+ md5_uuid.raw_digest(mData);
+
+ time_last = timestamp;
+}
+
+void LLUUID::generate(const std::string& hash_string)
+{
+ LLMD5 md5_uuid((U8*)hash_string.c_str());
+ md5_uuid.raw_digest(mData);
+}
+
+U32 LLUUID::getRandomSeed()
+{
+ static unsigned char seed[16]; /* Flawfinder: ignore */
+
+ getNodeID(&seed[0]);
+ seed[6]='\0';
+ seed[7]='\0';
+ getSystemTime((uuid_time_t *)(&seed[8]));
+
+ LLMD5 md5_seed;
+
+ md5_seed.update(seed,16);
+ md5_seed.finalize();
+ md5_seed.raw_digest(seed);
+
+ return(*(U32 *)seed);
+}
+
+BOOL LLUUID::parseUUID(const std::string& buf, LLUUID* value)
+{
+ if( buf.empty() || value == NULL)
+ {
+ return FALSE;
+ }
+
+ std::string temp( buf );
+ LLStringUtil::trim(temp);
+ if( LLUUID::validate( temp ) )
+ {
+ value->set( temp );
+ return TRUE;
+ }
+ return FALSE;
+}
+
+//static
+LLUUID LLUUID::generateNewID(std::string hash_string)
+{
+ LLUUID new_id;
+ if (hash_string.empty())
+ {
+ new_id.generate();
+ }
+ else
+ {
+ new_id.generate(hash_string);
+ }
+ return new_id;
+}
+
+LLAssetID LLTransactionID::makeAssetID(const LLUUID& session) const
+{
+ LLAssetID result;
+ if (isNull())
+ {
+ result.setNull();
+ }
+ else
+ {
+ combine(session, result);
+ }
+ return result;
+}
diff --git a/indra/llcommon/lluuid.h b/indra/llcommon/lluuid.h
new file mode 100644
index 0000000000..726be4a82d
--- /dev/null
+++ b/indra/llcommon/lluuid.h
@@ -0,0 +1,331 @@
+/**
+ * @file lluuid.h
+ *
+ * $LicenseInfo:firstyear=2000&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$
+ */
+
+#ifndef LL_LLUUID_H
+#define LL_LLUUID_H
+
+#include <iostream>
+#include <set>
+#include "stdtypes.h"
+#include "llpreprocessor.h"
+
+const S32 UUID_BYTES = 16;
+const S32 UUID_WORDS = 4;
+const S32 UUID_STR_LENGTH = 37; // actually wrong, should be 36 and use size below
+const S32 UUID_STR_SIZE = 37;
+const S32 UUID_BASE85_LENGTH = 21; // including the trailing NULL.
+
+struct uuid_time_t {
+ U32 high;
+ U32 low;
+ };
+
+class LL_COMMON_API LLUUID
+{
+public:
+ //
+ // CREATORS
+ //
+ LLUUID();
+ explicit LLUUID(const char *in_string); // Convert from string.
+ explicit LLUUID(const std::string& in_string); // Convert from string.
+ LLUUID(const LLUUID &in);
+ LLUUID &operator=(const LLUUID &rhs);
+
+ ~LLUUID();
+
+ //
+ // MANIPULATORS
+ //
+ void generate(); // Generate a new UUID
+ void generate(const std::string& stream); //Generate a new UUID based on hash of input stream
+
+ static LLUUID generateNewID(std::string stream = ""); //static version of above for use in initializer expressions such as constructor params, etc.
+
+ BOOL set(const char *in_string, BOOL emit = TRUE); // Convert from string, if emit is FALSE, do not emit warnings
+ BOOL set(const std::string& in_string, BOOL emit = TRUE); // Convert from string, if emit is FALSE, do not emit warnings
+ void setNull(); // Faster than setting to LLUUID::null.
+
+ S32 cmpTime(uuid_time_t *t1, uuid_time_t *t2);
+ static void getSystemTime(uuid_time_t *timestamp);
+ void getCurrentTime(uuid_time_t *timestamp);
+
+ //
+ // ACCESSORS
+ //
+ BOOL isNull() const; // Faster than comparing to LLUUID::null.
+ BOOL notNull() const; // Faster than comparing to LLUUID::null.
+ // JC: This is dangerous. It allows UUIDs to be cast automatically
+ // to integers, among other things. Use isNull() or notNull().
+ // operator bool() const;
+
+ // JC: These must return real bool's (not BOOLs) or else use of the STL
+ // will generate bool-to-int performance warnings.
+ bool operator==(const LLUUID &rhs) const;
+ bool operator!=(const LLUUID &rhs) const;
+ bool operator<(const LLUUID &rhs) const;
+ bool operator>(const LLUUID &rhs) const;
+
+ // xor functions. Useful since any two random uuids xored together
+ // will yield a determinate third random unique id that can be
+ // used as a key in a single uuid that represents 2.
+ const LLUUID& operator^=(const LLUUID& rhs);
+ LLUUID operator^(const LLUUID& rhs) const;
+
+ // similar to functions above, but not invertible
+ // yields a third random UUID that can be reproduced from the two inputs
+ // but which, given the result and one of the inputs can't be used to
+ // deduce the other input
+ LLUUID combine(const LLUUID& other) const;
+ void combine(const LLUUID& other, LLUUID& result) const;
+
+ friend LL_COMMON_API std::ostream& operator<<(std::ostream& s, const LLUUID &uuid);
+ friend LL_COMMON_API std::istream& operator>>(std::istream& s, LLUUID &uuid);
+
+ void toString(char *out) const; // Does not allocate memory, needs 36 characters (including \0)
+ void toString(std::string& out) const;
+ void toCompressedString(char *out) const; // Does not allocate memory, needs 17 characters (including \0)
+ void toCompressedString(std::string& out) const;
+
+ std::string asString() const;
+ std::string getString() const;
+
+ U16 getCRC16() const;
+ U32 getCRC32() const;
+
+ static BOOL validate(const std::string& in_string); // Validate that the UUID string is legal.
+
+ static const LLUUID null;
+
+ static U32 getRandomSeed();
+ static S32 getNodeID(unsigned char * node_id);
+
+ static BOOL parseUUID(const std::string& buf, LLUUID* value);
+
+ U8 mData[UUID_BYTES];
+};
+
+typedef std::vector<LLUUID> uuid_vec_t;
+
+// Construct
+inline LLUUID::LLUUID()
+{
+ setNull();
+}
+
+
+// Faster than copying from memory
+inline void LLUUID::setNull()
+{
+ U32 *word = (U32 *)mData;
+ word[0] = 0;
+ word[1] = 0;
+ word[2] = 0;
+ word[3] = 0;
+}
+
+
+// Compare
+inline bool LLUUID::operator==(const LLUUID& rhs) const
+{
+ U32 *tmp = (U32 *)mData;
+ U32 *rhstmp = (U32 *)rhs.mData;
+ // Note: binary & to avoid branching
+ return
+ (tmp[0] == rhstmp[0]) &
+ (tmp[1] == rhstmp[1]) &
+ (tmp[2] == rhstmp[2]) &
+ (tmp[3] == rhstmp[3]);
+}
+
+
+inline bool LLUUID::operator!=(const LLUUID& rhs) const
+{
+ U32 *tmp = (U32 *)mData;
+ U32 *rhstmp = (U32 *)rhs.mData;
+ // Note: binary | to avoid branching
+ return
+ (tmp[0] != rhstmp[0]) |
+ (tmp[1] != rhstmp[1]) |
+ (tmp[2] != rhstmp[2]) |
+ (tmp[3] != rhstmp[3]);
+}
+
+/*
+// JC: This is dangerous. It allows UUIDs to be cast automatically
+// to integers, among other things. Use isNull() or notNull().
+inline LLUUID::operator bool() const
+{
+ U32 *word = (U32 *)mData;
+ return (word[0] | word[1] | word[2] | word[3]) > 0;
+}
+*/
+
+inline BOOL LLUUID::notNull() const
+{
+ U32 *word = (U32 *)mData;
+ return (word[0] | word[1] | word[2] | word[3]) > 0;
+}
+
+// Faster than == LLUUID::null because doesn't require
+// as much memory access.
+inline BOOL LLUUID::isNull() const
+{
+ U32 *word = (U32 *)mData;
+ // If all bits are zero, return !0 == TRUE
+ return !(word[0] | word[1] | word[2] | word[3]);
+}
+
+// Copy constructor
+inline LLUUID::LLUUID(const LLUUID& rhs)
+{
+ U32 *tmp = (U32 *)mData;
+ U32 *rhstmp = (U32 *)rhs.mData;
+ tmp[0] = rhstmp[0];
+ tmp[1] = rhstmp[1];
+ tmp[2] = rhstmp[2];
+ tmp[3] = rhstmp[3];
+}
+
+inline LLUUID::~LLUUID()
+{
+}
+
+// Assignment
+inline LLUUID& LLUUID::operator=(const LLUUID& rhs)
+{
+ // No need to check the case where this==&rhs. The branch is slower than the write.
+ U32 *tmp = (U32 *)mData;
+ U32 *rhstmp = (U32 *)rhs.mData;
+ tmp[0] = rhstmp[0];
+ tmp[1] = rhstmp[1];
+ tmp[2] = rhstmp[2];
+ tmp[3] = rhstmp[3];
+
+ return *this;
+}
+
+
+inline LLUUID::LLUUID(const char *in_string)
+{
+ if (!in_string || in_string[0] == 0)
+ {
+ setNull();
+ return;
+ }
+
+ set(in_string);
+}
+
+inline LLUUID::LLUUID(const std::string& in_string)
+{
+ if (in_string.empty())
+ {
+ setNull();
+ return;
+ }
+
+ set(in_string);
+}
+
+// IW: DON'T "optimize" these w/ U32s or you'll scoogie the sort order
+// IW: this will make me very sad
+inline bool LLUUID::operator<(const LLUUID &rhs) const
+{
+ U32 i;
+ for( i = 0; i < (UUID_BYTES - 1); i++ )
+ {
+ if( mData[i] != rhs.mData[i] )
+ {
+ return (mData[i] < rhs.mData[i]);
+ }
+ }
+ return (mData[UUID_BYTES - 1] < rhs.mData[UUID_BYTES - 1]);
+}
+
+inline bool LLUUID::operator>(const LLUUID &rhs) const
+{
+ U32 i;
+ for( i = 0; i < (UUID_BYTES - 1); i++ )
+ {
+ if( mData[i] != rhs.mData[i] )
+ {
+ return (mData[i] > rhs.mData[i]);
+ }
+ }
+ return (mData[UUID_BYTES - 1] > rhs.mData[UUID_BYTES - 1]);
+}
+
+inline U16 LLUUID::getCRC16() const
+{
+ // A UUID is 16 bytes, or 8 shorts.
+ U16 *short_data = (U16*)mData;
+ U16 out = 0;
+ out += short_data[0];
+ out += short_data[1];
+ out += short_data[2];
+ out += short_data[3];
+ out += short_data[4];
+ out += short_data[5];
+ out += short_data[6];
+ out += short_data[7];
+ return out;
+}
+
+inline U32 LLUUID::getCRC32() const
+{
+ U32 *tmp = (U32*)mData;
+ return tmp[0] + tmp[1] + tmp[2] + tmp[3];
+}
+
+
+// Helper structure for ordering lluuids in stl containers.
+// eg: std::map<LLUUID, LLWidget*, lluuid_less> widget_map;
+struct lluuid_less
+{
+ bool operator()(const LLUUID& lhs, const LLUUID& rhs) const
+ {
+ return (lhs < rhs) ? true : false;
+ }
+};
+
+typedef std::set<LLUUID, lluuid_less> uuid_list_t;
+
+/*
+ * Sub-classes for keeping transaction IDs and asset IDs
+ * straight.
+ */
+typedef LLUUID LLAssetID;
+
+class LL_COMMON_API LLTransactionID : public LLUUID
+{
+public:
+ LLTransactionID() : LLUUID() { }
+
+ static const LLTransactionID tnull;
+ LLAssetID makeAssetID(const LLUUID& session) const;
+};
+
+#endif
diff --git a/indra/llcommon/lluuidhashmap.h b/indra/llcommon/lluuidhashmap.h
index d8d3cffcb0..e294670030 100644
--- a/indra/llcommon/lluuidhashmap.h
+++ b/indra/llcommon/lluuidhashmap.h
@@ -2,30 +2,25 @@
* @file lluuidhashmap.h
* @brief A uuid based hash map.
*
- * $LicenseInfo:firstyear=2003&license=viewergpl$
- *
- * Copyright (c) 2003-2007, Linden Research, Inc.
- *
+ * $LicenseInfo:firstyear=2003&license=viewerlgpl$
* Second Life Viewer Source Code
- * The source code in this file ("Source Code") is provided by Linden Lab
- * to you under the terms of the GNU General Public License, version 2.0
- * ("GPL"), unless you have obtained a separate licensing agreement
- * ("Other License"), formally executed by you and Linden Lab. Terms of
- * the GPL can be found in doc/GPL-license.txt in this distribution, or
- * online at http://secondlife.com/developers/opensource/gplv2
+ * 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.
*
- * There are special exceptions to the terms and conditions of the GPL as
- * it is applied to this Source Code. View the full text of the exception
- * in the file doc/FLOSS-exception.txt in this software distribution, or
- * online at http://secondlife.com/developers/opensource/flossexception
+ * 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.
*
- * By copying, modifying or distributing this software, you acknowledge
- * that you have read and understood your obligations described above,
- * and agree to abide by those obligations.
+ * 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
*
- * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
- * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
- * COMPLETENESS OR PERFORMANCE.
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
* $/LicenseInfo$
*/
diff --git a/indra/llcommon/llversionserver.h b/indra/llcommon/llversionserver.h
index 9c34852031..b19ba3bf74 100644
--- a/indra/llcommon/llversionserver.h
+++ b/indra/llcommon/llversionserver.h
@@ -2,40 +2,35 @@
* @file llversionserver.h
* @brief
*
- * $LicenseInfo:firstyear=2002&license=viewergpl$
- *
- * Copyright (c) 2002-2007, Linden Research, Inc.
- *
+ * $LicenseInfo:firstyear=2002&license=viewerlgpl$
* Second Life Viewer Source Code
- * The source code in this file ("Source Code") is provided by Linden Lab
- * to you under the terms of the GNU General Public License, version 2.0
- * ("GPL"), unless you have obtained a separate licensing agreement
- * ("Other License"), formally executed by you and Linden Lab. Terms of
- * the GPL can be found in doc/GPL-license.txt in this distribution, or
- * online at http://secondlife.com/developers/opensource/gplv2
+ * 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.
*
- * There are special exceptions to the terms and conditions of the GPL as
- * it is applied to this Source Code. View the full text of the exception
- * in the file doc/FLOSS-exception.txt in this software distribution, or
- * online at http://secondlife.com/developers/opensource/flossexception
+ * 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.
*
- * By copying, modifying or distributing this software, you acknowledge
- * that you have read and understood your obligations described above,
- * and agree to abide by those obligations.
+ * 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
*
- * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
- * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
- * COMPLETENESS OR PERFORMANCE.
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
* $/LicenseInfo$
*/
#ifndef LL_LLVERSIONSERVER_H
#define LL_LLVERSIONSERVER_H
-const S32 LL_VERSION_MAJOR = 1;
-const S32 LL_VERSION_MINOR = 19;
-const S32 LL_VERSION_PATCH = 1;
-const S32 LL_VERSION_BUILD = 81992;
+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 char * const LL_CHANNEL = "Second Life Server";
diff --git a/indra/llcommon/llversionviewer.h b/indra/llcommon/llversionviewer.h
index 02b956d86c..bd65ce8573 100644
--- a/indra/llcommon/llversionviewer.h
+++ b/indra/llcommon/llversionviewer.h
@@ -2,41 +2,36 @@
* @file llversionviewer.h
* @brief
*
- * $LicenseInfo:firstyear=2002&license=viewergpl$
- *
- * Copyright (c) 2002-2007, Linden Research, Inc.
- *
+ * $LicenseInfo:firstyear=2002&license=viewerlgpl$
* Second Life Viewer Source Code
- * The source code in this file ("Source Code") is provided by Linden Lab
- * to you under the terms of the GNU General Public License, version 2.0
- * ("GPL"), unless you have obtained a separate licensing agreement
- * ("Other License"), formally executed by you and Linden Lab. Terms of
- * the GPL can be found in doc/GPL-license.txt in this distribution, or
- * online at http://secondlife.com/developers/opensource/gplv2
+ * 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.
*
- * There are special exceptions to the terms and conditions of the GPL as
- * it is applied to this Source Code. View the full text of the exception
- * in the file doc/FLOSS-exception.txt in this software distribution, or
- * online at http://secondlife.com/developers/opensource/flossexception
+ * 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.
*
- * By copying, modifying or distributing this software, you acknowledge
- * that you have read and understood your obligations described above,
- * and agree to abide by those obligations.
+ * 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
*
- * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
- * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
- * COMPLETENESS OR PERFORMANCE.
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
* $/LicenseInfo$
*/
#ifndef LL_LLVERSIONVIEWER_H
#define LL_LLVERSIONVIEWER_H
-const S32 LL_VERSION_MAJOR = 1;
-const S32 LL_VERSION_MINOR = 19;
+const S32 LL_VERSION_MAJOR = 2;
+const S32 LL_VERSION_MINOR = 2;
const S32 LL_VERSION_PATCH = 1;
const S32 LL_VERSION_BUILD = 0;
-const char * const LL_CHANNEL = "Second Life Release";
+const char * const LL_CHANNEL = "Second Life Developer";
#endif
diff --git a/indra/llcommon/llworkerthread.cpp b/indra/llcommon/llworkerthread.cpp
index d828ed9468..3ac50832fd 100644
--- a/indra/llcommon/llworkerthread.cpp
+++ b/indra/llcommon/llworkerthread.cpp
@@ -1,30 +1,25 @@
/**
* @file llworkerthread.cpp
*
- * $LicenseInfo:firstyear=2004&license=viewergpl$
- *
- * Copyright (c) 2004-2007, Linden Research, Inc.
- *
+ * $LicenseInfo:firstyear=2004&license=viewerlgpl$
* Second Life Viewer Source Code
- * The source code in this file ("Source Code") is provided by Linden Lab
- * to you under the terms of the GNU General Public License, version 2.0
- * ("GPL"), unless you have obtained a separate licensing agreement
- * ("Other License"), formally executed by you and Linden Lab. Terms of
- * the GPL can be found in doc/GPL-license.txt in this distribution, or
- * online at http://secondlife.com/developers/opensource/gplv2
+ * Copyright (C) 2010, Linden Research, Inc.
*
- * There are special exceptions to the terms and conditions of the GPL as
- * it is applied to this Source Code. View the full text of the exception
- * in the file doc/FLOSS-exception.txt in this software distribution, or
- * online at http://secondlife.com/developers/opensource/flossexception
+ * 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.
*
- * By copying, modifying or distributing this software, you acknowledge
- * that you have read and understood your obligations described above,
- * and agree to abide by those obligations.
+ * 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.
*
- * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
- * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
- * COMPLETENESS OR PERFORMANCE.
+ * 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$
*/
@@ -40,11 +35,14 @@
// Run on MAIN thread
LLWorkerThread::LLWorkerThread(const std::string& name, bool threaded) :
- LLQueuedThread(name, threaded),
- mWorkerAPRPoolp(NULL)
+ LLQueuedThread(name, threaded)
{
- apr_pool_create(&mWorkerAPRPoolp, NULL);
- mDeleteMutex = new LLMutex(getAPRPool());
+ mDeleteMutex = new LLMutex(NULL);
+
+ if(!mLocalAPRFilePoolp)
+ {
+ mLocalAPRFilePoolp = new LLVolatileAPRPool() ;
+ }
}
LLWorkerThread::~LLWorkerThread()
@@ -61,6 +59,27 @@ LLWorkerThread::~LLWorkerThread()
// ~LLQueuedThread() will be called here
}
+//called only in destructor.
+void LLWorkerThread::clearDeleteList()
+{
+ // Delete any workers in the delete queue (should be safe - had better be!)
+ if (!mDeleteList.empty())
+ {
+ llwarns << "Worker Thread: " << mName << " destroyed with " << mDeleteList.size()
+ << " entries in delete list." << llendl;
+
+ mDeleteMutex->lock();
+ for (delete_list_t::iterator iter = mDeleteList.begin(); iter != mDeleteList.end(); ++iter)
+ {
+ (*iter)->mRequestHandle = LLWorkerThread::nullHandle();
+ (*iter)->clearFlags(LLWorkerClass::WCF_HAVE_WORK);
+ delete *iter ;
+ }
+ mDeleteList.clear() ;
+ mDeleteMutex->unlock() ;
+ }
+}
+
// virtual
S32 LLWorkerThread::update(U32 max_time_ms)
{
@@ -107,7 +126,7 @@ S32 LLWorkerThread::update(U32 max_time_ms)
}
delete *iter;
}
- // delete and aborted entries mean there's still work to do
+ // delete and aborted entries mean there's still work to do
res += delete_list.size() + abort_list.size();
return res;
}
@@ -184,7 +203,8 @@ LLWorkerClass::LLWorkerClass(LLWorkerThread* workerthread, const std::string& na
: mWorkerThread(workerthread),
mWorkerClassName(name),
mRequestHandle(LLWorkerThread::nullHandle()),
- mMutex(workerthread->getWorkerAPRPool()),
+ mRequestPriority(LLWorkerThread::PRIORITY_NORMAL),
+ mMutex(NULL),
mWorkFlags(0)
{
if (!mWorkerThread)
@@ -197,6 +217,7 @@ LLWorkerClass::~LLWorkerClass()
{
llassert_always(!(mWorkFlags & WCF_WORKING));
llassert_always(mWorkFlags & WCF_DELETE_REQUESTED);
+ llassert_always(!mMutex.isLocked());
if (mRequestHandle != LLWorkerThread::nullHandle())
{
LLWorkerThread::WorkRequest* workreq = (LLWorkerThread::WorkRequest*)mWorkerThread->getRequest(mRequestHandle);
@@ -314,7 +335,20 @@ bool LLWorkerClass::checkWork(bool aborting)
if (mRequestHandle != LLWorkerThread::nullHandle())
{
LLWorkerThread::WorkRequest* workreq = (LLWorkerThread::WorkRequest*)mWorkerThread->getRequest(mRequestHandle);
- llassert_always(workreq);
+ if(!workreq)
+ {
+ if(mWorkerThread->isQuitting() || mWorkerThread->isStopped()) //the mWorkerThread is not running
+ {
+ mRequestHandle = LLWorkerThread::nullHandle();
+ clearFlags(WCF_HAVE_WORK);
+ }
+ else
+ {
+ llassert_always(workreq);
+ }
+ return true ;
+ }
+
LLQueuedThread::status_t status = workreq->getStatus();
if (status == LLWorkerThread::STATUS_ABORTED)
{
@@ -364,7 +398,7 @@ void LLWorkerClass::scheduleDelete()
void LLWorkerClass::setPriority(U32 priority)
{
mMutex.lock();
- if (mRequestHandle != LLWorkerThread::nullHandle())
+ if (mRequestHandle != LLWorkerThread::nullHandle() && mRequestPriority != priority)
{
mRequestPriority = priority;
mWorkerThread->setPriority(mRequestHandle, priority);
diff --git a/indra/llcommon/llworkerthread.h b/indra/llcommon/llworkerthread.h
index be06bc2a58..9bff18303e 100644
--- a/indra/llcommon/llworkerthread.h
+++ b/indra/llcommon/llworkerthread.h
@@ -1,30 +1,25 @@
/**
* @file llworkerthread.h
*
- * $LicenseInfo:firstyear=2004&license=viewergpl$
- *
- * Copyright (c) 2004-2007, Linden Research, Inc.
- *
+ * $LicenseInfo:firstyear=2004&license=viewerlgpl$
* Second Life Viewer Source Code
- * The source code in this file ("Source Code") is provided by Linden Lab
- * to you under the terms of the GNU General Public License, version 2.0
- * ("GPL"), unless you have obtained a separate licensing agreement
- * ("Other License"), formally executed by you and Linden Lab. Terms of
- * the GPL can be found in doc/GPL-license.txt in this distribution, or
- * online at http://secondlife.com/developers/opensource/gplv2
+ * Copyright (C) 2010, Linden Research, Inc.
*
- * There are special exceptions to the terms and conditions of the GPL as
- * it is applied to this Source Code. View the full text of the exception
- * in the file doc/FLOSS-exception.txt in this software distribution, or
- * online at http://secondlife.com/developers/opensource/flossexception
+ * 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.
*
- * By copying, modifying or distributing this software, you acknowledge
- * that you have read and understood your obligations described above,
- * and agree to abide by those obligations.
+ * 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.
*
- * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
- * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
- * COMPLETENESS OR PERFORMANCE.
+ * 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$
*/
@@ -37,6 +32,7 @@
#include <set>
#include "llqueuedthread.h"
+#include "llapr.h"
#define USE_FRAME_CALLBACK_MANAGER 0
@@ -48,8 +44,9 @@ class LLWorkerClass;
// Note: ~LLWorkerThread is O(N) N=# of worker threads, assumed to be small
// It is assumed that LLWorkerThreads are rarely created/destroyed.
-class LLWorkerThread : public LLQueuedThread
+class LL_COMMON_API LLWorkerThread : public LLQueuedThread
{
+ friend class LLWorkerClass;
public:
class WorkRequest : public LLQueuedThread::QueuedRequest
{
@@ -77,24 +74,27 @@ public:
S32 mParam;
};
+protected:
+ void clearDeleteList() ;
+
private:
typedef std::list<LLWorkerClass*> delete_list_t;
delete_list_t mDeleteList;
LLMutex* mDeleteMutex;
- apr_pool_t* mWorkerAPRPoolp;
public:
LLWorkerThread(const std::string& name, bool threaded = true);
~LLWorkerThread();
- apr_pool_t* getWorkerAPRPool() { return mWorkerAPRPoolp; }
-
/*virtual*/ S32 update(U32 max_time_ms);
handle_t addWorkRequest(LLWorkerClass* workerclass, S32 param, U32 priority = PRIORITY_NORMAL);
- void deleteWorker(LLWorkerClass* workerclass); // schedule for deletion
S32 getNumDeletes() { return (S32)mDeleteList.size(); } // debug
+
+private:
+ void deleteWorker(LLWorkerClass* workerclass); // schedule for deletion
+
};
//============================================================================
@@ -114,10 +114,11 @@ public:
// Only one background task can be active at a time (per instance).
// i.e. don't call addWork() if haveWork() returns true
-class LLWorkerClass
+class LL_COMMON_API LLWorkerClass
{
friend class LLWorkerThread;
friend class LLWorkerThread::WorkRequest;
+
public:
typedef LLWorkerThread::handle_t handle_t;
enum FLAGS
@@ -178,6 +179,7 @@ private:
void setFlags(U32 flags) { mWorkFlags = mWorkFlags | flags; }
void clearFlags(U32 flags) { mWorkFlags = mWorkFlags & ~flags; }
U32 getFlags() { return mWorkFlags; }
+public:
bool getFlags(U32 flags) { return mWorkFlags & flags ? true : false; }
private:
diff --git a/indra/llcommon/metaclass.cpp b/indra/llcommon/metaclass.cpp
index aa62cef150..5e403511cf 100644
--- a/indra/llcommon/metaclass.cpp
+++ b/indra/llcommon/metaclass.cpp
@@ -4,30 +4,25 @@
* @date 2006-05-15
* @brief Implementation of LLMetaClass
*
- * $LicenseInfo:firstyear=2006&license=viewergpl$
- *
- * Copyright (c) 2006-2007, Linden Research, Inc.
- *
+ * $LicenseInfo:firstyear=2006&license=viewerlgpl$
* Second Life Viewer Source Code
- * The source code in this file ("Source Code") is provided by Linden Lab
- * to you under the terms of the GNU General Public License, version 2.0
- * ("GPL"), unless you have obtained a separate licensing agreement
- * ("Other License"), formally executed by you and Linden Lab. Terms of
- * the GPL can be found in doc/GPL-license.txt in this distribution, or
- * online at http://secondlife.com/developers/opensource/gplv2
+ * 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.
*
- * There are special exceptions to the terms and conditions of the GPL as
- * it is applied to this Source Code. View the full text of the exception
- * in the file doc/FLOSS-exception.txt in this software distribution, or
- * online at http://secondlife.com/developers/opensource/flossexception
+ * 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.
*
- * By copying, modifying or distributing this software, you acknowledge
- * that you have read and understood your obligations described above,
- * and agree to abide by those obligations.
+ * 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
*
- * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
- * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
- * COMPLETENESS OR PERFORMANCE.
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
* $/LicenseInfo$
*/
diff --git a/indra/llcommon/metaclass.h b/indra/llcommon/metaclass.h
index fa22107fe1..626757d58d 100644
--- a/indra/llcommon/metaclass.h
+++ b/indra/llcommon/metaclass.h
@@ -4,30 +4,25 @@
* @date 2006-05-15
* @brief Reflective meta information describing a class.
*
- * $LicenseInfo:firstyear=2006&license=viewergpl$
- *
- * Copyright (c) 2006-2007, Linden Research, Inc.
- *
+ * $LicenseInfo:firstyear=2006&license=viewerlgpl$
* Second Life Viewer Source Code
- * The source code in this file ("Source Code") is provided by Linden Lab
- * to you under the terms of the GNU General Public License, version 2.0
- * ("GPL"), unless you have obtained a separate licensing agreement
- * ("Other License"), formally executed by you and Linden Lab. Terms of
- * the GPL can be found in doc/GPL-license.txt in this distribution, or
- * online at http://secondlife.com/developers/opensource/gplv2
+ * 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.
*
- * There are special exceptions to the terms and conditions of the GPL as
- * it is applied to this Source Code. View the full text of the exception
- * in the file doc/FLOSS-exception.txt in this software distribution, or
- * online at http://secondlife.com/developers/opensource/flossexception
+ * 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.
*
- * By copying, modifying or distributing this software, you acknowledge
- * that you have read and understood your obligations described above,
- * and agree to abide by those obligations.
+ * 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
*
- * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
- * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
- * COMPLETENESS OR PERFORMANCE.
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
* $/LicenseInfo$
*/
@@ -42,7 +37,7 @@
class LLReflective;
class LLMetaProperty;
class LLMetaMethod;
-class LLMetaClass
+class LL_COMMON_API LLMetaClass
{
public:
diff --git a/indra/llcommon/metaclasst.h b/indra/llcommon/metaclasst.h
index d8d10bd0f3..b9a7ae219d 100644
--- a/indra/llcommon/metaclasst.h
+++ b/indra/llcommon/metaclasst.h
@@ -1,30 +1,25 @@
/**
* @file metaclasst.h
*
- * $LicenseInfo:firstyear=2006&license=viewergpl$
- *
- * Copyright (c) 2006-2007, Linden Research, Inc.
- *
+ * $LicenseInfo:firstyear=2006&license=viewerlgpl$
* Second Life Viewer Source Code
- * The source code in this file ("Source Code") is provided by Linden Lab
- * to you under the terms of the GNU General Public License, version 2.0
- * ("GPL"), unless you have obtained a separate licensing agreement
- * ("Other License"), formally executed by you and Linden Lab. Terms of
- * the GPL can be found in doc/GPL-license.txt in this distribution, or
- * online at http://secondlife.com/developers/opensource/gplv2
+ * 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.
*
- * There are special exceptions to the terms and conditions of the GPL as
- * it is applied to this Source Code. View the full text of the exception
- * in the file doc/FLOSS-exception.txt in this software distribution, or
- * online at http://secondlife.com/developers/opensource/flossexception
+ * 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.
*
- * By copying, modifying or distributing this software, you acknowledge
- * that you have read and understood your obligations described above,
- * and agree to abide by those obligations.
+ * 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
*
- * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
- * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
- * COMPLETENESS OR PERFORMANCE.
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
* $/LicenseInfo$
*/
diff --git a/indra/llcommon/metaproperty.cpp b/indra/llcommon/metaproperty.cpp
index fb4720ff06..98d850bf1e 100644
--- a/indra/llcommon/metaproperty.cpp
+++ b/indra/llcommon/metaproperty.cpp
@@ -4,30 +4,25 @@
* @date 2006-05-15
* @brief Implementation of LLMetaProperty.
*
- * $LicenseInfo:firstyear=2006&license=viewergpl$
- *
- * Copyright (c) 2006-2007, Linden Research, Inc.
- *
+ * $LicenseInfo:firstyear=2006&license=viewerlgpl$
* Second Life Viewer Source Code
- * The source code in this file ("Source Code") is provided by Linden Lab
- * to you under the terms of the GNU General Public License, version 2.0
- * ("GPL"), unless you have obtained a separate licensing agreement
- * ("Other License"), formally executed by you and Linden Lab. Terms of
- * the GPL can be found in doc/GPL-license.txt in this distribution, or
- * online at http://secondlife.com/developers/opensource/gplv2
+ * 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.
*
- * There are special exceptions to the terms and conditions of the GPL as
- * it is applied to this Source Code. View the full text of the exception
- * in the file doc/FLOSS-exception.txt in this software distribution, or
- * online at http://secondlife.com/developers/opensource/flossexception
+ * 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.
*
- * By copying, modifying or distributing this software, you acknowledge
- * that you have read and understood your obligations described above,
- * and agree to abide by those obligations.
+ * 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
*
- * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
- * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
- * COMPLETENESS OR PERFORMANCE.
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
* $/LicenseInfo$
*/
diff --git a/indra/llcommon/metaproperty.h b/indra/llcommon/metaproperty.h
index 9664e99fba..bd5bb1a30f 100644
--- a/indra/llcommon/metaproperty.h
+++ b/indra/llcommon/metaproperty.h
@@ -4,30 +4,25 @@
* @date 2006-05-15
* @brief Reflective meta information describing a property of a class.
*
- * $LicenseInfo:firstyear=2006&license=viewergpl$
- *
- * Copyright (c) 2006-2007, Linden Research, Inc.
- *
+ * $LicenseInfo:firstyear=2006&license=viewerlgpl$
* Second Life Viewer Source Code
- * The source code in this file ("Source Code") is provided by Linden Lab
- * to you under the terms of the GNU General Public License, version 2.0
- * ("GPL"), unless you have obtained a separate licensing agreement
- * ("Other License"), formally executed by you and Linden Lab. Terms of
- * the GPL can be found in doc/GPL-license.txt in this distribution, or
- * online at http://secondlife.com/developers/opensource/gplv2
+ * 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.
*
- * There are special exceptions to the terms and conditions of the GPL as
- * it is applied to this Source Code. View the full text of the exception
- * in the file doc/FLOSS-exception.txt in this software distribution, or
- * online at http://secondlife.com/developers/opensource/flossexception
+ * 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.
*
- * By copying, modifying or distributing this software, you acknowledge
- * that you have read and understood your obligations described above,
- * and agree to abide by those obligations.
+ * 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
*
- * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
- * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
- * COMPLETENESS OR PERFORMANCE.
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
* $/LicenseInfo$
*/
@@ -40,7 +35,7 @@
class LLMetaClass;
class LLReflective;
-class LLMetaProperty
+class LL_COMMON_API LLMetaProperty
{
public:
LLMetaProperty(const std::string& name, const LLMetaClass& object_class);
diff --git a/indra/llcommon/metapropertyt.h b/indra/llcommon/metapropertyt.h
index 488a60c22f..7a36c161da 100644
--- a/indra/llcommon/metapropertyt.h
+++ b/indra/llcommon/metapropertyt.h
@@ -1,30 +1,25 @@
/**
* @file metapropertyt.h
*
- * $LicenseInfo:firstyear=2006&license=viewergpl$
- *
- * Copyright (c) 2006-2007, Linden Research, Inc.
- *
+ * $LicenseInfo:firstyear=2006&license=viewerlgpl$
* Second Life Viewer Source Code
- * The source code in this file ("Source Code") is provided by Linden Lab
- * to you under the terms of the GNU General Public License, version 2.0
- * ("GPL"), unless you have obtained a separate licensing agreement
- * ("Other License"), formally executed by you and Linden Lab. Terms of
- * the GPL can be found in doc/GPL-license.txt in this distribution, or
- * online at http://secondlife.com/developers/opensource/gplv2
+ * Copyright (C) 2010, Linden Research, Inc.
*
- * There are special exceptions to the terms and conditions of the GPL as
- * it is applied to this Source Code. View the full text of the exception
- * in the file doc/FLOSS-exception.txt in this software distribution, or
- * online at http://secondlife.com/developers/opensource/flossexception
+ * 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.
*
- * By copying, modifying or distributing this software, you acknowledge
- * that you have read and understood your obligations described above,
- * and agree to abide by those obligations.
+ * 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.
*
- * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
- * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
- * COMPLETENESS OR PERFORMANCE.
+ * 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$
*/
@@ -86,14 +81,14 @@ inline const LLReflective* LLMetaPropertyT<std::string>::get(const LLReflective*
}
template <>
-inline const LLReflective* LLMetaPropertyT<LLString>::get(const LLReflective* object) const
+inline const LLReflective* LLMetaPropertyT<LLUUID>::get(const LLReflective* object) const
{
checkObjectClass(object);
return NULL;
}
template <>
-inline const LLReflective* LLMetaPropertyT<LLUUID>::get(const LLReflective* object) const
+inline const LLReflective* LLMetaPropertyT<bool>::get(const LLReflective* object) const
{
checkObjectClass(object);
return NULL;
@@ -112,13 +107,13 @@ inline LLSD LLMetaPropertyT<std::string>::getLLSD(const LLReflective* object) co
}
template <>
-inline LLSD LLMetaPropertyT<LLString>::getLLSD(const LLReflective* object) const
+inline LLSD LLMetaPropertyT<LLUUID>::getLLSD(const LLReflective* object) const
{
return *(getProperty(object));
}
template <>
-inline LLSD LLMetaPropertyT<LLUUID>::getLLSD(const LLReflective* object) const
+inline LLSD LLMetaPropertyT<bool>::getLLSD(const LLReflective* object) const
{
return *(getProperty(object));
}
diff --git a/indra/llcommon/reflective.cpp b/indra/llcommon/reflective.cpp
index 942ed0eefa..2cc0e7e1f2 100644
--- a/indra/llcommon/reflective.cpp
+++ b/indra/llcommon/reflective.cpp
@@ -4,30 +4,25 @@
* @date 2006-05-15
* @brief Implementation of LLReflective.
*
- * $LicenseInfo:firstyear=2006&license=viewergpl$
- *
- * Copyright (c) 2006-2007, Linden Research, Inc.
- *
+ * $LicenseInfo:firstyear=2006&license=viewerlgpl$
* Second Life Viewer Source Code
- * The source code in this file ("Source Code") is provided by Linden Lab
- * to you under the terms of the GNU General Public License, version 2.0
- * ("GPL"), unless you have obtained a separate licensing agreement
- * ("Other License"), formally executed by you and Linden Lab. Terms of
- * the GPL can be found in doc/GPL-license.txt in this distribution, or
- * online at http://secondlife.com/developers/opensource/gplv2
+ * 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.
*
- * There are special exceptions to the terms and conditions of the GPL as
- * it is applied to this Source Code. View the full text of the exception
- * in the file doc/FLOSS-exception.txt in this software distribution, or
- * online at http://secondlife.com/developers/opensource/flossexception
+ * 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.
*
- * By copying, modifying or distributing this software, you acknowledge
- * that you have read and understood your obligations described above,
- * and agree to abide by those obligations.
+ * 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
*
- * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
- * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
- * COMPLETENESS OR PERFORMANCE.
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
* $/LicenseInfo$
*/
diff --git a/indra/llcommon/reflective.h b/indra/llcommon/reflective.h
index 6ed2b43fb0..da5c5a2630 100644
--- a/indra/llcommon/reflective.h
+++ b/indra/llcommon/reflective.h
@@ -4,30 +4,25 @@
* @date 2006-05-15
* @brief Interface that must be implemented by all reflective classes.
*
- * $LicenseInfo:firstyear=2006&license=viewergpl$
- *
- * Copyright (c) 2006-2007, Linden Research, Inc.
- *
+ * $LicenseInfo:firstyear=2006&license=viewerlgpl$
* Second Life Viewer Source Code
- * The source code in this file ("Source Code") is provided by Linden Lab
- * to you under the terms of the GNU General Public License, version 2.0
- * ("GPL"), unless you have obtained a separate licensing agreement
- * ("Other License"), formally executed by you and Linden Lab. Terms of
- * the GPL can be found in doc/GPL-license.txt in this distribution, or
- * online at http://secondlife.com/developers/opensource/gplv2
+ * 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.
*
- * There are special exceptions to the terms and conditions of the GPL as
- * it is applied to this Source Code. View the full text of the exception
- * in the file doc/FLOSS-exception.txt in this software distribution, or
- * online at http://secondlife.com/developers/opensource/flossexception
+ * 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.
*
- * By copying, modifying or distributing this software, you acknowledge
- * that you have read and understood your obligations described above,
- * and agree to abide by those obligations.
+ * 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
*
- * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
- * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
- * COMPLETENESS OR PERFORMANCE.
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
* $/LicenseInfo$
*/
@@ -35,7 +30,7 @@
#define LL_REFLECTIVE_H
class LLMetaClass;
-class LLReflective
+class LL_COMMON_API LLReflective
{
public:
LLReflective();
diff --git a/indra/llcommon/reflectivet.h b/indra/llcommon/reflectivet.h
index 85c7206da3..958921f23e 100644
--- a/indra/llcommon/reflectivet.h
+++ b/indra/llcommon/reflectivet.h
@@ -1,30 +1,25 @@
/**
* @file reflectivet.h
*
- * $LicenseInfo:firstyear=2006&license=viewergpl$
- *
- * Copyright (c) 2006-2007, Linden Research, Inc.
- *
+ * $LicenseInfo:firstyear=2006&license=viewerlgpl$
* Second Life Viewer Source Code
- * The source code in this file ("Source Code") is provided by Linden Lab
- * to you under the terms of the GNU General Public License, version 2.0
- * ("GPL"), unless you have obtained a separate licensing agreement
- * ("Other License"), formally executed by you and Linden Lab. Terms of
- * the GPL can be found in doc/GPL-license.txt in this distribution, or
- * online at http://secondlife.com/developers/opensource/gplv2
+ * 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.
*
- * There are special exceptions to the terms and conditions of the GPL as
- * it is applied to this Source Code. View the full text of the exception
- * in the file doc/FLOSS-exception.txt in this software distribution, or
- * online at http://secondlife.com/developers/opensource/flossexception
+ * 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.
*
- * By copying, modifying or distributing this software, you acknowledge
- * that you have read and understood your obligations described above,
- * and agree to abide by those obligations.
+ * 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
*
- * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
- * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
- * COMPLETENESS OR PERFORMANCE.
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
* $/LicenseInfo$
*/
diff --git a/indra/llcommon/roles_constants.h b/indra/llcommon/roles_constants.h
index 23ebcf34d6..effd15ea72 100644
--- a/indra/llcommon/roles_constants.h
+++ b/indra/llcommon/roles_constants.h
@@ -2,30 +2,25 @@
* @file roles_constants.h
* @brief General Roles Constants
*
- * $LicenseInfo:firstyear=2006&license=viewergpl$
- *
- * Copyright (c) 2006-2007, Linden Research, Inc.
- *
+ * $LicenseInfo:firstyear=2006&license=viewerlgpl$
* Second Life Viewer Source Code
- * The source code in this file ("Source Code") is provided by Linden Lab
- * to you under the terms of the GNU General Public License, version 2.0
- * ("GPL"), unless you have obtained a separate licensing agreement
- * ("Other License"), formally executed by you and Linden Lab. Terms of
- * the GPL can be found in doc/GPL-license.txt in this distribution, or
- * online at http://secondlife.com/developers/opensource/gplv2
+ * Copyright (C) 2010, Linden Research, Inc.
*
- * There are special exceptions to the terms and conditions of the GPL as
- * it is applied to this Source Code. View the full text of the exception
- * in the file doc/FLOSS-exception.txt in this software distribution, or
- * online at http://secondlife.com/developers/opensource/flossexception
+ * 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.
*
- * By copying, modifying or distributing this software, you acknowledge
- * that you have read and understood your obligations described above,
- * and agree to abide by those obligations.
+ * 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.
*
- * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
- * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
- * COMPLETENESS OR PERFORMANCE.
+ * 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$
*/
@@ -57,7 +52,6 @@ enum LLRoleChangeType
//
// KNOWN HOLES: use these for any single bit powers you need
-// bit 0x1 << 41
// bit 0x1 << 46
// bit 0x1 << 49 and above
@@ -108,6 +102,8 @@ const U64 GP_LAND_ALLOW_FLY = 0x1 << 24; // Bypass Fly Restriction
const U64 GP_LAND_ALLOW_CREATE = 0x1 << 25; // Bypass Create/Edit Objects Restriction
const U64 GP_LAND_ALLOW_LANDMARK = 0x1 << 26; // Bypass Landmark Restriction
const U64 GP_LAND_ALLOW_SET_HOME = 0x1 << 28; // Bypass Set Home Point Restriction
+const U64 GP_LAND_ALLOW_HOLD_EVENT = 0x1LL << 41; // Allowed to hold events on group-owned land
+
// Parcel Access
const U64 GP_LAND_MANAGE_ALLOWED = 0x1 << 29; // Manage Allowed List
@@ -140,24 +136,30 @@ const U64 GP_NOTICES_SEND = 0x1LL << 42; // Send Notices
const U64 GP_NOTICES_RECEIVE = 0x1LL << 43; // Receive Notices and View Notice History
// Proposals
+// TODO: _DEPRECATED suffix as part of vote removal - DEV-24856:
const U64 GP_PROPOSAL_START = 0x1LL << 44; // Start Proposal
+// TODO: _DEPRECATED suffix as part of vote removal - DEV-24856:
const U64 GP_PROPOSAL_VOTE = 0x1LL << 45; // Vote on Proposal
+// Group chat moderation related
+const U64 GP_SESSION_JOIN = 0x1LL << 16; //can join session
+const U64 GP_SESSION_VOICE = 0x1LL << 27; //can hear/talk
+const U64 GP_SESSION_MODERATOR = 0x1LL << 37; //can mute people's session
+
const U64 GP_DEFAULT_MEMBER = GP_ACCOUNTING_ACCOUNTABLE
| GP_LAND_ALLOW_SET_HOME
| GP_NOTICES_RECEIVE
- | GP_PROPOSAL_START
- | GP_PROPOSAL_VOTE
+ | GP_SESSION_JOIN
+ | GP_SESSION_VOICE
;
-const U64 GP_DEFAULT_OFFICER = GP_ACCOUNTING_ACCOUNTABLE
+const U64 GP_DEFAULT_OFFICER = GP_DEFAULT_MEMBER // Superset of GP_DEFAULT_MEMBER
| GP_GROUP_CHANGE_IDENTITY
| GP_LAND_ADMIN
| GP_LAND_ALLOW_EDIT_LAND
| GP_LAND_ALLOW_FLY
| GP_LAND_ALLOW_CREATE
| GP_LAND_ALLOW_LANDMARK
- | GP_LAND_ALLOW_SET_HOME
| GP_LAND_CHANGE_IDENTITY
| GP_LAND_CHANGE_MEDIA
| GP_LAND_DEED
@@ -179,14 +181,12 @@ const U64 GP_DEFAULT_OFFICER = GP_ACCOUNTING_ACCOUNTABLE
| GP_MEMBER_INVITE
| GP_MEMBER_OPTIONS
| GP_MEMBER_VISIBLE_IN_DIR
- | GP_NOTICES_RECEIVE
| GP_NOTICES_SEND
| GP_OBJECT_DEED
| GP_OBJECT_MANIPULATE
| GP_OBJECT_SET_SALE
- | GP_PROPOSAL_START
- | GP_PROPOSAL_VOTE
| GP_ROLE_ASSIGN_MEMBER_LIMITED
| GP_ROLE_PROPERTIES
+ | GP_SESSION_MODERATOR
;
#endif
diff --git a/indra/llcommon/stdenums.h b/indra/llcommon/stdenums.h
index 92de405195..9f86de124e 100644
--- a/indra/llcommon/stdenums.h
+++ b/indra/llcommon/stdenums.h
@@ -2,30 +2,25 @@
* @file stdenums.h
* @brief Enumerations for indra.
*
- * $LicenseInfo:firstyear=2002&license=viewergpl$
- *
- * Copyright (c) 2002-2007, Linden Research, Inc.
- *
+ * $LicenseInfo:firstyear=2002&license=viewerlgpl$
* Second Life Viewer Source Code
- * The source code in this file ("Source Code") is provided by Linden Lab
- * to you under the terms of the GNU General Public License, version 2.0
- * ("GPL"), unless you have obtained a separate licensing agreement
- * ("Other License"), formally executed by you and Linden Lab. Terms of
- * the GPL can be found in doc/GPL-license.txt in this distribution, or
- * online at http://secondlife.com/developers/opensource/gplv2
+ * 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.
*
- * There are special exceptions to the terms and conditions of the GPL as
- * it is applied to this Source Code. View the full text of the exception
- * in the file doc/FLOSS-exception.txt in this software distribution, or
- * online at http://secondlife.com/developers/opensource/flossexception
+ * 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.
*
- * By copying, modifying or distributing this software, you acknowledge
- * that you have read and understood your obligations described above,
- * and agree to abide by those obligations.
+ * 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
*
- * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
- * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
- * COMPLETENESS OR PERFORMANCE.
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
* $/LicenseInfo$
*/
@@ -53,7 +48,8 @@ enum EDragAndDropType
DAD_BODYPART = 11,
DAD_ANIMATION = 12,
DAD_GESTURE = 13,
- DAD_COUNT = 14, // number of types in this enum
+ DAD_LINK = 14,
+ DAD_COUNT = 15, // number of types in this enum
};
// Reasons for drags to be denied.
@@ -117,8 +113,8 @@ enum EObjectPropertiesExtraID
enum EAddPosition
{
ADD_TOP,
- ADD_SORTED,
- ADD_BOTTOM
+ ADD_BOTTOM,
+ ADD_DEFAULT
};
enum LLGroupChange
diff --git a/indra/llcommon/stdtypes.h b/indra/llcommon/stdtypes.h
index f8982d79f8..bf3f3f9ee8 100644
--- a/indra/llcommon/stdtypes.h
+++ b/indra/llcommon/stdtypes.h
@@ -2,35 +2,33 @@
* @file stdtypes.h
* @brief Basic type declarations for cross platform compatibility.
*
- * $LicenseInfo:firstyear=2000&license=viewergpl$
- *
- * Copyright (c) 2000-2007, Linden Research, Inc.
- *
+ * $LicenseInfo:firstyear=2000&license=viewerlgpl$
* Second Life Viewer Source Code
- * The source code in this file ("Source Code") is provided by Linden Lab
- * to you under the terms of the GNU General Public License, version 2.0
- * ("GPL"), unless you have obtained a separate licensing agreement
- * ("Other License"), formally executed by you and Linden Lab. Terms of
- * the GPL can be found in doc/GPL-license.txt in this distribution, or
- * online at http://secondlife.com/developers/opensource/gplv2
+ * 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.
*
- * There are special exceptions to the terms and conditions of the GPL as
- * it is applied to this Source Code. View the full text of the exception
- * in the file doc/FLOSS-exception.txt in this software distribution, or
- * online at http://secondlife.com/developers/opensource/flossexception
+ * 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.
*
- * By copying, modifying or distributing this software, you acknowledge
- * that you have read and understood your obligations described above,
- * and agree to abide by those obligations.
+ * 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
*
- * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
- * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
- * COMPLETENESS OR PERFORMANCE.
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
* $/LicenseInfo$
*/
#ifndef LL_STDTYPES_H
#define LL_STDTYPES_H
+#include <cfloat>
+#include <climits>
+
typedef signed char S8;
typedef unsigned char U8;
typedef signed short S16;
@@ -102,6 +100,8 @@ typedef U32 TPACKETID;
typedef U8 LLPCode;
+#define LL_ARRAY_SIZE( _kArray ) ( sizeof( (_kArray) ) / sizeof( _kArray[0] ) )
+
#if LL_LINUX && __GNUC__ <= 2
typedef int intptr_t;
#endif
diff --git a/indra/llcommon/string_table.h b/indra/llcommon/string_table.h
index f057007086..fe6416fb50 100644
--- a/indra/llcommon/string_table.h
+++ b/indra/llcommon/string_table.h
@@ -2,30 +2,25 @@
* @file string_table.h
* @brief Legacy wrapper header.
*
- * $LicenseInfo:firstyear=2000&license=viewergpl$
- *
- * Copyright (c) 2000-2007, Linden Research, Inc.
- *
+ * $LicenseInfo:firstyear=2000&license=viewerlgpl$
* Second Life Viewer Source Code
- * The source code in this file ("Source Code") is provided by Linden Lab
- * to you under the terms of the GNU General Public License, version 2.0
- * ("GPL"), unless you have obtained a separate licensing agreement
- * ("Other License"), formally executed by you and Linden Lab. Terms of
- * the GPL can be found in doc/GPL-license.txt in this distribution, or
- * online at http://secondlife.com/developers/opensource/gplv2
+ * 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.
*
- * There are special exceptions to the terms and conditions of the GPL as
- * it is applied to this Source Code. View the full text of the exception
- * in the file doc/FLOSS-exception.txt in this software distribution, or
- * online at http://secondlife.com/developers/opensource/flossexception
+ * 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.
*
- * By copying, modifying or distributing this software, you acknowledge
- * that you have read and understood your obligations described above,
- * and agree to abide by those obligations.
+ * 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
*
- * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
- * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
- * COMPLETENESS OR PERFORMANCE.
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
* $/LicenseInfo$
*/
#include "llstringtable.h"
diff --git a/indra/llcommon/stringize.h b/indra/llcommon/stringize.h
new file mode 100644
index 0000000000..72f2e58ce1
--- /dev/null
+++ b/indra/llcommon/stringize.h
@@ -0,0 +1,107 @@
+/**
+ * @file stringize.h
+ * @author Nat Goodspeed
+ * @date 2008-12-17
+ * @brief stringize(item) template function and STRINGIZE(expression) macro
+ *
+ * $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_STRINGIZE_H)
+#define LL_STRINGIZE_H
+
+#include <sstream>
+#include <boost/lambda/lambda.hpp>
+
+/**
+ * stringize(item) encapsulates an idiom we use constantly, using
+ * operator<<(std::ostringstream&, TYPE) followed by std::ostringstream::str()
+ * to render a string expressing some item.
+ */
+template <typename T>
+std::string stringize(const T& item)
+{
+ std::ostringstream out;
+ out << item;
+ return out.str();
+}
+
+/**
+ * stringize_f(functor)
+ */
+template <typename Functor>
+std::string stringize_f(Functor const & f)
+{
+ std::ostringstream out;
+ f(out);
+ return out.str();
+}
+
+/**
+ * STRINGIZE(item1 << item2 << item3 ...) effectively expands to the
+ * following:
+ * @code
+ * std::ostringstream out;
+ * out << item1 << item2 << item3 ... ;
+ * return out.str();
+ * @endcode
+ */
+#define STRINGIZE(EXPRESSION) (stringize_f(boost::lambda::_1 << EXPRESSION))
+
+
+/**
+ * destringize(str)
+ * defined for symmetry with stringize
+ * *NOTE - this has distinct behavior from boost::lexical_cast<T> regarding
+ * leading/trailing whitespace and handling of bad_lexical_cast exceptions
+ */
+template <typename T>
+T destringize(std::string const & str)
+{
+ T val;
+ std::istringstream in(str);
+ in >> val;
+ return val;
+}
+
+/**
+ * destringize_f(str, functor)
+ */
+template <typename Functor>
+void destringize_f(std::string const & str, Functor const & f)
+{
+ std::istringstream in(str);
+ f(in);
+}
+
+/**
+ * DESTRINGIZE(str, item1 >> item2 >> item3 ...) effectively expands to the
+ * following:
+ * @code
+ * std::istringstream in(str);
+ * in >> item1 >> item2 >> item3 ... ;
+ * @endcode
+ */
+#define DESTRINGIZE(STR, EXPRESSION) (destringize_f((STR), (boost::lambda::_1 >> EXPRESSION)))
+
+
+#endif /* ! defined(LL_STRINGIZE_H) */
diff --git a/indra/llcommon/tests/bitpack_test.cpp b/indra/llcommon/tests/bitpack_test.cpp
new file mode 100644
index 0000000000..05289881d0
--- /dev/null
+++ b/indra/llcommon/tests/bitpack_test.cpp
@@ -0,0 +1,119 @@
+/**
+ * @file bitpack_test.cpp
+ * @author Adroit
+ * @date 2007-02
+ * @brief llstreamtools test cases.
+ *
+ * $LicenseInfo:firstyear=2007&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$
+ */
+
+#include "linden_common.h"
+
+#include "../bitpack.h"
+
+#include "../test/lltut.h"
+
+
+namespace tut
+{
+ struct bit_pack
+ {
+ };
+ typedef test_group<bit_pack> bit_pack_t;
+ typedef bit_pack_t::object bit_pack_object_t;
+ tut::bit_pack_t tut_bit_pack("LLBitPack");
+
+ // pack -> unpack
+ template<> template<>
+ void bit_pack_object_t::test<1>()
+ {
+ U8 packbuffer[255];
+ U8 unpackbuffer[255];
+ int pack_bufsize = 0;
+ int unpack_bufsize = 0;
+
+ LLBitPack bitpack(packbuffer, 255);
+
+ char str[] = "SecondLife is a 3D virtual world";
+ int len = sizeof(str);
+ pack_bufsize = bitpack.bitPack((U8*) str, len*8);
+ pack_bufsize = bitpack.flushBitPack();
+
+ LLBitPack bitunpack(packbuffer, pack_bufsize*8);
+ unpack_bufsize = bitunpack.bitUnpack(unpackbuffer, len*8);
+ ensure("bitPack: unpack size should be same as string size prior to pack", len == unpack_bufsize);
+ ensure_memory_matches("str->bitPack->bitUnpack should be equal to string", str, len, unpackbuffer, unpack_bufsize);
+ }
+
+ // pack large, unpack in individual bytes
+ template<> template<>
+ void bit_pack_object_t::test<2>()
+ {
+ U8 packbuffer[255];
+ U8 unpackbuffer[255];
+ int pack_bufsize = 0;
+ int unpack_bufsize = 0;
+
+ LLBitPack bitpack(packbuffer, 255);
+
+ char str[] = "SecondLife";
+ int len = sizeof(str);
+ pack_bufsize = bitpack.bitPack((U8*) str, len*8);
+ pack_bufsize = bitpack.flushBitPack();
+
+ LLBitPack bitunpack(packbuffer, pack_bufsize*8);
+ unpack_bufsize = bitunpack.bitUnpack(&unpackbuffer[0], 8);
+ ensure("bitPack: individual unpack: 0", unpackbuffer[0] == (U8) str[0]);
+ unpack_bufsize = bitunpack.bitUnpack(&unpackbuffer[0], 8);
+ ensure("bitPack: individual unpack: 1", unpackbuffer[0] == (U8) str[1]);
+ unpack_bufsize = bitunpack.bitUnpack(&unpackbuffer[0], 8);
+ ensure("bitPack: individual unpack: 2", unpackbuffer[0] == (U8) str[2]);
+ unpack_bufsize = bitunpack.bitUnpack(&unpackbuffer[0], 8);
+ ensure("bitPack: individual unpack: 3", unpackbuffer[0] == (U8) str[3]);
+ unpack_bufsize = bitunpack.bitUnpack(&unpackbuffer[0], 8);
+ ensure("bitPack: individual unpack: 4", unpackbuffer[0] == (U8) str[4]);
+ unpack_bufsize = bitunpack.bitUnpack(&unpackbuffer[0], 8);
+ ensure("bitPack: individual unpack: 5", unpackbuffer[0] == (U8) str[5]);
+ unpack_bufsize = bitunpack.bitUnpack(unpackbuffer, 8*4); // Life
+ ensure_memory_matches("bitPack: 4 bytes unpack:", unpackbuffer, 4, str+6, 4);
+ }
+
+ // U32 packing
+ template<> template<>
+ void bit_pack_object_t::test<3>()
+ {
+ U8 packbuffer[255];
+ int pack_bufsize = 0;
+
+ LLBitPack bitpack(packbuffer, 255);
+ U32 num = 0x41fab67a;
+ pack_bufsize = bitpack.bitPack((U8*)&num, 8*sizeof(U32));
+ pack_bufsize = bitpack.flushBitPack();
+
+ LLBitPack bitunpack(packbuffer, pack_bufsize*8);
+ U32 res = 0;
+ // since packing and unpacking is done on same machine in the unit test run,
+ // endianness should not matter
+ bitunpack.bitUnpack((U8*) &res, sizeof(res)*8);
+ ensure("U32->bitPack->bitUnpack->U32 should be equal", num == res);
+ }
+}
diff --git a/indra/llcommon/tests/commonmisc_test.cpp b/indra/llcommon/tests/commonmisc_test.cpp
new file mode 100644
index 0000000000..b115c153c1
--- /dev/null
+++ b/indra/llcommon/tests/commonmisc_test.cpp
@@ -0,0 +1,671 @@
+/**
+ * @file common.cpp
+ * @author Phoenix
+ * @date 2005-10-12
+ * @brief Common templates for test framework
+ *
+ * $LicenseInfo:firstyear=2005&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$
+ */
+
+/**
+ *
+ * THOROUGH_DESCRIPTION of common.cpp
+ *
+ */
+
+#include <algorithm>
+#include <iomanip>
+#include <iterator>
+
+#include "linden_common.h"
+
+#include "../llmemorystream.h"
+#include "../llsd.h"
+#include "../llsdserialize.h"
+#include "../u64.h"
+#include "../llhash.h"
+
+#include "../test/lltut.h"
+
+
+#if LL_WINDOWS
+// disable overflow warnings
+#pragma warning(disable: 4307)
+#endif
+
+namespace tut
+{
+ struct sd_data
+ {
+ };
+ typedef test_group<sd_data> sd_test;
+ typedef sd_test::object sd_object;
+ tut::sd_test sd("LLSD");
+
+ template<> template<>
+ void sd_object::test<1>()
+ {
+ std::ostringstream resp;
+ resp << "{'connect':true, 'position':[r128,r128,r128], 'look_at':[r0,r1,r0], 'agent_access':'M', 'region_x':i8192, 'region_y':i8192}";
+ std::string str = resp.str();
+ LLMemoryStream mstr((U8*)str.c_str(), str.size());
+ LLSD response;
+ S32 count = LLSDSerialize::fromNotation(response, mstr, str.size());
+ ensure("stream parsed", response.isDefined());
+ ensure_equals("stream parse count", count, 13);
+ ensure_equals("sd type", response.type(), LLSD::TypeMap);
+ ensure_equals("map element count", response.size(), 6);
+ ensure_equals("value connect", response["connect"].asBoolean(), true);
+ ensure_equals("value region_x", response["region_x"].asInteger(),8192);
+ ensure_equals("value region_y", response["region_y"].asInteger(),8192);
+ }
+
+ template<> template<>
+ void sd_object::test<2>()
+ {
+ const std::string decoded("random");
+ //const std::string encoded("cmFuZG9t\n");
+ const std::string streamed("b(6)\"random\"");
+ typedef std::vector<U8> buf_t;
+ buf_t buf;
+ std::copy(
+ decoded.begin(),
+ decoded.end(),
+ std::back_insert_iterator<buf_t>(buf));
+ LLSD sd;
+ sd = buf;
+ std::stringstream str;
+ S32 count = LLSDSerialize::toNotation(sd, str);
+ ensure_equals("output count", count, 1);
+ std::string actual(str.str());
+ ensure_equals("formatted binary encoding", actual, streamed);
+ sd.clear();
+ LLSDSerialize::fromNotation(sd, str, str.str().size());
+ std::vector<U8> after;
+ after = sd.asBinary();
+ ensure_equals("binary decoded size", after.size(), decoded.size());
+ ensure("binary decoding", (0 == memcmp(
+ &after[0],
+ decoded.c_str(),
+ decoded.size())));
+ }
+
+ template<> template<>
+ void sd_object::test<3>()
+ {
+ for(S32 i = 0; i < 100; ++i)
+ {
+ // gen up a starting point
+ typedef std::vector<U8> buf_t;
+ buf_t source;
+ srand(i); /* Flawfinder: ignore */
+ S32 size = rand() % 1000 + 10;
+ std::generate_n(
+ std::back_insert_iterator<buf_t>(source),
+ size,
+ rand);
+ LLSD sd(source);
+ std::stringstream str;
+ S32 count = LLSDSerialize::toNotation(sd, str);
+ sd.clear();
+ ensure_equals("format count", count, 1);
+ LLSD sd2;
+ count = LLSDSerialize::fromNotation(sd2, str, str.str().size());
+ ensure_equals("parse count", count, 1);
+ buf_t dest = sd2.asBinary();
+ str.str("");
+ str << "binary encoding size " << i;
+ ensure_equals(str.str().c_str(), dest.size(), source.size());
+ str.str("");
+ str << "binary encoding " << i;
+ ensure(str.str().c_str(), (source == dest));
+ }
+ }
+
+ template<> template<>
+ void sd_object::test<4>()
+ {
+ std::ostringstream ostr;
+ ostr << "{'task_id':u1fd77b79-a8e7-25a5-9454-02a4d948ba1c}\n"
+ << "{\n\tname\tObject|\n}\n";
+ std::string expected = ostr.str();
+ std::stringstream serialized;
+ serialized << "'" << LLSDNotationFormatter::escapeString(expected)
+ << "'";
+ LLSD sd;
+ S32 count = LLSDSerialize::fromNotation(
+ sd,
+ serialized,
+ serialized.str().size());
+ ensure_equals("parse count", count, 1);
+ ensure_equals("String streaming", sd.asString(), expected);
+ }
+
+ template<> template<>
+ void sd_object::test<5>()
+ {
+ for(S32 i = 0; i < 100; ++i)
+ {
+ // gen up a starting point
+ typedef std::vector<U8> buf_t;
+ buf_t source;
+ srand(666 + i); /* Flawfinder: ignore */
+ S32 size = rand() % 1000 + 10;
+ std::generate_n(
+ std::back_insert_iterator<buf_t>(source),
+ size,
+ rand);
+ std::stringstream str;
+ str << "b(" << size << ")\"";
+ str.write((const char*)&source[0], size);
+ str << "\"";
+ LLSD sd;
+ S32 count = LLSDSerialize::fromNotation(sd, str, str.str().size());
+ ensure_equals("binary parse", count, 1);
+ buf_t actual = sd.asBinary();
+ ensure_equals("binary size", actual.size(), (size_t)size);
+ ensure("binary data", (0 == memcmp(&source[0], &actual[0], size)));
+ }
+ }
+
+ template<> template<>
+ void sd_object::test<6>()
+ {
+ std::string expected("'{\"task_id\":u1fd77b79-a8e7-25a5-9454-02a4d948ba1c}'\t\n\t\t");
+ std::stringstream str;
+ str << "s(" << expected.size() << ")'";
+ str.write(expected.c_str(), expected.size());
+ str << "'";
+ LLSD sd;
+ S32 count = LLSDSerialize::fromNotation(sd, str, str.str().size());
+ ensure_equals("parse count", count, 1);
+ std::string actual = sd.asString();
+ ensure_equals("string sizes", actual.size(), expected.size());
+ ensure_equals("string content", actual, expected);
+ }
+
+ template<> template<>
+ void sd_object::test<7>()
+ {
+ std::string msg("come on in");
+ std::stringstream stream;
+ stream << "{'connect':1, 'message':'" << msg << "',"
+ << " 'position':[r45.65,r100.1,r25.5],"
+ << " 'look_at':[r0,r1,r0],"
+ << " 'agent_access':'PG'}";
+ LLSD sd;
+ S32 count = LLSDSerialize::fromNotation(
+ sd,
+ stream,
+ stream.str().size());
+ ensure_equals("parse count", count, 12);
+ ensure_equals("bool value", sd["connect"].asBoolean(), true);
+ ensure_equals("message value", sd["message"].asString(), msg);
+ ensure_equals("pos x", sd["position"][0].asReal(), 45.65);
+ ensure_equals("pos y", sd["position"][1].asReal(), 100.1);
+ ensure_equals("pos z", sd["position"][2].asReal(), 25.5);
+ ensure_equals("look x", sd["look_at"][0].asReal(), 0.0);
+ ensure_equals("look y", sd["look_at"][1].asReal(), 1.0);
+ ensure_equals("look z", sd["look_at"][2].asReal(), 0.0);
+ }
+
+ template<> template<>
+ void sd_object::test<8>()
+ {
+ std::stringstream resp;
+ resp << "{'label':'short string test', 'singlechar':'a', 'empty':'', 'endoftest':'end' }";
+ LLSD response;
+ S32 count = LLSDSerialize::fromNotation(
+ response,
+ resp,
+ resp.str().size());
+ ensure_equals("parse count", count, 5);
+ ensure_equals("sd type", response.type(), LLSD::TypeMap);
+ ensure_equals("map element count", response.size(), 4);
+ ensure_equals("singlechar", response["singlechar"].asString(), "a");
+ ensure_equals("empty", response["empty"].asString(), "");
+ }
+
+ template<> template<>
+ void sd_object::test<9>()
+ {
+ std::ostringstream resp;
+ resp << "{'label':'short binary test', 'singlebinary':b(1)\"A\", 'singlerawstring':s(1)\"A\", 'endoftest':'end' }";
+ std::string str = resp.str();
+ LLSD sd;
+ LLMemoryStream mstr((U8*)str.c_str(), str.size());
+ S32 count = LLSDSerialize::fromNotation(sd, mstr, str.size());
+ ensure_equals("parse count", count, 5);
+ ensure("sd created", sd.isDefined());
+ ensure_equals("sd type", sd.type(), LLSD::TypeMap);
+ ensure_equals("map element count", sd.size(), 4);
+ ensure_equals(
+ "label",
+ sd["label"].asString(),
+ "short binary test");
+ std::vector<U8> bin = sd["singlebinary"].asBinary();
+ std::vector<U8> expected;
+ expected.resize(1);
+ expected[0] = 'A';
+ ensure("single binary", (0 == memcmp(&bin[0], &expected[0], 1)));
+ ensure_equals(
+ "single string",
+ sd["singlerawstring"].asString(),
+ std::string("A"));
+ ensure_equals("end", sd["endoftest"].asString(), "end");
+ }
+
+ template<> template<>
+ void sd_object::test<10>()
+ {
+
+ std::string message("parcel '' is naughty.");
+ std::stringstream str;
+ str << "{'message':'" << LLSDNotationFormatter::escapeString(message)
+ << "'}";
+ std::string expected_str("{'message':'parcel \\'\\' is naughty.'}");
+ std::string actual_str = str.str();
+ ensure_equals("stream contents", actual_str, expected_str);
+ LLSD sd;
+ S32 count = LLSDSerialize::fromNotation(sd, str, actual_str.size());
+ ensure_equals("parse count", count, 2);
+ ensure("valid parse", sd.isDefined());
+ std::string actual = sd["message"].asString();
+ ensure_equals("message contents", actual, message);
+ }
+
+ template<> template<>
+ void sd_object::test<11>()
+ {
+ std::string expected("\"\"\"\"''''''\"");
+ std::stringstream str;
+ str << "'" << LLSDNotationFormatter::escapeString(expected) << "'";
+ LLSD sd;
+ S32 count = LLSDSerialize::fromNotation(sd, str, str.str().size());
+ ensure_equals("parse count", count, 1);
+ ensure_equals("string value", sd.asString(), expected);
+ }
+
+ template<> template<>
+ void sd_object::test<12>()
+ {
+ std::string expected("mytest\\");
+ std::stringstream str;
+ str << "'" << LLSDNotationFormatter::escapeString(expected) << "'";
+ LLSD sd;
+ S32 count = LLSDSerialize::fromNotation(sd, str, str.str().size());
+ ensure_equals("parse count", count, 1);
+ ensure_equals("string value", sd.asString(), expected);
+ }
+
+ template<> template<>
+ void sd_object::test<13>()
+ {
+ for(S32 i = 0; i < 1000; ++i)
+ {
+ // gen up a starting point
+ std::string expected;
+ srand(1337 + i); /* Flawfinder: ignore */
+ S32 size = rand() % 30 + 5;
+ std::generate_n(
+ std::back_insert_iterator<std::string>(expected),
+ size,
+ rand);
+ std::stringstream str;
+ str << "'" << LLSDNotationFormatter::escapeString(expected) << "'";
+ LLSD sd;
+ S32 count = LLSDSerialize::fromNotation(sd, str, expected.size());
+ ensure_equals("parse count", count, 1);
+ std::string actual = sd.asString();
+/*
+ if(actual != expected)
+ {
+ llwarns << "iteration " << i << llendl;
+ std::ostringstream e_str;
+ std::string::iterator iter = expected.begin();
+ std::string::iterator end = expected.end();
+ for(; iter != end; ++iter)
+ {
+ e_str << (S32)((U8)(*iter)) << " ";
+ }
+ e_str << std::endl;
+ llsd_serialize_string(e_str, expected);
+ llwarns << "expected size: " << expected.size() << llendl;
+ llwarns << "expected: " << e_str.str() << llendl;
+
+ std::ostringstream a_str;
+ iter = actual.begin();
+ end = actual.end();
+ for(; iter != end; ++iter)
+ {
+ a_str << (S32)((U8)(*iter)) << " ";
+ }
+ a_str << std::endl;
+ llsd_serialize_string(a_str, actual);
+ llwarns << "actual size: " << actual.size() << llendl;
+ llwarns << "actual: " << a_str.str() << llendl;
+ }
+*/
+ ensure_equals("string value", actual, expected);
+ }
+ }
+
+ template<> template<>
+ void sd_object::test<14>()
+ {
+//#if LL_WINDOWS && _MSC_VER >= 1400
+// skip_fail("Fails on VS2005 due to broken LLSDSerialize::fromNotation() parser.");
+//#endif
+ std::string param = "[{'version':i1},{'data':{'binary_bucket':b(0)\"\"},'from_id':u3c115e51-04f4-523c-9fa6-98aff1034730,'from_name':'Phoenix Linden','id':u004e45e5-5576-277a-fba7-859d6a4cb5c8,'message':'hey','offline':i0,'timestamp':i0,'to_id':u3c5f1bb4-5182-7546-6401-1d329b4ff2f8,'type':i0},{'agent_id':u3c115e51-04f4-523c-9fa6-98aff1034730,'god_level':i0,'limited_to_estate':i1}]";
+ std::istringstream istr;
+ istr.str(param);
+ LLSD param_sd;
+ LLSDSerialize::fromNotation(param_sd, istr, param.size());
+ ensure_equals("parsed type", param_sd.type(), LLSD::TypeArray);
+ LLSD version_sd = param_sd[0];
+ ensure_equals("version type", version_sd.type(), LLSD::TypeMap);
+ ensure("has version", version_sd.has("version"));
+ ensure_equals("version number", version_sd["version"].asInteger(), 1);
+ LLSD src_sd = param_sd[1];
+ ensure_equals("src type", src_sd.type(), LLSD::TypeMap);
+ LLSD dst_sd = param_sd[2];
+ ensure_equals("dst type", dst_sd.type(), LLSD::TypeMap);
+ }
+
+ template<> template<>
+ void sd_object::test<15>()
+ {
+ std::string val = "[{'failures':!,'successfuls':[u3c115e51-04f4-523c-9fa6-98aff1034730]}]";
+ std::istringstream istr;
+ istr.str(val);
+ LLSD sd;
+ LLSDSerialize::fromNotation(sd, istr, val.size());
+ ensure_equals("parsed type", sd.type(), LLSD::TypeArray);
+ ensure_equals("parsed size", sd.size(), 1);
+ LLSD failures = sd[0]["failures"];
+ ensure("no failures.", failures.isUndefined());
+ LLSD success = sd[0]["successfuls"];
+ ensure_equals("success type", success.type(), LLSD::TypeArray);
+ ensure_equals("success size", success.size(), 1);
+ ensure_equals("success instance type", success[0].type(), LLSD::TypeUUID);
+ }
+
+ template<> template<>
+ void sd_object::test<16>()
+ {
+ std::string val = "[f,t,0,1,{'foo':t,'bar':f}]";
+ std::istringstream istr;
+ istr.str(val);
+ LLSD sd;
+ LLSDSerialize::fromNotation(sd, istr, val.size());
+ ensure_equals("parsed type", sd.type(), LLSD::TypeArray);
+ ensure_equals("parsed size", sd.size(), 5);
+ ensure_equals("element 0 false", sd[0].asBoolean(), false);
+ ensure_equals("element 1 true", sd[1].asBoolean(), true);
+ ensure_equals("element 2 false", sd[2].asBoolean(), false);
+ ensure_equals("element 3 true", sd[3].asBoolean(), true);
+ LLSD map = sd[4];
+ ensure_equals("element 4 type", map.type(), LLSD::TypeMap);
+ ensure_equals("map foo type", map["foo"].type(), LLSD::TypeBoolean);
+ ensure_equals("map foo value", map["foo"].asBoolean(), true);
+ ensure_equals("map bar type", map["bar"].type(), LLSD::TypeBoolean);
+ ensure_equals("map bar value", map["bar"].asBoolean(), false);
+ }
+
+/*
+ template<> template<>
+ void sd_object::test<16>()
+ {
+ }
+*/
+}
+
+#if 0
+'{\'task_id\':u1fd77b79-a8e7-25a5-9454-02a4d948ba1c}\n{\n\tname\tObject|\n\tpermissions 0\n\t{\n\t\tbase_mask\t7fffffff\n\t\towner_mask\t7fffffff\n\t\tgroup_mask\t00000000\n\t\teveryone_mask\t00000000\n\t\tnext_owner_mask\t00082000\n\t\tcreator_id\t3c115e51-04f4-523c-9fa6-98aff1034730\n\t\towner_id\t3c115e51-04f4-523c-9fa6-98aff1034730\n\t\tlast_owner_id\t00000000-0000-0000-0000-000000000000\n\t\tgroup_id\t00000000-0000-0000-0000-000000000000\n\t}\n\tlocal_id\t10284\n\ttotal_crc\t35\n\ttype\t1\n\ttask_valid\t2\n\ttravel_access\t21\n\tdisplayopts\t2\n\tdisplaytype\tv\n\tpos\t0\t0\t0\n\toldpos\t0\t0\t0\n\trotation\t4.371139183945160766597837e-08\t1\t4.371139183945160766597837e-08\t0\n\tvelocity\t0\t0\t0\n\tangvel\t0\t0\t0\n\tscale\t0.2816932\t0.2816932\t0.2816932\n\tsit_offset\t0\t0\t0\n\tcamera_eye_offset\t0\t0\t0\n\tcamera_at_offset\t0\t0\t0\n\tsit_quat\t0\t0\t0\t1\n\tsit_hint\t0\n\tstate\t80\n\tmaterial\t3\n\tsoundid\t00000000-0000-0000-0000-000000000000\n\tsoundgain\t0\n\tsoundradius\t0\n\tsoundflags\t0\n\ttextcolor\t0 0 0 1\n\tselected\t0\n\tselector\t00000000-0000-0000-0000-000000000000\n\tusephysics\t0\n\trotate_x\t1\n\trotate_y\t1\n\trotate_z\t1\n\tphantom\t0\n\tremote_script_access_pin\t0\n\tvolume_detect\t0\n\tblock_grabs\t0\n\tdie_at_edge\t0\n\treturn_at_edge\t0\n\ttemporary\t0\n\tsandbox\t0\n\tsandboxhome\t0\t0\t0\n\tshape 0\n\t{\n\t\tpath 0\n\t\t{\n\t\t\tcurve\t16\n\t\t\tbegin\t0\n\t\t\tend\t1\n\t\t\tscale_x\t1\n\t\t\tscale_y\t1\n\t\t\tshear_x\t0\n\t\t\tshear_y\t0\n\t\t\ttwist\t0\n\t\t\ttwist_begin\t0\n\t\t\tradius_offset\t0\n\t\t\ttaper_x\t0\n\t\t\ttaper_y\t0\n\t\t\trevolutions\t1\n\t\t\tskew\t0\n\t\t}\n\t\tprofile 0\n\t\t{\n\t\t\tcurve\t1\n\t\t\tbegin\t0\n\t\t\tend\t1\n\t\t\thollow\t0\n\t\t}\n\t}\n\tfaces\t6\n\t{\n\t\timageid\t89556747-24cb-43ed-920b-47caed15465f\n\t\tcolors\t1 1 1 1\n\t\tscales\t0.56\n\t\tscalet\t0.56\n\t\toffsets\t0\n\t\toffsett\t0\n\t\timagerot\t0\n\t\tbump\t0\n\t\tfullbright\t0\n\t\tmedia_flags\t0\n\t}\n\t{\n\t\timageid\t89556747-24cb-43ed-920b-47caed15465f\n\t\tcolors\t1 1 1 1\n\t\tscales\t0.56\n\t\tscalet\t0.56\n\t\toffsets\t0\n\t\toffsett\t0\n\t\timagerot\t0\n\t\tbump\t0\n\t\tfullbright\t0\n\t\tmedia_flags\t0\n\t}\n\t{\n\t\timageid\t89556747-24cb-43ed-920b-47caed15465f\n\t\tcolors\t1 1 1 1\n\t\tscales\t0.56\n\t\tscalet\t0.56\n\t\toffsets\t0\n\t\toffsett\t0\n\t\timagerot\t0\n\t\tbump\t0\n\t\tfullbright\t0\n\t\tmedia_flags\t0\n\t}\n\t{\n\t\timageid\t89556747-24cb-43ed-920b-47caed15465f\n\t\tcolors\t1 1 1 1\n\t\tscales\t0.56\n\t\tscalet\t0.56\n\t\toffsets\t0\n\t\toffsett\t0\n\t\timagerot\t0\n\t\tbump\t0\n\t\tfullbright\t0\n\t\tmedia_flags\t0\n\t}\n\t{\n\t\timageid\t89556747-24cb-43ed-920b-47caed15465f\n\t\tcolors\t1 1 1 1\n\t\tscales\t0.56\n\t\tscalet\t0.56\n\t\toffsets\t0\n\t\toffsett\t0\n\t\timagerot\t0\n\t\tbump\t0\n\t\tfullbright\t0\n\t\tmedia_flags\t0\n\t}\n\t{\n\t\timageid\t89556747-24cb-43ed-920b-47caed15465f\n\t\tcolors\t1 1 1 1\n\t\tscales\t0.56\n\t\tscalet\t0.56\n\t\toffsets\t0\n\t\toffsett\t0\n\t\timagerot\t0\n\t\tbump\t0\n\t\tfullbright\t0\n\t\tmedia_flags\t0\n\t}\n\tps_next_crc\t1\n\tgpw_bias\t1\n\tip\t0\n\tcomplete\tTRUE\n\tdelay\t50000\n\tnextstart\t1132625972249870\n\tbirthtime\t1132625953120694\n\treztime\t1132625953120694\n\tparceltime\t1132625953120694\n\ttax_rate\t1.01615\n\tnamevalue\tAttachmentOrientation VEC3 RW DS -3.141593, 0.000000, -3.141593\n\tnamevalue\tAttachmentOffset VEC3 RW DS 0.000000, 0.000000, 0.000000\n\tnamevalue\tAttachPt U32 RW S 5\n\tnamevalue\tAttachItemID STRING RW SV 1f9975c0-2951-1b93-dd83-46e2b932fcc8\n\tscratchpad\t0\n\t{\n\t\n\t}\n\tsale_info\t0\n\t{\n\t\tsale_type\tnot\n\t\tsale_price\t10\n\t}\n\torig_asset_id\t52019cdd-b464-ba19-e66d-3da751fef9da\n\torig_item_id\t1f9975c0-2951-1b93-dd83-46e2b932fcc8\n\tcorrect_family_id\t00000000-0000-0000-0000-000000000000\n\thas_rezzed\t0\n\tpre_link_base_mask\t7fffffff\n\tdefault_pay_price\t-2\t1\t5\t10\t20\n}\n'
+#endif
+
+namespace tut
+{
+ struct mem_data
+ {
+ };
+ typedef test_group<mem_data> mem_test;
+ typedef mem_test::object mem_object;
+ tut::mem_test mem_stream("LLMemoryStream");
+
+ template<> template<>
+ void mem_object::test<1>()
+ {
+ const char HELLO_WORLD[] = "hello world";
+ LLMemoryStream mem((U8*)&HELLO_WORLD[0], strlen(HELLO_WORLD)); /* Flawfinder: ignore */
+ std::string hello;
+ std::string world;
+ mem >> hello >> world;
+ ensure_equals("first word", hello, std::string("hello"));
+ ensure_equals("second word", world, std::string("world"));
+ }
+}
+
+namespace tut
+{
+ struct U64_data
+ {
+ };
+ typedef test_group<U64_data> U64_test;
+ typedef U64_test::object U64_object;
+ tut::U64_test U64_testcase("U64_conversion");
+
+ // U64_to_str
+ template<> template<>
+ void U64_object::test<1>()
+ {
+ U64 val;
+ std::string val_str;
+ char result[256];
+ std::string result_str;
+
+ val = U64L(18446744073709551610); // slightly less than MAX_U64
+ val_str = "18446744073709551610";
+
+ U64_to_str(val, result, sizeof(result));
+ result_str = (const char*) result;
+ ensure_equals("U64_to_str converted 1.1", val_str, result_str);
+
+ val = 0;
+ val_str = "0";
+ U64_to_str(val, result, sizeof(result));
+ result_str = (const char*) result;
+ ensure_equals("U64_to_str converted 1.2", val_str, result_str);
+
+ val = U64L(18446744073709551615); // 0xFFFFFFFFFFFFFFFF
+ val_str = "18446744073709551615";
+ U64_to_str(val, result, sizeof(result));
+ result_str = (const char*) result;
+ ensure_equals("U64_to_str converted 1.3", val_str, result_str);
+
+ // overflow - will result in warning at compile time
+ val = U64L(18446744073709551615) + 1; // overflow 0xFFFFFFFFFFFFFFFF + 1 == 0
+ val_str = "0";
+ U64_to_str(val, result, sizeof(result));
+ result_str = (const char*) result;
+ ensure_equals("U64_to_str converted 1.4", val_str, result_str);
+
+ val = U64L(-1); // 0xFFFFFFFFFFFFFFFF == 18446744073709551615
+ val_str = "18446744073709551615";
+ U64_to_str(val, result, sizeof(result));
+ result_str = (const char*) result;
+ ensure_equals("U64_to_str converted 1.5", val_str, result_str);
+
+ val = U64L(10000000000000000000); // testing preserving of 0s
+ val_str = "10000000000000000000";
+ U64_to_str(val, result, sizeof(result));
+ result_str = (const char*) result;
+ ensure_equals("U64_to_str converted 1.6", val_str, result_str);
+
+ val = 1; // testing no leading 0s
+ val_str = "1";
+ U64_to_str(val, result, sizeof(result));
+ result_str = (const char*) result;
+ ensure_equals("U64_to_str converted 1.7", val_str, result_str);
+
+ val = U64L(18446744073709551615); // testing exact sized buffer for result
+ val_str = "18446744073709551615";
+ memset(result, 'A', sizeof(result)); // initialize buffer with all 'A'
+ U64_to_str(val, result, sizeof("18446744073709551615")); //pass in the exact size
+ result_str = (const char*) result;
+ ensure_equals("U64_to_str converted 1.8", val_str, result_str);
+
+ val = U64L(18446744073709551615); // testing smaller sized buffer for result
+ val_str = "1844";
+ memset(result, 'A', sizeof(result)); // initialize buffer with all 'A'
+ U64_to_str(val, result, 5); //pass in a size of 5. should only copy first 4 integers and add a null terminator
+ result_str = (const char*) result;
+ ensure_equals("U64_to_str converted 1.9", val_str, result_str);
+ }
+
+ // str_to_U64
+ template<> template<>
+ void U64_object::test<2>()
+ {
+ U64 val;
+ U64 result;
+
+ val = U64L(18446744073709551610); // slightly less than MAX_U64
+ result = str_to_U64("18446744073709551610");
+ ensure_equals("str_to_U64 converted 2.1", val, result);
+
+ val = U64L(0); // empty string
+ result = str_to_U64(LLStringUtil::null);
+ ensure_equals("str_to_U64 converted 2.2", val, result);
+
+ val = U64L(0); // 0
+ result = str_to_U64("0");
+ ensure_equals("str_to_U64 converted 2.3", val, result);
+
+ val = U64L(18446744073709551615); // 0xFFFFFFFFFFFFFFFF
+ result = str_to_U64("18446744073709551615");
+ ensure_equals("str_to_U64 converted 2.4", val, result);
+
+ // overflow - will result in warning at compile time
+ val = U64L(18446744073709551615) + 1; // overflow 0xFFFFFFFFFFFFFFFF + 1 == 0
+ result = str_to_U64("18446744073709551616");
+ ensure_equals("str_to_U64 converted 2.5", val, result);
+
+ val = U64L(1234); // process till first non-integral character
+ result = str_to_U64("1234A5678");
+ ensure_equals("str_to_U64 converted 2.6", val, result);
+
+ val = U64L(5678); // skip all non-integral characters
+ result = str_to_U64("ABCD5678");
+ ensure_equals("str_to_U64 converted 2.7", val, result);
+
+ // should it skip negative sign and process
+ // rest of string or return 0
+ val = U64L(1234); // skip initial negative sign
+ result = str_to_U64("-1234");
+ ensure_equals("str_to_U64 converted 2.8", val, result);
+
+ val = U64L(5678); // stop at negative sign in the middle
+ result = str_to_U64("5678-1234");
+ ensure_equals("str_to_U64 converted 2.9", val, result);
+
+ val = U64L(0); // no integers
+ result = str_to_U64("AaCD");
+ ensure_equals("str_to_U64 converted 2.10", val, result);
+ }
+
+ // U64_to_F64
+ template<> template<>
+ void U64_object::test<3>()
+ {
+ F64 val;
+ F64 result;
+
+ result = 18446744073709551610.0;
+ val = U64_to_F64(U64L(18446744073709551610));
+ ensure_equals("U64_to_F64 converted 3.1", val, result);
+
+ result = 18446744073709551615.0; // 0xFFFFFFFFFFFFFFFF
+ val = U64_to_F64(U64L(18446744073709551615));
+ ensure_equals("U64_to_F64 converted 3.2", val, result);
+
+ result = 0.0; // overflow 0xFFFFFFFFFFFFFFFF + 1 == 0
+ // overflow - will result in warning at compile time
+ val = U64_to_F64(U64L(18446744073709551615)+1);
+ ensure_equals("U64_to_F64 converted 3.3", val, result);
+
+ result = 0.0; // 0
+ val = U64_to_F64(U64L(0));
+ ensure_equals("U64_to_F64 converted 3.4", val, result);
+
+ result = 1.0; // odd
+ val = U64_to_F64(U64L(1));
+ ensure_equals("U64_to_F64 converted 3.5", val, result);
+
+ result = 2.0; // even
+ val = U64_to_F64(U64L(2));
+ ensure_equals("U64_to_F64 converted 3.6", val, result);
+
+ result = U64L(0x7FFFFFFFFFFFFFFF) * 1.0L; // 0x7FFFFFFFFFFFFFFF
+ val = U64_to_F64(U64L(0x7FFFFFFFFFFFFFFF));
+ ensure_equals("U64_to_F64 converted 3.7", val, result);
+ }
+
+ // llstrtou64
+ // seems to be deprecated - could not find it being used
+ // anywhere in the tarball - skipping unit tests for now
+}
+
+
+namespace tut
+{
+ struct hash_data
+ {
+ };
+ typedef test_group<hash_data> hash_test;
+ typedef hash_test::object hash_object;
+ tut::hash_test hash_tester("LLHash");
+
+ template<> template<>
+ void hash_object::test<1>()
+ {
+ const char * str1 = "test string one";
+ const char * same_as_str1 = "test string one";
+
+ size_t hash1 = llhash(str1);
+ size_t same_as_hash1 = llhash(same_as_str1);
+
+
+ ensure("Hashes from identical strings should be equal", hash1 == same_as_hash1);
+
+ char str[100];
+ strcpy( str, "Another test" );
+
+ size_t hash2 = llhash(str);
+
+ strcpy( str, "Different string, same pointer" );
+
+ size_t hash3 = llhash(str);
+
+ ensure("Hashes from same pointer but different string should not be equal", hash2 != hash3);
+ }
+}
diff --git a/indra/llcommon/tests/listener.h b/indra/llcommon/tests/listener.h
new file mode 100644
index 0000000000..dcdb2412be
--- /dev/null
+++ b/indra/llcommon/tests/listener.h
@@ -0,0 +1,156 @@
+/**
+ * @file listener.h
+ * @author Nat Goodspeed
+ * @date 2009-03-06
+ * @brief Useful for tests of the LLEventPump family of classes
+ *
+ * $LicenseInfo:firstyear=2009&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_LISTENER_H)
+#define LL_LISTENER_H
+
+#include "llsd.h"
+#include <iostream>
+
+/*****************************************************************************
+* test listener class
+*****************************************************************************/
+class Listener;
+std::ostream& operator<<(std::ostream&, const Listener&);
+
+/// Bear in mind that this is strictly for testing
+class Listener
+{
+public:
+ /// Every Listener is instantiated with a name
+ Listener(const std::string& name):
+ mName(name)
+ {
+// std::cout << *this << ": ctor\n";
+ }
+/*==========================================================================*|
+ // These methods are only useful when trying to track Listener instance
+ // lifespan
+ Listener(const Listener& that):
+ mName(that.mName),
+ mLastEvent(that.mLastEvent)
+ {
+ std::cout << *this << ": copy\n";
+ }
+ virtual ~Listener()
+ {
+ std::cout << *this << ": dtor\n";
+ }
+|*==========================================================================*/
+ /// You can request the name
+ std::string getName() const { return mName; }
+ /// This is a typical listener method that returns 'false' when done,
+ /// allowing subsequent listeners on the LLEventPump to process the
+ /// incoming event.
+ bool call(const LLSD& event)
+ {
+// std::cout << *this << "::call(" << event << ")\n";
+ mLastEvent = event;
+ return false;
+ }
+ /// This is an alternate listener that returns 'true' when done, which
+ /// stops processing of the incoming event.
+ bool callstop(const LLSD& event)
+ {
+// std::cout << *this << "::callstop(" << event << ")\n";
+ mLastEvent = event;
+ return true;
+ }
+ /// ListenMethod can represent either call() or callstop().
+ typedef bool (Listener::*ListenMethod)(const LLSD&);
+ /**
+ * This helper method is only because our test code makes so many
+ * repetitive listen() calls to ListenerMethods. In real code, you should
+ * call LLEventPump::listen() directly so it can examine the specific
+ * object you pass to boost::bind().
+ */
+ LLBoundListener listenTo(LLEventPump& pump,
+ ListenMethod method=&Listener::call,
+ const LLEventPump::NameList& after=LLEventPump::empty,
+ const LLEventPump::NameList& before=LLEventPump::empty)
+ {
+ return pump.listen(getName(), boost::bind(method, this, _1), after, before);
+ }
+ /// Both call() and callstop() set mLastEvent. Retrieve it.
+ LLSD getLastEvent() const
+ {
+// std::cout << *this << "::getLastEvent() -> " << mLastEvent << "\n";
+ return mLastEvent;
+ }
+ /// Reset mLastEvent to a known state.
+ void reset(const LLSD& to = LLSD())
+ {
+// std::cout << *this << "::reset(" << to << ")\n";
+ mLastEvent = to;
+ }
+
+private:
+ std::string mName;
+ LLSD mLastEvent;
+};
+
+std::ostream& operator<<(std::ostream& out, const Listener& listener)
+{
+ out << "Listener(" << listener.getName() /* << "@" << &listener */ << ')';
+ return out;
+}
+
+/**
+ * This class tests the relative order in which various listeners on a given
+ * LLEventPump are called. Each listen() call binds a particular string, which
+ * we collect for later examination. The actual event is ignored.
+ */
+struct Collect
+{
+ bool add(const std::string& bound, const LLSD& event)
+ {
+ result.push_back(bound);
+ return false;
+ }
+ void clear() { result.clear(); }
+ typedef std::vector<std::string> StringList;
+ StringList result;
+};
+
+std::ostream& operator<<(std::ostream& out, const Collect::StringList& strings)
+{
+ out << '(';
+ Collect::StringList::const_iterator begin(strings.begin()), end(strings.end());
+ if (begin != end)
+ {
+ out << '"' << *begin << '"';
+ while (++begin != end)
+ {
+ out << ", \"" << *begin << '"';
+ }
+ }
+ out << ')';
+ return out;
+}
+
+#endif /* ! defined(LL_LISTENER_H) */
diff --git a/indra/llcommon/tests/llallocator_heap_profile_test.cpp b/indra/llcommon/tests/llallocator_heap_profile_test.cpp
new file mode 100644
index 0000000000..44a9705803
--- /dev/null
+++ b/indra/llcommon/tests/llallocator_heap_profile_test.cpp
@@ -0,0 +1,144 @@
+/**
+ * @file llallocator_heap_profile_test.cpp
+ * @author Brad Kittenbrink
+ * @date 2008-02-
+ * @brief Test for llallocator_heap_profile.cpp.
+ *
+ * $LicenseInfo:firstyear=2009&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$
+ */
+
+#include "../llallocator_heap_profile.h"
+#include "../test/lltut.h"
+
+namespace tut
+{
+ struct llallocator_heap_profile_data
+ {
+ LLAllocatorHeapProfile prof;
+
+ static char const * const sample_win_profile;
+ // *TODO - get test output from mac/linux tcmalloc
+ static char const * const sample_mac_profile;
+ static char const * const sample_lin_profile;
+
+ static char const * const crash_testcase;
+ };
+ typedef test_group<llallocator_heap_profile_data> factory;
+ typedef factory::object object;
+}
+namespace
+{
+ tut::factory llallocator_heap_profile_test_factory("LLAllocatorHeapProfile");
+}
+
+namespace tut
+{
+ template<> template<>
+ void object::test<1>()
+ {
+ prof.parse(sample_win_profile);
+
+ ensure_equals("count lines", prof.mLines.size() , 5);
+ ensure_equals("alloc counts", prof.mLines[0].mLiveCount, 2131854U);
+ ensure_equals("alloc counts", prof.mLines[0].mLiveSize, 2245710106ULL);
+ ensure_equals("alloc counts", prof.mLines[0].mTotalCount, 14069198U);
+ ensure_equals("alloc counts", prof.mLines[0].mTotalSize, 4295177308ULL);
+ ensure_equals("count markers", prof.mLines[0].mTrace.size(), 0);
+ ensure_equals("count markers", prof.mLines[1].mTrace.size(), 0);
+ ensure_equals("count markers", prof.mLines[2].mTrace.size(), 4);
+ ensure_equals("count markers", prof.mLines[3].mTrace.size(), 6);
+ ensure_equals("count markers", prof.mLines[4].mTrace.size(), 7);
+
+ //prof.dump(std::cout);
+ }
+
+ template<> template<>
+ void object::test<2>()
+ {
+ prof.parse(crash_testcase);
+
+ ensure_equals("count lines", prof.mLines.size(), 2);
+ ensure_equals("alloc counts", prof.mLines[0].mLiveCount, 3U);
+ ensure_equals("alloc counts", prof.mLines[0].mLiveSize, 1049652ULL);
+ ensure_equals("alloc counts", prof.mLines[0].mTotalCount, 8U);
+ ensure_equals("alloc counts", prof.mLines[0].mTotalSize, 1049748ULL);
+ ensure_equals("count markers", prof.mLines[0].mTrace.size(), 0);
+ ensure_equals("count markers", prof.mLines[1].mTrace.size(), 0);
+
+ //prof.dump(std::cout);
+ }
+
+ template<> template<>
+ void object::test<3>()
+ {
+ // test that we don't crash on edge case data
+ prof.parse("");
+ ensure("emtpy on error", prof.mLines.empty());
+
+ prof.parse("heap profile:");
+ ensure("emtpy on error", prof.mLines.empty());
+ }
+
+char const * const llallocator_heap_profile_data::sample_win_profile =
+"heap profile: 2131854: 2245710106 [14069198: 4295177308] @\n"
+"308592: 1073398388 [966564: 1280998739] @\n"
+"462651: 375969538 [1177377: 753561247] @ 2 3 6 1\n"
+"314744: 206611283 [2008722: 570934755] @ 2 3 3 7 21 32\n"
+"277152: 82862770 [621961: 168503640] @ 2 3 3 7 21 32 87\n"
+"\n"
+"MAPPED_LIBRARIES:\n"
+"00400000-02681000 r-xp 00000000 00:00 0 c:\\proj\\tcmalloc-eval-9\\indra\\build-vc80\\newview\\RelWithDebInfo\\secondlife-bin.exe\n"
+"77280000-773a7000 r-xp 00000000 00:00 0 C:\\Windows\\system32\\ntdll.dll\n"
+"76df0000-76ecb000 r-xp 00000000 00:00 0 C:\\Windows\\system32\\kernel32.dll\n"
+"76000000-76073000 r-xp 00000000 00:00 0 C:\\Windows\\system32\\comdlg32.dll\n"
+"75ee0000-75f8a000 r-xp 00000000 00:00 0 C:\\Windows\\system32\\msvcrt.dll\n"
+"76c30000-76c88000 r-xp 00000000 00:00 0 C:\\Windows\\system32\\SHLWAPI.dll\n"
+"75f90000-75fdb000 r-xp 00000000 00:00 0 C:\\Windows\\system32\\GDI32.dll\n"
+"77420000-774bd000 r-xp 00000000 00:00 0 C:\\Windows\\system32\\USER32.dll\n"
+"75e10000-75ed6000 r-xp 00000000 00:00 0 C:\\Windows\\system32\\ADVAPI32.dll\n"
+"75b00000-75bc2000 r-xp 00000000 00:00 0 C:\\Windows\\system32\\RPCRT4.dll\n"
+"72ca0000-72d25000 r-xp 00000000 00:00 0 C:\\Windows\\WinSxS\\x86_microsoft.windows.common-controls_6595b64144ccf1df_5.82.6001.18000_none_886786f450a74a05\\COMCTL32.dll\n"
+"76120000-76c30000 r-xp 00000000 00:00 0 C:\\Windows\\system32\\SHELL32.dll\n"
+"71ce0000-71d13000 r-xp 00000000 00:00 0 C:\\Windows\\system32\\DINPUT8.dll\n";
+
+
+char const * const llallocator_heap_profile_data::crash_testcase =
+"heap profile: 3: 1049652 [ 8: 1049748] @\n"
+" 3: 1049652 [ 8: 1049748] @\n"
+"\n"
+"MAPPED_LIBRARIES:\n"
+"00400000-004d5000 r-xp 00000000 00:00 0 c:\\code\\linden\\tcmalloc\\indra\\build-vc80\\llcommon\\RelWithDebInfo\\llallocator_test.exe\n"
+"7c900000-7c9af000 r-xp 00000000 00:00 0 C:\\WINDOWS\\system32\\ntdll.dll\n"
+"7c800000-7c8f6000 r-xp 00000000 00:00 0 C:\\WINDOWS\\system32\\kernel32.dll\n"
+"77dd0000-77e6b000 r-xp 00000000 00:00 0 C:\\WINDOWS\\system32\\ADVAPI32.dll\n"
+"77e70000-77f02000 r-xp 00000000 00:00 0 C:\\WINDOWS\\system32\\RPCRT4.dll\n"
+"77fe0000-77ff1000 r-xp 00000000 00:00 0 C:\\WINDOWS\\system32\\Secur32.dll\n"
+"71ab0000-71ac7000 r-xp 00000000 00:00 0 C:\\WINDOWS\\system32\\WS2_32.dll\n"
+"77c10000-77c68000 r-xp 00000000 00:00 0 C:\\WINDOWS\\system32\\msvcrt.dll\n"
+"71aa0000-71aa8000 r-xp 00000000 00:00 0 C:\\WINDOWS\\system32\\WS2HELP.dll\n"
+"76bf0000-76bfb000 r-xp 00000000 00:00 0 C:\\WINDOWS\\system32\\PSAPI.DLL\n"
+"5b860000-5b8b5000 r-xp 00000000 00:00 0 C:\\WINDOWS\\system32\\NETAPI32.dll\n"
+"10000000-10041000 r-xp 00000000 00:00 0 c:\\code\\linden\\tcmalloc\\indra\\build-vc80\\llcommon\\RelWithDebInfo\\libtcmalloc_minimal.dll\n"
+"7c420000-7c4a7000 r-xp 00000000 00:00 0 C:\\WINDOWS\\WinSxS\\x86_Microsoft.VC80.CRT_1fc8b3b9a1e18e3b_8.0.50727.1433_x-ww_5cf844d2\\MSVCP80.dll\n"
+"78130000-781cb000 r-xp 00000000 00:00 0 C:\\WINDOWS\\WinSxS\\x86_Microsoft.VC80.CRT_1fc8b3b9a1e18e3b_8.0.50727.1433_x-ww_5cf844d2\\MSVCR80.dll\n";
+
+}
diff --git a/indra/llcommon/tests/llallocator_test.cpp b/indra/llcommon/tests/llallocator_test.cpp
new file mode 100644
index 0000000000..4e62eaee67
--- /dev/null
+++ b/indra/llcommon/tests/llallocator_test.cpp
@@ -0,0 +1,80 @@
+/**
+ * @file llallocator_test.cpp
+ * @author Brad Kittenbrink
+ * @date 2008-02-
+ * @brief Test for llallocator.cpp.
+ *
+ * $LicenseInfo:firstyear=2009&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$
+ */
+
+#include "../llallocator.h"
+#include "../test/lltut.h"
+
+namespace tut
+{
+ struct llallocator_data
+ {
+ LLAllocator llallocator;
+ };
+ typedef test_group<llallocator_data> factory;
+ typedef factory::object object;
+}
+namespace
+{
+ tut::factory llallocator_test_factory("LLAllocator");
+}
+
+namespace tut
+{
+ template<> template<>
+ void object::test<1>()
+ {
+ llallocator.setProfilingEnabled(false);
+ ensure("Profiler disable", !llallocator.isProfiling());
+ }
+
+#if LL_USE_TCMALLOC
+ template<> template<>
+ void object::test<2>()
+ {
+ llallocator.setProfilingEnabled(true);
+ ensure("Profiler enable", llallocator.isProfiling());
+ }
+
+ template <> template <>
+ void object::test<3>()
+ {
+ llallocator.setProfilingEnabled(true);
+
+ char * test_alloc = new char[1024];
+
+ llallocator.getProfile();
+
+ delete [] test_alloc;
+
+ llallocator.getProfile();
+
+ // *NOTE - this test isn't ensuring anything right now other than no
+ // exceptions are thrown.
+ }
+#endif // LL_USE_TCMALLOC
+};
diff --git a/indra/llcommon/tests/llbase64_test.cpp b/indra/llcommon/tests/llbase64_test.cpp
new file mode 100644
index 0000000000..d0394150fa
--- /dev/null
+++ b/indra/llcommon/tests/llbase64_test.cpp
@@ -0,0 +1,77 @@
+/**
+ * @file llbase64_test.cpp
+ * @author James Cook
+ * @date 2007-02-04
+ *
+ * $LicenseInfo:firstyear=2007&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$
+ */
+
+#include <string>
+
+#include "linden_common.h"
+
+#include "../llbase64.h"
+#include "../lluuid.h"
+
+#include "../test/lltut.h"
+
+namespace tut
+{
+ struct base64_data
+ {
+ };
+ typedef test_group<base64_data> base64_test;
+ typedef base64_test::object base64_object;
+ tut::base64_test base64("LLBase64");
+
+ template<> template<>
+ void base64_object::test<1>()
+ {
+ std::string result;
+
+ result = LLBase64::encode(NULL, 0);
+ ensure("encode nothing", (result == "") );
+
+ LLUUID nothing;
+ result = LLBase64::encode(&nothing.mData[0], UUID_BYTES);
+ ensure("encode blank uuid",
+ (result == "AAAAAAAAAAAAAAAAAAAAAA==") );
+
+ LLUUID id("526a1e07-a19d-baed-84c4-ff08a488d15e");
+ result = LLBase64::encode(&id.mData[0], UUID_BYTES);
+ ensure("encode random uuid",
+ (result == "UmoeB6Gduu2ExP8IpIjRXg==") );
+
+ }
+
+ template<> template<>
+ void base64_object::test<2>()
+ {
+ std::string result;
+
+ U8 blob[40] = { 115, 223, 172, 255, 140, 70, 49, 125, 236, 155, 45, 199, 101, 17, 164, 131, 230, 19, 80, 64, 112, 53, 135, 98, 237, 12, 26, 72, 126, 14, 145, 143, 118, 196, 11, 177, 132, 169, 195, 134 };
+ result = LLBase64::encode(&blob[0], 40);
+ ensure("encode 40 bytes",
+ (result == "c9+s/4xGMX3smy3HZRGkg+YTUEBwNYdi7QwaSH4OkY92xAuxhKnDhg==") );
+ }
+
+}
diff --git a/indra/llcommon/tests/lldate_test.cpp b/indra/llcommon/tests/lldate_test.cpp
new file mode 100644
index 0000000000..7c95ccb91f
--- /dev/null
+++ b/indra/llcommon/tests/lldate_test.cpp
@@ -0,0 +1,213 @@
+/**
+ * @file lldate_test.cpp
+ * @author Adroit
+ * @date 2007-02
+ * @brief LLDate test cases.
+ *
+ * $LicenseInfo:firstyear=2007&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$
+ */
+
+#include "linden_common.h"
+
+#include "../llstring.h"
+#include "../lldate.h"
+
+#include "../test/lltut.h"
+
+
+#define VALID_DATE "2003-04-30T04:00:00Z"
+#define VALID_DATE_LEAP "2004-02-29T04:00:00Z"
+#define VALID_DATE_HOUR_BOUNDARY "2003-04-30T23:59:59Z"
+#define VALID_DATE_FRACTIONAL_SECS "2007-09-26T20:31:33.70Z"
+
+// invalid format
+#define INVALID_DATE_MISSING_YEAR "-04-30T22:59:59Z"
+#define INVALID_DATE_MISSING_MONTH "1900-0430T22:59:59Z"
+#define INVALID_DATE_MISSING_DATE "1900-0430-T22:59:59Z"
+#define INVALID_DATE_MISSING_T "1900-04-30-22:59:59Z"
+#define INVALID_DATE_MISSING_HOUR "1900-04-30T:59:59Z"
+#define INVALID_DATE_MISSING_MIN "1900-04-30T01::59Z"
+#define INVALID_DATE_MISSING_SEC "1900-04-30T01:59Z"
+#define INVALID_DATE_MISSING_Z "1900-04-30T01:59:23"
+#define INVALID_DATE_EMPTY ""
+
+// invalid values
+// apr 1.1.1 seems to not care about constraining the date to valid
+// dates. Put these back when the parser checks.
+#define LL_DATE_PARSER_CHECKS_BOUNDARY 0
+//#define INVALID_DATE_24HOUR_BOUNDARY "2003-04-30T24:00:00Z"
+//#define INVALID_DATE_LEAP "2003-04-29T04:00:00Z"
+//#define INVALID_DATE_HOUR "2003-04-30T24:59:59Z"
+//#define INVALID_DATE_MIN "2003-04-30T22:69:59Z"
+//#define INVALID_DATE_SEC "2003-04-30T22:59:69Z"
+//#define INVALID_DATE_YEAR "0-04-30T22:59:59Z"
+//#define INVALID_DATE_MONTH "2003-13-30T22:59:59Z"
+//#define INVALID_DATE_DAY "2003-04-35T22:59:59Z"
+
+namespace tut
+{
+ struct date_test
+ {
+
+ };
+ typedef test_group<date_test> date_test_t;
+ typedef date_test_t::object date_test_object_t;
+ tut::date_test_t tut_date_test("LLDate");
+
+ /* format validation */
+ template<> template<>
+ void date_test_object_t::test<1>()
+ {
+ LLDate date(VALID_DATE);
+ std::string expected_string;
+ bool result;
+ expected_string = VALID_DATE;
+ ensure_equals("Valid Date failed" , expected_string, date.asString());
+
+ result = date.fromString(VALID_DATE_LEAP);
+ expected_string = VALID_DATE_LEAP;
+ ensure_equals("VALID_DATE_LEAP failed" , expected_string, date.asString());
+
+ result = date.fromString(VALID_DATE_HOUR_BOUNDARY);
+ expected_string = VALID_DATE_HOUR_BOUNDARY;
+ ensure_equals("VALID_DATE_HOUR_BOUNDARY failed" , expected_string, date.asString());
+
+ result = date.fromString(VALID_DATE_FRACTIONAL_SECS);
+ expected_string = VALID_DATE_FRACTIONAL_SECS;
+ ensure_equals("VALID_DATE_FRACTIONAL_SECS failed" , expected_string, date.asString());
+
+ result = date.fromString(INVALID_DATE_MISSING_YEAR);
+ ensure_equals("INVALID_DATE_MISSING_YEAR should have failed" , result, false);
+
+ result = date.fromString(INVALID_DATE_MISSING_MONTH);
+ ensure_equals("INVALID_DATE_MISSING_MONTH should have failed" , result, false);
+
+ result = date.fromString(INVALID_DATE_MISSING_DATE);
+ ensure_equals("INVALID_DATE_MISSING_DATE should have failed" , result, false);
+
+ result = date.fromString(INVALID_DATE_MISSING_T);
+ ensure_equals("INVALID_DATE_MISSING_T should have failed" , result, false);
+
+ result = date.fromString(INVALID_DATE_MISSING_HOUR);
+ ensure_equals("INVALID_DATE_MISSING_HOUR should have failed" , result, false);
+
+ result = date.fromString(INVALID_DATE_MISSING_MIN);
+ ensure_equals("INVALID_DATE_MISSING_MIN should have failed" , result, false);
+
+ result = date.fromString(INVALID_DATE_MISSING_SEC);
+ ensure_equals("INVALID_DATE_MISSING_SEC should have failed" , result, false);
+
+ result = date.fromString(INVALID_DATE_MISSING_Z);
+ ensure_equals("INVALID_DATE_MISSING_Z should have failed" , result, false);
+
+ result = date.fromString(INVALID_DATE_EMPTY);
+ ensure_equals("INVALID_DATE_EMPTY should have failed" , result, false);
+ }
+
+ /* Invalid Value Handling */
+ template<> template<>
+ void date_test_object_t::test<2>()
+ {
+#if LL_DATE_PARSER_CHECKS_BOUNDARY
+ LLDate date;
+ std::string expected_string;
+ bool result;
+
+ result = date.fromString(INVALID_DATE_24HOUR_BOUNDARY);
+ ensure_equals("INVALID_DATE_24HOUR_BOUNDARY should have failed" , result, false);
+ ensure_equals("INVALID_DATE_24HOUR_BOUNDARY date still set to old value on failure!" , date.secondsSinceEpoch(), 0);
+
+ result = date.fromString(INVALID_DATE_LEAP);
+ ensure_equals("INVALID_DATE_LEAP should have failed" , result, false);
+
+ result = date.fromString(INVALID_DATE_HOUR);
+ ensure_equals("INVALID_DATE_HOUR should have failed" , result, false);
+
+ result = date.fromString(INVALID_DATE_MIN);
+ ensure_equals("INVALID_DATE_MIN should have failed" , result, false);
+
+ result = date.fromString(INVALID_DATE_SEC);
+ ensure_equals("INVALID_DATE_SEC should have failed" , result, false);
+
+ result = date.fromString(INVALID_DATE_YEAR);
+ ensure_equals("INVALID_DATE_YEAR should have failed" , result, false);
+
+ result = date.fromString(INVALID_DATE_MONTH);
+ ensure_equals("INVALID_DATE_MONTH should have failed" , result, false);
+
+ result = date.fromString(INVALID_DATE_DAY);
+ ensure_equals("INVALID_DATE_DAY should have failed" , result, false);
+#endif
+ }
+
+ /* API checks */
+ template<> template<>
+ void date_test_object_t::test<3>()
+ {
+ LLDate date;
+ std::istringstream stream(VALID_DATE);
+ std::string expected_string = VALID_DATE;
+ date.fromStream(stream);
+ ensure_equals("fromStream failed", date.asString(), expected_string);
+ }
+
+ template<> template<>
+ void date_test_object_t::test<4>()
+ {
+ LLDate date1(VALID_DATE);
+ LLDate date2(date1);
+ ensure_equals("LLDate(const LLDate& date) constructor failed", date1.asString(), date2.asString());
+ }
+
+ template<> template<>
+ void date_test_object_t::test<5>()
+ {
+ LLDate date1(VALID_DATE);
+ LLDate date2(date1.secondsSinceEpoch());
+ ensure_equals("secondsSinceEpoch not equal",date1.secondsSinceEpoch(), date2.secondsSinceEpoch());
+ ensure_equals("LLDate created using secondsSinceEpoch not equal", date1.asString(), date2.asString());
+ }
+
+ template<> template<>
+ void date_test_object_t::test<6>()
+ {
+ LLDate date(VALID_DATE);
+ std::ostringstream stream;
+ stream << date;
+ std::string expected_str = VALID_DATE;
+ ensure_equals("ostringstream failed", expected_str, stream.str());
+ }
+
+ template<> template<>
+ void date_test_object_t::test<7>()
+ {
+ LLDate date;
+ std::istringstream stream(VALID_DATE);
+ stream >> date;
+ std::string expected_str = VALID_DATE;
+ std::ostringstream out_stream;
+ out_stream << date;
+
+ ensure_equals("<< failed", date.asString(),expected_str);
+ ensure_equals("<< to >> failed", stream.str(),out_stream.str());
+ }
+}
diff --git a/indra/llcommon/tests/lldependencies_test.cpp b/indra/llcommon/tests/lldependencies_test.cpp
new file mode 100644
index 0000000000..e40743ccf7
--- /dev/null
+++ b/indra/llcommon/tests/lldependencies_test.cpp
@@ -0,0 +1,292 @@
+/**
+ * @file lldependencies_tut.cpp
+ * @author Nat Goodspeed
+ * @date 2008-09-17
+ * @brief Test of lldependencies.h
+ *
+ * $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$
+ */
+
+// STL headers
+#include <iostream>
+#include <string>
+// std headers
+// external library headers
+#include <boost/assign/list_of.hpp>
+// Precompiled header
+#include "linden_common.h"
+// associated header
+#include "../lldependencies.h"
+// other Linden headers
+#include "../test/lltut.h"
+
+using boost::assign::list_of;
+
+#if LL_WINDOWS
+#pragma warning (disable : 4675) // "resolved by ADL" -- just as I want!
+#endif
+
+typedef LLDependencies<> StringDeps;
+typedef StringDeps::KeyList StringList;
+
+// We use the very cool boost::assign::list_of() construct to specify vectors
+// of strings inline. For reasons on which I'm not entirely clear, though, it
+// needs a helper function. You can use list_of() to construct an implicit
+// StringList (std::vector<std::string>) by conversion, e.g. for a function
+// parameter -- but if you simply write StringList(list_of("etc.")), you get
+// ambiguity errors. Shrug!
+template<typename CONTAINER>
+CONTAINER make(const CONTAINER& data)
+{
+ return data;
+}
+
+// Display an arbitary value as itself...
+template<typename T>
+std::ostream& display(std::ostream& out, const T& value)
+{
+ out << value;
+ return out;
+}
+
+// ...but display std::string enclosed in double quotes.
+template<>
+std::ostream& display(std::ostream& out, const std::string& value)
+{
+ out << '"' << value << '"';
+ return out;
+}
+
+// display any sequence compatible with Boost.Range
+template<typename SEQUENCE>
+std::ostream& display_seq(std::ostream& out,
+ const std::string& open, const SEQUENCE& seq, const std::string& close)
+{
+ out << open;
+ typename boost::range_const_iterator<SEQUENCE>::type
+ sli = boost::begin(seq),
+ slend = boost::end(seq);
+ if (sli != slend)
+ {
+ display(out, *sli);
+ while (++sli != slend)
+ {
+ out << ", ";
+ display(out, *sli);
+ }
+ }
+ out << close;
+ return out;
+}
+
+// helper to dump a StringList to std::cout if needed
+template<typename ENTRY>
+std::ostream& operator<<(std::ostream& out, const std::vector<ENTRY>& list)
+{
+ display_seq(out, "(", list, ")");
+ return out;
+}
+
+template<typename ENTRY>
+std::ostream& operator<<(std::ostream& out, const std::set<ENTRY>& set)
+{
+ display_seq(out, "{", set, "}");
+ return out;
+}
+
+const std::string& extract_key(const LLDependencies<>::value_type& entry)
+{
+ return entry.first;
+}
+
+// helper to return a StringList of keys from LLDependencies::sort()
+StringList sorted_keys(LLDependencies<>& deps)
+{
+ // 1. Call deps.sort(), returning a value_type range of (key, node) pairs.
+ // 2. Use make_transform_range() to obtain a range of just keys.
+ // 3. Use instance_from_range to instantiate a StringList from that range.
+ // 4. Return by value "slices" instance_from_range<StringList> (a subclass
+ // of StringList) to its base class StringList.
+ return instance_from_range<StringList>(make_transform_range(deps.sort(), extract_key));
+}
+
+template<typename RANGE>
+bool is_empty(const RANGE& range)
+{
+ return boost::begin(range) == boost::end(range);
+}
+
+/*****************************************************************************
+* tut test group
+*****************************************************************************/
+namespace tut
+{
+ struct deps_data
+ {
+ };
+ typedef test_group<deps_data> deps_group;
+ typedef deps_group::object deps_object;
+ tut::deps_group depsgr("LLDependencies");
+
+ template<> template<>
+ void deps_object::test<1>()
+ {
+ StringDeps deps;
+ StringList empty;
+ // The quick brown fox jumps over the lazy yellow dog.
+ // (note, "The" and "the" are distinct, else this test wouldn't work)
+ deps.add("lazy");
+ ensure_equals(sorted_keys(deps), make<StringList>(list_of("lazy")));
+ deps.add("jumps");
+ ensure("found lazy", deps.get("lazy"));
+ ensure("not found dog.", ! deps.get("dog."));
+ // NOTE: Maybe it's overkill to test each of these intermediate
+ // results before all the interdependencies have been specified. My
+ // thought is simply that if the order changes, I'd like to know why.
+ // A change to the implementation of boost::topological_sort() would
+ // be an acceptable reason, and you can simply update the expected
+ // test output.
+ ensure_equals(sorted_keys(deps), make<StringList>(list_of("lazy")("jumps")));
+ deps.add("The", 0, empty, list_of("fox")("dog."));
+ // Test key accessors
+ ensure("empty before deps for missing key", is_empty(deps.get_before_range("bogus")));
+ ensure("empty before deps for jumps", is_empty(deps.get_before_range("jumps")));
+ ensure_equals(instance_from_range< std::set<std::string> >(deps.get_before_range("The")),
+ make< std::set<std::string> >(list_of("dog.")("fox")));
+ // resume building dependencies
+ ensure_equals(sorted_keys(deps), make<StringList>(list_of("lazy")("jumps")("The")));
+ deps.add("the", 0, list_of("The"));
+ ensure_equals(sorted_keys(deps), make<StringList>(list_of("lazy")("jumps")("The")("the")));
+ deps.add("fox", 0, list_of("The"), list_of("jumps"));
+ ensure_equals(sorted_keys(deps), make<StringList>(list_of("lazy")("The")("the")("fox")("jumps")));
+ deps.add("the", 0, list_of("The")); // same, see if cache works
+ ensure_equals(sorted_keys(deps), make<StringList>(list_of("lazy")("The")("the")("fox")("jumps")));
+ deps.add("jumps", 0, empty, list_of("over")); // update jumps deps
+ ensure_equals(sorted_keys(deps), make<StringList>(list_of("lazy")("The")("the")("fox")("jumps")));
+/*==========================================================================*|
+ // It drives me nuts that this test doesn't work in the test
+ // framework, because -- for reasons unknown -- running the test
+ // framework on Mac OS X 10.5 Leopard and Windows XP Pro, the catch
+ // clause below doesn't catch the exception. Something about the TUT
+ // test framework?!? The identical code works fine in a standalone
+ // test program. Commenting out the test for now, in hopes that our
+ // real builds will be able to catch Cycle exceptions...
+ try
+ {
+ // We've already specified fox -> jumps and jumps -> over. Try an
+ // impossible constraint.
+ deps.add("over", 0, empty, list_of("fox"));
+ }
+ catch (const StringDeps::Cycle& e)
+ {
+ std::cout << "Cycle detected: " << e.what() << '\n';
+ // It's legal to add() an impossible constraint because we don't
+ // detect the cycle until sort(). So sort() can't know the minimum set
+ // of nodes to remove to make the StringDeps object valid again.
+ // Therefore we must break the cycle by hand.
+ deps.remove("over");
+ }
+|*==========================================================================*/
+ deps.add("dog.", 0, list_of("yellow")("lazy"));
+ ensure_equals(instance_from_range< std::set<std::string> >(deps.get_after_range("dog.")),
+ make< std::set<std::string> >(list_of("lazy")("yellow")));
+ ensure_equals(sorted_keys(deps), make<StringList>(list_of("lazy")("The")("the")("fox")("jumps")("dog.")));
+ deps.add("quick", 0, list_of("The"), list_of("fox")("brown"));
+ ensure_equals(sorted_keys(deps), make<StringList>(list_of("lazy")("The")("the")("quick")("fox")("jumps")("dog.")));
+ deps.add("over", 0, list_of("jumps"), list_of("yellow")("the"));
+ ensure_equals(sorted_keys(deps), make<StringList>(list_of("lazy")("The")("quick")("fox")("jumps")("over")("the")("dog.")));
+ deps.add("yellow", 0, list_of("the"), list_of("lazy"));
+ ensure_equals(sorted_keys(deps), make<StringList>(list_of("The")("quick")("fox")("jumps")("over")("the")("yellow")("lazy")("dog.")));
+ deps.add("brown");
+ // By now the dependencies are pretty well in place. A change to THIS
+ // order should be viewed with suspicion.
+ ensure_equals(sorted_keys(deps), make<StringList>(list_of("The")("quick")("brown")("fox")("jumps")("over")("the")("yellow")("lazy")("dog.")));
+
+ StringList keys(make<StringList>(list_of("The")("brown")("dog.")("fox")("jumps")("lazy")("over")("quick")("the")("yellow")));
+ ensure_equals(instance_from_range<StringList>(deps.get_key_range()), keys);
+#if (! defined(__GNUC__)) || (__GNUC__ > 3) || (__GNUC__ == 3 && __GNUC_MINOR__ > 3)
+ // This is the succinct way, works on modern compilers
+ ensure_equals(instance_from_range<StringList>(make_transform_range(deps.get_range(), extract_key)), keys);
+#else // gcc 3.3
+ StringDeps::range got_range(deps.get_range());
+ StringDeps::iterator kni = got_range.begin(), knend = got_range.end();
+ StringList::iterator ki = keys.begin(), kend = keys.end();
+ for ( ; kni != knend && ki != kend; ++kni, ++ki)
+ {
+ ensure_equals(kni->first, *ki);
+ }
+ ensure("get_range() returns proper length", kni == knend && ki == kend);
+#endif // gcc 3.3
+ // blow off get_node_range() because they're all LLDependenciesEmpty instances
+ }
+
+ template<> template<>
+ void deps_object::test<2>()
+ {
+ typedef LLDependencies<std::string, int> NameIndexDeps;
+ NameIndexDeps nideps;
+ const NameIndexDeps& const_nideps(nideps);
+ nideps.add("def", 2, list_of("ghi"));
+ nideps.add("ghi", 3);
+ nideps.add("abc", 1, list_of("def"));
+ NameIndexDeps::range range(nideps.get_range());
+ ensure_equals(range.begin()->first, "abc");
+ ensure_equals(range.begin()->second, 1);
+ range.begin()->second = 0;
+ range.begin()->second = 1;
+ NameIndexDeps::const_range const_range(const_nideps.get_range());
+ NameIndexDeps::const_iterator const_iterator(const_range.begin());
+ ++const_iterator;
+ ensure_equals(const_iterator->first, "def");
+ ensure_equals(const_iterator->second, 2);
+ NameIndexDeps::node_range node_range(nideps.get_node_range());
+ ensure_equals(instance_from_range<std::vector<int> >(node_range), make< std::vector<int> >(list_of(1)(2)(3)));
+ *node_range.begin() = 0;
+ *node_range.begin() = 1;
+ NameIndexDeps::const_node_range const_node_range(const_nideps.get_node_range());
+ ensure_equals(instance_from_range<std::vector<int> >(const_node_range), make< std::vector<int> >(list_of(1)(2)(3)));
+ NameIndexDeps::const_key_range const_key_range(const_nideps.get_key_range());
+ ensure_equals(instance_from_range<StringList>(const_key_range), make<StringList>(list_of("abc")("def")("ghi")));
+ NameIndexDeps::sorted_range sorted(const_nideps.sort());
+ NameIndexDeps::sorted_iterator sortiter(sorted.begin());
+ ensure_equals(sortiter->first, "ghi");
+ ensure_equals(sortiter->second, 3);
+
+ // test all iterator-flavored versions of get_after_range()
+ StringList def(make<StringList>(list_of("def")));
+ ensure("empty abc before list", is_empty(nideps.get_before_range(nideps.get_range().begin())));
+ ensure_equals(instance_from_range<StringList>(nideps.get_after_range(nideps.get_range().begin())),
+ def);
+ ensure_equals(instance_from_range<StringList>(const_nideps.get_after_range(const_nideps.get_range().begin())),
+ def);
+ ensure_equals(instance_from_range<StringList>(nideps.get_after_range(nideps.get_node_range().begin())),
+ def);
+ ensure_equals(instance_from_range<StringList>(const_nideps.get_after_range(const_nideps.get_node_range().begin())),
+ def);
+ ensure_equals(instance_from_range<StringList>(nideps.get_after_range(nideps.get_key_range().begin())),
+ def);
+ // advance from "ghi" to "def", which must come after "ghi"
+ ++sortiter;
+ ensure_equals(instance_from_range<StringList>(const_nideps.get_after_range(sortiter)),
+ make<StringList>(list_of("ghi")));
+ }
+} // namespace tut
diff --git a/indra/llcommon/tests/llerror_test.cpp b/indra/llcommon/tests/llerror_test.cpp
new file mode 100644
index 0000000000..1ef8fc9712
--- /dev/null
+++ b/indra/llcommon/tests/llerror_test.cpp
@@ -0,0 +1,762 @@
+/**
+ * @file llerror_test.cpp
+ * @date December 2006
+ * @brief error unit tests
+ *
+ * $LicenseInfo:firstyear=2006&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$
+ */
+
+#include <vector>
+
+#include "linden_common.h"
+
+#include "../llerror.h"
+
+#include "../llerrorcontrol.h"
+#include "../llsd.h"
+
+#include "../test/lltut.h"
+
+namespace
+{
+ void test_that_error_h_includes_enough_things_to_compile_a_message()
+ {
+ llinfos << "!" << llendl;
+ }
+}
+
+namespace
+{
+ static bool fatalWasCalled;
+ void fatalCall(const std::string&) { fatalWasCalled = true; }
+
+ class TestRecorder : public LLError::Recorder
+ {
+ public:
+ TestRecorder() : mWantsTime(false) { }
+ ~TestRecorder() { LLError::removeRecorder(this); }
+
+ void recordMessage(LLError::ELevel level,
+ const std::string& message)
+ {
+ mMessages.push_back(message);
+ }
+
+ int countMessages() { return (int) mMessages.size(); }
+ void clearMessages() { mMessages.clear(); }
+
+ void setWantsTime(bool t) { mWantsTime = t; }
+ bool wantsTime() { return mWantsTime; }
+
+ std::string message(int n)
+ {
+ std::ostringstream test_name;
+ test_name << "testing message " << n << ", not enough messages";
+
+ tut::ensure(test_name.str(), n < countMessages());
+ return mMessages[n];
+ }
+
+ private:
+ typedef std::vector<std::string> MessageVector;
+ MessageVector mMessages;
+
+ bool mWantsTime;
+ };
+}
+
+namespace tut
+{
+ struct ErrorTestData
+ {
+ TestRecorder mRecorder;
+ LLError::Settings* mPriorErrorSettings;
+
+ ErrorTestData()
+ {
+ fatalWasCalled = false;
+
+ mPriorErrorSettings = LLError::saveAndResetSettings();
+ LLError::setDefaultLevel(LLError::LEVEL_DEBUG);
+ LLError::setFatalFunction(fatalCall);
+ LLError::addRecorder(&mRecorder);
+ }
+
+ ~ErrorTestData()
+ {
+ LLError::removeRecorder(&mRecorder);
+ LLError::restoreSettings(mPriorErrorSettings);
+ }
+
+ void ensure_message_count(int expectedCount)
+ {
+ ensure_equals("message count", mRecorder.countMessages(), expectedCount);
+ }
+
+ void ensure_message_contains(int n, const std::string& expectedText)
+ {
+ std::ostringstream test_name;
+ test_name << "testing message " << n;
+
+ ensure_contains(test_name.str(), mRecorder.message(n), expectedText);
+ }
+
+ void ensure_message_does_not_contain(int n, const std::string& expectedText)
+ {
+ std::ostringstream test_name;
+ test_name << "testing message " << n;
+
+ ensure_does_not_contain(test_name.str(), mRecorder.message(n), expectedText);
+ }
+ };
+
+ typedef test_group<ErrorTestData> ErrorTestGroup;
+ typedef ErrorTestGroup::object ErrorTestObject;
+
+ ErrorTestGroup errorTestGroup("error");
+
+ template<> template<>
+ void ErrorTestObject::test<1>()
+ // basic test of output
+ {
+ llinfos << "test" << llendl;
+ llinfos << "bob" << llendl;
+
+ ensure_message_contains(0, "test");
+ ensure_message_contains(1, "bob");
+ }
+}
+
+namespace
+{
+ void writeSome()
+ {
+ lldebugs << "one" << llendl;
+ llinfos << "two" << llendl;
+ llwarns << "three" << llendl;
+ llerrs << "four" << llendl;
+ // fatal messages write out and addtional "error" message
+ }
+};
+
+namespace tut
+{
+ template<> template<>
+ void ErrorTestObject::test<2>()
+ // messages are filtered based on default level
+ {
+ LLError::setDefaultLevel(LLError::LEVEL_DEBUG);
+ writeSome();
+ ensure_message_contains(0, "one");
+ ensure_message_contains(1, "two");
+ ensure_message_contains(2, "three");
+ ensure_message_contains(3, "error");
+ ensure_message_contains(4, "four");
+ ensure_message_count(5);
+
+ LLError::setDefaultLevel(LLError::LEVEL_INFO);
+ writeSome();
+ ensure_message_contains(5, "two");
+ ensure_message_contains(6, "three");
+ ensure_message_contains(7, "error");
+ ensure_message_contains(8, "four");
+ ensure_message_count(9);
+
+ LLError::setDefaultLevel(LLError::LEVEL_WARN);
+ writeSome();
+ ensure_message_contains(9, "three");
+ ensure_message_contains(10, "error");
+ ensure_message_contains(11, "four");
+ ensure_message_count(12);
+
+ LLError::setDefaultLevel(LLError::LEVEL_ERROR);
+ writeSome();
+ ensure_message_contains(12, "error");
+ ensure_message_contains(13, "four");
+ ensure_message_count(14);
+
+ LLError::setDefaultLevel(LLError::LEVEL_NONE);
+ writeSome();
+ ensure_message_count(14);
+ }
+
+ template<> template<>
+ void ErrorTestObject::test<3>()
+ // error type string in output
+ {
+ writeSome();
+ ensure_message_contains(0, "DEBUG: ");
+ ensure_message_contains(1, "INFO: ");
+ ensure_message_contains(2, "WARNING: ");
+ ensure_message_does_not_contain(3, "ERROR");
+ ensure_message_contains(4, "ERROR: ");
+ ensure_message_count(5);
+ }
+
+ template<> template<>
+ void ErrorTestObject::test<4>()
+ // file abbreviation
+ {
+ std::string thisFile = __FILE__;
+ std::string abbreviateFile = LLError::abbreviateFile(thisFile);
+
+ ensure_ends_with("file name abbreviation",
+ abbreviateFile,
+ "llcommon/tests/llerror_test.cpp"
+ );
+ ensure_does_not_contain("file name abbreviation",
+ abbreviateFile, "indra");
+
+ std::string someFile =
+#if LL_WINDOWS
+ "C:/amy/bob/cam.cpp"
+#else
+ "/amy/bob/cam.cpp"
+#endif
+ ;
+ std::string someAbbreviation = LLError::abbreviateFile(someFile);
+
+ ensure_equals("non-indra file abbreviation",
+ someAbbreviation, someFile);
+ }
+}
+
+namespace
+{
+ std::string locationString(int line)
+ {
+ std::ostringstream location;
+ location << LLError::abbreviateFile(__FILE__)
+ << "(" << line << ") : ";
+
+ return location.str();
+ }
+
+ std::string writeReturningLocation()
+ {
+ llinfos << "apple" << llendl; int this_line = __LINE__;
+ return locationString(this_line);
+ }
+
+ std::string writeReturningLocationAndFunction()
+ {
+ llinfos << "apple" << llendl; int this_line = __LINE__;
+ return locationString(this_line) + __FUNCTION__;
+ }
+
+ std::string errorReturningLocation()
+ {
+ llerrs << "die" << llendl; int this_line = __LINE__;
+ return locationString(this_line);
+ }
+}
+
+namespace tut
+{
+ template<> template<>
+ void ErrorTestObject::test<5>()
+ // file and line information in log messages
+ {
+ std::string location = writeReturningLocation();
+ // expecting default to not print location information
+
+ LLError::setPrintLocation(true);
+ writeReturningLocation();
+
+ LLError::setPrintLocation(false);
+ writeReturningLocation();
+
+ ensure_message_does_not_contain(0, location);
+ ensure_message_contains(1, location);
+ ensure_message_does_not_contain(2, location);
+ }
+}
+
+/* The following helper functions and class members all log a simple message
+ from some particular function scope. Each function takes a bool argument
+ that indicates if it should log its own name or not (in the manner that
+ existing log messages often do.) The functions all return their C++
+ name so that test can be substantial mechanized.
+ */
+
+std::string logFromGlobal(bool id)
+{
+ llinfos << (id ? "logFromGlobal: " : "") << "hi" << llendl;
+ return "logFromGlobal";
+}
+
+static std::string logFromStatic(bool id)
+{
+ llinfos << (id ? "logFromStatic: " : "") << "hi" << llendl;
+ return "logFromStatic";
+}
+
+namespace
+{
+ std::string logFromAnon(bool id)
+ {
+ llinfos << (id ? "logFromAnon: " : "") << "hi" << llendl;
+ return "logFromAnon";
+ }
+}
+
+namespace Foo {
+ std::string logFromNamespace(bool id)
+ {
+ llinfos << (id ? "Foo::logFromNamespace: " : "") << "hi" << llendl;
+ //return "Foo::logFromNamespace";
+ // there is no standard way to get the namespace name, hence
+ // we won't be testing for it
+ return "logFromNamespace";
+ }
+}
+
+namespace
+{
+ class ClassWithNoLogType {
+ public:
+ std::string logFromMember(bool id)
+ {
+ llinfos << (id ? "ClassWithNoLogType::logFromMember: " : "") << "hi" << llendl;
+ return "ClassWithNoLogType::logFromMember";
+ }
+ static std::string logFromStatic(bool id)
+ {
+ llinfos << (id ? "ClassWithNoLogType::logFromStatic: " : "") << "hi" << llendl;
+ return "ClassWithNoLogType::logFromStatic";
+ }
+ };
+
+ class ClassWithLogType {
+ LOG_CLASS(ClassWithLogType);
+ public:
+ std::string logFromMember(bool id)
+ {
+ llinfos << (id ? "ClassWithLogType::logFromMember: " : "") << "hi" << llendl;
+ return "ClassWithLogType::logFromMember";
+ }
+ static std::string logFromStatic(bool id)
+ {
+ llinfos << (id ? "ClassWithLogType::logFromStatic: " : "") << "hi" << llendl;
+ return "ClassWithLogType::logFromStatic";
+ }
+ };
+
+ std::string logFromNamespace(bool id) { return Foo::logFromNamespace(id); }
+ std::string logFromClassWithNoLogTypeMember(bool id) { ClassWithNoLogType c; return c.logFromMember(id); }
+ std::string logFromClassWithNoLogTypeStatic(bool id) { return ClassWithNoLogType::logFromStatic(id); }
+ std::string logFromClassWithLogTypeMember(bool id) { ClassWithLogType c; return c.logFromMember(id); }
+ std::string logFromClassWithLogTypeStatic(bool id) { return ClassWithLogType::logFromStatic(id); }
+
+ void ensure_has(const std::string& message,
+ const std::string& actual, const std::string& expected)
+ {
+ std::string::size_type n1 = actual.find(expected);
+ if (n1 == std::string::npos)
+ {
+ std::stringstream ss;
+ ss << message << ": " << "expected to find a copy of " << expected
+ << " in actual " << actual;
+ throw tut::failure(ss.str().c_str());
+ }
+ }
+
+ typedef std::string (*LogFromFunction)(bool);
+ void testLogName(TestRecorder& recorder, LogFromFunction f,
+ const std::string& class_name = "")
+ {
+ recorder.clearMessages();
+ std::string name = f(false);
+ f(true);
+
+ std::string messageWithoutName = recorder.message(0);
+ std::string messageWithName = recorder.message(1);
+
+ ensure_has(name + " logged without name",
+ messageWithoutName, name);
+ ensure_has(name + " logged with name",
+ messageWithName, name);
+
+ if (!class_name.empty())
+ {
+ ensure_has(name + "logged without name",
+ messageWithoutName, class_name);
+ ensure_has(name + "logged with name",
+ messageWithName, class_name);
+ }
+ }
+}
+
+namespace tut
+{
+ template<> template<>
+ // class/function information in output
+ void ErrorTestObject::test<6>()
+ {
+ testLogName(mRecorder, logFromGlobal);
+ testLogName(mRecorder, logFromStatic);
+ testLogName(mRecorder, logFromAnon);
+ testLogName(mRecorder, logFromNamespace);
+ //testLogName(mRecorder, logFromClassWithNoLogTypeMember, "ClassWithNoLogType");
+ //testLogName(mRecorder, logFromClassWithNoLogTypeStatic, "ClassWithNoLogType");
+ // XXX: figure out what the exepcted response is for these
+ testLogName(mRecorder, logFromClassWithLogTypeMember, "ClassWithLogType");
+ testLogName(mRecorder, logFromClassWithLogTypeStatic, "ClassWithLogType");
+ }
+}
+
+namespace
+{
+ std::string innerLogger()
+ {
+ llinfos << "inside" << llendl;
+ return "moo";
+ }
+
+ std::string outerLogger()
+ {
+ llinfos << "outside(" << innerLogger() << ")" << llendl;
+ return "bar";
+ }
+
+ void uberLogger()
+ {
+ llinfos << "uber(" << outerLogger() << "," << innerLogger() << ")" << llendl;
+ }
+
+ class LogWhileLogging
+ {
+ public:
+ void print(std::ostream& out) const
+ {
+ llinfos << "logging" << llendl;
+ out << "baz";
+ }
+ };
+
+ std::ostream& operator<<(std::ostream& out, const LogWhileLogging& l)
+ { l.print(out); return out; }
+
+ void metaLogger()
+ {
+ LogWhileLogging l;
+ llinfos << "meta(" << l << ")" << llendl;
+ }
+
+}
+
+namespace tut
+{
+ template<> template<>
+ // handle nested logging
+ void ErrorTestObject::test<7>()
+ {
+ outerLogger();
+ ensure_message_contains(0, "inside");
+ ensure_message_contains(1, "outside(moo)");
+ ensure_message_count(2);
+
+ uberLogger();
+ ensure_message_contains(2, "inside");
+ ensure_message_contains(3, "inside");
+ ensure_message_contains(4, "outside(moo)");
+ ensure_message_contains(5, "uber(bar,moo)");
+ ensure_message_count(6);
+
+ metaLogger();
+ ensure_message_contains(6, "logging");
+ ensure_message_contains(7, "meta(baz)");
+ ensure_message_count(8);
+ }
+
+ template<> template<>
+ // special handling of llerrs calls
+ void ErrorTestObject::test<8>()
+ {
+ LLError::setPrintLocation(false);
+ std::string location = errorReturningLocation();
+
+ ensure_message_contains(0, location + "error");
+ ensure_message_contains(1, "die");
+ ensure_message_count(2);
+
+ ensure("fatal callback called", fatalWasCalled);
+ }
+}
+
+namespace
+{
+ std::string roswell()
+ {
+ return "1947-07-08T03:04:05Z";
+ }
+
+ void ufoSighting()
+ {
+ llinfos << "ufo" << llendl;
+ }
+}
+
+namespace tut
+{
+ template<> template<>
+ // time in output (for recorders that need it)
+ void ErrorTestObject::test<9>()
+ {
+ LLError::setTimeFunction(roswell);
+
+ mRecorder.setWantsTime(false);
+ ufoSighting();
+ ensure_message_contains(0, "ufo");
+ ensure_message_does_not_contain(0, roswell());
+
+ mRecorder.setWantsTime(true);
+ ufoSighting();
+ ensure_message_contains(1, "ufo");
+ ensure_message_contains(1, roswell());
+ }
+
+ template<> template<>
+ // output order
+ void ErrorTestObject::test<10>()
+ {
+ LLError::setPrintLocation(true);
+ LLError::setTimeFunction(roswell);
+ mRecorder.setWantsTime(true);
+ std::string locationAndFunction = writeReturningLocationAndFunction();
+
+ ensure_equals("order is time type location function message",
+ mRecorder.message(0),
+ roswell() + " INFO: " + locationAndFunction + ": apple");
+ }
+
+ template<> template<>
+ // multiple recorders
+ void ErrorTestObject::test<11>()
+ {
+ TestRecorder altRecorder;
+ LLError::addRecorder(&altRecorder);
+
+ llinfos << "boo" << llendl;
+
+ ensure_message_contains(0, "boo");
+ ensure_equals("alt recorder count", altRecorder.countMessages(), 1);
+ ensure_contains("alt recorder message 0", altRecorder.message(0), "boo");
+
+ LLError::setTimeFunction(roswell);
+
+ TestRecorder anotherRecorder;
+ anotherRecorder.setWantsTime(true);
+ LLError::addRecorder(&anotherRecorder);
+
+ llinfos << "baz" << llendl;
+
+ std::string when = roswell();
+
+ ensure_message_does_not_contain(1, when);
+ ensure_equals("alt recorder count", altRecorder.countMessages(), 2);
+ ensure_does_not_contain("alt recorder message 1", altRecorder.message(1), when);
+ ensure_equals("another recorder count", anotherRecorder.countMessages(), 1);
+ ensure_contains("another recorder message 0", anotherRecorder.message(0), when);
+ }
+}
+
+class TestAlpha
+{
+ LOG_CLASS(TestAlpha);
+public:
+ static void doDebug() { lldebugs << "add dice" << llendl; }
+ static void doInfo() { llinfos << "any idea" << llendl; }
+ static void doWarn() { llwarns << "aim west" << llendl; }
+ static void doError() { llerrs << "ate eels" << llendl; }
+ static void doAll() { doDebug(); doInfo(); doWarn(); doError(); }
+};
+
+class TestBeta
+{
+ LOG_CLASS(TestBeta);
+public:
+ static void doDebug() { lldebugs << "bed down" << llendl; }
+ static void doInfo() { llinfos << "buy iron" << llendl; }
+ static void doWarn() { llwarns << "bad word" << llendl; }
+ static void doError() { llerrs << "big easy" << llendl; }
+ static void doAll() { doDebug(); doInfo(); doWarn(); doError(); }
+};
+
+namespace tut
+{
+ template<> template<>
+ // filtering by class
+ void ErrorTestObject::test<12>()
+ {
+ LLError::setDefaultLevel(LLError::LEVEL_WARN);
+ LLError::setClassLevel("TestBeta", LLError::LEVEL_INFO);
+
+ TestAlpha::doAll();
+ TestBeta::doAll();
+
+ ensure_message_contains(0, "aim west");
+ ensure_message_contains(1, "error");
+ ensure_message_contains(2, "ate eels");
+ ensure_message_contains(3, "buy iron");
+ ensure_message_contains(4, "bad word");
+ ensure_message_contains(5, "error");
+ ensure_message_contains(6, "big easy");
+ ensure_message_count(7);
+ }
+
+ template<> template<>
+ // filtering by function, and that it will override class filtering
+ void ErrorTestObject::test<13>()
+ {
+ LLError::setDefaultLevel(LLError::LEVEL_DEBUG);
+ LLError::setClassLevel("TestBeta", LLError::LEVEL_WARN);
+ LLError::setFunctionLevel("TestBeta::doInfo", LLError::LEVEL_DEBUG);
+ LLError::setFunctionLevel("TestBeta::doError", LLError::LEVEL_NONE);
+
+ TestBeta::doAll();
+ ensure_message_contains(0, "buy iron");
+ ensure_message_contains(1, "bad word");
+ ensure_message_count(2);
+ }
+
+ template<> template<>
+ // filtering by file
+ // and that it is overridden by both class and function filtering
+ void ErrorTestObject::test<14>()
+ {
+ LLError::setDefaultLevel(LLError::LEVEL_DEBUG);
+ LLError::setFileLevel(LLError::abbreviateFile(__FILE__),
+ LLError::LEVEL_WARN);
+ LLError::setClassLevel("TestAlpha", LLError::LEVEL_INFO);
+ LLError::setFunctionLevel("TestAlpha::doError",
+ LLError::LEVEL_NONE);
+ LLError::setFunctionLevel("TestBeta::doError",
+ LLError::LEVEL_NONE);
+
+ TestAlpha::doAll();
+ TestBeta::doAll();
+ ensure_message_contains(0, "any idea");
+ ensure_message_contains(1, "aim west");
+ ensure_message_contains(2, "bad word");
+ ensure_message_count(3);
+ }
+
+ template<> template<>
+ // proper cached, efficient lookup of filtering
+ void ErrorTestObject::test<15>()
+ {
+ LLError::setDefaultLevel(LLError::LEVEL_NONE);
+
+ TestAlpha::doInfo();
+ ensure_message_count(0);
+ ensure_equals("first check", LLError::shouldLogCallCount(), 1);
+ TestAlpha::doInfo();
+ ensure_message_count(0);
+ ensure_equals("second check", LLError::shouldLogCallCount(), 1);
+
+ LLError::setClassLevel("TestAlpha", LLError::LEVEL_DEBUG);
+ TestAlpha::doInfo();
+ ensure_message_count(1);
+ ensure_equals("third check", LLError::shouldLogCallCount(), 2);
+ TestAlpha::doInfo();
+ ensure_message_count(2);
+ ensure_equals("fourth check", LLError::shouldLogCallCount(), 2);
+
+ LLError::setClassLevel("TestAlpha", LLError::LEVEL_WARN);
+ TestAlpha::doInfo();
+ ensure_message_count(2);
+ ensure_equals("fifth check", LLError::shouldLogCallCount(), 3);
+ TestAlpha::doInfo();
+ ensure_message_count(2);
+ ensure_equals("sixth check", LLError::shouldLogCallCount(), 3);
+ }
+
+ template<> template<>
+ // configuration from LLSD
+ void ErrorTestObject::test<16>()
+ {
+ std::string this_file = LLError::abbreviateFile(__FILE__);
+ LLSD config;
+ config["print-location"] = true;
+ config["default-level"] = "DEBUG";
+
+ LLSD set1;
+ set1["level"] = "WARN";
+ set1["files"][0] = this_file;
+
+ LLSD set2;
+ set2["level"] = "INFO";
+ set2["classes"][0] = "TestAlpha";
+
+ LLSD set3;
+ set3["level"] = "NONE";
+ set3["functions"][0] = "TestAlpha::doError";
+ set3["functions"][1] = "TestBeta::doError";
+
+ config["settings"][0] = set1;
+ config["settings"][1] = set2;
+ config["settings"][2] = set3;
+
+ LLError::configure(config);
+
+ TestAlpha::doAll();
+ TestBeta::doAll();
+ ensure_message_contains(0, "any idea");
+ ensure_message_contains(0, this_file);
+ ensure_message_contains(1, "aim west");
+ ensure_message_contains(2, "bad word");
+ ensure_message_count(3);
+
+ // make sure reconfiguring works
+ LLSD config2;
+ config2["default-level"] = "WARN";
+
+ LLError::configure(config2);
+
+ TestAlpha::doAll();
+ TestBeta::doAll();
+ ensure_message_contains(3, "aim west");
+ ensure_message_does_not_contain(3, this_file);
+ ensure_message_contains(4, "error");
+ ensure_message_contains(5, "ate eels");
+ ensure_message_contains(6, "bad word");
+ ensure_message_contains(7, "error");
+ ensure_message_contains(8, "big easy");
+ ensure_message_count(9);
+ }
+}
+
+/* Tests left:
+ handling of classes without LOG_CLASS
+
+ live update of filtering from file
+
+ syslog recorder
+ file recorder
+ cerr/stderr recorder
+ fixed buffer recorder
+ windows recorder
+
+ mutex use when logging (?)
+ strange careful about to crash handling (?)
+*/
diff --git a/indra/llcommon/tests/lleventcoro_test.cpp b/indra/llcommon/tests/lleventcoro_test.cpp
new file mode 100644
index 0000000000..901ba35b2f
--- /dev/null
+++ b/indra/llcommon/tests/lleventcoro_test.cpp
@@ -0,0 +1,799 @@
+/**
+ * @file coroutine_test.cpp
+ * @author Nat Goodspeed
+ * @date 2009-04-22
+ * @brief Test for coroutine.
+ *
+ * $LicenseInfo:firstyear=2009&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$
+ */
+
+/*****************************************************************************/
+// test<1>() is cloned from a Boost.Coroutine example program whose copyright
+// info is reproduced here:
+/*---------------------------------------------------------------------------*/
+// Copyright (c) 2006, Giovanni P. Deretta
+//
+// This code may be used under either of the following two licences:
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE. OF SUCH DAMAGE.
+//
+// Or:
+//
+// Distributed under the Boost Software License, Version 1.0.
+// (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+/*****************************************************************************/
+
+// On some platforms, Boost.Coroutine must #define magic symbols before
+// #including platform-API headers. Naturally, that's ineffective unless the
+// Boost.Coroutine #include is the *first* #include of the platform header.
+// That means that client code must generally #include Boost.Coroutine headers
+// before anything else.
+#include <boost/coroutine/coroutine.hpp>
+// Normally, lleventcoro.h obviates future.hpp. We only include this because
+// we implement a "by hand" test of future functionality.
+#include <boost/coroutine/future.hpp>
+#include <boost/bind.hpp>
+#include <boost/range.hpp>
+
+#include "linden_common.h"
+
+#include <iostream>
+#include <string>
+
+#include "../test/lltut.h"
+#include "llsd.h"
+#include "llevents.h"
+#include "tests/wrapllerrs.h"
+#include "stringize.h"
+#include "lleventcoro.h"
+#include "../test/debug.h"
+
+/*****************************************************************************
+* from the banana.cpp example program borrowed for test<1>()
+*****************************************************************************/
+namespace coroutines = boost::coroutines;
+using coroutines::coroutine;
+
+template<typename Iter>
+bool match(Iter first, Iter last, std::string match) {
+ std::string::iterator i = match.begin();
+ i != match.end();
+ for(; (first != last) && (i != match.end()); ++i) {
+ if (*first != *i)
+ return false;
+ ++first;
+ }
+ return i == match.end();
+}
+
+template<typename BidirectionalIterator>
+BidirectionalIterator
+match_substring(BidirectionalIterator begin,
+ BidirectionalIterator end,
+ std::string xmatch,
+ BOOST_DEDUCED_TYPENAME coroutine<BidirectionalIterator(void)>::self& self) {
+ BidirectionalIterator begin_ = begin;
+ for(; begin != end; ++begin)
+ if(match(begin, end, xmatch)) {
+ self.yield(begin);
+ }
+ return end;
+}
+
+typedef coroutine<std::string::iterator(void)> match_coroutine_type;
+
+/*****************************************************************************
+* Test helpers
+*****************************************************************************/
+// I suspect this will be typical of coroutines used in Linden software
+typedef boost::coroutines::coroutine<void()> coroutine_type;
+
+/// Simulate an event API whose response is immediate: sent on receipt of the
+/// initial request, rather than after some delay. This is the case that
+/// distinguishes postAndWait() from calling post(), then calling
+/// waitForEventOn().
+class ImmediateAPI
+{
+public:
+ ImmediateAPI():
+ mPump("immediate", true)
+ {
+ mPump.listen("API", boost::bind(&ImmediateAPI::operator(), this, _1));
+ }
+
+ LLEventPump& getPump() { return mPump; }
+
+ // Invoke this with an LLSD map containing:
+ // ["value"]: Integer value. We will reply with ["value"] + 1.
+ // ["reply"]: Name of LLEventPump on which to send success response.
+ // ["error"]: Name of LLEventPump on which to send error response.
+ // ["fail"]: Presence of this key selects ["error"], else ["success"] as
+ // the name of the pump on which to send the response.
+ bool operator()(const LLSD& event) const
+ {
+ LLSD::Integer value(event["value"]);
+ LLSD::String replyPumpName(event.has("fail")? "error" : "reply");
+ LLEventPumps::instance().obtain(event[replyPumpName]).post(value + 1);
+ return false;
+ }
+
+private:
+ LLEventStream mPump;
+};
+
+/*****************************************************************************
+* TUT
+*****************************************************************************/
+namespace tut
+{
+ struct coroutine_data
+ {
+ // Define coroutine bodies as methods here so they can use ensure*()
+
+ void explicit_wait(coroutine_type::self& self)
+ {
+ BEGIN
+ {
+ // ... do whatever preliminary stuff must happen ...
+
+ // declare the future
+ boost::coroutines::future<LLSD> future(self);
+ // tell the future what to wait for
+ LLTempBoundListener connection(
+ LLEventPumps::instance().obtain("source").listen("coro", voidlistener(boost::coroutines::make_callback(future))));
+ ensure("Not yet", ! future);
+ // attempting to dereference ("resolve") the future causes the calling
+ // coroutine to wait for it
+ debug("about to wait");
+ result = *future;
+ ensure("Got it", future);
+ }
+ END
+ }
+
+ void waitForEventOn1(coroutine_type::self& self)
+ {
+ BEGIN
+ {
+ result = waitForEventOn(self, "source");
+ }
+ END
+ }
+
+ void waitForEventOn2(coroutine_type::self& self)
+ {
+ BEGIN
+ {
+ LLEventWithID pair = waitForEventOn(self, "reply", "error");
+ result = pair.first;
+ which = pair.second;
+ debug(STRINGIZE("result = " << result << ", which = " << which));
+ }
+ END
+ }
+
+ void postAndWait1(coroutine_type::self& self)
+ {
+ BEGIN
+ {
+ result = postAndWait(self,
+ LLSD().insert("value", 17), // request event
+ immediateAPI.getPump(), // requestPump
+ "reply1", // replyPump
+ "reply"); // request["reply"] = name
+ }
+ END
+ }
+
+ void postAndWait2(coroutine_type::self& self)
+ {
+ BEGIN
+ {
+ LLEventWithID pair = ::postAndWait2(self,
+ LLSD().insert("value", 18),
+ immediateAPI.getPump(),
+ "reply2",
+ "error2",
+ "reply",
+ "error");
+ result = pair.first;
+ which = pair.second;
+ debug(STRINGIZE("result = " << result << ", which = " << which));
+ }
+ END
+ }
+
+ void postAndWait2_1(coroutine_type::self& self)
+ {
+ BEGIN
+ {
+ LLEventWithID pair = ::postAndWait2(self,
+ LLSD().insert("value", 18).insert("fail", LLSD()),
+ immediateAPI.getPump(),
+ "reply2",
+ "error2",
+ "reply",
+ "error");
+ result = pair.first;
+ which = pair.second;
+ debug(STRINGIZE("result = " << result << ", which = " << which));
+ }
+ END
+ }
+
+ void coroPump(coroutine_type::self& self)
+ {
+ BEGIN
+ {
+ LLCoroEventPump waiter;
+ replyName = waiter.getName();
+ result = waiter.wait(self);
+ }
+ END
+ }
+
+ void coroPumpPost(coroutine_type::self& self)
+ {
+ BEGIN
+ {
+ LLCoroEventPump waiter;
+ result = waiter.postAndWait(self, LLSD().insert("value", 17),
+ immediateAPI.getPump(), "reply");
+ }
+ END
+ }
+
+ void coroPumps(coroutine_type::self& self)
+ {
+ BEGIN
+ {
+ LLCoroEventPumps waiter;
+ replyName = waiter.getName0();
+ errorName = waiter.getName1();
+ LLEventWithID pair(waiter.wait(self));
+ result = pair.first;
+ which = pair.second;
+ }
+ END
+ }
+
+ void coroPumpsNoEx(coroutine_type::self& self)
+ {
+ BEGIN
+ {
+ LLCoroEventPumps waiter;
+ replyName = waiter.getName0();
+ errorName = waiter.getName1();
+ result = waiter.waitWithException(self);
+ }
+ END
+ }
+
+ void coroPumpsEx(coroutine_type::self& self)
+ {
+ BEGIN
+ {
+ LLCoroEventPumps waiter;
+ replyName = waiter.getName0();
+ errorName = waiter.getName1();
+ try
+ {
+ result = waiter.waitWithException(self);
+ debug("no exception");
+ }
+ catch (const LLErrorEvent& e)
+ {
+ debug(STRINGIZE("exception " << e.what()));
+ errordata = e.getData();
+ }
+ }
+ END
+ }
+
+ void coroPumpsNoLog(coroutine_type::self& self)
+ {
+ BEGIN
+ {
+ LLCoroEventPumps waiter;
+ replyName = waiter.getName0();
+ errorName = waiter.getName1();
+ result = waiter.waitWithLog(self);
+ }
+ END
+ }
+
+ void coroPumpsLog(coroutine_type::self& self)
+ {
+ BEGIN
+ {
+ LLCoroEventPumps waiter;
+ replyName = waiter.getName0();
+ errorName = waiter.getName1();
+ WrapLL_ERRS capture;
+ try
+ {
+ result = waiter.waitWithLog(self);
+ debug("no exception");
+ }
+ catch (const WrapLL_ERRS::FatalException& e)
+ {
+ debug(STRINGIZE("exception " << e.what()));
+ threw = e.what();
+ }
+ }
+ END
+ }
+
+ void coroPumpsPost(coroutine_type::self& self)
+ {
+ BEGIN
+ {
+ LLCoroEventPumps waiter;
+ LLEventWithID pair(waiter.postAndWait(self, LLSD().insert("value", 23),
+ immediateAPI.getPump(), "reply", "error"));
+ result = pair.first;
+ which = pair.second;
+ }
+ END
+ }
+
+ void coroPumpsPost_1(coroutine_type::self& self)
+ {
+ BEGIN
+ {
+ LLCoroEventPumps waiter;
+ LLEventWithID pair(
+ waiter.postAndWait(self, LLSD().insert("value", 23).insert("fail", LLSD()),
+ immediateAPI.getPump(), "reply", "error"));
+ result = pair.first;
+ which = pair.second;
+ }
+ END
+ }
+
+ void coroPumpsPostNoEx(coroutine_type::self& self)
+ {
+ BEGIN
+ {
+ LLCoroEventPumps waiter;
+ result = waiter.postAndWaitWithException(self, LLSD().insert("value", 8),
+ immediateAPI.getPump(), "reply", "error");
+ }
+ END
+ }
+
+ void coroPumpsPostEx(coroutine_type::self& self)
+ {
+ BEGIN
+ {
+ LLCoroEventPumps waiter;
+ try
+ {
+ result = waiter.postAndWaitWithException(self,
+ LLSD().insert("value", 9).insert("fail", LLSD()),
+ immediateAPI.getPump(), "reply", "error");
+ debug("no exception");
+ }
+ catch (const LLErrorEvent& e)
+ {
+ debug(STRINGIZE("exception " << e.what()));
+ errordata = e.getData();
+ }
+ }
+ END
+ }
+
+ void coroPumpsPostNoLog(coroutine_type::self& self)
+ {
+ BEGIN
+ {
+ LLCoroEventPumps waiter;
+ result = waiter.postAndWaitWithLog(self, LLSD().insert("value", 30),
+ immediateAPI.getPump(), "reply", "error");
+ }
+ END
+ }
+
+ void coroPumpsPostLog(coroutine_type::self& self)
+ {
+ BEGIN
+ {
+ LLCoroEventPumps waiter;
+ WrapLL_ERRS capture;
+ try
+ {
+ result = waiter.postAndWaitWithLog(self,
+ LLSD().insert("value", 31).insert("fail", LLSD()),
+ immediateAPI.getPump(), "reply", "error");
+ debug("no exception");
+ }
+ catch (const WrapLL_ERRS::FatalException& e)
+ {
+ debug(STRINGIZE("exception " << e.what()));
+ threw = e.what();
+ }
+ }
+ END
+ }
+
+ void ensure_done(coroutine_type& coro)
+ {
+ ensure("coroutine complete", ! coro);
+ }
+
+ ImmediateAPI immediateAPI;
+ std::string replyName, errorName, threw;
+ LLSD result, errordata;
+ int which;
+ };
+ typedef test_group<coroutine_data> coroutine_group;
+ typedef coroutine_group::object object;
+ coroutine_group coroutinegrp("coroutine");
+
+ template<> template<>
+ void object::test<1>()
+ {
+ set_test_name("From banana.cpp example program in Boost.Coroutine distro");
+ std::string buffer = "banananana";
+ std::string match = "nana";
+ std::string::iterator begin = buffer.begin();
+ std::string::iterator end = buffer.end();
+
+#if defined(BOOST_CORO_POSIX_IMPL)
+// std::cout << "Using Boost.Coroutine " << BOOST_CORO_POSIX_IMPL << '\n';
+#else
+// std::cout << "Using non-Posix Boost.Coroutine implementation" << std::endl;
+#endif
+
+ typedef std::string::iterator signature(std::string::iterator,
+ std::string::iterator,
+ std::string,
+ match_coroutine_type::self&);
+
+ coroutine<std::string::iterator(void)> matcher
+ (boost::bind(static_cast<signature*>(match_substring),
+ begin,
+ end,
+ match,
+ _1));
+
+ std::string::iterator i = matcher();
+/*==========================================================================*|
+ while(matcher && i != buffer.end()) {
+ std::cout <<"Match at: "<< std::distance(buffer.begin(), i)<<'\n';
+ i = matcher();
+ }
+|*==========================================================================*/
+ size_t matches[] = { 2, 4, 6 };
+ for (size_t *mi(boost::begin(matches)), *mend(boost::end(matches));
+ mi != mend; ++mi, i = matcher())
+ {
+ ensure("more", matcher);
+ ensure("found", i != buffer.end());
+ ensure_equals("value", std::distance(buffer.begin(), i), *mi);
+ }
+ ensure("done", ! matcher);
+ }
+
+ template<> template<>
+ void object::test<2>()
+ {
+ set_test_name("explicit_wait");
+ DEBUG;
+
+ // Construct the coroutine instance that will run explicit_wait.
+ // Pass the ctor a callable that accepts the coroutine_type::self
+ // param passed by the library.
+ coroutine_type coro(boost::bind(&coroutine_data::explicit_wait, this, _1));
+ // Start the coroutine
+ coro(std::nothrow);
+ // When the coroutine waits for the event pump, it returns here.
+ debug("about to send");
+ // Satisfy the wait.
+ LLEventPumps::instance().obtain("source").post("received");
+ // Now wait for the coroutine to complete.
+ ensure_done(coro);
+ // ensure the coroutine ran and woke up again with the intended result
+ ensure_equals(result.asString(), "received");
+ }
+
+ template<> template<>
+ void object::test<3>()
+ {
+ set_test_name("waitForEventOn1");
+ DEBUG;
+ coroutine_type coro(boost::bind(&coroutine_data::waitForEventOn1, this, _1));
+ coro(std::nothrow);
+ debug("about to send");
+ LLEventPumps::instance().obtain("source").post("received");
+ debug("back from send");
+ ensure_done(coro);
+ ensure_equals(result.asString(), "received");
+ }
+
+ template<> template<>
+ void object::test<4>()
+ {
+ set_test_name("waitForEventOn2 reply");
+ {
+ DEBUG;
+ coroutine_type coro(boost::bind(&coroutine_data::waitForEventOn2, this, _1));
+ coro(std::nothrow);
+ debug("about to send");
+ LLEventPumps::instance().obtain("reply").post("received");
+ debug("back from send");
+ ensure_done(coro);
+ }
+ ensure_equals(result.asString(), "received");
+ ensure_equals("which pump", which, 0);
+ }
+
+ template<> template<>
+ void object::test<5>()
+ {
+ set_test_name("waitForEventOn2 error");
+ DEBUG;
+ coroutine_type coro(boost::bind(&coroutine_data::waitForEventOn2, this, _1));
+ coro(std::nothrow);
+ debug("about to send");
+ LLEventPumps::instance().obtain("error").post("badness");
+ debug("back from send");
+ ensure_done(coro);
+ ensure_equals(result.asString(), "badness");
+ ensure_equals("which pump", which, 1);
+ }
+
+ template<> template<>
+ void object::test<6>()
+ {
+ set_test_name("coroPump");
+ DEBUG;
+ coroutine_type coro(boost::bind(&coroutine_data::coroPump, this, _1));
+ coro(std::nothrow);
+ debug("about to send");
+ LLEventPumps::instance().obtain(replyName).post("received");
+ debug("back from send");
+ ensure_done(coro);
+ ensure_equals(result.asString(), "received");
+ }
+
+ template<> template<>
+ void object::test<7>()
+ {
+ set_test_name("coroPumps reply");
+ DEBUG;
+ coroutine_type coro(boost::bind(&coroutine_data::coroPumps, this, _1));
+ coro(std::nothrow);
+ debug("about to send");
+ LLEventPumps::instance().obtain(replyName).post("received");
+ debug("back from send");
+ ensure_done(coro);
+ ensure_equals(result.asString(), "received");
+ ensure_equals("which pump", which, 0);
+ }
+
+ template<> template<>
+ void object::test<8>()
+ {
+ set_test_name("coroPumps error");
+ DEBUG;
+ coroutine_type coro(boost::bind(&coroutine_data::coroPumps, this, _1));
+ coro(std::nothrow);
+ debug("about to send");
+ LLEventPumps::instance().obtain(errorName).post("badness");
+ debug("back from send");
+ ensure_done(coro);
+ ensure_equals(result.asString(), "badness");
+ ensure_equals("which pump", which, 1);
+ }
+
+ template<> template<>
+ void object::test<9>()
+ {
+ set_test_name("coroPumpsNoEx");
+ DEBUG;
+ coroutine_type coro(boost::bind(&coroutine_data::coroPumpsNoEx, this, _1));
+ coro(std::nothrow);
+ debug("about to send");
+ LLEventPumps::instance().obtain(replyName).post("received");
+ debug("back from send");
+ ensure_done(coro);
+ ensure_equals(result.asString(), "received");
+ }
+
+ template<> template<>
+ void object::test<10>()
+ {
+ set_test_name("coroPumpsEx");
+ DEBUG;
+ coroutine_type coro(boost::bind(&coroutine_data::coroPumpsEx, this, _1));
+ coro(std::nothrow);
+ debug("about to send");
+ LLEventPumps::instance().obtain(errorName).post("badness");
+ debug("back from send");
+ ensure_done(coro);
+ ensure("no result", result.isUndefined());
+ ensure_equals("got error", errordata.asString(), "badness");
+ }
+
+ template<> template<>
+ void object::test<11>()
+ {
+ set_test_name("coroPumpsNoLog");
+ DEBUG;
+ coroutine_type coro(boost::bind(&coroutine_data::coroPumpsNoLog, this, _1));
+ coro(std::nothrow);
+ debug("about to send");
+ LLEventPumps::instance().obtain(replyName).post("received");
+ debug("back from send");
+ ensure_done(coro);
+ ensure_equals(result.asString(), "received");
+ }
+
+ template<> template<>
+ void object::test<12>()
+ {
+ set_test_name("coroPumpsLog");
+ DEBUG;
+ coroutine_type coro(boost::bind(&coroutine_data::coroPumpsLog, this, _1));
+ coro(std::nothrow);
+ debug("about to send");
+ LLEventPumps::instance().obtain(errorName).post("badness");
+ debug("back from send");
+ ensure_done(coro);
+ ensure("no result", result.isUndefined());
+ ensure_contains("got error", threw, "badness");
+ }
+
+ template<> template<>
+ void object::test<13>()
+ {
+ set_test_name("postAndWait1");
+ DEBUG;
+ coroutine_type coro(boost::bind(&coroutine_data::postAndWait1, this, _1));
+ coro(std::nothrow);
+ ensure_done(coro);
+ ensure_equals(result.asInteger(), 18);
+ }
+
+ template<> template<>
+ void object::test<14>()
+ {
+ set_test_name("postAndWait2");
+ DEBUG;
+ coroutine_type coro(boost::bind(&coroutine_data::postAndWait2, this, _1));
+ coro(std::nothrow);
+ ensure_done(coro);
+ ensure_equals(result.asInteger(), 19);
+ ensure_equals(which, 0);
+ }
+
+ template<> template<>
+ void object::test<15>()
+ {
+ set_test_name("postAndWait2_1");
+ DEBUG;
+ coroutine_type coro(boost::bind(&coroutine_data::postAndWait2_1, this, _1));
+ coro(std::nothrow);
+ ensure_done(coro);
+ ensure_equals(result.asInteger(), 19);
+ ensure_equals(which, 1);
+ }
+
+ template<> template<>
+ void object::test<16>()
+ {
+ set_test_name("coroPumpPost");
+ DEBUG;
+ coroutine_type coro(boost::bind(&coroutine_data::coroPumpPost, this, _1));
+ coro(std::nothrow);
+ ensure_done(coro);
+ ensure_equals(result.asInteger(), 18);
+ }
+
+ template<> template<>
+ void object::test<17>()
+ {
+ set_test_name("coroPumpsPost reply");
+ DEBUG;
+ coroutine_type coro(boost::bind(&coroutine_data::coroPumpsPost, this, _1));
+ coro(std::nothrow);
+ ensure_done(coro);
+ ensure_equals(result.asInteger(), 24);
+ ensure_equals("which pump", which, 0);
+ }
+
+ template<> template<>
+ void object::test<18>()
+ {
+ set_test_name("coroPumpsPost error");
+ DEBUG;
+ coroutine_type coro(boost::bind(&coroutine_data::coroPumpsPost_1, this, _1));
+ coro(std::nothrow);
+ ensure_done(coro);
+ ensure_equals(result.asInteger(), 24);
+ ensure_equals("which pump", which, 1);
+ }
+
+ template<> template<>
+ void object::test<19>()
+ {
+ set_test_name("coroPumpsPostNoEx");
+ DEBUG;
+ coroutine_type coro(boost::bind(&coroutine_data::coroPumpsPostNoEx, this, _1));
+ coro(std::nothrow);
+ ensure_done(coro);
+ ensure_equals(result.asInteger(), 9);
+ }
+
+ template<> template<>
+ void object::test<20>()
+ {
+ set_test_name("coroPumpsPostEx");
+ DEBUG;
+ coroutine_type coro(boost::bind(&coroutine_data::coroPumpsPostEx, this, _1));
+ coro(std::nothrow);
+ ensure_done(coro);
+ ensure("no result", result.isUndefined());
+ ensure_equals("got error", errordata.asInteger(), 10);
+ }
+
+ template<> template<>
+ void object::test<21>()
+ {
+ set_test_name("coroPumpsPostNoLog");
+ DEBUG;
+ coroutine_type coro(boost::bind(&coroutine_data::coroPumpsPostNoLog, this, _1));
+ coro(std::nothrow);
+ ensure_done(coro);
+ ensure_equals(result.asInteger(), 31);
+ }
+
+ template<> template<>
+ void object::test<22>()
+ {
+ set_test_name("coroPumpsPostLog");
+ DEBUG;
+ coroutine_type coro(boost::bind(&coroutine_data::coroPumpsPostLog, this, _1));
+ coro(std::nothrow);
+ ensure_done(coro);
+ ensure("no result", result.isUndefined());
+ ensure_contains("got error", threw, "32");
+ }
+} // namespace tut
diff --git a/indra/llcommon/tests/lleventfilter_test.cpp b/indra/llcommon/tests/lleventfilter_test.cpp
new file mode 100644
index 0000000000..ca05ef62a9
--- /dev/null
+++ b/indra/llcommon/tests/lleventfilter_test.cpp
@@ -0,0 +1,293 @@
+/**
+ * @file lleventfilter_test.cpp
+ * @author Nat Goodspeed
+ * @date 2009-03-06
+ * @brief Test for lleventfilter.
+ *
+ * $LicenseInfo:firstyear=2009&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$
+ */
+
+// Precompiled header
+#include "linden_common.h"
+// associated header
+#include "lleventfilter.h"
+// STL headers
+// std headers
+// external library headers
+// other Linden headers
+#include "../test/lltut.h"
+#include "stringize.h"
+#include "listener.h"
+#include "tests/wrapllerrs.h"
+
+/*****************************************************************************
+* Test classes
+*****************************************************************************/
+// Strictly speaking, we're testing LLEventTimeoutBase rather than the
+// production LLEventTimeout (using LLTimer) because we don't want every test
+// run to pause for some number of seconds until we reach a real timeout. But
+// as we've carefully put all functionality except actual LLTimer calls into
+// LLEventTimeoutBase, that should suffice. We're not not not trying to test
+// LLTimer here.
+class TestEventTimeout: public LLEventTimeoutBase
+{
+public:
+ TestEventTimeout():
+ mElapsed(true)
+ {}
+ TestEventTimeout(LLEventPump& source):
+ LLEventTimeoutBase(source),
+ mElapsed(true)
+ {}
+
+ // test hook
+ void forceTimeout(bool timeout=true) { mElapsed = timeout; }
+
+protected:
+ virtual void setCountdown(F32 seconds) { mElapsed = false; }
+ virtual bool countdownElapsed() const { return mElapsed; }
+
+private:
+ bool mElapsed;
+};
+
+/*****************************************************************************
+* TUT
+*****************************************************************************/
+namespace tut
+{
+ struct filter_data
+ {
+ // The resemblance between this test data and that in llevents_tut.cpp
+ // is not coincidental.
+ filter_data():
+ pumps(LLEventPumps::instance()),
+ mainloop(pumps.obtain("mainloop")),
+ listener0("first"),
+ listener1("second")
+ {}
+ LLEventPumps& pumps;
+ LLEventPump& mainloop;
+ Listener listener0;
+ Listener listener1;
+
+ void check_listener(const std::string& desc, const Listener& listener, const LLSD& got)
+ {
+ ensure_equals(STRINGIZE(listener << ' ' << desc),
+ listener.getLastEvent(), got);
+ }
+ };
+ typedef test_group<filter_data> filter_group;
+ typedef filter_group::object filter_object;
+ filter_group filtergrp("lleventfilter");
+
+ template<> template<>
+ void filter_object::test<1>()
+ {
+ set_test_name("LLEventMatching");
+ LLEventPump& driver(pumps.obtain("driver"));
+ listener0.reset(0);
+ // Listener isn't derived from LLEventTrackable specifically to test
+ // various connection-management mechanisms. But that means we have a
+ // couple of transient Listener objects, one of which is listening to
+ // a persistent LLEventPump. Capture those connections in local
+ // LLTempBoundListener instances so they'll disconnect
+ // on destruction.
+ LLTempBoundListener temp1(
+ listener0.listenTo(driver));
+ // Construct a pattern LLSD: desired Event must have a key "foo"
+ // containing string "bar"
+ LLEventMatching filter(driver, LLSD().insert("foo", "bar"));
+ listener1.reset(0);
+ LLTempBoundListener temp2(
+ listener1.listenTo(filter));
+ driver.post(1);
+ check_listener("direct", listener0, LLSD(1));
+ check_listener("filtered", listener1, LLSD(0));
+ // Okay, construct an LLSD map matching the pattern
+ LLSD data;
+ data["foo"] = "bar";
+ data["random"] = 17;
+ driver.post(data);
+ check_listener("direct", listener0, data);
+ check_listener("filtered", listener1, data);
+ }
+
+ template<> template<>
+ void filter_object::test<2>()
+ {
+ set_test_name("LLEventTimeout::actionAfter()");
+ LLEventPump& driver(pumps.obtain("driver"));
+ TestEventTimeout filter(driver);
+ listener0.reset(0);
+ LLTempBoundListener temp1(
+ listener0.listenTo(filter));
+ // Use listener1.call() as the Action for actionAfter(), since it
+ // already provides a way to sense the call
+ listener1.reset(0);
+ // driver --> filter --> listener0
+ filter.actionAfter(20,
+ boost::bind(&Listener::call, boost::ref(listener1), LLSD("timeout")));
+ // Okay, (fake) timer is ticking. 'filter' can only sense the timer
+ // when we pump mainloop. Do that right now to take the logic path
+ // before either the anticipated event arrives or the timer expires.
+ mainloop.post(17);
+ check_listener("no timeout 1", listener1, LLSD(0));
+ // Expected event arrives...
+ driver.post(1);
+ check_listener("event passed thru", listener0, LLSD(1));
+ // Should have canceled the timer. Verify that by asserting that the
+ // time has expired, then pumping mainloop again.
+ filter.forceTimeout();
+ mainloop.post(17);
+ check_listener("no timeout 2", listener1, LLSD(0));
+ // Verify chained actionAfter() calls, that is, that a second
+ // actionAfter() resets the timer established by the first
+ // actionAfter().
+ filter.actionAfter(20,
+ boost::bind(&Listener::call, boost::ref(listener1), LLSD("timeout")));
+ // Since our TestEventTimeout class isn't actually manipulating time
+ // (quantities of seconds), only a bool "elapsed" flag, sense that by
+ // forcing the flag between actionAfter() calls.
+ filter.forceTimeout();
+ // Pumping mainloop here would result in a timeout (as we'll verify
+ // below). This state simulates a ticking timer that has not yet timed
+ // out. But now, before a mainloop event lets 'filter' recognize
+ // timeout on the previous actionAfter() call, pretend we're pushing
+ // that timeout farther into the future.
+ filter.actionAfter(20,
+ boost::bind(&Listener::call, boost::ref(listener1), LLSD("timeout")));
+ // Look ma, no timeout!
+ mainloop.post(17);
+ check_listener("no timeout 3", listener1, LLSD(0));
+ // Now let the updated actionAfter() timer expire.
+ filter.forceTimeout();
+ // Notice the timeout.
+ mainloop.post(17);
+ check_listener("timeout", listener1, LLSD("timeout"));
+ // Timing out cancels the timer. Verify that.
+ listener1.reset(0);
+ filter.forceTimeout();
+ mainloop.post(17);
+ check_listener("no timeout 4", listener1, LLSD(0));
+ // Reset the timer and then cancel() it.
+ filter.actionAfter(20,
+ boost::bind(&Listener::call, boost::ref(listener1), LLSD("timeout")));
+ // neither expired nor satisified
+ mainloop.post(17);
+ check_listener("no timeout 5", listener1, LLSD(0));
+ // cancel
+ filter.cancel();
+ // timeout!
+ filter.forceTimeout();
+ mainloop.post(17);
+ check_listener("no timeout 6", listener1, LLSD(0));
+ }
+
+ template<> template<>
+ void filter_object::test<3>()
+ {
+ set_test_name("LLEventTimeout::eventAfter()");
+ LLEventPump& driver(pumps.obtain("driver"));
+ TestEventTimeout filter(driver);
+ listener0.reset(0);
+ LLTempBoundListener temp1(
+ listener0.listenTo(filter));
+ filter.eventAfter(20, LLSD("timeout"));
+ // Okay, (fake) timer is ticking. 'filter' can only sense the timer
+ // when we pump mainloop. Do that right now to take the logic path
+ // before either the anticipated event arrives or the timer expires.
+ mainloop.post(17);
+ check_listener("no timeout 1", listener0, LLSD(0));
+ // Expected event arrives...
+ driver.post(1);
+ check_listener("event passed thru", listener0, LLSD(1));
+ // Should have canceled the timer. Verify that by asserting that the
+ // time has expired, then pumping mainloop again.
+ filter.forceTimeout();
+ mainloop.post(17);
+ check_listener("no timeout 2", listener0, LLSD(1));
+ // Set timer again.
+ filter.eventAfter(20, LLSD("timeout"));
+ // Now let the timer expire.
+ filter.forceTimeout();
+ // Notice the timeout.
+ mainloop.post(17);
+ check_listener("timeout", listener0, LLSD("timeout"));
+ // Timing out cancels the timer. Verify that.
+ listener0.reset(0);
+ filter.forceTimeout();
+ mainloop.post(17);
+ check_listener("no timeout 3", listener0, LLSD(0));
+ }
+
+ template<> template<>
+ void filter_object::test<4>()
+ {
+ set_test_name("LLEventTimeout::errorAfter()");
+ WrapLL_ERRS capture;
+ LLEventPump& driver(pumps.obtain("driver"));
+ TestEventTimeout filter(driver);
+ listener0.reset(0);
+ LLTempBoundListener temp1(
+ listener0.listenTo(filter));
+ filter.errorAfter(20, "timeout");
+ // Okay, (fake) timer is ticking. 'filter' can only sense the timer
+ // when we pump mainloop. Do that right now to take the logic path
+ // before either the anticipated event arrives or the timer expires.
+ mainloop.post(17);
+ check_listener("no timeout 1", listener0, LLSD(0));
+ // Expected event arrives...
+ driver.post(1);
+ check_listener("event passed thru", listener0, LLSD(1));
+ // Should have canceled the timer. Verify that by asserting that the
+ // time has expired, then pumping mainloop again.
+ filter.forceTimeout();
+ mainloop.post(17);
+ check_listener("no timeout 2", listener0, LLSD(1));
+ // Set timer again.
+ filter.errorAfter(20, "timeout");
+ // Now let the timer expire.
+ filter.forceTimeout();
+ // Notice the timeout.
+ std::string threw;
+ try
+ {
+ mainloop.post(17);
+ }
+ catch (const WrapLL_ERRS::FatalException& e)
+ {
+ threw = e.what();
+ }
+ ensure_contains("errorAfter() timeout exception", threw, "timeout");
+ // Timing out cancels the timer. Verify that.
+ listener0.reset(0);
+ filter.forceTimeout();
+ mainloop.post(17);
+ check_listener("no timeout 3", listener0, LLSD(0));
+ }
+} // namespace tut
+
+/*****************************************************************************
+* Link dependencies
+*****************************************************************************/
+#include "llsdutil.cpp"
diff --git a/indra/llcommon/tests/llframetimer_test.cpp b/indra/llcommon/tests/llframetimer_test.cpp
new file mode 100644
index 0000000000..8ac1c91a3a
--- /dev/null
+++ b/indra/llcommon/tests/llframetimer_test.cpp
@@ -0,0 +1,112 @@
+/**
+ * @file lltiming_test.cpp
+ * @date 2006-07-23
+ * @brief Tests the timers.
+ *
+ * $LicenseInfo:firstyear=2006&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$
+ */
+
+#include "linden_common.h"
+
+#include "../llframetimer.h"
+#include "../llsd.h"
+
+#include "../test/lltut.h"
+
+namespace tut
+{
+ struct frametimer_test
+ {
+ frametimer_test()
+ {
+ LLFrameTimer::updateFrameTime();
+ }
+ };
+ typedef test_group<frametimer_test> frametimer_group_t;
+ typedef frametimer_group_t::object frametimer_object_t;
+ tut::frametimer_group_t frametimer_instance("LLFrameTimer");
+
+ template<> template<>
+ void frametimer_object_t::test<1>()
+ {
+ F64 seconds_since_epoch = LLFrameTimer::getTotalSeconds();
+ LLFrameTimer timer;
+ timer.setExpiryAt(seconds_since_epoch);
+ F64 expires_at = timer.expiresAt();
+ ensure_distance(
+ "set expiry matches get expiry",
+ expires_at,
+ seconds_since_epoch,
+ 0.001);
+ }
+
+ template<> template<>
+ void frametimer_object_t::test<2>()
+ {
+ F64 seconds_since_epoch = LLFrameTimer::getTotalSeconds();
+ seconds_since_epoch += 10.0;
+ LLFrameTimer timer;
+ timer.setExpiryAt(seconds_since_epoch);
+ F64 expires_at = timer.expiresAt();
+ ensure_distance(
+ "set expiry matches get expiry 1",
+ expires_at,
+ seconds_since_epoch,
+ 0.001);
+ seconds_since_epoch += 10.0;
+ timer.setExpiryAt(seconds_since_epoch);
+ expires_at = timer.expiresAt();
+ ensure_distance(
+ "set expiry matches get expiry 2",
+ expires_at,
+ seconds_since_epoch,
+ 0.001);
+ }
+ template<> template<>
+ void frametimer_object_t::test<3>()
+ {
+ F64 seconds_since_epoch = LLFrameTimer::getTotalSeconds();
+ seconds_since_epoch += 2.0;
+ LLFrameTimer timer;
+ timer.setExpiryAt(seconds_since_epoch);
+ ensure("timer not expired on create", !timer.hasExpired());
+ int ii;
+ for(ii = 0; ii < 10; ++ii)
+ {
+ ms_sleep(150);
+ LLFrameTimer::updateFrameTime();
+ }
+ ensure("timer not expired after a bit", !timer.hasExpired());
+ for(ii = 0; ii < 10; ++ii)
+ {
+ ms_sleep(100);
+ LLFrameTimer::updateFrameTime();
+ }
+ ensure("timer expired", timer.hasExpired());
+ }
+/*
+ template<> template<>
+ void frametimer_object_t::test<4>()
+ {
+ }
+*/
+}
diff --git a/indra/llcommon/tests/llinstancetracker_test.cpp b/indra/llcommon/tests/llinstancetracker_test.cpp
new file mode 100644
index 0000000000..c7cb488ca1
--- /dev/null
+++ b/indra/llcommon/tests/llinstancetracker_test.cpp
@@ -0,0 +1,183 @@
+/**
+ * @file llinstancetracker_test.cpp
+ * @author Nat Goodspeed
+ * @date 2009-11-10
+ * @brief Test for llinstancetracker.
+ *
+ * $LicenseInfo:firstyear=2009&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$
+ */
+
+// Precompiled header
+#include "linden_common.h"
+// associated header
+#include "llinstancetracker.h"
+// STL headers
+#include <string>
+#include <vector>
+#include <set>
+#include <algorithm> // std::sort()
+// std headers
+// external library headers
+#include <boost/scoped_ptr.hpp>
+// other Linden headers
+#include "../test/lltut.h"
+
+struct Keyed: public LLInstanceTracker<Keyed, std::string>
+{
+ Keyed(const std::string& name):
+ LLInstanceTracker<Keyed, std::string>(name),
+ mName(name)
+ {}
+ std::string mName;
+};
+
+struct Unkeyed: public LLInstanceTracker<Unkeyed>
+{
+};
+
+/*****************************************************************************
+* TUT
+*****************************************************************************/
+namespace tut
+{
+ struct llinstancetracker_data
+ {
+ };
+ typedef test_group<llinstancetracker_data> llinstancetracker_group;
+ typedef llinstancetracker_group::object object;
+ llinstancetracker_group llinstancetrackergrp("llinstancetracker");
+
+ template<> template<>
+ void object::test<1>()
+ {
+ ensure_equals(Keyed::instanceCount(), 0);
+ {
+ Keyed one("one");
+ ensure_equals(Keyed::instanceCount(), 1);
+ Keyed* found = Keyed::getInstance("one");
+ ensure("couldn't find stack Keyed", found);
+ ensure_equals("found wrong Keyed instance", found, &one);
+ {
+ boost::scoped_ptr<Keyed> two(new Keyed("two"));
+ ensure_equals(Keyed::instanceCount(), 2);
+ Keyed* found = Keyed::getInstance("two");
+ ensure("couldn't find heap Keyed", found);
+ ensure_equals("found wrong Keyed instance", found, two.get());
+ }
+ ensure_equals(Keyed::instanceCount(), 1);
+ }
+ Keyed* found = Keyed::getInstance("one");
+ ensure("Keyed key lives too long", ! found);
+ ensure_equals(Keyed::instanceCount(), 0);
+ }
+
+ template<> template<>
+ void object::test<2>()
+ {
+ ensure_equals(Unkeyed::instanceCount(), 0);
+ {
+ Unkeyed one;
+ ensure_equals(Unkeyed::instanceCount(), 1);
+ Unkeyed* found = Unkeyed::getInstance(&one);
+ ensure_equals(found, &one);
+ {
+ boost::scoped_ptr<Unkeyed> two(new Unkeyed);
+ ensure_equals(Unkeyed::instanceCount(), 2);
+ Unkeyed* found = Unkeyed::getInstance(two.get());
+ ensure_equals(found, two.get());
+ }
+ ensure_equals(Unkeyed::instanceCount(), 1);
+ }
+ ensure_equals(Unkeyed::instanceCount(), 0);
+ }
+
+ template<> template<>
+ void object::test<3>()
+ {
+ Keyed one("one"), two("two"), three("three");
+ // We don't want to rely on the underlying container delivering keys
+ // in any particular order. That allows us the flexibility to
+ // reimplement LLInstanceTracker using, say, a hash map instead of a
+ // std::map. We DO insist that every key appear exactly once.
+ typedef std::vector<std::string> StringVector;
+ StringVector keys(Keyed::beginKeys(), Keyed::endKeys());
+ std::sort(keys.begin(), keys.end());
+ StringVector::const_iterator ki(keys.begin());
+ ensure_equals(*ki++, "one");
+ ensure_equals(*ki++, "three");
+ ensure_equals(*ki++, "two");
+ // Use ensure() here because ensure_equals would want to display
+ // mismatched values, and frankly that wouldn't help much.
+ ensure("didn't reach end", ki == keys.end());
+
+ // Use a somewhat different approach to order independence with
+ // beginInstances(): explicitly capture the instances we know in a
+ // set, and delete them as we iterate through.
+ typedef std::set<Keyed*> InstanceSet;
+ InstanceSet instances;
+ instances.insert(&one);
+ instances.insert(&two);
+ instances.insert(&three);
+ for (Keyed::instance_iter ii(Keyed::beginInstances()), iend(Keyed::endInstances());
+ ii != iend; ++ii)
+ {
+ Keyed& ref = *ii;
+ ensure_equals("spurious instance", instances.erase(&ref), 1);
+ }
+ ensure_equals("unreported instance", instances.size(), 0);
+ }
+
+ template<> template<>
+ void object::test<4>()
+ {
+ Unkeyed one, two, three;
+ typedef std::set<Unkeyed*> KeySet;
+ KeySet keys;
+ keys.insert(&one);
+ keys.insert(&two);
+ keys.insert(&three);
+ {
+ Unkeyed::LLInstanceTrackerScopedGuard guard;
+ for (Unkeyed::key_iter ki(guard.beginKeys()), kend(guard.endKeys());
+ ki != kend; ++ki)
+ {
+ ensure_equals("spurious key", keys.erase(*ki), 1);
+ }
+ }
+ ensure_equals("unreported key", keys.size(), 0);
+
+ KeySet instances;
+ instances.insert(&one);
+ instances.insert(&two);
+ instances.insert(&three);
+ {
+ Unkeyed::LLInstanceTrackerScopedGuard guard;
+ for (Unkeyed::instance_iter ii(guard.beginInstances()), iend(guard.endInstances());
+ ii != iend; ++ii)
+ {
+ Unkeyed& ref = *ii;
+ ensure_equals("spurious instance", instances.erase(&ref), 1);
+ }
+ }
+ ensure_equals("unreported instance", instances.size(), 0);
+ }
+} // namespace tut
diff --git a/indra/llcommon/tests/lllazy_test.cpp b/indra/llcommon/tests/lllazy_test.cpp
new file mode 100644
index 0000000000..32a717f4fc
--- /dev/null
+++ b/indra/llcommon/tests/lllazy_test.cpp
@@ -0,0 +1,244 @@
+/**
+ * @file lllazy_test.cpp
+ * @author Nat Goodspeed
+ * @date 2009-01-28
+ * @brief Tests of lllazy.h.
+ *
+ * $LicenseInfo:firstyear=2009&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$
+ */
+
+// Precompiled header
+#include "linden_common.h"
+// associated header
+#include "lllazy.h"
+// STL headers
+#include <iostream>
+// std headers
+// external library headers
+#include <boost/lambda/construct.hpp>
+#include <boost/lambda/bind.hpp>
+// other Linden headers
+#include "../test/lltut.h"
+
+namespace bll = boost::lambda;
+
+/*****************************************************************************
+* Test classes
+*****************************************************************************/
+
+// Let's say that because of its many external dependencies, YuckyFoo is very
+// hard to instantiate in a test harness.
+class YuckyFoo
+{
+public:
+ virtual ~YuckyFoo() {}
+ virtual std::string whoami() const { return "YuckyFoo"; }
+};
+
+// Let's further suppose that YuckyBar is another hard-to-instantiate class.
+class YuckyBar
+{
+public:
+ YuckyBar(const std::string& which):
+ mWhich(which)
+ {}
+ virtual ~YuckyBar() {}
+
+ virtual std::string identity() const { return std::string("YuckyBar(") + mWhich + ")"; }
+
+private:
+ const std::string mWhich;
+};
+
+// Pretend that this class would be tough to test because, up until we started
+// trying to test it, it contained instances of both YuckyFoo and YuckyBar.
+// Now we've refactored so it contains LLLazy<YuckyFoo> and LLLazy<YuckyBar>.
+// More than that, it contains them by virtue of deriving from
+// LLLazyBase<YuckyFoo> and LLLazyBase<YuckyBar>.
+// We postulate two different LLLazyBases because, with only one, you need not
+// specify *which* get()/set() method you're talking about. That's a simpler
+// case.
+class NeedsTesting: public LLLazyBase<YuckyFoo>, public LLLazyBase<YuckyBar>
+{
+public:
+ NeedsTesting():
+ // mYuckyBar("RealYuckyBar")
+ LLLazyBase<YuckyBar>(bll::bind(bll::new_ptr<YuckyBar>(), "RealYuckyBar"))
+ {}
+ virtual ~NeedsTesting() {}
+
+ virtual std::string describe() const
+ {
+ return std::string("NeedsTesting(") + getLazy<YuckyFoo>(this).whoami() + ", " +
+ getLazy<YuckyBar>(this).identity() + ")";
+ }
+
+private:
+ // These instance members were moved to LLLazyBases:
+ // YuckyFoo mYuckyFoo;
+ // YuckyBar mYuckyBar;
+};
+
+// Fake up a test YuckyFoo class
+class TestFoo: public YuckyFoo
+{
+public:
+ virtual std::string whoami() const { return "TestFoo"; }
+};
+
+// and a test YuckyBar
+class TestBar: public YuckyBar
+{
+public:
+ TestBar(const std::string& which): YuckyBar(which) {}
+ virtual std::string identity() const
+ {
+ return std::string("TestBar(") + YuckyBar::identity() + ")";
+ }
+};
+
+// So here's a test subclass of NeedsTesting that uses TestFoo and TestBar
+// instead of YuckyFoo and YuckyBar.
+class TestNeedsTesting: public NeedsTesting
+{
+public:
+ TestNeedsTesting()
+ {
+ // Exercise setLazy(T*)
+ setLazy<YuckyFoo>(this, new TestFoo());
+ // Exercise setLazy(Factory)
+ setLazy<YuckyBar>(this, bll::bind(bll::new_ptr<TestBar>(), "TestYuckyBar"));
+ }
+
+ virtual std::string describe() const
+ {
+ return std::string("TestNeedsTesting(") + NeedsTesting::describe() + ")";
+ }
+
+ void toolate()
+ {
+ setLazy<YuckyFoo>(this, new TestFoo());
+ }
+};
+
+// This class tests having an explicit LLLazy<T> instance as a named member,
+// rather than deriving from LLLazyBase<T>.
+class LazyMember
+{
+public:
+ YuckyFoo& getYuckyFoo() { return *mYuckyFoo; }
+ std::string whoisit() const { return mYuckyFoo->whoami(); }
+
+protected:
+ LLLazy<YuckyFoo> mYuckyFoo;
+};
+
+// This is a test subclass of the above, dynamically replacing the
+// LLLazy<YuckyFoo> member.
+class TestLazyMember: public LazyMember
+{
+public:
+ // use factory setter
+ TestLazyMember()
+ {
+ mYuckyFoo.set(bll::new_ptr<TestFoo>());
+ }
+
+ // use instance setter
+ TestLazyMember(YuckyFoo* instance)
+ {
+ mYuckyFoo.set(instance);
+ }
+};
+
+/*****************************************************************************
+* TUT
+*****************************************************************************/
+namespace tut
+{
+ struct lllazy_data
+ {
+ };
+ typedef test_group<lllazy_data> lllazy_group;
+ typedef lllazy_group::object lllazy_object;
+ lllazy_group lllazygrp("lllazy");
+
+ template<> template<>
+ void lllazy_object::test<1>()
+ {
+ // Instantiate an official one, just because we can
+ NeedsTesting nt;
+ // and a test one
+ TestNeedsTesting tnt;
+// std::cout << nt.describe() << '\n';
+ ensure_equals(nt.describe(), "NeedsTesting(YuckyFoo, YuckyBar(RealYuckyBar))");
+// std::cout << tnt.describe() << '\n';
+ ensure_equals(tnt.describe(),
+ "TestNeedsTesting(NeedsTesting(TestFoo, TestBar(YuckyBar(TestYuckyBar))))");
+ }
+
+ template<> template<>
+ void lllazy_object::test<2>()
+ {
+ TestNeedsTesting tnt;
+ std::string threw;
+ try
+ {
+ tnt.toolate();
+ }
+ catch (const LLLazyCommon::InstanceChange& e)
+ {
+ threw = e.what();
+ }
+ ensure_contains("InstanceChange exception", threw, "replace LLLazy instance");
+ }
+
+ template<> template<>
+ void lllazy_object::test<3>()
+ {
+ {
+ LazyMember lm;
+ // operator*() on-demand instantiation
+ ensure_equals(lm.getYuckyFoo().whoami(), "YuckyFoo");
+ }
+ {
+ LazyMember lm;
+ // operator->() on-demand instantiation
+ ensure_equals(lm.whoisit(), "YuckyFoo");
+ }
+ }
+
+ template<> template<>
+ void lllazy_object::test<4>()
+ {
+ {
+ // factory setter
+ TestLazyMember tlm;
+ ensure_equals(tlm.whoisit(), "TestFoo");
+ }
+ {
+ // instance setter
+ TestLazyMember tlm(new TestFoo());
+ ensure_equals(tlm.whoisit(), "TestFoo");
+ }
+ }
+} // namespace tut
diff --git a/indra/llcommon/tests/llmemtype_test.cpp b/indra/llcommon/tests/llmemtype_test.cpp
new file mode 100644
index 0000000000..1f050d6dc7
--- /dev/null
+++ b/indra/llcommon/tests/llmemtype_test.cpp
@@ -0,0 +1,117 @@
+/**
+ * @file llmemtype_test.cpp
+ * @author Palmer Truelson
+ * @date 2008-03-
+ * @brief Test for llmemtype.cpp.
+ *
+ * $LicenseInfo:firstyear=2009&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$
+ */
+
+#include "../llmemtype.h"
+#include "../test/lltut.h"
+#include "../llallocator.h"
+
+
+#include <stack>
+
+std::stack<S32> memTypeStack;
+
+void LLAllocator::pushMemType(S32 i)
+{
+ memTypeStack.push(i);
+}
+
+S32 LLAllocator::popMemType(void)
+{
+ S32 ret = memTypeStack.top();
+ memTypeStack.pop();
+ return ret;
+}
+
+namespace tut
+{
+ struct llmemtype_data
+ {
+ };
+
+ typedef test_group<llmemtype_data> factory;
+ typedef factory::object object;
+}
+namespace
+{
+ tut::factory llmemtype_test_factory("LLMemType");
+}
+
+namespace tut
+{
+ template<> template<>
+ void object::test<1>()
+ {
+ ensure("Simplest test ever", true);
+ }
+
+ // test with no scripts
+ template<> template<>
+ void object::test<2>()
+ {
+ {
+ LLMemType m1(LLMemType::MTYPE_INIT);
+ }
+ ensure("Test that you can construct and destruct the mem type");
+ }
+
+ // test creation and stack testing
+ template<> template<>
+ void object::test<3>()
+ {
+ {
+ ensure("Test that creation and destruction properly inc/dec the stack");
+ ensure_equals(memTypeStack.size(), 0);
+ {
+ LLMemType m1(LLMemType::MTYPE_INIT);
+ ensure_equals(memTypeStack.size(), 1);
+ LLMemType m2(LLMemType::MTYPE_STARTUP);
+ ensure_equals(memTypeStack.size(), 2);
+ }
+ ensure_equals(memTypeStack.size(), 0);
+ }
+ }
+
+ // test with no scripts
+ template<> template<>
+ void object::test<4>()
+ {
+ // catch the begining and end
+ std::string test_name = LLMemType::getNameFromID(LLMemType::MTYPE_INIT.mID);
+ ensure_equals("Init name", test_name, "Init");
+
+ std::string test_name2 = LLMemType::getNameFromID(LLMemType::MTYPE_VOLUME.mID);
+ ensure_equals("Volume name", test_name2, "Volume");
+
+ std::string test_name3 = LLMemType::getNameFromID(LLMemType::MTYPE_OTHER.mID);
+ ensure_equals("Other name", test_name3, "Other");
+
+ std::string test_name4 = LLMemType::getNameFromID(-1);
+ ensure_equals("Invalid name", test_name4, "INVALID");
+ }
+
+};
diff --git a/indra/llcommon/tests/llprocessor_test.cpp b/indra/llcommon/tests/llprocessor_test.cpp
new file mode 100644
index 0000000000..884e1b5e5b
--- /dev/null
+++ b/indra/llcommon/tests/llprocessor_test.cpp
@@ -0,0 +1,61 @@
+/**
+ * @file llprocessor_test.cpp
+ * @date 2010-06-01
+ *
+ * $LicenseInfo:firstyear=2010&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$
+ */
+
+#include "linden_common.h"
+#include "../test/lltut.h"
+
+#include "../llprocessor.h"
+
+
+namespace tut
+{
+ struct processor
+ {
+ };
+
+ typedef test_group<processor> processor_t;
+ typedef processor_t::object processor_object_t;
+ tut::processor_t tut_processor("LLProcessor");
+
+ template<> template<>
+ void processor_object_t::test<1>()
+ {
+ set_test_name("LLProcessorInfo regression test");
+
+ LLProcessorInfo pi;
+ F64 freq = pi.getCPUFrequency();
+ //bool sse = pi.hasSSE();
+ //bool sse2 = pi.hasSSE2();
+ //bool alitvec = pi.hasAltivec();
+ std::string family = pi.getCPUFamilyName();
+ std::string brand = pi.getCPUBrandName();
+ //std::string steam = pi.getCPUFeatureDescription();
+
+ ensure_not_equals("Unknown Brand name", brand, "Unknown");
+ ensure_not_equals("Unknown Family name", family, "Unknown");
+ ensure("Reasonable CPU Frequency > 100 && < 10000", freq > 100 && freq < 10000);
+ }
+}
diff --git a/indra/llcommon/tests/llrand_test.cpp b/indra/llcommon/tests/llrand_test.cpp
new file mode 100644
index 0000000000..383e6f9e0a
--- /dev/null
+++ b/indra/llcommon/tests/llrand_test.cpp
@@ -0,0 +1,127 @@
+/**
+ * @file llrandom_test.cpp
+ * @author Phoenix
+ * @date 2007-01-25
+ *
+ * $LicenseInfo:firstyear=2007&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$
+ */
+
+#include "linden_common.h"
+#include "../test/lltut.h"
+
+#include "../llrand.h"
+
+
+namespace tut
+{
+ struct random
+ {
+ };
+
+ typedef test_group<random> random_t;
+ typedef random_t::object random_object_t;
+ tut::random_t tut_random("LLSeedRand");
+
+ template<> template<>
+ void random_object_t::test<1>()
+ {
+ F32 number = 0.0f;
+ for(S32 ii = 0; ii < 100000; ++ii)
+ {
+ number = ll_frand();
+ ensure("frand >= 0", (number >= 0.0f));
+ ensure("frand < 1", (number < 1.0f));
+ }
+ }
+
+ template<> template<>
+ void random_object_t::test<2>()
+ {
+ F64 number = 0.0f;
+ for(S32 ii = 0; ii < 100000; ++ii)
+ {
+ number = ll_drand();
+ ensure("drand >= 0", (number >= 0.0));
+ ensure("drand < 1", (number < 1.0));
+ }
+ }
+
+ template<> template<>
+ void random_object_t::test<3>()
+ {
+ F32 number = 0.0f;
+ for(S32 ii = 0; ii < 100000; ++ii)
+ {
+ number = ll_frand(2.0f) - 1.0f;
+ ensure("frand >= 0", (number >= -1.0f));
+ ensure("frand < 1", (number <= 1.0f));
+ }
+ }
+
+ template<> template<>
+ void random_object_t::test<4>()
+ {
+ F32 number = 0.0f;
+ for(S32 ii = 0; ii < 100000; ++ii)
+ {
+ number = ll_frand(-7.0);
+ ensure("drand <= 0", (number <= 0.0));
+ ensure("drand > -7", (number > -7.0));
+ }
+ }
+
+ template<> template<>
+ void random_object_t::test<5>()
+ {
+ F64 number = 0.0f;
+ for(S32 ii = 0; ii < 100000; ++ii)
+ {
+ number = ll_drand(-2.0);
+ ensure("drand <= 0", (number <= 0.0));
+ ensure("drand > -2", (number > -2.0));
+ }
+ }
+
+ template<> template<>
+ void random_object_t::test<6>()
+ {
+ S32 number = 0;
+ for(S32 ii = 0; ii < 100000; ++ii)
+ {
+ number = ll_rand(100);
+ ensure("rand >= 0", (number >= 0));
+ ensure("rand < 100", (number < 100));
+ }
+ }
+
+ template<> template<>
+ void random_object_t::test<7>()
+ {
+ S32 number = 0;
+ for(S32 ii = 0; ii < 100000; ++ii)
+ {
+ number = ll_rand(-127);
+ ensure("rand <= 0", (number <= 0));
+ ensure("rand > -127", (number > -127));
+ }
+ }
+}
diff --git a/indra/llcommon/tests/llsdserialize_test.cpp b/indra/llcommon/tests/llsdserialize_test.cpp
new file mode 100644
index 0000000000..770443da1d
--- /dev/null
+++ b/indra/llcommon/tests/llsdserialize_test.cpp
@@ -0,0 +1,1498 @@
+/**
+ * @file llsdserialize_test.cpp
+ * @date 2006-04
+ * @brief LLSDSerialize unit tests
+ *
+ * $LicenseInfo:firstyear=2006&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 !LL_WINDOWS
+#include <netinet/in.h>
+#endif
+
+#include "linden_common.h"
+#include "../llsd.h"
+#include "../llsdserialize.h"
+#include "../llformat.h"
+
+#include "../test/lltut.h"
+
+
+#if LL_WINDOWS
+#include <winsock2.h>
+typedef U32 uint32_t;
+#endif
+
+std::vector<U8> string_to_vector(std::string str)
+{
+ // bc LLSD can't...
+ size_t len = (size_t)str.length();
+ std::vector<U8> v(len);
+ for (size_t i = 0; i < len ; i++)
+ {
+ v[i] = str[i];
+ }
+ return v;
+}
+
+namespace tut
+{
+ struct sd_xml_data
+ {
+ sd_xml_data()
+ {
+ mFormatter = new LLSDXMLFormatter;
+ }
+ LLSD mSD;
+ LLPointer<LLSDXMLFormatter> mFormatter;
+ void xml_test(const char* name, const std::string& expected)
+ {
+ std::ostringstream ostr;
+ mFormatter->format(mSD, ostr);
+ ensure_equals(name, ostr.str(), expected);
+ }
+ };
+
+ typedef test_group<sd_xml_data> sd_xml_test;
+ typedef sd_xml_test::object sd_xml_object;
+ tut::sd_xml_test sd_xml_stream("LLSDXMLFormatter");
+
+ template<> template<>
+ void sd_xml_object::test<1>()
+ {
+ // random atomic tests
+ std::string expected;
+
+ expected = "<llsd><undef /></llsd>\n";
+ xml_test("undef", expected);
+
+ mSD = 3463;
+ expected = "<llsd><integer>3463</integer></llsd>\n";
+ xml_test("integer", expected);
+
+ mSD = "";
+ expected = "<llsd><string /></llsd>\n";
+ xml_test("empty string", expected);
+
+ mSD = "foobar";
+ expected = "<llsd><string>foobar</string></llsd>\n";
+ xml_test("string", expected);
+
+ mSD = LLUUID::null;
+ expected = "<llsd><uuid /></llsd>\n";
+ xml_test("null uuid", expected);
+
+ mSD = LLUUID("c96f9b1e-f589-4100-9774-d98643ce0bed");
+ expected = "<llsd><uuid>c96f9b1e-f589-4100-9774-d98643ce0bed</uuid></llsd>\n";
+ xml_test("uuid", expected);
+
+ mSD = LLURI("https://secondlife.com/login");
+ expected = "<llsd><uri>https://secondlife.com/login</uri></llsd>\n";
+ xml_test("uri", expected);
+
+ mSD = LLDate("2006-04-24T16:11:33Z");
+ expected = "<llsd><date>2006-04-24T16:11:33Z</date></llsd>\n";
+ xml_test("date", expected);
+
+ // Generated by: echo -n 'hello' | openssl enc -e -base64
+ std::vector<U8> hello;
+ hello.push_back('h');
+ hello.push_back('e');
+ hello.push_back('l');
+ hello.push_back('l');
+ hello.push_back('o');
+ mSD = hello;
+ expected = "<llsd><binary encoding=\"base64\">aGVsbG8=</binary></llsd>\n";
+ xml_test("binary", expected);
+ }
+
+ template<> template<>
+ void sd_xml_object::test<2>()
+ {
+ // tests with boolean values.
+ std::string expected;
+
+ mFormatter->boolalpha(true);
+ mSD = true;
+ expected = "<llsd><boolean>true</boolean></llsd>\n";
+ xml_test("bool alpha true", expected);
+ mSD = false;
+ expected = "<llsd><boolean>false</boolean></llsd>\n";
+ xml_test("bool alpha false", expected);
+
+ mFormatter->boolalpha(false);
+ mSD = true;
+ expected = "<llsd><boolean>1</boolean></llsd>\n";
+ xml_test("bool true", expected);
+ mSD = false;
+ expected = "<llsd><boolean>0</boolean></llsd>\n";
+ xml_test("bool false", expected);
+ }
+
+
+ template<> template<>
+ void sd_xml_object::test<3>()
+ {
+ // tests with real values.
+ std::string expected;
+
+ mFormatter->realFormat("%.2f");
+ mSD = 1.0;
+ expected = "<llsd><real>1.00</real></llsd>\n";
+ xml_test("real 1", expected);
+
+ mSD = -34379.0438;
+ expected = "<llsd><real>-34379.04</real></llsd>\n";
+ xml_test("real reduced precision", expected);
+ mFormatter->realFormat("%.4f");
+ expected = "<llsd><real>-34379.0438</real></llsd>\n";
+ xml_test("higher precision", expected);
+
+ mFormatter->realFormat("%.0f");
+ mSD = 0.0;
+ expected = "<llsd><real>0</real></llsd>\n";
+ xml_test("no decimal 0", expected);
+ mSD = 3287.4387;
+ expected = "<llsd><real>3287</real></llsd>\n";
+ xml_test("no decimal real number", expected);
+ }
+
+ template<> template<>
+ void sd_xml_object::test<4>()
+ {
+ // tests with arrays
+ std::string expected;
+
+ mSD = LLSD::emptyArray();
+ expected = "<llsd><array /></llsd>\n";
+ xml_test("empty array", expected);
+
+ mSD.append(LLSD());
+ expected = "<llsd><array><undef /></array></llsd>\n";
+ xml_test("1 element array", expected);
+
+ mSD.append(1);
+ expected = "<llsd><array><undef /><integer>1</integer></array></llsd>\n";
+ xml_test("2 element array", expected);
+ }
+
+ template<> template<>
+ void sd_xml_object::test<5>()
+ {
+ // tests with arrays
+ std::string expected;
+
+ mSD = LLSD::emptyMap();
+ expected = "<llsd><map /></llsd>\n";
+ xml_test("empty map", expected);
+
+ mSD["foo"] = "bar";
+ expected = "<llsd><map><key>foo</key><string>bar</string></map></llsd>\n";
+ xml_test("1 element map", expected);
+
+ mSD["baz"] = LLSD();
+ expected = "<llsd><map><key>baz</key><undef /><key>foo</key><string>bar</string></map></llsd>\n";
+ xml_test("2 element map", expected);
+ }
+
+ template<> template<>
+ void sd_xml_object::test<6>()
+ {
+ // tests with binary
+ std::string expected;
+
+ // Generated by: echo -n 'hello' | openssl enc -e -base64
+ mSD = string_to_vector("hello");
+ expected = "<llsd><binary encoding=\"base64\">aGVsbG8=</binary></llsd>\n";
+ xml_test("binary", expected);
+
+ mSD = string_to_vector("6|6|asdfhappybox|60e44ec5-305c-43c2-9a19-b4b89b1ae2a6|60e44ec5-305c-43c2-9a19-b4b89b1ae2a6|60e44ec5-305c-43c2-9a19-b4b89b1ae2a6|00000000-0000-0000-0000-000000000000|7fffffff|7fffffff|0|0|82000|450fe394-2904-c9ad-214c-a07eb7feec29|(No Description)|0|10|0");
+ expected = "<llsd><binary encoding=\"base64\">Nnw2fGFzZGZoYXBweWJveHw2MGU0NGVjNS0zMDVjLTQzYzItOWExOS1iNGI4OWIxYWUyYTZ8NjBlNDRlYzUtMzA1Yy00M2MyLTlhMTktYjRiODliMWFlMmE2fDYwZTQ0ZWM1LTMwNWMtNDNjMi05YTE5LWI0Yjg5YjFhZTJhNnwwMDAwMDAwMC0wMDAwLTAwMDAtMDAwMC0wMDAwMDAwMDAwMDB8N2ZmZmZmZmZ8N2ZmZmZmZmZ8MHwwfDgyMDAwfDQ1MGZlMzk0LTI5MDQtYzlhZC0yMTRjLWEwN2ViN2ZlZWMyOXwoTm8gRGVzY3JpcHRpb24pfDB8MTB8MA==</binary></llsd>\n";
+ xml_test("binary", expected);
+ }
+
+ class TestLLSDSerializeData
+ {
+ public:
+ TestLLSDSerializeData();
+ ~TestLLSDSerializeData();
+
+ void doRoundTripTests(const std::string&);
+ void checkRoundTrip(const std::string&, const LLSD& v);
+
+ LLPointer<LLSDFormatter> mFormatter;
+ LLPointer<LLSDParser> mParser;
+ };
+
+ TestLLSDSerializeData::TestLLSDSerializeData()
+ {
+ }
+
+ TestLLSDSerializeData::~TestLLSDSerializeData()
+ {
+ }
+
+ void TestLLSDSerializeData::checkRoundTrip(const std::string& msg, const LLSD& v)
+ {
+ std::stringstream stream;
+ mFormatter->format(v, stream);
+ //llinfos << "checkRoundTrip: length " << stream.str().length() << llendl;
+ LLSD w;
+ mParser->reset(); // reset() call is needed since test code re-uses mParser
+ mParser->parse(stream, w, stream.str().size());
+
+ try
+ {
+ ensure_equals(msg.c_str(), w, v);
+ }
+ catch (...)
+ {
+ std::cerr << "the serialized string was:" << std::endl;
+ std::cerr << stream.str() << std::endl;
+ throw;
+ }
+ }
+
+ static void fillmap(LLSD& root, U32 width, U32 depth)
+ {
+ if(depth == 0)
+ {
+ root["foo"] = "bar";
+ return;
+ }
+
+ for(U32 i = 0; i < width; ++i)
+ {
+ std::string key = llformat("child %d", i);
+ root[key] = LLSD::emptyMap();
+ fillmap(root[key], width, depth - 1);
+ }
+ }
+
+ void TestLLSDSerializeData::doRoundTripTests(const std::string& msg)
+ {
+ LLSD v;
+ checkRoundTrip(msg + " undefined", v);
+
+ v = true;
+ checkRoundTrip(msg + " true bool", v);
+
+ v = false;
+ checkRoundTrip(msg + " false bool", v);
+
+ v = 1;
+ checkRoundTrip(msg + " positive int", v);
+
+ v = 0;
+ checkRoundTrip(msg + " zero int", v);
+
+ v = -1;
+ checkRoundTrip(msg + " negative int", v);
+
+ v = 1234.5f;
+ checkRoundTrip(msg + " positive float", v);
+
+ v = 0.0f;
+ checkRoundTrip(msg + " zero float", v);
+
+ v = -1234.5f;
+ checkRoundTrip(msg + " negative float", v);
+
+ // FIXME: need a NaN test
+
+ v = LLUUID::null;
+ checkRoundTrip(msg + " null uuid", v);
+
+ LLUUID newUUID;
+ newUUID.generate();
+ v = newUUID;
+ checkRoundTrip(msg + " new uuid", v);
+
+ v = "";
+ checkRoundTrip(msg + " empty string", v);
+
+ v = "some string";
+ checkRoundTrip(msg + " non-empty string", v);
+
+ v =
+"Second Life is a 3-D virtual world entirely built and owned by its residents. "
+"Since opening to the public in 2003, it has grown explosively and today is "
+"inhabited by nearly 100,000 people from around the globe.\n"
+"\n"
+"From the moment you enter the World you'll discover a vast digital continent, "
+"teeming with people, entertainment, experiences and opportunity. Once you've "
+"explored a bit, perhaps you'll find a perfect parcel of land to build your "
+"house or business.\n"
+"\n"
+"You'll also be surrounded by the Creations of your fellow residents. Because "
+"residents retain the rights to their digital creations, they can buy, sell "
+"and trade with other residents.\n"
+"\n"
+"The Marketplace currently supports millions of US dollars in monthly "
+"transactions. This commerce is handled with the in-world currency, the Linden "
+"dollar, which can be converted to US dollars at several thriving online "
+"currency exchanges.\n"
+"\n"
+"Welcome to Second Life. We look forward to seeing you in-world!\n"
+ ;
+ checkRoundTrip(msg + " long string", v);
+
+ static const U32 block_size = 0x000020;
+ for (U32 block = 0x000000; block <= 0x10ffff; block += block_size)
+ {
+ std::ostringstream out;
+
+ for (U32 c = block; c < block + block_size; ++c)
+ {
+ if (c <= 0x000001f
+ && c != 0x000009
+ && c != 0x00000a)
+ {
+ // see XML standard, sections 2.2 and 4.1
+ continue;
+ }
+ if (0x00d800 <= c && c <= 0x00dfff) { continue; }
+ if (0x00fdd0 <= c && c <= 0x00fdef) { continue; }
+ if ((c & 0x00fffe) == 0x00fffe) { continue; }
+ // see Unicode standard, section 15.8
+
+ if (c <= 0x00007f)
+ {
+ out << (char)(c & 0x7f);
+ }
+ else if (c <= 0x0007ff)
+ {
+ out << (char)(0xc0 | ((c >> 6) & 0x1f));
+ out << (char)(0x80 | ((c >> 0) & 0x3f));
+ }
+ else if (c <= 0x00ffff)
+ {
+ out << (char)(0xe0 | ((c >> 12) & 0x0f));
+ out << (char)(0x80 | ((c >> 6) & 0x3f));
+ out << (char)(0x80 | ((c >> 0) & 0x3f));
+ }
+ else
+ {
+ out << (char)(0xf0 | ((c >> 18) & 0x07));
+ out << (char)(0x80 | ((c >> 12) & 0x3f));
+ out << (char)(0x80 | ((c >> 6) & 0x3f));
+ out << (char)(0x80 | ((c >> 0) & 0x3f));
+ }
+ }
+
+ v = out.str();
+
+ std::ostringstream blockmsg;
+ blockmsg << msg << " unicode string block 0x" << std::hex << block;
+ checkRoundTrip(blockmsg.str(), v);
+ }
+
+ LLDate epoch;
+ v = epoch;
+ checkRoundTrip(msg + " epoch date", v);
+
+ LLDate aDay("2002-12-07T05:07:15.00Z");
+ v = aDay;
+ checkRoundTrip(msg + " date", v);
+
+ LLURI path("http://slurl.com/secondlife/Ambleside/57/104/26/");
+ v = path;
+ checkRoundTrip(msg + " url", v);
+
+ const char source[] = "it must be a blue moon again";
+ std::vector<U8> data;
+ copy(&source[0], &source[sizeof(source)], back_inserter(data));
+
+ v = data;
+ checkRoundTrip(msg + " binary", v);
+
+ v = LLSD::emptyMap();
+ checkRoundTrip(msg + " empty map", v);
+
+ v = LLSD::emptyMap();
+ v["name"] = "luke"; //v.insert("name", "luke");
+ v["age"] = 3; //v.insert("age", 3);
+ checkRoundTrip(msg + " map", v);
+
+ v.clear();
+ v["a"]["1"] = true;
+ v["b"]["0"] = false;
+ checkRoundTrip(msg + " nested maps", v);
+
+ v = LLSD::emptyArray();
+ checkRoundTrip(msg + " empty array", v);
+
+ v = LLSD::emptyArray();
+ v.append("ali");
+ v.append(28);
+ checkRoundTrip(msg + " array", v);
+
+ v.clear();
+ v[0][0] = true;
+ v[1][0] = false;
+ checkRoundTrip(msg + " nested arrays", v);
+
+ v = LLSD::emptyMap();
+ fillmap(v, 10, 6); // 10^6 maps
+ checkRoundTrip(msg + " many nested maps", v);
+ }
+
+ typedef tut::test_group<TestLLSDSerializeData> TestLLSDSerialzeGroup;
+ typedef TestLLSDSerialzeGroup::object TestLLSDSerializeObject;
+ TestLLSDSerialzeGroup gTestLLSDSerializeGroup("llsd serialization");
+
+ template<> template<>
+ void TestLLSDSerializeObject::test<1>()
+ {
+ mFormatter = new LLSDNotationFormatter();
+ mParser = new LLSDNotationParser();
+ doRoundTripTests("notation serialization");
+ }
+
+ template<> template<>
+ void TestLLSDSerializeObject::test<2>()
+ {
+ mFormatter = new LLSDXMLFormatter();
+ mParser = new LLSDXMLParser();
+ doRoundTripTests("xml serialization");
+ }
+
+ template<> template<>
+ void TestLLSDSerializeObject::test<3>()
+ {
+ mFormatter = new LLSDBinaryFormatter();
+ mParser = new LLSDBinaryParser();
+ doRoundTripTests("binary serialization");
+ }
+
+
+ /**
+ * @class TestLLSDParsing
+ * @brief Base class for of a parse tester.
+ */
+ template <class parser_t>
+ class TestLLSDParsing
+ {
+ public:
+ TestLLSDParsing()
+ {
+ mParser = new parser_t;
+ }
+
+ void ensureParse(
+ const std::string& msg,
+ const std::string& in,
+ const LLSD& expected_value,
+ S32 expected_count)
+ {
+ std::stringstream input;
+ input.str(in);
+
+ LLSD parsed_result;
+ mParser->reset(); // reset() call is needed since test code re-uses mParser
+ S32 parsed_count = mParser->parse(input, parsed_result, in.size());
+ ensure_equals(msg.c_str(), parsed_result, expected_value);
+
+ // This count check is really only useful for expected
+ // parse failures, since the ensures equal will already
+ // require eqality.
+ std::string count_msg(msg);
+ count_msg += " (count)";
+ ensure_equals(count_msg, parsed_count, expected_count);
+ }
+
+ LLPointer<parser_t> mParser;
+ };
+
+
+ /**
+ * @class TestLLSDXMLParsing
+ * @brief Concrete instance of a parse tester.
+ */
+ class TestLLSDXMLParsing : public TestLLSDParsing<LLSDXMLParser>
+ {
+ public:
+ TestLLSDXMLParsing() {}
+ };
+
+ typedef tut::test_group<TestLLSDXMLParsing> TestLLSDXMLParsingGroup;
+ typedef TestLLSDXMLParsingGroup::object TestLLSDXMLParsingObject;
+ TestLLSDXMLParsingGroup gTestLLSDXMLParsingGroup("llsd XML parsing");
+
+ template<> template<>
+ void TestLLSDXMLParsingObject::test<1>()
+ {
+ // test handling of xml not recognized as llsd results in an
+ // LLSD Undefined
+ ensureParse(
+ "malformed xml",
+ "<llsd><string>ha ha</string>",
+ LLSD(),
+ LLSDParser::PARSE_FAILURE);
+ ensureParse(
+ "not llsd",
+ "<html><body><p>ha ha</p></body></html>",
+ LLSD(),
+ LLSDParser::PARSE_FAILURE);
+ ensureParse(
+ "value without llsd",
+ "<string>ha ha</string>",
+ LLSD(),
+ LLSDParser::PARSE_FAILURE);
+ ensureParse(
+ "key without llsd",
+ "<key>ha ha</key>",
+ LLSD(),
+ LLSDParser::PARSE_FAILURE);
+ }
+
+
+ template<> template<>
+ void TestLLSDXMLParsingObject::test<2>()
+ {
+ // test handling of unrecognized or unparseable llsd values
+ LLSD v;
+ v["amy"] = 23;
+ v["bob"] = LLSD();
+ v["cam"] = 1.23;
+
+ ensureParse(
+ "unknown data type",
+ "<llsd><map>"
+ "<key>amy</key><integer>23</integer>"
+ "<key>bob</key><bigint>99999999999999999</bigint>"
+ "<key>cam</key><real>1.23</real>"
+ "</map></llsd>",
+ v,
+ v.size() + 1);
+ }
+
+ template<> template<>
+ void TestLLSDXMLParsingObject::test<3>()
+ {
+ // test handling of nested bad data
+
+ LLSD v;
+ v["amy"] = 23;
+ v["cam"] = 1.23;
+
+ ensureParse(
+ "map with html",
+ "<llsd><map>"
+ "<key>amy</key><integer>23</integer>"
+ "<html><body>ha ha</body></html>"
+ "<key>cam</key><real>1.23</real>"
+ "</map></llsd>",
+ v,
+ v.size() + 1);
+
+ v.clear();
+ v["amy"] = 23;
+ v["cam"] = 1.23;
+ ensureParse(
+ "map with value for key",
+ "<llsd><map>"
+ "<key>amy</key><integer>23</integer>"
+ "<string>ha ha</string>"
+ "<key>cam</key><real>1.23</real>"
+ "</map></llsd>",
+ v,
+ v.size() + 1);
+
+ v.clear();
+ v["amy"] = 23;
+ v["bob"] = LLSD::emptyMap();
+ v["cam"] = 1.23;
+ ensureParse(
+ "map with map of html",
+ "<llsd><map>"
+ "<key>amy</key><integer>23</integer>"
+ "<key>bob</key>"
+ "<map>"
+ "<html><body>ha ha</body></html>"
+ "</map>"
+ "<key>cam</key><real>1.23</real>"
+ "</map></llsd>",
+ v,
+ v.size() + 1);
+
+ v.clear();
+ v[0] = 23;
+ v[1] = LLSD();
+ v[2] = 1.23;
+
+ ensureParse(
+ "array value of html",
+ "<llsd><array>"
+ "<integer>23</integer>"
+ "<html><body>ha ha</body></html>"
+ "<real>1.23</real>"
+ "</array></llsd>",
+ v,
+ v.size() + 1);
+
+ v.clear();
+ v[0] = 23;
+ v[1] = LLSD::emptyMap();
+ v[2] = 1.23;
+ ensureParse(
+ "array with map of html",
+ "<llsd><array>"
+ "<integer>23</integer>"
+ "<map>"
+ "<html><body>ha ha</body></html>"
+ "</map>"
+ "<real>1.23</real>"
+ "</array></llsd>",
+ v,
+ v.size() + 1);
+ }
+
+ template<> template<>
+ void TestLLSDXMLParsingObject::test<4>()
+ {
+ // test handling of binary object in XML
+ std::string xml;
+ LLSD expected;
+
+ // Generated by: echo -n 'hello' | openssl enc -e -base64
+ expected = string_to_vector("hello");
+ xml = "<llsd><binary encoding=\"base64\">aGVsbG8=</binary></llsd>\n";
+ ensureParse(
+ "the word 'hello' packed in binary encoded base64",
+ xml,
+ expected,
+ 1);
+
+ expected = string_to_vector("6|6|asdfhappybox|60e44ec5-305c-43c2-9a19-b4b89b1ae2a6|60e44ec5-305c-43c2-9a19-b4b89b1ae2a6|60e44ec5-305c-43c2-9a19-b4b89b1ae2a6|00000000-0000-0000-0000-000000000000|7fffffff|7fffffff|0|0|82000|450fe394-2904-c9ad-214c-a07eb7feec29|(No Description)|0|10|0");
+ xml = "<llsd><binary encoding=\"base64\">Nnw2fGFzZGZoYXBweWJveHw2MGU0NGVjNS0zMDVjLTQzYzItOWExOS1iNGI4OWIxYWUyYTZ8NjBlNDRlYzUtMzA1Yy00M2MyLTlhMTktYjRiODliMWFlMmE2fDYwZTQ0ZWM1LTMwNWMtNDNjMi05YTE5LWI0Yjg5YjFhZTJhNnwwMDAwMDAwMC0wMDAwLTAwMDAtMDAwMC0wMDAwMDAwMDAwMDB8N2ZmZmZmZmZ8N2ZmZmZmZmZ8MHwwfDgyMDAwfDQ1MGZlMzk0LTI5MDQtYzlhZC0yMTRjLWEwN2ViN2ZlZWMyOXwoTm8gRGVzY3JpcHRpb24pfDB8MTB8MA==</binary></llsd>\n";
+ ensureParse(
+ "a common binary blob for object -> agent offline inv transfer",
+ xml,
+ expected,
+ 1);
+
+ expected = string_to_vector("6|6|asdfhappybox|60e44ec5-305c-43c2-9a19-b4b89b1ae2a6|60e44ec5-305c-43c2-9a19-b4b89b1ae2a6|60e44ec5-305c-43c2-9a19-b4b89b1ae2a6|00000000-0000-0000-0000-000000000000|7fffffff|7fffffff|0|0|82000|450fe394-2904-c9ad-214c-a07eb7feec29|(No Description)|0|10|0");
+ xml = "<llsd><binary encoding=\"base64\">Nnw2fGFzZGZoYXBweWJveHw2MGU0NGVjNS0zMDVjLTQzYzItOWExOS1iNGI4OWIxYWUyYTZ8NjBl\n";
+ xml += "NDRlYzUtMzA1Yy00M2MyLTlhMTktYjRiODliMWFlMmE2fDYwZTQ0ZWM1LTMwNWMtNDNjMi05YTE5\n";
+ xml += "LWI0Yjg5YjFhZTJhNnwwMDAwMDAwMC0wMDAwLTAwMDAtMDAwMC0wMDAwMDAwMDAwMDB8N2ZmZmZm\n";
+ xml += "ZmZ8N2ZmZmZmZmZ8MHwwfDgyMDAwfDQ1MGZlMzk0LTI5MDQtYzlhZC0yMTRjLWEwN2ViN2ZlZWMy\n";
+ xml += "OXwoTm8gRGVzY3JpcHRpb24pfDB8MTB8MA==</binary></llsd>\n";
+ ensureParse(
+ "a common binary blob for object -> agent offline inv transfer",
+ xml,
+ expected,
+ 1);
+ }
+ /*
+ TODO:
+ test XML parsing
+ binary with unrecognized encoding
+ nested LLSD tags
+ multiple values inside an LLSD
+ */
+
+
+ /**
+ * @class TestLLSDNotationParsing
+ * @brief Concrete instance of a parse tester.
+ */
+ class TestLLSDNotationParsing : public TestLLSDParsing<LLSDNotationParser>
+ {
+ public:
+ TestLLSDNotationParsing() {}
+ };
+
+ typedef tut::test_group<TestLLSDNotationParsing> TestLLSDNotationParsingGroup;
+ typedef TestLLSDNotationParsingGroup::object TestLLSDNotationParsingObject;
+ TestLLSDNotationParsingGroup gTestLLSDNotationParsingGroup(
+ "llsd notation parsing");
+
+ template<> template<>
+ void TestLLSDNotationParsingObject::test<1>()
+ {
+ // test handling of xml not recognized as llsd results in an
+ // LLSD Undefined
+ ensureParse(
+ "malformed notation map",
+ "{'ha ha'",
+ LLSD(),
+ LLSDParser::PARSE_FAILURE);
+ ensureParse(
+ "malformed notation array",
+ "['ha ha'",
+ LLSD(),
+ LLSDParser::PARSE_FAILURE);
+ ensureParse(
+ "malformed notation string",
+ "'ha ha",
+ LLSD(),
+ LLSDParser::PARSE_FAILURE);
+ ensureParse(
+ "bad notation noise",
+ "g48ejlnfr",
+ LLSD(),
+ LLSDParser::PARSE_FAILURE);
+ }
+
+ template<> template<>
+ void TestLLSDNotationParsingObject::test<2>()
+ {
+ ensureParse("valid undef", "!", LLSD(), 1);
+ }
+
+ template<> template<>
+ void TestLLSDNotationParsingObject::test<3>()
+ {
+ LLSD val = false;
+ ensureParse("valid boolean false 0", "false", val, 1);
+ ensureParse("valid boolean false 1", "f", val, 1);
+ ensureParse("valid boolean false 2", "0", val, 1);
+ ensureParse("valid boolean false 3", "F", val, 1);
+ ensureParse("valid boolean false 4", "FALSE", val, 1);
+ val = true;
+ ensureParse("valid boolean true 0", "true", val, 1);
+ ensureParse("valid boolean true 1", "t", val, 1);
+ ensureParse("valid boolean true 2", "1", val, 1);
+ ensureParse("valid boolean true 3", "T", val, 1);
+ ensureParse("valid boolean true 4", "TRUE", val, 1);
+
+ val.clear();
+ ensureParse("invalid true", "TR", val, LLSDParser::PARSE_FAILURE);
+ ensureParse("invalid false", "FAL", val, LLSDParser::PARSE_FAILURE);
+ }
+
+ template<> template<>
+ void TestLLSDNotationParsingObject::test<4>()
+ {
+ LLSD val = 123;
+ ensureParse("valid integer", "i123", val, 1);
+ val.clear();
+ ensureParse("invalid integer", "421", val, LLSDParser::PARSE_FAILURE);
+ }
+
+ template<> template<>
+ void TestLLSDNotationParsingObject::test<5>()
+ {
+ LLSD val = 456.7;
+ ensureParse("valid real", "r456.7", val, 1);
+ val.clear();
+ ensureParse("invalid real", "456.7", val, LLSDParser::PARSE_FAILURE);
+ }
+
+ template<> template<>
+ void TestLLSDNotationParsingObject::test<6>()
+ {
+ LLUUID id;
+ LLSD val = id;
+ ensureParse(
+ "unparseable uuid",
+ "u123",
+ LLSD(),
+ LLSDParser::PARSE_FAILURE);
+ id.generate();
+ val = id;
+ std::string uuid_str("u");
+ uuid_str += id.asString();
+ ensureParse("valid uuid", uuid_str.c_str(), val, 1);
+ }
+
+ template<> template<>
+ void TestLLSDNotationParsingObject::test<7>()
+ {
+ LLSD val = std::string("foolish");
+ ensureParse("valid string 1", "\"foolish\"", val, 1);
+ val = std::string("g'day");
+ ensureParse("valid string 2", "\"g'day\"", val, 1);
+ val = std::string("have a \"nice\" day");
+ ensureParse("valid string 3", "'have a \"nice\" day'", val, 1);
+ val = std::string("whatever");
+ ensureParse("valid string 4", "s(8)\"whatever\"", val, 1);
+ }
+
+ template<> template<>
+ void TestLLSDNotationParsingObject::test<8>()
+ {
+ ensureParse(
+ "invalid string 1",
+ "s(7)\"whatever\"",
+ LLSD(),
+ LLSDParser::PARSE_FAILURE);
+ ensureParse(
+ "invalid string 2",
+ "s(9)\"whatever\"",
+ LLSD(),
+ LLSDParser::PARSE_FAILURE);
+ }
+
+ template<> template<>
+ void TestLLSDNotationParsingObject::test<9>()
+ {
+ LLSD val = LLURI("http://www.google.com");
+ ensureParse("valid uri", "l\"http://www.google.com\"", val, 1);
+ }
+
+ template<> template<>
+ void TestLLSDNotationParsingObject::test<10>()
+ {
+ LLSD val = LLDate("2007-12-28T09:22:53.10Z");
+ ensureParse("valid date", "d\"2007-12-28T09:22:53.10Z\"", val, 1);
+ }
+
+ template<> template<>
+ void TestLLSDNotationParsingObject::test<11>()
+ {
+ std::vector<U8> vec;
+ vec.push_back((U8)'a'); vec.push_back((U8)'b'); vec.push_back((U8)'c');
+ vec.push_back((U8)'3'); vec.push_back((U8)'2'); vec.push_back((U8)'1');
+ LLSD val = vec;
+ ensureParse("valid binary b64", "b64\"YWJjMzIx\"", val, 1);
+ ensureParse("valid bainry b16", "b16\"616263333231\"", val, 1);
+ ensureParse("valid bainry raw", "b(6)\"abc321\"", val, 1);
+ }
+
+ template<> template<>
+ void TestLLSDNotationParsingObject::test<12>()
+ {
+ ensureParse(
+ "invalid -- binary length specified too long",
+ "b(7)\"abc321\"",
+ LLSD(),
+ LLSDParser::PARSE_FAILURE);
+ ensureParse(
+ "invalid -- binary length specified way too long",
+ "b(1000000)\"abc321\"",
+ LLSD(),
+ LLSDParser::PARSE_FAILURE);
+ }
+
+ template<> template<>
+ void TestLLSDNotationParsingObject::test<13>()
+ {
+ LLSD val;
+ val["amy"] = 23;
+ val["bob"] = LLSD();
+ val["cam"] = 1.23;
+ ensureParse("simple map", "{'amy':i23,'bob':!,'cam':r1.23}", val, 4);
+
+ val["bob"] = LLSD::emptyMap();
+ val["bob"]["vehicle"] = std::string("bicycle");
+ ensureParse(
+ "nested map",
+ "{'amy':i23,'bob':{'vehicle':'bicycle'},'cam':r1.23}",
+ val,
+ 5);
+ }
+
+ template<> template<>
+ void TestLLSDNotationParsingObject::test<14>()
+ {
+ LLSD val;
+ val.append(23);
+ val.append(LLSD());
+ val.append(1.23);
+ ensureParse("simple array", "[i23,!,r1.23]", val, 4);
+ val[1] = LLSD::emptyArray();
+ val[1].append("bicycle");
+ ensureParse("nested array", "[i23,['bicycle'],r1.23]", val, 5);
+ }
+
+ template<> template<>
+ void TestLLSDNotationParsingObject::test<15>()
+ {
+ LLSD val;
+ val["amy"] = 23;
+ val["bob"]["dogs"] = LLSD::emptyArray();
+ val["bob"]["dogs"].append(LLSD::emptyMap());
+ val["bob"]["dogs"][0]["name"] = std::string("groove");
+ val["bob"]["dogs"][0]["breed"] = std::string("samoyed");
+ val["bob"]["dogs"].append(LLSD::emptyMap());
+ val["bob"]["dogs"][1]["name"] = std::string("greyley");
+ val["bob"]["dogs"][1]["breed"] = std::string("chow/husky");
+ val["cam"] = 1.23;
+ ensureParse(
+ "nested notation",
+ "{'amy':i23,"
+ " 'bob':{'dogs':["
+ "{'name':'groove', 'breed':'samoyed'},"
+ "{'name':'greyley', 'breed':'chow/husky'}]},"
+ " 'cam':r1.23}",
+ val,
+ 11);
+ }
+
+ template<> template<>
+ void TestLLSDNotationParsingObject::test<16>()
+ {
+ // text to make sure that incorrect sizes bail because
+ std::string bad_str("s(5)\"hi\"");
+ ensureParse(
+ "size longer than bytes left",
+ bad_str,
+ LLSD(),
+ LLSDParser::PARSE_FAILURE);
+ }
+
+ template<> template<>
+ void TestLLSDNotationParsingObject::test<17>()
+ {
+ // text to make sure that incorrect sizes bail because
+ std::string bad_bin("b(5)\"hi\"");
+ ensureParse(
+ "size longer than bytes left",
+ bad_bin,
+ LLSD(),
+ LLSDParser::PARSE_FAILURE);
+ }
+
+ /**
+ * @class TestLLSDBinaryParsing
+ * @brief Concrete instance of a parse tester.
+ */
+ class TestLLSDBinaryParsing : public TestLLSDParsing<LLSDBinaryParser>
+ {
+ public:
+ TestLLSDBinaryParsing() {}
+ };
+
+ typedef tut::test_group<TestLLSDBinaryParsing> TestLLSDBinaryParsingGroup;
+ typedef TestLLSDBinaryParsingGroup::object TestLLSDBinaryParsingObject;
+ TestLLSDBinaryParsingGroup gTestLLSDBinaryParsingGroup(
+ "llsd binary parsing");
+
+ template<> template<>
+ void TestLLSDBinaryParsingObject::test<1>()
+ {
+ std::vector<U8> vec;
+ vec.resize(6);
+ vec[0] = 'a'; vec[1] = 'b'; vec[2] = 'c';
+ vec[3] = '3'; vec[4] = '2'; vec[5] = '1';
+ std::string string_expected((char*)&vec[0], vec.size());
+ LLSD value = string_expected;
+
+ vec.resize(11);
+ vec[0] = 's'; // for string
+ vec[5] = 'a'; vec[6] = 'b'; vec[7] = 'c';
+ vec[8] = '3'; vec[9] = '2'; vec[10] = '1';
+
+ uint32_t size = htonl(6);
+ memcpy(&vec[1], &size, sizeof(uint32_t));
+ std::string str_good((char*)&vec[0], vec.size());
+ ensureParse("correct string parse", str_good, value, 1);
+
+ size = htonl(7);
+ memcpy(&vec[1], &size, sizeof(uint32_t));
+ std::string str_bad_1((char*)&vec[0], vec.size());
+ ensureParse(
+ "incorrect size string parse",
+ str_bad_1,
+ LLSD(),
+ LLSDParser::PARSE_FAILURE);
+
+ size = htonl(100000);
+ memcpy(&vec[1], &size, sizeof(uint32_t));
+ std::string str_bad_2((char*)&vec[0], vec.size());
+ ensureParse(
+ "incorrect size string parse",
+ str_bad_2,
+ LLSD(),
+ LLSDParser::PARSE_FAILURE);
+ }
+
+ template<> template<>
+ void TestLLSDBinaryParsingObject::test<2>()
+ {
+ std::vector<U8> vec;
+ vec.resize(6);
+ vec[0] = 'a'; vec[1] = 'b'; vec[2] = 'c';
+ vec[3] = '3'; vec[4] = '2'; vec[5] = '1';
+ LLSD value = vec;
+
+ vec.resize(11);
+ vec[0] = 'b'; // for binary
+ vec[5] = 'a'; vec[6] = 'b'; vec[7] = 'c';
+ vec[8] = '3'; vec[9] = '2'; vec[10] = '1';
+
+ uint32_t size = htonl(6);
+ memcpy(&vec[1], &size, sizeof(uint32_t));
+ std::string str_good((char*)&vec[0], vec.size());
+ ensureParse("correct binary parse", str_good, value, 1);
+
+ size = htonl(7);
+ memcpy(&vec[1], &size, sizeof(uint32_t));
+ std::string str_bad_1((char*)&vec[0], vec.size());
+ ensureParse(
+ "incorrect size binary parse 1",
+ str_bad_1,
+ LLSD(),
+ LLSDParser::PARSE_FAILURE);
+
+ size = htonl(100000);
+ memcpy(&vec[1], &size, sizeof(uint32_t));
+ std::string str_bad_2((char*)&vec[0], vec.size());
+ ensureParse(
+ "incorrect size binary parse 2",
+ str_bad_2,
+ LLSD(),
+ LLSDParser::PARSE_FAILURE);
+ }
+
+ template<> template<>
+ void TestLLSDBinaryParsingObject::test<3>()
+ {
+ // test handling of xml not recognized as llsd results in an
+ // LLSD Undefined
+ ensureParse(
+ "malformed binary map",
+ "{'ha ha'",
+ LLSD(),
+ LLSDParser::PARSE_FAILURE);
+ ensureParse(
+ "malformed binary array",
+ "['ha ha'",
+ LLSD(),
+ LLSDParser::PARSE_FAILURE);
+ ensureParse(
+ "malformed binary string",
+ "'ha ha",
+ LLSD(),
+ LLSDParser::PARSE_FAILURE);
+ ensureParse(
+ "bad noise",
+ "g48ejlnfr",
+ LLSD(),
+ LLSDParser::PARSE_FAILURE);
+ }
+ template<> template<>
+ void TestLLSDBinaryParsingObject::test<4>()
+ {
+ ensureParse("valid undef", "!", LLSD(), 1);
+ }
+
+ template<> template<>
+ void TestLLSDBinaryParsingObject::test<5>()
+ {
+ LLSD val = false;
+ ensureParse("valid boolean false 2", "0", val, 1);
+ val = true;
+ ensureParse("valid boolean true 2", "1", val, 1);
+
+ val.clear();
+ ensureParse("invalid true", "t", val, LLSDParser::PARSE_FAILURE);
+ ensureParse("invalid false", "f", val, LLSDParser::PARSE_FAILURE);
+ }
+
+ template<> template<>
+ void TestLLSDBinaryParsingObject::test<6>()
+ {
+ std::vector<U8> vec;
+ vec.push_back('{');
+ vec.resize(vec.size() + 4);
+ uint32_t size = htonl(1);
+ memcpy(&vec[1], &size, sizeof(uint32_t));
+ vec.push_back('k');
+ int key_size_loc = vec.size();
+ size = htonl(1); // 1 too short
+ vec.resize(vec.size() + 4);
+ memcpy(&vec[key_size_loc], &size, sizeof(uint32_t));
+ vec.push_back('a'); vec.push_back('m'); vec.push_back('y');
+ vec.push_back('i');
+ int integer_loc = vec.size();
+ vec.resize(vec.size() + 4);
+ uint32_t val_int = htonl(23);
+ memcpy(&vec[integer_loc], &val_int, sizeof(uint32_t));
+ std::string str_bad_1((char*)&vec[0], vec.size());
+ ensureParse(
+ "invalid key size",
+ str_bad_1,
+ LLSD(),
+ LLSDParser::PARSE_FAILURE);
+
+ // check with correct size, but unterminated map (missing '}')
+ size = htonl(3); // correct size
+ memcpy(&vec[key_size_loc], &size, sizeof(uint32_t));
+ std::string str_bad_2((char*)&vec[0], vec.size());
+ ensureParse(
+ "valid key size, unterminated map",
+ str_bad_2,
+ LLSD(),
+ LLSDParser::PARSE_FAILURE);
+
+ // check w/ correct size and correct map termination
+ LLSD val;
+ val["amy"] = 23;
+ vec.push_back('}');
+ std::string str_good((char*)&vec[0], vec.size());
+ ensureParse(
+ "valid map",
+ str_good,
+ val,
+ 2);
+
+ // check w/ incorrect sizes and correct map termination
+ size = htonl(0); // 1 too few (for the map entry)
+ memcpy(&vec[1], &size, sizeof(uint32_t));
+ std::string str_bad_3((char*)&vec[0], vec.size());
+ ensureParse(
+ "invalid map too long",
+ str_bad_3,
+ LLSD(),
+ LLSDParser::PARSE_FAILURE);
+
+ size = htonl(2); // 1 too many
+ memcpy(&vec[1], &size, sizeof(uint32_t));
+ std::string str_bad_4((char*)&vec[0], vec.size());
+ ensureParse(
+ "invalid map too short",
+ str_bad_4,
+ LLSD(),
+ LLSDParser::PARSE_FAILURE);
+ }
+
+ template<> template<>
+ void TestLLSDBinaryParsingObject::test<7>()
+ {
+ std::vector<U8> vec;
+ vec.push_back('[');
+ vec.resize(vec.size() + 4);
+ uint32_t size = htonl(1); // 1 too short
+ memcpy(&vec[1], &size, sizeof(uint32_t));
+ vec.push_back('"'); vec.push_back('a'); vec.push_back('m');
+ vec.push_back('y'); vec.push_back('"'); vec.push_back('i');
+ int integer_loc = vec.size();
+ vec.resize(vec.size() + 4);
+ uint32_t val_int = htonl(23);
+ memcpy(&vec[integer_loc], &val_int, sizeof(uint32_t));
+
+ std::string str_bad_1((char*)&vec[0], vec.size());
+ ensureParse(
+ "invalid array size",
+ str_bad_1,
+ LLSD(),
+ LLSDParser::PARSE_FAILURE);
+
+ // check with correct size, but unterminated map (missing ']')
+ size = htonl(2); // correct size
+ memcpy(&vec[1], &size, sizeof(uint32_t));
+ std::string str_bad_2((char*)&vec[0], vec.size());
+ ensureParse(
+ "unterminated array",
+ str_bad_2,
+ LLSD(),
+ LLSDParser::PARSE_FAILURE);
+
+ // check w/ correct size and correct map termination
+ LLSD val;
+ val.append("amy");
+ val.append(23);
+ vec.push_back(']');
+ std::string str_good((char*)&vec[0], vec.size());
+ ensureParse(
+ "valid array",
+ str_good,
+ val,
+ 3);
+
+ // check with too many elements
+ size = htonl(3); // 1 too long
+ memcpy(&vec[1], &size, sizeof(uint32_t));
+ std::string str_bad_3((char*)&vec[0], vec.size());
+ ensureParse(
+ "array too short",
+ str_bad_3,
+ LLSD(),
+ LLSDParser::PARSE_FAILURE);
+ }
+
+ template<> template<>
+ void TestLLSDBinaryParsingObject::test<8>()
+ {
+ std::vector<U8> vec;
+ vec.push_back('{');
+ vec.resize(vec.size() + 4);
+ memset(&vec[1], 0, 4);
+ vec.push_back('}');
+ std::string str_good((char*)&vec[0], vec.size());
+ LLSD val = LLSD::emptyMap();
+ ensureParse(
+ "empty map",
+ str_good,
+ val,
+ 1);
+ }
+
+ template<> template<>
+ void TestLLSDBinaryParsingObject::test<9>()
+ {
+ std::vector<U8> vec;
+ vec.push_back('[');
+ vec.resize(vec.size() + 4);
+ memset(&vec[1], 0, 4);
+ vec.push_back(']');
+ std::string str_good((char*)&vec[0], vec.size());
+ LLSD val = LLSD::emptyArray();
+ ensureParse(
+ "empty array",
+ str_good,
+ val,
+ 1);
+ }
+
+ template<> template<>
+ void TestLLSDBinaryParsingObject::test<10>()
+ {
+ std::vector<U8> vec;
+ vec.push_back('l');
+ vec.resize(vec.size() + 4);
+ uint32_t size = htonl(14); // 1 too long
+ memcpy(&vec[1], &size, sizeof(uint32_t));
+ vec.push_back('h'); vec.push_back('t'); vec.push_back('t');
+ vec.push_back('p'); vec.push_back(':'); vec.push_back('/');
+ vec.push_back('/'); vec.push_back('s'); vec.push_back('l');
+ vec.push_back('.'); vec.push_back('c'); vec.push_back('o');
+ vec.push_back('m');
+ std::string str_bad((char*)&vec[0], vec.size());
+ ensureParse(
+ "invalid uri length size",
+ str_bad,
+ LLSD(),
+ LLSDParser::PARSE_FAILURE);
+
+ LLSD val;
+ val = LLURI("http://sl.com");
+ size = htonl(13); // correct length
+ memcpy(&vec[1], &size, sizeof(uint32_t));
+ std::string str_good((char*)&vec[0], vec.size());
+ ensureParse(
+ "valid key size",
+ str_good,
+ val,
+ 1);
+ }
+
+/*
+ template<> template<>
+ void TestLLSDBinaryParsingObject::test<11>()
+ {
+ }
+*/
+
+ /**
+ * @class TestLLSDCrossCompatible
+ * @brief Miscellaneous serialization and parsing tests
+ */
+ class TestLLSDCrossCompatible
+ {
+ public:
+ TestLLSDCrossCompatible() {}
+
+ void ensureBinaryAndNotation(
+ const std::string& msg,
+ const LLSD& input)
+ {
+ // to binary, and back again
+ std::stringstream str1;
+ S32 count1 = LLSDSerialize::toBinary(input, str1);
+ LLSD actual_value_bin;
+ S32 count2 = LLSDSerialize::fromBinary(
+ actual_value_bin,
+ str1,
+ LLSDSerialize::SIZE_UNLIMITED);
+ ensure_equals(
+ "ensureBinaryAndNotation binary count",
+ count2,
+ count1);
+
+ // to notation and back again
+ std::stringstream str2;
+ S32 count3 = LLSDSerialize::toNotation(actual_value_bin, str2);
+ ensure_equals(
+ "ensureBinaryAndNotation notation count1",
+ count3,
+ count2);
+ LLSD actual_value_notation;
+ S32 count4 = LLSDSerialize::fromNotation(
+ actual_value_notation,
+ str2,
+ LLSDSerialize::SIZE_UNLIMITED);
+ ensure_equals(
+ "ensureBinaryAndNotation notation count2",
+ count4,
+ count3);
+ ensure_equals(
+ (msg + " (binaryandnotation)").c_str(),
+ actual_value_notation,
+ input);
+ }
+
+ void ensureBinaryAndXML(
+ const std::string& msg,
+ const LLSD& input)
+ {
+ // to binary, and back again
+ std::stringstream str1;
+ S32 count1 = LLSDSerialize::toBinary(input, str1);
+ LLSD actual_value_bin;
+ S32 count2 = LLSDSerialize::fromBinary(
+ actual_value_bin,
+ str1,
+ LLSDSerialize::SIZE_UNLIMITED);
+ ensure_equals(
+ "ensureBinaryAndXML binary count",
+ count2,
+ count1);
+
+ // to xml and back again
+ std::stringstream str2;
+ S32 count3 = LLSDSerialize::toXML(actual_value_bin, str2);
+ ensure_equals(
+ "ensureBinaryAndXML xml count1",
+ count3,
+ count2);
+ LLSD actual_value_xml;
+ S32 count4 = LLSDSerialize::fromXML(actual_value_xml, str2);
+ ensure_equals(
+ "ensureBinaryAndXML xml count2",
+ count4,
+ count3);
+ ensure_equals((msg + " (binaryandxml)").c_str(), actual_value_xml, input);
+ }
+ };
+
+ typedef tut::test_group<TestLLSDCrossCompatible> TestLLSDCompatibleGroup;
+ typedef TestLLSDCompatibleGroup::object TestLLSDCompatibleObject;
+ TestLLSDCompatibleGroup gTestLLSDCompatibleGroup(
+ "llsd serialize compatible");
+
+ template<> template<>
+ void TestLLSDCompatibleObject::test<1>()
+ {
+ LLSD test;
+ ensureBinaryAndNotation("undef", test);
+ ensureBinaryAndXML("undef", test);
+ test = true;
+ ensureBinaryAndNotation("boolean true", test);
+ ensureBinaryAndXML("boolean true", test);
+ test = false;
+ ensureBinaryAndNotation("boolean false", test);
+ ensureBinaryAndXML("boolean false", test);
+ test = 0;
+ ensureBinaryAndNotation("integer zero", test);
+ ensureBinaryAndXML("integer zero", test);
+ test = 1;
+ ensureBinaryAndNotation("integer positive", test);
+ ensureBinaryAndXML("integer positive", test);
+ test = -234567;
+ ensureBinaryAndNotation("integer negative", test);
+ ensureBinaryAndXML("integer negative", test);
+ test = 0.0;
+ ensureBinaryAndNotation("real zero", test);
+ ensureBinaryAndXML("real zero", test);
+ test = 1.0;
+ ensureBinaryAndNotation("real positive", test);
+ ensureBinaryAndXML("real positive", test);
+ test = -1.0;
+ ensureBinaryAndNotation("real negative", test);
+ ensureBinaryAndXML("real negative", test);
+ }
+
+ template<> template<>
+ void TestLLSDCompatibleObject::test<2>()
+ {
+ LLSD test;
+ test = "foobar";
+ ensureBinaryAndNotation("string", test);
+ ensureBinaryAndXML("string", test);
+ }
+
+ template<> template<>
+ void TestLLSDCompatibleObject::test<3>()
+ {
+ LLSD test;
+ LLUUID id;
+ id.generate();
+ test = id;
+ ensureBinaryAndNotation("uuid", test);
+ ensureBinaryAndXML("uuid", test);
+ }
+
+ template<> template<>
+ void TestLLSDCompatibleObject::test<4>()
+ {
+ LLSD test;
+ test = LLDate(12345.0);
+ ensureBinaryAndNotation("date", test);
+ ensureBinaryAndXML("date", test);
+ }
+
+ template<> template<>
+ void TestLLSDCompatibleObject::test<5>()
+ {
+ LLSD test;
+ test = LLURI("http://www.secondlife.com/");
+ ensureBinaryAndNotation("uri", test);
+ ensureBinaryAndXML("uri", test);
+ }
+
+ template<> template<>
+ void TestLLSDCompatibleObject::test<6>()
+ {
+ LLSD test;
+ typedef std::vector<U8> buf_t;
+ buf_t val;
+ for(int ii = 0; ii < 100; ++ii)
+ {
+ srand(ii); /* Flawfinder: ignore */
+ S32 size = rand() % 100 + 10;
+ std::generate_n(
+ std::back_insert_iterator<buf_t>(val),
+ size,
+ rand);
+ }
+ test = val;
+ ensureBinaryAndNotation("binary", test);
+ ensureBinaryAndXML("binary", test);
+ }
+
+ template<> template<>
+ void TestLLSDCompatibleObject::test<7>()
+ {
+ LLSD test;
+ test = LLSD::emptyArray();
+ test.append(1);
+ test.append("hello");
+ ensureBinaryAndNotation("array", test);
+ ensureBinaryAndXML("array", test);
+ }
+
+ template<> template<>
+ void TestLLSDCompatibleObject::test<8>()
+ {
+ LLSD test;
+ test = LLSD::emptyArray();
+ test["foo"] = "bar";
+ test["baz"] = 100;
+ ensureBinaryAndNotation("map", test);
+ ensureBinaryAndXML("map", test);
+ }
+}
+
diff --git a/indra/llcommon/tests/llstring_test.cpp b/indra/llcommon/tests/llstring_test.cpp
new file mode 100644
index 0000000000..304e91ed92
--- /dev/null
+++ b/indra/llcommon/tests/llstring_test.cpp
@@ -0,0 +1,745 @@
+/**
+ * @file llstring_test.cpp
+ * @author Adroit, Steve Linden, Tofu Linden
+ * @date 2006-12-24
+ * @brief Test cases of llstring.cpp
+ *
+ * $LicenseInfo:firstyear=2007&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$
+ */
+
+#include "linden_common.h"
+#include "../test/lltut.h"
+
+#include "../llstring.h"
+
+namespace tut
+{
+ struct string_index
+ {
+ };
+ typedef test_group<string_index> string_index_t;
+ typedef string_index_t::object string_index_object_t;
+ tut::string_index_t tut_string_index("LLString");
+
+ template<> template<>
+ void string_index_object_t::test<1>()
+ {
+ std::string llstr1;
+ ensure("Empty std::string", (llstr1.size() == 0) && llstr1.empty());
+
+ std::string llstr2("Hello");
+ ensure("std::string = Hello", (!strcmp(llstr2.c_str(), "Hello")) && (llstr2.size() == 5) && !llstr2.empty());
+
+ std::string llstr3(llstr2);
+ ensure("std::string = std::string(std::string)", (!strcmp(llstr3.c_str(), "Hello")) && (llstr3.size() == 5) && !llstr3.empty());
+
+ std::string str("Hello World");
+ std::string llstr4(str, 6);
+ ensure("std::string = std::string(s, size_type pos, size_type n = npos)", (!strcmp(llstr4.c_str(), "World")) && (llstr4.size() == 5) && !llstr4.empty());
+
+ std::string llstr5(str, str.size());
+ ensure("std::string = std::string(s, size_type pos, size_type n = npos)", (llstr5.size() == 0) && llstr5.empty());
+
+ std::string llstr6(5, 'A');
+ ensure("std::string = std::string(count, c)", (!strcmp(llstr6.c_str(), "AAAAA")) && (llstr6.size() == 5) && !llstr6.empty());
+
+ std::string llstr7("Hello World", 5);
+ ensure("std::string(s, n)", (!strcmp(llstr7.c_str(), "Hello")) && (llstr7.size() == 5) && !llstr7.empty());
+
+ std::string llstr8("Hello World", 6, 5);
+ ensure("std::string(s, n, count)", (!strcmp(llstr8.c_str(), "World")) && (llstr8.size() == 5) && !llstr8.empty());
+
+ std::string llstr9("Hello World", sizeof("Hello World")-1, 5); // go past end
+ ensure("std::string(s, n, count) goes past end", (llstr9.size() == 0) && llstr9.empty());
+ }
+
+ template<> template<>
+ void string_index_object_t::test<3>()
+ {
+ std::string str("Len=5");
+ ensure("isValidIndex failed", LLStringUtil::isValidIndex(str, 0) == TRUE &&
+ LLStringUtil::isValidIndex(str, 5) == TRUE &&
+ LLStringUtil::isValidIndex(str, 6) == FALSE);
+
+ std::string str1;
+ ensure("isValidIndex failed fo rempty string", LLStringUtil::isValidIndex(str1, 0) == FALSE);
+ }
+
+ template<> template<>
+ void string_index_object_t::test<4>()
+ {
+ std::string str_val(" Testing the extra whitespaces ");
+ LLStringUtil::trimHead(str_val);
+ ensure_equals("1: trimHead failed", str_val, "Testing the extra whitespaces ");
+
+ std::string str_val1("\n\t\r\n Testing the extra whitespaces ");
+ LLStringUtil::trimHead(str_val1);
+ ensure_equals("2: trimHead failed", str_val1, "Testing the extra whitespaces ");
+ }
+
+ template<> template<>
+ void string_index_object_t::test<5>()
+ {
+ std::string str_val(" Testing the extra whitespaces ");
+ LLStringUtil::trimTail(str_val);
+ ensure_equals("1: trimTail failed", str_val, " Testing the extra whitespaces");
+
+ std::string str_val1("\n Testing the extra whitespaces \n\t\r\n ");
+ LLStringUtil::trimTail(str_val1);
+ ensure_equals("2: trimTail failed", str_val1, "\n Testing the extra whitespaces");
+ }
+
+
+ template<> template<>
+ void string_index_object_t::test<6>()
+ {
+ std::string str_val(" \t \r Testing the extra \r\n whitespaces \n \t ");
+ LLStringUtil::trim(str_val);
+ ensure_equals("1: trim failed", str_val, "Testing the extra \r\n whitespaces");
+ }
+
+ template<> template<>
+ void string_index_object_t::test<7>()
+ {
+ std::string str("Second LindenLabs");
+ LLStringUtil::truncate(str, 6);
+ ensure_equals("1: truncate", str, "Second");
+
+ // further truncate more than the length
+ LLStringUtil::truncate(str, 0);
+ ensure_equals("2: truncate", str, "");
+ }
+
+ template<> template<>
+ void string_index_object_t::test<8>()
+ {
+ std::string str_val("SecondLife Source");
+ LLStringUtil::toUpper(str_val);
+ ensure_equals("toUpper failed", str_val, "SECONDLIFE SOURCE");
+ }
+
+ template<> template<>
+ void string_index_object_t::test<9>()
+ {
+ std::string str_val("SecondLife Source");
+ LLStringUtil::toLower(str_val);
+ ensure_equals("toLower failed", str_val, "secondlife source");
+ }
+
+ template<> template<>
+ void string_index_object_t::test<10>()
+ {
+ std::string str_val("Second");
+ ensure("1. isHead failed", LLStringUtil::isHead(str_val, "SecondLife Source") == TRUE);
+ ensure("2. isHead failed", LLStringUtil::isHead(str_val, " SecondLife Source") == FALSE);
+ std::string str_val2("");
+ ensure("3. isHead failed", LLStringUtil::isHead(str_val2, "") == FALSE);
+ }
+
+ template<> template<>
+ void string_index_object_t::test<11>()
+ {
+ std::string str_val("Hello.\n\n Lindenlabs. \n This is \na simple test.\n");
+ std::string orig_str_val(str_val);
+ LLStringUtil::addCRLF(str_val);
+ ensure_equals("addCRLF failed", str_val, "Hello.\r\n\r\n Lindenlabs. \r\n This is \r\na simple test.\r\n");
+ LLStringUtil::removeCRLF(str_val);
+ ensure_equals("removeCRLF failed", str_val, orig_str_val);
+ }
+
+ template<> template<>
+ void string_index_object_t::test<12>()
+ {
+ std::string str_val("Hello.\n\n\t \t Lindenlabs. \t\t");
+ std::string orig_str_val(str_val);
+ LLStringUtil::replaceTabsWithSpaces(str_val, 1);
+ ensure_equals("replaceTabsWithSpaces failed", str_val, "Hello.\n\n Lindenlabs. ");
+ LLStringUtil::replaceTabsWithSpaces(orig_str_val, 0);
+ ensure_equals("replaceTabsWithSpaces failed for 0", orig_str_val, "Hello.\n\n Lindenlabs. ");
+
+ str_val = "\t\t\t\t";
+ LLStringUtil::replaceTabsWithSpaces(str_val, 0);
+ ensure_equals("replaceTabsWithSpaces failed for all tabs", str_val, "");
+ }
+
+ template<> template<>
+ void string_index_object_t::test<13>()
+ {
+ std::string str_val("Hello.\n\n\t\t\r\nLindenlabsX.");
+ LLStringUtil::replaceNonstandardASCII(str_val, 'X');
+ ensure_equals("replaceNonstandardASCII failed", str_val, "Hello.\n\nXXX\nLindenlabsX.");
+ }
+
+ template<> template<>
+ void string_index_object_t::test<14>()
+ {
+ std::string str_val("Hello.\n\t\r\nABCDEFGHIABABAB");
+ LLStringUtil::replaceChar(str_val, 'A', 'X');
+ ensure_equals("1: replaceChar failed", str_val, "Hello.\n\t\r\nXBCDEFGHIXBXBXB");
+ std::string str_val1("Hello.\n\t\r\nABCDEFGHIABABAB");
+ }
+
+ template<> template<>
+ void string_index_object_t::test<15>()
+ {
+ std::string str_val("Hello.\n\r\t");
+ ensure("containsNonprintable failed", LLStringUtil::containsNonprintable(str_val) == TRUE);
+
+ str_val = "ABC ";
+ ensure("containsNonprintable failed", LLStringUtil::containsNonprintable(str_val) == FALSE);
+ }
+
+ template<> template<>
+ void string_index_object_t::test<16>()
+ {
+ std::string str_val("Hello.\n\r\t Again!");
+ LLStringUtil::stripNonprintable(str_val);
+ ensure_equals("stripNonprintable failed", str_val, "Hello. Again!");
+
+ str_val = "\r\n\t\t";
+ LLStringUtil::stripNonprintable(str_val);
+ ensure_equals("stripNonprintable resulting in empty string failed", str_val, "");
+
+ str_val = "";
+ LLStringUtil::stripNonprintable(str_val);
+ ensure_equals("stripNonprintable of empty string resulting in empty string failed", str_val, "");
+ }
+
+ template<> template<>
+ void string_index_object_t::test<17>()
+ {
+ BOOL value;
+ std::string str_val("1");
+ ensure("convertToBOOL 1 failed", LLStringUtil::convertToBOOL(str_val, value) && value);
+ str_val = "T";
+ ensure("convertToBOOL T failed", LLStringUtil::convertToBOOL(str_val, value) && value);
+ str_val = "t";
+ ensure("convertToBOOL t failed", LLStringUtil::convertToBOOL(str_val, value) && value);
+ str_val = "TRUE";
+ ensure("convertToBOOL TRUE failed", LLStringUtil::convertToBOOL(str_val, value) && value);
+ str_val = "True";
+ ensure("convertToBOOL True failed", LLStringUtil::convertToBOOL(str_val, value) && value);
+ str_val = "true";
+ ensure("convertToBOOL true failed", LLStringUtil::convertToBOOL(str_val, value) && value);
+
+ str_val = "0";
+ ensure("convertToBOOL 0 failed", LLStringUtil::convertToBOOL(str_val, value) && !value);
+ str_val = "F";
+ ensure("convertToBOOL F failed", LLStringUtil::convertToBOOL(str_val, value) && !value);
+ str_val = "f";
+ ensure("convertToBOOL f failed", LLStringUtil::convertToBOOL(str_val, value) && !value);
+ str_val = "FALSE";
+ ensure("convertToBOOL FASLE failed", LLStringUtil::convertToBOOL(str_val, value) && !value);
+ str_val = "False";
+ ensure("convertToBOOL False failed", LLStringUtil::convertToBOOL(str_val, value) && !value);
+ str_val = "false";
+ ensure("convertToBOOL false failed", LLStringUtil::convertToBOOL(str_val, value) && !value);
+
+ str_val = "Tblah";
+ ensure("convertToBOOL false failed", !LLStringUtil::convertToBOOL(str_val, value));
+ }
+
+ template<> template<>
+ void string_index_object_t::test<18>()
+ {
+ U8 value;
+ std::string str_val("255");
+ ensure("1: convertToU8 failed", LLStringUtil::convertToU8(str_val, value) && value == 255);
+
+ str_val = "0";
+ ensure("2: convertToU8 failed", LLStringUtil::convertToU8(str_val, value) && value == 0);
+
+ str_val = "-1";
+ ensure("3: convertToU8 failed", !LLStringUtil::convertToU8(str_val, value));
+
+ str_val = "256"; // bigger than MAX_U8
+ ensure("4: convertToU8 failed", !LLStringUtil::convertToU8(str_val, value));
+ }
+
+ template<> template<>
+ void string_index_object_t::test<19>()
+ {
+ S8 value;
+ std::string str_val("127");
+ ensure("1: convertToS8 failed", LLStringUtil::convertToS8(str_val, value) && value == 127);
+
+ str_val = "0";
+ ensure("2: convertToS8 failed", LLStringUtil::convertToS8(str_val, value) && value == 0);
+
+ str_val = "-128";
+ ensure("3: convertToS8 failed", LLStringUtil::convertToS8(str_val, value) && value == -128);
+
+ str_val = "128"; // bigger than MAX_S8
+ ensure("4: convertToS8 failed", !LLStringUtil::convertToS8(str_val, value));
+
+ str_val = "-129";
+ ensure("5: convertToS8 failed", !LLStringUtil::convertToS8(str_val, value));
+ }
+
+ template<> template<>
+ void string_index_object_t::test<20>()
+ {
+ S16 value;
+ std::string str_val("32767");
+ ensure("1: convertToS16 failed", LLStringUtil::convertToS16(str_val, value) && value == 32767);
+
+ str_val = "0";
+ ensure("2: convertToS16 failed", LLStringUtil::convertToS16(str_val, value) && value == 0);
+
+ str_val = "-32768";
+ ensure("3: convertToS16 failed", LLStringUtil::convertToS16(str_val, value) && value == -32768);
+
+ str_val = "32768";
+ ensure("4: convertToS16 failed", !LLStringUtil::convertToS16(str_val, value));
+
+ str_val = "-32769";
+ ensure("5: convertToS16 failed", !LLStringUtil::convertToS16(str_val, value));
+ }
+
+ template<> template<>
+ void string_index_object_t::test<21>()
+ {
+ U16 value;
+ std::string str_val("65535"); //0xFFFF
+ ensure("1: convertToU16 failed", LLStringUtil::convertToU16(str_val, value) && value == 65535);
+
+ str_val = "0";
+ ensure("2: convertToU16 failed", LLStringUtil::convertToU16(str_val, value) && value == 0);
+
+ str_val = "-1";
+ ensure("3: convertToU16 failed", !LLStringUtil::convertToU16(str_val, value));
+
+ str_val = "65536";
+ ensure("4: convertToU16 failed", !LLStringUtil::convertToU16(str_val, value));
+ }
+
+ template<> template<>
+ void string_index_object_t::test<22>()
+ {
+ U32 value;
+ std::string str_val("4294967295"); //0xFFFFFFFF
+ ensure("1: convertToU32 failed", LLStringUtil::convertToU32(str_val, value) && value == 4294967295UL);
+
+ str_val = "0";
+ ensure("2: convertToU32 failed", LLStringUtil::convertToU32(str_val, value) && value == 0);
+
+ str_val = "4294967296";
+ ensure("3: convertToU32 failed", !LLStringUtil::convertToU32(str_val, value));
+ }
+
+ template<> template<>
+ void string_index_object_t::test<23>()
+ {
+ S32 value;
+ std::string str_val("2147483647"); //0x7FFFFFFF
+ ensure("1: convertToS32 failed", LLStringUtil::convertToS32(str_val, value) && value == 2147483647);
+
+ str_val = "0";
+ ensure("2: convertToS32 failed", LLStringUtil::convertToS32(str_val, value) && value == 0);
+
+ // Avoid "unary minus operator applied to unsigned type" warning on VC++. JC
+ S32 min_val = -2147483647 - 1;
+ str_val = "-2147483648";
+ ensure("3: convertToS32 failed", LLStringUtil::convertToS32(str_val, value) && value == min_val);
+
+ str_val = "2147483648";
+ ensure("4: convertToS32 failed", !LLStringUtil::convertToS32(str_val, value));
+
+ str_val = "-2147483649";
+ ensure("5: convertToS32 failed", !LLStringUtil::convertToS32(str_val, value));
+ }
+
+ template<> template<>
+ void string_index_object_t::test<24>()
+ {
+ F32 value;
+ std::string str_val("2147483647"); //0x7FFFFFFF
+ ensure("1: convertToF32 failed", LLStringUtil::convertToF32(str_val, value) && value == 2147483647);
+
+ str_val = "0";
+ ensure("2: convertToF32 failed", LLStringUtil::convertToF32(str_val, value) && value == 0);
+
+ /* Need to find max/min F32 values
+ str_val = "-2147483648";
+ ensure("3: convertToF32 failed", LLStringUtil::convertToF32(str_val, value) && value == -2147483648);
+
+ str_val = "2147483648";
+ ensure("4: convertToF32 failed", !LLStringUtil::convertToF32(str_val, value));
+
+ str_val = "-2147483649";
+ ensure("5: convertToF32 failed", !LLStringUtil::convertToF32(str_val, value));
+ */
+ }
+
+ template<> template<>
+ void string_index_object_t::test<25>()
+ {
+ F64 value;
+ std::string str_val("9223372036854775807"); //0x7FFFFFFFFFFFFFFF
+ ensure("1: convertToF64 failed", LLStringUtil::convertToF64(str_val, value) && value == 9223372036854775807LL);
+
+ str_val = "0";
+ ensure("2: convertToF64 failed", LLStringUtil::convertToF64(str_val, value) && value == 0.0F);
+
+ /* Need to find max/min F64 values
+ str_val = "-2147483648";
+ ensure("3: convertToF32 failed", LLStringUtil::convertToF32(str_val, value) && value == -2147483648);
+
+ str_val = "2147483648";
+ ensure("4: convertToF32 failed", !LLStringUtil::convertToF32(str_val, value));
+
+ str_val = "-2147483649";
+ ensure("5: convertToF32 failed", !LLStringUtil::convertToF32(str_val, value));
+ */
+ }
+
+ template<> template<>
+ void string_index_object_t::test<26>()
+ {
+ const char* str1 = NULL;
+ const char* str2 = NULL;
+
+ ensure("1: compareStrings failed", LLStringUtil::compareStrings(str1, str2) == 0);
+ str2 = "A";
+ ensure("2: compareStrings failed", LLStringUtil::compareStrings(str1, str2) > 0);
+ ensure("3: compareStrings failed", LLStringUtil::compareStrings(str2, str1) < 0);
+
+ str1 = "A is smaller than B";
+ str2 = "B is greater than A";
+ ensure("4: compareStrings failed", LLStringUtil::compareStrings(str1, str2) < 0);
+
+ str2 = "A is smaller than B";
+ ensure("5: compareStrings failed", LLStringUtil::compareStrings(str1, str2) == 0);
+ }
+
+ template<> template<>
+ void string_index_object_t::test<27>()
+ {
+ const char* str1 = NULL;
+ const char* str2 = NULL;
+
+ ensure("1: compareInsensitive failed", LLStringUtil::compareInsensitive(str1, str2) == 0);
+ str2 = "A";
+ ensure("2: compareInsensitive failed", LLStringUtil::compareInsensitive(str1, str2) > 0);
+ ensure("3: compareInsensitive failed", LLStringUtil::compareInsensitive(str2, str1) < 0);
+
+ str1 = "A is equal to a";
+ str2 = "a is EQUAL to A";
+ ensure("4: compareInsensitive failed", LLStringUtil::compareInsensitive(str1, str2) == 0);
+ }
+
+ template<> template<>
+ void string_index_object_t::test<28>()
+ {
+ std::string lhs_str("PROgraM12files");
+ std::string rhs_str("PROgram12Files");
+ ensure("compareDict 1 failed", LLStringUtil::compareDict(lhs_str, rhs_str) < 0);
+ ensure("precedesDict 1 failed", LLStringUtil::precedesDict(lhs_str, rhs_str) == TRUE);
+
+ lhs_str = "PROgram12Files";
+ rhs_str = "PROgram12Files";
+ ensure("compareDict 2 failed", LLStringUtil::compareDict(lhs_str, rhs_str) == 0);
+ ensure("precedesDict 2 failed", LLStringUtil::precedesDict(lhs_str, rhs_str) == FALSE);
+
+ lhs_str = "PROgram12Files";
+ rhs_str = "PROgRAM12FILES";
+ ensure("compareDict 3 failed", LLStringUtil::compareDict(lhs_str, rhs_str) > 0);
+ ensure("precedesDict 3 failed", LLStringUtil::precedesDict(lhs_str, rhs_str) == FALSE);
+ }
+
+ template<> template<>
+ void string_index_object_t::test<29>()
+ {
+ char str1[] = "First String...";
+ char str2[100];
+
+ LLStringUtil::copy(str2, str1, 100);
+ ensure("LLStringUtil::copy with enough dest length failed", strcmp(str2, str1) == 0);
+ LLStringUtil::copy(str2, str1, sizeof("First"));
+ ensure("LLStringUtil::copy with less dest length failed", strcmp(str2, "First") == 0);
+ }
+
+ template<> template<>
+ void string_index_object_t::test<30>()
+ {
+ std::string str1 = "This is the sentence...";
+ std::string str2 = "This is the ";
+ std::string str3 = "first ";
+ std::string str4 = "This is the first sentence...";
+ std::string str5 = "This is the sentence...first ";
+ std::string dest;
+
+ dest = str1;
+ LLStringUtil::copyInto(dest, str3, str2.length());
+ ensure("LLStringUtil::copyInto insert failed", dest == str4);
+
+ dest = str1;
+ LLStringUtil::copyInto(dest, str3, dest.length());
+ ensure("LLStringUtil::copyInto append failed", dest == str5);
+ }
+
+ template<> template<>
+ void string_index_object_t::test<31>()
+ {
+ std::string stripped;
+
+ // Plain US ASCII text, including spaces and punctuation,
+ // should not be altered.
+ std::string simple_text = "Hello, world!";
+ stripped = LLStringFn::strip_invalid_xml(simple_text);
+ ensure("Simple text passed unchanged", stripped == simple_text);
+
+ // Control characters should be removed
+ // except for 0x09, 0x0a, 0x0d
+ std::string control_chars;
+ for (char c = 0x01; c < 0x20; c++)
+ {
+ control_chars.push_back(c);
+ }
+ std::string allowed_control_chars;
+ allowed_control_chars.push_back( (char)0x09 );
+ allowed_control_chars.push_back( (char)0x0a );
+ allowed_control_chars.push_back( (char)0x0d );
+
+ stripped = LLStringFn::strip_invalid_xml(control_chars);
+ ensure("Only tab, LF, CR control characters allowed",
+ stripped == allowed_control_chars);
+
+ // UTF-8 should be passed intact, including high byte
+ // characters. Try Francais (with C squiggle cedilla)
+ std::string french = "Fran";
+ french.push_back( (char)0xC3 );
+ french.push_back( (char)0xA7 );
+ french += "ais";
+ stripped = LLStringFn::strip_invalid_xml( french );
+ ensure("UTF-8 high byte text is allowed", french == stripped );
+ }
+
+ template<> template<>
+ void string_index_object_t::test<32>()
+ {
+ // Test LLStringUtil::format() string interpolation
+ LLStringUtil::format_map_t fmt_map;
+ std::string s;
+ int subcount;
+
+ fmt_map["[TRICK1]"] = "[A]";
+ fmt_map["[A]"] = "a";
+ fmt_map["[B]"] = "b";
+ fmt_map["[AAA]"] = "aaa";
+ fmt_map["[BBB]"] = "bbb";
+ fmt_map["[TRICK2]"] = "[A]";
+ fmt_map["[EXPLOIT]"] = "!!!!!!!!!!!![EXPLOIT]!!!!!!!!!!!!";
+ fmt_map["[KEYLONGER]"] = "short";
+ fmt_map["[KEYSHORTER]"] = "Am I not a long string?";
+ fmt_map["?"] = "?";
+ fmt_map["[DELETE]"] = "";
+ fmt_map["[]"] = "[]"; // doesn't do a substitution, but shouldn't crash either
+
+ for (LLStringUtil::format_map_t::const_iterator iter = fmt_map.begin(); iter != fmt_map.end(); ++iter)
+ {
+ // Test when source string is entirely one key
+ std::string s1 = (std::string)iter->first;
+ std::string s2 = (std::string)iter->second;
+ subcount = LLStringUtil::format(s1, fmt_map);
+ ensure_equals("LLStringUtil::format: Raw interpolation result", s1, s2);
+ if (s1 == "?" || s1 == "[]") // no interp expected
+ {
+ ensure_equals("LLStringUtil::format: Raw interpolation result count", 0, subcount);
+ }
+ else
+ {
+ ensure_equals("LLStringUtil::format: Raw interpolation result count", 1, subcount);
+ }
+ }
+
+ for (LLStringUtil::format_map_t::const_iterator iter = fmt_map.begin(); iter != fmt_map.end(); ++iter)
+ {
+ // Test when source string is one key, duplicated
+ std::string s1 = (std::string)iter->first;
+ std::string s2 = (std::string)iter->second;
+ s = s1 + s1 + s1 + s1;
+ subcount = LLStringUtil::format(s, fmt_map);
+ ensure_equals("LLStringUtil::format: Rawx4 interpolation result", s, s2 + s2 + s2 + s2);
+ if (s1 == "?" || s1 == "[]") // no interp expected
+ {
+ ensure_equals("LLStringUtil::format: Rawx4 interpolation result count", 0, subcount);
+ }
+ else
+ {
+ ensure_equals("LLStringUtil::format: Rawx4 interpolation result count", 4, subcount);
+ }
+ }
+
+ // Test when source string has no keys
+ std::string srcs = "!!!!!!!!!!!!!!!!";
+ s = srcs;
+ subcount = LLStringUtil::format(s, fmt_map);
+ ensure_equals("LLStringUtil::format: No key test result", s, srcs);
+ ensure_equals("LLStringUtil::format: No key test result count", 0, subcount);
+
+ // Test when source string has no keys and is empty
+ std::string srcs3;
+ s = srcs3;
+ subcount = LLStringUtil::format(s, fmt_map);
+ ensure("LLStringUtil::format: No key test3 result", s.empty());
+ ensure_equals("LLStringUtil::format: No key test3 result count", 0, subcount);
+
+ // Test a substitution where a key is substituted with blankness
+ std::string srcs2 = "[DELETE]";
+ s = srcs2;
+ subcount = LLStringUtil::format(s, fmt_map);
+ ensure("LLStringUtil::format: Delete key test2 result", s.empty());
+ ensure_equals("LLStringUtil::format: Delete key test2 result count", 1, subcount);
+
+ // Test an assorted substitution
+ std::string srcs4 = "[TRICK1][A][B][AAA][BBB][TRICK2][KEYLONGER][KEYSHORTER]?[DELETE]";
+ s = srcs4;
+ subcount = LLStringUtil::format(s, fmt_map);
+ ensure_equals("LLStringUtil::format: Assorted Test1 result", s, "[A]abaaabbb[A]shortAm I not a long string??");
+ ensure_equals("LLStringUtil::format: Assorted Test1 result count", 9, subcount);
+
+ // Test an assorted substitution
+ std::string srcs5 = "[DELETE]?[KEYSHORTER][KEYLONGER][TRICK2][BBB][AAA][B][A][TRICK1]";
+ s = srcs5;
+ subcount = LLStringUtil::format(s, fmt_map);
+ ensure_equals("LLStringUtil::format: Assorted Test2 result", s, "?Am I not a long string?short[A]bbbaaaba[A]");
+ ensure_equals("LLStringUtil::format: Assorted Test2 result count", 9, subcount);
+
+ // Test an assorted substitution
+ std::string srcs8 = "foo[DELETE]bar?";
+ s = srcs8;
+ subcount = LLStringUtil::format(s, fmt_map);
+ ensure_equals("LLStringUtil::format: Assorted Test3 result", s, "foobar?");
+ ensure_equals("LLStringUtil::format: Assorted Test3 result count", 1, subcount);
+ }
+
+ template<> template<>
+ void string_index_object_t::test<33>()
+ {
+ // Test LLStringUtil::format() string interpolation
+ LLStringUtil::format_map_t blank_fmt_map;
+ std::string s;
+ int subcount;
+
+ // Test substituting out of a blank format_map
+ std::string srcs6 = "12345";
+ s = srcs6;
+ subcount = LLStringUtil::format(s, blank_fmt_map);
+ ensure_equals("LLStringUtil::format: Blankfmt Test1 result", s, "12345");
+ ensure_equals("LLStringUtil::format: Blankfmt Test1 result count", 0, subcount);
+
+ // Test substituting a blank string out of a blank format_map
+ std::string srcs7;
+ s = srcs7;
+ subcount = LLStringUtil::format(s, blank_fmt_map);
+ ensure("LLStringUtil::format: Blankfmt Test2 result", s.empty());
+ ensure_equals("LLStringUtil::format: Blankfmt Test2 result count", 0, subcount);
+ }
+
+ template<> template<>
+ void string_index_object_t::test<34>()
+ {
+ // Test that incorrect LLStringUtil::format() use does not explode.
+ LLStringUtil::format_map_t nasty_fmt_map;
+ std::string s;
+ int subcount;
+
+ nasty_fmt_map[""] = "never used"; // see, this is nasty.
+
+ // Test substituting out of a nasty format_map
+ std::string srcs6 = "12345";
+ s = srcs6;
+ subcount = LLStringUtil::format(s, nasty_fmt_map);
+ ensure_equals("LLStringUtil::format: Nastyfmt Test1 result", s, "12345");
+ ensure_equals("LLStringUtil::format: Nastyfmt Test1 result count", 0, subcount);
+
+ // Test substituting a blank string out of a nasty format_map
+ std::string srcs7;
+ s = srcs7;
+ subcount = LLStringUtil::format(s, nasty_fmt_map);
+ ensure("LLStringUtil::format: Nastyfmt Test2 result", s.empty());
+ ensure_equals("LLStringUtil::format: Nastyfmt Test2 result count", 0, subcount);
+ }
+
+ template<> template<>
+ void string_index_object_t::test<35>()
+ {
+ // Make sure startsWith works
+ std::string string("anybody in there?");
+ std::string substr("anybody");
+ ensure("startsWith works.", LLStringUtil::startsWith(string, substr));
+ }
+
+ template<> template<>
+ void string_index_object_t::test<36>()
+ {
+ // Make sure startsWith correctly fails
+ std::string string("anybody in there?");
+ std::string substr("there");
+ ensure("startsWith fails.", !LLStringUtil::startsWith(string, substr));
+ }
+
+ template<> template<>
+ void string_index_object_t::test<37>()
+ {
+ // startsWith fails on empty strings
+ std::string value("anybody in there?");
+ std::string empty;
+ ensure("empty string.", !LLStringUtil::startsWith(value, empty));
+ ensure("empty substr.", !LLStringUtil::startsWith(empty, value));
+ ensure("empty everything.", !LLStringUtil::startsWith(empty, empty));
+ }
+
+ template<> template<>
+ void string_index_object_t::test<38>()
+ {
+ // Make sure endsWith works correctly
+ std::string string("anybody in there?");
+ std::string substr("there?");
+ ensure("endsWith works.", LLStringUtil::endsWith(string, substr));
+ }
+
+ template<> template<>
+ void string_index_object_t::test<39>()
+ {
+ // Make sure endsWith correctly fails
+ std::string string("anybody in there?");
+ std::string substr("anybody");
+ ensure("endsWith fails.", !LLStringUtil::endsWith(string, substr));
+ substr = "there";
+ ensure("endsWith fails.", !LLStringUtil::endsWith(string, substr));
+ substr = "ther?";
+ ensure("endsWith fails.", !LLStringUtil::endsWith(string, substr));
+ }
+
+ template<> template<>
+ void string_index_object_t::test<40>()
+ {
+ // endsWith fails on empty strings
+ std::string value("anybody in there?");
+ std::string empty;
+ ensure("empty string.", !LLStringUtil::endsWith(value, empty));
+ ensure("empty substr.", !LLStringUtil::endsWith(empty, value));
+ ensure("empty everything.", !LLStringUtil::endsWith(empty, empty));
+ }
+}
diff --git a/indra/llcommon/tests/lltreeiterators_test.cpp b/indra/llcommon/tests/lltreeiterators_test.cpp
new file mode 100644
index 0000000000..1d619867d4
--- /dev/null
+++ b/indra/llcommon/tests/lltreeiterators_test.cpp
@@ -0,0 +1,1213 @@
+/**
+ * @file lltreeiterators.cpp
+ * @author Nat Goodspeed
+ * @date 2008-08-20
+ * @brief Test of lltreeiterators.h
+ *
+ * $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$
+ */
+
+// Precompiled header
+#include "linden_common.h"
+
+
+// STL headers
+// std headers
+#include <iostream>
+#include <sstream>
+#include <string>
+// external library headers
+#include <boost/bind.hpp>
+#include <boost/range/iterator_range.hpp>
+#include <boost/foreach.hpp>
+
+// associated header
+#include "../lltreeiterators.h"
+#include "../llpointer.h"
+
+#include "../test/lltut.h"
+
+/*****************************************************************************
+* tut test group
+*****************************************************************************/
+namespace tut
+{
+ struct iter_data
+ {
+ };
+ typedef test_group<iter_data> iter_group;
+ typedef iter_group::object iter_object;
+ tut::iter_group ig("LLTreeIterators");
+} // namespace tut
+
+/*****************************************************************************
+* boost::get_pointer() specialization for LLPointer<>
+*****************************************************************************/
+// This specialization of boost::get_pointer() undoubtedly belongs in
+// llmemory.h. It's used by boost::bind() so that you can pass an
+// LLPointer<Foo> as well as a Foo* to a functor such as
+// boost::bind(&Foo::method, _1).
+//namespace boost
+//{
+ template <class NODE>
+ NODE* get_pointer(const LLPointer<NODE>& ptr) { return ptr.get(); }
+//};
+
+/*****************************************************************************
+* ScopeLabel
+*****************************************************************************/
+class ScopeLabel
+{
+public:
+ ScopeLabel(const std::string& label): mLabel(label)
+ {
+ std::cout << "Entering " << mLabel << '\n';
+ }
+ ~ScopeLabel()
+ {
+ std::cout << "Leaving " << mLabel << '\n';
+ }
+private:
+ std::string mLabel;
+};
+
+/*****************************************************************************
+* Cleanup
+*****************************************************************************/
+// Yes, we realize this is redundant with auto_ptr and LLPointer and all
+// kinds of better mechanisms. But in this particular source file, we need to
+// test nodes managed with plain old dumb pointers as well as nodes managed
+// with LLPointer, so we introduce this mechanism.
+//
+// In the general case, when we declare a Cleanup for some pointer, delete the
+// pointer when the Cleanup goes out of scope.
+template <typename PTRTYPE>
+struct Cleanup
+{
+ Cleanup(const PTRTYPE& ptr): mPtr(ptr) {}
+ ~Cleanup()
+ {
+ delete mPtr;
+ }
+ PTRTYPE mPtr;
+};
+
+// But when the pointer is an LLPointer<something>, Cleanup is a no-op:
+// LLPointer will handle the cleanup automagically.
+template <typename NODE>
+struct Cleanup< LLPointer<NODE> >
+{
+ Cleanup(const LLPointer<NODE>& ptr) {}
+ ~Cleanup() {}
+};
+
+/*****************************************************************************
+* Expected
+*****************************************************************************/
+// Expected is a base class used to capture the expected results -- a sequence
+// of string node names -- from one of our traversals of this example data.
+// Its subclasses initialize it with a pair of string iterators. It's not
+// strictly necessary to customize Expected to model Boost.Range, it's just
+// convenient.
+struct Expected
+{
+ template <typename ITER>
+ Expected(ITER begin, ITER end):
+ strings(begin, end)
+ {}
+ /*------ The following are to make Expected work with Boost.Range ------*/
+ typedef std::vector<std::string> container_type;
+ typedef container_type::iterator iterator;
+ typedef container_type::const_iterator const_iterator;
+ typedef container_type::size_type size_type;
+ container_type strings;
+ iterator begin() { return strings.begin(); }
+ iterator end() { return strings.end(); }
+ size_type size() { return strings.size(); }
+ const_iterator begin() const { return strings.begin(); }
+ const_iterator end() const { return strings.end(); }
+};
+
+// We have a couple of generic Expected template subclasses. This list of
+// strings is used for the "else" case when all specializations fail.
+const char* bad_strings[] = { "FAIL" };
+
+/*****************************************************************************
+* verify()
+*****************************************************************************/
+// test function: given (an object modeling) a Boost.Range of tree nodes,
+// compare the sequence of visited node names with a range of expected name
+// strings. Report success both with std::cout output and a bool return. The
+// string desc parameter is to identify the different tests.
+template <typename NODERANGE, typename STRINGRANGE>
+bool verify(const std::string& desc, NODERANGE noderange, STRINGRANGE expected)
+{
+ typename boost::range_iterator<NODERANGE>::type
+ nri = boost::begin(noderange),
+ nrend = boost::end(noderange);
+ typename boost::range_iterator<STRINGRANGE>::type
+ sri = boost::begin(expected),
+ srend = boost::end(expected);
+ // We choose to loop over both sequences explicitly rather than using
+ // std::equal() or std::lexicographical_compare(). The latter tells you
+ // whether one sequence is *less* than the other -- it doesn't tell you
+ // equality. std::equal() needs you to verify the sequence lengths ahead
+ // of time. Anyway, comparing explicitly allows us to report much more
+ // information about any sequence mismatch.
+ for ( ; nri != nrend && sri != srend; ++nri, ++sri)
+ {
+ if ((*nri)->name() != *sri)
+ {
+ std::cout << desc << " mismatch: "
+ << "expected " << *sri << ", got " << (*nri)->name() << "\n";
+ return false;
+ }
+ }
+ if (nri != nrend)
+ {
+ std::cout << desc << " produced too many items:\n";
+ for ( ; nri != nrend; ++nri)
+ {
+ std::cout << " " << (*nri)->name() << '\n';
+ }
+ return false;
+ }
+ if (sri != srend)
+ {
+ std::cout << desc << " produced too few items, omitting:\n";
+ for ( ; sri != srend; ++sri)
+ {
+ std::cout << " " << *sri << '\n';
+ }
+ return false;
+ }
+// std::cout << desc << " test passed\n";
+ return true;
+}
+
+/*****************************************************************************
+* PlainNode: LLLinkIter, non-refcounted
+*****************************************************************************/
+class PlainNode
+{
+public:
+ PlainNode(const std::string& name, PlainNode* next=NULL):
+ mName(name),
+ mNext(next)
+ {}
+ ~PlainNode()
+ {
+ delete mNext;
+ }
+ std::string name() const { return mName; }
+ PlainNode* next() const { return mNext; }
+public: // if this were 'private', couldn't bind mNext
+ PlainNode* mNext;
+private:
+ std::string mName;
+};
+
+namespace tut
+{
+ template<> template<>
+ void iter_object::test<1>()
+ {
+// set_test_name("LLLinkedIter -- non-refcounted class");
+ PlainNode* last(new PlainNode("c"));
+ PlainNode* second(new PlainNode("b", last));
+ PlainNode* first(new PlainNode("a", second));
+ Cleanup<PlainNode*> cleanup(first);
+ static const char* cseq[] = { "a", "b", "c" };
+ Expected seq(boost::begin(cseq), boost::end(cseq));
+ std::string desc1("Iterate by public link member");
+// std::cout << desc1 << ":\n";
+ // Try instantiating an iterator with NULL. This test is less about
+ // "did we iterate once?" than "did we avoid blowing up?"
+ for (LLLinkedIter<PlainNode> pni(NULL, boost::bind(&PlainNode::mNext, _1)), end;
+ pni != end; ++pni)
+ {
+// std::cout << (*pni)->name() << '\n';
+ ensure("LLLinkedIter<PlainNode>(NULL)", false);
+ }
+ ensure(desc1,
+ verify(desc1,
+ boost::make_iterator_range(LLLinkedIter<PlainNode>(first,
+ boost::bind(&PlainNode::mNext, _1)),
+ LLLinkedIter<PlainNode>()),
+ seq));
+ std::string desc2("Iterate by next() method");
+// std::cout << desc2 << ":\n";
+// for (LLLinkedIter<PlainNode> pni(first, boost::bind(&PlainNode::next, _1)); ! (pni == end); ++pni)
+// std::cout << (**pni).name() << '\n';
+ ensure(desc2,
+ verify(desc2,
+ boost::make_iterator_range(LLLinkedIter<PlainNode>(first,
+ boost::bind(&PlainNode::next, _1)),
+ LLLinkedIter<PlainNode>()),
+ seq));
+ {
+// LLLinkedIter<PlainNode> pni(first, boost::bind(&PlainNode::next, _1));
+// std::cout << "First is " << (*pni++)->name() << '\n';
+// std::cout << "Second is " << (*pni )->name() << '\n';
+ }
+ {
+ LLLinkedIter<PlainNode> pni(first, boost::bind(&PlainNode::next, _1));
+ ensure_equals("first", (*pni++)->name(), "a");
+ ensure_equals("second", (*pni )->name(), "b");
+ }
+ }
+} // tut
+
+/*****************************************************************************
+* RCNode: LLLinkIter, refcounted
+*****************************************************************************/
+class RCNode;
+typedef LLPointer<RCNode> RCNodePtr;
+
+class RCNode: public LLRefCount
+{
+public:
+ RCNode(const std::string& name, const RCNodePtr& next=RCNodePtr()):
+ mName(name),
+ mNext(next)
+ {
+// std::cout << "New RCNode(" << mName << ")\n";
+ }
+ RCNode(const RCNode& that):
+ mName(that.mName),
+ mNext(that.mNext)
+ {
+// std::cout << "Copy RCNode(" << mName << ")\n";
+ }
+ virtual ~RCNode();
+ std::string name() const { return mName; }
+ RCNodePtr next() const { return mNext; }
+public: // if this were 'private', couldn't bind mNext
+ RCNodePtr mNext;
+private:
+ std::string mName;
+};
+
+std::ostream& operator<<(std::ostream& out, const RCNode& node)
+{
+ out << "RCNode(" << node.name() << ')';
+ return out;
+}
+
+// This string contains the node name of the last RCNode destroyed. We use it
+// to validate that LLLinkedIter<RCNode> in fact contains LLPointer<RCNode>,
+// and that therefore an outstanding LLLinkedIter to an instance of a
+// refcounted class suffices to keep that instance alive.
+std::string last_RCNode_destroyed;
+
+RCNode::~RCNode()
+{
+// std::cout << "Kill " << *this << "\n";
+ last_RCNode_destroyed = mName;
+}
+
+namespace tut
+{
+ template<> template<>
+ void iter_object::test<2>()
+ {
+// set_test_name("LLLinkedIter -- refcounted class");
+ LLLinkedIter<RCNode> rcni, end2;
+ {
+// ScopeLabel label("inner scope");
+ RCNodePtr head(new RCNode("x", new RCNode("y", new RCNode("z"))));
+// for (rcni = LLLinkedIter<RCNode>(head, boost::bind(&RCNode::mNext, _1)); rcni != end2; ++rcni)
+// std::cout << **rcni << '\n';
+ rcni = LLLinkedIter<RCNode>(head, boost::bind(&RCNode::next, _1));
+ }
+// std::cout << "Now the LLLinkedIter<RCNode> is the only remaining reference to RCNode chain\n";
+ ensure_equals(last_RCNode_destroyed, "");
+ ensure(rcni != end2);
+ ensure_equals((*rcni)->name(), "x");
+ ++rcni;
+ ensure_equals(last_RCNode_destroyed, "x");
+ ensure(rcni != end2);
+ ensure_equals((*rcni)->name(), "y");
+ ++rcni;
+ ensure_equals(last_RCNode_destroyed, "y");
+ ensure(rcni != end2);
+ ensure_equals((*rcni)->name(), "z");
+ ++rcni;
+ ensure_equals(last_RCNode_destroyed, "z");
+ ensure(rcni == end2);
+ }
+}
+
+/*****************************************************************************
+* TreeNode
+*****************************************************************************/
+class TreeNode;
+typedef LLPointer<TreeNode> TreeNodePtr;
+
+/**
+ * TreeNode represents a refcounted tree-node class that hasn't (yet) been
+ * modified to incorporate LLTreeIter methods. This illustrates how you can
+ * use tree iterators either standalone, or with free functions.
+ */
+class TreeNode: public LLRefCount
+{
+public:
+ typedef std::vector<TreeNodePtr> list_type;
+ typedef list_type::const_iterator child_iterator;
+
+ // To avoid cycles, use a "weak" raw pointer for the parent link
+ TreeNode(const std::string& name, TreeNode* parent=0):
+ mParent(parent),
+ mName(name)
+ {}
+ TreeNodePtr newChild(const std::string& name)
+ {
+ TreeNodePtr child(new TreeNode(name, this));
+ mChildren.push_back(child);
+ return child;
+ }
+ std::string name() const { return mName; }
+ TreeNodePtr getParent() const { return mParent; }
+ child_iterator child_begin() const { return mChildren.begin(); }
+ child_iterator child_end() const { return mChildren.end(); }
+private:
+ std::string mName;
+ // To avoid cycles, use a "weak" raw pointer for the parent link
+ TreeNode* mParent;
+ list_type mChildren;
+};
+
+/**
+ * This is an example of a helper function to facilitate iterating from a
+ * TreeNode up to the root or down from the root (see LLTreeIter::RootIter).
+ *
+ * Example:
+ * @code
+ * BOOST_FOREACH(TreeNodePtr node, getRootRange<LLTreeIter::UP>(somenode))
+ * {
+ * std::cout << node->name() << '\n';
+ * }
+ * @endcode
+ */
+template <LLTreeIter::RootIter DISCRIM>
+boost::iterator_range< LLTreeRootIter<DISCRIM, TreeNode> >
+getRootRange(const TreeNodePtr& node)
+{
+ typedef LLTreeRootIter<DISCRIM, TreeNode> iter_type;
+ typedef boost::iterator_range<iter_type> range_type;
+ return range_type(iter_type(node, boost::bind(&TreeNode::getParent, _1)),
+ iter_type());
+}
+
+/**
+ * This is an example of a helper function to facilitate walking a given
+ * TreeNode's subtree in any supported order (see LLTreeIter::WalkIter).
+ *
+ * Example:
+ * @code
+ * BOOST_FOREACH(TreeNodePtr node, getWalkRange<LLTreeIter::DFS_PRE>(root))
+ * {
+ * std::cout << node->name() << '\n';
+ * }
+ * @endcode
+ */
+template <LLTreeIter::WalkIter DISCRIM>
+boost::iterator_range< LLTreeWalkIter<DISCRIM, TreeNode, TreeNode::child_iterator> >
+getWalkRange(const TreeNodePtr& node)
+{
+ typedef LLTreeWalkIter<DISCRIM, TreeNode, TreeNode::child_iterator> iter_type;
+ typedef boost::iterator_range<iter_type> range_type;
+ return range_type(iter_type(node,
+ boost::bind(&TreeNode::child_begin, _1),
+ boost::bind(&TreeNode::child_end, _1)),
+ iter_type());
+}
+
+/*****************************************************************************
+* EnhancedTreeNode
+*****************************************************************************/
+class EnhancedTreeNode;
+typedef LLPointer<EnhancedTreeNode> EnhancedTreeNodePtr;
+
+/**
+ * More typically, you enhance the tree-node class itself with template
+ * methods like the above. This EnhancedTreeNode class illustrates the
+ * technique. Normally, of course, you'd simply add these methods to TreeNode;
+ * we put them in a separate class to preserve the undecorated TreeNode class
+ * to illustrate (and test) the use of plain tree iterators and standalone
+ * helper functions.
+ *
+ * We originally implemented EnhancedTreeNode as a subclass of TreeNode -- but
+ * because TreeNode stores and manipulates TreeNodePtrs and TreeNode*s,
+ * reusing its methods required so much ugly downcast logic that we gave up
+ * and restated the whole class. Bear in mind that logically these aren't two
+ * separate classes; logically they're two snapshots of the @em same class at
+ * different moments in time.
+ */
+class EnhancedTreeNode: public LLRefCount
+{
+public:
+ /*-------------- The following is restated from TreeNode ---------------*/
+ typedef std::vector<EnhancedTreeNodePtr> list_type;
+ typedef list_type::const_iterator child_iterator;
+
+ // To avoid cycles, use a "weak" raw pointer for the parent link
+ EnhancedTreeNode(const std::string& name, EnhancedTreeNode* parent=0):
+ mParent(parent),
+ mName(name)
+ {}
+ EnhancedTreeNodePtr newChild(const std::string& name)
+ {
+ EnhancedTreeNodePtr child(new EnhancedTreeNode(name, this));
+ mChildren.push_back(child);
+ return child;
+ }
+ std::string name() const { return mName; }
+ EnhancedTreeNodePtr getParent() const { return mParent; }
+ child_iterator child_begin() const { return mChildren.begin(); }
+ child_iterator child_end() const { return mChildren.end(); }
+
+private:
+ std::string mName;
+ // To avoid cycles, use a "weak" raw pointer for the parent link
+ EnhancedTreeNode* mParent;
+ list_type mChildren;
+public:
+ /*----- End of TreeNode; what follows is new with EnhancedTreeNode -----*/
+
+ /**
+ * Because the type of the iterator range returned by getRootRange()
+ * depends on the discriminator enum value, instead of a simple typedef we
+ * use a templated struct. Example usage:
+ *
+ * @code
+ * for (EnhancedTreeNode::root_range<LLTreeIter::UP>::type range =
+ * somenode->getRootRange<LLTreeIter::UP>();
+ * range.first != range.second; ++range.first)
+ * {
+ * std::cout << (*range.first)->name() << '\n';
+ * }
+ * @endcode
+ */
+ template <LLTreeIter::RootIter DISCRIM>
+ struct root_range
+ {
+ typedef boost::iterator_range< LLTreeRootIter<DISCRIM, EnhancedTreeNode> > type;
+ };
+
+ /**
+ * Helper method for walking up to (or down from) the tree root. See
+ * LLTreeIter::RootIter.
+ *
+ * Example usage:
+ * @code
+ * BOOST_FOREACH(EnhancedTreeNodePtr node, somenode->getRootRange<LLTreeIter::UP>())
+ * {
+ * std::cout << node->name() << '\n';
+ * }
+ * @endcode
+ */
+ template <LLTreeIter::RootIter DISCRIM>
+ typename root_range<DISCRIM>::type getRootRange() const
+ {
+ typedef typename root_range<DISCRIM>::type range_type;
+ typedef typename range_type::iterator iter_type;
+ return range_type(iter_type(const_cast<EnhancedTreeNode*>(this),
+ boost::bind(&EnhancedTreeNode::getParent, _1)),
+ iter_type());
+ }
+
+ /**
+ * Because the type of the iterator range returned by getWalkRange()
+ * depends on the discriminator enum value, instead of a simple typedef we
+ * use a templated stuct. Example usage:
+ *
+ * @code
+ * for (EnhancedTreeNode::walk_range<LLTreeIter::DFS_PRE>::type range =
+ * somenode->getWalkRange<LLTreeIter::DFS_PRE>();
+ * range.first != range.second; ++range.first)
+ * {
+ * std::cout << (*range.first)->name() << '\n';
+ * }
+ * @endcode
+ */
+ template <LLTreeIter::WalkIter DISCRIM>
+ struct walk_range
+ {
+ typedef boost::iterator_range< LLTreeWalkIter<DISCRIM,
+ EnhancedTreeNode,
+ EnhancedTreeNode::child_iterator> > type;
+ };
+
+ /**
+ * Helper method for walking a given node's subtree in any supported
+ * order (see LLTreeIter::WalkIter).
+ *
+ * Example usage:
+ * @code
+ * BOOST_FOREACH(EnhancedTreeNodePtr node, somenode->getWalkRange<LLTreeIter::DFS_PRE>())
+ * {
+ * std::cout << node->name() << '\n';
+ * }
+ * @endcode
+ */
+ template <LLTreeIter::WalkIter DISCRIM>
+ typename walk_range<DISCRIM>::type getWalkRange() const
+ {
+ typedef typename walk_range<DISCRIM>::type range_type;
+ typedef typename range_type::iterator iter_type;
+ return range_type(iter_type(const_cast<EnhancedTreeNode*>(this),
+ boost::bind(&EnhancedTreeNode::child_begin, _1),
+ boost::bind(&EnhancedTreeNode::child_end, _1)),
+ iter_type());
+ }
+};
+
+/*****************************************************************************
+* PlainTree
+*****************************************************************************/
+struct PlainTree
+{
+ PlainTree(const std::string& name, PlainTree* parent=0):
+ mName(name),
+ mParent(parent),
+ mNextSibling(0),
+ mFirstChild(0)
+ {
+ mLastChildLink = &mFirstChild;
+ }
+ ~PlainTree()
+ {
+ delete mNextSibling;
+ delete mFirstChild;
+ }
+ PlainTree* newChild(const std::string& name)
+ {
+ PlainTree* child(new PlainTree(name, this));
+ *mLastChildLink = child;
+ mLastChildLink = &child->mNextSibling;
+ return child;
+ }
+ std::string name() const { return mName; }
+
+ std::string mName;
+ PlainTree* mParent;
+ PlainTree* mNextSibling;
+ PlainTree* mFirstChild;
+ PlainTree** mLastChildLink;
+};
+
+// This "classic" tree tracks each node's children with a linked list anchored
+// at the parent's mFirstChild and linked through each child's mNextSibling.
+// LLTreeDFSIter<> and LLTreeBFSIter<> need functors to return begin()/end()
+// iterators over a given node's children. But because this tree's children
+// aren't stored in an STL container, we can't just export that container's
+// begin()/end(). Instead we'll use LLLinkedIter<> to view the hand-maintained
+// linked list as an iterator range. The straightforward way to do that would
+// be to add child_begin() and child_end() methods. But let's say (for the
+// sake of argument) that this struct is so venerable we don't dare modify it
+// even to add new methods. Well, we can use free functions (or functors) too.
+LLLinkedIter<PlainTree> PlainTree_child_begin(PlainTree* node)
+{
+ return LLLinkedIter<PlainTree>(node->mFirstChild, boost::bind(&PlainTree::mNextSibling, _1));
+}
+
+LLLinkedIter<PlainTree> PlainTree_child_end(PlainTree* node)
+{
+ return LLLinkedIter<PlainTree>();
+}
+
+/**
+ * This is an example of a helper function to facilitate iterating from a
+ * PlainTree up to the root or down from the root (see LLTreeIter::RootIter).
+ * Note that we're simply overloading the same getRootRange() helper function
+ * name we used for TreeNode.
+ *
+ * Example:
+ * @code
+ * BOOST_FOREACH(PlainTree* node, getRootRange<LLTreeIter::UP>(somenode))
+ * {
+ * std::cout << node->name() << '\n';
+ * }
+ * @endcode
+ */
+template <LLTreeIter::RootIter DISCRIM>
+boost::iterator_range< LLTreeRootIter<DISCRIM, PlainTree> >
+getRootRange(PlainTree* node)
+{
+ typedef LLTreeRootIter<DISCRIM, PlainTree> iter_type;
+ typedef boost::iterator_range<iter_type> range_type;
+ return range_type(iter_type(node, boost::bind(&PlainTree::mParent, _1)),
+ iter_type());
+}
+
+/**
+ * This is an example of a helper function to facilitate walking a given
+ * PlainTree's subtree in any supported order (see LLTreeIter::WalkIter). Note
+ * that we're simply overloading the same getWalkRange() helper function name
+ * we used for TreeNode.
+ *
+ * Example:
+ * @code
+ * BOOST_FOREACH(PlainTree* node, getWalkRange<LLTreeIter::DFS_PRE>(root))
+ * {
+ * std::cout << node->name() << '\n';
+ * }
+ * @endcode
+ */
+template <LLTreeIter::WalkIter DISCRIM>
+boost::iterator_range< LLTreeWalkIter<DISCRIM, PlainTree, LLLinkedIter<PlainTree> > >
+getWalkRange(PlainTree* node)
+{
+ typedef LLTreeWalkIter<DISCRIM, PlainTree, LLLinkedIter<PlainTree> > iter_type;
+ typedef boost::iterator_range<iter_type> range_type;
+ return range_type(iter_type(node,
+ PlainTree_child_begin,
+ PlainTree_child_end),
+ iter_type());
+}
+
+// We could go through the exercise of writing EnhancedPlainTree containing
+// root_range, getRootRange(), walk_range and getWalkRange() members -- but we
+// won't. See EnhancedTreeNode for examples.
+
+/*****************************************************************************
+* Generic tree test data
+*****************************************************************************/
+template <class NODE>
+typename LLPtrTo<NODE>::type example_tree()
+{
+ typedef typename LLPtrTo<NODE>::type NodePtr;
+ NodePtr root(new NODE("root"));
+ NodePtr A(root->newChild("A"));
+ NodePtr A1(A->newChild("A1"));
+/* NodePtr A1a*/(A1->newChild("A1a"));
+/* NodePtr A1b*/(A1->newChild("A1b"));
+/* NodePtr A1c*/(A1->newChild("A1c"));
+ NodePtr A2(A->newChild("A2"));
+/* NodePtr A2a*/(A2->newChild("A2a"));
+/* NodePtr A2b*/(A2->newChild("A2b"));
+/* NodePtr A2c*/(A2->newChild("A2c"));
+ NodePtr A3(A->newChild("A3"));
+/* NodePtr A3a*/(A3->newChild("A3a"));
+/* NodePtr A3b*/(A3->newChild("A3b"));
+/* NodePtr A3c*/(A3->newChild("A3c"));
+ NodePtr B(root->newChild("B"));
+ NodePtr B1(B->newChild("B1"));
+/* NodePtr B1a*/(B1->newChild("B1a"));
+/* NodePtr B1b*/(B1->newChild("B1b"));
+/* NodePtr B1c*/(B1->newChild("B1c"));
+ NodePtr B2(B->newChild("B2"));
+/* NodePtr B2a*/(B2->newChild("B2a"));
+/* NodePtr B2b*/(B2->newChild("B2b"));
+/* NodePtr B2c*/(B2->newChild("B2c"));
+ NodePtr B3(B->newChild("B3"));
+/* NodePtr B3a*/(B3->newChild("B3a"));
+/* NodePtr B3b*/(B3->newChild("B3b"));
+/* NodePtr B3c*/(B3->newChild("B3c"));
+ NodePtr C(root->newChild("C"));
+ NodePtr C1(C->newChild("C1"));
+/* NodePtr C1a*/(C1->newChild("C1a"));
+/* NodePtr C1b*/(C1->newChild("C1b"));
+/* NodePtr C1c*/(C1->newChild("C1c"));
+ NodePtr C2(C->newChild("C2"));
+/* NodePtr C2a*/(C2->newChild("C2a"));
+/* NodePtr C2b*/(C2->newChild("C2b"));
+/* NodePtr C2c*/(C2->newChild("C2c"));
+ NodePtr C3(C->newChild("C3"));
+/* NodePtr C3a*/(C3->newChild("C3a"));
+/* NodePtr C3b*/(C3->newChild("C3b"));
+/* NodePtr C3c*/(C3->newChild("C3c"));
+ return root;
+}
+
+// WalkExpected<WalkIter> is the list of string node names we expect from a
+// WalkIter traversal of our example_tree() data.
+template <LLTreeIter::WalkIter DISCRIM>
+struct WalkExpected: public Expected
+{
+ // Initialize with bad_strings: we don't expect to use this generic case,
+ // only the specializations. Note that for a classic C-style array we must
+ // pass a pair of iterators rather than extracting boost::begin() and
+ // boost::end() within the target constructor: a template ctor accepts
+ // these classic C-style arrays as char** rather than char*[length]. Oh well.
+ WalkExpected(): Expected(boost::begin(bad_strings), boost::end(bad_strings)) {}
+};
+
+// list of string node names we expect from traversing example_tree() in
+// DFS_PRE order
+const char* dfs_pre_strings[] =
+{
+ "root",
+ "A",
+ "A1",
+ "A1a",
+ "A1b",
+ "A1c",
+ "A2",
+ "A2a",
+ "A2b",
+ "A2c",
+ "A3",
+ "A3a",
+ "A3b",
+ "A3c",
+ "B",
+ "B1",
+ "B1a",
+ "B1b",
+ "B1c",
+ "B2",
+ "B2a",
+ "B2b",
+ "B2c",
+ "B3",
+ "B3a",
+ "B3b",
+ "B3c",
+ "C",
+ "C1",
+ "C1a",
+ "C1b",
+ "C1c",
+ "C2",
+ "C2a",
+ "C2b",
+ "C2c",
+ "C3",
+ "C3a",
+ "C3b",
+ "C3c"
+};
+
+// specialize WalkExpected<DFS_PRE> with the expected strings
+template <>
+struct WalkExpected<LLTreeIter::DFS_PRE>: public Expected
+{
+ WalkExpected(): Expected(boost::begin(dfs_pre_strings), boost::end(dfs_pre_strings)) {}
+};
+
+// list of string node names we expect from traversing example_tree() in
+// DFS_POST order
+const char* dfs_post_strings[] =
+{
+ "A1a",
+ "A1b",
+ "A1c",
+ "A1",
+ "A2a",
+ "A2b",
+ "A2c",
+ "A2",
+ "A3a",
+ "A3b",
+ "A3c",
+ "A3",
+ "A",
+ "B1a",
+ "B1b",
+ "B1c",
+ "B1",
+ "B2a",
+ "B2b",
+ "B2c",
+ "B2",
+ "B3a",
+ "B3b",
+ "B3c",
+ "B3",
+ "B",
+ "C1a",
+ "C1b",
+ "C1c",
+ "C1",
+ "C2a",
+ "C2b",
+ "C2c",
+ "C2",
+ "C3a",
+ "C3b",
+ "C3c",
+ "C3",
+ "C",
+ "root"
+};
+
+// specialize WalkExpected<DFS_POST> with the expected strings
+template <>
+struct WalkExpected<LLTreeIter::DFS_POST>: public Expected
+{
+ WalkExpected(): Expected(boost::begin(dfs_post_strings), boost::end(dfs_post_strings)) {}
+};
+
+// list of string node names we expect from traversing example_tree() in BFS order
+const char* bfs_strings[] =
+{
+ "root",
+ "A",
+ "B",
+ "C",
+ "A1",
+ "A2",
+ "A3",
+ "B1",
+ "B2",
+ "B3",
+ "C1",
+ "C2",
+ "C3",
+ "A1a",
+ "A1b",
+ "A1c",
+ "A2a",
+ "A2b",
+ "A2c",
+ "A3a",
+ "A3b",
+ "A3c",
+ "B1a",
+ "B1b",
+ "B1c",
+ "B2a",
+ "B2b",
+ "B2c",
+ "B3a",
+ "B3b",
+ "B3c",
+ "C1a",
+ "C1b",
+ "C1c",
+ "C2a",
+ "C2b",
+ "C2c",
+ "C3a",
+ "C3b",
+ "C3c"
+};
+
+// specialize WalkExpected<BFS> with the expected strings
+template <>
+struct WalkExpected<LLTreeIter::BFS>: public Expected
+{
+ WalkExpected(): Expected(boost::begin(bfs_strings), boost::end(bfs_strings)) {}
+};
+
+// extract a particular "arbitrary" node from the example_tree() data: the
+// second (middle) node at each child level
+template <class NODE, typename CHILDITER>
+typename LLPtrTo<NODE>::type
+get_B2b(const typename LLPtrTo<NODE>::type& root,
+ const boost::function<CHILDITER(const typename LLPtrTo<NODE>::type&)>& child_begin)
+{
+ typedef typename LLPtrTo<NODE>::type NodePtr;
+ CHILDITER Bi(child_begin(root));
+ ++Bi;
+ NodePtr B(*Bi);
+ CHILDITER B2i(child_begin(B));
+ ++B2i;
+ NodePtr B2(*B2i);
+ CHILDITER B2bi(child_begin(B2));
+ ++B2bi;
+ NodePtr B2b(*B2bi);
+ return B2b;
+}
+
+// RootExpected<RootIter> is the list of string node names we expect from a
+// RootIter traversal of our example_tree() data.
+template <LLTreeIter::RootIter DISCRIM>
+struct RootExpected: public Expected
+{
+ // Initialize with bad_strings: we don't expect to use this generic case,
+ // only the specializations.
+ RootExpected(): Expected(boost::begin(bad_strings), boost::end(bad_strings)) {}
+};
+
+// list of string node names we expect from traversing UP from
+// example_tree()'s B2b node
+const char* up_from_B2b[] =
+{
+ "B2b",
+ "B2",
+ "B",
+ "root"
+};
+
+// specialize RootExpected<UP> with the expected strings
+template <>
+struct RootExpected<LLTreeIter::UP>: public Expected
+{
+ RootExpected(): Expected(boost::begin(up_from_B2b), boost::end(up_from_B2b)) {}
+};
+
+// list of string node names we expect from traversing DOWN to
+// example_tree()'s B2b node
+const char* down_to_B2b[] =
+{
+ "root",
+ "B",
+ "B2",
+ "B2b"
+};
+
+// specialize RootExpected<DOWN> with the expected strings
+template <>
+struct RootExpected<LLTreeIter::DOWN>: public Expected
+{
+ RootExpected(): Expected(boost::begin(down_to_B2b), boost::end(down_to_B2b)) {}
+};
+
+/*****************************************************************************
+* Generic tree test functions
+*****************************************************************************/
+template<LLTreeIter::RootIter DISCRIM, class NODE, typename PARENTFUNC>
+bool LLTreeRootIter_test(const std::string& itername, const std::string& nodename,
+ const typename LLPtrTo<NODE>::type& node,
+ PARENTFUNC parentfunc)
+{
+ std::ostringstream desc;
+ desc << itername << '<' << nodename << "> from " << node->name();
+ if (! verify(desc.str(),
+ boost::make_iterator_range(LLTreeRootIter<DISCRIM, NODE>(node, parentfunc),
+ LLTreeRootIter<DISCRIM, NODE>()),
+ RootExpected<DISCRIM>()))
+ return false;
+// std::cout << desc.str() << '\n';
+ // Try instantiating an iterator with NULL (that is, a default-constructed
+ // node pointer). This test is less about "did we iterate once?" than "did
+ // we avoid blowing up?"
+ for (LLTreeRootIter<DISCRIM, NODE> hri = LLTreeRootIter<DISCRIM, NODE>(typename LLPtrTo<NODE>::type(), parentfunc), hrend;
+ hri != hrend; /* ++hri */) // incrementing is moot, and MSVC complains
+ {
+// std::cout << nodename << '(' << (*hri)->name() << ")\n";
+ std::cout << itername << '<' << nodename << ">(NULL)\n";
+ return false;
+ }
+ return true;
+}
+
+template<class NODE, typename CHILDITER, typename PARENTFUNC, typename CHILDFUNC>
+bool LLTreeUpIter_test(const std::string& nodename, PARENTFUNC parentfunc, CHILDFUNC childfunc)
+{
+ bool success = true;
+ typedef typename LLPtrTo<NODE>::type ptr_type;
+ ptr_type root(example_tree<NODE>());
+ Cleanup<ptr_type> cleanup(root);
+ ptr_type B2b(get_B2b<NODE, CHILDITER>(root, childfunc));
+ if (! LLTreeRootIter_test<LLTreeIter::UP, NODE>("LLTreeUpIter", nodename, B2b, parentfunc))
+ success = false;
+ if (! LLTreeRootIter_test<LLTreeIter::DOWN, NODE>("LLTreeDownIter", nodename, B2b, parentfunc))
+ success = false;
+ return success;
+}
+
+template <LLTreeIter::WalkIter DISCRIM, class NODE, typename CHILDITER,
+ typename CHILDBEGINFUNC, typename CHILDENDFUNC>
+bool LLTreeWalkIter_test(const std::string& itername, const std::string& nodename,
+ CHILDBEGINFUNC childbegin, CHILDENDFUNC childend)
+{
+ typename LLPtrTo<NODE>::type root(example_tree<NODE>());
+ Cleanup<typename LLPtrTo<NODE>::type> cleanup(root);
+ std::ostringstream desc;
+ desc << itername << '<' << nodename << "> from " << root->name();
+ if (! verify(desc.str(),
+ boost::make_iterator_range(LLTreeWalkIter<DISCRIM, NODE, CHILDITER>(root,
+ childbegin,
+ childend),
+ LLTreeWalkIter<DISCRIM, NODE, CHILDITER>()),
+ WalkExpected<DISCRIM>()))
+ return false;
+ // Try instantiating an iterator with NULL (that is, a default-constructed
+ // node pointer). This test is less about "did we iterate once?" than "did
+ // we avoid blowing up?"
+ for (LLTreeWalkIter<DISCRIM, NODE, CHILDITER> twi = LLTreeWalkIter<DISCRIM, NODE, CHILDITER>(typename LLPtrTo<NODE>::type(),
+ childbegin,
+ childend),
+ twend;
+ twi != twend; /* ++twi */) // incrementing is moot, and MSVC complains
+ {
+ std::cout << itername << '<' << nodename << ">(NULL)\n";
+ return false;
+ }
+ return true;
+}
+
+template <class NODE, typename CHILDITER,
+ typename PARENTFUNC, typename CHILDBEGINFUNC, typename CHILDENDFUNC>
+bool LLTreeIter_tests(const std::string& nodename,
+ PARENTFUNC parentfunc, CHILDBEGINFUNC childbegin, CHILDENDFUNC childend)
+{
+ bool success = true;
+ if (! LLTreeUpIter_test<NODE, CHILDITER>(nodename, parentfunc, childbegin))
+ success = false;
+/*==========================================================================*|
+ LLTreeIter_test<NODE, LLTreeDFSIter<NODE, CHILDITER> >("LLTreeDFSIter", nodename,
+ childbegin, childend);
+ LLTreeIter_test<NODE, LLTreeDFSPostIter<NODE, CHILDITER> >("LLTreeDFSPostIter", nodename,
+ childbegin, childend);
+ LLTreeIter_test<NODE, LLTreeBFSIter<NODE, CHILDITER> >("LLTreeBFSIter", nodename,
+ childbegin, childend);
+|*==========================================================================*/
+ if (! LLTreeWalkIter_test<LLTreeIter::DFS_PRE, NODE, CHILDITER>("LLTreeDFSIter", nodename,
+ childbegin, childend))
+ success = false;
+ if (! LLTreeWalkIter_test<LLTreeIter::DFS_POST, NODE, CHILDITER>("LLTreeDFSPostIter", nodename,
+ childbegin, childend))
+ success = false;
+ if (! LLTreeWalkIter_test<LLTreeIter::BFS, NODE, CHILDITER>("LLTreeBFSIter", nodename,
+ childbegin, childend))
+ success = false;
+ return success;
+}
+
+namespace tut
+{
+ template<> template<>
+ void iter_object::test<3>()
+ {
+// set_test_name("LLTreeIter tests");
+ ensure(LLTreeIter_tests<TreeNode, TreeNode::child_iterator>
+ ("TreeNode",
+ boost::bind(&TreeNode::getParent, _1),
+ boost::bind(&TreeNode::child_begin, _1),
+ boost::bind(&TreeNode::child_end, _1)));
+ ensure(LLTreeIter_tests<PlainTree, LLLinkedIter<PlainTree> >
+ ("PlainTree",
+ boost::bind(&PlainTree::mParent, _1),
+ PlainTree_child_begin,
+ PlainTree_child_end));
+ }
+
+ template<> template<>
+ void iter_object::test<4>()
+ {
+// set_test_name("getRootRange() tests");
+ // This test function illustrates the looping techniques described in the
+ // comments for the getRootRange() free function, the
+ // EnhancedTreeNode::root_range template and the
+ // EnhancedTreeNode::getRootRange() method. Obviously the BOOST_FOREACH()
+ // forms are more succinct.
+ TreeNodePtr tnroot(example_tree<TreeNode>());
+ TreeNodePtr tnB2b(get_B2b<TreeNode, TreeNode::child_iterator>
+ (tnroot, boost::bind(&TreeNode::child_begin, _1)));
+
+ std::string desc1("BOOST_FOREACH(TreeNodePr, getRootRange<LLTreeIter::UP>(tnB2b))");
+// std::cout << desc1 << "\n";
+ // Although we've commented out the output statement, ensure that the
+ // loop construct is still valid, as promised by the getRootRange()
+ // documentation.
+ BOOST_FOREACH(TreeNodePtr node, getRootRange<LLTreeIter::UP>(tnB2b))
+ {
+// std::cout << node->name() << '\n';
+ }
+ ensure(desc1,
+ verify(desc1, getRootRange<LLTreeIter::UP>(tnB2b), RootExpected<LLTreeIter::UP>()));
+
+ EnhancedTreeNodePtr etnroot(example_tree<EnhancedTreeNode>());
+ EnhancedTreeNodePtr etnB2b(get_B2b<EnhancedTreeNode, EnhancedTreeNode::child_iterator>
+ (etnroot, boost::bind(&EnhancedTreeNode::child_begin, _1)));
+
+// std::cout << "EnhancedTreeNode::root_range<LLTreeIter::DOWN>::type range =\n"
+// << " etnB2b->getRootRange<LLTreeIter::DOWN>();\n"
+// << "for (EnhancedTreeNode::root_range<LLTreeIter::DOWN>::type::iterator ri = range.begin();\n"
+// << " ri != range.end(); ++ri)\n";
+ EnhancedTreeNode::root_range<LLTreeIter::DOWN>::type range =
+ etnB2b->getRootRange<LLTreeIter::DOWN>();
+ for (EnhancedTreeNode::root_range<LLTreeIter::DOWN>::type::iterator ri = range.begin();
+ ri != range.end(); ++ri)
+ {
+// std::cout << (*ri)->name() << '\n';
+ }
+
+ std::string desc2("BOOST_FOREACH(EnhancedTreeNodePtr node, etnB2b->getRootRange<LLTreeIter::UP>())");
+// std::cout << desc2 << '\n';
+ BOOST_FOREACH(EnhancedTreeNodePtr node, etnB2b->getRootRange<LLTreeIter::UP>())
+ {
+// std::cout << node->name() << '\n';
+ }
+ ensure(desc2,
+ verify(desc2, etnB2b->getRootRange<LLTreeIter::UP>(), RootExpected<LLTreeIter::UP>()));
+ }
+
+ template<> template<>
+ void iter_object::test<5>()
+ {
+// set_test_name("getWalkRange() tests");
+ // This test function doesn't illustrate the looping permutations for
+ // getWalkRange(); see getRootRange_tests() for such examples. This
+ // function simply verifies that they all work.
+
+ // TreeNode, using helper function
+ TreeNodePtr tnroot(example_tree<TreeNode>());
+ std::string desc_tnpre("getWalkRange<LLTreeIter::DFS_PRE>(tnroot)");
+ ensure(desc_tnpre,
+ verify(desc_tnpre,
+ getWalkRange<LLTreeIter::DFS_PRE>(tnroot),
+ WalkExpected<LLTreeIter::DFS_PRE>()));
+ std::string desc_tnpost("getWalkRange<LLTreeIter::DFS_POST>(tnroot)");
+ ensure(desc_tnpost,
+ verify(desc_tnpost,
+ getWalkRange<LLTreeIter::DFS_POST>(tnroot),
+ WalkExpected<LLTreeIter::DFS_POST>()));
+ std::string desc_tnb("getWalkRange<LLTreeIter::BFS>(tnroot)");
+ ensure(desc_tnb,
+ verify(desc_tnb,
+ getWalkRange<LLTreeIter::BFS>(tnroot),
+ WalkExpected<LLTreeIter::BFS>()));
+
+ // EnhancedTreeNode, using method
+ EnhancedTreeNodePtr etnroot(example_tree<EnhancedTreeNode>());
+ std::string desc_etnpre("etnroot->getWalkRange<LLTreeIter::DFS_PRE>()");
+ ensure(desc_etnpre,
+ verify(desc_etnpre,
+ etnroot->getWalkRange<LLTreeIter::DFS_PRE>(),
+ WalkExpected<LLTreeIter::DFS_PRE>()));
+ std::string desc_etnpost("etnroot->getWalkRange<LLTreeIter::DFS_POST>()");
+ ensure(desc_etnpost,
+ verify(desc_etnpost,
+ etnroot->getWalkRange<LLTreeIter::DFS_POST>(),
+ WalkExpected<LLTreeIter::DFS_POST>()));
+ std::string desc_etnb("etnroot->getWalkRange<LLTreeIter::BFS>()");
+ ensure(desc_etnb,
+ verify(desc_etnb,
+ etnroot->getWalkRange<LLTreeIter::BFS>(),
+ WalkExpected<LLTreeIter::BFS>()));
+
+ // PlainTree, using helper function
+ PlainTree* ptroot(example_tree<PlainTree>());
+ Cleanup<PlainTree*> cleanup(ptroot);
+ std::string desc_ptpre("getWalkRange<LLTreeIter::DFS_PRE>(ptroot)");
+ ensure(desc_ptpre,
+ verify(desc_ptpre,
+ getWalkRange<LLTreeIter::DFS_PRE>(ptroot),
+ WalkExpected<LLTreeIter::DFS_PRE>()));
+ std::string desc_ptpost("getWalkRange<LLTreeIter::DFS_POST>(ptroot)");
+ ensure(desc_ptpost,
+ verify(desc_ptpost,
+ getWalkRange<LLTreeIter::DFS_POST>(ptroot),
+ WalkExpected<LLTreeIter::DFS_POST>()));
+ std::string desc_ptb("getWalkRange<LLTreeIter::BFS>(ptroot)");
+ ensure(desc_ptb,
+ verify(desc_ptb,
+ getWalkRange<LLTreeIter::BFS>(ptroot),
+ WalkExpected<LLTreeIter::BFS>()));
+ }
+} // tut
diff --git a/indra/llcommon/tests/lluri_test.cpp b/indra/llcommon/tests/lluri_test.cpp
new file mode 100644
index 0000000000..f6d4221256
--- /dev/null
+++ b/indra/llcommon/tests/lluri_test.cpp
@@ -0,0 +1,364 @@
+/**
+ * @file lluri_test.cpp
+ * @brief LLURI unit tests
+ * @date September 2006
+ *
+ * $LicenseInfo:firstyear=2006&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$
+ */
+
+#include "linden_common.h"
+
+#include "../llsd.h"
+#include "../lluri.h"
+
+#include "../test/lltut.h"
+
+namespace tut
+{
+ struct URITestData {
+ void checkParts(const LLURI& u,
+ const char* expectedScheme,
+ const char* expectedOpaque,
+ const char* expectedAuthority,
+ const char* expectedPath,
+ const char* expectedQuery = "")
+ {
+ ensure_equals("scheme", u.scheme(), expectedScheme);
+ ensure_equals("opaque", u.opaque(), expectedOpaque);
+ ensure_equals("authority", u.authority(), expectedAuthority);
+ ensure_equals("path", u.path(), expectedPath);
+ ensure_equals("query", u.query(), expectedQuery);
+ }
+
+ void escapeRoundTrip(const std::string& uri_raw_1)
+ {
+ std::string uri_esc_1(LLURI::escape(uri_raw_1));
+ std::string uri_raw_2(LLURI::unescape(uri_esc_1));
+ ensure_equals("escape/unescape raw", uri_raw_2, uri_raw_1);
+ std::string uri_esc_2(LLURI::escape(uri_raw_2));
+ ensure_equals("escape/unescape escaped", uri_esc_2, uri_esc_1);
+ }
+ };
+
+ typedef test_group<URITestData> URITestGroup;
+ typedef URITestGroup::object URITestObject;
+
+ URITestGroup uriTestGroup("LLURI");
+
+ template<> template<>
+ void URITestObject::test<1>()
+ {
+ LLURI u("http://abc.com/def/ghi?x=37&y=hello");
+
+ ensure_equals("scheme", u.scheme(), "http");
+ ensure_equals("authority", u.authority(), "abc.com");
+ ensure_equals("path", u.path(), "/def/ghi");
+ ensure_equals("query", u.query(), "x=37&y=hello");
+
+ ensure_equals("host name", u.hostName(), "abc.com");
+ ensure_equals("host port", u.hostPort(), 80);
+
+ LLSD query = u.queryMap();
+ ensure_equals("query x", query["x"].asInteger(), 37);
+ ensure_equals("query y", query["y"].asString(), "hello");
+
+ query = LLURI::queryMap("x=22.23&y=https://lindenlab.com/");
+ ensure_equals("query x", query["x"].asReal(), 22.23);
+ ensure_equals("query y", query["y"].asURI().asString(), "https://lindenlab.com/");
+ }
+
+ template<> template<>
+ void URITestObject::test<2>()
+ {
+ // empty string
+ checkParts(LLURI(""), "", "", "", "");
+ }
+
+ template<> template<>
+ void URITestObject::test<3>()
+ {
+ // no scheme
+ checkParts(LLURI("foo"), "", "foo", "", "");
+ checkParts(LLURI("foo%3A"), "", "foo:", "", "");
+ }
+
+ template<> template<>
+ void URITestObject::test<4>()
+ {
+ // scheme w/o paths
+ checkParts(LLURI("mailto:zero@ll.com"),
+ "mailto", "zero@ll.com", "", "");
+ checkParts(LLURI("silly://abc/def?foo"),
+ "silly", "//abc/def?foo", "", "");
+ }
+
+ template<> template<>
+ void URITestObject::test<5>()
+ {
+ // authority section
+ checkParts(LLURI("http:///"),
+ "http", "///", "", "/");
+
+ checkParts(LLURI("http://abc"),
+ "http", "//abc", "abc", "");
+
+ checkParts(LLURI("http://a%2Fb/cd"),
+ "http", "//a/b/cd", "a/b", "/cd");
+
+ checkParts(LLURI("http://host?"),
+ "http", "//host?", "host", "");
+ }
+
+ template<> template<>
+ void URITestObject::test<6>()
+ {
+ // path section
+ checkParts(LLURI("http://host/a/b/"),
+ "http", "//host/a/b/", "host", "/a/b/");
+
+ checkParts(LLURI("http://host/a%3Fb/"),
+ "http", "//host/a?b/", "host", "/a?b/");
+
+ checkParts(LLURI("http://host/a:b/"),
+ "http", "//host/a:b/", "host", "/a:b/");
+ }
+
+ template<> template<>
+ void URITestObject::test<7>()
+ {
+ // query string
+ checkParts(LLURI("http://host/?"),
+ "http", "//host/?", "host", "/", "");
+
+ checkParts(LLURI("http://host/?x"),
+ "http", "//host/?x", "host", "/", "x");
+
+ checkParts(LLURI("http://host/??"),
+ "http", "//host/??", "host", "/", "?");
+
+ checkParts(LLURI("http://host/?%3F"),
+ "http", "//host/??", "host", "/", "?");
+ }
+
+ template<> template<>
+ void URITestObject::test<8>()
+ {
+ LLSD path;
+ path.append("x");
+ path.append("123");
+ checkParts(LLURI::buildHTTP("host", path),
+ "http", "//host/x/123", "host", "/x/123");
+
+ LLSD query;
+ query["123"] = "12";
+ query["abcd"] = "abc";
+ checkParts(LLURI::buildHTTP("host", path, query),
+ "http", "//host/x/123?123=12&abcd=abc",
+ "host", "/x/123", "123=12&abcd=abc");
+ }
+
+ template<> template<>
+ void URITestObject::test<9>()
+ {
+ // test unescaped path components
+ LLSD path;
+ path.append("x@*//*$&^");
+ path.append("123");
+ checkParts(LLURI::buildHTTP("host", path),
+ "http", "//host/x@*//*$&^/123", "host", "/x@*//*$&^/123");
+ }
+
+ template<> template<>
+ void URITestObject::test<10>()
+ {
+ // test unescaped query components
+ LLSD path;
+ path.append("x");
+ path.append("123");
+ LLSD query;
+ query["123"] = "?&*#//";
+ query["**@&?//"] = "abc";
+ checkParts(LLURI::buildHTTP("host", path, query),
+ "http", "//host/x/123?**@&?//=abc&123=?&*#//",
+ "host", "/x/123", "**@&?//=abc&123=?&*#//");
+ }
+
+ template<> template<>
+ void URITestObject::test<11>()
+ {
+ // test unescaped host components
+ LLSD path;
+ path.append("x");
+ path.append("123");
+ LLSD query;
+ query["123"] = "12";
+ query["abcd"] = "abc";
+ checkParts(LLURI::buildHTTP("hi123*33--}{:portstuffs", path, query),
+ "http", "//hi123*33--}{:portstuffs/x/123?123=12&abcd=abc",
+ "hi123*33--}{:portstuffs", "/x/123", "123=12&abcd=abc");
+ }
+
+ template<> template<>
+ void URITestObject::test<12>()
+ {
+ // test funky host_port values that are actually prefixes
+
+ checkParts(LLURI::buildHTTP("http://example.com:8080", LLSD()),
+ "http", "//example.com:8080",
+ "example.com:8080", "");
+
+ checkParts(LLURI::buildHTTP("http://example.com:8080/", LLSD()),
+ "http", "//example.com:8080/",
+ "example.com:8080", "/");
+
+ checkParts(LLURI::buildHTTP("http://example.com:8080/a/b", LLSD()),
+ "http", "//example.com:8080/a/b",
+ "example.com:8080", "/a/b");
+ }
+
+ template<> template<>
+ void URITestObject::test<13>()
+ {
+ const std::string unreserved =
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
+ "0123456789"
+ "-._~";
+ // test escape
+ ensure_equals("escaping", LLURI::escape("abcdefg", "abcdef"), "abcdef%67");
+ ensure_equals("escaping", LLURI::escape("|/&\\+-_!@", ""), "%7C%2F%26%5C%2B%2D%5F%21%40");
+ ensure_equals("escaping as query variable",
+ LLURI::escape("http://10.0.1.4:12032/agent/god/agent-id/map/layer/?resume=http://station3.ll.com:12032/agent/203ad6df-b522-491d-ba48-4e24eb57aeff/send-postcard", unreserved + ":@!$'()*+,="),
+ "http:%2F%2F10.0.1.4:12032%2Fagent%2Fgod%2Fagent-id%2Fmap%2Flayer%2F%3Fresume=http:%2F%2Fstation3.ll.com:12032%2Fagent%2F203ad6df-b522-491d-ba48-4e24eb57aeff%2Fsend-postcard");
+ // French cedilla (C with squiggle, like in the word Francais) is UTF-8 C3 A7
+
+#if LL_WINDOWS
+#pragma warning(disable: 4309)
+#endif
+
+ std::string cedilla;
+ cedilla.push_back( (char)0xC3 );
+ cedilla.push_back( (char)0xA7 );
+ ensure_equals("escape UTF8", LLURI::escape( cedilla, unreserved), "%C3%A7");
+ }
+
+
+ template<> template<>
+ void URITestObject::test<14>()
+ {
+ // make sure escape and unescape of empty strings return empty
+ // strings.
+ std::string uri_esc(LLURI::escape(""));
+ ensure("escape string empty", uri_esc.empty());
+ std::string uri_raw(LLURI::unescape(""));
+ ensure("unescape string empty", uri_raw.empty());
+ }
+
+ template<> template<>
+ void URITestObject::test<15>()
+ {
+ // do some round-trip tests
+ escapeRoundTrip("http://secondlife.com");
+ escapeRoundTrip("http://secondlife.com/url with spaces");
+ escapeRoundTrip("http://bad[domain]name.com/");
+ escapeRoundTrip("ftp://bill.gates@ms/micro$oft.com/c:\\autoexec.bat");
+ escapeRoundTrip("");
+ }
+
+ template<> template<>
+ void URITestObject::test<16>()
+ {
+ // Test the default escaping
+ // yes -- this mangles the url. This is expected behavior
+ std::string simple("http://secondlife.com");
+ ensure_equals(
+ "simple http",
+ LLURI::escape(simple),
+ "http%3A%2F%2Fsecondlife.com");
+ ensure_equals(
+ "needs escape",
+ LLURI::escape("http://get.secondlife.com/windows viewer"),
+ "http%3A%2F%2Fget.secondlife.com%2Fwindows%20viewer");
+ }
+
+ template<> template<>
+ void URITestObject::test<17>()
+ {
+ // do some round-trip tests with very long strings.
+ escapeRoundTrip("Welcome to Second Life.We hope you'll have a richly rewarding experience, filled with creativity, self expression and fun.The goals of the Community Standards are simple: treat each other with respect and without harassment, adhere to local standards as indicated by simulator ratings, and refrain from any hate activity which slurs a real-world individual or real-world community. Behavioral Guidelines - The Big Six");
+ escapeRoundTrip(
+ "'asset_data':b(12100){'task_id':ucc706f2d-0b68-68f8-11a4-f1043ff35ca0}\n{\n\tname\tObject|\n\tpermissions 0\n\t{\n\t\tbase_mask\t7fffffff\n\t\towner_mask\t7fffffff\n\t\tgroup_mask\t00000000\n\t\teveryone_mask\t00000000\n\t\tnext_owner_mask\t7fffffff\n\t\tcreator_id\t13fd9595-a47b-4d64-a5fb-6da645f038e0\n\t\towner_id\t3c115e51-04f4-523c-9fa6-98aff1034730\n\t\tlast_owner_id\t3c115e51-04f4-523c-9fa6-98aff1034730\n\t\tgroup_id\t00000000-0000-0000-0000-000000000000\n\t}\n\tlocal_id\t217444921\n\ttotal_crc\t323\n\ttype\t2\n\ttask_valid\t2\n\ttravel_access\t13\n\tdisplayopts\t2\n\tdisplaytype\tv\n\tpos\t-0.368634403\t0.00781063363\t-0.569040775\n\toldpos\t150.117996\t25.8658009\t8.19664001\n\trotation\t-0.06293071806430816650390625\t-0.6995697021484375\t-0.7002241611480712890625\t0.1277817934751510620117188\n\tchildpos\t-0.00499999989\t-0.0359999985\t0.307999998\n\tchildrot\t-0.515492737293243408203125\t-0.46601200103759765625\t0.529055416584014892578125\t0.4870323240756988525390625\n\tscale"
+ "\t0.074629\t0.289956\t0.01\n\tsit_offset\t0\t0\t0\n\tcamera_eye_offset\t0\t0\t0\n\tcamera_at_offset\t0\t0\t0\n\tsit_quat\t0\t0\t0\t1\n\tsit_hint\t0\n\tstate\t160\n\tmaterial\t3\n\tsoundid\t00000000-0000-0000-0000-000000000000\n\tsoundgain\t0\n\tsoundradius\t0\n\tsoundflags\t0\n\ttextcolor\t0 0 0 1\n\tselected\t0\n\tselector\t00000000-0000-0000-0000-000000000000\n\tusephysics\t0\n\trotate_x\t1\n\trotate_y\t1\n\trotate_z\t1\n\tphantom\t0\n\tremote_script_access_pin\t0\n\tvolume_detect\t0\n\tblock_grabs\t0\n\tdie_at_edge\t0\n\treturn_at_edge\t0\n\ttemporary\t0\n\tsandbox\t0\n\tsandboxhome\t0\t0\t0\n\tshape 0\n\t{\n\t\tpath 0\n\t\t{\n\t\t\tcurve\t16\n\t\t\tbegin\t0\n\t\t\tend\t1\n\t\t\tscale_x\t1\n\t\t\tscale_y\t1\n\t\t\tshear_x\t0\n\t\t\tshear_y\t0\n\t\t\ttwist\t0\n\t\t\ttwist_begin\t0\n\t\t\tradius_offset\t0\n\t\t\ttaper_x\t0\n\t\t\ttaper_y\t0\n\t\t\trevolutions\t1\n\t\t\tskew\t0\n\t\t}\n\t\tprofile 0\n\t\t{\n\t\t\tcurve\t1\n\t\t\tbegin\t0\n\t\t\tend\t1\n\t\t\thollow\t0\n\t\t}\n\t}\n\tf"
+ "aces\t6\n\t{\n\t\timageid\tddde1ffc-678b-3cda-1748-513086bdf01b\n\t\tcolors\t0.937255 0.796078 0.494118 1\n\t\tscales\t1\n\t\tscalet\t1\n\t\toffsets\t0\n\t\toffsett\t0\n\t\timagerot\t0\n\t\tbump\t0\n\t\tfullbright\t0\n\t\tmedia_flags\t0\n\t}\n\t{\n\t\timageid\tf54a0c32-3cd1-d49a-5b4f-7b792bebc204\n\t\tcolors\t0.937255 0.796078 0.494118 1\n\t\tscales\t1\n\t\tscalet\t1\n\t\toffsets\t0\n\t\toffsett\t0\n\t\timagerot\t0\n\t\tbump\t0\n\t\tfullbright\t0\n\t\tmedia_flags\t0\n\t}\n\t{\n\t\timageid\tf54a0c32-3cd1-d49a-5b4f-7b792bebc204\n\t\tcolors\t0.937255 0.796078 0.494118 1\n\t\tscales\t1\n\t\tscalet\t1\n\t\toffsets\t0\n\t\toffsett\t0\n\t\timagerot\t0\n\t\tbump\t0\n\t\tfullbright\t0\n\t\tmedia_flags\t0\n\t}\n\t{\n\t\timageid\tf54a0c32-3cd1-d49a-5b4f-7b792bebc204\n\t\tcolors\t0.937255 0.796078 0.494118 1\n\t\tscales\t1\n\t\tscalet\t1\n\t\toffsets\t0\n\t\toffsett\t0\n\t\timagerot\t0\n\t\tbump\t0\n\t\tfullbright\t0\n\t\tmedia_flags\t0\n\t}\n\t{\n\t\timageid\tf54a0c32-3cd1-d49a-5b4f-7b792bebc204"
+ "\n\t\tcolors\t0.937255 0.796078 0.494118 1\n\t\tscales\t1\n\t\tscalet\t1\n\t\toffsets\t0\n\t\toffsett\t0\n\t\timagerot\t0\n\t\tbump\t0\n\t\tfullbright\t0\n\t\tmedia_flags\t0\n\t}\n\t{\n\t\timageid\tddde1ffc-678b-3cda-1748-513086bdf01b\n\t\tcolors\t0.937255 0.796078 0.494118 1\n\t\tscales\t1\n\t\tscalet\t-1\n\t\toffsets\t0\n\t\toffsett\t0\n\t\timagerot\t0\n\t\tbump\t0\n\t\tfullbright\t0\n\t\tmedia_flags\t0\n\t}\n\tps_next_crc\t1\n\tgpw_bias\t1\n\tip\t0\n\tcomplete\tTRUE\n\tdelay\t50000\n\tnextstart\t0\n\tbirthtime\t1061088050622956\n\treztime\t1094866329019785\n\tparceltime\t1133568981980596\n\ttax_rate\t1.00084\n\tscratchpad\t0\n\t{\n\t\n\t}\n\tsale_info\t0\n\t{\n\t\tsale_type\tnot\n\t\tsale_price\t10\n\t}\n\tcorrect_family_id\t00000000-0000-0000-0000-000000000000\n\thas_rezzed\t0\n\tpre_link_base_mask\t7fffffff\n\tlinked \tchild\n\tdefault_pay_price\t-2\t1\t5\t10\t20\n}\n{'task_id':u61fa7364-e151-0597-774c-523312dae31b}\n{\n\tname\tObject|\n\tpermissions 0\n\t{\n\t\tbase_mask\t7fffff"
+ "ff\n\t\towner_mask\t7fffffff\n\t\tgroup_mask\t00000000\n\t\teveryone_mask\t00000000\n\t\tnext_owner_mask\t7fffffff\n\t\tcreator_id\t13fd9595-a47b-4d64-a5fb-6da645f038e0\n\t\towner_id\t3c115e51-04f4-523c-9fa6-98aff1034730\n\t\tlast_owner_id\t3c115e51-04f4-523c-9fa6-98aff1034730\n\t\tgroup_id\t00000000-0000-0000-0000-000000000000\n\t}\n\tlocal_id\t217444922\n\ttotal_crc\t324\n\ttype\t2\n\ttask_valid\t2\n\ttravel_access\t13\n\tdisplayopts\t2\n\tdisplaytype\tv\n\tpos\t-0.367110789\t0.00780026987\t-0.566269755\n\toldpos\t150.115005\t25.8479004\t8.18669987\n\trotation\t0.47332942485809326171875\t-0.380102097988128662109375\t-0.5734078884124755859375\t0.550168216228485107421875\n\tchildpos\t-0.00499999989\t-0.0370000005\t0.305000007\n\tchildrot\t-0.736649334430694580078125\t-0.03042060509324073791503906\t-0.02784589119255542755126953\t0.67501628398895263671875\n\tscale\t0.074629\t0.289956\t0.01\n\tsit_offset\t0\t0\t0\n\tcamera_eye_offset\t0\t0\t0\n\tcamera_at_offset\t0\t0\t0\n\tsit_quat\t0\t"
+ "0\t0\t1\n\tsit_hint\t0\n\tstate\t160\n\tmaterial\t3\n\tsoundid\t00000000-0000-0000-0000-000000000000\n\tsoundgain\t0\n\tsoundradius\t0\n\tsoundflags\t0\n\ttextcolor\t0 0 0 1\n\tselected\t0\n\tselector\t00000000-0000-0000-0000-000000000000\n\tusephysics\t0\n\trotate_x\t1\n\trotate_y\t1\n\trotate_z\t1\n\tphantom\t0\n\tremote_script_access_pin\t0\n\tvolume_detect\t0\n\tblock_grabs\t0\n\tdie_at_edge\t0\n\treturn_at_edge\t0\n\ttemporary\t0\n\tsandbox\t0\n\tsandboxhome\t0\t0\t0\n\tshape 0\n\t{\n\t\tpath 0\n\t\t{\n\t\t\tcurve\t16\n\t\t\tbegin\t0\n\t\t\tend\t1\n\t\t\tscale_x\t1\n\t\t\tscale_y\t1\n\t\t\tshear_x\t0\n\t\t\tshear_y\t0\n\t\t\ttwist\t0\n\t\t\ttwist_begin\t0\n\t\t\tradius_offset\t0\n\t\t\ttaper_x\t0\n\t\t\ttaper_y\t0\n\t\t\trevolutions\t1\n\t\t\tskew\t0\n\t\t}\n\t\tprofile 0\n\t\t{\n\t\t\tcurve\t1\n\t\t\tbegin\t0\n\t\t\tend\t1\n\t\t\thollow\t0\n\t\t}\n\t}\n\tfaces\t6\n\t{\n\t\timageid\tddde1ffc-678b-3cda-1748-513086bdf01b\n\t\tcolors\t0.937255 0.796078 0.494118 1\n\t\tscales\t1\n\t"
+ "\tscalet\t1\n\t\toffsets\t0\n\t\toffsett\t0\n\t\timagerot\t0\n\t\tbump\t0\n\t\tfullbright\t0\n\t\tmedia_flags\t0\n\t}\n\t{\n\t\timageid\tf54a0c32-3cd1-d49a-5b4f-7b792bebc204\n\t\tcolors\t0.937255 0.796078 0.494118 1\n\t\tscales\t1\n\t\tscalet\t1\n\t\toffsets\t0\n\t\toffsett\t0\n\t\timagerot\t0\n\t\tbump\t0\n\t\tfullbright\t0\n\t\tmedia_flags\t0\n\t}\n\t{\n\t\timageid\tf54a0c32-3cd1-d49a-5b4f-7b792bebc204\n\t\tcolors\t0.937255 0.796078 0.494118 1\n\t\tscales\t1\n\t\tscalet\t1\n\t\toffsets\t0\n\t\toffsett\t0\n\t\timagerot\t0\n\t\tbump\t0\n\t\tfullbright\t0\n\t\tmedia_flags\t0\n\t}\n\t{\n\t\timageid\tf54a0c32-3cd1-d49a-5b4f-7b792bebc204\n\t\tcolors\t0.937255 0.796078 0.494118 1\n\t\tscales\t1\n\t\tscalet\t1\n\t\toffsets\t0\n\t\toffsett\t0\n\t\timagerot\t0\n\t\tbump\t0\n\t\tfullbright\t0\n\t\tmedia_flags\t0\n\t}\n\t{\n\t\timageid\tf54a0c32-3cd1-d49a-5b4f-7b792bebc204\n\t\tcolors\t0.937255 0.796078 0.494118 1\n\t\tscales\t1\n\t\tscalet\t1\n\t\toffsets\t0\n\t\toffsett\t0\n\t\timagerot\t0\n\t"
+ "\tbump\t0\n\t\tfullbright\t0\n\t\tmedia_flags\t0\n\t}\n\t{\n\t\timageid\tddde1ffc-678b-3cda-1748-513086bdf01b\n\t\tcolors\t0.937255 0.796078 0.494118 1\n\t\tscales\t1\n\t\tscalet\t-1\n\t\toffsets\t0\n\t\toffsett\t0\n\t\timagerot\t0\n\t\tbump\t0\n\t\tfullbright\t0\n\t\tmedia_flags\t0\n\t}\n\tps_next_crc\t1\n\tgpw_bias\t1\n\tip\t0\n\tcomplete\tTRUE\n\tdelay\t50000\n\tnextstart\t0\n\tbirthtime\t1061087839248891\n\treztime\t1094866329020800\n\tparceltime\t1133568981981983\n\ttax_rate\t1.00084\n\tscratchpad\t0\n\t{\n\t\n\t}\n\tsale_info\t0\n\t{\n\t\tsale_type\tnot\n\t\tsale_price\t10\n\t}\n\tcorrect_family_id\t00000000-0000-0000-0000-000000000000\n\thas_rezzed\t0\n\tpre_link_base_mask\t7fffffff\n\tlinked \tchild\n\tdefault_pay_price\t-2\t1\t5\t10\t20\n}\n{'task_id':ub8d68643-7dd8-57af-0d24-8790032aed0c}\n{\n\tname\tObject|\n\tpermissions 0\n\t{\n\t\tbase_mask\t7fffffff\n\t\towner_mask\t7fffffff\n\t\tgroup_mask\t00000000\n\t\teveryone_mask\t00000000\n\t\tnext_owner_mask\t7fffffff\n\t\tcreat"
+ "or_id\t13fd9595-a47b-4d64-a5fb-6da645f038e0\n\t\towner_id\t3c115e51-04f4-523c-9fa6-98aff1034730\n\t\tlast_owner_id\t3c115e51-04f4-523c-9fa6-98aff1034730\n\t\tgroup_id\t00000000-0000-0000-0000-000000000000\n\t}\n\tlocal_id\t217444923\n\ttotal_crc\t235\n\ttype\t2\n\ttask_valid\t2\n\ttravel_access\t13\n\tdisplayopts\t2\n\tdisplaytype\tv\n\tpos\t-0.120029509\t-0.00284469454\t-0.0302077383\n\toldpos\t150.710999\t25.8584995\t8.19172001\n\trotation\t0.145459949970245361328125\t-0.1646589934825897216796875\t0.659558117389678955078125\t-0.718826770782470703125\n\tchildpos\t0\t-0.182999998\t-0.26699999\n\tchildrot\t0.991444766521453857421875\t3.271923924330621957778931e-05\t-0.0002416197530692443251609802\t0.1305266767740249633789062\n\tscale\t0.0382982\t0.205957\t0.368276\n\tsit_offset\t0\t0\t0\n\tcamera_eye_offset\t0\t0\t0\n\tcamera_at_offset\t0\t0\t0\n\tsit_quat\t0\t0\t0\t1\n\tsit_hint\t0\n\tstate\t160\n\tmaterial\t3\n\tsoundid\t00000000-0000-0000-0000-000000000000\n\tsoundgain\t0\n\tsoundra"
+ "dius\t0\n\tsoundflags\t0\n\ttextcolor\t0 0 0 1\n\tselected\t0\n\tselector\t00000000-0000-0000-0000-000000000000\n\tusephysics\t0\n\trotate_x\t1\n\trotate_y\t1\n\trotate_z\t1\n\tphantom\t0\n\tremote_script_access_pin\t0\n\tvolume_detect\t0\n\tblock_grabs\t0\n\tdie_at_edge\t0\n\treturn_at_edge\t0\n\ttemporary\t0\n\tsandbox\t0\n\tsandboxhome\t0\t0\t0\n\tshape 0\n\t{\n\t\tpath 0\n\t\t{\n\t\t\tcurve\t32\n\t\t\tbegin\t0.3\n\t\t\tend\t0.65\n\t\t\tscale_x\t1\n\t\t\tscale_y\t0.05\n\t\t\tshear_x\t0\n\t\t\tshear_y\t0\n\t\t\ttwist\t0\n\t\t\ttwist_begin\t0\n\t\t\tradius_offset\t0\n\t\t\ttaper_x\t0\n\t\t\ttaper_y\t0\n\t\t\trevolutions\t1\n\t\t\tskew\t0\n\t\t}\n\t\tprofile 0\n\t\t{\n\t\t\tcurve\t0\n\t\t\tbegin\t0\n\t\t\tend\t1\n\t\t\thollow\t0\n\t\t}\n\t}\n\tfaces\t3\n\t{\n\t\timageid\te7150bed-3e3e-c698-eb15-d17b178148af\n\t\tcolors\t0.843137 0.156863 0.156863 1\n\t\tscales\t15\n\t\tscalet\t1\n\t\toffsets\t0\n\t\toffsett\t0\n\t\timagerot\t-1.57084\n\t\tbump\t0\n\t\tfullbright\t0\n\t\tmedia_flags\t0"
+ "\n\t}\n\t{\n\t\timageid\te7150bed-3e3e-c698-eb15-d17b178148af\n\t\tcolors\t0.843137 0.156863 0.156863 1\n\t\tscales\t15\n\t\tscalet\t1\n\t\toffsets\t0\n\t\toffsett\t0\n\t\timagerot\t-1.57084\n\t\tbump\t0\n\t\tfullbright\t0\n\t\tmedia_flags\t0\n\t}\n\t{\n\t\timageid\te7150bed-3e3e-c698-eb15-d17b178148af\n\t\tcolors\t0.843137 0.156863 0.156863 1\n\t\tscales\t15\n\t\tscalet\t1\n\t\toffsets\t0\n\t\toffsett\t0\n\t\timagerot\t-1.57084\n\t\tbump\t0\n\t\tfullbright\t0\n\t\tmedia_flags\t0\n\t}\n\tps_next_crc\t1\n\tgpw_bias\t1\n\tip\t0\n\tcomplete\tTRUE\n\tdelay\t50000\n\tnextstart\t0\n\tbirthtime\t1061087534454174\n\treztime\t1094866329021741\n\tparceltime\t1133568981982889\n\ttax_rate\t1.00326\n\tscratchpad\t0\n\t{\n\t\n\t}\n\tsale_info\t0\n\t{\n\t\tsale_type\tnot\n\t\tsale_price\t10\n\t}\n\tcorrect_family_id\t00000000-0000-0000-0000-000000000000\n\thas_rezzed\t0\n\tpre_link_base_mask\t7fffffff\n\tlinked \tchild\n\tdefault_pay_price\t-2\t1\t5\t10\t20\n}\n{'task_id':ue4b19200-9d33-962f-c8c5-6f"
+ "25be3a3fd0}\n{\n\tname\tApotheosis_Immolaine_tail|\n\tpermissions 0\n\t{\n\t\tbase_mask\t7fffffff\n\t\towner_mask\t7fffffff\n\t\tgroup_mask\t00000000\n\t\teveryone_mask\t00000000\n\t\tnext_owner_mask\t7fffffff\n\t\tcreator_id\t13fd9595-a47b-4d64-a5fb-6da645f038e0\n\t\towner_id\t3c115e51-04f4-523c-9fa6-98aff1034730\n\t\tlast_owner_id\t3c115e51-04f4-523c-9fa6-98aff1034730\n\t\tgroup_id\t00000000-0000-0000-0000-000000000000\n\t}\n\tlocal_id\t217444924\n\ttotal_crc\t675\n\ttype\t1\n\ttask_valid\t2\n\ttravel_access\t13\n\tdisplayopts\t2\n\tdisplaytype\tv\n\tpos\t-0.34780401\t-0.00968400016\t-0.260098994\n\toldpos\t0\t0\t0\n\trotation\t0.73164522647857666015625\t-0.67541944980621337890625\t-0.07733880728483200073242188\t0.05022468417882919311523438\n\tvelocity\t0\t0\t0\n\tangvel\t0\t0\t0\n\tscale\t0.0382982\t0.32228\t0.383834\n\tsit_offset\t0\t0\t0\n\tcamera_eye_offset\t0\t0\t0\n\tcamera_at_offset\t0\t0\t0\n\tsit_quat\t0\t0\t0\t1\n\tsit_hint\t0\n\tstate\t160\n\tmaterial\t3\n\tsoundid\t00000"
+ "000-0000-0000-0000-000000000000\n\tsoundgain\t0\n\tsoundradius\t0\n\tsoundflags\t0\n\ttextcolor\t0 0 0 1\n\tselected\t0\n\tselector\t00000000-0000-0000-0000-000000000000\n\tusephysics\t0\n\trotate_x\t1\n\trotate_y\t1\n\trotate_z\t1\n\tphantom\t0\n\tremote_script_access_pin\t0\n\tvolume_detect\t0\n\tblock_grabs\t0\n\tdie_at_edge\t0\n\treturn_at_edge\t0\n\ttemporary\t0\n\tsandbox\t0\n\tsandboxhome\t0\t0\t0\n\tshape 0\n\t{\n\t\tpath 0\n\t\t{\n\t\t\tcurve\t32\n\t\t\tbegin\t0.3\n\t\t\tend\t0.65\n\t\t\tscale_x\t1\n\t\t\tscale_y\t0.05\n\t\t\tshear_x\t0\n\t\t\tshear_y\t0\n\t\t\ttwist\t0\n\t\t\ttwist_begin\t0\n\t\t\tradius_offset\t0\n\t\t\ttaper_x\t0\n\t\t\ttaper_y\t0\n\t\t\trevolutions\t1\n\t\t\tskew\t0\n\t\t}\n\t\tprofile 0\n\t\t{\n\t\t\tcurve\t0\n\t\t\tbegin\t0\n\t\t\tend\t1\n\t\t\thollow\t0\n\t\t}\n\t}\n\tfaces\t3\n\t{\n\t\timageid\te7150bed-3e3e-c698-eb15-d17b178148af\n\t\tcolors\t0.843137 0.156863 0.156863 1\n\t\tscales\t15\n\t\tscalet\t1\n\t\toffsets\t0\n\t\toffsett\t0\n\t\timagerot\t-1"
+ ".57084\n\t\tbump\t0\n\t\tfullbright\t0\n\t\tmedia_flags\t0\n\t}\n\t{\n\t\timageid\te7150bed-3e3e-c698-eb15-d17b178148af\n\t\tcolors\t0.843137 0.156863 0.156863 1\n\t\tscales\t15\n\t\tscalet\t1\n\t\toffsets\t0\n\t\toffsett\t0\n\t\timagerot\t-1.57084\n\t\tbump\t0\n\t\tfullbright\t0\n\t\tmedia_flags\t0\n\t}\n\t{\n\t\timageid\te7150bed-3e3e-c698-eb15-d17b178148af\n\t\tcolors\t0.843137 0.156863 0.156863 1\n\t\tscales\t15\n\t\tscalet\t1\n\t\toffsets\t0\n\t\toffsett\t0\n\t\timagerot\t-1.57084\n\t\tbump\t0\n\t\tfullbright\t0\n\t\tmedia_flags\t0\n\t}\n\tps_next_crc\t1\n\tgpw_bias\t1\n\tip\t0\n\tcomplete\tTRUE\n\tdelay\t50000\n\tnextstart\t0\n\tbirthtime\t1061087463950186\n\treztime\t1094866329022555\n\tparceltime\t1133568981984359\n\tdescription\t(No Description)|\n\ttax_rate\t1.01736\n\tnamevalue\tAttachPt U32 RW S 10\n\tnamevalue\tAttachmentOrientation VEC3 RW DS -3.110088, -0.182018, 1.493795\n\tnamevalue\tAttachmentOffset VEC3 RW DS -0.347804, -0.009684, -0.260099\n\tnamevalue\tAttachItemI"
+ "D STRING RW SV 20f36c3a-b44b-9bc7-87f3-018bfdfc8cda\n\tscratchpad\t0\n\t{\n\t\n\t}\n\tsale_info\t0\n\t{\n\t\tsale_type\tnot\n\t\tsale_price\t10\n\t}\n\torig_asset_id\t8747acbc-d391-1e59-69f1-41d06830e6c0\n\torig_item_id\t20f36c3a-b44b-9bc7-87f3-018bfdfc8cda\n\tfrom_task_id\t3c115e51-04f4-523c-9fa6-98aff1034730\n\tcorrect_family_id\t00000000-0000-0000-0000-000000000000\n\thas_rezzed\t0\n\tpre_link_base_mask\t7fffffff\n\tlinked \tlinked\n\tdefault_pay_price\t-2\t1\t5\t10\t20\n}\n");
+ }
+
+
+ template<> template<>
+ void URITestObject::test<18>()
+ {
+ LLURI u("secondlife:///app/login?first_name=Testert4&last_name=Tester&web_login_key=test");
+ // if secondlife is the scheme, LLURI should parse /app/login as path, with no authority
+ ensure_equals("scheme", u.scheme(), "secondlife");
+ ensure_equals("authority", u.authority(), "");
+ ensure_equals("path", u.path(), "/app/login");
+ ensure_equals("pathmap", u.pathArray()[0].asString(), "app");
+ ensure_equals("pathmap", u.pathArray()[1].asString(), "login");
+ ensure_equals("query", u.query(), "first_name=Testert4&last_name=Tester&web_login_key=test");
+ ensure_equals("query map element", u.queryMap()["last_name"].asString(), "Tester");
+
+ u = LLURI("secondlife://Da Boom/128/128/128");
+ // if secondlife is the scheme, LLURI should parse /128/128/128 as path, with Da Boom as authority
+ ensure_equals("scheme", u.scheme(), "secondlife");
+ ensure_equals("authority", u.authority(), "Da Boom");
+ ensure_equals("path", u.path(), "/128/128/128");
+ ensure_equals("pathmap", u.pathArray()[0].asString(), "128");
+ ensure_equals("pathmap", u.pathArray()[1].asString(), "128");
+ ensure_equals("pathmap", u.pathArray()[2].asString(), "128");
+ ensure_equals("query", u.query(), "");
+ }
+
+ template<> template<>
+ void URITestObject::test<19>()
+ {
+ // Parse about: schemes
+ LLURI u("about:blank?redirect-http-hack=secondlife%3A%2F%2F%2Fapp%2Flogin%3Ffirst_name%3DCallum%26last_name%3DLinden%26location%3Dspecify%26grid%3Dvaak%26region%3D%2FMorris%2F128%2F128%26web_login_key%3Defaa4795-c2aa-4c58-8966-763c27931e78");
+ ensure_equals("scheme", u.scheme(), "about");
+ ensure_equals("authority", u.authority(), "");
+ ensure_equals("path", u.path(), "blank");
+ ensure_equals("pathmap", u.pathArray()[0].asString(), "blank");
+ ensure_equals("query", u.query(), "redirect-http-hack=secondlife:///app/login?first_name=Callum&last_name=Linden&location=specify&grid=vaak&region=/Morris/128/128&web_login_key=efaa4795-c2aa-4c58-8966-763c27931e78");
+ ensure_equals("query map element", u.queryMap()["redirect-http-hack"].asString(), "secondlife:///app/login?first_name=Callum&last_name=Linden&location=specify&grid=vaak&region=/Morris/128/128&web_login_key=efaa4795-c2aa-4c58-8966-763c27931e78");
+ }
+}
+
+
diff --git a/indra/llcommon/tests/reflection_test.cpp b/indra/llcommon/tests/reflection_test.cpp
new file mode 100644
index 0000000000..59491cd1fe
--- /dev/null
+++ b/indra/llcommon/tests/reflection_test.cpp
@@ -0,0 +1,220 @@
+/**
+ * @file reflection_test.cpp
+ * @date May 2006
+ * @brief Reflection unit tests.
+ *
+ * $LicenseInfo:firstyear=2006&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$
+ */
+
+#include "../linden_common.h"
+#include "../reflective.h"
+#include "../metaclasst.h"
+#include "../metapropertyt.h"
+#include "../stdtypes.h"
+
+#include "../test/lltut.h"
+
+namespace tut
+{
+ class TestAggregatedData : public LLReflective
+ {
+ public:
+ TestAggregatedData() {;}
+ virtual const LLMetaClass& getMetaClass() const;
+
+ private:
+ };
+
+ class TestReflectionData : public LLReflective
+ {
+ public:
+ TestReflectionData() : mInt(42), mString("foo"), mNullPtr(NULL), mPtr(new TestAggregatedData()), mRef(*(new TestAggregatedData)) {;}
+ virtual ~TestReflectionData() {delete mPtr;}
+ virtual const LLMetaClass& getMetaClass() const;
+
+ static U32 getPropertyCount() {return 5;}
+
+ private:
+
+ friend class LLMetaClassT<TestReflectionData>;
+ S32 mInt;
+ std::string mString;
+ TestAggregatedData* mNullPtr;
+ TestAggregatedData* mPtr;
+ TestAggregatedData mObj;
+ TestAggregatedData& mRef;
+ };
+}
+
+template <>
+void LLMetaClassT<tut::TestReflectionData>::reflectProperties(LLMetaClass& meta_class)
+{
+ reflectProperty(meta_class, "mInt", &tut::TestReflectionData::mInt);
+ reflectProperty(meta_class, "mString", &tut::TestReflectionData::mString);
+ reflectPtrProperty(meta_class, "mNullPtr", &tut::TestReflectionData::mNullPtr);
+ reflectPtrProperty(meta_class, "mPtr", &tut::TestReflectionData::mPtr);
+ reflectProperty(meta_class, "mObj", &tut::TestReflectionData::mObj);
+ //reflectProperty(meta_class, "mRef", &tut::TestReflectionData::mRef); // AARGH!
+}
+
+namespace tut
+{
+ // virtual
+ const LLMetaClass& TestReflectionData::getMetaClass() const
+ {
+ return LLMetaClassT<TestReflectionData>::instance();
+ }
+
+ const LLMetaClass& TestAggregatedData::getMetaClass() const
+ {
+ return LLMetaClassT<TestAggregatedData>::instance();
+ }
+}
+
+namespace tut
+{
+ typedef tut::test_group<TestReflectionData> TestReflectionGroup;
+ typedef TestReflectionGroup::object TestReflectionObject;
+ TestReflectionGroup gTestReflectionGroup("reflection");
+
+ template<> template<>
+ void TestReflectionObject::test<1>()
+ {
+ // Check properties can be found.
+ const LLMetaClass& meta_class = LLMetaClassT<TestReflectionData>::instance();
+ const LLMetaProperty* null = NULL;
+ ensure_not_equals(meta_class.findProperty("mInt"), null);
+ ensure_not_equals(meta_class.findProperty("mString"), null);
+ }
+
+ template<> template<>
+ void TestReflectionObject::test<2>()
+ {
+ // Check non-existent property cannot be found.
+ const LLMetaClass& meta_class = LLMetaClassT<TestReflectionData>::instance();
+ const LLMetaProperty* null = NULL;
+ ensure_equals(meta_class.findProperty("foo"), null);
+ }
+
+ template<> template<>
+ void TestReflectionObject::test<3>()
+ {
+ // Check integer property has correct value.
+ const LLMetaClass& meta_class = LLMetaClassT<TestReflectionData>::instance();
+ ensure_equals(meta_class.findProperty("mInt")->getLLSD(this).asInteger(), 42);
+ }
+
+ template<> template<>
+ void TestReflectionObject::test<4>()
+ {
+ // Check string property has correct value.
+ const LLMetaClass& meta_class = LLMetaClassT<TestReflectionData>::instance();
+ ensure_equals(meta_class.findProperty("mString")->getLLSD(this).asString(), std::string("foo"));
+ }
+
+ template<> template<>
+ void TestReflectionObject::test<5>()
+ {
+ // Check NULL reference property has correct value.
+ const LLMetaClass& meta_class = LLMetaClassT<TestReflectionData>::instance();
+ const LLReflective* null = NULL;
+ ensure_equals(meta_class.findProperty("mNullPtr")->get(this), null);
+ }
+
+ template<> template<>
+ void TestReflectionObject::test<6>()
+ {
+ // Check reference property has correct value.
+ const LLMetaClass& meta_class = LLMetaClassT<TestReflectionData>::instance();
+ const LLReflective* null = NULL;
+ const LLReflective* ref = meta_class.findProperty("mPtr")->get(this);
+ ensure_not_equals(ref, null);
+ }
+
+ template<> template<>
+ void TestReflectionObject::test<7>()
+ {
+ // Check reflective property has correct value.
+ const LLMetaClass& meta_class = LLMetaClassT<TestReflectionData>::instance();
+ const LLReflective* null = NULL;
+ const LLReflective* ref = meta_class.findProperty("mObj")->get(this);
+ ensure_not_equals(ref, null);
+ }
+
+ template<> template<>
+ void TestReflectionObject::test<8>()
+ {
+ // Check property count.
+ const LLMetaClass& meta_class = LLMetaClassT<TestReflectionData>::instance();
+ ensure_equals(meta_class.getPropertyCount(), TestReflectionData::getPropertyCount());
+ }
+
+ template<> template<>
+ void TestReflectionObject::test<9>()
+ {
+ // Check property iteration.
+ const LLMetaClass& meta_class = LLMetaClassT<TestReflectionData>::instance();
+ U32 count = 0;
+ LLMetaClass::PropertyIterator iter;
+ for(iter = meta_class.beginProperties(); iter != meta_class.endProperties(); ++iter)
+ {
+ ++count;
+ }
+ ensure_equals(count, TestReflectionData::getPropertyCount());
+ }
+
+ template<> template<>
+ void TestReflectionObject::test<10>()
+ {
+ // Check meta classes of different types do not compare equal.
+ const LLMetaClass* reflection_data_meta_class = &(LLMetaClassT<TestReflectionData>::instance());
+ const LLMetaClass* aggregated_data_meta_class = &(LLMetaClassT<TestAggregatedData>::instance());
+ ensure_not_equals(reflection_data_meta_class, aggregated_data_meta_class);
+ }
+
+ template<> template<>
+ void TestReflectionObject::test<11>()
+ {
+ // Check class cast checks.
+ const LLMetaClass& meta_class = LLMetaClassT<TestReflectionData>::instance();
+ TestAggregatedData* aggregated_data = new TestAggregatedData();
+ LLMetaClass::PropertyIterator iter;
+ U32 exception_count = 0;
+ for(iter = meta_class.beginProperties(); iter != meta_class.endProperties(); ++iter)
+ {
+ try
+ {
+ const LLMetaProperty* property = (*iter).second;
+ const LLReflective* reflective = property->get(aggregated_data); // Wrong reflective type, should throw exception.
+
+ // useless op to get rid of compiler warning.
+ reflective = NULL;
+ }
+ catch(...)
+ {
+ ++exception_count;
+ }
+ }
+ ensure_equals(exception_count, getPropertyCount());
+
+ }
+}
diff --git a/indra/llcommon/tests/stringize_test.cpp b/indra/llcommon/tests/stringize_test.cpp
new file mode 100644
index 0000000000..3d34f23998
--- /dev/null
+++ b/indra/llcommon/tests/stringize_test.cpp
@@ -0,0 +1,104 @@
+/**
+ * @file stringize_test.cpp
+ * @author Nat Goodspeed
+ * @date 2008-09-12
+ * @brief Test of stringize.h
+ *
+ * $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 LL_WINDOWS
+#pragma warning (disable : 4675) // "resolved by ADL" -- just as I want!
+#endif
+|*==========================================================================*/
+
+// STL headers
+#include <iomanip>
+
+// Precompiled header
+#include "linden_common.h"
+
+// associated header
+#include "../stringize.h"
+
+// std headers
+// external library headers
+// other Linden headers
+#include "../llsd.h"
+
+#include "../test/lltut.h"
+
+namespace tut
+{
+ struct stringize_data
+ {
+ stringize_data():
+ c('c'),
+ s(17),
+ i(34),
+ l(68),
+ f(3.14159265358979f),
+ d(3.14159265358979),
+ // Including a space differentiates this from
+ // boost::lexical_cast<std::string>, which doesn't handle embedded
+ // spaces so well.
+ abc("abc def")
+ {
+ llsd["i"] = i;
+ llsd["d"] = d;
+ llsd["abc"] = abc;
+ }
+
+ char c;
+ short s;
+ int i;
+ long l;
+ float f;
+ double d;
+ std::string abc;
+ LLSD llsd;
+ };
+ typedef test_group<stringize_data> stringize_group;
+ typedef stringize_group::object stringize_object;
+ tut::stringize_group strzgrp("stringize_h");
+
+ template<> template<>
+ void stringize_object::test<1>()
+ {
+ ensure_equals(stringize(c), "c");
+ ensure_equals(stringize(s), "17");
+ ensure_equals(stringize(i), "34");
+ ensure_equals(stringize(l), "68");
+ ensure_equals(stringize(f), "3.14159");
+ ensure_equals(stringize(d), "3.14159");
+ ensure_equals(stringize(abc), "abc def");
+ ensure_equals(stringize(llsd), "{'abc':'abc def','d':r3.14159,'i':i34}");
+ }
+
+ template<> template<>
+ void stringize_object::test<2>()
+ {
+ ensure_equals(STRINGIZE("c is " << c), "c is c");
+ ensure_equals(STRINGIZE(std::setprecision(4) << d), "3.142");
+ }
+} // namespace tut
diff --git a/indra/llcommon/tests/wrapllerrs.h b/indra/llcommon/tests/wrapllerrs.h
new file mode 100644
index 0000000000..ffda84729b
--- /dev/null
+++ b/indra/llcommon/tests/wrapllerrs.h
@@ -0,0 +1,73 @@
+/**
+ * @file wrapllerrs.h
+ * @author Nat Goodspeed
+ * @date 2009-03-11
+ * @brief Define a class useful for unit tests that engage llerrs (LL_ERRS) functionality
+ *
+ * $LicenseInfo:firstyear=2009&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_WRAPLLERRS_H)
+#define LL_WRAPLLERRS_H
+
+#include "llerrorcontrol.h"
+
+struct WrapLL_ERRS
+{
+ WrapLL_ERRS():
+ // Resetting Settings discards the default Recorder that writes to
+ // stderr. Otherwise, expected llerrs (LL_ERRS) messages clutter the
+ // console output of successful tests, potentially confusing things.
+ mPriorErrorSettings(LLError::saveAndResetSettings()),
+ // Save shutdown function called by LL_ERRS
+ mPriorFatal(LLError::getFatalFunction())
+ {
+ // Make LL_ERRS call our own operator() method
+ LLError::setFatalFunction(boost::bind(&WrapLL_ERRS::operator(), this, _1));
+ }
+
+ ~WrapLL_ERRS()
+ {
+ LLError::setFatalFunction(mPriorFatal);
+ LLError::restoreSettings(mPriorErrorSettings);
+ }
+
+ struct FatalException: public std::runtime_error
+ {
+ FatalException(const std::string& what): std::runtime_error(what) {}
+ };
+
+ void operator()(const std::string& message)
+ {
+ // Save message for later in case consumer wants to sense the result directly
+ error = message;
+ // Also throw an appropriate exception since calling code is likely to
+ // assume that control won't continue beyond LL_ERRS.
+ throw FatalException(message);
+ }
+
+ std::string error;
+ LLError::Settings* mPriorErrorSettings;
+ LLError::FatalFunction mPriorFatal;
+};
+
+#endif /* ! defined(LL_WRAPLLERRS_H) */
diff --git a/indra/llcommon/timer.h b/indra/llcommon/timer.h
index ec3b62f9ac..82d19c2d32 100644
--- a/indra/llcommon/timer.h
+++ b/indra/llcommon/timer.h
@@ -2,30 +2,25 @@
* @file timer.h
* @brief Legacy wrapper header.
*
- * $LicenseInfo:firstyear=2000&license=viewergpl$
- *
- * Copyright (c) 2000-2007, Linden Research, Inc.
- *
+ * $LicenseInfo:firstyear=2000&license=viewerlgpl$
* Second Life Viewer Source Code
- * The source code in this file ("Source Code") is provided by Linden Lab
- * to you under the terms of the GNU General Public License, version 2.0
- * ("GPL"), unless you have obtained a separate licensing agreement
- * ("Other License"), formally executed by you and Linden Lab. Terms of
- * the GPL can be found in doc/GPL-license.txt in this distribution, or
- * online at http://secondlife.com/developers/opensource/gplv2
+ * 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.
*
- * There are special exceptions to the terms and conditions of the GPL as
- * it is applied to this Source Code. View the full text of the exception
- * in the file doc/FLOSS-exception.txt in this software distribution, or
- * online at http://secondlife.com/developers/opensource/flossexception
+ * 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.
*
- * By copying, modifying or distributing this software, you acknowledge
- * that you have read and understood your obligations described above,
- * and agree to abide by those obligations.
+ * 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
*
- * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
- * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
- * COMPLETENESS OR PERFORMANCE.
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
* $/LicenseInfo$
*/
#include "lltimer.h"
diff --git a/indra/llcommon/timing.cpp b/indra/llcommon/timing.cpp
index 411593261d..c2dc695ef3 100644
--- a/indra/llcommon/timing.cpp
+++ b/indra/llcommon/timing.cpp
@@ -2,29 +2,24 @@
* @file timing.cpp
* @brief This file will be deprecated in the future.
*
- * $LicenseInfo:firstyear=2000&license=viewergpl$
- *
- * Copyright (c) 2000-2007, Linden Research, Inc.
- *
+ * $LicenseInfo:firstyear=2000&license=viewerlgpl$
* Second Life Viewer Source Code
- * The source code in this file ("Source Code") is provided by Linden Lab
- * to you under the terms of the GNU General Public License, version 2.0
- * ("GPL"), unless you have obtained a separate licensing agreement
- * ("Other License"), formally executed by you and Linden Lab. Terms of
- * the GPL can be found in doc/GPL-license.txt in this distribution, or
- * online at http://secondlife.com/developers/opensource/gplv2
+ * 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.
*
- * There are special exceptions to the terms and conditions of the GPL as
- * it is applied to this Source Code. View the full text of the exception
- * in the file doc/FLOSS-exception.txt in this software distribution, or
- * online at http://secondlife.com/developers/opensource/flossexception
+ * 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.
*
- * By copying, modifying or distributing this software, you acknowledge
- * that you have read and understood your obligations described above,
- * and agree to abide by those obligations.
+ * 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
*
- * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
- * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
- * COMPLETENESS OR PERFORMANCE.
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
* $/LicenseInfo$
*/
diff --git a/indra/llcommon/timing.h b/indra/llcommon/timing.h
index 3ea2a0e692..c408d4c446 100644
--- a/indra/llcommon/timing.h
+++ b/indra/llcommon/timing.h
@@ -2,30 +2,25 @@
* @file timing.h
* @brief Cross-platform routines for doing timing.
*
- * $LicenseInfo:firstyear=2000&license=viewergpl$
- *
- * Copyright (c) 2000-2007, Linden Research, Inc.
- *
+ * $LicenseInfo:firstyear=2000&license=viewerlgpl$
* Second Life Viewer Source Code
- * The source code in this file ("Source Code") is provided by Linden Lab
- * to you under the terms of the GNU General Public License, version 2.0
- * ("GPL"), unless you have obtained a separate licensing agreement
- * ("Other License"), formally executed by you and Linden Lab. Terms of
- * the GPL can be found in doc/GPL-license.txt in this distribution, or
- * online at http://secondlife.com/developers/opensource/gplv2
+ * 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.
*
- * There are special exceptions to the terms and conditions of the GPL as
- * it is applied to this Source Code. View the full text of the exception
- * in the file doc/FLOSS-exception.txt in this software distribution, or
- * online at http://secondlife.com/developers/opensource/flossexception
+ * 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.
*
- * By copying, modifying or distributing this software, you acknowledge
- * that you have read and understood your obligations described above,
- * and agree to abide by those obligations.
+ * 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
*
- * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
- * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
- * COMPLETENESS OR PERFORMANCE.
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
* $/LicenseInfo$
*/
@@ -42,7 +37,6 @@ const F32 SEC_TO_MICROSEC = 1000000.f;
const U64 SEC_TO_MICROSEC_U64 = 1000000;
const U32 SEC_PER_DAY = 86400;
-// This is just a stub, implementation in lltimer.cpp. This file will be deprecated in the future.
-U64 totalTime(); // Returns current system time in microseconds
+// functionality has been moved lltimer.{cpp,h}. This file will be deprecated in the future.
#endif
diff --git a/indra/llcommon/u64.cpp b/indra/llcommon/u64.cpp
index f3422770ae..eea16c5036 100644
--- a/indra/llcommon/u64.cpp
+++ b/indra/llcommon/u64.cpp
@@ -2,30 +2,25 @@
* @file u64.cpp
* @brief Utilities to deal with U64s.
*
- * $LicenseInfo:firstyear=2001&license=viewergpl$
- *
- * Copyright (c) 2001-2007, Linden Research, Inc.
- *
+ * $LicenseInfo:firstyear=2001&license=viewerlgpl$
* Second Life Viewer Source Code
- * The source code in this file ("Source Code") is provided by Linden Lab
- * to you under the terms of the GNU General Public License, version 2.0
- * ("GPL"), unless you have obtained a separate licensing agreement
- * ("Other License"), formally executed by you and Linden Lab. Terms of
- * the GPL can be found in doc/GPL-license.txt in this distribution, or
- * online at http://secondlife.com/developers/opensource/gplv2
+ * 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.
*
- * There are special exceptions to the terms and conditions of the GPL as
- * it is applied to this Source Code. View the full text of the exception
- * in the file doc/FLOSS-exception.txt in this software distribution, or
- * online at http://secondlife.com/developers/opensource/flossexception
+ * 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.
*
- * By copying, modifying or distributing this software, you acknowledge
- * that you have read and understood your obligations described above,
- * and agree to abide by those obligations.
+ * 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
*
- * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
- * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
- * COMPLETENESS OR PERFORMANCE.
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
* $/LicenseInfo$
*/
@@ -34,10 +29,10 @@
#include "u64.h"
-U64 str_to_U64(const char *str)
+U64 str_to_U64(const std::string& str)
{
U64 result = 0;
- const char *aptr = strpbrk(str,"0123456789");
+ const char *aptr = strpbrk(str.c_str(),"0123456789");
if (!aptr)
{
@@ -54,8 +49,9 @@ U64 str_to_U64(const char *str)
}
-char* U64_to_str(U64 value, char* result, S32 result_size)
-{
+std::string U64_to_str(U64 value)
+{
+ std::string res;
U32 part1,part2,part3;
part3 = (U32)(value % (U64)10000000);
@@ -70,31 +66,26 @@ char* U64_to_str(U64 value, char* result, S32 result_size)
if (part1)
{
- snprintf( /* Flawfinder: ignore */
- result,
- result_size,
- "%u%07u%07u",
- part1,part2,part3);
+ res = llformat("%u%07u%07u",part1,part2,part3);
}
else if (part2)
{
- snprintf( /* Flawfinder: ignore */
- result,
- result_size,
- "%u%07u",
- part2,part3);
+ res = llformat("%u%07u",part2,part3);
}
else
{
- snprintf( /* Flawfinder: ignore */
- result,
- result_size,
- "%u",
- part3);
+ res = llformat("%u",part3);
}
- return (result);
+ return res;
}
+char* U64_to_str(U64 value, char* result, S32 result_size)
+{
+ std::string res = U64_to_str(value);
+ LLStringUtil::copy(result, res.c_str(), result_size);
+ return result;
+}
+
F64 U64_to_F64(const U64 value)
{
S64 top_bits = (S64)(value >> 1);
diff --git a/indra/llcommon/u64.h b/indra/llcommon/u64.h
index f4580513bc..75c8a59136 100644
--- a/indra/llcommon/u64.h
+++ b/indra/llcommon/u64.h
@@ -2,30 +2,25 @@
* @file u64.h
* @brief Utilities to deal with U64s.
*
- * $LicenseInfo:firstyear=2001&license=viewergpl$
- *
- * Copyright (c) 2001-2007, Linden Research, Inc.
- *
+ * $LicenseInfo:firstyear=2001&license=viewerlgpl$
* Second Life Viewer Source Code
- * The source code in this file ("Source Code") is provided by Linden Lab
- * to you under the terms of the GNU General Public License, version 2.0
- * ("GPL"), unless you have obtained a separate licensing agreement
- * ("Other License"), formally executed by you and Linden Lab. Terms of
- * the GPL can be found in doc/GPL-license.txt in this distribution, or
- * online at http://secondlife.com/developers/opensource/gplv2
+ * Copyright (C) 2010, Linden Research, Inc.
*
- * There are special exceptions to the terms and conditions of the GPL as
- * it is applied to this Source Code. View the full text of the exception
- * in the file doc/FLOSS-exception.txt in this software distribution, or
- * online at http://secondlife.com/developers/opensource/flossexception
+ * 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.
*
- * By copying, modifying or distributing this software, you acknowledge
- * that you have read and understood your obligations described above,
- * and agree to abide by those obligations.
+ * 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.
*
- * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
- * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
- * COMPLETENESS OR PERFORMANCE.
+ * 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$
*/
@@ -38,7 +33,14 @@
* @param str The string to parse.
* @return Returns the first U64 value found in the string or 0 on failure.
*/
-U64 str_to_U64(const char* str);
+LL_COMMON_API U64 str_to_U64(const std::string& str);
+
+/**
+ * @brief Given a U64 value, return a printable representation.
+ * @param value The U64 to turn into a printable character array.
+ * @return Returns the result string.
+ */
+LL_COMMON_API std::string U64_to_str(U64 value);
/**
* @brief Given a U64 value, return a printable representation.
@@ -57,16 +59,16 @@ U64 str_to_U64(const char* str);
* @param result_size The size of the buffer allocated. Use U64_BUF.
* @return Returns the result pointer.
*/
-char* U64_to_str(U64 value, char* result, S32 result_size);
+LL_COMMON_API char* U64_to_str(U64 value, char* result, S32 result_size);
/**
* @brief Convert a U64 to the closest F64 value.
*/
-F64 U64_to_F64(const U64 value);
+LL_COMMON_API F64 U64_to_F64(const U64 value);
/**
* @brief Helper function to wrap strtoull() which is not available on windows.
*/
-U64 llstrtou64(const char* str, char** end, S32 base);
+LL_COMMON_API U64 llstrtou64(const char* str, char** end, S32 base);
#endif