diff --git a/a8/stringlist.cc b/a8/stringlist.cc index e290781..14f7459 100644 --- a/a8/stringlist.cc +++ b/a8/stringlist.cc @@ -69,6 +69,11 @@ namespace a8 } p2++; } + #if 0 + if (p2 > p1) { + Add(p2 > p1 ? std::string(p1, p2 - p1) : ""); + } + #endif } std::string StringList::Text() diff --git a/a8/sysutils.cc b/a8/sysutils.cc index bfca194..e293166 100644 --- a/a8/sysutils.cc +++ b/a8/sysutils.cc @@ -209,4 +209,10 @@ namespace a8 return (int)(int64_val >> 32); } + float RandAngle() + { + float angle = 0.00001f + ((float)rand() / RAND_MAX) * 2.0f; + return angle; + } + } diff --git a/a8/sysutils.h b/a8/sysutils.h index 0e04df2..72befc2 100644 --- a/a8/sysutils.h +++ b/a8/sysutils.h @@ -42,6 +42,18 @@ namespace a8 return t.back(); } + template + const T& Clamp(const T& v, const T& lo, const T& hi) + { + return v < hi ? (v > lo ? v : lo) : hi; + } + + template + float LengthSqr(const T& v) + { + return v.x * v.x + v.y * v.y; + } + template void SetToVector(std::set& set_v, std::vector& vector_v) { @@ -73,6 +85,7 @@ namespace a8 int Low32(long long int64_val); int High32(long long int64_val); + float RandAngle(); } #endif diff --git a/a8/timer.cc b/a8/timer.cc index 232369a..4753894 100644 --- a/a8/timer.cc +++ b/a8/timer.cc @@ -148,6 +148,9 @@ namespace a8 void Timer::UnInit() { + Clear(); + delete base_; + base_ = nullptr; } void Timer::Update() @@ -227,7 +230,7 @@ namespace a8 if (!list_empty(&timer->attach_entry)) { list_del_init(&timer->attach_entry); } - AddToFreeList(timer); + AddToFreeList(timer); } timer_list* Timer::GetTimerByAttach(list_head* attach_entry) @@ -332,6 +335,33 @@ namespace a8 base_->free_timer_num++; } + void Timer::Clear() + { + auto free_timers = + [] (list_head* head) + { + while (!list_empty(head)) { + struct timer_list *timer; + timer = list_first_entry(head, struct timer_list,entry); + DetachTimer(timer); + if (!list_empty(&timer->attach_entry)) { + list_del_init(&timer->attach_entry); + } + delete timer; + } + }; + for (int j = 0; j < TVN_SIZE; j++) { + free_timers(base_->tv5.vec + j); + free_timers(base_->tv4.vec + j); + free_timers(base_->tv3.vec + j); + free_timers(base_->tv2.vec + j); + } + for (int j = 0; j < TVR_SIZE; j++) { + free_timers(base_->tv1.vec + j); + } + free_timers(&base_->free_timer); + } + void Timer::GC_TimerFunc(const a8::XParams& param) { Timer* timer = (Timer*)param.sender.GetUserData(); diff --git a/a8/timer.h b/a8/timer.h index 14c41b9..9695f2b 100644 --- a/a8/timer.h +++ b/a8/timer.h @@ -47,6 +47,7 @@ namespace a8 void UpdateTimer(); timer_list* NewTimerList(); void AddToFreeList(timer_list* timer); + void Clear(); static void GC_TimerFunc(const a8::XParams& param); private: diff --git a/a8/xobject.cc b/a8/xobject.cc index fe6db94..1341313 100644 --- a/a8/xobject.cc +++ b/a8/xobject.cc @@ -298,6 +298,33 @@ namespace a8 return ReadFromJsonString(sl.Text()); } + bool XObject::ReadFromJsonFile(const std::string& filename) + { + std::string json_data; + { + FILE *fp = fopen(filename.c_str(), "rb"); + if (!fp) { + return false; + } + fseek(fp, 0, SEEK_END); + int fileSize = ftell(fp); + if(fileSize){ + char *p = (char*)malloc(fileSize + 1); + if(p){ + *(p + fileSize) = '\0'; + fseek(fp, 0, SEEK_SET); + fread(p, 1, fileSize, fp); + if (fileSize > 0) { + json_data.append(p, fileSize); + } + free(p); + } + } + fclose(fp); + } + return ReadFromJsonString(json_data); + } + bool XObject::ReadFromJsonString(const std::string& json_data) { Json::Reader reader; diff --git a/a8/xobject.h b/a8/xobject.h index 6b17e4e..1214d11 100644 --- a/a8/xobject.h +++ b/a8/xobject.h @@ -44,6 +44,7 @@ namespace a8 a8::XObject& Move(a8::XObject& a); bool ReadFromFile(const std::string& filename); + bool ReadFromJsonFile(const std::string& filename); bool ReadFromJsonString(const std::string& jsondata); bool ReadFromXmlFile(const std::string& filename); bool ReadFromXmlString(const std::string& xmldata); diff --git a/a8/xtimer.cc b/a8/xtimer.cc new file mode 100644 index 0000000..824cc82 --- /dev/null +++ b/a8/xtimer.cc @@ -0,0 +1,352 @@ +#include + +#include + +#define CONFIG_BASE_SMALL 0 +#define TVN_BITS (CONFIG_BASE_SMALL ? 4 : 6) +#define TVR_BITS (CONFIG_BASE_SMALL ? 6 : 8) +#define TVN_SIZE (1 << TVN_BITS) +#define TVR_SIZE (1 << TVR_BITS) +#define TVN_MASK (TVN_SIZE - 1) +#define TVR_MASK (TVR_SIZE - 1) +#define INDEX(N) ((base->timer_tick >> (TVR_BITS + (N) * TVN_BITS)) & TVN_MASK) + +struct xtvec { + struct list_head vec[TVN_SIZE]; +}; + +struct xtvec_root { + struct list_head vec[TVR_SIZE]; +}; + +struct xtvec_base { + struct xtimer_list *running_timer; + long long timer_tick; + list_head free_timer; + int free_timer_num; + struct xtvec_root tv1; + struct xtvec tv2; + struct xtvec tv3; + struct xtvec tv4; + struct xtvec tv5; +}; + +struct xtimer_list { + struct list_head entry; + struct list_head attach_entry; + int timer_type; // 0:deadline 1: repeattimer 2:fixedtimer outher:deadline + long long expires; + int expire_time; + int fixed_timer_execute_times; + struct xtvec_base *base; + + a8::XTimerFunc timer_func; + a8::XTimerAfterFunc timer_after_func; + a8::XParams param; +}; + +static void InternalAddXTimer(struct xtvec_base *base, struct xtimer_list *timer) +{ + long long expires = timer->expires; + long long idx = expires - base->timer_tick; + struct list_head *vec; + + if (idx < 0) { + vec = base->tv1.vec + (base->timer_tick & TVR_MASK); + }else if (idx < TVR_SIZE) { + int i = expires & TVR_MASK; + vec = base->tv1.vec + i; + } else if (idx < 1 << (TVR_BITS + TVN_BITS)) { + int i = (expires >> TVR_BITS) & TVN_MASK; + vec = base->tv2.vec + i; + } else if (idx < 1 << (TVR_BITS + 2 * TVN_BITS)) { + int i = (expires >> (TVR_BITS + TVN_BITS)) & TVN_MASK; + vec = base->tv3.vec + i; + } else if (idx < 1 << (TVR_BITS + 3 * TVN_BITS)) { + int i = (expires >> (TVR_BITS + 2 * TVN_BITS)) & TVN_MASK; + vec = base->tv4.vec + i; + } else { + int i = (expires >> (TVR_BITS + 3 * TVN_BITS)) & TVN_MASK; + vec = base->tv5.vec + i; + } + list_add_tail(&timer->entry, vec); +} + +static int Cascade(struct xtvec_base *base, struct xtvec *tv, int index) +{ + /* cascade all the timers from tv up one level */ + struct xtimer_list *timer, *tmp; + struct list_head tv_list; + + // 将tv数组中以index为下标的定时器队列取出,准备搬移 + list_replace_init(tv->vec + index, &tv_list); + + // 根据超时时间,将队列中的定时器重新排队。定时器往上一级时间轮排队的过程就 // 在这里发生。 + list_for_each_entry_safe(timer, tmp, &tv_list, entry) { + InternalAddXTimer(base, timer); + } + return index; +} + +static inline int DetachTimer(struct xtimer_list *timer) +{ + if (!list_empty(&timer->entry)) { + list_del_init(&timer->entry); + } + return 1; +} + +static inline void InitTimerList(xtvec_base* base, xtimer_list* timer, int timer_type, + long long expires, int expire_time, a8::XParams& param, + a8::XTimerFunc timer_func, a8::XTimerAfterFunc timer_after_func) +{ + INIT_LIST_HEAD(&timer->entry); + INIT_LIST_HEAD(&timer->attach_entry); + timer->timer_type = timer_type; + timer->expires = expires; + timer->expire_time = expire_time; + timer->fixed_timer_execute_times = 0; + timer->base = base; + timer->timer_func = timer_func; + timer->timer_after_func = timer_after_func; + timer->param = param; +} + +namespace a8 +{ + + XTimer::XTimer() + { + base_ = new xtvec_base(); + base_->running_timer = nullptr; + base_->timer_tick = get_tick_count_func_(context_); + INIT_LIST_HEAD(&base_->free_timer); + base_->free_timer_num = 0; + for (int j = 0; j < TVN_SIZE; j++) { + INIT_LIST_HEAD(base_->tv5.vec + j); + INIT_LIST_HEAD(base_->tv4.vec + j); + INIT_LIST_HEAD(base_->tv3.vec + j); + INIT_LIST_HEAD(base_->tv2.vec + j); + } + for (int j = 0; j < TVR_SIZE; j++) { + INIT_LIST_HEAD(base_->tv1.vec + j); + } + } + + XTimer::~XTimer() + { + Clear(); + delete base_; + base_ = nullptr; + } + + void XTimer::Init(XGetTickCountFunc func, void* context, int gc_time, int cache_timer_num) + { + get_tick_count_func_ = func; + context_ = context_; + gc_time_ = gc_time; + cache_timer_num_ = cache_timer_num; + AddRepeatTimer(gc_time_, + a8::XParams().SetSender(this), + &XTimer::GC_XTimerFunc); + } + + void XTimer::Update() + { + if (get_tick_count_func_(context_) >= base_->timer_tick) { + UpdateTimer(); + } + } + + xtimer_list* XTimer::AddDeadLineTimer(int expire_time, a8::XParams param, a8::XTimerFunc timer_func, + a8::XTimerAfterFunc timer_after_func) + { + xtimer_list *timer = NewTimerList(); + InitTimerList(base_, + timer, + 0, + get_tick_count_func_(context_) + expire_time, + expire_time, + param, + timer_func, + timer_after_func); + ModifyTimer(timer, expire_time); + return timer; + } + + xtimer_list* XTimer::AddDeadLineTimerAndAttach(int expire_time, a8::XParams param, a8::XTimerFunc timer_func, + list_head* attach_list, a8::XTimerAfterFunc timer_after_func) + { + xtimer_list* timer = AddDeadLineTimer(expire_time, param, timer_func, timer_after_func); + list_add_tail(&timer->attach_entry, attach_list); + return timer; + } + + xtimer_list* XTimer::AddRepeatTimer(int expire_time, a8::XParams param, a8::XTimerFunc timer_func) + { + xtimer_list *timer = NewTimerList(); + InitTimerList(base_, + timer, + 1, + get_tick_count_func_(context_) + expire_time, + expire_time, + param, + timer_func, + nullptr); + ModifyTimer(timer, expire_time); + return timer; + } + + void XTimer::ModifyTimer(xtimer_list* timer, int expire_time) + { + DetachTimer(timer); + timer->expire_time = expire_time; + if (timer->timer_type == 2) { + long long tick = get_tick_count_func_(context_); + long long today_passed_seconds = time(nullptr) - a8::GetDaySeconds(time(nullptr), 0); + timer->expires = (tick - today_passed_seconds * 1000) + expire_time; + if (timer->fixed_timer_execute_times > 0) { + if (timer->expires <= tick) { //已过期 + timer->expires += 1000 * 3600 * 24; + } + } + }else { + timer->expires = get_tick_count_func_(context_) + expire_time; + } + InternalAddXTimer(base_, timer); + } + + void XTimer::DeleteTimer(xtimer_list* timer) + { + if (timer->timer_after_func) { + timer->timer_after_func(timer->param); + } + DetachTimer(timer); + if (!list_empty(&timer->attach_entry)) { + list_del_init(&timer->attach_entry); + } + AddToFreeList(timer); + } + + xtimer_list* XTimer::GetTimerByAttach(list_head* attach_entry) + { + if (attach_entry) { + xtimer_list* timer = list_entry(attach_entry, struct xtimer_list, attach_entry); + return timer; + } else { + return nullptr; + } + } + + void XTimer::UpdateTimer() + { + struct xtvec_base *base = base_; + while (get_tick_count_func_(context_) >= base->timer_tick) { + struct list_head work_list; + struct list_head *head = &work_list; + int index = base->timer_tick & TVR_MASK; + + if (!index && + (!Cascade(base, &base->tv2, INDEX(0))) && + (!Cascade(base, &base->tv3, INDEX(1))) && + !Cascade(base, &base->tv4, INDEX(2))) { + Cascade(base, &base->tv5, INDEX(3)); + } + ++base->timer_tick; + list_replace_init(base->tv1.vec + index, &work_list); + while (!list_empty(head)) { + struct xtimer_list *timer; + timer = list_first_entry(head, struct xtimer_list,entry); + base->running_timer = timer; + if (timer->timer_func) { + timer->timer_func(timer->param); + } + if (timer->timer_after_func) { + timer->timer_after_func(timer->param); + } + switch (timer->timer_type) { + case 1: + case 2: //循环类定时 fixed timer也是循环定时器 + { + if (timer->timer_type == 2) { + timer->fixed_timer_execute_times++; + } + ModifyTimer(timer, timer->expire_time); + } + break; + default: //deadline timer + { + DetachTimer(timer); + if (!list_empty(&timer->attach_entry)) { + list_del_init(&timer->attach_entry); + } + AddToFreeList(timer); + } + break; + } + } + } + base->running_timer = nullptr; + } + + xtimer_list* XTimer::NewTimerList() + { + if (!list_empty(&base_->free_timer)) { + xtimer_list* timer = list_first_entry(&base_->free_timer, struct xtimer_list,entry); + list_del_init(&timer->entry); + base_->free_timer_num--; + return timer; + } else { + return new xtimer_list(); + } + } + + void XTimer::AddToFreeList(xtimer_list* timer) + { + list_add_tail(&timer->entry, &base_->free_timer); + base_->free_timer_num++; + } + + void XTimer::Clear() + { + auto free_timers = + [] (list_head* head) + { + while (!list_empty(head)) { + struct xtimer_list *timer; + timer = list_first_entry(head, struct xtimer_list,entry); + DetachTimer(timer); + if (!list_empty(&timer->attach_entry)) { + list_del_init(&timer->attach_entry); + } + delete timer; + } + }; + for (int j = 0; j < TVN_SIZE; j++) { + free_timers(base_->tv5.vec + j); + free_timers(base_->tv4.vec + j); + free_timers(base_->tv3.vec + j); + free_timers(base_->tv2.vec + j); + } + for (int j = 0; j < TVR_SIZE; j++) { + free_timers(base_->tv1.vec + j); + } + free_timers(&base_->free_timer); + } + + void XTimer::GC_XTimerFunc(const a8::XParams& param) + { + XTimer* timer = (XTimer*)param.sender.GetUserData(); + int i = 0; + while (!list_empty(&timer->base_->free_timer) && + timer->base_->free_timer_num > timer->cache_timer_num_ && i < 1000) { + xtimer_list* timer1 = list_first_entry(&timer->base_->free_timer, struct xtimer_list, entry); + list_del_init(&timer1->entry); + delete timer1; + + timer->base_->free_timer_num--; + i++; + } + } + +} diff --git a/a8/xtimer.h b/a8/xtimer.h new file mode 100644 index 0000000..f398f74 --- /dev/null +++ b/a8/xtimer.h @@ -0,0 +1,60 @@ +/* + * 仿照linux2.6内核定时器实现 + */ +#ifndef A8_XTIMER_H +#define A8_XTIMER_H + +struct xtimer_list; +struct xtvec_base; + +namespace a8 +{ + typedef void (*XTimerFunc)(const a8::XParams& param); + typedef void (*XTimerAfterFunc)(const a8::XParams& param); + typedef long long (*XGetTickCountFunc)(void*); + + class XTimer + { + private: + XTimer(); + ~XTimer(); + + public: + void Init(XGetTickCountFunc func, void* context, int gc_time, int cache_timer_num); + + void Update(); + + //添加截止时间定时器(一次性定时器) + xtimer_list* AddDeadLineTimer(int expire_time, a8::XParams param, a8::XTimerFunc timer_func, + a8::XTimerAfterFunc timer_after_func = nullptr); + xtimer_list* AddDeadLineTimerAndAttach(int expire_time, a8::XParams, + a8::XTimerFunc timer_func, + list_head* attach_list, + a8::XTimerAfterFunc timer_after_func = nullptr); + //添加重复执行定时器(周期性定时器) + xtimer_list* AddRepeatTimer(int expire_time, a8::XParams param, a8::XTimerFunc timer_func); + //修改定时器参数 + void ModifyTimer(xtimer_list* timer, int expire_time); + //删除定时器 + void DeleteTimer(xtimer_list* timer); + //通过关联的list_head获取定时器对象 + xtimer_list* GetTimerByAttach(list_head* attach_entry); + + private: + void UpdateTimer(); + xtimer_list* NewTimerList(); + void AddToFreeList(xtimer_list* timer); + void Clear(); + static void GC_XTimerFunc(const a8::XParams& param); + + private: + xtvec_base* base_ = nullptr; + XGetTickCountFunc get_tick_count_func_ = nullptr; + void* context_ = nullptr; + int gc_time_ = 10; + int cache_timer_num_ = 100; + }; + +} + +#endif