From 0939acca3052622a1435457b3c91517fb50bde92 Mon Sep 17 00:00:00 2001 From: artemp Date: Wed, 12 Feb 2014 14:32:54 +0000 Subject: [PATCH 1/2] custom variant type (replaces boost::variant and removes boost dependency altogether) --- include/llmr/style/value.hpp | 4 +- include/llmr/util/variant.hpp | 380 ++++++++++++++++++++++++++++++++++ src/map/vector_tile.cpp | 4 +- src/style/style.cpp | 2 +- src/style/value.cpp | 2 +- 5 files changed, 386 insertions(+), 6 deletions(-) create mode 100644 include/llmr/util/variant.hpp diff --git a/include/llmr/style/value.hpp b/include/llmr/style/value.hpp index b90f824e9..2e9d66136 100644 --- a/include/llmr/style/value.hpp +++ b/include/llmr/style/value.hpp @@ -1,12 +1,12 @@ #ifndef LLMR_STYLE_VALUE #define LLMR_STYLE_VALUE -#include +#include #include namespace llmr { -typedef boost::variant Value; +typedef ::util::variant Value; Value parseValue(pbf data); diff --git a/include/llmr/util/variant.hpp b/include/llmr/util/variant.hpp new file mode 100644 index 000000000..410aa8ead --- /dev/null +++ b/include/llmr/util/variant.hpp @@ -0,0 +1,380 @@ +#ifndef UTIL_VARIANT_HPP +#define UTIL_VARIANT_HPP + +#include +#include +#include +#include // std::move/swap +#include // runtime_error +#include // operator new +#include // size_t +#include + +#ifdef NDEBUG + #define VARIANT_INLINE inline __attribute__((always_inline)) +#else + #define VARIANT_INLINE __attribute__((noinline)) +#endif + +namespace util { + +namespace detail { + +static constexpr std::size_t invalid_value = std::size_t(-1); + +template +struct type_traits; + +template +struct type_traits +{ + static constexpr std::size_t id = std::is_same::value ? sizeof...(Types) : type_traits::id; +}; + +template +struct type_traits +{ + static constexpr std::size_t id = invalid_value; +}; + +template +struct is_valid_type; + +template +struct is_valid_type +{ + static constexpr bool value = std::is_same::value + || is_valid_type::value; +}; + +template +struct is_valid_type : std::false_type {}; + +} + +template +struct static_max; + +template +struct static_max +{ + static const std::size_t value = arg; +}; + +template +struct static_max +{ + static const std::size_t value = arg1 >= arg2 ? static_max::value : + static_max::value; +}; + +template +struct variant_helper; + +template +struct variant_helper +{ + VARIANT_INLINE static void destroy(std::size_t id, void * data) + { + if (id == sizeof...(Types)) + { + reinterpret_cast(data)->~T(); + } + else + { + variant_helper::destroy(id, data); + } + } + + VARIANT_INLINE static void move(const std::size_t old_t, void * old_v, void * new_v) + { + if (old_t == sizeof...(Types)) + { + new (new_v) T(std::move(*reinterpret_cast(old_v))); + //std::memcpy(new_v, old_v, sizeof(T)); + // ^^ DANGER: this should only be considered for relocatable types e.g built-in types + // Also, I don't see any measurable performance benefit just yet + } + else + { + variant_helper::move(old_t, old_v, new_v); + } + } + + VARIANT_INLINE static void copy(const std::size_t old_t, const void * old_v, void * new_v) + { + if (old_t == sizeof...(Types)) + { + new (new_v) T(*reinterpret_cast(old_v)); + } + else + { + variant_helper::copy(old_t, old_v, new_v); + } + } +}; + +template<> struct variant_helper<> +{ + VARIANT_INLINE static void destroy(const std::size_t, void *) {} + VARIANT_INLINE static void move(const std::size_t, void *, void *) {} + VARIANT_INLINE static void copy(const std::size_t, const void *, void *) {} +}; + +namespace detail { + +template +struct dispatcher; + +template +struct dispatcher +{ + typedef typename std::result_of::type result_type; + VARIANT_INLINE static result_type apply(V const& v, F f) + { + if (v.get_type_id() == sizeof...(Types)) + { + return f(v. template get()); + } + else + { + return dispatcher::apply(v, f); + } + } +}; + +template +struct dispatcher +{ + typedef typename std::result_of::type result_type; + VARIANT_INLINE static result_type apply(V const&, F) + { + throw std::runtime_error("dispatch: FAIL"); + } +}; + +// comparator functors +struct equal_comp +{ + template + bool operator()(T const& lhs, T const& rhs) const + { + return lhs == rhs; + } +}; + +struct less_comp +{ + template + bool operator()(const T& lhs, const T& rhs) const + { + return lhs < rhs; + } +}; + +template +struct comparer +{ +public: + explicit comparer(Variant const& lhs) noexcept + : lhs_(lhs) {} + comparer& operator=(const comparer&) = delete; + // visitor + template + bool operator()(T const& rhs_content) const + { + T const& lhs_content = lhs_.template get(); + return Comp()(lhs_content, rhs_content); + } +private: + Variant const& lhs_; +}; + +// operator<< helper +template +struct printer +{ +public: + explicit printer(Out & out) + : out_(out) {} + printer& operator=(const printer&) = delete; + +// visitor + template + void operator()(const T& operand) const + { + out_ << operand; + } +private: + Out & out_; +}; + +} // detail + +template +struct variant +{ +private: + + static const std::size_t data_size = static_max::value; + static const std::size_t data_align = static_max::value; + + using data_t = typename std::aligned_storage::type; + + using helper_t = variant_helper; + + std::size_t type_id; + data_t data; + +public: + + VARIANT_INLINE variant() + : type_id(detail::invalid_value) {} + + template + VARIANT_INLINE explicit variant(T const& val) noexcept + : type_id(detail::type_traits::id) + { + static_assert(detail::is_valid_type::value, "Not a valid type for this variant"); + new (&data) T(val); + } + + template + VARIANT_INLINE variant(T && val) noexcept + : type_id(detail::type_traits::id) + { + static_assert(detail::is_valid_type::value, "Not a valid type for this variant"); + new (&data) T(std::forward(val)); // nothrow + } + + VARIANT_INLINE variant(variant const& old) + : type_id(old.type_id) + { + helper_t::copy(old.type_id, &old.data, &data); + } + + VARIANT_INLINE variant(variant&& old) noexcept + : type_id(old.type_id) + { + helper_t::move(old.type_id, &old.data, &data); + } + + friend void swap(variant & first, variant & second) + { + using std::swap; //enable ADL + swap(first.type_id, second.type_id); + swap(first.data, second.data); + } + + VARIANT_INLINE variant& operator= (variant other) + { + swap(*this, other); + return *this; + } + + template + VARIANT_INLINE void is() const + { + return (type_id == detail::type_traits::id); + } + + VARIANT_INLINE void valid() const + { + return (type_id != detail::invalid_value); + } + + template + VARIANT_INLINE void set(Args&&... args) + { + helper_t::destroy(type_id, &data); + new (&data) T(std::forward(args)...); + type_id = detail::type_traits::id; + } + + template + VARIANT_INLINE T& get() + { + if (type_id == detail::type_traits::id) + { + return *reinterpret_cast(&data); + } + else + { + throw std::runtime_error("in get()"); + } + } + + template + VARIANT_INLINE T const& get() const + { + if (type_id == detail::type_traits::id) + { + return *reinterpret_cast(&data); + } + else + { + throw std::runtime_error("in get()"); + } + } + + VARIANT_INLINE std::size_t get_type_id() const + { + return type_id; + } + + // visitor + template + typename std::result_of::type + VARIANT_INLINE static visit(V const& v, F f) + { + return detail::dispatcher::apply(v, f); + } + + ~variant() noexcept + { + helper_t::destroy(type_id, &data); + } + + // comparison operators + // equality + VARIANT_INLINE bool operator==(variant const& rhs) const + { + if (this->get_type_id() != rhs.get_type_id()) + return false; + detail::comparer visitor(*this); + return visit(rhs, visitor); + } + // less than + VARIANT_INLINE bool operator<(variant const& rhs) const + { + if (this->get_type_id() != rhs.get_type_id()) + { + return this->get_type_id() < rhs.get_type_id(); + // ^^ borrowed from boost::variant + } + detail::comparer visitor(*this); + return visit(rhs, visitor); + } +}; + +// unary visitor interface +template +typename std::result_of::type +VARIANT_INLINE static apply_visitor(V const& v, F f) +{ + return V::visit(v,f); +} + +// operator<< +template +VARIANT_INLINE std::basic_ostream& +operator<< (std::basic_ostream& out, Variant const& rhs) +{ + detail::printer > visitor(out); + apply_visitor(rhs, visitor); + return out; +} + +} + +#endif // UTIL_VARIANT_HPP diff --git a/src/map/vector_tile.cpp b/src/map/vector_tile.cpp index e64d7114b..c6ded9302 100644 --- a/src/map/vector_tile.cpp +++ b/src/map/vector_tile.cpp @@ -12,7 +12,7 @@ VectorTile::VectorTile(pbf tile) { while (tile.next()) { if (tile.tag == 3) { // layer VectorTileLayer layer(tile.message()); - layers.emplace(layer.name, layer); + layers.emplace(layer.name, std::forward(layer)); } else { tile.skip(); } @@ -34,7 +34,7 @@ VectorTileLayer::VectorTileLayer(pbf layer) : data(layer) { } else if (layer.tag == 3) { // keys keys.emplace_back(layer.string()); } else if (layer.tag == 4) { // values - values.emplace_back(parseValue(layer.message())); + values.emplace_back(std::move(parseValue(layer.message()))); } else if (layer.tag == 5) { // extent extent = layer.varint(); } else { diff --git a/src/style/style.cpp b/src/style/style.cpp index 0e8e9f3b6..7ac5e9ef7 100644 --- a/src/style/style.cpp +++ b/src/style/style.cpp @@ -60,7 +60,7 @@ std::pair Style::parseBucket(pbf data) { } } - return { name, bucket }; + return { name, std::forward(bucket) }; } LayerDescription Style::parseLayer(pbf data) { diff --git a/src/style/value.cpp b/src/style/value.cpp index 99086f377..4ea1a6cd8 100644 --- a/src/style/value.cpp +++ b/src/style/value.cpp @@ -8,7 +8,7 @@ llmr::Value llmr::parseValue(pbf data) { case 1: // string_value return data.string(); case 2: // float_value - return data.float32(); + return static_cast(data.float32()); case 3: // double_value return data.float64(); case 4: // int_value From 7fbb33b5de38ca24b834204a8831b359203dfc06 Mon Sep 17 00:00:00 2001 From: Dane Springmeyer Date: Wed, 12 Feb 2014 13:15:09 -0800 Subject: [PATCH 2/2] remove boost from readme and build system --- .travis.yml | 2 +- README.md | 15 +++------------ common.gypi | 11 ++++------- configure | 9 --------- 4 files changed, 8 insertions(+), 29 deletions(-) diff --git a/.travis.yml b/.travis.yml index 50857eb68..d64f152cb 100644 --- a/.travis.yml +++ b/.travis.yml @@ -8,7 +8,7 @@ before_install: - sudo add-apt-repository --yes ppa:ubuntu-toolchain-r/test - sudo apt-get update -qq - sudo apt-get -y install gcc-4.8 g++-4.8 -- sudo apt-get -y install git cmake make pkg-config libboost-dev libpng-dev +- sudo apt-get -y install git cmake make pkg-config libpng-dev - sudo apt-get -y install libxi-dev libglu1-mesa-dev x11proto-randr-dev x11proto-xext-dev libxrandr-dev x11proto-xf86vidmode-dev libxxf86vm-dev install: diff --git a/README.md b/README.md index f6b8c8b11..24f97490c 100644 --- a/README.md +++ b/README.md @@ -5,16 +5,16 @@ implemented in C++, targeting iOS & OS X. ## OS X -Install boost, libpng, and [glfw3](http://www.glfw.org/docs/latest/): +Install libpng and [glfw3](http://www.glfw.org/docs/latest/): ``` -brew install boost libpng +brew install libpng brew install homebrew/versions/glfw3 ``` Then configure the project: - ./configure --boost=`brew --prefix` --glfw3=`brew --prefix` --png=`brew --prefix` + ./configure --glfw3=`brew --prefix` --png=`brew --prefix` See all the options by calling `./configure --help` @@ -25,7 +25,6 @@ Usage: configure [options] Options: -h, --help show this help message and exit --debug Also build debug build - --boost=BOOST_ROOT Path to boost (defaults to /usr/local) --glfw3=GLFW3 Path to gflw3 (defaults to using pkg-config) --png=PNG Path to png (defaults to using pkg-config) --png-includes=PNG_INCLUDES @@ -45,10 +44,6 @@ Or generate a dual iOS/OS X-compatible Xcode project for `libllmr` to include as ## iOS -Install boost: - - brew install boost - Because `libpng` isn't included in the iOS SDK, you will need to build a cross-architecture version yourself. Run `./ios/setup_libpng.sh`, which is derived from Mapnik's cross-architecture build scripts. This will also run `./configure`. Then you can build the iOS app with make: @@ -69,10 +64,6 @@ Install a `-std=c++11` capable compiler sudo apt-get update sudo apt-get install gcc-4.8 g++-4.8 -Install boost (we only need headers): - - sudo apt-get install libboost-dev - Install libpng-dev: sudo apt-get install libpng-dev diff --git a/common.gypi b/common.gypi index a9e700c7b..55aaad9d9 100644 --- a/common.gypi +++ b/common.gypi @@ -9,18 +9,15 @@ 'cflags':['-std=c++11'], 'configurations': { 'Debug': { - 'cflags': [ '-g', '-O0', '-I<(boost_root)/include' ], + 'cflags': [ '-g', '-O0' ], 'defines': [ 'DEBUG' ], 'xcode_settings': { - 'OTHER_CPLUSPLUSFLAGS': [ '-g', '-I<(boost_root)/include' ] + 'OTHER_CPLUSPLUSFLAGS': [ '-g'] } }, 'Release': { - 'cflags': [ '-O3', '-I<(boost_root)/include' ], - 'defines': [ 'NDEBUG' ], - 'xcode_settings': { - 'OTHER_CPLUSPLUSFLAGS': [ '-I<(boost_root)/include' ] - } + 'cflags': [ '-O3'], + 'defines': [ 'NDEBUG' ] } } } diff --git a/configure b/configure index b669e2295..e774317a2 100755 --- a/configure +++ b/configure @@ -19,11 +19,6 @@ parser.add_option("--debug", dest="debug", help="Also build debug build") -parser.add_option("--boost", - action="store", - dest="boost_root", - help="Path to boost (defaults to /usr/local)") - parser.add_option("--glfw3", action="store", dest="glfw3", @@ -60,10 +55,6 @@ def pkg_config(pkg): return (libs, cflags) def configure_llmr(o): - if options.boost_root: - o['variables']['boost_root'] = options.boost_root - else: - o['variables']['boost_root'] = '/usr/local' o['target_defaults']['default_configuration'] = 'Debug' if options.debug else 'Release' def configure_glfw3(o):