-
Notifications
You must be signed in to change notification settings - Fork 111
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Implemented #320. #339
Implemented #320. #339
Conversation
Added buffer class that supports `mqtt::string_view` compatible behavior and life keekping mechanism (optional). Callback functions for users hold receive buffer directly via `buffer`. Removed `*_ref` properties. Ref or not ref is hidden by `buffer`. Added `""_mb` user defined literals for `buffer`. Added boost type_erasure. `mqtt::socket` is type erased socket. It covers tcp, tls, ws, and wss. Compile times become faster. Replaced static_cast with boost::numeric_cast if overflow could happen. Removed redundant static_cast. Implemented efficient shared_ptr_array allocation. If use boost (default), then use `boost::make_shared<char[]>(size)`. If user defines MQTT_STD_SHARED_PTR_ARRAY, if __cplusplus is greater than 201703L (means C++20 or later), then `std::make_shared<char[]>(size)`, otherwise `std::shared_ptr<char[]>(new size)` is called.
Codecov Report
@@ Coverage Diff @@
## master #339 +/- ##
==========================================
+ Coverage 85.53% 86.25% +0.72%
==========================================
Files 34 37 +3
Lines 4889 6215 +1326
==========================================
+ Hits 4182 5361 +1179
- Misses 707 854 +147 |
.travis.yml
Outdated
@@ -1,6 +1,6 @@ | |||
sudo: false | |||
language: cpp | |||
dist: trusty | |||
dist: bionic |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm still cautious about changes to the minimum compiler version.
Did this turn out to still be necessary?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe I can move back to trusty. Would you want to do that?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If it's practical.
If trusty is not "really" too old, and there's an "easy" solution to the compiler issues, then I would prefer to keep supporting trusty, but I'm not opposed to Bionic, as long as the compiler series is still the GCC 7.x.y release.
Like I said, I'm currently stuck on 7.3.0, which supports most of C++17, and it looks like Bionic has GCC 7.4.0, which is probably close enough.
But I'm saying that if there isn't otherwise a reason to switch to the newer version (because compiler errors, for example) then we shouldn't change the minimum version.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok, I will downgrade to trusty.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I just confirmed the current version of impl_320_2 works fine with trusty. I will use trusty.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done(just my memo, not pushed yet).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This change does not appear to have been reverted.
Did you revert it?
mqtt::v5::property::user_property("key2", "val2"), | ||
mqtt::v5::property::authentication_method("test authentication method"), | ||
mqtt::v5::property::authentication_data("test authentication data") | ||
mqtt::v5::property::user_property("key1"_mb, "val1"_mb), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We could do a user defined literal for UserProperties as well, but it's not clear to me if that is better, or worse, than this approach. Perhaps something that we shouldn't provide at the library level. Or if we did, as a separate header file that people have to include themselves "for convenience".
inline mqtt::v5::property::user_property operator""_user_property(char const* str, std::size_t length) {
// Search for separator character (Not sure what character to use. ';' could be one.
// Not knowing the right separator character is the reason why i say we probably shouldn't provide this function.
// return { mqtt::buffer(string_view of first part), mqtt::buffer(string_view of second part));
}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This PR is already very big and contains many(?) breaking changes. I'd like to consider the issue after the PR merged. Could you create a new issue for that?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I can make an issue.
I'm not sure it's a good idea.
Do you think it's a good idea to offer user-defined literals for all of the property types?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think that it is good idea for all single string-base properties such as Content Type, Response Topic.
It is not good for binary-base properties such as Correlation Data.
UserProperty is difficult. I think that user defined literals is not sutable for UserProperty. Because separator is required. I think that mqtt::v5::property::user_property("key1"_mb, "val1"_mb)
is simple enough.
@@ -0,0 +1,67 @@ | |||
// Copyright Takatoshi Kondo 2019 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For reference, here's the design for a "Shared String", that I use for my own code. (Note: Does not support custom allocators yet. Haven't had time)
Not saying your design is better or worse. Just showing you for sake of sharing design ideas.
I'd be happy to see some of my implementation ideas incorporated into mqtt_cpp, but it's certainly not necessary.
Having mqtt::buffer use a boost::shared_ptr under the hood means that I'm able to write a trivial conversion function from mqtt::buffer -> my "BasicSharedString" code.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you for sharing. I will check it later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Was the BasicSharedString implementation that I shared interesting to you?
|
||
inline namespace literals { | ||
|
||
inline buffer operator""_mb(char const* str, std::size_t length) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Probably put a brief comment here explaining that strings where user defined literals are used have indefinite lifetime in the read-only data section of the binary, and therefore no reference counting is needed.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I will add comments.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done(just my memo, not pushed yet).
namespace boost { | ||
namespace asio { | ||
|
||
inline const_buffer buffer(mqtt::buffer const& data) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A brief comment explaining that management of the mqtt::buffer.lifetime_ needs to happen outside the boost::asio::buffer, e.g. with the "life_keeper" parameters or similar.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I will add the comment.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done(just my memo, not pushed yet).
base::socket() = std::move(socket); | ||
connect_impl(*base::socket(), it, end, std::move(props), std::move(func)); | ||
socket_ = std::move(socket); | ||
base::socket_optional().emplace(socket_); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why make the socket optional for the base class? That seems weird, that an mqtt::endpoint could ever exist without a socket.
Can the socket be replaced during a session, for example?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It is the most difficult and controversy point of the PR I think.
Let me explain.
- The
optional
is only for lazy initialization. Once the socket is created then it would never be updated. - The design is the same as the current master.
mqtt_cpp/include/mqtt/endpoint.hpp
Lines 7302 to 7308 in 757cba1
/** * @brief Get Socket shared_ptr reference. * @return refereence of Socket unique_ptr */ std::shared_ptr<Socket>& socket() { return socket_; }
mqtt_cpp/include/mqtt/client.hpp
Lines 462 to 475 in 757cba1
void connect(std::vector<v5::property_variant> props, async_handler_t func = async_handler_t()) { as::ip::tcp::resolver r(ios_); #if BOOST_VERSION < 106600 as::ip::tcp::resolver::query q(host_, port_); auto it = r.resolve(q); as::ip::tcp::resolver::iterator end; #else // BOOST_VERSION < 106600 auto eps = r.resolve(host_, port_); auto it = eps.begin(); auto end = eps.end(); #endif // BOOST_VERSION < 106600 setup_socket(base::socket()); connect_impl(*base::socket(), it, end, std::move(props), std::move(func)); }
mqtt_cpp/include/mqtt/client.hpp
Lines 778 to 782 in 757cba1
#if !defined(MQTT_NO_TLS) template <typename Strand> void setup_socket(std::shared_ptr<tcp_endpoint<as::ssl::stream<as::ip::tcp::socket>, Strand>>& socket) { socket.reset(new Socket(ios_, ctx_)); } -
On TLS connection, user needs to setup
ssl::context
before connect. The socket requiresssl::context
as the constructor parameter. So the socket should be created in theconnect()
, not in theclient
constructor. However,endpoint
has the member ofshared_ptr<Scoket>
, so it is initialized as nullptr at construction time. Then lazy initialized inconnect()
. This is the original (master) design. -
In order to do the same things, I introduced
optional
in this PR. Becauseshared_any
cannot be initialized by nullptr. Because it requires a reference of the pointee that is hold by the shared_ptr.
-
That is the reason I introduced optional
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you for the explanation.
I'd rather this change be done separately from the mqtt::buffer changes
But I understand that that is a lot of work to separate the two changes.
Thoughts?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd rather this change be done separately from the mqtt::buffer changes
But I understand that that is a lot of work to separate the two changes.
Yes it is difficult. I can't separate them. Because type erasure is required for zero copy buffer without increasing compile times. So I'd like to go this way.
BTW, API socket_optional()
is protected. So ordinary user doesn't care about optional
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can they be separated into two separate commits, on the same PR?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If we keep successful compile result, we can't do that. Because zero copy and not slow compile times required both.
Once I commit slower compile times version, and then modify it, it could be possible but it is hard to me. It is unnecessary work and might take a long time.
So I'd like to commit them in the same commit.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Alright.
I understand.
I'm still not sure what causes the increased compile times, which is why I wanted to see your code by itself, but I understand that it's extra work.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I pushed the slow compile times branch that is not type erased.
It is not continuous to the current impl_320_2 branch but it might help to analyze the reason of compile times increasing.
https://github.com/redboltz/mqtt_cpp/tree/impl_320_no_te_slow_compile
include/mqtt/endpoint.hpp
Outdated
|
||
// process common | ||
|
||
templat |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
would
static constexpr char version_string = { 0x00, 0x04, 'M', 'Q', 'T', 'T' };
memcmp(buf, version_string, sizeof(version_string) != 0
be easier for people to read and understand?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think that the code reference is something wrong. Could you update it?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes. Something is wrong.
I was talking about where you compare the protocol identifier string on the incoming message.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok, I will fix it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done(just my memo, not pushed yet).
|
||
// process common | ||
|
||
templat |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not actually using anything captured by reference.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think that the code reference is something wrong. Could you update it?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes. This comment went to the wrong place somehow...
I was pointing out that there are some lambda functions in one of the process_*** functions that are
[&](){...}
But don't actually use any of the variables in the local context. So the & can be removed.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I will fix it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I noticed that [&]
is for this
. version_
is referred int the lambda expression.
I know that it is better to write the capture list explicitly but in this case, the lambda expression is defined and called in the same time. Dangling reference can't happen. Only in this case, I think that [&]
is acceptable. It is easy to maintain.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok. Sounds good.
|
||
// process common | ||
|
||
templat |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think that the code reference is something wrong. Could you update it?
include/mqtt/endpoint.hpp
Outdated
|
||
// process common | ||
|
||
templat |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
static constexpr
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think that the code reference is something wrong. Could you update it?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There are several
std::size_t size = ...
statements that are inside the "process_***" functions.
Those size variables could be static constexpr
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I will fix it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done(just my memo, not pushed yet).
|
||
// process common | ||
|
||
templat |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How practical would it be to make all of these process_*** functions into free functions, that accessed the member variables of the endpoint object via the passed in std::shared_ptr<endpoint<>> parameter?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think that the code reference is something wrong. Could you update it?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The code reference is wrong, but I was talking about process_connect
, and process_pingresp
and similar.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Some of proces_* functions access buf_
member variable to avoid allocation. It is a private member of endpoint.
For example https://github.com/redboltz/mqtt_cpp/blob/impl_320_2/include/mqtt/endpoint.hpp#L8487-L8505
I think that they should be member function and not practical to become free function. I think that frined function with endpoint parameter is worse than member function.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok. I understand.
|
||
// process common | ||
|
||
templat |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think that the code reference is something wrong. Could you update it?
I believe that I replied all of your comments. Before I update the code, could you check my comments? |
I think there may have been several places where comments were hidden that you did not see. I pointed out 2 of them, but there were multiple that I didn't see any response from you. |
* Reverted travis-ci linux distro to trusty from bionic. * Added documents for mqtt::buffer. * Added documents for mqtt::shared_ptr_array. * Added documents for mqtt::shared_any. * Removed unused include. * Added mqtt::buffer allocating function. * Replaced `&buf[0]` with `buf.data()` and `&buf_[0]` with `buf_.data()`. * Replaced `buf[0]` with `buf.front()` and `buf_[0]` with `buf_.front()` except continuous `buf[0]` amd `buf[1]` case. * Improved lambda capture on `async_read()`. * Replaced `static_cast` with `boost::numeric_cast` if error could happen. * Added comments for rvalue reference parameters in the local lambda expressions. * Added `calc_variable_length()` to avoid code repeatation. * Replaced `type const val = ...` with `static constexpr type const val = ...`. * Improved MQTT protocol name conparison. * Replaced `mqtt::string_view` passed by const reference with passed by value. * Replaced `buf = std::move(buf).substr(N)` with `buf.remove_prefix(N)`. * Replaecd iterator with plus operator with `std::next()`. * Fixed `topic_name_length_buf_` usage to easy to understand. * Fixed `parse_one()` return value and parameter to passed by reference. * Removed code repeatation from `shared_any`.
I just pushed the commit that fixes all of codes that I commented "done(just my memo, not pushed yet).". |
Ok. Do you think it's ready to submit now? Should I go through it one more time? |
I believe that it is ready to merge now. |
I will check it once more right now. It will take approximately 1 hr. Can we merge in approximately 1hr, if I don't see any problems? |
Sounds good. Thank you very much! |
/** | ||
* @brief shared_ptr_array creating function. | ||
* You can choose the target type. | ||
* - If MQTT_STD_SHARED_PTR_ARRAY is defined, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The CMakeLists.txt file does not offer an option to control this behavior, because this PR does not include changes to CMakeLists.txt
Was that something you planned to do?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I forgot adding MQTT_STD_SHARED_PTR_ARRAY to CMakeLists.txt. I will add the following code to CMakeLists.txt.
OPTION(MQTT_STD_SHARED_PTR_ARRAY "Use std::shared_ptr<char[]> from C++17 instead of boost::shared_ptr<char[]>" OFF)
...
IF (MQTT_STD_SHARED_PTR_ARRAY)
SET(CMAKE_CXX_STANDARD 17)
SET(CMAKE_CXX_STANDARD_REQUIRED ON)
MESSAGE (STATUS "Using std::shared_ptr<char []> instead of boost::shared_ptr<char []>. Enables C++17!!!")
SET (CMAKE_CXX_FLAGS "-DMQTT_STD_SHARED_PTR_ARRAY ${CMAKE_CXX_FLAGS}")
ELSE ()
MESSAGE (STATUS "Using boost::shared_ptr<char []> instead of boost::shared_ptr<char []>")
ENDIF ()
topic_name_ = as::buffer(&*b, topic_name_length); | ||
b += topic_name_length; | ||
if (buf.size() < topic_name_length) throw remaining_length_error(); | ||
utf8string_check(static_cast<mqtt::string_view>(buf).substr(0, topic_name_length)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A comment here explaining why you cast to mqtt::string_view would help future contributors.
In this case, the reason is to avoid increasing the reference count of buf when .substr() is called.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I agree. I will add a comment.
BOOST_TEST(v2.val() == v_ref2.val()); | ||
|
||
BOOST_AUTO_TEST_CASE( content_type ) { | ||
mqtt::v5::property::content_type v1 { "abc"_mb }; | ||
BOOST_TEST(boost::lexical_cast<std::string>(v1) == "abc"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't understand how boost::lexical_cast knows what to do with mqtt::v5::property::content_type ...?
Can you help me understand?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is a test for
std::ostream& operator<<(std::ostream&, mqtt::v4::property::content_type const&);
lexical_cast uses stream output operator. https://www.boost.org/doc/libs/1_71_0/doc/html/boost_lexical_cast/synopsis.html#boost_lexical_cast.synopsis.lexical_cast
It is easy to write test codes so I use lexical_cast.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah, I did not know that. Thank you for explaining.
include/mqtt/property.hpp
Outdated
@@ -915,123 +559,51 @@ class user_property_ref { | |||
std::size_t num_of_const_buffer_sequence() const { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can't this function be static constexpr?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, it should be. I will fix it. Including other three member functions.
include/mqtt/property.hpp
Outdated
@@ -869,31 +512,32 @@ class user_property_ref { | |||
void add_const_buffer_sequence(std::vector<as::const_buffer>& v) const { | |||
v.emplace_back(as::buffer(&id_, 1)); | |||
v.emplace_back(as::buffer(key_.len.data(), key_.len.size())); | |||
v.emplace_back(key_.str); | |||
v.emplace_back(as::buffer(key_.buf.data(), key_.buf.size())); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We now support
as::buffer(key_.buf)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah yes, I will replace it.
I have reviewed all files except endpoint.hpp. I am reviewing endpoint.hpp now. |
include/mqtt/endpoint.hpp
Outdated
typename std::iterator_traits<Iterator>::iterator_category, | ||
std::random_access_iterator_tag | ||
>::value, | ||
"Iterator doesn't support random access" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe better wording:
Iterators provided to restore_serialized_message() must be random access iterators.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks, I use your wording.
restore_serialized_message(basic_pubrel_message<PacketIdBytes>(b, e)); | ||
restore_serialized_message( | ||
basic_pubrel_message<PacketIdBytes>( | ||
buffer(string_view(&*b, static_cast<std::size_t>(std::distance(b, e)))) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A comment explaining why you construct the mqtt::buffer such that it does not own the data would be good to have.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I will add the following comment:
// basic_pubrel_message have no member variable that type is mqtt::buffer.
// When creating basic_pubrel_message, the constructor just read mqtt::buffer
// and convert to some values.
// So the argument buffer(...) doesn't need to hold the lifetime.
async_handler_t func, | ||
buffer buf, | ||
std::size_t size, | ||
std::function<void(buffer, buffer, async_handler_t, this_type_sp)> handler, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Would doing
using process_handler_t = std::function<void(buffer, buffer, async_handler_t, this_type_sp)>;
improve the code?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There are some variations as follows:
std::function<void(packet_id_t, buffer, async_handler_t, this_type_sp)> handler,
std::function<void(buffer, buffer, async_handler_t, this_type_sp)> handler,
So if we introduce type aliases, naming is difficult. I think that current implementation is good enough.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok.
include/mqtt/endpoint.hpp
Outdated
call_message_size_error_handlers(func); | ||
return; | ||
} | ||
if (buf.front() & 0b10000000) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think that 0b10000000 should be a named constant.
E.g.
static constexpr std::uint8_t variable_length_flag = 0b10000000
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok I will introduce the constant.
include/mqtt/endpoint.hpp
Outdated
if (!check_error_and_transferred_length(ec, func, bytes_transferred, 1)) return; | ||
proc( | ||
std::move(func), | ||
buffer(string_view(buf_.data(), 1)), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Make a comment saying the lifetime of buf_
is handled by self
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I will add comment.
include/mqtt/endpoint.hpp
Outdated
if (property_length_rest < len) { | ||
call_message_size_error_handlers(func); | ||
return; | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Typos.
paramter
= parameter
controll
= control
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I will fix them.
I've reviewed about 2/3 of endpoint.hpp, and haven't seen any major problems. I think i'm going to stop now, I ran out of time. I think this pull request can be merged when you've reviewed my comments from the last hour. |
Also, did you notice that the PR does not think that changes to .travis.yaml were reverted? |
It should be reverted to trusty. I made a mistake to remove that commit. I will fix it. |
Removed magic number and add constant. Added comments for developer. Updated `num_of_const_buffer_sequence()` from member function to static constexpr function.
I don't know way but codecov upload failed on `pr`.
Looking good! |
Added buffer class that supports
mqtt::string_view
compatiblebehavior and life keekping mechanism (optional).
Callback functions for users hold receive buffer directly via
buffer
.Removed
*_ref
properties. Ref or not ref is hidden bybuffer
.Added
""_mb
user defined literals forbuffer
.Added boost type_erasure.
mqtt::socket
is type erased socket. It covers tcp, tls, ws, and wss.Compile times become faster.
Replaced static_cast with boost::numeric_cast if overflow could happen.
Removed redundant static_cast.
Implemented efficient shared_ptr_array allocation.
If use boost (default), then use
boost::make_shared<char[]>(size)
.If user defines MQTT_STD_SHARED_PTR_ARRAY,
if __cplusplus is greater than 201703L (means C++20 or later),
then
std::make_shared<char[]>(size)
,otherwise
std::shared_ptr<char[]>(new size)
is called.