Reduced memory allocations by wifiscanmenu by reusing removed menu entries from a pool

This commit is contained in:
2021-01-03 00:57:22 +01:00
parent 67bb5554e4
commit 894644001b
2 changed files with 53 additions and 66 deletions

View File

@ -42,9 +42,12 @@ public:
}
template<typename T, typename... Args>
void constructItem(Args&&... args)
T &constructItem(Args&&... args)
{
emplaceItem(std::make_unique<T>(std::forward<Args>(args)...));
auto ptr = std::make_unique<T>(std::forward<Args>(args)...);
T &ref = *ptr;
emplaceItem(std::move(ptr));
return ref;
}
void emplaceItem(std::unique_ptr<MenuItem> &&ptr)
@ -57,6 +60,16 @@ public:
m_items.clear();
}
std::unique_ptr<MenuItem> takeLast()
{
if (m_items.empty())
throw "aua";
std::unique_ptr<MenuItem> ptr = std::move(m_items.back());
m_items.pop_back();
return ptr;
}
private:
std::vector<std::unique_ptr<MenuItem>> m_items;
};

View File

@ -1,14 +1,12 @@
#pragma once
// system includes
#include <vector>
// Arduino includes
#include <Arduino.h>
#include <WiFi.h>
// local includes
#include "menudisplay.h"
#include "containermenudefinition.h"
#include "utils.h"
#include "actions/multiaction.h"
#include "actions/switchscreenaction.h"
@ -23,7 +21,7 @@ class WifiSettingsMenu;
} // namespace
namespace {
class WifiScanMenu : public MenuDisplay, public BackActionInterface<SwitchScreenAction<WifiSettingsMenu>>
class WifiScanMenu : public MenuDisplay, public BackActionInterface<SwitchScreenAction<WifiSettingsMenu>>, public ContainerMenuDefinition
{
using Base = MenuDisplay;
@ -34,55 +32,15 @@ public:
void update() override;
void stop() override;
std::size_t size() const override { return 1 + vec.size(); }
MenuItem& getMenuItem(std::size_t index) override
{
if (index < vec.size())
return vec[index];
if (index == vec.size())
return m_backItem;
throw "aua";
}
const MenuItem& getMenuItem(std::size_t index) const override
{
if (index < vec.size())
return vec[index];
if (index == vec.size())
return m_backItem;
throw "aua";
}
void runForEveryMenuItem(std::function<void(MenuItem&)> &&callback) override
{
for (auto &item : vec)
callback(item);
callback(m_backItem);
}
void runForEveryMenuItem(std::function<void(const MenuItem&)> &&callback) const override
{
for (auto &item : vec)
callback(item);
callback(m_backItem);
}
private:
makeComponent<MenuItem, StaticText<TEXT_BACK>, SwitchScreenAction<WifiSettingsMenu>, StaticMenuItemIcon<&icons::back>> m_backItem;
std::vector<makeComponent<MenuItem, ChangeableText, DummyAction>> vec;
millis_t m_lastScanComplete;
std::vector<std::unique_ptr<makeComponent<MenuItem, ChangeableText, DummyAction>>> m_reusableItems;
};
String WifiScanMenu::text() const
{
auto text = String{vec.size()} + " found";
auto text = String{size()-1} + " found";
switch (WiFi.scanComplete())
{
case WIFI_SCAN_RUNNING: text += " (scanning)"; break;
@ -93,6 +51,8 @@ String WifiScanMenu::text() const
void WifiScanMenu::start()
{
constructItem<makeComponent<MenuItem, StaticText<TEXT_BACK>, SwitchScreenAction<WifiSettingsMenu>, StaticMenuItemIcon<&icons::back>>>();
Base::start();
m_lastScanComplete = 0;
@ -105,26 +65,40 @@ void WifiScanMenu::update()
const auto n = WiFi.scanComplete();
if (n >= 0)
{
if (n != vec.size())
{
while (n > vec.size())
{
vec.emplace_back();
vec.back().start();
}
while (n < vec.size())
{
vec.back().stop();
vec.pop_back();
}
}
const auto now = millis();
if (!m_lastScanComplete)
{
for (auto iter = std::begin(vec); iter != std::end(vec); iter++)
iter->setTitle(WiFi.SSID(std::distance(std::begin(vec), iter)));
auto backButton = takeLast();
for (std::size_t i = 0; i < n; i++)
{
const auto ssid = WiFi.SSID(i);
if (size() <= i)
{
if (m_reusableItems.empty())
{
auto &item = constructItem<makeComponent<MenuItem, ChangeableText, DummyAction>>();
item.setTitle(ssid);
}
else
{
std::unique_ptr<makeComponent<MenuItem, ChangeableText, DummyAction>> ptr = std::move(m_reusableItems.back());
m_reusableItems.pop_back();
ptr->setTitle(ssid);
emplaceItem(std::move(ptr));
}
}
else
{
auto &item = *(makeComponent<MenuItem, ChangeableText, DummyAction>*)(&getMenuItem(i));
item.setTitle(ssid);
}
}
while (size() > n)
m_reusableItems.emplace_back((makeComponent<MenuItem, ChangeableText, DummyAction>*)takeLast().release());
emplaceItem(std::move(backButton));
m_lastScanComplete = now;
}