-
Notifications
You must be signed in to change notification settings - Fork 1.6k
Add a nanopb string #1839
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
Add a nanopb string #1839
Changes from all commits
eb5e474
52f3401
55696c4
1f1655f
833981a
9435631
f5838ad
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,66 @@ | ||
/* | ||
* Copyright 2018 Google | ||
* | ||
* Licensed under the Apache License, Version 2.0 (the "License"); | ||
* you may not use this file except in compliance with the License. | ||
* You may obtain a copy of the License at | ||
* | ||
* http://www.apache.org/licenses/LICENSE-2.0 | ||
* | ||
* Unless required by applicable law or agreed to in writing, software | ||
* distributed under the License is distributed on an "AS IS" BASIS, | ||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
* See the License for the specific language governing permissions and | ||
* limitations under the License. | ||
*/ | ||
|
||
#include "Firestore/core/src/firebase/firestore/nanopb/nanopb_string.h" | ||
|
||
#include <cstdlib> | ||
#include <utility> | ||
|
||
namespace firebase { | ||
namespace firestore { | ||
namespace nanopb { | ||
|
||
/* static */ pb_bytes_array_t* String::MakeBytesArray(absl::string_view value) { | ||
auto size = static_cast<pb_size_t>(value.size()); | ||
|
||
// Allocate one extra byte for the null terminator that's not necessarily | ||
// there in a string_view. As long as we're making a copy, might as well | ||
// make a copy that won't overrun when used as a regular C string. This is | ||
// essentially just to make debugging easier--actual user data can have | ||
// embedded nulls so we shouldn't be using this as a C string under normal | ||
// circumstances. | ||
auto result = static_cast<pb_bytes_array_t*>( | ||
malloc(PB_BYTES_ARRAY_T_ALLOCSIZE(size) + 1)); | ||
result->size = size; | ||
memcpy(result->bytes, value.data(), size); | ||
result->bytes[size] = '\0'; | ||
|
||
return result; | ||
} | ||
|
||
pb_bytes_array_t* String::release() { | ||
pb_bytes_array_t* result = bytes_; | ||
bytes_ = nullptr; | ||
return result; | ||
} | ||
|
||
void swap(String& lhs, String& rhs) noexcept { | ||
using std::swap; | ||
swap(lhs.bytes_, rhs.bytes_); | ||
} | ||
|
||
/* static */ String String::Wrap(pb_bytes_array_t* bytes) { | ||
return String{bytes}; | ||
} | ||
|
||
/* static */ absl::string_view String::ToStringView(pb_bytes_array_t* bytes) { | ||
const char* str = reinterpret_cast<const char*>(bytes->bytes); | ||
return absl::string_view{str, bytes->size}; | ||
} | ||
|
||
} // namespace nanopb | ||
} // namespace firestore | ||
} // namespace firebase |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,153 @@ | ||
/* | ||
* Copyright 2018 Google | ||
* | ||
* Licensed under the Apache License, Version 2.0 (the "License"); | ||
* you may not use this file except in compliance with the License. | ||
* You may obtain a copy of the License at | ||
* | ||
* http://www.apache.org/licenses/LICENSE-2.0 | ||
* | ||
* Unless required by applicable law or agreed to in writing, software | ||
* distributed under the License is distributed on an "AS IS" BASIS, | ||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
* See the License for the specific language governing permissions and | ||
* limitations under the License. | ||
*/ | ||
|
||
#ifndef FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_NANOPB_NANOPB_STRING_H_ | ||
#define FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_NANOPB_NANOPB_STRING_H_ | ||
|
||
#include <pb.h> | ||
|
||
#include <string> | ||
#include <utility> | ||
|
||
#include "Firestore/core/src/firebase/firestore/util/comparison.h" | ||
#include "absl/strings/string_view.h" | ||
|
||
namespace firebase { | ||
namespace firestore { | ||
namespace nanopb { | ||
|
||
/** | ||
* A string-like object backed by a nanopb byte array. | ||
*/ | ||
class String : public util::Comparable<String> { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. docstrings might be nice. Specifically, something mentioning that the ctor copies it's arguments. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yup. As submitted I was trying to figure out if it was worth investing in such things. |
||
public: | ||
/** | ||
* Creates a new, null-terminated byte array that's a copy of the given string | ||
* value. | ||
*/ | ||
static pb_bytes_array_t* MakeBytesArray(absl::string_view value); | ||
|
||
String() { | ||
} | ||
|
||
/** | ||
* Creates a new String whose backing byte array is a copy of the of the | ||
* given C string. | ||
*/ | ||
explicit String(const char* value) : bytes_{MakeBytesArray(value)} { | ||
} | ||
|
||
/** | ||
* Creates a new String whose backing byte array is a copy of the of the | ||
* given string. | ||
*/ | ||
explicit String(const std::string& value) : bytes_{MakeBytesArray(value)} { | ||
} | ||
|
||
/** | ||
* Creates a new String whose backing byte array is a copy of the of the | ||
* given string_view. | ||
*/ | ||
explicit String(absl::string_view value) : bytes_{MakeBytesArray(value)} { | ||
} | ||
|
||
String(const String& other) | ||
: bytes_{MakeBytesArray(absl::string_view{other})} { | ||
} | ||
|
||
String(String&& other) noexcept : String{} { | ||
swap(*this, other); | ||
} | ||
|
||
~String() { | ||
delete bytes_; | ||
} | ||
|
||
String& operator=(String other) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Performance nit: Rather than this function, you could implement:
This would allow you to eliminate the copy in the move case. If you want to do this, but don't care to now, you could just defer it with a TODO. |
||
swap(*this, other); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Spelling There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I've removed the using statement here because it's clearly the case that we want to invoke the friend function below. However, in the other case |
||
return *this; | ||
} | ||
|
||
/** | ||
* Creates a new String that takes ownership of the given byte array. | ||
*/ | ||
static String Wrap(pb_bytes_array_t* bytes); | ||
|
||
bool empty() const { | ||
return !bytes_ || bytes_->size == 0; | ||
} | ||
|
||
/** | ||
* Returns a pointer to the character data backing this String. The return | ||
* value is `nullptr` if the backing bytes are themselves null. | ||
*/ | ||
const char* data() const { | ||
return bytes_ ? reinterpret_cast<const char*>(bytes_->bytes) : nullptr; | ||
} | ||
|
||
/** Returns a const view of the underlying byte array. */ | ||
const pb_bytes_array_t* get() const { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. An alternative: string_view calls it's equivalent method |
||
return bytes_; | ||
} | ||
|
||
/** | ||
* Returns the current byte array and assigns the backing byte array to | ||
* nullptr, releasing the ownership of the array contents to the caller. | ||
*/ | ||
pb_bytes_array_t* release(); | ||
|
||
/** | ||
* Converts this String to an absl::string_view (without changing ownership). | ||
*/ | ||
explicit operator absl::string_view() const { | ||
return ToStringView(bytes_); | ||
} | ||
|
||
/** | ||
* Swaps the contents of the given Strings. | ||
*/ | ||
friend void swap(String& lhs, String& rhs) noexcept; | ||
|
||
friend bool operator==(const String& lhs, const String& rhs) { | ||
return absl::string_view{lhs} == absl::string_view{rhs}; | ||
} | ||
friend bool operator<(const String& lhs, const String& rhs) { | ||
return absl::string_view{lhs} < absl::string_view{rhs}; | ||
} | ||
|
||
friend bool operator==(const String& lhs, absl::string_view rhs) { | ||
absl::string_view lhs_view{lhs}; | ||
return lhs_view == rhs; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. For consistency with the above operators, you could implement this as: There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. For whatever reason that trips up the linter. We can either do this or something like: return absl::string_view{lhs} == rhs; // NOLINT(whitespace/braces) There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Well that's strange. Either is fine with me; there's no point fighting the linter. |
||
} | ||
|
||
friend bool operator!=(const String& lhs, absl::string_view rhs) { | ||
return !(lhs == rhs); | ||
} | ||
|
||
private: | ||
explicit String(pb_bytes_array_t* bytes) : bytes_{bytes} { | ||
} | ||
|
||
static absl::string_view ToStringView(pb_bytes_array_t* bytes); | ||
|
||
pb_bytes_array_t* bytes_ = nullptr; | ||
}; | ||
|
||
} // namespace nanopb | ||
} // namespace firestore | ||
} // namespace firebase | ||
|
||
#endif // FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_NANOPB_NANOPB_STRING_H_ | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. You might consider moving some of the implementation to a .cc file. Though leaving it inline here actually seems ok too. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Done. |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
# Copyright 2018 Google | ||
# | ||
# Licensed under the Apache License, Version 2.0 (the "License"); | ||
# you may not use this file except in compliance with the License. | ||
# You may obtain a copy of the License at | ||
# | ||
# http://www.apache.org/licenses/LICENSE-2.0 | ||
# | ||
# Unless required by applicable law or agreed to in writing, software | ||
# distributed under the License is distributed on an "AS IS" BASIS, | ||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
# See the License for the specific language governing permissions and | ||
# limitations under the License. | ||
|
||
cc_test( | ||
firebase_firestore_nanopb_test | ||
SOURCES | ||
nanopb_string_test.cc | ||
DEPENDS | ||
firebase_firestore_nanopb | ||
) |
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.
You'll eventually want some unit tests for this too.
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.