Added the Mapbox files.
This commit is contained in:
		
							parent
							
								
									e0a2599d8d
								
							
						
					
					
						commit
						27d16e33bd
					
				| 
						 | 
				
			
			@ -0,0 +1,251 @@
 | 
			
		|||
#include <iostream>
 | 
			
		||||
 | 
			
		||||
/* Requires the mapbox header-only variant found at
 | 
			
		||||
   https://github.com/mapbox/variant
 | 
			
		||||
 | 
			
		||||
   Compiles with: 
 | 
			
		||||
   clang++ -std=c++14 -I./include/ -o collector collector.cpp
 | 
			
		||||
   …  or
 | 
			
		||||
   g++ -std=c++1y -I./include/ -g -o collector collector.cpp
 | 
			
		||||
   … where 'include' has the variant headers.
 | 
			
		||||
 | 
			
		||||
   clang version 3.9.1-svn288847-1~exp1 (branches/release_39)
 | 
			
		||||
   g++ version (Ubuntu 4.8.5-2ubuntu1~14.04.1) 4.8.5
 | 
			
		||||
 | 
			
		||||
*/
 | 
			
		||||
#include <mapbox/variant.hpp>
 | 
			
		||||
 | 
			
		||||
#define MAX_STACK 256
 | 
			
		||||
#define MAX_BARRIER 8
 | 
			
		||||
 | 
			
		||||
void my_assert(int condition, const char* message) {
 | 
			
		||||
  if (!condition) {
 | 
			
		||||
    std::cout << message << std::endl;
 | 
			
		||||
    exit(1);
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* An implementation of Bob Nystrom's "Baby's First Garbage Collector"
 | 
			
		||||
   http://journal.stuffwithstuff.com/2013/12/08/babys-first-garbage-collector/,
 | 
			
		||||
   only in C++, and with some educational stuff along the way about
 | 
			
		||||
   the new Variant (automagical discriminated unions) coming in
 | 
			
		||||
   Libstdc++ version 4, part of the C++ 2017 standard.
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
class Object {
 | 
			
		||||
public:
 | 
			
		||||
  unsigned char marked;
 | 
			
		||||
  Object *next;
 | 
			
		||||
  Object(int v): marked(0), value(v) {}
 | 
			
		||||
  Object(Object* head, Object* tail): marked(0), value(Pair(head, tail)) {}
 | 
			
		||||
 | 
			
		||||
  class Pair {
 | 
			
		||||
  public:
 | 
			
		||||
    Pair(Object* h, Object* t): head(h), tail(t) {};
 | 
			
		||||
    Object* head;
 | 
			
		||||
    Object* tail;
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  /* This is mostly an exploration of a discriminated union, and
 | 
			
		||||
     making one work in the context of a primitive but functional
 | 
			
		||||
     garbage collector. */
 | 
			
		||||
  mapbox::util::variant<int, Pair> value;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
class VM {
 | 
			
		||||
public:
 | 
			
		||||
  /* Imagine my surprise when I learned that clang doesn't bother to
 | 
			
		||||
     zero out memory allocated on the threadstack. */
 | 
			
		||||
  VM(): stackSize(0), numObjects(0), maxObjects(MAX_BARRIER), root(NULL) {};
 | 
			
		||||
  
 | 
			
		||||
  Object* pop() {
 | 
			
		||||
    my_assert(stackSize > 0, "Stack underflow!");
 | 
			
		||||
    return stack[--stackSize];
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /* This is basically the interface for a very primitive reverse
 | 
			
		||||
     polish notation calculator of some kind.  A garbage-collected
 | 
			
		||||
     Forth interpreter, perhaps. */
 | 
			
		||||
 | 
			
		||||
  Object* push(int v) {
 | 
			
		||||
    return _push(insert(new Object(v)));
 | 
			
		||||
  }
 | 
			
		||||
  
 | 
			
		||||
  Object* push() {
 | 
			
		||||
    return _push(insert(new Object(pop(), pop())));
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /* Lambda-style visitors, enabling descent. */
 | 
			
		||||
  void mark(Object *o) {
 | 
			
		||||
    auto marker = mapbox::util::make_visitor(
 | 
			
		||||
        [this](int) {},
 | 
			
		||||
        [this](Object::Pair p) {
 | 
			
		||||
          this->mark(p.head);
 | 
			
		||||
          this->mark(p.tail);
 | 
			
		||||
    });
 | 
			
		||||
    
 | 
			
		||||
    if (o->marked) {
 | 
			
		||||
      return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    o->marked = 1;
 | 
			
		||||
    return mapbox::util::apply_visitor(marker, o->value);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /* So named because each scope resembles a collection of objects
 | 
			
		||||
     leading horizontally from the vertical stack, creating a spine. */
 | 
			
		||||
  void markSpine() {
 | 
			
		||||
    for(auto i = 0; i < stackSize; i++) {
 | 
			
		||||
      mark(stack[i]);
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  void collect() {
 | 
			
		||||
    int num = numObjects;
 | 
			
		||||
    markSpine();
 | 
			
		||||
    sweep();
 | 
			
		||||
    maxObjects = numObjects * 2;
 | 
			
		||||
#ifdef DEBUG
 | 
			
		||||
    std::cout << "Collected " << (num - numObjects) << " objects, "
 | 
			
		||||
              << numObjects << " remain." << std::endl;
 | 
			
		||||
#endif
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /* The saddest fact: I went with using NULL as our end-of-stack
 | 
			
		||||
     discriminator rather than something higher-level, like an
 | 
			
		||||
     Optional or Either-variant, because to use those I'd have to
 | 
			
		||||
     user recursion to sweep the interpreter's stack, which means
 | 
			
		||||
     I'm at the mercy of the C stack, complete with the cost of the
 | 
			
		||||
     unwind at the end.  Bummer. */
 | 
			
		||||
 | 
			
		||||
  /* I look at this and ask, WWHSD?  What Would Herb Sutter Do? */
 | 
			
		||||
  
 | 
			
		||||
  void sweep() {
 | 
			
		||||
    Object** o = &root;
 | 
			
		||||
    while(*o) {
 | 
			
		||||
      if (!(*o)->marked) {
 | 
			
		||||
        Object* unreached = *o;
 | 
			
		||||
        *o = unreached->next;
 | 
			
		||||
        numObjects--;
 | 
			
		||||
        delete unreached;
 | 
			
		||||
      } else {
 | 
			
		||||
        (*o)->marked = 0;
 | 
			
		||||
        o = &(*o)->next;
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
      
 | 
			
		||||
  int numObjects;
 | 
			
		||||
  
 | 
			
		||||
private:
 | 
			
		||||
 | 
			
		||||
  /* Heh.  Typo, "Stark overflow."  I'll just leave Tony right there anyway... */
 | 
			
		||||
  Object* _push(Object *o) {
 | 
			
		||||
    my_assert(stackSize < MAX_STACK, "Stark overflow");
 | 
			
		||||
    stack[stackSize++] = o;
 | 
			
		||||
    return o;
 | 
			
		||||
  }
 | 
			
		||||
  
 | 
			
		||||
  Object* insert(Object *o) {
 | 
			
		||||
    if (numObjects >= maxObjects) {
 | 
			
		||||
      collect();
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    o->marked = 0;
 | 
			
		||||
    o->next = root;
 | 
			
		||||
    root = o;
 | 
			
		||||
    numObjects++;
 | 
			
		||||
    return o;
 | 
			
		||||
  }
 | 
			
		||||
    
 | 
			
		||||
  Object* stack[MAX_STACK];
 | 
			
		||||
  Object* root;
 | 
			
		||||
  int stackSize;
 | 
			
		||||
  int maxObjects;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
void test1() {
 | 
			
		||||
  std::cout << "Test 1: Objects on stack are preserved." << std::endl;
 | 
			
		||||
  VM vm;
 | 
			
		||||
  vm.push(1);
 | 
			
		||||
  vm.push(2);
 | 
			
		||||
  vm.collect();
 | 
			
		||||
  my_assert(vm.numObjects == 2, "Should have preserved objects.");
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void test2() {
 | 
			
		||||
  std::cout << "Test 2: Unreached objects are collected." << std::endl;
 | 
			
		||||
  VM vm;
 | 
			
		||||
  vm.push(1);
 | 
			
		||||
  vm.push(2);
 | 
			
		||||
  vm.pop();
 | 
			
		||||
  vm.pop();
 | 
			
		||||
  vm.collect();
 | 
			
		||||
  my_assert(vm.numObjects == 0, "Should have collected objects.");
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
    
 | 
			
		||||
void test3() {
 | 
			
		||||
  std::cout << "Test 3: Reach nested objects." << std::endl;
 | 
			
		||||
  VM vm;
 | 
			
		||||
  vm.push(1);
 | 
			
		||||
  vm.push(2);
 | 
			
		||||
  vm.push();
 | 
			
		||||
  vm.push(3);
 | 
			
		||||
  vm.push(4);
 | 
			
		||||
  vm.push();
 | 
			
		||||
  vm.push();
 | 
			
		||||
  vm.collect();
 | 
			
		||||
  my_assert(vm.numObjects == 7, "Should have reached objects.");
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void test4() {
 | 
			
		||||
  std::cout << "Test 4: Handle cycles." << std::endl;
 | 
			
		||||
  VM vm;
 | 
			
		||||
  vm.push(1);
 | 
			
		||||
  vm.push(2);
 | 
			
		||||
  Object* a = vm.push();
 | 
			
		||||
  vm.push(3);
 | 
			
		||||
  vm.push(4);
 | 
			
		||||
  Object* b = vm.push();
 | 
			
		||||
 | 
			
		||||
  /* Constructor-based variant visitor. */
 | 
			
		||||
  struct tail_setter {
 | 
			
		||||
    Object* tail;
 | 
			
		||||
    tail_setter(Object *t) : tail(t) {}
 | 
			
		||||
    inline void operator()(int &i) {}
 | 
			
		||||
    inline void operator()(Object::Pair &p) { p.tail = tail; }
 | 
			
		||||
  };
 | 
			
		||||
  
 | 
			
		||||
  /* Set up a cycle, and also make 2 and 4 unreachable and collectible. */
 | 
			
		||||
  mapbox::util::apply_visitor(tail_setter(b), a->value);
 | 
			
		||||
  mapbox::util::apply_visitor(tail_setter(a), b->value);
 | 
			
		||||
  vm.collect();
 | 
			
		||||
  my_assert(vm.numObjects == 4, "Should have collected objects.");
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void perfTest() {
 | 
			
		||||
  std::cout << "Performance Test." << std::endl;
 | 
			
		||||
  VM vm;
 | 
			
		||||
 | 
			
		||||
  for (int i = 0; i < 1000; i++) {
 | 
			
		||||
    for (int j = 0; j < 20; j++) {
 | 
			
		||||
      vm.push(i);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    for (int k = 0; k < 20; k++) {
 | 
			
		||||
      vm.pop();
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int main(int argc, const char * argv[]) {
 | 
			
		||||
  test1();
 | 
			
		||||
  test2();
 | 
			
		||||
  test3();
 | 
			
		||||
  test4();
 | 
			
		||||
  perfTest();
 | 
			
		||||
 | 
			
		||||
  return 0;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,74 @@
 | 
			
		|||
#ifndef MAPBOX_UTIL_OPTIONAL_HPP
 | 
			
		||||
#define MAPBOX_UTIL_OPTIONAL_HPP
 | 
			
		||||
 | 
			
		||||
#pragma message("This implementation of optional is deprecated. See https://github.com/mapbox/variant/issues/64.")
 | 
			
		||||
 | 
			
		||||
#include <type_traits>
 | 
			
		||||
#include <utility>
 | 
			
		||||
 | 
			
		||||
#include <mapbox/variant.hpp>
 | 
			
		||||
 | 
			
		||||
namespace mapbox {
 | 
			
		||||
namespace util {
 | 
			
		||||
 | 
			
		||||
template <typename T>
 | 
			
		||||
class optional
 | 
			
		||||
{
 | 
			
		||||
    static_assert(!std::is_reference<T>::value, "optional doesn't support references");
 | 
			
		||||
 | 
			
		||||
    struct none_type
 | 
			
		||||
    {
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    variant<none_type, T> variant_;
 | 
			
		||||
 | 
			
		||||
public:
 | 
			
		||||
    optional() = default;
 | 
			
		||||
 | 
			
		||||
    optional(optional const& rhs)
 | 
			
		||||
    {
 | 
			
		||||
        if (this != &rhs)
 | 
			
		||||
        { // protect against invalid self-assignment
 | 
			
		||||
            variant_ = rhs.variant_;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    optional(T const& v) { variant_ = v; }
 | 
			
		||||
 | 
			
		||||
    explicit operator bool() const noexcept { return variant_.template is<T>(); }
 | 
			
		||||
 | 
			
		||||
    T const& get() const { return variant_.template get<T>(); }
 | 
			
		||||
    T& get() { return variant_.template get<T>(); }
 | 
			
		||||
 | 
			
		||||
    T const& operator*() const { return this->get(); }
 | 
			
		||||
    T operator*() { return this->get(); }
 | 
			
		||||
 | 
			
		||||
    optional& operator=(T const& v)
 | 
			
		||||
    {
 | 
			
		||||
        variant_ = v;
 | 
			
		||||
        return *this;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    optional& operator=(optional const& rhs)
 | 
			
		||||
    {
 | 
			
		||||
        if (this != &rhs)
 | 
			
		||||
        {
 | 
			
		||||
            variant_ = rhs.variant_;
 | 
			
		||||
        }
 | 
			
		||||
        return *this;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    template <typename... Args>
 | 
			
		||||
    void emplace(Args&&... args)
 | 
			
		||||
    {
 | 
			
		||||
        variant_ = T{std::forward<Args>(args)...};
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void reset() { variant_ = none_type{}; }
 | 
			
		||||
 | 
			
		||||
}; // class optional
 | 
			
		||||
 | 
			
		||||
} // namespace util
 | 
			
		||||
} // namespace mapbox
 | 
			
		||||
 | 
			
		||||
#endif // MAPBOX_UTIL_OPTIONAL_HPP
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,122 @@
 | 
			
		|||
#ifndef MAPBOX_UTIL_RECURSIVE_WRAPPER_HPP
 | 
			
		||||
#define MAPBOX_UTIL_RECURSIVE_WRAPPER_HPP
 | 
			
		||||
 | 
			
		||||
// Based on variant/recursive_wrapper.hpp from boost.
 | 
			
		||||
//
 | 
			
		||||
// Original license:
 | 
			
		||||
//
 | 
			
		||||
// Copyright (c) 2002-2003
 | 
			
		||||
// Eric Friedman, Itay Maman
 | 
			
		||||
//
 | 
			
		||||
// Distributed under the Boost Software License, Version 1.0. (See
 | 
			
		||||
// accompanying file LICENSE_1_0.txt or copy at
 | 
			
		||||
// http://www.boost.org/LICENSE_1_0.txt)
 | 
			
		||||
 | 
			
		||||
#include <cassert>
 | 
			
		||||
#include <utility>
 | 
			
		||||
 | 
			
		||||
namespace mapbox {
 | 
			
		||||
namespace util {
 | 
			
		||||
 | 
			
		||||
template <typename T>
 | 
			
		||||
class recursive_wrapper
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
    T* p_;
 | 
			
		||||
 | 
			
		||||
    void assign(T const& rhs)
 | 
			
		||||
    {
 | 
			
		||||
        this->get() = rhs;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
public:
 | 
			
		||||
    using type = T;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Default constructor default initializes the internally stored value.
 | 
			
		||||
     * For POD types this means nothing is done and the storage is
 | 
			
		||||
     * uninitialized.
 | 
			
		||||
     *
 | 
			
		||||
     * @throws std::bad_alloc if there is insufficient memory for an object
 | 
			
		||||
     *         of type T.
 | 
			
		||||
     * @throws any exception thrown by the default constructur of T.
 | 
			
		||||
     */
 | 
			
		||||
    recursive_wrapper()
 | 
			
		||||
        : p_(new T){}
 | 
			
		||||
 | 
			
		||||
    ~recursive_wrapper() noexcept { delete p_; }
 | 
			
		||||
 | 
			
		||||
    recursive_wrapper(recursive_wrapper const& operand)
 | 
			
		||||
        : p_(new T(operand.get())) {}
 | 
			
		||||
 | 
			
		||||
    recursive_wrapper(T const& operand)
 | 
			
		||||
        : p_(new T(operand)) {}
 | 
			
		||||
 | 
			
		||||
    recursive_wrapper(recursive_wrapper&& operand)
 | 
			
		||||
        : p_(new T(std::move(operand.get()))) {}
 | 
			
		||||
 | 
			
		||||
    recursive_wrapper(T&& operand)
 | 
			
		||||
        : p_(new T(std::move(operand))) {}
 | 
			
		||||
 | 
			
		||||
    inline recursive_wrapper& operator=(recursive_wrapper const& rhs)
 | 
			
		||||
    {
 | 
			
		||||
        assign(rhs.get());
 | 
			
		||||
        return *this;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    inline recursive_wrapper& operator=(T const& rhs)
 | 
			
		||||
    {
 | 
			
		||||
        assign(rhs);
 | 
			
		||||
        return *this;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    inline void swap(recursive_wrapper& operand) noexcept
 | 
			
		||||
    {
 | 
			
		||||
        T* temp = operand.p_;
 | 
			
		||||
        operand.p_ = p_;
 | 
			
		||||
        p_ = temp;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    recursive_wrapper& operator=(recursive_wrapper&& rhs) noexcept
 | 
			
		||||
    {
 | 
			
		||||
        swap(rhs);
 | 
			
		||||
        return *this;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    recursive_wrapper& operator=(T&& rhs)
 | 
			
		||||
    {
 | 
			
		||||
        get() = std::move(rhs);
 | 
			
		||||
        return *this;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    T& get()
 | 
			
		||||
    {
 | 
			
		||||
        assert(p_);
 | 
			
		||||
        return *get_pointer();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    T const& get() const
 | 
			
		||||
    {
 | 
			
		||||
        assert(p_);
 | 
			
		||||
        return *get_pointer();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    T* get_pointer() { return p_; }
 | 
			
		||||
 | 
			
		||||
    const T* get_pointer() const { return p_; }
 | 
			
		||||
 | 
			
		||||
    operator T const&() const { return this->get(); }
 | 
			
		||||
 | 
			
		||||
    operator T&() { return this->get(); }
 | 
			
		||||
 | 
			
		||||
}; // class recursive_wrapper
 | 
			
		||||
 | 
			
		||||
template <typename T>
 | 
			
		||||
inline void swap(recursive_wrapper<T>& lhs, recursive_wrapper<T>& rhs) noexcept
 | 
			
		||||
{
 | 
			
		||||
    lhs.swap(rhs);
 | 
			
		||||
}
 | 
			
		||||
} // namespace util
 | 
			
		||||
} // namespace mapbox
 | 
			
		||||
 | 
			
		||||
#endif // MAPBOX_UTIL_RECURSIVE_WRAPPER_HPP
 | 
			
		||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| 
						 | 
				
			
			@ -0,0 +1,45 @@
 | 
			
		|||
#ifndef MAPBOX_UTIL_VARIANT_IO_HPP
 | 
			
		||||
#define MAPBOX_UTIL_VARIANT_IO_HPP
 | 
			
		||||
 | 
			
		||||
#include <iosfwd>
 | 
			
		||||
 | 
			
		||||
#include <mapbox/variant.hpp>
 | 
			
		||||
 | 
			
		||||
namespace mapbox {
 | 
			
		||||
namespace util {
 | 
			
		||||
 | 
			
		||||
namespace detail {
 | 
			
		||||
// operator<< helper
 | 
			
		||||
template <typename Out>
 | 
			
		||||
class printer
 | 
			
		||||
{
 | 
			
		||||
public:
 | 
			
		||||
    explicit printer(Out& out)
 | 
			
		||||
        : out_(out) {}
 | 
			
		||||
    printer& operator=(printer const&) = delete;
 | 
			
		||||
 | 
			
		||||
    // visitor
 | 
			
		||||
    template <typename T>
 | 
			
		||||
    void operator()(T const& operand) const
 | 
			
		||||
    {
 | 
			
		||||
        out_ << operand;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    Out& out_;
 | 
			
		||||
};
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// operator<<
 | 
			
		||||
template <typename CharT, typename Traits, typename... Types>
 | 
			
		||||
VARIANT_INLINE std::basic_ostream<CharT, Traits>&
 | 
			
		||||
operator<<(std::basic_ostream<CharT, Traits>& out, variant<Types...> const& rhs)
 | 
			
		||||
{
 | 
			
		||||
    detail::printer<std::basic_ostream<CharT, Traits>> visitor(out);
 | 
			
		||||
    apply_visitor(visitor, rhs);
 | 
			
		||||
    return out;
 | 
			
		||||
}
 | 
			
		||||
} // namespace util
 | 
			
		||||
} // namespace mapbox
 | 
			
		||||
 | 
			
		||||
#endif // MAPBOX_UTIL_VARIANT_IO_HPP
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,38 @@
 | 
			
		|||
#ifndef MAPBOX_UTIL_VARIANT_VISITOR_HPP
 | 
			
		||||
#define MAPBOX_UTIL_VARIANT_VISITOR_HPP
 | 
			
		||||
 | 
			
		||||
namespace mapbox {
 | 
			
		||||
namespace util {
 | 
			
		||||
 | 
			
		||||
template <typename... Fns>
 | 
			
		||||
struct visitor;
 | 
			
		||||
 | 
			
		||||
template <typename Fn>
 | 
			
		||||
struct visitor<Fn> : Fn
 | 
			
		||||
{
 | 
			
		||||
    using type = Fn;
 | 
			
		||||
    using Fn::operator();
 | 
			
		||||
 | 
			
		||||
    visitor(Fn fn) : Fn(fn) {}
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
template <typename Fn, typename... Fns>
 | 
			
		||||
struct visitor<Fn, Fns...> : Fn, visitor<Fns...>
 | 
			
		||||
{
 | 
			
		||||
    using type = visitor;
 | 
			
		||||
    using Fn::operator();
 | 
			
		||||
    using visitor<Fns...>::operator();
 | 
			
		||||
 | 
			
		||||
    visitor(Fn fn, Fns... fns) : Fn(fn), visitor<Fns...>(fns...) {}
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
template <typename... Fns>
 | 
			
		||||
visitor<Fns...> make_visitor(Fns... fns)
 | 
			
		||||
{
 | 
			
		||||
    return visitor<Fns...>(fns...);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
} // namespace util
 | 
			
		||||
} // namespace mapbox
 | 
			
		||||
 | 
			
		||||
#endif // MAPBOX_UTIL_VARIANT_VISITOR_HPP
 | 
			
		||||
		Loading…
	
		Reference in New Issue