Created
July 18, 2014 22:49
-
-
Save lukebitts/b13549923190a4296f32 to your computer and use it in GitHub Desktop.
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
// | |
// 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