diff options
| author | Even Rouault <even.rouault@spatialys.com> | 2018-12-19 12:25:33 +0100 |
|---|---|---|
| committer | Even Rouault <even.rouault@spatialys.com> | 2018-12-26 10:08:54 +0100 |
| commit | e6de172371ea203f6393d745641d66c82b5b13e2 (patch) | |
| tree | 791fa07f431a2d1db6f6e813ab984db982587278 /src/iso19111/internal.cpp | |
| parent | ce8075076b4e4ffebd32afaba419e1d9ab27cd03 (diff) | |
| download | PROJ-e6de172371ea203f6393d745641d66c82b5b13e2.tar.gz PROJ-e6de172371ea203f6393d745641d66c82b5b13e2.zip | |
cpp conversion: move source files in apps/ iso19111/ conversions/ projections/ transformations/ tests/ subdirectories
Diffstat (limited to 'src/iso19111/internal.cpp')
| -rw-r--r-- | src/iso19111/internal.cpp | 374 |
1 files changed, 374 insertions, 0 deletions
diff --git a/src/iso19111/internal.cpp b/src/iso19111/internal.cpp new file mode 100644 index 00000000..c43605d1 --- /dev/null +++ b/src/iso19111/internal.cpp @@ -0,0 +1,374 @@ +/****************************************************************************** + * + * Project: PROJ + * Purpose: ISO19111:2018 implementation + * Author: Even Rouault <even dot rouault at spatialys dot com> + * + ****************************************************************************** + * Copyright (c) 2018, Even Rouault <even dot rouault at spatialys dot com> + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + ****************************************************************************/ + +#ifndef FROM_PROJ_CPP +#define FROM_PROJ_CPP +#endif + +#include "proj/internal/internal.hpp" + +#include <cstdint> +#include <cstring> +#ifdef _MSC_VER +#include <string.h> +#else +#include <strings.h> +#endif +#include <exception> +#include <iomanip> // std::setprecision +#include <locale> +#include <sstream> // std::istringstream and std::ostringstream +#include <string> + +#include "sqlite3.h" + +NS_PROJ_START + +namespace internal { + +// --------------------------------------------------------------------------- + +/** + * Replace all occurrences of before with after. + */ +std::string replaceAll(const std::string &str, const std::string &before, + const std::string &after) { + std::string ret(str); + const size_t nBeforeSize = before.size(); + const size_t nAfterSize = after.size(); + if (nBeforeSize) { + size_t nStartPos = 0; + while ((nStartPos = ret.find(before, nStartPos)) != std::string::npos) { + ret.replace(nStartPos, nBeforeSize, after); + nStartPos += nAfterSize; + } + } + return ret; +} + +// --------------------------------------------------------------------------- + +inline static bool EQUALN(const char *a, const char *b, size_t size) { +#ifdef _MSC_VER + return _strnicmp(a, b, size) == 0; +#else + return strncasecmp(a, b, size) == 0; +#endif +} + +/** + * Case-insensitive equality test + */ +bool ci_equal(const std::string &a, const std::string &b) noexcept { + const auto size = a.size(); + if (size != b.size()) { + return false; + } + return EQUALN(a.c_str(), b.c_str(), size); +} + +bool ci_equal(const std::string &a, const char *b) noexcept { + const auto size = a.size(); + if (size != strlen(b)) { + return false; + } + return EQUALN(a.c_str(), b, size); +} + +bool ci_equal(const char *a, const char *b) noexcept { + const auto size = strlen(a); + if (size != strlen(b)) { + return false; + } + return EQUALN(a, b, size); +} + +// --------------------------------------------------------------------------- + +bool ci_less(const std::string &a, const std::string &b) noexcept { +#ifdef _MSC_VER + return _stricmp(a.c_str(), b.c_str()) < 0; +#else + return strcasecmp(a.c_str(), b.c_str()) < 0; +#endif +} + +// --------------------------------------------------------------------------- + +/** + * Convert to lower case. + */ + +std::string tolower(const std::string &str) + +{ + std::string ret(str); + for (size_t i = 0; i < ret.size(); i++) + ret[i] = static_cast<char>(::tolower(ret[i])); + return ret; +} + +// --------------------------------------------------------------------------- + +/** + * Convert to upper case. + */ + +std::string toupper(const std::string &str) + +{ + std::string ret(str); + for (size_t i = 0; i < ret.size(); i++) + ret[i] = static_cast<char>(::toupper(ret[i])); + return ret; +} + +// --------------------------------------------------------------------------- + +/** Strip leading and trailing double quote characters */ +std::string stripQuotes(const std::string &str) { + if (str.size() >= 2 && str[0] == '"' && str.back() == '"') { + return str.substr(1, str.size() - 2); + } + return str; +} + +// --------------------------------------------------------------------------- + +size_t ci_find(const std::string &str, const char *needle) noexcept { + const size_t needleSize = strlen(needle); + for (size_t i = 0; i + needleSize <= str.size(); i++) { + if (EQUALN(str.c_str() + i, needle, needleSize)) { + return i; + } + } + return std::string::npos; +} + +// --------------------------------------------------------------------------- + +size_t ci_find(const std::string &str, const std::string &needle, + size_t startPos) noexcept { + const size_t needleSize = needle.size(); + for (size_t i = startPos; i + needleSize <= str.size(); i++) { + if (EQUALN(str.c_str() + i, needle.c_str(), needleSize)) { + return i; + } + } + return std::string::npos; +} + +// --------------------------------------------------------------------------- + +/* +bool starts_with(const std::string &str, const std::string &prefix) noexcept { + if (str.size() < prefix.size()) { + return false; + } + return std::memcmp(str.c_str(), prefix.c_str(), prefix.size()) == 0; +} +*/ + +// --------------------------------------------------------------------------- + +/* +bool starts_with(const std::string &str, const char *prefix) noexcept { + const size_t prefixSize = std::strlen(prefix); + if (str.size() < prefixSize) { + return false; + } + return std::memcmp(str.c_str(), prefix, prefixSize) == 0; +} +*/ + +// --------------------------------------------------------------------------- + +bool ci_starts_with(const char *str, const char *prefix) noexcept { + const auto str_size = strlen(str); + const auto prefix_size = strlen(prefix); + if (str_size < prefix_size) { + return false; + } + return EQUALN(str, prefix, prefix_size); +} + +// --------------------------------------------------------------------------- + +bool ci_starts_with(const std::string &str, + const std::string &prefix) noexcept { + if (str.size() < prefix.size()) { + return false; + } + return EQUALN(str.c_str(), prefix.c_str(), prefix.size()); +} + +// --------------------------------------------------------------------------- + +bool ends_with(const std::string &str, const std::string &suffix) noexcept { + if (str.size() < suffix.size()) { + return false; + } + return std::memcmp(str.c_str() + str.size() - suffix.size(), suffix.c_str(), + suffix.size()) == 0; +} + +// --------------------------------------------------------------------------- + +double c_locale_stod(const std::string &s) { + + const auto s_size = s.size(); + // Fast path + if (s_size > 0 && s_size < 15) { + std::int64_t acc = 0; + std::int64_t div = 1; + bool afterDot = false; + size_t i = 0; + if (s[0] == '-') { + ++i; + div = -1; + } else if (s[0] == '+') { + ++i; + } + for (; i < s_size; ++i) { + const auto ch = s[i]; + if (ch >= '0' && ch <= '9') { + acc = acc * 10 + ch - '0'; + if (afterDot) { + div *= 10; + } + } else if (ch == '.') { + afterDot = true; + } else { + div = 0; + } + } + if (div) { + return static_cast<double>(acc) / div; + } + } + + std::istringstream iss(s); + iss.imbue(std::locale::classic()); + double d; + iss >> d; + if (!iss.eof() || iss.fail()) { + throw std::invalid_argument("non double value"); + } + return d; +} + +// --------------------------------------------------------------------------- + +std::vector<std::string> split(const std::string &str, char separator) { + std::vector<std::string> res; + size_t lastPos = 0; + size_t newPos = 0; + while ((newPos = str.find(separator, lastPos)) != std::string::npos) { + res.push_back(str.substr(lastPos, newPos - lastPos)); + lastPos = newPos + 1; + } + res.push_back(str.substr(lastPos)); + return res; +} + +// --------------------------------------------------------------------------- + +#ifdef _WIN32 + +// For some reason, sqlite3_snprintf() in the sqlite3 builds used on AppVeyor +// doesn't round identically to the Unix builds, and thus breaks a number of +// unit test. So to avoid this, use the stdlib formatting + +std::string toString(int val) { + std::ostringstream buffer; + buffer.imbue(std::locale::classic()); + buffer << val; + return buffer.str(); +} + +std::string toString(double val, int precision) { + std::ostringstream buffer; + buffer.imbue(std::locale::classic()); + buffer << std::setprecision(precision); + buffer << val; + auto str = buffer.str(); + if (precision == 15 && str.find("9999999999") != std::string::npos) { + buffer.str(""); + buffer.clear(); + buffer << std::setprecision(14); + buffer << val; + return buffer.str(); + } + return str; +} + +#else + +std::string toString(int val) { + // use sqlite3 API that is slighly faster than std::ostringstream + // with forcing the C locale. sqlite3_snprintf() emulates a C locale. + constexpr int BUF_SIZE = 16; + char szBuffer[BUF_SIZE]; + sqlite3_snprintf(BUF_SIZE, szBuffer, "%d", val); + return szBuffer; +} + +std::string toString(double val, int precision) { + // use sqlite3 API that is slighly faster than std::ostringstream + // with forcing the C locale. sqlite3_snprintf() emulates a C locale. + constexpr int BUF_SIZE = 32; + char szBuffer[BUF_SIZE]; + sqlite3_snprintf(BUF_SIZE, szBuffer, "%.*g", precision, val); + if (precision == 15 && strstr(szBuffer, "9999999999")) { + sqlite3_snprintf(BUF_SIZE, szBuffer, "%.14g", val); + } + return szBuffer; +} + +#endif + +// --------------------------------------------------------------------------- + +std::string concat(const char *a, const std::string &b) { + std::string res(a); + res += b; + return res; +} + +std::string concat(const char *a, const std::string &b, const char *c) { + std::string res(a); + res += b; + res += c; + return res; +} + +// --------------------------------------------------------------------------- + +} // namespace internal + +NS_PROJ_END |
