#ifndef __AlertsDailyData_h_ #define __AlertsDailyData_h_ #include #include "../shared/ThreadSafeWrapper.h" #include "HashHelper.h" #include "IAlertsDaily.h" class AlertsDailyData { private: struct Value { std::shared_ptr< const char > symbol; Record::Ref record; }; typedef std::unordered_map< char const *, Value, SimpleCharStarHash, SimpleCharStarEqual > OneDay; typedef std::map< time_t, OneDay > AllDays; AllDays _allDays; Record::Ref findWithinDay(AllDays::const_iterator it, char const *symbol) const; Record::Ref findInternal(char const *symbol, time_t time) const; void setDateInternal(std::string const &symbol, time_t date, Record::Ref const &record); public: AlertsDailyData() { } AlertsDailyData(AlertsDailyData const &other) : _allDays(other._allDays) { } AlertsDailyData(AlertsDailyData &&other) : _allDays(other._allDays) { } Record::Ref find(char const *symbol, time_t time) const; // This will convert the time into a date. We always save things by date. // This is a slighly slow process. Use setDate() if you are sure this is // already a date. // // "setTime" is short for SET the given value, using a TIME for a key. void setTime(std::string const &symbol, time_t time, Record::Ref const &record); // This assumes that date is really a date. If you are not sure, call // setTime() instead. Adding an invalid date could seriously break things. // // "setDate" is short for SET the given value, using a DATE for a key. void setDate(std::string const &symbol, time_t date, Record::Ref const &record); // This works for a date or a time. void set(std::string const &symbol, std::string const &mysqlDate, Record::Ref const &record); // This quickly swaps the data between two objects. void swap(AlertsDailyData &other); // This quickly clears all entries. void clear(); }; class AlertsDailyDataManager : public IAlertsDaily { private: AlertsDailyDataManager() { } static ThreadSafeWrapper< AlertsDailyData > _current; static __thread ThreadSafeCache< AlertsDailyData > *_cache; static ThreadSafeCache< AlertsDailyData > &cache() { if (!_cache) _cache = new ThreadSafeCache< AlertsDailyData >(_current); return *_cache; } public: virtual Record::Ref find(char const *symbol, time_t time) const { return cache()->find(symbol, time); } // Notice the ThreadSafeCache semantics here. The return value is an // ordinary reference, not a smart pointer. We are holding a smart pointer // internally. The reference will remain valid until the next call to // cache(). Most calls to cache() come indirectly from calls to execute a // strategy. This IS thread safe; calling cache() in a different thread // doesn't hurt anything. // // In practice, people use getAll() in a simple way. They immediately // make a copy of the object then abandon the reference. That's // completely safe. static AlertsDailyData const &getAll() { return *cache(); } static void set(AlertsDailyData const &newValue); static void set(AlertsDailyData &&newValue); static void install(); }; #endif