Skip to content

Commit c5b0310

Browse files
Add C++ header with std::allocator implementation.
1 parent 73ff608 commit c5b0310

File tree

4 files changed

+108
-1
lines changed

4 files changed

+108
-1
lines changed

README.md

+41-1
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,42 @@
11
# libglaswegian
2-
Use GHC's Memory Allocator from C
2+
3+
Use GHC's Memory Allocator from C/C++. Yes, I'm serious. You can do this:
4+
5+
```c++
6+
#include <iostream>
7+
#include <vector>
8+
9+
#include <glaswegian++.h>
10+
11+
#define LEN 4096
12+
13+
int main()
14+
{
15+
ghc_init();
16+
std::vector<double, GlaswegianAllocator<double>> xs;
17+
for(int i = 0; i < LEN; i++)
18+
{
19+
xs.emplace_back(i * i);
20+
}
21+
double s = 0;
22+
for(double i : xs)
23+
{
24+
s += i;
25+
}
26+
std::cout << s << std::endl;
27+
return 0;
28+
}
29+
```
30+
31+
This works by allocating pinned `MutableByteArray#`s, then sticking a
32+
`StablePtr` into a radix tree with the `MutableByteArray#`'s address as the key.
33+
This keeps the array alive on the heap until the caller frees the memory (which
34+
just deletes the `StablePtr` from the tree and does `freeStablePtr`).
35+
36+
A further optimization might be to call the RTS' C functions for doing
37+
allocations directly, but this library is *shockingly* competitive with other
38+
memory allocators. I'll add benchmarks soon.
39+
40+
This library is a fun toy I made for some silly benchmarks I wanted to run. It
41+
is probably only useful for getting your colleagues to shut up about how
42+
"garbage collectors are slow."

include/glaswegian++.h

+43
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
#include <limits>
2+
3+
extern "C"
4+
{
5+
#include <glaswegian.h>
6+
};
7+
8+
// Call ghc_init before constructing one of these.
9+
template <typename a>
10+
struct GlaswegianAllocator
11+
{
12+
typedef a value_type;
13+
14+
GlaswegianAllocator() = default;
15+
16+
a* allocate(std::size_t n)
17+
{
18+
if(n > std::numeric_limits<std::size_t>::max() / sizeof(a))
19+
{
20+
throw std::bad_alloc();
21+
}
22+
if(auto p = static_cast<a*>(ghc_alloc(n*sizeof(a))))
23+
{
24+
return p;
25+
}
26+
throw std::bad_alloc();
27+
}
28+
void deallocate(a* p, std::size_t) noexcept
29+
{
30+
ghc_free(p);
31+
}
32+
};
33+
34+
template <typename a, typename b>
35+
bool operator==(const GlaswegianAllocator<a>&, const GlaswegianAllocator<b>&)
36+
{
37+
return true;
38+
}
39+
template <typename a, typename b>
40+
bool operator!=(const GlaswegianAllocator<a>&, const GlaswegianAllocator<b>&)
41+
{
42+
return false;
43+
}

libglaswegian.cabal

+1
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ foreign-library glaswegian
2727
cbits/ghc_cleanup.c
2828
include-dirs: include
2929
install-includes: glaswegian.h
30+
glaswegian++.h
3031
ghc-options: -O2
3132
-threaded
3233
-Wall

test/main.cc

+23
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
#include <iostream>
2+
#include <vector>
3+
4+
#include <glaswegian++.h>
5+
6+
#define LEN 4096
7+
8+
int main()
9+
{
10+
ghc_init();
11+
std::vector<double, GlaswegianAllocator<double>> xs;
12+
for(int i = 0; i < LEN; i++)
13+
{
14+
xs.emplace_back(i * i);
15+
}
16+
double s = 0;
17+
for(double i : xs)
18+
{
19+
s += i;
20+
}
21+
std::cout << s << std::endl;
22+
return 0;
23+
}

0 commit comments

Comments
 (0)