Skip to content

Instantly share code, notes, and snippets.

@g-pechorin
Last active August 29, 2015 14:02
Show Gist options
  • Save g-pechorin/928d12d6e6e15440f540 to your computer and use it in GitHub Desktop.
Save g-pechorin/928d12d6e6e15440f540 to your computer and use it in GitHub Desktop.
fun with ram
/**
* Copyright and all glory to Peter LaValle / gPechorin
*
* This little joke is what C++ is good for ; memory acrobatics.
* This demonstrates (what I'm naming) a "kitty pointer"
* (I started it as shrimp_pointer but I decided no-one would care about mantis-shrimp)
* (someone else probably has a much more serious version of this somewhere)
*
* The thought process went;
* - I want to serialise wads of data
* - My dinner is tasty
* - I want lumps of data (within the wads) to point to eachother
* - I don't want to adjust my pointers after serialisation
* - I sure do with I had some cake to go with this bolognese
* - Can't I store the relative offsets and use a template class to jump from the offset to the desired location?
*
* It's endian dependant (so no using it on the Cell/PS3/360 without a bit of work)
* Probably exists in something like GOAL or D(ata)C(ompilation)
* Most likely slower than real-man's pointers while being disgustingly fast compared to parsing data
* Don't you f!@king dare send these across the network!
*/
#include <cstdint>
#include <vector>
#include <iostream>
template<typename T, typename S>
struct kitty_pointer
{
S _offset;
void operator =(T* ptr)
{
if ( ptr == nullptr)
{
_offset = 0;
}
else
{
const size_t target = (size_t)ptr;
const size_t begin = (size_t)this;
_offset = (S)(target - begin);
}
}
T* get(void) const
{
const size_t offset = (size_t) _offset;
uint8_t* cast = (uint8_t*) this;
return _offset != 0x0000 ? (T*)(cast + offset) : nullptr;
}
T& operator*(void) const
{
return get()[0];
}
T& operator ->(void) const
{
return get()[0];
}
};
struct data
{
kitty_pointer<char,uint16_t> _name;
kitty_pointer<struct data,uint16_t> _next;
};
int main(const int argc, const char* argv[])
{
std::vector<char> buffer;
buffer.resize(sizeof(data));
buffer.push_back('P');
buffer.push_back('e');
buffer.push_back('t');
buffer.push_back('e');
buffer.push_back('r');
buffer.push_back('\0');
((data*)&(buffer[0]))->_name = &( buffer[sizeof(data)]);
((data*)&(buffer[0]))->_next = nullptr;
std::cout << "@" << ((size_t)&(buffer[0])) << "\n";
std::cout << ((data*)&(buffer[0]))->_name.get() << "\n";
const size_t niki = buffer.size();
buffer.resize(niki + sizeof(data));
buffer.push_back('J');
buffer.push_back('e');
buffer.push_back('a');
buffer.push_back('n');
buffer.push_back('n');
buffer.push_back('e');
buffer.push_back('\0');
((data*)&(buffer[0]))->_next = (data*)&(buffer[niki]);
((data*)&(buffer[niki]))->_next = nullptr;
((data*)&(buffer[niki]))->_name = &(buffer[niki + sizeof(data)]);
// Imagine that the buffer was written to disk and then loaded in another program
data* ptr = (data*)&(buffer[0]);
std::cout << "@" << (size_t)ptr << "\n";
for (data* i = ((data*)&(buffer[0])); i != nullptr; i = i->_next.get())
{
std::cout << ">" << i->_name.get() << "<\n";
}
return EXIT_SUCCESS;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment