// Copyright (C) 2005 Davis E. King (davis@dlib.net)
// License: Boost Software License See LICENSE.txt for the full license.
#ifndef DLIB_STATIC_MAP_KERNEl_1_
#define DLIB_STATIC_MAP_KERNEl_1_
#include "static_map_kernel_abstract.h"
#include "../interfaces/map_pair.h"
#include "../interfaces/enumerable.h"
#include "../interfaces/remover.h"
#include "../algs.h"
#include "../serialize.h"
#include <functional>
namespace dlib
{
template <
typename domain,
typename range,
typename compare = std::less<domain>
>
class static_map_kernel_1 : public enumerable<map_pair<domain,range> >
{
/*!
INITIAL VALUE
- map_size == 0
- d == 0
- r == 0
- mp.d = 0;
- at_start_ == true
CONVENTION
- size() == map_size
- if (size() > 0) then
- d == pointer to an array containing all the domain elements
- r == pointer to an array containing all the range elements
- for every i: operator[](d[i]) == r[i]
- d is sorted according to operator<
- else
- d == 0
- r == 0
- current_element_valid() == (mp.d != 0)
- at_start() == (at_start_)
- if (current_element_valid()) then
- element() == mp
!*/
class mpair : public map_pair<domain,range>
{
public:
const domain* d;
range* r;
const domain& key(
) const { return *d; }
const range& value(
) const { return *r; }
range& value(
) { return *r; }
};
// I would define this outside the class but Borland 5.5 has some problems
// with non-inline templated friend functions.
friend void deserialize (
static_map_kernel_1& item,
std::istream& in
)
{
try
{
item.clear();
unsigned long size;
deserialize(size,in);
item.map_size = size;
item.d = new domain[size];
item.r = new range[size];
for (unsigned long i = 0; i < size; ++i)
{
deserialize(item.d[i],in);
deserialize(item.r[i],in);
}
}
catch (serialization_error& e)
{
item.map_size = 0;
if (item.d)
{
delete [] item.d;
item.d = 0;
}
if (item.r)
{
delete [] item.r;
item.r = 0;
}
throw serialization_error(e.info + "\n while deserializing object of type static_map_kernel_1");
}
catch (...)
{
item.map_size = 0;
if (item.d)
{
delete [] item.d;
item.d = 0;
}
if (item.r)
{
delete [] item.r;
item.r = 0;
}
throw;
}
}
public:
typedef domain domain_type;
typedef range range_type;
typedef compare compare_type;
static_map_kernel_1(
);
virtual ~static_map_kernel_1(
);
void clear (
);
void load (
pair_remover<domain,range>& source
);
void load (
asc_pair_remover<domain,range,compare>& source
);
inline const range* operator[] (
const domain& d
) const;
inline range* operator[] (
const domain& d
);
inline void swap (
static_map_kernel_1& item
);
// functions from the enumerable interface
inline size_t size (
) const;
inline bool at_start (
) const;
inline void reset (
) const;
inline bool current_element_valid (
) const;
inline const map_pair<domain,range>& element (
) const;
inline map_pair<domain,range>& element (
);
inline bool move_next (
) const;
private:
bool binary_search (
const domain& item,
unsigned long& pos
) const;
/*!
ensures
- if (there is an item in d equivalent to item) then
- returns true
- d[#pos] is equivalent item
- else
- returns false
!*/
void sort_arrays (
unsigned long left,
unsigned long right
);
/*!
requires
- left and right are within the bounts of the array
ensures
- everything in the convention is still true and d[left] though
d[right] is sorted according to operator<
!*/
void qsort_partition (
unsigned long& partition_element,
const unsigned long left,
const unsigned long right
);
/*!
requires
- left < right
- left and right are within the bounts of the array
ensures
- the convention is still true
- left <= #partition_element <= right
- all elements in #d < #d[#partition_element] have
indices >= left and < #partition_element
- all elements in #d >= #d[#partition_element] have
indices >= #partition_element and <= right
!*/
unsigned long median (
unsigned long one,
unsigned long two,
unsigned long three
);
/*!
requires
- one, two, and three are valid indexes into d
ensures
- returns the median of d[one], d[two], and d[three]
!*/
// data members
unsigned long map_size;
domain* d;
range* r;
mutable mpair mp;
mutable bool at_start_;
compare comp;
// restricted functions
static_map_kernel_1(static_map_kernel_1&); // copy constructor
static_map_kernel_1& operator=(static_map_kernel_1&); // assignment operator
};
template <
typename domain,
typename range,
typename compare
>
inline void swap (
static_map_kernel_1<domain,range,compare>& a,
static_map_kernel_1<domain,range,compare>& b
) { a.swap(b); }
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
// member function definitions
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
template <
typename domain,
typename range,
typename compare
>
static_map_kernel_1<domain,range,compare>::
static_map_kernel_1(
) :
map_size(0),
d(0),
r(0),
at_start_(true)
{
mp.d = 0;
}
// ----------------------------------------------------------------------------------------
template <
typename domain,
typename range,
typename compare
>
static_map_kernel_1<domain,range,compare>::
~static_map_kernel_1(
)
{
if (map_size > 0)
{
delete [] d;
delete [] r;
}
}
// ----------------------------------------------------------------------------------------
template <
typename domain,
typename range,
typename compare
>
void static_map_kernel_1<domain,range,compare>::
clear (
)
{
if (map_size > 0)
{
map_size = 0;
delete [] d;
delete [] r;
d = 0;
r = 0;
}
reset();
}
// ----------------------------------------------------------------------------------------
template <
typename domain,
typename range,
typename compare
>
void static_map_kernel_1<domain,range,compare>::
load (
pair_remover<domain,range>& source
)
{
if (source.size() > 0)
{
domain* old_d = d;
d = new domain[source.size()];
try { r = new range[source.size()]; }
catch (...) { delete [] d; d = old_d; throw; }
map_size = source.size();
for (unsigned long i = 0; source.size() > 0; ++i)
source.remove_any(d[i],r[i]);
sort_arrays(0,map_size-1);
}
else
{
clear();
}
reset();
}
// ----------------------------------------------------------------------------------------
template <
typename domain,
typename range,
typename compare
>
void static_map_kernel_1<domain,range,compare>::
load (
asc_pair_remover<domain,range,compare>& source
)
{
if (source.size() > 0)
{
domain* old_d = d;
d = new domain[source.size()];
try { r = new range[source.size()]; }
catch (...) { delete [] d; d = old_d; throw; }
map_size = source.size();
for (unsigned long i = 0; source.size() > 0; ++i)
source.remove_any(d[i],r[i]);
}
else
{
clear();
}
reset();
}
// ----------------------------------------------------------------------------------------
template <
typename domain,
typename range,
typename compare
>
const range* static_map_kernel_1<domain,range,compare>::
operator[] (
const domain& d_item
) const
{
unsigned long pos;
if (binary_search(d_item,pos))
return r+pos;
else
return 0;
}
// ----------------------------------------------------------------------------------------
template <
typename domain,
typename range,
typename compare
>
range* static_map_kernel_1<domain,range,compare>::
operator[] (
const domain& d_item
)
{
unsigned long pos;
if (binary_search(d_item,pos))
return r+pos;
else
return 0;
}
// ----------------------------------------------------------------------------------------
template <
typename domain,
typename range,
typename compare
>
size_t static_map_kernel_1<domain,range,compare>::
size (
) const
{
return map_size;
}
// ----------------------------------------------------------------------------------------
template <
typename domain,
typename range,
typename compare
>
void static_map_kernel_1<domain,range,compare>::
swap (
static_map_kernel_1<domain,range,compare>& item
)
{
exchange(map_size,item.map_size);
exchange(d,item.d);
exchange(r,item.r);
exchange(mp,item.mp);
exchange(at_start_,item.at_start_);
exchange(comp,item.comp);
}
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
// enumerable function definitions
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
template <
typename domain,
typename range,
typename compare
>
bool static_map_kernel_1<domain,range,compare>::
at_start (
) const
{
return (at_start_);
}
// ----------------------------------------------------------------------------------------
template <
typename domain,
typename range,
typename compare
>
void static_map_kernel_1<domain,range,compare>::
reset (
) const
{
mp.d = 0;
at_start_ = true;
}
// ----------------------------------------------------------------------------------------
template <
typename domain,
typename range,
typename compare
>
bool static_map_kernel_1<domain,range,compare>::
current_element_valid (
) const
{
return (mp.d != 0);
}
// ----------------------------------------------------------------------------------------
template <
typename domain,
typename range,
typename compare
>
const map_pair<domain,range>& static_map_kernel_1<domain,range,compare>::
element (
) const
{
return mp;
}
// ----------------------------------------------------------------------------------------
template <
typename domain,
typename range,
typename compare
>
map_pair<domain,range>& static_map_kernel_1<domain,range,compare>::
element (
)
{
return mp;
}
// ----------------------------------------------------------------------------------------
template <
typename domain,
typename range,
typename compare
>
bool static_map_kernel_1<domain,range,compare>::
move_next (
) const
{
// if at_start() && size() > 0
if (at_start_ && map_size > 0)
{
at_start_ = false;
mp.r = r;
mp.d = d;
return true;
}
// else if current_element_valid()
else if (mp.d != 0)
{
++mp.d;
++mp.r;
if (static_cast<unsigned long>(mp.d - d) < map_size)
{
return true;
}
else
{
mp.d = 0;
return false;
}
}
else
{
at_start_ = false;
return false;
}
}
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
// private member function definitions
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
template <
typename domain,
typename range,
typename compare
>
bool static_map_kernel_1<domain,range,compare>::
binary_search (
const domain& item,
unsigned long& pos
) const
{
unsigned long high = map_size;
unsigned long low = 0;
unsigned long p = map_size;
unsigned long idx;
while (p > 0)
{
p = (high-low)>>1;
idx = p+low;
if (comp(item , d[idx]))
{
high = idx;
}
else if (comp(d[idx] , item))
{
low = idx;
}
else
{
pos = idx;
return true;
}
}
return false;
}
// ----------------------------------------------------------------------------------------
template <
typename domain,
typename range,
typename compare
>
void static_map_kernel_1<domain,range,compare>::
sort_arrays (
unsigned long left,
unsigned long right
)
{
if ( left < right)
{
unsigned long partition_element;
qsort_partition(partition_element,left,right);
if (partition_element > 0)
sort_arrays(left,partition_element-1);
sort_arrays(partition_element+1,right);
}
}
// ----------------------------------------------------------------------------------------
template <
typename domain,
typename range,
typename compare
>
void static_map_kernel_1<domain,range,compare>::
qsort_partition (
unsigned long& partition_element,
const unsigned long left,
const unsigned long right
)
{
partition_element = right;
unsigned long med = median(partition_element,left,((right-left)>>1) +left);
exchange(d[partition_element],d[med]);
exchange(r[partition_element],r[med]);
unsigned long right_scan = right-1;
unsigned long left_scan = left;
while (true)
{
// find an element to the left of partition_element that needs to be moved
while ( comp( d[left_scan] , d[partition_element]) )
{
++left_scan;
}
// find an element to the right of partition_element that needs to be moved
while (
!(comp (d[right_scan] , d[partition_element])) &&
(right_scan > left_scan)
)
{
--right_scan;
}
if (left_scan >= right_scan)
break;
exchange(d[left_scan],d[right_scan]);
exchange(r[left_scan],r[right_scan]);
}
exchange(d[left_scan],d[partition_element]);
exchange(r[left_scan],r[partition_element]);
partition_element = left_scan;
}
// ----------------------------------------------------------------------------------------
template <
typename domain,
typename range,
typename compare
>
unsigned long static_map_kernel_1<domain,range,compare>::
median (
unsigned long one,
unsigned long two,
unsigned long three
)
{
if ( comp( d[one] , d[two]) )
{
// one < two
if ( comp( d[two] , d[three]) )
{
// one < two < three : two
return two;
}
else
{
// one < two >= three
if (comp( d[one] , d[three]))
{
// three
return three;
}
}
}
else
{
// one >= two
if ( comp(d[three] , d[one] ))
{
// three <= one >= two
if ( comp(d[three] , d[two]) )
{
// two
return two;
}
else
{
// three
return three;
}
}
}
return one;
}
// ----------------------------------------------------------------------------------------
}
#endif // DLIB_STATIC_MAP_KERNEl_1_