Skip to content

Instantly share code, notes, and snippets.

@tejacques
Last active August 10, 2016 01:27
Show Gist options
  • Save tejacques/5e3ab14de6d638832810cf73e2098d0f to your computer and use it in GitHub Desktop.
Save tejacques/5e3ab14de6d638832810cf73e2098d0f to your computer and use it in GitHub Desktop.
TypeSafe object loader
#include <stdio.h>
#include <vector>
using std::vector;
enum UserFlags {
BASICS = 0x1,
LOCATION = 0x2
};
class User {
public:
int userid;
};
class UserBasics {
public:
static const UserFlags flag = UserFlags::BASICS;
int name;
int age;
bool loaded;
UserBasics() : name(0xdeadbeef), age(18), loaded(false) {}
static void load(UserBasics& userBasics) {}
};
class UserLocation {
public:
static const UserFlags flag = UserFlags::LOCATION;
int city;
bool loaded;
UserLocation() : city(0xbeefbeef), loaded(false) {}
static void load(UserLocation& userLocation) {}
};
inline UserFlags operator|(UserFlags a, UserFlags b) {
return UserFlags(int(a) | int(b));
}
template<class Built, class T, class ...Types>
void loadTypes(Built& built);
template<class ...Types>
class Builder;
template<class ToRemove, class T, class ...Types>
struct Demolisher {
using type = typename std::conditional<
std::is_same<ToRemove, T>::value,
Builder<Types...>,
Builder<T, Types...>
>::type;
};
template<class ...Types>
class Builder {
public:
template<class U>
Builder<U, Types...> load() {
Builder<U, Types...> result;
result.flags = this->flags | U::flag;
return result;
}
class Built: public User, public Types... {
public:
template<class T>
typename Demolisher<T, Types...>::type without()
{
typename Demolisher<T, Types...>::type result;
return result;
}
};
Built load(int userid) {
Built result;
result.userid = userid;
loadTypes<Built, Types...>(result);
return result;
}
vector<Built> load(vector<int> userids) {
vector<Built> results;
results.reserve(userids.size());
for(const auto& result: results) {
loadTypes<Built, Types...>(result);
}
return results;
}
UserFlags flags;
};
template<class Built, class T, class ...Types>
void loadTypes(Built& built)
{
T *t = static_cast<T*>(&built);
if (!t->loaded) {
printf("Loading %d\n", T::flag);
T::load(built);
t->loaded = true;
printf("Loaded: %d\n", static_cast<T>(built).loaded);
}
loadTypes<Built, Types...>(built);
}
template<class Built>
void loadTypes(Built& built)
{
}
int main() {
auto basicsBuilder = Builder<>()
.load<UserBasics>();
auto builder = Builder<>()
.load<UserBasics>()
.load<UserLocation>();
int userid = 1234;
auto basics = builder.load(userid);
basics.age = 10;
basics.city = 0xf00d;
auto builtUser = builder.load(userid);
printf("userid: %d, name: %x, age: %d, city: %x\n", builtUser.userid, builtUser.name, builtUser.age, builtUser.city);
auto basics2 = basics.without<UserLocation>();
basics2.city = 0xd00f;
// vector<int> userids;
// userids.push_back(1);
// userids.push_back(2);
// userids.push_back(3);
// for (const auto& uid: userids) {
// auto built = builder.load(uid);
// printf("userid: %d, name: %x, age: %d, city: %x\n", built.userid, built.name, built.age, built.city);
// }
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment