Skip to content

Commit 55696c4

Browse files
committed
Flesh out nanopb_string
1 parent 52f3401 commit 55696c4

File tree

8 files changed

+248
-29
lines changed

8 files changed

+248
-29
lines changed

Firestore/Example/Firestore.xcodeproj/project.pbxproj

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -179,6 +179,7 @@
179179
7346E61D20325C6900FD6CEF /* FSTDispatchQueueTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = 7346E61C20325C6900FD6CEF /* FSTDispatchQueueTests.mm */; };
180180
73866AA12082B0A5009BB4FF /* FIRArrayTransformTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = 73866A9F2082B069009BB4FF /* FIRArrayTransformTests.mm */; };
181181
73FE5066020EF9B2892C86BF /* hard_assert_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = 444B7AB3F5A2929070CB1363 /* hard_assert_test.cc */; };
182+
84DBE646DCB49305879D3500 /* nanopb_string_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = 353EEE078EF3F39A9B7279F6 /* nanopb_string_test.cc */; };
182183
873B8AEB1B1F5CCA007FD442 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 873B8AEA1B1F5CCA007FD442 /* Main.storyboard */; };
183184
8C82D4D3F9AB63E79CC52DC8 /* Pods_Firestore_IntegrationTests_iOS.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = ECEBABC7E7B693BE808A1052 /* Pods_Firestore_IntegrationTests_iOS.framework */; };
184185
AB356EF7200EA5EB0089B766 /* field_value_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = AB356EF6200EA5EB0089B766 /* field_value_test.cc */; };
@@ -308,6 +309,7 @@
308309
2A0CF41BA5AED6049B0BEB2C /* type_traits_apple_test.mm */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.cpp.objcpp; path = type_traits_apple_test.mm; sourceTree = "<group>"; };
309310
2B50B3A0DF77100EEE887891 /* Pods_Firestore_Tests_iOS.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Firestore_Tests_iOS.framework; sourceTree = BUILT_PRODUCTS_DIR; };
310311
332485C4DCC6BA0DBB5E31B7 /* leveldb_util_test.cc */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.cpp.cpp; path = leveldb_util_test.cc; sourceTree = "<group>"; };
312+
353EEE078EF3F39A9B7279F6 /* nanopb_string_test.cc */ = {isa = PBXFileReference; includeInIndex = 1; name = nanopb_string_test.cc; path = nanopb/nanopb_string_test.cc; sourceTree = "<group>"; };
311313
358C3B5FE573B1D60A4F7592 /* strerror_test.cc */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.cpp.cpp; path = strerror_test.cc; sourceTree = "<group>"; };
312314
3B843E4A1F3930A400548890 /* remote_store_spec_test.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = remote_store_spec_test.json; sourceTree = "<group>"; };
313315
3C81DE3772628FE297055662 /* Pods-Firestore_Example_iOS.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Firestore_Example_iOS.debug.xcconfig"; path = "Pods/Target Support Files/Pods-Firestore_Example_iOS/Pods-Firestore_Example_iOS.debug.xcconfig"; sourceTree = "<group>"; };
@@ -729,6 +731,7 @@
729731
54EB764B202277970088B8F3 /* immutable */,
730732
54995F70205B6E1A004EFFA0 /* local */,
731733
AB356EF5200E9D1A0089B766 /* model */,
734+
5C332D7293E6114E491D3662 /* nanopb */,
732735
546854A720A3681B004BDBD5 /* remote */,
733736
5467FB05203E652F009C9584 /* testutil */,
734737
54740A561FC913EB00713A1A /* util */,
@@ -781,6 +784,14 @@
781784
path = immutable;
782785
sourceTree = "<group>";
783786
};
787+
5C332D7293E6114E491D3662 /* nanopb */ = {
788+
isa = PBXGroup;
789+
children = (
790+
353EEE078EF3F39A9B7279F6 /* nanopb_string_test.cc */,
791+
);
792+
name = nanopb;
793+
sourceTree = "<group>";
794+
};
784795
5CAE131A20FFFED600BE9A4A /* Benchmarks */ = {
785796
isa = PBXGroup;
786797
children = (
@@ -1939,6 +1950,7 @@
19391950
AB6B908620322E6D00CC290A /* maybe_document_test.cc in Sources */,
19401951
618BBEA820B89AAC00B5BCE7 /* mutation.pb.cc in Sources */,
19411952
32F022CB75AEE48CDDAF2982 /* mutation_test.cc in Sources */,
1953+
84DBE646DCB49305879D3500 /* nanopb_string_test.cc in Sources */,
19421954
AB6B908820322E8800CC290A /* no_document_test.cc in Sources */,
19431955
AB380D04201BC6E400D97691 /* ordered_code_test.cc in Sources */,
19441956
5A080105CCBFDB6BF3F3772D /* path_test.cc in Sources */,

Firestore/core/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,5 +31,6 @@ add_subdirectory(test/firebase/firestore/core)
3131
add_subdirectory(test/firebase/firestore/immutable)
3232
add_subdirectory(test/firebase/firestore/local)
3333
add_subdirectory(test/firebase/firestore/model)
34+
add_subdirectory(test/firebase/firestore/nanopb)
3435
add_subdirectory(test/firebase/firestore/remote)
3536
add_subdirectory(test/firebase/firestore/util)

Firestore/core/src/firebase/firestore/nanopb/CMakeLists.txt

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,11 @@
1515
cc_library(
1616
firebase_firestore_nanopb
1717
SOURCES
18-
tag.h
18+
nanopb_string.cc
19+
nanopb_string.h
1920
reader.h
2021
reader.cc
22+
tag.h
2123
writer.h
2224
writer.cc
2325
DEPENDS
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
/*
2+
* Copyright 2018 Google
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
#include "Firestore/core/src/firebase/firestore/nanopb/nanopb_string.h"
18+
19+
#include <cstdlib>
20+
#include <utility>
21+
22+
namespace firebase {
23+
namespace firestore {
24+
namespace nanopb {
25+
26+
/* static */ pb_bytes_array_t* String::MakeBytesArray(absl::string_view value) {
27+
auto size = static_cast<pb_size_t>(value.size());
28+
29+
// Allocate one extra byte for the null terminator that's not necessarily
30+
// there in a string_view. As long as we're making a copy, might as well
31+
// make a copy that can be used as a regular C string too.
32+
auto result = static_cast<pb_bytes_array_t*>(
33+
malloc(PB_BYTES_ARRAY_T_ALLOCSIZE(size) + 1));
34+
result->size = size;
35+
memcpy(result->bytes, value.data(), size);
36+
result->bytes[size] = '\0';
37+
38+
return result;
39+
}
40+
41+
pb_bytes_array_t* String::release() {
42+
pb_bytes_array_t* result = bytes_;
43+
bytes_ = nullptr;
44+
return result;
45+
}
46+
47+
void swap(String& lhs, String& rhs) noexcept {
48+
using std::swap;
49+
swap(lhs.bytes_, rhs.bytes_);
50+
}
51+
52+
/* static */ String String::Wrap(pb_bytes_array_t* bytes) {
53+
return String{bytes};
54+
}
55+
56+
/* static */ absl::string_view String::ToStringView(pb_bytes_array_t* bytes) {
57+
const char* str = reinterpret_cast<const char*>(bytes->bytes);
58+
return absl::string_view{str, bytes->size};
59+
}
60+
61+
} // namespace nanopb
62+
} // namespace firestore
63+
} // namespace firebase

Firestore/core/src/firebase/firestore/nanopb/nanopb_string.h

Lines changed: 54 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,6 @@
1919

2020
#include <pb.h>
2121

22-
#include <cstdlib>
23-
#include <functional>
2422
#include <string>
2523
#include <utility>
2624

@@ -31,32 +29,38 @@ namespace firebase {
3129
namespace firestore {
3230
namespace nanopb {
3331

32+
/**
33+
* A string-like object backed by a nanopb byte array.
34+
*/
3435
class String : public util::Comparable<String> {
3536
public:
36-
static pb_bytes_array_t* MakeBytesArray(absl::string_view value) {
37-
auto size = static_cast<pb_size_t>(value.size());
38-
39-
// Allocate one extra byte for the null terminator that's not necessarily
40-
// there in a string_view. As long as we're making a copy, might as well
41-
// make a copy that can be used as a regular C string too.
42-
auto result = reinterpret_cast<pb_bytes_array_t*>(
43-
malloc(PB_BYTES_ARRAY_T_ALLOCSIZE(size) + 1));
44-
result->size = size;
45-
memcpy(result->bytes, value.data(), size);
46-
result->bytes[size] = '\0';
47-
48-
return result;
49-
}
37+
/**
38+
* Creates a new, null-terminated byte array that's a copy of the given string
39+
* value.
40+
*/
41+
static pb_bytes_array_t* MakeBytesArray(absl::string_view value);
5042

5143
String() {
5244
}
5345

46+
/**
47+
* Creates a new String whose backing byte array is a copy of the of the
48+
* given C string.
49+
*/
5450
explicit String(const char* value) : bytes_{MakeBytesArray(value)} {
5551
}
5652

53+
/**
54+
* Creates a new String whose backing byte array is a copy of the of the
55+
* given string.
56+
*/
5757
explicit String(const std::string& value) : bytes_{MakeBytesArray(value)} {
5858
}
5959

60+
/**
61+
* Creates a new String whose backing byte array is a copy of the of the
62+
* given string_view.
63+
*/
6064
explicit String(absl::string_view value) : bytes_{MakeBytesArray(value)} {
6165
}
6266

@@ -73,29 +77,46 @@ class String : public util::Comparable<String> {
7377
}
7478

7579
String& operator=(String other) {
76-
using std::swap;
7780
swap(*this, other);
7881
return *this;
7982
}
8083

81-
size_t Hash() const {
82-
std::hash<absl::string_view>{}.operator()(absl::string_view{*this});
83-
}
84+
/**
85+
* Creates a new String that takes ownership of the given byte array.
86+
*/
87+
static String Wrap(pb_bytes_array_t* bytes);
8488

8589
bool empty() const {
8690
return !bytes_ || bytes_->size == 0;
8791
}
8892

89-
explicit operator absl::string_view() const {
90-
const char* str = reinterpret_cast<const char*>(bytes_->bytes);
91-
return absl::string_view{str, bytes_->size};
93+
const char* c_str() const {
94+
return bytes_ ? reinterpret_cast<const char*>(bytes_->bytes) : nullptr;
9295
}
9396

94-
friend void swap(String& lhs, String& rhs) noexcept {
95-
using std::swap;
96-
swap(lhs.bytes_, rhs.bytes_);
97+
/** Returns a const view of the underlying byte array. */
98+
const pb_bytes_array_t* get() const {
99+
return bytes_;
97100
}
98101

102+
/**
103+
* Returns the current byte array and assigns the backing byte array to
104+
* nullptr, releasing the ownership of the array contents to the caller.
105+
*/
106+
pb_bytes_array_t* release();
107+
108+
/**
109+
* Converts this String to an absl::string_view (without changing ownership).
110+
*/
111+
explicit operator absl::string_view() const {
112+
return ToStringView(bytes_);
113+
}
114+
115+
/**
116+
* Swaps the contents of the given Strings.
117+
*/
118+
friend void swap(String& lhs, String& rhs) noexcept;
119+
99120
friend bool operator==(const String& lhs, const String& rhs) {
100121
return absl::string_view{lhs} == absl::string_view{rhs};
101122
}
@@ -107,13 +128,19 @@ class String : public util::Comparable<String> {
107128
absl::string_view lhs_view{lhs};
108129
return lhs_view == rhs;
109130
}
131+
110132
friend bool operator!=(const String& lhs, absl::string_view rhs) {
111133
return !(lhs == rhs);
112134
}
113135

114136
private:
137+
explicit String(pb_bytes_array_t* bytes) : bytes_{bytes} {
138+
}
139+
140+
static absl::string_view ToStringView(pb_bytes_array_t* bytes);
141+
115142
pb_bytes_array_t* bytes_ = nullptr;
116-
}; // namespace nanopb
143+
};
117144

118145
} // namespace nanopb
119146
} // namespace firestore

Firestore/core/src/firebase/firestore/util/comparison.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -196,7 +196,7 @@ class Comparable : public Equatable<T> {
196196
friend bool operator<=(const T& lhs, const T& rhs) {
197197
return !(rhs < lhs);
198198
}
199-
friend bool operator<=(const T& lhs, const T& rhs) {
199+
friend bool operator>=(const T& lhs, const T& rhs) {
200200
return !(lhs < rhs);
201201
}
202202
};
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
# Copyright 2018 Google
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
15+
cc_test(
16+
firebase_firestore_nanopb_test
17+
SOURCES
18+
nanopb_string_test.cc
19+
DEPENDS
20+
firebase_firestore_nanopb
21+
)
Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
/*
2+
* Copyright 2018 Google
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
#include "Firestore/core/src/firebase/firestore/nanopb/nanopb_string.h"
18+
19+
#include "gtest/gtest.h"
20+
21+
namespace firebase {
22+
namespace firestore {
23+
namespace nanopb {
24+
25+
TEST(String, DefaultConstructor) {
26+
String str;
27+
ASSERT_EQ(nullptr, str.c_str());
28+
}
29+
30+
TEST(String, FromStdString) {
31+
std::string original{"foo"};
32+
String copy{original};
33+
ASSERT_EQ(copy, original);
34+
35+
original = "bar";
36+
ASSERT_EQ(copy, "foo");
37+
}
38+
39+
TEST(String, FromCString) {
40+
char original[] = {'f', 'o', 'o', '\0'};
41+
String copy{original};
42+
ASSERT_EQ(copy, original);
43+
44+
original[0] = 'b';
45+
ASSERT_EQ(copy, "foo");
46+
}
47+
48+
TEST(String, WrapByteArray) {
49+
auto original =
50+
static_cast<pb_bytes_array_t*>(malloc(PB_BYTES_ARRAY_T_ALLOCSIZE(4)));
51+
memcpy(original->bytes, "foo", 4); // null terminator
52+
original->size = 3;
53+
54+
String wrapper = String::Wrap(original);
55+
ASSERT_EQ(wrapper, absl::string_view{"foo"});
56+
57+
original->bytes[0] = 'b';
58+
ASSERT_EQ(wrapper, absl::string_view{"boo"});
59+
}
60+
61+
TEST(String, Release) {
62+
String value{"foo"};
63+
64+
pb_bytes_array_t* released = value.release();
65+
ASSERT_EQ(released->size, 3);
66+
ASSERT_EQ(memcmp(released->bytes, "foo", 3), 0);
67+
ASSERT_EQ(value.get(), nullptr);
68+
69+
free(released);
70+
}
71+
72+
TEST(String, Comparison) {
73+
String abc{"abc"};
74+
String def{"def"};
75+
76+
String abc2{"abc"};
77+
78+
ASSERT_TRUE(abc == abc);
79+
ASSERT_TRUE(abc == abc2);
80+
ASSERT_TRUE(abc != def);
81+
82+
ASSERT_TRUE(abc < def);
83+
ASSERT_TRUE(abc <= def);
84+
ASSERT_TRUE(abc <= abc2);
85+
86+
ASSERT_TRUE(def > abc);
87+
ASSERT_TRUE(def >= abc);
88+
ASSERT_TRUE(abc2 >= abc);
89+
}
90+
91+
} // namespace nanopb
92+
} // namespace firestore
93+
} // namespace firebase

0 commit comments

Comments
 (0)