From a35c779aef59545a1b8d1da0aa39cc153b345339 Mon Sep 17 00:00:00 2001 From: hdpoliveira Date: Sun, 31 May 2020 18:54:28 -0300 Subject: [PATCH 1/2] Rename NewsItemQueue to NewsItemQueues --- src/openrct2/management/NewsItem.cpp | 38 ++++++++++++++-------------- src/openrct2/management/NewsItem.h | 4 +-- 2 files changed, 21 insertions(+), 21 deletions(-) diff --git a/src/openrct2/management/NewsItem.cpp b/src/openrct2/management/NewsItem.cpp index cd264c428c..534886b923 100644 --- a/src/openrct2/management/NewsItem.cpp +++ b/src/openrct2/management/NewsItem.cpp @@ -23,7 +23,7 @@ #include "../windows/Intent.h" #include "../world/Sprite.h" -NewsItemQueue gNewsItems; +NewsItemQueues gNewsItems; /** rct2: 0x0097BE7C */ const uint8_t news_type_properties[] = { @@ -39,22 +39,22 @@ const uint8_t news_type_properties[] = { NEWS_TYPE_HAS_SUBJECT, // NEWS_ITEM_GRAPH }; -NewsItem& NewsItemQueue::Current() +NewsItem& NewsItemQueues::Current() { return Recent[0]; } -const NewsItem& NewsItemQueue::Current() const +const NewsItem& NewsItemQueues::Current() const { return Recent[0]; } -NewsItem& NewsItemQueue::Oldest() +NewsItem& NewsItemQueues::Oldest() { return Archived[0]; } -const NewsItem& NewsItemQueue::Oldest() const +const NewsItem& NewsItemQueues::Oldest() const { return Archived[0]; } @@ -74,12 +74,12 @@ NewsItem* news_item_get(int32_t index) return gNewsItems.At(index); } -NewsItem& NewsItemQueue::operator[](size_t index) +NewsItem& NewsItemQueues::operator[](size_t index) { - return const_cast(const_cast(*this)[index]); + return const_cast(const_cast(*this)[index]); } -const NewsItem& NewsItemQueue::operator[](size_t index) const +const NewsItem& NewsItemQueues::operator[](size_t index) const { if (index < NEWS_ITEM_HISTORY_START) return Recent[index]; @@ -87,12 +87,12 @@ const NewsItem& NewsItemQueue::operator[](size_t index) const return Archived[index - NEWS_ITEM_HISTORY_START]; } -NewsItem* NewsItemQueue::At(int32_t index) +NewsItem* NewsItemQueues::At(int32_t index) { - return const_cast(const_cast(*this).At(index)); + return const_cast(const_cast(*this).At(index)); } -const NewsItem* NewsItemQueue::At(int32_t index) const +const NewsItem* NewsItemQueues::At(int32_t index) const { if (news_item_is_valid_idx(index)) { @@ -115,7 +115,7 @@ bool news_item_is_queue_empty() return gNewsItems.IsEmpty(); } -bool NewsItemQueue::IsEmpty() const +bool NewsItemQueues::IsEmpty() const { return Current().IsEmpty(); } @@ -124,7 +124,7 @@ bool NewsItemQueue::IsEmpty() const * * rct2: 0x0066DF32 */ -void NewsItemQueue::Init() +void NewsItemQueues::Init() { Current().Type = NEWS_ITEM_NULL; Oldest().Type = NEWS_ITEM_NULL; @@ -144,7 +144,7 @@ void news_item_init_queue() context_broadcast_intent(&intent); } -uint16_t NewsItemQueue::IncrementTicks() +uint16_t NewsItemQueues::IncrementTicks() { return ++Current().Ticks; } @@ -160,7 +160,7 @@ static void news_item_tick_current() } } -int32_t NewsItemQueue::RemoveTime() const +int32_t NewsItemQueues::RemoveTime() const { if (!Recent[5].IsEmpty() && !Recent[4].IsEmpty() && !Recent[3].IsEmpty() && !Recent[2].IsEmpty()) { @@ -169,7 +169,7 @@ int32_t NewsItemQueue::RemoveTime() const return 320; } -bool NewsItemQueue::CurrentShouldBeArchived() const +bool NewsItemQueues::CurrentShouldBeArchived() const { return Current().Ticks >= RemoveTime(); } @@ -204,7 +204,7 @@ void news_item_close_current() gNewsItems.ArchiveCurrent(); } -void NewsItemQueue::ArchiveCurrent() +void NewsItemQueues::ArchiveCurrent() { // Check if there is a current message if (IsEmpty()) @@ -228,7 +228,7 @@ void NewsItemQueue::ArchiveCurrent() * Finds a spare history slot or replaces an existing one if there are no spare * slots available. */ -void NewsItemQueue::AppendToArchive(NewsItem& item) +void NewsItemQueues::AppendToArchive(NewsItem& item) { auto it = std::find_if(std::begin(Archived), std::end(Archived), [](const auto& newsItem) { return newsItem.IsEmpty(); }); if (it != std::end(Archived)) @@ -339,7 +339,7 @@ std::optional news_item_get_subject_location(int32_t type, int32_t su return subjectLoc; } -NewsItem* NewsItemQueue::FirstOpenOrNewSlot() +NewsItem* NewsItemQueues::FirstOpenOrNewSlot() { auto it = std::begin(Recent); for (; !it->IsEmpty();) diff --git a/src/openrct2/management/NewsItem.h b/src/openrct2/management/NewsItem.h index 3623bac716..afc871aa1e 100644 --- a/src/openrct2/management/NewsItem.h +++ b/src/openrct2/management/NewsItem.h @@ -65,7 +65,7 @@ constexpr int32_t MAX_NEWS_ITEMS = NEWS_ITEM_HISTORY_START + MAX_NEWS_ITEMS_ARCH extern const uint8_t news_type_properties[10]; -struct NewsItemQueue +struct NewsItemQueues { NewsItem& operator[](size_t index); const NewsItem& operator[](size_t index) const; @@ -110,7 +110,7 @@ private: NewsItem Archived[MAX_NEWS_ITEMS_ARCHIVE]; }; -extern NewsItemQueue gNewsItems; +extern NewsItemQueues gNewsItems; void news_item_init_queue(); From 8c33bccc86407265242490930eb574022911b2b6 Mon Sep 17 00:00:00 2001 From: hdpoliveira Date: Sun, 31 May 2020 17:40:42 -0300 Subject: [PATCH 2/2] Create NewsItemQueue --- src/openrct2/management/NewsItem.cpp | 82 ++++------------- src/openrct2/management/NewsItem.h | 126 +++++++++++++++++++++++++-- 2 files changed, 138 insertions(+), 70 deletions(-) diff --git a/src/openrct2/management/NewsItem.cpp b/src/openrct2/management/NewsItem.cpp index 534886b923..43caec61e2 100644 --- a/src/openrct2/management/NewsItem.cpp +++ b/src/openrct2/management/NewsItem.cpp @@ -41,22 +41,12 @@ const uint8_t news_type_properties[] = { NewsItem& NewsItemQueues::Current() { - return Recent[0]; + return Recent.front(); } const NewsItem& NewsItemQueues::Current() const { - return Recent[0]; -} - -NewsItem& NewsItemQueues::Oldest() -{ - return Archived[0]; -} - -const NewsItem& NewsItemQueues::Oldest() const -{ - return Archived[0]; + return Recent.front(); } bool news_item_is_valid_idx(int32_t index) @@ -81,10 +71,10 @@ NewsItem& NewsItemQueues::operator[](size_t index) const NewsItem& NewsItemQueues::operator[](size_t index) const { - if (index < NEWS_ITEM_HISTORY_START) + if (index < Recent.capacity()) return Recent[index]; else - return Archived[index - NEWS_ITEM_HISTORY_START]; + return Archived[index - Recent.capacity()]; } NewsItem* NewsItemQueues::At(int32_t index) @@ -117,23 +107,15 @@ bool news_item_is_queue_empty() bool NewsItemQueues::IsEmpty() const { - return Current().IsEmpty(); + return Recent.empty(); } /** * * rct2: 0x0066DF32 */ -void NewsItemQueues::Init() -{ - Current().Type = NEWS_ITEM_NULL; - Oldest().Type = NEWS_ITEM_NULL; -} - void news_item_init_queue() { - gNewsItems.Init(); - // Throttles for warning types (PEEP_*_WARNING) for (auto& warningThrottle : gPeepWarningThrottle) { @@ -210,41 +192,19 @@ void NewsItemQueues::ArchiveCurrent() if (IsEmpty()) return; - AppendToArchive(Current()); + Archived.push_back(Current()); // Invalidate the news window window_invalidate_by_class(WC_RECENT_NEWS); // Dequeue the current news item, shift news up - memmove(Recent, Recent + 1, sizeof(NewsItem) * (std::size(Recent) - 1)); - Recent[NEWS_ITEM_HISTORY_START - 1].Type = NEWS_ITEM_NULL; + Recent.pop_front(); // Invalidate current news item bar auto intent = Intent(INTENT_ACTION_INVALIDATE_TICKER_NEWS); context_broadcast_intent(&intent); } -/** - * Finds a spare history slot or replaces an existing one if there are no spare - * slots available. - */ -void NewsItemQueues::AppendToArchive(NewsItem& item) -{ - auto it = std::find_if(std::begin(Archived), std::end(Archived), [](const auto& newsItem) { return newsItem.IsEmpty(); }); - if (it != std::end(Archived)) - { - *it = item; - ++it; - if (it != std::end(Archived)) - it->Type = NEWS_ITEM_NULL; - return; - } - - // Dequeue the first history news item, shift history up - memmove(Archived, Archived + 1, sizeof(NewsItem) * (std::size(Archived) - 1)); - Archived[MAX_NEWS_ITEMS_ARCHIVE - 1] = item; -} - /** * Get the (x,y,z) coordinates of the subject of a news item. * If the new item is no longer valid, return LOCATION_NULL in the x-coordinate @@ -341,15 +301,18 @@ std::optional news_item_get_subject_location(int32_t type, int32_t su NewsItem* NewsItemQueues::FirstOpenOrNewSlot() { - auto it = std::begin(Recent); - for (; !it->IsEmpty();) + for (auto emptySlots = Recent.capacity() - Recent.size(); emptySlots < 2; ++emptySlots) { - if (it + 2 >= std::end(Recent)) - ArchiveCurrent(); - else - it++; + ArchiveCurrent(); } - return &*it; + + auto res = Recent.end(); + // The for loop above guarantees there is always an extra element to use + assert(Recent.capacity() - Recent.size() >= 2); + auto newsItem = res + 1; + newsItem->Type = NEWS_ITEM_NULL; + + return &*res; } /** @@ -377,14 +340,7 @@ NewsItem* news_item_add_to_queue_raw(uint8_t type, const utf8* text, uint32_t as newsItem->Day = ((days_in_month[date_get_month(newsItem->MonthYear)] * gDateMonthTicks) >> 16) + 1; safe_strcpy(newsItem->Text, text, sizeof(newsItem->Text)); - NewsItem* res = newsItem; - - // Blatant disregard for what happens on the last element. - // TODO: Change this when we implement the queue ourselves. - newsItem++; - newsItem->Type = NEWS_ITEM_NULL; - - return res; + return newsItem; } /** @@ -506,8 +462,6 @@ void news_item_add_to_queue_custom(NewsItem* newNewsItem) { NewsItem* newsItem = gNewsItems.FirstOpenOrNewSlot(); *newsItem = *newNewsItem; - newsItem++; - newsItem->Type = NEWS_ITEM_NULL; } void news_item_remove(int32_t index) diff --git a/src/openrct2/management/NewsItem.h b/src/openrct2/management/NewsItem.h index afc871aa1e..3367036cfc 100644 --- a/src/openrct2/management/NewsItem.h +++ b/src/openrct2/management/NewsItem.h @@ -12,6 +12,8 @@ #include "../common.h" #include "../world/Location.hpp" +#include +#include #include enum @@ -65,6 +67,122 @@ constexpr int32_t MAX_NEWS_ITEMS = NEWS_ITEM_HISTORY_START + MAX_NEWS_ITEMS_ARCH extern const uint8_t news_type_properties[10]; +template class NewsItemQueue +{ +public: + static_assert(N > 0, "Cannot instantiate NewsItemQueue with size=0"); + + using value_type = typename std::array::value_type; + using pointer = value_type*; + using const_pointer = const value_type*; + using reference = value_type&; + using const_reference = const value_type&; + using iterator = typename std::array::iterator; + using const_iterator = typename std::array::const_iterator; + using size_type = std::size_t; + using difference_type = std::ptrdiff_t; + using reverse_iterator = std::reverse_iterator; + using const_reverse_iterator = std::reverse_iterator; + + NewsItemQueue() + { + Queue[0].Type = NEWS_ITEM_NULL; + } + + constexpr iterator begin() noexcept + { + return std::begin(Queue); + } + constexpr const_iterator begin() const noexcept + { + return cbegin(); + } + constexpr const_iterator cbegin() const noexcept + { + return std::cbegin(Queue); + } + iterator end() noexcept + { + return std::find_if(std::begin(Queue), std::end(Queue), [](const_reference item) { return item.IsEmpty(); }); + } + const_iterator end() const noexcept + { + return cend(); + } + const_iterator cend() const noexcept + { + return std::find_if(std::cbegin(Queue), std::cend(Queue), [](const_reference item) { return item.IsEmpty(); }); + } + + constexpr bool empty() const noexcept + { + return Queue[0].IsEmpty(); + } + + size_type size() const noexcept + { + return std::distance(cbegin(), cend()); + } + + reference front() noexcept + { + return *begin(); + } + const_reference front() const noexcept + { + return *cbegin(); + } + reference back() noexcept + { + return *end(); + } + const_reference back() const noexcept + { + return *cend(); + } + + void pop_front() + { + std::move(std::begin(Queue) + 1, std::end(Queue), std::begin(Queue)); + Queue[N - 1].Type = NEWS_ITEM_NULL; + } + + void push_back(const_reference item) + { + auto it = end(); + if (!std::distance(it, std::end(Queue))) + { + // Reached queue max size, need to free some space + pop_front(); + Queue[N - 1] = item; + } + else + { + *it = item; + ++it; + if (std::distance(it, std::end(Queue))) + it->Type = NEWS_ITEM_NULL; + } + } + + reference operator[](size_type n) noexcept + { + return Queue[n]; + } + const_reference operator[](size_type n) const noexcept + { + return Queue[n]; + } + + constexpr size_type capacity() const noexcept + { + return N; + } + +private: + std::array Queue; +}; + struct NewsItemQueues { NewsItem& operator[](size_t index); @@ -86,8 +204,6 @@ struct NewsItemQueues { for (auto& newsItem : Recent) { - if (newsItem.IsEmpty()) - break; p(newsItem); } } @@ -96,8 +212,6 @@ struct NewsItemQueues { for (auto& newsItem : Archived) { - if (newsItem.IsEmpty()) - break; p(newsItem); } } @@ -106,8 +220,8 @@ private: int32_t RemoveTime() const; void AppendToArchive(NewsItem& item); - NewsItem Recent[NEWS_ITEM_HISTORY_START]; - NewsItem Archived[MAX_NEWS_ITEMS_ARCHIVE]; + NewsItemQueue Recent; + NewsItemQueue Archived; }; extern NewsItemQueues gNewsItems;