diff --git a/include/mapnik/value.hpp b/include/mapnik/value.hpp index c6a95d3e0..649f3bff8 100644 --- a/include/mapnik/value.hpp +++ b/include/mapnik/value.hpp @@ -24,805 +24,25 @@ #define MAPNIK_VALUE_HPP // mapnik +#include #include #include -#include #include -// stl -#include -#include -#include - -#include -#include -#include -#include - -// icu -#include -#include namespace mapnik { using value_base = util::variant; -inline void to_utf8(mapnik::value_unicode_string const& input, std::string & target) -{ - target.clear(); // mimic previous target.assign(...) semantics - input.toUTF8String(target); // this appends to target -} - -namespace detail { - -namespace { -template -struct both_arithmetic : std::integral_constant::value && - std::is_arithmetic::value > {}; - -struct equals -{ - static bool apply(value_null, value_unicode_string const& rhs) - { - return false; - } - - template - static auto apply(T const& lhs, T const& rhs) - -> decltype(lhs == rhs) - { - return lhs == rhs; - } -}; - -struct not_equal -{ - // back compatibility shim to equate empty string with null for != test - // https://github.com/mapnik/mapnik/issues/1859 - // TODO - consider removing entire specialization at Mapnik 3.1.x - static bool apply(value_null, value_unicode_string const& rhs) - { - if (rhs.isEmpty()) return false; - return true; - } - - template - static auto apply(T const& lhs, T const& rhs) - ->decltype(lhs != rhs) - { - return lhs != rhs; - } -}; - -struct greater_than -{ - static bool apply(value_null, value_unicode_string const& rhs) - { - return false; - } - - template - static auto apply(T const& lhs, T const& rhs) - ->decltype(lhs > rhs) - { - return lhs > rhs; - } -}; - -struct greater_or_equal -{ - static bool apply(value_null, value_unicode_string const& rhs) - { - return false; - } - - template - static auto apply(T const& lhs, T const& rhs) - ->decltype(lhs >= rhs) - { - return lhs >= rhs; - } -}; - -struct less_than -{ - static bool apply(value_null, value_unicode_string const& rhs) - { - return false; - } - - template - static auto apply(T const& lhs, T const& rhs) - ->decltype(lhs < rhs) - { - return lhs < rhs; - } -}; - -struct less_or_equal -{ - static bool apply(value_null, value_unicode_string const& rhs) - { - return false; - } - - template - static auto apply(T const& lhs, T const& rhs) - ->decltype(lhs <= rhs) - { - return lhs <= rhs; - } -}; - -} - -template -struct comparison -{ - // special case for unicode_strings (fixes MSVC C4800) - bool operator() (value_unicode_string const& lhs, - value_unicode_string const& rhs) const - { - return Op::apply(lhs, rhs) ? true : false; - } - - ////////////////////////////////////////////////////////////////////////// - // special case for unicode_string and value_null - ////////////////////////////////////////////////////////////////////////// - - bool operator() (value_null const& lhs, value_unicode_string const& rhs) const - { - return Op::apply(lhs, rhs); - } - ////////////////////////////////////////////////////////////////////////// - - - // same types - template - bool operator() (T lhs, T rhs) const - { - return Op::apply(lhs, rhs); - } - - // both types are arithmetic - promote to the common type - template ::value, int>::type = 0> - bool operator() (T const& lhs, U const& rhs) const - { - using common_type = typename std::common_type::type; - return Op::apply(static_cast(lhs),static_cast(rhs)); - } - - // - template ::value, int>::type = 0> - bool operator() (T const& lhs, U const& rhs) const - { - return default_result; - } -}; - -template -struct add -{ - using value_type = V; - value_type operator() (value_unicode_string const& lhs , - value_unicode_string const& rhs ) const - { - return lhs + rhs; - } - - value_type operator() (value_null const& lhs , - value_null const& rhs) const - { - return lhs; - } - - value_type operator() (value_unicode_string const& lhs, value_null) const - { - return lhs; - } - - value_type operator() (value_null, value_unicode_string const& rhs) const - { - return rhs; - } - - template - value_type operator() (L const& lhs, value_null const&) const - { - return lhs; - } - - template - value_type operator() (value_null const&, R const& rhs) const - { - return rhs; - } - - template - value_type operator() (L const& lhs , value_unicode_string const& rhs) const - { - std::string val; - if (util::to_string(val,lhs)) - return value_unicode_string(val.c_str()) + rhs; - return rhs; - } - - template - value_type operator() (value_unicode_string const& lhs, R const& rhs) const - { - std::string val; - if (util::to_string(val,rhs)) - return lhs + value_unicode_string(val.c_str()); - return lhs; - } - - template - value_type operator() (T1 const& lhs, T2 const& rhs) const - { - return typename std::common_type::type{ lhs + rhs }; - } - - value_type operator() (value_bool lhs, value_bool rhs) const - { - return value_integer(lhs + rhs); - } -}; - -template -struct sub -{ - using value_type = V; - - value_type operator() (value_null const& lhs , - value_null const& rhs) const - { - return lhs; - } - - value_type operator() (value_null, value_unicode_string const& rhs) const - { - return rhs; - } - value_type operator() (value_unicode_string const& lhs, value_null) const - { - return lhs; - } - - template - value_type operator() (value_unicode_string const& lhs, R const&) const - { - return lhs; - } - - template - value_type operator() (L const&, value_unicode_string const& rhs) const - { - return rhs; - } - - template - value_type operator() (L const& lhs, value_null const&) const - { - return lhs; - } - - template - value_type operator() (value_null const&, R const& rhs) const - { - return rhs; - } - - template - value_type operator() (T lhs, T rhs) const - { - return lhs - rhs ; - } - - value_type operator() (value_unicode_string const&, - value_unicode_string const&) const - { - return value_type(); - } - - template - value_type operator() (T1 const& lhs, T2 const& rhs) const - { - return typename std::common_type::type{ lhs - rhs }; - } - - - value_type operator() (value_bool lhs, value_bool rhs) const - { - return value_integer(lhs - rhs); - } -}; - -template -struct mult -{ - using value_type = V; - - value_type operator() (value_null const& lhs , - value_null const& rhs) const - { - return lhs; - } - - value_type operator() (value_unicode_string const& lhs, value_null) const - { - return lhs; - } - - value_type operator() (value_null, value_unicode_string const& rhs) const - { - return rhs; - } - - template - value_type operator() (L const& lhs, value_null const&) const - { - return lhs; - } - - template - value_type operator() (value_null const&, R const& rhs) const - { - return rhs; - } - - template - value_type operator() (value_unicode_string const& lhs, R const&) const - { - return lhs; - } - - template - value_type operator() (L const&, value_unicode_string const& rhs) const - { - return rhs; - } - - template - value_type operator() (T lhs, T rhs) const - { - return lhs * rhs; - } - - value_type operator() (value_unicode_string const&, - value_unicode_string const&) const - { - return value_type(); - } - - template - value_type operator() (T1 const& lhs, T2 const& rhs) const - { - return typename std::common_type::type{ lhs * rhs }; - } - - value_type operator() (value_bool lhs, value_bool rhs) const - { - return value_integer(lhs * rhs); - } -}; - -template -struct div -{ - using value_type = V; - - value_type operator() (value_null const& lhs , - value_null const& rhs) const - { - return lhs; - } - - value_type operator() (value_unicode_string const& lhs, value_null) const - { - return lhs; - } - - value_type operator() (value_null, value_unicode_string const& rhs) const - { - return rhs; - } - - template - value_type operator() (L const& lhs, value_null const&) const - { - return lhs; - } - - template - value_type operator() (value_null const&, R const& rhs) const - { - return rhs; - } - - template - value_type operator() (T lhs, T rhs) const - { - if (rhs == 0) return value_type(); - return lhs / rhs; - } - - value_type operator() (value_bool lhs, value_bool rhs) const - { - if (rhs == 0) return lhs; - return value_integer(lhs) / value_integer(rhs); - } - - value_type operator() (value_unicode_string const&, - value_unicode_string const&) const - { - return value_type(); - } - - template - value_type operator() (value_unicode_string const& lhs, R const&) const - { - return lhs; - } - - template - value_type operator() (L const&, value_unicode_string const& rhs) const - { - return rhs; - } - - template - value_type operator() (T1 const& lhs, T2 const& rhs) const - { - if (rhs == 0) return value_type(); - using common_type = typename std::common_type::type; - return common_type(lhs)/common_type(rhs); - } -}; - -template -struct mod -{ - using value_type = V; - - template - value_type operator() (T1 const& lhs, T2 const&) const - { - return lhs; - } - - template - value_type operator() (T lhs, T rhs) const - { - return lhs % rhs; - } - - value_type operator() (value_unicode_string const&, - value_unicode_string const&) const - { - return value_type(); - } - - value_type operator() (value_bool, - value_bool) const - { - return false; - } - - value_type operator() (value_double lhs, value_integer rhs) const - { - return std::fmod(lhs, static_cast(rhs)); - } - - value_type operator() (value_integer lhs, value_double rhs) const - { - return std::fmod(static_cast(lhs), rhs); - } - - value_type operator() (value_double lhs, value_double rhs) const - { - return std::fmod(lhs, rhs); - } -}; - -template -struct negate -{ - using value_type = V; - - template - value_type operator() (T val) const - { - return -val; - } - - value_type operator() (value_null val) const - { - return val; - } - - value_type operator() (value_bool val) const - { - return val ? value_integer(-1) : value_integer(0); - } - - value_type operator() (value_unicode_string const&) const - { - return value_type(); - } -}; - -// converters -template -struct convert {}; - -template <> -struct convert -{ - value_bool operator() (value_bool val) const - { - return val; - } - - value_bool operator() (value_unicode_string const& ustr) const - { - return !ustr.isEmpty(); - } - - value_bool operator() (value_null const&) const - { - return false; - } - - template - value_bool operator() (T val) const - { - return val > 0 ? true : false; - } -}; - -template <> -struct convert -{ - value_double operator() (value_double val) const - { - return val; - } - - value_double operator() (value_integer val) const - { - return static_cast(val); - } - - value_double operator() (value_bool val) const - { - return static_cast(val); - } - - value_double operator() (std::string const& val) const - { - value_double result; - if (util::string2double(val,result)) - return result; - return 0; - } - - value_double operator() (value_unicode_string const& val) const - { - std::string utf8; - val.toUTF8String(utf8); - return operator()(utf8); - } - - value_double operator() (value_null const&) const - { - return 0.0; - } -}; - -template <> -struct convert -{ - value_integer operator() (value_integer val) const - { - return val; - } - - value_integer operator() (value_double val) const - { - return static_cast(rint(val)); - } - - value_integer operator() (value_bool val) const - { - return static_cast(val); - } - - value_integer operator() (std::string const& val) const - { - value_integer result; - if (util::string2int(val,result)) - return result; - return value_integer(0); - } - - value_integer operator() (value_unicode_string const& val) const - { - std::string utf8; - val.toUTF8String(utf8); - return operator()(utf8); - } - - value_integer operator() (value_null const&) const - { - return value_integer(0); - } -}; - -template <> -struct convert -{ - template - std::string operator() (T val) const - { - std::string str; - util::to_string(str, val); - return str; - } - - // specializations - std::string operator() (value_unicode_string const& val) const - { - std::string utf8; - val.toUTF8String(utf8); - return utf8; - } - - std::string operator() (value_double val) const - { - std::string str; - util::to_string(str, val); // TODO set precision(16) - return str; - } - - std::string operator() (value_bool val) const - { - return val ? "true": "false"; - } - - std::string operator() (value_null const&) const - { - return std::string(); - } -}; - -struct to_unicode_impl -{ - - template - value_unicode_string operator() (T val) const - { - std::string str; - util::to_string(str,val); - return value_unicode_string(str.c_str()); - } - - // specializations - value_unicode_string const& operator() (value_unicode_string const& val) const - { - return val; - } - - value_unicode_string operator() (value_double val) const - { - std::string str; - util::to_string(str,val); - return value_unicode_string(str.c_str()); - } - - value_unicode_string operator() (value_bool val) const - { - return value_unicode_string(val ? "true" : "false"); - } - - value_unicode_string operator() (value_null const&) const - { - return value_unicode_string(); - } -}; - -struct to_expression_string_impl -{ - struct EscapingByteSink : U_NAMESPACE_QUALIFIER ByteSink - { - std::string dest_; - char quote_; - - explicit EscapingByteSink(char quote) - : quote_(quote) - {} - - virtual void Append(const char* data, int32_t n) - { - // reserve enough room to hold the appended chunk and quotes; - // if another chunk follows, or any character needs escaping, - // the string will grow naturally - if (dest_.empty()) - { - dest_.reserve(2 + static_cast(n)); - dest_.append(1, quote_); - } - else - { - dest_.reserve(dest_.size() + n + 1); - } - - for (auto end = data + n; data < end; ++data) - { - if (*data == '\\' || *data == quote_) - dest_.append(1, '\\'); - dest_.append(1, *data); - } - } - - virtual void Flush() - { - if (dest_.empty()) - dest_.append(2, quote_); - else - dest_.append(1, quote_); - } - }; - - explicit to_expression_string_impl(char quote = '\'') - : quote_(quote) {} - - std::string operator() (value_unicode_string const& val) const - { - EscapingByteSink sink(quote_); - val.toUTF8(sink); - return sink.dest_; - } - - std::string operator() (value_integer val) const - { - std::string output; - util::to_string(output,val); - return output; - } - - std::string operator() (value_double val) const - { - std::string output; - util::to_string(output,val); // TODO precision(16) - return output; - } - - std::string operator() (value_bool val) const - { - return val ? "true" : "false"; - } - - std::string operator() (value_null const&) const - { - return "null"; - } - - const char quote_; -}; - - -} // namespace detail - namespace value_adl_barrier { -class value : public value_base +class MAPNIK_DECL value : public value_base { - friend const value operator+(value const&,value const&); - friend const value operator-(value const&,value const&); - friend const value operator*(value const&,value const&); - friend const value operator/(value const&,value const&); - friend const value operator%(value const&,value const&); + friend value operator+(value const&,value const&); + friend value operator-(value const&,value const&); + friend value operator*(value const&,value const&); + friend value operator/(value const&,value const&); + friend value operator%(value const&,value const&); public: value() = default; @@ -856,104 +76,32 @@ public: return *this; } - bool operator==(value const& other) const - { - return util::apply_visitor(detail::comparison(), *this, other); - } + bool operator==(value const& other) const; + bool operator!=(value const& other) const; + bool operator>(value const& other) const; + bool operator>=(value const& other) const; + bool operator<(value const& other) const; + bool operator<=(value const& other) const; - bool operator!=(value const& other) const - { - return util::apply_visitor(detail::comparison(), *this, other); - } - - bool operator>(value const& other) const - { - return util::apply_visitor(detail::comparison(), *this, other); - } - - bool operator>=(value const& other) const - { - return util::apply_visitor(detail::comparison(), *this, other); - } - - bool operator<(value const& other) const - { - return util::apply_visitor(detail::comparison(), *this, other); - } - - bool operator<=(value const& other) const - { - return util::apply_visitor(detail::comparison(), *this, other); - } - - value operator- () const - { - return util::apply_visitor(detail::negate(), *this); - } + value operator-() const; bool is_null() const; - template - T convert() const - { - return util::apply_visitor(detail::convert(),*this); - } + template T convert() const; - value_bool to_bool() const - { - return util::apply_visitor(detail::convert(),*this); - } - - std::string to_expression_string(char quote = '\'') const - { - return util::apply_visitor(detail::to_expression_string_impl(quote),*this); - } - - std::string to_string() const - { - return util::apply_visitor(detail::convert(),*this); - } - - value_unicode_string to_unicode() const - { - return util::apply_visitor(detail::to_unicode_impl(),*this); - } - - value_double to_double() const - { - return util::apply_visitor(detail::convert(),*this); - } - - value_integer to_int() const - { - return util::apply_visitor(detail::convert(),*this); - } + value_bool to_bool() const; + std::string to_expression_string(char quote = '\'') const; + std::string to_string() const; + value_unicode_string to_unicode() const; + value_double to_double() const; + value_integer to_int() const; }; -inline const value operator+(value const& p1,value const& p2) -{ - return value(util::apply_visitor(detail::add(),p1, p2)); -} - -inline const value operator-(value const& p1,value const& p2) -{ - return value(util::apply_visitor(detail::sub(),p1, p2)); -} - -inline const value operator*(value const& p1,value const& p2) -{ - return value(util::apply_visitor(detail::mult(),p1, p2)); -} - -inline const value operator/(value const& p1,value const& p2) -{ - return value(util::apply_visitor(detail::div(),p1, p2)); -} - -inline const value operator%(value const& p1,value const& p2) -{ - return value(util::apply_visitor(detail::mod(),p1, p2)); -} +MAPNIK_DECL value operator+(value const& p1,value const& p2); +MAPNIK_DECL value operator-(value const& p1,value const& p2); +MAPNIK_DECL value operator*(value const& p1,value const& p2); +MAPNIK_DECL value operator/(value const& p1,value const& p2); +MAPNIK_DECL value operator%(value const& p1,value const& p2); template inline std::basic_ostream& @@ -972,36 +120,28 @@ inline std::size_t hash_value(value const& val) } // namespace value_adl_barrier -using value_adl_barrier::value; +using value = value_adl_barrier::value; namespace detail { - struct is_null_visitor { - bool operator() (value const& val) const + bool operator()(value const& val) const { return val.is_null(); } - bool operator() (value_null const&) const + bool operator()(value_null const&) const { return true; } template - bool operator() (T const&) const + bool operator()(T const&) const { return false; } }; - } // namespace detail - -inline bool value::is_null() const -{ - return util::apply_visitor(mapnik::detail::is_null_visitor(), *this); -} - } // namespace mapnik // support for std::unordered_xxx diff --git a/src/build.py b/src/build.py index c405eb151..57f373e7b 100644 --- a/src/build.py +++ b/src/build.py @@ -257,6 +257,7 @@ source = Split( renderer_common/render_pattern.cpp renderer_common/render_thunk_extractor.cpp math.cpp + value.cpp """ ) diff --git a/src/value.cpp b/src/value.cpp new file mode 100644 index 000000000..579f9c0c4 --- /dev/null +++ b/src/value.cpp @@ -0,0 +1,927 @@ +/***************************************************************************** + * + * This file is part of Mapnik (c++ mapping toolkit) + * + * Copyright (C) 2016 Artem Pavlenko + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + *****************************************************************************/ + +// mapnik +#include +#include +#include + +// stl +#include +#include +#include + +#include +#include +#include +#include + +// icu +#include +#include + +namespace mapnik { + +namespace detail { + +namespace { +template +struct both_arithmetic : std::integral_constant::value && + std::is_arithmetic::value> {}; + +struct equals +{ + static bool apply(value_null, value_unicode_string const& rhs) + { + return false; + } + + template + static auto apply(T const& lhs, T const& rhs) + -> decltype(lhs == rhs) + { + return lhs == rhs; + } +}; + +struct not_equal +{ + // back compatibility shim to equate empty string with null for != test + // https://github.com/mapnik/mapnik/issues/1859 + // TODO - consider removing entire specialization at Mapnik 3.1.x + static bool apply(value_null, value_unicode_string const& rhs) + { + if (rhs.isEmpty()) return false; + return true; + } + + template + static auto apply(T const& lhs, T const& rhs) + -> decltype(lhs != rhs) + { + return lhs != rhs; + } +}; + +struct greater_than +{ + static bool apply(value_null, value_unicode_string const& rhs) + { + return false; + } + + template + static auto apply(T const& lhs, T const& rhs) + -> decltype(lhs > rhs) + { + return lhs > rhs; + } +}; + +struct greater_or_equal +{ + static bool apply(value_null, value_unicode_string const& rhs) + { + return false; + } + + template + static auto apply(T const& lhs, T const& rhs) + -> decltype(lhs >= rhs) + { + return lhs >= rhs; + } +}; + +struct less_than +{ + static bool apply(value_null, value_unicode_string const& rhs) + { + return false; + } + + template + static auto apply(T const& lhs, T const& rhs) + -> decltype(lhs < rhs) + { + return lhs < rhs; + } +}; + +struct less_or_equal +{ + static bool apply(value_null, value_unicode_string const& rhs) + { + return false; + } + + template + static auto apply(T const& lhs, T const& rhs) + -> decltype(lhs <= rhs) + { + return lhs <= rhs; + } +}; +} + +template +struct comparison +{ + // special case for unicode_strings (fixes MSVC C4800) + bool operator()(value_unicode_string const& lhs, + value_unicode_string const& rhs) const + { + return Op::apply(lhs, rhs) ? true : false; + } + + ////////////////////////////////////////////////////////////////////////// + // special case for unicode_string and value_null + ////////////////////////////////////////////////////////////////////////// + + bool operator()(value_null const& lhs, value_unicode_string const& rhs) const + { + return Op::apply(lhs, rhs); + } + ////////////////////////////////////////////////////////////////////////// + + // same types + template + bool operator()(T lhs, T rhs) const + { + return Op::apply(lhs, rhs); + } + + // both types are arithmetic - promote to the common type + template ::value, int>::type = 0> + bool operator()(T const& lhs, U const& rhs) const + { + using common_type = typename std::common_type::type; + return Op::apply(static_cast(lhs), static_cast(rhs)); + } + + // + template ::value, int>::type = 0> + bool operator()(T const& lhs, U const& rhs) const + { + return default_result; + } +}; + +template +struct add +{ + using value_type = V; + value_type operator()(value_unicode_string const& lhs, + value_unicode_string const& rhs) const + { + return lhs + rhs; + } + + value_type operator()(value_null const& lhs, + value_null const& rhs) const + { + return lhs; + } + + value_type operator()(value_unicode_string const& lhs, value_null) const + { + return lhs; + } + + value_type operator()(value_null, value_unicode_string const& rhs) const + { + return rhs; + } + + template + value_type operator()(L const& lhs, value_null const&) const + { + return lhs; + } + + template + value_type operator()(value_null const&, R const& rhs) const + { + return rhs; + } + + template + value_type operator()(L const& lhs, value_unicode_string const& rhs) const + { + std::string val; + if (util::to_string(val, lhs)) + return value_unicode_string(val.c_str()) + rhs; + return rhs; + } + + template + value_type operator()(value_unicode_string const& lhs, R const& rhs) const + { + std::string val; + if (util::to_string(val, rhs)) + return lhs + value_unicode_string(val.c_str()); + return lhs; + } + + template + value_type operator()(T1 const& lhs, T2 const& rhs) const + { + return typename std::common_type::type{lhs + rhs}; + } + + value_type operator()(value_bool lhs, value_bool rhs) const + { + return value_integer(lhs + rhs); + } +}; + +template +struct sub +{ + using value_type = V; + + value_type operator()(value_null const& lhs, + value_null const& rhs) const + { + return lhs; + } + + value_type operator()(value_null, value_unicode_string const& rhs) const + { + return rhs; + } + value_type operator()(value_unicode_string const& lhs, value_null) const + { + return lhs; + } + + template + value_type operator()(value_unicode_string const& lhs, R const&) const + { + return lhs; + } + + template + value_type operator()(L const&, value_unicode_string const& rhs) const + { + return rhs; + } + + template + value_type operator()(L const& lhs, value_null const&) const + { + return lhs; + } + + template + value_type operator()(value_null const&, R const& rhs) const + { + return rhs; + } + + template + value_type operator()(T lhs, T rhs) const + { + return lhs - rhs; + } + + value_type operator()(value_unicode_string const&, + value_unicode_string const&) const + { + return value_type(); + } + + template + value_type operator()(T1 const& lhs, T2 const& rhs) const + { + return typename std::common_type::type{lhs - rhs}; + } + + value_type operator()(value_bool lhs, value_bool rhs) const + { + return value_integer(lhs - rhs); + } +}; + +template +struct mult +{ + using value_type = V; + + value_type operator()(value_null const& lhs, + value_null const& rhs) const + { + return lhs; + } + + value_type operator()(value_unicode_string const& lhs, value_null) const + { + return lhs; + } + + value_type operator()(value_null, value_unicode_string const& rhs) const + { + return rhs; + } + + template + value_type operator()(L const& lhs, value_null const&) const + { + return lhs; + } + + template + value_type operator()(value_null const&, R const& rhs) const + { + return rhs; + } + + template + value_type operator()(value_unicode_string const& lhs, R const&) const + { + return lhs; + } + + template + value_type operator()(L const&, value_unicode_string const& rhs) const + { + return rhs; + } + + template + value_type operator()(T lhs, T rhs) const + { + return lhs * rhs; + } + + value_type operator()(value_unicode_string const&, + value_unicode_string const&) const + { + return value_type(); + } + + template + value_type operator()(T1 const& lhs, T2 const& rhs) const + { + return typename std::common_type::type{lhs * rhs}; + } + + value_type operator()(value_bool lhs, value_bool rhs) const + { + return value_integer(lhs * rhs); + } +}; + +template +struct div +{ + using value_type = V; + + value_type operator()(value_null const& lhs, + value_null const& rhs) const + { + return lhs; + } + + value_type operator()(value_unicode_string const& lhs, value_null) const + { + return lhs; + } + + value_type operator()(value_null, value_unicode_string const& rhs) const + { + return rhs; + } + + template + value_type operator()(L const& lhs, value_null const&) const + { + return lhs; + } + + template + value_type operator()(value_null const&, R const& rhs) const + { + return rhs; + } + + template + value_type operator()(T lhs, T rhs) const + { + if (rhs == 0) return value_type(); + return lhs / rhs; + } + + value_type operator()(value_bool lhs, value_bool rhs) const + { + if (rhs == 0) return lhs; + return value_integer(lhs) / value_integer(rhs); + } + + value_type operator()(value_unicode_string const&, + value_unicode_string const&) const + { + return value_type(); + } + + template + value_type operator()(value_unicode_string const& lhs, R const&) const + { + return lhs; + } + + template + value_type operator()(L const&, value_unicode_string const& rhs) const + { + return rhs; + } + + template + value_type operator()(T1 const& lhs, T2 const& rhs) const + { + if (rhs == 0) return value_type(); + using common_type = typename std::common_type::type; + return common_type(lhs) / common_type(rhs); + } +}; + +template +struct mod +{ + using value_type = V; + + template + value_type operator()(T1 const& lhs, T2 const&) const + { + return lhs; + } + + template + value_type operator()(T lhs, T rhs) const + { + return lhs % rhs; + } + + value_type operator()(value_unicode_string const&, + value_unicode_string const&) const + { + return value_type(); + } + + value_type operator()(value_bool, + value_bool) const + { + return false; + } + + value_type operator()(value_double lhs, value_integer rhs) const + { + return std::fmod(lhs, static_cast(rhs)); + } + + value_type operator()(value_integer lhs, value_double rhs) const + { + return std::fmod(static_cast(lhs), rhs); + } + + value_type operator()(value_double lhs, value_double rhs) const + { + return std::fmod(lhs, rhs); + } +}; + +template +struct negate +{ + using value_type = V; + + template + value_type operator()(T val) const + { + return -val; + } + + value_type operator()(value_null val) const + { + return val; + } + + value_type operator()(value_bool val) const + { + return val ? value_integer(-1) : value_integer(0); + } + + value_type operator()(value_unicode_string const&) const + { + return value_type(); + } +}; + +// converters +template +struct convert +{ +}; + +template <> +struct convert +{ + value_bool operator()(value_bool val) const + { + return val; + } + + value_bool operator()(value_unicode_string const& ustr) const + { + return !ustr.isEmpty(); + } + + value_bool operator()(value_null const&) const + { + return false; + } + + template + value_bool operator()(T val) const + { + return val > 0 ? true : false; + } +}; + +template <> +struct convert +{ + value_double operator()(value_double val) const + { + return val; + } + + value_double operator()(value_integer val) const + { + return static_cast(val); + } + + value_double operator()(value_bool val) const + { + return static_cast(val); + } + + value_double operator()(std::string const& val) const + { + value_double result; + if (util::string2double(val, result)) + return result; + return 0; + } + + value_double operator()(value_unicode_string const& val) const + { + std::string utf8; + val.toUTF8String(utf8); + return operator()(utf8); + } + + value_double operator()(value_null const&) const + { + return 0.0; + } +}; + +template <> +struct convert +{ + value_integer operator()(value_integer val) const + { + return val; + } + + value_integer operator()(value_double val) const + { + return static_cast(rint(val)); + } + + value_integer operator()(value_bool val) const + { + return static_cast(val); + } + + value_integer operator()(std::string const& val) const + { + value_integer result; + if (util::string2int(val, result)) + return result; + return value_integer(0); + } + + value_integer operator()(value_unicode_string const& val) const + { + std::string utf8; + val.toUTF8String(utf8); + return operator()(utf8); + } + + value_integer operator()(value_null const&) const + { + return value_integer(0); + } +}; + +template <> +struct convert +{ + template + std::string operator()(T val) const + { + std::string str; + util::to_string(str, val); + return str; + } + + // specializations + std::string operator()(value_unicode_string const& val) const + { + std::string utf8; + val.toUTF8String(utf8); + return utf8; + } + + std::string operator()(value_double val) const + { + std::string str; + util::to_string(str, val); // TODO set precision(16) + return str; + } + + std::string operator()(value_bool val) const + { + return val ? "true" : "false"; + } + + std::string operator()(value_null const&) const + { + return std::string(); + } +}; + +struct to_unicode_impl +{ + + template + value_unicode_string operator()(T val) const + { + std::string str; + util::to_string(str, val); + return value_unicode_string(str.c_str()); + } + + // specializations + value_unicode_string const& operator()(value_unicode_string const& val) const + { + return val; + } + + value_unicode_string operator()(value_double val) const + { + std::string str; + util::to_string(str, val); + return value_unicode_string(str.c_str()); + } + + value_unicode_string operator()(value_bool val) const + { + return value_unicode_string(val ? "true" : "false"); + } + + value_unicode_string operator()(value_null const&) const + { + return value_unicode_string(); + } +}; + +struct to_expression_string_impl +{ + struct EscapingByteSink : U_NAMESPACE_QUALIFIER ByteSink + { + std::string dest_; + char quote_; + + explicit EscapingByteSink(char quote) + : quote_(quote) + { + } + + virtual void Append(const char* data, int32_t n) + { + // reserve enough room to hold the appended chunk and quotes; + // if another chunk follows, or any character needs escaping, + // the string will grow naturally + if (dest_.empty()) + { + dest_.reserve(2 + static_cast(n)); + dest_.append(1, quote_); + } + else + { + dest_.reserve(dest_.size() + n + 1); + } + + for (auto end = data + n; data < end; ++data) + { + if (*data == '\\' || *data == quote_) + dest_.append(1, '\\'); + dest_.append(1, *data); + } + } + + virtual void Flush() + { + if (dest_.empty()) + dest_.append(2, quote_); + else + dest_.append(1, quote_); + } + }; + + explicit to_expression_string_impl(char quote = '\'') + : quote_(quote) {} + + std::string operator()(value_unicode_string const& val) const + { + EscapingByteSink sink(quote_); + val.toUTF8(sink); + return sink.dest_; + } + + std::string operator()(value_integer val) const + { + std::string output; + util::to_string(output, val); + return output; + } + + std::string operator()(value_double val) const + { + std::string output; + util::to_string(output, val); // TODO precision(16) + return output; + } + + std::string operator()(value_bool val) const + { + return val ? "true" : "false"; + } + + std::string operator()(value_null const&) const + { + return "null"; + } + + const char quote_; +}; + +} // ns detail + +namespace value_adl_barrier { + +bool value::operator==(value const& other) const +{ + return util::apply_visitor(detail::comparison(), *this, other); +} + +bool value::operator!=(value const& other) const +{ + return util::apply_visitor(detail::comparison(), *this, other); +} + +bool value::operator>(value const& other) const +{ + return util::apply_visitor(detail::comparison(), *this, other); +} + +bool value::operator>=(value const& other) const +{ + return util::apply_visitor(detail::comparison(), *this, other); +} + +bool value::operator<(value const& other) const +{ + return util::apply_visitor(detail::comparison(), *this, other); +} + +bool value::operator<=(value const& other) const +{ + return util::apply_visitor(detail::comparison(), *this, other); +} + +value value::operator-() const +{ + return util::apply_visitor(detail::negate(), *this); +} + +value_bool value::to_bool() const +{ + return util::apply_visitor(detail::convert(), *this); +} + +std::string value::to_expression_string(char quote) const +{ + return util::apply_visitor(detail::to_expression_string_impl(quote), *this); +} + +std::string value::to_string() const +{ + return util::apply_visitor(detail::convert(), *this); +} + +value_unicode_string value::to_unicode() const +{ + return util::apply_visitor(detail::to_unicode_impl(), *this); +} + +value_double value::to_double() const +{ + return util::apply_visitor(detail::convert(), *this); +} + +value_integer value::to_int() const +{ + return util::apply_visitor(detail::convert(), *this); +} + +bool value::is_null() const +{ + return util::apply_visitor(mapnik::detail::is_null_visitor(), *this); +} + +template <> +value_double value::convert() const +{ + return util::apply_visitor(detail::convert(), *this); +} + +template <> +value_integer value::convert() const +{ + return util::apply_visitor(detail::convert(), *this); +} + +template <> +value_bool value::convert() const +{ + return util::apply_visitor(detail::convert(), *this); +} + +template <> +std::string value::convert() const +{ + return util::apply_visitor(detail::convert(), *this); +} + +// +value operator+(value const& p1, value const& p2) +{ + return value(util::apply_visitor(detail::add(), p1, p2)); +} + +value operator-(value const& p1, value const& p2) +{ + return value(util::apply_visitor(detail::sub(), p1, p2)); +} + +value operator*(value const& p1, value const& p2) +{ + return value(util::apply_visitor(detail::mult(), p1, p2)); +} + +value operator/(value const& p1, value const& p2) +{ + return value(util::apply_visitor(detail::div(), p1, p2)); +} + +value operator%(value const& p1, value const& p2) +{ + return value(util::apply_visitor(detail::mod(), p1, p2)); +} + +} // namespace value_adl_barrier +} // namespace mapnik