WIP: RSDK-11082: Remove instances of C-style pointer manipulation #30
WIP: RSDK-11082: Remove instances of C-style pointer manipulation #30lia-viam wants to merge 4 commits intoviam-modules:mainfrom
Conversation
| return boost::span{bytes.get(), size}; | ||
| } | ||
|
|
||
| static constexpr deleter_type array_delete_deleter = [](unsigned char* ptr) { delete[] ptr; }; |
There was a problem hiding this comment.
note that
- it is UB to
freememory that wasnew'd - the
std::default_deletetemplate parameter forunique_ptr<T[]>already doesdelete[]
https://en.cppreference.com/w/cpp/memory/default_delete.html
|
|
||
| std::vector<unsigned char> RGBPointsToPCD(std::shared_ptr<ob::Frame> frame, float scale) { | ||
| int numPoints = frame->dataSize() / sizeof(OBColorPoint); | ||
| assert(frame->is<ob::PointsFrame>()); |
There was a problem hiding this comment.
If this pattern comes up more often we could write a FrameView<T> class which performs the following asserts and returns a span of the data already set to type T
There was a problem hiding this comment.
what kind of error message is produced when an assert fails?
There was a problem hiding this comment.
It includes the line like:
orbbec.cpp:152 frame->is<ob::PointsFrame>() assert failed
So it includes the line number and string of the failing assert.
| std::memcpy(rawBuf, encodedData.data(), encodedData.size()); | ||
| raw_camera_image rawBuf(encodedData.size()); | ||
|
|
||
| std::copy(encodedData.begin(), encodedData.end(), rawBuf.span().begin()); |
There was a problem hiding this comment.
note that most standard library implementations of std::copy will fall back to a compiler intrinsic version of memcpy or memmove when operating on contiguous iterators of arithmetic types
| } | ||
|
|
||
| static constexpr deleter_type array_delete_deleter = [](unsigned char* ptr) { delete[] ptr; }; | ||
| boost::span<unsigned char> span() noexcept { |
There was a problem hiding this comment.
Not critical at all, but could we use std::uint8_t instead of unsigned char to express bytes?
There was a problem hiding this comment.
@SebastianMunozP I was looking into this and it seems like we may want to use either unsigned char or std::byte, as per these guidelines: https://stackoverflow.com/a/77097674 but they advise against std::uint8_t
I believe this project is C++17 so we could use std::byte instead of unsigned char, do you have thoughts or preferences?
There was a problem hiding this comment.
huh, didn't know about std::byte :) , I agree, let's go with that then.
There was a problem hiding this comment.
just added some changes using std::byte. unfortunately since the Viam SDK is still on C++14 there is no access to std::byte so we end up having to convert back to unsigned char. Please let me know your thoughts, we can keep it this way or revert to the previous diff using unsigned char
There was a problem hiding this comment.
I see, in that case let's just go back to unsigned char and try this change maybe in the future.
| assert(frame->is<ob::PointsFrame>()); | ||
| assert(frame->getFormat() == OBFormat::OB_FORMAT_RGB_POINT); | ||
|
|
||
| auto pointSpan = boost::span{reinterpret_cast<OBColorPoint*>(frame->data()), frame->dataSize() / sizeof(OBColorPoint)}; |
There was a problem hiding this comment.
how do we ensure that the span's underlying bytes do not get freed while using it?
There was a problem hiding this comment.
@hexbabe that's the responsibility of the calling code; span is a non-owning reference or "view" type, meaning it provides a different view or interface upon some underlying data without taking responsibility for the lifetime of the data. Similar to string_view, or language-level references (int i; int& j = i;).
see https://stackoverflow.com/a/45723820 for further discussion
|
|
||
| std::vector<unsigned char> RGBPointsToPCD(std::shared_ptr<ob::Frame> frame, float scale) { | ||
| int numPoints = frame->dataSize() / sizeof(OBColorPoint); | ||
| assert(frame->is<ob::PointsFrame>()); |
There was a problem hiding this comment.
I like using asserts, but in this case I would prefer to detect the case of these two asserts and log it and early return. I think it would be better to handle this by looking at logs than forcing the module to terminate.
Cc. @nicksanford in case you want to weigh in.
There was a problem hiding this comment.
- If the assert fails does it terminate the os process?
- If it terminates the os process does Viam server get an unambiguous log that would tell us immediately why the process terminated?
- Is it impossible for the assertion to ever fail in practice given the current state of the code?
If the answers to all those questions are 'yes' then this is fine.
If the answer to any of them is no then I'll need a justification for why this asset is here.
There was a problem hiding this comment.
- yes (via calling std::abort())
- yes (we will get a message stating the file/line of the assert and the assert that failed)
- I tested this module and the assertions did not failed
It's worth noting that as the code is at the moment, these asserts are being removed from the binary since this is a release build. I enabled them by creating a debug build and making sure that I could hit asserts.
There was a problem hiding this comment.
Having assets fire in release builds sounds good to me.
I'd also be ok with us writing our own assert function. Whichever you feel is best.
There was a problem hiding this comment.
So in the current code as is the assert wouldn't get hit unless someone called RGBPointsToPCD(not_an_rgb_point_frame). The asserts are there to show how we can check type safety given that we are dealing with polymorphic data but in this function only one type of input is acceptable.
Per another comment #30 (comment) the use of assert here was meant to sketch a general procedure that could be used if this pattern keeps coming up. Namely, we have an ob::Frame* frame, and we want to get a range which refers to a definite underlying type. In this case it would be nice to be able to just do
void f(std::shared_ptr<ob::Frame> frame){
FrameView<OBColorPoint> frameView(frame);
}and we would expect this to be an error if frame were not in fact an OB_FORMAT_RGB_POINT, similar to how some standard library containers have asserts or bounds checking in debug builds.
I think assert or throw is the right behavior here; this will fail loudly with a meaningful log message and viam-server can restart the module. An early return would result in further control flow being executed with an empty vector, which could be easy to miss.
A possible option, since we already use Boost, is Boost.Assert. This has the advantage of letting us
- keep asserts in non-debug builds independent of
NDEBUG - write a different assertion processing function (eg, log error, throw exception) rather than the
assertbehavior of callingabort
There was a problem hiding this comment.
That's a good idea, let's do that, let's change the asserts for BOOST_ASSERT
hexbabe
left a comment
There was a problem hiding this comment.
approving, but mostly just read over and asked questions for learning
| assert(frame->is<ob::PointsFrame>()); | ||
| assert(frame->getFormat() == OBFormat::OB_FORMAT_RGB_POINT); | ||
|
|
||
| auto pointSpan = boost::span{reinterpret_cast<OBColorPoint*>(frame->data()), frame->dataSize() / sizeof(OBColorPoint)}; |
There was a problem hiding this comment.
how do we ensure that the span's underlying bytes do not get freed while using it?
| } | ||
| auto depthPixels = boost::span{reinterpret_cast<uint16_t const*>(data), height * width}; | ||
|
|
||
| std::transform(depthPixels.begin(), depthPixels.end(), m.begin(), [](uint16_t mi) { return mi * mmToMeterMultiple; }); |
There was a problem hiding this comment.
may i recommend this for inspo 🙂
https://youtu.be/W2tWOdzgXHA?t=133
|
|
||
| std::vector<unsigned char> RGBPointsToPCD(std::shared_ptr<ob::Frame> frame, float scale) { | ||
| int numPoints = frame->dataSize() / sizeof(OBColorPoint); | ||
| assert(frame->is<ob::PointsFrame>()); |
There was a problem hiding this comment.
what kind of error message is produced when an assert fails?
|
Actually I'll hold off approval until manual tests are reported to ensure no regressions |
hexbabe
left a comment
There was a problem hiding this comment.
blocked on test writeup
This PR modernizes some of the older C-style pointer code in favor of modern approaches using
boost::spanand range-based for loops or algorithms from<algorithm>. I will annotate the PR below with comments; feel free to suggest if you think they should be put into the code as comments alsoMarking as draft for now pending some further testing