#include "../shared/ThreadMonitor.h" #include "../shared/MarketHours.h" #include "../shared/MiscSQL.h" #include "AlertsDailyData.h" ///////////////////////////////////////////////////////////////////// // AlertsDailyData ///////////////////////////////////////////////////////////////////// Record::Ref AlertsDailyData::findWithinDay(AllDays::const_iterator it, char const *symbol) const { auto found = it->second.find(symbol); if (found == it->second.end()) return Record::EMPTY; else return found->second.record; } Record::Ref AlertsDailyData::findInternal(char const *symbol, time_t time) const { if (_allDays.empty()) // This is not just an optimization. If we didn't stop on an empty // map, it-- would cause a core dump! return Record::EMPTY; // The key for allDays is midnight on the given day. Using lowerBound() // like this means that we don't have to convert a time to a date each time // we do a lookup. allDays.find(midight(time)) would be a little simpler, // but would take longer. AllDays::const_iterator it = _allDays.upper_bound(time); it--; if (it == _allDays.end()) // This time comes before any time that we have in the map. return Record::EMPTY; if (it->first + MARKET_HOURS_DAY < time) // We found a day that comes before the day we're looking for. The day // we're looking for must not exist. return Record::EMPTY; // We found the right day. Now look for the given symbol. //return getProperty(it->second, symbol, Record::EMPTY); return findWithinDay(it, symbol); } void AlertsDailyData::setDateInternal(std::string const &symbol, time_t date, Record::Ref const &record) { auto persistentCharStar = makeSharedPtr(symbol); Value &value = _allDays[date][persistentCharStar.get()]; value.symbol = std::move(persistentCharStar); value.record = record; } //static const std::string s_AlertsDailyFind = "s_AlertsDailyFind"; Record::Ref AlertsDailyData::find(char const *symbol, time_t time) const { //ThreadMonitor::find().setState(s_AlertsDailyFind); Record::Ref result = findInternal(symbol, time); return result; } void AlertsDailyData::setTime(std::string const &symbol, time_t time, Record::Ref const &record) { setDate(symbol, midnight(time), record); } void AlertsDailyData::setDate(std::string const &symbol, time_t date, Record::Ref const &record) { setDateInternal(symbol, date, record); } void AlertsDailyData::set(std::string const &symbol, std::string const &mysqlDate, Record::Ref const &record) { time_t time = mysqlToTimeT(mysqlDate); if (mysqlDate.length() == 10) // This is already a date. setDate(symbol, time, record); else setTime(symbol, time, record); } void AlertsDailyData::swap(AlertsDailyData &other) { _allDays.swap(other._allDays); } void AlertsDailyData::clear() { AlertsDailyData empty; swap(empty); } ///////////////////////////////////////////////////////////////////// // AlertsDailyDataManager ///////////////////////////////////////////////////////////////////// ThreadSafeWrapper< AlertsDailyData > AlertsDailyDataManager::_current(new AlertsDailyData); __thread ThreadSafeCache< AlertsDailyData > *AlertsDailyDataManager::_cache = NULL; void AlertsDailyDataManager::set(AlertsDailyData const &newValue) { // Copy (or move) the data into here. Then we don't have to worry about // someone accidentally holding onto a writable pointer too long. _current.set(new AlertsDailyData(newValue)); } void AlertsDailyDataManager::set(AlertsDailyData &&newValue) { _current.set(new AlertsDailyData(newValue)); } void AlertsDailyDataManager::install() { IAlertsDaily::set(new AlertsDailyDataManager); }