hacking std::copy to use pointers
-
wrote on 28 Aug 2021, 02:40 last edited by
Is there a way to hack std::copy so that it can take simple uint8_t* as range limits? The method is passed const uint8_t* and const size_t...not a container or real iterators.
const uint8_t* ptr = ADDRESS; uint8_t* dest = DESTINATION; constexpr size_t length = 0x20U; std::copy(ptr, ptr+length, dest);
I'm trying to avoid the code review justification of explicitly exempting the AUTOSAR violations of using ::memcpy(). They strongly discourage <cstring>
I should rephase: Is there a way to hack std::copy so that it can use pointers without creating an iterator wrapper class for the pointers?
Or alternately, is there an existing stl vectorish container that supports iterators and can reference the existing memory as it's internal buffer without creating a copy of the data?
-
wrote on 28 Aug 2021, 06:14 last edited by
I'm confused by that code snippet. The following compiles with a selection of compilers for C++11 and later.
#include <cstdint> #include <algorithm> #if _cplusplus >= 202002L #include <span> #endif void test(uint8_t *input, size_t length, uint8_t *output) { #if _cplusplus >= 202002L std::span s{input, length}; std::copy(s.begin(), s.end(), output); #endif std::copy(input, input + length, output); }
std::span is a C++20 non-owning wrapper container for contiguous sequences, which might meet your last request.
I don't understand how std::copy() using a separately passed length is superior to memcpy(). I do understand following arbitrary rules to avoid spending time discussing arbitrary rules.
Was the original formulation of the question referring to C++20 ranges?
-
wrote on 28 Aug 2021, 14:28 last edited by Kent-Dorfman
No c++20...It is to conform to AUTOSAR "Guidelines for the use of the C++14 language in critical and safety related systems". It's a coding safety standard where much of it makes sense and some of it is pure OCD on the part of the members of the standards committee. LOL Point is, trying to slowly phase out C-ish code but still working on low level embedded systems so "pointers are king". Standard requires documentation and justification each time a rule is violated.
A custom allocator for std::vector may be a work-around but I had hoped something already existed for this use-case.
Yes, this compiles but give erroneous results.
void test(const uint8_t *input, const size_t length, uint8_t *output) { std::copy(input, input + length, output); }
and this is the other real use-case that fails...moving into or out of the destPtr buffer
uint32_t ip = ::htonl((127U << 24U) | 1U); std::copy(&ip, &ip + sizeof(ip), destPtr);
-
No c++20...It is to conform to AUTOSAR "Guidelines for the use of the C++14 language in critical and safety related systems". It's a coding safety standard where much of it makes sense and some of it is pure OCD on the part of the members of the standards committee. LOL Point is, trying to slowly phase out C-ish code but still working on low level embedded systems so "pointers are king". Standard requires documentation and justification each time a rule is violated.
A custom allocator for std::vector may be a work-around but I had hoped something already existed for this use-case.
Yes, this compiles but give erroneous results.
void test(const uint8_t *input, const size_t length, uint8_t *output) { std::copy(input, input + length, output); }
and this is the other real use-case that fails...moving into or out of the destPtr buffer
uint32_t ip = ::htonl((127U << 24U) | 1U); std::copy(&ip, &ip + sizeof(ip), destPtr);
@Kent-Dorfman said in hacking std::copy to use pointers:
Is there a way to hack std::copy so that it can take simple uint8_t* as range limits
You don't need to hack it; the code you posted in your original post should already work (assuming that ADDRESS, DESTINATION, and length are correct).
Yes, this compiles but give erroneous results.
void test(const uint8_t *input, const size_t length, uint8_t *output) { std::copy(input, input + length, output); }
Erroneous how?
and this is the other real use-case that fails...moving into or out of the destPtr buffer
uint32_t ip = ::htonl((127U << 24U) | 1U); std::copy(&ip, &ip + sizeof(ip), destPtr);
This code will try to copy 16 bytes, not 4 bytes. You want
std::copy(&ip, &ip + 1, destPtr);
-
@Kent-Dorfman said in hacking std::copy to use pointers:
Is there a way to hack std::copy so that it can take simple uint8_t* as range limits
You don't need to hack it; the code you posted in your original post should already work (assuming that ADDRESS, DESTINATION, and length are correct).
Yes, this compiles but give erroneous results.
void test(const uint8_t *input, const size_t length, uint8_t *output) { std::copy(input, input + length, output); }
Erroneous how?
and this is the other real use-case that fails...moving into or out of the destPtr buffer
uint32_t ip = ::htonl((127U << 24U) | 1U); std::copy(&ip, &ip + sizeof(ip), destPtr);
This code will try to copy 16 bytes, not 4 bytes. You want
std::copy(&ip, &ip + 1, destPtr);
wrote on 28 Aug 2021, 16:57 last edited byThis post is deleted! -
wrote on 28 Aug 2021, 17:19 last edited by
std::copy(&ip, &ip + sizeof(ip), destPtr); was definitely a goof on my part.
-
wrote on 30 Aug 2021, 14:23 last edited by
another fly in the ointment that makes std::copy unsuitable for moving memory buffers around:
Given the above example of copying the bytes of a uint32_t to an arbitrary memory location, the destPtr (being of type uint8_t*) wont allow std::copy to copy the whole range from the input iteratores. It only copies one byte! Some would argue that destPtr should then be of type uint32_t* but that could cause other problems since there is no guarantee that the destination address would be word aligned...IOW, I don't necessarily want it to be aligned, but instead packed.
going back to using using <cstring> methods that aren't so picky about how you address memory.
-
another fly in the ointment that makes std::copy unsuitable for moving memory buffers around:
Given the above example of copying the bytes of a uint32_t to an arbitrary memory location, the destPtr (being of type uint8_t*) wont allow std::copy to copy the whole range from the input iteratores. It only copies one byte! Some would argue that destPtr should then be of type uint32_t* but that could cause other problems since there is no guarantee that the destination address would be word aligned...IOW, I don't necessarily want it to be aligned, but instead packed.
going back to using using <cstring> methods that aren't so picky about how you address memory.
@Kent-Dorfman You can cast your input pointers to <uint8_t*> (and change your pointer arithmetic for the end iterator) before passing them to std::copy.
going back to using using <cstring> methods
I thought that was strongly discouraged?
-
wrote on 30 Aug 2021, 20:56 last edited by
I understand why, but std::copy is just too particular about operand types for generic RAM (network buffer) manipulation. Going back to <cstring> methods that use void*...yeah, it violates the consortium rules but this is embedded programming, not high level algorithmic stuff..and rank has its privilege. I'm the one driving the conformance level so nobody is gonna complain if I make their life easier. and in the end, violations just have to be documented, if I leave the rule turned on. at this point I'm inclined to disable that particular rule as being overly strict for nodes with no safety critical functions.
-
wrote on 31 Aug 2021, 04:33 last edited by
memmove() or memcpy() sound like the right abstraction for a block of memory. std::copy() deals a range of items that may be noncontiguous or have copy constructors. Using it on a buffer presumably means breaking that abstraction to get char sized chunks, while having limited potential to utilize the iterator abstraction. I guess it could make sense with a scatter/gather interface.
-
wrote on 25 Oct 2021, 16:58 last edited by
I just don't get where it fails from this discussion:
#include <cstdint> #include <algorithm> #include <cassert> int main(int argc, char *argv[]) { constexpr size_t length = 0x20U; uint8_t* ptr = new uint8_t[length]; for(size_t count=0; count<length; ++count) ptr[count] = count; uint8_t* dest = new uint8_t[length]; std::copy(ptr, ptr+length, dest); for(size_t count=0; count<length; ++count){ assert(ptr[count] == dest[count]); } delete[] ptr; delete[] dest; return 0; }
I tested in both c++11 and c++17.