1 /* 2 * TdZdd: a Top-down/Breadth-first Decision Diagram Manipulation Framework 3 * by Hiroaki Iwashita <iwashita@erato.ist.hokudai.ac.jp> 4 * Copyright (c) 2014 ERATO MINATO Project 5 * 6 * Permission is hereby granted, free of charge, to any person obtaining a 7 * copy of this software and associated documentation files (the "Software"), 8 * to deal in the Software without restriction, including without limitation 9 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 10 * and/or sell copies of the Software, and to permit persons to whom the 11 * Software is furnished to do so, subject to the following conditions: 12 * 13 * The above copyright notice and this permission notice shall be included in 14 * all copies or substantial portions of the Software. 15 * 16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 21 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 22 * DEALINGS IN THE SOFTWARE. 23 */ 24 25 #pragma once 26 27 #include <cassert> 28 #include <cstring> 29 #include <stdexcept> 30 31 namespace tdzdd { 32 33 template<typename T, size_t BLOCK_ELEMENTS = 1000> 34 class MyList { 35 static int const headerCells = 1; 36 37 struct Cell { 38 Cell* next; 39 }; 40 41 Cell* front_; 42 size_t size_; 43 numCells(size_t n)44 static size_t numCells(size_t n) { 45 return (n + sizeof(Cell) - 1) / sizeof(Cell); 46 } 47 setFlag(Cell * p)48 static Cell* setFlag(Cell* p) { 49 return reinterpret_cast<Cell*>(reinterpret_cast<size_t>(p) | 1); 50 } 51 clearFlag(Cell * p)52 static Cell* clearFlag(Cell* p) { 53 static size_t const mask = ~size_t(0) << 1; 54 return reinterpret_cast<Cell*>(reinterpret_cast<size_t>(p) & mask); 55 } 56 flagged(Cell * p)57 static bool flagged(Cell* p) { 58 return reinterpret_cast<size_t>(p) & 1; 59 } 60 blockStart(Cell * p)61 static Cell*& blockStart(Cell* p) { 62 return p[-1].next; 63 } 64 dataStart(Cell * p)65 static T* dataStart(Cell* p) { 66 return reinterpret_cast<T*>(p + 1); 67 } 68 69 public: MyList()70 MyList() 71 : front_(0), size_(0) { 72 } 73 MyList(MyList const & o)74 MyList(MyList const& o) 75 : front_(0), size_(0) { 76 if (o.size_ != 0) throw std::runtime_error( 77 "MyList can't be copied unless it is empty!"); //FIXME 78 } 79 operator =(MyList const & o)80 MyList& operator=(MyList const& o) { 81 if (o.size_ != 0) throw std::runtime_error( 82 "MyList can't be copied unless it is empty!"); //FIXME 83 clear(); 84 return *this; 85 } 86 87 // MyList(MyList&& o) { 88 // *this = std::move(o); 89 // } 90 91 // MyList& operator=(MyList&& o) { 92 // front_ = o.front_; 93 // o.front_ = 0; 94 // return *this; 95 // } 96 ~MyList()97 virtual ~MyList() { 98 clear(); 99 } 100 101 /** 102 * Returns the number of elements. 103 * @return the number of elements. 104 */ size() const105 size_t size() const { 106 return size_; 107 } 108 109 /** 110 * Checks emptiness. 111 * @return true if empty. 112 */ empty() const113 bool empty() const { 114 assert((front_ == 0) == (size_ == 0)); 115 return front_ == 0; 116 } 117 118 /** 119 * Initializes the array to be empty. 120 * The memory is deallocated. 121 */ clear()122 void clear() { 123 while (front_) { 124 Cell* p = front_; 125 126 while (!flagged(p)) { 127 p = p->next; 128 } 129 130 delete[] blockStart(front_); 131 front_ = clearFlag(p); 132 } 133 size_ = 0; 134 } 135 136 /** 137 * Accesses the first element. 138 * @return pointer to the first element. 139 */ front()140 T* front() { 141 return dataStart(front_); 142 } 143 144 /** 145 * Accesses the first element. 146 * @return pointer to the first element. 147 */ front() const148 T const* front() const { 149 return dataStart(front_); 150 } 151 152 /** 153 * Allocates a contiguous memory block for one or more new elements 154 * at the beginning. 155 * The memory block is not initialized. 156 * @param numElements the number of elements. 157 * @return pointer to the memory block. 158 */ alloc_front(size_t numElements=1)159 T* alloc_front(size_t numElements = 1) { 160 size_t const n = numCells(numElements * sizeof(T)) + 1; 161 162 if (front_ == 0 || front_ < blockStart(front_) + headerCells + n) { 163 size_t const m = headerCells + n * BLOCK_ELEMENTS; 164 Cell* newBlock = new Cell[m]; 165 Cell* newFront = newBlock + m - n; 166 blockStart(newFront) = newBlock; 167 newFront->next = setFlag(front_); 168 front_ = newFront; 169 } 170 else { 171 Cell* newFront = front_ - n; 172 blockStart(newFront) = blockStart(front_); 173 newFront->next = front_; 174 front_ = newFront; 175 } 176 ++size_; 177 178 return dataStart(front_); 179 } 180 181 /** 182 * Removes a memory block at the beginning. 183 */ pop_front()184 void pop_front() { 185 //front().~T(); I don't care about destruction! 186 Cell* next = front_->next; 187 188 if (flagged(next)) { 189 delete[] blockStart(front_); 190 front_ = clearFlag(next); 191 } 192 else { 193 blockStart(next) = blockStart(front_); 194 front_ = next; 195 } 196 --size_; 197 } 198 199 class iterator { 200 Cell* front; 201 202 public: iterator(Cell * front)203 iterator(Cell* front) 204 : front(front) { 205 } 206 operator *() const207 T* operator*() const { 208 return dataStart(front); 209 } 210 operator ->() const211 T* operator->() const { 212 return dataStart(front); 213 } 214 operator ++()215 iterator& operator++() { 216 front = clearFlag(front->next); 217 return *this; 218 } 219 operator ==(iterator const & o) const220 bool operator==(iterator const& o) const { 221 return front == o.front; 222 } 223 operator !=(iterator const & o) const224 bool operator!=(iterator const& o) const { 225 return front != o.front; 226 } 227 }; 228 229 class const_iterator { 230 Cell const* front; 231 232 public: const_iterator(Cell const * front)233 const_iterator(Cell const* front) 234 : front(front) { 235 } 236 operator *() const237 T const* operator*() const { 238 return *dataStart(front); 239 } 240 operator ->() const241 T const* operator->() const { 242 return dataStart(front); 243 } 244 operator ++()245 const_iterator& operator++() { 246 front = clearFlag(front->next); 247 return *this; 248 } 249 operator ==(iterator const & o) const250 bool operator==(iterator const& o) const { 251 return front == o.front; 252 } 253 operator !=(iterator const & o) const254 bool operator!=(iterator const& o) const { 255 return front != o.front; 256 } 257 }; 258 259 /** 260 * Returns an iterator to the beginning. 261 * @return iterator to the beginning. 262 */ begin()263 iterator begin() { 264 return iterator(front_); 265 } 266 267 /** 268 * Returns an iterator to the beginning. 269 * @return iterator to the beginning. 270 */ begin() const271 const_iterator begin() const { 272 return const_iterator(front_); 273 } 274 275 /** 276 * Returns an iterator to the end. 277 * @return iterator to the end. 278 */ end()279 iterator end() { 280 return iterator(0); 281 } 282 283 /** 284 * Returns an iterator to the end. 285 * @return iterator to the end. 286 */ end() const287 const_iterator end() const { 288 return const_iterator(0); 289 } 290 291 // /** 292 // * Get the hash code of this object. 293 // * @return the hash code. 294 // */ 295 // size_t hash() const { 296 // size_t h = size_; 297 // for (size_t i = 0; i < size_; ++i) { 298 // h = h * 31 + array_[i].hash(); 299 // } 300 // return h; 301 // } 302 // 303 // /** 304 // * Check equivalence between another object. 305 // * @param o another object. 306 // * @return true if equivalent. 307 // */ 308 // bool operator==(MyList const& o) const { 309 // if (size_ != o.size_) return false; 310 // for (size_t i = 0; i < size_; ++i) { 311 // if (!(array_[i] == o.array_[i])) return false; 312 // } 313 // return true; 314 // } 315 316 /** 317 * Sends an object to an output stream. 318 * @param os the output stream. 319 * @param o the object. 320 * @return os. 321 */ operator <<(std::ostream & os,MyList const & o)322 friend std::ostream& operator<<(std::ostream& os, MyList const& o) { 323 bool cont = false; 324 os << "("; 325 for (const_iterator t = o.begin(); t != o.end(); ++t) { 326 if (cont) os << ","; 327 os << **t; 328 cont = true; 329 } 330 return os << ")"; 331 } 332 }; 333 334 template<typename T> 335 class MyListOnPool { 336 struct Cell { 337 Cell* next; 338 }; 339 340 Cell* front_; 341 size_t size_; 342 dataCells(size_t n)343 static size_t dataCells(size_t n) { 344 return (n + sizeof(Cell) - 1) / sizeof(Cell); 345 } 346 workCells(size_t n)347 static size_t workCells(size_t n) { 348 return 1 + dataCells(n); 349 } 350 dataStart(Cell * p)351 static T* dataStart(Cell* p) { 352 return reinterpret_cast<T*>(p + 1); 353 } 354 dataStart(Cell const * p)355 static T const* dataStart(Cell const* p) { 356 return reinterpret_cast<T const*>(p + 1); 357 } 358 359 public: MyListOnPool()360 MyListOnPool() 361 : front_(0), size_(0) { 362 } 363 MyListOnPool(MyListOnPool const & o)364 MyListOnPool(MyListOnPool const& o) { 365 *this = o; 366 } 367 operator =(MyListOnPool const & o)368 MyListOnPool& operator=(MyListOnPool const& o) { 369 if (!o.empty()) throw std::runtime_error( 370 "MyListOnPool: Can't copy a nonempty object."); 371 372 front_ = 0; 373 size_ = 0; 374 return *this; 375 } 376 377 // MyListOnPool(MyListOnPool&& o) { 378 // *this = std::move(o); 379 // } 380 // 381 // MyListOnPool& operator=(MyListOnPool&& o) { 382 // front_ = o.front_; 383 // size_ = o.size_; 384 // o.front_ = 0; 385 // o.size_ = 0; 386 // return *this; 387 // } 388 ~MyListOnPool()389 virtual ~MyListOnPool() { 390 clear(); 391 } 392 393 /** 394 * Returns the number of elements. 395 * @return the number of elements. 396 */ size() const397 size_t size() const { 398 return size_; 399 } 400 401 /** 402 * Checks emptiness. 403 * @return true if empty. 404 */ empty() const405 bool empty() const { 406 assert((front_ == 0) == (size_ == 0)); 407 return front_ == 0; 408 } 409 410 /** 411 * Initializes the array to be empty. 412 * The memory is left unused on the pool. 413 */ clear()414 void clear() { 415 front_ = 0; 416 size_ = 0; 417 } 418 419 /** 420 * Accesses the first element. 421 * @return pointer to the first element. 422 */ front()423 T* front() { 424 return dataStart(front_); 425 } 426 427 /** 428 * Accesses the first element. 429 * @return pointer to the first element. 430 */ front() const431 T const* front() const { 432 return dataStart(front_); 433 } 434 435 /** 436 * Allocates a contiguous memory block for one or more new elements 437 * at the beginning. 438 * The memory block is not initialized. 439 * @param pool memory pool for allocating new entries. 440 * @param numElements the number of elements. 441 * @return pointer to the memory block. 442 */ 443 template<typename Pool> alloc_front(Pool & pool,size_t numElements=1)444 T* alloc_front(Pool& pool, size_t numElements = 1) { 445 size_t const n = workCells(numElements * sizeof(T)); 446 Cell* newFront = pool.template allocate<Cell>(n); 447 newFront->next = front_; 448 front_ = newFront; 449 ++size_; 450 451 return dataStart(front_); 452 } 453 454 /** 455 * Removes a memory block at the beginning. 456 */ pop_front()457 void pop_front() { 458 front_ = front_->next; 459 --size_; 460 } 461 462 class iterator { 463 Cell* front; 464 465 public: iterator(Cell * front)466 iterator(Cell* front) 467 : front(front) { 468 } 469 operator *() const470 T* operator*() const { 471 return dataStart(front); 472 } 473 operator ++()474 iterator& operator++() { 475 front = front->next; 476 return *this; 477 } 478 operator ==(iterator const & o) const479 bool operator==(iterator const& o) const { 480 return front == o.front; 481 } 482 operator !=(iterator const & o) const483 bool operator!=(iterator const& o) const { 484 return front != o.front; 485 } 486 }; 487 488 class const_iterator { 489 Cell const* front; 490 491 public: const_iterator(Cell const * front)492 const_iterator(Cell const* front) 493 : front(front) { 494 } 495 operator *() const496 T const* operator*() const { 497 return dataStart(front); 498 } 499 operator ++()500 const_iterator& operator++() { 501 front = front->next; 502 return *this; 503 } 504 operator ==(const_iterator const & o) const505 bool operator==(const_iterator const& o) const { 506 return front == o.front; 507 } 508 operator !=(const_iterator const & o) const509 bool operator!=(const_iterator const& o) const { 510 return front != o.front; 511 } 512 }; 513 514 /** 515 * Returns an iterator to the beginning. 516 * @return iterator to the beginning. 517 */ begin()518 iterator begin() { 519 return iterator(front_); 520 } 521 522 /** 523 * Returns an iterator to the beginning. 524 * @return iterator to the beginning. 525 */ begin() const526 const_iterator begin() const { 527 return const_iterator(front_); 528 } 529 530 /** 531 * Returns an iterator to the end. 532 * @return iterator to the end. 533 */ end()534 iterator end() { 535 return iterator(0); 536 } 537 538 /** 539 * Returns an iterator to the end. 540 * @return iterator to the end. 541 */ end() const542 const_iterator end() const { 543 return const_iterator(0); 544 } 545 546 // /** 547 // * Get the hash code of this object. 548 // * @return the hash code. 549 // */ 550 // size_t hash() const { 551 // size_t h = size_; 552 // for (size_t i = 0; i < size_; ++i) { 553 // h = h * 31 + array_[i].hash(); 554 // } 555 // return h; 556 // } 557 // 558 // /** 559 // * Check equivalence between another object. 560 // * @param o another object. 561 // * @return true if equivalent. 562 // */ 563 // bool operator==(MyListOnPool const& o) const { 564 // if (size_ != o.size_) return false; 565 // for (size_t i = 0; i < size_; ++i) { 566 // if (!(array_[i] == o.array_[i])) return false; 567 // } 568 // return true; 569 // } 570 571 /** 572 * Sends an object to an output stream. 573 * @param os the output stream. 574 * @param o the object. 575 * @return os. 576 */ operator <<(std::ostream & os,MyListOnPool const & o)577 friend std::ostream& operator<<(std::ostream& os, MyListOnPool const& o) { 578 bool cont = false; 579 os << "("; 580 for (const_iterator t = o.begin(); t != o.end(); ++t) { 581 if (cont) os << ","; 582 os << **t; 583 cont = true; 584 } 585 return os << ")"; 586 } 587 }; 588 589 } // namespace tdzdd 590