From e0a2599d8debf2d6871eb121bc4af8345fbfa62c Mon Sep 17 00:00:00 2001 From: "Elf M. Sternberg" Date: Sat, 10 Dec 2016 17:00:58 -0800 Subject: [PATCH 1/3] Initial check-in. --- .gitignore | 18 ++++ CMakeLists.txt | 7 ++ src/collector.c | 238 ++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 263 insertions(+) create mode 100644 .gitignore create mode 100644 CMakeLists.txt create mode 100644 src/collector.c diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..d9d39f2 --- /dev/null +++ b/.gitignore @@ -0,0 +1,18 @@ +*# +.#* +*~ +*.orig +npm-debug.log +package.yml +node_modules/* +tmp/ +bin/_mocha +bin/mocha +bin/escodegen +bin/esgenerate +test-reports.xml +LisperatorLanguage +src/test.js +src/test.coffee +notes/ +build/ diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..802a300 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,7 @@ +project("Collector") + +list(APPEND CMAKE_C_FLAGS "-std=c99 ${CMAKE_C_FLAGS} -g -ftest-coverage -fprofile-arcs") + +add_executable(collector + src/collector.c) + diff --git a/src/collector.c b/src/collector.c new file mode 100644 index 0000000..4daa110 --- /dev/null +++ b/src/collector.c @@ -0,0 +1,238 @@ +#include +#include + +#define MAX_STACK 256 +#define MAX_BARRIER 8 + +typedef enum { + OBJ_INT, + OBJ_PAIR +} ObjectType; + +typedef struct sObject { + unsigned char marked; + struct sObject* next; + ObjectType type; + union { + int value; + struct { + struct sObject* head; + struct sObject* tail; + }; + }; +} Object; + +typedef struct { + Object* stack[MAX_STACK]; + Object* root; + int stackSize; + int numObjects; + int maxObjects; +} VM; + +void assert(int condition, const char* message) { + if (!condition) { + printf("%s\n", message); + exit(1); + } +} + +VM* newVM() { + VM* vm = malloc(sizeof(VM)); + vm->stackSize = 0; + vm->numObjects = 0; + vm->maxObjects = MAX_BARRIER; + return vm; +} + +void push(VM* vm, Object* value) { + assert(vm->stackSize < MAX_STACK, "Stack overflow!"); + vm->stack[vm->stackSize++] = value; +} + +Object* pop(VM* vm) { + assert(vm->stackSize > 0, "Stack underflow!"); + return vm->stack[--(vm->stackSize)]; +} + +void mark(Object* object) { + if (object->marked) { + return; + } + + object->marked = 1; + if (object->type == OBJ_PAIR) { + mark(object->head); + mark(object->tail); + } +} + +void markAll(VM* vm) { + for(int i = 0; i < vm->stackSize; i++) { + mark(vm->stack[i]); + } +} + +void sweep(VM* vm) { + Object** object = &vm->root; + while (*object) { + if (!(*object)->marked) { + Object* unreached = *object; + *object = unreached->next; + vm->numObjects--; + free(unreached); + } else { + (*object)->marked = 0; + object = &(*object)->next; + } + } +} + +void gc(VM* vm) { + int numObjects = vm->numObjects; + markAll(vm); + sweep(vm); + vm->maxObjects = vm->numObjects * 2; + printf("Collected %d objects, %d remaining.\n", numObjects - vm->numObjects, + vm->numObjects); +} + +Object *newObject(VM* vm, ObjectType type) { + if (vm->numObjects == vm->maxObjects) { + gc(vm); + } + + Object* object = malloc(sizeof(Object)); + object->marked = 0; + object->type = type; + object->next = vm->root; + vm->root = object; + vm->numObjects++; + return object; +} + +Object* pushInt(VM* vm, int value) { + Object* object = newObject(vm, OBJ_INT); + object->value = value; + push(vm, object); + return object; +} + +Object* pushPair(VM* vm) { + Object* object = newObject(vm, OBJ_PAIR); + object->head = pop(vm); + object->tail = pop(vm); + push(vm, object); + return object; +} + +void freeVM(VM *vm) { + vm->stackSize = 0; + gc(vm); + free(vm); +} + +void objectPrint(Object* object) { + switch(object->type) { + case OBJ_INT: + printf("%d\n", object->value); + break; + + case OBJ_PAIR: + printf("("); + objectPrint(object->head); + printf(", "); + objectPrint(object->tail); + printf(")"); + break; + } +} + +void test1() { + printf("Test 1: Objects on stack are preserved.\n"); + VM* vm = newVM(); + pushInt(vm, 1); + pushInt(vm, 2); + + gc(vm); + assert(vm->numObjects == 2, "Should have preserved objects."); + freeVM(vm); +} + +void test2() { + printf("Test 2: Unreached objects are collected.\n"); + VM* vm = newVM(); + pushInt(vm, 1); + pushInt(vm, 2); + pop(vm); + pop(vm); + + gc(vm); + assert(vm->numObjects == 0, "Should have collected objects."); + freeVM(vm); +} + +void test3() { + printf("Test 3: Reach nested objects.\n"); + VM* vm = newVM(); + pushInt(vm, 1); + pushInt(vm, 2); + pushPair(vm); + pushInt(vm, 3); + pushInt(vm, 4); + pushPair(vm); + pushPair(vm); + + gc(vm); + assert(vm->numObjects == 7, "Should have reached objects."); + freeVM(vm); +} + +void test4() { + printf("Test 4: Handle cycles.\n"); + VM* vm = newVM(); + pushInt(vm, 1); + pushInt(vm, 2); + Object* a = pushPair(vm); + pushInt(vm, 3); + pushInt(vm, 4); + Object* b = pushPair(vm); + + /* Set up a cycle, and also make 2 and 4 unreachable and collectible. */ + a->tail = b; + b->tail = a; + + gc(vm); + assert(vm->numObjects == 4, "Should have collected objects."); + freeVM(vm); +} + +void perfTest() { + printf("Performance Test.\n"); + VM* vm = newVM(); + + for (int i = 0; i < 1000; i++) { + for (int j = 0; j < 20; j++) { + pushInt(vm, i); + } + + for (int k = 0; k < 20; k++) { + pop(vm); + } + } + freeVM(vm); +} + +int main(int argc, const char * argv[]) { + test1(); + test2(); + test3(); + test4(); + perfTest(); + + return 0; +} + + + + From 27d16e33bdccfb592c019b0abbf62d398ae2ee12 Mon Sep 17 00:00:00 2001 From: "Elf M. Sternberg" Date: Fri, 30 Dec 2016 09:54:30 -0800 Subject: [PATCH 2/3] Added the Mapbox files. --- src/collector.cpp | 251 ++++++ src/include/mapbox/optional.hpp | 74 ++ src/include/mapbox/recursive_wrapper.hpp | 122 +++ src/include/mapbox/variant.hpp | 1013 ++++++++++++++++++++++ src/include/mapbox/variant_io.hpp | 45 + src/include/mapbox/variant_visitor.hpp | 38 + src/marked | 0 7 files changed, 1543 insertions(+) create mode 100644 src/collector.cpp create mode 100644 src/include/mapbox/optional.hpp create mode 100644 src/include/mapbox/recursive_wrapper.hpp create mode 100644 src/include/mapbox/variant.hpp create mode 100644 src/include/mapbox/variant_io.hpp create mode 100644 src/include/mapbox/variant_visitor.hpp create mode 100644 src/marked diff --git a/src/collector.cpp b/src/collector.cpp new file mode 100644 index 0000000..df66db2 --- /dev/null +++ b/src/collector.cpp @@ -0,0 +1,251 @@ +#include + +/* 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 + +#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 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; +} diff --git a/src/include/mapbox/optional.hpp b/src/include/mapbox/optional.hpp new file mode 100644 index 0000000..d84705c --- /dev/null +++ b/src/include/mapbox/optional.hpp @@ -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 +#include + +#include + +namespace mapbox { +namespace util { + +template +class optional +{ + static_assert(!std::is_reference::value, "optional doesn't support references"); + + struct none_type + { + }; + + variant 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 const& get() const { return variant_.template get(); } + T& get() { return variant_.template get(); } + + 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 + void emplace(Args&&... args) + { + variant_ = T{std::forward(args)...}; + } + + void reset() { variant_ = none_type{}; } + +}; // class optional + +} // namespace util +} // namespace mapbox + +#endif // MAPBOX_UTIL_OPTIONAL_HPP diff --git a/src/include/mapbox/recursive_wrapper.hpp b/src/include/mapbox/recursive_wrapper.hpp new file mode 100644 index 0000000..4ffcbd7 --- /dev/null +++ b/src/include/mapbox/recursive_wrapper.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 +#include + +namespace mapbox { +namespace util { + +template +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 +inline void swap(recursive_wrapper& lhs, recursive_wrapper& rhs) noexcept +{ + lhs.swap(rhs); +} +} // namespace util +} // namespace mapbox + +#endif // MAPBOX_UTIL_RECURSIVE_WRAPPER_HPP diff --git a/src/include/mapbox/variant.hpp b/src/include/mapbox/variant.hpp new file mode 100644 index 0000000..fb0f77e --- /dev/null +++ b/src/include/mapbox/variant.hpp @@ -0,0 +1,1013 @@ +#ifndef MAPBOX_UTIL_VARIANT_HPP +#define MAPBOX_UTIL_VARIANT_HPP + +#include +#include // size_t +#include // operator new +#include // runtime_error +#include +#include +#include +#include +#include +#include + +#include +#include + +// clang-format off +// [[deprecated]] is only available in C++14, use this for the time being +#if __cplusplus <= 201103L +# ifdef __GNUC__ +# define MAPBOX_VARIANT_DEPRECATED __attribute__((deprecated)) +# elif defined(_MSC_VER) +# define MAPBOX_VARIANT_DEPRECATED __declspec(deprecated) +# else +# define MAPBOX_VARIANT_DEPRECATED +# endif +#else +# define MAPBOX_VARIANT_DEPRECATED [[deprecated]] +#endif + + +#ifdef _MSC_VER +// https://msdn.microsoft.com/en-us/library/bw1hbe6y.aspx +# ifdef NDEBUG +# define VARIANT_INLINE __forceinline +# else +# define VARIANT_INLINE //__declspec(noinline) +# endif +#else +# ifdef NDEBUG +# define VARIANT_INLINE //inline __attribute__((always_inline)) +# else +# define VARIANT_INLINE __attribute__((noinline)) +# endif +#endif +// clang-format on + +// Exceptions +#if defined( __EXCEPTIONS) || defined( _MSC_VER) +#define HAS_EXCEPTIONS +#endif + +#define VARIANT_MAJOR_VERSION 1 +#define VARIANT_MINOR_VERSION 1 +#define VARIANT_PATCH_VERSION 0 + +#define VARIANT_VERSION (VARIANT_MAJOR_VERSION * 100000) + (VARIANT_MINOR_VERSION * 100) + (VARIANT_PATCH_VERSION) + +namespace mapbox { +namespace util { + +// XXX This should derive from std::logic_error instead of std::runtime_error. +// See https://github.com/mapbox/variant/issues/48 for details. +class bad_variant_access : public std::runtime_error +{ + +public: + explicit bad_variant_access(const std::string& what_arg) + : runtime_error(what_arg) {} + + explicit bad_variant_access(const char* what_arg) + : runtime_error(what_arg) {} + +}; // class bad_variant_access + +template +struct MAPBOX_VARIANT_DEPRECATED static_visitor +{ + using result_type = R; + +protected: + static_visitor() {} + ~static_visitor() {} +}; + +namespace detail { + +static constexpr std::size_t invalid_value = std::size_t(-1); + +template +struct direct_type; + +template +struct direct_type +{ + static constexpr std::size_t index = std::is_same::value + ? sizeof...(Types) + : direct_type::index; +}; + +template +struct direct_type +{ + static constexpr std::size_t index = invalid_value; +}; + +#if __cpp_lib_logical_traits >= 201510L + +using std::disjunction; + +#else + +template +struct disjunction : std::false_type {}; + +template +struct disjunction : B1 {}; + +template +struct disjunction : std::conditional::type {}; + +template +struct disjunction : std::conditional>::type {}; + +#endif + +template +struct convertible_type; + +template +struct convertible_type +{ + static constexpr std::size_t index = std::is_convertible::value + ? disjunction...>::value ? invalid_value : sizeof...(Types) + : convertible_type::index; +}; + +template +struct convertible_type +{ + static constexpr std::size_t index = invalid_value; +}; + +template +struct value_traits +{ + using value_type = typename std::remove_const::type>::type; + static constexpr std::size_t direct_index = direct_type::index; + static constexpr bool is_direct = direct_index != invalid_value; + static constexpr std::size_t index = is_direct ? direct_index : convertible_type::index; + static constexpr bool is_valid = index != invalid_value; + static constexpr std::size_t tindex = is_valid ? sizeof...(Types)-index : 0; + using target_type = typename std::tuple_element>::type; +}; + +template +struct enable_if_type +{ + using type = R; +}; + +template +struct result_of_unary_visit +{ + using type = typename std::result_of::type; +}; + +template +struct result_of_unary_visit::type> +{ + using type = typename F::result_type; +}; + +template +struct result_of_binary_visit +{ + using type = typename std::result_of::type; +}; + +template +struct result_of_binary_visit::type> +{ + using type = typename F::result_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(const std::size_t type_index, void* data) + { + if (type_index == sizeof...(Types)) + { + reinterpret_cast(data)->~T(); + } + else + { + variant_helper::destroy(type_index, data); + } + } + + VARIANT_INLINE static void move(const std::size_t old_type_index, void* old_value, void* new_value) + { + if (old_type_index == sizeof...(Types)) + { + new (new_value) T(std::move(*reinterpret_cast(old_value))); + } + else + { + variant_helper::move(old_type_index, old_value, new_value); + } + } + + VARIANT_INLINE static void copy(const std::size_t old_type_index, const void* old_value, void* new_value) + { + if (old_type_index == sizeof...(Types)) + { + new (new_value) T(*reinterpret_cast(old_value)); + } + else + { + variant_helper::copy(old_type_index, old_value, new_value); + } + } +}; + +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*) {} +}; + +template +struct unwrapper +{ + static T const& apply_const(T const& obj) { return obj; } + static T& apply(T& obj) { return obj; } +}; + +template +struct unwrapper> +{ + static auto apply_const(recursive_wrapper const& obj) + -> typename recursive_wrapper::type const& + { + return obj.get(); + } + static auto apply(recursive_wrapper& obj) + -> typename recursive_wrapper::type& + { + return obj.get(); + } +}; + +template +struct unwrapper> +{ + static auto apply_const(std::reference_wrapper const& obj) + -> typename std::reference_wrapper::type const& + { + return obj.get(); + } + static auto apply(std::reference_wrapper& obj) + -> typename std::reference_wrapper::type& + { + return obj.get(); + } +}; + +template +struct dispatcher; + +template +struct dispatcher +{ + VARIANT_INLINE static R apply_const(V const& v, F&& f) + { + if (v.template is()) + { + return f(unwrapper::apply_const(v.template get_unchecked())); + } + else + { + return dispatcher::apply_const(v, std::forward(f)); + } + } + + VARIANT_INLINE static R apply(V& v, F&& f) + { + if (v.template is()) + { + return f(unwrapper::apply(v.template get_unchecked())); + } + else + { + return dispatcher::apply(v, std::forward(f)); + } + } +}; + +template +struct dispatcher +{ + VARIANT_INLINE static R apply_const(V const& v, F&& f) + { + return f(unwrapper::apply_const(v.template get_unchecked())); + } + + VARIANT_INLINE static R apply(V& v, F&& f) + { + return f(unwrapper::apply(v.template get_unchecked())); + } +}; + +template +struct binary_dispatcher_rhs; + +template +struct binary_dispatcher_rhs +{ + VARIANT_INLINE static R apply_const(V const& lhs, V const& rhs, F&& f) + { + if (rhs.template is()) // call binary functor + { + return f(unwrapper::apply_const(lhs.template get_unchecked()), + unwrapper::apply_const(rhs.template get_unchecked())); + } + else + { + return binary_dispatcher_rhs::apply_const(lhs, rhs, std::forward(f)); + } + } + + VARIANT_INLINE static R apply(V& lhs, V& rhs, F&& f) + { + if (rhs.template is()) // call binary functor + { + return f(unwrapper::apply(lhs.template get_unchecked()), + unwrapper::apply(rhs.template get_unchecked())); + } + else + { + return binary_dispatcher_rhs::apply(lhs, rhs, std::forward(f)); + } + } +}; + +template +struct binary_dispatcher_rhs +{ + VARIANT_INLINE static R apply_const(V const& lhs, V const& rhs, F&& f) + { + return f(unwrapper::apply_const(lhs.template get_unchecked()), + unwrapper::apply_const(rhs.template get_unchecked())); + } + + VARIANT_INLINE static R apply(V& lhs, V& rhs, F&& f) + { + return f(unwrapper::apply(lhs.template get_unchecked()), + unwrapper::apply(rhs.template get_unchecked())); + } +}; + +template +struct binary_dispatcher_lhs; + +template +struct binary_dispatcher_lhs +{ + VARIANT_INLINE static R apply_const(V const& lhs, V const& rhs, F&& f) + { + if (lhs.template is()) // call binary functor + { + return f(unwrapper::apply_const(lhs.template get_unchecked()), + unwrapper::apply_const(rhs.template get_unchecked())); + } + else + { + return binary_dispatcher_lhs::apply_const(lhs, rhs, std::forward(f)); + } + } + + VARIANT_INLINE static R apply(V& lhs, V& rhs, F&& f) + { + if (lhs.template is()) // call binary functor + { + return f(unwrapper::apply(lhs.template get_unchecked()), + unwrapper::apply(rhs.template get_unchecked())); + } + else + { + return binary_dispatcher_lhs::apply(lhs, rhs, std::forward(f)); + } + } +}; + +template +struct binary_dispatcher_lhs +{ + VARIANT_INLINE static R apply_const(V const& lhs, V const& rhs, F&& f) + { + return f(unwrapper::apply_const(lhs.template get_unchecked()), + unwrapper::apply_const(rhs.template get_unchecked())); + } + + VARIANT_INLINE static R apply(V& lhs, V& rhs, F&& f) + { + return f(unwrapper::apply(lhs.template get_unchecked()), + unwrapper::apply(rhs.template get_unchecked())); + } +}; + +template +struct binary_dispatcher; + +template +struct binary_dispatcher +{ + VARIANT_INLINE static R apply_const(V const& v0, V const& v1, F&& f) + { + if (v0.template is()) + { + if (v1.template is()) + { + return f(unwrapper::apply_const(v0.template get_unchecked()), + unwrapper::apply_const(v1.template get_unchecked())); // call binary functor + } + else + { + return binary_dispatcher_rhs::apply_const(v0, v1, std::forward(f)); + } + } + else if (v1.template is()) + { + return binary_dispatcher_lhs::apply_const(v0, v1, std::forward(f)); + } + return binary_dispatcher::apply_const(v0, v1, std::forward(f)); + } + + VARIANT_INLINE static R apply(V& v0, V& v1, F&& f) + { + if (v0.template is()) + { + if (v1.template is()) + { + return f(unwrapper::apply(v0.template get_unchecked()), + unwrapper::apply(v1.template get_unchecked())); // call binary functor + } + else + { + return binary_dispatcher_rhs::apply(v0, v1, std::forward(f)); + } + } + else if (v1.template is()) + { + return binary_dispatcher_lhs::apply(v0, v1, std::forward(f)); + } + return binary_dispatcher::apply(v0, v1, std::forward(f)); + } +}; + +template +struct binary_dispatcher +{ + VARIANT_INLINE static R apply_const(V const& v0, V const& v1, F&& f) + { + return f(unwrapper::apply_const(v0.template get_unchecked()), + unwrapper::apply_const(v1.template get_unchecked())); // call binary functor + } + + VARIANT_INLINE static R apply(V& v0, V& v1, F&& f) + { + return f(unwrapper::apply(v0.template get_unchecked()), + unwrapper::apply(v1.template get_unchecked())); // call binary functor + } +}; + +// comparator functors +struct equal_comp +{ + template + bool operator()(T const& lhs, T const& rhs) const + { + return lhs == rhs; + } +}; + +struct less_comp +{ + template + bool operator()(T const& lhs, T const& rhs) const + { + return lhs < rhs; + } +}; + +template +class comparer +{ +public: + explicit comparer(Variant const& lhs) noexcept + : lhs_(lhs) {} + comparer& operator=(comparer const&) = delete; + // visitor + template + bool operator()(T const& rhs_content) const + { + T const& lhs_content = lhs_.template get_unchecked(); + return Comp()(lhs_content, rhs_content); + } + +private: + Variant const& lhs_; +}; + +// hashing visitor +struct hasher +{ + template + std::size_t operator()(const T& hashable) const + { + return std::hash{}(hashable); + } +}; + +} // namespace detail + +struct no_init +{ +}; + +template +class variant +{ + static_assert(sizeof...(Types) > 0, "Template parameter type list of variant can not be empty"); + static_assert(!detail::disjunction...>::value, "Variant can not hold reference types. Maybe use std::reference_wrapper?"); + +private: + static const std::size_t data_size = detail::static_max::value; + static const std::size_t data_align = detail::static_max::value; +public: + struct adapted_variant_tag; + using types = std::tuple; +private: + using first_type = typename std::tuple_element<0, types>::type; + using data_type = typename std::aligned_storage::type; + using helper_type = detail::variant_helper; + + std::size_t type_index; + data_type data; + +public: + VARIANT_INLINE variant() noexcept(std::is_nothrow_default_constructible::value) + : type_index(sizeof...(Types)-1) + { + static_assert(std::is_default_constructible::value, "First type in variant must be default constructible to allow default construction of variant"); + new (&data) first_type(); + } + + VARIANT_INLINE variant(no_init) noexcept + : type_index(detail::invalid_value) {} + + // http://isocpp.org/blog/2012/11/universal-references-in-c11-scott-meyers + template , + typename Enable = typename std::enable_if, typename Traits::value_type>::value>::type > + VARIANT_INLINE variant(T&& val) noexcept(std::is_nothrow_constructible::value) + : type_index(Traits::index) + { + new (&data) typename Traits::target_type(std::forward(val)); + } + + VARIANT_INLINE variant(variant const& old) + : type_index(old.type_index) + { + helper_type::copy(old.type_index, &old.data, &data); + } + + VARIANT_INLINE variant(variant&& old) noexcept(std::is_nothrow_move_constructible::value) + : type_index(old.type_index) + { + helper_type::move(old.type_index, &old.data, &data); + } + +private: + VARIANT_INLINE void copy_assign(variant const& rhs) + { + helper_type::destroy(type_index, &data); + type_index = detail::invalid_value; + helper_type::copy(rhs.type_index, &rhs.data, &data); + type_index = rhs.type_index; + } + + VARIANT_INLINE void move_assign(variant&& rhs) + { + helper_type::destroy(type_index, &data); + type_index = detail::invalid_value; + helper_type::move(rhs.type_index, &rhs.data, &data); + type_index = rhs.type_index; + } + +public: + VARIANT_INLINE variant& operator=(variant&& other) + { + move_assign(std::move(other)); + return *this; + } + + VARIANT_INLINE variant& operator=(variant const& other) + { + copy_assign(other); + return *this; + } + + // conversions + // move-assign + template + VARIANT_INLINE variant& operator=(T&& rhs) noexcept + { + variant temp(std::forward(rhs)); + move_assign(std::move(temp)); + return *this; + } + + // copy-assign + template + VARIANT_INLINE variant& operator=(T const& rhs) + { + variant temp(rhs); + copy_assign(temp); + return *this; + } + + template ::index != detail::invalid_value)>::type* = nullptr> + VARIANT_INLINE bool is() const + { + return type_index == detail::direct_type::index; + } + + template , Types...>::index != detail::invalid_value)>::type* = nullptr> + VARIANT_INLINE bool is() const + { + return type_index == detail::direct_type, Types...>::index; + } + + VARIANT_INLINE bool valid() const + { + return type_index != detail::invalid_value; + } + + template + VARIANT_INLINE void set(Args&&... args) + { + helper_type::destroy(type_index, &data); + type_index = detail::invalid_value; + new (&data) T(std::forward(args)...); + type_index = detail::direct_type::index; + } + + // get_unchecked() + template ::index != detail::invalid_value)>::type* = nullptr> + VARIANT_INLINE T& get_unchecked() + { + return *reinterpret_cast(&data); + } + +#ifdef HAS_EXCEPTIONS + // get() + template ::index != detail::invalid_value)>::type* = nullptr> + VARIANT_INLINE T& get() + { + if (type_index == detail::direct_type::index) + { + return *reinterpret_cast(&data); + } + else + { + throw bad_variant_access("in get()"); + } + } +#endif + + template ::index != detail::invalid_value)>::type* = nullptr> + VARIANT_INLINE T const& get_unchecked() const + { + return *reinterpret_cast(&data); + } + +#ifdef HAS_EXCEPTIONS + template ::index != detail::invalid_value)>::type* = nullptr> + VARIANT_INLINE T const& get() const + { + if (type_index == detail::direct_type::index) + { + return *reinterpret_cast(&data); + } + else + { + throw bad_variant_access("in get()"); + } + } +#endif + + // get_unchecked() - T stored as recursive_wrapper + template , Types...>::index != detail::invalid_value)>::type* = nullptr> + VARIANT_INLINE T& get_unchecked() + { + return (*reinterpret_cast*>(&data)).get(); + } + +#ifdef HAS_EXCEPTIONS + // get() - T stored as recursive_wrapper + template , Types...>::index != detail::invalid_value)>::type* = nullptr> + VARIANT_INLINE T& get() + { + if (type_index == detail::direct_type, Types...>::index) + { + return (*reinterpret_cast*>(&data)).get(); + } + else + { + throw bad_variant_access("in get()"); + } + } +#endif + + template , Types...>::index != detail::invalid_value)>::type* = nullptr> + VARIANT_INLINE T const& get_unchecked() const + { + return (*reinterpret_cast const*>(&data)).get(); + } + +#ifdef HAS_EXCEPTIONS + template , Types...>::index != detail::invalid_value)>::type* = nullptr> + VARIANT_INLINE T const& get() const + { + if (type_index == detail::direct_type, Types...>::index) + { + return (*reinterpret_cast const*>(&data)).get(); + } + else + { + throw bad_variant_access("in get()"); + } + } +#endif + + // get_unchecked() - T stored as std::reference_wrapper + template , Types...>::index != detail::invalid_value)>::type* = nullptr> + VARIANT_INLINE T& get_unchecked() + { + return (*reinterpret_cast*>(&data)).get(); + } + +#ifdef HAS_EXCEPTIONS + // get() - T stored as std::reference_wrapper + template , Types...>::index != detail::invalid_value)>::type* = nullptr> + VARIANT_INLINE T& get() + { + if (type_index == detail::direct_type, Types...>::index) + { + return (*reinterpret_cast*>(&data)).get(); + } + else + { + throw bad_variant_access("in get()"); + } + } +#endif + + template , Types...>::index != detail::invalid_value)>::type* = nullptr> + VARIANT_INLINE T const& get_unchecked() const + { + return (*reinterpret_cast const*>(&data)).get(); + } + +#ifdef HAS_EXCEPTIONS + template , Types...>::index != detail::invalid_value)>::type* = nullptr> + VARIANT_INLINE T const& get() const + { + if (type_index == detail::direct_type, Types...>::index) + { + return (*reinterpret_cast const*>(&data)).get(); + } + else + { + throw bad_variant_access("in get()"); + } + } +#endif + + // This function is deprecated because it returns an internal index field. + // Use which() instead. + MAPBOX_VARIANT_DEPRECATED VARIANT_INLINE std::size_t get_type_index() const + { + return type_index; + } + + VARIANT_INLINE int which() const noexcept + { + return static_cast(sizeof...(Types)-type_index - 1); + } + + template ::index != detail::invalid_value)>::type* = nullptr> + VARIANT_INLINE static constexpr int which() noexcept + { + return static_cast(sizeof...(Types)-detail::direct_type::index - 1); + } + + // visitor + // unary + template ::type> + auto VARIANT_INLINE static visit(V const& v, F&& f) + -> decltype(detail::dispatcher::apply_const(v, std::forward(f))) + { + return detail::dispatcher::apply_const(v, std::forward(f)); + } + // non-const + template ::type> + auto VARIANT_INLINE static visit(V& v, F&& f) + -> decltype(detail::dispatcher::apply(v, std::forward(f))) + { + return detail::dispatcher::apply(v, std::forward(f)); + } + + // binary + // const + template ::type> + auto VARIANT_INLINE static binary_visit(V const& v0, V const& v1, F&& f) + -> decltype(detail::binary_dispatcher::apply_const(v0, v1, std::forward(f))) + { + return detail::binary_dispatcher::apply_const(v0, v1, std::forward(f)); + } + // non-const + template ::type> + auto VARIANT_INLINE static binary_visit(V& v0, V& v1, F&& f) + -> decltype(detail::binary_dispatcher::apply(v0, v1, std::forward(f))) + { + return detail::binary_dispatcher::apply(v0, v1, std::forward(f)); + } + + // match + // unary + template + auto VARIANT_INLINE match(Fs&&... fs) const + -> decltype(variant::visit(*this, ::mapbox::util::make_visitor(std::forward(fs)...))) + { + return variant::visit(*this, ::mapbox::util::make_visitor(std::forward(fs)...)); + } + // non-const + template + auto VARIANT_INLINE match(Fs&&... fs) + -> decltype(variant::visit(*this, ::mapbox::util::make_visitor(std::forward(fs)...))) + { + return variant::visit(*this, ::mapbox::util::make_visitor(std::forward(fs)...)); + } + + ~variant() noexcept // no-throw destructor + { + helper_type::destroy(type_index, &data); + } + + // comparison operators + // equality + VARIANT_INLINE bool operator==(variant const& rhs) const + { + assert(valid() && rhs.valid()); + if (this->which() != rhs.which()) + { + return false; + } + detail::comparer visitor(*this); + return visit(rhs, visitor); + } + + VARIANT_INLINE bool operator!=(variant const& rhs) const + { + return !(*this == rhs); + } + + // less than + VARIANT_INLINE bool operator<(variant const& rhs) const + { + assert(valid() && rhs.valid()); + if (this->which() != rhs.which()) + { + return this->which() < rhs.which(); + } + detail::comparer visitor(*this); + return visit(rhs, visitor); + } + VARIANT_INLINE bool operator>(variant const& rhs) const + { + return rhs < *this; + } + VARIANT_INLINE bool operator<=(variant const& rhs) const + { + return !(*this > rhs); + } + VARIANT_INLINE bool operator>=(variant const& rhs) const + { + return !(*this < rhs); + } +}; + +// unary visitor interface +// const +template +auto VARIANT_INLINE apply_visitor(F&& f, V const& v) -> decltype(V::visit(v, std::forward(f))) +{ + return V::visit(v, std::forward(f)); +} + +// non-const +template +auto VARIANT_INLINE apply_visitor(F&& f, V& v) -> decltype(V::visit(v, std::forward(f))) +{ + return V::visit(v, std::forward(f)); +} + +// binary visitor interface +// const +template +auto VARIANT_INLINE apply_visitor(F&& f, V const& v0, V const& v1) -> decltype(V::binary_visit(v0, v1, std::forward(f))) +{ + return V::binary_visit(v0, v1, std::forward(f)); +} + +// non-const +template +auto VARIANT_INLINE apply_visitor(F&& f, V& v0, V& v1) -> decltype(V::binary_visit(v0, v1, std::forward(f))) +{ + return V::binary_visit(v0, v1, std::forward(f)); +} + +// getter interface + +#ifdef HAS_EXCEPTIONS +template +auto get(T& var)->decltype(var.template get()) +{ + return var.template get(); +} +#endif + +template +ResultType& get_unchecked(T& var) +{ + return var.template get_unchecked(); +} + +#ifdef HAS_EXCEPTIONS +template +auto get(T const& var)->decltype(var.template get()) +{ + return var.template get(); +} +#endif + +template +ResultType const& get_unchecked(T const& var) +{ + return var.template get_unchecked(); +} +} // namespace util +} // namespace mapbox + +// hashable iff underlying types are hashable +namespace std { +template +struct hash< ::mapbox::util::variant> { + std::size_t operator()(const ::mapbox::util::variant& v) const noexcept + { + return ::mapbox::util::apply_visitor(::mapbox::util::detail::hasher{}, v); + } +}; +} + +#endif // MAPBOX_UTIL_VARIANT_HPP diff --git a/src/include/mapbox/variant_io.hpp b/src/include/mapbox/variant_io.hpp new file mode 100644 index 0000000..1456cc5 --- /dev/null +++ b/src/include/mapbox/variant_io.hpp @@ -0,0 +1,45 @@ +#ifndef MAPBOX_UTIL_VARIANT_IO_HPP +#define MAPBOX_UTIL_VARIANT_IO_HPP + +#include + +#include + +namespace mapbox { +namespace util { + +namespace detail { +// operator<< helper +template +class printer +{ +public: + explicit printer(Out& out) + : out_(out) {} + printer& operator=(printer const&) = delete; + + // visitor + template + void operator()(T const& operand) const + { + out_ << operand; + } + +private: + Out& out_; +}; +} + +// operator<< +template +VARIANT_INLINE std::basic_ostream& +operator<<(std::basic_ostream& out, variant const& rhs) +{ + detail::printer> visitor(out); + apply_visitor(visitor, rhs); + return out; +} +} // namespace util +} // namespace mapbox + +#endif // MAPBOX_UTIL_VARIANT_IO_HPP diff --git a/src/include/mapbox/variant_visitor.hpp b/src/include/mapbox/variant_visitor.hpp new file mode 100644 index 0000000..481eb65 --- /dev/null +++ b/src/include/mapbox/variant_visitor.hpp @@ -0,0 +1,38 @@ +#ifndef MAPBOX_UTIL_VARIANT_VISITOR_HPP +#define MAPBOX_UTIL_VARIANT_VISITOR_HPP + +namespace mapbox { +namespace util { + +template +struct visitor; + +template +struct visitor : Fn +{ + using type = Fn; + using Fn::operator(); + + visitor(Fn fn) : Fn(fn) {} +}; + +template +struct visitor : Fn, visitor +{ + using type = visitor; + using Fn::operator(); + using visitor::operator(); + + visitor(Fn fn, Fns... fns) : Fn(fn), visitor(fns...) {} +}; + +template +visitor make_visitor(Fns... fns) +{ + return visitor(fns...); +} + +} // namespace util +} // namespace mapbox + +#endif // MAPBOX_UTIL_VARIANT_VISITOR_HPP diff --git a/src/marked b/src/marked new file mode 100644 index 0000000..e69de29 From 9635a253f53f197c5cbcc871d1e8ef477941b030 Mon Sep 17 00:00:00 2001 From: "Elf M. Sternberg" Date: Fri, 30 Dec 2016 10:47:42 -0800 Subject: [PATCH 3/3] Updated with README and stuff. --- CMakeLists.txt | 5 ++- README.md | 65 ++++++++++++++++++++++++++++++++++++++ src/collector.cpp | 9 +++--- src/include/mapbox/LICENSE | 25 +++++++++++++++ src/marked | 0 5 files changed, 97 insertions(+), 7 deletions(-) create mode 100644 README.md create mode 100644 src/include/mapbox/LICENSE delete mode 100644 src/marked diff --git a/CMakeLists.txt b/CMakeLists.txt index 802a300..ab467c9 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,7 +1,6 @@ project("Collector") -list(APPEND CMAKE_C_FLAGS "-std=c99 ${CMAKE_C_FLAGS} -g -ftest-coverage -fprofile-arcs") +list(APPEND CMAKE_CXX_FLAGS "${CXXMAKE_C_FLAGS} -std=c++1y -I../src/include/ -g") -add_executable(collector - src/collector.c) +add_executable(collector src/collector.cpp) diff --git a/README.md b/README.md new file mode 100644 index 0000000..f85eaf3 --- /dev/null +++ b/README.md @@ -0,0 +1,65 @@ +--- +**WHAT:** + +This is an example of Bob Nystrom's +"[Baby's First Garbage Collector](http://journal.stuffwithstuff.com/2013/12/08/babys-first-garbage-collector/)," +which I've been wanting to implement for a while in order to understand +it better. To make the problem harder (as I always do), I decided to +write it in C++, and to make it even more fun, I've implemented it using +the new Variant container from C++17. + +**WHY:** + +I've never written a garbage collector before. Now I know what it is +and how it works. + +**DETAILS:** + +The collector Nystrom wrote is a simple bi-color mark-and-sweep +collector for a singly threaded process with distinct pauses based upon +a straightforward memory usage heuristic. That heuristic is simply, "Is +the amount of memory currently in use twice as much as the last time we +garbage collected?" If the answer is yes, the collector runs and sweeps +up the stack. + +Nystrom's code is highly readable, and I hope mine is as well. Because +I used Variant, my Object class has an internal Pair class, and then the +Variant is just \, where "Pair" is a pair of pointers to +other objects. The entirety of the VM is basically a stack of +singly-linked lists which either represents integers or collections of +integers in a Lisp-like structure. + +The allocator creates two kinds of objects, then: pairs, and lists. A +pair is created by pushing two other objects onto the stack, then +calling `push()`, which pops them off the stack and replaces them with a +Pair object. The VM class has two methods, both named `push()`, one of +which pushes an integer, the other a pair. Since a pair is built from +objects on the stack, the Pair version takes no arguments, and since +C++14 and beyond have move semantics that Variant honors, +Variant\ only constructs a single pair. Pretty nice. I was also +able to use both lambda-style and constructor-style visitors in my +Variant, which was a fun little bonus. + +**NOTE:** + +I have included the header files for the +[Mapbox version of Variant](https://github.com/mapbox/variant) since the +C++17 committee's standards haven't quite reached the general public and +the Variant implementation is still a subject of some debate. This +implementation looks straightforward enough and is a header-only +release. It works with both GCC 4.8.5 and Clang 3.8, and that's good +enough for me. + +The Mapbox variant is BSD licensed, and a copy of the license is +included in the Include directory. + +**BUILDING:** + +From the base directory of the project: + +mkdir build +cd build +cmake .. +make + +And you should be able to run the basic tests. It's just one file. diff --git a/src/collector.cpp b/src/collector.cpp index df66db2..2be9145 100644 --- a/src/collector.cpp +++ b/src/collector.cpp @@ -37,6 +37,7 @@ public: unsigned char marked; Object *next; Object(int v): marked(0), value(v) {} + // Variant uses move semantics; this doesn't result in Pair being built twice. Object(Object* head, Object* tail): marked(0), value(Pair(head, tail)) {} class Pair { @@ -113,10 +114,10 @@ public: /* 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. */ + Optional or Either-variant, because to use those I'd have to use + 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? */ diff --git a/src/include/mapbox/LICENSE b/src/include/mapbox/LICENSE new file mode 100644 index 0000000..6c4ce40 --- /dev/null +++ b/src/include/mapbox/LICENSE @@ -0,0 +1,25 @@ +Copyright (c) MapBox +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +- Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright notice, this + list of conditions and the following disclaimer in the documentation and/or + other materials provided with the distribution. +- Neither the name "MapBox" nor the names of its contributors may be + used to endorse or promote products derived from this software without + specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. \ No newline at end of file diff --git a/src/marked b/src/marked deleted file mode 100644 index e69de29..0000000