splay-scheduler.cc
上传用户:rrhhcc
上传日期:2015-12-11
资源大小:54129k
文件大小:8k
源码类别:

通讯编程

开发平台:

Visual C++

  1. /* -*-  Mode:C++; c-basic-offset:8; tab-width:8; indent-tabs-mode:t -*- */
  2. /*
  3.  * splay-scheduler.cc
  4.  * Copyright (C) 2002 by the University of Southern California
  5.  * $Id: splay-scheduler.cc,v 1.6 2005/08/25 18:58:02 johnh Exp $
  6.  *
  7.  * This program is free software; you can redistribute it and/or
  8.  * modify it under the terms of the GNU General Public License,
  9.  * version 2, as published by the Free Software Foundation.
  10.  *
  11.  * This program is distributed in the hope that it will be useful,
  12.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14.  * GNU General Public License for more details.
  15.  *
  16.  * You should have received a copy of the GNU General Public License along
  17.  * with this program; if not, write to the Free Software Foundation, Inc.,
  18.  * 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
  19.  *
  20.  *
  21.  * The copyright of this module includes the following
  22.  * linking-with-specific-other-licenses addition:
  23.  *
  24.  * In addition, as a special exception, the copyright holders of
  25.  * this module give you permission to combine (via static or
  26.  * dynamic linking) this module with free software programs or
  27.  * libraries that are released under the GNU LGPL and with code
  28.  * included in the standard release of ns-2 under the Apache 2.0
  29.  * license or under otherwise-compatible licenses with advertising
  30.  * requirements (or modified versions of such code, with unchanged
  31.  * license).  You may copy and distribute such a system following the
  32.  * terms of the GNU GPL for this module and the licenses of the
  33.  * other code concerned, provided that you include the source code of
  34.  * that other code when and as the GNU GPL requires distribution of
  35.  * source code.
  36.  *
  37.  * Note that people who make modified versions of this module
  38.  * are not obligated to grant this special exception for their
  39.  * modified versions; it is their choice whether to do so.  The GNU
  40.  * General Public License gives permission to release a modified
  41.  * version without this exception; this exception also makes it
  42.  * possible to release a modified version which carries forward this
  43.  * exception.
  44.  *
  45.  */
  46. // @(#) $Header: /cvsroot/nsnam/ns-2/common/splay-scheduler.cc,v 1.6 2005/08/25 18:58:02 johnh Exp $
  47. #ifndef lint
  48. static const char rcsid[] =
  49. "@(#) $Header: /cvsroot/nsnam/ns-2/common/splay-scheduler.cc,v 1.6 2005/08/25 18:58:02 johnh Exp $";
  50. #endif
  51. /**
  52.  *
  53.  * Scheduler based on a splay tree.
  54.  *
  55.  * Daniel D. Sleator and Robert E. Tarjan. Self-adjusting binary
  56.  * search trees. Journal of the ACM, 32(3):652--686, 1985. 118.
  57.  *
  58.  * Basic idea of this scheduler: it organizes the event queue into a
  59.  * binary search tree.  For every insert and deque operation,
  60.  * "splaying" is performed aimed at shortening the search path for
  61.  * "similar" priorities (time_).  This should give O(log(N)) amortized
  62.  * time for basic operations, may be even better for correlated inserts.
  63.  *
  64.  * Implementation notes: Event::next_ and Event::prev_ are used as
  65.  * right and left pointers.  insert() and deque() use the "top-down"
  66.  * splaying algorithm taken almost verbatim from the paper and in some
  67.  * cases optimized for particular operations.  lookup() is extremely
  68.  * inefficient, and should be avoided whenever possible.  cancel()
  69.  * would be better off if we had a pointer to the parent, then there
  70.  * wouldn't be any need to search for it (and use Event::uid_ to
  71.  * resolve conflicts when same-priority events are both on the left
  72.  * and right).  cancel() does not perform any splaying, while it
  73.  * perhaps should.
  74.  *
  75.  * Memory used by this scheduler is O(1) (not counting the events).
  76.  *
  77.  * The original vefsion of this code was by Yuri Pryadkin.
  78.  **/
  79. #include <scheduler.h>
  80. #include <assert.h>
  81. static class SplaySchedulerClass : public TclClass 
  82. {
  83. public:
  84.         SplaySchedulerClass() : TclClass("Scheduler/Splay") {}
  85.         TclObject* create(int /* argc */, const char*const* /* argv */) {
  86.                 return (new SplayScheduler);
  87.         }
  88. } class_splay_sched;
  89. #undef LEFT
  90. #undef RIGHT
  91. #define LEFT(e) ((e)->prev_)
  92. #define RIGHT(e) ((e)->next_)
  93. #define ROTATE_RIGHT(t, x)
  94.     do {
  95.      LEFT(t) = RIGHT(x);  
  96.      RIGHT(x) = (t);
  97.      (t) = (x);
  98.     } while(0)
  99. #define ROTATE_LEFT(t, x)
  100.     do {
  101.      RIGHT(t)  = LEFT(x);  
  102.      LEFT(x) = (t);
  103.      (t) = (x);
  104.     } while(0)
  105. #define LINK_LEFT(l, t)
  106.     do {
  107. RIGHT(l) = (t);
  108. (l) = (t);
  109. (t) = RIGHT(t);
  110.     } while (0)
  111. #define LINK_RIGHT(r, t)
  112.     do {
  113. LEFT(r) = (t);
  114. (r) = (t);
  115. (t) = LEFT(t);
  116.     } while (0)
  117. void
  118. SplayScheduler::insert(Event *n) 
  119. {
  120. Event *l; // bottom right in the left tree
  121. Event *r; // bottom left in the right tree
  122. Event *t; // root of the remaining tree
  123. Event *x;    // current node
  124.     
  125. ++qsize_;
  126. double time = n->time_;
  127.     
  128. if (root_ == 0) {
  129. LEFT(n) = RIGHT(n) = 0;
  130. root_ = n;
  131. //validate();
  132. return;
  133. }
  134. t = root_;
  135. root_ = n; // n is the new root
  136. l = n;
  137. r = n;
  138. for (;;) {
  139. if (time < t->time_) {
  140. x = LEFT(t);
  141. if (x == 0) {
  142. LEFT(r) = t;
  143. RIGHT(l) = 0;
  144. break;
  145. }
  146. if (time < x->time_) {
  147. ROTATE_RIGHT(t, x);
  148. }
  149. LINK_RIGHT(r, t);
  150. if (t == 0) {
  151. RIGHT(l) = 0;
  152. break;
  153. }
  154. } else {
  155. x = RIGHT(t);
  156. if (x == 0) {
  157. RIGHT(l) = t; 
  158. LEFT(r) = 0;
  159. break;
  160. }
  161. if (time >= x->time_) {
  162. ROTATE_LEFT(t, x);
  163. }
  164. LINK_LEFT(l, t);
  165. if (t == 0) {
  166. LEFT(r) = 0;
  167. break;
  168. }
  169. }
  170. } /* for (;;) */
  171. // assemble:
  172. //   swap left and right children
  173. x = LEFT(n);
  174. LEFT(n) = RIGHT(n);
  175. RIGHT(n) = x;
  176. //validate();
  177. }
  178. const Event *
  179. SplayScheduler::head()
  180. {
  181. Event *t;
  182. Event *l;
  183. #if 1
  184. if (root_ == 0)
  185. return 0;
  186. for (t = root_; (l = LEFT(t)); t = l)
  187. ;
  188. return t;
  189. #else
  190. Event *ll;
  191. Event *lll;
  192. if (root_ == 0)
  193. return 0;
  194. t = root_;
  195. l = LEFT(t);
  196. if (l == 0) {
  197. return t;
  198. }
  199. for (;;) { 
  200. ll = LEFT(l);
  201. if (ll == 0) {
  202. return l;
  203. }
  204. lll = LEFT(ll);
  205. if (lll == 0) {
  206. return ll;
  207. }
  208. // zig-zig: rotate l with ll
  209. LEFT(t) = ll;
  210. LEFT(l) = RIGHT(ll);
  211. RIGHT(ll) = l;
  212. t = ll;
  213. l = lll;
  214. }
  215. #endif /* 1/0 */
  216. }
  217. Event *
  218. SplayScheduler::deque()
  219. {
  220. Event *t;
  221. Event *l;
  222. Event *ll;
  223. Event *lll;
  224. if (root_ == 0)
  225. return 0;
  226. --qsize_;
  227. t = root_;
  228. l = LEFT(t);
  229. if (l == 0) { // root is the element to dequeue
  230. root_ = RIGHT(t); // right branch becomes the root
  231. //validate();
  232. return t;
  233. }
  234. for (;;) { 
  235. ll = LEFT(l);
  236. if (ll == 0) {
  237. LEFT(t) = RIGHT(l);
  238. //validate();
  239. return l;
  240. }
  241. lll = LEFT(ll);
  242. if (lll == 0) {
  243. LEFT(l) = RIGHT(ll);
  244. //validate();
  245. return ll;
  246. }
  247. // zig-zig: rotate l with ll
  248. LEFT(t) = ll;
  249. LEFT(l) = RIGHT(ll);
  250. RIGHT(ll) = l;
  251. t = ll;
  252. l = lll;
  253. }
  254. void 
  255. SplayScheduler::cancel(Event *e)
  256. {
  257. if (e->uid_ <= 0) 
  258. return; // event not in queue
  259. Event **t;
  260. //validate();
  261. if (e == root_) {
  262. t = &root_;
  263. } else {
  264. // searching among same-time events is a real bugger,
  265. // all because we don't have a parent pointer; use
  266. // uid_ to resolve conflicts.
  267. for (t = &root_; *t;) {
  268. t = ((e->time_ > (*t)->time_) || 
  269.      ((e->time_ == (*t)->time_) && e->uid_ > (*t)->uid_))
  270. ? &RIGHT(*t) : &LEFT(*t);
  271. if (*t == e)
  272. break;
  273. }
  274. if (*t == 0) {
  275. fprintf(stderr, "did not find itn");
  276. abort(); // not found
  277. }
  278. }
  279. // t is the pointer to e in the parent or to root_ if e is root_
  280. e->uid_ = -e->uid_;
  281. --qsize_;
  282. if (RIGHT(e) == 0) {
  283. *t = LEFT(e);
  284. LEFT(e) = 0;
  285. //validate();
  286. return;
  287. if (LEFT(e) == 0) {
  288. *t = RIGHT(e);
  289. RIGHT(e) = 0;
  290. //validate();
  291. return;
  292. }
  293. // find successor
  294. Event *p = RIGHT(e), *q = LEFT(p);
  295. if (q == 0) {
  296. // p is the sucessor
  297. *t = p;
  298. LEFT(p) = LEFT(e);
  299. //validate();
  300. return;
  301. }
  302. for (; LEFT(q); p = q, q = LEFT(q)) 
  303. ;
  304. // q is the successor
  305. // p is q's parent
  306. *t = q;
  307. LEFT(p) = RIGHT(q);
  308. LEFT(q) = LEFT(e);
  309. RIGHT(q) = RIGHT(e);
  310. RIGHT(e) = LEFT(e) = 0;
  311. //validate();
  312. }
  313. Event *
  314. SplayScheduler::lookup(scheduler_uid_t uid) 
  315. {
  316. lookup_uid_ = uid;
  317. return uid_lookup(root_);
  318. }
  319. Event *
  320. SplayScheduler::uid_lookup(Event *root)
  321. {
  322. if (root == 0)
  323. return 0;
  324. if (root->uid_ == lookup_uid_)
  325. return root;
  326. Event *res = uid_lookup(LEFT(root));
  327.  
  328. if (res) 
  329. return res;
  330. return uid_lookup(RIGHT(root));
  331. }
  332. int
  333. SplayScheduler::validate(Event *root) 
  334. {
  335. int size = 0;
  336. if (root) {
  337. ++size;
  338. assert(LEFT(root) == 0 || root->time_ >= LEFT(root)->time_);
  339. assert(RIGHT(root) == 0 || root->time_ <= RIGHT(root)->time_);
  340. size += validate(LEFT(root));
  341. size += validate(RIGHT(root));
  342. return size;
  343. }
  344. return 0;
  345. }