memory_allocation.h 23.7 KB
Newer Older
1
/*
Marcus Winter committed
2
 * Copyright (c) 2014-2016, Siemens AG. All rights reserved.
3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * 1. Redistributions of source code must retain the above copyright notice,
 * this list of conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above copyright notice,
 * this list of conditions and the following disclaimer in the documentation
 * and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */

#ifndef EMBB_BASE_MEMORY_ALLOCATION_H_
#define EMBB_BASE_MEMORY_ALLOCATION_H_

#include <embb/base/exceptions.h>
#include <embb/base/internal/config.h>
#include <embb/base/c/internal/unused.h>
#include <limits>
#include <cstddef>

#include <new>
#include <embb/base/c/memory_allocation.h>

/**
 * \defgroup CPP_BASE_MEMORY_ALLOCATION Memory Allocation
 * Functions, classes, and allocators for dynamic memory allocation.
 *
 * \ingroup CPP_BASE
 */

namespace embb {
namespace base {
/**
 * Common (static) functionality for unaligned and aligned memory allocation.
 * This class is a wrapper for the functions in
 * \ref embb/base/c/memory_allocation.h
 *
 * \ingroup CPP_BASE_MEMORY_ALLOCATION
 */
class Allocation {
 public:
  /**
   * Allocates memory for an instance of type \c Type and default-initializes
   * it.
   *
   * Keeps track of allocated memory in debug mode.
   *
   * \return Pointer to new instance of type \c Type
   *
   * \throws embb::base::NoMemoryException if not enough memory is available
   *         for the given type.
   *
   * \see Delete()
   *
   * \memory <tt>size+3*sizeof(size_t)</tt> bytes in debug mode, otherwise \c
   *         size bytes
   *
   * \threadsafe
   *
   * \tparam Type %Type of the object to be allocated
   */
  template<typename Type>
  static Type* New() {
    void* memory = embb_alloc(sizeof(Type));
    if (memory == NULL) EMBB_THROW(NoMemoryException, "When allocating memory");
    return new(memory) Type();
  }

  #ifdef DOXYGEN

  /**
   * Allocates memory unaligned for an instance of type \c Type and initializes
   * it with the specified arguments.
   *
   * Keeps track of allocated memory in debug mode.
   *
   * \return Pointer to new instance of type \c Type
   *
   * \throws embb::base::NoMemoryException if not enough memory is available
   *         for the given type.
   *
   * \see Delete()
   *
   * \memory <tt>size+3*sizeof(size_t)</tt> bytes in debug mode, otherwise \c
   *         size bytes
   *
   * \threadsafe
   *
   * \tparam Type %Type of the instance to be allocated
   * \tparam Arg1 %Type of (first) constructor argument
   */
  template<typename Type, typename Arg1, ...>
  static Type* New(
    Arg1 argument1,
    /**< [IN] (First) argument for constructor of \c Type */
    ...
    );

#else // DOXYGEN

  /**
   * See Doxygen documentation dummy above
   */
  template<typename Type, typename Arg1>
  static Type* New(Arg1 arg1) {
    void* memory = embb_alloc(sizeof(Type));
    if (memory == NULL) EMBB_THROW(NoMemoryException, "When allocating memory");
    return new(memory) Type(arg1);
  }

  /**
   * See Doxygen documentation dummy above
   */
  template<typename Type, typename Arg1, typename Arg2>
  static Type* New(Arg1 arg1, Arg2 arg2) {
    void* memory = embb_alloc(sizeof(Type));
    if (memory == NULL) EMBB_THROW(NoMemoryException, "When allocating memory");
    return new(memory) Type(arg1, arg2);
  }

  /**
   * See Doxygen documentation dummy above
   */
  template<typename Type, typename Arg1, typename Arg2, typename Arg3>
  static Type* New(Arg1 arg1, Arg2 arg2, Arg3 arg3) {
    void* memory = embb_alloc(sizeof(Type));
    if (memory == NULL) EMBB_THROW(NoMemoryException, "When allocating memory");
    return new(memory) Type(arg1, arg2, arg3);
  }

  /**
   * See Doxygen documentation dummy above
   */
  template<typename Type, typename Arg1, typename Arg2, typename Arg3,
           typename Arg4>
  static Type* New(Arg1 arg1, Arg2 arg2, Arg3 arg3, Arg4 arg4) {
    void* memory = embb_alloc(sizeof(Type));
    if (memory == NULL) EMBB_THROW(NoMemoryException, "When allocating memory");
    return new(memory) Type(arg1, arg2, arg3, arg4);
  }

  /**
   * See Doxygen documentation dummy above
   */
  template<typename Type, typename Arg1, typename Arg2, typename Arg3,
           typename Arg4, typename Arg5>
  static Type* New(Arg1 arg1, Arg2 arg2, Arg3 arg3, Arg4 arg4, Arg5 arg5) {
    void* memory = embb_alloc(sizeof(Type));
    if (memory == NULL) EMBB_THROW(NoMemoryException, "When allocating memory");
    return new(memory) Type(arg1, arg2, arg3, arg4, arg5);
  }

#endif // else DOXYGEN

  /**
   * Destructs an instance of type \c Type and frees the allocated memory.
   *
   * \tparam Type %Type of instance to be deleted
   */
  template<typename Type>
  static void Delete(
    Type* to_delete
    /**< [IN,OUT] Instance to be deleted */
    ) {
    to_delete->~Type();
    embb_free(static_cast<void*>(to_delete));
  }

  /**
   * Returns the total number of bytes currently allocated.
   *
   * Wrapper for C function embb_get_bytes_allocated().
   *
   * \return Number of currently allocated bytes in debug mode, otherwise 0.
   *
   * \waitfree
   */
  static size_t AllocatedBytes();

  /**
   * Allocates \p size bytes of memory (unaligned).
   *
   * Wrapper for C function embb_allocate().
   *
   * Keeps track of allocated memory in debug mode.
   *
   * \return NULL in case of failure, otherwise address of allocated memory
   * block.
   *
   * \throws embb::base::NoMemoryException if not enough memory is available.
   *
   * \memory <tt>size+3*sizeof(size_t)</tt> bytes in debug mode, otherwise \c
   *         size bytes
   *
   * \threadsafe
   *
   * \note Memory allocated using this function must be freed using
   *       Allocation::Free().
   *
   * \see AllocateAligned(), AllocateCacheAligned(), Free()
   */
  static void* Allocate(
    size_t size
    /**< [IN] Size of memory block to be allocated in bytes */
    );

  /**
   * Frees memory that has been allocated by Allocation::Allocate() for
   * some pointer \p ptr.
   *
   * Wrapper for C function embb_free().
   *
   * Keeps track of freed memory in debug mode.
   *
   * \threadsafe
   *
   * \see Allocate()
   */
  static void Free(
    void * ptr
    /**< [IN,OUT] Pointer to memory block to be freed */
    );

  /**
   * Allocates \p size bytes of memory with alignment \p alignment.
   *
   * Wrapper for C function embb_alloc_aligned().
   *
   * This function can be used to align objects to certain boundaries such as
   * cache lines, memory pages, etc.
   *
   * Keeps track of allocated memory in debug mode.
   *
   * It is not required that \p size is a multiple of \p alignment as, e.g.,
   * for the \c aligned\_alloc function of the C11 Standard.
   *
   * \pre The alignment has to be power of 2 and a multiple of
   *      <tt>size(void*)</tt>.
   * \post The returned pointer is a multiple of \p alignment.
   *
   * \return NULL in case of failure, otherwise address of allocated memory
   * block.
   *
   * \throws embb::base::NoMemoryException if not enough memory is available.
   *
   * \memory Debug mode: Let \c n be the number of aligned cells necessary to
   *         fit the payload. Then, <tt>(n+1)*alignment+3*size_of(size_t)-1</tt>
   *         bytes are allocated.<br> Release mode: \c size bytes are requested
   *         using the functions provided by the operating systems.
   *
   * \threadsafe
   *
   * \note Memory allocated using this function must be freed using
   *       Allocation::FreeAligned().
   *
   * \see Allocate(), AllocateCacheAligned(), FreeAligned()
   */
  static void* AllocateAligned(
    size_t alignment,
    /**< [IN] Alignment in bytes */
    size_t size
    /**< [IN] Size of memory block to be allocated in bytes */
    );

  /**
   * Frees memory that has been allocated by Allocation::AllocateAligned() or
   * Allocation::AllocateCacheAligned() for some pointer \p ptr.
   *
   * Wrapper for C function embb_free_aligned().
   *
   * Keeps track of freed memory in debug mode.
   *
   * \threadsafe
   *
   * \see AllocateAligned(), AllocateCacheAligned()
   */
  static void FreeAligned(
    void * ptr
    /**< [IN,OUT] Pointer to memory block to be freed */
    );

  /**
   * Allocates \p size bytes of cache-aligned memory.
   *
   * Wrapper for C function embb_alloc_cache_aligned().
   *
   * Specialized version of Allocation::AllocateAligned(). The alignment is
   * chosen automatically (usually 64 bytes).
   *
   * Keeps track of allocated memory in debug mode.
   *
   * \post The returned pointer is a multiple of the cache line size.
   *
   * \return NULL in case of failure, otherwise address of allocated memory
   *         block.
   *
   * \throws embb::base::NoMemoryException if not enough memory is available.
   *
   * \memory See Allocation::AllocateAligned()
   *
   * \threadsafe
   *
   * \note Memory allocated using this function must be freed using
   *       Allocation::FreeAligned().
   *
   * \see Allocate(), AllocateAligned(), FreeAligned()
   */
  static void* AllocateCacheAligned(
    size_t size
    /**< [IN] Size of memory block to be allocated in bytes */
    );
};

/**
 * Overloaded new/delete operators.
 *
 * Classes that derive from this class will use the EMBB methods for dynamic
 * allocation and deallocation of memory (Allocation::Allocate() and
 * Allocation::Free()). In debug mode, memory consumption is tracked in order to
 * detect memory leaks.
 *
 * \see CacheAlignedAllocatable
 *
 * \ingroup CPP_BASE_MEMORY_ALLOCATION
 */
class Allocatable {
 public:
  /**
   * New operator.
   *
   * Allocates \c size bytes of memory. Must not be called directly!
   *
   * \return Pointer to allocated block of memory
   *
   * \throws embb::base::NoMemoryException if not enough memory is available.
   *
   * \threadsafe
   *
   * \memory See Allocation::Allocate()
   *
   * \see operator delete()
   */
  static void* operator new(
    size_t size
    /**< [IN] Size of the memory block in bytes */
    );

  /**
   * Delete operator.
   *
   * Deletes \c size bytes of memory pointed to by \c ptr. Must not be called
   * directly!
   *
   * \threadsafe
   *
   * \see operator new()
   */
  static void operator delete(
    void* ptr,
    /**< [IN,OUT] Pointer to memory block to be freed */
    size_t size
    /**< [IN] Size of the memory block in bytes */
    );

  /**
   * Array new operator.
   *
   * Allocates an array of \c size bytes. Must not be called directly!
   *
   * \remark  Note that the global new[], calling this function, might
   *          return a different address. This is stated in the standard
   *          (5.3.4 New [expr.new]):
   * \remark  "A new-expression passes the amount of space requested to the
   *          allocation function as the first argument of type std::size_t.
   *          That argument shall be no less than the size of the object being
   *          created; it may be greater than the size of the object being
   *          created only if the object is an array."
   * \remark  So, even if the returned pointer of this function is aligned,
   *          the pointer to the array returned by global new[] need not be.
   *          For example, when using GCC 4.8.3 (64 bit), the size of the array
   *          is kept in the first 8 bytes of the allocated memory.
   *
   * \return Pointer to allocated block of memory
   *
   * \threadsafe
   *
   * \memory See Allocation::Allocate()
   *
   * \throws embb::base::NoMemoryException if not enough memory is available.
   *
   * \see operator delete[]()
   */
  static void* operator new[](
    size_t size
    /**< [IN] Size of the array in bytes*/
    );

  /**
   * Array delete operator.
   *
   * Deletes array of \c size bytes pointed to by \c ptr. Must not be called
   * directly!
   *
   * \threadsafe
   *
   * \see operator new[]()
   */
  static void operator delete[](
    void* ptr,
    /**< [IN,OUT] Pointer to the array to be freed */
    size_t size
    /**< [IN] Size of the array in bytes */
    );
};

/**
 * Overloaded new/delete operators.
 *
 * Classes that derive from this class will use the EMBB methods for dynamic,
 * cache-aligned allocation and deallocation of memory
 * (Allocation::AllocateCacheAligned() and Allocation::FreeAligned()).
 * In debug mode, memory consumption is tracked in order to detect memory leaks.
 *
 * \note When using the new[] operator, not each object in the array is aligned,
 * but only the constructed array as a whole.
 *
 * \see Allocatable
 *
 * \ingroup CPP_BASE_MEMORY_ALLOCATION
 */
class CacheAlignedAllocatable {
 public:
  /**
   * New operator.
   *
   * Allocates \c size bytes of memory. Must not be called directly!
   *
   * \return Pointer to allocated block of memory
   *
   * \throws embb::base::NoMemoryException if not enough memory is available.
   *
   * \threadsafe
   *
   * \memory See Allocation::AllocateCacheAligned()
   *
   * \see operator delete()
   */
  static void* operator new(
    size_t size
    /**< [IN] Size of the memory block in bytes */
    );

  /**
   * Delete operator.
   *
   * Deletes \c size bytes of memory pointed to by \c ptr. Must not be called
   * directly!
   *
   * \threadsafe
   */
  static void operator delete(
    void* ptr,
    /**< [IN,OUT] Pointer to memory block to be freed */
    size_t size
    /**< [IN] Size of the memory block in bytes */
    );

  /**
   * Array new operator.
   *
   * Allocates an array of \c size bytes. Must not be called directly!
   *
   * \return Pointer to allocated block of memory
   *
   * \throws embb::base::NoMemoryException if not enough memory is available.
   *
   * \memory See Allocation::AllocateCacheAligned()
   *
   * \threadsafe
   *
   * \see operator delete[]()
   */
  static void* operator new[](
    size_t size
    /**< [IN] size of bytes to allocate for the array*/
    );

  /**
   * Array delete operator.
   *
   * Deletes array of \c size bytes pointed to by \c ptr. Must not be called
   * directly!
   *
   * \threadsafe
   *
   * \see operator new[]()
   */
  static void operator delete[](
    void* ptr,
    /**< [IN,OUT] Pointer to the array to be freed */
    size_t size
    /**< [IN] Size of the array in bytes */
    );
};

/*
 * Forward declaration
 */
524
template <typename Type>
525 526 527 528 529 530 531 532 533 534 535 536
class Allocator;

/*
 * Specialization for void
 */
template <>
class Allocator < void > {
 public:
  typedef void*       pointer;
  typedef const void* const_pointer;
  typedef void        value_type;

537 538
  template <typename OtherType> struct rebind {
    typedef Allocator<OtherType> other;
539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554
  };
};

/**
 * %Allocator according to the C++ standard.
 *
 * For memory allocation and deallocation,
 * embb::base::Allocation::Allocate() and
 * embb::base::Allocation::Free() are used, respectively.
 *
 * In debug mode, leak checking is active. The function
 * embb::base::Allocation::AllocatedBytes() returns the number of
 * currently allocated bytes.
 *
 * \ingroup CPP_BASE_MEMORY_ALLOCATION
 */
555
template <typename Type>
556 557 558
class Allocator {
 public:
  /** Quantity of elements type */
559
  typedef size_t      size_type;
560 561

  /** Difference between two pointers type */
562
  typedef ptrdiff_t   difference_type;
563 564

  /** Pointer to element type */
565
  typedef Type*       pointer;
566 567

  /** Pointer to constant element type */
568
  typedef const Type* const_pointer;
569 570

  /** Reference to element type */
571
  typedef Type&       reference;
572 573

  /** Reference to constant element type */
574
  typedef const Type& const_reference;
575 576

  /** Element type */
577
  typedef Type        value_type;
578 579

  /**
580
   * Rebind allocator to type OtherType
581
   */
582
  template <typename OtherType> struct rebind {
583
    /** Type to rebind to */
584
    typedef Allocator<OtherType> other;
585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604
  };

  /**
   * Constructs allocator object
   */
  Allocator() throw() {}

  /**
   * Copies allocator object
   */
  Allocator(
    const Allocator&
    /**< [IN] Other allocator object */
    ) throw() {}

  /**
   * Constructs allocator object
   *
   * Allows construction from allocators for different types (rebind)
   */
605 606
  template <typename OtherType> Allocator(
    const Allocator<OtherType>&
607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644
    /**< [IN] Other allocator object*/
    )
    throw() {}

  /**
   * Destructs allocator object
   */
  ~Allocator() throw() {}

  /**
   * Gets address of an object
   *
   * \return Address of object
   *
   * \waitfree
   */
  pointer address(
    reference x
    /**< [IN] Reference to object */
    ) const {
    return &x;
  }

  /**
   * Gets address of a constant object
   *
   * \return Address of object
   *
   * \waitfree
   */
  const_pointer address(
    const_reference x
    /**< [IN] Reference to constant object */
    ) const {
    return &x;
  }

  /**
645
   * Allocates but doesn't initialize storage for elements of type Type
646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726
   *
   * \threadsafe
   *
   * \return Pointer to allocated storage
   *
   * \memory See Allocation::Allocate()
   */
  pointer allocate(
    size_type n,
    /**< [IN] Number of elements to allocate */
    const void* = 0
    /**< [IN] Optional pointer previously obtained from allocate */
    ) {
    if (n > max_size())
      EMBB_THROW(embb::base::NoMemoryException,
      "Amount of requested memory too high");
    return reinterpret_cast<pointer>
      (embb::base::Allocation::Allocate(n*sizeof(value_type)));
  }

  /**
   * Deallocates storage of destroyed elements.
   *
   * \threadsafe
   */
  void deallocate(
    pointer p,
    /**< [IN,OUT] Pointer to allocated storage */
    size_type
    ) {
    embb::base::Allocation::Free(p);
  }

  /**
   * %Allocation maximum
   *
   * \return Maximum number of elements that can be allocated
   *
   *\waitfree
   */
  size_type max_size() const throw() {
    return std::numeric_limits<size_type>::max() / sizeof(value_type);
  }

  /**
   * Initializes elements of allocated storage with specified value.
   *
   * \threadsafe
   */
  void construct(
    pointer p,
    /**< [IN,OUT] Pointer to allocated storage */
    const value_type& val
    /**< [IN] Value */
    ) {
    new(p)value_type(val);
  }

  /**
   * Destroys elements of initialized storage.
   *
   * \threadsafe
   */
  void destroy(
    pointer p
    /**< [IN,OUT] Pointer to allocated storage*/
    ) {
    EMBB_UNUSED(p);
    p->~value_type();
  }

 private:
  /*
   * \threadsafe
   */
  Allocator& operator=(const Allocator&);
};

/*
 * Forward declaration
 */
727
template <typename Type>
728 729 730 731 732 733 734 735 736 737 738 739
class AllocatorCacheAligned;

/*
 * Specialization for void
 */
template <>
class AllocatorCacheAligned < void > {
 public:
  typedef void*       pointer;
  typedef const void* const_pointer;
  typedef void        value_type;

740 741
  template <typename OtherType> struct rebind {
    typedef AllocatorCacheAligned<OtherType> other;
742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757
  };
};

/**
 * %Allocator according to the C++ standard. Allocates memory cache-aligned.
 *
 * For memory allocation and deallocation,
 * embb::base::Allocation::AllocateCacheAligned() and
 * embb::base::Allocation::FreeAligned() are used, respectively.
 *
 * In debug mode, leak checking is active. The function
 * embb::base::Allocation::AllocatedBytes() returns the number of
 * currently allocated bytes.
 *
 * \ingroup CPP_BASE_MEMORY_ALLOCATION
 */
758 759
template< typename Type >
class AllocatorCacheAligned : public Allocator < Type > {
760 761
 public:
  /** Quantity of elements type */
762
  typedef size_t      size_type;
763 764

  /** Difference between two pointers type */
765
  typedef ptrdiff_t   difference_type;
766 767

  /** Pointer to element type */
768
  typedef Type*       pointer;
769 770

  /** Pointer to constant element type */
771
  typedef const Type* const_pointer;
772 773

  /** Reference to element type */
774
  typedef Type&       reference;
775 776

  /** Reference to constant element type */
777
  typedef const Type& const_reference;
778 779

  /** Element type */
780
  typedef Type        value_type;
781 782

  /**
783
   * Rebind allocator to type OtherType
784
   */
785
  template <typename OtherType> struct rebind {
786
    /** Type to rebind to */
787
    typedef Allocator<OtherType> other;
788 789 790 791 792 793 794 795 796 797 798 799 800 801
  };

  /**
   * Constructs allocator object
   */
  AllocatorCacheAligned() throw() { }

  /**
   * Copies allocator object
   */
  AllocatorCacheAligned(
    const AllocatorCacheAligned& a
    /**< [IN] Other allocator object */
    ) throw()
802
    : Allocator < Type >(a) { }
803 804 805 806 807 808

  /**
   * Constructs allocator object
   *
   * Allows construction from allocators for different types (rebind)
   */
809
  template<typename OtherType>
810
  AllocatorCacheAligned(
811
    const AllocatorCacheAligned<OtherType>&
812 813 814 815 816 817 818 819 820
    /**< [IN] Other allocator object*/
    ) throw() { }

  /**
   * Destructs allocator object
   */
  ~AllocatorCacheAligned() throw() { }

  /**
821
   * Allocates but doesn't initialize storage for elements of type Type
822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938
   *
   * \threadsafe
   *
   * \return Pointer to allocated storage
   *
   * \memory see Allocation::Allocate()
   */
  pointer allocate(
    size_type n,
    /**< [IN] Number of elements to allocate */
    const void* = 0
    /**< [IN] Optional pointer previously obtained from allocate */
    ) {
    if (n > this->max_size())
      EMBB_THROW(embb::base::NoMemoryException,
      "Amount of requested memory too high");
    return reinterpret_cast<pointer>
      (embb::base::Allocation::AllocateCacheAligned(n*sizeof(value_type)));
  }

  /**
   * Deallocates storage of destroyed elements.
   *
   * \threadsafe
   */
  void deallocate(
    pointer p,
    /**< [IN,OUT] Pointer to allocated storage */
    size_type
    ) {
    embb::base::Allocation::FreeAligned(p);
  }
  // Inherit everything else.
};

/*
 * Comparison operator for Allocator objects.
 * Not for manual use.
 */
template<typename O>
inline bool operator==(const Allocator<O>&, const Allocator<O>&) {
  return true;
}

/*
 * Comparison operator for Allocator objects.
 * Not for manual use.
 */
template<typename T, typename U>
inline bool operator==(const Allocator<T>&, const Allocator<U>&) {
  return true;
}

/*
 * Comparison operator for Allocator objects.
 * Not for manual use.
 */
template<typename O>
inline bool operator!=(const Allocator<O>&, const Allocator<O>&) {
  return false;
}

/*
 * Comparison operator for Allocator objects.
 * Not for manual use.
 */
template<typename T, typename U>
inline bool
operator!=(const Allocator<T>&, const Allocator<U>&) {
  return false;
}

/*
 * Comparison operator for AllocatorCacheAligned objects.
 * Not for manual use.
 */
template<typename O>
inline bool operator==(
  const AllocatorCacheAligned<O>&, const AllocatorCacheAligned<O>&) {
  return true;
}

/*
 * Comparison operator for AllocatorCacheAligned objects.
 * Not for manual use.
 */
template<typename T, typename U>
inline bool operator==(
  const AllocatorCacheAligned<T>&, const AllocatorCacheAligned<U>&) {
  return true;
}

/*
 * Comparison operator for AllocatorCacheAligned objects.
 * Not for manual use.
 */
template<typename O>
inline bool operator!=(
  const AllocatorCacheAligned<O>&, const AllocatorCacheAligned<O>&) {
  return false;
}

/*
 * Comparison operator for AllocatorCacheAligned objects.
 * Not for manual use.
 */
template<typename T, typename U>
inline bool operator!=(
  const AllocatorCacheAligned<T>&, const AllocatorCacheAligned<U>&) {
  return false;
}
} // namespace base
} // namespace embb

#include <embb/base/internal/memory_allocation-inl.h>

#endif //  EMBB_BASE_MEMORY_ALLOCATION_H_