From 4ce8f3f9352645426a5fc03bbb0f41ca653e2c7e Mon Sep 17 00:00:00 2001 From: Thad House Date: Mon, 13 May 2024 05:35:14 -0700 Subject: [PATCH] Change C APIs to a unified string implementation (#6299) Currently in the entire C API of WPILib we have ~8 different ways of handling strings. The C API actually isn't built for pure C callers (We don't actually have any of those). Instead, they're built for interop between languages like LabVIEW and C# which can talk to C API's directly. For output parameters, the choice was fairly obvious. An output struct containing a const string pointer and a length makes the most sense. Its easy to use these from most other languages, and doesn't require special null termination handling. Freeing these is also easy, as if you ever receive one of these string structures, theres just a single function call to free it. Input parameters are a bit more complex. To be used from pure C, and from LabVIEW, a null terminated string is the best in most cases. However, null terminated strings in general have a lot of downsides. Additionally, from LabVIEW there are other considerations around encoding that having a wrapper struct helps make a bit easier. From a language like C#, a wrapper struct is by far the easiest, as custom marshalling can make it trivial to marshal both UTF8 and UTF16 strings down. The final consideration is its nice to have an identical concept for both input and output. It makes the rules fairly easy to understand. WPILib will not have any APIs that manipulate a string allocated externally. This means WPI_String can be const, as across the boundary it is always const. If a WPILib API takes a const WPI_String*, WPILib will not manipulate or attempt to free that string, and that string is treated as an input. It is up to the caller to handle that memory, WPILib will never hold onto that memory longer than the call. If a WPILib API takes a WPI_String*, that string is an output. WPILib will allocate that API with WPI_AllocateString(), fill in the string, and return to the caller. When the caller is done with the string, they must free it with WPI_FreeString(). If an output struct contains a WPI_String member, that member is considered read only, and should not be explicitly freed. The caller should call the free function for that struct. If an array of WPI_Strings are returned, each individual string is considered read only, and should not be explicitly freed. The free function for that array should be called by the caller. If an input struct containing a WPI_String, or an input array of WPI_Strings is passed to WPILib, the individual strings will not be manipulated or freed by WPILib, and the caller owns and should free that memory. Callbacks also follow these rules. The most common is a callback either getting passed a const WPI_String* or a struct containing a WPI_String. In both of these cases, the callback target should consider these strings read only, and not attempt to free them or manipulate them. --- .../native/cpp/ConfigurableSourceImpl.cpp | 24 +- cscore/src/main/native/cpp/HttpCameraImpl.cpp | 40 ++- .../src/main/native/cpp/MjpegServerImpl.cpp | 14 +- cscore/src/main/native/cpp/RawSinkImpl.cpp | 15 +- cscore/src/main/native/cpp/RawSourceImpl.cpp | 4 +- cscore/src/main/native/cpp/SinkImpl.cpp | 13 +- .../main/native/cpp/UsbCameraImplCommon.cpp | 52 ++-- cscore/src/main/native/cpp/c_util.h | 11 +- cscore/src/main/native/cpp/cscore_c.cpp | 155 +++++------ cscore/src/main/native/include/cscore_c.h | 134 +++++---- cscore/src/main/native/include/cscore_raw.h | 12 +- .../main/native/athena/FRCDriverStation.cpp | 19 +- hal/src/main/native/athena/HAL.cpp | 31 +-- .../athena/mockdata/DriverStationData.cpp | 6 +- .../native/athena/mockdata/RoboRioData.cpp | 18 +- .../main/native/cpp/jni/DriverStationJNI.cpp | 7 +- hal/src/main/native/cpp/jni/HALUtil.cpp | 16 +- .../jni/simulation/DriverStationDataJNI.cpp | 9 +- .../cpp/jni/simulation/RoboRioDataJNI.cpp | 23 +- .../main/native/include/hal/DriverStation.h | 16 +- hal/src/main/native/include/hal/HALBase.h | 14 +- .../hal/simulation/DriverStationData.h | 8 +- .../include/hal/simulation/RoboRioData.h | 10 +- hal/src/main/native/sim/DriverStation.cpp | 11 +- hal/src/main/native/sim/HAL.cpp | 9 +- .../native/sim/mockdata/DriverStationData.cpp | 48 ++-- .../sim/mockdata/DriverStationDataInternal.h | 6 +- .../main/native/sim/mockdata/RoboRioData.cpp | 53 ++-- .../native/sim/mockdata/RoboRioDataInternal.h | 8 +- .../main/native/cpp/ntcore_c_types.cpp.jinja | 29 +- .../native/include/ntcore_c_types.h.jinja | 15 +- ntcore/src/generate/types.json | 10 +- .../main/native/cpp/ntcore_c_types.cpp | 42 +-- .../main/native/include/ntcore_c_types.h | 35 +-- ntcore/src/main/native/cpp/Value.cpp | 31 +-- ntcore/src/main/native/cpp/Value_internal.h | 4 +- ntcore/src/main/native/cpp/ntcore_c.cpp | 254 ++++++++---------- ntcore/src/main/native/cpp/ntcore_cpp.cpp | 4 +- ntcore/src/main/native/cpp/ntcore_meta_c.cpp | 14 +- ntcore/src/main/native/cpp/ntcore_test.cpp | 27 +- .../networktables/NetworkTableInstance.h | 4 +- .../networktables/NetworkTableInstance.inc | 2 +- ntcore/src/main/native/include/ntcore_c.h | 231 ++++++---------- ntcore/src/main/native/include/ntcore_cpp.h | 6 +- ntcore/src/main/native/include/ntcore_test.h | 4 +- ntcore/src/test/native/cpp/ValueTest.cpp | 20 +- ntcoreffi/src/main/native/symbols.txt | 10 +- .../src/main/native/cpp/DriverStationGui.cpp | 3 +- .../native/cpp/WSProvider_DriverStation.cpp | 3 +- .../src/main/native/cpp/RobotController.cpp | 17 +- .../cpp/simulation/DriverStationSim.cpp | 9 +- .../main/native/cpp/simulation/RoboRioSim.cpp | 22 +- wpiutil/src/main/native/cpp/DataLog.cpp | 46 ++-- .../native/cpp/DataLogBackgroundWriter.cpp | 20 +- wpiutil/src/main/native/cpp/DataLogWriter.cpp | 10 +- wpiutil/src/main/native/cpp/string.cpp | 77 ++++++ wpiutil/src/main/native/include/wpi/DataLog.h | 3 +- .../src/main/native/include/wpi/DataLog_c.h | 56 ++-- .../src/main/native/include/wpi/jni_util.h | 2 + wpiutil/src/main/native/include/wpi/string.h | 108 ++++++++ 60 files changed, 990 insertions(+), 914 deletions(-) create mode 100644 wpiutil/src/main/native/cpp/string.cpp create mode 100644 wpiutil/src/main/native/include/wpi/string.h diff --git a/cscore/src/main/native/cpp/ConfigurableSourceImpl.cpp b/cscore/src/main/native/cpp/ConfigurableSourceImpl.cpp index 9f09eff050..e7e8721d9f 100644 --- a/cscore/src/main/native/cpp/ConfigurableSourceImpl.cpp +++ b/cscore/src/main/native/cpp/ConfigurableSourceImpl.cpp @@ -197,9 +197,9 @@ void SetSourceEnumPropertyChoices(CS_Source source, CS_Property property, } // namespace cs extern "C" { -void CS_NotifySourceError(CS_Source source, const char* msg, +void CS_NotifySourceError(CS_Source source, const struct WPI_String* msg, CS_Status* status) { - return cs::NotifySourceError(source, msg, status); + return cs::NotifySourceError(source, wpi::to_string_view(msg), status); } void CS_SetSourceConnected(CS_Source source, CS_Bool connected, @@ -207,17 +207,21 @@ void CS_SetSourceConnected(CS_Source source, CS_Bool connected, return cs::SetSourceConnected(source, connected, status); } -void CS_SetSourceDescription(CS_Source source, const char* description, +void CS_SetSourceDescription(CS_Source source, + const struct WPI_String* description, CS_Status* status) { - return cs::SetSourceDescription(source, description, status); + return cs::SetSourceDescription(source, wpi::to_string_view(description), + status); } -CS_Property CS_CreateSourceProperty(CS_Source source, const char* name, +CS_Property CS_CreateSourceProperty(CS_Source source, + const struct WPI_String* name, enum CS_PropertyKind kind, int minimum, int maximum, int step, int defaultValue, int value, CS_Status* status) { - return cs::CreateSourceProperty(source, name, kind, minimum, maximum, step, - defaultValue, value, status); + return cs::CreateSourceProperty(source, wpi::to_string_view(name), kind, + minimum, maximum, step, defaultValue, value, + status); } CS_Property CS_CreateSourcePropertyCallback( @@ -230,12 +234,12 @@ CS_Property CS_CreateSourcePropertyCallback( } void CS_SetSourceEnumPropertyChoices(CS_Source source, CS_Property property, - const char** choices, int count, - CS_Status* status) { + const struct WPI_String* choices, + int count, CS_Status* status) { wpi::SmallVector vec; vec.reserve(count); for (int i = 0; i < count; ++i) { - vec.push_back(choices[i]); + vec.emplace_back(wpi::to_string_view(&choices[i])); } return cs::SetSourceEnumPropertyChoices(source, property, vec, status); } diff --git a/cscore/src/main/native/cpp/HttpCameraImpl.cpp b/cscore/src/main/native/cpp/HttpCameraImpl.cpp index da60d77f29..05a5c90caf 100644 --- a/cscore/src/main/native/cpp/HttpCameraImpl.cpp +++ b/cscore/src/main/native/cpp/HttpCameraImpl.cpp @@ -634,55 +634,47 @@ std::vector GetHttpCameraUrls(CS_Source source, extern "C" { -CS_Source CS_CreateHttpCamera(const char* name, const char* url, +CS_Source CS_CreateHttpCamera(const struct WPI_String* name, + const struct WPI_String* url, CS_HttpCameraKind kind, CS_Status* status) { - return cs::CreateHttpCamera(name, url, kind, status); + return cs::CreateHttpCamera(wpi::to_string_view(name), + wpi::to_string_view(url), kind, status); } -CS_Source CS_CreateHttpCameraMulti(const char* name, const char** urls, - int count, CS_HttpCameraKind kind, - CS_Status* status) { +CS_Source CS_CreateHttpCameraMulti(const struct WPI_String* name, + const struct WPI_String* urls, int count, + CS_HttpCameraKind kind, CS_Status* status) { wpi::SmallVector vec; vec.reserve(count); for (int i = 0; i < count; ++i) { - vec.push_back(urls[i]); + vec.emplace_back(wpi::to_string_view(&urls[i])); } - return cs::CreateHttpCamera(name, vec, kind, status); + return cs::CreateHttpCamera(wpi::to_string_view(name), vec, kind, status); } CS_HttpCameraKind CS_GetHttpCameraKind(CS_Source source, CS_Status* status) { return cs::GetHttpCameraKind(source, status); } -void CS_SetHttpCameraUrls(CS_Source source, const char** urls, int count, - CS_Status* status) { +void CS_SetHttpCameraUrls(CS_Source source, const struct WPI_String* urls, + int count, CS_Status* status) { wpi::SmallVector vec; vec.reserve(count); for (int i = 0; i < count; ++i) { - vec.push_back(urls[i]); + vec.emplace_back(wpi::to_string_view(&urls[i])); } cs::SetHttpCameraUrls(source, vec, status); } -char** CS_GetHttpCameraUrls(CS_Source source, int* count, CS_Status* status) { +WPI_String* CS_GetHttpCameraUrls(CS_Source source, int* count, + CS_Status* status) { auto urls = cs::GetHttpCameraUrls(source, status); - char** out = - static_cast(wpi::safe_malloc(urls.size() * sizeof(char*))); + WPI_String* out = WPI_AllocateStringArray(urls.size()); *count = urls.size(); for (size_t i = 0; i < urls.size(); ++i) { - out[i] = cs::ConvertToC(urls[i]); + cs::ConvertToC(&out[i], urls[i]); } return out; } -void CS_FreeHttpCameraUrls(char** urls, int count) { - if (!urls) { - return; - } - for (int i = 0; i < count; ++i) { - std::free(urls[i]); - } - std::free(urls); -} - } // extern "C" diff --git a/cscore/src/main/native/cpp/MjpegServerImpl.cpp b/cscore/src/main/native/cpp/MjpegServerImpl.cpp index 6dd09847ec..f6f63d6673 100644 --- a/cscore/src/main/native/cpp/MjpegServerImpl.cpp +++ b/cscore/src/main/native/cpp/MjpegServerImpl.cpp @@ -1047,13 +1047,17 @@ int GetMjpegServerPort(CS_Sink sink, CS_Status* status) { extern "C" { -CS_Sink CS_CreateMjpegServer(const char* name, const char* listenAddress, - int port, CS_Status* status) { - return cs::CreateMjpegServer(name, listenAddress, port, status); +CS_Sink CS_CreateMjpegServer(const struct WPI_String* name, + const struct WPI_String* listenAddress, int port, + CS_Status* status) { + return cs::CreateMjpegServer(wpi::to_string_view(name), + wpi::to_string_view(listenAddress), port, + status); } -char* CS_GetMjpegServerListenAddress(CS_Sink sink, CS_Status* status) { - return ConvertToC(cs::GetMjpegServerListenAddress(sink, status)); +void CS_GetMjpegServerListenAddress(CS_Sink sink, WPI_String* listenAddress, + CS_Status* status) { + cs::ConvertToC(listenAddress, cs::GetMjpegServerListenAddress(sink, status)); } int CS_GetMjpegServerPort(CS_Sink sink, CS_Status* status) { diff --git a/cscore/src/main/native/cpp/RawSinkImpl.cpp b/cscore/src/main/native/cpp/RawSinkImpl.cpp index 74e7359093..bdbf2c1a9a 100644 --- a/cscore/src/main/native/cpp/RawSinkImpl.cpp +++ b/cscore/src/main/native/cpp/RawSinkImpl.cpp @@ -184,16 +184,17 @@ uint64_t GrabSinkFrameTimeout(CS_Sink sink, WPI_RawFrame& image, double timeout, } // namespace cs extern "C" { -CS_Sink CS_CreateRawSink(const char* name, CS_Bool isCv, CS_Status* status) { - return cs::CreateRawSink(name, isCv, status); +CS_Sink CS_CreateRawSink(const struct WPI_String* name, CS_Bool isCv, + CS_Status* status) { + return cs::CreateRawSink(wpi::to_string_view(name), isCv, status); } -CS_Sink CS_CreateRawSinkCallback(const char* name, CS_Bool isCv, void* data, - void (*processFrame)(void* data, - uint64_t time), - CS_Status* status) { +CS_Sink CS_CreateRawSinkCallback( + const struct WPI_String* name, CS_Bool isCv, void* data, + void (*processFrame)(void* data, uint64_t time), CS_Status* status) { return cs::CreateRawSinkCallback( - name, isCv, [=](uint64_t time) { processFrame(data, time); }, status); + wpi::to_string_view(name), isCv, + [=](uint64_t time) { processFrame(data, time); }, status); } uint64_t CS_GrabRawSinkFrame(CS_Sink sink, struct WPI_RawFrame* image, diff --git a/cscore/src/main/native/cpp/RawSourceImpl.cpp b/cscore/src/main/native/cpp/RawSourceImpl.cpp index 94da6d06aa..aad27b240e 100644 --- a/cscore/src/main/native/cpp/RawSourceImpl.cpp +++ b/cscore/src/main/native/cpp/RawSourceImpl.cpp @@ -53,9 +53,9 @@ void PutSourceFrame(CS_Source source, const WPI_RawFrame& image, } // namespace cs extern "C" { -CS_Source CS_CreateRawSource(const char* name, CS_Bool isCv, +CS_Source CS_CreateRawSource(const struct WPI_String* name, CS_Bool isCv, const CS_VideoMode* mode, CS_Status* status) { - return cs::CreateRawSource(name, isCv, + return cs::CreateRawSource(wpi::to_string_view(name), isCv, static_cast(*mode), status); } diff --git a/cscore/src/main/native/cpp/SinkImpl.cpp b/cscore/src/main/native/cpp/SinkImpl.cpp index 3d4e70cf9a..0897bb8d6a 100644 --- a/cscore/src/main/native/cpp/SinkImpl.cpp +++ b/cscore/src/main/native/cpp/SinkImpl.cpp @@ -242,18 +242,15 @@ void SetSinkEnabled(CS_Sink sink, bool enabled, CS_Status* status) { } // namespace cs extern "C" { -void CS_SetSinkDescription(CS_Sink sink, const char* description, +void CS_SetSinkDescription(CS_Sink sink, const struct WPI_String* description, CS_Status* status) { - return cs::SetSinkDescription(sink, description, status); + return cs::SetSinkDescription(sink, wpi::to_string_view(description), status); } -char* CS_GetSinkError(CS_Sink sink, CS_Status* status) { +void CS_GetSinkError(CS_Sink sink, struct WPI_String* error, + CS_Status* status) { wpi::SmallString<128> buf; - auto str = cs::GetSinkError(sink, buf, status); - if (*status != 0) { - return nullptr; - } - return cs::ConvertToC(str); + cs::ConvertToC(error, cs::GetSinkError(sink, buf, status)); } void CS_SetSinkEnabled(CS_Sink sink, CS_Bool enabled, CS_Status* status) { diff --git a/cscore/src/main/native/cpp/UsbCameraImplCommon.cpp b/cscore/src/main/native/cpp/UsbCameraImplCommon.cpp index 5731f1f1b6..81afcc1056 100644 --- a/cscore/src/main/native/cpp/UsbCameraImplCommon.cpp +++ b/cscore/src/main/native/cpp/UsbCameraImplCommon.cpp @@ -4,6 +4,8 @@ #include "cscore_c.h" // NOLINT(build/include_order) +#include + #include "c_util.h" #include "cscore_cpp.h" @@ -11,56 +13,53 @@ using namespace cs; static void ConvertToC(CS_UsbCameraInfo* out, const UsbCameraInfo& in) { out->dev = in.dev; - out->path = ConvertToC(in.path); - out->name = ConvertToC(in.name); - out->otherPaths = static_cast( - wpi::safe_malloc(in.otherPaths.size() * sizeof(char*))); + cs::ConvertToC(&out->path, in.path); + cs::ConvertToC(&out->name, in.name); + out->otherPaths = WPI_AllocateStringArray(in.otherPaths.size()); out->otherPathsCount = in.otherPaths.size(); for (size_t i = 0; i < in.otherPaths.size(); ++i) { - out->otherPaths[i] = cs::ConvertToC(in.otherPaths[i]); + cs::ConvertToC(&out->otherPaths[i], in.otherPaths[i]); } out->vendorId = in.vendorId; out->productId = in.productId; } static void FreeUsbCameraInfo(CS_UsbCameraInfo* info) { - std::free(info->path); - std::free(info->name); + WPI_FreeString(&info->path); + WPI_FreeString(&info->name); for (int i = 0; i < info->otherPathsCount; ++i) { - std::free(info->otherPaths[i]); + WPI_FreeString(&info->otherPaths[i]); } - std::free(info->otherPaths); } extern "C" { -CS_Source CS_CreateUsbCameraDev(const char* name, int dev, CS_Status* status) { - return cs::CreateUsbCameraDev(name, dev, status); +CS_Source CS_CreateUsbCameraDev(const struct WPI_String* name, int dev, + CS_Status* status) { + return cs::CreateUsbCameraDev(wpi::to_string_view(name), dev, status); } -CS_Source CS_CreateUsbCameraPath(const char* name, const char* path, +CS_Source CS_CreateUsbCameraPath(const struct WPI_String* name, + const struct WPI_String* path, CS_Status* status) { - return cs::CreateUsbCameraPath(name, path, status); + return cs::CreateUsbCameraPath(wpi::to_string_view(name), + wpi::to_string_view(path), status); } -void CS_SetUsbCameraPath(CS_Source source, const char* path, +void CS_SetUsbCameraPath(CS_Source source, const struct WPI_String* path, CS_Status* status) { - cs::SetUsbCameraPath(source, path, status); + cs::SetUsbCameraPath(source, wpi::to_string_view(path), status); } -char* CS_GetUsbCameraPath(CS_Source source, CS_Status* status) { - return ConvertToC(cs::GetUsbCameraPath(source, status)); +void CS_GetUsbCameraPath(CS_Source source, WPI_String* path, + CS_Status* status) { + ConvertToC(path, cs::GetUsbCameraPath(source, status)); } -CS_UsbCameraInfo* CS_GetUsbCameraInfo(CS_Source source, CS_Status* status) { - auto info = cs::GetUsbCameraInfo(source, status); - if (*status != CS_OK) { - return nullptr; - } - CS_UsbCameraInfo* out = static_cast( - wpi::safe_malloc(sizeof(CS_UsbCameraInfo))); - ConvertToC(out, info); - return out; +void CS_GetUsbCameraInfo(CS_Source source, CS_UsbCameraInfo* info, + CS_Status* status) { + auto info_cpp = cs::GetUsbCameraInfo(source, status); + ConvertToC(info, info_cpp); } CS_UsbCameraInfo* CS_EnumerateUsbCameras(int* count, CS_Status* status) { @@ -89,7 +88,6 @@ void CS_FreeUsbCameraInfo(CS_UsbCameraInfo* info) { return; } FreeUsbCameraInfo(info); - std::free(info); } } // extern "C" diff --git a/cscore/src/main/native/cpp/c_util.h b/cscore/src/main/native/cpp/c_util.h index 904d049ef6..a81f428716 100644 --- a/cscore/src/main/native/cpp/c_util.h +++ b/cscore/src/main/native/cpp/c_util.h @@ -5,19 +5,16 @@ #ifndef CSCORE_C_UTIL_H_ #define CSCORE_C_UTIL_H_ -#include #include #include -#include +#include namespace cs { -inline char* ConvertToC(std::string_view in) { - char* out = static_cast(wpi::safe_malloc(in.size() + 1)); - std::memmove(out, in.data(), in.size()); - out[in.size()] = '\0'; - return out; +inline void ConvertToC(struct WPI_String* output, std::string_view str) { + char* write = WPI_AllocateString(output, str.size()); + std::memcpy(write, str.data(), str.size()); } } // namespace cs diff --git a/cscore/src/main/native/cpp/cscore_c.cpp b/cscore/src/main/native/cpp/cscore_c.cpp index 4670dd4c8e..521a1ffa50 100644 --- a/cscore/src/main/native/cpp/cscore_c.cpp +++ b/cscore/src/main/native/cpp/cscore_c.cpp @@ -19,12 +19,12 @@ static CS_Event ConvertToC(const cs::RawEvent& rawEvent) { event.kind = static_cast(static_cast(rawEvent.kind)); event.source = rawEvent.sourceHandle; event.sink = rawEvent.sinkHandle; - event.name = rawEvent.name.c_str(); + cs::ConvertToC(&event.name, rawEvent.name); event.mode = rawEvent.mode; event.property = rawEvent.propertyHandle; event.propertyKind = rawEvent.propertyKind; event.value = rawEvent.value; - event.valueStr = rawEvent.valueStr.c_str(); + cs::ConvertToC(&event.name, rawEvent.valueStr); event.listener = rawEvent.listener; return event; } @@ -53,13 +53,10 @@ CS_PropertyKind CS_GetPropertyKind(CS_Property property, CS_Status* status) { return cs::GetPropertyKind(property, status); } -char* CS_GetPropertyName(CS_Property property, CS_Status* status) { +void CS_GetPropertyName(CS_Property property, WPI_String* name, + CS_Status* status) { wpi::SmallString<128> buf; - auto str = cs::GetPropertyName(property, buf, status); - if (*status != 0) { - return nullptr; - } - return cs::ConvertToC(str); + cs::ConvertToC(name, cs::GetPropertyName(property, buf, status)); } int CS_GetProperty(CS_Property property, CS_Status* status) { @@ -86,28 +83,24 @@ int CS_GetPropertyDefault(CS_Property property, CS_Status* status) { return cs::GetPropertyDefault(property, status); } -char* CS_GetStringProperty(CS_Property property, CS_Status* status) { - wpi::SmallString<128> buf; - auto str = cs::GetStringProperty(property, buf, status); - if (*status != 0) { - return nullptr; - } - return cs::ConvertToC(str); -} - -void CS_SetStringProperty(CS_Property property, const char* value, +void CS_GetStringProperty(CS_Property property, WPI_String* value, CS_Status* status) { - return cs::SetStringProperty(property, value, status); + wpi::SmallString<128> buf; + cs::ConvertToC(value, cs::GetStringProperty(property, buf, status)); } -char** CS_GetEnumPropertyChoices(CS_Property property, int* count, - CS_Status* status) { +void CS_SetStringProperty(CS_Property property, const struct WPI_String* value, + CS_Status* status) { + return cs::SetStringProperty(property, wpi::to_string_view(value), status); +} + +WPI_String* CS_GetEnumPropertyChoices(CS_Property property, int* count, + CS_Status* status) { auto choices = cs::GetEnumPropertyChoices(property, status); - char** out = - static_cast(wpi::safe_malloc(choices.size() * sizeof(char*))); + WPI_String* out = WPI_AllocateStringArray(choices.size()); *count = choices.size(); for (size_t i = 0; i < choices.size(); ++i) { - out[i] = cs::ConvertToC(choices[i]); + cs::ConvertToC(&out[i], choices[i]); } return out; } @@ -116,22 +109,15 @@ CS_SourceKind CS_GetSourceKind(CS_Source source, CS_Status* status) { return cs::GetSourceKind(source, status); } -char* CS_GetSourceName(CS_Source source, CS_Status* status) { +void CS_GetSourceName(CS_Source source, WPI_String* name, CS_Status* status) { wpi::SmallString<128> buf; - auto str = cs::GetSourceName(source, buf, status); - if (*status != 0) { - return nullptr; - } - return cs::ConvertToC(str); + cs::ConvertToC(name, cs::GetSourceName(source, buf, status)); } -char* CS_GetSourceDescription(CS_Source source, CS_Status* status) { +void CS_GetSourceDescription(CS_Source source, WPI_String* description, + CS_Status* status) { wpi::SmallString<128> buf; - auto str = cs::GetSourceDescription(source, buf, status); - if (*status != 0) { - return nullptr; - } - return cs::ConvertToC(str); + cs::ConvertToC(description, cs::GetSourceDescription(source, buf, status)); } uint64_t CS_GetSourceLastFrameTime(CS_Source source, CS_Status* status) { @@ -152,9 +138,10 @@ CS_Bool CS_IsSourceEnabled(CS_Source source, CS_Status* status) { return cs::IsSourceEnabled(source, status); } -CS_Property CS_GetSourceProperty(CS_Source source, const char* name, +CS_Property CS_GetSourceProperty(CS_Source source, + const struct WPI_String* name, CS_Status* status) { - return cs::GetSourceProperty(source, name, status); + return cs::GetSourceProperty(source, wpi::to_string_view(name), status); } CS_Property* CS_EnumerateSourceProperties(CS_Source source, int* count, @@ -209,13 +196,15 @@ CS_Bool CS_SetSourceFPS(CS_Source source, int fps, CS_Status* status) { return cs::SetSourceFPS(source, fps, status); } -CS_Bool CS_SetSourceConfigJson(CS_Source source, const char* config, +CS_Bool CS_SetSourceConfigJson(CS_Source source, + const struct WPI_String* config, CS_Status* status) { - return cs::SetSourceConfigJson(source, config, status); + return cs::SetSourceConfigJson(source, wpi::to_string_view(config), status); } -char* CS_GetSourceConfigJson(CS_Source source, CS_Status* status) { - return cs::ConvertToC(cs::GetSourceConfigJson(source, status)); +void CS_GetSourceConfigJson(CS_Source source, WPI_String* config, + CS_Status* status) { + cs::ConvertToC(config, cs::GetSourceConfigJson(source, status)); } CS_VideoMode* CS_EnumerateSourceVideoModes(CS_Source source, int* count, @@ -286,27 +275,20 @@ CS_SinkKind CS_GetSinkKind(CS_Sink sink, CS_Status* status) { return cs::GetSinkKind(sink, status); } -char* CS_GetSinkName(CS_Sink sink, CS_Status* status) { +void CS_GetSinkName(CS_Sink sink, WPI_String* name, CS_Status* status) { wpi::SmallString<128> buf; - auto str = cs::GetSinkName(sink, buf, status); - if (*status != 0) { - return nullptr; - } - return cs::ConvertToC(str); + cs::ConvertToC(name, cs::GetSinkName(sink, buf, status)); } -char* CS_GetSinkDescription(CS_Sink sink, CS_Status* status) { +void CS_GetSinkDescription(CS_Sink sink, WPI_String* description, + CS_Status* status) { wpi::SmallString<128> buf; - auto str = cs::GetSinkDescription(sink, buf, status); - if (*status != 0) { - return nullptr; - } - return cs::ConvertToC(str); + cs::ConvertToC(description, cs::GetSinkDescription(sink, buf, status)); } -CS_Property CS_GetSinkProperty(CS_Sink sink, const char* name, +CS_Property CS_GetSinkProperty(CS_Sink sink, const struct WPI_String* name, CS_Status* status) { - return cs::GetSinkProperty(sink, name, status); + return cs::GetSinkProperty(sink, wpi::to_string_view(name), status); } CS_Property* CS_EnumerateSinkProperties(CS_Sink sink, int* count, @@ -320,13 +302,13 @@ CS_Property* CS_EnumerateSinkProperties(CS_Sink sink, int* count, return out; } -CS_Bool CS_SetSinkConfigJson(CS_Sink sink, const char* config, +CS_Bool CS_SetSinkConfigJson(CS_Sink sink, const struct WPI_String* config, CS_Status* status) { - return cs::SetSinkConfigJson(sink, config, status); + return cs::SetSinkConfigJson(sink, wpi::to_string_view(config), status); } -char* CS_GetSinkConfigJson(CS_Sink sink, CS_Status* status) { - return cs::ConvertToC(cs::GetSinkConfigJson(sink, status)); +void CS_GetSinkConfigJson(CS_Sink sink, WPI_String* config, CS_Status* status) { + cs::ConvertToC(config, cs::GetSinkConfigJson(sink, status)); } void CS_SetSinkSource(CS_Sink sink, CS_Source source, CS_Status* status) { @@ -337,9 +319,10 @@ CS_Source CS_GetSinkSource(CS_Sink sink, CS_Status* status) { return cs::GetSinkSource(sink, status); } -CS_Property CS_GetSinkSourceProperty(CS_Sink sink, const char* name, +CS_Property CS_GetSinkSourceProperty(CS_Sink sink, + const struct WPI_String* name, CS_Status* status) { - return cs::GetSinkSourceProperty(sink, name, status); + return cs::GetSinkSourceProperty(sink, wpi::to_string_view(name), status); } CS_Sink CS_CopySink(CS_Sink sink, CS_Status* status) { @@ -360,7 +343,7 @@ void CS_SetListenerOnExit(void (*onExit)(void* data), void* data) { CS_Listener CS_AddListener(void* data, void (*callback)(void* data, const CS_Event* event), - int eventMask, int immediateNotify, + int eventMask, CS_Bool immediateNotify, CS_Status* status) { return cs::AddListener( [=](const cs::RawEvent& rawEvent) { @@ -435,8 +418,15 @@ double CS_GetTelemetryAverageValue(CS_Handle handle, CS_TelemetryKind kind, return cs::GetTelemetryAverageValue(handle, kind, status); } -void CS_SetLogger(CS_LogFunc func, unsigned int min_level) { - cs::SetLogger(func, min_level); +void CS_SetLogger(CS_LogFunc func, void* data, unsigned int min_level) { + cs::SetLogger( + [=](unsigned int level, const char* file, unsigned int line, + const char* msg) { + auto fileStr = wpi::make_string(file); + auto msgStr = wpi::make_string(msg); + func(data, level, &fileStr, line, &msgStr); + }, + min_level); } void CS_SetDefaultLogger(unsigned int min_level) { @@ -493,20 +483,6 @@ void CS_ReleaseEnumeratedSinks(CS_Sink* sinks, int count) { std::free(sinks); } -void CS_FreeString(char* str) { - std::free(str); -} - -void CS_FreeEnumPropertyChoices(char** choices, int count) { - if (!choices) { - return; - } - for (int i = 0; i < count; ++i) { - std::free(choices[i]); - } - std::free(choices); -} - void CS_FreeEnumeratedProperties(CS_Property* properties, int count) { std::free(properties); } @@ -515,29 +491,18 @@ void CS_FreeEnumeratedVideoModes(CS_VideoMode* modes, int count) { std::free(modes); } -char* CS_GetHostname(void) { - return cs::ConvertToC(cs::GetHostname()); +void CS_GetHostname(struct WPI_String* hostname) { + cs::ConvertToC(hostname, cs::GetHostname()); } -char** CS_GetNetworkInterfaces(int* count) { +WPI_String* CS_GetNetworkInterfaces(int* count) { auto interfaces = cs::GetNetworkInterfaces(); - char** out = - static_cast(wpi::safe_malloc(interfaces.size() * sizeof(char*))); + WPI_String* out = WPI_AllocateStringArray(interfaces.size()); *count = interfaces.size(); for (size_t i = 0; i < interfaces.size(); ++i) { - out[i] = cs::ConvertToC(interfaces[i]); + cs::ConvertToC(&out[i], interfaces[i]); } return out; } -void CS_FreeNetworkInterfaces(char** interfaces, int count) { - if (!interfaces) { - return; - } - for (int i = 0; i < count; ++i) { - std::free(interfaces[i]); - } - std::free(interfaces); -} - } // extern "C" diff --git a/cscore/src/main/native/include/cscore_c.h b/cscore/src/main/native/include/cscore_c.h index 45a334269a..60e66bf209 100644 --- a/cscore/src/main/native/include/cscore_c.h +++ b/cscore/src/main/native/include/cscore_c.h @@ -8,6 +8,7 @@ #include #include +#include #ifdef __cplusplus #include @@ -204,7 +205,7 @@ struct CS_Event { CS_Sink sink; // Source/sink/property name - const char* name; + struct WPI_String name; // Fields for CS_SOURCE_VIDEOMODE_CHANGED event CS_VideoMode mode; @@ -213,7 +214,7 @@ struct CS_Event { CS_Property property; enum CS_PropertyKind propertyKind; int value; - const char* valueStr; + struct WPI_String valueStr; // Listener that was triggered CS_Listener listener; @@ -224,10 +225,10 @@ struct CS_Event { */ typedef struct CS_UsbCameraInfo { int dev; - char* path; - char* name; + struct WPI_String path; + struct WPI_String name; int otherPathsCount; - char** otherPaths; + struct WPI_String* otherPaths; int vendorId; int productId; } CS_UsbCameraInfo; @@ -238,34 +239,40 @@ typedef struct CS_UsbCameraInfo { */ enum CS_PropertyKind CS_GetPropertyKind(CS_Property property, CS_Status* status); -char* CS_GetPropertyName(CS_Property property, CS_Status* status); +void CS_GetPropertyName(CS_Property property, struct WPI_String* name, + CS_Status* status); int CS_GetProperty(CS_Property property, CS_Status* status); void CS_SetProperty(CS_Property property, int value, CS_Status* status); int CS_GetPropertyMin(CS_Property property, CS_Status* status); int CS_GetPropertyMax(CS_Property property, CS_Status* status); int CS_GetPropertyStep(CS_Property property, CS_Status* status); int CS_GetPropertyDefault(CS_Property property, CS_Status* status); -char* CS_GetStringProperty(CS_Property property, CS_Status* status); -void CS_SetStringProperty(CS_Property property, const char* value, +void CS_GetStringProperty(CS_Property property, struct WPI_String* value, CS_Status* status); -char** CS_GetEnumPropertyChoices(CS_Property property, int* count, - CS_Status* status); +void CS_SetStringProperty(CS_Property property, const struct WPI_String* value, + CS_Status* status); +struct WPI_String* CS_GetEnumPropertyChoices(CS_Property property, int* count, + CS_Status* status); /** @} */ /** * @defgroup cscore_source_create_cfunc Source Creation Functions * @{ */ -CS_Source CS_CreateUsbCameraDev(const char* name, int dev, CS_Status* status); -CS_Source CS_CreateUsbCameraPath(const char* name, const char* path, +CS_Source CS_CreateUsbCameraDev(const struct WPI_String* name, int dev, + CS_Status* status); +CS_Source CS_CreateUsbCameraPath(const struct WPI_String* name, + const struct WPI_String* path, CS_Status* status); -CS_Source CS_CreateHttpCamera(const char* name, const char* url, +CS_Source CS_CreateHttpCamera(const struct WPI_String* name, + const struct WPI_String* url, enum CS_HttpCameraKind kind, CS_Status* status); -CS_Source CS_CreateHttpCameraMulti(const char* name, const char** urls, - int count, enum CS_HttpCameraKind kind, +CS_Source CS_CreateHttpCameraMulti(const struct WPI_String* name, + const struct WPI_String* urls, int count, + enum CS_HttpCameraKind kind, CS_Status* status); -CS_Source CS_CreateCvSource(const char* name, const CS_VideoMode* mode, - CS_Status* status); +CS_Source CS_CreateCvSource(const struct WPI_String* name, + const CS_VideoMode* mode, CS_Status* status); /** @} */ /** @@ -273,15 +280,18 @@ CS_Source CS_CreateCvSource(const char* name, const CS_VideoMode* mode, * @{ */ enum CS_SourceKind CS_GetSourceKind(CS_Source source, CS_Status* status); -char* CS_GetSourceName(CS_Source source, CS_Status* status); -char* CS_GetSourceDescription(CS_Source source, CS_Status* status); +void CS_GetSourceName(CS_Source source, struct WPI_String* name, + CS_Status* status); +void CS_GetSourceDescription(CS_Source source, struct WPI_String* description, + CS_Status* status); uint64_t CS_GetSourceLastFrameTime(CS_Source source, CS_Status* status); void CS_SetSourceConnectionStrategy(CS_Source source, enum CS_ConnectionStrategy strategy, CS_Status* status); CS_Bool CS_IsSourceConnected(CS_Source source, CS_Status* status); CS_Bool CS_IsSourceEnabled(CS_Source source, CS_Status* status); -CS_Property CS_GetSourceProperty(CS_Source source, const char* name, +CS_Property CS_GetSourceProperty(CS_Source source, + const struct WPI_String* name, CS_Status* status); CS_Property* CS_EnumerateSourceProperties(CS_Source source, int* count, CS_Status* status); @@ -299,9 +309,11 @@ CS_Bool CS_SetSourcePixelFormat(CS_Source source, CS_Bool CS_SetSourceResolution(CS_Source source, int width, int height, CS_Status* status); CS_Bool CS_SetSourceFPS(CS_Source source, int fps, CS_Status* status); -CS_Bool CS_SetSourceConfigJson(CS_Source source, const char* config, +CS_Bool CS_SetSourceConfigJson(CS_Source source, + const struct WPI_String* config, CS_Status* status); -char* CS_GetSourceConfigJson(CS_Source source, CS_Status* status); +void CS_GetSourceConfigJson(CS_Source source, struct WPI_String* config, + CS_Status* status); CS_VideoMode* CS_EnumerateSourceVideoModes(CS_Source source, int* count, CS_Status* status); CS_Sink* CS_EnumerateSourceSinks(CS_Source source, int* count, @@ -330,9 +342,12 @@ void CS_SetCameraExposureManual(CS_Source source, int value, CS_Status* status); * @defgroup cscore_usbcamera_cfunc UsbCamera Source Functions * @{ */ -void CS_SetUsbCameraPath(CS_Source source, const char* path, CS_Status* status); -char* CS_GetUsbCameraPath(CS_Source source, CS_Status* status); -CS_UsbCameraInfo* CS_GetUsbCameraInfo(CS_Source source, CS_Status* status); +void CS_SetUsbCameraPath(CS_Source source, const struct WPI_String* path, + CS_Status* status); +void CS_GetUsbCameraPath(CS_Source source, struct WPI_String* path, + CS_Status* status); +void CS_GetUsbCameraInfo(CS_Source source, CS_UsbCameraInfo* info, + CS_Status* status); /** @} */ /** @@ -341,38 +356,43 @@ CS_UsbCameraInfo* CS_GetUsbCameraInfo(CS_Source source, CS_Status* status); */ enum CS_HttpCameraKind CS_GetHttpCameraKind(CS_Source source, CS_Status* status); -void CS_SetHttpCameraUrls(CS_Source source, const char** urls, int count, - CS_Status* status); -char** CS_GetHttpCameraUrls(CS_Source source, int* count, CS_Status* status); +void CS_SetHttpCameraUrls(CS_Source source, const struct WPI_String* urls, + int count, CS_Status* status); +struct WPI_String* CS_GetHttpCameraUrls(CS_Source source, int* count, + CS_Status* status); /** @} */ /** * @defgroup cscore_frame_source_cfunc Frame Source Functions * @{ */ -void CS_NotifySourceError(CS_Source source, const char* msg, CS_Status* status); +void CS_NotifySourceError(CS_Source source, const struct WPI_String* msg, + CS_Status* status); void CS_SetSourceConnected(CS_Source source, CS_Bool connected, CS_Status* status); -void CS_SetSourceDescription(CS_Source source, const char* description, +void CS_SetSourceDescription(CS_Source source, + const struct WPI_String* description, CS_Status* status); -CS_Property CS_CreateSourceProperty(CS_Source source, const char* name, +CS_Property CS_CreateSourceProperty(CS_Source source, + const struct WPI_String* name, enum CS_PropertyKind kind, int minimum, int maximum, int step, int defaultValue, int value, CS_Status* status); void CS_SetSourceEnumPropertyChoices(CS_Source source, CS_Property property, - const char** choices, int count, - CS_Status* status); + const struct WPI_String* choices, + int count, CS_Status* status); /** @} */ /** * @defgroup cscore_sink_create_cfunc Sink Creation Functions * @{ */ -CS_Sink CS_CreateMjpegServer(const char* name, const char* listenAddress, - int port, CS_Status* status); -CS_Sink CS_CreateCvSink(const char* name, enum WPI_PixelFormat pixelFormat, - CS_Status* status); -CS_Sink CS_CreateCvSinkCallback(const char* name, +CS_Sink CS_CreateMjpegServer(const struct WPI_String* name, + const struct WPI_String* listenAddress, int port, + CS_Status* status); +CS_Sink CS_CreateCvSink(const struct WPI_String* name, + enum WPI_PixelFormat pixelFormat, CS_Status* status); +CS_Sink CS_CreateCvSinkCallback(const struct WPI_String* name, enum WPI_PixelFormat pixelFormat, void* data, void (*processFrame)(void* data, uint64_t time), CS_Status* status); @@ -383,18 +403,21 @@ CS_Sink CS_CreateCvSinkCallback(const char* name, * @{ */ enum CS_SinkKind CS_GetSinkKind(CS_Sink sink, CS_Status* status); -char* CS_GetSinkName(CS_Sink sink, CS_Status* status); -char* CS_GetSinkDescription(CS_Sink sink, CS_Status* status); -CS_Property CS_GetSinkProperty(CS_Sink sink, const char* name, +void CS_GetSinkName(CS_Sink sink, struct WPI_String* name, CS_Status* status); +void CS_GetSinkDescription(CS_Sink sink, struct WPI_String* description, + CS_Status* status); +CS_Property CS_GetSinkProperty(CS_Sink sink, const struct WPI_String* name, CS_Status* status); CS_Property* CS_EnumerateSinkProperties(CS_Sink sink, int* count, CS_Status* status); void CS_SetSinkSource(CS_Sink sink, CS_Source source, CS_Status* status); -CS_Property CS_GetSinkSourceProperty(CS_Sink sink, const char* name, +CS_Property CS_GetSinkSourceProperty(CS_Sink sink, + const struct WPI_String* name, CS_Status* status); -CS_Bool CS_SetSinkConfigJson(CS_Sink sink, const char* config, +CS_Bool CS_SetSinkConfigJson(CS_Sink sink, const struct WPI_String* config, CS_Status* status); -char* CS_GetSinkConfigJson(CS_Sink sink, CS_Status* status); +void CS_GetSinkConfigJson(CS_Sink sink, struct WPI_String* config, + CS_Status* status); CS_Source CS_GetSinkSource(CS_Sink sink, CS_Status* status); CS_Sink CS_CopySink(CS_Sink sink, CS_Status* status); void CS_ReleaseSink(CS_Sink sink, CS_Status* status); @@ -404,7 +427,9 @@ void CS_ReleaseSink(CS_Sink sink, CS_Status* status); * @defgroup cscore_mjpegserver_cfunc MjpegServer Sink Functions * @{ */ -char* CS_GetMjpegServerListenAddress(CS_Sink sink, CS_Status* status); +void CS_GetMjpegServerListenAddress(CS_Sink sink, + struct WPI_String* listenAddress, + CS_Status* status); int CS_GetMjpegServerPort(CS_Sink sink, CS_Status* status); /** @} */ @@ -412,9 +437,9 @@ int CS_GetMjpegServerPort(CS_Sink sink, CS_Status* status); * @defgroup cscore_frame_sink_cfunc Frame Sink Functions * @{ */ -void CS_SetSinkDescription(CS_Sink sink, const char* description, +void CS_SetSinkDescription(CS_Sink sink, const struct WPI_String* description, CS_Status* status); -char* CS_GetSinkError(CS_Sink sink, CS_Status* status); +void CS_GetSinkError(CS_Sink sink, struct WPI_String* error, CS_Status* status); void CS_SetSinkEnabled(CS_Sink sink, CS_Bool enabled, CS_Status* status); /** @} */ @@ -459,9 +484,10 @@ double CS_GetTelemetryAverageValue(CS_Handle handle, enum CS_TelemetryKind kind, * @defgroup cscore_logging_cfunc Logging Functions * @{ */ -typedef void (*CS_LogFunc)(unsigned int level, const char* file, - unsigned int line, const char* msg); -void CS_SetLogger(CS_LogFunc func, unsigned int min_level); +typedef void (*CS_LogFunc)(void* data, unsigned int level, + const struct WPI_String* file, unsigned int line, + const struct WPI_String* msg); +void CS_SetLogger(CS_LogFunc func, void* data, unsigned int min_level); void CS_SetDefaultLogger(unsigned int min_level); /** @} */ @@ -486,18 +512,14 @@ void CS_ReleaseEnumeratedSources(CS_Source* sources, int count); CS_Sink* CS_EnumerateSinks(int* count, CS_Status* status); void CS_ReleaseEnumeratedSinks(CS_Sink* sinks, int count); -void CS_FreeString(char* str); -void CS_FreeEnumPropertyChoices(char** choices, int count); void CS_FreeUsbCameraInfo(CS_UsbCameraInfo* info); -void CS_FreeHttpCameraUrls(char** urls, int count); void CS_FreeEnumeratedProperties(CS_Property* properties, int count); void CS_FreeEnumeratedVideoModes(CS_VideoMode* modes, int count); -char* CS_GetHostname(void); +void CS_GetHostname(struct WPI_String* hostName); -char** CS_GetNetworkInterfaces(int* count); -void CS_FreeNetworkInterfaces(char** interfaces, int count); +struct WPI_String* CS_GetNetworkInterfaces(int* count); /** @} */ /** @} */ diff --git a/cscore/src/main/native/include/cscore_raw.h b/cscore/src/main/native/include/cscore_raw.h index 9367c26c6b..e610683563 100644 --- a/cscore/src/main/native/include/cscore_raw.h +++ b/cscore/src/main/native/include/cscore_raw.h @@ -28,17 +28,17 @@ uint64_t CS_GrabRawSinkFrame(CS_Sink sink, struct WPI_RawFrame* rawImage, uint64_t CS_GrabRawSinkFrameTimeout(CS_Sink sink, struct WPI_RawFrame* rawImage, double timeout, CS_Status* status); -CS_Sink CS_CreateRawSink(const char* name, CS_Bool isCv, CS_Status* status); +CS_Sink CS_CreateRawSink(const struct WPI_String* name, CS_Bool isCv, + CS_Status* status); -CS_Sink CS_CreateRawSinkCallback(const char* name, CS_Bool isCv, void* data, - void (*processFrame)(void* data, - uint64_t time), - CS_Status* status); +CS_Sink CS_CreateRawSinkCallback( + const struct WPI_String* name, CS_Bool isCv, void* data, + void (*processFrame)(void* data, uint64_t time), CS_Status* status); void CS_PutRawSourceFrame(CS_Source source, const struct WPI_RawFrame* image, CS_Status* status); -CS_Source CS_CreateRawSource(const char* name, CS_Bool isCv, +CS_Source CS_CreateRawSource(const struct WPI_String* name, CS_Bool isCv, const CS_VideoMode* mode, CS_Status* status); /** @} */ diff --git a/hal/src/main/native/athena/FRCDriverStation.cpp b/hal/src/main/native/athena/FRCDriverStation.cpp index b0aeb05acc..1e2565b009 100644 --- a/hal/src/main/native/athena/FRCDriverStation.cpp +++ b/hal/src/main/native/athena/FRCDriverStation.cpp @@ -424,22 +424,15 @@ int32_t HAL_GetJoystickType(int32_t joystickNum) { } } -char* HAL_GetJoystickName(int32_t joystickNum) { +void HAL_GetJoystickName(struct WPI_String* name, int32_t joystickNum) { HAL_JoystickDescriptor joystickDesc; + const char* cName = joystickDesc.name; if (HAL_GetJoystickDescriptor(joystickNum, &joystickDesc) < 0) { - char* name = static_cast(std::malloc(1)); - name[0] = '\0'; - return name; - } else { - const size_t len = std::strlen(joystickDesc.name) + 1; - char* name = static_cast(std::malloc(len)); - std::memcpy(name, joystickDesc.name, len); - return name; + cName = ""; } -} - -void HAL_FreeJoystickName(char* name) { - std::free(name); + auto len = std::strlen(cName); + auto write = WPI_AllocateString(name, len); + std::memcpy(write, cName, len); } int32_t HAL_GetJoystickAxisType(int32_t joystickNum, int32_t axis) { diff --git a/hal/src/main/native/athena/HAL.cpp b/hal/src/main/native/athena/HAL.cpp index 7be0e478a7..3ada7d8170 100644 --- a/hal/src/main/native/athena/HAL.cpp +++ b/hal/src/main/native/athena/HAL.cpp @@ -286,18 +286,14 @@ int64_t HAL_GetFPGARevision(int32_t* status) { return global->readRevision(status); } -size_t HAL_GetSerialNumber(char* buffer, size_t size) { +void HAL_GetSerialNumber(struct WPI_String* serialNumber) { const char* serialNum = std::getenv("serialnum"); - if (serialNum) { - std::strncpy(buffer, serialNum, size); - buffer[size - 1] = '\0'; - return std::strlen(buffer); - } else { - if (size > 0) { - buffer[0] = '\0'; - } - return 0; + if (!serialNum) { + serialNum = ""; } + size_t len = std::strlen(serialNum); + auto write = WPI_AllocateString(serialNumber, len); + std::memcpy(write, serialNum, len); } void InitializeRoboRioComments(void) { @@ -341,21 +337,12 @@ void InitializeRoboRioComments(void) { } } -size_t HAL_GetComments(char* buffer, size_t size) { +void HAL_GetComments(struct WPI_String* comments) { if (!roboRioCommentsStringInitialized) { InitializeRoboRioComments(); } - size_t toCopy = size; - if (size > roboRioCommentsStringSize) { - toCopy = roboRioCommentsStringSize; - } - std::memcpy(buffer, roboRioCommentsString, toCopy); - if (toCopy < size) { - buffer[toCopy] = '\0'; - } else { - buffer[toCopy - 1] = '\0'; - } - return toCopy; + auto write = WPI_AllocateString(comments, roboRioCommentsStringSize); + std::memcpy(write, roboRioCommentsString, roboRioCommentsStringSize); } void InitializeTeamNumber(void) { diff --git a/hal/src/main/native/athena/mockdata/DriverStationData.cpp b/hal/src/main/native/athena/mockdata/DriverStationData.cpp index 76a8e8bf1e..90fa34fc56 100644 --- a/hal/src/main/native/athena/mockdata/DriverStationData.cpp +++ b/hal/src/main/native/athena/mockdata/DriverStationData.cpp @@ -103,13 +103,13 @@ void HALSIM_SetJoystickIsXbox(int32_t stick, HAL_Bool isXbox) {} void HALSIM_SetJoystickType(int32_t stick, int32_t type) {} -void HALSIM_SetJoystickName(int32_t stick, const char* name, size_t size) {} +void HALSIM_SetJoystickName(int32_t stick, const struct WPI_String* name) {} void HALSIM_SetJoystickAxisType(int32_t stick, int32_t axis, int32_t type) {} -void HALSIM_SetGameSpecificMessage(const char* message, size_t size) {} +void HALSIM_SetGameSpecificMessage(const struct WPI_String* message) {} -void HALSIM_SetEventName(const char* name, size_t size) {} +void HALSIM_SetEventName(const struct WPI_String* name) {} void HALSIM_SetMatchType(HAL_MatchType type) {} diff --git a/hal/src/main/native/athena/mockdata/RoboRioData.cpp b/hal/src/main/native/athena/mockdata/RoboRioData.cpp index b57b706b8a..b1ba26026d 100644 --- a/hal/src/main/native/athena/mockdata/RoboRioData.cpp +++ b/hal/src/main/native/athena/mockdata/RoboRioData.cpp @@ -37,26 +37,20 @@ int32_t HALSIM_RegisterRoboRioSerialNumberCallback( return 0; } void HALSIM_CancelRoboRioSerialNumberCallback(int32_t uid) {} -size_t HALSIM_GetRoboRioSerialNumber(char* buffer, size_t size) { - if (size > 0) { - buffer[0] = '\0'; - } - return 0; +void HALSIM_GetRoboRioSerialNumber(struct WPI_String* serialNumber) { + WPI_AllocateString(serialNumber, 0); } -void HALSIM_SetRoboRioSerialNumber(const char* buffer, size_t size) {} +void HALSIM_SetRoboRioSerialNumber(const struct WPI_String* serialNumber) {} int32_t HALSIM_RegisterRoboRioCommentsCallback( HAL_RoboRioStringCallback callback, void* param, HAL_Bool initialNotify) { return 0; } void HALSIM_CancelRoboRioCommentsCallback(int32_t uid) {} -size_t HALSIM_GetRoboRioComments(char* buffer, size_t size) { - if (size > 0) { - buffer[0] = '\0'; - } - return 0; +void HALSIM_GetRoboRioComments(struct WPI_String* comments) { + WPI_AllocateString(comments, 0); } -void HALSIM_SetRoboRioComments(const char* buffer, size_t size) {} +void HALSIM_SetRoboRioComments(const struct WPI_String* comments) {} void HALSIM_RegisterRoboRioAllCallbacks(HAL_NotifyCallback callback, void* param, HAL_Bool initialNotify) {} diff --git a/hal/src/main/native/cpp/jni/DriverStationJNI.cpp b/hal/src/main/native/cpp/jni/DriverStationJNI.cpp index 6b17cc0146..87c8b14505 100644 --- a/hal/src/main/native/cpp/jni/DriverStationJNI.cpp +++ b/hal/src/main/native/cpp/jni/DriverStationJNI.cpp @@ -336,9 +336,10 @@ JNIEXPORT jstring JNICALL Java_edu_wpi_first_hal_DriverStationJNI_getJoystickName (JNIEnv* env, jclass, jbyte port) { - char* joystickName = HAL_GetJoystickName(port); - jstring str = MakeJString(env, joystickName); - HAL_FreeJoystickName(joystickName); + WPI_String joystickName; + HAL_GetJoystickName(&joystickName, port); + jstring str = MakeJString(env, wpi::to_string_view(&joystickName)); + WPI_FreeString(&joystickName); return str; } diff --git a/hal/src/main/native/cpp/jni/HALUtil.cpp b/hal/src/main/native/cpp/jni/HALUtil.cpp index 1915108b34..31b40efc57 100644 --- a/hal/src/main/native/cpp/jni/HALUtil.cpp +++ b/hal/src/main/native/cpp/jni/HALUtil.cpp @@ -490,9 +490,11 @@ JNIEXPORT jstring JNICALL Java_edu_wpi_first_hal_HALUtil_getSerialNumber (JNIEnv* env, jclass) { - char serialNum[9]; - size_t len = HAL_GetSerialNumber(serialNum, sizeof(serialNum)); - return MakeJString(env, std::string_view(serialNum, len)); + WPI_String serialNum; + HAL_GetSerialNumber(&serialNum); + jstring ret = MakeJString(env, wpi::to_string_view(&serialNum)); + WPI_FreeString(&serialNum); + return ret; } /* @@ -504,9 +506,11 @@ JNIEXPORT jstring JNICALL Java_edu_wpi_first_hal_HALUtil_getComments (JNIEnv* env, jclass) { - char comments[65]; - size_t len = HAL_GetComments(comments, sizeof(comments)); - return MakeJString(env, std::string_view(comments, len)); + WPI_String comments; + HAL_GetComments(&comments); + jstring ret = MakeJString(env, wpi::to_string_view(&comments)); + WPI_FreeString(&comments); + return ret; } /* diff --git a/hal/src/main/native/cpp/jni/simulation/DriverStationDataJNI.cpp b/hal/src/main/native/cpp/jni/simulation/DriverStationDataJNI.cpp index 8b1ba4f68f..63af783d41 100644 --- a/hal/src/main/native/cpp/jni/simulation/DriverStationDataJNI.cpp +++ b/hal/src/main/native/cpp/jni/simulation/DriverStationDataJNI.cpp @@ -733,7 +733,8 @@ Java_edu_wpi_first_hal_simulation_DriverStationDataJNI_setJoystickName (JNIEnv* env, jclass, jint stick, jstring name) { JStringRef nameJString{env, name}; - HALSIM_SetJoystickName(stick, nameJString.c_str(), nameJString.size()); + auto str = wpi::make_string(nameJString); + HALSIM_SetJoystickName(stick, &str); } /* @@ -758,7 +759,8 @@ Java_edu_wpi_first_hal_simulation_DriverStationDataJNI_setGameSpecificMessage (JNIEnv* env, jclass, jstring message) { JStringRef messageJString{env, message}; - HALSIM_SetGameSpecificMessage(messageJString.c_str(), messageJString.size()); + auto str = wpi::make_string(messageJString); + HALSIM_SetGameSpecificMessage(&str); } /* @@ -771,7 +773,8 @@ Java_edu_wpi_first_hal_simulation_DriverStationDataJNI_setEventName (JNIEnv* env, jclass, jstring name) { JStringRef nameJString{env, name}; - HALSIM_SetEventName(nameJString.c_str(), nameJString.size()); + auto str = wpi::make_string(nameJString); + HALSIM_SetEventName(&str); } /* diff --git a/hal/src/main/native/cpp/jni/simulation/RoboRioDataJNI.cpp b/hal/src/main/native/cpp/jni/simulation/RoboRioDataJNI.cpp index c9a2acaa67..3c9d4422d4 100644 --- a/hal/src/main/native/cpp/jni/simulation/RoboRioDataJNI.cpp +++ b/hal/src/main/native/cpp/jni/simulation/RoboRioDataJNI.cpp @@ -937,9 +937,11 @@ JNIEXPORT jstring JNICALL Java_edu_wpi_first_hal_simulation_RoboRioDataJNI_getSerialNumber (JNIEnv* env, jclass) { - char serialNum[9]; - size_t len = HALSIM_GetRoboRioSerialNumber(serialNum, sizeof(serialNum)); - return MakeJString(env, std::string_view(serialNum, len)); + WPI_String str; + HALSIM_GetRoboRioSerialNumber(&str); + auto jstr = MakeJString(env, wpi::to_string_view(&str)); + WPI_FreeString(&str); + return jstr; } /* @@ -952,8 +954,8 @@ Java_edu_wpi_first_hal_simulation_RoboRioDataJNI_setSerialNumber (JNIEnv* env, jclass, jstring serialNumber) { JStringRef serialNumberJString{env, serialNumber}; - HALSIM_SetRoboRioSerialNumber(serialNumberJString.c_str(), - serialNumberJString.size()); + auto str = wpi::make_string(serialNumberJString); + HALSIM_SetRoboRioSerialNumber(&str); } /* @@ -965,9 +967,11 @@ JNIEXPORT jstring JNICALL Java_edu_wpi_first_hal_simulation_RoboRioDataJNI_getComments (JNIEnv* env, jclass) { - char comments[65]; - size_t len = HALSIM_GetRoboRioComments(comments, sizeof(comments)); - return MakeJString(env, std::string_view(comments, len)); + WPI_String str; + HALSIM_GetRoboRioComments(&str); + auto jstr = MakeJString(env, wpi::to_string_view(&str)); + WPI_FreeString(&str); + return jstr; } /* @@ -980,7 +984,8 @@ Java_edu_wpi_first_hal_simulation_RoboRioDataJNI_setComments (JNIEnv* env, jclass, jstring comments) { JStringRef commentsJString{env, comments}; - HALSIM_SetRoboRioComments(commentsJString.c_str(), commentsJString.size()); + auto str = wpi::make_string(commentsJString); + HALSIM_SetRoboRioComments(&str); } /* diff --git a/hal/src/main/native/include/hal/DriverStation.h b/hal/src/main/native/include/hal/DriverStation.h index e0790742b0..8c5fea0c23 100644 --- a/hal/src/main/native/include/hal/DriverStation.h +++ b/hal/src/main/native/include/hal/DriverStation.h @@ -9,6 +9,7 @@ #include //NOLINT #include +#include #include "hal/DriverStationTypes.h" #include "hal/Types.h" @@ -142,21 +143,12 @@ int32_t HAL_GetJoystickType(int32_t joystickNum); /** * Gets the name of a joystick. * - * The returned array must be freed with HAL_FreeJoystickName. - * - * Will be null terminated. + * The returned string must be freed with WPI_FreeString * + * @param name the joystick name string * @param joystickNum the joystick number - * @return the joystick name */ -char* HAL_GetJoystickName(int32_t joystickNum); - -/** - * Frees a joystick name received with HAL_GetJoystickName - * - * @param name the name storage - */ -void HAL_FreeJoystickName(char* name); +void HAL_GetJoystickName(struct WPI_String* name, int32_t joystickNum); /** * Gets the type of a specific joystick axis. diff --git a/hal/src/main/native/include/hal/HALBase.h b/hal/src/main/native/include/hal/HALBase.h index 3e9ddc67d1..e59b26cbae 100644 --- a/hal/src/main/native/include/hal/HALBase.h +++ b/hal/src/main/native/include/hal/HALBase.h @@ -14,6 +14,8 @@ #endif +#include + #include "hal/Types.h" /** @@ -79,20 +81,16 @@ int64_t HAL_GetFPGARevision(int32_t* status); /** * Returns the roboRIO serial number. * - * @param[out] buffer The roboRIO serial number. - * @param size The maximum characters to copy into buffer. - * @return Number of characters copied into buffer. + * @param[out] serialNumber The roboRIO serial number. Free with WPI_FreeString */ -size_t HAL_GetSerialNumber(char* buffer, size_t size); +void HAL_GetSerialNumber(struct WPI_String* serialNumber); /** * Returns the comments from the roboRIO web interface. * - * @param[out] buffer The comments string. - * @param size The maximum characters to copy into buffer. - * @return Number of characters copied into buffer. + * @param[out] comments The comments string. Free with WPI_FreeString */ -size_t HAL_GetComments(char* buffer, size_t size); +void HAL_GetComments(struct WPI_String* comments); /** * Returns the team number configured for the robot controller. diff --git a/hal/src/main/native/include/hal/simulation/DriverStationData.h b/hal/src/main/native/include/hal/simulation/DriverStationData.h index b10cf03262..b00fef8b51 100644 --- a/hal/src/main/native/include/hal/simulation/DriverStationData.h +++ b/hal/src/main/native/include/hal/simulation/DriverStationData.h @@ -6,6 +6,8 @@ #include +#include + #include "hal/DriverStationTypes.h" #include "hal/Types.h" #include "hal/simulation/NotifyListener.h" @@ -147,11 +149,11 @@ void HALSIM_GetJoystickCounts(int32_t stick, int32_t* axisCount, void HALSIM_SetJoystickIsXbox(int32_t stick, HAL_Bool isXbox); void HALSIM_SetJoystickType(int32_t stick, int32_t type); -void HALSIM_SetJoystickName(int32_t stick, const char* name, size_t size); +void HALSIM_SetJoystickName(int32_t stick, const struct WPI_String* name); void HALSIM_SetJoystickAxisType(int32_t stick, int32_t axis, int32_t type); -void HALSIM_SetGameSpecificMessage(const char* message, size_t size); -void HALSIM_SetEventName(const char* name, size_t size); +void HALSIM_SetGameSpecificMessage(const struct WPI_String* message); +void HALSIM_SetEventName(const struct WPI_String* name); void HALSIM_SetMatchType(HAL_MatchType type); void HALSIM_SetMatchNumber(int32_t matchNumber); void HALSIM_SetReplayNumber(int32_t replayNumber); diff --git a/hal/src/main/native/include/hal/simulation/RoboRioData.h b/hal/src/main/native/include/hal/simulation/RoboRioData.h index 83d68eadeb..0c87b07e5c 100644 --- a/hal/src/main/native/include/hal/simulation/RoboRioData.h +++ b/hal/src/main/native/include/hal/simulation/RoboRioData.h @@ -6,6 +6,8 @@ #include +#include + #include "hal/LEDs.h" #include "hal/Types.h" #include "hal/simulation/NotifyListener.h" @@ -137,14 +139,14 @@ void HALSIM_SetRoboRioTeamNumber(int32_t teamNumber); int32_t HALSIM_RegisterRoboRioSerialNumberCallback( HAL_RoboRioStringCallback callback, void* param, HAL_Bool initialNotify); void HALSIM_CancelRoboRioSerialNumberCallback(int32_t uid); -size_t HALSIM_GetRoboRioSerialNumber(char* buffer, size_t size); -void HALSIM_SetRoboRioSerialNumber(const char* serialNumber, size_t size); +void HALSIM_GetRoboRioSerialNumber(struct WPI_String* serialNumber); +void HALSIM_SetRoboRioSerialNumber(const struct WPI_String* serialNumber); int32_t HALSIM_RegisterRoboRioCommentsCallback( HAL_RoboRioStringCallback callback, void* param, HAL_Bool initialNotify); void HALSIM_CancelRoboRioCommentsCallback(int32_t uid); -size_t HALSIM_GetRoboRioComments(char* buffer, size_t size); -void HALSIM_SetRoboRioComments(const char* comments, size_t size); +void HALSIM_GetRoboRioComments(struct WPI_String* comments); +void HALSIM_SetRoboRioComments(const struct WPI_String* comments); int32_t HALSIM_RegisterRoboRioCPUTempCallback(HAL_NotifyCallback callback, void* param, diff --git a/hal/src/main/native/sim/DriverStation.cpp b/hal/src/main/native/sim/DriverStation.cpp index 2ad13de861..f50deaceb5 100644 --- a/hal/src/main/native/sim/DriverStation.cpp +++ b/hal/src/main/native/sim/DriverStation.cpp @@ -272,17 +272,12 @@ int32_t HAL_GetJoystickType(int32_t joystickNum) { return desc.type; } -char* HAL_GetJoystickName(int32_t joystickNum) { +void HAL_GetJoystickName(struct WPI_String* name, int32_t joystickNum) { HAL_JoystickDescriptor desc; SimDriverStationData->GetJoystickDescriptor(joystickNum, &desc); size_t len = std::strlen(desc.name); - char* name = static_cast(std::malloc(len + 1)); - std::memcpy(name, desc.name, len + 1); - return name; -} - -void HAL_FreeJoystickName(char* name) { - std::free(name); + auto write = WPI_AllocateString(name, len); + std::memcpy(write, desc.name, len); } int32_t HAL_GetJoystickAxisType(int32_t joystickNum, int32_t axis) { diff --git a/hal/src/main/native/sim/HAL.cpp b/hal/src/main/native/sim/HAL.cpp index c7b632c1b6..000ad8f80d 100644 --- a/hal/src/main/native/sim/HAL.cpp +++ b/hal/src/main/native/sim/HAL.cpp @@ -5,6 +5,7 @@ #include "hal/HAL.h" #include +#include #include #include @@ -280,12 +281,12 @@ int64_t HAL_GetFPGARevision(int32_t* status) { return 0; // TODO: Find a better number to return; } -size_t HAL_GetSerialNumber(char* buffer, size_t size) { - return HALSIM_GetRoboRioSerialNumber(buffer, size); +void HAL_GetSerialNumber(struct WPI_String* serialNumber) { + HALSIM_GetRoboRioSerialNumber(serialNumber); } -size_t HAL_GetComments(char* buffer, size_t size) { - return HALSIM_GetRoboRioComments(buffer, size); +void HAL_GetComments(struct WPI_String* comments) { + HALSIM_GetRoboRioComments(comments); } int32_t HAL_GetTeamNumber(void) { diff --git a/hal/src/main/native/sim/mockdata/DriverStationData.cpp b/hal/src/main/native/sim/mockdata/DriverStationData.cpp index d124b21308..d7b8a087fa 100644 --- a/hal/src/main/native/sim/mockdata/DriverStationData.cpp +++ b/hal/src/main/native/sim/mockdata/DriverStationData.cpp @@ -339,17 +339,14 @@ void DriverStationData::SetJoystickType(int32_t stick, int32_t type) { m_joystickDescriptorCallbacks(stick, &m_joystickData[stick].descriptor); } -void DriverStationData::SetJoystickName(int32_t stick, const char* name, - size_t size) { +void DriverStationData::SetJoystickName(int32_t stick, std::string_view name) { if (stick < 0 || stick >= kNumJoysticks) { return; } std::scoped_lock lock(m_joystickDataMutex); - if (size > sizeof(m_joystickData[stick].descriptor.name) - 1) { - size = sizeof(m_joystickData[stick].descriptor.name) - 1; - } - std::strncpy(m_joystickData[stick].descriptor.name, name, size); - m_joystickData[stick].descriptor.name[size] = '\0'; + auto copied = name.copy(m_joystickData[stick].descriptor.name, + sizeof(m_joystickData[stick].descriptor.name) - 1); + m_joystickData[stick].descriptor.name[copied] = '\0'; m_joystickDescriptorCallbacks(stick, &m_joystickData[stick].descriptor); } @@ -366,27 +363,20 @@ void DriverStationData::SetJoystickAxisType(int32_t stick, int32_t axis, m_joystickDescriptorCallbacks(stick, &m_joystickData[stick].descriptor); } -void DriverStationData::SetGameSpecificMessage(const char* message, - size_t size) { +void DriverStationData::SetGameSpecificMessage(std::string_view message) { std::scoped_lock lock(m_matchInfoMutex); - if (size > sizeof(m_matchInfo.gameSpecificMessage) - 1) { - size = sizeof(m_matchInfo.gameSpecificMessage) - 1; - } - std::strncpy(reinterpret_cast(m_matchInfo.gameSpecificMessage), - message, size); - m_matchInfo.gameSpecificMessage[size] = '\0'; - m_matchInfo.gameSpecificMessageSize = - std::strlen(reinterpret_cast(m_matchInfo.gameSpecificMessage)); + auto copied = + message.copy(reinterpret_cast(m_matchInfo.gameSpecificMessage), + sizeof(m_matchInfo.gameSpecificMessage)); + m_matchInfo.gameSpecificMessageSize = copied; m_matchInfoCallbacks(&m_matchInfo); } -void DriverStationData::SetEventName(const char* name, size_t size) { +void DriverStationData::SetEventName(std::string_view name) { std::scoped_lock lock(m_matchInfoMutex); - if (size > sizeof(m_matchInfo.eventName) - 1) { - size = sizeof(m_matchInfo.eventName) - 1; - } - std::strncpy(m_matchInfo.eventName, name, size); - m_matchInfo.eventName[size] = '\0'; + auto copied = + name.copy(m_matchInfo.eventName, sizeof(m_matchInfo.eventName) - 1); + m_matchInfo.eventName[copied] = '\0'; m_matchInfoCallbacks(&m_matchInfo); } @@ -551,20 +541,20 @@ void HALSIM_SetJoystickType(int32_t stick, int32_t type) { SimDriverStationData->SetJoystickType(stick, type); } -void HALSIM_SetJoystickName(int32_t stick, const char* name, size_t size) { - SimDriverStationData->SetJoystickName(stick, name, size); +void HALSIM_SetJoystickName(int32_t stick, const WPI_String* name) { + SimDriverStationData->SetJoystickName(stick, wpi::to_string_view(name)); } void HALSIM_SetJoystickAxisType(int32_t stick, int32_t axis, int32_t type) { SimDriverStationData->SetJoystickAxisType(stick, axis, type); } -void HALSIM_SetGameSpecificMessage(const char* message, size_t size) { - SimDriverStationData->SetGameSpecificMessage(message, size); +void HALSIM_SetGameSpecificMessage(const WPI_String* message) { + SimDriverStationData->SetGameSpecificMessage(wpi::to_string_view(message)); } -void HALSIM_SetEventName(const char* name, size_t size) { - SimDriverStationData->SetEventName(name, size); +void HALSIM_SetEventName(const WPI_String* name) { + SimDriverStationData->SetEventName(wpi::to_string_view(name)); } void HALSIM_SetMatchType(HAL_MatchType type) { diff --git a/hal/src/main/native/sim/mockdata/DriverStationDataInternal.h b/hal/src/main/native/sim/mockdata/DriverStationDataInternal.h index 008329fde8..01de9cbdb1 100644 --- a/hal/src/main/native/sim/mockdata/DriverStationDataInternal.h +++ b/hal/src/main/native/sim/mockdata/DriverStationDataInternal.h @@ -107,11 +107,11 @@ class DriverStationData { void SetJoystickIsXbox(int32_t stick, HAL_Bool isXbox); void SetJoystickType(int32_t stick, int32_t type); - void SetJoystickName(int32_t stick, const char* name, size_t size); + void SetJoystickName(int32_t stick, std::string_view message); void SetJoystickAxisType(int32_t stick, int32_t axis, int32_t type); - void SetGameSpecificMessage(const char* message, size_t size); - void SetEventName(const char* name, size_t size); + void SetGameSpecificMessage(std::string_view message); + void SetEventName(std::string_view name); void SetMatchType(HAL_MatchType type); void SetMatchNumber(int32_t matchNumber); void SetReplayNumber(int32_t replayNumber); diff --git a/hal/src/main/native/sim/mockdata/RoboRioData.cpp b/hal/src/main/native/sim/mockdata/RoboRioData.cpp index 8ccc019edb..94d61f8972 100644 --- a/hal/src/main/native/sim/mockdata/RoboRioData.cpp +++ b/hal/src/main/native/sim/mockdata/RoboRioData.cpp @@ -53,25 +53,20 @@ void RoboRioData::CancelSerialNumberCallback(int32_t uid) { m_serialNumberCallbacks.Cancel(uid); } -size_t RoboRioData::GetSerialNumber(char* buffer, size_t size) { +void RoboRioData::GetSerialNumber(struct WPI_String* serialNumber) { std::scoped_lock lock(m_serialNumberMutex); - size_t copied = m_serialNumber.copy(buffer, size); - // Null terminate - if (copied == size) { - copied -= 1; - } - buffer[copied] = '\0'; - return copied; + auto write = WPI_AllocateString(serialNumber, m_serialNumber.size()); + m_serialNumber.copy(write, m_serialNumber.size()); } -void RoboRioData::SetSerialNumber(const char* serialNumber, size_t size) { +void RoboRioData::SetSerialNumber(std::string_view serialNumber) { // Limit serial number to 8 characters internally- serialnum environment // variable is always 8 characters - if (size > 8) { - size = 8; + if (serialNumber.size() > 8) { + serialNumber = serialNumber.substr(0, 8); } std::scoped_lock lock(m_serialNumberMutex); - m_serialNumber = std::string(serialNumber, size); + m_serialNumber = std::string(serialNumber); m_serialNumberCallbacks(m_serialNumber.c_str(), m_serialNumber.size()); } @@ -90,22 +85,18 @@ void RoboRioData::CancelCommentsCallback(int32_t uid) { m_commentsCallbacks.Cancel(uid); } -size_t RoboRioData::GetComments(char* buffer, size_t size) { +void RoboRioData::GetComments(struct WPI_String* comments) { std::scoped_lock lock(m_commentsMutex); - size_t copied = m_comments.copy(buffer, size); - // Null terminate if there is room - if (copied < size) { - buffer[copied] = '\0'; - } - return copied; + auto write = WPI_AllocateString(comments, m_comments.size()); + m_comments.copy(write, m_comments.size()); } -void RoboRioData::SetComments(const char* comments, size_t size) { - if (size > 64) { - size = 64; +void RoboRioData::SetComments(std::string_view comments) { + if (comments.size() > 64) { + comments = comments.substr(0, 64); } std::scoped_lock lock(m_commentsMutex); - m_comments = std::string(comments, size); + m_comments = std::string(comments); m_commentsCallbacks(m_comments.c_str(), m_comments.size()); } @@ -146,11 +137,11 @@ int32_t HALSIM_RegisterRoboRioSerialNumberCallback( void HALSIM_CancelRoboRioSerialNumberCallback(int32_t uid) { return SimRoboRioData->CancelSerialNumberCallback(uid); } -size_t HALSIM_GetRoboRioSerialNumber(char* buffer, size_t size) { - return SimRoboRioData->GetSerialNumber(buffer, size); +void HALSIM_GetRoboRioSerialNumber(struct WPI_String* serialNumber) { + SimRoboRioData->GetSerialNumber(serialNumber); } -void HALSIM_SetRoboRioSerialNumber(const char* serialNumber, size_t size) { - SimRoboRioData->SetSerialNumber(serialNumber, size); +void HALSIM_SetRoboRioSerialNumber(const struct WPI_String* serialNumber) { + SimRoboRioData->SetSerialNumber(wpi::to_string_view(serialNumber)); } int32_t HALSIM_RegisterRoboRioCommentsCallback( @@ -161,11 +152,11 @@ int32_t HALSIM_RegisterRoboRioCommentsCallback( void HALSIM_CancelRoboRioCommentsCallback(int32_t uid) { SimRoboRioData->CancelCommentsCallback(uid); } -size_t HALSIM_GetRoboRioComments(char* buffer, size_t size) { - return SimRoboRioData->GetComments(buffer, size); +void HALSIM_GetRoboRioComments(struct WPI_String* comments) { + SimRoboRioData->GetComments(comments); } -void HALSIM_SetRoboRioComments(const char* comments, size_t size) { - SimRoboRioData->SetComments(comments, size); +void HALSIM_SetRoboRioComments(const struct WPI_String* comments) { + SimRoboRioData->SetComments(wpi::to_string_view(comments)); } void HALSIM_RegisterRoboRioAllCallbacks(HAL_NotifyCallback callback, diff --git a/hal/src/main/native/sim/mockdata/RoboRioDataInternal.h b/hal/src/main/native/sim/mockdata/RoboRioDataInternal.h index 413c38eb2d..6ef523e182 100644 --- a/hal/src/main/native/sim/mockdata/RoboRioDataInternal.h +++ b/hal/src/main/native/sim/mockdata/RoboRioDataInternal.h @@ -72,14 +72,14 @@ class RoboRioData { int32_t RegisterSerialNumberCallback(HAL_RoboRioStringCallback callback, void* param, HAL_Bool initialNotify); void CancelSerialNumberCallback(int32_t uid); - size_t GetSerialNumber(char* buffer, size_t size); - void SetSerialNumber(const char* serialNumber, size_t size); + void GetSerialNumber(struct WPI_String* serialNumber); + void SetSerialNumber(std::string_view serialNumber); int32_t RegisterCommentsCallback(HAL_RoboRioStringCallback callback, void* param, HAL_Bool initialNotify); void CancelCommentsCallback(int32_t uid); - size_t GetComments(char* buffer, size_t size); - void SetComments(const char* comments, size_t size); + void GetComments(struct WPI_String* comments); + void SetComments(std::string_view comments); virtual void ResetData(); diff --git a/ntcore/src/generate/main/native/cpp/ntcore_c_types.cpp.jinja b/ntcore/src/generate/main/native/cpp/ntcore_c_types.cpp.jinja index a22563464c..ccfe1833ac 100644 --- a/ntcore/src/generate/main/native/cpp/ntcore_c_types.cpp.jinja +++ b/ntcore/src/generate/main/native/cpp/ntcore_c_types.cpp.jinja @@ -16,11 +16,11 @@ static inline std::span ConvertFromC(const T* arr, size_t size) { return {arr, size}; } -static inline std::string_view ConvertFromC(const char* arr, size_t size) { - return {arr, size}; +static inline std::string_view ConvertFromC(const struct WPI_String* str) { + return wpi::to_string_view(str); } -static std::vector ConvertFromC(const NT_String* arr, size_t size) { +static std::vector ConvertFromC(const struct WPI_String* arr, size_t size) { std::vector v; v.reserve(size); for (size_t i = 0; i < size; ++i) { @@ -35,6 +35,8 @@ static void ConvertToC(const nt::Timestamped{{ t.TypeName }}& in, NT_Timestamped out->serverTime = in.serverTime; {%- if t.c.IsArray %} out->value = ConvertToC<{{ t.c.ValueType[:-1] }}>(in.value, &out->len); +{% elif t.c.ValueInline %} + ConvertToC(in.value, &out->value); {% else %} out->value = in.value; {% endif -%} @@ -46,6 +48,8 @@ extern "C" { NT_Bool NT_Set{{ t.TypeName }}(NT_Handle pubentry, int64_t time, {{ t.c.ParamType }} value{% if t.c.IsArray %}, size_t len{% endif %}) { {%- if t.c.IsArray %} return nt::Set{{ t.TypeName }}(pubentry, ConvertFromC(value, len), time); +{%- elif t.c.ValueInline %} + return nt::Set{{ t.TypeName }}(pubentry, ConvertFromC(value), time); {%- else %} return nt::Set{{ t.TypeName }}(pubentry, value, time); {%- endif %} @@ -54,11 +58,21 @@ NT_Bool NT_Set{{ t.TypeName }}(NT_Handle pubentry, int64_t time, {{ t.c.ParamTyp NT_Bool NT_SetDefault{{ t.TypeName }}(NT_Handle pubentry, {{ t.c.ParamType }} defaultValue{% if t.c.IsArray %}, size_t defaultValueLen{% endif %}) { {%- if t.c.IsArray %} return nt::SetDefault{{ t.TypeName }}(pubentry, ConvertFromC(defaultValue, defaultValueLen)); +{%- elif t.c.ValueInline %} + return nt::SetDefault{{ t.TypeName }}(pubentry, ConvertFromC(defaultValue)); {%- else %} return nt::SetDefault{{ t.TypeName }}(pubentry, defaultValue); {%- endif %} } +{%- if t.c.ValueInline %} + +void NT_Get{{ t.TypeName }}(NT_Handle subentry, {{ t.c.ParamType }} defaultValue, {{ t.c.ValueType }} value) { + auto cppValue = nt::Get{{ t.TypeName }}(subentry, ConvertFromC(defaultValue)); + ConvertToC(cppValue, value); +} +{%- else %} + {{ t.c.ValueType }} NT_Get{{ t.TypeName }}(NT_Handle subentry, {{ t.c.ParamType }} defaultValue{% if t.c.IsArray %}, size_t defaultValueLen, size_t* len{% endif %}) { {%- if t.c.IsArray %} auto cppValue = nt::Get{{ t.TypeName }}(subentry, ConvertFromC(defaultValue, defaultValueLen)); @@ -67,10 +81,13 @@ NT_Bool NT_SetDefault{{ t.TypeName }}(NT_Handle pubentry, {{ t.c.ParamType }} de return nt::Get{{ t.TypeName }}(subentry, defaultValue); {%- endif %} } +{%- endif %} void NT_GetAtomic{{ t.TypeName }}(NT_Handle subentry, {{ t.c.ParamType }} defaultValue{% if t.c.IsArray %}, size_t defaultValueLen{% endif %}, struct NT_Timestamped{{ t.TypeName }}* value) { {%- if t.c.IsArray %} auto cppValue = nt::GetAtomic{{ t.TypeName }}(subentry, ConvertFromC(defaultValue, defaultValueLen)); +{%- elif t.c.ValueInline %} + auto cppValue = nt::GetAtomic{{ t.TypeName }}(subentry, ConvertFromC(defaultValue)); {%- else %} auto cppValue = nt::GetAtomic{{ t.TypeName }}(subentry, defaultValue); {%- endif %} @@ -79,7 +96,9 @@ void NT_GetAtomic{{ t.TypeName }}(NT_Handle subentry, {{ t.c.ParamType }} defaul void NT_DisposeTimestamped{{ t.TypeName }}(struct NT_Timestamped{{ t.TypeName }}* value) { {%- if t.TypeName == "StringArray" %} - NT_FreeStringArray(value->value, value->len); + WPI_FreeStringArray(value->value, value->len); +{%- elif t.TypeName == "String" %} + WPI_FreeString(&value->value); {%- elif t.c.IsArray %} std::free(value->value); {%- endif %} @@ -97,7 +116,7 @@ void NT_FreeQueue{{ t.TypeName }}(struct NT_Timestamped{{ t.TypeName }}* arr, si std::free(arr); } -{%- if not t.c.IsArray %} +{%- if not t.c.IsArray and not t.c.ValueInline %} {{ t.c.ValueType }}* NT_ReadQueueValues{{ t.TypeName }}(NT_Handle subentry, size_t* len) { auto arr = nt::ReadQueueValues{{ t.TypeName }}(subentry); return ConvertToC<{{ t.c.ValueType }}>(arr, len); diff --git a/ntcore/src/generate/main/native/include/ntcore_c_types.h.jinja b/ntcore/src/generate/main/native/include/ntcore_c_types.h.jinja index 22866fbe6e..93359ffce5 100644 --- a/ntcore/src/generate/main/native/include/ntcore_c_types.h.jinja +++ b/ntcore/src/generate/main/native/include/ntcore_c_types.h.jinja @@ -33,7 +33,11 @@ struct NT_Timestamped{{ t.TypeName }} { /** * Value. */ +{%- if t.c.ValueInline %} + {{ t.c.ValueInline }} value; +{%- else %} {{ t.c.ValueType }} value; +{%- endif %} {%- if t.c.IsArray %} /** * Value length. @@ -79,13 +83,22 @@ NT_Bool NT_SetDefault{{ t.TypeName }}(NT_Handle pubentry, {{ t.c.ParamType }} de * * @param subentry subscriber or entry handle * @param defaultValue default value to return if no value has been published +{%- if t.c.ValueInline %} + * @param value returned value (output) +{% endif %} {%- if t.c.IsArray %} * @param defaultValueLen length of default value * @param len length of returned value (output) {% endif %} +{%- if not t.c.ValueInline %} * @return value +{%- endif %} */ +{%- if t.c.ValueInline %} +void NT_Get{{ t.TypeName }}(NT_Handle subentry, {{ t.c.ParamType }} defaultValue, {{ t.c.ValueType }} value); +{%- else %} {{ t.c.ValueType }} NT_Get{{ t.TypeName }}(NT_Handle subentry, {{ t.c.ParamType }} defaultValue{% if t.c.IsArray %}, size_t defaultValueLen, size_t* len{% endif %}); +{%- endif %} /** * Get the last published value along with its timestamp. @@ -130,7 +143,7 @@ struct NT_Timestamped{{ t.TypeName }}* NT_ReadQueue{{ t.TypeName }}(NT_Handle su */ void NT_FreeQueue{{ t.TypeName }}(struct NT_Timestamped{{ t.TypeName }}* arr, size_t len); -{%- if not t.c.IsArray %} +{%- if not t.c.IsArray and not t.c.ValueInline %} /** * Get an array of all value changes since the last call to ReadQueue. * diff --git a/ntcore/src/generate/types.json b/ntcore/src/generate/types.json index 3f9f252d54..1ce48d950d 100644 --- a/ntcore/src/generate/types.json +++ b/ntcore/src/generate/types.json @@ -133,9 +133,9 @@ "TypeName": "String", "TypeString": "\"string\"", "c": { - "ValueType": "char*", - "ParamType": "const char*", - "IsArray": true + "ValueType": "struct WPI_String*", + "ParamType": "const struct WPI_String*", + "ValueInline": "struct WPI_String" }, "cpp": { "ValueType": "std::string", @@ -345,8 +345,8 @@ "TypeName": "StringArray", "TypeString": "\"string[]\"", "c": { - "ValueType": "struct NT_String*", - "ParamType": "const struct NT_String*", + "ValueType": "struct WPI_String*", + "ParamType": "const struct WPI_String*", "IsArray": true }, "cpp": { diff --git a/ntcore/src/generated/main/native/cpp/ntcore_c_types.cpp b/ntcore/src/generated/main/native/cpp/ntcore_c_types.cpp index ca14c7d6cd..dcf1a946cb 100644 --- a/ntcore/src/generated/main/native/cpp/ntcore_c_types.cpp +++ b/ntcore/src/generated/main/native/cpp/ntcore_c_types.cpp @@ -16,11 +16,11 @@ static inline std::span ConvertFromC(const T* arr, size_t size) { return {arr, size}; } -static inline std::string_view ConvertFromC(const char* arr, size_t size) { - return {arr, size}; +static inline std::string_view ConvertFromC(const struct WPI_String* str) { + return wpi::to_string_view(str); } -static std::vector ConvertFromC(const NT_String* arr, size_t size) { +static std::vector ConvertFromC(const struct WPI_String* arr, size_t size) { std::vector v; v.reserve(size); for (size_t i = 0; i < size; ++i) { @@ -57,7 +57,7 @@ static void ConvertToC(const nt::TimestampedDouble& in, NT_TimestampedDouble* ou static void ConvertToC(const nt::TimestampedString& in, NT_TimestampedString* out) { out->time = in.time; out->serverTime = in.serverTime; - out->value = ConvertToC(in.value, &out->len); + ConvertToC(in.value, &out->value); } static void ConvertToC(const nt::TimestampedRaw& in, NT_TimestampedRaw* out) { @@ -93,7 +93,7 @@ static void ConvertToC(const nt::TimestampedDoubleArray& in, NT_TimestampedDoubl static void ConvertToC(const nt::TimestampedStringArray& in, NT_TimestampedStringArray* out) { out->time = in.time; out->serverTime = in.serverTime; - out->value = ConvertToC(in.value, &out->len); + out->value = ConvertToC(in.value, &out->len); } @@ -247,26 +247,26 @@ double* NT_ReadQueueValuesDouble(NT_Handle subentry, size_t* len) { } -NT_Bool NT_SetString(NT_Handle pubentry, int64_t time, const char* value, size_t len) { - return nt::SetString(pubentry, ConvertFromC(value, len), time); +NT_Bool NT_SetString(NT_Handle pubentry, int64_t time, const struct WPI_String* value) { + return nt::SetString(pubentry, ConvertFromC(value), time); } -NT_Bool NT_SetDefaultString(NT_Handle pubentry, const char* defaultValue, size_t defaultValueLen) { - return nt::SetDefaultString(pubentry, ConvertFromC(defaultValue, defaultValueLen)); +NT_Bool NT_SetDefaultString(NT_Handle pubentry, const struct WPI_String* defaultValue) { + return nt::SetDefaultString(pubentry, ConvertFromC(defaultValue)); } -char* NT_GetString(NT_Handle subentry, const char* defaultValue, size_t defaultValueLen, size_t* len) { - auto cppValue = nt::GetString(subentry, ConvertFromC(defaultValue, defaultValueLen)); - return ConvertToC(cppValue, len); +void NT_GetString(NT_Handle subentry, const struct WPI_String* defaultValue, struct WPI_String* value) { + auto cppValue = nt::GetString(subentry, ConvertFromC(defaultValue)); + ConvertToC(cppValue, value); } -void NT_GetAtomicString(NT_Handle subentry, const char* defaultValue, size_t defaultValueLen, struct NT_TimestampedString* value) { - auto cppValue = nt::GetAtomicString(subentry, ConvertFromC(defaultValue, defaultValueLen)); +void NT_GetAtomicString(NT_Handle subentry, const struct WPI_String* defaultValue, struct NT_TimestampedString* value) { + auto cppValue = nt::GetAtomicString(subentry, ConvertFromC(defaultValue)); ConvertToC(cppValue, value); } void NT_DisposeTimestampedString(struct NT_TimestampedString* value) { - std::free(value->value); + WPI_FreeString(&value->value); } struct NT_TimestampedString* NT_ReadQueueString(NT_Handle subentry, size_t* len) { @@ -457,26 +457,26 @@ void NT_FreeQueueDoubleArray(struct NT_TimestampedDoubleArray* arr, size_t len) } -NT_Bool NT_SetStringArray(NT_Handle pubentry, int64_t time, const struct NT_String* value, size_t len) { +NT_Bool NT_SetStringArray(NT_Handle pubentry, int64_t time, const struct WPI_String* value, size_t len) { return nt::SetStringArray(pubentry, ConvertFromC(value, len), time); } -NT_Bool NT_SetDefaultStringArray(NT_Handle pubentry, const struct NT_String* defaultValue, size_t defaultValueLen) { +NT_Bool NT_SetDefaultStringArray(NT_Handle pubentry, const struct WPI_String* defaultValue, size_t defaultValueLen) { return nt::SetDefaultStringArray(pubentry, ConvertFromC(defaultValue, defaultValueLen)); } -struct NT_String* NT_GetStringArray(NT_Handle subentry, const struct NT_String* defaultValue, size_t defaultValueLen, size_t* len) { +struct WPI_String* NT_GetStringArray(NT_Handle subentry, const struct WPI_String* defaultValue, size_t defaultValueLen, size_t* len) { auto cppValue = nt::GetStringArray(subentry, ConvertFromC(defaultValue, defaultValueLen)); - return ConvertToC(cppValue, len); + return ConvertToC(cppValue, len); } -void NT_GetAtomicStringArray(NT_Handle subentry, const struct NT_String* defaultValue, size_t defaultValueLen, struct NT_TimestampedStringArray* value) { +void NT_GetAtomicStringArray(NT_Handle subentry, const struct WPI_String* defaultValue, size_t defaultValueLen, struct NT_TimestampedStringArray* value) { auto cppValue = nt::GetAtomicStringArray(subentry, ConvertFromC(defaultValue, defaultValueLen)); ConvertToC(cppValue, value); } void NT_DisposeTimestampedStringArray(struct NT_TimestampedStringArray* value) { - NT_FreeStringArray(value->value, value->len); + WPI_FreeStringArray(value->value, value->len); } struct NT_TimestampedStringArray* NT_ReadQueueStringArray(NT_Handle subentry, size_t* len) { diff --git a/ntcore/src/generated/main/native/include/ntcore_c_types.h b/ntcore/src/generated/main/native/include/ntcore_c_types.h index 3b95a09b6f..a9a57117c1 100644 --- a/ntcore/src/generated/main/native/include/ntcore_c_types.h +++ b/ntcore/src/generated/main/native/include/ntcore_c_types.h @@ -473,12 +473,7 @@ struct NT_TimestampedString { /** * Value. */ - char* value; - /** - * Value length. - */ - size_t len; - + struct WPI_String value; }; /** @@ -493,10 +488,8 @@ struct NT_TimestampedString { * @param pubentry publisher or entry handle * @param time timestamp; 0 indicates current NT time should be used * @param value value to publish - * @param len length of value - */ -NT_Bool NT_SetString(NT_Handle pubentry, int64_t time, const char* value, size_t len); +NT_Bool NT_SetString(NT_Handle pubentry, int64_t time, const struct WPI_String* value); /** * Publish a default value. @@ -505,10 +498,8 @@ NT_Bool NT_SetString(NT_Handle pubentry, int64_t time, const char* value, size_t * * @param pubentry publisher or entry handle * @param defaultValue default value - * @param defaultValueLen length of default value - */ -NT_Bool NT_SetDefaultString(NT_Handle pubentry, const char* defaultValue, size_t defaultValueLen); +NT_Bool NT_SetDefaultString(NT_Handle pubentry, const struct WPI_String* defaultValue); /** * Get the last published value. @@ -516,12 +507,10 @@ NT_Bool NT_SetDefaultString(NT_Handle pubentry, const char* defaultValue, size_t * * @param subentry subscriber or entry handle * @param defaultValue default value to return if no value has been published - * @param defaultValueLen length of default value - * @param len length of returned value (output) + * @param value returned value (output) - * @return value */ -char* NT_GetString(NT_Handle subentry, const char* defaultValue, size_t defaultValueLen, size_t* len); +void NT_GetString(NT_Handle subentry, const struct WPI_String* defaultValue, struct WPI_String* value); /** * Get the last published value along with its timestamp. @@ -530,11 +519,9 @@ char* NT_GetString(NT_Handle subentry, const char* defaultValue, size_t defaultV * * @param subentry subscriber or entry handle * @param defaultValue default value to return if no value has been published - * @param defaultValueLen length of default value - * @param value timestamped value (output) */ -void NT_GetAtomicString(NT_Handle subentry, const char* defaultValue, size_t defaultValueLen, struct NT_TimestampedString* value); +void NT_GetAtomicString(NT_Handle subentry, const struct WPI_String* defaultValue, struct NT_TimestampedString* value); /** * Disposes a timestamped value (as returned by NT_GetAtomicString). @@ -1145,7 +1132,7 @@ struct NT_TimestampedStringArray { /** * Value. */ - struct NT_String* value; + struct WPI_String* value; /** * Value length. */ @@ -1168,7 +1155,7 @@ struct NT_TimestampedStringArray { * @param len length of value */ -NT_Bool NT_SetStringArray(NT_Handle pubentry, int64_t time, const struct NT_String* value, size_t len); +NT_Bool NT_SetStringArray(NT_Handle pubentry, int64_t time, const struct WPI_String* value, size_t len); /** * Publish a default value. @@ -1180,7 +1167,7 @@ NT_Bool NT_SetStringArray(NT_Handle pubentry, int64_t time, const struct NT_Stri * @param defaultValueLen length of default value */ -NT_Bool NT_SetDefaultStringArray(NT_Handle pubentry, const struct NT_String* defaultValue, size_t defaultValueLen); +NT_Bool NT_SetDefaultStringArray(NT_Handle pubentry, const struct WPI_String* defaultValue, size_t defaultValueLen); /** * Get the last published value. @@ -1193,7 +1180,7 @@ NT_Bool NT_SetDefaultStringArray(NT_Handle pubentry, const struct NT_String* def * @return value */ -struct NT_String* NT_GetStringArray(NT_Handle subentry, const struct NT_String* defaultValue, size_t defaultValueLen, size_t* len); +struct WPI_String* NT_GetStringArray(NT_Handle subentry, const struct WPI_String* defaultValue, size_t defaultValueLen, size_t* len); /** * Get the last published value along with its timestamp. @@ -1206,7 +1193,7 @@ struct NT_String* NT_GetStringArray(NT_Handle subentry, const struct NT_String* * @param value timestamped value (output) */ -void NT_GetAtomicStringArray(NT_Handle subentry, const struct NT_String* defaultValue, size_t defaultValueLen, struct NT_TimestampedStringArray* value); +void NT_GetAtomicStringArray(NT_Handle subentry, const struct WPI_String* defaultValue, size_t defaultValueLen, struct NT_TimestampedStringArray* value); /** * Disposes a timestamped value (as returned by NT_GetAtomicStringArray). diff --git a/ntcore/src/main/native/cpp/Value.cpp b/ntcore/src/main/native/cpp/Value.cpp index 09ba775b89..28765487ae 100644 --- a/ntcore/src/main/native/cpp/Value.cpp +++ b/ntcore/src/main/native/cpp/Value.cpp @@ -32,7 +32,7 @@ struct StringArrayStorage { size_t EstimateSize() const { return sizeof(StringArrayStorage) + strings.capacity() * sizeof(std::string) + - ntStrings.capacity() * sizeof(NT_String) + + ntStrings.capacity() * sizeof(WPI_String) + std::accumulate(strings.begin(), strings.end(), 0, [](const auto& sum, const auto& val) { return sum + val.capacity(); @@ -40,7 +40,7 @@ struct StringArrayStorage { } std::vector strings; - std::vector ntStrings; + std::vector ntStrings; }; template @@ -58,11 +58,11 @@ inline std::shared_ptr AllocateArray(size_t nelem) { } // namespace void StringArrayStorage::InitNtStrings() { - // point NT_String's to the contents in the vector. + // point WPI_String's to the contents in the vector. ntStrings.reserve(strings.size()); for (const auto& str : strings) { ntStrings.emplace_back( - NT_String{const_cast(str.c_str()), str.size()}); + WPI_String{const_cast(str.c_str()), str.size()}); } } @@ -250,8 +250,7 @@ void nt::ConvertToC(const Value& in, NT_Value* out) { } case NT_STRING_ARRAY: { auto v = in.GetStringArray(); - out->data.arr_string.arr = static_cast( - wpi::safe_malloc(v.size() * sizeof(NT_String))); + out->data.arr_string.arr = WPI_AllocateStringArray(v.size()); for (size_t i = 0; i < v.size(); ++i) { ConvertToC(std::string_view{v[i]}, &out->data.arr_string.arr[i]); } @@ -263,18 +262,14 @@ void nt::ConvertToC(const Value& in, NT_Value* out) { } } -size_t nt::ConvertToC(std::string_view in, char** out) { - *out = static_cast(wpi::safe_malloc(in.size() + 1)); - std::memmove(*out, in.data(), in.size()); // NOLINT - (*out)[in.size()] = '\0'; - return in.size(); -} - -void nt::ConvertToC(std::string_view in, NT_String* out) { - out->len = in.size(); - out->str = static_cast(wpi::safe_malloc(in.size() + 1)); - std::memcpy(out->str, in.data(), in.size()); - out->str[in.size()] = '\0'; +void nt::ConvertToC(std::string_view in, WPI_String* out) { + if (in.empty()) { + out->len = 0; + out->str = nullptr; + return; + } + auto write = WPI_AllocateString(out, in.size()); + std::memcpy(write, in.data(), in.size()); } Value nt::ConvertFromC(const NT_Value& value) { diff --git a/ntcore/src/main/native/cpp/Value_internal.h b/ntcore/src/main/native/cpp/Value_internal.h index 8f2c8fb138..fd633f1300 100644 --- a/ntcore/src/main/native/cpp/Value_internal.h +++ b/ntcore/src/main/native/cpp/Value_internal.h @@ -420,8 +420,8 @@ inline void ConvertToC(const T& in, T* out) { void ConvertToC(const Value& in, NT_Value* out); Value ConvertFromC(const NT_Value& value); size_t ConvertToC(std::string_view in, char** out); -void ConvertToC(std::string_view in, NT_String* out); -inline std::string_view ConvertFromC(const NT_String& str) { +void ConvertToC(std::string_view in, WPI_String* out); +inline std::string_view ConvertFromC(const WPI_String& str) { return {str.str, str.len}; } diff --git a/ntcore/src/main/native/cpp/ntcore_c.cpp b/ntcore/src/main/native/cpp/ntcore_c.cpp index cac7a3391e..ee8b45eeb1 100644 --- a/ntcore/src/main/native/cpp/ntcore_c.cpp +++ b/ntcore/src/main/native/cpp/ntcore_c.cpp @@ -87,19 +87,19 @@ static void ConvertToC(const Event& in, NT_Event* out) { } static void DisposeConnectionInfo(NT_ConnectionInfo* info) { - std::free(info->remote_id.str); - std::free(info->remote_ip.str); + WPI_FreeString(&info->remote_id); + WPI_FreeString(&info->remote_ip); } static void DisposeTopicInfo(NT_TopicInfo* info) { - std::free(info->name.str); - std::free(info->type_str.str); - std::free(info->properties.str); + WPI_FreeString(&info->name); + WPI_FreeString(&info->type_str); + WPI_FreeString(&info->properties); } static void DisposeLogMessage(NT_LogMessage* msg) { - std::free(msg->filename); - std::free(msg->message); + WPI_FreeString(&msg->filename); + WPI_FreeString(&msg->message); } static void DisposeEvent(NT_Event* event) { @@ -156,15 +156,12 @@ NT_Inst NT_GetInstanceFromHandle(NT_Handle handle) { * Table Functions */ -NT_Entry NT_GetEntry(NT_Inst inst, const char* name, size_t name_len) { - return nt::GetEntry(inst, {name, name_len}); +NT_Entry NT_GetEntry(NT_Inst inst, const struct WPI_String* name) { + return nt::GetEntry(inst, wpi::to_string_view(name)); } -char* NT_GetEntryName(NT_Entry entry, size_t* name_len) { - struct NT_String v_name; - nt::ConvertToC(nt::GetEntryName(entry), &v_name); - *name_len = v_name.len; - return v_name.str; +void NT_GetEntryName(NT_Entry entry, struct WPI_String* name) { + nt::ConvertToC(nt::GetEntryName(entry), name); } enum NT_Type NT_GetEntryType(NT_Entry entry) { @@ -218,41 +215,41 @@ struct NT_Value* NT_ReadQueueValueType(NT_Handle subentry, unsigned int types, return ConvertToC(nt::ReadQueueValue(subentry, types), count); } -NT_Topic* NT_GetTopics(NT_Inst inst, const char* prefix, size_t prefix_len, +NT_Topic* NT_GetTopics(NT_Inst inst, const struct WPI_String* prefix, unsigned int types, size_t* count) { - auto info_v = nt::GetTopics(inst, {prefix, prefix_len}, types); + auto info_v = nt::GetTopics(inst, wpi::to_string_view(prefix), types); return ConvertToC(info_v, count); } -NT_Topic* NT_GetTopicsStr(NT_Inst inst, const char* prefix, size_t prefix_len, - const char* const* types, size_t types_len, +NT_Topic* NT_GetTopicsStr(NT_Inst inst, const struct WPI_String* prefix, + const struct WPI_String* types, size_t types_len, size_t* count) { wpi::SmallVector typesCpp; typesCpp.reserve(types_len); for (size_t i = 0; i < types_len; ++i) { - typesCpp.emplace_back(types[i]); + typesCpp.emplace_back(wpi::to_string_view(&types[i])); } - auto info_v = nt::GetTopics(inst, {prefix, prefix_len}, typesCpp); + auto info_v = nt::GetTopics(inst, wpi::to_string_view(prefix), typesCpp); return ConvertToC(info_v, count); } -struct NT_TopicInfo* NT_GetTopicInfos(NT_Inst inst, const char* prefix, - size_t prefix_len, unsigned int types, - size_t* count) { - auto info_v = nt::GetTopicInfo(inst, {prefix, prefix_len}, types); +struct NT_TopicInfo* NT_GetTopicInfos(NT_Inst inst, + const struct WPI_String* prefix, + unsigned int types, size_t* count) { + auto info_v = nt::GetTopicInfo(inst, wpi::to_string_view(prefix), types); return ConvertToC(info_v, count); } -struct NT_TopicInfo* NT_GetTopicInfosStr(NT_Inst inst, const char* prefix, - size_t prefix_len, - const char* const* types, +struct NT_TopicInfo* NT_GetTopicInfosStr(NT_Inst inst, + const struct WPI_String* prefix, + const struct WPI_String* types, size_t types_len, size_t* count) { wpi::SmallVector typesCpp; typesCpp.reserve(types_len); for (size_t i = 0; i < types_len; ++i) { - typesCpp.emplace_back(types[i]); + typesCpp.emplace_back(wpi::to_string_view(&types[i])); } - auto info_v = nt::GetTopicInfo(inst, {prefix, prefix_len}, typesCpp); + auto info_v = nt::GetTopicInfo(inst, wpi::to_string_view(prefix), typesCpp); return ConvertToC(info_v, count); } @@ -265,32 +262,20 @@ NT_Bool NT_GetTopicInfo(NT_Topic topic, struct NT_TopicInfo* info) { return true; } -NT_Topic NT_GetTopic(NT_Inst inst, const char* name, size_t name_len) { - return nt::GetTopic(inst, std::string_view{name, name_len}); +NT_Topic NT_GetTopic(NT_Inst inst, const struct WPI_String* name) { + return nt::GetTopic(inst, wpi::to_string_view(name)); } -char* NT_GetTopicName(NT_Topic topic, size_t* name_len) { - auto name = nt::GetTopicName(topic); - if (name.empty()) { - *name_len = 0; - return nullptr; - } - struct NT_String v_name; - nt::ConvertToC(name, &v_name); - *name_len = v_name.len; - return v_name.str; +void NT_GetTopicName(NT_Topic topic, struct WPI_String* name) { + nt::ConvertToC(nt::GetTopicName(topic), name); } NT_Type NT_GetTopicType(NT_Topic topic) { return nt::GetTopicType(topic); } -char* NT_GetTopicTypeString(NT_Topic topic, size_t* type_len) { - auto type = nt::GetTopicTypeString(topic); - struct NT_String v_type; - nt::ConvertToC(type, &v_type); - *type_len = v_type.len; - return v_type.str; +void NT_GetTopicTypeString(NT_Topic topic, struct WPI_String* type) { + nt::ConvertToC(nt::GetTopicTypeString(topic), type); } void NT_SetTopicPersistent(NT_Topic topic, NT_Bool value) { @@ -321,87 +306,91 @@ NT_Bool NT_GetTopicExists(NT_Handle handle) { return nt::GetTopicExists(handle); } -char* NT_GetTopicProperty(NT_Topic topic, const char* name, size_t* len) { - wpi::json j = nt::GetTopicProperty(topic, name); - struct NT_String v; - nt::ConvertToC(j.dump(), &v); - *len = v.len; - return v.str; +void NT_GetTopicProperty(NT_Topic topic, const struct WPI_String* name, + struct WPI_String* prop) { + wpi::json j = nt::GetTopicProperty(topic, wpi::to_string_view(name)); + nt::ConvertToC(j.dump(), prop); } -NT_Bool NT_SetTopicProperty(NT_Topic topic, const char* name, - const char* value) { +NT_Bool NT_SetTopicProperty(NT_Topic topic, const struct WPI_String* name, + const struct WPI_String* value) { wpi::json j; try { - j = wpi::json::parse(value); + j = wpi::json::parse(wpi::to_string_view(value)); } catch (wpi::json::parse_error&) { return false; } - nt::SetTopicProperty(topic, name, j); + nt::SetTopicProperty(topic, wpi::to_string_view(name), j); return true; } -void NT_DeleteTopicProperty(NT_Topic topic, const char* name) { - nt::DeleteTopicProperty(topic, name); +void NT_DeleteTopicProperty(NT_Topic topic, const struct WPI_String* name) { + nt::DeleteTopicProperty(topic, wpi::to_string_view(name)); } -char* NT_GetTopicProperties(NT_Topic topic, size_t* len) { +void NT_GetTopicProperties(NT_Topic topic, struct WPI_String* property) { wpi::json j = nt::GetTopicProperties(topic); - struct NT_String v; - nt::ConvertToC(j.dump(), &v); - *len = v.len; - return v.str; + nt::ConvertToC(j.dump(), property); } -NT_Bool NT_SetTopicProperties(NT_Topic topic, const char* properties) { +NT_Bool NT_SetTopicProperties(NT_Topic topic, + const struct WPI_String* properties) { wpi::json j; try { - j = wpi::json::parse(properties); + j = wpi::json::parse(wpi::to_string_view(properties)); } catch (wpi::json::parse_error&) { return false; } return nt::SetTopicProperties(topic, j); } -NT_Subscriber NT_Subscribe(NT_Topic topic, NT_Type type, const char* typeStr, +NT_Subscriber NT_Subscribe(NT_Topic topic, NT_Type type, + const struct WPI_String* typeStr, const struct NT_PubSubOptions* options) { - return nt::Subscribe(topic, type, typeStr, ConvertToCpp(options)); + return nt::Subscribe(topic, type, wpi::to_string_view(typeStr), + ConvertToCpp(options)); } void NT_Unsubscribe(NT_Subscriber sub) { return nt::Unsubscribe(sub); } -NT_Publisher NT_Publish(NT_Topic topic, NT_Type type, const char* typeStr, +NT_Publisher NT_Publish(NT_Topic topic, NT_Type type, + const struct WPI_String* typeStr, const struct NT_PubSubOptions* options) { - return nt::Publish(topic, type, typeStr, ConvertToCpp(options)); + return nt::Publish(topic, type, wpi::to_string_view(typeStr), + ConvertToCpp(options)); } -NT_Publisher NT_PublishEx(NT_Topic topic, NT_Type type, const char* typeStr, - const char* properties, +NT_Publisher NT_PublishEx(NT_Topic topic, NT_Type type, + const struct WPI_String* typeStr, + const struct WPI_String* properties, const struct NT_PubSubOptions* options) { wpi::json j; - if (properties[0] == '\0') { + if (properties->len == 0) { // gracefully handle empty string j = wpi::json::object(); } else { try { - j = wpi::json::parse(properties); + j = wpi::json::parse(wpi::to_string_view(properties)); } catch (wpi::json::parse_error&) { return {}; } } - return nt::PublishEx(topic, type, typeStr, j, ConvertToCpp(options)); + return nt::PublishEx(topic, type, wpi::to_string_view(typeStr), j, + ConvertToCpp(options)); } void NT_Unpublish(NT_Handle pubentry) { return nt::Unpublish(pubentry); } -NT_Entry NT_GetEntryEx(NT_Topic topic, NT_Type type, const char* typeStr, +NT_Entry NT_GetEntryEx(NT_Topic topic, NT_Type type, + const struct WPI_String* typeStr, const struct NT_PubSubOptions* options) { - return nt::GetEntry(topic, type, typeStr, ConvertToCpp(options)); + return nt::GetEntry(topic, type, wpi::to_string_view(typeStr), + ConvertToCpp(options)); } void NT_ReleaseEntry(NT_Entry entry) { @@ -441,10 +430,10 @@ NT_Bool NT_WaitForListenerQueue(NT_Handle handle, double timeout) { return nt::WaitForListenerQueue(handle, timeout); } -NT_Listener NT_AddListenerSingle(NT_Inst inst, const char* prefix, - size_t prefix_len, unsigned int mask, - void* data, NT_ListenerCallback callback) { - std::string_view p{prefix, prefix_len}; +NT_Listener NT_AddListenerSingle(NT_Inst inst, const struct WPI_String* prefix, + unsigned int mask, void* data, + NT_ListenerCallback callback) { + std::string_view p = wpi::to_string_view(prefix); return nt::AddListener(inst, {{p}}, mask, [=](auto& event) { NT_Event event_c; ConvertToC(event, &event_c); @@ -453,7 +442,8 @@ NT_Listener NT_AddListenerSingle(NT_Inst inst, const char* prefix, }); } -NT_Listener NT_AddListenerMultiple(NT_Inst inst, const NT_String* prefixes, +NT_Listener NT_AddListenerMultiple(NT_Inst inst, + const struct WPI_String* prefixes, size_t prefixes_len, unsigned int mask, void* data, NT_ListenerCallback callback) { wpi::SmallVector p; @@ -480,14 +470,14 @@ NT_Listener NT_AddListener(NT_Topic topic, unsigned int mask, void* data, } NT_Listener NT_AddPolledListenerSingle(NT_ListenerPoller poller, - const char* prefix, size_t prefix_len, + const struct WPI_String* prefix, unsigned int mask) { - std::string_view p{prefix, prefix_len}; + std::string_view p = wpi::to_string_view(prefix); return nt::AddPolledListener(poller, {{p}}, mask); } NT_Listener NT_AddPolledListenerMultiple(NT_ListenerPoller poller, - const NT_String* prefixes, + const struct WPI_String* prefixes, size_t prefixes_len, unsigned int mask) { wpi::SmallVector p; @@ -519,38 +509,42 @@ void NT_StopLocal(NT_Inst inst) { nt::StopLocal(inst); } -void NT_StartServer(NT_Inst inst, const char* persist_filename, - const char* listen_address, unsigned int port3, +void NT_StartServer(NT_Inst inst, const struct WPI_String* persist_filename, + const struct WPI_String* listen_address, unsigned int port3, unsigned int port4) { - nt::StartServer(inst, persist_filename, listen_address, port3, port4); + nt::StartServer(inst, wpi::to_string_view(persist_filename), + wpi::to_string_view(listen_address), port3, port4); } void NT_StopServer(NT_Inst inst) { nt::StopServer(inst); } -void NT_StartClient3(NT_Inst inst, const char* identity) { - nt::StartClient3(inst, identity); +void NT_StartClient3(NT_Inst inst, const struct WPI_String* identity) { + nt::StartClient3(inst, wpi::to_string_view(identity)); } -void NT_StartClient4(NT_Inst inst, const char* identity) { - nt::StartClient4(inst, identity); +void NT_StartClient4(NT_Inst inst, const struct WPI_String* identity) { + nt::StartClient4(inst, wpi::to_string_view(identity)); } void NT_StopClient(NT_Inst inst) { nt::StopClient(inst); } -void NT_SetServer(NT_Inst inst, const char* server_name, unsigned int port) { - nt::SetServer(inst, server_name, port); +void NT_SetServer(NT_Inst inst, const struct WPI_String* server_name, + unsigned int port) { + nt::SetServer(inst, wpi::to_string_view(server_name), port); } -void NT_SetServerMulti(NT_Inst inst, size_t count, const char** server_names, +void NT_SetServerMulti(NT_Inst inst, size_t count, + const struct WPI_String* server_names, const unsigned int* ports) { std::vector> servers; servers.reserve(count); for (size_t i = 0; i < count; ++i) { - servers.emplace_back(std::make_pair(server_names[i], ports[i])); + servers.emplace_back( + std::make_pair(wpi::to_string_view(&server_names[i]), ports[i])); } nt::SetServer(inst, servers); } @@ -611,20 +605,22 @@ void NT_SetNow(int64_t timestamp) { } NT_DataLogger NT_StartEntryDataLog(NT_Inst inst, struct WPI_DataLog* log, - const char* prefix, const char* logPrefix) { + const struct WPI_String* prefix, + const struct WPI_String* logPrefix) { return nt::StartEntryDataLog(inst, *reinterpret_cast(log), - prefix, logPrefix); + wpi::to_string_view(prefix), + wpi::to_string_view(logPrefix)); } void NT_StopEntryDataLog(NT_DataLogger logger) { nt::StopEntryDataLog(logger); } -NT_ConnectionDataLogger NT_StartConnectionDataLog(NT_Inst inst, - struct WPI_DataLog* log, - const char* name) { - return nt::StartConnectionDataLog( - inst, *reinterpret_cast(log), name); +NT_ConnectionDataLogger NT_StartConnectionDataLog( + NT_Inst inst, struct WPI_DataLog* log, const struct WPI_String* name) { + return nt::StartConnectionDataLog(inst, + *reinterpret_cast(log), + wpi::to_string_view(name)); } void NT_StopConnectionDataLog(NT_ConnectionDataLogger logger) { @@ -647,13 +643,15 @@ NT_Listener NT_AddPolledLogger(NT_ListenerPoller poller, unsigned int min_level, return nt::AddPolledLogger(poller, min_level, max_level); } -NT_Bool NT_HasSchema(NT_Inst inst, const char* name) { - return nt::HasSchema(inst, name); +NT_Bool NT_HasSchema(NT_Inst inst, const struct WPI_String* name) { + return nt::HasSchema(inst, wpi::to_string_view(name)); } -void NT_AddSchema(NT_Inst inst, const char* name, const char* type, - const uint8_t* schema, size_t schemaSize) { - nt::AddSchema(inst, name, type, {schema, schemaSize}); +void NT_AddSchema(NT_Inst inst, const struct WPI_String* name, + const struct WPI_String* type, const uint8_t* schema, + size_t schemaSize) { + nt::AddSchema(inst, wpi::to_string_view(name), wpi::to_string_view(type), + {schema, schemaSize}); } void NT_DisposeValue(NT_Value* value) { @@ -665,7 +663,7 @@ void NT_DisposeValue(NT_Value* value) { case NT_DOUBLE: break; case NT_STRING: - std::free(value->data.v_string.str); + WPI_FreeString(&value->data.v_string); break; case NT_RAW: std::free(value->data.v_raw.data); @@ -684,7 +682,7 @@ void NT_DisposeValue(NT_Value* value) { break; case NT_STRING_ARRAY: { for (size_t i = 0; i < value->data.arr_string.size; i++) { - std::free(value->data.arr_string.arr[i].str); + WPI_FreeString(&value->data.arr_string.arr[i]); } std::free(value->data.arr_string.arr); break; @@ -703,17 +701,6 @@ void NT_InitValue(NT_Value* value) { value->server_time = 0; } -void NT_DisposeString(NT_String* str) { - std::free(str->str); - str->str = nullptr; - str->len = 0; -} - -void NT_InitString(NT_String* str) { - str->str = nullptr; - str->len = 0; -} - void NT_DisposeValueArray(struct NT_Value* arr, size_t count) { for (size_t i = 0; i < count; ++i) { NT_DisposeValue(&arr[i]); @@ -781,12 +768,6 @@ double* NT_AllocateDoubleArray(size_t size) { return retVal; } -struct NT_String* NT_AllocateStringArray(size_t size) { - NT_String* retVal = - static_cast(wpi::safe_malloc(size * sizeof(NT_String))); - return retVal; -} - void NT_FreeCharArray(char* v_char) { std::free(v_char); } @@ -802,12 +783,6 @@ void NT_FreeFloatArray(float* v_float) { void NT_FreeDoubleArray(double* v_double) { std::free(v_double); } -void NT_FreeStringArray(struct NT_String* v_string, size_t arr_size) { - for (size_t i = 0; i < arr_size; ++i) { - std::free(v_string[i].str); - } - std::free(v_string); -} enum NT_Type NT_GetValueType(const struct NT_Value* value) { if (!value) { @@ -938,20 +913,19 @@ double* NT_GetValueDoubleArray(const struct NT_Value* value, return arr; } -NT_String* NT_GetValueStringArray(const struct NT_Value* value, - uint64_t* last_change, size_t* arr_size) { +struct WPI_String* NT_GetValueStringArray(const struct NT_Value* value, + uint64_t* last_change, + size_t* arr_size) { if (!value || value->type != NT_Type::NT_STRING_ARRAY) { return nullptr; } *last_change = value->last_change; *arr_size = value->data.arr_string.size; - NT_String* arr = static_cast( - wpi::safe_malloc(value->data.arr_string.size * sizeof(NT_String))); + struct WPI_String* arr = WPI_AllocateStringArray(value->data.arr_string.size); for (size_t i = 0; i < value->data.arr_string.size; ++i) { size_t len = value->data.arr_string.arr[i].len; - arr[i].len = len; - arr[i].str = static_cast(wpi::safe_malloc(len + 1)); - std::memcpy(arr[i].str, value->data.arr_string.arr[i].str, len + 1); + auto write = WPI_AllocateString(&arr[i], len); + std::memcpy(write, value->data.arr_string.arr[i].str, len); } return arr; } diff --git a/ntcore/src/main/native/cpp/ntcore_cpp.cpp b/ntcore/src/main/native/cpp/ntcore_cpp.cpp index 33920ea48f..75f20a6db5 100644 --- a/ntcore/src/main/native/cpp/ntcore_cpp.cpp +++ b/ntcore/src/main/native/cpp/ntcore_cpp.cpp @@ -630,7 +630,7 @@ void StopLocal(NT_Inst inst) { } void StartServer(NT_Inst inst, std::string_view persist_filename, - const char* listen_address, unsigned int port3, + std::string_view listen_address, unsigned int port3, unsigned int port4) { if (auto ii = InstanceImpl::GetTyped(inst, Handle::kInstance)) { ii->StartServer(persist_filename, listen_address, port3, port4); @@ -661,7 +661,7 @@ void StopClient(NT_Inst inst) { } } -void SetServer(NT_Inst inst, const char* server_name, unsigned int port) { +void SetServer(NT_Inst inst, std::string_view server_name, unsigned int port) { SetServer(inst, {{{server_name, port}}}); } diff --git a/ntcore/src/main/native/cpp/ntcore_meta_c.cpp b/ntcore/src/main/native/cpp/ntcore_meta_c.cpp index 889254e1b7..6c6c026ecb 100644 --- a/ntcore/src/main/native/cpp/ntcore_meta_c.cpp +++ b/ntcore/src/main/native/cpp/ntcore_meta_c.cpp @@ -40,7 +40,7 @@ static void ConvertToC(const ClientPublisher& in, static void ConvertToC(const ClientSubscriber& in, NT_Meta_ClientSubscriber* out) { out->uid = in.uid; - out->topics = ConvertToC(in.topics, &out->topicsCount); + out->topics = ConvertToC(in.topics, &out->topicsCount); ConvertToC(in.options, &out->options); } @@ -98,7 +98,7 @@ struct NT_Meta_Client* NT_Meta_DecodeClients(const uint8_t* data, size_t size, void NT_Meta_FreeTopicPublishers(struct NT_Meta_TopicPublisher* arr, size_t count) { for (size_t i = 0; i < count; ++i) { - std::free(arr[i].client.str); + WPI_FreeString(&arr[i].client); } std::free(arr); } @@ -106,7 +106,7 @@ void NT_Meta_FreeTopicPublishers(struct NT_Meta_TopicPublisher* arr, void NT_Meta_FreeTopicSubscribers(struct NT_Meta_TopicSubscriber* arr, size_t count) { for (size_t i = 0; i < count; ++i) { - std::free(arr[i].client.str); + WPI_FreeString(&arr[i].client); } std::free(arr); } @@ -114,7 +114,7 @@ void NT_Meta_FreeTopicSubscribers(struct NT_Meta_TopicSubscriber* arr, void NT_Meta_FreeClientPublishers(struct NT_Meta_ClientPublisher* arr, size_t count) { for (size_t i = 0; i < count; ++i) { - std::free(arr[i].topic.str); + WPI_FreeString(&arr[i].topic); } std::free(arr); } @@ -122,15 +122,15 @@ void NT_Meta_FreeClientPublishers(struct NT_Meta_ClientPublisher* arr, void NT_Meta_FreeClientSubscribers(struct NT_Meta_ClientSubscriber* arr, size_t count) { for (size_t i = 0; i < count; ++i) { - NT_FreeStringArray(arr[i].topics, arr[i].topicsCount); + WPI_FreeStringArray(arr[i].topics, arr[i].topicsCount); } std::free(arr); } void NT_Meta_FreeClients(struct NT_Meta_Client* arr, size_t count) { for (size_t i = 0; i < count; ++i) { - std::free(arr[i].id.str); - std::free(arr[i].conn.str); + WPI_FreeString(&arr[i].id); + WPI_FreeString(&arr[i].conn); } std::free(arr); } diff --git a/ntcore/src/main/native/cpp/ntcore_test.cpp b/ntcore/src/main/native/cpp/ntcore_test.cpp index 2a07867e95..4364370668 100644 --- a/ntcore/src/main/native/cpp/ntcore_test.cpp +++ b/ntcore/src/main/native/cpp/ntcore_test.cpp @@ -11,11 +11,11 @@ #include "Value_internal.h" extern "C" { -struct NT_String* NT_GetStringForTesting(const char* str, int* struct_size) { - struct NT_String* strout = - static_cast(wpi::safe_calloc(1, sizeof(NT_String))); +struct WPI_String* NT_GetStringForTesting(const char* str, int* struct_size) { + struct WPI_String* strout = + static_cast(wpi::safe_calloc(1, sizeof(WPI_String))); nt::ConvertToC(str, strout); - *struct_size = sizeof(NT_String); + *struct_size = sizeof(WPI_String); return strout; } @@ -33,8 +33,9 @@ struct NT_TopicInfo* NT_GetTopicInfoForTesting(const char* name, } void NT_FreeTopicInfoForTesting(struct NT_TopicInfo* info) { - std::free(info->name.str); - std::free(info->type_str.str); + WPI_FreeString(&info->name); + WPI_FreeString(&info->type_str); + WPI_FreeString(&info->properties); std::free(info); } @@ -53,8 +54,8 @@ struct NT_ConnectionInfo* NT_GetConnectionInfoForTesting( } void NT_FreeConnectionInfoForTesting(struct NT_ConnectionInfo* info) { - std::free(info->remote_id.str); - std::free(info->remote_ip.str); + WPI_FreeString(&info->remote_id); + WPI_FreeString(&info->remote_ip); std::free(info); } @@ -136,21 +137,19 @@ struct NT_Value* NT_GetValueDoubleArrayForTesting(uint64_t last_change, } struct NT_Value* NT_GetValueStringArrayForTesting(uint64_t last_change, - const struct NT_String* arr, + const struct WPI_String* arr, size_t array_len, int* struct_size) { struct NT_Value* value = static_cast(wpi::safe_calloc(1, sizeof(NT_Value))); value->type = NT_BOOLEAN; value->last_change = last_change; - value->data.arr_string.arr = NT_AllocateStringArray(array_len); + value->data.arr_string.arr = WPI_AllocateStringArray(array_len); value->data.arr_string.size = array_len; for (size_t i = 0; i < value->data.arr_string.size; ++i) { size_t len = arr[i].len; - value->data.arr_string.arr[i].len = len; - value->data.arr_string.arr[i].str = - static_cast(wpi::safe_malloc(len + 1)); - std::memcpy(value->data.arr_string.arr[i].str, arr[i].str, len + 1); + auto write = WPI_AllocateString(&value->data.arr_string.arr[i], len); + std::memcpy(write, arr[i].str, len); } *struct_size = sizeof(NT_Value); return value; diff --git a/ntcore/src/main/native/include/networktables/NetworkTableInstance.h b/ntcore/src/main/native/include/networktables/NetworkTableInstance.h index cf8f8e116d..60cf7841de 100644 --- a/ntcore/src/main/native/include/networktables/NetworkTableInstance.h +++ b/ntcore/src/main/native/include/networktables/NetworkTableInstance.h @@ -596,10 +596,10 @@ class NetworkTableInstance final { /** * Sets server address and port for client (without restarting client). * - * @param server_name server name (UTF-8 string, null terminated) + * @param server_name server name (UTF-8 string) * @param port port to communicate over (0 = default) */ - void SetServer(const char* server_name, unsigned int port = 0); + void SetServer(std::string_view server_name, unsigned int port = 0); /** * Sets server addresses and ports for client (without restarting client). diff --git a/ntcore/src/main/native/include/networktables/NetworkTableInstance.inc b/ntcore/src/main/native/include/networktables/NetworkTableInstance.inc index e583e59702..20b5c0b58a 100644 --- a/ntcore/src/main/native/include/networktables/NetworkTableInstance.inc +++ b/ntcore/src/main/native/include/networktables/NetworkTableInstance.inc @@ -168,7 +168,7 @@ inline void NetworkTableInstance::StopClient() { ::nt::StopClient(m_handle); } -inline void NetworkTableInstance::SetServer(const char* server_name, +inline void NetworkTableInstance::SetServer(std::string_view server_name, unsigned int port) { ::nt::SetServer(m_handle, server_name, port); } diff --git a/ntcore/src/main/native/include/ntcore_c.h b/ntcore/src/main/native/include/ntcore_c.h index 67efd76611..e918aaafa0 100644 --- a/ntcore/src/main/native/include/ntcore_c.h +++ b/ntcore/src/main/native/include/ntcore_c.h @@ -6,6 +6,8 @@ #include +#include + #ifdef __cplusplus #include #else @@ -129,23 +131,6 @@ enum NT_EventFlags { * Structures */ -/** A NetworkTables string. */ -struct NT_String { - /** - * String contents (UTF-8). - * The string is NOT required to be zero-terminated. - * When returned by the library, this is zero-terminated and allocated with - * std::malloc(). - */ - char* str; - - /** - * Length of the string in bytes. If the string happens to be zero - * terminated, this does not include the zero-termination. - */ - size_t len; -}; - /** NetworkTables Entry Value. Note this is a typed union. */ struct NT_Value { enum NT_Type type; @@ -156,7 +141,7 @@ struct NT_Value { int64_t v_int; float v_float; double v_double; - struct NT_String v_string; + struct WPI_String v_string; struct { uint8_t* data; size_t size; @@ -178,7 +163,7 @@ struct NT_Value { size_t size; } arr_int; struct { - struct NT_String* arr; + struct WPI_String* arr; size_t size; } arr_string; } data; @@ -190,16 +175,16 @@ struct NT_TopicInfo { NT_Topic topic; /** Topic name */ - struct NT_String name; + struct WPI_String name; /** Topic type */ enum NT_Type type; /** Topic type string */ - struct NT_String type_str; + struct WPI_String type_str; /** Topic properties JSON string */ - struct NT_String properties; + struct WPI_String properties; }; /** NetworkTables Connection Information */ @@ -207,10 +192,10 @@ struct NT_ConnectionInfo { /** * The remote identifier (as set on the remote node by NT_StartClient4(). */ - struct NT_String remote_id; + struct WPI_String remote_id; /** The IP address of the remote node. */ - struct NT_String remote_ip; + struct WPI_String remote_ip; /** The port number of the remote node. */ unsigned int remote_port; @@ -246,13 +231,13 @@ struct NT_LogMessage { unsigned int level; /** The filename of the source file that generated the message. */ - char* filename; + struct WPI_String filename; /** The line number in the source file that generated the message. */ unsigned int line; /** The message. */ - char* message; + struct WPI_String message; }; /** NetworkTables time sync event data. */ @@ -425,20 +410,18 @@ NT_Inst NT_GetInstanceFromHandle(NT_Handle handle); * * @param inst instance handle * @param name entry name (UTF-8 string) - * @param name_len length of name in bytes * @return entry handle */ -NT_Entry NT_GetEntry(NT_Inst inst, const char* name, size_t name_len); +NT_Entry NT_GetEntry(NT_Inst inst, const struct WPI_String* name); /** * Gets the name of the specified entry. * Returns an empty string if the handle is invalid. * * @param entry entry handle - * @param name_len length of the returned string (output parameter) - * @return Entry name + * @param name entry name (output parameter) */ -char* NT_GetEntryName(NT_Entry entry, size_t* name_len); +void NT_GetEntryName(NT_Entry entry, struct WPI_String* name); /** * Gets the type for the specified key, or unassigned if non existent. @@ -576,13 +559,12 @@ struct NT_Value* NT_ReadQueueValueType(NT_Handle subentry, unsigned int types, * @param inst instance handle * @param prefix name required prefix; only topics whose name * starts with this string are returned - * @param prefix_len length of prefix in bytes * @param types bitmask of NT_Type values; 0 is treated specially * as a "don't care" * @param count output parameter; set to length of returned array * @return Array of topic handles. */ -NT_Topic* NT_GetTopics(NT_Inst inst, const char* prefix, size_t prefix_len, +NT_Topic* NT_GetTopics(NT_Inst inst, const struct WPI_String* prefix, unsigned int types, size_t* count); /** @@ -595,14 +577,13 @@ NT_Topic* NT_GetTopics(NT_Inst inst, const char* prefix, size_t prefix_len, * @param inst instance handle * @param prefix name required prefix; only topics whose name * starts with this string are returned - * @param prefix_len length of prefix in bytes * @param types array of type strings * @param types_len number of elements in types array * @param count output parameter; set to length of returned array * @return Array of topic handles. */ -NT_Topic* NT_GetTopicsStr(NT_Inst inst, const char* prefix, size_t prefix_len, - const char* const* types, size_t types_len, +NT_Topic* NT_GetTopicsStr(NT_Inst inst, const struct WPI_String* prefix, + const struct WPI_String* types, size_t types_len, size_t* count); /** @@ -615,15 +596,14 @@ NT_Topic* NT_GetTopicsStr(NT_Inst inst, const char* prefix, size_t prefix_len, * @param inst instance handle * @param prefix name required prefix; only topics whose name * starts with this string are returned - * @param prefix_len length of prefix in bytes * @param types bitmask of NT_Type values; 0 is treated specially * as a "don't care" * @param count output parameter; set to length of returned array * @return Array of topic information. */ -struct NT_TopicInfo* NT_GetTopicInfos(NT_Inst inst, const char* prefix, - size_t prefix_len, unsigned int types, - size_t* count); +struct NT_TopicInfo* NT_GetTopicInfos(NT_Inst inst, + const struct WPI_String* prefix, + unsigned int types, size_t* count); /** * Get Topics. @@ -635,15 +615,14 @@ struct NT_TopicInfo* NT_GetTopicInfos(NT_Inst inst, const char* prefix, * @param inst instance handle * @param prefix name required prefix; only topics whose name * starts with this string are returned - * @param prefix_len length of prefix in bytes * @param types array of type strings * @param types_len number of elements in types array * @param count output parameter; set to length of returned array * @return Array of topic information. */ -struct NT_TopicInfo* NT_GetTopicInfosStr(NT_Inst inst, const char* prefix, - size_t prefix_len, - const char* const* types, +struct NT_TopicInfo* NT_GetTopicInfosStr(NT_Inst inst, + const struct WPI_String* prefix, + const struct WPI_String* types, size_t types_len, size_t* count); /** @@ -664,19 +643,18 @@ NT_Bool NT_GetTopicInfo(NT_Topic topic, struct NT_TopicInfo* info); * * @param inst instance handle * @param name topic name - * @param name_len length of topic name in bytes * @return Topic handle. */ -NT_Topic NT_GetTopic(NT_Inst inst, const char* name, size_t name_len); +NT_Topic NT_GetTopic(NT_Inst inst, const struct WPI_String* name); /** * Gets the name of the specified topic. * * @param topic topic handle - * @param name_len length of topic name (output) - * @return Topic name; returns NULL and name_len=0 if the handle is invalid. + * @param name topic name (output); return length of 0 and nullptr if + * handle is invalid. */ -char* NT_GetTopicName(NT_Topic topic, size_t* name_len); +void NT_GetTopicName(NT_Topic topic, struct WPI_String* name); /** * Gets the type for the specified topic, or unassigned if non existent. @@ -690,11 +668,10 @@ enum NT_Type NT_GetTopicType(NT_Topic topic); * Gets the type string for the specified topic. This may have more information * than the numeric type (especially for raw values). * - * @param topic topic handle - * @param type_len length of type string (output) - * @return Topic type string; returns NULL if non-existent + * @param topic topic handle + * @param type topic type string (output) */ -char* NT_GetTopicTypeString(NT_Topic topic, size_t* type_len); +void NT_GetTopicTypeString(NT_Topic topic, struct WPI_String* type); /** * Sets the persistent property of a topic. If true, the stored value is @@ -761,10 +738,10 @@ NT_Bool NT_GetTopicExists(NT_Handle handle); * * @param topic topic handle * @param name property name - * @param len length of returned string (output) - * @return JSON string; empty string if the property does not exist. + * @param property JSON string (output) */ -char* NT_GetTopicProperty(NT_Topic topic, const char* name, size_t* len); +void NT_GetTopicProperty(NT_Topic topic, const struct WPI_String* name, + struct WPI_String* property); /** * Sets a property value. @@ -773,8 +750,8 @@ char* NT_GetTopicProperty(NT_Topic topic, const char* name, size_t* len); * @param name property name * @param value property value (JSON string) */ -NT_Bool NT_SetTopicProperty(NT_Topic topic, const char* name, - const char* value); +NT_Bool NT_SetTopicProperty(NT_Topic topic, const struct WPI_String* name, + const struct WPI_String* value); /** * Deletes a property. Has no effect if the property does not exist. @@ -782,17 +759,16 @@ NT_Bool NT_SetTopicProperty(NT_Topic topic, const char* name, * @param topic topic handle * @param name property name */ -void NT_DeleteTopicProperty(NT_Topic topic, const char* name); +void NT_DeleteTopicProperty(NT_Topic topic, const struct WPI_String* name); /** * Gets all topic properties as a JSON string. Each key in the object * is the property name, and the corresponding value is the property value. * * @param topic topic handle - * @param len length of returned string (output) - * @return JSON string + * @param properties JSON string (output) */ -char* NT_GetTopicProperties(NT_Topic topic, size_t* len); +void NT_GetTopicProperties(NT_Topic topic, struct WPI_String* properties); /** * Updates multiple topic properties. Each key in the passed-in JSON object is @@ -804,7 +780,8 @@ char* NT_GetTopicProperties(NT_Topic topic, size_t* len); * @param properties JSON object string with keys to add/update/delete * @return False if properties are not a valid JSON object */ -NT_Bool NT_SetTopicProperties(NT_Topic topic, const char* properties); +NT_Bool NT_SetTopicProperties(NT_Topic topic, + const struct WPI_String* properties); /** * Creates a new subscriber to value changes on a topic. @@ -816,7 +793,7 @@ NT_Bool NT_SetTopicProperties(NT_Topic topic, const char* properties); * @return Subscriber handle */ NT_Subscriber NT_Subscribe(NT_Topic topic, enum NT_Type type, - const char* typeStr, + const struct WPI_String* typeStr, const struct NT_PubSubOptions* options); /** @@ -835,7 +812,8 @@ void NT_Unsubscribe(NT_Subscriber sub); * @param options publish options * @return Publisher handle */ -NT_Publisher NT_Publish(NT_Topic topic, enum NT_Type type, const char* typeStr, +NT_Publisher NT_Publish(NT_Topic topic, enum NT_Type type, + const struct WPI_String* typeStr, const struct NT_PubSubOptions* options); /** @@ -849,7 +827,8 @@ NT_Publisher NT_Publish(NT_Topic topic, enum NT_Type type, const char* typeStr, * @return Publisher handle */ NT_Publisher NT_PublishEx(NT_Topic topic, enum NT_Type type, - const char* typeStr, const char* properties, + const struct WPI_String* typeStr, + const struct WPI_String* properties, const struct NT_PubSubOptions* options); /** @@ -868,7 +847,8 @@ void NT_Unpublish(NT_Handle pubentry); * @param options publish options * @return Entry handle */ -NT_Entry NT_GetEntryEx(NT_Topic topic, enum NT_Type type, const char* typeStr, +NT_Entry NT_GetEntryEx(NT_Topic topic, enum NT_Type type, + const struct WPI_String* typeStr, const struct NT_PubSubOptions* options); /** @@ -912,7 +892,7 @@ NT_Topic NT_GetTopicFromHandle(NT_Handle pubsubentry); * @return subscriber handle */ NT_MultiSubscriber NT_SubscribeMultiple(NT_Inst inst, - const struct NT_String* prefixes, + const struct WPI_String* prefixes, size_t prefixes_len, const struct NT_PubSubOptions* options); @@ -996,16 +976,15 @@ NT_Bool NT_WaitForListenerQueue(NT_Handle handle, double timeout); * * @param inst Instance handle * @param prefix Topic name string prefix - * @param prefix_len Length of topic name string prefix * @param mask Bitmask of NT_EventFlags values (only topic and value events will * be generated) * @param data Data passed to callback function * @param callback Listener function * @return Listener handle */ -NT_Listener NT_AddListenerSingle(NT_Inst inst, const char* prefix, - size_t prefix_len, unsigned int mask, - void* data, NT_ListenerCallback callback); +NT_Listener NT_AddListenerSingle(NT_Inst inst, const struct WPI_String* prefix, + unsigned int mask, void* data, + NT_ListenerCallback callback); /** * Create a listener for changes to topics with names that start with any of @@ -1022,7 +1001,7 @@ NT_Listener NT_AddListenerSingle(NT_Inst inst, const char* prefix, * @return Listener handle */ NT_Listener NT_AddListenerMultiple(NT_Inst inst, - const struct NT_String* prefixes, + const struct WPI_String* prefixes, size_t prefixes_len, unsigned int mask, void* data, NT_ListenerCallback callback); @@ -1056,13 +1035,12 @@ NT_Listener NT_AddListener(NT_Handle handle, unsigned int mask, void* data, * * @param poller poller handle * @param prefix UTF-8 string prefix - * @param prefix_len Length of UTF-8 string prefix * @param mask NT_EventFlags bitmask (only topic and value events * will be generated) * @return Listener handle */ NT_Listener NT_AddPolledListenerSingle(NT_ListenerPoller poller, - const char* prefix, size_t prefix_len, + const struct WPI_String* prefix, unsigned int mask); /** @@ -1078,7 +1056,7 @@ NT_Listener NT_AddPolledListenerSingle(NT_ListenerPoller poller, * @return Listener handle */ NT_Listener NT_AddPolledListenerMultiple(NT_ListenerPoller poller, - const struct NT_String* prefixes, + const struct WPI_String* prefixes, size_t prefixes_len, unsigned int mask); @@ -1144,8 +1122,8 @@ void NT_StopLocal(NT_Inst inst); * @param port3 port to communicate over (NT3) * @param port4 port to communicate over (NT4) */ -void NT_StartServer(NT_Inst inst, const char* persist_filename, - const char* listen_address, unsigned int port3, +void NT_StartServer(NT_Inst inst, const struct WPI_String* persist_filename, + const struct WPI_String* listen_address, unsigned int port3, unsigned int port4); /** @@ -1162,7 +1140,7 @@ void NT_StopServer(NT_Inst inst); * @param inst instance handle * @param identity network identity to advertise (cannot be empty string) */ -void NT_StartClient3(NT_Inst inst, const char* identity); +void NT_StartClient3(NT_Inst inst, const struct WPI_String* identity); /** * Starts a NT4 client. Use NT_SetServer or NT_SetServerTeam to set the server @@ -1171,7 +1149,7 @@ void NT_StartClient3(NT_Inst inst, const char* identity); * @param inst instance handle * @param identity network identity to advertise (cannot be empty string) */ -void NT_StartClient4(NT_Inst inst, const char* identity); +void NT_StartClient4(NT_Inst inst, const struct WPI_String* identity); /** * Stops the client if it is running. @@ -1187,7 +1165,8 @@ void NT_StopClient(NT_Inst inst); * @param server_name server name (UTF-8 string, null terminated) * @param port port to communicate over */ -void NT_SetServer(NT_Inst inst, const char* server_name, unsigned int port); +void NT_SetServer(NT_Inst inst, const struct WPI_String* server_name, + unsigned int port); /** * Sets server addresses for client (without restarting client). @@ -1199,7 +1178,8 @@ void NT_SetServer(NT_Inst inst, const char* server_name, unsigned int port); * terminated) * @param ports array of ports to communicate over (one for each server) */ -void NT_SetServerMulti(NT_Inst inst, size_t count, const char** server_names, +void NT_SetServerMulti(NT_Inst inst, size_t count, + const struct WPI_String* server_names, const unsigned int* ports); /** @@ -1323,21 +1303,6 @@ void NT_DisposeValue(struct NT_Value* value); */ void NT_InitValue(struct NT_Value* value); -/** - * Frees string memory. - * - * @param str string to free - */ -void NT_DisposeString(struct NT_String* str); - -/** - * Initializes a NT_String. - * Sets length to zero and pointer to null. - * - * @param str string to initialize - */ -void NT_InitString(struct NT_String* str); - /** * Frees an array of NT_Values. * @@ -1429,7 +1394,8 @@ void NT_SetNow(int64_t timestamp); * @return Data logger handle */ NT_DataLogger NT_StartEntryDataLog(NT_Inst inst, struct WPI_DataLog* log, - const char* prefix, const char* logPrefix); + const struct WPI_String* prefix, + const struct WPI_String* logPrefix); /** * Stops logging entry changes to a DataLog. @@ -1447,9 +1413,8 @@ void NT_StopEntryDataLog(NT_DataLogger logger); * @param name data log entry name * @return Data logger handle */ -NT_ConnectionDataLogger NT_StartConnectionDataLog(NT_Inst inst, - struct WPI_DataLog* log, - const char* name); +NT_ConnectionDataLogger NT_StartConnectionDataLog( + NT_Inst inst, struct WPI_DataLog* log, const struct WPI_String* name); /** * Stops logging connection changes to a DataLog. @@ -1513,7 +1478,7 @@ NT_Listener NT_AddPolledLogger(NT_ListenerPoller poller, unsigned int min_level, * schema) * @return True if schema already registered */ -NT_Bool NT_HasSchema(NT_Inst inst, const char* name); +NT_Bool NT_HasSchema(NT_Inst inst, const struct WPI_String* name); /** * Registers a data schema. Data schemas provide information for how a @@ -1531,8 +1496,9 @@ NT_Bool NT_HasSchema(NT_Inst inst, const char* name); * @param schema Schema data * @param schemaSize Size of schema data */ -void NT_AddSchema(NT_Inst inst, const char* name, const char* type, - const uint8_t* schema, size_t schemaSize); +void NT_AddSchema(NT_Inst inst, const struct WPI_String* name, + const struct WPI_String* type, const uint8_t* schema, + size_t schemaSize); /** @} */ @@ -1611,19 +1577,6 @@ float* NT_AllocateFloatArray(size_t size); */ double* NT_AllocateDoubleArray(size_t size); -/** - * Allocates an array of NT_Strings. - * Note that the size is the number of elements, and not the - * specific number of bytes to allocate. That is calculated internally. - * - * @param size the number of elements the array will contain - * @return the allocated NT_String array - * - * After use, the array should be freed using the NT_FreeStringArray() - * function. - */ -struct NT_String* NT_AllocateStringArray(size_t size); - /** * Frees an array of chars. * @@ -1659,18 +1612,6 @@ void NT_FreeFloatArray(float* v_float); */ void NT_FreeDoubleArray(double* v_double); -/** - * Frees an array of NT_Strings. - * - * @param v_string pointer to the string array to free - * @param arr_size size of the string array to free - * - * Note that the individual NT_Strings in the array should NOT be - * freed before calling this. This function will free all the strings - * individually. - */ -void NT_FreeStringArray(struct NT_String* v_string, size_t arr_size); - /** @} */ /** @@ -1838,24 +1779,24 @@ double* NT_GetValueDoubleArray(const struct NT_Value* value, uint64_t* last_change, size_t* arr_size); /** - * Returns a copy of the NT_String array from the NT_Value. + * Returns a copy of the struct WPI_String array from the NT_Value. * If the NT_Value is null, or is assigned to a different type, returns null. * - * @param value NT_Value struct to get the NT_String array from + * @param value NT_Value struct to get the struct WPI_String array from * @param last_change returns time in ms since the last change in the value * @param arr_size returns the number of elements in the array - * @return pointer to the NT_String array, or null if error + * @return pointer to the struct WPI_String array, or null if error * * It is the caller's responsibility to free the array once its no longer - * needed. The NT_FreeStringArray() function is useful for this purpose. + * needed. The WPI_FreeStringArray() function is useful for this purpose. * The returned array is a copy of the array in the value, and must be - * freed separately. Note that the individual NT_Strings should not be freed, - * but the entire array should be freed at once. The NT_FreeStringArray() - * function will free all the NT_Strings. + * freed separately. Note that the individual struct WPI_Strings should not be + * freed, but the entire array should be freed at once. The + * WPI_FreeStringArray() function will free all the struct WPI_Strings. */ -struct NT_String* NT_GetValueStringArray(const struct NT_Value* value, - uint64_t* last_change, - size_t* arr_size); +struct WPI_String* NT_GetValueStringArray(const struct NT_Value* value, + uint64_t* last_change, + size_t* arr_size); /** @} */ /** @} */ @@ -1884,7 +1825,7 @@ struct NT_Meta_SubscriberOptions { * Topic publisher (as published via `$pub$`). */ struct NT_Meta_TopicPublisher { - struct NT_String client; + struct WPI_String client; uint64_t pubuid; }; @@ -1892,7 +1833,7 @@ struct NT_Meta_TopicPublisher { * Topic subscriber (as published via `$sub$`). */ struct NT_Meta_TopicSubscriber { - struct NT_String client; + struct WPI_String client; uint64_t subuid; struct NT_Meta_SubscriberOptions options; }; @@ -1902,7 +1843,7 @@ struct NT_Meta_TopicSubscriber { */ struct NT_Meta_ClientPublisher { int64_t uid; - struct NT_String topic; + struct WPI_String topic; }; /** @@ -1911,7 +1852,7 @@ struct NT_Meta_ClientPublisher { struct NT_Meta_ClientSubscriber { int64_t uid; size_t topicsCount; - struct NT_String* topics; + struct WPI_String* topics; struct NT_Meta_SubscriberOptions options; }; @@ -1919,8 +1860,8 @@ struct NT_Meta_ClientSubscriber { * Client (as published via `$clients`). */ struct NT_Meta_Client { - struct NT_String id; - struct NT_String conn; + struct WPI_String id; + struct WPI_String conn; uint16_t version; }; diff --git a/ntcore/src/main/native/include/ntcore_cpp.h b/ntcore/src/main/native/include/ntcore_cpp.h index f241f63811..226669927c 100644 --- a/ntcore/src/main/native/include/ntcore_cpp.h +++ b/ntcore/src/main/native/include/ntcore_cpp.h @@ -1056,12 +1056,12 @@ void StopLocal(NT_Inst inst); * @param persist_filename the name of the persist file to use (UTF-8 string, * null terminated) * @param listen_address the address to listen on, or null to listen on any - * address. (UTF-8 string, null terminated) + * address. (UTF-8 string) * @param port3 port to communicate over (NT3) * @param port4 port to communicate over (NT4) */ void StartServer(NT_Inst inst, std::string_view persist_filename, - const char* listen_address, unsigned int port3, + std::string_view listen_address, unsigned int port3, unsigned int port4); /** @@ -1103,7 +1103,7 @@ void StopClient(NT_Inst inst); * @param server_name server name (UTF-8 string, null terminated) * @param port port to communicate over */ -void SetServer(NT_Inst inst, const char* server_name, unsigned int port); +void SetServer(NT_Inst inst, std::string_view server_name, unsigned int port); /** * Sets server addresses for client (without restarting client). diff --git a/ntcore/src/main/native/include/ntcore_test.h b/ntcore/src/main/native/include/ntcore_test.h index 7e0244682a..bc17b6d6aa 100644 --- a/ntcore/src/main/native/include/ntcore_test.h +++ b/ntcore/src/main/native/include/ntcore_test.h @@ -14,7 +14,7 @@ extern "C" { #endif -struct NT_String* NT_GetStringForTesting(const char* str, int* struct_size); +struct WPI_String* NT_GetStringForTesting(const char* str, int* struct_size); // No need for free as one already exists in main library struct NT_EntryInfo* NT_GetEntryInfoForTesting(const char* name, @@ -54,7 +54,7 @@ struct NT_Value* NT_GetValueDoubleArrayForTesting(uint64_t last_change, int* struct_size); struct NT_Value* NT_GetValueStringArrayForTesting(uint64_t last_change, - const struct NT_String* arr, + const struct WPI_String* arr, size_t array_len, int* struct_size); // No need for free as one already exists in the main library diff --git a/ntcore/src/test/native/cpp/ValueTest.cpp b/ntcore/src/test/native/cpp/ValueTest.cpp index ba99782ff6..abb0dd5ece 100644 --- a/ntcore/src/test/native/cpp/ValueTest.cpp +++ b/ntcore/src/test/native/cpp/ValueTest.cpp @@ -84,7 +84,7 @@ TEST_F(ValueTest, String) { NT_InitValue(&cv); ConvertToC(v, &cv); ASSERT_EQ(NT_STRING, cv.type); - ASSERT_EQ("hello"sv, cv.data.v_string.str); + ASSERT_EQ("hello"sv, wpi::to_string_view(&cv.data.v_string)); ASSERT_EQ(5u, cv.data.v_string.len); v = Value::MakeString("goodbye"); @@ -93,7 +93,7 @@ TEST_F(ValueTest, String) { NT_DisposeValue(&cv); ConvertToC(v, &cv); ASSERT_EQ(NT_STRING, cv.type); - ASSERT_EQ("goodbye"sv, cv.data.v_string.str); + ASSERT_EQ("goodbye"sv, wpi::to_string_view(&cv.data.v_string)); ASSERT_EQ(7u, cv.data.v_string.len); NT_DisposeValue(&cv); @@ -226,9 +226,9 @@ TEST_F(ValueTest, StringArray) { ConvertToC(v, &cv); ASSERT_EQ(NT_STRING_ARRAY, cv.type); ASSERT_EQ(3u, cv.data.arr_string.size); - ASSERT_EQ("hello"sv, cv.data.arr_string.arr[0].str); - ASSERT_EQ("goodbye"sv, cv.data.arr_string.arr[1].str); - ASSERT_EQ("string"sv, cv.data.arr_string.arr[2].str); + ASSERT_EQ("hello"sv, wpi::to_string_view(&cv.data.arr_string.arr[0])); + ASSERT_EQ("goodbye"sv, wpi::to_string_view(&cv.data.arr_string.arr[1])); + ASSERT_EQ("string"sv, wpi::to_string_view(&cv.data.arr_string.arr[2])); // assign with same size vec.clear(); @@ -245,9 +245,9 @@ TEST_F(ValueTest, StringArray) { ConvertToC(v, &cv); ASSERT_EQ(NT_STRING_ARRAY, cv.type); ASSERT_EQ(3u, cv.data.arr_string.size); - ASSERT_EQ("s1"sv, cv.data.arr_string.arr[0].str); - ASSERT_EQ("str2"sv, cv.data.arr_string.arr[1].str); - ASSERT_EQ("string3"sv, cv.data.arr_string.arr[2].str); + ASSERT_EQ("s1"sv, wpi::to_string_view(&cv.data.arr_string.arr[0])); + ASSERT_EQ("str2"sv, wpi::to_string_view(&cv.data.arr_string.arr[1])); + ASSERT_EQ("string3"sv, wpi::to_string_view(&cv.data.arr_string.arr[2])); // assign with different size vec.clear(); @@ -262,8 +262,8 @@ TEST_F(ValueTest, StringArray) { ConvertToC(v, &cv); ASSERT_EQ(NT_STRING_ARRAY, cv.type); ASSERT_EQ(2u, cv.data.arr_string.size); - ASSERT_EQ("short"sv, cv.data.arr_string.arr[0].str); - ASSERT_EQ("er"sv, cv.data.arr_string.arr[1].str); + ASSERT_EQ("short"sv, wpi::to_string_view(&cv.data.arr_string.arr[0])); + ASSERT_EQ("er"sv, wpi::to_string_view(&cv.data.arr_string.arr[1])); NT_DisposeValue(&cv); } diff --git a/ntcoreffi/src/main/native/symbols.txt b/ntcoreffi/src/main/native/symbols.txt index 2a09552940..aeacd0f849 100644 --- a/ntcoreffi/src/main/native/symbols.txt +++ b/ntcoreffi/src/main/native/symbols.txt @@ -18,7 +18,6 @@ NT_AllocateCharArray NT_AllocateDoubleArray NT_AllocateFloatArray NT_AllocateIntegerArray -NT_AllocateStringArray NT_CreateInstance NT_CreateListenerPoller NT_DeleteTopicProperty @@ -27,7 +26,6 @@ NT_DestroyListenerPoller NT_DisposeConnectionInfoArray NT_DisposeEvent NT_DisposeEventArray -NT_DisposeString NT_DisposeTimestampedBoolean NT_DisposeTimestampedBooleanArray NT_DisposeTimestampedDouble @@ -62,7 +60,6 @@ NT_FreeQueueIntegerArray NT_FreeQueueRaw NT_FreeQueueString NT_FreeQueueStringArray -NT_FreeStringArray NT_FreeTopicInfoForTesting NT_GetAtomicBoolean NT_GetAtomicBooleanArray @@ -135,7 +132,12 @@ NT_GetValueStringArray NT_GetValueStringArrayForTesting NT_GetValueStringForTesting NT_GetValueType -NT_InitString +WPI_InitString +WPI_InitStringWithLength +WPI_AllocateString +WPI_FreeString +WPI_AllocateStringArray +WPI_FreeStringArray NT_InitValue NT_IsConnected NT_Meta_DecodeClientPublishers diff --git a/simulation/halsim_gui/src/main/native/cpp/DriverStationGui.cpp b/simulation/halsim_gui/src/main/native/cpp/DriverStationGui.cpp index 42df53efea..5639c147c2 100644 --- a/simulation/halsim_gui/src/main/native/cpp/DriverStationGui.cpp +++ b/simulation/halsim_gui/src/main/native/cpp/DriverStationGui.cpp @@ -1168,7 +1168,8 @@ void FMSSimModel::UpdateHAL() { HALSIM_SetDriverStationTest(m_test.GetValue()); HALSIM_SetDriverStationAutonomous(m_autonomous.GetValue()); HALSIM_SetDriverStationMatchTime(m_matchTime.GetValue()); - HALSIM_SetGameSpecificMessage(m_gameMessage.data(), m_gameMessage.size()); + auto str = wpi::make_string(m_gameMessage); + HALSIM_SetGameSpecificMessage(&str); HALSIM_SetDriverStationDsAttached(m_dsAttached.GetValue()); } diff --git a/simulation/halsim_ws_core/src/main/native/cpp/WSProvider_DriverStation.cpp b/simulation/halsim_ws_core/src/main/native/cpp/WSProvider_DriverStation.cpp index ee959b6be0..27495263b9 100644 --- a/simulation/halsim_ws_core/src/main/native/cpp/WSProvider_DriverStation.cpp +++ b/simulation/halsim_ws_core/src/main/native/cpp/WSProvider_DriverStation.cpp @@ -170,7 +170,8 @@ void HALSimWSProviderDriverStation::OnNetValueChanged(const wpi::json& json) { } if ((it = json.find(">game_data")) != json.end()) { std::string message = it.value().get_ref(); - HALSIM_SetGameSpecificMessage(message.c_str(), message.length()); + auto str = wpi::make_string(message); + HALSIM_SetGameSpecificMessage(&str); } // Only notify usercode if we get the new data message diff --git a/wpilibc/src/main/native/cpp/RobotController.cpp b/wpilibc/src/main/native/cpp/RobotController.cpp index 2414ed7fbe..48da72372a 100644 --- a/wpilibc/src/main/native/cpp/RobotController.cpp +++ b/wpilibc/src/main/native/cpp/RobotController.cpp @@ -30,16 +30,19 @@ int64_t RobotController::GetFPGARevision() { } std::string RobotController::GetSerialNumber() { - // Serial number is 8 characters - char serialNum[9]; - size_t len = HAL_GetSerialNumber(serialNum, sizeof(serialNum)); - return std::string(serialNum, len); + WPI_String serialNum; + HAL_GetSerialNumber(&serialNum); + std::string ret{wpi::to_string_view(&serialNum)}; + WPI_FreeString(&serialNum); + return ret; } std::string RobotController::GetComments() { - char comments[65]; - size_t len = HAL_GetComments(comments, sizeof(comments)); - return std::string(comments, len); + WPI_String comments; + HAL_GetComments(&comments); + std::string ret{wpi::to_string_view(&comments)}; + WPI_FreeString(&comments); + return ret; } int32_t RobotController::GetTeamNumber() { diff --git a/wpilibc/src/main/native/cpp/simulation/DriverStationSim.cpp b/wpilibc/src/main/native/cpp/simulation/DriverStationSim.cpp index 345204a82a..bdefda9002 100644 --- a/wpilibc/src/main/native/cpp/simulation/DriverStationSim.cpp +++ b/wpilibc/src/main/native/cpp/simulation/DriverStationSim.cpp @@ -235,7 +235,8 @@ void DriverStationSim::SetJoystickType(int stick, int type) { } void DriverStationSim::SetJoystickName(int stick, std::string_view name) { - HALSIM_SetJoystickName(stick, name.data(), name.size()); + auto str = wpi::make_string(name); + HALSIM_SetJoystickName(stick, &str); } void DriverStationSim::SetJoystickAxisType(int stick, int axis, int type) { @@ -243,11 +244,13 @@ void DriverStationSim::SetJoystickAxisType(int stick, int axis, int type) { } void DriverStationSim::SetGameSpecificMessage(std::string_view message) { - HALSIM_SetGameSpecificMessage(message.data(), message.size()); + auto str = wpi::make_string(message); + HALSIM_SetGameSpecificMessage(&str); } void DriverStationSim::SetEventName(std::string_view name) { - HALSIM_SetEventName(name.data(), name.size()); + auto str = wpi::make_string(name); + HALSIM_SetEventName(&str); } void DriverStationSim::SetMatchType(DriverStation::MatchType type) { diff --git a/wpilibc/src/main/native/cpp/simulation/RoboRioSim.cpp b/wpilibc/src/main/native/cpp/simulation/RoboRioSim.cpp index 728d358bfb..3717128d99 100644 --- a/wpilibc/src/main/native/cpp/simulation/RoboRioSim.cpp +++ b/wpilibc/src/main/native/cpp/simulation/RoboRioSim.cpp @@ -319,23 +319,29 @@ void RoboRioSim::SetTeamNumber(int32_t teamNumber) { } std::string RoboRioSim::GetSerialNumber() { - char serialNum[9]; - size_t len = HALSIM_GetRoboRioSerialNumber(serialNum, sizeof(serialNum)); - return std::string(serialNum, len); + WPI_String serialNum; + HALSIM_GetRoboRioSerialNumber(&serialNum); + std::string serial{wpi::to_string_view(&serialNum)}; + WPI_FreeString(&serialNum); + return serial; } void RoboRioSim::SetSerialNumber(std::string_view serialNumber) { - HALSIM_SetRoboRioSerialNumber(serialNumber.data(), serialNumber.size()); + auto str = wpi::make_string(serialNumber); + HALSIM_SetRoboRioSerialNumber(&str); } std::string RoboRioSim::GetComments() { - char comments[65]; - size_t len = HALSIM_GetRoboRioComments(comments, sizeof(comments)); - return std::string(comments, len); + WPI_String comments; + HALSIM_GetRoboRioComments(&comments); + std::string serial{wpi::to_string_view(&comments)}; + WPI_FreeString(&comments); + return serial; } void RoboRioSim::SetComments(std::string_view comments) { - HALSIM_SetRoboRioComments(comments.data(), comments.size()); + auto str = wpi::make_string(comments); + HALSIM_SetRoboRioComments(&str); } std::unique_ptr RoboRioSim::RegisterRadioLEDStateCallback( diff --git a/wpiutil/src/main/native/cpp/DataLog.cpp b/wpiutil/src/main/native/cpp/DataLog.cpp index befcc7513a..5234c8e705 100644 --- a/wpiutil/src/main/native/cpp/DataLog.cpp +++ b/wpiutil/src/main/native/cpp/DataLog.cpp @@ -596,7 +596,7 @@ void DataLog::AppendStringArray(int entry, } void DataLog::AppendStringArray(int entry, - std::span arr, + std::span arr, int64_t timestamp) { if (entry <= 0) { return; @@ -640,11 +640,13 @@ void WPI_DataLog_Stop(struct WPI_DataLog* datalog) { reinterpret_cast(datalog)->Stop(); } -int WPI_DataLog_Start(struct WPI_DataLog* datalog, const char* name, - const char* type, const char* metadata, - int64_t timestamp) { - return reinterpret_cast(datalog)->Start(name, type, metadata, - timestamp); +int WPI_DataLog_Start(struct WPI_DataLog* datalog, + const struct WPI_String* name, + const struct WPI_String* type, + const struct WPI_String* metadata, int64_t timestamp) { + return reinterpret_cast(datalog)->Start( + wpi::to_string_view(name), wpi::to_string_view(type), + wpi::to_string_view(metadata), timestamp); } void WPI_DataLog_Finish(struct WPI_DataLog* datalog, int entry, @@ -653,8 +655,10 @@ void WPI_DataLog_Finish(struct WPI_DataLog* datalog, int entry, } void WPI_DataLog_SetMetadata(struct WPI_DataLog* datalog, int entry, - const char* metadata, int64_t timestamp) { - reinterpret_cast(datalog)->SetMetadata(entry, metadata, timestamp); + const struct WPI_String* metadata, + int64_t timestamp) { + reinterpret_cast(datalog)->SetMetadata( + entry, wpi::to_string_view(metadata), timestamp); } void WPI_DataLog_AppendRaw(struct WPI_DataLog* datalog, int entry, @@ -683,10 +687,10 @@ void WPI_DataLog_AppendDouble(struct WPI_DataLog* datalog, int entry, } void WPI_DataLog_AppendString(struct WPI_DataLog* datalog, int entry, - const char* value, size_t len, + const struct WPI_String* value, int64_t timestamp) { - reinterpret_cast(datalog)->AppendString(entry, {value, len}, - timestamp); + reinterpret_cast(datalog)->AppendString( + entry, {value->str, value->len}, timestamp); } void WPI_DataLog_AppendBooleanArray(struct WPI_DataLog* datalog, int entry, @@ -725,23 +729,29 @@ void WPI_DataLog_AppendDoubleArray(struct WPI_DataLog* datalog, int entry, } void WPI_DataLog_AppendStringArray(struct WPI_DataLog* datalog, int entry, - const WPI_DataLog_String* arr, size_t len, + const struct WPI_String* arr, size_t len, int64_t timestamp) { reinterpret_cast(datalog)->AppendStringArray(entry, {arr, len}, timestamp); } -void WPI_DataLog_AddSchemaString(struct WPI_DataLog* datalog, const char* name, - const char* type, const char* schema, +void WPI_DataLog_AddSchemaString(struct WPI_DataLog* datalog, + const struct WPI_String* name, + const struct WPI_String* type, + const struct WPI_String* schema, int64_t timestamp) { - reinterpret_cast(datalog)->AddSchema(name, type, schema, timestamp); + reinterpret_cast(datalog)->AddSchema( + wpi::to_string_view(name), wpi::to_string_view(type), + wpi::to_string_view(schema), timestamp); } -void WPI_DataLog_AddSchema(struct WPI_DataLog* datalog, const char* name, - const char* type, const uint8_t* schema, +void WPI_DataLog_AddSchema(struct WPI_DataLog* datalog, + const struct WPI_String* name, + const struct WPI_String* type, const uint8_t* schema, size_t schema_len, int64_t timestamp) { reinterpret_cast(datalog)->AddSchema( - name, type, std::span{schema, schema_len}, timestamp); + wpi::to_string_view(name), wpi::to_string_view(type), + std::span{schema, schema_len}, timestamp); } } // extern "C" diff --git a/wpiutil/src/main/native/cpp/DataLogBackgroundWriter.cpp b/wpiutil/src/main/native/cpp/DataLogBackgroundWriter.cpp index 4ef7ef7cf9..2db52e3cf7 100644 --- a/wpiutil/src/main/native/cpp/DataLogBackgroundWriter.cpp +++ b/wpiutil/src/main/native/cpp/DataLogBackgroundWriter.cpp @@ -461,23 +461,25 @@ void DataLogBackgroundWriter::WriterThreadMain( extern "C" { struct WPI_DataLog* WPI_DataLog_CreateBackgroundWriter( - const char* dir, const char* filename, double period, - const char* extraHeader) { - return reinterpret_cast( - new DataLogBackgroundWriter{dir, filename, period, extraHeader}); + const struct WPI_String* dir, const struct WPI_String* filename, + double period, const struct WPI_String* extraHeader) { + return reinterpret_cast(new DataLogBackgroundWriter{ + wpi::to_string_view(dir), wpi::to_string_view(filename), period, + wpi::to_string_view(extraHeader)}); } struct WPI_DataLog* WPI_DataLog_CreateBackgroundWriter_Func( void (*write)(void* ptr, const uint8_t* data, size_t len), void* ptr, - double period, const char* extraHeader) { + double period, const struct WPI_String* extraHeader) { return reinterpret_cast(new DataLogBackgroundWriter{ [=](auto data) { write(ptr, data.data(), data.size()); }, period, - extraHeader}); + wpi::to_string_view(extraHeader)}); } -void WPI_DataLog_SetBackgroundWriterFilename(struct WPI_DataLog* datalog, - const char* filename) { - reinterpret_cast(datalog)->SetFilename(filename); +void WPI_DataLog_SetBackgroundWriterFilename( + struct WPI_DataLog* datalog, const struct WPI_String* filename) { + reinterpret_cast(datalog)->SetFilename( + wpi::to_string_view(filename)); } } // extern "C" diff --git a/wpiutil/src/main/native/cpp/DataLogWriter.cpp b/wpiutil/src/main/native/cpp/DataLogWriter.cpp index ca4645187f..c4e4a501d4 100644 --- a/wpiutil/src/main/native/cpp/DataLogWriter.cpp +++ b/wpiutil/src/main/native/cpp/DataLogWriter.cpp @@ -63,12 +63,12 @@ bool DataLogWriter::BufferFull() { extern "C" { -struct WPI_DataLog* WPI_DataLog_CreateWriter(const char* filename, - int* errorCode, - const char* extraHeader) { +struct WPI_DataLog* WPI_DataLog_CreateWriter( + const struct WPI_String* filename, int* errorCode, + const struct WPI_String* extraHeader) { std::error_code ec; - auto rv = reinterpret_cast( - new DataLogWriter{filename, ec, extraHeader}); + auto rv = reinterpret_cast(new DataLogWriter{ + wpi::to_string_view(filename), ec, wpi::to_string_view(extraHeader)}); *errorCode = ec.value(); return rv; } diff --git a/wpiutil/src/main/native/cpp/string.cpp b/wpiutil/src/main/native/cpp/string.cpp new file mode 100644 index 0000000000..e7a7ea3597 --- /dev/null +++ b/wpiutil/src/main/native/cpp/string.cpp @@ -0,0 +1,77 @@ +// Copyright (c) FIRST and other WPILib contributors. +// Open Source Software; you can modify and/or share it under the terms of +// the WPILib BSD license file in the root directory of this project. + +#include "wpi/string.h" + +#include + +#include + +extern "C" { + +void WPI_InitString(struct WPI_String* wpiString, const char* utf8String) { + if (wpiString == nullptr) { + return; + } + if (utf8String == nullptr) { + wpiString->str = nullptr; + wpiString->len = 0; + } else { + wpiString->str = utf8String; + wpiString->len = std::char_traits::length(utf8String); + } +} + +void WPI_InitStringWithLength(struct WPI_String* wpiString, + const char* utf8String, size_t length) { + if (wpiString == nullptr) { + return; + } + wpiString->str = utf8String; + wpiString->len = length; +} + +// Returned from AllocateString if 0 length is requested. +// Returned instead of nullptr due to memcpy pointer validity rules +static char writeBuffer; + +char* WPI_AllocateString(struct WPI_String* wpiString, size_t length) { + if (wpiString == nullptr) { + return nullptr; + } + if (length == 0) { + wpiString->len = 0; + wpiString->str = nullptr; + return &writeBuffer; + } + char* str = static_cast(wpi::safe_malloc(length)); + wpiString->str = str; + wpiString->len = length; + return str; +} + +void WPI_FreeString(const struct WPI_String* wpiString) { + if (wpiString == nullptr) { + return; + } + std::free(const_cast(wpiString->str)); +} + +struct WPI_String* WPI_AllocateStringArray(size_t length) { + return static_cast( + wpi::safe_malloc(length * sizeof(struct WPI_String))); +} + +void WPI_FreeStringArray(const struct WPI_String* wpiStringArray, + size_t length) { + if (wpiStringArray == nullptr) { + return; + } + for (size_t i = 0; i < length; ++i) { + WPI_FreeString(&wpiStringArray[i]); + } + std::free(const_cast(wpiStringArray)); +} + +} // extern "C" diff --git a/wpiutil/src/main/native/include/wpi/DataLog.h b/wpiutil/src/main/native/include/wpi/DataLog.h index c7665ff1dc..9fa209b244 100644 --- a/wpiutil/src/main/native/include/wpi/DataLog.h +++ b/wpiutil/src/main/native/include/wpi/DataLog.h @@ -23,6 +23,7 @@ #include "wpi/StringMap.h" #include "wpi/mutex.h" #include "wpi/protobuf/Protobuf.h" +#include "wpi/string.h" #include "wpi/struct/Struct.h" #include "wpi/timestamp.h" @@ -373,7 +374,7 @@ class DataLog { * @param arr String array to record * @param timestamp Time stamp (may be 0 to indicate now) */ - void AppendStringArray(int entry, std::span arr, + void AppendStringArray(int entry, std::span arr, int64_t timestamp); protected: diff --git a/wpiutil/src/main/native/include/wpi/DataLog_c.h b/wpiutil/src/main/native/include/wpi/DataLog_c.h index c4f48e3a38..654181a843 100644 --- a/wpiutil/src/main/native/include/wpi/DataLog_c.h +++ b/wpiutil/src/main/native/include/wpi/DataLog_c.h @@ -7,22 +7,12 @@ #include // NOLINT #include +#include #ifdef __cplusplus extern "C" { #endif -/** - * A datalog string (for use with string array). - */ -struct WPI_DataLog_String { - /** Contents. */ - const char* str; - - /** Length. */ - size_t len; -}; - /** C-compatible data log (opaque struct). */ struct WPI_DataLog; @@ -33,9 +23,9 @@ struct WPI_DataLog; * @param errorCode error if file failed to open (output) * @param extraHeader extra header data */ -struct WPI_DataLog* WPI_DataLog_CreateWriter(const char* filename, - int* errorCode, - const char* extraHeader); +struct WPI_DataLog* WPI_DataLog_CreateWriter( + const struct WPI_String* filename, int* errorCode, + const struct WPI_String* extraHeader); /** * Construct a new Data Log background writer. The log will be initially @@ -48,10 +38,9 @@ struct WPI_DataLog* WPI_DataLog_CreateWriter(const char* filename, * this is a time/storage tradeoff * @param extraHeader extra header data */ -struct WPI_DataLog* WPI_DataLog_CreateBackgroundWriter(const char* dir, - const char* filename, - double period, - const char* extraHeader); +struct WPI_DataLog* WPI_DataLog_CreateBackgroundWriter( + const struct WPI_String* dir, const struct WPI_String* filename, + double period, const struct WPI_String* extraHeader); /** * Construct a new Data Log background writer that passes its output to the @@ -67,7 +56,7 @@ struct WPI_DataLog* WPI_DataLog_CreateBackgroundWriter(const char* dir, */ struct WPI_DataLog* WPI_DataLog_CreateBackgroundWriter_Func( void (*write)(void* ptr, const uint8_t* data, size_t len), void* ptr, - double period, const char* extraHeader); + double period, const struct WPI_String* extraHeader); /** * Change log filename. Can only be used on background writer data logs. @@ -76,7 +65,7 @@ struct WPI_DataLog* WPI_DataLog_CreateBackgroundWriter_Func( * @param filename filename */ void WPI_DataLog_SetBackgroundWriterFilename(struct WPI_DataLog* datalog, - const char* filename); + const struct WPI_String* filename); /** * Releases a data log object. Closes the file and returns resources to the @@ -134,9 +123,10 @@ void WPI_DataLog_Stop(struct WPI_DataLog* datalog); * * @return Entry index */ -int WPI_DataLog_Start(struct WPI_DataLog* datalog, const char* name, - const char* type, const char* metadata, - int64_t timestamp); +int WPI_DataLog_Start(struct WPI_DataLog* datalog, + const struct WPI_String* name, + const struct WPI_String* type, + const struct WPI_String* metadata, int64_t timestamp); /** * Finish an entry. @@ -157,7 +147,8 @@ void WPI_DataLog_Finish(struct WPI_DataLog* datalog, int entry, * @param timestamp Time stamp (may be 0 to indicate now) */ void WPI_DataLog_SetMetadata(struct WPI_DataLog* datalog, int entry, - const char* metadata, int64_t timestamp); + const struct WPI_String* metadata, + int64_t timestamp); /** * Appends a raw record to the log. @@ -221,11 +212,11 @@ void WPI_DataLog_AppendDouble(struct WPI_DataLog* datalog, int entry, * @param datalog data log * @param entry Entry index, as returned by WPI_DataLog_Start() * @param value String value to record - * @param len Length of string * @param timestamp Time stamp (may be 0 to indicate now) */ void WPI_DataLog_AppendString(struct WPI_DataLog* datalog, int entry, - const char* value, size_t len, int64_t timestamp); + const struct WPI_String* value, + int64_t timestamp); /** * Appends a boolean array record to the log. @@ -302,15 +293,18 @@ void WPI_DataLog_AppendDoubleArray(struct WPI_DataLog* datalog, int entry, * @param timestamp Time stamp (may be 0 to indicate now) */ void WPI_DataLog_AppendStringArray(struct WPI_DataLog* datalog, int entry, - const WPI_DataLog_String* arr, size_t len, + const struct WPI_String* arr, size_t len, int64_t timestamp); -void WPI_DataLog_AddSchemaString(struct WPI_DataLog* datalog, const char* name, - const char* type, const char* schema, +void WPI_DataLog_AddSchemaString(struct WPI_DataLog* datalog, + const struct WPI_String* name, + const struct WPI_String* type, + const struct WPI_String* schema, int64_t timestamp); -void WPI_DataLog_AddSchema(struct WPI_DataLog* datalog, const char* name, - const char* type, const uint8_t* schema, +void WPI_DataLog_AddSchema(struct WPI_DataLog* datalog, + const struct WPI_String* name, + const struct WPI_String* type, const uint8_t* schema, size_t schema_len, int64_t timestamp); #ifdef __cplusplus diff --git a/wpiutil/src/main/native/include/wpi/jni_util.h b/wpiutil/src/main/native/include/wpi/jni_util.h index 089e6efd2f..f341842391 100644 --- a/wpiutil/src/main/native/include/wpi/jni_util.h +++ b/wpiutil/src/main/native/include/wpi/jni_util.h @@ -23,6 +23,7 @@ #include "wpi/mutex.h" #include "wpi/print.h" #include "wpi/raw_ostream.h" +#include "wpi/string.h" /** Java Native Interface (JNI) utility functions */ namespace wpi::java { @@ -171,6 +172,7 @@ class JStringRef { std::string_view str() const { return m_str.str(); } const char* c_str() const { return m_str.data(); } size_t size() const { return m_str.size(); } + WPI_String wpi_str() const { return wpi::make_string(str()); } private: SmallString<128> m_str; diff --git a/wpiutil/src/main/native/include/wpi/string.h b/wpiutil/src/main/native/include/wpi/string.h new file mode 100644 index 0000000000..a001b7be17 --- /dev/null +++ b/wpiutil/src/main/native/include/wpi/string.h @@ -0,0 +1,108 @@ +// Copyright (c) FIRST and other WPILib contributors. +// Open Source Software; you can modify and/or share it under the terms of +// the WPILib BSD license file in the root directory of this project. + +#pragma once + +#ifdef __cplusplus +#include +#endif + +/** + * A const UTF8 string. + */ +struct WPI_String { + /** Contents. */ + const char* str; + /** Length */ + size_t len; +}; + +#ifdef __cplusplus +namespace wpi { +/** Converts a WPI_String to a string_view */ +constexpr std::string_view to_string_view(const struct WPI_String* str) { + if (str) { + return {str->str, str->len}; + } else { + return ""; + } +} + +/** Converts a string_view to a WPI_String */ +constexpr WPI_String make_string(std::string_view view) { + return WPI_String{view.data(), view.size()}; +} +} // namespace wpi +#endif // __cplusplus + +#ifdef __cplusplus +extern "C" { +#endif // __cplusplus + +/** + * Initializes a WPI_String from a null terminated UTF-8 string. + * If input string is null, initializes output to 0 length. + * The output length does not include the null terminator. + * + * The lifetime of the output string is the lifetime of the input string. + * Do not call WPI_FreeString() with the output of this call. + * + * @param wpiString output string + * @param utf8String input string (null terminated) + */ +void WPI_InitString(struct WPI_String* wpiString, const char* utf8String); + +/** + * Initializes a WPI_String from a UTF-8 string and length. + * If input string is null or 0 length, initilizes output to 0 length. + * The input string does not need to be null terminated. + * + * The lifetime of the output string is the lifetime of the input string. + * Do not call WPI_FreeString() with the output of this call. + * + * @param wpiString output string + * @param utf8String input string + * @param length input string length in chars + */ +void WPI_InitStringWithLength(struct WPI_String* wpiString, + const char* utf8String, size_t length); + +/** + * Allocates a WPI_String for the specified length. + * The resultant string must be freed with WPI_FreeString(). + * + * @param wpiString output string + * @param length string length in chars to allocate + * @return mutable pointer to allocated buffer + * + */ +char* WPI_AllocateString(struct WPI_String* wpiString, size_t length); + +/** + * Frees a WPI_String that was allocated with WPI_AllocateString() + * + * @param wpiString string to free + */ +void WPI_FreeString(const struct WPI_String* wpiString); + +/** + * Allocates an array of WPI_Strings. + * + * @param length array length + * @return string array + */ +struct WPI_String* WPI_AllocateStringArray(size_t length); + +/** + * Frees a WPI_String array returned by WPI_AllocateStringArray(). + * + * @param wpiStringArray string array to free + * @param length length of array + */ +void WPI_FreeStringArray(const struct WPI_String* wpiStringArray, + size_t length); + +#ifdef __cplusplus +} // extern "C" +#endif // __cplusplus