diff --git a/ntcore/src/main/native/cpp/InstanceImpl.cpp b/ntcore/src/main/native/cpp/InstanceImpl.cpp index bbeff6ff77..3fef3563bd 100644 --- a/ntcore/src/main/native/cpp/InstanceImpl.cpp +++ b/ntcore/src/main/native/cpp/InstanceImpl.cpp @@ -174,3 +174,15 @@ std::shared_ptr InstanceImpl::GetClient() { std::scoped_lock lock{m_mutex}; return m_networkClient; } + +void InstanceImpl::Reset() { + std::scoped_lock lock{m_mutex}; + m_networkServer.reset(); + m_networkClient.reset(); + m_servers.clear(); + networkMode = NT_NET_MODE_NONE; + + listenerStorage.Reset(); + // connectionList should have been cleared by destroying networkClient/server + localStorage.Reset(); +} diff --git a/ntcore/src/main/native/cpp/InstanceImpl.h b/ntcore/src/main/native/cpp/InstanceImpl.h index 4b916690a8..6d250c54fe 100644 --- a/ntcore/src/main/native/cpp/InstanceImpl.h +++ b/ntcore/src/main/native/cpp/InstanceImpl.h @@ -56,6 +56,8 @@ class InstanceImpl { std::shared_ptr GetServer(); std::shared_ptr GetClient(); + void Reset(); + ListenerStorage listenerStorage; LoggerImpl logger_impl; wpi::Logger logger; diff --git a/ntcore/src/main/native/cpp/ListenerStorage.cpp b/ntcore/src/main/native/cpp/ListenerStorage.cpp index b19e871ba5..301934b36e 100644 --- a/ntcore/src/main/native/cpp/ListenerStorage.cpp +++ b/ntcore/src/main/native/cpp/ListenerStorage.cpp @@ -320,6 +320,19 @@ bool ListenerStorage::WaitForListenerQueue(double timeout) { return wpi::WaitForObject(h, timeout, &timedOut); } +void ListenerStorage::Reset() { + std::scoped_lock lock{m_mutex}; + m_pollers.clear(); + m_listeners.clear(); + m_connListeners.clear(); + m_topicListeners.clear(); + m_valueListeners.clear(); + m_logListeners.clear(); + if (m_thread) { + m_thread.Stop(); + } +} + std::vector> ListenerStorage::DoRemoveListeners(std::span handles) { std::vector> rv; diff --git a/ntcore/src/main/native/cpp/ListenerStorage.h b/ntcore/src/main/native/cpp/ListenerStorage.h index 654d7fd5fe..bbea074756 100644 --- a/ntcore/src/main/native/cpp/ListenerStorage.h +++ b/ntcore/src/main/native/cpp/ListenerStorage.h @@ -59,6 +59,8 @@ class ListenerStorage final : public IListenerStorage { bool WaitForListenerQueue(double timeout); + void Reset(); + private: // these assume the mutex is already held NT_Listener DoAddListener(NT_ListenerPoller pollerHandle); diff --git a/ntcore/src/main/native/cpp/LocalStorage.cpp b/ntcore/src/main/native/cpp/LocalStorage.cpp index 2145011492..04b9398c1e 100644 --- a/ntcore/src/main/native/cpp/LocalStorage.cpp +++ b/ntcore/src/main/native/cpp/LocalStorage.cpp @@ -2187,3 +2187,9 @@ void LocalStorage::StopDataLog(NT_DataLogger logger) { } } } + +void LocalStorage::Reset() { + std::scoped_lock lock{m_mutex}; + m_impl = std::make_unique(m_impl->m_inst, m_impl->m_listenerStorage, + m_impl->m_logger); +} diff --git a/ntcore/src/main/native/cpp/LocalStorage.h b/ntcore/src/main/native/cpp/LocalStorage.h index e2b770a1fe..8205da3f01 100644 --- a/ntcore/src/main/native/cpp/LocalStorage.h +++ b/ntcore/src/main/native/cpp/LocalStorage.h @@ -209,6 +209,8 @@ class LocalStorage final : public net::ILocalStorage { std::string_view logPrefix); void StopDataLog(NT_DataLogger logger); + void Reset(); + private: class Impl; std::unique_ptr m_impl; diff --git a/ntcore/src/main/native/cpp/ntcore_cpp.cpp b/ntcore/src/main/native/cpp/ntcore_cpp.cpp index 512ceeccc4..fd8d323844 100644 --- a/ntcore/src/main/native/cpp/ntcore_cpp.cpp +++ b/ntcore/src/main/native/cpp/ntcore_cpp.cpp @@ -45,6 +45,12 @@ NT_Inst CreateInstance() { return Handle{InstanceImpl::Alloc(), 0, Handle::kInstance}; } +void ResetInstance(NT_Inst inst) { + if (auto ii = InstanceImpl::GetTyped(inst, Handle::kInstance)) { + ii->Reset(); + } +} + void DestroyInstance(NT_Inst inst) { int i = Handle{inst}.GetTypedInst(Handle::kInstance); if (i < 0) { diff --git a/ntcore/src/main/native/include/ntcore_cpp.h b/ntcore/src/main/native/include/ntcore_cpp.h index 1dd33aea3b..1b1e4717cf 100644 --- a/ntcore/src/main/native/include/ntcore_cpp.h +++ b/ntcore/src/main/native/include/ntcore_cpp.h @@ -348,6 +348,13 @@ NT_Inst GetDefaultInstance(); */ NT_Inst CreateInstance(); +/** + * Reset the internals of an instance. Every handle previously associated + * with this instance will no longer be valid, except for the instance + * handle. + */ +void ResetInstance(NT_Inst inst); + /** * Destroy an instance. * The default instance cannot be destroyed. diff --git a/ntcore/src/test/native/cpp/NetworkTableTest.cpp b/ntcore/src/test/native/cpp/NetworkTableTest.cpp index 73c4786238..aa28afd664 100644 --- a/ntcore/src/test/native/cpp/NetworkTableTest.cpp +++ b/ntcore/src/test/native/cpp/NetworkTableTest.cpp @@ -89,3 +89,15 @@ TEST_F(NetworkTableTest, EmptyOrNoSlash) { ASSERT_TRUE(inst.GetEntry("/testkey").Exists()); nt::NetworkTableInstance::Destroy(inst); } + +TEST_F(NetworkTableTest, ResetInstance) { + auto inst = nt::NetworkTableInstance::Create(); + auto nt = inst.GetTable("containskey"); + ASSERT_FALSE(nt->ContainsKey("testkey")); + nt->PutNumber("testkey", 5); + ASSERT_TRUE(nt->ContainsKey("testkey")); + ASSERT_TRUE(inst.GetEntry("/containskey/testkey").Exists()); + nt::ResetInstance(inst.GetHandle()); + ASSERT_FALSE(nt->ContainsKey("testkey")); + nt::NetworkTableInstance::Destroy(inst); +}