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