Last active
August 29, 2015 14:02
-
-
Save g-pechorin/928d12d6e6e15440f540 to your computer and use it in GitHub Desktop.
fun with ram
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* 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