aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorGravatar Gil <mcg@google.com>2018-01-08 08:57:36 -0800
committerGravatar GitHub <noreply@github.com>2018-01-08 08:57:36 -0800
commit0f6103e4048242aa066b4ae0e0473578b50b559c (patch)
tree7f5e450db0a866f29a5bd0e64f7a40e6a264825e
parentbc74670afec651c3f912cb6b7e54f5b68bd507f5 (diff)
Port StringPrintf from //base (#624)
* Port StringPrintf from //base. Prefer this to approaches based on variadic templates. While the variadic template mechanisms are strictly safer, they result in binary bloat we can't afford. This is essentially the same StringPrintf previously open sourced as a part of protobuf, though updated for C++11 which saves a copy and a temporary buffer on the heap. * Add abseil as a subdirectory of Firestore This saves having to redefine all the libraries that abseil defines as imported libraries. * Rename firebase_firesture_util_log_* targets Cut the log out of the name to reflect that these will get more components besides just logging.
-rw-r--r--CMakeLists.txt1
-rw-r--r--Firestore/CMakeLists.txt1
-rw-r--r--Firestore/Example/Firestore.xcodeproj/project.pbxproj6
-rw-r--r--Firestore/core/src/firebase/firestore/util/CMakeLists.txt41
-rw-r--r--Firestore/core/src/firebase/firestore/util/string_printf.cc101
-rw-r--r--Firestore/core/src/firebase/firestore/util/string_printf.h48
-rw-r--r--Firestore/core/test/firebase/firestore/util/CMakeLists.txt13
-rw-r--r--Firestore/core/test/firebase/firestore/util/string_printf_test.cc78
-rw-r--r--Firestore/third_party/abseil-cpp/CMakeLists.txt8
-rw-r--r--cmake/external/abseil-cpp.cmake35
-rw-r--r--cmake/external/firestore.cmake2
11 files changed, 280 insertions, 54 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 52a4376..edcd611 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -40,5 +40,4 @@ include(external/FirebaseCore)
include(external/googletest)
include(external/leveldb)
-include(external/abseil-cpp)
include(external/firestore)
diff --git a/Firestore/CMakeLists.txt b/Firestore/CMakeLists.txt
index cffd015..9b90815 100644
--- a/Firestore/CMakeLists.txt
+++ b/Firestore/CMakeLists.txt
@@ -57,4 +57,5 @@ if(APPLE)
endif(APPLE)
enable_testing()
+add_subdirectory(third_party/abseil-cpp EXCLUDE_FROM_ALL)
add_subdirectory(core)
diff --git a/Firestore/Example/Firestore.xcodeproj/project.pbxproj b/Firestore/Example/Firestore.xcodeproj/project.pbxproj
index faed0b8..a8ad799 100644
--- a/Firestore/Example/Firestore.xcodeproj/project.pbxproj
+++ b/Firestore/Example/Firestore.xcodeproj/project.pbxproj
@@ -24,6 +24,7 @@
/* Begin PBXBuildFile section */
3B843E4C1F3A182900548890 /* remote_store_spec_test.json in Resources */ = {isa = PBXBuildFile; fileRef = 3B843E4A1F3930A400548890 /* remote_store_spec_test.json */; };
+ 5436F32420008FAD006E51E3 /* string_printf_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = 5436F32320008FAD006E51E3 /* string_printf_test.cc */; };
54740A571FC914BA00713A1A /* secure_random_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = 54740A531FC913E500713A1A /* secure_random_test.cc */; };
54740A581FC914F000713A1A /* autoid_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = 54740A521FC913E500713A1A /* autoid_test.cc */; };
54764FAB1FAA0C320085E60A /* string_util_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = 54764FAA1FAA0C320085E60A /* string_util_test.cc */; };
@@ -186,6 +187,7 @@
3B843E4A1F3930A400548890 /* remote_store_spec_test.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = remote_store_spec_test.json; sourceTree = "<group>"; };
42491D7DC8C8CD245CC22B93 /* Pods-SwiftBuildTest.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-SwiftBuildTest.debug.xcconfig"; path = "Pods/Target Support Files/Pods-SwiftBuildTest/Pods-SwiftBuildTest.debug.xcconfig"; sourceTree = "<group>"; };
4EBC5F5ABE1FD097EFE5E224 /* Pods-Firestore_Example.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Firestore_Example.release.xcconfig"; path = "Pods/Target Support Files/Pods-Firestore_Example/Pods-Firestore_Example.release.xcconfig"; sourceTree = "<group>"; };
+ 5436F32320008FAD006E51E3 /* string_printf_test.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = string_printf_test.cc; path = ../../core/test/firebase/firestore/util/string_printf_test.cc; sourceTree = "<group>"; };
54740A521FC913E500713A1A /* autoid_test.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = autoid_test.cc; path = ../../core/test/firebase/firestore/util/autoid_test.cc; sourceTree = "<group>"; };
54740A531FC913E500713A1A /* secure_random_test.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = secure_random_test.cc; path = ../../core/test/firebase/firestore/util/secure_random_test.cc; sourceTree = "<group>"; };
54764FAA1FAA0C320085E60A /* string_util_test.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = string_util_test.cc; path = ../../Port/string_util_test.cc; sourceTree = "<group>"; };
@@ -376,6 +378,7 @@
54740A521FC913E500713A1A /* autoid_test.cc */,
54C2294E1FECABAE007D065B /* log_test.cc */,
54740A531FC913E500713A1A /* secure_random_test.cc */,
+ 5436F32320008FAD006E51E3 /* string_printf_test.cc */,
);
name = util;
sourceTree = "<group>";
@@ -1186,6 +1189,7 @@
DE51B1F41F0D491B0013853F /* FSTRemoteEventTests.m in Sources */,
54E928241F33953300C1953E /* FSTEventAccumulator.m in Sources */,
DE51B1D11F0D48CD0013853F /* FSTTargetIDGeneratorTests.m in Sources */,
+ 5436F32420008FAD006E51E3 /* string_printf_test.cc in Sources */,
DE51B1EF1F0D49140013853F /* FSTDocumentTests.m in Sources */,
DE51B1DC1F0D490D0013853F /* FSTLocalSerializerTests.m in Sources */,
DE51B1E71F0D490D0013853F /* FSTRemoteDocumentChangeBufferTests.m in Sources */,
@@ -1454,6 +1458,7 @@
HEADER_SEARCH_PATHS = (
"$(inherited)",
"\"${PODS_ROOT}/../../..\"",
+ "\"${PODS_ROOT}/../../../Firestore/third_party/abseil-cpp\"",
"\"${PODS_ROOT}/leveldb-library/include\"",
"\"${PODS_ROOT}/GoogleTest/googletest/include\"",
);
@@ -1486,6 +1491,7 @@
HEADER_SEARCH_PATHS = (
"$(inherited)",
"\"${PODS_ROOT}/../../..\"",
+ "\"${PODS_ROOT}/../../../Firestore/third_party/abseil-cpp\"",
"\"${PODS_ROOT}/leveldb-library/include\"",
"\"${PODS_ROOT}/GoogleTest/googletest/include\"",
);
diff --git a/Firestore/core/src/firebase/firestore/util/CMakeLists.txt b/Firestore/core/src/firebase/firestore/util/CMakeLists.txt
index d70397d..a2da3b4 100644
--- a/Firestore/core/src/firebase/firestore/util/CMakeLists.txt
+++ b/Firestore/core/src/firebase/firestore/util/CMakeLists.txt
@@ -12,50 +12,71 @@
# See the License for the specific language governing permissions and
# limitations under the License.
+# firebase_firestore_util is the interface of this module. The rest of the
+# libraries in here are an implementation detail of making this a
+# mutli-platform build.
+
add_library(
- firebase_firestore_util
- autoid.cc
+ firebase_firestore_util_base
secure_random_arc4random.cc
+ string_printf.cc
+)
+target_link_libraries(
+ firebase_firestore_util_base
+ PRIVATE
+ absl_base
)
-# log_stdio can be built and tested everywhere
+# stdio-dependent bits can be built and tested everywhere
add_library(
- firebase_firestore_util_log_stdio
+ firebase_firestore_util_stdio
log_stdio.cc
)
+target_link_libraries(
+ firebase_firestore_util_stdio
+ PUBLIC
+ firebase_firestore_util_base
+)
-# log_apple can only built and tested on apple plaforms
+# apple-dependent bits can only built and tested on apple plaforms
if(APPLE)
add_library(
- firebase_firestore_util_log_apple
+ firebase_firestore_util_apple
log_apple.mm
)
target_compile_options(
- firebase_firestore_util_log_apple
+ firebase_firestore_util_apple
PRIVATE
${OBJC_FLAGS}
)
target_link_libraries(
- firebase_firestore_util_log_apple
+ firebase_firestore_util_apple
PUBLIC
FirebaseCore
)
endif(APPLE)
+add_library(
+ firebase_firestore_util
+ autoid.cc
+)
+
# Export a dependency on the correct logging library for this platform. All
# buildable libraries are built and tested but only the best fit is exported.
if(APPLE)
target_link_libraries(
firebase_firestore_util
PUBLIC
- firebase_firestore_util_log_apple
+ firebase_firestore_util_apple
+ firebase_firestore_util_base
)
else(NOT APPLE)
target_link_libraries(
firebase_firestore_util
PUBLIC
- firebase_firestore_util_log_stdio
+ firebase_firestore_util_stdio
+ firebase_firestore_util_base
)
endif(APPLE)
diff --git a/Firestore/core/src/firebase/firestore/util/string_printf.cc b/Firestore/core/src/firebase/firestore/util/string_printf.cc
new file mode 100644
index 0000000..60cc564
--- /dev/null
+++ b/Firestore/core/src/firebase/firestore/util/string_printf.cc
@@ -0,0 +1,101 @@
+/*
+ * 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/util/string_printf.h"
+
+#include <stdio.h>
+
+namespace firebase {
+namespace firestore {
+namespace util {
+
+void StringAppendV(std::string* dst, const char* format, va_list ap) {
+ // First try with a small fixed size buffer
+ static const int kSpaceLength = 1024;
+ char space[kSpaceLength];
+
+ // It's possible for methods that use a va_list to invalidate
+ // the data in it upon use. The fix is to make a copy
+ // of the structure before using it and use that copy instead.
+ va_list backup_ap;
+ va_copy(backup_ap, ap);
+ int result = vsnprintf(space, kSpaceLength, format, backup_ap);
+ va_end(backup_ap);
+
+ if (result < kSpaceLength) {
+ if (result >= 0) {
+ // Normal case -- everything fit.
+ dst->append(space, result);
+ return;
+ }
+
+#ifdef _MSC_VER
+ // Error or MSVC running out of space. MSVC 8.0 and higher
+ // can be asked about space needed with the special idiom below:
+ va_copy(backup_ap, ap);
+ result = vsnprintf(nullptr, 0, format, backup_ap);
+ va_end(backup_ap);
+#endif
+
+ if (result < 0) {
+ // Just an error.
+ return;
+ }
+ }
+
+ // Increase the buffer size to the size requested by vsnprintf,
+ // plus one for the closing \0.
+ size_t initial_size = dst->size();
+ size_t target_size = initial_size + result;
+
+ dst->resize(target_size + 1);
+ char* buf = &(*dst)[initial_size];
+ int buf_remain = result + 1;
+
+ // Restore the va_list before we use it again
+ va_copy(backup_ap, ap);
+ result = vsnprintf(buf, buf_remain, format, backup_ap);
+ va_end(backup_ap);
+
+ if (result >= 0 && result < buf_remain) {
+ // It fit and vsnprintf copied in directly. Resize down one to
+ // remove the trailing \0.
+ dst->resize(target_size);
+ } else {
+ // Didn't fit. Leave the original string unchanged.
+ dst->resize(initial_size);
+ }
+}
+
+std::string StringPrintf(const char* format, ...) {
+ va_list ap;
+ va_start(ap, format);
+ std::string result;
+ StringAppendV(&result, format, ap);
+ va_end(ap);
+ return result;
+}
+
+void StringAppendF(std::string* dst, const char* format, ...) {
+ va_list ap;
+ va_start(ap, format);
+ StringAppendV(dst, format, ap);
+ va_end(ap);
+}
+
+} // namespace util
+} // namespace firestore
+} // namespace firebase
diff --git a/Firestore/core/src/firebase/firestore/util/string_printf.h b/Firestore/core/src/firebase/firestore/util/string_printf.h
new file mode 100644
index 0000000..9e2b9c0
--- /dev/null
+++ b/Firestore/core/src/firebase/firestore/util/string_printf.h
@@ -0,0 +1,48 @@
+/*
+ * 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_UTIL_STRING_PRINTF_H_
+#define FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_UTIL_STRING_PRINTF_H_
+
+#include <stdarg.h>
+
+#include <string>
+
+#include <absl/base/attributes.h>
+
+namespace firebase {
+namespace firestore {
+namespace util {
+
+/** Return a C++ string. */
+std::string StringPrintf(const char* format, ...)
+ ABSL_PRINTF_ATTRIBUTE(1, 2);
+
+/** Append result to a supplied string. */
+void StringAppendF(std::string* dst, const char* format, ...)
+ ABSL_PRINTF_ATTRIBUTE(2, 3);
+
+/**
+ * Lower-level routine that takes a va_list and appends to a specified
+ * string. All other routines are just convenience wrappers around it.
+ */
+void StringAppendV(std::string* dst, const char* format, va_list ap);
+
+} // namespace util
+} // namespace firestore
+} // namespace firebase
+
+#endif // FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_UTIL_STRING_FORMAT_H_
diff --git a/Firestore/core/test/firebase/firestore/util/CMakeLists.txt b/Firestore/core/test/firebase/firestore/util/CMakeLists.txt
index 42c4dcc..5e10715 100644
--- a/Firestore/core/test/firebase/firestore/util/CMakeLists.txt
+++ b/Firestore/core/test/firebase/firestore/util/CMakeLists.txt
@@ -16,6 +16,7 @@ cc_test(
firebase_firestore_util_test
autoid_test.cc
secure_random_test.cc
+ string_printf_test.cc
)
target_link_libraries(
firebase_firestore_util_test
@@ -24,20 +25,20 @@ target_link_libraries(
if(APPLE)
cc_test(
- firebase_firestore_util_log_apple_test
+ firebase_firestore_util_apple_test
log_test.cc
)
target_link_libraries(
- firebase_firestore_util_log_apple_test
- firebase_firestore_util_log_apple
+ firebase_firestore_util_apple_test
+ firebase_firestore_util_apple
)
endif(APPLE)
cc_test(
- firebase_firestore_util_log_stdio_test
+ firebase_firestore_util_stdio_test
log_test.cc
)
target_link_libraries(
- firebase_firestore_util_log_stdio_test
- firebase_firestore_util_log_stdio
+ firebase_firestore_util_stdio_test
+ firebase_firestore_util_stdio
)
diff --git a/Firestore/core/test/firebase/firestore/util/string_printf_test.cc b/Firestore/core/test/firebase/firestore/util/string_printf_test.cc
new file mode 100644
index 0000000..76f7cde
--- /dev/null
+++ b/Firestore/core/test/firebase/firestore/util/string_printf_test.cc
@@ -0,0 +1,78 @@
+/*
+ * Copyright 2017 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/util/string_printf.h"
+
+#include <gtest/gtest.h>
+
+namespace firebase {
+namespace firestore {
+namespace util {
+
+TEST(StringPrintf, Empty) {
+ EXPECT_EQ("", StringPrintf(""));
+ EXPECT_EQ("", StringPrintf("%s", std::string().c_str()));
+ EXPECT_EQ("", StringPrintf("%s", ""));
+}
+
+TEST(StringAppendFTest, Empty) {
+ std::string value("Hello");
+ const char* empty = "";
+ StringAppendF(&value, "%s", empty);
+ EXPECT_EQ("Hello", value);
+}
+
+TEST(StringAppendFTest, EmptyString) {
+ std::string value("Hello");
+ StringAppendF(&value, "%s", "");
+ EXPECT_EQ("Hello", value);
+}
+
+TEST(StringAppendFTest, String) {
+ std::string value("Hello");
+ StringAppendF(&value, " %s", "World");
+ EXPECT_EQ("Hello World", value);
+}
+
+TEST(StringAppendFTest, Int) {
+ std::string value("Hello");
+ StringAppendF(&value, " %d", 123);
+ EXPECT_EQ("Hello 123", value);
+}
+
+TEST(StringPrintf, DontOverwriteErrno) {
+ // Check that errno isn't overwritten unless we're printing
+ // something significantly larger than what people are normally
+ // printing in their badly written PLOG() statements.
+ errno = ECHILD;
+ std::string value = StringPrintf("Hello, %s!", "World");
+ EXPECT_EQ(ECHILD, errno);
+}
+
+TEST(StringPrintf, LargeBuf) {
+ // Check that the large buffer is handled correctly.
+ int n = 2048;
+ char* buf = new char[n + 1];
+ memset(buf, ' ', n);
+ buf[n] = 0;
+ std::string value = StringPrintf("%s", buf);
+ EXPECT_EQ(buf, value);
+ delete[] buf;
+}
+
+} // namespace util
+} // namespace firestore
+} // namespace firebase
diff --git a/Firestore/third_party/abseil-cpp/CMakeLists.txt b/Firestore/third_party/abseil-cpp/CMakeLists.txt
index 1c53a72..b25a006 100644
--- a/Firestore/third_party/abseil-cpp/CMakeLists.txt
+++ b/Firestore/third_party/abseil-cpp/CMakeLists.txt
@@ -53,7 +53,13 @@ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_WARNING_VLA} ${CMAKE_CXX_FLAGS} ")
## pthread
find_package(Threads REQUIRED)
-find_package(GTest REQUIRED)
+# commented: used only for standalone test
+#add_subdirectory(cctz)
+#add_subdirectory(googletest)
+
+## check targets
+check_target(GTest::GTest)
+check_target(GTest::Main)
# -fexceptions
set(ABSL_EXCEPTIONS_FLAG "${CMAKE_CXX_EXCEPTIONS}")
diff --git a/cmake/external/abseil-cpp.cmake b/cmake/external/abseil-cpp.cmake
deleted file mode 100644
index d29b7d5..0000000
--- a/cmake/external/abseil-cpp.cmake
+++ /dev/null
@@ -1,35 +0,0 @@
-# Copyright 2017 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(ExternalProject)
-
-set(source_dir ${PROJECT_SOURCE_DIR}/Firestore/third_party/abseil-cpp)
-set(binary_dir ${PROJECT_BINARY_DIR}/Firestore/third_party/abseil-cpp)
-
-ExternalProject_Add(
- abseil-cpp
- DEPENDS googletest
-
- PREFIX "${binary_dir}"
- SOURCE_DIR "${source_dir}"
- BINARY_DIR "${binary_dir}"
-
- INSTALL_DIR "${FIREBASE_INSTALL_DIR}"
- INSTALL_COMMAND ""
- TEST_BEFORE_INSTALL ON
-
- CMAKE_ARGS
- -DCMAKE_BUILD_TYPE:STRING=${CMAKE_BUILD_TYPE}
- -DCMAKE_INSTALL_PREFIX:PATH=<INSTALL_DIR>
-)
diff --git a/cmake/external/firestore.cmake b/cmake/external/firestore.cmake
index 61f79f3..1abb629 100644
--- a/cmake/external/firestore.cmake
+++ b/cmake/external/firestore.cmake
@@ -19,7 +19,7 @@ set(binary_dir ${PROJECT_BINARY_DIR}/Firestore)
ExternalProject_Add(
Firestore
- DEPENDS abseil-cpp FirebaseCore googletest leveldb
+ DEPENDS FirebaseCore googletest leveldb
# Lay the binary directory out as if this were a subproject. This makes it
# possible to build and test in it directly.