Skip to content

Instantly share code, notes, and snippets.

@lukebitts
Created July 18, 2014 22:49
Show Gist options
  • Save lukebitts/b13549923190a4296f32 to your computer and use it in GitHub Desktop.
Save lukebitts/b13549923190a4296f32 to your computer and use it in GitHub Desktop.
//
// main.cpp
// EntCompTest
//
// Created by Lucas Bittencourt on 7/8/14.
// Copyright (c) 2014 Lucas Bittencourt. All rights reserved.
//
#include <iostream>
#include <vector>
#include <boost/optional.hpp>
#include <boost/utility.hpp>
#include <bitset>
#include <future>
#include <thread>
#include <unordered_map>
#include <fstream>
#include <string>
#include <cerrno>
#include <mutex>
struct Logger
{
private:
static std::mutex m;
static std::vector<std::string> to_log;
public:
static void Log(std::string s)
{
std::lock_guard<std::mutex> g{m};
to_log.push_back(s);
}
static void Flush()
{
std::lock_guard<std::mutex> g{m};
for(std::string& s : to_log)
std::cout<<s;
to_log.clear();
}
};
std::mutex Logger::m;
std::vector<std::string> Logger::to_log;
class Resources;
struct Resource : public boost::noncopyable
{
enum State
{
UNDEFINED,
WAITING,
LOADED
};
static bool Load(Resource* r, std::string path)
{
throw std::runtime_error("Load not implemented for this type.");
}
virtual ~Resource() {}
};
template <class T>
struct ResourceHandle
{
private:
const Resources* _r = nullptr;
std::string _path = "";
public:
ResourceHandle(const Resources* r, std::string path) : _r(r), _path(path) {}
ResourceHandle() {}
const T& get() const;
Resource::State state() const;
static ResourceHandle<T> make_handle(const Resources* r, std::string path)
{
return ResourceHandle<T>(r, path);
}
operator bool()
{
return state() == Resource::State::LOADED;
}
};
struct TextResource : public Resource
{
public:
std::string text = "";
static bool Load(TextResource* r, std::string path)
{
std::ifstream ifs(path.c_str(), std::ios::in | std::ios::binary | std::ios::ate);
if(!ifs) return false;
std::fstream::pos_type fileSize = ifs.tellg();
ifs.seekg(0, std::ios::beg);
std::vector<char> bytes(fileSize);
ifs.read(&bytes[0], fileSize);
r->text = std::move(std::string(&bytes[0], fileSize));
return true;
}
};
class Resources
{
private:
std::unordered_map<std::string, std::unique_ptr<Resource>> _resources;
std::vector<std::pair<std::string, std::function<void()>>> _load_queue;
template<class T>
T* _get(std::string path) const
{
if(_resources.find(path) != _resources.end())
return static_cast<T*>(_resources.at(path).get());
return nullptr;
}
template <class T>
friend class ResourceHandle;
//*****//
std::thread _load_worker;
std::atomic<bool> _worker_run{true};
std::mutex _resources_mutex;
std::mutex _load_queue_mutex;
public:
Resources()
{
_load_worker = std::thread(
[this]()
{
while(_worker_run.load())
{
size_t load_queue_size = 0;
{
std::lock_guard<std::mutex> g{_load_queue_mutex};
load_queue_size = _load_queue.size();
}
while(load_queue_size > 0)
{
std::function<void()> fn;
{
std::lock_guard<std::mutex> g{_load_queue_mutex};
fn = _load_queue.back().second;
}
fn();
{
std::lock_guard<std::mutex> g{_load_queue_mutex};
_load_queue.pop_back();
}
}
}
}
);
}
template <class T, class ... Params>
bool load(std::string path, Params&& ... params)
{
std::unique_ptr<T> t{new T{}};
if(T::Load(t.get(), path, std::forward<Params>(params)...))
{
std::lock_guard<std::mutex> g{_resources_mutex};
_resources[path] = std::move(t);
return true;
}
return false;
}
template <class T, class ... Params>
void load_async(std::string path, Params&& ... params)
{
std::lock_guard<std::mutex> g{_load_queue_mutex};
_load_queue.push_back(std::make_pair(path,[this,path,params...](){
load<T>(path, std::forward<Params>(params)...);
}));
}
template <class T>
ResourceHandle<T> get(std::string path) const
{
return ResourceHandle<T>(this, path);
}
~Resources()
{
_worker_run.store(false);
_load_worker.join();
}
};
template<class T>
const T& ResourceHandle<T>::get() const
{
static const T default_return{};
auto resource = _r ? static_cast<T*>(_r->_get<T>(_path)) : nullptr;
return resource ? *resource : default_return;
}
template<class T>
Resource::State ResourceHandle<T>::state() const
{
if(_r->_resources.find(_path) != _r->_resources.end())
return Resource::State::LOADED;
else if(std::find_if(_r->_load_queue.begin(),_r->_load_queue.end(),
[this](const std::pair<std::string, std::function<void()>>& q){return q.first == _path;}) != _r->_load_queue.end())
return Resource::State::WAITING;
else
return Resource::State::UNDEFINED;
/*while(_r->_get<T>(_path) == nullptr);
return ResourceHandle<T>(*this);*/
}
int main()
{
Resources r{};
r.load_async<TextResource>("/Users/lucasbittencourt/Desktop/boxes.ply");
auto t = r.get<TextResource>("/Users/lucasbittencourt/Desktop/boxes.ply");
Logger::Log(t.get().text);
while(t.state() != Resource::State::LOADED);
Logger::Log(t.get().text);
Logger::Flush();
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment