From cf59064566ed68d35031a541a3e09330d664803f Mon Sep 17 00:00:00 2001
From: Rye Mutt <rye@alchemyviewer.org>
Date: Wed, 19 Feb 2020 16:06:26 -0500
Subject: [PATCH] Fix experience log depending on brain dead sorted LLSD map
 behavior

---
 indra/newview/llexperiencelog.cpp      | 38 +++++------
 indra/newview/llexperiencelog.h        |  4 +-
 indra/newview/llpanelexperiencelog.cpp | 94 ++++++++++++--------------
 3 files changed, 65 insertions(+), 71 deletions(-)

diff --git a/indra/newview/llexperiencelog.cpp b/indra/newview/llexperiencelog.cpp
index 0a365d0c38..38677d49b9 100644
--- a/indra/newview/llexperiencelog.cpp
+++ b/indra/newview/llexperiencelog.cpp
@@ -90,7 +90,8 @@ void LLExperienceLog::handleExperienceMessage(LLSD& message)
 
 	std::string day = daybuf;
 
-	if(!mEvents.has(day))
+	auto iter = mEvents.find(day);
+	if(iter == mEvents.end())
 	{
 		mEvents[day] = LLSD::emptyArray();
 	}
@@ -178,7 +179,12 @@ void LLExperienceLog::saveEvents()
 {
 	eraseExpired();
 	std::string filename = getFilename();
-	LLSD settings = LLSD::emptyMap().with("Events", mEvents);
+	LLSD temp_events;
+	for (const auto& event_pair : mEvents)
+	{
+		temp_events[event_pair.first] = event_pair.second;
+	}
+	LLSD settings = LLSD::emptyMap().with("Events", temp_events);
 
 	settings["MaxDays"] = (int)mMaxDays;
 	settings["Notify"] = mNotifyNewEvent;
@@ -212,7 +218,11 @@ void LLExperienceLog::loadEvents()
 	mEvents.clear();
 	if(mMaxDays > 0 && settings.has("Events"))
 	{
-		mEvents = settings["Events"];
+		const auto& events = settings["Events"];
+		for (auto iter = events.beginMap(), end = events.endMap(); iter != end; ++iter)
+		{
+			mEvents[iter->first] = iter->second;
+		}
 	}
 
 	eraseExpired();
@@ -225,21 +235,14 @@ LLExperienceLog::~LLExperienceLog()
 
 void LLExperienceLog::eraseExpired()
 {
-    std::vector<std::string> expired;
-	std::for_each(mEvents.beginMap(), mEvents.endMap(),
-				  [&](const auto& event_pair)
+	for (auto it = mEvents.begin(), end = mEvents.end(); it != end;)
 	{
-		const std::string& date = event_pair.first;
-		if (isExpired(date))
+		auto event_it = it++;
+		if (isExpired(event_it->first))
 		{
-            expired.push_back(date);
+			mEvents.erase(event_it);
 		}
-	});
-    
-    for (const auto& date : expired)
-    {
-        mEvents.erase(date);
-    }
+	}
 }
 
 bool LLExperienceLog::isExpired(const std::string& date)
@@ -256,11 +259,6 @@ bool LLExperienceLog::isExpired(const std::string& date)
 	return event_date.secondsSinceEpoch() <= (LLDate::now().secondsSinceEpoch() - F64(getMaxDays() * 86400U));
 }
 
-const LLSD& LLExperienceLog::getEvents() const
-{
-	return mEvents;
-}
-
 void LLExperienceLog::clear()
 {
 	mEvents.clear();
diff --git a/indra/newview/llexperiencelog.h b/indra/newview/llexperiencelog.h
index 695d542c6f..cb3180773e 100644
--- a/indra/newview/llexperiencelog.h
+++ b/indra/newview/llexperiencelog.h
@@ -50,7 +50,7 @@ public:
 	U32 getPageSize() const { return mPageSize; }
 	void setPageSize(U32 val) { mPageSize = val; }
 
-	const LLSD& getEvents()const;
+	const auto& getEvents() const { return mEvents; };
 	void clear();
 
 	virtual ~LLExperienceLog();
@@ -67,7 +67,7 @@ protected:
 	void saveEvents();
 	void eraseExpired();
 
-	LLSD mEvents;
+	std::map<std::string, LLSD> mEvents;
 	callback_signal_t mSignals;
 	callback_connection_t mNotifyConnection;
 	U32 mMaxDays;
diff --git a/indra/newview/llpanelexperiencelog.cpp b/indra/newview/llpanelexperiencelog.cpp
index 0a390e8189..2df780a2df 100644
--- a/indra/newview/llpanelexperiencelog.cpp
+++ b/indra/newview/llpanelexperiencelog.cpp
@@ -94,9 +94,9 @@ void LLPanelExperienceLog::refresh()
 {
 	S32 selected = mEventList->getFirstSelectedIndex();
 	mEventList->deleteAllItems();
-	const LLSD events = LLExperienceLog::instance().getEvents();
+	const auto& events = LLExperienceLog::instance().getEvents();
 
-	if(events.size() == 0)
+	if(events.empty())
 	{
 		mEventList->setCommentText(getString("no_events"));
 		return;
@@ -112,62 +112,58 @@ void LLPanelExperienceLog::refresh()
 	U32 items = 0;
 	bool moreItems = false;
 	
-	if (!events.emptyMap())
+	for (auto day = events.crbegin(), end_day = events.crend(); day != end_day; ++day)
 	{
-		LLSD::map_const_iterator day = events.endMap();
-		do
+		const std::string date = day->first;
+		if (LLExperienceLog::instance().isExpired(date))
 		{
-			--day;
-			const std::string& date = day->first;
-			if (LLExperienceLog::instance().isExpired(date))
-			{
-				continue;
-			}
-			const LLSD& dayArray = day->second;
-			int size = dayArray.size();
-			if(itemsToSkip > size)
-			{
-				itemsToSkip -= size;
-				continue;
-			}
-			if(items >= mPageSize && size > 0)
+			continue;
+		}
+		const LLSD& dayArray = day->second;
+		int size = dayArray.size();
+		if (itemsToSkip > size)
+		{
+			itemsToSkip -= size;
+			continue;
+		}
+		if (items >= mPageSize && size > 0)
+		{
+			moreItems = true;
+			break;
+		}
+		for (int i = dayArray.size() - itemsToSkip - 1; i >= 0; i--)
+		{
+			if (items >= mPageSize)
 			{
 				moreItems = true;
 				break;
 			}
-			for(int i = dayArray.size() - itemsToSkip - 1; i >= 0; i--)
+			const LLSD event = dayArray[i];
+			LLUUID id = event[LLExperienceCache::EXPERIENCE_ID].asUUID();
+			const LLSD& experience = LLExperienceCache::instance().get(id);
+			if (experience.isUndefined()) {
+				waiting = true;
+				waiting_id = id;
+			}
+			if (!waiting)
 			{
-				if(items >= mPageSize)
-				{
-					moreItems = true;
-					break;
-				}
-				const LLSD event = dayArray[i];
-				LLUUID id = event[LLExperienceCache::EXPERIENCE_ID].asUUID();
-                const LLSD& experience = LLExperienceCache::instance().get(id);
-				if(experience.isUndefined()){
-					waiting = true;
-					waiting_id = id;
-				}
-				if(!waiting)
-				{
-					item["id"] = event;
-
-					LLSD& columns = item["columns"];
-					columns[0]["column"] = "time";
-					columns[0]["value"] = day->first+event["Time"].asString();
-					columns[1]["column"] = "event";
-					columns[1]["value"] = LLExperienceLog::getPermissionString(event, "ExperiencePermissionShort");
-					columns[2]["column"] = "experience_name";
-					columns[2]["value"] = experience[LLExperienceCache::NAME].asString();
-					columns[3]["column"] = "object_name";
-					columns[3]["value"] = event["ObjectName"].asString();
-					mEventList->addElement(item);
-				}
-				++items;
+				item["id"] = event;
+
+				LLSD& columns = item["columns"];
+				columns[0]["column"] = "time";
+				columns[0]["value"] = day->first + event["Time"].asString();
+				columns[1]["column"] = "event";
+				columns[1]["value"] = LLExperienceLog::getPermissionString(event, "ExperiencePermissionShort");
+				columns[2]["column"] = "experience_name";
+				columns[2]["value"] = experience[LLExperienceCache::NAME].asString();
+				columns[3]["column"] = "object_name";
+				columns[3]["value"] = event["ObjectName"].asString();
+				mEventList->addElement(item);
 			}
-		} while (day != events.beginMap());
+			++items;
+		}
 	}
+
 	if(waiting)
 	{
 		mEventList->deleteAllItems();
-- 
GitLab