ChipMaster's trial hacks on C++CMS starting with v1.2.1. Not sure I'll follow on with the v2 since it looks to be breaking and mostly frivolous.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

511 lines
8.8 KiB

  1. ///////////////////////////////////////////////////////////////////////////////
  2. //
  3. // Copyright (C) 2008-2012 Artyom Beilis (Tonkikh) <artyomtnk@yahoo.com>
  4. //
  5. // See accompanying file COPYING.TXT file for licensing details.
  6. //
  7. ///////////////////////////////////////////////////////////////////////////////
  8. #ifndef CPPCMS_IMPL_HASH_MAP_H
  9. #define CPPCMS_IMPL_HASH_MAP_H
  10. #include <new>
  11. #include <functional>
  12. #include <vector>
  13. #include <utility>
  14. #include <assert.h>
  15. #include <cppcms/cstdint.h>
  16. #include <booster/iterator/iterator_facade.h>
  17. namespace cppcms {
  18. namespace impl {
  19. struct string_hash {
  20. public:
  21. typedef uint32_t state_type;
  22. static const state_type initial_state = 0;
  23. static state_type update_state(state_type value,char c)
  24. {
  25. value = (value << 4) + static_cast<unsigned char>(c);
  26. uint32_t high = (value & 0xF0000000U);
  27. if(high!=0)
  28. value = (value ^ (high >> 24)) ^ high;
  29. return value;
  30. }
  31. template<typename T>
  32. size_t operator()(T const &v) const
  33. {
  34. state_type st = initial_state;
  35. for(typename T::const_iterator p=v.begin();p!=v.end();++p) {
  36. st = update_state(st,*p);
  37. }
  38. return st;
  39. }
  40. };
  41. namespace details {
  42. struct are_equal {
  43. template<typename T1,typename T2>
  44. bool operator()(T1 const &v1,T2 const &v2) const
  45. {
  46. return v1==v2;
  47. }
  48. };
  49. template<typename T>
  50. class intrusive_list
  51. {
  52. public:
  53. intrusive_list() : begin(0), end(0)
  54. {
  55. }
  56. void push_back(T *p)
  57. {
  58. p->next = 0;
  59. p->prev = end;
  60. if(end)
  61. end->next = p;
  62. end = p;
  63. if(begin == 0)
  64. begin = p;
  65. }
  66. void push_front(T *p)
  67. {
  68. p->next = begin;
  69. p->prev = 0;
  70. if(begin)
  71. begin->prev = p;
  72. begin = p;
  73. if(end == 0)
  74. end = p;
  75. }
  76. void erase(T *p)
  77. {
  78. if(p->prev) {
  79. p->prev->next = p->next;
  80. }
  81. if(p->next) {
  82. p->next->prev = p->prev;
  83. }
  84. if(begin == p)
  85. begin = p->next;
  86. if(end == p)
  87. end = p->prev;
  88. p->next = p->prev = 0;
  89. }
  90. void insert_after(T *p,T *after_me)
  91. {
  92. if(!after_me->next) {
  93. push_back(p);
  94. return;
  95. }
  96. p->prev = after_me;
  97. p->next = after_me->next;
  98. if(after_me->next)
  99. after_me->next->prev = p;
  100. after_me->next = p;
  101. }
  102. void insert_before(T *p,T *before_me)
  103. {
  104. if(!before_me->prev) {
  105. push_front(p);
  106. return;
  107. }
  108. p->next = before_me;
  109. p->prev = before_me->prev;
  110. if(before_me->prev)
  111. before_me->prev->next = p;
  112. before_me->prev = p;
  113. }
  114. void swap(intrusive_list &other)
  115. {
  116. std::swap(other.begin,begin);
  117. std::swap(other.end,end);
  118. }
  119. T *begin,*end;
  120. };
  121. template< typename Key,
  122. typename Value,
  123. typename Hash,
  124. typename Equals=are_equal,
  125. typename Alloc= std::allocator<std::pair<Key,Value> >
  126. >
  127. class basic_map
  128. {
  129. public:
  130. basic_map() : size_(0)
  131. {
  132. }
  133. ~basic_map()
  134. {
  135. clear();
  136. }
  137. typedef std::pair<const Key,Value> value_type;
  138. struct container {
  139. container() : val(), next(0),prev(0) {}
  140. container(value_type const &v) : val(v), next(0),prev(0) {}
  141. value_type val;
  142. size_t hash;
  143. container *next;
  144. container *prev;
  145. };
  146. typedef container *iterator;
  147. typedef typename Alloc::template rebind<container>::other container_alloc;
  148. typedef std::pair<iterator,iterator> range_type;
  149. typedef typename Alloc::template rebind<range_type>::other vec_allocator;
  150. iterator erase(iterator p)
  151. {
  152. if(p==0)
  153. return 0;
  154. range_type &r = get(p->val.first);
  155. if(r.first == r.second) {
  156. assert(p == r.first);
  157. r.first = r.second = 0;
  158. }
  159. else if(r.first == p)
  160. r.first = p->next;
  161. else if(r.second == p)
  162. r.second = p->prev;
  163. iterator next = p->next;
  164. list_.erase(p);
  165. size_ --;
  166. destroy(p);
  167. return next;
  168. }
  169. size_t size() const
  170. {
  171. return size_;
  172. }
  173. template<typename Kt>
  174. iterator find(Kt const &k)
  175. {
  176. if(hash_.empty())
  177. return 0;
  178. range_type &range=get(k);
  179. return find_in_range(range,k);
  180. }
  181. std::pair<iterator,bool> insert(value_type const &entry)
  182. {
  183. std::pair<iterator,bool> r(iterator(),false);
  184. rehash_if_needed();
  185. range_type &range=get(entry.first);
  186. iterator p = find_in_range(range,entry.first);
  187. if(p) {
  188. r.first = p;
  189. return r;
  190. }
  191. p = allocate(entry);
  192. if(range.second == 0) {
  193. list_.push_back(p);
  194. range.first = range.second = p;
  195. }
  196. else {
  197. list_.insert_after(p,range.second);
  198. range.second = p;
  199. }
  200. r.first = p;
  201. r.second = true;
  202. size_ ++;
  203. return r;
  204. }
  205. void clear()
  206. {
  207. iterator p=list_.begin;
  208. if(size_ / 4 >= hash_.size()) {
  209. for(size_t i=0;i<hash_.size();i++) {
  210. hash_[i].first = 0;
  211. hash_[i].second = 0;
  212. }
  213. while(p) {
  214. iterator del = p;
  215. p=p->next;
  216. del->prev = 0;
  217. del->next = 0;
  218. destroy(del);
  219. }
  220. }
  221. else {
  222. while(p) {
  223. iterator del = p;
  224. p=p->next;
  225. del->prev = 0;
  226. del->next = 0;
  227. range_type &r=get(del->val.first);
  228. r.first = r.second = 0;
  229. destroy(del);
  230. }
  231. }
  232. list_.begin = list_.end = 0;
  233. size_ = 0;
  234. }
  235. iterator begin()
  236. {
  237. return list_.begin;
  238. }
  239. iterator end()
  240. {
  241. return 0;
  242. }
  243. #ifdef TEST_MAP
  244. void check()
  245. {
  246. size_t count = 0;
  247. for(iterator p=list_.begin;p!=0;p=p->next,count++) {
  248. range_type &r = get(p->val.first);
  249. if(r.first == r.second) {
  250. TEST(r.first==p);
  251. }
  252. bool found = false;
  253. iterator p2;
  254. for(p2=r.first;p2!=r.second;p2=p2->next) {
  255. if(p2 == p) {
  256. found = true;
  257. break;
  258. }
  259. }
  260. if(!found)
  261. TEST(p2 == p);
  262. if(p->next == 0) {
  263. TEST(p == list_.end);
  264. }
  265. }
  266. TEST(size_ == count);
  267. count = 0;
  268. for(size_t i=0;i<hash_.size();i++) {
  269. for(iterator p=hash_[i].first;p;p=p->next) {
  270. count++;
  271. Hash h;
  272. TEST(h(p->val.first) % hash_.size() == i);
  273. if(p==hash_[i].second)
  274. break;
  275. }
  276. }
  277. TEST(size_ == count);
  278. }
  279. #endif
  280. void rehash(size_t new_size)
  281. {
  282. basic_map tmp;
  283. tmp.hash_.resize(new_size,range_type(iterator(),iterator()));
  284. while(list_.begin) {
  285. iterator p=list_.begin;
  286. list_.erase(p);
  287. range_type &r = tmp.get(p->val.first);
  288. if(r.first == 0) {
  289. tmp.list_.push_back(p);
  290. r.first = r.second = p;
  291. }
  292. else {
  293. tmp.list_.insert_after(p,r.second);
  294. r.second = p;
  295. }
  296. }
  297. list_.swap(tmp.list_);
  298. hash_.swap(tmp.hash_);
  299. tmp.hash_.clear();
  300. }
  301. private:
  302. template<typename Kt>
  303. iterator find_in_range(range_type &r,Kt const &k)
  304. {
  305. for(iterator p=r.first;p!=0;p=p->next) {
  306. Equals compare;
  307. if(compare(p->val.first,k)) {
  308. return p;
  309. }
  310. if(p==r.second)
  311. return 0;
  312. }
  313. return 0;
  314. }
  315. template<typename Kt>
  316. range_type &get(Kt const &k)
  317. {
  318. Hash hf;
  319. size_t h = hf(k) % hash_.size();
  320. return hash_[h];
  321. }
  322. size_t next_size()
  323. {
  324. return (1+size_)*2;
  325. }
  326. void rehash_if_needed()
  327. {
  328. size_t table_size = hash_.size();
  329. if(size_ + 1 >= table_size) {
  330. rehash(next_size());
  331. }
  332. }
  333. iterator allocate(value_type const &v)
  334. {
  335. container_alloc al;
  336. iterator p = al.allocate(1);
  337. try {
  338. new (p) container(v);
  339. }
  340. catch(...) {
  341. al.deallocate(p,1);
  342. throw;
  343. }
  344. return p;
  345. }
  346. iterator allocate()
  347. {
  348. container_alloc al;
  349. iterator p = al.allocate(1);
  350. try {
  351. new (p) container();
  352. }
  353. catch(...) {
  354. al.deallocate(p);
  355. throw;
  356. }
  357. return p;
  358. }
  359. void destroy(iterator p)
  360. {
  361. container_alloc al;
  362. p->~container();
  363. al.deallocate(p,1);
  364. }
  365. std::vector<range_type, vec_allocator> hash_;
  366. intrusive_list<container> list_;
  367. size_t size_;
  368. };
  369. } // details
  370. template< typename Key,
  371. typename Value,
  372. typename Hash,
  373. typename Equals = details::are_equal,
  374. typename Alloc= std::allocator<std::pair<Key,Value> > >
  375. class hash_map {
  376. typedef details::basic_map<Key,Value,Hash,Equals,Alloc> impl_type;
  377. typedef typename impl_type::iterator impl_iterator;
  378. public:
  379. typedef std::pair<const Key,Value> value_type;
  380. #ifdef TEST_MAP
  381. void check()
  382. {
  383. impl_.check();
  384. }
  385. #endif
  386. void rehash(size_t n)
  387. {
  388. impl_.rehash(n);
  389. }
  390. ~hash_map()
  391. {
  392. clear();
  393. }
  394. class iterator :
  395. public booster::iterator_facade<
  396. iterator,
  397. value_type,
  398. booster::bidirectional_traversal_tag>
  399. {
  400. public:
  401. iterator(typename impl_type::iterator p = 0) : p_(p) {}
  402. value_type &dereference() const
  403. {
  404. return p_->val;
  405. }
  406. void increment()
  407. {
  408. p_=p_->next;
  409. }
  410. void decrement()
  411. {
  412. p_=p_->prev;
  413. }
  414. bool equal(iterator const &other) const
  415. {
  416. return p_==other.p_;
  417. }
  418. private:
  419. friend class hash_map;
  420. typename impl_type::iterator p_;
  421. };
  422. iterator begin()
  423. {
  424. return iterator(impl_.begin());
  425. }
  426. iterator end()
  427. {
  428. return iterator(0);
  429. }
  430. template<typename Kt>
  431. iterator find(Kt const &k)
  432. {
  433. return iterator(impl_.find(k));
  434. }
  435. std::pair<iterator,bool> insert(value_type const &v)
  436. {
  437. std::pair<impl_iterator,bool> r = impl_.insert(v);
  438. return std::pair<iterator,bool>(iterator(r.first),r.second);
  439. }
  440. iterator erase(iterator p)
  441. {
  442. return iterator(impl_.erase(p.p_));
  443. }
  444. void clear()
  445. {
  446. impl_.clear();
  447. }
  448. size_t size() const
  449. {
  450. return impl_.size();
  451. }
  452. private:
  453. impl_type impl_;
  454. };
  455. } // impl
  456. } // cppcms
  457. #endif