diff --git a/ntcore/src/main/native/cpp/networktables/NetworkTable.cpp b/ntcore/src/main/native/cpp/networktables/NetworkTable.cpp index d3b73f7016..1ec0942a62 100644 --- a/ntcore/src/main/native/cpp/networktables/NetworkTable.cpp +++ b/ntcore/src/main/native/cpp/networktables/NetworkTable.cpp @@ -194,6 +194,7 @@ NetworkTable::NetworkTable(NT_Inst inst, const Twine& path, const private_init&) NetworkTable::~NetworkTable() { for (auto& i : m_listeners) RemoveEntryListener(i.second); + for (auto i : m_lambdaListeners) RemoveEntryListener(i); } NetworkTableInstance NetworkTable::GetInstance() const { @@ -297,6 +298,40 @@ void NetworkTable::AddSubTableListener(ITableListener* listener) { AddSubTableListener(listener, false); } +NT_EntryListener NetworkTable::AddSubTableListener(TableListener listener, + bool localNotify) { + size_t prefix_len = m_path.size() + 1; + + // The lambda needs to be copyable, but StringMap is not, so use + // a shared_ptr to it. + auto notified_tables = std::make_shared>(); + + unsigned int flags = NT_NOTIFY_NEW | NT_NOTIFY_IMMEDIATE; + if (localNotify) flags |= NT_NOTIFY_LOCAL; + NT_EntryListener id = nt::AddEntryListener( + m_inst, m_path + Twine(PATH_SEPARATOR_CHAR), + [=](const EntryNotification& event) { + StringRef relative_key = event.name.substr(prefix_len); + auto end_sub_table = relative_key.find(PATH_SEPARATOR_CHAR); + if (end_sub_table == StringRef::npos) return; + StringRef sub_table_key = relative_key.substr(0, end_sub_table); + if (notified_tables->find(sub_table_key) == notified_tables->end()) + return; + notified_tables->insert(std::make_pair(sub_table_key, '\0')); + listener(this, sub_table_key, this->GetSubTable(sub_table_key)); + }, + flags); + m_lambdaListeners.emplace_back(id); + return id; +} + +void NetworkTable::RemoveTableListener(NT_EntryListener listener) { + nt::RemoveEntryListener(listener); + auto matches_begin = + std::remove(m_lambdaListeners.begin(), m_lambdaListeners.end(), listener); + m_lambdaListeners.erase(matches_begin, m_lambdaListeners.end()); +} + void NetworkTable::AddSubTableListener(ITableListener* listener, bool localNotify) { std::lock_guard lock(m_mutex); diff --git a/ntcore/src/main/native/include/networktables/NetworkTable.h b/ntcore/src/main/native/include/networktables/NetworkTable.h index 8e664e770c..6bc2af6c92 100644 --- a/ntcore/src/main/native/include/networktables/NetworkTable.h +++ b/ntcore/src/main/native/include/networktables/NetworkTable.h @@ -56,6 +56,7 @@ class NetworkTable final : public ITable { mutable wpi::StringMap m_entries; typedef std::pair Listener; std::vector m_listeners; + std::vector m_lambdaListeners; static std::vector s_ip_addresses; static std::string s_persistent_filename; @@ -338,14 +339,14 @@ class NetworkTable final : public ITable { * @return Listener handle */ NT_EntryListener AddSubTableListener(TableListener listener, - bool localNotify = false) const; + bool localNotify = false); /** * Remove a sub-table listener. * * @param listener listener handle */ - void RemoveTableListener(NT_EntryListener listener) const; + void RemoveTableListener(NT_EntryListener listener); WPI_DEPRECATED( "use AddEntryListener() instead with flags value of NT_NOTIFY_NEW | " diff --git a/ntcore/src/main/native/include/networktables/TableListener.h b/ntcore/src/main/native/include/networktables/TableListener.h index 4353174e51..9940badd75 100644 --- a/ntcore/src/main/native/include/networktables/TableListener.h +++ b/ntcore/src/main/native/include/networktables/TableListener.h @@ -31,7 +31,7 @@ using wpi::StringRef; * @ingroup ntcore_cpp_api */ typedef std::function + std::shared_ptr table)> TableListener; } // namespace nt