Skip to content

Commit

Permalink
Add C++ header with std::allocator implementation.
Browse files Browse the repository at this point in the history
  • Loading branch information
TravisWhitaker committed Feb 22, 2020
1 parent 73ff608 commit c5b0310
Show file tree
Hide file tree
Showing 4 changed files with 108 additions and 1 deletion.
42 changes: 41 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,2 +1,42 @@
# libglaswegian
Use GHC's Memory Allocator from C

Use GHC's Memory Allocator from C/C++. Yes, I'm serious. You can do this:

```c++
#include <iostream>
#include <vector>

#include <glaswegian++.h>

#define LEN 4096

int main()
{
ghc_init();
std::vector<double, GlaswegianAllocator<double>> xs;
for(int i = 0; i < LEN; i++)
{
xs.emplace_back(i * i);
}
double s = 0;
for(double i : xs)
{
s += i;
}
std::cout << s << std::endl;
return 0;
}
```

This works by allocating pinned `MutableByteArray#`s, then sticking a
`StablePtr` into a radix tree with the `MutableByteArray#`'s address as the key.
This keeps the array alive on the heap until the caller frees the memory (which
just deletes the `StablePtr` from the tree and does `freeStablePtr`).

A further optimization might be to call the RTS' C functions for doing
allocations directly, but this library is *shockingly* competitive with other
memory allocators. I'll add benchmarks soon.

This library is a fun toy I made for some silly benchmarks I wanted to run. It
is probably only useful for getting your colleagues to shut up about how
"garbage collectors are slow."
43 changes: 43 additions & 0 deletions include/glaswegian++.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
#include <limits>

extern "C"
{
#include <glaswegian.h>
};

// Call ghc_init before constructing one of these.
template <typename a>
struct GlaswegianAllocator
{
typedef a value_type;

GlaswegianAllocator() = default;

a* allocate(std::size_t n)
{
if(n > std::numeric_limits<std::size_t>::max() / sizeof(a))
{
throw std::bad_alloc();
}
if(auto p = static_cast<a*>(ghc_alloc(n*sizeof(a))))
{
return p;
}
throw std::bad_alloc();
}
void deallocate(a* p, std::size_t) noexcept
{
ghc_free(p);
}
};

template <typename a, typename b>
bool operator==(const GlaswegianAllocator<a>&, const GlaswegianAllocator<b>&)
{
return true;
}
template <typename a, typename b>
bool operator!=(const GlaswegianAllocator<a>&, const GlaswegianAllocator<b>&)
{
return false;
}
1 change: 1 addition & 0 deletions libglaswegian.cabal
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ foreign-library glaswegian
cbits/ghc_cleanup.c
include-dirs: include
install-includes: glaswegian.h
glaswegian++.h
ghc-options: -O2
-threaded
-Wall
Expand Down
23 changes: 23 additions & 0 deletions test/main.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
#include <iostream>
#include <vector>

#include <glaswegian++.h>

#define LEN 4096

int main()
{
ghc_init();
std::vector<double, GlaswegianAllocator<double>> xs;
for(int i = 0; i < LEN; i++)
{
xs.emplace_back(i * i);
}
double s = 0;
for(double i : xs)
{
s += i;
}
std::cout << s << std::endl;
return 0;
}

0 comments on commit c5b0310

Please sign in to comment.