// File:       hoistalgo.c++
// Version:    1.01
// Author:     (c) Miles Sabin, 1997
// Purpose:    hoisted algorithms

// Change log:
//  13/01/97   v. 1.00
//  14/01/97   Added hoist algorithms.
//  15/01/97   Added equal() and lexicographical_compare().
//  23/02/97   Split HoistComparator_base off from HoistHelper_base
//               to remove requirement for contained classes to define
//               operator==() and operator<() whereever possible.
//             member_offset() replaced by member_base_offset().
//  01/04/97   Changed _base suffix to Protocol.
//             Added HoistUnaryPredicateProtocol.
//             Added HoistBinaryPredicateProtocol.
//  01/04/97   v. 1.01
//             Split off into separate translation unit.
//  04/04/97   Replaced HoistComparators with HoistBinaryPredicates.

#include "hoistalgo.h"

#include "hoistbpp.h"
#include "hoistctdtp.h"
#include "newcasts.h"


// Implementation of HoistAlgorithm

void HoistAlgorithm::destroy
  (HoistConstructorDestructorProtocol const& hoist_ctdt,
   void* first, void* last)
{
  size_t sz = hoist_ctdt.size();

  while(first != last)
  {
    hoist_ctdt.destroy(first);
    first = reinterpret_cast(char*, first)+sz;
  }
}

void* HoistAlgorithm::copy
  (HoistConstructorDestructorProtocol const& hoist_ctdt,
   void const* first, void const* last, void* result)
{
  size_t sz = hoist_ctdt.size();

  while(first != last)
  {
    hoist_ctdt.assign(result, first);
    first = reinterpret_cast(char*, first)+sz;
    result = reinterpret_cast(char*, result)+sz;
  }

  return result;
}

void* HoistAlgorithm::copy_backward
  (HoistConstructorDestructorProtocol const& hoist_ctdt,
   void const* first, void const* last, void* result)
{
  size_t sz = hoist_ctdt.size();

  while(first != last)
  {
    last = reinterpret_cast(char*, last)-sz;
    result = reinterpret_cast(char*, result)-sz;
    hoist_ctdt.assign(result, last);
  }

  return result;
}

void* HoistAlgorithm::uninitialized_copy
  (HoistConstructorDestructorProtocol const& hoist_ctdt,
   void const* first, void const* last, void* result)
{
  size_t sz = hoist_ctdt.size();

  while(first != last)
  {
    hoist_ctdt.construct(result, first);
    first = reinterpret_cast(char*, first)+sz;
    result = reinterpret_cast(char*, result)+sz;
  }

  return result;
}

void HoistAlgorithm::uninitialized_fill
  (HoistConstructorDestructorProtocol const& hoist_ctdt,
   void* first, void* last, void const* value)
{
  size_t sz = hoist_ctdt.size();

  while(first != last)
  {
    hoist_ctdt.construct(first, value);
    first = reinterpret_cast(char*, first)+sz;
  }
}

void HoistAlgorithm::uninitialized_fill
  (HoistConstructorDestructorProtocol const& hoist_ctdt,
   void* first, size_t n, void const* value)
{
  size_t sz = hoist_ctdt.size();

  while(n--)
  {
    hoist_ctdt.construct(first, value);
    first = reinterpret_cast(char*, first)+sz;
  }
}

ptrdiff_t HoistAlgorithm::member_base_offset
  (HoistConstructorDestructorProtocol const& hoist_ctdt,
   ptrdiff_t previous_member_base_offset, size_t previous_member_size)
{
  size_t member_size = hoist_ctdt.size();
  size_t prev_end = previous_member_base_offset+previous_member_size;
  return (member_size == sizeof(char) ? prev_end : (member_size == sizeof(short) ? (prev_end+1)&~1 : (prev_end+3)&~3));
}

bool HoistAlgorithm::equal
  (HoistConstructorDestructorProtocol const& hoist_ctdt, HoistBinaryPredicateProtocol const& hoist_comparator,
   void const* first1, void const* last1, void const* first2)
{
  size_t sz = hoist_ctdt.size();

  while(first1 != last1 && hoist_comparator(first1, first2))
  {
    first1 += sz;
    first2 += sz;
  }

  return first1 == last1;
}

bool HoistAlgorithm::lexicographical_compare
  (HoistConstructorDestructorProtocol const& hoist_ctdt, HoistBinaryPredicateProtocol const& hoist_comparator,
   void const* first1, void const* last1, void const* first2, void const* last2)
{
  size_t sz = hoist_ctdt.size();

  while(first1 != last1 && first2 != last2)
  {
    if(hoist_comparator(first1, first2))
      return true;
    if(hoist_comparator(first2, first1))
      return false;
    first1 += sz;
    first2 += sz;
  }

  return first1 == last1 && first2 != last2;
}
